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