Commit Graph

2013 Commits

Author SHA1 Message Date
Matthew Stanley f4c5d6c93f Draw paused host menus even before the first held game frame 2026-10-14 11:47:04 -07:00
Matthew Stanley 656aa1d35f Register shared menu snapshot coherence regression 2026-10-14 11:31:46 -07:00
Matthew Stanley 934e6c96b6 Synchronize shared menu video and netplay getters across runtime threads 2026-10-14 11:29:13 -07:00
Shokunin 83f1468860 In-game menu host: a provider-neutral contract (psx_menu_host.h)
psxrecomp owns the contract between the runtime and any in-game menu
frontend. A provider (PsxMenuProvider: attach, event, is_open, set_open,
draw, detach) is registered by the title with psx_menu_set_provider();
none is registered by default, so a title's UI and pin are unchanged.
The runtime offers every provider the same host (PsxMenuHost): pause
(P1, refused in netplay), video get/apply on PsxHostVideoSettings (P4),
mod switch/option set (P5, via the new psx_mod_feature_enable /
psx_mod_feature_set_option shared with the launcher ABI provider),
reload bindings, exit (quit, back to the frontend loop in-process, or a
quick relaunch with the original arguments), disc/tray slots filled by
the tray policy (psx_menu_set_disc_ops), and optional helpers on the
shared launcher ABI both frontends already speak (game info with the
mod catalogue and lobby, settings get/apply with the handoff's filter
translations).

Policies live here, the same for every provider: the lobby is pumped
during play and a started match ends the local session and starts in
the frontend loop (pending launch, seats and signals kept, pumping
stopped so the match port stays free), the menu is closed and its pause
dropped first; the provider detaches before its GL context goes away at
session teardown and attaches to the next one. --launcher sets
RECOMP_LAUNCHER_PREGAME for frontends that boot into the game;
PSX_HIDDEN_WINDOW is a hidden-window test hook that keeps the frontend.
Nothing here includes or names a frontend's own headers or types.
Tests: psx_menu_host_test, host_overlay_test (relaunch quoting).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:02:57 -07:00
Shokunin df0f36adde Live mod options: overrides end with their session's plan
Review (#602): live_option_values() was process-static and never cleared, so
an override set in one session outlived mod_runtime_initialize and a new
committed plan (committed 'eight', API still answered the old 'four'). Every
plan change -- initialise, commit, the netplay plan (vanilla or negotiated)
-- now drops the overrides. test_mod_runtime: a second session answers its
own committed value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:02:57 -07:00
Shokunin e5542c6879 Live mod options: keep a value only after a callback accepts
Review (#602): psx_mod_set_option_live stored the new value before any
callback ran, so a refusal ("nothing changes until next start") still
changed what psx_mod_option_value answered. The value is visible to the
callbacks while they run and is rolled back unless one accepts. New
test_mod_runtime case: a refusing callback leaves the running value as is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:02:57 -07:00
Shokunin 5b454f3db0 Live mod options: psx_mod_save_selection writes state.toml without re-planning
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:02:57 -07:00
Shokunin a32471d5fd Live mod options: restart-only changes do not reach the running plugin
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:02:57 -07:00
Shokunin 00671ce845 Live mod options: psx_mod_option_live_capable
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:02:57 -07:00
Shokunin f739d1feb7 Live mod option changes (in-game overlay P5)
psx_mod_set_option_live records a session override for a committed
feature's option and calls the plugin's new option-changed callback in
that plugin's context; psx_mod_option_value answers the override. It
returns 1 when applied live, 0 when the change waits for a restart, -1
during netplay (the plan is negotiated between peers). Nothing changes
unless an overlay calls it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:02:57 -07:00
Shokunin 3534e21aa5 Live video apply: use master's texture-filter enum (#655) instead of a copy
#655 landed the same PSX_TEXTURE_FILTER_* enum and translation in
video_texture_filter.h/.c; drop this PR's duplicate (link error) and
include that header.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:02:57 -07:00
Shokunin 0f09935c23 Live video apply: one texture-filter enum for settings, handoff and menu
Review (#601/#603): the live path and the launcher handoff both collapsed
the texture filter to a boolean (value ? 1 : 0), so neither could carry xBR
(#586) and they could drift from settings.toml. PSX_TEXTURE_FILTER_* is now
the one enum (equal to [video] texture_filtering / gr_set_texture_filter),
and psx_texture_filter_from_ui is the one translation used by the launcher
handoff (seed, UserSettings, live globals) and the in-game apply. Unit-
tested in host_overlay_test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:02:57 -07:00
Shokunin 09144c8c31 Live video apply: netplay guard, persist every field, build in Release
Review (#601):
- psx_video_apply_live had no netplay guard. In a match only presentation
  (fullscreen, scanlines, linear present) applies live; dynamic resolution,
  frame generation and the filters are saved and reported with the new
  PSX_VIDEO_RESTART_NETPLAY bit (next session).
- internal_resolution and present_thread are written to UserSettings like
  the other restart-only fields, so the choice survives a restart.
- The live-apply code sat inside #ifndef PSX_NO_DEBUG_TOOLS but is used by
  the launcher path, so Release + launcher did not compile. It now lives
  outside the debug-tools block.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:02:57 -07:00
Shokunin ca3994e86d Live video apply (in-game overlay P4)
psx_video_apply_live applies the [video] keys a running game can change
(fullscreen, texture and FMV filter, scanlines, linear present, dynamic
resolution, frame generation) through the existing live setters, saves
them to settings.toml, and reports renderer / internal resolution /
thread changes as restart-only. Nothing calls it without a provider.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:02:57 -07:00
Shokunin 4cda11d207 Input sink: the netplay admit wait routes events to the overlay first
The admit barrier polls SDL every frame of a netplay match and treated
Esc as "leave the match" before the in-game overlay saw it, so opening
the menu online could end the session (netplay_barrier_escape).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:02:57 -07:00
Shokunin c73b34d578 Overlay input: service the overlay in the low-latency re-drain
Review (#600): with low_latency_input on, the re-drain after the pacer
wait sampled the pad without host_pause_service, so ui_capture was a frame
stale and the overlay's opening chord (Start+Select) could reach the guest
for one frame. The re-drain now services the overlay before the sample.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:33:32 -07:00
Shokunin 475a3ad6c5 Debug host_mouse: inject a click or wheel step at a window point
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:33:32 -07:00
Shokunin e21226feb7 Overlay input sink and UI capture gate (in-game overlay P3)
psx_host_set_input_sink: an overlay provider sees host SDL events first,
in the event drain and the host pause loop, and may consume them.
psx_host_set_ui_capture: while on, local game input reads released and
centred (netplay included, so peers receive "nothing pressed") and the
external-input gate stays closed. Debug builds gain host_key, which pushes
a real SDL key event for scripted runs. Inert without a provider.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:33:32 -07:00
Shokunin facdf01ac6 Overlay draw callback: unregister waits for in-flight draws (lifetime contract)
Review (#599): who keeps the callback context alive until render-thread
calls are quiescent. Draw calls now run inside an in-flight count, and
set_draw_cb (replace or NULL) swaps the record and waits until no call
that read the old one is running, then frees it. When it returns, the
registrant may free ctx and its GL objects; it must unregister before
destroying them or the context. A change from inside the callback does
not wait. Documented in host_overlay.h. Tests: a reader thread drawing
while the owner unregisters and frees (300 rounds; fails without the
wait), and self-unregister from the callback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:33:29 -07:00
Shokunin 8b003a591d Overlay draw callback: publish fn+ctx atomically; link it in GL fixtures
Review (#599): fn and ctx were two separate stores read on the render
thread, so an unregister could pair a live fn with a NULL ctx. They are now
one immutable record behind an acquire/release atomic pointer. The GL
fixture runners compile a fixed source list; gpu_gl_renderer.c now calls
psx_host_overlay_draw, so every run_gl_*.py links host_overlay.c.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:33:29 -07:00
Shokunin 153279824a Overlay draw callback (in-game overlay P2)
psx_host_overlay_set_draw_cb: the OpenGL backend calls it after the game
frame and host OSD layers are composed, before present_shot capture and
the swap, on the thread that owns the GL context. Without a registered
callback nothing changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:33:29 -07:00
Shokunin 5c8a0c2d60 Host pause: re-anchor pacing on resume; hold the guest headless too
Review (#598): resuming left the frame pacer's deadline in the past, so it
paid a pause back as up to ~12 unpaced frames. Resume now runs
present_session_reset, an audio cycle resync and a dynamic-resolution hold,
as a savestate load does. host_pause on=1 headless was a no-op that answered
ok; the headless frame path now enters host_pause_loop too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:33:17 -07:00
Shokunin 138b44a58e Host pause API (in-game overlay P1)
psx_host_pause_push/pop: a nesting, host-owned pause. While it is held the
runtime freezes the guest at the vblank present (as the save-state menu
does), keeps presenting the last frame and pauses audio. Push refuses
during netplay. Nothing pushes unless an overlay provider (or the debug
server's new host_pause command) asks, so behaviour is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:33:17 -07:00
Matthew Stanley 1473c66772 Merge validated renderer fixes into generic post-effect pipeline 2026-10-13 10:18:03 -07:00
Matt Stanley 081aeb1ada Merge pull request #619 from FractalEngineer/feat/vr-desktop-mirror
VR: desktop spectator mirror of the headset eye view
2026-10-13 10:12:34 -07:00
Matt Stanley 6eaf078699 Merge pull request #584 from RetroPortingToolKit/feat/gl-dithering
GL: PS1 dithering by default (native grid), elective fine/off modes
2026-10-13 10:10:53 -07:00
Matt Stanley 7b12bd9ef1 Merge pull request #596 from RetroPortingToolKit/perf/gl-pbo-upload
GL: upload the HD-authoritative raw mirror through a pixel-unpack buffer
2026-10-13 10:09:44 -07:00
Matt Stanley a042ed00c8 Merge pull request #610 from RetroPortingToolKit/feat/netplay-host-output
Mod plugins: netplay = "host_output" (read-only hooks stay on online)
2026-10-13 10:09:37 -07:00
Matt Stanley 2095249191 Merge pull request #640 from RetroPortingToolKit/fix/display-ring-full-frame
display_ring_get: whole display (480i, depth24) from the frame VRAM snapshot
2026-10-13 10:09:30 -07:00
Matt Stanley 20d31bea1a Merge pull request #639 from RetroPortingToolKit/fix/cue-sector-geometry
Disc geometry from cue TRACK mode / sector-0 sync, never file length
2026-10-13 10:09:23 -07:00
Matt Stanley 53898b958a Merge pull request #635 from RetroPortingToolKit/fix/spu-restore-phase
SPU: anchor the restored sample phase to the restored clock at load
2026-10-13 10:09:17 -07:00
Yves c27abb3b05 VR: desktop spectator mirror (single eye, on by default)
The window shows the live XR eye textures while a session runs, so the headset view can be watched on the monitor. Default is the left eye filled to the window; PSX_VR_DESKTOP_MIRROR selects 0 (keep the legacy desktop presentation, the side-by-side pair), 1 left (default), 2 side-by-side, 3 right. Uses the exact textures submitted to the runtime.
2026-10-14 00:58:53 +08:00
Shokunin 8dbe2165ff bloom: cost of real and generated frames
Smooth motion lost most of its generated frames with bloom on (R4 race,
120 Hz: ~30% of bloom-off). Measured and fixed in order of cost:

- Depth-stencil blits (CPU milliseconds each on macOS) are gone:
  generation surfaces no longer copy the marks and are not marked while
  drawn (generated frames reuse the newer real frame's mask); the
  native-wide centre copy is colour only again and the mask takes the
  centre's marks from the hr surface; the mask itself is resolved in the
  presented surface's own pixels through an R8 target that shares the
  surface's depth-stencil renderbuffer, then mapped to the window.
- Marking needs one pass per batch, not two: 3D batches only set, 2D
  opaque ones only clear, semi-transparent ones only set; only batches of
  unknown make (queued replays, lines) still do both.
- No full-size copy of the image: `source_down` (a blit straight to the
  pass's size) feeds the bright pass, and the composite screen-blends onto
  the window (`blend screen`; unlit pixels are discarded, so they keep their
  exact value). The debug split/bloom-only views go with the copy.

M4, R4 race, render thread + reprojection, PSX_FRAME_GEN_FORCE, a host
loaded by other work (absolute rates low): bloom pass on real / generated
frames 1.2 / 0.7 ms at 1080p, 1.3 / 0.9 ms at 1440p, 2.6 / 1.6 ms at 4K
(glFinish-bracketed); generated frames with bloom 79-80% of bloom-off at
all three (was ~30%). A 1/8-resolution blur chain was tried and kept no
more frames, so the 1/4 chain (the look) stays.

Tests: parser (blend, source_down, bloom preset reads no full copy), GL
fixture (source_down + blend screen chain exact; HUD and mask checks
unchanged), FXAA unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 04:03:35 -07:00
Shokunin de8d286180 Dithering: native-grid pattern is the default, internal-pixel is elective
Review of #584: the default must not make guest-visible VRAM depend on the
internal scale. Mode 1 ("on", default; "scaled" kept as an alias) now
puts the PS1 pattern on the native VRAM grid; mode 2 ("fine") is the
elective per-internal-pixel pattern. gl_dithering_test checks the default
mode's native VRAM is identical at 4x and 1x (equal-colour Gouraud now
averages 15.50 in the default at every scale). Docs keep the
semi-transparent approximation explicit. OpenBIOS stamp regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:18:29 -07:00
Shokunin abbae48947 Dithering on by default with explicit per-primitive eligibility
Maintainer review of #584: PS1 dithering is hardware behaviour, so it is
now on by default whenever the guest sets GP0(E1h) bit 9 ([video]
dithering = "on"; "scaled" stays opt-in, "off" is the old true-colour
output).

Eligibility is decided per primitive from its command and carried in the
vertex instead of being inferred from the colour:
- Gouraud polygons and shaded lines: geometry vertex a_col.a + 2*131072
  (decoded in GEO_VS, v_dith);
- texture-modulated polygons: a_semi + 8 (v_dith in TEX_VS);
- flat polygons/lines, raw-texture polygons and every rectangle: never.
This fixes the two reproduced bugs (Gouraud with 5-bit-exact colours was
skipped; textured rectangles were dithered). Bit changes no longer flush:
eligibility is fixed when the primitive is queued; mode changes still drain.

gl_dithering_test covers each case (Gouraud incl. equal colours, shaded
line, modulated and neutral-modulated textured polys dithered; flat tri,
flat rect, flat line, raw poly, modulated and raw textured rects never;
bit clear and off unchanged), plus scaled 4x == 1x, render thread, PGXP
depth, native-wide and the accurate-blending basis. OpenBIOS stamp
regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:18:29 -07:00
Shokunin b3d24a4796 gpu_gp0_history_guard_test: stub gr_set_dither
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:18:29 -07:00
Shokunin 023af6d9d4 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-13 02:18:29 -07:00
Shokunin 5c1d27bf17 post effects: a failed pass is not rebuilt every present; binary fixture files
pfx_stage_load checked loaded before failed, so a preset whose pass did not
compile was rebuilt on every present. failed is checked first; setting
[video] post_shader again (same path or not) reloads and clears it. The GL
fixture presents once more and checks no rebuild happened; the parser
fixture writes its sample files in binary mode (LF byte-exact on Windows).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:15:46 -07:00
Shokunin 8eccea1612 post effects: no per-frame GL queries; CRLF presets tested
- Uniform locations are looked up once per program (each lookup can be a
  driver round trip on a threaded GL; the executor runs per present,
  generated frames included).
- State save queries only capability flags and the viewport. The mask pass
  no longer clears (it draws 0 then 1), so the clear colour is never
  touched; the present's window target and texture unit 0 are left bound.
  The GL fixture checks exactly that contract.
- postfx_chain_test: a preset with CRLF line ends parses the same, and the
  import check writes its shader in binary mode (it failed on Windows).
- docs/POST_EFFECTS.md: `generated reuse`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:15:46 -07:00
Shokunin 18e10693c4 post effects: MinGW build fix, generated frames reuse bloom's glow, no glGet in marking
- config: [video] post_shader is a std::filesystem::path (like memcard_dir);
  the frontend turns it into UTF-8 bytes for the GL API. Assigning the path
  to a std::string did not compile on MinGW.
- .pfx `generated reuse`: a Smooth motion generated frame keeps that pass's
  target from the last real frame. The bloom preset marks its bright and
  blur passes so; generated frames run only the masked composite (over their
  own picture and mask). bloom debug reports real/generated pass times and
  reused passes.
- Mask marking no longer queries GL state per batch: each call site puts
  back the blend and mask-bit stencil it set (no driver round trips on the
  render thread).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:15:46 -07:00
Shokunin 74dadc6004 GL: one post-effect pipeline; bloom and FXAA as built-in chains, user chains via [video] post_shader
Post effects now run as chains of full-screen fragment passes on one
executor (gl_postfx.inc), as asked in review. A chain is a small .pfx preset
(postfx_chain.c, GL-free): passes with a shader (a file next to the preset or
builtin:<name>), inputs (source, the optional primitive-derived mask,
previous or a named earlier pass), a scale, format, filter and uniforms.
The executor owns target allocation and lifetime, program build/cache,
uniform binding (u_rcp, u_size, u_org) and GL state save/restore.

Stages, in order, each from a fresh copy of the image: the built-in "bloom"
chain ([video] bloom), a user chain ([video] post_shader / PSX_POST_SHADER,
elective, off by default), and the built-in "fxaa"/"fxaa_hq" chain
([video] antialiasing_mode). FXAA folds in as a one-pass chain and its
output is byte-identical to the former fixed pass; it still runs on real
frames only. Generated (Smooth motion) frames run bloom and the user chain.

The "may glow" mask is an optional pipeline input: draws keep stencil bit 1
only while an active chain reads `mask`, and the window-sized mask texture is
built once per present for the chains that use it.

Tests: postfx_chain_test (format, built-ins, errors, file import, no GL);
gl_bloom_test gains an imported two-pass chain (byte-exact invert), the mask
input (HUD unlit, 3D lit), a bad preset, a pass that does not compile, and GL
state restored with bloom + a mask chain + FXAA on, all on the caller thread
and the render thread. docs/POST_EFFECTS.md documents the format.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:15:46 -07:00
Shokunin e730e03a8a GL: opt-in bloom ([video] bloom), sourced from 3D and additive primitives only
[video] bloom = 0.0 (off, default) .. 2.0 adds a glow around lights on the
OpenGL backend. PSX_BLOOM overrides it for one run; {"cmd":"bloom"} reads or
changes strength, threshold and a debug view live. It is a plain [video] key,
so [quality.*] presets can switch it off on low-end machines.

The HUD never glows: with bloom on every textured and untextured draw is
followed by two stencil-only passes of the same vertices that keep a
"may glow" mark in stencil bit 1 (bit 0 stays the mask-bit mirror). Opaque
primitives clear it under their coverage, then PGXP-proven 3D primitives and
additive semi-transparent texels/primitives (modes 1 and 3) set it, painter
ordered like the colour; 3D and non-3D primitives never share a batch while
bloom is on. Semi-transparent primitives leave the mark alone and the PGXP
depth-clear pass (colour writes off) marks nothing. Without PGXP geometry only
additive primitives glow.

The pass runs on the composed game image before AA and the OSD: the presented
surface's marks are blitted into a quarter-resolution stencil, a soft-knee
bright pass runs under it, three separable Gaussian iterations spread it and a
screen blend adds it back. The marks follow the picture: native-wide centre
copies and Smooth motion surfaces (redraw and reprojection) copy stencil with
colour, and generated frames get the same pass. Off: nothing runs, no state
changes, and the composed frame is byte-identical to master.

test_gl_bloom (gl_bloom_test): off is byte-identical before/after bloom and
with --dump against master; on, a bright 2D panel and a panel over a lit 3D
polygon are byte-identical to off, an additive and a 3D polygon glow; guest
VRAM is unchanged; on this thread and on the render thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:15:46 -07:00
Matt Stanley 7b3b1ea286 Merge pull request #654 from RetroPortingToolKit/fix/gl-present-ring-restart
Debug present ring: forget GL names when the renderer shuts down
2026-10-13 01:31:20 -07:00
Matt Stanley 035af4e444 Merge pull request #592 from RetroPortingToolKit/feat/linux-tcc
Linux releases bundle TinyCC (built from source) with musl headers
2026-10-13 01:31:14 -07:00
Shokunin dbe4be60d3 GL scale fixture: drop duplicate stubs that slipped into 9720528c
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 01:29:49 -07:00
Shokunin 9720528c1a GL fixtures: inert psx_mod_host_output_scope for mod_texture_banks.c
The GL fixtures (scale invariance, texture filter / bloom, render thread,
frame gen, readback) include mod_texture_banks.c, which now asks
psx_mod_host_output_scope(); define it as 0 (no host-output hook runs there).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 01:26:41 -07:00
Shokunin 4c2e703f12 Present ring reset after the render thread stops; fixture covers the worker
Review (#654): forget the ring's names after gl_renderer_render_thread_stop
(the worker presents and captures on its own thread, and stop drains it
and hands the context back), before the context is deleted. The call is
unconditional (an empty stub without debug tools). The fixture adds a
render-thread pass: frames captured on the worker and drained, more left
queued at shutdown, then checks the worker stopped first and every name
and pending readback is gone. Fails if the reset runs before the stop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 01:22:15 -07:00
Shokunin 47fb2af915 Launcher handoff: keep the texture filter enum (xBR no longer becomes bilinear)
The seed path collapsed ls.texture_filter to a boolean, so a launcher's
xBR (3) was saved and applied as bilinear, and the rematch paths passed
the raw value through unchecked. psx_texture_filter_from_ui is now the
one translation (in-range values pass, others are nearest). Test:
video_texture_filter_test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:06:00 -07:00
Shokunin d4a2f6afdb gl_present_ring_restart_test: ring names do not outlive the GL context
Hidden-GL fixture: presents build the ring, shutdown must forget every
name and pending readback, and a second context rebuilds live objects.
Fails without the fix (names kept). run_gl_texture_filter.py gains
--debug-tools to compile the ring in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:05:10 -07:00
Shokunin 09f10143e4 Debug present ring: forget GL names when the renderer shuts down
After a renderer restart (lobby rematch, in-game menu -> match) the
capture read back into a stale pack-buffer name, i.e. into client memory
at offset 0, and crashed in glReadPixels (debug-tools builds).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:03:50 -07:00