use std::arch::aarch64::*;
#[repr(align(16))]
struct ColorEncConsts {
data: [u16; 8],
}
const COLOR_ENC_CONSTS: ColorEncConsts = ColorEncConsts {
data: [
19595, 38470, 7471, 11059, 21709, 32768, 27439, 5329, ],
};
pub fn neon_rgb_to_ycbcr_row(rgb: &[u8], y: &mut [u8], cb: &mut [u8], cr: &mut [u8], width: usize) {
if width == 0 {
return;
}
unsafe {
neon_rgb_to_ycbcr_row_inner(rgb, y, cb, cr, width);
}
}
#[target_feature(enable = "neon")]
unsafe fn neon_rgb_to_ycbcr_row_inner(
rgb: &[u8],
y: &mut [u8],
cb: &mut [u8],
cr: &mut [u8],
width: usize,
) {
let consts: uint16x8_t = vld1q_u16(COLOR_ENC_CONSTS.data.as_ptr());
let scaled_128_5: uint32x4_t = vdupq_n_u32((128 << 16) + 32767);
let rgb_ptr: *const u8 = rgb.as_ptr();
let y_ptr: *mut u8 = y.as_mut_ptr();
let cb_ptr: *mut u8 = cb.as_mut_ptr();
let cr_ptr: *mut u8 = cr.as_mut_ptr();
let mut offset: usize = 0;
let mut remaining: usize = width;
while remaining >= 16 {
let input_pixels: uint8x16x3_t = vld3q_u8(rgb_ptr.add(offset * 3));
let r_full: uint8x16_t = input_pixels.0;
let g_full: uint8x16_t = input_pixels.1;
let b_full: uint8x16_t = input_pixels.2;
let r_l: uint16x8_t = vmovl_u8(vget_low_u8(r_full));
let g_l: uint16x8_t = vmovl_u8(vget_low_u8(g_full));
let b_l: uint16x8_t = vmovl_u8(vget_low_u8(b_full));
let r_h: uint16x8_t = vmovl_u8(vget_high_u8(r_full));
let g_h: uint16x8_t = vmovl_u8(vget_high_u8(g_full));
let b_h: uint16x8_t = vmovl_u8(vget_high_u8(b_full));
let mut y_ll: uint32x4_t = vmull_laneq_u16(vget_low_u16(r_l), consts, 0);
y_ll = vmlal_laneq_u16(y_ll, vget_low_u16(g_l), consts, 1);
y_ll = vmlal_laneq_u16(y_ll, vget_low_u16(b_l), consts, 2);
let mut y_lh: uint32x4_t = vmull_laneq_u16(vget_high_u16(r_l), consts, 0);
y_lh = vmlal_laneq_u16(y_lh, vget_high_u16(g_l), consts, 1);
y_lh = vmlal_laneq_u16(y_lh, vget_high_u16(b_l), consts, 2);
let mut y_hl: uint32x4_t = vmull_laneq_u16(vget_low_u16(r_h), consts, 0);
y_hl = vmlal_laneq_u16(y_hl, vget_low_u16(g_h), consts, 1);
y_hl = vmlal_laneq_u16(y_hl, vget_low_u16(b_h), consts, 2);
let mut y_hh: uint32x4_t = vmull_laneq_u16(vget_high_u16(r_h), consts, 0);
y_hh = vmlal_laneq_u16(y_hh, vget_high_u16(g_h), consts, 1);
y_hh = vmlal_laneq_u16(y_hh, vget_high_u16(b_h), consts, 2);
let mut cb_ll: uint32x4_t = scaled_128_5;
cb_ll = vmlsl_laneq_u16(cb_ll, vget_low_u16(r_l), consts, 3);
cb_ll = vmlsl_laneq_u16(cb_ll, vget_low_u16(g_l), consts, 4);
cb_ll = vmlal_laneq_u16(cb_ll, vget_low_u16(b_l), consts, 5);
let mut cb_lh: uint32x4_t = scaled_128_5;
cb_lh = vmlsl_laneq_u16(cb_lh, vget_high_u16(r_l), consts, 3);
cb_lh = vmlsl_laneq_u16(cb_lh, vget_high_u16(g_l), consts, 4);
cb_lh = vmlal_laneq_u16(cb_lh, vget_high_u16(b_l), consts, 5);
let mut cb_hl: uint32x4_t = scaled_128_5;
cb_hl = vmlsl_laneq_u16(cb_hl, vget_low_u16(r_h), consts, 3);
cb_hl = vmlsl_laneq_u16(cb_hl, vget_low_u16(g_h), consts, 4);
cb_hl = vmlal_laneq_u16(cb_hl, vget_low_u16(b_h), consts, 5);
let mut cb_hh: uint32x4_t = scaled_128_5;
cb_hh = vmlsl_laneq_u16(cb_hh, vget_high_u16(r_h), consts, 3);
cb_hh = vmlsl_laneq_u16(cb_hh, vget_high_u16(g_h), consts, 4);
cb_hh = vmlal_laneq_u16(cb_hh, vget_high_u16(b_h), consts, 5);
let mut cr_ll: uint32x4_t = scaled_128_5;
cr_ll = vmlal_laneq_u16(cr_ll, vget_low_u16(r_l), consts, 5);
cr_ll = vmlsl_laneq_u16(cr_ll, vget_low_u16(g_l), consts, 6);
cr_ll = vmlsl_laneq_u16(cr_ll, vget_low_u16(b_l), consts, 7);
let mut cr_lh: uint32x4_t = scaled_128_5;
cr_lh = vmlal_laneq_u16(cr_lh, vget_high_u16(r_l), consts, 5);
cr_lh = vmlsl_laneq_u16(cr_lh, vget_high_u16(g_l), consts, 6);
cr_lh = vmlsl_laneq_u16(cr_lh, vget_high_u16(b_l), consts, 7);
let mut cr_hl: uint32x4_t = scaled_128_5;
cr_hl = vmlal_laneq_u16(cr_hl, vget_low_u16(r_h), consts, 5);
cr_hl = vmlsl_laneq_u16(cr_hl, vget_low_u16(g_h), consts, 6);
cr_hl = vmlsl_laneq_u16(cr_hl, vget_low_u16(b_h), consts, 7);
let mut cr_hh: uint32x4_t = scaled_128_5;
cr_hh = vmlal_laneq_u16(cr_hh, vget_high_u16(r_h), consts, 5);
cr_hh = vmlsl_laneq_u16(cr_hh, vget_high_u16(g_h), consts, 6);
cr_hh = vmlsl_laneq_u16(cr_hh, vget_high_u16(b_h), consts, 7);
let y_u16_l: uint16x8_t = vcombine_u16(vrshrn_n_u32(y_ll, 16), vrshrn_n_u32(y_lh, 16));
let y_u16_h: uint16x8_t = vcombine_u16(vrshrn_n_u32(y_hl, 16), vrshrn_n_u32(y_hh, 16));
let cb_u16_l: uint16x8_t = vcombine_u16(vshrn_n_u32(cb_ll, 16), vshrn_n_u32(cb_lh, 16));
let cb_u16_h: uint16x8_t = vcombine_u16(vshrn_n_u32(cb_hl, 16), vshrn_n_u32(cb_hh, 16));
let cr_u16_l: uint16x8_t = vcombine_u16(vshrn_n_u32(cr_ll, 16), vshrn_n_u32(cr_lh, 16));
let cr_u16_h: uint16x8_t = vcombine_u16(vshrn_n_u32(cr_hl, 16), vshrn_n_u32(cr_hh, 16));
vst1q_u8(
y_ptr.add(offset),
vcombine_u8(vmovn_u16(y_u16_l), vmovn_u16(y_u16_h)),
);
vst1q_u8(
cb_ptr.add(offset),
vcombine_u8(vmovn_u16(cb_u16_l), vmovn_u16(cb_u16_h)),
);
vst1q_u8(
cr_ptr.add(offset),
vcombine_u8(vmovn_u16(cr_u16_l), vmovn_u16(cr_u16_h)),
);
offset += 16;
remaining -= 16;
}
if remaining >= 8 {
let input_pixels: uint8x8x3_t = vld3_u8(rgb_ptr.add(offset * 3));
let r: uint16x8_t = vmovl_u8(input_pixels.0);
let g: uint16x8_t = vmovl_u8(input_pixels.1);
let b: uint16x8_t = vmovl_u8(input_pixels.2);
let mut y_l: uint32x4_t = vmull_laneq_u16(vget_low_u16(r), consts, 0);
y_l = vmlal_laneq_u16(y_l, vget_low_u16(g), consts, 1);
y_l = vmlal_laneq_u16(y_l, vget_low_u16(b), consts, 2);
let mut y_h: uint32x4_t = vmull_laneq_u16(vget_high_u16(r), consts, 0);
y_h = vmlal_laneq_u16(y_h, vget_high_u16(g), consts, 1);
y_h = vmlal_laneq_u16(y_h, vget_high_u16(b), consts, 2);
let mut cb_l: uint32x4_t = scaled_128_5;
cb_l = vmlsl_laneq_u16(cb_l, vget_low_u16(r), consts, 3);
cb_l = vmlsl_laneq_u16(cb_l, vget_low_u16(g), consts, 4);
cb_l = vmlal_laneq_u16(cb_l, vget_low_u16(b), consts, 5);
let mut cb_h: uint32x4_t = scaled_128_5;
cb_h = vmlsl_laneq_u16(cb_h, vget_high_u16(r), consts, 3);
cb_h = vmlsl_laneq_u16(cb_h, vget_high_u16(g), consts, 4);
cb_h = vmlal_laneq_u16(cb_h, vget_high_u16(b), consts, 5);
let mut cr_l: uint32x4_t = scaled_128_5;
cr_l = vmlal_laneq_u16(cr_l, vget_low_u16(r), consts, 5);
cr_l = vmlsl_laneq_u16(cr_l, vget_low_u16(g), consts, 6);
cr_l = vmlsl_laneq_u16(cr_l, vget_low_u16(b), consts, 7);
let mut cr_h: uint32x4_t = scaled_128_5;
cr_h = vmlal_laneq_u16(cr_h, vget_high_u16(r), consts, 5);
cr_h = vmlsl_laneq_u16(cr_h, vget_high_u16(g), consts, 6);
cr_h = vmlsl_laneq_u16(cr_h, vget_high_u16(b), consts, 7);
let y_u16: uint16x8_t = vcombine_u16(vrshrn_n_u32(y_l, 16), vrshrn_n_u32(y_h, 16));
let cb_u16: uint16x8_t = vcombine_u16(vshrn_n_u32(cb_l, 16), vshrn_n_u32(cb_h, 16));
let cr_u16: uint16x8_t = vcombine_u16(vshrn_n_u32(cr_l, 16), vshrn_n_u32(cr_h, 16));
vst1_u8(y_ptr.add(offset), vmovn_u16(y_u16));
vst1_u8(cb_ptr.add(offset), vmovn_u16(cb_u16));
vst1_u8(cr_ptr.add(offset), vmovn_u16(cr_u16));
offset += 8;
remaining -= 8;
}
if remaining > 0 {
crate::encode::color::rgb_to_ycbcr_row(
&rgb[offset * 3..],
&mut y[offset..],
&mut cb[offset..],
&mut cr[offset..],
remaining,
);
}
}