pixie_anim_lib/simd/
mod.rs1use crate::quant::Rgb;
4#[cfg(target_arch = "x86_64")]
5use std::sync::LazyLock;
6
7#[cfg(target_arch = "x86_64")]
8pub mod x86_64;
9
10#[cfg(target_arch = "x86_64")]
11pub use x86_64::PlanarLabPalette;
12
13pub mod fallback;
15
16#[cfg(target_arch = "x86_64")]
17enum SimdLevel {
18 Scalar,
19 Avx2,
20}
21
22#[cfg(target_arch = "x86_64")]
23static SIMD_LEVEL: LazyLock<SimdLevel> = LazyLock::new(|| {
24 if is_x86_feature_detected!("avx2") {
25 SimdLevel::Avx2
26 } else {
27 SimdLevel::Scalar
28 }
29});
30
31#[cfg(not(target_arch = "x86_64"))]
33pub struct PlanarLabPalette {
34 pub l: Vec<f32>,
36 pub a: Vec<f32>,
38 pub b: Vec<f32>,
40 pub len: usize,
42}
43
44#[cfg(not(target_arch = "x86_64"))]
45impl PlanarLabPalette {
46 pub fn from_lab(colors: &[crate::color::Lab]) -> Self {
48 let len = colors.len();
49 let mut l = Vec::with_capacity(len);
50 let mut a = Vec::with_capacity(len);
51 let mut b = Vec::with_capacity(len);
52 for c in colors {
53 l.push(c.l);
54 a.push(c.a);
55 b.push(c.b);
56 }
57 Self { l, a, b, len }
58 }
59}
60
61#[inline]
63pub fn find_nearest_color_lab(pixel: crate::color::Lab, palette: &PlanarLabPalette) -> usize {
64 #[cfg(target_arch = "x86_64")]
65 {
66 match *SIMD_LEVEL {
67 SimdLevel::Avx2 => unsafe {
68 x86_64::find_nearest_color_lab_planar_avx2(pixel, palette)
69 },
70 SimdLevel::Scalar => fallback::find_nearest_color_lab_planar(pixel, palette),
71 }
72 }
73
74 #[cfg(not(target_arch = "x86_64"))]
75 fallback::find_nearest_color_lab_planar(pixel, palette)
76}
77
78#[inline]
80pub fn find_nearest_color(pixel: Rgb, palette: &[Rgb]) -> usize {
81 #[cfg(target_arch = "x86_64")]
82 {
83 match *SIMD_LEVEL {
84 SimdLevel::Avx2 => unsafe { x86_64::find_nearest_color_avx2(pixel, palette) },
85 SimdLevel::Scalar => fallback::find_nearest_color(pixel, palette),
86 }
87 }
88
89 #[cfg(not(target_arch = "x86_64"))]
90 fallback::find_nearest_color(pixel, palette)
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn test_simd_vs_scalar() {
99 let palette = vec![
100 Rgb { r: 255, g: 0, b: 0 },
101 Rgb { r: 0, g: 255, b: 0 },
102 Rgb { r: 0, g: 0, b: 255 },
103 Rgb {
104 r: 128,
105 g: 128,
106 b: 128,
107 },
108 Rgb {
109 r: 10,
110 g: 10,
111 b: 10,
112 },
113 Rgb {
114 r: 200,
115 g: 200,
116 b: 200,
117 },
118 Rgb {
119 r: 50,
120 g: 150,
121 b: 250,
122 },
123 Rgb {
124 r: 250,
125 g: 150,
126 b: 50,
127 },
128 Rgb {
129 r: 20,
130 g: 30,
131 b: 40,
132 },
133 ];
134 let pixel = Rgb {
135 r: 240,
136 g: 10,
137 b: 10,
138 };
139
140 let scalar_idx = fallback::find_nearest_color(pixel, &palette);
141 let simd_idx = find_nearest_color(pixel, &palette);
142
143 assert_eq!(scalar_idx, simd_idx);
144 assert_eq!(scalar_idx, 0); }
146}