Coverage Report

Created: 2026-10-28 06:18

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