use super::super::*;
fn equal_with_safe_rel_error(
value: f32,
expected: f32,
eps: f32,
min_expected: f32,
) -> (bool, f32) {
if value == expected {
return (true, 0.0);
}
if value.is_nan() && expected.is_nan() {
return (true, 0.0);
}
let div = if expected > 0.0 {
if expected < min_expected {
min_expected
} else {
expected
}
} else if -expected < min_expected {
min_expected
} else {
-expected
};
let err = (if value > expected {
value - expected
} else {
expected - value
}) / div;
(err <= eps, err)
}
fn to_pixels(img: &[f32]) -> Vec<Pixel> {
img.as_chunks::<4>()
.0
.iter()
.map(|c| [c[0], c[1], c[2], c[3]])
.collect()
}
fn from_pixels(px: &[Pixel], img: &mut [f32]) {
for (i, p) in px.iter().enumerate() {
img[i * 4..i * 4 + 4].copy_from_slice(p);
}
}
fn renderer(style: FixedFunctionOpStyle, params: &[f64]) -> FixedFunctionOp {
FixedFunctionOp::new(FixedFunctionOpData::new(style, params).unwrap()).unwrap()
}
#[track_caller]
fn apply_fixed_function(
img: &mut [f32],
expected: &[f32],
num_samples: usize,
style: FixedFunctionOpStyle,
params: &[f64],
error_threshold: f32,
) {
let op = renderer(style, params);
let n = num_samples * 4;
let mut px = to_pixels(&img[..n]);
op.apply(&mut px);
from_pixels(&px, &mut img[..n]);
let mut failures = Vec::new();
for idx in 0..n {
let (ok, err) = equal_with_safe_rel_error(img[idx], expected[idx], error_threshold, 1.0);
if !ok {
failures.push(format!(
"Index: {idx} - Values: {} expected: {} - Error: {err} ({:.3}x of Threshold: {error_threshold})",
img[idx],
expected[idx],
err / error_threshold
));
}
}
assert!(failures.is_empty(), "{style:?}:\n{}", failures.join("\n"));
}
fn generate_identity_lut3d(edge_len: usize) -> Vec<f32> {
let num_channels = 4;
let mut img = vec![0.0f32; edge_len * edge_len * edge_len * num_channels];
let c = 1.0f32 / (edge_len as f32 - 1.0);
for i in 0..edge_len * edge_len * edge_len {
img[num_channels * i] = (i % edge_len) as f32 * c;
img[num_channels * i + 1] = ((i / edge_len) % edge_len) as f32 * c;
img[num_channels * i + 2] = ((i / edge_len / edge_len) % edge_len) as f32 * c;
}
img
}
#[test]
fn aces_red_mod_03() {
let num_samples = 4;
let input_32f: [f32; 16] = [
0.90, 0.05, 0.22, 0.5, 0.97, 0.097, 0.0097, 1.0, 0.89, 0.15, 0.56, 0.0, -1.0, -0.001, 1.2, 0.0,
];
let mut output_32f = input_32f;
let expected_32f: [f32; 16] = [
0.79670035, 0.05, 0.19934007, 0.5, 0.83517569, 0.08474324, 0.0097, 1.0, 0.87166744, 0.15, 0.54984271, 0.0, -1.0, -0.001, 1.2, 0.0,
];
apply_fixed_function(
&mut output_32f,
&expected_32f,
num_samples,
S::AcesRedMod03Fwd,
&[],
1e-7,
);
apply_fixed_function(
&mut output_32f,
&input_32f,
num_samples,
S::AcesRedMod03Inv,
&[],
1e-7,
);
}
#[test]
fn aces_red_mod_10() {
let num_samples = 4;
let input_32f: [f32; 16] = [
0.90, 0.05, 0.22, 0.5, 0.97, 0.097, 0.0097, 1.0, 0.89, 0.15, 0.56, 0.0, -1.0, -0.001, 1.2, 0.0,
];
let mut output_32f = input_32f;
let expected_32f: [f32; 16] = [
0.77148211, 0.05, 0.22, 0.5, 0.80705338, 0.097, 0.0097, 1.0, 0.85730940, 0.15, 0.56, 0.0, -1.0, -0.001, 1.2, 0.0,
];
apply_fixed_function(
&mut output_32f,
&expected_32f,
num_samples,
S::AcesRedMod10Fwd,
&[],
1e-7,
);
let mut adjusted_input_32f = input_32f;
adjusted_input_32f[0] = 0.89146208;
adjusted_input_32f[4] = 0.96750682;
adjusted_input_32f[8] = 0.88518190;
apply_fixed_function(
&mut output_32f,
&adjusted_input_32f,
num_samples,
S::AcesRedMod10Inv,
&[],
1e-7,
);
}
#[test]
fn aces_glow_03() {
let num_samples = 4;
let input_32f: [f32; 16] = [
0.11, 0.02, 0.0, 0.5, 0.01, 0.02, 0.03, 1.0, 0.11, 0.91, 0.01, 0.0, -1.0, -0.001, 1.2, 0.0,
];
let mut output_32f = input_32f;
let expected_32f: [f32; 16] = [
0.11392101, 0.02071291, 0.0, 0.5, 0.01070833, 0.02141666, 0.03212499, 1.0, 0.10999999, 0.91000002, 0.00999999, 0.0, -1.0, -0.001, 1.2, 0.0,
];
apply_fixed_function(
&mut output_32f,
&expected_32f,
num_samples,
S::AcesGlow03Fwd,
&[],
1e-7,
);
apply_fixed_function(
&mut output_32f,
&input_32f,
num_samples,
S::AcesGlow03Inv,
&[],
1e-7,
);
}
#[test]
fn aces_glow_10() {
let num_samples = 4;
let input_32f: [f32; 16] = [
0.11, 0.02, 0.0, 0.5, 0.01, 0.02, 0.03, 1.0, 0.11, 0.91, 0.01, 0.0, -1.0, -0.001, 1.2, 0.0,
];
let mut output_32f = input_32f;
let expected_32f: [f32; 16] = [
0.11154121, 0.02028021, 0.0, 0.5, 0.01047222, 0.02094444, 0.03141666, 1.0, 0.10999999, 0.91000002, 0.00999999, 0.0, -1.0, -0.001, 1.2, 0.0,
];
apply_fixed_function(
&mut output_32f,
&expected_32f,
num_samples,
S::AcesGlow10Fwd,
&[],
1e-7,
);
apply_fixed_function(
&mut output_32f,
&input_32f,
num_samples,
S::AcesGlow10Inv,
&[],
1e-7,
);
}
#[test]
fn aces_dark_to_dim_10() {
let num_samples = 4;
let input_32f: [f32; 16] = [
0.11, 0.02, 0.04, 0.5, 0.71, 0.51, 0.92, 1.0, 0.43, 0.82, 0.71, 0.0, -0.3, 0.5, 1.2, 0.0,
];
let mut output_32f = input_32f;
let expected_32f: [f32; 16] = [
0.11661188,
0.02120216,
0.04240432,
0.5, 0.71719729,
0.51516991,
0.92932611,
1.0, 0.43281638,
0.82537078,
0.71465027,
0.0, -0.30653429,
0.51089048,
1.22613716,
0.0,
];
apply_fixed_function(
&mut output_32f,
&expected_32f,
num_samples,
S::AcesDarkToDim10Fwd,
&[],
1e-7,
);
apply_fixed_function(
&mut output_32f,
&input_32f,
num_samples,
S::AcesDarkToDim10Inv,
&[],
1e-7,
);
}
#[test]
fn aces_gamut_map_13() {
let num_samples = 39;
#[rustfmt::skip]
let input_32f: [f32; 39 * 4] = [
0.96663409472, 0.04819045216, 0.00719300006, 0.0,
0.11554181576, 1.18493819237, -0.06659350544, 0.0,
-0.08217582852, -0.23312863708, 1.05940067768, 0.0,
0.92980366945, 0.03025679290, -0.02240031771, 0.0,
0.12437260151, 1.19238424301, -0.08014731854, 0.0,
-0.05417707562, -0.22264070809, 1.10254764557, 0.0,
1.10869872570, -0.05317572504, -0.00306261564, 0.0,
0.00142395718, 1.31239914894, -0.22332298756, 0.0,
-0.11012268066, -0.25922337174, 1.22638559341, 0.0,
1.14983725548, -0.02548932098, -0.06720325351, 0.0,
-0.06796986610, 1.30455482006, -0.31973674893, 0.0,
-0.08186896890, -0.27906489372, 1.38694024086, 0.0,
1.08979821205, -0.03117186762, -0.00326358480, 0.0,
-0.03276504576, 1.18293666840, -0.00156985107, 0.0,
-0.05703317001, -0.15176482499, 1.00483345985, 0.0,
1.15183949471, -0.04052511975, -0.01231821068, 0.0,
-0.11769985408, 1.20661473274, 0.00725125661, 0.0,
-0.03413961083, -0.16608965397, 1.00506699085, 0.0,
1.04839742184, -0.02998665348, -0.00313943392, 0.0,
0.01196120959, 1.14840388298, -0.00963746291, 0.0,
-0.06036021933, -0.11841656268, 1.01277709007, 0.0,
0.13911968470, 0.08746965975, 0.05927771702, 0.0,
0.45410454273, 0.32112336159, 0.23821924627, 0.0,
0.15262818336, 0.19457373023, 0.31270095706, 0.0,
0.11231111735, 0.14410330355, 0.06487321854, 0.0,
0.24113640189, 0.22817260027, 0.40912008286, 0.0,
0.27200737596, 0.47832396626, 0.40502992272, 0.0,
0.49412208796, 0.23219805956, 0.05947655812, 0.0,
0.09734666348, 0.10917002708, 0.33662334085, 0.0,
0.37841814756, 0.12591768801, 0.12897071242, 0.0,
0.09104857594, 0.05404697359, 0.13533248007, 0.0,
0.38014721870, 0.47619381547, 0.10615456849, 0.0,
0.60210841894, 0.38621774316, 0.08225912601, 0.0,
0.05051656812, 0.05367648974, 0.27239432931, 0.0,
0.14276765287, 0.28139206767, 0.09023084491, 0.0,
0.28782477975, 0.06140174344, 0.05256444961, 0.0,
0.70791155100, 0.58026152849, 0.09300658852, 0.0,
0.35456034541, 0.12329842150, 0.27530980110, 0.0,
0.08374430984, 0.22774916887, 0.35839819908, 0.0,
];
let mut output_32f = input_32f;
#[rustfmt::skip]
let expected_32f: [f32; 39 * 4] = [
0.96663409472, 0.08610087633, 0.04698687792, 0.0,
0.13048231602, 1.18493819237, 0.03576064110, 0.0,
0.02295053005, 0.00768482685, 1.05940067768, 0.0,
0.92980366945, 0.07499730587, 0.03567957878, 0.0,
0.13714194298, 1.19238424301, 0.03311228752, 0.0,
0.03551459312, 0.01163744926, 1.10254764557, 0.0,
1.10869872570, 0.05432271957, 0.04990577698, 0.0,
0.07070028782, 1.31239914894, 0.01541912556, 0.0,
0.02140641212, 0.01080632210, 1.22638559341, 0.0,
1.14983725548, 0.06666719913, 0.03411936760, 0.0,
0.04051816463, 1.30455482006, 0.00601124763, 0.0,
0.03941023350, 0.01482784748, 1.38694024086, 0.0,
1.08979821205, 0.06064450741, 0.04896950722, 0.0,
0.04843533039, 1.18293666840, 0.05382478237, 0.0,
0.02941548824, 0.02107459307, 1.00483345985, 0.0,
1.15183949471, 0.06142425537, 0.04885411263, 0.0,
0.01795542240, 1.20661473274, 0.05802130699, 0.0,
0.03851079941, 0.01796829700, 1.00506699085, 0.0,
1.04839742184, 0.05834102631, 0.04710924625, 0.0,
0.06705272198, 1.14840388298, 0.04955554008, 0.0,
0.02856093645, 0.02944415808, 1.01277709007, 0.0,
0.13911968470, 0.08746965975, 0.05927771330, 0.0,
0.45410454273, 0.32112336159, 0.23821924627, 0.0,
0.15262818336, 0.19457373023, 0.31270095706, 0.0,
0.11231111735, 0.14410330355, 0.06487321109, 0.0,
0.24113640189, 0.22817260027, 0.40912008286, 0.0,
0.27200737596, 0.47832396626, 0.40502992272, 0.0,
0.49412208796, 0.23219805956, 0.05947655439, 0.0,
0.09734666348, 0.10917001963, 0.33662334085, 0.0,
0.37841814756, 0.12591767311, 0.12897071242, 0.0,
0.09104857594, 0.05404697359, 0.13533248007, 0.0,
0.38014721870, 0.47619381547, 0.10615456104, 0.0,
0.60210841894, 0.38621774316, 0.08225911856, 0.0,
0.05051657557, 0.05367648602, 0.27239432931, 0.0,
0.14276765287, 0.28139206767, 0.09023086727, 0.0,
0.28782477975, 0.06140173972, 0.05256444216, 0.0,
0.70791155100, 0.58026152849, 0.09300661087, 0.0,
0.35456034541, 0.12329842150, 0.27530980110, 0.0,
0.08374431729, 0.22774916887, 0.35839819908, 0.0,
];
let params = [1.147, 1.264, 1.312, 0.815, 0.803, 0.880, 1.2];
apply_fixed_function(
&mut output_32f,
&expected_32f,
num_samples,
S::AcesGamutComp13Fwd,
¶ms,
1e-6,
);
apply_fixed_function(
&mut output_32f,
&input_32f,
num_samples,
S::AcesGamutComp13Inv,
¶ms,
1e-6,
);
}
const OT_INPUT: [f32; 35 * 4] = [
2.781808965,
0.179178253,
-0.022103530,
1.0, 3.344523751,
3.617862727,
-0.006002689,
1.0, 0.562714786,
3.438684474,
0.016100841,
1.0, 1.218191035,
3.820821747,
4.022103530,
1.0, 0.655476249,
0.382137273,
4.006002689,
1.0, 3.437285214,
0.561315526,
3.983899159,
1.0, 0.110000000,
0.020000000,
0.040000000,
0.5, 0.710000000,
0.510000000,
0.810000000,
1.0, 0.430000000,
0.820000000,
0.710000000,
0.0, 0.118770000,
0.087090000,
0.058950000,
1.0, 0.400020000,
0.319160000,
0.237360000,
1.0, 0.184760000,
0.203980000,
0.313110000,
1.0, 0.109010000,
0.135110000,
0.064930000,
1.0, 0.266840000,
0.246040000,
0.409320000,
1.0, 0.322830000,
0.462080000,
0.406060000,
1.0, 0.386050000,
0.227430000,
0.057770000,
1.0, 0.138220000,
0.130370000,
0.337030000,
1.0, 0.302020000,
0.137520000,
0.127580000,
1.0, 0.093100000,
0.063470000,
0.135250000,
1.0, 0.348760000,
0.436540000,
0.106130000,
1.0, 0.486550000,
0.366850000,
0.080610000,
1.0, 0.087320000,
0.074430000,
0.272740000,
1.0, 0.153660000,
0.256920000,
0.090710000,
1.0, 0.217420000,
0.070700000,
0.051300000,
1.0, 0.589190000,
0.539430000,
0.091570000,
1.0, 0.309040000,
0.148180000,
0.274260000,
1.0, 0.149010000,
0.233780000,
0.359390000,
1.0, 0.866530000,
0.867920000,
0.858180000,
1.0, 0.573560000,
0.572560000,
0.571690000,
1.0, 0.353460000,
0.353370000,
0.353910000,
1.0, 0.202530000,
0.202430000,
0.202870000,
1.0, 0.094670000,
0.095200000,
0.096370000,
1.0, 0.037450000,
0.037660000,
0.038950000,
1.0, 0.180000000,
0.180000000,
0.180000000,
1.0, 0.977840000,
0.977840000,
0.977840000,
1.0,
];
#[test]
fn aces_output_transform_20() {
let num_samples = 35;
let mut input2_32f = OT_INPUT;
let expected_32f: [f32; 35 * 4] = [
4.966013432,
-0.033002287,
0.041583523,
1.0, 3.969460726,
3.825797558,
-0.056160748,
1.0, -0.075460039,
3.689072609,
0.270235062,
1.0, -0.095436633,
3.650521517,
3.459975719,
1.0, -0.028881177,
0.196473420,
2.796123743,
1.0, 4.900828362,
-0.064385533,
3.838270903,
1.0, 0.096890487,
-0.001135427,
0.018971475,
0.5, 0.809613585,
0.479857147,
0.814239979,
1.0, 0.107417941,
0.920530438,
0.726379037,
0.0, 0.115475342,
0.050812997,
0.030212998,
1.0, 0.484880149,
0.301042914,
0.226769030,
1.0, 0.098463453,
0.160814837,
0.277010798,
1.0, 0.071130276,
0.107334509,
0.035097614,
1.0, 0.207111374,
0.198474824,
0.375326097,
1.0, 0.195447117,
0.481112540,
0.393299103,
1.0, 0.571913302,
0.196873263,
0.041634843,
1.0, 0.045791976,
0.069875412,
0.291233569,
1.0, 0.424848884,
0.083199054,
0.102153927,
1.0, 0.059589352,
0.022219239,
0.091246955,
1.0, 0.360364884,
0.478741497,
0.086726815,
1.0, 0.695661962,
0.371994466,
0.068298057,
1.0, 0.011806240,
0.021665439,
0.199594870,
1.0, 0.076526135,
0.256237596,
0.060564563,
1.0, 0.300064713,
0.023416281,
0.030360531,
1.0, 0.805483222,
0.596904039,
0.082996234,
1.0, 0.388385385,
0.079899333,
0.245818958,
1.0, 0.010951802,
0.196106046,
0.307181537,
1.0, 0.921020269,
0.921707630,
0.912857533,
1.0, 0.590191603,
0.588424563,
0.587825298,
1.0, 0.337743223,
0.337686002,
0.338155240,
1.0, 0.169266403,
0.169178575,
0.169557154,
1.0, 0.058346011,
0.059387885,
0.060296256,
1.0, 0.012581199,
0.012947144,
0.013654212,
1.0, 0.145115077,
0.145115703,
0.145115480,
1.0, 1.041565537,
1.041566610,
1.041566253,
1.0,
];
let params = [
1000.0, 0.680, 0.320, 0.265, 0.690, 0.150, 0.060, 0.3127, 0.3290,
];
apply_fixed_function(
&mut input2_32f,
&expected_32f,
num_samples,
S::AcesOutputTransform20Fwd,
¶ms,
1e-5,
);
apply_fixed_function(
&mut input2_32f,
&OT_INPUT,
num_samples,
S::AcesOutputTransform20Inv,
¶ms,
1e-4,
);
}
fn ot_round_trip(params: &[f64], scale: f32, tolerance: f32) {
let lut_size = 8;
let num_samples = lut_size * lut_size * lut_size;
let mut input_32f = generate_identity_lut3d(lut_size);
for v in input_32f.iter_mut() {
*v *= scale;
}
let op = renderer(S::AcesOutputTransform20Inv, params);
let mut px = to_pixels(&input_32f);
op.apply(&mut px);
let mut output_32f = vec![0.0f32; input_32f.len()];
from_pixels(&px, &mut output_32f);
apply_fixed_function(
&mut output_32f,
&input_32f,
num_samples,
S::AcesOutputTransform20Fwd,
params,
tolerance,
);
}
#[test]
fn aces_ot_20_rec709_100n_rt() {
let params = [
100.0, 0.6400, 0.3300, 0.3000, 0.6000, 0.1500, 0.0600, 0.3127, 0.3290,
];
ot_round_trip(¶ms, 1.0, 1e-3);
}
#[test]
fn aces_ot_20_edge_cases() {
let mut input_32f: [f32; 8] = [
0.0,
0.0,
0.0,
1.0, 0.742242277,
0.0931933373,
0.321542144,
1.0,
];
let expected_32f: [f32; 8] = [
0.0,
0.0,
0.0,
1.0, 0.74736571311951,
-0.0019352473318577,
0.19451357424259,
1.0,
];
let params = [
100.0, 0.6400, 0.3300, 0.3000, 0.6000, 0.1500, 0.0600, 0.3127, 0.3290,
];
apply_fixed_function(
&mut input_32f,
&expected_32f,
2,
S::AcesOutputTransform20Fwd,
¶ms,
1e-4,
);
}
#[test]
fn aces_ot_20_p3d65_100n_rt() {
let params = [
100.0, 0.680, 0.320, 0.265, 0.690, 0.150, 0.060, 0.3127, 0.3290,
];
ot_round_trip(¶ms, 1.0, 1e-2);
}
#[test]
fn aces_ot_20_p3d65_1000n_rt() {
let params = [
1000.0, 0.680, 0.320, 0.265, 0.690, 0.150, 0.060, 0.3127, 0.3290,
];
ot_round_trip(¶ms, 10.0, 1e-3);
}
fn jmh_input() -> [f32; 27 * 4] {
let mut v = [0.0f32; 27 * 4];
v.copy_from_slice(&OT_INPUT[..27 * 4]);
v
}
const JMH_EXPECTED: [f32; 27 * 4] = [
107.480636597,
206.827301025,
25.025110245,
1.0, 173.194076538,
133.330886841,
106.183448792,
1.0, 139.210220337,
191.922363281,
147.056488037,
1.0, 157.905166626,
111.975311279,
192.204727173,
1.0, 79.229278564,
100.424659729,
268.442108154,
1.0, 132.888137817,
173.358779907,
341.715240479,
1.0, 26.112514496,
42.523605347,
4.173158169,
0.5, 79.190460205,
25.002300262,
332.159759521,
1.0, 81.912559509,
39.754810333,
182.925750732,
0.0, 33.924663544,
12.254567146,
38.146659851,
1.0, 61.332393646,
15.169423103,
39.841842651,
1.0, 47.191543579,
11.839941978,
249.107116699,
1.0, 37.328300476,
13.224150658,
128.878036499,
1.0, 53.465549469,
13.121579170,
285.658966064,
1.0, 65.414512634,
19.172147751,
179.324264526,
1.0, 55.711513519,
37.182041168,
50.924011230,
1.0, 40.020961761,
20.762512207,
271.008331299,
1.0, 47.704769135,
35.791145325,
13.975610733,
1.0, 30.385913849,
14.544739723,
317.544281006,
1.0, 64.222846985,
33.487697601,
119.145133972,
1.0, 65.570358276,
35.864013672,
70.842193604,
1.0, 31.800464630,
23.920211792,
273.228973389,
1.0, 47.950405121,
28.027387619,
144.154159546,
1.0, 38.440967560,
42.604164124,
17.892261505,
1.0, 75.117736816,
40.952045441,
90.752044678,
1.0, 49.311210632,
33.812240601,
348.832092285,
1.0, 47.441757202,
22.915655136,
218.454376221,
1.0,
];
#[test]
fn aces_rgb_to_jmh_20() {
let num_samples = 27;
let input_32f = jmh_input();
let mut input2_32f = input_32f;
let params = [
0.7347, 0.2653, 0.0000, 1.0000, 0.0001, -0.0770, 0.32168, 0.33767,
];
apply_fixed_function(
&mut input2_32f,
&JMH_EXPECTED,
num_samples,
S::AcesRgbToJmh20,
¶ms,
1e-5,
);
apply_fixed_function(
&mut input2_32f,
&input_32f,
num_samples,
S::AcesJmhToRgb20,
¶ms,
1e-4,
);
let mut expected_hmj_32f = [0.0f32; 27 * 4];
for idx in 0..num_samples {
let j = JMH_EXPECTED[idx * 4];
let m = JMH_EXPECTED[idx * 4 + 1];
let h = JMH_EXPECTED[idx * 4 + 2];
expected_hmj_32f[idx * 4] = h / 360.0;
expected_hmj_32f[idx * 4 + 1] = m / 200.0;
expected_hmj_32f[idx * 4 + 2] = j / 100.0;
expected_hmj_32f[idx * 4 + 3] = JMH_EXPECTED[idx * 4 + 3];
}
let mut input2_32f = input_32f;
apply_fixed_function(
&mut input2_32f,
&expected_hmj_32f,
num_samples,
S::AcesRgbToHmj20,
¶ms,
1e-5,
);
apply_fixed_function(
&mut input2_32f,
&input_32f,
num_samples,
S::AcesHmjToRgb20,
¶ms,
1e-4,
);
}
#[test]
fn aces_tonescale_compress_20() {
let num_samples = 27;
let input_32f = JMH_EXPECTED;
let mut input2_32f = input_32f;
let expected_32f: [f32; 27 * 4] = [
110.702453613,
211.251770020,
25.025110245,
1.0, 168.016815186,
129.796249390,
106.183448792,
1.0, 140.814849854,
193.459197998,
147.056488037,
1.0, 156.429504395,
110.938423157,
192.204727173,
1.0, 80.456558228,
98.490531921,
268.442108154,
1.0, 135.172225952,
175.559326172,
341.715240479,
1.0, 18.187316895,
33.819190979,
4.173158169,
0.5, 80.413101196,
21.309329987,
332.159759521,
1.0, 83.447883606,
37.852523804,
182.925750732,
0.0, 27.411968231,
13.382784843,
38.146659851,
1.0, 59.987659454,
14.391894341,
39.841842651,
1.0, 43.298923492,
12.199877739,
249.107116699,
1.0, 31.489654541,
14.075141907,
128.878036499,
1.0, 50.749198914,
12.731806755,
285.658966064,
1.0, 64.728637695,
18.593791962,
179.324264526,
1.0, 53.399444580,
37.394416809,
50.924011230,
1.0, 34.719596863,
21.616765976,
271.008331299,
1.0, 43.910709381,
36.788166046,
13.975610733,
1.0, 23.196529388,
15.118354797,
317.544281006,
1.0, 63.348682404,
33.283519745,
119.145133972,
1.0, 64.908874512,
35.371063232,
70.842193604,
1.0, 24.876913071,
23.143159866,
273.228973389,
1.0, 44.203376770,
28.918329239,
144.154159546,
1.0, 32.824359894,
43.447853088,
17.892261505,
1.0, 75.830871582,
39.872489929,
90.752044678,
1.0, 45.823120117,
34.652057648,
348.832092285,
1.0, 43.597236633,
23.079071045,
218.454376221,
1.0,
];
let params = [1000.0];
apply_fixed_function(
&mut input2_32f,
&expected_32f,
num_samples,
S::AcesTonescaleCompress20Fwd,
¶ms,
1e-5,
);
apply_fixed_function(
&mut input2_32f,
&input_32f,
num_samples,
S::AcesTonescaleCompress20Inv,
¶ms,
1e-4,
);
}
#[test]
fn aces_gamut_map_20() {
let num_samples = 27;
let input_32f: [f32; 27 * 4] = [
110.702453613,
211.251770020,
25.025110245,
1.0, 168.016815186,
129.796249390,
106.183448792,
1.0, 140.814849854,
193.459213257,
147.056488037,
1.0, 156.429519653,
110.938514709,
192.204727173,
1.0, 80.456542969,
98.490524292,
268.442108154,
1.0, 135.172195435,
175.559280396,
341.715240479,
1.0, 18.187314987,
33.819175720,
4.173158169,
0.5, 80.413116455,
21.309329987,
332.159759521,
1.0, 83.447891235,
37.852291107,
182.925750732,
0.0, 27.411964417,
13.382769585,
38.146659851,
1.0, 59.987670898,
14.391894341,
39.841842651,
1.0, 43.298923492,
12.199877739,
249.107116699,
1.0, 31.489658356,
14.075142860,
128.878036499,
1.0, 50.749198914,
12.731814384,
285.658966064,
1.0, 64.728637695,
18.593795776,
179.324264526,
1.0, 53.399448395,
37.394428253,
50.924011230,
1.0, 34.719596863,
21.616765976,
271.008331299,
1.0, 43.910713196,
36.788166046,
13.975610733,
1.0, 23.196525574,
15.118354797,
317.544281006,
1.0, 63.348674774,
33.283493042,
119.145133972,
1.0, 64.908889771,
35.371044159,
70.842193604,
1.0, 24.876911163,
23.143159866,
273.228973389,
1.0, 44.203376770,
28.918329239,
144.154159546,
1.0, 32.824356079,
43.447875977,
17.892261505,
1.0, 75.830871582,
39.872474670,
90.752044678,
1.0, 45.823116302,
34.652069092,
348.832092285,
1.0, 43.597240448,
23.079078674,
218.454376221,
1.0,
];
let mut input2_32f = input_32f;
let expected_32f: [f32; 27 * 4] = [
107.829742432,
174.270156860,
25.025110245,
1.0, 168.028274536,
118.227561951,
106.183448792,
1.0, 140.030166626,
127.184478760,
147.056488037,
1.0, 156.512435913,
73.219184875,
192.204727173,
1.0, 79.378555298,
72.608604431,
268.442108154,
1.0, 133.827941895,
149.930618286,
341.715240479,
1.0, 18.193992615,
33.313068390,
4.173158169,
0.5, 80.413116455,
21.309329987,
332.159759521,
1.0, 83.467445374,
37.305030823,
182.925750732,
0.0, 27.411962509,
13.382769585,
38.146659851,
1.0, 59.987674713,
14.391894341,
39.841842651,
1.0, 43.298919678,
12.199877739,
249.107116699,
1.0, 31.489658356,
14.075142860,
128.878036499,
1.0, 50.749198914,
12.731814384,
285.658966064,
1.0, 64.728637695,
18.593795776,
179.324264526,
1.0, 53.399448395,
37.394428253,
50.924011230,
1.0, 34.719596863,
21.616765976,
271.008331299,
1.0, 43.910713196,
36.788166046,
13.975610733,
1.0, 23.196525574,
15.118354797,
317.544281006,
1.0, 63.348674774,
33.283493042,
119.145133972,
1.0, 64.908882141,
35.371044159,
70.842193604,
1.0, 24.876911163,
23.143159866,
273.228973389,
1.0, 44.203376770,
28.918329239,
144.154159546,
1.0, 32.824356079,
43.447875977,
17.892261505,
1.0, 75.830871582,
39.872474670,
90.752044678,
1.0, 45.823112488,
34.652069092,
348.832092285,
1.0, 43.635547638,
21.629518509,
218.454376221,
1.0,
];
let params = [
1000.0, 0.680, 0.320, 0.265, 0.690, 0.150, 0.060, 0.3127, 0.3290,
];
apply_fixed_function(
&mut input2_32f,
&expected_32f,
num_samples,
S::AcesGamutCompress20Fwd,
¶ms,
1e-5,
);
apply_fixed_function(
&mut input2_32f,
&input_32f,
num_samples,
S::AcesGamutCompress20Inv,
¶ms,
1e-5,
);
}
#[test]
fn rec2100_surround() {
let num_samples = 5;
let input_32f: [f32; 20] = [
8.4e-5, 2.4e-5, 1.4e-4, 0.1, 0.11, 0.02, 0.04, 0.5, 0.71, 0.51, 0.81, 1.0, 0.43, 0.82, 0.71, 0.0, -1.00, -0.001, 1.2, 0.0,
];
{
let params = [0.78];
let mut output_32f = input_32f;
let expected_32f: [f32; 20] = [
0.000637205163,
0.000182058618,
0.001062008605,
0.1, 0.21779590,
0.03959925,
0.07919850,
0.5, 0.80029451,
0.57485944,
0.91301214,
1.0, 0.46350446,
0.88389223,
0.76532131,
0.0, -1.43735918,
-0.00143735918,
1.72483102,
0.0,
];
apply_fixed_function(
&mut output_32f,
&expected_32f,
num_samples,
S::Rec2100SurroundFwd,
¶ms,
4e-7,
);
apply_fixed_function(
&mut output_32f,
&input_32f,
num_samples,
S::Rec2100SurroundInv,
¶ms,
3e-7,
);
}
{
let params = [1.2];
let mut output_32f = input_32f;
let expected_32f: [f32; 20] = [
1.331310281667e-05,
3.803743661907e-06,
2.218850469446e-05,
0.1, 0.059115925805,
0.010748350146,
0.021496700293,
0.5, 0.636785774786,
0.457409500198,
0.726473912080,
1.0, 0.401647721515,
0.765932864285,
0.663185772735,
0.0, -7.190495367684e-01,
-7.190495367684e-04,
8.628594441221e-01,
0.0,
];
apply_fixed_function(
&mut output_32f,
&expected_32f,
num_samples,
S::Rec2100SurroundFwd,
¶ms,
2e-7,
);
apply_fixed_function(
&mut output_32f,
&input_32f,
num_samples,
S::Rec2100SurroundInv,
¶ms,
2e-7,
);
}
}
#[test]
fn rgb_to_hsv() {
#[rustfmt::skip]
let hsv_frame: Vec<f32> = vec![
3.0 / 12.0, 0.80, 2.50, 0.50, 11.0 / 12.0, 1.20, 2.50, 1.00, 15.0 / 24.0, 0.80, -2.00, 0.25, 19.0 / 24.0, 1.50, -0.40, 0.25, -89.0 / 24.0, 0.50, 0.40, 2.00, 81.0 / 24.0, 1.50, -0.40, -0.25, 81.0 / 24.0, -0.50, 0.40, 0.00, 0.5000, 2.50, 0.04, 0.00, ];
#[rustfmt::skip]
let rgb_frame: Vec<f32> = vec![
1.500, 2.500, 0.500, 0.50,
3.125, -0.625, 1.250, 1.00,
-5.0 / 3.0, -4.0 / 3.0, -1.0 / 3.0, 0.25,
0.100, -0.800, 0.400, 0.25,
0.250, 0.400, 0.200, 2.00,
-0.800, 0.400, -0.500, -0.25,
0.400, 0.400, 0.400, 0.00,
-39.96, 40.00, 40.00, 0.00,
];
let num_rgb = 4; let mut img = rgb_frame.clone();
apply_fixed_function(&mut img, &hsv_frame, num_rgb, S::RgbToHsv, &[], 1e-6);
let num_hsv = 7; let mut img = hsv_frame.clone();
apply_fixed_function(&mut img, &rgb_frame, num_hsv, S::HsvToRgb, &[], 1e-6);
}
#[test]
fn rgb_to_hsy_lin() {
let num_pixels = 8;
#[rustfmt::skip]
let hsy_frame: Vec<f32> = vec![
0.470554752, 9.12594033, 0.0326650218, 0.0, 0.75, 0.22196741, 0.38596, 0.0,
0.08333333, 0.12976444, 0.034974, 0.0,
0.333333333333, 0.606036032, 0.0056680, 1.0, 0.241666666667, 0.8372990325, 0.0034440, 1.0,
0.734693877551, 0.752099600, 0.0005572, 0.0, 0.96296296, 9.7034, -0.1862, 0.0,
0.730158730159, 0.811517000, -0.0009310, 0.0,
];
#[rustfmt::skip]
let rgb_frame: Vec<f32> = vec![
-0.075290, 0.078996, -0.108397, 0.0,
0.3, 0.4, 0.5, 0.0,
0.05, 0.03, 0.04, 0.0,
0.01, 0.01, -0.05, 1.0,
0.05, -0.005, -0.05, 1.0,
-0.048, 0.01, 0.05, 0.0,
0.3, -0.4, 0.5, 0.0,
-0.055, 0.01, 0.05, 0.0,
];
let mut img = rgb_frame.clone();
apply_fixed_function(&mut img, &hsy_frame, num_pixels, S::RgbToHsyLin, &[], 1e-6);
let mut img = hsy_frame.clone();
apply_fixed_function(&mut img, &rgb_frame, num_pixels, S::HsyLinToRgb, &[], 1e-6);
}
#[test]
fn rgb_to_hsy_log() {
let hsy_frame: Vec<f32> = vec![
14563.0 / 65535.0,
64392.0 / 65535.0,
20899.0 / 65535.0,
32007.0 / 65535.0,
50061.0 / 65535.0,
64310.0 / 65535.0,
6328.0 / 65535.0,
65535.0 / 65535.0,
];
let rgb_frame: Vec<f32> = vec![
1800.0 / 4095.0,
1200.0 / 4095.0,
900.0 / 4095.0,
2000.0 / 4095.0,
40.0 / 4095.0,
440.0 / 4095.0,
1000.0 / 4095.0,
4095.0 / 4095.0,
];
let mut img = rgb_frame.clone();
apply_fixed_function(&mut img, &hsy_frame, 2, S::RgbToHsyLog, &[], 1e-5);
let mut img = hsy_frame.clone();
apply_fixed_function(&mut img, &rgb_frame, 2, S::HsyLogToRgb, &[], 1e-5);
}
#[test]
fn rgb_to_hsy_vid() {
let hsy_frame: Vec<f32> = vec![
0.54190051555634,
1.0851333141327,
0.55111348628998,
0.48840048909187,
0.54262113571167,
1.4824789762497,
1.1281162500381,
1.0,
];
let rgb_frame: Vec<f32> = vec![
0.12152557820082,
0.70731294155121,
0.26879417896271,
0.48840048909187,
0.53938156366348,
1.3418402671814,
0.74459171295166,
1.0,
];
let mut img = rgb_frame.clone();
apply_fixed_function(&mut img, &hsy_frame, 2, S::RgbToHsyVid, &[], 1e-6);
let mut img = hsy_frame.clone();
apply_fixed_function(&mut img, &rgb_frame, 2, S::HsyVidToRgb, &[], 1e-6);
}
#[test]
fn xyz_to_xyy() {
let input_frame: Vec<f32> = vec![
3600.0 / 4095.0,
250.0 / 4095.0,
900.0 / 4095.0,
2000.0 / 4095.0,
400.0 / 4095.0,
3000.0 / 4095.0,
4000.0 / 4095.0,
4095.0 / 4095.0,
];
let output_frame: Vec<f32> = vec![
49669.0 / 65535.0,
3449.0 / 65535.0,
4001.0 / 65535.0,
32007.0 / 65535.0,
3542.0 / 65535.0,
26568.0 / 65535.0,
48011.0 / 65535.0,
65535.0 / 65535.0,
];
let mut img = input_frame.clone();
apply_fixed_function(&mut img, &output_frame, 2, S::XyzToXyy, &[], 1e-5);
let mut img = output_frame.clone();
apply_fixed_function(&mut img, &input_frame, 2, S::XyyToXyz, &[], 1e-4);
}
#[test]
fn xyz_to_uvy() {
let input_frame: Vec<f32> = vec![
3600.0 / 4095.0,
350.0 / 4095.0,
1900.0 / 4095.0,
2000.0 / 4095.0,
400.0 / 4095.0,
3000.0 / 4095.0,
4000.0 / 4095.0,
4095.0 / 4095.0,
];
let output_frame: Vec<f32> = vec![
64859.0 / 65535.0,
14188.0 / 65535.0,
5601.0 / 65535.0,
32007.0 / 65535.0,
1827.0 / 65535.0,
30827.0 / 65535.0,
48011.0 / 65535.0,
65535.0 / 65535.0,
];
let mut img = input_frame.clone();
apply_fixed_function(&mut img, &output_frame, 2, S::XyzToUvy, &[], 1e-5);
let mut img = output_frame.clone();
apply_fixed_function(&mut img, &input_frame, 2, S::UvyToXyz, &[], 1e-4);
}
#[test]
fn xyz_to_luv() {
let input_frame: Vec<f32> = vec![
3600.0 / 4095.0,
3500.0 / 4095.0,
1900.0 / 4095.0,
2000.0 / 4095.0,
50.0 / 4095.0,
30.0 / 4095.0,
19.0 / 4095.0,
4095.0 / 4095.0, ];
let output_frame: Vec<f32> = vec![
61659.0 / 65535.0,
28199.0 / 65535.0,
33176.0 / 65535.0,
32007.0 / 65535.0,
4337.0 / 65535.0,
9090.0 / 65535.0,
926.0 / 65535.0,
65535.0 / 65535.0,
];
let mut img = input_frame.clone();
apply_fixed_function(&mut img, &output_frame, 2, S::XyzToLuv, &[], 1e-5);
let mut img = output_frame.clone();
apply_fixed_function(&mut img, &input_frame, 2, S::LuvToXyz, &[], 1e-5);
}
#[test]
fn lin_to_pq() {
let num_pixels = 9;
#[rustfmt::skip]
let pq_frame: [f32; 36] = [
-0.10, -0.05, 0.00, -1.0, 0.05, 0.10, 0.15, 1.0,
0.20, 0.25, 0.30, 1.0,
0.35, 0.40, 0.45, 0.5,
0.50, 0.55, 0.60, 0.0,
0.65, 0.70, 0.75, 1.0,
0.80, 0.85, 0.90, 1.0,
0.95, 1.00, 1.05, 1.0,
1.10, 1.15, 1.20, 1.0, ];
#[rustfmt::skip]
let linear_frame: [f32; 36] = [
-3.2456559e-03, -6.0001636e-04, 0.0, -1.0,
6.0001636e-04, 3.2456559e-03, 1.0010649e-02, 1.0,
2.4292633e-02, 5.1541760e-02, 1.0038226e-01, 1.0,
1.8433567e-01, 3.2447918e-01, 5.5356688e-01, 0.5,
9.2245709e-01, 1.5102065e+00, 2.4400519e+00, 0.0,
3.9049474e+00, 6.2087938e+00, 9.8337786e+00, 1.0,
1.5551784e+01, 2.4611351e+01, 3.9056447e+01, 1.0,
6.2279535e+01, 1.0000000e+02, 1.6203272e+02, 1.0,
2.6556253e+02, 4.4137110e+02, 7.4603927e+02, 1.0,
];
let mut img = pq_frame;
apply_fixed_function(&mut img, &linear_frame, num_pixels, S::PqToLin, &[], 5e-5);
let mut img = linear_frame;
apply_fixed_function(&mut img, &pq_frame, num_pixels, S::LinToPq, &[], 1e-5);
}
#[test]
fn lin_to_gamma_log() {
let num_pixels = 10;
#[rustfmt::skip]
let hlg_frame: [f32; 40] = [
-0.60, -0.55, -0.50, -1.0, -0.10, -0.05, 0.00, 1.0, 0.05, 0.10, 0.15, 1.0,
0.20, 0.25, 0.30, 1.0,
0.35, 0.40, 0.45, 0.5,
0.50, 0.55, 0.60, 0.0,
0.65, 0.70, 0.75, 1.0,
0.80, 0.85, 0.90, 1.0,
0.95, 1.00, 1.05, 1.0,
1.10, 1.15, 1.20, 1.0, ];
#[rustfmt::skip]
let linear_frame: [f32; 40] = [
-0.383988768, -0.307689428, -0.250000000, -1.0,
-0.01000000, -0.002500000, 0.00000000, 1.0,
0.002500000, 0.010000000, 0.02250000, 1.0,
0.040000000, 0.062500000, 0.09000000, 1.0,
0.122500000, 0.160000000, 0.202499986, 0.5,
0.250000000, 0.307689428, 0.383988768, 0.0,
0.484901309, 0.618367195, 0.794887662, 1.0,
1.02835166, 1.33712840, 1.74551260, 1.0,
2.28563738, 3.00000000, 3.94480681, 1.0,
5.19440079, 6.84709501, 9.03293514, 1.0,
];
let mut img = hlg_frame;
apply_fixed_function(
&mut img,
&linear_frame,
num_pixels,
S::GammaLogToLin,
&super::HLG_PARAMS,
5e-5,
);
let mut img = linear_frame;
apply_fixed_function(
&mut img,
&hlg_frame,
num_pixels,
S::LinToGammaLog,
&super::HLG_PARAMS,
1e-5,
);
}
#[test]
fn lin_to_double_log() {
let params = [
10.0, 0.25, 0.5, -1.0, 0.0, -1.0,
1.25, 1.0, 1.0, 1.0,
0.5, 1.0, 0.0, ];
let num_pixels = 10;
#[rustfmt::skip]
let linear_frame: [f32; 40] = [
-0.25, -0.20, -0.15, -1.00, -0.10, -0.05, 0.00, 0.00,
0.05, 0.10, 0.15, 1.00,
0.20, 0.25, 0.30, 1.00, 0.35, 0.40, 0.45, 1.00, 0.50, 0.55, 0.60, 1.00, 0.65, 0.70, 0.75, 1.00,
0.80, 0.85, 0.90, 1.00,
0.95, 1.00, 1.05, 1.00,
1.10, 1.15, 1.20, 1.25, ];
#[rustfmt::skip]
let log_frame: [f32; 40] = [
-0.17609126, -0.161368, -0.14612804, -1.00, -0.13033377, -0.11394335, -0.09691001, 0.00,
-0.07918125, -0.06069784, -0.04139269, 1.00,
-0.0211893, 0.0, 0.3, 1.00, 0.35, 0.4, 0.45, 1.00, 1.0, 1.0211893, 1.04139269, 1.00, 1.06069784, 1.07918125, 1.09691001, 1.00,
1.11394335, 1.13033377, 1.14612804, 1.00,
1.161368, 1.17609126, 1.1903317, 1.00,
1.20411998, 1.21748394, 1.23044892, 1.25, ];
let mut img = linear_frame;
apply_fixed_function(
&mut img,
&log_frame,
num_pixels,
S::LinToDoubleLog,
¶ms,
1e-6,
);
let mut img = log_frame;
apply_fixed_function(
&mut img,
&linear_frame,
num_pixels,
S::DoubleLogToLin,
¶ms,
1e-6,
);
}
#[test]
fn nan_and_inf_do_not_panic() {
let p9 = [
1000.0, 0.680, 0.320, 0.265, 0.690, 0.150, 0.060, 0.3127, 0.3290,
];
let p8 = [
0.7347, 0.2653, 0.0000, 1.0000, 0.0001, -0.0770, 0.32168, 0.33767,
];
let ops = [
renderer(S::AcesOutputTransform20Fwd, &p9),
renderer(S::AcesOutputTransform20Inv, &p9),
renderer(S::AcesGamutCompress20Fwd, &p9),
renderer(S::AcesGamutCompress20Inv, &p9),
renderer(S::AcesTonescaleCompress20Fwd, &[1000.0]),
renderer(S::AcesTonescaleCompress20Inv, &[1000.0]),
renderer(S::AcesJmhToRgb20, &p8),
renderer(S::AcesHmjToRgb20, &p8),
];
let special = [
f32::NAN,
f32::INFINITY,
f32::NEG_INFINITY,
-1e30,
1e30,
0.0,
-0.0,
360.0,
720.5,
];
for op in &ops {
for &a in &special {
for &b in &special {
let mut px = vec![[a, b, 50.0, 1.0], [50.0, a, b, 1.0], [b, 50.0, a, 1.0]];
op.apply(&mut px);
}
}
}
}