#![allow(
clippy::many_single_char_names,
clippy::cast_lossless,
clippy::cast_possible_truncation,
clippy::similar_names,
clippy::cast_sign_loss
)]
#[cfg(all(feature = "simd", target_arch = "x86_64"))]
#[allow(clippy::many_single_char_names)]
pub unsafe fn clcl_row_to_bgra_sse2(y_ptr: *const u8, cb_ptr: *const u8, cr_ptr: *const u8, width: u32, dst: *mut u8) {
unsafe {
use core::arch::x86_64::{
__m128i, _mm_and_si128, _mm_cvtsi32_si128, _mm_loadl_epi64, _mm_set1_epi8, _mm_slli_epi16, _mm_srli_epi16,
_mm_storeu_si128, _mm_unpacklo_epi8,
};
let w = width as usize;
let full_batches = (w / 8) * 8;
let mut i: usize = 0;
let low_mask = _mm_set1_epi8(0x0F);
while i < full_batches {
let y_val = _mm_loadl_epi64(y_ptr.add(i).cast::<__m128i>());
let cb_word = core::ptr::read_unaligned(cb_ptr.add(i / 2).cast::<i32>());
let cr_word = core::ptr::read_unaligned(cr_ptr.add(i / 2).cast::<i32>());
let cb_raw = _mm_cvtsi32_si128(cb_word);
let cr_raw = _mm_cvtsi32_si128(cr_word);
let cb_lo = _mm_and_si128(cb_raw, low_mask);
let cb_hi = _mm_and_si128(_mm_srli_epi16(cb_raw, 4), low_mask);
let cr_lo = _mm_and_si128(cr_raw, low_mask);
let cr_hi = _mm_and_si128(_mm_srli_epi16(cr_raw, 4), low_mask);
let cb_unpacked = _mm_unpacklo_epi8(cb_lo, cb_hi);
let cr_unpacked = _mm_unpacklo_epi8(cr_lo, cr_hi);
let cb_exp = _mm_slli_epi16(cb_unpacked, 4);
let cr_exp = _mm_slli_epi16(cr_unpacked, 4);
let mut y_arr: [u8; 8] = [0u8; 8];
let mut cb_arr: [u8; 8] = [0u8; 8];
let mut cr_arr: [u8; 8] = [0u8; 8];
_mm_storeu_si128(y_arr.as_mut_ptr().cast::<__m128i>(), y_val);
_mm_storeu_si128(cb_arr.as_mut_ptr().cast::<__m128i>(), cb_exp);
_mm_storeu_si128(cr_arr.as_mut_ptr().cast::<__m128i>(), cr_exp);
for px in 0..8usize {
let y = i32::from(y_arr[px]);
let cb = i32::from(cb_arr[px]).wrapping_sub(128);
let cr = i32::from(cr_arr[px]).wrapping_sub(128);
let r = (y + ((cr * 359) >> 8)).clamp(0, 255) as u8;
let g = (y - ((cb * 88) >> 8) - ((cr * 183) >> 8)).clamp(0, 255) as u8;
let b = (y + ((cb * 454) >> 8)).clamp(0, 255) as u8;
let out = dst.add(i * 4 + px * 4);
*out = b;
*out.add(1) = g;
*out.add(2) = r;
*out.add(3) = 255;
}
i += 8;
}
while i < w {
let y = i32::from(*y_ptr.add(i));
let cb_byte = *cb_ptr.add(i / 2);
let cr_byte = *cr_ptr.add(i / 2);
let n_cb = if i & 1 == 0 { cb_byte & 0x0F } else { cb_byte >> 4 };
let n_cr = if i & 1 == 0 { cr_byte & 0x0F } else { cr_byte >> 4 };
let cb8 = i32::from(n_cb) << 4;
let cr8 = i32::from(n_cr) << 4;
let cb = cb8.wrapping_sub(128);
let cr = cr8.wrapping_sub(128);
let r = (y + ((cr * 359) >> 8)).clamp(0, 255) as u8;
let g = (y - ((cb * 88) >> 8) - ((cr * 183) >> 8)).clamp(0, 255) as u8;
let b = (y + ((cb * 454) >> 8)).clamp(0, 255) as u8;
let out = dst.add(i * 4);
*out = b;
*out.add(1) = g;
*out.add(2) = r;
*out.add(3) = 255;
i += 1;
}
}
}
#[cfg(feature = "simd")]
#[inline]
pub fn clcl_row_to_bgra(y: &[u8], cb: &[u8], cr: &[u8], width: usize, dst: &mut [u8]) {
#[cfg(target_arch = "x86_64")]
{
unsafe {
clcl_row_to_bgra_sse2(y.as_ptr(), cb.as_ptr(), cr.as_ptr(), width as u32, dst.as_mut_ptr());
}
return;
}
#[allow(unreachable_code)]
scalar_fallback(y, cb, cr, width, dst);
}
#[cfg(not(feature = "simd"))]
#[inline]
pub fn clcl_row_to_bgra(y: &[u8], cb: &[u8], cr: &[u8], width: usize, dst: &mut [u8]) {
scalar_fallback(y, cb, cr, width, dst);
}
#[allow(dead_code)]
fn scalar_fallback(y: &[u8], cb: &[u8], cr: &[u8], width: usize, dst: &mut [u8]) {
for i in 0..width {
let cb_byte = cb[i / 2];
let cr_byte = cr[i / 2];
let n_cb = if i & 1 == 0 { cb_byte & 0x0F } else { cb_byte >> 4 };
let n_cr = if i & 1 == 0 { cr_byte & 0x0F } else { cr_byte >> 4 };
let pixel = crate::yuv::yuv_to_bgra(y[i], n_cb << 4, n_cr << 4);
let out = i * 4;
dst[out..out + 4].copy_from_slice(&pixel);
}
}