Coverage Report

Created: 2026-10-17 06:56

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
3.06M
{
48
3.06M
    if (b->mv.mv[0].n == INVALID_MV) return; // intra block, no intrabc
49
50
2.62M
    if (ref.ref[1] == -1) {
51
3.10M
        for (int n = 0; n < 2; n++) {
52
2.69M
            if (b->ref.ref[n] == ref.ref[0]) {
53
1.80M
                const mv cand_mv = ((b->mf & 1) && gmv[0].n != INVALID_MV) ?
54
1.76M
                                   gmv[0] : b->mv.mv[n];
55
56
1.80M
                *have_refmv_match = 1;
57
1.80M
                *have_newmv_match |= b->mf >> 1;
58
59
1.80M
                const int last = *cnt;
60
3.53M
                for (int m = 0; m < last; m++)
61
2.24M
                    if (mvstack[m].mv.mv[0].n == cand_mv.n) {
62
510k
                        mvstack[m].weight += weight;
63
510k
                        return;
64
510k
                    }
65
66
1.29M
                if (last < 8) {
67
1.28M
                    mvstack[last].mv.mv[0] = cand_mv;
68
1.28M
                    mvstack[last].weight = weight;
69
1.28M
                    *cnt = last + 1;
70
1.28M
                }
71
1.29M
                return;
72
1.80M
            }
73
2.69M
        }
74
2.21M
    } else if (b->ref.pair == ref.pair) {
75
121k
        const refmvs_mvpair cand_mv = { .mv = {
76
121k
            [0] = ((b->mf & 1) && gmv[0].n != INVALID_MV) ? gmv[0] : b->mv.mv[0],
77
121k
            [1] = ((b->mf & 1) && gmv[1].n != INVALID_MV) ? gmv[1] : b->mv.mv[1],
78
121k
        }};
79
80
121k
        *have_refmv_match = 1;
81
121k
        *have_newmv_match |= b->mf >> 1;
82
83
121k
        const int last = *cnt;
84
174k
        for (int n = 0; n < last; n++)
85
97.8k
            if (mvstack[n].mv.n == cand_mv.n) {
86
44.7k
                mvstack[n].weight += weight;
87
44.7k
                return;
88
44.7k
            }
89
90
76.5k
        if (last < 8) {
91
76.5k
            mvstack[last].mv = cand_mv;
92
76.5k
            mvstack[last].weight = weight;
93
76.5k
            *cnt = last + 1;
94
76.5k
        }
95
76.5k
    }
96
2.62M
}
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
922k
{
104
922k
    const refmvs_block *cand_b = b;
105
922k
    const enum BlockSize first_cand_bs = cand_b->bs;
106
922k
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
107
922k
    int cand_bw4 = first_cand_b_dim[0];
108
922k
    int len = imax(step, imin(bw4, cand_bw4));
109
110
922k
    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
811k
        const int weight = bw4 == 1 ? 2 :
116
811k
                           imax(2, imin(2 * max_rows, first_cand_b_dim[1]));
117
811k
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
118
811k
                              have_newmv_match, have_refmv_match);
119
811k
        return weight >> 1;
120
811k
    }
121
122
217k
    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
217k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
127
217k
                              have_newmv_match, have_refmv_match);
128
217k
        x += len;
129
217k
        if (x >= w4) return 1;
130
107k
        cand_b = &b[x];
131
107k
        cand_bw4 = dav1d_block_dimensions[cand_b->bs][0];
132
107k
        assert(cand_bw4 < bw4);
133
107k
        len = imax(step, cand_bw4);
134
107k
    }
135
110k
}
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
1.24M
{
143
1.24M
    const refmvs_block *cand_b = &b[0][bx4];
144
1.24M
    const enum BlockSize first_cand_bs = cand_b->bs;
145
1.24M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
146
1.24M
    int cand_bh4 = first_cand_b_dim[1];
147
1.24M
    int len = imax(step, imin(bh4, cand_bh4));
148
149
1.24M
    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
1.10M
        const int weight = bh4 == 1 ? 2 :
155
1.10M
                           imax(2, imin(2 * max_cols, first_cand_b_dim[0]));
156
1.10M
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
157
1.10M
                            have_newmv_match, have_refmv_match);
158
1.10M
        return weight >> 1;
159
1.10M
    }
160
161
266k
    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
266k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
166
266k
                              have_newmv_match, have_refmv_match);
167
266k
        y += len;
168
266k
        if (y >= h4) return 1;
169
128k
        cand_b = &b[y][bx4];
170
128k
        cand_bh4 = dav1d_block_dimensions[cand_b->bs][1];
171
128k
        assert(cand_bh4 < bh4);
172
128k
        len = imax(step, cand_bh4);
173
128k
    }
174
139k
}
175
176
103k
static inline union mv mv_projection(const union mv mv, const int num, const int den) {
177
103k
    static const uint16_t div_mult[32] = {
178
103k
           0, 16384, 8192, 5461, 4096, 3276, 2730, 2340,
179
103k
        2048,  1820, 1638, 1489, 1365, 1260, 1170, 1092,
180
103k
        1024,   963,  910,  862,  819,  780,  744,  712,
181
103k
         682,   655,  630,  606,  585,  564,  546,  528
182
103k
    };
183
103k
    assert(den > 0 && den < 32);
184
103k
    assert(num > -32 && num < 32);
185
103k
    const int frac = num * div_mult[den];
186
103k
    const int y = mv.y * frac, x = mv.x * frac;
187
    // Round and clip according to AV1 spec section 7.9.3
188
103k
    return (union mv) { // 0x3fff == (1 << 14) - 1
189
103k
        .y = iclip((y + 8192 + (y >> 31)) >> 14, -0x3fff, 0x3fff),
190
103k
        .x = iclip((x + 8192 + (x >> 31)) >> 14, -0x3fff, 0x3fff)
191
103k
    };
192
103k
}
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
54.8k
{
200
54.8k
    if (rb->mv.n == INVALID_MV) return;
201
202
20.6k
    union mv mv = mv_projection(rb->mv, rf->pocdiff[ref.ref[0] - 1], rb->ref);
203
20.6k
    fix_mv_precision(rf->frm_hdr, &mv);
204
205
20.6k
    const int last = *cnt;
206
20.6k
    if (ref.ref[1] == -1) {
207
11.6k
        if (globalmv_ctx)
208
6.94k
            *globalmv_ctx = (abs(mv.x - gmv[0].x) | abs(mv.y - gmv[0].y)) >= 16;
209
210
15.0k
        for (int n = 0; n < last; n++)
211
9.36k
            if (mvstack[n].mv.mv[0].n == mv.n) {
212
5.90k
                mvstack[n].weight += weight;
213
5.90k
                return;
214
5.90k
            }
215
5.71k
        if (last < 8) {
216
5.71k
            mvstack[last].mv.mv[0] = mv;
217
5.71k
            mvstack[last].weight = weight;
218
5.71k
            *cnt = last + 1;
219
5.71k
        }
220
9.02k
    } else {
221
9.02k
        refmvs_mvpair mvp = { .mv = {
222
9.02k
            [0] = mv,
223
9.02k
            [1] = mv_projection(rb->mv, rf->pocdiff[ref.ref[1] - 1], rb->ref),
224
9.02k
        }};
225
9.02k
        fix_mv_precision(rf->frm_hdr, &mvp.mv[1]);
226
227
12.3k
        for (int n = 0; n < last; n++)
228
4.92k
            if (mvstack[n].mv.n == mvp.n) {
229
1.57k
                mvstack[n].weight += weight;
230
1.57k
                return;
231
1.57k
            }
232
7.45k
        if (last < 8) {
233
7.45k
            mvstack[last].mv = mvp;
234
7.45k
            mvstack[last].weight = weight;
235
7.45k
            *cnt = last + 1;
236
7.45k
        }
237
7.45k
    }
238
20.6k
}
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
104k
{
247
104k
    refmvs_candidate *const diff = &same[2];
248
104k
    int *const diff_count = &same_count[2];
249
250
268k
    for (int n = 0; n < 2; n++) {
251
206k
        const int cand_ref = cand_b->ref.ref[n];
252
253
206k
        if (cand_ref <= 0) break;
254
255
163k
        mv cand_mv = cand_b->mv.mv[n];
256
163k
        if (cand_ref == ref.ref[0]) {
257
59.9k
            if (same_count[0] < 2)
258
57.9k
                same[same_count[0]++].mv.mv[0] = cand_mv;
259
59.9k
            if (diff_count[1] < 2) {
260
51.7k
                if (sign1 ^ sign_bias[cand_ref - 1]) {
261
3.91k
                    cand_mv.y = -cand_mv.y;
262
3.91k
                    cand_mv.x = -cand_mv.x;
263
3.91k
                }
264
51.7k
                diff[diff_count[1]++].mv.mv[1] = cand_mv;
265
51.7k
            }
266
103k
        } else if (cand_ref == ref.ref[1]) {
267
55.4k
            if (same_count[1] < 2)
268
53.9k
                same[same_count[1]++].mv.mv[1] = cand_mv;
269
55.4k
            if (diff_count[0] < 2) {
270
45.6k
                if (sign0 ^ sign_bias[cand_ref - 1]) {
271
2.70k
                    cand_mv.y = -cand_mv.y;
272
2.70k
                    cand_mv.x = -cand_mv.x;
273
2.70k
                }
274
45.6k
                diff[diff_count[0]++].mv.mv[0] = cand_mv;
275
45.6k
            }
276
55.4k
        } else {
277
48.4k
            mv i_cand_mv = (union mv) {
278
48.4k
                .x = -cand_mv.x,
279
48.4k
                .y = -cand_mv.y
280
48.4k
            };
281
282
48.4k
            if (diff_count[0] < 2) {
283
38.6k
                diff[diff_count[0]++].mv.mv[0] =
284
38.6k
                    sign0 ^ sign_bias[cand_ref - 1] ?
285
36.7k
                    i_cand_mv : cand_mv;
286
38.6k
            }
287
288
48.4k
            if (diff_count[1] < 2) {
289
36.0k
                diff[diff_count[1]++].mv.mv[1] =
290
36.0k
                    sign1 ^ sign_bias[cand_ref - 1] ?
291
34.3k
                    i_cand_mv : cand_mv;
292
36.0k
            }
293
48.4k
        }
294
163k
    }
295
104k
}
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
201k
{
301
410k
    for (int n = 0; n < 2; n++) {
302
392k
        const int cand_ref = cand_b->ref.ref[n];
303
304
392k
        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
209k
        mv cand_mv = cand_b->mv.mv[n];
312
209k
        if (sign ^ sign_bias[cand_ref - 1]) {
313
5.17k
            cand_mv.y = -cand_mv.y;
314
5.17k
            cand_mv.x = -cand_mv.x;
315
5.17k
        }
316
317
209k
        int m;
318
209k
        const int last = *cnt;
319
255k
        for (m = 0; m < last; m++)
320
186k
            if (cand_mv.n == mvstack[m].mv.mv[0].n)
321
140k
                break;
322
209k
        if (m == last) {
323
68.6k
            mvstack[m].mv.mv[0] = cand_mv;
324
68.6k
            mvstack[m].weight = 2; // "minimal"
325
68.6k
            *cnt = last + 1;
326
68.6k
        }
327
209k
    }
328
201k
}
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
723k
{
356
723k
    const refmvs_frame *const rf = rt->rf;
357
723k
    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
358
723k
    const int bw4 = b_dim[0], w4 = imin(imin(bw4, 16), rt->tile_col.end - bx4);
359
723k
    const int bh4 = b_dim[1], h4 = imin(imin(bh4, 16), rt->tile_row.end - by4);
360
723k
    mv gmv[2], tgmv[2];
361
362
723k
    *cnt = 0;
363
723k
    assert(ref.ref[0] >=  0 && ref.ref[0] <= 8 &&
364
723k
           ref.ref[1] >= -1 && ref.ref[1] <= 8);
365
723k
    if (ref.ref[0] > 0) {
366
411k
        tgmv[0] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[0] - 1],
367
411k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
368
411k
        gmv[0] = rf->frm_hdr->gmv[ref.ref[0] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
369
285k
                 tgmv[0] : (mv) { .n = INVALID_MV };
370
411k
    } else {
371
312k
        tgmv[0] = (mv) { .n = 0 };
372
312k
        gmv[0] = (mv) { .n = INVALID_MV };
373
312k
    }
374
723k
    if (ref.ref[1] > 0) {
375
100k
        tgmv[1] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[1] - 1],
376
100k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
377
100k
        gmv[1] = rf->frm_hdr->gmv[ref.ref[1] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
378
70.8k
                 tgmv[1] : (mv) { .n = INVALID_MV };
379
100k
    }
380
381
    // top
382
723k
    int have_newmv = 0, have_col_mvs = 0, have_row_mvs = 0;
383
723k
    unsigned max_rows = 0, n_rows = ~0;
384
723k
    const refmvs_block *b_top;
385
723k
    if (by4 > rt->tile_row.start) {
386
485k
        max_rows = imin((by4 - rt->tile_row.start + 1) >> 1, 2 + (bh4 > 1));
387
485k
        b_top = &rt->r[(by4 & 31) - 1 + 5][bx4];
388
485k
        n_rows = scan_row(mvstack, cnt, ref, gmv, b_top,
389
485k
                          bw4, w4, max_rows, bw4 >= 16 ? 4 : 1,
390
485k
                          &have_newmv, &have_row_mvs);
391
485k
    }
392
393
    // left
394
723k
    unsigned max_cols = 0, n_cols = ~0U;
395
723k
    refmvs_block *const *b_left;
396
723k
    if (bx4 > rt->tile_col.start) {
397
589k
        max_cols = imin((bx4 - rt->tile_col.start + 1) >> 1, 2 + (bw4 > 1));
398
589k
        b_left = &rt->r[(by4 & 31) + 5];
399
589k
        n_cols = scan_col(mvstack, cnt, ref, gmv, b_left,
400
589k
                          bh4, h4, bx4 - 1, max_cols, bh4 >= 16 ? 4 : 1,
401
589k
                          &have_newmv, &have_col_mvs);
402
589k
    }
403
404
    // top/right
405
723k
    if (n_rows != ~0U && edge_flags & EDGE_I444_TOP_HAS_RIGHT &&
406
275k
        imax(bw4, bh4) <= 16 && bw4 + bx4 < rt->tile_col.end)
407
239k
    {
408
239k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[bw4], ref, gmv,
409
239k
                              &have_newmv, &have_row_mvs);
410
239k
    }
411
412
723k
    const int nearest_match = have_col_mvs + have_row_mvs;
413
723k
    const int nearest_cnt = *cnt;
414
1.54M
    for (int n = 0; n < nearest_cnt; n++)
415
817k
        mvstack[n].weight += 640;
416
417
    // temporal
418
723k
    int globalmv_ctx = rf->frm_hdr->use_ref_frame_mvs;
419
723k
    if (rf->use_ref_frame_mvs) {
420
46.9k
        const ptrdiff_t stride = rf->rp_stride;
421
46.9k
        const int by8 = by4 >> 1, bx8 = bx4 >> 1;
422
46.9k
        const refmvs_temporal_block *const rbi = &rt->rp_proj[(by8 & 15) * stride + bx8];
423
46.9k
        const refmvs_temporal_block *rb = rbi;
424
46.9k
        const int step_h = bw4 >= 16 ? 2 : 1, step_v = bh4 >= 16 ? 2 : 1;
425
46.9k
        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
46.9k
        const refmvs_temporal_block *run = &rb[0];
440
46.9k
        int run_len = 1;
441
46.9k
        int *run_gmv_ctx = &globalmv_ctx;
442
161k
        for (int y = 0; y < h8; y += step_v) {
443
195k
            for (int x = y ? 0 : step_h; x < w8; x += step_h) {
444
81.5k
                const unsigned mvn = rb[x].mv.n;
445
81.5k
                if (mvn == run->mv.n &&
446
76.9k
                    (mvn == INVALID_MV || rb[x].ref == run->ref))
447
76.6k
                {
448
76.6k
                    run_len++;
449
76.6k
                    continue;
450
76.6k
                }
451
4.92k
                add_temporal_candidate(rf, mvstack, cnt, run, ref,
452
4.92k
                                       run_gmv_ctx, tgmv, 2 * run_len);
453
4.92k
                run_gmv_ctx = NULL;
454
4.92k
                run = &rb[x];
455
4.92k
                run_len = 1;
456
4.92k
            }
457
114k
            rb += stride * step_v;
458
114k
        }
459
46.9k
        add_temporal_candidate(rf, mvstack, cnt, run, ref,
460
46.9k
                               run_gmv_ctx, tgmv, 2 * run_len);
461
46.9k
        if (imin(bw4, bh4) >= 2 && imax(bw4, bh4) < 16) {
462
20.0k
            const int bh8 = bh4 >> 1, bw8 = bw4 >> 1;
463
20.0k
            rb = &rbi[bh8 * stride];
464
20.0k
            const int has_bottom = by8 + bh8 < imin(rt->tile_row.end >> 1,
465
20.0k
                                                    (by8 & ~7) + 8);
466
20.0k
            if (has_bottom && bx8 - 1 >= imax(rt->tile_col.start >> 1, bx8 & ~7)) {
467
855
                add_temporal_candidate(rf, mvstack, cnt, &rb[-1], ref,
468
855
                                       NULL, NULL, 2);
469
855
            }
470
20.0k
            if (bx8 + bw8 < imin(rt->tile_col.end >> 1, (bx8 & ~7) + 8)) {
471
1.43k
                if (has_bottom) {
472
893
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8], ref,
473
893
                                           NULL, NULL, 2);
474
893
                }
475
1.43k
                if (by8 + bh8 - 1 < imin(rt->tile_row.end >> 1, (by8 & ~7) + 8)) {
476
1.20k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8 - stride],
477
1.20k
                                           ref, NULL, NULL, 2);
478
1.20k
                }
479
1.43k
            }
480
20.0k
        }
481
46.9k
    }
482
723k
    assert(*cnt <= 8);
483
484
    // top/left (which, confusingly, is part of "secondary" references)
485
723k
    int have_dummy_newmv_match;
486
723k
    if ((n_rows | n_cols) != ~0U) {
487
431k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[-1], ref, gmv,
488
431k
                              &have_dummy_newmv_match, &have_row_mvs);
489
431k
    }
490
491
    // "secondary" (non-direct neighbour) top & left edges
492
    // what is different about secondary is that everything is now in 8x8 resolution
493
2.16M
    for (int n = 2; n <= 3; n++) {
494
1.44M
        if ((unsigned) n > n_rows && (unsigned) n <= max_rows) {
495
437k
            n_rows += scan_row(mvstack, cnt, ref, gmv,
496
437k
                               &rt->r[(((by4 & 31) - 2 * n + 1) | 1) + 5][bx4 | 1],
497
437k
                               bw4, w4, 1 + max_rows - n, bw4 >= 16 ? 4 : 2,
498
437k
                               &have_dummy_newmv_match, &have_row_mvs);
499
437k
        }
500
501
1.44M
        if ((unsigned) n > n_cols && (unsigned) n <= max_cols) {
502
661k
            n_cols += scan_col(mvstack, cnt, ref, gmv, &rt->r[((by4 & 31) | 1) + 5],
503
661k
                               bh4, h4, (bx4 - n * 2 + 1) | 1,
504
661k
                               1 + max_cols - n, bh4 >= 16 ? 4 : 2,
505
661k
                               &have_dummy_newmv_match, &have_col_mvs);
506
661k
        }
507
1.44M
    }
508
723k
    assert(*cnt <= 8);
509
510
723k
    const int ref_match_count = have_col_mvs + have_row_mvs;
511
512
    // context build-up
513
723k
    int refmv_ctx, newmv_ctx;
514
723k
    switch (nearest_match) {
515
192k
    case 0:
516
192k
        refmv_ctx = imin(2, ref_match_count);
517
192k
        newmv_ctx = ref_match_count > 0;
518
192k
        break;
519
288k
    case 1:
520
288k
        refmv_ctx = imin(ref_match_count * 3, 4);
521
288k
        newmv_ctx = 3 - have_newmv;
522
288k
        break;
523
242k
    case 2:
524
242k
        refmv_ctx = 5;
525
242k
        newmv_ctx = 5 - have_newmv;
526
242k
        break;
527
723k
    }
528
529
    // sorting (nearest, then "secondary")
530
723k
    int len = nearest_cnt;
531
1.39M
    while (len) {
532
675k
        int last = 0;
533
1.02M
        for (int n = 1; n < len; n++) {
534
347k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
535
186k
#define EXCHANGE(a, b) do { refmvs_candidate tmp = a; a = b; b = tmp; } while (0)
536
152k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
537
152k
                last = n;
538
152k
            }
539
347k
        }
540
675k
        len = last;
541
675k
    }
542
723k
    len = *cnt;
543
1.13M
    while (len > nearest_cnt) {
544
410k
        int last = nearest_cnt;
545
611k
        for (int n = nearest_cnt + 1; n < len; n++) {
546
201k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
547
33.9k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
548
33.9k
#undef EXCHANGE
549
33.9k
                last = n;
550
33.9k
            }
551
201k
        }
552
410k
        len = last;
553
410k
    }
554
555
723k
    if (ref.ref[1] > 0) {
556
100k
        if (*cnt < 2) {
557
79.8k
            const int sign0 = rf->sign_bias[ref.ref[0] - 1];
558
79.8k
            const int sign1 = rf->sign_bias[ref.ref[1] - 1];
559
79.8k
            const int sz4 = imin(w4, h4);
560
79.8k
            refmvs_candidate *const same = &mvstack[*cnt];
561
79.8k
            int same_count[4] = { 0 };
562
563
            // non-self references in top
564
100k
            if (n_rows != ~0U) for (int x = 0; x < sz4;) {
565
51.9k
                const refmvs_block *const cand_b = &b_top[x];
566
51.9k
                add_compound_extended_candidate(same, same_count, cand_b,
567
51.9k
                                                sign0, sign1, ref, rf->sign_bias);
568
51.9k
                x += dav1d_block_dimensions[cand_b->bs][0];
569
51.9k
            }
570
571
            // non-self references in left
572
98.8k
            if (n_cols != ~0U) for (int y = 0; y < sz4;) {
573
52.7k
                const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
574
52.7k
                add_compound_extended_candidate(same, same_count, cand_b,
575
52.7k
                                                sign0, sign1, ref, rf->sign_bias);
576
52.7k
                y += dav1d_block_dimensions[cand_b->bs][1];
577
52.7k
            }
578
579
79.8k
            refmvs_candidate *const diff = &same[2];
580
79.8k
            const int *const diff_count = &same_count[2];
581
582
            // merge together
583
239k
            for (int n = 0; n < 2; n++) {
584
159k
                int m = same_count[n];
585
586
159k
                if (m >= 2) continue;
587
588
131k
                const int l = diff_count[n];
589
131k
                if (l) {
590
78.2k
                    same[m].mv.mv[n] = diff[0].mv.mv[n];
591
78.2k
                    if (++m == 2) continue;
592
26.5k
                    if (l == 2) {
593
21.8k
                        same[1].mv.mv[n] = diff[1].mv.mv[n];
594
21.8k
                        continue;
595
21.8k
                    }
596
26.5k
                }
597
107k
                do {
598
107k
                    same[m].mv.mv[n] = tgmv[n];
599
107k
                } while (++m < 2);
600
57.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
79.8k
            int n = *cnt;
605
79.8k
            if (n == 1 && mvstack[0].mv.n == same[0].mv.n)
606
22.2k
                mvstack[1].mv = mvstack[2].mv;
607
126k
            do {
608
126k
                mvstack[n].weight = 2;
609
126k
            } while (++n < 2);
610
79.8k
            *cnt = 2;
611
79.8k
        }
612
613
        // clamping
614
100k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
615
100k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
616
100k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
617
100k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
618
619
100k
        const int n_refmvs = *cnt;
620
100k
        int n = 0;
621
210k
        do {
622
210k
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
623
210k
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
624
210k
            mvstack[n].mv.mv[1].x = iclip(mvstack[n].mv.mv[1].x, left, right);
625
210k
            mvstack[n].mv.mv[1].y = iclip(mvstack[n].mv.mv[1].y, top, bottom);
626
210k
        } while (++n < n_refmvs);
627
628
100k
        switch (refmv_ctx >> 1) {
629
54.3k
        case 0:
630
54.3k
            *ctx = imin(newmv_ctx, 1);
631
54.3k
            break;
632
29.6k
        case 1:
633
29.6k
            *ctx = 1 + imin(newmv_ctx, 3);
634
29.6k
            break;
635
16.2k
        case 2:
636
16.2k
            *ctx = iclip(3 + newmv_ctx, 4, 7);
637
16.2k
            break;
638
100k
        }
639
640
100k
        return;
641
622k
    } else if (*cnt < 2 && ref.ref[0] > 0) {
642
189k
        const int sign = rf->sign_bias[ref.ref[0] - 1];
643
189k
        const int sz4 = imin(w4, h4);
644
645
        // non-self references in top
646
213k
        if (n_rows != ~0U) for (int x = 0; x < sz4 && *cnt < 2;) {
647
108k
            const refmvs_block *const cand_b = &b_top[x];
648
108k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
649
108k
            x += dav1d_block_dimensions[cand_b->bs][0];
650
108k
        }
651
652
        // non-self references in left
653
199k
        if (n_cols != ~0U) for (int y = 0; y < sz4 && *cnt < 2;) {
654
92.9k
            const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
655
92.9k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
656
92.9k
            y += dav1d_block_dimensions[cand_b->bs][1];
657
92.9k
        }
658
189k
    }
659
622k
    assert(*cnt <= 8);
660
661
    // clamping
662
622k
    int n_refmvs = *cnt;
663
622k
    if (n_refmvs) {
664
535k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
665
535k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
666
535k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
667
535k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
668
669
535k
        int n = 0;
670
1.37M
        do {
671
1.37M
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
672
1.37M
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
673
1.37M
        } while (++n < n_refmvs);
674
535k
    }
675
676
917k
    for (int n = *cnt; n < 2; n++)
677
294k
        mvstack[n].mv.mv[0] = tgmv[0];
678
679
622k
    *ctx = (refmv_ctx << 4) | (globalmv_ctx << 3) | newmv_ctx;
680
622k
}
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
221k
{
687
221k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
688
221k
    rt->rp_proj = &rf->rp_proj[16 * rf->rp_stride * tile_row_idx];
689
221k
    const ptrdiff_t r_stride = rf->rp_stride * 2;
690
221k
    const ptrdiff_t pass_off = (rf->n_frame_threads > 1 && pass == 2) ?
691
115k
        35 * 2 * rf->n_blocks : 0;
692
221k
    refmvs_block *r = &rf->r[35 * r_stride * tile_row_idx + pass_off];
693
221k
    const int sbsz = rf->sbsz;
694
221k
    const int off = (sbsz * sby) & 16;
695
5.19M
    for (int i = 0; i < sbsz; i++, r += r_stride)
696
4.97M
        rt->r[off + 5 + i] = r;
697
221k
    rt->r[off + 0] = r;
698
221k
    r += r_stride;
699
221k
    rt->r[off + 1] = NULL;
700
221k
    rt->r[off + 2] = r;
701
221k
    r += r_stride;
702
221k
    rt->r[off + 3] = NULL;
703
221k
    rt->r[off + 4] = r;
704
221k
    if (sby & 1) {
705
74.2k
#define EXCHANGE(a, b) do { void *const tmp = a; a = b; b = tmp; } while (0)
706
24.7k
        EXCHANGE(rt->r[off + 0], rt->r[off + sbsz + 0]);
707
24.7k
        EXCHANGE(rt->r[off + 2], rt->r[off + sbsz + 2]);
708
24.7k
        EXCHANGE(rt->r[off + 4], rt->r[off + sbsz + 4]);
709
24.7k
#undef EXCHANGE
710
24.7k
    }
711
712
221k
    rt->rf = rf;
713
221k
    rt->tile_row.start = tile_row_start4;
714
221k
    rt->tile_row.end = imin(tile_row_end4, rf->ih4);
715
221k
    rt->tile_col.start = tile_col_start4;
716
221k
    rt->tile_col.end = imin(tile_col_end4, rf->iw4);
717
221k
}
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
26.8k
{
723
26.8k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
724
26.8k
    assert(row_start8 >= 0);
725
26.8k
    assert((unsigned) (row_end8 - row_start8) <= 16U);
726
26.8k
    row_end8 = imin(row_end8, rf->ih8);
727
26.8k
    const int col_start8i = imax(col_start8 - 8, 0);
728
26.8k
    const int col_end8i = imin(col_end8 + 8, rf->iw8);
729
730
26.8k
    const ptrdiff_t stride = rf->rp_stride;
731
26.8k
    refmvs_temporal_block *rp_proj =
732
26.8k
        &rf->rp_proj[16 * stride * tile_row_idx + (row_start8 & 15) * stride];
733
240k
    for (int y = row_start8; y < row_end8; y++) {
734
464k
        for (int x = col_start8; x < col_end8; x++)
735
250k
            rp_proj[x].mv.n = INVALID_MV;
736
213k
        rp_proj += stride;
737
213k
    }
738
739
26.8k
    rp_proj = &rf->rp_proj[16 * stride * tile_row_idx];
740
58.2k
    for (int n = 0; n < rf->n_mfmvs; n++) {
741
31.4k
        const int ref2cur = rf->mfmv_ref2cur[n];
742
31.4k
        if (ref2cur == INVALID_REF2CUR) continue;
743
744
29.4k
        const int ref = rf->mfmv_ref[n];
745
29.4k
        const int ref_sign = ref - 4;
746
29.4k
        const refmvs_temporal_block *r = &rf->rp_ref[ref][row_start8 * stride];
747
264k
        for (int y = row_start8; y < row_end8; y++) {
748
234k
            const int y_sb_align = y & ~7;
749
234k
            const int y_proj_start = imax(y_sb_align, row_start8);
750
234k
            const int y_proj_end = imin(y_sb_align + 8, row_end8);
751
486k
            for (int x = col_start8i; x < col_end8i; x++) {
752
251k
                const refmvs_temporal_block *rb = &r[x];
753
251k
                const int b_ref = rb->ref;
754
251k
                if (!b_ref) continue;
755
87.8k
                const int ref2ref = rf->mfmv_ref2ref[n][b_ref - 1];
756
87.8k
                if (!ref2ref) continue;
757
73.3k
                const mv b_mv = rb->mv;
758
73.3k
                const mv offset = mv_projection(b_mv, ref2cur, ref2ref);
759
73.3k
                int pos_x = x + apply_sign(abs(offset.x) >> 6,
760
73.3k
                                           offset.x ^ ref_sign);
761
73.3k
                const int pos_y = y + apply_sign(abs(offset.y) >> 6,
762
73.3k
                                                 offset.y ^ ref_sign);
763
73.3k
                if (pos_y >= y_proj_start && pos_y < y_proj_end) {
764
69.6k
                    const ptrdiff_t pos = (pos_y & 15) * stride;
765
88.7k
                    for (;;) {
766
88.7k
                        const int x_sb_align = x & ~7;
767
88.7k
                        if (pos_x >= imax(x_sb_align - 8, col_start8) &&
768
87.2k
                            pos_x < imin(x_sb_align + 16, col_end8))
769
86.8k
                        {
770
86.8k
                            rp_proj[pos + pos_x].mv = rb->mv;
771
86.8k
                            rp_proj[pos + pos_x].ref = ref2ref;
772
86.8k
                        }
773
88.7k
                        if (++x >= col_end8i) break;
774
25.2k
                        rb++;
775
25.2k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
776
19.1k
                        pos_x++;
777
19.1k
                    }
778
69.6k
                } else {
779
4.12k
                    for (;;) {
780
4.12k
                        if (++x >= col_end8i) break;
781
1.65k
                        rb++;
782
1.65k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
783
1.65k
                    }
784
3.71k
                }
785
73.3k
                x--;
786
73.3k
            }
787
234k
            r += stride;
788
234k
        }
789
29.4k
    }
790
26.8k
}
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
47.3k
{
798
326k
    for (int y = row_start8; y < row_end8; y++) {
799
279k
        const refmvs_block *const b = rr[(y & 15) * 2];
800
801
571k
        for (int x = col_start8; x < col_end8;) {
802
292k
            const refmvs_block *const cand_b = &b[x * 2 + 1];
803
292k
            const int bw8 = (dav1d_block_dimensions[cand_b->bs][0] + 1) >> 1;
804
805
292k
            if (cand_b->ref.ref[1] > 0 && ref_sign[cand_b->ref.ref[1] - 1] &&
806
39.2k
                (abs(cand_b->mv.mv[1].y) | abs(cand_b->mv.mv[1].x)) < 4096)
807
38.7k
            {
808
38.7k
                const refmvs_temporal_block tmv = {
809
38.7k
                    .mv = cand_b->mv.mv[1],
810
38.7k
                    .ref = cand_b->ref.ref[1],
811
38.7k
                };
812
175k
                for (int n = 0; n < bw8; n++, x++)
813
137k
                    rp[x] = tmv;
814
253k
            } else if (cand_b->ref.ref[0] > 0 && ref_sign[cand_b->ref.ref[0] - 1] &&
815
39.1k
                       (abs(cand_b->mv.mv[0].y) | abs(cand_b->mv.mv[0].x)) < 4096)
816
38.4k
            {
817
38.4k
                const refmvs_temporal_block tmv = {
818
38.4k
                    .mv = cand_b->mv.mv[0],
819
38.4k
                    .ref = cand_b->ref.ref[0],
820
38.4k
                };
821
257k
                for (int n = 0; n < bw8; n++, x++)
822
219k
                    rp[x] = tmv;
823
215k
            } else {
824
215k
                memset(&rp[x], 0, bw8 * sizeof(*rp));
825
215k
                x += bw8;
826
215k
            }
827
292k
        }
828
279k
        rp += stride;
829
279k
    }
830
47.3k
}
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
95.5k
{
841
95.5k
    const int rp_stride = ((frm_hdr->width[0] + 127) & ~127) >> 3;
842
95.5k
    const int n_tile_rows = n_tile_threads > 1 ? frm_hdr->tiling.rows : 1;
843
95.5k
    const int n_blocks = rp_stride * n_tile_rows;
844
845
95.5k
    rf->sbsz = 16 << seq_hdr->sb128;
846
95.5k
    rf->frm_hdr = frm_hdr;
847
95.5k
    rf->iw8 = (frm_hdr->width[0] + 7) >> 3;
848
95.5k
    rf->ih8 = (frm_hdr->height + 7) >> 3;
849
95.5k
    rf->iw4 = rf->iw8 << 1;
850
95.5k
    rf->ih4 = rf->ih8 << 1;
851
95.5k
    rf->rp = rp;
852
95.5k
    rf->rp_stride = rp_stride;
853
95.5k
    rf->n_tile_threads = n_tile_threads;
854
95.5k
    rf->n_frame_threads = n_frame_threads;
855
856
95.5k
    if (n_blocks != rf->n_blocks) {
857
29.0k
        const size_t r_sz = sizeof(*rf->r) * 35 * 2 * n_blocks * (1 + (n_frame_threads > 1));
858
29.0k
        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
29.0k
        dav1d_free_aligned(rf->r);
862
29.0k
        rf->r = dav1d_alloc_aligned(ALLOC_REFMVS, r_sz + rp_proj_sz, 64);
863
29.0k
        if (!rf->r) {
864
0
            rf->n_blocks = 0;
865
0
            return DAV1D_ERR(ENOMEM);
866
0
        }
867
868
29.0k
        rf->rp_proj = (refmvs_temporal_block*)((uintptr_t)rf->r + r_sz);
869
29.0k
        rf->n_blocks = n_blocks;
870
29.0k
    }
871
872
95.5k
    const int poc = frm_hdr->frame_offset;
873
764k
    for (int i = 0; i < 7; i++) {
874
668k
        const int poc_diff = get_poc_diff(seq_hdr->order_hint_n_bits,
875
668k
                                          ref_poc[i], poc);
876
668k
        rf->sign_bias[i] = poc_diff > 0;
877
668k
        rf->mfmv_sign[i] = poc_diff < 0;
878
668k
        rf->pocdiff[i] = iclip(get_poc_diff(seq_hdr->order_hint_n_bits,
879
668k
                                            poc, ref_poc[i]), -31, 31);
880
668k
    }
881
882
    // temporal MV setup
883
95.5k
    rf->n_mfmvs = 0;
884
95.5k
    rf->rp_ref = rp_ref;
885
95.5k
    if (frm_hdr->use_ref_frame_mvs && seq_hdr->order_hint_n_bits) {
886
26.0k
        int total = 2;
887
26.0k
        if (rp_ref[0] && ref_ref_poc[0][6] != ref_poc[3] /* alt-of-last != gold */) {
888
6.54k
            rf->mfmv_ref[rf->n_mfmvs++] = 0; // last
889
6.54k
            total = 3;
890
6.54k
        }
891
26.0k
        if (rp_ref[4] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[4],
892
17.7k
                                      frm_hdr->frame_offset) > 0)
893
847
        {
894
847
            rf->mfmv_ref[rf->n_mfmvs++] = 4; // bwd
895
847
        }
896
26.0k
        if (rp_ref[5] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[5],
897
22.0k
                                      frm_hdr->frame_offset) > 0)
898
337
        {
899
337
            rf->mfmv_ref[rf->n_mfmvs++] = 5; // altref2
900
337
        }
901
26.0k
        if (rf->n_mfmvs < total && rp_ref[6] &&
902
8.30k
            get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[6],
903
8.30k
                         frm_hdr->frame_offset) > 0)
904
1.83k
        {
905
1.83k
            rf->mfmv_ref[rf->n_mfmvs++] = 6; // altref
906
1.83k
        }
907
26.0k
        if (rf->n_mfmvs < total && rp_ref[1])
908
21.3k
            rf->mfmv_ref[rf->n_mfmvs++] = 1; // last2
909
910
56.8k
        for (int n = 0; n < rf->n_mfmvs; n++) {
911
30.8k
            const int rpoc = ref_poc[rf->mfmv_ref[n]];
912
30.8k
            const int diff1 = get_poc_diff(seq_hdr->order_hint_n_bits,
913
30.8k
                                           rpoc, frm_hdr->frame_offset);
914
30.8k
            if (abs(diff1) > 31) {
915
1.55k
                rf->mfmv_ref2cur[n] = INVALID_REF2CUR;
916
29.3k
            } else {
917
29.3k
                rf->mfmv_ref2cur[n] = rf->mfmv_ref[n] < 4 ? -diff1 : diff1;
918
234k
                for (int m = 0; m < 7; m++) {
919
205k
                    const int rrpoc = ref_ref_poc[rf->mfmv_ref[n]][m];
920
205k
                    const int diff2 = get_poc_diff(seq_hdr->order_hint_n_bits,
921
205k
                                                   rpoc, rrpoc);
922
                    // unsigned comparison also catches the < 0 case
923
205k
                    rf->mfmv_ref2ref[n][m] = (unsigned) diff2 > 31U ? 0 : diff2;
924
205k
                }
925
29.3k
            }
926
30.8k
        }
927
26.0k
    }
928
95.5k
    rf->use_ref_frame_mvs = rf->n_mfmvs > 0;
929
930
95.5k
    return 0;
931
95.5k
}
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
1.36M
{
936
5.45M
    do {
937
5.45M
        refmvs_block *const r = *rr++ + bx4;
938
52.9M
        for (int x = 0; x < bw4; x++)
939
47.4M
            r[x] = *rmv;
940
5.45M
    } while (--bh4);
941
1.36M
}
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
26.6k
{
955
26.6k
    c->load_tmvs = load_tmvs_c;
956
26.6k
    c->save_tmvs = save_tmvs_c;
957
26.6k
    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
26.6k
}