#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::*;
const CONST_BITS: i32 = 13;
const PASS1_BITS: i32 = 2;
const F_0_298: i32 = 2446;
const F_0_390: i32 = 3196;
const F_0_541: i32 = 4433;
const F_0_765: i32 = 6270;
const F_0_899: i32 = 7373;
const F_1_175: i32 = 9633;
const F_1_501: i32 = 12299;
const F_1_847: i32 = 15137;
const F_1_961: i32 = 16069;
const F_2_053: i32 = 16819;
const F_2_562: i32 = 20995;
const F_3_072: i32 = 25172;
pub fn sse2_idct_islow(coeffs: &[i16; 64], quant: &[u16; 64], output: &mut [u8; 64]) {
unsafe {
sse2_idct_islow_inner(coeffs, quant, output);
}
}
#[inline(always)]
unsafe fn mullo_epi32_sse2(a: __m128i, b: __m128i) -> __m128i {
let mul02: __m128i = _mm_mul_epu32(a, b);
let a_odd: __m128i = _mm_srli_si128(a, 4);
let b_odd: __m128i = _mm_srli_si128(b, 4);
let mul13: __m128i = _mm_mul_epu32(a_odd, b_odd);
let lo02: __m128i = _mm_shuffle_epi32(mul02, 0b00_00_10_00);
let lo13: __m128i = _mm_shuffle_epi32(mul13, 0b00_00_10_00);
_mm_unpacklo_epi32(lo02, lo13)
}
#[inline(always)]
#[allow(clippy::too_many_arguments)]
unsafe fn idct_1d_pass(
s0: __m128i,
s1: __m128i,
s2: __m128i,
s3: __m128i,
s4: __m128i,
s5: __m128i,
s6: __m128i,
s7: __m128i,
) -> [__m128i; 8] {
let s2_plus_s6: __m128i = _mm_add_epi32(s2, s6);
let z1: __m128i = mullo_epi32_sse2(s2_plus_s6, _mm_set1_epi32(F_0_541));
let tmp2: __m128i = _mm_add_epi32(z1, mullo_epi32_sse2(s6, _mm_set1_epi32(-F_1_847)));
let tmp3: __m128i = _mm_add_epi32(z1, mullo_epi32_sse2(s2, _mm_set1_epi32(F_0_765)));
let tmp0: __m128i = _mm_slli_epi32(_mm_add_epi32(s0, s4), CONST_BITS);
let tmp1: __m128i = _mm_slli_epi32(_mm_sub_epi32(s0, s4), CONST_BITS);
let tmp10: __m128i = _mm_add_epi32(tmp0, tmp3);
let tmp13: __m128i = _mm_sub_epi32(tmp0, tmp3);
let tmp11: __m128i = _mm_add_epi32(tmp1, tmp2);
let tmp12: __m128i = _mm_sub_epi32(tmp1, tmp2);
let z1: __m128i = _mm_add_epi32(s7, s1);
let z2: __m128i = _mm_add_epi32(s5, s3);
let z3: __m128i = _mm_add_epi32(s7, s3);
let z4: __m128i = _mm_add_epi32(s5, s1);
let z5: __m128i = mullo_epi32_sse2(_mm_add_epi32(z3, z4), _mm_set1_epi32(F_1_175));
let o0: __m128i = mullo_epi32_sse2(s7, _mm_set1_epi32(F_0_298));
let o1: __m128i = mullo_epi32_sse2(s5, _mm_set1_epi32(F_2_053));
let o2: __m128i = mullo_epi32_sse2(s3, _mm_set1_epi32(F_3_072));
let o3: __m128i = mullo_epi32_sse2(s1, _mm_set1_epi32(F_1_501));
let z1: __m128i = mullo_epi32_sse2(z1, _mm_set1_epi32(-F_0_899));
let z2: __m128i = mullo_epi32_sse2(z2, _mm_set1_epi32(-F_2_562));
let z3: __m128i = _mm_add_epi32(mullo_epi32_sse2(z3, _mm_set1_epi32(-F_1_961)), z5);
let z4: __m128i = _mm_add_epi32(mullo_epi32_sse2(z4, _mm_set1_epi32(-F_0_390)), z5);
let o0: __m128i = _mm_add_epi32(_mm_add_epi32(o0, z1), z3);
let o1: __m128i = _mm_add_epi32(_mm_add_epi32(o1, z2), z4);
let o2: __m128i = _mm_add_epi32(_mm_add_epi32(o2, z2), z3);
let o3: __m128i = _mm_add_epi32(_mm_add_epi32(o3, z1), z4);
[
_mm_add_epi32(tmp10, o3),
_mm_add_epi32(tmp11, o2),
_mm_add_epi32(tmp12, o1),
_mm_add_epi32(tmp13, o0),
_mm_sub_epi32(tmp13, o0),
_mm_sub_epi32(tmp12, o1),
_mm_sub_epi32(tmp11, o2),
_mm_sub_epi32(tmp10, o3),
]
}
#[inline(always)]
unsafe fn descale_p1(val: __m128i) -> __m128i {
let round: __m128i = _mm_set1_epi32(1 << (CONST_BITS - PASS1_BITS - 1));
_mm_srai_epi32(_mm_add_epi32(val, round), CONST_BITS - PASS1_BITS)
}
#[inline(always)]
unsafe fn descale_p2(val: __m128i) -> __m128i {
let round: __m128i = _mm_set1_epi32(1 << (CONST_BITS + PASS1_BITS + 3 - 1));
_mm_srai_epi32(_mm_add_epi32(val, round), CONST_BITS + PASS1_BITS + 3)
}
#[target_feature(enable = "sse2")]
unsafe fn sse2_idct_islow_inner(coeffs: &[i16; 64], quant: &[u16; 64], output: &mut [u8; 64]) {
let mut ws = [0i32; 64];
for col_base in (0..8).step_by(4) {
let mut rows = [_mm_setzero_si128(); 8];
for (row, row_val) in rows.iter_mut().enumerate() {
let idx: usize = row * 8 + col_base;
let c0: i32 = coeffs[idx] as i32;
let c1: i32 = coeffs[idx + 1] as i32;
let c2: i32 = coeffs[idx + 2] as i32;
let c3: i32 = coeffs[idx + 3] as i32;
let q0: i32 = quant[idx] as i32;
let q1: i32 = quant[idx + 1] as i32;
let q2: i32 = quant[idx + 2] as i32;
let q3: i32 = quant[idx + 3] as i32;
*row_val = _mm_set_epi32(c3 * q3, c2 * q2, c1 * q1, c0 * q0);
}
let result: [__m128i; 8] = idct_1d_pass(
rows[0], rows[1], rows[2], rows[3], rows[4], rows[5], rows[6], rows[7],
);
for (row, &res) in result.iter().enumerate() {
let descaled: __m128i = descale_p1(res);
let idx: usize = row * 8 + col_base;
_mm_storeu_si128(ws.as_mut_ptr().add(idx) as *mut __m128i, descaled);
}
}
let center: __m128i = _mm_set1_epi32(128);
for row_base in (0..8).step_by(4) {
let r0: __m128i = _mm_loadu_si128(ws.as_ptr().add(row_base * 8) as *const __m128i);
let r0h: __m128i = _mm_loadu_si128(ws.as_ptr().add(row_base * 8 + 4) as *const __m128i);
let r1: __m128i = _mm_loadu_si128(ws.as_ptr().add((row_base + 1) * 8) as *const __m128i);
let r1h: __m128i =
_mm_loadu_si128(ws.as_ptr().add((row_base + 1) * 8 + 4) as *const __m128i);
let r2: __m128i = _mm_loadu_si128(ws.as_ptr().add((row_base + 2) * 8) as *const __m128i);
let r2h: __m128i =
_mm_loadu_si128(ws.as_ptr().add((row_base + 2) * 8 + 4) as *const __m128i);
let r3: __m128i = _mm_loadu_si128(ws.as_ptr().add((row_base + 3) * 8) as *const __m128i);
let r3h: __m128i =
_mm_loadu_si128(ws.as_ptr().add((row_base + 3) * 8 + 4) as *const __m128i);
let t0: __m128i = _mm_unpacklo_epi32(r0, r1);
let t1: __m128i = _mm_unpackhi_epi32(r0, r1);
let t2: __m128i = _mm_unpacklo_epi32(r2, r3);
let t3: __m128i = _mm_unpackhi_epi32(r2, r3);
let col0: __m128i = _mm_unpacklo_epi64(t0, t2);
let col1: __m128i = _mm_unpackhi_epi64(t0, t2);
let col2: __m128i = _mm_unpacklo_epi64(t1, t3);
let col3: __m128i = _mm_unpackhi_epi64(t1, t3);
let t0h: __m128i = _mm_unpacklo_epi32(r0h, r1h);
let t1h: __m128i = _mm_unpackhi_epi32(r0h, r1h);
let t2h: __m128i = _mm_unpacklo_epi32(r2h, r3h);
let t3h: __m128i = _mm_unpackhi_epi32(r2h, r3h);
let col4: __m128i = _mm_unpacklo_epi64(t0h, t2h);
let col5: __m128i = _mm_unpackhi_epi64(t0h, t2h);
let col6: __m128i = _mm_unpacklo_epi64(t1h, t3h);
let col7: __m128i = _mm_unpackhi_epi64(t1h, t3h);
let result: [__m128i; 8] = idct_1d_pass(col0, col1, col2, col3, col4, col5, col6, col7);
for c in 0..8 {
let descaled: __m128i = descale_p2(result[c]);
let shifted: __m128i = _mm_add_epi32(descaled, center);
let zero: __m128i = _mm_setzero_si128();
let packed_i16: __m128i = _mm_packs_epi32(shifted, zero);
let packed_u8: __m128i = _mm_packus_epi16(packed_i16, zero);
let mut bytes = [0u8; 16];
_mm_storeu_si128(bytes.as_mut_ptr() as *mut __m128i, packed_u8);
output[(row_base) * 8 + c] = bytes[0];
output[(row_base + 1) * 8 + c] = bytes[1];
output[(row_base + 2) * 8 + c] = bytes[2];
output[(row_base + 3) * 8 + c] = bytes[3];
}
}
}