diff --git a/pcsx2/Recording/InputRecording.cpp b/pcsx2/Recording/InputRecording.cpp index f84b5cb89d..4a55c86ae0 100644 --- a/pcsx2/Recording/InputRecording.cpp +++ b/pcsx2/Recording/InputRecording.cpp @@ -49,7 +49,7 @@ void SaveStateBase::InputRecordingFreeze() else if (g_InputRecording.IsActive()) { // Explicitly set the frame change tracking variable as to not - // detect loading a savestate as a frame being drawn + // detect saving or loading a savestate as a frame being drawn g_InputRecordingControls.SetFrameCountTracker(g_FrameCount); if (IsLoading()) @@ -77,11 +77,11 @@ void Pcsx2App::RecordingReset() } else if (g_InputRecording.IsActive()) { - // Explicitly set the frame change tracking variable as to not - // detect rebooting as a frame being drawn - g_InputRecordingControls.SetFrameCountTracker(g_FrameCount); g_InputRecording.SetFrameCounter(0); + g_InputRecordingControls.Lock(0, false); } + else + g_InputRecordingControls.Resume(); } InputRecording g_InputRecording; @@ -138,7 +138,7 @@ void InputRecording::ControllerInterrupt(u8 &data, u8 &port, u16 &bufCount, u8 b } } -u32 InputRecording::GetFrameCounter() +s32 InputRecording::GetFrameCounter() { return frameCounter; } @@ -218,13 +218,7 @@ void InputRecording::SetToReplayMode() } void InputRecording::SetFrameCounter(u32 newGFrameCount) -{ - // Forces inputRecording to wait for a confirmed pause before resetting - // frameCounter to the proper value. Ensures that any lingering emulation - // before the load doesn't increment the already reset value - const bool initiallyPaused = g_InputRecordingControls.IsRecordingPaused(); - if (!initiallyPaused) - g_InputRecordingControls.PauseImmediately(); +{ if (newGFrameCount > startingFrame + g_InputRecording.GetInputRecordingData().GetTotalFrames()) { recordingConLog(L"[REC]: Warning, you've loaded PCSX2 emulation to a point after the end of the original recording. This should be avoided.\n"); @@ -246,10 +240,12 @@ void InputRecording::SetFrameCounter(u32 newGFrameCount) SetToReplayMode(); } } + else if (newGFrameCount == 0 && state == InputRecordingMode::Recording) + { + SetToReplayMode(); + } frameCounter = static_cast(newGFrameCount - startingFrame); incrementUndo = true; - if (!initiallyPaused) - g_InputRecordingControls.Resume(); } } @@ -263,6 +259,7 @@ void InputRecording::SetStartingFrame(u32 newStartingFrame) } frameCounter = 0; initialLoad = false; + g_InputRecordingControls.Lock(startingFrame, inputRecordingData.FromSaveState()); } void InputRecording::Stop() diff --git a/pcsx2/Recording/InputRecording.h b/pcsx2/Recording/InputRecording.h index ae8d64ca67..d786bb6cea 100644 --- a/pcsx2/Recording/InputRecording.h +++ b/pcsx2/Recording/InputRecording.h @@ -27,7 +27,7 @@ public: void ControllerInterrupt(u8 &data, u8 &port, u16 &BufCount, u8 buf[]); // The running frame counter for the input recording - u32 GetFrameCounter(); + s32 GetFrameCounter(); InputRecordingFile &GetInputRecordingData(); diff --git a/pcsx2/Recording/InputRecordingControls.cpp b/pcsx2/Recording/InputRecordingControls.cpp index 4dec63e645..975a4c4b73 100644 --- a/pcsx2/Recording/InputRecordingControls.cpp +++ b/pcsx2/Recording/InputRecordingControls.cpp @@ -36,10 +36,28 @@ void InputRecordingControls::HandleFrameAdvanceAndPausing() // often this is twice per frame but this may vary as Counters.cpp mentions the // vsync timing can change. // + // When loading a recording file or rebooting with a recording active, lock will be enabled. + // Emulation will be forced into and remain in a paused state until the transition in progress + // has completed - signaled when g_framecount and frameCountTracker are equal. + if (frameLock) + { + if (!emulationCurrentlyPaused && CoreThread.IsOpen() && CoreThread.IsRunning()) + { + pauseEmulation = true; + emulationCurrentlyPaused = true; + CoreThread.PauseSelf(); + } + else if (g_FrameCount == frameCountTracker) + { + frameLock = false; + g_InputRecordingControls.Resume(); + } + return; + } // As a safeguard, use the global g_FrameCount to know when the frame counter has truly changed. - // + // // NOTE - Do not mutate g_FrameCount or use it's value to set the input recording's internal frame counter - if (frameCountTracker != g_FrameCount) + else if (frameCountTracker != g_FrameCount) { frameCountTracker = g_FrameCount; g_InputRecording.IncrementFrameCounter(); @@ -60,7 +78,7 @@ void InputRecordingControls::HandleFrameAdvanceAndPausing() switchToReplay = false; } - if (g_InputRecording.IsReplaying() && g_InputRecording.GetFrameCounter() >= g_InputRecording.GetInputRecordingData().GetTotalFrames()) + if (g_InputRecording.IsReplaying() && g_InputRecording.GetFrameCounter() >= (s32)g_InputRecording.GetInputRecordingData().GetTotalFrames()) { pauseEmulation = true; } @@ -92,7 +110,7 @@ void InputRecordingControls::ResumeCoreThreadIfStarted() void InputRecordingControls::FrameAdvance() { - if (g_InputRecording.IsReplaying() && g_InputRecording.GetFrameCounter() >= g_InputRecording.GetInputRecordingData().GetTotalFrames()) + if (g_InputRecording.IsReplaying() && g_InputRecording.GetFrameCounter() >= (s32)g_InputRecording.GetInputRecordingData().GetTotalFrames()) { g_InputRecording.SetToRecordMode(); return; @@ -120,7 +138,7 @@ void InputRecordingControls::PauseImmediately() return; } Pause(); - if (pauseEmulation && CoreThread.IsOpen() && CoreThread.IsRunning()) + if (CoreThread.IsOpen() && CoreThread.IsRunning()) { emulationCurrentlyPaused = true; CoreThread.PauseSelf(); @@ -129,7 +147,7 @@ void InputRecordingControls::PauseImmediately() void InputRecordingControls::Resume() { - if (g_InputRecording.IsReplaying() && g_InputRecording.GetFrameCounter() >= g_InputRecording.GetInputRecordingData().GetTotalFrames()) + if (g_InputRecording.IsReplaying() && g_InputRecording.GetFrameCounter() >= (s32)g_InputRecording.GetInputRecordingData().GetTotalFrames()) { g_InputRecording.SetToRecordMode(); return; @@ -145,7 +163,7 @@ void InputRecordingControls::SetFrameCountTracker(u32 newFrame) void InputRecordingControls::TogglePause() { - if (pauseEmulation && g_InputRecording.IsReplaying() && g_InputRecording.GetFrameCounter() >= g_InputRecording.GetInputRecordingData().GetTotalFrames()) + if (pauseEmulation && g_InputRecording.IsReplaying() && g_InputRecording.GetFrameCounter() >= (s32)g_InputRecording.GetInputRecordingData().GetTotalFrames()) { g_InputRecording.SetToRecordMode(); return; @@ -156,7 +174,7 @@ void InputRecordingControls::TogglePause() void InputRecordingControls::RecordModeToggle() { - if (IsRecordingPaused() || g_InputRecording.IsReplaying() || g_InputRecording.GetFrameCounter() < g_InputRecording.GetInputRecordingData().GetTotalFrames()) + if (IsRecordingPaused() || g_InputRecording.IsReplaying() || g_InputRecording.GetFrameCounter() < (s32)g_InputRecording.GetInputRecordingData().GetTotalFrames()) { if (g_InputRecording.IsReplaying()) { @@ -170,4 +188,15 @@ void InputRecordingControls::RecordModeToggle() else if (g_InputRecording.IsRecording()) switchToReplay = true; } + +void InputRecordingControls::Lock(u32 frame, bool savestate) +{ + frameLock = true; + frameCountTracker = frame; + if (!savestate) + { + //Ensures that g_frameCount can be used to resume emulation after a fast/full boot + g_FrameCount = frame + 1; + } +} #endif diff --git a/pcsx2/Recording/InputRecordingControls.h b/pcsx2/Recording/InputRecordingControls.h index ff9696df40..88b355ad7a 100644 --- a/pcsx2/Recording/InputRecordingControls.h +++ b/pcsx2/Recording/InputRecordingControls.h @@ -53,6 +53,10 @@ public: void TogglePause(); // Switches between recording and replaying the active input recording file void RecordModeToggle(); + // Enables the frame locking mechanism so that when recordings are loaded + // or when processing a reboot with a recording active that no frames are + // lost in prior emulation + void Lock(u32 frame, bool savestate); private: // Indicates if the input recording controls have explicitly paused emulation or not @@ -61,7 +65,7 @@ private: // and should be cleared once a single frame has passed bool frameAdvancing = false; // The input recording frame that frame advancing began on - u32 frameAdvanceMarker = 0; + s32 frameAdvanceMarker = 0; // Used to detect if the internal PCSX2 g_FrameCount has changed u32 frameCountTracker = -1; // Indicates if we intend to call CoreThread.PauseSelf() on the current or next available vsync @@ -70,6 +74,8 @@ private: bool resumeEmulation = false; // Indicates to switch to replay mode after the next vsync bool switchToReplay = false; + // Used to stop recording frames from incrementing during a reset + bool frameLock = false; }; extern InputRecordingControls g_InputRecordingControls; diff --git a/pcsx2/gui/MainMenuClicks.cpp b/pcsx2/gui/MainMenuClicks.cpp index 0f428561d0..7c5c42bb43 100644 --- a/pcsx2/gui/MainMenuClicks.cpp +++ b/pcsx2/gui/MainMenuClicks.cpp @@ -926,7 +926,6 @@ void MainEmuFrame::Menu_Recording_Play_Click(wxCommandEvent &event) m_menuRecording.FindChildItem(MenuId_Recording_New)->Enable(false); m_menuRecording.FindChildItem(MenuId_Recording_Stop)->Enable(true); } - g_InputRecordingControls.Resume(); } void MainEmuFrame::Menu_Recording_Stop_Click(wxCommandEvent &event)