#include <emmintrin.h>
#define VS_MERGE_IMPL
#include "../merge.h"
#include "VSHelper4.h"
#define MERGESHIFT 15
#define ROUND (1U << (MERGESHIFT - 1))
void vs_merge_byte_sse2(const void *src1, const void *src2, void *dst, union vs_merge_weight weight, unsigned n)
{
const uint8_t *srcp1 = src1;
const uint8_t *srcp2 = src2;
uint8_t *dstp = dst;
unsigned i;
__m128i w = _mm_set1_epi16(weight.u);
for (i = 0; i < n; i += 16) {
__m128i v1b = _mm_load_si128((const __m128i *)(srcp1 + i));
__m128i v2b = _mm_load_si128((const __m128i *)(srcp2 + i));
__m128i v1w_lo = _mm_unpacklo_epi8(v1b, _mm_setzero_si128());
__m128i v2w_lo = _mm_unpacklo_epi8(v2b, _mm_setzero_si128());
__m128i v1w_hi = _mm_unpackhi_epi8(v1b, _mm_setzero_si128());
__m128i v2w_hi = _mm_unpackhi_epi8(v2b, _mm_setzero_si128());
__m128i tmp1lo = _mm_slli_epi16(_mm_sub_epi16(v2w_lo, v1w_lo), 1);
__m128i tmp1hi = _mm_slli_epi16(_mm_sub_epi16(v2w_hi, v1w_hi), 1);
__m128i tmp2lo = _mm_add_epi16(_mm_add_epi16(_mm_mulhi_epi16(tmp1lo, w), _mm_srli_epi16(_mm_mullo_epi16(tmp1lo, w), 15)), v1w_lo);
__m128i tmp2hi = _mm_add_epi16(_mm_add_epi16(_mm_mulhi_epi16(tmp1hi, w), _mm_srli_epi16(_mm_mullo_epi16(tmp1hi, w), 15)), v1w_hi);
__m128i result = _mm_packus_epi16(tmp2lo, tmp2hi);
_mm_store_si128((__m128i *)(dstp + i), result);
}
}
void vs_merge_word_sse2(const void *src1, const void *src2, void *dst, union vs_merge_weight weight, unsigned n)
{
const uint16_t *srcp1 = src1;
const uint16_t *srcp2 = src2;
uint16_t *dstp = dst;
unsigned i;
unsigned w2 = VSMIN(VSMAX(weight.u, 1U), (1U << MERGESHIFT) - 1);
unsigned w1 = (1U << MERGESHIFT) - w2;
__m128i w = _mm_set1_epi32((w2 << 16) | w1);
for (i = 0; i < n; i += 8) {
__m128i v1 = _mm_load_si128((const __m128i *)(srcp1 + i));
__m128i v2 = _mm_load_si128((const __m128i *)(srcp2 + i));
__m128i tmplo, tmphi, result;
v1 = _mm_add_epi16(v1, _mm_set1_epi16(INT16_MIN));
v2 = _mm_add_epi16(v2, _mm_set1_epi16(INT16_MIN));
tmplo = _mm_unpacklo_epi16(v1, v2);
tmphi = _mm_unpackhi_epi16(v1, v2);
tmplo = _mm_madd_epi16(w, tmplo);
tmplo = _mm_add_epi32(tmplo, _mm_set1_epi32(ROUND));
tmplo = _mm_srai_epi32(tmplo, MERGESHIFT);
tmphi = _mm_madd_epi16(w, tmphi);
tmphi = _mm_add_epi32(tmphi, _mm_set1_epi32(ROUND));
tmphi = _mm_srai_epi32(tmphi, MERGESHIFT);
result = _mm_packs_epi32(tmplo, tmphi);
result = _mm_sub_epi16(result, _mm_set1_epi16(INT16_MIN));
_mm_store_si128((__m128i *)(dstp + i), result);
}
}
void vs_merge_float_sse2(const void *src1, const void *src2, void *dst, union vs_merge_weight weight, unsigned n)
{
const float *srcp1 = src1;
const float *srcp2 = src2;
float *dstp = dst;
unsigned i;
__m128 w2 = _mm_set_ps1(weight.f);
__m128 w1 = _mm_set_ps1(1.0f - weight.f);
for (i = 0; i < n; i += 4) {
__m128 v1 = _mm_load_ps(srcp1 + i);
__m128 v2 = _mm_load_ps(srcp2 + i);
v1 = _mm_mul_ps(w1, v1);
v2 = _mm_mul_ps(w2, v2);
_mm_store_ps(dstp + i, _mm_add_ps(v1, v2));
}
}
static __m128i div255_epu16(__m128i x)
{
x = _mm_mulhi_epu16(x, _mm_set1_epi16(0x8081));
x = _mm_srli_epi16(x, 7);
return x;
}
static __m128i divX_epu32(__m128i x, unsigned depth)
{
__m128i lo = _mm_unpacklo_epi32(x, x);
__m128i hi = _mm_unpackhi_epi32(x, x);
__m128i div = _mm_set1_epi32(div_table[depth - 9]);
lo = _mm_mul_epu32(lo, div);
hi = _mm_mul_epu32(hi, div);
x = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(lo), _mm_castsi128_ps(hi), _MM_SHUFFLE(3, 1, 3, 1)));
x = _mm_srl_epi32(x, _mm_cvtsi32_si128(shift_table[depth - 9]));
return x;
}
void vs_mask_merge_byte_sse2(const void *src1, const void *src2, const void *mask, void *dst, unsigned depth, unsigned offset, unsigned n)
{
const uint8_t *srcp1 = src1;
const uint8_t *srcp2 = src2;
const uint8_t *maskp = mask;
uint8_t *dstp = dst;
unsigned i;
(void)depth;
(void)offset;
for (i = 0; i < n; i += 8) {
__m128i v1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(srcp1 + i)), _mm_setzero_si128());
__m128i v2 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(srcp2 + i)), _mm_setzero_si128());
__m128i w2 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(maskp + i)), _mm_setzero_si128());
__m128i w1 = _mm_sub_epi16(_mm_set1_epi16(UINT8_MAX), w2);
__m128i tmp1 = _mm_mullo_epi16(v1, w1);
__m128i tmp2 = _mm_mullo_epi16(v2, w2);
__m128i tmp;
tmp = _mm_add_epi16(_mm_add_epi16(tmp1, tmp2), _mm_set1_epi16(UINT8_MAX / 2));
tmp = div255_epu16(tmp);
_mm_storel_epi64((__m128i *)(dstp + i), _mm_packus_epi16(tmp, tmp));
}
}
void vs_mask_merge_word_sse2(const void *src1, const void *src2, const void *mask, void *dst, unsigned depth, unsigned offset, unsigned n)
{
const uint16_t *srcp1 = src1;
const uint16_t *srcp2 = src2;
const uint16_t *maskp = mask;
uint16_t *dstp = dst;
unsigned i;
uint16_t maxval = (1U << depth) - 1;
(void)offset;
for (i = 0; i < n; i += 8) {
__m128i v1 = _mm_load_si128((const __m128i *)(srcp1 + i));
__m128i v2 = _mm_load_si128((const __m128i *)(srcp2 + i));
__m128i w2 = _mm_load_si128((const __m128i *)(maskp + i));
__m128i w1 = _mm_sub_epi16(_mm_set1_epi16(maxval), w2);
__m128i tmp1lo = _mm_mullo_epi16(w1, v1);
__m128i tmp1hi = _mm_mulhi_epu16(w1, v1);
__m128i tmp2lo = _mm_mullo_epi16(w2, v2);
__m128i tmp2hi = _mm_mulhi_epu16(w2, v2);
__m128i tmp1d_lo = _mm_unpacklo_epi16(tmp1lo, tmp1hi);
__m128i tmp1d_hi = _mm_unpackhi_epi16(tmp1lo, tmp1hi);
__m128i tmp2d_lo = _mm_unpacklo_epi16(tmp2lo, tmp2hi);
__m128i tmp2d_hi = _mm_unpackhi_epi16(tmp2lo, tmp2hi);
__m128i tmp;
tmp1d_lo = _mm_add_epi32(tmp1d_lo, tmp2d_lo);
tmp1d_lo = _mm_add_epi32(tmp1d_lo, _mm_set1_epi32(maxval / 2));
tmp1d_hi = _mm_add_epi32(tmp1d_hi, tmp2d_hi);
tmp1d_hi = _mm_add_epi32(tmp1d_hi, _mm_set1_epi32(maxval / 2));
tmp1d_lo = divX_epu32(tmp1d_lo, depth);
tmp1d_lo = _mm_add_epi32(tmp1d_lo, _mm_set1_epi32(INT16_MIN));
tmp1d_hi = divX_epu32(tmp1d_hi, depth);
tmp1d_hi = _mm_add_epi32(tmp1d_hi, _mm_set1_epi32(INT16_MIN));
tmp = _mm_packs_epi32(tmp1d_lo, tmp1d_hi);
tmp = _mm_sub_epi16(tmp, _mm_set1_epi16(INT16_MIN));
_mm_store_si128((__m128i *)(dstp + i), tmp);
}
}
void vs_mask_merge_float_sse2(const void *src1, const void *src2, const void *mask, void *dst, unsigned depth, unsigned offset, unsigned n)
{
const float *srcp1 = src1;
const float *srcp2 = src2;
const float *maskp = mask;
float *dstp = dst;
unsigned i;
(void)depth;
(void)offset;
for (i = 0; i < n; i += 4) {
__m128 v1 = _mm_load_ps(srcp1 + i);
__m128 v2 = _mm_load_ps(srcp2 + i);
__m128 w2 = _mm_load_ps(maskp + i);
__m128 diff = _mm_sub_ps(v2, v1);
__m128 result = _mm_add_ps(v1, _mm_mul_ps(diff, w2));
_mm_store_ps(dstp + i, result);
}
}
void vs_mask_merge_premul_byte_sse2(const void *src1, const void *src2, const void *mask, void *dst, unsigned depth, unsigned offset, unsigned n)
{
const uint8_t *srcp1 = src1;
const uint8_t *srcp2 = src2;
const uint8_t *maskp = mask;
uint8_t *dstp = dst;
unsigned i;
(void)depth;
for (i = 0; i < n; i += 8) {
__m128i v1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(srcp1 + i)), _mm_setzero_si128());
__m128i v2 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(srcp2 + i)), _mm_setzero_si128());
__m128i w2 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(maskp + i)), _mm_setzero_si128());
__m128i w1 = _mm_sub_epi16(_mm_set1_epi16(UINT8_MAX), w2);
__m128i neg, sign, tmp;
tmp = _mm_sub_epi16(v1, _mm_set1_epi16(offset));
sign = _mm_cmplt_epi16(tmp, _mm_setzero_si128());
neg = _mm_sub_epi16(_mm_setzero_si128(), tmp);
tmp = _mm_or_si128(_mm_andnot_si128(sign, tmp), _mm_and_si128(sign, neg));
tmp = _mm_add_epi16(_mm_mullo_epi16(tmp, w1), _mm_set1_epi16(UINT8_MAX / 2));
tmp = div255_epu16(tmp);
neg = _mm_sub_epi16(_mm_setzero_si128(), tmp);
tmp = _mm_or_si128(_mm_andnot_si128(sign, tmp), _mm_and_si128(sign, neg));
tmp = _mm_add_epi16(tmp, v2);
tmp = _mm_packus_epi16(tmp, tmp);
_mm_storel_epi64((__m128i *)(dstp + i), tmp);
}
}
void vs_mask_merge_premul_word_sse2(const void *src1, const void *src2, const void *mask, void *dst, unsigned depth, unsigned offset, unsigned n)
{
const uint16_t *srcp1 = src1;
const uint16_t *srcp2 = src2;
const uint16_t *maskp = mask;
uint16_t *dstp = dst;
unsigned i;
uint16_t maxval = (1U << depth) - 1;
for (i = 0; i < n; i += 8) {
__m128i v1 = _mm_load_si128((const __m128i *)(srcp1 + i));
__m128i v2 = _mm_load_si128((const __m128i *)(srcp2 + i));
__m128i w2 = _mm_load_si128((const __m128i *)(maskp + i));
__m128i w1 = _mm_sub_epi16(_mm_set1_epi16(maxval), w2);
__m128i neg, sign, tmp, tmp_lo, tmp_hi, tmpd_lo, tmpd_hi, negd, signd;
tmp = _mm_sub_epi16(v1, _mm_set1_epi16(offset));
sign = _mm_cmplt_epi16(_mm_add_epi16(v1, _mm_set1_epi16(INT16_MIN)), _mm_set1_epi16(offset + INT16_MIN));
neg = _mm_sub_epi16(_mm_setzero_si128(), tmp);
tmp = _mm_or_si128(_mm_andnot_si128(sign, tmp), _mm_and_si128(sign, neg));
tmp_lo = _mm_mullo_epi16(w1, tmp);
tmp_hi = _mm_mulhi_epu16(w1, tmp);
tmpd_lo = _mm_unpacklo_epi16(tmp_lo, tmp_hi);
tmpd_lo = _mm_add_epi32(tmpd_lo, _mm_set1_epi32(maxval / 2));
tmpd_lo = divX_epu32(tmpd_lo, depth);
signd = _mm_unpacklo_epi16(sign, sign);
negd = _mm_sub_epi32(_mm_setzero_si128(), tmpd_lo);
tmpd_lo = _mm_or_si128(_mm_andnot_si128(signd, tmpd_lo), _mm_and_si128(signd, negd));
tmpd_hi = _mm_unpackhi_epi16(tmp_lo, tmp_hi);
tmpd_hi = _mm_add_epi32(tmpd_hi, _mm_set1_epi32(maxval / 2));
tmpd_hi = divX_epu32(tmpd_hi, depth);
signd = _mm_unpackhi_epi16(sign, sign);
negd = _mm_sub_epi32(_mm_setzero_si128(), tmpd_hi);
tmpd_hi = _mm_or_si128(_mm_andnot_si128(signd, tmpd_hi), _mm_and_si128(signd, negd));
tmpd_lo = _mm_add_epi32(tmpd_lo, _mm_unpacklo_epi16(v2, _mm_setzero_si128()));
tmpd_lo = _mm_add_epi32(tmpd_lo, _mm_set1_epi32(INT16_MIN));
tmpd_hi = _mm_add_epi32(tmpd_hi, _mm_unpackhi_epi16(v2, _mm_setzero_si128()));
tmpd_hi = _mm_add_epi32(tmpd_hi, _mm_set1_epi32(INT16_MIN));
tmp = _mm_packs_epi32(tmpd_lo, tmpd_hi);
tmp = _mm_min_epi16(tmp, _mm_set1_epi16(maxval + INT16_MIN));
tmp = _mm_sub_epi16(tmp, _mm_set1_epi16(INT16_MIN));
_mm_store_si128((__m128i *)(dstp + i), tmp);
}
}
void vs_mask_merge_premul_float_sse2(const void *src1, const void *src2, const void *mask, void *dst, unsigned depth, unsigned offset, unsigned n)
{
const float *srcp1 = src1;
const float *srcp2 = src2;
const float *maskp = mask;
float *dstp = dst;
unsigned i;
(void)depth;
(void)offset;
for (i = 0; i < n; i += 4) {
__m128 v1 = _mm_load_ps(srcp1 + i);
__m128 v2 = _mm_load_ps(srcp2 + i);
__m128 w1 = _mm_sub_ps(_mm_set_ps1(1.0f), _mm_load_ps(maskp + i));
__m128 result = _mm_add_ps(_mm_mul_ps(w1, v1), v2);
_mm_store_ps(dstp + i, result);
}
}
void vs_makediff_byte_sse2(const void *src1, const void *src2, void *dst, unsigned depth, unsigned n)
{
const uint8_t *srcp1 = src1;
const uint8_t *srcp2 = src2;
uint8_t *dstp = dst;
unsigned i;
(void)depth;
for (i = 0; i < n; i += 16) {
__m128i v1 = _mm_load_si128((const __m128i *)(srcp1 + i));
__m128i v2 = _mm_load_si128((const __m128i *)(srcp2 + i));
__m128i diff = _mm_subs_epi8(_mm_add_epi8(v1, _mm_set1_epi8(INT8_MIN)), _mm_add_epi8(v2, _mm_set1_epi8(INT8_MIN)));
diff = _mm_sub_epi8(diff, _mm_set1_epi8(INT8_MIN));
_mm_store_si128((__m128i *)(dstp + i), diff);
}
}
void vs_makediff_word_sse2(const void *src1, const void *src2, void *dst, unsigned depth, unsigned n)
{
const uint16_t *srcp1 = src1;
const uint16_t *srcp2 = src2;
uint16_t *dstp = dst;
unsigned i;
int32_t maxval = (1 << (depth - 1)) - 1;
int32_t minval = -maxval - 1;
for (i = 0; i < n; i += 8) {
__m128i v1 = _mm_load_si128((const __m128i *)(srcp1 + i));
__m128i v2 = _mm_load_si128((const __m128i *)(srcp2 + i));
__m128i diff = _mm_subs_epi16(_mm_add_epi16(v1, _mm_set1_epi16(minval)), _mm_add_epi16(v2, _mm_set1_epi16(minval)));
diff = _mm_min_epi16(_mm_max_epi16(diff, _mm_set1_epi16(minval)), _mm_set1_epi16(maxval));
diff = _mm_sub_epi16(diff, _mm_set1_epi16(minval));
_mm_store_si128((__m128i *)(dstp + i), diff);
}
}
void vs_makediff_float_sse2(const void *src1, const void *src2, void *dst, unsigned depth, unsigned n)
{
const float *srcp1 = src1;
const float *srcp2 = src2;
float *dstp = dst;
unsigned i;
(void)depth;
for (i = 0; i < n; i += 4) {
__m128 v1 = _mm_load_ps(srcp1 + i);
__m128 v2 = _mm_load_ps(srcp2 + i);
_mm_store_ps(dstp + i, _mm_sub_ps(v1, v2));
}
}
void vs_mergediff_byte_sse2(const void *src1, const void *src2, void *dst, unsigned depth, unsigned n)
{
const uint8_t *srcp1 = src1;
const uint8_t *srcp2 = src2;
uint8_t *dstp = dst;
unsigned i;
(void)depth;
for (i = 0; i < n; i += 16) {
__m128i v1 = _mm_load_si128((const __m128i *)(srcp1 + i));
__m128i v2 = _mm_load_si128((const __m128i *)(srcp2 + i));
__m128i tmp = _mm_adds_epi8(_mm_add_epi8(v1, _mm_set1_epi8(INT8_MIN)), _mm_add_epi8(v2, _mm_set1_epi8(INT8_MIN)));
tmp = _mm_sub_epi8(tmp, _mm_set1_epi8(INT8_MIN));
_mm_store_si128((__m128i *)(dstp + i), tmp);
}
}
void vs_mergediff_word_sse2(const void *src1, const void *src2, void *dst, unsigned depth, unsigned n)
{
const uint16_t *srcp1 = src1;
const uint16_t *srcp2 = src2;
uint16_t *dstp = dst;
unsigned i;
int32_t maxval = (1 << (depth - 1)) - 1;
int32_t minval = -maxval - 1;
for (i = 0; i < n; i += 8) {
__m128i v1 = _mm_load_si128((const __m128i *)(srcp1 + i));
__m128i v2 = _mm_load_si128((const __m128i *)(srcp2 + i));
__m128i tmp = _mm_adds_epi16(_mm_add_epi16(v1, _mm_set1_epi16(minval)), _mm_add_epi16(v2, _mm_set1_epi16(minval)));
tmp = _mm_min_epi16(_mm_max_epi16(tmp, _mm_set1_epi16(minval)), _mm_set1_epi16(maxval));
tmp = _mm_sub_epi16(tmp, _mm_set1_epi16(minval));
_mm_store_si128((__m128i *)(dstp + i), tmp);
}
}
void vs_mergediff_float_sse2(const void *src1, const void *src2, void *dst, unsigned depth, unsigned n)
{
const float *srcp1 = src1;
const float *srcp2 = src2;
float *dstp = dst;
unsigned i;
(void)depth;
for (i = 0; i < n; i += 4) {
__m128 v1 = _mm_load_ps(srcp1 + i);
__m128 v2 = _mm_load_ps(srcp2 + i);
_mm_store_ps(dstp + i, _mm_add_ps(v1, v2));
}
}