Coverage Report

Created: 2026-08-13 07:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/dav1d/src/refmvs.c
Line
Count
Source
1
/*
2
 * Copyright © 2020, VideoLAN and dav1d authors
3
 * Copyright © 2020, Two Orioles, LLC
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions are met:
8
 *
9
 * 1. Redistributions of source code must retain the above copyright notice, this
10
 *    list of conditions and the following disclaimer.
11
 *
12
 * 2. Redistributions in binary form must reproduce the above copyright notice,
13
 *    this list of conditions and the following disclaimer in the documentation
14
 *    and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 */
27
28
#include "config.h"
29
30
#include <limits.h>
31
#include <stdlib.h>
32
33
#include "dav1d/common.h"
34
35
#include "common/intops.h"
36
37
#include "src/env.h"
38
#include "src/mem.h"
39
#include "src/refmvs.h"
40
41
static void add_spatial_candidate(refmvs_candidate *const mvstack, int *const cnt,
42
                                  const int weight, const refmvs_block *const b,
43
                                  const union refmvs_refpair ref, const mv gmv[2],
44
                                  int *const have_newmv_match,
45
                                  int *const have_refmv_match)
46
991k
{
47
991k
    if (b->mv.mv[0].n == INVALID_MV) return; // intra block, no intrabc
48
49
857k
    if (ref.ref[1] == -1) {
50
985k
        for (int n = 0; n < 2; n++) {
51
881k
            if (b->ref.ref[n] == ref.ref[0]) {
52
661k
                const mv cand_mv = ((b->mf & 1) && gmv[0].n != INVALID_MV) ?
53
650k
                                   gmv[0] : b->mv.mv[n];
54
55
661k
                *have_refmv_match = 1;
56
661k
                *have_newmv_match |= b->mf >> 1;
57
58
661k
                const int last = *cnt;
59
1.07M
                for (int m = 0; m < last; m++)
60
766k
                    if (mvstack[m].mv.mv[0].n == cand_mv.n) {
61
355k
                        mvstack[m].weight += weight;
62
355k
                        return;
63
355k
                    }
64
65
305k
                if (last < 8) {
66
304k
                    mvstack[last].mv.mv[0] = cand_mv;
67
304k
                    mvstack[last].weight = weight;
68
304k
                    *cnt = last + 1;
69
304k
                }
70
305k
                return;
71
661k
            }
72
881k
        }
73
764k
    } else if (b->ref.pair == ref.pair) {
74
24.1k
        const refmvs_mvpair cand_mv = { .mv = {
75
24.1k
            [0] = ((b->mf & 1) && gmv[0].n != INVALID_MV) ? gmv[0] : b->mv.mv[0],
76
24.1k
            [1] = ((b->mf & 1) && gmv[1].n != INVALID_MV) ? gmv[1] : b->mv.mv[1],
77
24.1k
        }};
78
79
24.1k
        *have_refmv_match = 1;
80
24.1k
        *have_newmv_match |= b->mf >> 1;
81
82
24.1k
        const int last = *cnt;
83
34.8k
        for (int n = 0; n < last; n++)
84
19.1k
            if (mvstack[n].mv.n == cand_mv.n) {
85
8.40k
                mvstack[n].weight += weight;
86
8.40k
                return;
87
8.40k
            }
88
89
15.7k
        if (last < 8) {
90
15.7k
            mvstack[last].mv = cand_mv;
91
15.7k
            mvstack[last].weight = weight;
92
15.7k
            *cnt = last + 1;
93
15.7k
        }
94
15.7k
    }
95
857k
}
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
326k
{
103
326k
    const refmvs_block *cand_b = b;
104
326k
    const enum BlockSize first_cand_bs = cand_b->bs;
105
326k
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
106
326k
    int cand_bw4 = first_cand_b_dim[0];
107
326k
    int len = imax(step, imin(bw4, cand_bw4));
108
109
326k
    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
281k
        const int weight = bw4 == 1 ? 2 :
115
281k
                           imax(2, imin(2 * max_rows, first_cand_b_dim[1]));
116
281k
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
117
281k
                              have_newmv_match, have_refmv_match);
118
281k
        return weight >> 1;
119
281k
    }
120
121
92.1k
    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
92.1k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
126
92.1k
                              have_newmv_match, have_refmv_match);
127
92.1k
        x += len;
128
92.1k
        if (x >= w4) return 1;
129
47.4k
        cand_b = &b[x];
130
47.4k
        cand_bw4 = dav1d_block_dimensions[cand_b->bs][0];
131
47.4k
        assert(cand_bw4 < bw4);
132
47.4k
        len = imax(step, cand_bw4);
133
47.4k
    }
134
44.6k
}
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
341k
{
142
341k
    const refmvs_block *cand_b = &b[0][bx4];
143
341k
    const enum BlockSize first_cand_bs = cand_b->bs;
144
341k
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
145
341k
    int cand_bh4 = first_cand_b_dim[1];
146
341k
    int len = imax(step, imin(bh4, cand_bh4));
147
148
341k
    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
288k
        const int weight = bh4 == 1 ? 2 :
154
288k
                           imax(2, imin(2 * max_cols, first_cand_b_dim[0]));
155
288k
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
156
288k
                            have_newmv_match, have_refmv_match);
157
288k
        return weight >> 1;
158
288k
    }
159
160
105k
    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
105k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
165
105k
                              have_newmv_match, have_refmv_match);
166
105k
        y += len;
167
105k
        if (y >= h4) return 1;
168
53.2k
        cand_b = &b[y][bx4];
169
53.2k
        cand_bh4 = dav1d_block_dimensions[cand_b->bs][1];
170
53.2k
        assert(cand_bh4 < bh4);
171
53.2k
        len = imax(step, cand_bh4);
172
53.2k
    }
173
52.3k
}
174
175
37.8k
static inline union mv mv_projection(const union mv mv, const int num, const int den) {
176
37.8k
    static const uint16_t div_mult[32] = {
177
37.8k
           0, 16384, 8192, 5461, 4096, 3276, 2730, 2340,
178
37.8k
        2048,  1820, 1638, 1489, 1365, 1260, 1170, 1092,
179
37.8k
        1024,   963,  910,  862,  819,  780,  744,  712,
180
37.8k
         682,   655,  630,  606,  585,  564,  546,  528
181
37.8k
    };
182
37.8k
    assert(den > 0 && den < 32);
183
37.8k
    assert(num > -32 && num < 32);
184
37.8k
    const int frac = num * div_mult[den];
185
37.8k
    const int y = mv.y * frac, x = mv.x * frac;
186
    // Round and clip according to AV1 spec section 7.9.3
187
37.8k
    return (union mv) { // 0x3fff == (1 << 14) - 1
188
37.8k
        .y = iclip((y + 8192 + (y >> 31)) >> 14, -0x3fff, 0x3fff),
189
37.8k
        .x = iclip((x + 8192 + (x >> 31)) >> 14, -0x3fff, 0x3fff)
190
37.8k
    };
191
37.8k
}
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
54.9k
{
199
54.9k
    if (rb->mv.n == INVALID_MV) return;
200
201
17.1k
    union mv mv = mv_projection(rb->mv, rf->pocdiff[ref.ref[0] - 1], rb->ref);
202
17.1k
    fix_mv_precision(rf->frm_hdr, &mv);
203
204
17.1k
    const int last = *cnt;
205
17.1k
    if (ref.ref[1] == -1) {
206
15.2k
        if (globalmv_ctx)
207
2.53k
            *globalmv_ctx = (abs(mv.x - gmv[0].x) | abs(mv.y - gmv[0].y)) >= 16;
208
209
16.5k
        for (int n = 0; n < last; n++)
210
14.1k
            if (mvstack[n].mv.mv[0].n == mv.n) {
211
12.8k
                mvstack[n].weight += 2;
212
12.8k
                return;
213
12.8k
            }
214
2.39k
        if (last < 8) {
215
2.39k
            mvstack[last].mv.mv[0] = mv;
216
2.39k
            mvstack[last].weight = 2;
217
2.39k
            *cnt = last + 1;
218
2.39k
        }
219
2.39k
    } else {
220
1.90k
        refmvs_mvpair mvp = { .mv = {
221
1.90k
            [0] = mv,
222
1.90k
            [1] = mv_projection(rb->mv, rf->pocdiff[ref.ref[1] - 1], rb->ref),
223
1.90k
        }};
224
1.90k
        fix_mv_precision(rf->frm_hdr, &mvp.mv[1]);
225
226
2.46k
        for (int n = 0; n < last; n++)
227
1.68k
            if (mvstack[n].mv.n == mvp.n) {
228
1.12k
                mvstack[n].weight += 2;
229
1.12k
                return;
230
1.12k
            }
231
778
        if (last < 8) {
232
778
            mvstack[last].mv = mvp;
233
778
            mvstack[last].weight = 2;
234
778
            *cnt = last + 1;
235
778
        }
236
778
    }
237
17.1k
}
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
24.6k
{
246
24.6k
    refmvs_candidate *const diff = &same[2];
247
24.6k
    int *const diff_count = &same_count[2];
248
249
62.3k
    for (int n = 0; n < 2; n++) {
250
48.2k
        const int cand_ref = cand_b->ref.ref[n];
251
252
48.2k
        if (cand_ref <= 0) break;
253
254
37.7k
        mv cand_mv = cand_b->mv.mv[n];
255
37.7k
        if (cand_ref == ref.ref[0]) {
256
13.3k
            if (same_count[0] < 2)
257
12.5k
                same[same_count[0]++].mv.mv[0] = cand_mv;
258
13.3k
            if (diff_count[1] < 2) {
259
10.9k
                if (sign1 ^ sign_bias[cand_ref - 1]) {
260
301
                    cand_mv.y = -cand_mv.y;
261
301
                    cand_mv.x = -cand_mv.x;
262
301
                }
263
10.9k
                diff[diff_count[1]++].mv.mv[1] = cand_mv;
264
10.9k
            }
265
24.4k
        } else if (cand_ref == ref.ref[1]) {
266
11.9k
            if (same_count[1] < 2)
267
11.5k
                same[same_count[1]++].mv.mv[1] = cand_mv;
268
11.9k
            if (diff_count[0] < 2) {
269
9.66k
                if (sign0 ^ sign_bias[cand_ref - 1]) {
270
708
                    cand_mv.y = -cand_mv.y;
271
708
                    cand_mv.x = -cand_mv.x;
272
708
                }
273
9.66k
                diff[diff_count[0]++].mv.mv[0] = cand_mv;
274
9.66k
            }
275
12.5k
        } else {
276
12.5k
            mv i_cand_mv = (union mv) {
277
12.5k
                .x = -cand_mv.x,
278
12.5k
                .y = -cand_mv.y
279
12.5k
            };
280
281
12.5k
            if (diff_count[0] < 2) {
282
9.87k
                diff[diff_count[0]++].mv.mv[0] =
283
9.87k
                    sign0 ^ sign_bias[cand_ref - 1] ?
284
9.34k
                    i_cand_mv : cand_mv;
285
9.87k
            }
286
287
12.5k
            if (diff_count[1] < 2) {
288
9.24k
                diff[diff_count[1]++].mv.mv[1] =
289
9.24k
                    sign1 ^ sign_bias[cand_ref - 1] ?
290
8.84k
                    i_cand_mv : cand_mv;
291
9.24k
            }
292
12.5k
        }
293
37.7k
    }
294
24.6k
}
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
134k
{
300
269k
    for (int n = 0; n < 2; n++) {
301
264k
        const int cand_ref = cand_b->ref.ref[n];
302
303
264k
        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
134k
        mv cand_mv = cand_b->mv.mv[n];
311
134k
        if (sign ^ sign_bias[cand_ref - 1]) {
312
1.05k
            cand_mv.y = -cand_mv.y;
313
1.05k
            cand_mv.x = -cand_mv.x;
314
1.05k
        }
315
316
134k
        int m;
317
134k
        const int last = *cnt;
318
146k
        for (m = 0; m < last; m++)
319
126k
            if (cand_mv.n == mvstack[m].mv.mv[0].n)
320
115k
                break;
321
134k
        if (m == last) {
322
19.4k
            mvstack[m].mv.mv[0] = cand_mv;
323
19.4k
            mvstack[m].weight = 2; // "minimal"
324
19.4k
            *cnt = last + 1;
325
19.4k
        }
326
134k
    }
327
134k
}
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
236k
{
355
236k
    const refmvs_frame *const rf = rt->rf;
356
236k
    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
357
236k
    const int bw4 = b_dim[0], w4 = imin(imin(bw4, 16), rt->tile_col.end - bx4);
358
236k
    const int bh4 = b_dim[1], h4 = imin(imin(bh4, 16), rt->tile_row.end - by4);
359
236k
    mv gmv[2], tgmv[2];
360
361
236k
    *cnt = 0;
362
236k
    assert(ref.ref[0] >=  0 && ref.ref[0] <= 8 &&
363
236k
           ref.ref[1] >= -1 && ref.ref[1] <= 8);
364
236k
    if (ref.ref[0] > 0) {
365
202k
        tgmv[0] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[0] - 1],
366
202k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
367
202k
        gmv[0] = rf->frm_hdr->gmv[ref.ref[0] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
368
156k
                 tgmv[0] : (mv) { .n = INVALID_MV };
369
202k
    } else {
370
34.0k
        tgmv[0] = (mv) { .n = 0 };
371
34.0k
        gmv[0] = (mv) { .n = INVALID_MV };
372
34.0k
    }
373
236k
    if (ref.ref[1] > 0) {
374
30.6k
        tgmv[1] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[1] - 1],
375
30.6k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
376
30.6k
        gmv[1] = rf->frm_hdr->gmv[ref.ref[1] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
377
16.7k
                 tgmv[1] : (mv) { .n = INVALID_MV };
378
30.6k
    }
379
380
    // top
381
236k
    int have_newmv = 0, have_col_mvs = 0, have_row_mvs = 0;
382
236k
    unsigned max_rows = 0, n_rows = ~0;
383
236k
    const refmvs_block *b_top;
384
236k
    if (by4 > rt->tile_row.start) {
385
157k
        max_rows = imin((by4 - rt->tile_row.start + 1) >> 1, 2 + (bh4 > 1));
386
157k
        b_top = &rt->r[(by4 & 31) - 1 + 5][bx4];
387
157k
        n_rows = scan_row(mvstack, cnt, ref, gmv, b_top,
388
157k
                          bw4, w4, max_rows, bw4 >= 16 ? 4 : 1,
389
157k
                          &have_newmv, &have_row_mvs);
390
157k
    }
391
392
    // left
393
236k
    unsigned max_cols = 0, n_cols = ~0U;
394
236k
    refmvs_block *const *b_left;
395
236k
    if (bx4 > rt->tile_col.start) {
396
157k
        max_cols = imin((bx4 - rt->tile_col.start + 1) >> 1, 2 + (bw4 > 1));
397
157k
        b_left = &rt->r[(by4 & 31) + 5];
398
157k
        n_cols = scan_col(mvstack, cnt, ref, gmv, b_left,
399
157k
                          bh4, h4, bx4 - 1, max_cols, bh4 >= 16 ? 4 : 1,
400
157k
                          &have_newmv, &have_col_mvs);
401
157k
    }
402
403
    // top/right
404
236k
    if (n_rows != ~0U && edge_flags & EDGE_I444_TOP_HAS_RIGHT &&
405
92.5k
        imax(bw4, bh4) <= 16 && bw4 + bx4 < rt->tile_col.end)
406
82.9k
    {
407
82.9k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[bw4], ref, gmv,
408
82.9k
                              &have_newmv, &have_row_mvs);
409
82.9k
    }
410
411
236k
    const int nearest_match = have_col_mvs + have_row_mvs;
412
236k
    const int nearest_cnt = *cnt;
413
450k
    for (int n = 0; n < nearest_cnt; n++)
414
213k
        mvstack[n].weight += 640;
415
416
    // temporal
417
236k
    int globalmv_ctx = rf->frm_hdr->use_ref_frame_mvs;
418
236k
    if (rf->use_ref_frame_mvs) {
419
15.4k
        const ptrdiff_t stride = rf->rp_stride;
420
15.4k
        const int by8 = by4 >> 1, bx8 = bx4 >> 1;
421
15.4k
        const refmvs_temporal_block *const rbi = &rt->rp_proj[(by8 & 15) * stride + bx8];
422
15.4k
        const refmvs_temporal_block *rb = rbi;
423
15.4k
        const int step_h = bw4 >= 16 ? 2 : 1, step_v = bh4 >= 16 ? 2 : 1;
424
15.4k
        const int w8 = imin((w4 + 1) >> 1, 8), h8 = imin((h4 + 1) >> 1, 8);
425
52.7k
        for (int y = 0; y < h8; y += step_v) {
426
89.9k
            for (int x = 0; x < w8; x+= step_h) {
427
52.6k
                add_temporal_candidate(rf, mvstack, cnt, &rb[x], ref,
428
52.6k
                                       !(x | y) ? &globalmv_ctx : NULL, tgmv);
429
52.6k
            }
430
37.2k
            rb += stride * step_v;
431
37.2k
        }
432
15.4k
        if (imin(bw4, bh4) >= 2 && imax(bw4, bh4) < 16) {
433
8.27k
            const int bh8 = bh4 >> 1, bw8 = bw4 >> 1;
434
8.27k
            rb = &rbi[bh8 * stride];
435
8.27k
            const int has_bottom = by8 + bh8 < imin(rt->tile_row.end >> 1,
436
8.27k
                                                    (by8 & ~7) + 8);
437
8.27k
            if (has_bottom && bx8 - 1 >= imax(rt->tile_col.start >> 1, bx8 & ~7)) {
438
798
                add_temporal_candidate(rf, mvstack, cnt, &rb[-1], ref,
439
798
                                       NULL, NULL);
440
798
            }
441
8.27k
            if (bx8 + bw8 < imin(rt->tile_col.end >> 1, (bx8 & ~7) + 8)) {
442
1.17k
                if (has_bottom) {
443
537
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8], ref,
444
537
                                           NULL, NULL);
445
537
                }
446
1.17k
                if (by8 + bh8 - 1 < imin(rt->tile_row.end >> 1, (by8 & ~7) + 8)) {
447
976
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8 - stride],
448
976
                                           ref, NULL, NULL);
449
976
                }
450
1.17k
            }
451
8.27k
        }
452
15.4k
    }
453
236k
    assert(*cnt <= 8);
454
455
    // top/left (which, confusingly, is part of "secondary" references)
456
236k
    int have_dummy_newmv_match;
457
236k
    if ((n_rows | n_cols) != ~0U) {
458
140k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[-1], ref, gmv,
459
140k
                              &have_dummy_newmv_match, &have_row_mvs);
460
140k
    }
461
462
    // "secondary" (non-direct neighbour) top & left edges
463
    // what is different about secondary is that everything is now in 8x8 resolution
464
709k
    for (int n = 2; n <= 3; n++) {
465
472k
        if ((unsigned) n > n_rows && (unsigned) n <= max_rows) {
466
169k
            n_rows += scan_row(mvstack, cnt, ref, gmv,
467
169k
                               &rt->r[(((by4 & 31) - 2 * n + 1) | 1) + 5][bx4 | 1],
468
169k
                               bw4, w4, 1 + max_rows - n, bw4 >= 16 ? 4 : 2,
469
169k
                               &have_dummy_newmv_match, &have_row_mvs);
470
169k
        }
471
472
472k
        if ((unsigned) n > n_cols && (unsigned) n <= max_cols) {
473
183k
            n_cols += scan_col(mvstack, cnt, ref, gmv, &rt->r[((by4 & 31) | 1) + 5],
474
183k
                               bh4, h4, (bx4 - n * 2 + 1) | 1,
475
183k
                               1 + max_cols - n, bh4 >= 16 ? 4 : 2,
476
183k
                               &have_dummy_newmv_match, &have_col_mvs);
477
183k
        }
478
472k
    }
479
236k
    assert(*cnt <= 8);
480
481
236k
    const int ref_match_count = have_col_mvs + have_row_mvs;
482
483
    // context build-up
484
236k
    int refmv_ctx, newmv_ctx;
485
236k
    switch (nearest_match) {
486
87.1k
    case 0:
487
87.1k
        refmv_ctx = imin(2, ref_match_count);
488
87.1k
        newmv_ctx = ref_match_count > 0;
489
87.1k
        break;
490
61.5k
    case 1:
491
61.5k
        refmv_ctx = imin(ref_match_count * 3, 4);
492
61.5k
        newmv_ctx = 3 - have_newmv;
493
61.5k
        break;
494
87.7k
    case 2:
495
87.7k
        refmv_ctx = 5;
496
87.7k
        newmv_ctx = 5 - have_newmv;
497
87.7k
        break;
498
236k
    }
499
500
    // sorting (nearest, then "secondary")
501
236k
    int len = nearest_cnt;
502
410k
    while (len) {
503
173k
        int last = 0;
504
245k
        for (int n = 1; n < len; n++) {
505
71.9k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
506
42.4k
#define EXCHANGE(a, b) do { refmvs_candidate tmp = a; a = b; b = tmp; } while (0)
507
27.4k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
508
27.4k
                last = n;
509
27.4k
            }
510
71.9k
        }
511
173k
        len = last;
512
173k
    }
513
236k
    len = *cnt;
514
315k
    while (len > nearest_cnt) {
515
78.9k
        int last = nearest_cnt;
516
126k
        for (int n = nearest_cnt + 1; n < len; n++) {
517
47.9k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
518
14.9k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
519
14.9k
#undef EXCHANGE
520
14.9k
                last = n;
521
14.9k
            }
522
47.9k
        }
523
78.9k
        len = last;
524
78.9k
    }
525
526
236k
    if (ref.ref[1] > 0) {
527
30.6k
        if (*cnt < 2) {
528
26.5k
            const int sign0 = rf->sign_bias[ref.ref[0] - 1];
529
26.5k
            const int sign1 = rf->sign_bias[ref.ref[1] - 1];
530
26.5k
            const int sz4 = imin(w4, h4);
531
26.5k
            refmvs_candidate *const same = &mvstack[*cnt];
532
26.5k
            int same_count[4] = { 0 };
533
534
            // non-self references in top
535
26.5k
            if (n_rows != ~0U) for (int x = 0; x < sz4;) {
536
12.2k
                const refmvs_block *const cand_b = &b_top[x];
537
12.2k
                add_compound_extended_candidate(same, same_count, cand_b,
538
12.2k
                                                sign0, sign1, ref, rf->sign_bias);
539
12.2k
                x += dav1d_block_dimensions[cand_b->bs][0];
540
12.2k
            }
541
542
            // non-self references in left
543
26.5k
            if (n_cols != ~0U) for (int y = 0; y < sz4;) {
544
12.3k
                const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
545
12.3k
                add_compound_extended_candidate(same, same_count, cand_b,
546
12.3k
                                                sign0, sign1, ref, rf->sign_bias);
547
12.3k
                y += dav1d_block_dimensions[cand_b->bs][1];
548
12.3k
            }
549
550
26.5k
            refmvs_candidate *const diff = &same[2];
551
26.5k
            const int *const diff_count = &same_count[2];
552
553
            // merge together
554
79.5k
            for (int n = 0; n < 2; n++) {
555
53.0k
                int m = same_count[n];
556
557
53.0k
                if (m >= 2) continue;
558
559
46.6k
                const int l = diff_count[n];
560
46.6k
                if (l) {
561
17.6k
                    same[m].mv.mv[n] = diff[0].mv.mv[n];
562
17.6k
                    if (++m == 2) continue;
563
6.71k
                    if (l == 2) {
564
5.83k
                        same[1].mv.mv[n] = diff[1].mv.mv[n];
565
5.83k
                        continue;
566
5.83k
                    }
567
6.71k
                }
568
58.3k
                do {
569
58.3k
                    same[m].mv.mv[n] = tgmv[n];
570
58.3k
                } while (++m < 2);
571
29.8k
            }
572
573
            // if the first extended was the same as the non-extended one,
574
            // then replace it with the second extended one
575
26.5k
            int n = *cnt;
576
26.5k
            if (n == 1 && mvstack[0].mv.n == same[0].mv.n)
577
4.31k
                mvstack[1].mv = mvstack[2].mv;
578
46.7k
            do {
579
46.7k
                mvstack[n].weight = 2;
580
46.7k
            } while (++n < 2);
581
26.5k
            *cnt = 2;
582
26.5k
        }
583
584
        // clamping
585
30.6k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
586
30.6k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
587
30.6k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
588
30.6k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
589
590
30.6k
        const int n_refmvs = *cnt;
591
30.6k
        int n = 0;
592
63.3k
        do {
593
63.3k
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
594
63.3k
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
595
63.3k
            mvstack[n].mv.mv[1].x = iclip(mvstack[n].mv.mv[1].x, left, right);
596
63.3k
            mvstack[n].mv.mv[1].y = iclip(mvstack[n].mv.mv[1].y, top, bottom);
597
63.3k
        } while (++n < n_refmvs);
598
599
30.6k
        switch (refmv_ctx >> 1) {
600
21.5k
        case 0:
601
21.5k
            *ctx = imin(newmv_ctx, 1);
602
21.5k
            break;
603
5.77k
        case 1:
604
5.77k
            *ctx = 1 + imin(newmv_ctx, 3);
605
5.77k
            break;
606
3.35k
        case 2:
607
3.35k
            *ctx = iclip(3 + newmv_ctx, 4, 7);
608
3.35k
            break;
609
30.6k
        }
610
611
30.6k
        return;
612
205k
    } else if (*cnt < 2 && ref.ref[0] > 0) {
613
126k
        const int sign = rf->sign_bias[ref.ref[0] - 1];
614
126k
        const int sz4 = imin(w4, h4);
615
616
        // non-self references in top
617
134k
        if (n_rows != ~0U) for (int x = 0; x < sz4 && *cnt < 2;) {
618
68.9k
            const refmvs_block *const cand_b = &b_top[x];
619
68.9k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
620
68.9k
            x += dav1d_block_dimensions[cand_b->bs][0];
621
68.9k
        }
622
623
        // non-self references in left
624
132k
        if (n_cols != ~0U) for (int y = 0; y < sz4 && *cnt < 2;) {
625
65.9k
            const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
626
65.9k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
627
65.9k
            y += dav1d_block_dimensions[cand_b->bs][1];
628
65.9k
        }
629
126k
    }
630
205k
    assert(*cnt <= 8);
631
632
    // clamping
633
205k
    int n_refmvs = *cnt;
634
205k
    if (n_refmvs) {
635
155k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
636
155k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
637
155k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
638
155k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
639
640
155k
        int n = 0;
641
326k
        do {
642
326k
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
643
326k
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
644
326k
        } while (++n < n_refmvs);
645
155k
    }
646
647
381k
    for (int n = *cnt; n < 2; n++)
648
175k
        mvstack[n].mv.mv[0] = tgmv[0];
649
650
205k
    *ctx = (refmv_ctx << 4) | (globalmv_ctx << 3) | newmv_ctx;
651
205k
}
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
138k
{
658
138k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
659
138k
    rt->rp_proj = &rf->rp_proj[16 * rf->rp_stride * tile_row_idx];
660
138k
    const ptrdiff_t r_stride = rf->rp_stride * 2;
661
138k
    const ptrdiff_t pass_off = (rf->n_frame_threads > 1 && pass == 2) ?
662
70.1k
        35 * 2 * rf->n_blocks : 0;
663
138k
    refmvs_block *r = &rf->r[35 * r_stride * tile_row_idx + pass_off];
664
138k
    const int sbsz = rf->sbsz;
665
138k
    const int off = (sbsz * sby) & 16;
666
2.85M
    for (int i = 0; i < sbsz; i++, r += r_stride)
667
2.71M
        rt->r[off + 5 + i] = r;
668
138k
    rt->r[off + 0] = r;
669
138k
    r += r_stride;
670
138k
    rt->r[off + 1] = NULL;
671
138k
    rt->r[off + 2] = r;
672
138k
    r += r_stride;
673
138k
    rt->r[off + 3] = NULL;
674
138k
    rt->r[off + 4] = r;
675
138k
    if (sby & 1) {
676
22.9k
#define EXCHANGE(a, b) do { void *const tmp = a; a = b; b = tmp; } while (0)
677
7.64k
        EXCHANGE(rt->r[off + 0], rt->r[off + sbsz + 0]);
678
7.64k
        EXCHANGE(rt->r[off + 2], rt->r[off + sbsz + 2]);
679
7.64k
        EXCHANGE(rt->r[off + 4], rt->r[off + sbsz + 4]);
680
7.64k
#undef EXCHANGE
681
7.64k
    }
682
683
138k
    rt->rf = rf;
684
138k
    rt->tile_row.start = tile_row_start4;
685
138k
    rt->tile_row.end = imin(tile_row_end4, rf->ih4);
686
138k
    rt->tile_col.start = tile_col_start4;
687
138k
    rt->tile_col.end = imin(tile_col_end4, rf->iw4);
688
138k
}
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
11.7k
{
694
11.7k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
695
11.7k
    assert(row_start8 >= 0);
696
11.7k
    assert((unsigned) (row_end8 - row_start8) <= 16U);
697
11.7k
    row_end8 = imin(row_end8, rf->ih8);
698
11.7k
    const int col_start8i = imax(col_start8 - 8, 0);
699
11.7k
    const int col_end8i = imin(col_end8 + 8, rf->iw8);
700
701
11.7k
    const ptrdiff_t stride = rf->rp_stride;
702
11.7k
    refmvs_temporal_block *rp_proj =
703
11.7k
        &rf->rp_proj[16 * stride * tile_row_idx + (row_start8 & 15) * stride];
704
75.2k
    for (int y = row_start8; y < row_end8; y++) {
705
150k
        for (int x = col_start8; x < col_end8; x++)
706
86.6k
            rp_proj[x].mv.n = INVALID_MV;
707
63.4k
        rp_proj += stride;
708
63.4k
    }
709
710
11.7k
    rp_proj = &rf->rp_proj[16 * stride * tile_row_idx];
711
25.2k
    for (int n = 0; n < rf->n_mfmvs; n++) {
712
13.4k
        const int ref2cur = rf->mfmv_ref2cur[n];
713
13.4k
        if (ref2cur == INVALID_REF2CUR) continue;
714
715
11.9k
        const int ref = rf->mfmv_ref[n];
716
11.9k
        const int ref_sign = ref - 4;
717
11.9k
        const refmvs_temporal_block *r = &rf->rp_ref[ref][row_start8 * stride];
718
75.8k
        for (int y = row_start8; y < row_end8; y++) {
719
63.9k
            const int y_sb_align = y & ~7;
720
63.9k
            const int y_proj_start = imax(y_sb_align, row_start8);
721
63.9k
            const int y_proj_end = imin(y_sb_align + 8, row_end8);
722
144k
            for (int x = col_start8i; x < col_end8i; x++) {
723
80.4k
                const refmvs_temporal_block *rb = &r[x];
724
80.4k
                const int b_ref = rb->ref;
725
80.4k
                if (!b_ref) continue;
726
25.7k
                const int ref2ref = rf->mfmv_ref2ref[n][b_ref - 1];
727
25.7k
                if (!ref2ref) continue;
728
18.8k
                const mv b_mv = rb->mv;
729
18.8k
                const mv offset = mv_projection(b_mv, ref2cur, ref2ref);
730
18.8k
                int pos_x = x + apply_sign(abs(offset.x) >> 6,
731
18.8k
                                           offset.x ^ ref_sign);
732
18.8k
                const int pos_y = y + apply_sign(abs(offset.y) >> 6,
733
18.8k
                                                 offset.y ^ ref_sign);
734
18.8k
                if (pos_y >= y_proj_start && pos_y < y_proj_end) {
735
17.3k
                    const ptrdiff_t pos = (pos_y & 15) * stride;
736
26.6k
                    for (;;) {
737
26.6k
                        const int x_sb_align = x & ~7;
738
26.6k
                        if (pos_x >= imax(x_sb_align - 8, col_start8) &&
739
26.4k
                            pos_x < imin(x_sb_align + 16, col_end8))
740
26.0k
                        {
741
26.0k
                            rp_proj[pos + pos_x].mv = rb->mv;
742
26.0k
                            rp_proj[pos + pos_x].ref = ref2ref;
743
26.0k
                        }
744
26.6k
                        if (++x >= col_end8i) break;
745
17.8k
                        rb++;
746
17.8k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
747
9.30k
                        pos_x++;
748
9.30k
                    }
749
17.3k
                } else {
750
1.97k
                    for (;;) {
751
1.97k
                        if (++x >= col_end8i) break;
752
992
                        rb++;
753
992
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
754
992
                    }
755
1.53k
                }
756
18.8k
                x--;
757
18.8k
            }
758
63.9k
            r += stride;
759
63.9k
        }
760
11.9k
    }
761
11.7k
}
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
21.6k
{
769
115k
    for (int y = row_start8; y < row_end8; y++) {
770
93.5k
        const refmvs_block *const b = rr[(y & 15) * 2];
771
772
190k
        for (int x = col_start8; x < col_end8;) {
773
97.1k
            const refmvs_block *const cand_b = &b[x * 2 + 1];
774
97.1k
            const int bw8 = (dav1d_block_dimensions[cand_b->bs][0] + 1) >> 1;
775
776
97.1k
            if (cand_b->ref.ref[1] > 0 && ref_sign[cand_b->ref.ref[1] - 1] &&
777
2.13k
                (abs(cand_b->mv.mv[1].y) | abs(cand_b->mv.mv[1].x)) < 4096)
778
2.13k
            {
779
2.13k
                const refmvs_temporal_block tmv = {
780
2.13k
                    .mv = cand_b->mv.mv[1],
781
2.13k
                    .ref = cand_b->ref.ref[1],
782
2.13k
                };
783
11.1k
                for (int n = 0; n < bw8; n++, x++)
784
9.00k
                    rp[x] = tmv;
785
94.9k
            } else if (cand_b->ref.ref[0] > 0 && ref_sign[cand_b->ref.ref[0] - 1] &&
786
19.1k
                       (abs(cand_b->mv.mv[0].y) | abs(cand_b->mv.mv[0].x)) < 4096)
787
19.1k
            {
788
19.1k
                const refmvs_temporal_block tmv = {
789
19.1k
                    .mv = cand_b->mv.mv[0],
790
19.1k
                    .ref = cand_b->ref.ref[0],
791
19.1k
                };
792
109k
                for (int n = 0; n < bw8; n++, x++)
793
90.8k
                    rp[x] = tmv;
794
75.8k
            } else {
795
75.8k
                const refmvs_temporal_block tmv = { .mv = { .n = 0 }, .ref = 0 };
796
466k
                for (int n = 0; n < bw8; n++, x++)
797
390k
                    rp[x] = tmv;
798
75.8k
            }
799
97.1k
        }
800
93.5k
        rp += stride;
801
93.5k
    }
802
21.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
67.3k
{
813
67.3k
    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
67.3k
    const int n_blocks = rp_stride * n_tile_rows;
816
817
67.3k
    rf->sbsz = 16 << seq_hdr->sb128;
818
67.3k
    rf->frm_hdr = frm_hdr;
819
67.3k
    rf->iw8 = (frm_hdr->width[0] + 7) >> 3;
820
67.3k
    rf->ih8 = (frm_hdr->height + 7) >> 3;
821
67.3k
    rf->iw4 = rf->iw8 << 1;
822
67.3k
    rf->ih4 = rf->ih8 << 1;
823
67.3k
    rf->rp = rp;
824
67.3k
    rf->rp_stride = rp_stride;
825
67.3k
    rf->n_tile_threads = n_tile_threads;
826
67.3k
    rf->n_frame_threads = n_frame_threads;
827
828
67.3k
    if (n_blocks != rf->n_blocks) {
829
12.0k
        const size_t r_sz = sizeof(*rf->r) * 35 * 2 * n_blocks * (1 + (n_frame_threads > 1));
830
12.0k
        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
12.0k
        dav1d_free_aligned(rf->r);
834
12.0k
        rf->r = dav1d_alloc_aligned(ALLOC_REFMVS, r_sz + rp_proj_sz, 64);
835
12.0k
        if (!rf->r) {
836
0
            rf->n_blocks = 0;
837
0
            return DAV1D_ERR(ENOMEM);
838
0
        }
839
840
12.0k
        rf->rp_proj = (refmvs_temporal_block*)((uintptr_t)rf->r + r_sz);
841
12.0k
        rf->n_blocks = n_blocks;
842
12.0k
    }
843
844
67.3k
    const int poc = frm_hdr->frame_offset;
845
538k
    for (int i = 0; i < 7; i++) {
846
471k
        const int poc_diff = get_poc_diff(seq_hdr->order_hint_n_bits,
847
471k
                                          ref_poc[i], poc);
848
471k
        rf->sign_bias[i] = poc_diff > 0;
849
471k
        rf->mfmv_sign[i] = poc_diff < 0;
850
471k
        rf->pocdiff[i] = iclip(get_poc_diff(seq_hdr->order_hint_n_bits,
851
471k
                                            poc, ref_poc[i]), -31, 31);
852
471k
    }
853
854
    // temporal MV setup
855
67.3k
    rf->n_mfmvs = 0;
856
67.3k
    rf->rp_ref = rp_ref;
857
67.3k
    if (frm_hdr->use_ref_frame_mvs && seq_hdr->order_hint_n_bits) {
858
10.3k
        int total = 2;
859
10.3k
        if (rp_ref[0] && ref_ref_poc[0][6] != ref_poc[3] /* alt-of-last != gold */) {
860
2.38k
            rf->mfmv_ref[rf->n_mfmvs++] = 0; // last
861
2.38k
            total = 3;
862
2.38k
        }
863
10.3k
        if (rp_ref[4] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[4],
864
8.59k
                                      frm_hdr->frame_offset) > 0)
865
350
        {
866
350
            rf->mfmv_ref[rf->n_mfmvs++] = 4; // bwd
867
350
        }
868
10.3k
        if (rp_ref[5] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[5],
869
6.86k
                                      frm_hdr->frame_offset) > 0)
870
227
        {
871
227
            rf->mfmv_ref[rf->n_mfmvs++] = 5; // altref2
872
227
        }
873
10.3k
        if (rf->n_mfmvs < total && rp_ref[6] &&
874
5.15k
            get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[6],
875
5.15k
                         frm_hdr->frame_offset) > 0)
876
1.27k
        {
877
1.27k
            rf->mfmv_ref[rf->n_mfmvs++] = 6; // altref
878
1.27k
        }
879
10.3k
        if (rf->n_mfmvs < total && rp_ref[1])
880
7.86k
            rf->mfmv_ref[rf->n_mfmvs++] = 1; // last2
881
882
22.4k
        for (int n = 0; n < rf->n_mfmvs; n++) {
883
12.0k
            const int rpoc = ref_poc[rf->mfmv_ref[n]];
884
12.0k
            const int diff1 = get_poc_diff(seq_hdr->order_hint_n_bits,
885
12.0k
                                           rpoc, frm_hdr->frame_offset);
886
12.0k
            if (abs(diff1) > 31) {
887
1.37k
                rf->mfmv_ref2cur[n] = INVALID_REF2CUR;
888
10.7k
            } else {
889
10.7k
                rf->mfmv_ref2cur[n] = rf->mfmv_ref[n] < 4 ? -diff1 : diff1;
890
85.7k
                for (int m = 0; m < 7; m++) {
891
75.0k
                    const int rrpoc = ref_ref_poc[rf->mfmv_ref[n]][m];
892
75.0k
                    const int diff2 = get_poc_diff(seq_hdr->order_hint_n_bits,
893
75.0k
                                                   rpoc, rrpoc);
894
                    // unsigned comparison also catches the < 0 case
895
75.0k
                    rf->mfmv_ref2ref[n][m] = (unsigned) diff2 > 31U ? 0 : diff2;
896
75.0k
                }
897
10.7k
            }
898
12.0k
        }
899
10.3k
    }
900
67.3k
    rf->use_ref_frame_mvs = rf->n_mfmvs > 0;
901
902
67.3k
    return 0;
903
67.3k
}
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
372k
{
908
1.71M
    do {
909
1.71M
        refmvs_block *const r = *rr++ + bx4;
910
17.0M
        for (int x = 0; x < bw4; x++)
911
15.3M
            r[x] = *rmv;
912
1.71M
    } while (--bh4);
913
372k
}
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
4.79k
{
927
4.79k
    c->load_tmvs = load_tmvs_c;
928
4.79k
    c->save_tmvs = save_tmvs_c;
929
4.79k
    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
4.79k
}