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.
This commit is contained in:
Scott Mansell 2015-11-08 05:25:27 +13:00
parent 1656b2788d
commit 0367c3107d
7 changed files with 147 additions and 212 deletions

View File

@ -8,6 +8,9 @@
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/Core.h" #include "Core/Core.h"
#include "Core/FifoPlayer/FifoAnalyzer.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.h"
#include "VideoCommon/VertexLoader_Normal.h" #include "VideoCommon/VertexLoader_Normal.h"
#include "VideoCommon/VertexLoader_Position.h" #include "VideoCommon/VertexLoader_Position.h"
@ -16,6 +19,10 @@
namespace FifoAnalyzer namespace FifoAnalyzer
{ {
bool s_DrawingObject;
BPMemory s_BpMem;
FifoAnalyzer::CPMemory s_CpMem;
void Init() void Init()
{ {
VertexLoader_Normal::Init(); VertexLoader_Normal::Init();
@ -42,6 +49,123 @@ u32 ReadFifo32(u8*& data)
return value; 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) void InitBPMemory(BPMemory* bpMem)
{ {
memset(bpMem, 0, sizeof(BPMemory)); 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) void CalculateVertexElementSizes(int sizes[], int vatIndex, const CPMemory& cpMem)
{ {
const TVtxDesc &vtxDesc = cpMem.vtxDesc; const TVtxDesc &vtxDesc = cpMem.vtxDesc;

View File

@ -17,6 +17,14 @@ namespace FifoAnalyzer
u16 ReadFifo16(u8*& data); u16 ReadFifo16(u8*& data);
u32 ReadFifo32(u8*& data); u32 ReadFifo32(u8*& data);
enum DecodeMode
{
DECODE_RECORD,
DECODE_PLAYBACK,
};
u32 AnalyzeCommand(u8* data, DecodeMode mode);
// TODO- move to video common // TODO- move to video common
void InitBPMemory(BPMemory* bpMem); void InitBPMemory(BPMemory* bpMem);
BPCmd DecodeBPCmd(u32 value, const BPMemory &bpMem); BPCmd DecodeBPCmd(u32 value, const BPMemory &bpMem);
@ -32,6 +40,9 @@ namespace FifoAnalyzer
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); void CalculateVertexElementSizes(int sizes[], int vatIndex, const CPMemory& cpMem);
extern bool s_DrawingObject;
extern BPMemory s_BpMem;
extern FifoAnalyzer::CPMemory s_CpMem;
} }

View File

@ -12,7 +12,7 @@ namespace FifoFileStruct
enum enum
{ {
FILE_ID = 0x0d01f1f0, FILE_ID = 0x0d01f1f0,
VERSION_NUMBER = 2, VERSION_NUMBER = 3,
MIN_LOADER_VERSION = 1, MIN_LOADER_VERSION = 1,
}; };

View File

@ -29,13 +29,8 @@ struct MemoryRange
}; };
static std::vector<MemoryRange> s_WrittenMemory; static std::vector<MemoryRange> s_WrittenMemory;
static BPMemory s_BpMem;
static FifoAnalyzer::CPMemory s_CpMem;
static bool s_DrawingObject;
static void AddMemoryUpdate(MemoryUpdate memUpdate, AnalyzedFrameInfo& frameInfo); static void AddMemoryUpdate(MemoryUpdate memUpdate, AnalyzedFrameInfo& frameInfo);
static u32 DecodeCommand(u8* data);
static void StoreEfbCopyRegion();
static void StoreWrittenRegion(u32 address, u32 size); static void StoreWrittenRegion(u32 address, u32 size);
void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile* file, std::vector<AnalyzedFrameInfo>& frameInfo) void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile* file, std::vector<AnalyzedFrameInfo>& frameInfo)
@ -84,7 +79,7 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile* file, std::vector<Analyze
bool wasDrawing = s_DrawingObject; bool wasDrawing = s_DrawingObject;
u32 cmdSize = DecodeCommand(&frame.fifoData[cmdStart]); u32 cmdSize = FifoAnalyzer::AnalyzeCommand(&frame.fifoData[cmdStart], DECODE_PLAYBACK);
#if LOG_FIFO_CMDS #if LOG_FIFO_CMDS
CmdData cmdData; CmdData cmdData;
@ -162,95 +157,7 @@ static void AddMemoryUpdate(MemoryUpdate memUpdate, AnalyzedFrameInfo& frameInfo
frameInfo.memoryUpdates.push_back(memUpdate); frameInfo.memoryUpdates.push_back(memUpdate);
} }
static u32 DecodeCommand(u8* data) void FifoPlaybackAnalyzer::StoreEfbCopyRegion()
{
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);
FifoAnalyzer::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;
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()
{ {
UPE_Copy peCopy = s_BpMem.triggerEFBCopy; UPE_Copy peCopy = s_BpMem.triggerEFBCopy;

View File

@ -20,4 +20,6 @@ struct AnalyzedFrameInfo
namespace FifoPlaybackAnalyzer namespace FifoPlaybackAnalyzer
{ {
void AnalyzeFrames(FifoDataFile* file, std::vector<AnalyzedFrameInfo>& frameInfo); void AnalyzeFrames(FifoDataFile* file, std::vector<AnalyzedFrameInfo>& frameInfo);
void StoreEfbCopyRegion();
}; };

View File

@ -15,11 +15,6 @@
using namespace FifoAnalyzer; 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 ProcessVertexArrays(u8* data, u8 vtxAttrGroup);
static void WriteVertexArray(int arrayIndex, u8* vertexData, int vertexSize, int numVertices); 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) void FifoRecordAnalyzer::AnalyzeGPCommand(u8* data)
{ {
DecodeOpcode(data); FifoAnalyzer::AnalyzeCommand(data, DECODE_RECORD);
} }
static void DecodeOpcode(u8* data) void FifoRecordAnalyzer::ProcessLoadIndexedXf(u32 val, int array)
{
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)
{ {
int index = val >> 16; int index = val >> 16;
int size = ((val >> 12) & 0xF) + 1; 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); FifoRecorder::GetInstance().UseMemory(address, size * 4, MemoryUpdate::XF_DATA);
} }
static void ProcessVertexArrays(u8* data, u8 vtxAttrGroup) void FifoRecordAnalyzer::WriteVertexArray(int arrayIndex, u8* vertexData, int vertexSize, int numVertices)
{
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)
{ {
// Skip if not indexed array // Skip if not indexed array
int arrayType = (s_CpMem.vtxDesc.Hex >> (9 + (arrayIndex * 2))) & 3; int arrayType = (s_CpMem.vtxDesc.Hex >> (9 + (arrayIndex * 2))) & 3;

View File

@ -18,4 +18,7 @@ namespace FifoRecordAnalyzer
// Assumes data contains all information for the command // Assumes data contains all information for the command
// Calls FifoRecorder::UseMemory // Calls FifoRecorder::UseMemory
void AnalyzeGPCommand(u8* data); void AnalyzeGPCommand(u8* data);
void ProcessLoadIndexedXf(u32 val, int array);
void WriteVertexArray(int arrayIndex, u8* vertexData, int vertexSize, int numVertices);
}; };