Coverage Report

Created: 2026-08-13 07:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/dav1d/src/refmvs.c
Line
Count
Source
1
/*
2
 * Copyright © 2020, VideoLAN and dav1d authors
3
 * Copyright © 2020, Two Orioles, LLC
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions are met:
8
 *
9
 * 1. Redistributions of source code must retain the above copyright notice, this
10
 *    list of conditions and the following disclaimer.
11
 *
12
 * 2. Redistributions in binary form must reproduce the above copyright notice,
13
 *    this list of conditions and the following disclaimer in the documentation
14
 *    and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 */
27
28
#include "config.h"
29
30
#include <limits.h>
31
#include <stdlib.h>
32
33
#include "dav1d/common.h"
34
35
#include "common/intops.h"
36
37
#include "src/env.h"
38
#include "src/mem.h"
39
#include "src/refmvs.h"
40
41
static void add_spatial_candidate(refmvs_candidate *const mvstack, int *const cnt,
42
                                  const int weight, const refmvs_block *const b,
43
                                  const union refmvs_refpair ref, const mv gmv[2],
44
                                  int *const have_newmv_match,
45
                                  int *const have_refmv_match)
46
5.85M
{
47
5.85M
    if (b->mv.mv[0].n == INVALID_MV) return; // intra block, no intrabc
48
49
5.02M
    if (ref.ref[1] == -1) {
50
5.76M
        for (int n = 0; n < 2; n++) {
51
5.18M
            if (b->ref.ref[n] == ref.ref[0]) {
52
3.94M
                const mv cand_mv = ((b->mf & 1) && gmv[0].n != INVALID_MV) ?
53
3.83M
                                   gmv[0] : b->mv.mv[n];
54
55
3.94M
                *have_refmv_match = 1;
56
3.94M
                *have_newmv_match |= b->mf >> 1;
57
58
3.94M
                const int last = *cnt;
59
7.17M
                for (int m = 0; m < last; m++)
60
4.60M
                    if (mvstack[m].mv.mv[0].n == cand_mv.n) {
61
1.37M
                        mvstack[m].weight += weight;
62
1.37M
                        return;
63
1.37M
                    }
64
65
2.56M
                if (last < 8) {
66
2.56M
                    mvstack[last].mv.mv[0] = cand_mv;
67
2.56M
                    mvstack[last].weight = weight;
68
2.56M
                    *cnt = last + 1;
69
2.56M
                }
70
2.56M
                return;
71
3.94M
            }
72
5.18M
        }
73
4.52M
    } else if (b->ref.pair == ref.pair) {
74
165k
        const refmvs_mvpair cand_mv = { .mv = {
75
165k
            [0] = ((b->mf & 1) && gmv[0].n != INVALID_MV) ? gmv[0] : b->mv.mv[0],
76
165k
            [1] = ((b->mf & 1) && gmv[1].n != INVALID_MV) ? gmv[1] : b->mv.mv[1],
77
165k
        }};
78
79
165k
        *have_refmv_match = 1;
80
165k
        *have_newmv_match |= b->mf >> 1;
81
82
165k
        const int last = *cnt;
83
246k
        for (int n = 0; n < last; n++)
84
140k
            if (mvstack[n].mv.n == cand_mv.n) {
85
59.2k
                mvstack[n].weight += weight;
86
59.2k
                return;
87
59.2k
            }
88
89
106k
        if (last < 8) {
90
105k
            mvstack[last].mv = cand_mv;
91
105k
            mvstack[last].weight = weight;
92
105k
            *cnt = last + 1;
93
105k
        }
94
106k
    }
95
5.02M
}
96
97
static int scan_row(refmvs_candidate *const mvstack, int *const cnt,
98
                    const union refmvs_refpair ref, const mv gmv[2],
99
                    const refmvs_block *b, const int bw4, const int w4,
100
                    const int max_rows, const int step,
101
                    int *const have_newmv_match, int *const have_refmv_match)
102
1.76M
{
103
1.76M
    const refmvs_block *cand_b = b;
104
1.76M
    const enum BlockSize first_cand_bs = cand_b->bs;
105
1.76M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
106
1.76M
    int cand_bw4 = first_cand_b_dim[0];
107
1.76M
    int len = imax(step, imin(bw4, cand_bw4));
108
109
1.76M
    if (bw4 <= cand_bw4) {
110
        // FIXME weight can be higher for odd blocks (bx4 & 1), but then the
111
        // position of the first block has to be odd already, i.e. not just
112
        // for row_offset=-3/-5
113
        // FIXME why can this not be cand_bw4?
114
1.54M
        const int weight = bw4 == 1 ? 2 :
115
1.54M
                           imax(2, imin(2 * max_rows, first_cand_b_dim[1]));
116
1.54M
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
117
1.54M
                              have_newmv_match, have_refmv_match);
118
1.54M
        return weight >> 1;
119
1.54M
    }
120
121
429k
    for (int x = 0;;) {
122
        // FIXME if we overhang above, we could fill a bitmask so we don't have
123
        // to repeat the add_spatial_candidate() for the next row, but just increase
124
        // the weight here
125
429k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
126
429k
                              have_newmv_match, have_refmv_match);
127
429k
        x += len;
128
429k
        if (x >= w4) return 1;
129
209k
        cand_b = &b[x];
130
209k
        cand_bw4 = dav1d_block_dimensions[cand_b->bs][0];
131
209k
        assert(cand_bw4 < bw4);
132
209k
        len = imax(step, cand_bw4);
133
209k
    }
134
220k
}
135
136
static int scan_col(refmvs_candidate *const mvstack, int *const cnt,
137
                    const union refmvs_refpair ref, const mv gmv[2],
138
                    /*const*/ refmvs_block *const *b, const int bh4, const int h4,
139
                    const int bx4, const int max_cols, const int step,
140
                    int *const have_newmv_match, int *const have_refmv_match)
141
2.39M
{
142
2.39M
    const refmvs_block *cand_b = &b[0][bx4];
143
2.39M
    const enum BlockSize first_cand_bs = cand_b->bs;
144
2.39M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
145
2.39M
    int cand_bh4 = first_cand_b_dim[1];
146
2.39M
    int len = imax(step, imin(bh4, cand_bh4));
147
148
2.39M
    if (bh4 <= cand_bh4) {
149
        // FIXME weight can be higher for odd blocks (by4 & 1), but then the
150
        // position of the first block has to be odd already, i.e. not just
151
        // for col_offset=-3/-5
152
        // FIXME why can this not be cand_bh4?
153
2.13M
        const int weight = bh4 == 1 ? 2 :
154
2.13M
                           imax(2, imin(2 * max_cols, first_cand_b_dim[0]));
155
2.13M
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
156
2.13M
                            have_newmv_match, have_refmv_match);
157
2.13M
        return weight >> 1;
158
2.13M
    }
159
160
497k
    for (int y = 0;;) {
161
        // FIXME if we overhang above, we could fill a bitmask so we don't have
162
        // to repeat the add_spatial_candidate() for the next row, but just increase
163
        // the weight here
164
497k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
165
497k
                              have_newmv_match, have_refmv_match);
166
497k
        y += len;
167
497k
        if (y >= h4) return 1;
168
243k
        cand_b = &b[y][bx4];
169
243k
        cand_bh4 = dav1d_block_dimensions[cand_b->bs][1];
170
243k
        assert(cand_bh4 < bh4);
171
243k
        len = imax(step, cand_bh4);
172
243k
    }
173
257k
}
174
175
140k
static inline union mv mv_projection(const union mv mv, const int num, const int den) {
176
140k
    static const uint16_t div_mult[32] = {
177
140k
           0, 16384, 8192, 5461, 4096, 3276, 2730, 2340,
178
140k
        2048,  1820, 1638, 1489, 1365, 1260, 1170, 1092,
179
140k
        1024,   963,  910,  862,  819,  780,  744,  712,
180
140k
         682,   655,  630,  606,  585,  564,  546,  528
181
140k
    };
182
140k
    assert(den > 0 && den < 32);
183
140k
    assert(num > -32 && num < 32);
184
140k
    const int frac = num * div_mult[den];
185
140k
    const int y = mv.y * frac, x = mv.x * frac;
186
    // Round and clip according to AV1 spec section 7.9.3
187
140k
    return (union mv) { // 0x3fff == (1 << 14) - 1
188
140k
        .y = iclip((y + 8192 + (y >> 31)) >> 14, -0x3fff, 0x3fff),
189
140k
        .x = iclip((x + 8192 + (x >> 31)) >> 14, -0x3fff, 0x3fff)
190
140k
    };
191
140k
}
192
193
static void add_temporal_candidate(const refmvs_frame *const rf,
194
                                   refmvs_candidate *const mvstack, int *const cnt,
195
                                   const refmvs_temporal_block *const rb,
196
                                   const union refmvs_refpair ref, int *const globalmv_ctx,
197
                                   const union mv gmv[])
198
160k
{
199
160k
    if (rb->mv.n == INVALID_MV) return;
200
201
77.3k
    union mv mv = mv_projection(rb->mv, rf->pocdiff[ref.ref[0] - 1], rb->ref);
202
77.3k
    fix_mv_precision(rf->frm_hdr, &mv);
203
204
77.3k
    const int last = *cnt;
205
77.3k
    if (ref.ref[1] == -1) {
206
54.1k
        if (globalmv_ctx)
207
13.1k
            *globalmv_ctx = (abs(mv.x - gmv[0].x) | abs(mv.y - gmv[0].y)) >= 16;
208
209
82.9k
        for (int n = 0; n < last; n++)
210
71.6k
            if (mvstack[n].mv.mv[0].n == mv.n) {
211
42.9k
                mvstack[n].weight += 2;
212
42.9k
                return;
213
42.9k
            }
214
11.2k
        if (last < 8) {
215
11.1k
            mvstack[last].mv.mv[0] = mv;
216
11.1k
            mvstack[last].weight = 2;
217
11.1k
            *cnt = last + 1;
218
11.1k
        }
219
23.1k
    } else {
220
23.1k
        refmvs_mvpair mvp = { .mv = {
221
23.1k
            [0] = mv,
222
23.1k
            [1] = mv_projection(rb->mv, rf->pocdiff[ref.ref[1] - 1], rb->ref),
223
23.1k
        }};
224
23.1k
        fix_mv_precision(rf->frm_hdr, &mvp.mv[1]);
225
226
36.1k
        for (int n = 0; n < last; n++)
227
31.1k
            if (mvstack[n].mv.n == mvp.n) {
228
18.2k
                mvstack[n].weight += 2;
229
18.2k
                return;
230
18.2k
            }
231
4.97k
        if (last < 8) {
232
4.93k
            mvstack[last].mv = mvp;
233
4.93k
            mvstack[last].weight = 2;
234
4.93k
            *cnt = last + 1;
235
4.93k
        }
236
4.97k
    }
237
77.3k
}
238
239
static void add_compound_extended_candidate(refmvs_candidate *const same,
240
                                            int *const same_count,
241
                                            const refmvs_block *const cand_b,
242
                                            const int sign0, const int sign1,
243
                                            const union refmvs_refpair ref,
244
                                            const uint8_t *const sign_bias)
245
135k
{
246
135k
    refmvs_candidate *const diff = &same[2];
247
135k
    int *const diff_count = &same_count[2];
248
249
347k
    for (int n = 0; n < 2; n++) {
250
266k
        const int cand_ref = cand_b->ref.ref[n];
251
252
266k
        if (cand_ref <= 0) break;
253
254
211k
        mv cand_mv = cand_b->mv.mv[n];
255
211k
        if (cand_ref == ref.ref[0]) {
256
74.8k
            if (same_count[0] < 2)
257
72.4k
                same[same_count[0]++].mv.mv[0] = cand_mv;
258
74.8k
            if (diff_count[1] < 2) {
259
64.7k
                if (sign1 ^ sign_bias[cand_ref - 1]) {
260
3.05k
                    cand_mv.y = -cand_mv.y;
261
3.05k
                    cand_mv.x = -cand_mv.x;
262
3.05k
                }
263
64.7k
                diff[diff_count[1]++].mv.mv[1] = cand_mv;
264
64.7k
            }
265
136k
        } else if (cand_ref == ref.ref[1]) {
266
74.5k
            if (same_count[1] < 2)
267
72.9k
                same[same_count[1]++].mv.mv[1] = cand_mv;
268
74.5k
            if (diff_count[0] < 2) {
269
62.3k
                if (sign0 ^ sign_bias[cand_ref - 1]) {
270
3.98k
                    cand_mv.y = -cand_mv.y;
271
3.98k
                    cand_mv.x = -cand_mv.x;
272
3.98k
                }
273
62.3k
                diff[diff_count[0]++].mv.mv[0] = cand_mv;
274
62.3k
            }
275
74.5k
        } else {
276
61.8k
            mv i_cand_mv = (union mv) {
277
61.8k
                .x = -cand_mv.x,
278
61.8k
                .y = -cand_mv.y
279
61.8k
            };
280
281
61.8k
            if (diff_count[0] < 2) {
282
49.2k
                diff[diff_count[0]++].mv.mv[0] =
283
49.2k
                    sign0 ^ sign_bias[cand_ref - 1] ?
284
47.7k
                    i_cand_mv : cand_mv;
285
49.2k
            }
286
287
61.8k
            if (diff_count[1] < 2) {
288
46.6k
                diff[diff_count[1]++].mv.mv[1] =
289
46.6k
                    sign1 ^ sign_bias[cand_ref - 1] ?
290
45.4k
                    i_cand_mv : cand_mv;
291
46.6k
            }
292
61.8k
        }
293
211k
    }
294
135k
}
295
296
static void add_single_extended_candidate(refmvs_candidate mvstack[8], int *const cnt,
297
                                          const refmvs_block *const cand_b,
298
                                          const int sign, const uint8_t *const sign_bias)
299
587k
{
300
1.17M
    for (int n = 0; n < 2; n++) {
301
1.15M
        const int cand_ref = cand_b->ref.ref[n];
302
303
1.15M
        if (cand_ref <= 0) break;
304
        // we need to continue even if cand_ref == ref.ref[0], since
305
        // the candidate could have been added as a globalmv variant,
306
        // which changes the value
307
        // FIXME if scan_{row,col}() returned a mask for the nearest
308
        // edge, we could skip the appropriate ones here
309
310
592k
        mv cand_mv = cand_b->mv.mv[n];
311
592k
        if (sign ^ sign_bias[cand_ref - 1]) {
312
7.38k
            cand_mv.y = -cand_mv.y;
313
7.38k
            cand_mv.x = -cand_mv.x;
314
7.38k
        }
315
316
592k
        int m;
317
592k
        const int last = *cnt;
318
658k
        for (m = 0; m < last; m++)
319
546k
            if (cand_mv.n == mvstack[m].mv.mv[0].n)
320
481k
                break;
321
592k
        if (m == last) {
322
111k
            mvstack[m].mv.mv[0] = cand_mv;
323
111k
            mvstack[m].weight = 2; // "minimal"
324
111k
            *cnt = last + 1;
325
111k
        }
326
592k
    }
327
587k
}
328
329
/*
330
 * refmvs_frame allocates memory for one sbrow (32 blocks high, whole frame
331
 * wide) of 4x4-resolution refmvs_block entries for spatial MV referencing.
332
 * mvrefs_tile[] keeps a list of 35 (32 + 3 above) pointers into this memory,
333
 * and each sbrow, the bottom entries (y=27/29/31) are exchanged with the top
334
 * (-5/-3/-1) pointers by calling dav1d_refmvs_tile_sbrow_init() at the start
335
 * of each tile/sbrow.
336
 *
337
 * For temporal MV referencing, we call dav1d_refmvs_save_tmvs() at the end of
338
 * each tile/sbrow (when tile column threading is enabled), or at the start of
339
 * each interleaved sbrow (i.e. once for all tile columns together, when tile
340
 * column threading is disabled). This will copy the 4x4-resolution spatial MVs
341
 * into 8x8-resolution refmvs_temporal_block structures. Then, for subsequent
342
 * frames, at the start of each tile/sbrow (when tile column threading is
343
 * enabled) or at the start of each interleaved sbrow (when tile column
344
 * threading is disabled), we call load_tmvs(), which will project the MVs to
345
 * their respective position in the current frame.
346
 */
347
348
void dav1d_refmvs_find(const refmvs_tile *const rt,
349
                       refmvs_candidate mvstack[8], int *const cnt,
350
                       int *const ctx,
351
                       const union refmvs_refpair ref, const enum BlockSize bs,
352
                       const enum EdgeFlags edge_flags,
353
                       const int by4, const int bx4)
354
1.43M
{
355
1.43M
    const refmvs_frame *const rf = rt->rf;
356
1.43M
    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
357
1.43M
    const int bw4 = b_dim[0], w4 = imin(imin(bw4, 16), rt->tile_col.end - bx4);
358
1.43M
    const int bh4 = b_dim[1], h4 = imin(imin(bh4, 16), rt->tile_row.end - by4);
359
1.43M
    mv gmv[2], tgmv[2];
360
361
1.43M
    *cnt = 0;
362
1.43M
    assert(ref.ref[0] >=  0 && ref.ref[0] <= 8 &&
363
1.43M
           ref.ref[1] >= -1 && ref.ref[1] <= 8);
364
1.43M
    if (ref.ref[0] > 0) {
365
794k
        tgmv[0] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[0] - 1],
366
794k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
367
794k
        gmv[0] = rf->frm_hdr->gmv[ref.ref[0] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
368
604k
                 tgmv[0] : (mv) { .n = INVALID_MV };
369
794k
    } else {
370
639k
        tgmv[0] = (mv) { .n = 0 };
371
639k
        gmv[0] = (mv) { .n = INVALID_MV };
372
639k
    }
373
1.43M
    if (ref.ref[1] > 0) {
374
138k
        tgmv[1] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[1] - 1],
375
138k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
376
138k
        gmv[1] = rf->frm_hdr->gmv[ref.ref[1] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
377
95.1k
                 tgmv[1] : (mv) { .n = INVALID_MV };
378
138k
    }
379
380
    // top
381
1.43M
    int have_newmv = 0, have_col_mvs = 0, have_row_mvs = 0;
382
1.43M
    unsigned max_rows = 0, n_rows = ~0;
383
1.43M
    const refmvs_block *b_top;
384
1.43M
    if (by4 > rt->tile_row.start) {
385
953k
        max_rows = imin((by4 - rt->tile_row.start + 1) >> 1, 2 + (bh4 > 1));
386
953k
        b_top = &rt->r[(by4 & 31) - 1 + 5][bx4];
387
953k
        n_rows = scan_row(mvstack, cnt, ref, gmv, b_top,
388
953k
                          bw4, w4, max_rows, bw4 >= 16 ? 4 : 1,
389
953k
                          &have_newmv, &have_row_mvs);
390
953k
    }
391
392
    // left
393
1.43M
    unsigned max_cols = 0, n_cols = ~0U;
394
1.43M
    refmvs_block *const *b_left;
395
1.43M
    if (bx4 > rt->tile_col.start) {
396
1.13M
        max_cols = imin((bx4 - rt->tile_col.start + 1) >> 1, 2 + (bw4 > 1));
397
1.13M
        b_left = &rt->r[(by4 & 31) + 5];
398
1.13M
        n_cols = scan_col(mvstack, cnt, ref, gmv, b_left,
399
1.13M
                          bh4, h4, bx4 - 1, max_cols, bh4 >= 16 ? 4 : 1,
400
1.13M
                          &have_newmv, &have_col_mvs);
401
1.13M
    }
402
403
    // top/right
404
1.43M
    if (n_rows != ~0U && edge_flags & EDGE_I444_TOP_HAS_RIGHT &&
405
552k
        imax(bw4, bh4) <= 16 && bw4 + bx4 < rt->tile_col.end)
406
443k
    {
407
443k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[bw4], ref, gmv,
408
443k
                              &have_newmv, &have_row_mvs);
409
443k
    }
410
411
1.43M
    const int nearest_match = have_col_mvs + have_row_mvs;
412
1.43M
    const int nearest_cnt = *cnt;
413
3.06M
    for (int n = 0; n < nearest_cnt; n++)
414
1.62M
        mvstack[n].weight += 640;
415
416
    // temporal
417
1.43M
    int globalmv_ctx = rf->frm_hdr->use_ref_frame_mvs;
418
1.43M
    if (rf->use_ref_frame_mvs) {
419
53.2k
        const ptrdiff_t stride = rf->rp_stride;
420
53.2k
        const int by8 = by4 >> 1, bx8 = bx4 >> 1;
421
53.2k
        const refmvs_temporal_block *const rbi = &rt->rp_proj[(by8 & 15) * stride + bx8];
422
53.2k
        const refmvs_temporal_block *rb = rbi;
423
53.2k
        const int step_h = bw4 >= 16 ? 2 : 1, step_v = bh4 >= 16 ? 2 : 1;
424
53.2k
        const int w8 = imin((w4 + 1) >> 1, 8), h8 = imin((h4 + 1) >> 1, 8);
425
152k
        for (int y = 0; y < h8; y += step_v) {
426
240k
            for (int x = 0; x < w8; x+= step_h) {
427
140k
                add_temporal_candidate(rf, mvstack, cnt, &rb[x], ref,
428
140k
                                       !(x | y) ? &globalmv_ctx : NULL, tgmv);
429
140k
            }
430
99.1k
            rb += stride * step_v;
431
99.1k
        }
432
53.2k
        if (imin(bw4, bh4) >= 2 && imax(bw4, bh4) < 16) {
433
26.0k
            const int bh8 = bh4 >> 1, bw8 = bw4 >> 1;
434
26.0k
            rb = &rbi[bh8 * stride];
435
26.0k
            const int has_bottom = by8 + bh8 < imin(rt->tile_row.end >> 1,
436
26.0k
                                                    (by8 & ~7) + 8);
437
26.0k
            if (has_bottom && bx8 - 1 >= imax(rt->tile_col.start >> 1, bx8 & ~7)) {
438
5.76k
                add_temporal_candidate(rf, mvstack, cnt, &rb[-1], ref,
439
5.76k
                                       NULL, NULL);
440
5.76k
            }
441
26.0k
            if (bx8 + bw8 < imin(rt->tile_col.end >> 1, (bx8 & ~7) + 8)) {
442
9.31k
                if (has_bottom) {
443
5.32k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8], ref,
444
5.32k
                                           NULL, NULL);
445
5.32k
                }
446
9.31k
                if (by8 + bh8 - 1 < imin(rt->tile_row.end >> 1, (by8 & ~7) + 8)) {
447
8.02k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8 - stride],
448
8.02k
                                           ref, NULL, NULL);
449
8.02k
                }
450
9.31k
            }
451
26.0k
        }
452
53.2k
    }
453
1.43M
    assert(*cnt <= 8);
454
455
    // top/left (which, confusingly, is part of "secondary" references)
456
1.43M
    int have_dummy_newmv_match;
457
1.43M
    if ((n_rows | n_cols) != ~0U) {
458
807k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[-1], ref, gmv,
459
807k
                              &have_dummy_newmv_match, &have_row_mvs);
460
807k
    }
461
462
    // "secondary" (non-direct neighbour) top & left edges
463
    // what is different about secondary is that everything is now in 8x8 resolution
464
4.29M
    for (int n = 2; n <= 3; n++) {
465
2.86M
        if ((unsigned) n > n_rows && (unsigned) n <= max_rows) {
466
811k
            n_rows += scan_row(mvstack, cnt, ref, gmv,
467
811k
                               &rt->r[(((by4 & 31) - 2 * n + 1) | 1) + 5][bx4 | 1],
468
811k
                               bw4, w4, 1 + max_rows - n, bw4 >= 16 ? 4 : 2,
469
811k
                               &have_dummy_newmv_match, &have_row_mvs);
470
811k
        }
471
472
2.86M
        if ((unsigned) n > n_cols && (unsigned) n <= max_cols) {
473
1.25M
            n_cols += scan_col(mvstack, cnt, ref, gmv, &rt->r[((by4 & 31) | 1) + 5],
474
1.25M
                               bh4, h4, (bx4 - n * 2 + 1) | 1,
475
1.25M
                               1 + max_cols - n, bh4 >= 16 ? 4 : 2,
476
1.25M
                               &have_dummy_newmv_match, &have_col_mvs);
477
1.25M
        }
478
2.86M
    }
479
1.43M
    assert(*cnt <= 8);
480
481
1.43M
    const int ref_match_count = have_col_mvs + have_row_mvs;
482
483
    // context build-up
484
1.43M
    int refmv_ctx, newmv_ctx;
485
1.43M
    switch (nearest_match) {
486
331k
    case 0:
487
331k
        refmv_ctx = imin(2, ref_match_count);
488
331k
        newmv_ctx = ref_match_count > 0;
489
331k
        break;
490
584k
    case 1:
491
584k
        refmv_ctx = imin(ref_match_count * 3, 4);
492
584k
        newmv_ctx = 3 - have_newmv;
493
584k
        break;
494
518k
    case 2:
495
518k
        refmv_ctx = 5;
496
518k
        newmv_ctx = 5 - have_newmv;
497
518k
        break;
498
1.43M
    }
499
500
    // sorting (nearest, then "secondary")
501
1.43M
    int len = nearest_cnt;
502
2.79M
    while (len) {
503
1.36M
        int last = 0;
504
2.00M
        for (int n = 1; n < len; n++) {
505
639k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
506
336k
#define EXCHANGE(a, b) do { refmvs_candidate tmp = a; a = b; b = tmp; } while (0)
507
276k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
508
276k
                last = n;
509
276k
            }
510
639k
        }
511
1.36M
        len = last;
512
1.36M
    }
513
1.43M
    len = *cnt;
514
2.18M
    while (len > nearest_cnt) {
515
747k
        int last = nearest_cnt;
516
1.14M
        for (int n = nearest_cnt + 1; n < len; n++) {
517
393k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
518
60.4k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
519
60.4k
#undef EXCHANGE
520
60.4k
                last = n;
521
60.4k
            }
522
393k
        }
523
747k
        len = last;
524
747k
    }
525
526
1.43M
    if (ref.ref[1] > 0) {
527
138k
        if (*cnt < 2) {
528
111k
            const int sign0 = rf->sign_bias[ref.ref[0] - 1];
529
111k
            const int sign1 = rf->sign_bias[ref.ref[1] - 1];
530
111k
            const int sz4 = imin(w4, h4);
531
111k
            refmvs_candidate *const same = &mvstack[*cnt];
532
111k
            int same_count[4] = { 0 };
533
534
            // non-self references in top
535
132k
            if (n_rows != ~0U) for (int x = 0; x < sz4;) {
536
68.6k
                const refmvs_block *const cand_b = &b_top[x];
537
68.6k
                add_compound_extended_candidate(same, same_count, cand_b,
538
68.6k
                                                sign0, sign1, ref, rf->sign_bias);
539
68.6k
                x += dav1d_block_dimensions[cand_b->bs][0];
540
68.6k
            }
541
542
            // non-self references in left
543
126k
            if (n_cols != ~0U) for (int y = 0; y < sz4;) {
544
67.0k
                const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
545
67.0k
                add_compound_extended_candidate(same, same_count, cand_b,
546
67.0k
                                                sign0, sign1, ref, rf->sign_bias);
547
67.0k
                y += dav1d_block_dimensions[cand_b->bs][1];
548
67.0k
            }
549
550
111k
            refmvs_candidate *const diff = &same[2];
551
111k
            const int *const diff_count = &same_count[2];
552
553
            // merge together
554
334k
            for (int n = 0; n < 2; n++) {
555
222k
                int m = same_count[n];
556
557
222k
                if (m >= 2) continue;
558
559
188k
                const int l = diff_count[n];
560
188k
                if (l) {
561
107k
                    same[m].mv.mv[n] = diff[0].mv.mv[n];
562
107k
                    if (++m == 2) continue;
563
39.9k
                    if (l == 2) {
564
28.4k
                        same[1].mv.mv[n] = diff[1].mv.mv[n];
565
28.4k
                        continue;
566
28.4k
                    }
567
39.9k
                }
568
163k
                do {
569
163k
                    same[m].mv.mv[n] = tgmv[n];
570
163k
                } while (++m < 2);
571
91.7k
            }
572
573
            // if the first extended was the same as the non-extended one,
574
            // then replace it with the second extended one
575
111k
            int n = *cnt;
576
111k
            if (n == 1 && mvstack[0].mv.n == same[0].mv.n)
577
29.6k
                mvstack[1].mv = mvstack[2].mv;
578
182k
            do {
579
182k
                mvstack[n].weight = 2;
580
182k
            } while (++n < 2);
581
111k
            *cnt = 2;
582
111k
        }
583
584
        // clamping
585
138k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
586
138k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
587
138k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
588
138k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
589
590
138k
        const int n_refmvs = *cnt;
591
138k
        int n = 0;
592
293k
        do {
593
293k
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
594
293k
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
595
293k
            mvstack[n].mv.mv[1].x = iclip(mvstack[n].mv.mv[1].x, left, right);
596
293k
            mvstack[n].mv.mv[1].y = iclip(mvstack[n].mv.mv[1].y, top, bottom);
597
293k
        } while (++n < n_refmvs);
598
599
138k
        switch (refmv_ctx >> 1) {
600
77.8k
        case 0:
601
77.8k
            *ctx = imin(newmv_ctx, 1);
602
77.8k
            break;
603
39.4k
        case 1:
604
39.4k
            *ctx = 1 + imin(newmv_ctx, 3);
605
39.4k
            break;
606
21.1k
        case 2:
607
21.1k
            *ctx = iclip(3 + newmv_ctx, 4, 7);
608
21.1k
            break;
609
138k
        }
610
611
138k
        return;
612
1.29M
    } else if (*cnt < 2 && ref.ref[0] > 0) {
613
487k
        const int sign = rf->sign_bias[ref.ref[0] - 1];
614
487k
        const int sz4 = imin(w4, h4);
615
616
        // non-self references in top
617
607k
        if (n_rows != ~0U) for (int x = 0; x < sz4 && *cnt < 2;) {
618
310k
            const refmvs_block *const cand_b = &b_top[x];
619
310k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
620
310k
            x += dav1d_block_dimensions[cand_b->bs][0];
621
310k
        }
622
623
        // non-self references in left
624
560k
        if (n_cols != ~0U) for (int y = 0; y < sz4 && *cnt < 2;) {
625
277k
            const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
626
277k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
627
277k
            y += dav1d_block_dimensions[cand_b->bs][1];
628
277k
        }
629
487k
    }
630
1.29M
    assert(*cnt <= 8);
631
632
    // clamping
633
1.29M
    int n_refmvs = *cnt;
634
1.29M
    if (n_refmvs) {
635
1.13M
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
636
1.13M
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
637
1.13M
        const int top = -(by4 + bh4 + 4) * 4 * 8;
638
1.13M
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
639
640
1.13M
        int n = 0;
641
2.69M
        do {
642
2.69M
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
643
2.69M
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
644
2.69M
        } while (++n < n_refmvs);
645
1.13M
    }
646
647
1.99M
    for (int n = *cnt; n < 2; n++)
648
695k
        mvstack[n].mv.mv[0] = tgmv[0];
649
650
1.29M
    *ctx = (refmv_ctx << 4) | (globalmv_ctx << 3) | newmv_ctx;
651
1.29M
}
652
653
void dav1d_refmvs_tile_sbrow_init(refmvs_tile *const rt, const refmvs_frame *const rf,
654
                                  const int tile_col_start4, const int tile_col_end4,
655
                                  const int tile_row_start4, const int tile_row_end4,
656
                                  const int sby, int tile_row_idx, const int pass)
657
441k
{
658
441k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
659
441k
    rt->rp_proj = &rf->rp_proj[16 * rf->rp_stride * tile_row_idx];
660
441k
    const ptrdiff_t r_stride = rf->rp_stride * 2;
661
441k
    const ptrdiff_t pass_off = (rf->n_frame_threads > 1 && pass == 2) ?
662
230k
        35 * 2 * rf->n_blocks : 0;
663
441k
    refmvs_block *r = &rf->r[35 * r_stride * tile_row_idx + pass_off];
664
441k
    const int sbsz = rf->sbsz;
665
441k
    const int off = (sbsz * sby) & 16;
666
9.22M
    for (int i = 0; i < sbsz; i++, r += r_stride)
667
8.77M
        rt->r[off + 5 + i] = r;
668
441k
    rt->r[off + 0] = r;
669
441k
    r += r_stride;
670
441k
    rt->r[off + 1] = NULL;
671
441k
    rt->r[off + 2] = r;
672
441k
    r += r_stride;
673
441k
    rt->r[off + 3] = NULL;
674
441k
    rt->r[off + 4] = r;
675
441k
    if (sby & 1) {
676
224k
#define EXCHANGE(a, b) do { void *const tmp = a; a = b; b = tmp; } while (0)
677
74.7k
        EXCHANGE(rt->r[off + 0], rt->r[off + sbsz + 0]);
678
74.7k
        EXCHANGE(rt->r[off + 2], rt->r[off + sbsz + 2]);
679
74.7k
        EXCHANGE(rt->r[off + 4], rt->r[off + sbsz + 4]);
680
74.7k
#undef EXCHANGE
681
74.7k
    }
682
683
441k
    rt->rf = rf;
684
441k
    rt->tile_row.start = tile_row_start4;
685
441k
    rt->tile_row.end = imin(tile_row_end4, rf->ih4);
686
441k
    rt->tile_col.start = tile_col_start4;
687
441k
    rt->tile_col.end = imin(tile_col_end4, rf->iw4);
688
441k
}
689
690
static void load_tmvs_c(const refmvs_frame *const rf, int tile_row_idx,
691
                        const int col_start8, const int col_end8,
692
                        const int row_start8, int row_end8)
693
30.8k
{
694
30.8k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
695
30.8k
    assert(row_start8 >= 0);
696
30.8k
    assert((unsigned) (row_end8 - row_start8) <= 16U);
697
30.8k
    row_end8 = imin(row_end8, rf->ih8);
698
30.8k
    const int col_start8i = imax(col_start8 - 8, 0);
699
30.8k
    const int col_end8i = imin(col_end8 + 8, rf->iw8);
700
701
30.8k
    const ptrdiff_t stride = rf->rp_stride;
702
30.8k
    refmvs_temporal_block *rp_proj =
703
30.8k
        &rf->rp_proj[16 * stride * tile_row_idx + (row_start8 & 15) * stride];
704
169k
    for (int y = row_start8; y < row_end8; y++) {
705
524k
        for (int x = col_start8; x < col_end8; x++)
706
386k
            rp_proj[x].mv.n = INVALID_MV;
707
138k
        rp_proj += stride;
708
138k
    }
709
710
30.8k
    rp_proj = &rf->rp_proj[16 * stride * tile_row_idx];
711
68.4k
    for (int n = 0; n < rf->n_mfmvs; n++) {
712
37.6k
        const int ref2cur = rf->mfmv_ref2cur[n];
713
37.6k
        if (ref2cur == INVALID_REF2CUR) continue;
714
715
26.1k
        const int ref = rf->mfmv_ref[n];
716
26.1k
        const int ref_sign = ref - 4;
717
26.1k
        const refmvs_temporal_block *r = &rf->rp_ref[ref][row_start8 * stride];
718
135k
        for (int y = row_start8; y < row_end8; y++) {
719
109k
            const int y_sb_align = y & ~7;
720
109k
            const int y_proj_start = imax(y_sb_align, row_start8);
721
109k
            const int y_proj_end = imin(y_sb_align + 8, row_end8);
722
263k
            for (int x = col_start8i; x < col_end8i; x++) {
723
154k
                const refmvs_temporal_block *rb = &r[x];
724
154k
                const int b_ref = rb->ref;
725
154k
                if (!b_ref) continue;
726
56.1k
                const int ref2ref = rf->mfmv_ref2ref[n][b_ref - 1];
727
56.1k
                if (!ref2ref) continue;
728
40.0k
                const mv b_mv = rb->mv;
729
40.0k
                const mv offset = mv_projection(b_mv, ref2cur, ref2ref);
730
40.0k
                int pos_x = x + apply_sign(abs(offset.x) >> 6,
731
40.0k
                                           offset.x ^ ref_sign);
732
40.0k
                const int pos_y = y + apply_sign(abs(offset.y) >> 6,
733
40.0k
                                                 offset.y ^ ref_sign);
734
40.0k
                if (pos_y >= y_proj_start && pos_y < y_proj_end) {
735
36.6k
                    const ptrdiff_t pos = (pos_y & 15) * stride;
736
103k
                    for (;;) {
737
103k
                        const int x_sb_align = x & ~7;
738
103k
                        if (pos_x >= imax(x_sb_align - 8, col_start8) &&
739
102k
                            pos_x < imin(x_sb_align + 16, col_end8))
740
100k
                        {
741
100k
                            rp_proj[pos + pos_x].mv = rb->mv;
742
100k
                            rp_proj[pos + pos_x].ref = ref2ref;
743
100k
                        }
744
103k
                        if (++x >= col_end8i) break;
745
79.3k
                        rb++;
746
79.3k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
747
67.0k
                        pos_x++;
748
67.0k
                    }
749
36.6k
                } else {
750
8.06k
                    for (;;) {
751
8.06k
                        if (++x >= col_end8i) break;
752
6.08k
                        rb++;
753
6.08k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
754
6.08k
                    }
755
3.34k
                }
756
40.0k
                x--;
757
40.0k
            }
758
109k
            r += stride;
759
109k
        }
760
26.1k
    }
761
30.8k
}
762
763
static void save_tmvs_c(refmvs_temporal_block *rp, const ptrdiff_t stride,
764
                        refmvs_block *const *const rr,
765
                        const uint8_t *const ref_sign,
766
                        const int col_end8, const int row_end8,
767
                        const int col_start8, const int row_start8)
768
74.8k
{
769
467k
    for (int y = row_start8; y < row_end8; y++) {
770
393k
        const refmvs_block *const b = rr[(y & 15) * 2];
771
772
897k
        for (int x = col_start8; x < col_end8;) {
773
504k
            const refmvs_block *const cand_b = &b[x * 2 + 1];
774
504k
            const int bw8 = (dav1d_block_dimensions[cand_b->bs][0] + 1) >> 1;
775
776
504k
            if (cand_b->ref.ref[1] > 0 && ref_sign[cand_b->ref.ref[1] - 1] &&
777
54.9k
                (abs(cand_b->mv.mv[1].y) | abs(cand_b->mv.mv[1].x)) < 4096)
778
47.7k
            {
779
47.7k
                const refmvs_temporal_block tmv = {
780
47.7k
                    .mv = cand_b->mv.mv[1],
781
47.7k
                    .ref = cand_b->ref.ref[1],
782
47.7k
                };
783
186k
                for (int n = 0; n < bw8; n++, x++)
784
138k
                    rp[x] = tmv;
785
456k
            } else if (cand_b->ref.ref[0] > 0 && ref_sign[cand_b->ref.ref[0] - 1] &&
786
141k
                       (abs(cand_b->mv.mv[0].y) | abs(cand_b->mv.mv[0].x)) < 4096)
787
136k
            {
788
136k
                const refmvs_temporal_block tmv = {
789
136k
                    .mv = cand_b->mv.mv[0],
790
136k
                    .ref = cand_b->ref.ref[0],
791
136k
                };
792
547k
                for (int n = 0; n < bw8; n++, x++)
793
410k
                    rp[x] = tmv;
794
320k
            } else {
795
320k
                const refmvs_temporal_block tmv = { .mv = { .n = 0 }, .ref = 0 };
796
1.46M
                for (int n = 0; n < bw8; n++, x++)
797
1.14M
                    rp[x] = tmv;
798
320k
            }
799
504k
        }
800
393k
        rp += stride;
801
393k
    }
802
74.8k
}
803
804
int dav1d_refmvs_init_frame(refmvs_frame *const rf,
805
                            const Dav1dSequenceHeader *const seq_hdr,
806
                            const Dav1dFrameHeader *const frm_hdr,
807
                            const uint8_t ref_poc[7],
808
                            refmvs_temporal_block *const rp,
809
                            const uint8_t ref_ref_poc[7][7],
810
                            /*const*/ refmvs_temporal_block *const rp_ref[7],
811
                            const int n_tile_threads, const int n_frame_threads)
812
174k
{
813
174k
    const int rp_stride = ((frm_hdr->width[0] + 127) & ~127) >> 3;
814
174k
    const int n_tile_rows = n_tile_threads > 1 ? frm_hdr->tiling.rows : 1;
815
174k
    const int n_blocks = rp_stride * n_tile_rows;
816
817
174k
    rf->sbsz = 16 << seq_hdr->sb128;
818
174k
    rf->frm_hdr = frm_hdr;
819
174k
    rf->iw8 = (frm_hdr->width[0] + 7) >> 3;
820
174k
    rf->ih8 = (frm_hdr->height + 7) >> 3;
821
174k
    rf->iw4 = rf->iw8 << 1;
822
174k
    rf->ih4 = rf->ih8 << 1;
823
174k
    rf->rp = rp;
824
174k
    rf->rp_stride = rp_stride;
825
174k
    rf->n_tile_threads = n_tile_threads;
826
174k
    rf->n_frame_threads = n_frame_threads;
827
828
174k
    if (n_blocks != rf->n_blocks) {
829
48.2k
        const size_t r_sz = sizeof(*rf->r) * 35 * 2 * n_blocks * (1 + (n_frame_threads > 1));
830
48.2k
        const size_t rp_proj_sz = sizeof(*rf->rp_proj) * 16 * n_blocks;
831
        /* Note that sizeof(*rf->r) == 12, but it's accessed using 16-byte unaligned
832
         * loads in save_tmvs() asm which can overread 4 bytes into rp_proj. */
833
48.2k
        dav1d_free_aligned(rf->r);
834
48.2k
        rf->r = dav1d_alloc_aligned(ALLOC_REFMVS, r_sz + rp_proj_sz, 64);
835
48.2k
        if (!rf->r) {
836
0
            rf->n_blocks = 0;
837
0
            return DAV1D_ERR(ENOMEM);
838
0
        }
839
840
48.2k
        rf->rp_proj = (refmvs_temporal_block*)((uintptr_t)rf->r + r_sz);
841
48.2k
        rf->n_blocks = n_blocks;
842
48.2k
    }
843
844
174k
    const int poc = frm_hdr->frame_offset;
845
1.39M
    for (int i = 0; i < 7; i++) {
846
1.22M
        const int poc_diff = get_poc_diff(seq_hdr->order_hint_n_bits,
847
1.22M
                                          ref_poc[i], poc);
848
1.22M
        rf->sign_bias[i] = poc_diff > 0;
849
1.22M
        rf->mfmv_sign[i] = poc_diff < 0;
850
1.22M
        rf->pocdiff[i] = iclip(get_poc_diff(seq_hdr->order_hint_n_bits,
851
1.22M
                                            poc, ref_poc[i]), -31, 31);
852
1.22M
    }
853
854
    // temporal MV setup
855
174k
    rf->n_mfmvs = 0;
856
174k
    rf->rp_ref = rp_ref;
857
174k
    if (frm_hdr->use_ref_frame_mvs && seq_hdr->order_hint_n_bits) {
858
26.5k
        int total = 2;
859
26.5k
        if (rp_ref[0] && ref_ref_poc[0][6] != ref_poc[3] /* alt-of-last != gold */) {
860
8.96k
            rf->mfmv_ref[rf->n_mfmvs++] = 0; // last
861
8.96k
            total = 3;
862
8.96k
        }
863
26.5k
        if (rp_ref[4] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[4],
864
21.3k
                                      frm_hdr->frame_offset) > 0)
865
1.26k
        {
866
1.26k
            rf->mfmv_ref[rf->n_mfmvs++] = 4; // bwd
867
1.26k
        }
868
26.5k
        if (rp_ref[5] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[5],
869
19.5k
                                      frm_hdr->frame_offset) > 0)
870
1.02k
        {
871
1.02k
            rf->mfmv_ref[rf->n_mfmvs++] = 5; // altref2
872
1.02k
        }
873
26.5k
        if (rf->n_mfmvs < total && rp_ref[6] &&
874
14.4k
            get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[6],
875
14.4k
                         frm_hdr->frame_offset) > 0)
876
5.99k
        {
877
5.99k
            rf->mfmv_ref[rf->n_mfmvs++] = 6; // altref
878
5.99k
        }
879
26.5k
        if (rf->n_mfmvs < total && rp_ref[1])
880
17.6k
            rf->mfmv_ref[rf->n_mfmvs++] = 1; // last2
881
882
61.4k
        for (int n = 0; n < rf->n_mfmvs; n++) {
883
34.9k
            const int rpoc = ref_poc[rf->mfmv_ref[n]];
884
34.9k
            const int diff1 = get_poc_diff(seq_hdr->order_hint_n_bits,
885
34.9k
                                           rpoc, frm_hdr->frame_offset);
886
34.9k
            if (abs(diff1) > 31) {
887
11.1k
                rf->mfmv_ref2cur[n] = INVALID_REF2CUR;
888
23.7k
            } else {
889
23.7k
                rf->mfmv_ref2cur[n] = rf->mfmv_ref[n] < 4 ? -diff1 : diff1;
890
189k
                for (int m = 0; m < 7; m++) {
891
166k
                    const int rrpoc = ref_ref_poc[rf->mfmv_ref[n]][m];
892
166k
                    const int diff2 = get_poc_diff(seq_hdr->order_hint_n_bits,
893
166k
                                                   rpoc, rrpoc);
894
                    // unsigned comparison also catches the < 0 case
895
166k
                    rf->mfmv_ref2ref[n][m] = (unsigned) diff2 > 31U ? 0 : diff2;
896
166k
                }
897
23.7k
            }
898
34.9k
        }
899
26.5k
    }
900
174k
    rf->use_ref_frame_mvs = rf->n_mfmvs > 0;
901
902
174k
    return 0;
903
174k
}
904
905
static void splat_mv_c(refmvs_block **rr, const refmvs_block *const rmv,
906
                       const int bx4, const int bw4, int bh4)
907
2.29M
{
908
8.69M
    do {
909
8.69M
        refmvs_block *const r = *rr++ + bx4;
910
80.8M
        for (int x = 0; x < bw4; x++)
911
72.2M
            r[x] = *rmv;
912
8.69M
    } while (--bh4);
913
2.29M
}
914
915
#if HAVE_ASM
916
#if ARCH_AARCH64 || ARCH_ARM
917
#include "src/arm/refmvs.h"
918
#elif ARCH_LOONGARCH64
919
#include "src/loongarch/refmvs.h"
920
#elif ARCH_X86
921
#include "src/x86/refmvs.h"
922
#endif
923
#endif
924
925
COLD void dav1d_refmvs_dsp_init(Dav1dRefmvsDSPContext *const c)
926
60.8k
{
927
60.8k
    c->load_tmvs = load_tmvs_c;
928
60.8k
    c->save_tmvs = save_tmvs_c;
929
60.8k
    c->splat_mv = splat_mv_c;
930
931
#if HAVE_ASM
932
#if ARCH_AARCH64 || ARCH_ARM
933
    refmvs_dsp_init_arm(c);
934
#elif ARCH_LOONGARCH64
935
    refmvs_dsp_init_loongarch(c);
936
#elif ARCH_X86
937
    refmvs_dsp_init_x86(c);
938
#endif
939
#endif
940
60.8k
}