#![allow(
clippy::excessive_precision,
clippy::unreadable_literal,
clippy::module_name_repetitions,
unused_parens,
clippy::wildcard_imports
)]
use zune_core::log::debug;
use zune_core::options::DecoderOptions;
use crate::decoder::IDCTPtr;
use crate::idct::scalar::{idct_int, idct_int_1x1};
#[cfg(feature = "x86")]
pub mod avx2;
#[cfg(feature = "neon")]
pub mod neon;
pub mod scalar;
#[allow(unused_variables)]
pub fn choose_idct_func(options: &DecoderOptions) -> IDCTPtr {
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[cfg(feature = "x86")]
{
if options.use_avx2() {
debug!("Using vector integer IDCT");
return |a: &mut [i32; 64], b: &mut [i16], c: usize| {
unsafe { avx2::idct_avx2(a,b,c) }
};
}
}
#[cfg(target_arch = "aarch64")]
#[cfg(feature = "neon")]
{
if options.use_neon() {
debug!("Using vector integer IDCT");
return |a: &mut [i32; 64], b: &mut [i16], c: usize| {
unsafe { neon::idct_neon(a,b,c) }
};
}
}
debug!("Using scalar integer IDCT");
return idct_int;
}
pub fn choose_idct_4x4_func(_options: &DecoderOptions) -> IDCTPtr {
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[cfg(feature = "x86")]
{
if _options.use_avx2() {
debug!("Using vector integer IDCT");
return |a: &mut [i32; 64], b: &mut [i16], c: usize| {
unsafe { avx2::idct_avx2_4x4(a,b,c) }
};
}
}
scalar::idct4x4
}
pub fn choose_idct_1x1_func(_: &DecoderOptions) -> IDCTPtr {
idct_int_1x1
}
#[cfg(test)]
#[allow(unreachable_code)]
#[allow(dead_code)]
mod tests {
use super::*;
#[test]
fn idct_test0() {
let stride = 8;
let mut coeff = [10; 64];
let mut coeff2 = [10; 64];
let mut output_scalar = [0; 64];
let mut output_vector = [0; 64];
let idct_func = choose_idct_func(&DecoderOptions::new_fast());
idct_func(&mut coeff, &mut output_vector, stride);
idct_int(&mut coeff2, &mut output_scalar, stride);
assert_eq!(output_scalar, output_vector, "IDCT and scalar do not match");
}
#[test]
fn do_idct_test1() {
let stride = 8;
let mut coeff = [14; 64];
let mut coeff2 = [14; 64];
let mut output_scalar = [0; 64];
let mut output_vector = [0; 64];
let idct_func = choose_idct_func(&DecoderOptions::new_fast());
idct_func(&mut coeff, &mut output_vector, stride);
idct_int(&mut coeff2, &mut output_scalar, stride);
assert_eq!(output_scalar, output_vector, "IDCT and scalar do not match");
}
#[test]
fn do_idct_test2() {
let stride = 8;
let mut coeff = [0; 64];
coeff[0] = 255;
coeff[63] = -256;
let mut coeff2 = coeff;
let mut output_scalar = [0; 64];
let mut output_vector = [0; 64];
let idct_func = choose_idct_func(&DecoderOptions::new_fast());
idct_func(&mut coeff, &mut output_vector, stride);
idct_int(&mut coeff2, &mut output_scalar, stride);
assert_eq!(output_scalar, output_vector, "IDCT and scalar do not match");
}
#[test]
fn do_idct_zeros() {
let stride = 8;
let mut coeff = [0; 64];
let mut coeff2 = [0; 64];
let mut output_scalar = [0; 64];
let mut output_vector = [0; 64];
let idct_func = choose_idct_func(&DecoderOptions::new_fast());
idct_func(&mut coeff, &mut output_vector, stride);
idct_int(&mut coeff2, &mut output_scalar, stride);
assert_eq!(output_scalar, output_vector, "IDCT and scalar do not match");
}
#[test]
fn idct_4x4() {
#[rustfmt::skip]
const A: [i32; 32] = [
-254, -7, 0, 0, 0, 0, 0, 0,
7, 0, -30, 32, 0, 0, 0, 0,
7, 0, -30, 32, 0, 0, 0, 0,
7, 0, -30, 32, 0, 0, 0, 0,
];
let v: Vec<IDCTPtr> = vec![
choose_idct_func(&DecoderOptions::new_safe()),
choose_idct_4x4_func(&DecoderOptions::new_safe()),
choose_idct_func(&DecoderOptions::new_fast()),
choose_idct_4x4_func(&DecoderOptions::new_fast()),
];
let dct_names = vec![
"safe idct",
"safe idct 4x4",
"fast idct",
"fast idct 4x4",
];
let mut color = vec![];
for idct in v {
let mut a = [0i32; 64];
a[..32].copy_from_slice(&A);
let mut b = [0i16; 64];
idct(&mut a, &mut b, 8);
color.push(b);
}
for (wnd, name) in color.windows(2).zip(&dct_names) {
let [a, b] = wnd else { unreachable!() };
assert_eq!(a, b, "{name}");
}
}
}