Coverage Report

Created: 2026-09-14 06:41

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