From 82a835b20b4e2254ea52109bf6b50795ca2dfc87 Mon Sep 17 00:00:00 2001 From: Shokunin <30949000+tetrisgm@users.noreply.github.com> Date: Sat, 26 Sep 2026 03:04:12 -0700 Subject: [PATCH] frame_fingerprint reset_on_load for A/B runs from one savestate frame_fingerprint reset_on_load=1 restarts the rolling hashes and the ring when the next savestate load completes, so two runs that load the same state (for example with and without a presentation mod) compare frame by frame from the same guest point. Debug tooling only. Co-Authored-By: Claude Opus 5.5 --- runtime/include/debug_server.h | 3 +++ runtime/src/debug_server.c | 21 +++++++++++++++++++++ runtime/src/main.cpp | 3 +++ 3 files changed, 27 insertions(+) diff --git a/runtime/include/debug_server.h b/runtime/include/debug_server.h index c4b512f5..27a3d2b9 100644 --- a/runtime/include/debug_server.h +++ b/runtime/include/debug_server.h @@ -255,6 +255,9 @@ void debug_server_freeze_dump_dirty_block_json(FILE *f, uint32_t max_count); void debug_server_freeze_dump_dirty_insn_json(FILE *f, uint32_t max_count); void debug_server_freeze_dump_evcb_json(FILE *f, uint32_t max_count); +/* frame_fingerprint reset_on_load: called when a savestate load completes. */ +void debug_server_note_savestate_loaded(void); + #ifdef __cplusplus } #endif diff --git a/runtime/src/debug_server.c b/runtime/src/debug_server.c index 0b5bf3e7..b3454379 100644 --- a/runtime/src/debug_server.c +++ b/runtime/src/debug_server.c @@ -5028,8 +5028,29 @@ static void handle_frame(int id, const char *json) * of two runs (native vs interp/oracle): the first frame whose wr or pc differs * is the first-divergence frame. Small integer fields only — no large/ragged * payload, so it never trips the trace-dump JSON/eviction problems. */ +/* frame_fingerprint reset_on_load=1: restart the rolling hashes and the ring + * when the next savestate load completes, so two runs that load the same state + * (for example with and without a presentation mod) compare frame by frame + * from that guest point on, independent of what happened before the load. */ +static int s_fp_reset_on_load = 0; +void debug_server_note_savestate_loaded(void) +{ + if (!s_fp_reset_on_load) return; + s_fp_reset_on_load = 0; + g_fp_wr_hash = g_fp_pc_hash = 1469598103934665603ULL; + g_fp_mmio_hash = g_fp_sp_hash = 1469598103934665603ULL; + g_fp_write_count = g_fp_mmio_count = g_fp_sp_count = 0; + s_fp_head = 0; + s_fp_total = 0; +} + static void handle_frame_fingerprint(int id, const char *json) { + if (json_get_int(json, "reset_on_load", 0)) { + s_fp_reset_on_load = 1; + send_fmt("{\"id\":%d,\"ok\":true,\"armed\":1}", id); + return; + } int count = json_get_int(json, "count", 1024); if (count < 1) count = 1; if (count > FP_RING_CAP) count = FP_RING_CAP; diff --git a/runtime/src/main.cpp b/runtime/src/main.cpp index 15ca6267..00efb41c 100644 --- a/runtime/src/main.cpp +++ b/runtime/src/main.cpp @@ -1018,6 +1018,9 @@ extern "C" void psx_frontend_on_savestate_notify(int is_load, int slot, int ok) extern "C" void psx_frontend_on_savestate_loaded(void) { mod_runtime_on_savestate_loaded(); +#ifndef PSX_NO_DEBUG_TOOLS + debug_server_note_savestate_loaded(); +#endif s_disabled_frame_presented = false; s_force_present_after_load = true; smooth_60_reset();