xref: /aosp_15_r20/external/libaom/av1/encoder/x86/highbd_block_error_intrin_sse2.c (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
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 <emmintrin.h>
13 #include <stdio.h>
14 
15 #include "av1/common/common.h"
16 #include "config/av1_rtcd.h"
17 
av1_highbd_block_error_sse2(const tran_low_t * coeff,const tran_low_t * dqcoeff,intptr_t block_size,int64_t * ssz,int bps)18 int64_t av1_highbd_block_error_sse2(const tran_low_t *coeff,
19                                     const tran_low_t *dqcoeff,
20                                     intptr_t block_size, int64_t *ssz,
21                                     int bps) {
22   int i, j, test;
23   uint32_t temp[4];
24   __m128i max, min, cmp0, cmp1, cmp2, cmp3;
25   int64_t error = 0, sqcoeff = 0;
26   const int shift = 2 * (bps - 8);
27   const int rounding = shift > 0 ? 1 << (shift - 1) : 0;
28 
29   for (i = 0; i < block_size; i += 8) {
30     // Load the data into xmm registers
31     __m128i mm_coeff = _mm_load_si128((__m128i *)(coeff + i));
32     __m128i mm_coeff2 = _mm_load_si128((__m128i *)(coeff + i + 4));
33     __m128i mm_dqcoeff = _mm_load_si128((__m128i *)(dqcoeff + i));
34     __m128i mm_dqcoeff2 = _mm_load_si128((__m128i *)(dqcoeff + i + 4));
35     // Check if any values require more than 15 bit
36     max = _mm_set1_epi32(0x3fff);
37     min = _mm_set1_epi32((int)0xffffc000);
38     cmp0 = _mm_xor_si128(_mm_cmpgt_epi32(mm_coeff, max),
39                          _mm_cmplt_epi32(mm_coeff, min));
40     cmp1 = _mm_xor_si128(_mm_cmpgt_epi32(mm_coeff2, max),
41                          _mm_cmplt_epi32(mm_coeff2, min));
42     cmp2 = _mm_xor_si128(_mm_cmpgt_epi32(mm_dqcoeff, max),
43                          _mm_cmplt_epi32(mm_dqcoeff, min));
44     cmp3 = _mm_xor_si128(_mm_cmpgt_epi32(mm_dqcoeff2, max),
45                          _mm_cmplt_epi32(mm_dqcoeff2, min));
46     test = _mm_movemask_epi8(
47         _mm_or_si128(_mm_or_si128(cmp0, cmp1), _mm_or_si128(cmp2, cmp3)));
48 
49     if (!test) {
50       __m128i mm_diff, error_sse2, sqcoeff_sse2;
51       mm_coeff = _mm_packs_epi32(mm_coeff, mm_coeff2);
52       mm_dqcoeff = _mm_packs_epi32(mm_dqcoeff, mm_dqcoeff2);
53       mm_diff = _mm_sub_epi16(mm_coeff, mm_dqcoeff);
54       error_sse2 = _mm_madd_epi16(mm_diff, mm_diff);
55       sqcoeff_sse2 = _mm_madd_epi16(mm_coeff, mm_coeff);
56       _mm_storeu_si128((__m128i *)temp, error_sse2);
57       error = error + temp[0] + temp[1] + temp[2] + temp[3];
58       _mm_storeu_si128((__m128i *)temp, sqcoeff_sse2);
59       sqcoeff += temp[0] + temp[1] + temp[2] + temp[3];
60     } else {
61       for (j = 0; j < 8; j++) {
62         const int64_t diff = coeff[i + j] - dqcoeff[i + j];
63         error += diff * diff;
64         sqcoeff += (int64_t)coeff[i + j] * (int64_t)coeff[i + j];
65       }
66     }
67   }
68   assert(error >= 0 && sqcoeff >= 0);
69   error = (error + rounding) >> shift;
70   sqcoeff = (sqcoeff + rounding) >> shift;
71 
72   *ssz = sqcoeff;
73   return error;
74 }
75