Commit Graph

1961 Commits

Author SHA1 Message Date
Shokunin e730e03a8a GL: opt-in bloom ([video] bloom), sourced from 3D and additive primitives only
[video] bloom = 0.0 (off, default) .. 2.0 adds a glow around lights on the
OpenGL backend. PSX_BLOOM overrides it for one run; {"cmd":"bloom"} reads or
changes strength, threshold and a debug view live. It is a plain [video] key,
so [quality.*] presets can switch it off on low-end machines.

The HUD never glows: with bloom on every textured and untextured draw is
followed by two stencil-only passes of the same vertices that keep a
"may glow" mark in stencil bit 1 (bit 0 stays the mask-bit mirror). Opaque
primitives clear it under their coverage, then PGXP-proven 3D primitives and
additive semi-transparent texels/primitives (modes 1 and 3) set it, painter
ordered like the colour; 3D and non-3D primitives never share a batch while
bloom is on. Semi-transparent primitives leave the mark alone and the PGXP
depth-clear pass (colour writes off) marks nothing. Without PGXP geometry only
additive primitives glow.

The pass runs on the composed game image before AA and the OSD: the presented
surface's marks are blitted into a quarter-resolution stencil, a soft-knee
bright pass runs under it, three separable Gaussian iterations spread it and a
screen blend adds it back. The marks follow the picture: native-wide centre
copies and Smooth motion surfaces (redraw and reprojection) copy stencil with
colour, and generated frames get the same pass. Off: nothing runs, no state
changes, and the composed frame is byte-identical to master.

test_gl_bloom (gl_bloom_test): off is byte-identical before/after bloom and
with --dump against master; on, a bright 2D panel and a panel over a lit 3D
polygon are byte-identical to off, an additive and a 3D polygon glow; guest
VRAM is unchanged; on this thread and on the render thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:15:46 -07:00
Matt Stanley 7b3b1ea286 Merge pull request #654 from RetroPortingToolKit/fix/gl-present-ring-restart
Debug present ring: forget GL names when the renderer shuts down
2026-10-13 01:31:20 -07:00
Matt Stanley 035af4e444 Merge pull request #592 from RetroPortingToolKit/feat/linux-tcc
Linux releases bundle TinyCC (built from source) with musl headers
2026-10-13 01:31:14 -07:00
Shokunin 4c2e703f12 Present ring reset after the render thread stops; fixture covers the worker
Review (#654): forget the ring's names after gl_renderer_render_thread_stop
(the worker presents and captures on its own thread, and stop drains it
and hands the context back), before the context is deleted. The call is
unconditional (an empty stub without debug tools). The fixture adds a
render-thread pass: frames captured on the worker and drained, more left
queued at shutdown, then checks the worker stopped first and every name
and pending readback is gone. Fails if the reset runs before the stop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 01:22:15 -07:00
Shokunin 47fb2af915 Launcher handoff: keep the texture filter enum (xBR no longer becomes bilinear)
The seed path collapsed ls.texture_filter to a boolean, so a launcher's
xBR (3) was saved and applied as bilinear, and the rematch paths passed
the raw value through unchecked. psx_texture_filter_from_ui is now the
one translation (in-range values pass, others are nearest). Test:
video_texture_filter_test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:06:00 -07:00
Shokunin d4a2f6afdb gl_present_ring_restart_test: ring names do not outlive the GL context
Hidden-GL fixture: presents build the ring, shutdown must forget every
name and pending readback, and a second context rebuilds live objects.
Fails without the fix (names kept). run_gl_texture_filter.py gains
--debug-tools to compile the ring in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:05:10 -07:00
Shokunin 09f10143e4 Debug present ring: forget GL names when the renderer shuts down
After a renderer restart (lobby rematch, in-game menu -> match) the
capture read back into a stale pack-buffer name, i.e. into client memory
at offset 0, and crashed in glReadPixels (debug-tools builds).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:03:50 -07:00
Shokunin 3fee0ae7be Linux tcc: build without the legacy bounds-checking runtime (glibc 2.34+)
tcc 0.9.27's lib/bcheck.c uses __malloc_hook, removed in glibc 2.34, so
the pinned build failed on Ubuntu 24.04 (lib/bcheck.c:738). Shards never use
-b; the build now passes BCHECK_O= unconditionally, keeping every other
libtcc1.a object. The bundle smoke also clears LIBRARY_PATH, CC and
GCC_EXEC_PREFIX and checks shards import no bounds-checking symbols.
Verified: linux_tcc_bundle_smoke_test passes on Ubuntu 24.04 x86_64
(glibc 2.39, gcc + libc6-dev installed, so host headers exist but are not
used) and on Steam Runtime sniper (glibc 2.31).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:02:09 -07:00
Matt Stanley e6223c9c42 Merge pull request #648 from RetroPortingToolKit/fix/host-sampler-new-thread
host sampler: no pthread_self() in the SIGPROF handler on macOS
2026-10-12 23:36:26 -07:00
Matt Stanley 1f51d7e617 Merge pull request #650 from RetroPortingToolKit/fix/debug-savestate-slot-range
debug server: name an out-of-range savestate slot
2026-10-12 23:35:48 -07:00
Shokunin 7dc8fdde9a debug server: name an out-of-range savestate slot
savestate save/load with slot >= SAVESTATE_SLOTS (12) was refused with the
generic message that blames LLE runs, which sent a test chasing the wrong
cause. It now replies "slot N out of range (0..11)". Guarded in
test_savestate_status_protocol.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:21:53 -07:00
Shokunin 7ef25d50ff host sampler: tell the emulation thread apart by stack, not pthread_self
SIGPROF can land on a thread that is still being created. On macOS arm64
pthread_self() there hits a pointer-authentication trap (EXC_BREAKPOINT in
on_prof), which killed debug-tools builds at boot when a second instance
started lobby threads. The handler now compares the interrupted stack
pointer with the emulation thread's stack range; Linux keeps pthread_equal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 11:36:26 -07:00
Shokunin d185dac101 tests: drop duplicate stubs in test_gl_scale_invariance.c
gpu_ws_background_requires_full_composite and gpu_timeline_note were defined
twice after a merge, so every GL fixture that includes this file
(gl_post_aa, gl_bloom, ...) failed to compile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 23:01:52 -07:00
Shokunin 9714fb678a Linux tcc bundle: hermetic includes and a real-shard smoke test
- compile_overlays: the bundle layout now compiles with -nostdinc and only
  the bundle's own headers (tcc's include/, then musl's libc-include/), so a
  host with libc6-dev cannot change what a shard compiles against.
- runtime/tests/test_linux_tcc_bundle_smoke.py (ctest
  linux_tcc_bundle_smoke_test): stages the bundle exactly as a release does
  (pinned tcc 0.9.27 built from source, musl 1.2.5 headers, runtime
  headers), compiles an emitter-shaped overlay shard through
  compile_overlays' own tcc path (preamble shim, call_by_address rewrite,
  exports) for PGXP flavors 0 and 2 with PATH emptied, loads the .so and
  checks overlay_abi() and the exported function. Linux x86_64 only (skips
  77 elsewhere). Passes in the Steam Runtime sniper SDK image.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 22:38:53 -07:00
Shokunin 7e869d7741 Linux tcc: adapt musl's va_list to tcc's stdarg.h
Found by the clean-box smoke: every shard failed with "';' expected (got
va_list)". With the adaptation, 26 overlay shards compile on a Debian box
with no compiler and no libc headers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 22:38:48 -07:00
Shokunin 32f6aa7315 Linux releases bundle TinyCC (built from source) with musl headers
tinycc publishes no Linux binary, so Linux release toolchains had no tcc and
a player without a compiler -- every Steam Deck: SteamOS has none and a
read-only root -- kept overlays interpreted. stage_toolchain now builds the
pinned, unmodified tcc 0.9.27 source on the packaging machine and stages it
as overlay_toolchain/tcc/ (tcc, libtcc1.a, tcc's include/) with musl 1.2.5's
MIT-licensed C headers in libc-include/ (both sources SHA-256 pinned).

compile_overlays.py recognises that layout and calls tcc with -B<dir>
-nostdlib -isystem <dir>/libc-include <dir>/libtcc1.a, so nothing from the
player's system is needed; shard libc symbols resolve against the game's
glibc at dlopen. Windows and system tcc invocations are unchanged. The
TinyCC notice names the Linux build and the musl headers.

Tests: test_release_stage_cache.py (Linux pins, notice, bundle args).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 22:38:48 -07:00
Alex Vanderveen c47f7391e8 fix netplay 2026-10-11 16:16:33 -04:00
Matthew Stanley f55a156c0b Adapt private sample-bank regression to guest-clock block mixer 2026-10-10 22:15:55 -07:00
Matthew Stanley 9fcbf43e3d Keep per-primitive filtering and PGXP lookup consistent after co-op merge 2026-10-10 20:53:30 -07:00
Matthew Stanley 7dfef44598 Reconcile current master with validated X4 co-op support for PR23 playtest 2026-10-10 20:49:35 -07:00
Matt Stanley 26b3878e78 fix: reduce CPU spin before high-refresh blended presents (#627) 2026-10-10 12:56:57 -07:00
Matt Stanley f9db2561d0 Fix persistent HD texture cache churn and missing live background dumps (#626)
* fix: reuse resident HD textures and publish live background dumps

* test: keep residency stubs local to the filtering fixture
2026-10-10 12:55:54 -07:00
Matt Stanley 19785e9f51 fix: guard ICE waiting-room helpers in offline builds (#625) 2026-10-10 12:55:50 -07:00
Matthew Stanley 4b96c039f6 Integrate current ICE lobby transports and preserve settled LAN boot settings 2026-10-10 10:53:54 -07:00
Shokunin 0b0641cbae Lobby: honour transport "ice" launches (same-NAT peers no longer dial themselves)
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>
2026-10-10 10:37:31 -07:00
Matt Stanley 8cb420660e Merge pull request #624 from RetroPortingToolKit/fix/pgxp-qualified-defaults-20261010
Use dataflow-only PGXP defaults automatically in hook builds
2026-10-10 09:52:57 -07:00
Matt Stanley f17a946e6a Merge pull request #623 from RetroPortingToolKit/fix/native-wide-default-clipping-20261010
Make camera-plane clipping automatic with native-wide projection correction
2026-10-10 09:52:51 -07:00
Alex Vanderveen 1a8994ac0b Merge feat/ice-hub-relay: host relay over ICE for online rooms
Resolved against master: resolve_transport keeps master's single-agent
transport=ice launch (2-player rooms) ahead of psx_transport_decide; match_caps
JSON keeps the mod-plan fields and adds relay_via=ice; recomp-net bumped to
a48d355 (host_ice).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-10 04:20:24 -04:00
Matthew Stanley 8f6867225c Support independent co-op audio voices and diagnostic OSD rows 2026-10-10 00:53:39 -07:00
Matthew Stanley e7a059643c fix: select dataflow-only PGXP defaults in hook builds 2026-10-10 00:48:22 -07:00
Matthew Stanley ddbb979f18 fix: enable camera-plane clipping with native-wide projection correction 2026-10-10 00:48:17 -07:00
Matt Stanley 6fd3d1c326 Merge pull request #587 from RetroPortingToolKit/feat/gl-accurate-blending
GL: correct PS1 blending by default + blend/mask accuracy test
2026-10-09 23:56:33 -07:00
Matthew Stanley 1dd2afec07 Merge master and enable PS1 blend correction by default 2026-10-09 23:55:29 -07:00
Matt Stanley 6beb7d821b Merge pull request #621 from RetroPortingToolKit/fix/no-fp-contract
Runtime: build with -ffp-contract=off for cross-host determinism
2026-10-09 23:54:18 -07:00
Alex Vanderveen 50b53cc6d0 Merge master into fix/lobby-ice-launch
Keep both new test targets in runtime/CMakeLists.txt.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-10 02:22:03 -04:00
Alex Vanderveen 9d6f0d4319 Merge master into fix/rb-multipeer-frontier
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>
2026-10-10 02:20:17 -04:00
Matt Stanley eb4c76fc47 Merge pull request #586 from RetroPortingToolKit/feat/gl-xbr-filter
GL: opt-in xBR edge-directed texture filter (texture_filtering = "xbr")
2026-10-09 23:19:31 -07:00
Shokunin bd0425d7ab Netplay rb: re-anchor dirty-RAM IRQ poll stride each tick; av skips d24 helpers
- 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>
2026-10-09 22:40:01 -07:00
Alex Vanderveen 1d2f4f95d3 sync 2026-10-10 01:38:54 -04:00
Matt Stanley 501a27c2fc Merge pull request #611 from RetroPortingToolKit/fix/fmv-confirm-lag
Netplay rollback: count post-movie agreement in confirmed ticks
2026-10-09 22:36:12 -07:00
Matt Stanley cf5bf1c88a Merge pull request #608 from RetroPortingToolKit/feat/mod-host-rumble
Mod API: title-supplied host rumble (psx_mod_set_host_rumble)
2026-10-09 22:36:08 -07:00
Matt Stanley 5a6527acc1 Merge pull request #605 from RetroPortingToolKit/fix/launcher-vsync-roundtrip
Launcher V-Sync row round-trips to [video] vsync
2026-10-09 22:36:04 -07:00
Matt Stanley 16758c1e24 Merge pull request #604 from RetroPortingToolKit/codex/mod-internal-resolution
Support session-only internal resolution requests from graphics mods
2026-10-09 22:35:59 -07:00
Shokunin c7d5b873cd Rollback snaps: the canonical machine at the tick boundary
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>
2026-10-09 22:16:06 -07:00
Shokunin 0ae1725627 Netplay rb: Live and Replay tick snaps use one resume-PC rule
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>
2026-10-09 22:15:57 -07:00
Shokunin 56f1e7bd3a Netplay rb: PSX_RB_DET_SELFTEST forces no-op rollbacks for the determinism diff
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>
2026-10-09 21:34:14 -07:00
Shokunin 2943e50cb1 Lobby: re-assert ready at most once a second (no lobby_update storm)
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>
2026-10-09 21:07:08 -07:00
Shokunin 1751c6973b Netplay rb: PSX_RB_SNAP_AUDIT replay-determinism log + diff tool
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>
2026-10-09 20:40:50 -07:00
Shokunin 2337f56764 Netplay rb: fix resim audit row print (else bound to the analog line)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 20:40:09 -07:00
Shokunin e88823ee4f Netplay rb: admit the Live tick a realign resumes into
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>
2026-10-09 20:03:14 -07:00