1 /*
2  * Copyright (c) 2017, 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 <emmintrin.h>
13 
14 #include "av1/common/cfl.h"
15 #include "config/av1_rtcd.h"
16 
fill_sum_epi32(__m128i l0)17 static INLINE __m128i fill_sum_epi32(__m128i l0) {
18   l0 = _mm_add_epi32(l0, _mm_shuffle_epi32(l0, _MM_SHUFFLE(1, 0, 3, 2)));
19   return _mm_add_epi32(l0, _mm_shuffle_epi32(l0, _MM_SHUFFLE(2, 3, 0, 1)));
20 }
21 
subtract_average_sse2(const uint16_t * src_ptr,int16_t * dst_ptr,int width,int height,int round_offset,int num_pel_log2)22 static INLINE void subtract_average_sse2(const uint16_t *src_ptr,
23                                          int16_t *dst_ptr, int width,
24                                          int height, int round_offset,
25                                          int num_pel_log2) {
26   const __m128i zeros = _mm_setzero_si128();
27   const __m128i round_offset_epi32 = _mm_set1_epi32(round_offset);
28   const __m128i *src = (__m128i *)src_ptr;
29   const __m128i *const end = src + height * CFL_BUF_LINE_I128;
30   const int step = CFL_BUF_LINE_I128 * (1 + (width == 8) + 3 * (width == 4));
31 
32   __m128i sum = zeros;
33   do {
34     __m128i l0;
35     if (width == 4) {
36       l0 = _mm_add_epi16(_mm_loadl_epi64(src),
37                          _mm_loadl_epi64(src + CFL_BUF_LINE_I128));
38       __m128i l1 = _mm_add_epi16(_mm_loadl_epi64(src + 2 * CFL_BUF_LINE_I128),
39                                  _mm_loadl_epi64(src + 3 * CFL_BUF_LINE_I128));
40       sum = _mm_add_epi32(sum, _mm_add_epi32(_mm_unpacklo_epi16(l0, zeros),
41                                              _mm_unpacklo_epi16(l1, zeros)));
42     } else {
43       if (width == 8) {
44         l0 = _mm_add_epi16(_mm_loadu_si128(src),
45                            _mm_loadu_si128(src + CFL_BUF_LINE_I128));
46       } else {
47         l0 = _mm_add_epi16(_mm_loadu_si128(src), _mm_loadu_si128(src + 1));
48       }
49       sum = _mm_add_epi32(sum, _mm_add_epi32(_mm_unpacklo_epi16(l0, zeros),
50                                              _mm_unpackhi_epi16(l0, zeros)));
51       if (width == 32) {
52         l0 = _mm_add_epi16(_mm_loadu_si128(src + 2), _mm_loadu_si128(src + 3));
53         sum = _mm_add_epi32(sum, _mm_add_epi32(_mm_unpacklo_epi16(l0, zeros),
54                                                _mm_unpackhi_epi16(l0, zeros)));
55       }
56     }
57     src += step;
58   } while (src < end);
59 
60   sum = fill_sum_epi32(sum);
61 
62   __m128i avg_epi16 =
63       _mm_srli_epi32(_mm_add_epi32(sum, round_offset_epi32), num_pel_log2);
64   avg_epi16 = _mm_packs_epi32(avg_epi16, avg_epi16);
65 
66   src = (__m128i *)src_ptr;
67   __m128i *dst = (__m128i *)dst_ptr;
68   do {
69     if (width == 4) {
70       _mm_storel_epi64(dst, _mm_sub_epi16(_mm_loadl_epi64(src), avg_epi16));
71     } else {
72       _mm_storeu_si128(dst, _mm_sub_epi16(_mm_loadu_si128(src), avg_epi16));
73       if (width > 8) {
74         _mm_storeu_si128(dst + 1,
75                          _mm_sub_epi16(_mm_loadu_si128(src + 1), avg_epi16));
76         if (width == 32) {
77           _mm_storeu_si128(dst + 2,
78                            _mm_sub_epi16(_mm_loadu_si128(src + 2), avg_epi16));
79           _mm_storeu_si128(dst + 3,
80                            _mm_sub_epi16(_mm_loadu_si128(src + 3), avg_epi16));
81         }
82       }
83     }
84     src += CFL_BUF_LINE_I128;
85     dst += CFL_BUF_LINE_I128;
86   } while (src < end);
87 }
88 
89 CFL_SUB_AVG_FN(sse2)
90