#[cfg(target_arch = "x86")]
use std::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;
pub fn morph_gradient_sse(dilation: &[u8], erosion: &[u8], dst: &mut [u8]) {
unsafe {
morph_gradient_sse_impl(dilation, erosion, dst);
}
}
#[target_feature(enable = "sse4.1")]
unsafe fn morph_gradient_sse_impl(dilation: &[u8], erosion: &[u8], dst: &mut [u8]) {
if dilation.len() != erosion.len() || erosion.len() != dst.len() {
panic!(
"All array must match in size for gradient but received v0: {}, v1: {}, v2: {}",
dilation.len(),
erosion.len(),
dst.len()
);
}
let length = dilation.len();
let mut cx = 0usize;
unsafe {
while cx + 64 < length {
let v0_ptr = dilation.get_unchecked(cx..).as_ptr();
let v0_set = (
_mm_loadu_si128(v0_ptr as *const __m128i),
_mm_loadu_si128(v0_ptr.add(16) as *const __m128i),
_mm_loadu_si128(v0_ptr.add(32) as *const __m128i),
_mm_loadu_si128(v0_ptr.add(48) as *const __m128i),
);
let v1_ptr = erosion.get_unchecked(cx..).as_ptr();
let v1_set = (
_mm_loadu_si128(v1_ptr as *const __m128i),
_mm_loadu_si128(v1_ptr.add(16) as *const __m128i),
_mm_loadu_si128(v1_ptr.add(32) as *const __m128i),
_mm_loadu_si128(v1_ptr.add(48) as *const __m128i),
);
let result_set = (
_mm_subs_epu8(v0_set.0, v1_set.0),
_mm_subs_epu8(v0_set.1, v1_set.1),
_mm_subs_epu8(v0_set.2, v1_set.2),
_mm_subs_epu8(v0_set.3, v1_set.3),
);
let v_dst_ptr = dst.get_unchecked_mut(cx..).as_mut_ptr();
_mm_storeu_si128(v_dst_ptr as *mut __m128i, result_set.0);
_mm_storeu_si128(v_dst_ptr.add(16) as *mut __m128i, result_set.1);
_mm_storeu_si128(v_dst_ptr.add(32) as *mut __m128i, result_set.2);
_mm_storeu_si128(v_dst_ptr.add(48) as *mut __m128i, result_set.3);
cx += 64;
}
while cx + 32 < length {
let v0_ptr = dilation.get_unchecked(cx..).as_ptr();
let v0_set = (
_mm_loadu_si128(v0_ptr as *const __m128i),
_mm_loadu_si128(v0_ptr.add(16) as *const __m128i),
);
let v1_ptr = erosion.get_unchecked(cx..).as_ptr();
let v1_set = (
_mm_loadu_si128(v1_ptr as *const __m128i),
_mm_loadu_si128(v1_ptr.add(16) as *const __m128i),
);
let result_set = (
_mm_subs_epu8(v0_set.0, v1_set.0),
_mm_subs_epu8(v0_set.1, v1_set.1),
);
let v_dst_ptr = dst.get_unchecked_mut(cx..).as_mut_ptr();
_mm_storeu_si128(v_dst_ptr as *mut __m128i, result_set.0);
_mm_storeu_si128(v_dst_ptr.add(16) as *mut __m128i, result_set.1);
cx += 32;
}
while cx + 16 < length {
let v0_ptr = dilation.get_unchecked(cx..).as_ptr();
let v0_set = _mm_loadu_si128(v0_ptr as *const __m128i);
let v1_ptr = erosion.get_unchecked(cx..).as_ptr();
let v1_set = _mm_loadu_si128(v1_ptr as *const __m128i);
let result_set = _mm_subs_epu8(v0_set, v1_set);
let v_dst_ptr = dst.get_unchecked_mut(cx..).as_mut_ptr();
_mm_storeu_si128(v_dst_ptr as *mut __m128i, result_set);
cx += 16;
}
while cx < length {
*dst.get_unchecked_mut(cx) = dilation
.get_unchecked(cx)
.saturating_sub(*erosion.get_unchecked(cx));
cx += 1;
}
}
}