Keep temporary keyboard profiles separate from saved bindings. Add optional persistent mouse capture with ordered release/focus/reset handling, and let offline sources represent an unplugged port without falling back to physical input. Existing capture and source defaults remain intact. Beads: beads-9wg8 and beads-eio.19.18.
Preserve new Setloc targets and explicit seeks. Serialize the pending-location flag in a validated CDF3 extension while retaining CDF2 and legacy state readers. Covers ReadN/ReadS pause, repeated resume, seeks and state restores. Beads: beads-cgvd.
P1: quality_launcher_apply is now a pure preset -> rows mapping
(psxq::rows_from_runtime plus startup constants); it never writes the live
globals. The in-game menu publishes only thread-safe callbacks: that
mapper, and a re-detect that returns this session's detection (a fresh
probe needs the GL context and mutates the run's state, so it stays in the
pre-game launcher). Summary/reason strings and the detection are fixed on
the main thread at menu setup; settings_get reads only the main-thread
snapshot.
P2: psxq::MenuSelection keeps what the player selected versus what is live.
A pick's next-launch rows and netplay-deferred rows stay selected for the
next seed until the live value matches; other rows follow live. The host
classification moves to psxq::classify_launcher/row_differs (same rules).
Tests: quality_presets_test test_ingame_menu_host_path runs the review's
fixture through the host get/pick/apply/save path (Ultra -> High, then
Antialiasing = NONE; a governed edit is still Custom from High; a netplay-
deferred row stays selected). menu_quality_callbacks_test guards the
draw-thread callbacks against runtime writes and stateful calls.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Restart bits: a group waits only when the edit touches it (next differs
from the live value) and the result differs from boot. Dynamic
resolution moves the live internal resolution off boot, so an in-game
texture filter change relaunched the game. test_menu_video_snapshot
covers both cases.
- Return to the frontend from a local game opens the launcher as at
boot; only a lobby match start (the runtime's pending-launch exit, or
the provider's lobby view asking once its match started) keeps the
launch and resumes the room.
- Default provider: with no title choice, the UI library's provider is
used when it ships one (recomp_ui_psx_menu.h), so recomp-ui stays the
default; PsxMenuHost.default_selection tells it to keep the title's
default presentation.
- Debug: menu_host reports provider, open, pause, capture and snapshot.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Register netplay_rb_verify_lost_post_test (#636). Each seat is built from
the production POST receive loop, Verify retransmit/wait/timeout block,
quorum publish and progress helpers cut from psx_netplay_rb.c, with
recomp-net's quorum, a controlled clock and a lossy/delaying POST
transport. Covers a Live seat past the target with its POST dropped,
genuine slow replay up to and at the target, first observation, multiple
owing seats, a disconnected or never-present seat, late and duplicate
POSTs, a later epoch and a rematch; each timeout must land within
RB_VERIFY_TIMEOUT_MS of the last in-episode progress, and the following
realignment episode must confirm one digest on every seat and advance the
confirmed frontier. The lost-POST case is also built against the pre-fix
wait (rb_owing_seats_progressed) and must hang there.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review follow-up on #661 (#636):
- test_depth24_present_hold_vblank.py reads sources as UTF-8 (cp1252 on
native Windows Python raised UnicodeDecodeError).
- The present skip is now guest state: set at guest VBlank, read (not
consumed) by the present and packed into the GPU snap's hold word (bit 8;
older snaps derive it from the count). The executable test showed the
host-side latch made the present of a restored tick differ from live on
the last held VBlank (hold 0, skip 1), exposing stale trailing FMV
columns after a rollback load.
- Depth24 scanout staging and trailing-column blanking move from main.cpp
into gpu_depth24_stage_scanout (gpu.c), so the test renders through the
same code every CPU depth24 present runs.
- New depth24_present_hold_exec_test: drives real gpu.c through a 15-bit to
24-bit FMV, GP1(07h) retargets and mode transitions; compares hold, skip,
upload span and snapshot bytes across windowed/headless/deferred presents,
rollback replay from every tick and disk loads, and checks staged frames
never show stale movie pixels while the new movie stays visible.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
restore_edge_irq_replay_test links the real scheduler (traps.c) and IRQ
delivery (interrupts.c) against a deterministic harness guest. Each case
runs live, captures state at a block edge with the edge's resume PC, then
restores from inside guest execution through interrupts_resync_after_restore
+ psx_scheduler_resume_at and requires every delivery (cycle, EPC, CAUSE,
SR, I_STAT, interrupted GPRs, TCB save) and every later block to match live.
Covers compiled-game, BIOS ROM, CPS-continuation and interpreted resumes,
no pending IRQ, I_MASK / SR.IEc / SR.IM2 gating, same-edge dedup against the
game dispatch-entry check, and null-PC recovery (RESUME_CURRENT without
resume_at) not inheriting the one-shot check. On master the ROM,
continuation and interpreted resumes take the IRQ one block late.
The source-guard test now reads traps.c as UTF-8.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Verify retransmits POST and aborts the episode (realign) after
RB_VERIFY_TIMEOUT_MS, but re-arms that timer whenever an owing seat's
tip moves, on the theory that it is still replaying. A seat that already
finished the episode and runs Live past the target also moves its tip,
so a lost POST from it kept the others in Verify until the liveness
timeout ended the match (3 seats across a Mac and a PC: two seats waited
for "peer POST" at tick 12099 while the third was Live at 12114; #636).
Only progress up to the episode target now re-arms the wait; past it the
timeout is honoured and the episode realigns.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GP1(07h) arms s_d24_present_hold to skip a few Swaps after a depth24
display-band retarget. The hold is in the GPU snap, but it counted down
only at host present: a headless run (and any path that skips the present)
left it stuck, and a rollback snap load zeroed it. In R4's 4-seat rollback
self-test the replayed saves then differed from the live saves of the same
ticks in the GPU section (hold 3 live, 0 replay; #636).
The count now moves at guest VBlank (gpu_vblank_tick), which also latches
whether the following present skips its Swap; the present only consumes
that latch. A rollback snap load keeps the restored count. A disk
savestate load still clears it so the restored VRAM shows at once.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>