From a26ef51a0cecde5dd1785358a9bd18a6745eb3e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 6 Oct 2026 13:16:55 -0600 Subject: [PATCH] GE dump playback: Restore old-layout contexts from old dumps Dumps recorded before savedContextVersion 1 hold PPSSPP's old context layout, with the matrices as raw floats, but GEState::Restore picks the layout from savedContextVersion, which only a savestate sets. Playback restored them as the new layout, so the matrices became garbage and the scene vanished (4140 drew only its HUD). Tell the layouts apart by the END the new one ends with, as the PSP replayer does. Other callers are unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) --- GPU/Debugger/Playback.cpp | 13 ++++++++++++- GPU/GPUState.cpp | 6 +++++- GPU/GPUState.h | 2 ++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/GPU/Debugger/Playback.cpp b/GPU/Debugger/Playback.cpp index 81b0d96cee..9c636d5063 100644 --- a/GPU/Debugger/Playback.cpp +++ b/GPU/Debugger/Playback.cpp @@ -610,7 +610,18 @@ void DumpExecute::SubmitListEnd() { } void DumpExecute::Init(u32 ptr, u32 sz) { - gstate.Restore((u32_le *)(pushbuf_.data() + ptr)); + // Dumps from before savedContextVersion 1 hold PPSSPP's old context layout, with the matrices as raw + // floats; the new one ends its commands with an END. Restoring an old one as new turned its matrices + // into garbage and the scene disappeared (4140). The PSP replayer tells them apart the same way. + const u32_le *context = (const u32_le *)(pushbuf_.data() + ptr); + bool oldLayout = true; + for (int i = 17; i < 512; ++i) { + if (context[i] == GE_CMD_END << 24) { + oldLayout = false; + break; + } + } + gstate.Restore(context, oldLayout); ExecuteOnMain(Operation{ OpType::ReapplyGfxState }); fbPtr_ = gstate.fbptr & 0x00FFFFFF; fbWidth_ = gstate.fbwidth & 0x00FFFFFF; diff --git a/GPU/GPUState.cpp b/GPU/GPUState.cpp index 8b7de27977..c384df55df 100644 --- a/GPU/GPUState.cpp +++ b/GPU/GPUState.cpp @@ -205,6 +205,10 @@ void GEState::FastLoadBoneMatrix(u32 addr) { } void GEState::Restore(const u32_le *ptr) { + Restore(ptr, savedContextVersion == 0); +} + +void GEState::Restore(const u32_le *ptr, bool oldLayout) { // Not sure what the first 10 values are, exactly, but these seem right. gstate_c.vertexAddr = ptr[5]; gstate_c.indexAddr = ptr[6]; @@ -218,7 +222,7 @@ void GEState::Restore(const u32_le *ptr) { } } - if (savedContextVersion == 0) { + if (oldLayout) { if (Memory::IsValidAddress(getClutAddress())) loadclut = *cmds++; boneMatrixNumber = *cmds++; diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 0422d67d89..7fe8bd8238 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -439,6 +439,8 @@ struct GEState { static void Reset(); void Save(u32_le *ptr); void Restore(const u32_le *ptr); + // oldLayout: PPSSPP's layout before savedContextVersion 1, with the matrices as raw floats. + void Restore(const u32_le *ptr, bool oldLayout); }; bool vertTypeIsSkinningEnabled(u32 vertType);