Skip to content

vello_gpu: fix Extend::Pad with bilinear/bicubic sampling - #1974

Open
nicoburns wants to merge 1 commit into
linebender:mainfrom
DioxusLabs:devin/1791043826-gpu-bilinear-pad
Open

nicoburns wants to merge 1 commit into
linebender:mainfrom
DioxusLabs:devin/1791043826-gpu-bilinear-pad

Conversation

@nicoburns

@nicoburns nicoburns commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Bug noticed when smoke testing AnyRender upgrade to vello_gpu 0.3.

Fix entirely generated by LLM (but it's very small).

Summary

If an image paint uses Extend::Pad with ImageQuality::Medium, vello_gpu fills everything past the image's right and bottom edges with one flat colour: an exact 50/50 blend of the last two texels. vello_cpu repeats the edge texels, which is the expected output.

vello_cpu (expected) vello_gpu before vello_gpu after
vello_cpu vello_gpu vello_gpu_patched

(8×8 checkerboard, scaled 8×, filled into a rect 4×3 times the image size.)

Cause: extend_mode clamped the Pad position to [0, size - 1] before the bilinear sampler subtracted the half-texel offset. For an 8-wide image, every point past the edge became 7.0 - 0.5 = 6.5, so the sampler blended texels 6 and 7 at fract = 0.5. Bicubic had the same problem.

Fix: external_bilinear_sample and external_bicubic_sample already clamp each tap to the image bounds, which matches what vello_cpu does with per-tap extend_mode. So Pad no longer clamps the position at all, and the only path that relied on that clamp, the nearest-neighbour textureLoad, now clamps to the image bounds itself:

 // helpers/extend.wesl
 case EXTEND_PAD: {
-    return clamp(t, 0.0, max - 1.0);
+    return t;
 }
 // helpers/external_texture.wesl, sample_external_image
-return textureLoad(external_texture, vec2<u32>(coords), 0);
+return textureLoad(external_texture, vec2<u32>(clamp(coords, image_offset, image_max)), 0);

Tests:

  • New image_bilinear_pad and image_bicubic_pad snapshot tests: a 4×4 checkerboard on a 100×100 canvas, with snapshots of 368 B and 1 KB. Both fail on GPU before this change and pass after it.
  • The GPU-only snapshots external_texture_skewed and external_texture_with_scene_transform were regenerated. Only their right and bottom edge pixels change, by at most 4/255, because of the half-texel fix at those edges.

Pad clamped the sample position to [0, size - 1] before the bilinear
half-texel offset, so everything past the right/bottom edge blended
the last two texels 50/50 instead of repeating the edge texel. The
samplers already clamp each tap to the image bounds, so leave the
position unclamped for Pad and clamp the nearest-neighbour load instead.

Adds image_bilinear_pad and image_bicubic_pad snapshot tests and
updates two GPU-only external texture snapshots whose right/bottom
edge pixels change slightly (max difference 4).
@LaurenzV

LaurenzV commented Oct 3, 2026

Copy link
Copy Markdown
Collaborator

Is this not fixed by #1963?

@LaurenzV

LaurenzV commented Oct 3, 2026

Copy link
Copy Markdown
Collaborator

I think it should be. It will still take a bit but I hope I can land it next week! 😄

@nicoburns

Copy link
Copy Markdown
Contributor Author

Is this not fixed by #1963?

Might well be. Bug is present in 0.3. I didn't check for open PRs.

@LaurenzV

Copy link
Copy Markdown
Collaborator

@nicoburns Could you check whether this works fine on newest main?

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants