summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/Src/OpcodeDecoding.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core/VideoCommon/Src/OpcodeDecoding.cpp')
-rw-r--r--Source/Core/VideoCommon/Src/OpcodeDecoding.cpp473
1 files changed, 260 insertions, 213 deletions
diff --git a/Source/Core/VideoCommon/Src/OpcodeDecoding.cpp b/Source/Core/VideoCommon/Src/OpcodeDecoding.cpp
index 4f7f86d655..92d596b774 100644
--- a/Source/Core/VideoCommon/Src/OpcodeDecoding.cpp
+++ b/Source/Core/VideoCommon/Src/OpcodeDecoding.cpp
@@ -123,7 +123,7 @@ void InterpretDisplayList(u32 address, u32 size)
Statistics::SwapDL();
}
- // reset to the old pointer
+ // reset to the old pointer
g_pVideoData = old_pVideoData;
}
@@ -136,74 +136,114 @@ void ExecuteDisplayList(u32 address, u32 size)
InterpretDisplayList(address, size);
}
-bool FifoCommandRunnable()
+u32 FifoCommandRunnable(u32 &command_size)
{
+ u32 cycleTime = 0;
u32 buffer_size = (u32)(GetVideoBufferEndPtr() - g_pVideoData);
- if (buffer_size == 0)
- return false; // can't peek
+ if (buffer_size == 0)
+ return 0; // can't peek
u8 cmd_byte = DataPeek8(0);
- u32 command_size = 0;
- switch (cmd_byte)
- {
- case GX_NOP: // Hm, this means that we scan over nop streams pretty slowly...
+ switch (cmd_byte)
+ {
+ case GX_NOP: // Hm, this means that we scan over nop streams pretty slowly...
+ command_size = 1;
+ cycleTime = 6;
+ break;
case GX_CMD_INVL_VC: // Invalidate Vertex Cache - no parameters
- case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that
- command_size = 1;
- break;
-
- case GX_LOAD_BP_REG:
- command_size = 5;
- break;
-
- case GX_LOAD_CP_REG:
- command_size = 6;
- break;
-
- case GX_LOAD_INDX_A:
- case GX_LOAD_INDX_B:
- case GX_LOAD_INDX_C:
- case GX_LOAD_INDX_D:
- command_size = 5;
- break;
-
- case GX_CMD_CALL_DL:
- command_size = 9;
- break;
-
- case GX_LOAD_XF_REG:
- {
- // check if we can read the header
- if (buffer_size >= 5)
- {
- command_size = 1 + 4;
- u32 Cmd2 = DataPeek32(1);
- int transfer_size = ((Cmd2 >> 16) & 15) + 1;
- command_size += transfer_size * 4;
- }
- else
+ command_size = 1;
+ cycleTime = 6;
+ break;
+ case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that
+ command_size = 1;
+ cycleTime = 6;
+ break;
+
+ case GX_LOAD_BP_REG:
+ command_size = 5;
+ cycleTime = 12;
+ break;
+
+ case GX_LOAD_CP_REG:
+ command_size = 6;
+ cycleTime = 12;
+ break;
+
+ case GX_LOAD_INDX_A:
+ case GX_LOAD_INDX_B:
+ case GX_LOAD_INDX_C:
+ case GX_LOAD_INDX_D:
+ command_size = 5;
+ cycleTime = 6; // TODO
+ break;
+
+ case GX_CMD_CALL_DL:
+ {
+ // FIXME: Calculate the cycle time of the display list.
+ //u32 address = DataPeek32(1);
+ //u32 size = DataPeek32(5);
+ //u8* old_pVideoData = g_pVideoData;
+ //u8* startAddress = Memory::GetPointer(address);
+
+ //// Avoid the crash if Memory::GetPointer failed ..
+ //if (startAddress != 0)
+ //{
+ // g_pVideoData = startAddress;
+ // u8 *end = g_pVideoData + size;
+ // u32 step = 0;
+ // while (g_pVideoData < end)
+ // {
+ // cycleTime += FifoCommandRunnable(step);
+ // g_pVideoData += step;
+ // }
+ //}
+ //else
+ //{
+ // cycleTime = 45;
+ //}
+
+ //// reset to the old pointer
+ //g_pVideoData = old_pVideoData;
+ command_size = 9;
+ cycleTime = 45; // This is unverified
+ }
+ break;
+
+ case GX_LOAD_XF_REG:
+ {
+ // check if we can read the header
+ if (buffer_size >= 5)
{
- return false;
- }
- }
- break;
-
- default:
- if (cmd_byte & 0x80)
- {
- // check if we can read the header
- if (buffer_size >= 3)
+ command_size = 1 + 4;
+ u32 Cmd2 = DataPeek32(1);
+ int transfer_size = ((Cmd2 >> 16) & 15) + 1;
+ command_size += transfer_size * 4;
+ cycleTime = 18 + 6 * transfer_size;
+ }
+ else
{
- command_size = 1 + 2;
- u16 numVertices = DataPeek16(1);
+ return 0;
+ }
+ }
+ break;
+
+ default:
+ if (cmd_byte & 0x80)
+ {
+ // check if we can read the header
+ if (buffer_size >= 3)
+ {
+ command_size = 1 + 2;
+ u16 numVertices = DataPeek16(1);
command_size += numVertices * VertexLoaderManager::GetVertexSize(cmd_byte & GX_VAT_MASK);
- }
+ cycleTime = 1600; // This depends on the number of pixels rendered
+ }
else
- {
- return false;
- }
- }
+ {
+ return 0;
+ }
+ }
else
{
// TODO(Omega): Maybe dump FIFO to file on this error
@@ -218,7 +258,7 @@ bool FifoCommandRunnable()
Host_SysMessage(szTemp);
INFO_LOG(VIDEO, "%s", szTemp);
{
- SCPFifoStruct &fifo = CommandProcessor::fifo;
+ SCPFifoStruct &fifo = CommandProcessor::fifo;
char szTmp[512];
// sprintf(szTmp, "Illegal command %02x (at %08x)",cmd_byte,g_pDataReader->GetPtr());
@@ -243,197 +283,205 @@ bool FifoCommandRunnable()
Host_SysMessage(szTmp);
INFO_LOG(VIDEO, "%s", szTmp);
}
- }
- break;
- }
-
- if (command_size > buffer_size)
- return false;
+ }
+ break;
+ }
+
+ if (command_size > buffer_size)
+ return 0;
- // INFO_LOG("OP detected: cmd_byte 0x%x size %i buffer %i",cmd_byte, command_size, buffer_size);
+ // INFO_LOG("OP detected: cmd_byte 0x%x size %i buffer %i",cmd_byte, command_size, buffer_size);
+ if (cycleTime == 0)
+ cycleTime = 6;
- return true;
+ return cycleTime;
+}
+
+u32 FifoCommandRunnable()
+{
+ u32 command_size = 0;
+ return FifoCommandRunnable(command_size);
}
static void Decode()
{
- u8 *opcodeStart = g_pVideoData;
-
- int cmd_byte = DataReadU8();
- switch (cmd_byte)
- {
- case GX_NOP:
- break;
-
- case GX_LOAD_CP_REG: //0x08
- {
- u8 sub_cmd = DataReadU8();
- u32 value = DataReadU32();
- LoadCPReg(sub_cmd, value);
+ u8 *opcodeStart = g_pVideoData;
+
+ int cmd_byte = DataReadU8();
+ switch (cmd_byte)
+ {
+ case GX_NOP:
+ break;
+
+ case GX_LOAD_CP_REG: //0x08
+ {
+ u8 sub_cmd = DataReadU8();
+ u32 value = DataReadU32();
+ LoadCPReg(sub_cmd, value);
INCSTAT(stats.thisFrame.numCPLoads);
- }
- break;
+ }
+ break;
- case GX_LOAD_XF_REG:
- {
- u32 Cmd2 = DataReadU32();
- int transfer_size = ((Cmd2 >> 16) & 15) + 1;
+ case GX_LOAD_XF_REG:
+ {
+ u32 Cmd2 = DataReadU32();
+ int transfer_size = ((Cmd2 >> 16) & 15) + 1;
u32 xf_address = Cmd2 & 0xFFFF;
GC_ALIGNED128(u32 data_buffer[16]);
DataReadU32xFuncs[transfer_size-1](data_buffer);
- LoadXFReg(transfer_size, xf_address, data_buffer);
+ LoadXFReg(transfer_size, xf_address, data_buffer);
INCSTAT(stats.thisFrame.numXFLoads);
- }
- break;
-
- case GX_LOAD_INDX_A: //used for position matrices
- LoadIndexedXF(DataReadU32(), 0xC);
- break;
- case GX_LOAD_INDX_B: //used for normal matrices
- LoadIndexedXF(DataReadU32(), 0xD);
- break;
- case GX_LOAD_INDX_C: //used for postmatrices
- LoadIndexedXF(DataReadU32(), 0xE);
- break;
- case GX_LOAD_INDX_D: //used for lights
- LoadIndexedXF(DataReadU32(), 0xF);
- break;
-
- case GX_CMD_CALL_DL:
- {
- u32 address = DataReadU32();
- u32 count = DataReadU32();
- ExecuteDisplayList(address, count);
- }
- break;
-
- case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that
+ }
+ break;
+
+ case GX_LOAD_INDX_A: //used for position matrices
+ LoadIndexedXF(DataReadU32(), 0xC);
+ break;
+ case GX_LOAD_INDX_B: //used for normal matrices
+ LoadIndexedXF(DataReadU32(), 0xD);
+ break;
+ case GX_LOAD_INDX_C: //used for postmatrices
+ LoadIndexedXF(DataReadU32(), 0xE);
+ break;
+ case GX_LOAD_INDX_D: //used for lights
+ LoadIndexedXF(DataReadU32(), 0xF);
+ break;
+
+ case GX_CMD_CALL_DL:
+ {
+ u32 address = DataReadU32();
+ u32 count = DataReadU32();
+ ExecuteDisplayList(address, count);
+ }
+ break;
+
+ case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that
DEBUG_LOG(VIDEO, "GX 0x44: %08x", cmd_byte);
- break;
+ break;
- case GX_CMD_INVL_VC: // Invalidate Vertex Cache
- DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)");
- break;
+ case GX_CMD_INVL_VC: // Invalidate Vertex Cache
+ DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)");
+ break;
- case GX_LOAD_BP_REG: //0x61
- {
+ case GX_LOAD_BP_REG: //0x61
+ {
u32 bp_cmd = DataReadU32();
- LoadBPReg(bp_cmd);
+ LoadBPReg(bp_cmd);
INCSTAT(stats.thisFrame.numBPLoads);
- }
- break;
-
- // draw primitives
- default:
- if (cmd_byte & 0x80)
- {
- // load vertices (use computed vertex size from FifoCommandRunnable above)
+ }
+ break;
+
+ // draw primitives
+ default:
+ if (cmd_byte & 0x80)
+ {
+ // load vertices (use computed vertex size from FifoCommandRunnable above)
u16 numVertices = DataReadU16();
VertexLoaderManager::RunVertices(
cmd_byte & GX_VAT_MASK, // Vertex loader index (0 - 7)
(cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT,
numVertices);
- }
- else
- {
+ }
+ else
+ {
ERROR_LOG(VIDEO, "OpcodeDecoding::Decode: Illegal command %02x", cmd_byte);
- break;
- }
- break;
- }
+ break;
+ }
+ break;
+ }
// Display lists get added directly into the FIFO stream
if (g_bRecordFifoData && cmd_byte != GX_CMD_CALL_DL)
- FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, g_pVideoData - opcodeStart);
+ FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, u32(g_pVideoData - opcodeStart));
}
static void DecodeSemiNop()
{
- u8 *opcodeStart = g_pVideoData;
-
- int cmd_byte = DataReadU8();
- switch (cmd_byte)
- {
- case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that
- case GX_CMD_INVL_VC: // Invalidate Vertex Cache
- case GX_NOP:
+ u8 *opcodeStart = g_pVideoData;
+
+ int cmd_byte = DataReadU8();
+ switch (cmd_byte)
+ {
+ case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that
+ case GX_CMD_INVL_VC: // Invalidate Vertex Cache
+ case GX_NOP:
break;
case GX_LOAD_CP_REG: //0x08
// We have to let CP writes through because they determine the size of vertices.
- {
- u8 sub_cmd = DataReadU8();
- u32 value = DataReadU32();
- LoadCPReg(sub_cmd, value);
- INCSTAT(stats.thisFrame.numCPLoads);
- }
- break;
-
- case GX_LOAD_XF_REG:
- {
- u32 Cmd2 = DataReadU32();
- int transfer_size = ((Cmd2 >> 16) & 15) + 1;
- u32 address = Cmd2 & 0xFFFF;
- GC_ALIGNED128(u32 data_buffer[16]);
- DataReadU32xFuncs[transfer_size-1](data_buffer);
- LoadXFReg(transfer_size, address, data_buffer);
- INCSTAT(stats.thisFrame.numXFLoads);
- }
- break;
-
- case GX_LOAD_INDX_A: //used for position matrices
- LoadIndexedXF(DataReadU32(), 0xC);
- break;
- case GX_LOAD_INDX_B: //used for normal matrices
- LoadIndexedXF(DataReadU32(), 0xD);
- break;
- case GX_LOAD_INDX_C: //used for postmatrices
- LoadIndexedXF(DataReadU32(), 0xE);
- break;
- case GX_LOAD_INDX_D: //used for lights
- LoadIndexedXF(DataReadU32(), 0xF);
- break;
-
- case GX_CMD_CALL_DL:
+ {
+ u8 sub_cmd = DataReadU8();
+ u32 value = DataReadU32();
+ LoadCPReg(sub_cmd, value);
+ INCSTAT(stats.thisFrame.numCPLoads);
+ }
+ break;
+
+ case GX_LOAD_XF_REG:
+ {
+ u32 Cmd2 = DataReadU32();
+ int transfer_size = ((Cmd2 >> 16) & 15) + 1;
+ u32 address = Cmd2 & 0xFFFF;
+ GC_ALIGNED128(u32 data_buffer[16]);
+ DataReadU32xFuncs[transfer_size-1](data_buffer);
+ LoadXFReg(transfer_size, address, data_buffer);
+ INCSTAT(stats.thisFrame.numXFLoads);
+ }
+ break;
+
+ case GX_LOAD_INDX_A: //used for position matrices
+ LoadIndexedXF(DataReadU32(), 0xC);
+ break;
+ case GX_LOAD_INDX_B: //used for normal matrices
+ LoadIndexedXF(DataReadU32(), 0xD);
+ break;
+ case GX_LOAD_INDX_C: //used for postmatrices
+ LoadIndexedXF(DataReadU32(), 0xE);
+ break;
+ case GX_LOAD_INDX_D: //used for lights
+ LoadIndexedXF(DataReadU32(), 0xF);
+ break;
+
+ case GX_CMD_CALL_DL:
// Hm, wonder if any games put tokens in display lists - in that case,
// we'll have to parse them too.
- DataSkip(8);
- break;
+ DataSkip(8);
+ break;
- case GX_LOAD_BP_REG: //0x61
+ case GX_LOAD_BP_REG: //0x61
// We have to let BP writes through because they set tokens and stuff.
// TODO: Call a much simplified LoadBPReg instead.
- {
+ {
u32 bp_cmd = DataReadU32();
- LoadBPReg(bp_cmd);
+ LoadBPReg(bp_cmd);
INCSTAT(stats.thisFrame.numBPLoads);
- }
- break;
-
- // draw primitives
- default:
- if (cmd_byte & 0x80)
- {
- // load vertices (use computed vertex size from FifoCommandRunnable above)
+ }
+ break;
+
+ // draw primitives
+ default:
+ if (cmd_byte & 0x80)
+ {
+ // load vertices (use computed vertex size from FifoCommandRunnable above)
u16 numVertices = DataReadU16();
DataSkip(numVertices * VertexLoaderManager::GetVertexSize(cmd_byte & GX_VAT_MASK));
- }
- else
- {
+ }
+ else
+ {
ERROR_LOG(VIDEO, "OpcodeDecoding::Decode: Illegal command %02x", cmd_byte);
- break;
- }
- break;
- }
+ break;
+ }
+ break;
+ }
if (g_bRecordFifoData && cmd_byte != GX_CMD_CALL_DL)
- FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, g_pVideoData - opcodeStart);
+ FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, u32(g_pVideoData - opcodeStart));
}
void OpcodeDecoder_Init()
-{
+{
g_pVideoData = GetVideoBufferStartPtr();
#if _M_SSE >= 0x301
@@ -446,8 +494,8 @@ void OpcodeDecoder_Init()
if (g_Config.bEnableOpenCL)
{
- OpenCL::Initialize();
- TexDecoder_OpenCL_Initialize();
+ OpenCL::Initialize();
+ TexDecoder_OpenCL_Initialize();
}
}
@@ -456,21 +504,20 @@ void OpcodeDecoder_Shutdown()
{
if (g_Config.bEnableOpenCL)
{
- TexDecoder_OpenCL_Shutdown();
- OpenCL::Destroy();
+ TexDecoder_OpenCL_Shutdown();
+ OpenCL::Destroy();
}
}
-void OpcodeDecoder_Run(bool skipped_frame)
+u32 OpcodeDecoder_Run(bool skipped_frame)
{
- if (!skipped_frame)
- {
- while (FifoCommandRunnable())
- Decode();
- }
- else
+ u32 totalCycles = 0;
+ u32 cycles = FifoCommandRunnable();
+ while (cycles > 0)
{
- while (FifoCommandRunnable())
- DecodeSemiNop();
+ skipped_frame ? DecodeSemiNop() : Decode();
+ totalCycles += cycles;
+ cycles = FifoCommandRunnable();
}
+ return totalCycles;
}