xref: /aosp_15_r20/external/libgav1/src/dsp/film_grain.cc (revision 095378508e87ed692bf8dfeb34008b65b3735891)
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/film_grain.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/dsp/film_grain_common.h"
26 #include "src/utils/array_2d.h"
27 #include "src/utils/common.h"
28 #include "src/utils/compiler_attributes.h"
29 #include "src/utils/constants.h"
30 #include "src/utils/memory.h"
31 #include "src/utils/types.h"
32 
33 namespace libgav1 {
34 namespace dsp {
35 namespace film_grain {
36 namespace {
37 
38 template <int bitdepth>
InitializeScalingLookupTable_C(int num_points,const uint8_t point_value[],const uint8_t point_scaling[],int16_t * scaling_lut,const int scaling_lut_length)39 void InitializeScalingLookupTable_C(int num_points, const uint8_t point_value[],
40                                     const uint8_t point_scaling[],
41                                     int16_t* scaling_lut,
42                                     const int scaling_lut_length) {
43   if (num_points == 0) {
44     memset(scaling_lut, 0, sizeof(scaling_lut[0]) * scaling_lut_length);
45     return;
46   }
47   constexpr int index_shift = (bitdepth == kBitdepth10) ? 2 : 0;
48   static_assert(sizeof(scaling_lut[0]) == 2, "");
49   Memset(scaling_lut, point_scaling[0],
50          std::max(static_cast<int>(point_value[0]), 1) << index_shift);
51   for (int i = 0; i < num_points - 1; ++i) {
52     const int delta_y = point_scaling[i + 1] - point_scaling[i];
53     const int delta_x = point_value[i + 1] - point_value[i];
54     const int delta = delta_y * ((65536 + (delta_x >> 1)) / delta_x);
55     for (int x = 0; x < delta_x; ++x) {
56       const int v = point_scaling[i] + ((x * delta + 32768) >> 16);
57       assert(v >= 0 && v <= UINT8_MAX);
58       const int lut_index = (point_value[i] + x) << index_shift;
59       scaling_lut[lut_index] = v;
60     }
61   }
62   const int16_t last_point_value = point_value[num_points - 1];
63   const int x_base = last_point_value << index_shift;
64   Memset(&scaling_lut[x_base], point_scaling[num_points - 1],
65          scaling_lut_length - x_base);
66   // Fill in the gaps.
67   if (bitdepth == kBitdepth10) {
68     for (int x = 4; x < x_base + 4; x += 4) {
69       const int start = scaling_lut[x - 4];
70       const int end = scaling_lut[x];
71       const int delta = end - start;
72       scaling_lut[x - 3] = start + RightShiftWithRounding(delta, 2);
73       scaling_lut[x - 2] = start + RightShiftWithRounding(2 * delta, 2);
74       scaling_lut[x - 1] = start + RightShiftWithRounding(3 * delta, 2);
75     }
76   }
77 }
78 
79 // Section 7.18.3.5.
80 template <int bitdepth>
ScaleLut(const int16_t * scaling_lut,int index)81 int ScaleLut(const int16_t* scaling_lut, int index) {
82   if (bitdepth <= kBitdepth10) {
83     assert(index < kScalingLookupTableSize << (bitdepth - 2));
84     return scaling_lut[index];
85   }
86   // Performs a piecewise linear interpolation into the scaling table.
87   const int shift = bitdepth - kBitdepth8;
88   const int quotient = index >> shift;
89   const int remainder = index - (quotient << shift);
90   assert(quotient + 1 < kScalingLookupTableSize);
91   const int start = scaling_lut[quotient];
92   const int end = scaling_lut[quotient + 1];
93   return start + RightShiftWithRounding((end - start) * remainder, shift);
94 }
95 
96 // Applies an auto-regressive filter to the white noise in luma_grain.
97 template <int bitdepth, typename GrainType>
ApplyAutoRegressiveFilterToLumaGrain_C(const FilmGrainParams & params,void * luma_grain_buffer)98 void ApplyAutoRegressiveFilterToLumaGrain_C(const FilmGrainParams& params,
99                                             void* luma_grain_buffer) {
100   auto* luma_grain = static_cast<GrainType*>(luma_grain_buffer);
101   const int grain_min = GetGrainMin<bitdepth>();
102   const int grain_max = GetGrainMax<bitdepth>();
103   const int auto_regression_coeff_lag = params.auto_regression_coeff_lag;
104   assert(auto_regression_coeff_lag > 0 && auto_regression_coeff_lag <= 3);
105   // A pictorial representation of the auto-regressive filter for various values
106   // of auto_regression_coeff_lag. The letter 'O' represents the current sample.
107   // (The filter always operates on the current sample with filter
108   // coefficient 1.) The letters 'X' represent the neighboring samples that the
109   // filter operates on.
110   //
111   // auto_regression_coeff_lag == 3:
112   //   X X X X X X X
113   //   X X X X X X X
114   //   X X X X X X X
115   //   X X X O
116   // auto_regression_coeff_lag == 2:
117   //     X X X X X
118   //     X X X X X
119   //     X X O
120   // auto_regression_coeff_lag == 1:
121   //       X X X
122   //       X O
123   // auto_regression_coeff_lag == 0:
124   //         O
125   //
126   // Note that if auto_regression_coeff_lag is 0, the filter is the identity
127   // filter and therefore can be skipped. This implementation assumes it is not
128   // called in that case.
129   const int shift = params.auto_regression_shift;
130   for (int y = kAutoRegressionBorder; y < kLumaHeight; ++y) {
131     for (int x = kAutoRegressionBorder; x < kLumaWidth - kAutoRegressionBorder;
132          ++x) {
133       int sum = 0;
134       int pos = 0;
135       int delta_row = -auto_regression_coeff_lag;
136       // The last iteration (delta_row == 0) is shorter and is handled
137       // separately.
138       do {
139         int delta_column = -auto_regression_coeff_lag;
140         do {
141           const int coeff = params.auto_regression_coeff_y[pos];
142           sum += luma_grain[(y + delta_row) * kLumaWidth + (x + delta_column)] *
143                  coeff;
144           ++pos;
145         } while (++delta_column <= auto_regression_coeff_lag);
146       } while (++delta_row < 0);
147       // Last iteration: delta_row == 0.
148       {
149         int delta_column = -auto_regression_coeff_lag;
150         do {
151           const int coeff = params.auto_regression_coeff_y[pos];
152           sum += luma_grain[y * kLumaWidth + (x + delta_column)] * coeff;
153           ++pos;
154         } while (++delta_column < 0);
155       }
156       luma_grain[y * kLumaWidth + x] = Clip3(
157           luma_grain[y * kLumaWidth + x] + RightShiftWithRounding(sum, shift),
158           grain_min, grain_max);
159     }
160   }
161 }
162 
163 template <int bitdepth, typename GrainType, int auto_regression_coeff_lag,
164           bool use_luma>
ApplyAutoRegressiveFilterToChromaGrains_C(const FilmGrainParams & params,const void * LIBGAV1_RESTRICT luma_grain_buffer,int subsampling_x,int subsampling_y,void * LIBGAV1_RESTRICT u_grain_buffer,void * LIBGAV1_RESTRICT v_grain_buffer)165 void ApplyAutoRegressiveFilterToChromaGrains_C(
166     const FilmGrainParams& params,
167     const void* LIBGAV1_RESTRICT luma_grain_buffer, int subsampling_x,
168     int subsampling_y, void* LIBGAV1_RESTRICT u_grain_buffer,
169     void* LIBGAV1_RESTRICT v_grain_buffer) {
170   static_assert(
171       auto_regression_coeff_lag >= 0 && auto_regression_coeff_lag <= 3,
172       "Unsupported autoregression lag for chroma.");
173   const auto* luma_grain = static_cast<const GrainType*>(luma_grain_buffer);
174   const int grain_min = GetGrainMin<bitdepth>();
175   const int grain_max = GetGrainMax<bitdepth>();
176   auto* u_grain = static_cast<GrainType*>(u_grain_buffer);
177   auto* v_grain = static_cast<GrainType*>(v_grain_buffer);
178   const int shift = params.auto_regression_shift;
179   const int chroma_height =
180       (subsampling_y == 0) ? kMaxChromaHeight : kMinChromaHeight;
181   const int chroma_width =
182       (subsampling_x == 0) ? kMaxChromaWidth : kMinChromaWidth;
183   for (int y = kAutoRegressionBorder; y < chroma_height; ++y) {
184     const int luma_y =
185         ((y - kAutoRegressionBorder) << subsampling_y) + kAutoRegressionBorder;
186     for (int x = kAutoRegressionBorder;
187          x < chroma_width - kAutoRegressionBorder; ++x) {
188       int sum_u = 0;
189       int sum_v = 0;
190       int pos = 0;
191       int delta_row = -auto_regression_coeff_lag;
192       do {
193         int delta_column = -auto_regression_coeff_lag;
194         do {
195           if (delta_row == 0 && delta_column == 0) {
196             break;
197           }
198           const int coeff_u = params.auto_regression_coeff_u[pos];
199           const int coeff_v = params.auto_regression_coeff_v[pos];
200           sum_u +=
201               u_grain[(y + delta_row) * chroma_width + (x + delta_column)] *
202               coeff_u;
203           sum_v +=
204               v_grain[(y + delta_row) * chroma_width + (x + delta_column)] *
205               coeff_v;
206           ++pos;
207         } while (++delta_column <= auto_regression_coeff_lag);
208       } while (++delta_row <= 0);
209       if (use_luma) {
210         int luma = 0;
211         const int luma_x = ((x - kAutoRegressionBorder) << subsampling_x) +
212                            kAutoRegressionBorder;
213         int i = 0;
214         do {
215           int j = 0;
216           do {
217             luma += luma_grain[(luma_y + i) * kLumaWidth + (luma_x + j)];
218           } while (++j <= subsampling_x);
219         } while (++i <= subsampling_y);
220         luma = SubsampledValue(luma, subsampling_x + subsampling_y);
221         const int coeff_u = params.auto_regression_coeff_u[pos];
222         const int coeff_v = params.auto_regression_coeff_v[pos];
223         sum_u += luma * coeff_u;
224         sum_v += luma * coeff_v;
225       }
226       u_grain[y * chroma_width + x] = Clip3(
227           u_grain[y * chroma_width + x] + RightShiftWithRounding(sum_u, shift),
228           grain_min, grain_max);
229       v_grain[y * chroma_width + x] = Clip3(
230           v_grain[y * chroma_width + x] + RightShiftWithRounding(sum_v, shift),
231           grain_min, grain_max);
232     }
233   }
234 }
235 
236 // This implementation is for the condition overlap_flag == false.
237 template <int bitdepth, typename GrainType>
ConstructNoiseStripes_C(const void * LIBGAV1_RESTRICT grain_buffer,int grain_seed,int width,int height,int subsampling_x,int subsampling_y,void * LIBGAV1_RESTRICT noise_stripes_buffer)238 void ConstructNoiseStripes_C(const void* LIBGAV1_RESTRICT grain_buffer,
239                              int grain_seed, int width, int height,
240                              int subsampling_x, int subsampling_y,
241                              void* LIBGAV1_RESTRICT noise_stripes_buffer) {
242   auto* noise_stripes =
243       static_cast<Array2DView<GrainType>*>(noise_stripes_buffer);
244   const auto* grain = static_cast<const GrainType*>(grain_buffer);
245   const int half_width = DivideBy2(width + 1);
246   const int half_height = DivideBy2(height + 1);
247   assert(half_width > 0);
248   assert(half_height > 0);
249   static_assert(kLumaWidth == kMaxChromaWidth,
250                 "kLumaWidth width should be equal to kMaxChromaWidth");
251   const int grain_width =
252       (subsampling_x == 0) ? kMaxChromaWidth : kMinChromaWidth;
253   const int plane_width = (width + subsampling_x) >> subsampling_x;
254   constexpr int kNoiseStripeHeight = 34;
255   int luma_num = 0;
256   int y = 0;
257   do {
258     GrainType* const noise_stripe = (*noise_stripes)[luma_num];
259     uint16_t seed = grain_seed;
260     seed ^= ((luma_num * 37 + 178) & 255) << 8;
261     seed ^= ((luma_num * 173 + 105) & 255);
262     int x = 0;
263     do {
264       const int rand = GetFilmGrainRandomNumber(8, &seed);
265       const int offset_x = rand >> 4;
266       const int offset_y = rand & 15;
267       const int plane_offset_x =
268           (subsampling_x != 0) ? 6 + offset_x : 9 + offset_x * 2;
269       const int plane_offset_y =
270           (subsampling_y != 0) ? 6 + offset_y : 9 + offset_y * 2;
271       int i = 0;
272       do {
273         // Section 7.18.3.5 says:
274         //   noiseStripe[ lumaNum ][ 0 ] is 34 samples high and w samples
275         //   wide (a few additional samples across are actually written to
276         //   the array, but these are never read) ...
277         //
278         // Note: The warning in the parentheses also applies to
279         // noiseStripe[ lumaNum ][ 1 ] and noiseStripe[ lumaNum ][ 2 ].
280         //
281         // Writes beyond the width of each row could happen below. To
282         // prevent those writes, we clip the number of pixels to copy against
283         // the remaining width.
284         const int copy_size =
285             std::min(kNoiseStripeHeight >> subsampling_x,
286                      plane_width - (x << (1 - subsampling_x)));
287         memcpy(&noise_stripe[i * plane_width + (x << (1 - subsampling_x))],
288                &grain[(plane_offset_y + i) * grain_width + plane_offset_x],
289                copy_size * sizeof(noise_stripe[0]));
290       } while (++i < (kNoiseStripeHeight >> subsampling_y));
291       x += 16;
292     } while (x < half_width);
293 
294     ++luma_num;
295     y += 16;
296   } while (y < half_height);
297 }
298 
299 // This implementation is for the condition overlap_flag == true.
300 template <int bitdepth, typename GrainType>
ConstructNoiseStripesWithOverlap_C(const void * LIBGAV1_RESTRICT grain_buffer,int grain_seed,int width,int height,int subsampling_x,int subsampling_y,void * LIBGAV1_RESTRICT noise_stripes_buffer)301 void ConstructNoiseStripesWithOverlap_C(
302     const void* LIBGAV1_RESTRICT grain_buffer, int grain_seed, int width,
303     int height, int subsampling_x, int subsampling_y,
304     void* LIBGAV1_RESTRICT noise_stripes_buffer) {
305   auto* noise_stripes =
306       static_cast<Array2DView<GrainType>*>(noise_stripes_buffer);
307   const auto* grain = static_cast<const GrainType*>(grain_buffer);
308   const int half_width = DivideBy2(width + 1);
309   const int half_height = DivideBy2(height + 1);
310   assert(half_width > 0);
311   assert(half_height > 0);
312   static_assert(kLumaWidth == kMaxChromaWidth,
313                 "kLumaWidth width should be equal to kMaxChromaWidth");
314   const int grain_width =
315       (subsampling_x == 0) ? kMaxChromaWidth : kMinChromaWidth;
316   const int plane_width = (width + subsampling_x) >> subsampling_x;
317   constexpr int kNoiseStripeHeight = 34;
318   int luma_num = 0;
319   int y = 0;
320   do {
321     GrainType* const noise_stripe = (*noise_stripes)[luma_num];
322     uint16_t seed = grain_seed;
323     seed ^= ((luma_num * 37 + 178) & 255) << 8;
324     seed ^= ((luma_num * 173 + 105) & 255);
325     // Begin special iteration for x == 0.
326     const int rand = GetFilmGrainRandomNumber(8, &seed);
327     const int offset_x = rand >> 4;
328     const int offset_y = rand & 15;
329     const int plane_offset_x =
330         (subsampling_x != 0) ? 6 + offset_x : 9 + offset_x * 2;
331     const int plane_offset_y =
332         (subsampling_y != 0) ? 6 + offset_y : 9 + offset_y * 2;
333     // The overlap computation only occurs when x > 0, so it is omitted here.
334     int i = 0;
335     do {
336       const int copy_size =
337           std::min(kNoiseStripeHeight >> subsampling_x, plane_width);
338       memcpy(&noise_stripe[i * plane_width],
339              &grain[(plane_offset_y + i) * grain_width + plane_offset_x],
340              copy_size * sizeof(noise_stripe[0]));
341     } while (++i < (kNoiseStripeHeight >> subsampling_y));
342     // End special iteration for x == 0.
343     for (int x = 16; x < half_width; x += 16) {
344       const int rand = GetFilmGrainRandomNumber(8, &seed);
345       const int offset_x = rand >> 4;
346       const int offset_y = rand & 15;
347       const int plane_offset_x =
348           (subsampling_x != 0) ? 6 + offset_x : 9 + offset_x * 2;
349       const int plane_offset_y =
350           (subsampling_y != 0) ? 6 + offset_y : 9 + offset_y * 2;
351       int i = 0;
352       do {
353         int j = 0;
354         int grain_sample =
355             grain[(plane_offset_y + i) * grain_width + plane_offset_x];
356         // The first pixel(s) of each segment of the noise_stripe are subject to
357         // the "overlap" computation.
358         if (subsampling_x == 0) {
359           // Corresponds to the line in the spec:
360           // if (j < 2 && x > 0)
361           // j = 0
362           int old = noise_stripe[i * plane_width + x * 2];
363           grain_sample = old * 27 + grain_sample * 17;
364           grain_sample =
365               Clip3(RightShiftWithRounding(grain_sample, 5),
366                     GetGrainMin<bitdepth>(), GetGrainMax<bitdepth>());
367           noise_stripe[i * plane_width + x * 2] = grain_sample;
368 
369           // This check prevents overwriting for the iteration j = 1. The
370           // continue applies to the i-loop.
371           if (x * 2 + 1 >= plane_width) continue;
372           // j = 1
373           grain_sample =
374               grain[(plane_offset_y + i) * grain_width + plane_offset_x + 1];
375           old = noise_stripe[i * plane_width + x * 2 + 1];
376           grain_sample = old * 17 + grain_sample * 27;
377           grain_sample =
378               Clip3(RightShiftWithRounding(grain_sample, 5),
379                     GetGrainMin<bitdepth>(), GetGrainMax<bitdepth>());
380           noise_stripe[i * plane_width + x * 2 + 1] = grain_sample;
381           j = 2;
382         } else {
383           // Corresponds to the line in the spec:
384           // if (j == 0 && x > 0)
385           const int old = noise_stripe[i * plane_width + x];
386           grain_sample = old * 23 + grain_sample * 22;
387           grain_sample =
388               Clip3(RightShiftWithRounding(grain_sample, 5),
389                     GetGrainMin<bitdepth>(), GetGrainMax<bitdepth>());
390           noise_stripe[i * plane_width + x] = grain_sample;
391           j = 1;
392         }
393         // The following covers the rest of the loop over j as described in the
394         // spec.
395         //
396         // Section 7.18.3.5 says:
397         //   noiseStripe[ lumaNum ][ 0 ] is 34 samples high and w samples
398         //   wide (a few additional samples across are actually written to
399         //   the array, but these are never read) ...
400         //
401         // Note: The warning in the parentheses also applies to
402         // noiseStripe[ lumaNum ][ 1 ] and noiseStripe[ lumaNum ][ 2 ].
403         //
404         // Writes beyond the width of each row could happen below. To
405         // prevent those writes, we clip the number of pixels to copy against
406         // the remaining width.
407         const int copy_size =
408             std::min(kNoiseStripeHeight >> subsampling_x,
409                      plane_width - (x << (1 - subsampling_x))) -
410             j;
411         memcpy(&noise_stripe[i * plane_width + (x << (1 - subsampling_x)) + j],
412                &grain[(plane_offset_y + i) * grain_width + plane_offset_x + j],
413                copy_size * sizeof(noise_stripe[0]));
414       } while (++i < (kNoiseStripeHeight >> subsampling_y));
415     }
416 
417     ++luma_num;
418     y += 16;
419   } while (y < half_height);
420 }
421 
422 template <int bitdepth, typename GrainType>
WriteOverlapLine_C(const GrainType * LIBGAV1_RESTRICT noise_stripe_row,const GrainType * LIBGAV1_RESTRICT noise_stripe_row_prev,int plane_width,int grain_coeff,int old_coeff,GrainType * LIBGAV1_RESTRICT noise_image_row)423 inline void WriteOverlapLine_C(
424     const GrainType* LIBGAV1_RESTRICT noise_stripe_row,
425     const GrainType* LIBGAV1_RESTRICT noise_stripe_row_prev, int plane_width,
426     int grain_coeff, int old_coeff,
427     GrainType* LIBGAV1_RESTRICT noise_image_row) {
428   int x = 0;
429   do {
430     int grain = noise_stripe_row[x];
431     const int old = noise_stripe_row_prev[x];
432     grain = old * old_coeff + grain * grain_coeff;
433     grain = Clip3(RightShiftWithRounding(grain, 5), GetGrainMin<bitdepth>(),
434                   GetGrainMax<bitdepth>());
435     noise_image_row[x] = grain;
436   } while (++x < plane_width);
437 }
438 
439 template <int bitdepth, typename GrainType>
ConstructNoiseImageOverlap_C(const void * LIBGAV1_RESTRICT noise_stripes_buffer,int width,int height,int subsampling_x,int subsampling_y,void * LIBGAV1_RESTRICT noise_image_buffer)440 void ConstructNoiseImageOverlap_C(
441     const void* LIBGAV1_RESTRICT noise_stripes_buffer, int width, int height,
442     int subsampling_x, int subsampling_y,
443     void* LIBGAV1_RESTRICT noise_image_buffer) {
444   const auto* noise_stripes =
445       static_cast<const Array2DView<GrainType>*>(noise_stripes_buffer);
446   auto* noise_image = static_cast<Array2D<GrainType>*>(noise_image_buffer);
447   const int plane_width = (width + subsampling_x) >> subsampling_x;
448   const int plane_height = (height + subsampling_y) >> subsampling_y;
449   const int stripe_height = 32 >> subsampling_y;
450   const int stripe_mask = stripe_height - 1;
451   int y = stripe_height;
452   int luma_num = 1;
453   if (subsampling_y == 0) {
454     // Begin complete stripes section. This is when we are guaranteed to have
455     // two overlap rows in each stripe.
456     for (; y < (plane_height & ~stripe_mask); ++luma_num, y += stripe_height) {
457       const GrainType* noise_stripe = (*noise_stripes)[luma_num];
458       const GrainType* noise_stripe_prev = (*noise_stripes)[luma_num - 1];
459       // First overlap row.
460       WriteOverlapLine_C<bitdepth>(noise_stripe,
461                                    &noise_stripe_prev[32 * plane_width],
462                                    plane_width, 17, 27, (*noise_image)[y]);
463       // Second overlap row.
464       WriteOverlapLine_C<bitdepth>(&noise_stripe[plane_width],
465                                    &noise_stripe_prev[(32 + 1) * plane_width],
466                                    plane_width, 27, 17, (*noise_image)[y + 1]);
467     }
468     // End complete stripes section.
469 
470     const int remaining_height = plane_height - y;
471     // Either one partial stripe remains (remaining_height  > 0),
472     // OR image is less than one stripe high (remaining_height < 0),
473     // OR all stripes are completed (remaining_height == 0).
474     if (remaining_height <= 0) {
475       return;
476     }
477     const GrainType* noise_stripe = (*noise_stripes)[luma_num];
478     const GrainType* noise_stripe_prev = (*noise_stripes)[luma_num - 1];
479     WriteOverlapLine_C<bitdepth>(noise_stripe,
480                                  &noise_stripe_prev[32 * plane_width],
481                                  plane_width, 17, 27, (*noise_image)[y]);
482 
483     // Check if second overlap row is in the image.
484     if (remaining_height > 1) {
485       WriteOverlapLine_C<bitdepth>(&noise_stripe[plane_width],
486                                    &noise_stripe_prev[(32 + 1) * plane_width],
487                                    plane_width, 27, 17, (*noise_image)[y + 1]);
488     }
489   } else {  // |subsampling_y| == 1
490     // No special checks needed for partial stripes, because if one exists, the
491     // first and only overlap row is guaranteed to exist.
492     for (; y < plane_height; ++luma_num, y += stripe_height) {
493       const GrainType* noise_stripe = (*noise_stripes)[luma_num];
494       const GrainType* noise_stripe_prev = (*noise_stripes)[luma_num - 1];
495       WriteOverlapLine_C<bitdepth>(noise_stripe,
496                                    &noise_stripe_prev[16 * plane_width],
497                                    plane_width, 22, 23, (*noise_image)[y]);
498     }
499   }
500 }
501 
502 template <int bitdepth, typename GrainType, typename Pixel>
BlendNoiseWithImageLuma_C(const void * LIBGAV1_RESTRICT noise_image_ptr,int min_value,int max_luma,int scaling_shift,int width,int height,int start_height,const int16_t * scaling_lut_y,const void * source_plane_y,ptrdiff_t source_stride_y,void * dest_plane_y,ptrdiff_t dest_stride_y)503 void BlendNoiseWithImageLuma_C(const void* LIBGAV1_RESTRICT noise_image_ptr,
504                                int min_value, int max_luma, int scaling_shift,
505                                int width, int height, int start_height,
506                                const int16_t* scaling_lut_y,
507                                const void* source_plane_y,
508                                ptrdiff_t source_stride_y, void* dest_plane_y,
509                                ptrdiff_t dest_stride_y) {
510   const auto* noise_image =
511       static_cast<const Array2D<GrainType>*>(noise_image_ptr);
512   const auto* in_y = static_cast<const Pixel*>(source_plane_y);
513   source_stride_y /= sizeof(Pixel);
514   auto* out_y = static_cast<Pixel*>(dest_plane_y);
515   dest_stride_y /= sizeof(Pixel);
516 
517   int y = 0;
518   do {
519     int x = 0;
520     do {
521       const int orig = in_y[y * source_stride_y + x];
522       int noise = noise_image[kPlaneY][y + start_height][x];
523       noise = RightShiftWithRounding(
524           ScaleLut<bitdepth>(scaling_lut_y, orig) * noise, scaling_shift);
525       out_y[y * dest_stride_y + x] = Clip3(orig + noise, min_value, max_luma);
526     } while (++x < width);
527   } while (++y < height);
528 }
529 
530 // This function is for the case params_.chroma_scaling_from_luma == false.
531 template <int bitdepth, typename GrainType, typename Pixel>
BlendNoiseWithImageChroma_C(Plane plane,const FilmGrainParams & params,const void * LIBGAV1_RESTRICT noise_image_ptr,int min_value,int max_chroma,int width,int height,int start_height,int subsampling_x,int subsampling_y,const int16_t * scaling_lut_uv,const void * source_plane_y,ptrdiff_t source_stride_y,const void * source_plane_uv,ptrdiff_t source_stride_uv,void * dest_plane_uv,ptrdiff_t dest_stride_uv)532 void BlendNoiseWithImageChroma_C(
533     Plane plane, const FilmGrainParams& params,
534     const void* LIBGAV1_RESTRICT noise_image_ptr, int min_value, int max_chroma,
535     int width, int height, int start_height, int subsampling_x,
536     int subsampling_y, const int16_t* scaling_lut_uv,
537     const void* source_plane_y, ptrdiff_t source_stride_y,
538     const void* source_plane_uv, ptrdiff_t source_stride_uv,
539     void* dest_plane_uv, ptrdiff_t dest_stride_uv) {
540   const auto* noise_image =
541       static_cast<const Array2D<GrainType>*>(noise_image_ptr);
542 
543   const int chroma_width = (width + subsampling_x) >> subsampling_x;
544   const int chroma_height = (height + subsampling_y) >> subsampling_y;
545 
546   const auto* in_y = static_cast<const Pixel*>(source_plane_y);
547   source_stride_y /= sizeof(Pixel);
548   const auto* in_uv = static_cast<const Pixel*>(source_plane_uv);
549   source_stride_uv /= sizeof(Pixel);
550   auto* out_uv = static_cast<Pixel*>(dest_plane_uv);
551   dest_stride_uv /= sizeof(Pixel);
552 
553   const int offset = (plane == kPlaneU) ? params.u_offset : params.v_offset;
554   const int luma_multiplier =
555       (plane == kPlaneU) ? params.u_luma_multiplier : params.v_luma_multiplier;
556   const int multiplier =
557       (plane == kPlaneU) ? params.u_multiplier : params.v_multiplier;
558 
559   const int scaling_shift = params.chroma_scaling;
560   start_height >>= subsampling_y;
561   int y = 0;
562   do {
563     int x = 0;
564     do {
565       const int luma_x = x << subsampling_x;
566       const int luma_y = y << subsampling_y;
567       const int luma_next_x = std::min(luma_x + 1, width - 1);
568       int average_luma;
569       if (subsampling_x != 0) {
570         average_luma = RightShiftWithRounding(
571             in_y[luma_y * source_stride_y + luma_x] +
572                 in_y[luma_y * source_stride_y + luma_next_x],
573             1);
574       } else {
575         average_luma = in_y[luma_y * source_stride_y + luma_x];
576       }
577       const int orig = in_uv[y * source_stride_uv + x];
578       const int combined = average_luma * luma_multiplier + orig * multiplier;
579       const int merged =
580           Clip3((combined >> 6) + LeftShift(offset, bitdepth - kBitdepth8), 0,
581                 (1 << bitdepth) - 1);
582       int noise = noise_image[plane][y + start_height][x];
583       noise = RightShiftWithRounding(
584           ScaleLut<bitdepth>(scaling_lut_uv, merged) * noise, scaling_shift);
585       out_uv[y * dest_stride_uv + x] =
586           Clip3(orig + noise, min_value, max_chroma);
587     } while (++x < chroma_width);
588   } while (++y < chroma_height);
589 }
590 
591 // This function is for the case params_.chroma_scaling_from_luma == true.
592 // This further implies that scaling_lut_u == scaling_lut_v == scaling_lut_y.
593 template <int bitdepth, typename GrainType, typename Pixel>
BlendNoiseWithImageChromaWithCfl_C(Plane plane,const FilmGrainParams & params,const void * LIBGAV1_RESTRICT noise_image_ptr,int min_value,int max_chroma,int width,int height,int start_height,int subsampling_x,int subsampling_y,const int16_t * scaling_lut,const void * source_plane_y,ptrdiff_t source_stride_y,const void * source_plane_uv,ptrdiff_t source_stride_uv,void * dest_plane_uv,ptrdiff_t dest_stride_uv)594 void BlendNoiseWithImageChromaWithCfl_C(
595     Plane plane, const FilmGrainParams& params,
596     const void* LIBGAV1_RESTRICT noise_image_ptr, int min_value, int max_chroma,
597     int width, int height, int start_height, int subsampling_x,
598     int subsampling_y, const int16_t* scaling_lut, const void* source_plane_y,
599     ptrdiff_t source_stride_y, const void* source_plane_uv,
600     ptrdiff_t source_stride_uv, void* dest_plane_uv, ptrdiff_t dest_stride_uv) {
601   const auto* noise_image =
602       static_cast<const Array2D<GrainType>*>(noise_image_ptr);
603   const auto* in_y = static_cast<const Pixel*>(source_plane_y);
604   source_stride_y /= sizeof(Pixel);
605   const auto* in_uv = static_cast<const Pixel*>(source_plane_uv);
606   source_stride_uv /= sizeof(Pixel);
607   auto* out_uv = static_cast<Pixel*>(dest_plane_uv);
608   dest_stride_uv /= sizeof(Pixel);
609 
610   const int chroma_width = (width + subsampling_x) >> subsampling_x;
611   const int chroma_height = (height + subsampling_y) >> subsampling_y;
612   const int scaling_shift = params.chroma_scaling;
613   start_height >>= subsampling_y;
614   int y = 0;
615   do {
616     int x = 0;
617     do {
618       const int luma_x = x << subsampling_x;
619       const int luma_y = y << subsampling_y;
620       const int luma_next_x = std::min(luma_x + 1, width - 1);
621       int average_luma;
622       if (subsampling_x != 0) {
623         average_luma = RightShiftWithRounding(
624             in_y[luma_y * source_stride_y + luma_x] +
625                 in_y[luma_y * source_stride_y + luma_next_x],
626             1);
627       } else {
628         average_luma = in_y[luma_y * source_stride_y + luma_x];
629       }
630       const int orig_uv = in_uv[y * source_stride_uv + x];
631       int noise_uv = noise_image[plane][y + start_height][x];
632       noise_uv = RightShiftWithRounding(
633           ScaleLut<bitdepth>(scaling_lut, average_luma) * noise_uv,
634           scaling_shift);
635       out_uv[y * dest_stride_uv + x] =
636           Clip3(orig_uv + noise_uv, min_value, max_chroma);
637     } while (++x < chroma_width);
638   } while (++y < chroma_height);
639 }
640 
Init8bpp()641 void Init8bpp() {
642   Dsp* const dsp = dsp_internal::GetWritableDspTable(8);
643   assert(dsp != nullptr);
644 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
645   // LumaAutoRegressionFunc
646   dsp->film_grain.luma_auto_regression[0] =
647       ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth8, int8_t>;
648   dsp->film_grain.luma_auto_regression[1] =
649       ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth8, int8_t>;
650   dsp->film_grain.luma_auto_regression[2] =
651       ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth8, int8_t>;
652 
653   // ChromaAutoRegressionFunc
654   // Chroma autoregression should never be called when lag is 0 and use_luma is
655   // false.
656   dsp->film_grain.chroma_auto_regression[0][0] = nullptr;
657   dsp->film_grain.chroma_auto_regression[0][1] =
658       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 1, false>;
659   dsp->film_grain.chroma_auto_regression[0][2] =
660       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 2, false>;
661   dsp->film_grain.chroma_auto_regression[0][3] =
662       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 3, false>;
663   dsp->film_grain.chroma_auto_regression[1][0] =
664       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 0, true>;
665   dsp->film_grain.chroma_auto_regression[1][1] =
666       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 1, true>;
667   dsp->film_grain.chroma_auto_regression[1][2] =
668       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 2, true>;
669   dsp->film_grain.chroma_auto_regression[1][3] =
670       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 3, true>;
671 
672   // ConstructNoiseStripesFunc
673   dsp->film_grain.construct_noise_stripes[0] =
674       ConstructNoiseStripes_C<kBitdepth8, int8_t>;
675   dsp->film_grain.construct_noise_stripes[1] =
676       ConstructNoiseStripesWithOverlap_C<kBitdepth8, int8_t>;
677 
678   // ConstructNoiseImageOverlapFunc
679   dsp->film_grain.construct_noise_image_overlap =
680       ConstructNoiseImageOverlap_C<kBitdepth8, int8_t>;
681 
682   // InitializeScalingLutFunc
683   dsp->film_grain.initialize_scaling_lut =
684       InitializeScalingLookupTable_C<kBitdepth8>;
685 
686   // BlendNoiseWithImageLumaFunc
687   dsp->film_grain.blend_noise_luma =
688       BlendNoiseWithImageLuma_C<kBitdepth8, int8_t, uint8_t>;
689 
690   // BlendNoiseWithImageChromaFunc
691   dsp->film_grain.blend_noise_chroma[0] =
692       BlendNoiseWithImageChroma_C<kBitdepth8, int8_t, uint8_t>;
693   dsp->film_grain.blend_noise_chroma[1] =
694       BlendNoiseWithImageChromaWithCfl_C<kBitdepth8, int8_t, uint8_t>;
695 #else  // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
696   static_cast<void>(dsp);
697 #ifndef LIBGAV1_Dsp8bpp_FilmGrainAutoregressionLuma
698   dsp->film_grain.luma_auto_regression[0] =
699       ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth8, int8_t>;
700   dsp->film_grain.luma_auto_regression[1] =
701       ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth8, int8_t>;
702   dsp->film_grain.luma_auto_regression[2] =
703       ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth8, int8_t>;
704 #endif
705 #ifndef LIBGAV1_Dsp8bpp_FilmGrainAutoregressionChroma
706   // Chroma autoregression should never be called when lag is 0 and use_luma is
707   // false.
708   dsp->film_grain.chroma_auto_regression[0][0] = nullptr;
709   dsp->film_grain.chroma_auto_regression[0][1] =
710       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 1, false>;
711   dsp->film_grain.chroma_auto_regression[0][2] =
712       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 2, false>;
713   dsp->film_grain.chroma_auto_regression[0][3] =
714       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 3, false>;
715   dsp->film_grain.chroma_auto_regression[1][0] =
716       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 0, true>;
717   dsp->film_grain.chroma_auto_regression[1][1] =
718       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 1, true>;
719   dsp->film_grain.chroma_auto_regression[1][2] =
720       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 2, true>;
721   dsp->film_grain.chroma_auto_regression[1][3] =
722       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 3, true>;
723 #endif
724 #ifndef LIBGAV1_Dsp8bpp_FilmGrainConstructNoiseStripes
725   dsp->film_grain.construct_noise_stripes[0] =
726       ConstructNoiseStripes_C<kBitdepth8, int8_t>;
727   dsp->film_grain.construct_noise_stripes[1] =
728       ConstructNoiseStripesWithOverlap_C<kBitdepth8, int8_t>;
729 #endif
730 #ifndef LIBGAV1_Dsp8bpp_FilmGrainConstructNoiseImageOverlap
731   dsp->film_grain.construct_noise_image_overlap =
732       ConstructNoiseImageOverlap_C<kBitdepth8, int8_t>;
733 #endif
734 #ifndef LIBGAV1_Dsp8bpp_FilmGrainInitializeScalingLutFunc
735   dsp->film_grain.initialize_scaling_lut =
736       InitializeScalingLookupTable_C<kBitdepth8>;
737 #endif
738 #ifndef LIBGAV1_Dsp8bpp_FilmGrainBlendNoiseLuma
739   dsp->film_grain.blend_noise_luma =
740       BlendNoiseWithImageLuma_C<kBitdepth8, int8_t, uint8_t>;
741 #endif
742 #ifndef LIBGAV1_Dsp8bpp_FilmGrainBlendNoiseChroma
743   dsp->film_grain.blend_noise_chroma[0] =
744       BlendNoiseWithImageChroma_C<kBitdepth8, int8_t, uint8_t>;
745 #endif
746 #ifndef LIBGAV1_Dsp8bpp_FilmGrainBlendNoiseChromaWithCfl
747   dsp->film_grain.blend_noise_chroma[1] =
748       BlendNoiseWithImageChromaWithCfl_C<kBitdepth8, int8_t, uint8_t>;
749 #endif
750 #endif  // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
751 }
752 
753 #if LIBGAV1_MAX_BITDEPTH >= 10
Init10bpp()754 void Init10bpp() {
755   Dsp* const dsp = dsp_internal::GetWritableDspTable(10);
756   assert(dsp != nullptr);
757 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
758 
759   // LumaAutoRegressionFunc
760   dsp->film_grain.luma_auto_regression[0] =
761       ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth10, int16_t>;
762   dsp->film_grain.luma_auto_regression[1] =
763       ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth10, int16_t>;
764   dsp->film_grain.luma_auto_regression[2] =
765       ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth10, int16_t>;
766 
767   // ChromaAutoRegressionFunc
768   // Chroma autoregression should never be called when lag is 0 and use_luma is
769   // false.
770   dsp->film_grain.chroma_auto_regression[0][0] = nullptr;
771   dsp->film_grain.chroma_auto_regression[0][1] =
772       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 1, false>;
773   dsp->film_grain.chroma_auto_regression[0][2] =
774       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 2, false>;
775   dsp->film_grain.chroma_auto_regression[0][3] =
776       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 3, false>;
777   dsp->film_grain.chroma_auto_regression[1][0] =
778       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 0, true>;
779   dsp->film_grain.chroma_auto_regression[1][1] =
780       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 1, true>;
781   dsp->film_grain.chroma_auto_regression[1][2] =
782       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 2, true>;
783   dsp->film_grain.chroma_auto_regression[1][3] =
784       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 3, true>;
785 
786   // ConstructNoiseStripesFunc
787   dsp->film_grain.construct_noise_stripes[0] =
788       ConstructNoiseStripes_C<kBitdepth10, int16_t>;
789   dsp->film_grain.construct_noise_stripes[1] =
790       ConstructNoiseStripesWithOverlap_C<kBitdepth10, int16_t>;
791 
792   // ConstructNoiseImageOverlapFunc
793   dsp->film_grain.construct_noise_image_overlap =
794       ConstructNoiseImageOverlap_C<kBitdepth10, int16_t>;
795 
796   // InitializeScalingLutFunc
797   dsp->film_grain.initialize_scaling_lut =
798       InitializeScalingLookupTable_C<kBitdepth10>;
799 
800   // BlendNoiseWithImageLumaFunc
801   dsp->film_grain.blend_noise_luma =
802       BlendNoiseWithImageLuma_C<kBitdepth10, int16_t, uint16_t>;
803 
804   // BlendNoiseWithImageChromaFunc
805   dsp->film_grain.blend_noise_chroma[0] =
806       BlendNoiseWithImageChroma_C<kBitdepth10, int16_t, uint16_t>;
807   dsp->film_grain.blend_noise_chroma[1] =
808       BlendNoiseWithImageChromaWithCfl_C<kBitdepth10, int16_t, uint16_t>;
809 #else  // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
810   static_cast<void>(dsp);
811 #ifndef LIBGAV1_Dsp10bpp_FilmGrainAutoregressionLuma
812   dsp->film_grain.luma_auto_regression[0] =
813       ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth10, int16_t>;
814   dsp->film_grain.luma_auto_regression[1] =
815       ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth10, int16_t>;
816   dsp->film_grain.luma_auto_regression[2] =
817       ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth10, int16_t>;
818 #endif
819 #ifndef LIBGAV1_Dsp10bpp_FilmGrainAutoregressionChroma
820   // Chroma autoregression should never be called when lag is 0 and use_luma is
821   // false.
822   dsp->film_grain.chroma_auto_regression[0][0] = nullptr;
823   dsp->film_grain.chroma_auto_regression[0][1] =
824       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 1, false>;
825   dsp->film_grain.chroma_auto_regression[0][2] =
826       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 2, false>;
827   dsp->film_grain.chroma_auto_regression[0][3] =
828       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 3, false>;
829   dsp->film_grain.chroma_auto_regression[1][0] =
830       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 0, true>;
831   dsp->film_grain.chroma_auto_regression[1][1] =
832       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 1, true>;
833   dsp->film_grain.chroma_auto_regression[1][2] =
834       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 2, true>;
835   dsp->film_grain.chroma_auto_regression[1][3] =
836       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 3, true>;
837 #endif
838 #ifndef LIBGAV1_Dsp10bpp_FilmGrainConstructNoiseStripes
839   dsp->film_grain.construct_noise_stripes[0] =
840       ConstructNoiseStripes_C<kBitdepth10, int16_t>;
841   dsp->film_grain.construct_noise_stripes[1] =
842       ConstructNoiseStripesWithOverlap_C<kBitdepth10, int16_t>;
843 #endif
844 #ifndef LIBGAV1_Dsp10bpp_FilmGrainConstructNoiseImageOverlap
845   dsp->film_grain.construct_noise_image_overlap =
846       ConstructNoiseImageOverlap_C<kBitdepth10, int16_t>;
847 #endif
848 #ifndef LIBGAV1_Dsp10bpp_FilmGrainInitializeScalingLutFunc
849   dsp->film_grain.initialize_scaling_lut =
850       InitializeScalingLookupTable_C<kBitdepth10>;
851 #endif
852 #ifndef LIBGAV1_Dsp10bpp_FilmGrainBlendNoiseLuma
853   dsp->film_grain.blend_noise_luma =
854       BlendNoiseWithImageLuma_C<kBitdepth10, int16_t, uint16_t>;
855 #endif
856 #ifndef LIBGAV1_Dsp10bpp_FilmGrainBlendNoiseChroma
857   dsp->film_grain.blend_noise_chroma[0] =
858       BlendNoiseWithImageChroma_C<kBitdepth10, int16_t, uint16_t>;
859 #endif
860 #ifndef LIBGAV1_Dsp10bpp_FilmGrainBlendNoiseChromaWithCfl
861   dsp->film_grain.blend_noise_chroma[1] =
862       BlendNoiseWithImageChromaWithCfl_C<kBitdepth10, int16_t, uint16_t>;
863 #endif
864 #endif  // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
865 }
866 #endif  // LIBGAV1_MAX_BITDEPTH >= 10
867 
868 #if LIBGAV1_MAX_BITDEPTH == 12
Init12bpp()869 void Init12bpp() {
870   Dsp* const dsp = dsp_internal::GetWritableDspTable(12);
871   assert(dsp != nullptr);
872 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
873 
874   // LumaAutoRegressionFunc
875   dsp->film_grain.luma_auto_regression[0] =
876       ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth12, int16_t>;
877   dsp->film_grain.luma_auto_regression[1] =
878       ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth12, int16_t>;
879   dsp->film_grain.luma_auto_regression[2] =
880       ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth12, int16_t>;
881 
882   // ChromaAutoRegressionFunc
883   // Chroma autoregression should never be called when lag is 0 and use_luma is
884   // false.
885   dsp->film_grain.chroma_auto_regression[0][0] = nullptr;
886   dsp->film_grain.chroma_auto_regression[0][1] =
887       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 1, false>;
888   dsp->film_grain.chroma_auto_regression[0][2] =
889       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 2, false>;
890   dsp->film_grain.chroma_auto_regression[0][3] =
891       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 3, false>;
892   dsp->film_grain.chroma_auto_regression[1][0] =
893       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 0, true>;
894   dsp->film_grain.chroma_auto_regression[1][1] =
895       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 1, true>;
896   dsp->film_grain.chroma_auto_regression[1][2] =
897       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 2, true>;
898   dsp->film_grain.chroma_auto_regression[1][3] =
899       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 3, true>;
900 
901   // ConstructNoiseStripesFunc
902   dsp->film_grain.construct_noise_stripes[0] =
903       ConstructNoiseStripes_C<kBitdepth12, int16_t>;
904   dsp->film_grain.construct_noise_stripes[1] =
905       ConstructNoiseStripesWithOverlap_C<kBitdepth12, int16_t>;
906 
907   // ConstructNoiseImageOverlapFunc
908   dsp->film_grain.construct_noise_image_overlap =
909       ConstructNoiseImageOverlap_C<kBitdepth12, int16_t>;
910 
911   // InitializeScalingLutFunc
912   dsp->film_grain.initialize_scaling_lut =
913       InitializeScalingLookupTable_C<kBitdepth12>;
914 
915   // BlendNoiseWithImageLumaFunc
916   dsp->film_grain.blend_noise_luma =
917       BlendNoiseWithImageLuma_C<kBitdepth12, int16_t, uint16_t>;
918 
919   // BlendNoiseWithImageChromaFunc
920   dsp->film_grain.blend_noise_chroma[0] =
921       BlendNoiseWithImageChroma_C<kBitdepth12, int16_t, uint16_t>;
922   dsp->film_grain.blend_noise_chroma[1] =
923       BlendNoiseWithImageChromaWithCfl_C<kBitdepth12, int16_t, uint16_t>;
924 #else  // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
925   static_cast<void>(dsp);
926 #ifndef LIBGAV1_Dsp12bpp_FilmGrainAutoregressionLuma
927   dsp->film_grain.luma_auto_regression[0] =
928       ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth12, int16_t>;
929   dsp->film_grain.luma_auto_regression[1] =
930       ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth12, int16_t>;
931   dsp->film_grain.luma_auto_regression[2] =
932       ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth12, int16_t>;
933 #endif
934 #ifndef LIBGAV1_Dsp12bpp_FilmGrainAutoregressionChroma
935   // Chroma autoregression should never be called when lag is 0 and use_luma is
936   // false.
937   dsp->film_grain.chroma_auto_regression[0][0] = nullptr;
938   dsp->film_grain.chroma_auto_regression[0][1] =
939       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 1, false>;
940   dsp->film_grain.chroma_auto_regression[0][2] =
941       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 2, false>;
942   dsp->film_grain.chroma_auto_regression[0][3] =
943       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 3, false>;
944   dsp->film_grain.chroma_auto_regression[1][0] =
945       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 0, true>;
946   dsp->film_grain.chroma_auto_regression[1][1] =
947       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 1, true>;
948   dsp->film_grain.chroma_auto_regression[1][2] =
949       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 2, true>;
950   dsp->film_grain.chroma_auto_regression[1][3] =
951       ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 3, true>;
952 #endif
953 #ifndef LIBGAV1_Dsp12bpp_FilmGrainConstructNoiseStripes
954   dsp->film_grain.construct_noise_stripes[0] =
955       ConstructNoiseStripes_C<kBitdepth12, int16_t>;
956   dsp->film_grain.construct_noise_stripes[1] =
957       ConstructNoiseStripesWithOverlap_C<kBitdepth12, int16_t>;
958 #endif
959 #ifndef LIBGAV1_Dsp12bpp_FilmGrainConstructNoiseImageOverlap
960   dsp->film_grain.construct_noise_image_overlap =
961       ConstructNoiseImageOverlap_C<kBitdepth12, int16_t>;
962 #endif
963 #ifndef LIBGAV1_Dsp12bpp_FilmGrainInitializeScalingLutFunc
964   dsp->film_grain.initialize_scaling_lut =
965       InitializeScalingLookupTable_C<kBitdepth12>;
966 #endif
967 #ifndef LIBGAV1_Dsp12bpp_FilmGrainBlendNoiseLuma
968   dsp->film_grain.blend_noise_luma =
969       BlendNoiseWithImageLuma_C<kBitdepth12, int16_t, uint16_t>;
970 #endif
971 #ifndef LIBGAV1_Dsp12bpp_FilmGrainBlendNoiseChroma
972   dsp->film_grain.blend_noise_chroma[0] =
973       BlendNoiseWithImageChroma_C<kBitdepth12, int16_t, uint16_t>;
974 #endif
975 #ifndef LIBGAV1_Dsp12bpp_FilmGrainBlendNoiseChromaWithCfl
976   dsp->film_grain.blend_noise_chroma[1] =
977       BlendNoiseWithImageChromaWithCfl_C<kBitdepth12, int16_t, uint16_t>;
978 #endif
979 #endif  // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
980 }
981 #endif  // LIBGAV1_MAX_BITDEPTH == 12
982 
983 }  // namespace
984 }  // namespace film_grain
985 
FilmGrainInit_C()986 void FilmGrainInit_C() {
987   film_grain::Init8bpp();
988 #if LIBGAV1_MAX_BITDEPTH >= 10
989   film_grain::Init10bpp();
990 #endif
991 #if LIBGAV1_MAX_BITDEPTH == 12
992   film_grain::Init12bpp();
993 #endif
994 }
995 
996 }  // namespace dsp
997 }  // namespace libgav1
998