Coverage Report

Created: 2026-09-13 06:34

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
8.41M
{
47
8.41M
    if (b->mv.mv[0].n == INVALID_MV) return; // intra block, no intrabc
48
49
7.58M
    if (ref.ref[1] == -1) {
50
9.11M
        for (int n = 0; n < 2; n++) {
51
7.93M
            if (b->ref.ref[n] == ref.ref[0]) {
52
5.40M
                const mv cand_mv = ((b->mf & 1) && gmv[0].n != INVALID_MV) ?
53
5.21M
                                   gmv[0] : b->mv.mv[n];
54
55
5.40M
                *have_refmv_match = 1;
56
5.40M
                *have_newmv_match |= b->mf >> 1;
57
58
5.40M
                const int last = *cnt;
59
9.70M
                for (int m = 0; m < last; m++)
60
6.15M
                    if (mvstack[m].mv.mv[0].n == cand_mv.n) {
61
1.85M
                        mvstack[m].weight += weight;
62
1.85M
                        return;
63
1.85M
                    }
64
65
3.55M
                if (last < 8) {
66
3.54M
                    mvstack[last].mv.mv[0] = cand_mv;
67
3.54M
                    mvstack[last].weight = weight;
68
3.54M
                    *cnt = last + 1;
69
3.54M
                }
70
3.55M
                return;
71
5.40M
            }
72
7.93M
        }
73
6.59M
    } else if (b->ref.pair == ref.pair) {
74
324k
        const refmvs_mvpair cand_mv = { .mv = {
75
324k
            [0] = ((b->mf & 1) && gmv[0].n != INVALID_MV) ? gmv[0] : b->mv.mv[0],
76
324k
            [1] = ((b->mf & 1) && gmv[1].n != INVALID_MV) ? gmv[1] : b->mv.mv[1],
77
324k
        }};
78
79
324k
        *have_refmv_match = 1;
80
324k
        *have_newmv_match |= b->mf >> 1;
81
82
324k
        const int last = *cnt;
83
478k
        for (int n = 0; n < last; n++)
84
275k
            if (mvstack[n].mv.n == cand_mv.n) {
85
121k
                mvstack[n].weight += weight;
86
121k
                return;
87
121k
            }
88
89
203k
        if (last < 8) {
90
203k
            mvstack[last].mv = cand_mv;
91
203k
            mvstack[last].weight = weight;
92
203k
            *cnt = last + 1;
93
203k
        }
94
203k
    }
95
7.58M
}
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
2.70M
{
103
2.70M
    const refmvs_block *cand_b = b;
104
2.70M
    const enum BlockSize first_cand_bs = cand_b->bs;
105
2.70M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
106
2.70M
    int cand_bw4 = first_cand_b_dim[0];
107
2.70M
    int len = imax(step, imin(bw4, cand_bw4));
108
109
2.70M
    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
2.34M
        const int weight = bw4 == 1 ? 2 :
115
2.34M
                           imax(2, imin(2 * max_rows, first_cand_b_dim[1]));
116
2.34M
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
117
2.34M
                              have_newmv_match, have_refmv_match);
118
2.34M
        return weight >> 1;
119
2.34M
    }
120
121
671k
    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
671k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
126
671k
                              have_newmv_match, have_refmv_match);
127
671k
        x += len;
128
671k
        if (x >= w4) return 1;
129
310k
        cand_b = &b[x];
130
310k
        cand_bw4 = dav1d_block_dimensions[cand_b->bs][0];
131
310k
        assert(cand_bw4 < bw4);
132
310k
        len = imax(step, cand_bw4);
133
310k
    }
134
361k
}
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
3.31M
{
142
3.31M
    const refmvs_block *cand_b = &b[0][bx4];
143
3.31M
    const enum BlockSize first_cand_bs = cand_b->bs;
144
3.31M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
145
3.31M
    int cand_bh4 = first_cand_b_dim[1];
146
3.31M
    int len = imax(step, imin(bh4, cand_bh4));
147
148
3.31M
    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
2.99M
        const int weight = bh4 == 1 ? 2 :
154
2.99M
                           imax(2, imin(2 * max_cols, first_cand_b_dim[0]));
155
2.99M
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
156
2.99M
                            have_newmv_match, have_refmv_match);
157
2.99M
        return weight >> 1;
158
2.99M
    }
159
160
624k
    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
624k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
165
624k
                              have_newmv_match, have_refmv_match);
166
624k
        y += len;
167
624k
        if (y >= h4) return 1;
168
301k
        cand_b = &b[y][bx4];
169
301k
        cand_bh4 = dav1d_block_dimensions[cand_b->bs][1];
170
301k
        assert(cand_bh4 < bh4);
171
301k
        len = imax(step, cand_bh4);
172
301k
    }
173
325k
}
174
175
289k
static inline union mv mv_projection(const union mv mv, const int num, const int den) {
176
289k
    static const uint16_t div_mult[32] = {
177
289k
           0, 16384, 8192, 5461, 4096, 3276, 2730, 2340,
178
289k
        2048,  1820, 1638, 1489, 1365, 1260, 1170, 1092,
179
289k
        1024,   963,  910,  862,  819,  780,  744,  712,
180
289k
         682,   655,  630,  606,  585,  564,  546,  528
181
289k
    };
182
289k
    assert(den > 0 && den < 32);
183
289k
    assert(num > -32 && num < 32);
184
289k
    const int frac = num * div_mult[den];
185
289k
    const int y = mv.y * frac, x = mv.x * frac;
186
    // Round and clip according to AV1 spec section 7.9.3
187
289k
    return (union mv) { // 0x3fff == (1 << 14) - 1
188
289k
        .y = iclip((y + 8192 + (y >> 31)) >> 14, -0x3fff, 0x3fff),
189
289k
        .x = iclip((x + 8192 + (x >> 31)) >> 14, -0x3fff, 0x3fff)
190
289k
    };
191
289k
}
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
291k
{
199
291k
    if (rb->mv.n == INVALID_MV) return;
200
201
146k
    union mv mv = mv_projection(rb->mv, rf->pocdiff[ref.ref[0] - 1], rb->ref);
202
146k
    fix_mv_precision(rf->frm_hdr, &mv);
203
204
146k
    const int last = *cnt;
205
146k
    if (ref.ref[1] == -1) {
206
90.8k
        if (globalmv_ctx)
207
24.3k
            *globalmv_ctx = (abs(mv.x - gmv[0].x) | abs(mv.y - gmv[0].y)) >= 16;
208
209
147k
        for (int n = 0; n < last; n++)
210
127k
            if (mvstack[n].mv.mv[0].n == mv.n) {
211
70.9k
                mvstack[n].weight += 2;
212
70.9k
                return;
213
70.9k
            }
214
19.8k
        if (last < 8) {
215
19.8k
            mvstack[last].mv.mv[0] = mv;
216
19.8k
            mvstack[last].weight = 2;
217
19.8k
            *cnt = last + 1;
218
19.8k
        }
219
55.3k
    } else {
220
55.3k
        refmvs_mvpair mvp = { .mv = {
221
55.3k
            [0] = mv,
222
55.3k
            [1] = mv_projection(rb->mv, rf->pocdiff[ref.ref[1] - 1], rb->ref),
223
55.3k
        }};
224
55.3k
        fix_mv_precision(rf->frm_hdr, &mvp.mv[1]);
225
226
80.3k
        for (int n = 0; n < last; n++)
227
68.5k
            if (mvstack[n].mv.n == mvp.n) {
228
43.5k
                mvstack[n].weight += 2;
229
43.5k
                return;
230
43.5k
            }
231
11.7k
        if (last < 8) {
232
11.7k
            mvstack[last].mv = mvp;
233
11.7k
            mvstack[last].weight = 2;
234
11.7k
            *cnt = last + 1;
235
11.7k
        }
236
11.7k
    }
237
146k
}
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
263k
{
246
263k
    refmvs_candidate *const diff = &same[2];
247
263k
    int *const diff_count = &same_count[2];
248
249
678k
    for (int n = 0; n < 2; n++) {
250
518k
        const int cand_ref = cand_b->ref.ref[n];
251
252
518k
        if (cand_ref <= 0) break;
253
254
415k
        mv cand_mv = cand_b->mv.mv[n];
255
415k
        if (cand_ref == ref.ref[0]) {
256
148k
            if (same_count[0] < 2)
257
143k
                same[same_count[0]++].mv.mv[0] = cand_mv;
258
148k
            if (diff_count[1] < 2) {
259
127k
                if (sign1 ^ sign_bias[cand_ref - 1]) {
260
7.43k
                    cand_mv.y = -cand_mv.y;
261
7.43k
                    cand_mv.x = -cand_mv.x;
262
7.43k
                }
263
127k
                diff[diff_count[1]++].mv.mv[1] = cand_mv;
264
127k
            }
265
267k
        } else if (cand_ref == ref.ref[1]) {
266
144k
            if (same_count[1] < 2)
267
140k
                same[same_count[1]++].mv.mv[1] = cand_mv;
268
144k
            if (diff_count[0] < 2) {
269
119k
                if (sign0 ^ sign_bias[cand_ref - 1]) {
270
7.42k
                    cand_mv.y = -cand_mv.y;
271
7.42k
                    cand_mv.x = -cand_mv.x;
272
7.42k
                }
273
119k
                diff[diff_count[0]++].mv.mv[0] = cand_mv;
274
119k
            }
275
144k
        } else {
276
123k
            mv i_cand_mv = (union mv) {
277
123k
                .x = -cand_mv.x,
278
123k
                .y = -cand_mv.y
279
123k
            };
280
281
123k
            if (diff_count[0] < 2) {
282
97.5k
                diff[diff_count[0]++].mv.mv[0] =
283
97.5k
                    sign0 ^ sign_bias[cand_ref - 1] ?
284
94.0k
                    i_cand_mv : cand_mv;
285
97.5k
            }
286
287
123k
            if (diff_count[1] < 2) {
288
91.4k
                diff[diff_count[1]++].mv.mv[1] =
289
91.4k
                    sign1 ^ sign_bias[cand_ref - 1] ?
290
88.7k
                    i_cand_mv : cand_mv;
291
91.4k
            }
292
123k
        }
293
415k
    }
294
263k
}
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
916k
{
300
1.84M
    for (int n = 0; n < 2; n++) {
301
1.79M
        const int cand_ref = cand_b->ref.ref[n];
302
303
1.79M
        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
928k
        mv cand_mv = cand_b->mv.mv[n];
311
928k
        if (sign ^ sign_bias[cand_ref - 1]) {
312
9.55k
            cand_mv.y = -cand_mv.y;
313
9.55k
            cand_mv.x = -cand_mv.x;
314
9.55k
        }
315
316
928k
        int m;
317
928k
        const int last = *cnt;
318
1.05M
        for (m = 0; m < last; m++)
319
827k
            if (cand_mv.n == mvstack[m].mv.mv[0].n)
320
698k
                break;
321
928k
        if (m == last) {
322
230k
            mvstack[m].mv.mv[0] = cand_mv;
323
230k
            mvstack[m].weight = 2; // "minimal"
324
230k
            *cnt = last + 1;
325
230k
        }
326
928k
    }
327
916k
}
328
329
/*
330
 * refmvs_frame allocates memory for one sbrow (32 blocks high, whole frame
331
 * wide) of 4x4-resolution refmvs_block entries for spatial MV referencing.
332
 * mvrefs_tile[] keeps a list of 35 (32 + 3 above) pointers into this memory,
333
 * and each sbrow, the bottom entries (y=27/29/31) are exchanged with the top
334
 * (-5/-3/-1) pointers by calling dav1d_refmvs_tile_sbrow_init() at the start
335
 * of each tile/sbrow.
336
 *
337
 * For temporal MV referencing, we call dav1d_refmvs_save_tmvs() at the end of
338
 * each tile/sbrow (when tile column threading is enabled), or at the start of
339
 * each interleaved sbrow (i.e. once for all tile columns together, when tile
340
 * column threading is disabled). This will copy the 4x4-resolution spatial MVs
341
 * into 8x8-resolution refmvs_temporal_block structures. Then, for subsequent
342
 * frames, at the start of each tile/sbrow (when tile column threading is
343
 * enabled) or at the start of each interleaved sbrow (when tile column
344
 * threading is disabled), we call load_tmvs(), which will project the MVs to
345
 * their respective position in the current frame.
346
 */
347
348
void dav1d_refmvs_find(const refmvs_tile *const rt,
349
                       refmvs_candidate mvstack[8], int *const cnt,
350
                       int *const ctx,
351
                       const union refmvs_refpair ref, const enum BlockSize bs,
352
                       const enum EdgeFlags edge_flags,
353
                       const int by4, const int bx4)
354
2.12M
{
355
2.12M
    const refmvs_frame *const rf = rt->rf;
356
2.12M
    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
357
2.12M
    const int bw4 = b_dim[0], w4 = imin(imin(bw4, 16), rt->tile_col.end - bx4);
358
2.12M
    const int bh4 = b_dim[1], h4 = imin(imin(bh4, 16), rt->tile_row.end - by4);
359
2.12M
    mv gmv[2], tgmv[2];
360
361
2.12M
    *cnt = 0;
362
2.12M
    assert(ref.ref[0] >=  0 && ref.ref[0] <= 8 &&
363
2.12M
           ref.ref[1] >= -1 && ref.ref[1] <= 8);
364
2.12M
    if (ref.ref[0] > 0) {
365
1.34M
        tgmv[0] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[0] - 1],
366
1.34M
                             bx4, by4, bw4, bh4, rf->frm_hdr);
367
1.34M
        gmv[0] = rf->frm_hdr->gmv[ref.ref[0] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
368
935k
                 tgmv[0] : (mv) { .n = INVALID_MV };
369
1.34M
    } else {
370
775k
        tgmv[0] = (mv) { .n = 0 };
371
775k
        gmv[0] = (mv) { .n = INVALID_MV };
372
775k
    }
373
2.12M
    if (ref.ref[1] > 0) {
374
250k
        tgmv[1] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[1] - 1],
375
250k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
376
250k
        gmv[1] = rf->frm_hdr->gmv[ref.ref[1] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
377
173k
                 tgmv[1] : (mv) { .n = INVALID_MV };
378
250k
    }
379
380
    // top
381
2.12M
    int have_newmv = 0, have_col_mvs = 0, have_row_mvs = 0;
382
2.12M
    unsigned max_rows = 0, n_rows = ~0;
383
2.12M
    const refmvs_block *b_top;
384
2.12M
    if (by4 > rt->tile_row.start) {
385
1.46M
        max_rows = imin((by4 - rt->tile_row.start + 1) >> 1, 2 + (bh4 > 1));
386
1.46M
        b_top = &rt->r[(by4 & 31) - 1 + 5][bx4];
387
1.46M
        n_rows = scan_row(mvstack, cnt, ref, gmv, b_top,
388
1.46M
                          bw4, w4, max_rows, bw4 >= 16 ? 4 : 1,
389
1.46M
                          &have_newmv, &have_row_mvs);
390
1.46M
    }
391
392
    // left
393
2.12M
    unsigned max_cols = 0, n_cols = ~0U;
394
2.12M
    refmvs_block *const *b_left;
395
2.12M
    if (bx4 > rt->tile_col.start) {
396
1.60M
        max_cols = imin((bx4 - rt->tile_col.start + 1) >> 1, 2 + (bw4 > 1));
397
1.60M
        b_left = &rt->r[(by4 & 31) + 5];
398
1.60M
        n_cols = scan_col(mvstack, cnt, ref, gmv, b_left,
399
1.60M
                          bh4, h4, bx4 - 1, max_cols, bh4 >= 16 ? 4 : 1,
400
1.60M
                          &have_newmv, &have_col_mvs);
401
1.60M
    }
402
403
    // top/right
404
2.12M
    if (n_rows != ~0U && edge_flags & EDGE_I444_TOP_HAS_RIGHT &&
405
903k
        imax(bw4, bh4) <= 16 && bw4 + bx4 < rt->tile_col.end)
406
648k
    {
407
648k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[bw4], ref, gmv,
408
648k
                              &have_newmv, &have_row_mvs);
409
648k
    }
410
411
2.12M
    const int nearest_match = have_col_mvs + have_row_mvs;
412
2.12M
    const int nearest_cnt = *cnt;
413
4.48M
    for (int n = 0; n < nearest_cnt; n++)
414
2.35M
        mvstack[n].weight += 640;
415
416
    // temporal
417
2.12M
    int globalmv_ctx = rf->frm_hdr->use_ref_frame_mvs;
418
2.12M
    if (rf->use_ref_frame_mvs) {
419
97.9k
        const ptrdiff_t stride = rf->rp_stride;
420
97.9k
        const int by8 = by4 >> 1, bx8 = bx4 >> 1;
421
97.9k
        const refmvs_temporal_block *const rbi = &rt->rp_proj[(by8 & 15) * stride + bx8];
422
97.9k
        const refmvs_temporal_block *rb = rbi;
423
97.9k
        const int step_h = bw4 >= 16 ? 2 : 1, step_v = bh4 >= 16 ? 2 : 1;
424
97.9k
        const int w8 = imin((w4 + 1) >> 1, 8), h8 = imin((h4 + 1) >> 1, 8);
425
284k
        for (int y = 0; y < h8; y += step_v) {
426
442k
            for (int x = 0; x < w8; x+= step_h) {
427
255k
                add_temporal_candidate(rf, mvstack, cnt, &rb[x], ref,
428
255k
                                       !(x | y) ? &globalmv_ctx : NULL, tgmv);
429
255k
            }
430
186k
            rb += stride * step_v;
431
186k
        }
432
97.9k
        if (imin(bw4, bh4) >= 2 && imax(bw4, bh4) < 16) {
433
48.5k
            const int bh8 = bh4 >> 1, bw8 = bw4 >> 1;
434
48.5k
            rb = &rbi[bh8 * stride];
435
48.5k
            const int has_bottom = by8 + bh8 < imin(rt->tile_row.end >> 1,
436
48.5k
                                                    (by8 & ~7) + 8);
437
48.5k
            if (has_bottom && bx8 - 1 >= imax(rt->tile_col.start >> 1, bx8 & ~7)) {
438
10.6k
                add_temporal_candidate(rf, mvstack, cnt, &rb[-1], ref,
439
10.6k
                                       NULL, NULL);
440
10.6k
            }
441
48.5k
            if (bx8 + bw8 < imin(rt->tile_col.end >> 1, (bx8 & ~7) + 8)) {
442
16.3k
                if (has_bottom) {
443
10.2k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8], ref,
444
10.2k
                                           NULL, NULL);
445
10.2k
                }
446
16.3k
                if (by8 + bh8 - 1 < imin(rt->tile_row.end >> 1, (by8 & ~7) + 8)) {
447
14.9k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8 - stride],
448
14.9k
                                           ref, NULL, NULL);
449
14.9k
                }
450
16.3k
            }
451
48.5k
        }
452
97.9k
    }
453
2.12M
    assert(*cnt <= 8);
454
455
    // top/left (which, confusingly, is part of "secondary" references)
456
2.12M
    int have_dummy_newmv_match;
457
2.12M
    if ((n_rows | n_cols) != ~0U) {
458
1.14M
        add_spatial_candidate(mvstack, cnt, 4, &b_top[-1], ref, gmv,
459
1.14M
                              &have_dummy_newmv_match, &have_row_mvs);
460
1.14M
    }
461
462
    // "secondary" (non-direct neighbour) top & left edges
463
    // what is different about secondary is that everything is now in 8x8 resolution
464
6.36M
    for (int n = 2; n <= 3; n++) {
465
4.24M
        if ((unsigned) n > n_rows && (unsigned) n <= max_rows) {
466
1.24M
            n_rows += scan_row(mvstack, cnt, ref, gmv,
467
1.24M
                               &rt->r[(((by4 & 31) - 2 * n + 1) | 1) + 5][bx4 | 1],
468
1.24M
                               bw4, w4, 1 + max_rows - n, bw4 >= 16 ? 4 : 2,
469
1.24M
                               &have_dummy_newmv_match, &have_row_mvs);
470
1.24M
        }
471
472
4.24M
        if ((unsigned) n > n_cols && (unsigned) n <= max_cols) {
473
1.71M
            n_cols += scan_col(mvstack, cnt, ref, gmv, &rt->r[((by4 & 31) | 1) + 5],
474
1.71M
                               bh4, h4, (bx4 - n * 2 + 1) | 1,
475
1.71M
                               1 + max_cols - n, bh4 >= 16 ? 4 : 2,
476
1.71M
                               &have_dummy_newmv_match, &have_col_mvs);
477
1.71M
        }
478
4.24M
    }
479
2.12M
    assert(*cnt <= 8);
480
481
2.12M
    const int ref_match_count = have_col_mvs + have_row_mvs;
482
483
    // context build-up
484
2.12M
    int refmv_ctx, newmv_ctx;
485
2.12M
    switch (nearest_match) {
486
509k
    case 0:
487
509k
        refmv_ctx = imin(2, ref_match_count);
488
509k
        newmv_ctx = ref_match_count > 0;
489
509k
        break;
490
896k
    case 1:
491
896k
        refmv_ctx = imin(ref_match_count * 3, 4);
492
896k
        newmv_ctx = 3 - have_newmv;
493
896k
        break;
494
718k
    case 2:
495
718k
        refmv_ctx = 5;
496
718k
        newmv_ctx = 5 - have_newmv;
497
718k
        break;
498
2.12M
    }
499
500
    // sorting (nearest, then "secondary")
501
2.12M
    int len = nearest_cnt;
502
4.11M
    while (len) {
503
1.99M
        int last = 0;
504
2.89M
        for (int n = 1; n < len; n++) {
505
898k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
506
462k
#define EXCHANGE(a, b) do { refmvs_candidate tmp = a; a = b; b = tmp; } while (0)
507
394k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
508
394k
                last = n;
509
394k
            }
510
898k
        }
511
1.99M
        len = last;
512
1.99M
    }
513
2.12M
    len = *cnt;
514
3.15M
    while (len > nearest_cnt) {
515
1.02M
        int last = nearest_cnt;
516
1.51M
        for (int n = nearest_cnt + 1; n < len; n++) {
517
484k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
518
68.2k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
519
68.2k
#undef EXCHANGE
520
68.2k
                last = n;
521
68.2k
            }
522
484k
        }
523
1.02M
        len = last;
524
1.02M
    }
525
526
2.12M
    if (ref.ref[1] > 0) {
527
250k
        if (*cnt < 2) {
528
197k
            const int sign0 = rf->sign_bias[ref.ref[0] - 1];
529
197k
            const int sign1 = rf->sign_bias[ref.ref[1] - 1];
530
197k
            const int sz4 = imin(w4, h4);
531
197k
            refmvs_candidate *const same = &mvstack[*cnt];
532
197k
            int same_count[4] = { 0 };
533
534
            // non-self references in top
535
257k
            if (n_rows != ~0U) for (int x = 0; x < sz4;) {
536
134k
                const refmvs_block *const cand_b = &b_top[x];
537
134k
                add_compound_extended_candidate(same, same_count, cand_b,
538
134k
                                                sign0, sign1, ref, rf->sign_bias);
539
134k
                x += dav1d_block_dimensions[cand_b->bs][0];
540
134k
            }
541
542
            // non-self references in left
543
243k
            if (n_cols != ~0U) for (int y = 0; y < sz4;) {
544
128k
                const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
545
128k
                add_compound_extended_candidate(same, same_count, cand_b,
546
128k
                                                sign0, sign1, ref, rf->sign_bias);
547
128k
                y += dav1d_block_dimensions[cand_b->bs][1];
548
128k
            }
549
550
197k
            refmvs_candidate *const diff = &same[2];
551
197k
            const int *const diff_count = &same_count[2];
552
553
            // merge together
554
592k
            for (int n = 0; n < 2; n++) {
555
395k
                int m = same_count[n];
556
557
395k
                if (m >= 2) continue;
558
559
324k
                const int l = diff_count[n];
560
324k
                if (l) {
561
202k
                    same[m].mv.mv[n] = diff[0].mv.mv[n];
562
202k
                    if (++m == 2) continue;
563
72.8k
                    if (l == 2) {
564
54.4k
                        same[1].mv.mv[n] = diff[1].mv.mv[n];
565
54.4k
                        continue;
566
54.4k
                    }
567
72.8k
                }
568
248k
                do {
569
248k
                    same[m].mv.mv[n] = tgmv[n];
570
248k
                } while (++m < 2);
571
140k
            }
572
573
            // if the first extended was the same as the non-extended one,
574
            // then replace it with the second extended one
575
197k
            int n = *cnt;
576
197k
            if (n == 1 && mvstack[0].mv.n == same[0].mv.n)
577
56.4k
                mvstack[1].mv = mvstack[2].mv;
578
316k
            do {
579
316k
                mvstack[n].weight = 2;
580
316k
            } while (++n < 2);
581
197k
            *cnt = 2;
582
197k
        }
583
584
        // clamping
585
250k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
586
250k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
587
250k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
588
250k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
589
590
250k
        const int n_refmvs = *cnt;
591
250k
        int n = 0;
592
531k
        do {
593
531k
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
594
531k
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
595
531k
            mvstack[n].mv.mv[1].x = iclip(mvstack[n].mv.mv[1].x, left, right);
596
531k
            mvstack[n].mv.mv[1].y = iclip(mvstack[n].mv.mv[1].y, top, bottom);
597
531k
        } while (++n < n_refmvs);
598
599
250k
        switch (refmv_ctx >> 1) {
600
132k
        case 0:
601
132k
            *ctx = imin(newmv_ctx, 1);
602
132k
            break;
603
74.1k
        case 1:
604
74.1k
            *ctx = 1 + imin(newmv_ctx, 3);
605
74.1k
            break;
606
43.0k
        case 2:
607
43.0k
            *ctx = iclip(3 + newmv_ctx, 4, 7);
608
43.0k
            break;
609
250k
        }
610
611
250k
        return;
612
1.87M
    } else if (*cnt < 2 && ref.ref[0] > 0) {
613
762k
        const int sign = rf->sign_bias[ref.ref[0] - 1];
614
762k
        const int sz4 = imin(w4, h4);
615
616
        // non-self references in top
617
1.07M
        if (n_rows != ~0U) for (int x = 0; x < sz4 && *cnt < 2;) {
618
547k
            const refmvs_block *const cand_b = &b_top[x];
619
547k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
620
547k
            x += dav1d_block_dimensions[cand_b->bs][0];
621
547k
        }
622
623
        // non-self references in left
624
769k
        if (n_cols != ~0U) for (int y = 0; y < sz4 && *cnt < 2;) {
625
369k
            const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
626
369k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
627
369k
            y += dav1d_block_dimensions[cand_b->bs][1];
628
369k
        }
629
762k
    }
630
1.87M
    assert(*cnt <= 8);
631
632
    // clamping
633
1.87M
    int n_refmvs = *cnt;
634
1.87M
    if (n_refmvs) {
635
1.65M
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
636
1.65M
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
637
1.65M
        const int top = -(by4 + bh4 + 4) * 4 * 8;
638
1.65M
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
639
640
1.65M
        int n = 0;
641
3.80M
        do {
642
3.80M
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
643
3.80M
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
644
3.80M
        } while (++n < n_refmvs);
645
1.65M
    }
646
647
2.87M
    for (int n = *cnt; n < 2; n++)
648
999k
        mvstack[n].mv.mv[0] = tgmv[0];
649
650
1.87M
    *ctx = (refmv_ctx << 4) | (globalmv_ctx << 3) | newmv_ctx;
651
1.87M
}
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
684k
{
658
684k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
659
684k
    rt->rp_proj = &rf->rp_proj[16 * rf->rp_stride * tile_row_idx];
660
684k
    const ptrdiff_t r_stride = rf->rp_stride * 2;
661
684k
    const ptrdiff_t pass_off = (rf->n_frame_threads > 1 && pass == 2) ?
662
359k
        35 * 2 * rf->n_blocks : 0;
663
684k
    refmvs_block *r = &rf->r[35 * r_stride * tile_row_idx + pass_off];
664
684k
    const int sbsz = rf->sbsz;
665
684k
    const int off = (sbsz * sby) & 16;
666
14.1M
    for (int i = 0; i < sbsz; i++, r += r_stride)
667
13.4M
        rt->r[off + 5 + i] = r;
668
684k
    rt->r[off + 0] = r;
669
684k
    r += r_stride;
670
684k
    rt->r[off + 1] = NULL;
671
684k
    rt->r[off + 2] = r;
672
684k
    r += r_stride;
673
684k
    rt->r[off + 3] = NULL;
674
684k
    rt->r[off + 4] = r;
675
684k
    if (sby & 1) {
676
500k
#define EXCHANGE(a, b) do { void *const tmp = a; a = b; b = tmp; } while (0)
677
166k
        EXCHANGE(rt->r[off + 0], rt->r[off + sbsz + 0]);
678
166k
        EXCHANGE(rt->r[off + 2], rt->r[off + sbsz + 2]);
679
166k
        EXCHANGE(rt->r[off + 4], rt->r[off + sbsz + 4]);
680
166k
#undef EXCHANGE
681
166k
    }
682
683
684k
    rt->rf = rf;
684
684k
    rt->tile_row.start = tile_row_start4;
685
684k
    rt->tile_row.end = imin(tile_row_end4, rf->ih4);
686
684k
    rt->tile_col.start = tile_col_start4;
687
684k
    rt->tile_col.end = imin(tile_col_end4, rf->iw4);
688
684k
}
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
49.7k
{
694
49.7k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
695
49.7k
    assert(row_start8 >= 0);
696
49.7k
    assert((unsigned) (row_end8 - row_start8) <= 16U);
697
49.7k
    row_end8 = imin(row_end8, rf->ih8);
698
49.7k
    const int col_start8i = imax(col_start8 - 8, 0);
699
49.7k
    const int col_end8i = imin(col_end8 + 8, rf->iw8);
700
701
49.7k
    const ptrdiff_t stride = rf->rp_stride;
702
49.7k
    refmvs_temporal_block *rp_proj =
703
49.7k
        &rf->rp_proj[16 * stride * tile_row_idx + (row_start8 & 15) * stride];
704
311k
    for (int y = row_start8; y < row_end8; y++) {
705
958k
        for (int x = col_start8; x < col_end8; x++)
706
696k
            rp_proj[x].mv.n = INVALID_MV;
707
262k
        rp_proj += stride;
708
262k
    }
709
710
49.7k
    rp_proj = &rf->rp_proj[16 * stride * tile_row_idx];
711
110k
    for (int n = 0; n < rf->n_mfmvs; n++) {
712
60.2k
        const int ref2cur = rf->mfmv_ref2cur[n];
713
60.2k
        if (ref2cur == INVALID_REF2CUR) continue;
714
715
43.9k
        const int ref = rf->mfmv_ref[n];
716
43.9k
        const int ref_sign = ref - 4;
717
43.9k
        const refmvs_temporal_block *r = &rf->rp_ref[ref][row_start8 * stride];
718
279k
        for (int y = row_start8; y < row_end8; y++) {
719
235k
            const int y_sb_align = y & ~7;
720
235k
            const int y_proj_start = imax(y_sb_align, row_start8);
721
235k
            const int y_proj_end = imin(y_sb_align + 8, row_end8);
722
550k
            for (int x = col_start8i; x < col_end8i; x++) {
723
315k
                const refmvs_temporal_block *rb = &r[x];
724
315k
                const int b_ref = rb->ref;
725
315k
                if (!b_ref) continue;
726
118k
                const int ref2ref = rf->mfmv_ref2ref[n][b_ref - 1];
727
118k
                if (!ref2ref) continue;
728
87.8k
                const mv b_mv = rb->mv;
729
87.8k
                const mv offset = mv_projection(b_mv, ref2cur, ref2ref);
730
87.8k
                int pos_x = x + apply_sign(abs(offset.x) >> 6,
731
87.8k
                                           offset.x ^ ref_sign);
732
87.8k
                const int pos_y = y + apply_sign(abs(offset.y) >> 6,
733
87.8k
                                                 offset.y ^ ref_sign);
734
87.8k
                if (pos_y >= y_proj_start && pos_y < y_proj_end) {
735
79.7k
                    const ptrdiff_t pos = (pos_y & 15) * stride;
736
200k
                    for (;;) {
737
200k
                        const int x_sb_align = x & ~7;
738
200k
                        if (pos_x >= imax(x_sb_align - 8, col_start8) &&
739
196k
                            pos_x < imin(x_sb_align + 16, col_end8))
740
193k
                        {
741
193k
                            rp_proj[pos + pos_x].mv = rb->mv;
742
193k
                            rp_proj[pos + pos_x].ref = ref2ref;
743
193k
                        }
744
200k
                        if (++x >= col_end8i) break;
745
135k
                        rb++;
746
135k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
747
120k
                        pos_x++;
748
120k
                    }
749
79.7k
                } else {
750
14.0k
                    for (;;) {
751
14.0k
                        if (++x >= col_end8i) break;
752
9.87k
                        rb++;
753
9.87k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
754
9.87k
                    }
755
8.11k
                }
756
87.8k
                x--;
757
87.8k
            }
758
235k
            r += stride;
759
235k
        }
760
43.9k
    }
761
49.7k
}
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
102k
{
769
627k
    for (int y = row_start8; y < row_end8; y++) {
770
524k
        const refmvs_block *const b = rr[(y & 15) * 2];
771
772
1.22M
        for (int x = col_start8; x < col_end8;) {
773
703k
            const refmvs_block *const cand_b = &b[x * 2 + 1];
774
703k
            const int bw8 = (dav1d_block_dimensions[cand_b->bs][0] + 1) >> 1;
775
776
703k
            if (cand_b->ref.ref[1] > 0 && ref_sign[cand_b->ref.ref[1] - 1] &&
777
69.9k
                (abs(cand_b->mv.mv[1].y) | abs(cand_b->mv.mv[1].x)) < 4096)
778
63.4k
            {
779
63.4k
                const refmvs_temporal_block tmv = {
780
63.4k
                    .mv = cand_b->mv.mv[1],
781
63.4k
                    .ref = cand_b->ref.ref[1],
782
63.4k
                };
783
232k
                for (int n = 0; n < bw8; n++, x++)
784
169k
                    rp[x] = tmv;
785
639k
            } else if (cand_b->ref.ref[0] > 0 && ref_sign[cand_b->ref.ref[0] - 1] &&
786
203k
                       (abs(cand_b->mv.mv[0].y) | abs(cand_b->mv.mv[0].x)) < 4096)
787
199k
            {
788
199k
                const refmvs_temporal_block tmv = {
789
199k
                    .mv = cand_b->mv.mv[0],
790
199k
                    .ref = cand_b->ref.ref[0],
791
199k
                };
792
887k
                for (int n = 0; n < bw8; n++, x++)
793
687k
                    rp[x] = tmv;
794
439k
            } else {
795
439k
                const refmvs_temporal_block tmv = { .mv = { .n = 0 }, .ref = 0 };
796
2.24M
                for (int n = 0; n < bw8; n++, x++)
797
1.80M
                    rp[x] = tmv;
798
439k
            }
799
703k
        }
800
524k
        rp += stride;
801
524k
    }
802
102k
}
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
232k
{
813
232k
    const int rp_stride = ((frm_hdr->width[0] + 127) & ~127) >> 3;
814
18.4E
    const int n_tile_rows = n_tile_threads > 1 ? frm_hdr->tiling.rows : 1;
815
232k
    const int n_blocks = rp_stride * n_tile_rows;
816
817
232k
    rf->sbsz = 16 << seq_hdr->sb128;
818
232k
    rf->frm_hdr = frm_hdr;
819
232k
    rf->iw8 = (frm_hdr->width[0] + 7) >> 3;
820
232k
    rf->ih8 = (frm_hdr->height + 7) >> 3;
821
232k
    rf->iw4 = rf->iw8 << 1;
822
232k
    rf->ih4 = rf->ih8 << 1;
823
232k
    rf->rp = rp;
824
232k
    rf->rp_stride = rp_stride;
825
232k
    rf->n_tile_threads = n_tile_threads;
826
232k
    rf->n_frame_threads = n_frame_threads;
827
828
232k
    if (n_blocks != rf->n_blocks) {
829
75.5k
        const size_t r_sz = sizeof(*rf->r) * 35 * 2 * n_blocks * (1 + (n_frame_threads > 1));
830
75.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
75.5k
        dav1d_free_aligned(rf->r);
834
75.5k
        rf->r = dav1d_alloc_aligned(ALLOC_REFMVS, r_sz + rp_proj_sz, 64);
835
75.5k
        if (!rf->r) {
836
0
            rf->n_blocks = 0;
837
0
            return DAV1D_ERR(ENOMEM);
838
0
        }
839
840
75.5k
        rf->rp_proj = (refmvs_temporal_block*)((uintptr_t)rf->r + r_sz);
841
75.5k
        rf->n_blocks = n_blocks;
842
75.5k
    }
843
844
232k
    const int poc = frm_hdr->frame_offset;
845
1.85M
    for (int i = 0; i < 7; i++) {
846
1.62M
        const int poc_diff = get_poc_diff(seq_hdr->order_hint_n_bits,
847
1.62M
                                          ref_poc[i], poc);
848
1.62M
        rf->sign_bias[i] = poc_diff > 0;
849
1.62M
        rf->mfmv_sign[i] = poc_diff < 0;
850
1.62M
        rf->pocdiff[i] = iclip(get_poc_diff(seq_hdr->order_hint_n_bits,
851
1.62M
                                            poc, ref_poc[i]), -31, 31);
852
1.62M
    }
853
854
    // temporal MV setup
855
232k
    rf->n_mfmvs = 0;
856
232k
    rf->rp_ref = rp_ref;
857
232k
    if (frm_hdr->use_ref_frame_mvs && seq_hdr->order_hint_n_bits) {
858
44.8k
        int total = 2;
859
44.8k
        if (rp_ref[0] && ref_ref_poc[0][6] != ref_poc[3] /* alt-of-last != gold */) {
860
14.8k
            rf->mfmv_ref[rf->n_mfmvs++] = 0; // last
861
14.8k
            total = 3;
862
14.8k
        }
863
44.8k
        if (rp_ref[4] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[4],
864
34.9k
                                      frm_hdr->frame_offset) > 0)
865
2.30k
        {
866
2.30k
            rf->mfmv_ref[rf->n_mfmvs++] = 4; // bwd
867
2.30k
        }
868
44.8k
        if (rp_ref[5] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[5],
869
34.5k
                                      frm_hdr->frame_offset) > 0)
870
1.17k
        {
871
1.17k
            rf->mfmv_ref[rf->n_mfmvs++] = 5; // altref2
872
1.17k
        }
873
44.8k
        if (rf->n_mfmvs < total && rp_ref[6] &&
874
25.4k
            get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[6],
875
25.4k
                         frm_hdr->frame_offset) > 0)
876
10.3k
        {
877
10.3k
            rf->mfmv_ref[rf->n_mfmvs++] = 6; // altref
878
10.3k
        }
879
44.8k
        if (rf->n_mfmvs < total && rp_ref[1])
880
29.5k
            rf->mfmv_ref[rf->n_mfmvs++] = 1; // last2
881
882
103k
        for (int n = 0; n < rf->n_mfmvs; n++) {
883
58.2k
            const int rpoc = ref_poc[rf->mfmv_ref[n]];
884
58.2k
            const int diff1 = get_poc_diff(seq_hdr->order_hint_n_bits,
885
58.2k
                                           rpoc, frm_hdr->frame_offset);
886
58.2k
            if (abs(diff1) > 31) {
887
16.0k
                rf->mfmv_ref2cur[n] = INVALID_REF2CUR;
888
42.1k
            } else {
889
42.1k
                rf->mfmv_ref2cur[n] = rf->mfmv_ref[n] < 4 ? -diff1 : diff1;
890
337k
                for (int m = 0; m < 7; m++) {
891
294k
                    const int rrpoc = ref_ref_poc[rf->mfmv_ref[n]][m];
892
294k
                    const int diff2 = get_poc_diff(seq_hdr->order_hint_n_bits,
893
294k
                                                   rpoc, rrpoc);
894
                    // unsigned comparison also catches the < 0 case
895
294k
                    rf->mfmv_ref2ref[n][m] = (unsigned) diff2 > 31U ? 0 : diff2;
896
294k
                }
897
42.1k
            }
898
58.2k
        }
899
44.8k
    }
900
232k
    rf->use_ref_frame_mvs = rf->n_mfmvs > 0;
901
902
232k
    return 0;
903
232k
}
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
3.51M
{
908
14.2M
    do {
909
14.2M
        refmvs_block *const r = *rr++ + bx4;
910
136M
        for (int x = 0; x < bw4; x++)
911
122M
            r[x] = *rmv;
912
14.2M
    } while (--bh4);
913
3.51M
}
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
95.7k
{
927
95.7k
    c->load_tmvs = load_tmvs_c;
928
95.7k
    c->save_tmvs = save_tmvs_c;
929
95.7k
    c->splat_mv = splat_mv_c;
930
931
#if HAVE_ASM
932
#if ARCH_AARCH64 || ARCH_ARM
933
    refmvs_dsp_init_arm(c);
934
#elif ARCH_LOONGARCH64
935
    refmvs_dsp_init_loongarch(c);
936
#elif ARCH_X86
937
    refmvs_dsp_init_x86(c);
938
#endif
939
#endif
940
95.7k
}