summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-14 13:34:04 +0900
committerAdam Malczewski <[email protected]>2026-06-14 13:34:04 +0900
commit4e0b07cecd1dc5cbd4fcabe05cbcfc897ce6dc43 (patch)
treee33ab068f9c6840a0dc180de676d961d0110840a
parent18bcca4f820aca68c6f50c4d59b66d73f0d0970d (diff)
downloadunbox-4e0b07cecd1dc5cbd4fcabe05cbcfc897ce6dc43.tar.gz
unbox-4e0b07cecd1dc5cbd4fcabe05cbcfc897ce6dc43.zip
kernel: dither gradient shader to kill 8-bit banding (TPDF ~1 LSB)
The shader-based gradient (linear/radial) fragment shader now adds a mean-zero triangular-PDF dither (~1 LSB of 8-bit) from a spatial pixel-position hash before writing finalColor, so smooth ramps (e.g. an alpha fade) no longer show quantization banding when written to the 8-bit surface buffer. Spatial, non-temporal — no shimmer on static panels. Applies to every shader gradient.
-rw-r--r--packages/kernel/src/rmlui_renderer_gl3.cpp16
1 files changed, 15 insertions, 1 deletions
diff --git a/packages/kernel/src/rmlui_renderer_gl3.cpp b/packages/kernel/src/rmlui_renderer_gl3.cpp
index dfb455f..092c1c8 100644
--- a/packages/kernel/src/rmlui_renderer_gl3.cpp
+++ b/packages/kernel/src/rmlui_renderer_gl3.cpp
@@ -128,6 +128,13 @@ in vec2 fragTexCoord;
in vec4 fragColor;
out vec4 finalColor;
+// Dave Hoskins' hash (https://www.shadertoy.com/view/4djSRW): vec2 -> [0,1).
+float hash12(vec2 p) {
+ vec3 q = fract(vec3(p.xyx) * 0.1031);
+ q += dot(q, q.yzx + 33.33);
+ return fract((q.x + q.y) * q.z);
+}
+
vec4 mix_stop_colors(float t) {
vec4 color = _stop_colors[0];
@@ -165,7 +172,14 @@ void main() {
t = t0 + mod(t - t0, t1 - t0);
}
- finalColor = fragColor * mix_stop_colors(t);
+ vec4 color = fragColor * mix_stop_colors(t);
+ // TPDF (triangular-PDF) dither, ~1 LSB of 8-bit, applied before this color is
+ // written to the 8-bit surface buffer — breaks the quantization banding of a
+ // smooth gradient (e.g. the dock's alpha ramp). Mean-zero, so it does not
+ // shift the gradient; spatial pixel-position hash (no texture) and NON-temporal
+ // so a mostly-static panel does not shimmer frame to frame.
+ float dither = (hash12(gl_FragCoord.xy) - hash12(gl_FragCoord.xy + 37.0)) / 255.0;
+ finalColor = color + dither;
}
)";