Commit Graph

1113 Commits

Author SHA1 Message Date
Matthew Stanley cd87fe403d docs: retract G1.5 — both titles crack; partial coverage is not shippable
User verified seams on Ape Escape AND Tomba 2 with the exact-table plus
ambiguity-gate build. G1.5 claimed the gate fixed the cracking; it did not, and
G1.4's original conclusion stands.

Both wrong turns came from concluding on a single observation rather than a
controlled A/B: first from native captures that structurally could not show the
defect, then from one in-game frame where the corrected ~5% happened not to
border a visible silhouette.

The gate did remove vertices inheriting a neighbour's fraction, but ~5% coverage
still mixes corrected and uncorrected triangles inside a mesh and those seams
are visible. The crack is a property of the boundary, not of the error
magnitude, so no coverage ratio short of near-total is shippable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 16:02:18 -07:00
Matthew Stanley 9217ae203a feat(video): expose geometry precision through the launcher
Wires the two [video] settings into the recomp-ui Display page: seeds ls.* from
settings.toml, writes the player's choice back, and sets the new
has_geometry_precision capability. Geometry precision is a property of the PS1
pipeline rather than of any particular disc, so every PSX title exposes it.

Pairs with recomp-ui feat/psx-geometry-precision.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 15:48:08 -07:00
Matthew Stanley c630b5e2fc docs: correct G1.4 — the ambiguity gate fixed the cracking; my instrument was blind
G1.4 claimed the meshes still cracked after the exact-table + ambiguity-gate
change and called it visually confirmed. That was wrong and unverified: the
user reports the same scene now clean at window resolution.

The verification was done with the TCP screenshot, which resolves native 15-bit
VRAM — and geometry correction exists only in the supersampled mirror, so a
native capture erases it and reports a clean frame regardless. The conclusion
then leaned on counters. screenshot_hires now closes that gap.

Technically this reframes the defect: ambiguity was the harm (a wrong fraction
displaces a vertex by up to a whole pixel in an arbitrary direction), while
missing coverage only leaves sub-pixel mismatches at shared edges. So coverage
now bounds the benefit rather than causing damage, and full value propagation is
an improvement path rather than a prerequisite.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 15:38:51 -07:00
Matthew Stanley af6dff5132 feat(debug): screenshot_hires — capture the surface the player actually sees
screenshot/screenshot_file read native 15-bit VRAM via gpu_display_pixel_rgb.
That is correct for faithfulness work but BLIND to any enhancement that only
exists in the supersampled mirror: at supersampling >= 2 the geometry-correction
sub-pixel vertices, SSAA edges and perspective UVs are resolved in the hi-res
surface and gone once pixels are packed back to native.

This bit hard. Native captures of Ape Escape looked clean while the user was
looking at a visibly cracked frame, so a real regression got reported as fixed
and the argument moved to counters. An instrument that cannot show the defect
is worse than no instrument.

screenshot_hires routes gr_render_display_hires — the same present path the
window uses — and falls back to the native resolve (reporting scale 1) when
there is no hi-res surface, so it always answers truthfully about real output.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 15:36:27 -07:00
Matthew Stanley 3fbb9effa0 docs(enhancements): measure the exact table — 93% of lookups are ambiguous
Tried the cheap fix and measured it rather than arguing it. With the references'
exact direct-indexed table and ambiguity gate, Ape Escape attract gives 5.2%
hits, 1.7% never-recorded, and 93.1% AMBIGUOUS — several distinct projections
rounded onto the same pixel.

So the tracking is reaching the vertices; the rounded screen position is simply
not a unique key, and that share is irreducible for any position-keyed scheme.
It also explains the severity of the first attempt: without the gate those 93%
were answered with another vertex's fraction rather than skipped.

Rules out both the bigger-cache and coverage-gate options by measurement. Only
precision travelling with the data through the CPU dataflow gives a clean
result.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 15:32:14 -07:00
Matthew Stanley b35892fc16 fix(gte): exact direct-indexed vertex table + ambiguity gate, with a miss census
The geometry side cache was an 8192-entry HASHED table with no ambiguity check.
Unrelated screen positions shared a slot, so a vertex could be handed a
different vertex's sub-pixel fraction, and eviction changed which triangles got
corrected from frame to frame — moving seams across every mesh.

Both references index this table exactly, one slot per reachable SXY
(beetle-psx vertexCache[0x800*2][0x800*2]; DuckStation 2048x2048), and gate it
on an ambiguity flag so a pixel that two DIFFERENT projections rounded to is
never used. Do the same: direct index, first writer wins, flag on a conflicting
value, allocate lazily on enable so the faithful default costs nothing, and
fail closed to the faithful path if the allocation fails.

Adds a lookup census (attempted / hit / miss_unrecorded / miss_ambiguous) on
geom_correction. With an exact table a miss_unrecorded is a genuine tracking
coverage gap rather than a cache artifact, which is what distinguishes 'the
cache was lossy' from 'the vertex path never reaches us in a matchable form'.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 15:18:29 -07:00
Matthew Stanley 4d1e22c5ad docs(enhancements): root-cause the geometry-correction regression against the reference PGXP implementations
Ape Escape A/B showed moving seams across meshes. Measured with the new
geom_correction counter: under 10% of triangles get sub-pixel positions, and
correction is all-or-nothing per triangle, so every corrected/uncorrected
neighbour pair is a seam — and because the cache is keyed on the ROUNDED
position it changes winners frame to frame, hence the jitter.

Read both vendored references (beetle-psx/pgxp, duckstation cpu_pgxp.cpp).
They shadow the whole dataflow — a value per RAM/scratchpad word plus per-GPR
and per-GTE-register shadows — and propagate it through 47 instruction classes
with a Validate() that drops stale precision. Their value-keyed vertex cache is
only a last-resort fallback, and even that is fully direct-indexed (no hash
collisions), ambiguity-gated, and perspective-disabled.

What is parked here is only that fallback, degraded to an 8192-entry hashed
table with no ambiguity check and no primary path — so a vertex can inherit a
different vertex's fraction. Records the port cost, including the point that
matters most here: these hooks are emitted C on the hot path, so they must be
gated at codegen time rather than runtime.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 15:10:19 -07:00
Matthew Stanley 5a64a98440 feat(debug): geom_correction TCP command — is the correction engaging?
Both [video] enhancements are silent no-ops on anything they cannot prove is
projected geometry: a vertex whose sub-pixel fraction was never cached, or a
packet whose position words lack full GTE projection provenance, just draws the
faithful way. So the enable flag alone says nothing about whether a given title
benefits, and the existing hit counters had no reader.

geom_correction reports the flag plus the free-running geometry_vertex_hits and
perspective_triangles totals, so per-title bring-up can tell an engaged
correction from an inert one before anyone argues about screenshots. Sample
twice and diff for a per-window rate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 14:42:37 -07:00
Matthew Stanley 2bdaff3244 fix(gl): floor/ceil the wide-mirror centre-only test for sub-pixel vertices
The native-wide centre-only fast path read batch x extents with a truncating
(int) cast. With geometry_correction those are fractional, and truncation
rounds a negative x TOWARD the centre — so a batch just touching the left
margin could be misclassified as fully inside the 4:3 frame and have its
wide-mirror draw skipped, leaving a one-pixel sliver unmirrored. Take floor
for the low edge and ceil for the high edge instead; whole-valued positions
(the faithful path, and every prim with the feature off) are unaffected.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 14:04:56 -07: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 7f7fbc8e1a feat(mods): expose linked package attribution 2026-08-05 11:17:30 -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 e629d622fa dma: implement channel 5 (PIO / expansion port) transfers
Salvaged from PR #13 (feat/launcher-stb-revamp, commit 2ba52e97) by
NyperYuhgard. Master fatal-halts on any DMA start for channel 5; this
moves words to/from RAM directly (device side unemulated: RAM-to-device
reads-and-discards, device-to-RAM zero-fills) and completes the
transfer with the normal IRQ path.

Note: zero-filling from an unemulated expansion device is weaker than
the fail-closed psx_fatal_halt default the other channels follow; kept
as submitted because the contributor exercised it on a real title.
Trimmed from the original hunk: unused DMA_PIO_CYCLES_PER_WORD macro
and mdec_finish_async_{in,out}_transfer wrappers nothing references.

Co-Authored-By: NyperYuhgard <noreply@github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 10:55:00 -07:00
NyperYuhgard 95669105de interp: deliver alignment exceptions, protect Cause read-only bits, add CFC0
Salvaged from PR #13 (feat/launcher-stb-revamp, commit 9fd2876c) by
NyperYuhgard. Adds to the dirty-RAM interpreter:

- LoadAddressError/StoreAddressError delivery for misaligned LH/LW/LHU/
  SH/SW and misaligned JR/JALR targets, via a new interp_exception()
  that performs the architectural COP0 sequence (BadVAddr, Cause ExcCode,
  SR mode-stack push, EPC, BEV-selected vector).
- COP0 Cause write protection on MTC0/CTC0.
- CFC0/CTC0 aliases (identical to MFC0/MTC0 on R3000A).

Two deviations from the original:
- The original masked Cause writes to bits [15:10] (backwards vs
  hardware); corrected to the writable software-interrupt bits [9:8]
  per psx-spx / PCSX-Redux, which also un-deadens the psxTestSWInts
  recheck below it.
- The original's post-RFE immediate psx_check_interrupts recheck is
  dropped: master already delivers post-RFE interrupts through
  psx_rfe_mark_escape() and re-checking inside the handler window is
  the documented dbg-build boot-wedge livelock.

Co-Authored-By: NyperYuhgard <noreply@github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 10:55:00 -07:00
Matthew Stanley 084d2d4639 mods: clear the staged catalog before restaging it
copy_directory merges, so a mod package deleted from source survived in the
build output indefinitely -- it kept showing on the Mods page and inflated
the release packagers' catalog assertions (Tomba 2 found 7 manifests where 5
exist). Remove the staged tree first; this runs before the game's own
POST_BUILD copy, so game and framework catalogs both land on a clean slate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 10:48:09 -07:00
Matthew Stanley 25d2798037 mods: ship loading-speed mods with the framework, for every game
Loading acceleration is a property of the emulated hardware, not of any
particular disc, so having each title carry its own copy of the same two
manifests and plugins was duplication waiting to drift.

- target game_id "*" now matches every game. An empty target list still
  matches nothing, so a malformed manifest fails loudly as before.
- mods/builtin/packages ships psx.enhancement.fast-loading and
  psx.enhancement.cd-speed: independent host-pacing and CD-timing mods,
  each a free integer multiplier (1..1024) plus a tickbox that uses
  disabled_by to grey out the field it overrides.
- runtime/src/mod_builtin_speed.c registers both activation plugins.
- runtime.cmake stages mods/builtin into every game's output beside its own
  catalog, before the game's own copy, so a title can still override an id.

Titles adopting these should delete their per-game copies; keeping both
would show two of each mod.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 10:40:07 -07:00
Matthew Stanley f44f56bfdc mods: let games expose loading speed as a free integer, plus disabled_by
Players asked for CD speeds beyond the curated 2x/4x list and for the two
loading accelerators to stop being one control (GH TombaRecomp#5: a
speedrunner wants shorter loads but NOT the host speed-up, which runs past
the loading screen and breaks a skip).

Three changes, all general:

- psx_mod_set_disc_speed accepted only divisor 2 or 4. That was policy,
  not safety: cdrom.c divides the sector delay and floors the result at
  CDROM_MIN_DELAY, and apply_speed leaves XA streaming at authentic
  timing, so no positive divisor can produce a zero-delay storm or
  pitch-shift FMV audio. Accept 1..PSX_MOD_DISC_SPEED_MAX and let the
  mod's description carry the risk warning.

- psx_mod_set_load_acceleration accepted 2..16. Host pacing cannot desync
  the guest at all (every frame, CD deadline, interrupt and callback still
  happens), so the ceiling was arbitrary. Accept 1..PSX_MOD_LOAD_ACCEL_MAX,
  with 1 meaning authentic and 0 still meaning uncapped.

- New option key disabled_by: an option names a BOOLEAN sibling that
  overrides it, so "tick Instant and the speed box stops mattering" needs
  no second widget type. The parser rejects a dangling, self-referential
  or non-boolean reference rather than leaving a control silently always
  enabled, and the provider resolves the link against the live selection
  so the launcher and the plugins can never disagree about whether a
  control counts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-04 23:55:25 -07:00
Matt Stanley 59244b228c Merge pull request #101 from mstan/codex/steam-car-disc-images
runtime: accept Steam .car disc images
2026-08-04 19:33:26 -07:00
Matthew Stanley 5abdb7d0a1 runtime: accept Steam .car disc images 2026-08-04 19:32:16 -07:00
Matthew Stanley 1bc84f38c6 mods: support save-safe damage override and deadzone rounding 2026-08-04 18:50:31 -07:00
Matthew Stanley 1dcab6a2ff Merge remote-tracking branch 'origin/master' into codex/debug-input-route-20260803 2026-08-03 23:31:59 -07:00
Matthew Stanley 3e89dbc6c2 widescreen: support MMX4 background refill layout 2026-08-03 23:31:52 -07:00
Matthew Stanley 33c96c567d debug: capture presented widescreen surface in screenshot 2026-08-03 23:00:44 -07:00
Matt Stanley 854a658372 Merge pull request #100 from mstan/codex/tomba-v011-framework
feat(runtime): CHD support and mod-owned loading modes
2026-08-03 22:46:09 -07:00
Matthew Stanley 67757efac4 feat(runtime): add CHD discs and mod-owned loading modes 2026-08-03 22:32:17 -07:00
Matthew Stanley ceb4919bb2 debug: add exact VBlank input route queue 2026-08-03 22:24:44 -07:00
Matthew Stanley 5959ef2fdd feat(tools): shared macOS release packager for game repos
tools/package_release.ps1 packages this framework's BIOS-only runtime, and
each game repo carries its own Windows packager. There was no macOS
equivalent at either level, so the first macOS release (Crash Bandicoot) was
assembled by hand and TombaRecomp already carries a private copy of most of
this logic. Add the generic one here so titles configure rather than
duplicate it.

Takes an already-built runtime plus the per-game identity and produces a
signed, relocatable .app in a staged release folder, archived as
<package>-<version>-macos-<arch>.zip with a .sha256 sidecar — the naming the
game repos' Windows releases already use. It does not build; the game's
build script builds, then calls this.

Release gates, porting the intent of the Windows packager to macOS:
- self-containment via otool (only OS libraries or bundled Frameworks)
- no baked absolute BIOS path, and no build-machine home path. The Windows
  gate keys on a drive letter; the macOS tell is a path rooted under
  /Users, /Volumes and friends. Matching bare "/...SCPH*.BIN" instead would
  flag both the correct relative default "bios/SCPH1001.BIN" and the usage
  string "/path/to/SCPH1001.BIN" in every binary.
- the 512 KiB OpenBIOS image and its MIT notice are present
- every --require-mod package is present, so a title cannot ship a launcher
  whose Mods page silently vanished
- no disc / retail BIOS / memory-card / generated / local-state files
- saves/ ships empty
- the .app carries a valid signature

The mod catalog is taken from the repo's reviewed source, never the build
tree: a developer build dir accumulates mods/state.toml with enhancements
switched on, which would silently flip a title's default presentation for
every player. Packaging from a build tree without --mods-src is refused.

Bundle layout: staged data lives in Contents/Resources with symlinks from
Contents/MacOS. The runtime resolves bios/, assets/ and mods/ beside the
real executable, but codesign treats anything non-executable under
Contents/MacOS as nested code and rejects the whole bundle —
mods/packages/<pkg>/<version>/ parses as a versioned bundle. codesign seals
a symlink without descending, so this signs cleanly and path resolution is
unchanged. Signing is deliberately not --deep for the same reason.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 18:19:34 -07:00
Matthew Stanley bc6b277c94 feat(mods): add GPU DMA enhancement memory 2026-08-03 15:55:47 -07:00
Matthew Stanley b2af4e89c9 feat(mods): add trusted game enhancement hooks 2026-08-03 15:17:39 -07:00
Matthew Stanley 0cfa9fe0a8 runtime: add PaRappa timing debug controls 2026-08-01 16:11:11 -07:00
Matt Stanley 295262e25e Merge pull request #91 from mstan/codex/generic-startup-wtrace-20260801
Generalize the Crash Bash boot write watch and fix SDL3 MinGW entry-point ownership.
2026-08-01 10:45:53 -07: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
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
Matt Stanley 9aa748bb6b Merge pull request #89 from fabioap-cpu/master
Add condition to prevent CDDA playback restart
2026-07-31 18:28:09 -07:00
Matt Stanley d9eb0f02d3 Merge pull request #85 from luisg0c/test/register-orphaned-cxx-tests
test(recompiler): register l2_structural_test and reachable_discovery_test
2026-07-31 15:45:48 -07: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
Matt Stanley cb0c00f397 Merge pull request #86 from luisg0c/fix/persist-dir-host-independent-path-check
fix(config): validate overlay_capture_persist_dir independent of host path grammar
2026-07-31 15:40:21 -07:00
Matt Stanley ba37110ee3 Merge pull request #90 from mstan/codex/fix-pr87-regressions-20260731
fix: revert destructive PR #87 runtime merge
2026-07-31 15:39:06 -07:00
Matthew Stanley 987c6eeced Revert "Merge pull request #87 from mstan/feat/ui-5p"
This reverts commit e01347cbca, reversing
changes made to 60cb60eee6.
2026-07-31 15:37:57 -07:00
Fábio AP 1348c118f9 Add condition to prevent CDDA playback restart
This fix is ​​due to games like Tekken 1, which contains multiple discs (multiple .bin files). The problem was that the current code caused the music to repeat several times without counting each second and never allowed the music to continue, both in menus and during gameplay, and also when we paused the game, this repetition continued and did not stop...

(I would appreciate it if you could review and analyze the code. My intention is to keep it updated and improve it over time.)

This is my current possible fix:

`cdda_playing` -> "Is the music already playing?" If the game sends a "Play" command, but the music is paused, we allow the command to pass normally so that the music starts.

`requested_track == 0` -> "Does the game want to play the same track?" When Tekken 1 enters "spam" mode, it sends the pure "Play" command (0x03), without specifying a new track (which in the engine code translates to `requested_track = 0`). If you request track 4, we will allow the command to pass. Since it asks for "0", we know it's just redundancy for a song that's already playing.

`iso_handle` -> "Is there a CD inserted?" This ensures the engine doesn't try to check for phantom tracks and won't crash if there's no .cue file loaded. `iso_track_count(iso_handle) > 1` -> "Does the CD have audio tracks?" The PlayStation game format dictates that Track 1 always contains the game data. If the CD has more than one track, it means it has audio tracks (CDDA).
2026-07-31 16:07:43 +01:00
Matthew Stanley c03fcf4746 docs: add mod authoring guide 2026-07-30 14:54:34 -07:00
Matthew Stanley fc23d497de Merge branch 'codex/remove-engine-recomp-ui' 2026-07-30 13:36:18 -07:00
Matthew Stanley 18ba9dcf1e build: remove recomp-ui from engine tree 2026-07-30 13:35:14 -07:00
Alex Vanderveen c5b64dc75d bump recomp-net back to main 2026-07-29 22:11:48 -04:00
Alex Vanderveen 1b3bd66eca rollback checklist doc 2026-07-29 22:11:05 -04:00
Alex Vanderveen 11de0f2b95 bump recomp-net, REMOVE recomp-ui. 2026-07-29 22:10:30 -04:00
Matthew Stanley eaa4062b78 fix: pin launcher boot timing implementation 2026-07-29 00:42:55 -07:00
Alex Vanderveen bb7240261d sdf 2026-07-29 03:27:25 -04:00
Alex Vanderveen 3da61df355 Revert "ok"
This reverts commit b836f2198c.
2026-07-29 03:18:10 -04:00
Alex Vanderveen b836f2198c ok 2026-07-29 03:15:42 -04:00