Coverage Report

Created: 2026-09-01 06:56

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