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:
Shokunin
2026-10-08 13:58:37 -07:00
parent 0b82ce5bf6
commit f14af5594d
14 changed files with 356 additions and 9 deletions
+5
View File
@@ -306,6 +306,11 @@ int gl_renderer_anisotropy(void);
* uploads and untextured primitives already are). On by default. */
void gl_renderer_set_accurate_blending(int on);
int gl_renderer_accurate_blending(void);
/* [video] dithering: 0 off (true colour, default), 1 PS1 dither pattern at
* internal resolution, 2 pattern scaled to the native pixel grid. Applies to
* shaded/modulated draws while the guest's GP0(E1h) dither bit is set. */
void gl_renderer_set_dithering(int mode);
int gl_renderer_dithering(void);
int gl_renderer_get_pgxp_depth(void);
void gl_renderer_set_pgxp_color_perspective(int on);
int gl_renderer_get_pgxp_color_perspective(void);
+4
View File
@@ -61,6 +61,9 @@ void gr_set_precise_triangle(int enabled,
* perspective_texturing). q[i] is the normalized 1/z homogeneous weight at
* vertex i. enabled == 0 restores the PS1's affine UV interpolation. */
void gr_set_perspective_triangle(int enabled, float q0, float q1, float q2);
/* GP0(E1h) bit 9 (dither enable). Only a backend with [video] dithering
* implements it; the default renderers stay true colour. */
void gr_set_dither(int enabled);
/* PGXP depth for the NEXT triangle (docs/ENHANCEMENTS.md G1.14): the GTE SZ
* of each vertex (1..65535), taken from validated dataflow shadows. Only a
* backend with a PGXP depth buffer / perspective-correct colour uses it;
@@ -167,6 +170,7 @@ typedef struct GpuRenderBackend {
int32_t x1, int32_t y1,
int32_t x2, int32_t y2);
void (*set_perspective_triangle)(int enabled, float q0, float q1, float q2);
void (*set_dither)(int enabled); /* optional: GP0(E1h) bit 9 */
void (*fill_rect)(int x, int y, int w, int h, uint16_t color);
void (*copy_rect)(int src_x, int src_y, int dst_x, int dst_y, int w, int h);
void (*draw_flat_triangle)(int x0, int y0, int x1, int y1, int x2, int y2,