diff --git a/pcsx2/VMManager.cpp b/pcsx2/VMManager.cpp index b12f705884..0e4992b254 100644 --- a/pcsx2/VMManager.cpp +++ b/pcsx2/VMManager.cpp @@ -108,6 +108,7 @@ static u32 s_active_game_fixes = 0; static std::vector s_widescreen_cheats_data; static bool s_widescreen_cheats_loaded = false; static s32 s_current_save_slot = 1; +static u32 s_frame_advance_count = 0; static u32 s_mxcsr_saved; VMState VMManager::GetState() @@ -932,6 +933,15 @@ void VMManager::SetLimiterMode(LimiterModeType type) GetMTGS().SetVSync(EmuConfig.GetEffectiveVsyncMode()); } +void VMManager::FrameAdvance(u32 num_frames /*= 1*/) +{ + if (!HasValidVM()) + return; + + s_frame_advance_count = num_frames; + SetState(VMState::Running); +} + bool VMManager::ChangeDisc(std::string path) { std::string old_path(CDVDsys_GetFile(CDVD_SourceType::Iso)); @@ -1027,6 +1037,18 @@ void VMManager::Internal::VSyncOnCPUThread() ApplyLoadedPatches(PPT_CONTINUOUSLY); ApplyLoadedPatches(PPT_COMBINED_0_1); + // Frame advance must be done *before* pumping messages, because otherwise + // we'll immediately reduce the counter we just set. + if (s_frame_advance_count > 0) + { + s_frame_advance_count--; + if (s_frame_advance_count == 0) + { + // auto pause at the end of frame advance + SetState(VMState::Paused); + } + } + Host::PumpMessagesOnCPUThread(); InputManager::PollSources(); } @@ -1309,6 +1331,10 @@ DEFINE_HOTKEY("ResetVM", "System", "Reset Virtual Machine", [](bool pressed) { if (!pressed && VMManager::HasValidVM()) VMManager::Reset(); }) +DEFINE_HOTKEY("FrameAdvance", "System", "Frame Advance", [](bool pressed) { + if (!pressed) + VMManager::FrameAdvance(1); +}) DEFINE_HOTKEY("PreviousSaveStateSlot", "Save States", "Select Previous Save Slot", [](bool pressed) { if (!pressed) diff --git a/pcsx2/VMManager.h b/pcsx2/VMManager.h index fce58d7a2e..bb753d7c04 100644 --- a/pcsx2/VMManager.h +++ b/pcsx2/VMManager.h @@ -123,6 +123,9 @@ namespace VMManager /// Updates the host vsync state, as well as timer frequencies. Call when the speed limiter is adjusted. void SetLimiterMode(LimiterModeType type); + /// Runs the virtual machine for the specified number of video frames, and then automatically pauses. + void FrameAdvance(u32 num_frames = 1); + /// Changes the disc in the virtual CD/DVD drive. Passing an empty will remove any current disc. /// Returns false if the new disc can't be opened. bool ChangeDisc(std::string path);