From 4c1d93a322ce2f1567de29a86ebab4d787dca35b Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 25 Jan 2023 22:02:19 +1000 Subject: [PATCH] VMManager: Defer reset when running Stops us resetting during the event test, which can leave things in a pretty messed up state. --- pcsx2-qt/QtHost.cpp | 4 ++++ pcsx2/VMManager.cpp | 19 ++++++++++++++++++- pcsx2/VMManager.h | 1 + 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/pcsx2-qt/QtHost.cpp b/pcsx2-qt/QtHost.cpp index abdbb94c44..d7169a5550 100644 --- a/pcsx2-qt/QtHost.cpp +++ b/pcsx2-qt/QtHost.cpp @@ -429,6 +429,10 @@ void EmuThread::executeVM() VMManager::Execute(); continue; + case VMState::Resetting: + VMManager::Reset(); + continue; + case VMState::Stopping: destroyVM(); m_event_loop->processEvents(QEventLoop::AllEvents); diff --git a/pcsx2/VMManager.cpp b/pcsx2/VMManager.cpp index 5f7e49b0a5..e587e521c9 100644 --- a/pcsx2/VMManager.cpp +++ b/pcsx2/VMManager.cpp @@ -214,7 +214,7 @@ void VMManager::SetState(VMState state) bool VMManager::HasValidVM() { const VMState state = s_state.load(std::memory_order_acquire); - return (state == VMState::Running || state == VMState::Paused); + return (state >= VMState::Running && state <= VMState::Resetting); } std::string VMManager::GetDiscPath() @@ -1161,6 +1161,19 @@ void VMManager::Shutdown(bool save_resume_state) void VMManager::Reset() { + pxAssert(HasValidVM()); + + // If we're running, we're probably going to be executing this at event test time, + // at vsync, which happens in the middle of event handling. Resetting everything + // immediately here is a bad idea (tm), in fact, it breaks some games (e.g. TC:NYC). + // So, instead, we tell the rec to exit execution, _then_ reset. Paused is fine here, + // since the rec won't be running, so it's safe to immediately reset there. + if (s_state.load(std::memory_order_acquire) == VMState::Running) + { + s_state.store(VMState::Resetting, std::memory_order_release); + return; + } + #ifdef ENABLE_ACHIEVEMENTS if (!Achievements::OnReset()) return; @@ -1187,6 +1200,10 @@ void VMManager::Reset() g_InputRecording.handleReset(); GetMTGS().PresentCurrentFrame(); } + + // If we were paused, state won't be resetting, so don't flip back to running. + if (s_state.load(std::memory_order_acquire) == VMState::Resetting) + s_state.store(VMState::Running, std::memory_order_release); } std::string VMManager::GetSaveStateFileName(const char* game_serial, u32 game_crc, s32 slot) diff --git a/pcsx2/VMManager.h b/pcsx2/VMManager.h index 0b9d927ce7..61cb920040 100644 --- a/pcsx2/VMManager.h +++ b/pcsx2/VMManager.h @@ -35,6 +35,7 @@ enum class VMState Initializing, Running, Paused, + Resetting, Stopping, };