srgb/
srgb.rs

1// Copyright 2024 the Fearless_SIMD Authors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4#![expect(
5    clippy::excessive_precision,
6    missing_docs,
7    reason = "TODO: https://github.com/linebender/fearless_simd/issues/40"
8)]
9
10use fearless_simd::{Level, Select, Simd, SimdInto, f32x4, simd_dispatch};
11
12// This block shows how to use safe wrappers for compile-time enforcement
13// of using valid SIMD intrinsics.
14#[cfg(feature = "safe_wrappers")]
15#[inline(always)]
16fn copy_alpha<S: Simd>(a: f32x4<S>, b: f32x4<S>) -> f32x4<S> {
17    // #[cfg(target_arch = "x86_64")]
18    // if let Some(avx2) = a.simd.level().as_avx2() {
19    //     return avx2
20    //         .sse4_1
21    //         ._mm_blend_ps::<8>(a.into(), b.into())
22    //         .simd_into(a.simd);
23    // }
24    #[cfg(target_arch = "aarch64")]
25    if let Some(neon) = a.simd.level().as_neon() {
26        return neon
27            .neon
28            .vcopyq_laneq_f32::<3, 3>(a.into(), b.into())
29            .simd_into(a.simd);
30    }
31    let mut result = a;
32    result[3] = b[3];
33    result
34}
35
36// This block lets the example compile without safe wrappers.
37#[cfg(not(feature = "safe_wrappers"))]
38#[inline(always)]
39fn copy_alpha<S: Simd>(a: f32x4<S>, b: f32x4<S>) -> f32x4<S> {
40    #[cfg(target_arch = "aarch64")]
41    if let Some(_neon) = a.simd.level().as_neon() {
42        unsafe {
43            return core::arch::aarch64::vcopyq_laneq_f32::<3, 3>(a.into(), b.into())
44                .simd_into(a.simd);
45        }
46    }
47    let mut result = a;
48    result[3] = b[3];
49    result
50}
51
52#[inline(always)]
53fn to_srgb_impl<S: Simd>(simd: S, rgba: [f32; 4]) -> [f32; 4] {
54    let v: f32x4<S> = rgba.simd_into(simd);
55    let vabs = v.abs();
56    let x = vabs - 5.35862651e-04;
57    let x2 = x * x;
58    let even1 = x * -9.12795913e-01 + -2.88143143e-02;
59    let even2 = x2 * -7.29192910e-01 + even1;
60    let odd1 = x * 1.06133172e+00 + 1.40194533e+00;
61    let odd2 = x2 * 2.07758287e-01 + odd1;
62    let poly = odd2 * x.sqrt() + even2;
63    let lin = vabs * 12.92;
64    let z = vabs.simd_gt(0.0031308).select(poly, lin);
65    let z_signed = z.copysign(v);
66    let result = copy_alpha(z_signed, v);
67    result.into()
68}
69
70simd_dispatch!(fn to_srgb(level, rgba: [f32; 4]) -> [f32; 4] = to_srgb_impl);
71
72fn main() {
73    let level = Level::new();
74    let rgba = [0.1, -0.2, 0.001, 0.4];
75    println!("{:?}", to_srgb(level, rgba));
76}