vello_cpu/fine/lowp/
image.rs1use crate::fine::PosExt;
5use crate::fine::common::image::{ImagePainterData, extend, sample};
6use crate::fine::macros::u8x16_painter;
7use vello_common::encode::EncodedImage;
8use vello_common::fearless_simd::{Simd, SimdBase, f32x4, u8x16};
9use vello_common::pixmap::Pixmap;
10use vello_common::simd::element_wise_splat;
11use vello_common::util::f32_to_u8;
12
13#[derive(Debug)]
15pub(crate) struct BilinearImagePainter<'a, S: Simd> {
16 data: ImagePainterData<'a, S>,
17 simd: S,
18}
19
20impl<'a, S: Simd> BilinearImagePainter<'a, S> {
21 pub(crate) fn new(
22 simd: S,
23 image: &'a EncodedImage,
24 pixmap: &'a Pixmap,
25 start_x: u16,
26 start_y: u16,
27 ) -> Self {
28 let data = ImagePainterData::new(simd, image, pixmap, start_x, start_y);
29
30 Self { data, simd }
31 }
32}
33
34impl<S: Simd> Iterator for BilinearImagePainter<'_, S> {
35 type Item = u8x16<S>;
36
37 fn next(&mut self) -> Option<Self::Item> {
38 let x_positions = f32x4::splat_pos(
39 self.simd,
40 self.data.cur_pos.x as f32,
41 self.data.x_advances.0,
42 self.data.y_advances.0,
43 );
44
45 let y_positions = f32x4::splat_pos(
46 self.simd,
47 self.data.cur_pos.y as f32,
48 self.data.x_advances.1,
49 self.data.y_advances.1,
50 );
51
52 #[inline(always)]
55 fn fract<S: Simd>(val: f32x4<S>) -> f32x4<S> {
56 val - val.floor()
57 }
58
59 let extend_x = |x_pos: f32x4<S>| {
60 extend(
61 self.simd,
62 x_pos,
63 self.data.image.sampler.x_extend,
64 self.data.width,
65 self.data.width_inv,
66 )
67 };
68
69 let extend_y = |y_pos: f32x4<S>| {
70 extend(
71 self.simd,
72 y_pos,
73 self.data.image.sampler.y_extend,
74 self.data.height,
75 self.data.height_inv,
76 )
77 };
78
79 let fx = f32_to_u8(element_wise_splat(
80 self.simd,
81 fract(x_positions + 0.5) * 256.0,
82 ));
83 let fy = f32_to_u8(element_wise_splat(
84 self.simd,
85 fract(y_positions + 0.5) * 256.0,
86 ));
87 let fx_inv = self.simd.widen_u8x16(u8x16::splat(self.simd, 255) - fx);
88 let fy_inv = self.simd.widen_u8x16(u8x16::splat(self.simd, 255) - fy);
89
90 let fx = self.simd.widen_u8x16(fx);
91 let fy = self.simd.widen_u8x16(fy);
92
93 let x_pos1 = extend_x(x_positions - 0.5);
94 let x_pos2 = extend_x(x_positions + 0.5);
95 let y_pos1 = extend_y(y_positions - 0.5);
96 let y_pos2 = extend_y(y_positions + 0.5);
97
98 let p00 = self
99 .simd
100 .widen_u8x16(sample(self.simd, &self.data, x_pos1, y_pos1));
101 let p10 = self
102 .simd
103 .widen_u8x16(sample(self.simd, &self.data, x_pos2, y_pos1));
104 let p01 = self
105 .simd
106 .widen_u8x16(sample(self.simd, &self.data, x_pos1, y_pos2));
107 let p11 = self
108 .simd
109 .widen_u8x16(sample(self.simd, &self.data, x_pos2, y_pos2));
110
111 let ip1 = (p00 * fx_inv + p10 * fx).shr(8);
112 let ip2 = (p01 * fx_inv + p11 * fx).shr(8);
113 let res = self.simd.narrow_u16x16((ip1 * fy_inv + ip2 * fy).shr(8));
114
115 self.data.cur_pos += self.data.image.x_advance;
116
117 Some(res)
118 }
119}
120
121u8x16_painter!(BilinearImagePainter<'_, S>);