mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-20 04:18:26 +01:00
Merge "clean-up and slight speed-up in-loop filtering SSE2"
This commit is contained in:
commit
e2f405c969
@ -481,8 +481,8 @@ const VP8PredFunc VP8PredChroma8[NUM_B_DC_MODES] = {
|
|||||||
// 4 pixels in, 2 pixels out
|
// 4 pixels in, 2 pixels out
|
||||||
static WEBP_INLINE void do_filter2(uint8_t* p, int step) {
|
static WEBP_INLINE void do_filter2(uint8_t* p, int step) {
|
||||||
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
|
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
|
||||||
const int a = 3 * (q0 - p0) + VP8ksclip1[p1 - q1];
|
const int a = 3 * (q0 - p0) + VP8ksclip1[p1 - q1]; // in [-893,892]
|
||||||
const int a1 = VP8ksclip2[(a + 4) >> 3];
|
const int a1 = VP8ksclip2[(a + 4) >> 3]; // in [-16,15]
|
||||||
const int a2 = VP8ksclip2[(a + 3) >> 3];
|
const int a2 = VP8ksclip2[(a + 3) >> 3];
|
||||||
p[-step] = VP8kclip1[p0 + a2];
|
p[-step] = VP8kclip1[p0 + a2];
|
||||||
p[ 0] = VP8kclip1[q0 - a1];
|
p[ 0] = VP8kclip1[q0 - a1];
|
||||||
@ -506,6 +506,7 @@ static WEBP_INLINE void do_filter6(uint8_t* p, int step) {
|
|||||||
const int p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step];
|
const int p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step];
|
||||||
const int q0 = p[0], q1 = p[step], q2 = p[2*step];
|
const int q0 = p[0], q1 = p[step], q2 = p[2*step];
|
||||||
const int a = VP8ksclip1[3 * (q0 - p0) + VP8ksclip1[p1 - q1]];
|
const int a = VP8ksclip1[3 * (q0 - p0) + VP8ksclip1[p1 - q1]];
|
||||||
|
// a is in [-128,127], a1 in [-27,27], a2 in [-18,18] and a3 in [-9,9]
|
||||||
const int a1 = (27 * a + 63) >> 7; // eq. to ((3 * a + 7) * 9) >> 7
|
const int a1 = (27 * a + 63) >> 7; // eq. to ((3 * a + 7) * 9) >> 7
|
||||||
const int a2 = (18 * a + 63) >> 7; // eq. to ((2 * a + 7) * 9) >> 7
|
const int a2 = (18 * a + 63) >> 7; // eq. to ((2 * a + 7) * 9) >> 7
|
||||||
const int a3 = (9 * a + 63) >> 7; // eq. to ((1 * a + 7) * 9) >> 7
|
const int a3 = (9 * a + 63) >> 7; // eq. to ((1 * a + 7) * 9) >> 7
|
||||||
|
@ -298,20 +298,15 @@ static void TransformAC3(const int16_t* in, uint8_t* dst) {
|
|||||||
_mm_subs_epu8((q), (p)), \
|
_mm_subs_epu8((q), (p)), \
|
||||||
_mm_subs_epu8((p), (q)))
|
_mm_subs_epu8((p), (q)))
|
||||||
|
|
||||||
// Shift each byte of "a" by N bits while preserving by the sign bit.
|
// Shift each byte of "x" by 3 bits while preserving by the sign bit.
|
||||||
//
|
static WEBP_INLINE void SignedShift8b(__m128i* const x) {
|
||||||
// It first shifts the lower bytes of the words and then the upper bytes and
|
const __m128i zero = _mm_setzero_si128();
|
||||||
// then merges the results together.
|
const __m128i signs = _mm_cmpgt_epi8(zero, *x);
|
||||||
#define SIGNED_SHIFT_N(a, N) { \
|
const __m128i lo_0 = _mm_unpacklo_epi8(*x, signs); // s8 -> s16 sign extend
|
||||||
__m128i t = a; \
|
const __m128i hi_0 = _mm_unpackhi_epi8(*x, signs);
|
||||||
t = _mm_slli_epi16(t, 8); \
|
const __m128i lo_1 = _mm_srai_epi16(lo_0, 3);
|
||||||
t = _mm_srai_epi16(t, N); \
|
const __m128i hi_1 = _mm_srai_epi16(hi_0, 3);
|
||||||
t = _mm_srli_epi16(t, 8); \
|
*x = _mm_packs_epi16(lo_1, hi_1);
|
||||||
\
|
|
||||||
a = _mm_srai_epi16(a, N + 8); \
|
|
||||||
a = _mm_slli_epi16(a, 8); \
|
|
||||||
\
|
|
||||||
a = _mm_or_si128(t, a); \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FLIP_SIGN_BIT2(a, b) { \
|
#define FLIP_SIGN_BIT2(a, b) { \
|
||||||
@ -324,103 +319,123 @@ static void TransformAC3(const int16_t* in, uint8_t* dst) {
|
|||||||
FLIP_SIGN_BIT2(c, d); \
|
FLIP_SIGN_BIT2(c, d); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GET_NOTHEV(p1, p0, q0, q1, hev_thresh, not_hev) { \
|
// input/output is uint8_t
|
||||||
const __m128i zero = _mm_setzero_si128(); \
|
static WEBP_INLINE void GetNotHEV(const __m128i* const p1,
|
||||||
const __m128i t_1 = MM_ABS(p1, p0); \
|
const __m128i* const p0,
|
||||||
const __m128i t_2 = MM_ABS(q1, q0); \
|
const __m128i* const q0,
|
||||||
\
|
const __m128i* const q1,
|
||||||
const __m128i h = _mm_set1_epi8(hev_thresh); \
|
int hev_thresh, __m128i* const not_hev) {
|
||||||
const __m128i t_3 = _mm_subs_epu8(t_1, h); /* abs(p1 - p0) - hev_tresh */ \
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i t_4 = _mm_subs_epu8(t_2, h); /* abs(q1 - q0) - hev_tresh */ \
|
const __m128i t_1 = MM_ABS(*p1, *p0);
|
||||||
\
|
const __m128i t_2 = MM_ABS(*q1, *q0);
|
||||||
not_hev = _mm_or_si128(t_3, t_4); \
|
|
||||||
not_hev = _mm_cmpeq_epi8(not_hev, zero); /* not_hev <= t1 && not_hev <= t2 */\
|
const __m128i h = _mm_set1_epi8(hev_thresh);
|
||||||
|
const __m128i t_3 = _mm_subs_epu8(t_1, h); // abs(p1 - p0) - hev_tresh
|
||||||
|
const __m128i t_4 = _mm_subs_epu8(t_2, h); // abs(q1 - q0) - hev_tresh
|
||||||
|
|
||||||
|
*not_hev = _mm_or_si128(t_3, t_4);
|
||||||
|
*not_hev = _mm_cmpeq_epi8(*not_hev, zero); // not_hev <= t1 && not_hev <= t2
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GET_BASE_DELTA(p1, p0, q0, q1, o) { \
|
// input pixels are int8_t
|
||||||
const __m128i qp0 = _mm_subs_epi8(q0, p0); /* q0 - p0 */ \
|
static WEBP_INLINE void GetBaseDelta(const __m128i* const p1,
|
||||||
o = _mm_subs_epi8(p1, q1); /* p1 - q1 */ \
|
const __m128i* const p0,
|
||||||
o = _mm_adds_epi8(o, qp0); /* p1 - q1 + 1 * (q0 - p0) */ \
|
const __m128i* const q0,
|
||||||
o = _mm_adds_epi8(o, qp0); /* p1 - q1 + 2 * (q0 - p0) */ \
|
const __m128i* const q1,
|
||||||
o = _mm_adds_epi8(o, qp0); /* p1 - q1 + 3 * (q0 - p0) */ \
|
__m128i* const delta) {
|
||||||
|
// beware of addition order, for saturation!
|
||||||
|
const __m128i p1_q1 = _mm_subs_epi8(*p1, *q1); // p1 - q1
|
||||||
|
const __m128i q0_p0 = _mm_subs_epi8(*q0, *p0); // q0 - p0
|
||||||
|
const __m128i s1 = _mm_adds_epi8(p1_q1, q0_p0); // p1 - q1 + 1 * (q0 - p0)
|
||||||
|
const __m128i s2 = _mm_adds_epi8(q0_p0, s1); // p1 - q1 + 2 * (q0 - p0)
|
||||||
|
const __m128i s3 = _mm_adds_epi8(q0_p0, s2); // p1 - q1 + 3 * (q0 - p0)
|
||||||
|
*delta = s3;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DO_SIMPLE_FILTER(p0, q0, fl) { \
|
// input and output are int8_t
|
||||||
const __m128i three = _mm_set1_epi8(3); \
|
static WEBP_INLINE void DoSimpleFilter(__m128i* const p0, __m128i* const q0,
|
||||||
const __m128i four = _mm_set1_epi8(4); \
|
const __m128i* const fl) {
|
||||||
__m128i v3 = _mm_adds_epi8(fl, three); \
|
const __m128i k3 = _mm_set1_epi8(3);
|
||||||
__m128i v4 = _mm_adds_epi8(fl, four); \
|
const __m128i k4 = _mm_set1_epi8(4);
|
||||||
\
|
__m128i v3 = _mm_adds_epi8(*fl, k3);
|
||||||
/* Do +4 side */ \
|
__m128i v4 = _mm_adds_epi8(*fl, k4);
|
||||||
SIGNED_SHIFT_N(v4, 3); /* v4 >> 3 */ \
|
|
||||||
q0 = _mm_subs_epi8(q0, v4); /* q0 -= v4 */ \
|
SignedShift8b(&v4); // v4 >> 3
|
||||||
\
|
SignedShift8b(&v3); // v3 >> 3
|
||||||
/* Now do +3 side */ \
|
*q0 = _mm_subs_epi8(*q0, v4); // q0 -= v4
|
||||||
SIGNED_SHIFT_N(v3, 3); /* v3 >> 3 */ \
|
*p0 = _mm_adds_epi8(*p0, v3); // p0 += v3
|
||||||
p0 = _mm_adds_epi8(p0, v3); /* p0 += v3 */ \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updates values of 2 pixels at MB edge during complex filtering.
|
// Updates values of 2 pixels at MB edge during complex filtering.
|
||||||
// Update operations:
|
// Update operations:
|
||||||
// q = q - delta and p = p + delta; where delta = [(a_hi >> 7), (a_lo >> 7)]
|
// q = q - delta and p = p + delta; where delta = [(a_hi >> 7), (a_lo >> 7)]
|
||||||
#define UPDATE_2PIXELS(pi, qi, a_lo, a_hi) { \
|
// Pixels 'pi' and 'qi' are int8_t on input, uint8_t on output (sign flip).
|
||||||
const __m128i a_lo7 = _mm_srai_epi16(a_lo, 7); \
|
static WEBP_INLINE void Update2Pixels(__m128i* const pi, __m128i* const qi,
|
||||||
const __m128i a_hi7 = _mm_srai_epi16(a_hi, 7); \
|
const __m128i* const a0_lo,
|
||||||
const __m128i delta = _mm_packs_epi16(a_lo7, a_hi7); \
|
const __m128i* const a0_hi) {
|
||||||
pi = _mm_adds_epi8(pi, delta); \
|
const __m128i a1_lo = _mm_srai_epi16(*a0_lo, 7);
|
||||||
qi = _mm_subs_epi8(qi, delta); \
|
const __m128i a1_hi = _mm_srai_epi16(*a0_hi, 7);
|
||||||
|
const __m128i delta = _mm_packs_epi16(a1_lo, a1_hi);
|
||||||
|
const __m128i sign_bit = _mm_set1_epi8(0x80);
|
||||||
|
*pi = _mm_adds_epi8(*pi, delta);
|
||||||
|
*qi = _mm_subs_epi8(*qi, delta);
|
||||||
|
FLIP_SIGN_BIT2(*pi, *qi);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NeedsFilter(const __m128i* p1, const __m128i* p0, const __m128i* q0,
|
// input pixels are uint8_t
|
||||||
const __m128i* q1, int thresh, __m128i *mask) {
|
static WEBP_INLINE void NeedsFilter(const __m128i* const p1,
|
||||||
__m128i t1 = MM_ABS(*p1, *q1); // abs(p1 - q1)
|
const __m128i* const p0,
|
||||||
*mask = _mm_set1_epi8(0xFE);
|
const __m128i* const q0,
|
||||||
t1 = _mm_and_si128(t1, *mask); // set lsb of each byte to zero
|
const __m128i* const q1,
|
||||||
t1 = _mm_srli_epi16(t1, 1); // abs(p1 - q1) / 2
|
int thresh, __m128i* const mask) {
|
||||||
|
const __m128i m_thresh = _mm_set1_epi8(thresh);
|
||||||
|
const __m128i t1 = MM_ABS(*p1, *q1); // abs(p1 - q1)
|
||||||
|
const __m128i kFE = _mm_set1_epi8(0xFE);
|
||||||
|
const __m128i t2 = _mm_and_si128(t1, kFE); // set lsb of each byte to zero
|
||||||
|
const __m128i t3 = _mm_srli_epi16(t2, 1); // abs(p1 - q1) / 2
|
||||||
|
|
||||||
*mask = MM_ABS(*p0, *q0); // abs(p0 - q0)
|
const __m128i t4 = MM_ABS(*p0, *q0); // abs(p0 - q0)
|
||||||
*mask = _mm_adds_epu8(*mask, *mask); // abs(p0 - q0) * 2
|
const __m128i t5 = _mm_adds_epu8(t4, t4); // abs(p0 - q0) * 2
|
||||||
*mask = _mm_adds_epu8(*mask, t1); // abs(p0 - q0) * 2 + abs(p1 - q1) / 2
|
const __m128i t6 = _mm_adds_epu8(t5, t3); // abs(p0-q0)*2 + abs(p1-q1)/2
|
||||||
|
|
||||||
t1 = _mm_set1_epi8(thresh);
|
const __m128i t7 = _mm_subs_epu8(t6, m_thresh); // mask <= m_thresh
|
||||||
*mask = _mm_subs_epu8(*mask, t1); // mask <= thresh
|
*mask = _mm_cmpeq_epi8(t7, _mm_setzero_si128());
|
||||||
*mask = _mm_cmpeq_epi8(*mask, _mm_setzero_si128());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Edge filtering functions
|
// Edge filtering functions
|
||||||
|
|
||||||
// Applies filter on 2 pixels (p0 and q0)
|
// Applies filter on 2 pixels (p0 and q0)
|
||||||
static WEBP_INLINE void DoFilter2(const __m128i* p1, __m128i* p0, __m128i* q0,
|
static WEBP_INLINE void DoFilter2(__m128i* const p1, __m128i* const p0,
|
||||||
const __m128i* q1, int thresh) {
|
__m128i* const q0, __m128i* const q1,
|
||||||
|
int thresh) {
|
||||||
__m128i a, mask;
|
__m128i a, mask;
|
||||||
const __m128i sign_bit = _mm_set1_epi8(0x80);
|
const __m128i sign_bit = _mm_set1_epi8(0x80);
|
||||||
|
// convert p1/q1 to int8_t (for GetBaseDelta)
|
||||||
const __m128i p1s = _mm_xor_si128(*p1, sign_bit);
|
const __m128i p1s = _mm_xor_si128(*p1, sign_bit);
|
||||||
const __m128i q1s = _mm_xor_si128(*q1, sign_bit);
|
const __m128i q1s = _mm_xor_si128(*q1, sign_bit);
|
||||||
|
|
||||||
NeedsFilter(p1, p0, q0, q1, thresh, &mask);
|
NeedsFilter(p1, p0, q0, q1, thresh, &mask);
|
||||||
|
|
||||||
// convert to signed values
|
|
||||||
FLIP_SIGN_BIT2(*p0, *q0);
|
FLIP_SIGN_BIT2(*p0, *q0);
|
||||||
|
GetBaseDelta(&p1s, p0, q0, &q1s, &a);
|
||||||
GET_BASE_DELTA(p1s, *p0, *q0, q1s, a);
|
|
||||||
a = _mm_and_si128(a, mask); // mask filter values we don't care about
|
a = _mm_and_si128(a, mask); // mask filter values we don't care about
|
||||||
DO_SIMPLE_FILTER(*p0, *q0, a);
|
DoSimpleFilter(p0, q0, &a);
|
||||||
|
|
||||||
// unoffset
|
|
||||||
FLIP_SIGN_BIT2(*p0, *q0);
|
FLIP_SIGN_BIT2(*p0, *q0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Applies filter on 4 pixels (p1, p0, q0 and q1)
|
// Applies filter on 4 pixels (p1, p0, q0 and q1)
|
||||||
static WEBP_INLINE void DoFilter4(__m128i* p1, __m128i *p0,
|
static WEBP_INLINE void DoFilter4(__m128i* const p1, __m128i* const p0,
|
||||||
__m128i* q0, __m128i* q1,
|
__m128i* const q0, __m128i* const q1,
|
||||||
const __m128i* mask, int hev_thresh) {
|
const __m128i* const mask, int hev_thresh) {
|
||||||
|
const __m128i sign_bit = _mm_set1_epi8(0x80);
|
||||||
|
const __m128i k64 = _mm_set1_epi8(0x40);
|
||||||
|
const __m128i zero = _mm_setzero_si128();
|
||||||
__m128i not_hev;
|
__m128i not_hev;
|
||||||
__m128i t1, t2, t3;
|
__m128i t1, t2, t3;
|
||||||
const __m128i sign_bit = _mm_set1_epi8(0x80);
|
|
||||||
|
|
||||||
// compute hev mask
|
// compute hev mask
|
||||||
GET_NOTHEV(*p1, *p0, *q0, *q1, hev_thresh, not_hev);
|
GetNotHEV(p1, p0, q0, q1, hev_thresh, ¬_hev);
|
||||||
|
|
||||||
// convert to signed values
|
// convert to signed values
|
||||||
FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
|
FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
|
||||||
@ -433,92 +448,83 @@ static WEBP_INLINE void DoFilter4(__m128i* p1, __m128i *p0,
|
|||||||
t1 = _mm_adds_epi8(t1, t2); // hev(p1 - q1) + 3 * (q0 - p0)
|
t1 = _mm_adds_epi8(t1, t2); // hev(p1 - q1) + 3 * (q0 - p0)
|
||||||
t1 = _mm_and_si128(t1, *mask); // mask filter values we don't care about
|
t1 = _mm_and_si128(t1, *mask); // mask filter values we don't care about
|
||||||
|
|
||||||
// Do +4 side
|
|
||||||
t2 = _mm_set1_epi8(4);
|
|
||||||
t2 = _mm_adds_epi8(t1, t2); // 3 * (q0 - p0) + (p1 - q1) + 4
|
|
||||||
SIGNED_SHIFT_N(t2, 3); // (3 * (q0 - p0) + hev(p1 - q1) + 4) >> 3
|
|
||||||
t3 = t2; // save t2
|
|
||||||
*q0 = _mm_subs_epi8(*q0, t2); // q0 -= t2
|
|
||||||
|
|
||||||
// Now do +3 side
|
|
||||||
t2 = _mm_set1_epi8(3);
|
t2 = _mm_set1_epi8(3);
|
||||||
t2 = _mm_adds_epi8(t1, t2); // +3 instead of +4
|
t3 = _mm_set1_epi8(4);
|
||||||
SIGNED_SHIFT_N(t2, 3); // (3 * (q0 - p0) + hev(p1 - q1) + 3) >> 3
|
t2 = _mm_adds_epi8(t1, t2); // 3 * (q0 - p0) + (p1 - q1) + 3
|
||||||
|
t3 = _mm_adds_epi8(t1, t3); // 3 * (q0 - p0) + (p1 - q1) + 4
|
||||||
|
SignedShift8b(&t2); // (3 * (q0 - p0) + hev(p1 - q1) + 3) >> 3
|
||||||
|
SignedShift8b(&t3); // (3 * (q0 - p0) + hev(p1 - q1) + 4) >> 3
|
||||||
*p0 = _mm_adds_epi8(*p0, t2); // p0 += t2
|
*p0 = _mm_adds_epi8(*p0, t2); // p0 += t2
|
||||||
|
*q0 = _mm_subs_epi8(*q0, t3); // q0 -= t3
|
||||||
|
FLIP_SIGN_BIT2(*p0, *q0);
|
||||||
|
|
||||||
t2 = _mm_set1_epi8(1);
|
// this is equivalent to signed (a + 1) >> 1 calculation
|
||||||
t3 = _mm_adds_epi8(t3, t2);
|
t2 = _mm_add_epi8(t3, sign_bit);
|
||||||
SIGNED_SHIFT_N(t3, 1); // (3 * (q0 - p0) + hev(p1 - q1) + 4) >> 4
|
t3 = _mm_avg_epu8(t2, zero);
|
||||||
|
t3 = _mm_sub_epi8(t3, k64);
|
||||||
|
|
||||||
t3 = _mm_and_si128(not_hev, t3); // if !hev
|
t3 = _mm_and_si128(not_hev, t3); // if !hev
|
||||||
*q1 = _mm_subs_epi8(*q1, t3); // q1 -= t3
|
*q1 = _mm_subs_epi8(*q1, t3); // q1 -= t3
|
||||||
*p1 = _mm_adds_epi8(*p1, t3); // p1 += t3
|
*p1 = _mm_adds_epi8(*p1, t3); // p1 += t3
|
||||||
|
FLIP_SIGN_BIT2(*p1, *q1);
|
||||||
// unoffset
|
|
||||||
FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Applies filter on 6 pixels (p2, p1, p0, q0, q1 and q2)
|
// Applies filter on 6 pixels (p2, p1, p0, q0, q1 and q2)
|
||||||
static WEBP_INLINE void DoFilter6(__m128i *p2, __m128i* p1, __m128i *p0,
|
static WEBP_INLINE void DoFilter6(__m128i* const p2, __m128i* const p1,
|
||||||
__m128i* q0, __m128i* q1, __m128i *q2,
|
__m128i* const p0, __m128i* const q0,
|
||||||
const __m128i* mask, int hev_thresh) {
|
__m128i* const q1, __m128i* const q2,
|
||||||
__m128i a, not_hev;
|
const __m128i* const mask, int hev_thresh) {
|
||||||
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i sign_bit = _mm_set1_epi8(0x80);
|
const __m128i sign_bit = _mm_set1_epi8(0x80);
|
||||||
|
__m128i a, not_hev;
|
||||||
|
|
||||||
// compute hev mask
|
// compute hev mask
|
||||||
GET_NOTHEV(*p1, *p0, *q0, *q1, hev_thresh, not_hev);
|
GetNotHEV(p1, p0, q0, q1, hev_thresh, ¬_hev);
|
||||||
|
|
||||||
// convert to signed values
|
|
||||||
FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
|
FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
|
||||||
FLIP_SIGN_BIT2(*p2, *q2);
|
FLIP_SIGN_BIT2(*p2, *q2);
|
||||||
|
GetBaseDelta(p1, p0, q0, q1, &a);
|
||||||
GET_BASE_DELTA(*p1, *p0, *q0, *q1, a);
|
|
||||||
|
|
||||||
{ // do simple filter on pixels with hev
|
{ // do simple filter on pixels with hev
|
||||||
const __m128i m = _mm_andnot_si128(not_hev, *mask);
|
const __m128i m = _mm_andnot_si128(not_hev, *mask);
|
||||||
const __m128i f = _mm_and_si128(a, m);
|
const __m128i f = _mm_and_si128(a, m);
|
||||||
DO_SIMPLE_FILTER(*p0, *q0, f);
|
DoSimpleFilter(p0, q0, &f);
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // do strong filter on pixels with not hev
|
{ // do strong filter on pixels with not hev
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i k9 = _mm_set1_epi16(0x0900);
|
||||||
const __m128i nine = _mm_set1_epi16(0x0900);
|
const __m128i k63 = _mm_set1_epi16(63);
|
||||||
const __m128i sixty_three = _mm_set1_epi16(63);
|
|
||||||
|
|
||||||
const __m128i m = _mm_and_si128(not_hev, *mask);
|
const __m128i m = _mm_and_si128(not_hev, *mask);
|
||||||
const __m128i f = _mm_and_si128(a, m);
|
const __m128i f = _mm_and_si128(a, m);
|
||||||
|
|
||||||
const __m128i f_lo = _mm_unpacklo_epi8(zero, f);
|
const __m128i f_lo = _mm_unpacklo_epi8(zero, f);
|
||||||
const __m128i f_hi = _mm_unpackhi_epi8(zero, f);
|
const __m128i f_hi = _mm_unpackhi_epi8(zero, f);
|
||||||
|
|
||||||
const __m128i f9_lo = _mm_mulhi_epi16(f_lo, nine); // Filter (lo) * 9
|
const __m128i f9_lo = _mm_mulhi_epi16(f_lo, k9); // Filter (lo) * 9
|
||||||
const __m128i f9_hi = _mm_mulhi_epi16(f_hi, nine); // Filter (hi) * 9
|
const __m128i f9_hi = _mm_mulhi_epi16(f_hi, k9); // Filter (hi) * 9
|
||||||
const __m128i f18_lo = _mm_add_epi16(f9_lo, f9_lo); // Filter (lo) * 18
|
|
||||||
const __m128i f18_hi = _mm_add_epi16(f9_hi, f9_hi); // Filter (hi) * 18
|
|
||||||
|
|
||||||
const __m128i a2_lo = _mm_add_epi16(f9_lo, sixty_three); // Filter * 9 + 63
|
const __m128i a2_lo = _mm_add_epi16(f9_lo, k63); // Filter * 9 + 63
|
||||||
const __m128i a2_hi = _mm_add_epi16(f9_hi, sixty_three); // Filter * 9 + 63
|
const __m128i a2_hi = _mm_add_epi16(f9_hi, k63); // Filter * 9 + 63
|
||||||
|
|
||||||
const __m128i a1_lo = _mm_add_epi16(f18_lo, sixty_three); // F... * 18 + 63
|
const __m128i a1_lo = _mm_add_epi16(a2_lo, f9_lo); // Filter * 18 + 63
|
||||||
const __m128i a1_hi = _mm_add_epi16(f18_hi, sixty_three); // F... * 18 + 63
|
const __m128i a1_hi = _mm_add_epi16(a2_hi, f9_hi); // Filter * 18 + 63
|
||||||
|
|
||||||
const __m128i a0_lo = _mm_add_epi16(f18_lo, a2_lo); // Filter * 27 + 63
|
const __m128i a0_lo = _mm_add_epi16(a1_lo, f9_lo); // Filter * 27 + 63
|
||||||
const __m128i a0_hi = _mm_add_epi16(f18_hi, a2_hi); // Filter * 27 + 63
|
const __m128i a0_hi = _mm_add_epi16(a1_hi, f9_hi); // Filter * 27 + 63
|
||||||
|
|
||||||
UPDATE_2PIXELS(*p2, *q2, a2_lo, a2_hi);
|
Update2Pixels(p2, q2, &a2_lo, &a2_hi);
|
||||||
UPDATE_2PIXELS(*p1, *q1, a1_lo, a1_hi);
|
Update2Pixels(p1, q1, &a1_lo, &a1_hi);
|
||||||
UPDATE_2PIXELS(*p0, *q0, a0_lo, a0_hi);
|
Update2Pixels(p0, q0, &a0_lo, &a0_hi);
|
||||||
}
|
}
|
||||||
|
|
||||||
// unoffset
|
|
||||||
FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
|
|
||||||
FLIP_SIGN_BIT2(*p2, *q2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// reads 8 rows across a vertical edge.
|
// reads 8 rows across a vertical edge.
|
||||||
//
|
//
|
||||||
// TODO(somnath): Investigate _mm_shuffle* also see if it can be broken into
|
// TODO(somnath): Investigate _mm_shuffle* also see if it can be broken into
|
||||||
// two Load4x4() to avoid code duplication.
|
// two Load4x4() to avoid code duplication.
|
||||||
static WEBP_INLINE void Load8x4(const uint8_t* b, int stride,
|
static WEBP_INLINE void Load8x4(const uint8_t* const b, int stride,
|
||||||
__m128i* p, __m128i* q) {
|
__m128i* const p, __m128i* const q) {
|
||||||
__m128i t1, t2;
|
__m128i t1, t2;
|
||||||
|
|
||||||
// Load 0th, 1st, 4th and 5th rows
|
// Load 0th, 1st, 4th and 5th rows
|
||||||
@ -557,10 +563,11 @@ static WEBP_INLINE void Load8x4(const uint8_t* b, int stride,
|
|||||||
*q = _mm_unpackhi_epi32(t1, t2);
|
*q = _mm_unpackhi_epi32(t1, t2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE void Load16x4(const uint8_t* r0, const uint8_t* r8,
|
static WEBP_INLINE void Load16x4(const uint8_t* const r0,
|
||||||
|
const uint8_t* const r8,
|
||||||
int stride,
|
int stride,
|
||||||
__m128i* p1, __m128i* p0,
|
__m128i* const p1, __m128i* const p0,
|
||||||
__m128i* q0, __m128i* q1) {
|
__m128i* const q0, __m128i* const q1) {
|
||||||
__m128i t1, t2;
|
__m128i t1, t2;
|
||||||
// Assume the pixels around the edge (|) are numbered as follows
|
// Assume the pixels around the edge (|) are numbered as follows
|
||||||
// 00 01 | 02 03
|
// 00 01 | 02 03
|
||||||
@ -592,7 +599,7 @@ static WEBP_INLINE void Load16x4(const uint8_t* r0, const uint8_t* r8,
|
|||||||
*q1 = _mm_unpackhi_epi64(t2, *q1);
|
*q1 = _mm_unpackhi_epi64(t2, *q1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE void Store4x4(__m128i* x, uint8_t* dst, int stride) {
|
static WEBP_INLINE void Store4x4(__m128i* const x, uint8_t* dst, int stride) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 4; ++i, dst += stride) {
|
for (i = 0; i < 4; ++i, dst += stride) {
|
||||||
*((int32_t*)dst) = _mm_cvtsi128_si32(*x);
|
*((int32_t*)dst) = _mm_cvtsi128_si32(*x);
|
||||||
@ -601,9 +608,10 @@ static WEBP_INLINE void Store4x4(__m128i* x, uint8_t* dst, int stride) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Transpose back and store
|
// Transpose back and store
|
||||||
static WEBP_INLINE void Store16x4(uint8_t* r0, uint8_t* r8, int stride,
|
static WEBP_INLINE void Store16x4(__m128i* const p1, __m128i* const p0,
|
||||||
__m128i* p1, __m128i* p0,
|
__m128i* const q0, __m128i* const q1,
|
||||||
__m128i* q0, __m128i* q1) {
|
uint8_t* r0, uint8_t* r8,
|
||||||
|
int stride) {
|
||||||
__m128i t1;
|
__m128i t1;
|
||||||
|
|
||||||
// p0 = 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00
|
// p0 = 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00
|
||||||
@ -653,7 +661,7 @@ static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
|
|||||||
|
|
||||||
// Store
|
// Store
|
||||||
_mm_storeu_si128((__m128i*)&p[-stride], p0);
|
_mm_storeu_si128((__m128i*)&p[-stride], p0);
|
||||||
_mm_storeu_si128((__m128i*)p, q0);
|
_mm_storeu_si128((__m128i*)&p[0], q0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
|
static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
|
||||||
@ -661,9 +669,9 @@ static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
|
|||||||
|
|
||||||
p -= 2; // beginning of p1
|
p -= 2; // beginning of p1
|
||||||
|
|
||||||
Load16x4(p, p + 8 * stride, stride, &p1, &p0, &q0, &q1);
|
Load16x4(p, p + 8 * stride, stride, &p1, &p0, &q0, &q1);
|
||||||
DoFilter2(&p1, &p0, &q0, &q1, thresh);
|
DoFilter2(&p1, &p0, &q0, &q1, thresh);
|
||||||
Store16x4(p, p + 8 * stride, stride, &p1, &p0, &q0, &q1);
|
Store16x4(&p1, &p0, &q0, &q1, p, p + 8 * stride, stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) {
|
static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) {
|
||||||
@ -722,13 +730,18 @@ static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
|
|||||||
_mm_storel_epi64((__m128i*)&v[(stride)], p); \
|
_mm_storel_epi64((__m128i*)&v[(stride)], p); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask) { \
|
static WEBP_INLINE void ComplexMask(const __m128i* const p1,
|
||||||
__m128i fl_yes; \
|
const __m128i* const p0,
|
||||||
const __m128i it = _mm_set1_epi8(ithresh); \
|
const __m128i* const q0,
|
||||||
mask = _mm_subs_epu8(mask, it); \
|
const __m128i* const q1,
|
||||||
mask = _mm_cmpeq_epi8(mask, _mm_setzero_si128()); \
|
int thresh, int ithresh,
|
||||||
NeedsFilter(&p1, &p0, &q0, &q1, thresh, &fl_yes); \
|
__m128i* const mask) {
|
||||||
mask = _mm_and_si128(mask, fl_yes); \
|
const __m128i it = _mm_set1_epi8(ithresh);
|
||||||
|
const __m128i diff = _mm_subs_epu8(*mask, it);
|
||||||
|
const __m128i thresh_mask = _mm_cmpeq_epi8(diff, _mm_setzero_si128());
|
||||||
|
__m128i filter_mask;
|
||||||
|
NeedsFilter(p1, p0, q0, q1, thresh, &filter_mask);
|
||||||
|
*mask = _mm_and_si128(thresh_mask, filter_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
// on macroblock edges
|
// on macroblock edges
|
||||||
@ -746,16 +759,16 @@ static void VFilter16(uint8_t* p, int stride,
|
|||||||
LOAD_H_EDGES4(p, stride, q0, q1, q2, t1);
|
LOAD_H_EDGES4(p, stride, q0, q1, q2, t1);
|
||||||
MAX_DIFF2(t1, q2, q1, q0, mask);
|
MAX_DIFF2(t1, q2, q1, q0, mask);
|
||||||
|
|
||||||
COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
|
ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
||||||
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
|
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
|
||||||
|
|
||||||
// Store
|
// Store
|
||||||
_mm_storeu_si128((__m128i*)&p[-3 * stride], p2);
|
_mm_storeu_si128((__m128i*)&p[-3 * stride], p2);
|
||||||
_mm_storeu_si128((__m128i*)&p[-2 * stride], p1);
|
_mm_storeu_si128((__m128i*)&p[-2 * stride], p1);
|
||||||
_mm_storeu_si128((__m128i*)&p[-1 * stride], p0);
|
_mm_storeu_si128((__m128i*)&p[-1 * stride], p0);
|
||||||
_mm_storeu_si128((__m128i*)&p[0 * stride], q0);
|
_mm_storeu_si128((__m128i*)&p[+0 * stride], q0);
|
||||||
_mm_storeu_si128((__m128i*)&p[1 * stride], q1);
|
_mm_storeu_si128((__m128i*)&p[+1 * stride], q1);
|
||||||
_mm_storeu_si128((__m128i*)&p[2 * stride], q2);
|
_mm_storeu_si128((__m128i*)&p[+2 * stride], q2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HFilter16(uint8_t* p, int stride,
|
static void HFilter16(uint8_t* p, int stride,
|
||||||
@ -770,11 +783,11 @@ static void HFilter16(uint8_t* p, int stride,
|
|||||||
Load16x4(p, p + 8 * stride, stride, &q0, &q1, &q2, &q3); // q0, q1, q2, q3
|
Load16x4(p, p + 8 * stride, stride, &q0, &q1, &q2, &q3); // q0, q1, q2, q3
|
||||||
MAX_DIFF2(q3, q2, q1, q0, mask);
|
MAX_DIFF2(q3, q2, q1, q0, mask);
|
||||||
|
|
||||||
COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
|
ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
||||||
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
|
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
|
||||||
|
|
||||||
Store16x4(b, b + 8 * stride, stride, &p3, &p2, &p1, &p0);
|
Store16x4(&p3, &p2, &p1, &p0, b, b + 8 * stride, stride);
|
||||||
Store16x4(p, p + 8 * stride, stride, &q0, &q1, &q2, &q3);
|
Store16x4(&q0, &q1, &q2, &q3, p, p + 8 * stride, stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
// on three inner edges
|
// on three inner edges
|
||||||
@ -795,7 +808,7 @@ static void VFilter16i(uint8_t* p, int stride,
|
|||||||
LOAD_H_EDGES4(p, stride, q0, q1, t1, t2);
|
LOAD_H_EDGES4(p, stride, q0, q1, t1, t2);
|
||||||
MAX_DIFF2(t2, t1, q1, q0, mask);
|
MAX_DIFF2(t2, t1, q1, q0, mask);
|
||||||
|
|
||||||
COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
|
ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
||||||
DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
|
DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
|
||||||
|
|
||||||
// Store
|
// Store
|
||||||
@ -822,11 +835,11 @@ static void HFilter16i(uint8_t* p, int stride,
|
|||||||
Load16x4(b, b + 8 * stride, stride, &q0, &q1, &t1, &t2); // q0, q1, q2, q3
|
Load16x4(b, b + 8 * stride, stride, &q0, &q1, &t1, &t2); // q0, q1, q2, q3
|
||||||
MAX_DIFF2(t2, t1, q1, q0, mask);
|
MAX_DIFF2(t2, t1, q1, q0, mask);
|
||||||
|
|
||||||
COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
|
ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
||||||
DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
|
DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
|
||||||
|
|
||||||
b -= 2; // beginning of p1
|
b -= 2; // beginning of p1
|
||||||
Store16x4(b, b + 8 * stride, stride, &p1, &p0, &q0, &q1);
|
Store16x4(&p1, &p0, &q0, &q1, b, b + 8 * stride, stride);
|
||||||
|
|
||||||
p += 4;
|
p += 4;
|
||||||
}
|
}
|
||||||
@ -846,7 +859,7 @@ static void VFilter8(uint8_t* u, uint8_t* v, int stride,
|
|||||||
LOADUV_H_EDGES4(u, v, stride, q0, q1, q2, t1);
|
LOADUV_H_EDGES4(u, v, stride, q0, q1, q2, t1);
|
||||||
MAX_DIFF2(t1, q2, q1, q0, mask);
|
MAX_DIFF2(t1, q2, q1, q0, mask);
|
||||||
|
|
||||||
COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
|
ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
||||||
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
|
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
|
||||||
|
|
||||||
// Store
|
// Store
|
||||||
@ -871,11 +884,11 @@ static void HFilter8(uint8_t* u, uint8_t* v, int stride,
|
|||||||
Load16x4(u, v, stride, &q0, &q1, &q2, &q3); // q0, q1, q2, q3
|
Load16x4(u, v, stride, &q0, &q1, &q2, &q3); // q0, q1, q2, q3
|
||||||
MAX_DIFF2(q3, q2, q1, q0, mask);
|
MAX_DIFF2(q3, q2, q1, q0, mask);
|
||||||
|
|
||||||
COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
|
ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
||||||
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
|
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
|
||||||
|
|
||||||
Store16x4(tu, tv, stride, &p3, &p2, &p1, &p0);
|
Store16x4(&p3, &p2, &p1, &p0, tu, tv, stride);
|
||||||
Store16x4(u, v, stride, &q0, &q1, &q2, &q3);
|
Store16x4(&q0, &q1, &q2, &q3, u, v, stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
|
static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
|
||||||
@ -894,7 +907,7 @@ static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
|
|||||||
LOADUV_H_EDGES4(u, v, stride, q0, q1, t1, t2);
|
LOADUV_H_EDGES4(u, v, stride, q0, q1, t1, t2);
|
||||||
MAX_DIFF2(t2, t1, q1, q0, mask);
|
MAX_DIFF2(t2, t1, q1, q0, mask);
|
||||||
|
|
||||||
COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
|
ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
||||||
DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
|
DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
|
||||||
|
|
||||||
// Store
|
// Store
|
||||||
@ -916,12 +929,12 @@ static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
|
|||||||
Load16x4(u, v, stride, &q0, &q1, &t1, &t2); // q0, q1, q2, q3
|
Load16x4(u, v, stride, &q0, &q1, &t1, &t2); // q0, q1, q2, q3
|
||||||
MAX_DIFF2(t2, t1, q1, q0, mask);
|
MAX_DIFF2(t2, t1, q1, q0, mask);
|
||||||
|
|
||||||
COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
|
ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
||||||
DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
|
DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
|
||||||
|
|
||||||
u -= 2; // beginning of p1
|
u -= 2; // beginning of p1
|
||||||
v -= 2;
|
v -= 2;
|
||||||
Store16x4(u, v, stride, &p1, &p0, &q0, &q1);
|
Store16x4(&p1, &p0, &q0, &q1, u, v, stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // WEBP_USE_SSE2
|
#endif // WEBP_USE_SSE2
|
||||||
|
Loading…
Reference in New Issue
Block a user