1 /*
2  * Copyright (c) 2018, Alliance for Open Media. All rights reserved
3  *
4  * This source code is subject to the terms of the BSD 2 Clause License and
5  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6  * was not distributed with this source code in the LICENSE file, you can
7  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8  * Media Patent License 1.0 was not distributed with this source code in the
9  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10  */
11 
12 #include <smmintrin.h>
13 
14 #include "config/av1_rtcd.h"
15 
16 #include "aom_dsp/x86/synonyms.h"
17 #include "av1/common/enums.h"
18 #include "av1/common/reconintra.h"
19 
av1_filter_intra_predictor_sse4_1(uint8_t * dst,ptrdiff_t stride,TX_SIZE tx_size,const uint8_t * above,const uint8_t * left,int mode)20 void av1_filter_intra_predictor_sse4_1(uint8_t *dst, ptrdiff_t stride,
21                                        TX_SIZE tx_size, const uint8_t *above,
22                                        const uint8_t *left, int mode) {
23   int r, c;
24   uint8_t buffer[33][33];
25   const int bw = tx_size_wide[tx_size];
26   const int bh = tx_size_high[tx_size];
27 
28   assert(bw <= 32 && bh <= 32);
29 
30   // The initialization is just for silencing Jenkins static analysis warnings
31   for (r = 0; r < bh + 1; ++r)
32     memset(buffer[r], 0, (bw + 1) * sizeof(buffer[0][0]));
33 
34   for (r = 0; r < bh; ++r) buffer[r + 1][0] = left[r];
35   memcpy(buffer[0], &above[-1], (bw + 1) * sizeof(uint8_t));
36 
37   const __m128i f1f0 = xx_load_128(av1_filter_intra_taps[mode][0]);
38   const __m128i f3f2 = xx_load_128(av1_filter_intra_taps[mode][2]);
39   const __m128i f5f4 = xx_load_128(av1_filter_intra_taps[mode][4]);
40   const __m128i f7f6 = xx_load_128(av1_filter_intra_taps[mode][6]);
41   const __m128i filter_intra_scale_bits =
42       _mm_set1_epi16(1 << (15 - FILTER_INTRA_SCALE_BITS));
43 
44   for (r = 1; r < bh + 1; r += 2) {
45     for (c = 1; c < bw + 1; c += 4) {
46       DECLARE_ALIGNED(16, uint8_t, p[8]);
47       memcpy(p, &buffer[r - 1][c - 1], 5 * sizeof(uint8_t));
48       p[5] = buffer[r][c - 1];
49       p[6] = buffer[r + 1][c - 1];
50       p[7] = 0;
51       const __m128i p_b = xx_loadl_64(p);
52       const __m128i in = _mm_unpacklo_epi64(p_b, p_b);
53       const __m128i out_01 = _mm_maddubs_epi16(in, f1f0);
54       const __m128i out_23 = _mm_maddubs_epi16(in, f3f2);
55       const __m128i out_45 = _mm_maddubs_epi16(in, f5f4);
56       const __m128i out_67 = _mm_maddubs_epi16(in, f7f6);
57       const __m128i out_0123 = _mm_hadd_epi16(out_01, out_23);
58       const __m128i out_4567 = _mm_hadd_epi16(out_45, out_67);
59       const __m128i out_01234567 = _mm_hadd_epi16(out_0123, out_4567);
60       // Rounding
61       const __m128i round_w =
62           _mm_mulhrs_epi16(out_01234567, filter_intra_scale_bits);
63       const __m128i out_r = _mm_packus_epi16(round_w, round_w);
64       const __m128i out_r1 = _mm_srli_si128(out_r, 4);
65       // Storing
66       xx_storel_32(&buffer[r][c], out_r);
67       xx_storel_32(&buffer[r + 1][c], out_r1);
68     }
69   }
70 
71   for (r = 0; r < bh; ++r) {
72     memcpy(dst, &buffer[r + 1][1], bw * sizeof(uint8_t));
73     dst += stride;
74   }
75 }
76