Support identified scene motion in shared draw replay

This commit is contained in:
Matthew Stanley
2026-10-06 23:48:08 -07:00
parent e5e2dca85c
commit ce4ae025c6
+23 -12
View File
@@ -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;