Coverage Report

Created: 2026-09-13 06:30

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