diff --git a/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp b/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp index e64c48f52e..332cd29959 100644 --- a/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp @@ -8,6 +8,9 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/FifoPlayer/FifoAnalyzer.h" +#include "Core/FifoPlayer/FifoPlaybackAnalyzer.h" +#include "Core/FifoPlayer/FifoRecordAnalyzer.h" +#include "VideoCommon/OpcodeDecoding.h" #include "VideoCommon/VertexLoader.h" #include "VideoCommon/VertexLoader_Normal.h" #include "VideoCommon/VertexLoader_Position.h" @@ -16,6 +19,10 @@ namespace FifoAnalyzer { +bool s_DrawingObject; +BPMemory s_BpMem; +FifoAnalyzer::CPMemory s_CpMem; + void Init() { VertexLoader_Normal::Init(); @@ -42,6 +49,123 @@ u32 ReadFifo32(u8*& data) return value; } +u32 AnalyzeCommand(u8* data, DecodeMode mode) +{ + u8* dataStart = data; + + int cmd = ReadFifo8(data); + + switch (cmd) + { + case GX_NOP: + case 0x44: + case GX_CMD_INVL_VC: + break; + + case GX_LOAD_CP_REG: + { + s_DrawingObject = false; + + u32 cmd2 = ReadFifo8(data); + u32 value = ReadFifo32(data); + LoadCPReg(cmd2, value, s_CpMem); + break; + } + + case GX_LOAD_XF_REG: + { + s_DrawingObject = false; + + u32 cmd2 = ReadFifo32(data); + u8 streamSize = ((cmd2 >> 16) & 15) + 1; + + data += streamSize * 4; + break; + } + + case GX_LOAD_INDX_A: + case GX_LOAD_INDX_B: + case GX_LOAD_INDX_C: + case GX_LOAD_INDX_D: + { + s_DrawingObject = false; + + int array = 0xc + (cmd - GX_LOAD_INDX_A) / 8; + u32 value = ReadFifo32(data); + + if (mode == DECODE_RECORD) + FifoRecordAnalyzer::ProcessLoadIndexedXf(value, array); + break; + } + + case GX_CMD_CALL_DL: + // The recorder should have expanded display lists into the fifo stream and skipped the call to start them + // That is done to make it easier to track where memory is updated + _assert_(false); + data += 8; + break; + + case GX_LOAD_BP_REG: + { + s_DrawingObject = false; + u32 cmd2 = ReadFifo32(data); + + if (mode == DECODE_PLAYBACK) + { + BPCmd bp = DecodeBPCmd(cmd2, s_BpMem); + + LoadBPReg(bp, s_BpMem); + + if (bp.address == BPMEM_TRIGGER_EFB_COPY) + { + FifoPlaybackAnalyzer::StoreEfbCopyRegion(); + } + } + break; + } + + default: + if (cmd & 0x80) + { + s_DrawingObject = true; + + int sizes[21]; + FifoAnalyzer::CalculateVertexElementSizes(sizes, cmd & GX_VAT_MASK, s_CpMem); + + // Determine offset of each element that might be a vertex array + // The first 9 elements are never vertex arrays so we just accumulate their sizes. + int offsets[12]; + int offset = std::accumulate(&sizes[0], &sizes[9], 0u); + for (int i = 0; i < 12; ++i) + { + offsets[i] = offset; + offset += sizes[i + 9]; + } + + int vertexSize = offset; + int numVertices = ReadFifo16(data); + + if (mode == DECODE_RECORD && numVertices > 0) + { + for (int i = 0; i < 12; ++i) + { + FifoRecordAnalyzer::WriteVertexArray(i, data + offsets[i], vertexSize, numVertices); + } + } + + data += numVertices * vertexSize; + } + else + { + PanicAlert("FifoPlayer: Unknown Opcode (0x%x).\n", cmd); + return 0; + } + break; + } + + return (u32)(data - dataStart); +} + void InitBPMemory(BPMemory* bpMem) { memset(bpMem, 0, sizeof(BPMemory)); @@ -109,14 +233,6 @@ void LoadCPReg(u32 subCmd, u32 value, CPMemory& cpMem) } } -u32 CalculateVertexSize(int vatIndex, const CPMemory& cpMem) -{ - int sizes[21]; - CalculateVertexElementSizes(sizes, vatIndex, cpMem); - - return std::accumulate(std::begin(sizes), std::end(sizes), 0U); -} - void CalculateVertexElementSizes(int sizes[], int vatIndex, const CPMemory& cpMem) { const TVtxDesc &vtxDesc = cpMem.vtxDesc; diff --git a/Source/Core/Core/FifoPlayer/FifoAnalyzer.h b/Source/Core/Core/FifoPlayer/FifoAnalyzer.h index e853d697bf..f15f8cc97e 100644 --- a/Source/Core/Core/FifoPlayer/FifoAnalyzer.h +++ b/Source/Core/Core/FifoPlayer/FifoAnalyzer.h @@ -17,6 +17,14 @@ namespace FifoAnalyzer u16 ReadFifo16(u8*& data); u32 ReadFifo32(u8*& data); + enum DecodeMode + { + DECODE_RECORD, + DECODE_PLAYBACK, + }; + + u32 AnalyzeCommand(u8* data, DecodeMode mode); + // TODO- move to video common void InitBPMemory(BPMemory* bpMem); BPCmd DecodeBPCmd(u32 value, const BPMemory &bpMem); @@ -32,6 +40,9 @@ namespace FifoAnalyzer void LoadCPReg(u32 subCmd, u32 value, CPMemory& cpMem); - u32 CalculateVertexSize(int vatIndex, const CPMemory& cpMem); void CalculateVertexElementSizes(int sizes[], int vatIndex, const CPMemory& cpMem); + + extern bool s_DrawingObject; + extern BPMemory s_BpMem; + extern FifoAnalyzer::CPMemory s_CpMem; } diff --git a/Source/Core/Core/FifoPlayer/FifoFileStruct.h b/Source/Core/Core/FifoPlayer/FifoFileStruct.h index 4cf81aca72..1a2f129a23 100644 --- a/Source/Core/Core/FifoPlayer/FifoFileStruct.h +++ b/Source/Core/Core/FifoPlayer/FifoFileStruct.h @@ -12,7 +12,7 @@ namespace FifoFileStruct enum { FILE_ID = 0x0d01f1f0, - VERSION_NUMBER = 2, + VERSION_NUMBER = 3, MIN_LOADER_VERSION = 1, }; diff --git a/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.cpp b/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.cpp index cdc103bff2..914e544549 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.cpp @@ -29,13 +29,8 @@ struct MemoryRange }; static std::vector s_WrittenMemory; -static BPMemory s_BpMem; -static FifoAnalyzer::CPMemory s_CpMem; -static bool s_DrawingObject; static void AddMemoryUpdate(MemoryUpdate memUpdate, AnalyzedFrameInfo& frameInfo); -static u32 DecodeCommand(u8* data); -static void StoreEfbCopyRegion(); static void StoreWrittenRegion(u32 address, u32 size); void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile* file, std::vector& frameInfo) @@ -84,7 +79,7 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile* file, std::vector> 16) & 15) + 1; - - data += streamSize * 4; - } - break; - - case GX_LOAD_INDX_A: - case GX_LOAD_INDX_B: - case GX_LOAD_INDX_C: - case GX_LOAD_INDX_D: - s_DrawingObject = false; - data += 4; - break; - - case GX_CMD_CALL_DL: - // The recorder should have expanded display lists into the fifo stream and skipped the call to start them - // That is done to make it easier to track where memory is updated - _assert_(false); - data += 8; - break; - - case GX_LOAD_BP_REG: - { - s_DrawingObject = false; - - u32 cmd2 = ReadFifo32(data); - BPCmd bp = FifoAnalyzer::DecodeBPCmd(cmd2, s_BpMem); - - FifoAnalyzer::LoadBPReg(bp, s_BpMem); - - if (bp.address == BPMEM_TRIGGER_EFB_COPY) - { - StoreEfbCopyRegion(); - } - } - break; - - default: - if (cmd & 0x80) - { - s_DrawingObject = true; - - u32 vtxAttrGroup = cmd & GX_VAT_MASK; - int vertexSize = FifoAnalyzer::CalculateVertexSize(vtxAttrGroup, s_CpMem); - - u16 streamSize = ReadFifo16(data); - - data += streamSize * vertexSize; - } - else - { - PanicAlert("FifoPlayer: Unknown Opcode (0x%x).\nAborting frame analysis.\n", cmd); - return 0; - } - break; - } - - return (u32)(data - dataStart); -} - -static void StoreEfbCopyRegion() +void FifoPlaybackAnalyzer::StoreEfbCopyRegion() { UPE_Copy peCopy = s_BpMem.triggerEFBCopy; diff --git a/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.h b/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.h index bd558b9d8a..4c956a7891 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.h +++ b/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.h @@ -20,4 +20,6 @@ struct AnalyzedFrameInfo namespace FifoPlaybackAnalyzer { void AnalyzeFrames(FifoDataFile* file, std::vector& frameInfo); + + void StoreEfbCopyRegion(); }; diff --git a/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.cpp b/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.cpp index 1a3b657f4e..687be2ced3 100644 --- a/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.cpp @@ -15,11 +15,6 @@ using namespace FifoAnalyzer; -static bool s_DrawingObject; -FifoAnalyzer::CPMemory s_CpMem; - -static void DecodeOpcode(u8* data); -static void ProcessLoadIndexedXf(u32 val, int array); static void ProcessVertexArrays(u8* data, u8 vtxAttrGroup); static void WriteVertexArray(int arrayIndex, u8* vertexData, int vertexSize, int numVertices); @@ -38,83 +33,10 @@ void FifoRecordAnalyzer::Initialize(u32* cpMem) void FifoRecordAnalyzer::AnalyzeGPCommand(u8* data) { - DecodeOpcode(data); + FifoAnalyzer::AnalyzeCommand(data, DECODE_RECORD); } -static void DecodeOpcode(u8* data) -{ - int cmd = ReadFifo8(data); - - switch (cmd) - { - case GX_NOP: - case 0x44: - case GX_CMD_INVL_VC: - break; - - case GX_LOAD_CP_REG: - { - s_DrawingObject = false; - - u32 cmd2 = ReadFifo8(data); - u32 value = ReadFifo32(data); - FifoAnalyzer::LoadCPReg(cmd2, value, s_CpMem); - } - - break; - - case GX_LOAD_XF_REG: - s_DrawingObject = false; - break; - - case GX_LOAD_INDX_A: - s_DrawingObject = false; - ProcessLoadIndexedXf(ReadFifo32(data), 0xc); - break; - case GX_LOAD_INDX_B: - s_DrawingObject = false; - ProcessLoadIndexedXf(ReadFifo32(data), 0xd); - break; - case GX_LOAD_INDX_C: - s_DrawingObject = false; - ProcessLoadIndexedXf(ReadFifo32(data), 0xe); - break; - case GX_LOAD_INDX_D: - s_DrawingObject = false; - ProcessLoadIndexedXf(ReadFifo32(data), 0xf); - break; - - case GX_CMD_CALL_DL: - { - // The recorder should have expanded display lists into the fifo stream and skipped the call to start them - // That is done to make it easier to track where memory is updated - _assert_(false); - } - break; - - case GX_LOAD_BP_REG: - s_DrawingObject = false; - ReadFifo32(data); - break; - - default: - if (cmd & 0x80) - { - if (!s_DrawingObject) - { - s_DrawingObject = true; - } - - ProcessVertexArrays(data, cmd & GX_VAT_MASK); - } - else - { - PanicAlert("FifoRecordAnalyzer: Unknown Opcode (0x%x).\n", cmd); - } - } -} - -static void ProcessLoadIndexedXf(u32 val, int array) +void FifoRecordAnalyzer::ProcessLoadIndexedXf(u32 val, int array) { int index = val >> 16; int size = ((val >> 12) & 0xF) + 1; @@ -124,33 +46,7 @@ static void ProcessLoadIndexedXf(u32 val, int array) FifoRecorder::GetInstance().UseMemory(address, size * 4, MemoryUpdate::XF_DATA); } -static void ProcessVertexArrays(u8* data, u8 vtxAttrGroup) -{ - int sizes[21]; - FifoAnalyzer::CalculateVertexElementSizes(sizes, vtxAttrGroup, s_CpMem); - - // Determine offset of each element from start of vertex data - int offsets[12]; - int offset = 0; - for (int i = 0; i < 12; ++i) - { - offsets[i] = offset; - offset += sizes[i + 9]; - } - - int vertexSize = offset; - int numVertices = ReadFifo16(data); - - if (numVertices > 0) - { - for (int i = 0; i < 12; ++i) - { - WriteVertexArray(i, data + offsets[i], vertexSize, numVertices); - } - } -} - -static void 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 = (s_CpMem.vtxDesc.Hex >> (9 + (arrayIndex * 2))) & 3; diff --git a/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.h b/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.h index 4a44189599..53a591543f 100644 --- a/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.h +++ b/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.h @@ -18,4 +18,7 @@ namespace FifoRecordAnalyzer // Assumes data contains all information for the command // Calls FifoRecorder::UseMemory void AnalyzeGPCommand(u8* data); + + void ProcessLoadIndexedXf(u32 val, int array); + void WriteVertexArray(int arrayIndex, u8* vertexData, int vertexSize, int numVertices); };