VMManager: Defer reset when running

Stops us resetting during the event test, which can leave things in a
pretty messed up state.
This commit is contained in:
Stenzek 2023-01-25 22:02:19 +10:00 committed by refractionpcsx2
parent 6a40959f3a
commit 4c1d93a322
3 changed files with 23 additions and 1 deletions

View File

@ -429,6 +429,10 @@ void EmuThread::executeVM()
VMManager::Execute(); VMManager::Execute();
continue; continue;
case VMState::Resetting:
VMManager::Reset();
continue;
case VMState::Stopping: case VMState::Stopping:
destroyVM(); destroyVM();
m_event_loop->processEvents(QEventLoop::AllEvents); m_event_loop->processEvents(QEventLoop::AllEvents);

View File

@ -214,7 +214,7 @@ void VMManager::SetState(VMState state)
bool VMManager::HasValidVM() bool VMManager::HasValidVM()
{ {
const VMState state = s_state.load(std::memory_order_acquire); 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() std::string VMManager::GetDiscPath()
@ -1161,6 +1161,19 @@ void VMManager::Shutdown(bool save_resume_state)
void VMManager::Reset() 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 #ifdef ENABLE_ACHIEVEMENTS
if (!Achievements::OnReset()) if (!Achievements::OnReset())
return; return;
@ -1187,6 +1200,10 @@ void VMManager::Reset()
g_InputRecording.handleReset(); g_InputRecording.handleReset();
GetMTGS().PresentCurrentFrame(); 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) std::string VMManager::GetSaveStateFileName(const char* game_serial, u32 game_crc, s32 slot)

View File

@ -35,6 +35,7 @@ enum class VMState
Initializing, Initializing,
Running, Running,
Paused, Paused,
Resetting,
Stopping, Stopping,
}; };