mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 18:25:35 -04:00
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>
This commit is contained in:
@@ -62,6 +62,7 @@ Columns: **N** = native, **D** = DuckStation oracle.
|
||||
| `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 |
|
||||
| `fmv_chroma` | ✓ | | `on` (optional: 0/1) | Read or set `[video] fmv_chroma_smoothing` live. Replies `on` and `frames` (24-bit presents smoothed so far) |
|
||||
| `texture_lod` | ✓ | | `mode` (optional: 0 off, 1 mipmap), `aniso` (optional: 1..16) | Read or set `[video] texture_lod` / `anisotropic_filtering` live. Replies `mode`, `aniso` |
|
||||
| `dithering` | ✓ | | `mode` (optional: 0 off, 1 on, 2 scaled) | Read or set `[video] dithering` live. Replies `mode` |
|
||||
| `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, queued/pending dumps, composition hits/builds/pixels, GL uploads/evictions, decoded images/evictions/bytes. 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) |
|
||||
@@ -491,9 +492,9 @@ between Play and TCP availability.
|
||||
|
||||
## Complete command index (generated)
|
||||
|
||||
**369 commands registered** — 356 on the native server (`runtime/src/debug_server.c`), 61 on the Beetle server (`runtime/src/beetle_debug_server.c`).
|
||||
**371 commands registered** — 358 on the native server (`runtime/src/debug_server.c`), 61 on the Beetle server (`runtime/src/beetle_debug_server.c`).
|
||||
|
||||
82 of 369 have prose above; **287 are index-only**. An index-only command still works — it just has no description here yet. Send it `{"cmd":"<name>"}` and read the reply, or find its `handle_*` function in the server source.
|
||||
83 of 371 have prose above; **288 are index-only**. An index-only command still works — it just has no description here yet. Send it `{"cmd":"<name>"}` and read the reply, or find its `handle_*` function in the server source.
|
||||
|
||||
Regenerate with `python tools/gen_tcp_commands.py`; `--check` fails if this block has drifted from the code.
|
||||
|
||||
@@ -579,6 +580,7 @@ Regenerate with `python tools/gen_tcp_commands.py`; `--check` fails if this bloc
|
||||
| `display_ring_aux` | ✓ | | |
|
||||
| `display_ring_get` | ✓ | | |
|
||||
| `display_ring_stats` | ✓ | | |
|
||||
| `dithering` | ✓ | | ✓ |
|
||||
| `dma_cdrom_history` | ✓ | | |
|
||||
| `dma_hold_ring` | ✓ | | ✓ |
|
||||
| `dma_hold_stats` | ✓ | | ✓ |
|
||||
@@ -654,6 +656,7 @@ Regenerate with `python tools/gen_tcp_commands.py`; `--check` fails if this bloc
|
||||
| `history` | ✓ | ✓ | ✓ |
|
||||
| `hle_dump` | ✓ | | ✓ |
|
||||
| `host_launch_timings` | ✓ | | ✓ |
|
||||
| `host_osd_shot` | ✓ | | |
|
||||
| `host_profile` | ✓ | | |
|
||||
| `idle_skip` | ✓ | | |
|
||||
| `imask_trace` | ✓ | | |
|
||||
|
||||
@@ -725,6 +725,31 @@ first layer's full 8-bit result where the console would have truncated it to
|
||||
5 bits first (at most one 5-bit step). OpenGL only.
|
||||
`PSX_ACCURATE_BLENDING=0|1` overrides it for one run and the
|
||||
`accurate_blending` TCP command switches it live.
|
||||
### Dithering (`dithering`)
|
||||
|
||||
```toml
|
||||
[video]
|
||||
dithering = "off" # off (default, true colour) | on | scaled
|
||||
```
|
||||
|
||||
The PS1 GPU adds a 4x4 offset pattern to shaded and texture-modulated pixels
|
||||
before truncating them to 5 bits per channel, when the game sets GP0(E1h)
|
||||
bit 9. The OpenGL renderer has always drawn those pixels at 8 bits per channel
|
||||
with no pattern ("true colour"), and `off` keeps exactly that. `on` applies
|
||||
the PS1 pattern and 5-bit truncation per internal-resolution pixel (a fine
|
||||
grain that all but vanishes at high scales); `scaled` puts the pattern on the
|
||||
native pixel grid, so it looks like the console at any scale and the native
|
||||
VRAM a game reads back is the same at every internal resolution. Flat fills,
|
||||
flat polygons and raw textures are already 5-bit exact and are never touched.
|
||||
The pattern is applied to the source colour before semi-transparent blending;
|
||||
the console dithers the blended result at its final 8-to-5-bit write. Fixed-
|
||||
function GL blending cannot run a shader after the blend (GL 3.3 has no
|
||||
framebuffer fetch, and macOS offers none), so a dithered semi-transparent
|
||||
pixel can differ from the console by one 5-bit step; opaque pixels match.
|
||||
The dither output follows the surface basis, so it composes with
|
||||
`accurate_blending`.
|
||||
OpenGL only. `PSX_DITHERING=0|1|2` overrides it for one run and the
|
||||
`dithering` TCP command switches it live.
|
||||
|
||||
### Texture filtering (`texture_filtering`)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user