Coverage Report

Created: 2026-10-17 06:56

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
#include <string.h>
33
34
#include "dav1d/common.h"
35
36
#include "common/intops.h"
37
38
#include "src/env.h"
39
#include "src/mem.h"
40
#include "src/refmvs.h"
41
42
static void add_spatial_candidate(refmvs_candidate *const mvstack, int *const cnt,
43
                                  const int weight, const refmvs_block *const b,
44
                                  const union refmvs_refpair ref, const mv gmv[2],
45
                                  int *const have_newmv_match,
46
                                  int *const have_refmv_match)
47
10.8M
{
48
10.8M
    if (b->mv.mv[0].n == INVALID_MV) return; // intra block, no intrabc
49
50
9.94M
    if (ref.ref[1] == -1) {
51
12.0M
        for (int n = 0; n < 2; n++) {
52
10.4M
            if (b->ref.ref[n] == ref.ref[0]) {
53
7.14M
                const mv cand_mv = ((b->mf & 1) && gmv[0].n != INVALID_MV) ?
54
6.91M
                                   gmv[0] : b->mv.mv[n];
55
56
7.14M
                *have_refmv_match = 1;
57
7.14M
                *have_newmv_match |= b->mf >> 1;
58
59
7.14M
                const int last = *cnt;
60
12.9M
                for (int m = 0; m < last; m++)
61
8.11M
                    if (mvstack[m].mv.mv[0].n == cand_mv.n) {
62
2.32M
                        mvstack[m].weight += weight;
63
2.32M
                        return;
64
2.32M
                    }
65
66
4.82M
                if (last < 8) {
67
4.82M
                    mvstack[last].mv.mv[0] = cand_mv;
68
4.82M
                    mvstack[last].weight = weight;
69
4.82M
                    *cnt = last + 1;
70
4.82M
                }
71
4.82M
                return;
72
7.14M
            }
73
10.4M
        }
74
8.70M
    } else if (b->ref.pair == ref.pair) {
75
404k
        const refmvs_mvpair cand_mv = { .mv = {
76
404k
            [0] = ((b->mf & 1) && gmv[0].n != INVALID_MV) ? gmv[0] : b->mv.mv[0],
77
404k
            [1] = ((b->mf & 1) && gmv[1].n != INVALID_MV) ? gmv[1] : b->mv.mv[1],
78
404k
        }};
79
80
404k
        *have_refmv_match = 1;
81
404k
        *have_newmv_match |= b->mf >> 1;
82
83
404k
        const int last = *cnt;
84
601k
        for (int n = 0; n < last; n++)
85
345k
            if (mvstack[n].mv.n == cand_mv.n) {
86
148k
                mvstack[n].weight += weight;
87
148k
                return;
88
148k
            }
89
90
255k
        if (last < 8) {
91
255k
            mvstack[last].mv = cand_mv;
92
255k
            mvstack[last].weight = weight;
93
255k
            *cnt = last + 1;
94
255k
        }
95
255k
    }
96
9.94M
}
97
98
static int scan_row(refmvs_candidate *const mvstack, int *const cnt,
99
                    const union refmvs_refpair ref, const mv gmv[2],
100
                    const refmvs_block *b, const int bw4, const int w4,
101
                    const int max_rows, const int step,
102
                    int *const have_newmv_match, int *const have_refmv_match)
103
3.30M
{
104
3.30M
    const refmvs_block *cand_b = b;
105
3.30M
    const enum BlockSize first_cand_bs = cand_b->bs;
106
3.30M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
107
3.30M
    int cand_bw4 = first_cand_b_dim[0];
108
3.30M
    int len = imax(step, imin(bw4, cand_bw4));
109
110
3.30M
    if (bw4 <= cand_bw4) {
111
        // FIXME weight can be higher for odd blocks (bx4 & 1), but then the
112
        // position of the first block has to be odd already, i.e. not just
113
        // for row_offset=-3/-5
114
        // FIXME why can this not be cand_bw4?
115
2.89M
        const int weight = bw4 == 1 ? 2 :
116
2.89M
                           imax(2, imin(2 * max_rows, first_cand_b_dim[1]));
117
2.89M
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
118
2.89M
                              have_newmv_match, have_refmv_match);
119
2.89M
        return weight >> 1;
120
2.89M
    }
121
122
775k
    for (int x = 0;;) {
123
        // FIXME if we overhang above, we could fill a bitmask so we don't have
124
        // to repeat the add_spatial_candidate() for the next row, but just increase
125
        // the weight here
126
775k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
127
775k
                              have_newmv_match, have_refmv_match);
128
775k
        x += len;
129
775k
        if (x >= w4) return 1;
130
366k
        cand_b = &b[x];
131
366k
        cand_bw4 = dav1d_block_dimensions[cand_b->bs][0];
132
366k
        assert(cand_bw4 < bw4);
133
366k
        len = imax(step, cand_bw4);
134
366k
    }
135
409k
}
136
137
static int scan_col(refmvs_candidate *const mvstack, int *const cnt,
138
                    const union refmvs_refpair ref, const mv gmv[2],
139
                    /*const*/ refmvs_block *const *b, const int bh4, const int h4,
140
                    const int bx4, const int max_cols, const int step,
141
                    int *const have_newmv_match, int *const have_refmv_match)
142
4.55M
{
143
4.55M
    const refmvs_block *cand_b = &b[0][bx4];
144
4.55M
    const enum BlockSize first_cand_bs = cand_b->bs;
145
4.55M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
146
4.55M
    int cand_bh4 = first_cand_b_dim[1];
147
4.55M
    int len = imax(step, imin(bh4, cand_bh4));
148
149
4.55M
    if (bh4 <= cand_bh4) {
150
        // FIXME weight can be higher for odd blocks (by4 & 1), but then the
151
        // position of the first block has to be odd already, i.e. not just
152
        // for col_offset=-3/-5
153
        // FIXME why can this not be cand_bh4?
154
4.13M
        const int weight = bh4 == 1 ? 2 :
155
4.13M
                           imax(2, imin(2 * max_cols, first_cand_b_dim[0]));
156
4.13M
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
157
4.13M
                            have_newmv_match, have_refmv_match);
158
4.13M
        return weight >> 1;
159
4.13M
    }
160
161
802k
    for (int y = 0;;) {
162
        // FIXME if we overhang above, we could fill a bitmask so we don't have
163
        // to repeat the add_spatial_candidate() for the next row, but just increase
164
        // the weight here
165
802k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
166
802k
                              have_newmv_match, have_refmv_match);
167
802k
        y += len;
168
802k
        if (y >= h4) return 1;
169
386k
        cand_b = &b[y][bx4];
170
386k
        cand_bh4 = dav1d_block_dimensions[cand_b->bs][1];
171
386k
        assert(cand_bh4 < bh4);
172
386k
        len = imax(step, cand_bh4);
173
386k
    }
174
419k
}
175
176
198k
static inline union mv mv_projection(const union mv mv, const int num, const int den) {
177
198k
    static const uint16_t div_mult[32] = {
178
198k
           0, 16384, 8192, 5461, 4096, 3276, 2730, 2340,
179
198k
        2048,  1820, 1638, 1489, 1365, 1260, 1170, 1092,
180
198k
        1024,   963,  910,  862,  819,  780,  744,  712,
181
198k
         682,   655,  630,  606,  585,  564,  546,  528
182
198k
    };
183
198k
    assert(den > 0 && den < 32);
184
198k
    assert(num > -32 && num < 32);
185
198k
    const int frac = num * div_mult[den];
186
198k
    const int y = mv.y * frac, x = mv.x * frac;
187
    // Round and clip according to AV1 spec section 7.9.3
188
198k
    return (union mv) { // 0x3fff == (1 << 14) - 1
189
198k
        .y = iclip((y + 8192 + (y >> 31)) >> 14, -0x3fff, 0x3fff),
190
198k
        .x = iclip((x + 8192 + (x >> 31)) >> 14, -0x3fff, 0x3fff)
191
198k
    };
192
198k
}
193
194
static void add_temporal_candidate(const refmvs_frame *const rf,
195
                                   refmvs_candidate *const mvstack, int *const cnt,
196
                                   const refmvs_temporal_block *const rb,
197
                                   const union refmvs_refpair ref, int *const globalmv_ctx,
198
                                   const union mv gmv[], const int weight)
199
152k
{
200
152k
    if (rb->mv.n == INVALID_MV) return;
201
202
68.1k
    union mv mv = mv_projection(rb->mv, rf->pocdiff[ref.ref[0] - 1], rb->ref);
203
68.1k
    fix_mv_precision(rf->frm_hdr, &mv);
204
205
68.1k
    const int last = *cnt;
206
68.1k
    if (ref.ref[1] == -1) {
207
42.0k
        if (globalmv_ctx)
208
23.5k
            *globalmv_ctx = (abs(mv.x - gmv[0].x) | abs(mv.y - gmv[0].y)) >= 16;
209
210
70.3k
        for (int n = 0; n < last; n++)
211
52.0k
            if (mvstack[n].mv.mv[0].n == mv.n) {
212
23.7k
                mvstack[n].weight += weight;
213
23.7k
                return;
214
23.7k
            }
215
18.2k
        if (last < 8) {
216
18.1k
            mvstack[last].mv.mv[0] = mv;
217
18.1k
            mvstack[last].weight = weight;
218
18.1k
            *cnt = last + 1;
219
18.1k
        }
220
26.1k
    } else {
221
26.1k
        refmvs_mvpair mvp = { .mv = {
222
26.1k
            [0] = mv,
223
26.1k
            [1] = mv_projection(rb->mv, rf->pocdiff[ref.ref[1] - 1], rb->ref),
224
26.1k
        }};
225
26.1k
        fix_mv_precision(rf->frm_hdr, &mvp.mv[1]);
226
227
40.4k
        for (int n = 0; n < last; n++)
228
26.6k
            if (mvstack[n].mv.n == mvp.n) {
229
12.3k
                mvstack[n].weight += weight;
230
12.3k
                return;
231
12.3k
            }
232
13.7k
        if (last < 8) {
233
13.7k
            mvstack[last].mv = mvp;
234
13.7k
            mvstack[last].weight = weight;
235
13.7k
            *cnt = last + 1;
236
13.7k
        }
237
13.7k
    }
238
68.1k
}
239
240
static void add_compound_extended_candidate(refmvs_candidate *const same,
241
                                            int *const same_count,
242
                                            const refmvs_block *const cand_b,
243
                                            const int sign0, const int sign1,
244
                                            const union refmvs_refpair ref,
245
                                            const uint8_t *const sign_bias)
246
323k
{
247
323k
    refmvs_candidate *const diff = &same[2];
248
323k
    int *const diff_count = &same_count[2];
249
250
831k
    for (int n = 0; n < 2; n++) {
251
636k
        const int cand_ref = cand_b->ref.ref[n];
252
253
636k
        if (cand_ref <= 0) break;
254
255
508k
        mv cand_mv = cand_b->mv.mv[n];
256
508k
        if (cand_ref == ref.ref[0]) {
257
183k
            if (same_count[0] < 2)
258
178k
                same[same_count[0]++].mv.mv[0] = cand_mv;
259
183k
            if (diff_count[1] < 2) {
260
158k
                if (sign1 ^ sign_bias[cand_ref - 1]) {
261
7.70k
                    cand_mv.y = -cand_mv.y;
262
7.70k
                    cand_mv.x = -cand_mv.x;
263
7.70k
                }
264
158k
                diff[diff_count[1]++].mv.mv[1] = cand_mv;
265
158k
            }
266
324k
        } else if (cand_ref == ref.ref[1]) {
267
174k
            if (same_count[1] < 2)
268
170k
                same[same_count[1]++].mv.mv[1] = cand_mv;
269
174k
            if (diff_count[0] < 2) {
270
145k
                if (sign0 ^ sign_bias[cand_ref - 1]) {
271
6.34k
                    cand_mv.y = -cand_mv.y;
272
6.34k
                    cand_mv.x = -cand_mv.x;
273
6.34k
                }
274
145k
                diff[diff_count[0]++].mv.mv[0] = cand_mv;
275
145k
            }
276
174k
        } else {
277
149k
            mv i_cand_mv = (union mv) {
278
149k
                .x = -cand_mv.x,
279
149k
                .y = -cand_mv.y
280
149k
            };
281
282
149k
            if (diff_count[0] < 2) {
283
118k
                diff[diff_count[0]++].mv.mv[0] =
284
118k
                    sign0 ^ sign_bias[cand_ref - 1] ?
285
115k
                    i_cand_mv : cand_mv;
286
118k
            }
287
288
149k
            if (diff_count[1] < 2) {
289
111k
                diff[diff_count[1]++].mv.mv[1] =
290
111k
                    sign1 ^ sign_bias[cand_ref - 1] ?
291
108k
                    i_cand_mv : cand_mv;
292
111k
            }
293
149k
        }
294
508k
    }
295
323k
}
296
297
static void add_single_extended_candidate(refmvs_candidate mvstack[8], int *const cnt,
298
                                          const refmvs_block *const cand_b,
299
                                          const int sign, const uint8_t *const sign_bias)
300
1.11M
{
301
2.24M
    for (int n = 0; n < 2; n++) {
302
2.18M
        const int cand_ref = cand_b->ref.ref[n];
303
304
2.18M
        if (cand_ref <= 0) break;
305
        // we need to continue even if cand_ref == ref.ref[0], since
306
        // the candidate could have been added as a globalmv variant,
307
        // which changes the value
308
        // FIXME if scan_{row,col}() returned a mask for the nearest
309
        // edge, we could skip the appropriate ones here
310
311
1.12M
        mv cand_mv = cand_b->mv.mv[n];
312
1.12M
        if (sign ^ sign_bias[cand_ref - 1]) {
313
9.40k
            cand_mv.y = -cand_mv.y;
314
9.40k
            cand_mv.x = -cand_mv.x;
315
9.40k
        }
316
317
1.12M
        int m;
318
1.12M
        const int last = *cnt;
319
1.29M
        for (m = 0; m < last; m++)
320
1.01M
            if (cand_mv.n == mvstack[m].mv.mv[0].n)
321
840k
                break;
322
1.12M
        if (m == last) {
323
286k
            mvstack[m].mv.mv[0] = cand_mv;
324
286k
            mvstack[m].weight = 2; // "minimal"
325
286k
            *cnt = last + 1;
326
286k
        }
327
1.12M
    }
328
1.11M
}
329
330
/*
331
 * refmvs_frame allocates memory for one sbrow (32 blocks high, whole frame
332
 * wide) of 4x4-resolution refmvs_block entries for spatial MV referencing.
333
 * mvrefs_tile[] keeps a list of 35 (32 + 3 above) pointers into this memory,
334
 * and each sbrow, the bottom entries (y=27/29/31) are exchanged with the top
335
 * (-5/-3/-1) pointers by calling dav1d_refmvs_tile_sbrow_init() at the start
336
 * of each tile/sbrow.
337
 *
338
 * For temporal MV referencing, we call dav1d_refmvs_save_tmvs() at the end of
339
 * each tile/sbrow (when tile column threading is enabled), or at the start of
340
 * each interleaved sbrow (i.e. once for all tile columns together, when tile
341
 * column threading is disabled). This will copy the 4x4-resolution spatial MVs
342
 * into 8x8-resolution refmvs_temporal_block structures. Then, for subsequent
343
 * frames, at the start of each tile/sbrow (when tile column threading is
344
 * enabled) or at the start of each interleaved sbrow (when tile column
345
 * threading is disabled), we call load_tmvs(), which will project the MVs to
346
 * their respective position in the current frame.
347
 */
348
349
void dav1d_refmvs_find(const refmvs_tile *const rt,
350
                       refmvs_candidate mvstack[8], int *const cnt,
351
                       int *const ctx,
352
                       const union refmvs_refpair ref, const enum BlockSize bs,
353
                       const enum EdgeFlags edge_flags,
354
                       const int by4, const int bx4)
355
2.70M
{
356
2.70M
    const refmvs_frame *const rf = rt->rf;
357
2.70M
    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
358
2.70M
    const int bw4 = b_dim[0], w4 = imin(imin(bw4, 16), rt->tile_col.end - bx4);
359
2.70M
    const int bh4 = b_dim[1], h4 = imin(imin(bh4, 16), rt->tile_row.end - by4);
360
2.70M
    mv gmv[2], tgmv[2];
361
362
2.70M
    *cnt = 0;
363
2.70M
    assert(ref.ref[0] >=  0 && ref.ref[0] <= 8 &&
364
2.70M
           ref.ref[1] >= -1 && ref.ref[1] <= 8);
365
2.70M
    if (ref.ref[0] > 0) {
366
1.55M
        tgmv[0] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[0] - 1],
367
1.55M
                             bx4, by4, bw4, bh4, rf->frm_hdr);
368
1.55M
        gmv[0] = rf->frm_hdr->gmv[ref.ref[0] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
369
1.12M
                 tgmv[0] : (mv) { .n = INVALID_MV };
370
1.55M
    } else {
371
1.14M
        tgmv[0] = (mv) { .n = 0 };
372
1.14M
        gmv[0] = (mv) { .n = INVALID_MV };
373
1.14M
    }
374
2.70M
    if (ref.ref[1] > 0) {
375
292k
        tgmv[1] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[1] - 1],
376
292k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
377
292k
        gmv[1] = rf->frm_hdr->gmv[ref.ref[1] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
378
205k
                 tgmv[1] : (mv) { .n = INVALID_MV };
379
292k
    }
380
381
    // top
382
2.70M
    int have_newmv = 0, have_col_mvs = 0, have_row_mvs = 0;
383
2.70M
    unsigned max_rows = 0, n_rows = ~0;
384
2.70M
    const refmvs_block *b_top;
385
2.70M
    if (by4 > rt->tile_row.start) {
386
1.81M
        max_rows = imin((by4 - rt->tile_row.start + 1) >> 1, 2 + (bh4 > 1));
387
1.81M
        b_top = &rt->r[(by4 & 31) - 1 + 5][bx4];
388
1.81M
        n_rows = scan_row(mvstack, cnt, ref, gmv, b_top,
389
1.81M
                          bw4, w4, max_rows, bw4 >= 16 ? 4 : 1,
390
1.81M
                          &have_newmv, &have_row_mvs);
391
1.81M
    }
392
393
    // left
394
2.70M
    unsigned max_cols = 0, n_cols = ~0U;
395
2.70M
    refmvs_block *const *b_left;
396
2.70M
    if (bx4 > rt->tile_col.start) {
397
2.19M
        max_cols = imin((bx4 - rt->tile_col.start + 1) >> 1, 2 + (bw4 > 1));
398
2.19M
        b_left = &rt->r[(by4 & 31) + 5];
399
2.19M
        n_cols = scan_col(mvstack, cnt, ref, gmv, b_left,
400
2.19M
                          bh4, h4, bx4 - 1, max_cols, bh4 >= 16 ? 4 : 1,
401
2.19M
                          &have_newmv, &have_col_mvs);
402
2.19M
    }
403
404
    // top/right
405
2.70M
    if (n_rows != ~0U && edge_flags & EDGE_I444_TOP_HAS_RIGHT &&
406
1.07M
        imax(bw4, bh4) <= 16 && bw4 + bx4 < rt->tile_col.end)
407
830k
    {
408
830k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[bw4], ref, gmv,
409
830k
                              &have_newmv, &have_row_mvs);
410
830k
    }
411
412
2.70M
    const int nearest_match = have_col_mvs + have_row_mvs;
413
2.70M
    const int nearest_cnt = *cnt;
414
5.83M
    for (int n = 0; n < nearest_cnt; n++)
415
3.13M
        mvstack[n].weight += 640;
416
417
    // temporal
418
2.70M
    int globalmv_ctx = rf->frm_hdr->use_ref_frame_mvs;
419
2.70M
    if (rf->use_ref_frame_mvs) {
420
105k
        const ptrdiff_t stride = rf->rp_stride;
421
105k
        const int by8 = by4 >> 1, bx8 = bx4 >> 1;
422
105k
        const refmvs_temporal_block *const rbi = &rt->rp_proj[(by8 & 15) * stride + bx8];
423
105k
        const refmvs_temporal_block *rb = rbi;
424
105k
        const int step_h = bw4 >= 16 ? 2 : 1, step_v = bh4 >= 16 ? 2 : 1;
425
105k
        const int w8 = imin((w4 + 1) >> 1, 8), h8 = imin((h4 + 1) >> 1, 8);
426
        // save_tmvs() writes one record per 8x8 cell of a coded block, so the
427
        // scan walks runs of bit-identical records. add_temporal_candidate()
428
        // is a pure function of (rb->mv, rb->ref) plus loop invariants, and on
429
        // a repeat its only effect is `weight += 2` on the same stack entry
430
        // the first call of the run inserted or merged into -- the first match
431
        // is stable because a repeat never inserts. So a run of `n` identical
432
        // records is exactly one call carrying weight 2*n.
433
        //
434
        // Two records with mv.n == INVALID_MV belong to the same run whatever
435
        // their .ref holds: add_temporal_candidate() returns before reading
436
        // .ref, so both are no-ops. The check must be written that way round
437
        // rather than merely being allowed to be, because load_tmvs() marks a
438
        // cell unprojected by writing .mv.n alone and leaves .ref uninitialized.
439
105k
        const refmvs_temporal_block *run = &rb[0];
440
105k
        int run_len = 1;
441
105k
        int *run_gmv_ctx = &globalmv_ctx;
442
316k
        for (int y = 0; y < h8; y += step_v) {
443
384k
            for (int x = y ? 0 : step_h; x < w8; x += step_h) {
444
173k
                const unsigned mvn = rb[x].mv.n;
445
173k
                if (mvn == run->mv.n &&
446
164k
                    (mvn == INVALID_MV || rb[x].ref == run->ref))
447
164k
                {
448
164k
                    run_len++;
449
164k
                    continue;
450
164k
                }
451
8.81k
                add_temporal_candidate(rf, mvstack, cnt, run, ref,
452
8.81k
                                       run_gmv_ctx, tgmv, 2 * run_len);
453
8.81k
                run_gmv_ctx = NULL;
454
8.81k
                run = &rb[x];
455
8.81k
                run_len = 1;
456
8.81k
            }
457
210k
            rb += stride * step_v;
458
210k
        }
459
105k
        add_temporal_candidate(rf, mvstack, cnt, run, ref,
460
105k
                               run_gmv_ctx, tgmv, 2 * run_len);
461
105k
        if (imin(bw4, bh4) >= 2 && imax(bw4, bh4) < 16) {
462
48.9k
            const int bh8 = bh4 >> 1, bw8 = bw4 >> 1;
463
48.9k
            rb = &rbi[bh8 * stride];
464
48.9k
            const int has_bottom = by8 + bh8 < imin(rt->tile_row.end >> 1,
465
48.9k
                                                    (by8 & ~7) + 8);
466
48.9k
            if (has_bottom && bx8 - 1 >= imax(rt->tile_col.start >> 1, bx8 & ~7)) {
467
11.0k
                add_temporal_candidate(rf, mvstack, cnt, &rb[-1], ref,
468
11.0k
                                       NULL, NULL, 2);
469
11.0k
            }
470
48.9k
            if (bx8 + bw8 < imin(rt->tile_col.end >> 1, (bx8 & ~7) + 8)) {
471
17.9k
                if (has_bottom) {
472
10.8k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8], ref,
473
10.8k
                                           NULL, NULL, 2);
474
10.8k
                }
475
17.9k
                if (by8 + bh8 - 1 < imin(rt->tile_row.end >> 1, (by8 & ~7) + 8)) {
476
15.9k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8 - stride],
477
15.9k
                                           ref, NULL, NULL, 2);
478
15.9k
                }
479
17.9k
            }
480
48.9k
        }
481
105k
    }
482
2.70M
    assert(*cnt <= 8);
483
484
    // top/left (which, confusingly, is part of "secondary" references)
485
2.70M
    int have_dummy_newmv_match;
486
2.70M
    if ((n_rows | n_cols) != ~0U) {
487
1.49M
        add_spatial_candidate(mvstack, cnt, 4, &b_top[-1], ref, gmv,
488
1.49M
                              &have_dummy_newmv_match, &have_row_mvs);
489
1.49M
    }
490
491
    // "secondary" (non-direct neighbour) top & left edges
492
    // what is different about secondary is that everything is now in 8x8 resolution
493
8.08M
    for (int n = 2; n <= 3; n++) {
494
5.38M
        if ((unsigned) n > n_rows && (unsigned) n <= max_rows) {
495
1.49M
            n_rows += scan_row(mvstack, cnt, ref, gmv,
496
1.49M
                               &rt->r[(((by4 & 31) - 2 * n + 1) | 1) + 5][bx4 | 1],
497
1.49M
                               bw4, w4, 1 + max_rows - n, bw4 >= 16 ? 4 : 2,
498
1.49M
                               &have_dummy_newmv_match, &have_row_mvs);
499
1.49M
        }
500
501
5.38M
        if ((unsigned) n > n_cols && (unsigned) n <= max_cols) {
502
2.37M
            n_cols += scan_col(mvstack, cnt, ref, gmv, &rt->r[((by4 & 31) | 1) + 5],
503
2.37M
                               bh4, h4, (bx4 - n * 2 + 1) | 1,
504
2.37M
                               1 + max_cols - n, bh4 >= 16 ? 4 : 2,
505
2.37M
                               &have_dummy_newmv_match, &have_col_mvs);
506
2.37M
        }
507
5.38M
    }
508
2.70M
    assert(*cnt <= 8);
509
510
2.70M
    const int ref_match_count = have_col_mvs + have_row_mvs;
511
512
    // context build-up
513
2.70M
    int refmv_ctx, newmv_ctx;
514
2.70M
    switch (nearest_match) {
515
562k
    case 0:
516
562k
        refmv_ctx = imin(2, ref_match_count);
517
562k
        newmv_ctx = ref_match_count > 0;
518
562k
        break;
519
1.18M
    case 1:
520
1.18M
        refmv_ctx = imin(ref_match_count * 3, 4);
521
1.18M
        newmv_ctx = 3 - have_newmv;
522
1.18M
        break;
523
958k
    case 2:
524
958k
        refmv_ctx = 5;
525
958k
        newmv_ctx = 5 - have_newmv;
526
958k
        break;
527
2.70M
    }
528
529
    // sorting (nearest, then "secondary")
530
2.69M
    int len = nearest_cnt;
531
5.34M
    while (len) {
532
2.64M
        int last = 0;
533
3.86M
        for (int n = 1; n < len; n++) {
534
1.21M
            if (mvstack[n - 1].weight < mvstack[n].weight) {
535
601k
#define EXCHANGE(a, b) do { refmvs_candidate tmp = a; a = b; b = tmp; } while (0)
536
533k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
537
533k
                last = n;
538
533k
            }
539
1.21M
        }
540
2.64M
        len = last;
541
2.64M
    }
542
2.69M
    len = *cnt;
543
4.13M
    while (len > nearest_cnt) {
544
1.43M
        int last = nearest_cnt;
545
2.08M
        for (int n = nearest_cnt + 1; n < len; n++) {
546
654k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
547
67.9k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
548
67.9k
#undef EXCHANGE
549
67.9k
                last = n;
550
67.9k
            }
551
654k
        }
552
1.43M
        len = last;
553
1.43M
    }
554
555
2.69M
    if (ref.ref[1] > 0) {
556
292k
        if (*cnt < 2) {
557
226k
            const int sign0 = rf->sign_bias[ref.ref[0] - 1];
558
226k
            const int sign1 = rf->sign_bias[ref.ref[1] - 1];
559
226k
            const int sz4 = imin(w4, h4);
560
226k
            refmvs_candidate *const same = &mvstack[*cnt];
561
226k
            int same_count[4] = { 0 };
562
563
            // non-self references in top
564
313k
            if (n_rows != ~0U) for (int x = 0; x < sz4;) {
565
163k
                const refmvs_block *const cand_b = &b_top[x];
566
163k
                add_compound_extended_candidate(same, same_count, cand_b,
567
163k
                                                sign0, sign1, ref, rf->sign_bias);
568
163k
                x += dav1d_block_dimensions[cand_b->bs][0];
569
163k
            }
570
571
            // non-self references in left
572
303k
            if (n_cols != ~0U) for (int y = 0; y < sz4;) {
573
160k
                const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
574
160k
                add_compound_extended_candidate(same, same_count, cand_b,
575
160k
                                                sign0, sign1, ref, rf->sign_bias);
576
160k
                y += dav1d_block_dimensions[cand_b->bs][1];
577
160k
            }
578
579
226k
            refmvs_candidate *const diff = &same[2];
580
226k
            const int *const diff_count = &same_count[2];
581
582
            // merge together
583
679k
            for (int n = 0; n < 2; n++) {
584
452k
                int m = same_count[n];
585
586
452k
                if (m >= 2) continue;
587
588
366k
                const int l = diff_count[n];
589
366k
                if (l) {
590
248k
                    same[m].mv.mv[n] = diff[0].mv.mv[n];
591
248k
                    if (++m == 2) continue;
592
88.9k
                    if (l == 2) {
593
66.3k
                        same[1].mv.mv[n] = diff[1].mv.mv[n];
594
66.3k
                        continue;
595
66.3k
                    }
596
88.9k
                }
597
242k
                do {
598
242k
                    same[m].mv.mv[n] = tgmv[n];
599
242k
                } while (++m < 2);
600
140k
            }
601
602
            // if the first extended was the same as the non-extended one,
603
            // then replace it with the second extended one
604
226k
            int n = *cnt;
605
226k
            if (n == 1 && mvstack[0].mv.n == same[0].mv.n)
606
69.4k
                mvstack[1].mv = mvstack[2].mv;
607
355k
            do {
608
355k
                mvstack[n].weight = 2;
609
355k
            } while (++n < 2);
610
226k
            *cnt = 2;
611
226k
        }
612
613
        // clamping
614
292k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
615
292k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
616
292k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
617
292k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
618
619
292k
        const int n_refmvs = *cnt;
620
292k
        int n = 0;
621
625k
        do {
622
625k
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
623
625k
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
624
625k
            mvstack[n].mv.mv[1].x = iclip(mvstack[n].mv.mv[1].x, left, right);
625
625k
            mvstack[n].mv.mv[1].y = iclip(mvstack[n].mv.mv[1].y, top, bottom);
626
625k
        } while (++n < n_refmvs);
627
628
292k
        switch (refmv_ctx >> 1) {
629
146k
        case 0:
630
146k
            *ctx = imin(newmv_ctx, 1);
631
146k
            break;
632
92.6k
        case 1:
633
92.6k
            *ctx = 1 + imin(newmv_ctx, 3);
634
92.6k
            break;
635
53.6k
        case 2:
636
53.6k
            *ctx = iclip(3 + newmv_ctx, 4, 7);
637
53.6k
            break;
638
292k
        }
639
640
292k
        return;
641
2.40M
    } else if (*cnt < 2 && ref.ref[0] > 0) {
642
867k
        const int sign = rf->sign_bias[ref.ref[0] - 1];
643
867k
        const int sz4 = imin(w4, h4);
644
645
        // non-self references in top
646
1.24M
        if (n_rows != ~0U) for (int x = 0; x < sz4 && *cnt < 2;) {
647
634k
            const refmvs_block *const cand_b = &b_top[x];
648
634k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
649
634k
            x += dav1d_block_dimensions[cand_b->bs][0];
650
634k
        }
651
652
        // non-self references in left
653
1.00M
        if (n_cols != ~0U) for (int y = 0; y < sz4 && *cnt < 2;) {
654
480k
            const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
655
480k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
656
480k
            y += dav1d_block_dimensions[cand_b->bs][1];
657
480k
        }
658
867k
    }
659
2.40M
    assert(*cnt <= 8);
660
661
    // clamping
662
2.40M
    int n_refmvs = *cnt;
663
2.40M
    if (n_refmvs) {
664
2.18M
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
665
2.18M
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
666
2.18M
        const int top = -(by4 + bh4 + 4) * 4 * 8;
667
2.18M
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
668
669
2.18M
        int n = 0;
670
5.15M
        do {
671
5.15M
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
672
5.15M
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
673
5.15M
        } while (++n < n_refmvs);
674
2.18M
    }
675
676
3.50M
    for (int n = *cnt; n < 2; n++)
677
1.10M
        mvstack[n].mv.mv[0] = tgmv[0];
678
679
2.40M
    *ctx = (refmv_ctx << 4) | (globalmv_ctx << 3) | newmv_ctx;
680
2.40M
}
681
682
void dav1d_refmvs_tile_sbrow_init(refmvs_tile *const rt, const refmvs_frame *const rf,
683
                                  const int tile_col_start4, const int tile_col_end4,
684
                                  const int tile_row_start4, const int tile_row_end4,
685
                                  const int sby, int tile_row_idx, const int pass)
686
691k
{
687
691k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
688
691k
    rt->rp_proj = &rf->rp_proj[16 * rf->rp_stride * tile_row_idx];
689
691k
    const ptrdiff_t r_stride = rf->rp_stride * 2;
690
691k
    const ptrdiff_t pass_off = (rf->n_frame_threads > 1 && pass == 2) ?
691
365k
        35 * 2 * rf->n_blocks : 0;
692
691k
    refmvs_block *r = &rf->r[35 * r_stride * tile_row_idx + pass_off];
693
691k
    const int sbsz = rf->sbsz;
694
691k
    const int off = (sbsz * sby) & 16;
695
14.7M
    for (int i = 0; i < sbsz; i++, r += r_stride)
696
14.0M
        rt->r[off + 5 + i] = r;
697
691k
    rt->r[off + 0] = r;
698
691k
    r += r_stride;
699
691k
    rt->r[off + 1] = NULL;
700
691k
    rt->r[off + 2] = r;
701
691k
    r += r_stride;
702
691k
    rt->r[off + 3] = NULL;
703
691k
    rt->r[off + 4] = r;
704
691k
    if (sby & 1) {
705
504k
#define EXCHANGE(a, b) do { void *const tmp = a; a = b; b = tmp; } while (0)
706
168k
        EXCHANGE(rt->r[off + 0], rt->r[off + sbsz + 0]);
707
168k
        EXCHANGE(rt->r[off + 2], rt->r[off + sbsz + 2]);
708
168k
        EXCHANGE(rt->r[off + 4], rt->r[off + sbsz + 4]);
709
168k
#undef EXCHANGE
710
168k
    }
711
712
691k
    rt->rf = rf;
713
691k
    rt->tile_row.start = tile_row_start4;
714
691k
    rt->tile_row.end = imin(tile_row_end4, rf->ih4);
715
691k
    rt->tile_col.start = tile_col_start4;
716
691k
    rt->tile_col.end = imin(tile_col_end4, rf->iw4);
717
691k
}
718
719
static void load_tmvs_c(const refmvs_frame *const rf, int tile_row_idx,
720
                        const int col_start8, const int col_end8,
721
                        const int row_start8, int row_end8)
722
56.4k
{
723
56.4k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
724
56.4k
    assert(row_start8 >= 0);
725
56.4k
    assert((unsigned) (row_end8 - row_start8) <= 16U);
726
56.4k
    row_end8 = imin(row_end8, rf->ih8);
727
56.4k
    const int col_start8i = imax(col_start8 - 8, 0);
728
56.4k
    const int col_end8i = imin(col_end8 + 8, rf->iw8);
729
730
56.4k
    const ptrdiff_t stride = rf->rp_stride;
731
56.4k
    refmvs_temporal_block *rp_proj =
732
56.4k
        &rf->rp_proj[16 * stride * tile_row_idx + (row_start8 & 15) * stride];
733
388k
    for (int y = row_start8; y < row_end8; y++) {
734
1.16M
        for (int x = col_start8; x < col_end8; x++)
735
837k
            rp_proj[x].mv.n = INVALID_MV;
736
331k
        rp_proj += stride;
737
331k
    }
738
739
56.4k
    rp_proj = &rf->rp_proj[16 * stride * tile_row_idx];
740
119k
    for (int n = 0; n < rf->n_mfmvs; n++) {
741
63.2k
        const int ref2cur = rf->mfmv_ref2cur[n];
742
63.2k
        if (ref2cur == INVALID_REF2CUR) continue;
743
744
47.4k
        const int ref = rf->mfmv_ref[n];
745
47.4k
        const int ref_sign = ref - 4;
746
47.4k
        const refmvs_temporal_block *r = &rf->rp_ref[ref][row_start8 * stride];
747
340k
        for (int y = row_start8; y < row_end8; y++) {
748
293k
            const int y_sb_align = y & ~7;
749
293k
            const int y_proj_start = imax(y_sb_align, row_start8);
750
293k
            const int y_proj_end = imin(y_sb_align + 8, row_end8);
751
697k
            for (int x = col_start8i; x < col_end8i; x++) {
752
404k
                const refmvs_temporal_block *rb = &r[x];
753
404k
                const int b_ref = rb->ref;
754
404k
                if (!b_ref) continue;
755
157k
                const int ref2ref = rf->mfmv_ref2ref[n][b_ref - 1];
756
157k
                if (!ref2ref) continue;
757
104k
                const mv b_mv = rb->mv;
758
104k
                const mv offset = mv_projection(b_mv, ref2cur, ref2ref);
759
104k
                int pos_x = x + apply_sign(abs(offset.x) >> 6,
760
104k
                                           offset.x ^ ref_sign);
761
104k
                const int pos_y = y + apply_sign(abs(offset.y) >> 6,
762
104k
                                                 offset.y ^ ref_sign);
763
104k
                if (pos_y >= y_proj_start && pos_y < y_proj_end) {
764
98.2k
                    const ptrdiff_t pos = (pos_y & 15) * stride;
765
204k
                    for (;;) {
766
204k
                        const int x_sb_align = x & ~7;
767
204k
                        if (pos_x >= imax(x_sb_align - 8, col_start8) &&
768
200k
                            pos_x < imin(x_sb_align + 16, col_end8))
769
197k
                        {
770
197k
                            rp_proj[pos + pos_x].mv = rb->mv;
771
197k
                            rp_proj[pos + pos_x].ref = ref2ref;
772
197k
                        }
773
204k
                        if (++x >= col_end8i) break;
774
119k
                        rb++;
775
119k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
776
105k
                        pos_x++;
777
105k
                    }
778
98.2k
                } else {
779
11.2k
                    for (;;) {
780
11.2k
                        if (++x >= col_end8i) break;
781
7.87k
                        rb++;
782
7.87k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
783
7.87k
                    }
784
6.08k
                }
785
104k
                x--;
786
104k
            }
787
293k
            r += stride;
788
293k
        }
789
47.4k
    }
790
56.4k
}
791
792
static void save_tmvs_c(refmvs_temporal_block *rp, const ptrdiff_t stride,
793
                        refmvs_block *const *const rr,
794
                        const uint8_t *const ref_sign,
795
                        const int col_end8, const int row_end8,
796
                        const int col_start8, const int row_start8)
797
102k
{
798
661k
    for (int y = row_start8; y < row_end8; y++) {
799
558k
        const refmvs_block *const b = rr[(y & 15) * 2];
800
801
1.33M
        for (int x = col_start8; x < col_end8;) {
802
776k
            const refmvs_block *const cand_b = &b[x * 2 + 1];
803
776k
            const int bw8 = (dav1d_block_dimensions[cand_b->bs][0] + 1) >> 1;
804
805
776k
            if (cand_b->ref.ref[1] > 0 && ref_sign[cand_b->ref.ref[1] - 1] &&
806
96.6k
                (abs(cand_b->mv.mv[1].y) | abs(cand_b->mv.mv[1].x)) < 4096)
807
89.6k
            {
808
89.6k
                const refmvs_temporal_block tmv = {
809
89.6k
                    .mv = cand_b->mv.mv[1],
810
89.6k
                    .ref = cand_b->ref.ref[1],
811
89.6k
                };
812
365k
                for (int n = 0; n < bw8; n++, x++)
813
275k
                    rp[x] = tmv;
814
687k
            } else if (cand_b->ref.ref[0] > 0 && ref_sign[cand_b->ref.ref[0] - 1] &&
815
230k
                       (abs(cand_b->mv.mv[0].y) | abs(cand_b->mv.mv[0].x)) < 4096)
816
224k
            {
817
224k
                const refmvs_temporal_block tmv = {
818
224k
                    .mv = cand_b->mv.mv[0],
819
224k
                    .ref = cand_b->ref.ref[0],
820
224k
                };
821
991k
                for (int n = 0; n < bw8; n++, x++)
822
767k
                    rp[x] = tmv;
823
462k
            } else {
824
462k
                memset(&rp[x], 0, bw8 * sizeof(*rp));
825
462k
                x += bw8;
826
462k
            }
827
776k
        }
828
558k
        rp += stride;
829
558k
    }
830
102k
}
831
832
int dav1d_refmvs_init_frame(refmvs_frame *const rf,
833
                            const Dav1dSequenceHeader *const seq_hdr,
834
                            const Dav1dFrameHeader *const frm_hdr,
835
                            const uint8_t ref_poc[7],
836
                            refmvs_temporal_block *const rp,
837
                            const uint8_t ref_ref_poc[7][7],
838
                            /*const*/ refmvs_temporal_block *const rp_ref[7],
839
                            const int n_tile_threads, const int n_frame_threads)
840
236k
{
841
236k
    const int rp_stride = ((frm_hdr->width[0] + 127) & ~127) >> 3;
842
236k
    const int n_tile_rows = n_tile_threads > 1 ? frm_hdr->tiling.rows : 1;
843
236k
    const int n_blocks = rp_stride * n_tile_rows;
844
845
236k
    rf->sbsz = 16 << seq_hdr->sb128;
846
236k
    rf->frm_hdr = frm_hdr;
847
236k
    rf->iw8 = (frm_hdr->width[0] + 7) >> 3;
848
236k
    rf->ih8 = (frm_hdr->height + 7) >> 3;
849
236k
    rf->iw4 = rf->iw8 << 1;
850
236k
    rf->ih4 = rf->ih8 << 1;
851
236k
    rf->rp = rp;
852
236k
    rf->rp_stride = rp_stride;
853
236k
    rf->n_tile_threads = n_tile_threads;
854
236k
    rf->n_frame_threads = n_frame_threads;
855
856
236k
    if (n_blocks != rf->n_blocks) {
857
87.8k
        const size_t r_sz = sizeof(*rf->r) * 35 * 2 * n_blocks * (1 + (n_frame_threads > 1));
858
87.8k
        const size_t rp_proj_sz = sizeof(*rf->rp_proj) * 16 * n_blocks;
859
        /* Note that sizeof(*rf->r) == 12, but it's accessed using 16-byte unaligned
860
         * loads in save_tmvs() asm which can overread 4 bytes into rp_proj. */
861
87.8k
        dav1d_free_aligned(rf->r);
862
87.8k
        rf->r = dav1d_alloc_aligned(ALLOC_REFMVS, r_sz + rp_proj_sz, 64);
863
87.8k
        if (!rf->r) {
864
0
            rf->n_blocks = 0;
865
0
            return DAV1D_ERR(ENOMEM);
866
0
        }
867
868
87.8k
        rf->rp_proj = (refmvs_temporal_block*)((uintptr_t)rf->r + r_sz);
869
87.8k
        rf->n_blocks = n_blocks;
870
87.8k
    }
871
872
236k
    const int poc = frm_hdr->frame_offset;
873
1.89M
    for (int i = 0; i < 7; i++) {
874
1.65M
        const int poc_diff = get_poc_diff(seq_hdr->order_hint_n_bits,
875
1.65M
                                          ref_poc[i], poc);
876
1.65M
        rf->sign_bias[i] = poc_diff > 0;
877
1.65M
        rf->mfmv_sign[i] = poc_diff < 0;
878
1.65M
        rf->pocdiff[i] = iclip(get_poc_diff(seq_hdr->order_hint_n_bits,
879
1.65M
                                            poc, ref_poc[i]), -31, 31);
880
1.65M
    }
881
882
    // temporal MV setup
883
236k
    rf->n_mfmvs = 0;
884
236k
    rf->rp_ref = rp_ref;
885
236k
    if (frm_hdr->use_ref_frame_mvs && seq_hdr->order_hint_n_bits) {
886
51.7k
        int total = 2;
887
51.7k
        if (rp_ref[0] && ref_ref_poc[0][6] != ref_poc[3] /* alt-of-last != gold */) {
888
15.7k
            rf->mfmv_ref[rf->n_mfmvs++] = 0; // last
889
15.7k
            total = 3;
890
15.7k
        }
891
51.7k
        if (rp_ref[4] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[4],
892
37.2k
                                      frm_hdr->frame_offset) > 0)
893
1.95k
        {
894
1.95k
            rf->mfmv_ref[rf->n_mfmvs++] = 4; // bwd
895
1.95k
        }
896
51.7k
        if (rp_ref[5] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[5],
897
38.4k
                                      frm_hdr->frame_offset) > 0)
898
1.38k
        {
899
1.38k
            rf->mfmv_ref[rf->n_mfmvs++] = 5; // altref2
900
1.38k
        }
901
51.7k
        if (rf->n_mfmvs < total && rp_ref[6] &&
902
26.2k
            get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[6],
903
26.2k
                         frm_hdr->frame_offset) > 0)
904
8.84k
        {
905
8.84k
            rf->mfmv_ref[rf->n_mfmvs++] = 6; // altref
906
8.84k
        }
907
51.7k
        if (rf->n_mfmvs < total && rp_ref[1])
908
33.3k
            rf->mfmv_ref[rf->n_mfmvs++] = 1; // last2
909
910
113k
        for (int n = 0; n < rf->n_mfmvs; n++) {
911
61.2k
            const int rpoc = ref_poc[rf->mfmv_ref[n]];
912
61.2k
            const int diff1 = get_poc_diff(seq_hdr->order_hint_n_bits,
913
61.2k
                                           rpoc, frm_hdr->frame_offset);
914
61.2k
            if (abs(diff1) > 31) {
915
15.3k
                rf->mfmv_ref2cur[n] = INVALID_REF2CUR;
916
45.9k
            } else {
917
45.9k
                rf->mfmv_ref2cur[n] = rf->mfmv_ref[n] < 4 ? -diff1 : diff1;
918
367k
                for (int m = 0; m < 7; m++) {
919
321k
                    const int rrpoc = ref_ref_poc[rf->mfmv_ref[n]][m];
920
321k
                    const int diff2 = get_poc_diff(seq_hdr->order_hint_n_bits,
921
321k
                                                   rpoc, rrpoc);
922
                    // unsigned comparison also catches the < 0 case
923
321k
                    rf->mfmv_ref2ref[n][m] = (unsigned) diff2 > 31U ? 0 : diff2;
924
321k
                }
925
45.9k
            }
926
61.2k
        }
927
51.7k
    }
928
236k
    rf->use_ref_frame_mvs = rf->n_mfmvs > 0;
929
930
236k
    return 0;
931
236k
}
932
933
static void splat_mv_c(refmvs_block **rr, const refmvs_block *const rmv,
934
                       const int bx4, const int bw4, int bh4)
935
4.20M
{
936
16.2M
    do {
937
16.2M
        refmvs_block *const r = *rr++ + bx4;
938
158M
        for (int x = 0; x < bw4; x++)
939
142M
            r[x] = *rmv;
940
16.2M
    } while (--bh4);
941
4.20M
}
942
943
#if HAVE_ASM
944
#if ARCH_AARCH64 || ARCH_ARM
945
#include "src/arm/refmvs.h"
946
#elif ARCH_LOONGARCH64
947
#include "src/loongarch/refmvs.h"
948
#elif ARCH_X86
949
#include "src/x86/refmvs.h"
950
#endif
951
#endif
952
953
COLD void dav1d_refmvs_dsp_init(Dav1dRefmvsDSPContext *const c)
954
110k
{
955
110k
    c->load_tmvs = load_tmvs_c;
956
110k
    c->save_tmvs = save_tmvs_c;
957
110k
    c->splat_mv = splat_mv_c;
958
959
#if HAVE_ASM
960
#if ARCH_AARCH64 || ARCH_ARM
961
    refmvs_dsp_init_arm(c);
962
#elif ARCH_LOONGARCH64
963
    refmvs_dsp_init_loongarch(c);
964
#elif ARCH_X86
965
    refmvs_dsp_init_x86(c);
966
#endif
967
#endif
968
110k
}