From cd94e414cde964bf25ec67267f64fcd3d01283bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 28 Sep 2026 11:21:22 -0600 Subject: [PATCH] Savestate: Reset what older states lack instead of keeping pre-load values Missing sections (videocodec, audiocodec, aac, mp3) and old-version branches (impose, io, umd, gps, mic, display, font) left the session before the load in place. Co-Authored-By: Claude Opus 5.5 (1M context) --- Core/HLE/sceAac.cpp | 6 +++++- Core/HLE/sceAudiocodec.cpp | 8 +++++++- Core/HLE/sceDisplay.cpp | 4 ++++ Core/HLE/sceFont.cpp | 3 +++ Core/HLE/sceImpose.cpp | 3 +++ Core/HLE/sceIo.cpp | 3 +++ Core/HLE/sceMp3.cpp | 7 ++++++- Core/HLE/sceUmd.cpp | 2 ++ Core/HLE/sceUsbGps.cpp | 16 ++++++++++++---- Core/HLE/sceUsbMic.cpp | 12 ++++++++++++ Core/HLE/sceVideocodec.cpp | 8 ++++++++ 11 files changed, 65 insertions(+), 7 deletions(-) diff --git a/Core/HLE/sceAac.cpp b/Core/HLE/sceAac.cpp index 73567d0853..f70b29d969 100644 --- a/Core/HLE/sceAac.cpp +++ b/Core/HLE/sceAac.cpp @@ -43,8 +43,12 @@ void __AACShutdown() { void __AACDoState(PointerWrap &p) { auto s = p.Section("sceAAC", 0, 1); - if (!s) + if (!s) { + if (p.mode == PointerWrap::MODE_READ) { + __AACShutdown(); + } return; + } Do(p, g_aacMap); } diff --git a/Core/HLE/sceAudiocodec.cpp b/Core/HLE/sceAudiocodec.cpp index d738cd36bf..93de522240 100644 --- a/Core/HLE/sceAudiocodec.cpp +++ b/Core/HLE/sceAudiocodec.cpp @@ -658,9 +658,15 @@ void Register_sceAudiocodec() { void __sceAudiocodecDoState(PointerWrap &p){ auto s = p.Section("AudioList", 0, 2); if (!s) { - oldStateLoaded = true; + if (p.mode == PointerWrap::MODE_READ) { + clearDecoders(); + oldStateLoaded = true; + } return; } + if (p.mode == PointerWrap::MODE_READ) { + oldStateLoaded = false; + } int count = (int)g_audioDecoderContexts.size(); Do(p, count); diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 6b5da48bd4..4f81dd093d 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -299,6 +299,10 @@ void __DisplayDoState(PointerWrap &p) { Do(p, lastFlipCycles); Do(p, nextFlipCycles); } + if (p.mode == p.MODE_READ) { + // Not saved. Start counting again rather than carry over the session before the load. + lastFlipsTooFrequent = 0; + } gpu->DoState(p); diff --git a/Core/HLE/sceFont.cpp b/Core/HLE/sceFont.cpp index 32b72b1756..0f3b0354e3 100644 --- a/Core/HLE/sceFont.cpp +++ b/Core/HLE/sceFont.cpp @@ -1107,6 +1107,9 @@ void __FontDoState(PointerWrap &p) { Do(p, actionPostAllocCallback); __KernelRestoreActionType(actionPostAllocCallback, PostAllocCallback::Create); + if (s >= 2) { + useAllocCallbacks = true; + } Do(p, actionPostOpenCallback); __KernelRestoreActionType(actionPostOpenCallback, PostOpenCallback::Create); if (s >= 2) { diff --git a/Core/HLE/sceImpose.cpp b/Core/HLE/sceImpose.cpp index c8b506aea1..0a62a25523 100644 --- a/Core/HLE/sceImpose.cpp +++ b/Core/HLE/sceImpose.cpp @@ -70,6 +70,9 @@ void __ImposeDoState(PointerWrap &p) { if (s >= 2) { Do(p, imposeChanges); Do(p, imposeAvls); + } else if (p.mode == p.MODE_READ) { + imposeChanges = 0; + imposeAvls = 0; } } diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 2bbc70d3fd..f9058bfcae 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -726,6 +726,9 @@ void __IoDoState(PointerWrap &p) { if (s >= 3) { Do(p, lastMemStickState); Do(p, lastMemStickFatState); + } else if (p.mode == p.MODE_READ) { + lastMemStickState = MemoryStick_State(); + lastMemStickFatState = MemoryStick_FatState(); } for (int i = 0; i < PSP_COUNT_FDS; ++i) { diff --git a/Core/HLE/sceMp3.cpp b/Core/HLE/sceMp3.cpp index 9e05bdcede..225b3937d8 100644 --- a/Core/HLE/sceMp3.cpp +++ b/Core/HLE/sceMp3.cpp @@ -158,8 +158,13 @@ void __Mp3Shutdown() { void __Mp3DoState(PointerWrap &p) { auto s = p.Section("sceMp3", 0, 3); - if (!s) + if (!s) { + if (p.mode == PointerWrap::MODE_READ) { + __Mp3Shutdown(); + resourceInited = false; + } return; + } if (s >= 2) { Do(p, g_mp3Map); diff --git a/Core/HLE/sceUmd.cpp b/Core/HLE/sceUmd.cpp index 439de53786..40b67d3852 100644 --- a/Core/HLE/sceUmd.cpp +++ b/Core/HLE/sceUmd.cpp @@ -109,6 +109,8 @@ void __UmdDoState(PointerWrap &p) if (g_UMDReplacePermit && p.mode == p.MODE_READ) { System_Notify(SystemNotification::UI); } + } else if (p.mode == p.MODE_READ) { + g_UMDReplacePermit = false; } if (s > 2) { Do(p, umdInsertChangeEvent); diff --git a/Core/HLE/sceUsbGps.cpp b/Core/HLE/sceUsbGps.cpp index 5291ce8cdd..f97d430e16 100644 --- a/Core/HLE/sceUsbGps.cpp +++ b/Core/HLE/sceUsbGps.cpp @@ -45,11 +45,19 @@ void __UsbGpsInit() { } void __UsbGpsDoState(PointerWrap &p) { - auto s = p.Section("sceUsbGps", 0, 1); - if (!s) - return; - const bool wasOn = gpsStatus == GPS_STATE_ON; + auto s = p.Section("sceUsbGps", 0, 1); + if (!s) { + // Older states didn't save it, so leave it off. + if (p.mode == p.MODE_READ) { + if (wasOn) { + System_GPSCommand("close"); + } + gpsStatus = GPS_STATE_OFF; + } + return; + } + Do(p, gpsStatus); if (p.mode == p.MODE_READ) { if (gpsStatus == GPS_STATE_ON) { diff --git a/Core/HLE/sceUsbMic.cpp b/Core/HLE/sceUsbMic.cpp index da58ec9185..33c838aee9 100644 --- a/Core/HLE/sceUsbMic.cpp +++ b/Core/HLE/sceUsbMic.cpp @@ -126,6 +126,14 @@ void __UsbMicDoState(PointerWrap &p) { eventMicBlockingResume = -1; CoreTiming::RestoreRegisterEvent(eventMicBlockingResume, "MicBlockingResume", &__MicBlockingResume); waitingThreads.clear(); + // Nor was the mic, so leave it off. + if (Microphone::isMicStarted()) { + Microphone::stopMic(); + } + numNeedSamples = 0; + curTargetAddr = 0; + readMicDataLength = 0; + micState = 0; } return; } @@ -146,6 +154,10 @@ void __UsbMicDoState(PointerWrap &p) { if (s > 2) { Do(p, curTargetAddr); Do(p, readMicDataLength); + } else if (p.mode == p.MODE_READ) { + // The host mic thread writes to curTargetAddr, so don't leave the one from before the load. + curTargetAddr = 0; + readMicDataLength = 0; } if (!audioBuf && numNeedSamples > 0) { audioBuf = new QueueBuf(numNeedSamples << 1); diff --git a/Core/HLE/sceVideocodec.cpp b/Core/HLE/sceVideocodec.cpp index 329e01c5bc..a808925f26 100644 --- a/Core/HLE/sceVideocodec.cpp +++ b/Core/HLE/sceVideocodec.cpp @@ -194,6 +194,14 @@ void __VideocodecDoState(PointerWrap &p) { auto s = p.Section("sceVideocodec", 0, 1); if (!s) { + if (p.mode == p.MODE_READ) { + // A state from before this module. Don't keep the contexts and ME memory of the session + // before the load. + ClearContexts(false); + g_meRam.clear(); + g_meRam.shrink_to_fit(); + g_meAlloc.Shutdown(); + } return; }