1 /*
2 * Copyright (c) 2014 The WebM project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include <emmintrin.h>
12 #include <stdio.h>
13
14 #include "./vp9_rtcd.h"
15 #include "vp9/common/vp9_common.h"
16
vp9_highbd_block_error_sse2(const tran_low_t * coeff,const tran_low_t * dqcoeff,intptr_t block_size,int64_t * ssz,int bd)17 int64_t vp9_highbd_block_error_sse2(const tran_low_t *coeff,
18 const tran_low_t *dqcoeff,
19 intptr_t block_size, int64_t *ssz, int bd) {
20 int i, j, test;
21 uint32_t temp[4];
22 __m128i max, min, cmp0, cmp1, cmp2, cmp3;
23 int64_t error = 0, sqcoeff = 0;
24 const int shift = 2 * (bd - 8);
25 const int rounding = shift > 0 ? 1 << (shift - 1) : 0;
26
27 for (i = 0; i < block_size; i += 8) {
28 // Load the data into xmm registers
29 __m128i mm_coeff = _mm_load_si128((const __m128i *)(coeff + i));
30 __m128i mm_coeff2 = _mm_load_si128((const __m128i *)(coeff + i + 4));
31 __m128i mm_dqcoeff = _mm_load_si128((const __m128i *)(dqcoeff + i));
32 __m128i mm_dqcoeff2 = _mm_load_si128((const __m128i *)(dqcoeff + i + 4));
33 // Check if any values require more than 15 bit
34 max = _mm_set1_epi32(0x3fff);
35 min = _mm_set1_epi32(0xffffc000);
36 cmp0 = _mm_xor_si128(_mm_cmpgt_epi32(mm_coeff, max),
37 _mm_cmplt_epi32(mm_coeff, min));
38 cmp1 = _mm_xor_si128(_mm_cmpgt_epi32(mm_coeff2, max),
39 _mm_cmplt_epi32(mm_coeff2, min));
40 cmp2 = _mm_xor_si128(_mm_cmpgt_epi32(mm_dqcoeff, max),
41 _mm_cmplt_epi32(mm_dqcoeff, min));
42 cmp3 = _mm_xor_si128(_mm_cmpgt_epi32(mm_dqcoeff2, max),
43 _mm_cmplt_epi32(mm_dqcoeff2, min));
44 test = _mm_movemask_epi8(
45 _mm_or_si128(_mm_or_si128(cmp0, cmp1), _mm_or_si128(cmp2, cmp3)));
46
47 if (!test) {
48 __m128i mm_diff, error_sse2, sqcoeff_sse2;
49 mm_coeff = _mm_packs_epi32(mm_coeff, mm_coeff2);
50 mm_dqcoeff = _mm_packs_epi32(mm_dqcoeff, mm_dqcoeff2);
51 mm_diff = _mm_sub_epi16(mm_coeff, mm_dqcoeff);
52 error_sse2 = _mm_madd_epi16(mm_diff, mm_diff);
53 sqcoeff_sse2 = _mm_madd_epi16(mm_coeff, mm_coeff);
54 _mm_storeu_si128((__m128i *)temp, error_sse2);
55 error = error + temp[0] + temp[1] + temp[2] + temp[3];
56 _mm_storeu_si128((__m128i *)temp, sqcoeff_sse2);
57 sqcoeff += temp[0] + temp[1] + temp[2] + temp[3];
58 } else {
59 for (j = 0; j < 8; j++) {
60 const int64_t diff = coeff[i + j] - dqcoeff[i + j];
61 error += diff * diff;
62 sqcoeff += (int64_t)coeff[i + j] * (int64_t)coeff[i + j];
63 }
64 }
65 }
66 assert(error >= 0 && sqcoeff >= 0);
67 error = (error + rounding) >> shift;
68 sqcoeff = (sqcoeff + rounding) >> shift;
69
70 *ssz = sqcoeff;
71 return error;
72 }
73