The default demanded SCPH1001.emitter.sha, which is gitignored (retail output
is generated from a dump, never committed), so every game's release CI failed
with 'SCPH1001.emitter.sha missing' on a clean checkout. Default to every
generated/*.emitter.sha; naming a stem still requires it.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The lobby server starts a 2-player room the host relay cannot carry on ICE
(recomp-net-server start_transport, launch transport "ice"). This client
knew only "host" and the legacy server relay. It inferred a relay from
equal host/guest endpoints -- which is exactly what two peers behind one NAT
advertise -- and each peer dialled its own public address: the match stayed
at "linking" forever.
- psx_lobby_launch_transport.h: one pure decision (host / ice / relay /
direct) with a unit test covering ICE, same-NAT endpoints, host relay and
the legacy relay cases.
- PsxLobbyJoinInfo.transport_ice; the launch handler records it and never
turns it into a relay; launch fill and resolve_use_ice start ICE p2p
(signalled over the lobby) for it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep both netplay_peer_frontier.h and netplay_fmv_confirm.h includes; advance lib/recomp-net to a48d355 (main, includes #38).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- The dirty-RAM interpreter's IRQ poll stride is host-only; a load resets
it to phase 0 while Live carried an arbitrary phase, so a replay could
take the VBlank in RAM code at another instruction. It is now
re-anchored at every tick boundary in Live and Replay alike.
- The av digest zeroes the three depth-24 present helpers at the end of
the GPU snapshot (upload span, present hold, previous height): host
presentation state a suppressed-present replay leaves different, not
guest-visible.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PSX_RB_DET_SELFTEST on R4 4P showed a replayed save of tick T differing
from the live save of T. Each cause, and the fix:
- Replay's finish_frame poll passed no PC hint (Live used the IRQ resume
chain); it now uses psx_netplay_snap_resume_hint.
- Devices are serviced lazily up to the next event, so root counters and
cycles_since_vblank lagged the clock by a host-path amount at save; a
load re-anchors them at the clock and drops the lag. The save now
publishes pending cycle charges and services every device to the clock
first, and renders the SPU up to it.
- GTE / mul-div completion stamps and the load-delay give-back were
re-anchored at the restored clock on every load, so a stall in flight at
the snap point cost the live run cycles but the replay none. New
BS_SEC_CPUTIM carries them relative to the clock.
- The SPU CD-input FIFO was outside the snap and wiped on rollback loads;
new BS_SEC_SPUCD carries the queued frames and the load keeps them.
- LZCR is serialized as derived from LZCS (the raw backing stays 0 until
the first LZCS write; guests only ever read the derived value).
Older snaps without the new sections load as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replay's finish_frame saved its tick snap with no PC hint while Live used
the IRQ resume / last check / cpu->pc chain; the same tick's snap could
carry a different resume PC (psx_netplay_snap_resume_hint now serves both).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every K ticks the host rewinds 16 ticks with nothing mispredicted, so each
seat replays confirmed rows over ticks it ran live; with PSX_RB_SNAP_AUDIT
the diff tool then compares replayed saves with live ones field by field.
On R4 4P it shows replay saves taken at a different guest point than the
live save of the same tick (CPU pc, cycles_since_vblank, root counters).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The waiting-room pump sent set_ready every frame while the local seat was
not yet echoed as ready. Each set_ready is a lobby_update broadcast to the
whole room, so two waiting peers produced hundreds of updates; the host then
missed the seat update (seat 2 shown open, Start disabled) and, after Start,
the launch itself. Offer changes still go out immediately.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Per ring save, the section CRCs (and small sections in hex) of the
boot_state blob, marked live or replay. tools/rb_snap_audit_diff.py
checks a seat's replay against its own live save and seats against each
other, naming the first differing section and bytes. Off unless set.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Live realign restores the snap at T, sets the session to T+1 and
longjmps back into the guest from the admit spin. The resume ran before
T+1 was admitted, so that frame latched no inputs and did not advance;
the next frame was then counted as T+1 and the realigned seat ran one
frame ahead of its tick label from there on (ring saves after a NACK
realign carried the next tick's clock, 2x the cycles in the first
tick). Only the realigned seat shifted, so it forked from every other
seat; with four seats this produced the "resim core diverge" splits
and the later hc-fork / hang cascade.
flush_resume now admits the tick first on the Live realign path and
keeps spinning until it can.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gl_texture_lod_test (#585) and gl_blend_accuracy_test sat in the
SDL3::SDL3-static block after _gl_scale_sdl_inc was unset, so they got an
empty --sdl-include and were not registered at all where the static
target is absent. Move them into the gl_scale_invariance block that
defines both.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
NVIDIA quantises the constant blend colour to the 8-bit target (0.5 ->
127/255), putting B/2+F/2 and B+F/4 one step under a k*8 boundary, so
gl_blend_accuracy_test failed there (2016 mismatches). With accurate
blending on, use 128/255 and 64/255: exact in unorm8, and the small upward
bias stays inside the PS1 truncation bucket for every 5-bit operand, so
fixed-point and float blenders agree. Passes on Apple M-series GL and an
RTX 4080 SUPER (NVIDIA 610.88). Default path unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Verifies the four PS1 semi-transparency modes, set-mask, mask check and
texel STP at 4x internal resolution with PGXP depth on and off, directly
and on the render thread, against the PS1 formulas and the software
rasterizer (new gl_blend_accuracy_test).
Finding: with the historical surface bases (fills and texels stored as
k*255/31, everything else as k*8) single-layer blends are off by one 5-bit
step in places (1312 of the test's checked pixels, e.g. B+F/4 over a fill).
[video] accurate_blending = true stores every VRAM write as k*8 so GL's
8-bit blend truncated by the readback is exactly the PS1 arithmetic; whites
of fills/texels then present as 248 like uploads already do. Default off.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gl_texture_lod_test (#585) and gl_xbr_filter_test sat in the
SDL3::SDL3-static block after _gl_scale_sdl_inc was unset, so they got an
empty --sdl-include and were not registered where the static target is
absent. Move them into the gl_scale_invariance block that defines both.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- THIRD_PARTY_ATTRIBUTION.md carries Hyllian's MIT notice; the shader
comment says the filter derives from xBR instead of 'written from the
published description'.
- Rebased on #585: the branch tests fmode == 3 so xBR still runs when the
LOD bit is set; gl_xbr_filter_test now draws tracked quads with
texture_lod on and fails on the old u_filter == 3 test.
- The under-2x early-out runs before any neighbour fetch, and the other
ten fetches wait for the E==F/E==H test.
- OpenBIOS emitter stamp regenerated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>