Coverage Report

Created: 2026-09-13 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/dav1d/src/refmvs.c
Line
Count
Source
1
/*
2
 * Copyright © 2020, VideoLAN and dav1d authors
3
 * Copyright © 2020, 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 <limits.h>
31
#include <stdlib.h>
32
33
#include "dav1d/common.h"
34
35
#include "common/intops.h"
36
37
#include "src/env.h"
38
#include "src/mem.h"
39
#include "src/refmvs.h"
40
41
static void add_spatial_candidate(refmvs_candidate *const mvstack, int *const cnt,
42
                                  const int weight, const refmvs_block *const b,
43
                                  const union refmvs_refpair ref, const mv gmv[2],
44
                                  int *const have_newmv_match,
45
                                  int *const have_refmv_match)
46
3.30M
{
47
3.30M
    if (b->mv.mv[0].n == INVALID_MV) return; // intra block, no intrabc
48
49
3.06M
    if (ref.ref[1] == -1) {
50
3.71M
        for (int n = 0; n < 2; n++) {
51
3.21M
            if (b->ref.ref[n] == ref.ref[0]) {
52
2.17M
                const mv cand_mv = ((b->mf & 1) && gmv[0].n != INVALID_MV) ?
53
2.09M
                                   gmv[0] : b->mv.mv[n];
54
55
2.17M
                *have_refmv_match = 1;
56
2.17M
                *have_newmv_match |= b->mf >> 1;
57
58
2.17M
                const int last = *cnt;
59
3.97M
                for (int m = 0; m < last; m++)
60
2.50M
                    if (mvstack[m].mv.mv[0].n == cand_mv.n) {
61
700k
                        mvstack[m].weight += weight;
62
700k
                        return;
63
700k
                    }
64
65
1.47M
                if (last < 8) {
66
1.47M
                    mvstack[last].mv.mv[0] = cand_mv;
67
1.47M
                    mvstack[last].weight = weight;
68
1.47M
                    *cnt = last + 1;
69
1.47M
                }
70
1.47M
                return;
71
2.17M
            }
72
3.21M
        }
73
2.66M
    } else if (b->ref.pair == ref.pair) {
74
126k
        const refmvs_mvpair cand_mv = { .mv = {
75
126k
            [0] = ((b->mf & 1) && gmv[0].n != INVALID_MV) ? gmv[0] : b->mv.mv[0],
76
126k
            [1] = ((b->mf & 1) && gmv[1].n != INVALID_MV) ? gmv[1] : b->mv.mv[1],
77
126k
        }};
78
79
126k
        *have_refmv_match = 1;
80
126k
        *have_newmv_match |= b->mf >> 1;
81
82
126k
        const int last = *cnt;
83
191k
        for (int n = 0; n < last; n++)
84
111k
            if (mvstack[n].mv.n == cand_mv.n) {
85
46.9k
                mvstack[n].weight += weight;
86
46.9k
                return;
87
46.9k
            }
88
89
80.0k
        if (last < 8) {
90
80.0k
            mvstack[last].mv = cand_mv;
91
80.0k
            mvstack[last].weight = weight;
92
80.0k
            *cnt = last + 1;
93
80.0k
        }
94
80.0k
    }
95
3.06M
}
96
97
static int scan_row(refmvs_candidate *const mvstack, int *const cnt,
98
                    const union refmvs_refpair ref, const mv gmv[2],
99
                    const refmvs_block *b, const int bw4, const int w4,
100
                    const int max_rows, const int step,
101
                    int *const have_newmv_match, int *const have_refmv_match)
102
962k
{
103
962k
    const refmvs_block *cand_b = b;
104
962k
    const enum BlockSize first_cand_bs = cand_b->bs;
105
962k
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
106
962k
    int cand_bw4 = first_cand_b_dim[0];
107
962k
    int len = imax(step, imin(bw4, cand_bw4));
108
109
962k
    if (bw4 <= cand_bw4) {
110
        // FIXME weight can be higher for odd blocks (bx4 & 1), but then the
111
        // position of the first block has to be odd already, i.e. not just
112
        // for row_offset=-3/-5
113
        // FIXME why can this not be cand_bw4?
114
839k
        const int weight = bw4 == 1 ? 2 :
115
839k
                           imax(2, imin(2 * max_rows, first_cand_b_dim[1]));
116
839k
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
117
839k
                              have_newmv_match, have_refmv_match);
118
839k
        return weight >> 1;
119
839k
    }
120
121
251k
    for (int x = 0;;) {
122
        // FIXME if we overhang above, we could fill a bitmask so we don't have
123
        // to repeat the add_spatial_candidate() for the next row, but just increase
124
        // the weight here
125
251k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
126
251k
                              have_newmv_match, have_refmv_match);
127
251k
        x += len;
128
251k
        if (x >= w4) return 1;
129
128k
        cand_b = &b[x];
130
128k
        cand_bw4 = dav1d_block_dimensions[cand_b->bs][0];
131
128k
        assert(cand_bw4 < bw4);
132
128k
        len = imax(step, cand_bw4);
133
128k
    }
134
123k
}
135
136
static int scan_col(refmvs_candidate *const mvstack, int *const cnt,
137
                    const union refmvs_refpair ref, const mv gmv[2],
138
                    /*const*/ refmvs_block *const *b, const int bh4, const int h4,
139
                    const int bx4, const int max_cols, const int step,
140
                    int *const have_newmv_match, int *const have_refmv_match)
141
1.38M
{
142
1.38M
    const refmvs_block *cand_b = &b[0][bx4];
143
1.38M
    const enum BlockSize first_cand_bs = cand_b->bs;
144
1.38M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
145
1.38M
    int cand_bh4 = first_cand_b_dim[1];
146
1.38M
    int len = imax(step, imin(bh4, cand_bh4));
147
148
1.38M
    if (bh4 <= cand_bh4) {
149
        // FIXME weight can be higher for odd blocks (by4 & 1), but then the
150
        // position of the first block has to be odd already, i.e. not just
151
        // for col_offset=-3/-5
152
        // FIXME why can this not be cand_bh4?
153
1.26M
        const int weight = bh4 == 1 ? 2 :
154
1.26M
                           imax(2, imin(2 * max_cols, first_cand_b_dim[0]));
155
1.26M
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
156
1.26M
                            have_newmv_match, have_refmv_match);
157
1.26M
        return weight >> 1;
158
1.26M
    }
159
160
212k
    for (int y = 0;;) {
161
        // FIXME if we overhang above, we could fill a bitmask so we don't have
162
        // to repeat the add_spatial_candidate() for the next row, but just increase
163
        // the weight here
164
212k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
165
212k
                              have_newmv_match, have_refmv_match);
166
212k
        y += len;
167
212k
        if (y >= h4) return 1;
168
98.2k
        cand_b = &b[y][bx4];
169
98.2k
        cand_bh4 = dav1d_block_dimensions[cand_b->bs][1];
170
98.2k
        assert(cand_bh4 < bh4);
171
98.2k
        len = imax(step, cand_bh4);
172
98.2k
    }
173
115k
}
174
175
35.7k
static inline union mv mv_projection(const union mv mv, const int num, const int den) {
176
35.7k
    static const uint16_t div_mult[32] = {
177
35.7k
           0, 16384, 8192, 5461, 4096, 3276, 2730, 2340,
178
35.7k
        2048,  1820, 1638, 1489, 1365, 1260, 1170, 1092,
179
35.7k
        1024,   963,  910,  862,  819,  780,  744,  712,
180
35.7k
         682,   655,  630,  606,  585,  564,  546,  528
181
35.7k
    };
182
35.7k
    assert(den > 0 && den < 32);
183
35.7k
    assert(num > -32 && num < 32);
184
35.7k
    const int frac = num * div_mult[den];
185
35.7k
    const int y = mv.y * frac, x = mv.x * frac;
186
    // Round and clip according to AV1 spec section 7.9.3
187
35.7k
    return (union mv) { // 0x3fff == (1 << 14) - 1
188
35.7k
        .y = iclip((y + 8192 + (y >> 31)) >> 14, -0x3fff, 0x3fff),
189
35.7k
        .x = iclip((x + 8192 + (x >> 31)) >> 14, -0x3fff, 0x3fff)
190
35.7k
    };
191
35.7k
}
192
193
static void add_temporal_candidate(const refmvs_frame *const rf,
194
                                   refmvs_candidate *const mvstack, int *const cnt,
195
                                   const refmvs_temporal_block *const rb,
196
                                   const union refmvs_refpair ref, int *const globalmv_ctx,
197
                                   const union mv gmv[])
198
43.4k
{
199
43.4k
    if (rb->mv.n == INVALID_MV) return;
200
201
19.7k
    union mv mv = mv_projection(rb->mv, rf->pocdiff[ref.ref[0] - 1], rb->ref);
202
19.7k
    fix_mv_precision(rf->frm_hdr, &mv);
203
204
19.7k
    const int last = *cnt;
205
19.7k
    if (ref.ref[1] == -1) {
206
12.7k
        if (globalmv_ctx)
207
3.37k
            *globalmv_ctx = (abs(mv.x - gmv[0].x) | abs(mv.y - gmv[0].y)) >= 16;
208
209
24.3k
        for (int n = 0; n < last; n++)
210
21.2k
            if (mvstack[n].mv.mv[0].n == mv.n) {
211
9.67k
                mvstack[n].weight += 2;
212
9.67k
                return;
213
9.67k
            }
214
3.09k
        if (last < 8) {
215
3.09k
            mvstack[last].mv.mv[0] = mv;
216
3.09k
            mvstack[last].weight = 2;
217
3.09k
            *cnt = last + 1;
218
3.09k
        }
219
7.00k
    } else {
220
7.00k
        refmvs_mvpair mvp = { .mv = {
221
7.00k
            [0] = mv,
222
7.00k
            [1] = mv_projection(rb->mv, rf->pocdiff[ref.ref[1] - 1], rb->ref),
223
7.00k
        }};
224
7.00k
        fix_mv_precision(rf->frm_hdr, &mvp.mv[1]);
225
226
11.3k
        for (int n = 0; n < last; n++)
227
9.53k
            if (mvstack[n].mv.n == mvp.n) {
228
5.17k
                mvstack[n].weight += 2;
229
5.17k
                return;
230
5.17k
            }
231
1.82k
        if (last < 8) {
232
1.82k
            mvstack[last].mv = mvp;
233
1.82k
            mvstack[last].weight = 2;
234
1.82k
            *cnt = last + 1;
235
1.82k
        }
236
1.82k
    }
237
19.7k
}
238
239
static void add_compound_extended_candidate(refmvs_candidate *const same,
240
                                            int *const same_count,
241
                                            const refmvs_block *const cand_b,
242
                                            const int sign0, const int sign1,
243
                                            const union refmvs_refpair ref,
244
                                            const uint8_t *const sign_bias)
245
99.1k
{
246
99.1k
    refmvs_candidate *const diff = &same[2];
247
99.1k
    int *const diff_count = &same_count[2];
248
249
256k
    for (int n = 0; n < 2; n++) {
250
195k
        const int cand_ref = cand_b->ref.ref[n];
251
252
195k
        if (cand_ref <= 0) break;
253
254
157k
        mv cand_mv = cand_b->mv.mv[n];
255
157k
        if (cand_ref == ref.ref[0]) {
256
53.8k
            if (same_count[0] < 2)
257
52.1k
                same[same_count[0]++].mv.mv[0] = cand_mv;
258
53.8k
            if (diff_count[1] < 2) {
259
45.8k
                if (sign1 ^ sign_bias[cand_ref - 1]) {
260
707
                    cand_mv.y = -cand_mv.y;
261
707
                    cand_mv.x = -cand_mv.x;
262
707
                }
263
45.8k
                diff[diff_count[1]++].mv.mv[1] = cand_mv;
264
45.8k
            }
265
103k
        } else if (cand_ref == ref.ref[1]) {
266
55.3k
            if (same_count[1] < 2)
267
53.9k
                same[same_count[1]++].mv.mv[1] = cand_mv;
268
55.3k
            if (diff_count[0] < 2) {
269
44.7k
                if (sign0 ^ sign_bias[cand_ref - 1]) {
270
696
                    cand_mv.y = -cand_mv.y;
271
696
                    cand_mv.x = -cand_mv.x;
272
696
                }
273
44.7k
                diff[diff_count[0]++].mv.mv[0] = cand_mv;
274
44.7k
            }
275
55.3k
        } else {
276
48.1k
            mv i_cand_mv = (union mv) {
277
48.1k
                .x = -cand_mv.x,
278
48.1k
                .y = -cand_mv.y
279
48.1k
            };
280
281
48.1k
            if (diff_count[0] < 2) {
282
37.5k
                diff[diff_count[0]++].mv.mv[0] =
283
37.5k
                    sign0 ^ sign_bias[cand_ref - 1] ?
284
37.3k
                    i_cand_mv : cand_mv;
285
37.5k
            }
286
287
48.1k
            if (diff_count[1] < 2) {
288
35.7k
                diff[diff_count[1]++].mv.mv[1] =
289
35.7k
                    sign1 ^ sign_bias[cand_ref - 1] ?
290
35.4k
                    i_cand_mv : cand_mv;
291
35.7k
            }
292
48.1k
        }
293
157k
    }
294
99.1k
}
295
296
static void add_single_extended_candidate(refmvs_candidate mvstack[8], int *const cnt,
297
                                          const refmvs_block *const cand_b,
298
                                          const int sign, const uint8_t *const sign_bias)
299
292k
{
300
586k
    for (int n = 0; n < 2; n++) {
301
571k
        const int cand_ref = cand_b->ref.ref[n];
302
303
571k
        if (cand_ref <= 0) break;
304
        // we need to continue even if cand_ref == ref.ref[0], since
305
        // the candidate could have been added as a globalmv variant,
306
        // which changes the value
307
        // FIXME if scan_{row,col}() returned a mask for the nearest
308
        // edge, we could skip the appropriate ones here
309
310
294k
        mv cand_mv = cand_b->mv.mv[n];
311
294k
        if (sign ^ sign_bias[cand_ref - 1]) {
312
630
            cand_mv.y = -cand_mv.y;
313
630
            cand_mv.x = -cand_mv.x;
314
630
        }
315
316
294k
        int m;
317
294k
        const int last = *cnt;
318
351k
        for (m = 0; m < last; m++)
319
268k
            if (cand_mv.n == mvstack[m].mv.mv[0].n)
320
211k
                break;
321
294k
        if (m == last) {
322
83.5k
            mvstack[m].mv.mv[0] = cand_mv;
323
83.5k
            mvstack[m].weight = 2; // "minimal"
324
83.5k
            *cnt = last + 1;
325
83.5k
        }
326
294k
    }
327
292k
}
328
329
/*
330
 * refmvs_frame allocates memory for one sbrow (32 blocks high, whole frame
331
 * wide) of 4x4-resolution refmvs_block entries for spatial MV referencing.
332
 * mvrefs_tile[] keeps a list of 35 (32 + 3 above) pointers into this memory,
333
 * and each sbrow, the bottom entries (y=27/29/31) are exchanged with the top
334
 * (-5/-3/-1) pointers by calling dav1d_refmvs_tile_sbrow_init() at the start
335
 * of each tile/sbrow.
336
 *
337
 * For temporal MV referencing, we call dav1d_refmvs_save_tmvs() at the end of
338
 * each tile/sbrow (when tile column threading is enabled), or at the start of
339
 * each interleaved sbrow (i.e. once for all tile columns together, when tile
340
 * column threading is disabled). This will copy the 4x4-resolution spatial MVs
341
 * into 8x8-resolution refmvs_temporal_block structures. Then, for subsequent
342
 * frames, at the start of each tile/sbrow (when tile column threading is
343
 * enabled) or at the start of each interleaved sbrow (when tile column
344
 * threading is disabled), we call load_tmvs(), which will project the MVs to
345
 * their respective position in the current frame.
346
 */
347
348
void dav1d_refmvs_find(const refmvs_tile *const rt,
349
                       refmvs_candidate mvstack[8], int *const cnt,
350
                       int *const ctx,
351
                       const union refmvs_refpair ref, const enum BlockSize bs,
352
                       const enum EdgeFlags edge_flags,
353
                       const int by4, const int bx4)
354
740k
{
355
740k
    const refmvs_frame *const rf = rt->rf;
356
740k
    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
357
740k
    const int bw4 = b_dim[0], w4 = imin(imin(bw4, 16), rt->tile_col.end - bx4);
358
740k
    const int bh4 = b_dim[1], h4 = imin(imin(bh4, 16), rt->tile_row.end - by4);
359
740k
    mv gmv[2], tgmv[2];
360
361
740k
    *cnt = 0;
362
740k
    assert(ref.ref[0] >=  0 && ref.ref[0] <= 8 &&
363
740k
           ref.ref[1] >= -1 && ref.ref[1] <= 8);
364
740k
    if (ref.ref[0] > 0) {
365
396k
        tgmv[0] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[0] - 1],
366
396k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
367
396k
        gmv[0] = rf->frm_hdr->gmv[ref.ref[0] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
368
259k
                 tgmv[0] : (mv) { .n = INVALID_MV };
369
396k
    } else {
370
343k
        tgmv[0] = (mv) { .n = 0 };
371
343k
        gmv[0] = (mv) { .n = INVALID_MV };
372
343k
    }
373
740k
    if (ref.ref[1] > 0) {
374
76.9k
        tgmv[1] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[1] - 1],
375
76.9k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
376
76.9k
        gmv[1] = rf->frm_hdr->gmv[ref.ref[1] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
377
47.5k
                 tgmv[1] : (mv) { .n = INVALID_MV };
378
76.9k
    }
379
380
    // top
381
740k
    int have_newmv = 0, have_col_mvs = 0, have_row_mvs = 0;
382
740k
    unsigned max_rows = 0, n_rows = ~0;
383
740k
    const refmvs_block *b_top;
384
740k
    if (by4 > rt->tile_row.start) {
385
527k
        max_rows = imin((by4 - rt->tile_row.start + 1) >> 1, 2 + (bh4 > 1));
386
527k
        b_top = &rt->r[(by4 & 31) - 1 + 5][bx4];
387
527k
        n_rows = scan_row(mvstack, cnt, ref, gmv, b_top,
388
527k
                          bw4, w4, max_rows, bw4 >= 16 ? 4 : 1,
389
527k
                          &have_newmv, &have_row_mvs);
390
527k
    }
391
392
    // left
393
740k
    unsigned max_cols = 0, n_cols = ~0U;
394
740k
    refmvs_block *const *b_left;
395
740k
    if (bx4 > rt->tile_col.start) {
396
666k
        max_cols = imin((bx4 - rt->tile_col.start + 1) >> 1, 2 + (bw4 > 1));
397
666k
        b_left = &rt->r[(by4 & 31) + 5];
398
666k
        n_cols = scan_col(mvstack, cnt, ref, gmv, b_left,
399
666k
                          bh4, h4, bx4 - 1, max_cols, bh4 >= 16 ? 4 : 1,
400
666k
                          &have_newmv, &have_col_mvs);
401
666k
    }
402
403
    // top/right
404
740k
    if (n_rows != ~0U && edge_flags & EDGE_I444_TOP_HAS_RIGHT &&
405
308k
        imax(bw4, bh4) <= 16 && bw4 + bx4 < rt->tile_col.end)
406
267k
    {
407
267k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[bw4], ref, gmv,
408
267k
                              &have_newmv, &have_row_mvs);
409
267k
    }
410
411
740k
    const int nearest_match = have_col_mvs + have_row_mvs;
412
740k
    const int nearest_cnt = *cnt;
413
1.69M
    for (int n = 0; n < nearest_cnt; n++)
414
953k
        mvstack[n].weight += 640;
415
416
    // temporal
417
740k
    int globalmv_ctx = rf->frm_hdr->use_ref_frame_mvs;
418
740k
    if (rf->use_ref_frame_mvs) {
419
10.9k
        const ptrdiff_t stride = rf->rp_stride;
420
10.9k
        const int by8 = by4 >> 1, bx8 = bx4 >> 1;
421
10.9k
        const refmvs_temporal_block *const rbi = &rt->rp_proj[(by8 & 15) * stride + bx8];
422
10.9k
        const refmvs_temporal_block *rb = rbi;
423
10.9k
        const int step_h = bw4 >= 16 ? 2 : 1, step_v = bh4 >= 16 ? 2 : 1;
424
10.9k
        const int w8 = imin((w4 + 1) >> 1, 8), h8 = imin((h4 + 1) >> 1, 8);
425
31.2k
        for (int y = 0; y < h8; y += step_v) {
426
54.6k
            for (int x = 0; x < w8; x+= step_h) {
427
34.3k
                add_temporal_candidate(rf, mvstack, cnt, &rb[x], ref,
428
34.3k
                                       !(x | y) ? &globalmv_ctx : NULL, tgmv);
429
34.3k
            }
430
20.3k
            rb += stride * step_v;
431
20.3k
        }
432
10.9k
        if (imin(bw4, bh4) >= 2 && imax(bw4, bh4) < 16) {
433
6.87k
            const int bh8 = bh4 >> 1, bw8 = bw4 >> 1;
434
6.87k
            rb = &rbi[bh8 * stride];
435
6.87k
            const int has_bottom = by8 + bh8 < imin(rt->tile_row.end >> 1,
436
6.87k
                                                    (by8 & ~7) + 8);
437
6.87k
            if (has_bottom && bx8 - 1 >= imax(rt->tile_col.start >> 1, bx8 & ~7)) {
438
2.81k
                add_temporal_candidate(rf, mvstack, cnt, &rb[-1], ref,
439
2.81k
                                       NULL, NULL);
440
2.81k
            }
441
6.87k
            if (bx8 + bw8 < imin(rt->tile_col.end >> 1, (bx8 & ~7) + 8)) {
442
3.77k
                if (has_bottom) {
443
2.62k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8], ref,
444
2.62k
                                           NULL, NULL);
445
2.62k
                }
446
3.77k
                if (by8 + bh8 - 1 < imin(rt->tile_row.end >> 1, (by8 & ~7) + 8)) {
447
3.67k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8 - stride],
448
3.67k
                                           ref, NULL, NULL);
449
3.67k
                }
450
3.77k
            }
451
6.87k
        }
452
10.9k
    }
453
740k
    assert(*cnt <= 8);
454
455
    // top/left (which, confusingly, is part of "secondary" references)
456
740k
    int have_dummy_newmv_match;
457
740k
    if ((n_rows | n_cols) != ~0U) {
458
467k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[-1], ref, gmv,
459
467k
                              &have_dummy_newmv_match, &have_row_mvs);
460
467k
    }
461
462
    // "secondary" (non-direct neighbour) top & left edges
463
    // what is different about secondary is that everything is now in 8x8 resolution
464
2.21M
    for (int n = 2; n <= 3; n++) {
465
1.47M
        if ((unsigned) n > n_rows && (unsigned) n <= max_rows) {
466
435k
            n_rows += scan_row(mvstack, cnt, ref, gmv,
467
435k
                               &rt->r[(((by4 & 31) - 2 * n + 1) | 1) + 5][bx4 | 1],
468
435k
                               bw4, w4, 1 + max_rows - n, bw4 >= 16 ? 4 : 2,
469
435k
                               &have_dummy_newmv_match, &have_row_mvs);
470
435k
        }
471
472
1.47M
        if ((unsigned) n > n_cols && (unsigned) n <= max_cols) {
473
715k
            n_cols += scan_col(mvstack, cnt, ref, gmv, &rt->r[((by4 & 31) | 1) + 5],
474
715k
                               bh4, h4, (bx4 - n * 2 + 1) | 1,
475
715k
                               1 + max_cols - n, bh4 >= 16 ? 4 : 2,
476
715k
                               &have_dummy_newmv_match, &have_col_mvs);
477
715k
        }
478
1.47M
    }
479
740k
    assert(*cnt <= 8);
480
481
740k
    const int ref_match_count = have_col_mvs + have_row_mvs;
482
483
    // context build-up
484
740k
    int refmv_ctx, newmv_ctx;
485
740k
    switch (nearest_match) {
486
107k
    case 0:
487
107k
        refmv_ctx = imin(2, ref_match_count);
488
107k
        newmv_ctx = ref_match_count > 0;
489
107k
        break;
490
329k
    case 1:
491
329k
        refmv_ctx = imin(ref_match_count * 3, 4);
492
329k
        newmv_ctx = 3 - have_newmv;
493
329k
        break;
494
303k
    case 2:
495
303k
        refmv_ctx = 5;
496
303k
        newmv_ctx = 5 - have_newmv;
497
303k
        break;
498
740k
    }
499
500
    // sorting (nearest, then "secondary")
501
740k
    int len = nearest_cnt;
502
1.54M
    while (len) {
503
803k
        int last = 0;
504
1.19M
        for (int n = 1; n < len; n++) {
505
394k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
506
191k
#define EXCHANGE(a, b) do { refmvs_candidate tmp = a; a = b; b = tmp; } while (0)
507
175k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
508
175k
                last = n;
509
175k
            }
510
394k
        }
511
803k
        len = last;
512
803k
    }
513
740k
    len = *cnt;
514
1.17M
    while (len > nearest_cnt) {
515
433k
        int last = nearest_cnt;
516
630k
        for (int n = nearest_cnt + 1; n < len; n++) {
517
197k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
518
15.7k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
519
15.7k
#undef EXCHANGE
520
15.7k
                last = n;
521
15.7k
            }
522
197k
        }
523
433k
        len = last;
524
433k
    }
525
526
740k
    if (ref.ref[1] > 0) {
527
76.9k
        if (*cnt < 2) {
528
56.2k
            const int sign0 = rf->sign_bias[ref.ref[0] - 1];
529
56.2k
            const int sign1 = rf->sign_bias[ref.ref[1] - 1];
530
56.2k
            const int sz4 = imin(w4, h4);
531
56.2k
            refmvs_candidate *const same = &mvstack[*cnt];
532
56.2k
            int same_count[4] = { 0 };
533
534
            // non-self references in top
535
97.3k
            if (n_rows != ~0U) for (int x = 0; x < sz4;) {
536
51.1k
                const refmvs_block *const cand_b = &b_top[x];
537
51.1k
                add_compound_extended_candidate(same, same_count, cand_b,
538
51.1k
                                                sign0, sign1, ref, rf->sign_bias);
539
51.1k
                x += dav1d_block_dimensions[cand_b->bs][0];
540
51.1k
            }
541
542
            // non-self references in left
543
91.8k
            if (n_cols != ~0U) for (int y = 0; y < sz4;) {
544
48.0k
                const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
545
48.0k
                add_compound_extended_candidate(same, same_count, cand_b,
546
48.0k
                                                sign0, sign1, ref, rf->sign_bias);
547
48.0k
                y += dav1d_block_dimensions[cand_b->bs][1];
548
48.0k
            }
549
550
56.2k
            refmvs_candidate *const diff = &same[2];
551
56.2k
            const int *const diff_count = &same_count[2];
552
553
            // merge together
554
168k
            for (int n = 0; n < 2; n++) {
555
112k
                int m = same_count[n];
556
557
112k
                if (m >= 2) continue;
558
559
84.7k
                const int l = diff_count[n];
560
84.7k
                if (l) {
561
72.7k
                    same[m].mv.mv[n] = diff[0].mv.mv[n];
562
72.7k
                    if (++m == 2) continue;
563
25.7k
                    if (l == 2) {
564
20.4k
                        same[1].mv.mv[n] = diff[1].mv.mv[n];
565
20.4k
                        continue;
566
20.4k
                    }
567
25.7k
                }
568
25.8k
                do {
569
25.8k
                    same[m].mv.mv[n] = tgmv[n];
570
25.8k
                } while (++m < 2);
571
17.3k
            }
572
573
            // if the first extended was the same as the non-extended one,
574
            // then replace it with the second extended one
575
56.2k
            int n = *cnt;
576
56.2k
            if (n == 1 && mvstack[0].mv.n == same[0].mv.n)
577
19.8k
                mvstack[1].mv = mvstack[2].mv;
578
85.3k
            do {
579
85.3k
                mvstack[n].weight = 2;
580
85.3k
            } while (++n < 2);
581
56.2k
            *cnt = 2;
582
56.2k
        }
583
584
        // clamping
585
76.9k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
586
76.9k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
587
76.9k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
588
76.9k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
589
590
76.9k
        const int n_refmvs = *cnt;
591
76.9k
        int n = 0;
592
167k
        do {
593
167k
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
594
167k
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
595
167k
            mvstack[n].mv.mv[1].x = iclip(mvstack[n].mv.mv[1].x, left, right);
596
167k
            mvstack[n].mv.mv[1].y = iclip(mvstack[n].mv.mv[1].y, top, bottom);
597
167k
        } while (++n < n_refmvs);
598
599
76.9k
        switch (refmv_ctx >> 1) {
600
32.4k
        case 0:
601
32.4k
            *ctx = imin(newmv_ctx, 1);
602
32.4k
            break;
603
27.0k
        case 1:
604
27.0k
            *ctx = 1 + imin(newmv_ctx, 3);
605
27.0k
            break;
606
17.4k
        case 2:
607
17.4k
            *ctx = iclip(3 + newmv_ctx, 4, 7);
608
17.4k
            break;
609
76.9k
        }
610
611
76.9k
        return;
612
663k
    } else if (*cnt < 2 && ref.ref[0] > 0) {
613
188k
        const int sign = rf->sign_bias[ref.ref[0] - 1];
614
188k
        const int sz4 = imin(w4, h4);
615
616
        // non-self references in top
617
319k
        if (n_rows != ~0U) for (int x = 0; x < sz4 && *cnt < 2;) {
618
163k
            const refmvs_block *const cand_b = &b_top[x];
619
163k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
620
163k
            x += dav1d_block_dimensions[cand_b->bs][0];
621
163k
        }
622
623
        // non-self references in left
624
273k
        if (n_cols != ~0U) for (int y = 0; y < sz4 && *cnt < 2;) {
625
128k
            const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
626
128k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
627
128k
            y += dav1d_block_dimensions[cand_b->bs][1];
628
128k
        }
629
188k
    }
630
663k
    assert(*cnt <= 8);
631
632
    // clamping
633
663k
    int n_refmvs = *cnt;
634
663k
    if (n_refmvs) {
635
631k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
636
631k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
637
631k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
638
631k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
639
640
631k
        int n = 0;
641
1.56M
        do {
642
1.56M
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
643
1.56M
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
644
1.56M
        } while (++n < n_refmvs);
645
631k
    }
646
647
873k
    for (int n = *cnt; n < 2; n++)
648
210k
        mvstack[n].mv.mv[0] = tgmv[0];
649
650
663k
    *ctx = (refmv_ctx << 4) | (globalmv_ctx << 3) | newmv_ctx;
651
663k
}
652
653
void dav1d_refmvs_tile_sbrow_init(refmvs_tile *const rt, const refmvs_frame *const rf,
654
                                  const int tile_col_start4, const int tile_col_end4,
655
                                  const int tile_row_start4, const int tile_row_end4,
656
                                  const int sby, int tile_row_idx, const int pass)
657
85.3k
{
658
85.3k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
659
85.3k
    rt->rp_proj = &rf->rp_proj[16 * rf->rp_stride * tile_row_idx];
660
85.3k
    const ptrdiff_t r_stride = rf->rp_stride * 2;
661
85.3k
    const ptrdiff_t pass_off = (rf->n_frame_threads > 1 && pass == 2) ?
662
49.6k
        35 * 2 * rf->n_blocks : 0;
663
85.3k
    refmvs_block *r = &rf->r[35 * r_stride * tile_row_idx + pass_off];
664
85.3k
    const int sbsz = rf->sbsz;
665
85.3k
    const int off = (sbsz * sby) & 16;
666
1.80M
    for (int i = 0; i < sbsz; i++, r += r_stride)
667
1.71M
        rt->r[off + 5 + i] = r;
668
85.3k
    rt->r[off + 0] = r;
669
85.3k
    r += r_stride;
670
85.3k
    rt->r[off + 1] = NULL;
671
85.3k
    rt->r[off + 2] = r;
672
85.3k
    r += r_stride;
673
85.3k
    rt->r[off + 3] = NULL;
674
85.3k
    rt->r[off + 4] = r;
675
85.3k
    if (sby & 1) {
676
92.3k
#define EXCHANGE(a, b) do { void *const tmp = a; a = b; b = tmp; } while (0)
677
30.7k
        EXCHANGE(rt->r[off + 0], rt->r[off + sbsz + 0]);
678
30.7k
        EXCHANGE(rt->r[off + 2], rt->r[off + sbsz + 2]);
679
30.7k
        EXCHANGE(rt->r[off + 4], rt->r[off + sbsz + 4]);
680
30.7k
#undef EXCHANGE
681
30.7k
    }
682
683
85.3k
    rt->rf = rf;
684
85.3k
    rt->tile_row.start = tile_row_start4;
685
85.3k
    rt->tile_row.end = imin(tile_row_end4, rf->ih4);
686
85.3k
    rt->tile_col.start = tile_col_start4;
687
85.3k
    rt->tile_col.end = imin(tile_col_end4, rf->iw4);
688
85.3k
}
689
690
static void load_tmvs_c(const refmvs_frame *const rf, int tile_row_idx,
691
                        const int col_start8, const int col_end8,
692
                        const int row_start8, int row_end8)
693
2.64k
{
694
2.64k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
695
2.64k
    assert(row_start8 >= 0);
696
2.64k
    assert((unsigned) (row_end8 - row_start8) <= 16U);
697
2.64k
    row_end8 = imin(row_end8, rf->ih8);
698
2.64k
    const int col_start8i = imax(col_start8 - 8, 0);
699
2.64k
    const int col_end8i = imin(col_end8 + 8, rf->iw8);
700
701
2.64k
    const ptrdiff_t stride = rf->rp_stride;
702
2.64k
    refmvs_temporal_block *rp_proj =
703
2.64k
        &rf->rp_proj[16 * stride * tile_row_idx + (row_start8 & 15) * stride];
704
22.9k
    for (int y = row_start8; y < row_end8; y++) {
705
109k
        for (int x = col_start8; x < col_end8; x++)
706
89.6k
            rp_proj[x].mv.n = INVALID_MV;
707
20.2k
        rp_proj += stride;
708
20.2k
    }
709
710
2.64k
    rp_proj = &rf->rp_proj[16 * stride * tile_row_idx];
711
5.06k
    for (int n = 0; n < rf->n_mfmvs; n++) {
712
2.41k
        const int ref2cur = rf->mfmv_ref2cur[n];
713
2.41k
        if (ref2cur == INVALID_REF2CUR) continue;
714
715
2.05k
        const int ref = rf->mfmv_ref[n];
716
2.05k
        const int ref_sign = ref - 4;
717
2.05k
        const refmvs_temporal_block *r = &rf->rp_ref[ref][row_start8 * stride];
718
17.1k
        for (int y = row_start8; y < row_end8; y++) {
719
15.0k
            const int y_sb_align = y & ~7;
720
15.0k
            const int y_proj_start = imax(y_sb_align, row_start8);
721
15.0k
            const int y_proj_end = imin(y_sb_align + 8, row_end8);
722
63.3k
            for (int x = col_start8i; x < col_end8i; x++) {
723
48.2k
                const refmvs_temporal_block *rb = &r[x];
724
48.2k
                const int b_ref = rb->ref;
725
48.2k
                if (!b_ref) continue;
726
31.1k
                const int ref2ref = rf->mfmv_ref2ref[n][b_ref - 1];
727
31.1k
                if (!ref2ref) continue;
728
8.99k
                const mv b_mv = rb->mv;
729
8.99k
                const mv offset = mv_projection(b_mv, ref2cur, ref2ref);
730
8.99k
                int pos_x = x + apply_sign(abs(offset.x) >> 6,
731
8.99k
                                           offset.x ^ ref_sign);
732
8.99k
                const int pos_y = y + apply_sign(abs(offset.y) >> 6,
733
8.99k
                                                 offset.y ^ ref_sign);
734
8.99k
                if (pos_y >= y_proj_start && pos_y < y_proj_end) {
735
7.86k
                    const ptrdiff_t pos = (pos_y & 15) * stride;
736
25.6k
                    for (;;) {
737
25.6k
                        const int x_sb_align = x & ~7;
738
25.6k
                        if (pos_x >= imax(x_sb_align - 8, col_start8) &&
739
25.3k
                            pos_x < imin(x_sb_align + 16, col_end8))
740
25.0k
                        {
741
25.0k
                            rp_proj[pos + pos_x].mv = rb->mv;
742
25.0k
                            rp_proj[pos + pos_x].ref = ref2ref;
743
25.0k
                        }
744
25.6k
                        if (++x >= col_end8i) break;
745
21.4k
                        rb++;
746
21.4k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
747
17.8k
                        pos_x++;
748
17.8k
                    }
749
7.86k
                } else {
750
3.34k
                    for (;;) {
751
3.34k
                        if (++x >= col_end8i) break;
752
2.97k
                        rb++;
753
2.97k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
754
2.97k
                    }
755
1.13k
                }
756
8.99k
                x--;
757
8.99k
            }
758
15.0k
            r += stride;
759
15.0k
        }
760
2.05k
    }
761
2.64k
}
762
763
static void save_tmvs_c(refmvs_temporal_block *rp, const ptrdiff_t stride,
764
                        refmvs_block *const *const rr,
765
                        const uint8_t *const ref_sign,
766
                        const int col_end8, const int row_end8,
767
                        const int col_start8, const int row_start8)
768
7.48k
{
769
66.3k
    for (int y = row_start8; y < row_end8; y++) {
770
58.8k
        const refmvs_block *const b = rr[(y & 15) * 2];
771
772
152k
        for (int x = col_start8; x < col_end8;) {
773
93.4k
            const refmvs_block *const cand_b = &b[x * 2 + 1];
774
93.4k
            const int bw8 = (dav1d_block_dimensions[cand_b->bs][0] + 1) >> 1;
775
776
93.4k
            if (cand_b->ref.ref[1] > 0 && ref_sign[cand_b->ref.ref[1] - 1] &&
777
16.2k
                (abs(cand_b->mv.mv[1].y) | abs(cand_b->mv.mv[1].x)) < 4096)
778
14.9k
            {
779
14.9k
                const refmvs_temporal_block tmv = {
780
14.9k
                    .mv = cand_b->mv.mv[1],
781
14.9k
                    .ref = cand_b->ref.ref[1],
782
14.9k
                };
783
46.7k
                for (int n = 0; n < bw8; n++, x++)
784
31.7k
                    rp[x] = tmv;
785
78.4k
            } else if (cand_b->ref.ref[0] > 0 && ref_sign[cand_b->ref.ref[0] - 1] &&
786
30.5k
                       (abs(cand_b->mv.mv[0].y) | abs(cand_b->mv.mv[0].x)) < 4096)
787
29.7k
            {
788
29.7k
                const refmvs_temporal_block tmv = {
789
29.7k
                    .mv = cand_b->mv.mv[0],
790
29.7k
                    .ref = cand_b->ref.ref[0],
791
29.7k
                };
792
149k
                for (int n = 0; n < bw8; n++, x++)
793
119k
                    rp[x] = tmv;
794
48.6k
            } else {
795
48.6k
                const refmvs_temporal_block tmv = { .mv = { .n = 0 }, .ref = 0 };
796
220k
                for (int n = 0; n < bw8; n++, x++)
797
171k
                    rp[x] = tmv;
798
48.6k
            }
799
93.4k
        }
800
58.8k
        rp += stride;
801
58.8k
    }
802
7.48k
}
803
804
int dav1d_refmvs_init_frame(refmvs_frame *const rf,
805
                            const Dav1dSequenceHeader *const seq_hdr,
806
                            const Dav1dFrameHeader *const frm_hdr,
807
                            const uint8_t ref_poc[7],
808
                            refmvs_temporal_block *const rp,
809
                            const uint8_t ref_ref_poc[7][7],
810
                            /*const*/ refmvs_temporal_block *const rp_ref[7],
811
                            const int n_tile_threads, const int n_frame_threads)
812
20.4k
{
813
20.4k
    const int rp_stride = ((frm_hdr->width[0] + 127) & ~127) >> 3;
814
20.4k
    const int n_tile_rows = n_tile_threads > 1 ? frm_hdr->tiling.rows : 1;
815
20.4k
    const int n_blocks = rp_stride * n_tile_rows;
816
817
20.4k
    rf->sbsz = 16 << seq_hdr->sb128;
818
20.4k
    rf->frm_hdr = frm_hdr;
819
20.4k
    rf->iw8 = (frm_hdr->width[0] + 7) >> 3;
820
20.4k
    rf->ih8 = (frm_hdr->height + 7) >> 3;
821
20.4k
    rf->iw4 = rf->iw8 << 1;
822
20.4k
    rf->ih4 = rf->ih8 << 1;
823
20.4k
    rf->rp = rp;
824
20.4k
    rf->rp_stride = rp_stride;
825
20.4k
    rf->n_tile_threads = n_tile_threads;
826
20.4k
    rf->n_frame_threads = n_frame_threads;
827
828
20.4k
    if (n_blocks != rf->n_blocks) {
829
20.3k
        const size_t r_sz = sizeof(*rf->r) * 35 * 2 * n_blocks * (1 + (n_frame_threads > 1));
830
20.3k
        const size_t rp_proj_sz = sizeof(*rf->rp_proj) * 16 * n_blocks;
831
        /* Note that sizeof(*rf->r) == 12, but it's accessed using 16-byte unaligned
832
         * loads in save_tmvs() asm which can overread 4 bytes into rp_proj. */
833
20.3k
        dav1d_free_aligned(rf->r);
834
20.3k
        rf->r = dav1d_alloc_aligned(ALLOC_REFMVS, r_sz + rp_proj_sz, 64);
835
20.3k
        if (!rf->r) {
836
0
            rf->n_blocks = 0;
837
0
            return DAV1D_ERR(ENOMEM);
838
0
        }
839
840
20.3k
        rf->rp_proj = (refmvs_temporal_block*)((uintptr_t)rf->r + r_sz);
841
20.3k
        rf->n_blocks = n_blocks;
842
20.3k
    }
843
844
20.4k
    const int poc = frm_hdr->frame_offset;
845
163k
    for (int i = 0; i < 7; i++) {
846
143k
        const int poc_diff = get_poc_diff(seq_hdr->order_hint_n_bits,
847
143k
                                          ref_poc[i], poc);
848
143k
        rf->sign_bias[i] = poc_diff > 0;
849
143k
        rf->mfmv_sign[i] = poc_diff < 0;
850
143k
        rf->pocdiff[i] = iclip(get_poc_diff(seq_hdr->order_hint_n_bits,
851
143k
                                            poc, ref_poc[i]), -31, 31);
852
143k
    }
853
854
    // temporal MV setup
855
20.4k
    rf->n_mfmvs = 0;
856
20.4k
    rf->rp_ref = rp_ref;
857
20.4k
    if (frm_hdr->use_ref_frame_mvs && seq_hdr->order_hint_n_bits) {
858
2.08k
        int total = 2;
859
2.08k
        if (rp_ref[0] && ref_ref_poc[0][6] != ref_poc[3] /* alt-of-last != gold */) {
860
416
            rf->mfmv_ref[rf->n_mfmvs++] = 0; // last
861
416
            total = 3;
862
416
        }
863
2.08k
        if (rp_ref[4] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[4],
864
690
                                      frm_hdr->frame_offset) > 0)
865
351
        {
866
351
            rf->mfmv_ref[rf->n_mfmvs++] = 4; // bwd
867
351
        }
868
2.08k
        if (rp_ref[5] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[5],
869
596
                                      frm_hdr->frame_offset) > 0)
870
241
        {
871
241
            rf->mfmv_ref[rf->n_mfmvs++] = 5; // altref2
872
241
        }
873
2.08k
        if (rf->n_mfmvs < total && rp_ref[6] &&
874
518
            get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[6],
875
518
                         frm_hdr->frame_offset) > 0)
876
239
        {
877
239
            rf->mfmv_ref[rf->n_mfmvs++] = 6; // altref
878
239
        }
879
2.08k
        if (rf->n_mfmvs < total && rp_ref[1])
880
673
            rf->mfmv_ref[rf->n_mfmvs++] = 1; // last2
881
882
4.00k
        for (int n = 0; n < rf->n_mfmvs; n++) {
883
1.92k
            const int rpoc = ref_poc[rf->mfmv_ref[n]];
884
1.92k
            const int diff1 = get_poc_diff(seq_hdr->order_hint_n_bits,
885
1.92k
                                           rpoc, frm_hdr->frame_offset);
886
1.92k
            if (abs(diff1) > 31) {
887
285
                rf->mfmv_ref2cur[n] = INVALID_REF2CUR;
888
1.63k
            } else {
889
1.63k
                rf->mfmv_ref2cur[n] = rf->mfmv_ref[n] < 4 ? -diff1 : diff1;
890
13.0k
                for (int m = 0; m < 7; m++) {
891
11.4k
                    const int rrpoc = ref_ref_poc[rf->mfmv_ref[n]][m];
892
11.4k
                    const int diff2 = get_poc_diff(seq_hdr->order_hint_n_bits,
893
11.4k
                                                   rpoc, rrpoc);
894
                    // unsigned comparison also catches the < 0 case
895
11.4k
                    rf->mfmv_ref2ref[n][m] = (unsigned) diff2 > 31U ? 0 : diff2;
896
11.4k
                }
897
1.63k
            }
898
1.92k
        }
899
2.08k
    }
900
20.4k
    rf->use_ref_frame_mvs = rf->n_mfmvs > 0;
901
902
20.4k
    return 0;
903
20.4k
}
904
905
static void splat_mv_c(refmvs_block **rr, const refmvs_block *const rmv,
906
                       const int bx4, const int bw4, int bh4)
907
1.15M
{
908
4.23M
    do {
909
4.23M
        refmvs_block *const r = *rr++ + bx4;
910
45.5M
        for (int x = 0; x < bw4; x++)
911
41.3M
            r[x] = *rmv;
912
4.23M
    } while (--bh4);
913
1.15M
}
914
915
#if HAVE_ASM
916
#if ARCH_AARCH64 || ARCH_ARM
917
#include "src/arm/refmvs.h"
918
#elif ARCH_LOONGARCH64
919
#include "src/loongarch/refmvs.h"
920
#elif ARCH_X86
921
#include "src/x86/refmvs.h"
922
#endif
923
#endif
924
925
COLD void dav1d_refmvs_dsp_init(Dav1dRefmvsDSPContext *const c)
926
40.9k
{
927
40.9k
    c->load_tmvs = load_tmvs_c;
928
40.9k
    c->save_tmvs = save_tmvs_c;
929
40.9k
    c->splat_mv = splat_mv_c;
930
931
#if HAVE_ASM
932
#if ARCH_AARCH64 || ARCH_ARM
933
    refmvs_dsp_init_arm(c);
934
#elif ARCH_LOONGARCH64
935
    refmvs_dsp_init_loongarch(c);
936
#elif ARCH_X86
937
    refmvs_dsp_init_x86(c);
938
#endif
939
#endif
940
40.9k
}