Coverage Report

Created: 2026-07-16 06:32

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