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>
`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>
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>
it stops checking the entire PSX disc for full hash check every time the launcher runs, assuming the user's hash checked it when selecting the disc the first time and saving it to settings, so it just validates the file name and size instead, then it shares lifecycle with the launcher and the game to load the game faster, and several optimizations were made to loadstate paths which I think in the end relied on reanchoring host timings to the restored clock that came with the state