diff options
Diffstat (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp')
| -rw-r--r-- | Source/Core/VideoCommon/OpcodeDecoding.cpp | 180 |
1 files changed, 123 insertions, 57 deletions
diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index fe70bcf492..1bb5fae940 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -24,6 +24,7 @@ #include "VideoCommon/DataReader.h" #include "VideoCommon/Fifo.h" #include "VideoCommon/OpcodeDecoding.h" +#include "VideoCommon/PixelEngine.h" #include "VideoCommon/Statistics.h" #include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VideoCommon.h" @@ -36,7 +37,12 @@ bool g_bRecordFifoData = false; static u32 InterpretDisplayList(u32 address, u32 size) { u8* old_pVideoData = g_video_buffer_read_ptr; - u8* startAddress = Memory::GetPointer(address); + u8* startAddress; + + if (g_use_deterministic_gpu_thread) + startAddress = (u8*) PopFifoAuxBuffer(size); + else + startAddress = Memory::GetPointer(address); u32 cycles = 0; @@ -62,11 +68,29 @@ static u32 InterpretDisplayList(u32 address, u32 size) return cycles; } +static void InterpretDisplayListPreprocess(u32 address, u32 size) +{ + u8* old_read_ptr = g_video_buffer_pp_read_ptr; + u8* startAddress = Memory::GetPointer(address); + + PushFifoAuxBuffer(startAddress, size); + + if (startAddress != nullptr) + { + g_video_buffer_pp_read_ptr = startAddress; + + u8 *end = startAddress + size; + OpcodeDecoder_Preprocess(end); + } + + g_video_buffer_pp_read_ptr = old_read_ptr; +} + static void UnknownOpcode(u8 cmd_byte, void *buffer, bool preprocess) { // TODO(Omega): Maybe dump FIFO to file on this error std::string temp = StringFromFormat( - "GFX FIFO: Unknown Opcode (0x%x @ %p).\n" + "GFX FIFO: Unknown Opcode (0x%x @ %p, preprocessing=%s).\n" "This means one of the following:\n" "* The emulated GPU got desynced, disabling dual core can help\n" "* Command stream corrupted by some spurious memory bug\n" @@ -74,7 +98,8 @@ static void UnknownOpcode(u8 cmd_byte, void *buffer, bool preprocess) "* Some other sort of bug\n\n" "Dolphin will now likely crash or hang. Enjoy." , cmd_byte, - buffer); + buffer, + preprocess ? "yes" : "no"); Host_SysMessage(temp.c_str()); INFO_LOG(VIDEO, "%s", temp.c_str()); { @@ -104,14 +129,16 @@ static void UnknownOpcode(u8 cmd_byte, void *buffer, bool preprocess) } } +template <bool is_preprocess, u8** bufp> static u32 Decode(u8* end) { - u8 *opcodeStart = g_video_buffer_read_ptr; - if (g_video_buffer_read_ptr == end) + u8 *opcodeStart = *bufp; + if (*bufp == end) return 0; - u8 cmd_byte = DataReadU8(); + u8 cmd_byte = DataRead<u8>(bufp); u32 cycles; + int refarray; switch (cmd_byte) { case GX_NOP: @@ -120,64 +147,72 @@ static u32 Decode(u8* end) case GX_LOAD_CP_REG: //0x08 { - if (end - g_video_buffer_read_ptr < 1 + 4) + if (end - *bufp < 1 + 4) return 0; cycles = 12; - u8 sub_cmd = DataReadU8(); - u32 value = DataReadU32(); - LoadCPReg(sub_cmd, value); - INCSTAT(stats.thisFrame.numCPLoads); + u8 sub_cmd = DataRead<u8>(bufp); + u32 value = DataRead<u32>(bufp); + LoadCPReg(sub_cmd, value, is_preprocess); + if (!is_preprocess) + INCSTAT(stats.thisFrame.numCPLoads); } break; case GX_LOAD_XF_REG: { - if (end - g_video_buffer_read_ptr < 4) + if (end - *bufp < 4) return 0; - u32 Cmd2 = DataReadU32(); + u32 Cmd2 = DataRead<u32>(bufp); int transfer_size = ((Cmd2 >> 16) & 15) + 1; - if ((size_t) (end - g_video_buffer_read_ptr) < transfer_size * sizeof(u32)) + if ((size_t) (end - *bufp) < transfer_size * sizeof(u32)) return 0; cycles = 18 + 6 * transfer_size; - u32 xf_address = Cmd2 & 0xFFFF; - LoadXFReg(transfer_size, xf_address); + if (!is_preprocess) + { + u32 xf_address = Cmd2 & 0xFFFF; + LoadXFReg(transfer_size, xf_address); - INCSTAT(stats.thisFrame.numXFLoads); + INCSTAT(stats.thisFrame.numXFLoads); + } + else + { + *bufp += transfer_size * sizeof(u32); + } } break; case GX_LOAD_INDX_A: //used for position matrices - if (end - g_video_buffer_read_ptr < 4) - return 0; - cycles = 6; - LoadIndexedXF(DataReadU32(), 0xC); - break; + refarray = 0xC; + goto load_indx; case GX_LOAD_INDX_B: //used for normal matrices - if (end - g_video_buffer_read_ptr < 4) - return 0; - cycles = 6; - LoadIndexedXF(DataReadU32(), 0xD); - break; + refarray = 0xD; + goto load_indx; case GX_LOAD_INDX_C: //used for postmatrices - if (end - g_video_buffer_read_ptr < 4) - return 0; - cycles = 6; - LoadIndexedXF(DataReadU32(), 0xE); - break; + refarray = 0xE; + goto load_indx; case GX_LOAD_INDX_D: //used for lights - if (end - g_video_buffer_read_ptr < 4) + refarray = 0xF; + goto load_indx; + load_indx: + if (end - *bufp < 4) return 0; cycles = 6; - LoadIndexedXF(DataReadU32(), 0xF); + if (is_preprocess) + PreprocessIndexedXF(DataRead<u32>(bufp), refarray); + else + LoadIndexedXF(DataRead<u32>(bufp), refarray); break; case GX_CMD_CALL_DL: { - if (end - g_video_buffer_read_ptr < 8) + if (end - *bufp < 8) return 0; - u32 address = DataReadU32(); - u32 count = DataReadU32(); - cycles = 6 + InterpretDisplayList(address, count); + u32 address = DataRead<u32>(bufp); + u32 count = DataRead<u32>(bufp); + if (is_preprocess) + InterpretDisplayListPreprocess(address, count); + else + cycles = 6 + InterpretDisplayList(address, count); } break; @@ -195,12 +230,19 @@ static u32 Decode(u8* end) // In skipped_frame case: We have to let BP writes through because they set // tokens and stuff. TODO: Call a much simplified LoadBPReg instead. { - if (end - g_video_buffer_read_ptr < 4) + if (end - *bufp < 4) return 0; cycles = 12; - u32 bp_cmd = DataReadU32(); - LoadBPReg(bp_cmd); - INCSTAT(stats.thisFrame.numBPLoads); + u32 bp_cmd = DataRead<u32>(bufp); + if (is_preprocess) + { + LoadBPRegPreprocess(bp_cmd); + } + else + { + LoadBPReg(bp_cmd); + INCSTAT(stats.thisFrame.numBPLoads); + } } break; @@ -210,33 +252,43 @@ static u32 Decode(u8* end) { cycles = 1600; // load vertices - if (end - g_video_buffer_read_ptr < 2) + if (end - *bufp < 2) return 0; - u16 numVertices = DataReadU16(); - - if (!VertexLoaderManager::RunVertices( - cmd_byte & GX_VAT_MASK, // Vertex loader index (0 - 7) - (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, - numVertices, - end - g_video_buffer_read_ptr, - g_bSkipCurrentFrame)) + u16 num_vertices = DataRead<u16>(bufp); + + if (is_preprocess) { - return 0; + size_t size = num_vertices * VertexLoaderManager::GetVertexSize(cmd_byte & GX_VAT_MASK, is_preprocess); + if ((size_t) (end - *bufp) < size) + return 0; + *bufp += size; + } + else + { + if (!VertexLoaderManager::RunVertices( + cmd_byte & GX_VAT_MASK, // Vertex loader index (0 - 7) + (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, + num_vertices, + end - *bufp, + g_bSkipCurrentFrame)) + return 0; } } else { - UnknownOpcode(cmd_byte, opcodeStart, false); + UnknownOpcode(cmd_byte, opcodeStart, is_preprocess); cycles = 1; } break; } // Display lists get added directly into the FIFO stream - if (g_bRecordFifoData && cmd_byte != GX_CMD_CALL_DL) - FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, u32(g_video_buffer_read_ptr - opcodeStart)); + if (!is_preprocess && g_bRecordFifoData && cmd_byte != GX_CMD_CALL_DL) + FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, u32(*bufp - opcodeStart)); - return cycles; + // In is_preprocess mode, we don't actually care about cycles, at least for + // now... make sure the compiler realizes that. + return is_preprocess ? 1 : cycles; } void OpcodeDecoder_Init() @@ -255,7 +307,7 @@ u32 OpcodeDecoder_Run(u8* end) while (true) { u8* old = g_video_buffer_read_ptr; - u32 cycles = Decode(end); + u32 cycles = Decode</*is_preprocess*/ false, &g_video_buffer_read_ptr>(end); if (cycles == 0) { g_video_buffer_read_ptr = old; @@ -265,3 +317,17 @@ u32 OpcodeDecoder_Run(u8* end) } return totalCycles; } + +void OpcodeDecoder_Preprocess(u8 *end) +{ + while (true) + { + u8* old = g_video_buffer_pp_read_ptr; + u32 cycles = Decode</*is_preprocess*/ true, &g_video_buffer_pp_read_ptr>(end); + if (cycles == 0) + { + g_video_buffer_pp_read_ptr = old; + break; + } + } +} |
