Commit Graph

1846 Commits

Author SHA1 Message Date
Shokunin 599007d1ce GL: opt-in PS1 dithering ([video] dithering = off|on|scaled)
The OpenGL renderer has always drawn shaded and texture-modulated pixels
at 8 bits per channel with no dither pattern (true colour). That stays the
default. 'on' applies the PS1 4x4 offset matrix and 5-bit truncation per
internal-resolution pixel; 'scaled' puts the pattern on the native grid,
so it reads like the console at any scale and the native VRAM is the same
at every internal resolution.

GP0(E1h) bit 9 reaches the backend through a new optional facade hook
(gr_set_dither) recorded for the render thread and Smooth motion redraws.
With the mode off nothing flushes and no uniform changes. Flat, raw and
other 5-bit-exact pixels are never touched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 19:18:47 -07:00
Shokunin 75dc9e84a7 CMake: register the facade GL fixtures where their SDL include and target exist
gl_texture_lod_test (#585) and gl_blend_accuracy_test sat in the
SDL3::SDL3-static block after _gl_scale_sdl_inc was unset, so they got an
empty --sdl-include and were not registered at all where the static
target is absent. Move them into the gl_scale_invariance block that
defines both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 19:18:36 -07:00
Shokunin 0e3c53720b GL: opt-in accurate blending + PS1 blend/mask accuracy test
Verifies the four PS1 semi-transparency modes, set-mask, mask check and
texel STP at 4x internal resolution with PGXP depth on and off, directly
and on the render thread, against the PS1 formulas and the software
rasterizer (new gl_blend_accuracy_test).

Finding: with the historical surface bases (fills and texels stored as
k*255/31, everything else as k*8) single-layer blends are off by one 5-bit
step in places (1312 of the test's checked pixels, e.g. B+F/4 over a fill).
[video] accurate_blending = true stores every VRAM write as k*8 so GL's
8-bit blend truncated by the readback is exactly the PS1 arithmetic; whites
of fills/texels then present as 248 like uploads already do. Default off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 19:18:16 -07:00
Matthew Stanley 73f527f926 Merge remote-tracking branch 'origin/master' into feat/uncharged-call-counted-cycles
# Conflicts:
#	docs/TCP_COMMANDS.md
2026-10-09 15:44:41 -07:00
Matthew Stanley 9dab74fac3 Merge remote-tracking branch 'origin/master' into feat/pgxp-mod-region-depth
# Conflicts:
#	docs/TCP_COMMANDS.md
2026-10-09 15:43:57 -07:00
Matt Stanley b97dcc4541 Merge pull request #615 from RetroPortingToolKit/feat/gl-batch-tier
Build-time HLE tier for OpenGL textured batching + batch_sites attribution
2026-10-09 15:40:09 -07:00
Matthew Stanley 37d3ab3e38 PGXP: track packets in mod guest regions and keep validated depth through the seam clamp
Enhancement arenas (GPU DMA aperture, Expansion-1 mod memory) were untracked, so Crash widescreen drew every vertex native with no depth. Adds depth stats/clear causes to pgxp, depth to pgxp_tri_ring, input_route_start at_frame, integer number keys in game.toml.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 13:20:27 -07:00
Matthew Stanley 456f6013d7 Clock the SPU from the guest cycle counter on every access
Games that read ENVX right after KEYON saw 0 until the per-frame pump and keyed the voice off (Crash spin sfx at 21:9).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 12:49:32 -07:00
Matthew Stanley 1e33a8b8ec Add build-time HLE tier for OpenGL textured batching and batch_sites flush attribution
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 11:19:42 -07:00
Matthew Stanley e4300a46e0 Add an always-on guest-cycle profile ring (gcp_ring)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 04:45:27 -07:00
Matthew Stanley 371a0a4396 Report the guest cycles an uncharged call executed
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 04:45:12 -07:00
Matthew Stanley 50747ae16d Merge PR #585: GL opt-in texture LOD + anisotropic filtering
# Conflicts:
#	docs/TCP_COMMANDS.md
#	docs/config_schema.md
#	generated/OpenBIOS.emitter.sha
#	recompiler/src/config_loader.cpp
#	recompiler/src/config_loader.h
#	runtime/CMakeLists.txt
#	runtime/src/debug_server.c
#	runtime/src/main.cpp
2026-10-08 23:04:04 -07:00
Matthew Stanley c92278e415 Merge PR #588: GL opt-in FMV chroma smoothing 2026-10-08 23:03:43 -07:00
Matthew Stanley 2f69a16370 Write guest implementation identity during configure 2026-10-08 17:00:09 -07:00
Matthew Stanley 29e647cebb Share build-selected guest HLE bindings and implementation metadata 2026-10-08 16:58:05 -07:00
Matthew Stanley 6fbd5a3462 Merge remote-tracking branch 'origin/master' into fix/tomba-session-capture-20261008
# Conflicts:
#	runtime/src/boot_state.c
2026-10-08 16:52:33 -07:00
Matthew Stanley c6dcdcf834 Expose snapshot implementation-tag support to title adapters 2026-10-08 16:44:47 -07:00
Matthew Stanley edb78e8391 Gate snapshots by build-selected implementation identity 2026-10-08 16:38:45 -07:00
Matthew Stanley 5d7837e991 fix(runtime): restore capture guards after nonlocal guest escapes 2026-10-08 15:39:01 -07:00
Shokunin ab13278bdf GL: opt-in FMV chroma smoothing for 24-bit MDEC frames
[video] fmv_chroma_smoothing = true makes the OpenGL present of a 24-bit
(MDEC) frame keep each sample's luma and take its chroma from a [1 2 1]
tent over the 3x3 source pixels, hiding the 2x2 colour blocks of 4:2:0
video without softening luma. Pairs with the existing fmv_filter upscale.
Guest VRAM/MDEC output untouched; 15-bit presents and the default unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:37:27 -07:00
Shokunin cf756f0b2d GL: opt-in texture LOD + anisotropic filtering for world textures
[video] texture_lod = "mipmap" emulates mip levels for PS1 texture pages,
which are decoded per fetch from VRAM and so have no GL mip chain: the
screen-space UV footprint of a minified, proven-3D primitive is box-averaged
(opaque texels of the fragment's STP class only), and anisotropic_filtering
(1..16) spreads that many taps along the footprint's major axis. Every tap
clamps to the primitive's UV bounds or texture window, so packed atlases
never bleed. The mode rides in the textured batch's filter key; off (the
default), sprites/HUD and magnified textures are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:01:07 -07:00
Matthew Stanley 62d26bff82 Fix redraw policy, HD reload residency, AA ownership and FG budget publication
Address objective review blockers in #563, #567, #576 and #580 on the combined renderer stack. Preserve redraw/default policy, bounded same-pack learned uploads, GL context ownership, and coherent current-window budget accounting. Add focused CPU, real-GL, concurrent-publication and authority-transition regressions.
2026-10-08 11:16:22 -07:00
Matthew Stanley d6652474fe Merge commit 'fe88727025' into integrate/pr558plus-fixes-20261008 2026-10-08 11:00:53 -07:00
Matthew Stanley c87b8deab6 Merge commit '33a4ff56b0f769cf37f2804d00dce2e4cb106408' into integrate/pr558plus-fixes-20261008
# Conflicts:
#	runtime/include/frame_gen.h
#	runtime/src/gpu_gl_renderer.c
#	runtime/src/main.cpp
2026-10-08 11:00:53 -07:00
Matthew Stanley 699cc5bb3e Merge commit 'cb8a2e617dd5edbe1dc3dafbfc82f1a48bf3d6f6' into integrate/pr558plus-fixes-20261008
# Conflicts:
#	docs/TCP_COMMANDS.md
#	generated/OpenBIOS.emitter.sha
#	runtime/src/main.cpp
2026-10-08 11:00:25 -07:00
Matthew Stanley 0662437c56 Merge commit '2b517f3a0529742647b4c12c1a6f3d4818b29d84' into integrate/pr558plus-fixes-20261008
# Conflicts:
#	runtime/include/gpu_render.h
#	runtime/src/gpu_gl_renderer.c
#	runtime/src/gpu_render.c
#	runtime/tests/gpu_hd_texture_stubs.inc
#	runtime/tests/test_gl_hd_texture_pack.c
2026-10-08 10:59:40 -07:00
Matthew Stanley a03b1cf413 Merge commit '08cf54a99a8155191623b54e4f3a5b5ae1249d1e' into integrate/pr558plus-fixes-20261008 2026-10-08 10:58:36 -07:00
Beman fe88727025 Fix MSVC dynres probe tokenizer linkage 2026-10-08 06:05:48 -07:00
Shokunin dbb8a86eee Host sampler: include <sys/ucontext.h> on macOS
<ucontext.h> stops with #error unless _XOPEN_SOURCE is defined, so
debug-tools runtime builds on macOS failed at host_sampler.c. The
sampler only needs ucontext_t's machine context, which
<sys/ucontext.h> declares without the deprecated routines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 06:05:48 -07:00
Shokunin 2b517f3a05 HD + render thread: keep the A0 hold across HD activation and savestate loads
Track an open GP0(A0) upload in the renderer whatever the HD state
(facade gr_vram_upload_begin/commit/set_open): HD activation mid-A0
waits for the commit instead of reading the FBO over received words,
and a full-VRAM load no longer ends the hold; gpu.c restores it from
gp0_state on load and ends it on GP1(01h). Sync the render thread
before flushing dumps or reading HD diagnostics, suppress dumps from
generated frames, use _putenv on MinGW, drop a stale log. Adversarial
fixtures for both cases in full-VRAM and high-resolution-window modes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 03:41:54 -07:00
Shokunin d06352b3e7 Smooth motion with HD texture packs
Generated frames are presentation only: their replayed draws skip the CPU
raster and the pack flush, and textured draws resolve the same HD
replacements as the real frame. Drop the HD gate on frame generation. The
HD fixture runs a 30 Hz game with generation off and forced on: real frames
and native VRAM are identical, and every generated frame shows the HD HUD.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 03:33:18 -07:00
Shokunin 988b85b73f Render thread: exact HD native-VRAM publication; lift the HD exclusion
A GP0(A0) under HD authority takes the context at its header and keeps it
until the payload commits, so gpu.c's array holds every earlier native draw:
unwritten words keep queued draws and mask checks see the prior native mask.
Publication copies the whole private VRAM (no A0 can be open then), and
render_thread_stop publishes the final private draws before freeing them.
HD replacements and dumping no longer refuse startup or park the thread;
Smooth motion stays off under HD. Adds the review reproduction and #570's
HD safety cases with the render thread running.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 03:33:18 -07:00
Shokunin 8f839e56f7 Render thread: publish the HD-authoritative VRAM at sync points
With an HD texture pack the CPU raster is native VRAM's authority, and on
the render thread it writes the private copy: gpu.c's array never saw those
draws, so guest readbacks, mask checks and savestates read stale VRAM. Each
acquire now copies the private result into gpu.c's array (the analogue of
ensure_cpu's FBO readback), leaving the words of a GP0(A0) payload that is
still streaming. Fixture: a recorded fill/draw is visible to a readback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 03:33:18 -07:00
Shokunin 64292bb23d Render thread: HD texture residency in command order
HD texture packs matched draws on the render thread but tracked uploads and
invalidations on the emulation thread, hashing gpu.c's array: a data race
(crash seen in hd_texture_pack_match) and wrong identities whenever the
emulation thread had already recorded a later upload.

The facade now sends residency changes through an optional backend hook
(hd_texture_note). The render-thread backend records them as RTH_HD_NOTE
after the upload/draw they follow; the replay hashes the render thread's own
VRAM copy, which the HD module now follows with the SW rasterizer
(gpu_hd_textures_bind_vram). Pack (re)configuration and HD mode changes are
sync points. Other backends apply the change immediately as before.

The HD GL fixture gains a render-thread case (fails without this change)
and links again: the scale fixture's facade stubs no longer collide with
the real gpu_render.c it includes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 03:33:17 -07:00
Shokunin 7d06942eb0 Dynamic resolution floor "display": the output's own lines
dynamic_resolution_min = "display" (game.toml, settings.toml,
PSX_DYNRES_MIN) floors the controller at the selected internal resolution
without the supersample factor, so with supersample > 1 it only trades
supersampling and never renders below the output. psx_dynres_floor_scale
in internal_resolution.h, tested in test_internal_resolution. OpenBIOS
emitter stamp regenerated (config_loader changed).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:40:17 -07:00
Shokunin 14feec22bf post_aa debug command: time the pass (PSX_POST_AA_TIME=N)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:40:10 -07:00
Shokunin 976da1a812 Opt-in post-process anti-aliasing (FXAA) and a supersample factor
[video] antialiasing_mode = "off" | "fxaa" | "fxaa_hq" (PSX_AA_MODE)
filters the composed game image after the game quad and before hold-last
capture, OSD and swap; guest VRAM, readbacks and the Smooth motion /
frame generation sources are untouched. Off (default) never runs the pass
and is byte-identical to master.

[video] supersample = 1.0..4.0 (PSX_SUPERSAMPLE) multiplies the internal-
resolution target (Match display or a line preset), so the existing area
resolve does ordered-grid SSAA; dynamic resolution takes it as its ceiling.

Debug server: post_aa reads/sets the mode live. Real-GL fixture
gl_post_aa_test; supersample checks in test_internal_resolution.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:39:59 -07:00
Shokunin e44d872964 Release builds: define psx_debug_toggle_key so debug_key links
debug_server.c is compiled in every build and its debug_key handler calls
psx_debug_toggle_key, which existed only under #ifndef PSX_NO_DEBUG_TOOLS.
Release now gets a stub that reports the keys as unavailable, like
psx_debug_display_aspect.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:39:56 -07:00
Shokunin a0cf9197f0 Debug-tools builds: live rendering A/B keys
PSX_DEBUG_TOOLS builds only (PSX_DEBUG_TOGGLES=0 turns them off). Keys flip one
rendering feature while the game runs and show the state on the OSD: 1 scale,
2 dynamic resolution, 3 widescreen, 4 Smooth motion, 5 texture filter,
6 wide mirror, 7 geometry correction, 8 perspective texturing, 0 summary,
9 PGXP depth, F10 PGXP colour, F11 PGXP seam, F12 PGXP CPU mode. The
debug_key TCP command presses one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:39:56 -07:00
Shokunin 4ba48c331f gl_frame_gen test: reprojection's depth switch is FG_RP_DEPTH
FG_PGXP now names the PGXP feature pass (#558-#560: none / depth / color
/ seam); the reprojection pass turns PGXP depth on with FG_RP_DEPTH=1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:39:42 -07:00
Shokunin 706cb0cdd5 gl_frame_gen test: rename near/far locals (Win32 macros); regenerate stamp
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:39:42 -07:00
Shokunin f3739b8495 Smooth motion: reprojection opt-in per title, redraw the default
[video] frame_generation_method = "redraw" (default) | "reprojection",
PSX_FRAME_GEN_METHOD overrides; replaces frame_generation_redraw.

- Redraw runs and allocates nothing of reprojection: no snapshots, depth
  image, programs, HUD matching; the cost-spike clamp and the dynamic
  resolution load formula apply to reprojection only. Switching to redraw
  or turning Smooth motion off frees what reprojection held.
- Uniform locations and PSX_RP_DEBUG/PSX_RP_NOPREV are read once with the
  programs.
- Each method gets its own breaker settings, set again on a switch;
  frame_gen_hold takes a kind (step down / over budget), not a string.
- The warp's depth is cleared before the cars are drawn (PGXP depth tested
  them LEQUAL against it).
- The warp restores the renderer's texture bindings on units 1 and 2 and
  never leaves a sampler on texture 0.
- gl_frame_gen_test: redraw asserts nothing of reprojection ran or was
  allocated (its phase 0.5 digest matches master's); reprojection runs
  check the warp's pixels on a parallax pan (vs the redraw of the pair, no
  holes, HUD exact), real frames unchanged, and no warp depth with PGXP.
- FRAME_GENERATION.md: the key, the default, reprojection and its
  R4-tuned object rules.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:39:42 -07:00
Shokunin bc74368c99 Reprojection: fit split-screen views with a third of the pairs; short breaker holds
A rival car filling half of a 2P view left fewer than half of the pairs
on the camera, rejecting ~7% of 2P game frames; reprojection redraws the
cars itself, so 30% inliers suffice. Overload holds are 0.1-1 s while
in-between frames are reprojected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:39:42 -07:00
Shokunin 754c8cc271 Reprojection: cars are textured objects that moved against the world; needles are small
Fixes the 2P band near the minimap: a 2D sky gradient that shifts with the
camera was treated as a HUD needle and drawn on top. Object-mode road
corners the camera alone explains are warped as world; only textured
triangles that really moved are redrawn as cars, after their view's first
world triangle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:39:42 -07:00
Shokunin 4085710323 Smooth motion: real frames cheaper; reprojection: HUD needle, split screen, outliers
- Dynamic resolution: Smooth motion's share inflates the measured cost
  instead of shrinking the period, so guest-bound detection works again
  (it had pinned the level at the ceiling).
- Cost estimate: a sample more than 4x the estimate counts as 4x (one
  stall no longer stops generation for many seconds); compiling the
  reprojection programs is outside the timed frame.
- Reprojection source: the surface snapshotted at the real frame's present
  (two slots: newer and older); the HUD and mirror of both lists are
  'keep' in the depth image, drawn last, so a HUD drawn after its list
  closed is kept too. Tunnel A/G/B worst ratio 2.9 -> 1.3.
- HUD needles: 2D triangles that move between the frames are drawn at
  their in-between position; under them the older frame's dial shows.
- Split screen: a view whose camera cannot be fitted keeps the real image
  instead of rejecting the frame (FgCamParams.keep_partial).
- Car redraw skips object triangles before the first world triangle (the
  sky dome). Redundant base copies skipped when reprojecting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:39:42 -07:00
Shokunin b0a89e4ede Smooth motion: in-between frames by reprojecting the real frame
Each in-between frame warps the newer real frame's finished image by the
in-between camera instead of drawing the scene again:
- per game frame: a snapshot of the list's finished image (taken when the
  list closes; R4 flips to a buffer before drawing into it, so the live
  surface is not a stable source) and a 2x native image of camera 1/z,
  pixel kind and view rasterized from the recorded triangles in painter
  order (world / car-or-dome / 2D-HUD-small-view);
- per in-between frame: one grid draw (a vertex per native pixel) that
  unprojects world pixels with their depth, moves them by the view's
  in-between camera (fg_view_affine) and samples the snapshot at full
  resolution, nearest wins; cells over depth edges or non-world pixels are
  left to the snapshot underneath; 2D/HUD pixels are put back; cars are
  drawn again at their own in-between position.
Measured: ~0.3-0.8 ms CPU and ~0.3-2 ms GPU per in-between frame (was 2-4
ms each), A/G/B max out-of-range 0.3-3 %, worst ratio 1.1-1.5.
[video] frame_generation_redraw / PSX_FRAME_GEN_REDRAW=1 keeps the old path.
Planner/holds: dynres 'over budget' no longer stops cheap reprojected
frames; guest-late trips ignored while they are cheap; allocation and
shader compilation are kept out of the cost estimate. frame_gen JSON:
rp_ms, rp_zn, reprojected, np (why a flip planned none); debug buffer 4 KiB.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:39:42 -07:00
Shokunin e723060a5d Merge feat/pgxp-seam (#558-#560) for the PGXP depth API the reprojection test uses
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:39:42 -07:00
Shokunin 4102438ab4 PGXP seam: above 1x only; expand only depth-tested triangles
- `wide` (mode 2) is half a native px above 1x and nothing at 1x, as the
  docs and `fine` already said.
- Expansion needs the triangle's depth mode 1 (opaque, 3D, depth buffer on,
  not near-camera); without depth, painter order resolves the overlap and a
  widened edge would draw over its neighbour.
- gl_renderer_set_pgxp_seam syncs with a live render thread (GL_RT_SYNC)
  and counts as a PGXP renderer feature.
- gl_frame_gen_test: seam alone draws exactly like no features; at 1x
  depth+seam draws like depth; at 3x it changes the image; the in-between
  frame at phase 1 still equals the real one with seam on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:39:19 -07:00
Shokunin 28fdd27b66 PGXP seam expansion for opaque 3D polygons (opt-in)
[video] pgxp_seam = "off" | "fine" | "wide" (default off; PSX_PGXP_SEAM,
PSX_PGXP_SEAM_PX). Above 1x, a vertex that sits on a neighbour's edge only to
the PS1's precision leaves a hairline crack. Opaque 3D triangles move each
edge outward (mitred, limited at sharp corners): fine = 1 output px, wide =
half a native px; UVs, colour, q and SZ extrapolate with the barycentric
coordinates of the new corners so textures do not slide.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:39:11 -07:00
Shokunin 7d56562066 PGXP colour: Smooth motion test covers it; setter syncs with the render thread
gl_renderer_set_pgxp_color_perspective syncs with a live render thread
(GL_RT_SYNC) and counts as a PGXP renderer feature for the per-triangle
depth command. gl_frame_gen_test's PGXP pass runs depth, colour and both:
the scene's SZ now differs per vertex (colour) with rows ordered far to
the right (depth), and the in-between frame at phase 1 must equal the real
frame with each.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:39:11 -07:00