vello_cpu/fine/common/gradient/
radial.rs1use crate::fine::common::gradient::SimdGradientKind;
5use vello_common::encode::{FocalData, RadialKind};
6use vello_common::fearless_simd::{Simd, SimdBase, f32x8};
7
8pub(crate) enum SimdRadialKindInner<S: Simd> {
9 Radial {
10 bias: f32x8<S>,
11 scale: f32x8<S>,
12 },
13 Strip {
14 scaled_r0_squared: f32x8<S>,
15 },
16 Focal {
17 focal_data: FocalData,
18 fp0: f32x8<S>,
19 fp1: f32x8<S>,
20 },
21}
22
23pub(crate) struct SimdRadialKind<S: Simd> {
24 inner: SimdRadialKindInner<S>,
25}
26
27impl<S: Simd> SimdRadialKind<S> {
28 pub(crate) fn new(simd: S, kind: &RadialKind) -> Self {
29 let inner = match kind {
30 RadialKind::Radial { bias, scale } => SimdRadialKindInner::Radial {
31 bias: f32x8::splat(simd, *bias),
32 scale: f32x8::splat(simd, *scale),
33 },
34 RadialKind::Strip { scaled_r0_squared } => SimdRadialKindInner::Strip {
35 scaled_r0_squared: f32x8::splat(simd, *scaled_r0_squared),
36 },
37 RadialKind::Focal {
38 focal_data,
39 fp0,
40 fp1,
41 } => SimdRadialKindInner::Focal {
42 fp0: f32x8::splat(simd, *fp0),
43 fp1: f32x8::splat(simd, *fp1),
44 focal_data: *focal_data,
45 },
46 };
47
48 Self { inner }
49 }
50}
51
52impl<S: Simd> SimdGradientKind<S> for SimdRadialKind<S> {
53 #[inline(always)]
54 fn cur_pos(&self, x_pos: f32x8<S>, y_pos: f32x8<S>) -> f32x8<S> {
55 let simd = x_pos.simd;
56
57 match &self.inner {
58 SimdRadialKindInner::Radial { bias, scale } => {
59 let radius = (x_pos * x_pos + y_pos * y_pos).sqrt();
60
61 *bias + radius * *scale
62 }
63 SimdRadialKindInner::Strip { scaled_r0_squared } => {
64 let p1 = *scaled_r0_squared - y_pos * y_pos;
65
66 let mask = simd.simd_lt_f32x8(p1, f32x8::splat(simd, 0.0));
67 simd.select_f32x8(mask, f32x8::splat(simd, f32::NAN), x_pos + p1.sqrt())
68 }
69 SimdRadialKindInner::Focal {
70 focal_data,
71 fp0,
72 fp1,
73 } => {
74 let mut t = if focal_data.is_focal_on_circle() {
75 x_pos + y_pos * y_pos / x_pos
76 } else if focal_data.is_well_behaved() {
77 (x_pos * x_pos + y_pos * y_pos).sqrt() - x_pos * *fp0
78 } else if focal_data.is_swapped() || (1.0 - focal_data.f_focal_x < 0.0) {
79 f32x8::splat(simd, -1.0) * (x_pos * x_pos - y_pos * y_pos).sqrt() - x_pos * *fp0
80 } else {
81 (x_pos * x_pos - y_pos * y_pos).sqrt() - x_pos * *fp0
82 };
83
84 if !focal_data.is_well_behaved() {
85 let is_degenerate = simd.simd_le_f32x8(t, f32x8::splat(simd, 0.0));
87
88 t = simd.select_f32x8(is_degenerate, f32x8::splat(simd, f32::NAN), t);
89 }
90
91 if 1.0 - focal_data.f_focal_x < 0.0 {
92 t = f32x8::splat(simd, -1.0) * t;
93 }
94
95 if !focal_data.is_natively_focal() {
96 t += *fp1;
97 }
98
99 if focal_data.is_swapped() {
100 t = f32x8::splat(simd, 1.0) - t;
101 }
102
103 t
104 }
105 }
106 }
107}