Commit Graph

1195 Commits

Author SHA1 Message Date
Matthew Stanley 93a93c8e07 Fix game runtime wrapper setup gating 2026-09-08 13:36:54 -07:00
Matthew Stanley ae2fc168cc Fix native-wide textured dot HUD shift 2026-09-08 12:52:09 -07:00
Matthew Stanley 912c44c75e Support native-wide HUD and tiled backgrounds with guarded culling 2026-09-07 22:40:23 -07:00
Matt Stanley d3e91e07b5 Merge pull request #336 from mstan/fix/retail-bios-rollback-327
Revert #327 interlaced row submission to restore retail BIOS boot
2026-09-07 13:00:46 -07:00
Matt Stanley aeaa14a52d Merge pull request #335 from mstan/fix/mmx6-mod-disc-resolution-before-commit
Resolve launch disc before committing mods
2026-09-07 13:00:36 -07:00
Alex Vanderveen 3e038f289c launcher: seed personal memcards on netplay soft-return; fold card choices into rematch
After a match the soft-return launcher was built from a fresh settings struct
that never carried the memcard paths or enabled flags. With nothing to inspect
the Save panel painted a placeholder block pattern on both cards, which read as
foreign save data even though the personal card files were untouched (the
netplay sandbox is unbound and personal cards reloaded before the launcher
opens).

- soft_return_lobby: seed memcard_path[] from the personal cards (settings.toml
  path, else <memcard_dir>/cardN.mcd) and memcard_enabled[] like first boot.
- rematch writeback: fold ls.memcard_enabled/memcard_path back into the runtime
  slot config and settings.toml, mirroring the first-boot exit path, so a card
  toggled or browsed in from the rematch launcher reaches memcard_init_slots.
  --memcard-dir keeps winning over paths.
- enabled flag is passed as -1 for disabled (0 means "unset -> on" to the
  launcher) and read back as > 0, at both seed sites. Needs recomp-ui 028fa5c.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016HE3VRJ7nBVP1x7x2Yw2Ho
2026-09-07 15:35:15 -04:00
Matthew Stanley 24c6c56cc0 Revert PR #327 interlaced row submission to restore retail BIOS boot
Matched Ape Escape retail SCPH1001 LLE builds identify 0661ce77 as the visible boot regression: parent 155e269b reaches game code, while 0661ce77 stalls near BIOS frame 375. Revert its four dependent follow-ups too; retain PR #326 readback bounds and PR #328 Vulkan aspect changes.

The row-by-row raster dispatcher amplifies an existing malformed DMA list into massive GL work. Keep the broader CPU/DMA arbitration experiment separate for compatibility testing. Document attribution, validation, and the temporarily restored interlace limitation.

Validation: full Ape target reaches title/menu and frame 11669 on retail LLE; OpenBIOS control reaches frame 3701. Eight focused tests pass; retained GL readback fixture passes 71 checks at both 1x and 4x after linking local SDL with iconv. Beads: beads-iisy; DMA follow-up: beads-eio.3.122.
2026-09-07 12:30:30 -07:00
Matthew Stanley 7e492fa5f8 Resolve launch disc before committing mods 2026-09-07 12:07:27 -07:00
Alex Vanderveen 0bdc648604 cmake patch 2026-09-07 14:51:39 -04:00
Matt Stanley 421f58ec8c Merge pull request #334 from mstan/codex/regression-bundle-326-328-20260907
Bundle GPU regression candidates #326 #327 #328
2026-09-07 11:19:32 -07:00
Alex Vanderveen 39ebb06ff9 lobby: escape every free-text value in an outbound frame
queue_hello was fixed this way once, with a comment explaining why: a
name with a quote in it builds malformed JSON, the server drops the frame
whole, and the rename simply never happens. Its siblings were missed.

psx_lobby_create and psx_lobby_join interpolated the lobby name, the
PASSWORD, the display name, the game name and version, the bind address
and disc_fp straight into the frame. So a quote in a lobby name or a
password silently broke create/join, and a crafted value injected fields
into the client's own message -- which is the shape an edited client
would use deliberately.

Fix the class: every free-text value in an outbound frame now goes
through json_escape, at all seven remaining sites (list, create, join,
server_chat's game_name, seat_swap_answer, signal's lobby_id,
set_host_endpoint). JSON_ESC_CAP and a prototype are hoisted above the
first frame that needs them.

Two supporting changes:

  - the create and join frame buffers grew (1536 -> 2304, 1024 -> 1536),
    because escaping can double every value and a frame that no longer
    fits is a create that silently fails.

  - join now checks snprintf for truncation. create already did; join did
    not, so an over-long frame was sent truncated and dropped whole.

match_caps needed nothing: language is already filtered to alnum/_/- and
session_bios to a two-value whitelist.

Compiles clean with -Wall -Wextra -Wformat=2, no new warnings against the
parent commit. Verified on the translation unit only -- no full runtime
build was run here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1dT6h1ZshMVUUVKTPxsCD
2026-09-07 14:04:34 -04:00
Matthew Stanley 7e770f14a6 Fix GL readback fixture backdrop hook stub 2026-09-07 09:38:52 -07:00
Matthew Stanley 461dcb360a Merge remote-tracking branch 'origin/pr/328' into review/pr326plus-gpu-bundle 2026-09-07 09:36:05 -07:00
Matthew Stanley b775d3e1c1 Merge remote-tracking branch 'origin/pr/327' into review/pr326plus-gpu-bundle 2026-09-07 09:36:00 -07:00
Matthew Stanley 04516212b8 Merge remote-tracking branch 'origin/pr/326' into review/pr326plus-gpu-bundle 2026-09-07 09:35:56 -07:00
Matthew Stanley a7d894fdce Merge remote-tracking branch 'origin/pr/329' into review/pr329
# Conflicts:
#	runtime/CMakeLists.txt
2026-09-07 09:33:16 -07:00
Matthew Stanley fa9d282e7f Merge remote-tracking branch 'origin/pr/331' into review/pr331
# Conflicts:
#	runtime/CMakeLists.txt
2026-09-07 09:29:29 -07:00
Alexandros Mandravillis 406451cb92 Check resolved paths for every staged BIOS asset 2026-09-07 17:17:30 +03:00
Alexandros Mandravillis d8725466bc Keep retry labels and trace declarations C compatible 2026-09-07 16:11:22 +03:00
Alexandros Mandravillis 7c11d57ea1 Preserve CUE track metadata at launch 2026-09-07 16:11:21 +03:00
Alexandros Mandravillis 94f03775c0 Check BIOS assets selected by the setup recipe 2026-09-07 16:11:21 +03:00
FábioAP 6ab221a598 Fix Vulkan renderer ignoring widescreen aspect ratio updates 2026-09-06 14:53:35 +01:00
Alexandros Mandravillis 6fcfb8adbd Preserve field masks in wide flat overlay geometry 2026-09-06 14:16:53 +03:00
Alexandros Mandravillis e57d9b9f4f Validate GL fixture SDL dependencies before building 2026-09-06 13:58:00 +03:00
Alexandros Mandravillis 5aee9c831a Preserve Vulkan wide overlay row clipping 2026-09-06 13:58:00 +03:00
Alexandros Mandravillis 7dc34829fb Synchronize depth24 clears before immediate CPU reads 2026-09-06 13:54:52 +03:00
Alexandros Mandravillis 7c4b03000e Bound interlaced precise triangle row submissions 2026-09-06 13:54:52 +03:00
Alexandros Mandravillis 4c35d0515b Validate GL fixture toolchain and exact negative result 2026-09-06 13:36:37 +03:00
Alexandros Mandravillis 439097184f Count perspective triangles once across interlaced row submissions 2026-09-06 13:34:03 +03:00
Alexandros Mandravillis 54f86b4c91 Bound OpenGL native readback to GPU-written regions 2026-09-06 13:16:37 +03:00
Alexandros Mandravillis 0661ce7773 Preserve active display field during interlaced raster drawing 2026-09-06 13:13:03 +03:00
Alex Vanderveen 4a3748ce06 lobby: a rename reaches the server, so the player list follows
set_player_name only wrote the name locally, and the name reached the
server exactly once, in the hello sent at connect. So renaming left the
players-online list -- which is fed entirely by the server -- and the seat
table showing the old name until the next reconnect.

hello is the identity message, not a handshake: both clients now re-send it
when the name actually changes, through one builder that json-escapes both
fields (a name containing a quote used to build malformed JSON, which the
server drops whole, so the rename silently never happened). The server
applies it to the hub-wide row and, when the client is seated, to the seat
as well -- deduplicated within that room exactly as a join is, then
broadcast as lobby_update -- and hello_ok now reports the accepted name,
which differs from the requested one on a collision.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1dT6h1ZshMVUUVKTPxsCD
2026-09-06 04:52:23 -04:00
Alex Vanderveen e9038af4cd lobby: log the title presented at hello
The per-game scope failing silently is what made an empty title hard to
find; the client now says which one it announced.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1dT6h1ZshMVUUVKTPxsCD
2026-09-06 03:37:26 -04:00
Alex Vanderveen 0f1fd021a8 patch lobby chat 2026-09-06 03:31:56 -04:00
Alex Vanderveen ecc121ade6 lobby browser: spectator column, players online, gallery latency
- lobby_list rows carry allow_spectators / max_spectators / spectator_count
  (browser shows "No" or "1/4"), and every lobby_list carries a players
  array: everyone on the hub with country, room and a short connection tag
  so a client can pick out its own row without publishing whole ids.
- Spectator latency: the round-trip table was keyed by seat and bounds-
  checked against its size, so gallery seats (numbered from 64) were always
  dropped. Seats now map to table cells, player seats first.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1dT6h1ZshMVUUVKTPxsCD
2026-09-06 03:31:38 -04:00
Alex Vanderveen 5e1b7d3332 netplay: host from the gallery, seat swaps across tables, LAN seat self-service, keybind fixes
- Host may sit in a spectator seat: session slot 0 stays the sim authority
  with a muted pad and no port; slot->port map keeps players on the port of
  their lobby seat (host first). Rematch path copies the same plan.
- Seat self-service on LAN (MOTK5 SEATMOVE / SWAPASK / SWAPANS / SWAPRES)
  relayed by the host; online swap requests accept a gallery seat as target.
- Lobby chat ring + join/leave lines; country codes from the server.
- Keybinds: a key drives one input per player (binding S to Cross unbinds it
  from Circle), and keybinds.ini is re-read after the rematch launcher too.
- LAN registry file anchored to the exe directory.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1dT6h1ZshMVUUVKTPxsCD
2026-09-06 03:31:38 -04:00
Matt Stanley b213858c4c Merge pull request #323 from Alexbeav/codex/sbi-setup
Preserve SBI companions and validate them before launch
2026-09-05 22:45:15 -07:00
Matt Stanley 87c06376fb Merge pull request #324 from kerokline/feat/dirty-pc-enrichment
dirty_ram per_pc: stamp resident-occupant CRC and caller RA on external entries
2026-09-05 22:40:28 -07:00
Matt Stanley b0e7c157f3 Merge pull request #322 from Alexbeav/codex/fix-exit-critical-section
runtime: preserve registers in ExitCriticalSection
2026-09-05 22:38:27 -07:00
Matt Stanley 12c40a5b12 Merge pull request #321 from kerokline/fix/starvation-watchdog-wrap
runtime: fix starvation watchdog cross-thread wrap; label watchdog and console exits
2026-09-05 22:36:37 -07:00
Alex Vanderveen f3e9a3f8eb tests: cover the lobby chat ring
psxrecomp's chat was already complete -- client, callbacks, and a host-relayed
LAN path snesrecomp does not have -- but nothing tested it. The SNES side got
this coverage when its chat was written; this brings psx level, against the
same properties, so the two cannot drift apart silently.

Covers what the ring actually promises: room order and both ends, local vs
peer vs system identity (decided by player id, not by who called send, because
the server echoes our own line back and that echo is the copy we keep),
monotonic seq, out-of-range reads refused, wrap-around dropping the OLDEST --
a chat that discards what was just said is worse than no chat -- empty lines
ignored, seq surviving a clear so a UI tracking "newest seen" does not skip
the first line of a new room, and an over-long line clipped to the field
rather than past it.

Links the REAL recomp_net and WS helpers rather than a wall of stubs: nothing
here reaches a socket, so fakes would buy nothing and could drift from what
the runtime links. Only psx_host_mono_ms is supplied, because it lives in the
runtime's own main TU.

Verified to discriminate: making the ring refuse new lines at capacity instead
of evicting the oldest fails two assertions.

ctest with -DPSX_NETPLAY=ON: 67/67 pass (2 disabled).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DYwgPRbwbXz8FhpVzDM7tA
2026-09-05 21:47:18 -04:00
Alex Vanderveen 8f266efe27 netplay: bring-your-own memory card, lobby chat, and the fullscreen lobby glue
Seat 1 (P2) can bring its LOCAL slot-1 card to a match: it uploads the card
to the host at launch over the new recomp-net MEMCARD op, the host installs
it as the match's slot-2 card, and the usual card broadcast carries it to
everyone. The host's real slot-2 file is rebound to netplay/guest_card2.mcd
for the session and restored on shutdown; guests already sandbox both slots.
Lobby side: a per-seat memcard_offer on set_ready (has_card, share), a host
allow flag in match_caps, and guest_memcard_active settled ONCE by the host
at start and shipped with the launch, so a toggle racing the start cannot
split the room. LAN carries the same over MOTK5 UPDATE / MEMCARD / JOIN
tail / a trailing START line. PSX_NET_GUEST_MEMCARD=1 for CLI sessions;
a host waiting on a card that never comes stalls at a named phase
(mc_guest_wait), not a silent "ok".

Two latent guest-sandbox bugs fixed on the way: a disabled slot 2 had no
bound path, so a host blob carrying a card for it failed to import and the
guest stalled forever; and leaving the sandbox re-bound a disabled slot to
the sandbox file. Both slots are now bound in the sandbox and restored per
slot (memcard_rebind_path, which can also unbind).

Lobby chat: the client keeps a ring fed by the server's echo (op:chat);
LAN rooms relay through the host (MOTK5 CHATREQ guest->host, MOTK5 CHAT
host->everyone). Wired to the launcher's chat_send/chat_count/chat_get.

Also carries the spectator-seat work that was in the tree alongside this
(spectator seats in the lobby client, spectator_wire_slot in the launch).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1dT6h1ZshMVUUVKTPxsCD
2026-09-05 21:18:20 -04:00
Kevin 6e760748c2 dirty_ram per_pc: stamp resident-occupant CRC and caller RA on external entries
Make a bare interpreted PC explainable from the session-long per_pc snapshot
alone. DirtyRamPcEntry gains occ_crc / occ_ok (the static overlay variant whose
code ranges span the PC, via a per-PC scan of the static-match cache, and
whether it validated at that moment) and last_ext_ra (gpr[31] at the most
recent external entry, i.e. the caller that reached this interior). Both are
stamped only on external entries -- arrivals from native dispatch, not interp
block chaining -- and emitted per row in dirty_ram_stats.per_pc as occ_crc,
occ_ok and ext_ra.

Reading the pair: occ_ok=1 is an interior gap inside live native code (an
alias seed fixes it); occ_ok=0 with a CRC means the spanning piece is resident
but CRC-missing, so it was compiled from another section's bytes or rewritten
at run time and no seed helps; 0 means nothing compiled spans the PC.

psx_overlay_resident_crc_at() records each static-match cache entry's code
span (lo_min/hi_max) so the scan is a range test; DLL-path titles fall back to
the loader's last residency hash. The debug-server reply buffer grows 32 -> 64
KiB for the wider rows; the tail reserve still cuts between rows.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 18:11:13 -04:00
Alexandros Mandravillis 10eb22b775 Keep native SBI test assertions enabled in release builds 2026-09-05 21:47:40 +03:00
Alexandros Mandravillis 83ba647b6e Register SBI setup tests with CTest 2026-09-05 21:38:40 +03:00
Alexandros Mandravillis 2d92d67592 Validate and import SBI companions in the native launcher 2026-09-05 21:34:14 +03:00
Alexandros Mandravillis 49d5f6233c Report unsupported syscall test toolchains explicitly 2026-09-05 20:09:57 +03:00
Alexandros Mandravillis f3229541a1 Preserve registers in ExitCriticalSection 2026-09-05 19:53:03 +03:00
Kevin 430c93b8a4 runtime: fix starvation watchdog cross-thread wrap; label watchdog and console exits
starvation_watchdog_check() sampled the clock before loading the heartbeat,
but the heartbeat is also stamped by the debug-server IO thread on every
send() chunk. A stamp landing between the two reads made last > now, the
uint64 subtraction wrapped past any threshold, and a healthy runtime exited
with code 2 (BoF3 2026-09-02: 402 us of real staleness tripped the 4 s
watchdog within ~2 min whenever the area poller was attached).

- Load the heartbeat first, decide through the new pure helper
  starvation_watchdog_stale(), which refuses a negative gap by construction
  (same shape as the frame_pacing_sleep_ms fix).
- Make s_last_heartbeat_us _Atomic with relaxed store/load.
- Tag the exit origin: "starvation_watchdog" on the trip, console_close /
  console_ctrl_break / console_ctrl_c in the Win32 console handler, and
  signal_sigint / signal_sigterm in the soft-exit handler. These all used
  to reach psx_atexit_handler as atexit/unknown, indistinguishable from an
  SDL window close.
- Add starvation_watchdog_test (ctest) pinning the decision function.

Verified on BoF3 build-dbg: 10 min soak with the poller polling at 1 s and
the watchdog enabled at its 4 s default, no dump, process alive; forced
trip with PSX_STARVATION_TIMEOUT_US=1000 fires and the run report reads
exit_origin "starvation_watchdog".

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 12:17:16 -04:00
Matthew Stanley 08ec6fc84a host_keymap: hide labels for explicit unbinds 2026-09-04 23:32:45 -07:00