#![cfg(all(test, target_arch = "aarch64", not(feature = "c-ffi")))]
use crate::include::common::bitdepth::{BitDepth, BitDepth8, BitDepth16};
use crate::include::dav1d::picture::Rav1dPictureDataComponent;
use crate::src::levels::{self, TxClass, TxfmSize, TxfmType};
use crate::src::scan::dav1d_scans;
use crate::src::tables::dav1d_tx_type_class;
struct Rng(u64);
impl Rng {
fn next(&mut self) -> u64 {
let mut x = self.0;
x ^= x >> 12;
x ^= x << 25;
x ^= x >> 27;
self.0 = x;
x.wrapping_mul(0x2545_F491_4F6C_DD1D)
}
fn in_range(&mut self, lo: i32, hi: i32) -> i32 {
lo + (self.next() % ((hi - lo + 1) as u64)) as i32
}
}
fn log2(n: usize) -> u32 {
n.trailing_zeros()
}
fn reachable_positions(tx: TxfmSize, tx_type: TxfmType, eob: usize) -> Vec<usize> {
let (w, h) = tx.to_wh();
let (sw, sh) = (w.min(32), h.min(32));
match dav1d_tx_type_class[tx_type as usize] {
TxClass::TwoD => {
let scan = dav1d_scans[tx as usize];
(0..=eob).map(|i| scan[i].get() as usize).collect()
}
TxClass::H => (0..=eob).collect(),
TxClass::V => (0..=eob)
.map(|i| (i & (sw - 1)) * sh + (i >> log2(sw)))
.collect(),
}
}
fn run_cell(
tx: TxfmSize,
tx_type: TxfmType,
eob: i32,
coeff: &[i16],
pixels: &[u8],
stride: usize,
) -> (Vec<u8>, Vec<u8>, bool) {
let bd = BitDepth8::new(());
let run = |simd: bool| -> (Vec<u8>, bool) {
let mut px = pixels.to_vec();
let mut cf = coeff.to_vec();
let mut out = vec![0u8; px.len()];
let handled = {
let comp = Rav1dPictureDataComponent::wrap_buf::<BitDepth8>(&mut px, stride);
let mut dst = crate::src::owned_recon::ReconDst::Pic(comp.with_offset::<BitDepth8>());
let handled = if simd {
crate::src::safe_simd::itx_arm::itxfm_add_dispatch::<BitDepth8>(
tx as usize,
tx_type as usize,
&mut dst,
&mut cf,
eob,
bd,
)
} else {
crate::src::itx::itxfm_add_scalar_fallback::<BitDepth8>(
tx as usize,
tx_type,
&mut dst,
&mut cf,
eob,
bd,
);
true
};
comp.copy_pixels_to::<BitDepth8>(&mut out);
handled
};
(out, handled)
};
let (neon, handled) = run(true);
let (scalar, _) = run(false);
(neon, scalar, handled)
}
#[derive(Default)]
struct Report {
cells: usize,
live: usize,
bad: Vec<String>,
first: Option<String>,
}
impl Report {
fn record(&mut self, label: &str, live: bool, ok: bool, detail: impl FnOnce() -> String) {
self.cells += 1;
if live {
self.live += 1;
}
if !ok {
if self.first.is_none() {
self.first = Some(format!("{label}: {}", detail()));
}
if !self.bad.iter().any(|b| b == label) {
self.bad.push(label.to_string());
}
}
}
fn finish(self, what: &str, min_live: usize) {
assert!(
self.cells >= min_live,
"{what}: only {} parameter cells ran (expected >= {min_live}) — \
the sweep is not reaching the kernels",
self.cells
);
assert_eq!(
self.live,
self.cells,
"{what}: {} of {} cells did NOT take the NEON path. \
`itxfm_add_dispatch` returned false, so those cells compared the \
scalar reference against itself and proved nothing.",
self.cells - self.live,
self.cells
);
assert!(
self.bad.is_empty(),
"{what}: {} of {} parameter cells diverge from the scalar reference.\n \
first: {}\n cells: {:?}",
self.bad.len(),
self.cells,
self.first.unwrap_or_default(),
self.bad
);
}
}
fn wired_cells() -> Vec<(TxfmSize, TxfmType)> {
use TxfmSize::*;
let all16: [TxfmType; 16] = [
levels::DCT_DCT,
levels::ADST_DCT,
levels::DCT_ADST,
levels::ADST_ADST,
levels::FLIPADST_DCT,
levels::DCT_FLIPADST,
levels::FLIPADST_FLIPADST,
levels::ADST_FLIPADST,
levels::FLIPADST_ADST,
levels::IDTX,
levels::V_DCT,
levels::H_DCT,
levels::V_ADST,
levels::H_ADST,
levels::V_FLIPADST,
levels::H_FLIPADST,
];
let mut out = Vec::new();
for &sz in &[S4x4, S8x8, S16x16] {
for &t in &all16 {
out.push((sz, t));
}
}
for &sz in &[S32x32, R8x32, R32x8, R16x32, R32x16] {
out.push((sz, levels::DCT_DCT));
out.push((sz, levels::IDTX));
}
for &sz in &[S64x64, R64x32, R32x64, R16x64, R64x16] {
out.push((sz, levels::DCT_DCT));
}
out
}
fn eob_sweep(n: usize) -> Vec<i32> {
let mut v: Vec<i32> = vec![0, 1, 2, 3, 7, 8, 9, 15, 16, 17];
for &t in &[
29usize, 32, 35, 36, 37, 43, 64, 107, 136, 151, 171, 256, 279, 300, 512, 1024,
] {
v.push(t as i32 - 1);
v.push(t as i32);
}
v.push(n as i32 - 1);
v.retain(|&e| e >= 0 && (e as usize) < n);
v.sort_unstable();
v.dedup();
v
}
fn sweep(scale: i32, seed: u64, what: &str) {
sweep_with(scale, seed, what, false)
}
fn sweep_with(scale: i32, seed: u64, what: &str, every_eob: bool) {
let _lock = crate::src::safe_simd::token_test_lock();
let mut rep = Report::default();
for (tx, tx_type) in wired_cells() {
let (w, h) = tx.to_wh();
let (sw, sh) = (w.min(32), h.min(32));
let n = sw * sh;
let stride = (w + 16).next_multiple_of(16);
let mut rng = Rng(seed ^ ((tx as u64) << 40) ^ ((tx_type as u64) << 32));
let pixels: Vec<u8> = (0..stride * h)
.map(|_| rng.in_range(0, 255) as u8)
.collect();
let eobs: Vec<i32> = if every_eob {
(0..n as i32).collect()
} else {
eob_sweep(n)
};
for eob in eobs {
let mut coeff = vec![0i16; 32 * 32];
for pos in reachable_positions(tx, tx_type, eob as usize) {
let mut c = rng.in_range(-scale, scale);
if c == 0 {
c = 1;
}
coeff[pos] = c as i16;
}
let (neon, scalar, live) = run_cell(tx, tx_type, eob, &coeff, &pixels, stride);
let bad = (0..h)
.flat_map(|y| (0..w).map(move |x| (x, y)))
.find(|&(x, y)| neon[y * stride + x] != scalar[y * stride + x]);
rep.record(
&format!("{w}x{h} type={tx_type} eob={eob}"),
live,
bad.is_none(),
|| {
let (x, y) = bad.unwrap();
format!(
"at ({x},{y}) neon={} scalar={}",
neon[y * stride + x],
scalar[y * stride + x]
)
},
);
}
}
rep.finish(what, 1400);
}
#[test]
fn itx_8bpc_matches_scalar_small_coeffs() {
sweep(
64,
0x1234_5678_9ABC_DEF0,
"aarch64 8bpc itx (|coeff| <= 64)",
);
}
#[test]
fn itx_8bpc_matches_scalar_medium_coeffs() {
sweep(
1024,
0x0BAD_C0DE_1234_5678,
"aarch64 8bpc itx (|coeff| <= 1024)",
);
}
#[test]
fn itx_8bpc_every_eob_small_coeffs() {
sweep_with(
48,
0xFEED_FACE_0000_0001,
"aarch64 8bpc itx, every eob (|coeff| <= 48)",
true,
);
}
fn run_cell_16(
tx: TxfmSize,
tx_type: TxfmType,
eob: i32,
coeff: &[i32],
pixels: &[u16],
stride: usize,
bitdepth_max: u16,
) -> (Vec<u16>, Vec<u16>, bool) {
let bd = BitDepth16::new(bitdepth_max);
let run = |simd: bool| -> (Vec<u16>, bool) {
let mut px = pixels.to_vec();
let mut cf = coeff.to_vec();
let mut out = vec![0u16; px.len()];
let handled = {
let comp = Rav1dPictureDataComponent::wrap_buf::<BitDepth16>(&mut px, stride);
let mut dst = crate::src::owned_recon::ReconDst::Pic(comp.with_offset::<BitDepth16>());
let handled = if simd {
crate::src::safe_simd::itx_arm::itxfm_add_dispatch::<BitDepth16>(
tx as usize,
tx_type as usize,
&mut dst,
&mut cf,
eob,
bd,
)
} else {
crate::src::itx::itxfm_add_scalar_fallback::<BitDepth16>(
tx as usize,
tx_type,
&mut dst,
&mut cf,
eob,
bd,
);
true
};
comp.copy_pixels_to::<BitDepth16>(&mut out);
handled
};
(out, handled)
};
let (neon, handled) = run(true);
let (scalar, _) = run(false);
(neon, scalar, handled)
}
fn wired_cells_16() -> Vec<(TxfmSize, TxfmType)> {
use TxfmSize::*;
let all16: [TxfmType; 16] = [
levels::DCT_DCT,
levels::ADST_DCT,
levels::DCT_ADST,
levels::ADST_ADST,
levels::FLIPADST_DCT,
levels::DCT_FLIPADST,
levels::FLIPADST_FLIPADST,
levels::ADST_FLIPADST,
levels::FLIPADST_ADST,
levels::IDTX,
levels::V_DCT,
levels::H_DCT,
levels::V_ADST,
levels::H_ADST,
levels::V_FLIPADST,
levels::H_FLIPADST,
];
let mut out = Vec::new();
for &sz in &[S4x4, S8x8, S16x16, R4x8, R8x4, R4x16, R16x4, R8x16, R16x8] {
for &t in &all16 {
out.push((sz, t));
}
}
out
}
fn sweep16(scale: i32, seed: u64, bitdepth_max: u16, what: &str, every_eob: bool) {
let _lock = crate::src::safe_simd::token_test_lock();
let mut rep = Report::default();
for (tx, tx_type) in wired_cells_16() {
let (w, h) = tx.to_wh();
let n = w * h;
let stride = (w + 16).next_multiple_of(16);
let mut rng = Rng(seed ^ ((tx as u64) << 40) ^ ((tx_type as u64) << 32));
let pixels: Vec<u16> = (0..stride * h)
.map(|_| rng.in_range(0, bitdepth_max as i32) as u16)
.collect();
let eobs: Vec<i32> = if every_eob {
(0..n as i32).collect()
} else {
eob_sweep(n)
};
for eob in eobs {
let mut coeff = vec![0i32; 32 * 32];
for pos in reachable_positions(tx, tx_type, eob as usize) {
let mut c = rng.in_range(-scale, scale);
if c == 0 {
c = 1;
}
coeff[pos] = c;
}
let (neon, scalar, live) =
run_cell_16(tx, tx_type, eob, &coeff, &pixels, stride, bitdepth_max);
let bad = (0..h)
.flat_map(|y| (0..w).map(move |x| (x, y)))
.find(|&(x, y)| neon[y * stride + x] != scalar[y * stride + x]);
rep.record(
&format!("{w}x{h} type={tx_type} eob={eob}"),
live,
bad.is_none(),
|| {
let (x, y) = bad.unwrap();
format!(
"at ({x},{y}) neon={} scalar={}",
neon[y * stride + x],
scalar[y * stride + x]
)
},
);
}
}
rep.finish(what, 1400);
}
#[test]
fn itx_10bpc_matches_scalar_small_coeffs() {
sweep16(
64,
0x1234_5678_9ABC_DEF0,
1023,
"aarch64 10bpc itx (|coeff| <= 64)",
false,
);
}
#[test]
fn itx_10bpc_matches_scalar_large_coeffs() {
sweep16(
1 << 14,
0x0BAD_C0DE_1234_5678,
1023,
"aarch64 10bpc itx (|coeff| <= 16384)",
false,
);
}
#[test]
fn itx_12bpc_matches_scalar_large_coeffs() {
sweep16(
1 << 16,
0xC0FF_EE00_1234_5678,
4095,
"aarch64 12bpc itx (|coeff| <= 65536)",
false,
);
}
#[test]
fn itx_10bpc_every_eob_small_coeffs() {
sweep16(
48,
0xFEED_FACE_0000_0002,
1023,
"aarch64 10bpc itx, every eob (|coeff| <= 48)",
true,
);
}
#[test]
fn reachable_positions_track_the_transform_class() {
assert_eq!(dav1d_tx_type_class[levels::H_DCT as usize], TxClass::H);
let p = reachable_positions(TxfmSize::S16x16, levels::H_DCT, 8);
assert_eq!(p, (0..=8).collect::<Vec<_>>());
assert!(
p.iter().any(|&rc| rc % 16 >= 8),
"eob=8 must reach row >= 8"
);
assert_eq!(dav1d_tx_type_class[levels::V_DCT as usize], TxClass::V);
let p = reachable_positions(TxfmSize::S16x16, levels::V_DCT, 8);
assert!(
p.iter().all(|&rc| rc % 16 == 0),
"class V at eob=8 stays in coefficient row 0"
);
assert_eq!(dav1d_tx_type_class[levels::DCT_DCT as usize], TxClass::TwoD);
let p = reachable_positions(TxfmSize::S16x16, levels::DCT_DCT, 35);
assert!(
p.iter().all(|&rc| rc % 16 < 8),
"the 2D scan's first 36 positions are what makes eob_half = 36 sound"
);
}