Commit Graph

1311 Commits

Author SHA1 Message Date
Shokunin 9805a00a7e GL: queue the native-wide mirror with the high-resolution window's draws
With lines batched, 8K widescreen still switched to the wide surface and
back for every textured or flat batch that reaches the margins (~29 per
frame at 21:9 in an R4 race; 32:9 flushes ~4x as many textured batches).
At 18x those surfaces are 10080x9216 and 15372x9216, and each switch ends a
render pass: with the mirror drawn into the hr surface instead (no switch,
gl_ws_ablate 3) 32:9 at 8K ran at 57 guest frames/s instead of 12.

In windowed mode a draw's native-wide mirror now rides in its window queue
entry (target surface, x shift, backdrop stretch) and is replayed in the
queue's flush, in order, one pass per wide surface (hiw_replay_wide). The
queue's sync points already cover what the mirror samples (the raw mirror)
and the stencil rebuild; every other write to a wide surface (the clears,
the full-screen overlay rect, reallocation) and every read of one
(present, capture, dumps) now flushes the queue first. Outside windowed
mode, and with the mirror ablated, the immediate mirror runs as before.

- gl_scale_invariance_test: the window runs' native-wide surfaces (the
  scene's and the new lines runs') stay byte-identical to the full-VRAM
  runs, and the lines runs check that the mirrors were queued. Mutations
  fail it: no queueing (the queue check), a wrong x shift or no replay
  (the wide digests).
- R4, same setup as the previous commit: 21:9 at 8K 34.2-37.7 -> 56.1-56.6
  guest frames/s (4:3 at 8K: 59.4), 32:9 12.6-13.8 -> 45.1-45.9; mirror
  passes per frame 29 -> 0.5. With the debug server's per-frame readback on
  (the default debug build): 21:9 43.7, 32:9 40.0.
- test_gl_internal_scale_guards pins the queued path, the replay state and
  the sync points.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:52:24 -07:00
Shokunin 624fadc14f GL: batch lines in the high-resolution window mode too
In windowed mode (8K past a 16384 texture limit: VRAM at 1x plus the
high-resolution window at S) lines stayed immediate. Each one drew GL_LINES
on the 1x hr surface and then, with native-wide, switched to the wide
surface (10080x9216 at 21:9 and 18x, 15372x9216 at 32:9) and back for its
mirror. In an R4 Grand Prix race that was ~130 mirror passes per frame:
21:9 at 8K ran at 15 guest frames/s and 32:9 at 5.5.

A batched line now carries two vertex sets. Its one-native-pixel quad joins
the flat batch with the triangles, as above 1x, and is what the window and
the wide surfaces draw. Its two GL_LINES vertices go in s_fbl, with the
batch position of its quad in s_fbl_at. The 1x hr draw
(flat_batch_draw_hr_lines) walks the batch in order, drawing triangle runs
from s_fb and line runs as GL_LINES from the copy uploaded after the
batch's vertices, so painter order and the 1x pixels are unchanged. A batch
without windowed lines keeps its single draw; outside windowed mode nothing
changes (s_out_scale > 1 is the old gate there).

- gl_scale_invariance_test: new "lines" runs (lines interleaved with
  triangles that overlap them, over a native-wide surface) at 1x and 9x on
  the full-VRAM surface and 9x and 18x in windowed mode. The windowed runs'
  native frame equals the 1x run's, and at 9x their frame and wide surface
  equal the full-VRAM run's; above 1x the lines and the triangle must share
  one flat batch, windowed lines with their GL_LINES vertices. Every
  existing digest line is unchanged, and the lines runs give the same
  digests against the renderer without this change (immediate lines).
  Mutations fail it: drawing all triangles before all lines, or the quads
  on the 1x surface.
- R4 (scratch merge with feat/adaptive-widescreen c042434c and the R4
  widescreen mod, one race savestate, debug build, GL timer queries and the
  debug server's per-frame VRAM readback off): 21:9 at 8K 15.0 -> 34.2-37.7
  guest frames/s, 32:9 5.5 -> 12.6-13.8; mirror passes per frame 132 -> 29.
- test_gl_internal_scale_guards pins the gate, the second vertex set and
  the ordered 1x draw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:52:23 -07:00
Shokunin 3b2f54803c GL: drain the flat batch before switching the native-wide target
The flat batch mirrors into whatever native-wide target is current when it
is flushed. glb_wide_set_target() and glb_wide_disable_target() drained only
the textured batch before switching, so flat triangles -- and, since the
previous commit, line quads above 1x -- still queued at a switch would be
mirrored into the new target. The draw-area change that normally precedes a
switch (GP0 E3 -> glb_set_draw_area) already flushes both batches, so this
is a guard rather than an observed fault; the identical change is on
feat/adaptive-widescreen, which batches native-wide lines at 1x.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:52:23 -07:00
Shokunin c47a9059b9 GL: batch line quads above 1x with the flat triangles
Found in the R4 integration build: widescreen 21:9 (native-wide) at 4K ran
a Grand Prix race at 22-30 guest frames/s instead of 60 (26 with the
debug build's GL timer queries off). A CPU sample put
~57% of the emulation thread in glb_draw_line -> gpu_geometry ->
glDrawArrays -> the driver ending a render pass: every line was drawn on
its own, flushing the textured batch and, with native-wide, binding the
wide surface and the hr surface again for its mirror. R4 draws hundreds of
lines per race frame; at 9x each of those render-pass switches stores and
reloads a 9216x4608 surface.

Above 1x (full-VRAM surface, s_hr_scale > 1, not windowed) a line is
already a quad of two triangles (line_to_quad), drawn with the GEO program
like a gouraud triangle. It now joins the flat batch: same vertices, same
program, same painter order and batch keys (semi, mask). A line the
backdrop-stretch gate would widen keeps the immediate path, since the flat
batch mirrors unstretched. 1x keeps GL_LINES unchanged and the windowed
high-resolution mode keeps its own path.

- run_gl_scale_invariance (real GL; its fixture draws horizontal,
  diagonal, steep and side-by-side lines): passes, and all 48 digest lines
  of its 14 probe runs are identical to the build without this change.
- R4 21:9 at 4K from one race savestate (debug build, GL timer queries
  off, widescreen only): 26.1 -> 59.9 guest frames/s over 4-10 s; 4:3 at
  4K stays 59.9.
- test_gl_internal_scale_guards pins the gate and that the batched path
  issues no draw of its own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:52:23 -07:00
Shokunin 84dbc2982a GL: keep side-by-side buffers at full resolution; bound copy staging
Windowed high-resolution mode kept one window over the union of displayed
columns. Two 512-wide buffers side by side need 18432 px at 18x, past a
16384 GPU limit, so the second buffer was refused and every other frame
presented at 1x.

- The window is now up to four tiles, each its own surface over a column
  range. A new display first tries one surface over the union of all
  displays (the old behaviour, so R4's 320-wide window is unchanged), then
  a merge with the tiles it overlaps, then a tile of its own. Every
  mirrored write (queued draws, fills, uploads, copies, the depth24 clear,
  stencil rebuilds) goes to each tile it touches; present, captures,
  screenshot_hires and the native-wide centre read the tile holding the
  display. A display no tile can hold within the GPU limit, the memory
  budget (all tiles together) or the tile cap still presents at 1x, logged.
- A copy into the window stages its S-scaled source in a scratch of its
  own, in column chunks that fit the GPU limit, walked in memmove order so
  an overlapping copy still reads pre-copy pixels. The shared scratch no
  longer grows past the hr surface for it.
- Staging textures commit a new size only after the driver accepted the
  storage; a size past the limit is refused with a log line and the
  texture keeps its old storage (scratch_ensure used to record the size
  before a glTexImage2D that could fail).
- PSX_GL_MAX_DIM lowers the GPU limit the backend plans with (testing a
  layout for a smaller GPU). video_info adds display_x/display_y,
  hires_window_tiles and hires_window_mib.
- gl_scale_invariance_test: side-by-side runs flip two 512-wide buffers
  and require one surface at 5x and two tiles at 9x (PSX_GL_MAX_DIM=8192)
  to equal the full-VRAM surface, including copies between the buffers
  and 1000-column copies; at 18x both buffers must read back at S. A
  scratch request past the limit must be refused and leave the texture
  and its recorded size intact.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:52:23 -07:00
Shokunin dbfb175903 GL: split s_scale into s_hr_scale and s_out_scale; poison the old name
The high-resolution window made the GL backend's single scale two: the
scale of s_hr_fbo (1 in windowed mode) and the scale presented (up to
32). The previous commit kept s_scale for the presented one, so code
written against the old contract (s_hr_fbo at s_scale) still compiled
after a merge and read the 1024x512 surface at 18x coordinates in
windowed 8K. The frame-rate branches add exactly such reads (render-pass
capture, backup, journal and verify).

Rename the presented scale to s_out_scale, keep s_hr_scale, document the
contract at the declarations, and #pragma GCC poison s_scale, so every
use of the old name fails to build and must pick one: s_hr_scale for
s_hr_fbo and whatever backs it up or mirrors it, s_out_scale for the
window, the wide surfaces and captures of the presented image. A VRAM
transaction must also back up and restore the window's rows while
hiw_on(), or refuse to run.

No behaviour change: a mechanical rename. gl_scale_invariance_test
(real GL, window forced at 2/3/5/9/18x) passes; new guards check the
poison and that a function binding s_hr_fbo at s_out_scale also handles
the window.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:52:23 -07:00
Shokunin b3fc8ce7a2 Test: native-wide surface identical with the high-resolution window
gl_scale_invariance_test also mirrors margin-reaching draws (flat, gouraud,
textured, a line across both margins) into a 16:9 native-wide surface and
requires its full dump at internal resolution to match between the
full-VRAM and windowed runs at the same scale. This covers the wide passes'
sample-grid shift in windowed mode and the centre blit from the window;
dropping the shift switch fails it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:52:23 -07:00
Shokunin 9bb983208e Settings: shorter Internal resolution note
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:52:23 -07:00
Shokunin 9f08b6d9b7 GL: queue the high-resolution window's draws into one render pass
Mirroring every batch into the window as it was flushed switched
framebuffers twice per batch. On Apple's GL (Metal underneath) each switch
ends a render pass, about 80 us: 10 ms of CPU per R4 frame at any window
scale, and the 8K preset ran at 21 fps (frame_perf total 47 ms,
cpu_flush 17.4 ms).

The window's copies of textured, flat and line draws are now queued
(vertices plus the state they were drawn with: blend key, set-mask,
mask-check, texture window, filter, sampled texture, draw area) and
replayed into the window in one pass at the next sync point: before the
raw mirror changes (pack, upload, depth24 clear), before any immediate
write to the window (fill, copy, upload, stencil rebuild), and before every
read of it (present, capture, growth, hires readback). Order within the
window is kept, so it equals an immediate mirror wherever it is observed.

tex_batch_draw_passes and mask_stencil take their mask state as
parameters (tex_draw_passes_ex, mask_stencil_ex) so the replay uses the
recorded state; the canonical pass calls them with the live state, the
same GL call sequence as before (native and 2x/4x digests unchanged).

Measured on an M4 in a race: 8K total 16.68 ms per present (60 Hz
cadence), cpu_flush 0.62 ms; forced window at 4K likewise. The invariance
test still finds the window's frame byte-identical to the full-VRAM
surface at 2/3/5/9x.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:52:23 -07:00
Shokunin 2211ecabf3 GL: true 8K past a 16384 texture limit with a high-resolution window
8K is 18x at a 240-line reference, and a full-VRAM surface at 18x is
18432 px wide: over the 16384 limit of Apple's GL, Intel and MoltenVK. A
title only needs its displayed frame at 18x, so past the full-VRAM limit
the GL backend now splits the work:

- The authoritative VRAM stays the ordinary hr surface at 1x, i.e. the
  native renderer unchanged: pack, CPU readback, render-to-texture and VRAM
  copies are exactly the native results (s_hr_scale; s_scale stays the
  presented scale gr_scale reports).
- A presentation-only surface at S covers the displayed columns W =
  [x0, x1) x all 512 rows (R4: 0..319, 5760x9216 at 18x, 405 MiB). Every
  GPU write touching W is mirrored into it: textured and flat batches,
  lines (quads), fills, uploads, the depth24 clear, and VRAM copies (hi to
  hi when the source is in W, otherwise the 1x source upscaled; both staged
  before drawing so overlapping copies read pre-copy pixels). It keeps its
  own stencil. A separate blit program carries the window projection, so
  the canonical shaders are untouched.
- W grows (64-column aligned) the first time a display rectangle outside it
  is presented, seeded by upscaling the 1x content. Present, hold-last,
  interpolation capture, screenshot_hires and the native-wide centre read
  it; a display it cannot hold presents at 1x.

It engages only when the full-VRAM surface cannot hold the request (driver
limit or budget), sized so a 320-wide window fits both; up to 16x on the
M4 nothing changes. PSX_GL_HIRES_WINDOW=0/1 disables or forces it. The
launcher note and video_info (hr_scale, windowed, hires_window_*, hires_fbo)
report it.

Default-off: at 1x and whenever the full-VRAM surface fits, the paths are
the previous ones (same native-VRAM and present digests on a fixed scene at
1x and 2x).

Tests: gl_scale_invariance_test now also forces the window at 2/3/5/9x and
requires its frame at internal resolution to be byte-identical to the
full-VRAM surface at the same scale (copies inside, into and across the
window edge, fills/uploads across it, mask, all blend modes) with native
VRAM identical to 1x, and runs it at 18x; gl_scale_limits_test covers the
window clamp; guards pin that it only engages past the full-VRAM limit.
Verified in R4 on an M4: the 8K preset renders 5760x4320 in a race (rear-
view mirror present) and 5760x8640 on a 480i menu.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:52:23 -07:00
Shokunin 472f9c7ed0 Debug: screenshot_wide_hires reaches the lower buffer's band at 8K
The capture dumps the wide surface from its top row into a buffer capped at
8192x8192 pixels, then cuts the displayed band out of it. A 21:9 surface at
18x is 10080 wide, so the cap held 6657 of its 9216 rows: with R4's lower
double buffer displayed (y 240, band rows 4320..8639) the capture came back
10080x2337 instead of 10080x4320. Size the buffer to the end of the displayed
band at the native-wide width (up to 256M pixels); smaller captures keep the
old budget.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:52:23 -07:00
Shokunin bb2864bc60 Settings: an older launcher's Supersampling pick wins over a preset
A host built against a recomp-ui without the Internal resolution row
(RECOMP_LAUNCHER_HAS_INTERNAL_RESOLUTION undefined) still seeded
internal_resolution on first boot and applied it after the launcher.
From a fresh start the seed was "native", so a Supersampling pick of 3x
was reset to 1x and "native" was saved; on the netplay soft-return the
sticky preset was re-applied at session_reboot. The legacy row stopped
working.

Both launcher exits now go through two pure helpers in
internal_resolution.h:
- psx_ir_launcher_seed_supersampling: with the row, the factor as before;
  without it, the factor itself when no preset is configured (the
  historical round trip), else the preset's scale capped at the row's 4x.
- psx_ir_adopt_launcher: with the row, the row's preset as before;
  without it, a pick in the Supersampling row drops the preset, and an
  untouched row keeps a preset the player cannot see (game.toml or a
  hand-edited settings.toml). It also returns what settings.toml saves:
  no internal_resolution key unless a preset is kept.

internal_resolution_test drives seed -> launcher -> adopt for both
launcher kinds, first boot and soft-return, against a model of the
legacy row (clamp to 1..4, cycle); keeping the old sticky preset fails
it. gl_internal_scale_guards pins both exits to the helpers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:52:23 -07:00
Shokunin ecda594996 Settings: never persist the PSX_INTERNAL_RESOLUTION override
The environment override was written into g_video_internal_res, the
configured preset. On a netplay soft-return the launcher was seeded from
it and saved it to settings.toml, so one local peer started with
PSX_INTERNAL_RESOLUTION=8k left 8k in the settings.toml the other peer
shares: the case the override exists for.

Keep the override in g_video_internal_res_env. It still wins for the run
(scale, Match display, HiDPI window, video_info), but the launcher only
shows, and settings.toml only saves, the configured preset.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:52:23 -07:00
Shokunin 7d49d4c491 Settings: PSX_INTERNAL_RESOLUTION override for one run
A preset id or a line count in PSX_INTERNAL_RESOLUTION overrides every
config layer, like the other validation env overrides (PSX_SCANLINES,
PSX_GEOMETRY_CORRECTION). Two local netplay peers share one settings.toml,
so this is how one runs at 4K beside another at Native. Also say
"measured when the game window opens" for Match display before the window
exists instead of logging a 1x request.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:52:23 -07:00
Shokunin f34f91cc25 Settings: Internal resolution presets (Native ... 8K, Match display)
Add a player-facing internal resolution on top of the raised GL ceiling.
A preset is a target height; the runtime renders at the integer scale
S = ceil(target / reference_lines), reference 240 by default: 720p 3x,
1080p 5x (area-resolved to 1080), 1440p 6x, 4K 9x, 5K 12x, 8K 18x. The
backend then clamps S to what it can allocate.

- runtime/include/internal_resolution.h: the preset table, stable ids,
  the value encoding shared with recomp-ui (0 unset, 1 native, -1 match
  display, N target lines) and the pure resolver.
- config: [video] internal_resolution (a preset id or a number of lines)
  and resolution_reference_lines in game.toml; internal_resolution in
  settings.toml, written as a stable id beside supersampling = min(S, 4)
  for older runtimes. Precedence: game default < player's legacy factor <
  player's preset. settings.toml window_width now accepts up to 7680.
- main.cpp: resolve the preset before gpu_init; Match display re-resolves
  from the game window's monitor (SDL3 mode height x pixel density) before
  the GL context allocates. The launcher gets the vocabulary (with a
  synthesized "Nx (L lines)" entry for a legacy factor no preset matches)
  behind RECOMP_LAUNCHER_HAS_INTERNAL_RESOLUTION, on first boot and on the
  netplay soft-return.
- The OpenGL game window gets SDL_WINDOW_HIGH_PIXEL_DENSITY (SDL2:
  ALLOW_HIGHDPI) only when the player chose more than native, so the
  drawable is in pixels on Retina; native keeps the window as it was.
- debug server: video_info (preset, requested and effective scale, GL
  limit and clamp, hr surface, window points vs pixels), screenshot_hires
  reads the GL hr FBO at full size, screenshot_wide_hires captures the
  native-wide band at internal resolution.
- docs: config_schema (keys, precedence), NETPLAY (a per-peer presentation
  setting), TCP_COMMANDS (index regenerated), ENHANCEMENTS IR1.

Default-off: with no internal_resolution anywhere the scale, the window
flags and the present path are unchanged.

Tests: internal_resolution_test (presets x reference 240/480 x backend
maxima, legacy mapping round trip), video_enhancement_settings_test (game
and settings keys, stable-id round trip, legacy key still written),
gl_internal_scale_guards (HiDPI only when opted in, launcher fields behind
the capability macro).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:52:23 -07:00
Shokunin de8f4ef148 Test: link the GL probe strictly, with the renderer's other sources
run_gl_scale_invariance.py linked the probe with -undefined dynamic_lookup
(--unresolved-symbols=ignore-all on Linux), so a renderer call into a
source the probe did not build bound to NULL and crashed the run (-11)
instead of failing the link. Once the frame-rate render passes land, the
renderer calls render_pass_plan.c and frame_interpolation.c, and the
probe crashed on every run.

Link frame_interpolation.c (the fixture's stub for it goes) and
render_pass_plan.c whenever it exists, and drop the unresolved-symbol
flags: unused renderer functions are still removed (-dead_strip, or
per-function sections with --gc-sections), and anything left unresolved
is a link error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:52:23 -07:00
Shokunin ec7bc14ad9 GL: Fit to Window stays within the native-wide surface limit
A native-wide surface is g_wide_w*S wide and the driver limit bounds it
(1024 native columns at 16x on a 16384 limit, about 38:9 at a 320-px
display). An uncapped Fit to Window aspect could ask for more; wide_fbo_for
then refused the surface and the frame fell back to a 1x CPU present with
no native-wide margins.

update_adaptive_widescreen now narrows the Fit aspect to the widest the
surface holds (gl_renderer_fit_wide_aspect: psx_gl_max_wide_width at the
context's scale, psx_gl_fit_wide_aspect at the current display width,
gpu_ws_display_width). It changes nothing unless the surface would be
refused. The refusal stays for a fixed aspect on a wide display mode; its
comment now gives the right limit and what the frame falls back to.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:52:23 -07:00
Shokunin eee07fe910 GL: raise the internal-resolution ceiling to the driver's limits
The OpenGL backend capped supersampling at 4, the software mirror's limit,
although its hr surface lives on the GPU. Raise the compile-time ceiling to
32 (gpu_render.h) and decide the real scale at context init:

- Query GL_MAX_TEXTURE_SIZE, GL_MAX_RENDERBUFFER_SIZE and
  GL_MAX_VIEWPORT_DIMS and clamp S so the 1024*S x 512*S surface fits them
  and a 2 GiB memory budget (PSX_GL_VRAM_BUDGET_MB overrides it). Apple's
  GL on Metal reports 16384, so 16x is the most a full-VRAM surface can be.
  The clamp is logged with the limit that applied.
- If the surface still fails to allocate, retry one scale lower inside GL.
  Only a 1x failure drops the backend to software, as before.
- Draw lines above 1x as quads one native pixel thick covering both
  endpoints. glLineWidth(S) is capped at 1 on core profiles, so every line
  was one hr pixel thick (1/9 of native at 9x).
- Present a supersampled source with an area resolve when it is more than
  1.25x the output (1200 lines into a 1080 window, 480i menus), and inset the
  UV rect by half a texel instead of half a native pixel, which cropped and
  zoomed the image by (S-1)/2 texels per edge.
- Size the copy scratch to the largest copy (copies stage at its origin) and
  rebuild the mask stencil in tiles, only over the primitive bbox union, so a
  large S does not cost another full-size surface.
- Refuse a native-wide surface wider than the driver limit (uncapped Fit at
  a high scale) with one log line; the frame presents 4:3.
- main.cpp: the offline and dual-raster clamps no longer cap GL at the
  software 4x. The CPU present path presents GL frames at 1x (its readout is
  native) and its staging buffer stays sized for at most 4x.
- [video] supersampling accepts 1..32 in game.toml and settings.toml; the
  runtime clamps per backend.

Every change is gated on S > 1: at 1x the renderer is byte-identical (same
native VRAM and presented framebuffer digests as the previous source on a
fixed GP0 scene).

Tests: gl_scale_limits_test (clamp arithmetic), gl_internal_scale_guards
(source guards + runner parsing), and gl_scale_invariance_test, a hidden
real-GL run at 1,2,3,5,9x that requires identical guest-visible VRAM at
every scale, one-native-pixel lines at internal resolution, and a 32x
request that stays on GL at the driver's clamp (16x on Apple).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:52:22 -07:00
Matt Stanley f9d8830721 Merge pull request #410 from shaneomac1337/fix/debug-server-socket-noinherit
debug_server: make the listen socket non-inheritable on Windows
2026-09-28 15:34:48 -07:00
Martin Penkava c619fe2b75 debug_server: make the listen socket non-inheritable on Windows
Winsock sockets are inheritable by default. Any child process the runtime
spawns (e.g. the overlay autocompile's `cmd.exe /C python compile_overlays.py`)
inherits the debug server's listening socket; if the game exits while the
child is still running, the child keeps 127.0.0.1:<debug_port> bound and the
next launch cannot bind it (clients get connection refused / talk to a dead
listener).

Observed: after closing the game mid-autocompile, `netstat -ano` showed :4370
LISTENING under the exited game's PID, held by the surviving python child;
killing the compile freed it. Fix: SetHandleInformation(HANDLE_FLAG_INHERIT, 0)
right after socket(). No behavior change on non-Windows.

This change was made with AI assistance (Claude Opus 5.5, Anthropic) and
reviewed/tested by the submitter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 13:11:23 +02:00
Martin Penkava a8f91653d1 vulkan: fix depth/stencil aspect + usage and staging-buffer usage (validation errors)
Found with the Khronos validation layer on AMD RX 7900 XT (Windows, mingw),
where D24S8 is unavailable and choose_ds_format() picks the combined
D32_SFLOAT_S8_UINT:

- VUID-VkImageMemoryBarrier-image-03320: every view/barrier/clear on the
  canonical and wide depth-stencil images named only the STENCIL aspect.
  Without separateDepthStencilLayouts, a combined depth/stencil format must
  be transitioned with both aspects. Added DS_ASPECT and used it for the
  image views, barriers and vkCmdClearDepthStencilImage ranges.
  (vkCmdClearAttachments keeps the stencil-only mask - that is legal.)
- VUID-vkCmdClearDepthStencilImage-pRanges-02659: the canonical DS image is
  cleared with vkCmdClearDepthStencilImage but lacked
  VK_IMAGE_USAGE_TRANSFER_DST_BIT (the wide DS images already had it).
- VUID-vkCmdCopyImageToBuffer-dstBuffer-00191: staging buffers are used for
  readbacks (vkCmdCopyImageToBuffer) but were created with TRANSFER_SRC only.

Validation messages over the same 20 s boot (SmackDown 2, Vulkan):
53 -> 3 (the remaining VUID-vkQueueSubmit-pSignalSemaphores-00067 swapchain
semaphore reuse is untouched). The fix also cleared the downstream
VkImageMemoryBarrier-oldLayout-01213 and vkCmdDraw-None-09600 reports.

This change was made with AI assistance (Claude Opus 5.5, Anthropic) and
reviewed/tested by the submitter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 13:11:02 +02:00
Matthew Stanley 78534deff4 mods: [runtime] hide_hidden_mod_features opts the launcher into never showing hidden features
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 16:41:47 -07:00
Matt Stanley 68d77ed6a9 Merge pull request #404 from RetroPortingToolKit/fix/vblank-follows-video-mode
runtime: VBlank rate follows the GPU video mode, not the disc region
2026-09-26 16:03:47 -07:00
Matthew Stanley 7caef77459 debug_server: report the live video standard and frame timing in vblank_rate
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 15:39:51 -07:00
Matthew Stanley f51617bb7d runtime: VBlank rate follows the GPU video mode (GP1(08h) bit 3), not the disc region
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 15:38:21 -07:00
Matthew Stanley c547f3b967 mods: implicit cross-package feature requirements ([[requirement]], format 7)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 13:58:16 -07:00
Matthew Stanley 141eb39002 mods: let titles exclude framework builtins with EXCLUDE_BUILTIN_MODS
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 12:11:39 -07:00
Matthew Stanley bc5ec35998 cli: generate builds the static overlay shard an AOT profile declares
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 10:28:14 -07:00
Matt Stanley 321776b836 Merge pull request #399 from RetroPortingToolKit/feat/aot-nfe-lzss
AOT: indexed_lzss_members method for bit-stream LZSS packs
2026-09-26 10:04:42 -07:00
Matt Stanley 0487e0cb81 Merge pull request #398 from RetroPortingToolKit/feat/8mb-ram-opt-in
Opt-in 8 MB main RAM
2026-09-26 10:04:39 -07:00
Matthew Stanley b6a80e5d9e debug_server: dirty_ram_stats per_pc range filter, paging and completeness counts
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 08:17:34 -07:00
Matthew Stanley c67327e42f aot: per-entry static overlay dispatch counters, queried by overlay_static_entries
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 08:17:28 -07:00
Matthew Stanley ec4c91cd94 runtime: GP0 source key and overlay_region_floor follow the 8 MiB window
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 08:03:58 -07:00
Matthew Stanley 1721739a73 debug_server: PSX_WTRACE_BOOT_RANGES gets reserved slots and is refused whole, with the reason in wtrace stats
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 08:03:58 -07:00
Matthew Stanley 0238117450 runtime: keep RAM-mirror PCs architectural; fold only bytes, through one live mask
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 08:03:57 -07:00
Matthew Stanley 18e3030440 savestate: validate every section before applying any; header records the live RAM size
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 08:03:39 -07:00
Matthew Stanley ab5d63e1f1 tests: register every offline-tool unit test and make the registration guard scan tools/ and tests/
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 07:36:33 -07:00
Matthew Stanley 199cfe01bc mods: flat function-entry hook table built at activation; interpreter skips it when empty
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 07:34:20 -07:00
Matthew Stanley 71fdd712db debug_server: seed boot/transition write-ring ranges from PSX_WTRACE_BOOT_RANGES
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 06:43:12 -07:00
Matthew Stanley cd8135406b mods: give the 8 MB RAM builtin a current-schema manifest and parse-test every builtin
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 06:43:12 -07:00
Matthew Stanley c564ccd1f1 runtime: route every RAM consumer through one live 2/8 MiB geometry
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 06:31:33 -07:00
Matthew Stanley fa951645b4 runtime: add opt-in 8 MB main RAM mod
Adapt the 8 MB RAM work from the rbengine branch into a master-targeted change. The builtin package is disabled by default, activation requests expanded RAM before memory init, and runtime/state/digest/dispatch paths respect the live RAM map.
2026-09-26 06:02:23 -07:00
Matthew Stanley 1a3cf12289 aot: mod-package image sources, static action, mirror-aware static overlay gate
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 00:27:12 -07:00
Matthew Stanley 41a76a72d8 mods: resolve function-entry plugins and run them only for the active plan
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 00:27:12 -07:00
Matthew Stanley f9109e21c6 Resolve relative bezel artwork paths against the exe directory
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 22:27:47 -07:00
Shokunin 5bd0397278 Resolve the executable path on macOS without /proc
The setup host located itself with realpath("/proc/self/exe"), which only
exists on Linux. On macOS it failed, so a host launched from Finder (cwd =
$HOME) could not find its project tree: Generate & rebuild never appeared
and forward-to-built-game never fired. Take the path from dyld's
_NSGetExecutablePath there (as recomp-ui's launcher_model.c already does);
Linux and Windows are unchanged.

The netplay rollback "binary path" diagnostic had the same /proc read and
logged "(unknown)" on macOS; it uses the same source now.

No emulation or runtime behaviour changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 20:05:09 -07:00
Alex Vanderveen b5ef7b86d9 netplay: take the scheduler, input history and hash-confirm from recomp-net
recomp-net now carries the peer-facing rollback modules that used to live in
retcomm-rbengine (RetroPortingToolKit/recomp-net#14). Switch the MotK shims and
psx_netplay_sched.c from rbe_sched_* / rbe_ih_* / rbe_hc_* /
rbe_rb_peer_post_tip_ok to their rnet_* names and recomp_net/ headers, and bump
lib/recomp-net to c2338c6.

The netplay_* / np_sched_* surface the rest of the runtime calls is unchanged.
The snap ring and rbe_mono_ms still come from retcomm-rbengine, which stays at
a7b9850 for now; the three moved-module unit tests link recomp_net directly
instead of reaching it through rbengine. RBE_RB_* env knobs keep their names.

Checked with PSX_NETPLAY=ON: psx-runtime links and the netplay tests pass
against both the current rbengine and the split one (rbengine
refactor/launcher-core), and the binary's 33 scheduler / history /
hash-confirm functions now resolve to rnet_* where they were rbe_*.
lobby_chat_ring_test does not compile on master either (chat_push arity) and
is untouched here.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 22:06:27 -04:00
Matt Stanley dc7a4c1084 Merge pull request #389 from RetroPortingToolKit/fix/cue-pregap
Honour cue PREGAP/POSTGAP in the BIN/CUE mount (fixes #388)
2026-09-24 15:42:52 -07:00
Matt Stanley 9e9ec7b401 Merge pull request #383 from x6568tank/feat/mid-session-disc-change
Mount a different disc while the game runs
2026-09-24 15:15:43 -07:00
Matthew Stanley eec71b9787 fix: open the game window at a normal size instead of maximised
Default = largest multiple of 240 lines within 2/3 of the usable height;
an explicit window_width is still honoured.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 14:42:12 -07:00