From 40a70b004cfb6607ac34d90935720ebb369fdfd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 25 Sep 2026 18:36:49 -0600 Subject: [PATCH] Savestate: Reset video frame tracking and ME busy time on load Neither is serialized, and both went stale on load. The ME busy time was measured against the pre-load clock, so loading an earlier state made the next SAS/codec job wait until the old time came around, freezing the game. Co-Authored-By: Claude Opus 5.5 (1M context) --- Core/HLE/sceVideocodec.cpp | 5 +++++ GPU/GPUCommon.cpp | 3 +++ 2 files changed, 8 insertions(+) diff --git a/Core/HLE/sceVideocodec.cpp b/Core/HLE/sceVideocodec.cpp index f0d6618bfe..329e01c5bc 100644 --- a/Core/HLE/sceVideocodec.cpp +++ b/Core/HLE/sceVideocodec.cpp @@ -187,6 +187,11 @@ void __VideocodecShutdown() { } void __VideocodecDoState(PointerWrap &p) { + if (p.mode == p.MODE_READ) { + // Not serialized, and the clock it was measured against just moved (maybe backwards). + g_meBusyUntilUs = 0; + } + auto s = p.Section("sceVideocodec", 0, 1); if (!s) { return; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 2c52aad300..0bd1aadab7 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -112,6 +112,7 @@ void GPUCommon::Reinitialize() { drawCompleteTicks = 0; busyTicks = 0; interruptsEnabled_ = true; + videos_.clear(); if (textureCache_) textureCache_->Clear(true); @@ -1722,6 +1723,8 @@ void GPUCommon::DoState(PointerWrap &p) { p.SetError(p.ERROR_FAILURE); return; } + // Video frames aren't saved, and the ones before the load are no longer in memory. + videos_.clear(); } // List 0 looks the same as no list here, but no list means an empty queue. if (currentID == 0 && (dlQueue.empty() || dlQueue.front() != 0)) {