Coverage Report

Created: 2026-08-31 06:20

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.28M
{
47
4.28M
    if (b->mv.mv[0].n == INVALID_MV) return; // intra block, no intrabc
48
49
3.09M
    if (ref.ref[1] == -1) {
50
3.33M
        for (int n = 0; n < 2; n++) {
51
3.12M
            if (b->ref.ref[n] == ref.ref[0]) {
52
2.66M
                const mv cand_mv = ((b->mf & 1) && gmv[0].n != INVALID_MV) ?
53
2.61M
                                   gmv[0] : b->mv.mv[n];
54
55
2.66M
                *have_refmv_match = 1;
56
2.66M
                *have_newmv_match |= b->mf >> 1;
57
58
2.66M
                const int last = *cnt;
59
5.75M
                for (int m = 0; m < last; m++)
60
3.80M
                    if (mvstack[m].mv.mv[0].n == cand_mv.n) {
61
707k
                        mvstack[m].weight += weight;
62
707k
                        return;
63
707k
                    }
64
65
1.95M
                if (last < 8) {
66
1.94M
                    mvstack[last].mv.mv[0] = cand_mv;
67
1.94M
                    mvstack[last].weight = weight;
68
1.94M
                    *cnt = last + 1;
69
1.94M
                }
70
1.95M
                return;
71
2.66M
            }
72
3.12M
        }
73
2.87M
    } else if (b->ref.pair == ref.pair) {
74
73.1k
        const refmvs_mvpair cand_mv = { .mv = {
75
73.1k
            [0] = ((b->mf & 1) && gmv[0].n != INVALID_MV) ? gmv[0] : b->mv.mv[0],
76
73.1k
            [1] = ((b->mf & 1) && gmv[1].n != INVALID_MV) ? gmv[1] : b->mv.mv[1],
77
73.1k
        }};
78
79
73.1k
        *have_refmv_match = 1;
80
73.1k
        *have_newmv_match |= b->mf >> 1;
81
82
73.1k
        const int last = *cnt;
83
109k
        for (int n = 0; n < last; n++)
84
63.0k
            if (mvstack[n].mv.n == cand_mv.n) {
85
27.0k
                mvstack[n].weight += weight;
86
27.0k
                return;
87
27.0k
            }
88
89
46.1k
        if (last < 8) {
90
46.0k
            mvstack[last].mv = cand_mv;
91
46.0k
            mvstack[last].weight = weight;
92
46.0k
            *cnt = last + 1;
93
46.0k
        }
94
46.1k
    }
95
3.09M
}
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.32M
{
103
1.32M
    const refmvs_block *cand_b = b;
104
1.32M
    const enum BlockSize first_cand_bs = cand_b->bs;
105
1.32M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
106
1.32M
    int cand_bw4 = first_cand_b_dim[0];
107
1.32M
    int len = imax(step, imin(bw4, cand_bw4));
108
109
1.32M
    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.13M
        const int weight = bw4 == 1 ? 2 :
115
1.13M
                           imax(2, imin(2 * max_rows, first_cand_b_dim[1]));
116
1.13M
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
117
1.13M
                              have_newmv_match, have_refmv_match);
118
1.13M
        return weight >> 1;
119
1.13M
    }
120
121
397k
    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
397k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
126
397k
                              have_newmv_match, have_refmv_match);
127
397k
        x += len;
128
397k
        if (x >= w4) return 1;
129
207k
        cand_b = &b[x];
130
207k
        cand_bw4 = dav1d_block_dimensions[cand_b->bs][0];
131
207k
        assert(cand_bw4 < bw4);
132
207k
        len = imax(step, cand_bw4);
133
207k
    }
134
190k
}
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.58M
{
142
1.58M
    const refmvs_block *cand_b = &b[0][bx4];
143
1.58M
    const enum BlockSize first_cand_bs = cand_b->bs;
144
1.58M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
145
1.58M
    int cand_bh4 = first_cand_b_dim[1];
146
1.58M
    int len = imax(step, imin(bh4, cand_bh4));
147
148
1.58M
    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.38M
        const int weight = bh4 == 1 ? 2 :
154
1.38M
                           imax(2, imin(2 * max_cols, first_cand_b_dim[0]));
155
1.38M
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
156
1.38M
                            have_newmv_match, have_refmv_match);
157
1.38M
        return weight >> 1;
158
1.38M
    }
159
160
406k
    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
406k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
165
406k
                              have_newmv_match, have_refmv_match);
166
406k
        y += len;
167
406k
        if (y >= h4) return 1;
168
203k
        cand_b = &b[y][bx4];
169
203k
        cand_bh4 = dav1d_block_dimensions[cand_b->bs][1];
170
203k
        assert(cand_bh4 < bh4);
171
203k
        len = imax(step, cand_bh4);
172
203k
    }
173
203k
}
174
175
31.3k
static inline union mv mv_projection(const union mv mv, const int num, const int den) {
176
31.3k
    static const uint16_t div_mult[32] = {
177
31.3k
           0, 16384, 8192, 5461, 4096, 3276, 2730, 2340,
178
31.3k
        2048,  1820, 1638, 1489, 1365, 1260, 1170, 1092,
179
31.3k
        1024,   963,  910,  862,  819,  780,  744,  712,
180
31.3k
         682,   655,  630,  606,  585,  564,  546,  528
181
31.3k
    };
182
31.3k
    assert(den > 0 && den < 32);
183
31.3k
    assert(num > -32 && num < 32);
184
31.3k
    const int frac = num * div_mult[den];
185
31.3k
    const int y = mv.y * frac, x = mv.x * frac;
186
    // Round and clip according to AV1 spec section 7.9.3
187
31.3k
    return (union mv) { // 0x3fff == (1 << 14) - 1
188
31.3k
        .y = iclip((y + 8192 + (y >> 31)) >> 14, -0x3fff, 0x3fff),
189
31.3k
        .x = iclip((x + 8192 + (x >> 31)) >> 14, -0x3fff, 0x3fff)
190
31.3k
    };
191
31.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
38.1k
{
199
38.1k
    if (rb->mv.n == INVALID_MV) return;
200
201
17.2k
    union mv mv = mv_projection(rb->mv, rf->pocdiff[ref.ref[0] - 1], rb->ref);
202
17.2k
    fix_mv_precision(rf->frm_hdr, &mv);
203
204
17.2k
    const int last = *cnt;
205
17.2k
    if (ref.ref[1] == -1) {
206
11.1k
        if (globalmv_ctx)
207
2.93k
            *globalmv_ctx = (abs(mv.x - gmv[0].x) | abs(mv.y - gmv[0].y)) >= 16;
208
209
20.9k
        for (int n = 0; n < last; n++)
210
18.2k
            if (mvstack[n].mv.mv[0].n == mv.n) {
211
8.45k
                mvstack[n].weight += 2;
212
8.45k
                return;
213
8.45k
            }
214
2.68k
        if (last < 8) {
215
2.68k
            mvstack[last].mv.mv[0] = mv;
216
2.68k
            mvstack[last].weight = 2;
217
2.68k
            *cnt = last + 1;
218
2.68k
        }
219
6.07k
    } else {
220
6.07k
        refmvs_mvpair mvp = { .mv = {
221
6.07k
            [0] = mv,
222
6.07k
            [1] = mv_projection(rb->mv, rf->pocdiff[ref.ref[1] - 1], rb->ref),
223
6.07k
        }};
224
6.07k
        fix_mv_precision(rf->frm_hdr, &mvp.mv[1]);
225
226
9.62k
        for (int n = 0; n < last; n++)
227
8.24k
            if (mvstack[n].mv.n == mvp.n) {
228
4.69k
                mvstack[n].weight += 2;
229
4.69k
                return;
230
4.69k
            }
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
17.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
56.2k
{
246
56.2k
    refmvs_candidate *const diff = &same[2];
247
56.2k
    int *const diff_count = &same_count[2];
248
249
145k
    for (int n = 0; n < 2; n++) {
250
111k
        const int cand_ref = cand_b->ref.ref[n];
251
252
111k
        if (cand_ref <= 0) break;
253
254
89.7k
        mv cand_mv = cand_b->mv.mv[n];
255
89.7k
        if (cand_ref == ref.ref[0]) {
256
30.6k
            if (same_count[0] < 2)
257
29.7k
                same[same_count[0]++].mv.mv[0] = cand_mv;
258
30.6k
            if (diff_count[1] < 2) {
259
26.4k
                if (sign1 ^ sign_bias[cand_ref - 1]) {
260
420
                    cand_mv.y = -cand_mv.y;
261
420
                    cand_mv.x = -cand_mv.x;
262
420
                }
263
26.4k
                diff[diff_count[1]++].mv.mv[1] = cand_mv;
264
26.4k
            }
265
59.0k
        } else if (cand_ref == ref.ref[1]) {
266
32.7k
            if (same_count[1] < 2)
267
32.0k
                same[same_count[1]++].mv.mv[1] = cand_mv;
268
32.7k
            if (diff_count[0] < 2) {
269
26.9k
                if (sign0 ^ sign_bias[cand_ref - 1]) {
270
438
                    cand_mv.y = -cand_mv.y;
271
438
                    cand_mv.x = -cand_mv.x;
272
438
                }
273
26.9k
                diff[diff_count[0]++].mv.mv[0] = cand_mv;
274
26.9k
            }
275
32.7k
        } else {
276
26.3k
            mv i_cand_mv = (union mv) {
277
26.3k
                .x = -cand_mv.x,
278
26.3k
                .y = -cand_mv.y
279
26.3k
            };
280
281
26.3k
            if (diff_count[0] < 2) {
282
20.9k
                diff[diff_count[0]++].mv.mv[0] =
283
20.9k
                    sign0 ^ sign_bias[cand_ref - 1] ?
284
20.7k
                    i_cand_mv : cand_mv;
285
20.9k
            }
286
287
26.3k
            if (diff_count[1] < 2) {
288
20.0k
                diff[diff_count[1]++].mv.mv[1] =
289
20.0k
                    sign1 ^ sign_bias[cand_ref - 1] ?
290
19.8k
                    i_cand_mv : cand_mv;
291
20.0k
            }
292
26.3k
        }
293
89.7k
    }
294
56.2k
}
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
154k
{
300
312k
    for (int n = 0; n < 2; n++) {
301
302k
        const int cand_ref = cand_b->ref.ref[n];
302
303
302k
        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
157k
        mv cand_mv = cand_b->mv.mv[n];
311
157k
        if (sign ^ sign_bias[cand_ref - 1]) {
312
482
            cand_mv.y = -cand_mv.y;
313
482
            cand_mv.x = -cand_mv.x;
314
482
        }
315
316
157k
        int m;
317
157k
        const int last = *cnt;
318
184k
        for (m = 0; m < last; m++)
319
143k
            if (cand_mv.n == mvstack[m].mv.mv[0].n)
320
116k
                break;
321
157k
        if (m == last) {
322
41.1k
            mvstack[m].mv.mv[0] = cand_mv;
323
41.1k
            mvstack[m].weight = 2; // "minimal"
324
41.1k
            *cnt = last + 1;
325
41.1k
        }
326
157k
    }
327
154k
}
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
791k
{
355
791k
    const refmvs_frame *const rf = rt->rf;
356
791k
    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
357
791k
    const int bw4 = b_dim[0], w4 = imin(imin(bw4, 16), rt->tile_col.end - bx4);
358
791k
    const int bh4 = b_dim[1], h4 = imin(imin(bh4, 16), rt->tile_row.end - by4);
359
791k
    mv gmv[2], tgmv[2];
360
361
791k
    *cnt = 0;
362
791k
    assert(ref.ref[0] >=  0 && ref.ref[0] <= 8 &&
363
791k
           ref.ref[1] >= -1 && ref.ref[1] <= 8);
364
791k
    if (ref.ref[0] > 0) {
365
215k
        tgmv[0] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[0] - 1],
366
215k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
367
215k
        gmv[0] = rf->frm_hdr->gmv[ref.ref[0] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
368
149k
                 tgmv[0] : (mv) { .n = INVALID_MV };
369
576k
    } else {
370
576k
        tgmv[0] = (mv) { .n = 0 };
371
576k
        gmv[0] = (mv) { .n = INVALID_MV };
372
576k
    }
373
791k
    if (ref.ref[1] > 0) {
374
46.4k
        tgmv[1] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[1] - 1],
375
46.4k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
376
46.4k
        gmv[1] = rf->frm_hdr->gmv[ref.ref[1] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
377
32.0k
                 tgmv[1] : (mv) { .n = INVALID_MV };
378
46.4k
    }
379
380
    // top
381
791k
    int have_newmv = 0, have_col_mvs = 0, have_row_mvs = 0;
382
791k
    unsigned max_rows = 0, n_rows = ~0;
383
791k
    const refmvs_block *b_top;
384
791k
    if (by4 > rt->tile_row.start) {
385
655k
        max_rows = imin((by4 - rt->tile_row.start + 1) >> 1, 2 + (bh4 > 1));
386
655k
        b_top = &rt->r[(by4 & 31) - 1 + 5][bx4];
387
655k
        n_rows = scan_row(mvstack, cnt, ref, gmv, b_top,
388
655k
                          bw4, w4, max_rows, bw4 >= 16 ? 4 : 1,
389
655k
                          &have_newmv, &have_row_mvs);
390
655k
    }
391
392
    // left
393
791k
    unsigned max_cols = 0, n_cols = ~0U;
394
791k
    refmvs_block *const *b_left;
395
791k
    if (bx4 > rt->tile_col.start) {
396
735k
        max_cols = imin((bx4 - rt->tile_col.start + 1) >> 1, 2 + (bw4 > 1));
397
735k
        b_left = &rt->r[(by4 & 31) + 5];
398
735k
        n_cols = scan_col(mvstack, cnt, ref, gmv, b_left,
399
735k
                          bh4, h4, bx4 - 1, max_cols, bh4 >= 16 ? 4 : 1,
400
735k
                          &have_newmv, &have_col_mvs);
401
735k
    }
402
403
    // top/right
404
791k
    if (n_rows != ~0U && edge_flags & EDGE_I444_TOP_HAS_RIGHT &&
405
382k
        imax(bw4, bh4) <= 16 && bw4 + bx4 < rt->tile_col.end)
406
348k
    {
407
348k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[bw4], ref, gmv,
408
348k
                              &have_newmv, &have_row_mvs);
409
348k
    }
410
411
791k
    const int nearest_match = have_col_mvs + have_row_mvs;
412
791k
    const int nearest_cnt = *cnt;
413
1.88M
    for (int n = 0; n < nearest_cnt; n++)
414
1.09M
        mvstack[n].weight += 640;
415
416
    // temporal
417
791k
    int globalmv_ctx = rf->frm_hdr->use_ref_frame_mvs;
418
791k
    if (rf->use_ref_frame_mvs) {
419
10.3k
        const ptrdiff_t stride = rf->rp_stride;
420
10.3k
        const int by8 = by4 >> 1, bx8 = bx4 >> 1;
421
10.3k
        const refmvs_temporal_block *const rbi = &rt->rp_proj[(by8 & 15) * stride + bx8];
422
10.3k
        const refmvs_temporal_block *rb = rbi;
423
10.3k
        const int step_h = bw4 >= 16 ? 2 : 1, step_v = bh4 >= 16 ? 2 : 1;
424
10.3k
        const int w8 = imin((w4 + 1) >> 1, 8), h8 = imin((h4 + 1) >> 1, 8);
425
29.1k
        for (int y = 0; y < h8; y += step_v) {
426
50.3k
            for (int x = 0; x < w8; x+= step_h) {
427
31.5k
                add_temporal_candidate(rf, mvstack, cnt, &rb[x], ref,
428
31.5k
                                       !(x | y) ? &globalmv_ctx : NULL, tgmv);
429
31.5k
            }
430
18.8k
            rb += stride * step_v;
431
18.8k
        }
432
10.3k
        if (imin(bw4, bh4) >= 2 && imax(bw4, bh4) < 16) {
433
6.31k
            const int bh8 = bh4 >> 1, bw8 = bw4 >> 1;
434
6.31k
            rb = &rbi[bh8 * stride];
435
6.31k
            const int has_bottom = by8 + bh8 < imin(rt->tile_row.end >> 1,
436
6.31k
                                                    (by8 & ~7) + 8);
437
6.31k
            if (has_bottom && bx8 - 1 >= imax(rt->tile_col.start >> 1, bx8 & ~7)) {
438
2.00k
                add_temporal_candidate(rf, mvstack, cnt, &rb[-1], ref,
439
2.00k
                                       NULL, NULL);
440
2.00k
            }
441
6.31k
            if (bx8 + bw8 < imin(rt->tile_col.end >> 1, (bx8 & ~7) + 8)) {
442
2.81k
                if (has_bottom) {
443
1.89k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8], ref,
444
1.89k
                                           NULL, NULL);
445
1.89k
                }
446
2.81k
                if (by8 + bh8 - 1 < imin(rt->tile_row.end >> 1, (by8 & ~7) + 8)) {
447
2.70k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8 - stride],
448
2.70k
                                           ref, NULL, NULL);
449
2.70k
                }
450
2.81k
            }
451
6.31k
        }
452
10.3k
    }
453
791k
    assert(*cnt <= 8);
454
455
    // top/left (which, confusingly, is part of "secondary" references)
456
791k
    int have_dummy_newmv_match;
457
791k
    if ((n_rows | n_cols) != ~0U) {
458
615k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[-1], ref, gmv,
459
615k
                              &have_dummy_newmv_match, &have_row_mvs);
460
615k
    }
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.37M
    for (int n = 2; n <= 3; n++) {
465
1.58M
        if ((unsigned) n > n_rows && (unsigned) n <= max_rows) {
466
673k
            n_rows += scan_row(mvstack, cnt, ref, gmv,
467
673k
                               &rt->r[(((by4 & 31) - 2 * n + 1) | 1) + 5][bx4 | 1],
468
673k
                               bw4, w4, 1 + max_rows - n, bw4 >= 16 ? 4 : 2,
469
673k
                               &have_dummy_newmv_match, &have_row_mvs);
470
673k
        }
471
472
1.58M
        if ((unsigned) n > n_cols && (unsigned) n <= max_cols) {
473
852k
            n_cols += scan_col(mvstack, cnt, ref, gmv, &rt->r[((by4 & 31) | 1) + 5],
474
852k
                               bh4, h4, (bx4 - n * 2 + 1) | 1,
475
852k
                               1 + max_cols - n, bh4 >= 16 ? 4 : 2,
476
852k
                               &have_dummy_newmv_match, &have_col_mvs);
477
852k
        }
478
1.58M
    }
479
791k
    assert(*cnt <= 8);
480
481
791k
    const int ref_match_count = have_col_mvs + have_row_mvs;
482
483
    // context build-up
484
791k
    int refmv_ctx, newmv_ctx;
485
791k
    switch (nearest_match) {
486
134k
    case 0:
487
134k
        refmv_ctx = imin(2, ref_match_count);
488
134k
        newmv_ctx = ref_match_count > 0;
489
134k
        break;
490
324k
    case 1:
491
324k
        refmv_ctx = imin(ref_match_count * 3, 4);
492
324k
        newmv_ctx = 3 - have_newmv;
493
324k
        break;
494
333k
    case 2:
495
333k
        refmv_ctx = 5;
496
333k
        newmv_ctx = 5 - have_newmv;
497
333k
        break;
498
791k
    }
499
500
    // sorting (nearest, then "secondary")
501
792k
    int len = nearest_cnt;
502
1.63M
    while (len) {
503
838k
        int last = 0;
504
1.36M
        for (int n = 1; n < len; n++) {
505
522k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
506
299k
#define EXCHANGE(a, b) do { refmvs_candidate tmp = a; a = b; b = tmp; } while (0)
507
202k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
508
202k
                last = n;
509
202k
            }
510
522k
        }
511
838k
        len = last;
512
838k
    }
513
792k
    len = *cnt;
514
1.39M
    while (len > nearest_cnt) {
515
598k
        int last = nearest_cnt;
516
1.03M
        for (int n = nearest_cnt + 1; n < len; n++) {
517
434k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
518
97.8k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
519
97.8k
#undef EXCHANGE
520
97.8k
                last = n;
521
97.8k
            }
522
434k
        }
523
598k
        len = last;
524
598k
    }
525
526
792k
    if (ref.ref[1] > 0) {
527
46.4k
        if (*cnt < 2) {
528
34.6k
            const int sign0 = rf->sign_bias[ref.ref[0] - 1];
529
34.6k
            const int sign1 = rf->sign_bias[ref.ref[1] - 1];
530
34.6k
            const int sz4 = imin(w4, h4);
531
34.6k
            refmvs_candidate *const same = &mvstack[*cnt];
532
34.6k
            int same_count[4] = { 0 };
533
534
            // non-self references in top
535
55.3k
            if (n_rows != ~0U) for (int x = 0; x < sz4;) {
536
28.9k
                const refmvs_block *const cand_b = &b_top[x];
537
28.9k
                add_compound_extended_candidate(same, same_count, cand_b,
538
28.9k
                                                sign0, sign1, ref, rf->sign_bias);
539
28.9k
                x += dav1d_block_dimensions[cand_b->bs][0];
540
28.9k
            }
541
542
            // non-self references in left
543
52.2k
            if (n_cols != ~0U) for (int y = 0; y < sz4;) {
544
27.3k
                const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
545
27.3k
                add_compound_extended_candidate(same, same_count, cand_b,
546
27.3k
                                                sign0, sign1, ref, rf->sign_bias);
547
27.3k
                y += dav1d_block_dimensions[cand_b->bs][1];
548
27.3k
            }
549
550
34.6k
            refmvs_candidate *const diff = &same[2];
551
34.6k
            const int *const diff_count = &same_count[2];
552
553
            // merge together
554
103k
            for (int n = 0; n < 2; n++) {
555
69.2k
                int m = same_count[n];
556
557
69.2k
                if (m >= 2) continue;
558
559
53.7k
                const int l = diff_count[n];
560
53.7k
                if (l) {
561
43.5k
                    same[m].mv.mv[n] = diff[0].mv.mv[n];
562
43.5k
                    if (++m == 2) continue;
563
15.5k
                    if (l == 2) {
564
11.7k
                        same[1].mv.mv[n] = diff[1].mv.mv[n];
565
11.7k
                        continue;
566
11.7k
                    }
567
15.5k
                }
568
21.4k
                do {
569
21.4k
                    same[m].mv.mv[n] = tgmv[n];
570
21.4k
                } while (++m < 2);
571
13.9k
            }
572
573
            // if the first extended was the same as the non-extended one,
574
            // then replace it with the second extended one
575
34.6k
            int n = *cnt;
576
34.6k
            if (n == 1 && mvstack[0].mv.n == same[0].mv.n)
577
12.1k
                mvstack[1].mv = mvstack[2].mv;
578
52.8k
            do {
579
52.8k
                mvstack[n].weight = 2;
580
52.8k
            } while (++n < 2);
581
34.6k
            *cnt = 2;
582
34.6k
        }
583
584
        // clamping
585
46.4k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
586
46.4k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
587
46.4k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
588
46.4k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
589
590
46.4k
        const int n_refmvs = *cnt;
591
46.4k
        int n = 0;
592
100k
        do {
593
100k
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
594
100k
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
595
100k
            mvstack[n].mv.mv[1].x = iclip(mvstack[n].mv.mv[1].x, left, right);
596
100k
            mvstack[n].mv.mv[1].y = iclip(mvstack[n].mv.mv[1].y, top, bottom);
597
100k
        } while (++n < n_refmvs);
598
599
46.4k
        switch (refmv_ctx >> 1) {
600
20.3k
        case 0:
601
20.3k
            *ctx = imin(newmv_ctx, 1);
602
20.3k
            break;
603
16.6k
        case 1:
604
16.6k
            *ctx = 1 + imin(newmv_ctx, 3);
605
16.6k
            break;
606
9.47k
        case 2:
607
9.47k
            *ctx = iclip(3 + newmv_ctx, 4, 7);
608
9.47k
            break;
609
46.4k
        }
610
611
46.4k
        return;
612
745k
    } else if (*cnt < 2 && ref.ref[0] > 0) {
613
111k
        const int sign = rf->sign_bias[ref.ref[0] - 1];
614
111k
        const int sz4 = imin(w4, h4);
615
616
        // non-self references in top
617
164k
        if (n_rows != ~0U) for (int x = 0; x < sz4 && *cnt < 2;) {
618
84.2k
            const refmvs_block *const cand_b = &b_top[x];
619
84.2k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
620
84.2k
            x += dav1d_block_dimensions[cand_b->bs][0];
621
84.2k
        }
622
623
        // non-self references in left
624
148k
        if (n_cols != ~0U) for (int y = 0; y < sz4 && *cnt < 2;) {
625
70.2k
            const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
626
70.2k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
627
70.2k
            y += dav1d_block_dimensions[cand_b->bs][1];
628
70.2k
        }
629
111k
    }
630
745k
    assert(*cnt <= 8);
631
632
    // clamping
633
745k
    int n_refmvs = *cnt;
634
745k
    if (n_refmvs) {
635
694k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
636
694k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
637
694k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
638
694k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
639
640
694k
        int n = 0;
641
1.99M
        do {
642
1.99M
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
643
1.99M
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
644
1.99M
        } while (++n < n_refmvs);
645
694k
    }
646
647
991k
    for (int n = *cnt; n < 2; n++)
648
245k
        mvstack[n].mv.mv[0] = tgmv[0];
649
650
745k
    *ctx = (refmv_ctx << 4) | (globalmv_ctx << 3) | newmv_ctx;
651
745k
}
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
80.5k
{
658
80.5k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
659
80.5k
    rt->rp_proj = &rf->rp_proj[16 * rf->rp_stride * tile_row_idx];
660
80.5k
    const ptrdiff_t r_stride = rf->rp_stride * 2;
661
80.5k
    const ptrdiff_t pass_off = (rf->n_frame_threads > 1 && pass == 2) ?
662
45.6k
        35 * 2 * rf->n_blocks : 0;
663
80.5k
    refmvs_block *r = &rf->r[35 * r_stride * tile_row_idx + pass_off];
664
80.5k
    const int sbsz = rf->sbsz;
665
80.5k
    const int off = (sbsz * sby) & 16;
666
1.83M
    for (int i = 0; i < sbsz; i++, r += r_stride)
667
1.75M
        rt->r[off + 5 + i] = r;
668
80.5k
    rt->r[off + 0] = r;
669
80.5k
    r += r_stride;
670
80.5k
    rt->r[off + 1] = NULL;
671
80.5k
    rt->r[off + 2] = r;
672
80.5k
    r += r_stride;
673
80.5k
    rt->r[off + 3] = NULL;
674
80.5k
    rt->r[off + 4] = r;
675
80.5k
    if (sby & 1) {
676
74.6k
#define EXCHANGE(a, b) do { void *const tmp = a; a = b; b = tmp; } while (0)
677
24.8k
        EXCHANGE(rt->r[off + 0], rt->r[off + sbsz + 0]);
678
24.8k
        EXCHANGE(rt->r[off + 2], rt->r[off + sbsz + 2]);
679
24.8k
        EXCHANGE(rt->r[off + 4], rt->r[off + sbsz + 4]);
680
24.8k
#undef EXCHANGE
681
24.8k
    }
682
683
80.5k
    rt->rf = rf;
684
80.5k
    rt->tile_row.start = tile_row_start4;
685
80.5k
    rt->tile_row.end = imin(tile_row_end4, rf->ih4);
686
80.5k
    rt->tile_col.start = tile_col_start4;
687
80.5k
    rt->tile_col.end = imin(tile_col_end4, rf->iw4);
688
80.5k
}
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.49k
{
694
4.49k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
695
4.49k
    assert(row_start8 >= 0);
696
4.49k
    assert((unsigned) (row_end8 - row_start8) <= 16U);
697
4.49k
    row_end8 = imin(row_end8, rf->ih8);
698
4.49k
    const int col_start8i = imax(col_start8 - 8, 0);
699
4.49k
    const int col_end8i = imin(col_end8 + 8, rf->iw8);
700
701
4.49k
    const ptrdiff_t stride = rf->rp_stride;
702
4.49k
    refmvs_temporal_block *rp_proj =
703
4.49k
        &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
106k
        for (int x = col_start8; x < col_end8; x++)
706
85.4k
            rp_proj[x].mv.n = INVALID_MV;
707
21.2k
        rp_proj += stride;
708
21.2k
    }
709
710
4.49k
    rp_proj = &rf->rp_proj[16 * stride * tile_row_idx];
711
8.41k
    for (int n = 0; n < rf->n_mfmvs; n++) {
712
3.92k
        const int ref2cur = rf->mfmv_ref2cur[n];
713
3.92k
        if (ref2cur == INVALID_REF2CUR) continue;
714
715
3.36k
        const int ref = rf->mfmv_ref[n];
716
3.36k
        const int ref_sign = ref - 4;
717
3.36k
        const refmvs_temporal_block *r = &rf->rp_ref[ref][row_start8 * stride];
718
18.3k
        for (int y = row_start8; y < row_end8; y++) {
719
15.0k
            const int y_sb_align = y & ~7;
720
15.0k
            const int y_proj_start = imax(y_sb_align, row_start8);
721
15.0k
            const int y_proj_end = imin(y_sb_align + 8, row_end8);
722
64.3k
            for (int x = col_start8i; x < col_end8i; x++) {
723
49.3k
                const refmvs_temporal_block *rb = &r[x];
724
49.3k
                const int b_ref = rb->ref;
725
49.3k
                if (!b_ref) continue;
726
26.5k
                const int ref2ref = rf->mfmv_ref2ref[n][b_ref - 1];
727
26.5k
                if (!ref2ref) continue;
728
8.08k
                const mv b_mv = rb->mv;
729
8.08k
                const mv offset = mv_projection(b_mv, ref2cur, ref2ref);
730
8.08k
                int pos_x = x + apply_sign(abs(offset.x) >> 6,
731
8.08k
                                           offset.x ^ ref_sign);
732
8.08k
                const int pos_y = y + apply_sign(abs(offset.y) >> 6,
733
8.08k
                                                 offset.y ^ ref_sign);
734
8.08k
                if (pos_y >= y_proj_start && pos_y < y_proj_end) {
735
7.26k
                    const ptrdiff_t pos = (pos_y & 15) * stride;
736
24.8k
                    for (;;) {
737
24.8k
                        const int x_sb_align = x & ~7;
738
24.8k
                        if (pos_x >= imax(x_sb_align - 8, col_start8) &&
739
24.6k
                            pos_x < imin(x_sb_align + 16, col_end8))
740
24.5k
                        {
741
24.5k
                            rp_proj[pos + pos_x].mv = rb->mv;
742
24.5k
                            rp_proj[pos + pos_x].ref = ref2ref;
743
24.5k
                        }
744
24.8k
                        if (++x >= col_end8i) break;
745
20.9k
                        rb++;
746
20.9k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
747
17.5k
                        pos_x++;
748
17.5k
                    }
749
7.26k
                } else {
750
2.10k
                    for (;;) {
751
2.10k
                        if (++x >= col_end8i) break;
752
1.80k
                        rb++;
753
1.80k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
754
1.80k
                    }
755
820
                }
756
8.08k
                x--;
757
8.08k
            }
758
15.0k
            r += stride;
759
15.0k
        }
760
3.36k
    }
761
4.49k
}
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
10.9k
{
769
69.9k
    for (int y = row_start8; y < row_end8; y++) {
770
59.0k
        const refmvs_block *const b = rr[(y & 15) * 2];
771
772
149k
        for (int x = col_start8; x < col_end8;) {
773
90.8k
            const refmvs_block *const cand_b = &b[x * 2 + 1];
774
90.8k
            const int bw8 = (dav1d_block_dimensions[cand_b->bs][0] + 1) >> 1;
775
776
90.8k
            if (cand_b->ref.ref[1] > 0 && ref_sign[cand_b->ref.ref[1] - 1] &&
777
13.4k
                (abs(cand_b->mv.mv[1].y) | abs(cand_b->mv.mv[1].x)) < 4096)
778
11.6k
            {
779
11.6k
                const refmvs_temporal_block tmv = {
780
11.6k
                    .mv = cand_b->mv.mv[1],
781
11.6k
                    .ref = cand_b->ref.ref[1],
782
11.6k
                };
783
39.7k
                for (int n = 0; n < bw8; n++, x++)
784
28.0k
                    rp[x] = tmv;
785
79.1k
            } else if (cand_b->ref.ref[0] > 0 && ref_sign[cand_b->ref.ref[0] - 1] &&
786
28.1k
                       (abs(cand_b->mv.mv[0].y) | abs(cand_b->mv.mv[0].x)) < 4096)
787
26.1k
            {
788
26.1k
                const refmvs_temporal_block tmv = {
789
26.1k
                    .mv = cand_b->mv.mv[0],
790
26.1k
                    .ref = cand_b->ref.ref[0],
791
26.1k
                };
792
117k
                for (int n = 0; n < bw8; n++, x++)
793
91.7k
                    rp[x] = tmv;
794
53.0k
            } else {
795
53.0k
                const refmvs_temporal_block tmv = { .mv = { .n = 0 }, .ref = 0 };
796
228k
                for (int n = 0; n < bw8; n++, x++)
797
175k
                    rp[x] = tmv;
798
53.0k
            }
799
90.8k
        }
800
59.0k
        rp += stride;
801
59.0k
    }
802
10.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
23.5k
{
813
23.5k
    const int rp_stride = ((frm_hdr->width[0] + 127) & ~127) >> 3;
814
23.5k
    const int n_tile_rows = n_tile_threads > 1 ? frm_hdr->tiling.rows : 1;
815
23.5k
    const int n_blocks = rp_stride * n_tile_rows;
816
817
23.5k
    rf->sbsz = 16 << seq_hdr->sb128;
818
23.5k
    rf->frm_hdr = frm_hdr;
819
23.5k
    rf->iw8 = (frm_hdr->width[0] + 7) >> 3;
820
23.5k
    rf->ih8 = (frm_hdr->height + 7) >> 3;
821
23.5k
    rf->iw4 = rf->iw8 << 1;
822
23.5k
    rf->ih4 = rf->ih8 << 1;
823
23.5k
    rf->rp = rp;
824
23.5k
    rf->rp_stride = rp_stride;
825
23.5k
    rf->n_tile_threads = n_tile_threads;
826
23.5k
    rf->n_frame_threads = n_frame_threads;
827
828
23.5k
    if (n_blocks != rf->n_blocks) {
829
19.6k
        const size_t r_sz = sizeof(*rf->r) * 35 * 2 * n_blocks * (1 + (n_frame_threads > 1));
830
19.6k
        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
19.6k
        dav1d_free_aligned(rf->r);
834
19.6k
        rf->r = dav1d_alloc_aligned(ALLOC_REFMVS, r_sz + rp_proj_sz, 64);
835
19.6k
        if (!rf->r) {
836
0
            rf->n_blocks = 0;
837
0
            return DAV1D_ERR(ENOMEM);
838
0
        }
839
840
19.6k
        rf->rp_proj = (refmvs_temporal_block*)((uintptr_t)rf->r + r_sz);
841
19.6k
        rf->n_blocks = n_blocks;
842
19.6k
    }
843
844
23.5k
    const int poc = frm_hdr->frame_offset;
845
188k
    for (int i = 0; i < 7; i++) {
846
164k
        const int poc_diff = get_poc_diff(seq_hdr->order_hint_n_bits,
847
164k
                                          ref_poc[i], poc);
848
164k
        rf->sign_bias[i] = poc_diff > 0;
849
164k
        rf->mfmv_sign[i] = poc_diff < 0;
850
164k
        rf->pocdiff[i] = iclip(get_poc_diff(seq_hdr->order_hint_n_bits,
851
164k
                                            poc, ref_poc[i]), -31, 31);
852
164k
    }
853
854
    // temporal MV setup
855
23.5k
    rf->n_mfmvs = 0;
856
23.5k
    rf->rp_ref = rp_ref;
857
23.5k
    if (frm_hdr->use_ref_frame_mvs && seq_hdr->order_hint_n_bits) {
858
4.23k
        int total = 2;
859
4.23k
        if (rp_ref[0] && ref_ref_poc[0][6] != ref_poc[3] /* alt-of-last != gold */) {
860
563
            rf->mfmv_ref[rf->n_mfmvs++] = 0; // last
861
563
            total = 3;
862
563
        }
863
4.23k
        if (rp_ref[4] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[4],
864
2.63k
                                      frm_hdr->frame_offset) > 0)
865
454
        {
866
454
            rf->mfmv_ref[rf->n_mfmvs++] = 4; // bwd
867
454
        }
868
4.23k
        if (rp_ref[5] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[5],
869
1.73k
                                      frm_hdr->frame_offset) > 0)
870
287
        {
871
287
            rf->mfmv_ref[rf->n_mfmvs++] = 5; // altref2
872
287
        }
873
4.23k
        if (rf->n_mfmvs < total && rp_ref[6] &&
874
2.30k
            get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[6],
875
2.30k
                         frm_hdr->frame_offset) > 0)
876
1.01k
        {
877
1.01k
            rf->mfmv_ref[rf->n_mfmvs++] = 6; // altref
878
1.01k
        }
879
4.23k
        if (rf->n_mfmvs < total && rp_ref[1])
880
1.50k
            rf->mfmv_ref[rf->n_mfmvs++] = 1; // last2
881
882
8.05k
        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
620
                rf->mfmv_ref2cur[n] = INVALID_REF2CUR;
888
3.20k
            } else {
889
3.20k
                rf->mfmv_ref2cur[n] = rf->mfmv_ref[n] < 4 ? -diff1 : diff1;
890
25.6k
                for (int m = 0; m < 7; m++) {
891
22.4k
                    const int rrpoc = ref_ref_poc[rf->mfmv_ref[n]][m];
892
22.4k
                    const int diff2 = get_poc_diff(seq_hdr->order_hint_n_bits,
893
22.4k
                                                   rpoc, rrpoc);
894
                    // unsigned comparison also catches the < 0 case
895
22.4k
                    rf->mfmv_ref2ref[n][m] = (unsigned) diff2 > 31U ? 0 : diff2;
896
22.4k
                }
897
3.20k
            }
898
3.82k
        }
899
4.23k
    }
900
23.5k
    rf->use_ref_frame_mvs = rf->n_mfmvs > 0;
901
902
23.5k
    return 0;
903
23.5k
}
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.67M
{
908
6.45M
    do {
909
6.45M
        refmvs_block *const r = *rr++ + bx4;
910
68.7M
        for (int x = 0; x < bw4; x++)
911
62.2M
            r[x] = *rmv;
912
6.45M
    } while (--bh4);
913
1.67M
}
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
32.3k
{
927
32.3k
    c->load_tmvs = load_tmvs_c;
928
32.3k
    c->save_tmvs = save_tmvs_c;
929
32.3k
    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
32.3k
}