• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The libgav1 Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/dsp/cdef.h"
16 
17 #include <algorithm>
18 #include <cassert>
19 #include <cstddef>
20 #include <cstdint>
21 #include <cstring>
22 
23 #include "src/dsp/constants.h"
24 #include "src/dsp/dsp.h"
25 #include "src/utils/common.h"
26 #include "src/utils/constants.h"
27 
28 namespace libgav1 {
29 namespace dsp {
30 namespace {
31 
32 #include "src/dsp/cdef.inc"
33 
34 // Silence unused function warnings when CdefDirection_C is obviated.
35 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS ||        \
36     !defined(LIBGAV1_Dsp8bpp_CdefDirection) || \
37     (LIBGAV1_MAX_BITDEPTH >= 10 && !defined(LIBGAV1_Dsp10bpp_CdefDirection))
38 constexpr int16_t kDivisionTable[] = {840, 420, 280, 210, 168, 140, 120, 105};
39 
Square(int32_t x)40 int32_t Square(int32_t x) { return x * x; }
41 
42 template <int bitdepth, typename Pixel>
CdefDirection_C(const void * LIBGAV1_RESTRICT const source,ptrdiff_t stride,uint8_t * LIBGAV1_RESTRICT const direction,int * LIBGAV1_RESTRICT const variance)43 void CdefDirection_C(const void* LIBGAV1_RESTRICT const source,
44                      ptrdiff_t stride,
45                      uint8_t* LIBGAV1_RESTRICT const direction,
46                      int* LIBGAV1_RESTRICT const variance) {
47   assert(direction != nullptr);
48   assert(variance != nullptr);
49   const auto* src = static_cast<const Pixel*>(source);
50   stride /= sizeof(Pixel);
51   int32_t cost[8] = {};
52   // |partial| does not have to be int32_t for 8bpp. int16_t will suffice. We
53   // use int32_t to keep it simple since |cost| will have to be int32_t.
54   int32_t partial[8][15] = {};
55   for (int i = 0; i < 8; ++i) {
56     for (int j = 0; j < 8; ++j) {
57       const int x = (src[j] >> (bitdepth - 8)) - 128;
58       partial[0][i + j] += x;
59       partial[1][i + j / 2] += x;
60       partial[2][i] += x;
61       partial[3][3 + i - j / 2] += x;
62       partial[4][7 + i - j] += x;
63       partial[5][3 - i / 2 + j] += x;
64       partial[6][j] += x;
65       partial[7][i / 2 + j] += x;
66     }
67     src += stride;
68   }
69   for (int i = 0; i < 8; ++i) {
70     cost[2] += Square(partial[2][i]);
71     cost[6] += Square(partial[6][i]);
72   }
73   cost[2] *= kDivisionTable[7];
74   cost[6] *= kDivisionTable[7];
75   for (int i = 0; i < 7; ++i) {
76     cost[0] += (Square(partial[0][i]) + Square(partial[0][14 - i])) *
77                kDivisionTable[i];
78     cost[4] += (Square(partial[4][i]) + Square(partial[4][14 - i])) *
79                kDivisionTable[i];
80   }
81   cost[0] += Square(partial[0][7]) * kDivisionTable[7];
82   cost[4] += Square(partial[4][7]) * kDivisionTable[7];
83   for (int i = 1; i < 8; i += 2) {
84     for (int j = 0; j < 5; ++j) {
85       cost[i] += Square(partial[i][3 + j]);
86     }
87     cost[i] *= kDivisionTable[7];
88     for (int j = 0; j < 3; ++j) {
89       cost[i] += (Square(partial[i][j]) + Square(partial[i][10 - j])) *
90                  kDivisionTable[2 * j + 1];
91     }
92   }
93   int32_t best_cost = 0;
94   *direction = 0;
95   for (int i = 0; i < 8; ++i) {
96     if (cost[i] > best_cost) {
97       best_cost = cost[i];
98       *direction = i;
99     }
100   }
101   *variance = (best_cost - cost[(*direction + 4) & 7]) >> 10;
102 }
103 #endif  // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS ||
104         // !defined(LIBGAV1_Dsp8bpp_CdefDirection) ||
105         // (LIBGAV1_MAX_BITDEPTH >= 10 &&
106         // !defined(LIBGAV1_Dsp10bpp_CdefDirection))
107 
108 // Silence unused function warnings when CdefFilter_C is obviated.
109 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS ||      \
110     !defined(LIBGAV1_Dsp8bpp_CdefFilters) || \
111     (LIBGAV1_MAX_BITDEPTH >= 10 && !defined(LIBGAV1_Dsp10bpp_CdefFilters))
112 
Constrain(int diff,int threshold,int damping)113 int Constrain(int diff, int threshold, int damping) {
114   assert(threshold != 0);
115   damping = std::max(0, damping - FloorLog2(threshold));
116   const int sign = (diff < 0) ? -1 : 1;
117   return sign *
118          Clip3(threshold - (std::abs(diff) >> damping), 0, std::abs(diff));
119 }
120 
121 // Filters the source block. It doesn't check whether the candidate pixel is
122 // inside the frame. However it requires the source input to be padded with a
123 // constant large value (kCdefLargeValue) if at the boundary.
124 template <int block_width, int bitdepth, typename Pixel,
125           bool enable_primary = true, bool enable_secondary = true>
CdefFilter_C(const uint16_t * LIBGAV1_RESTRICT src,const ptrdiff_t src_stride,const int block_height,const int primary_strength,const int secondary_strength,const int damping,const int direction,void * LIBGAV1_RESTRICT const dest,const ptrdiff_t dest_stride)126 void CdefFilter_C(const uint16_t* LIBGAV1_RESTRICT src,
127                   const ptrdiff_t src_stride, const int block_height,
128                   const int primary_strength, const int secondary_strength,
129                   const int damping, const int direction,
130                   void* LIBGAV1_RESTRICT const dest,
131                   const ptrdiff_t dest_stride) {
132   static_assert(block_width == 4 || block_width == 8, "Invalid CDEF width.");
133   static_assert(enable_primary || enable_secondary, "");
134   assert(block_height == 4 || block_height == 8);
135   assert(direction >= 0 && direction <= 7);
136   constexpr int coeff_shift = bitdepth - 8;
137   // Section 5.9.19. CDEF params syntax.
138   assert(primary_strength >= 0 && primary_strength <= 15 << coeff_shift);
139   assert(secondary_strength >= 0 && secondary_strength <= 4 << coeff_shift &&
140          secondary_strength != 3 << coeff_shift);
141   assert(primary_strength != 0 || secondary_strength != 0);
142   // damping is decreased by 1 for chroma.
143   assert((damping >= 3 && damping <= 6 + coeff_shift) ||
144          (damping >= 2 && damping <= 5 + coeff_shift));
145   // When only primary_strength or secondary_strength are non-zero the number
146   // of pixels inspected (4 for primary_strength, 8 for secondary_strength) and
147   // the taps used don't exceed the amount the sum is
148   // descaled by (16) so we can skip tracking and clipping to the minimum and
149   // maximum value observed.
150   constexpr bool clipping_required = enable_primary && enable_secondary;
151   static constexpr int kCdefSecondaryTaps[2] = {kCdefSecondaryTap0,
152                                                 kCdefSecondaryTap1};
153   auto* dst = static_cast<Pixel*>(dest);
154   const ptrdiff_t dst_stride = dest_stride / sizeof(Pixel);
155   int y = block_height;
156   do {
157     int x = 0;
158     do {
159       int16_t sum = 0;
160       const uint16_t pixel_value = src[x];
161       uint16_t max_value = pixel_value;
162       uint16_t min_value = pixel_value;
163       for (int k = 0; k < 2; ++k) {
164         static constexpr int signs[] = {-1, 1};
165         for (const int& sign : signs) {
166           if (enable_primary) {
167             const int dy = sign * kCdefDirections[direction][k][0];
168             const int dx = sign * kCdefDirections[direction][k][1];
169             const uint16_t value = src[dy * src_stride + dx + x];
170             // Note: the summation can ignore the condition check in SIMD
171             // implementation, because Constrain() will return 0 when
172             // value == kCdefLargeValue.
173             if (value != kCdefLargeValue) {
174               sum += Constrain(value - pixel_value, primary_strength, damping) *
175                      kCdefPrimaryTaps[(primary_strength >> coeff_shift) & 1][k];
176               if (clipping_required) {
177                 max_value = std::max(value, max_value);
178                 min_value = std::min(value, min_value);
179               }
180             }
181           }
182 
183           if (enable_secondary) {
184             static constexpr int offsets[] = {-2, 2};
185             for (const int& offset : offsets) {
186               const int dy = sign * kCdefDirections[direction + offset][k][0];
187               const int dx = sign * kCdefDirections[direction + offset][k][1];
188               const uint16_t value = src[dy * src_stride + dx + x];
189               // Note: the summation can ignore the condition check in SIMD
190               // implementation.
191               if (value != kCdefLargeValue) {
192                 sum += Constrain(value - pixel_value, secondary_strength,
193                                  damping) *
194                        kCdefSecondaryTaps[k];
195                 if (clipping_required) {
196                   max_value = std::max(value, max_value);
197                   min_value = std::min(value, min_value);
198                 }
199               }
200             }
201           }
202         }
203       }
204 
205       const int offset = (8 + sum - (sum < 0)) >> 4;
206       if (clipping_required) {
207         dst[x] = static_cast<Pixel>(
208             Clip3(pixel_value + offset, min_value, max_value));
209       } else {
210         dst[x] = static_cast<Pixel>(pixel_value + offset);
211       }
212     } while (++x < block_width);
213 
214     src += src_stride;
215     dst += dst_stride;
216   } while (--y != 0);
217 }
218 #endif  // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS ||
219         // !defined(LIBGAV1_Dsp8bpp_CdefFilters) ||
220         // (LIBGAV1_MAX_BITDEPTH >= 10 &&
221         // !defined(LIBGAV1_Dsp10bpp_CdefFilters))
222 
Init8bpp()223 void Init8bpp() {
224   Dsp* const dsp = dsp_internal::GetWritableDspTable(8);
225   assert(dsp != nullptr);
226 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
227   dsp->cdef_direction = CdefDirection_C<8, uint8_t>;
228   dsp->cdef_filters[0][0] = CdefFilter_C<4, 8, uint8_t>;
229   dsp->cdef_filters[0][1] = CdefFilter_C<4, 8, uint8_t, /*enable_primary=*/true,
230                                          /*enable_secondary=*/false>;
231   dsp->cdef_filters[0][2] =
232       CdefFilter_C<4, 8, uint8_t, /*enable_primary=*/false>;
233   dsp->cdef_filters[1][0] = CdefFilter_C<8, 8, uint8_t>;
234   dsp->cdef_filters[1][1] = CdefFilter_C<8, 8, uint8_t, /*enable_primary=*/true,
235                                          /*enable_secondary=*/false>;
236   dsp->cdef_filters[1][2] =
237       CdefFilter_C<8, 8, uint8_t, /*enable_primary=*/false>;
238 #else  // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
239   static_cast<void>(dsp);
240 #ifndef LIBGAV1_Dsp8bpp_CdefDirection
241   dsp->cdef_direction = CdefDirection_C<8, uint8_t>;
242 #endif
243 #ifndef LIBGAV1_Dsp8bpp_CdefFilters
244   dsp->cdef_filters[0][0] = CdefFilter_C<4, 8, uint8_t>;
245   dsp->cdef_filters[0][1] = CdefFilter_C<4, 8, uint8_t, /*enable_primary=*/true,
246                                          /*enable_secondary=*/false>;
247   dsp->cdef_filters[0][2] =
248       CdefFilter_C<4, 8, uint8_t, /*enable_primary=*/false>;
249   dsp->cdef_filters[1][0] = CdefFilter_C<8, 8, uint8_t>;
250   dsp->cdef_filters[1][1] = CdefFilter_C<8, 8, uint8_t, /*enable_primary=*/true,
251                                          /*enable_secondary=*/false>;
252   dsp->cdef_filters[1][2] =
253       CdefFilter_C<8, 8, uint8_t, /*enable_primary=*/false>;
254 #endif
255 #endif  // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
256 }
257 
258 #if LIBGAV1_MAX_BITDEPTH >= 10
Init10bpp()259 void Init10bpp() {
260   Dsp* const dsp = dsp_internal::GetWritableDspTable(10);
261   assert(dsp != nullptr);
262 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
263   dsp->cdef_direction = CdefDirection_C<10, uint16_t>;
264   dsp->cdef_filters[0][0] = CdefFilter_C<4, 10, uint16_t>;
265   dsp->cdef_filters[0][1] =
266       CdefFilter_C<4, 10, uint16_t, /*enable_primary=*/true,
267                    /*enable_secondary=*/false>;
268   dsp->cdef_filters[0][2] =
269       CdefFilter_C<4, 10, uint16_t, /*enable_primary=*/false>;
270   dsp->cdef_filters[1][0] = CdefFilter_C<8, 10, uint16_t>;
271   dsp->cdef_filters[1][1] =
272       CdefFilter_C<8, 10, uint16_t, /*enable_primary=*/true,
273                    /*enable_secondary=*/false>;
274   dsp->cdef_filters[1][2] =
275       CdefFilter_C<8, 10, uint16_t, /*enable_primary=*/false>;
276 #else  // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
277   static_cast<void>(dsp);
278 #ifndef LIBGAV1_Dsp10bpp_CdefDirection
279   dsp->cdef_direction = CdefDirection_C<10, uint16_t>;
280 #endif
281 #ifndef LIBGAV1_Dsp10bpp_CdefFilters
282   dsp->cdef_filters[0][0] = CdefFilter_C<4, 10, uint16_t>;
283   dsp->cdef_filters[0][1] =
284       CdefFilter_C<4, 10, uint16_t, /*enable_primary=*/true,
285                    /*enable_secondary=*/false>;
286   dsp->cdef_filters[0][2] =
287       CdefFilter_C<4, 10, uint16_t, /*enable_primary=*/false>;
288   dsp->cdef_filters[1][0] = CdefFilter_C<8, 10, uint16_t>;
289   dsp->cdef_filters[1][1] =
290       CdefFilter_C<8, 10, uint16_t, /*enable_primary=*/true,
291                    /*enable_secondary=*/false>;
292   dsp->cdef_filters[1][2] =
293       CdefFilter_C<8, 10, uint16_t, /*enable_primary=*/false>;
294 #endif
295 #endif  // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
296 }
297 #endif
298 
299 }  // namespace
300 
CdefInit_C()301 void CdefInit_C() {
302   Init8bpp();
303 #if LIBGAV1_MAX_BITDEPTH >= 10
304   Init10bpp();
305 #endif
306 }
307 
308 }  // namespace dsp
309 }  // namespace libgav1
310