Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions sparse_strips/vello_cpu/src/fine/common/gradient/linear.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2025 the Vello Authors
// SPDX-License-Identifier: Apache-2.0 OR MIT

use crate::fine::PlainPaintPositions;
use crate::fine::common::gradient::SimdGradientKind;
use core::marker::PhantomData;
use vello_common::encode::LinearKind;
Expand All @@ -21,8 +22,10 @@ impl<S: Simd> SimdLinearKind<S> {
}

impl<S: Simd> SimdGradientKind<S> for SimdLinearKind<S> {
type Positions = PlainPaintPositions<S, f32x8<S>>;

#[inline(always)]
fn cur_pos(&self, x_pos: f32x8<S>, _: f32x8<S>) -> f32x8<S> {
x_pos
fn cur_pos(&self, positions: &Self::Positions) -> f32x8<S> {
positions.current()
}
}
19 changes: 9 additions & 10 deletions sparse_strips/vello_cpu/src/fine/common/gradient/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2025 the Vello Authors
// SPDX-License-Identifier: Apache-2.0 OR MIT

use crate::fine::{NumericVec, PosExt};
use crate::fine::{NumericVec, PositionIterator};
use crate::kurbo::Point;
use crate::peniko;
use core::slice::ChunksExact;
Expand All @@ -25,17 +25,14 @@ pub(crate) fn calculate_t_vals<S: Simd, U: SimdGradientKind<S>>(
simd.vectorize(
#[inline(always)]
|| {
let mut cur_pos = gradient.transform * Point::new(start_x, start_y);
let x_advances = (gradient.x_advance.x as f32, gradient.x_advance.y as f32);
let y_advances = (gradient.y_advance.x as f32, gradient.y_advance.y as f32);
let cur_pos = gradient.transform * Point::new(start_x, start_y);
let mut positions =
U::Positions::new(simd, cur_pos, gradient.x_advance, gradient.y_advance, 2.0);

for buf_part in buf.chunks_exact_mut(8) {
let x_pos = f32x8::splat_pos(simd, cur_pos.x as f32, x_advances.0, y_advances.0);
let y_pos = f32x8::splat_pos(simd, cur_pos.y as f32, x_advances.1, y_advances.1);
let pos = kind.cur_pos(x_pos, y_pos);
let pos = kind.cur_pos(&positions);
pos.store_slice(buf_part);

cur_pos += 2.0 * gradient.x_advance;
positions.advance();
}
},
);
Expand Down Expand Up @@ -247,5 +244,7 @@ pub(crate) fn apply_extend<S: Simd>(val: f32x8<S>, extend: peniko::Extend) -> f3
}

pub(crate) trait SimdGradientKind<S: Simd> {
fn cur_pos(&self, x_pos: f32x8<S>, y_pos: f32x8<S>) -> f32x8<S>;
type Positions: PositionIterator<S>;

fn cur_pos(&self, positions: &Self::Positions) -> f32x8<S>;
}
6 changes: 5 additions & 1 deletion sparse_strips/vello_cpu/src/fine/common/gradient/radial.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2025 the Vello Authors
// SPDX-License-Identifier: Apache-2.0 OR MIT

use crate::fine::PaintPositions;
use crate::fine::common::gradient::SimdGradientKind;
use vello_common::encode::{FocalData, RadialKind};
use vello_common::fearless_simd::{Simd, SimdBase, SimdFloat, f32x8};
Expand Down Expand Up @@ -55,8 +56,11 @@ impl<S: Simd> SimdRadialKind<S> {
}

impl<S: Simd> SimdGradientKind<S> for SimdRadialKind<S> {
type Positions = PaintPositions<S, f32x8<S>>;

#[inline(always)]
fn cur_pos(&self, x_pos: f32x8<S>, y_pos: f32x8<S>) -> f32x8<S> {
fn cur_pos(&self, positions: &Self::Positions) -> f32x8<S> {
let (x_pos, y_pos) = positions.current();
let simd = x_pos.simd;

match &self.inner {
Expand Down
6 changes: 5 additions & 1 deletion sparse_strips/vello_cpu/src/fine/common/gradient/sweep.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2025 the Vello Authors
// SPDX-License-Identifier: Apache-2.0 OR MIT

use crate::fine::PaintPositions;
use crate::fine::common::gradient::SimdGradientKind;
use core::f32::consts::PI;
use vello_common::encode::SweepKind;
Expand All @@ -27,8 +28,11 @@ impl<S: Simd> SimdSweepKind<S> {
}

impl<S: Simd> SimdGradientKind<S> for SimdSweepKind<S> {
type Positions = PaintPositions<S, f32x8<S>>;

#[inline(always)]
fn cur_pos(&self, x_pos: f32x8<S>, y_pos: f32x8<S>) -> f32x8<S> {
fn cur_pos(&self, positions: &Self::Positions) -> f32x8<S> {
let (x_pos, y_pos) = positions.current();
let angle = x_y_to_unit_angle(self.simd, x_pos, y_pos) * f32x8::splat(self.simd, 2.0 * PI);

(angle - self.start_angle) * self.inv_angle_delta
Expand Down
133 changes: 66 additions & 67 deletions sparse_strips/vello_cpu/src/fine/common/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT

use crate::fine::macros::{f32x16_painter, u8x16_painter};
use crate::fine::{PosExt, Splat4thExt, u8_to_f32};
use crate::fine::{
PaintPositions, PlainPaintPositions, PosExt, PositionIterator, Splat4thExt, u8_to_f32,
};
use crate::kurbo::Point;
use vello_common::encode::EncodedImage;
use vello_common::fearless_simd::{Bytes, Simd, SimdBase, SimdFloat, f32x4, f32x16, u8x16, u32x4};
Expand All @@ -14,8 +16,6 @@ use vello_common::simd::element_wise_splat;
pub(crate) struct PlainNNImagePainter<'a, S: Simd> {
data: ImagePainterData<'a, S>,
y_positions: f32x4<S>,
cur_x_pos: f32x4<S>,
advance: f32,
simd: S,
}

Expand Down Expand Up @@ -45,47 +45,36 @@ impl<'a, S: Simd> PlainNNImagePainter<'a, S> {
data.height_inv,
);

let cur_x_pos = f32x4::splat_pos(
simd,
data.cur_pos.x as f32,
data.x_advances.0,
data.y_advances.0,
);

Self {
data,
advance: image.x_advance.x as f32,
y_positions,
cur_x_pos,
simd,
}
},
)
}
}

impl<S: Simd> Iterator for PlainNNImagePainter<'_, S> {
type Item = u8x16<S>;

impl<S: Simd> PlainNNImagePainter<'_, S> {
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
fn next(&self, positions: &PlainPaintPositions<S, f32x4<S>>) -> u8x16<S> {
let x_pos = extend(
self.simd,
self.cur_x_pos,
positions.current(),
self.data.image.sampler.x_extend,
self.data.width,
self.data.width_inv,
);

let samples = sample(self.simd, &self.data, x_pos, self.y_positions);

self.cur_x_pos += self.advance;

Some(samples)
sample(self.simd, &self.data, x_pos, self.y_positions)
}
}

u8x16_painter!(PlainNNImagePainter<'_, S>);
u8x16_painter!(
PlainNNImagePainter<'_, S>,
painter,
painter.data.plain_positions::<f32x4<S>>(painter.simd)
);

/// A painter for nearest-neighbor images with arbitrary transforms.
#[derive(Debug)]
Expand All @@ -108,46 +97,36 @@ impl<'a, S: Simd> NNImagePainter<'a, S> {
}
}

impl<S: Simd> Iterator for NNImagePainter<'_, S> {
type Item = u8x16<S>;

impl<S: Simd> NNImagePainter<'_, S> {
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
fn next(&self, positions: &PaintPositions<S, f32x4<S>>) -> u8x16<S> {
let (x_positions, y_positions) = positions.current();

let x_positions = extend(
self.simd,
f32x4::splat_pos(
self.simd,
self.data.cur_pos.x as f32,
self.data.x_advances.0,
self.data.y_advances.0,
),
x_positions,
self.data.image.sampler.x_extend,
self.data.width,
self.data.width_inv,
);

let y_positions = extend(
self.simd,
f32x4::splat_pos(
self.simd,
self.data.cur_pos.y as f32,
self.data.x_advances.1,
self.data.y_advances.1,
),
y_positions,
self.data.image.sampler.y_extend,
self.data.height,
self.data.height_inv,
);

let samples = sample(self.simd, &self.data, x_positions, y_positions);

self.data.cur_pos += self.data.image.x_advance;

Some(samples)
sample(self.simd, &self.data, x_positions, y_positions)
}
}

u8x16_painter!(NNImagePainter<'_, S>);
u8x16_painter!(
NNImagePainter<'_, S>,
painter,
painter.data.positions::<f32x4<S>>(painter.simd)
);

/// A painter for images with bilinear or bicubic filtering.
///
Expand Down Expand Up @@ -178,24 +157,10 @@ impl<'a, S: Simd, const QUALITY: u8> FilteredImagePainter<'a, S, QUALITY> {
}
}

impl<S: Simd, const QUALITY: u8> Iterator for FilteredImagePainter<'_, S, QUALITY> {
type Item = f32x16<S>;

impl<S: Simd, const QUALITY: u8> FilteredImagePainter<'_, S, QUALITY> {
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
let x_positions = f32x4::splat_pos(
self.simd,
self.data.cur_pos.x as f32,
self.data.x_advances.0,
self.data.y_advances.0,
);

let y_positions = f32x4::splat_pos(
self.simd,
self.data.cur_pos.y as f32,
self.data.x_advances.1,
self.data.y_advances.1,
);
fn next(&self, positions: &PaintPositions<S, f32x4<S>>) -> f32x16<S> {
let (x_positions, y_positions) = positions.current();

// We have two versions of filtering: `Medium` (bilinear filtering) and
// `High` (bicubic filtering).
Expand Down Expand Up @@ -330,16 +295,22 @@ impl<S: Simd, const QUALITY: u8> Iterator for FilteredImagePainter<'_, S, QUALIT
),
}

self.data.cur_pos += self.data.image.x_advance;

Some(interpolated_color)
interpolated_color
}
}

// Bilinear
f32x16_painter!(FilteredImagePainter<'_, S, 1>);
f32x16_painter!(
FilteredImagePainter<'_, S, 1>,
painter,
painter.data.positions::<f32x4<S>>(painter.simd)
);
// Bicubic
f32x16_painter!(FilteredImagePainter<'_, S, 2>);
f32x16_painter!(
FilteredImagePainter<'_, S, 2>,
painter,
painter.data.positions::<f32x4<S>>(painter.simd)
);

/// Computes the positive fractional part of a value: `val - val.floor()`.
///
Expand Down Expand Up @@ -404,6 +375,34 @@ impl<'a, S: Simd> ImagePainterData<'a, S> {
},
)
}

#[inline(always)]
pub(crate) fn positions<V>(&self, simd: S) -> PaintPositions<S, V>
where
V: PosExt<S> + SimdFloat<S, Element = f32>,
{
PaintPositions::new(
simd,
self.cur_pos,
self.image.x_advance,
self.image.y_advance,
1.0,
)
}

#[inline(always)]
pub(crate) fn plain_positions<V>(&self, simd: S) -> PlainPaintPositions<S, V>
where
V: PosExt<S> + SimdFloat<S, Element = f32>,
{
PlainPaintPositions::new(
simd,
self.cur_pos,
self.image.x_advance,
self.image.y_advance,
1.0,
)
}
}

#[inline(always)]
Expand Down
Loading
Loading