xref: /aosp_15_r20/external/libdav1d/src/fg_apply_tmpl.c (revision c09093415860a1c2373dacd84c4fde00c507cdfd)
1 /*
2  * Copyright © 2018, Niklas Haas
3  * Copyright © 2018, VideoLAN and dav1d authors
4  * Copyright © 2018, Two Orioles, LLC
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice, this
11  *    list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  *    this list of conditions and the following disclaimer in the documentation
15  *    and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "config.h"
30 
31 #include <stdint.h>
32 
33 #include "dav1d/common.h"
34 #include "dav1d/picture.h"
35 
36 #include "common/intops.h"
37 #include "common/bitdepth.h"
38 
39 #include "src/fg_apply.h"
40 
generate_scaling(const int bitdepth,const uint8_t points[][2],const int num,uint8_t scaling[SCALING_SIZE])41 static void generate_scaling(const int bitdepth,
42                              const uint8_t points[][2], const int num,
43                              uint8_t scaling[SCALING_SIZE])
44 {
45 #if BITDEPTH == 8
46     const int shift_x = 0;
47     const int scaling_size = SCALING_SIZE;
48 #else
49     assert(bitdepth > 8);
50     const int shift_x = bitdepth - 8;
51     const int scaling_size = 1 << bitdepth;
52 #endif
53 
54     if (num == 0) {
55         memset(scaling, 0, scaling_size);
56         return;
57     }
58 
59     // Fill up the preceding entries with the initial value
60     memset(scaling, points[0][1], points[0][0] << shift_x);
61 
62     // Linearly interpolate the values in the middle
63     for (int i = 0; i < num - 1; i++) {
64         const int bx = points[i][0];
65         const int by = points[i][1];
66         const int ex = points[i+1][0];
67         const int ey = points[i+1][1];
68         const int dx = ex - bx;
69         const int dy = ey - by;
70         assert(dx > 0);
71         const int delta = dy * ((0x10000 + (dx >> 1)) / dx);
72         for (int x = 0, d = 0x8000; x < dx; x++) {
73             scaling[(bx + x) << shift_x] = by + (d >> 16);
74             d += delta;
75         }
76     }
77 
78     // Fill up the remaining entries with the final value
79     const int n = points[num - 1][0] << shift_x;
80     memset(&scaling[n], points[num - 1][1], scaling_size - n);
81 
82 #if BITDEPTH != 8
83     const int pad = 1 << shift_x, rnd = pad >> 1;
84     for (int i = 0; i < num - 1; i++) {
85         const int bx = points[i][0] << shift_x;
86         const int ex = points[i+1][0] << shift_x;
87         const int dx = ex - bx;
88         for (int x = 0; x < dx; x += pad) {
89             const int range = scaling[bx + x + pad] - scaling[bx + x];
90             for (int n = 1, r = rnd; n < pad; n++) {
91                 r += range;
92                 scaling[bx + x + n] = scaling[bx + x] + (r >> shift_x);
93             }
94         }
95     }
96 #endif
97 }
98 
99 #ifndef UNIT_TEST
bitfn(dav1d_prep_grain)100 void bitfn(dav1d_prep_grain)(const Dav1dFilmGrainDSPContext *const dsp,
101                              Dav1dPicture *const out,
102                              const Dav1dPicture *const in,
103                              uint8_t scaling[3][SCALING_SIZE],
104                              entry grain_lut[3][GRAIN_HEIGHT+1][GRAIN_WIDTH])
105 {
106     const Dav1dFilmGrainData *const data = &out->frame_hdr->film_grain.data;
107 #if BITDEPTH != 8
108     const int bitdepth_max = (1 << out->p.bpc) - 1;
109 #endif
110 
111     // Generate grain LUTs as needed
112     dsp->generate_grain_y(grain_lut[0], data HIGHBD_TAIL_SUFFIX); // always needed
113     if (data->num_uv_points[0] || data->chroma_scaling_from_luma)
114         dsp->generate_grain_uv[in->p.layout - 1](grain_lut[1], grain_lut[0],
115                                                  data, 0 HIGHBD_TAIL_SUFFIX);
116     if (data->num_uv_points[1] || data->chroma_scaling_from_luma)
117         dsp->generate_grain_uv[in->p.layout - 1](grain_lut[2], grain_lut[0],
118                                                  data, 1 HIGHBD_TAIL_SUFFIX);
119 
120     // Generate scaling LUTs as needed
121     if (data->num_y_points || data->chroma_scaling_from_luma)
122         generate_scaling(in->p.bpc, data->y_points, data->num_y_points, scaling[0]);
123     if (data->num_uv_points[0])
124         generate_scaling(in->p.bpc, data->uv_points[0], data->num_uv_points[0], scaling[1]);
125     if (data->num_uv_points[1])
126         generate_scaling(in->p.bpc, data->uv_points[1], data->num_uv_points[1], scaling[2]);
127 
128     // Copy over the non-modified planes
129     assert(out->stride[0] == in->stride[0]);
130     if (!data->num_y_points) {
131         const ptrdiff_t stride = out->stride[0];
132         const ptrdiff_t sz = out->p.h * stride;
133         if (sz < 0)
134             memcpy((uint8_t*) out->data[0] + sz - stride,
135                    (uint8_t*) in->data[0] + sz - stride, -sz);
136         else
137             memcpy(out->data[0], in->data[0], sz);
138     }
139 
140     if (in->p.layout != DAV1D_PIXEL_LAYOUT_I400 && !data->chroma_scaling_from_luma) {
141         assert(out->stride[1] == in->stride[1]);
142         const int ss_ver = in->p.layout == DAV1D_PIXEL_LAYOUT_I420;
143         const ptrdiff_t stride = out->stride[1];
144         const ptrdiff_t sz = ((out->p.h + ss_ver) >> ss_ver) * stride;
145         if (sz < 0) {
146             if (!data->num_uv_points[0])
147                 memcpy((uint8_t*) out->data[1] + sz - stride,
148                        (uint8_t*) in->data[1] + sz - stride, -sz);
149             if (!data->num_uv_points[1])
150                 memcpy((uint8_t*) out->data[2] + sz - stride,
151                        (uint8_t*) in->data[2] + sz - stride, -sz);
152         } else {
153             if (!data->num_uv_points[0])
154                 memcpy(out->data[1], in->data[1], sz);
155             if (!data->num_uv_points[1])
156                 memcpy(out->data[2], in->data[2], sz);
157         }
158     }
159 }
160 
bitfn(dav1d_apply_grain_row)161 void bitfn(dav1d_apply_grain_row)(const Dav1dFilmGrainDSPContext *const dsp,
162                                   Dav1dPicture *const out,
163                                   const Dav1dPicture *const in,
164                                   const uint8_t scaling[3][SCALING_SIZE],
165                                   const entry grain_lut[3][GRAIN_HEIGHT+1][GRAIN_WIDTH],
166                                   const int row)
167 {
168     // Synthesize grain for the affected planes
169     const Dav1dFilmGrainData *const data = &out->frame_hdr->film_grain.data;
170     const int ss_y = in->p.layout == DAV1D_PIXEL_LAYOUT_I420;
171     const int ss_x = in->p.layout != DAV1D_PIXEL_LAYOUT_I444;
172     const int cpw = (out->p.w + ss_x) >> ss_x;
173     const int is_id = out->seq_hdr->mtrx == DAV1D_MC_IDENTITY;
174     pixel *const luma_src =
175         ((pixel *) in->data[0]) + row * FG_BLOCK_SIZE * PXSTRIDE(in->stride[0]);
176 #if BITDEPTH != 8
177     const int bitdepth_max = (1 << out->p.bpc) - 1;
178 #endif
179 
180     if (data->num_y_points) {
181         const int bh = imin(out->p.h - row * FG_BLOCK_SIZE, FG_BLOCK_SIZE);
182         dsp->fgy_32x32xn(((pixel *) out->data[0]) + row * FG_BLOCK_SIZE * PXSTRIDE(out->stride[0]),
183                          luma_src, out->stride[0], data,
184                          out->p.w, scaling[0], grain_lut[0], bh, row HIGHBD_TAIL_SUFFIX);
185     }
186 
187     if (!data->num_uv_points[0] && !data->num_uv_points[1] &&
188         !data->chroma_scaling_from_luma)
189     {
190         return;
191     }
192 
193     const int bh = (imin(out->p.h - row * FG_BLOCK_SIZE, FG_BLOCK_SIZE) + ss_y) >> ss_y;
194 
195     // extend padding pixels
196     if (out->p.w & ss_x) {
197         pixel *ptr = luma_src;
198         for (int y = 0; y < bh; y++) {
199             ptr[out->p.w] = ptr[out->p.w - 1];
200             ptr += PXSTRIDE(in->stride[0]) << ss_y;
201         }
202     }
203 
204     const ptrdiff_t uv_off = row * FG_BLOCK_SIZE * PXSTRIDE(out->stride[1]) >> ss_y;
205     if (data->chroma_scaling_from_luma) {
206         for (int pl = 0; pl < 2; pl++)
207             dsp->fguv_32x32xn[in->p.layout - 1](((pixel *) out->data[1 + pl]) + uv_off,
208                                                 ((const pixel *) in->data[1 + pl]) + uv_off,
209                                                 in->stride[1], data, cpw,
210                                                 scaling[0], grain_lut[1 + pl],
211                                                 bh, row, luma_src, in->stride[0],
212                                                 pl, is_id HIGHBD_TAIL_SUFFIX);
213     } else {
214         for (int pl = 0; pl < 2; pl++)
215             if (data->num_uv_points[pl])
216                 dsp->fguv_32x32xn[in->p.layout - 1](((pixel *) out->data[1 + pl]) + uv_off,
217                                                     ((const pixel *) in->data[1 + pl]) + uv_off,
218                                                     in->stride[1], data, cpw,
219                                                     scaling[1 + pl], grain_lut[1 + pl],
220                                                     bh, row, luma_src, in->stride[0],
221                                                     pl, is_id HIGHBD_TAIL_SUFFIX);
222     }
223 }
224 
bitfn(dav1d_apply_grain)225 void bitfn(dav1d_apply_grain)(const Dav1dFilmGrainDSPContext *const dsp,
226                               Dav1dPicture *const out,
227                               const Dav1dPicture *const in)
228 {
229     ALIGN_STK_16(entry, grain_lut, 3,[GRAIN_HEIGHT + 1][GRAIN_WIDTH]);
230 #if ARCH_X86_64 && BITDEPTH == 8
231     ALIGN_STK_64(uint8_t, scaling, 3,[SCALING_SIZE]);
232 #else
233     uint8_t scaling[3][SCALING_SIZE];
234 #endif
235     const int rows = (out->p.h + FG_BLOCK_SIZE - 1) / FG_BLOCK_SIZE;
236 
237     bitfn(dav1d_prep_grain)(dsp, out, in, scaling, grain_lut);
238     for (int row = 0; row < rows; row++)
239         bitfn(dav1d_apply_grain_row)(dsp, out, in, scaling, grain_lut, row);
240 }
241 #endif
242