Coverage Report

Created: 2026-07-16 06:31

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