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