Coverage Report

Created: 2026-09-02 06:43

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
4.29M
{
47
4.29M
    if (b->mv.mv[0].n == INVALID_MV) return; // intra block, no intrabc
48
49
3.97M
    if (ref.ref[1] == -1) {
50
4.89M
        for (int n = 0; n < 2; n++) {
51
4.16M
            if (b->ref.ref[n] == ref.ref[0]) {
52
2.64M
                const mv cand_mv = ((b->mf & 1) && gmv[0].n != INVALID_MV) ?
53
2.54M
                                   gmv[0] : b->mv.mv[n];
54
55
2.64M
                *have_refmv_match = 1;
56
2.64M
                *have_newmv_match |= b->mf >> 1;
57
58
2.64M
                const int last = *cnt;
59
3.90M
                for (int m = 0; m < last; m++)
60
2.82M
                    if (mvstack[m].mv.mv[0].n == cand_mv.n) {
61
1.55M
                        mvstack[m].weight += weight;
62
1.55M
                        return;
63
1.55M
                    }
64
65
1.08M
                if (last < 8) {
66
1.08M
                    mvstack[last].mv.mv[0] = cand_mv;
67
1.08M
                    mvstack[last].weight = weight;
68
1.08M
                    *cnt = last + 1;
69
1.08M
                }
70
1.08M
                return;
71
2.64M
            }
72
4.16M
        }
73
3.36M
    } else if (b->ref.pair == ref.pair) {
74
195k
        const refmvs_mvpair cand_mv = { .mv = {
75
195k
            [0] = ((b->mf & 1) && gmv[0].n != INVALID_MV) ? gmv[0] : b->mv.mv[0],
76
195k
            [1] = ((b->mf & 1) && gmv[1].n != INVALID_MV) ? gmv[1] : b->mv.mv[1],
77
195k
        }};
78
79
195k
        *have_refmv_match = 1;
80
195k
        *have_newmv_match |= b->mf >> 1;
81
82
195k
        const int last = *cnt;
83
311k
        for (int n = 0; n < last; n++)
84
182k
            if (mvstack[n].mv.n == cand_mv.n) {
85
66.4k
                mvstack[n].weight += weight;
86
66.4k
                return;
87
66.4k
            }
88
89
129k
        if (last < 8) {
90
129k
            mvstack[last].mv = cand_mv;
91
129k
            mvstack[last].weight = weight;
92
129k
            *cnt = last + 1;
93
129k
        }
94
129k
    }
95
3.97M
}
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
1.35M
{
103
1.35M
    const refmvs_block *cand_b = b;
104
1.35M
    const enum BlockSize first_cand_bs = cand_b->bs;
105
1.35M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
106
1.35M
    int cand_bw4 = first_cand_b_dim[0];
107
1.35M
    int len = imax(step, imin(bw4, cand_bw4));
108
109
1.35M
    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
1.16M
        const int weight = bw4 == 1 ? 2 :
115
1.16M
                           imax(2, imin(2 * max_rows, first_cand_b_dim[1]));
116
1.16M
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
117
1.16M
                              have_newmv_match, have_refmv_match);
118
1.16M
        return weight >> 1;
119
1.16M
    }
120
121
383k
    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
383k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
126
383k
                              have_newmv_match, have_refmv_match);
127
383k
        x += len;
128
383k
        if (x >= w4) return 1;
129
197k
        cand_b = &b[x];
130
197k
        cand_bw4 = dav1d_block_dimensions[cand_b->bs][0];
131
197k
        assert(cand_bw4 < bw4);
132
197k
        len = imax(step, cand_bw4);
133
197k
    }
134
186k
}
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.54M
{
142
1.54M
    const refmvs_block *cand_b = &b[0][bx4];
143
1.54M
    const enum BlockSize first_cand_bs = cand_b->bs;
144
1.54M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
145
1.54M
    int cand_bh4 = first_cand_b_dim[1];
146
1.54M
    int len = imax(step, imin(bh4, cand_bh4));
147
148
1.54M
    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.30M
        const int weight = bh4 == 1 ? 2 :
154
1.30M
                           imax(2, imin(2 * max_cols, first_cand_b_dim[0]));
155
1.30M
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
156
1.30M
                            have_newmv_match, have_refmv_match);
157
1.30M
        return weight >> 1;
158
1.30M
    }
159
160
483k
    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
483k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
165
483k
                              have_newmv_match, have_refmv_match);
166
483k
        y += len;
167
483k
        if (y >= h4) return 1;
168
243k
        cand_b = &b[y][bx4];
169
243k
        cand_bh4 = dav1d_block_dimensions[cand_b->bs][1];
170
243k
        assert(cand_bh4 < bh4);
171
243k
        len = imax(step, cand_bh4);
172
243k
    }
173
239k
}
174
175
30.2k
static inline union mv mv_projection(const union mv mv, const int num, const int den) {
176
30.2k
    static const uint16_t div_mult[32] = {
177
30.2k
           0, 16384, 8192, 5461, 4096, 3276, 2730, 2340,
178
30.2k
        2048,  1820, 1638, 1489, 1365, 1260, 1170, 1092,
179
30.2k
        1024,   963,  910,  862,  819,  780,  744,  712,
180
30.2k
         682,   655,  630,  606,  585,  564,  546,  528
181
30.2k
    };
182
30.2k
    assert(den > 0 && den < 32);
183
30.2k
    assert(num > -32 && num < 32);
184
30.2k
    const int frac = num * div_mult[den];
185
30.2k
    const int y = mv.y * frac, x = mv.x * frac;
186
    // Round and clip according to AV1 spec section 7.9.3
187
30.2k
    return (union mv) { // 0x3fff == (1 << 14) - 1
188
30.2k
        .y = iclip((y + 8192 + (y >> 31)) >> 14, -0x3fff, 0x3fff),
189
30.2k
        .x = iclip((x + 8192 + (x >> 31)) >> 14, -0x3fff, 0x3fff)
190
30.2k
    };
191
30.2k
}
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
49.2k
{
199
49.2k
    if (rb->mv.n == INVALID_MV) return;
200
201
13.3k
    union mv mv = mv_projection(rb->mv, rf->pocdiff[ref.ref[0] - 1], rb->ref);
202
13.3k
    fix_mv_precision(rf->frm_hdr, &mv);
203
204
13.3k
    const int last = *cnt;
205
13.3k
    if (ref.ref[1] == -1) {
206
10.7k
        if (globalmv_ctx)
207
2.33k
            *globalmv_ctx = (abs(mv.x - gmv[0].x) | abs(mv.y - gmv[0].y)) >= 16;
208
209
12.5k
        for (int n = 0; n < last; n++)
210
10.4k
            if (mvstack[n].mv.mv[0].n == mv.n) {
211
8.55k
                mvstack[n].weight += 2;
212
8.55k
                return;
213
8.55k
            }
214
2.15k
        if (last < 8) {
215
2.15k
            mvstack[last].mv.mv[0] = mv;
216
2.15k
            mvstack[last].weight = 2;
217
2.15k
            *cnt = last + 1;
218
2.15k
        }
219
2.68k
    } else {
220
2.68k
        refmvs_mvpair mvp = { .mv = {
221
2.68k
            [0] = mv,
222
2.68k
            [1] = mv_projection(rb->mv, rf->pocdiff[ref.ref[1] - 1], rb->ref),
223
2.68k
        }};
224
2.68k
        fix_mv_precision(rf->frm_hdr, &mvp.mv[1]);
225
226
3.89k
        for (int n = 0; n < last; n++)
227
3.21k
            if (mvstack[n].mv.n == mvp.n) {
228
1.99k
                mvstack[n].weight += 2;
229
1.99k
                return;
230
1.99k
            }
231
689
        if (last < 8) {
232
689
            mvstack[last].mv = mvp;
233
689
            mvstack[last].weight = 2;
234
689
            *cnt = last + 1;
235
689
        }
236
689
    }
237
13.3k
}
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
138k
{
246
138k
    refmvs_candidate *const diff = &same[2];
247
138k
    int *const diff_count = &same_count[2];
248
249
355k
    for (int n = 0; n < 2; n++) {
250
272k
        const int cand_ref = cand_b->ref.ref[n];
251
252
272k
        if (cand_ref <= 0) break;
253
254
217k
        mv cand_mv = cand_b->mv.mv[n];
255
217k
        if (cand_ref == ref.ref[0]) {
256
78.7k
            if (same_count[0] < 2)
257
75.4k
                same[same_count[0]++].mv.mv[0] = cand_mv;
258
78.7k
            if (diff_count[1] < 2) {
259
65.4k
                if (sign1 ^ sign_bias[cand_ref - 1]) {
260
1.12k
                    cand_mv.y = -cand_mv.y;
261
1.12k
                    cand_mv.x = -cand_mv.x;
262
1.12k
                }
263
65.4k
                diff[diff_count[1]++].mv.mv[1] = cand_mv;
264
65.4k
            }
265
138k
        } else if (cand_ref == ref.ref[1]) {
266
70.5k
            if (same_count[1] < 2)
267
68.5k
                same[same_count[1]++].mv.mv[1] = cand_mv;
268
70.5k
            if (diff_count[0] < 2) {
269
56.6k
                if (sign0 ^ sign_bias[cand_ref - 1]) {
270
1.20k
                    cand_mv.y = -cand_mv.y;
271
1.20k
                    cand_mv.x = -cand_mv.x;
272
1.20k
                }
273
56.6k
                diff[diff_count[0]++].mv.mv[0] = cand_mv;
274
56.6k
            }
275
70.5k
        } else {
276
67.8k
            mv i_cand_mv = (union mv) {
277
67.8k
                .x = -cand_mv.x,
278
67.8k
                .y = -cand_mv.y
279
67.8k
            };
280
281
67.8k
            if (diff_count[0] < 2) {
282
52.4k
                diff[diff_count[0]++].mv.mv[0] =
283
52.4k
                    sign0 ^ sign_bias[cand_ref - 1] ?
284
51.6k
                    i_cand_mv : cand_mv;
285
52.4k
            }
286
287
67.8k
            if (diff_count[1] < 2) {
288
48.2k
                diff[diff_count[1]++].mv.mv[1] =
289
48.2k
                    sign1 ^ sign_bias[cand_ref - 1] ?
290
47.6k
                    i_cand_mv : cand_mv;
291
48.2k
            }
292
67.8k
        }
293
217k
    }
294
138k
}
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
594k
{
300
1.18M
    for (int n = 0; n < 2; n++) {
301
1.16M
        const int cand_ref = cand_b->ref.ref[n];
302
303
1.16M
        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
591k
        mv cand_mv = cand_b->mv.mv[n];
311
591k
        if (sign ^ sign_bias[cand_ref - 1]) {
312
1.50k
            cand_mv.y = -cand_mv.y;
313
1.50k
            cand_mv.x = -cand_mv.x;
314
1.50k
        }
315
316
591k
        int m;
317
591k
        const int last = *cnt;
318
667k
        for (m = 0; m < last; m++)
319
558k
            if (cand_mv.n == mvstack[m].mv.mv[0].n)
320
482k
                break;
321
591k
        if (m == last) {
322
108k
            mvstack[m].mv.mv[0] = cand_mv;
323
108k
            mvstack[m].weight = 2; // "minimal"
324
108k
            *cnt = last + 1;
325
108k
        }
326
591k
    }
327
594k
}
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
777k
{
355
777k
    const refmvs_frame *const rf = rt->rf;
356
777k
    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
357
777k
    const int bw4 = b_dim[0], w4 = imin(imin(bw4, 16), rt->tile_col.end - bx4);
358
777k
    const int bh4 = b_dim[1], h4 = imin(imin(bh4, 16), rt->tile_row.end - by4);
359
777k
    mv gmv[2], tgmv[2];
360
361
777k
    *cnt = 0;
362
777k
    assert(ref.ref[0] >=  0 && ref.ref[0] <= 8 &&
363
777k
           ref.ref[1] >= -1 && ref.ref[1] <= 8);
364
777k
    if (ref.ref[0] > 0) {
365
696k
        tgmv[0] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[0] - 1],
366
696k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
367
696k
        gmv[0] = rf->frm_hdr->gmv[ref.ref[0] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
368
531k
                 tgmv[0] : (mv) { .n = INVALID_MV };
369
696k
    } else {
370
81.2k
        tgmv[0] = (mv) { .n = 0 };
371
81.2k
        gmv[0] = (mv) { .n = INVALID_MV };
372
81.2k
    }
373
777k
    if (ref.ref[1] > 0) {
374
118k
        tgmv[1] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[1] - 1],
375
118k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
376
118k
        gmv[1] = rf->frm_hdr->gmv[ref.ref[1] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
377
68.1k
                 tgmv[1] : (mv) { .n = INVALID_MV };
378
118k
    }
379
380
    // top
381
777k
    int have_newmv = 0, have_col_mvs = 0, have_row_mvs = 0;
382
777k
    unsigned max_rows = 0, n_rows = ~0;
383
777k
    const refmvs_block *b_top;
384
777k
    if (by4 > rt->tile_row.start) {
385
640k
        max_rows = imin((by4 - rt->tile_row.start + 1) >> 1, 2 + (bh4 > 1));
386
640k
        b_top = &rt->r[(by4 & 31) - 1 + 5][bx4];
387
640k
        n_rows = scan_row(mvstack, cnt, ref, gmv, b_top,
388
640k
                          bw4, w4, max_rows, bw4 >= 16 ? 4 : 1,
389
640k
                          &have_newmv, &have_row_mvs);
390
640k
    }
391
392
    // left
393
777k
    unsigned max_cols = 0, n_cols = ~0U;
394
777k
    refmvs_block *const *b_left;
395
777k
    if (bx4 > rt->tile_col.start) {
396
694k
        max_cols = imin((bx4 - rt->tile_col.start + 1) >> 1, 2 + (bw4 > 1));
397
694k
        b_left = &rt->r[(by4 & 31) + 5];
398
694k
        n_cols = scan_col(mvstack, cnt, ref, gmv, b_left,
399
694k
                          bh4, h4, bx4 - 1, max_cols, bh4 >= 16 ? 4 : 1,
400
694k
                          &have_newmv, &have_col_mvs);
401
694k
    }
402
403
    // top/right
404
777k
    if (n_rows != ~0U && edge_flags & EDGE_I444_TOP_HAS_RIGHT &&
405
368k
        imax(bw4, bh4) <= 16 && bw4 + bx4 < rt->tile_col.end)
406
348k
    {
407
348k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[bw4], ref, gmv,
408
348k
                              &have_newmv, &have_row_mvs);
409
348k
    }
410
411
777k
    const int nearest_match = have_col_mvs + have_row_mvs;
412
777k
    const int nearest_cnt = *cnt;
413
1.62M
    for (int n = 0; n < nearest_cnt; n++)
414
846k
        mvstack[n].weight += 640;
415
416
    // temporal
417
777k
    int globalmv_ctx = rf->frm_hdr->use_ref_frame_mvs;
418
777k
    if (rf->use_ref_frame_mvs) {
419
15.2k
        const ptrdiff_t stride = rf->rp_stride;
420
15.2k
        const int by8 = by4 >> 1, bx8 = bx4 >> 1;
421
15.2k
        const refmvs_temporal_block *const rbi = &rt->rp_proj[(by8 & 15) * stride + bx8];
422
15.2k
        const refmvs_temporal_block *rb = rbi;
423
15.2k
        const int step_h = bw4 >= 16 ? 2 : 1, step_v = bh4 >= 16 ? 2 : 1;
424
15.2k
        const int w8 = imin((w4 + 1) >> 1, 8), h8 = imin((h4 + 1) >> 1, 8);
425
49.1k
        for (int y = 0; y < h8; y += step_v) {
426
80.3k
            for (int x = 0; x < w8; x+= step_h) {
427
46.4k
                add_temporal_candidate(rf, mvstack, cnt, &rb[x], ref,
428
46.4k
                                       !(x | y) ? &globalmv_ctx : NULL, tgmv);
429
46.4k
            }
430
33.8k
            rb += stride * step_v;
431
33.8k
        }
432
15.2k
        if (imin(bw4, bh4) >= 2 && imax(bw4, bh4) < 16) {
433
7.89k
            const int bh8 = bh4 >> 1, bw8 = bw4 >> 1;
434
7.89k
            rb = &rbi[bh8 * stride];
435
7.89k
            const int has_bottom = by8 + bh8 < imin(rt->tile_row.end >> 1,
436
7.89k
                                                    (by8 & ~7) + 8);
437
7.89k
            if (has_bottom && bx8 - 1 >= imax(rt->tile_col.start >> 1, bx8 & ~7)) {
438
890
                add_temporal_candidate(rf, mvstack, cnt, &rb[-1], ref,
439
890
                                       NULL, NULL);
440
890
            }
441
7.89k
            if (bx8 + bw8 < imin(rt->tile_col.end >> 1, (bx8 & ~7) + 8)) {
442
1.47k
                if (has_bottom) {
443
734
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8], ref,
444
734
                                           NULL, NULL);
445
734
                }
446
1.47k
                if (by8 + bh8 - 1 < imin(rt->tile_row.end >> 1, (by8 & ~7) + 8)) {
447
1.18k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8 - stride],
448
1.18k
                                           ref, NULL, NULL);
449
1.18k
                }
450
1.47k
            }
451
7.89k
        }
452
15.2k
    }
453
777k
    assert(*cnt <= 8);
454
455
    // top/left (which, confusingly, is part of "secondary" references)
456
777k
    int have_dummy_newmv_match;
457
777k
    if ((n_rows | n_cols) != ~0U) {
458
615k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[-1], ref, gmv,
459
615k
                              &have_dummy_newmv_match, &have_row_mvs);
460
615k
    }
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.33M
    for (int n = 2; n <= 3; n++) {
465
1.55M
        if ((unsigned) n > n_rows && (unsigned) n <= max_rows) {
466
711k
            n_rows += scan_row(mvstack, cnt, ref, gmv,
467
711k
                               &rt->r[(((by4 & 31) - 2 * n + 1) | 1) + 5][bx4 | 1],
468
711k
                               bw4, w4, 1 + max_rows - n, bw4 >= 16 ? 4 : 2,
469
711k
                               &have_dummy_newmv_match, &have_row_mvs);
470
711k
        }
471
472
1.55M
        if ((unsigned) n > n_cols && (unsigned) n <= max_cols) {
473
845k
            n_cols += scan_col(mvstack, cnt, ref, gmv, &rt->r[((by4 & 31) | 1) + 5],
474
845k
                               bh4, h4, (bx4 - n * 2 + 1) | 1,
475
845k
                               1 + max_cols - n, bh4 >= 16 ? 4 : 2,
476
845k
                               &have_dummy_newmv_match, &have_col_mvs);
477
845k
        }
478
1.55M
    }
479
777k
    assert(*cnt <= 8);
480
481
777k
    const int ref_match_count = have_col_mvs + have_row_mvs;
482
483
    // context build-up
484
777k
    int refmv_ctx, newmv_ctx;
485
777k
    switch (nearest_match) {
486
166k
    case 0:
487
166k
        refmv_ctx = imin(2, ref_match_count);
488
166k
        newmv_ctx = ref_match_count > 0;
489
166k
        break;
490
239k
    case 1:
491
239k
        refmv_ctx = imin(ref_match_count * 3, 4);
492
239k
        newmv_ctx = 3 - have_newmv;
493
239k
        break;
494
371k
    case 2:
495
371k
        refmv_ctx = 5;
496
371k
        newmv_ctx = 5 - have_newmv;
497
371k
        break;
498
777k
    }
499
500
    // sorting (nearest, then "secondary")
501
777k
    int len = nearest_cnt;
502
1.48M
    while (len) {
503
702k
        int last = 0;
504
964k
        for (int n = 1; n < len; n++) {
505
261k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
506
134k
#define EXCHANGE(a, b) do { refmvs_candidate tmp = a; a = b; b = tmp; } while (0)
507
99.4k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
508
99.4k
                last = n;
509
99.4k
            }
510
261k
        }
511
702k
        len = last;
512
702k
    }
513
777k
    len = *cnt;
514
1.05M
    while (len > nearest_cnt) {
515
282k
        int last = nearest_cnt;
516
413k
        for (int n = nearest_cnt + 1; n < len; n++) {
517
130k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
518
34.9k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
519
34.9k
#undef EXCHANGE
520
34.9k
                last = n;
521
34.9k
            }
522
130k
        }
523
282k
        len = last;
524
282k
    }
525
526
777k
    if (ref.ref[1] > 0) {
527
118k
        if (*cnt < 2) {
528
83.0k
            const int sign0 = rf->sign_bias[ref.ref[0] - 1];
529
83.0k
            const int sign1 = rf->sign_bias[ref.ref[1] - 1];
530
83.0k
            const int sz4 = imin(w4, h4);
531
83.0k
            refmvs_candidate *const same = &mvstack[*cnt];
532
83.0k
            int same_count[4] = { 0 };
533
534
            // non-self references in top
535
121k
            if (n_rows != ~0U) for (int x = 0; x < sz4;) {
536
63.5k
                const refmvs_block *const cand_b = &b_top[x];
537
63.5k
                add_compound_extended_candidate(same, same_count, cand_b,
538
63.5k
                                                sign0, sign1, ref, rf->sign_bias);
539
63.5k
                x += dav1d_block_dimensions[cand_b->bs][0];
540
63.5k
            }
541
542
            // non-self references in left
543
140k
            if (n_cols != ~0U) for (int y = 0; y < sz4;) {
544
75.2k
                const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
545
75.2k
                add_compound_extended_candidate(same, same_count, cand_b,
546
75.2k
                                                sign0, sign1, ref, rf->sign_bias);
547
75.2k
                y += dav1d_block_dimensions[cand_b->bs][1];
548
75.2k
            }
549
550
83.0k
            refmvs_candidate *const diff = &same[2];
551
83.0k
            const int *const diff_count = &same_count[2];
552
553
            // merge together
554
249k
            for (int n = 0; n < 2; n++) {
555
166k
                int m = same_count[n];
556
557
166k
                if (m >= 2) continue;
558
559
126k
                const int l = diff_count[n];
560
126k
                if (l) {
561
93.4k
                    same[m].mv.mv[n] = diff[0].mv.mv[n];
562
93.4k
                    if (++m == 2) continue;
563
32.6k
                    if (l == 2) {
564
27.6k
                        same[1].mv.mv[n] = diff[1].mv.mv[n];
565
27.6k
                        continue;
566
27.6k
                    }
567
32.6k
                }
568
67.3k
                do {
569
67.3k
                    same[m].mv.mv[n] = tgmv[n];
570
67.3k
                } while (++m < 2);
571
37.9k
            }
572
573
            // if the first extended was the same as the non-extended one,
574
            // then replace it with the second extended one
575
83.0k
            int n = *cnt;
576
83.0k
            if (n == 1 && mvstack[0].mv.n == same[0].mv.n)
577
25.6k
                mvstack[1].mv = mvstack[2].mv;
578
130k
            do {
579
130k
                mvstack[n].weight = 2;
580
130k
            } while (++n < 2);
581
83.0k
            *cnt = 2;
582
83.0k
        }
583
584
        // clamping
585
118k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
586
118k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
587
118k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
588
118k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
589
590
118k
        const int n_refmvs = *cnt;
591
118k
        int n = 0;
592
259k
        do {
593
259k
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
594
259k
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
595
259k
            mvstack[n].mv.mv[1].x = iclip(mvstack[n].mv.mv[1].x, left, right);
596
259k
            mvstack[n].mv.mv[1].y = iclip(mvstack[n].mv.mv[1].y, top, bottom);
597
259k
        } while (++n < n_refmvs);
598
599
118k
        switch (refmv_ctx >> 1) {
600
51.1k
        case 0:
601
51.1k
            *ctx = imin(newmv_ctx, 1);
602
51.1k
            break;
603
39.7k
        case 1:
604
39.7k
            *ctx = 1 + imin(newmv_ctx, 3);
605
39.7k
            break;
606
27.3k
        case 2:
607
27.3k
            *ctx = iclip(3 + newmv_ctx, 4, 7);
608
27.3k
            break;
609
118k
        }
610
611
118k
        return;
612
659k
    } else if (*cnt < 2 && ref.ref[0] > 0) {
613
362k
        const int sign = rf->sign_bias[ref.ref[0] - 1];
614
362k
        const int sz4 = imin(w4, h4);
615
616
        // non-self references in top
617
579k
        if (n_rows != ~0U) for (int x = 0; x < sz4 && *cnt < 2;) {
618
297k
            const refmvs_block *const cand_b = &b_top[x];
619
297k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
620
297k
            x += dav1d_block_dimensions[cand_b->bs][0];
621
297k
        }
622
623
        // non-self references in left
624
602k
        if (n_cols != ~0U) for (int y = 0; y < sz4 && *cnt < 2;) {
625
297k
            const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
626
297k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
627
297k
            y += dav1d_block_dimensions[cand_b->bs][1];
628
297k
        }
629
362k
    }
630
659k
    assert(*cnt <= 8);
631
632
    // clamping
633
659k
    int n_refmvs = *cnt;
634
659k
    if (n_refmvs) {
635
595k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
636
595k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
637
595k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
638
595k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
639
640
595k
        int n = 0;
641
1.19M
        do {
642
1.19M
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
643
1.19M
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
644
1.19M
        } while (++n < n_refmvs);
645
595k
    }
646
647
1.04M
    for (int n = *cnt; n < 2; n++)
648
384k
        mvstack[n].mv.mv[0] = tgmv[0];
649
650
659k
    *ctx = (refmv_ctx << 4) | (globalmv_ctx << 3) | newmv_ctx;
651
659k
}
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
151k
{
658
151k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
659
151k
    rt->rp_proj = &rf->rp_proj[16 * rf->rp_stride * tile_row_idx];
660
151k
    const ptrdiff_t r_stride = rf->rp_stride * 2;
661
151k
    const ptrdiff_t pass_off = (rf->n_frame_threads > 1 && pass == 2) ?
662
79.2k
        35 * 2 * rf->n_blocks : 0;
663
151k
    refmvs_block *r = &rf->r[35 * r_stride * tile_row_idx + pass_off];
664
151k
    const int sbsz = rf->sbsz;
665
151k
    const int off = (sbsz * sby) & 16;
666
3.20M
    for (int i = 0; i < sbsz; i++, r += r_stride)
667
3.05M
        rt->r[off + 5 + i] = r;
668
151k
    rt->r[off + 0] = r;
669
151k
    r += r_stride;
670
151k
    rt->r[off + 1] = NULL;
671
151k
    rt->r[off + 2] = r;
672
151k
    r += r_stride;
673
151k
    rt->r[off + 3] = NULL;
674
151k
    rt->r[off + 4] = r;
675
151k
    if (sby & 1) {
676
50.9k
#define EXCHANGE(a, b) do { void *const tmp = a; a = b; b = tmp; } while (0)
677
16.9k
        EXCHANGE(rt->r[off + 0], rt->r[off + sbsz + 0]);
678
16.9k
        EXCHANGE(rt->r[off + 2], rt->r[off + sbsz + 2]);
679
16.9k
        EXCHANGE(rt->r[off + 4], rt->r[off + sbsz + 4]);
680
16.9k
#undef EXCHANGE
681
16.9k
    }
682
683
151k
    rt->rf = rf;
684
151k
    rt->tile_row.start = tile_row_start4;
685
151k
    rt->tile_row.end = imin(tile_row_end4, rf->ih4);
686
151k
    rt->tile_col.start = tile_col_start4;
687
151k
    rt->tile_col.end = imin(tile_col_end4, rf->iw4);
688
151k
}
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
8.92k
{
694
8.92k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
695
8.92k
    assert(row_start8 >= 0);
696
8.92k
    assert((unsigned) (row_end8 - row_start8) <= 16U);
697
8.92k
    row_end8 = imin(row_end8, rf->ih8);
698
8.92k
    const int col_start8i = imax(col_start8 - 8, 0);
699
8.92k
    const int col_end8i = imin(col_end8 + 8, rf->iw8);
700
701
8.92k
    const ptrdiff_t stride = rf->rp_stride;
702
8.92k
    refmvs_temporal_block *rp_proj =
703
8.92k
        &rf->rp_proj[16 * stride * tile_row_idx + (row_start8 & 15) * stride];
704
64.6k
    for (int y = row_start8; y < row_end8; y++) {
705
138k
        for (int x = col_start8; x < col_end8; x++)
706
82.7k
            rp_proj[x].mv.n = INVALID_MV;
707
55.6k
        rp_proj += stride;
708
55.6k
    }
709
710
8.92k
    rp_proj = &rf->rp_proj[16 * stride * tile_row_idx];
711
19.4k
    for (int n = 0; n < rf->n_mfmvs; n++) {
712
10.5k
        const int ref2cur = rf->mfmv_ref2cur[n];
713
10.5k
        if (ref2cur == INVALID_REF2CUR) continue;
714
715
9.21k
        const int ref = rf->mfmv_ref[n];
716
9.21k
        const int ref_sign = ref - 4;
717
9.21k
        const refmvs_temporal_block *r = &rf->rp_ref[ref][row_start8 * stride];
718
68.1k
        for (int y = row_start8; y < row_end8; y++) {
719
58.9k
            const int y_sb_align = y & ~7;
720
58.9k
            const int y_proj_start = imax(y_sb_align, row_start8);
721
58.9k
            const int y_proj_end = imin(y_sb_align + 8, row_end8);
722
129k
            for (int x = col_start8i; x < col_end8i; x++) {
723
70.1k
                const refmvs_temporal_block *rb = &r[x];
724
70.1k
                const int b_ref = rb->ref;
725
70.1k
                if (!b_ref) continue;
726
19.3k
                const int ref2ref = rf->mfmv_ref2ref[n][b_ref - 1];
727
19.3k
                if (!ref2ref) continue;
728
14.1k
                const mv b_mv = rb->mv;
729
14.1k
                const mv offset = mv_projection(b_mv, ref2cur, ref2ref);
730
14.1k
                int pos_x = x + apply_sign(abs(offset.x) >> 6,
731
14.1k
                                           offset.x ^ ref_sign);
732
14.1k
                const int pos_y = y + apply_sign(abs(offset.y) >> 6,
733
14.1k
                                                 offset.y ^ ref_sign);
734
14.1k
                if (pos_y >= y_proj_start && pos_y < y_proj_end) {
735
12.8k
                    const ptrdiff_t pos = (pos_y & 15) * stride;
736
21.2k
                    for (;;) {
737
21.2k
                        const int x_sb_align = x & ~7;
738
21.2k
                        if (pos_x >= imax(x_sb_align - 8, col_start8) &&
739
21.0k
                            pos_x < imin(x_sb_align + 16, col_end8))
740
20.0k
                        {
741
20.0k
                            rp_proj[pos + pos_x].mv = rb->mv;
742
20.0k
                            rp_proj[pos + pos_x].ref = ref2ref;
743
20.0k
                        }
744
21.2k
                        if (++x >= col_end8i) break;
745
13.1k
                        rb++;
746
13.1k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
747
8.43k
                        pos_x++;
748
8.43k
                    }
749
12.8k
                } else {
750
1.57k
                    for (;;) {
751
1.57k
                        if (++x >= col_end8i) break;
752
908
                        rb++;
753
908
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
754
908
                    }
755
1.31k
                }
756
14.1k
                x--;
757
14.1k
            }
758
58.9k
            r += stride;
759
58.9k
        }
760
9.21k
    }
761
8.92k
}
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
22.6k
{
769
115k
    for (int y = row_start8; y < row_end8; y++) {
770
93.3k
        const refmvs_block *const b = rr[(y & 15) * 2];
771
772
203k
        for (int x = col_start8; x < col_end8;) {
773
109k
            const refmvs_block *const cand_b = &b[x * 2 + 1];
774
109k
            const int bw8 = (dav1d_block_dimensions[cand_b->bs][0] + 1) >> 1;
775
776
109k
            if (cand_b->ref.ref[1] > 0 && ref_sign[cand_b->ref.ref[1] - 1] &&
777
8.64k
                (abs(cand_b->mv.mv[1].y) | abs(cand_b->mv.mv[1].x)) < 4096)
778
7.54k
            {
779
7.54k
                const refmvs_temporal_block tmv = {
780
7.54k
                    .mv = cand_b->mv.mv[1],
781
7.54k
                    .ref = cand_b->ref.ref[1],
782
7.54k
                };
783
30.7k
                for (int n = 0; n < bw8; n++, x++)
784
23.2k
                    rp[x] = tmv;
785
102k
            } else if (cand_b->ref.ref[0] > 0 && ref_sign[cand_b->ref.ref[0] - 1] &&
786
21.4k
                       (abs(cand_b->mv.mv[0].y) | abs(cand_b->mv.mv[0].x)) < 4096)
787
20.3k
            {
788
20.3k
                const refmvs_temporal_block tmv = {
789
20.3k
                    .mv = cand_b->mv.mv[0],
790
20.3k
                    .ref = cand_b->ref.ref[0],
791
20.3k
                };
792
116k
                for (int n = 0; n < bw8; n++, x++)
793
96.3k
                    rp[x] = tmv;
794
81.9k
            } else {
795
81.9k
                const refmvs_temporal_block tmv = { .mv = { .n = 0 }, .ref = 0 };
796
547k
                for (int n = 0; n < bw8; n++, x++)
797
465k
                    rp[x] = tmv;
798
81.9k
            }
799
109k
        }
800
93.3k
        rp += stride;
801
93.3k
    }
802
22.6k
}
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
66.4k
{
813
66.4k
    const int rp_stride = ((frm_hdr->width[0] + 127) & ~127) >> 3;
814
66.4k
    const int n_tile_rows = n_tile_threads > 1 ? frm_hdr->tiling.rows : 1;
815
66.4k
    const int n_blocks = rp_stride * n_tile_rows;
816
817
66.4k
    rf->sbsz = 16 << seq_hdr->sb128;
818
66.4k
    rf->frm_hdr = frm_hdr;
819
66.4k
    rf->iw8 = (frm_hdr->width[0] + 7) >> 3;
820
66.4k
    rf->ih8 = (frm_hdr->height + 7) >> 3;
821
66.4k
    rf->iw4 = rf->iw8 << 1;
822
66.4k
    rf->ih4 = rf->ih8 << 1;
823
66.4k
    rf->rp = rp;
824
66.4k
    rf->rp_stride = rp_stride;
825
66.4k
    rf->n_tile_threads = n_tile_threads;
826
66.4k
    rf->n_frame_threads = n_frame_threads;
827
828
66.4k
    if (n_blocks != rf->n_blocks) {
829
18.1k
        const size_t r_sz = sizeof(*rf->r) * 35 * 2 * n_blocks * (1 + (n_frame_threads > 1));
830
18.1k
        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
18.1k
        dav1d_free_aligned(rf->r);
834
18.1k
        rf->r = dav1d_alloc_aligned(ALLOC_REFMVS, r_sz + rp_proj_sz, 64);
835
18.1k
        if (!rf->r) {
836
0
            rf->n_blocks = 0;
837
0
            return DAV1D_ERR(ENOMEM);
838
0
        }
839
840
18.1k
        rf->rp_proj = (refmvs_temporal_block*)((uintptr_t)rf->r + r_sz);
841
18.1k
        rf->n_blocks = n_blocks;
842
18.1k
    }
843
844
66.4k
    const int poc = frm_hdr->frame_offset;
845
531k
    for (int i = 0; i < 7; i++) {
846
464k
        const int poc_diff = get_poc_diff(seq_hdr->order_hint_n_bits,
847
464k
                                          ref_poc[i], poc);
848
464k
        rf->sign_bias[i] = poc_diff > 0;
849
464k
        rf->mfmv_sign[i] = poc_diff < 0;
850
464k
        rf->pocdiff[i] = iclip(get_poc_diff(seq_hdr->order_hint_n_bits,
851
464k
                                            poc, ref_poc[i]), -31, 31);
852
464k
    }
853
854
    // temporal MV setup
855
66.4k
    rf->n_mfmvs = 0;
856
66.4k
    rf->rp_ref = rp_ref;
857
66.4k
    if (frm_hdr->use_ref_frame_mvs && seq_hdr->order_hint_n_bits) {
858
8.34k
        int total = 2;
859
8.34k
        if (rp_ref[0] && ref_ref_poc[0][6] != ref_poc[3] /* alt-of-last != gold */) {
860
2.13k
            rf->mfmv_ref[rf->n_mfmvs++] = 0; // last
861
2.13k
            total = 3;
862
2.13k
        }
863
8.34k
        if (rp_ref[4] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[4],
864
7.00k
                                      frm_hdr->frame_offset) > 0)
865
166
        {
866
166
            rf->mfmv_ref[rf->n_mfmvs++] = 4; // bwd
867
166
        }
868
8.34k
        if (rp_ref[5] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[5],
869
6.12k
                                      frm_hdr->frame_offset) > 0)
870
226
        {
871
226
            rf->mfmv_ref[rf->n_mfmvs++] = 5; // altref2
872
226
        }
873
8.34k
        if (rf->n_mfmvs < total && rp_ref[6] &&
874
3.24k
            get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[6],
875
3.24k
                         frm_hdr->frame_offset) > 0)
876
1.05k
        {
877
1.05k
            rf->mfmv_ref[rf->n_mfmvs++] = 6; // altref
878
1.05k
        }
879
8.34k
        if (rf->n_mfmvs < total && rp_ref[1])
880
6.42k
            rf->mfmv_ref[rf->n_mfmvs++] = 1; // last2
881
882
18.3k
        for (int n = 0; n < rf->n_mfmvs; n++) {
883
10.0k
            const int rpoc = ref_poc[rf->mfmv_ref[n]];
884
10.0k
            const int diff1 = get_poc_diff(seq_hdr->order_hint_n_bits,
885
10.0k
                                           rpoc, frm_hdr->frame_offset);
886
10.0k
            if (abs(diff1) > 31) {
887
1.21k
                rf->mfmv_ref2cur[n] = INVALID_REF2CUR;
888
8.78k
            } else {
889
8.78k
                rf->mfmv_ref2cur[n] = rf->mfmv_ref[n] < 4 ? -diff1 : diff1;
890
70.2k
                for (int m = 0; m < 7; m++) {
891
61.5k
                    const int rrpoc = ref_ref_poc[rf->mfmv_ref[n]][m];
892
61.5k
                    const int diff2 = get_poc_diff(seq_hdr->order_hint_n_bits,
893
61.5k
                                                   rpoc, rrpoc);
894
                    // unsigned comparison also catches the < 0 case
895
61.5k
                    rf->mfmv_ref2ref[n][m] = (unsigned) diff2 > 31U ? 0 : diff2;
896
61.5k
                }
897
8.78k
            }
898
10.0k
        }
899
8.34k
    }
900
66.4k
    rf->use_ref_frame_mvs = rf->n_mfmvs > 0;
901
902
66.4k
    return 0;
903
66.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.28M
{
908
5.21M
    do {
909
5.21M
        refmvs_block *const r = *rr++ + bx4;
910
46.4M
        for (int x = 0; x < bw4; x++)
911
41.1M
            r[x] = *rmv;
912
5.21M
    } while (--bh4);
913
1.28M
}
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
21.2k
{
927
21.2k
    c->load_tmvs = load_tmvs_c;
928
21.2k
    c->save_tmvs = save_tmvs_c;
929
21.2k
    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
21.2k
}