Coverage Report

Created: 2026-09-07 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/aom/aom_dsp/x86/variance_impl_ssse3.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2018, 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 <tmmintrin.h>
13
14
#include "config/aom_config.h"
15
#include "config/aom_dsp_rtcd.h"
16
17
#include "aom_dsp/x86/synonyms.h"
18
#include "aom_dsp/x86/variance_impl_ssse3.h"
19
20
void aom_var_filter_block2d_bil_first_pass_ssse3(
21
    const uint8_t *a, uint16_t *b, unsigned int src_pixels_per_line,
22
    unsigned int pixel_step, unsigned int output_height,
23
0
    unsigned int output_width, const uint8_t *filter) {
24
  // Note: filter[0], filter[1] could be {128, 0}, where 128 will overflow
25
  // in computation using _mm_maddubs_epi16.
26
  // Change {128, 0} to {64, 0} and reduce FILTER_BITS by 1 to avoid overflow.
27
0
  const int16_t round = (1 << (FILTER_BITS - 1)) >> 1;
28
0
  const __m128i r = _mm_set1_epi16(round);
29
0
  const int8_t f0 = (int8_t)(filter[0] >> 1);
30
0
  const int8_t f1 = (int8_t)(filter[1] >> 1);
31
0
  const __m128i filters = _mm_setr_epi8(f0, f1, f0, f1, f0, f1, f0, f1, f0, f1,
32
0
                                        f0, f1, f0, f1, f0, f1);
33
0
  unsigned int i, j;
34
0
  (void)pixel_step;
35
36
0
  if (output_width >= 8) {
37
0
    for (i = 0; i < output_height; ++i) {
38
0
      for (j = 0; j < output_width; j += 8) {
39
        // load source
40
0
        __m128i source_low = xx_loadl_64(a);
41
0
        __m128i source_hi = xx_loadl_64(a + 1);
42
43
        // unpack to:
44
        // { a[0], a[1], a[1], a[2], a[2], a[3], a[3], a[4],
45
        //   a[4], a[5], a[5], a[6], a[6], a[7], a[7], a[8] }
46
0
        __m128i source = _mm_unpacklo_epi8(source_low, source_hi);
47
48
        // b[i] = a[i] * filter[0] + a[i + 1] * filter[1]
49
0
        __m128i res = _mm_maddubs_epi16(source, filters);
50
51
        // round
52
0
        res = _mm_srai_epi16(_mm_add_epi16(res, r), FILTER_BITS - 1);
53
54
0
        xx_storeu_128(b, res);
55
56
0
        a += 8;
57
0
        b += 8;
58
0
      }
59
60
0
      a += src_pixels_per_line - output_width;
61
0
    }
62
0
  } else {
63
0
    const __m128i shuffle_mask =
64
0
        _mm_setr_epi8(0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8);
65
0
    for (i = 0; i < output_height; ++i) {
66
      // load source, only first 5 values are meaningful:
67
      // { a[0], a[1], a[2], a[3], a[4], xxxx }
68
0
      __m128i source = xx_loadl_64(a);
69
70
      // shuffle, up to the first 8 are useful
71
      // { a[0], a[1], a[1], a[2], a[2], a[3], a[3], a[4],
72
      //   a[4], a[5], a[5], a[6], a[6], a[7], a[7], a[8] }
73
0
      __m128i source_shuffle = _mm_shuffle_epi8(source, shuffle_mask);
74
75
0
      __m128i res = _mm_maddubs_epi16(source_shuffle, filters);
76
0
      res = _mm_srai_epi16(_mm_add_epi16(res, r), FILTER_BITS - 1);
77
78
0
      xx_storel_64(b, res);
79
80
0
      a += src_pixels_per_line;
81
0
      b += output_width;
82
0
    }
83
0
  }
84
0
}
85
86
void aom_var_filter_block2d_bil_second_pass_ssse3(
87
    const uint16_t *a, uint8_t *b, unsigned int src_pixels_per_line,
88
    unsigned int pixel_step, unsigned int output_height,
89
0
    unsigned int output_width, const uint8_t *filter) {
90
0
  const int16_t round = (1 << FILTER_BITS) >> 1;
91
0
  const __m128i r = _mm_set1_epi32(round);
92
0
  const __m128i filters =
93
0
      _mm_setr_epi16(filter[0], filter[1], filter[0], filter[1], filter[0],
94
0
                     filter[1], filter[0], filter[1]);
95
0
  const __m128i shuffle_mask =
96
0
      _mm_setr_epi8(0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15);
97
0
  const __m128i mask =
98
0
      _mm_setr_epi8(0, 4, 8, 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1);
99
0
  unsigned int i, j;
100
101
0
  for (i = 0; i < output_height; ++i) {
102
0
    for (j = 0; j < output_width; j += 4) {
103
      // load source as:
104
      // { a[0], a[1], a[2], a[3], a[w], a[w+1], a[w+2], a[w+3] }
105
0
      __m128i source1 = xx_loadl_64(a);
106
0
      __m128i source2 = xx_loadl_64(a + pixel_step);
107
0
      __m128i source = _mm_unpacklo_epi64(source1, source2);
108
109
      // shuffle source to:
110
      // { a[0], a[w], a[1], a[w+1], a[2], a[w+2], a[3], a[w+3] }
111
0
      __m128i source_shuffle = _mm_shuffle_epi8(source, shuffle_mask);
112
113
      // b[i] = a[i] * filter[0] + a[w + i] * filter[1]
114
0
      __m128i res = _mm_madd_epi16(source_shuffle, filters);
115
116
      // round
117
0
      res = _mm_srai_epi32(_mm_add_epi32(res, r), FILTER_BITS);
118
119
      // shuffle to get each lower 8 bit of every 32 bit
120
0
      res = _mm_shuffle_epi8(res, mask);
121
122
0
      xx_storel_32(b, res);
123
124
0
      a += 4;
125
0
      b += 4;
126
0
    }
127
128
0
    a += src_pixels_per_line - output_width;
129
0
  }
130
0
}