xref: /aosp_15_r20/external/libgav1/src/film_grain.cc (revision 095378508e87ed692bf8dfeb34008b65b3735891)
1*09537850SAkhilesh Sanikop // Copyright 2020 The libgav1 Authors
2*09537850SAkhilesh Sanikop //
3*09537850SAkhilesh Sanikop // Licensed under the Apache License, Version 2.0 (the "License");
4*09537850SAkhilesh Sanikop // you may not use this file except in compliance with the License.
5*09537850SAkhilesh Sanikop // You may obtain a copy of the License at
6*09537850SAkhilesh Sanikop //
7*09537850SAkhilesh Sanikop //      http://www.apache.org/licenses/LICENSE-2.0
8*09537850SAkhilesh Sanikop //
9*09537850SAkhilesh Sanikop // Unless required by applicable law or agreed to in writing, software
10*09537850SAkhilesh Sanikop // distributed under the License is distributed on an "AS IS" BASIS,
11*09537850SAkhilesh Sanikop // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*09537850SAkhilesh Sanikop // See the License for the specific language governing permissions and
13*09537850SAkhilesh Sanikop // limitations under the License.
14*09537850SAkhilesh Sanikop 
15*09537850SAkhilesh Sanikop #include "src/film_grain.h"
16*09537850SAkhilesh Sanikop 
17*09537850SAkhilesh Sanikop #include <algorithm>
18*09537850SAkhilesh Sanikop #include <cassert>
19*09537850SAkhilesh Sanikop #include <cstddef>
20*09537850SAkhilesh Sanikop #include <cstdint>
21*09537850SAkhilesh Sanikop #include <cstring>
22*09537850SAkhilesh Sanikop #include <new>
23*09537850SAkhilesh Sanikop 
24*09537850SAkhilesh Sanikop #include "src/dsp/common.h"
25*09537850SAkhilesh Sanikop #include "src/dsp/constants.h"
26*09537850SAkhilesh Sanikop #include "src/dsp/dsp.h"
27*09537850SAkhilesh Sanikop #include "src/dsp/film_grain_common.h"
28*09537850SAkhilesh Sanikop #include "src/utils/array_2d.h"
29*09537850SAkhilesh Sanikop #include "src/utils/blocking_counter.h"
30*09537850SAkhilesh Sanikop #include "src/utils/common.h"
31*09537850SAkhilesh Sanikop #include "src/utils/compiler_attributes.h"
32*09537850SAkhilesh Sanikop #include "src/utils/constants.h"
33*09537850SAkhilesh Sanikop #include "src/utils/logging.h"
34*09537850SAkhilesh Sanikop #include "src/utils/threadpool.h"
35*09537850SAkhilesh Sanikop 
36*09537850SAkhilesh Sanikop namespace libgav1 {
37*09537850SAkhilesh Sanikop 
38*09537850SAkhilesh Sanikop namespace {
39*09537850SAkhilesh Sanikop 
40*09537850SAkhilesh Sanikop // The kGaussianSequence array contains random samples from a Gaussian
41*09537850SAkhilesh Sanikop // distribution with zero mean and standard deviation of about 512 clipped to
42*09537850SAkhilesh Sanikop // the range of [-2048, 2047] (representable by a signed integer using 12 bits
43*09537850SAkhilesh Sanikop // of precision) and rounded to the nearest multiple of 4.
44*09537850SAkhilesh Sanikop //
45*09537850SAkhilesh Sanikop // Note: It is important that every element in the kGaussianSequence array be
46*09537850SAkhilesh Sanikop // less than 2040, so that RightShiftWithRounding(kGaussianSequence[i], 4) is
47*09537850SAkhilesh Sanikop // less than 128 for bitdepth=8 (GrainType=int8_t).
48*09537850SAkhilesh Sanikop constexpr int16_t kGaussianSequence[/*2048*/] = {
49*09537850SAkhilesh Sanikop     56,    568,   -180,  172,   124,   -84,   172,   -64,   -900,  24,   820,
50*09537850SAkhilesh Sanikop     224,   1248,  996,   272,   -8,    -916,  -388,  -732,  -104,  -188, 800,
51*09537850SAkhilesh Sanikop     112,   -652,  -320,  -376,  140,   -252,  492,   -168,  44,    -788, 588,
52*09537850SAkhilesh Sanikop     -584,  500,   -228,  12,    680,   272,   -476,  972,   -100,  652,  368,
53*09537850SAkhilesh Sanikop     432,   -196,  -720,  -192,  1000,  -332,  652,   -136,  -552,  -604, -4,
54*09537850SAkhilesh Sanikop     192,   -220,  -136,  1000,  -52,   372,   -96,   -624,  124,   -24,  396,
55*09537850SAkhilesh Sanikop     540,   -12,   -104,  640,   464,   244,   -208,  -84,   368,   -528, -740,
56*09537850SAkhilesh Sanikop     248,   -968,  -848,  608,   376,   -60,   -292,  -40,   -156,  252,  -292,
57*09537850SAkhilesh Sanikop     248,   224,   -280,  400,   -244,  244,   -60,   76,    -80,   212,  532,
58*09537850SAkhilesh Sanikop     340,   128,   -36,   824,   -352,  -60,   -264,  -96,   -612,  416,  -704,
59*09537850SAkhilesh Sanikop     220,   -204,  640,   -160,  1220,  -408,  900,   336,   20,    -336, -96,
60*09537850SAkhilesh Sanikop     -792,  304,   48,    -28,   -1232, -1172, -448,  104,   -292,  -520, 244,
61*09537850SAkhilesh Sanikop     60,    -948,  0,     -708,  268,   108,   356,   -548,  488,   -344, -136,
62*09537850SAkhilesh Sanikop     488,   -196,  -224,  656,   -236,  -1128, 60,    4,     140,   276,  -676,
63*09537850SAkhilesh Sanikop     -376,  168,   -108,  464,   8,     564,   64,    240,   308,   -300, -400,
64*09537850SAkhilesh Sanikop     -456,  -136,  56,    120,   -408,  -116,  436,   504,   -232,  328,  844,
65*09537850SAkhilesh Sanikop     -164,  -84,   784,   -168,  232,   -224,  348,   -376,  128,   568,  96,
66*09537850SAkhilesh Sanikop     -1244, -288,  276,   848,   832,   -360,  656,   464,   -384,  -332, -356,
67*09537850SAkhilesh Sanikop     728,   -388,  160,   -192,  468,   296,   224,   140,   -776,  -100, 280,
68*09537850SAkhilesh Sanikop     4,     196,   44,    -36,   -648,  932,   16,    1428,  28,    528,  808,
69*09537850SAkhilesh Sanikop     772,   20,    268,   88,    -332,  -284,  124,   -384,  -448,  208,  -228,
70*09537850SAkhilesh Sanikop     -1044, -328,  660,   380,   -148,  -300,  588,   240,   540,   28,   136,
71*09537850SAkhilesh Sanikop     -88,   -436,  256,   296,   -1000, 1400,  0,     -48,   1056,  -136, 264,
72*09537850SAkhilesh Sanikop     -528,  -1108, 632,   -484,  -592,  -344,  796,   124,   -668,  -768, 388,
73*09537850SAkhilesh Sanikop     1296,  -232,  -188,  -200,  -288,  -4,    308,   100,   -168,  256,  -500,
74*09537850SAkhilesh Sanikop     204,   -508,  648,   -136,  372,   -272,  -120,  -1004, -552,  -548, -384,
75*09537850SAkhilesh Sanikop     548,   -296,  428,   -108,  -8,    -912,  -324,  -224,  -88,   -112, -220,
76*09537850SAkhilesh Sanikop     -100,  996,   -796,  548,   360,   -216,  180,   428,   -200,  -212, 148,
77*09537850SAkhilesh Sanikop     96,    148,   284,   216,   -412,  -320,  120,   -300,  -384,  -604, -572,
78*09537850SAkhilesh Sanikop     -332,  -8,    -180,  -176,  696,   116,   -88,   628,   76,    44,   -516,
79*09537850SAkhilesh Sanikop     240,   -208,  -40,   100,   -592,  344,   -308,  -452,  -228,  20,   916,
80*09537850SAkhilesh Sanikop     -1752, -136,  -340,  -804,  140,   40,    512,   340,   248,   184,  -492,
81*09537850SAkhilesh Sanikop     896,   -156,  932,   -628,  328,   -688,  -448,  -616,  -752,  -100, 560,
82*09537850SAkhilesh Sanikop     -1020, 180,   -800,  -64,   76,    576,   1068,  396,   660,   552,  -108,
83*09537850SAkhilesh Sanikop     -28,   320,   -628,  312,   -92,   -92,   -472,  268,   16,    560,  516,
84*09537850SAkhilesh Sanikop     -672,  -52,   492,   -100,  260,   384,   284,   292,   304,   -148, 88,
85*09537850SAkhilesh Sanikop     -152,  1012,  1064,  -228,  164,   -376,  -684,  592,   -392,  156,  196,
86*09537850SAkhilesh Sanikop     -524,  -64,   -884,  160,   -176,  636,   648,   404,   -396,  -436, 864,
87*09537850SAkhilesh Sanikop     424,   -728,  988,   -604,  904,   -592,  296,   -224,  536,   -176, -920,
88*09537850SAkhilesh Sanikop     436,   -48,   1176,  -884,  416,   -776,  -824,  -884,  524,   -548, -564,
89*09537850SAkhilesh Sanikop     -68,   -164,  -96,   692,   364,   -692,  -1012, -68,   260,   -480, 876,
90*09537850SAkhilesh Sanikop     -1116, 452,   -332,  -352,  892,   -1088, 1220,  -676,  12,    -292, 244,
91*09537850SAkhilesh Sanikop     496,   372,   -32,   280,   200,   112,   -440,  -96,   24,    -644, -184,
92*09537850SAkhilesh Sanikop     56,    -432,  224,   -980,  272,   -260,  144,   -436,  420,   356,  364,
93*09537850SAkhilesh Sanikop     -528,  76,    172,   -744,  -368,  404,   -752,  -416,  684,   -688, 72,
94*09537850SAkhilesh Sanikop     540,   416,   92,    444,   480,   -72,   -1416, 164,   -1172, -68,  24,
95*09537850SAkhilesh Sanikop     424,   264,   1040,  128,   -912,  -524,  -356,  64,    876,   -12,  4,
96*09537850SAkhilesh Sanikop     -88,   532,   272,   -524,  320,   276,   -508,  940,   24,    -400, -120,
97*09537850SAkhilesh Sanikop     756,   60,    236,   -412,  100,   376,   -484,  400,   -100,  -740, -108,
98*09537850SAkhilesh Sanikop     -260,  328,   -268,  224,   -200,  -416,  184,   -604,  -564,  -20,  296,
99*09537850SAkhilesh Sanikop     60,    892,   -888,  60,    164,   68,    -760,  216,   -296,  904,  -336,
100*09537850SAkhilesh Sanikop     -28,   404,   -356,  -568,  -208,  -1480, -512,  296,   328,   -360, -164,
101*09537850SAkhilesh Sanikop     -1560, -776,  1156,  -428,  164,   -504,  -112,  120,   -216,  -148, -264,
102*09537850SAkhilesh Sanikop     308,   32,    64,    -72,   72,    116,   176,   -64,   -272,  460,  -536,
103*09537850SAkhilesh Sanikop     -784,  -280,  348,   108,   -752,  -132,  524,   -540,  -776,  116,  -296,
104*09537850SAkhilesh Sanikop     -1196, -288,  -560,  1040,  -472,  116,   -848,  -1116, 116,   636,  696,
105*09537850SAkhilesh Sanikop     284,   -176,  1016,  204,   -864,  -648,  -248,  356,   972,   -584, -204,
106*09537850SAkhilesh Sanikop     264,   880,   528,   -24,   -184,  116,   448,   -144,  828,   524,  212,
107*09537850SAkhilesh Sanikop     -212,  52,    12,    200,   268,   -488,  -404,  -880,  824,   -672, -40,
108*09537850SAkhilesh Sanikop     908,   -248,  500,   716,   -576,  492,   -576,  16,    720,   -108, 384,
109*09537850SAkhilesh Sanikop     124,   344,   280,   576,   -500,  252,   104,   -308,  196,   -188, -8,
110*09537850SAkhilesh Sanikop     1268,  296,   1032,  -1196, 436,   316,   372,   -432,  -200,  -660, 704,
111*09537850SAkhilesh Sanikop     -224,  596,   -132,  268,   32,    -452,  884,   104,   -1008, 424,  -1348,
112*09537850SAkhilesh Sanikop     -280,  4,     -1168, 368,   476,   696,   300,   -8,    24,    180,  -592,
113*09537850SAkhilesh Sanikop     -196,  388,   304,   500,   724,   -160,  244,   -84,   272,   -256, -420,
114*09537850SAkhilesh Sanikop     320,   208,   -144,  -156,  156,   364,   452,   28,    540,   316,  220,
115*09537850SAkhilesh Sanikop     -644,  -248,  464,   72,    360,   32,    -388,  496,   -680,  -48,  208,
116*09537850SAkhilesh Sanikop     -116,  -408,  60,    -604,  -392,  548,   -840,  784,   -460,  656,  -544,
117*09537850SAkhilesh Sanikop     -388,  -264,  908,   -800,  -628,  -612,  -568,  572,   -220,  164,  288,
118*09537850SAkhilesh Sanikop     -16,   -308,  308,   -112,  -636,  -760,  280,   -668,  432,   364,  240,
119*09537850SAkhilesh Sanikop     -196,  604,   340,   384,   196,   592,   -44,   -500,  432,   -580, -132,
120*09537850SAkhilesh Sanikop     636,   -76,   392,   4,     -412,  540,   508,   328,   -356,  -36,  16,
121*09537850SAkhilesh Sanikop     -220,  -64,   -248,  -60,   24,    -192,  368,   1040,  92,    -24,  -1044,
122*09537850SAkhilesh Sanikop     -32,   40,    104,   148,   192,   -136,  -520,  56,    -816,  -224, 732,
123*09537850SAkhilesh Sanikop     392,   356,   212,   -80,   -424,  -1008, -324,  588,   -1496, 576,  460,
124*09537850SAkhilesh Sanikop     -816,  -848,  56,    -580,  -92,   -1372, -112,  -496,  200,   364,  52,
125*09537850SAkhilesh Sanikop     -140,  48,    -48,   -60,   84,    72,    40,    132,   -356,  -268, -104,
126*09537850SAkhilesh Sanikop     -284,  -404,  732,   -520,  164,   -304,  -540,  120,   328,   -76,  -460,
127*09537850SAkhilesh Sanikop     756,   388,   588,   236,   -436,  -72,   -176,  -404,  -316,  -148, 716,
128*09537850SAkhilesh Sanikop     -604,  404,   -72,   -88,   -888,  -68,   944,   88,    -220,  -344, 960,
129*09537850SAkhilesh Sanikop     472,   460,   -232,  704,   120,   832,   -228,  692,   -508,  132,  -476,
130*09537850SAkhilesh Sanikop     844,   -748,  -364,  -44,   1116,  -1104, -1056, 76,    428,   552,  -692,
131*09537850SAkhilesh Sanikop     60,    356,   96,    -384,  -188,  -612,  -576,  736,   508,   892,  352,
132*09537850SAkhilesh Sanikop     -1132, 504,   -24,   -352,  324,   332,   -600,  -312,  292,   508,  -144,
133*09537850SAkhilesh Sanikop     -8,    484,   48,    284,   -260,  -240,  256,   -100,  -292,  -204, -44,
134*09537850SAkhilesh Sanikop     472,   -204,  908,   -188,  -1000, -256,  92,    1164,  -392,  564,  356,
135*09537850SAkhilesh Sanikop     652,   -28,   -884,  256,   484,   -192,  760,   -176,  376,   -524, -452,
136*09537850SAkhilesh Sanikop     -436,  860,   -736,  212,   124,   504,   -476,  468,   76,    -472, 552,
137*09537850SAkhilesh Sanikop     -692,  -944,  -620,  740,   -240,  400,   132,   20,    192,   -196, 264,
138*09537850SAkhilesh Sanikop     -668,  -1012, -60,   296,   -316,  -828,  76,    -156,  284,   -768, -448,
139*09537850SAkhilesh Sanikop     -832,  148,   248,   652,   616,   1236,  288,   -328,  -400,  -124, 588,
140*09537850SAkhilesh Sanikop     220,   520,   -696,  1032,  768,   -740,  -92,   -272,  296,   448,  -464,
141*09537850SAkhilesh Sanikop     412,   -200,  392,   440,   -200,  264,   -152,  -260,  320,   1032, 216,
142*09537850SAkhilesh Sanikop     320,   -8,    -64,   156,   -1016, 1084,  1172,  536,   484,   -432, 132,
143*09537850SAkhilesh Sanikop     372,   -52,   -256,  84,    116,   -352,  48,    116,   304,   -384, 412,
144*09537850SAkhilesh Sanikop     924,   -300,  528,   628,   180,   648,   44,    -980,  -220,  1320, 48,
145*09537850SAkhilesh Sanikop     332,   748,   524,   -268,  -720,  540,   -276,  564,   -344,  -208, -196,
146*09537850SAkhilesh Sanikop     436,   896,   88,    -392,  132,   80,    -964,  -288,  568,   56,   -48,
147*09537850SAkhilesh Sanikop     -456,  888,   8,     552,   -156,  -292,  948,   288,   128,   -716, -292,
148*09537850SAkhilesh Sanikop     1192,  -152,  876,   352,   -600,  -260,  -812,  -468,  -28,   -120, -32,
149*09537850SAkhilesh Sanikop     -44,   1284,  496,   192,   464,   312,   -76,   -516,  -380,  -456, -1012,
150*09537850SAkhilesh Sanikop     -48,   308,   -156,  36,    492,   -156,  -808,  188,   1652,  68,   -120,
151*09537850SAkhilesh Sanikop     -116,  316,   160,   -140,  352,   808,   -416,  592,   316,   -480, 56,
152*09537850SAkhilesh Sanikop     528,   -204,  -568,  372,   -232,  752,   -344,  744,   -4,    324,  -416,
153*09537850SAkhilesh Sanikop     -600,  768,   268,   -248,  -88,   -132,  -420,  -432,  80,    -288, 404,
154*09537850SAkhilesh Sanikop     -316,  -1216, -588,  520,   -108,  92,    -320,  368,   -480,  -216, -92,
155*09537850SAkhilesh Sanikop     1688,  -300,  180,   1020,  -176,  820,   -68,   -228,  -260,  436,  -904,
156*09537850SAkhilesh Sanikop     20,    40,    -508,  440,   -736,  312,   332,   204,   760,   -372, 728,
157*09537850SAkhilesh Sanikop     96,    -20,   -632,  -520,  -560,  336,   1076,  -64,   -532,  776,  584,
158*09537850SAkhilesh Sanikop     192,   396,   -728,  -520,  276,   -188,  80,    -52,   -612,  -252, -48,
159*09537850SAkhilesh Sanikop     648,   212,   -688,  228,   -52,   -260,  428,   -412,  -272,  -404, 180,
160*09537850SAkhilesh Sanikop     816,   -796,  48,    152,   484,   -88,   -216,  988,   696,   188,  -528,
161*09537850SAkhilesh Sanikop     648,   -116,  -180,  316,   476,   12,    -564,  96,    476,   -252, -364,
162*09537850SAkhilesh Sanikop     -376,  -392,  556,   -256,  -576,  260,   -352,  120,   -16,   -136, -260,
163*09537850SAkhilesh Sanikop     -492,  72,    556,   660,   580,   616,   772,   436,   424,   -32,  -324,
164*09537850SAkhilesh Sanikop     -1268, 416,   -324,  -80,   920,   160,   228,   724,   32,    -516, 64,
165*09537850SAkhilesh Sanikop     384,   68,    -128,  136,   240,   248,   -204,  -68,   252,   -932, -120,
166*09537850SAkhilesh Sanikop     -480,  -628,  -84,   192,   852,   -404,  -288,  -132,  204,   100,  168,
167*09537850SAkhilesh Sanikop     -68,   -196,  -868,  460,   1080,  380,   -80,   244,   0,     484,  -888,
168*09537850SAkhilesh Sanikop     64,    184,   352,   600,   460,   164,   604,   -196,  320,   -64,  588,
169*09537850SAkhilesh Sanikop     -184,  228,   12,    372,   48,    -848,  -344,  224,   208,   -200, 484,
170*09537850SAkhilesh Sanikop     128,   -20,   272,   -468,  -840,  384,   256,   -720,  -520,  -464, -580,
171*09537850SAkhilesh Sanikop     112,   -120,  644,   -356,  -208,  -608,  -528,  704,   560,   -424, 392,
172*09537850SAkhilesh Sanikop     828,   40,    84,    200,   -152,  0,     -144,  584,   280,   -120, 80,
173*09537850SAkhilesh Sanikop     -556,  -972,  -196,  -472,  724,   80,    168,   -32,   88,    160,  -688,
174*09537850SAkhilesh Sanikop     0,     160,   356,   372,   -776,  740,   -128,  676,   -248,  -480, 4,
175*09537850SAkhilesh Sanikop     -364,  96,    544,   232,   -1032, 956,   236,   356,   20,    -40,  300,
176*09537850SAkhilesh Sanikop     24,    -676,  -596,  132,   1120,  -104,  532,   -1096, 568,   648,  444,
177*09537850SAkhilesh Sanikop     508,   380,   188,   -376,  -604,  1488,  424,   24,    756,   -220, -192,
178*09537850SAkhilesh Sanikop     716,   120,   920,   688,   168,   44,    -460,  568,   284,   1144, 1160,
179*09537850SAkhilesh Sanikop     600,   424,   888,   656,   -356,  -320,  220,   316,   -176,  -724, -188,
180*09537850SAkhilesh Sanikop     -816,  -628,  -348,  -228,  -380,  1012,  -452,  -660,  736,   928,  404,
181*09537850SAkhilesh Sanikop     -696,  -72,   -268,  -892,  128,   184,   -344,  -780,  360,   336,  400,
182*09537850SAkhilesh Sanikop     344,   428,   548,   -112,  136,   -228,  -216,  -820,  -516,  340,  92,
183*09537850SAkhilesh Sanikop     -136,  116,   -300,  376,   -244,  100,   -316,  -520,  -284,  -12,  824,
184*09537850SAkhilesh Sanikop     164,   -548,  -180,  -128,  116,   -924,  -828,  268,   -368,  -580, 620,
185*09537850SAkhilesh Sanikop     192,   160,   0,     -1676, 1068,  424,   -56,   -360,  468,   -156, 720,
186*09537850SAkhilesh Sanikop     288,   -528,  556,   -364,  548,   -148,  504,   316,   152,   -648, -620,
187*09537850SAkhilesh Sanikop     -684,  -24,   -376,  -384,  -108,  -920,  -1032, 768,   180,   -264, -508,
188*09537850SAkhilesh Sanikop     -1268, -260,  -60,   300,   -240,  988,   724,   -376,  -576,  -212, -736,
189*09537850SAkhilesh Sanikop     556,   192,   1092,  -620,  -880,  376,   -56,   -4,    -216,  -32,  836,
190*09537850SAkhilesh Sanikop     268,   396,   1332,  864,   -600,  100,   56,    -412,  -92,   356,  180,
191*09537850SAkhilesh Sanikop     884,   -468,  -436,  292,   -388,  -804,  -704,  -840,  368,   -348, 140,
192*09537850SAkhilesh Sanikop     -724,  1536,  940,   372,   112,   -372,  436,   -480,  1136,  296,  -32,
193*09537850SAkhilesh Sanikop     -228,  132,   -48,   -220,  868,   -1016, -60,   -1044, -464,  328,  916,
194*09537850SAkhilesh Sanikop     244,   12,    -736,  -296,  360,   468,   -376,  -108,  -92,   788,  368,
195*09537850SAkhilesh Sanikop     -56,   544,   400,   -672,  -420,  728,   16,    320,   44,    -284, -380,
196*09537850SAkhilesh Sanikop     -796,  488,   132,   204,   -596,  -372,  88,    -152,  -908,  -636, -572,
197*09537850SAkhilesh Sanikop     -624,  -116,  -692,  -200,  -56,   276,   -88,   484,   -324,  948,  864,
198*09537850SAkhilesh Sanikop     1000,  -456,  -184,  -276,  292,   -296,  156,   676,   320,   160,  908,
199*09537850SAkhilesh Sanikop     -84,   -1236, -288,  -116,  260,   -372,  -644,  732,   -756,  -96,  84,
200*09537850SAkhilesh Sanikop     344,   -520,  348,   -688,  240,   -84,   216,   -1044, -136,  -676, -396,
201*09537850SAkhilesh Sanikop     -1500, 960,   -40,   176,   168,   1516,  420,   -504,  -344,  -364, -360,
202*09537850SAkhilesh Sanikop     1216,  -940,  -380,  -212,  252,   -660,  -708,  484,   -444,  -152, 928,
203*09537850SAkhilesh Sanikop     -120,  1112,  476,   -260,  560,   -148,  -344,  108,   -196,  228,  -288,
204*09537850SAkhilesh Sanikop     504,   560,   -328,  -88,   288,   -1008, 460,   -228,  468,   -836, -196,
205*09537850SAkhilesh Sanikop     76,    388,   232,   412,   -1168, -716,  -644,  756,   -172,  -356, -504,
206*09537850SAkhilesh Sanikop     116,   432,   528,   48,    476,   -168,  -608,  448,   160,   -532, -272,
207*09537850SAkhilesh Sanikop     28,    -676,  -12,   828,   980,   456,   520,   104,   -104,  256,  -344,
208*09537850SAkhilesh Sanikop     -4,    -28,   -368,  -52,   -524,  -572,  -556,  -200,  768,   1124, -208,
209*09537850SAkhilesh Sanikop     -512,  176,   232,   248,   -148,  -888,  604,   -600,  -304,  804,  -156,
210*09537850SAkhilesh Sanikop     -212,  488,   -192,  -804,  -256,  368,   -360,  -916,  -328,  228,  -240,
211*09537850SAkhilesh Sanikop     -448,  -472,  856,   -556,  -364,  572,   -12,   -156,  -368,  -340, 432,
212*09537850SAkhilesh Sanikop     252,   -752,  -152,  288,   268,   -580,  -848,  -592,  108,   -76,  244,
213*09537850SAkhilesh Sanikop     312,   -716,  592,   -80,   436,   360,   4,     -248,  160,   516,  584,
214*09537850SAkhilesh Sanikop     732,   44,    -468,  -280,  -292,  -156,  -588,  28,    308,   912,  24,
215*09537850SAkhilesh Sanikop     124,   156,   180,   -252,  944,   -924,  -772,  -520,  -428,  -624, 300,
216*09537850SAkhilesh Sanikop     -212,  -1144, 32,    -724,  800,   -1128, -212,  -1288, -848,  180,  -416,
217*09537850SAkhilesh Sanikop     440,   192,   -576,  -792,  -76,   -1080, 80,    -532,  -352,  -132, 380,
218*09537850SAkhilesh Sanikop     -820,  148,   1112,  128,   164,   456,   700,   -924,  144,   -668, -384,
219*09537850SAkhilesh Sanikop     648,   -832,  508,   552,   -52,   -100,  -656,  208,   -568,  748,  -88,
220*09537850SAkhilesh Sanikop     680,   232,   300,   192,   -408,  -1012, -152,  -252,  -268,  272,  -876,
221*09537850SAkhilesh Sanikop     -664,  -648,  -332,  -136,  16,    12,    1152,  -28,   332,   -536, 320,
222*09537850SAkhilesh Sanikop     -672,  -460,  -316,  532,   -260,  228,   -40,   1052,  -816,  180,  88,
223*09537850SAkhilesh Sanikop     -496,  -556,  -672,  -368,  428,   92,    356,   404,   -408,  252,  196,
224*09537850SAkhilesh Sanikop     -176,  -556,  792,   268,   32,    372,   40,    96,    -332,  328,  120,
225*09537850SAkhilesh Sanikop     372,   -900,  -40,   472,   -264,  -592,  952,   128,   656,   112,  664,
226*09537850SAkhilesh Sanikop     -232,  420,   4,     -344,  -464,  556,   244,   -416,  -32,   252,  0,
227*09537850SAkhilesh Sanikop     -412,  188,   -696,  508,   -476,  324,   -1096, 656,   -312,  560,  264,
228*09537850SAkhilesh Sanikop     -136,  304,   160,   -64,   -580,  248,   336,   -720,  560,   -348, -288,
229*09537850SAkhilesh Sanikop     -276,  -196,  -500,  852,   -544,  -236,  -1128, -992,  -776,  116,  56,
230*09537850SAkhilesh Sanikop     52,    860,   884,   212,   -12,   168,   1020,  512,   -552,  924,  -148,
231*09537850SAkhilesh Sanikop     716,   188,   164,   -340,  -520,  -184,  880,   -152,  -680,  -208, -1156,
232*09537850SAkhilesh Sanikop     -300,  -528,  -472,  364,   100,   -744,  -1056, -32,   540,   280,  144,
233*09537850SAkhilesh Sanikop     -676,  -32,   -232,  -280,  -224,  96,    568,   -76,   172,   148,  148,
234*09537850SAkhilesh Sanikop     104,   32,    -296,  -32,   788,   -80,   32,    -16,   280,   288,  944,
235*09537850SAkhilesh Sanikop     428,   -484};
236*09537850SAkhilesh Sanikop static_assert(sizeof(kGaussianSequence) / sizeof(kGaussianSequence[0]) == 2048,
237*09537850SAkhilesh Sanikop               "");
238*09537850SAkhilesh Sanikop 
239*09537850SAkhilesh Sanikop // The number of rows in a contiguous group computed by a single worker thread
240*09537850SAkhilesh Sanikop // before checking for the next available group.
241*09537850SAkhilesh Sanikop constexpr int kFrameChunkHeight = 8;
242*09537850SAkhilesh Sanikop 
243*09537850SAkhilesh Sanikop // |width| and |height| refer to the plane, not the frame, meaning any
244*09537850SAkhilesh Sanikop // subsampling should be applied by the caller.
245*09537850SAkhilesh Sanikop template <typename Pixel>
CopyImagePlane(const uint8_t * source_plane,ptrdiff_t source_stride,int width,int height,uint8_t * dest_plane,ptrdiff_t dest_stride)246*09537850SAkhilesh Sanikop inline void CopyImagePlane(const uint8_t* source_plane, ptrdiff_t source_stride,
247*09537850SAkhilesh Sanikop                            int width, int height, uint8_t* dest_plane,
248*09537850SAkhilesh Sanikop                            ptrdiff_t dest_stride) {
249*09537850SAkhilesh Sanikop   // If it's the same buffer there's nothing to do.
250*09537850SAkhilesh Sanikop   if (source_plane == dest_plane) return;
251*09537850SAkhilesh Sanikop 
252*09537850SAkhilesh Sanikop   int y = 0;
253*09537850SAkhilesh Sanikop   do {
254*09537850SAkhilesh Sanikop     memcpy(dest_plane, source_plane, width * sizeof(Pixel));
255*09537850SAkhilesh Sanikop     source_plane += source_stride;
256*09537850SAkhilesh Sanikop     dest_plane += dest_stride;
257*09537850SAkhilesh Sanikop   } while (++y < height);
258*09537850SAkhilesh Sanikop }
259*09537850SAkhilesh Sanikop 
260*09537850SAkhilesh Sanikop }  // namespace
261*09537850SAkhilesh Sanikop 
262*09537850SAkhilesh Sanikop template <int bitdepth>
FilmGrain(const FilmGrainParams & params,bool is_monochrome,bool color_matrix_is_identity,int subsampling_x,int subsampling_y,int width,int height,ThreadPool * thread_pool)263*09537850SAkhilesh Sanikop FilmGrain<bitdepth>::FilmGrain(const FilmGrainParams& params,
264*09537850SAkhilesh Sanikop                                bool is_monochrome,
265*09537850SAkhilesh Sanikop                                bool color_matrix_is_identity, int subsampling_x,
266*09537850SAkhilesh Sanikop                                int subsampling_y, int width, int height,
267*09537850SAkhilesh Sanikop                                ThreadPool* thread_pool)
268*09537850SAkhilesh Sanikop     : params_(params),
269*09537850SAkhilesh Sanikop       is_monochrome_(is_monochrome),
270*09537850SAkhilesh Sanikop       color_matrix_is_identity_(color_matrix_is_identity),
271*09537850SAkhilesh Sanikop       subsampling_x_(subsampling_x),
272*09537850SAkhilesh Sanikop       subsampling_y_(subsampling_y),
273*09537850SAkhilesh Sanikop       width_(width),
274*09537850SAkhilesh Sanikop       height_(height),
275*09537850SAkhilesh Sanikop       template_uv_width_((subsampling_x != 0) ? kMinChromaWidth
276*09537850SAkhilesh Sanikop                                               : kMaxChromaWidth),
277*09537850SAkhilesh Sanikop       template_uv_height_((subsampling_y != 0) ? kMinChromaHeight
278*09537850SAkhilesh Sanikop                                                : kMaxChromaHeight),
279*09537850SAkhilesh Sanikop       thread_pool_(thread_pool) {}
280*09537850SAkhilesh Sanikop 
281*09537850SAkhilesh Sanikop template <int bitdepth>
Init()282*09537850SAkhilesh Sanikop bool FilmGrain<bitdepth>::Init() {
283*09537850SAkhilesh Sanikop   // Section 7.18.3.3. Generate grain process.
284*09537850SAkhilesh Sanikop   const dsp::Dsp& dsp = *dsp::GetDspTable(bitdepth);
285*09537850SAkhilesh Sanikop   // If params_.num_y_points is 0, luma_grain_ will never be read, so we don't
286*09537850SAkhilesh Sanikop   // need to generate it.
287*09537850SAkhilesh Sanikop   const bool use_luma = params_.num_y_points > 0;
288*09537850SAkhilesh Sanikop   if (use_luma) {
289*09537850SAkhilesh Sanikop     GenerateLumaGrain(params_, luma_grain_);
290*09537850SAkhilesh Sanikop     // If params_.auto_regression_coeff_lag is 0, the filter is the identity
291*09537850SAkhilesh Sanikop     // filter and therefore can be skipped.
292*09537850SAkhilesh Sanikop     if (params_.auto_regression_coeff_lag > 0) {
293*09537850SAkhilesh Sanikop       dsp.film_grain
294*09537850SAkhilesh Sanikop           .luma_auto_regression[params_.auto_regression_coeff_lag - 1](
295*09537850SAkhilesh Sanikop               params_, luma_grain_);
296*09537850SAkhilesh Sanikop     }
297*09537850SAkhilesh Sanikop   } else {
298*09537850SAkhilesh Sanikop     // Have AddressSanitizer warn if luma_grain_ is used.
299*09537850SAkhilesh Sanikop     ASAN_POISON_MEMORY_REGION(luma_grain_, sizeof(luma_grain_));
300*09537850SAkhilesh Sanikop   }
301*09537850SAkhilesh Sanikop   if (!is_monochrome_) {
302*09537850SAkhilesh Sanikop     GenerateChromaGrains(params_, template_uv_width_, template_uv_height_,
303*09537850SAkhilesh Sanikop                          u_grain_, v_grain_);
304*09537850SAkhilesh Sanikop     if (params_.auto_regression_coeff_lag > 0 || use_luma) {
305*09537850SAkhilesh Sanikop       dsp.film_grain.chroma_auto_regression[static_cast<int>(
306*09537850SAkhilesh Sanikop           use_luma)][params_.auto_regression_coeff_lag](
307*09537850SAkhilesh Sanikop           params_, luma_grain_, subsampling_x_, subsampling_y_, u_grain_,
308*09537850SAkhilesh Sanikop           v_grain_);
309*09537850SAkhilesh Sanikop     }
310*09537850SAkhilesh Sanikop   }
311*09537850SAkhilesh Sanikop 
312*09537850SAkhilesh Sanikop   // Section 7.18.3.4. Scaling lookup initialization process.
313*09537850SAkhilesh Sanikop 
314*09537850SAkhilesh Sanikop   // Initialize scaling_lut_y_. If params_.num_y_points > 0, scaling_lut_y_
315*09537850SAkhilesh Sanikop   // is used for the Y plane. If params_.chroma_scaling_from_luma is true,
316*09537850SAkhilesh Sanikop   // scaling_lut_u_ and scaling_lut_v_ are the same as scaling_lut_y_ and are
317*09537850SAkhilesh Sanikop   // set up as aliases. So we need to initialize scaling_lut_y_ under these
318*09537850SAkhilesh Sanikop   // two conditions.
319*09537850SAkhilesh Sanikop   //
320*09537850SAkhilesh Sanikop   // Note: Although it does not seem to make sense, there are test vectors
321*09537850SAkhilesh Sanikop   // with chroma_scaling_from_luma=true and params_.num_y_points=0.
322*09537850SAkhilesh Sanikop #if LIBGAV1_MSAN
323*09537850SAkhilesh Sanikop   // Quiet film grain / md5 msan warnings.
324*09537850SAkhilesh Sanikop   memset(scaling_lut_y_, 0, sizeof(scaling_lut_y_));
325*09537850SAkhilesh Sanikop #endif
326*09537850SAkhilesh Sanikop   if (use_luma || params_.chroma_scaling_from_luma) {
327*09537850SAkhilesh Sanikop     dsp.film_grain.initialize_scaling_lut(
328*09537850SAkhilesh Sanikop         params_.num_y_points, params_.point_y_value, params_.point_y_scaling,
329*09537850SAkhilesh Sanikop         scaling_lut_y_, kScalingLutLength);
330*09537850SAkhilesh Sanikop   } else {
331*09537850SAkhilesh Sanikop     ASAN_POISON_MEMORY_REGION(scaling_lut_y_, sizeof(scaling_lut_y_));
332*09537850SAkhilesh Sanikop   }
333*09537850SAkhilesh Sanikop   if (!is_monochrome_) {
334*09537850SAkhilesh Sanikop     if (params_.chroma_scaling_from_luma) {
335*09537850SAkhilesh Sanikop       scaling_lut_u_ = scaling_lut_y_;
336*09537850SAkhilesh Sanikop       scaling_lut_v_ = scaling_lut_y_;
337*09537850SAkhilesh Sanikop     } else if (params_.num_u_points > 0 || params_.num_v_points > 0) {
338*09537850SAkhilesh Sanikop       const size_t buffer_size =
339*09537850SAkhilesh Sanikop           kScalingLutLength * (static_cast<int>(params_.num_u_points > 0) +
340*09537850SAkhilesh Sanikop                                static_cast<int>(params_.num_v_points > 0));
341*09537850SAkhilesh Sanikop       scaling_lut_chroma_buffer_.reset(new (std::nothrow) int16_t[buffer_size]);
342*09537850SAkhilesh Sanikop       if (scaling_lut_chroma_buffer_ == nullptr) return false;
343*09537850SAkhilesh Sanikop 
344*09537850SAkhilesh Sanikop       int16_t* buffer = scaling_lut_chroma_buffer_.get();
345*09537850SAkhilesh Sanikop #if LIBGAV1_MSAN
346*09537850SAkhilesh Sanikop       // Quiet film grain / md5 msan warnings.
347*09537850SAkhilesh Sanikop       memset(buffer, 0, buffer_size * 2);
348*09537850SAkhilesh Sanikop #endif
349*09537850SAkhilesh Sanikop       if (params_.num_u_points > 0) {
350*09537850SAkhilesh Sanikop         scaling_lut_u_ = buffer;
351*09537850SAkhilesh Sanikop         dsp.film_grain.initialize_scaling_lut(
352*09537850SAkhilesh Sanikop             params_.num_u_points, params_.point_u_value,
353*09537850SAkhilesh Sanikop             params_.point_u_scaling, scaling_lut_u_, kScalingLutLength);
354*09537850SAkhilesh Sanikop         buffer += kScalingLutLength;
355*09537850SAkhilesh Sanikop       }
356*09537850SAkhilesh Sanikop       if (params_.num_v_points > 0) {
357*09537850SAkhilesh Sanikop         scaling_lut_v_ = buffer;
358*09537850SAkhilesh Sanikop         dsp.film_grain.initialize_scaling_lut(
359*09537850SAkhilesh Sanikop             params_.num_v_points, params_.point_v_value,
360*09537850SAkhilesh Sanikop             params_.point_v_scaling, scaling_lut_v_, kScalingLutLength);
361*09537850SAkhilesh Sanikop       }
362*09537850SAkhilesh Sanikop     }
363*09537850SAkhilesh Sanikop   }
364*09537850SAkhilesh Sanikop   return true;
365*09537850SAkhilesh Sanikop }
366*09537850SAkhilesh Sanikop 
367*09537850SAkhilesh Sanikop template <int bitdepth>
GenerateLumaGrain(const FilmGrainParams & params,GrainType * luma_grain)368*09537850SAkhilesh Sanikop void FilmGrain<bitdepth>::GenerateLumaGrain(const FilmGrainParams& params,
369*09537850SAkhilesh Sanikop                                             GrainType* luma_grain) {
370*09537850SAkhilesh Sanikop   // If params.num_y_points is equal to 0, Section 7.18.3.3 specifies we set
371*09537850SAkhilesh Sanikop   // the luma_grain array to all zeros. But the Note at the end of Section
372*09537850SAkhilesh Sanikop   // 7.18.3.3 says luma_grain "will never be read in this case". So we don't
373*09537850SAkhilesh Sanikop   // call GenerateLumaGrain if params.num_y_points is equal to 0.
374*09537850SAkhilesh Sanikop   assert(params.num_y_points > 0);
375*09537850SAkhilesh Sanikop   const int shift = kBitdepth12 - bitdepth + params.grain_scale_shift;
376*09537850SAkhilesh Sanikop   uint16_t seed = params.grain_seed;
377*09537850SAkhilesh Sanikop   GrainType* luma_grain_row = luma_grain;
378*09537850SAkhilesh Sanikop   for (int y = 0; y < kLumaHeight; ++y) {
379*09537850SAkhilesh Sanikop     for (int x = 0; x < kLumaWidth; ++x) {
380*09537850SAkhilesh Sanikop       luma_grain_row[x] = RightShiftWithRounding(
381*09537850SAkhilesh Sanikop           kGaussianSequence[GetFilmGrainRandomNumber(11, &seed)], shift);
382*09537850SAkhilesh Sanikop     }
383*09537850SAkhilesh Sanikop     luma_grain_row += kLumaWidth;
384*09537850SAkhilesh Sanikop   }
385*09537850SAkhilesh Sanikop }
386*09537850SAkhilesh Sanikop 
387*09537850SAkhilesh Sanikop template <int bitdepth>
GenerateChromaGrains(const FilmGrainParams & params,int chroma_width,int chroma_height,GrainType * u_grain,GrainType * v_grain)388*09537850SAkhilesh Sanikop void FilmGrain<bitdepth>::GenerateChromaGrains(const FilmGrainParams& params,
389*09537850SAkhilesh Sanikop                                                int chroma_width,
390*09537850SAkhilesh Sanikop                                                int chroma_height,
391*09537850SAkhilesh Sanikop                                                GrainType* u_grain,
392*09537850SAkhilesh Sanikop                                                GrainType* v_grain) {
393*09537850SAkhilesh Sanikop   const int shift = kBitdepth12 - bitdepth + params.grain_scale_shift;
394*09537850SAkhilesh Sanikop   if (params.num_u_points == 0 && !params.chroma_scaling_from_luma) {
395*09537850SAkhilesh Sanikop     memset(u_grain, 0, chroma_height * chroma_width * sizeof(*u_grain));
396*09537850SAkhilesh Sanikop   } else {
397*09537850SAkhilesh Sanikop     uint16_t seed = params.grain_seed ^ 0xb524;
398*09537850SAkhilesh Sanikop     GrainType* u_grain_row = u_grain;
399*09537850SAkhilesh Sanikop     assert(chroma_width > 0);
400*09537850SAkhilesh Sanikop     assert(chroma_height > 0);
401*09537850SAkhilesh Sanikop     int y = 0;
402*09537850SAkhilesh Sanikop     do {
403*09537850SAkhilesh Sanikop       int x = 0;
404*09537850SAkhilesh Sanikop       do {
405*09537850SAkhilesh Sanikop         u_grain_row[x] = RightShiftWithRounding(
406*09537850SAkhilesh Sanikop             kGaussianSequence[GetFilmGrainRandomNumber(11, &seed)], shift);
407*09537850SAkhilesh Sanikop       } while (++x < chroma_width);
408*09537850SAkhilesh Sanikop 
409*09537850SAkhilesh Sanikop       u_grain_row += chroma_width;
410*09537850SAkhilesh Sanikop     } while (++y < chroma_height);
411*09537850SAkhilesh Sanikop   }
412*09537850SAkhilesh Sanikop   if (params.num_v_points == 0 && !params.chroma_scaling_from_luma) {
413*09537850SAkhilesh Sanikop     memset(v_grain, 0, chroma_height * chroma_width * sizeof(*v_grain));
414*09537850SAkhilesh Sanikop   } else {
415*09537850SAkhilesh Sanikop     GrainType* v_grain_row = v_grain;
416*09537850SAkhilesh Sanikop     uint16_t seed = params.grain_seed ^ 0x49d8;
417*09537850SAkhilesh Sanikop     int y = 0;
418*09537850SAkhilesh Sanikop     do {
419*09537850SAkhilesh Sanikop       int x = 0;
420*09537850SAkhilesh Sanikop       do {
421*09537850SAkhilesh Sanikop         v_grain_row[x] = RightShiftWithRounding(
422*09537850SAkhilesh Sanikop             kGaussianSequence[GetFilmGrainRandomNumber(11, &seed)], shift);
423*09537850SAkhilesh Sanikop       } while (++x < chroma_width);
424*09537850SAkhilesh Sanikop 
425*09537850SAkhilesh Sanikop       v_grain_row += chroma_width;
426*09537850SAkhilesh Sanikop     } while (++y < chroma_height);
427*09537850SAkhilesh Sanikop   }
428*09537850SAkhilesh Sanikop }
429*09537850SAkhilesh Sanikop 
430*09537850SAkhilesh Sanikop template <int bitdepth>
AllocateNoiseStripes()431*09537850SAkhilesh Sanikop bool FilmGrain<bitdepth>::AllocateNoiseStripes() {
432*09537850SAkhilesh Sanikop   const int half_height = DivideBy2(height_ + 1);
433*09537850SAkhilesh Sanikop   assert(half_height > 0);
434*09537850SAkhilesh Sanikop   // ceil(half_height / 16.0)
435*09537850SAkhilesh Sanikop   const int max_luma_num = DivideBy16(half_height + 15);
436*09537850SAkhilesh Sanikop   constexpr int kNoiseStripeHeight = 34;
437*09537850SAkhilesh Sanikop   size_t noise_buffer_size = kNoiseStripePadding;
438*09537850SAkhilesh Sanikop   if (params_.num_y_points > 0) {
439*09537850SAkhilesh Sanikop     noise_buffer_size += max_luma_num * kNoiseStripeHeight * width_;
440*09537850SAkhilesh Sanikop   }
441*09537850SAkhilesh Sanikop   if (!is_monochrome_) {
442*09537850SAkhilesh Sanikop     noise_buffer_size += 2 * max_luma_num *
443*09537850SAkhilesh Sanikop                          (kNoiseStripeHeight >> subsampling_y_) *
444*09537850SAkhilesh Sanikop                          SubsampledValue(width_, subsampling_x_);
445*09537850SAkhilesh Sanikop   }
446*09537850SAkhilesh Sanikop   noise_buffer_.reset(new (std::nothrow) GrainType[noise_buffer_size]);
447*09537850SAkhilesh Sanikop   if (noise_buffer_ == nullptr) return false;
448*09537850SAkhilesh Sanikop   GrainType* noise_buffer = noise_buffer_.get();
449*09537850SAkhilesh Sanikop   if (params_.num_y_points > 0) {
450*09537850SAkhilesh Sanikop     noise_stripes_[kPlaneY].Reset(max_luma_num, kNoiseStripeHeight * width_,
451*09537850SAkhilesh Sanikop                                   noise_buffer);
452*09537850SAkhilesh Sanikop     noise_buffer += max_luma_num * kNoiseStripeHeight * width_;
453*09537850SAkhilesh Sanikop   }
454*09537850SAkhilesh Sanikop   if (!is_monochrome_) {
455*09537850SAkhilesh Sanikop     noise_stripes_[kPlaneU].Reset(max_luma_num,
456*09537850SAkhilesh Sanikop                                   (kNoiseStripeHeight >> subsampling_y_) *
457*09537850SAkhilesh Sanikop                                       SubsampledValue(width_, subsampling_x_),
458*09537850SAkhilesh Sanikop                                   noise_buffer);
459*09537850SAkhilesh Sanikop     noise_buffer += max_luma_num * (kNoiseStripeHeight >> subsampling_y_) *
460*09537850SAkhilesh Sanikop                     SubsampledValue(width_, subsampling_x_);
461*09537850SAkhilesh Sanikop     noise_stripes_[kPlaneV].Reset(max_luma_num,
462*09537850SAkhilesh Sanikop                                   (kNoiseStripeHeight >> subsampling_y_) *
463*09537850SAkhilesh Sanikop                                       SubsampledValue(width_, subsampling_x_),
464*09537850SAkhilesh Sanikop                                   noise_buffer);
465*09537850SAkhilesh Sanikop   }
466*09537850SAkhilesh Sanikop   return true;
467*09537850SAkhilesh Sanikop }
468*09537850SAkhilesh Sanikop 
469*09537850SAkhilesh Sanikop template <int bitdepth>
AllocateNoiseImage()470*09537850SAkhilesh Sanikop bool FilmGrain<bitdepth>::AllocateNoiseImage() {
471*09537850SAkhilesh Sanikop   // When LIBGAV1_MSAN is enabled, zero initialize to quiet optimized film grain
472*09537850SAkhilesh Sanikop   // msan warnings.
473*09537850SAkhilesh Sanikop   constexpr bool zero_initialize = LIBGAV1_MSAN == 1;
474*09537850SAkhilesh Sanikop   if (params_.num_y_points > 0 &&
475*09537850SAkhilesh Sanikop       !noise_image_[kPlaneY].Reset(height_, width_ + kNoiseImagePadding,
476*09537850SAkhilesh Sanikop                                    zero_initialize)) {
477*09537850SAkhilesh Sanikop     return false;
478*09537850SAkhilesh Sanikop   }
479*09537850SAkhilesh Sanikop   if (!is_monochrome_) {
480*09537850SAkhilesh Sanikop     if (!noise_image_[kPlaneU].Reset(
481*09537850SAkhilesh Sanikop             (height_ + subsampling_y_) >> subsampling_y_,
482*09537850SAkhilesh Sanikop             ((width_ + subsampling_x_) >> subsampling_x_) + kNoiseImagePadding,
483*09537850SAkhilesh Sanikop             zero_initialize)) {
484*09537850SAkhilesh Sanikop       return false;
485*09537850SAkhilesh Sanikop     }
486*09537850SAkhilesh Sanikop     if (!noise_image_[kPlaneV].Reset(
487*09537850SAkhilesh Sanikop             (height_ + subsampling_y_) >> subsampling_y_,
488*09537850SAkhilesh Sanikop             ((width_ + subsampling_x_) >> subsampling_x_) + kNoiseImagePadding,
489*09537850SAkhilesh Sanikop             zero_initialize)) {
490*09537850SAkhilesh Sanikop       return false;
491*09537850SAkhilesh Sanikop     }
492*09537850SAkhilesh Sanikop   }
493*09537850SAkhilesh Sanikop   return true;
494*09537850SAkhilesh Sanikop }
495*09537850SAkhilesh Sanikop 
496*09537850SAkhilesh Sanikop // Uses |overlap_flag| to skip rows that are covered by the overlap computation.
497*09537850SAkhilesh Sanikop template <int bitdepth>
ConstructNoiseImage(const Array2DView<GrainType> * noise_stripes,int width,int height,int subsampling_x,int subsampling_y,int stripe_start_offset,Array2D<GrainType> * noise_image)498*09537850SAkhilesh Sanikop void FilmGrain<bitdepth>::ConstructNoiseImage(
499*09537850SAkhilesh Sanikop     const Array2DView<GrainType>* noise_stripes, int width, int height,
500*09537850SAkhilesh Sanikop     int subsampling_x, int subsampling_y, int stripe_start_offset,
501*09537850SAkhilesh Sanikop     Array2D<GrainType>* noise_image) {
502*09537850SAkhilesh Sanikop   const int plane_width = (width + subsampling_x) >> subsampling_x;
503*09537850SAkhilesh Sanikop   const int plane_height = (height + subsampling_y) >> subsampling_y;
504*09537850SAkhilesh Sanikop   const int stripe_height = 32 >> subsampling_y;
505*09537850SAkhilesh Sanikop   const int stripe_mask = stripe_height - 1;
506*09537850SAkhilesh Sanikop   int y = 0;
507*09537850SAkhilesh Sanikop   // |luma_num| = y >> (5 - |subsampling_y|). Hence |luma_num| == 0 for all y up
508*09537850SAkhilesh Sanikop   // to either 16 or 32.
509*09537850SAkhilesh Sanikop   const GrainType* first_noise_stripe = (*noise_stripes)[0];
510*09537850SAkhilesh Sanikop   do {
511*09537850SAkhilesh Sanikop     memcpy((*noise_image)[y], first_noise_stripe + y * plane_width,
512*09537850SAkhilesh Sanikop            plane_width * sizeof(first_noise_stripe[0]));
513*09537850SAkhilesh Sanikop   } while (++y < std::min(stripe_height, plane_height));
514*09537850SAkhilesh Sanikop   // End special iterations for luma_num == 0.
515*09537850SAkhilesh Sanikop 
516*09537850SAkhilesh Sanikop   int luma_num = 1;
517*09537850SAkhilesh Sanikop   for (; y < (plane_height & ~stripe_mask); ++luma_num, y += stripe_height) {
518*09537850SAkhilesh Sanikop     const GrainType* noise_stripe = (*noise_stripes)[luma_num];
519*09537850SAkhilesh Sanikop     int i = stripe_start_offset;
520*09537850SAkhilesh Sanikop     do {
521*09537850SAkhilesh Sanikop       memcpy((*noise_image)[y + i], noise_stripe + i * plane_width,
522*09537850SAkhilesh Sanikop              plane_width * sizeof(noise_stripe[0]));
523*09537850SAkhilesh Sanikop     } while (++i < stripe_height);
524*09537850SAkhilesh Sanikop   }
525*09537850SAkhilesh Sanikop 
526*09537850SAkhilesh Sanikop   // If there is a partial stripe, copy any rows beyond the overlap rows.
527*09537850SAkhilesh Sanikop   const int remaining_height = plane_height - y;
528*09537850SAkhilesh Sanikop   if (remaining_height > stripe_start_offset) {
529*09537850SAkhilesh Sanikop     assert(luma_num < noise_stripes->rows());
530*09537850SAkhilesh Sanikop     const GrainType* noise_stripe = (*noise_stripes)[luma_num];
531*09537850SAkhilesh Sanikop     int i = stripe_start_offset;
532*09537850SAkhilesh Sanikop     do {
533*09537850SAkhilesh Sanikop       memcpy((*noise_image)[y + i], noise_stripe + i * plane_width,
534*09537850SAkhilesh Sanikop              plane_width * sizeof(noise_stripe[0]));
535*09537850SAkhilesh Sanikop     } while (++i < remaining_height);
536*09537850SAkhilesh Sanikop   }
537*09537850SAkhilesh Sanikop }
538*09537850SAkhilesh Sanikop 
539*09537850SAkhilesh Sanikop template <int bitdepth>
BlendNoiseChromaWorker(const dsp::Dsp & dsp,const Plane * planes,int num_planes,std::atomic<int> * job_counter,int min_value,int max_chroma,const uint8_t * source_plane_y,ptrdiff_t source_stride_y,const uint8_t * source_plane_u,const uint8_t * source_plane_v,ptrdiff_t source_stride_uv,uint8_t * dest_plane_u,uint8_t * dest_plane_v,ptrdiff_t dest_stride_uv)540*09537850SAkhilesh Sanikop void FilmGrain<bitdepth>::BlendNoiseChromaWorker(
541*09537850SAkhilesh Sanikop     const dsp::Dsp& dsp, const Plane* planes, int num_planes,
542*09537850SAkhilesh Sanikop     std::atomic<int>* job_counter, int min_value, int max_chroma,
543*09537850SAkhilesh Sanikop     const uint8_t* source_plane_y, ptrdiff_t source_stride_y,
544*09537850SAkhilesh Sanikop     const uint8_t* source_plane_u, const uint8_t* source_plane_v,
545*09537850SAkhilesh Sanikop     ptrdiff_t source_stride_uv, uint8_t* dest_plane_u, uint8_t* dest_plane_v,
546*09537850SAkhilesh Sanikop     ptrdiff_t dest_stride_uv) {
547*09537850SAkhilesh Sanikop   assert(num_planes > 0);
548*09537850SAkhilesh Sanikop   const int full_jobs_per_plane = height_ / kFrameChunkHeight;
549*09537850SAkhilesh Sanikop   const int remainder_job_height = height_ & (kFrameChunkHeight - 1);
550*09537850SAkhilesh Sanikop   const int total_full_jobs = full_jobs_per_plane * num_planes;
551*09537850SAkhilesh Sanikop   // If the frame height is not a multiple of kFrameChunkHeight, one job with
552*09537850SAkhilesh Sanikop   // a smaller number of rows is necessary at the end of each plane.
553*09537850SAkhilesh Sanikop   const int total_jobs =
554*09537850SAkhilesh Sanikop       total_full_jobs + ((remainder_job_height == 0) ? 0 : num_planes);
555*09537850SAkhilesh Sanikop   int job_index;
556*09537850SAkhilesh Sanikop   // Each job corresponds to a slice of kFrameChunkHeight rows in the luma
557*09537850SAkhilesh Sanikop   // plane. dsp->blend_noise_chroma handles subsampling.
558*09537850SAkhilesh Sanikop   // This loop body handles a slice of one plane or the other, depending on
559*09537850SAkhilesh Sanikop   // which are active. That way, threads working on consecutive jobs will keep
560*09537850SAkhilesh Sanikop   // the same region of luma source in working memory.
561*09537850SAkhilesh Sanikop   while ((job_index = job_counter->fetch_add(1, std::memory_order_relaxed)) <
562*09537850SAkhilesh Sanikop          total_jobs) {
563*09537850SAkhilesh Sanikop     const Plane plane = planes[job_index % num_planes];
564*09537850SAkhilesh Sanikop     const int slice_index = job_index / num_planes;
565*09537850SAkhilesh Sanikop     const int start_height = slice_index * kFrameChunkHeight;
566*09537850SAkhilesh Sanikop     const int job_height = std::min(height_ - start_height, kFrameChunkHeight);
567*09537850SAkhilesh Sanikop 
568*09537850SAkhilesh Sanikop     const auto* source_cursor_y = reinterpret_cast<const Pixel*>(
569*09537850SAkhilesh Sanikop         source_plane_y + start_height * source_stride_y);
570*09537850SAkhilesh Sanikop     const int16_t* scaling_lut_uv;
571*09537850SAkhilesh Sanikop     const uint8_t* source_plane_uv;
572*09537850SAkhilesh Sanikop     uint8_t* dest_plane_uv;
573*09537850SAkhilesh Sanikop 
574*09537850SAkhilesh Sanikop     if (plane == kPlaneU) {
575*09537850SAkhilesh Sanikop       scaling_lut_uv = scaling_lut_u_;
576*09537850SAkhilesh Sanikop       source_plane_uv = source_plane_u;
577*09537850SAkhilesh Sanikop       dest_plane_uv = dest_plane_u;
578*09537850SAkhilesh Sanikop     } else {
579*09537850SAkhilesh Sanikop       assert(plane == kPlaneV);
580*09537850SAkhilesh Sanikop       scaling_lut_uv = scaling_lut_v_;
581*09537850SAkhilesh Sanikop       source_plane_uv = source_plane_v;
582*09537850SAkhilesh Sanikop       dest_plane_uv = dest_plane_v;
583*09537850SAkhilesh Sanikop     }
584*09537850SAkhilesh Sanikop     const auto* source_cursor_uv = reinterpret_cast<const Pixel*>(
585*09537850SAkhilesh Sanikop         source_plane_uv + (start_height >> subsampling_y_) * source_stride_uv);
586*09537850SAkhilesh Sanikop     auto* dest_cursor_uv = reinterpret_cast<Pixel*>(
587*09537850SAkhilesh Sanikop         dest_plane_uv + (start_height >> subsampling_y_) * dest_stride_uv);
588*09537850SAkhilesh Sanikop     dsp.film_grain.blend_noise_chroma[params_.chroma_scaling_from_luma](
589*09537850SAkhilesh Sanikop         plane, params_, noise_image_, min_value, max_chroma, width_, job_height,
590*09537850SAkhilesh Sanikop         start_height, subsampling_x_, subsampling_y_, scaling_lut_uv,
591*09537850SAkhilesh Sanikop         source_cursor_y, source_stride_y, source_cursor_uv, source_stride_uv,
592*09537850SAkhilesh Sanikop         dest_cursor_uv, dest_stride_uv);
593*09537850SAkhilesh Sanikop   }
594*09537850SAkhilesh Sanikop }
595*09537850SAkhilesh Sanikop 
596*09537850SAkhilesh Sanikop template <int bitdepth>
BlendNoiseLumaWorker(const dsp::Dsp & dsp,std::atomic<int> * job_counter,int min_value,int max_luma,const uint8_t * source_plane_y,ptrdiff_t source_stride_y,uint8_t * dest_plane_y,ptrdiff_t dest_stride_y)597*09537850SAkhilesh Sanikop void FilmGrain<bitdepth>::BlendNoiseLumaWorker(
598*09537850SAkhilesh Sanikop     const dsp::Dsp& dsp, std::atomic<int>* job_counter, int min_value,
599*09537850SAkhilesh Sanikop     int max_luma, const uint8_t* source_plane_y, ptrdiff_t source_stride_y,
600*09537850SAkhilesh Sanikop     uint8_t* dest_plane_y, ptrdiff_t dest_stride_y) {
601*09537850SAkhilesh Sanikop   const int total_full_jobs = height_ / kFrameChunkHeight;
602*09537850SAkhilesh Sanikop   const int remainder_job_height = height_ & (kFrameChunkHeight - 1);
603*09537850SAkhilesh Sanikop   const int total_jobs =
604*09537850SAkhilesh Sanikop       total_full_jobs + static_cast<int>(remainder_job_height > 0);
605*09537850SAkhilesh Sanikop   int job_index;
606*09537850SAkhilesh Sanikop   // Each job is some number of rows in a plane.
607*09537850SAkhilesh Sanikop   while ((job_index = job_counter->fetch_add(1, std::memory_order_relaxed)) <
608*09537850SAkhilesh Sanikop          total_jobs) {
609*09537850SAkhilesh Sanikop     const int start_height = job_index * kFrameChunkHeight;
610*09537850SAkhilesh Sanikop     const int job_height = std::min(height_ - start_height, kFrameChunkHeight);
611*09537850SAkhilesh Sanikop 
612*09537850SAkhilesh Sanikop     const auto* source_cursor_y = reinterpret_cast<const Pixel*>(
613*09537850SAkhilesh Sanikop         source_plane_y + start_height * source_stride_y);
614*09537850SAkhilesh Sanikop     auto* dest_cursor_y =
615*09537850SAkhilesh Sanikop         reinterpret_cast<Pixel*>(dest_plane_y + start_height * dest_stride_y);
616*09537850SAkhilesh Sanikop     dsp.film_grain.blend_noise_luma(
617*09537850SAkhilesh Sanikop         noise_image_, min_value, max_luma, params_.chroma_scaling, width_,
618*09537850SAkhilesh Sanikop         job_height, start_height, scaling_lut_y_, source_cursor_y,
619*09537850SAkhilesh Sanikop         source_stride_y, dest_cursor_y, dest_stride_y);
620*09537850SAkhilesh Sanikop   }
621*09537850SAkhilesh Sanikop }
622*09537850SAkhilesh Sanikop 
623*09537850SAkhilesh Sanikop template <int bitdepth>
AddNoise(const uint8_t * source_plane_y,ptrdiff_t source_stride_y,const uint8_t * source_plane_u,const uint8_t * source_plane_v,ptrdiff_t source_stride_uv,uint8_t * dest_plane_y,ptrdiff_t dest_stride_y,uint8_t * dest_plane_u,uint8_t * dest_plane_v,ptrdiff_t dest_stride_uv)624*09537850SAkhilesh Sanikop bool FilmGrain<bitdepth>::AddNoise(
625*09537850SAkhilesh Sanikop     const uint8_t* source_plane_y, ptrdiff_t source_stride_y,
626*09537850SAkhilesh Sanikop     const uint8_t* source_plane_u, const uint8_t* source_plane_v,
627*09537850SAkhilesh Sanikop     ptrdiff_t source_stride_uv, uint8_t* dest_plane_y, ptrdiff_t dest_stride_y,
628*09537850SAkhilesh Sanikop     uint8_t* dest_plane_u, uint8_t* dest_plane_v, ptrdiff_t dest_stride_uv) {
629*09537850SAkhilesh Sanikop   if (!Init()) {
630*09537850SAkhilesh Sanikop     LIBGAV1_DLOG(ERROR, "Init() failed.");
631*09537850SAkhilesh Sanikop     return false;
632*09537850SAkhilesh Sanikop   }
633*09537850SAkhilesh Sanikop   if (!AllocateNoiseStripes()) {
634*09537850SAkhilesh Sanikop     LIBGAV1_DLOG(ERROR, "AllocateNoiseStripes() failed.");
635*09537850SAkhilesh Sanikop     return false;
636*09537850SAkhilesh Sanikop   }
637*09537850SAkhilesh Sanikop 
638*09537850SAkhilesh Sanikop   const dsp::Dsp& dsp = *dsp::GetDspTable(bitdepth);
639*09537850SAkhilesh Sanikop   const bool use_luma = params_.num_y_points > 0;
640*09537850SAkhilesh Sanikop 
641*09537850SAkhilesh Sanikop   // Construct noise stripes.
642*09537850SAkhilesh Sanikop   if (use_luma) {
643*09537850SAkhilesh Sanikop     // The luma plane is never subsampled.
644*09537850SAkhilesh Sanikop     dsp.film_grain
645*09537850SAkhilesh Sanikop         .construct_noise_stripes[static_cast<int>(params_.overlap_flag)](
646*09537850SAkhilesh Sanikop             luma_grain_, params_.grain_seed, width_, height_,
647*09537850SAkhilesh Sanikop             /*subsampling_x=*/0, /*subsampling_y=*/0, &noise_stripes_[kPlaneY]);
648*09537850SAkhilesh Sanikop   }
649*09537850SAkhilesh Sanikop   if (!is_monochrome_) {
650*09537850SAkhilesh Sanikop     dsp.film_grain
651*09537850SAkhilesh Sanikop         .construct_noise_stripes[static_cast<int>(params_.overlap_flag)](
652*09537850SAkhilesh Sanikop             u_grain_, params_.grain_seed, width_, height_, subsampling_x_,
653*09537850SAkhilesh Sanikop             subsampling_y_, &noise_stripes_[kPlaneU]);
654*09537850SAkhilesh Sanikop     dsp.film_grain
655*09537850SAkhilesh Sanikop         .construct_noise_stripes[static_cast<int>(params_.overlap_flag)](
656*09537850SAkhilesh Sanikop             v_grain_, params_.grain_seed, width_, height_, subsampling_x_,
657*09537850SAkhilesh Sanikop             subsampling_y_, &noise_stripes_[kPlaneV]);
658*09537850SAkhilesh Sanikop   }
659*09537850SAkhilesh Sanikop 
660*09537850SAkhilesh Sanikop   if (!AllocateNoiseImage()) {
661*09537850SAkhilesh Sanikop     LIBGAV1_DLOG(ERROR, "AllocateNoiseImage() failed.");
662*09537850SAkhilesh Sanikop     return false;
663*09537850SAkhilesh Sanikop   }
664*09537850SAkhilesh Sanikop 
665*09537850SAkhilesh Sanikop   // Construct noise image.
666*09537850SAkhilesh Sanikop   if (use_luma) {
667*09537850SAkhilesh Sanikop     ConstructNoiseImage(
668*09537850SAkhilesh Sanikop         &noise_stripes_[kPlaneY], width_, height_, /*subsampling_x=*/0,
669*09537850SAkhilesh Sanikop         /*subsampling_y=*/0, static_cast<int>(params_.overlap_flag) << 1,
670*09537850SAkhilesh Sanikop         &noise_image_[kPlaneY]);
671*09537850SAkhilesh Sanikop     if (params_.overlap_flag) {
672*09537850SAkhilesh Sanikop       dsp.film_grain.construct_noise_image_overlap(
673*09537850SAkhilesh Sanikop           &noise_stripes_[kPlaneY], width_, height_, /*subsampling_x=*/0,
674*09537850SAkhilesh Sanikop           /*subsampling_y=*/0, &noise_image_[kPlaneY]);
675*09537850SAkhilesh Sanikop     }
676*09537850SAkhilesh Sanikop   }
677*09537850SAkhilesh Sanikop   if (!is_monochrome_) {
678*09537850SAkhilesh Sanikop     ConstructNoiseImage(&noise_stripes_[kPlaneU], width_, height_,
679*09537850SAkhilesh Sanikop                         subsampling_x_, subsampling_y_,
680*09537850SAkhilesh Sanikop                         static_cast<int>(params_.overlap_flag)
681*09537850SAkhilesh Sanikop                             << (1 - subsampling_y_),
682*09537850SAkhilesh Sanikop                         &noise_image_[kPlaneU]);
683*09537850SAkhilesh Sanikop     ConstructNoiseImage(&noise_stripes_[kPlaneV], width_, height_,
684*09537850SAkhilesh Sanikop                         subsampling_x_, subsampling_y_,
685*09537850SAkhilesh Sanikop                         static_cast<int>(params_.overlap_flag)
686*09537850SAkhilesh Sanikop                             << (1 - subsampling_y_),
687*09537850SAkhilesh Sanikop                         &noise_image_[kPlaneV]);
688*09537850SAkhilesh Sanikop     if (params_.overlap_flag) {
689*09537850SAkhilesh Sanikop       dsp.film_grain.construct_noise_image_overlap(
690*09537850SAkhilesh Sanikop           &noise_stripes_[kPlaneU], width_, height_, subsampling_x_,
691*09537850SAkhilesh Sanikop           subsampling_y_, &noise_image_[kPlaneU]);
692*09537850SAkhilesh Sanikop       dsp.film_grain.construct_noise_image_overlap(
693*09537850SAkhilesh Sanikop           &noise_stripes_[kPlaneV], width_, height_, subsampling_x_,
694*09537850SAkhilesh Sanikop           subsampling_y_, &noise_image_[kPlaneV]);
695*09537850SAkhilesh Sanikop     }
696*09537850SAkhilesh Sanikop   }
697*09537850SAkhilesh Sanikop 
698*09537850SAkhilesh Sanikop   // Blend noise image.
699*09537850SAkhilesh Sanikop   int min_value;
700*09537850SAkhilesh Sanikop   int max_luma;
701*09537850SAkhilesh Sanikop   int max_chroma;
702*09537850SAkhilesh Sanikop   if (params_.clip_to_restricted_range) {
703*09537850SAkhilesh Sanikop     min_value = 16 << (bitdepth - kBitdepth8);
704*09537850SAkhilesh Sanikop     max_luma = 235 << (bitdepth - kBitdepth8);
705*09537850SAkhilesh Sanikop     if (color_matrix_is_identity_) {
706*09537850SAkhilesh Sanikop       max_chroma = max_luma;
707*09537850SAkhilesh Sanikop     } else {
708*09537850SAkhilesh Sanikop       max_chroma = 240 << (bitdepth - kBitdepth8);
709*09537850SAkhilesh Sanikop     }
710*09537850SAkhilesh Sanikop   } else {
711*09537850SAkhilesh Sanikop     min_value = 0;
712*09537850SAkhilesh Sanikop     max_luma = (256 << (bitdepth - kBitdepth8)) - 1;
713*09537850SAkhilesh Sanikop     max_chroma = max_luma;
714*09537850SAkhilesh Sanikop   }
715*09537850SAkhilesh Sanikop 
716*09537850SAkhilesh Sanikop   // Handle all chroma planes first because luma source may be altered in place.
717*09537850SAkhilesh Sanikop   if (!is_monochrome_) {
718*09537850SAkhilesh Sanikop     // This is done in a strange way but Vector can't be passed by copy to the
719*09537850SAkhilesh Sanikop     // lambda capture that spawns the thread.
720*09537850SAkhilesh Sanikop     Plane planes_to_blend[2];
721*09537850SAkhilesh Sanikop     int num_planes = 0;
722*09537850SAkhilesh Sanikop     if (params_.chroma_scaling_from_luma) {
723*09537850SAkhilesh Sanikop       // Both noise planes are computed from the luma scaling lookup table.
724*09537850SAkhilesh Sanikop       planes_to_blend[num_planes++] = kPlaneU;
725*09537850SAkhilesh Sanikop       planes_to_blend[num_planes++] = kPlaneV;
726*09537850SAkhilesh Sanikop     } else {
727*09537850SAkhilesh Sanikop       const int height_uv = SubsampledValue(height_, subsampling_y_);
728*09537850SAkhilesh Sanikop       const int width_uv = SubsampledValue(width_, subsampling_x_);
729*09537850SAkhilesh Sanikop 
730*09537850SAkhilesh Sanikop       // Noise is applied according to a lookup table defined by pieceiwse
731*09537850SAkhilesh Sanikop       // linear "points." If the lookup table is empty, that corresponds to
732*09537850SAkhilesh Sanikop       // outputting zero noise.
733*09537850SAkhilesh Sanikop       if (params_.num_u_points == 0) {
734*09537850SAkhilesh Sanikop         CopyImagePlane<Pixel>(source_plane_u, source_stride_uv, width_uv,
735*09537850SAkhilesh Sanikop                               height_uv, dest_plane_u, dest_stride_uv);
736*09537850SAkhilesh Sanikop       } else {
737*09537850SAkhilesh Sanikop         planes_to_blend[num_planes++] = kPlaneU;
738*09537850SAkhilesh Sanikop       }
739*09537850SAkhilesh Sanikop       if (params_.num_v_points == 0) {
740*09537850SAkhilesh Sanikop         CopyImagePlane<Pixel>(source_plane_v, source_stride_uv, width_uv,
741*09537850SAkhilesh Sanikop                               height_uv, dest_plane_v, dest_stride_uv);
742*09537850SAkhilesh Sanikop       } else {
743*09537850SAkhilesh Sanikop         planes_to_blend[num_planes++] = kPlaneV;
744*09537850SAkhilesh Sanikop       }
745*09537850SAkhilesh Sanikop     }
746*09537850SAkhilesh Sanikop     if (thread_pool_ != nullptr && num_planes > 0) {
747*09537850SAkhilesh Sanikop       const int num_workers = thread_pool_->num_threads();
748*09537850SAkhilesh Sanikop       BlockingCounter pending_workers(num_workers);
749*09537850SAkhilesh Sanikop       std::atomic<int> job_counter(0);
750*09537850SAkhilesh Sanikop       for (int i = 0; i < num_workers; ++i) {
751*09537850SAkhilesh Sanikop         thread_pool_->Schedule([this, dsp, &pending_workers, &planes_to_blend,
752*09537850SAkhilesh Sanikop                                 num_planes, &job_counter, min_value, max_chroma,
753*09537850SAkhilesh Sanikop                                 source_plane_y, source_stride_y, source_plane_u,
754*09537850SAkhilesh Sanikop                                 source_plane_v, source_stride_uv, dest_plane_u,
755*09537850SAkhilesh Sanikop                                 dest_plane_v, dest_stride_uv]() {
756*09537850SAkhilesh Sanikop           BlendNoiseChromaWorker(dsp, planes_to_blend, num_planes, &job_counter,
757*09537850SAkhilesh Sanikop                                  min_value, max_chroma, source_plane_y,
758*09537850SAkhilesh Sanikop                                  source_stride_y, source_plane_u,
759*09537850SAkhilesh Sanikop                                  source_plane_v, source_stride_uv, dest_plane_u,
760*09537850SAkhilesh Sanikop                                  dest_plane_v, dest_stride_uv);
761*09537850SAkhilesh Sanikop           pending_workers.Decrement();
762*09537850SAkhilesh Sanikop         });
763*09537850SAkhilesh Sanikop       }
764*09537850SAkhilesh Sanikop       BlendNoiseChromaWorker(
765*09537850SAkhilesh Sanikop           dsp, planes_to_blend, num_planes, &job_counter, min_value, max_chroma,
766*09537850SAkhilesh Sanikop           source_plane_y, source_stride_y, source_plane_u, source_plane_v,
767*09537850SAkhilesh Sanikop           source_stride_uv, dest_plane_u, dest_plane_v, dest_stride_uv);
768*09537850SAkhilesh Sanikop 
769*09537850SAkhilesh Sanikop       pending_workers.Wait();
770*09537850SAkhilesh Sanikop     } else {
771*09537850SAkhilesh Sanikop       // Single threaded.
772*09537850SAkhilesh Sanikop       if (params_.num_u_points > 0 || params_.chroma_scaling_from_luma) {
773*09537850SAkhilesh Sanikop         dsp.film_grain.blend_noise_chroma[params_.chroma_scaling_from_luma](
774*09537850SAkhilesh Sanikop             kPlaneU, params_, noise_image_, min_value, max_chroma, width_,
775*09537850SAkhilesh Sanikop             height_, /*start_height=*/0, subsampling_x_, subsampling_y_,
776*09537850SAkhilesh Sanikop             scaling_lut_u_, source_plane_y, source_stride_y, source_plane_u,
777*09537850SAkhilesh Sanikop             source_stride_uv, dest_plane_u, dest_stride_uv);
778*09537850SAkhilesh Sanikop       }
779*09537850SAkhilesh Sanikop       if (params_.num_v_points > 0 || params_.chroma_scaling_from_luma) {
780*09537850SAkhilesh Sanikop         dsp.film_grain.blend_noise_chroma[params_.chroma_scaling_from_luma](
781*09537850SAkhilesh Sanikop             kPlaneV, params_, noise_image_, min_value, max_chroma, width_,
782*09537850SAkhilesh Sanikop             height_, /*start_height=*/0, subsampling_x_, subsampling_y_,
783*09537850SAkhilesh Sanikop             scaling_lut_v_, source_plane_y, source_stride_y, source_plane_v,
784*09537850SAkhilesh Sanikop             source_stride_uv, dest_plane_v, dest_stride_uv);
785*09537850SAkhilesh Sanikop       }
786*09537850SAkhilesh Sanikop     }
787*09537850SAkhilesh Sanikop   }
788*09537850SAkhilesh Sanikop   if (use_luma) {
789*09537850SAkhilesh Sanikop     if (thread_pool_ != nullptr) {
790*09537850SAkhilesh Sanikop       const int num_workers = thread_pool_->num_threads();
791*09537850SAkhilesh Sanikop       BlockingCounter pending_workers(num_workers);
792*09537850SAkhilesh Sanikop       std::atomic<int> job_counter(0);
793*09537850SAkhilesh Sanikop       for (int i = 0; i < num_workers; ++i) {
794*09537850SAkhilesh Sanikop         thread_pool_->Schedule(
795*09537850SAkhilesh Sanikop             [this, dsp, &pending_workers, &job_counter, min_value, max_luma,
796*09537850SAkhilesh Sanikop              source_plane_y, source_stride_y, dest_plane_y, dest_stride_y]() {
797*09537850SAkhilesh Sanikop               BlendNoiseLumaWorker(dsp, &job_counter, min_value, max_luma,
798*09537850SAkhilesh Sanikop                                    source_plane_y, source_stride_y,
799*09537850SAkhilesh Sanikop                                    dest_plane_y, dest_stride_y);
800*09537850SAkhilesh Sanikop               pending_workers.Decrement();
801*09537850SAkhilesh Sanikop             });
802*09537850SAkhilesh Sanikop       }
803*09537850SAkhilesh Sanikop 
804*09537850SAkhilesh Sanikop       BlendNoiseLumaWorker(dsp, &job_counter, min_value, max_luma,
805*09537850SAkhilesh Sanikop                            source_plane_y, source_stride_y, dest_plane_y,
806*09537850SAkhilesh Sanikop                            dest_stride_y);
807*09537850SAkhilesh Sanikop       pending_workers.Wait();
808*09537850SAkhilesh Sanikop     } else {
809*09537850SAkhilesh Sanikop       dsp.film_grain.blend_noise_luma(
810*09537850SAkhilesh Sanikop           noise_image_, min_value, max_luma, params_.chroma_scaling, width_,
811*09537850SAkhilesh Sanikop           height_, /*start_height=*/0, scaling_lut_y_, source_plane_y,
812*09537850SAkhilesh Sanikop           source_stride_y, dest_plane_y, dest_stride_y);
813*09537850SAkhilesh Sanikop     }
814*09537850SAkhilesh Sanikop   } else {
815*09537850SAkhilesh Sanikop     CopyImagePlane<Pixel>(source_plane_y, source_stride_y, width_, height_,
816*09537850SAkhilesh Sanikop                           dest_plane_y, dest_stride_y);
817*09537850SAkhilesh Sanikop   }
818*09537850SAkhilesh Sanikop 
819*09537850SAkhilesh Sanikop   return true;
820*09537850SAkhilesh Sanikop }
821*09537850SAkhilesh Sanikop 
822*09537850SAkhilesh Sanikop // Explicit instantiations.
823*09537850SAkhilesh Sanikop template class FilmGrain<kBitdepth8>;
824*09537850SAkhilesh Sanikop #if LIBGAV1_MAX_BITDEPTH >= 10
825*09537850SAkhilesh Sanikop template class FilmGrain<kBitdepth10>;
826*09537850SAkhilesh Sanikop #endif
827*09537850SAkhilesh Sanikop #if LIBGAV1_MAX_BITDEPTH == 12
828*09537850SAkhilesh Sanikop template class FilmGrain<kBitdepth12>;
829*09537850SAkhilesh Sanikop #endif
830*09537850SAkhilesh Sanikop 
831*09537850SAkhilesh Sanikop }  // namespace libgav1
832