Commit Graph

192 Commits

Author SHA1 Message Date
NyperYuhgard be0f9656a6 Patch 2026-07-18 13:42:59 -05:00
NyperYuhgard 2be617890c Revert "other"
This reverts commit 5a9e256adc.
2026-07-18 13:01:50 -05:00
NyperYuhgard bbe5d89435 more fixes 2026-07-18 11:43:42 -05:00
NyperYuhgard da138849b7 recomp patches 2026-07-18 11:29:17 -05:00
NyperYuhgard 5a9e256adc other 2026-07-18 10:26:43 -05:00
NyperYuhgard 8239a174bf Explicit Names 2026-07-18 09:38:07 -05:00
NyperYuhgard 1bc4e23b09 recompiler separate function 2026-07-18 08:28:46 -05:00
Matthew Stanley 41370a64e4 recompiler: split SCUS_*_full.c into parallel-compilable shards
Emit a shared <stem>_decls.h (runtime extern prologue, static-inline
unaligned helpers, all func + alias-body forward decls) and distribute
function bodies across N ~40k-line <stem>_full_NN.c shards instead of one
monolithic <stem>_full.c. Overlapping-alias host bodies become externally
linked so shard bucketing has no atomicity constraint. runtime.cmake's
GAME_GENERATED_FULL_C is now multi-value (single path still works, so
other games are unaffected until they regen + glob).

Tomba: SCUS_942.36_full.c 41MB single TU -> 36 shards; compile (-O3)
4m35s -> 51s (-j16, ~5.4x). Generated function bytes verified byte-identical
(6245/6245 functions).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 11:54:11 -07:00
Matthew Stanley d2006e02a3 recomp-ui launcher: generalize the RECOMP_LAUNCHER seam for all titles
Replace the Ape Escape literals in the recomp-ui launcher block with
config-driven values so every PSX title can consume the shared seam:
- gi.name/gi.region <- game.toml [game] name + new optional region key,
  falling back to serial-prefix derivation (SCUS/SLUS/LSP -> USA,
  SCES/SLES -> Europe, SCPS/SLPS/SLPM -> Japan; unknown -> no badge)
- gi.num_players <- new optional [game] players key (default 1)
- gi.widescreen_supported <- ws_offered (same source as the RmlUi path)
- Localization parity: language_labels/num_languages from
  [runtime].languages, language_index matched from the resolved language,
  and the chosen language written back to settings on Launch (mirrors
  launcher.cpp's bounds-checked write-back)

config_loader: GameConfig gains region (string) + players (int, default 1),
parsed from [game]; existing configs without the keys are unchanged
(recompiler_patch_test 11/11, defaults probe verified against Ape's toml).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 19:27:22 -07:00
Matthew Stanley 5b7e69b441 Remove the sljit Tier-2 in-process JIT backend
The tier mis-compiled and has been hard-gated off since 2026-06-25; overlay
gaps fall to gcc/tcc shards and the dirty-RAM interpreter, unchanged.

Re-do on master of the removal validated on the stale branch (6da8c02),
reconciled with everything master grew since the fork:

- Delete overlay_sljit.{c,h}, overlay_compile_worker.{c,h}, lib/sljit,
  runtime/tests/sljit_*.c, and the runtime.cmake sources/include-dirs.
- Strip the sljit provider/backend from code_provider.{c,h},
  overlay_backend.{c,h} ("sljit" in overlay_backend/PSX_OVERLAY_BACKEND now
  degrades to auto so stale configs still boot), main.cpp, debug_server.c
  (sljit_status/sljit_async/sljit_try TCP commands), overlay_loader.{c,h}
  (live policy, JIT-on-miss, persisted-shard cache, async worker glue,
  psx_sljit_call/cop2/memx host helpers — reachable only via the removed
  cpu->sljit_helpers table), and cpu_state.h (SLJIT_HLP_* enum + the
  sljit_helpers[] member; CPUState layout change reshards via the cg tag).
- Master-only entanglement resolved before deletion: 28165d6's Einhander WS
  player-X bound emit existed in three paths (gcc code_generator, sljit,
  dirty_ram_interp). The gcc shard link contract now forwards
  psx_ws_player_x_bound (ABI v13, previous commit), so deleting the sljit
  emit path loses no widescreen behavior; ffc6688's game-dispatch block
  inside the dead psx_sljit_call helper goes with it.
- Reword comments that described sljit as a live backend (gpu.{c,h},
  ws_*_detect.h, cosim_state.c, dirty_ram_interp.c, autocompile.h,
  boot_state.h, config_loader.h, compile_overlays.py, and the CPS marker
  comments the recompiler emits).

recompiler psxrecomp-game builds clean; game runtimes rebuilt + boot-verified
separately.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 22:22:38 -07:00
Matthew Stanley 411532bd87 Merge remote-tracking branch 'origin/master' into spike/load-time-zero 2026-07-14 23:09:27 -07:00
Matthew Stanley 2ceaf5abee feat: park projection and perspective correction
Adapted from https://github.com/mstan/psxrecomp/commit/ec889d6e5956fc4f34acfee41d87f30b24123b7f

Co-authored-by: Kareem Olim <kareemolim@gmail.com>
2026-07-14 23:06:38 -07:00
douglasjv 28165d6421 Expand Einhander player bounds for native widescreen 2026-07-14 23:06:05 -07:00
douglasjv 9a8cdb6772 Add typed native-wide textured edge expansion 2026-07-14 23:04:55 -07:00
Matthew Stanley 44b895e331 Merge remote-tracking branch 'origin/master' into spike/load-time-zero 2026-07-14 22:48:36 -07:00
Matthew Stanley 64b084e2a7 load: add opt-in event horizon, warm routes, and audio sink 2026-07-14 22:44:31 -07:00
Matthew Stanley 12934ed2c5 data-shards spike: memoized pure-function replay (capture/verify/replay + cycle-faithful credit)
- runtime/src/data_shards.c + include: read-before-write recorder fed from
  the memory chokepoints; byte-verified replay (kernel-bless pattern);
  recorded-cycle credit in slices through psx_advance_cycles +
  psx_check_interrupts_at; purity poisons (MMIO/DMA/thread-switch/budget);
  .dss persistence under the unified cache dir; TCP data_shards cmd.
- emitter: [data_shards] funcs -> psx_datashard_enter at entry +
  psx_datashard_ret at jr-$ra sites (rolls cg-hash).
- obs: phase_hot set=static keyed on new g_psx_last_fn_entry entry stamp
  (current_func dispatch stamp survives post-IRQ resumption and pooled 55%
  of static samples on kernel 0xF40); TCP starv_ring query for the
  always-on PC-sample ring.
- docs/DATA_SHARDS.md: design, soundness model, gates, FMV exclusion.
2026-07-14 11:08:02 -07:00
Matthew Stanley 098b06e047 Merge remote-tracking branch 'origin/master' into feat/reachable-main-discovery-douglas
# Conflicts:
#	docs/config_schema.md
#	recompiler/CMakeLists.txt
#	recompiler/src/main_psx.cpp
2026-07-14 00:09:56 -07:00
Matt Stanley f7d6bf2149 Merge pull request #22 from mstan/feat/config-guarded-mips-patches-douglas
Add config-driven guarded MIPS patches
2026-07-14 00:05:13 -07:00
Matthew Stanley 5f62dedaa3 fix: inline runtime-visible patch address key
Runtime config parsing uses the physical alias key but does not link the recompiler patch implementation. Keep the dependency-free key in the C++17-compatible header and exercise it in the header smoke test.
2026-07-13 22:36:32 -07:00
Matthew Stanley 2f73f73f92 fix: keep patch config header C++17-compatible
Avoid exposing std::span through config_loader.h, which is consumed by C++17 game runtimes. Add a dedicated C++17 header compile test alongside the guarded-patch suite.
2026-07-13 22:33:02 -07:00
Matthew Stanley e7b61c807c recompiler: add guarded config MIPS patches
Add alias-aware, opcode-verified game-owned instruction replacements before discovery and code generation. Validate duplicate IDs and physical sites, preserve guarded overlay variants, and cover parser and generated-code behavior with CTest.

Co-authored-by: douglasjv <vanderveerdouglas@gmail.com>
2026-07-13 21:59:18 -07:00
Matthew Stanley bd705bfcec Add bounded reachable main-EXE discovery
Adapt Douglas's opt-in reachable discovery onto current exact/static dispatch. Validate configured static-analysis bounds before truncation, preserve the whole-image default and canonical page reservations, and leave unresolved indirect or out-of-bound targets to runtime fallback.

Source: https://github.com/douglasjv/mm8

Source-commit: https://github.com/douglasjv/mm8/commit/8415f3a95458c41c7f48fbe36caaf0ee82730720

Co-authored-by: douglasjv <vanderveerdouglas@gmail.com>
2026-07-13 21:56:43 -07:00
Martin Penkava 05d4f35bd6 build: MSVC portability for runtime and generated code
- psx_cyc.h / psx_cycles.c: _BitScanForward/_BitScanReverse shims for
  __builtin_ctz/__builtin_clz under _MSC_VER
- full_function_emitter.cpp / main_psx.cpp: emit a portable .CRT$XCU
  init-pointer instead of GCC-only __attribute__((constructor)) in
  generated dispatch/game code
- main.cpp: declare cross-language globals extern "C" so MSVC links
  them against their C definitions (no-op for GCC/Clang)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 21:47:40 -07:00
Matthew Stanley b39387eb00 Fix exact native and static overlay dispatch 2026-07-13 05:23:16 -07:00
Matthew Stanley d53742310d release hygiene: no baked build-machine paths, loud malformed-settings warning
Triage of Tomba2Recomp GH issue #1 exposed three ways a release exe
behaves differently on the build machine than on every user machine:

- DEFAULT_BIOS_PATH baked an ABSOLUTE build-tree path into the binary,
  so promoted/release exes silently load the builder's BIOS wherever
  that path exists and the clean-install picker flow is never
  exercised where releases are validated. runtime.cmake now refuses
  absolute values (loud configure warning, converts to the relative
  default); dev checkouts keep prompt-free boots via a new
  resolve_bios_path rung that walks exe-dir ancestors for
  psxrecomp-v4/<relative>, a layout only dev trees have.

- A settings.toml with a TOML syntax error was silently discarded
  wholesale (user's renderer choice, BIOS/disc paths - everything),
  and the next launcher save then overwrote the file with defaults.
  load_user_settings now reports parse_error; the runtime preserves
  the broken file as settings.toml.bad and warns via message box +
  stderr.

- package_release.ps1 gains guards: fail packaging if the staged exe
  contains a drive-letter absolute SCPH1001.BIN path, if the stage
  carries BIOS/disc/save/sidecar files (SCPH*.BIN, *.cue, *.iso,
  *.mcd, bios.cfg, disc.cfg, settings.toml, keybinds.ini,
  overlay_captures.json), or if saves/ is non-empty.

Verified: rebuilt Tomba2 against this tree - configure warning fires
on the absolute arg, strings scan of the exe finds no drive-letter
BIOS path, and a boot with no [bios] setting and no bios.cfg resolves
the BIOS through the psxrecomp-v4 dev rung.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 18:52:37 -07:00
Matthew Stanley 34ca37cc65 Merge feat/opengl-performance: full-rate OpenGL presentation 2026-07-11 14:08:08 -07:00
Matthew Stanley fb585541ec opengl: sustain full-rate gameplay and FMV presentation 2026-07-11 14:07:17 -07:00
Matthew Stanley 8f2389211c Merge feat/kernel-stub-bless: byte-verified static dispatch for the relocated kernel window
Closes the latent Rule-18 soundness hole: kernel-window static dispatch
hits (RAM [0x500,0x8500), the BIOS's boot-time ROM copy) now require the
live RAM bytes of the function's full reachable extent to byte-match the
ROM source (lazy verify, cached, precisely invalidated on writes); patched
bodies divert to the faithful interpreter. Emitter ships
psx_bios_kernel_bodies[] (499 entries); runtime guard in memory.c; TCP
kernel_bless observability; PSX_KERNEL_BLESS=0 A/B switch.

USER-VALIDATED on Tomba (SCUS-94236): multiple play runs, LLE + HLE boots,
pads/menus/events, title 1.00x / village 0.92x parity; 208-214/219 kernel
functions verified clean, the 5 mismatches (runtime-patched pad-driver
family) faithfully interpreted as before.

NOTE: rolls the codegen hash — regen BIOS+game generated C and recompile
overlay shards with a same-tree recompiler on each title's next fw bump
(the overlay loader fail-closes loudly on tag mismatch).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 19:59:20 -07:00
Matthew Stanley 71c2df0f54 kernel-image bless: byte-verified static dispatch for the relocated kernel window
The generated dispatcher ran kernel-window table hits (RAM [0x500,0x8500),
the BIOS's boot-time copy of ROM 0x1FC10000+) natively with NO check that
the live RAM bytes still match the ROM image the functions were compiled
from — unsound for runtime-patched kernel code (the BIOS installs pad/SIO
handlers INSIDE compiled bodies; live diff: 15 clusters, 348 bytes). It
never misfired only because entry points happened to avoid patched keys.

A static kernel hit now requires psx_kernel_bless_dispatchable(): the
emitter emits psx_bios_kernel_bodies[] (key -> full RAM extent of the code
reachable from it; continuations carry their parent's extent, 499 entries),
and the runtime lazily byte-compares each entry's body against the ROM
source, caches the verdict, and invalidates precisely on writes into the
body (store chokepoint, DMA/EXE range marks, savestate restore). Clean ->
guarded native; patched/unverifiable -> the faithful dirty-RAM interpreter,
exactly as Rule 18 prescribes. This implements the runtime half of the
relocation-manifest contract (docs/RELOCATION_MANIFEST_FORMAT.md).

Measured on Tomba (SCUS-94236): 208-214 of 219 verified functions clean
(the 5 mismatches are the genuinely patched pad-driver family, faithfully
interpreted); millions of guarded native hits per boot; title 1.00x,
village 0.92x (parity — kernel keys were already native, now they are
PROVEN native); LLE and HLE boots + gameplay input verified. Kernel-window
interp measures 1.3% of interp burden (dirty_ram_stats), so this is a
soundness fix, not a speedup; the dominant interp cost is overlay-region
coverage (cg-tag hygiene), tracked separately.

Observability: TCP kernel_bless (entries/clean/mismatch/native_hits/
verifies/invalidations), always-on. PSX_KERNEL_BLESS=0 reverts to
unguarded-table behavior for A/B.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 19:12:32 -07:00
Matthew Stanley eefea1295f Merge codex/ape-widescreen-framework: scope curved backdrop projection sites (Ape widescreen) 2026-07-10 16:33:00 -07:00
Matthew Stanley 244474a147 widescreen: scope curved backdrop projection sites 2026-07-10 15:51:07 -07:00
Matthew Stanley e8943945e1 Merge codex/tomba2-whoopee-beach-fix: native-wide flat/phase backdrop gates + FMV silent-hold
Tomba 2 widescreen enablers: [widescreen] nw_flat_backdrop /
nw_phase_backdrop native-wide mirror gates (canonical 4:3 untouched),
[video] fmv_skip_no_xa_hold for silent preloaded-logo auto-skip,
ws_dbg_stretch modes 7/8, fmv_state JSON escaping.

Conflicts (config_loader.h/.cpp, main.cpp) were both-sides-adds vs the
MMX4/5 clear_reveal work - resolved keeping both feature sets.
Compile + boot sanity: Ape build-release rebuilt and boots.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 13:48:56 -07:00
Matthew Stanley 264f00cee5 widescreen: native-wide flat/phase backdrop gates + FMV silent-hold (Tomba 2 Beach Town)
- [widescreen] nw_flat_backdrop: in the native-wide mirror only, stretch
  untextured flat primitives across the wide output (flat-colour sky/water
  backdrops). Canonical 4:3 framebuffer stays byte-for-byte untouched.
- [widescreen] nw_phase_backdrop: stretch textured prims emitted before the
  frame first shaded 3D primitive (authored 2D backdrop phase), isolating
  the sky from the textured 3D foreground. Both runtime-only, off by default,
  title-opted (draw ordering is title-specific).
- [video] fmv_skip_no_xa_hold (4..3600 vblanks): presentation-side
  fast-forward latch after the last silent MDEC decode, so auto-skip covers a
  preloaded logo authored post-decode wait (Whoopee Camp logo). Guest
  timeline unchanged; default stays the generic 4-vblank hysteresis.
- ws_dbg_stretch correlation modes 7 (all prims) / 8 (all flat prims).
- fmv_state: JSON-escape config_path + report fmv_skip_no_xa_hold.

Validated on Tomba 2: Release build, unattended first-attract captures at
4:3 / 16:9 / 21:9, zero unknown dispatches.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 13:45:23 -07:00
Matthew Stanley dbfc124856 Merge master into feat/mmx4-widescreen-fw
Master brought the MMX5 true-wide generalization, which evolved this
branch's earlier X4 work (unified psx_ws_bg2d_* helpers, copied-a1 cull,
sltiu count sites, nw_left_hud_packet arena filter). Resolution keeps
master's evolved implementations and grafts the X4-only pieces on top:

- bg2d count_site accepts signed slti alongside sltiu (master style
  ?1u:0u emission); startx_site accepts subu rd,zero,rt (X4's
  -(scrollX & 15)).
- cull a1 move sites accept both move encodings (addu rD,a1,zero and
  addu rD,zero,a1) with a distinct addu-but-not-move error.
- HUD arena filter: master's nw_left_hud_packet_lo/hi is the single
  mechanism (X4's parallel nw_hud_source_lo/hi dropped); X4's broader
  prim coverage kept — ws_nw_hud_shift_vertices re-anchors polygons,
  lines and dots as rigid composites alongside the rect/sprite sites.
- mono_rect gets both ws_expand_fullscreen_rect and the HUD re-anchor.

Also carried from this branch: binary-search dispatch table and
Release-gated GL frame_perf instrumentation (auto-merged).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 10:52:04 -07:00
Matthew Stanley 2ef067129b dispatch: binary-search table instead of a giant sparse switch
X4 generates ~60K dispatch entries; GCC lowers the sparse switch to a
multi-megabyte linear compare chain at -O0, making Debug builds unusably
slow. Materialize one sorted table shared by psx_dispatch_game_compiled
and psx_game_is_function_entry and look up via O(log N) binary search,
which is optimizer-independent and avoids emitting the case set twice.
CPS resume PCs ride the same records. Behavior-identical.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 10:32:51 -07:00
Matthew Stanley 97ea975580 widescreen: X4-generation 2D hooks — inline-count bg2d variants, copied-a1 cull, HUD source-range filter
Generalizes the Capcom 2D widescreen machinery for the MMX4 engine revision:

- [widescreen.bg2d] count_site accepts the inline slti/sltiu loop compare
  (X4/X5 style) alongside MMX6's li; startx_site accepts subu rd,zero,rt
  (X4's -(scrollX & 15)); inline-count sites route through the generic
  psx_ws_bg2d_* helpers that keep the emitted ring mask and skip MMX6's
  title-specific host-side refill state.
- [widescreen.cull] a1_sites now also accept a move rd,a1 (addu encoding):
  classifiers that copy the caller margin with no delay-slot nop widen the
  copied value instead.
- [widescreen] nw_hud_source_lo/hi: optional GP0 command-source range filter
  for nw_hud_corners, so a pure-2D game re-anchors only its dedicated HUD
  packet arena and never world sprites. 0/0 preserves legacy behavior.
  ws_nw_hud_shift_vertices re-anchors polygon/line prims as one rigid
  composite; mono rect/dot/8x8 sites shift too.

All helpers identity at 4:3; unset config keys are byte-identical.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 10:32:40 -07:00
Matthew Stanley 40b476c4e4 widescreen: finish MMX5 edge handling 2026-07-10 10:07:40 -07:00
Matthew Stanley 57ce271990 Merge branch 'master' into feat/mmx5-widescreen-fw
# Conflicts:
#	recompiler/src/config_loader.cpp
#	recompiler/src/config_loader.h
#	recompiler/src/main_psx.cpp
#	runtime/src/gpu.c
#	runtime/src/main.cpp
2026-07-10 08:52:29 -07:00
Matthew Stanley e4145d7008 Merge feat/crashbash-fw-fixes: GTE lm/sf depth-cue/lighting fix + dispatch shell-window + VBlank pacing
GTE honors per-instruction lm (bit 10) and sf (bit 19) in the depth-cue and
lighting family (INTPL/DPCS/DPCT/DPCL/NCDS/NCDT/CDP/...) with the faithful
hardware formula and always-on GTE observability rings (gte_ring_dump,
gte_intpl_dump, gte_frame_stats, gte_latch_dump). Fixes Crash Bash
menu-character strobe/flicker and in-game flattening (signed INTPL vertex
tweens were clamped to zero by the hardcoded lm=1).

Also: dispatch no longer shadows runtime-relocated game code in the BIOS
shell window (native-ok byte compare routes matching text to the game path);
stale GPUSTAT-poll VBlank over-delivery fix + present pacing tooling.

Cross-title validation (GTE_LM_FIX.md): Crash Bash (fix target), Ape Escape,
Tomba 2, Mega Man X6 - all rebuilt branch-flavor (regen included) and verified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 08:43:38 -07:00
Matthew Stanley e9ca97ad11 feat: finish MMX6 widescreen edge handling 2026-07-10 08:28:43 -07:00
Matthew Stanley 79cdb12eed feat: support MMX6 finite-map widescreen 2026-07-10 01:47:29 -07:00
Matthew Stanley d9dae48c8e widescreen: generalize Capcom 2D background hooks for MMX5 2026-07-10 00:57:03 -07:00
Matthew Stanley 3d05c9e98b fix(dispatch): don't shadow runtime-relocated game code in the BIOS shell window
Boots Crash Bash (SCUS-94570) past its frame-~144 hang into the attract loop.
Root cause: the Class-A shell-window fix (normalize() maps RAM 0x30000-0x5AFFF ->
shell ROM) collides with games whose code lives in that window, and Crash Bash
RELOCATES a code page onto 0x30000 at runtime. Three interacting gaps sent that
real game code to dead shell ROM -> unknown-dispatch abort:

1. fntrace.c — game_started never latched: it only tripped on a dispatch to
   entry_pc (0x2E7B0), but Crash Bash reaches entry via compiled internal flow,
   so the latch never armed and the shell-window shadow stayed active. Now also
   latches on the first dispatch to native-ok game text (safe pre-load: that RAM
   still holds shell bytes that differ from the game image).

2. dirty_ram_interp.c — THE decisive fix. When a game-text address diverged from
   the static EXE image (native_ok=0, i.e. runtime-relocated/overlaid code) but
   was not "dirty", dirty_ram_dispatch_inner bailed (return 0) and the caller
   shadowed it to shell ROM. Now a diverged game-text address is marked a clean
   game-text miss so the dirty interpreter executes the live RAM bytes.

3. full_function_emitter.cpp (BIOS dispatch driver) — also route native-ok
   game-text shell-window addresses to the game path regardless of the latch.
   Likely redundant now that (1) latches correctly; flagged to slim during the
   final cross-game validation.

NOT merged/validated against other titles yet (MMX6/Tomba2) — per plan that
happens after Crash is fully running. Verified: Crash Bash runs headless to
6000+ frames and windowed with no dispatch abort; the vblank fix delivers 60/s.
Known remaining issue: character flicker at the game-type menu (Bart's original
report) — under investigation, unrelated to this dispatch fix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 18:47:38 -07:00
NyperYuhgard fe95491ab1 PSXRecomp-Toml Tool 2026-07-09 14:43:05 -05:00
Matthew Stanley 850140835a codegen: PSX_EMIT_PROD default ON — collapse data-as-code funcs to loud stubs
The experiment flag is now the default. A "function" that is >=50%
untranslatable (TODO-opcode) words is a data region discovery mistook for
code (primary-opcode-only validity check); emit it as the compact,
fail-closed psx_unknown_dispatch data stub instead of ~hundreds of silent
/* TODO */ no-op lines. Strictly MORE faithful than the baseline (loud
abort-if-dispatched vs silent no-op), and slashes emission: Tomba
259->42MB, exe 59->24MB, -O2 ~25min->~2.5min.

Smoke-validated by full launch of Tomba (SCUS-94236), Tomba2 (SCUS-94454)
and Ape Escape (SCUS-94423) regenerated with the flag on — all boot and
play, no unknown-dispatch fatal (=> no reachable function misclassified).
Set PSX_EMIT_PROD=0 to restore the full-scan (oracle) emission. Proper
productionization moves the judgment upstream into function_analysis.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 16:35:00 -07:00
Matthew Stanley 43820876e4 experiment(codegen): PSX_EMIT_PROD — collapse data-as-code funcs to fail-closed stubs
Discovery's validity check (function_analysis valid_primary_p3) only checks the
PRIMARY opcode, so data words with a valid primary opcode but a garbage
sub-field (e.g. fake-REGIMM 0x01 with rt=0x0E) slip through as "code". The
generator then can't translate the bogus (opcode, subfield) combo and emits a
silent /* TODO: opcode */ no-op. Nothing is currently emitted as is_data_section
for the games, so these ride as code — Tomba 1's 0x29000..0x88000 data region
becomes ~348K TODO lines / 259MB / ~25min -O2 compile.

This env-flagged (PSX_EMIT_PROD) downstream pass re-emits any function whose
body is >=50% untranslatable (TODO) words as the existing compact, fail-closed
psx_unknown_dispatch data stub — using the generator's OWN judgment of what it
can translate rather than duplicating the implemented-instruction set. Default
OFF => byte-identical to the full-scan baseline (the complete/oracle emission
stays intact).

Measured on Tomba 1 (SCUS-94454), validated by full playthrough (plays great,
no unknown-dispatch fatal => no reachable function misclassified):
  generated full.c   259.1 MB -> 39.7 MB   (348K TODO -> 1026)
  game full.c -O2     ~25 min  -> 156 s     (~10x)
  runtime exe          59.3 MB -> 26.7 MB

EXPERIMENT ONLY. Proper productionization moves this judgment UPSTREAM into
discovery (sub-field-aware validity in function_analysis), fixing it for every
title at discovery time without a post-hoc generate-then-discard pass, and turns
the env var into a real config option. Also apply/measure on Tsumu (261MB) and
MMX4 (215MB).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 16:34:59 -07:00
Matthew Stanley 9ed48831b7 launcher: [controller] lock_device — hide the Player controller cards entirely
For a title whose controller type is fixed and auto-bound (e.g. Ape Escape =
DualShock analog), exposing a device/mode picker is pointless. New per-game
[controller] lock_device flag hides the Player 1/2 cards in the launcher
entirely (distinct from lock_mode, which only hides the pad-mode segment but
keeps the device dropdown). Plumbed config_loader -> RuntimeConfig ->
GameInfo.lock_device -> launcher model `device_locked` -> rml
`data-if="device_locked == false"` on the players cards-row. Default false, so
every other game is unchanged. The runtime still auto-binds whatever pad/keyboard
is present and presents the game's declared pad type.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 19:30:12 -07:00
Matthew Stanley ee09ab9bbb widescreen: generic Ape-Escape-class support + native-wide GL perf + cutscene flicker fix
Adds full 16:9/21:9 native-wide support for fully-3D titles (Ape Escape,
SCUS-94423) as a generic, opt-in, 4:3-byte-identical framework capability, plus
a native-wide GL compositor perf fix and a cutscene present-mode flicker fix.

Widescreen (generic, per-game opt-in via [widescreen*]):
- Shared screen-extent cull detector (runtime/include/ws_cull_detect.h) used by
  all three backends (recompiler, dirty-RAM interp, sljit). Per-game signature
  immediates ([widescreen.cull] screen_w_imms/screen_h_imms) — Ape's funnel
  tests 0x181/0xF1 on its 368px display, not Tomba's 0x140/0xE0.
- Three funnel idioms widened: unsigned per-vertex sltiu (psx_ws_cull_sltiu),
  signed min/max slti right edge + bare-bltz left edge (psx_ws_cull_slti/bltz,
  new helpers + SLJIT_HLP appends), and billboard center+/-halfwidth. Explicit
  [widescreen.cull] slti_sites for X-only funnels the auto-detector can't
  qualify.
- gte_game_mode: GTE-activity gameplay detector for 3D titles with no sprite-tag
  helper (gte.cpp notes every RTPS/RTPT). STICKY (>=3 verts, 45-frame hysteresis)
  so sparse cutscene frames never flip to a 4:3 pillarbox = fixes intro flicker.
- nw_hud_corners: push outer-third screen-space HUD sprites to the true wide
  corners in native-wide (else inset by the reveal).
- nw_backdrop: stretch a full-frame axis-aligned 2D backdrop quad to fill the
  wide frame (for titles with a flat sky plane).
- Pattern-scanned interp/sljit widen hooks now gated per-game (auto_screen_x /
  auto_backdrop): fixes an ungated auto_backdrop false-positive that rewrote a
  live GPR = the ~24s native-wide crash on Ape.

Native-wide GL perf (fixes 16:9 frame drops):
- The wide surface centre equals the canonical 4:3 framebuffer, so wide_blit_center
  copies canonical->wide-centre at present (both present paths) and the per-prim
  mirror SKIPS prims fully inside the 4:3 frame (mirror_x/geo/batch_center_only).
  Only reveal-margin prims re-rasterize. Peak frame time 38.8ms -> 17.5ms, no
  vsync misses. Toggle gl_wide_fast; 4:3 untouched (all gated on g_wide_cur).

Runtime-only except the recompiler cull emit (regen needed for cull widening).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 19:30:09 -07:00
Matthew Stanley 5abc5f0dca launcher/runtime: per-game [widescreen] offer gate for the Widescreen toggle
A title whose widescreen is unported/unvalidated (MMX4 at bring-up) had no
way to hide the launcher's EXPERIMENTAL Widescreen toggle — ws_eligible was
hardcoded true. Add game.toml [widescreen] offer (default true, runtime-only,
no regen):

- offer=false hides the launcher's Widescreen row and resets a stale
  persisted 16:9 aspect back to 4:3 at launcher-model init;
- the runtime also clamps the display aspect to 4:3 after all config
  sources (same completeness treatment as the lock_mode clamp), covering
  launcher-less builds and hand-edited settings.toml;
- refresh_labels() no longer stomps ws_eligible every refresh — it is set
  once from GameInfo.ws_offered at model init.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 19:30:05 -07:00