blob: 4f77da4463e6922203dd19e920379eb692767316 [file] [log] [blame]
/*
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#include <smmintrin.h>
#include "./av1_rtcd.h"
#include "aom_ports/mem.h"
#include "av1/common/enums.h"
#include "av1/common/reconintra.h"
#if USE_3TAP_INTRA_FILTER
void filterintra_sse4_3tap_dummy_func(void);
void filterintra_sse4_3tap_dummy_func(void) {}
#else
static INLINE void AddPixelsSmall(const uint8_t *above, const uint8_t *left,
__m128i *sum) {
const __m128i a = _mm_loadu_si128((const __m128i *)above);
const __m128i l = _mm_loadu_si128((const __m128i *)left);
const __m128i zero = _mm_setzero_si128();
__m128i u0 = _mm_unpacklo_epi8(a, zero);
__m128i u1 = _mm_unpacklo_epi8(l, zero);
sum[0] = _mm_add_epi16(u0, u1);
}
static INLINE int GetMeanValue4x4(const uint8_t *above, const uint8_t *left,
__m128i *params) {
const __m128i zero = _mm_setzero_si128();
__m128i sum_vector, u;
uint16_t sum_value;
AddPixelsSmall(above, left, &sum_vector);
sum_vector = _mm_hadd_epi16(sum_vector, zero); // still has 2 values
u = _mm_srli_si128(sum_vector, 2);
sum_vector = _mm_add_epi16(sum_vector, u);
sum_value = _mm_extract_epi16(sum_vector, 0);
sum_value += 4;
sum_value >>= 3;
*params = _mm_set1_epi32(sum_value);
return sum_value;
}
static INLINE int GetMeanValue8x8(const uint8_t *above, const uint8_t *left,
__m128i *params) {
const __m128i zero = _mm_setzero_si128();
__m128i sum_vector, u;
uint16_t sum_value;
AddPixelsSmall(above, left, &sum_vector);
sum_vector = _mm_hadd_epi16(sum_vector, zero); // still has 4 values
sum_vector = _mm_hadd_epi16(sum_vector, zero); // still has 2 values
u = _mm_srli_si128(sum_vector, 2);
sum_vector = _mm_add_epi16(sum_vector, u);
sum_value = _mm_extract_epi16(sum_vector, 0);
sum_value += 8;
sum_value >>= 4;
*params = _mm_set1_epi32(sum_value);
return sum_value;
}
static INLINE void AddPixelsLarge(const uint8_t *above, const uint8_t *left,
__m128i *sum) {
const __m128i a = _mm_loadu_si128((const __m128i *)above);
const __m128i l = _mm_loadu_si128((const __m128i *)left);
const __m128i zero = _mm_setzero_si128();
__m128i u0 = _mm_unpacklo_epi8(a, zero);
__m128i u1 = _mm_unpacklo_epi8(l, zero);
sum[0] = _mm_add_epi16(u0, u1);
u0 = _mm_unpackhi_epi8(a, zero);
u1 = _mm_unpackhi_epi8(l, zero);
sum[0] = _mm_add_epi16(sum[0], u0);
sum[0] = _mm_add_epi16(sum[0], u1);
}
static INLINE int GetMeanValue16x16(const uint8_t *above, const uint8_t *left,
__m128i *params) {
const __m128i zero = _mm_setzero_si128();
__m128i sum_vector, u;
uint16_t sum_value;
AddPixelsLarge(above, left, &sum_vector);
sum_vector = _mm_hadd_epi16(sum_vector, zero); // still has 4 values
sum_vector = _mm_hadd_epi16(sum_vector, zero); // still has 2 values
u = _mm_srli_si128(sum_vector, 2);
sum_vector = _mm_add_epi16(sum_vector, u);
sum_value = _mm_extract_epi16(sum_vector, 0);
sum_value += 16;
sum_value >>= 5;
*params = _mm_set1_epi32(sum_value);
return sum_value;
}
static INLINE int GetMeanValue32x32(const uint8_t *above, const uint8_t *left,
__m128i *params) {
const __m128i zero = _mm_setzero_si128();
__m128i sum_vector[2], u;
uint16_t sum_value;
AddPixelsLarge(above, left, &sum_vector[0]);
AddPixelsLarge(above + 16, left + 16, &sum_vector[1]);
sum_vector[0] = _mm_add_epi16(sum_vector[0], sum_vector[1]);
sum_vector[0] = _mm_hadd_epi16(sum_vector[0], zero); // still has 4 values
sum_vector[0] = _mm_hadd_epi16(sum_vector[0], zero); // still has 2 values
u = _mm_srli_si128(sum_vector[0], 2);
sum_vector[0] = _mm_add_epi16(sum_vector[0], u);
sum_value = _mm_extract_epi16(sum_vector[0], 0);
sum_value += 32;
sum_value >>= 6;
*params = _mm_set1_epi32(sum_value);
return sum_value;
}
// Note:
// params[4] : mean value, 4 int32_t repetition
//
static INLINE int CalcRefPixelsMeanValue(const uint8_t *above,
const uint8_t *left, int bs,
__m128i *params) {
int meanValue = 0;
switch (bs) {
case 4: meanValue = GetMeanValue4x4(above, left, params); break;
case 8: meanValue = GetMeanValue8x8(above, left, params); break;
case 16: meanValue = GetMeanValue16x16(above, left, params); break;
case 32: meanValue = GetMeanValue32x32(above, left, params); break;
default: assert(0);
}
return meanValue;
}
// Note:
// params[0-3] : 4-tap filter coefficients (int32_t per coefficient)
//
static INLINE void GetIntraFilterParams(int bs, int mode, __m128i *params) {
const TX_SIZE tx_size =
(bs == 32) ? TX_32X32
: ((bs == 16) ? TX_16X16 : ((bs == 8) ? TX_8X8 : (TX_4X4)));
// c0
params[0] = _mm_set_epi32(av1_filter_intra_taps_4[tx_size][mode][0],
av1_filter_intra_taps_4[tx_size][mode][0],
av1_filter_intra_taps_4[tx_size][mode][0],
av1_filter_intra_taps_4[tx_size][mode][0]);
// c1
params[1] = _mm_set_epi32(av1_filter_intra_taps_4[tx_size][mode][1],
av1_filter_intra_taps_4[tx_size][mode][1],
av1_filter_intra_taps_4[tx_size][mode][1],
av1_filter_intra_taps_4[tx_size][mode][1]);
// c2
params[2] = _mm_set_epi32(av1_filter_intra_taps_4[tx_size][mode][2],
av1_filter_intra_taps_4[tx_size][mode][2],
av1_filter_intra_taps_4[tx_size][mode][2],
av1_filter_intra_taps_4[tx_size][mode][2]);
// c3
params[3] = _mm_set_epi32(av1_filter_intra_taps_4[tx_size][mode][3],
av1_filter_intra_taps_4[tx_size][mode][3],
av1_filter_intra_taps_4[tx_size][mode][3],
av1_filter_intra_taps_4[tx_size][mode][3]);
}
static const int maxBlkSize = 32;
static INLINE void SavePred4x4(int *pred, const __m128i *mean, uint8_t *dst,
ptrdiff_t stride) {
const int predStride = (maxBlkSize << 1) + 1;
__m128i p0 = _mm_loadu_si128((const __m128i *)pred);
__m128i p1 = _mm_loadu_si128((const __m128i *)(pred + predStride));
__m128i p2 = _mm_loadu_si128((const __m128i *)(pred + 2 * predStride));
__m128i p3 = _mm_loadu_si128((const __m128i *)(pred + 3 * predStride));
p0 = _mm_add_epi32(p0, mean[0]);
p1 = _mm_add_epi32(p1, mean[0]);
p2 = _mm_add_epi32(p2, mean[0]);
p3 = _mm_add_epi32(p3, mean[0]);
p0 = _mm_packus_epi32(p0, p1);
p1 = _mm_packus_epi32(p2, p3);
p0 = _mm_packus_epi16(p0, p1);
*((int *)dst) = _mm_cvtsi128_si32(p0);
p0 = _mm_srli_si128(p0, 4);
*((int *)(dst + stride)) = _mm_cvtsi128_si32(p0);
p0 = _mm_srli_si128(p0, 4);
*((int *)(dst + 2 * stride)) = _mm_cvtsi128_si32(p0);
p0 = _mm_srli_si128(p0, 4);
*((int *)(dst + 3 * stride)) = _mm_cvtsi128_si32(p0);
}
static void SavePred8x8(int *pred, const __m128i *mean, uint8_t *dst,
ptrdiff_t stride) {
const int predStride = (maxBlkSize << 1) + 1;
__m128i p0, p1, p2, p3;
int r = 0;
while (r < 8) {
p0 = _mm_loadu_si128((const __m128i *)(pred + r * predStride));
p1 = _mm_loadu_si128((const __m128i *)(pred + r * predStride + 4));
r += 1;
p2 = _mm_loadu_si128((const __m128i *)(pred + r * predStride));
p3 = _mm_loadu_si128((const __m128i *)(pred + r * predStride + 4));
p0 = _mm_add_epi32(p0, mean[0]);
p1 = _mm_add_epi32(p1, mean[0]);
p2 = _mm_add_epi32(p2, mean[0]);
p3 = _mm_add_epi32(p3, mean[0]);
p0 = _mm_packus_epi32(p0, p1);
p1 = _mm_packus_epi32(p2, p3);
p0 = _mm_packus_epi16(p0, p1);
_mm_storel_epi64((__m128i *)dst, p0);
dst += stride;
p0 = _mm_srli_si128(p0, 8);
_mm_storel_epi64((__m128i *)dst, p0);
dst += stride;
r += 1;
}
}
static void SavePred16x16(int *pred, const __m128i *mean, uint8_t *dst,
ptrdiff_t stride) {
const int predStride = (maxBlkSize << 1) + 1;
__m128i p0, p1, p2, p3;
int r = 0;
while (r < 16) {
p0 = _mm_loadu_si128((const __m128i *)(pred + r * predStride));
p1 = _mm_loadu_si128((const __m128i *)(pred + r * predStride + 4));
p2 = _mm_loadu_si128((const __m128i *)(pred + r * predStride + 8));
p3 = _mm_loadu_si128((const __m128i *)(pred + r * predStride + 12));
p0 = _mm_add_epi32(p0, mean[0]);
p1 = _mm_add_epi32(p1, mean[0]);
p2 = _mm_add_epi32(p2, mean[0]);
p3 = _mm_add_epi32(p3, mean[0]);
p0 = _mm_packus_epi32(p0, p1);
p1 = _mm_packus_epi32(p2, p3);
p0 = _mm_packus_epi16(p0, p1);
_mm_storel_epi64((__m128i *)dst, p0);
p0 = _mm_srli_si128(p0, 8);
_mm_storel_epi64((__m128i *)(dst + 8), p0);
dst += stride;
r += 1;
}
}
static void SavePred32x32(int *pred, const __m128i *mean, uint8_t *dst,
ptrdiff_t stride) {
const int predStride = (maxBlkSize << 1) + 1;
__m128i p0, p1, p2, p3, p4, p5, p6, p7;
int r = 0;
while (r < 32) {
p0 = _mm_loadu_si128((const __m128i *)(pred + r * predStride));
p1 = _mm_loadu_si128((const __m128i *)(pred + r * predStride + 4));
p2 = _mm_loadu_si128((const __m128i *)(pred + r * predStride + 8));
p3 = _mm_loadu_si128((const __m128i *)(pred + r * predStride + 12));
p4 = _mm_loadu_si128((const __m128i *)(pred + r * predStride + 16));
p5 = _mm_loadu_si128((const __m128i *)(pred + r * predStride + 20));
p6 = _mm_loadu_si128((const __m128i *)(pred + r * predStride + 24));
p7 = _mm_loadu_si128((const __m128i *)(pred + r * predStride + 28));
p0 = _mm_add_epi32(p0, mean[0]);
p1 = _mm_add_epi32(p1, mean[0]);
p2 = _mm_add_epi32(p2, mean[0]);
p3 = _mm_add_epi32(p3, mean[0]);
p4 = _mm_add_epi32(p4, mean[0]);
p5 = _mm_add_epi32(p5, mean[0]);
p6 = _mm_add_epi32(p6, mean[0]);
p7 = _mm_add_epi32(p7, mean[0]);
p0 = _mm_packus_epi32(p0, p1);
p1 = _mm_packus_epi32(p2, p3);
p0 = _mm_packus_epi16(p0, p1);
p4 = _mm_packus_epi32(p4, p5);
p5 = _mm_packus_epi32(p6, p7);
p4 = _mm_packus_epi16(p4, p5);
_mm_storel_epi64((__m128i *)dst, p0);
p0 = _mm_srli_si128(p0, 8);
_mm_storel_epi64((__m128i *)(dst + 8), p0);
_mm_storel_epi64((__m128i *)(dst + 16), p4);
p4 = _mm_srli_si128(p4, 8);
_mm_storel_epi64((__m128i *)(dst + 24), p4);
dst += stride;
r += 1;
}
}
static void SavePrediction(int *pred, const __m128i *mean, int bs, uint8_t *dst,
ptrdiff_t stride) {
switch (bs) {
case 4: SavePred4x4(pred, mean, dst, stride); break;
case 8: SavePred8x8(pred, mean, dst, stride); break;
case 16: SavePred16x16(pred, mean, dst, stride); break;
case 32: SavePred32x32(pred, mean, dst, stride); break;
default: assert(0);
}
}
typedef void (*ProducePixelsFunc)(__m128i *p, const __m128i *prm, int *pred,
const int predStride);
static void ProduceFourPixels(__m128i *p, const __m128i *prm, int *pred,
const int predStride) {
__m128i u0, u1, u2;
int c0 = _mm_extract_epi32(prm[1], 0);
int x = *(pred + predStride);
int sum;
u0 = _mm_mullo_epi32(p[0], prm[2]);
u1 = _mm_mullo_epi32(p[1], prm[0]);
u2 = _mm_mullo_epi32(p[2], prm[3]);
u0 = _mm_add_epi32(u0, u1);
u0 = _mm_add_epi32(u0, u2);
sum = _mm_extract_epi32(u0, 0);
sum += c0 * x;
x = ROUND_POWER_OF_TWO_SIGNED(sum, FILTER_INTRA_PREC_BITS);
*(pred + predStride + 1) = x;
sum = _mm_extract_epi32(u0, 1);
sum += c0 * x;
x = ROUND_POWER_OF_TWO_SIGNED(sum, FILTER_INTRA_PREC_BITS);
*(pred + predStride + 2) = x;
sum = _mm_extract_epi32(u0, 2);
sum += c0 * x;
x = ROUND_POWER_OF_TWO_SIGNED(sum, FILTER_INTRA_PREC_BITS);
*(pred + predStride + 3) = x;
sum = _mm_extract_epi32(u0, 3);
sum += c0 * x;
x = ROUND_POWER_OF_TWO_SIGNED(sum, FILTER_INTRA_PREC_BITS);
*(pred + predStride + 4) = x;
}
static void ProduceThreePixels(__m128i *p, const __m128i *prm, int *pred,
const int predStride) {
__m128i u0, u1, u2;
int c0 = _mm_extract_epi32(prm[1], 0);
int x = *(pred + predStride);
int sum;
u0 = _mm_mullo_epi32(p[0], prm[2]);
u1 = _mm_mullo_epi32(p[1], prm[0]);
u2 = _mm_mullo_epi32(p[2], prm[3]);
u0 = _mm_add_epi32(u0, u1);
u0 = _mm_add_epi32(u0, u2);
sum = _mm_extract_epi32(u0, 0);
sum += c0 * x;
x = ROUND_POWER_OF_TWO_SIGNED(sum, FILTER_INTRA_PREC_BITS);
*(pred + predStride + 1) = x;
sum = _mm_extract_epi32(u0, 1);
sum += c0 * x;
x = ROUND_POWER_OF_TWO_SIGNED(sum, FILTER_INTRA_PREC_BITS);
*(pred + predStride + 2) = x;
sum = _mm_extract_epi32(u0, 2);
sum += c0 * x;
x = ROUND_POWER_OF_TWO_SIGNED(sum, FILTER_INTRA_PREC_BITS);
*(pred + predStride + 3) = x;
}
static void ProduceTwoPixels(__m128i *p, const __m128i *prm, int *pred,
const int predStride) {
__m128i u0, u1, u2;
int c0 = _mm_extract_epi32(prm[1], 0);
int x = *(pred + predStride);
int sum;
u0 = _mm_mullo_epi32(p[0], prm[2]);
u1 = _mm_mullo_epi32(p[1], prm[0]);
u2 = _mm_mullo_epi32(p[2], prm[3]);
u0 = _mm_add_epi32(u0, u1);
u0 = _mm_add_epi32(u0, u2);
sum = _mm_extract_epi32(u0, 0);
sum += c0 * x;
x = ROUND_POWER_OF_TWO_SIGNED(sum, FILTER_INTRA_PREC_BITS);
*(pred + predStride + 1) = x;
sum = _mm_extract_epi32(u0, 1);
sum += c0 * x;
x = ROUND_POWER_OF_TWO_SIGNED(sum, FILTER_INTRA_PREC_BITS);
*(pred + predStride + 2) = x;
}
static void ProduceOnePixels(__m128i *p, const __m128i *prm, int *pred,
const int predStride) {
__m128i u0, u1, u2;
int c0 = _mm_extract_epi32(prm[1], 0);
int x = *(pred + predStride);
int sum;
u0 = _mm_mullo_epi32(p[0], prm[2]);
u1 = _mm_mullo_epi32(p[1], prm[0]);
u2 = _mm_mullo_epi32(p[2], prm[3]);
u0 = _mm_add_epi32(u0, u1);
u0 = _mm_add_epi32(u0, u2);
sum = _mm_extract_epi32(u0, 0);
sum += c0 * x;
x = ROUND_POWER_OF_TWO_SIGNED(sum, FILTER_INTRA_PREC_BITS);
*(pred + predStride + 1) = x;
}
static ProducePixelsFunc prodPixelsFuncTab[4] = {
ProduceOnePixels, ProduceTwoPixels, ProduceThreePixels, ProduceFourPixels
};
static void ProducePixels(int *pred, const __m128i *prm, int remain) {
__m128i p[3];
const int predStride = (maxBlkSize << 1) + 1;
int index;
p[0] = _mm_loadu_si128((const __m128i *)pred);
p[1] = _mm_loadu_si128((const __m128i *)(pred + 1));
p[2] = _mm_loadu_si128((const __m128i *)(pred + 2));
if (remain <= 2) {
return;
}
if (remain > 5) {
index = 3;
} else {
index = remain - 3;
}
prodPixelsFuncTab[index](p, prm, pred, predStride);
}
// Note:
// At column index c, the remaining pixels are R = 2 * bs + 1 - r - c
// the number of pixels to produce is R - 2 = 2 * bs - r - c - 1
static void GeneratePrediction(const uint8_t *above, const uint8_t *left,
const int bs, const __m128i *prm, int meanValue,
uint8_t *dst, ptrdiff_t stride) {
int pred[33][65];
int r, c, colBound;
int remainings;
for (r = 0; r < bs; ++r) {
pred[r + 1][0] = (int)left[r] - meanValue;
}
above -= 1;
for (c = 0; c < 2 * bs + 1; ++c) {
pred[0][c] = (int)above[c] - meanValue;
}
r = 0;
c = 0;
while (r < bs) {
colBound = (bs << 1) - r;
for (c = 0; c < colBound; c += 4) {
remainings = colBound - c + 1;
ProducePixels(&pred[r][c], prm, remainings);
}
r += 1;
}
SavePrediction(&pred[1][1], &prm[4], bs, dst, stride);
}
static void FilterPrediction(const uint8_t *above, const uint8_t *left, int bs,
__m128i *prm, uint8_t *dst, ptrdiff_t stride) {
int meanValue = 0;
meanValue = CalcRefPixelsMeanValue(above, left, bs, &prm[4]);
GeneratePrediction(above, left, bs, prm, meanValue, dst, stride);
}
void av1_dc_filter_predictor_sse4_1(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left) {
__m128i prm[5];
GetIntraFilterParams(bs, DC_PRED, &prm[0]);
FilterPrediction(above, left, bs, prm, dst, stride);
}
void av1_v_filter_predictor_sse4_1(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left) {
__m128i prm[5];
GetIntraFilterParams(bs, V_PRED, &prm[0]);
FilterPrediction(above, left, bs, prm, dst, stride);
}
void av1_h_filter_predictor_sse4_1(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left) {
__m128i prm[5];
GetIntraFilterParams(bs, H_PRED, &prm[0]);
FilterPrediction(above, left, bs, prm, dst, stride);
}
void av1_d45_filter_predictor_sse4_1(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above,
const uint8_t *left) {
__m128i prm[5];
GetIntraFilterParams(bs, D45_PRED, &prm[0]);
FilterPrediction(above, left, bs, prm, dst, stride);
}
void av1_d135_filter_predictor_sse4_1(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above,
const uint8_t *left) {
__m128i prm[5];
GetIntraFilterParams(bs, D135_PRED, &prm[0]);
FilterPrediction(above, left, bs, prm, dst, stride);
}
void av1_d117_filter_predictor_sse4_1(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above,
const uint8_t *left) {
__m128i prm[5];
GetIntraFilterParams(bs, D117_PRED, &prm[0]);
FilterPrediction(above, left, bs, prm, dst, stride);
}
void av1_d153_filter_predictor_sse4_1(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above,
const uint8_t *left) {
__m128i prm[5];
GetIntraFilterParams(bs, D153_PRED, &prm[0]);
FilterPrediction(above, left, bs, prm, dst, stride);
}
void av1_d207_filter_predictor_sse4_1(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above,
const uint8_t *left) {
__m128i prm[5];
GetIntraFilterParams(bs, D207_PRED, &prm[0]);
FilterPrediction(above, left, bs, prm, dst, stride);
}
void av1_d63_filter_predictor_sse4_1(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above,
const uint8_t *left) {
__m128i prm[5];
GetIntraFilterParams(bs, D63_PRED, &prm[0]);
FilterPrediction(above, left, bs, prm, dst, stride);
}
void av1_tm_filter_predictor_sse4_1(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left) {
__m128i prm[5];
GetIntraFilterParams(bs, TM_PRED, &prm[0]);
FilterPrediction(above, left, bs, prm, dst, stride);
}
// ============== High Bit Depth ==============
#if CONFIG_HIGHBITDEPTH
static INLINE int HighbdGetMeanValue4x4(const uint16_t *above,
const uint16_t *left, const int bd,
__m128i *params) {
const __m128i a = _mm_loadu_si128((const __m128i *)above);
const __m128i l = _mm_loadu_si128((const __m128i *)left);
const __m128i zero = _mm_setzero_si128();
__m128i sum_vector, u;
uint16_t sum_value;
(void)bd;
sum_vector = _mm_add_epi16(a, l);
sum_vector = _mm_hadd_epi16(sum_vector, zero); // still has 2 values
u = _mm_srli_si128(sum_vector, 2);
sum_vector = _mm_add_epi16(sum_vector, u);
sum_value = _mm_extract_epi16(sum_vector, 0);
sum_value += 4;
sum_value >>= 3;
*params = _mm_set1_epi32(sum_value);
return sum_value;
}
static INLINE int HighbdGetMeanValue8x8(const uint16_t *above,
const uint16_t *left, const int bd,
__m128i *params) {
const __m128i a = _mm_loadu_si128((const __m128i *)above);
const __m128i l = _mm_loadu_si128((const __m128i *)left);
const __m128i zero = _mm_setzero_si128();
__m128i sum_vector, u;
uint16_t sum_value;
(void)bd;
sum_vector = _mm_add_epi16(a, l);
sum_vector = _mm_hadd_epi16(sum_vector, zero); // still has 4 values
sum_vector = _mm_hadd_epi16(sum_vector, zero); // still has 2 values
u = _mm_srli_si128(sum_vector, 2);
sum_vector = _mm_add_epi16(sum_vector, u);
sum_value = _mm_extract_epi16(sum_vector, 0);
sum_value += 8;
sum_value >>= 4;
*params = _mm_set1_epi32(sum_value);
return sum_value;
}
// Note:
// Process 16 pixels above and left, 10-bit depth
// Add to the last 8 pixels sum
static INLINE void AddPixels10bit(const uint16_t *above, const uint16_t *left,
__m128i *sum) {
__m128i a = _mm_loadu_si128((const __m128i *)above);
__m128i l = _mm_loadu_si128((const __m128i *)left);
sum[0] = _mm_add_epi16(a, l);
a = _mm_loadu_si128((const __m128i *)(above + 8));
l = _mm_loadu_si128((const __m128i *)(left + 8));
sum[0] = _mm_add_epi16(sum[0], a);
sum[0] = _mm_add_epi16(sum[0], l);
}
// Note:
// Process 16 pixels above and left, 12-bit depth
// Add to the last 8 pixels sum
static INLINE void AddPixels12bit(const uint16_t *above, const uint16_t *left,
__m128i *sum) {
__m128i a = _mm_loadu_si128((const __m128i *)above);
__m128i l = _mm_loadu_si128((const __m128i *)left);
const __m128i zero = _mm_setzero_si128();
__m128i v0, v1;
v0 = _mm_unpacklo_epi16(a, zero);
v1 = _mm_unpacklo_epi16(l, zero);
sum[0] = _mm_add_epi32(v0, v1);
v0 = _mm_unpackhi_epi16(a, zero);
v1 = _mm_unpackhi_epi16(l, zero);
sum[0] = _mm_add_epi32(sum[0], v0);
sum[0] = _mm_add_epi32(sum[0], v1);
a = _mm_loadu_si128((const __m128i *)(above + 8));
l = _mm_loadu_si128((const __m128i *)(left + 8));
v0 = _mm_unpacklo_epi16(a, zero);
v1 = _mm_unpacklo_epi16(l, zero);
sum[0] = _mm_add_epi32(sum[0], v0);
sum[0] = _mm_add_epi32(sum[0], v1);
v0 = _mm_unpackhi_epi16(a, zero);
v1 = _mm_unpackhi_epi16(l, zero);
sum[0] = _mm_add_epi32(sum[0], v0);
sum[0] = _mm_add_epi32(sum[0], v1);
}
static INLINE int HighbdGetMeanValue16x16(const uint16_t *above,
const uint16_t *left, const int bd,
__m128i *params) {
const __m128i zero = _mm_setzero_si128();
__m128i sum_vector, u;
uint32_t sum_value = 0;
if (10 == bd) {
AddPixels10bit(above, left, &sum_vector);
sum_vector = _mm_hadd_epi16(sum_vector, zero); // still has 4 values
sum_vector = _mm_hadd_epi16(sum_vector, zero); // still has 2 values
u = _mm_srli_si128(sum_vector, 2);
sum_vector = _mm_add_epi16(sum_vector, u);
sum_value = _mm_extract_epi16(sum_vector, 0);
} else if (12 == bd) {
AddPixels12bit(above, left, &sum_vector);
sum_vector = _mm_hadd_epi32(sum_vector, zero);
u = _mm_srli_si128(sum_vector, 4);
sum_vector = _mm_add_epi32(u, sum_vector);
sum_value = _mm_extract_epi32(sum_vector, 0);
}
sum_value += 16;
sum_value >>= 5;
*params = _mm_set1_epi32(sum_value);
return sum_value;
}
static INLINE int HighbdGetMeanValue32x32(const uint16_t *above,
const uint16_t *left, const int bd,
__m128i *params) {
const __m128i zero = _mm_setzero_si128();
__m128i sum_vector[2], u;
uint32_t sum_value = 0;
if (10 == bd) {
AddPixels10bit(above, left, &sum_vector[0]);
AddPixels10bit(above + 16, left + 16, &sum_vector[1]);
sum_vector[0] = _mm_add_epi16(sum_vector[0], sum_vector[1]);
sum_vector[0] = _mm_hadd_epi16(sum_vector[0], zero); // still has 4 values
sum_vector[0] = _mm_hadd_epi16(sum_vector[0], zero); // still has 2 values
u = _mm_srli_si128(sum_vector[0], 2);
sum_vector[0] = _mm_add_epi16(sum_vector[0], u);
sum_value = _mm_extract_epi16(sum_vector[0], 0);
} else if (12 == bd) {
AddPixels12bit(above, left, &sum_vector[0]);
AddPixels12bit(above + 16, left + 16, &sum_vector[1]);
sum_vector[0] = _mm_add_epi32(sum_vector[0], sum_vector[1]);
sum_vector[0] = _mm_hadd_epi32(sum_vector[0], zero);
u = _mm_srli_si128(sum_vector[0], 4);
sum_vector[0] = _mm_add_epi32(u, sum_vector[0]);
sum_value = _mm_extract_epi32(sum_vector[0], 0);
}
sum_value += 32;
sum_value >>= 6;
*params = _mm_set1_epi32(sum_value);
return sum_value;
}
// Note:
// params[4] : mean value, 4 int32_t repetition
//
static INLINE int HighbdCalcRefPixelsMeanValue(const uint16_t *above,
const uint16_t *left, int bs,
const int bd, __m128i *params) {
int meanValue = 0;
switch (bs) {
case 4: meanValue = HighbdGetMeanValue4x4(above, left, bd, params); break;
case 8: meanValue = HighbdGetMeanValue8x8(above, left, bd, params); break;
case 16:
meanValue = HighbdGetMeanValue16x16(above, left, bd, params);
break;
case 32:
meanValue = HighbdGetMeanValue32x32(above, left, bd, params);
break;
default: assert(0);
}
return meanValue;
}
// Note:
// At column index c, the remaining pixels are R = 2 * bs + 1 - r - c
// the number of pixels to produce is R - 2 = 2 * bs - r - c - 1
static void HighbdGeneratePrediction(const uint16_t *above,
const uint16_t *left, const int bs,
const int bd, const __m128i *prm,
int meanValue, uint16_t *dst,
ptrdiff_t stride) {
int pred[33][65];
int r, c, colBound;
int remainings;
int ipred;
for (r = 0; r < bs; ++r) {
pred[r + 1][0] = (int)left[r] - meanValue;
}
above -= 1;
for (c = 0; c < 2 * bs + 1; ++c) {
pred[0][c] = (int)above[c] - meanValue;
}
r = 0;
c = 0;
while (r < bs) {
colBound = (bs << 1) - r;
for (c = 0; c < colBound; c += 4) {
remainings = colBound - c + 1;
ProducePixels(&pred[r][c], prm, remainings);
}
r += 1;
}
for (r = 0; r < bs; ++r) {
for (c = 0; c < bs; ++c) {
ipred = pred[r + 1][c + 1] + meanValue;
dst[c] = clip_pixel_highbd(ipred, bd);
}
dst += stride;
}
}
static void HighbdFilterPrediction(const uint16_t *above, const uint16_t *left,
int bs, const int bd, __m128i *prm,
uint16_t *dst, ptrdiff_t stride) {
int meanValue = 0;
meanValue = HighbdCalcRefPixelsMeanValue(above, left, bs, bd, &prm[4]);
HighbdGeneratePrediction(above, left, bs, bd, prm, meanValue, dst, stride);
}
void av1_highbd_dc_filter_predictor_sse4_1(uint16_t *dst, ptrdiff_t stride,
int bs, const uint16_t *above,
const uint16_t *left, int bd) {
__m128i prm[5];
GetIntraFilterParams(bs, DC_PRED, &prm[0]);
HighbdFilterPrediction(above, left, bs, bd, prm, dst, stride);
}
void av1_highbd_v_filter_predictor_sse4_1(uint16_t *dst, ptrdiff_t stride,
int bs, const uint16_t *above,
const uint16_t *left, int bd) {
__m128i prm[5];
GetIntraFilterParams(bs, V_PRED, &prm[0]);
HighbdFilterPrediction(above, left, bs, bd, prm, dst, stride);
}
void av1_highbd_h_filter_predictor_sse4_1(uint16_t *dst, ptrdiff_t stride,
int bs, const uint16_t *above,
const uint16_t *left, int bd) {
__m128i prm[5];
GetIntraFilterParams(bs, H_PRED, &prm[0]);
HighbdFilterPrediction(above, left, bs, bd, prm, dst, stride);
}
void av1_highbd_d45_filter_predictor_sse4_1(uint16_t *dst, ptrdiff_t stride,
int bs, const uint16_t *above,
const uint16_t *left, int bd) {
__m128i prm[5];
GetIntraFilterParams(bs, D45_PRED, &prm[0]);
HighbdFilterPrediction(above, left, bs, bd, prm, dst, stride);
}
void av1_highbd_d135_filter_predictor_sse4_1(uint16_t *dst, ptrdiff_t stride,
int bs, const uint16_t *above,
const uint16_t *left, int bd) {
__m128i prm[5];
GetIntraFilterParams(bs, D135_PRED, &prm[0]);
HighbdFilterPrediction(above, left, bs, bd, prm, dst, stride);
}
void av1_highbd_d117_filter_predictor_sse4_1(uint16_t *dst, ptrdiff_t stride,
int bs, const uint16_t *above,
const uint16_t *left, int bd) {
__m128i prm[5];
GetIntraFilterParams(bs, D117_PRED, &prm[0]);
HighbdFilterPrediction(above, left, bs, bd, prm, dst, stride);
}
void av1_highbd_d153_filter_predictor_sse4_1(uint16_t *dst, ptrdiff_t stride,
int bs, const uint16_t *above,
const uint16_t *left, int bd) {
__m128i prm[5];
GetIntraFilterParams(bs, D153_PRED, &prm[0]);
HighbdFilterPrediction(above, left, bs, bd, prm, dst, stride);
}
void av1_highbd_d207_filter_predictor_sse4_1(uint16_t *dst, ptrdiff_t stride,
int bs, const uint16_t *above,
const uint16_t *left, int bd) {
__m128i prm[5];
GetIntraFilterParams(bs, D207_PRED, &prm[0]);
HighbdFilterPrediction(above, left, bs, bd, prm, dst, stride);
}
void av1_highbd_d63_filter_predictor_sse4_1(uint16_t *dst, ptrdiff_t stride,
int bs, const uint16_t *above,
const uint16_t *left, int bd) {
__m128i prm[5];
GetIntraFilterParams(bs, D63_PRED, &prm[0]);
HighbdFilterPrediction(above, left, bs, bd, prm, dst, stride);
}
void av1_highbd_tm_filter_predictor_sse4_1(uint16_t *dst, ptrdiff_t stride,
int bs, const uint16_t *above,
const uint16_t *left, int bd) {
__m128i prm[5];
GetIntraFilterParams(bs, TM_PRED, &prm[0]);
HighbdFilterPrediction(above, left, bs, bd, prm, dst, stride);
}
#endif // CONFIG_HIGHBITDEPTH
#endif // USE_3TAP_INTRA_FILTER