1use crate::fine::PosExt;
5use crate::fine::common::image::{ImagePainterData, extend, fract_floor, sample};
6use crate::fine::macros::u8x16_painter;
7use vello_common::encode::EncodedImage;
8use vello_common::fearless_simd::{Simd, SimdBase, SimdFloat, f32x4, u8x16, u16x16};
9use vello_common::pixmap::Pixmap;
10use vello_common::simd::element_wise_splat;
11use vello_common::util::{Div255Ext, 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 let extend_x = |x_pos: f32x4<S>| {
53 extend(
54 self.simd,
55 x_pos,
56 self.data.image.sampler.x_extend,
57 self.data.width,
58 self.data.width_inv,
59 )
60 };
61
62 let extend_y = |y_pos: f32x4<S>| {
63 extend(
64 self.simd,
65 y_pos,
66 self.data.image.sampler.y_extend,
67 self.data.height,
68 self.data.height_inv,
69 )
70 };
71
72 let fx = f32_to_u8(element_wise_splat(
73 self.simd,
74 fract_floor(x_positions + 0.5).madd(255.0, 0.5),
75 ));
76 let fy = f32_to_u8(element_wise_splat(
77 self.simd,
78 fract_floor(y_positions + 0.5).madd(255.0, 0.5),
79 ));
80
81 let fx = self.simd.widen_u8x16(fx);
82 let fy = self.simd.widen_u8x16(fy);
83 let fx_inv = u16x16::splat(self.simd, 255) - fx;
84 let fy_inv = u16x16::splat(self.simd, 255) - fy;
85
86 let x_pos1 = extend_x(x_positions - 0.5);
87 let x_pos2 = extend_x(x_positions + 0.5);
88 let y_pos1 = extend_y(y_positions - 0.5);
89 let y_pos2 = extend_y(y_positions + 0.5);
90
91 let p00 = self
92 .simd
93 .widen_u8x16(sample(self.simd, &self.data, x_pos1, y_pos1));
94 let p10 = self
95 .simd
96 .widen_u8x16(sample(self.simd, &self.data, x_pos2, y_pos1));
97 let p01 = self
98 .simd
99 .widen_u8x16(sample(self.simd, &self.data, x_pos1, y_pos2));
100 let p11 = self
101 .simd
102 .widen_u8x16(sample(self.simd, &self.data, x_pos2, y_pos2));
103
104 let ip1 = (p00 * fx_inv + p10 * fx).div_255();
105 let ip2 = (p01 * fx_inv + p11 * fx).div_255();
106 let res = self.simd.narrow_u16x16((ip1 * fy_inv + ip2 * fy).div_255());
107
108 self.data.cur_pos += self.data.image.x_advance;
109
110 Some(res)
111 }
112}
113
114u8x16_painter!(BilinearImagePainter<'_, S>);
115
116#[derive(Debug)]
121pub(crate) struct PlainBilinearImagePainter<'a, S: Simd> {
122 data: ImagePainterData<'a, S>,
123 simd: S,
124 y_pos1: f32x4<S>,
126 y_pos2: f32x4<S>,
128 fy: u16x16<S>,
130 fy_inv: u16x16<S>,
132 cur_x_pos: f32x4<S>,
134 advance: f32,
136}
137
138impl<'a, S: Simd> PlainBilinearImagePainter<'a, S> {
139 pub(crate) fn new(
140 simd: S,
141 image: &'a EncodedImage,
142 pixmap: &'a Pixmap,
143 start_x: u16,
144 start_y: u16,
145 ) -> Self {
146 let data = ImagePainterData::new(simd, image, pixmap, start_x, start_y);
147
148 let y_positions = f32x4::splat_pos(
150 simd,
151 data.cur_pos.y as f32,
152 data.x_advances.1,
153 data.y_advances.1,
154 );
155
156 let y_pos1 = extend(
158 simd,
159 y_positions - 0.5,
160 image.sampler.y_extend,
161 data.height,
162 data.height_inv,
163 );
164 let y_pos2 = extend(
165 simd,
166 y_positions + 0.5,
167 image.sampler.y_extend,
168 data.height,
169 data.height_inv,
170 );
171
172 let fy = f32_to_u8(element_wise_splat(
174 simd,
175 fract_floor(y_positions + 0.5).madd(255.0, 0.5),
176 ));
177 let fy = simd.widen_u8x16(fy);
178 let fy_inv = u16x16::splat(simd, 255) - fy;
179
180 let cur_x_pos = f32x4::splat_pos(
181 simd,
182 data.cur_pos.x as f32,
183 data.x_advances.0,
184 data.y_advances.0,
185 );
186
187 Self {
188 data,
189 y_pos1,
190 y_pos2,
191 fy,
192 fy_inv,
193 cur_x_pos,
194 advance: image.x_advance.x as f32,
195 simd,
196 }
197 }
198}
199
200impl<S: Simd> Iterator for PlainBilinearImagePainter<'_, S> {
201 type Item = u8x16<S>;
202
203 #[inline(always)]
204 fn next(&mut self) -> Option<Self::Item> {
205 let x_minus_half = self.cur_x_pos - 0.5;
206 let x_plus_half = self.cur_x_pos + 0.5;
207
208 let x_pos1 = extend(
210 self.simd,
211 x_minus_half,
212 self.data.image.sampler.x_extend,
213 self.data.width,
214 self.data.width_inv,
215 );
216 let x_pos2 = extend(
217 self.simd,
218 x_plus_half,
219 self.data.image.sampler.x_extend,
220 self.data.width,
221 self.data.width_inv,
222 );
223
224 let fx = f32_to_u8(element_wise_splat(
226 self.simd,
227 fract_floor(x_plus_half).madd(255.0, 0.5),
228 ));
229 let fx = self.simd.widen_u8x16(fx);
230 let fx_inv = u16x16::splat(self.simd, 255) - fx;
231
232 let p00 = self
234 .simd
235 .widen_u8x16(sample(self.simd, &self.data, x_pos1, self.y_pos1));
236 let p10 = self
237 .simd
238 .widen_u8x16(sample(self.simd, &self.data, x_pos2, self.y_pos1));
239 let p01 = self
240 .simd
241 .widen_u8x16(sample(self.simd, &self.data, x_pos1, self.y_pos2));
242 let p11 = self
243 .simd
244 .widen_u8x16(sample(self.simd, &self.data, x_pos2, self.y_pos2));
245
246 let ip1 = (p00 * fx_inv + p10 * fx).div_255();
248 let ip2 = (p01 * fx_inv + p11 * fx).div_255();
249 let res = self
250 .simd
251 .narrow_u16x16((ip1 * self.fy_inv + ip2 * self.fy).div_255());
252
253 self.cur_x_pos += self.advance;
254
255 Some(res)
256 }
257}
258
259u8x16_painter!(PlainBilinearImagePainter<'_, S>);