From 34692ab826abc8f8faa61bdb2280b742424528f1 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Sat, 7 Dec 2013 15:14:29 -0500 Subject: Remove unnecessary Src/ folders --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 497 +++++++++++++++++++++++++++++ 1 file changed, 497 insertions(+) create mode 100644 Source/Core/VideoCommon/OpcodeDecoding.cpp (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp new file mode 100644 index 0000000000..f469bc7f6d --- /dev/null +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -0,0 +1,497 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +//DL facts: +// Ikaruga uses (nearly) NO display lists! +// Zelda WW uses TONS of display lists +// Zelda TP uses almost 100% display lists except menus (we like this!) +// Super Mario Galaxy has nearly all geometry and more than half of the state in DLs (great!) + +// Note that it IS NOT GENERALLY POSSIBLE to precompile display lists! You can compile them as they are +// while interpreting them, and hope that the vertex format doesn't change, though, if you do it right +// when they are called. The reason is that the vertex format affects the sizes of the vertices. + +#include "Common.h" +#include "VideoCommon.h" +#include "OpcodeDecoding.h" +#include "CommandProcessor.h" +#include "CPUDetect.h" +#include "Core.h" +#include "Host.h" +#include "HW/Memmap.h" +#include "FifoPlayer/FifoRecorder.h" + +#include "VertexLoaderManager.h" + +#include "Statistics.h" + +#include "XFMemory.h" +#include "CPMemory.h" +#include "BPMemory.h" + +#include "Fifo.h" +#include "DataReader.h" + +#include "VideoConfig.h" + +u8* g_pVideoData = 0; +bool g_bRecordFifoData = false; + +#if _M_SSE >= 0x301 +DataReadU32xNfunc DataReadU32xFuncs_SSSE3[16] = { + DataReadU32xN_SSSE3<1>, + DataReadU32xN_SSSE3<2>, + DataReadU32xN_SSSE3<3>, + DataReadU32xN_SSSE3<4>, + DataReadU32xN_SSSE3<5>, + DataReadU32xN_SSSE3<6>, + DataReadU32xN_SSSE3<7>, + DataReadU32xN_SSSE3<8>, + DataReadU32xN_SSSE3<9>, + DataReadU32xN_SSSE3<10>, + DataReadU32xN_SSSE3<11>, + DataReadU32xN_SSSE3<12>, + DataReadU32xN_SSSE3<13>, + DataReadU32xN_SSSE3<14>, + DataReadU32xN_SSSE3<15>, + DataReadU32xN_SSSE3<16> +}; +#endif + +DataReadU32xNfunc DataReadU32xFuncs[16] = { + DataReadU32xN<1>, + DataReadU32xN<2>, + DataReadU32xN<3>, + DataReadU32xN<4>, + DataReadU32xN<5>, + DataReadU32xN<6>, + DataReadU32xN<7>, + DataReadU32xN<8>, + DataReadU32xN<9>, + DataReadU32xN<10>, + DataReadU32xN<11>, + DataReadU32xN<12>, + DataReadU32xN<13>, + DataReadU32xN<14>, + DataReadU32xN<15>, + DataReadU32xN<16> +}; + +extern u8* GetVideoBufferStartPtr(); +extern u8* GetVideoBufferEndPtr(); + +static void Decode(); + +void InterpretDisplayList(u32 address, u32 size) +{ + u8* old_pVideoData = g_pVideoData; + u8* startAddress = Memory::GetPointer(address); + + // Avoid the crash if Memory::GetPointer failed .. + if (startAddress != 0) + { + g_pVideoData = startAddress; + + // temporarily swap dl and non-dl (small "hack" for the stats) + Statistics::SwapDL(); + + u8 *end = g_pVideoData + size; + while (g_pVideoData < end) + { + Decode(); + } + INCSTAT(stats.numDListsCalled); + INCSTAT(stats.thisFrame.numDListsCalled); + + // un-swap + Statistics::SwapDL(); + } + + // reset to the old pointer + g_pVideoData = old_pVideoData; +} + +// Defer to backend-specific DL cache. +extern bool HandleDisplayList(u32 address, u32 size); + +void ExecuteDisplayList(u32 address, u32 size) +{ + if (!HandleDisplayList(address, size)) + InterpretDisplayList(address, size); +} + +u32 FifoCommandRunnable(u32 &command_size) +{ + u32 cycleTime = 0; + u32 buffer_size = (u32)(GetVideoBufferEndPtr() - g_pVideoData); + if (buffer_size == 0) + return 0; // can't peek + + u8 cmd_byte = DataPeek8(0); + + 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 + 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) + { + 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 + { + 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 0; + } + } + else + { + // TODO(Omega): Maybe dump FIFO to file on this error + char szTemp[1024]; + sprintf(szTemp, "GFX FIFO: Unknown Opcode (0x%x).\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" + "* This really is an unknown opcode (unlikely)\n" + "* Some other sort of bug\n\n" + "Dolphin will now likely crash or hang. Enjoy." , cmd_byte); + Host_SysMessage(szTemp); + INFO_LOG(VIDEO, "%s", szTemp); + { + SCPFifoStruct &fifo = CommandProcessor::fifo; + + char szTmp[512]; + // sprintf(szTmp, "Illegal command %02x (at %08x)",cmd_byte,g_pDataReader->GetPtr()); + sprintf(szTmp, "Illegal command %02x\n" + "CPBase: 0x%08x\n" + "CPEnd: 0x%08x\n" + "CPHiWatermark: 0x%08x\n" + "CPLoWatermark: 0x%08x\n" + "CPReadWriteDistance: 0x%08x\n" + "CPWritePointer: 0x%08x\n" + "CPReadPointer: 0x%08x\n" + "CPBreakpoint: 0x%08x\n" + "bFF_GPReadEnable: %s\n" + "bFF_BPEnable: %s\n" + "bFF_BPInt: %s\n" + "bFF_Breakpoint: %s\n" + ,cmd_byte, fifo.CPBase, fifo.CPEnd, fifo.CPHiWatermark, fifo.CPLoWatermark, fifo.CPReadWriteDistance + ,fifo.CPWritePointer, fifo.CPReadPointer, fifo.CPBreakpoint, fifo.bFF_GPReadEnable ? "true" : "false" + ,fifo.bFF_BPEnable ? "true" : "false" ,fifo.bFF_BPInt ? "true" : "false" + ,fifo.bFF_Breakpoint ? "true" : "false"); + + Host_SysMessage(szTmp); + INFO_LOG(VIDEO, "%s", szTmp); + } + } + 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); + if (cycleTime == 0) + cycleTime = 6; + + 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); + INCSTAT(stats.thisFrame.numCPLoads); + } + break; + + 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); + + 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 + DEBUG_LOG(VIDEO, "GX 0x44: %08x", cmd_byte); + break; + + case GX_CMD_INVL_VC: // Invalidate Vertex Cache + DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)"); + break; + + case GX_LOAD_BP_REG: //0x61 + { + u32 bp_cmd = DataReadU32(); + LoadBPReg(bp_cmd); + INCSTAT(stats.thisFrame.numBPLoads); + } + 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 + { + ERROR_LOG(VIDEO, "OpcodeDecoding::Decode: Illegal command %02x", cmd_byte); + break; + } + 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_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: + 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: + // Hm, wonder if any games put tokens in display lists - in that case, + // we'll have to parse them too. + DataSkip(8); + break; + + 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); + INCSTAT(stats.thisFrame.numBPLoads); + } + 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 + { + ERROR_LOG(VIDEO, "OpcodeDecoding::Decode: Illegal command %02x", cmd_byte); + break; + } + break; + } + + if (g_bRecordFifoData && cmd_byte != GX_CMD_CALL_DL) + FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, u32(g_pVideoData - opcodeStart)); +} + +void OpcodeDecoder_Init() +{ + g_pVideoData = GetVideoBufferStartPtr(); + +#if _M_SSE >= 0x301 + if (cpu_info.bSSSE3) + { + for (int i = 0; i < 16; ++i) + DataReadU32xFuncs[i] = DataReadU32xFuncs_SSSE3[i]; + } +#endif +} + + +void OpcodeDecoder_Shutdown() +{ +} + +u32 OpcodeDecoder_Run(bool skipped_frame) +{ + u32 totalCycles = 0; + u32 cycles = FifoCommandRunnable(); + while (cycles > 0) + { + skipped_frame ? DecodeSemiNop() : Decode(); + totalCycles += cycles; + cycles = FifoCommandRunnable(); + } + return totalCycles; +} -- cgit v1.2.3 From 010a0d481ad0f5dd19182eafc411feec387404db Mon Sep 17 00:00:00 2001 From: degasus Date: Thu, 30 Jan 2014 15:51:20 +0100 Subject: VideoCommon: remove Cache Displaylist This option was known to break every second game and only boost a bit. It also seems to be broken because of streaming into pinned memory and buffer storage buffers. v2: also remove dlc_desc --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index f469bc7f6d..4211bd650d 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -112,15 +112,6 @@ void InterpretDisplayList(u32 address, u32 size) g_pVideoData = old_pVideoData; } -// Defer to backend-specific DL cache. -extern bool HandleDisplayList(u32 address, u32 size); - -void ExecuteDisplayList(u32 address, u32 size) -{ - if (!HandleDisplayList(address, size)) - InterpretDisplayList(address, size); -} - u32 FifoCommandRunnable(u32 &command_size) { u32 cycleTime = 0; @@ -337,7 +328,7 @@ static void Decode() { u32 address = DataReadU32(); u32 count = DataReadU32(); - ExecuteDisplayList(address, count); + InterpretDisplayList(address, count); } break; -- cgit v1.2.3 From 3fd87a7636ff434118a5d7f7334550be8db55c0b Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 16 Feb 2014 23:51:41 -0500 Subject: Second and final pass of clearing out tabs. --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 4211bd650d..cb47639b81 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -3,7 +3,7 @@ // Refer to the license.txt file included. //DL facts: -// Ikaruga uses (nearly) NO display lists! +// Ikaruga uses (nearly) NO display lists! // Zelda WW uses TONS of display lists // Zelda TP uses almost 100% display lists except menus (we like this!) // Super Mario Galaxy has nearly all geometry and more than half of the state in DLs (great!) -- cgit v1.2.3 From 2afe2152712981e21d6bda6f029292ed2b1cf91e Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 17 Feb 2014 05:18:15 -0500 Subject: Convert all includes to relative paths. --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 42 ++++++++++++++---------------- 1 file changed, 20 insertions(+), 22 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index cb47639b81..29cee8e1a5 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -12,28 +12,26 @@ // while interpreting them, and hope that the vertex format doesn't change, though, if you do it right // when they are called. The reason is that the vertex format affects the sizes of the vertices. -#include "Common.h" -#include "VideoCommon.h" -#include "OpcodeDecoding.h" -#include "CommandProcessor.h" -#include "CPUDetect.h" -#include "Core.h" -#include "Host.h" -#include "HW/Memmap.h" -#include "FifoPlayer/FifoRecorder.h" - -#include "VertexLoaderManager.h" - -#include "Statistics.h" - -#include "XFMemory.h" -#include "CPMemory.h" -#include "BPMemory.h" - -#include "Fifo.h" -#include "DataReader.h" - -#include "VideoConfig.h" +#include "Common/Common.h" +#include "Common/CPUDetect.h" + +#include "Core/Core.h" +#include "Core/Host.h" +#include "Core/FifoPlayer/FifoRecorder.h" +#include "Core/HW/Memmap.h" + +#include "VideoCommon/BPMemory.h" +#include "VideoCommon/CPMemory.h" +#include "VideoCommon/XFMemory.h" + +#include "VideoCommon/CommandProcessor.h" +#include "VideoCommon/DataReader.h" +#include "VideoCommon/Fifo.h" +#include "VideoCommon/OpcodeDecoding.h" +#include "VideoCommon/Statistics.h" +#include "VideoCommon/VertexLoaderManager.h" +#include "VideoCommon/VideoConfig.h" +#include "VideoCommon/VideoCommon.h" u8* g_pVideoData = 0; bool g_bRecordFifoData = false; -- cgit v1.2.3 From ffe588cc240745f0a30595c604083d37e791c670 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Wed, 19 Feb 2014 02:27:20 +0100 Subject: Fix more header sorting issues in VideoCommon/ (now check-includes clean). --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 29cee8e1a5..8c680a04c5 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -14,24 +14,22 @@ #include "Common/Common.h" #include "Common/CPUDetect.h" - #include "Core/Core.h" #include "Core/Host.h" #include "Core/FifoPlayer/FifoRecorder.h" #include "Core/HW/Memmap.h" - #include "VideoCommon/BPMemory.h" -#include "VideoCommon/CPMemory.h" -#include "VideoCommon/XFMemory.h" - #include "VideoCommon/CommandProcessor.h" +#include "VideoCommon/CPMemory.h" #include "VideoCommon/DataReader.h" #include "VideoCommon/Fifo.h" #include "VideoCommon/OpcodeDecoding.h" #include "VideoCommon/Statistics.h" #include "VideoCommon/VertexLoaderManager.h" -#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoCommon.h" +#include "VideoCommon/VideoConfig.h" +#include "VideoCommon/XFMemory.h" + u8* g_pVideoData = 0; bool g_bRecordFifoData = false; -- cgit v1.2.3 From d802d392811be44d34ae9cd23f616db93e54c50f Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Sun, 9 Mar 2014 21:14:26 +0100 Subject: clang-modernize -use-nullptr and s/\bNULL\b/nullptr/g for *.cpp/h/mm files not compiled on my machine --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 8c680a04c5..703f691e7e 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -31,7 +31,7 @@ #include "VideoCommon/XFMemory.h" -u8* g_pVideoData = 0; +u8* g_pVideoData = nullptr; bool g_bRecordFifoData = false; #if _M_SSE >= 0x301 @@ -85,7 +85,7 @@ void InterpretDisplayList(u32 address, u32 size) u8* startAddress = Memory::GetPointer(address); // Avoid the crash if Memory::GetPointer failed .. - if (startAddress != 0) + if (startAddress != nullptr) { g_pVideoData = startAddress; -- cgit v1.2.3 From 369c0c4ce20859448a82c509661cbfe90dcc8d44 Mon Sep 17 00:00:00 2001 From: magumagu Date: Thu, 8 May 2014 15:43:41 -0700 Subject: Opcode decoding: 0xC0 isn't a valid command. Fix our opcode decoders to handle this appropriately. --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 703f691e7e..2500dbdd38 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -201,7 +201,7 @@ u32 FifoCommandRunnable(u32 &command_size) break; default: - if (cmd_byte & 0x80) + if ((cmd_byte & 0xC0) == 0x80) { // check if we can read the header if (buffer_size >= 3) @@ -346,7 +346,7 @@ static void Decode() // draw primitives default: - if (cmd_byte & 0x80) + if ((cmd_byte & 0xC0) == 0x80) { // load vertices (use computed vertex size from FifoCommandRunnable above) u16 numVertices = DataReadU16(); @@ -434,7 +434,7 @@ static void DecodeSemiNop() // draw primitives default: - if (cmd_byte & 0x80) + if ((cmd_byte & 0xC0) == 0x80) { // load vertices (use computed vertex size from FifoCommandRunnable above) u16 numVertices = DataReadU16(); -- cgit v1.2.3 From ce54c1e571a7f79c173dd8f949003255ba95670a Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 3 Jun 2014 01:08:54 -0400 Subject: Kill off replaceable usages of s[n]printf. --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 2500dbdd38..9575563c7c 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -219,22 +219,21 @@ u32 FifoCommandRunnable(u32 &command_size) else { // TODO(Omega): Maybe dump FIFO to file on this error - char szTemp[1024]; - sprintf(szTemp, "GFX FIFO: Unknown Opcode (0x%x).\n" + std::string temp = StringFromFormat( + "GFX FIFO: Unknown Opcode (0x%x).\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" "* This really is an unknown opcode (unlikely)\n" "* Some other sort of bug\n\n" "Dolphin will now likely crash or hang. Enjoy." , cmd_byte); - Host_SysMessage(szTemp); - INFO_LOG(VIDEO, "%s", szTemp); + Host_SysMessage(temp.c_str()); + INFO_LOG(VIDEO, "%s", temp.c_str()); { SCPFifoStruct &fifo = CommandProcessor::fifo; - char szTmp[512]; - // sprintf(szTmp, "Illegal command %02x (at %08x)",cmd_byte,g_pDataReader->GetPtr()); - sprintf(szTmp, "Illegal command %02x\n" + std::string tmp = StringFromFormat( + "Illegal command %02x\n" "CPBase: 0x%08x\n" "CPEnd: 0x%08x\n" "CPHiWatermark: 0x%08x\n" @@ -252,8 +251,8 @@ u32 FifoCommandRunnable(u32 &command_size) ,fifo.bFF_BPEnable ? "true" : "false" ,fifo.bFF_BPInt ? "true" : "false" ,fifo.bFF_Breakpoint ? "true" : "false"); - Host_SysMessage(szTmp); - INFO_LOG(VIDEO, "%s", szTmp); + Host_SysMessage(tmp.c_str()); + INFO_LOG(VIDEO, "%s", tmp.c_str()); } } break; -- cgit v1.2.3 From f1ddd3c66a3a04c455d7ae41cb98e0f7c554c41c Mon Sep 17 00:00:00 2001 From: degasus Date: Mon, 2 Jun 2014 19:36:09 +0200 Subject: VideoCommon: remove unused stats --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 9575563c7c..5370c35750 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -97,7 +97,6 @@ void InterpretDisplayList(u32 address, u32 size) { Decode(); } - INCSTAT(stats.numDListsCalled); INCSTAT(stats.thisFrame.numDListsCalled); // un-swap -- cgit v1.2.3 From 22e1aa5bb4a159d6d66a321f978917614aa36331 Mon Sep 17 00:00:00 2001 From: degasus Date: Tue, 8 Jul 2014 14:29:26 +0200 Subject: mark all local functions as static --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 5370c35750..8b42a20367 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -74,9 +74,6 @@ DataReadU32xNfunc DataReadU32xFuncs[16] = { DataReadU32xN<16> }; -extern u8* GetVideoBufferStartPtr(); -extern u8* GetVideoBufferEndPtr(); - static void Decode(); void InterpretDisplayList(u32 address, u32 size) @@ -107,7 +104,7 @@ void InterpretDisplayList(u32 address, u32 size) g_pVideoData = old_pVideoData; } -u32 FifoCommandRunnable(u32 &command_size) +static u32 FifoCommandRunnable(u32 &command_size) { u32 cycleTime = 0; u32 buffer_size = (u32)(GetVideoBufferEndPtr() - g_pVideoData); @@ -267,7 +264,7 @@ u32 FifoCommandRunnable(u32 &command_size) return cycleTime; } -u32 FifoCommandRunnable() +static u32 FifoCommandRunnable() { u32 command_size = 0; return FifoCommandRunnable(command_size); -- cgit v1.2.3 From 7e79806efcd5c5e41efea89fa385b480ac1882f5 Mon Sep 17 00:00:00 2001 From: degasus Date: Tue, 8 Jul 2014 22:37:58 +0200 Subject: remove unused globals Also change globals into statics which are only used in one file --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 8b42a20367..4dc80f8c3e 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -34,8 +34,9 @@ u8* g_pVideoData = nullptr; bool g_bRecordFifoData = false; +typedef void (*DataReadU32xNfunc)(u32 *buf); #if _M_SSE >= 0x301 -DataReadU32xNfunc DataReadU32xFuncs_SSSE3[16] = { +static DataReadU32xNfunc DataReadU32xFuncs_SSSE3[16] = { DataReadU32xN_SSSE3<1>, DataReadU32xN_SSSE3<2>, DataReadU32xN_SSSE3<3>, @@ -55,7 +56,7 @@ DataReadU32xNfunc DataReadU32xFuncs_SSSE3[16] = { }; #endif -DataReadU32xNfunc DataReadU32xFuncs[16] = { +static DataReadU32xNfunc DataReadU32xFuncs[16] = { DataReadU32xN<1>, DataReadU32xN<2>, DataReadU32xN<3>, -- cgit v1.2.3 From 45a4236283f412ed62eb2a1f6ace54090bbb3a3f Mon Sep 17 00:00:00 2001 From: comex Date: Sun, 24 Aug 2014 18:17:39 -0400 Subject: A tiny restructuring to allow inlining of FifoCommandRunnable. Probably useless. --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 4dc80f8c3e..ff9cd8e735 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -469,12 +469,13 @@ void OpcodeDecoder_Shutdown() u32 OpcodeDecoder_Run(bool skipped_frame) { u32 totalCycles = 0; - u32 cycles = FifoCommandRunnable(); - while (cycles > 0) + while (true) { + u32 cycles = FifoCommandRunnable(); + if (cycles == 0) + break; skipped_frame ? DecodeSemiNop() : Decode(); totalCycles += cycles; - cycles = FifoCommandRunnable(); } return totalCycles; } -- cgit v1.2.3 From 608f9bcd6724c77fef9be8e45ec8f14b49e2b3fb Mon Sep 17 00:00:00 2001 From: comex Date: Mon, 1 Sep 2014 01:11:32 -0400 Subject: Refactor opcode decoding a bit to kill FifoCommandRunnable. Separated out from my gpu-determinism branch by request. It's not a big commit; I just like to write long commit messages. The main reason to kill it is hopefully a slight performance improvement from avoiding the double switch (especially in single core mode); however, this also improves cycle calculation, as described below. - FifoCommandRunnable is removed; in its stead, Decode returns the number of cycles (which only matters for "sync" GPU mode), or 0 if there was not enough data, and is also responsible for unknown opcode alerts. Decode and DecodeSemiNop are almost identical, so the latter is replaced with a skipped_frame parameter to Decode. Doesn't mean we can't improve skipped_frame mode to do less work; if, at such a point, branching on it has too much overhead (it certainly won't now), it can always be changed to a template parameter. - FifoCommandRunnable used a fixed, large cycle count for display lists, regardless of the contents. Presumably the actual hardware's processing time is mostly the processing time of whatever commands are in the list, and with this change InterpretDisplayList can just return the list's cycle count to be added to the total. (Since the calculation for this is part of Decode, it didn't seem easy to split this change up.) To facilitate this, Decode also gains an explicit 'end' parameter in lieu of FifoCommandRunnable's call to GetVideoBufferEndPtr, which can point to there or to the end of a display list (or elsewhere in gpu-determinism, but that's another story). Also, as a small optimization, InterpretDisplayList now calls OpcodeDecoder_Run rather than having its own Decode loop, to allow Decode to be inlined (haven't checked whether this actually happens though). skipped_frame mode still does not traverse display lists and uses the old fake value of 45 cycles. degasus has suggested that this hack is not essential for performance and can be removed, but I want to separate any potential performance impact of that from this commit. --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 374 +++++++++-------------------- 1 file changed, 111 insertions(+), 263 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index ff9cd8e735..fe644db21e 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -75,13 +75,13 @@ static DataReadU32xNfunc DataReadU32xFuncs[16] = { DataReadU32xN<16> }; -static void Decode(); - -void InterpretDisplayList(u32 address, u32 size) +static u32 InterpretDisplayList(u32 address, u32 size) { u8* old_pVideoData = g_pVideoData; u8* startAddress = Memory::GetPointer(address); + u32 cycles = 0; + // Avoid the crash if Memory::GetPointer failed .. if (startAddress != nullptr) { @@ -91,10 +91,7 @@ void InterpretDisplayList(u32 address, u32 size) Statistics::SwapDL(); u8 *end = g_pVideoData + size; - while (g_pVideoData < end) - { - Decode(); - } + cycles = OpcodeDecoder_Run(false, end); INCSTAT(stats.thisFrame.numDListsCalled); // un-swap @@ -103,186 +100,71 @@ void InterpretDisplayList(u32 address, u32 size) // reset to the old pointer g_pVideoData = old_pVideoData; + + return cycles; } -static u32 FifoCommandRunnable(u32 &command_size) +static void UnknownOpcode(u8 cmd_byte, void *buffer, bool preprocess) { - u32 cycleTime = 0; - u32 buffer_size = (u32)(GetVideoBufferEndPtr() - g_pVideoData); - if (buffer_size == 0) - return 0; // can't peek - - u8 cmd_byte = DataPeek8(0); - - switch (cmd_byte) + // TODO(Omega): Maybe dump FIFO to file on this error + std::string temp = StringFromFormat( + "GFX FIFO: Unknown Opcode (0x%x @ %p).\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" + "* This really is an unknown opcode (unlikely)\n" + "* Some other sort of bug\n\n" + "Dolphin will now likely crash or hang. Enjoy." , + cmd_byte, + buffer); + Host_SysMessage(temp.c_str()); + INFO_LOG(VIDEO, "%s", temp.c_str()); { - 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 - 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) - { - 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 - { - return 0; - } - } - break; - - default: - if ((cmd_byte & 0xC0) == 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 0; - } - } - else - { - // TODO(Omega): Maybe dump FIFO to file on this error - std::string temp = StringFromFormat( - "GFX FIFO: Unknown Opcode (0x%x).\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" - "* This really is an unknown opcode (unlikely)\n" - "* Some other sort of bug\n\n" - "Dolphin will now likely crash or hang. Enjoy." , cmd_byte); - Host_SysMessage(temp.c_str()); - INFO_LOG(VIDEO, "%s", temp.c_str()); - { - SCPFifoStruct &fifo = CommandProcessor::fifo; - - std::string tmp = StringFromFormat( - "Illegal command %02x\n" - "CPBase: 0x%08x\n" - "CPEnd: 0x%08x\n" - "CPHiWatermark: 0x%08x\n" - "CPLoWatermark: 0x%08x\n" - "CPReadWriteDistance: 0x%08x\n" - "CPWritePointer: 0x%08x\n" - "CPReadPointer: 0x%08x\n" - "CPBreakpoint: 0x%08x\n" - "bFF_GPReadEnable: %s\n" - "bFF_BPEnable: %s\n" - "bFF_BPInt: %s\n" - "bFF_Breakpoint: %s\n" - ,cmd_byte, fifo.CPBase, fifo.CPEnd, fifo.CPHiWatermark, fifo.CPLoWatermark, fifo.CPReadWriteDistance - ,fifo.CPWritePointer, fifo.CPReadPointer, fifo.CPBreakpoint, fifo.bFF_GPReadEnable ? "true" : "false" - ,fifo.bFF_BPEnable ? "true" : "false" ,fifo.bFF_BPInt ? "true" : "false" - ,fifo.bFF_Breakpoint ? "true" : "false"); - - Host_SysMessage(tmp.c_str()); - INFO_LOG(VIDEO, "%s", tmp.c_str()); - } - } - break; + SCPFifoStruct &fifo = CommandProcessor::fifo; + + std::string tmp = StringFromFormat( + "Illegal command %02x\n" + "CPBase: 0x%08x\n" + "CPEnd: 0x%08x\n" + "CPHiWatermark: 0x%08x\n" + "CPLoWatermark: 0x%08x\n" + "CPReadWriteDistance: 0x%08x\n" + "CPWritePointer: 0x%08x\n" + "CPReadPointer: 0x%08x\n" + "CPBreakpoint: 0x%08x\n" + "bFF_GPReadEnable: %s\n" + "bFF_BPEnable: %s\n" + "bFF_BPInt: %s\n" + "bFF_Breakpoint: %s\n" + ,cmd_byte, fifo.CPBase, fifo.CPEnd, fifo.CPHiWatermark, fifo.CPLoWatermark, fifo.CPReadWriteDistance + ,fifo.CPWritePointer, fifo.CPReadPointer, fifo.CPBreakpoint, fifo.bFF_GPReadEnable ? "true" : "false" + ,fifo.bFF_BPEnable ? "true" : "false" ,fifo.bFF_BPInt ? "true" : "false" + ,fifo.bFF_Breakpoint ? "true" : "false"); + + Host_SysMessage(tmp.c_str()); + INFO_LOG(VIDEO, "%s", tmp.c_str()); } - - 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); - if (cycleTime == 0) - cycleTime = 6; - - return cycleTime; } -static u32 FifoCommandRunnable() -{ - u32 command_size = 0; - return FifoCommandRunnable(command_size); -} - -static void Decode() +static u32 Decode(u8* end, bool skipped_frame) { u8 *opcodeStart = g_pVideoData; + if (g_pVideoData == end) + return 0; - int cmd_byte = DataReadU8(); + u8 cmd_byte = DataReadU8(); + u32 cycles; switch (cmd_byte) { case GX_NOP: + cycles = 6; // Hm, this means that we scan over nop streams pretty slowly... break; case GX_LOAD_CP_REG: //0x08 { + if (end - g_pVideoData < 1 + 4) + return 0; + cycles = 12; u8 sub_cmd = DataReadU8(); u32 value = DataReadU32(); LoadCPReg(sub_cmd, value); @@ -292,8 +174,13 @@ static void Decode() case GX_LOAD_XF_REG: { + if (end - g_pVideoData < 4) + return 0; u32 Cmd2 = DataReadU32(); int transfer_size = ((Cmd2 >> 16) & 15) + 1; + if ((size_t) (end - g_pVideoData) < transfer_size * sizeof(u32)) + return 0; + cycles = 18 + 6 * transfer_size; u32 xf_address = Cmd2 & 0xFFFF; GC_ALIGNED128(u32 data_buffer[16]); DataReadU32xFuncs[transfer_size-1](data_buffer); @@ -304,36 +191,60 @@ static void Decode() break; case GX_LOAD_INDX_A: //used for position matrices + if (end - g_pVideoData < 4) + return 0; + cycles = 6; LoadIndexedXF(DataReadU32(), 0xC); break; case GX_LOAD_INDX_B: //used for normal matrices + if (end - g_pVideoData < 4) + return 0; + cycles = 6; LoadIndexedXF(DataReadU32(), 0xD); break; case GX_LOAD_INDX_C: //used for postmatrices + if (end - g_pVideoData < 4) + return 0; + cycles = 6; LoadIndexedXF(DataReadU32(), 0xE); break; case GX_LOAD_INDX_D: //used for lights + if (end - g_pVideoData < 4) + return 0; + cycles = 6; LoadIndexedXF(DataReadU32(), 0xF); break; case GX_CMD_CALL_DL: { + if (end - g_pVideoData < 8) + return 0; u32 address = DataReadU32(); u32 count = DataReadU32(); - InterpretDisplayList(address, count); + if (skipped_frame) + cycles = 45; // xxx + else + cycles = 6 + InterpretDisplayList(address, count); } break; case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that + cycles = 6; DEBUG_LOG(VIDEO, "GX 0x44: %08x", cmd_byte); break; case GX_CMD_INVL_VC: // Invalidate Vertex Cache + cycles = 6; DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)"); break; case GX_LOAD_BP_REG: //0x61 + // 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_pVideoData < 4) + return 0; + cycles = 12; u32 bp_cmd = DataReadU32(); LoadBPReg(bp_cmd); INCSTAT(stats.thisFrame.numBPLoads); @@ -344,18 +255,33 @@ static void Decode() default: if ((cmd_byte & 0xC0) == 0x80) { - // load vertices (use computed vertex size from FifoCommandRunnable above) + cycles = 1600; + // load vertices + if (end - g_pVideoData < 2) + return 0; u16 numVertices = DataReadU16(); - VertexLoaderManager::RunVertices( - cmd_byte & GX_VAT_MASK, // Vertex loader index (0 - 7) - (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, - numVertices); + if (skipped_frame) + { + size_t size = numVertices * VertexLoaderManager::GetVertexSize(cmd_byte & GX_VAT_MASK); + if ((size_t) (end - g_pVideoData) < size) + return 0; + DataSkip((u32)size); + } + else + { + if (!VertexLoaderManager::RunVertices( + cmd_byte & GX_VAT_MASK, // Vertex loader index (0 - 7) + (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, + numVertices, + end - g_pVideoData)) + return 0; + } } else { - ERROR_LOG(VIDEO, "OpcodeDecoding::Decode: Illegal command %02x", cmd_byte); - break; + UnknownOpcode(cmd_byte, opcodeStart, false); + cycles = 1; } break; } @@ -363,89 +289,8 @@ static void Decode() // Display lists get added directly into the FIFO stream if (g_bRecordFifoData && cmd_byte != GX_CMD_CALL_DL) 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: - 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: - // Hm, wonder if any games put tokens in display lists - in that case, - // we'll have to parse them too. - DataSkip(8); - break; - - 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); - INCSTAT(stats.thisFrame.numBPLoads); - } - break; - - // draw primitives - default: - if ((cmd_byte & 0xC0) == 0x80) - { - // load vertices (use computed vertex size from FifoCommandRunnable above) - u16 numVertices = DataReadU16(); - DataSkip(numVertices * VertexLoaderManager::GetVertexSize(cmd_byte & GX_VAT_MASK)); - } - else - { - ERROR_LOG(VIDEO, "OpcodeDecoding::Decode: Illegal command %02x", cmd_byte); - break; - } - break; - } - - if (g_bRecordFifoData && cmd_byte != GX_CMD_CALL_DL) - FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, u32(g_pVideoData - opcodeStart)); + return cycles; } void OpcodeDecoder_Init() @@ -466,15 +311,18 @@ void OpcodeDecoder_Shutdown() { } -u32 OpcodeDecoder_Run(bool skipped_frame) +u32 OpcodeDecoder_Run(bool skipped_frame, u8* end) { u32 totalCycles = 0; while (true) { - u32 cycles = FifoCommandRunnable(); + u8* old = g_pVideoData; + u32 cycles = Decode(end, skipped_frame); if (cycles == 0) + { + g_pVideoData = old; break; - skipped_frame ? DecodeSemiNop() : Decode(); + } totalCycles += cycles; } return totalCycles; -- cgit v1.2.3 From ef6f6a7fa9a90efa78d0ae557e5546dd6568bb74 Mon Sep 17 00:00:00 2001 From: degasus Date: Wed, 3 Sep 2014 22:39:26 +0200 Subject: VideoCommon: remove XFReg copy optimization This code is just ugly and I doubt there is a way that copying twice is faster. --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 53 +----------------------------- 1 file changed, 1 insertion(+), 52 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index fe644db21e..a5bd8a62ee 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -34,47 +34,6 @@ u8* g_pVideoData = nullptr; bool g_bRecordFifoData = false; -typedef void (*DataReadU32xNfunc)(u32 *buf); -#if _M_SSE >= 0x301 -static DataReadU32xNfunc DataReadU32xFuncs_SSSE3[16] = { - DataReadU32xN_SSSE3<1>, - DataReadU32xN_SSSE3<2>, - DataReadU32xN_SSSE3<3>, - DataReadU32xN_SSSE3<4>, - DataReadU32xN_SSSE3<5>, - DataReadU32xN_SSSE3<6>, - DataReadU32xN_SSSE3<7>, - DataReadU32xN_SSSE3<8>, - DataReadU32xN_SSSE3<9>, - DataReadU32xN_SSSE3<10>, - DataReadU32xN_SSSE3<11>, - DataReadU32xN_SSSE3<12>, - DataReadU32xN_SSSE3<13>, - DataReadU32xN_SSSE3<14>, - DataReadU32xN_SSSE3<15>, - DataReadU32xN_SSSE3<16> -}; -#endif - -static DataReadU32xNfunc DataReadU32xFuncs[16] = { - DataReadU32xN<1>, - DataReadU32xN<2>, - DataReadU32xN<3>, - DataReadU32xN<4>, - DataReadU32xN<5>, - DataReadU32xN<6>, - DataReadU32xN<7>, - DataReadU32xN<8>, - DataReadU32xN<9>, - DataReadU32xN<10>, - DataReadU32xN<11>, - DataReadU32xN<12>, - DataReadU32xN<13>, - DataReadU32xN<14>, - DataReadU32xN<15>, - DataReadU32xN<16> -}; - static u32 InterpretDisplayList(u32 address, u32 size) { u8* old_pVideoData = g_pVideoData; @@ -182,9 +141,7 @@ static u32 Decode(u8* end, bool skipped_frame) return 0; cycles = 18 + 6 * transfer_size; 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); INCSTAT(stats.thisFrame.numXFLoads); } @@ -296,14 +253,6 @@ static u32 Decode(u8* end, bool skipped_frame) void OpcodeDecoder_Init() { g_pVideoData = GetVideoBufferStartPtr(); - -#if _M_SSE >= 0x301 - if (cpu_info.bSSSE3) - { - for (int i = 0; i < 16; ++i) - DataReadU32xFuncs[i] = DataReadU32xFuncs_SSSE3[i]; - } -#endif } -- cgit v1.2.3 From 8b84ddce9a3e9c889996e2022279f78ef7a4ab5c Mon Sep 17 00:00:00 2001 From: degasus Date: Wed, 3 Sep 2014 21:49:15 +0200 Subject: VideoCommon: rewrite frame skipping code --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 34 +++++++++++------------------- 1 file changed, 12 insertions(+), 22 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index fe644db21e..884a8c978a 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -91,7 +91,7 @@ static u32 InterpretDisplayList(u32 address, u32 size) Statistics::SwapDL(); u8 *end = g_pVideoData + size; - cycles = OpcodeDecoder_Run(false, end); + cycles = OpcodeDecoder_Run(end); INCSTAT(stats.thisFrame.numDListsCalled); // un-swap @@ -146,7 +146,7 @@ static void UnknownOpcode(u8 cmd_byte, void *buffer, bool preprocess) } } -static u32 Decode(u8* end, bool skipped_frame) +static u32 Decode(u8* end) { u8 *opcodeStart = g_pVideoData; if (g_pVideoData == end) @@ -221,10 +221,7 @@ static u32 Decode(u8* end, bool skipped_frame) return 0; u32 address = DataReadU32(); u32 count = DataReadU32(); - if (skipped_frame) - cycles = 45; // xxx - else - cycles = 6 + InterpretDisplayList(address, count); + cycles = 6 + InterpretDisplayList(address, count); } break; @@ -261,21 +258,14 @@ static u32 Decode(u8* end, bool skipped_frame) return 0; u16 numVertices = DataReadU16(); - if (skipped_frame) + if (!VertexLoaderManager::RunVertices( + cmd_byte & GX_VAT_MASK, // Vertex loader index (0 - 7) + (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, + numVertices, + end - g_pVideoData, + g_bSkipCurrentFrame)) { - size_t size = numVertices * VertexLoaderManager::GetVertexSize(cmd_byte & GX_VAT_MASK); - if ((size_t) (end - g_pVideoData) < size) - return 0; - DataSkip((u32)size); - } - else - { - if (!VertexLoaderManager::RunVertices( - cmd_byte & GX_VAT_MASK, // Vertex loader index (0 - 7) - (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, - numVertices, - end - g_pVideoData)) - return 0; + return 0; } } else @@ -311,13 +301,13 @@ void OpcodeDecoder_Shutdown() { } -u32 OpcodeDecoder_Run(bool skipped_frame, u8* end) +u32 OpcodeDecoder_Run(u8* end) { u32 totalCycles = 0; while (true) { u8* old = g_pVideoData; - u32 cycles = Decode(end, skipped_frame); + u32 cycles = Decode(end); if (cycles == 0) { g_pVideoData = old; -- cgit v1.2.3 From fbc64984ca7de7db10b1a8a4f49002f260c93569 Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Sun, 7 Sep 2014 20:06:58 -0500 Subject: Include CommonTypes.h instead of Common.h. --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 2b9e314ec0..e9a20a526a 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -12,7 +12,7 @@ // while interpreting them, and hope that the vertex format doesn't change, though, if you do it right // when they are called. The reason is that the vertex format affects the sizes of the vertices. -#include "Common/Common.h" +#include "Common/CommonTypes.h" #include "Common/CPUDetect.h" #include "Core/Core.h" #include "Core/Host.h" -- cgit v1.2.3 From 0ae9e398c8e0f808eb4da6cc6f5e3cd553e975a1 Mon Sep 17 00:00:00 2001 From: comex Date: Tue, 26 Aug 2014 13:37:32 -0400 Subject: Rejigger some FIFO buffer variables to be more rational. videoBuffer -> s_video_buffer size -> s_video_buffer_write_ptr g_pVideoData -> g_video_buffer_read_ptr (impl moved to Fifo.cpp) This eradicates the wonderful use of 'size' as a global name, and makes it clear that s_video_buffer_write_ptr and g_video_buffer_read_ptr are the two ends of the FIFO buffer s_video_buffer. Oh, and remove a useless namespace {}. --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 43 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 22 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index e9a20a526a..fe70bcf492 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -31,12 +31,11 @@ #include "VideoCommon/XFMemory.h" -u8* g_pVideoData = nullptr; bool g_bRecordFifoData = false; static u32 InterpretDisplayList(u32 address, u32 size) { - u8* old_pVideoData = g_pVideoData; + u8* old_pVideoData = g_video_buffer_read_ptr; u8* startAddress = Memory::GetPointer(address); u32 cycles = 0; @@ -44,12 +43,12 @@ static u32 InterpretDisplayList(u32 address, u32 size) // Avoid the crash if Memory::GetPointer failed .. if (startAddress != nullptr) { - g_pVideoData = startAddress; + g_video_buffer_read_ptr = startAddress; // temporarily swap dl and non-dl (small "hack" for the stats) Statistics::SwapDL(); - u8 *end = g_pVideoData + size; + u8 *end = g_video_buffer_read_ptr + size; cycles = OpcodeDecoder_Run(end); INCSTAT(stats.thisFrame.numDListsCalled); @@ -58,7 +57,7 @@ static u32 InterpretDisplayList(u32 address, u32 size) } // reset to the old pointer - g_pVideoData = old_pVideoData; + g_video_buffer_read_ptr = old_pVideoData; return cycles; } @@ -107,8 +106,8 @@ static void UnknownOpcode(u8 cmd_byte, void *buffer, bool preprocess) static u32 Decode(u8* end) { - u8 *opcodeStart = g_pVideoData; - if (g_pVideoData == end) + u8 *opcodeStart = g_video_buffer_read_ptr; + if (g_video_buffer_read_ptr == end) return 0; u8 cmd_byte = DataReadU8(); @@ -121,7 +120,7 @@ static u32 Decode(u8* end) case GX_LOAD_CP_REG: //0x08 { - if (end - g_pVideoData < 1 + 4) + if (end - g_video_buffer_read_ptr < 1 + 4) return 0; cycles = 12; u8 sub_cmd = DataReadU8(); @@ -133,11 +132,11 @@ static u32 Decode(u8* end) case GX_LOAD_XF_REG: { - if (end - g_pVideoData < 4) + if (end - g_video_buffer_read_ptr < 4) return 0; u32 Cmd2 = DataReadU32(); int transfer_size = ((Cmd2 >> 16) & 15) + 1; - if ((size_t) (end - g_pVideoData) < transfer_size * sizeof(u32)) + if ((size_t) (end - g_video_buffer_read_ptr) < transfer_size * sizeof(u32)) return 0; cycles = 18 + 6 * transfer_size; u32 xf_address = Cmd2 & 0xFFFF; @@ -148,25 +147,25 @@ static u32 Decode(u8* end) break; case GX_LOAD_INDX_A: //used for position matrices - if (end - g_pVideoData < 4) + if (end - g_video_buffer_read_ptr < 4) return 0; cycles = 6; LoadIndexedXF(DataReadU32(), 0xC); break; case GX_LOAD_INDX_B: //used for normal matrices - if (end - g_pVideoData < 4) + if (end - g_video_buffer_read_ptr < 4) return 0; cycles = 6; LoadIndexedXF(DataReadU32(), 0xD); break; case GX_LOAD_INDX_C: //used for postmatrices - if (end - g_pVideoData < 4) + if (end - g_video_buffer_read_ptr < 4) return 0; cycles = 6; LoadIndexedXF(DataReadU32(), 0xE); break; case GX_LOAD_INDX_D: //used for lights - if (end - g_pVideoData < 4) + if (end - g_video_buffer_read_ptr < 4) return 0; cycles = 6; LoadIndexedXF(DataReadU32(), 0xF); @@ -174,7 +173,7 @@ static u32 Decode(u8* end) case GX_CMD_CALL_DL: { - if (end - g_pVideoData < 8) + if (end - g_video_buffer_read_ptr < 8) return 0; u32 address = DataReadU32(); u32 count = DataReadU32(); @@ -196,7 +195,7 @@ 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_pVideoData < 4) + if (end - g_video_buffer_read_ptr < 4) return 0; cycles = 12; u32 bp_cmd = DataReadU32(); @@ -211,7 +210,7 @@ static u32 Decode(u8* end) { cycles = 1600; // load vertices - if (end - g_pVideoData < 2) + if (end - g_video_buffer_read_ptr < 2) return 0; u16 numVertices = DataReadU16(); @@ -219,7 +218,7 @@ static u32 Decode(u8* end) cmd_byte & GX_VAT_MASK, // Vertex loader index (0 - 7) (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, numVertices, - end - g_pVideoData, + end - g_video_buffer_read_ptr, g_bSkipCurrentFrame)) { return 0; @@ -235,14 +234,14 @@ static u32 Decode(u8* end) // Display lists get added directly into the FIFO stream if (g_bRecordFifoData && cmd_byte != GX_CMD_CALL_DL) - FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, u32(g_pVideoData - opcodeStart)); + FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, u32(g_video_buffer_read_ptr - opcodeStart)); return cycles; } void OpcodeDecoder_Init() { - g_pVideoData = GetVideoBufferStartPtr(); + g_video_buffer_read_ptr = GetVideoBufferStartPtr(); } @@ -255,11 +254,11 @@ u32 OpcodeDecoder_Run(u8* end) u32 totalCycles = 0; while (true) { - u8* old = g_pVideoData; + u8* old = g_video_buffer_read_ptr; u32 cycles = Decode(end); if (cycles == 0) { - g_pVideoData = old; + g_video_buffer_read_ptr = old; break; } totalCycles += cycles; -- cgit v1.2.3 From 65af90669bd5f9e02bbaa994d51d5c83d147b868 Mon Sep 17 00:00:00 2001 From: comex Date: Wed, 27 Aug 2014 22:56:19 -0400 Subject: Add the 'desynced GPU thread' mode. It's a relatively big commit (less big with -w), but it's hard to test any of this separately... The basic problem is that in netplay or movies, the state of the CPU must be deterministic, including when the game receives notification that the GPU has processed FIFO data. Dual core mode notifies the game whenever the GPU thread actually gets around to doing the work, so it isn't deterministic. Single core mode is because it notifies the game 'instantly' (after processing the data synchronously), but it's too slow for many systems and games. My old dc-netplay branch worked as follows: everything worked as normal except the state of the CP registers was a lie, and the CPU thread only delivered results when idle detection triggered (waiting for the GPU if they weren't ready at that point). Usually, a game is idle iff all the work for the frame has been done, except for a small amount of work depending on the GPU result, so neither the CPU or the GPU waiting on the other affected performance much. However, it's possible that the game could be waiting for some earlier interrupt, and any of several games which, for whatever reason, never went into a detectable idle (even when I tried to improve the detection) would never receive results at all. (The current method should have better compatibility, but it also has slightly higher overhead and breaks some other things, so I want to reimplement this, hopefully with less impact on the code, in the future.) With this commit, the basic idea is that the CPU thread acts as if the work has been done instantly, like single core mode, but actually hands it off asynchronously to the GPU thread (after backing up some data that the game might change in memory before it's actually done). Since the work isn't done, any feedback from the GPU to the CPU, such as real XFB/EFB copies (virtual are OK), EFB pokes, performance queries, etc. is broken; but most games work with these options disabled, and there is no need to try to detect what the CPU thread is doing. Technically: when the flag g_use_deterministic_gpu_thread (currently stuck on) is on, the CPU thread calls RunGpu like in single core mode. This function synchronously copies the data from the FIFO to the internal video buffer and updates the CP registers, interrupts, etc. However, instead of the regular ReadDataFromFifo followed by running the opcode decoder, it runs ReadDataFromFifoOnCPU -> OpcodeDecoder_Preprocess, which relatively quickly scans through the FIFO data, detects SetFinish calls etc., which are immediately fired, and saves certain associated data from memory (e.g. display lists) in AuxBuffers (a parallel stream to the main FIFO, which is a bit slow at the moment), before handing the data off to the GPU thread to actually render. That makes up the bulk of this commit. In various circumstances, including the aforementioned EFB pokes and performance queries as well as swap requests (i.e. the end of a frame - we don't want the CPU potentially pumping out frames too quickly and the GPU falling behind*), SyncGPU is called to wait for actual completion. The overhead mainly comes from OpcodeDecoder_Preprocess (which is, again, synchronous), as well as the actual copying. Currently, display lists and such are escrowed from main memory even though they usually won't change over the course of a frame, and textures are not even though they might, resulting in a small chance of graphical glitches. When the texture locking (i.e. fault on write) code lands, I can make this all correct and maybe a little faster. * This suggests an alternate determinism method of just delaying results until a short time before the end of each frame. For all I know this might mostly work - I haven't tried it - but if any significant work hinges on the competion of render to texture etc., the frame will be missed. --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 180 ++++++++++++++++++++--------- 1 file changed, 123 insertions(+), 57 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') 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 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(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(bufp); + u32 value = DataRead(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(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(bufp), refarray); + else + LoadIndexedXF(DataRead(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(bufp); + u32 count = DataRead(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(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(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(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(end); + if (cycles == 0) + { + g_video_buffer_pp_read_ptr = old; + break; + } + } +} -- cgit v1.2.3 From 884ec2ed13bd47c188317a9b91b8af20876d9919 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 5 Nov 2014 02:22:33 -0500 Subject: Host: Kill off Host_SysMessage Equivalent facilities already exist. --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 64 ++++++++++++++---------------- 1 file changed, 30 insertions(+), 34 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 1bb5fae940..1f71bd051b 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -89,43 +89,39 @@ static void InterpretDisplayListPreprocess(u32 address, u32 size) 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, 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" - "* This really is an unknown opcode (unlikely)\n" - "* Some other sort of bug\n\n" - "Dolphin will now likely crash or hang. Enjoy." , - cmd_byte, - buffer, - preprocess ? "yes" : "no"); - Host_SysMessage(temp.c_str()); - INFO_LOG(VIDEO, "%s", temp.c_str()); + PanicAlert( + "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" + "* This really is an unknown opcode (unlikely)\n" + "* Some other sort of bug\n\n" + "Dolphin will now likely crash or hang. Enjoy." , + cmd_byte, + buffer, + preprocess ? "yes" : "no"); + { SCPFifoStruct &fifo = CommandProcessor::fifo; - std::string tmp = StringFromFormat( - "Illegal command %02x\n" - "CPBase: 0x%08x\n" - "CPEnd: 0x%08x\n" - "CPHiWatermark: 0x%08x\n" - "CPLoWatermark: 0x%08x\n" - "CPReadWriteDistance: 0x%08x\n" - "CPWritePointer: 0x%08x\n" - "CPReadPointer: 0x%08x\n" - "CPBreakpoint: 0x%08x\n" - "bFF_GPReadEnable: %s\n" - "bFF_BPEnable: %s\n" - "bFF_BPInt: %s\n" - "bFF_Breakpoint: %s\n" - ,cmd_byte, fifo.CPBase, fifo.CPEnd, fifo.CPHiWatermark, fifo.CPLoWatermark, fifo.CPReadWriteDistance - ,fifo.CPWritePointer, fifo.CPReadPointer, fifo.CPBreakpoint, fifo.bFF_GPReadEnable ? "true" : "false" - ,fifo.bFF_BPEnable ? "true" : "false" ,fifo.bFF_BPInt ? "true" : "false" - ,fifo.bFF_Breakpoint ? "true" : "false"); - - Host_SysMessage(tmp.c_str()); - INFO_LOG(VIDEO, "%s", tmp.c_str()); + PanicAlert( + "Illegal command %02x\n" + "CPBase: 0x%08x\n" + "CPEnd: 0x%08x\n" + "CPHiWatermark: 0x%08x\n" + "CPLoWatermark: 0x%08x\n" + "CPReadWriteDistance: 0x%08x\n" + "CPWritePointer: 0x%08x\n" + "CPReadPointer: 0x%08x\n" + "CPBreakpoint: 0x%08x\n" + "bFF_GPReadEnable: %s\n" + "bFF_BPEnable: %s\n" + "bFF_BPInt: %s\n" + "bFF_Breakpoint: %s\n" + ,cmd_byte, fifo.CPBase, fifo.CPEnd, fifo.CPHiWatermark, fifo.CPLoWatermark, fifo.CPReadWriteDistance + ,fifo.CPWritePointer, fifo.CPReadPointer, fifo.CPBreakpoint, fifo.bFF_GPReadEnable ? "true" : "false" + ,fifo.bFF_BPEnable ? "true" : "false" ,fifo.bFF_BPInt ? "true" : "false" + ,fifo.bFF_Breakpoint ? "true" : "false"); } } -- cgit v1.2.3 From 90613a1bda4d80e4c2760ad5f3ebdefd53a19a87 Mon Sep 17 00:00:00 2001 From: degasus Date: Sat, 15 Nov 2014 16:24:06 +0100 Subject: OpcodeDecoder: Skip recursiv display lists --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 1f71bd051b..5c3544aecb 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -55,7 +55,7 @@ static u32 InterpretDisplayList(u32 address, u32 size) Statistics::SwapDL(); u8 *end = g_video_buffer_read_ptr + size; - cycles = OpcodeDecoder_Run(end); + cycles = OpcodeDecoder_Run(end, true); INCSTAT(stats.thisFrame.numDListsCalled); // un-swap @@ -80,7 +80,7 @@ static void InterpretDisplayListPreprocess(u32 address, u32 size) g_video_buffer_pp_read_ptr = startAddress; u8 *end = startAddress + size; - OpcodeDecoder_Preprocess(end); + OpcodeDecoder_Preprocess(end, true); } g_video_buffer_pp_read_ptr = old_read_ptr; @@ -126,7 +126,7 @@ static void UnknownOpcode(u8 cmd_byte, void *buffer, bool preprocess) } template -static u32 Decode(u8* end) +static u32 Decode(u8* end, bool in_display_list) { u8 *opcodeStart = *bufp; if (*bufp == end) @@ -205,10 +205,19 @@ static u32 Decode(u8* end) return 0; u32 address = DataRead(bufp); u32 count = DataRead(bufp); - if (is_preprocess) - InterpretDisplayListPreprocess(address, count); + + if (in_display_list) + { + cycles = 6; + WARN_LOG(VIDEO,"recursive display list detected"); + } else - cycles = 6 + InterpretDisplayList(address, count); + { + if (is_preprocess) + InterpretDisplayListPreprocess(address, count); + else + cycles = 6 + InterpretDisplayList(address, count); + } } break; @@ -297,13 +306,13 @@ void OpcodeDecoder_Shutdown() { } -u32 OpcodeDecoder_Run(u8* end) +u32 OpcodeDecoder_Run(u8* end, bool in_display_list) { u32 totalCycles = 0; while (true) { u8* old = g_video_buffer_read_ptr; - u32 cycles = Decode(end); + u32 cycles = Decode(end, in_display_list); if (cycles == 0) { g_video_buffer_read_ptr = old; @@ -314,12 +323,12 @@ u32 OpcodeDecoder_Run(u8* end) return totalCycles; } -void OpcodeDecoder_Preprocess(u8 *end) +void OpcodeDecoder_Preprocess(u8 *end, bool in_display_list) { while (true) { u8* old = g_video_buffer_pp_read_ptr; - u32 cycles = Decode(end); + u32 cycles = Decode(end, in_display_list); if (cycles == 0) { g_video_buffer_pp_read_ptr = old; -- cgit v1.2.3 From 3d448e49c6b2cb51121e85046ee4b96c18b12e01 Mon Sep 17 00:00:00 2001 From: skidau Date: Fri, 14 Nov 2014 17:07:11 +1100 Subject: Update CPStatus before processing the FIFO events and force an exception check on interrupts. Added more information into the FIFO unknown opcode error message. --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 5c3544aecb..a7dd5b6a85 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -118,10 +118,19 @@ static void UnknownOpcode(u8 cmd_byte, void *buffer, bool preprocess) "bFF_BPEnable: %s\n" "bFF_BPInt: %s\n" "bFF_Breakpoint: %s\n" + "bFF_GPLinkEnable: %s\n" + "bFF_HiWatermarkInt: %s\n" + "bFF_LoWatermarkInt: %s\n" ,cmd_byte, fifo.CPBase, fifo.CPEnd, fifo.CPHiWatermark, fifo.CPLoWatermark, fifo.CPReadWriteDistance - ,fifo.CPWritePointer, fifo.CPReadPointer, fifo.CPBreakpoint, fifo.bFF_GPReadEnable ? "true" : "false" - ,fifo.bFF_BPEnable ? "true" : "false" ,fifo.bFF_BPInt ? "true" : "false" - ,fifo.bFF_Breakpoint ? "true" : "false"); + ,fifo.CPWritePointer, fifo.CPReadPointer, fifo.CPBreakpoint + ,fifo.bFF_GPReadEnable ? "true" : "false" + ,fifo.bFF_BPEnable ? "true" : "false" + ,fifo.bFF_BPInt ? "true" : "false" + ,fifo.bFF_Breakpoint ? "true" : "false" + ,fifo.bFF_GPLinkEnable ? "true" : "false" + ,fifo.bFF_HiWatermarkInt ? "true" : "false" + ,fifo.bFF_LoWatermarkInt ? "true" : "false" + ); } } -- cgit v1.2.3 From 4b22885ed8b7c56f5332b855defb83a24a0aa33c Mon Sep 17 00:00:00 2001 From: degasus Date: Wed, 26 Nov 2014 22:12:54 +0100 Subject: VideoCommon: fifo cleanups --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 42 ++++++++++++++++-------------- 1 file changed, 23 insertions(+), 19 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index a7dd5b6a85..c5b1a09099 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -34,6 +34,9 @@ bool g_bRecordFifoData = false; +u8* g_video_buffer_read_ptr; +static u8* s_video_buffer_pp_read_ptr; + static u32 InterpretDisplayList(u32 address, u32 size) { u8* old_pVideoData = g_video_buffer_read_ptr; @@ -49,13 +52,10 @@ static u32 InterpretDisplayList(u32 address, u32 size) // Avoid the crash if Memory::GetPointer failed .. if (startAddress != nullptr) { - g_video_buffer_read_ptr = startAddress; - // temporarily swap dl and non-dl (small "hack" for the stats) Statistics::SwapDL(); - u8 *end = g_video_buffer_read_ptr + size; - cycles = OpcodeDecoder_Run(end, true); + OpcodeDecoder_Run(startAddress, startAddress + size, &cycles, true); INCSTAT(stats.thisFrame.numDListsCalled); // un-swap @@ -70,20 +70,17 @@ static u32 InterpretDisplayList(u32 address, u32 size) static void InterpretDisplayListPreprocess(u32 address, u32 size) { - u8* old_read_ptr = g_video_buffer_pp_read_ptr; + u8* old_read_ptr = s_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, true); + OpcodeDecoder_Preprocess(startAddress, startAddress + size, true); } - g_video_buffer_pp_read_ptr = old_read_ptr; + s_video_buffer_pp_read_ptr = old_read_ptr; } static void UnknownOpcode(u8 cmd_byte, void *buffer, bool preprocess) @@ -315,33 +312,40 @@ void OpcodeDecoder_Shutdown() { } -u32 OpcodeDecoder_Run(u8* end, bool in_display_list) +u8* OpcodeDecoder_Run(u8* start, u8* end, u32* cycles, bool in_display_list) { + g_video_buffer_read_ptr = start; u32 totalCycles = 0; while (true) { u8* old = g_video_buffer_read_ptr; - u32 cycles = Decode(end, in_display_list); - if (cycles == 0) + u32 cycles_op = Decode(end, in_display_list); + if (cycles_op == 0) { g_video_buffer_read_ptr = old; break; } - totalCycles += cycles; + totalCycles += cycles_op; + } + if (cycles) + { + *cycles = totalCycles; } - return totalCycles; + return g_video_buffer_read_ptr; } -void OpcodeDecoder_Preprocess(u8 *end, bool in_display_list) +u8* OpcodeDecoder_Preprocess(u8* start, u8 *end, bool in_display_list) { + s_video_buffer_pp_read_ptr = start; while (true) { - u8* old = g_video_buffer_pp_read_ptr; - u32 cycles = Decode(end, in_display_list); + u8* old = s_video_buffer_pp_read_ptr; + u32 cycles = Decode(end, in_display_list); if (cycles == 0) { - g_video_buffer_pp_read_ptr = old; + s_video_buffer_pp_read_ptr = old; break; } } + return s_video_buffer_pp_read_ptr; } -- cgit v1.2.3 From 21970c4a2a728669687a687f61a8f7453319dd54 Mon Sep 17 00:00:00 2001 From: degasus Date: Thu, 27 Nov 2014 23:53:11 +0100 Subject: VideoCommon: cleanup OpcodeDecoder --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 349 +++++++++++++---------------- 1 file changed, 156 insertions(+), 193 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index c5b1a09099..12a9d5b350 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -34,12 +34,8 @@ bool g_bRecordFifoData = false; -u8* g_video_buffer_read_ptr; -static u8* s_video_buffer_pp_read_ptr; - static u32 InterpretDisplayList(u32 address, u32 size) { - u8* old_pVideoData = g_video_buffer_read_ptr; u8* startAddress; if (g_use_deterministic_gpu_thread) @@ -55,32 +51,26 @@ static u32 InterpretDisplayList(u32 address, u32 size) // temporarily swap dl and non-dl (small "hack" for the stats) Statistics::SwapDL(); - OpcodeDecoder_Run(startAddress, startAddress + size, &cycles, true); + OpcodeDecoder_Run(DataReader(startAddress, startAddress + size), &cycles, true); INCSTAT(stats.thisFrame.numDListsCalled); // un-swap Statistics::SwapDL(); } - // reset to the old pointer - g_video_buffer_read_ptr = old_pVideoData; - return cycles; } static void InterpretDisplayListPreprocess(u32 address, u32 size) { - u8* old_read_ptr = s_video_buffer_pp_read_ptr; u8* startAddress = Memory::GetPointer(address); PushFifoAuxBuffer(startAddress, size); if (startAddress != nullptr) { - OpcodeDecoder_Preprocess(startAddress, startAddress + size, true); + OpcodeDecoder_Run(DataReader(startAddress, startAddress + size), nullptr, true); } - - s_video_buffer_pp_read_ptr = old_read_ptr; } static void UnknownOpcode(u8 cmd_byte, void *buffer, bool preprocess) @@ -131,221 +121,194 @@ static void UnknownOpcode(u8 cmd_byte, void *buffer, bool preprocess) } } -template -static u32 Decode(u8* end, bool in_display_list) +void OpcodeDecoder_Init() +{ +} + + +void OpcodeDecoder_Shutdown() +{ +} + +template +u8* OpcodeDecoder_Run(DataReader src, u32* cycles, bool in_display_list) { - u8 *opcodeStart = *bufp; - if (*bufp == end) - return 0; - - u8 cmd_byte = DataRead(bufp); - u32 cycles; - int refarray; - switch (cmd_byte) + u32 totalCycles = 0; + u8* opcodeStart; + while (true) { - case GX_NOP: - cycles = 6; // Hm, this means that we scan over nop streams pretty slowly... - break; + src.WritePointer(&opcodeStart); - case GX_LOAD_CP_REG: //0x08 - { - if (end - *bufp < 1 + 4) - return 0; - cycles = 12; - u8 sub_cmd = DataRead(bufp); - u32 value = DataRead(bufp); - LoadCPReg(sub_cmd, value, is_preprocess); - if (!is_preprocess) - INCSTAT(stats.thisFrame.numCPLoads); - } - break; + if (!src.size()) + goto end; - case GX_LOAD_XF_REG: + u8 cmd_byte = src.Read(); + int refarray; + switch (cmd_byte) { - if (end - *bufp < 4) - return 0; - u32 Cmd2 = DataRead(bufp); - int transfer_size = ((Cmd2 >> 16) & 15) + 1; - if ((size_t) (end - *bufp) < transfer_size * sizeof(u32)) - return 0; - cycles = 18 + 6 * transfer_size; - if (!is_preprocess) - { - u32 xf_address = Cmd2 & 0xFFFF; - LoadXFReg(transfer_size, xf_address); + case GX_NOP: + totalCycles += 6; // Hm, this means that we scan over nop streams pretty slowly... + break; - INCSTAT(stats.thisFrame.numXFLoads); - } - else + case GX_LOAD_CP_REG: //0x08 { - *bufp += transfer_size * sizeof(u32); + if (src.size() < 1 + 4) + goto end; + totalCycles += 12; + u8 sub_cmd = src.Read(); + u32 value = src.Read(); + LoadCPReg(sub_cmd, value, is_preprocess); + if (!is_preprocess) + INCSTAT(stats.thisFrame.numCPLoads); } - } - break; - - case GX_LOAD_INDX_A: //used for position matrices - refarray = 0xC; - goto load_indx; - case GX_LOAD_INDX_B: //used for normal matrices - refarray = 0xD; - goto load_indx; - case GX_LOAD_INDX_C: //used for postmatrices - refarray = 0xE; - goto load_indx; - case GX_LOAD_INDX_D: //used for lights - refarray = 0xF; - goto load_indx; - load_indx: - if (end - *bufp < 4) - return 0; - cycles = 6; - if (is_preprocess) - PreprocessIndexedXF(DataRead(bufp), refarray); - else - LoadIndexedXF(DataRead(bufp), refarray); - break; - - case GX_CMD_CALL_DL: - { - if (end - *bufp < 8) - return 0; - u32 address = DataRead(bufp); - u32 count = DataRead(bufp); + break; - if (in_display_list) + case GX_LOAD_XF_REG: { - cycles = 6; - WARN_LOG(VIDEO,"recursive display list detected"); + if (src.size() < 4) + goto end; + u32 Cmd2 = src.Read(); + int transfer_size = ((Cmd2 >> 16) & 15) + 1; + if (src.size() < transfer_size * sizeof(u32)) + goto end; + totalCycles += 18 + 6 * transfer_size; + if (!is_preprocess) + { + u32 xf_address = Cmd2 & 0xFFFF; + LoadXFReg(transfer_size, xf_address, src); + + INCSTAT(stats.thisFrame.numXFLoads); + } + src.Skip(transfer_size); } + break; + + case GX_LOAD_INDX_A: //used for position matrices + refarray = 0xC; + goto load_indx; + case GX_LOAD_INDX_B: //used for normal matrices + refarray = 0xD; + goto load_indx; + case GX_LOAD_INDX_C: //used for postmatrices + refarray = 0xE; + goto load_indx; + case GX_LOAD_INDX_D: //used for lights + refarray = 0xF; + goto load_indx; + load_indx: + if (src.size() < 4) + goto end; + totalCycles += 6; + if (is_preprocess) + PreprocessIndexedXF(src.Read(), refarray); else + LoadIndexedXF(src.Read(), refarray); + break; + + case GX_CMD_CALL_DL: { - if (is_preprocess) - InterpretDisplayListPreprocess(address, count); + if (src.size() < 8) + goto end; + u32 address = src.Read(); + u32 count = src.Read(); + + if (in_display_list) + { + totalCycles += 6; + WARN_LOG(VIDEO,"recursive display list detected"); + } else - cycles = 6 + InterpretDisplayList(address, count); + { + if (is_preprocess) + InterpretDisplayListPreprocess(address, count); + else + totalCycles += 6 + InterpretDisplayList(address, count); + } } - } - break; + break; - case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that - cycles = 6; - DEBUG_LOG(VIDEO, "GX 0x44: %08x", cmd_byte); - break; + case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that + totalCycles += 6; + DEBUG_LOG(VIDEO, "GX 0x44: %08x", cmd_byte); + break; - case GX_CMD_INVL_VC: // Invalidate Vertex Cache - cycles = 6; - DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)"); - break; + case GX_CMD_INVL_VC: // Invalidate Vertex Cache + totalCycles += 6; + DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)"); + break; - case GX_LOAD_BP_REG: //0x61 - // 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 - *bufp < 4) - return 0; - cycles = 12; - u32 bp_cmd = DataRead(bufp); - if (is_preprocess) + case GX_LOAD_BP_REG: //0x61 + // In skipped_frame case: We have to let BP writes through because they set + // tokens and stuff. TODO: Call a much simplified LoadBPReg instead. { - LoadBPRegPreprocess(bp_cmd); - } - else - { - LoadBPReg(bp_cmd); - INCSTAT(stats.thisFrame.numBPLoads); + if (src.size() < 4) + goto end; + totalCycles += 12; + u32 bp_cmd = src.Read(); + if (is_preprocess) + { + LoadBPRegPreprocess(bp_cmd); + } + else + { + LoadBPReg(bp_cmd); + INCSTAT(stats.thisFrame.numBPLoads); + } } - } - break; - - // draw primitives - default: - if ((cmd_byte & 0xC0) == 0x80) - { - cycles = 1600; - // load vertices - if (end - *bufp < 2) - return 0; - u16 num_vertices = DataRead(bufp); + break; - if (is_preprocess) + // draw primitives + default: + if ((cmd_byte & 0xC0) == 0x80) { - size_t size = num_vertices * VertexLoaderManager::GetVertexSize(cmd_byte & GX_VAT_MASK, is_preprocess); - if ((size_t) (end - *bufp) < size) - return 0; - *bufp += size; + // load vertices + if (src.size() < 2) + goto end; + u16 num_vertices = src.Read(); + + if (is_preprocess) + { + size_t size = num_vertices * VertexLoaderManager::GetVertexSize(cmd_byte & GX_VAT_MASK, is_preprocess); + if (src.size() < size) + goto end; + src.Skip(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, + src, + g_bSkipCurrentFrame)) + goto end; + } + totalCycles += 1600; } 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; + UnknownOpcode(cmd_byte, opcodeStart, is_preprocess); + totalCycles += 1; } + break; } - else - { - UnknownOpcode(cmd_byte, opcodeStart, is_preprocess); - cycles = 1; - } - break; - } - - // Display lists get added directly into the FIFO stream - if (!is_preprocess && g_bRecordFifoData && cmd_byte != GX_CMD_CALL_DL) - FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, u32(*bufp - opcodeStart)); - - // 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() -{ - g_video_buffer_read_ptr = GetVideoBufferStartPtr(); -} - -void OpcodeDecoder_Shutdown() -{ -} - -u8* OpcodeDecoder_Run(u8* start, u8* end, u32* cycles, bool in_display_list) -{ - g_video_buffer_read_ptr = start; - u32 totalCycles = 0; - while (true) - { - u8* old = g_video_buffer_read_ptr; - u32 cycles_op = Decode(end, in_display_list); - if (cycles_op == 0) + // Display lists get added directly into the FIFO stream + if (!is_preprocess && g_bRecordFifoData && cmd_byte != GX_CMD_CALL_DL) { - g_video_buffer_read_ptr = old; - break; + u8* opcodeEnd; + src.WritePointer(&opcodeEnd); + FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, u32(opcodeEnd - opcodeStart)); } - totalCycles += cycles_op; } + +end: if (cycles) { *cycles = totalCycles; } - return g_video_buffer_read_ptr; + return opcodeStart; } -u8* OpcodeDecoder_Preprocess(u8* start, u8 *end, bool in_display_list) -{ - s_video_buffer_pp_read_ptr = start; - while (true) - { - u8* old = s_video_buffer_pp_read_ptr; - u32 cycles = Decode(end, in_display_list); - if (cycles == 0) - { - s_video_buffer_pp_read_ptr = old; - break; - } - } - return s_video_buffer_pp_read_ptr; -} +template u8* OpcodeDecoder_Run(DataReader src, u32* cycles, bool in_display_list); +template u8* OpcodeDecoder_Run(DataReader src, u32* cycles, bool in_display_list); -- cgit v1.2.3 From 3fc7e55cc4623c1c49efb4c317ab0202499bb5fd Mon Sep 17 00:00:00 2001 From: degasus Date: Tue, 9 Dec 2014 08:35:04 +0100 Subject: VideoCommon: clean up VertexLoader --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 12a9d5b350..34b821605f 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -275,13 +275,17 @@ u8* OpcodeDecoder_Run(DataReader src, u32* cycles, bool in_display_list) } else { - if (!VertexLoaderManager::RunVertices( + int bytes = VertexLoaderManager::RunVertices( cmd_byte & GX_VAT_MASK, // Vertex loader index (0 - 7) (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, num_vertices, src, - g_bSkipCurrentFrame)) + g_bSkipCurrentFrame); + + if (bytes < 0) goto end; + else + src.Skip(bytes); } totalCycles += 1600; } -- cgit v1.2.3 From 2cedc0034def0d8e8b23fafceca9a0f87bdd2e63 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Tue, 6 Jan 2015 17:49:27 +0100 Subject: DataReader: turn WritePointer into GetPointer --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 34b821605f..0c1083b9c2 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -137,7 +137,7 @@ u8* OpcodeDecoder_Run(DataReader src, u32* cycles, bool in_display_list) u8* opcodeStart; while (true) { - src.WritePointer(&opcodeStart); + opcodeStart = src.GetPointer(); if (!src.size()) goto end; @@ -301,7 +301,7 @@ u8* OpcodeDecoder_Run(DataReader src, u32* cycles, bool in_display_list) if (!is_preprocess && g_bRecordFifoData && cmd_byte != GX_CMD_CALL_DL) { u8* opcodeEnd; - src.WritePointer(&opcodeEnd); + opcodeEnd = src.GetPointer(); FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, u32(opcodeEnd - opcodeStart)); } } -- cgit v1.2.3 From 20628b6e5d69acd8ec6f4286bcc65cee58fd5776 Mon Sep 17 00:00:00 2001 From: degasus Date: Tue, 27 Jan 2015 23:37:17 +0100 Subject: OpcodeDecoder: Calculate decoding time for vertices --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 0c1083b9c2..e347b93a76 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -287,7 +287,9 @@ u8* OpcodeDecoder_Run(DataReader src, u32* cycles, bool in_display_list) else src.Skip(bytes); } - totalCycles += 1600; + + // 4 GPU ticks per vertex, 3 CPU ticks per GPU tick + totalCycles += num_vertices * 4 * 3 + 6; } else { -- cgit v1.2.3 From 1aac65f9880787ef8a68131429f4f71cacbee838 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Sat, 31 Jan 2015 09:23:50 +0100 Subject: VertexLoaderManager: assimilate GetVertexSize() --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 32 ++++++++++-------------------- 1 file changed, 11 insertions(+), 21 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index e347b93a76..4a23ac717b 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -265,28 +265,18 @@ u8* OpcodeDecoder_Run(DataReader src, u32* cycles, bool in_display_list) if (src.size() < 2) goto end; u16 num_vertices = src.Read(); + int bytes = VertexLoaderManager::RunVertices( + cmd_byte & GX_VAT_MASK, // Vertex loader index (0 - 7) + (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, + num_vertices, + src, + g_bSkipCurrentFrame, + is_preprocess); + + if (bytes < 0) + goto end; - if (is_preprocess) - { - size_t size = num_vertices * VertexLoaderManager::GetVertexSize(cmd_byte & GX_VAT_MASK, is_preprocess); - if (src.size() < size) - goto end; - src.Skip(size); - } - else - { - int bytes = VertexLoaderManager::RunVertices( - cmd_byte & GX_VAT_MASK, // Vertex loader index (0 - 7) - (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, - num_vertices, - src, - g_bSkipCurrentFrame); - - if (bytes < 0) - goto end; - else - src.Skip(bytes); - } + src.Skip(bytes); // 4 GPU ticks per vertex, 3 CPU ticks per GPU tick totalCycles += num_vertices * 4 * 3 + 6; -- cgit v1.2.3 From 93b16a4a2d5f3e6d467d1315c461aff12852b26c Mon Sep 17 00:00:00 2001 From: Stevoisiak Date: Sun, 15 Feb 2015 14:43:31 -0500 Subject: Formatting/Whitespace Cleanup Various fixes to formatting and whitespace --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 4a23ac717b..b7bcb8c8e3 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -39,7 +39,7 @@ static u32 InterpretDisplayList(u32 address, u32 size) u8* startAddress; if (g_use_deterministic_gpu_thread) - startAddress = (u8*) PopFifoAuxBuffer(size); + startAddress = (u8*)PopFifoAuxBuffer(size); else startAddress = Memory::GetPointer(address); -- cgit v1.2.3 From cdff138c671c260527108e6771427c05f265f6a7 Mon Sep 17 00:00:00 2001 From: skidau Date: Fri, 13 Mar 2015 23:25:15 +1100 Subject: Show no more than one FIFO error per session. --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index b7bcb8c8e3..20a8f2eac9 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -33,6 +33,7 @@ bool g_bRecordFifoData = false; +bool g_bFifoErrorSeen = false; static u32 InterpretDisplayList(u32 address, u32 size) { @@ -77,12 +78,13 @@ static void UnknownOpcode(u8 cmd_byte, void *buffer, bool preprocess) { // TODO(Omega): Maybe dump FIFO to file on this error PanicAlert( - "GFX FIFO: Unknown Opcode (0x%x @ %p, preprocessing=%s).\n" + "GFX FIFO: Unknown Opcode (0x%02x @ %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" "* This really is an unknown opcode (unlikely)\n" "* Some other sort of bug\n\n" + "Further errors will be sent to the Video Backend log and\n" "Dolphin will now likely crash or hang. Enjoy." , cmd_byte, buffer, @@ -123,6 +125,7 @@ static void UnknownOpcode(u8 cmd_byte, void *buffer, bool preprocess) void OpcodeDecoder_Init() { + g_bFifoErrorSeen = false; } @@ -150,7 +153,12 @@ u8* OpcodeDecoder_Run(DataReader src, u32* cycles, bool in_display_list) totalCycles += 6; // Hm, this means that we scan over nop streams pretty slowly... break; - case GX_LOAD_CP_REG: //0x08 + case GX_UNKNOWN_RESET: + totalCycles += 6; // Datel software uses this command + DEBUG_LOG(VIDEO, "GX Reset?: %08x", cmd_byte); + break; + + case GX_LOAD_CP_REG: { if (src.size() < 1 + 4) goto end; @@ -237,7 +245,7 @@ u8* OpcodeDecoder_Run(DataReader src, u32* cycles, bool in_display_list) DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)"); break; - case GX_LOAD_BP_REG: //0x61 + case GX_LOAD_BP_REG: // In skipped_frame case: We have to let BP writes through because they set // tokens and stuff. TODO: Call a much simplified LoadBPReg instead. { @@ -283,7 +291,10 @@ u8* OpcodeDecoder_Run(DataReader src, u32* cycles, bool in_display_list) } else { - UnknownOpcode(cmd_byte, opcodeStart, is_preprocess); + if (!g_bFifoErrorSeen) + UnknownOpcode(cmd_byte, opcodeStart, is_preprocess); + ERROR_LOG(VIDEO, "FIFO: Unknown Opcode(0x%02x @ %p, preprocessing = %s)", cmd_byte, opcodeStart, is_preprocess ? "yes" : "no"); + g_bFifoErrorSeen = true; totalCycles += 1; } break; -- cgit v1.2.3 From f82afd1b2f4f13aecec6c7a36542121167cda357 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Mon, 16 Mar 2015 10:56:16 +0100 Subject: Fix warnings --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 20a8f2eac9..4b258e7127 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -33,7 +33,7 @@ bool g_bRecordFifoData = false; -bool g_bFifoErrorSeen = false; +static bool s_bFifoErrorSeen = false; static u32 InterpretDisplayList(u32 address, u32 size) { @@ -125,7 +125,7 @@ static void UnknownOpcode(u8 cmd_byte, void *buffer, bool preprocess) void OpcodeDecoder_Init() { - g_bFifoErrorSeen = false; + s_bFifoErrorSeen = false; } @@ -291,10 +291,10 @@ u8* OpcodeDecoder_Run(DataReader src, u32* cycles, bool in_display_list) } else { - if (!g_bFifoErrorSeen) + if (!s_bFifoErrorSeen) UnknownOpcode(cmd_byte, opcodeStart, is_preprocess); ERROR_LOG(VIDEO, "FIFO: Unknown Opcode(0x%02x @ %p, preprocessing = %s)", cmd_byte, opcodeStart, is_preprocess ? "yes" : "no"); - g_bFifoErrorSeen = true; + s_bFifoErrorSeen = true; totalCycles += 1; } break; -- cgit v1.2.3 From cefcb0ace9d363b3679b4e93bcc9ec05f1e5f4f8 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Mon, 18 May 2015 01:08:10 +0200 Subject: Update license headers to GPLv2+ --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 4b258e7127..9a98c7106d 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -1,5 +1,5 @@ // Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 +// Licensed under GPLv2+ // Refer to the license.txt file included. //DL facts: -- cgit v1.2.3 From 30ebb2459eb97ba544547183854775df8460b475 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Sun, 24 May 2015 06:55:12 +0200 Subject: Set copyright year to when a file was created --- Source/Core/VideoCommon/OpcodeDecoding.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Source/Core/VideoCommon/OpcodeDecoding.cpp') diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 9a98c7106d..3f2bd68eb3 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -1,4 +1,4 @@ -// Copyright 2013 Dolphin Emulator Project +// Copyright 2008 Dolphin Emulator Project // Licensed under GPLv2+ // Refer to the license.txt file included. -- cgit v1.2.3