Commit Graph

684 Commits

Author SHA1 Message Date
Matthew Stanley 224147bb07 runtime: select PSX recomp-ui assets 2026-07-28 13:48:08 -07:00
Matthew Stanley 9aa5466da7 Add per-game audio buffer target 2026-07-28 12:23:06 -07:00
Matthew Stanley a292a7c136 Add activation-only widescreen cull margin 2026-07-28 11:08:03 -07:00
Matthew Stanley 106e31d6e9 Make SDL3 the default runtime backend 2026-07-28 09:22:28 -07:00
Matthew Stanley f8c0f3f3b0 runtime: detect dev-any controllers in Hybrid mode 2026-07-28 00:26:36 -07:00
Matthew Stanley e4e2aa7a7d runtime: add per-game radial stick response 2026-07-28 00:20:45 -07:00
Matthew Stanley 64097606fb runtime: fix game-owned display and controller mods 2026-07-28 00:04:20 -07:00
Matthew Stanley c1eb052ca3 runtime: remove dead MMX6 host-side reveal 2026-07-27 19:30:48 -07:00
Matthew Stanley eb262c4b23 feat(mods): let a trusted plugin read its own option values
The manifest schema already carries typed, validated, launcher-rendered,
persisted options ([[option]] boolean/choice/integer), and the launcher
provider already reads them. A trusted activation plugin could not: the
callback takes no arguments, so a plugin was only ever an on/off switch.

That forced a parameterised feature to be modelled as one feature per
value, and `constraint` only expresses ordered_integer WITHIN a feature, so
those pseudo-features could not even be made mutually exclusive. A game
wanting "Widescreen: 16:9 / 21:9" or "Interpolation: 90/120/144/165/240"
had no way to express it as one entry.

psx_mod_option_value(package, feature, option, out, out_size) closes the
gap against the value the player actually committed. It returns 0 with an
empty string when the plan is not committed or the ids do not resolve, so a
caller applies its own default rather than reading "" as a selection. Ids
are explicit because registration is by plugin id alone and the callback
carries no package/feature context.

Also in this commit, from the same investigation:

* Sustained overlay-autocompile failure is now LOUD. After 3 consecutive
  failed runs the runtime prints once to stdout: what failed, the exit
  code, that overlays are staying interpreted and frame times will be far
  worse than the build is capable of, what to check, and the compiler's own
  output tail. Previously the only trace was a `fails` counter reachable
  over TCP, so a wholly-interpreted title presented as "why is this slow"
  rather than as a message. Threshold is 3, not 1, because isolated
  failures (a shard racing a capture rewrite, a transient lock) are
  ordinary and self-heal. Measured cost of the silent case on Tomba!:
  p50 frame period 105ms, vs 3.1ms once shards existed.

* The autocompile child's working directory is printed at startup beside
  cache and captures. Every relative path in overlay_autocompile_cmd
  resolves against it and it comes from game.toml's detected project root,
  so a game.toml staged outside the real root silently repoints the entire
  compile command with no other symptom.

* A build tree whose cache still carries recomp-ui's OFF for
  RECOMP_UI_ENABLE_MODS now says so at configure time. 610234a's seed only
  fires on a fresh cache, and a stale OFF is indistinguishable from a
  deliberate one, so such trees kept producing Mods-less builds across
  reconfigures - the same "reads as a stale build" failure one level up,
  and invisible. The explicit-OFF contract is deliberate so this does not
  override it; it makes the state audible.

Runtime ctest 16/16. Warning verified to fire on a tree configured with
-DRECOMP_UI_ENABLE_MODS=OFF and to stay silent on a fresh configure.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 17:33:44 -07:00
Matthew Stanley 5ec343ab4f fix(bios): make the boot-skip flag mean the same thing on every BIOS
`bios_hle` (default on) is the player-facing "skip the BIOS and go
straight to the game" flag, and it did nothing under the bundled
OpenBIOS: choosing OpenBIOS sat the player in the boot animation while
the identical build on retail SCPH-1001 went straight to the game.

Root cause was ordering, not policy. The tier has two axes with
different per-image requirements:

  * boot-skip     needs only `shell_entry_phys`, works under pure LLE
                  (nothing is synthesized — the shell call just returns
                  immediately), so any image exporting it can skip
  * kernel-call    needs `deliver_event_ret`, the kernel's own
                  DeliverEvent `$ra`, or a delivered callback returns to
                  the wrong PC

main.cpp correctly refused the call axis on an image without
`deliver_event_ret` by assigning `bios_hle = false` — and then derived
`boot_skip` from that already-mutated flag. OpenBIOS omits
`deliver_event_ret` (B0 semantics unvalidated) but DOES export
`shell_entry_phys`, so an available skip was cancelled by an unrelated
refusal, and one flag meant two things depending on a BIOS detail no
player can see.

Both axes are now decided by one pure, dependency-free function,
`psx_bios_hle_plan()` (runtime/src/bios_hle_plan.c): the boot decision
reads the REQUESTED `bios_hle`, each axis is gated on only the anchor it
needs, and refusals are reported at startup instead of downgrading
silently. `psx_bios_hle_configure()` clamps `boot_skip` to
`shell_entry_phys != 0` as a backstop so the banner and `hle_dump`
cannot overstate what can fire. The main.cpp local is renamed
`bios_hle_requested` and is no longer written back from the plan — the
`session_reboot` path re-enters that block, so folding a refusal into
the request would have made a netplay rematch differ from first launch.

Also in this pass:

* A BIOS profile's `[runtime]` block was parsed into
  `BiosConfig::runtime` and read by NOTHING, and bios/OpenBIOS.toml
  carried an inert `bios_hle = false` there that read as the reason HLE
  was off on OpenBIOS. It was not. `load_bios_config` now REJECTS
  `[runtime]` in a BIOS profile: a profile states facts about an image,
  never preferences.
* `psx_icache_fastpath_test` had been unbuildable ("redefinition of
  `psx_advance_cycles`" — the test's counting stub vs the header's
  `static inline`), which blocked every runtime test registered after
  it. It now builds with `PSX_OVERLAY_DLL_BUILD=1`, the seam
  psx_cycles.h already provides for a TU supplying its own advance.

Tests: new `bios_hle_plan_test` pins the matrix, including a 64-case
sweep asserting the boot decision is independent of
`deliver_event_ret` and the call decision independent of
`shell_entry_phys`. Runtime ctest 15/15, recompiler ctest 30/30.

Validated on Ape Escape (SCUS-94423) built against this framework with
both backends linked, headless, all four cases:

  OpenBIOS default   bios_boot=skip to game; route=2 fire at vec 0x30000
                     ra=0xBFC06EA8 (the continuation OpenBIOS.toml
                     documents); in-game on screen
  retail default     bios_boot=skip to game; route=2 at vec 0x30000
                     ra=0xBFC0702C; in-game on screen; differs only in
                     bios_backend=HLE (LLE fallback)
  PSX_BIOS_HLE=0     bios_boot=real intro; ring empty (no hook)
  KEEP_INTRO=1       bios_boot=real intro; ring empty

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 16:36:48 -07:00
Matthew Stanley b699089d46 runtime: let games move display options into mods 2026-07-27 16:16:26 -07:00
Matthew Stanley 63d8f88dc5 runtime: group front-layer UI for widescreen 2026-07-27 15:54:23 -07:00
Matthew Stanley 610234a907 fix(launcher): opt in to the recomp-ui Mods view by default
recomp-ui f6395d6 (upstream commit 39a6e4e, 'mods: make launcher integration
opt-in') gates the Mods view behind RECOMP_UI_ENABLE_MODS, which defaults OFF.
That is the right default for a cross-console launcher -- a console with no mod
system should not show an empty Mods tab -- but it is the wrong default here.

psxrecomp ships mod packages as a first-class documented feature
(docs/MOD_PACKAGES.md); Tomba! ships three catalogs and Ape Escape two. With
the option off, a title that already shipped a working Mods panel silently
loses it on its next rebuild: the panel is compiled in, the catalog is staged
beside the exe, and the view simply never appears. It reads as a stale build
rather than a missing flag, which is how it was found.

Opt in from the framework rather than in each game's CMakeLists, so every
title inherits it instead of six repos each needing the same line. Set before
including recomp_ui.cmake so its option() honours the value, and only when the
caller has not already decided, so -DRECOMP_UI_ENABLE_MODS=OFF still wins.

Verified on ApeEscapeRecomp: a clean configure with no extra flags now yields
RECOMP_UI_ENABLE_MODS:BOOL=ON and the compile definition on every launcher TU;
configuring with -DRECOMP_UI_ENABLE_MODS=OFF still produces none. runtime.cmake
is not in codegen_hash_sources.cmake, so the overlay cache tag is unaffected.
2026-07-27 15:24:52 -07:00
Matthew Stanley da093d4374 fix(build): link a BIOS backend only when its generated C provides one
PSXRECOMP_BIOS_STEMS defaults to "OpenBIOS;SCPH1001", so every game link
required a SCPH1001 backend. That backend is compiled from generated C which is
a derivative of a copyrighted Sony BIOS, so it is gitignored and only exists
after a developer regenerates it from their own dump. A checkout that has only
the bundled MIT OpenBIOS -- the documented default, and what a fresh clone gets
-- configured fine and then failed at link with:

    undefined reference to `SCPH1001_psx_bios_backend'

Hit while building Tomba 1, Tomba 2 and MMX6 to validate an unrelated branch;
all three needed -DPSXRECOMP_BIOS_STEMS=OpenBIOS as a workaround.

Filter the stem list to those that actually supply a backend, rather than
flipping the default. Flipping it would silently drop SCPH1001 for developers
who HAVE regenerated it; filtering keeps it fully supported when present and
simply absent when not.

Presence of the files is not a sufficient test. A generated/ tree produced
before the backend-descriptor mechanism existed has both <stem>_full.c and
<stem>_dispatch.c yet defines no descriptor -- exactly the local state that
produced the error above. The check therefore probes for the descriptor symbol
itself, in <stem>_dispatch.c (~1MB, where the emitter puts it) rather than the
multi-megabyte <stem>_full.c, so configure stays fast.

Also report what happened instead of leaving it implicit:
  - STATUS line naming the linked backends
  - STATUS line naming skipped stems with the regen command to fix them
  - FATAL_ERROR, with the OpenBIOS regen command, if no backend resolves at all
    (previously an empty registry would have surfaced as a confusing link error)

Verified: with default flags and a stale local SCPH1001 tree, Tomba 2 now
reports "BIOS backends skipped ... SCPH1001" / "BIOS backends linked: OpenBIOS",
links, and boots.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 12:32:30 -07:00
Matthew Stanley 49b57f4178 docs(gpu): correct the MMX6 widescreen comments; record what is safe to delete
Comment-only. No compiled code changes -- the sole non-comment diff line moves
a trailing comment off the g_mmx6_hostside declaration into a block above it;
the declaration itself is byte-identical.

A survey of the mmx6-named widescreen symbols found the existing comments
misleading in a way that invites a dangerous cleanup, so the findings are
recorded in the source next to the code they describe.

1. "Compatibility entry points for already-generated MMX6 sources" (gpu.h) was
   wrong. These are not MMX6 compat shims and are not safe to delete. They are
   the widescreen-2D entry points the recompiler emits for ANY title with a
   [widescreen.bg2d] block, and live generated code in several non-MMX6 repos
   links them today:
     cols/startcol/startx/stream_left/stream_right
         -> CrashBash, MegaManX5, Tsumu (+ -release)
     undercap
         -> Ape, CrashBash, MMX4, MMX5, Tsumu, Vigilante8, THPS2
   Each forwards to its psx_ws_bg2d_* twin, which is the real implementation.
   Only the name is historical. Renaming is not runtime-only: the names come
   from code_generator.cpp, which is in codegen_hash_sources.cmake, so it rolls
   the overlay cache tag and forces regen + reshard of every title.

2. Host-side reveal (g_mmx6_hostside) is dead in every shipping build, which
   the previous "kept inert pending removal" note understated. Nothing sets it
   but the mmx6_reveal debug command, PSX_DEBUG_TOOLS is OFF for Release, and
   no generated source anywhere references a host-side symbol. Noted that
   removing it is the last step decoupling the generic psx_ws_bg2d_* API from
   MMX6 -- mmx6_hostside_active() is currently embedded in the ternaries of
   psx_ws_bg2d_cols/startcol/startx -- and listed the symbols that go with it.

3. BG buffer relocation is a parked FEATURE behind a load-bearing SYMBOL, a
   distinction the old comment did not draw. With g_mmx6_reloc == 0 both hooks
   return their argument unchanged, but MegaManX6Recomp/game.toml names the
   bufbase/cap instruction sites, so the emitter writes calls into generated
   code and psx_ws_mmx6_bg_bufbase is genuinely called by MMX6's generated C.
   The supportable cleanup is to gut the bodies to identity and keep the
   symbols, not to delete the functions.

Removal of (2) and (3) is deliberately deferred: it touches the renderer and
wants its own session with MMX6 revalidation.

Verified: gcc -fsyntax-only on gpu.c exits clean (an earlier draft embedded
"*/" inside a block comment and broke the parse -- caught before commit);
ctest 29/29 green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 11:49:31 -07:00
Matthew Stanley 45408d60f1 fix(build): stop shipping the wrong binary as psxrecomp.exe
recompiler/CMakeLists.txt defined both `psxrecomp` (the user-facing CLI,
src/main_cli.cpp) and `PSXRecomp` (a legacy duplicate of psxrecomp-game, built
from the identical PSXRECOMP_GAME_SOURCES list). CMake treats those as distinct
targets, but Windows and macOS filesystems are case-insensitive, so both wrote
the same file and the last one linked won.

The CLI lost. After a clean build, psxrecomp.exe was the game recompiler,
answering `--config <game.toml>` instead of the documented
`build --disc ... --bios ... --output ...`. tools/build_cli.py packages that
binary into psxrecomp-cli-windows-x86_64.zip, and README's first instruction to
a new user is to download and run it, so the primary onboarding path handed
people a program matching no documentation. Invisible on Linux, which is why it
survived.

Remove the legacy target (psxrecomp-game already covers those sources) and add a
configure-time guard so it cannot recur: the guard compares OUTPUT_NAME
case-insensitively across a directory's targets and fails with an actionable
message. A rename alone would not have prevented recurrence.

The PSXRecomp.exe named in README's Release Package section is a different
artifact, the BIOS-only runtime named via OUTPUT_NAME in runtime/runtime.cmake,
and is unaffected.

Verified: clean build now yields psxrecomp.exe (791KB) printing the documented
`build --disc` interface; no case-colliding pair remains; guard confirmed to
fire by temporarily reintroducing a collision.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 11:49:31 -07:00
Matthew Stanley bb5fccea51 fix: make FPS telemetry opt-in 2026-07-27 11:44:31 -07:00
Matthew Stanley 79baa76d0a fix: stop overlay autocompile during shutdown 2026-07-27 11:01:50 -07:00
Matthew Stanley 2696c391b8 feat: add aspect-aware world participation 2026-07-27 10:48:41 -07:00
Matthew Stanley d116e0da3b feat(mods): add presentation interpolation rates 2026-07-27 10:40:49 -07:00
Matthew Stanley d34af54141 feat(mods): support native VBlank rate selection 2026-07-27 10:32:33 -07:00
Matthew Stanley 964cdb3870 feat(mods): expose adaptive display activation 2026-07-27 10:19:07 -07:00
Matthew Stanley fa408aae50 Merge trusted mod plugin support 2026-07-26 21:05:03 -07:00
Matthew Stanley 45dd4210cf Remove Tomba legacy hybrid controller path 2026-07-26 20:52:12 -07:00
Matthew Stanley 9683a1cf8c feat(mods): support mod-owned FMV skipping 2026-07-26 20:34:20 -07:00
Matthew Stanley 27a05dc09e fix(launcher): hide native-only aspect control 2026-07-26 20:26:28 -07:00
Matthew Stanley 99abda239f feat(mods): add pre-runtime activation plugins 2026-07-26 20:18:00 -07:00
Matthew Stanley a4afb828ac feat(mods): add trusted static vblank plugins 2026-07-26 18:59:10 -07:00
Matthew Stanley 8b77d8a730 fix: make overlay autocompile cache-safe 2026-07-26 09:39:24 -07:00
Matthew Stanley 436fe14101 widescreen: support guarded object participation overrides 2026-07-25 23:24:41 -07:00
Matthew Stanley 05e569c121 runtime: add sparse guarded mod fields 2026-07-25 21:42:35 -07:00
Matthew Stanley 62a80eab30 fix(mods): fingerprint CUE data track only 2026-07-25 21:14:28 -07:00
Matthew Stanley 35c1859cf4 Handle feature prerequisites in mod packages 2026-07-25 21:14:28 -07:00
Matthew Stanley 66f2c7be9e runtime: pass active mod context to resolvers 2026-07-25 21:14:28 -07:00
Matthew Stanley ddf3ca8962 feat: add ordered mod values and MIPS pair patches 2026-07-25 21:14:28 -07:00
Matthew Stanley bd460f3ce1 fix: guard complete dynamic patch records 2026-07-25 21:14:28 -07:00
Matthew Stanley eb3b4db599 feat: add bounded integer mod patches 2026-07-25 21:14:28 -07:00
Matthew Stanley 82bb5a21af fix: compose compatible partial mod overlaps 2026-07-25 21:14:28 -07:00
Matthew Stanley 968c9c23ce feat: add feature-oriented mod resolution 2026-07-25 21:14:28 -07:00
Matthew Stanley 50d4f456bf fix: preserve independent mod toggles 2026-07-25 21:14:28 -07:00
Matthew Stanley 9ff287c1fa feat: support multi-option mod conditions 2026-07-25 21:14:28 -07:00
Matthew Stanley 162194dc9b fix: auto-disable conflicting mod packages 2026-07-25 21:14:27 -07:00
Matthew Stanley 6c1bd61a1f feat: derive modded discs from verified stock images 2026-07-25 21:14:27 -07:00
Matthew Stanley 316eaa44a7 feat: add versioned runtime mod packages 2026-07-25 21:14:27 -07:00
Matthew Stanley ef38122068 fix(launcher): honor CLI disc before verification 2026-07-25 21:14:09 -07:00
Rick G 2715b7483a gpu: union native-wide host reject with guest draw area (#79)
Preserve wider guest staging and composition regions while extending framebuffer draw bounds for native-wide margins. Regression-tested in 16:9 on Tomba and Mega Man X6 with bundled OpenBIOS.
2026-07-25 19:42:30 -07:00
OpokXeno 0a8f8ac98c widescreen: stretch backdrop X-stores about screen centre in native-wide mode (#78)
Stretch explicitly configured backdrop X-store sites across the native-wide surface while leaving 4:3, FMV, menu, and unconfigured games unchanged.\n\nValidated by the contributor on Xenogears Battle Mountain and regression-tested on Tomba's Watch Tower flower backdrop with bundled OpenBIOS.
2026-07-25 19:15:30 -07:00
Matthew Stanley 4bf868da4f feat(bios): ship OpenBIOS as a runtime dependency 2026-07-25 18:11:57 -07:00
Matthew Stanley a162aa7fb1 fix(interp): scope load-delay values to BIOS-owned code 2026-07-25 17:02:33 -07:00
Matthew Stanley 986d8be94c Merge remote-tracking branch 'origin/master' into integrate/openbios-bundle
# Conflicts:
#	recompiler/src/full_function_emitter.cpp
#	recompiler/src/full_function_emitter.h
#	recompiler/src/main_bios.cpp
#	runtime/runtime.cmake
#	runtime/src/main.cpp
2026-07-25 12:31:05 -07:00