Coverage Report

Created: 2026-07-16 06:29

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