From aa47018197fe4403a62121b2da5f3f1da32f982d Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Tue, 24 May 2022 23:10:39 +1000 Subject: [PATCH] Qt: Apply patches on entry point compile Fixes WRC4's entrypoint patch not being used. --- pcsx2-qt/QtHost.cpp | 13 +------ pcsx2/VMManager.cpp | 68 +++++++++++++++++++++------------ pcsx2/VMManager.h | 1 + pcsx2/x86/ix86-32/iR5900-32.cpp | 14 ++++++- 4 files changed, 58 insertions(+), 38 deletions(-) diff --git a/pcsx2-qt/QtHost.cpp b/pcsx2-qt/QtHost.cpp index 5038507fc9..9b58b04fc7 100644 --- a/pcsx2-qt/QtHost.cpp +++ b/pcsx2-qt/QtHost.cpp @@ -67,6 +67,7 @@ static void SaveSettings(); ////////////////////////////////////////////////////////////////////////// // Local variable declarations ////////////////////////////////////////////////////////////////////////// +const IConsoleWriter* PatchesCon = &Console; static std::unique_ptr s_settings_save_timer; static std::unique_ptr s_base_settings_interface; static bool s_batch_mode = false; @@ -488,18 +489,6 @@ void Host::OnInputDeviceDisconnected(const std::string_view& identifier) // Interface Stuff ////////////////////////////////////////////////////////////////////////// -const IConsoleWriter* PatchesCon = &Console; - -void LoadAllPatchesAndStuff(const Pcsx2Config& cfg) -{ - // FIXME -} - -void PatchesVerboseReset() -{ - // FIXME -} - static void SignalHandler(int signal) { // First try the normal (graceful) shutdown/exit. diff --git a/pcsx2/VMManager.cpp b/pcsx2/VMManager.cpp index 57bcc600fe..dcf6ee58e3 100644 --- a/pcsx2/VMManager.cpp +++ b/pcsx2/VMManager.cpp @@ -83,7 +83,9 @@ namespace VMManager static bool AutoDetectSource(const std::string& filename); static bool ApplyBootParameters(const VMBootParameters& params, std::string* state_to_load); static bool CheckBIOSAvailability(); - static void UpdateRunningGame(bool force); + static void LoadPatches(const std::string& serial, u32 crc, + bool show_messages, bool show_messages_when_disabled); + static void UpdateRunningGame(bool force, bool game_starting); static std::string GetCurrentSaveStateFileName(s32 slot); static bool DoLoadState(const char* filename); @@ -113,6 +115,7 @@ static std::mutex s_save_state_threads_mutex; static std::mutex s_info_mutex; static std::string s_disc_path; static u32 s_game_crc; +static u32 s_patches_crc; static std::string s_game_serial; static std::string s_game_name; static std::string s_elf_override; @@ -386,15 +389,19 @@ bool VMManager::UpdateGameSettingsLayer() return true; } -static void LoadPatches(const std::string& crc_string, bool show_messages, bool show_messages_when_disabled) +void VMManager::LoadPatches(const std::string& serial, u32 crc, bool show_messages, bool show_messages_when_disabled) { + const std::string crc_string(fmt::format("{:08X}", crc)); + s_patches_crc = crc; + ForgetLoadedPatches(); + std::string message; int patch_count = 0; if (EmuConfig.EnablePatches) { - const GameDatabaseSchema::GameEntry* game = GameDatabase::findGame(s_game_serial); - const std::string* patches = game ? game->findPatch(s_game_crc) : nullptr; + const GameDatabaseSchema::GameEntry* game = GameDatabase::findGame(serial); + const std::string* patches = game ? game->findPatch(crc) : nullptr; if (patches && (patch_count = LoadPatchesFromString(*patches)) > 0) { PatchesCon->WriteLn(Color_Green, "(GameDB) Patches Loaded: %d", patch_count); @@ -416,7 +423,7 @@ static void LoadPatches(const std::string& crc_string, bool show_messages, bool // wide screen patches int ws_patch_count = 0; - if (EmuConfig.EnableWideScreenPatches && s_game_crc != 0) + if (EmuConfig.EnableWideScreenPatches && crc != 0) { if (ws_patch_count = LoadPatchesFromDir(crc_string, EmuFolders::CheatsWS, "Widescreen hacks", false)) { @@ -446,7 +453,7 @@ static void LoadPatches(const std::string& crc_string, bool show_messages, bool } // no-interlacing patches - if (EmuConfig.EnableNoInterlacingPatches && s_game_crc != 0) + if (EmuConfig.EnableNoInterlacingPatches && crc != 0) { if (s_active_no_interlacing_patches = LoadPatchesFromDir(crc_string, EmuFolders::CheatsNI, "No-interlacing patches", false)) { @@ -502,7 +509,7 @@ static void LoadPatches(const std::string& crc_string, bool show_messages, bool } } -void VMManager::UpdateRunningGame(bool force) +void VMManager::UpdateRunningGame(bool force, bool game_starting) { // The CRC can be known before the game actually starts (at the bios), so when // we have the CRC but we're still at the bios and the settings are changed @@ -545,22 +552,32 @@ void VMManager::UpdateRunningGame(bool force) } sioSetGameSerial(memcardFilters.empty() ? s_game_serial : memcardFilters); + + // If we don't reset the timer here, when using folder memcards the reindex will cause an eject, + // which a bunch of games don't like since they access the memory card on boot. + if (game_starting) + ClearMcdEjectTimeoutNow(); } UpdateGameSettingsLayer(); ApplySettings(); - ForgetLoadedPatches(); - LoadPatches(StringUtil::StdStringFromFormat("%08X", new_crc), true, false); + // check this here, for two cases: dynarec on, and when enable cheats is set per-game. + if (s_patches_crc != s_game_crc) + ReloadPatches(false); + GetMTGS().SendGameCRC(new_crc); Host::OnGameChanged(s_disc_path, s_game_serial, s_game_name, s_game_crc); + + MIPSAnalyst::ScanForFunctions(R5900SymbolMap, ElfTextRange.first, ElfTextRange.first + ElfTextRange.second, true); + R5900SymbolMap.UpdateActiveSymbols(); + R3000SymbolMap.UpdateActiveSymbols(); } void VMManager::ReloadPatches(bool verbose) { - ForgetLoadedPatches(); - LoadPatches(StringUtil::StdStringFromFormat("%08X", s_game_crc), verbose, verbose); + LoadPatches(s_game_serial, s_game_crc, verbose, verbose); } static LimiterModeType GetInitialLimiterMode() @@ -828,7 +845,7 @@ bool VMManager::Initialize(const VMBootParameters& boot_params) s_state.store(VMState::Paused); Host::OnVMStarted(); - UpdateRunningGame(true); + UpdateRunningGame(true, true); SetEmuThreadAffinities(true); @@ -871,6 +888,7 @@ void VMManager::Shutdown(bool save_resume_state) std::unique_lock lock(s_info_mutex); s_disc_path.clear(); s_game_crc = 0; + s_patches_crc = 0; s_game_serial.clear(); s_game_name.clear(); Host::OnGameChanged(s_disc_path, s_game_serial, s_game_name, 0); @@ -924,7 +942,7 @@ void VMManager::Reset() // gameid change, so apply settings if (game_was_started) - UpdateRunningGame(true); + UpdateRunningGame(true, true); } std::string VMManager::GetSaveStateFileName(const char* game_serial, u32 game_crc, s32 slot) @@ -989,7 +1007,7 @@ bool VMManager::DoLoadState(const char* filename) { Host::OnSaveStateLoading(filename); SaveState_UnzipFromDisk(filename); - UpdateRunningGame(false); + UpdateRunningGame(false, false); Host::OnSaveStateLoaded(filename, true); return true; } @@ -1232,21 +1250,21 @@ bool VMManager::Internal::IsExecutionInterrupted() return s_state.load() != VMState::Running || s_cpu_implementation_changed.load(); } +void VMManager::Internal::EntryPointCompilingOnCPUThread() +{ + // Classic chicken and egg problem here. We don't want to update the running game + // until the game entry point actually runs, because that can update settings, which + // can flush the JIT, etc. But we need to apply patches for games where the entry + // point is in the patch (e.g. WRC 4). So. Gross, but the only way to handle it really. + LoadPatches(SysGetDiscID(), ElfCRC, false, false); + ApplyLoadedPatches(PPT_ONCE_ON_LOAD); +} + void VMManager::Internal::GameStartingOnCPUThread() { - GetMTGS().SendGameCRC(ElfCRC); - - MIPSAnalyst::ScanForFunctions(R5900SymbolMap, ElfTextRange.first, ElfTextRange.first + ElfTextRange.second, true); - R5900SymbolMap.UpdateActiveSymbols(); - R3000SymbolMap.UpdateActiveSymbols(); - - UpdateRunningGame(false); + UpdateRunningGame(false, true); ApplyLoadedPatches(PPT_ONCE_ON_LOAD); ApplyLoadedPatches(PPT_COMBINED_0_1); - - // If we don't reset the timer here, when using folder memcards the reindex will cause an eject, - // which a bunch of games don't like since they access the memory card on boot. - ClearMcdEjectTimeoutNow(); } void VMManager::Internal::VSyncOnCPUThread() diff --git a/pcsx2/VMManager.h b/pcsx2/VMManager.h index 8e516be542..afd6da8349 100644 --- a/pcsx2/VMManager.h +++ b/pcsx2/VMManager.h @@ -164,6 +164,7 @@ namespace VMManager const std::string& GetElfOverride(); bool IsExecutionInterrupted(); + void EntryPointCompilingOnCPUThread(); void GameStartingOnCPUThread(); void VSyncOnCPUThread(); } diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index 7434894cc0..793099631e 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -56,7 +56,9 @@ static std::atomic eeRecNeedsReset(false); static bool eeCpuExecuting = false; static bool eeRecExitRequested = false; static bool g_resetEeScalingStats = false; +#ifndef PCSX2_CORE static int g_patchesNeedRedo = 0; +#endif #define PC_GETBLOCK(x) PC_GETBLOCK_(x, recLUT) @@ -665,7 +667,9 @@ static void recResetRaw() g_branch = 0; g_resetEeScalingStats = true; +#ifndef PCSX2_CORE g_patchesNeedRedo = 1; +#endif } static void recShutdown() @@ -1797,14 +1801,16 @@ bool skipMPEG_By_Pattern(u32 sPC) return 0; } +#ifndef PCSX2_CORE // defined at AppCoreThread.cpp but unclean and should not be public. We're the only // consumers of it, so it's declared only here. void LoadAllPatchesAndStuff(const Pcsx2Config&); -void doPlace0Patches() +static void doPlace0Patches() { LoadAllPatchesAndStuff(EmuConfig); ApplyLoadedPatches(PPT_ONCE_ON_LOAD); } +#endif static void recRecompile(const u32 startpc) { @@ -1878,6 +1884,7 @@ static void recRecompile(const u32 startpc) Console.WriteLn("recRecompile: Could not enable launch arguments for fast boot mode; unidentified BIOS version! Please report this to the PCSX2 developers."); } +#ifndef PCSX2_CORE // On fast/full boot this will have a crc of 0x0. But when the game/elf itself is // recompiled (below - ElfEntry && g_GameLoading), then the crc would be from the elf. // g_patchesNeedRedo is set on rec reset, and this is the only consumer. @@ -1885,6 +1892,7 @@ static void recRecompile(const u32 startpc) if (g_patchesNeedRedo) doPlace0Patches(); g_patchesNeedRedo = 0; +#endif } if (g_eeloadExec && HWADDR(startpc) == HWADDR(g_eeloadExec)) @@ -1896,9 +1904,13 @@ static void recRecompile(const u32 startpc) Console.WriteLn("Elf entry point @ 0x%08x about to get recompiled. Load patches first.", startpc); xFastCall((void*)eeGameStarting); +#ifndef PCSX2_CORE // Apply patch as soon as possible. Normally it is done in // eeGameStarting but first block is already compiled. doPlace0Patches(); +#else + VMManager::Internal::EntryPointCompilingOnCPUThread(); +#endif } g_branch = 0;