vello_cpu/fine/common/gradient/
sweep.rs

1// Copyright 2025 the Vello Authors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4use crate::fine::common::gradient::SimdGradientKind;
5use core::f32::consts::PI;
6use vello_common::encode::SweepKind;
7use vello_common::fearless_simd::{Simd, SimdBase, SimdFloat, f32x8};
8
9#[derive(Debug)]
10pub(crate) struct SimdSweepKind<S: Simd> {
11    start_angle: f32x8<S>,
12    inv_angle_delta: f32x8<S>,
13    simd: S,
14}
15
16impl<S: Simd> SimdSweepKind<S> {
17    pub(crate) fn new(simd: S, kind: &SweepKind) -> Self {
18        Self {
19            start_angle: f32x8::splat(simd, kind.start_angle),
20            inv_angle_delta: f32x8::splat(simd, kind.inv_angle_delta),
21            simd,
22        }
23    }
24}
25
26impl<S: Simd> SimdGradientKind<S> for SimdSweepKind<S> {
27    #[inline(always)]
28    fn cur_pos(&self, x_pos: f32x8<S>, y_pos: f32x8<S>) -> f32x8<S> {
29        let angle = x_y_to_unit_angle(self.simd, x_pos, y_pos) * f32x8::splat(self.simd, 2.0 * PI);
30
31        (angle - self.start_angle) * self.inv_angle_delta
32    }
33}
34
35#[inline(always)]
36fn x_y_to_unit_angle<S: Simd>(simd: S, x: f32x8<S>, y: f32x8<S>) -> f32x8<S> {
37    let c0 = f32x8::splat(simd, 0.0);
38    let c1 = f32x8::splat(simd, 1.0);
39    let c2 = f32x8::splat(simd, 1.0 / 4.0);
40    let c3 = f32x8::splat(simd, 1.0 / 2.0);
41
42    let x_abs = x.abs();
43    let y_abs = y.abs();
44
45    let slope = x_abs.min(y_abs) / x_abs.max(y_abs);
46    let s = slope * slope;
47
48    let a = f32x8::splat(simd, -7.054_738_2e-3).madd(s, f32x8::splat(simd, 2.476_102e-2));
49    let b = a.madd(s, f32x8::splat(simd, -5.185_397e-2));
50    let c = b.madd(s, f32x8::splat(simd, 0.159_121_17));
51
52    let mut phi = slope * c;
53
54    phi = simd.select_f32x8(simd.simd_lt_f32x8(x_abs, y_abs), c2 - phi, phi);
55    phi = simd.select_f32x8(simd.simd_lt_f32x8(x, c0), c3 - phi, phi);
56    phi = simd.select_f32x8(simd.simd_lt_f32x8(y, c0), c1 - phi, phi);
57    // Clears all NaNs, using the property that NaN != NaN.
58    phi = simd.select_f32x8(phi.simd_eq(phi), phi, c0);
59
60    phi
61}