From 937c100af8cdbaca72b4ac8c366fa1d7063a043a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 25 Sep 2026 20:27:29 -0600 Subject: [PATCH] Savestate: Defer operations while the GE debugger holds a list The list belongs to the sceGe call still in progress, whose end would have run on the loaded CPU state. Also stop the camera and GPS when a state has them off, don't restart capture when saving, and fix a double free of the pmp frame queue (it only holds the media engine's own frame). Co-Authored-By: Claude Opus 5.5 (1M context) --- Core/HLE/sceMpeg.cpp | 5 +---- Core/HLE/sceUsbCam.cpp | 11 ++++++++--- Core/HLE/sceUsbGps.cpp | 11 ++++++++--- Core/MIPS/ARM/ArmJit.cpp | 2 +- Core/SaveState.cpp | 5 +++++ 5 files changed, 23 insertions(+), 11 deletions(-) diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index 5871db61e9..1ba7b84b51 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -1049,10 +1049,7 @@ void __VideoPmpInit() { void __VideoPmpShutdown() { #ifdef USE_FFMPEG - // We need to empty pmp_queue to not leak memory. - for (auto it = pmp_queue.begin(); it != pmp_queue.end(); ++it){ - av_free(*it); - } + // The queued frames are the media engine's own m_pFrameRGB, which it frees. pmp_queue.clear(); pmp_ContextList.clear(); delete pmpframes; diff --git a/Core/HLE/sceUsbCam.cpp b/Core/HLE/sceUsbCam.cpp index 0530a337c8..1a6a6cec14 100644 --- a/Core/HLE/sceUsbCam.cpp +++ b/Core/HLE/sceUsbCam.cpp @@ -63,10 +63,15 @@ void __UsbCamDoState(PointerWrap &p) { return; } + const bool wasCapturing = config->mode == Camera::Mode::Video; Do(p, *config); - if (config->mode == Camera::Mode::Video) { // stillImage? TBD - Camera::stopCapture(); - Camera::startCapture(); + if (p.mode == p.MODE_READ) { + if (config->mode == Camera::Mode::Video) { // stillImage? TBD + Camera::stopCapture(); + Camera::startCapture(); + } else if (wasCapturing) { + Camera::stopCapture(); + } } } diff --git a/Core/HLE/sceUsbGps.cpp b/Core/HLE/sceUsbGps.cpp index e749185675..5291ce8cdd 100644 --- a/Core/HLE/sceUsbGps.cpp +++ b/Core/HLE/sceUsbGps.cpp @@ -49,10 +49,15 @@ void __UsbGpsDoState(PointerWrap &p) { if (!s) return; + const bool wasOn = gpsStatus == GPS_STATE_ON; Do(p, gpsStatus); - if (gpsStatus == GPS_STATE_ON) { - GPS::init(); - System_GPSCommand("open"); + if (p.mode == p.MODE_READ) { + if (gpsStatus == GPS_STATE_ON) { + GPS::init(); + System_GPSCommand("open"); + } else if (wasOn) { + System_GPSCommand("close"); + } } } diff --git a/Core/MIPS/ARM/ArmJit.cpp b/Core/MIPS/ARM/ArmJit.cpp index 64f228cfac..8af7087b28 100644 --- a/Core/MIPS/ARM/ArmJit.cpp +++ b/Core/MIPS/ARM/ArmJit.cpp @@ -131,10 +131,10 @@ void ArmJit::DoState(PointerWrap &p) if (!s) return; + Do(p, js.startDefaultPrefix); if (p.mode == PointerWrap::MODE_READ && !js.startDefaultPrefix) { WARN_LOG(Log::CPU, "Jit: An uneaten prefix was previously detected. Jitting in unknown-prefix mode."); } - Do(p, js.startDefaultPrefix); if (s >= 2) { Do(p, js.hasSetRounding); if (p.mode == PointerWrap::MODE_READ) { diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index e982694718..d21ec64833 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -852,6 +852,11 @@ int g_screenshotFailures; if (!needsProcess) return; + if (coreState == CORE_STEPPING_GE || coreState == CORE_RUNNING_GE) { + // A display list stopped in the GE debugger still belongs to the sceGe call that started + // it, which finishes when the list does. Wait for that. + return; + } needsProcess = false; if (!__KernelIsRunning()) {