Coverage Report

Created: 2026-10-17 06:52

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
2.64M
{
48
2.64M
    if (b->mv.mv[0].n == INVALID_MV) return; // intra block, no intrabc
49
50
2.50M
    if (ref.ref[1] == -1) {
51
3.09M
        for (int n = 0; n < 2; n++) {
52
2.69M
            if (b->ref.ref[n] == ref.ref[0]) {
53
1.85M
                const mv cand_mv = ((b->mf & 1) && gmv[0].n != INVALID_MV) ?
54
1.76M
                                   gmv[0] : b->mv.mv[n];
55
56
1.85M
                *have_refmv_match = 1;
57
1.85M
                *have_newmv_match |= b->mf >> 1;
58
59
1.85M
                const int last = *cnt;
60
2.98M
                for (int m = 0; m < last; m++)
61
1.82M
                    if (mvstack[m].mv.mv[0].n == cand_mv.n) {
62
705k
                        mvstack[m].weight += weight;
63
705k
                        return;
64
705k
                    }
65
66
1.15M
                if (last < 8) {
67
1.15M
                    mvstack[last].mv.mv[0] = cand_mv;
68
1.15M
                    mvstack[last].weight = weight;
69
1.15M
                    *cnt = last + 1;
70
1.15M
                }
71
1.15M
                return;
72
1.85M
            }
73
2.69M
        }
74
2.25M
    } else if (b->ref.pair == ref.pair) {
75
86.0k
        const refmvs_mvpair cand_mv = { .mv = {
76
86.0k
            [0] = ((b->mf & 1) && gmv[0].n != INVALID_MV) ? gmv[0] : b->mv.mv[0],
77
86.0k
            [1] = ((b->mf & 1) && gmv[1].n != INVALID_MV) ? gmv[1] : b->mv.mv[1],
78
86.0k
        }};
79
80
86.0k
        *have_refmv_match = 1;
81
86.0k
        *have_newmv_match |= b->mf >> 1;
82
83
86.0k
        const int last = *cnt;
84
124k
        for (int n = 0; n < last; n++)
85
69.5k
            if (mvstack[n].mv.n == cand_mv.n) {
86
31.4k
                mvstack[n].weight += weight;
87
31.4k
                return;
88
31.4k
            }
89
90
54.6k
        if (last < 8) {
91
54.5k
            mvstack[last].mv = cand_mv;
92
54.5k
            mvstack[last].weight = weight;
93
54.5k
            *cnt = last + 1;
94
54.5k
        }
95
54.6k
    }
96
2.50M
}
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
924k
{
104
924k
    const refmvs_block *cand_b = b;
105
924k
    const enum BlockSize first_cand_bs = cand_b->bs;
106
924k
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
107
924k
    int cand_bw4 = first_cand_b_dim[0];
108
924k
    int len = imax(step, imin(bw4, cand_bw4));
109
110
924k
    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
801k
        const int weight = bw4 == 1 ? 2 :
116
801k
                           imax(2, imin(2 * max_rows, first_cand_b_dim[1]));
117
801k
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
118
801k
                              have_newmv_match, have_refmv_match);
119
801k
        return weight >> 1;
120
801k
    }
121
122
198k
    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
198k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
127
198k
                              have_newmv_match, have_refmv_match);
128
198k
        x += len;
129
198k
        if (x >= w4) return 1;
130
75.7k
        cand_b = &b[x];
131
75.7k
        cand_bw4 = dav1d_block_dimensions[cand_b->bs][0];
132
75.7k
        assert(cand_bw4 < bw4);
133
75.7k
        len = imax(step, cand_bw4);
134
75.7k
    }
135
122k
}
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.06M
{
143
1.06M
    const refmvs_block *cand_b = &b[0][bx4];
144
1.06M
    const enum BlockSize first_cand_bs = cand_b->bs;
145
1.06M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
146
1.06M
    int cand_bh4 = first_cand_b_dim[1];
147
1.06M
    int len = imax(step, imin(bh4, cand_bh4));
148
149
1.06M
    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
970k
        const int weight = bh4 == 1 ? 2 :
155
970k
                           imax(2, imin(2 * max_cols, first_cand_b_dim[0]));
156
970k
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
157
970k
                            have_newmv_match, have_refmv_match);
158
970k
        return weight >> 1;
159
970k
    }
160
161
182k
    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
182k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
166
182k
                              have_newmv_match, have_refmv_match);
167
182k
        y += len;
168
182k
        if (y >= h4) return 1;
169
89.6k
        cand_b = &b[y][bx4];
170
89.6k
        cand_bh4 = dav1d_block_dimensions[cand_b->bs][1];
171
89.6k
        assert(cand_bh4 < bh4);
172
89.6k
        len = imax(step, cand_bh4);
173
89.6k
    }
174
93.0k
}
175
176
75.1k
static inline union mv mv_projection(const union mv mv, const int num, const int den) {
177
75.1k
    static const uint16_t div_mult[32] = {
178
75.1k
           0, 16384, 8192, 5461, 4096, 3276, 2730, 2340,
179
75.1k
        2048,  1820, 1638, 1489, 1365, 1260, 1170, 1092,
180
75.1k
        1024,   963,  910,  862,  819,  780,  744,  712,
181
75.1k
         682,   655,  630,  606,  585,  564,  546,  528
182
75.1k
    };
183
75.1k
    assert(den > 0 && den < 32);
184
75.1k
    assert(num > -32 && num < 32);
185
75.1k
    const int frac = num * div_mult[den];
186
75.1k
    const int y = mv.y * frac, x = mv.x * frac;
187
    // Round and clip according to AV1 spec section 7.9.3
188
75.1k
    return (union mv) { // 0x3fff == (1 << 14) - 1
189
75.1k
        .y = iclip((y + 8192 + (y >> 31)) >> 14, -0x3fff, 0x3fff),
190
75.1k
        .x = iclip((x + 8192 + (x >> 31)) >> 14, -0x3fff, 0x3fff)
191
75.1k
    };
192
75.1k
}
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
79.2k
{
200
79.2k
    if (rb->mv.n == INVALID_MV) return;
201
202
38.0k
    union mv mv = mv_projection(rb->mv, rf->pocdiff[ref.ref[0] - 1], rb->ref);
203
38.0k
    fix_mv_precision(rf->frm_hdr, &mv);
204
205
38.0k
    const int last = *cnt;
206
38.0k
    if (ref.ref[1] == -1) {
207
24.4k
        if (globalmv_ctx)
208
13.7k
            *globalmv_ctx = (abs(mv.x - gmv[0].x) | abs(mv.y - gmv[0].y)) >= 16;
209
210
43.8k
        for (int n = 0; n < last; n++)
211
33.8k
            if (mvstack[n].mv.mv[0].n == mv.n) {
212
14.4k
                mvstack[n].weight += weight;
213
14.4k
                return;
214
14.4k
            }
215
9.94k
        if (last < 8) {
216
9.89k
            mvstack[last].mv.mv[0] = mv;
217
9.89k
            mvstack[last].weight = weight;
218
9.89k
            *cnt = last + 1;
219
9.89k
        }
220
13.6k
    } else {
221
13.6k
        refmvs_mvpair mvp = { .mv = {
222
13.6k
            [0] = mv,
223
13.6k
            [1] = mv_projection(rb->mv, rf->pocdiff[ref.ref[1] - 1], rb->ref),
224
13.6k
        }};
225
13.6k
        fix_mv_precision(rf->frm_hdr, &mvp.mv[1]);
226
227
22.4k
        for (int n = 0; n < last; n++)
228
17.7k
            if (mvstack[n].mv.n == mvp.n) {
229
8.85k
                mvstack[n].weight += weight;
230
8.85k
                return;
231
8.85k
            }
232
4.78k
        if (last < 8) {
233
4.72k
            mvstack[last].mv = mvp;
234
4.72k
            mvstack[last].weight = weight;
235
4.72k
            *cnt = last + 1;
236
4.72k
        }
237
4.78k
    }
238
38.0k
}
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
72.8k
{
247
72.8k
    refmvs_candidate *const diff = &same[2];
248
72.8k
    int *const diff_count = &same_count[2];
249
250
186k
    for (int n = 0; n < 2; n++) {
251
143k
        const int cand_ref = cand_b->ref.ref[n];
252
253
143k
        if (cand_ref <= 0) break;
254
255
113k
        mv cand_mv = cand_b->mv.mv[n];
256
113k
        if (cand_ref == ref.ref[0]) {
257
41.9k
            if (same_count[0] < 2)
258
40.9k
                same[same_count[0]++].mv.mv[0] = cand_mv;
259
41.9k
            if (diff_count[1] < 2) {
260
37.2k
                if (sign1 ^ sign_bias[cand_ref - 1]) {
261
2.87k
                    cand_mv.y = -cand_mv.y;
262
2.87k
                    cand_mv.x = -cand_mv.x;
263
2.87k
                }
264
37.2k
                diff[diff_count[1]++].mv.mv[1] = cand_mv;
265
37.2k
            }
266
71.8k
        } else if (cand_ref == ref.ref[1]) {
267
40.4k
            if (same_count[1] < 2)
268
39.7k
                same[same_count[1]++].mv.mv[1] = cand_mv;
269
40.4k
            if (diff_count[0] < 2) {
270
35.1k
                if (sign0 ^ sign_bias[cand_ref - 1]) {
271
2.72k
                    cand_mv.y = -cand_mv.y;
272
2.72k
                    cand_mv.x = -cand_mv.x;
273
2.72k
                }
274
35.1k
                diff[diff_count[0]++].mv.mv[0] = cand_mv;
275
35.1k
            }
276
40.4k
        } else {
277
31.4k
            mv i_cand_mv = (union mv) {
278
31.4k
                .x = -cand_mv.x,
279
31.4k
                .y = -cand_mv.y
280
31.4k
            };
281
282
31.4k
            if (diff_count[0] < 2) {
283
25.5k
                diff[diff_count[0]++].mv.mv[0] =
284
25.5k
                    sign0 ^ sign_bias[cand_ref - 1] ?
285
24.4k
                    i_cand_mv : cand_mv;
286
25.5k
            }
287
288
31.4k
            if (diff_count[1] < 2) {
289
23.9k
                diff[diff_count[1]++].mv.mv[1] =
290
23.9k
                    sign1 ^ sign_bias[cand_ref - 1] ?
291
23.2k
                    i_cand_mv : cand_mv;
292
23.9k
            }
293
31.4k
        }
294
113k
    }
295
72.8k
}
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
454k
{
301
912k
    for (int n = 0; n < 2; n++) {
302
895k
        const int cand_ref = cand_b->ref.ref[n];
303
304
895k
        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
457k
        mv cand_mv = cand_b->mv.mv[n];
312
457k
        if (sign ^ sign_bias[cand_ref - 1]) {
313
3.52k
            cand_mv.y = -cand_mv.y;
314
3.52k
            cand_mv.x = -cand_mv.x;
315
3.52k
        }
316
317
457k
        int m;
318
457k
        const int last = *cnt;
319
499k
        for (m = 0; m < last; m++)
320
403k
            if (cand_mv.n == mvstack[m].mv.mv[0].n)
321
362k
                break;
322
457k
        if (m == last) {
323
95.8k
            mvstack[m].mv.mv[0] = cand_mv;
324
95.8k
            mvstack[m].weight = 2; // "minimal"
325
95.8k
            *cnt = last + 1;
326
95.8k
        }
327
457k
    }
328
454k
}
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
804k
{
356
804k
    const refmvs_frame *const rf = rt->rf;
357
804k
    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
358
804k
    const int bw4 = b_dim[0], w4 = imin(imin(bw4, 16), rt->tile_col.end - bx4);
359
804k
    const int bh4 = b_dim[1], h4 = imin(imin(bh4, 16), rt->tile_row.end - by4);
360
804k
    mv gmv[2], tgmv[2];
361
362
804k
    *cnt = 0;
363
804k
    assert(ref.ref[0] >=  0 && ref.ref[0] <= 8 &&
364
804k
           ref.ref[1] >= -1 && ref.ref[1] <= 8);
365
804k
    if (ref.ref[0] > 0) {
366
551k
        tgmv[0] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[0] - 1],
367
551k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
368
551k
        gmv[0] = rf->frm_hdr->gmv[ref.ref[0] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
369
397k
                 tgmv[0] : (mv) { .n = INVALID_MV };
370
551k
    } else {
371
252k
        tgmv[0] = (mv) { .n = 0 };
372
252k
        gmv[0] = (mv) { .n = INVALID_MV };
373
252k
    }
374
804k
    if (ref.ref[1] > 0) {
375
79.3k
        tgmv[1] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[1] - 1],
376
79.3k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
377
79.3k
        gmv[1] = rf->frm_hdr->gmv[ref.ref[1] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
378
55.1k
                 tgmv[1] : (mv) { .n = INVALID_MV };
379
79.3k
    }
380
381
    // top
382
804k
    int have_newmv = 0, have_col_mvs = 0, have_row_mvs = 0;
383
804k
    unsigned max_rows = 0, n_rows = ~0;
384
804k
    const refmvs_block *b_top;
385
804k
    if (by4 > rt->tile_row.start) {
386
514k
        max_rows = imin((by4 - rt->tile_row.start + 1) >> 1, 2 + (bh4 > 1));
387
514k
        b_top = &rt->r[(by4 & 31) - 1 + 5][bx4];
388
514k
        n_rows = scan_row(mvstack, cnt, ref, gmv, b_top,
389
514k
                          bw4, w4, max_rows, bw4 >= 16 ? 4 : 1,
390
514k
                          &have_newmv, &have_row_mvs);
391
514k
    }
392
393
    // left
394
804k
    unsigned max_cols = 0, n_cols = ~0U;
395
804k
    refmvs_block *const *b_left;
396
804k
    if (bx4 > rt->tile_col.start) {
397
525k
        max_cols = imin((bx4 - rt->tile_col.start + 1) >> 1, 2 + (bw4 > 1));
398
525k
        b_left = &rt->r[(by4 & 31) + 5];
399
525k
        n_cols = scan_col(mvstack, cnt, ref, gmv, b_left,
400
525k
                          bh4, h4, bx4 - 1, max_cols, bh4 >= 16 ? 4 : 1,
401
525k
                          &have_newmv, &have_col_mvs);
402
525k
    }
403
404
    // top/right
405
804k
    if (n_rows != ~0U && edge_flags & EDGE_I444_TOP_HAS_RIGHT &&
406
339k
        imax(bw4, bh4) <= 16 && bw4 + bx4 < rt->tile_col.end)
407
179k
    {
408
179k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[bw4], ref, gmv,
409
179k
                              &have_newmv, &have_row_mvs);
410
179k
    }
411
412
804k
    const int nearest_match = have_col_mvs + have_row_mvs;
413
804k
    const int nearest_cnt = *cnt;
414
1.59M
    for (int n = 0; n < nearest_cnt; n++)
415
793k
        mvstack[n].weight += 640;
416
417
    // temporal
418
804k
    int globalmv_ctx = rf->frm_hdr->use_ref_frame_mvs;
419
804k
    if (rf->use_ref_frame_mvs) {
420
49.2k
        const ptrdiff_t stride = rf->rp_stride;
421
49.2k
        const int by8 = by4 >> 1, bx8 = bx4 >> 1;
422
49.2k
        const refmvs_temporal_block *const rbi = &rt->rp_proj[(by8 & 15) * stride + bx8];
423
49.2k
        const refmvs_temporal_block *rb = rbi;
424
49.2k
        const int step_h = bw4 >= 16 ? 2 : 1, step_v = bh4 >= 16 ? 2 : 1;
425
49.2k
        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
49.2k
        const refmvs_temporal_block *run = &rb[0];
440
49.2k
        int run_len = 1;
441
49.2k
        int *run_gmv_ctx = &globalmv_ctx;
442
128k
        for (int y = 0; y < h8; y += step_v) {
443
151k
            for (int x = y ? 0 : step_h; x < w8; x += step_h) {
444
71.7k
                const unsigned mvn = rb[x].mv.n;
445
71.7k
                if (mvn == run->mv.n &&
446
69.3k
                    (mvn == INVALID_MV || rb[x].ref == run->ref))
447
69.2k
                {
448
69.2k
                    run_len++;
449
69.2k
                    continue;
450
69.2k
                }
451
2.48k
                add_temporal_candidate(rf, mvstack, cnt, run, ref,
452
2.48k
                                       run_gmv_ctx, tgmv, 2 * run_len);
453
2.48k
                run_gmv_ctx = NULL;
454
2.48k
                run = &rb[x];
455
2.48k
                run_len = 1;
456
2.48k
            }
457
79.3k
            rb += stride * step_v;
458
79.3k
        }
459
49.2k
        add_temporal_candidate(rf, mvstack, cnt, run, ref,
460
49.2k
                               run_gmv_ctx, tgmv, 2 * run_len);
461
49.2k
        if (imin(bw4, bh4) >= 2 && imax(bw4, bh4) < 16) {
462
22.9k
            const int bh8 = bh4 >> 1, bw8 = bw4 >> 1;
463
22.9k
            rb = &rbi[bh8 * stride];
464
22.9k
            const int has_bottom = by8 + bh8 < imin(rt->tile_row.end >> 1,
465
22.9k
                                                    (by8 & ~7) + 8);
466
22.9k
            if (has_bottom && bx8 - 1 >= imax(rt->tile_col.start >> 1, bx8 & ~7)) {
467
7.89k
                add_temporal_candidate(rf, mvstack, cnt, &rb[-1], ref,
468
7.89k
                                       NULL, NULL, 2);
469
7.89k
            }
470
22.9k
            if (bx8 + bw8 < imin(rt->tile_col.end >> 1, (bx8 & ~7) + 8)) {
471
13.5k
                if (has_bottom) {
472
7.80k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8], ref,
473
7.80k
                                           NULL, NULL, 2);
474
7.80k
                }
475
13.5k
                if (by8 + bh8 - 1 < imin(rt->tile_row.end >> 1, (by8 & ~7) + 8)) {
476
11.8k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8 - stride],
477
11.8k
                                           ref, NULL, NULL, 2);
478
11.8k
                }
479
13.5k
            }
480
22.9k
        }
481
49.2k
    }
482
804k
    assert(*cnt <= 8);
483
484
    // top/left (which, confusingly, is part of "secondary" references)
485
804k
    int have_dummy_newmv_match;
486
804k
    if ((n_rows | n_cols) != ~0U) {
487
320k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[-1], ref, gmv,
488
320k
                              &have_dummy_newmv_match, &have_row_mvs);
489
320k
    }
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.41M
    for (int n = 2; n <= 3; n++) {
494
1.60M
        if ((unsigned) n > n_rows && (unsigned) n <= max_rows) {
495
409k
            n_rows += scan_row(mvstack, cnt, ref, gmv,
496
409k
                               &rt->r[(((by4 & 31) - 2 * n + 1) | 1) + 5][bx4 | 1],
497
409k
                               bw4, w4, 1 + max_rows - n, bw4 >= 16 ? 4 : 2,
498
409k
                               &have_dummy_newmv_match, &have_row_mvs);
499
409k
        }
500
501
1.60M
        if ((unsigned) n > n_cols && (unsigned) n <= max_cols) {
502
539k
            n_cols += scan_col(mvstack, cnt, ref, gmv, &rt->r[((by4 & 31) | 1) + 5],
503
539k
                               bh4, h4, (bx4 - n * 2 + 1) | 1,
504
539k
                               1 + max_cols - n, bh4 >= 16 ? 4 : 2,
505
539k
                               &have_dummy_newmv_match, &have_col_mvs);
506
539k
        }
507
1.60M
    }
508
804k
    assert(*cnt <= 8);
509
510
804k
    const int ref_match_count = have_col_mvs + have_row_mvs;
511
512
    // context build-up
513
804k
    int refmv_ctx, newmv_ctx;
514
804k
    switch (nearest_match) {
515
206k
    case 0:
516
206k
        refmv_ctx = imin(2, ref_match_count);
517
206k
        newmv_ctx = ref_match_count > 0;
518
206k
        break;
519
377k
    case 1:
520
377k
        refmv_ctx = imin(ref_match_count * 3, 4);
521
377k
        newmv_ctx = 3 - have_newmv;
522
377k
        break;
523
222k
    case 2:
524
222k
        refmv_ctx = 5;
525
222k
        newmv_ctx = 5 - have_newmv;
526
222k
        break;
527
804k
    }
528
529
    // sorting (nearest, then "secondary")
530
805k
    int len = nearest_cnt;
531
1.50M
    while (len) {
532
698k
        int last = 0;
533
933k
        for (int n = 1; n < len; n++) {
534
235k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
535
113k
#define EXCHANGE(a, b) do { refmvs_candidate tmp = a; a = b; b = tmp; } while (0)
536
104k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
537
104k
                last = n;
538
104k
            }
539
235k
        }
540
698k
        len = last;
541
698k
    }
542
805k
    len = *cnt;
543
1.12M
    while (len > nearest_cnt) {
544
319k
        int last = nearest_cnt;
545
445k
        for (int n = nearest_cnt + 1; n < len; n++) {
546
125k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
547
9.14k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
548
9.14k
#undef EXCHANGE
549
9.14k
                last = n;
550
9.14k
            }
551
125k
        }
552
319k
        len = last;
553
319k
    }
554
555
805k
    if (ref.ref[1] > 0) {
556
79.3k
        if (*cnt < 2) {
557
65.6k
            const int sign0 = rf->sign_bias[ref.ref[0] - 1];
558
65.6k
            const int sign1 = rf->sign_bias[ref.ref[1] - 1];
559
65.6k
            const int sz4 = imin(w4, h4);
560
65.6k
            refmvs_candidate *const same = &mvstack[*cnt];
561
65.6k
            int same_count[4] = { 0 };
562
563
            // non-self references in top
564
73.9k
            if (n_rows != ~0U) for (int x = 0; x < sz4;) {
565
38.1k
                const refmvs_block *const cand_b = &b_top[x];
566
38.1k
                add_compound_extended_candidate(same, same_count, cand_b,
567
38.1k
                                                sign0, sign1, ref, rf->sign_bias);
568
38.1k
                x += dav1d_block_dimensions[cand_b->bs][0];
569
38.1k
            }
570
571
            // non-self references in left
572
65.7k
            if (n_cols != ~0U) for (int y = 0; y < sz4;) {
573
34.6k
                const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
574
34.6k
                add_compound_extended_candidate(same, same_count, cand_b,
575
34.6k
                                                sign0, sign1, ref, rf->sign_bias);
576
34.6k
                y += dav1d_block_dimensions[cand_b->bs][1];
577
34.6k
            }
578
579
65.6k
            refmvs_candidate *const diff = &same[2];
580
65.6k
            const int *const diff_count = &same_count[2];
581
582
            // merge together
583
197k
            for (int n = 0; n < 2; n++) {
584
131k
                int m = same_count[n];
585
586
131k
                if (m >= 2) continue;
587
588
114k
                const int l = diff_count[n];
589
114k
                if (l) {
590
64.6k
                    same[m].mv.mv[n] = diff[0].mv.mv[n];
591
64.6k
                    if (++m == 2) continue;
592
25.7k
                    if (l == 2) {
593
15.2k
                        same[1].mv.mv[n] = diff[1].mv.mv[n];
594
15.2k
                        continue;
595
15.2k
                    }
596
25.7k
                }
597
102k
                do {
598
102k
                    same[m].mv.mv[n] = tgmv[n];
599
102k
                } while (++m < 2);
600
59.9k
            }
601
602
            // if the first extended was the same as the non-extended one,
603
            // then replace it with the second extended one
604
65.6k
            int n = *cnt;
605
65.6k
            if (n == 1 && mvstack[0].mv.n == same[0].mv.n)
606
17.5k
                mvstack[1].mv = mvstack[2].mv;
607
107k
            do {
608
107k
                mvstack[n].weight = 2;
609
107k
            } while (++n < 2);
610
65.6k
            *cnt = 2;
611
65.6k
        }
612
613
        // clamping
614
79.3k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
615
79.3k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
616
79.3k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
617
79.3k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
618
619
79.3k
        const int n_refmvs = *cnt;
620
79.3k
        int n = 0;
621
167k
        do {
622
167k
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
623
167k
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
624
167k
            mvstack[n].mv.mv[1].x = iclip(mvstack[n].mv.mv[1].x, left, right);
625
167k
            mvstack[n].mv.mv[1].y = iclip(mvstack[n].mv.mv[1].y, top, bottom);
626
167k
        } while (++n < n_refmvs);
627
628
79.3k
        switch (refmv_ctx >> 1) {
629
46.5k
        case 0:
630
46.5k
            *ctx = imin(newmv_ctx, 1);
631
46.5k
            break;
632
22.5k
        case 1:
633
22.5k
            *ctx = 1 + imin(newmv_ctx, 3);
634
22.5k
            break;
635
10.3k
        case 2:
636
10.3k
            *ctx = iclip(3 + newmv_ctx, 4, 7);
637
10.3k
            break;
638
79.3k
        }
639
640
79.3k
        return;
641
725k
    } else if (*cnt < 2 && ref.ref[0] > 0) {
642
386k
        const int sign = rf->sign_bias[ref.ref[0] - 1];
643
386k
        const int sz4 = imin(w4, h4);
644
645
        // non-self references in top
646
544k
        if (n_rows != ~0U) for (int x = 0; x < sz4 && *cnt < 2;) {
647
278k
            const refmvs_block *const cand_b = &b_top[x];
648
278k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
649
278k
            x += dav1d_block_dimensions[cand_b->bs][0];
650
278k
        }
651
652
        // non-self references in left
653
386k
        if (n_cols != ~0U) for (int y = 0; y < sz4 && *cnt < 2;) {
654
176k
            const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
655
176k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
656
176k
            y += dav1d_block_dimensions[cand_b->bs][1];
657
176k
        }
658
386k
    }
659
725k
    assert(*cnt <= 8);
660
661
    // clamping
662
725k
    int n_refmvs = *cnt;
663
725k
    if (n_refmvs) {
664
640k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
665
640k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
666
640k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
667
640k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
668
669
640k
        int n = 0;
670
1.26M
        do {
671
1.26M
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
672
1.26M
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
673
1.26M
        } while (++n < n_refmvs);
674
640k
    }
675
676
1.19M
    for (int n = *cnt; n < 2; n++)
677
470k
        mvstack[n].mv.mv[0] = tgmv[0];
678
679
725k
    *ctx = (refmv_ctx << 4) | (globalmv_ctx << 3) | newmv_ctx;
680
725k
}
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
342k
{
687
342k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
688
342k
    rt->rp_proj = &rf->rp_proj[16 * rf->rp_stride * tile_row_idx];
689
342k
    const ptrdiff_t r_stride = rf->rp_stride * 2;
690
342k
    const ptrdiff_t pass_off = (rf->n_frame_threads > 1 && pass == 2) ?
691
177k
        35 * 2 * rf->n_blocks : 0;
692
342k
    refmvs_block *r = &rf->r[35 * r_stride * tile_row_idx + pass_off];
693
342k
    const int sbsz = rf->sbsz;
694
342k
    const int off = (sbsz * sby) & 16;
695
6.81M
    for (int i = 0; i < sbsz; i++, r += r_stride)
696
6.47M
        rt->r[off + 5 + i] = r;
697
342k
    rt->r[off + 0] = r;
698
342k
    r += r_stride;
699
342k
    rt->r[off + 1] = NULL;
700
342k
    rt->r[off + 2] = r;
701
342k
    r += r_stride;
702
342k
    rt->r[off + 3] = NULL;
703
342k
    rt->r[off + 4] = r;
704
342k
    if (sby & 1) {
705
314k
#define EXCHANGE(a, b) do { void *const tmp = a; a = b; b = tmp; } while (0)
706
104k
        EXCHANGE(rt->r[off + 0], rt->r[off + sbsz + 0]);
707
104k
        EXCHANGE(rt->r[off + 2], rt->r[off + sbsz + 2]);
708
104k
        EXCHANGE(rt->r[off + 4], rt->r[off + sbsz + 4]);
709
104k
#undef EXCHANGE
710
104k
    }
711
712
342k
    rt->rf = rf;
713
342k
    rt->tile_row.start = tile_row_start4;
714
342k
    rt->tile_row.end = imin(tile_row_end4, rf->ih4);
715
342k
    rt->tile_col.start = tile_col_start4;
716
342k
    rt->tile_col.end = imin(tile_col_end4, rf->iw4);
717
342k
}
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
25.4k
{
723
25.4k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
724
25.4k
    assert(row_start8 >= 0);
725
25.4k
    assert((unsigned) (row_end8 - row_start8) <= 16U);
726
25.4k
    row_end8 = imin(row_end8, rf->ih8);
727
25.4k
    const int col_start8i = imax(col_start8 - 8, 0);
728
25.4k
    const int col_end8i = imin(col_end8 + 8, rf->iw8);
729
730
25.4k
    const ptrdiff_t stride = rf->rp_stride;
731
25.4k
    refmvs_temporal_block *rp_proj =
732
25.4k
        &rf->rp_proj[16 * stride * tile_row_idx + (row_start8 & 15) * stride];
733
120k
    for (int y = row_start8; y < row_end8; y++) {
734
583k
        for (int x = col_start8; x < col_end8; x++)
735
488k
            rp_proj[x].mv.n = INVALID_MV;
736
95.1k
        rp_proj += stride;
737
95.1k
    }
738
739
25.4k
    rp_proj = &rf->rp_proj[16 * stride * tile_row_idx];
740
54.0k
    for (int n = 0; n < rf->n_mfmvs; n++) {
741
28.6k
        const int ref2cur = rf->mfmv_ref2cur[n];
742
28.6k
        if (ref2cur == INVALID_REF2CUR) continue;
743
744
15.3k
        const int ref = rf->mfmv_ref[n];
745
15.3k
        const int ref_sign = ref - 4;
746
15.3k
        const refmvs_temporal_block *r = &rf->rp_ref[ref][row_start8 * stride];
747
59.2k
        for (int y = row_start8; y < row_end8; y++) {
748
43.9k
            const int y_sb_align = y & ~7;
749
43.9k
            const int y_proj_start = imax(y_sb_align, row_start8);
750
43.9k
            const int y_proj_end = imin(y_sb_align + 8, row_end8);
751
147k
            for (int x = col_start8i; x < col_end8i; x++) {
752
103k
                const refmvs_temporal_block *rb = &r[x];
753
103k
                const int b_ref = rb->ref;
754
103k
                if (!b_ref) continue;
755
36.5k
                const int ref2ref = rf->mfmv_ref2ref[n][b_ref - 1];
756
36.5k
                if (!ref2ref) continue;
757
23.4k
                const mv b_mv = rb->mv;
758
23.4k
                const mv offset = mv_projection(b_mv, ref2cur, ref2ref);
759
23.4k
                int pos_x = x + apply_sign(abs(offset.x) >> 6,
760
23.4k
                                           offset.x ^ ref_sign);
761
23.4k
                const int pos_y = y + apply_sign(abs(offset.y) >> 6,
762
23.4k
                                                 offset.y ^ ref_sign);
763
23.4k
                if (pos_y >= y_proj_start && pos_y < y_proj_end) {
764
22.0k
                    const ptrdiff_t pos = (pos_y & 15) * stride;
765
95.6k
                    for (;;) {
766
95.6k
                        const int x_sb_align = x & ~7;
767
95.6k
                        if (pos_x >= imax(x_sb_align - 8, col_start8) &&
768
93.8k
                            pos_x < imin(x_sb_align + 16, col_end8))
769
92.0k
                        {
770
92.0k
                            rp_proj[pos + pos_x].mv = rb->mv;
771
92.0k
                            rp_proj[pos + pos_x].ref = ref2ref;
772
92.0k
                        }
773
95.6k
                        if (++x >= col_end8i) break;
774
78.4k
                        rb++;
775
78.4k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
776
73.6k
                        pos_x++;
777
73.6k
                    }
778
22.0k
                } else {
779
4.20k
                    for (;;) {
780
4.20k
                        if (++x >= col_end8i) break;
781
3.65k
                        rb++;
782
3.65k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
783
3.65k
                    }
784
1.38k
                }
785
23.4k
                x--;
786
23.4k
            }
787
43.9k
            r += stride;
788
43.9k
        }
789
15.3k
    }
790
25.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
43.0k
{
798
242k
    for (int y = row_start8; y < row_end8; y++) {
799
199k
        const refmvs_block *const b = rr[(y & 15) * 2];
800
801
565k
        for (int x = col_start8; x < col_end8;) {
802
365k
            const refmvs_block *const cand_b = &b[x * 2 + 1];
803
365k
            const int bw8 = (dav1d_block_dimensions[cand_b->bs][0] + 1) >> 1;
804
805
365k
            if (cand_b->ref.ref[1] > 0 && ref_sign[cand_b->ref.ref[1] - 1] &&
806
41.3k
                (abs(cand_b->mv.mv[1].y) | abs(cand_b->mv.mv[1].x)) < 4096)
807
35.9k
            {
808
35.9k
                const refmvs_temporal_block tmv = {
809
35.9k
                    .mv = cand_b->mv.mv[1],
810
35.9k
                    .ref = cand_b->ref.ref[1],
811
35.9k
                };
812
135k
                for (int n = 0; n < bw8; n++, x++)
813
99.5k
                    rp[x] = tmv;
814
330k
            } else if (cand_b->ref.ref[0] > 0 && ref_sign[cand_b->ref.ref[0] - 1] &&
815
153k
                       (abs(cand_b->mv.mv[0].y) | abs(cand_b->mv.mv[0].x)) < 4096)
816
150k
            {
817
150k
                const refmvs_temporal_block tmv = {
818
150k
                    .mv = cand_b->mv.mv[0],
819
150k
                    .ref = cand_b->ref.ref[0],
820
150k
                };
821
552k
                for (int n = 0; n < bw8; n++, x++)
822
402k
                    rp[x] = tmv;
823
179k
            } else {
824
179k
                memset(&rp[x], 0, bw8 * sizeof(*rp));
825
179k
                x += bw8;
826
179k
            }
827
365k
        }
828
199k
        rp += stride;
829
199k
    }
830
43.0k
}
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
104k
{
841
104k
    const int rp_stride = ((frm_hdr->width[0] + 127) & ~127) >> 3;
842
18.4E
    const int n_tile_rows = n_tile_threads > 1 ? frm_hdr->tiling.rows : 1;
843
104k
    const int n_blocks = rp_stride * n_tile_rows;
844
845
104k
    rf->sbsz = 16 << seq_hdr->sb128;
846
104k
    rf->frm_hdr = frm_hdr;
847
104k
    rf->iw8 = (frm_hdr->width[0] + 7) >> 3;
848
104k
    rf->ih8 = (frm_hdr->height + 7) >> 3;
849
104k
    rf->iw4 = rf->iw8 << 1;
850
104k
    rf->ih4 = rf->ih8 << 1;
851
104k
    rf->rp = rp;
852
104k
    rf->rp_stride = rp_stride;
853
104k
    rf->n_tile_threads = n_tile_threads;
854
104k
    rf->n_frame_threads = n_frame_threads;
855
856
104k
    if (n_blocks != rf->n_blocks) {
857
29.4k
        const size_t r_sz = sizeof(*rf->r) * 35 * 2 * n_blocks * (1 + (n_frame_threads > 1));
858
29.4k
        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
29.4k
        dav1d_free_aligned(rf->r);
862
29.4k
        rf->r = dav1d_alloc_aligned(ALLOC_REFMVS, r_sz + rp_proj_sz, 64);
863
29.4k
        if (!rf->r) {
864
0
            rf->n_blocks = 0;
865
0
            return DAV1D_ERR(ENOMEM);
866
0
        }
867
868
29.4k
        rf->rp_proj = (refmvs_temporal_block*)((uintptr_t)rf->r + r_sz);
869
29.4k
        rf->n_blocks = n_blocks;
870
29.4k
    }
871
872
104k
    const int poc = frm_hdr->frame_offset;
873
836k
    for (int i = 0; i < 7; i++) {
874
731k
        const int poc_diff = get_poc_diff(seq_hdr->order_hint_n_bits,
875
731k
                                          ref_poc[i], poc);
876
731k
        rf->sign_bias[i] = poc_diff > 0;
877
731k
        rf->mfmv_sign[i] = poc_diff < 0;
878
731k
        rf->pocdiff[i] = iclip(get_poc_diff(seq_hdr->order_hint_n_bits,
879
731k
                                            poc, ref_poc[i]), -31, 31);
880
731k
    }
881
882
    // temporal MV setup
883
104k
    rf->n_mfmvs = 0;
884
104k
    rf->rp_ref = rp_ref;
885
104k
    if (frm_hdr->use_ref_frame_mvs && seq_hdr->order_hint_n_bits) {
886
21.8k
        int total = 2;
887
21.8k
        if (rp_ref[0] && ref_ref_poc[0][6] != ref_poc[3] /* alt-of-last != gold */) {
888
8.46k
            rf->mfmv_ref[rf->n_mfmvs++] = 0; // last
889
8.46k
            total = 3;
890
8.46k
        }
891
21.8k
        if (rp_ref[4] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[4],
892
17.4k
                                      frm_hdr->frame_offset) > 0)
893
796
        {
894
796
            rf->mfmv_ref[rf->n_mfmvs++] = 4; // bwd
895
796
        }
896
21.8k
        if (rp_ref[5] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[5],
897
14.3k
                                      frm_hdr->frame_offset) > 0)
898
765
        {
899
765
            rf->mfmv_ref[rf->n_mfmvs++] = 5; // altref2
900
765
        }
901
21.8k
        if (rf->n_mfmvs < total && rp_ref[6] &&
902
16.1k
            get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[6],
903
16.1k
                         frm_hdr->frame_offset) > 0)
904
6.60k
        {
905
6.60k
            rf->mfmv_ref[rf->n_mfmvs++] = 6; // altref
906
6.60k
        }
907
21.8k
        if (rf->n_mfmvs < total && rp_ref[1])
908
10.7k
            rf->mfmv_ref[rf->n_mfmvs++] = 1; // last2
909
910
49.3k
        for (int n = 0; n < rf->n_mfmvs; n++) {
911
27.4k
            const int rpoc = ref_poc[rf->mfmv_ref[n]];
912
27.4k
            const int diff1 = get_poc_diff(seq_hdr->order_hint_n_bits,
913
27.4k
                                           rpoc, frm_hdr->frame_offset);
914
27.4k
            if (abs(diff1) > 31) {
915
13.3k
                rf->mfmv_ref2cur[n] = INVALID_REF2CUR;
916
14.0k
            } else {
917
14.0k
                rf->mfmv_ref2cur[n] = rf->mfmv_ref[n] < 4 ? -diff1 : diff1;
918
112k
                for (int m = 0; m < 7; m++) {
919
98.4k
                    const int rrpoc = ref_ref_poc[rf->mfmv_ref[n]][m];
920
98.4k
                    const int diff2 = get_poc_diff(seq_hdr->order_hint_n_bits,
921
98.4k
                                                   rpoc, rrpoc);
922
                    // unsigned comparison also catches the < 0 case
923
98.4k
                    rf->mfmv_ref2ref[n][m] = (unsigned) diff2 > 31U ? 0 : diff2;
924
98.4k
                }
925
14.0k
            }
926
27.4k
        }
927
21.8k
    }
928
104k
    rf->use_ref_frame_mvs = rf->n_mfmvs > 0;
929
930
104k
    return 0;
931
104k
}
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.07M
{
936
4.37M
    do {
937
4.37M
        refmvs_block *const r = *rr++ + bx4;
938
34.6M
        for (int x = 0; x < bw4; x++)
939
30.3M
            r[x] = *rmv;
940
4.37M
    } while (--bh4);
941
1.07M
}
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
32.8k
{
955
32.8k
    c->load_tmvs = load_tmvs_c;
956
32.8k
    c->save_tmvs = save_tmvs_c;
957
32.8k
    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
32.8k
}