1use crate::{BlendMode, Color, LengthU32, Paint, PixmapRef, PremultipliedColorU8, Shader};
8use crate::{ALPHA_U8_OPAQUE, ALPHA_U8_TRANSPARENT};
9
10use crate::alpha_runs::AlphaRun;
11use crate::blitter::{Blitter, Mask};
12use crate::color::AlphaU8;
13use crate::geom::ScreenIntRect;
14use crate::mask::SubMaskRef;
15use crate::math::LENGTH_U32_ONE;
16use crate::pipeline::{self, RasterPipeline, RasterPipelineBuilder};
17use crate::pixmap::SubPixmapMut;
18
19pub struct RasterPipelineBlitter<'a, 'b: 'a> {
20 mask: Option<SubMaskRef<'a>>,
21 pixmap_src: PixmapRef<'a>,
22 pixmap: &'a mut SubPixmapMut<'b>,
23 memset2d_color: Option<PremultipliedColorU8>,
24 blit_anti_h_rp: RasterPipeline,
25 blit_rect_rp: RasterPipeline,
26 blit_mask_rp: RasterPipeline,
27 is_mask: bool,
28}
29
30impl<'a, 'b: 'a> RasterPipelineBlitter<'a, 'b> {
31 pub fn new(
32 paint: &Paint<'a>,
33 mask: Option<SubMaskRef<'a>>,
34 pixmap: &'a mut SubPixmapMut<'b>,
35 ) -> Option<Self> {
36 if let Some(mask) = mask {
38 if mask.size.width() != pixmap.size.width()
39 || mask.size.height() != pixmap.size.height()
40 {
41 log::warn!("Pixmap and Mask are expected to have the same size");
42 return None;
43 }
44 }
45
46 match paint.blend_mode {
49 BlendMode::Destination => return None,
51 BlendMode::DestinationIn if paint.shader.is_opaque() && paint.is_solid_color() => {
52 return None
53 }
54 _ => {}
55 }
56
57 let mut blend_mode = paint.blend_mode;
59 if paint.shader.is_opaque() && blend_mode == BlendMode::SourceOver && mask.is_none() {
60 blend_mode = BlendMode::Source;
61 }
62
63 let mut memset2d_color = None;
65 if paint.is_solid_color() && blend_mode == BlendMode::Source && mask.is_none() {
66 if let Shader::SolidColor(ref color) = paint.shader {
69 memset2d_color = Some(color.premultiply().to_color_u8());
70 }
71 };
72
73 if blend_mode == BlendMode::Clear && !paint.anti_alias && mask.is_none() {
75 blend_mode = BlendMode::Source;
76 memset2d_color = Some(PremultipliedColorU8::TRANSPARENT);
77 }
78
79 let blit_anti_h_rp = {
80 let mut p = RasterPipelineBuilder::new();
81 p.set_force_hq_pipeline(paint.force_hq_pipeline);
82 if !paint.shader.push_stages(paint.colorspace, &mut p) {
83 return None;
84 }
85
86 if mask.is_some() {
87 p.push(pipeline::Stage::MaskU8);
88 }
89
90 if blend_mode.should_pre_scale_coverage() {
91 p.push(pipeline::Stage::Scale1Float);
92 p.push(pipeline::Stage::LoadDestination);
93 if let Some(stage) = paint.colorspace.expand_dest_stage() {
94 p.push(stage);
95 }
96 if let Some(blend_stage) = blend_mode.to_stage() {
97 p.push(blend_stage);
98 }
99 } else {
100 p.push(pipeline::Stage::LoadDestination);
101 if let Some(stage) = paint.colorspace.expand_dest_stage() {
102 p.push(stage);
103 }
104 if let Some(blend_stage) = blend_mode.to_stage() {
105 p.push(blend_stage);
106 }
107
108 p.push(pipeline::Stage::Lerp1Float);
109 }
110
111 if let Some(stage) = paint.colorspace.compress_stage() {
112 p.push(stage);
113 }
114 p.push(pipeline::Stage::Store);
115
116 p.compile()
117 };
118
119 let blit_rect_rp = {
120 let mut p = RasterPipelineBuilder::new();
121 p.set_force_hq_pipeline(paint.force_hq_pipeline);
122 if !paint.shader.push_stages(paint.colorspace, &mut p) {
123 return None;
124 }
125
126 if mask.is_some() {
127 p.push(pipeline::Stage::MaskU8);
128 }
129
130 if blend_mode == BlendMode::SourceOver && mask.is_none() {
131 if let Some(stage) = paint.colorspace.compress_stage() {
132 p.push(stage);
133 }
134 p.push(pipeline::Stage::SourceOverRgba);
136 } else {
137 if blend_mode != BlendMode::Source {
138 p.push(pipeline::Stage::LoadDestination);
139 if let Some(blend_stage) = blend_mode.to_stage() {
140 if let Some(stage) = paint.colorspace.expand_dest_stage() {
141 p.push(stage);
142 }
143 p.push(blend_stage);
144 }
145 }
146
147 if let Some(stage) = paint.colorspace.compress_stage() {
148 p.push(stage);
149 }
150 p.push(pipeline::Stage::Store);
151 }
152
153 p.compile()
154 };
155
156 let blit_mask_rp = {
157 let mut p = RasterPipelineBuilder::new();
158 p.set_force_hq_pipeline(paint.force_hq_pipeline);
159 if !paint.shader.push_stages(paint.colorspace, &mut p) {
160 return None;
161 }
162
163 if mask.is_some() {
164 p.push(pipeline::Stage::MaskU8);
165 }
166
167 if blend_mode.should_pre_scale_coverage() {
168 p.push(pipeline::Stage::ScaleU8);
169 p.push(pipeline::Stage::LoadDestination);
170 if let Some(stage) = paint.colorspace.expand_dest_stage() {
171 p.push(stage);
172 }
173 if let Some(blend_stage) = blend_mode.to_stage() {
174 p.push(blend_stage);
175 }
176 } else {
177 p.push(pipeline::Stage::LoadDestination);
178 if let Some(stage) = paint.colorspace.expand_dest_stage() {
179 p.push(stage);
180 }
181 if let Some(blend_stage) = blend_mode.to_stage() {
182 p.push(blend_stage);
183 }
184
185 p.push(pipeline::Stage::LerpU8);
186 }
187
188 if let Some(stage) = paint.colorspace.compress_stage() {
189 p.push(stage);
190 }
191 p.push(pipeline::Stage::Store);
192
193 p.compile()
194 };
195
196 let pixmap_src = match paint.shader {
197 Shader::Pattern(ref patt) => patt.pixmap,
198 _ => PixmapRef::from_bytes(&[0, 0, 0, 0], 1, 1).unwrap(),
200 };
201
202 Some(RasterPipelineBlitter {
203 mask,
204 pixmap_src,
205 pixmap,
206 memset2d_color,
207 blit_anti_h_rp,
208 blit_rect_rp,
209 blit_mask_rp,
210 is_mask: false,
211 })
212 }
213
214 pub fn new_mask(pixmap: &'a mut SubPixmapMut<'b>) -> Option<Self> {
215 let color = Color::WHITE.premultiply();
216
217 let memset2d_color = Some(color.to_color_u8());
218
219 let blit_anti_h_rp = {
220 let mut p = RasterPipelineBuilder::new();
221 p.push_uniform_color(color);
222 p.push(pipeline::Stage::LoadDestinationU8);
223 p.push(pipeline::Stage::Lerp1Float);
224 p.push(pipeline::Stage::StoreU8);
225 p.compile()
226 };
227
228 let blit_rect_rp = {
229 let mut p = RasterPipelineBuilder::new();
230 p.push_uniform_color(color);
231 p.push(pipeline::Stage::StoreU8);
232 p.compile()
233 };
234
235 let blit_mask_rp = {
236 let mut p = RasterPipelineBuilder::new();
237 p.push_uniform_color(color);
238 p.push(pipeline::Stage::LoadDestinationU8);
239 p.push(pipeline::Stage::LerpU8);
240 p.push(pipeline::Stage::StoreU8);
241 p.compile()
242 };
243
244 Some(RasterPipelineBlitter {
245 mask: None,
246 pixmap_src: PixmapRef::from_bytes(&[0, 0, 0, 0], 1, 1).unwrap(),
247 pixmap,
248 memset2d_color,
249 blit_anti_h_rp,
250 blit_rect_rp,
251 blit_mask_rp,
252 is_mask: true,
253 })
254 }
255}
256
257impl Blitter for RasterPipelineBlitter<'_, '_> {
258 fn blit_h(&mut self, x: u32, y: u32, width: LengthU32) {
259 let r = ScreenIntRect::from_xywh_safe(x, y, width, LENGTH_U32_ONE);
260 self.blit_rect(&r);
261 }
262
263 fn blit_anti_h(&mut self, mut x: u32, y: u32, aa: &mut [AlphaU8], runs: &mut [AlphaRun]) {
264 let mask_ctx = self.mask.map(|c| c.mask_ctx()).unwrap_or_default();
265
266 let mut aa_offset = 0;
267 let mut run_offset = 0;
268 let mut run_opt = runs[0];
269 while let Some(run) = run_opt {
270 let width = LengthU32::from(run);
271
272 match aa[aa_offset] {
273 ALPHA_U8_TRANSPARENT => {}
274 ALPHA_U8_OPAQUE => {
275 self.blit_h(x, y, width);
276 }
277 alpha => {
278 self.blit_anti_h_rp.ctx.current_coverage = alpha as f32 * (1.0 / 255.0);
279
280 let rect = ScreenIntRect::from_xywh_safe(x, y, width, LENGTH_U32_ONE);
281 self.blit_anti_h_rp.run(
282 &rect,
283 pipeline::AAMaskCtx::default(),
284 mask_ctx,
285 self.pixmap_src,
286 self.pixmap,
287 );
288 }
289 }
290
291 x += width.get();
292 run_offset += usize::from(run.get());
293 aa_offset += usize::from(run.get());
294 run_opt = runs[run_offset];
295 }
296 }
297
298 fn blit_v(&mut self, x: u32, y: u32, height: LengthU32, alpha: AlphaU8) {
299 let bounds = ScreenIntRect::from_xywh_safe(x, y, LENGTH_U32_ONE, height);
300
301 let mask = Mask {
302 image: [alpha, alpha],
303 bounds,
304 row_bytes: 0, };
306
307 self.blit_mask(&mask, &bounds);
308 }
309
310 fn blit_anti_h2(&mut self, x: u32, y: u32, alpha0: AlphaU8, alpha1: AlphaU8) {
311 let bounds = ScreenIntRect::from_xywh(x, y, 2, 1).unwrap();
312
313 let mask = Mask {
314 image: [alpha0, alpha1],
315 bounds,
316 row_bytes: 2,
317 };
318
319 self.blit_mask(&mask, &bounds);
320 }
321
322 fn blit_anti_v2(&mut self, x: u32, y: u32, alpha0: AlphaU8, alpha1: AlphaU8) {
323 let bounds = ScreenIntRect::from_xywh(x, y, 1, 2).unwrap();
324
325 let mask = Mask {
326 image: [alpha0, alpha1],
327 bounds,
328 row_bytes: 1,
329 };
330
331 self.blit_mask(&mask, &bounds);
332 }
333
334 fn blit_rect(&mut self, rect: &ScreenIntRect) {
335 if let Some(c) = self.memset2d_color {
336 if self.is_mask {
337 for y in 0..rect.height() {
338 let start = self
339 .pixmap
340 .offset(rect.x() as usize, (rect.y() + y) as usize);
341 let end = start + rect.width() as usize;
342 self.pixmap.data[start..end]
343 .iter_mut()
344 .for_each(|p| *p = c.alpha());
345 }
346 } else {
347 for y in 0..rect.height() {
348 let start = self
349 .pixmap
350 .offset(rect.x() as usize, (rect.y() + y) as usize);
351 let end = start + rect.width() as usize;
352 self.pixmap.pixels_mut()[start..end]
353 .iter_mut()
354 .for_each(|p| *p = c);
355 }
356 }
357
358 return;
359 }
360
361 let mask_ctx = self.mask.map(|c| c.mask_ctx()).unwrap_or_default();
362
363 self.blit_rect_rp.run(
364 rect,
365 pipeline::AAMaskCtx::default(),
366 mask_ctx,
367 self.pixmap_src,
368 self.pixmap,
369 );
370 }
371
372 fn blit_mask(&mut self, mask: &Mask, clip: &ScreenIntRect) {
373 let aa_mask_ctx = pipeline::AAMaskCtx {
374 pixels: mask.image,
375 stride: mask.row_bytes,
376 shift: (mask.bounds.left() + mask.bounds.top() * mask.row_bytes) as usize,
377 };
378
379 let mask_ctx = self.mask.map(|c| c.mask_ctx()).unwrap_or_default();
380
381 self.blit_mask_rp
382 .run(clip, aa_mask_ctx, mask_ctx, self.pixmap_src, self.pixmap);
383 }
384}