From 898410621720a046e1dfa5703879fac5be089c73 Mon Sep 17 00:00:00 2001 From: Laurenz Stampfl Date: Mon, 28 Sep 2026 13:59:34 +0200 Subject: [PATCH 1/3] vello_gpu: Implement proper bilinear and bicubic image sampling --- vello_gpu_shaders/shaders/helpers/extend.wesl | 12 +- .../shaders/helpers/external_texture.wesl | 103 +++++++++++++----- vello_gpu_shaders/shaders/render.wesl | 9 +- .../external_texture_reflect_with_offset.png | 3 + .../snapshots/external_texture_skewed.png | 4 +- .../external_texture_with_scene_transform.png | 4 +- ...xternal_texture_with_scene_transform_2.png | 4 +- .../image_bicubic_repeat_x_pad_y.png | 3 + vello_tests/tests/external_texture.rs | 23 ++++ vello_tests/tests/image.rs | 16 ++- vello_tests/tests/issues.rs | 4 +- 11 files changed, 135 insertions(+), 50 deletions(-) create mode 100644 vello_tests/snapshots/external_texture_reflect_with_offset.png create mode 100644 vello_tests/snapshots/image_bicubic_repeat_x_pad_y.png diff --git a/vello_gpu_shaders/shaders/helpers/extend.wesl b/vello_gpu_shaders/shaders/helpers/extend.wesl index 0f963abe9b..463833254a 100644 --- a/vello_gpu_shaders/shaders/helpers/extend.wesl +++ b/vello_gpu_shaders/shaders/helpers/extend.wesl @@ -13,14 +13,22 @@ fn extend_mode(t: f32, mode: u32, max: f32) -> f32 { return clamp(t, 0.0, max - 1.0); } case EXTEND_REPEAT: { - return extend_mode_normalized(t / max, mode) * max; + return euclid_mod(floor(t), max); } case EXTEND_REFLECT, default: { - return extend_mode_normalized(t / max, mode) * max; + let period = max + max; + let r = euclid_mod(floor(t), period); + return select(r, period - 1.0 - r, r >= max); } } } +fn euclid_mod(t: f32, m: f32) -> f32 { + let q = round(t / m); + let r = fma(q, -m, t); + return select(r, r + m, r < 0.0); +} + fn extend_mode_normalized(t: f32, mode: u32) -> f32 { switch mode { case EXTEND_PAD: { diff --git a/vello_gpu_shaders/shaders/helpers/external_texture.wesl b/vello_gpu_shaders/shaders/helpers/external_texture.wesl index 077c829f55..b135abc8f8 100644 --- a/vello_gpu_shaders/shaders/helpers/external_texture.wesl +++ b/vello_gpu_shaders/shaders/helpers/external_texture.wesl @@ -8,6 +8,11 @@ import package::helpers::image::{ IMAGE_QUALITY_MEDIUM, cubic_weights }; +import package::helpers::extend::extend_mode; + +fn external_axis_index(coord: f32, extend_mode_id: u32, size: f32) -> i32 { + return i32(min(extend_mode(coord, extend_mode_id, size), size - 1.0)); +} // This is the same as `helpers::image::bilinear_sample`, but for a 2D texture // instead of an atlas texture array. @@ -16,15 +21,24 @@ fn external_bilinear_sample( coords: vec2, image_offset: vec2, image_size: vec2, + image_extend_modes: vec2, ) -> vec4 { - let image_max = image_offset + image_size - vec2(1.0); - let clamped_coords = clamp(coords, image_offset, image_max); - let coord_quad = vec4(floor(clamped_coords), ceil(clamped_coords)); - let coord_frac = fract(coords); - let a = textureLoad(external_texture, vec2(coord_quad.xy), 0); - let b = textureLoad(external_texture, vec2(coord_quad.xw), 0); - let c = textureLoad(external_texture, vec2(coord_quad.zy), 0); - let d = textureLoad(external_texture, vec2(coord_quad.zw), 0); + let shifted_coords = coords + vec2(0.5); + let base_coords = floor(shifted_coords); + let coord_frac = shifted_coords - base_coords; + let x = vec2( + external_axis_index(base_coords.x - 1.0, image_extend_modes.x, image_size.x), + external_axis_index(base_coords.x, image_extend_modes.x, image_size.x), + ); + let y = vec2( + external_axis_index(base_coords.y - 1.0, image_extend_modes.y, image_size.y), + external_axis_index(base_coords.y, image_extend_modes.y, image_size.y), + ); + let offset = vec2(image_offset); + let a = textureLoad(external_texture, offset + vec2(x.x, y.x), 0); + let b = textureLoad(external_texture, offset + vec2(x.x, y.y), 0); + let c = textureLoad(external_texture, offset + vec2(x.y, y.x), 0); + let d = textureLoad(external_texture, offset + vec2(x.y, y.y), 0); return mix(mix(a, b, coord_frac.y), mix(c, d, coord_frac.y), coord_frac.x); } @@ -35,31 +49,47 @@ fn external_bicubic_sample( coords: vec2, image_offset: vec2, image_size: vec2, + image_extend_modes: vec2, ) -> vec4 { - let image_max = image_offset + image_size - vec2(1.0); - let frac_coords = fract(coords + 0.5); + let shifted_coords = coords + vec2(0.5); + let base_coords = floor(shifted_coords); + let frac_coords = shifted_coords - base_coords; let cx = cubic_weights(frac_coords.x); let cy = cubic_weights(frac_coords.y); - let s00 = textureLoad(external_texture, vec2(clamp(coords + vec2(-1.5, -1.5), image_offset, image_max)), 0); - let s10 = textureLoad(external_texture, vec2(clamp(coords + vec2(-0.5, -1.5), image_offset, image_max)), 0); - let s20 = textureLoad(external_texture, vec2(clamp(coords + vec2(0.5, -1.5), image_offset, image_max)), 0); - let s30 = textureLoad(external_texture, vec2(clamp(coords + vec2(1.5, -1.5), image_offset, image_max)), 0); + let x = vec4( + external_axis_index(base_coords.x - 2.0, image_extend_modes.x, image_size.x), + external_axis_index(base_coords.x - 1.0, image_extend_modes.x, image_size.x), + external_axis_index(base_coords.x, image_extend_modes.x, image_size.x), + external_axis_index(base_coords.x + 1.0, image_extend_modes.x, image_size.x), + ); + let y = vec4( + external_axis_index(base_coords.y - 2.0, image_extend_modes.y, image_size.y), + external_axis_index(base_coords.y - 1.0, image_extend_modes.y, image_size.y), + external_axis_index(base_coords.y, image_extend_modes.y, image_size.y), + external_axis_index(base_coords.y + 1.0, image_extend_modes.y, image_size.y), + ); + let offset = vec2(image_offset); - let s01 = textureLoad(external_texture, vec2(clamp(coords + vec2(-1.5, -0.5), image_offset, image_max)), 0); - let s11 = textureLoad(external_texture, vec2(clamp(coords + vec2(-0.5, -0.5), image_offset, image_max)), 0); - let s21 = textureLoad(external_texture, vec2(clamp(coords + vec2(0.5, -0.5), image_offset, image_max)), 0); - let s31 = textureLoad(external_texture, vec2(clamp(coords + vec2(1.5, -0.5), image_offset, image_max)), 0); + let s00 = textureLoad(external_texture, offset + vec2(x.x, y.x), 0); + let s10 = textureLoad(external_texture, offset + vec2(x.y, y.x), 0); + let s20 = textureLoad(external_texture, offset + vec2(x.z, y.x), 0); + let s30 = textureLoad(external_texture, offset + vec2(x.w, y.x), 0); - let s02 = textureLoad(external_texture, vec2(clamp(coords + vec2(-1.5, 0.5), image_offset, image_max)), 0); - let s12 = textureLoad(external_texture, vec2(clamp(coords + vec2(-0.5, 0.5), image_offset, image_max)), 0); - let s22 = textureLoad(external_texture, vec2(clamp(coords + vec2(0.5, 0.5), image_offset, image_max)), 0); - let s32 = textureLoad(external_texture, vec2(clamp(coords + vec2(1.5, 0.5), image_offset, image_max)), 0); + let s01 = textureLoad(external_texture, offset + vec2(x.x, y.y), 0); + let s11 = textureLoad(external_texture, offset + vec2(x.y, y.y), 0); + let s21 = textureLoad(external_texture, offset + vec2(x.z, y.y), 0); + let s31 = textureLoad(external_texture, offset + vec2(x.w, y.y), 0); - let s03 = textureLoad(external_texture, vec2(clamp(coords + vec2(-1.5, 1.5), image_offset, image_max)), 0); - let s13 = textureLoad(external_texture, vec2(clamp(coords + vec2(-0.5, 1.5), image_offset, image_max)), 0); - let s23 = textureLoad(external_texture, vec2(clamp(coords + vec2(0.5, 1.5), image_offset, image_max)), 0); - let s33 = textureLoad(external_texture, vec2(clamp(coords + vec2(1.5, 1.5), image_offset, image_max)), 0); + let s02 = textureLoad(external_texture, offset + vec2(x.x, y.z), 0); + let s12 = textureLoad(external_texture, offset + vec2(x.y, y.z), 0); + let s22 = textureLoad(external_texture, offset + vec2(x.z, y.z), 0); + let s32 = textureLoad(external_texture, offset + vec2(x.w, y.z), 0); + + let s03 = textureLoad(external_texture, offset + vec2(x.x, y.w), 0); + let s13 = textureLoad(external_texture, offset + vec2(x.y, y.w), 0); + let s23 = textureLoad(external_texture, offset + vec2(x.z, y.w), 0); + let s33 = textureLoad(external_texture, offset + vec2(x.w, y.w), 0); let row0 = cx.x * s00 + cx.y * s10 + cx.z * s20 + cx.w * s30; let row1 = cx.x * s01 + cx.y * s11 + cx.z * s21 + cx.w * s31; @@ -78,17 +108,32 @@ fn sample_external_image( coords: vec2, image_offset: vec2, image_size: vec2, + image_extend_modes: vec2, ) -> vec4 { if quality == IMAGE_QUALITY_HIGH { - return external_bicubic_sample(external_texture, coords, image_offset, image_size); + return external_bicubic_sample( + external_texture, + coords, + image_offset, + image_size, + image_extend_modes, + ); } if quality == IMAGE_QUALITY_MEDIUM { return external_bilinear_sample( external_texture, - coords - vec2(0.5), + coords, image_offset, image_size, + image_extend_modes, ); } - return textureLoad(external_texture, vec2(coords), 0); + return textureLoad( + external_texture, + vec2(image_offset) + vec2( + external_axis_index(coords.x, image_extend_modes.x, image_size.x), + external_axis_index(coords.y, image_extend_modes.y, image_size.y), + ), + 0, + ); } diff --git a/vello_gpu_shaders/shaders/render.wesl b/vello_gpu_shaders/shaders/render.wesl index a909af54ba..0d1bff3c15 100644 --- a/vello_gpu_shaders/shaders/render.wesl +++ b/vello_gpu_shaders/shaders/render.wesl @@ -25,7 +25,6 @@ import package::helpers::alpha::unpack_alphas_from_channel; import package::helpers::blurred_rounded_rect::calculate_blurred_rounded_rect; -import package::helpers::extend::extend_mode; import package::helpers::external_texture::sample_external_image; import package::helpers::gradient::{ apply_gradient_transform, @@ -395,21 +394,17 @@ fn fs_main( let image_tint = unpack4x8unorm(packed_tint); let is_multiply = image_texel2.z == TINT_MODE_MULTIPLY; let local_xy = sample_xy - image_offset; - let extended_xy = vec2( - extend_mode(local_xy.x, image_extend_modes.x, image_size.x), - extend_mode(local_xy.y, image_extend_modes.y, image_size.y) - ); // TODO: add a fast path for images where we are using bilinear sampling and want transparent pixels, // using GPU-native bilinear sampling - let final_xy = image_offset + extended_xy; let sample_color = sample_external_image( external_texture_0, image_quality, - final_xy, + local_xy, image_offset, image_size, + image_extend_modes, ); final_color = alpha * select( diff --git a/vello_tests/snapshots/external_texture_reflect_with_offset.png b/vello_tests/snapshots/external_texture_reflect_with_offset.png new file mode 100644 index 0000000000..8678c2f607 --- /dev/null +++ b/vello_tests/snapshots/external_texture_reflect_with_offset.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5e676ba0d8f98393cfae378bee4421b0f6fda43ee306165a46bae6e341e4eea5 +size 140 diff --git a/vello_tests/snapshots/external_texture_skewed.png b/vello_tests/snapshots/external_texture_skewed.png index 1ae171ee57..90d92182c0 100644 --- a/vello_tests/snapshots/external_texture_skewed.png +++ b/vello_tests/snapshots/external_texture_skewed.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d06ad352104023d1d7bf59de03ab80ae6fda22a8e4d65fb826fc15a513af3695 -size 2733 +oid sha256:039e3944b98e786a7846daf4652aa5e871485a20ffff224596decdf139dcb953 +size 2739 diff --git a/vello_tests/snapshots/external_texture_with_scene_transform.png b/vello_tests/snapshots/external_texture_with_scene_transform.png index 086e1b6ecd..8444df82b1 100644 --- a/vello_tests/snapshots/external_texture_with_scene_transform.png +++ b/vello_tests/snapshots/external_texture_with_scene_transform.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e53972600365cacdffd3e6df1b479637ff96e290740b391b65de825a3b46d5de -size 8784 +oid sha256:4d80594b9bc13732b5a82c55a7c00711cc56506228f8890a3dcdbd2d80f7e8a1 +size 8677 diff --git a/vello_tests/snapshots/external_texture_with_scene_transform_2.png b/vello_tests/snapshots/external_texture_with_scene_transform_2.png index 4ca670b93e..dd239f7e88 100644 --- a/vello_tests/snapshots/external_texture_with_scene_transform_2.png +++ b/vello_tests/snapshots/external_texture_with_scene_transform_2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f835051b66e43aeca0579ce31145e4507d3e95ce5ba1ade542be44b8d2d1fcb3 -size 1207 +oid sha256:bba9d941a3a90104859101d426e41c9e75d15379d3696c62c48182b04c83fcae +size 1812 diff --git a/vello_tests/snapshots/image_bicubic_repeat_x_pad_y.png b/vello_tests/snapshots/image_bicubic_repeat_x_pad_y.png new file mode 100644 index 0000000000..265332b1c2 --- /dev/null +++ b/vello_tests/snapshots/image_bicubic_repeat_x_pad_y.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5d0d7edf12944b746f563e35eb09ae3dc9daa0e2ac2c1b5ae64fdc700d92459c +size 755 diff --git a/vello_tests/tests/external_texture.rs b/vello_tests/tests/external_texture.rs index 29bcdaa3f8..30eccd203d 100644 --- a/vello_tests/tests/external_texture.rs +++ b/vello_tests/tests/external_texture.rs @@ -158,6 +158,29 @@ mod tests { ctx.fill_rect(&Rect::new(5., 5., 95., 95.)); } + #[vello_test(gpu_only)] + fn external_texture_reflect_with_offset(ctx: &mut impl Renderer) { + let pixmap = Arc::new(Pixmap::from_parts( + vec![0, 0, 0, 255, 255, 0, 0, 255, 0, 255, 0, 255], + 3, + 1, + PixelMetadata::new(ImageAlphaType::AlphaPremultiplied, false), + )); + let texture_id = ctx.register_external_texture(pixmap); + + ctx.set_paint_transform(Affine::scale(3.0)); + ctx.set_paint(Image { + image: ImageSource::external_texture(texture_id, RectU16::new(1, 0, 3, 1), false), + sampler: ImageSampler { + x_extend: Extend::Reflect, + y_extend: Extend::Pad, + quality: ImageQuality::Medium, + alpha: 1.0, + }, + }); + ctx.fill_rect(&Rect::new(10.0, 10.0, 90.0, 90.0)); + } + #[vello_test(gpu_only)] fn external_texture_with_paint_transform(ctx: &mut impl Renderer) { let texture_id = ctx.register_external_texture(load_image!("color_grid_16x16")); diff --git a/vello_tests/tests/image.rs b/vello_tests/tests/image.rs index fa33cc2dd4..46f33bb44c 100644 --- a/vello_tests/tests/image.rs +++ b/vello_tests/tests/image.rs @@ -89,9 +89,7 @@ fn image_pad_x_pad_y(ctx: &mut impl Renderer) { repeat(ctx, Extend::Pad, Extend::Pad); } -// TODO: Doesn't work correctly in the GPU renderer due to a difference in sampling behavior. -#[vello_test(skip_gpu)] -fn image_bilinear_repeat_x_pad_y(ctx: &mut impl Renderer) { +fn filtered_repeat_x_pad_y(ctx: &mut impl Renderer, quality: ImageQuality) { let rect = Rect::new(10.0, 10.0, 90.0, 90.0); let image_source = rgb_img_2x2(ctx); @@ -101,13 +99,23 @@ fn image_bilinear_repeat_x_pad_y(ctx: &mut impl Renderer) { sampler: ImageSampler { x_extend: Extend::Repeat, y_extend: Extend::Pad, - quality: ImageQuality::Medium, + quality, alpha: 1.0, }, }); ctx.fill_rect(&rect); } +#[vello_test] +fn image_bilinear_repeat_x_pad_y(ctx: &mut impl Renderer) { + filtered_repeat_x_pad_y(ctx, ImageQuality::Medium); +} + +#[vello_test] +fn image_bicubic_repeat_x_pad_y(ctx: &mut impl Renderer) { + filtered_repeat_x_pad_y(ctx, ImageQuality::High); +} + fn transform(ctx: &mut impl Renderer, transform: Affine, l: f64, t: f64, r: f64, b: f64) { let rect = Rect::new(l, t, r, b); let image_source = rgb_img_10x10(ctx); diff --git a/vello_tests/tests/issues.rs b/vello_tests/tests/issues.rs index 8ff8a5c7ea..27aa5081f8 100644 --- a/vello_tests/tests/issues.rs +++ b/vello_tests/tests/issues.rs @@ -857,12 +857,12 @@ fn image_filtering_at_extend_boundary( ctx.fill_rect(&Rect::new(10.0, 10.0, 90.0, 90.0)); } -#[vello_test(skip_gpu)] +#[vello_test] fn issue_image_filtering_at_reflect_boundary(ctx: &mut impl Renderer) { image_filtering_at_extend_boundary(ctx, 2, Extend::Reflect, (-1.0_f32).next_down()); } -#[vello_test(skip_gpu)] +#[vello_test] fn issue_image_filtering_at_repeat_boundary(ctx: &mut impl Renderer) { image_filtering_at_extend_boundary(ctx, 3, Extend::Repeat, 15.0_f32.next_down()); } From 248c7cefe2e0b861d42c2adec45d6db8124544d6 Mon Sep 17 00:00:00 2001 From: Laurenz Stampfl Date: Mon, 28 Sep 2026 14:00:06 +0200 Subject: [PATCH 2/3] vello_tests: Use CPU references for full external textures --- .../external_texture_root_painter_order.png | 2 +- ...xternal_texture_with_scene_transform_2.png | 4 +-- vello_tests/src/renderer.rs | 29 +++++++++++++++++-- vello_tests/tests/external_texture.rs | 20 ++++++------- 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/vello_tests/snapshots/external_texture_root_painter_order.png b/vello_tests/snapshots/external_texture_root_painter_order.png index d2bf0dbe36..782873a444 100644 --- a/vello_tests/snapshots/external_texture_root_painter_order.png +++ b/vello_tests/snapshots/external_texture_root_painter_order.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:15b84b78e387a1a0b49cd9d9af887eb62fe5f4725baada75926ec46d34883b6c +oid sha256:27d71e2c4550ce9b27085785dcfe385fc5052a57f8a5634b4fc15399df8cc056 size 334 diff --git a/vello_tests/snapshots/external_texture_with_scene_transform_2.png b/vello_tests/snapshots/external_texture_with_scene_transform_2.png index dd239f7e88..b7e88bf298 100644 --- a/vello_tests/snapshots/external_texture_with_scene_transform_2.png +++ b/vello_tests/snapshots/external_texture_with_scene_transform_2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bba9d941a3a90104859101d426e41c9e75d15379d3696c62c48182b04c83fcae -size 1812 +oid sha256:5f909833810e2c1bfa4eea87006b2674484b67e5666a037d3e64d8c12d6a64bf +size 1813 diff --git a/vello_tests/src/renderer.rs b/vello_tests/src/renderer.rs index 2c6c10bfa3..40e0a1b24f 100644 --- a/vello_tests/src/renderer.rs +++ b/vello_tests/src/renderer.rs @@ -1,7 +1,6 @@ // Copyright 2025 the Vello Authors // SPDX-License-Identifier: Apache-2.0 OR MIT -#[cfg(not(all(target_arch = "wasm32", feature = "webgl")))] use std::collections::HashMap; use std::sync::Arc; @@ -100,6 +99,8 @@ pub trait Renderer: Sized { pub struct CpuRenderer { ctx: RenderContext, resources: Resources, + external_textures: HashMap>, + next_external_texture_id: u64, render_mode: RenderMode, target: Pixmap, target_init: GpuTargetInit<'static>, @@ -119,6 +120,8 @@ impl Renderer for CpuRenderer { Self { ctx: RenderContext::new_with(width, height, settings), resources: Resources::new(), + external_textures: HashMap::new(), + next_external_texture_id: 1, render_mode, target: Pixmap::new(width, height), target_init: GpuTargetInit::Clear(ClearSettings::default()), @@ -214,6 +217,23 @@ impl Renderer for CpuRenderer { } fn set_paint(&mut self, paint: impl Into) { + let mut paint = paint.into(); + if let PaintType::Image(image) = &mut paint + && let ImageSource::ExternalTexture { + id, source_region, .. + } = &image.image + { + let pixmap = self + .external_textures + .get(id) + .unwrap_or_else(|| panic!("External texture {id:?} not found in test registry")); + assert_eq!( + *source_region, + RectU16::new(0, 0, pixmap.width(), pixmap.height()), + "CPU test renderer only supports full external texture regions" + ); + image.image = ImageSource::Pixmap(Arc::clone(pixmap)); + } self.ctx.set_paint(paint); } @@ -283,8 +303,11 @@ impl Renderer for CpuRenderer { self.target.clone() } - fn register_external_texture(&mut self, _: Arc) -> TextureId { - unimplemented!("external textures are only supported by GPU renderer tests") + fn register_external_texture(&mut self, pixmap: Arc) -> TextureId { + let texture_id = TextureId(self.next_external_texture_id); + self.next_external_texture_id += 1; + self.external_textures.insert(texture_id, pixmap); + texture_id } fn get_image_source(&mut self, pixmap: Arc) -> ImageSource { diff --git a/vello_tests/tests/external_texture.rs b/vello_tests/tests/external_texture.rs index 30eccd203d..85f73255ff 100644 --- a/vello_tests/tests/external_texture.rs +++ b/vello_tests/tests/external_texture.rs @@ -130,7 +130,7 @@ mod tests { fill_sprite_rect(ctx, texture_id, SPRITES[3], 25., 25., ImageQuality::Low); } - #[vello_test(gpu_only)] + #[vello_test] fn external_texture_circle(ctx: &mut impl Renderer) { let texture_id = ctx.register_external_texture(load_image!("color_grid_16x16")); @@ -142,7 +142,7 @@ mod tests { ctx.fill_path(&Circle::new((50., 50.), 40.).to_path(0.1)); } - #[vello_test(gpu_only)] + #[vello_test] fn external_texture_repeat(ctx: &mut impl Renderer) { let texture_id = ctx.register_external_texture(load_image!("color_grid_16x16")); @@ -198,7 +198,7 @@ mod tests { ctx.fill_rect(&Rect::new(5., 5., 95., 95.)); } - #[vello_test(gpu_only)] + #[vello_test] fn external_texture_with_scene_transform_2(ctx: &mut impl Renderer) { let texture_id = ctx.register_external_texture(load_image!("color_grid_16x16")); @@ -232,7 +232,7 @@ mod tests { ctx.fill_rect(&Rect::new(5., 5., 95., 95.)); } - #[vello_test(width = 96, height = 96, gpu_only, gpu_no_depth)] + #[vello_test(width = 96, height = 96, gpu_no_depth)] fn external_texture_opaque_interleaving(ctx: &mut impl Renderer) { let texture_id = ctx.register_external_texture(solid_pixmap(192, 0, 0, 192)); @@ -245,7 +245,7 @@ mod tests { ctx.fill_rect(&Rect::new(48., 16., 88., 56.)); } - #[vello_test(width = 96, height = 96, gpu_only, gpu_no_depth)] + #[vello_test(width = 96, height = 96, gpu_no_depth)] fn external_texture_runs_with_opaque_prefix(ctx: &mut impl Renderer) { let red_texture = ctx.register_external_texture(solid_pixmap(255, 0, 0, 255)); let green_texture = ctx.register_external_texture(solid_pixmap(0, 255, 0, 255)); @@ -262,7 +262,7 @@ mod tests { fill_texture_rect(ctx, red_texture, 48., 48., 40., 40., true); } - #[vello_test(gpu_only, gpu_no_depth)] + #[vello_test(gpu_no_depth)] fn external_texture_root_painter_order(ctx: &mut impl Renderer) { let coral = ctx.register_external_texture(solid_pixmap(225, 87, 89, 255)); let teal = ctx.register_external_texture(solid_pixmap(42, 157, 143, 255)); @@ -287,7 +287,7 @@ mod tests { fill_texture_rect(ctx, coral, 44., 44., 12., 12., false); } - #[vello_test(gpu_only)] + #[vello_test] fn external_texture_atlas_interleaving(ctx: &mut impl Renderer) { let atlas_red = ctx.get_image_source(solid_pixmap(254, 0, 0, 254)); let external_green = ctx.register_external_texture(solid_pixmap(0, 254, 0, 254)); @@ -302,7 +302,7 @@ mod tests { draw_atlas_rect(ctx, atlas_magenta, Rect::new(66., 66., 90., 90.)); } - #[vello_test(gpu_only)] + #[vello_test] fn external_texture_layer_before_external(ctx: &mut impl Renderer) { let texture_id = ctx.register_external_texture(solid_pixmap(128, 0, 0, 128)); @@ -316,7 +316,7 @@ mod tests { ctx.pop_layer(); } - #[vello_test(gpu_only)] + #[vello_test] fn external_texture_external_before_layer(ctx: &mut impl Renderer) { let texture_id = ctx.register_external_texture(solid_pixmap(0, 255, 0, 255)); @@ -330,7 +330,7 @@ mod tests { ctx.pop_layer(); } - #[vello_test(gpu_only)] + #[vello_test] fn external_texture_layer_circle_orders(ctx: &mut impl Renderer) { let blue_texture = ctx.register_external_texture(solid_pixmap(0, 0, 255, 255)); let red_texture = ctx.register_external_texture(solid_pixmap(255, 0, 0, 255)); From 0fa8fe99f363e233de616455fa15eb6b7db7f919 Mon Sep 17 00:00:00 2001 From: Laurenz Stampfl Date: Wed, 30 Sep 2026 08:52:48 +0200 Subject: [PATCH 3/3] ci: Test longer WebDriver page-load timeout --- vello_tests/webdriver.json | 1 + 1 file changed, 1 insertion(+) diff --git a/vello_tests/webdriver.json b/vello_tests/webdriver.json index 345b6818ae..808bebfdb1 100644 --- a/vello_tests/webdriver.json +++ b/vello_tests/webdriver.json @@ -1,5 +1,6 @@ { "timeouts": { + "pageLoad": 1200000, "script": 1200000 } }