Coverage Report

Created: 2026-08-31 06:22

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