From ce4ae025c699acb163e4be610b00a043f311581a Mon Sep 17 00:00:00 2001 From: Matthew Stanley <1379tech@gmail.com> Date: Tue, 6 Oct 2026 23:48:08 -0700 Subject: [PATCH] Support identified scene motion in shared draw replay --- runtime/include/render_pass_replay.hpp | 35 +++++++++++++++++--------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/runtime/include/render_pass_replay.hpp b/runtime/include/render_pass_replay.hpp index fa3dff83..c707eab7 100644 --- a/runtime/include/render_pass_replay.hpp +++ b/runtime/include/render_pass_replay.hpp @@ -21,6 +21,7 @@ class PSXDrawReplay { uint8_t scratch[1024]{}; uint32_t start = 0, stop = 0, previous_tick = 0; bool captured = false, ready = false, have_tick = false; + bool projections = true; PSXProjectionHistory* history = nullptr; public: PSXProjectionStats stats{}; @@ -30,26 +31,34 @@ public: captured = ready = have_tick = false; ticks = 0; psx_projection_invalidate(history); } - void capture(CPUState* cpu, uint32_t first, uint32_t last) { + // Titles with known actor/camera layouts can apply their motion sets after + // restore, instead of matching final GTE projections. Both routes share the + // same draw-entry snapshot and machine sandbox. + void capture(CPUState* cpu, uint32_t first, uint32_t last, + bool capture_projections = true) { if (g_psx_render_pass_active) return; if (captured) invalidate(); // previous drawing section never completed - if (!history) history = psx_projection_create(65536); - if (!history || first >= last || ((first | last) & 3)) return; + projections = capture_projections; + if (projections && !history) history = psx_projection_create(65536); + if ((projections && !history) || first >= last || ((first | last) & 3)) return; entry = *cpu; start = first; stop = last; ram.resize(memory_get_ram_bytes()); std::memcpy(ram.data(), memory_get_ram_ptr(), ram.size()); std::memcpy(scratch, memory_get_scratchpad_ptr(), sizeof scratch); captured = true; ready = false; - psx_projection_capture_begin(history); + if (projections) psx_projection_capture_begin(history); } - bool prepare(uint32_t tick) { + bool prepare(uint32_t tick, bool motion_ready = false) { if (!captured) { invalidate(); return false; } captured = false; ticks = have_tick ? tick - previous_tick : 0; previous_tick = tick; have_tick = true; - psx_projection_capture_end(history, ticks, 512.0); - psx_projection_stats(history, &stats); - ready = ticks && ticks <= 8 && stats.changed && !stats.overflow; + if (projections) { + psx_projection_capture_end(history, ticks, 512.0); + psx_projection_stats(history, &stats); + } + ready = ticks && ticks <= 8 && (projections + ? stats.changed && !stats.overflow : motion_ready); return ready; } bool restore(CPUState* cpu, uint32_t alpha) { @@ -60,14 +69,16 @@ public: // shadows are stale; the pass checkpoint restores them afterwards. pgxp_invalidate_all(); *cpu = entry; - psx_projection_replay_begin(history, alpha); + if (projections) psx_projection_replay_begin(history, alpha); return true; } bool draw(CPUState* cpu) { const bool reached = psx_mod_run_guest_span(cpu, start, stop) != 0; - psx_projection_replay_end(history); - psx_projection_stats(history, &stats); - return reached && stats.replayed != 0; + if (projections) { + psx_projection_replay_end(history); + psx_projection_stats(history, &stats); + } + return reached && (!projections || stats.replayed != 0); } static uint32_t call(CPUState* cpu, uint32_t function, uint32_t a0=0, uint32_t a1=0) { const CPUState saved = *cpu;