Keep the requested internal resolution / supersample (shown and saved)
apart from what the backend last applied. When the live change is
unavailable (no GL, windowed high-resolution mode, CPU-authoritative dual
rendering, no context) or refused, the session scale is left as applied and
PSX_VIDEO_RESTART_RESOLUTION stays set, in both psx_video_apply_live and
the menu's restart bits (psx_host_video_restart_bits_backend, unit-tested
for the capable and refused cases). video_set rejects invalid presets and
factors without applying or saving, and reports applied values, capability
and pending restart. TCP command index regenerated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Narrow host_driver_vsync_unreliable() on Windows to the configuration the
stall was measured on: GL active, render thread running, GL_VENDOR NVIDIA,
not exclusive fullscreen. Other driver families and the unthreaded path
keep driver vsync; PSX_TRUST_DRIVER_VSYNC=1 still forces it everywhere.
Evaluated per call, so runtime renderer/fullscreen changes apply.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
psx_video_current reported the live scale as the legacy supersampling
factor, so a second live change looked like a legacy edit and asked for
a relaunch. Report the boot value. Debug-tools builds gain video_set
(internal_resolution, supersample) to drive the live path in tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Changing the internal resolution in the in-game menu did nothing until a
relaunch: ovl_video_from() never copied it, and the restart bits forced
a relaunch for it anyway. Supersampling (the [video] supersample
multiplier) had no player setting at all.
- PsxHostVideoSettings gains supersample_milli; internal resolution and
supersample are live changes (PSX_VIDEO_LIVE_RESOLUTION). Only the
legacy integer supersampling factor still needs a relaunch.
- psx_video_apply_live resolves the new scale and calls
gl_renderer_set_internal_scale_live(): it moves the step ceiling
(clamped like the boot scale) and queues the step through the dynamic
resolution machinery, recorded in stream order with the render thread.
The dynamic-resolution controller is retargeted to the new ceiling.
- settings.toml [video] supersample is the player's pick (1.0..4.0).
- The in-game menu round-trips internal_resolution and, with a launcher
that has RECOMP_LAUNCHER_HAS_SUPERSAMPLE, supersample_milli.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Windowed or borderless, DWM composes the window and owns the display's
vsync, so a driver swap interval only adds a stall. On NVIDIA (RTX 4080
SUPER, 610.88) a vsync'd SwapBuffers holds the GPU queue the render
thread submits to: every render-thread frame cost a full refresh
(16.7 ms "GPU" at any internal scale, render_busy 100 %), back-pressure
slowed the guest to 52-57 Hz, and dynamic resolution dropped for
nothing. Measured on R4 0.8 at 7680x4320, windowed and borderless: guest
60.0 Hz, render_busy 5-8 %, GPU 4.4 ms. Exclusive fullscreen keeps
driver vsync; PSX_TRUST_DRIVER_VSYNC=1 restores it everywhere.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep selector zero stock and seal all choices until the next session restart. Refuse nonzero online activation, scope non-stock save states by frozen choices, and preserve original instruction guards when combined with effective-address adapters. Use overlay ABI34 on current master without the old menu dependency stack.
Extract the audited adapters and card transport onto master without the held selector/menu stack. Keep adapters and codecs tied to mod activation, use overlay ABI 33, retain rejected-load protection on codec registration, and refuse extended-card codecs in netplay before frame zero. Preserve default atomic save publication and guest-visible write failures.
Keep temporary keyboard profiles separate from saved bindings. Add optional persistent mouse capture with ordered release/focus/reset handling, and let offline sources represent an unplugged port without falling back to physical input. Existing capture and source defaults remain intact. Beads: beads-9wg8 and beads-eio.19.18.
P1: quality_launcher_apply is now a pure preset -> rows mapping
(psxq::rows_from_runtime plus startup constants); it never writes the live
globals. The in-game menu publishes only thread-safe callbacks: that
mapper, and a re-detect that returns this session's detection (a fresh
probe needs the GL context and mutates the run's state, so it stays in the
pre-game launcher). Summary/reason strings and the detection are fixed on
the main thread at menu setup; settings_get reads only the main-thread
snapshot.
P2: psxq::MenuSelection keeps what the player selected versus what is live.
A pick's next-launch rows and netplay-deferred rows stay selected for the
next seed until the live value matches; other rows follow live. The host
classification moves to psxq::classify_launcher/row_differs (same rules).
Tests: quality_presets_test test_ingame_menu_host_path runs the review's
fixture through the host get/pick/apply/save path (Ultra -> High, then
Antialiasing = NONE; a governed edit is still Custom from High; a netplay-
deferred row stays selected). menu_quality_callbacks_test guards the
draw-thread callbacks against runtime writes and stateful calls.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mh_launcher_game_info publishes the presets (quality_fill_game_info),
mh_launcher_settings_get seeds the preset and the governed rows as in
force, and an applied menu change goes through quality_take_launcher, so
a pick or a governed edit is settled by the same save transaction
(settle_save) as the launchers. Shown rows apply live; preset-only keys
at the next launch.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- [quality.*] accepts only the supported keys (quality_key_supported):
twelve player-editable ones (masked, copied, classified, applied) and
nine preset-only ones (no settings.toml form; applied on select). Any
other key, e.g. vsync or renderer, is a load error.
- Picking a preset now also applies bloom, texture LOD, anisotropy, FMV
chroma smoothing and dithering (quality_apply_video_globals).
- The frontends flag Custom on any tracked row; the host counts only rows
of keys the title governs (psxq::launcher_custom_edit), so Antialiasing
no longer turns Ultra into Custom when no preset sets it.
Tests cover the rejection, every player key's masking/copy, and the
classification cases.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hands the launcher game info (pre-game launcher, soft return, and the
in-game menu's launcher_game_info) the [video] texture_filtering
vocabulary {Nearest, Bilinear, xBR} = PSX_TEXTURE_FILTER_{0,1,3}, so
frontends keep xBR across startup and soft return instead of collapsing
it to Bilinear. Needs a recomp_launcher.h with
RECOMP_LAUNCHER_HAS_TEXTURE_FILTER_CATALOG (recomp-ui); without it this
is a no-op.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The boot launcher, soft-return launcher and the in-game menu's live
settings now save settings.toml through psxq::settle_save:
- a one-run PSX_QUALITY override never persists: governed keys and the
quality_* keys come from disk, so the previous preset or Custom values
survive even when the boot seed was built empty;
- a governed live edit (psxq::live_edit) or launcher Custom becomes
Custom from the current base, with the edited values, and survives
restart instead of being masked away;
- a launcher pick records the preset; unrelated edits keep it.
Tests reproduce both review cases through a settings.toml round trip.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>