vello_cpu/fine/lowp/
gradient.rs1use crate::peniko;
5use core::slice::ChunksExact;
6use vello_common::encode::EncodedGradient;
7use vello_common::fearless_simd::*;
8
9#[derive(Debug)]
13pub(crate) struct GradientPainter<'a, S: Simd> {
14 gradient: &'a EncodedGradient,
15 lut: &'a [[u8; 4]],
16 t_vals: ChunksExact<'a, f32>,
17 scale_factor: f32x16<S>,
18 simd: S,
19}
20
21impl<'a, S: Simd> GradientPainter<'a, S> {
22 pub(crate) fn new(simd: S, gradient: &'a EncodedGradient, t_vals: &'a [f32]) -> Self {
23 let lut = gradient.u8_lut(simd);
24 let scale_factor = f32x16::splat(simd, lut.scale_factor());
25
26 Self {
27 gradient,
28 scale_factor,
29 lut: lut.lut(),
30 t_vals: t_vals.chunks_exact(16),
31 simd,
32 }
33 }
34}
35
36impl<S: Simd> Iterator for GradientPainter<'_, S> {
37 type Item = u8x64<S>;
38
39 #[inline(always)]
40 fn next(&mut self) -> Option<Self::Item> {
41 let extend = self.gradient.extend;
42 let pos = f32x16::from_slice(self.simd, self.t_vals.next()?);
43 let t_vals = apply_extend(pos, extend);
44 let indices = (t_vals * self.scale_factor).cvt_u32();
45
46 let mut vals = [0_u8; 64];
47 for (val, idx) in vals.chunks_exact_mut(4).zip(indices.val) {
48 val.copy_from_slice(&self.lut[idx as usize]);
49 }
50
51 Some(u8x64::from_slice(self.simd, &vals))
52 }
53}
54
55impl<S: Simd> crate::fine::Painter for GradientPainter<'_, S> {
56 fn paint_u8(&mut self, buf: &mut [u8]) {
57 for chunk in buf.chunks_exact_mut(64) {
58 chunk.copy_from_slice(&self.next().unwrap().val);
59 }
60 }
61
62 fn paint_f32(&mut self, _: &mut [f32]) {
63 unimplemented!()
64 }
65}
66
67#[inline(always)]
69pub(crate) fn apply_extend<S: Simd>(val: f32x16<S>, extend: peniko::Extend) -> f32x16<S> {
70 match extend {
71 peniko::Extend::Pad => val.max(0.0).min(1.0),
72 peniko::Extend::Repeat => (val - val.floor()).fract(),
73 peniko::Extend::Reflect => ((val - 1.0) - 2.0 * ((val - 1.0) * 0.5).floor() - 1.0)
75 .abs()
76 .max(0.0)
77 .min(1.0),
78 }
79}