• 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/loop_filter.h"
16 
17 #include <cassert>
18 #include <cstddef>
19 #include <cstdint>
20 #include <cstdlib>
21 
22 #include "src/dsp/dsp.h"
23 #include "src/utils/common.h"
24 
25 namespace libgav1 {
26 namespace dsp {
27 namespace {
28 
29 // 7.14.6.1.
30 template <int bitdepth, typename Pixel>
31 struct LoopFilterFuncs_C {
32   LoopFilterFuncs_C() = delete;
33 
34   static constexpr int kMaxPixel = (1 << bitdepth) - 1;
35   static constexpr int kMinSignedPixel = -(1 << (bitdepth - 1));
36   static constexpr int kMaxSignedPixel = (1 << (bitdepth - 1)) - 1;
37   static constexpr int kFlatThresh = 1 << (bitdepth - 8);
38 
39   static void Vertical4(void* dest, ptrdiff_t stride, int outer_thresh,
40                         int inner_thresh, int hev_thresh);
41   static void Horizontal4(void* dest, ptrdiff_t stride, int outer_thresh,
42                           int inner_thresh, int hev_thresh);
43   static void Vertical6(void* dest, ptrdiff_t stride, int outer_thresh,
44                         int inner_thresh, int hev_thresh);
45   static void Horizontal6(void* dest, ptrdiff_t stride, int outer_thresh,
46                           int inner_thresh, int hev_thresh);
47   static void Vertical8(void* dest, ptrdiff_t stride, int outer_thresh,
48                         int inner_thresh, int hev_thresh);
49   static void Horizontal8(void* dest, ptrdiff_t stride, int outer_thresh,
50                           int inner_thresh, int hev_thresh);
51   static void Vertical14(void* dest, ptrdiff_t stride, int outer_thresh,
52                          int inner_thresh, int hev_thresh);
53   static void Horizontal14(void* dest, ptrdiff_t stride, int outer_thresh,
54                            int inner_thresh, int hev_thresh);
55 };
56 
AdjustThresholds(const int bitdepth,int * const outer_thresh,int * const inner_thresh,int * const hev_thresh)57 inline void AdjustThresholds(const int bitdepth, int* const outer_thresh,
58                              int* const inner_thresh, int* const hev_thresh) {
59   *outer_thresh <<= bitdepth - 8;
60   *inner_thresh <<= bitdepth - 8;
61   *hev_thresh <<= bitdepth - 8;
62 }
63 
64 //------------------------------------------------------------------------------
65 // 4-tap filters
66 
67 // 7.14.6.2.
68 template <typename Pixel>
NeedsFilter4(const Pixel * p,ptrdiff_t step,int outer_thresh,int inner_thresh)69 inline bool NeedsFilter4(const Pixel* p, ptrdiff_t step, int outer_thresh,
70                          int inner_thresh) {
71   const int p1 = p[-2 * step], p0 = p[-step];
72   const int q0 = p[0], q1 = p[step];
73   return std::abs(p1 - p0) <= inner_thresh &&
74          std::abs(q1 - q0) <= inner_thresh &&
75          std::abs(p0 - q0) * 2 + std::abs(p1 - q1) / 2 <= outer_thresh;
76 }
77 
78 // 7.14.6.2.
79 template <typename Pixel>
Hev(const Pixel * p,ptrdiff_t step,int thresh)80 inline bool Hev(const Pixel* p, ptrdiff_t step, int thresh) {
81   const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step];
82   return (std::abs(p1 - p0) > thresh) || (std::abs(q1 - q0) > thresh);
83 }
84 
85 // 7.14.6.3.
86 // 4 pixels in, 2 pixels out.
87 template <int bitdepth, typename Pixel>
Filter2_C(Pixel * p,ptrdiff_t step)88 inline void Filter2_C(Pixel* p, ptrdiff_t step) {
89   const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step];
90   const int min_signed_val =
91       LoopFilterFuncs_C<bitdepth, Pixel>::kMinSignedPixel;
92   const int max_signed_val =
93       LoopFilterFuncs_C<bitdepth, Pixel>::kMaxSignedPixel;
94   // 8bpp: [-893,892], 10bpp: [-3581,3580], 12bpp [-14333,14332]
95   const int a = 3 * (q0 - p0) + Clip3(p1 - q1, min_signed_val, max_signed_val);
96   // 8bpp: [-16,15], 10bpp: [-64,63], 12bpp: [-256,255]
97   const int a1 = Clip3(a + 4, min_signed_val, max_signed_val) >> 3;
98   const int a2 = Clip3(a + 3, min_signed_val, max_signed_val) >> 3;
99   const int max_unsigned_val = LoopFilterFuncs_C<bitdepth, Pixel>::kMaxPixel;
100   p[-step] = Clip3(p0 + a2, 0, max_unsigned_val);
101   p[0] = Clip3(q0 - a1, 0, max_unsigned_val);
102 }
103 
104 // 7.14.6.3.
105 // 4 pixels in, 4 pixels out.
106 template <int bitdepth, typename Pixel>
Filter4_C(Pixel * p,ptrdiff_t step)107 inline void Filter4_C(Pixel* p, ptrdiff_t step) {
108   const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step];
109   const int a = 3 * (q0 - p0);
110   const int min_signed_val =
111       LoopFilterFuncs_C<bitdepth, Pixel>::kMinSignedPixel;
112   const int max_signed_val =
113       LoopFilterFuncs_C<bitdepth, Pixel>::kMaxSignedPixel;
114   const int a1 = Clip3(a + 4, min_signed_val, max_signed_val) >> 3;
115   const int a2 = Clip3(a + 3, min_signed_val, max_signed_val) >> 3;
116   const int a3 = (a1 + 1) >> 1;
117   const int max_unsigned_val = LoopFilterFuncs_C<bitdepth, Pixel>::kMaxPixel;
118   p[-2 * step] = Clip3(p1 + a3, 0, max_unsigned_val);
119   p[-1 * step] = Clip3(p0 + a2, 0, max_unsigned_val);
120   p[0 * step] = Clip3(q0 - a1, 0, max_unsigned_val);
121   p[1 * step] = Clip3(q1 - a3, 0, max_unsigned_val);
122 }
123 
124 template <int bitdepth, typename Pixel>
Vertical4(void * dest,ptrdiff_t stride,int outer_thresh,int inner_thresh,int hev_thresh)125 void LoopFilterFuncs_C<bitdepth, Pixel>::Vertical4(void* dest, ptrdiff_t stride,
126                                                    int outer_thresh,
127                                                    int inner_thresh,
128                                                    int hev_thresh) {
129   AdjustThresholds(bitdepth, &outer_thresh, &inner_thresh, &hev_thresh);
130   auto* dst = static_cast<Pixel*>(dest);
131   stride /= sizeof(Pixel);
132   for (int i = 0; i < 4; ++i) {
133     if (NeedsFilter4(dst, 1, outer_thresh, inner_thresh)) {
134       if (Hev(dst, 1, hev_thresh)) {
135         Filter2_C<bitdepth>(dst, 1);
136       } else {
137         Filter4_C<bitdepth>(dst, 1);
138       }
139     }
140     dst += stride;
141   }
142 }
143 
144 template <int bitdepth, typename Pixel>
Horizontal4(void * dest,ptrdiff_t stride,int outer_thresh,int inner_thresh,int hev_thresh)145 void LoopFilterFuncs_C<bitdepth, Pixel>::Horizontal4(void* dest,
146                                                      ptrdiff_t stride,
147                                                      int outer_thresh,
148                                                      int inner_thresh,
149                                                      int hev_thresh) {
150   AdjustThresholds(bitdepth, &outer_thresh, &inner_thresh, &hev_thresh);
151   auto* dst = static_cast<Pixel*>(dest);
152   stride /= sizeof(Pixel);
153   for (int i = 0; i < 4; ++i) {
154     if (NeedsFilter4(dst, stride, outer_thresh, inner_thresh)) {
155       if (Hev(dst, stride, hev_thresh)) {
156         Filter2_C<bitdepth>(dst, stride);
157       } else {
158         Filter4_C<bitdepth>(dst, stride);
159       }
160     }
161     ++dst;
162   }
163 }
164 
165 //------------------------------------------------------------------------------
166 // 5-tap (chroma) filters
167 
168 // 7.14.6.2.
169 template <typename Pixel>
NeedsFilter6(const Pixel * p,ptrdiff_t step,int outer_thresh,int inner_thresh)170 inline bool NeedsFilter6(const Pixel* p, ptrdiff_t step, int outer_thresh,
171                          int inner_thresh) {
172   const int p2 = p[-3 * step], p1 = p[-2 * step], p0 = p[-step];
173   const int q0 = p[0], q1 = p[step], q2 = p[2 * step];
174   return std::abs(p2 - p1) <= inner_thresh &&
175          std::abs(p1 - p0) <= inner_thresh &&
176          std::abs(q1 - q0) <= inner_thresh &&
177          std::abs(q2 - q1) <= inner_thresh &&
178          std::abs(p0 - q0) * 2 + std::abs(p1 - q1) / 2 <= outer_thresh;
179 }
180 
181 // 7.14.6.2.
182 template <typename Pixel>
IsFlat3(const Pixel * p,ptrdiff_t step,int flat_thresh)183 inline bool IsFlat3(const Pixel* p, ptrdiff_t step, int flat_thresh) {
184   const int p2 = p[-3 * step], p1 = p[-2 * step], p0 = p[-step];
185   const int q0 = p[0], q1 = p[step], q2 = p[2 * step];
186   return std::abs(p1 - p0) <= flat_thresh && std::abs(q1 - q0) <= flat_thresh &&
187          std::abs(p2 - p0) <= flat_thresh && std::abs(q2 - q0) <= flat_thresh;
188 }
189 
190 template <typename Pixel>
ApplyFilter6(int filter_value)191 inline Pixel ApplyFilter6(int filter_value) {
192   return static_cast<Pixel>(RightShiftWithRounding(filter_value, 3));
193 }
194 
195 // 7.14.6.4.
196 // 6 pixels in, 4 pixels out.
197 template <typename Pixel>
Filter6_C(Pixel * p,ptrdiff_t step)198 inline void Filter6_C(Pixel* p, ptrdiff_t step) {
199   const int p2 = p[-3 * step], p1 = p[-2 * step], p0 = p[-step];
200   const int q0 = p[0], q1 = p[step], q2 = p[2 * step];
201   const int a1 = 2 * p1;
202   const int a0 = 2 * p0;
203   const int b0 = 2 * q0;
204   const int b1 = 2 * q1;
205   // The max is 8 * max_pixel + 4 for the rounder.
206   // 8bpp: 2044 (11 bits), 10bpp: 8188 (13 bits), 12bpp: 32764 (15 bits)
207   p[-2 * step] = ApplyFilter6<Pixel>(3 * p2 + a1 + a0 + q0);
208   p[-1 * step] = ApplyFilter6<Pixel>(p2 + a1 + a0 + b0 + q1);
209   p[0 * step] = ApplyFilter6<Pixel>(p1 + a0 + b0 + b1 + q2);
210   p[1 * step] = ApplyFilter6<Pixel>(p0 + b0 + b1 + 3 * q2);
211 }
212 
213 template <int bitdepth, typename Pixel>
Vertical6(void * dest,ptrdiff_t stride,int outer_thresh,int inner_thresh,int hev_thresh)214 void LoopFilterFuncs_C<bitdepth, Pixel>::Vertical6(void* dest, ptrdiff_t stride,
215                                                    int outer_thresh,
216                                                    int inner_thresh,
217                                                    int hev_thresh) {
218   const int flat_thresh = LoopFilterFuncs_C<bitdepth, Pixel>::kFlatThresh;
219   AdjustThresholds(bitdepth, &outer_thresh, &inner_thresh, &hev_thresh);
220   auto* dst = static_cast<Pixel*>(dest);
221   stride /= sizeof(Pixel);
222   for (int i = 0; i < 4; ++i) {
223     if (NeedsFilter6(dst, 1, outer_thresh, inner_thresh)) {
224       if (IsFlat3(dst, 1, flat_thresh)) {
225         Filter6_C(dst, 1);
226       } else if (Hev(dst, 1, hev_thresh)) {
227         Filter2_C<bitdepth>(dst, 1);
228       } else {
229         Filter4_C<bitdepth>(dst, 1);
230       }
231     }
232     dst += stride;
233   }
234 }
235 
236 template <int bitdepth, typename Pixel>
Horizontal6(void * dest,ptrdiff_t stride,int outer_thresh,int inner_thresh,int hev_thresh)237 void LoopFilterFuncs_C<bitdepth, Pixel>::Horizontal6(void* dest,
238                                                      ptrdiff_t stride,
239                                                      int outer_thresh,
240                                                      int inner_thresh,
241                                                      int hev_thresh) {
242   const int flat_thresh = LoopFilterFuncs_C<bitdepth, Pixel>::kFlatThresh;
243   AdjustThresholds(bitdepth, &outer_thresh, &inner_thresh, &hev_thresh);
244   auto* dst = static_cast<Pixel*>(dest);
245   stride /= sizeof(Pixel);
246   for (int i = 0; i < 4; ++i) {
247     if (NeedsFilter6(dst, stride, outer_thresh, inner_thresh)) {
248       if (IsFlat3(dst, stride, flat_thresh)) {
249         Filter6_C(dst, stride);
250       } else if (Hev(dst, stride, hev_thresh)) {
251         Filter2_C<bitdepth>(dst, stride);
252       } else {
253         Filter4_C<bitdepth>(dst, stride);
254       }
255     }
256     ++dst;
257   }
258 }
259 
260 //------------------------------------------------------------------------------
261 // 7-tap filters
262 
263 // 7.14.6.2.
264 template <typename Pixel>
NeedsFilter8(const Pixel * p,ptrdiff_t step,int outer_thresh,int inner_thresh)265 inline bool NeedsFilter8(const Pixel* p, ptrdiff_t step, int outer_thresh,
266                          int inner_thresh) {
267   const int p3 = p[-4 * step], p2 = p[-3 * step], p1 = p[-2 * step],
268             p0 = p[-step];
269   const int q0 = p[0], q1 = p[step], q2 = p[2 * step], q3 = p[3 * step];
270   return std::abs(p3 - p2) <= inner_thresh &&
271          std::abs(p2 - p1) <= inner_thresh &&
272          std::abs(p1 - p0) <= inner_thresh &&
273          std::abs(q1 - q0) <= inner_thresh &&
274          std::abs(q2 - q1) <= inner_thresh &&
275          std::abs(q3 - q2) <= inner_thresh &&
276          std::abs(p0 - q0) * 2 + std::abs(p1 - q1) / 2 <= outer_thresh;
277 }
278 
279 // 7.14.6.2.
280 template <typename Pixel>
IsFlat4(const Pixel * p,ptrdiff_t step,int flat_thresh)281 inline bool IsFlat4(const Pixel* p, ptrdiff_t step, int flat_thresh) {
282   const int p3 = p[-4 * step], p2 = p[-3 * step], p1 = p[-2 * step],
283             p0 = p[-step];
284   const int q0 = p[0], q1 = p[step], q2 = p[2 * step], q3 = p[3 * step];
285   return std::abs(p1 - p0) <= flat_thresh && std::abs(q1 - q0) <= flat_thresh &&
286          std::abs(p2 - p0) <= flat_thresh && std::abs(q2 - q0) <= flat_thresh &&
287          std::abs(p3 - p0) <= flat_thresh && std::abs(q3 - q0) <= flat_thresh;
288 }
289 
290 template <typename Pixel>
ApplyFilter8(int filter_value)291 inline Pixel ApplyFilter8(int filter_value) {
292   return static_cast<Pixel>(RightShiftWithRounding(filter_value, 3));
293 }
294 
295 // 7.14.6.4.
296 // 8 pixels in, 6 pixels out.
297 template <typename Pixel>
Filter8_C(Pixel * p,ptrdiff_t step)298 inline void Filter8_C(Pixel* p, ptrdiff_t step) {
299   const int p3 = p[-4 * step], p2 = p[-3 * step], p1 = p[-2 * step],
300             p0 = p[-step];
301   const int q0 = p[0], q1 = p[step], q2 = p[2 * step], q3 = p[3 * step];
302   // The max is 8 * max_pixel + 4 for the rounder.
303   // 8bpp: 2044 (11 bits), 10bpp: 8188 (13 bits), 12bpp: 32764 (15 bits)
304   p[-3 * step] = ApplyFilter8<Pixel>(3 * p3 + 2 * p2 + p1 + p0 + q0);
305   p[-2 * step] = ApplyFilter8<Pixel>(2 * p3 + p2 + 2 * p1 + p0 + q0 + q1);
306   p[-1 * step] = ApplyFilter8<Pixel>(p3 + p2 + p1 + 2 * p0 + q0 + q1 + q2);
307   p[0 * step] = ApplyFilter8<Pixel>(p2 + p1 + p0 + 2 * q0 + q1 + q2 + q3);
308   p[1 * step] = ApplyFilter8<Pixel>(p1 + p0 + q0 + 2 * q1 + q2 + 2 * q3);
309   p[2 * step] = ApplyFilter8<Pixel>(p0 + q0 + q1 + 2 * q2 + 3 * q3);
310 }
311 
312 template <int bitdepth, typename Pixel>
Vertical8(void * dest,ptrdiff_t stride,int outer_thresh,int inner_thresh,int hev_thresh)313 void LoopFilterFuncs_C<bitdepth, Pixel>::Vertical8(void* dest, ptrdiff_t stride,
314                                                    int outer_thresh,
315                                                    int inner_thresh,
316                                                    int hev_thresh) {
317   const int flat_thresh = LoopFilterFuncs_C<bitdepth, Pixel>::kFlatThresh;
318   AdjustThresholds(bitdepth, &outer_thresh, &inner_thresh, &hev_thresh);
319   auto* dst = static_cast<Pixel*>(dest);
320   stride /= sizeof(Pixel);
321   for (int i = 0; i < 4; ++i) {
322     if (NeedsFilter8(dst, 1, outer_thresh, inner_thresh)) {
323       if (IsFlat4(dst, 1, flat_thresh)) {
324         Filter8_C(dst, 1);
325       } else if (Hev(dst, 1, hev_thresh)) {
326         Filter2_C<bitdepth>(dst, 1);
327       } else {
328         Filter4_C<bitdepth>(dst, 1);
329       }
330     }
331     dst += stride;
332   }
333 }
334 
335 template <int bitdepth, typename Pixel>
Horizontal8(void * dest,ptrdiff_t stride,int outer_thresh,int inner_thresh,int hev_thresh)336 void LoopFilterFuncs_C<bitdepth, Pixel>::Horizontal8(void* dest,
337                                                      ptrdiff_t stride,
338                                                      int outer_thresh,
339                                                      int inner_thresh,
340                                                      int hev_thresh) {
341   const int flat_thresh = LoopFilterFuncs_C<bitdepth, Pixel>::kFlatThresh;
342   AdjustThresholds(bitdepth, &outer_thresh, &inner_thresh, &hev_thresh);
343   auto* dst = static_cast<Pixel*>(dest);
344   stride /= sizeof(Pixel);
345   for (int i = 0; i < 4; ++i) {
346     if (NeedsFilter8(dst, stride, outer_thresh, inner_thresh)) {
347       if (IsFlat4(dst, stride, flat_thresh)) {
348         Filter8_C(dst, stride);
349       } else if (Hev(dst, stride, hev_thresh)) {
350         Filter2_C<bitdepth>(dst, stride);
351       } else {
352         Filter4_C<bitdepth>(dst, stride);
353       }
354     }
355     ++dst;
356   }
357 }
358 
359 //------------------------------------------------------------------------------
360 // 13-tap filters
361 
362 // 7.14.6.2.
363 template <typename Pixel>
IsFlatOuter4(const Pixel * p,ptrdiff_t step,int flat_thresh)364 inline bool IsFlatOuter4(const Pixel* p, ptrdiff_t step, int flat_thresh) {
365   const int p6 = p[-7 * step], p5 = p[-6 * step], p4 = p[-5 * step],
366             p0 = p[-step];
367   const int q0 = p[0], q4 = p[4 * step], q5 = p[5 * step], q6 = p[6 * step];
368   return std::abs(p4 - p0) <= flat_thresh && std::abs(q4 - q0) <= flat_thresh &&
369          std::abs(p5 - p0) <= flat_thresh && std::abs(q5 - q0) <= flat_thresh &&
370          std::abs(p6 - p0) <= flat_thresh && std::abs(q6 - q0) <= flat_thresh;
371 }
372 
373 template <typename Pixel>
ApplyFilter14(int filter_value)374 inline Pixel ApplyFilter14(int filter_value) {
375   return static_cast<Pixel>(RightShiftWithRounding(filter_value, 4));
376 }
377 
378 // 7.14.6.4.
379 // 14 pixels in, 12 pixels out.
380 template <typename Pixel>
Filter14_C(Pixel * p,ptrdiff_t step)381 inline void Filter14_C(Pixel* p, ptrdiff_t step) {
382   const int p6 = p[-7 * step], p5 = p[-6 * step], p4 = p[-5 * step],
383             p3 = p[-4 * step], p2 = p[-3 * step], p1 = p[-2 * step],
384             p0 = p[-step];
385   const int q0 = p[0], q1 = p[step], q2 = p[2 * step], q3 = p[3 * step],
386             q4 = p[4 * step], q5 = p[5 * step], q6 = p[6 * step];
387   // The max is 16 * max_pixel + 8 for the rounder.
388   // 8bpp: 4088 (12 bits), 10bpp: 16376 (14 bits), 12bpp: 65528 (16 bits)
389   p[-6 * step] =
390       ApplyFilter14<Pixel>(p6 * 7 + p5 * 2 + p4 * 2 + p3 + p2 + p1 + p0 + q0);
391   p[-5 * step] = ApplyFilter14<Pixel>(p6 * 5 + p5 * 2 + p4 * 2 + p3 * 2 + p2 +
392                                       p1 + p0 + q0 + q1);
393   p[-4 * step] = ApplyFilter14<Pixel>(p6 * 4 + p5 + p4 * 2 + p3 * 2 + p2 * 2 +
394                                       p1 + p0 + q0 + q1 + q2);
395   p[-3 * step] = ApplyFilter14<Pixel>(p6 * 3 + p5 + p4 + p3 * 2 + p2 * 2 +
396                                       p1 * 2 + p0 + q0 + q1 + q2 + q3);
397   p[-2 * step] = ApplyFilter14<Pixel>(p6 * 2 + p5 + p4 + p3 + p2 * 2 + p1 * 2 +
398                                       p0 * 2 + q0 + q1 + q2 + q3 + q4);
399   p[-1 * step] = ApplyFilter14<Pixel>(p6 + p5 + p4 + p3 + p2 + p1 * 2 + p0 * 2 +
400                                       q0 * 2 + q1 + q2 + q3 + q4 + q5);
401   p[0 * step] = ApplyFilter14<Pixel>(p5 + p4 + p3 + p2 + p1 + p0 * 2 + q0 * 2 +
402                                      q1 * 2 + q2 + q3 + q4 + q5 + q6);
403   p[1 * step] = ApplyFilter14<Pixel>(p4 + p3 + p2 + p1 + p0 + q0 * 2 + q1 * 2 +
404                                      q2 * 2 + q3 + q4 + q5 + q6 * 2);
405   p[2 * step] = ApplyFilter14<Pixel>(p3 + p2 + p1 + p0 + q0 + q1 * 2 + q2 * 2 +
406                                      q3 * 2 + q4 + q5 + q6 * 3);
407   p[3 * step] = ApplyFilter14<Pixel>(p2 + p1 + p0 + q0 + q1 + q2 * 2 + q3 * 2 +
408                                      q4 * 2 + q5 + q6 * 4);
409   p[4 * step] = ApplyFilter14<Pixel>(p1 + p0 + q0 + q1 + q2 + q3 * 2 + q4 * 2 +
410                                      q5 * 2 + q6 * 5);
411   p[5 * step] =
412       ApplyFilter14<Pixel>(p0 + q0 + q1 + q2 + q3 + q4 * 2 + q5 * 2 + q6 * 7);
413 }
414 
415 template <int bitdepth, typename Pixel>
Vertical14(void * dest,ptrdiff_t stride,int outer_thresh,int inner_thresh,int hev_thresh)416 void LoopFilterFuncs_C<bitdepth, Pixel>::Vertical14(void* dest,
417                                                     ptrdiff_t stride,
418                                                     int outer_thresh,
419                                                     int inner_thresh,
420                                                     int hev_thresh) {
421   const int flat_thresh = LoopFilterFuncs_C<bitdepth, Pixel>::kFlatThresh;
422   AdjustThresholds(bitdepth, &outer_thresh, &inner_thresh, &hev_thresh);
423   auto* dst = static_cast<Pixel*>(dest);
424   stride /= sizeof(Pixel);
425   for (int i = 0; i < 4; ++i) {
426     if (NeedsFilter8(dst, 1, outer_thresh, inner_thresh)) {
427       if (IsFlat4(dst, 1, flat_thresh)) {
428         if (IsFlatOuter4(dst, 1, flat_thresh)) {
429           Filter14_C(dst, 1);
430         } else {
431           Filter8_C(dst, 1);
432         }
433       } else if (Hev(dst, 1, hev_thresh)) {
434         Filter2_C<bitdepth>(dst, 1);
435       } else {
436         Filter4_C<bitdepth>(dst, 1);
437       }
438     }
439     dst += stride;
440   }
441 }
442 
443 template <int bitdepth, typename Pixel>
Horizontal14(void * dest,ptrdiff_t stride,int outer_thresh,int inner_thresh,int hev_thresh)444 void LoopFilterFuncs_C<bitdepth, Pixel>::Horizontal14(void* dest,
445                                                       ptrdiff_t stride,
446                                                       int outer_thresh,
447                                                       int inner_thresh,
448                                                       int hev_thresh) {
449   const int flat_thresh = LoopFilterFuncs_C<bitdepth, Pixel>::kFlatThresh;
450   AdjustThresholds(bitdepth, &outer_thresh, &inner_thresh, &hev_thresh);
451   auto* dst = static_cast<Pixel*>(dest);
452   stride /= sizeof(Pixel);
453   for (int i = 0; i < 4; ++i) {
454     if (NeedsFilter8(dst, stride, outer_thresh, inner_thresh)) {
455       if (IsFlat4(dst, stride, flat_thresh)) {
456         if (IsFlatOuter4(dst, stride, flat_thresh)) {
457           Filter14_C(dst, stride);
458         } else {
459           Filter8_C(dst, stride);
460         }
461       } else if (Hev(dst, stride, hev_thresh)) {
462         Filter2_C<bitdepth>(dst, stride);
463       } else {
464         Filter4_C<bitdepth>(dst, stride);
465       }
466     }
467     ++dst;
468   }
469 }
470 
471 using Defs8bpp = LoopFilterFuncs_C<8, uint8_t>;
472 
Init8bpp()473 void Init8bpp() {
474   Dsp* const dsp = dsp_internal::GetWritableDspTable(8);
475   assert(dsp != nullptr);
476 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
477   dsp->loop_filters[kLoopFilterSize4][kLoopFilterTypeHorizontal] =
478       Defs8bpp::Horizontal4;
479   dsp->loop_filters[kLoopFilterSize4][kLoopFilterTypeVertical] =
480       Defs8bpp::Vertical4;
481 
482   dsp->loop_filters[kLoopFilterSize6][kLoopFilterTypeHorizontal] =
483       Defs8bpp::Horizontal6;
484   dsp->loop_filters[kLoopFilterSize6][kLoopFilterTypeVertical] =
485       Defs8bpp::Vertical6;
486 
487   dsp->loop_filters[kLoopFilterSize8][kLoopFilterTypeHorizontal] =
488       Defs8bpp::Horizontal8;
489   dsp->loop_filters[kLoopFilterSize8][kLoopFilterTypeVertical] =
490       Defs8bpp::Vertical8;
491 
492   dsp->loop_filters[kLoopFilterSize14][kLoopFilterTypeHorizontal] =
493       Defs8bpp::Horizontal14;
494   dsp->loop_filters[kLoopFilterSize14][kLoopFilterTypeVertical] =
495       Defs8bpp::Vertical14;
496 #else  // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
497   static_cast<void>(dsp);
498 #ifndef LIBGAV1_Dsp8bpp_LoopFilterSize4_LoopFilterTypeHorizontal
499   dsp->loop_filters[kLoopFilterSize4][kLoopFilterTypeHorizontal] =
500       Defs8bpp::Horizontal4;
501 #endif
502 #ifndef LIBGAV1_Dsp8bpp_LoopFilterSize4_LoopFilterTypeVertical
503   dsp->loop_filters[kLoopFilterSize4][kLoopFilterTypeVertical] =
504       Defs8bpp::Vertical4;
505 #endif
506 
507 #ifndef LIBGAV1_Dsp8bpp_LoopFilterSize6_LoopFilterTypeHorizontal
508   dsp->loop_filters[kLoopFilterSize6][kLoopFilterTypeHorizontal] =
509       Defs8bpp::Horizontal6;
510 #endif
511 #ifndef LIBGAV1_Dsp8bpp_LoopFilterSize6_LoopFilterTypeVertical
512   dsp->loop_filters[kLoopFilterSize6][kLoopFilterTypeVertical] =
513       Defs8bpp::Vertical6;
514 #endif
515 
516 #ifndef LIBGAV1_Dsp8bpp_LoopFilterSize8_LoopFilterTypeHorizontal
517   dsp->loop_filters[kLoopFilterSize8][kLoopFilterTypeHorizontal] =
518       Defs8bpp::Horizontal8;
519 #endif
520 #ifndef LIBGAV1_Dsp8bpp_LoopFilterSize8_LoopFilterTypeVertical
521   dsp->loop_filters[kLoopFilterSize8][kLoopFilterTypeVertical] =
522       Defs8bpp::Vertical8;
523 #endif
524 
525 #ifndef LIBGAV1_Dsp8bpp_LoopFilterSize14_LoopFilterTypeHorizontal
526   dsp->loop_filters[kLoopFilterSize14][kLoopFilterTypeHorizontal] =
527       Defs8bpp::Horizontal14;
528 #endif
529 #ifndef LIBGAV1_Dsp8bpp_LoopFilterSize14_LoopFilterTypeVertical
530   dsp->loop_filters[kLoopFilterSize14][kLoopFilterTypeVertical] =
531       Defs8bpp::Vertical14;
532 #endif
533 #endif  // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
534 }
535 
536 #if LIBGAV1_MAX_BITDEPTH >= 10
537 using Defs10bpp = LoopFilterFuncs_C<10, uint16_t>;
538 
Init10bpp()539 void Init10bpp() {
540   Dsp* const dsp = dsp_internal::GetWritableDspTable(10);
541   assert(dsp != nullptr);
542 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
543   dsp->loop_filters[kLoopFilterSize4][kLoopFilterTypeHorizontal] =
544       Defs10bpp::Horizontal4;
545   dsp->loop_filters[kLoopFilterSize4][kLoopFilterTypeVertical] =
546       Defs10bpp::Vertical4;
547 
548   dsp->loop_filters[kLoopFilterSize6][kLoopFilterTypeHorizontal] =
549       Defs10bpp::Horizontal6;
550   dsp->loop_filters[kLoopFilterSize6][kLoopFilterTypeVertical] =
551       Defs10bpp::Vertical6;
552 
553   dsp->loop_filters[kLoopFilterSize8][kLoopFilterTypeHorizontal] =
554       Defs10bpp::Horizontal8;
555   dsp->loop_filters[kLoopFilterSize8][kLoopFilterTypeVertical] =
556       Defs10bpp::Vertical8;
557 
558   dsp->loop_filters[kLoopFilterSize14][kLoopFilterTypeHorizontal] =
559       Defs10bpp::Horizontal14;
560   dsp->loop_filters[kLoopFilterSize14][kLoopFilterTypeVertical] =
561       Defs10bpp::Vertical14;
562 #else  // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
563   static_cast<void>(dsp);
564 #ifndef LIBGAV1_Dsp10bpp_LoopFilterSize4_LoopFilterTypeHorizontal
565   dsp->loop_filters[kLoopFilterSize4][kLoopFilterTypeHorizontal] =
566       Defs10bpp::Horizontal4;
567 #endif
568 #ifndef LIBGAV1_Dsp10bpp_LoopFilterSize4_LoopFilterTypeVertical
569   dsp->loop_filters[kLoopFilterSize4][kLoopFilterTypeVertical] =
570       Defs10bpp::Vertical4;
571 #endif
572 
573 #ifndef LIBGAV1_Dsp10bpp_LoopFilterSize6_LoopFilterTypeHorizontal
574   dsp->loop_filters[kLoopFilterSize6][kLoopFilterTypeHorizontal] =
575       Defs10bpp::Horizontal6;
576 #endif
577 #ifndef LIBGAV1_Dsp10bpp_LoopFilterSize6_LoopFilterTypeVertical
578   dsp->loop_filters[kLoopFilterSize6][kLoopFilterTypeVertical] =
579       Defs10bpp::Vertical6;
580 #endif
581 
582 #ifndef LIBGAV1_Dsp10bpp_LoopFilterSize8_LoopFilterTypeHorizontal
583   dsp->loop_filters[kLoopFilterSize8][kLoopFilterTypeHorizontal] =
584       Defs10bpp::Horizontal8;
585 #endif
586 #ifndef LIBGAV1_Dsp10bpp_LoopFilterSize8_LoopFilterTypeVertical
587   dsp->loop_filters[kLoopFilterSize8][kLoopFilterTypeVertical] =
588       Defs10bpp::Vertical8;
589 #endif
590 
591 #ifndef LIBGAV1_Dsp10bpp_LoopFilterSize14_LoopFilterTypeHorizontal
592   dsp->loop_filters[kLoopFilterSize14][kLoopFilterTypeHorizontal] =
593       Defs10bpp::Horizontal14;
594 #endif
595 #ifndef LIBGAV1_Dsp10bpp_LoopFilterSize14_LoopFilterTypeVertical
596   dsp->loop_filters[kLoopFilterSize14][kLoopFilterTypeVertical] =
597       Defs10bpp::Vertical14;
598 #endif
599 #endif  // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
600 }
601 #endif  // LIBGAV1_MAX_BITDEPTH >= 10
602 
603 }  // namespace
604 
LoopFilterInit_C()605 void LoopFilterInit_C() {
606   Init8bpp();
607 #if LIBGAV1_MAX_BITDEPTH >= 10
608   Init10bpp();
609 #endif
610   // Local functions that may be unused depending on the optimizations
611   // available.
612   static_cast<void>(AdjustThresholds);
613 }
614 
615 }  // namespace dsp
616 }  // namespace libgav1
617