Coverage Report

Created: 2026-10-17 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/dav1d/src/refmvs.c
Line
Count
Source
1
/*
2
 * Copyright © 2020, VideoLAN and dav1d authors
3
 * Copyright © 2020, Two Orioles, LLC
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions are met:
8
 *
9
 * 1. Redistributions of source code must retain the above copyright notice, this
10
 *    list of conditions and the following disclaimer.
11
 *
12
 * 2. Redistributions in binary form must reproduce the above copyright notice,
13
 *    this list of conditions and the following disclaimer in the documentation
14
 *    and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 */
27
28
#include "config.h"
29
30
#include <limits.h>
31
#include <stdlib.h>
32
#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
4.15M
{
48
4.15M
    if (b->mv.mv[0].n == INVALID_MV) return; // intra block, no intrabc
49
50
3.87M
    if (ref.ref[1] == -1) {
51
4.55M
        for (int n = 0; n < 2; n++) {
52
4.02M
            if (b->ref.ref[n] == ref.ref[0]) {
53
2.92M
                const mv cand_mv = ((b->mf & 1) && gmv[0].n != INVALID_MV) ?
54
2.83M
                                   gmv[0] : b->mv.mv[n];
55
56
2.92M
                *have_refmv_match = 1;
57
2.92M
                *have_newmv_match |= b->mf >> 1;
58
59
2.92M
                const int last = *cnt;
60
5.60M
                for (int m = 0; m < last; m++)
61
3.47M
                    if (mvstack[m].mv.mv[0].n == cand_mv.n) {
62
795k
                        mvstack[m].weight += weight;
63
795k
                        return;
64
795k
                    }
65
66
2.12M
                if (last < 8) {
67
2.12M
                    mvstack[last].mv.mv[0] = cand_mv;
68
2.12M
                    mvstack[last].weight = weight;
69
2.12M
                    *cnt = last + 1;
70
2.12M
                }
71
2.12M
                return;
72
2.92M
            }
73
4.02M
        }
74
3.44M
    } else if (b->ref.pair == ref.pair) {
75
144k
        const refmvs_mvpair cand_mv = { .mv = {
76
144k
            [0] = ((b->mf & 1) && gmv[0].n != INVALID_MV) ? gmv[0] : b->mv.mv[0],
77
144k
            [1] = ((b->mf & 1) && gmv[1].n != INVALID_MV) ? gmv[1] : b->mv.mv[1],
78
144k
        }};
79
80
144k
        *have_refmv_match = 1;
81
144k
        *have_newmv_match |= b->mf >> 1;
82
83
144k
        const int last = *cnt;
84
223k
        for (int n = 0; n < last; n++)
85
132k
            if (mvstack[n].mv.n == cand_mv.n) {
86
53.1k
                mvstack[n].weight += weight;
87
53.1k
                return;
88
53.1k
            }
89
90
91.2k
        if (last < 8) {
91
91.1k
            mvstack[last].mv = cand_mv;
92
91.1k
            mvstack[last].weight = weight;
93
91.1k
            *cnt = last + 1;
94
91.1k
        }
95
91.2k
    }
96
3.87M
}
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
1.13M
{
104
1.13M
    const refmvs_block *cand_b = b;
105
1.13M
    const enum BlockSize first_cand_bs = cand_b->bs;
106
1.13M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
107
1.13M
    int cand_bw4 = first_cand_b_dim[0];
108
1.13M
    int len = imax(step, imin(bw4, cand_bw4));
109
110
1.13M
    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
1.00M
        const int weight = bw4 == 1 ? 2 :
116
1.00M
                           imax(2, imin(2 * max_rows, first_cand_b_dim[1]));
117
1.00M
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
118
1.00M
                              have_newmv_match, have_refmv_match);
119
1.00M
        return weight >> 1;
120
1.00M
    }
121
122
270k
    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
270k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
127
270k
                              have_newmv_match, have_refmv_match);
128
270k
        x += len;
129
270k
        if (x >= w4) return 1;
130
137k
        cand_b = &b[x];
131
137k
        cand_bw4 = dav1d_block_dimensions[cand_b->bs][0];
132
137k
        assert(cand_bw4 < bw4);
133
137k
        len = imax(step, cand_bw4);
134
137k
    }
135
132k
}
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
1.86M
{
143
1.86M
    const refmvs_block *cand_b = &b[0][bx4];
144
1.86M
    const enum BlockSize first_cand_bs = cand_b->bs;
145
1.86M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
146
1.86M
    int cand_bh4 = first_cand_b_dim[1];
147
1.86M
    int len = imax(step, imin(bh4, cand_bh4));
148
149
1.86M
    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
1.73M
        const int weight = bh4 == 1 ? 2 :
155
1.73M
                           imax(2, imin(2 * max_cols, first_cand_b_dim[0]));
156
1.73M
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
157
1.73M
                            have_newmv_match, have_refmv_match);
158
1.73M
        return weight >> 1;
159
1.73M
    }
160
161
237k
    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
237k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
166
237k
                              have_newmv_match, have_refmv_match);
167
237k
        y += len;
168
237k
        if (y >= h4) return 1;
169
110k
        cand_b = &b[y][bx4];
170
110k
        cand_bh4 = dav1d_block_dimensions[cand_b->bs][1];
171
110k
        assert(cand_bh4 < bh4);
172
110k
        len = imax(step, cand_bh4);
173
110k
    }
174
128k
}
175
176
20.3k
static inline union mv mv_projection(const union mv mv, const int num, const int den) {
177
20.3k
    static const uint16_t div_mult[32] = {
178
20.3k
           0, 16384, 8192, 5461, 4096, 3276, 2730, 2340,
179
20.3k
        2048,  1820, 1638, 1489, 1365, 1260, 1170, 1092,
180
20.3k
        1024,   963,  910,  862,  819,  780,  744,  712,
181
20.3k
         682,   655,  630,  606,  585,  564,  546,  528
182
20.3k
    };
183
20.3k
    assert(den > 0 && den < 32);
184
20.3k
    assert(num > -32 && num < 32);
185
20.3k
    const int frac = num * div_mult[den];
186
20.3k
    const int y = mv.y * frac, x = mv.x * frac;
187
    // Round and clip according to AV1 spec section 7.9.3
188
20.3k
    return (union mv) { // 0x3fff == (1 << 14) - 1
189
20.3k
        .y = iclip((y + 8192 + (y >> 31)) >> 14, -0x3fff, 0x3fff),
190
20.3k
        .x = iclip((x + 8192 + (x >> 31)) >> 14, -0x3fff, 0x3fff)
191
20.3k
    };
192
20.3k
}
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
18.3k
{
200
18.3k
    if (rb->mv.n == INVALID_MV) return;
201
202
9.35k
    union mv mv = mv_projection(rb->mv, rf->pocdiff[ref.ref[0] - 1], rb->ref);
203
9.35k
    fix_mv_precision(rf->frm_hdr, &mv);
204
205
9.35k
    const int last = *cnt;
206
9.35k
    if (ref.ref[1] == -1) {
207
5.87k
        if (globalmv_ctx)
208
2.72k
            *globalmv_ctx = (abs(mv.x - gmv[0].x) | abs(mv.y - gmv[0].y)) >= 16;
209
210
11.3k
        for (int n = 0; n < last; n++)
211
8.79k
            if (mvstack[n].mv.mv[0].n == mv.n) {
212
3.35k
                mvstack[n].weight += weight;
213
3.35k
                return;
214
3.35k
            }
215
2.52k
        if (last < 8) {
216
2.52k
            mvstack[last].mv.mv[0] = mv;
217
2.52k
            mvstack[last].weight = weight;
218
2.52k
            *cnt = last + 1;
219
2.52k
        }
220
3.47k
    } else {
221
3.47k
        refmvs_mvpair mvp = { .mv = {
222
3.47k
            [0] = mv,
223
3.47k
            [1] = mv_projection(rb->mv, rf->pocdiff[ref.ref[1] - 1], rb->ref),
224
3.47k
        }};
225
3.47k
        fix_mv_precision(rf->frm_hdr, &mvp.mv[1]);
226
227
5.54k
        for (int n = 0; n < last; n++)
228
3.99k
            if (mvstack[n].mv.n == mvp.n) {
229
1.92k
                mvstack[n].weight += weight;
230
1.92k
                return;
231
1.92k
            }
232
1.55k
        if (last < 8) {
233
1.55k
            mvstack[last].mv = mvp;
234
1.55k
            mvstack[last].weight = weight;
235
1.55k
            *cnt = last + 1;
236
1.55k
        }
237
1.55k
    }
238
9.35k
}
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
105k
{
247
105k
    refmvs_candidate *const diff = &same[2];
248
105k
    int *const diff_count = &same_count[2];
249
250
274k
    for (int n = 0; n < 2; n++) {
251
208k
        const int cand_ref = cand_b->ref.ref[n];
252
253
208k
        if (cand_ref <= 0) break;
254
255
168k
        mv cand_mv = cand_b->mv.mv[n];
256
168k
        if (cand_ref == ref.ref[0]) {
257
59.7k
            if (same_count[0] < 2)
258
57.8k
                same[same_count[0]++].mv.mv[0] = cand_mv;
259
59.7k
            if (diff_count[1] < 2) {
260
50.7k
                if (sign1 ^ sign_bias[cand_ref - 1]) {
261
880
                    cand_mv.y = -cand_mv.y;
262
880
                    cand_mv.x = -cand_mv.x;
263
880
                }
264
50.7k
                diff[diff_count[1]++].mv.mv[1] = cand_mv;
265
50.7k
            }
266
108k
        } else if (cand_ref == ref.ref[1]) {
267
57.8k
            if (same_count[1] < 2)
268
56.5k
                same[same_count[1]++].mv.mv[1] = cand_mv;
269
57.8k
            if (diff_count[0] < 2) {
270
47.2k
                if (sign0 ^ sign_bias[cand_ref - 1]) {
271
875
                    cand_mv.y = -cand_mv.y;
272
875
                    cand_mv.x = -cand_mv.x;
273
875
                }
274
47.2k
                diff[diff_count[0]++].mv.mv[0] = cand_mv;
275
47.2k
            }
276
57.8k
        } else {
277
50.8k
            mv i_cand_mv = (union mv) {
278
50.8k
                .x = -cand_mv.x,
279
50.8k
                .y = -cand_mv.y
280
50.8k
            };
281
282
50.8k
            if (diff_count[0] < 2) {
283
40.1k
                diff[diff_count[0]++].mv.mv[0] =
284
40.1k
                    sign0 ^ sign_bias[cand_ref - 1] ?
285
39.9k
                    i_cand_mv : cand_mv;
286
40.1k
            }
287
288
50.8k
            if (diff_count[1] < 2) {
289
37.4k
                diff[diff_count[1]++].mv.mv[1] =
290
37.4k
                    sign1 ^ sign_bias[cand_ref - 1] ?
291
37.1k
                    i_cand_mv : cand_mv;
292
37.4k
            }
293
50.8k
        }
294
168k
    }
295
105k
}
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
309k
{
301
621k
    for (int n = 0; n < 2; n++) {
302
605k
        const int cand_ref = cand_b->ref.ref[n];
303
304
605k
        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
311k
        mv cand_mv = cand_b->mv.mv[n];
312
311k
        if (sign ^ sign_bias[cand_ref - 1]) {
313
641
            cand_mv.y = -cand_mv.y;
314
641
            cand_mv.x = -cand_mv.x;
315
641
        }
316
317
311k
        int m;
318
311k
        const int last = *cnt;
319
372k
        for (m = 0; m < last; m++)
320
285k
            if (cand_mv.n == mvstack[m].mv.mv[0].n)
321
224k
                break;
322
311k
        if (m == last) {
323
87.1k
            mvstack[m].mv.mv[0] = cand_mv;
324
87.1k
            mvstack[m].weight = 2; // "minimal"
325
87.1k
            *cnt = last + 1;
326
87.1k
        }
327
311k
    }
328
309k
}
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
984k
{
356
984k
    const refmvs_frame *const rf = rt->rf;
357
984k
    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
358
984k
    const int bw4 = b_dim[0], w4 = imin(imin(bw4, 16), rt->tile_col.end - bx4);
359
984k
    const int bh4 = b_dim[1], h4 = imin(imin(bh4, 16), rt->tile_row.end - by4);
360
984k
    mv gmv[2], tgmv[2];
361
362
984k
    *cnt = 0;
363
984k
    assert(ref.ref[0] >=  0 && ref.ref[0] <= 8 &&
364
984k
           ref.ref[1] >= -1 && ref.ref[1] <= 8);
365
984k
    if (ref.ref[0] > 0) {
366
426k
        tgmv[0] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[0] - 1],
367
426k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
368
426k
        gmv[0] = rf->frm_hdr->gmv[ref.ref[0] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
369
297k
                 tgmv[0] : (mv) { .n = INVALID_MV };
370
557k
    } else {
371
557k
        tgmv[0] = (mv) { .n = 0 };
372
557k
        gmv[0] = (mv) { .n = INVALID_MV };
373
557k
    }
374
984k
    if (ref.ref[1] > 0) {
375
83.5k
        tgmv[1] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[1] - 1],
376
83.5k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
377
83.5k
        gmv[1] = rf->frm_hdr->gmv[ref.ref[1] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
378
56.9k
                 tgmv[1] : (mv) { .n = INVALID_MV };
379
83.5k
    }
380
381
    // top
382
984k
    int have_newmv = 0, have_col_mvs = 0, have_row_mvs = 0;
383
984k
    unsigned max_rows = 0, n_rows = ~0;
384
984k
    const refmvs_block *b_top;
385
984k
    if (by4 > rt->tile_row.start) {
386
657k
        max_rows = imin((by4 - rt->tile_row.start + 1) >> 1, 2 + (bh4 > 1));
387
657k
        b_top = &rt->r[(by4 & 31) - 1 + 5][bx4];
388
657k
        n_rows = scan_row(mvstack, cnt, ref, gmv, b_top,
389
657k
                          bw4, w4, max_rows, bw4 >= 16 ? 4 : 1,
390
657k
                          &have_newmv, &have_row_mvs);
391
657k
    }
392
393
    // left
394
984k
    unsigned max_cols = 0, n_cols = ~0U;
395
984k
    refmvs_block *const *b_left;
396
984k
    if (bx4 > rt->tile_col.start) {
397
900k
        max_cols = imin((bx4 - rt->tile_col.start + 1) >> 1, 2 + (bw4 > 1));
398
900k
        b_left = &rt->r[(by4 & 31) + 5];
399
900k
        n_cols = scan_col(mvstack, cnt, ref, gmv, b_left,
400
900k
                          bh4, h4, bx4 - 1, max_cols, bh4 >= 16 ? 4 : 1,
401
900k
                          &have_newmv, &have_col_mvs);
402
900k
    }
403
404
    // top/right
405
984k
    if (n_rows != ~0U && edge_flags & EDGE_I444_TOP_HAS_RIGHT &&
406
374k
        imax(bw4, bh4) <= 16 && bw4 + bx4 < rt->tile_col.end)
407
333k
    {
408
333k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[bw4], ref, gmv,
409
333k
                              &have_newmv, &have_row_mvs);
410
333k
    }
411
412
984k
    const int nearest_match = have_col_mvs + have_row_mvs;
413
984k
    const int nearest_cnt = *cnt;
414
2.30M
    for (int n = 0; n < nearest_cnt; n++)
415
1.32M
        mvstack[n].weight += 640;
416
417
    // temporal
418
984k
    int globalmv_ctx = rf->frm_hdr->use_ref_frame_mvs;
419
984k
    if (rf->use_ref_frame_mvs) {
420
9.62k
        const ptrdiff_t stride = rf->rp_stride;
421
9.62k
        const int by8 = by4 >> 1, bx8 = bx4 >> 1;
422
9.62k
        const refmvs_temporal_block *const rbi = &rt->rp_proj[(by8 & 15) * stride + bx8];
423
9.62k
        const refmvs_temporal_block *rb = rbi;
424
9.62k
        const int step_h = bw4 >= 16 ? 2 : 1, step_v = bh4 >= 16 ? 2 : 1;
425
9.62k
        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
9.62k
        const refmvs_temporal_block *run = &rb[0];
440
9.62k
        int run_len = 1;
441
9.62k
        int *run_gmv_ctx = &globalmv_ctx;
442
26.6k
        for (int y = 0; y < h8; y += step_v) {
443
36.9k
            for (int x = y ? 0 : step_h; x < w8; x += step_h) {
444
19.9k
                const unsigned mvn = rb[x].mv.n;
445
19.9k
                if (mvn == run->mv.n &&
446
18.5k
                    (mvn == INVALID_MV || rb[x].ref == run->ref))
447
18.5k
                {
448
18.5k
                    run_len++;
449
18.5k
                    continue;
450
18.5k
                }
451
1.39k
                add_temporal_candidate(rf, mvstack, cnt, run, ref,
452
1.39k
                                       run_gmv_ctx, tgmv, 2 * run_len);
453
1.39k
                run_gmv_ctx = NULL;
454
1.39k
                run = &rb[x];
455
1.39k
                run_len = 1;
456
1.39k
            }
457
17.0k
            rb += stride * step_v;
458
17.0k
        }
459
9.62k
        add_temporal_candidate(rf, mvstack, cnt, run, ref,
460
9.62k
                               run_gmv_ctx, tgmv, 2 * run_len);
461
9.62k
        if (imin(bw4, bh4) >= 2 && imax(bw4, bh4) < 16) {
462
5.84k
            const int bh8 = bh4 >> 1, bw8 = bw4 >> 1;
463
5.84k
            rb = &rbi[bh8 * stride];
464
5.84k
            const int has_bottom = by8 + bh8 < imin(rt->tile_row.end >> 1,
465
5.84k
                                                    (by8 & ~7) + 8);
466
5.84k
            if (has_bottom && bx8 - 1 >= imax(rt->tile_col.start >> 1, bx8 & ~7)) {
467
2.28k
                add_temporal_candidate(rf, mvstack, cnt, &rb[-1], ref,
468
2.28k
                                       NULL, NULL, 2);
469
2.28k
            }
470
5.84k
            if (bx8 + bw8 < imin(rt->tile_col.end >> 1, (bx8 & ~7) + 8)) {
471
3.01k
                if (has_bottom) {
472
2.16k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8], ref,
473
2.16k
                                           NULL, NULL, 2);
474
2.16k
                }
475
3.01k
                if (by8 + bh8 - 1 < imin(rt->tile_row.end >> 1, (by8 & ~7) + 8)) {
476
2.86k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8 - stride],
477
2.86k
                                           ref, NULL, NULL, 2);
478
2.86k
                }
479
3.01k
            }
480
5.84k
        }
481
9.62k
    }
482
984k
    assert(*cnt <= 8);
483
484
    // top/left (which, confusingly, is part of "secondary" references)
485
984k
    int have_dummy_newmv_match;
486
984k
    if ((n_rows | n_cols) != ~0U) {
487
594k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[-1], ref, gmv,
488
594k
                              &have_dummy_newmv_match, &have_row_mvs);
489
594k
    }
490
491
    // "secondary" (non-direct neighbour) top & left edges
492
    // what is different about secondary is that everything is now in 8x8 resolution
493
2.94M
    for (int n = 2; n <= 3; n++) {
494
1.95M
        if ((unsigned) n > n_rows && (unsigned) n <= max_rows) {
495
475k
            n_rows += scan_row(mvstack, cnt, ref, gmv,
496
475k
                               &rt->r[(((by4 & 31) - 2 * n + 1) | 1) + 5][bx4 | 1],
497
475k
                               bw4, w4, 1 + max_rows - n, bw4 >= 16 ? 4 : 2,
498
475k
                               &have_dummy_newmv_match, &have_row_mvs);
499
475k
        }
500
501
1.95M
        if ((unsigned) n > n_cols && (unsigned) n <= max_cols) {
502
967k
            n_cols += scan_col(mvstack, cnt, ref, gmv, &rt->r[((by4 & 31) | 1) + 5],
503
967k
                               bh4, h4, (bx4 - n * 2 + 1) | 1,
504
967k
                               1 + max_cols - n, bh4 >= 16 ? 4 : 2,
505
967k
                               &have_dummy_newmv_match, &have_col_mvs);
506
967k
        }
507
1.95M
    }
508
984k
    assert(*cnt <= 8);
509
510
984k
    const int ref_match_count = have_col_mvs + have_row_mvs;
511
512
    // context build-up
513
984k
    int refmv_ctx, newmv_ctx;
514
984k
    switch (nearest_match) {
515
123k
    case 0:
516
123k
        refmv_ctx = imin(2, ref_match_count);
517
123k
        newmv_ctx = ref_match_count > 0;
518
123k
        break;
519
444k
    case 1:
520
444k
        refmv_ctx = imin(ref_match_count * 3, 4);
521
444k
        newmv_ctx = 3 - have_newmv;
522
444k
        break;
523
417k
    case 2:
524
417k
        refmv_ctx = 5;
525
417k
        newmv_ctx = 5 - have_newmv;
526
417k
        break;
527
984k
    }
528
529
    // sorting (nearest, then "secondary")
530
981k
    int len = nearest_cnt;
531
2.08M
    while (len) {
532
1.10M
        int last = 0;
533
1.68M
        for (int n = 1; n < len; n++) {
534
581k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
535
275k
#define EXCHANGE(a, b) do { refmvs_candidate tmp = a; a = b; b = tmp; } while (0)
536
256k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
537
256k
                last = n;
538
256k
            }
539
581k
        }
540
1.10M
        len = last;
541
1.10M
    }
542
981k
    len = *cnt;
543
1.62M
    while (len > nearest_cnt) {
544
639k
        int last = nearest_cnt;
545
939k
        for (int n = nearest_cnt + 1; n < len; n++) {
546
300k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
547
18.7k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
548
18.7k
#undef EXCHANGE
549
18.7k
                last = n;
550
18.7k
            }
551
300k
        }
552
639k
        len = last;
553
639k
    }
554
555
981k
    if (ref.ref[1] > 0) {
556
83.5k
        if (*cnt < 2) {
557
60.2k
            const int sign0 = rf->sign_bias[ref.ref[0] - 1];
558
60.2k
            const int sign1 = rf->sign_bias[ref.ref[1] - 1];
559
60.2k
            const int sz4 = imin(w4, h4);
560
60.2k
            refmvs_candidate *const same = &mvstack[*cnt];
561
60.2k
            int same_count[4] = { 0 };
562
563
            // non-self references in top
564
104k
            if (n_rows != ~0U) for (int x = 0; x < sz4;) {
565
54.7k
                const refmvs_block *const cand_b = &b_top[x];
566
54.7k
                add_compound_extended_candidate(same, same_count, cand_b,
567
54.7k
                                                sign0, sign1, ref, rf->sign_bias);
568
54.7k
                x += dav1d_block_dimensions[cand_b->bs][0];
569
54.7k
            }
570
571
            // non-self references in left
572
97.9k
            if (n_cols != ~0U) for (int y = 0; y < sz4;) {
573
51.0k
                const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
574
51.0k
                add_compound_extended_candidate(same, same_count, cand_b,
575
51.0k
                                                sign0, sign1, ref, rf->sign_bias);
576
51.0k
                y += dav1d_block_dimensions[cand_b->bs][1];
577
51.0k
            }
578
579
60.2k
            refmvs_candidate *const diff = &same[2];
580
60.2k
            const int *const diff_count = &same_count[2];
581
582
            // merge together
583
180k
            for (int n = 0; n < 2; n++) {
584
120k
                int m = same_count[n];
585
586
120k
                if (m >= 2) continue;
587
588
90.1k
                const int l = diff_count[n];
589
90.1k
                if (l) {
590
77.0k
                    same[m].mv.mv[n] = diff[0].mv.mv[n];
591
77.0k
                    if (++m == 2) continue;
592
27.0k
                    if (l == 2) {
593
21.5k
                        same[1].mv.mv[n] = diff[1].mv.mv[n];
594
21.5k
                        continue;
595
21.5k
                    }
596
27.0k
                }
597
28.0k
                do {
598
28.0k
                    same[m].mv.mv[n] = tgmv[n];
599
28.0k
                } while (++m < 2);
600
18.5k
            }
601
602
            // if the first extended was the same as the non-extended one,
603
            // then replace it with the second extended one
604
60.2k
            int n = *cnt;
605
60.2k
            if (n == 1 && mvstack[0].mv.n == same[0].mv.n)
606
21.5k
                mvstack[1].mv = mvstack[2].mv;
607
90.9k
            do {
608
90.9k
                mvstack[n].weight = 2;
609
90.9k
            } while (++n < 2);
610
60.2k
            *cnt = 2;
611
60.2k
        }
612
613
        // clamping
614
83.5k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
615
83.5k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
616
83.5k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
617
83.5k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
618
619
83.5k
        const int n_refmvs = *cnt;
620
83.5k
        int n = 0;
621
183k
        do {
622
183k
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
623
183k
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
624
183k
            mvstack[n].mv.mv[1].x = iclip(mvstack[n].mv.mv[1].x, left, right);
625
183k
            mvstack[n].mv.mv[1].y = iclip(mvstack[n].mv.mv[1].y, top, bottom);
626
183k
        } while (++n < n_refmvs);
627
628
83.5k
        switch (refmv_ctx >> 1) {
629
34.3k
        case 0:
630
34.3k
            *ctx = imin(newmv_ctx, 1);
631
34.3k
            break;
632
29.2k
        case 1:
633
29.2k
            *ctx = 1 + imin(newmv_ctx, 3);
634
29.2k
            break;
635
19.9k
        case 2:
636
19.9k
            *ctx = iclip(3 + newmv_ctx, 4, 7);
637
19.9k
            break;
638
83.5k
        }
639
640
83.5k
        return;
641
898k
    } else if (*cnt < 2 && ref.ref[0] > 0) {
642
202k
        const int sign = rf->sign_bias[ref.ref[0] - 1];
643
202k
        const int sz4 = imin(w4, h4);
644
645
        // non-self references in top
646
338k
        if (n_rows != ~0U) for (int x = 0; x < sz4 && *cnt < 2;) {
647
173k
            const refmvs_block *const cand_b = &b_top[x];
648
173k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
649
173k
            x += dav1d_block_dimensions[cand_b->bs][0];
650
173k
        }
651
652
        // non-self references in left
653
290k
        if (n_cols != ~0U) for (int y = 0; y < sz4 && *cnt < 2;) {
654
135k
            const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
655
135k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
656
135k
            y += dav1d_block_dimensions[cand_b->bs][1];
657
135k
        }
658
202k
    }
659
898k
    assert(*cnt <= 8);
660
661
    // clamping
662
898k
    int n_refmvs = *cnt;
663
898k
    if (n_refmvs) {
664
855k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
665
855k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
666
855k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
667
855k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
668
669
855k
        int n = 0;
670
2.23M
        do {
671
2.23M
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
672
2.23M
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
673
2.23M
        } while (++n < n_refmvs);
674
855k
    }
675
676
1.14M
    for (int n = *cnt; n < 2; n++)
677
251k
        mvstack[n].mv.mv[0] = tgmv[0];
678
679
898k
    *ctx = (refmv_ctx << 4) | (globalmv_ctx << 3) | newmv_ctx;
680
898k
}
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
108k
{
687
108k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
688
108k
    rt->rp_proj = &rf->rp_proj[16 * rf->rp_stride * tile_row_idx];
689
108k
    const ptrdiff_t r_stride = rf->rp_stride * 2;
690
108k
    const ptrdiff_t pass_off = (rf->n_frame_threads > 1 && pass == 2) ?
691
62.0k
        35 * 2 * rf->n_blocks : 0;
692
108k
    refmvs_block *r = &rf->r[35 * r_stride * tile_row_idx + pass_off];
693
108k
    const int sbsz = rf->sbsz;
694
108k
    const int off = (sbsz * sby) & 16;
695
2.30M
    for (int i = 0; i < sbsz; i++, r += r_stride)
696
2.19M
        rt->r[off + 5 + i] = r;
697
108k
    rt->r[off + 0] = r;
698
108k
    r += r_stride;
699
108k
    rt->r[off + 1] = NULL;
700
108k
    rt->r[off + 2] = r;
701
108k
    r += r_stride;
702
108k
    rt->r[off + 3] = NULL;
703
108k
    rt->r[off + 4] = r;
704
108k
    if (sby & 1) {
705
103k
#define EXCHANGE(a, b) do { void *const tmp = a; a = b; b = tmp; } while (0)
706
34.4k
        EXCHANGE(rt->r[off + 0], rt->r[off + sbsz + 0]);
707
34.4k
        EXCHANGE(rt->r[off + 2], rt->r[off + sbsz + 2]);
708
34.4k
        EXCHANGE(rt->r[off + 4], rt->r[off + sbsz + 4]);
709
34.4k
#undef EXCHANGE
710
34.4k
    }
711
712
108k
    rt->rf = rf;
713
108k
    rt->tile_row.start = tile_row_start4;
714
108k
    rt->tile_row.end = imin(tile_row_end4, rf->ih4);
715
108k
    rt->tile_col.start = tile_col_start4;
716
108k
    rt->tile_col.end = imin(tile_col_end4, rf->iw4);
717
108k
}
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
4.00k
{
723
4.00k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
724
4.00k
    assert(row_start8 >= 0);
725
4.00k
    assert((unsigned) (row_end8 - row_start8) <= 16U);
726
4.00k
    row_end8 = imin(row_end8, rf->ih8);
727
4.00k
    const int col_start8i = imax(col_start8 - 8, 0);
728
4.00k
    const int col_end8i = imin(col_end8 + 8, rf->iw8);
729
730
4.00k
    const ptrdiff_t stride = rf->rp_stride;
731
4.00k
    refmvs_temporal_block *rp_proj =
732
4.00k
        &rf->rp_proj[16 * stride * tile_row_idx + (row_start8 & 15) * stride];
733
26.9k
    for (int y = row_start8; y < row_end8; y++) {
734
120k
        for (int x = col_start8; x < col_end8; x++)
735
97.5k
            rp_proj[x].mv.n = INVALID_MV;
736
22.9k
        rp_proj += stride;
737
22.9k
    }
738
739
4.00k
    rp_proj = &rf->rp_proj[16 * stride * tile_row_idx];
740
7.03k
    for (int n = 0; n < rf->n_mfmvs; n++) {
741
3.03k
        const int ref2cur = rf->mfmv_ref2cur[n];
742
3.03k
        if (ref2cur == INVALID_REF2CUR) continue;
743
744
2.53k
        const int ref = rf->mfmv_ref[n];
745
2.53k
        const int ref_sign = ref - 4;
746
2.53k
        const refmvs_temporal_block *r = &rf->rp_ref[ref][row_start8 * stride];
747
16.6k
        for (int y = row_start8; y < row_end8; y++) {
748
14.1k
            const int y_sb_align = y & ~7;
749
14.1k
            const int y_proj_start = imax(y_sb_align, row_start8);
750
14.1k
            const int y_proj_end = imin(y_sb_align + 8, row_end8);
751
63.8k
            for (int x = col_start8i; x < col_end8i; x++) {
752
49.7k
                const refmvs_temporal_block *rb = &r[x];
753
49.7k
                const int b_ref = rb->ref;
754
49.7k
                if (!b_ref) continue;
755
32.8k
                const int ref2ref = rf->mfmv_ref2ref[n][b_ref - 1];
756
32.8k
                if (!ref2ref) continue;
757
7.48k
                const mv b_mv = rb->mv;
758
7.48k
                const mv offset = mv_projection(b_mv, ref2cur, ref2ref);
759
7.48k
                int pos_x = x + apply_sign(abs(offset.x) >> 6,
760
7.48k
                                           offset.x ^ ref_sign);
761
7.48k
                const int pos_y = y + apply_sign(abs(offset.y) >> 6,
762
7.48k
                                                 offset.y ^ ref_sign);
763
7.48k
                if (pos_y >= y_proj_start && pos_y < y_proj_end) {
764
6.50k
                    const ptrdiff_t pos = (pos_y & 15) * stride;
765
19.7k
                    for (;;) {
766
19.7k
                        const int x_sb_align = x & ~7;
767
19.7k
                        if (pos_x >= imax(x_sb_align - 8, col_start8) &&
768
19.3k
                            pos_x < imin(x_sb_align + 16, col_end8))
769
18.4k
                        {
770
18.4k
                            rp_proj[pos + pos_x].mv = rb->mv;
771
18.4k
                            rp_proj[pos + pos_x].ref = ref2ref;
772
18.4k
                        }
773
19.7k
                        if (++x >= col_end8i) break;
774
16.0k
                        rb++;
775
16.0k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
776
13.2k
                        pos_x++;
777
13.2k
                    }
778
6.50k
                } else {
779
2.93k
                    for (;;) {
780
2.93k
                        if (++x >= col_end8i) break;
781
2.55k
                        rb++;
782
2.55k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
783
2.55k
                    }
784
978
                }
785
7.48k
                x--;
786
7.48k
            }
787
14.1k
            r += stride;
788
14.1k
        }
789
2.53k
    }
790
4.00k
}
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
11.5k
{
798
90.9k
    for (int y = row_start8; y < row_end8; y++) {
799
79.3k
        const refmvs_block *const b = rr[(y & 15) * 2];
800
801
196k
        for (int x = col_start8; x < col_end8;) {
802
117k
            const refmvs_block *const cand_b = &b[x * 2 + 1];
803
117k
            const int bw8 = (dav1d_block_dimensions[cand_b->bs][0] + 1) >> 1;
804
805
117k
            if (cand_b->ref.ref[1] > 0 && ref_sign[cand_b->ref.ref[1] - 1] &&
806
15.9k
                (abs(cand_b->mv.mv[1].y) | abs(cand_b->mv.mv[1].x)) < 4096)
807
14.8k
            {
808
14.8k
                const refmvs_temporal_block tmv = {
809
14.8k
                    .mv = cand_b->mv.mv[1],
810
14.8k
                    .ref = cand_b->ref.ref[1],
811
14.8k
                };
812
53.4k
                for (int n = 0; n < bw8; n++, x++)
813
38.6k
                    rp[x] = tmv;
814
102k
            } else if (cand_b->ref.ref[0] > 0 && ref_sign[cand_b->ref.ref[0] - 1] &&
815
36.6k
                       (abs(cand_b->mv.mv[0].y) | abs(cand_b->mv.mv[0].x)) < 4096)
816
35.3k
            {
817
35.3k
                const refmvs_temporal_block tmv = {
818
35.3k
                    .mv = cand_b->mv.mv[0],
819
35.3k
                    .ref = cand_b->ref.ref[0],
820
35.3k
                };
821
179k
                for (int n = 0; n < bw8; n++, x++)
822
143k
                    rp[x] = tmv;
823
67.2k
            } else {
824
67.2k
                memset(&rp[x], 0, bw8 * sizeof(*rp));
825
67.2k
                x += bw8;
826
67.2k
            }
827
117k
        }
828
79.3k
        rp += stride;
829
79.3k
    }
830
11.5k
}
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
29.8k
{
841
29.8k
    const int rp_stride = ((frm_hdr->width[0] + 127) & ~127) >> 3;
842
29.8k
    const int n_tile_rows = n_tile_threads > 1 ? frm_hdr->tiling.rows : 1;
843
29.8k
    const int n_blocks = rp_stride * n_tile_rows;
844
845
29.8k
    rf->sbsz = 16 << seq_hdr->sb128;
846
29.8k
    rf->frm_hdr = frm_hdr;
847
29.8k
    rf->iw8 = (frm_hdr->width[0] + 7) >> 3;
848
29.8k
    rf->ih8 = (frm_hdr->height + 7) >> 3;
849
29.8k
    rf->iw4 = rf->iw8 << 1;
850
29.8k
    rf->ih4 = rf->ih8 << 1;
851
29.8k
    rf->rp = rp;
852
29.8k
    rf->rp_stride = rp_stride;
853
29.8k
    rf->n_tile_threads = n_tile_threads;
854
29.8k
    rf->n_frame_threads = n_frame_threads;
855
856
29.8k
    if (n_blocks != rf->n_blocks) {
857
25.0k
        const size_t r_sz = sizeof(*rf->r) * 35 * 2 * n_blocks * (1 + (n_frame_threads > 1));
858
25.0k
        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
25.0k
        dav1d_free_aligned(rf->r);
862
25.0k
        rf->r = dav1d_alloc_aligned(ALLOC_REFMVS, r_sz + rp_proj_sz, 64);
863
25.0k
        if (!rf->r) {
864
0
            rf->n_blocks = 0;
865
0
            return DAV1D_ERR(ENOMEM);
866
0
        }
867
868
25.0k
        rf->rp_proj = (refmvs_temporal_block*)((uintptr_t)rf->r + r_sz);
869
25.0k
        rf->n_blocks = n_blocks;
870
25.0k
    }
871
872
29.8k
    const int poc = frm_hdr->frame_offset;
873
238k
    for (int i = 0; i < 7; i++) {
874
208k
        const int poc_diff = get_poc_diff(seq_hdr->order_hint_n_bits,
875
208k
                                          ref_poc[i], poc);
876
208k
        rf->sign_bias[i] = poc_diff > 0;
877
208k
        rf->mfmv_sign[i] = poc_diff < 0;
878
208k
        rf->pocdiff[i] = iclip(get_poc_diff(seq_hdr->order_hint_n_bits,
879
208k
                                            poc, ref_poc[i]), -31, 31);
880
208k
    }
881
882
    // temporal MV setup
883
29.8k
    rf->n_mfmvs = 0;
884
29.8k
    rf->rp_ref = rp_ref;
885
29.8k
    if (frm_hdr->use_ref_frame_mvs && seq_hdr->order_hint_n_bits) {
886
3.65k
        int total = 2;
887
3.65k
        if (rp_ref[0] && ref_ref_poc[0][6] != ref_poc[3] /* alt-of-last != gold */) {
888
730
            rf->mfmv_ref[rf->n_mfmvs++] = 0; // last
889
730
            total = 3;
890
730
        }
891
3.65k
        if (rp_ref[4] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[4],
892
1.94k
                                      frm_hdr->frame_offset) > 0)
893
299
        {
894
299
            rf->mfmv_ref[rf->n_mfmvs++] = 4; // bwd
895
299
        }
896
3.65k
        if (rp_ref[5] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[5],
897
1.88k
                                      frm_hdr->frame_offset) > 0)
898
259
        {
899
259
            rf->mfmv_ref[rf->n_mfmvs++] = 5; // altref2
900
259
        }
901
3.65k
        if (rf->n_mfmvs < total && rp_ref[6] &&
902
1.74k
            get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[6],
903
1.74k
                         frm_hdr->frame_offset) > 0)
904
389
        {
905
389
            rf->mfmv_ref[rf->n_mfmvs++] = 6; // altref
906
389
        }
907
3.65k
        if (rf->n_mfmvs < total && rp_ref[1])
908
1.12k
            rf->mfmv_ref[rf->n_mfmvs++] = 1; // last2
909
910
6.44k
        for (int n = 0; n < rf->n_mfmvs; n++) {
911
2.79k
            const int rpoc = ref_poc[rf->mfmv_ref[n]];
912
2.79k
            const int diff1 = get_poc_diff(seq_hdr->order_hint_n_bits,
913
2.79k
                                           rpoc, frm_hdr->frame_offset);
914
2.79k
            if (abs(diff1) > 31) {
915
387
                rf->mfmv_ref2cur[n] = INVALID_REF2CUR;
916
2.41k
            } else {
917
2.41k
                rf->mfmv_ref2cur[n] = rf->mfmv_ref[n] < 4 ? -diff1 : diff1;
918
19.2k
                for (int m = 0; m < 7; m++) {
919
16.8k
                    const int rrpoc = ref_ref_poc[rf->mfmv_ref[n]][m];
920
16.8k
                    const int diff2 = get_poc_diff(seq_hdr->order_hint_n_bits,
921
16.8k
                                                   rpoc, rrpoc);
922
                    // unsigned comparison also catches the < 0 case
923
16.8k
                    rf->mfmv_ref2ref[n][m] = (unsigned) diff2 > 31U ? 0 : diff2;
924
16.8k
                }
925
2.41k
            }
926
2.79k
        }
927
3.65k
    }
928
29.8k
    rf->use_ref_frame_mvs = rf->n_mfmvs > 0;
929
930
29.8k
    return 0;
931
29.8k
}
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
1.49M
{
936
5.24M
    do {
937
5.24M
        refmvs_block *const r = *rr++ + bx4;
938
58.8M
        for (int x = 0; x < bw4; x++)
939
53.6M
            r[x] = *rmv;
940
5.24M
    } while (--bh4);
941
1.49M
}
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
42.7k
{
955
42.7k
    c->load_tmvs = load_tmvs_c;
956
42.7k
    c->save_tmvs = save_tmvs_c;
957
42.7k
    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
42.7k
}