From 7fe1292c62621e80c061c8f017efa2e07f1a064b Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Sun, 7 Mar 2021 15:42:10 -0800 Subject: [PATCH] Add game quirks for unknown BP/CP/XF commands --- Source/Core/Core/DolphinAnalytics.cpp | 34 +++++++++++-------- Source/Core/Core/DolphinAnalytics.h | 9 +++++ Source/Core/VideoCommon/BPStructs.cpp | 3 ++ .../Core/VideoCommon/VertexLoaderManager.cpp | 24 +++++++++++++ Source/Core/VideoCommon/XFStructs.cpp | 4 +++ 5 files changed, 60 insertions(+), 14 deletions(-) diff --git a/Source/Core/Core/DolphinAnalytics.cpp b/Source/Core/Core/DolphinAnalytics.cpp index 81dbc16643..8e699213f6 100644 --- a/Source/Core/Core/DolphinAnalytics.cpp +++ b/Source/Core/Core/DolphinAnalytics.cpp @@ -133,20 +133,26 @@ void DolphinAnalytics::ReportGameStart() } // Keep in sync with enum class GameQuirk definition. -constexpr std::array GAME_QUIRKS_NAMES{"icache-matters", - "directly-reads-wiimote-input", - "uses-DVDLowStopLaser", - "uses-DVDLowOffset", - "uses-DVDLowReadDiskBca", - "uses-DVDLowRequestDiscStatus", - "uses-DVDLowRequestRetryNumber", - "uses-DVDLowSerMeasControl", - "uses-different-partition-command", - "uses-di-interrupt-command", - "mismatched-gpu-texgens-between-xf-and-bp", - "mismatched-gpu-colors-between-xf-and-bp", - "uses-uncommon-wd-mode", - "uses-wd-unimplemented-ioctl"}; +constexpr std::array GAME_QUIRKS_NAMES{ + "icache-matters", + "directly-reads-wiimote-input", + "uses-DVDLowStopLaser", + "uses-DVDLowOffset", + "uses-DVDLowReadDiskBca", + "uses-DVDLowRequestDiscStatus", + "uses-DVDLowRequestRetryNumber", + "uses-DVDLowSerMeasControl", + "uses-different-partition-command", + "uses-di-interrupt-command", + "mismatched-gpu-texgens-between-xf-and-bp", + "mismatched-gpu-colors-between-xf-and-bp", + "uses-uncommon-wd-mode", + "uses-wd-unimplemented-ioctl", + "uses-unknown-bp-command", + "uses-unknown-cp-command", + "uses-unknown-xf-command", + "uses-maybe-invalid-cp-command", +}; static_assert(GAME_QUIRKS_NAMES.size() == static_cast(GameQuirk::COUNT), "Game quirks names and enum definition are out of sync."); diff --git a/Source/Core/Core/DolphinAnalytics.h b/Source/Core/Core/DolphinAnalytics.h index 6416257b93..b5abb57b8f 100644 --- a/Source/Core/Core/DolphinAnalytics.h +++ b/Source/Core/Core/DolphinAnalytics.h @@ -61,6 +61,15 @@ enum class GameQuirk USES_WD_UNIMPLEMENTED_IOCTL, + // Some games use invalid/unknown graphics commands (see e.g. bug 10931). + // These are different from unknown opcodes: it is known that a BP/CP/XF command is being used, + // but the command itself is not understood. + USES_UNKNOWN_BP_COMMAND, + USES_UNKNOWN_CP_COMMAND, + USES_UNKNOWN_XF_COMMAND, + // YAGCD and Dolphin's implementation disagree about what is valid in some cases + USES_MAYBE_INVALID_CP_COMMAND, + COUNT, }; diff --git a/Source/Core/VideoCommon/BPStructs.cpp b/Source/Core/VideoCommon/BPStructs.cpp index 2ad90a350a..699b92ce17 100644 --- a/Source/Core/VideoCommon/BPStructs.cpp +++ b/Source/Core/VideoCommon/BPStructs.cpp @@ -12,8 +12,10 @@ #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" + #include "Core/ConfigManager.h" #include "Core/CoreTiming.h" +#include "Core/DolphinAnalytics.h" #include "Core/FifoPlayer/FifoPlayer.h" #include "Core/FifoPlayer/FifoRecorder.h" #include "Core/HW/Memmap.h" @@ -704,6 +706,7 @@ static void BPWritten(const BPCmd& bp) break; } + DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_UNKNOWN_BP_COMMAND); WARN_LOG_FMT(VIDEO, "Unknown BP opcode: address = {:#010x} value = {:#010x}", bp.address, bp.newvalue); } diff --git a/Source/Core/VideoCommon/VertexLoaderManager.cpp b/Source/Core/VideoCommon/VertexLoaderManager.cpp index 8a2eba09b4..a5088cef3a 100644 --- a/Source/Core/VideoCommon/VertexLoaderManager.cpp +++ b/Source/Core/VideoCommon/VertexLoaderManager.cpp @@ -16,6 +16,8 @@ #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" + +#include "Core/DolphinAnalytics.h" #include "Core/HW/Memmap.h" #include "VideoCommon/BPMemory.h" @@ -322,22 +324,34 @@ void LoadCPReg(u32 sub_cmd, u32 value, bool is_preprocess) switch (sub_cmd & CP_COMMAND_MASK) { case MATINDEX_A: + if (sub_cmd != MATINDEX_A) + DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_MAYBE_INVALID_CP_COMMAND); + if (update_global_state) VertexShaderManager::SetTexMatrixChangedA(value); break; case MATINDEX_B: + if (sub_cmd != MATINDEX_B) + DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_MAYBE_INVALID_CP_COMMAND); + if (update_global_state) VertexShaderManager::SetTexMatrixChangedB(value); break; case VCD_LO: + if (sub_cmd != VCD_LO) // Stricter than YAGCD + DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_MAYBE_INVALID_CP_COMMAND); + state->vtx_desc.low.Hex = value; state->attr_dirty = BitSet32::AllTrue(CP_NUM_VAT_REG); state->bases_dirty = true; break; case VCD_HI: + if (sub_cmd != VCD_HI) // Stricter than YAGCD + DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_MAYBE_INVALID_CP_COMMAND); + state->vtx_desc.high.Hex = value; state->attr_dirty = BitSet32::AllTrue(CP_NUM_VAT_REG); state->bases_dirty = true; @@ -345,21 +359,30 @@ void LoadCPReg(u32 sub_cmd, u32 value, bool is_preprocess) case CP_VAT_REG_A: if ((sub_cmd - CP_VAT_REG_A) >= CP_NUM_VAT_REG) + { + DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_MAYBE_INVALID_CP_COMMAND); WARN_LOG_FMT(VIDEO, "CP_VAT_REG_A: Invalid VAT {}", sub_cmd - CP_VAT_REG_A); + } state->vtx_attr[sub_cmd & CP_VAT_MASK].g0.Hex = value; state->attr_dirty[sub_cmd & CP_VAT_MASK] = true; break; case CP_VAT_REG_B: if ((sub_cmd - CP_VAT_REG_B) >= CP_NUM_VAT_REG) + { + DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_MAYBE_INVALID_CP_COMMAND); WARN_LOG_FMT(VIDEO, "CP_VAT_REG_B: Invalid VAT {}", sub_cmd - CP_VAT_REG_B); + } state->vtx_attr[sub_cmd & CP_VAT_MASK].g1.Hex = value; state->attr_dirty[sub_cmd & CP_VAT_MASK] = true; break; case CP_VAT_REG_C: if ((sub_cmd - CP_VAT_REG_C) >= CP_NUM_VAT_REG) + { + DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_MAYBE_INVALID_CP_COMMAND); WARN_LOG_FMT(VIDEO, "CP_VAT_REG_C: Invalid VAT {}", sub_cmd - CP_VAT_REG_C); + } state->vtx_attr[sub_cmd & CP_VAT_MASK].g2.Hex = value; state->attr_dirty[sub_cmd & CP_VAT_MASK] = true; break; @@ -376,6 +399,7 @@ void LoadCPReg(u32 sub_cmd, u32 value, bool is_preprocess) break; default: + DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_UNKNOWN_CP_COMMAND); WARN_LOG_FMT(VIDEO, "Unknown CP register {:02x} set to {:08x}", sub_cmd, value); } } diff --git a/Source/Core/VideoCommon/XFStructs.cpp b/Source/Core/VideoCommon/XFStructs.cpp index 741680b826..5bdbc9dd4b 100644 --- a/Source/Core/VideoCommon/XFStructs.cpp +++ b/Source/Core/VideoCommon/XFStructs.cpp @@ -9,6 +9,7 @@ #include "Common/Logging/Log.h" #include "Common/Swap.h" +#include "Core/DolphinAnalytics.h" #include "Core/HW/Memmap.h" #include "VideoCommon/CPMemory.h" @@ -182,6 +183,7 @@ static void XFRegWritten(int transferSize, u32 baseAddress, DataReader src) case 0x104d: case 0x104e: case 0x104f: + DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_UNKNOWN_XF_COMMAND); DEBUG_LOG_FMT(VIDEO, "Possible Normal Mtx XF reg?: {:x}={:x}", address, newValue); break; @@ -192,6 +194,7 @@ static void XFRegWritten(int transferSize, u32 baseAddress, DataReader src) case 0x1017: default: + DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_UNKNOWN_XF_COMMAND); if (newValue != 0) // Ignore writes of zero. WARN_LOG_FMT(VIDEO, "Unknown XF Reg: {:x}={:x}", address, newValue); break; @@ -211,6 +214,7 @@ void LoadXFReg(u32 transferSize, u32 baseAddress, DataReader src) if (baseAddress + transferSize > XFMEM_REGISTERS_END) { WARN_LOG_FMT(VIDEO, "XF load exceeds address space: {:x} {} bytes", baseAddress, transferSize); + DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_UNKNOWN_XF_COMMAND); if (baseAddress >= XFMEM_REGISTERS_END) transferSize = 0;