/src/aom/aom_dsp/x86/variance_avx2.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 | | |
16 | | #include "aom_dsp/x86/masked_variance_intrin_ssse3.h" |
17 | | #include "aom_dsp/x86/synonyms.h" |
18 | | |
19 | 0 | static inline __m128i mm256_add_hi_lo_epi16(const __m256i val) { |
20 | 0 | return _mm_add_epi16(_mm256_castsi256_si128(val), |
21 | 0 | _mm256_extractf128_si256(val, 1)); |
22 | 0 | } |
23 | | |
24 | 0 | static inline __m128i mm256_add_hi_lo_epi32(const __m256i val) { |
25 | 0 | return _mm_add_epi32(_mm256_castsi256_si128(val), |
26 | 0 | _mm256_extractf128_si256(val, 1)); |
27 | 0 | } |
28 | | |
29 | | static inline void variance_kernel_avx2(const __m256i src, const __m256i ref, |
30 | | __m256i *const sse, |
31 | 0 | __m256i *const sum) { |
32 | 0 | const __m256i adj_sub = _mm256_set1_epi16((short)0xff01); // (1,-1) |
33 | | |
34 | | // unpack into pairs of source and reference values |
35 | 0 | const __m256i src_ref0 = _mm256_unpacklo_epi8(src, ref); |
36 | 0 | const __m256i src_ref1 = _mm256_unpackhi_epi8(src, ref); |
37 | | |
38 | | // subtract adjacent elements using src*1 + ref*-1 |
39 | 0 | const __m256i diff0 = _mm256_maddubs_epi16(src_ref0, adj_sub); |
40 | 0 | const __m256i diff1 = _mm256_maddubs_epi16(src_ref1, adj_sub); |
41 | 0 | const __m256i madd0 = _mm256_madd_epi16(diff0, diff0); |
42 | 0 | const __m256i madd1 = _mm256_madd_epi16(diff1, diff1); |
43 | | |
44 | | // add to the running totals |
45 | 0 | *sum = _mm256_add_epi16(*sum, _mm256_add_epi16(diff0, diff1)); |
46 | 0 | *sse = _mm256_add_epi32(*sse, _mm256_add_epi32(madd0, madd1)); |
47 | 0 | } |
48 | | |
49 | | static inline int variance_final_from_32bit_sum_avx2(__m256i vsse, __m128i vsum, |
50 | 0 | unsigned int *const sse) { |
51 | | // extract the low lane and add it to the high lane |
52 | 0 | const __m128i sse_reg_128 = mm256_add_hi_lo_epi32(vsse); |
53 | | |
54 | | // unpack sse and sum registers and add |
55 | 0 | const __m128i sse_sum_lo = _mm_unpacklo_epi32(sse_reg_128, vsum); |
56 | 0 | const __m128i sse_sum_hi = _mm_unpackhi_epi32(sse_reg_128, vsum); |
57 | 0 | const __m128i sse_sum = _mm_add_epi32(sse_sum_lo, sse_sum_hi); |
58 | | |
59 | | // perform the final summation and extract the results |
60 | 0 | const __m128i res = _mm_add_epi32(sse_sum, _mm_srli_si128(sse_sum, 8)); |
61 | 0 | *((int *)sse) = _mm_cvtsi128_si32(res); |
62 | 0 | return _mm_extract_epi32(res, 1); |
63 | 0 | } |
64 | | |
65 | | // handle pixels (<= 512) |
66 | | static inline int variance_final_512_avx2(__m256i vsse, __m256i vsum, |
67 | 0 | unsigned int *const sse) { |
68 | | // extract the low lane and add it to the high lane |
69 | 0 | const __m128i vsum_128 = mm256_add_hi_lo_epi16(vsum); |
70 | 0 | const __m128i vsum_64 = _mm_add_epi16(vsum_128, _mm_srli_si128(vsum_128, 8)); |
71 | 0 | const __m128i sum_int32 = _mm_cvtepi16_epi32(vsum_64); |
72 | 0 | return variance_final_from_32bit_sum_avx2(vsse, sum_int32, sse); |
73 | 0 | } |
74 | | |
75 | | // handle 1024 pixels (32x32, 16x64, 64x16) |
76 | | static inline int variance_final_1024_avx2(__m256i vsse, __m256i vsum, |
77 | 0 | unsigned int *const sse) { |
78 | | // extract the low lane and add it to the high lane |
79 | 0 | const __m128i vsum_128 = mm256_add_hi_lo_epi16(vsum); |
80 | 0 | const __m128i vsum_64 = |
81 | 0 | _mm_add_epi32(_mm_cvtepi16_epi32(vsum_128), |
82 | 0 | _mm_cvtepi16_epi32(_mm_srli_si128(vsum_128, 8))); |
83 | 0 | return variance_final_from_32bit_sum_avx2(vsse, vsum_64, sse); |
84 | 0 | } |
85 | | |
86 | 0 | static inline __m256i sum_to_32bit_avx2(const __m256i sum) { |
87 | 0 | const __m256i sum_lo = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(sum)); |
88 | 0 | const __m256i sum_hi = |
89 | 0 | _mm256_cvtepi16_epi32(_mm256_extractf128_si256(sum, 1)); |
90 | 0 | return _mm256_add_epi32(sum_lo, sum_hi); |
91 | 0 | } |
92 | | |
93 | | // handle 2048 pixels (32x64, 64x32) |
94 | | static inline int variance_final_2048_avx2(__m256i vsse, __m256i vsum, |
95 | 0 | unsigned int *const sse) { |
96 | 0 | vsum = sum_to_32bit_avx2(vsum); |
97 | 0 | const __m128i vsum_128 = mm256_add_hi_lo_epi32(vsum); |
98 | 0 | return variance_final_from_32bit_sum_avx2(vsse, vsum_128, sse); |
99 | 0 | } |
100 | | |
101 | | static inline void variance16_kernel_avx2( |
102 | | const uint8_t *const src, const int src_stride, const uint8_t *const ref, |
103 | 0 | const int ref_stride, __m256i *const sse, __m256i *const sum) { |
104 | 0 | const __m128i s0 = _mm_loadu_si128((__m128i const *)(src + 0 * src_stride)); |
105 | 0 | const __m128i s1 = _mm_loadu_si128((__m128i const *)(src + 1 * src_stride)); |
106 | 0 | const __m128i r0 = _mm_loadu_si128((__m128i const *)(ref + 0 * ref_stride)); |
107 | 0 | const __m128i r1 = _mm_loadu_si128((__m128i const *)(ref + 1 * ref_stride)); |
108 | 0 | const __m256i s = _mm256_inserti128_si256(_mm256_castsi128_si256(s0), s1, 1); |
109 | 0 | const __m256i r = _mm256_inserti128_si256(_mm256_castsi128_si256(r0), r1, 1); |
110 | 0 | variance_kernel_avx2(s, r, sse, sum); |
111 | 0 | } |
112 | | |
113 | | static inline void variance32_kernel_avx2(const uint8_t *const src, |
114 | | const uint8_t *const ref, |
115 | | __m256i *const sse, |
116 | 0 | __m256i *const sum) { |
117 | 0 | const __m256i s = _mm256_loadu_si256((__m256i const *)(src)); |
118 | 0 | const __m256i r = _mm256_loadu_si256((__m256i const *)(ref)); |
119 | 0 | variance_kernel_avx2(s, r, sse, sum); |
120 | 0 | } |
121 | | |
122 | | static inline void variance16_avx2(const uint8_t *src, const int src_stride, |
123 | | const uint8_t *ref, const int ref_stride, |
124 | | const int h, __m256i *const vsse, |
125 | 0 | __m256i *const vsum) { |
126 | 0 | *vsum = _mm256_setzero_si256(); |
127 | |
|
128 | 0 | for (int i = 0; i < h; i += 2) { |
129 | 0 | variance16_kernel_avx2(src, src_stride, ref, ref_stride, vsse, vsum); |
130 | 0 | src += 2 * src_stride; |
131 | 0 | ref += 2 * ref_stride; |
132 | 0 | } |
133 | 0 | } |
134 | | |
135 | | static inline void variance32_avx2(const uint8_t *src, const int src_stride, |
136 | | const uint8_t *ref, const int ref_stride, |
137 | | const int h, __m256i *const vsse, |
138 | 0 | __m256i *const vsum) { |
139 | 0 | *vsum = _mm256_setzero_si256(); |
140 | |
|
141 | 0 | for (int i = 0; i < h; i++) { |
142 | 0 | variance32_kernel_avx2(src, ref, vsse, vsum); |
143 | 0 | src += src_stride; |
144 | 0 | ref += ref_stride; |
145 | 0 | } |
146 | 0 | } |
147 | | |
148 | | static inline void variance64_avx2(const uint8_t *src, const int src_stride, |
149 | | const uint8_t *ref, const int ref_stride, |
150 | | const int h, __m256i *const vsse, |
151 | 0 | __m256i *const vsum) { |
152 | 0 | *vsum = _mm256_setzero_si256(); |
153 | |
|
154 | 0 | for (int i = 0; i < h; i++) { |
155 | 0 | variance32_kernel_avx2(src + 0, ref + 0, vsse, vsum); |
156 | 0 | variance32_kernel_avx2(src + 32, ref + 32, vsse, vsum); |
157 | 0 | src += src_stride; |
158 | 0 | ref += ref_stride; |
159 | 0 | } |
160 | 0 | } |
161 | | |
162 | | static inline void variance128_avx2(const uint8_t *src, const int src_stride, |
163 | | const uint8_t *ref, const int ref_stride, |
164 | | const int h, __m256i *const vsse, |
165 | 0 | __m256i *const vsum) { |
166 | 0 | *vsum = _mm256_setzero_si256(); |
167 | |
|
168 | 0 | for (int i = 0; i < h; i++) { |
169 | 0 | variance32_kernel_avx2(src + 0, ref + 0, vsse, vsum); |
170 | 0 | variance32_kernel_avx2(src + 32, ref + 32, vsse, vsum); |
171 | 0 | variance32_kernel_avx2(src + 64, ref + 64, vsse, vsum); |
172 | 0 | variance32_kernel_avx2(src + 96, ref + 96, vsse, vsum); |
173 | 0 | src += src_stride; |
174 | 0 | ref += ref_stride; |
175 | 0 | } |
176 | 0 | } |
177 | | |
178 | | #define AOM_VAR_NO_LOOP_AVX2(bw, bh, bits, max_pixel) \ |
179 | | unsigned int aom_variance##bw##x##bh##_avx2( \ |
180 | | const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, \ |
181 | 0 | unsigned int *sse) { \ |
182 | 0 | __m256i vsse = _mm256_setzero_si256(); \ |
183 | 0 | __m256i vsum; \ |
184 | 0 | variance##bw##_avx2(src, src_stride, ref, ref_stride, bh, &vsse, &vsum); \ |
185 | 0 | const int sum = variance_final_##max_pixel##_avx2(vsse, vsum, sse); \ |
186 | 0 | return *sse - (uint32_t)(((int64_t)sum * sum) >> bits); \ |
187 | 0 | } Unexecuted instantiation: aom_variance16x8_avx2 Unexecuted instantiation: aom_variance16x16_avx2 Unexecuted instantiation: aom_variance16x32_avx2 Unexecuted instantiation: aom_variance32x16_avx2 Unexecuted instantiation: aom_variance32x32_avx2 Unexecuted instantiation: aom_variance32x64_avx2 Unexecuted instantiation: aom_variance64x32_avx2 Unexecuted instantiation: aom_variance64x16_avx2 Unexecuted instantiation: aom_variance32x8_avx2 Unexecuted instantiation: aom_variance16x64_avx2 Unexecuted instantiation: aom_variance16x4_avx2 |
188 | | |
189 | | AOM_VAR_NO_LOOP_AVX2(16, 8, 7, 512) |
190 | | AOM_VAR_NO_LOOP_AVX2(16, 16, 8, 512) |
191 | | AOM_VAR_NO_LOOP_AVX2(16, 32, 9, 512) |
192 | | |
193 | | AOM_VAR_NO_LOOP_AVX2(32, 16, 9, 512) |
194 | | AOM_VAR_NO_LOOP_AVX2(32, 32, 10, 1024) |
195 | | AOM_VAR_NO_LOOP_AVX2(32, 64, 11, 2048) |
196 | | |
197 | | AOM_VAR_NO_LOOP_AVX2(64, 32, 11, 2048) |
198 | | |
199 | | #if !CONFIG_REALTIME_ONLY |
200 | | AOM_VAR_NO_LOOP_AVX2(64, 16, 10, 1024) |
201 | | AOM_VAR_NO_LOOP_AVX2(32, 8, 8, 512) |
202 | | AOM_VAR_NO_LOOP_AVX2(16, 64, 10, 1024) |
203 | | AOM_VAR_NO_LOOP_AVX2(16, 4, 6, 512) |
204 | | #endif |
205 | | |
206 | | #define AOM_VAR_LOOP_AVX2(bw, bh, bits, uh) \ |
207 | | unsigned int aom_variance##bw##x##bh##_avx2( \ |
208 | | const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, \ |
209 | 0 | unsigned int *sse) { \ |
210 | 0 | __m256i vsse = _mm256_setzero_si256(); \ |
211 | 0 | __m256i vsum = _mm256_setzero_si256(); \ |
212 | 0 | for (int i = 0; i < (bh / uh); i++) { \ |
213 | 0 | __m256i vsum16; \ |
214 | 0 | variance##bw##_avx2(src, src_stride, ref, ref_stride, uh, &vsse, \ |
215 | 0 | &vsum16); \ |
216 | 0 | vsum = _mm256_add_epi32(vsum, sum_to_32bit_avx2(vsum16)); \ |
217 | 0 | src += uh * src_stride; \ |
218 | 0 | ref += uh * ref_stride; \ |
219 | 0 | } \ |
220 | 0 | const __m128i vsum_128 = mm256_add_hi_lo_epi32(vsum); \ |
221 | 0 | const int sum = variance_final_from_32bit_sum_avx2(vsse, vsum_128, sse); \ |
222 | 0 | return *sse - (unsigned int)(((int64_t)sum * sum) >> bits); \ |
223 | 0 | } Unexecuted instantiation: aom_variance64x64_avx2 Unexecuted instantiation: aom_variance64x128_avx2 Unexecuted instantiation: aom_variance128x64_avx2 Unexecuted instantiation: aom_variance128x128_avx2 |
224 | | |
225 | | AOM_VAR_LOOP_AVX2(64, 64, 12, 32) // 64x32 * ( 64/32) |
226 | | AOM_VAR_LOOP_AVX2(64, 128, 13, 32) // 64x32 * (128/32) |
227 | | AOM_VAR_LOOP_AVX2(128, 64, 13, 16) // 128x16 * ( 64/16) |
228 | | AOM_VAR_LOOP_AVX2(128, 128, 14, 16) // 128x16 * (128/16) |
229 | | |
230 | | unsigned int aom_mse16x16_avx2(const uint8_t *src, int src_stride, |
231 | | const uint8_t *ref, int ref_stride, |
232 | 0 | unsigned int *sse) { |
233 | 0 | aom_variance16x16_avx2(src, src_stride, ref, ref_stride, sse); |
234 | 0 | return *sse; |
235 | 0 | } |
236 | | |
237 | 0 | static inline __m256i mm256_loadu2(const uint8_t *p0, const uint8_t *p1) { |
238 | 0 | const __m256i d = |
239 | 0 | _mm256_castsi128_si256(_mm_loadu_si128((const __m128i *)p1)); |
240 | 0 | return _mm256_insertf128_si256(d, _mm_loadu_si128((const __m128i *)p0), 1); |
241 | 0 | } |
242 | | |
243 | | #if CONFIG_AV1_HIGHBITDEPTH |
244 | 0 | static inline __m256i mm256_loadu2_16(const uint16_t *p0, const uint16_t *p1) { |
245 | 0 | const __m256i d = |
246 | 0 | _mm256_castsi128_si256(_mm_loadu_si128((const __m128i *)p1)); |
247 | 0 | return _mm256_insertf128_si256(d, _mm_loadu_si128((const __m128i *)p0), 1); |
248 | 0 | } |
249 | | #endif // CONFIG_AV1_HIGHBITDEPTH |
250 | | |
251 | | static inline void comp_mask_pred_line_avx2(const __m256i s0, const __m256i s1, |
252 | | const __m256i a, |
253 | 0 | uint8_t *comp_pred) { |
254 | 0 | const __m256i alpha_max = _mm256_set1_epi8(AOM_BLEND_A64_MAX_ALPHA); |
255 | 0 | const int16_t round_bits = 15 - AOM_BLEND_A64_ROUND_BITS; |
256 | 0 | const __m256i round_offset = _mm256_set1_epi16(1 << (round_bits)); |
257 | |
|
258 | 0 | const __m256i ma = _mm256_sub_epi8(alpha_max, a); |
259 | |
|
260 | 0 | const __m256i ssAL = _mm256_unpacklo_epi8(s0, s1); |
261 | 0 | const __m256i aaAL = _mm256_unpacklo_epi8(a, ma); |
262 | 0 | const __m256i ssAH = _mm256_unpackhi_epi8(s0, s1); |
263 | 0 | const __m256i aaAH = _mm256_unpackhi_epi8(a, ma); |
264 | |
|
265 | 0 | const __m256i blendAL = _mm256_maddubs_epi16(ssAL, aaAL); |
266 | 0 | const __m256i blendAH = _mm256_maddubs_epi16(ssAH, aaAH); |
267 | 0 | const __m256i roundAL = _mm256_mulhrs_epi16(blendAL, round_offset); |
268 | 0 | const __m256i roundAH = _mm256_mulhrs_epi16(blendAH, round_offset); |
269 | |
|
270 | 0 | const __m256i roundA = _mm256_packus_epi16(roundAL, roundAH); |
271 | 0 | _mm256_storeu_si256((__m256i *)(comp_pred), roundA); |
272 | 0 | } |
273 | | |
274 | | void aom_comp_avg_pred_avx2(uint8_t *comp_pred, const uint8_t *pred, int width, |
275 | 0 | int height, const uint8_t *ref, int ref_stride) { |
276 | 0 | int row = 0; |
277 | 0 | if (width == 8) { |
278 | 0 | do { |
279 | 0 | const __m256i pred_0123 = _mm256_loadu_si256((const __m256i *)(pred)); |
280 | 0 | const __m128i ref_0 = _mm_loadl_epi64((const __m128i *)(ref)); |
281 | 0 | const __m128i ref_1 = |
282 | 0 | _mm_loadl_epi64((const __m128i *)(ref + ref_stride)); |
283 | 0 | const __m128i ref_2 = |
284 | 0 | _mm_loadl_epi64((const __m128i *)(ref + 2 * ref_stride)); |
285 | 0 | const __m128i ref_3 = |
286 | 0 | _mm_loadl_epi64((const __m128i *)(ref + 3 * ref_stride)); |
287 | 0 | const __m128i ref_01 = _mm_unpacklo_epi64(ref_0, ref_1); |
288 | 0 | const __m128i ref_23 = _mm_unpacklo_epi64(ref_2, ref_3); |
289 | |
|
290 | 0 | const __m256i ref_0123 = |
291 | 0 | _mm256_inserti128_si256(_mm256_castsi128_si256(ref_01), ref_23, 1); |
292 | 0 | const __m256i average = _mm256_avg_epu8(pred_0123, ref_0123); |
293 | 0 | _mm256_storeu_si256((__m256i *)(comp_pred), average); |
294 | |
|
295 | 0 | row += 4; |
296 | 0 | pred += 32; |
297 | 0 | comp_pred += 32; |
298 | 0 | ref += 4 * ref_stride; |
299 | 0 | } while (row < height); |
300 | 0 | } else if (width == 16) { |
301 | 0 | do { |
302 | 0 | const __m256i pred_0 = _mm256_loadu_si256((const __m256i *)(pred)); |
303 | 0 | const __m256i pred_1 = _mm256_loadu_si256((const __m256i *)(pred + 32)); |
304 | 0 | const __m256i tmp0 = |
305 | 0 | _mm256_castsi128_si256(_mm_loadu_si128((const __m128i *)(ref))); |
306 | 0 | const __m256i ref_0 = _mm256_inserti128_si256( |
307 | 0 | tmp0, _mm_loadu_si128((const __m128i *)(ref + ref_stride)), 1); |
308 | 0 | const __m256i tmp1 = _mm256_castsi128_si256( |
309 | 0 | _mm_loadu_si128((const __m128i *)(ref + 2 * ref_stride))); |
310 | 0 | const __m256i ref_1 = _mm256_inserti128_si256( |
311 | 0 | tmp1, _mm_loadu_si128((const __m128i *)(ref + 3 * ref_stride)), 1); |
312 | 0 | const __m256i average_0 = _mm256_avg_epu8(pred_0, ref_0); |
313 | 0 | const __m256i average_1 = _mm256_avg_epu8(pred_1, ref_1); |
314 | 0 | _mm256_storeu_si256((__m256i *)(comp_pred), average_0); |
315 | 0 | _mm256_storeu_si256((__m256i *)(comp_pred + 32), average_1); |
316 | |
|
317 | 0 | row += 4; |
318 | 0 | pred += 64; |
319 | 0 | comp_pred += 64; |
320 | 0 | ref += 4 * ref_stride; |
321 | 0 | } while (row < height); |
322 | 0 | } else if (width == 32) { |
323 | 0 | do { |
324 | 0 | const __m256i pred_0 = _mm256_loadu_si256((const __m256i *)(pred)); |
325 | 0 | const __m256i pred_1 = _mm256_loadu_si256((const __m256i *)(pred + 32)); |
326 | 0 | const __m256i ref_0 = _mm256_loadu_si256((const __m256i *)(ref)); |
327 | 0 | const __m256i ref_1 = |
328 | 0 | _mm256_loadu_si256((const __m256i *)(ref + ref_stride)); |
329 | 0 | const __m256i average_0 = _mm256_avg_epu8(pred_0, ref_0); |
330 | 0 | const __m256i average_1 = _mm256_avg_epu8(pred_1, ref_1); |
331 | 0 | _mm256_storeu_si256((__m256i *)(comp_pred), average_0); |
332 | 0 | _mm256_storeu_si256((__m256i *)(comp_pred + 32), average_1); |
333 | |
|
334 | 0 | row += 2; |
335 | 0 | pred += 64; |
336 | 0 | comp_pred += 64; |
337 | 0 | ref += 2 * ref_stride; |
338 | 0 | } while (row < height); |
339 | 0 | } else if (width % 64 == 0) { |
340 | 0 | do { |
341 | 0 | for (int x = 0; x < width; x += 64) { |
342 | 0 | const __m256i pred_0 = _mm256_loadu_si256((const __m256i *)(pred + x)); |
343 | 0 | const __m256i pred_1 = |
344 | 0 | _mm256_loadu_si256((const __m256i *)(pred + x + 32)); |
345 | 0 | const __m256i ref_0 = _mm256_loadu_si256((const __m256i *)(ref + x)); |
346 | 0 | const __m256i ref_1 = |
347 | 0 | _mm256_loadu_si256((const __m256i *)(ref + x + 32)); |
348 | 0 | const __m256i average_0 = _mm256_avg_epu8(pred_0, ref_0); |
349 | 0 | const __m256i average_1 = _mm256_avg_epu8(pred_1, ref_1); |
350 | 0 | _mm256_storeu_si256((__m256i *)(comp_pred + x), average_0); |
351 | 0 | _mm256_storeu_si256((__m256i *)(comp_pred + x + 32), average_1); |
352 | 0 | } |
353 | 0 | row++; |
354 | 0 | pred += width; |
355 | 0 | comp_pred += width; |
356 | 0 | ref += ref_stride; |
357 | 0 | } while (row < height); |
358 | 0 | } else { |
359 | 0 | aom_comp_avg_pred_c(comp_pred, pred, width, height, ref, ref_stride); |
360 | 0 | } |
361 | 0 | } |
362 | | |
363 | | void aom_comp_mask_pred_avx2(uint8_t *comp_pred, const uint8_t *pred, int width, |
364 | | int height, const uint8_t *ref, int ref_stride, |
365 | | const uint8_t *mask, int mask_stride, |
366 | 0 | int invert_mask) { |
367 | 0 | int i = 0; |
368 | 0 | const uint8_t *src0 = invert_mask ? pred : ref; |
369 | 0 | const uint8_t *src1 = invert_mask ? ref : pred; |
370 | 0 | const int stride0 = invert_mask ? width : ref_stride; |
371 | 0 | const int stride1 = invert_mask ? ref_stride : width; |
372 | 0 | if (width == 8) { |
373 | 0 | comp_mask_pred_8_ssse3(comp_pred, height, src0, stride0, src1, stride1, |
374 | 0 | mask, mask_stride); |
375 | 0 | } else if (width == 16) { |
376 | 0 | do { |
377 | 0 | const __m256i sA0 = mm256_loadu2(src0 + stride0, src0); |
378 | 0 | const __m256i sA1 = mm256_loadu2(src1 + stride1, src1); |
379 | 0 | const __m256i aA = mm256_loadu2(mask + mask_stride, mask); |
380 | 0 | src0 += (stride0 << 1); |
381 | 0 | src1 += (stride1 << 1); |
382 | 0 | mask += (mask_stride << 1); |
383 | 0 | const __m256i sB0 = mm256_loadu2(src0 + stride0, src0); |
384 | 0 | const __m256i sB1 = mm256_loadu2(src1 + stride1, src1); |
385 | 0 | const __m256i aB = mm256_loadu2(mask + mask_stride, mask); |
386 | 0 | src0 += (stride0 << 1); |
387 | 0 | src1 += (stride1 << 1); |
388 | 0 | mask += (mask_stride << 1); |
389 | | // comp_pred's stride == width == 16 |
390 | 0 | comp_mask_pred_line_avx2(sA0, sA1, aA, comp_pred); |
391 | 0 | comp_mask_pred_line_avx2(sB0, sB1, aB, comp_pred + 32); |
392 | 0 | comp_pred += (16 << 2); |
393 | 0 | i += 4; |
394 | 0 | } while (i < height); |
395 | 0 | } else { |
396 | 0 | do { |
397 | 0 | for (int x = 0; x < width; x += 32) { |
398 | 0 | const __m256i sA0 = _mm256_lddqu_si256((const __m256i *)(src0 + x)); |
399 | 0 | const __m256i sA1 = _mm256_lddqu_si256((const __m256i *)(src1 + x)); |
400 | 0 | const __m256i aA = _mm256_lddqu_si256((const __m256i *)(mask + x)); |
401 | |
|
402 | 0 | comp_mask_pred_line_avx2(sA0, sA1, aA, comp_pred); |
403 | 0 | comp_pred += 32; |
404 | 0 | } |
405 | 0 | src0 += stride0; |
406 | 0 | src1 += stride1; |
407 | 0 | mask += mask_stride; |
408 | 0 | i++; |
409 | 0 | } while (i < height); |
410 | 0 | } |
411 | 0 | } |
412 | | |
413 | | #if CONFIG_AV1_HIGHBITDEPTH |
414 | | static inline __m256i highbd_comp_mask_pred_line_avx2(const __m256i s0, |
415 | | const __m256i s1, |
416 | 0 | const __m256i a) { |
417 | 0 | const __m256i alpha_max = _mm256_set1_epi16((1 << AOM_BLEND_A64_ROUND_BITS)); |
418 | 0 | const __m256i round_const = |
419 | 0 | _mm256_set1_epi32((1 << AOM_BLEND_A64_ROUND_BITS) >> 1); |
420 | 0 | const __m256i a_inv = _mm256_sub_epi16(alpha_max, a); |
421 | |
|
422 | 0 | const __m256i s_lo = _mm256_unpacklo_epi16(s0, s1); |
423 | 0 | const __m256i a_lo = _mm256_unpacklo_epi16(a, a_inv); |
424 | 0 | const __m256i pred_lo = _mm256_madd_epi16(s_lo, a_lo); |
425 | 0 | const __m256i pred_l = _mm256_srai_epi32( |
426 | 0 | _mm256_add_epi32(pred_lo, round_const), AOM_BLEND_A64_ROUND_BITS); |
427 | |
|
428 | 0 | const __m256i s_hi = _mm256_unpackhi_epi16(s0, s1); |
429 | 0 | const __m256i a_hi = _mm256_unpackhi_epi16(a, a_inv); |
430 | 0 | const __m256i pred_hi = _mm256_madd_epi16(s_hi, a_hi); |
431 | 0 | const __m256i pred_h = _mm256_srai_epi32( |
432 | 0 | _mm256_add_epi32(pred_hi, round_const), AOM_BLEND_A64_ROUND_BITS); |
433 | |
|
434 | 0 | const __m256i comp = _mm256_packs_epi32(pred_l, pred_h); |
435 | |
|
436 | 0 | return comp; |
437 | 0 | } |
438 | | |
439 | | void aom_highbd_comp_mask_pred_avx2(uint8_t *comp_pred8, const uint8_t *pred8, |
440 | | int width, int height, const uint8_t *ref8, |
441 | | int ref_stride, const uint8_t *mask, |
442 | 0 | int mask_stride, int invert_mask) { |
443 | 0 | int i = 0; |
444 | 0 | uint16_t *pred = CONVERT_TO_SHORTPTR(pred8); |
445 | 0 | uint16_t *ref = CONVERT_TO_SHORTPTR(ref8); |
446 | 0 | uint16_t *comp_pred = CONVERT_TO_SHORTPTR(comp_pred8); |
447 | 0 | const uint16_t *src0 = invert_mask ? pred : ref; |
448 | 0 | const uint16_t *src1 = invert_mask ? ref : pred; |
449 | 0 | const int stride0 = invert_mask ? width : ref_stride; |
450 | 0 | const int stride1 = invert_mask ? ref_stride : width; |
451 | 0 | const __m256i zero = _mm256_setzero_si256(); |
452 | |
|
453 | 0 | if (width == 8) { |
454 | 0 | do { |
455 | 0 | const __m256i s0 = mm256_loadu2_16(src0 + stride0, src0); |
456 | 0 | const __m256i s1 = mm256_loadu2_16(src1 + stride1, src1); |
457 | |
|
458 | 0 | const __m128i m_l = _mm_loadl_epi64((const __m128i *)mask); |
459 | 0 | const __m128i m_h = _mm_loadl_epi64((const __m128i *)(mask + 8)); |
460 | |
|
461 | 0 | __m256i m = _mm256_castsi128_si256(m_l); |
462 | 0 | m = _mm256_insertf128_si256(m, m_h, 1); |
463 | 0 | const __m256i m_16 = _mm256_unpacklo_epi8(m, zero); |
464 | |
|
465 | 0 | const __m256i comp = highbd_comp_mask_pred_line_avx2(s0, s1, m_16); |
466 | |
|
467 | 0 | _mm_storeu_si128((__m128i *)(comp_pred), _mm256_castsi256_si128(comp)); |
468 | |
|
469 | 0 | _mm_storeu_si128((__m128i *)(comp_pred + width), |
470 | 0 | _mm256_extractf128_si256(comp, 1)); |
471 | |
|
472 | 0 | src0 += (stride0 << 1); |
473 | 0 | src1 += (stride1 << 1); |
474 | 0 | mask += (mask_stride << 1); |
475 | 0 | comp_pred += (width << 1); |
476 | 0 | i += 2; |
477 | 0 | } while (i < height); |
478 | 0 | } else if (width == 16) { |
479 | 0 | do { |
480 | 0 | const __m256i s0 = _mm256_loadu_si256((const __m256i *)(src0)); |
481 | 0 | const __m256i s1 = _mm256_loadu_si256((const __m256i *)(src1)); |
482 | 0 | const __m256i m_16 = |
483 | 0 | _mm256_cvtepu8_epi16(_mm_loadu_si128((const __m128i *)mask)); |
484 | |
|
485 | 0 | const __m256i comp = highbd_comp_mask_pred_line_avx2(s0, s1, m_16); |
486 | |
|
487 | 0 | _mm256_storeu_si256((__m256i *)comp_pred, comp); |
488 | |
|
489 | 0 | src0 += stride0; |
490 | 0 | src1 += stride1; |
491 | 0 | mask += mask_stride; |
492 | 0 | comp_pred += width; |
493 | 0 | i += 1; |
494 | 0 | } while (i < height); |
495 | 0 | } else { |
496 | 0 | do { |
497 | 0 | for (int x = 0; x < width; x += 32) { |
498 | 0 | const __m256i s0 = _mm256_loadu_si256((const __m256i *)(src0 + x)); |
499 | 0 | const __m256i s2 = _mm256_loadu_si256((const __m256i *)(src0 + x + 16)); |
500 | 0 | const __m256i s1 = _mm256_loadu_si256((const __m256i *)(src1 + x)); |
501 | 0 | const __m256i s3 = _mm256_loadu_si256((const __m256i *)(src1 + x + 16)); |
502 | |
|
503 | 0 | const __m256i m01_16 = |
504 | 0 | _mm256_cvtepu8_epi16(_mm_loadu_si128((const __m128i *)(mask + x))); |
505 | 0 | const __m256i m23_16 = _mm256_cvtepu8_epi16( |
506 | 0 | _mm_loadu_si128((const __m128i *)(mask + x + 16))); |
507 | |
|
508 | 0 | const __m256i comp = highbd_comp_mask_pred_line_avx2(s0, s1, m01_16); |
509 | 0 | const __m256i comp1 = highbd_comp_mask_pred_line_avx2(s2, s3, m23_16); |
510 | |
|
511 | 0 | _mm256_storeu_si256((__m256i *)comp_pred, comp); |
512 | 0 | _mm256_storeu_si256((__m256i *)(comp_pred + 16), comp1); |
513 | |
|
514 | 0 | comp_pred += 32; |
515 | 0 | } |
516 | 0 | src0 += stride0; |
517 | 0 | src1 += stride1; |
518 | 0 | mask += mask_stride; |
519 | 0 | i += 1; |
520 | 0 | } while (i < height); |
521 | 0 | } |
522 | 0 | } |
523 | | #endif // CONFIG_AV1_HIGHBITDEPTH |
524 | | |
525 | | static uint64_t mse_4xh_16bit_avx2(uint8_t *dst, int dstride, uint16_t *src, |
526 | 0 | int sstride, int h) { |
527 | 0 | uint64_t sum = 0; |
528 | 0 | __m128i dst0_4x8, dst1_4x8, dst2_4x8, dst3_4x8, dst_16x8; |
529 | 0 | __m128i src0_4x16, src1_4x16, src2_4x16, src3_4x16; |
530 | 0 | __m256i src0_8x16, src1_8x16, dst_16x16, src_16x16; |
531 | 0 | __m256i res0_4x64, res1_4x64; |
532 | 0 | __m256i sub_result; |
533 | 0 | const __m256i zeros = _mm256_broadcastsi128_si256(_mm_setzero_si128()); |
534 | 0 | __m256i square_result = _mm256_broadcastsi128_si256(_mm_setzero_si128()); |
535 | 0 | for (int i = 0; i < h; i += 4) { |
536 | 0 | dst0_4x8 = _mm_cvtsi32_si128(*(int const *)(&dst[(i + 0) * dstride])); |
537 | 0 | dst1_4x8 = _mm_cvtsi32_si128(*(int const *)(&dst[(i + 1) * dstride])); |
538 | 0 | dst2_4x8 = _mm_cvtsi32_si128(*(int const *)(&dst[(i + 2) * dstride])); |
539 | 0 | dst3_4x8 = _mm_cvtsi32_si128(*(int const *)(&dst[(i + 3) * dstride])); |
540 | 0 | dst_16x8 = _mm_unpacklo_epi64(_mm_unpacklo_epi32(dst0_4x8, dst1_4x8), |
541 | 0 | _mm_unpacklo_epi32(dst2_4x8, dst3_4x8)); |
542 | 0 | dst_16x16 = _mm256_cvtepu8_epi16(dst_16x8); |
543 | |
|
544 | 0 | src0_4x16 = _mm_loadl_epi64((__m128i const *)(&src[(i + 0) * sstride])); |
545 | 0 | src1_4x16 = _mm_loadl_epi64((__m128i const *)(&src[(i + 1) * sstride])); |
546 | 0 | src2_4x16 = _mm_loadl_epi64((__m128i const *)(&src[(i + 2) * sstride])); |
547 | 0 | src3_4x16 = _mm_loadl_epi64((__m128i const *)(&src[(i + 3) * sstride])); |
548 | 0 | src0_8x16 = |
549 | 0 | _mm256_castsi128_si256(_mm_unpacklo_epi64(src0_4x16, src1_4x16)); |
550 | 0 | src1_8x16 = |
551 | 0 | _mm256_castsi128_si256(_mm_unpacklo_epi64(src2_4x16, src3_4x16)); |
552 | 0 | src_16x16 = _mm256_permute2x128_si256(src0_8x16, src1_8x16, 0x20); |
553 | | |
554 | | // r15 r14 r13------------r1 r0 - 16 bit |
555 | 0 | sub_result = _mm256_abs_epi16(_mm256_sub_epi16(src_16x16, dst_16x16)); |
556 | | |
557 | | // s7 s6 s5 s4 s3 s2 s1 s0 - 32bit |
558 | 0 | src_16x16 = _mm256_madd_epi16(sub_result, sub_result); |
559 | | |
560 | | // accumulation of result |
561 | 0 | square_result = _mm256_add_epi32(square_result, src_16x16); |
562 | 0 | } |
563 | | |
564 | | // s5 s4 s1 s0 - 64bit |
565 | 0 | res0_4x64 = _mm256_unpacklo_epi32(square_result, zeros); |
566 | | // s7 s6 s3 s2 - 64bit |
567 | 0 | res1_4x64 = _mm256_unpackhi_epi32(square_result, zeros); |
568 | | // r3 r2 r1 r0 - 64bit |
569 | 0 | res0_4x64 = _mm256_add_epi64(res0_4x64, res1_4x64); |
570 | | // r1+r3 r2+r0 - 64bit |
571 | 0 | const __m128i sum_1x64 = |
572 | 0 | _mm_add_epi64(_mm256_castsi256_si128(res0_4x64), |
573 | 0 | _mm256_extracti128_si256(res0_4x64, 1)); |
574 | 0 | xx_storel_64(&sum, _mm_add_epi64(sum_1x64, _mm_srli_si128(sum_1x64, 8))); |
575 | 0 | return sum; |
576 | 0 | } |
577 | | |
578 | | // Compute mse of four consecutive 4x4 blocks. |
579 | | // In src buffer, each 4x4 block in a 32x32 filter block is stored sequentially. |
580 | | // Hence src_blk_stride is same as block width. Whereas dst buffer is a frame |
581 | | // buffer, thus dstride is a frame level stride. |
582 | | static uint64_t mse_4xh_quad_16bit_avx2(uint8_t *dst, int dstride, |
583 | | uint16_t *src, int src_blk_stride, |
584 | 0 | int h) { |
585 | 0 | uint64_t sum = 0; |
586 | 0 | __m128i dst0_16x8, dst1_16x8, dst2_16x8, dst3_16x8; |
587 | 0 | __m256i dst0_16x16, dst1_16x16, dst2_16x16, dst3_16x16; |
588 | 0 | __m256i res0_4x64, res1_4x64; |
589 | 0 | __m256i sub_result_0, sub_result_1, sub_result_2, sub_result_3; |
590 | 0 | const __m256i zeros = _mm256_broadcastsi128_si256(_mm_setzero_si128()); |
591 | 0 | __m256i square_result = zeros; |
592 | 0 | uint16_t *src_temp = src; |
593 | |
|
594 | 0 | for (int i = 0; i < h; i += 4) { |
595 | 0 | dst0_16x8 = _mm_loadu_si128((__m128i *)(&dst[(i + 0) * dstride])); |
596 | 0 | dst1_16x8 = _mm_loadu_si128((__m128i *)(&dst[(i + 1) * dstride])); |
597 | 0 | dst2_16x8 = _mm_loadu_si128((__m128i *)(&dst[(i + 2) * dstride])); |
598 | 0 | dst3_16x8 = _mm_loadu_si128((__m128i *)(&dst[(i + 3) * dstride])); |
599 | | |
600 | | // row0 of 1st,2nd, 3rd and 4th 4x4 blocks- d00 d10 d20 d30 |
601 | 0 | dst0_16x16 = _mm256_cvtepu8_epi16(dst0_16x8); |
602 | | // row1 of 1st,2nd, 3rd and 4th 4x4 blocks - d01 d11 d21 d31 |
603 | 0 | dst1_16x16 = _mm256_cvtepu8_epi16(dst1_16x8); |
604 | | // row2 of 1st,2nd, 3rd and 4th 4x4 blocks - d02 d12 d22 d32 |
605 | 0 | dst2_16x16 = _mm256_cvtepu8_epi16(dst2_16x8); |
606 | | // row3 of 1st,2nd, 3rd and 4th 4x4 blocks - d03 d13 d23 d33 |
607 | 0 | dst3_16x16 = _mm256_cvtepu8_epi16(dst3_16x8); |
608 | | |
609 | | // All rows of 1st 4x4 block - r00 r01 r02 r03 |
610 | 0 | __m256i src0_16x16 = _mm256_loadu_si256((__m256i const *)(&src_temp[0])); |
611 | | // All rows of 2nd 4x4 block - r10 r11 r12 r13 |
612 | 0 | __m256i src1_16x16 = |
613 | 0 | _mm256_loadu_si256((__m256i const *)(&src_temp[src_blk_stride])); |
614 | | // All rows of 3rd 4x4 block - r20 r21 r22 r23 |
615 | 0 | __m256i src2_16x16 = |
616 | 0 | _mm256_loadu_si256((__m256i const *)(&src_temp[2 * src_blk_stride])); |
617 | | // All rows of 4th 4x4 block - r30 r31 r32 r33 |
618 | 0 | __m256i src3_16x16 = |
619 | 0 | _mm256_loadu_si256((__m256i const *)(&src_temp[3 * src_blk_stride])); |
620 | | |
621 | | // r00 r10 r02 r12 |
622 | 0 | __m256i tmp0_16x16 = _mm256_unpacklo_epi64(src0_16x16, src1_16x16); |
623 | | // r01 r11 r03 r13 |
624 | 0 | __m256i tmp1_16x16 = _mm256_unpackhi_epi64(src0_16x16, src1_16x16); |
625 | | // r20 r30 r22 r32 |
626 | 0 | __m256i tmp2_16x16 = _mm256_unpacklo_epi64(src2_16x16, src3_16x16); |
627 | | // r21 r31 r23 r33 |
628 | 0 | __m256i tmp3_16x16 = _mm256_unpackhi_epi64(src2_16x16, src3_16x16); |
629 | | |
630 | | // r00 r10 r20 r30 |
631 | 0 | src0_16x16 = _mm256_permute2f128_si256(tmp0_16x16, tmp2_16x16, 0x20); |
632 | | // r01 r11 r21 r31 |
633 | 0 | src1_16x16 = _mm256_permute2f128_si256(tmp1_16x16, tmp3_16x16, 0x20); |
634 | | // r02 r12 r22 r32 |
635 | 0 | src2_16x16 = _mm256_permute2f128_si256(tmp0_16x16, tmp2_16x16, 0x31); |
636 | | // r03 r13 r23 r33 |
637 | 0 | src3_16x16 = _mm256_permute2f128_si256(tmp1_16x16, tmp3_16x16, 0x31); |
638 | | |
639 | | // r15 r14 r13------------r1 r0 - 16 bit |
640 | 0 | sub_result_0 = _mm256_abs_epi16(_mm256_sub_epi16(src0_16x16, dst0_16x16)); |
641 | 0 | sub_result_1 = _mm256_abs_epi16(_mm256_sub_epi16(src1_16x16, dst1_16x16)); |
642 | 0 | sub_result_2 = _mm256_abs_epi16(_mm256_sub_epi16(src2_16x16, dst2_16x16)); |
643 | 0 | sub_result_3 = _mm256_abs_epi16(_mm256_sub_epi16(src3_16x16, dst3_16x16)); |
644 | | |
645 | | // s7 s6 s5 s4 s3 s2 s1 s0 - 32bit |
646 | 0 | src0_16x16 = _mm256_madd_epi16(sub_result_0, sub_result_0); |
647 | 0 | src1_16x16 = _mm256_madd_epi16(sub_result_1, sub_result_1); |
648 | 0 | src2_16x16 = _mm256_madd_epi16(sub_result_2, sub_result_2); |
649 | 0 | src3_16x16 = _mm256_madd_epi16(sub_result_3, sub_result_3); |
650 | | |
651 | | // accumulation of result |
652 | 0 | src0_16x16 = _mm256_add_epi32(src0_16x16, src1_16x16); |
653 | 0 | src2_16x16 = _mm256_add_epi32(src2_16x16, src3_16x16); |
654 | 0 | const __m256i square_result_0 = _mm256_add_epi32(src0_16x16, src2_16x16); |
655 | 0 | square_result = _mm256_add_epi32(square_result, square_result_0); |
656 | 0 | src_temp += 16; |
657 | 0 | } |
658 | | |
659 | | // s5 s4 s1 s0 - 64bit |
660 | 0 | res0_4x64 = _mm256_unpacklo_epi32(square_result, zeros); |
661 | | // s7 s6 s3 s2 - 64bit |
662 | 0 | res1_4x64 = _mm256_unpackhi_epi32(square_result, zeros); |
663 | | // r3 r2 r1 r0 - 64bit |
664 | 0 | res0_4x64 = _mm256_add_epi64(res0_4x64, res1_4x64); |
665 | | // r1+r3 r2+r0 - 64bit |
666 | 0 | const __m128i sum_1x64 = |
667 | 0 | _mm_add_epi64(_mm256_castsi256_si128(res0_4x64), |
668 | 0 | _mm256_extracti128_si256(res0_4x64, 1)); |
669 | 0 | xx_storel_64(&sum, _mm_add_epi64(sum_1x64, _mm_srli_si128(sum_1x64, 8))); |
670 | 0 | return sum; |
671 | 0 | } |
672 | | |
673 | | static uint64_t mse_8xh_16bit_avx2(uint8_t *dst, int dstride, uint16_t *src, |
674 | 0 | int sstride, int h) { |
675 | 0 | uint64_t sum = 0; |
676 | 0 | __m128i dst0_8x8, dst1_8x8, dst3_16x8; |
677 | 0 | __m256i src0_8x16, src1_8x16, src_16x16, dst_16x16; |
678 | 0 | __m256i res0_4x64, res1_4x64; |
679 | 0 | __m256i sub_result; |
680 | 0 | const __m256i zeros = _mm256_broadcastsi128_si256(_mm_setzero_si128()); |
681 | 0 | __m256i square_result = _mm256_broadcastsi128_si256(_mm_setzero_si128()); |
682 | |
|
683 | 0 | for (int i = 0; i < h; i += 2) { |
684 | 0 | dst0_8x8 = _mm_loadl_epi64((__m128i const *)(&dst[(i + 0) * dstride])); |
685 | 0 | dst1_8x8 = _mm_loadl_epi64((__m128i const *)(&dst[(i + 1) * dstride])); |
686 | 0 | dst3_16x8 = _mm_unpacklo_epi64(dst0_8x8, dst1_8x8); |
687 | 0 | dst_16x16 = _mm256_cvtepu8_epi16(dst3_16x8); |
688 | |
|
689 | 0 | src0_8x16 = |
690 | 0 | _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)&src[i * sstride])); |
691 | 0 | src1_8x16 = _mm256_castsi128_si256( |
692 | 0 | _mm_loadu_si128((__m128i *)&src[(i + 1) * sstride])); |
693 | 0 | src_16x16 = _mm256_permute2x128_si256(src0_8x16, src1_8x16, 0x20); |
694 | | |
695 | | // r15 r14 r13 - - - r1 r0 - 16 bit |
696 | 0 | sub_result = _mm256_abs_epi16(_mm256_sub_epi16(src_16x16, dst_16x16)); |
697 | | |
698 | | // s7 s6 s5 s4 s3 s2 s1 s0 - 32bit |
699 | 0 | src_16x16 = _mm256_madd_epi16(sub_result, sub_result); |
700 | | |
701 | | // accumulation of result |
702 | 0 | square_result = _mm256_add_epi32(square_result, src_16x16); |
703 | 0 | } |
704 | | |
705 | | // s5 s4 s1 s0 - 64bit |
706 | 0 | res0_4x64 = _mm256_unpacklo_epi32(square_result, zeros); |
707 | | // s7 s6 s3 s2 - 64bit |
708 | 0 | res1_4x64 = _mm256_unpackhi_epi32(square_result, zeros); |
709 | | // r3 r2 r1 r0 - 64bit |
710 | 0 | res0_4x64 = _mm256_add_epi64(res0_4x64, res1_4x64); |
711 | | // r1+r3 r2+r0 - 64bit |
712 | 0 | const __m128i sum_1x64 = |
713 | 0 | _mm_add_epi64(_mm256_castsi256_si128(res0_4x64), |
714 | 0 | _mm256_extracti128_si256(res0_4x64, 1)); |
715 | 0 | xx_storel_64(&sum, _mm_add_epi64(sum_1x64, _mm_srli_si128(sum_1x64, 8))); |
716 | 0 | return sum; |
717 | 0 | } |
718 | | |
719 | | // Compute mse of two consecutive 8x8 blocks. |
720 | | // In src buffer, each 8x8 block in a 64x64 filter block is stored sequentially. |
721 | | // Hence src_blk_stride is same as block width. Whereas dst buffer is a frame |
722 | | // buffer, thus dstride is a frame level stride. |
723 | | static uint64_t mse_8xh_dual_16bit_avx2(uint8_t *dst, int dstride, |
724 | | uint16_t *src, int src_blk_stride, |
725 | 0 | int h) { |
726 | 0 | uint64_t sum = 0; |
727 | 0 | __m128i dst0_16x8, dst1_16x8; |
728 | 0 | __m256i dst0_16x16, dst1_16x16; |
729 | 0 | __m256i res0_4x64, res1_4x64; |
730 | 0 | __m256i sub_result_0, sub_result_1; |
731 | 0 | const __m256i zeros = _mm256_broadcastsi128_si256(_mm_setzero_si128()); |
732 | 0 | __m256i square_result = zeros; |
733 | 0 | uint16_t *src_temp = src; |
734 | |
|
735 | 0 | for (int i = 0; i < h; i += 2) { |
736 | 0 | dst0_16x8 = _mm_loadu_si128((__m128i *)(&dst[(i + 0) * dstride])); |
737 | 0 | dst1_16x8 = _mm_loadu_si128((__m128i *)(&dst[(i + 1) * dstride])); |
738 | | |
739 | | // row0 of 1st and 2nd 8x8 block - d00 d10 |
740 | 0 | dst0_16x16 = _mm256_cvtepu8_epi16(dst0_16x8); |
741 | | // row1 of 1st and 2nd 8x8 block - d01 d11 |
742 | 0 | dst1_16x16 = _mm256_cvtepu8_epi16(dst1_16x8); |
743 | | |
744 | | // 2 rows of 1st 8x8 block - r00 r01 |
745 | 0 | __m256i src0_16x16 = _mm256_loadu_si256((__m256i const *)(&src_temp[0])); |
746 | | // 2 rows of 2nd 8x8 block - r10 r11 |
747 | 0 | __m256i src1_16x16 = |
748 | 0 | _mm256_loadu_si256((__m256i const *)(&src_temp[src_blk_stride])); |
749 | | // r00 r10 - 128bit |
750 | 0 | __m256i tmp0_16x16 = |
751 | 0 | _mm256_permute2f128_si256(src0_16x16, src1_16x16, 0x20); |
752 | | // r01 r11 - 128bit |
753 | 0 | __m256i tmp1_16x16 = |
754 | 0 | _mm256_permute2f128_si256(src0_16x16, src1_16x16, 0x31); |
755 | | |
756 | | // r15 r14 r13------------r1 r0 - 16 bit |
757 | 0 | sub_result_0 = _mm256_abs_epi16(_mm256_sub_epi16(tmp0_16x16, dst0_16x16)); |
758 | 0 | sub_result_1 = _mm256_abs_epi16(_mm256_sub_epi16(tmp1_16x16, dst1_16x16)); |
759 | | |
760 | | // s7 s6 s5 s4 s3 s2 s1 s0 - 32bit each |
761 | 0 | src0_16x16 = _mm256_madd_epi16(sub_result_0, sub_result_0); |
762 | 0 | src1_16x16 = _mm256_madd_epi16(sub_result_1, sub_result_1); |
763 | | |
764 | | // accumulation of result |
765 | 0 | src0_16x16 = _mm256_add_epi32(src0_16x16, src1_16x16); |
766 | 0 | square_result = _mm256_add_epi32(square_result, src0_16x16); |
767 | 0 | src_temp += 16; |
768 | 0 | } |
769 | | |
770 | | // s5 s4 s1 s0 - 64bit |
771 | 0 | res0_4x64 = _mm256_unpacklo_epi32(square_result, zeros); |
772 | | // s7 s6 s3 s2 - 64bit |
773 | 0 | res1_4x64 = _mm256_unpackhi_epi32(square_result, zeros); |
774 | | // r3 r2 r1 r0 - 64bit |
775 | 0 | res0_4x64 = _mm256_add_epi64(res0_4x64, res1_4x64); |
776 | | // r1+r3 r2+r0 - 64bit |
777 | 0 | const __m128i sum_1x64 = |
778 | 0 | _mm_add_epi64(_mm256_castsi256_si128(res0_4x64), |
779 | 0 | _mm256_extracti128_si256(res0_4x64, 1)); |
780 | 0 | xx_storel_64(&sum, _mm_add_epi64(sum_1x64, _mm_srli_si128(sum_1x64, 8))); |
781 | 0 | return sum; |
782 | 0 | } |
783 | | |
784 | | uint64_t aom_mse_wxh_16bit_avx2(uint8_t *dst, int dstride, uint16_t *src, |
785 | 0 | int sstride, int w, int h) { |
786 | 0 | assert((w == 8 || w == 4) && (h == 8 || h == 4) && |
787 | 0 | "w=8/4 and h=8/4 must be satisfied"); |
788 | 0 | switch (w) { |
789 | 0 | case 4: return mse_4xh_16bit_avx2(dst, dstride, src, sstride, h); |
790 | 0 | case 8: return mse_8xh_16bit_avx2(dst, dstride, src, sstride, h); |
791 | 0 | default: assert(0 && "unsupported width"); return -1; |
792 | 0 | } |
793 | 0 | } |
794 | | |
795 | | // Computes mse of two 8x8 or four 4x4 consecutive blocks. Luma plane uses 8x8 |
796 | | // block and Chroma uses 4x4 block. In src buffer, each block in a filter block |
797 | | // is stored sequentially. Hence src_blk_stride is same as block width. Whereas |
798 | | // dst buffer is a frame buffer, thus dstride is a frame level stride. |
799 | | uint64_t aom_mse_16xh_16bit_avx2(uint8_t *dst, int dstride, uint16_t *src, |
800 | 0 | int w, int h) { |
801 | 0 | assert((w == 8 || w == 4) && (h == 8 || h == 4) && |
802 | 0 | "w=8/4 and h=8/4 must be satisfied"); |
803 | 0 | switch (w) { |
804 | 0 | case 4: return mse_4xh_quad_16bit_avx2(dst, dstride, src, w * h, h); |
805 | 0 | case 8: return mse_8xh_dual_16bit_avx2(dst, dstride, src, w * h, h); |
806 | 0 | default: assert(0 && "unsupported width"); return -1; |
807 | 0 | } |
808 | 0 | } |
809 | | |
810 | | static inline void calc_sum_sse_wd32_avx2(const uint8_t *src, |
811 | | const uint8_t *ref, |
812 | | __m256i set_one_minusone, |
813 | | __m256i sse_8x16[2], |
814 | 0 | __m256i sum_8x16[2]) { |
815 | 0 | const __m256i s00_256 = _mm256_loadu_si256((__m256i const *)(src)); |
816 | 0 | const __m256i r00_256 = _mm256_loadu_si256((__m256i const *)(ref)); |
817 | |
|
818 | 0 | const __m256i u_low_256 = _mm256_unpacklo_epi8(s00_256, r00_256); |
819 | 0 | const __m256i u_high_256 = _mm256_unpackhi_epi8(s00_256, r00_256); |
820 | |
|
821 | 0 | const __m256i diff0 = _mm256_maddubs_epi16(u_low_256, set_one_minusone); |
822 | 0 | const __m256i diff1 = _mm256_maddubs_epi16(u_high_256, set_one_minusone); |
823 | |
|
824 | 0 | sse_8x16[0] = _mm256_add_epi32(sse_8x16[0], _mm256_madd_epi16(diff0, diff0)); |
825 | 0 | sse_8x16[1] = _mm256_add_epi32(sse_8x16[1], _mm256_madd_epi16(diff1, diff1)); |
826 | 0 | sum_8x16[0] = _mm256_add_epi16(sum_8x16[0], diff0); |
827 | 0 | sum_8x16[1] = _mm256_add_epi16(sum_8x16[1], diff1); |
828 | 0 | } |
829 | | |
830 | | static inline __m256i calc_sum_sse_order(__m256i *sse_hx16, __m256i *sum_hx16, |
831 | 0 | unsigned int *tot_sse, int *tot_sum) { |
832 | | // s00 s01 s10 s11 s20 s21 s30 s31 |
833 | 0 | const __m256i sse_results = _mm256_hadd_epi32(sse_hx16[0], sse_hx16[1]); |
834 | | // d00 d01 d02 d03 | d10 d11 d12 d13 | d20 d21 d22 d23 | d30 d31 d32 d33 |
835 | 0 | const __m256i sum_result_r0 = _mm256_hadd_epi16(sum_hx16[0], sum_hx16[1]); |
836 | | // d00 d01 d10 d11 | d00 d02 d10 d11 | d20 d21 d30 d31 | d20 d21 d30 d31 |
837 | 0 | const __m256i sum_result_1 = _mm256_hadd_epi16(sum_result_r0, sum_result_r0); |
838 | | // d00 d01 d10 d11 d20 d21 d30 d31 | X |
839 | 0 | const __m256i sum_result_3 = _mm256_permute4x64_epi64(sum_result_1, 0x08); |
840 | | // d00 d01 d10 d11 d20 d21 d30 d31 |
841 | 0 | const __m256i sum_results = |
842 | 0 | _mm256_cvtepi16_epi32(_mm256_castsi256_si128(sum_result_3)); |
843 | | |
844 | | // Add sum & sse registers appropriately to get total sum & sse separately. |
845 | | // s0 s1 d0 d1 s2 s3 d2 d3 |
846 | 0 | const __m256i sum_sse_add = _mm256_hadd_epi32(sse_results, sum_results); |
847 | | // s0 s1 s2 s3 d0 d1 d2 d3 |
848 | 0 | const __m256i sum_sse_order_add = _mm256_permute4x64_epi64(sum_sse_add, 0xd8); |
849 | | // s0+s1 s2+s3 s0+s1 s2+s3 d0+d1 d2+d3 d0+d1 d2+d3 |
850 | 0 | const __m256i sum_sse_order_add_1 = |
851 | 0 | _mm256_hadd_epi32(sum_sse_order_add, sum_sse_order_add); |
852 | | // s0 x x x | d0 x x x |
853 | 0 | const __m256i sum_sse_order_add_final = |
854 | 0 | _mm256_hadd_epi32(sum_sse_order_add_1, sum_sse_order_add_1); |
855 | | // s0 |
856 | 0 | const uint32_t first_value = |
857 | 0 | (uint32_t)_mm256_extract_epi32(sum_sse_order_add_final, 0); |
858 | 0 | *tot_sse += first_value; |
859 | | // d0 |
860 | 0 | const int second_value = _mm256_extract_epi32(sum_sse_order_add_final, 4); |
861 | 0 | *tot_sum += second_value; |
862 | 0 | return sum_sse_order_add; |
863 | 0 | } |
864 | | |
865 | | static inline void get_var_sse_sum_8x8_quad_avx2( |
866 | | const uint8_t *src, int src_stride, const uint8_t *ref, |
867 | | const int ref_stride, const int h, uint32_t *sse8x8, int *sum8x8, |
868 | 0 | unsigned int *tot_sse, int *tot_sum, uint32_t *var8x8) { |
869 | 0 | assert(h <= 128); // May overflow for larger height. |
870 | 0 | __m256i sse_8x16[2], sum_8x16[2]; |
871 | 0 | sum_8x16[0] = _mm256_setzero_si256(); |
872 | 0 | sse_8x16[0] = _mm256_setzero_si256(); |
873 | 0 | sum_8x16[1] = sum_8x16[0]; |
874 | 0 | sse_8x16[1] = sse_8x16[0]; |
875 | 0 | const __m256i set_one_minusone = _mm256_set1_epi16((short)0xff01); |
876 | |
|
877 | 0 | for (int i = 0; i < h; i++) { |
878 | | // Process 8x32 block of one row. |
879 | 0 | calc_sum_sse_wd32_avx2(src, ref, set_one_minusone, sse_8x16, sum_8x16); |
880 | 0 | src += src_stride; |
881 | 0 | ref += ref_stride; |
882 | 0 | } |
883 | |
|
884 | 0 | const __m256i sum_sse_order_add = |
885 | 0 | calc_sum_sse_order(sse_8x16, sum_8x16, tot_sse, tot_sum); |
886 | | |
887 | | // s0 s1 s2 s3 |
888 | 0 | _mm_storeu_si128((__m128i *)sse8x8, |
889 | 0 | _mm256_castsi256_si128(sum_sse_order_add)); |
890 | | // d0 d1 d2 d3 |
891 | 0 | const __m128i sum_temp8x8 = _mm256_extractf128_si256(sum_sse_order_add, 1); |
892 | 0 | _mm_storeu_si128((__m128i *)sum8x8, sum_temp8x8); |
893 | | |
894 | | // (d0xd0 >> 6)=f0 (d1xd1 >> 6)=f1 (d2xd2 >> 6)=f2 (d3xd3 >> 6)=f3 |
895 | 0 | const __m128i mull_results = |
896 | 0 | _mm_srli_epi32(_mm_mullo_epi32(sum_temp8x8, sum_temp8x8), 6); |
897 | | // s0-f0=v0 s1-f1=v1 s2-f2=v2 s3-f3=v3 |
898 | 0 | const __m128i variance_8x8 = |
899 | 0 | _mm_sub_epi32(_mm256_castsi256_si128(sum_sse_order_add), mull_results); |
900 | | // v0 v1 v2 v3 |
901 | 0 | _mm_storeu_si128((__m128i *)var8x8, variance_8x8); |
902 | 0 | } |
903 | | |
904 | | static inline void get_var_sse_sum_16x16_dual_avx2( |
905 | | const uint8_t *src, int src_stride, const uint8_t *ref, |
906 | | const int ref_stride, const int h, uint32_t *sse16x16, |
907 | 0 | unsigned int *tot_sse, int *tot_sum, uint32_t *var16x16) { |
908 | 0 | assert(h <= 128); // May overflow for larger height. |
909 | 0 | __m256i sse_16x16[2], sum_16x16[2]; |
910 | 0 | sum_16x16[0] = _mm256_setzero_si256(); |
911 | 0 | sse_16x16[0] = _mm256_setzero_si256(); |
912 | 0 | sum_16x16[1] = sum_16x16[0]; |
913 | 0 | sse_16x16[1] = sse_16x16[0]; |
914 | 0 | const __m256i set_one_minusone = _mm256_set1_epi16((short)0xff01); |
915 | |
|
916 | 0 | for (int i = 0; i < h; i++) { |
917 | | // Process 16x32 block of one row. |
918 | 0 | calc_sum_sse_wd32_avx2(src, ref, set_one_minusone, sse_16x16, sum_16x16); |
919 | 0 | src += src_stride; |
920 | 0 | ref += ref_stride; |
921 | 0 | } |
922 | |
|
923 | 0 | const __m256i sum_sse_order_add = |
924 | 0 | calc_sum_sse_order(sse_16x16, sum_16x16, tot_sse, tot_sum); |
925 | |
|
926 | 0 | const __m256i sum_sse_order_add_1 = |
927 | 0 | _mm256_hadd_epi32(sum_sse_order_add, sum_sse_order_add); |
928 | | |
929 | | // s0+s1 s2+s3 x x |
930 | 0 | _mm_storel_epi64((__m128i *)sse16x16, |
931 | 0 | _mm256_castsi256_si128(sum_sse_order_add_1)); |
932 | | |
933 | | // d0+d1 d2+d3 x x |
934 | 0 | const __m128i sum_temp16x16 = |
935 | 0 | _mm256_extractf128_si256(sum_sse_order_add_1, 1); |
936 | | |
937 | | // (d0xd0 >> 6)=f0 (d1xd1 >> 6)=f1 (d2xd2 >> 6)=f2 (d3xd3 >> 6)=f3 |
938 | 0 | const __m128i mull_results = |
939 | 0 | _mm_srli_epi32(_mm_mullo_epi32(sum_temp16x16, sum_temp16x16), 8); |
940 | | |
941 | | // s0-f0=v0 s1-f1=v1 s2-f2=v2 s3-f3=v3 |
942 | 0 | const __m128i variance_16x16 = |
943 | 0 | _mm_sub_epi32(_mm256_castsi256_si128(sum_sse_order_add_1), mull_results); |
944 | | |
945 | | // v0 v1 v2 v3 |
946 | 0 | _mm_storel_epi64((__m128i *)var16x16, variance_16x16); |
947 | 0 | } |
948 | | |
949 | 0 | static inline int32_t yy_hsum_epi32_si32(__m256i v) { |
950 | 0 | __m128i v128 = |
951 | 0 | _mm_add_epi32(_mm256_castsi256_si128(v), _mm256_extracti128_si256(v, 1)); |
952 | 0 | v128 = _mm_hadd_epi32(v128, v128); |
953 | 0 | v128 = _mm_hadd_epi32(v128, v128); |
954 | 0 | return _mm_cvtsi128_si32(v128); |
955 | 0 | } |
956 | | |
957 | 0 | static inline int32_t xx_hsum_epi32_si32(__m128i v) { |
958 | 0 | v = _mm_hadd_epi32(v, v); |
959 | 0 | v = _mm_hadd_epi32(v, v); |
960 | 0 | return _mm_cvtsi128_si32(v); |
961 | 0 | } |
962 | | |
963 | | int64_t aom_calc_variance_stat_avx2(const uint8_t *src, int stride, int bw, |
964 | 0 | int bh) { |
965 | | // Temporary buffer to store horizontal filter results H[y][x] |
966 | | // Max block size in AV1 is 128x128 |
967 | 0 | DECLARE_ALIGNED(32, uint16_t, H_buf[128 * 128]); |
968 | | |
969 | | // Step 1: Compute Horizontal 1D Filter H[y][x] = P(y, x-1) + 2*P(y, x) + P(y, |
970 | | // x + 1) |
971 | 0 | for (int y = 0; y < bh; ++y) { |
972 | 0 | const uint8_t *src_row = src + y * stride; |
973 | 0 | uint16_t *H_row = H_buf + y * bw; |
974 | |
|
975 | 0 | if (bw >= 16) { |
976 | 0 | for (int x = 0; x < bw; x += 16) { |
977 | 0 | __m128i v_curr = _mm_loadu_si128((const __m128i *)(src_row + x)); |
978 | 0 | __m128i v_left, v_right; |
979 | |
|
980 | 0 | if (x == 0) { |
981 | 0 | v_left = |
982 | 0 | _mm_insert_epi8(_mm_slli_si128(v_curr, 1), (int8_t)src_row[0], 0); |
983 | 0 | } else { |
984 | 0 | v_left = _mm_loadu_si128((const __m128i *)(src_row + x - 1)); |
985 | 0 | } |
986 | |
|
987 | 0 | if (x + 16 < bw) { |
988 | 0 | v_right = _mm_loadu_si128((const __m128i *)(src_row + x + 1)); |
989 | 0 | } else { |
990 | 0 | v_right = _mm_insert_epi8(_mm_srli_si128(v_curr, 1), |
991 | 0 | (int8_t)src_row[bw - 1], 15); |
992 | 0 | } |
993 | |
|
994 | 0 | __m256i u16_left = _mm256_cvtepu8_epi16(v_left); |
995 | 0 | __m256i u16_curr = _mm256_cvtepu8_epi16(v_curr); |
996 | 0 | __m256i u16_right = _mm256_cvtepu8_epi16(v_right); |
997 | |
|
998 | 0 | __m256i u16_H = _mm256_add_epi16(_mm256_add_epi16(u16_left, u16_right), |
999 | 0 | _mm256_slli_epi16(u16_curr, 1)); |
1000 | |
|
1001 | 0 | _mm256_storeu_si256((__m256i *)(H_row + x), u16_H); |
1002 | 0 | } |
1003 | 0 | } else if (bw == 8) { |
1004 | 0 | __m128i v_curr = _mm_loadl_epi64((const __m128i *)src_row); |
1005 | 0 | __m128i v_left = |
1006 | 0 | _mm_insert_epi8(_mm_slli_si128(v_curr, 1), (int8_t)src_row[0], 0); |
1007 | 0 | __m128i v_right = |
1008 | 0 | _mm_insert_epi8(_mm_srli_si128(v_curr, 1), (int8_t)src_row[7], 7); |
1009 | |
|
1010 | 0 | __m128i u16_left = _mm_cvtepu8_epi16(v_left); |
1011 | 0 | __m128i u16_curr = _mm_cvtepu8_epi16(v_curr); |
1012 | 0 | __m128i u16_right = _mm_cvtepu8_epi16(v_right); |
1013 | |
|
1014 | 0 | __m128i u16_H = _mm_add_epi16(_mm_add_epi16(u16_left, u16_right), |
1015 | 0 | _mm_slli_epi16(u16_curr, 1)); |
1016 | |
|
1017 | 0 | _mm_storeu_si128((__m128i *)H_row, u16_H); |
1018 | 0 | } else { // bw == 4 |
1019 | 0 | __m128i v_curr = _mm_cvtsi32_si128(*(const int32_t *)src_row); |
1020 | 0 | __m128i v_left = |
1021 | 0 | _mm_insert_epi8(_mm_slli_si128(v_curr, 1), (int8_t)src_row[0], 0); |
1022 | 0 | __m128i v_right = |
1023 | 0 | _mm_insert_epi8(_mm_srli_si128(v_curr, 1), (int8_t)src_row[3], 3); |
1024 | |
|
1025 | 0 | __m128i u16_left = _mm_cvtepu8_epi16(v_left); |
1026 | 0 | __m128i u16_curr = _mm_cvtepu8_epi16(v_curr); |
1027 | 0 | __m128i u16_right = _mm_cvtepu8_epi16(v_right); |
1028 | |
|
1029 | 0 | __m128i u16_H = _mm_add_epi16(_mm_add_epi16(u16_left, u16_right), |
1030 | 0 | _mm_slli_epi16(u16_curr, 1)); |
1031 | |
|
1032 | 0 | _mm_storel_epi64((__m128i *)H_row, u16_H); |
1033 | 0 | } |
1034 | 0 | } |
1035 | | |
1036 | | // Step 2: Compute Vertical Filter V[y][x] = H(y-1, x) + 2*H(y, x) + H(y + 1, |
1037 | | // x), smooth = V >> 4, diff = P - smooth, and accum (diff^2) |
1038 | 0 | int64_t total_var = 0; |
1039 | |
|
1040 | 0 | if (bw >= 16) { |
1041 | 0 | __m256i acc_var_256 = _mm256_setzero_si256(); |
1042 | |
|
1043 | 0 | for (int y = 0; y < bh; ++y) { |
1044 | 0 | const uint8_t *src_row = src + y * stride; |
1045 | 0 | const uint16_t *H_curr_row = H_buf + y * bw; |
1046 | 0 | const uint16_t *H_top_row = (y == 0) ? H_curr_row : H_buf + (y - 1) * bw; |
1047 | 0 | const uint16_t *H_bot_row = |
1048 | 0 | (y == bh - 1) ? H_curr_row : H_buf + (y + 1) * bw; |
1049 | |
|
1050 | 0 | for (int x = 0; x < bw; x += 16) { |
1051 | 0 | __m256i H_top = _mm256_loadu_si256((const __m256i *)(H_top_row + x)); |
1052 | 0 | __m256i H_curr = _mm256_loadu_si256((const __m256i *)(H_curr_row + x)); |
1053 | 0 | __m256i H_bot = _mm256_loadu_si256((const __m256i *)(H_bot_row + x)); |
1054 | |
|
1055 | 0 | __m256i u16_V = _mm256_add_epi16(_mm256_add_epi16(H_top, H_bot), |
1056 | 0 | _mm256_slli_epi16(H_curr, 1)); |
1057 | |
|
1058 | 0 | __m256i u16_sum = _mm256_srli_epi16(u16_V, 4); |
1059 | |
|
1060 | 0 | __m128i v_p_curr = _mm_loadu_si128((const __m128i *)(src_row + x)); |
1061 | 0 | __m256i u16_p_curr = _mm256_cvtepu8_epi16(v_p_curr); |
1062 | |
|
1063 | 0 | __m256i diff = _mm256_sub_epi16(u16_p_curr, u16_sum); |
1064 | 0 | __m256i diff_sq = _mm256_madd_epi16(diff, diff); |
1065 | |
|
1066 | 0 | acc_var_256 = _mm256_add_epi32(acc_var_256, diff_sq); |
1067 | 0 | } |
1068 | 0 | } |
1069 | |
|
1070 | 0 | total_var = (int64_t)yy_hsum_epi32_si32(acc_var_256); |
1071 | 0 | } else if (bw == 8) { |
1072 | 0 | __m128i acc_var_128 = _mm_setzero_si128(); |
1073 | |
|
1074 | 0 | for (int y = 0; y < bh; ++y) { |
1075 | 0 | const uint8_t *src_row = src + y * stride; |
1076 | 0 | const uint16_t *H_curr_row = H_buf + y * 8; |
1077 | 0 | const uint16_t *H_top_row = (y == 0) ? H_curr_row : H_buf + (y - 1) * 8; |
1078 | 0 | const uint16_t *H_bot_row = |
1079 | 0 | (y == bh - 1) ? H_curr_row : H_buf + (y + 1) * 8; |
1080 | |
|
1081 | 0 | __m128i H_top = _mm_loadu_si128((const __m128i *)H_top_row); |
1082 | 0 | __m128i H_curr = _mm_loadu_si128((const __m128i *)H_curr_row); |
1083 | 0 | __m128i H_bot = _mm_loadu_si128((const __m128i *)H_bot_row); |
1084 | |
|
1085 | 0 | __m128i u16_V = |
1086 | 0 | _mm_add_epi16(_mm_add_epi16(H_top, H_bot), _mm_slli_epi16(H_curr, 1)); |
1087 | |
|
1088 | 0 | __m128i u16_sum = _mm_srli_epi16(u16_V, 4); |
1089 | |
|
1090 | 0 | __m128i v_p_curr = _mm_loadl_epi64((const __m128i *)src_row); |
1091 | 0 | __m128i u16_p_curr = _mm_cvtepu8_epi16(v_p_curr); |
1092 | |
|
1093 | 0 | __m128i diff = _mm_sub_epi16(u16_p_curr, u16_sum); |
1094 | 0 | __m128i diff_sq = _mm_madd_epi16(diff, diff); |
1095 | |
|
1096 | 0 | acc_var_128 = _mm_add_epi32(acc_var_128, diff_sq); |
1097 | 0 | } |
1098 | |
|
1099 | 0 | total_var = (int64_t)xx_hsum_epi32_si32(acc_var_128); |
1100 | 0 | } else { // bw == 4 |
1101 | 0 | __m128i acc_var_128 = _mm_setzero_si128(); |
1102 | |
|
1103 | 0 | for (int y = 0; y < bh; ++y) { |
1104 | 0 | const uint8_t *src_row = src + y * stride; |
1105 | 0 | const uint16_t *H_curr_row = H_buf + y * 4; |
1106 | 0 | const uint16_t *H_top_row = (y == 0) ? H_curr_row : H_buf + (y - 1) * 4; |
1107 | 0 | const uint16_t *H_bot_row = |
1108 | 0 | (y == bh - 1) ? H_curr_row : H_buf + (y + 1) * 4; |
1109 | |
|
1110 | 0 | __m128i H_top = _mm_loadl_epi64((const __m128i *)H_top_row); |
1111 | 0 | __m128i H_curr = _mm_loadl_epi64((const __m128i *)H_curr_row); |
1112 | 0 | __m128i H_bot = _mm_loadl_epi64((const __m128i *)H_bot_row); |
1113 | |
|
1114 | 0 | __m128i u16_V = |
1115 | 0 | _mm_add_epi16(_mm_add_epi16(H_top, H_bot), _mm_slli_epi16(H_curr, 1)); |
1116 | |
|
1117 | 0 | __m128i u16_sum = _mm_srli_epi16(u16_V, 4); |
1118 | |
|
1119 | 0 | __m128i v_p_curr = _mm_cvtsi32_si128(*(const int32_t *)src_row); |
1120 | 0 | __m128i u16_p_curr = _mm_cvtepu8_epi16(v_p_curr); |
1121 | |
|
1122 | 0 | __m128i diff = _mm_sub_epi16(u16_p_curr, u16_sum); |
1123 | 0 | __m128i diff_sq = _mm_madd_epi16(diff, diff); |
1124 | |
|
1125 | 0 | acc_var_128 = _mm_add_epi32(acc_var_128, diff_sq); |
1126 | 0 | } |
1127 | |
|
1128 | 0 | total_var = (int64_t)xx_hsum_epi32_si32(acc_var_128); |
1129 | 0 | } |
1130 | |
|
1131 | 0 | return total_var << 4; |
1132 | 0 | } |
1133 | | |
1134 | | #if CONFIG_AV1_HIGHBITDEPTH |
1135 | 0 | static inline int64_t yy_hsum_epi64_si64(__m256i v) { |
1136 | 0 | __m128i v128 = |
1137 | 0 | _mm_add_epi64(_mm256_castsi256_si128(v), _mm256_extracti128_si256(v, 1)); |
1138 | 0 | __m128i tmp = _mm_srli_si128(v128, 8); |
1139 | 0 | v128 = _mm_add_epi64(v128, tmp); |
1140 | |
|
1141 | 0 | #if AOM_ARCH_X86_64 |
1142 | 0 | return _mm_cvtsi128_si64(v128); |
1143 | | #else |
1144 | | int64_t tmp32; |
1145 | | _mm_storel_epi64((__m128i *)&tmp32, v128); |
1146 | | return tmp32; |
1147 | | #endif |
1148 | 0 | } |
1149 | | |
1150 | 0 | static inline int64_t xx_hsum_epi64_si64(__m128i v) { |
1151 | 0 | __m128i tmp = _mm_srli_si128(v, 8); |
1152 | 0 | v = _mm_add_epi64(v, tmp); |
1153 | |
|
1154 | 0 | #if AOM_ARCH_X86_64 |
1155 | 0 | return _mm_cvtsi128_si64(v); |
1156 | | #else |
1157 | | int64_t tmp32; |
1158 | | _mm_storel_epi64((__m128i *)&tmp32, v); |
1159 | | return tmp32; |
1160 | | #endif |
1161 | 0 | } |
1162 | | |
1163 | | int64_t aom_highbd_calc_variance_stat_avx2(const uint16_t *src, int stride, |
1164 | 0 | int bw, int bh) { |
1165 | | // Temporary buffer to store horizontal filter results H[y][x] |
1166 | 0 | DECLARE_ALIGNED(32, uint16_t, H_buf[128 * 128]); |
1167 | | |
1168 | | // Step 1: Compute Horizontal 1D Filter H[y][x] = P(y, x-1) + 2*P(y, x) + P(y, |
1169 | | // x + 1) |
1170 | 0 | for (int y = 0; y < bh; ++y) { |
1171 | 0 | const uint16_t *src_row = src + y * stride; |
1172 | 0 | uint16_t *H_row = H_buf + y * bw; |
1173 | |
|
1174 | 0 | if (bw >= 8) { |
1175 | 0 | for (int x = 0; x < bw; x += 8) { |
1176 | 0 | __m128i v_curr = _mm_loadu_si128((const __m128i *)(src_row + x)); |
1177 | 0 | __m128i v_left, v_right; |
1178 | |
|
1179 | 0 | if (x == 0) { |
1180 | 0 | v_left = _mm_insert_epi16(_mm_slli_si128(v_curr, 2), src_row[0], 0); |
1181 | 0 | } else { |
1182 | 0 | v_left = _mm_loadu_si128((const __m128i *)(src_row + x - 1)); |
1183 | 0 | } |
1184 | |
|
1185 | 0 | if (x + 8 < bw) { |
1186 | 0 | v_right = _mm_loadu_si128((const __m128i *)(src_row + x + 1)); |
1187 | 0 | } else { |
1188 | 0 | v_right = |
1189 | 0 | _mm_insert_epi16(_mm_srli_si128(v_curr, 2), src_row[bw - 1], 7); |
1190 | 0 | } |
1191 | |
|
1192 | 0 | __m128i u16_H = _mm_add_epi16(_mm_add_epi16(v_left, v_right), |
1193 | 0 | _mm_slli_epi16(v_curr, 1)); |
1194 | |
|
1195 | 0 | _mm_storeu_si128((__m128i *)(H_row + x), u16_H); |
1196 | 0 | } |
1197 | 0 | } else { // bw == 4 |
1198 | 0 | __m128i v_curr = _mm_loadl_epi64((const __m128i *)src_row); |
1199 | 0 | __m128i v_left = |
1200 | 0 | _mm_insert_epi16(_mm_slli_si128(v_curr, 2), src_row[0], 0); |
1201 | 0 | __m128i v_right = |
1202 | 0 | _mm_insert_epi16(_mm_srli_si128(v_curr, 2), src_row[3], 3); |
1203 | |
|
1204 | 0 | __m128i u16_H = _mm_add_epi16(_mm_add_epi16(v_left, v_right), |
1205 | 0 | _mm_slli_epi16(v_curr, 1)); |
1206 | |
|
1207 | 0 | _mm_storel_epi64((__m128i *)H_row, u16_H); |
1208 | 0 | } |
1209 | 0 | } |
1210 | | |
1211 | | // Step 2: Compute Vertical Filter V[y][x] = H(y-1, x) + 2*H(y, x) + H(y + 1, |
1212 | | // x), smooth = V >> 4, diff = P - smooth, and accum (diff^2) |
1213 | 0 | int64_t total_var = 0; |
1214 | |
|
1215 | 0 | if (bw >= 16) { |
1216 | 0 | __m256i acc_var_64 = _mm256_setzero_si256(); |
1217 | |
|
1218 | 0 | for (int y = 0; y < bh; ++y) { |
1219 | 0 | const uint16_t *src_row = src + y * stride; |
1220 | 0 | const uint16_t *H_curr_row = H_buf + y * bw; |
1221 | 0 | const uint16_t *H_top_row = (y == 0) ? H_curr_row : H_buf + (y - 1) * bw; |
1222 | 0 | const uint16_t *H_bot_row = |
1223 | 0 | (y == bh - 1) ? H_curr_row : H_buf + (y + 1) * bw; |
1224 | |
|
1225 | 0 | for (int x = 0; x < bw; x += 16) { |
1226 | 0 | __m256i H_top = _mm256_loadu_si256((const __m256i *)(H_top_row + x)); |
1227 | 0 | __m256i H_curr = _mm256_loadu_si256((const __m256i *)(H_curr_row + x)); |
1228 | 0 | __m256i H_bot = _mm256_loadu_si256((const __m256i *)(H_bot_row + x)); |
1229 | |
|
1230 | 0 | __m256i u16_V = _mm256_add_epi16(_mm256_add_epi16(H_top, H_bot), |
1231 | 0 | _mm256_slli_epi16(H_curr, 1)); |
1232 | |
|
1233 | 0 | __m256i u16_sum = _mm256_srli_epi16(u16_V, 4); |
1234 | |
|
1235 | 0 | __m256i v_p_curr = _mm256_loadu_si256((const __m256i *)(src_row + x)); |
1236 | |
|
1237 | 0 | __m256i diff = _mm256_sub_epi16(v_p_curr, u16_sum); |
1238 | 0 | __m256i diff_sq = _mm256_madd_epi16(diff, diff); |
1239 | |
|
1240 | 0 | __m256i diff_sq_lo = |
1241 | 0 | _mm256_cvtepi32_epi64(_mm256_castsi256_si128(diff_sq)); |
1242 | 0 | __m256i diff_sq_hi = |
1243 | 0 | _mm256_cvtepi32_epi64(_mm256_extracti128_si256(diff_sq, 1)); |
1244 | 0 | acc_var_64 = _mm256_add_epi64(acc_var_64, diff_sq_lo); |
1245 | 0 | acc_var_64 = _mm256_add_epi64(acc_var_64, diff_sq_hi); |
1246 | 0 | } |
1247 | 0 | } |
1248 | |
|
1249 | 0 | total_var = yy_hsum_epi64_si64(acc_var_64); |
1250 | 0 | } else if (bw == 8) { |
1251 | 0 | __m128i acc_var_64 = _mm_setzero_si128(); |
1252 | |
|
1253 | 0 | for (int y = 0; y < bh; ++y) { |
1254 | 0 | const uint16_t *src_row = src + y * stride; |
1255 | 0 | const uint16_t *H_curr_row = H_buf + y * 8; |
1256 | 0 | const uint16_t *H_top_row = (y == 0) ? H_curr_row : H_buf + (y - 1) * 8; |
1257 | 0 | const uint16_t *H_bot_row = |
1258 | 0 | (y == bh - 1) ? H_curr_row : H_buf + (y + 1) * 8; |
1259 | |
|
1260 | 0 | __m128i H_top = _mm_loadu_si128((const __m128i *)H_top_row); |
1261 | 0 | __m128i H_curr = _mm_loadu_si128((const __m128i *)H_curr_row); |
1262 | 0 | __m128i H_bot = _mm_loadu_si128((const __m128i *)H_bot_row); |
1263 | |
|
1264 | 0 | __m128i u16_V = |
1265 | 0 | _mm_add_epi16(_mm_add_epi16(H_top, H_bot), _mm_slli_epi16(H_curr, 1)); |
1266 | |
|
1267 | 0 | __m128i u16_sum = _mm_srli_epi16(u16_V, 4); |
1268 | |
|
1269 | 0 | __m128i v_p_curr = _mm_loadu_si128((const __m128i *)src_row); |
1270 | |
|
1271 | 0 | __m128i diff = _mm_sub_epi16(v_p_curr, u16_sum); |
1272 | 0 | __m128i diff_sq = _mm_madd_epi16(diff, diff); |
1273 | |
|
1274 | 0 | __m128i diff_sq_lo = _mm_cvtepi32_epi64(diff_sq); |
1275 | 0 | __m128i diff_sq_hi = _mm_cvtepi32_epi64(_mm_srli_si128(diff_sq, 8)); |
1276 | 0 | acc_var_64 = _mm_add_epi64(acc_var_64, diff_sq_lo); |
1277 | 0 | acc_var_64 = _mm_add_epi64(acc_var_64, diff_sq_hi); |
1278 | 0 | } |
1279 | |
|
1280 | 0 | total_var = xx_hsum_epi64_si64(acc_var_64); |
1281 | 0 | } else { // bw == 4 |
1282 | 0 | __m128i acc_var_64 = _mm_setzero_si128(); |
1283 | |
|
1284 | 0 | for (int y = 0; y < bh; ++y) { |
1285 | 0 | const uint16_t *src_row = src + y * stride; |
1286 | 0 | const uint16_t *H_curr_row = H_buf + y * 4; |
1287 | 0 | const uint16_t *H_top_row = (y == 0) ? H_curr_row : H_buf + (y - 1) * 4; |
1288 | 0 | const uint16_t *H_bot_row = |
1289 | 0 | (y == bh - 1) ? H_curr_row : H_buf + (y + 1) * 4; |
1290 | |
|
1291 | 0 | __m128i H_top = _mm_loadl_epi64((const __m128i *)H_top_row); |
1292 | 0 | __m128i H_curr = _mm_loadl_epi64((const __m128i *)H_curr_row); |
1293 | 0 | __m128i H_bot = _mm_loadl_epi64((const __m128i *)H_bot_row); |
1294 | |
|
1295 | 0 | __m128i u16_V = |
1296 | 0 | _mm_add_epi16(_mm_add_epi16(H_top, H_bot), _mm_slli_epi16(H_curr, 1)); |
1297 | |
|
1298 | 0 | __m128i u16_sum = _mm_srli_epi16(u16_V, 4); |
1299 | |
|
1300 | 0 | __m128i v_p_curr = _mm_loadl_epi64((const __m128i *)src_row); |
1301 | |
|
1302 | 0 | __m128i diff = _mm_sub_epi16(v_p_curr, u16_sum); |
1303 | 0 | __m128i diff_sq = _mm_madd_epi16(diff, diff); |
1304 | |
|
1305 | 0 | __m128i diff_sq_lo = _mm_cvtepi32_epi64(diff_sq); |
1306 | 0 | acc_var_64 = _mm_add_epi64(acc_var_64, diff_sq_lo); |
1307 | 0 | } |
1308 | |
|
1309 | 0 | total_var = xx_hsum_epi64_si64(acc_var_64); |
1310 | 0 | } |
1311 | |
|
1312 | 0 | return total_var << 4; |
1313 | 0 | } |
1314 | | #endif // CONFIG_AV1_HIGHBITDEPTH |
1315 | | |
1316 | | void aom_get_var_sse_sum_8x8_quad_avx2(const uint8_t *src_ptr, |
1317 | | int source_stride, |
1318 | | const uint8_t *ref_ptr, int ref_stride, |
1319 | | uint32_t *sse8x8, int *sum8x8, |
1320 | | unsigned int *tot_sse, int *tot_sum, |
1321 | 0 | uint32_t *var8x8) { |
1322 | 0 | get_var_sse_sum_8x8_quad_avx2(src_ptr, source_stride, ref_ptr, ref_stride, 8, |
1323 | 0 | sse8x8, sum8x8, tot_sse, tot_sum, var8x8); |
1324 | 0 | } |
1325 | | |
1326 | | void aom_get_var_sse_sum_16x16_dual_avx2(const uint8_t *src_ptr, |
1327 | | int source_stride, |
1328 | | const uint8_t *ref_ptr, int ref_stride, |
1329 | | uint32_t *sse16x16, |
1330 | | unsigned int *tot_sse, int *tot_sum, |
1331 | 0 | uint32_t *var16x16) { |
1332 | 0 | get_var_sse_sum_16x16_dual_avx2(src_ptr, source_stride, ref_ptr, ref_stride, |
1333 | 0 | 16, sse16x16, tot_sse, tot_sum, var16x16); |
1334 | 0 | } |