Coverage Report

Created: 2026-09-01 06:55

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