Coverage Report

Created: 2026-09-02 06:43

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