use std::arch::aarch64::*;
pub fn neon_downsample_h2v1(input: &[u8], in_width: usize, output: &mut [u8]) {
if in_width == 0 {
return;
}
unsafe {
neon_downsample_h2v1_inner(input, in_width, output);
}
}
pub fn neon_downsample_h2v2(row0: &[u8], row1: &[u8], in_width: usize, output: &mut [u8]) {
if in_width == 0 {
return;
}
unsafe {
neon_downsample_h2v2_inner(row0, row1, in_width, output);
}
}
#[target_feature(enable = "neon")]
unsafe fn neon_downsample_h2v1_inner(input: &[u8], in_width: usize, output: &mut [u8]) {
let bias: uint16x8_t = vreinterpretq_u16_u32(vdupq_n_u32(0x0001_0000));
let in_ptr: *const u8 = input.as_ptr();
let out_ptr: *mut u8 = output.as_mut_ptr();
let mut in_offset: usize = 0;
let mut out_offset: usize = 0;
while in_offset + 16 <= in_width {
let components: uint8x16_t = vld1q_u8(in_ptr.add(in_offset));
let samples_u16: uint16x8_t = vpadalq_u8(bias, components);
let samples_u8: uint8x8_t = vshrn_n_u16(samples_u16, 1);
vst1_u8(out_ptr.add(out_offset), samples_u8);
in_offset += 16;
out_offset += 8;
}
while in_offset + 1 < in_width {
let left: u16 = input[in_offset] as u16;
let right: u16 = input[in_offset + 1] as u16;
output[out_offset] = ((left + right + 1) >> 1) as u8;
in_offset += 2;
out_offset += 1;
}
if in_offset < in_width {
output[out_offset] = input[in_offset];
}
}
#[target_feature(enable = "neon")]
unsafe fn neon_downsample_h2v2_inner(row0: &[u8], row1: &[u8], in_width: usize, output: &mut [u8]) {
let bias: uint16x8_t = vreinterpretq_u16_u32(vdupq_n_u32(0x0002_0001));
let r0_ptr: *const u8 = row0.as_ptr();
let r1_ptr: *const u8 = row1.as_ptr();
let out_ptr: *mut u8 = output.as_mut_ptr();
let mut in_offset: usize = 0;
let mut out_offset: usize = 0;
while in_offset + 16 <= in_width {
let components_r0: uint8x16_t = vld1q_u8(r0_ptr.add(in_offset));
let components_r1: uint8x16_t = vld1q_u8(r1_ptr.add(in_offset));
let mut samples_u16: uint16x8_t = vpadalq_u8(bias, components_r0);
samples_u16 = vpadalq_u8(samples_u16, components_r1);
let samples_u8: uint8x8_t = vshrn_n_u16(samples_u16, 2);
vst1_u8(out_ptr.add(out_offset), samples_u8);
in_offset += 16;
out_offset += 8;
}
while in_offset + 1 < in_width {
let tl: u16 = row0[in_offset] as u16;
let tr: u16 = row0[in_offset + 1] as u16;
let bl: u16 = row1[in_offset] as u16;
let br: u16 = row1[in_offset + 1] as u16;
output[out_offset] = ((tl + tr + bl + br + 2) >> 2) as u8;
in_offset += 2;
out_offset += 1;
}
if in_offset < in_width {
let top: u16 = row0[in_offset] as u16;
let bot: u16 = row1[in_offset] as u16;
output[out_offset] = ((top + bot + 1) >> 1) as u8;
}
}