From 4a6d266acdf525c061e6b326689c491d509ab5b9 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 22 Jul 2026 08:51:37 +0200 Subject: [PATCH] vello_common: compute the transparency hint in ImageSource::from_peniko_image_data The conversion built the Pixmap via from_parts(), which conservatively marks every image as possibly transparent. As a result, images supplied as peniko::ImageData never hit the FillHint::OpaqueImage fast path in the coarse rasterizer (skipping per-pixel blending and occluding commands underneath), even when they are fully opaque. The conversion already visits every pixel to premultiply, so track whether any alpha value is not 255 in the same loop and construct the Pixmap with from_parts_with_opacity(). --- sparse_strips/vello_common/src/paint.rs | 34 ++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/sparse_strips/vello_common/src/paint.rs b/sparse_strips/vello_common/src/paint.rs index b032bc31b5..53d2246f89 100644 --- a/sparse_strips/vello_common/src/paint.rs +++ b/sparse_strips/vello_common/src/paint.rs @@ -137,6 +137,7 @@ impl ImageSource { let height = image.height.try_into().unwrap(); // TODO: SIMD + let mut may_have_transparency = false; #[expect(clippy::cast_possible_truncation, reason = "This cannot overflow.")] let pixels = image .data @@ -148,6 +149,7 @@ impl ImageSource { peniko::ImageFormat::Bgra8 => [pixel[2], pixel[1], pixel[0], pixel[3]], format => unimplemented!("Unsupported image format: {format:?}"), }; + may_have_transparency |= rgba[3] != 255; let alpha = u16::from(rgba[3]); let multiply = |component| ((alpha * u16::from(component)) / 255) as u8; if do_alpha_multiply { @@ -167,7 +169,7 @@ impl ImageSource { } }) .collect(); - let pixmap = Pixmap::from_parts(pixels, width, height); + let pixmap = Pixmap::from_parts_with_opacity(pixels, width, height, may_have_transparency); Self::Pixmap(Arc::new(pixmap)) } @@ -274,3 +276,33 @@ pub struct Tint { /// A kind of paint that can be used for filling and stroking shapes. pub type PaintType = peniko::Brush; + +#[cfg(test)] +mod tests { + use super::ImageSource; + use alloc::sync::Arc; + + fn image_data(pixels: &[u8], alpha_type: peniko::ImageAlphaType) -> peniko::ImageData { + peniko::ImageData { + data: peniko::Blob::new(Arc::new(pixels.to_vec())), + format: peniko::ImageFormat::Rgba8, + alpha_type, + width: (pixels.len() / 4) as u32, + height: 1, + } + } + + #[test] + fn from_peniko_image_data_computes_transparency_hint() { + for alpha_type in [ + peniko::ImageAlphaType::Alpha, + peniko::ImageAlphaType::AlphaPremultiplied, + ] { + let opaque = image_data(&[10, 20, 30, 255, 40, 50, 60, 255], alpha_type); + assert!(!ImageSource::from_peniko_image_data(&opaque).may_have_transparency()); + + let translucent = image_data(&[10, 20, 30, 255, 40, 50, 60, 128], alpha_type); + assert!(ImageSource::from_peniko_image_data(&translucent).may_have_transparency()); + } + } +}