Coverage Report

Created: 2026-08-13 07:20

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.17M
{
47
2.17M
    if (b->mv.mv[0].n == INVALID_MV) return; // intra block, no intrabc
48
49
1.64M
    if (ref.ref[1] == -1) {
50
1.80M
        for (int n = 0; n < 2; n++) {
51
1.65M
            if (b->ref.ref[n] == ref.ref[0]) {
52
1.33M
                const mv cand_mv = ((b->mf & 1) && gmv[0].n != INVALID_MV) ?
53
1.29M
                                   gmv[0] : b->mv.mv[n];
54
55
1.33M
                *have_refmv_match = 1;
56
1.33M
                *have_newmv_match |= b->mf >> 1;
57
58
1.33M
                const int last = *cnt;
59
2.67M
                for (int m = 0; m < last; m++)
60
1.72M
                    if (mvstack[m].mv.mv[0].n == cand_mv.n) {
61
377k
                        mvstack[m].weight += weight;
62
377k
                        return;
63
377k
                    }
64
65
958k
                if (last < 8) {
66
956k
                    mvstack[last].mv.mv[0] = cand_mv;
67
956k
                    mvstack[last].weight = weight;
68
956k
                    *cnt = last + 1;
69
956k
                }
70
958k
                return;
71
1.33M
            }
72
1.65M
        }
73
1.48M
    } else if (b->ref.pair == ref.pair) {
74
55.8k
        const refmvs_mvpair cand_mv = { .mv = {
75
55.8k
            [0] = ((b->mf & 1) && gmv[0].n != INVALID_MV) ? gmv[0] : b->mv.mv[0],
76
55.8k
            [1] = ((b->mf & 1) && gmv[1].n != INVALID_MV) ? gmv[1] : b->mv.mv[1],
77
55.8k
        }};
78
79
55.8k
        *have_refmv_match = 1;
80
55.8k
        *have_newmv_match |= b->mf >> 1;
81
82
55.8k
        const int last = *cnt;
83
85.7k
        for (int n = 0; n < last; n++)
84
49.8k
            if (mvstack[n].mv.n == cand_mv.n) {
85
19.9k
                mvstack[n].weight += weight;
86
19.9k
                return;
87
19.9k
            }
88
89
35.8k
        if (last < 8) {
90
35.8k
            mvstack[last].mv = cand_mv;
91
35.8k
            mvstack[last].weight = weight;
92
35.8k
            *cnt = last + 1;
93
35.8k
        }
94
35.8k
    }
95
1.64M
}
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
660k
{
103
660k
    const refmvs_block *cand_b = b;
104
660k
    const enum BlockSize first_cand_bs = cand_b->bs;
105
660k
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
106
660k
    int cand_bw4 = first_cand_b_dim[0];
107
660k
    int len = imax(step, imin(bw4, cand_bw4));
108
109
660k
    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
570k
        const int weight = bw4 == 1 ? 2 :
115
570k
                           imax(2, imin(2 * max_rows, first_cand_b_dim[1]));
116
570k
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
117
570k
                              have_newmv_match, have_refmv_match);
118
570k
        return weight >> 1;
119
570k
    }
120
121
186k
    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
186k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
126
186k
                              have_newmv_match, have_refmv_match);
127
186k
        x += len;
128
186k
        if (x >= w4) return 1;
129
95.4k
        cand_b = &b[x];
130
95.4k
        cand_bw4 = dav1d_block_dimensions[cand_b->bs][0];
131
95.4k
        assert(cand_bw4 < bw4);
132
95.4k
        len = imax(step, cand_bw4);
133
95.4k
    }
134
90.7k
}
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
848k
{
142
848k
    const refmvs_block *cand_b = &b[0][bx4];
143
848k
    const enum BlockSize first_cand_bs = cand_b->bs;
144
848k
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
145
848k
    int cand_bh4 = first_cand_b_dim[1];
146
848k
    int len = imax(step, imin(bh4, cand_bh4));
147
148
848k
    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
747k
        const int weight = bh4 == 1 ? 2 :
154
747k
                           imax(2, imin(2 * max_cols, first_cand_b_dim[0]));
155
747k
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
156
747k
                            have_newmv_match, have_refmv_match);
157
747k
        return weight >> 1;
158
747k
    }
159
160
196k
    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
196k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
165
196k
                              have_newmv_match, have_refmv_match);
166
196k
        y += len;
167
196k
        if (y >= h4) return 1;
168
95.2k
        cand_b = &b[y][bx4];
169
95.2k
        cand_bh4 = dav1d_block_dimensions[cand_b->bs][1];
170
95.2k
        assert(cand_bh4 < bh4);
171
95.2k
        len = imax(step, cand_bh4);
172
95.2k
    }
173
101k
}
174
175
15.1k
static inline union mv mv_projection(const union mv mv, const int num, const int den) {
176
15.1k
    static const uint16_t div_mult[32] = {
177
15.1k
           0, 16384, 8192, 5461, 4096, 3276, 2730, 2340,
178
15.1k
        2048,  1820, 1638, 1489, 1365, 1260, 1170, 1092,
179
15.1k
        1024,   963,  910,  862,  819,  780,  744,  712,
180
15.1k
         682,   655,  630,  606,  585,  564,  546,  528
181
15.1k
    };
182
15.1k
    assert(den > 0 && den < 32);
183
15.1k
    assert(num > -32 && num < 32);
184
15.1k
    const int frac = num * div_mult[den];
185
15.1k
    const int y = mv.y * frac, x = mv.x * frac;
186
    // Round and clip according to AV1 spec section 7.9.3
187
15.1k
    return (union mv) { // 0x3fff == (1 << 14) - 1
188
15.1k
        .y = iclip((y + 8192 + (y >> 31)) >> 14, -0x3fff, 0x3fff),
189
15.1k
        .x = iclip((x + 8192 + (x >> 31)) >> 14, -0x3fff, 0x3fff)
190
15.1k
    };
191
15.1k
}
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
20.0k
{
199
20.0k
    if (rb->mv.n == INVALID_MV) return;
200
201
7.96k
    union mv mv = mv_projection(rb->mv, rf->pocdiff[ref.ref[0] - 1], rb->ref);
202
7.96k
    fix_mv_precision(rf->frm_hdr, &mv);
203
204
7.96k
    const int last = *cnt;
205
7.96k
    if (ref.ref[1] == -1) {
206
4.88k
        if (globalmv_ctx)
207
1.40k
            *globalmv_ctx = (abs(mv.x - gmv[0].x) | abs(mv.y - gmv[0].y)) >= 16;
208
209
9.04k
        for (int n = 0; n < last; n++)
210
7.77k
            if (mvstack[n].mv.mv[0].n == mv.n) {
211
3.61k
                mvstack[n].weight += 2;
212
3.61k
                return;
213
3.61k
            }
214
1.27k
        if (last < 8) {
215
1.26k
            mvstack[last].mv.mv[0] = mv;
216
1.26k
            mvstack[last].weight = 2;
217
1.26k
            *cnt = last + 1;
218
1.26k
        }
219
3.08k
    } else {
220
3.08k
        refmvs_mvpair mvp = { .mv = {
221
3.08k
            [0] = mv,
222
3.08k
            [1] = mv_projection(rb->mv, rf->pocdiff[ref.ref[1] - 1], rb->ref),
223
3.08k
        }};
224
3.08k
        fix_mv_precision(rf->frm_hdr, &mvp.mv[1]);
225
226
4.47k
        for (int n = 0; n < last; n++)
227
3.72k
            if (mvstack[n].mv.n == mvp.n) {
228
2.32k
                mvstack[n].weight += 2;
229
2.32k
                return;
230
2.32k
            }
231
751
        if (last < 8) {
232
751
            mvstack[last].mv = mvp;
233
751
            mvstack[last].weight = 2;
234
751
            *cnt = last + 1;
235
751
        }
236
751
    }
237
7.96k
}
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
41.8k
{
246
41.8k
    refmvs_candidate *const diff = &same[2];
247
41.8k
    int *const diff_count = &same_count[2];
248
249
108k
    for (int n = 0; n < 2; n++) {
250
82.6k
        const int cand_ref = cand_b->ref.ref[n];
251
252
82.6k
        if (cand_ref <= 0) break;
253
254
67.1k
        mv cand_mv = cand_b->mv.mv[n];
255
67.1k
        if (cand_ref == ref.ref[0]) {
256
22.8k
            if (same_count[0] < 2)
257
22.2k
                same[same_count[0]++].mv.mv[0] = cand_mv;
258
22.8k
            if (diff_count[1] < 2) {
259
19.7k
                if (sign1 ^ sign_bias[cand_ref - 1]) {
260
333
                    cand_mv.y = -cand_mv.y;
261
333
                    cand_mv.x = -cand_mv.x;
262
333
                }
263
19.7k
                diff[diff_count[1]++].mv.mv[1] = cand_mv;
264
19.7k
            }
265
44.2k
        } else if (cand_ref == ref.ref[1]) {
266
24.1k
            if (same_count[1] < 2)
267
23.6k
                same[same_count[1]++].mv.mv[1] = cand_mv;
268
24.1k
            if (diff_count[0] < 2) {
269
19.8k
                if (sign0 ^ sign_bias[cand_ref - 1]) {
270
380
                    cand_mv.y = -cand_mv.y;
271
380
                    cand_mv.x = -cand_mv.x;
272
380
                }
273
19.8k
                diff[diff_count[0]++].mv.mv[0] = cand_mv;
274
19.8k
            }
275
24.1k
        } else {
276
20.0k
            mv i_cand_mv = (union mv) {
277
20.0k
                .x = -cand_mv.x,
278
20.0k
                .y = -cand_mv.y
279
20.0k
            };
280
281
20.0k
            if (diff_count[0] < 2) {
282
15.9k
                diff[diff_count[0]++].mv.mv[0] =
283
15.9k
                    sign0 ^ sign_bias[cand_ref - 1] ?
284
15.7k
                    i_cand_mv : cand_mv;
285
15.9k
            }
286
287
20.0k
            if (diff_count[1] < 2) {
288
15.1k
                diff[diff_count[1]++].mv.mv[1] =
289
15.1k
                    sign1 ^ sign_bias[cand_ref - 1] ?
290
15.0k
                    i_cand_mv : cand_mv;
291
15.1k
            }
292
20.0k
        }
293
67.1k
    }
294
41.8k
}
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
106k
{
300
215k
    for (int n = 0; n < 2; n++) {
301
208k
        const int cand_ref = cand_b->ref.ref[n];
302
303
208k
        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
109k
        mv cand_mv = cand_b->mv.mv[n];
311
109k
        if (sign ^ sign_bias[cand_ref - 1]) {
312
283
            cand_mv.y = -cand_mv.y;
313
283
            cand_mv.x = -cand_mv.x;
314
283
        }
315
316
109k
        int m;
317
109k
        const int last = *cnt;
318
129k
        for (m = 0; m < last; m++)
319
100k
            if (cand_mv.n == mvstack[m].mv.mv[0].n)
320
80.2k
                break;
321
109k
        if (m == last) {
322
29.0k
            mvstack[m].mv.mv[0] = cand_mv;
323
29.0k
            mvstack[m].weight = 2; // "minimal"
324
29.0k
            *cnt = last + 1;
325
29.0k
        }
326
109k
    }
327
106k
}
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
434k
{
355
434k
    const refmvs_frame *const rf = rt->rf;
356
434k
    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
357
434k
    const int bw4 = b_dim[0], w4 = imin(imin(bw4, 16), rt->tile_col.end - bx4);
358
434k
    const int bh4 = b_dim[1], h4 = imin(imin(bh4, 16), rt->tile_row.end - by4);
359
434k
    mv gmv[2], tgmv[2];
360
361
434k
    *cnt = 0;
362
434k
    assert(ref.ref[0] >=  0 && ref.ref[0] <= 8 &&
363
434k
           ref.ref[1] >= -1 && ref.ref[1] <= 8);
364
434k
    if (ref.ref[0] > 0) {
365
151k
        tgmv[0] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[0] - 1],
366
151k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
367
151k
        gmv[0] = rf->frm_hdr->gmv[ref.ref[0] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
368
102k
                 tgmv[0] : (mv) { .n = INVALID_MV };
369
282k
    } else {
370
282k
        tgmv[0] = (mv) { .n = 0 };
371
282k
        gmv[0] = (mv) { .n = INVALID_MV };
372
282k
    }
373
434k
    if (ref.ref[1] > 0) {
374
34.3k
        tgmv[1] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[1] - 1],
375
34.3k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
376
34.3k
        gmv[1] = rf->frm_hdr->gmv[ref.ref[1] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
377
24.1k
                 tgmv[1] : (mv) { .n = INVALID_MV };
378
34.3k
    }
379
380
    // top
381
434k
    int have_newmv = 0, have_col_mvs = 0, have_row_mvs = 0;
382
434k
    unsigned max_rows = 0, n_rows = ~0;
383
434k
    const refmvs_block *b_top;
384
434k
    if (by4 > rt->tile_row.start) {
385
334k
        max_rows = imin((by4 - rt->tile_row.start + 1) >> 1, 2 + (bh4 > 1));
386
334k
        b_top = &rt->r[(by4 & 31) - 1 + 5][bx4];
387
334k
        n_rows = scan_row(mvstack, cnt, ref, gmv, b_top,
388
334k
                          bw4, w4, max_rows, bw4 >= 16 ? 4 : 1,
389
334k
                          &have_newmv, &have_row_mvs);
390
334k
    }
391
392
    // left
393
434k
    unsigned max_cols = 0, n_cols = ~0U;
394
434k
    refmvs_block *const *b_left;
395
434k
    if (bx4 > rt->tile_col.start) {
396
398k
        max_cols = imin((bx4 - rt->tile_col.start + 1) >> 1, 2 + (bw4 > 1));
397
398k
        b_left = &rt->r[(by4 & 31) + 5];
398
398k
        n_cols = scan_col(mvstack, cnt, ref, gmv, b_left,
399
398k
                          bh4, h4, bx4 - 1, max_cols, bh4 >= 16 ? 4 : 1,
400
398k
                          &have_newmv, &have_col_mvs);
401
398k
    }
402
403
    // top/right
404
434k
    if (n_rows != ~0U && edge_flags & EDGE_I444_TOP_HAS_RIGHT &&
405
193k
        imax(bw4, bh4) <= 16 && bw4 + bx4 < rt->tile_col.end)
406
172k
    {
407
172k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[bw4], ref, gmv,
408
172k
                              &have_newmv, &have_row_mvs);
409
172k
    }
410
411
434k
    const int nearest_match = have_col_mvs + have_row_mvs;
412
434k
    const int nearest_cnt = *cnt;
413
996k
    for (int n = 0; n < nearest_cnt; n++)
414
562k
        mvstack[n].weight += 640;
415
416
    // temporal
417
434k
    int globalmv_ctx = rf->frm_hdr->use_ref_frame_mvs;
418
434k
    if (rf->use_ref_frame_mvs) {
419
5.83k
        const ptrdiff_t stride = rf->rp_stride;
420
5.83k
        const int by8 = by4 >> 1, bx8 = bx4 >> 1;
421
5.83k
        const refmvs_temporal_block *const rbi = &rt->rp_proj[(by8 & 15) * stride + bx8];
422
5.83k
        const refmvs_temporal_block *rb = rbi;
423
5.83k
        const int step_h = bw4 >= 16 ? 2 : 1, step_v = bh4 >= 16 ? 2 : 1;
424
5.83k
        const int w8 = imin((w4 + 1) >> 1, 8), h8 = imin((h4 + 1) >> 1, 8);
425
16.6k
        for (int y = 0; y < h8; y += step_v) {
426
26.9k
            for (int x = 0; x < w8; x+= step_h) {
427
16.0k
                add_temporal_candidate(rf, mvstack, cnt, &rb[x], ref,
428
16.0k
                                       !(x | y) ? &globalmv_ctx : NULL, tgmv);
429
16.0k
            }
430
10.8k
            rb += stride * step_v;
431
10.8k
        }
432
5.83k
        if (imin(bw4, bh4) >= 2 && imax(bw4, bh4) < 16) {
433
3.52k
            const int bh8 = bh4 >> 1, bw8 = bw4 >> 1;
434
3.52k
            rb = &rbi[bh8 * stride];
435
3.52k
            const int has_bottom = by8 + bh8 < imin(rt->tile_row.end >> 1,
436
3.52k
                                                    (by8 & ~7) + 8);
437
3.52k
            if (has_bottom && bx8 - 1 >= imax(rt->tile_col.start >> 1, bx8 & ~7)) {
438
1.19k
                add_temporal_candidate(rf, mvstack, cnt, &rb[-1], ref,
439
1.19k
                                       NULL, NULL);
440
1.19k
            }
441
3.52k
            if (bx8 + bw8 < imin(rt->tile_col.end >> 1, (bx8 & ~7) + 8)) {
442
1.72k
                if (has_bottom) {
443
1.16k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8], ref,
444
1.16k
                                           NULL, NULL);
445
1.16k
                }
446
1.72k
                if (by8 + bh8 - 1 < imin(rt->tile_row.end >> 1, (by8 & ~7) + 8)) {
447
1.63k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8 - stride],
448
1.63k
                                           ref, NULL, NULL);
449
1.63k
                }
450
1.72k
            }
451
3.52k
        }
452
5.83k
    }
453
434k
    assert(*cnt <= 8);
454
455
    // top/left (which, confusingly, is part of "secondary" references)
456
434k
    int have_dummy_newmv_match;
457
434k
    if ((n_rows | n_cols) != ~0U) {
458
306k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[-1], ref, gmv,
459
306k
                              &have_dummy_newmv_match, &have_row_mvs);
460
306k
    }
461
462
    // "secondary" (non-direct neighbour) top & left edges
463
    // what is different about secondary is that everything is now in 8x8 resolution
464
1.30M
    for (int n = 2; n <= 3; n++) {
465
867k
        if ((unsigned) n > n_rows && (unsigned) n <= max_rows) {
466
326k
            n_rows += scan_row(mvstack, cnt, ref, gmv,
467
326k
                               &rt->r[(((by4 & 31) - 2 * n + 1) | 1) + 5][bx4 | 1],
468
326k
                               bw4, w4, 1 + max_rows - n, bw4 >= 16 ? 4 : 2,
469
326k
                               &have_dummy_newmv_match, &have_row_mvs);
470
326k
        }
471
472
867k
        if ((unsigned) n > n_cols && (unsigned) n <= max_cols) {
473
449k
            n_cols += scan_col(mvstack, cnt, ref, gmv, &rt->r[((by4 & 31) | 1) + 5],
474
449k
                               bh4, h4, (bx4 - n * 2 + 1) | 1,
475
449k
                               1 + max_cols - n, bh4 >= 16 ? 4 : 2,
476
449k
                               &have_dummy_newmv_match, &have_col_mvs);
477
449k
        }
478
867k
    }
479
434k
    assert(*cnt <= 8);
480
481
434k
    const int ref_match_count = have_col_mvs + have_row_mvs;
482
483
    // context build-up
484
434k
    int refmv_ctx, newmv_ctx;
485
434k
    switch (nearest_match) {
486
73.6k
    case 0:
487
73.6k
        refmv_ctx = imin(2, ref_match_count);
488
73.6k
        newmv_ctx = ref_match_count > 0;
489
73.6k
        break;
490
191k
    case 1:
491
191k
        refmv_ctx = imin(ref_match_count * 3, 4);
492
191k
        newmv_ctx = 3 - have_newmv;
493
191k
        break;
494
168k
    case 2:
495
168k
        refmv_ctx = 5;
496
168k
        newmv_ctx = 5 - have_newmv;
497
168k
        break;
498
434k
    }
499
500
    // sorting (nearest, then "secondary")
501
433k
    int len = nearest_cnt;
502
886k
    while (len) {
503
452k
        int last = 0;
504
696k
        for (int n = 1; n < len; n++) {
505
243k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
506
136k
#define EXCHANGE(a, b) do { refmvs_candidate tmp = a; a = b; b = tmp; } while (0)
507
100k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
508
100k
                last = n;
509
100k
            }
510
243k
        }
511
452k
        len = last;
512
452k
    }
513
433k
    len = *cnt;
514
728k
    while (len > nearest_cnt) {
515
294k
        int last = nearest_cnt;
516
477k
        for (int n = nearest_cnt + 1; n < len; n++) {
517
182k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
518
36.2k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
519
36.2k
#undef EXCHANGE
520
36.2k
                last = n;
521
36.2k
            }
522
182k
        }
523
294k
        len = last;
524
294k
    }
525
526
433k
    if (ref.ref[1] > 0) {
527
34.3k
        if (*cnt < 2) {
528
25.2k
            const int sign0 = rf->sign_bias[ref.ref[0] - 1];
529
25.2k
            const int sign1 = rf->sign_bias[ref.ref[1] - 1];
530
25.2k
            const int sz4 = imin(w4, h4);
531
25.2k
            refmvs_candidate *const same = &mvstack[*cnt];
532
25.2k
            int same_count[4] = { 0 };
533
534
            // non-self references in top
535
40.8k
            if (n_rows != ~0U) for (int x = 0; x < sz4;) {
536
21.3k
                const refmvs_block *const cand_b = &b_top[x];
537
21.3k
                add_compound_extended_candidate(same, same_count, cand_b,
538
21.3k
                                                sign0, sign1, ref, rf->sign_bias);
539
21.3k
                x += dav1d_block_dimensions[cand_b->bs][0];
540
21.3k
            }
541
542
            // non-self references in left
543
39.2k
            if (n_cols != ~0U) for (int y = 0; y < sz4;) {
544
20.4k
                const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
545
20.4k
                add_compound_extended_candidate(same, same_count, cand_b,
546
20.4k
                                                sign0, sign1, ref, rf->sign_bias);
547
20.4k
                y += dav1d_block_dimensions[cand_b->bs][1];
548
20.4k
            }
549
550
25.2k
            refmvs_candidate *const diff = &same[2];
551
25.2k
            const int *const diff_count = &same_count[2];
552
553
            // merge together
554
75.7k
            for (int n = 0; n < 2; n++) {
555
50.4k
                int m = same_count[n];
556
557
50.4k
                if (m >= 2) continue;
558
559
39.1k
                const int l = diff_count[n];
560
39.1k
                if (l) {
561
32.8k
                    same[m].mv.mv[n] = diff[0].mv.mv[n];
562
32.8k
                    if (++m == 2) continue;
563
11.6k
                    if (l == 2) {
564
8.84k
                        same[1].mv.mv[n] = diff[1].mv.mv[n];
565
8.84k
                        continue;
566
8.84k
                    }
567
11.6k
                }
568
13.4k
                do {
569
13.4k
                    same[m].mv.mv[n] = tgmv[n];
570
13.4k
                } while (++m < 2);
571
9.11k
            }
572
573
            // if the first extended was the same as the non-extended one,
574
            // then replace it with the second extended one
575
25.2k
            int n = *cnt;
576
25.2k
            if (n == 1 && mvstack[0].mv.n == same[0].mv.n)
577
9.21k
                mvstack[1].mv = mvstack[2].mv;
578
38.2k
            do {
579
38.2k
                mvstack[n].weight = 2;
580
38.2k
            } while (++n < 2);
581
25.2k
            *cnt = 2;
582
25.2k
        }
583
584
        // clamping
585
34.3k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
586
34.3k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
587
34.3k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
588
34.3k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
589
590
34.3k
        const int n_refmvs = *cnt;
591
34.3k
        int n = 0;
592
74.8k
        do {
593
74.8k
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
594
74.8k
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
595
74.8k
            mvstack[n].mv.mv[1].x = iclip(mvstack[n].mv.mv[1].x, left, right);
596
74.8k
            mvstack[n].mv.mv[1].y = iclip(mvstack[n].mv.mv[1].y, top, bottom);
597
74.8k
        } while (++n < n_refmvs);
598
599
34.3k
        switch (refmv_ctx >> 1) {
600
14.5k
        case 0:
601
14.5k
            *ctx = imin(newmv_ctx, 1);
602
14.5k
            break;
603
12.4k
        case 1:
604
12.4k
            *ctx = 1 + imin(newmv_ctx, 3);
605
12.4k
            break;
606
7.32k
        case 2:
607
7.32k
            *ctx = iclip(3 + newmv_ctx, 4, 7);
608
7.32k
            break;
609
34.3k
        }
610
611
34.3k
        return;
612
399k
    } else if (*cnt < 2 && ref.ref[0] > 0) {
613
74.0k
        const int sign = rf->sign_bias[ref.ref[0] - 1];
614
74.0k
        const int sz4 = imin(w4, h4);
615
616
        // non-self references in top
617
113k
        if (n_rows != ~0U) for (int x = 0; x < sz4 && *cnt < 2;) {
618
57.9k
            const refmvs_block *const cand_b = &b_top[x];
619
57.9k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
620
57.9k
            x += dav1d_block_dimensions[cand_b->bs][0];
621
57.9k
        }
622
623
        // non-self references in left
624
103k
        if (n_cols != ~0U) for (int y = 0; y < sz4 && *cnt < 2;) {
625
48.5k
            const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
626
48.5k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
627
48.5k
            y += dav1d_block_dimensions[cand_b->bs][1];
628
48.5k
        }
629
74.0k
    }
630
399k
    assert(*cnt <= 8);
631
632
    // clamping
633
399k
    int n_refmvs = *cnt;
634
399k
    if (n_refmvs) {
635
372k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
636
372k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
637
372k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
638
372k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
639
640
372k
        int n = 0;
641
988k
        do {
642
988k
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
643
988k
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
644
988k
        } while (++n < n_refmvs);
645
372k
    }
646
647
538k
    for (int n = *cnt; n < 2; n++)
648
139k
        mvstack[n].mv.mv[0] = tgmv[0];
649
650
399k
    *ctx = (refmv_ctx << 4) | (globalmv_ctx << 3) | newmv_ctx;
651
399k
}
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
47.6k
{
658
47.6k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
659
47.6k
    rt->rp_proj = &rf->rp_proj[16 * rf->rp_stride * tile_row_idx];
660
47.6k
    const ptrdiff_t r_stride = rf->rp_stride * 2;
661
47.6k
    const ptrdiff_t pass_off = (rf->n_frame_threads > 1 && pass == 2) ?
662
28.2k
        35 * 2 * rf->n_blocks : 0;
663
47.6k
    refmvs_block *r = &rf->r[35 * r_stride * tile_row_idx + pass_off];
664
47.6k
    const int sbsz = rf->sbsz;
665
47.6k
    const int off = (sbsz * sby) & 16;
666
1.09M
    for (int i = 0; i < sbsz; i++, r += r_stride)
667
1.04M
        rt->r[off + 5 + i] = r;
668
47.6k
    rt->r[off + 0] = r;
669
47.6k
    r += r_stride;
670
47.6k
    rt->r[off + 1] = NULL;
671
47.6k
    rt->r[off + 2] = r;
672
47.6k
    r += r_stride;
673
47.6k
    rt->r[off + 3] = NULL;
674
47.6k
    rt->r[off + 4] = r;
675
47.6k
    if (sby & 1) {
676
49.6k
#define EXCHANGE(a, b) do { void *const tmp = a; a = b; b = tmp; } while (0)
677
16.5k
        EXCHANGE(rt->r[off + 0], rt->r[off + sbsz + 0]);
678
16.5k
        EXCHANGE(rt->r[off + 2], rt->r[off + sbsz + 2]);
679
16.5k
        EXCHANGE(rt->r[off + 4], rt->r[off + sbsz + 4]);
680
16.5k
#undef EXCHANGE
681
16.5k
    }
682
683
47.6k
    rt->rf = rf;
684
47.6k
    rt->tile_row.start = tile_row_start4;
685
47.6k
    rt->tile_row.end = imin(tile_row_end4, rf->ih4);
686
47.6k
    rt->tile_col.start = tile_col_start4;
687
47.6k
    rt->tile_col.end = imin(tile_col_end4, rf->iw4);
688
47.6k
}
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
1.90k
{
694
1.90k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
695
1.90k
    assert(row_start8 >= 0);
696
1.90k
    assert((unsigned) (row_end8 - row_start8) <= 16U);
697
1.90k
    row_end8 = imin(row_end8, rf->ih8);
698
1.90k
    const int col_start8i = imax(col_start8 - 8, 0);
699
1.90k
    const int col_end8i = imin(col_end8 + 8, rf->iw8);
700
701
1.90k
    const ptrdiff_t stride = rf->rp_stride;
702
1.90k
    refmvs_temporal_block *rp_proj =
703
1.90k
        &rf->rp_proj[16 * stride * tile_row_idx + (row_start8 & 15) * stride];
704
15.2k
    for (int y = row_start8; y < row_end8; y++) {
705
52.3k
        for (int x = col_start8; x < col_end8; x++)
706
39.0k
            rp_proj[x].mv.n = INVALID_MV;
707
13.3k
        rp_proj += stride;
708
13.3k
    }
709
710
1.90k
    rp_proj = &rf->rp_proj[16 * stride * tile_row_idx];
711
3.51k
    for (int n = 0; n < rf->n_mfmvs; n++) {
712
1.60k
        const int ref2cur = rf->mfmv_ref2cur[n];
713
1.60k
        if (ref2cur == INVALID_REF2CUR) continue;
714
715
1.16k
        const int ref = rf->mfmv_ref[n];
716
1.16k
        const int ref_sign = ref - 4;
717
1.16k
        const refmvs_temporal_block *r = &rf->rp_ref[ref][row_start8 * stride];
718
8.71k
        for (int y = row_start8; y < row_end8; y++) {
719
7.54k
            const int y_sb_align = y & ~7;
720
7.54k
            const int y_proj_start = imax(y_sb_align, row_start8);
721
7.54k
            const int y_proj_end = imin(y_sb_align + 8, row_end8);
722
26.8k
            for (int x = col_start8i; x < col_end8i; x++) {
723
19.2k
                const refmvs_temporal_block *rb = &r[x];
724
19.2k
                const int b_ref = rb->ref;
725
19.2k
                if (!b_ref) continue;
726
8.83k
                const int ref2ref = rf->mfmv_ref2ref[n][b_ref - 1];
727
8.83k
                if (!ref2ref) continue;
728
4.06k
                const mv b_mv = rb->mv;
729
4.06k
                const mv offset = mv_projection(b_mv, ref2cur, ref2ref);
730
4.06k
                int pos_x = x + apply_sign(abs(offset.x) >> 6,
731
4.06k
                                           offset.x ^ ref_sign);
732
4.06k
                const int pos_y = y + apply_sign(abs(offset.y) >> 6,
733
4.06k
                                                 offset.y ^ ref_sign);
734
4.06k
                if (pos_y >= y_proj_start && pos_y < y_proj_end) {
735
3.42k
                    const ptrdiff_t pos = (pos_y & 15) * stride;
736
10.6k
                    for (;;) {
737
10.6k
                        const int x_sb_align = x & ~7;
738
10.6k
                        if (pos_x >= imax(x_sb_align - 8, col_start8) &&
739
10.5k
                            pos_x < imin(x_sb_align + 16, col_end8))
740
10.4k
                        {
741
10.4k
                            rp_proj[pos + pos_x].mv = rb->mv;
742
10.4k
                            rp_proj[pos + pos_x].ref = ref2ref;
743
10.4k
                        }
744
10.6k
                        if (++x >= col_end8i) break;
745
8.71k
                        rb++;
746
8.71k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
747
7.23k
                        pos_x++;
748
7.23k
                    }
749
3.42k
                } else {
750
1.42k
                    for (;;) {
751
1.42k
                        if (++x >= col_end8i) break;
752
1.15k
                        rb++;
753
1.15k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
754
1.15k
                    }
755
640
                }
756
4.06k
                x--;
757
4.06k
            }
758
7.54k
            r += stride;
759
7.54k
        }
760
1.16k
    }
761
1.90k
}
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
5.77k
{
769
48.2k
    for (int y = row_start8; y < row_end8; y++) {
770
42.5k
        const refmvs_block *const b = rr[(y & 15) * 2];
771
772
100k
        for (int x = col_start8; x < col_end8;) {
773
57.8k
            const refmvs_block *const cand_b = &b[x * 2 + 1];
774
57.8k
            const int bw8 = (dav1d_block_dimensions[cand_b->bs][0] + 1) >> 1;
775
776
57.8k
            if (cand_b->ref.ref[1] > 0 && ref_sign[cand_b->ref.ref[1] - 1] &&
777
9.00k
                (abs(cand_b->mv.mv[1].y) | abs(cand_b->mv.mv[1].x)) < 4096)
778
7.57k
            {
779
7.57k
                const refmvs_temporal_block tmv = {
780
7.57k
                    .mv = cand_b->mv.mv[1],
781
7.57k
                    .ref = cand_b->ref.ref[1],
782
7.57k
                };
783
22.5k
                for (int n = 0; n < bw8; n++, x++)
784
14.9k
                    rp[x] = tmv;
785
50.2k
            } else if (cand_b->ref.ref[0] > 0 && ref_sign[cand_b->ref.ref[0] - 1] &&
786
20.2k
                       (abs(cand_b->mv.mv[0].y) | abs(cand_b->mv.mv[0].x)) < 4096)
787
19.2k
            {
788
19.2k
                const refmvs_temporal_block tmv = {
789
19.2k
                    .mv = cand_b->mv.mv[0],
790
19.2k
                    .ref = cand_b->ref.ref[0],
791
19.2k
                };
792
80.9k
                for (int n = 0; n < bw8; n++, x++)
793
61.6k
                    rp[x] = tmv;
794
30.9k
            } else {
795
30.9k
                const refmvs_temporal_block tmv = { .mv = { .n = 0 }, .ref = 0 };
796
130k
                for (int n = 0; n < bw8; n++, x++)
797
99.2k
                    rp[x] = tmv;
798
30.9k
            }
799
57.8k
        }
800
42.5k
        rp += stride;
801
42.5k
    }
802
5.77k
}
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
12.2k
{
813
12.2k
    const int rp_stride = ((frm_hdr->width[0] + 127) & ~127) >> 3;
814
12.2k
    const int n_tile_rows = n_tile_threads > 1 ? frm_hdr->tiling.rows : 1;
815
12.2k
    const int n_blocks = rp_stride * n_tile_rows;
816
817
12.2k
    rf->sbsz = 16 << seq_hdr->sb128;
818
12.2k
    rf->frm_hdr = frm_hdr;
819
12.2k
    rf->iw8 = (frm_hdr->width[0] + 7) >> 3;
820
12.2k
    rf->ih8 = (frm_hdr->height + 7) >> 3;
821
12.2k
    rf->iw4 = rf->iw8 << 1;
822
12.2k
    rf->ih4 = rf->ih8 << 1;
823
12.2k
    rf->rp = rp;
824
12.2k
    rf->rp_stride = rp_stride;
825
12.2k
    rf->n_tile_threads = n_tile_threads;
826
12.2k
    rf->n_frame_threads = n_frame_threads;
827
828
12.2k
    if (n_blocks != rf->n_blocks) {
829
12.1k
        const size_t r_sz = sizeof(*rf->r) * 35 * 2 * n_blocks * (1 + (n_frame_threads > 1));
830
12.1k
        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
12.1k
        dav1d_free_aligned(rf->r);
834
12.1k
        rf->r = dav1d_alloc_aligned(ALLOC_REFMVS, r_sz + rp_proj_sz, 64);
835
12.1k
        if (!rf->r) {
836
0
            rf->n_blocks = 0;
837
0
            return DAV1D_ERR(ENOMEM);
838
0
        }
839
840
12.1k
        rf->rp_proj = (refmvs_temporal_block*)((uintptr_t)rf->r + r_sz);
841
12.1k
        rf->n_blocks = n_blocks;
842
12.1k
    }
843
844
12.2k
    const int poc = frm_hdr->frame_offset;
845
97.7k
    for (int i = 0; i < 7; i++) {
846
85.5k
        const int poc_diff = get_poc_diff(seq_hdr->order_hint_n_bits,
847
85.5k
                                          ref_poc[i], poc);
848
85.5k
        rf->sign_bias[i] = poc_diff > 0;
849
85.5k
        rf->mfmv_sign[i] = poc_diff < 0;
850
85.5k
        rf->pocdiff[i] = iclip(get_poc_diff(seq_hdr->order_hint_n_bits,
851
85.5k
                                            poc, ref_poc[i]), -31, 31);
852
85.5k
    }
853
854
    // temporal MV setup
855
12.2k
    rf->n_mfmvs = 0;
856
12.2k
    rf->rp_ref = rp_ref;
857
12.2k
    if (frm_hdr->use_ref_frame_mvs && seq_hdr->order_hint_n_bits) {
858
1.44k
        int total = 2;
859
1.44k
        if (rp_ref[0] && ref_ref_poc[0][6] != ref_poc[3] /* alt-of-last != gold */) {
860
216
            rf->mfmv_ref[rf->n_mfmvs++] = 0; // last
861
216
            total = 3;
862
216
        }
863
1.44k
        if (rp_ref[4] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[4],
864
439
                                      frm_hdr->frame_offset) > 0)
865
212
        {
866
212
            rf->mfmv_ref[rf->n_mfmvs++] = 4; // bwd
867
212
        }
868
1.44k
        if (rp_ref[5] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[5],
869
399
                                      frm_hdr->frame_offset) > 0)
870
175
        {
871
175
            rf->mfmv_ref[rf->n_mfmvs++] = 5; // altref2
872
175
        }
873
1.44k
        if (rf->n_mfmvs < total && rp_ref[6] &&
874
280
            get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[6],
875
280
                         frm_hdr->frame_offset) > 0)
876
129
        {
877
129
            rf->mfmv_ref[rf->n_mfmvs++] = 6; // altref
878
129
        }
879
1.44k
        if (rf->n_mfmvs < total && rp_ref[1])
880
455
            rf->mfmv_ref[rf->n_mfmvs++] = 1; // last2
881
882
2.63k
        for (int n = 0; n < rf->n_mfmvs; n++) {
883
1.18k
            const int rpoc = ref_poc[rf->mfmv_ref[n]];
884
1.18k
            const int diff1 = get_poc_diff(seq_hdr->order_hint_n_bits,
885
1.18k
                                           rpoc, frm_hdr->frame_offset);
886
1.18k
            if (abs(diff1) > 31) {
887
264
                rf->mfmv_ref2cur[n] = INVALID_REF2CUR;
888
923
            } else {
889
923
                rf->mfmv_ref2cur[n] = rf->mfmv_ref[n] < 4 ? -diff1 : diff1;
890
7.38k
                for (int m = 0; m < 7; m++) {
891
6.46k
                    const int rrpoc = ref_ref_poc[rf->mfmv_ref[n]][m];
892
6.46k
                    const int diff2 = get_poc_diff(seq_hdr->order_hint_n_bits,
893
6.46k
                                                   rpoc, rrpoc);
894
                    // unsigned comparison also catches the < 0 case
895
6.46k
                    rf->mfmv_ref2ref[n][m] = (unsigned) diff2 > 31U ? 0 : diff2;
896
6.46k
                }
897
923
            }
898
1.18k
        }
899
1.44k
    }
900
12.2k
    rf->use_ref_frame_mvs = rf->n_mfmvs > 0;
901
902
12.2k
    return 0;
903
12.2k
}
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
894k
{
908
3.54M
    do {
909
3.54M
        refmvs_block *const r = *rr++ + bx4;
910
37.2M
        for (int x = 0; x < bw4; x++)
911
33.6M
            r[x] = *rmv;
912
3.54M
    } while (--bh4);
913
894k
}
914
915
#if HAVE_ASM
916
#if ARCH_AARCH64 || ARCH_ARM
917
#include "src/arm/refmvs.h"
918
#elif ARCH_LOONGARCH64
919
#include "src/loongarch/refmvs.h"
920
#elif ARCH_X86
921
#include "src/x86/refmvs.h"
922
#endif
923
#endif
924
925
COLD void dav1d_refmvs_dsp_init(Dav1dRefmvsDSPContext *const c)
926
25.8k
{
927
25.8k
    c->load_tmvs = load_tmvs_c;
928
25.8k
    c->save_tmvs = save_tmvs_c;
929
25.8k
    c->splat_mv = splat_mv_c;
930
931
#if HAVE_ASM
932
#if ARCH_AARCH64 || ARCH_ARM
933
    refmvs_dsp_init_arm(c);
934
#elif ARCH_LOONGARCH64
935
    refmvs_dsp_init_loongarch(c);
936
#elif ARCH_X86
937
    refmvs_dsp_init_x86(c);
938
#endif
939
#endif
940
25.8k
}