1use alloc::vec::Vec;
48
49use arrayvec::ArrayVec;
50
51use tiny_skia_path::NormalizedF32;
52
53use crate::{Color, PremultipliedColor, PremultipliedColorU8, SpreadMode};
54use crate::{PixmapRef, Transform};
55
56pub use blitter::RasterPipelineBlitter;
57
58use crate::geom::ScreenIntRect;
59use crate::pixmap::SubPixmapMut;
60use crate::wide::u32x8;
61
62mod blitter;
63#[rustfmt::skip] mod highp;
64#[rustfmt::skip] mod lowp;
65
66const MAX_STAGES: usize = 32; #[allow(dead_code)]
69#[derive(Copy, Clone, Debug)]
70pub enum Stage {
71 MoveSourceToDestination = 0,
72 MoveDestinationToSource,
73 Clamp0,
74 ClampA,
75 Premultiply,
76 UniformColor,
77 SeedShader,
78 LoadDestination,
79 Store,
80 LoadDestinationU8,
81 StoreU8,
82 Gather,
83 LoadMaskU8,
84 MaskU8,
85 ScaleU8,
86 LerpU8,
87 Scale1Float,
88 Lerp1Float,
89 DestinationAtop,
90 DestinationIn,
91 DestinationOut,
92 DestinationOver,
93 SourceAtop,
94 SourceIn,
95 SourceOut,
96 SourceOver,
97 Clear,
98 Modulate,
99 Multiply,
100 Plus,
101 Screen,
102 Xor,
103 ColorBurn,
104 ColorDodge,
105 Darken,
106 Difference,
107 Exclusion,
108 HardLight,
109 Lighten,
110 Overlay,
111 SoftLight,
112 Hue,
113 Saturation,
114 Color,
115 Luminosity,
116 SourceOverRgba,
117 Transform,
118 Reflect,
119 Repeat,
120 Bilinear,
121 Bicubic,
122 PadX1,
123 ReflectX1,
124 RepeatX1,
125 Gradient,
126 EvenlySpaced2StopGradient,
127 XYToRadius,
128 XYTo2PtConicalFocalOnCircle,
129 XYTo2PtConicalWellBehaved,
130 XYTo2PtConicalGreater,
131 Mask2PtConicalDegenerates,
132 ApplyVectorMask,
133}
134
135pub const STAGES_COUNT: usize = Stage::ApplyVectorMask as usize + 1;
136
137impl<'a> PixmapRef<'a> {
138 #[inline(always)]
139 pub(crate) fn gather(&self, index: u32x8) -> [PremultipliedColorU8; highp::STAGE_WIDTH] {
140 let index: [u32; 8] = bytemuck::cast(index);
141 let pixels = self.pixels();
142 [
143 pixels[index[0] as usize],
144 pixels[index[1] as usize],
145 pixels[index[2] as usize],
146 pixels[index[3] as usize],
147 pixels[index[4] as usize],
148 pixels[index[5] as usize],
149 pixels[index[6] as usize],
150 pixels[index[7] as usize],
151 ]
152 }
153}
154
155impl<'a> SubPixmapMut<'a> {
156 #[inline(always)]
157 pub(crate) fn offset(&self, dx: usize, dy: usize) -> usize {
158 self.real_width * dy + dx
159 }
160
161 #[inline(always)]
162 pub(crate) fn slice_at_xy(&mut self, dx: usize, dy: usize) -> &mut [PremultipliedColorU8] {
163 let offset = self.offset(dx, dy);
164 &mut self.pixels_mut()[offset..]
165 }
166
167 #[inline(always)]
168 pub(crate) fn slice_mask_at_xy(&mut self, dx: usize, dy: usize) -> &mut [u8] {
169 let offset = self.offset(dx, dy);
170 &mut self.data[offset..]
171 }
172
173 #[inline(always)]
174 pub(crate) fn slice4_at_xy(
175 &mut self,
176 dx: usize,
177 dy: usize,
178 ) -> &mut [PremultipliedColorU8; highp::STAGE_WIDTH] {
179 arrayref::array_mut_ref!(self.pixels_mut(), self.offset(dx, dy), highp::STAGE_WIDTH)
180 }
181
182 #[inline(always)]
183 pub(crate) fn slice16_at_xy(
184 &mut self,
185 dx: usize,
186 dy: usize,
187 ) -> &mut [PremultipliedColorU8; lowp::STAGE_WIDTH] {
188 arrayref::array_mut_ref!(self.pixels_mut(), self.offset(dx, dy), lowp::STAGE_WIDTH)
189 }
190
191 #[inline(always)]
192 pub(crate) fn slice16_mask_at_xy(
193 &mut self,
194 dx: usize,
195 dy: usize,
196 ) -> &mut [u8; lowp::STAGE_WIDTH] {
197 arrayref::array_mut_ref!(self.data, self.offset(dx, dy), lowp::STAGE_WIDTH)
198 }
199}
200
201#[derive(Default, Debug)]
202pub struct AAMaskCtx {
203 pub pixels: [u8; 2],
204 pub stride: u32, pub shift: usize, }
207
208impl AAMaskCtx {
209 #[inline(always)]
210 pub fn copy_at_xy(&self, dx: usize, dy: usize, tail: usize) -> [u8; 2] {
211 let offset = (self.stride as usize * dy + dx) - self.shift;
212 match (offset, tail) {
214 (0, 1) => [self.pixels[0], 0],
215 (0, 2) => [self.pixels[0], self.pixels[1]],
216 (1, 1) => [self.pixels[1], 0],
217 _ => [0, 0], }
219 }
220}
221
222#[derive(Copy, Clone, Debug, Default)]
223pub struct MaskCtx<'a> {
224 pub data: &'a [u8],
225 pub real_width: u32,
226}
227
228impl MaskCtx<'_> {
229 #[inline(always)]
230 fn offset(&self, dx: usize, dy: usize) -> usize {
231 self.real_width as usize * dy + dx
232 }
233}
234
235#[derive(Default)]
236pub struct Context {
237 pub current_coverage: f32,
238 pub sampler: SamplerCtx,
239 pub uniform_color: UniformColorCtx,
240 pub evenly_spaced_2_stop_gradient: EvenlySpaced2StopGradientCtx,
241 pub gradient: GradientCtx,
242 pub two_point_conical_gradient: TwoPointConicalGradientCtx,
243 pub limit_x: TileCtx,
244 pub limit_y: TileCtx,
245 pub transform: Transform,
246}
247
248#[derive(Copy, Clone, Default, Debug)]
249pub struct SamplerCtx {
250 pub spread_mode: SpreadMode,
251 pub inv_width: f32,
252 pub inv_height: f32,
253}
254
255#[derive(Copy, Clone, Default, Debug)]
256pub struct UniformColorCtx {
257 pub r: f32,
258 pub g: f32,
259 pub b: f32,
260 pub a: f32,
261 pub rgba: [u16; 4], }
263
264#[derive(Copy, Clone, Default, Debug)]
267pub struct GradientColor {
268 pub r: f32,
269 pub g: f32,
270 pub b: f32,
271 pub a: f32,
272}
273
274impl GradientColor {
275 pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
276 GradientColor { r, g, b, a }
277 }
278}
279
280impl From<Color> for GradientColor {
281 fn from(c: Color) -> Self {
282 GradientColor {
283 r: c.red(),
284 g: c.green(),
285 b: c.blue(),
286 a: c.alpha(),
287 }
288 }
289}
290
291#[derive(Copy, Clone, Default, Debug)]
292pub struct EvenlySpaced2StopGradientCtx {
293 pub factor: GradientColor,
294 pub bias: GradientColor,
295}
296
297#[derive(Clone, Default, Debug)]
298pub struct GradientCtx {
299 pub len: usize,
304 pub factors: Vec<GradientColor>,
305 pub biases: Vec<GradientColor>,
306 pub t_values: Vec<NormalizedF32>,
307}
308
309impl GradientCtx {
310 pub fn push_const_color(&mut self, color: GradientColor) {
311 self.factors.push(GradientColor::new(0.0, 0.0, 0.0, 0.0));
312 self.biases.push(color);
313 }
314}
315
316#[derive(Copy, Clone, Default, Debug)]
317pub struct TwoPointConicalGradientCtx {
318 pub mask: u32x8,
320 pub p0: f32,
321}
322
323#[derive(Copy, Clone, Default, Debug)]
324pub struct TileCtx {
325 pub scale: f32,
326 pub inv_scale: f32, }
328
329pub struct RasterPipelineBuilder {
330 stages: ArrayVec<Stage, MAX_STAGES>,
331 force_hq_pipeline: bool,
332 pub ctx: Context,
333}
334
335impl RasterPipelineBuilder {
336 pub fn new() -> Self {
337 RasterPipelineBuilder {
338 stages: ArrayVec::new(),
339 force_hq_pipeline: false,
340 ctx: Context::default(),
341 }
342 }
343
344 pub fn set_force_hq_pipeline(&mut self, hq: bool) {
345 self.force_hq_pipeline = hq;
346 }
347
348 pub fn push(&mut self, stage: Stage) {
349 self.stages.push(stage);
350 }
351
352 pub fn push_transform(&mut self, ts: Transform) {
353 if ts.is_finite() && !ts.is_identity() {
354 self.stages.push(Stage::Transform);
355 self.ctx.transform = ts;
356 }
357 }
358
359 pub fn push_uniform_color(&mut self, c: PremultipliedColor) {
360 let r = c.red();
361 let g = c.green();
362 let b = c.blue();
363 let a = c.alpha();
364 let rgba = [
365 (r * 255.0 + 0.5) as u16,
366 (g * 255.0 + 0.5) as u16,
367 (b * 255.0 + 0.5) as u16,
368 (a * 255.0 + 0.5) as u16,
369 ];
370
371 let ctx = UniformColorCtx { r, g, b, a, rgba };
372
373 self.stages.push(Stage::UniformColor);
374 self.ctx.uniform_color = ctx;
375 }
376
377 pub fn compile(self) -> RasterPipeline {
378 if self.stages.is_empty() {
379 return RasterPipeline {
380 kind: RasterPipelineKind::High {
381 functions: ArrayVec::new(),
382 tail_functions: ArrayVec::new(),
383 },
384 ctx: Context::default(),
385 };
386 }
387
388 let is_lowp_compatible = self
389 .stages
390 .iter()
391 .all(|stage| !lowp::fn_ptr_eq(lowp::STAGES[*stage as usize], lowp::null_fn));
392
393 if self.force_hq_pipeline || !is_lowp_compatible {
394 let mut functions: ArrayVec<_, MAX_STAGES> = self
395 .stages
396 .iter()
397 .map(|stage| highp::STAGES[*stage as usize] as highp::StageFn)
398 .collect();
399 functions.push(highp::just_return as highp::StageFn);
400
401 let mut tail_functions = functions.clone();
407 for fun in &mut tail_functions {
408 if highp::fn_ptr(*fun) == highp::fn_ptr(highp::load_dst) {
409 *fun = highp::load_dst_tail as highp::StageFn;
410 } else if highp::fn_ptr(*fun) == highp::fn_ptr(highp::store) {
411 *fun = highp::store_tail as highp::StageFn;
412 } else if highp::fn_ptr(*fun) == highp::fn_ptr(highp::load_dst_u8) {
413 *fun = highp::load_dst_u8_tail as highp::StageFn;
414 } else if highp::fn_ptr(*fun) == highp::fn_ptr(highp::store_u8) {
415 *fun = highp::store_u8_tail as highp::StageFn;
416 } else if highp::fn_ptr(*fun) == highp::fn_ptr(highp::source_over_rgba) {
417 *fun = highp::source_over_rgba_tail as highp::StageFn;
420 }
421 }
422
423 RasterPipeline {
424 kind: RasterPipelineKind::High {
425 functions,
426 tail_functions,
427 },
428 ctx: self.ctx,
429 }
430 } else {
431 let mut functions: ArrayVec<_, MAX_STAGES> = self
432 .stages
433 .iter()
434 .map(|stage| lowp::STAGES[*stage as usize] as lowp::StageFn)
435 .collect();
436 functions.push(lowp::just_return as lowp::StageFn);
437
438 let mut tail_functions = functions.clone();
440 for fun in &mut tail_functions {
441 if lowp::fn_ptr(*fun) == lowp::fn_ptr(lowp::load_dst) {
442 *fun = lowp::load_dst_tail as lowp::StageFn;
443 } else if lowp::fn_ptr(*fun) == lowp::fn_ptr(lowp::store) {
444 *fun = lowp::store_tail as lowp::StageFn;
445 } else if lowp::fn_ptr(*fun) == lowp::fn_ptr(lowp::load_dst_u8) {
446 *fun = lowp::load_dst_u8_tail as lowp::StageFn;
447 } else if lowp::fn_ptr(*fun) == lowp::fn_ptr(lowp::store_u8) {
448 *fun = lowp::store_u8_tail as lowp::StageFn;
449 } else if lowp::fn_ptr(*fun) == lowp::fn_ptr(lowp::source_over_rgba) {
450 *fun = lowp::source_over_rgba_tail as lowp::StageFn;
453 }
454 }
455
456 RasterPipeline {
457 kind: RasterPipelineKind::Low {
458 functions,
459 tail_functions,
460 },
461 ctx: self.ctx,
462 }
463 }
464 }
465}
466
467pub enum RasterPipelineKind {
468 High {
469 functions: ArrayVec<highp::StageFn, MAX_STAGES>,
470 tail_functions: ArrayVec<highp::StageFn, MAX_STAGES>,
471 },
472 Low {
473 functions: ArrayVec<lowp::StageFn, MAX_STAGES>,
474 tail_functions: ArrayVec<lowp::StageFn, MAX_STAGES>,
475 },
476}
477
478pub struct RasterPipeline {
479 kind: RasterPipelineKind,
480 pub ctx: Context,
481}
482
483impl RasterPipeline {
484 pub fn run(
485 &mut self,
486 rect: &ScreenIntRect,
487 aa_mask_ctx: AAMaskCtx,
488 mask_ctx: MaskCtx,
489 pixmap_src: PixmapRef,
490 pixmap_dst: &mut SubPixmapMut,
491 ) {
492 match self.kind {
493 RasterPipelineKind::High {
494 ref functions,
495 ref tail_functions,
496 } => {
497 highp::start(
498 functions.as_slice(),
499 tail_functions.as_slice(),
500 rect,
501 aa_mask_ctx,
502 mask_ctx,
503 &mut self.ctx,
504 pixmap_src,
505 pixmap_dst,
506 );
507 }
508 RasterPipelineKind::Low {
509 ref functions,
510 ref tail_functions,
511 } => {
512 lowp::start(
513 functions.as_slice(),
514 tail_functions.as_slice(),
515 rect,
516 aa_mask_ctx,
517 mask_ctx,
518 &mut self.ctx,
519 pixmap_dst,
521 );
522 }
523 }
524 }
525}
526
527#[rustfmt::skip]
528#[cfg(test)]
529mod blend_tests {
530 use super::*;
539 use crate::{BlendMode, Color, Pixmap, PremultipliedColorU8};
540 use crate::geom::IntSizeExt;
541
542 macro_rules! test_blend {
543 ($name:ident, $mode:expr, $is_highp:expr, $r:expr, $g:expr, $b:expr, $a:expr) => {
544 #[test]
545 fn $name() {
546 let mut pixmap = Pixmap::new(1, 1).unwrap();
547 pixmap.fill(Color::from_rgba8(50, 127, 150, 200));
548
549 let pixmap_src = PixmapRef::from_bytes(&[0, 0, 0, 0], 1, 1).unwrap();
550
551 let mut p = RasterPipelineBuilder::new();
552 p.set_force_hq_pipeline($is_highp);
553 p.push_uniform_color(Color::from_rgba8(220, 140, 75, 180).premultiply());
554 p.push(Stage::LoadDestination);
555 p.push($mode.to_stage().unwrap());
556 p.push(Stage::Store);
557 let mut p = p.compile();
558 let rect = pixmap.size().to_screen_int_rect(0, 0);
559 p.run(&rect, AAMaskCtx::default(), MaskCtx::default(), pixmap_src,
560 &mut pixmap.as_mut().as_subpixmap());
561
562 assert_eq!(
563 pixmap.as_ref().pixel(0, 0).unwrap(),
564 PremultipliedColorU8::from_rgba($r, $g, $b, $a).unwrap()
565 );
566 }
567 };
568 }
569
570 macro_rules! test_blend_lowp {
571 ($name:ident, $mode:expr, $r:expr, $g:expr, $b:expr, $a:expr) => (
572 test_blend!{$name, $mode, false, $r, $g, $b, $a}
573 )
574 }
575
576 macro_rules! test_blend_highp {
577 ($name:ident, $mode:expr, $r:expr, $g:expr, $b:expr, $a:expr) => (
578 test_blend!{$name, $mode, true, $r, $g, $b, $a}
579 )
580 }
581
582 test_blend_lowp!(clear_lowp, BlendMode::Clear, 0, 0, 0, 0);
583 test_blend_lowp!(destination_lowp, BlendMode::Destination, 39, 100, 118, 200);
585 test_blend_lowp!(source_over_lowp, BlendMode::SourceOver, 167, 129, 88, 239);
586 test_blend_lowp!(destination_over_lowp, BlendMode::DestinationOver, 73, 122, 130, 239);
587 test_blend_lowp!(source_in_lowp, BlendMode::SourceIn, 122, 78, 42, 141);
588 test_blend_lowp!(destination_in_lowp, BlendMode::DestinationIn, 28, 71, 83, 141);
589 test_blend_lowp!(source_out_lowp, BlendMode::SourceOut, 34, 22, 12, 39);
590 test_blend_lowp!(destination_out_lowp, BlendMode::DestinationOut, 12, 30, 35, 59);
591 test_blend_lowp!(source_atop_lowp, BlendMode::SourceAtop, 133, 107, 76, 200);
592 test_blend_lowp!(destination_atop_lowp, BlendMode::DestinationAtop, 61, 92, 95, 180);
593 test_blend_lowp!(xor_lowp, BlendMode::Xor, 45, 51, 46, 98);
594 test_blend_lowp!(plus_lowp, BlendMode::Plus, 194, 199, 171, 255);
595 test_blend_lowp!(modulate_lowp, BlendMode::Modulate, 24, 39, 25, 141);
596 test_blend_lowp!(screen_lowp, BlendMode::Screen, 170, 160, 146, 239);
597 test_blend_lowp!(overlay_lowp, BlendMode::Overlay, 92, 128, 106, 239);
598 test_blend_lowp!(darken_lowp, BlendMode::Darken, 72, 121, 88, 239);
599 test_blend_lowp!(lighten_lowp, BlendMode::Lighten, 166, 128, 129, 239);
600 test_blend_lowp!(hard_light_lowp, BlendMode::HardLight, 154, 128, 95, 239);
603 test_blend_lowp!(difference_lowp, BlendMode::Difference, 138, 57, 87, 239);
605 test_blend_lowp!(exclusion_lowp, BlendMode::Exclusion, 146, 121, 121, 239);
606 test_blend_lowp!(multiply_lowp, BlendMode::Multiply, 69, 90, 71, 238);
607 test_blend_highp!(clear_highp, BlendMode::Clear, 0, 0, 0, 0);
613 test_blend_highp!(destination_highp, BlendMode::Destination, 39, 100, 118, 200);
615 test_blend_highp!(source_over_highp, BlendMode::SourceOver, 167, 128, 88, 239);
616 test_blend_highp!(destination_over_highp, BlendMode::DestinationOver, 72, 121, 129, 239);
617 test_blend_highp!(source_in_highp, BlendMode::SourceIn, 122, 78, 42, 141);
618 test_blend_highp!(destination_in_highp, BlendMode::DestinationIn, 28, 71, 83, 141);
619 test_blend_highp!(source_out_highp, BlendMode::SourceOut, 33, 21, 11, 39);
620 test_blend_highp!(destination_out_highp, BlendMode::DestinationOut, 11, 29, 35, 59);
621 test_blend_highp!(source_atop_highp, BlendMode::SourceAtop, 133, 107, 76, 200);
622 test_blend_highp!(destination_atop_highp, BlendMode::DestinationAtop, 61, 92, 95, 180);
623 test_blend_highp!(xor_highp, BlendMode::Xor, 45, 51, 46, 98);
624 test_blend_highp!(plus_highp, BlendMode::Plus, 194, 199, 171, 255);
625 test_blend_highp!(modulate_highp, BlendMode::Modulate, 24, 39, 24, 141);
626 test_blend_highp!(screen_highp, BlendMode::Screen, 171, 160, 146, 239);
627 test_blend_highp!(overlay_highp, BlendMode::Overlay, 92, 128, 106, 239);
628 test_blend_highp!(darken_highp, BlendMode::Darken, 72, 121, 88, 239);
629 test_blend_highp!(lighten_highp, BlendMode::Lighten, 167, 128, 129, 239);
630 test_blend_highp!(color_dodge_highp, BlendMode::ColorDodge, 186, 192, 164, 239);
631 test_blend_highp!(color_burn_highp, BlendMode::ColorBurn, 54, 63, 46, 239);
632 test_blend_highp!(hard_light_highp, BlendMode::HardLight, 155, 128, 95, 239);
633 test_blend_highp!(soft_light_highp, BlendMode::SoftLight, 98, 124, 115, 239);
634 test_blend_highp!(difference_highp, BlendMode::Difference, 139, 58, 88, 239);
635 test_blend_highp!(exclusion_highp, BlendMode::Exclusion, 147, 121, 122, 239);
636 test_blend_highp!(multiply_highp, BlendMode::Multiply, 69, 89, 71, 239);
637 test_blend_highp!(hue_highp, BlendMode::Hue, 128, 103, 74, 239);
638 test_blend_highp!(saturation_highp, BlendMode::Saturation, 59, 126, 140, 239);
639 test_blend_highp!(color_highp, BlendMode::Color, 139, 100, 60, 239);
640 test_blend_highp!(luminosity_highp, BlendMode::Luminosity, 100, 149, 157, 239);
641}