Coverage Report

Created: 2026-07-30 06:25

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