Coverage Report

Created: 2026-09-14 06:44

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.43M
{
47
8.43M
    if (b->mv.mv[0].n == INVALID_MV) return; // intra block, no intrabc
48
49
7.62M
    if (ref.ref[1] == -1) {
50
9.12M
        for (int n = 0; n < 2; n++) {
51
7.95M
            if (b->ref.ref[n] == ref.ref[0]) {
52
5.45M
                const mv cand_mv = ((b->mf & 1) && gmv[0].n != INVALID_MV) ?
53
5.28M
                                   gmv[0] : b->mv.mv[n];
54
55
5.45M
                *have_refmv_match = 1;
56
5.45M
                *have_newmv_match |= b->mf >> 1;
57
58
5.45M
                const int last = *cnt;
59
9.87M
                for (int m = 0; m < last; m++)
60
6.27M
                    if (mvstack[m].mv.mv[0].n == cand_mv.n) {
61
1.86M
                        mvstack[m].weight += weight;
62
1.86M
                        return;
63
1.86M
                    }
64
65
3.59M
                if (last < 8) {
66
3.59M
                    mvstack[last].mv.mv[0] = cand_mv;
67
3.59M
                    mvstack[last].weight = weight;
68
3.59M
                    *cnt = last + 1;
69
3.59M
                }
70
3.59M
                return;
71
5.45M
            }
72
7.95M
        }
73
6.62M
    } else if (b->ref.pair == ref.pair) {
74
327k
        const refmvs_mvpair cand_mv = { .mv = {
75
327k
            [0] = ((b->mf & 1) && gmv[0].n != INVALID_MV) ? gmv[0] : b->mv.mv[0],
76
327k
            [1] = ((b->mf & 1) && gmv[1].n != INVALID_MV) ? gmv[1] : b->mv.mv[1],
77
327k
        }};
78
79
327k
        *have_refmv_match = 1;
80
327k
        *have_newmv_match |= b->mf >> 1;
81
82
327k
        const int last = *cnt;
83
490k
        for (int n = 0; n < last; n++)
84
284k
            if (mvstack[n].mv.n == cand_mv.n) {
85
121k
                mvstack[n].weight += weight;
86
121k
                return;
87
121k
            }
88
89
206k
        if (last < 8) {
90
205k
            mvstack[last].mv = cand_mv;
91
205k
            mvstack[last].weight = weight;
92
205k
            *cnt = last + 1;
93
205k
        }
94
206k
    }
95
7.62M
}
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.67M
{
103
2.67M
    const refmvs_block *cand_b = b;
104
2.67M
    const enum BlockSize first_cand_bs = cand_b->bs;
105
2.67M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
106
2.67M
    int cand_bw4 = first_cand_b_dim[0];
107
2.67M
    int len = imax(step, imin(bw4, cand_bw4));
108
109
2.67M
    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.32M
        const int weight = bw4 == 1 ? 2 :
115
2.32M
                           imax(2, imin(2 * max_rows, first_cand_b_dim[1]));
116
2.32M
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
117
2.32M
                              have_newmv_match, have_refmv_match);
118
2.32M
        return weight >> 1;
119
2.32M
    }
120
121
661k
    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
661k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
126
661k
                              have_newmv_match, have_refmv_match);
127
661k
        x += len;
128
661k
        if (x >= w4) return 1;
129
309k
        cand_b = &b[x];
130
309k
        cand_bw4 = dav1d_block_dimensions[cand_b->bs][0];
131
309k
        assert(cand_bw4 < bw4);
132
309k
        len = imax(step, cand_bw4);
133
309k
    }
134
352k
}
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.35M
{
142
3.35M
    const refmvs_block *cand_b = &b[0][bx4];
143
3.35M
    const enum BlockSize first_cand_bs = cand_b->bs;
144
3.35M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
145
3.35M
    int cand_bh4 = first_cand_b_dim[1];
146
3.35M
    int len = imax(step, imin(bh4, cand_bh4));
147
148
3.35M
    if (bh4 <= cand_bh4) {
149
        // FIXME weight can be higher for odd blocks (by4 & 1), but then the
150
        // position of the first block has to be odd already, i.e. not just
151
        // for col_offset=-3/-5
152
        // FIXME why can this not be cand_bh4?
153
3.03M
        const int weight = bh4 == 1 ? 2 :
154
3.03M
                           imax(2, imin(2 * max_cols, first_cand_b_dim[0]));
155
3.03M
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
156
3.03M
                            have_newmv_match, have_refmv_match);
157
3.03M
        return weight >> 1;
158
3.03M
    }
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
302k
        cand_b = &b[y][bx4];
169
302k
        cand_bh4 = dav1d_block_dimensions[cand_b->bs][1];
170
302k
        assert(cand_bh4 < bh4);
171
302k
        len = imax(step, cand_bh4);
172
302k
    }
173
325k
}
174
175
274k
static inline union mv mv_projection(const union mv mv, const int num, const int den) {
176
274k
    static const uint16_t div_mult[32] = {
177
274k
           0, 16384, 8192, 5461, 4096, 3276, 2730, 2340,
178
274k
        2048,  1820, 1638, 1489, 1365, 1260, 1170, 1092,
179
274k
        1024,   963,  910,  862,  819,  780,  744,  712,
180
274k
         682,   655,  630,  606,  585,  564,  546,  528
181
274k
    };
182
274k
    assert(den > 0 && den < 32);
183
274k
    assert(num > -32 && num < 32);
184
274k
    const int frac = num * div_mult[den];
185
274k
    const int y = mv.y * frac, x = mv.x * frac;
186
    // Round and clip according to AV1 spec section 7.9.3
187
274k
    return (union mv) { // 0x3fff == (1 << 14) - 1
188
274k
        .y = iclip((y + 8192 + (y >> 31)) >> 14, -0x3fff, 0x3fff),
189
274k
        .x = iclip((x + 8192 + (x >> 31)) >> 14, -0x3fff, 0x3fff)
190
274k
    };
191
274k
}
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
278k
{
199
278k
    if (rb->mv.n == INVALID_MV) return;
200
201
140k
    union mv mv = mv_projection(rb->mv, rf->pocdiff[ref.ref[0] - 1], rb->ref);
202
140k
    fix_mv_precision(rf->frm_hdr, &mv);
203
204
140k
    const int last = *cnt;
205
140k
    if (ref.ref[1] == -1) {
206
88.2k
        if (globalmv_ctx)
207
22.4k
            *globalmv_ctx = (abs(mv.x - gmv[0].x) | abs(mv.y - gmv[0].y)) >= 16;
208
209
141k
        for (int n = 0; n < last; n++)
210
123k
            if (mvstack[n].mv.mv[0].n == mv.n) {
211
69.9k
                mvstack[n].weight += 2;
212
69.9k
                return;
213
69.9k
            }
214
18.3k
        if (last < 8) {
215
18.2k
            mvstack[last].mv.mv[0] = mv;
216
18.2k
            mvstack[last].weight = 2;
217
18.2k
            *cnt = last + 1;
218
18.2k
        }
219
51.7k
    } else {
220
51.7k
        refmvs_mvpair mvp = { .mv = {
221
51.7k
            [0] = mv,
222
51.7k
            [1] = mv_projection(rb->mv, rf->pocdiff[ref.ref[1] - 1], rb->ref),
223
51.7k
        }};
224
51.7k
        fix_mv_precision(rf->frm_hdr, &mvp.mv[1]);
225
226
75.8k
        for (int n = 0; n < last; n++)
227
65.1k
            if (mvstack[n].mv.n == mvp.n) {
228
40.9k
                mvstack[n].weight += 2;
229
40.9k
                return;
230
40.9k
            }
231
10.7k
        if (last < 8) {
232
10.7k
            mvstack[last].mv = mvp;
233
10.7k
            mvstack[last].weight = 2;
234
10.7k
            *cnt = last + 1;
235
10.7k
        }
236
10.7k
    }
237
140k
}
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
262k
{
246
262k
    refmvs_candidate *const diff = &same[2];
247
262k
    int *const diff_count = &same_count[2];
248
249
676k
    for (int n = 0; n < 2; n++) {
250
517k
        const int cand_ref = cand_b->ref.ref[n];
251
252
517k
        if (cand_ref <= 0) break;
253
254
413k
        mv cand_mv = cand_b->mv.mv[n];
255
413k
        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.13k
                    cand_mv.y = -cand_mv.y;
261
7.13k
                    cand_mv.x = -cand_mv.x;
262
7.13k
                }
263
127k
                diff[diff_count[1]++].mv.mv[1] = cand_mv;
264
127k
            }
265
265k
        } else if (cand_ref == ref.ref[1]) {
266
142k
            if (same_count[1] < 2)
267
139k
                same[same_count[1]++].mv.mv[1] = cand_mv;
268
142k
            if (diff_count[0] < 2) {
269
118k
                if (sign0 ^ sign_bias[cand_ref - 1]) {
270
7.09k
                    cand_mv.y = -cand_mv.y;
271
7.09k
                    cand_mv.x = -cand_mv.x;
272
7.09k
                }
273
118k
                diff[diff_count[0]++].mv.mv[0] = cand_mv;
274
118k
            }
275
142k
        } else {
276
122k
            mv i_cand_mv = (union mv) {
277
122k
                .x = -cand_mv.x,
278
122k
                .y = -cand_mv.y
279
122k
            };
280
281
122k
            if (diff_count[0] < 2) {
282
97.0k
                diff[diff_count[0]++].mv.mv[0] =
283
97.0k
                    sign0 ^ sign_bias[cand_ref - 1] ?
284
93.7k
                    i_cand_mv : cand_mv;
285
97.0k
            }
286
287
122k
            if (diff_count[1] < 2) {
288
90.7k
                diff[diff_count[1]++].mv.mv[1] =
289
90.7k
                    sign1 ^ sign_bias[cand_ref - 1] ?
290
88.0k
                    i_cand_mv : cand_mv;
291
90.7k
            }
292
122k
        }
293
413k
    }
294
262k
}
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
896k
{
300
1.80M
    for (int n = 0; n < 2; n++) {
301
1.75M
        const int cand_ref = cand_b->ref.ref[n];
302
303
1.75M
        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
908k
        mv cand_mv = cand_b->mv.mv[n];
311
908k
        if (sign ^ sign_bias[cand_ref - 1]) {
312
9.24k
            cand_mv.y = -cand_mv.y;
313
9.24k
            cand_mv.x = -cand_mv.x;
314
9.24k
        }
315
316
908k
        int m;
317
908k
        const int last = *cnt;
318
1.03M
        for (m = 0; m < last; m++)
319
812k
            if (cand_mv.n == mvstack[m].mv.mv[0].n)
320
683k
                break;
321
908k
        if (m == last) {
322
225k
            mvstack[m].mv.mv[0] = cand_mv;
323
225k
            mvstack[m].weight = 2; // "minimal"
324
225k
            *cnt = last + 1;
325
225k
        }
326
908k
    }
327
896k
}
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.11M
{
355
2.11M
    const refmvs_frame *const rf = rt->rf;
356
2.11M
    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
357
2.11M
    const int bw4 = b_dim[0], w4 = imin(imin(bw4, 16), rt->tile_col.end - bx4);
358
2.11M
    const int bh4 = b_dim[1], h4 = imin(imin(bh4, 16), rt->tile_row.end - by4);
359
2.11M
    mv gmv[2], tgmv[2];
360
361
2.11M
    *cnt = 0;
362
2.11M
    assert(ref.ref[0] >=  0 && ref.ref[0] <= 8 &&
363
2.11M
           ref.ref[1] >= -1 && ref.ref[1] <= 8);
364
2.11M
    if (ref.ref[0] > 0) {
365
1.31M
        tgmv[0] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[0] - 1],
366
1.31M
                             bx4, by4, bw4, bh4, rf->frm_hdr);
367
1.31M
        gmv[0] = rf->frm_hdr->gmv[ref.ref[0] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
368
920k
                 tgmv[0] : (mv) { .n = INVALID_MV };
369
1.31M
    } else {
370
791k
        tgmv[0] = (mv) { .n = 0 };
371
791k
        gmv[0] = (mv) { .n = INVALID_MV };
372
791k
    }
373
2.11M
    if (ref.ref[1] > 0) {
374
247k
        tgmv[1] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[1] - 1],
375
247k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
376
247k
        gmv[1] = rf->frm_hdr->gmv[ref.ref[1] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
377
172k
                 tgmv[1] : (mv) { .n = INVALID_MV };
378
247k
    }
379
380
    // top
381
2.11M
    int have_newmv = 0, have_col_mvs = 0, have_row_mvs = 0;
382
2.11M
    unsigned max_rows = 0, n_rows = ~0;
383
2.11M
    const refmvs_block *b_top;
384
2.11M
    if (by4 > rt->tile_row.start) {
385
1.45M
        max_rows = imin((by4 - rt->tile_row.start + 1) >> 1, 2 + (bh4 > 1));
386
1.45M
        b_top = &rt->r[(by4 & 31) - 1 + 5][bx4];
387
1.45M
        n_rows = scan_row(mvstack, cnt, ref, gmv, b_top,
388
1.45M
                          bw4, w4, max_rows, bw4 >= 16 ? 4 : 1,
389
1.45M
                          &have_newmv, &have_row_mvs);
390
1.45M
    }
391
392
    // left
393
2.11M
    unsigned max_cols = 0, n_cols = ~0U;
394
2.11M
    refmvs_block *const *b_left;
395
2.11M
    if (bx4 > rt->tile_col.start) {
396
1.62M
        max_cols = imin((bx4 - rt->tile_col.start + 1) >> 1, 2 + (bw4 > 1));
397
1.62M
        b_left = &rt->r[(by4 & 31) + 5];
398
1.62M
        n_cols = scan_col(mvstack, cnt, ref, gmv, b_left,
399
1.62M
                          bh4, h4, bx4 - 1, max_cols, bh4 >= 16 ? 4 : 1,
400
1.62M
                          &have_newmv, &have_col_mvs);
401
1.62M
    }
402
403
    // top/right
404
2.11M
    if (n_rows != ~0U && edge_flags & EDGE_I444_TOP_HAS_RIGHT &&
405
893k
        imax(bw4, bh4) <= 16 && bw4 + bx4 < rt->tile_col.end)
406
655k
    {
407
655k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[bw4], ref, gmv,
408
655k
                              &have_newmv, &have_row_mvs);
409
655k
    }
410
411
2.11M
    const int nearest_match = have_col_mvs + have_row_mvs;
412
2.11M
    const int nearest_cnt = *cnt;
413
4.49M
    for (int n = 0; n < nearest_cnt; n++)
414
2.38M
        mvstack[n].weight += 640;
415
416
    // temporal
417
2.11M
    int globalmv_ctx = rf->frm_hdr->use_ref_frame_mvs;
418
2.11M
    if (rf->use_ref_frame_mvs) {
419
87.5k
        const ptrdiff_t stride = rf->rp_stride;
420
87.5k
        const int by8 = by4 >> 1, bx8 = bx4 >> 1;
421
87.5k
        const refmvs_temporal_block *const rbi = &rt->rp_proj[(by8 & 15) * stride + bx8];
422
87.5k
        const refmvs_temporal_block *rb = rbi;
423
87.5k
        const int step_h = bw4 >= 16 ? 2 : 1, step_v = bh4 >= 16 ? 2 : 1;
424
87.5k
        const int w8 = imin((w4 + 1) >> 1, 8), h8 = imin((h4 + 1) >> 1, 8);
425
261k
        for (int y = 0; y < h8; y += step_v) {
426
418k
            for (int x = 0; x < w8; x+= step_h) {
427
244k
                add_temporal_candidate(rf, mvstack, cnt, &rb[x], ref,
428
244k
                                       !(x | y) ? &globalmv_ctx : NULL, tgmv);
429
244k
            }
430
174k
            rb += stride * step_v;
431
174k
        }
432
87.5k
        if (imin(bw4, bh4) >= 2 && imax(bw4, bh4) < 16) {
433
45.3k
            const int bh8 = bh4 >> 1, bw8 = bw4 >> 1;
434
45.3k
            rb = &rbi[bh8 * stride];
435
45.3k
            const int has_bottom = by8 + bh8 < imin(rt->tile_row.end >> 1,
436
45.3k
                                                    (by8 & ~7) + 8);
437
45.3k
            if (has_bottom && bx8 - 1 >= imax(rt->tile_col.start >> 1, bx8 & ~7)) {
438
10.3k
                add_temporal_candidate(rf, mvstack, cnt, &rb[-1], ref,
439
10.3k
                                       NULL, NULL);
440
10.3k
            }
441
45.3k
            if (bx8 + bw8 < imin(rt->tile_col.end >> 1, (bx8 & ~7) + 8)) {
442
15.7k
                if (has_bottom) {
443
9.92k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8], ref,
444
9.92k
                                           NULL, NULL);
445
9.92k
                }
446
15.7k
                if (by8 + bh8 - 1 < imin(rt->tile_row.end >> 1, (by8 & ~7) + 8)) {
447
14.5k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8 - stride],
448
14.5k
                                           ref, NULL, NULL);
449
14.5k
                }
450
15.7k
            }
451
45.3k
        }
452
87.5k
    }
453
2.11M
    assert(*cnt <= 8);
454
455
    // top/left (which, confusingly, is part of "secondary" references)
456
2.11M
    int have_dummy_newmv_match;
457
2.11M
    if ((n_rows | n_cols) != ~0U) {
458
1.15M
        add_spatial_candidate(mvstack, cnt, 4, &b_top[-1], ref, gmv,
459
1.15M
                              &have_dummy_newmv_match, &have_row_mvs);
460
1.15M
    }
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.32M
    for (int n = 2; n <= 3; n++) {
465
4.21M
        if ((unsigned) n > n_rows && (unsigned) n <= max_rows) {
466
1.22M
            n_rows += scan_row(mvstack, cnt, ref, gmv,
467
1.22M
                               &rt->r[(((by4 & 31) - 2 * n + 1) | 1) + 5][bx4 | 1],
468
1.22M
                               bw4, w4, 1 + max_rows - n, bw4 >= 16 ? 4 : 2,
469
1.22M
                               &have_dummy_newmv_match, &have_row_mvs);
470
1.22M
        }
471
472
4.21M
        if ((unsigned) n > n_cols && (unsigned) n <= max_cols) {
473
1.73M
            n_cols += scan_col(mvstack, cnt, ref, gmv, &rt->r[((by4 & 31) | 1) + 5],
474
1.73M
                               bh4, h4, (bx4 - n * 2 + 1) | 1,
475
1.73M
                               1 + max_cols - n, bh4 >= 16 ? 4 : 2,
476
1.73M
                               &have_dummy_newmv_match, &have_col_mvs);
477
1.73M
        }
478
4.21M
    }
479
2.11M
    assert(*cnt <= 8);
480
481
2.11M
    const int ref_match_count = have_col_mvs + have_row_mvs;
482
483
    // context build-up
484
2.11M
    int refmv_ctx, newmv_ctx;
485
2.11M
    switch (nearest_match) {
486
491k
    case 0:
487
491k
        refmv_ctx = imin(2, ref_match_count);
488
491k
        newmv_ctx = ref_match_count > 0;
489
491k
        break;
490
887k
    case 1:
491
887k
        refmv_ctx = imin(ref_match_count * 3, 4);
492
887k
        newmv_ctx = 3 - have_newmv;
493
887k
        break;
494
734k
    case 2:
495
734k
        refmv_ctx = 5;
496
734k
        newmv_ctx = 5 - have_newmv;
497
734k
        break;
498
2.11M
    }
499
500
    // sorting (nearest, then "secondary")
501
2.11M
    int len = nearest_cnt;
502
4.12M
    while (len) {
503
2.00M
        int last = 0;
504
2.93M
        for (int n = 1; n < len; n++) {
505
927k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
506
479k
#define EXCHANGE(a, b) do { refmvs_candidate tmp = a; a = b; b = tmp; } while (0)
507
408k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
508
408k
                last = n;
509
408k
            }
510
927k
        }
511
2.00M
        len = last;
512
2.00M
    }
513
2.11M
    len = *cnt;
514
3.15M
    while (len > nearest_cnt) {
515
1.04M
        int last = nearest_cnt;
516
1.55M
        for (int n = nearest_cnt + 1; n < len; n++) {
517
500k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
518
71.0k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
519
71.0k
#undef EXCHANGE
520
71.0k
                last = n;
521
71.0k
            }
522
500k
        }
523
1.04M
        len = last;
524
1.04M
    }
525
526
2.11M
    if (ref.ref[1] > 0) {
527
247k
        if (*cnt < 2) {
528
195k
            const int sign0 = rf->sign_bias[ref.ref[0] - 1];
529
195k
            const int sign1 = rf->sign_bias[ref.ref[1] - 1];
530
195k
            const int sz4 = imin(w4, h4);
531
195k
            refmvs_candidate *const same = &mvstack[*cnt];
532
195k
            int same_count[4] = { 0 };
533
534
            // non-self references in top
535
256k
            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
242k
            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
195k
            refmvs_candidate *const diff = &same[2];
551
195k
            const int *const diff_count = &same_count[2];
552
553
            // merge together
554
585k
            for (int n = 0; n < 2; n++) {
555
390k
                int m = same_count[n];
556
557
390k
                if (m >= 2) continue;
558
559
319k
                const int l = diff_count[n];
560
319k
                if (l) {
561
201k
                    same[m].mv.mv[n] = diff[0].mv.mv[n];
562
201k
                    if (++m == 2) continue;
563
72.4k
                    if (l == 2) {
564
54.2k
                        same[1].mv.mv[n] = diff[1].mv.mv[n];
565
54.2k
                        continue;
566
54.2k
                    }
567
72.4k
                }
568
241k
                do {
569
241k
                    same[m].mv.mv[n] = tgmv[n];
570
241k
                } while (++m < 2);
571
136k
            }
572
573
            // if the first extended was the same as the non-extended one,
574
            // then replace it with the second extended one
575
195k
            int n = *cnt;
576
195k
            if (n == 1 && mvstack[0].mv.n == same[0].mv.n)
577
56.0k
                mvstack[1].mv = mvstack[2].mv;
578
312k
            do {
579
312k
                mvstack[n].weight = 2;
580
312k
            } while (++n < 2);
581
195k
            *cnt = 2;
582
195k
        }
583
584
        // clamping
585
247k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
586
247k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
587
247k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
588
247k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
589
590
247k
        const int n_refmvs = *cnt;
591
247k
        int n = 0;
592
528k
        do {
593
528k
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
594
528k
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
595
528k
            mvstack[n].mv.mv[1].x = iclip(mvstack[n].mv.mv[1].x, left, right);
596
528k
            mvstack[n].mv.mv[1].y = iclip(mvstack[n].mv.mv[1].y, top, bottom);
597
528k
        } while (++n < n_refmvs);
598
599
247k
        switch (refmv_ctx >> 1) {
600
130k
        case 0:
601
130k
            *ctx = imin(newmv_ctx, 1);
602
130k
            break;
603
73.3k
        case 1:
604
73.3k
            *ctx = 1 + imin(newmv_ctx, 3);
605
73.3k
            break;
606
43.5k
        case 2:
607
43.5k
            *ctx = iclip(3 + newmv_ctx, 4, 7);
608
43.5k
            break;
609
247k
        }
610
611
247k
        return;
612
1.86M
    } else if (*cnt < 2 && ref.ref[0] > 0) {
613
733k
        const int sign = rf->sign_bias[ref.ref[0] - 1];
614
733k
        const int sz4 = imin(w4, h4);
615
616
        // non-self references in top
617
1.03M
        if (n_rows != ~0U) for (int x = 0; x < sz4 && *cnt < 2;) {
618
527k
            const refmvs_block *const cand_b = &b_top[x];
619
527k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
620
527k
            x += dav1d_block_dimensions[cand_b->bs][0];
621
527k
        }
622
623
        // non-self references in left
624
768k
        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
733k
    }
630
1.86M
    assert(*cnt <= 8);
631
632
    // clamping
633
1.86M
    int n_refmvs = *cnt;
634
1.86M
    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.85M
        do {
642
3.85M
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
643
3.85M
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
644
3.85M
        } while (++n < n_refmvs);
645
1.65M
    }
646
647
2.82M
    for (int n = *cnt; n < 2; n++)
648
959k
        mvstack[n].mv.mv[0] = tgmv[0];
649
650
1.86M
    *ctx = (refmv_ctx << 4) | (globalmv_ctx << 3) | newmv_ctx;
651
1.86M
}
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
650k
{
658
650k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
659
650k
    rt->rp_proj = &rf->rp_proj[16 * rf->rp_stride * tile_row_idx];
660
650k
    const ptrdiff_t r_stride = rf->rp_stride * 2;
661
650k
    const ptrdiff_t pass_off = (rf->n_frame_threads > 1 && pass == 2) ?
662
341k
        35 * 2 * rf->n_blocks : 0;
663
650k
    refmvs_block *r = &rf->r[35 * r_stride * tile_row_idx + pass_off];
664
650k
    const int sbsz = rf->sbsz;
665
650k
    const int off = (sbsz * sby) & 16;
666
13.4M
    for (int i = 0; i < sbsz; i++, r += r_stride)
667
12.8M
        rt->r[off + 5 + i] = r;
668
650k
    rt->r[off + 0] = r;
669
650k
    r += r_stride;
670
650k
    rt->r[off + 1] = NULL;
671
650k
    rt->r[off + 2] = r;
672
650k
    r += r_stride;
673
650k
    rt->r[off + 3] = NULL;
674
650k
    rt->r[off + 4] = r;
675
650k
    if (sby & 1) {
676
474k
#define EXCHANGE(a, b) do { void *const tmp = a; a = b; b = tmp; } while (0)
677
158k
        EXCHANGE(rt->r[off + 0], rt->r[off + sbsz + 0]);
678
158k
        EXCHANGE(rt->r[off + 2], rt->r[off + sbsz + 2]);
679
158k
        EXCHANGE(rt->r[off + 4], rt->r[off + sbsz + 4]);
680
158k
#undef EXCHANGE
681
158k
    }
682
683
650k
    rt->rf = rf;
684
650k
    rt->tile_row.start = tile_row_start4;
685
650k
    rt->tile_row.end = imin(tile_row_end4, rf->ih4);
686
650k
    rt->tile_col.start = tile_col_start4;
687
650k
    rt->tile_col.end = imin(tile_col_end4, rf->iw4);
688
650k
}
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
44.2k
{
694
44.2k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
695
44.2k
    assert(row_start8 >= 0);
696
44.2k
    assert((unsigned) (row_end8 - row_start8) <= 16U);
697
44.2k
    row_end8 = imin(row_end8, rf->ih8);
698
44.2k
    const int col_start8i = imax(col_start8 - 8, 0);
699
44.2k
    const int col_end8i = imin(col_end8 + 8, rf->iw8);
700
701
44.2k
    const ptrdiff_t stride = rf->rp_stride;
702
44.2k
    refmvs_temporal_block *rp_proj =
703
44.2k
        &rf->rp_proj[16 * stride * tile_row_idx + (row_start8 & 15) * stride];
704
297k
    for (int y = row_start8; y < row_end8; y++) {
705
908k
        for (int x = col_start8; x < col_end8; x++)
706
655k
            rp_proj[x].mv.n = INVALID_MV;
707
252k
        rp_proj += stride;
708
252k
    }
709
710
44.2k
    rp_proj = &rf->rp_proj[16 * stride * tile_row_idx];
711
94.2k
    for (int n = 0; n < rf->n_mfmvs; n++) {
712
50.0k
        const int ref2cur = rf->mfmv_ref2cur[n];
713
50.0k
        if (ref2cur == INVALID_REF2CUR) continue;
714
715
40.0k
        const int ref = rf->mfmv_ref[n];
716
40.0k
        const int ref_sign = ref - 4;
717
40.0k
        const refmvs_temporal_block *r = &rf->rp_ref[ref][row_start8 * stride];
718
268k
        for (int y = row_start8; y < row_end8; y++) {
719
228k
            const int y_sb_align = y & ~7;
720
228k
            const int y_proj_start = imax(y_sb_align, row_start8);
721
228k
            const int y_proj_end = imin(y_sb_align + 8, row_end8);
722
540k
            for (int x = col_start8i; x < col_end8i; x++) {
723
312k
                const refmvs_temporal_block *rb = &r[x];
724
312k
                const int b_ref = rb->ref;
725
312k
                if (!b_ref) continue;
726
115k
                const int ref2ref = rf->mfmv_ref2ref[n][b_ref - 1];
727
115k
                if (!ref2ref) continue;
728
82.9k
                const mv b_mv = rb->mv;
729
82.9k
                const mv offset = mv_projection(b_mv, ref2cur, ref2ref);
730
82.9k
                int pos_x = x + apply_sign(abs(offset.x) >> 6,
731
82.9k
                                           offset.x ^ ref_sign);
732
82.9k
                const int pos_y = y + apply_sign(abs(offset.y) >> 6,
733
82.9k
                                                 offset.y ^ ref_sign);
734
82.9k
                if (pos_y >= y_proj_start && pos_y < y_proj_end) {
735
74.1k
                    const ptrdiff_t pos = (pos_y & 15) * stride;
736
188k
                    for (;;) {
737
188k
                        const int x_sb_align = x & ~7;
738
188k
                        if (pos_x >= imax(x_sb_align - 8, col_start8) &&
739
185k
                            pos_x < imin(x_sb_align + 16, col_end8))
740
183k
                        {
741
183k
                            rp_proj[pos + pos_x].mv = rb->mv;
742
183k
                            rp_proj[pos + pos_x].ref = ref2ref;
743
183k
                        }
744
188k
                        if (++x >= col_end8i) break;
745
129k
                        rb++;
746
129k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
747
114k
                        pos_x++;
748
114k
                    }
749
74.1k
                } else {
750
14.6k
                    for (;;) {
751
14.6k
                        if (++x >= col_end8i) break;
752
10.2k
                        rb++;
753
10.2k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
754
10.2k
                    }
755
8.84k
                }
756
82.9k
                x--;
757
82.9k
            }
758
228k
            r += stride;
759
228k
        }
760
40.0k
    }
761
44.2k
}
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
95.1k
{
769
599k
    for (int y = row_start8; y < row_end8; y++) {
770
504k
        const refmvs_block *const b = rr[(y & 15) * 2];
771
772
1.17M
        for (int x = col_start8; x < col_end8;) {
773
670k
            const refmvs_block *const cand_b = &b[x * 2 + 1];
774
670k
            const int bw8 = (dav1d_block_dimensions[cand_b->bs][0] + 1) >> 1;
775
776
670k
            if (cand_b->ref.ref[1] > 0 && ref_sign[cand_b->ref.ref[1] - 1] &&
777
67.8k
                (abs(cand_b->mv.mv[1].y) | abs(cand_b->mv.mv[1].x)) < 4096)
778
61.5k
            {
779
61.5k
                const refmvs_temporal_block tmv = {
780
61.5k
                    .mv = cand_b->mv.mv[1],
781
61.5k
                    .ref = cand_b->ref.ref[1],
782
61.5k
                };
783
228k
                for (int n = 0; n < bw8; n++, x++)
784
166k
                    rp[x] = tmv;
785
609k
            } else if (cand_b->ref.ref[0] > 0 && ref_sign[cand_b->ref.ref[0] - 1] &&
786
197k
                       (abs(cand_b->mv.mv[0].y) | abs(cand_b->mv.mv[0].x)) < 4096)
787
193k
            {
788
193k
                const refmvs_temporal_block tmv = {
789
193k
                    .mv = cand_b->mv.mv[0],
790
193k
                    .ref = cand_b->ref.ref[0],
791
193k
                };
792
858k
                for (int n = 0; n < bw8; n++, x++)
793
665k
                    rp[x] = tmv;
794
415k
            } else {
795
415k
                const refmvs_temporal_block tmv = { .mv = { .n = 0 }, .ref = 0 };
796
2.15M
                for (int n = 0; n < bw8; n++, x++)
797
1.74M
                    rp[x] = tmv;
798
415k
            }
799
670k
        }
800
504k
        rp += stride;
801
504k
    }
802
95.1k
}
803
804
int dav1d_refmvs_init_frame(refmvs_frame *const rf,
805
                            const Dav1dSequenceHeader *const seq_hdr,
806
                            const Dav1dFrameHeader *const frm_hdr,
807
                            const uint8_t ref_poc[7],
808
                            refmvs_temporal_block *const rp,
809
                            const uint8_t ref_ref_poc[7][7],
810
                            /*const*/ refmvs_temporal_block *const rp_ref[7],
811
                            const int n_tile_threads, const int n_frame_threads)
812
221k
{
813
221k
    const int rp_stride = ((frm_hdr->width[0] + 127) & ~127) >> 3;
814
221k
    const int n_tile_rows = n_tile_threads > 1 ? frm_hdr->tiling.rows : 1;
815
221k
    const int n_blocks = rp_stride * n_tile_rows;
816
817
221k
    rf->sbsz = 16 << seq_hdr->sb128;
818
221k
    rf->frm_hdr = frm_hdr;
819
221k
    rf->iw8 = (frm_hdr->width[0] + 7) >> 3;
820
221k
    rf->ih8 = (frm_hdr->height + 7) >> 3;
821
221k
    rf->iw4 = rf->iw8 << 1;
822
221k
    rf->ih4 = rf->ih8 << 1;
823
221k
    rf->rp = rp;
824
221k
    rf->rp_stride = rp_stride;
825
221k
    rf->n_tile_threads = n_tile_threads;
826
221k
    rf->n_frame_threads = n_frame_threads;
827
828
221k
    if (n_blocks != rf->n_blocks) {
829
75.3k
        const size_t r_sz = sizeof(*rf->r) * 35 * 2 * n_blocks * (1 + (n_frame_threads > 1));
830
75.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
75.3k
        dav1d_free_aligned(rf->r);
834
75.3k
        rf->r = dav1d_alloc_aligned(ALLOC_REFMVS, r_sz + rp_proj_sz, 64);
835
75.3k
        if (!rf->r) {
836
0
            rf->n_blocks = 0;
837
0
            return DAV1D_ERR(ENOMEM);
838
0
        }
839
840
75.3k
        rf->rp_proj = (refmvs_temporal_block*)((uintptr_t)rf->r + r_sz);
841
75.3k
        rf->n_blocks = n_blocks;
842
75.3k
    }
843
844
221k
    const int poc = frm_hdr->frame_offset;
845
1.76M
    for (int i = 0; i < 7; i++) {
846
1.54M
        const int poc_diff = get_poc_diff(seq_hdr->order_hint_n_bits,
847
1.54M
                                          ref_poc[i], poc);
848
1.54M
        rf->sign_bias[i] = poc_diff > 0;
849
1.54M
        rf->mfmv_sign[i] = poc_diff < 0;
850
1.54M
        rf->pocdiff[i] = iclip(get_poc_diff(seq_hdr->order_hint_n_bits,
851
1.54M
                                            poc, ref_poc[i]), -31, 31);
852
1.54M
    }
853
854
    // temporal MV setup
855
221k
    rf->n_mfmvs = 0;
856
221k
    rf->rp_ref = rp_ref;
857
221k
    if (frm_hdr->use_ref_frame_mvs && seq_hdr->order_hint_n_bits) {
858
39.6k
        int total = 2;
859
39.6k
        if (rp_ref[0] && ref_ref_poc[0][6] != ref_poc[3] /* alt-of-last != gold */) {
860
12.1k
            rf->mfmv_ref[rf->n_mfmvs++] = 0; // last
861
12.1k
            total = 3;
862
12.1k
        }
863
39.6k
        if (rp_ref[4] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[4],
864
29.6k
                                      frm_hdr->frame_offset) > 0)
865
2.20k
        {
866
2.20k
            rf->mfmv_ref[rf->n_mfmvs++] = 4; // bwd
867
2.20k
        }
868
39.6k
        if (rp_ref[5] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[5],
869
30.5k
                                      frm_hdr->frame_offset) > 0)
870
1.15k
        {
871
1.15k
            rf->mfmv_ref[rf->n_mfmvs++] = 5; // altref2
872
1.15k
        }
873
39.6k
        if (rf->n_mfmvs < total && rp_ref[6] &&
874
20.9k
            get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[6],
875
20.9k
                         frm_hdr->frame_offset) > 0)
876
6.75k
        {
877
6.75k
            rf->mfmv_ref[rf->n_mfmvs++] = 6; // altref
878
6.75k
        }
879
39.6k
        if (rf->n_mfmvs < total && rp_ref[1])
880
25.7k
            rf->mfmv_ref[rf->n_mfmvs++] = 1; // last2
881
882
87.7k
        for (int n = 0; n < rf->n_mfmvs; n++) {
883
48.0k
            const int rpoc = ref_poc[rf->mfmv_ref[n]];
884
48.0k
            const int diff1 = get_poc_diff(seq_hdr->order_hint_n_bits,
885
48.0k
                                           rpoc, frm_hdr->frame_offset);
886
48.0k
            if (abs(diff1) > 31) {
887
9.83k
                rf->mfmv_ref2cur[n] = INVALID_REF2CUR;
888
38.2k
            } else {
889
38.2k
                rf->mfmv_ref2cur[n] = rf->mfmv_ref[n] < 4 ? -diff1 : diff1;
890
305k
                for (int m = 0; m < 7; m++) {
891
267k
                    const int rrpoc = ref_ref_poc[rf->mfmv_ref[n]][m];
892
267k
                    const int diff2 = get_poc_diff(seq_hdr->order_hint_n_bits,
893
267k
                                                   rpoc, rrpoc);
894
                    // unsigned comparison also catches the < 0 case
895
267k
                    rf->mfmv_ref2ref[n][m] = (unsigned) diff2 > 31U ? 0 : diff2;
896
267k
                }
897
38.2k
            }
898
48.0k
        }
899
39.6k
    }
900
221k
    rf->use_ref_frame_mvs = rf->n_mfmvs > 0;
901
902
221k
    return 0;
903
221k
}
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.47M
{
908
13.9M
    do {
909
13.9M
        refmvs_block *const r = *rr++ + bx4;
910
134M
        for (int x = 0; x < bw4; x++)
911
120M
            r[x] = *rmv;
912
13.9M
    } while (--bh4);
913
3.47M
}
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
94.8k
{
927
94.8k
    c->load_tmvs = load_tmvs_c;
928
94.8k
    c->save_tmvs = save_tmvs_c;
929
94.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
94.8k
}