vello_cpu/fine/highp/
compose.rs

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