use crate::simd::traits::SimdOpsExt;
pub struct TransformSimd<S> {
simd: S,
}
impl<S: SimdOpsExt> TransformSimd<S> {
#[inline]
pub const fn new(simd: S) -> Self {
Self { simd }
}
pub fn forward_dct_4x4(&self, input: &[i16; 16], output: &mut [i16; 16]) {
use crate::simd::types::I16x8;
let mut rows = [I16x8::zero(); 4];
for i in 0..4 {
for j in 0..4 {
rows[i][j] = input[i * 4 + j];
}
}
self.dct_4_1d(&mut rows);
let rows = self.simd.transpose_4x4_i16(&rows);
let mut cols = rows;
self.dct_4_1d(&mut cols);
let result = self.simd.transpose_4x4_i16(&cols);
for i in 0..4 {
for j in 0..4 {
output[i * 4 + j] = result[i][j];
}
}
}
pub fn inverse_dct_4x4(&self, input: &[i16; 16], output: &mut [i16; 16]) {
use crate::simd::types::I16x8;
let mut rows = [I16x8::zero(); 4];
for i in 0..4 {
for j in 0..4 {
rows[i][j] = input[i * 4 + j];
}
}
self.idct_4_1d(&mut rows);
let rows = self.simd.transpose_4x4_i16(&rows);
let mut cols = rows;
self.idct_4_1d(&mut cols);
let result = self.simd.transpose_4x4_i16(&cols);
for i in 0..4 {
for j in 0..4 {
output[i * 4 + j] = result[i][j];
}
}
}
pub fn forward_dct_8x8(&self, input: &[i16; 64], output: &mut [i16; 64]) {
use crate::simd::types::I16x8;
let mut rows = [I16x8::zero(); 8];
for i in 0..8 {
for j in 0..8 {
rows[i][j] = input[i * 8 + j];
}
}
self.dct_8_1d(&mut rows);
let rows = self.simd.transpose_8x8_i16(&rows);
let mut cols = rows;
self.dct_8_1d(&mut cols);
let result = self.simd.transpose_8x8_i16(&cols);
for i in 0..8 {
for j in 0..8 {
output[i * 8 + j] = result[i][j];
}
}
}
pub fn inverse_dct_8x8(&self, input: &[i16; 64], output: &mut [i16; 64]) {
use crate::simd::types::I16x8;
let mut rows = [I16x8::zero(); 8];
for i in 0..8 {
for j in 0..8 {
rows[i][j] = input[i * 8 + j];
}
}
self.idct_8_1d(&mut rows);
let rows = self.simd.transpose_8x8_i16(&rows);
let mut cols = rows;
self.idct_8_1d(&mut cols);
let result = self.simd.transpose_8x8_i16(&cols);
for i in 0..8 {
for j in 0..8 {
output[i * 8 + j] = result[i][j];
}
}
}
pub fn forward_adst_4x4(&self, input: &[i16; 16], output: &mut [i16; 16]) {
use crate::simd::types::I16x8;
let mut rows = [I16x8::zero(); 4];
for i in 0..4 {
for j in 0..4 {
rows[i][j] = input[i * 4 + j];
}
}
self.adst_4_1d(&mut rows);
let rows = self.simd.transpose_4x4_i16(&rows);
let mut cols = rows;
self.adst_4_1d(&mut cols);
let result = self.simd.transpose_4x4_i16(&cols);
for i in 0..4 {
for j in 0..4 {
output[i * 4 + j] = result[i][j];
}
}
}
pub fn inverse_adst_4x4(&self, input: &[i16; 16], output: &mut [i16; 16]) {
use crate::simd::types::I16x8;
let mut rows = [I16x8::zero(); 4];
for i in 0..4 {
for j in 0..4 {
rows[i][j] = input[i * 4 + j];
}
}
self.iadst_4_1d(&mut rows);
let rows = self.simd.transpose_4x4_i16(&rows);
let mut cols = rows;
self.iadst_4_1d(&mut cols);
let result = self.simd.transpose_4x4_i16(&cols);
for i in 0..4 {
for j in 0..4 {
output[i * 4 + j] = result[i][j];
}
}
}
pub fn identity_4x4(&self, input: &[i16; 16], output: &mut [i16; 16]) {
for i in 0..16 {
let scaled = i32::from(input[i]) * 181 + 128;
output[i] = (scaled >> 8) as i16;
}
}
fn dct_4_1d(&self, rows: &mut [crate::simd::types::I16x8; 4]) {
let (s0, s3) = self.simd.butterfly_i16x8(rows[0], rows[3]);
let (s1, s2) = self.simd.butterfly_i16x8(rows[1], rows[2]);
let (x0, x1) = self.simd.butterfly_i16x8(s0, s1);
let (x3, x2) = self.simd.butterfly_i16x8(s3, s2);
rows[0] = x0;
rows[1] = x2;
rows[2] = x1;
rows[3] = x3;
}
fn idct_4_1d(&self, rows: &mut [crate::simd::types::I16x8; 4]) {
let t0 = rows[0];
let t1 = rows[2];
let t2 = rows[1];
let t3 = rows[3];
let (s0, s1) = self.simd.butterfly_i16x8(t0, t2);
let (s3, s2) = self.simd.butterfly_i16x8(t3, t1);
let (x0, x3) = self.simd.butterfly_i16x8(s0, s3);
let (x1, x2) = self.simd.butterfly_i16x8(s1, s2);
rows[0] = x0;
rows[1] = x1;
rows[2] = x2;
rows[3] = x3;
}
fn dct_8_1d(&self, rows: &mut [crate::simd::types::I16x8; 8]) {
let (s0, s7) = self.simd.butterfly_i16x8(rows[0], rows[7]);
let (s1, s6) = self.simd.butterfly_i16x8(rows[1], rows[6]);
let (s2, s5) = self.simd.butterfly_i16x8(rows[2], rows[5]);
let (s3, s4) = self.simd.butterfly_i16x8(rows[3], rows[4]);
let (t0, t3) = self.simd.butterfly_i16x8(s0, s3);
let (t1, t2) = self.simd.butterfly_i16x8(s1, s2);
let (t4, t7) = self.simd.butterfly_i16x8(s4, s7);
let (t5, t6) = self.simd.butterfly_i16x8(s5, s6);
let (u0, u1) = self.simd.butterfly_i16x8(t0, t1);
let (u2, u3) = self.simd.butterfly_i16x8(t2, t3);
let (u4, u5) = self.simd.butterfly_i16x8(t4, t5);
let (u6, u7) = self.simd.butterfly_i16x8(t6, t7);
rows[0] = u0;
rows[1] = u4;
rows[2] = u2;
rows[3] = u6;
rows[4] = u1;
rows[5] = u5;
rows[6] = u3;
rows[7] = u7;
}
fn idct_8_1d(&self, rows: &mut [crate::simd::types::I16x8; 8]) {
let t0 = rows[0];
let t4 = rows[1];
let t2 = rows[2];
let t6 = rows[3];
let t1 = rows[4];
let t5 = rows[5];
let t3 = rows[6];
let t7 = rows[7];
let (s0, s1) = self.simd.butterfly_i16x8(t0, t1);
let (s2, s3) = self.simd.butterfly_i16x8(t2, t3);
let (s4, s5) = self.simd.butterfly_i16x8(t4, t5);
let (s6, s7) = self.simd.butterfly_i16x8(t6, t7);
let (u0, u3) = self.simd.butterfly_i16x8(s0, s3);
let (u1, u2) = self.simd.butterfly_i16x8(s1, s2);
let (u4, u7) = self.simd.butterfly_i16x8(s4, s7);
let (u5, u6) = self.simd.butterfly_i16x8(s5, s6);
let (x0, x7) = self.simd.butterfly_i16x8(u0, u7);
let (x1, x6) = self.simd.butterfly_i16x8(u1, u6);
let (x2, x5) = self.simd.butterfly_i16x8(u2, u5);
let (x3, x4) = self.simd.butterfly_i16x8(u3, u4);
rows[0] = x0;
rows[1] = x1;
rows[2] = x2;
rows[3] = x3;
rows[4] = x4;
rows[5] = x5;
rows[6] = x6;
rows[7] = x7;
}
fn adst_4_1d(&self, rows: &mut [crate::simd::types::I16x8; 4]) {
let s0 = rows[0];
let s1 = rows[1];
let s2 = rows[2];
let s3 = rows[3];
let t0 = self.simd.add_i16x8(s0, s3);
let t1 = self.simd.add_i16x8(s1, s2);
let t2 = self.simd.sub_i16x8(s1, s2);
let t3 = self.simd.sub_i16x8(s0, s3);
rows[0] = t0;
rows[1] = t2;
rows[2] = t1;
rows[3] = t3;
}
fn iadst_4_1d(&self, rows: &mut [crate::simd::types::I16x8; 4]) {
let t0 = rows[0];
let t2 = rows[1];
let t1 = rows[2];
let t3 = rows[3];
let s0 = self.simd.add_i16x8(t0, t3);
let s1 = self.simd.add_i16x8(t1, t2);
let s2 = self.simd.sub_i16x8(t1, t2);
let s3 = self.simd.sub_i16x8(t0, t3);
rows[0] = s0;
rows[1] = s1;
rows[2] = s2;
rows[3] = s3;
}
}