Merge branch 'main' into strip_improvements
diff --git a/sparse_strips/vello_common/src/encode.rs b/sparse_strips/vello_common/src/encode.rs
index 715e79d..df558f3 100644
--- a/sparse_strips/vello_common/src/encode.rs
+++ b/sparse_strips/vello_common/src/encode.rs
@@ -11,14 +11,18 @@
use crate::paint::{Image, ImageSource, IndexedPaint, Paint, PremulColor};
use crate::peniko::{ColorStop, Extend, Gradient, GradientKind, ImageQuality};
use alloc::borrow::Cow;
+use alloc::fmt::Debug;
+use alloc::vec;
use alloc::vec::Vec;
#[cfg(not(feature = "multithreading"))]
use core::cell::OnceCell;
+use fearless_simd::{Simd, SimdBase, SimdFloat, f32x4, f32x16};
use smallvec::SmallVec;
// So we can just use `OnceCell` regardless of which feature is activated.
#[cfg(feature = "multithreading")]
use std::sync::OnceLock as OnceCell;
+use crate::simd::{Splat4thExt, element_wise_splat};
#[cfg(not(feature = "std"))]
use peniko::kurbo::common::FloatFuncs as _;
@@ -332,29 +336,12 @@
cs: ColorSpaceTag,
hue_dir: HueDirection,
) -> Vec<GradientRange> {
+ #[derive(Debug)]
struct EncodedColorStop {
offset: f32,
color: crate::color::PremulColor<Srgb>,
}
- // Create additional (SRGB-encoded) stops in-between to approximate the color space we want to
- // interpolate in.
- let interpolated_stops = stops
- .windows(2)
- .flat_map(|s| {
- let left_stop = &s[0];
- let right_stop = &s[1];
-
- let interpolated =
- gradient::<Srgb>(left_stop.color, right_stop.color, cs, hue_dir, 0.01);
-
- interpolated.map(|st| EncodedColorStop {
- offset: left_stop.offset + (right_stop.offset - left_stop.offset) * st.0,
- color: st.1,
- })
- })
- .collect::<Vec<_>>();
-
let create_range = |left_stop: &EncodedColorStop, right_stop: &EncodedColorStop| {
let clamp = |mut color: [f32; 4]| {
// The linear approximation of the gradient can produce values slightly outside of
@@ -388,15 +375,52 @@
GradientRange { x1, bias, scale }
};
- interpolated_stops
- .windows(2)
- .map(|s| {
- let left_stop = &s[0];
- let right_stop = &s[1];
+ // Create additional (SRGB-encoded) stops in-between to approximate the color space we want to
+ // interpolate in.
+ if cs != ColorSpaceTag::Srgb {
+ let interpolated_stops = stops
+ .windows(2)
+ .flat_map(|s| {
+ let left_stop = &s[0];
+ let right_stop = &s[1];
- create_range(left_stop, right_stop)
- })
- .collect()
+ let interpolated =
+ gradient::<Srgb>(left_stop.color, right_stop.color, cs, hue_dir, 0.01);
+
+ interpolated.map(|st| EncodedColorStop {
+ offset: left_stop.offset + (right_stop.offset - left_stop.offset) * st.0,
+ color: st.1,
+ })
+ })
+ .collect::<Vec<_>>();
+
+ interpolated_stops
+ .windows(2)
+ .map(|s| {
+ let left_stop = &s[0];
+ let right_stop = &s[1];
+
+ create_range(left_stop, right_stop)
+ })
+ .collect()
+ } else {
+ stops
+ .windows(2)
+ .map(|c| {
+ let c0 = EncodedColorStop {
+ offset: c[0].offset,
+ color: c[0].color.to_alpha_color::<Srgb>().premultiply(),
+ };
+
+ let c1 = EncodedColorStop {
+ offset: c[1].offset,
+ color: c[1].color.to_alpha_color::<Srgb>().premultiply(),
+ };
+
+ create_range(&c0, &c1)
+ })
+ .collect()
+ }
}
pub(crate) fn x_y_advances(transform: &Affine) -> (Vec2, Vec2) {
@@ -679,13 +703,15 @@
impl EncodedGradient {
/// Get the lookup table for sampling u8-based gradient values.
- pub fn u8_lut(&self) -> &GradientLut<u8> {
- self.u8_lut.get_or_init(|| GradientLut::new(&self.ranges))
+ pub fn u8_lut<S: Simd>(&self, simd: S) -> &GradientLut<u8> {
+ self.u8_lut
+ .get_or_init(|| GradientLut::new(simd, &self.ranges))
}
/// Get the lookup table for sampling f32-based gradient values.
- pub fn f32_lut(&self) -> &GradientLut<f32> {
- self.f32_lut.get_or_init(|| GradientLut::new(&self.ranges))
+ pub fn f32_lut<S: Simd>(&self, simd: S) -> &GradientLut<f32> {
+ self.f32_lut
+ .get_or_init(|| GradientLut::new(simd, &self.ranges))
}
}
@@ -840,69 +866,106 @@
}
/// A helper trait for converting a premultiplied f32 color to `Self`.
-pub trait FromF32Color: Sized {
+pub trait FromF32Color: Sized + Debug + Copy + Clone {
+ /// The zero value.
+ const ZERO: Self;
/// Convert from a premultiplied f32 color to `Self`.
- fn from_f32(color: &[f32; 4]) -> [Self; 4];
+ fn from_f32<S: Simd>(color: f32x4<S>) -> [Self; 4];
}
impl FromF32Color for f32 {
- fn from_f32(color: &[f32; 4]) -> [Self; 4] {
- *color
+ const ZERO: Self = 0.0;
+
+ fn from_f32<S: Simd>(color: f32x4<S>) -> [Self; 4] {
+ color.val
}
}
impl FromF32Color for u8 {
- fn from_f32(color: &[f32; 4]) -> [Self; 4] {
+ const ZERO: Self = 0;
+
+ fn from_f32<S: Simd>(mut color: f32x4<S>) -> [Self; 4] {
+ let simd = color.simd;
+ color = f32x4::splat(simd, 0.5).madd(color, f32x4::splat(simd, 255.0));
+
[
- (color[0] * 255.0 + 0.5) as Self,
- (color[1] * 255.0 + 0.5) as Self,
- (color[2] * 255.0 + 0.5) as Self,
- (color[3] * 255.0 + 0.5) as Self,
+ color[0] as Self,
+ color[1] as Self,
+ color[2] as Self,
+ color[3] as Self,
]
}
}
/// A lookup table for sampled gradient values.
#[derive(Debug)]
-pub struct GradientLut<T: Copy + Clone + FromF32Color> {
+pub struct GradientLut<T: FromF32Color> {
lut: Vec<[T; 4]>,
scale: f32,
}
-impl<T: Copy + Clone + FromF32Color> GradientLut<T> {
+impl<T: FromF32Color> GradientLut<T> {
/// Create a new lookup table.
- fn new(ranges: &[GradientRange]) -> Self {
- // TODO: SIMDify
+ fn new<S: Simd>(simd: S, ranges: &[GradientRange]) -> Self {
+ // Inspired by Blend2D.
+ let lut_size = match ranges.len() {
+ 1 => 256,
+ 2 => 512,
+ _ => 1024,
+ };
- // Somewhat arbitrary, but we use 1024 samples for
- // more than 2 stops, and 512 for just 2 stops. Blend2D does
- // something similar.
- let lut_size = if ranges.len() > 1 { 1024 } else { 512 };
+ // Add a bit of padding since we always process in blocks of 4, even though less might be
+ // needed.
+ let mut lut = vec![[T::ZERO, T::ZERO, T::ZERO, T::ZERO]; lut_size + 3];
- let mut lut = Vec::with_capacity(lut_size);
+ // Calculate how many indices are covered by each range.
+ let ramps = {
+ let mut ramps = Vec::with_capacity(ranges.len());
+ let mut prev_idx = 0;
- let inv_lut_size = 1.0 / lut_size as f32;
+ for range in ranges {
+ let max_idx = (range.x1 * lut_size as f32) as usize;
- let mut cur_idx = 0;
-
- (0..lut_size).for_each(|idx| {
- let t_val = idx as f32 * inv_lut_size;
-
- while ranges[cur_idx].x1 < t_val {
- cur_idx += 1;
+ ramps.push((prev_idx..max_idx, range));
+ prev_idx = max_idx;
}
- let range = &ranges[cur_idx];
- let mut interpolated = [0.0_f32; 4];
+ ramps
+ };
- let bias = range.bias;
+ let inv_lut_size = f32x4::splat(simd, 1.0 / lut_size as f32);
+ let add_factor = f32x4::from_slice(simd, &[0.0, 1.0, 2.0, 3.0]) * inv_lut_size;
- for (comp_idx, comp) in interpolated.iter_mut().enumerate() {
- *comp = bias[comp_idx] + range.scale[comp_idx] * t_val;
- }
+ for (ramp_range, range) in ramps {
+ let biases = f32x16::block_splat(f32x4::from_slice(simd, &range.bias));
+ let scales = f32x16::block_splat(f32x4::from_slice(simd, &range.scale));
- lut.push(T::from_f32(&interpolated));
- });
+ ramp_range.step_by(4).for_each(|idx| {
+ let t_vals = add_factor.madd(f32x4::splat(simd, idx as f32), inv_lut_size);
+
+ let t_vals = element_wise_splat(simd, t_vals);
+
+ let mut result = biases.madd(scales, t_vals);
+ let alphas = result.splat_4th();
+ // Due to floating-point impreciseness, it can happen that
+ // values either become greater than 1 or the RGB channels
+ // become greater than the alpha channel. To prevent overflows
+ // in later parts of the pipeline, we need to take the minimum here.
+ result = result.min(1.0).min(alphas);
+ let (im1, im2) = simd.split_f32x16(result);
+ let (r1, r2) = simd.split_f32x8(im1);
+ let (r3, r4) = simd.split_f32x8(im2);
+
+ let lut = &mut lut[idx..][..4];
+ lut[0] = T::from_f32(r1);
+ lut[1] = T::from_f32(r2);
+ lut[2] = T::from_f32(r3);
+ lut[3] = T::from_f32(r4);
+ });
+ }
+
+ // Due to SIMD we worked in blocks of 4, so we need to truncate to the actual length.
+ lut.truncate(lut_size);
let scale = lut.len() as f32 - 1.0;
diff --git a/sparse_strips/vello_common/src/lib.rs b/sparse_strips/vello_common/src/lib.rs
index 2f2575f..0032839 100644
--- a/sparse_strips/vello_common/src/lib.rs
+++ b/sparse_strips/vello_common/src/lib.rs
@@ -77,6 +77,7 @@
#[cfg(feature = "pico_svg")]
pub mod pico_svg;
pub mod pixmap;
+pub mod simd;
pub mod strip;
pub mod tile;
mod util;
diff --git a/sparse_strips/vello_common/src/simd.rs b/sparse_strips/vello_common/src/simd.rs
new file mode 100644
index 0000000..7f92005
--- /dev/null
+++ b/sparse_strips/vello_common/src/simd.rs
@@ -0,0 +1,98 @@
+// Copyright 2025 the Vello Authors
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+//! A number of SIMD extension traits.
+
+use fearless_simd::*;
+
+/// Splatting every 4th element in the vector, used for splatting the alpha value of
+/// a color to all lanes.
+pub trait Splat4thExt<S> {
+ /// Splat every 4th element of the vector.
+ fn splat_4th(self) -> Self;
+}
+
+impl<S: Simd> Splat4thExt<S> for f32x4<S> {
+ #[inline(always)]
+ fn splat_4th(self) -> Self {
+ // TODO: Explore whether it's just faster to manually access the 4th element and splat it.
+ let zip1 = self.zip_high(self);
+ zip1.zip_high(zip1)
+ }
+}
+
+impl<S: Simd> Splat4thExt<S> for f32x8<S> {
+ #[inline(always)]
+ fn splat_4th(self) -> Self {
+ let (mut p1, mut p2) = self.simd.split_f32x8(self);
+ p1 = p1.splat_4th();
+ p2 = p2.splat_4th();
+
+ self.simd.combine_f32x4(p1, p2)
+ }
+}
+
+impl<S: Simd> Splat4thExt<S> for f32x16<S> {
+ #[inline(always)]
+ fn splat_4th(self) -> Self {
+ let (mut p1, mut p2) = self.simd.split_f32x16(self);
+ p1 = p1.splat_4th();
+ p2 = p2.splat_4th();
+
+ self.simd.combine_f32x8(p1, p2)
+ }
+}
+
+impl<S: Simd> Splat4thExt<S> for u8x16<S> {
+ #[inline(always)]
+ fn splat_4th(self) -> Self {
+ // TODO: SIMDify
+ Self {
+ val: [
+ self.val[3],
+ self.val[3],
+ self.val[3],
+ self.val[3],
+ self.val[7],
+ self.val[7],
+ self.val[7],
+ self.val[7],
+ self.val[11],
+ self.val[11],
+ self.val[11],
+ self.val[11],
+ self.val[15],
+ self.val[15],
+ self.val[15],
+ self.val[15],
+ ],
+ simd: self.simd,
+ }
+ }
+}
+
+impl<S: Simd> Splat4thExt<S> for u8x32<S> {
+ #[inline(always)]
+ fn splat_4th(self) -> Self {
+ let (mut p1, mut p2) = self.simd.split_u8x32(self);
+ p1 = p1.splat_4th();
+ p2 = p2.splat_4th();
+
+ self.simd.combine_u8x16(p1, p2)
+ }
+}
+
+/// Splat each single element in the vector to 4 lanes.
+#[inline(always)]
+pub fn element_wise_splat<S: Simd>(simd: S, input: f32x4<S>) -> f32x16<S> {
+ simd.combine_f32x8(
+ simd.combine_f32x4(
+ f32x4::splat(simd, input.val[0]),
+ f32x4::splat(simd, input.val[1]),
+ ),
+ simd.combine_f32x4(
+ f32x4::splat(simd, input.val[2]),
+ f32x4::splat(simd, input.val[3]),
+ ),
+ )
+}
diff --git a/sparse_strips/vello_cpu/src/fine/common/gradient/mod.rs b/sparse_strips/vello_cpu/src/fine/common/gradient/mod.rs
index 42183dc..a39e6e5 100644
--- a/sparse_strips/vello_cpu/src/fine/common/gradient/mod.rs
+++ b/sparse_strips/vello_cpu/src/fine/common/gradient/mod.rs
@@ -50,7 +50,7 @@
has_undefined: bool,
t_vals: &'a [f32],
) -> Self {
- let lut = gradient.f32_lut();
+ let lut = gradient.f32_lut(simd);
let scale_factor = f32x8::splat(simd, lut.scale_factor());
Self {
diff --git a/sparse_strips/vello_cpu/src/fine/common/image.rs b/sparse_strips/vello_cpu/src/fine/common/image.rs
index 39bc6ad..b61c9f1 100644
--- a/sparse_strips/vello_cpu/src/fine/common/image.rs
+++ b/sparse_strips/vello_cpu/src/fine/common/image.rs
@@ -1,7 +1,6 @@
// Copyright 2025 the Vello Authors
// SPDX-License-Identifier: Apache-2.0 OR MIT
-use crate::fine::highp::element_wise_splat;
use crate::fine::macros::{f32x16_painter, u8x16_painter};
use crate::fine::{PosExt, Splat4thExt, u8_to_f32};
use crate::kurbo::Point;
@@ -9,6 +8,7 @@
use vello_common::encode::EncodedImage;
use vello_common::fearless_simd::{Bytes, Simd, SimdBase, SimdFloat, f32x4, f32x16, u8x16, u32x4};
use vello_common::pixmap::Pixmap;
+use vello_common::simd::element_wise_splat;
/// A painter for nearest-neighbor images with no skewing.
#[derive(Debug)]
diff --git a/sparse_strips/vello_cpu/src/fine/highp/mod.rs b/sparse_strips/vello_cpu/src/fine/highp/mod.rs
index 9ac35a7..557900e 100644
--- a/sparse_strips/vello_cpu/src/fine/highp/mod.rs
+++ b/sparse_strips/vello_cpu/src/fine/highp/mod.rs
@@ -2,12 +2,9 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
use crate::fine::FineKernel;
-use crate::fine::common::gradient::GradientPainter;
use crate::fine::{COLOR_COMPONENTS, Painter};
use crate::peniko::BlendMode;
use crate::region::Region;
-use alloc::boxed::Box;
-use vello_common::encode::EncodedGradient;
use vello_common::fearless_simd::*;
use vello_common::paint::PremulColor;
use vello_common::tile::Tile;
@@ -61,15 +58,6 @@
}
}
- fn gradient_painter<'a>(
- simd: S,
- gradient: &'a EncodedGradient,
- has_undefined: bool,
- t_vals: &'a [f32],
- ) -> Box<dyn Painter + 'a> {
- Box::new(GradientPainter::new(simd, gradient, has_undefined, t_vals))
- }
-
fn apply_mask(
simd: S,
dest: &mut [Self::Numeric],
@@ -83,7 +71,7 @@
}
#[inline(always)]
- fn apply_painter<'a>(_: S, dest: &mut [Self::Numeric], mut painter: Box<dyn Painter + 'a>) {
+ fn apply_painter<'a>(_: S, dest: &mut [Self::Numeric], mut painter: impl Painter + 'a) {
painter.paint_f32(dest);
}
@@ -280,20 +268,6 @@
}
#[inline(always)]
-pub(crate) fn element_wise_splat<S: Simd>(simd: S, input: f32x4<S>) -> f32x16<S> {
- simd.combine_f32x8(
- simd.combine_f32x4(
- f32x4::splat(simd, input.val[0]),
- f32x4::splat(simd, input.val[1]),
- ),
- simd.combine_f32x4(
- f32x4::splat(simd, input.val[2]),
- f32x4::splat(simd, input.val[3]),
- ),
- )
-}
-
-#[inline(always)]
fn extract_masks<S: Simd>(simd: S, masks: &[u8]) -> f32x16<S> {
let mut base_mask = [
masks[0] as f32,
diff --git a/sparse_strips/vello_cpu/src/fine/lowp/gradient.rs b/sparse_strips/vello_cpu/src/fine/lowp/gradient.rs
index f587739..f71320d 100644
--- a/sparse_strips/vello_cpu/src/fine/lowp/gradient.rs
+++ b/sparse_strips/vello_cpu/src/fine/lowp/gradient.rs
@@ -19,7 +19,7 @@
impl<'a, S: Simd> GradientPainter<'a, S> {
pub(crate) fn new(simd: S, gradient: &'a EncodedGradient, t_vals: &'a [f32]) -> Self {
- let lut = gradient.u8_lut();
+ let lut = gradient.u8_lut(simd);
let scale_factor = f32x16::splat(simd, lut.scale_factor());
Self {
diff --git a/sparse_strips/vello_cpu/src/fine/lowp/image.rs b/sparse_strips/vello_cpu/src/fine/lowp/image.rs
index 9a555f6..8a61eaa 100644
--- a/sparse_strips/vello_cpu/src/fine/lowp/image.rs
+++ b/sparse_strips/vello_cpu/src/fine/lowp/image.rs
@@ -2,12 +2,12 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
use crate::fine::common::image::{ImagePainterData, extend, sample};
-use crate::fine::highp::element_wise_splat;
use crate::fine::macros::u8x16_painter;
use crate::fine::{PosExt, f32_to_u8};
use vello_common::encode::EncodedImage;
use vello_common::fearless_simd::{Simd, SimdBase, f32x4, u8x16};
use vello_common::pixmap::Pixmap;
+use vello_common::simd::element_wise_splat;
/// A faster bilinear image renderer for the u8 pipeline.
#[derive(Debug)]
diff --git a/sparse_strips/vello_cpu/src/fine/lowp/mod.rs b/sparse_strips/vello_cpu/src/fine/lowp/mod.rs
index 26e0ef9..bdb045b 100644
--- a/sparse_strips/vello_cpu/src/fine/lowp/mod.rs
+++ b/sparse_strips/vello_cpu/src/fine/lowp/mod.rs
@@ -5,21 +5,17 @@
mod gradient;
mod image;
-use crate::fine::common;
-use crate::fine::common::image::FilteredImagePainter;
use crate::fine::lowp::image::BilinearImagePainter;
use crate::fine::{COLOR_COMPONENTS, Painter, SCRATCH_BUF_SIZE};
use crate::fine::{FineKernel, f32_to_u8, highp, u8_to_f32};
use crate::peniko::BlendMode;
use crate::region::Region;
use crate::util::Div255Ext;
-use alloc::boxed::Box;
use bytemuck::cast_slice;
use vello_common::coarse::WideTile;
use vello_common::encode::{EncodedGradient, EncodedImage};
use vello_common::fearless_simd::*;
use vello_common::paint::PremulColor;
-use vello_common::peniko::ImageQuality;
use vello_common::pixmap::Pixmap;
use vello_common::tile::Tile;
@@ -58,37 +54,19 @@
fn gradient_painter<'a>(
simd: S,
gradient: &'a EncodedGradient,
- has_undefined: bool,
t_vals: &'a [f32],
- ) -> Box<dyn Painter + 'a> {
- if has_undefined {
- Box::new(common::gradient::GradientPainter::new(
- simd,
- gradient,
- has_undefined,
- t_vals,
- ))
- } else {
- Box::new(gradient::GradientPainter::new(simd, gradient, t_vals))
- }
+ ) -> impl Painter + 'a {
+ gradient::GradientPainter::new(simd, gradient, t_vals)
}
- fn filtered_image_painter<'a>(
+ fn medium_quality_image_painter<'a>(
simd: S,
image: &'a EncodedImage,
pixmap: &'a Pixmap,
start_x: u16,
start_y: u16,
- ) -> Box<dyn Painter + 'a> {
- if image.quality == ImageQuality::Medium {
- Box::new(BilinearImagePainter::new(
- simd, image, pixmap, start_x, start_y,
- ))
- } else {
- Box::new(FilteredImagePainter::new(
- simd, image, pixmap, start_x, start_y,
- ))
- }
+ ) -> impl Painter + 'a {
+ BilinearImagePainter::new(simd, image, pixmap, start_x, start_y)
}
fn apply_mask(
@@ -106,7 +84,7 @@
}
#[inline(always)]
- fn apply_painter<'a>(_: S, dest: &mut [Self::Numeric], mut painter: Box<dyn Painter + 'a>) {
+ fn apply_painter<'a>(_: S, dest: &mut [Self::Numeric], mut painter: impl Painter + 'a) {
painter.paint_u8(dest);
}
diff --git a/sparse_strips/vello_cpu/src/fine/mod.rs b/sparse_strips/vello_cpu/src/fine/mod.rs
index 6991517..9feb999 100644
--- a/sparse_strips/vello_cpu/src/fine/mod.rs
+++ b/sparse_strips/vello_cpu/src/fine/mod.rs
@@ -5,9 +5,8 @@
mod highp;
mod lowp;
-use crate::peniko::{BlendMode, Compose, Mix};
+use crate::peniko::{BlendMode, Compose, ImageQuality, Mix};
use crate::region::Region;
-use alloc::boxed::Box;
use alloc::vec;
use alloc::vec::Vec;
use core::fmt::Debug;
@@ -24,10 +23,10 @@
pub const SCRATCH_BUF_SIZE: usize =
WideTile::WIDTH as usize * Tile::HEIGHT as usize * COLOR_COMPONENTS;
-use crate::fine::common::gradient::calculate_t_vals;
use crate::fine::common::gradient::linear::SimdLinearKind;
use crate::fine::common::gradient::radial::SimdRadialKind;
use crate::fine::common::gradient::sweep::SimdSweepKind;
+use crate::fine::common::gradient::{GradientPainter, calculate_t_vals};
use crate::fine::common::image::{FilteredImagePainter, NNImagePainter, PlainNNImagePainter};
use crate::fine::common::rounded_blurred_rect::BlurredRoundedRectFiller;
use crate::util::{BlendModeExt, EncodedImageExt};
@@ -37,6 +36,7 @@
Simd, SimdBase, SimdFloat, SimdInto, f32x4, f32x8, f32x16, u8x16, u8x32, u32x4, u32x8,
};
use vello_common::pixmap::Pixmap;
+use vello_common::simd::Splat4thExt;
pub type ScratchBuf<F> = [F; SCRATCH_BUF_SIZE];
@@ -91,24 +91,29 @@
#[inline(always)]
pub(crate) fn f32_to_u8<S: Simd>(val: f32x16<S>) -> u8x16<S> {
- // TODO: SIMDify
+ let simd = val.simd;
+ // Note that converting to u32 first using SIMD and then u8
+ // is much faster than converting directly from f32 to u8.
+ let converted = simd.cvt_u32_f32x16(val);
+
+ // TODO: Maybe we can also do this using SIMD?
[
- val.val[0] as u8,
- val.val[1] as u8,
- val.val[2] as u8,
- val.val[3] as u8,
- val.val[4] as u8,
- val.val[5] as u8,
- val.val[6] as u8,
- val.val[7] as u8,
- val.val[8] as u8,
- val.val[9] as u8,
- val.val[10] as u8,
- val.val[11] as u8,
- val.val[12] as u8,
- val.val[13] as u8,
- val.val[14] as u8,
- val.val[15] as u8,
+ converted[0] as u8,
+ converted[1] as u8,
+ converted[2] as u8,
+ converted[3] as u8,
+ converted[4] as u8,
+ converted[5] as u8,
+ converted[6] as u8,
+ converted[7] as u8,
+ converted[8] as u8,
+ converted[9] as u8,
+ converted[10] as u8,
+ converted[11] as u8,
+ converted[12] as u8,
+ converted[13] as u8,
+ converted[14] as u8,
+ converted[15] as u8,
]
.simd_into(val.simd)
}
@@ -191,9 +196,18 @@
fn gradient_painter<'a>(
simd: S,
gradient: &'a EncodedGradient,
- has_undefined: bool,
t_vals: &'a [f32],
- ) -> Box<dyn Painter + 'a>;
+ ) -> impl Painter + 'a {
+ GradientPainter::new(simd, gradient, false, t_vals)
+ }
+ /// Return the painter used for painting gradients, with support for masking undefined locations.
+ fn gradient_painter_with_undefined<'a>(
+ simd: S,
+ gradient: &'a EncodedGradient,
+ t_vals: &'a [f32],
+ ) -> impl Painter + 'a {
+ GradientPainter::new(simd, gradient, true, t_vals)
+ }
/// Return the painter used for painting plain nearest-neighbor images.
///
/// Plain nearest-neighbor images are images with the quality 'Low' and no skewing component in their
@@ -204,10 +218,8 @@
pixmap: &'a Pixmap,
start_x: u16,
start_y: u16,
- ) -> Box<dyn Painter + 'a> {
- Box::new(PlainNNImagePainter::new(
- simd, image, pixmap, start_x, start_y,
- ))
+ ) -> impl Painter + 'a {
+ PlainNNImagePainter::new(simd, image, pixmap, start_x, start_y)
}
/// Return the painter used for painting plain nearest-neighbor images.
///
@@ -218,20 +230,28 @@
pixmap: &'a Pixmap,
start_x: u16,
start_y: u16,
- ) -> Box<dyn Painter + 'a> {
- Box::new(NNImagePainter::new(simd, image, pixmap, start_x, start_y))
+ ) -> impl Painter + 'a {
+ NNImagePainter::new(simd, image, pixmap, start_x, start_y)
}
- /// Return the painter used for painting image with `Medium` or `High` quality.
- fn filtered_image_painter<'a>(
+ /// Return the painter used for painting image with `Medium` quality.
+ fn medium_quality_image_painter<'a>(
simd: S,
image: &'a EncodedImage,
pixmap: &'a Pixmap,
start_x: u16,
start_y: u16,
- ) -> Box<dyn Painter + 'a> {
- Box::new(FilteredImagePainter::new(
- simd, image, pixmap, start_x, start_y,
- ))
+ ) -> impl Painter + 'a {
+ FilteredImagePainter::new(simd, image, pixmap, start_x, start_y)
+ }
+ /// Return the painter used for painting image with `High` quality.
+ fn high_quality_image_painter<'a>(
+ simd: S,
+ image: &'a EncodedImage,
+ pixmap: &'a Pixmap,
+ start_x: u16,
+ start_y: u16,
+ ) -> impl Painter + 'a {
+ FilteredImagePainter::new(simd, image, pixmap, start_x, start_y)
}
/// Return the painter used for painting blurred rounded rectangles.
fn blurred_rounded_rectangle_painter<'a>(
@@ -239,13 +259,13 @@
rect: &'a EncodedBlurredRoundedRectangle,
start_x: u16,
start_y: u16,
- ) -> Box<dyn Painter + 'a> {
- Box::new(BlurredRoundedRectFiller::new(simd, rect, start_x, start_y))
+ ) -> impl Painter + 'a {
+ BlurredRoundedRectFiller::new(simd, rect, start_x, start_y)
}
/// Apply the mask to the destination buffer.
fn apply_mask(simd: S, dest: &mut [Self::Numeric], src: impl Iterator<Item = Self::NumericVec>);
/// Apply the painter to the destination buffer.
- fn apply_painter<'a>(simd: S, dest: &mut [Self::Numeric], painter: Box<dyn Painter + 'a>);
+ fn apply_painter<'a>(simd: S, dest: &mut [Self::Numeric], painter: impl Painter + 'a);
/// Do basic alpha compositing with a solid color.
fn alpha_composite_solid(
simd: S,
@@ -513,7 +533,7 @@
fill_complex_paint!(
g.has_opacities,
- T::gradient_painter(self.simd, g, false, f32_buf)
+ T::gradient_painter(self.simd, g, f32_buf)
);
}
EncodedKind::Sweep(s) => {
@@ -528,7 +548,7 @@
fill_complex_paint!(
g.has_opacities,
- T::gradient_painter(self.simd, g, false, f32_buf)
+ T::gradient_painter(self.simd, g, f32_buf)
);
}
EncodedKind::Radial(r) => {
@@ -541,10 +561,17 @@
start_y,
);
- fill_complex_paint!(
- g.has_opacities,
- T::gradient_painter(self.simd, g, r.has_undefined(), f32_buf)
- );
+ if r.has_undefined() {
+ fill_complex_paint!(
+ g.has_opacities,
+ T::gradient_painter_with_undefined(self.simd, g, f32_buf)
+ );
+ } else {
+ fill_complex_paint!(
+ g.has_opacities,
+ T::gradient_painter(self.simd, g, f32_buf)
+ );
+ }
}
}
}
@@ -555,12 +582,21 @@
match (i.has_skew(), i.nearest_neighbor()) {
(_, false) => {
- fill_complex_paint!(
- i.has_opacities,
- T::filtered_image_painter(
- self.simd, i, pixmap, start_x, start_y
- )
- );
+ if i.quality == ImageQuality::Medium {
+ fill_complex_paint!(
+ i.has_opacities,
+ T::medium_quality_image_painter(
+ self.simd, i, pixmap, start_x, start_y
+ )
+ );
+ } else {
+ fill_complex_paint!(
+ i.has_opacities,
+ T::high_quality_image_painter(
+ self.simd, i, pixmap, start_x, start_y
+ )
+ );
+ }
}
(false, true) => {
fill_complex_paint!(
@@ -587,15 +623,19 @@
let (source_buffer, rest) = self.blend_buf.split_last_mut().unwrap();
let target_buffer = rest.last_mut().unwrap();
- T::blend(
- self.simd,
- target_buffer,
- source_buffer
- .chunks_exact(T::Composite::LENGTH)
- .map(|s| T::Composite::from_slice(self.simd, s)),
- blend_mode,
- None,
- );
+ if blend_mode.is_default() {
+ T::alpha_composite_buffer(self.simd, target_buffer, source_buffer, None);
+ } else {
+ T::blend(
+ self.simd,
+ target_buffer,
+ source_buffer
+ .chunks_exact(T::Composite::LENGTH)
+ .map(|s| T::Composite::from_slice(self.simd, s)),
+ blend_mode,
+ None,
+ );
+ }
}
fn clip(&mut self, x: usize, width: usize, alphas: Option<&[u8]>) {
@@ -644,81 +684,6 @@
}
}
-/// Splatting every 4th element in the vector, used for splatting the alpha value of
-/// a color to all lanes.
-pub trait Splat4thExt<S> {
- fn splat_4th(self) -> Self;
-}
-
-impl<S: Simd> Splat4thExt<S> for f32x4<S> {
- #[inline(always)]
- fn splat_4th(self) -> Self {
- let zip1 = self.zip_high(self);
- zip1.zip_high(zip1)
- }
-}
-
-impl<S: Simd> Splat4thExt<S> for f32x8<S> {
- #[inline(always)]
- fn splat_4th(self) -> Self {
- let (mut p1, mut p2) = self.simd.split_f32x8(self);
- p1 = p1.splat_4th();
- p2 = p2.splat_4th();
-
- self.simd.combine_f32x4(p1, p2)
- }
-}
-
-impl<S: Simd> Splat4thExt<S> for f32x16<S> {
- #[inline(always)]
- fn splat_4th(self) -> Self {
- let (mut p1, mut p2) = self.simd.split_f32x16(self);
- p1 = p1.splat_4th();
- p2 = p2.splat_4th();
-
- self.simd.combine_f32x8(p1, p2)
- }
-}
-
-impl<S: Simd> Splat4thExt<S> for u8x16<S> {
- #[inline(always)]
- fn splat_4th(self) -> Self {
- // TODO: SIMDify
- Self {
- val: [
- self.val[3],
- self.val[3],
- self.val[3],
- self.val[3],
- self.val[7],
- self.val[7],
- self.val[7],
- self.val[7],
- self.val[11],
- self.val[11],
- self.val[11],
- self.val[11],
- self.val[15],
- self.val[15],
- self.val[15],
- self.val[15],
- ],
- simd: self.simd,
- }
- }
-}
-
-impl<S: Simd> Splat4thExt<S> for u8x32<S> {
- #[inline(always)]
- fn splat_4th(self) -> Self {
- let (mut p1, mut p2) = self.simd.split_u8x32(self);
- p1 = p1.splat_4th();
- p2 = p2.splat_4th();
-
- self.simd.combine_u8x16(p1, p2)
- }
-}
-
/// The results of an f32 shader, where each channel stored separately.
pub(crate) struct ShaderResultF32<S: Simd> {
pub(crate) r: f32x8<S>,
diff --git a/sparse_strips/vello_sparse_tests/snapshots/glyphs_colr_noto.png b/sparse_strips/vello_sparse_tests/snapshots/glyphs_colr_noto.png
index 35eb53c..167770b 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/glyphs_colr_noto.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/glyphs_colr_noto.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:53e7b8bd0aec7a12ca51f232e8956e42ef0a0bf190cf0dc0edd2b05e241ee540
-size 9946
+oid sha256:fc3d054072d054284ee72eb4ab71c66d21f11dd72d8d8f3b881db41f2f31992e
+size 9903
diff --git a/sparse_strips/vello_sparse_tests/snapshots/glyphs_colr_test_glyphs.png b/sparse_strips/vello_sparse_tests/snapshots/glyphs_colr_test_glyphs.png
index 49bfbe4..5e65bbd 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/glyphs_colr_test_glyphs.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/glyphs_colr_test_glyphs.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d45439545a4cb578d80ed9f69d2daad1b0404b91ee5ba2b7465ffbdfb2a431b0
-size 127633
+oid sha256:abe856ee4ff107fb268064518d8fd74575714c286b2079eafc6c5a5f13aed503
+size 127370
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_2_stops.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_2_stops.png
index b023591..cbcc9e4 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_2_stops.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_2_stops.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f97abbc5e58147f9a231c52e7ebb21d6765b6b6c3278569fbf28181a9f1ff279
-size 257
+oid sha256:a877bae5cc9af41bad3219e5300c56a331cbaac757485913236b1fa19d99af50
+size 245
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_2_stops_with_alpha.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_2_stops_with_alpha.png
index 78d6600..e10a574 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_2_stops_with_alpha.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_2_stops_with_alpha.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c9a97e0a76f74c318d0d6a928a34bb373ca22ceaf7c156df8ebf04be61b34e1e
-size 263
+oid sha256:67ccd25afd8f91572c400afee979222fff1a18db4304d793a032aa7dca75447b
+size 266
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_negative_direction.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_negative_direction.png
index 57d2662..b242c99 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_negative_direction.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_negative_direction.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:013e67184e021ec1792a8dbb0a227f2cf5f2dba7a2cc9e4df8820768691edd20
-size 258
+oid sha256:cfcee79b2d963755cce44f8995e793037014a3916d516fcb730644365909be35
+size 247
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_spread_method_pad.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_spread_method_pad.png
index 2324add..4017d77 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_spread_method_pad.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_spread_method_pad.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3876d67057ffa18030418eabeaff2697f1830bb86860fd6b55b883702e9553ca
-size 435
+oid sha256:14dccd7a9a993068f2062d107a9b5cfbc6d4c27be6f7b2e1a8fefae2d0971b9c
+size 453
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_spread_method_reflect.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_spread_method_reflect.png
index de10c62..b3b3207 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_spread_method_reflect.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_spread_method_reflect.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:fbcd96d7e9c64dd61bce6c10a3576f0002324fd26b9fa8bbf41df2c9834bf5c1
+oid sha256:6c5155f52b5c70a000513883753a8deb09c13f90cd8597e9a46a574babeb36ea
size 615
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_spread_method_repeat.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_spread_method_repeat.png
index a32d6a1..8232587 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_spread_method_repeat.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_spread_method_repeat.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:aa9f2ea69723ae2e96845ccc310772d181d9041b623fbeedf68809bf0048d35d
+oid sha256:6a332600734a257b02fccc8fb3e94d87611e3a12ac75646fa0efd236a365f1e6
size 415
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_vertical.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_vertical.png
index 83d2925..2085d3a 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_vertical.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_vertical.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:bcb2361ba91ec72b20aa2455ab337d9eac2f8d421c4c9690746c586ab6f33aed
-size 277
+oid sha256:6e83eea44562f0e330112e4f7625a1712e35f56e3128877480d2251cf6d260c9
+size 272
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_downward_y.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_downward_y.png
index bbb8223..04ea3bf 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_downward_y.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_downward_y.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e1f4ec72f27f676929bb777a45aabdc9de23b41359b5d294d97d9a077b908ecc
-size 461
+oid sha256:8ef89a7548774004759ba8969a90956b4f18e642abdb97541f8a96736fe32a4c
+size 533
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_identity.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_identity.png
index 70a8c19..f2e06b3 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_identity.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_identity.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5e35fc567139cae0b1b381b7d0a28cb778f3563570e1ae18316b3e47b2d925b9
+oid sha256:c11042007db24f708df578043488e21e02a16ea3cac0230cb17a3cdb05e86eb1
size 438
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_negative_scale.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_negative_scale.png
index cc4224e..100ac0d 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_negative_scale.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_negative_scale.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:14cf16def2ef8f2650b7cf4936984ca38999c20a99acb2de74673f4a630cb402
+oid sha256:d6592fa516bc2a20e20bd23e30b424f93524d3c03d92e841d5830a312d6bc652
size 444
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_scale.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_scale.png
index 70a8c19..f2e06b3 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_scale.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_scale.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5e35fc567139cae0b1b381b7d0a28cb778f3563570e1ae18316b3e47b2d925b9
+oid sha256:c11042007db24f708df578043488e21e02a16ea3cac0230cb17a3cdb05e86eb1
size 438
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_scale_and_translate.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_scale_and_translate.png
index 70a8c19..f2e06b3 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_scale_and_translate.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_scale_and_translate.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5e35fc567139cae0b1b381b7d0a28cb778f3563570e1ae18316b3e47b2d925b9
+oid sha256:c11042007db24f708df578043488e21e02a16ea3cac0230cb17a3cdb05e86eb1
size 438
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_scaling_non_uniform.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_scaling_non_uniform.png
index 7cd787f..65ec90b 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_scaling_non_uniform.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_scaling_non_uniform.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e2d292ce2d2f1c9f5336601a9f3f89f848ae0098153067ab17309c063a74c6b8
-size 528
+oid sha256:0078167dd363a6d0bc21a00d8ab6f6755ff400f9cd5b678099afdd3e95061cf3
+size 529
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_translate.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_translate.png
index 70a8c19..f2e06b3 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_translate.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_transform_translate.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5e35fc567139cae0b1b381b7d0a28cb778f3563570e1ae18316b3e47b2d925b9
+oid sha256:c11042007db24f708df578043488e21e02a16ea3cac0230cb17a3cdb05e86eb1
size 438
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_upward_y.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_upward_y.png
index b207a69..2fb15bf 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_upward_y.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_linear_with_upward_y.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3fc63cc58fea1d5769e2c2b7dcd28d179d52a7deef94cca78ca1f3602fa91065
-size 446
+oid sha256:1147e89ae951f7ead22beb24137a8ca41e4d42fb654253a230d97101a3f2ce57
+size 554
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_on_3_wide_tiles.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_on_3_wide_tiles.png
index 6406951..a39af52 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_on_3_wide_tiles.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_on_3_wide_tiles.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e26a9adc3b46c70f85b6bb59eb984b4061812aae631fdfe049223349c1b27d58
-size 251
+oid sha256:c0052b1875e7d87f62535a1cdea8425693855f388a826a36b88cd6ec47d1e3a9
+size 923
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_2_stops.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_2_stops.png
index 5e34954..fb9ce98 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_2_stops.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_2_stops.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:aca1f00d80d17532e862c0999e6ce4fa19f4c6c719fbb2f72e9fc4a466aa92ed
-size 1586
+oid sha256:bec40b2a9a0e7ba6088e0ef7e0003ced3b2f1ccab0b31ec49237f134dd31bd40
+size 1562
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_2_stops_with_alpha.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_2_stops_with_alpha.png
index 28de26c..573374e 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_2_stops_with_alpha.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_2_stops_with_alpha.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:089cdc8f0e527412f0d27f7a918ea67040fb8bbe4016b67498f9fcb436107093
-size 2121
+oid sha256:e3aecfcc8de69f3bff7db5722d296b5de83a553fb540f78686f71ea94f498c14
+size 1832
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_4_stops.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_4_stops.png
index 05a6349..8659de9 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_4_stops.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_4_stops.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:1f31616c5347425a4cd661d6d9415ab7ed8b14fa6bcaa2277bb2ca57a2ef43c9
-size 2554
+oid sha256:66a7b88735ef6b4508c6ddbaee9c22eedb25f2753355b0c2d3819c443153f38f
+size 2549
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_c0_bigger.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_c0_bigger.png
index 9014b57..a5c9aca 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_c0_bigger.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_c0_bigger.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:32166e19224571132f985b41f60efc6ddcafaefa3ff65d1883c4b1ffbfb9e4e4
-size 2823
+oid sha256:afbc7185a6d5fbd1fc6658d9188cee985d82958a52b695524bf407505c35e944
+size 2820
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_center_offset_bottom_left.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_center_offset_bottom_left.png
index d8528a3..523ce53 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_center_offset_bottom_left.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_center_offset_bottom_left.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:dd41f7cee4f0ea9a1a76ecc0fb62a2dc49d4b9b2ef4d15a2a6185a9b929071a4
-size 5531
+oid sha256:a0098c400931d6e1f357a97113a4a92e08814f6c052792aad6ffc5fe9e6612cc
+size 5533
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_center_offset_bottom_right.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_center_offset_bottom_right.png
index a4798e8..62009c1 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_center_offset_bottom_right.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_center_offset_bottom_right.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:82163de8e7d6136eeab0270a1303255e54d10b31ceab023252695037d46d69d7
-size 5519
+oid sha256:3b3652268eb4be0f1d36882d5d07a31b8ee674718ad65d876de16fbc78841f73
+size 5526
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_center_offset_top_left.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_center_offset_top_left.png
index 6dc449c..a9c6f03 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_center_offset_top_left.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_center_offset_top_left.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:64f2a7842e59fed9480bf30440c9a72d7efb8c2f16bee4b5eaba9956f4d25d50
-size 5421
+oid sha256:5af05767fbfc6462a2533d9a79560ef4c9154e017342b6aa49b724ffeb109878
+size 5399
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_center_offset_top_right.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_center_offset_top_right.png
index 3f65a99..8fb8b0d 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_center_offset_top_right.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_center_offset_top_right.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4acf3782a25167cc410a9a1a98b04b7219719734971dd18ac6f5b609191a60fa
-size 5535
+oid sha256:f5d51721b3b42c4f2421a5ab2e7a8cbd71dcaa95e8d27c4e50343a4529b22c68
+size 5537
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_focal_on_circle.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_focal_on_circle.png
index 8a2499c..cc6798f 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_focal_on_circle.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_focal_on_circle.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8eb22784a41237c7a0737eb4e21e0dabfaf4b83c0cab2094055e3560583ed444
-size 1350
+oid sha256:2414285d5e6d60c20dd6e8c5f430fbe23a7d8ca9bdd6a5ba90647fc3e4b9e9c8
+size 1351
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_natively_focal.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_natively_focal.png
index c4981ec..e3b8ae6 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_natively_focal.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_natively_focal.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7fadac6e7f4903a9ed6f1d2c385892c977c9543d4461937977754136f745df53
-size 2816
+oid sha256:cf9cab3557e195ccd9d86b3383324cd223f80a09157b61819282605e71c5a3d7
+size 2794
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_non_overlapping_c0_larger.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_non_overlapping_c0_larger.png
index 60fab80..64b527a 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_non_overlapping_c0_larger.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_non_overlapping_c0_larger.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8c4cc8df97176eef56732c74fdc29ab9dc1d2fb4e39c30ee9a730920c6a2b0c1
-size 1168
+oid sha256:c3a0a48e59be9a451e4cd43a155a4153fde49146b3b586c2617cbda02d763139
+size 1162
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_non_overlapping_c0_smaller.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_non_overlapping_c0_smaller.png
index 926b27e..59c077f 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_non_overlapping_c0_smaller.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_non_overlapping_c0_smaller.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a0e9d6b660d1ab98a44868ccaf84f7f9191e7a2df416eb233b3769f097332a56
-size 899
+oid sha256:a5282cac5c6a3c8a50183c016f578614ce91993dff15d5a796653890eb41e3c0
+size 898
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_non_overlapping_same_size.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_non_overlapping_same_size.png
index 28a6a6d..00dee1e 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_non_overlapping_same_size.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_non_overlapping_same_size.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5711ce3cfde627997e4d7b227825f589285bc6d5cec3bfd3c1da5f17bb79593d
-size 807
+oid sha256:9af665d5e231fdfbcaf8e3155a4c1a73ff3e257034993c556ca5de74a4fb3735
+size 802
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_spread_method_reflect.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_spread_method_reflect.png
index e2fd4c0..6903607 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_spread_method_reflect.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_spread_method_reflect.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6efa4201099a23f7f168a8f0256f43ea56d127616ba21a44d8eeb80a05bc47dd
-size 5408
+oid sha256:9e5fa46dc09ba9aba16d679dd267a894cd0382fd34fd2cb56803ee4e2c6ddb71
+size 5407
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_swapped.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_swapped.png
index 35080bc..b3ecd1e 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_swapped.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_swapped.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2b7e95352c4aa19c0c2144ad555d5500b33cb5bbb6b560bcb0d9e1e877107f8a
-size 2657
+oid sha256:4b4a4aa76a87e5772dae70ba0398db6194cbc41a2c814c216cbb06c4629fd90e
+size 2643
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_with_transform_negative_scale.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_with_transform_negative_scale.png
index 398b66b..e830b7b 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_with_transform_negative_scale.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_with_transform_negative_scale.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:18a56ce62c2691ee99fe72a7375dd3a562d68858b8815a210ce0728a53a18013
-size 1770
+oid sha256:fde6c6a15979fe5343904e6e5064d042d2796a8ad9f7b65d16c269884e5f4671
+size 1773
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_with_transform_scale.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_with_transform_scale.png
index 398b66b..e830b7b 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_with_transform_scale.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_with_transform_scale.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:18a56ce62c2691ee99fe72a7375dd3a562d68858b8815a210ce0728a53a18013
-size 1770
+oid sha256:fde6c6a15979fe5343904e6e5064d042d2796a8ad9f7b65d16c269884e5f4671
+size 1773
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_with_transform_scale_and_translate.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_with_transform_scale_and_translate.png
index 398b66b..e830b7b 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_with_transform_scale_and_translate.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_with_transform_scale_and_translate.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:18a56ce62c2691ee99fe72a7375dd3a562d68858b8815a210ce0728a53a18013
-size 1770
+oid sha256:fde6c6a15979fe5343904e6e5064d042d2796a8ad9f7b65d16c269884e5f4671
+size 1773
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_with_transform_scale_non_uniform.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_with_transform_scale_non_uniform.png
index 0856fb7..d1f7800 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_with_transform_scale_non_uniform.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_radial_with_transform_scale_non_uniform.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:dfc30c0b203dd9dd4d61abb9fce4d79c886f3cc4f7e1fdc3ec0b09a3a657fc55
-size 1732
+oid sha256:daa6dc043412d51b4c6e4675bffb7494b273898a11c4d8642973683e4baa8365
+size 1735
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_2_stops.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_2_stops.png
index 1b2a242..e07d365 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_2_stops.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_2_stops.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7193de7eea6d9cc48a44b96e05c2e90377c71d3b63d8225ce8ed7fcdb83683b4
-size 2434
+oid sha256:491b01d4bd9aa7eb4b5ad48528e3f665f7e19fb69013bca0e356a05cb03c081b
+size 1865
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_2_stops_with_alpha.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_2_stops_with_alpha.png
index bac89ae..987e8c5 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_2_stops_with_alpha.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_2_stops_with_alpha.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c2e3bab1c3ad27de78dde7f38c613e512415a35001e9bf308f84c0d1001b3bbf
-size 2957
+oid sha256:304af60ea89dc393fe69ef78da79f30953131c54a2577bebc343221c123bac3f
+size 2228
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_4_stops.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_4_stops.png
index 733456f..126e8fe 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_4_stops.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_4_stops.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f5a218c27c0f405818d7bc4a40d1a4e6947467c81fb65df3cb406dbbe6e625df
-size 3383
+oid sha256:1d9c5401ccbc483b2a2d0f07ce7f9aabaee96e247f8b36520241a384702b9838
+size 3384
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_complex_shape.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_complex_shape.png
index f7ca15c..9b60af1 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_complex_shape.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_complex_shape.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5576b2d590c8c082f1c117cac1bdb593299a0ffd842341514157f1fbad625d7e
-size 3255
+oid sha256:bdc1973c732e38b070a4bc23a8743549107e62d7c06b2de765c61deb0da19ce9
+size 3247
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_not_in_center.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_not_in_center.png
index 0cd9e5c..3de042c 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_not_in_center.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_not_in_center.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:cdfac6d5b03c50b65cf331a6c9d2942f489f1dac66563597acde884042e27c76
-size 2254
+oid sha256:f628bb4705b8bbcd73f3d99bc1a60ff455a07ddc7b898ee7c4398edd942daaa0
+size 1788
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_spread_method_pad.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_spread_method_pad.png
index 750c14f..02c5669 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_spread_method_pad.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_spread_method_pad.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6fffe33810627764ae4c5b6b4855003da206e91f2eb3f0d7433a146c9cf7ff23
-size 1389
+oid sha256:09c4aabf271a75b31b94e81017009807546117de33ee8dac30d286fbb232e938
+size 1382
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_spread_method_reflect.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_spread_method_reflect.png
index 7bb79aa..870585d 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_spread_method_reflect.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_spread_method_reflect.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ce838296c5c9cd20528f3b8e6090268537aac18c6e4e99b120033545133de062
-size 6447
+oid sha256:eeff76b10377bbf43ea27e14e95b7e4b94d033e90d5de379b5232cdf0e94aa98
+size 6452
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_spread_method_repeat.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_spread_method_repeat.png
index c2730c2..cbf7a76 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_spread_method_repeat.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_spread_method_repeat.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:031821f0593badc957400a1694ec5e5079dce749e7082022a7136f38df250aba
-size 6722
+oid sha256:e8d606edd0d50907d970bada7a3572d7952eeb500f36fe8def3f87868b651cdb
+size 6696
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_with_transform_rotate_2.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_with_transform_rotate_2.png
index 71bd7d7..faf7636 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_with_transform_rotate_2.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_with_transform_rotate_2.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:377f81e818c0aafa803fa6e1b259e4845dba5249dbd0b44bd5727d0400406710
-size 1885
+oid sha256:8844776e1d7d649ccdc53227263dc28c43f1f591ad354266bc2464b4998e8dff
+size 1880
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_with_transform_scale_non_uniform.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_with_transform_scale_non_uniform.png
index db20d5d..bb8f56a 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_with_transform_scale_non_uniform.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_sweep_with_transform_scale_non_uniform.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c31a4ab2be973e4f0e51f31db6b50a2278afe231ad97bfd6f4a2020f788307eb
-size 1235
+oid sha256:963b43dc98fa660f12dcb359e2d157b4db91ede54d97d9b6139c6fbadcfbb8f3
+size 1234
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_with_color_spaces_1.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_with_color_spaces_1.png
index bee0416..d6277a7 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_with_color_spaces_1.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_with_color_spaces_1.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c2061066c09dfb58516026ddff4c29699480eab00d64b8d2bb71842b8dfb5c21
-size 291
+oid sha256:428ee76355d09e08f6fafd0486a1da2e89a599d1a91454aff7e5f81e1b165feb
+size 287
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_with_color_spaces_2.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_with_color_spaces_2.png
index cf7404d..2a9c695 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_with_color_spaces_2.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_with_color_spaces_2.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:bfaa54bbf4612a18eba567032777cbae0e235b5ea07faac2aba649bd8c6b61a5
-size 655
+oid sha256:5692de8a250f22944eb885dda7a66e6436c52a721973d6f2ea4d4ce3c1553546
+size 652
diff --git a/sparse_strips/vello_sparse_tests/snapshots/gradient_with_color_spaces_3.png b/sparse_strips/vello_sparse_tests/snapshots/gradient_with_color_spaces_3.png
index 03d79f9..67e3b8d 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/gradient_with_color_spaces_3.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/gradient_with_color_spaces_3.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b7cc2150e2580c6e901a684452cc02740fe60dbf53b2ea5a225dda10d989ce9c
-size 780
+oid sha256:6449699600b4361c03127784dcad78a8e8b788bf4a0290d49ffba319163474b3
+size 781
diff --git a/sparse_strips/vello_sparse_tests/snapshots/layer_multiple_properties_1.png b/sparse_strips/vello_sparse_tests/snapshots/layer_multiple_properties_1.png
index ceba61f..3c20fc4 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/layer_multiple_properties_1.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/layer_multiple_properties_1.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:82224aa80df9966e22739a8de65844aef955108129f7c9813067eb3111111858
-size 1123
+oid sha256:87c472a0953b56af36dd3105a9e87c9297a7d9216525d6fb57f4d6f82a34cd9b
+size 1139
diff --git a/sparse_strips/vello_sparse_tests/snapshots/mask_alpha.png b/sparse_strips/vello_sparse_tests/snapshots/mask_alpha.png
index bd8a31a..68a13c1 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/mask_alpha.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/mask_alpha.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:60733dea33f69381a988228eb3a1ef79dec2772be5f5cba3233f599efea7b7b3
-size 239
+oid sha256:0c4a5beaee4cd4f2ae76436867bcb3f10ba85762d7cc561085ee25744aa6a06b
+size 243
diff --git a/sparse_strips/vello_sparse_tests/snapshots/mask_luminance.png b/sparse_strips/vello_sparse_tests/snapshots/mask_luminance.png
index e52d5d8..685f5be 100644
--- a/sparse_strips/vello_sparse_tests/snapshots/mask_luminance.png
+++ b/sparse_strips/vello_sparse_tests/snapshots/mask_luminance.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f9d9692bbce31dc35fcfc98897cb90aa8c1b2c935f832e97c48f97bf3d3fb31a
-size 266
+oid sha256:e8d6253f7fe03ced0cdef1eaa2b58dcd305166697051ce8ddc82b5385374cdd4
+size 261