Coverage Report

Created: 2026-09-01 06:57

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
11.0M
{
47
11.0M
    if (b->mv.mv[0].n == INVALID_MV) return; // intra block, no intrabc
48
49
9.41M
    if (ref.ref[1] == -1) {
50
11.1M
        for (int n = 0; n < 2; n++) {
51
9.80M
            if (b->ref.ref[n] == ref.ref[0]) {
52
7.02M
                const mv cand_mv = ((b->mf & 1) && gmv[0].n != INVALID_MV) ?
53
6.80M
                                   gmv[0] : b->mv.mv[n];
54
55
7.02M
                *have_refmv_match = 1;
56
7.02M
                *have_newmv_match |= b->mf >> 1;
57
58
7.02M
                const int last = *cnt;
59
12.4M
                for (int m = 0; m < last; m++)
60
8.33M
                    if (mvstack[m].mv.mv[0].n == cand_mv.n) {
61
2.90M
                        mvstack[m].weight += weight;
62
2.90M
                        return;
63
2.90M
                    }
64
65
4.11M
                if (last < 8) {
66
4.10M
                    mvstack[last].mv.mv[0] = cand_mv;
67
4.10M
                    mvstack[last].weight = weight;
68
4.10M
                    *cnt = last + 1;
69
4.10M
                }
70
4.11M
                return;
71
7.02M
            }
72
9.80M
        }
73
8.34M
    } else if (b->ref.pair == ref.pair) {
74
356k
        const refmvs_mvpair cand_mv = { .mv = {
75
356k
            [0] = ((b->mf & 1) && gmv[0].n != INVALID_MV) ? gmv[0] : b->mv.mv[0],
76
356k
            [1] = ((b->mf & 1) && gmv[1].n != INVALID_MV) ? gmv[1] : b->mv.mv[1],
77
356k
        }};
78
79
356k
        *have_refmv_match = 1;
80
356k
        *have_newmv_match |= b->mf >> 1;
81
82
356k
        const int last = *cnt;
83
545k
        for (int n = 0; n < last; n++)
84
315k
            if (mvstack[n].mv.n == cand_mv.n) {
85
126k
                mvstack[n].weight += weight;
86
126k
                return;
87
126k
            }
88
89
230k
        if (last < 8) {
90
229k
            mvstack[last].mv = cand_mv;
91
229k
            mvstack[last].weight = weight;
92
229k
            *cnt = last + 1;
93
229k
        }
94
230k
    }
95
9.41M
}
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
3.53M
{
103
3.53M
    const refmvs_block *cand_b = b;
104
3.53M
    const enum BlockSize first_cand_bs = cand_b->bs;
105
3.53M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
106
3.53M
    int cand_bw4 = first_cand_b_dim[0];
107
3.53M
    int len = imax(step, imin(bw4, cand_bw4));
108
109
3.53M
    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
3.03M
        const int weight = bw4 == 1 ? 2 :
115
3.03M
                           imax(2, imin(2 * max_rows, first_cand_b_dim[1]));
116
3.03M
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
117
3.03M
                              have_newmv_match, have_refmv_match);
118
3.03M
        return weight >> 1;
119
3.03M
    }
120
121
968k
    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
968k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
126
968k
                              have_newmv_match, have_refmv_match);
127
968k
        x += len;
128
968k
        if (x >= w4) return 1;
129
477k
        cand_b = &b[x];
130
477k
        cand_bw4 = dav1d_block_dimensions[cand_b->bs][0];
131
477k
        assert(cand_bw4 < bw4);
132
477k
        len = imax(step, cand_bw4);
133
477k
    }
134
491k
}
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
4.11M
{
142
4.11M
    const refmvs_block *cand_b = &b[0][bx4];
143
4.11M
    const enum BlockSize first_cand_bs = cand_b->bs;
144
4.11M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
145
4.11M
    int cand_bh4 = first_cand_b_dim[1];
146
4.11M
    int len = imax(step, imin(bh4, cand_bh4));
147
148
4.11M
    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
3.58M
        const int weight = bh4 == 1 ? 2 :
154
3.58M
                           imax(2, imin(2 * max_cols, first_cand_b_dim[0]));
155
3.58M
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
156
3.58M
                            have_newmv_match, have_refmv_match);
157
3.58M
        return weight >> 1;
158
3.58M
    }
159
160
1.06M
    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
1.06M
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
165
1.06M
                              have_newmv_match, have_refmv_match);
166
1.06M
        y += len;
167
1.06M
        if (y >= h4) return 1;
168
531k
        cand_b = &b[y][bx4];
169
531k
        cand_bh4 = dav1d_block_dimensions[cand_b->bs][1];
170
531k
        assert(cand_bh4 < bh4);
171
531k
        len = imax(step, cand_bh4);
172
531k
    }
173
532k
}
174
175
194k
static inline union mv mv_projection(const union mv mv, const int num, const int den) {
176
194k
    static const uint16_t div_mult[32] = {
177
194k
           0, 16384, 8192, 5461, 4096, 3276, 2730, 2340,
178
194k
        2048,  1820, 1638, 1489, 1365, 1260, 1170, 1092,
179
194k
        1024,   963,  910,  862,  819,  780,  744,  712,
180
194k
         682,   655,  630,  606,  585,  564,  546,  528
181
194k
    };
182
194k
    assert(den > 0 && den < 32);
183
194k
    assert(num > -32 && num < 32);
184
194k
    const int frac = num * div_mult[den];
185
194k
    const int y = mv.y * frac, x = mv.x * frac;
186
    // Round and clip according to AV1 spec section 7.9.3
187
194k
    return (union mv) { // 0x3fff == (1 << 14) - 1
188
194k
        .y = iclip((y + 8192 + (y >> 31)) >> 14, -0x3fff, 0x3fff),
189
194k
        .x = iclip((x + 8192 + (x >> 31)) >> 14, -0x3fff, 0x3fff)
190
194k
    };
191
194k
}
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
216k
{
199
216k
    if (rb->mv.n == INVALID_MV) return;
200
201
111k
    union mv mv = mv_projection(rb->mv, rf->pocdiff[ref.ref[0] - 1], rb->ref);
202
111k
    fix_mv_precision(rf->frm_hdr, &mv);
203
204
111k
    const int last = *cnt;
205
111k
    if (ref.ref[1] == -1) {
206
74.1k
        if (globalmv_ctx)
207
18.9k
            *globalmv_ctx = (abs(mv.x - gmv[0].x) | abs(mv.y - gmv[0].y)) >= 16;
208
209
122k
        for (int n = 0; n < last; n++)
210
106k
            if (mvstack[n].mv.mv[0].n == mv.n) {
211
58.4k
                mvstack[n].weight += 2;
212
58.4k
                return;
213
58.4k
            }
214
15.6k
        if (last < 8) {
215
15.6k
            mvstack[last].mv.mv[0] = mv;
216
15.6k
            mvstack[last].weight = 2;
217
15.6k
            *cnt = last + 1;
218
15.6k
        }
219
36.9k
    } else {
220
36.9k
        refmvs_mvpair mvp = { .mv = {
221
36.9k
            [0] = mv,
222
36.9k
            [1] = mv_projection(rb->mv, rf->pocdiff[ref.ref[1] - 1], rb->ref),
223
36.9k
        }};
224
36.9k
        fix_mv_precision(rf->frm_hdr, &mvp.mv[1]);
225
226
56.3k
        for (int n = 0; n < last; n++)
227
49.2k
            if (mvstack[n].mv.n == mvp.n) {
228
29.8k
                mvstack[n].weight += 2;
229
29.8k
                return;
230
29.8k
            }
231
7.17k
        if (last < 8) {
232
7.13k
            mvstack[last].mv = mvp;
233
7.13k
            mvstack[last].weight = 2;
234
7.13k
            *cnt = last + 1;
235
7.13k
        }
236
7.17k
    }
237
111k
}
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
269k
{
246
269k
    refmvs_candidate *const diff = &same[2];
247
269k
    int *const diff_count = &same_count[2];
248
249
692k
    for (int n = 0; n < 2; n++) {
250
530k
        const int cand_ref = cand_b->ref.ref[n];
251
252
530k
        if (cand_ref <= 0) break;
253
254
422k
        mv cand_mv = cand_b->mv.mv[n];
255
422k
        if (cand_ref == ref.ref[0]) {
256
152k
            if (same_count[0] < 2)
257
147k
                same[same_count[0]++].mv.mv[0] = cand_mv;
258
152k
            if (diff_count[1] < 2) {
259
130k
                if (sign1 ^ sign_bias[cand_ref - 1]) {
260
4.32k
                    cand_mv.y = -cand_mv.y;
261
4.32k
                    cand_mv.x = -cand_mv.x;
262
4.32k
                }
263
130k
                diff[diff_count[1]++].mv.mv[1] = cand_mv;
264
130k
            }
265
270k
        } else if (cand_ref == ref.ref[1]) {
266
144k
            if (same_count[1] < 2)
267
140k
                same[same_count[1]++].mv.mv[1] = cand_mv;
268
144k
            if (diff_count[0] < 2) {
269
118k
                if (sign0 ^ sign_bias[cand_ref - 1]) {
270
5.07k
                    cand_mv.y = -cand_mv.y;
271
5.07k
                    cand_mv.x = -cand_mv.x;
272
5.07k
                }
273
118k
                diff[diff_count[0]++].mv.mv[0] = cand_mv;
274
118k
            }
275
144k
        } else {
276
125k
            mv i_cand_mv = (union mv) {
277
125k
                .x = -cand_mv.x,
278
125k
                .y = -cand_mv.y
279
125k
            };
280
281
125k
            if (diff_count[0] < 2) {
282
98.8k
                diff[diff_count[0]++].mv.mv[0] =
283
98.8k
                    sign0 ^ sign_bias[cand_ref - 1] ?
284
96.6k
                    i_cand_mv : cand_mv;
285
98.8k
            }
286
287
125k
            if (diff_count[1] < 2) {
288
92.1k
                diff[diff_count[1]++].mv.mv[1] =
289
92.1k
                    sign1 ^ sign_bias[cand_ref - 1] ?
290
90.6k
                    i_cand_mv : cand_mv;
291
92.1k
            }
292
125k
        }
293
422k
    }
294
269k
}
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
1.16M
{
300
2.34M
    for (int n = 0; n < 2; n++) {
301
2.29M
        const int cand_ref = cand_b->ref.ref[n];
302
303
2.29M
        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
1.17M
        mv cand_mv = cand_b->mv.mv[n];
311
1.17M
        if (sign ^ sign_bias[cand_ref - 1]) {
312
6.44k
            cand_mv.y = -cand_mv.y;
313
6.44k
            cand_mv.x = -cand_mv.x;
314
6.44k
        }
315
316
1.17M
        int m;
317
1.17M
        const int last = *cnt;
318
1.31M
        for (m = 0; m < last; m++)
319
1.08M
            if (cand_mv.n == mvstack[m].mv.mv[0].n)
320
940k
                break;
321
1.17M
        if (m == last) {
322
235k
            mvstack[m].mv.mv[0] = cand_mv;
323
235k
            mvstack[m].weight = 2; // "minimal"
324
235k
            *cnt = last + 1;
325
235k
        }
326
1.17M
    }
327
1.16M
}
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
2.32M
{
355
2.32M
    const refmvs_frame *const rf = rt->rf;
356
2.32M
    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
357
2.32M
    const int bw4 = b_dim[0], w4 = imin(imin(bw4, 16), rt->tile_col.end - bx4);
358
2.32M
    const int bh4 = b_dim[1], h4 = imin(imin(bh4, 16), rt->tile_row.end - by4);
359
2.32M
    mv gmv[2], tgmv[2];
360
361
2.32M
    *cnt = 0;
362
2.32M
    assert(ref.ref[0] >=  0 && ref.ref[0] <= 8 &&
363
2.32M
           ref.ref[1] >= -1 && ref.ref[1] <= 8);
364
2.32M
    if (ref.ref[0] > 0) {
365
1.43M
        tgmv[0] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[0] - 1],
366
1.43M
                             bx4, by4, bw4, bh4, rf->frm_hdr);
367
1.43M
        gmv[0] = rf->frm_hdr->gmv[ref.ref[0] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
368
1.06M
                 tgmv[0] : (mv) { .n = INVALID_MV };
369
1.43M
    } else {
370
885k
        tgmv[0] = (mv) { .n = 0 };
371
885k
        gmv[0] = (mv) { .n = INVALID_MV };
372
885k
    }
373
2.32M
    if (ref.ref[1] > 0) {
374
245k
        tgmv[1] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[1] - 1],
375
245k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
376
245k
        gmv[1] = rf->frm_hdr->gmv[ref.ref[1] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
377
158k
                 tgmv[1] : (mv) { .n = INVALID_MV };
378
245k
    }
379
380
    // top
381
2.32M
    int have_newmv = 0, have_col_mvs = 0, have_row_mvs = 0;
382
2.32M
    unsigned max_rows = 0, n_rows = ~0;
383
2.32M
    const refmvs_block *b_top;
384
2.32M
    if (by4 > rt->tile_row.start) {
385
1.77M
        max_rows = imin((by4 - rt->tile_row.start + 1) >> 1, 2 + (bh4 > 1));
386
1.77M
        b_top = &rt->r[(by4 & 31) - 1 + 5][bx4];
387
1.77M
        n_rows = scan_row(mvstack, cnt, ref, gmv, b_top,
388
1.77M
                          bw4, w4, max_rows, bw4 >= 16 ? 4 : 1,
389
1.77M
                          &have_newmv, &have_row_mvs);
390
1.77M
    }
391
392
    // left
393
2.32M
    unsigned max_cols = 0, n_cols = ~0U;
394
2.32M
    refmvs_block *const *b_left;
395
2.32M
    if (bx4 > rt->tile_col.start) {
396
1.92M
        max_cols = imin((bx4 - rt->tile_col.start + 1) >> 1, 2 + (bw4 > 1));
397
1.92M
        b_left = &rt->r[(by4 & 31) + 5];
398
1.92M
        n_cols = scan_col(mvstack, cnt, ref, gmv, b_left,
399
1.92M
                          bh4, h4, bx4 - 1, max_cols, bh4 >= 16 ? 4 : 1,
400
1.92M
                          &have_newmv, &have_col_mvs);
401
1.92M
    }
402
403
    // top/right
404
2.32M
    if (n_rows != ~0U && edge_flags & EDGE_I444_TOP_HAS_RIGHT &&
405
1.06M
        imax(bw4, bh4) <= 16 && bw4 + bx4 < rt->tile_col.end)
406
867k
    {
407
867k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[bw4], ref, gmv,
408
867k
                              &have_newmv, &have_row_mvs);
409
867k
    }
410
411
2.32M
    const int nearest_match = have_col_mvs + have_row_mvs;
412
2.32M
    const int nearest_cnt = *cnt;
413
5.00M
    for (int n = 0; n < nearest_cnt; n++)
414
2.67M
        mvstack[n].weight += 640;
415
416
    // temporal
417
2.32M
    int globalmv_ctx = rf->frm_hdr->use_ref_frame_mvs;
418
2.32M
    if (rf->use_ref_frame_mvs) {
419
68.1k
        const ptrdiff_t stride = rf->rp_stride;
420
68.1k
        const int by8 = by4 >> 1, bx8 = bx4 >> 1;
421
68.1k
        const refmvs_temporal_block *const rbi = &rt->rp_proj[(by8 & 15) * stride + bx8];
422
68.1k
        const refmvs_temporal_block *rb = rbi;
423
68.1k
        const int step_h = bw4 >= 16 ? 2 : 1, step_v = bh4 >= 16 ? 2 : 1;
424
68.1k
        const int w8 = imin((w4 + 1) >> 1, 8), h8 = imin((h4 + 1) >> 1, 8);
425
192k
        for (int y = 0; y < h8; y += step_v) {
426
308k
            for (int x = 0; x < w8; x+= step_h) {
427
184k
                add_temporal_candidate(rf, mvstack, cnt, &rb[x], ref,
428
184k
                                       !(x | y) ? &globalmv_ctx : NULL, tgmv);
429
184k
            }
430
123k
            rb += stride * step_v;
431
123k
        }
432
68.1k
        if (imin(bw4, bh4) >= 2 && imax(bw4, bh4) < 16) {
433
34.4k
            const int bh8 = bh4 >> 1, bw8 = bw4 >> 1;
434
34.4k
            rb = &rbi[bh8 * stride];
435
34.4k
            const int has_bottom = by8 + bh8 < imin(rt->tile_row.end >> 1,
436
34.4k
                                                    (by8 & ~7) + 8);
437
34.4k
            if (has_bottom && bx8 - 1 >= imax(rt->tile_col.start >> 1, bx8 & ~7)) {
438
9.37k
                add_temporal_candidate(rf, mvstack, cnt, &rb[-1], ref,
439
9.37k
                                       NULL, NULL);
440
9.37k
            }
441
34.4k
            if (bx8 + bw8 < imin(rt->tile_col.end >> 1, (bx8 & ~7) + 8)) {
442
14.6k
                if (has_bottom) {
443
8.83k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8], ref,
444
8.83k
                                           NULL, NULL);
445
8.83k
                }
446
14.6k
                if (by8 + bh8 - 1 < imin(rt->tile_row.end >> 1, (by8 & ~7) + 8)) {
447
13.3k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8 - stride],
448
13.3k
                                           ref, NULL, NULL);
449
13.3k
                }
450
14.6k
            }
451
34.4k
        }
452
68.1k
    }
453
2.32M
    assert(*cnt <= 8);
454
455
    // top/left (which, confusingly, is part of "secondary" references)
456
2.32M
    int have_dummy_newmv_match;
457
2.32M
    if ((n_rows | n_cols) != ~0U) {
458
1.54M
        add_spatial_candidate(mvstack, cnt, 4, &b_top[-1], ref, gmv,
459
1.54M
                              &have_dummy_newmv_match, &have_row_mvs);
460
1.54M
    }
461
462
    // "secondary" (non-direct neighbour) top & left edges
463
    // what is different about secondary is that everything is now in 8x8 resolution
464
6.97M
    for (int n = 2; n <= 3; n++) {
465
4.64M
        if ((unsigned) n > n_rows && (unsigned) n <= max_rows) {
466
1.75M
            n_rows += scan_row(mvstack, cnt, ref, gmv,
467
1.75M
                               &rt->r[(((by4 & 31) - 2 * n + 1) | 1) + 5][bx4 | 1],
468
1.75M
                               bw4, w4, 1 + max_rows - n, bw4 >= 16 ? 4 : 2,
469
1.75M
                               &have_dummy_newmv_match, &have_row_mvs);
470
1.75M
        }
471
472
4.64M
        if ((unsigned) n > n_cols && (unsigned) n <= max_cols) {
473
2.19M
            n_cols += scan_col(mvstack, cnt, ref, gmv, &rt->r[((by4 & 31) | 1) + 5],
474
2.19M
                               bh4, h4, (bx4 - n * 2 + 1) | 1,
475
2.19M
                               1 + max_cols - n, bh4 >= 16 ? 4 : 2,
476
2.19M
                               &have_dummy_newmv_match, &have_col_mvs);
477
2.19M
        }
478
4.64M
    }
479
2.32M
    assert(*cnt <= 8);
480
481
2.32M
    const int ref_match_count = have_col_mvs + have_row_mvs;
482
483
    // context build-up
484
2.32M
    int refmv_ctx, newmv_ctx;
485
2.32M
    switch (nearest_match) {
486
504k
    case 0:
487
504k
        refmv_ctx = imin(2, ref_match_count);
488
504k
        newmv_ctx = ref_match_count > 0;
489
504k
        break;
490
902k
    case 1:
491
902k
        refmv_ctx = imin(ref_match_count * 3, 4);
492
902k
        newmv_ctx = 3 - have_newmv;
493
902k
        break;
494
917k
    case 2:
495
917k
        refmv_ctx = 5;
496
917k
        newmv_ctx = 5 - have_newmv;
497
917k
        break;
498
2.32M
    }
499
500
    // sorting (nearest, then "secondary")
501
2.32M
    int len = nearest_cnt;
502
4.51M
    while (len) {
503
2.19M
        int last = 0;
504
3.20M
        for (int n = 1; n < len; n++) {
505
1.01M
            if (mvstack[n - 1].weight < mvstack[n].weight) {
506
549k
#define EXCHANGE(a, b) do { refmvs_candidate tmp = a; a = b; b = tmp; } while (0)
507
404k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
508
404k
                last = n;
509
404k
            }
510
1.01M
        }
511
2.19M
        len = last;
512
2.19M
    }
513
2.32M
    len = *cnt;
514
3.49M
    while (len > nearest_cnt) {
515
1.17M
        int last = nearest_cnt;
516
1.86M
        for (int n = nearest_cnt + 1; n < len; n++) {
517
686k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
518
144k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
519
144k
#undef EXCHANGE
520
144k
                last = n;
521
144k
            }
522
686k
        }
523
1.17M
        len = last;
524
1.17M
    }
525
526
2.32M
    if (ref.ref[1] > 0) {
527
245k
        if (*cnt < 2) {
528
184k
            const int sign0 = rf->sign_bias[ref.ref[0] - 1];
529
184k
            const int sign1 = rf->sign_bias[ref.ref[1] - 1];
530
184k
            const int sz4 = imin(w4, h4);
531
184k
            refmvs_candidate *const same = &mvstack[*cnt];
532
184k
            int same_count[4] = { 0 };
533
534
            // non-self references in top
535
252k
            if (n_rows != ~0U) for (int x = 0; x < sz4;) {
536
131k
                const refmvs_block *const cand_b = &b_top[x];
537
131k
                add_compound_extended_candidate(same, same_count, cand_b,
538
131k
                                                sign0, sign1, ref, rf->sign_bias);
539
131k
                x += dav1d_block_dimensions[cand_b->bs][0];
540
131k
            }
541
542
            // non-self references in left
543
260k
            if (n_cols != ~0U) for (int y = 0; y < sz4;) {
544
137k
                const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
545
137k
                add_compound_extended_candidate(same, same_count, cand_b,
546
137k
                                                sign0, sign1, ref, rf->sign_bias);
547
137k
                y += dav1d_block_dimensions[cand_b->bs][1];
548
137k
            }
549
550
184k
            refmvs_candidate *const diff = &same[2];
551
184k
            const int *const diff_count = &same_count[2];
552
553
            // merge together
554
554k
            for (int n = 0; n < 2; n++) {
555
369k
                int m = same_count[n];
556
557
369k
                if (m >= 2) continue;
558
559
296k
                const int l = diff_count[n];
560
296k
                if (l) {
561
201k
                    same[m].mv.mv[n] = diff[0].mv.mv[n];
562
201k
                    if (++m == 2) continue;
563
72.9k
                    if (l == 2) {
564
54.2k
                        same[1].mv.mv[n] = diff[1].mv.mv[n];
565
54.2k
                        continue;
566
54.2k
                    }
567
72.9k
                }
568
196k
                do {
569
196k
                    same[m].mv.mv[n] = tgmv[n];
570
196k
                } while (++m < 2);
571
113k
            }
572
573
            // if the first extended was the same as the non-extended one,
574
            // then replace it with the second extended one
575
184k
            int n = *cnt;
576
184k
            if (n == 1 && mvstack[0].mv.n == same[0].mv.n)
577
55.8k
                mvstack[1].mv = mvstack[2].mv;
578
293k
            do {
579
293k
                mvstack[n].weight = 2;
580
293k
            } while (++n < 2);
581
184k
            *cnt = 2;
582
184k
        }
583
584
        // clamping
585
245k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
586
245k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
587
245k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
588
245k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
589
590
245k
        const int n_refmvs = *cnt;
591
245k
        int n = 0;
592
530k
        do {
593
530k
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
594
530k
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
595
530k
            mvstack[n].mv.mv[1].x = iclip(mvstack[n].mv.mv[1].x, left, right);
596
530k
            mvstack[n].mv.mv[1].y = iclip(mvstack[n].mv.mv[1].y, top, bottom);
597
530k
        } while (++n < n_refmvs);
598
599
245k
        switch (refmv_ctx >> 1) {
600
119k
        case 0:
601
119k
            *ctx = imin(newmv_ctx, 1);
602
119k
            break;
603
79.2k
        case 1:
604
79.2k
            *ctx = 1 + imin(newmv_ctx, 3);
605
79.2k
            break;
606
47.2k
        case 2:
607
47.2k
            *ctx = iclip(3 + newmv_ctx, 4, 7);
608
47.2k
            break;
609
245k
        }
610
611
245k
        return;
612
2.07M
    } else if (*cnt < 2 && ref.ref[0] > 0) {
613
839k
        const int sign = rf->sign_bias[ref.ref[0] - 1];
614
839k
        const int sz4 = imin(w4, h4);
615
616
        // non-self references in top
617
1.23M
        if (n_rows != ~0U) for (int x = 0; x < sz4 && *cnt < 2;) {
618
631k
            const refmvs_block *const cand_b = &b_top[x];
619
631k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
620
631k
            x += dav1d_block_dimensions[cand_b->bs][0];
621
631k
        }
622
623
        // non-self references in left
624
1.09M
        if (n_cols != ~0U) for (int y = 0; y < sz4 && *cnt < 2;) {
625
538k
            const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
626
538k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
627
538k
            y += dav1d_block_dimensions[cand_b->bs][1];
628
538k
        }
629
839k
    }
630
2.07M
    assert(*cnt <= 8);
631
632
    // clamping
633
2.07M
    int n_refmvs = *cnt;
634
2.07M
    if (n_refmvs) {
635
1.87M
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
636
1.87M
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
637
1.87M
        const int top = -(by4 + bh4 + 4) * 4 * 8;
638
1.87M
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
639
640
1.87M
        int n = 0;
641
4.36M
        do {
642
4.36M
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
643
4.36M
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
644
4.36M
        } while (++n < n_refmvs);
645
1.87M
    }
646
647
3.15M
    for (int n = *cnt; n < 2; n++)
648
1.08M
        mvstack[n].mv.mv[0] = tgmv[0];
649
650
2.07M
    *ctx = (refmv_ctx << 4) | (globalmv_ctx << 3) | newmv_ctx;
651
2.07M
}
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
560k
{
658
560k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
659
560k
    rt->rp_proj = &rf->rp_proj[16 * rf->rp_stride * tile_row_idx];
660
560k
    const ptrdiff_t r_stride = rf->rp_stride * 2;
661
560k
    const ptrdiff_t pass_off = (rf->n_frame_threads > 1 && pass == 2) ?
662
294k
        35 * 2 * rf->n_blocks : 0;
663
560k
    refmvs_block *r = &rf->r[35 * r_stride * tile_row_idx + pass_off];
664
560k
    const int sbsz = rf->sbsz;
665
560k
    const int off = (sbsz * sby) & 16;
666
11.4M
    for (int i = 0; i < sbsz; i++, r += r_stride)
667
10.9M
        rt->r[off + 5 + i] = r;
668
560k
    rt->r[off + 0] = r;
669
560k
    r += r_stride;
670
560k
    rt->r[off + 1] = NULL;
671
560k
    rt->r[off + 2] = r;
672
560k
    r += r_stride;
673
560k
    rt->r[off + 3] = NULL;
674
560k
    rt->r[off + 4] = r;
675
560k
    if (sby & 1) {
676
385k
#define EXCHANGE(a, b) do { void *const tmp = a; a = b; b = tmp; } while (0)
677
128k
        EXCHANGE(rt->r[off + 0], rt->r[off + sbsz + 0]);
678
128k
        EXCHANGE(rt->r[off + 2], rt->r[off + sbsz + 2]);
679
128k
        EXCHANGE(rt->r[off + 4], rt->r[off + sbsz + 4]);
680
128k
#undef EXCHANGE
681
128k
    }
682
683
560k
    rt->rf = rf;
684
560k
    rt->tile_row.start = tile_row_start4;
685
560k
    rt->tile_row.end = imin(tile_row_end4, rf->ih4);
686
560k
    rt->tile_col.start = tile_col_start4;
687
560k
    rt->tile_col.end = imin(tile_col_end4, rf->iw4);
688
560k
}
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
36.3k
{
694
36.3k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
695
36.3k
    assert(row_start8 >= 0);
696
36.3k
    assert((unsigned) (row_end8 - row_start8) <= 16U);
697
36.3k
    row_end8 = imin(row_end8, rf->ih8);
698
36.3k
    const int col_start8i = imax(col_start8 - 8, 0);
699
36.3k
    const int col_end8i = imin(col_end8 + 8, rf->iw8);
700
701
36.3k
    const ptrdiff_t stride = rf->rp_stride;
702
36.3k
    refmvs_temporal_block *rp_proj =
703
36.3k
        &rf->rp_proj[16 * stride * tile_row_idx + (row_start8 & 15) * stride];
704
199k
    for (int y = row_start8; y < row_end8; y++) {
705
663k
        for (int x = col_start8; x < col_end8; x++)
706
500k
            rp_proj[x].mv.n = INVALID_MV;
707
163k
        rp_proj += stride;
708
163k
    }
709
710
36.3k
    rp_proj = &rf->rp_proj[16 * stride * tile_row_idx];
711
77.8k
    for (int n = 0; n < rf->n_mfmvs; n++) {
712
41.5k
        const int ref2cur = rf->mfmv_ref2cur[n];
713
41.5k
        if (ref2cur == INVALID_REF2CUR) continue;
714
715
26.7k
        const int ref = rf->mfmv_ref[n];
716
26.7k
        const int ref_sign = ref - 4;
717
26.7k
        const refmvs_temporal_block *r = &rf->rp_ref[ref][row_start8 * stride];
718
148k
        for (int y = row_start8; y < row_end8; y++) {
719
121k
            const int y_sb_align = y & ~7;
720
121k
            const int y_proj_start = imax(y_sb_align, row_start8);
721
121k
            const int y_proj_end = imin(y_sb_align + 8, row_end8);
722
312k
            for (int x = col_start8i; x < col_end8i; x++) {
723
190k
                const refmvs_temporal_block *rb = &r[x];
724
190k
                const int b_ref = rb->ref;
725
190k
                if (!b_ref) continue;
726
68.5k
                const int ref2ref = rf->mfmv_ref2ref[n][b_ref - 1];
727
68.5k
                if (!ref2ref) continue;
728
46.6k
                const mv b_mv = rb->mv;
729
46.6k
                const mv offset = mv_projection(b_mv, ref2cur, ref2ref);
730
46.6k
                int pos_x = x + apply_sign(abs(offset.x) >> 6,
731
46.6k
                                           offset.x ^ ref_sign);
732
46.6k
                const int pos_y = y + apply_sign(abs(offset.y) >> 6,
733
46.6k
                                                 offset.y ^ ref_sign);
734
46.6k
                if (pos_y >= y_proj_start && pos_y < y_proj_end) {
735
43.5k
                    const ptrdiff_t pos = (pos_y & 15) * stride;
736
143k
                    for (;;) {
737
143k
                        const int x_sb_align = x & ~7;
738
143k
                        if (pos_x >= imax(x_sb_align - 8, col_start8) &&
739
141k
                            pos_x < imin(x_sb_align + 16, col_end8))
740
138k
                        {
741
138k
                            rp_proj[pos + pos_x].mv = rb->mv;
742
138k
                            rp_proj[pos + pos_x].ref = ref2ref;
743
138k
                        }
744
143k
                        if (++x >= col_end8i) break;
745
111k
                        rb++;
746
111k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
747
100k
                        pos_x++;
748
100k
                    }
749
43.5k
                } else {
750
7.65k
                    for (;;) {
751
7.65k
                        if (++x >= col_end8i) break;
752
6.15k
                        rb++;
753
6.15k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
754
6.15k
                    }
755
3.12k
                }
756
46.6k
                x--;
757
46.6k
            }
758
121k
            r += stride;
759
121k
        }
760
26.7k
    }
761
36.3k
}
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
87.6k
{
769
524k
    for (int y = row_start8; y < row_end8; y++) {
770
437k
        const refmvs_block *const b = rr[(y & 15) * 2];
771
772
1.03M
        for (int x = col_start8; x < col_end8;) {
773
595k
            const refmvs_block *const cand_b = &b[x * 2 + 1];
774
595k
            const int bw8 = (dav1d_block_dimensions[cand_b->bs][0] + 1) >> 1;
775
776
595k
            if (cand_b->ref.ref[1] > 0 && ref_sign[cand_b->ref.ref[1] - 1] &&
777
65.6k
                (abs(cand_b->mv.mv[1].y) | abs(cand_b->mv.mv[1].x)) < 4096)
778
58.8k
            {
779
58.8k
                const refmvs_temporal_block tmv = {
780
58.8k
                    .mv = cand_b->mv.mv[1],
781
58.8k
                    .ref = cand_b->ref.ref[1],
782
58.8k
                };
783
222k
                for (int n = 0; n < bw8; n++, x++)
784
163k
                    rp[x] = tmv;
785
536k
            } else if (cand_b->ref.ref[0] > 0 && ref_sign[cand_b->ref.ref[0] - 1] &&
786
193k
                       (abs(cand_b->mv.mv[0].y) | abs(cand_b->mv.mv[0].x)) < 4096)
787
187k
            {
788
187k
                const refmvs_temporal_block tmv = {
789
187k
                    .mv = cand_b->mv.mv[0],
790
187k
                    .ref = cand_b->ref.ref[0],
791
187k
                };
792
761k
                for (int n = 0; n < bw8; n++, x++)
793
574k
                    rp[x] = tmv;
794
349k
            } else {
795
349k
                const refmvs_temporal_block tmv = { .mv = { .n = 0 }, .ref = 0 };
796
1.64M
                for (int n = 0; n < bw8; n++, x++)
797
1.29M
                    rp[x] = tmv;
798
349k
            }
799
595k
        }
800
437k
        rp += stride;
801
437k
    }
802
87.6k
}
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
196k
{
813
196k
    const int rp_stride = ((frm_hdr->width[0] + 127) & ~127) >> 3;
814
18.4E
    const int n_tile_rows = n_tile_threads > 1 ? frm_hdr->tiling.rows : 1;
815
196k
    const int n_blocks = rp_stride * n_tile_rows;
816
817
196k
    rf->sbsz = 16 << seq_hdr->sb128;
818
196k
    rf->frm_hdr = frm_hdr;
819
196k
    rf->iw8 = (frm_hdr->width[0] + 7) >> 3;
820
196k
    rf->ih8 = (frm_hdr->height + 7) >> 3;
821
196k
    rf->iw4 = rf->iw8 << 1;
822
196k
    rf->ih4 = rf->ih8 << 1;
823
196k
    rf->rp = rp;
824
196k
    rf->rp_stride = rp_stride;
825
196k
    rf->n_tile_threads = n_tile_threads;
826
196k
    rf->n_frame_threads = n_frame_threads;
827
828
196k
    if (n_blocks != rf->n_blocks) {
829
63.7k
        const size_t r_sz = sizeof(*rf->r) * 35 * 2 * n_blocks * (1 + (n_frame_threads > 1));
830
63.7k
        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
63.7k
        dav1d_free_aligned(rf->r);
834
63.7k
        rf->r = dav1d_alloc_aligned(ALLOC_REFMVS, r_sz + rp_proj_sz, 64);
835
63.7k
        if (!rf->r) {
836
0
            rf->n_blocks = 0;
837
0
            return DAV1D_ERR(ENOMEM);
838
0
        }
839
840
63.7k
        rf->rp_proj = (refmvs_temporal_block*)((uintptr_t)rf->r + r_sz);
841
63.7k
        rf->n_blocks = n_blocks;
842
63.7k
    }
843
844
196k
    const int poc = frm_hdr->frame_offset;
845
1.57M
    for (int i = 0; i < 7; i++) {
846
1.37M
        const int poc_diff = get_poc_diff(seq_hdr->order_hint_n_bits,
847
1.37M
                                          ref_poc[i], poc);
848
1.37M
        rf->sign_bias[i] = poc_diff > 0;
849
1.37M
        rf->mfmv_sign[i] = poc_diff < 0;
850
1.37M
        rf->pocdiff[i] = iclip(get_poc_diff(seq_hdr->order_hint_n_bits,
851
1.37M
                                            poc, ref_poc[i]), -31, 31);
852
1.37M
    }
853
854
    // temporal MV setup
855
196k
    rf->n_mfmvs = 0;
856
196k
    rf->rp_ref = rp_ref;
857
196k
    if (frm_hdr->use_ref_frame_mvs && seq_hdr->order_hint_n_bits) {
858
31.1k
        int total = 2;
859
31.1k
        if (rp_ref[0] && ref_ref_poc[0][6] != ref_poc[3] /* alt-of-last != gold */) {
860
9.76k
            rf->mfmv_ref[rf->n_mfmvs++] = 0; // last
861
9.76k
            total = 3;
862
9.76k
        }
863
31.1k
        if (rp_ref[4] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[4],
864
25.3k
                                      frm_hdr->frame_offset) > 0)
865
1.48k
        {
866
1.48k
            rf->mfmv_ref[rf->n_mfmvs++] = 4; // bwd
867
1.48k
        }
868
31.1k
        if (rp_ref[5] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[5],
869
23.2k
                                      frm_hdr->frame_offset) > 0)
870
1.26k
        {
871
1.26k
            rf->mfmv_ref[rf->n_mfmvs++] = 5; // altref2
872
1.26k
        }
873
31.1k
        if (rf->n_mfmvs < total && rp_ref[6] &&
874
19.4k
            get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[6],
875
19.4k
                         frm_hdr->frame_offset) > 0)
876
10.0k
        {
877
10.0k
            rf->mfmv_ref[rf->n_mfmvs++] = 6; // altref
878
10.0k
        }
879
31.1k
        if (rf->n_mfmvs < total && rp_ref[1])
880
16.3k
            rf->mfmv_ref[rf->n_mfmvs++] = 1; // last2
881
882
70.0k
        for (int n = 0; n < rf->n_mfmvs; n++) {
883
38.9k
            const int rpoc = ref_poc[rf->mfmv_ref[n]];
884
38.9k
            const int diff1 = get_poc_diff(seq_hdr->order_hint_n_bits,
885
38.9k
                                           rpoc, frm_hdr->frame_offset);
886
38.9k
            if (abs(diff1) > 31) {
887
14.6k
                rf->mfmv_ref2cur[n] = INVALID_REF2CUR;
888
24.2k
            } else {
889
24.2k
                rf->mfmv_ref2cur[n] = rf->mfmv_ref[n] < 4 ? -diff1 : diff1;
890
194k
                for (int m = 0; m < 7; m++) {
891
169k
                    const int rrpoc = ref_ref_poc[rf->mfmv_ref[n]][m];
892
169k
                    const int diff2 = get_poc_diff(seq_hdr->order_hint_n_bits,
893
169k
                                                   rpoc, rrpoc);
894
                    // unsigned comparison also catches the < 0 case
895
169k
                    rf->mfmv_ref2ref[n][m] = (unsigned) diff2 > 31U ? 0 : diff2;
896
169k
                }
897
24.2k
            }
898
38.9k
        }
899
31.1k
    }
900
196k
    rf->use_ref_frame_mvs = rf->n_mfmvs > 0;
901
902
196k
    return 0;
903
196k
}
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
3.86M
{
908
15.2M
    do {
909
15.2M
        refmvs_block *const r = *rr++ + bx4;
910
145M
        for (int x = 0; x < bw4; x++)
911
130M
            r[x] = *rmv;
912
15.2M
    } while (--bh4);
913
3.86M
}
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
84.4k
{
927
84.4k
    c->load_tmvs = load_tmvs_c;
928
84.4k
    c->save_tmvs = save_tmvs_c;
929
84.4k
    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
84.4k
}