use super::*;
use crate::sinker::MixedSinker;
fn solid_gbrpf32_planes(
width: usize,
height: usize,
r: f32,
g: f32,
b: f32,
) -> (Vec<f32>, Vec<f32>, Vec<f32>) {
let n = width * height;
(std::vec![g; n], std::vec![b; n], std::vec![r; n])
}
fn patterned_gbrpf32_planes(
width: usize,
height: usize,
vals: &[f32],
) -> (Vec<f32>, Vec<f32>, Vec<f32>) {
let n = width * height;
let g: Vec<f32> = (0..n).map(|i| vals[i % vals.len()]).collect();
let b: Vec<f32> = (0..n).map(|i| vals[(i + 1) % vals.len()]).collect();
let r: Vec<f32> = (0..n).map(|i| vals[(i + 2) % vals.len()]).collect();
(g, b, r)
}
fn patterned_alpha_f32(width: usize, height: usize, seed: u8) -> Vec<f32> {
let n = width * height;
let mut buf = std::vec![0u8; n];
pseudo_random_u8(&mut buf, seed as u32);
buf.iter().map(|&b| b as f32 / 255.0).collect()
}
fn patterned_rgbf32_packed(width: usize, height: usize, vals: &[f32]) -> Vec<f32> {
let n = width * height;
let mut buf = std::vec![0.0f32; n * 3];
for i in 0..n {
buf[i * 3] = vals[(i + 2) % vals.len()]; buf[i * 3 + 1] = vals[i % vals.len()]; buf[i * 3 + 2] = vals[(i + 1) % vals.len()]; }
buf
}
#[test]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrpf32_rgb_matches_rgbf32_rgb() {
let w = 32usize;
let h = 8usize;
let vals = [0.0f32, 0.25, 0.5, 0.75, 1.0, 1.5, -0.5];
let (gp, bp, rp) = patterned_gbrpf32_planes(w, h, &vals);
let packed = patterned_rgbf32_packed(w, h, &vals);
let gbrp_src = Gbrpf32Frame::try_new(
&gp, &bp, &rp, w as u32, h as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let rgbf32_src = Rgbf32Frame::try_new(&packed, w as u32, h as u32, (w * 3) as u32).unwrap();
let mut rgb_gbrp = std::vec![0u8; w * h * 3];
let mut rgb_rgbf32 = std::vec![0u8; w * h * 3];
{
let mut sink = MixedSinker::<Gbrpf32>::new(w, h)
.with_rgb(&mut rgb_gbrp)
.unwrap();
gbrpf32_to(&gbrp_src, &mut sink).unwrap();
}
{
let mut sink = MixedSinker::<Rgbf32>::new(w, h)
.with_rgb(&mut rgb_rgbf32)
.unwrap();
rgbf32_to(&rgbf32_src, true, ColorMatrix::Bt709, &mut sink).unwrap();
}
assert_eq!(
rgb_gbrp, rgb_rgbf32,
"Gbrpf32 vs Rgbf32 RGB u8 output must be byte-identical"
);
}
#[test]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrpf16_rgb_matches_rgbf16_rgb() {
let w = 32usize;
let h = 8usize;
let vals_f32 = [0.0f32, 0.25, 0.5, 0.75, 1.0, 1.5, -0.5];
let vals_f16: Vec<half::f16> = vals_f32.iter().map(|&v| half::f16::from_f32(v)).collect();
let n = w * h;
let gp: Vec<half::f16> = (0..n).map(|i| vals_f16[i % vals_f16.len()]).collect();
let bp: Vec<half::f16> = (0..n).map(|i| vals_f16[(i + 1) % vals_f16.len()]).collect();
let rp: Vec<half::f16> = (0..n).map(|i| vals_f16[(i + 2) % vals_f16.len()]).collect();
let packed: Vec<half::f16> = (0..n * 3)
.map(|j| {
let i = j / 3;
let ch = j % 3;
match ch {
0 => vals_f16[(i + 2) % vals_f16.len()], 1 => vals_f16[i % vals_f16.len()], _ => vals_f16[(i + 1) % vals_f16.len()], }
})
.collect();
let gbrp_src = Gbrpf16Frame::try_new(
&gp, &bp, &rp, w as u32, h as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let rgbf16_src = Rgbf16Frame::try_new(&packed, w as u32, h as u32, (w * 3) as u32).unwrap();
let mut rgb_gbrp = std::vec![0u8; w * h * 3];
let mut rgb_rgbf16 = std::vec![0u8; w * h * 3];
{
let mut sink = MixedSinker::<Gbrpf16>::new(w, h)
.with_rgb(&mut rgb_gbrp)
.unwrap();
gbrpf16_to(&gbrp_src, &mut sink).unwrap();
}
{
let mut sink = MixedSinker::<Rgbf16>::new(w, h)
.with_rgb(&mut rgb_rgbf16)
.unwrap();
rgbf16_to(&rgbf16_src, true, ColorMatrix::Bt709, &mut sink).unwrap();
}
assert_eq!(
rgb_gbrp, rgb_rgbf16,
"Gbrpf16 vs Rgbf16 RGB u8 output must be byte-identical"
);
}
#[test]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrapf32_rgba_matches_independent_kernel() {
let w = 32usize;
let h = 8usize;
let vals = [0.1f32, 0.3, 0.5, 0.7, 0.9, 1.1, -0.1];
let (gp, bp, rp) = patterned_gbrpf32_planes(w, h, &vals);
let ap = patterned_alpha_f32(w, h, 0xAB);
let src = Gbrapf32Frame::try_new(
&gp, &bp, &rp, &ap, w as u32, h as u32, w as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut rgb_ref = std::vec![0u8; w * h * 3];
let mut rgba_ref = std::vec![0u8; w * h * 4];
{
let mut sink = MixedSinker::<Gbrapf32>::new(w, h)
.with_rgb(&mut rgb_ref)
.unwrap();
gbrapf32_to(&src, &mut sink).unwrap();
}
{
let mut sink = MixedSinker::<Gbrapf32>::new(w, h)
.with_rgba(&mut rgba_ref)
.unwrap();
gbrapf32_to(&src, &mut sink).unwrap();
}
let mut rgb_combo = std::vec![0u8; w * h * 3];
let mut rgba_combo = std::vec![0u8; w * h * 4];
{
let mut sink = MixedSinker::<Gbrapf32>::new(w, h)
.with_rgb(&mut rgb_combo)
.unwrap()
.with_rgba(&mut rgba_combo)
.unwrap();
gbrapf32_to(&src, &mut sink).unwrap();
}
assert_eq!(
rgb_combo, rgb_ref,
"Strategy A+ RGB must match independent RGB"
);
assert_eq!(
rgba_combo, rgba_ref,
"Strategy A+ RGBA must match independent RGBA"
);
}
#[test]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrapf32_rgba_f32_lossless_alpha() {
let w = 16usize;
let h = 4usize;
let ap: Vec<f32> = (0..w * h)
.map(|i| match i % 4 {
0 => 0.0,
1 => 0.5,
2 => 1.0,
_ => 1.5, })
.collect();
let g = std::vec![0.5f32; w * h];
let b = std::vec![0.5f32; w * h];
let r = std::vec![0.5f32; w * h];
let src = Gbrapf32Frame::try_new(
&g, &b, &r, &ap, w as u32, h as u32, w as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut rgba_out = std::vec![0.0f32; w * h * 4];
{
let mut sink = MixedSinker::<Gbrapf32>::new(w, h)
.with_rgba_f32(&mut rgba_out)
.unwrap();
gbrapf32_to(&src, &mut sink).unwrap();
}
for i in 0..w * h {
let got = rgba_out[i * 4 + 3];
let want = ap[i];
assert_eq!(
got.to_bits(),
want.to_bits(),
"α at pixel {i}: got {got} want {want}"
);
}
}
#[test]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrpf32_rgb_f16_matches_caller_side_narrow() {
let w = 64usize;
let h = 4usize;
let vals = [0.0f32, 0.25, 0.5, 0.75, 1.0, 1.25, 2.0, -0.5];
let (gp, bp, rp) = patterned_gbrpf32_planes(w, h, &vals);
let src = Gbrpf32Frame::try_new(
&gp, &bp, &rp, w as u32, h as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut rgb_f16_fused = std::vec![half::f16::ZERO; w * h * 3];
{
let mut sink = MixedSinker::<Gbrpf32>::new(w, h)
.with_rgb_f16(&mut rgb_f16_fused)
.unwrap();
gbrpf32_to(&src, &mut sink).unwrap();
}
let mut rgb_f32 = std::vec![0.0f32; w * h * 3];
{
let mut sink = MixedSinker::<Gbrpf32>::new(w, h)
.with_rgb_f32(&mut rgb_f32)
.unwrap();
gbrpf32_to(&src, &mut sink).unwrap();
}
let rgb_f16_caller: Vec<half::f16> = rgb_f32.iter().map(|&v| half::f16::from_f32(v)).collect();
assert_eq!(
rgb_f16_fused, rgb_f16_caller,
"fused with_rgb_f16 must equal caller-side narrow of with_rgb_f32"
);
}
#[test]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrpf32_rgb_f16_saturates_hdr_to_f16_inf() {
let w = 4usize;
let h = 1usize;
let r = std::vec![70000.0f32, -70000.0, 0.5, 1.0];
let g = std::vec![70000.0f32, -70000.0, 0.5, 1.0];
let b = std::vec![70000.0f32, -70000.0, 0.5, 1.0];
let src =
Gbrpf32Frame::try_new(&g, &b, &r, w as u32, h as u32, w as u32, w as u32, w as u32).unwrap();
let mut out = std::vec![half::f16::ZERO; w * 3];
{
let mut sink = MixedSinker::<Gbrpf32>::new(w, h)
.with_rgb_f16(&mut out)
.unwrap();
gbrpf32_to(&src, &mut sink).unwrap();
}
assert_eq!(out[0], half::f16::INFINITY, "px0 R must be +Inf");
assert_eq!(out[1], half::f16::INFINITY, "px0 G must be +Inf");
assert_eq!(out[2], half::f16::INFINITY, "px0 B must be +Inf");
assert_eq!(out[3], half::f16::NEG_INFINITY, "px1 R must be -Inf");
assert_eq!(out[4], half::f16::NEG_INFINITY, "px1 G must be -Inf");
assert_eq!(out[5], half::f16::NEG_INFINITY, "px1 B must be -Inf");
}
#[test]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrpf32_rgb_f32_preserves_hdr_nan_inf() {
let w = 8usize;
let h = 1usize;
let special: [f32; 8] = [
1.5,
f32::INFINITY,
f32::NEG_INFINITY,
f32::NAN,
100.0,
-0.5,
0.0,
1.0,
];
let gp: Vec<f32> = special.to_vec();
let bp: Vec<f32> = special.to_vec();
let rp: Vec<f32> = special.to_vec();
let src = Gbrpf32Frame::try_new(
&gp, &bp, &rp, w as u32, h as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut out = std::vec![0.0f32; w * 3];
{
let mut sink = MixedSinker::<Gbrpf32>::new(w, h)
.with_rgb_f32(&mut out)
.unwrap();
gbrpf32_to(&src, &mut sink).unwrap();
}
for i in 0..w {
let r_out = out[i * 3];
let r_src = rp[i];
assert_eq!(
r_out.to_bits(),
r_src.to_bits(),
"R at pixel {i}: expected {r_src} (bits {:08x}) got {r_out} (bits {:08x})",
r_src.to_bits(),
r_out.to_bits()
);
}
}
#[test]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrapf32_rgba_f32_preserves_hdr_alpha() {
let w = 8usize;
let h = 2usize;
let ap: Vec<f32> = (0..w * h)
.map(|i| match i % 4 {
0 => 0.0,
1 => f32::INFINITY,
2 => 1.5,
_ => 0.75,
})
.collect();
let g = std::vec![0.5f32; w * h];
let b = std::vec![0.5f32; w * h];
let r = std::vec![0.5f32; w * h];
let src = Gbrapf32Frame::try_new(
&g, &b, &r, &ap, w as u32, h as u32, w as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut rgba_out = std::vec![0.0f32; w * h * 4];
{
let mut sink = MixedSinker::<Gbrapf32>::new(w, h)
.with_rgba_f32(&mut rgba_out)
.unwrap();
gbrapf32_to(&src, &mut sink).unwrap();
}
for i in 0..w * h {
let got = rgba_out[i * 4 + 3];
let want = ap[i];
assert_eq!(
got.to_bits(),
want.to_bits(),
"α at pixel {i}: got {got} (bits {:08x}) want {want} (bits {:08x})",
got.to_bits(),
want.to_bits()
);
}
}
#[test]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrpf16_rgb_f16_lossless_passthrough() {
let w = 16usize;
let h = 4usize;
let vals_f32 = [0.0f32, 0.25, 0.5, 1.0, 1.5, 100.0, -0.5, f32::INFINITY];
let vals_f16: Vec<half::f16> = vals_f32.iter().map(|&v| half::f16::from_f32(v)).collect();
let n = w * h;
let gp: Vec<half::f16> = (0..n).map(|i| vals_f16[i % vals_f16.len()]).collect();
let bp: Vec<half::f16> = (0..n).map(|i| vals_f16[(i + 1) % vals_f16.len()]).collect();
let rp: Vec<half::f16> = (0..n).map(|i| vals_f16[(i + 2) % vals_f16.len()]).collect();
let src = Gbrpf16Frame::try_new(
&gp, &bp, &rp, w as u32, h as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut out = std::vec![half::f16::ZERO; w * h * 3];
{
let mut sink = MixedSinker::<Gbrpf16>::new(w, h)
.with_rgb_f16(&mut out)
.unwrap();
gbrpf16_to(&src, &mut sink).unwrap();
}
for i in 0..n {
assert_eq!(out[i * 3].to_bits(), rp[i].to_bits(), "R at pixel {i}");
assert_eq!(out[i * 3 + 1].to_bits(), gp[i].to_bits(), "G at pixel {i}");
assert_eq!(out[i * 3 + 2].to_bits(), bp[i].to_bits(), "B at pixel {i}");
}
}
#[test]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrpf32_rgba_f32_alpha_max_filled_correctly() {
let w = 16usize;
let h = 4usize;
let (gp, bp, rp) = solid_gbrpf32_planes(w, h, 0.5, 0.25, 0.75);
let src = Gbrpf32Frame::try_new(
&gp, &bp, &rp, w as u32, h as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut rgba_out = std::vec![0.0f32; w * h * 4];
{
let mut sink = MixedSinker::<Gbrpf32>::new(w, h)
.with_rgba_f32(&mut rgba_out)
.unwrap();
gbrpf32_to(&src, &mut sink).unwrap();
}
for i in 0..w * h {
let alpha = rgba_out[i * 4 + 3];
assert_eq!(
alpha.to_bits(),
1.0f32.to_bits(),
"α slot at pixel {i}: expected 1.0 got {alpha}"
);
}
}
fn round_half_up_check(rgb_out: &[u8], prefix: &str) {
assert_eq!(
rgb_out[0], 1,
"{prefix}: R[0] from 0.5/255 must be 1 (round-half-up)"
);
assert_eq!(rgb_out[1], 1, "{prefix}: G[0] from 0.5/255 must be 1");
assert_eq!(rgb_out[2], 1, "{prefix}: B[0] from 0.5/255 must be 1");
assert_eq!(rgb_out[3], 3, "{prefix}: R[1] from 2.5/255 must be 3");
assert_eq!(rgb_out[4], 3, "{prefix}: G[1] from 2.5/255 must be 3");
assert_eq!(rgb_out[5], 3, "{prefix}: B[1] from 2.5/255 must be 3");
assert_eq!(rgb_out[6], 5, "{prefix}: R[2] from 4.5/255 must be 5");
assert_eq!(rgb_out[7], 5, "{prefix}: G[2] from 4.5/255 must be 5");
assert_eq!(rgb_out[8], 5, "{prefix}: B[2] from 4.5/255 must be 5");
}
#[test]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrpf32_round_half_up_at_boundaries_scalar() {
let inputs = [0.5f32 / 255.0, 2.5 / 255.0, 4.5 / 255.0];
let w = inputs.len();
let gp = inputs.to_vec();
let bp = inputs.to_vec();
let rp = inputs.to_vec();
let src =
Gbrpf32Frame::try_new(&gp, &bp, &rp, w as u32, 1, w as u32, w as u32, w as u32).unwrap();
let mut rgb_out = std::vec![0u8; w * 3];
{
let mut sink = MixedSinker::<Gbrpf32>::new(w, 1)
.with_rgb(&mut rgb_out)
.unwrap()
.with_simd(false); gbrpf32_to(&src, &mut sink).unwrap();
}
round_half_up_check(&rgb_out, "scalar");
}
#[test]
#[cfg(target_arch = "aarch64")]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrpf32_round_half_up_at_boundaries_neon() {
if !crate::row::neon_available() {
return;
}
let inputs = [0.5f32 / 255.0, 2.5 / 255.0, 4.5 / 255.0];
let w = inputs.len();
let gp = inputs.to_vec();
let bp = inputs.to_vec();
let rp = inputs.to_vec();
let src =
Gbrpf32Frame::try_new(&gp, &bp, &rp, w as u32, 1, w as u32, w as u32, w as u32).unwrap();
let mut rgb_out = std::vec![0u8; w * 3];
{
let mut sink = MixedSinker::<Gbrpf32>::new(w, 1)
.with_rgb(&mut rgb_out)
.unwrap()
.with_simd(true);
gbrpf32_to(&src, &mut sink).unwrap();
}
round_half_up_check(&rgb_out, "neon");
}
#[test]
#[cfg(target_arch = "x86_64")]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrpf32_round_half_up_at_boundaries_sse41() {
if !is_x86_feature_detected!("sse4.1") {
return;
}
let inputs = [0.5f32 / 255.0, 2.5 / 255.0, 4.5 / 255.0];
let w = inputs.len();
let gp = inputs.to_vec();
let bp = inputs.to_vec();
let rp = inputs.to_vec();
let src =
Gbrpf32Frame::try_new(&gp, &bp, &rp, w as u32, 1, w as u32, w as u32, w as u32).unwrap();
let mut rgb_out = std::vec![0u8; w * 3];
{
let mut sink = MixedSinker::<Gbrpf32>::new(w, 1)
.with_rgb(&mut rgb_out)
.unwrap()
.with_simd(true);
gbrpf32_to(&src, &mut sink).unwrap();
}
round_half_up_check(&rgb_out, "sse41");
}
#[test]
#[cfg(target_arch = "x86_64")]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrpf32_round_half_up_at_boundaries_avx2() {
if !is_x86_feature_detected!("avx2") {
return;
}
let inputs = [0.5f32 / 255.0, 2.5 / 255.0, 4.5 / 255.0];
let w = inputs.len();
let gp = inputs.to_vec();
let bp = inputs.to_vec();
let rp = inputs.to_vec();
let src =
Gbrpf32Frame::try_new(&gp, &bp, &rp, w as u32, 1, w as u32, w as u32, w as u32).unwrap();
let mut rgb_out = std::vec![0u8; w * 3];
{
let mut sink = MixedSinker::<Gbrpf32>::new(w, 1)
.with_rgb(&mut rgb_out)
.unwrap()
.with_simd(true);
gbrpf32_to(&src, &mut sink).unwrap();
}
round_half_up_check(&rgb_out, "avx2");
}
#[test]
#[cfg(target_arch = "x86_64")]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrpf32_round_half_up_at_boundaries_avx512() {
if !is_x86_feature_detected!("avx512f") {
return;
}
let inputs = [0.5f32 / 255.0, 2.5 / 255.0, 4.5 / 255.0];
let w = inputs.len();
let gp = inputs.to_vec();
let bp = inputs.to_vec();
let rp = inputs.to_vec();
let src =
Gbrpf32Frame::try_new(&gp, &bp, &rp, w as u32, 1, w as u32, w as u32, w as u32).unwrap();
let mut rgb_out = std::vec![0u8; w * 3];
{
let mut sink = MixedSinker::<Gbrpf32>::new(w, 1)
.with_rgb(&mut rgb_out)
.unwrap()
.with_simd(true);
gbrpf32_to(&src, &mut sink).unwrap();
}
round_half_up_check(&rgb_out, "avx512");
}
fn make_gbrapf32_src(w: usize, h: usize) -> (Vec<f32>, Vec<f32>, Vec<f32>, Vec<f32>) {
let vals = [0.1f32, 0.3, 0.5, 0.7, 0.9, 0.2, 0.8];
let (gp, bp, rp) = patterned_gbrpf32_planes(w, h, &vals);
let ap = patterned_alpha_f32(w, h, 0xC3);
(gp, bp, rp, ap)
}
#[test]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrapf32_rgba_u8_strategy_a_plus_matches_independent_kernel() {
let w = 32usize;
let h = 8usize;
let (gp, bp, rp, ap) = make_gbrapf32_src(w, h);
let src = Gbrapf32Frame::try_new(
&gp, &bp, &rp, &ap, w as u32, h as u32, w as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut rgba_ref = std::vec![0u8; w * h * 4];
{
let mut sink = MixedSinker::<Gbrapf32>::new(w, h)
.with_rgba(&mut rgba_ref)
.unwrap();
gbrapf32_to(&src, &mut sink).unwrap();
}
let mut rgb_combo = std::vec![0u8; w * h * 3];
let mut rgba_combo = std::vec![0u8; w * h * 4];
{
let mut sink = MixedSinker::<Gbrapf32>::new(w, h)
.with_rgb(&mut rgb_combo)
.unwrap()
.with_rgba(&mut rgba_combo)
.unwrap();
gbrapf32_to(&src, &mut sink).unwrap();
}
assert_eq!(
rgba_combo, rgba_ref,
"Strategy A+ rgba_u8 must match independent kernel"
);
}
#[test]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrapf32_rgba_u16_strategy_a_plus_matches_independent_kernel() {
let w = 32usize;
let h = 8usize;
let (gp, bp, rp, ap) = make_gbrapf32_src(w, h);
let src = Gbrapf32Frame::try_new(
&gp, &bp, &rp, &ap, w as u32, h as u32, w as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut rgba_ref = std::vec![0u16; w * h * 4];
{
let mut sink = MixedSinker::<Gbrapf32>::new(w, h)
.with_rgba_u16(&mut rgba_ref)
.unwrap();
gbrapf32_to(&src, &mut sink).unwrap();
}
let mut rgb_combo = std::vec![0u8; w * h * 3];
let mut rgba_combo = std::vec![0u16; w * h * 4];
{
let mut sink = MixedSinker::<Gbrapf32>::new(w, h)
.with_rgb(&mut rgb_combo)
.unwrap()
.with_rgba_u16(&mut rgba_combo)
.unwrap();
gbrapf32_to(&src, &mut sink).unwrap();
}
assert_eq!(
rgba_combo, rgba_ref,
"Strategy A+ rgba_u16 must match independent kernel"
);
}
#[test]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrapf32_rgba_f32_strategy_a_plus_matches_independent_kernel() {
let w = 32usize;
let h = 8usize;
let (gp, bp, rp, ap) = make_gbrapf32_src(w, h);
let src = Gbrapf32Frame::try_new(
&gp, &bp, &rp, &ap, w as u32, h as u32, w as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut rgba_ref = std::vec![0.0f32; w * h * 4];
{
let mut sink = MixedSinker::<Gbrapf32>::new(w, h)
.with_rgba_f32(&mut rgba_ref)
.unwrap();
gbrapf32_to(&src, &mut sink).unwrap();
}
let mut rgb_combo = std::vec![0u8; w * h * 3];
let mut rgba_combo = std::vec![0.0f32; w * h * 4];
{
let mut sink = MixedSinker::<Gbrapf32>::new(w, h)
.with_rgb(&mut rgb_combo)
.unwrap()
.with_rgba_f32(&mut rgba_combo)
.unwrap();
gbrapf32_to(&src, &mut sink).unwrap();
}
let bits_ref: Vec<u32> = rgba_ref.iter().map(|v| v.to_bits()).collect();
let bits_combo: Vec<u32> = rgba_combo.iter().map(|v| v.to_bits()).collect();
assert_eq!(
bits_combo, bits_ref,
"Strategy A+ rgba_f32 must match independent kernel"
);
}
#[test]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrapf32_rgba_f16_strategy_a_plus_matches_independent_kernel() {
let w = 32usize;
let h = 8usize;
let (gp, bp, rp, ap) = make_gbrapf32_src(w, h);
let src = Gbrapf32Frame::try_new(
&gp, &bp, &rp, &ap, w as u32, h as u32, w as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut rgba_ref = std::vec![half::f16::ZERO; w * h * 4];
{
let mut sink = MixedSinker::<Gbrapf32>::new(w, h)
.with_rgba_f16(&mut rgba_ref)
.unwrap();
gbrapf32_to(&src, &mut sink).unwrap();
}
let mut rgb_combo = std::vec![0u8; w * h * 3];
let mut rgba_combo = std::vec![half::f16::ZERO; w * h * 4];
{
let mut sink = MixedSinker::<Gbrapf32>::new(w, h)
.with_rgb(&mut rgb_combo)
.unwrap()
.with_rgba_f16(&mut rgba_combo)
.unwrap();
gbrapf32_to(&src, &mut sink).unwrap();
}
let bits_ref: Vec<u16> = rgba_ref.iter().map(|v| v.to_bits()).collect();
let bits_combo: Vec<u16> = rgba_combo.iter().map(|v| v.to_bits()).collect();
assert_eq!(
bits_combo, bits_ref,
"Strategy A+ rgba_f16 must match independent kernel"
);
}
#[test]
fn gbrpf32_sinker_le_encoded_frame_decodes_correctly() {
let w = 16usize;
let h = 4usize;
let intended_g: Vec<f32> = (0..w * h)
.map(|i| match i % 4 {
0 => 0.5,
1 => 1.5,
2 => -0.25,
_ => 100.0,
})
.collect();
let intended_b: Vec<f32> = (0..w * h)
.map(|i| match i % 4 {
0 => 0.0,
1 => 0.25,
2 => 1.0,
_ => f32::INFINITY,
})
.collect();
let intended_r: Vec<f32> = (0..w * h)
.map(|i| match i % 4 {
0 => 1.0,
1 => -1.0,
2 => 65505.0,
_ => 0.5,
})
.collect();
let gp: Vec<f32> = intended_g
.iter()
.map(|&v| f32::from_bits(v.to_bits().to_le()))
.collect();
let bp: Vec<f32> = intended_b
.iter()
.map(|&v| f32::from_bits(v.to_bits().to_le()))
.collect();
let rp: Vec<f32> = intended_r
.iter()
.map(|&v| f32::from_bits(v.to_bits().to_le()))
.collect();
let src = Gbrpf32Frame::try_new(
&gp, &bp, &rp, w as u32, h as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut rgb_f32 = std::vec![0.0f32; w * h * 3];
let mut sink = MixedSinker::<Gbrpf32>::new(w, h)
.with_simd(false)
.with_rgb_f32(&mut rgb_f32)
.unwrap();
gbrpf32_to(&src, &mut sink).unwrap();
for i in 0..(w * h) {
assert_eq!(
rgb_f32[i * 3].to_bits(),
intended_r[i].to_bits(),
"R idx {i}"
);
assert_eq!(
rgb_f32[i * 3 + 1].to_bits(),
intended_g[i].to_bits(),
"G idx {i}"
);
assert_eq!(
rgb_f32[i * 3 + 2].to_bits(),
intended_b[i].to_bits(),
"B idx {i}"
);
}
}
#[test]
fn gbrapf32_sinker_le_encoded_frame_decodes_correctly() {
let w = 16usize;
let h = 4usize;
let intended_g: Vec<f32> = (0..w * h).map(|i| 0.1 + (i as f32) * 0.001).collect();
let intended_b: Vec<f32> = (0..w * h).map(|i| 0.2 + (i as f32) * 0.002).collect();
let intended_r: Vec<f32> = (0..w * h).map(|i| 0.3 + (i as f32) * 0.003).collect();
let intended_a: Vec<f32> = (0..w * h).map(|i| 0.5 + (i as f32) * 0.0005).collect();
let le = |v: &Vec<f32>| -> Vec<f32> {
v.iter()
.map(|&x| f32::from_bits(x.to_bits().to_le()))
.collect()
};
let gp = le(&intended_g);
let bp = le(&intended_b);
let rp = le(&intended_r);
let ap = le(&intended_a);
let src = Gbrapf32Frame::try_new(
&gp, &bp, &rp, &ap, w as u32, h as u32, w as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut rgba_f32 = std::vec![0.0f32; w * h * 4];
let mut sink = MixedSinker::<Gbrapf32>::new(w, h)
.with_simd(false)
.with_rgba_f32(&mut rgba_f32)
.unwrap();
gbrapf32_to(&src, &mut sink).unwrap();
for i in 0..(w * h) {
assert_eq!(
rgba_f32[i * 4].to_bits(),
intended_r[i].to_bits(),
"R idx {i}"
);
assert_eq!(
rgba_f32[i * 4 + 1].to_bits(),
intended_g[i].to_bits(),
"G idx {i}"
);
assert_eq!(
rgba_f32[i * 4 + 2].to_bits(),
intended_b[i].to_bits(),
"B idx {i}"
);
assert_eq!(
rgba_f32[i * 4 + 3].to_bits(),
intended_a[i].to_bits(),
"A idx {i}"
);
}
}
#[test]
#[cfg_attr(
miri,
ignore = "half::f16::from_f32 uses inline asm (fcvt) unsupported by Miri"
)]
fn gbrpf16_sinker_le_encoded_frame_decodes_correctly() {
let w = 16usize;
let h = 4usize;
let intended_g: Vec<half::f16> = (0..w * h)
.map(|i| {
half::f16::from_f32(match i % 4 {
0 => 0.5,
1 => 1.5,
2 => -0.25,
_ => 100.0,
})
})
.collect();
let intended_b: Vec<half::f16> = (0..w * h)
.map(|i| {
half::f16::from_f32(match i % 4 {
0 => 0.0,
1 => 0.25,
2 => 1.0,
_ => 65000.0,
})
})
.collect();
let intended_r: Vec<half::f16> = (0..w * h)
.map(|i| {
half::f16::from_f32(match i % 4 {
0 => 1.0,
1 => -1.0,
2 => 0.125,
_ => 0.5,
})
})
.collect();
let le_f16 = |v: &Vec<half::f16>| -> Vec<half::f16> {
v.iter()
.map(|&x| half::f16::from_bits(x.to_bits().to_le()))
.collect()
};
let gp = le_f16(&intended_g);
let bp = le_f16(&intended_b);
let rp = le_f16(&intended_r);
let src = Gbrpf16Frame::try_new(
&gp, &bp, &rp, w as u32, h as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut rgb_f16 = std::vec![half::f16::ZERO; w * h * 3];
let mut sink = MixedSinker::<Gbrpf16>::new(w, h)
.with_simd(false)
.with_rgb_f16(&mut rgb_f16)
.unwrap();
gbrpf16_to(&src, &mut sink).unwrap();
for i in 0..(w * h) {
assert_eq!(
rgb_f16[i * 3].to_bits(),
intended_r[i].to_bits(),
"R idx {i}"
);
assert_eq!(
rgb_f16[i * 3 + 1].to_bits(),
intended_g[i].to_bits(),
"G idx {i}"
);
assert_eq!(
rgb_f16[i * 3 + 2].to_bits(),
intended_b[i].to_bits(),
"B idx {i}"
);
}
}
#[test]
#[cfg_attr(
miri,
ignore = "half::f16::from_f32 uses inline asm (fcvt) unsupported by Miri"
)]
fn gbrapf16_sinker_le_encoded_frame_decodes_correctly() {
let w = 16usize;
let h = 4usize;
let intended_g: Vec<half::f16> = (0..w * h)
.map(|i| half::f16::from_f32(0.1 + (i as f32) * 0.001))
.collect();
let intended_b: Vec<half::f16> = (0..w * h)
.map(|i| half::f16::from_f32(0.2 + (i as f32) * 0.002))
.collect();
let intended_r: Vec<half::f16> = (0..w * h)
.map(|i| half::f16::from_f32(0.3 + (i as f32) * 0.003))
.collect();
let intended_a: Vec<half::f16> = (0..w * h)
.map(|i| half::f16::from_f32(0.5 + (i as f32) * 0.001))
.collect();
let le_f16 = |v: &Vec<half::f16>| -> Vec<half::f16> {
v.iter()
.map(|&x| half::f16::from_bits(x.to_bits().to_le()))
.collect()
};
let gp = le_f16(&intended_g);
let bp = le_f16(&intended_b);
let rp = le_f16(&intended_r);
let ap = le_f16(&intended_a);
let src = Gbrapf16Frame::try_new(
&gp, &bp, &rp, &ap, w as u32, h as u32, w as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut rgba_f16 = std::vec![half::f16::ZERO; w * h * 4];
let mut sink = MixedSinker::<Gbrapf16>::new(w, h)
.with_simd(false)
.with_rgba_f16(&mut rgba_f16)
.unwrap();
gbrapf16_to(&src, &mut sink).unwrap();
for i in 0..(w * h) {
assert_eq!(
rgba_f16[i * 4].to_bits(),
intended_r[i].to_bits(),
"R idx {i}"
);
assert_eq!(
rgba_f16[i * 4 + 1].to_bits(),
intended_g[i].to_bits(),
"G idx {i}"
);
assert_eq!(
rgba_f16[i * 4 + 2].to_bits(),
intended_b[i].to_bits(),
"B idx {i}"
);
assert_eq!(
rgba_f16[i * 4 + 3].to_bits(),
intended_a[i].to_bits(),
"A idx {i}"
);
}
}
#[test]
#[cfg_attr(
miri,
ignore = "half::f16::from_f32 uses inline asm (fcvt) unsupported by Miri"
)]
fn gbrpf16_sinker_widen_path_le_encoded_frame_decodes_correctly() {
let w = 16usize;
let h = 4usize;
let intended_g: Vec<half::f16> = (0..w * h)
.map(|i| {
half::f16::from_f32(match i % 4 {
0 => 0.5,
1 => 0.25,
2 => 0.0,
_ => 1.0,
})
})
.collect();
let intended_b: Vec<half::f16> = (0..w * h)
.map(|i| {
half::f16::from_f32(match i % 4 {
0 => 0.125,
1 => 0.75,
2 => 0.0625,
_ => 0.875,
})
})
.collect();
let intended_r: Vec<half::f16> = (0..w * h)
.map(|i| {
half::f16::from_f32(match i % 4 {
0 => 0.375,
1 => 0.625,
2 => 0.9375,
_ => 0.03125,
})
})
.collect();
let le_f16 = |v: &Vec<half::f16>| -> Vec<half::f16> {
v.iter()
.map(|&x| half::f16::from_bits(x.to_bits().to_le()))
.collect()
};
let gp = le_f16(&intended_g);
let bp = le_f16(&intended_b);
let rp = le_f16(&intended_r);
let src = Gbrpf16Frame::try_new(
&gp, &bp, &rp, w as u32, h as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut rgb_f32 = std::vec![0.0f32; w * h * 3];
let mut sink = MixedSinker::<Gbrpf16>::new(w, h)
.with_simd(false)
.with_rgb_f32(&mut rgb_f32)
.unwrap();
gbrpf16_to(&src, &mut sink).unwrap();
for i in 0..(w * h) {
assert_eq!(rgb_f32[i * 3], intended_r[i].to_f32(), "R idx {i}");
assert_eq!(rgb_f32[i * 3 + 1], intended_g[i].to_f32(), "G idx {i}");
assert_eq!(rgb_f32[i * 3 + 2], intended_b[i].to_f32(), "B idx {i}");
}
}
#[test]
#[cfg_attr(
miri,
ignore = "half::f16::from_f32 uses inline asm (fcvt) unsupported by Miri"
)]
fn gbrapf16_sinker_widen_path_le_encoded_frame_decodes_correctly() {
let w = 16usize;
let h = 4usize;
let intended_g: Vec<half::f16> = (0..w * h)
.map(|i| half::f16::from_f32(0.1 + (i as f32) * 0.001))
.collect();
let intended_b: Vec<half::f16> = (0..w * h)
.map(|i| half::f16::from_f32(0.2 + (i as f32) * 0.002))
.collect();
let intended_r: Vec<half::f16> = (0..w * h)
.map(|i| half::f16::from_f32(0.3 + (i as f32) * 0.003))
.collect();
let intended_a: Vec<half::f16> = (0..w * h)
.map(|i| half::f16::from_f32(0.5 + (i as f32) * 0.001))
.collect();
let le_f16 = |v: &Vec<half::f16>| -> Vec<half::f16> {
v.iter()
.map(|&x| half::f16::from_bits(x.to_bits().to_le()))
.collect()
};
let gp = le_f16(&intended_g);
let bp = le_f16(&intended_b);
let rp = le_f16(&intended_r);
let ap = le_f16(&intended_a);
let src = Gbrapf16Frame::try_new(
&gp, &bp, &rp, &ap, w as u32, h as u32, w as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut rgba_f32 = std::vec![0.0f32; w * h * 4];
let mut sink = MixedSinker::<Gbrapf16>::new(w, h)
.with_simd(false)
.with_rgba_f32(&mut rgba_f32)
.unwrap();
gbrapf16_to(&src, &mut sink).unwrap();
for i in 0..(w * h) {
assert_eq!(rgba_f32[i * 4], intended_r[i].to_f32(), "R idx {i}");
assert_eq!(rgba_f32[i * 4 + 1], intended_g[i].to_f32(), "G idx {i}");
assert_eq!(rgba_f32[i * 4 + 2], intended_b[i].to_f32(), "B idx {i}");
assert_eq!(rgba_f32[i * 4 + 3], intended_a[i].to_f32(), "A idx {i}");
}
}
#[test]
#[cfg_attr(
miri,
ignore = "half::f16::from_f32 uses inline asm (fcvt) unsupported by Miri"
)]
fn gbrpf16_sinker_widen_path_u16_and_u8_le_encoded_frame_decodes_correctly() {
let w = 16usize;
let h = 4usize;
let intended_g: Vec<half::f16> = (0..w * h)
.map(|i| {
half::f16::from_f32(match i % 4 {
0 => 0.5,
1 => 0.25,
2 => 0.0,
_ => 1.0,
})
})
.collect();
let intended_b: Vec<half::f16> = (0..w * h)
.map(|i| {
half::f16::from_f32(match i % 4 {
0 => 0.125,
1 => 0.75,
2 => 0.0625,
_ => 0.875,
})
})
.collect();
let intended_r: Vec<half::f16> = (0..w * h)
.map(|i| {
half::f16::from_f32(match i % 4 {
0 => 0.375,
1 => 0.625,
2 => 0.9375,
_ => 0.03125,
})
})
.collect();
let le_f16 = |v: &Vec<half::f16>| -> Vec<half::f16> {
v.iter()
.map(|&x| half::f16::from_bits(x.to_bits().to_le()))
.collect()
};
let gp = le_f16(&intended_g);
let bp = le_f16(&intended_b);
let rp = le_f16(&intended_r);
let src = Gbrpf16Frame::try_new(
&gp, &bp, &rp, w as u32, h as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut rgb_u16 = std::vec![0u16; w * h * 3];
let mut luma_u16 = std::vec![0u16; w * h];
{
let mut sink = MixedSinker::<Gbrpf16>::new(w, h)
.with_simd(false)
.with_rgb_u16(&mut rgb_u16)
.unwrap()
.with_luma_u16(&mut luma_u16)
.unwrap();
gbrpf16_to(&src, &mut sink).unwrap();
}
let to_u16 = |v: f32| -> u16 { (v.clamp(0.0, 1.0) * 65535.0 + 0.5) as u16 };
for i in 0..(w * h) {
assert_eq!(
rgb_u16[i * 3],
to_u16(intended_r[i].to_f32()),
"RGB u16 R idx {i}"
);
assert_eq!(
rgb_u16[i * 3 + 1],
to_u16(intended_g[i].to_f32()),
"RGB u16 G idx {i}"
);
assert_eq!(
rgb_u16[i * 3 + 2],
to_u16(intended_b[i].to_f32()),
"RGB u16 B idx {i}"
);
}
assert!(
luma_u16.iter().any(|&v| v > 0),
"luma_u16 must contain non-zero samples — \
a corrupted byte-swap would still emit non-zero output but the rgb_u16 \
assertion above is the primary guard"
);
}
#[test]
fn gbrapf32_strategy_a_plus_le_encoded_frame_alpha_decodes_correctly() {
let w = 15usize;
let h = 3usize;
let intended_g: Vec<f32> = (0..w * h).map(|i| 0.10 + (i as f32) * 0.001).collect();
let intended_b: Vec<f32> = (0..w * h).map(|i| 0.20 + (i as f32) * 0.002).collect();
let intended_r: Vec<f32> = (0..w * h).map(|i| 0.30 + (i as f32) * 0.003).collect();
let intended_a: Vec<f32> = (0..w * h)
.map(|i| match i % 7 {
0 => 0.0,
1 => 0.5,
2 => 1.0,
3 => 1.5,
4 => -0.1,
5 => 0.123,
_ => 0.876,
})
.collect();
let le = |v: &Vec<f32>| -> Vec<f32> {
v.iter()
.map(|&x| f32::from_bits(x.to_bits().to_le()))
.collect()
};
let gp = le(&intended_g);
let bp = le(&intended_b);
let rp = le(&intended_r);
let ap = le(&intended_a);
let src = Gbrapf32Frame::try_new(
&gp, &bp, &rp, &ap, w as u32, h as u32, w as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut rgba_ref = std::vec![0u8; w * h * 4];
{
let mut sink = MixedSinker::<Gbrapf32>::new(w, h)
.with_simd(false)
.with_rgba(&mut rgba_ref)
.unwrap();
gbrapf32_to(&src, &mut sink).unwrap();
}
let mut rgb_combo = std::vec![0u8; w * h * 3];
let mut rgba_combo = std::vec![0u8; w * h * 4];
{
let mut sink = MixedSinker::<Gbrapf32>::new(w, h)
.with_simd(false)
.with_rgb(&mut rgb_combo)
.unwrap()
.with_rgba(&mut rgba_combo)
.unwrap();
gbrapf32_to(&src, &mut sink).unwrap();
}
assert_eq!(
rgba_combo, rgba_ref,
"Gbrapf32 Strategy A+ alpha-patch must equal standalone `with_rgba`"
);
}
#[test]
fn gbrapf32_strategy_a_plus_le_encoded_u16_alpha_decodes_correctly() {
let w = 17usize;
let h = 3usize;
let intended_g: Vec<f32> = (0..w * h).map(|i| 0.11 + (i as f32) * 0.0011).collect();
let intended_b: Vec<f32> = (0..w * h).map(|i| 0.22 + (i as f32) * 0.0022).collect();
let intended_r: Vec<f32> = (0..w * h).map(|i| 0.33 + (i as f32) * 0.0033).collect();
let intended_a: Vec<f32> = (0..w * h)
.map(|i| match i % 5 {
0 => 0.0,
1 => 0.25,
2 => 1.0,
3 => 0.5,
_ => 0.75,
})
.collect();
let le = |v: &Vec<f32>| -> Vec<f32> {
v.iter()
.map(|&x| f32::from_bits(x.to_bits().to_le()))
.collect()
};
let gp = le(&intended_g);
let bp = le(&intended_b);
let rp = le(&intended_r);
let ap = le(&intended_a);
let src = Gbrapf32Frame::try_new(
&gp, &bp, &rp, &ap, w as u32, h as u32, w as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut rgba_ref = std::vec![0u16; w * h * 4];
{
let mut sink = MixedSinker::<Gbrapf32>::new(w, h)
.with_simd(false)
.with_rgba_u16(&mut rgba_ref)
.unwrap();
gbrapf32_to(&src, &mut sink).unwrap();
}
let mut rgb_combo = std::vec![0u16; w * h * 3];
let mut rgba_combo = std::vec![0u16; w * h * 4];
{
let mut sink = MixedSinker::<Gbrapf32>::new(w, h)
.with_simd(false)
.with_rgb_u16(&mut rgb_combo)
.unwrap()
.with_rgba_u16(&mut rgba_combo)
.unwrap();
gbrapf32_to(&src, &mut sink).unwrap();
}
assert_eq!(
rgba_combo, rgba_ref,
"Gbrapf32 Strategy A+ rgba_u16 must equal standalone `with_rgba_u16`"
);
let to_u16 = |v: f32| -> u16 { (v.clamp(0.0, 1.0) * 65535.0 + 0.5) as u16 };
for i in 0..(w * h) {
assert_eq!(
rgba_combo[i * 4 + 3],
to_u16(intended_a[i]),
"α slot idx {i}"
);
}
}
#[test]
#[cfg_attr(
miri,
ignore = "half::f16::from_f32 uses inline asm (fcvt) unsupported by Miri"
)]
fn gbrapf16_strategy_a_plus_post_widen_alpha_decodes_correctly() {
let w = 15usize;
let h = 3usize;
let intended_g: Vec<half::f16> = (0..w * h)
.map(|i| half::f16::from_f32(0.10 + (i as f32) * 0.001))
.collect();
let intended_b: Vec<half::f16> = (0..w * h)
.map(|i| half::f16::from_f32(0.20 + (i as f32) * 0.002))
.collect();
let intended_r: Vec<half::f16> = (0..w * h)
.map(|i| half::f16::from_f32(0.30 + (i as f32) * 0.003))
.collect();
let intended_a: Vec<half::f16> = (0..w * h)
.map(|i| {
half::f16::from_f32(match i % 5 {
0 => 0.0,
1 => 0.5,
2 => 1.0,
3 => 0.25,
_ => 0.75,
})
})
.collect();
let le_f16 = |v: &Vec<half::f16>| -> Vec<half::f16> {
v.iter()
.map(|&x| half::f16::from_bits(x.to_bits().to_le()))
.collect()
};
let gp = le_f16(&intended_g);
let bp = le_f16(&intended_b);
let rp = le_f16(&intended_r);
let ap = le_f16(&intended_a);
let src = Gbrapf16Frame::try_new(
&gp, &bp, &rp, &ap, w as u32, h as u32, w as u32, w as u32, w as u32, w as u32,
)
.unwrap();
let mut rgba_ref = std::vec![0u8; w * h * 4];
{
let mut sink = MixedSinker::<Gbrapf16>::new(w, h)
.with_simd(false)
.with_rgba(&mut rgba_ref)
.unwrap();
gbrapf16_to(&src, &mut sink).unwrap();
}
let mut rgb_combo = std::vec![0u8; w * h * 3];
let mut rgba_combo = std::vec![0u8; w * h * 4];
{
let mut sink = MixedSinker::<Gbrapf16>::new(w, h)
.with_simd(false)
.with_rgb(&mut rgb_combo)
.unwrap()
.with_rgba(&mut rgba_combo)
.unwrap();
gbrapf16_to(&src, &mut sink).unwrap();
}
assert_eq!(
rgba_combo, rgba_ref,
"Gbrapf16 Strategy A+ post-widen alpha-patch must equal standalone `with_rgba`"
);
let to_u8 = |v: f32| -> u8 { (v.clamp(0.0, 1.0) * 255.0 + 0.5) as u8 };
for i in 0..(w * h) {
assert_eq!(
rgba_combo[i * 4 + 3],
to_u8(intended_a[i].to_f32()),
"α slot idx {i}"
);
}
}
#[cfg(target_pointer_width = "32")]
#[test]
#[should_panic(expected = "overflows usize")]
fn gbr_float_dispatch_panics_on_width_overflow_gbrpf32_rgb() {
let bad_width = usize::MAX / 2 + 1;
let g = [0.0f32; 1];
let b = [0.0f32; 1];
let r = [0.0f32; 1];
let mut out = [0u8; 3];
crate::row::gbrpf32_to_rgb_row::<false>(&g, &b, &r, &mut out, bad_width, false);
}
#[cfg(target_pointer_width = "32")]
#[test]
#[should_panic(expected = "overflows usize")]
fn gbr_float_dispatch_panics_on_width_overflow_gbrpf32_rgba() {
let bad_width = usize::MAX / 2 + 1;
let g = [0.0f32; 1];
let b = [0.0f32; 1];
let r = [0.0f32; 1];
let mut out = [0u8; 4];
crate::row::gbrpf32_to_rgba_row::<false>(&g, &b, &r, &mut out, bad_width, false);
}
#[cfg(target_pointer_width = "32")]
#[test]
#[should_panic(expected = "overflows usize")]
fn gbr_float_dispatch_panics_on_width_overflow_gbrpf32_rgb_u16() {
let bad_width = usize::MAX / 2 + 1;
let g = [0.0f32; 1];
let b = [0.0f32; 1];
let r = [0.0f32; 1];
let mut out = [0u16; 3];
crate::row::gbrpf32_to_rgb_u16_row::<false>(&g, &b, &r, &mut out, bad_width, false);
}
#[cfg(target_pointer_width = "32")]
#[test]
#[should_panic(expected = "overflows usize")]
fn gbr_float_dispatch_panics_on_width_overflow_gbrpf32_rgba_u16() {
let bad_width = usize::MAX / 2 + 1;
let g = [0.0f32; 1];
let b = [0.0f32; 1];
let r = [0.0f32; 1];
let mut out = [0u16; 4];
crate::row::gbrpf32_to_rgba_u16_row::<false>(&g, &b, &r, &mut out, bad_width, false);
}
fn as_le_f32_buf(host: &[f32]) -> std::vec::Vec<f32> {
host
.iter()
.map(|v| f32::from_ne_bytes(v.to_le_bytes()))
.collect()
}
fn as_be_f32_buf(host: &[f32]) -> std::vec::Vec<f32> {
host
.iter()
.map(|v| f32::from_ne_bytes(v.to_be_bytes()))
.collect()
}
fn as_le_f16_buf(host: &[half::f16]) -> std::vec::Vec<half::f16> {
host
.iter()
.map(|v| {
let bits = v.to_bits();
let native_bits = u16::from_ne_bytes(bits.to_le_bytes());
half::f16::from_bits(native_bits)
})
.collect()
}
fn as_be_f16_buf(host: &[half::f16]) -> std::vec::Vec<half::f16> {
host
.iter()
.map(|v| {
let bits = v.to_bits();
let native_bits = u16::from_ne_bytes(bits.to_be_bytes());
half::f16::from_bits(native_bits)
})
.collect()
}
#[test]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrpf32_le_be_roundtrip_byte_identical() {
let w = 16usize;
let h = 4usize;
let intended: std::vec::Vec<f32> = (0..w * h)
.map(|i| {
let v = (i as f32) / (w * h) as f32;
match i % 4 {
0 => v,
1 => 1.0 - v,
2 => 0.5,
_ => 0.25,
}
})
.collect();
let g_le = as_le_f32_buf(&intended);
let b_le = as_le_f32_buf(&intended);
let r_le = as_le_f32_buf(&intended);
let g_be = as_be_f32_buf(&intended);
let b_be = as_be_f32_buf(&intended);
let r_be = as_be_f32_buf(&intended);
for use_simd in [false, true] {
let stride = w as u32;
let frame_le = Gbrpf32LeFrame::try_new(
&g_le, &b_le, &r_le, w as u32, h as u32, stride, stride, stride,
)
.unwrap();
let mut out_le = std::vec![0u8; w * h * 4];
let mut sink_le = MixedSinker::<Gbrpf32>::new(w, h)
.with_simd(use_simd)
.with_rgba(&mut out_le)
.unwrap();
gbrpf32_to(&frame_le, &mut sink_le).unwrap();
let frame_be = Gbrpf32BeFrame::try_new(
&g_be, &b_be, &r_be, w as u32, h as u32, stride, stride, stride,
)
.unwrap();
let mut out_be = std::vec![0u8; w * h * 4];
let mut sink_be = MixedSinker::<Gbrpf32<true>>::new(w, h)
.with_simd(use_simd)
.with_rgba(&mut out_be)
.unwrap();
gbrpf32_to_endian(&frame_be, &mut sink_be).unwrap();
assert_eq!(
out_le, out_be,
"Gbrpf32 LE/BE outputs diverge — `<const BE>` propagation broken (use_simd={use_simd})",
);
}
}
#[test]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrapf32_le_be_roundtrip_byte_identical() {
let w = 16usize;
let h = 4usize;
let intended: std::vec::Vec<f32> = (0..w * h)
.map(|i| {
let v = (i as f32) / (w * h) as f32;
match i % 5 {
0 => v,
1 => 1.0 - v,
2 => 0.5,
3 => 0.25,
_ => 0.75,
}
})
.collect();
let g_le = as_le_f32_buf(&intended);
let b_le = as_le_f32_buf(&intended);
let r_le = as_le_f32_buf(&intended);
let a_le = as_le_f32_buf(&intended);
let g_be = as_be_f32_buf(&intended);
let b_be = as_be_f32_buf(&intended);
let r_be = as_be_f32_buf(&intended);
let a_be = as_be_f32_buf(&intended);
for use_simd in [false, true] {
let stride = w as u32;
let frame_le = Gbrapf32LeFrame::try_new(
&g_le, &b_le, &r_le, &a_le, w as u32, h as u32, stride, stride, stride, stride,
)
.unwrap();
let mut out_le = std::vec![0u8; w * h * 4];
let mut sink_le = MixedSinker::<Gbrapf32>::new(w, h)
.with_simd(use_simd)
.with_rgba(&mut out_le)
.unwrap();
gbrapf32_to(&frame_le, &mut sink_le).unwrap();
let frame_be = Gbrapf32BeFrame::try_new(
&g_be, &b_be, &r_be, &a_be, w as u32, h as u32, stride, stride, stride, stride,
)
.unwrap();
let mut out_be = std::vec![0u8; w * h * 4];
let mut sink_be = MixedSinker::<Gbrapf32<true>>::new(w, h)
.with_simd(use_simd)
.with_rgba(&mut out_be)
.unwrap();
gbrapf32_to_endian(&frame_be, &mut sink_be).unwrap();
assert_eq!(
out_le, out_be,
"Gbrapf32 LE/BE outputs diverge — `<const BE>` propagation broken (use_simd={use_simd})",
);
}
}
#[test]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrpf16_le_be_roundtrip_byte_identical() {
let w = 16usize;
let h = 4usize;
let intended: std::vec::Vec<half::f16> = (0..w * h)
.map(|i| {
let v = (i as f32) / (w * h) as f32;
half::f16::from_f32(match i % 4 {
0 => v,
1 => 1.0 - v,
2 => 0.5,
_ => 0.25,
})
})
.collect();
let g_le = as_le_f16_buf(&intended);
let b_le = as_le_f16_buf(&intended);
let r_le = as_le_f16_buf(&intended);
let g_be = as_be_f16_buf(&intended);
let b_be = as_be_f16_buf(&intended);
let r_be = as_be_f16_buf(&intended);
for use_simd in [false, true] {
let stride = w as u32;
let frame_le = Gbrpf16LeFrame::try_new(
&g_le, &b_le, &r_le, w as u32, h as u32, stride, stride, stride,
)
.unwrap();
let mut out_le = std::vec![0u8; w * h * 4];
let mut sink_le = MixedSinker::<Gbrpf16>::new(w, h)
.with_simd(use_simd)
.with_rgba(&mut out_le)
.unwrap();
gbrpf16_to(&frame_le, &mut sink_le).unwrap();
let frame_be = Gbrpf16BeFrame::try_new(
&g_be, &b_be, &r_be, w as u32, h as u32, stride, stride, stride,
)
.unwrap();
let mut out_be = std::vec![0u8; w * h * 4];
let mut sink_be = MixedSinker::<Gbrpf16<true>>::new(w, h)
.with_simd(use_simd)
.with_rgba(&mut out_be)
.unwrap();
gbrpf16_to_endian(&frame_be, &mut sink_be).unwrap();
assert_eq!(
out_le, out_be,
"Gbrpf16 LE/BE outputs diverge — `<const BE>` propagation broken (use_simd={use_simd})",
);
}
}
#[test]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn gbrapf16_le_be_roundtrip_byte_identical() {
let w = 16usize;
let h = 4usize;
let intended: std::vec::Vec<half::f16> = (0..w * h)
.map(|i| {
let v = (i as f32) / (w * h) as f32;
half::f16::from_f32(match i % 5 {
0 => v,
1 => 1.0 - v,
2 => 0.5,
3 => 0.25,
_ => 0.75,
})
})
.collect();
let g_le = as_le_f16_buf(&intended);
let b_le = as_le_f16_buf(&intended);
let r_le = as_le_f16_buf(&intended);
let a_le = as_le_f16_buf(&intended);
let g_be = as_be_f16_buf(&intended);
let b_be = as_be_f16_buf(&intended);
let r_be = as_be_f16_buf(&intended);
let a_be = as_be_f16_buf(&intended);
for use_simd in [false, true] {
let stride = w as u32;
let frame_le = Gbrapf16LeFrame::try_new(
&g_le, &b_le, &r_le, &a_le, w as u32, h as u32, stride, stride, stride, stride,
)
.unwrap();
let mut out_le = std::vec![0u8; w * h * 4];
let mut sink_le = MixedSinker::<Gbrapf16>::new(w, h)
.with_simd(use_simd)
.with_rgba(&mut out_le)
.unwrap();
gbrapf16_to(&frame_le, &mut sink_le).unwrap();
let frame_be = Gbrapf16BeFrame::try_new(
&g_be, &b_be, &r_be, &a_be, w as u32, h as u32, stride, stride, stride, stride,
)
.unwrap();
let mut out_be = std::vec![0u8; w * h * 4];
let mut sink_be = MixedSinker::<Gbrapf16<true>>::new(w, h)
.with_simd(use_simd)
.with_rgba(&mut out_be)
.unwrap();
gbrapf16_to_endian(&frame_be, &mut sink_be).unwrap();
assert_eq!(
out_le, out_be,
"Gbrapf16 LE/BE outputs diverge — `<const BE>` propagation broken (use_simd={use_simd})",
);
}
}