Commit Graph

288 Commits

Author SHA1 Message Date
Alex Vanderveen 4cdccf58c1 multitap enhancements 2026-08-07 10:19:12 -04:00
Alex Vanderveen 33c9901497 buiild with ICE 2026-08-07 03:56:32 -04:00
Alex Vanderveen 7940137d0d bump setup script 2026-08-07 03:42:37 -04:00
Alex Vanderveen 03a187374c GH & CI patch automation 2026-08-07 03:25:11 -04:00
Alex Vanderveen bea16e3ad2 -DPSXRECOMP_ALLOW_NO_BIOS=ON 2026-08-07 03:24:34 -04:00
Alex Vanderveen 09d94214af GH reorder 2026-08-07 03:08:40 -04:00
Alex Vanderveen a79619462e update script 2026-08-07 02:04:55 -04:00
Alex Vanderveen 480fcad652 new build wizard 2026-08-07 01:43:04 -04:00
Alex Vanderveen 94cb3807a9 Merge origin/master into integrate/game-codegen-hooks-into-rollback
Keep rollback/netplay multiplayer routing, dual-raster GL present, and TOC
fingerprints while taking master's CHD support, mod load acceleration,
adaptive widescreen, and geometry/perspective APIs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-06 22:50:38 -04:00
Alex Vanderveen 9b72328afa SFU preferred 2026-08-06 22:08:09 -04:00
Alex Vanderveen 4073e2311c rollback + fmv + connectivity 2026-08-06 20:34:50 -04:00
Alex Vanderveen 652be7ba02 rollback FMV patches and overlay 2026-08-06 00:52:14 -04:00
Alex Vanderveen c8f668cc9e Fix lobby relay rewrite via WS peer IP and harden rollback netplay.
Resolve stash conflict in psx_lobby_client by keeping getpeername-based
relay rewrite with the RFC1918-aware path, and land pending rollback
hookup/runtime changes.
2026-08-05 22:23:30 -04:00
Matthew Stanley 66af5c8dfb docs: drop our redundant embed_spirv fix, record the autocompile interp trap
Master fixed the embed_spirv.py concurrency race independently and better
(tempfile.TemporaryDirectory cleans up on early-return error paths too), so the
rebase conflict was resolved in master's favour and our mkdtemp version
removed. This branch stays SPU-only.

Records the trap that invalidated the first Tomba 2 measurement: game.toml's
overlay_autocompile_cmd names a recompiler path, and when it is absent
autocompile fails every attempt, no shard is ever built, and the runtime
silently interprets everything. Tomba 2 expects a worktree-relative path the
documented build recipe does not produce; MMX6 hardcodes an absolute path into
the main repo that works only by luck of local layout. Check autocompile_status
before trusting any perf number from a fresh worktree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 18:20:13 -07:00
Matthew Stanley 7e1421be7c docs: correct the Tomba 2 perf measurement (first attempt was interp-bound)
The first FMV A/B was run on a fresh worktree whose overlay shard cache was
cold AND whose autocompile could never work: game.toml points at
psxrecomp-v4/recompiler/build-t2/psxrecomp-game.exe while the documented build
recipe builds the recompiler at build-recompiler/ in the worktree root, so it
failed 8/8 with WinError 2 and the runtime silently ran interpreted
(dispatch_native = 0). The '40 fps / ~19 underruns per second' attributed to
master in the previous commit was that broken setup, not master.

Re-measured against the fully warm cache with the pre-SPU exe as a control in
the same worktree: interp_share 0.7813 vs 0.7775, exc_share 0.2386 vs 0.2381,
39.1 vs 38.0-38.4 fps. Identical within noise, so the DSP work is free.

Separately characterises the real pre-existing defect: the FMV is 96% native by
dispatch count but 78% interpreted by wall clock with 24% in exception
handling, even warm.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 18:16:17 -07:00
Matthew Stanley fe518e3031 docs: record SPU fidelity validation results and merge prerequisites
Measured, not asserted:
- BIOS LLE boot proves the reverb engine runs and rings down after the dry
  signal stops; noise LFSR observed shifting with correct parity feedback.
- Tomba 2 intro FMV A/B against the exact parent commit shows the added
  per-frame DSP work is performance-neutral (min p50 40.0 vs 40.3 fps) and
  does not starve the CD bus or the host sink. The FMV's 40 fps and its
  ~19/s host underruns are PRE-EXISTING on master.
- Records all ten places the documentation ran out as an oracle-comparison
  work list, and the two merge prerequisites (rebase onto moved master; bump
  recomp-ui to 99558ee or no title compiles).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 18:16:17 -07:00
Matthew Stanley 6e6a0b3ed8 spu: implement reverb, noise, sweeps and SPU IRQ; make CAUSE.IP2 combinational
Closes the four gaps named in issue #103 and lands the separable, verified
parts of PR #102. See docs/internal/SPU_FIDELITY_103.md for the per-piece
disposition and the oracle-verification queue.

SPU DSP (issue #103), clean-room from hardware documentation:

- Reverb: the documented 22050 Hz engine — vLIN/vRIN input, same-side and
  crossed different-side IIR reflections, 4-tap comb early echo, both
  all-pass filters, vLOUT/vROUT output, and the work-area address advance.
  Gated on SPUCNT bit 7 for WRITES only; reads, IRQ checks, address advance
  and output always run, as on hardware. Addressing is confined to
  [mBASE, 0x80000). Per-voice sends from EON, CD send from SPUCNT bits 0+2.
- Noise: 16-bit LFSR with the documented parity feedback, clocked at the
  SPUCNT bits 8-13 rate; NON voices substitute it for their ADPCM sample.
- Volume sweeps: all 24 voice L/R plus main L/R. Bit 15 selects sweep vs
  direct; sweep is a live envelope on the same rate machinery as ADSR, and a
  guest read of a sweeping register returns the live level.
- Capture buffers: CD L/R and voice 1/3 output written to SPU RAM, so a game
  that parks the IRQ address there still gets its interrupt.
- SPU IRQ (I_STAT bit 9): checked at every SPU RAM access class — FIFO, DMA
  both directions, ADPCM block fetch, capture writes, reverb work-area
  accesses — gated on SPUCNT bit 6, mirrored in SPUSTAT bit 6, acked by
  clearing SPUCNT bit 6.

The CD-only fast path in spu_render was removed rather than extended: the
SPU now has per-frame work that must run in every path, and an FMV (XA audio
with zero active voices) is exactly the CD-with-reverb case.

This is a clean-room implementation from the psx-spx/nocash register map and
documented algorithm. Beetle's source was deliberately not consulted: it is
GPL-2.0-or-later and this project is PolyForm Noncommercial. PR #16 was
parked for exactly that reason and PR #13's reverb was separately wrong (it
gated on bit 15 of dAPF1, an address offset, instead of SPUCNT bit 7). The
one place this knowingly deviates from hardware is the 22.05 -> 44.1 kHz
reconstruction filter, which the documentation does not specify; it is
isolated in a single function and flagged for oracle comparison.

CAUSE.IP2 (from PR #102):

IP2 is combinational on R3000A — it mirrors the interrupt line and falls the
instant the guest acks I_STAT or masks the source. It was being OR'd in at
delivery and never cleared, in TWO places (the compiled path and
psx_interpreter.c, the latter missed by PR #102), leaving a phantom pending
interrupt that can spin a kernel dispatcher looping on CAUSE.IP & SR.IM.
psx_irq_refresh_cause_ip2() is now the sole writer of bit 10, refreshed at
raise, I_STAT ack, I_MASK write, HLE context restore and power-on. Verified
against the Beetle oracle's irq.cpp/cpu.cpp rather than asserted, and
covered by test_cause_ip2_combinational.

Mid-dispatch audio pump (from PR #102), with a fix: routed through a gate
that mirrors sdl_audio_update's mute/sink decision. Pumping unconditionally
from the VBlank edge, as submitted, would have pushed real audio during every
turbo-load hard mute and defeated the freeze-in-place mute model.

SPU RAM DMA readback (from PR #102): DMA4 in the SPU->RAM direction wrote
literal zeros; SPU RAM is readable memory and titles carry state through it
across an Exec boundary.

Also fixes an unrelated build race found on the way: tools/embed_spirv.py
wrote its intermediate SPIR-V to <source>.spv, so the two runtime targets
that embed the same shaders raced on one path and one deleted the file the
other was reading.

Co-Authored-By: Alexandros Mandravillis <Alexbeav@live.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 18:16:16 -07:00
Matthew Stanley 42a69624b1 fix(tools,docs): diagnose unconfigured recompiler build dirs in regen_bios
A contributor bringing up a new title hit four dead-ends in a row, three of
which were the same missing step wearing different masks: `regen_bios.sh`
builds the BIOS emitter but never configures it, and nothing said so.

- "no recompiler build dir found (set PSXRECOMP_BIOS_BUILD)" pointed at an
  env var when a fresh clone has no CMake tree to point it at. Both discovery
  failure and an explicit override now name the actual missing step and print
  the configure command.
- Setting PSXRECOMP_BIOS_BUILD skipped the CMakeCache.txt check that discovery
  applies, so an unconfigured directory reached `cmake --build` and died with
  cmake's bare "Error: could not load cache". Validate the override too.
- A CMake configure that FAILS still writes CMakeCache.txt — the cache lands
  before the generate step, which never runs after a FATAL_ERROR. So "has a
  cache" did not mean "is buildable": the directory left behind by his failed
  SDL and BIOS-backend configures had a cache and no build.ninja, and the
  build reported only `ninja: error: loading 'build.ninja': GetLastError() =
  2`. Read the generator out of the cache, check for its build files, and say
  what happened. Discovery skips such a directory and keeps looking rather
  than selecting it and dying; an unrecognized generator falls through to
  cmake instead of inventing a failure.

All errors now go to stderr (the old one went to stdout).

Docs: the README's framework build block configured the recompiler and jumped
straight to the runtime build, omitting the required BIOS regen between them —
exactly the hole he fell into. It is now the same numbered 1/2/3 sequence
docs/BUILDING.md already used. BUILDING.md gains troubleshooting entries for
the two CMake half-configured-directory errors, the fresh-clone "No recompiled
BIOS backend available", and PSXRECOMP_BIOS_BUILD being resolved relative to
the framework root rather than the shell's cwd.

Verified: both new failure paths and the half-configured-directory case
reproduce and now self-explain; discovery precedence (build-t2 over build),
explicit-override precedence, Ninja/Makefiles/unknown generators, and a CRLF
cache all behave; end-to-end `regen_bios.sh --config bios/OpenBIOS.toml`
still emits (Dispatch entries: 3911).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 18:03:03 -07:00
Alex Vanderveen 2f7a2d6026 new 3+p architecture 2026-08-05 19:07:06 -04:00
Matthew Stanley c8b692eda2 feat(video): opt-in sub-pixel vertex precision + perspective-correct textures
Makes the parked projection/perspective work reachable and gets it into the
renderers people actually use. Addresses issue #92 (PGXP-style geometry and
texture correction).

The GTE side cache, SWC2 RAM provenance, GP0 triangle preparation and the
software-renderer consumption path already landed in 2ceaf5a ("park projection
and perspective correction", from kem0x PR #14), but were unreachable: the
generic setters gte_geometry_correction_set() / gpu_texture_correction_set()
had no production caller, and the corrected vertices went straight to
sw_set_precise_triangle(), bypassing the renderer vtable — while the default
renderer is OpenGL.

This adds:

- [video] geometry_correction and [video] perspective_texturing, in game.toml
  and settings.toml, both defaulting false. Independent knobs; the launcher
  seed marks them present so a save round-trips a hand-edited key instead of
  dropping it. Startup names the active pair, and notes when geometry
  correction is on below supersampling 2 (where it cannot be seen).
- gr_set_precise_triangle() / gr_set_perspective_triangle() on the
  GpuRenderBackend vtable, so gpu.c hands the correction to whichever backend
  is live rather than to the software rasterizer directly. NULL entries no-op.
- OpenGL and Vulkan consumption. Positions are already float end-to-end, so
  sub-pixel vertices drop in; the readback dirty rect widens by one pixel to
  cover them. Perspective UVs use a per-vertex a_q weight and clip coordinates
  pre-multiplied by w = 1/q, letting the hardware's own perspective divide
  interpolate a smooth UV varying beside the affine noperspective one. a_q == 0
  — the default, and what every prim gets with the feature off — makes w
  exactly 1.0 and selects the affine varying, so the faithful path is the
  pre-feature pipeline unchanged.

The PS1-visible GTE SXY FIFO stays integer either way: guest-side screen-bounds
culling and SXY readback are untouched, and this remains visual-only.

Also fixes a pre-existing concurrent-build race found while validating: every
runtime target runs embed_spirv.py over the same shaders, and each wrote
"<shader>.spv" next to the source, so under -j N one process deleted the file
another had just written (FileNotFoundError on a shader that compiled fine).
The intermediates now go to a per-invocation temp dir.

Parked-work provenance retained; see ENHANCEMENTS.md G1.

Co-authored-by: Kareem Olim <kareemolim@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 14:02:58 -07:00
Matthew Stanley f3d60331a7 autocompile: name the resolved interpreter at configure, warn on Cygwin builds
Root-caused on Tomba 1: overlay_autocompile_cmd's bare 'python' resolved
through PATH to the devkitPro MSYS2/Cygwin python (usr/bin precedes the
Windows install), which segfaults (exit 0x0B00, signal 11) under the
kill-on-close job spawn BEFORE writing a byte — so every compile failed
with '(no output captured)' and nothing pointed at the cause; the title
silently ran interpreted.

At configure time, resolve the command's first token exactly as
cmd.exe /C will (SearchPathA with .exe), print the binding once, and
warn loudly when msys-2.0.dll/cygwin1.dll sits beside the resolved
interpreter, recommending the Windows launcher form 'py -3 ...'.
Also fail loudly up front when the token doesn't resolve at all.

Doc'd in ASYNC_OVERLAY_COMPILE.md. Title game.toml fixes (python ->
py -3) ship separately in each game repo.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 10:55:00 -07:00
Matthew Stanley 67757efac4 feat(runtime): add CHD discs and mod-owned loading modes 2026-08-03 22:32:17 -07:00
Alex Vanderveen c82c6deb35 rollback SFU using recomp-net-server 2026-08-03 18:18:18 -04:00
Alex Vanderveen 34f2ecb490 Merge pull request #97 from mstan/feat/game-codegen-hooks
Feat/game codegen hooks
2026-08-03 07:26:00 -04:00
Alex Vanderveen 3428829090 Require cmake-clang-v1 1.0.4 for Linux IPO linking.
Floor ensure-toolchain at 1.0.4 (libxml2 + clang.cfg -fuse-ld=lld) and
prepend pack lib/ to LD_LIBRARY_PATH when activating the toolchain.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-03 07:20:31 -04:00
Alex Vanderveen a1f80d6784 bump workflow 2026-08-03 05:36:36 -04:00
Alex Vanderveen 804d3094c0 Merge feat/game-codegen-hooks into feat/rollback-netplay.
Keep rollback netplay/runtime authority (dual-raster, snaps, lobby) while
taking local codegen host/CLI/toolchain packaging from game-codegen-hooks.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-03 05:13:45 -04:00
Alex Vanderveen 0feb7709f6 rollback opengl render path, ICE patches, resim optimizations 2026-08-03 05:04:48 -04:00
Alex Vanderveen 7234d347ea Merge upstream/master into feat/game-codegen-hooks.
Keep local codegen/FMV cutover/zlib host work while taking upstream
tests, FPS telemetry, and mod-provider wiring.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-03 03:29:32 -04:00
Alex Vanderveen d35024ef23 codegen toolchain shared dir with retcomm 2026-08-03 02:54:19 -04:00
Alex Vanderveen 90266d4eaa resim optimizations 2026-08-02 19:11:04 -04:00
Alex Vanderveen bc99f95fff optimize scheduler and button edge case 2026-08-02 18:12:17 -04:00
Alex Vanderveen 6917d4a620 scheduler optimization on WAN 2026-08-02 17:49:36 -04:00
Alex Vanderveen fb252728a5 optimize scheduler WAN performance 2026-08-02 16:12:01 -04:00
Alex Vanderveen ceb51b6a13 rollback stability patch 2026-08-02 14:13:08 -04:00
Alex Vanderveen cc6b061f24 resim catchup patch 2026-08-02 13:23:55 -04:00
Alex Vanderveen 0392b3ff48 rollback scheduler v1 2026-08-02 12:57:00 -04:00
Alex Vanderveen 9769e9fbc2 rollback patches 2026-08-02 00:08:39 -04:00
Alex Vanderveen 4ddd2d01b9 rollback patches 2026-08-01 14:13:58 -04:00
Matthew Stanley 5176e40037 build: isolate the SDL3 entry point implementation
SDL_main.h is a single-header implementation in SDL3. Include it only from the translation unit that owns main so MinGW emits one WinMain instead of one per SDL-using source.
2026-08-01 10:43:59 -07:00
Alex Vanderveen 3e46b5f033 windows host-native toolchain download 2026-08-01 12:57:13 -04:00
Alex Vanderveen f46bcaae85 windows toolchain patch 2026-08-01 10:36:07 -04:00
Matthew Stanley c264a704ec debug: generalize Crash Bash boot write watch
Extract the useful diagnostic from PR #13 into an opt-in, title-agnostic boot
write-range trace with TCP-queryable context.

Co-authored-by: NyperYuhgard <93950153+NyperYuhgard@users.noreply.github.com>
2026-08-01 02:15:34 -07:00
Alex Vanderveen 20d08da27a window dll workflow patch 2026-08-01 01:37:12 -04:00
Alex Vanderveen 92c82adecc split toolchain from core game package 2026-08-01 01:03:44 -04:00
Alex Vanderveen 2f99cca345 migrate more tools into psxrecomp for building 2026-08-01 00:32:10 -04:00
Alex Vanderveen 4cb93f8c3f migrate bundling logic into psxrecomp, thinner layer at game level 2026-07-31 23:18:24 -04:00
Alex Vanderveen defaf257d9 bundle final tools + self cleanup to save space 2026-07-31 21:39:03 -04:00
Alex Vanderveen d8e5c012e6 self-build patch 2026-07-31 21:11:07 -04:00
luisg0c 65b499f79a test(recompiler): register l2_structural_test and reachable_discovery_test
Both targets are defined unconditionally and every build produces them, but
neither had an add_test() entry, so neither could run and neither could fail.

This is the same gap the codegen tests below them had before they were wired
in, and docs/TESTING.md states the rule directly: "an unregistered test cannot
fail, and a test that cannot fail is not a test."

Both were run manually before being registered and both pass. They are
self-contained -- no BIOS profile, no generated C, no psxrecomp-game -- so
unlike the neighbouring tests they need no WORKING_DIRECTORY.

    l2_structural_test        -> L2 structural: 239/239 ok
    reachable_discovery_test  -> ALL PASS

ctest -N goes 33 -> 35, so the three places that state the count are updated
to match. Note they said 29, which was already stale before this change.
2026-07-31 15:42:55 -07:00