pub fn apply_gains_rgb(data: &mut [u16], gains: [f32; 3], max_value: u16) {
#[cfg(all(target_arch = "x86_64", target_feature = "avx2"))]
{
unsafe { apply_gains_rgb_avx2(data, gains, max_value) };
return;
}
#[cfg(not(all(target_arch = "x86_64", target_feature = "avx2")))]
apply_gains_rgb_scalar(data, gains, max_value);
}
fn apply_gains_rgb_scalar(data: &mut [u16], gains: [f32; 3], max_value: u16) {
let max_f = max_value as f32;
for chunk in data.chunks_exact_mut(3) {
for (val, &g) in chunk.iter_mut().zip(gains.iter()) {
*val = ((*val as f32 * g).clamp(0.0, max_f)) as u16;
}
}
}
#[cfg(all(target_arch = "x86_64", target_feature = "avx2"))]
unsafe fn apply_gains_rgb_avx2(data: &mut [u16], gains: [f32; 3], max_value: u16) {
use std::arch::x86_64::*;
let _ = unsafe { _mm256_setzero_ps() }; apply_gains_rgb_scalar(data, gains, max_value);
}
pub fn apply_matrix_rgb(data: &mut [u16], matrix: &[[f64; 3]; 3], max_value: u16) {
let max_f = max_value as f64;
for chunk in data.chunks_exact_mut(3) {
let r = chunk[0] as f64;
let g = chunk[1] as f64;
let b = chunk[2] as f64;
chunk[0] =
(matrix[0][0] * r + matrix[0][1] * g + matrix[0][2] * b).clamp(0.0, max_f) as u16;
chunk[1] =
(matrix[1][0] * r + matrix[1][1] * g + matrix[1][2] * b).clamp(0.0, max_f) as u16;
chunk[2] =
(matrix[2][0] * r + matrix[2][1] * g + matrix[2][2] * b).clamp(0.0, max_f) as u16;
}
}
pub fn subtract_black_level_uniform(data: &mut [u16], black_level: u16) {
for val in data.iter_mut() {
*val = val.saturating_sub(black_level);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_apply_gains_rgb_identity() {
let mut data = vec![1000u16, 2000, 3000, 4000, 5000, 6000];
apply_gains_rgb(&mut data, [1.0, 1.0, 1.0], 65535);
assert_eq!(data, vec![1000, 2000, 3000, 4000, 5000, 6000]);
}
#[test]
fn test_apply_gains_rgb_double() {
let mut data = vec![100u16, 200, 300];
apply_gains_rgb(&mut data, [2.0, 2.0, 2.0], 65535);
assert_eq!(data, vec![200, 400, 600]);
}
#[test]
fn test_apply_gains_rgb_clamps() {
let mut data = vec![50000u16, 50000, 50000];
apply_gains_rgb(&mut data, [2.0, 2.0, 2.0], 65535);
assert_eq!(data, vec![65535, 65535, 65535]);
}
#[test]
fn test_apply_gains_rgb_clamps_to_max_value() {
let mut data = vec![1000u16, 2000, 3000];
apply_gains_rgb(&mut data, [10.0, 10.0, 10.0], 4095);
assert!(data.iter().all(|&v| v <= 4095));
}
#[test]
fn test_apply_gains_rgb_per_channel() {
let mut data = vec![100u16, 200, 300];
apply_gains_rgb(&mut data, [2.0, 1.0, 0.5], 65535);
assert_eq!(data[0], 200);
assert_eq!(data[1], 200);
assert_eq!(data[2], 150);
}
#[test]
fn test_apply_gains_rgb_empty() {
let mut data: Vec<u16> = vec![];
apply_gains_rgb(&mut data, [1.0, 1.0, 1.0], 65535);
assert!(data.is_empty());
}
#[test]
fn test_apply_gains_rgb_trailing_samples_ignored() {
let mut data = vec![100u16, 200, 300, 400, 500, 600, 700];
apply_gains_rgb(&mut data, [2.0, 2.0, 2.0], 65535);
assert_eq!(data[0], 200);
assert_eq!(data[1], 400);
assert_eq!(data[2], 600);
assert_eq!(data[3], 800);
assert_eq!(data[4], 1000);
assert_eq!(data[5], 1200);
assert_eq!(data[6], 700); }
#[test]
fn test_apply_matrix_rgb_identity() {
let identity = [[1.0f64, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]];
let mut data = vec![1000u16, 2000, 3000];
apply_matrix_rgb(&mut data, &identity, 65535);
assert_eq!(data, vec![1000, 2000, 3000]);
}
#[test]
fn test_apply_matrix_rgb_scale() {
let scale = [[2.0f64, 0.0, 0.0], [0.0, 2.0, 0.0], [0.0, 0.0, 2.0]];
let mut data = vec![100u16, 200, 300];
apply_matrix_rgb(&mut data, &scale, 65535);
assert_eq!(data, vec![200, 400, 600]);
}
#[test]
fn test_apply_matrix_rgb_clamps() {
let scale = [[10.0f64, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]];
let mut data = vec![10000u16, 10000, 10000];
apply_matrix_rgb(&mut data, &scale, 65535);
assert_eq!(data, vec![65535, 65535, 65535]);
}
#[test]
fn test_apply_matrix_rgb_channel_mix() {
let swap = [[0.0f64, 0.0, 1.0], [0.0, 1.0, 0.0], [1.0, 0.0, 0.0]];
let mut data = vec![100u16, 200, 300];
apply_matrix_rgb(&mut data, &swap, 65535);
assert_eq!(data, vec![300, 200, 100]);
}
#[test]
fn test_apply_matrix_rgb_empty() {
let identity = [[1.0f64, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]];
let mut data: Vec<u16> = vec![];
apply_matrix_rgb(&mut data, &identity, 65535);
assert!(data.is_empty());
}
#[test]
fn test_subtract_black_level_uniform() {
let mut data = vec![500u16, 1000, 200, 0];
subtract_black_level_uniform(&mut data, 300);
assert_eq!(data, vec![200, 700, 0, 0]); }
#[test]
fn test_subtract_black_level_uniform_zero() {
let mut data = vec![100u16, 200, 300];
subtract_black_level_uniform(&mut data, 0);
assert_eq!(data, vec![100, 200, 300]);
}
#[test]
fn test_subtract_black_level_uniform_all_saturate() {
let mut data = vec![50u16, 10, 0, 100];
subtract_black_level_uniform(&mut data, 200);
assert_eq!(data, vec![0, 0, 0, 0]);
}
#[test]
fn test_subtract_black_level_uniform_exact() {
let mut data = vec![300u16];
subtract_black_level_uniform(&mut data, 300);
assert_eq!(data, vec![0]);
}
#[test]
fn test_subtract_black_level_uniform_empty() {
let mut data: Vec<u16> = vec![];
subtract_black_level_uniform(&mut data, 100);
assert!(data.is_empty());
}
}