Coverage Report

Created: 2026-10-28 06:15

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