linear_srgb/default.rs
1//! Recommended API for sRGB ↔ linear conversion.
2//!
3//! This module provides the optimal implementation for each use case:
4//!
5//! - **Single values**: Scalar functions (SIMD overhead not worthwhile)
6//! - **Slices**: SIMD-accelerated with runtime CPU dispatch
7//! - **x8 batches**: SIMD with dispatch (`_dispatch`) or inlineable (`_inline`)
8//!
9//! # Quick Start
10//!
11//! ```rust
12//! use linear_srgb::default::{srgb_to_linear, linear_to_srgb};
13//!
14//! // Single value conversion
15//! let linear = srgb_to_linear(0.5);
16//! let srgb = linear_to_srgb(linear);
17//! ```
18//!
19//! # Batch Processing
20//!
21//! ```rust
22//! use linear_srgb::default::{srgb_to_linear_slice, linear_to_srgb_slice};
23//!
24//! let mut values = vec![0.5f32; 10000];
25//! srgb_to_linear_slice(&mut values); // SIMD-accelerated
26//! linear_to_srgb_slice(&mut values);
27//! ```
28//!
29//! # x8 SIMD Functions
30//!
31//! For manual SIMD control, use the x8 functions:
32//!
33//! - `*_x8` - Default with CPU dispatch (standalone use)
34//! - [`inline`] module - `#[inline(always)]` variants for use inside your own `#[multiversed]` code
35//!
36//! ```rust
37//! use linear_srgb::default::{linear_to_srgb_x8, linear_to_srgb_u8_x8};
38//! use wide::f32x8;
39//!
40//! let linear = f32x8::splat(0.214);
41//! let srgb = linear_to_srgb_x8(linear); // CPU dispatch
42//! let srgb_u8 = linear_to_srgb_u8_x8(linear);
43//! ```
44//!
45//! For use inside `#[multiversed]` functions (no dispatch overhead):
46//! ```rust,ignore
47//! use linear_srgb::default::inline::*;
48//! ```
49
50// ============================================================================
51// Single-value functions (scalar - best for individual values)
52// ============================================================================
53
54pub use crate::scalar::{
55 // Custom gamma (pure power function)
56 gamma_to_linear,
57 gamma_to_linear_f64,
58 linear_to_gamma,
59 linear_to_gamma_f64,
60 // f32 sRGB
61 linear_to_srgb,
62 linear_to_srgb_extended,
63 // f64 sRGB (high precision)
64 linear_to_srgb_f64,
65 linear_to_srgb_u8,
66 srgb_to_linear,
67 srgb_to_linear_extended,
68 srgb_to_linear_f64,
69};
70
71// u8 → f32 uses LUT (20x faster than scalar powf)
72pub use crate::simd::srgb_u8_to_linear;
73
74// ============================================================================
75// Slice functions (SIMD with dispatch - best for batches)
76// ============================================================================
77
78pub use crate::simd::{
79 // Custom gamma slices
80 gamma_to_linear_slice,
81 // f32x8 slices (for pre-aligned SIMD data)
82 gamma_to_linear_x8_slice,
83 linear_to_gamma_slice,
84 linear_to_gamma_x8_slice,
85 // f32 slices (in-place)
86 linear_to_srgb_slice,
87 // u8 ↔ f32 slices
88 linear_to_srgb_u8_slice,
89 linear_to_srgb_x8_slice,
90 srgb_to_linear_slice,
91 srgb_to_linear_x8_slice,
92 srgb_u8_to_linear_slice,
93};
94
95// ============================================================================
96// x8 SIMD functions with CPU dispatch (default)
97// ============================================================================
98
99pub use crate::simd::{
100 // Custom gamma x8 with dispatch
101 gamma_to_linear_x8_dispatch as gamma_to_linear_x8,
102 linear_to_gamma_x8_dispatch as linear_to_gamma_x8,
103 // sRGB x8 with dispatch
104 linear_to_srgb_u8_x8_dispatch as linear_to_srgb_u8_x8,
105 linear_to_srgb_x8_dispatch as linear_to_srgb_x8,
106 srgb_to_linear_x8_dispatch as srgb_to_linear_x8,
107 // u8 x8 (LUT-based, no dispatch needed)
108 srgb_u8_to_linear_x8,
109};
110
111// ============================================================================
112// LUT converter (zero-cost const tables)
113// ============================================================================
114
115pub use crate::lut::SrgbConverter;
116
117pub mod inline {
118 //! Dispatch-free inline variants for use inside `#[multiversed]` functions.
119 //!
120 //! When building your own SIMD-accelerated functions with `multiversed`,
121 //! use these `_inline` variants to avoid nested dispatch overhead.
122 //! These functions are `#[inline(always)]` and contain no dispatch overhead.
123 //!
124 //! # Example
125 //!
126 //! ```rust,ignore
127 //! use linear_srgb::default::inline::*;
128 //! use multiversed::multiversed;
129 //! use wide::f32x8;
130 //!
131 //! #[multiversed] // Your function handles dispatch
132 //! pub fn process_pixels(data: &mut [f32]) {
133 //! for chunk in data.chunks_exact_mut(8) {
134 //! let v = f32x8::from([
135 //! chunk[0], chunk[1], chunk[2], chunk[3],
136 //! chunk[4], chunk[5], chunk[6], chunk[7],
137 //! ]);
138 //! // Use inline variants - no dispatch, just raw SIMD
139 //! let linear = srgb_to_linear_x8(v);
140 //! let processed = linear * f32x8::splat(1.5);
141 //! let result = linear_to_srgb_x8(processed);
142 //! let arr: [f32; 8] = result.into();
143 //! chunk.copy_from_slice(&arr);
144 //! }
145 //! }
146 //! ```
147
148 // Re-export inline x8 functions with clean names (no _inline suffix)
149 pub use crate::simd::{
150 gamma_to_linear_x8_inline as gamma_to_linear_x8,
151 linear_to_gamma_x8_inline as linear_to_gamma_x8,
152 linear_to_srgb_u8_x8_inline as linear_to_srgb_u8_x8,
153 linear_to_srgb_x8_inline as linear_to_srgb_x8,
154 srgb_to_linear_x8_inline as srgb_to_linear_x8,
155 };
156
157 // Re-export inline x8 slice functions with clean names (no _inline suffix)
158 pub use crate::simd::{
159 gamma_to_linear_x8_slice_inline as gamma_to_linear_x8_slice,
160 linear_to_gamma_x8_slice_inline as linear_to_gamma_x8_slice,
161 linear_to_srgb_x8_slice_inline as linear_to_srgb_x8_slice,
162 srgb_to_linear_x8_slice_inline as srgb_to_linear_x8_slice,
163 };
164}