gpui: Add dithering to linear gradient shader#51211
Merged
mikayla-maki merged 3 commits intozed-industries:mainfrom Mar 30, 2026
Merged
gpui: Add dithering to linear gradient shader#51211mikayla-maki merged 3 commits intozed-industries:mainfrom
mikayla-maki merged 3 commits intozed-industries:mainfrom
Conversation
c803f9e to
0a16a31
Compare
0a16a31 to
ae3a5da
Compare
mikayla-maki
requested changes
Mar 25, 2026
crates/gpui/src/color.rs
Outdated
| /// statistical properties. Note: f32 sin() on CPU vs GPU may produce | ||
| /// slightly different distributions, but the properties we test | ||
| /// (small mean, small amplitude, improved quantization) hold on both. | ||
| fn shader_dither(x: f32, y: f32) -> f32 { |
Member
There was a problem hiding this comment.
Let's remove the rust function and tests here, as they don't actually test the relevant code in the shaders
Linear gradients in dark color ranges (5-15% lightness) show visible banding due to 8-bit quantization — only ~7 distinct values exist in that range, producing hard steps instead of smooth transitions. Adds triangular-distributed dithering (±1/255) after gradient interpolation in both the Metal and HLSL fragment shaders. Two hash-based random values are combined for a triangular PDF that is mean-zero (no brightness shift) with amplitude below the perceptual threshold. Includes Rust unit tests verifying the dithering algorithm's statistical properties: near-zero mean, small amplitude, and improved quantization of dark gradients. Liam
Increase dither amplitude and extend to alpha channel: - RGB: ±2/255 (was ±1/255) — better for dark-on-dark compositing - Alpha: ±3/255 (new) — breaks banding in alpha gradients over dark backgrounds Same golden-ratio triangular PDF noise, still mean-zero (no shift). Liam
The Rust reimplementation of the shader dither algorithm doesn't actually test the GPU code path. Removed per reviewer feedback. Liam
ae3a5da to
9e75025
Compare
Contributor
Author
|
@mikayla-maki done, removed the rust function and tests. Rebased too. @reflectronic can you review please? should be good to go. |
mikayla-maki
approved these changes
Mar 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Linear gradients in dark color ranges (5-15% lightness) show visible banding due to 8-bit quantization — only ~7 distinct values exist in that range, producing hard steps instead of smooth transitions. This affects every dark theme in Zed.
What this does
Adds triangular-distributed dithering after gradient interpolation in both the Metal and HLSL fragment shaders. The noise breaks up quantization steps at the sub-pixel level, producing perceptually smooth gradients.
How it works
Two hash-based pseudo-random values (seeded from fragment position x golden ratio) are summed to produce a triangular probability distribution. This is added to the RGB channels at +/-1/255 amplitude.
fract/sinper fragment, negligible vs. the existing gradient mathChannel-specific amplitudes
The higher alpha amplitude is necessary because when a semi-transparent gradient (e.g., 0.4 → 0.0 alpha) composites over a dark background, the effective visible difference per quantization step is smaller than the RGB case. ±3/255 is still well below the perceptual threshold on bright/opaque elements.
Scope
Two files changed, purely additive:
crates/gpui_macos/src/shaders.metalmix()infill_color()crates/gpui_windows/src/shaders.hlsllerp()ingradient_color()No changes to Rust code, no API changes, no new dependencies.
Screenshots
Before
After
Test plan
This is a shader-level fix; no Rust test harness exists for visual output. Manual testing is appropriate here. Visual regression tests cover UI layout, not sub-pixel rendering quality.
Manual (macOS):
Windows: HLSL change is identical logic with HLSL built-ins (
frac/lerpvsfract/mix) — not tested locally.Release Notes:
Liam