Repository navigation
vello_cpu: Fix Color and Luminosity blends turning some grays black - #2000
Open
zlstringham wants to merge 1 commit into
Open
zlstringham wants to merge 1 commit into
zlstringham wants to merge 1 commit into
Conversation
After `set_lum`, a gray has `l == n == x`, so `clip_color` divides 0 by 0 when rounding leaves the channels just outside [0, 1]. The NaN survives `apply_alpha` and packs to black. Clip only where the denominator is positive, in vello_cpu and in the vello_gpu and research shaders alike, and add a unit test that `mix` stays finite for every gray pair. Fixes linebender#1999.
zlstringham
force-pushed
the
vello-cpu-clip-color-nan
branch
from
October 11, 2026 02:12
9cc3903 to
c068039
Compare
This branch has not been deployed
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.
Fixes #1999.
clip_colordivides byl - nwhenn < 0and byx - lwhenx > 1, without checking the denominator. Afterset_lum, a gray has three equal components, sol == n == x. When rounding leaves them just below 0 (or just above 1), the division is 0/0. The NaN survivesapply_alpha, even over a transparent backdrop, and packs to black. WithMix::ColorandMix::Luminosity, some gray levels come out black in both pipelines.This PR clips only where the denominator is positive:
n < 0 && l - n > 0andx > 1 && x - l > 0. For a neutral color, the clipped value's limit is the color itself, so skipping the clip loses nothing. Skia (l != mn,l != mx) and pixman (FLOAT_IS_ZERO(l - n)) guard the same case.vello_gpu_shaders/shaders/helpers/blend.weslandresearch/vello_shaders/shader/shared/blend.wgslhave the same unguardedclip_colorand get the same guard. I couldn't make the GPU path produce black pixels on Metal, but WGSL gives an indeterminate value for a division without a finite result, so the guard still helps there.Testing:
non_separable_mix_of_neutral_colors_is_finitechecks thatmixstays finite for Hue/Saturation/Color/Luminosity with every gray at 50% alpha over a transparent backdrop and over every opaque gray. It fails without the guard and passes with it.cargo test -p vello_cpupasses.cargo test -p vello_tests --releasepasses on CPU and on GPU (Metal, Apple M3 Max), with no snapshot changes.cargo test -p vello_gpu_shaders --all-featurespasses.vello_gpu_shadersandvello_shadersbuild, and their build scripts validate the WGSL with naga.cargo fmt --check,typos, the CI clippy commands forvello_cpu(includingno_stdand wasm32), and the 1.89 MSRV check are clean.