Coverage Report

Created: 2026-10-17 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/dav1d/src/lf_mask.c
Line
Count
Source
1
/*
2
 * Copyright © 2018, VideoLAN and dav1d authors
3
 * Copyright © 2018, Two Orioles, LLC
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions are met:
8
 *
9
 * 1. Redistributions of source code must retain the above copyright notice, this
10
 *    list of conditions and the following disclaimer.
11
 *
12
 * 2. Redistributions in binary form must reproduce the above copyright notice,
13
 *    this list of conditions and the following disclaimer in the documentation
14
 *    and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 */
27
28
#include "config.h"
29
30
#include <string.h>
31
32
#include "common/intops.h"
33
34
#include "src/ctx.h"
35
#include "src/levels.h"
36
#include "src/lf_mask.h"
37
#include "src/tables.h"
38
39
static void decomp_tx(uint8_t (*const txa)[2 /* txsz, step */][32 /* y */][32 /* x */],
40
                      const enum RectTxfmSize from,
41
                      const int depth,
42
                      const int y_off, const int x_off,
43
                      const uint16_t *const tx_masks)
44
2.09M
{
45
2.09M
    const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[from];
46
2.09M
    const int is_split = (from == (int) TX_4X4 || depth > 1) ? 0 :
47
2.09M
        (tx_masks[depth] >> (y_off * 4 + x_off)) & 1;
48
49
2.09M
    if (is_split) {
50
125k
        const enum RectTxfmSize sub = t_dim->sub;
51
125k
        const int htw4 = t_dim->w >> 1, hth4 = t_dim->h >> 1;
52
53
125k
        decomp_tx(txa, sub, depth + 1, y_off * 2 + 0, x_off * 2 + 0, tx_masks);
54
125k
        if (t_dim->w >= t_dim->h)
55
94.1k
            decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][0][htw4],
56
94.1k
                      sub, depth + 1, y_off * 2 + 0, x_off * 2 + 1, tx_masks);
57
125k
        if (t_dim->h >= t_dim->w) {
58
93.0k
            decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][hth4][0],
59
93.0k
                      sub, depth + 1, y_off * 2 + 1, x_off * 2 + 0, tx_masks);
60
93.0k
            if (t_dim->w >= t_dim->h)
61
61.3k
                decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][hth4][htw4],
62
61.3k
                          sub, depth + 1, y_off * 2 + 1, x_off * 2 + 1, tx_masks);
63
93.0k
        }
64
1.96M
    } else {
65
1.96M
        const int lw = imin(2, t_dim->lw), lh = imin(2, t_dim->lh);
66
67
1.96M
#define set_ctx(rep_macro) \
68
8.91M
        for (int y = 0; y < t_dim->h; y++) { \
69
6.95M
            rep_macro(txa[0][0][y], 0, lw); \
70
6.95M
            rep_macro(txa[1][0][y], 0, lh); \
71
6.95M
            txa[0][1][y][0] = t_dim->w; \
72
6.95M
        }
73
1.96M
        case_set_upto16(t_dim->lw);
74
1.96M
#undef set_ctx
75
1.96M
        dav1d_memset_pow2[t_dim->lw](txa[1][1][0], t_dim->h);
76
1.96M
    }
77
2.09M
}
78
79
static inline void mask_edges_inter(uint16_t (*const masks)[32][3][2],
80
                                    const int by4, const int bx4,
81
                                    const int w4, const int h4, const int skip,
82
                                    const enum RectTxfmSize max_tx,
83
                                    const uint16_t *const tx_masks,
84
                                    uint8_t *const a, uint8_t *const l)
85
1.25M
{
86
1.25M
    const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[max_tx];
87
1.25M
    int y, x;
88
89
1.25M
    ALIGN_STK_16(uint8_t, txa, 2 /* edge */, [2 /* txsz, step */][32 /* y */][32 /* x */]);
90
2.61M
    for (int y_off = 0, y = 0; y < h4; y += t_dim->h, y_off++)
91
3.07M
        for (int x_off = 0, x = 0; x < w4; x += t_dim->w, x_off++)
92
1.71M
            decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][y][x],
93
1.71M
                      max_tx, 0, y_off, x_off, tx_masks);
94
95
    // left block edge
96
1.25M
    unsigned mask = 1U << by4;
97
6.68M
    for (y = 0; y < h4; y++, mask <<= 1) {
98
5.42M
        const int sidx = mask >= 0x10000;
99
5.42M
        const unsigned smask = mask >> (sidx << 4);
100
5.42M
        masks[0][bx4][imin(txa[0][0][y][0], l[y])][sidx] |= smask;
101
5.42M
    }
102
103
    // top block edge
104
5.36M
    for (x = 0, mask = 1U << bx4; x < w4; x++, mask <<= 1) {
105
4.10M
        const int sidx = mask >= 0x10000;
106
4.10M
        const unsigned smask = mask >> (sidx << 4);
107
4.10M
        masks[1][by4][imin(txa[1][0][0][x], a[x])][sidx] |= smask;
108
4.10M
    }
109
110
1.25M
    if (!skip) {
111
        // inner (tx) left|right edges
112
3.99M
        for (y = 0, mask = 1U << by4; y < h4; y++, mask <<= 1) {
113
3.21M
            const int sidx = mask >= 0x10000U;
114
3.21M
            const unsigned smask = mask >> (sidx << 4);
115
3.21M
            int ltx = txa[0][0][y][0];
116
3.21M
            int step = txa[0][1][y][0];
117
3.75M
            for (x = step; x < w4; x += step) {
118
535k
                const int rtx = txa[0][0][y][x];
119
535k
                masks[0][bx4 + x][imin(rtx, ltx)][sidx] |= smask;
120
535k
                ltx = rtx;
121
535k
                step = txa[0][1][y][x];
122
535k
            }
123
3.21M
        }
124
125
        //            top
126
        // inner (tx) --- edges
127
        //           bottom
128
3.35M
        for (x = 0, mask = 1U << bx4; x < w4; x++, mask <<= 1) {
129
2.57M
            const int sidx = mask >= 0x10000U;
130
2.57M
            const unsigned smask = mask >> (sidx << 4);
131
2.57M
            int ttx = txa[1][0][0][x];
132
2.57M
            int step = txa[1][1][0][x];
133
3.14M
            for (y = step; y < h4; y += step) {
134
570k
                const int btx = txa[1][0][y][x];
135
570k
                masks[1][by4 + y][imin(ttx, btx)][sidx] |= smask;
136
570k
                ttx = btx;
137
570k
                step = txa[1][1][y][x];
138
570k
            }
139
2.57M
        }
140
781k
    }
141
142
6.68M
    for (y = 0; y < h4; y++)
143
5.42M
        l[y] = txa[0][0][y][w4 - 1];
144
1.25M
    memcpy(a, txa[1][0][h4 - 1], w4);
145
1.25M
}
146
147
static inline void mask_edges_intra(uint16_t (*const masks)[32][3][2],
148
                                    const int by4, const int bx4,
149
                                    const int w4, const int h4,
150
                                    const enum RectTxfmSize tx,
151
                                    uint8_t *const a, uint8_t *const l)
152
2.59M
{
153
2.59M
    const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[tx];
154
2.59M
    const int twl4 = t_dim->lw, thl4 = t_dim->lh;
155
2.59M
    const int twl4c = imin(2, twl4), thl4c = imin(2, thl4);
156
2.59M
    int y, x;
157
158
    // left block edge
159
2.59M
    unsigned mask = 1U << by4;
160
15.1M
    for (y = 0; y < h4; y++, mask <<= 1) {
161
12.5M
        const int sidx = mask >= 0x10000;
162
12.5M
        const unsigned smask = mask >> (sidx << 4);
163
12.5M
        masks[0][bx4][imin(twl4c, l[y])][sidx] |= smask;
164
12.5M
    }
165
166
    // top block edge
167
13.7M
    for (x = 0, mask = 1U << bx4; x < w4; x++, mask <<= 1) {
168
11.1M
        const int sidx = mask >= 0x10000;
169
11.1M
        const unsigned smask = mask >> (sidx << 4);
170
11.1M
        masks[1][by4][imin(thl4c, a[x])][sidx] |= smask;
171
11.1M
    }
172
173
    // inner (tx) left|right edges
174
2.59M
    const int hstep = t_dim->w;
175
2.59M
    unsigned t = 1U << by4;
176
2.59M
    unsigned inner = (unsigned) ((((uint64_t) t) << h4) - t);
177
2.59M
    unsigned inner1 = inner & 0xffff, inner2 = inner >> 16;
178
3.12M
    for (x = hstep; x < w4; x += hstep) {
179
525k
        if (inner1) masks[0][bx4 + x][twl4c][0] |= inner1;
180
525k
        if (inner2) masks[0][bx4 + x][twl4c][1] |= inner2;
181
525k
    }
182
183
    //            top
184
    // inner (tx) --- edges
185
    //           bottom
186
2.59M
    const int vstep = t_dim->h;
187
2.59M
    t = 1U << bx4;
188
2.59M
    inner = (unsigned) ((((uint64_t) t) << w4) - t);
189
2.59M
    inner1 = inner & 0xffff;
190
2.59M
    inner2 = inner >> 16;
191
3.27M
    for (y = vstep; y < h4; y += vstep) {
192
677k
        if (inner1) masks[1][by4 + y][thl4c][0] |= inner1;
193
677k
        if (inner2) masks[1][by4 + y][thl4c][1] |= inner2;
194
677k
    }
195
196
2.59M
    dav1d_memset_likely_pow2(a, thl4c, w4);
197
2.59M
    dav1d_memset_likely_pow2(l, twl4c, h4);
198
2.59M
}
199
200
static void mask_edges_chroma(uint16_t (*const masks)[32][2][2],
201
                              const int cby4, const int cbx4,
202
                              const int cw4, const int ch4,
203
                              const int skip_inter,
204
                              const enum RectTxfmSize tx,
205
                              uint8_t *const a, uint8_t *const l,
206
                              const int ss_hor, const int ss_ver)
207
2.92M
{
208
2.92M
    const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[tx];
209
2.92M
    const int twl4 = t_dim->lw, thl4 = t_dim->lh;
210
2.92M
    const int twl4c = !!twl4, thl4c = !!thl4;
211
2.92M
    int y, x;
212
2.92M
    const int vbits = 4 - ss_ver, hbits = 4 - ss_hor;
213
2.92M
    const int vmask = 16 >> ss_ver, hmask = 16 >> ss_hor;
214
2.92M
    const unsigned vmax = 1 << vmask, hmax = 1 << hmask;
215
216
    // left block edge
217
2.92M
    unsigned mask = 1U << cby4;
218
13.6M
    for (y = 0; y < ch4; y++, mask <<= 1) {
219
10.7M
        const int sidx = mask >= vmax;
220
10.7M
        const unsigned smask = mask >> (sidx << vbits);
221
10.7M
        masks[0][cbx4][imin(twl4c, l[y])][sidx] |= smask;
222
10.7M
    }
223
224
    // top block edge
225
12.4M
    for (x = 0, mask = 1U << cbx4; x < cw4; x++, mask <<= 1) {
226
9.55M
        const int sidx = mask >= hmax;
227
9.55M
        const unsigned smask = mask >> (sidx << hbits);
228
9.55M
        masks[1][cby4][imin(thl4c, a[x])][sidx] |= smask;
229
9.55M
    }
230
231
2.92M
    if (!skip_inter) {
232
        // inner (tx) left|right edges
233
2.62M
        const int hstep = t_dim->w;
234
2.62M
        unsigned t = 1U << cby4;
235
2.62M
        unsigned inner = (unsigned) ((((uint64_t) t) << ch4) - t);
236
2.62M
        unsigned inner1 = inner & ((1 << vmask) - 1), inner2 = inner >> vmask;
237
2.91M
        for (x = hstep; x < cw4; x += hstep) {
238
294k
            if (inner1) masks[0][cbx4 + x][twl4c][0] |= inner1;
239
294k
            if (inner2) masks[0][cbx4 + x][twl4c][1] |= inner2;
240
294k
        }
241
242
        //            top
243
        // inner (tx) --- edges
244
        //           bottom
245
2.62M
        const int vstep = t_dim->h;
246
2.62M
        t = 1U << cbx4;
247
2.62M
        inner = (unsigned) ((((uint64_t) t) << cw4) - t);
248
2.62M
        inner1 = inner & ((1 << hmask) - 1), inner2 = inner >> hmask;
249
2.99M
        for (y = vstep; y < ch4; y += vstep) {
250
368k
            if (inner1) masks[1][cby4 + y][thl4c][0] |= inner1;
251
368k
            if (inner2) masks[1][cby4 + y][thl4c][1] |= inner2;
252
368k
        }
253
2.62M
    }
254
255
2.92M
    dav1d_memset_likely_pow2(a, thl4c, cw4);
256
2.92M
    dav1d_memset_likely_pow2(l, twl4c, ch4);
257
2.92M
}
258
259
static void fill_levelcache_block(uint8_t (*level_cache_ptr)[4],
260
                                  const ptrdiff_t b_stride,
261
                                  const int bw, const int bh,
262
                                  const unsigned v0,
263
                                  const unsigned v1)
264
6.77M
{
265
6.77M
    union alias16 v = (union alias16) { .u8 = { v0, v1 }};
266
267
35.3M
    for (int y = 0; y < bh; y++) {
268
221M
        for (int x = 0; x < bw; x++)
269
192M
            ((union alias16 *) &level_cache_ptr[x][0])->u16 = v.u16;
270
28.5M
        level_cache_ptr += b_stride;
271
28.5M
    }
272
6.77M
}
273
274
void dav1d_create_lf_mask_intra(Av1Filter *const lflvl,
275
                                uint8_t (*const level_cache)[4],
276
                                const ptrdiff_t b4_stride,
277
                                const uint8_t (*filter_level)[8][2],
278
                                const int bx, const int by,
279
                                const int iw, const int ih,
280
                                const enum BlockSize bs,
281
                                const enum RectTxfmSize ytx,
282
                                const enum RectTxfmSize uvtx,
283
                                const enum Dav1dPixelLayout layout,
284
                                uint8_t *const ay, uint8_t *const ly,
285
                                uint8_t *const auv, uint8_t *const luv)
286
2.89M
{
287
2.89M
    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
288
2.89M
    const int bw4 = imin(iw - bx, b_dim[0]);
289
2.89M
    const int bh4 = imin(ih - by, b_dim[1]);
290
2.89M
    const int bx4 = bx & 31;
291
2.89M
    const int by4 = by & 31;
292
2.89M
    assert(bw4 >= 0 && bh4 >= 0);
293
294
2.89M
    if (bw4 && bh4) {
295
2.59M
        uint8_t (*level_cache_ptr)[4] = level_cache + by * b4_stride + bx;
296
297
2.59M
        fill_levelcache_block(level_cache_ptr, b4_stride, bw4, bh4,
298
2.59M
                              filter_level[0][0][0], filter_level[1][0][0]);
299
2.59M
        mask_edges_intra(lflvl->filter_y, by4, bx4, bw4, bh4, ytx, ay, ly);
300
2.59M
    }
301
302
2.89M
    if (!auv) return;
303
304
2.25M
    const int ss_ver = layout == DAV1D_PIXEL_LAYOUT_I420;
305
2.25M
    const int ss_hor = layout != DAV1D_PIXEL_LAYOUT_I444;
306
2.25M
    const int cbw4 = imin(((iw + ss_hor) >> ss_hor) - (bx >> ss_hor),
307
2.25M
                          (b_dim[0] + ss_hor) >> ss_hor);
308
2.25M
    const int cbh4 = imin(((ih + ss_ver) >> ss_ver) - (by >> ss_ver),
309
2.25M
                          (b_dim[1] + ss_ver) >> ss_ver);
310
2.25M
    assert(cbw4 >= 0 && cbh4 >= 0);
311
312
2.25M
    if (!cbw4 || !cbh4) return;
313
314
2.03M
    const int cbx4 = bx4 >> ss_hor;
315
2.03M
    const int cby4 = by4 >> ss_ver;
316
317
2.03M
    uint8_t (*level_cache_ptr)[4] =
318
2.03M
        level_cache + (by >> ss_ver) * b4_stride + (bx >> ss_hor);
319
320
2.03M
    fill_levelcache_block((uint8_t(*)[4]) &level_cache_ptr[0][2], b4_stride,
321
2.03M
                          cbw4, cbh4, filter_level[2][0][0],
322
2.03M
                          filter_level[3][0][0]);
323
2.03M
    mask_edges_chroma(lflvl->filter_uv, cby4, cbx4, cbw4, cbh4, 0, uvtx,
324
2.03M
                      auv, luv, ss_hor, ss_ver);
325
2.03M
}
326
327
void dav1d_create_lf_mask_inter(Av1Filter *const lflvl,
328
                                uint8_t (*const level_cache)[4],
329
                                const ptrdiff_t b4_stride,
330
                                const uint8_t (*filter_level)[8][2],
331
                                const int bx, const int by,
332
                                const int iw, const int ih,
333
                                const int skip, const enum BlockSize bs,
334
                                const enum RectTxfmSize max_ytx,
335
                                const uint16_t *const tx_masks,
336
                                const enum RectTxfmSize uvtx,
337
                                const enum Dav1dPixelLayout layout,
338
                                uint8_t *const ay, uint8_t *const ly,
339
                                uint8_t *const auv, uint8_t *const luv)
340
1.33M
{
341
1.33M
    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
342
1.33M
    const int bw4 = imin(iw - bx, b_dim[0]);
343
1.33M
    const int bh4 = imin(ih - by, b_dim[1]);
344
1.33M
    const int bx4 = bx & 31;
345
1.33M
    const int by4 = by & 31;
346
1.33M
    assert(bw4 >= 0 && bh4 >= 0);
347
348
1.33M
    if (bw4 && bh4) {
349
1.25M
        uint8_t (*level_cache_ptr)[4] = level_cache + by * b4_stride + bx;
350
351
1.25M
        fill_levelcache_block(level_cache_ptr, b4_stride, bw4, bh4,
352
1.25M
                              filter_level[0][0][0], filter_level[1][0][0]);
353
1.25M
        mask_edges_inter(lflvl->filter_y, by4, bx4, bw4, bh4, skip,
354
1.25M
                         max_ytx, tx_masks, ay, ly);
355
1.25M
    }
356
357
1.33M
    if (!auv) return;
358
359
888k
    const int ss_ver = layout == DAV1D_PIXEL_LAYOUT_I420;
360
888k
    const int ss_hor = layout != DAV1D_PIXEL_LAYOUT_I444;
361
888k
    const int cbw4 = imin(((iw + ss_hor) >> ss_hor) - (bx >> ss_hor),
362
888k
                          (b_dim[0] + ss_hor) >> ss_hor);
363
888k
    const int cbh4 = imin(((ih + ss_ver) >> ss_ver) - (by >> ss_ver),
364
888k
                          (b_dim[1] + ss_ver) >> ss_ver);
365
888k
    assert(cbw4 >= 0 && cbh4 >= 0);
366
367
888k
    if (!cbw4 || !cbh4) return;
368
369
876k
    const int cbx4 = bx4 >> ss_hor;
370
876k
    const int cby4 = by4 >> ss_ver;
371
372
876k
    uint8_t (*level_cache_ptr)[4] =
373
876k
        level_cache + (by >> ss_ver) * b4_stride + (bx >> ss_hor);
374
375
876k
    fill_levelcache_block((uint8_t(*)[4]) &level_cache_ptr[0][2], b4_stride,
376
876k
                          cbw4, cbh4, filter_level[2][0][0],
377
876k
                          filter_level[3][0][0]);
378
876k
    mask_edges_chroma(lflvl->filter_uv, cby4, cbx4, cbw4, cbh4, skip, uvtx,
379
876k
                      auv, luv, ss_hor, ss_ver);
380
876k
}
381
382
196k
void dav1d_calc_eih(Av1FilterLUT *const lim_lut, const int filter_sharpness) {
383
    // set E/I/H values from loopfilter level
384
196k
    const int sharp = filter_sharpness;
385
12.7M
    for (int level = 0; level < 64; level++) {
386
12.5M
        int limit = level;
387
388
12.5M
        if (sharp > 0) {
389
7.58M
            limit >>= (sharp + 3) >> 2;
390
7.58M
            limit = imin(limit, 9 - sharp);
391
7.58M
        }
392
12.5M
        limit = imax(limit, 1);
393
394
12.5M
        lim_lut->i[level] = limit;
395
12.5M
        lim_lut->e[level] = 2 * (level + 2) + limit;
396
12.5M
    }
397
196k
    lim_lut->sharp[0] = (sharp + 3) >> 2;
398
196k
    lim_lut->sharp[1] = sharp ? 9 - sharp : 0xff;
399
196k
}
400
401
static void calc_lf_value(uint8_t (*const lflvl_values)[2],
402
                          const int base_lvl, const int lf_delta,
403
                          const int seg_delta,
404
                          const Dav1dLoopfilterModeRefDeltas *const mr_delta)
405
3.99M
{
406
3.99M
    const int base = iclip(iclip(base_lvl + lf_delta, 0, 63) + seg_delta, 0, 63);
407
408
3.99M
    if (!mr_delta) {
409
3.10M
        memset(lflvl_values, base, sizeof(*lflvl_values) * 8);
410
3.10M
    } else {
411
899k
        const int sh = base >= 32;
412
899k
        lflvl_values[0][0] = lflvl_values[0][1] =
413
899k
            iclip(base + (mr_delta->ref_delta[0] * (1 << sh)), 0, 63);
414
7.19M
        for (int r = 1; r < 8; r++) {
415
18.8M
            for (int m = 0; m < 2; m++) {
416
12.5M
                const int delta =
417
12.5M
                    mr_delta->mode_delta[m] + mr_delta->ref_delta[r];
418
12.5M
                lflvl_values[r][m] = iclip(base + (delta * (1 << sh)), 0, 63);
419
12.5M
            }
420
6.29M
        }
421
899k
    }
422
3.99M
}
423
424
static inline void calc_lf_value_chroma(uint8_t (*const lflvl_values)[2],
425
                                        const int base_lvl, const int lf_delta,
426
                                        const int seg_delta,
427
                                        const Dav1dLoopfilterModeRefDeltas *const mr_delta)
428
2.29M
{
429
2.29M
    if (!base_lvl)
430
585k
        memset(lflvl_values, 0, sizeof(*lflvl_values) * 8);
431
1.70M
    else
432
1.70M
        calc_lf_value(lflvl_values, base_lvl, lf_delta, seg_delta, mr_delta);
433
2.29M
}
434
435
void dav1d_calc_lf_values(uint8_t (*const lflvl_values)[4][8][2],
436
                          const Dav1dFrameHeader *const hdr,
437
                          const int8_t lf_delta[4])
438
367k
{
439
367k
    const int n_seg = hdr->segmentation.enabled ? 8 : 1;
440
441
367k
    if (!hdr->loopfilter.level_y[0] && !hdr->loopfilter.level_y[1]) {
442
53.3k
        memset(lflvl_values, 0, sizeof(*lflvl_values) * n_seg);
443
53.3k
        return;
444
53.3k
    }
445
446
314k
    const Dav1dLoopfilterModeRefDeltas *const mr_deltas =
447
314k
        hdr->loopfilter.mode_ref_delta_enabled ?
448
314k
        &hdr->loopfilter.mode_ref_deltas : NULL;
449
1.46M
    for (int s = 0; s < n_seg; s++) {
450
1.14M
        const Dav1dSegmentationData *const segd =
451
1.14M
            hdr->segmentation.enabled ? &hdr->segmentation.seg_data.d[s] : NULL;
452
453
1.14M
        calc_lf_value(lflvl_values[s][0], hdr->loopfilter.level_y[0],
454
1.14M
                      lf_delta[0], segd ? segd->delta_lf_y_v : 0, mr_deltas);
455
1.14M
        calc_lf_value(lflvl_values[s][1], hdr->loopfilter.level_y[1],
456
1.14M
                      lf_delta[hdr->delta.lf.multi ? 1 : 0],
457
1.14M
                      segd ? segd->delta_lf_y_h : 0, mr_deltas);
458
1.14M
        calc_lf_value_chroma(lflvl_values[s][2], hdr->loopfilter.level_u,
459
1.14M
                             lf_delta[hdr->delta.lf.multi ? 2 : 0],
460
1.14M
                             segd ? segd->delta_lf_u : 0, mr_deltas);
461
1.14M
        calc_lf_value_chroma(lflvl_values[s][3], hdr->loopfilter.level_v,
462
1.14M
                             lf_delta[hdr->delta.lf.multi ? 3 : 0],
463
1.14M
                             segd ? segd->delta_lf_v : 0, mr_deltas);
464
1.14M
    }
465
314k
}