use super::*;
fn pseudo_random_rgba(width: usize) -> std::vec::Vec<u8> {
let n = width * 4;
let mut out = std::vec::Vec::with_capacity(n);
let mut state: u32 = 0x6CCD_5C7B;
for _ in 0..n {
state = state.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
out.push((state >> 8) as u8);
}
out
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn rgba_to_rgb_neon_matches_scalar_widths() {
for w in [1usize, 7, 15, 16, 17, 31, 32, 33, 1920, 1921] {
let input = pseudo_random_rgba(w);
let mut out_scalar = std::vec![0u8; w * 3];
let mut out_neon = std::vec![0u8; w * 3];
scalar::rgba_to_rgb_row(&input, &mut out_scalar, w);
unsafe {
rgba_to_rgb_row(&input, &mut out_neon, w);
}
assert_eq!(out_scalar, out_neon, "width {w}");
for x in 0..w {
assert_eq!(out_neon[x * 3], input[x * 4], "R width {w} px {x}");
assert_eq!(out_neon[x * 3 + 1], input[x * 4 + 1], "G width {w} px {x}");
assert_eq!(out_neon[x * 3 + 2], input[x * 4 + 2], "B width {w} px {x}");
}
}
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn bgra_to_rgba_neon_matches_scalar_widths() {
for w in [1usize, 7, 15, 16, 17, 31, 32, 33, 1920, 1921] {
let input = pseudo_random_rgba(w);
let mut out_scalar = std::vec![0u8; w * 4];
let mut out_neon = std::vec![0u8; w * 4];
scalar::bgra_to_rgba_row(&input, &mut out_scalar, w);
unsafe {
bgra_to_rgba_row(&input, &mut out_neon, w);
}
assert_eq!(out_scalar, out_neon, "width {w}");
for x in 0..w {
assert_eq!(out_neon[x * 4], input[x * 4 + 2], "R width {w} px {x}");
assert_eq!(out_neon[x * 4 + 1], input[x * 4 + 1], "G width {w} px {x}");
assert_eq!(out_neon[x * 4 + 2], input[x * 4], "B width {w} px {x}");
assert_eq!(out_neon[x * 4 + 3], input[x * 4 + 3], "A width {w} px {x}");
}
}
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn bgra_to_rgb_neon_matches_scalar_widths() {
for w in [1usize, 7, 15, 16, 17, 31, 32, 33, 1920, 1921] {
let input = pseudo_random_rgba(w);
let mut out_scalar = std::vec![0u8; w * 3];
let mut out_neon = std::vec![0u8; w * 3];
scalar::bgra_to_rgb_row(&input, &mut out_scalar, w);
unsafe {
bgra_to_rgb_row(&input, &mut out_neon, w);
}
assert_eq!(out_scalar, out_neon, "width {w}");
for x in 0..w {
assert_eq!(out_neon[x * 3], input[x * 4 + 2], "R width {w} px {x}");
assert_eq!(out_neon[x * 3 + 1], input[x * 4 + 1], "G width {w} px {x}");
assert_eq!(out_neon[x * 3 + 2], input[x * 4], "B width {w} px {x}");
}
}
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn argb_to_rgb_neon_matches_scalar_widths() {
for w in [1usize, 7, 15, 16, 17, 31, 32, 33, 1920, 1921] {
let input = pseudo_random_rgba(w);
let mut out_scalar = std::vec![0u8; w * 3];
let mut out_neon = std::vec![0u8; w * 3];
scalar::argb_to_rgb_row(&input, &mut out_scalar, w);
unsafe {
argb_to_rgb_row(&input, &mut out_neon, w);
}
assert_eq!(out_scalar, out_neon, "width {w}");
for x in 0..w {
assert_eq!(out_neon[x * 3], input[x * 4 + 1], "R width {w} px {x}");
assert_eq!(out_neon[x * 3 + 1], input[x * 4 + 2], "G width {w} px {x}");
assert_eq!(out_neon[x * 3 + 2], input[x * 4 + 3], "B width {w} px {x}");
}
}
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn abgr_to_rgb_neon_matches_scalar_widths() {
for w in [1usize, 7, 15, 16, 17, 31, 32, 33, 1920, 1921] {
let input = pseudo_random_rgba(w);
let mut out_scalar = std::vec![0u8; w * 3];
let mut out_neon = std::vec![0u8; w * 3];
scalar::abgr_to_rgb_row(&input, &mut out_scalar, w);
unsafe {
abgr_to_rgb_row(&input, &mut out_neon, w);
}
assert_eq!(out_scalar, out_neon, "width {w}");
for x in 0..w {
assert_eq!(out_neon[x * 3], input[x * 4 + 3], "R width {w} px {x}");
assert_eq!(out_neon[x * 3 + 1], input[x * 4 + 2], "G width {w} px {x}");
assert_eq!(out_neon[x * 3 + 2], input[x * 4 + 1], "B width {w} px {x}");
}
}
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn argb_to_rgba_neon_matches_scalar_widths() {
for w in [1usize, 7, 15, 16, 17, 31, 32, 33, 1920, 1921] {
let input = pseudo_random_rgba(w);
let mut out_scalar = std::vec![0u8; w * 4];
let mut out_neon = std::vec![0u8; w * 4];
scalar::argb_to_rgba_row(&input, &mut out_scalar, w);
unsafe {
argb_to_rgba_row(&input, &mut out_neon, w);
}
assert_eq!(out_scalar, out_neon, "width {w}");
for x in 0..w {
assert_eq!(out_neon[x * 4], input[x * 4 + 1], "R width {w} px {x}");
assert_eq!(out_neon[x * 4 + 1], input[x * 4 + 2], "G width {w} px {x}");
assert_eq!(out_neon[x * 4 + 2], input[x * 4 + 3], "B width {w} px {x}");
assert_eq!(out_neon[x * 4 + 3], input[x * 4], "A width {w} px {x}");
}
}
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn abgr_to_rgba_neon_matches_scalar_widths() {
for w in [1usize, 7, 15, 16, 17, 31, 32, 33, 1920, 1921] {
let input = pseudo_random_rgba(w);
let mut out_scalar = std::vec![0u8; w * 4];
let mut out_neon = std::vec![0u8; w * 4];
scalar::abgr_to_rgba_row(&input, &mut out_scalar, w);
unsafe {
abgr_to_rgba_row(&input, &mut out_neon, w);
}
assert_eq!(out_scalar, out_neon, "width {w}");
for x in 0..w {
assert_eq!(out_neon[x * 4], input[x * 4 + 3], "R width {w} px {x}");
assert_eq!(out_neon[x * 4 + 1], input[x * 4 + 2], "G width {w} px {x}");
assert_eq!(out_neon[x * 4 + 2], input[x * 4 + 1], "B width {w} px {x}");
assert_eq!(out_neon[x * 4 + 3], input[x * 4], "A width {w} px {x}");
}
}
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn xrgb_to_rgba_neon_matches_scalar_widths() {
for w in [1usize, 7, 15, 16, 17, 31, 32, 33, 1920, 1921] {
let input = pseudo_random_rgba(w);
let mut out_scalar = std::vec![0u8; w * 4];
let mut out_neon = std::vec![0u8; w * 4];
scalar::xrgb_to_rgba_row(&input, &mut out_scalar, w);
unsafe {
xrgb_to_rgba_row(&input, &mut out_neon, w);
}
assert_eq!(out_scalar, out_neon, "width {w}");
for x in 0..w {
assert_eq!(out_neon[x * 4], input[x * 4 + 1], "R width {w} px {x}");
assert_eq!(out_neon[x * 4 + 1], input[x * 4 + 2], "G width {w} px {x}");
assert_eq!(out_neon[x * 4 + 2], input[x * 4 + 3], "B width {w} px {x}");
assert_eq!(out_neon[x * 4 + 3], 0xFF, "A width {w} px {x}");
}
}
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn rgbx_to_rgba_neon_matches_scalar_widths() {
for w in [1usize, 7, 15, 16, 17, 31, 32, 33, 1920, 1921] {
let input = pseudo_random_rgba(w);
let mut out_scalar = std::vec![0u8; w * 4];
let mut out_neon = std::vec![0u8; w * 4];
scalar::rgbx_to_rgba_row(&input, &mut out_scalar, w);
unsafe {
rgbx_to_rgba_row(&input, &mut out_neon, w);
}
assert_eq!(out_scalar, out_neon, "width {w}");
for x in 0..w {
assert_eq!(out_neon[x * 4], input[x * 4], "R width {w} px {x}");
assert_eq!(out_neon[x * 4 + 1], input[x * 4 + 1], "G width {w} px {x}");
assert_eq!(out_neon[x * 4 + 2], input[x * 4 + 2], "B width {w} px {x}");
assert_eq!(out_neon[x * 4 + 3], 0xFF, "A width {w} px {x}");
}
}
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn xbgr_to_rgba_neon_matches_scalar_widths() {
for w in [1usize, 7, 15, 16, 17, 31, 32, 33, 1920, 1921] {
let input = pseudo_random_rgba(w);
let mut out_scalar = std::vec![0u8; w * 4];
let mut out_neon = std::vec![0u8; w * 4];
scalar::xbgr_to_rgba_row(&input, &mut out_scalar, w);
unsafe {
xbgr_to_rgba_row(&input, &mut out_neon, w);
}
assert_eq!(out_scalar, out_neon, "width {w}");
for x in 0..w {
assert_eq!(out_neon[x * 4], input[x * 4 + 3], "R width {w} px {x}");
assert_eq!(out_neon[x * 4 + 1], input[x * 4 + 2], "G width {w} px {x}");
assert_eq!(out_neon[x * 4 + 2], input[x * 4 + 1], "B width {w} px {x}");
assert_eq!(out_neon[x * 4 + 3], 0xFF, "A width {w} px {x}");
}
}
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn bgrx_to_rgba_neon_matches_scalar_widths() {
for w in [1usize, 7, 15, 16, 17, 31, 32, 33, 1920, 1921] {
let input = pseudo_random_rgba(w);
let mut out_scalar = std::vec![0u8; w * 4];
let mut out_neon = std::vec![0u8; w * 4];
scalar::bgrx_to_rgba_row(&input, &mut out_scalar, w);
unsafe {
bgrx_to_rgba_row(&input, &mut out_neon, w);
}
assert_eq!(out_scalar, out_neon, "width {w}");
for x in 0..w {
assert_eq!(out_neon[x * 4], input[x * 4 + 2], "R width {w} px {x}");
assert_eq!(out_neon[x * 4 + 1], input[x * 4 + 1], "G width {w} px {x}");
assert_eq!(out_neon[x * 4 + 2], input[x * 4], "B width {w} px {x}");
assert_eq!(out_neon[x * 4 + 3], 0xFF, "A width {w} px {x}");
}
}
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn x2rgb10_to_rgb_neon_matches_scalar_widths() {
for w in [1usize, 7, 15, 16, 17, 31, 32, 33, 1920, 1921] {
let input = pseudo_random_rgba(w);
let mut out_scalar = std::vec![0u8; w * 3];
let mut out_neon = std::vec![0u8; w * 3];
scalar::x2rgb10_to_rgb_row::<false>(&input, &mut out_scalar, w);
unsafe {
x2rgb10_to_rgb_row::<false>(&input, &mut out_neon, w);
}
assert_eq!(out_scalar, out_neon, "width {w}");
}
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn x2rgb10_to_rgba_neon_matches_scalar_widths() {
for w in [1usize, 7, 15, 16, 17, 31, 32, 33, 1920, 1921] {
let input = pseudo_random_rgba(w);
let mut out_scalar = std::vec![0u8; w * 4];
let mut out_neon = std::vec![0u8; w * 4];
scalar::x2rgb10_to_rgba_row::<false>(&input, &mut out_scalar, w);
unsafe {
x2rgb10_to_rgba_row::<false>(&input, &mut out_neon, w);
}
assert_eq!(out_scalar, out_neon, "width {w}");
}
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn x2rgb10_to_rgb_u16_neon_matches_scalar_widths() {
for w in [1usize, 7, 8, 9, 15, 16, 17, 31, 32, 33, 1920, 1921] {
let input = pseudo_random_rgba(w);
let mut out_scalar = std::vec![0u16; w * 3];
let mut out_neon = std::vec![0u16; w * 3];
scalar::x2rgb10_to_rgb_u16_row::<false>(&input, &mut out_scalar, w);
unsafe {
x2rgb10_to_rgb_u16_row::<false>(&input, &mut out_neon, w);
}
assert_eq!(out_scalar, out_neon, "width {w}");
}
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn x2bgr10_to_rgb_neon_matches_scalar_widths() {
for w in [1usize, 7, 15, 16, 17, 31, 32, 33, 1920, 1921] {
let input = pseudo_random_rgba(w);
let mut out_scalar = std::vec![0u8; w * 3];
let mut out_neon = std::vec![0u8; w * 3];
scalar::x2bgr10_to_rgb_row::<false>(&input, &mut out_scalar, w);
unsafe {
x2bgr10_to_rgb_row::<false>(&input, &mut out_neon, w);
}
assert_eq!(out_scalar, out_neon, "width {w}");
}
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn x2bgr10_to_rgba_neon_matches_scalar_widths() {
for w in [1usize, 7, 15, 16, 17, 31, 32, 33, 1920, 1921] {
let input = pseudo_random_rgba(w);
let mut out_scalar = std::vec![0u8; w * 4];
let mut out_neon = std::vec![0u8; w * 4];
scalar::x2bgr10_to_rgba_row::<false>(&input, &mut out_scalar, w);
unsafe {
x2bgr10_to_rgba_row::<false>(&input, &mut out_neon, w);
}
assert_eq!(out_scalar, out_neon, "width {w}");
}
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn x2bgr10_to_rgb_u16_neon_matches_scalar_widths() {
for w in [1usize, 7, 8, 9, 15, 16, 17, 31, 32, 33, 1920, 1921] {
let input = pseudo_random_rgba(w);
let mut out_scalar = std::vec![0u16; w * 3];
let mut out_neon = std::vec![0u16; w * 3];
scalar::x2bgr10_to_rgb_u16_row::<false>(&input, &mut out_scalar, w);
unsafe {
x2bgr10_to_rgb_u16_row::<false>(&input, &mut out_neon, w);
}
assert_eq!(out_scalar, out_neon, "width {w}");
}
}
fn pseudo_random_x2_intended(width: usize, seed: u32) -> std::vec::Vec<u32> {
let mut state = seed;
(0..width)
.map(|_| {
state = state.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
state
})
.collect()
}
fn make_le_be_pair_x2(intended: &[u32]) -> (std::vec::Vec<u8>, std::vec::Vec<u8>) {
let le_bytes: std::vec::Vec<u8> = intended.iter().flat_map(|v| v.to_le_bytes()).collect();
let be_bytes: std::vec::Vec<u8> = intended.iter().flat_map(|v| v.to_be_bytes()).collect();
(le_bytes, be_bytes)
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn neon_x2rgb10_be_le_simd_parity_width33() {
let intended = pseudo_random_x2_intended(33, 0xC0DE_BEEF);
let (le, be) = make_le_be_pair_x2(&intended);
let mut out_le = std::vec![0u8; 33 * 3];
let mut out_be = std::vec![0u8; 33 * 3];
unsafe {
x2rgb10_to_rgb_row::<false>(&le, &mut out_le, 33);
x2rgb10_to_rgb_row::<true>(&be, &mut out_be, 33);
}
assert_eq!(out_le, out_be, "x2rgb10→rgb SIMD BE/LE parity");
let mut out_le = std::vec![0u8; 33 * 4];
let mut out_be = std::vec![0u8; 33 * 4];
unsafe {
x2rgb10_to_rgba_row::<false>(&le, &mut out_le, 33);
x2rgb10_to_rgba_row::<true>(&be, &mut out_be, 33);
}
assert_eq!(out_le, out_be, "x2rgb10→rgba SIMD BE/LE parity");
let mut out_le = std::vec![0u16; 33 * 3];
let mut out_be = std::vec![0u16; 33 * 3];
unsafe {
x2rgb10_to_rgb_u16_row::<false>(&le, &mut out_le, 33);
x2rgb10_to_rgb_u16_row::<true>(&be, &mut out_be, 33);
}
assert_eq!(out_le, out_be, "x2rgb10→rgb_u16 SIMD BE/LE parity");
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn neon_x2bgr10_be_le_simd_parity_width33() {
let intended = pseudo_random_x2_intended(33, 0xFEED_FACE);
let (le, be) = make_le_be_pair_x2(&intended);
let mut out_le = std::vec![0u8; 33 * 3];
let mut out_be = std::vec![0u8; 33 * 3];
unsafe {
x2bgr10_to_rgb_row::<false>(&le, &mut out_le, 33);
x2bgr10_to_rgb_row::<true>(&be, &mut out_be, 33);
}
assert_eq!(out_le, out_be, "x2bgr10→rgb SIMD BE/LE parity");
let mut out_le = std::vec![0u8; 33 * 4];
let mut out_be = std::vec![0u8; 33 * 4];
unsafe {
x2bgr10_to_rgba_row::<false>(&le, &mut out_le, 33);
x2bgr10_to_rgba_row::<true>(&be, &mut out_be, 33);
}
assert_eq!(out_le, out_be, "x2bgr10→rgba SIMD BE/LE parity");
let mut out_le = std::vec![0u16; 33 * 3];
let mut out_be = std::vec![0u16; 33 * 3];
unsafe {
x2bgr10_to_rgb_u16_row::<false>(&le, &mut out_le, 33);
x2bgr10_to_rgb_u16_row::<true>(&be, &mut out_be, 33);
}
assert_eq!(out_le, out_be, "x2bgr10→rgb_u16 SIMD BE/LE parity");
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn neon_x2rgb10_be_simd_matches_scalar() {
for w in [1usize, 7, 15, 16, 17, 31, 32, 33, 1920, 1921] {
let input = pseudo_random_rgba(w);
let mut s_rgb = std::vec![0u8; w * 3];
let mut n_rgb = std::vec![0u8; w * 3];
scalar::x2rgb10_to_rgb_row::<true>(&input, &mut s_rgb, w);
unsafe {
x2rgb10_to_rgb_row::<true>(&input, &mut n_rgb, w);
}
assert_eq!(s_rgb, n_rgb, "NEON x2rgb10_to_rgb<BE> diverges (width={w})");
let mut s_rgba = std::vec![0u8; w * 4];
let mut n_rgba = std::vec![0u8; w * 4];
scalar::x2rgb10_to_rgba_row::<true>(&input, &mut s_rgba, w);
unsafe {
x2rgb10_to_rgba_row::<true>(&input, &mut n_rgba, w);
}
assert_eq!(
s_rgba, n_rgba,
"NEON x2rgb10_to_rgba<BE> diverges (width={w})"
);
let mut s_u16 = std::vec![0u16; w * 3];
let mut n_u16 = std::vec![0u16; w * 3];
scalar::x2rgb10_to_rgb_u16_row::<true>(&input, &mut s_u16, w);
unsafe {
x2rgb10_to_rgb_u16_row::<true>(&input, &mut n_u16, w);
}
assert_eq!(
s_u16, n_u16,
"NEON x2rgb10_to_rgb_u16<BE> diverges (width={w})"
);
}
}
#[test]
#[cfg_attr(miri, ignore = "NEON SIMD intrinsics unsupported by Miri")]
fn neon_x2bgr10_be_simd_matches_scalar() {
for w in [1usize, 7, 15, 16, 17, 31, 32, 33, 1920, 1921] {
let input = pseudo_random_rgba(w);
let mut s_rgb = std::vec![0u8; w * 3];
let mut n_rgb = std::vec![0u8; w * 3];
scalar::x2bgr10_to_rgb_row::<true>(&input, &mut s_rgb, w);
unsafe {
x2bgr10_to_rgb_row::<true>(&input, &mut n_rgb, w);
}
assert_eq!(s_rgb, n_rgb, "NEON x2bgr10_to_rgb<BE> diverges (width={w})");
let mut s_rgba = std::vec![0u8; w * 4];
let mut n_rgba = std::vec![0u8; w * 4];
scalar::x2bgr10_to_rgba_row::<true>(&input, &mut s_rgba, w);
unsafe {
x2bgr10_to_rgba_row::<true>(&input, &mut n_rgba, w);
}
assert_eq!(
s_rgba, n_rgba,
"NEON x2bgr10_to_rgba<BE> diverges (width={w})"
);
let mut s_u16 = std::vec![0u16; w * 3];
let mut n_u16 = std::vec![0u16; w * 3];
scalar::x2bgr10_to_rgb_u16_row::<true>(&input, &mut s_u16, w);
unsafe {
x2bgr10_to_rgb_u16_row::<true>(&input, &mut n_u16, w);
}
assert_eq!(
s_u16, n_u16,
"NEON x2bgr10_to_rgb_u16<BE> diverges (width={w})"
);
}
}