From 12f98480b321049f0db466feb545814a3d4da632 Mon Sep 17 00:00:00 2001 From: Matthew Stanley <1379tech@gmail.com> Date: Wed, 14 Oct 2026 11:19:53 -0700 Subject: [PATCH 1/2] Preserve explicit GPU hold output state before the first held VBlank --- runtime/src/gpu.c | 11 +++++++---- runtime/tests/test_depth24_present_hold_exec.c | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/runtime/src/gpu.c b/runtime/src/gpu.c index 3403841f..cc4fc219 100644 --- a/runtime/src/gpu.c +++ b/runtime/src/gpu.c @@ -7859,7 +7859,7 @@ static int gpu_snap_emit(PstW *w) { WI(vram_read_active); WH(vram_read_x); WH(vram_read_y); WH(vram_read_w); WH(vram_read_h); WH(vram_read_col); WH(vram_read_row); /* Depth24 present helpers (MotK FMV) — must resume with upload span. */ - WU(s_d24_upload_x1); WI(s_d24_present_hold | (s_d24_present_skip ? 0x100 : 0)); + WU(s_d24_upload_x1); WI(s_d24_present_hold | 0x200 | (s_d24_present_skip ? 0x100 : 0)); WU(s_d24_prev_disp_h); #undef WU #undef WI @@ -7894,9 +7894,12 @@ static int gpu_snap_parse(PstR *r) { RI(vram_read_active); RH(vram_read_x); RH(vram_read_y); RH(vram_read_w); RH(vram_read_h); RH(vram_read_col); RH(vram_read_row); RU(s_d24_upload_x1); RI(s_d24_present_hold); RU(s_d24_prev_disp_h); - /* Bit 8: the latest VBlank was held. Older snaps lack it; a positive - * count after a VBlank implies the VBlank was held. */ - s_d24_present_skip = (s_d24_present_hold & 0x100) || (s_d24_present_hold & 0xFF) > 0; + /* Bit 9 marks an explicit skip flag (bit 8). GP1 can arm a positive + * count before VBlank, when skip is still false: that state must round + * trip exactly. Older snaps without the marker infer skip from count. */ + s_d24_present_skip = (s_d24_present_hold & 0x200) + ? (s_d24_present_hold & 0x100) != 0 + : (s_d24_present_hold & 0x100) || (s_d24_present_hold & 0xFF) > 0; s_d24_present_hold &= 0xFF; #undef RU #undef RI diff --git a/runtime/tests/test_depth24_present_hold_exec.c b/runtime/tests/test_depth24_present_hold_exec.c index f8cc4b40..c9c44a4d 100644 --- a/runtime/tests/test_depth24_present_hold_exec.c +++ b/runtime/tests/test_depth24_present_hold_exec.c @@ -312,7 +312,23 @@ static void check_rollback_and_disk(void) { assert(r == live[RETARGET_1 + 3].presented && h == live[RETARGET_1 + 3].frame_hash); } +static void check_pre_vblank_snapshot(void) { + reset_gpu(); + for (int f = 0; f < RETARGET_1; f++) { guest_frame(f); gpu_vblank_tick(); } + guest_frame(RETARGET_1); /* GP1 arms a count before the first held VBlank. */ + assert(s_d24_present_hold == 3 && s_d24_present_skip == 0); + const uint32_t n = gpu_snapshot_bytes(); + uint8_t *snap = (uint8_t *)malloc(n); + assert(snap); + gpu_snapshot_write(snap); + s_d24_present_hold = s_d24_present_skip = 0; + assert(gpu_snapshot_read(snap, n)); + assert(s_d24_present_hold == 3 && s_d24_present_skip == 0); + free(snap); +} + int main(void) { + check_pre_vblank_snapshot(); check_policies_agree(); check_hold_is_needed(); check_rollback_and_disk(); From 3bbfd03a101acef45f1a13e16a3c472f217d3f0e Mon Sep 17 00:00:00 2001 From: Matthew Stanley <1379tech@gmail.com> Date: Wed, 14 Oct 2026 11:29:13 -0700 Subject: [PATCH 2/2] Build GPU hold regression with MinGW link-time section removal --- runtime/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 83a2e28d..16ea2b90 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -980,6 +980,10 @@ if(BUILD_TESTING) src/psx_video_timing.c src/gpu_timeline.c) target_include_directories(depth24_present_hold_exec_test PRIVATE include src) + if(MINGW) + target_compile_options(depth24_present_hold_exec_test PRIVATE -flto) + target_link_options(depth24_present_hold_exec_test PRIVATE -flto) + endif() if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") target_compile_options(depth24_present_hold_exec_test PRIVATE -ffunction-sections -fdata-sections)