mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-15 05:47:56 -07:00
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:
parent
1656b2788d
commit
0367c3107d
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ namespace FifoFileStruct
|
||||
enum
|
||||
{
|
||||
FILE_ID = 0x0d01f1f0,
|
||||
VERSION_NUMBER = 2,
|
||||
VERSION_NUMBER = 3,
|
||||
MIN_LOADER_VERSION = 1,
|
||||
};
|
||||
|
||||
|
@ -29,13 +29,8 @@ struct MemoryRange
|
||||
};
|
||||
|
||||
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 u32 DecodeCommand(u8* data);
|
||||
static void StoreEfbCopyRegion();
|
||||
static void StoreWrittenRegion(u32 address, u32 size);
|
||||
|
||||
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;
|
||||
|
||||
u32 cmdSize = DecodeCommand(&frame.fifoData[cmdStart]);
|
||||
u32 cmdSize = FifoAnalyzer::AnalyzeCommand(&frame.fifoData[cmdStart], DECODE_PLAYBACK);
|
||||
|
||||
#if LOG_FIFO_CMDS
|
||||
CmdData cmdData;
|
||||
@ -162,95 +157,7 @@ static void AddMemoryUpdate(MemoryUpdate memUpdate, AnalyzedFrameInfo& frameInfo
|
||||
frameInfo.memoryUpdates.push_back(memUpdate);
|
||||
}
|
||||
|
||||
static u32 DecodeCommand(u8* data)
|
||||
{
|
||||
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()
|
||||
void FifoPlaybackAnalyzer::StoreEfbCopyRegion()
|
||||
{
|
||||
UPE_Copy peCopy = s_BpMem.triggerEFBCopy;
|
||||
|
||||
|
@ -20,4 +20,6 @@ struct AnalyzedFrameInfo
|
||||
namespace FifoPlaybackAnalyzer
|
||||
{
|
||||
void AnalyzeFrames(FifoDataFile* file, std::vector<AnalyzedFrameInfo>& frameInfo);
|
||||
|
||||
void StoreEfbCopyRegion();
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user