1use crate::fine::Splat4thExt;
5use crate::peniko::{BlendMode, Compose};
6use crate::util::NormalizedMulExt;
7use vello_common::fearless_simd::*;
8
9pub(crate) trait ComposeExt {
10 fn compose<S: Simd>(
11 &self,
12 simd: S,
13 src_c: u8x32<S>,
14 bg_c: u8x32<S>,
15 alpha_mask: u8x32<S>,
16 ) -> u8x32<S>;
17}
18
19impl ComposeExt for BlendMode {
20 fn compose<S: Simd>(
21 &self,
22 simd: S,
23 src_c: u8x32<S>,
24 bg_c: u8x32<S>,
25 alpha_mask: u8x32<S>,
26 ) -> u8x32<S> {
27 match self.compose {
28 Compose::SrcOver => SrcOver::compose(simd, src_c, bg_c, alpha_mask),
29 Compose::Clear => Clear::compose(simd, src_c, bg_c, alpha_mask),
30 Compose::Copy => Copy::compose(simd, src_c, bg_c, alpha_mask),
31 Compose::DestOver => DestOver::compose(simd, src_c, bg_c, alpha_mask),
32 Compose::Dest => Dest::compose(simd, src_c, bg_c, alpha_mask),
33 Compose::SrcIn => SrcIn::compose(simd, src_c, bg_c, alpha_mask),
34 Compose::DestIn => DestIn::compose(simd, src_c, bg_c, alpha_mask),
35 Compose::SrcOut => SrcOut::compose(simd, src_c, bg_c, alpha_mask),
36 Compose::DestOut => DestOut::compose(simd, src_c, bg_c, alpha_mask),
37 Compose::SrcAtop => SrcAtop::compose(simd, src_c, bg_c, alpha_mask),
38 Compose::DestAtop => DestAtop::compose(simd, src_c, bg_c, alpha_mask),
39 Compose::Xor => Xor::compose(simd, src_c, bg_c, alpha_mask),
40 Compose::Plus => Plus::compose(simd, src_c, bg_c, alpha_mask),
41 Compose::PlusLighter => Plus::compose(simd, src_c, bg_c, alpha_mask),
43 }
44 }
45}
46
47macro_rules! compose {
48 ($name:ident, $fa:expr, $fb:expr, $sat:expr) => {
49 struct $name;
50
51 impl $name {
52 fn compose<S: Simd>(
53 simd: S,
54 src_c: u8x32<S>,
55 bg_c: u8x32<S>,
56 mask: u8x32<S>,
57 ) -> u8x32<S> {
58 let al_b = bg_c.splat_4th();
59 let al_s = src_c.splat_4th().normalized_mul(mask);
60
61 let fa = $fa(simd, al_s, al_b);
62 let fb = $fb(simd, al_s, al_b);
63
64 let src_c = src_c.normalized_mul(mask);
65
66 if $sat {
67 simd.narrow_u16x32(
68 (simd.widen_u8x32(src_c.normalized_mul(fa))
69 + simd.widen_u8x32(fb.normalized_mul(bg_c)))
70 .min(u16x32::splat(simd, 255))
71 .max(u16x32::splat(simd, 0)),
72 )
73 } else {
74 src_c.normalized_mul(fa) + fb.normalized_mul(bg_c)
75 }
76 }
77 }
78 };
79}
80
81compose!(
82 Clear,
83 |simd, _, _| u8x32::splat(simd, 0),
84 |simd, _, _| u8x32::splat(simd, 0),
85 false
86);
87compose!(
88 Copy,
89 |simd, _, _| u8x32::splat(simd, 255),
90 |simd, _, _| u8x32::splat(simd, 0),
91 false
92);
93compose!(
94 SrcOver,
95 |simd, _, _| u8x32::splat(simd, 255),
96 |_, al_s: u8x32<S>, _| 255 - al_s,
97 false
98);
99compose!(
100 DestOver,
101 |_, _, al_b: u8x32<S>| 255 - al_b,
102 |simd, _, _| u8x32::splat(simd, 255),
103 false
104);
105compose!(
106 Dest,
107 |simd, _, _| u8x32::splat(simd, 0),
108 |simd, _, _| u8x32::splat(simd, 255),
109 false
110);
111compose!(
112 Xor,
113 |_, _, al_b: u8x32<S>| 255 - al_b,
114 |_, al_s: u8x32<S>, _| 255 - al_s,
115 false
116);
117compose!(
118 SrcIn,
119 |_, _, al_b: u8x32<S>| al_b,
120 |simd, _, _| u8x32::splat(simd, 0),
121 false
122);
123compose!(
124 DestIn,
125 |simd, _, _| u8x32::splat(simd, 0),
126 |_, al_s: u8x32<S>, _| al_s,
127 false
128);
129compose!(
130 SrcOut,
131 |_, _, al_b: u8x32<S>| 255 - al_b,
132 |simd, _, _| u8x32::splat(simd, 0),
133 false
134);
135compose!(
136 DestOut,
137 |simd, _, _| u8x32::splat(simd, 0),
138 |_, al_s: u8x32<S>, _| 255 - al_s,
139 false
140);
141compose!(
142 SrcAtop,
143 |_, _, al_b: u8x32<S>| al_b,
144 |_, al_s: u8x32<S>, _| 255 - al_s,
145 false
146);
147compose!(
148 DestAtop,
149 |_, _, al_b: u8x32<S>| 255 - al_b,
150 |_, al_s: u8x32<S>, _| al_s,
151 false
152);
153compose!(
154 Plus,
155 |simd, _, _| u8x32::splat(simd, 255),
156 |simd, _, _| u8x32::splat(simd, 255),
157 true
158);