From 0367c3107d9c503b2b41b6d87fc12b2adb494ed5 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Sun, 8 Nov 2015 05:25:27 +1300 Subject: [PATCH] FifoAnalyzer: Unify DecodeOp/DecodeCommand We actually discovered a bug while combining the two functions with FifoRecordAnalzyer's vertex array loading code. If per-vertex postion or texture matrices were enabled and vertex arrays in use then the wrong data would be used to calculate the minimum/maxmium indices, which would result in either too much or too little vertex data being included in the dff. So this commit also increments the dff version number, so we can identify old broken dffs later. --- Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp | 132 ++++++++++++++++-- Source/Core/Core/FifoPlayer/FifoAnalyzer.h | 13 +- Source/Core/Core/FifoPlayer/FifoFileStruct.h | 2 +- .../Core/FifoPlayer/FifoPlaybackAnalyzer.cpp | 97 +------------ .../Core/FifoPlayer/FifoPlaybackAnalyzer.h | 2 + .../Core/FifoPlayer/FifoRecordAnalyzer.cpp | 110 +-------------- .../Core/Core/FifoPlayer/FifoRecordAnalyzer.h | 3 + 7 files changed, 147 insertions(+), 212 deletions(-) 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); };