Re-add watchdog/PC-sample fire wrappers and overlay icache_fetch_fn;
stop shadowing the inlined psx_advance_cycles with a missing extern.
Co-authored-by: Cursor <cursoragent@cursor.com>
Re-add watchdog/PC-sample fire wrappers and overlay icache_fetch_fn;
pull inlined psx_advance_cycles via psx_cycles.h.
Co-authored-by: Cursor <cursoragent@cursor.com>
Export service_to_now, rename advance to *_slow for the header inline,
and give g_audio_host_rate C linkage.
Co-authored-by: Cursor <cursoragent@cursor.com>
Rename out-of-line load helpers to *_slow to match psx_cyc.h inlines,
declare psx_icache_fetch/reset, and wire overlay callbacks to slow paths.
Co-authored-by: Cursor <cursoragent@cursor.com>
Jackie Chan Stuntmaster (SLUS-00684) hard-blackscreens after the intro
logos: the game's exception dispatcher is re-entrant by design. Its
stage-1 handler saves SR/EPC to a single save slot, then executes
mtc0 CAUSE,0x100 + mtc0 SR,0x101 and relies on the resulting COP0
SOFTWARE interrupt (CAUSE.IP0 & SR.IM0 & IEc) to vector into its
stage-2, which acks the CD INT at the controller, delivers events, and
restores the saved SR. The runtime only ever considered the INTC line
(i_stat & i_mask) gated by SR.IM2, so the sw-int was never taken:
stage-2 never ran, CD INT3 stayed unacked (process_pending freezes the
completion countdown while irq_flag != 0), and the machine deadlocked
with the display disabled and SR parked at 0x101 (IM2 stripped -> all
hardware interrupts dead).
Three changes, all architectural (no per-game logic):
1. interrupts.c psx_check_interrupts(): a pending software interrupt
(CAUSE & SR & 0x0300, plus IEc) is now a deliverable source. The
fast path, the pending check, and the SR gate each consider it; the
INTC path still requires IM2, the sw path only its own IM bit.
Exception entry sets CAUSE.IP2 only when the hardware line is what
is being delivered, so a pure sw-int presents the guest-written
IP0/IP1 bits unmodified (the dispatcher discriminates its stages by
exactly these bits).
2. interrupts.c: save/restore exception_jmpbuf across delivery. The
sw-int nests inside the hardware-interrupt handler window; the
nested setjmp used to overwrite the single global jmpbuf, so the
OUTER handler's later RFE longjmp'd into the exited inner frame
(host stack corruption, SIGSEGV).
3. dirty_ram_interp.c: deliver immediately after an interpreted MTC0
to CAUSE or SR that makes a sw-int deliverable, with EPC = the
committed next pc. Hardware vectors within the next instruction;
waiting for the next block boundary opened a window in which a
second hardware IRQ re-entered the (legitimately non-reentrant)
guest dispatcher and destroyed its saved SR. precise_irq_deliverable
gains the same sw-pending condition.
Verified on SLUS-00684: boots through BIOS/logos/FMV into rendered
3D gameplay at 60 fps, SR observed at the canonical 0x40000401, CD
irq_flag acked, MDEC decoding. BIOS-only boot unaffected.
Known scope limit: compiled (static) MTC0 sites do not yet trigger the
immediate check; the raising writes observed in the wild live in the
BIOS-installed, dirty-RAM-interpreted trampoline, which this covers.
Remove the in-tree launcher implementation and its submodules now that game projects use recomp-ui for launcher support.
Keep Vulkan hidden from the launcher unless a game explicitly sets [video] offer_vulkan = true, and clamp stale Vulkan settings back to OpenGL when it is not offered.
Co-authored-by: Martin Penkava <mpenkava1337@gmail.com>
Cycle the renderer selector through Software, OpenGL, and Vulkan while retaining OpenGL-only option gating.
Co-authored-by: Martin Penkava <mpenkava1337@gmail.com>
Record queue-wait, acquire, and present durations plus presentation timestamps in the existing vk_perf ring.
Co-authored-by: Martin Penkava <mpenkava1337@gmail.com>
Let the frontend remain the sole frame pacer by requesting MAILBOX for tear-free delivery, with FIFO retained as the required fallback.
Co-authored-by: Martin Penkava <mpenkava1337@gmail.com>
Keep a shared work command buffer open across logical GPU operations and submit it at the existing synchronization boundary.
Co-authored-by: Martin Penkava <mpenkava1337@gmail.com>
Add same-layout color attachment barriers before geometry and wide-surface render passes so prior writes are visible to LOAD and blend operations.
Co-authored-by: Martin Penkava <mpenkava1337@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Include the transfer stage in the swapchain acquire wait mask because the present command buffer clears and blits the acquired image with transfer operations.
Co-authored-by: Martin Penkava <mpenkava1337@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Pad each packed R16 upload region to an even texel count so subsequent VkBufferImageCopy offsets retain the required four-byte alignment.
Co-authored-by: Martin Penkava <mpenkava1337@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Add a small generic frame-hook surface for statically linked mod code. Mods can
register C callbacks with mod_register_frame_hook(); the runtime invokes them
after normal input sampling and before presentation/widescreen frame work.
Expose the SDL window symbol with C linkage so linked mod code can integrate
with SDL APIs such as window grab control.
Add opt-in [widescreen.cull] xclip_load_sites: a configured `lw rt,off(rs)`
loading a per-primitive X-reject bound (sltu-compared against ANDI-masked
u16 screen X) routes through psx_ws_xclip_bound() - INT32_MAX while the
margins are revealed (reject disabled; the wide-surface scissor clips the
overflow, wrapped off-left u16 coords pass), vanilla value at 4:3. Matched
native codegen emit and interpreter hook; overlay ABI v18 forwarder (NULL
preserves the vanilla loaded value); codegen ver 8. Parser, codegen and
overlay-mismatch regression coverage.
Split from #49: replaces the xclip_globals RAM poke with a recompile-time
instruction transform so native shards and the interpreter behave identically.
Add opt-in [widescreen.cull] plane_nx_sites: a configured `lw rt,off(rs)`
loading the X component of a side frustum-plane normal (sign-tested per
corner, dot = nx*px + nz*pz) routes through psx_ws_plane_nx() — scaled by
the inverse aspect factor (4*den)/(3*num) while the margins are revealed,
widening the plane cone by exactly atan((3*num)/(4*den)*tan(theta));
identity at 4:3. Matched native codegen emit and interpreter hook; overlay
ABI v17 forwarder (NULL preserves the vanilla normal); codegen ver 7.
Parser, codegen and overlay-mismatch regression coverage.
Split from #49: replaces the plane sign-test RAM pokes with a
recompile-time instruction transform so native shards and the interpreter
behave identically.
Reconstruct the shareable pieces from PR #58 onto current master: add contiguous MDEC DMA input bursts, reduce per-pixel/per-byte MDEC output overhead, add sparse IDCT fast paths, and keep the MDEC activity stamp sane across rematches.
Also quiet the heavy debug trace recorders while MDEC video is active so debug builds can query state without starving FMV playback.
Regression testing was done with non-debug OpenGL builds across multiple FMV-heavy titles. Debug-tool FMV playback was also exercised with the quiet gate enabled.
Co-authored-by: Alex Vanderveen <alex@technicallycomputers.ca>
Co-authored-by: Cursor <cursoragent@cursor.com>
Restore user savestates to their saved CPU PC instead of the game entry PC, and clear non-serialized CPU/GTE completion deadlines after loading a state so stale absolute guest-cycle deadlines cannot stall the first post-restore unit read.
Debounce load requests for 60 frames after a successful restore. This prevents repeated load requests from stacking multiple restore/recovery cycles into a long apparent softlock while keeping normal save/load behavior unchanged.
Regression testing was done. Caveat: restores can visibly pause, especially near CD/load transitions, and worst-case recovery may take several seconds; observed long recovery cases eventually resumed rather than crashing or permanently hanging.
Co-authored-by: Henrique Guedes <henrique.guedes@porttus.com>
The shared recomp-ui launcher already exposes fullscreen as a universal
tri-state (RecompLauncherCSettings.fullscreen: 0 off / 1 borderless /
2 exclusive), but the PSX runtime collapsed it to a bool everywhere and
only ever used SDL_WINDOW_FULLSCREEN_DESKTOP. Widen the runtime to carry
the full tri-state end to end, matching the SNES/Genesis engines:
- config_loader: UserSettings::fullscreen is now int (0/1/2) instead of
bool. settings.toml persists it as a bare int; loading still accepts
the old bool form (true -> 1) for back-compat with settings.toml files
written before this change, then clamps to [0,2].
- main.cpp: removed every `!= 0` / `? 1 : 0` collapse between
UserSettings, the seed struct, and RecompLauncherCSettings, so 0/1/2
round-trips unchanged through the launcher and back into settings.toml.
- main.cpp: win_flags now maps 2 -> SDL_WINDOW_FULLSCREEN (exclusive
mode change) and 1 -> SDL_WINDOW_FULLSCREEN_DESKTOP (borderless), via
a small psx_fullscreen_flag_for_mode() helper shared with the hotkey.
- main.cpp: the Alt+Enter / Cmd+Ctrl+F hotkey now detects "currently
fullscreen" by testing the SDL_WINDOW_FULLSCREEN bit (set in both
SDL_WINDOW_FULLSCREEN and SDL_WINDOW_FULLSCREEN_DESKTOP) instead of
only the DESKTOP flag, and toggles between windowed and the
CONFIGURED tri-state mode rather than hardcoding DESKTOP.
- launcher.cpp/launcher.rml (the legacy RmlUi launcher, still built
whenever PSX_LAUNCHER is on): fullscreen is now a 3-way cycle button
(Off/Borderless/Exclusive) following the same cycle_*/*_label pattern
as the existing CRT/texture-filter controls, instead of an On/Off
toggle.
Validated with g++ -fsyntax-only (mingw64) against config_loader.cpp
standalone, and main.cpp with no launcher flags, PSX_LAUNCHER only,
RECOMP_LAUNCHER only (against the real recomp-ui RecompLauncherCSettings
header), and both together - all clean. launcher.cpp (RmlUi) was
reviewed by exact pattern-match against the file's existing cycle_crt/
crt_label code (lib/RmlUi isn't checked out in this worktree, so it
could not be compiled).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Register configured range_sites with the dirty-RAM interpreter so overlay-resident classifiers use the same two-margin widening already emitted by native codegen.
Co-authored-by: Opok <novelasevilliousesp@gmail.com>
Add opt-in slti/sltiu far-bound scaling with matched native and interpreter semantics, correct immediate sign extension, and an overlay ABI forwarder for live aspect state.
Co-authored-by: Opok <novelasevilliousesp@gmail.com>
Two independent failures made every live reshard fail SILENTLY (runs
counted, shard_ok stayed 0, the game just never got shards):
- autocompile.c: the child line is executed via 'cmd.exe /C <line>'.
When the line BEGINS with a quoted path and contains further quotes,
cmd.exe strips the first and last quote characters and mangles the
command ('The filename, directory name, or volume label syntax is
incorrect'). Wrap the whole line in one extra pair of quotes -- cmd
then strips exactly those and executes the inner command verbatim.
- launch_tomba2_interp_perf.ps1: the autocompile command used an
unqualified 'python'; with an MSYS python first on the inherited
PATH, it cannot open the Windows-style script path ('can't open
file'). Use the canonical Windows Python312 explicitly and fail the
launch loudly if it is absent.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Landed while root-causing the Tomba 2 warm-cache boot death; each of these
was a hole that blocked attribution on the production binary:
- psx_fatal_halt: halt-and-serve is now keyed on the TCP listener being
live (debug_server_get_status) instead of the build flavor. A production
run with PSX_DEBUG_SERVER=1 + PSX_EXIT_HALT=1 now stays inspectable at
the fatal instead of exit(1)ing the evidence away.
- debug_server_get_status: was declared in debug_server.h but never
implemented; implemented (listener state, port, saved socket error).
- event_ring: EVENT_RING_ENABLED=1 unconditionally. The ring records
edges only; its production disable predated the production listener and
contradicted its own ALWAYS-ON design note.
- sp_ring (new): stack-domain (64 KB) transition ring at fntrace_record --
one entry per dispatch whose guest SP crossed a domain, i.e. the
provenance record for 'who installed this stack pointer'.
- disp_ring (new): 128-entry unconditional dispatch tail (target/ra/sp/
cycle) so the final control-flow sequence before a death is always
reconstructable post-mortem.
- overlay_loader: the native-call ring (overlay_native_ring recent[]) is
now recorded in production too -- each entry names the requested PC and
the claiming candidate CRC, which is what finally attributed the
wrong-variant native run.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add an opt-in horizontal low-edge transform for subu rd,zero,rt classifiers, with matching native and dirty-RAM interpreter behavior and guarded overlay variants.
Co-authored-by: Opok <novelasevilliousesp@gmail.com>