diff --git a/docs/TCP_COMMANDS.md b/docs/TCP_COMMANDS.md index 20dde483..b35d0529 100644 --- a/docs/TCP_COMMANDS.md +++ b/docs/TCP_COMMANDS.md @@ -55,6 +55,7 @@ Columns: **N** = native, **D** = DuckStation oracle. | `screenshot_wide_hires` | ✓ | | `path`, `base_x` | The displayed band of the native-wide surface at internal resolution (`wide_w×S` by `height×S`). `present_shot` is capped at the window; this checks a widescreen + internal-resolution combination at full size | | `present_shot` | ✓ | | `path` | PNG of the **composed present surface** — the frame after the backend fits the display buffer to the window, so it carries the presented aspect. ⚠ every other capture resolves the display buffer *before* that fit: on a 508×256 display in a 4:3 window they answer 508×256 while the player sees 640×480. Use this one for anything aspect-shaped (widescreen, letterbox), where a pre-fit buffer would hide the very stage the change touches. Staged and fulfilled on the next present, so the ack means *queued* — poll `present_shot_seq`. Unavailable headless and on the Vulkan backend (its swapchain has no readback hook) | | `present_shot_seq` | ✓ | | — | Completion counter for `present_shot`, plus `wrote` (1 = that completion produced a PNG). Sample before staging, poll until `seq` moves. Advances on success *and* failure, so the poll always terminates | +| `post_aa` | ✓ | | `mode` (optional: 0 off, 1 fxaa, 2 fxaa_hq) | Read or set post-process anti-aliasing live (`[video] antialiasing_mode`). Replies `mode`, `passes` (filtered presents so far) and `gpu_us`: the mean pass time since the last query when the run has `PSX_POST_AA_TIME=N` (N passes per present between `glFinish` fences, a measurement mode), else 0 | | `hd_textures` | ✓ | | optional `replacements`, `dump` (0 or 1), `reload` (1) | HD pack root, switches, backend support, replacement count, matched/ready/applied draw counts, and queued dump count. Optional controls update the configured host pack on the emulation thread; no configured root is an error. Reload retains unchanged upload identities. OpenGL displays replacements; software/Vulkan retain original artwork. Pair with `present_shot` for visual evidence and native VRAM probes for architectural data | | `gl_interp` | ✓ | | — | OpenGL frame-rate presenter ([FRAME_RATE.md](FRAME_RATE.md)): enabled/suspended, host and target Hz, swaps, `source` (`vblank`/`flip`), `flip_period`, `captures` (new source frames) and `duplicates` (VBlanks that re-presented the same frame) | | `render_pass_stats` | ✓ | | — | Render passes ([RENDER_PASSES.md](RENDER_PASSES.md)): plans, phases wanted/planned (shedding), passes, rollbacks (`nesting_repairs`: watchdog aborts whose skipped frame exits the restore undid), dropped device stores by class, `verify_mismatch` under `PSX_RENDER_PASS_VERIFY=1`, host-time split per pass, smoothed pass cost (`cost_us`; `cost_rewarms`: estimates no pass had run on for a while, measured again), presents made from pass images (`late_presents`: held past the frame's planned end because the next flip was late; `expired`: frames whose images stopped showing after several frame lengths without a flip), pass image textures allocated (`image_textures`, `image_bytes`), `status` (`psx_mod_render_pass_status`: 0 ready, 1 no presenter, 2 backend, 3 disabled, 4 session, 5 fast-forward, 6 busy), `backups_reused` (passes that reused the previous pass's VRAM backup), `spans` / `span_failures` and the last failure `span_fail` (`psx_mod_run_guest_span`: reason, exit PC, `$ra`, PC after a call that did not return) | @@ -711,6 +712,7 @@ Regenerate with `python tools/gen_tcp_commands.py`; `--check` fails if this bloc | `phase_hot` | ✓ | | | | `phase_profile` | ✓ | | ✓ | | `ping` | ✓ | ✓ | ✓ | +| `post_aa` | ✓ | | | | `present_image_ring_get` | ✓ | | | | `present_image_ring_stats` | ✓ | | | | `present_ring` | ✓ | | | diff --git a/docs/config_schema.md b/docs/config_schema.md index 16102b0d..d5f49aca 100644 --- a/docs/config_schema.md +++ b/docs/config_schema.md @@ -604,6 +604,43 @@ the pixels to show it. Native keeps the window exactly as before. downsamples to the window. It accepts 1 to 32 in both `game.toml` and the player's `settings.toml`; 1 (the default) is native and unchanged. +### Anti-aliasing (`antialiasing_mode`, `supersample`) + +Both are opt-in and change nothing unless set. + +```toml +[video] +supersample = 1.5 # 1.0..4.0, default 1.0 +antialiasing_mode = "fxaa" # off (default) | fxaa | fxaa_hq +``` + +`supersample` multiplies the target of a line preset or Match display before +it becomes a scale: Match display on a 1080 px monitor with 2.0 asks for 2160 +lines (S = 9) and the present's area resolve brings it back to 1080, which is +ordered-grid SSAA of everything, 2D included. Native and the legacy +`supersampling` factor are left alone. Dynamic resolution takes the result as +its ceiling and steps under it as before. `PSX_SUPERSAMPLE=` overrides +it for one run. + +`antialiasing_mode` filters the composed game image on OpenGL: after the game +quad (4:3, native-wide, Smooth motion and generated frames alike) and before +hold-last capture, the OSD, screenshots and the swap. It reads only output +pixels, so guest VRAM, readbacks, render passes and the Smooth motion sources +are untouched; the bezel and OSD stay sharp; 24-bit FMV frames are not +filtered. `fxaa` is one copy and one full-screen pass (about 0.1 ms at 1080p +on an M4); `fxaa_hq` lowers the contrast threshold and searches further along +long edges. `PSX_AA_MODE=off|fxaa|fxaa_hq` overrides it for one run and the +`post_aa` TCP command switches it live. The older boolean `antialiasing` key is +unrelated: it is the linear present filter the launcher already persists. + +Not offered: MSAA. The hi-res surface *is* guest VRAM (texture pages, CLUTs, +VRAM copies, readbacks and the mask stencil all sample or copy it between +draws), so a multisampled target would need a resolve before every one of +those and the mask/semi-transparency rules would have to run per sample; that +is a renderer redesign, not an option. SMAA needs its area/search lookup +textures and three passes; on an image that is already area-resolved from a +higher internal resolution it buys little over FXAA, so it is left for later. + The runtime clamps N per backend: - Software and Vulkan stop at 4.