Merge pull request #2997 from phire/FixFifoRecorder
FifoRecorder: Use Texture Cache to record efb copies correctly.
This commit is contained in:
commit
a537ca7543
|
@ -19,34 +19,34 @@ void Init()
|
|||
VertexLoader_Normal::Init();
|
||||
}
|
||||
|
||||
u8 ReadFifo8(u8 *&data)
|
||||
u8 ReadFifo8(u8*& data)
|
||||
{
|
||||
u8 value = data[0];
|
||||
data += 1;
|
||||
return value;
|
||||
}
|
||||
|
||||
u16 ReadFifo16(u8 *&data)
|
||||
u16 ReadFifo16(u8*& data)
|
||||
{
|
||||
u16 value = Common::swap16(data);
|
||||
data += 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
u32 ReadFifo32(u8 *&data)
|
||||
u32 ReadFifo32(u8*& data)
|
||||
{
|
||||
u32 value = Common::swap32(data);
|
||||
data += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
void InitBPMemory(BPMemory *bpMem)
|
||||
void InitBPMemory(BPMemory* bpMem)
|
||||
{
|
||||
memset(bpMem, 0, sizeof(BPMemory));
|
||||
bpMem->bpMask = 0x00FFFFFF;
|
||||
}
|
||||
|
||||
BPCmd DecodeBPCmd(u32 value, const BPMemory &bpMem)
|
||||
BPCmd DecodeBPCmd(u32 value, const BPMemory& bpMem)
|
||||
{
|
||||
//handle the mask register
|
||||
int opcode = value >> 24;
|
||||
|
@ -59,7 +59,7 @@ BPCmd DecodeBPCmd(u32 value, const BPMemory &bpMem)
|
|||
return bp;
|
||||
}
|
||||
|
||||
void LoadBPReg(const BPCmd &bp, BPMemory &bpMem)
|
||||
void LoadBPReg(const BPCmd& bp, BPMemory& bpMem)
|
||||
{
|
||||
((u32*)&bpMem)[bp.address] = bp.newvalue;
|
||||
|
||||
|
@ -68,19 +68,7 @@ void LoadBPReg(const BPCmd &bp, BPMemory &bpMem)
|
|||
bpMem.bpMask = 0xFFFFFF;
|
||||
}
|
||||
|
||||
void GetTlutLoadData(u32 &tlutAddr, u32 &memAddr, u32 &tlutXferCount, BPMemory &bpMem)
|
||||
{
|
||||
tlutAddr = (bpMem.tmem_config.tlut_dest & 0x3FF) << 9;
|
||||
tlutXferCount = (bpMem.tmem_config.tlut_dest & 0x1FFC00) >> 5;
|
||||
|
||||
// TODO - figure out a cleaner way.
|
||||
if (SConfig::GetInstance().bWii)
|
||||
memAddr = bpMem.tmem_config.tlut_src << 5;
|
||||
else
|
||||
memAddr = (bpMem.tmem_config.tlut_src & 0xFFFFF) << 5;
|
||||
}
|
||||
|
||||
void LoadCPReg(u32 subCmd, u32 value, CPMemory &cpMem)
|
||||
void LoadCPReg(u32 subCmd, u32 value, CPMemory& cpMem)
|
||||
{
|
||||
switch (subCmd & 0xF0)
|
||||
{
|
||||
|
@ -119,7 +107,7 @@ void LoadCPReg(u32 subCmd, u32 value, CPMemory &cpMem)
|
|||
}
|
||||
}
|
||||
|
||||
u32 CalculateVertexSize(int vatIndex, const CPMemory &cpMem)
|
||||
u32 CalculateVertexSize(int vatIndex, const CPMemory& cpMem)
|
||||
{
|
||||
u32 vertexSize = 0;
|
||||
|
||||
|
@ -132,7 +120,7 @@ u32 CalculateVertexSize(int vatIndex, const CPMemory &cpMem)
|
|||
return vertexSize;
|
||||
}
|
||||
|
||||
void CalculateVertexElementSizes(int sizes[], int vatIndex, const CPMemory &cpMem)
|
||||
void CalculateVertexElementSizes(int sizes[], int vatIndex, const CPMemory& cpMem)
|
||||
{
|
||||
const TVtxDesc &vtxDesc = cpMem.vtxDesc;
|
||||
const VAT &vtxAttr = cpMem.vtxAttr[vatIndex];
|
||||
|
|
|
@ -13,15 +13,15 @@ namespace FifoAnalyzer
|
|||
{
|
||||
void Init();
|
||||
|
||||
u8 ReadFifo8(u8 *&data);
|
||||
u16 ReadFifo16(u8 *&data);
|
||||
u32 ReadFifo32(u8 *&data);
|
||||
u8 ReadFifo8(u8*& data);
|
||||
u16 ReadFifo16(u8*& data);
|
||||
u32 ReadFifo32(u8*& data);
|
||||
|
||||
// TODO- move to video common
|
||||
void InitBPMemory(BPMemory *bpMem);
|
||||
void InitBPMemory(BPMemory* bpMem);
|
||||
BPCmd DecodeBPCmd(u32 value, const BPMemory &bpMem);
|
||||
void LoadBPReg(const BPCmd &bp, BPMemory &bpMem);
|
||||
void GetTlutLoadData(u32 &tlutAddr, u32 &memAddr, u32 &tlutXferCount, BPMemory &bpMem);
|
||||
void LoadBPReg(const BPCmd& bp, BPMemory &bpMem);
|
||||
void GetTlutLoadData(u32& tlutAddr, u32 &memAddr, u32 &tlutXferCount, BPMemory &bpMem);
|
||||
|
||||
struct CPMemory
|
||||
{
|
||||
|
@ -31,8 +31,8 @@ namespace FifoAnalyzer
|
|||
u32 arrayStrides[16];
|
||||
};
|
||||
|
||||
void LoadCPReg(u32 subCmd, u32 value, CPMemory &cpMem);
|
||||
void LoadCPReg(u32 subCmd, u32 value, CPMemory& cpMem);
|
||||
|
||||
u32 CalculateVertexSize(int vatIndex, const CPMemory &cpMem);
|
||||
void CalculateVertexElementSizes(int sizes[], int vatIndex, const CPMemory &cpMem);
|
||||
u32 CalculateVertexSize(int vatIndex, const CPMemory& cpMem);
|
||||
void CalculateVertexElementSizes(int sizes[], int vatIndex, const CPMemory& cpMem);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,11 @@ FifoDataFile::~FifoDataFile()
|
|||
}
|
||||
}
|
||||
|
||||
bool FifoDataFile::HasBrokenEFBCopies() const
|
||||
{
|
||||
return version < 2;
|
||||
}
|
||||
|
||||
void FifoDataFile::SetIsWii(bool isWii)
|
||||
{
|
||||
SetFlag(FLAG_IS_WII, isWii);
|
||||
|
@ -38,7 +43,7 @@ bool FifoDataFile::GetIsWii() const
|
|||
return GetFlag(FLAG_IS_WII);
|
||||
}
|
||||
|
||||
void FifoDataFile::AddFrame(const FifoFrameInfo &frameInfo)
|
||||
void FifoDataFile::AddFrame(const FifoFrameInfo& frameInfo)
|
||||
{
|
||||
m_Frames.push_back(frameInfo);
|
||||
}
|
||||
|
@ -126,7 +131,7 @@ bool FifoDataFile::Save(const std::string& filename)
|
|||
return true;
|
||||
}
|
||||
|
||||
FifoDataFile *FifoDataFile::Load(const std::string &filename, bool flagsOnly)
|
||||
FifoDataFile* FifoDataFile::Load(const std::string &filename, bool flagsOnly)
|
||||
{
|
||||
File::IOFile file;
|
||||
file.Open(filename, "rb");
|
||||
|
@ -214,7 +219,7 @@ bool FifoDataFile::GetFlag(u32 flag) const
|
|||
return !!(m_Flags & flag);
|
||||
}
|
||||
|
||||
u64 FifoDataFile::WriteMemoryUpdates(const std::vector<MemoryUpdate> &memUpdates, File::IOFile &file)
|
||||
u64 FifoDataFile::WriteMemoryUpdates(const std::vector<MemoryUpdate>& memUpdates, File::IOFile& file)
|
||||
{
|
||||
// Add space for memory update list
|
||||
u64 updateListOffset = file.Tell();
|
||||
|
@ -244,7 +249,7 @@ u64 FifoDataFile::WriteMemoryUpdates(const std::vector<MemoryUpdate> &memUpdates
|
|||
return updateListOffset;
|
||||
}
|
||||
|
||||
void FifoDataFile::ReadMemoryUpdates(u64 fileOffset, u32 numUpdates, std::vector<MemoryUpdate> &memUpdates, File::IOFile &file)
|
||||
void FifoDataFile::ReadMemoryUpdates(u64 fileOffset, u32 numUpdates, std::vector<MemoryUpdate>& memUpdates, File::IOFile& file)
|
||||
{
|
||||
memUpdates.resize(numUpdates);
|
||||
|
||||
|
@ -255,7 +260,7 @@ void FifoDataFile::ReadMemoryUpdates(u64 fileOffset, u32 numUpdates, std::vector
|
|||
FileMemoryUpdate srcUpdate;
|
||||
file.ReadBytes(&srcUpdate, sizeof(FileMemoryUpdate));
|
||||
|
||||
MemoryUpdate &dstUpdate = memUpdates[i];
|
||||
MemoryUpdate& dstUpdate = memUpdates[i];
|
||||
dstUpdate.address = srcUpdate.address;
|
||||
dstUpdate.fifoPosition = srcUpdate.fifoPosition;
|
||||
dstUpdate.size = srcUpdate.dataSize;
|
||||
|
|
|
@ -27,13 +27,13 @@ struct MemoryUpdate
|
|||
u32 fifoPosition;
|
||||
u32 address;
|
||||
u32 size;
|
||||
u8 *data;
|
||||
u8* data;
|
||||
Type type;
|
||||
};
|
||||
|
||||
struct FifoFrameInfo
|
||||
{
|
||||
u8 *fifoData;
|
||||
u8* fifoData;
|
||||
u32 fifoDataSize;
|
||||
|
||||
u32 fifoStart;
|
||||
|
@ -59,6 +59,7 @@ public:
|
|||
|
||||
void SetIsWii(bool isWii);
|
||||
bool GetIsWii() const;
|
||||
bool HasBrokenEFBCopies() const;
|
||||
|
||||
u32 *GetBPMem() { return m_BPMem; }
|
||||
u32 *GetCPMem() { return m_CPMem; }
|
||||
|
@ -71,7 +72,7 @@ public:
|
|||
|
||||
bool Save(const std::string& filename);
|
||||
|
||||
static FifoDataFile *Load(const std::string &filename, bool flagsOnly);
|
||||
static FifoDataFile* Load(const std::string &filename, bool flagsOnly);
|
||||
|
||||
private:
|
||||
enum
|
||||
|
@ -84,8 +85,8 @@ private:
|
|||
void SetFlag(u32 flag, bool set);
|
||||
bool GetFlag(u32 flag) const;
|
||||
|
||||
u64 WriteMemoryUpdates(const std::vector<MemoryUpdate> &memUpdates, File::IOFile &file);
|
||||
static void ReadMemoryUpdates(u64 fileOffset, u32 numUpdates, std::vector<MemoryUpdate> &memUpdates, File::IOFile &file);
|
||||
u64 WriteMemoryUpdates(const std::vector<MemoryUpdate>& memUpdates, File::IOFile &file);
|
||||
static void ReadMemoryUpdates(u64 fileOffset, u32 numUpdates, std::vector<MemoryUpdate>& memUpdates, File::IOFile& file);
|
||||
|
||||
u32 m_BPMem[BP_MEM_SIZE];
|
||||
u32 m_CPMem[CP_MEM_SIZE];
|
||||
|
@ -93,6 +94,7 @@ private:
|
|||
u32 m_XFRegs[XF_REGS_SIZE];
|
||||
|
||||
u32 m_Flags;
|
||||
u32 version;
|
||||
|
||||
std::vector<FifoFrameInfo> m_Frames;
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace FifoFileStruct
|
|||
enum
|
||||
{
|
||||
FILE_ID = 0x0d01f1f0,
|
||||
VERSION_NUMBER = 1,
|
||||
VERSION_NUMBER = 2,
|
||||
MIN_LOADER_VERSION = 1,
|
||||
};
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ struct CmdData
|
|||
{
|
||||
u32 size;
|
||||
u32 offset;
|
||||
u8 *ptr;
|
||||
u8* ptr;
|
||||
};
|
||||
|
||||
FifoPlaybackAnalyzer::FifoPlaybackAnalyzer()
|
||||
|
@ -28,13 +28,13 @@ FifoPlaybackAnalyzer::FifoPlaybackAnalyzer()
|
|||
FifoAnalyzer::Init();
|
||||
}
|
||||
|
||||
void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile *file, std::vector<AnalyzedFrameInfo> &frameInfo)
|
||||
void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile* file, std::vector<AnalyzedFrameInfo>& frameInfo)
|
||||
{
|
||||
// Load BP memory
|
||||
u32 *bpMem = file->GetBPMem();
|
||||
u32* bpMem = file->GetBPMem();
|
||||
memcpy(&m_BpMem, bpMem, sizeof(BPMemory));
|
||||
|
||||
u32 *cpMem = file->GetCPMem();
|
||||
u32* cpMem = file->GetCPMem();
|
||||
FifoAnalyzer::LoadCPReg(0x50, cpMem[0x50], m_CpMem);
|
||||
FifoAnalyzer::LoadCPReg(0x60, cpMem[0x60], m_CpMem);
|
||||
|
||||
|
@ -110,7 +110,7 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile *file, std::vector<Analyze
|
|||
}
|
||||
}
|
||||
|
||||
void FifoPlaybackAnalyzer::AddMemoryUpdate(MemoryUpdate memUpdate, AnalyzedFrameInfo &frameInfo)
|
||||
void FifoPlaybackAnalyzer::AddMemoryUpdate(MemoryUpdate memUpdate, AnalyzedFrameInfo& frameInfo)
|
||||
{
|
||||
u32 begin = memUpdate.address;
|
||||
u32 end = memUpdate.address + memUpdate.size;
|
||||
|
@ -152,9 +152,9 @@ void FifoPlaybackAnalyzer::AddMemoryUpdate(MemoryUpdate memUpdate, AnalyzedFrame
|
|||
frameInfo.memoryUpdates.push_back(memUpdate);
|
||||
}
|
||||
|
||||
u32 FifoPlaybackAnalyzer::DecodeCommand(u8 *data)
|
||||
u32 FifoPlaybackAnalyzer::DecodeCommand(u8* data)
|
||||
{
|
||||
u8 *dataStart = data;
|
||||
u8* dataStart = data;
|
||||
|
||||
int cmd = ReadFifo8(data);
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ class FifoPlaybackAnalyzer
|
|||
public:
|
||||
FifoPlaybackAnalyzer();
|
||||
|
||||
void AnalyzeFrames(FifoDataFile *file, std::vector<AnalyzedFrameInfo> &frameInfo);
|
||||
void AnalyzeFrames(FifoDataFile* file, std::vector<AnalyzedFrameInfo>& frameInfo);
|
||||
|
||||
private:
|
||||
struct MemoryRange
|
||||
|
@ -31,9 +31,9 @@ private:
|
|||
u32 end;
|
||||
};
|
||||
|
||||
void AddMemoryUpdate(MemoryUpdate memUpdate, AnalyzedFrameInfo &frameInfo);
|
||||
void AddMemoryUpdate(MemoryUpdate memUpdate, AnalyzedFrameInfo& frameInfo);
|
||||
|
||||
u32 DecodeCommand(u8 *data);
|
||||
u32 DecodeCommand(u8* data);
|
||||
|
||||
void StoreEfbCopyRegion();
|
||||
void StoreWrittenRegion(u32 address, u32 size);
|
||||
|
|
|
@ -63,8 +63,7 @@ bool FifoPlayer::Play()
|
|||
if (m_File->GetFrameCount() == 0)
|
||||
return false;
|
||||
|
||||
// Currently these is no such thing as a Fifolog without broken EFB copies.
|
||||
IsPlayingBackFifologWithBrokenEFBCopies = true;
|
||||
IsPlayingBackFifologWithBrokenEFBCopies = m_File->HasBrokenEFBCopies();
|
||||
|
||||
m_CurrentFrame = m_FrameRangeStart;
|
||||
|
||||
|
@ -154,7 +153,7 @@ void FifoPlayer::SetFrameRangeEnd(u32 end)
|
|||
}
|
||||
}
|
||||
|
||||
FifoPlayer &FifoPlayer::GetInstance()
|
||||
FifoPlayer& FifoPlayer::GetInstance()
|
||||
{
|
||||
static FifoPlayer instance;
|
||||
return instance;
|
||||
|
@ -174,7 +173,7 @@ FifoPlayer::FifoPlayer() :
|
|||
m_Loop = SConfig::GetInstance().bLoopFifoReplay;
|
||||
}
|
||||
|
||||
void FifoPlayer::WriteFrame(const FifoFrameInfo &frame, const AnalyzedFrameInfo &info)
|
||||
void FifoPlayer::WriteFrame(const FifoFrameInfo& frame, const AnalyzedFrameInfo& info)
|
||||
{
|
||||
// Core timing information
|
||||
m_CyclesPerFrame = SystemTimers::GetTicksPerSecond() / VideoInterface::TargetRefreshRate;
|
||||
|
@ -233,9 +232,9 @@ void FifoPlayer::WriteFrame(const FifoFrameInfo &frame, const AnalyzedFrameInfo
|
|||
FlushWGP();
|
||||
}
|
||||
|
||||
void FifoPlayer::WriteFramePart(u32 dataStart, u32 dataEnd, u32 &nextMemUpdate, const FifoFrameInfo &frame, const AnalyzedFrameInfo &info)
|
||||
void FifoPlayer::WriteFramePart(u32 dataStart, u32 dataEnd, u32& nextMemUpdate, const FifoFrameInfo& frame, const AnalyzedFrameInfo& info)
|
||||
{
|
||||
u8 *data = frame.fifoData;
|
||||
u8* data = frame.fifoData;
|
||||
|
||||
while (nextMemUpdate < frame.memoryUpdates.size() && dataStart < dataEnd)
|
||||
{
|
||||
|
@ -290,7 +289,7 @@ void FifoPlayer::WriteMemory(const MemoryUpdate& memUpdate)
|
|||
memcpy(mem, memUpdate.data, memUpdate.size);
|
||||
}
|
||||
|
||||
void FifoPlayer::WriteFifo(u8 *data, u32 start, u32 end)
|
||||
void FifoPlayer::WriteFifo(u8* data, u32 start, u32 end)
|
||||
{
|
||||
u32 written = start;
|
||||
u32 lastBurstEnd = end - 1;
|
||||
|
@ -453,7 +452,7 @@ void FifoPlayer::LoadXFReg(u16 reg, u32 value)
|
|||
GPFifo::Write32(value);
|
||||
}
|
||||
|
||||
void FifoPlayer::LoadXFMem16(u16 address, u32 *data)
|
||||
void FifoPlayer::LoadXFMem16(u16 address, u32* data)
|
||||
{
|
||||
// Loads 16 * 4 bytes in xf memory starting at address
|
||||
GPFifo::Write8(0x10); // load XF reg
|
||||
|
|
|
@ -87,15 +87,15 @@ public:
|
|||
private:
|
||||
FifoPlayer();
|
||||
|
||||
void WriteFrame(const FifoFrameInfo &frame, const AnalyzedFrameInfo &info);
|
||||
void WriteFramePart(u32 dataStart, u32 dataEnd, u32 &nextMemUpdate, const FifoFrameInfo &frame, const AnalyzedFrameInfo &info);
|
||||
void WriteFrame(const FifoFrameInfo& frame, const AnalyzedFrameInfo &info);
|
||||
void WriteFramePart(u32 dataStart, u32 dataEnd, u32 &nextMemUpdate, const FifoFrameInfo& frame, const AnalyzedFrameInfo& info);
|
||||
|
||||
void WriteAllMemoryUpdates();
|
||||
void WriteMemory(const MemoryUpdate &memUpdate);
|
||||
|
||||
// writes a range of data to the fifo
|
||||
// start and end must be relative to frame's fifo data so elapsed cycles are figured correctly
|
||||
void WriteFifo(u8 *data, u32 start, u32 end);
|
||||
void WriteFifo(u8* data, u32 start, u32 end);
|
||||
|
||||
void SetupFifo();
|
||||
|
||||
|
@ -131,7 +131,7 @@ private:
|
|||
CallbackFunc m_FileLoadedCb;
|
||||
CallbackFunc m_FrameWrittenCb;
|
||||
|
||||
FifoDataFile *m_File;
|
||||
FifoDataFile* m_File;
|
||||
|
||||
std::vector<AnalyzedFrameInfo> m_FrameInfo;
|
||||
};
|
||||
|
|
|
@ -22,7 +22,7 @@ FifoRecordAnalyzer::FifoRecordAnalyzer() :
|
|||
{
|
||||
}
|
||||
|
||||
void FifoRecordAnalyzer::Initialize(u32 *bpMem, u32 *cpMem)
|
||||
void FifoRecordAnalyzer::Initialize(u32* bpMem, u32* cpMem)
|
||||
{
|
||||
m_DrawingObject = false;
|
||||
|
||||
|
@ -37,12 +37,12 @@ void FifoRecordAnalyzer::Initialize(u32 *bpMem, u32 *cpMem)
|
|||
memcpy(m_CpMem.arrayStrides, cpMem + 0xB0, 16 * 4);
|
||||
}
|
||||
|
||||
void FifoRecordAnalyzer::AnalyzeGPCommand(u8 *data)
|
||||
void FifoRecordAnalyzer::AnalyzeGPCommand(u8* data)
|
||||
{
|
||||
DecodeOpcode(data);
|
||||
}
|
||||
|
||||
void FifoRecordAnalyzer::DecodeOpcode(u8 *data)
|
||||
void FifoRecordAnalyzer::DecodeOpcode(u8* data)
|
||||
{
|
||||
int cmd = ReadFifo8(data);
|
||||
|
||||
|
@ -99,11 +99,6 @@ void FifoRecordAnalyzer::DecodeOpcode(u8 *data)
|
|||
|
||||
u32 cmd2 = ReadFifo32(data);
|
||||
BPCmd bp = FifoAnalyzer::DecodeBPCmd(cmd2, *m_BpMem);
|
||||
|
||||
if (bp.address == BPMEM_LOADTLUT1)
|
||||
ProcessLoadTlut1();
|
||||
if (bp.address == BPMEM_PRELOAD_MODE)
|
||||
ProcessPreloadTexture();
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -113,7 +108,6 @@ void FifoRecordAnalyzer::DecodeOpcode(u8 *data)
|
|||
if (!m_DrawingObject)
|
||||
{
|
||||
m_DrawingObject = true;
|
||||
ProcessTexMaps();
|
||||
}
|
||||
|
||||
ProcessVertexArrays(data, cmd & GX_VAT_MASK);
|
||||
|
@ -125,26 +119,6 @@ void FifoRecordAnalyzer::DecodeOpcode(u8 *data)
|
|||
}
|
||||
}
|
||||
|
||||
void FifoRecordAnalyzer::ProcessLoadTlut1()
|
||||
{
|
||||
u32 tlutXferCount;
|
||||
u32 tlutMemAddr;
|
||||
u32 memAddr;
|
||||
|
||||
GetTlutLoadData(tlutMemAddr, memAddr, tlutXferCount, *m_BpMem);
|
||||
|
||||
FifoRecorder::GetInstance().WriteMemory(memAddr, tlutXferCount, MemoryUpdate::TMEM);
|
||||
}
|
||||
|
||||
void FifoRecordAnalyzer::ProcessPreloadTexture()
|
||||
{
|
||||
BPS_TmemConfig& tmem_cfg = m_BpMem->tmem_config;
|
||||
//u32 tmem_addr = tmem_cfg.preload_tmem_even * TMEM_LINE_SIZE;
|
||||
u32 size = tmem_cfg.preload_tile_info.count * TMEM_LINE_SIZE; // TODO: Should this be half size for RGBA8 preloads?
|
||||
|
||||
FifoRecorder::GetInstance().WriteMemory(tmem_cfg.preload_addr << 5, size, MemoryUpdate::TMEM);
|
||||
}
|
||||
|
||||
void FifoRecordAnalyzer::ProcessLoadIndexedXf(u32 val, int array)
|
||||
{
|
||||
int index = val >> 16;
|
||||
|
@ -152,10 +126,10 @@ void FifoRecordAnalyzer::ProcessLoadIndexedXf(u32 val, int array)
|
|||
|
||||
u32 address = m_CpMem.arrayBases[array] + m_CpMem.arrayStrides[array] * index;
|
||||
|
||||
FifoRecorder::GetInstance().WriteMemory(address, size * 4, MemoryUpdate::XF_DATA);
|
||||
FifoRecorder::GetInstance().UseMemory(address, size * 4, MemoryUpdate::XF_DATA);
|
||||
}
|
||||
|
||||
void FifoRecordAnalyzer::ProcessVertexArrays(u8 *data, u8 vtxAttrGroup)
|
||||
void FifoRecordAnalyzer::ProcessVertexArrays(u8* data, u8 vtxAttrGroup)
|
||||
{
|
||||
int sizes[21];
|
||||
FifoAnalyzer::CalculateVertexElementSizes(sizes, vtxAttrGroup, m_CpMem);
|
||||
|
@ -181,7 +155,7 @@ void FifoRecordAnalyzer::ProcessVertexArrays(u8 *data, u8 vtxAttrGroup)
|
|||
}
|
||||
}
|
||||
|
||||
void FifoRecordAnalyzer::WriteVertexArray(int arrayIndex, u8 *vertexData, int vertexSize, int numVertices)
|
||||
void FifoRecordAnalyzer::WriteVertexArray(int arrayIndex, u8* vertexData, int vertexSize, int numVertices)
|
||||
{
|
||||
// Skip if not indexed array
|
||||
int arrayType = (m_CpMem.vtxDesc.Hex >> (9 + (arrayIndex * 2))) & 3;
|
||||
|
@ -225,80 +199,5 @@ void FifoRecordAnalyzer::WriteVertexArray(int arrayIndex, u8 *vertexData, int ve
|
|||
u32 arrayStart = m_CpMem.arrayBases[arrayIndex];
|
||||
u32 arraySize = m_CpMem.arrayStrides[arrayIndex] * (maxIndex + 1);
|
||||
|
||||
FifoRecorder::GetInstance().WriteMemory(arrayStart, arraySize, MemoryUpdate::VERTEX_STREAM);
|
||||
}
|
||||
|
||||
void FifoRecordAnalyzer::ProcessTexMaps()
|
||||
{
|
||||
u32 writtenTexMaps = 0;
|
||||
|
||||
// Texture maps used in TEV indirect stages
|
||||
for (u32 i = 0; i < m_BpMem->genMode.numindstages; ++i)
|
||||
{
|
||||
u32 texMap = m_BpMem->tevindref.getTexMap(i);
|
||||
|
||||
WriteTexMapMemory(texMap, writtenTexMaps);
|
||||
}
|
||||
|
||||
// Texture maps used in TEV direct stages
|
||||
for (u32 i = 0; i <= m_BpMem->genMode.numtevstages; ++i)
|
||||
{
|
||||
int stageNum2 = i >> 1;
|
||||
int stageOdd = i & 1;
|
||||
TwoTevStageOrders &order = m_BpMem->tevorders[stageNum2];
|
||||
int texMap = order.getTexMap(stageOdd);
|
||||
|
||||
if (order.getEnable(stageOdd))
|
||||
WriteTexMapMemory(texMap, writtenTexMaps);
|
||||
}
|
||||
}
|
||||
|
||||
void FifoRecordAnalyzer::WriteTexMapMemory(int texMap, u32 &writtenTexMaps)
|
||||
{
|
||||
// Avoid rechecking the same texture map
|
||||
u32 texMapMask = 1 << texMap;
|
||||
if (writtenTexMaps & texMapMask)
|
||||
return;
|
||||
|
||||
writtenTexMaps |= texMapMask;
|
||||
|
||||
FourTexUnits& texUnit = m_BpMem->tex[(texMap >> 2) & 1];
|
||||
u8 subTexmap = texMap & 3;
|
||||
|
||||
TexImage0& ti0 = texUnit.texImage0[subTexmap];
|
||||
|
||||
u32 width = ti0.width + 1;
|
||||
u32 height = ti0.height + 1;
|
||||
u32 imageBase = texUnit.texImage3[subTexmap].image_base << 5;
|
||||
|
||||
u32 fmtWidth = TexDecoder_GetBlockWidthInTexels(ti0.format) - 1;
|
||||
u32 fmtHeight = TexDecoder_GetBlockHeightInTexels(ti0.format) - 1;
|
||||
int fmtDepth = TexDecoder_GetTexelSizeInNibbles(ti0.format);
|
||||
|
||||
// Round width and height up to the next block
|
||||
width = (width + fmtWidth) & (~fmtWidth);
|
||||
height = (height + fmtHeight) & (~fmtHeight);
|
||||
|
||||
u32 textureSize = (width * height * fmtDepth) / 2;
|
||||
|
||||
// TODO: mip maps
|
||||
int mip = texUnit.texMode1[subTexmap].max_lod;
|
||||
if ((texUnit.texMode0[subTexmap].min_filter & 3) == 0)
|
||||
mip = 0;
|
||||
|
||||
while (mip)
|
||||
{
|
||||
width >>= 1;
|
||||
height >>= 1;
|
||||
|
||||
width = std::max(width, fmtWidth);
|
||||
height = std::max(height, fmtHeight);
|
||||
u32 size = (width * height * fmtDepth) >> 1;
|
||||
|
||||
textureSize += size;
|
||||
|
||||
mip--;
|
||||
}
|
||||
|
||||
FifoRecorder::GetInstance().WriteMemory(imageBase, textureSize, MemoryUpdate::TEXTURE_MAP);
|
||||
FifoRecorder::GetInstance().UseMemory(arrayStart, arraySize, MemoryUpdate::VERTEX_STREAM);
|
||||
}
|
||||
|
|
|
@ -16,26 +16,22 @@ public:
|
|||
FifoRecordAnalyzer();
|
||||
|
||||
// Must call this before analyzing GP commands
|
||||
void Initialize(u32 *bpMem, u32 *cpMem);
|
||||
void Initialize(u32* bpMem, u32* cpMem);
|
||||
|
||||
// Assumes data contains all information for the command
|
||||
// Calls FifoRecorder::WriteMemory
|
||||
void AnalyzeGPCommand(u8 *data);
|
||||
// Calls FifoRecorder::UseMemory
|
||||
void AnalyzeGPCommand(u8* data);
|
||||
|
||||
private:
|
||||
void DecodeOpcode(u8 *data);
|
||||
void DecodeOpcode(u8* data);
|
||||
|
||||
void ProcessLoadTlut1();
|
||||
void ProcessPreloadTexture();
|
||||
void ProcessLoadIndexedXf(u32 val, int array);
|
||||
void ProcessVertexArrays(u8 *data, u8 vtxAttrGroup);
|
||||
void ProcessTexMaps();
|
||||
void ProcessVertexArrays(u8* data, u8 vtxAttrGroup);
|
||||
|
||||
void WriteVertexArray(int arrayIndex, u8 *vertexData, int vertexSize, int numVertices);
|
||||
void WriteTexMapMemory(int texMap, u32 &writtenTexMaps);
|
||||
void WriteVertexArray(int arrayIndex, u8* vertexData, int vertexSize, int numVertices);
|
||||
|
||||
bool m_DrawingObject;
|
||||
|
||||
BPMemory *m_BpMem;
|
||||
BPMemory* m_BpMem;
|
||||
FifoAnalyzer::CPMemory m_CpMem;
|
||||
};
|
||||
|
|
|
@ -64,7 +64,7 @@ void FifoRecorder::StopRecording()
|
|||
m_RequestedRecordingEnd = true;
|
||||
}
|
||||
|
||||
void FifoRecorder::WriteGPCommand(u8 *data, u32 size)
|
||||
void FifoRecorder::WriteGPCommand(u8* data, u32 size)
|
||||
{
|
||||
if (!m_SkipNextData)
|
||||
{
|
||||
|
@ -102,10 +102,10 @@ void FifoRecorder::WriteGPCommand(u8 *data, u32 size)
|
|||
m_SkipNextData = m_SkipFutureData;
|
||||
}
|
||||
|
||||
void FifoRecorder::WriteMemory(u32 address, u32 size, MemoryUpdate::Type type)
|
||||
void FifoRecorder::UseMemory(u32 address, u32 size, MemoryUpdate::Type type, bool dynamicUpdate)
|
||||
{
|
||||
u8 *curData;
|
||||
u8 *newData;
|
||||
u8* curData;
|
||||
u8* newData;
|
||||
if (address & 0x10000000)
|
||||
{
|
||||
curData = &m_ExRam[address & Memory::EXRAM_MASK];
|
||||
|
@ -117,7 +117,7 @@ void FifoRecorder::WriteMemory(u32 address, u32 size, MemoryUpdate::Type type)
|
|||
newData = &Memory::m_pRAM[address & Memory::RAM_MASK];
|
||||
}
|
||||
|
||||
if (memcmp(curData, newData, size) != 0)
|
||||
if (!dynamicUpdate && memcmp(curData, newData, size) != 0)
|
||||
{
|
||||
// Update current memory
|
||||
memcpy(curData, newData, size);
|
||||
|
@ -133,6 +133,11 @@ void FifoRecorder::WriteMemory(u32 address, u32 size, MemoryUpdate::Type type)
|
|||
|
||||
m_CurrentFrame.memoryUpdates.push_back(memUpdate);
|
||||
}
|
||||
else if (dynamicUpdate)
|
||||
{
|
||||
// Shadow the data so it won't be recorded as changed by a future UseMemory
|
||||
memcpy(curData, newData, size);
|
||||
}
|
||||
}
|
||||
|
||||
void FifoRecorder::EndFrame(u32 fifoStart, u32 fifoEnd)
|
||||
|
@ -200,7 +205,7 @@ void FifoRecorder::SetVideoMemory(u32 *bpMem, u32 *cpMem, u32 *xfMem, u32 *xfReg
|
|||
sMutex.unlock();
|
||||
}
|
||||
|
||||
FifoRecorder &FifoRecorder::GetInstance()
|
||||
FifoRecorder& FifoRecorder::GetInstance()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
|
|
@ -20,25 +20,28 @@ public:
|
|||
void StartRecording(s32 numFrames, CallbackFunc finishedCb);
|
||||
void StopRecording();
|
||||
|
||||
FifoDataFile *GetRecordedFile() { return m_File; }
|
||||
FifoDataFile* GetRecordedFile() { return m_File; }
|
||||
|
||||
// Called from video thread
|
||||
|
||||
// Must write one full GP command at a time
|
||||
void WriteGPCommand(u8 *data, u32 size);
|
||||
void WriteGPCommand(u8* data, u32 size);
|
||||
|
||||
void WriteMemory(u32 address, u32 size, MemoryUpdate::Type type);
|
||||
// Track memory that has been used and write it to the fifolog if it has changed.
|
||||
// If memory is updated by the video backend (dynamicUpdate == true) take special care to make sure the data
|
||||
// isn't baked into the fifolog.
|
||||
void UseMemory(u32 address, u32 size, MemoryUpdate::Type type, bool dynamicUpdate = false);
|
||||
|
||||
void EndFrame(u32 fifoStart, u32 fifoEnd);
|
||||
|
||||
// This function must be called before writing GP commands
|
||||
// bpMem must point to the actual bp mem array used by the plugin because it will be read as fifo data is recorded
|
||||
void SetVideoMemory(u32 *bpMem, u32 *cpMem, u32 *xfMem, u32 *xfRegs, u32 xfRegsSize);
|
||||
void SetVideoMemory(u32* bpMem, u32* cpMem, u32* xfMem, u32* xfRegs, u32 xfRegsSize);
|
||||
|
||||
// Checked once per frame prior to callng EndFrame()
|
||||
bool IsRecording() const { return m_IsRecording; }
|
||||
|
||||
static FifoRecorder &GetInstance();
|
||||
static FifoRecorder& GetInstance();
|
||||
|
||||
private:
|
||||
// Accessed from both GUI and video threads
|
||||
|
@ -51,7 +54,7 @@ private:
|
|||
volatile s32 m_RecordFramesRemaining;
|
||||
volatile CallbackFunc m_FinishedCb;
|
||||
|
||||
FifoDataFile *volatile m_File;
|
||||
FifoDataFile* volatile m_File;
|
||||
|
||||
// Accessed only from video thread
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "Common/Thread.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/FifoPlayer/FifoRecorder.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
|
||||
#include "VideoCommon/BoundingBox.h"
|
||||
|
@ -281,6 +282,9 @@ static void BPWritten(const BPCmd& bp)
|
|||
|
||||
Memory::CopyFromEmu(texMem + tlutTMemAddr, addr, tlutXferCount);
|
||||
|
||||
if (g_bRecordFifoData)
|
||||
FifoRecorder::GetInstance().UseMemory(addr, tlutXferCount, MemoryUpdate::TMEM);
|
||||
|
||||
return;
|
||||
}
|
||||
case BPMEM_FOGRANGE: // Fog Settings Control
|
||||
|
@ -455,15 +459,16 @@ static void BPWritten(const BPCmd& bp)
|
|||
|
||||
BPS_TmemConfig& tmem_cfg = bpmem.tmem_config;
|
||||
u32 src_addr = tmem_cfg.preload_addr << 5; // TODO: Should we add mask here on GC?
|
||||
u32 size = tmem_cfg.preload_tile_info.count * TMEM_LINE_SIZE;
|
||||
u32 bytes_read = 0;
|
||||
u32 tmem_addr_even = tmem_cfg.preload_tmem_even * TMEM_LINE_SIZE;
|
||||
|
||||
if (tmem_cfg.preload_tile_info.type != 3)
|
||||
{
|
||||
if (tmem_addr_even + size > TMEM_SIZE)
|
||||
size = TMEM_SIZE - tmem_addr_even;
|
||||
bytes_read = tmem_cfg.preload_tile_info.count * TMEM_LINE_SIZE;
|
||||
if (tmem_addr_even + bytes_read > TMEM_SIZE)
|
||||
bytes_read = TMEM_SIZE - tmem_addr_even;
|
||||
|
||||
Memory::CopyFromEmu(texMem + tmem_addr_even, src_addr, size);
|
||||
Memory::CopyFromEmu(texMem + tmem_addr_even, src_addr, bytes_read);
|
||||
}
|
||||
else // RGBA8 tiles (and CI14, but that might just be stupid libogc!)
|
||||
{
|
||||
|
@ -471,21 +476,23 @@ static void BPWritten(const BPCmd& bp)
|
|||
|
||||
// AR and GB tiles are stored in separate TMEM banks => can't use a single memcpy for everything
|
||||
u32 tmem_addr_odd = tmem_cfg.preload_tmem_odd * TMEM_LINE_SIZE;
|
||||
u32 bytes_read = 0;
|
||||
|
||||
for (u32 i = 0; i < tmem_cfg.preload_tile_info.count; ++i)
|
||||
{
|
||||
if (tmem_addr_even + TMEM_LINE_SIZE > TMEM_SIZE ||
|
||||
tmem_addr_odd + TMEM_LINE_SIZE > TMEM_SIZE)
|
||||
return;
|
||||
if (tmem_addr_even + TMEM_LINE_SIZE > TMEM_SIZE || tmem_addr_odd + TMEM_LINE_SIZE > TMEM_SIZE)
|
||||
break;
|
||||
|
||||
// TODO: This isn't very optimised, does a whole lot of small memcpys
|
||||
memcpy(texMem + tmem_addr_even, src_ptr, TMEM_LINE_SIZE);
|
||||
memcpy(texMem + tmem_addr_odd, src_ptr + TMEM_LINE_SIZE, TMEM_LINE_SIZE);
|
||||
memcpy(texMem + tmem_addr_even, src_ptr + bytes_read, TMEM_LINE_SIZE);
|
||||
memcpy(texMem + tmem_addr_odd, src_ptr + bytes_read + TMEM_LINE_SIZE, TMEM_LINE_SIZE);
|
||||
tmem_addr_even += TMEM_LINE_SIZE;
|
||||
tmem_addr_odd += TMEM_LINE_SIZE;
|
||||
src_ptr += TMEM_LINE_SIZE * 2;
|
||||
bytes_read += TMEM_LINE_SIZE * 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_bRecordFifoData)
|
||||
FifoRecorder::GetInstance().UseMemory(src_addr, bytes_read, MemoryUpdate::TMEM);
|
||||
}
|
||||
return;
|
||||
|
||||
|
|
|
@ -38,8 +38,6 @@
|
|||
#define GX_DRAW_LINE_STRIP 0x6 // 0xB0
|
||||
#define GX_DRAW_POINTS 0x7 // 0xB8
|
||||
|
||||
extern bool g_bRecordFifoData;
|
||||
|
||||
void OpcodeDecoder_Init();
|
||||
void OpcodeDecoder_Shutdown();
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/FifoPlayer/FifoPlayer.h"
|
||||
#include "Core/FifoPlayer/FifoRecorder.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
|
||||
#include "VideoCommon/Debugger.h"
|
||||
|
@ -19,6 +20,7 @@
|
|||
#include "VideoCommon/RenderBase.h"
|
||||
#include "VideoCommon/Statistics.h"
|
||||
#include "VideoCommon/TextureCacheBase.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
static const u64 TEXHASH_INVALID = 0;
|
||||
|
@ -395,6 +397,25 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
|
|||
full_format = texformat | (tlutfmt << 16);
|
||||
|
||||
const u32 texture_size = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, texformat);
|
||||
u32 additional_mips_size = 0; // not including level 0, which is texture_size
|
||||
|
||||
// GPUs don't like when the specified mipmap count would require more than one 1x1-sized LOD in the mipmap chain
|
||||
// e.g. 64x64 with 7 LODs would have the mipmap chain 64x64,32x32,16x16,8x8,4x4,2x2,1x1,0x0, so we limit the mipmap count to 6 there
|
||||
tex_levels = std::min<u32>(IntLog2(std::max(width, height)) + 1, tex_levels);
|
||||
|
||||
for (u32 level = 1; level != tex_levels; ++level)
|
||||
{
|
||||
// We still need to calculate the original size of the mips
|
||||
const u32 expanded_mip_width = ROUND_UP(CalculateLevelSize(width, level), bsw);
|
||||
const u32 expanded_mip_height = ROUND_UP(CalculateLevelSize(height, level), bsh);
|
||||
|
||||
additional_mips_size += TexDecoder_GetTextureSizeInBytes(expanded_mip_width, expanded_mip_height, texformat);
|
||||
}
|
||||
|
||||
// If we are recording a FifoLog, keep track of what memory we read.
|
||||
// FifiRecorder does it's own memory modification tracking independant of the texture hashing below.
|
||||
if (g_bRecordFifoData && !from_tmem)
|
||||
FifoRecorder::GetInstance().UseMemory(address, texture_size + additional_mips_size, MemoryUpdate::TEXTURE_MAP);
|
||||
|
||||
const u8* src_data;
|
||||
if (from_tmem)
|
||||
|
@ -415,10 +436,6 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
|
|||
full_hash = base_hash;
|
||||
}
|
||||
|
||||
// GPUs don't like when the specified mipmap count would require more than one 1x1-sized LOD in the mipmap chain
|
||||
// e.g. 64x64 with 7 LODs would have the mipmap chain 64x64,32x32,16x16,8x8,4x4,2x2,1x1,0x0, so we limit the mipmap count to 6 there
|
||||
tex_levels = std::min<u32>(IntLog2(std::max(width, height)) + 1, tex_levels);
|
||||
|
||||
// Search the texture cache for textures by address
|
||||
//
|
||||
// Find all texture cache entries for the current texture address, and decide whether to use one of
|
||||
|
@ -740,7 +757,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
|
|||
//
|
||||
// For historical reasons, Dolphin doesn't actually implement "pure" EFB to RAM emulation, but only EFB to texture and hybrid EFB copies.
|
||||
|
||||
float colmat[28] = {0};
|
||||
float colmat[28] = { 0 };
|
||||
float *const fConstAdd = colmat + 16;
|
||||
float *const ColorMask = colmat + 20;
|
||||
ColorMask[0] = ColorMask[1] = ColorMask[2] = ColorMask[3] = 255.0f;
|
||||
|
@ -1058,6 +1075,17 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
|
|||
count++), 0);
|
||||
}
|
||||
|
||||
if (g_bRecordFifoData)
|
||||
{
|
||||
// Mark the memory behind this efb copy as dynamicly generated for the Fifo log
|
||||
u32 address = dstAddr;
|
||||
for (u32 i = 0; i < entry->NumBlocksY(); i++)
|
||||
{
|
||||
FifoRecorder::GetInstance().UseMemory(address, entry->CacheLinesPerRow() * 32, MemoryUpdate::TEXTURE_MAP, true);
|
||||
address += entry->memory_stride;
|
||||
}
|
||||
}
|
||||
|
||||
textures_by_address.emplace((u64)dstAddr, entry);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
#include "Common/MathUtil.h"
|
||||
#include "VideoCommon/VideoBackendBase.h"
|
||||
|
||||
// Global flag to signal if FifoRecorder is active.
|
||||
extern bool g_bRecordFifoData;
|
||||
|
||||
// These are accurate (disregarding AA modes).
|
||||
enum
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue