Coverage Report

Created: 2026-09-14 06:39

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