Coverage Report

Created: 2026-09-02 06:39

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