/src/aom/aom_dsp/x86/avg_intrin_sse2.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2016, 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 <immintrin.h> |
13 | | |
14 | | #include "config/aom_dsp_rtcd.h" |
15 | | #include "aom/aom_integer.h" |
16 | | #include "aom_dsp/x86/bitdepth_conversion_sse2.h" |
17 | | #include "aom_dsp/x86/mem_sse2.h" |
18 | | #include "aom_dsp/x86/synonyms.h" |
19 | | #include "aom_ports/mem.h" |
20 | | |
21 | | static inline void sign_extend_16bit_to_32bit_sse2(__m128i in, __m128i zero, |
22 | | __m128i *out_lo, |
23 | 0 | __m128i *out_hi) { |
24 | 0 | const __m128i sign_bits = _mm_cmplt_epi16(in, zero); |
25 | 0 | *out_lo = _mm_unpacklo_epi16(in, sign_bits); |
26 | 0 | *out_hi = _mm_unpackhi_epi16(in, sign_bits); |
27 | 0 | } |
28 | | |
29 | 0 | static inline __m128i invert_sign_32_sse2(__m128i a, __m128i sign) { |
30 | 0 | a = _mm_xor_si128(a, sign); |
31 | 0 | return _mm_sub_epi32(a, sign); |
32 | 0 | } |
33 | | |
34 | | void aom_minmax_8x8_sse2(const uint8_t *s, int p, const uint8_t *d, int dp, |
35 | 0 | int *min, int *max) { |
36 | 0 | __m128i u0, s0, d0, diff, maxabsdiff, minabsdiff, negdiff, absdiff0, absdiff; |
37 | 0 | u0 = _mm_setzero_si128(); |
38 | | // Row 0 |
39 | 0 | s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s)), u0); |
40 | 0 | d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d)), u0); |
41 | 0 | diff = _mm_subs_epi16(s0, d0); |
42 | 0 | negdiff = _mm_subs_epi16(u0, diff); |
43 | 0 | absdiff0 = _mm_max_epi16(diff, negdiff); |
44 | | // Row 1 |
45 | 0 | s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + p)), u0); |
46 | 0 | d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + dp)), u0); |
47 | 0 | diff = _mm_subs_epi16(s0, d0); |
48 | 0 | negdiff = _mm_subs_epi16(u0, diff); |
49 | 0 | absdiff = _mm_max_epi16(diff, negdiff); |
50 | 0 | maxabsdiff = _mm_max_epi16(absdiff0, absdiff); |
51 | 0 | minabsdiff = _mm_min_epi16(absdiff0, absdiff); |
52 | | // Row 2 |
53 | 0 | s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 2 * p)), u0); |
54 | 0 | d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 2 * dp)), u0); |
55 | 0 | diff = _mm_subs_epi16(s0, d0); |
56 | 0 | negdiff = _mm_subs_epi16(u0, diff); |
57 | 0 | absdiff = _mm_max_epi16(diff, negdiff); |
58 | 0 | maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff); |
59 | 0 | minabsdiff = _mm_min_epi16(minabsdiff, absdiff); |
60 | | // Row 3 |
61 | 0 | s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 3 * p)), u0); |
62 | 0 | d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 3 * dp)), u0); |
63 | 0 | diff = _mm_subs_epi16(s0, d0); |
64 | 0 | negdiff = _mm_subs_epi16(u0, diff); |
65 | 0 | absdiff = _mm_max_epi16(diff, negdiff); |
66 | 0 | maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff); |
67 | 0 | minabsdiff = _mm_min_epi16(minabsdiff, absdiff); |
68 | | // Row 4 |
69 | 0 | s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 4 * p)), u0); |
70 | 0 | d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 4 * dp)), u0); |
71 | 0 | diff = _mm_subs_epi16(s0, d0); |
72 | 0 | negdiff = _mm_subs_epi16(u0, diff); |
73 | 0 | absdiff = _mm_max_epi16(diff, negdiff); |
74 | 0 | maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff); |
75 | 0 | minabsdiff = _mm_min_epi16(minabsdiff, absdiff); |
76 | | // Row 5 |
77 | 0 | s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 5 * p)), u0); |
78 | 0 | d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 5 * dp)), u0); |
79 | 0 | diff = _mm_subs_epi16(s0, d0); |
80 | 0 | negdiff = _mm_subs_epi16(u0, diff); |
81 | 0 | absdiff = _mm_max_epi16(diff, negdiff); |
82 | 0 | maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff); |
83 | 0 | minabsdiff = _mm_min_epi16(minabsdiff, absdiff); |
84 | | // Row 6 |
85 | 0 | s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 6 * p)), u0); |
86 | 0 | d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 6 * dp)), u0); |
87 | 0 | diff = _mm_subs_epi16(s0, d0); |
88 | 0 | negdiff = _mm_subs_epi16(u0, diff); |
89 | 0 | absdiff = _mm_max_epi16(diff, negdiff); |
90 | 0 | maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff); |
91 | 0 | minabsdiff = _mm_min_epi16(minabsdiff, absdiff); |
92 | | // Row 7 |
93 | 0 | s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 7 * p)), u0); |
94 | 0 | d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 7 * dp)), u0); |
95 | 0 | diff = _mm_subs_epi16(s0, d0); |
96 | 0 | negdiff = _mm_subs_epi16(u0, diff); |
97 | 0 | absdiff = _mm_max_epi16(diff, negdiff); |
98 | 0 | maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff); |
99 | 0 | minabsdiff = _mm_min_epi16(minabsdiff, absdiff); |
100 | |
|
101 | 0 | maxabsdiff = _mm_max_epi16(maxabsdiff, _mm_srli_si128(maxabsdiff, 8)); |
102 | 0 | maxabsdiff = _mm_max_epi16(maxabsdiff, _mm_srli_epi64(maxabsdiff, 32)); |
103 | 0 | maxabsdiff = _mm_max_epi16(maxabsdiff, _mm_srli_epi64(maxabsdiff, 16)); |
104 | 0 | *max = _mm_extract_epi16(maxabsdiff, 0); |
105 | |
|
106 | 0 | minabsdiff = _mm_min_epi16(minabsdiff, _mm_srli_si128(minabsdiff, 8)); |
107 | 0 | minabsdiff = _mm_min_epi16(minabsdiff, _mm_srli_epi64(minabsdiff, 32)); |
108 | 0 | minabsdiff = _mm_min_epi16(minabsdiff, _mm_srli_epi64(minabsdiff, 16)); |
109 | 0 | *min = _mm_extract_epi16(minabsdiff, 0); |
110 | 0 | } |
111 | | |
112 | 0 | unsigned int aom_avg_8x8_sse2(const uint8_t *s, int p) { |
113 | 0 | __m128i sum0, sum1, s0, s1, s2, s3, u0; |
114 | 0 | unsigned int avg = 0; |
115 | 0 | u0 = _mm_setzero_si128(); |
116 | 0 | s0 = loadh_epi64((const __m128i *)(s + p), |
117 | 0 | _mm_loadl_epi64((const __m128i *)(s))); |
118 | 0 | s1 = loadh_epi64((const __m128i *)(s + 3 * p), |
119 | 0 | _mm_loadl_epi64((const __m128i *)(s + 2 * p))); |
120 | 0 | s2 = loadh_epi64((const __m128i *)(s + 5 * p), |
121 | 0 | _mm_loadl_epi64((const __m128i *)(s + 4 * p))); |
122 | 0 | s3 = loadh_epi64((const __m128i *)(s + 7 * p), |
123 | 0 | _mm_loadl_epi64((const __m128i *)(s + 6 * p))); |
124 | 0 | s0 = _mm_sad_epu8(s0, u0); |
125 | 0 | s1 = _mm_sad_epu8(s1, u0); |
126 | 0 | s2 = _mm_sad_epu8(s2, u0); |
127 | 0 | s3 = _mm_sad_epu8(s3, u0); |
128 | |
|
129 | 0 | sum0 = _mm_add_epi16(s0, s1); |
130 | 0 | sum1 = _mm_add_epi16(s2, s3); |
131 | 0 | sum0 = _mm_add_epi16(sum0, sum1); |
132 | 0 | sum0 = _mm_add_epi16(sum0, _mm_srli_si128(sum0, 8)); |
133 | 0 | avg = _mm_cvtsi128_si32(sum0); |
134 | 0 | return (avg + 32) >> 6; |
135 | 0 | } |
136 | | |
137 | 0 | static void calc_avg_8x8_dual_sse2(const uint8_t *s, int p, int *avg) { |
138 | 0 | __m128i sum0, sum1, s0, s1, s2, s3, u0; |
139 | 0 | u0 = _mm_setzero_si128(); |
140 | 0 | s0 = _mm_sad_epu8(_mm_loadu_si128((const __m128i *)(s)), u0); |
141 | 0 | s1 = _mm_sad_epu8(_mm_loadu_si128((const __m128i *)(s + p)), u0); |
142 | 0 | s2 = _mm_sad_epu8(_mm_loadu_si128((const __m128i *)(s + 2 * p)), u0); |
143 | 0 | s3 = _mm_sad_epu8(_mm_loadu_si128((const __m128i *)(s + 3 * p)), u0); |
144 | 0 | sum0 = _mm_add_epi16(s0, s1); |
145 | 0 | sum1 = _mm_add_epi16(s2, s3); |
146 | 0 | s0 = _mm_sad_epu8(_mm_loadu_si128((const __m128i *)(s + 4 * p)), u0); |
147 | 0 | s1 = _mm_sad_epu8(_mm_loadu_si128((const __m128i *)(s + 5 * p)), u0); |
148 | 0 | s2 = _mm_sad_epu8(_mm_loadu_si128((const __m128i *)(s + 6 * p)), u0); |
149 | 0 | s3 = _mm_sad_epu8(_mm_loadu_si128((const __m128i *)(s + 7 * p)), u0); |
150 | 0 | sum0 = _mm_add_epi16(sum0, _mm_add_epi16(s0, s1)); |
151 | 0 | sum1 = _mm_add_epi16(sum1, _mm_add_epi16(s2, s3)); |
152 | 0 | sum0 = _mm_add_epi16(sum0, sum1); |
153 | | |
154 | | // (avg + 32) >> 6 |
155 | 0 | __m128i rounding = _mm_set1_epi32(32); |
156 | 0 | sum0 = _mm_add_epi32(sum0, rounding); |
157 | 0 | sum0 = _mm_srli_epi32(sum0, 6); |
158 | 0 | avg[0] = _mm_cvtsi128_si32(sum0); |
159 | 0 | avg[1] = _mm_extract_epi16(sum0, 4); |
160 | 0 | } |
161 | | |
162 | | void aom_avg_8x8_quad_sse2(const uint8_t *s, int p, int x16_idx, int y16_idx, |
163 | 0 | int *avg) { |
164 | 0 | const uint8_t *s_ptr = s + y16_idx * p + x16_idx; |
165 | 0 | for (int k = 0; k < 2; k++) { |
166 | 0 | calc_avg_8x8_dual_sse2(s_ptr, p, avg + k * 2); |
167 | 0 | s_ptr += 8 * p; |
168 | 0 | } |
169 | 0 | } |
170 | | |
171 | 0 | unsigned int aom_avg_4x4_sse2(const uint8_t *s, int p) { |
172 | 0 | __m128i s0, s1, u0; |
173 | 0 | unsigned int avg = 0; |
174 | 0 | u0 = _mm_setzero_si128(); |
175 | 0 | s0 = _mm_unpacklo_epi32(xx_loadl_32(s), xx_loadl_32(s + p)); |
176 | 0 | s1 = _mm_unpacklo_epi32(xx_loadl_32(s + p * 2), xx_loadl_32(s + p * 3)); |
177 | 0 | s0 = _mm_sad_epu8(s0, u0); |
178 | 0 | s1 = _mm_sad_epu8(s1, u0); |
179 | 0 | s0 = _mm_add_epi16(s0, s1); |
180 | 0 | avg = _mm_cvtsi128_si32(s0); |
181 | 0 | return (avg + 8) >> 4; |
182 | 0 | } |
183 | | |
184 | 0 | static inline void hadamard_col4_sse2(__m128i *in, int iter) { |
185 | 0 | const __m128i a0 = in[0]; |
186 | 0 | const __m128i a1 = in[1]; |
187 | 0 | const __m128i a2 = in[2]; |
188 | 0 | const __m128i a3 = in[3]; |
189 | 0 | const __m128i b0 = _mm_srai_epi16(_mm_add_epi16(a0, a1), 1); |
190 | 0 | const __m128i b1 = _mm_srai_epi16(_mm_sub_epi16(a0, a1), 1); |
191 | 0 | const __m128i b2 = _mm_srai_epi16(_mm_add_epi16(a2, a3), 1); |
192 | 0 | const __m128i b3 = _mm_srai_epi16(_mm_sub_epi16(a2, a3), 1); |
193 | 0 | in[0] = _mm_add_epi16(b0, b2); |
194 | 0 | in[1] = _mm_add_epi16(b1, b3); |
195 | 0 | in[2] = _mm_sub_epi16(b0, b2); |
196 | 0 | in[3] = _mm_sub_epi16(b1, b3); |
197 | |
|
198 | 0 | if (iter == 0) { |
199 | 0 | const __m128i ba = _mm_unpacklo_epi16(in[0], in[1]); |
200 | 0 | const __m128i dc = _mm_unpacklo_epi16(in[2], in[3]); |
201 | 0 | const __m128i dcba_lo = _mm_unpacklo_epi32(ba, dc); |
202 | 0 | const __m128i dcba_hi = _mm_unpackhi_epi32(ba, dc); |
203 | 0 | in[0] = dcba_lo; |
204 | 0 | in[1] = _mm_srli_si128(dcba_lo, 8); |
205 | 0 | in[2] = dcba_hi; |
206 | 0 | in[3] = _mm_srli_si128(dcba_hi, 8); |
207 | 0 | } |
208 | 0 | } |
209 | | |
210 | | void aom_hadamard_4x4_sse2(const int16_t *src_diff, ptrdiff_t src_stride, |
211 | 0 | tran_low_t *coeff) { |
212 | 0 | __m128i src[4]; |
213 | 0 | src[0] = _mm_loadl_epi64((const __m128i *)src_diff); |
214 | 0 | src[1] = _mm_loadl_epi64((const __m128i *)(src_diff += src_stride)); |
215 | 0 | src[2] = _mm_loadl_epi64((const __m128i *)(src_diff += src_stride)); |
216 | 0 | src[3] = _mm_loadl_epi64((const __m128i *)(src_diff + src_stride)); |
217 | |
|
218 | 0 | hadamard_col4_sse2(src, 0); |
219 | 0 | hadamard_col4_sse2(src, 1); |
220 | |
|
221 | 0 | store_tran_low(_mm_unpacklo_epi64(src[0], src[1]), coeff); |
222 | 0 | coeff += 8; |
223 | 0 | store_tran_low(_mm_unpacklo_epi64(src[2], src[3]), coeff); |
224 | 0 | } |
225 | | |
226 | 0 | static inline void hadamard_col8_sse2(__m128i *in, int iter) { |
227 | 0 | __m128i a0 = in[0]; |
228 | 0 | __m128i a1 = in[1]; |
229 | 0 | __m128i a2 = in[2]; |
230 | 0 | __m128i a3 = in[3]; |
231 | 0 | __m128i a4 = in[4]; |
232 | 0 | __m128i a5 = in[5]; |
233 | 0 | __m128i a6 = in[6]; |
234 | 0 | __m128i a7 = in[7]; |
235 | |
|
236 | 0 | __m128i b0 = _mm_add_epi16(a0, a1); |
237 | 0 | __m128i b1 = _mm_sub_epi16(a0, a1); |
238 | 0 | __m128i b2 = _mm_add_epi16(a2, a3); |
239 | 0 | __m128i b3 = _mm_sub_epi16(a2, a3); |
240 | 0 | __m128i b4 = _mm_add_epi16(a4, a5); |
241 | 0 | __m128i b5 = _mm_sub_epi16(a4, a5); |
242 | 0 | __m128i b6 = _mm_add_epi16(a6, a7); |
243 | 0 | __m128i b7 = _mm_sub_epi16(a6, a7); |
244 | |
|
245 | 0 | a0 = _mm_add_epi16(b0, b2); |
246 | 0 | a1 = _mm_add_epi16(b1, b3); |
247 | 0 | a2 = _mm_sub_epi16(b0, b2); |
248 | 0 | a3 = _mm_sub_epi16(b1, b3); |
249 | 0 | a4 = _mm_add_epi16(b4, b6); |
250 | 0 | a5 = _mm_add_epi16(b5, b7); |
251 | 0 | a6 = _mm_sub_epi16(b4, b6); |
252 | 0 | a7 = _mm_sub_epi16(b5, b7); |
253 | |
|
254 | 0 | if (iter == 0) { |
255 | 0 | b0 = _mm_add_epi16(a0, a4); |
256 | 0 | b7 = _mm_add_epi16(a1, a5); |
257 | 0 | b3 = _mm_add_epi16(a2, a6); |
258 | 0 | b4 = _mm_add_epi16(a3, a7); |
259 | 0 | b2 = _mm_sub_epi16(a0, a4); |
260 | 0 | b6 = _mm_sub_epi16(a1, a5); |
261 | 0 | b1 = _mm_sub_epi16(a2, a6); |
262 | 0 | b5 = _mm_sub_epi16(a3, a7); |
263 | |
|
264 | 0 | a0 = _mm_unpacklo_epi16(b0, b1); |
265 | 0 | a1 = _mm_unpacklo_epi16(b2, b3); |
266 | 0 | a2 = _mm_unpackhi_epi16(b0, b1); |
267 | 0 | a3 = _mm_unpackhi_epi16(b2, b3); |
268 | 0 | a4 = _mm_unpacklo_epi16(b4, b5); |
269 | 0 | a5 = _mm_unpacklo_epi16(b6, b7); |
270 | 0 | a6 = _mm_unpackhi_epi16(b4, b5); |
271 | 0 | a7 = _mm_unpackhi_epi16(b6, b7); |
272 | |
|
273 | 0 | b0 = _mm_unpacklo_epi32(a0, a1); |
274 | 0 | b1 = _mm_unpacklo_epi32(a4, a5); |
275 | 0 | b2 = _mm_unpackhi_epi32(a0, a1); |
276 | 0 | b3 = _mm_unpackhi_epi32(a4, a5); |
277 | 0 | b4 = _mm_unpacklo_epi32(a2, a3); |
278 | 0 | b5 = _mm_unpacklo_epi32(a6, a7); |
279 | 0 | b6 = _mm_unpackhi_epi32(a2, a3); |
280 | 0 | b7 = _mm_unpackhi_epi32(a6, a7); |
281 | |
|
282 | 0 | in[0] = _mm_unpacklo_epi64(b0, b1); |
283 | 0 | in[1] = _mm_unpackhi_epi64(b0, b1); |
284 | 0 | in[2] = _mm_unpacklo_epi64(b2, b3); |
285 | 0 | in[3] = _mm_unpackhi_epi64(b2, b3); |
286 | 0 | in[4] = _mm_unpacklo_epi64(b4, b5); |
287 | 0 | in[5] = _mm_unpackhi_epi64(b4, b5); |
288 | 0 | in[6] = _mm_unpacklo_epi64(b6, b7); |
289 | 0 | in[7] = _mm_unpackhi_epi64(b6, b7); |
290 | 0 | } else { |
291 | 0 | in[0] = _mm_add_epi16(a0, a4); |
292 | 0 | in[7] = _mm_add_epi16(a1, a5); |
293 | 0 | in[3] = _mm_add_epi16(a2, a6); |
294 | 0 | in[4] = _mm_add_epi16(a3, a7); |
295 | 0 | in[2] = _mm_sub_epi16(a0, a4); |
296 | 0 | in[6] = _mm_sub_epi16(a1, a5); |
297 | 0 | in[1] = _mm_sub_epi16(a2, a6); |
298 | 0 | in[5] = _mm_sub_epi16(a3, a7); |
299 | 0 | } |
300 | 0 | } |
301 | | |
302 | | static inline void hadamard_8x8_sse2(const int16_t *src_diff, |
303 | | ptrdiff_t src_stride, tran_low_t *coeff, |
304 | 0 | int is_final) { |
305 | 0 | __m128i src[8]; |
306 | 0 | src[0] = _mm_load_si128((const __m128i *)src_diff); |
307 | 0 | src[1] = _mm_load_si128((const __m128i *)(src_diff += src_stride)); |
308 | 0 | src[2] = _mm_load_si128((const __m128i *)(src_diff += src_stride)); |
309 | 0 | src[3] = _mm_load_si128((const __m128i *)(src_diff += src_stride)); |
310 | 0 | src[4] = _mm_load_si128((const __m128i *)(src_diff += src_stride)); |
311 | 0 | src[5] = _mm_load_si128((const __m128i *)(src_diff += src_stride)); |
312 | 0 | src[6] = _mm_load_si128((const __m128i *)(src_diff += src_stride)); |
313 | 0 | src[7] = _mm_load_si128((const __m128i *)(src_diff + src_stride)); |
314 | |
|
315 | 0 | hadamard_col8_sse2(src, 0); |
316 | 0 | hadamard_col8_sse2(src, 1); |
317 | |
|
318 | 0 | if (is_final) { |
319 | 0 | store_tran_low(src[0], coeff); |
320 | 0 | coeff += 8; |
321 | 0 | store_tran_low(src[1], coeff); |
322 | 0 | coeff += 8; |
323 | 0 | store_tran_low(src[2], coeff); |
324 | 0 | coeff += 8; |
325 | 0 | store_tran_low(src[3], coeff); |
326 | 0 | coeff += 8; |
327 | 0 | store_tran_low(src[4], coeff); |
328 | 0 | coeff += 8; |
329 | 0 | store_tran_low(src[5], coeff); |
330 | 0 | coeff += 8; |
331 | 0 | store_tran_low(src[6], coeff); |
332 | 0 | coeff += 8; |
333 | 0 | store_tran_low(src[7], coeff); |
334 | 0 | } else { |
335 | 0 | int16_t *coeff16 = (int16_t *)coeff; |
336 | 0 | _mm_store_si128((__m128i *)coeff16, src[0]); |
337 | 0 | coeff16 += 8; |
338 | 0 | _mm_store_si128((__m128i *)coeff16, src[1]); |
339 | 0 | coeff16 += 8; |
340 | 0 | _mm_store_si128((__m128i *)coeff16, src[2]); |
341 | 0 | coeff16 += 8; |
342 | 0 | _mm_store_si128((__m128i *)coeff16, src[3]); |
343 | 0 | coeff16 += 8; |
344 | 0 | _mm_store_si128((__m128i *)coeff16, src[4]); |
345 | 0 | coeff16 += 8; |
346 | 0 | _mm_store_si128((__m128i *)coeff16, src[5]); |
347 | 0 | coeff16 += 8; |
348 | 0 | _mm_store_si128((__m128i *)coeff16, src[6]); |
349 | 0 | coeff16 += 8; |
350 | 0 | _mm_store_si128((__m128i *)coeff16, src[7]); |
351 | 0 | } |
352 | 0 | } |
353 | | |
354 | | void aom_hadamard_8x8_sse2(const int16_t *src_diff, ptrdiff_t src_stride, |
355 | 0 | tran_low_t *coeff) { |
356 | 0 | hadamard_8x8_sse2(src_diff, src_stride, coeff, 1); |
357 | 0 | } |
358 | | |
359 | | static inline void hadamard_lp_8x8_sse2(const int16_t *src_diff, |
360 | 0 | ptrdiff_t src_stride, int16_t *coeff) { |
361 | 0 | __m128i src[8]; |
362 | 0 | src[0] = _mm_load_si128((const __m128i *)src_diff); |
363 | 0 | src[1] = _mm_load_si128((const __m128i *)(src_diff += src_stride)); |
364 | 0 | src[2] = _mm_load_si128((const __m128i *)(src_diff += src_stride)); |
365 | 0 | src[3] = _mm_load_si128((const __m128i *)(src_diff += src_stride)); |
366 | 0 | src[4] = _mm_load_si128((const __m128i *)(src_diff += src_stride)); |
367 | 0 | src[5] = _mm_load_si128((const __m128i *)(src_diff += src_stride)); |
368 | 0 | src[6] = _mm_load_si128((const __m128i *)(src_diff += src_stride)); |
369 | 0 | src[7] = _mm_load_si128((const __m128i *)(src_diff + src_stride)); |
370 | |
|
371 | 0 | hadamard_col8_sse2(src, 0); |
372 | 0 | hadamard_col8_sse2(src, 1); |
373 | |
|
374 | 0 | _mm_store_si128((__m128i *)coeff, src[0]); |
375 | 0 | coeff += 8; |
376 | 0 | _mm_store_si128((__m128i *)coeff, src[1]); |
377 | 0 | coeff += 8; |
378 | 0 | _mm_store_si128((__m128i *)coeff, src[2]); |
379 | 0 | coeff += 8; |
380 | 0 | _mm_store_si128((__m128i *)coeff, src[3]); |
381 | 0 | coeff += 8; |
382 | 0 | _mm_store_si128((__m128i *)coeff, src[4]); |
383 | 0 | coeff += 8; |
384 | 0 | _mm_store_si128((__m128i *)coeff, src[5]); |
385 | 0 | coeff += 8; |
386 | 0 | _mm_store_si128((__m128i *)coeff, src[6]); |
387 | 0 | coeff += 8; |
388 | 0 | _mm_store_si128((__m128i *)coeff, src[7]); |
389 | 0 | } |
390 | | |
391 | | void aom_hadamard_lp_8x8_sse2(const int16_t *src_diff, ptrdiff_t src_stride, |
392 | 0 | int16_t *coeff) { |
393 | 0 | hadamard_lp_8x8_sse2(src_diff, src_stride, coeff); |
394 | 0 | } |
395 | | |
396 | | void aom_hadamard_lp_8x8_dual_sse2(const int16_t *src_diff, |
397 | 0 | ptrdiff_t src_stride, int16_t *coeff) { |
398 | 0 | for (int i = 0; i < 2; i++) { |
399 | 0 | hadamard_lp_8x8_sse2(src_diff + (i * 8), src_stride, coeff + (i * 64)); |
400 | 0 | } |
401 | 0 | } |
402 | | |
403 | | void aom_hadamard_lp_16x16_sse2(const int16_t *src_diff, ptrdiff_t src_stride, |
404 | 0 | int16_t *coeff) { |
405 | 0 | for (int idx = 0; idx < 4; ++idx) { |
406 | 0 | const int16_t *src_ptr = |
407 | 0 | src_diff + (idx >> 1) * 8 * src_stride + (idx & 0x01) * 8; |
408 | 0 | hadamard_lp_8x8_sse2(src_ptr, src_stride, coeff + idx * 64); |
409 | 0 | } |
410 | |
|
411 | 0 | int16_t *t_coeff = coeff; |
412 | 0 | for (int idx = 0; idx < 64; idx += 8) { |
413 | 0 | __m128i coeff0 = _mm_load_si128((const __m128i *)t_coeff); |
414 | 0 | __m128i coeff1 = _mm_load_si128((const __m128i *)(t_coeff + 64)); |
415 | 0 | __m128i coeff2 = _mm_load_si128((const __m128i *)(t_coeff + 128)); |
416 | 0 | __m128i coeff3 = _mm_load_si128((const __m128i *)(t_coeff + 192)); |
417 | |
|
418 | 0 | __m128i b0 = _mm_add_epi16(coeff0, coeff1); |
419 | 0 | __m128i b1 = _mm_sub_epi16(coeff0, coeff1); |
420 | 0 | __m128i b2 = _mm_add_epi16(coeff2, coeff3); |
421 | 0 | __m128i b3 = _mm_sub_epi16(coeff2, coeff3); |
422 | |
|
423 | 0 | b0 = _mm_srai_epi16(b0, 1); |
424 | 0 | b1 = _mm_srai_epi16(b1, 1); |
425 | 0 | b2 = _mm_srai_epi16(b2, 1); |
426 | 0 | b3 = _mm_srai_epi16(b3, 1); |
427 | |
|
428 | 0 | coeff0 = _mm_add_epi16(b0, b2); |
429 | 0 | coeff1 = _mm_add_epi16(b1, b3); |
430 | 0 | coeff2 = _mm_sub_epi16(b0, b2); |
431 | 0 | coeff3 = _mm_sub_epi16(b1, b3); |
432 | |
|
433 | 0 | _mm_store_si128((__m128i *)t_coeff, coeff0); |
434 | 0 | _mm_store_si128((__m128i *)(t_coeff + 64), coeff1); |
435 | 0 | _mm_store_si128((__m128i *)(t_coeff + 128), coeff2); |
436 | 0 | _mm_store_si128((__m128i *)(t_coeff + 192), coeff3); |
437 | |
|
438 | 0 | t_coeff += 8; |
439 | 0 | } |
440 | 0 | } |
441 | | |
442 | | static inline void hadamard_16x16_sse2(const int16_t *src_diff, |
443 | | ptrdiff_t src_stride, tran_low_t *coeff, |
444 | 0 | int is_final) { |
445 | | // For high bitdepths, it is unnecessary to store_tran_low |
446 | | // (mult/unpack/store), then load_tran_low (load/pack) the same memory in the |
447 | | // next stage. Output to an intermediate buffer first, then store_tran_low() |
448 | | // in the final stage. |
449 | 0 | DECLARE_ALIGNED(32, int16_t, temp_coeff[16 * 16]); |
450 | 0 | int16_t *t_coeff = temp_coeff; |
451 | 0 | int16_t *coeff16 = (int16_t *)coeff; |
452 | 0 | int idx; |
453 | 0 | for (idx = 0; idx < 4; ++idx) { |
454 | 0 | const int16_t *src_ptr = |
455 | 0 | src_diff + (idx >> 1) * 8 * src_stride + (idx & 0x01) * 8; |
456 | 0 | hadamard_8x8_sse2(src_ptr, src_stride, (tran_low_t *)(t_coeff + idx * 64), |
457 | 0 | 0); |
458 | 0 | } |
459 | |
|
460 | 0 | for (idx = 0; idx < 64; idx += 8) { |
461 | 0 | __m128i coeff0 = _mm_load_si128((const __m128i *)t_coeff); |
462 | 0 | __m128i coeff1 = _mm_load_si128((const __m128i *)(t_coeff + 64)); |
463 | 0 | __m128i coeff2 = _mm_load_si128((const __m128i *)(t_coeff + 128)); |
464 | 0 | __m128i coeff3 = _mm_load_si128((const __m128i *)(t_coeff + 192)); |
465 | |
|
466 | 0 | __m128i b0 = _mm_add_epi16(coeff0, coeff1); |
467 | 0 | __m128i b1 = _mm_sub_epi16(coeff0, coeff1); |
468 | 0 | __m128i b2 = _mm_add_epi16(coeff2, coeff3); |
469 | 0 | __m128i b3 = _mm_sub_epi16(coeff2, coeff3); |
470 | |
|
471 | 0 | b0 = _mm_srai_epi16(b0, 1); |
472 | 0 | b1 = _mm_srai_epi16(b1, 1); |
473 | 0 | b2 = _mm_srai_epi16(b2, 1); |
474 | 0 | b3 = _mm_srai_epi16(b3, 1); |
475 | |
|
476 | 0 | coeff0 = _mm_add_epi16(b0, b2); |
477 | 0 | coeff1 = _mm_add_epi16(b1, b3); |
478 | 0 | coeff2 = _mm_sub_epi16(b0, b2); |
479 | 0 | coeff3 = _mm_sub_epi16(b1, b3); |
480 | |
|
481 | 0 | if (is_final) { |
482 | 0 | store_tran_low_offset_4(coeff0, coeff); |
483 | 0 | store_tran_low_offset_4(coeff1, coeff + 64); |
484 | 0 | store_tran_low_offset_4(coeff2, coeff + 128); |
485 | 0 | store_tran_low_offset_4(coeff3, coeff + 192); |
486 | 0 | coeff += 4; |
487 | 0 | } else { |
488 | 0 | _mm_store_si128((__m128i *)coeff16, coeff0); |
489 | 0 | _mm_store_si128((__m128i *)(coeff16 + 64), coeff1); |
490 | 0 | _mm_store_si128((__m128i *)(coeff16 + 128), coeff2); |
491 | 0 | _mm_store_si128((__m128i *)(coeff16 + 192), coeff3); |
492 | 0 | coeff16 += 8; |
493 | 0 | } |
494 | |
|
495 | 0 | t_coeff += 8; |
496 | | // Increment the pointer additionally by 0 and 8 in alternate |
497 | | // iterations(instead of 8) to ensure the coherency with the implementation |
498 | | // of store_tran_low_offset_4() |
499 | 0 | coeff += (((idx >> 3) & 1) << 3); |
500 | 0 | } |
501 | 0 | } |
502 | | |
503 | | void aom_hadamard_16x16_sse2(const int16_t *src_diff, ptrdiff_t src_stride, |
504 | 0 | tran_low_t *coeff) { |
505 | 0 | hadamard_16x16_sse2(src_diff, src_stride, coeff, 1); |
506 | 0 | } |
507 | | |
508 | | void aom_hadamard_32x32_sse2(const int16_t *src_diff, ptrdiff_t src_stride, |
509 | 0 | tran_low_t *coeff) { |
510 | | // For high bitdepths, it is unnecessary to store_tran_low |
511 | | // (mult/unpack/store), then load_tran_low (load/pack) the same memory in the |
512 | | // next stage. Output to an intermediate buffer first, then store_tran_low() |
513 | | // in the final stage. |
514 | 0 | DECLARE_ALIGNED(32, int16_t, temp_coeff[32 * 32]); |
515 | 0 | int16_t *t_coeff = temp_coeff; |
516 | 0 | int idx; |
517 | 0 | __m128i coeff0_lo, coeff1_lo, coeff2_lo, coeff3_lo, b0_lo, b1_lo, b2_lo, |
518 | 0 | b3_lo; |
519 | 0 | __m128i coeff0_hi, coeff1_hi, coeff2_hi, coeff3_hi, b0_hi, b1_hi, b2_hi, |
520 | 0 | b3_hi; |
521 | 0 | __m128i b0, b1, b2, b3; |
522 | 0 | const __m128i zero = _mm_setzero_si128(); |
523 | 0 | for (idx = 0; idx < 4; ++idx) { |
524 | 0 | const int16_t *src_ptr = |
525 | 0 | src_diff + (idx >> 1) * 16 * src_stride + (idx & 0x01) * 16; |
526 | 0 | hadamard_16x16_sse2(src_ptr, src_stride, |
527 | 0 | (tran_low_t *)(t_coeff + idx * 256), 0); |
528 | 0 | } |
529 | |
|
530 | 0 | for (idx = 0; idx < 256; idx += 8) { |
531 | 0 | __m128i coeff0 = _mm_load_si128((const __m128i *)t_coeff); |
532 | 0 | __m128i coeff1 = _mm_load_si128((const __m128i *)(t_coeff + 256)); |
533 | 0 | __m128i coeff2 = _mm_load_si128((const __m128i *)(t_coeff + 512)); |
534 | 0 | __m128i coeff3 = _mm_load_si128((const __m128i *)(t_coeff + 768)); |
535 | | |
536 | | // Sign extend 16 bit to 32 bit. |
537 | 0 | sign_extend_16bit_to_32bit_sse2(coeff0, zero, &coeff0_lo, &coeff0_hi); |
538 | 0 | sign_extend_16bit_to_32bit_sse2(coeff1, zero, &coeff1_lo, &coeff1_hi); |
539 | 0 | sign_extend_16bit_to_32bit_sse2(coeff2, zero, &coeff2_lo, &coeff2_hi); |
540 | 0 | sign_extend_16bit_to_32bit_sse2(coeff3, zero, &coeff3_lo, &coeff3_hi); |
541 | |
|
542 | 0 | b0_lo = _mm_add_epi32(coeff0_lo, coeff1_lo); |
543 | 0 | b0_hi = _mm_add_epi32(coeff0_hi, coeff1_hi); |
544 | |
|
545 | 0 | b1_lo = _mm_sub_epi32(coeff0_lo, coeff1_lo); |
546 | 0 | b1_hi = _mm_sub_epi32(coeff0_hi, coeff1_hi); |
547 | |
|
548 | 0 | b2_lo = _mm_add_epi32(coeff2_lo, coeff3_lo); |
549 | 0 | b2_hi = _mm_add_epi32(coeff2_hi, coeff3_hi); |
550 | |
|
551 | 0 | b3_lo = _mm_sub_epi32(coeff2_lo, coeff3_lo); |
552 | 0 | b3_hi = _mm_sub_epi32(coeff2_hi, coeff3_hi); |
553 | |
|
554 | 0 | b0_lo = _mm_srai_epi32(b0_lo, 2); |
555 | 0 | b1_lo = _mm_srai_epi32(b1_lo, 2); |
556 | 0 | b2_lo = _mm_srai_epi32(b2_lo, 2); |
557 | 0 | b3_lo = _mm_srai_epi32(b3_lo, 2); |
558 | |
|
559 | 0 | b0_hi = _mm_srai_epi32(b0_hi, 2); |
560 | 0 | b1_hi = _mm_srai_epi32(b1_hi, 2); |
561 | 0 | b2_hi = _mm_srai_epi32(b2_hi, 2); |
562 | 0 | b3_hi = _mm_srai_epi32(b3_hi, 2); |
563 | |
|
564 | 0 | b0 = _mm_packs_epi32(b0_lo, b0_hi); |
565 | 0 | b1 = _mm_packs_epi32(b1_lo, b1_hi); |
566 | 0 | b2 = _mm_packs_epi32(b2_lo, b2_hi); |
567 | 0 | b3 = _mm_packs_epi32(b3_lo, b3_hi); |
568 | |
|
569 | 0 | coeff0 = _mm_add_epi16(b0, b2); |
570 | 0 | coeff1 = _mm_add_epi16(b1, b3); |
571 | 0 | store_tran_low_offset_4(coeff0, coeff); |
572 | 0 | store_tran_low_offset_4(coeff1, coeff + 256); |
573 | |
|
574 | 0 | coeff2 = _mm_sub_epi16(b0, b2); |
575 | 0 | coeff3 = _mm_sub_epi16(b1, b3); |
576 | 0 | store_tran_low_offset_4(coeff2, coeff + 512); |
577 | 0 | store_tran_low_offset_4(coeff3, coeff + 768); |
578 | | |
579 | | // Increment the pointer by 4 and 12 in alternate iterations(instead of 8) |
580 | | // to ensure the coherency with the implementation of |
581 | | // store_tran_low_offset_4() |
582 | 0 | coeff += (4 + (((idx >> 3) & 1) << 3)); |
583 | 0 | t_coeff += 8; |
584 | 0 | } |
585 | 0 | } |
586 | | |
587 | 0 | int aom_satd_sse2(const tran_low_t *coeff, int length) { |
588 | 0 | int i; |
589 | 0 | const __m128i zero = _mm_setzero_si128(); |
590 | 0 | __m128i accum = zero; |
591 | |
|
592 | 0 | for (i = 0; i < length; i += 4) { |
593 | 0 | const __m128i src_line = _mm_load_si128((const __m128i *)coeff); |
594 | 0 | const __m128i coeff_sign = _mm_srai_epi32(src_line, 31); |
595 | 0 | const __m128i abs_coeff = invert_sign_32_sse2(src_line, coeff_sign); |
596 | 0 | accum = _mm_add_epi32(accum, abs_coeff); |
597 | 0 | coeff += 4; |
598 | 0 | } |
599 | |
|
600 | 0 | { // cascading summation of accum |
601 | 0 | __m128i hi = _mm_srli_si128(accum, 8); |
602 | 0 | accum = _mm_add_epi32(accum, hi); |
603 | 0 | hi = _mm_srli_epi64(accum, 32); |
604 | 0 | accum = _mm_add_epi32(accum, hi); |
605 | 0 | } |
606 | |
|
607 | 0 | return _mm_cvtsi128_si32(accum); |
608 | 0 | } |
609 | | |
610 | 0 | int aom_satd_lp_sse2(const int16_t *coeff, int length) { |
611 | 0 | const __m128i zero = _mm_setzero_si128(); |
612 | 0 | const __m128i one = _mm_set1_epi16(1); |
613 | 0 | __m128i accum = zero; |
614 | |
|
615 | 0 | for (int i = 0; i < length; i += 16) { |
616 | 0 | const __m128i src_line0 = _mm_loadu_si128((const __m128i *)coeff); |
617 | 0 | const __m128i src_line1 = _mm_loadu_si128((const __m128i *)(coeff + 8)); |
618 | 0 | const __m128i inv0 = _mm_sub_epi16(zero, src_line0); |
619 | 0 | const __m128i inv1 = _mm_sub_epi16(zero, src_line1); |
620 | 0 | const __m128i abs0 = _mm_max_epi16(src_line0, inv0); // abs(src_line) |
621 | 0 | const __m128i abs1 = _mm_max_epi16(src_line1, inv1); // abs(src_line) |
622 | 0 | const __m128i sum0 = _mm_madd_epi16(abs0, one); |
623 | 0 | const __m128i sum1 = _mm_madd_epi16(abs1, one); |
624 | 0 | accum = _mm_add_epi32(accum, sum0); |
625 | 0 | accum = _mm_add_epi32(accum, sum1); |
626 | 0 | coeff += 16; |
627 | 0 | } |
628 | |
|
629 | 0 | { // cascading summation of accum |
630 | 0 | __m128i hi = _mm_srli_si128(accum, 8); |
631 | 0 | accum = _mm_add_epi32(accum, hi); |
632 | 0 | hi = _mm_srli_epi64(accum, 32); |
633 | 0 | accum = _mm_add_epi32(accum, hi); |
634 | 0 | } |
635 | |
|
636 | 0 | return _mm_cvtsi128_si32(accum); |
637 | 0 | } |
638 | | |
639 | | void aom_int_pro_row_sse2(int16_t *hbuf, const uint8_t *ref, |
640 | | const int ref_stride, const int width, |
641 | 0 | const int height, int norm_factor) { |
642 | | // SIMD implementation assumes width and height to be multiple of 16 and 2 |
643 | | // respectively. For any odd width or height, SIMD support needs to be added. |
644 | 0 | assert(width % 16 == 0 && height % 2 == 0); |
645 | 0 | __m128i zero = _mm_setzero_si128(); |
646 | |
|
647 | 0 | for (int wd = 0; wd < width; wd += 16) { |
648 | 0 | const uint8_t *ref_tmp = ref + wd; |
649 | 0 | int16_t *hbuf_tmp = hbuf + wd; |
650 | 0 | __m128i s0 = zero; |
651 | 0 | __m128i s1 = zero; |
652 | 0 | int idx = 0; |
653 | 0 | do { |
654 | 0 | __m128i src_line = _mm_loadu_si128((const __m128i *)ref_tmp); |
655 | 0 | __m128i t0 = _mm_unpacklo_epi8(src_line, zero); |
656 | 0 | __m128i t1 = _mm_unpackhi_epi8(src_line, zero); |
657 | 0 | s0 = _mm_add_epi16(s0, t0); |
658 | 0 | s1 = _mm_add_epi16(s1, t1); |
659 | 0 | ref_tmp += ref_stride; |
660 | |
|
661 | 0 | src_line = _mm_loadu_si128((const __m128i *)ref_tmp); |
662 | 0 | t0 = _mm_unpacklo_epi8(src_line, zero); |
663 | 0 | t1 = _mm_unpackhi_epi8(src_line, zero); |
664 | 0 | s0 = _mm_add_epi16(s0, t0); |
665 | 0 | s1 = _mm_add_epi16(s1, t1); |
666 | 0 | ref_tmp += ref_stride; |
667 | 0 | idx += 2; |
668 | 0 | } while (idx < height); |
669 | |
|
670 | 0 | s0 = _mm_srai_epi16(s0, norm_factor); |
671 | 0 | s1 = _mm_srai_epi16(s1, norm_factor); |
672 | 0 | _mm_storeu_si128((__m128i *)(hbuf_tmp), s0); |
673 | 0 | _mm_storeu_si128((__m128i *)(hbuf_tmp + 8), s1); |
674 | 0 | } |
675 | 0 | } |
676 | | |
677 | | void aom_int_pro_col_sse2(int16_t *vbuf, const uint8_t *ref, |
678 | | const int ref_stride, const int width, |
679 | 0 | const int height, int norm_factor) { |
680 | | // SIMD implementation assumes width to be multiple of 16. |
681 | 0 | assert(width % 16 == 0); |
682 | | |
683 | 0 | for (int ht = 0; ht < height; ht++) { |
684 | 0 | const uint8_t *ref_tmp = ref + (ht * ref_stride); |
685 | 0 | __m128i zero = _mm_setzero_si128(); |
686 | 0 | __m128i s0 = zero; |
687 | 0 | __m128i s1, src_line; |
688 | 0 | for (int i = 0; i < width; i += 16) { |
689 | 0 | src_line = _mm_loadu_si128((const __m128i *)ref_tmp); |
690 | 0 | s1 = _mm_sad_epu8(src_line, zero); |
691 | 0 | s0 = _mm_add_epi16(s0, s1); |
692 | 0 | ref_tmp += 16; |
693 | 0 | } |
694 | |
|
695 | | s1 = _mm_srli_si128(s0, 8); |
696 | 0 | s0 = _mm_add_epi16(s0, s1); |
697 | 0 | vbuf[ht] = _mm_cvtsi128_si32(s0) >> norm_factor; |
698 | 0 | } |
699 | 0 | } |