Coverage Report

Created: 2026-08-31 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/dav1d/src/refmvs.c
Line
Count
Source
1
/*
2
 * Copyright © 2020, VideoLAN and dav1d authors
3
 * Copyright © 2020, Two Orioles, LLC
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions are met:
8
 *
9
 * 1. Redistributions of source code must retain the above copyright notice, this
10
 *    list of conditions and the following disclaimer.
11
 *
12
 * 2. Redistributions in binary form must reproduce the above copyright notice,
13
 *    this list of conditions and the following disclaimer in the documentation
14
 *    and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 */
27
28
#include "config.h"
29
30
#include <limits.h>
31
#include <stdlib.h>
32
33
#include "dav1d/common.h"
34
35
#include "common/intops.h"
36
37
#include "src/env.h"
38
#include "src/mem.h"
39
#include "src/refmvs.h"
40
41
static void add_spatial_candidate(refmvs_candidate *const mvstack, int *const cnt,
42
                                  const int weight, const refmvs_block *const b,
43
                                  const union refmvs_refpair ref, const mv gmv[2],
44
                                  int *const have_newmv_match,
45
                                  int *const have_refmv_match)
46
3.68M
{
47
3.68M
    if (b->mv.mv[0].n == INVALID_MV) return; // intra block, no intrabc
48
49
3.42M
    if (ref.ref[1] == -1) {
50
4.19M
        for (int n = 0; n < 2; n++) {
51
3.59M
            if (b->ref.ref[n] == ref.ref[0]) {
52
2.31M
                const mv cand_mv = ((b->mf & 1) && gmv[0].n != INVALID_MV) ?
53
2.26M
                                   gmv[0] : b->mv.mv[n];
54
55
2.31M
                *have_refmv_match = 1;
56
2.31M
                *have_newmv_match |= b->mf >> 1;
57
58
2.31M
                const int last = *cnt;
59
3.41M
                for (int m = 0; m < last; m++)
60
2.46M
                    if (mvstack[m].mv.mv[0].n == cand_mv.n) {
61
1.37M
                        mvstack[m].weight += weight;
62
1.37M
                        return;
63
1.37M
                    }
64
65
944k
                if (last < 8) {
66
943k
                    mvstack[last].mv.mv[0] = cand_mv;
67
943k
                    mvstack[last].weight = weight;
68
943k
                    *cnt = last + 1;
69
943k
                }
70
944k
                return;
71
2.31M
            }
72
3.59M
        }
73
2.92M
    } else if (b->ref.pair == ref.pair) {
74
166k
        const refmvs_mvpair cand_mv = { .mv = {
75
166k
            [0] = ((b->mf & 1) && gmv[0].n != INVALID_MV) ? gmv[0] : b->mv.mv[0],
76
166k
            [1] = ((b->mf & 1) && gmv[1].n != INVALID_MV) ? gmv[1] : b->mv.mv[1],
77
166k
        }};
78
79
166k
        *have_refmv_match = 1;
80
166k
        *have_newmv_match |= b->mf >> 1;
81
82
166k
        const int last = *cnt;
83
270k
        for (int n = 0; n < last; n++)
84
159k
            if (mvstack[n].mv.n == cand_mv.n) {
85
55.3k
                mvstack[n].weight += weight;
86
55.3k
                return;
87
55.3k
            }
88
89
111k
        if (last < 8) {
90
111k
            mvstack[last].mv = cand_mv;
91
111k
            mvstack[last].weight = weight;
92
111k
            *cnt = last + 1;
93
111k
        }
94
111k
    }
95
3.42M
}
96
97
static int scan_row(refmvs_candidate *const mvstack, int *const cnt,
98
                    const union refmvs_refpair ref, const mv gmv[2],
99
                    const refmvs_block *b, const int bw4, const int w4,
100
                    const int max_rows, const int step,
101
                    int *const have_newmv_match, int *const have_refmv_match)
102
1.15M
{
103
1.15M
    const refmvs_block *cand_b = b;
104
1.15M
    const enum BlockSize first_cand_bs = cand_b->bs;
105
1.15M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
106
1.15M
    int cand_bw4 = first_cand_b_dim[0];
107
1.15M
    int len = imax(step, imin(bw4, cand_bw4));
108
109
1.15M
    if (bw4 <= cand_bw4) {
110
        // FIXME weight can be higher for odd blocks (bx4 & 1), but then the
111
        // position of the first block has to be odd already, i.e. not just
112
        // for row_offset=-3/-5
113
        // FIXME why can this not be cand_bw4?
114
999k
        const int weight = bw4 == 1 ? 2 :
115
999k
                           imax(2, imin(2 * max_rows, first_cand_b_dim[1]));
116
999k
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
117
999k
                              have_newmv_match, have_refmv_match);
118
999k
        return weight >> 1;
119
999k
    }
120
121
329k
    for (int x = 0;;) {
122
        // FIXME if we overhang above, we could fill a bitmask so we don't have
123
        // to repeat the add_spatial_candidate() for the next row, but just increase
124
        // the weight here
125
329k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
126
329k
                              have_newmv_match, have_refmv_match);
127
329k
        x += len;
128
329k
        if (x >= w4) return 1;
129
170k
        cand_b = &b[x];
130
170k
        cand_bw4 = dav1d_block_dimensions[cand_b->bs][0];
131
170k
        assert(cand_bw4 < bw4);
132
170k
        len = imax(step, cand_bw4);
133
170k
    }
134
159k
}
135
136
static int scan_col(refmvs_candidate *const mvstack, int *const cnt,
137
                    const union refmvs_refpair ref, const mv gmv[2],
138
                    /*const*/ refmvs_block *const *b, const int bh4, const int h4,
139
                    const int bx4, const int max_cols, const int step,
140
                    int *const have_newmv_match, int *const have_refmv_match)
141
1.32M
{
142
1.32M
    const refmvs_block *cand_b = &b[0][bx4];
143
1.32M
    const enum BlockSize first_cand_bs = cand_b->bs;
144
1.32M
    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
145
1.32M
    int cand_bh4 = first_cand_b_dim[1];
146
1.32M
    int len = imax(step, imin(bh4, cand_bh4));
147
148
1.32M
    if (bh4 <= cand_bh4) {
149
        // FIXME weight can be higher for odd blocks (by4 & 1), but then the
150
        // position of the first block has to be odd already, i.e. not just
151
        // for col_offset=-3/-5
152
        // FIXME why can this not be cand_bh4?
153
1.12M
        const int weight = bh4 == 1 ? 2 :
154
1.12M
                           imax(2, imin(2 * max_cols, first_cand_b_dim[0]));
155
1.12M
        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
156
1.12M
                            have_newmv_match, have_refmv_match);
157
1.12M
        return weight >> 1;
158
1.12M
    }
159
160
411k
    for (int y = 0;;) {
161
        // FIXME if we overhang above, we could fill a bitmask so we don't have
162
        // to repeat the add_spatial_candidate() for the next row, but just increase
163
        // the weight here
164
411k
        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
165
411k
                              have_newmv_match, have_refmv_match);
166
411k
        y += len;
167
411k
        if (y >= h4) return 1;
168
207k
        cand_b = &b[y][bx4];
169
207k
        cand_bh4 = dav1d_block_dimensions[cand_b->bs][1];
170
207k
        assert(cand_bh4 < bh4);
171
207k
        len = imax(step, cand_bh4);
172
207k
    }
173
203k
}
174
175
28.0k
static inline union mv mv_projection(const union mv mv, const int num, const int den) {
176
28.0k
    static const uint16_t div_mult[32] = {
177
28.0k
           0, 16384, 8192, 5461, 4096, 3276, 2730, 2340,
178
28.0k
        2048,  1820, 1638, 1489, 1365, 1260, 1170, 1092,
179
28.0k
        1024,   963,  910,  862,  819,  780,  744,  712,
180
28.0k
         682,   655,  630,  606,  585,  564,  546,  528
181
28.0k
    };
182
28.0k
    assert(den > 0 && den < 32);
183
28.0k
    assert(num > -32 && num < 32);
184
28.0k
    const int frac = num * div_mult[den];
185
28.0k
    const int y = mv.y * frac, x = mv.x * frac;
186
    // Round and clip according to AV1 spec section 7.9.3
187
28.0k
    return (union mv) { // 0x3fff == (1 << 14) - 1
188
28.0k
        .y = iclip((y + 8192 + (y >> 31)) >> 14, -0x3fff, 0x3fff),
189
28.0k
        .x = iclip((x + 8192 + (x >> 31)) >> 14, -0x3fff, 0x3fff)
190
28.0k
    };
191
28.0k
}
192
193
static void add_temporal_candidate(const refmvs_frame *const rf,
194
                                   refmvs_candidate *const mvstack, int *const cnt,
195
                                   const refmvs_temporal_block *const rb,
196
                                   const union refmvs_refpair ref, int *const globalmv_ctx,
197
                                   const union mv gmv[])
198
45.1k
{
199
45.1k
    if (rb->mv.n == INVALID_MV) return;
200
201
12.1k
    union mv mv = mv_projection(rb->mv, rf->pocdiff[ref.ref[0] - 1], rb->ref);
202
12.1k
    fix_mv_precision(rf->frm_hdr, &mv);
203
204
12.1k
    const int last = *cnt;
205
12.1k
    if (ref.ref[1] == -1) {
206
10.1k
        if (globalmv_ctx)
207
2.04k
            *globalmv_ctx = (abs(mv.x - gmv[0].x) | abs(mv.y - gmv[0].y)) >= 16;
208
209
11.4k
        for (int n = 0; n < last; n++)
210
9.54k
            if (mvstack[n].mv.mv[0].n == mv.n) {
211
8.24k
                mvstack[n].weight += 2;
212
8.24k
                return;
213
8.24k
            }
214
1.92k
        if (last < 8) {
215
1.92k
            mvstack[last].mv.mv[0] = mv;
216
1.92k
            mvstack[last].weight = 2;
217
1.92k
            *cnt = last + 1;
218
1.92k
        }
219
1.97k
    } else {
220
1.97k
        refmvs_mvpair mvp = { .mv = {
221
1.97k
            [0] = mv,
222
1.97k
            [1] = mv_projection(rb->mv, rf->pocdiff[ref.ref[1] - 1], rb->ref),
223
1.97k
        }};
224
1.97k
        fix_mv_precision(rf->frm_hdr, &mvp.mv[1]);
225
226
2.74k
        for (int n = 0; n < last; n++)
227
2.16k
            if (mvstack[n].mv.n == mvp.n) {
228
1.39k
                mvstack[n].weight += 2;
229
1.39k
                return;
230
1.39k
            }
231
576
        if (last < 8) {
232
576
            mvstack[last].mv = mvp;
233
576
            mvstack[last].weight = 2;
234
576
            *cnt = last + 1;
235
576
        }
236
576
    }
237
12.1k
}
238
239
static void add_compound_extended_candidate(refmvs_candidate *const same,
240
                                            int *const same_count,
241
                                            const refmvs_block *const cand_b,
242
                                            const int sign0, const int sign1,
243
                                            const union refmvs_refpair ref,
244
                                            const uint8_t *const sign_bias)
245
115k
{
246
115k
    refmvs_candidate *const diff = &same[2];
247
115k
    int *const diff_count = &same_count[2];
248
249
293k
    for (int n = 0; n < 2; n++) {
250
226k
        const int cand_ref = cand_b->ref.ref[n];
251
252
226k
        if (cand_ref <= 0) break;
253
254
178k
        mv cand_mv = cand_b->mv.mv[n];
255
178k
        if (cand_ref == ref.ref[0]) {
256
65.0k
            if (same_count[0] < 2)
257
62.3k
                same[same_count[0]++].mv.mv[0] = cand_mv;
258
65.0k
            if (diff_count[1] < 2) {
259
54.1k
                if (sign1 ^ sign_bias[cand_ref - 1]) {
260
526
                    cand_mv.y = -cand_mv.y;
261
526
                    cand_mv.x = -cand_mv.x;
262
526
                }
263
54.1k
                diff[diff_count[1]++].mv.mv[1] = cand_mv;
264
54.1k
            }
265
113k
        } else if (cand_ref == ref.ref[1]) {
266
57.7k
            if (same_count[1] < 2)
267
56.1k
                same[same_count[1]++].mv.mv[1] = cand_mv;
268
57.7k
            if (diff_count[0] < 2) {
269
46.4k
                if (sign0 ^ sign_bias[cand_ref - 1]) {
270
695
                    cand_mv.y = -cand_mv.y;
271
695
                    cand_mv.x = -cand_mv.x;
272
695
                }
273
46.4k
                diff[diff_count[0]++].mv.mv[0] = cand_mv;
274
46.4k
            }
275
57.7k
        } else {
276
55.8k
            mv i_cand_mv = (union mv) {
277
55.8k
                .x = -cand_mv.x,
278
55.8k
                .y = -cand_mv.y
279
55.8k
            };
280
281
55.8k
            if (diff_count[0] < 2) {
282
43.2k
                diff[diff_count[0]++].mv.mv[0] =
283
43.2k
                    sign0 ^ sign_bias[cand_ref - 1] ?
284
42.6k
                    i_cand_mv : cand_mv;
285
43.2k
            }
286
287
55.8k
            if (diff_count[1] < 2) {
288
39.9k
                diff[diff_count[1]++].mv.mv[1] =
289
39.9k
                    sign1 ^ sign_bias[cand_ref - 1] ?
290
39.3k
                    i_cand_mv : cand_mv;
291
39.9k
            }
292
55.8k
        }
293
178k
    }
294
115k
}
295
296
static void add_single_extended_candidate(refmvs_candidate mvstack[8], int *const cnt,
297
                                          const refmvs_block *const cand_b,
298
                                          const int sign, const uint8_t *const sign_bias)
299
529k
{
300
1.05M
    for (int n = 0; n < 2; n++) {
301
1.03M
        const int cand_ref = cand_b->ref.ref[n];
302
303
1.03M
        if (cand_ref <= 0) break;
304
        // we need to continue even if cand_ref == ref.ref[0], since
305
        // the candidate could have been added as a globalmv variant,
306
        // which changes the value
307
        // FIXME if scan_{row,col}() returned a mask for the nearest
308
        // edge, we could skip the appropriate ones here
309
310
524k
        mv cand_mv = cand_b->mv.mv[n];
311
524k
        if (sign ^ sign_bias[cand_ref - 1]) {
312
869
            cand_mv.y = -cand_mv.y;
313
869
            cand_mv.x = -cand_mv.x;
314
869
        }
315
316
524k
        int m;
317
524k
        const int last = *cnt;
318
588k
        for (m = 0; m < last; m++)
319
496k
            if (cand_mv.n == mvstack[m].mv.mv[0].n)
320
433k
                break;
321
524k
        if (m == last) {
322
91.6k
            mvstack[m].mv.mv[0] = cand_mv;
323
91.6k
            mvstack[m].weight = 2; // "minimal"
324
91.6k
            *cnt = last + 1;
325
91.6k
        }
326
524k
    }
327
529k
}
328
329
/*
330
 * refmvs_frame allocates memory for one sbrow (32 blocks high, whole frame
331
 * wide) of 4x4-resolution refmvs_block entries for spatial MV referencing.
332
 * mvrefs_tile[] keeps a list of 35 (32 + 3 above) pointers into this memory,
333
 * and each sbrow, the bottom entries (y=27/29/31) are exchanged with the top
334
 * (-5/-3/-1) pointers by calling dav1d_refmvs_tile_sbrow_init() at the start
335
 * of each tile/sbrow.
336
 *
337
 * For temporal MV referencing, we call dav1d_refmvs_save_tmvs() at the end of
338
 * each tile/sbrow (when tile column threading is enabled), or at the start of
339
 * each interleaved sbrow (i.e. once for all tile columns together, when tile
340
 * column threading is disabled). This will copy the 4x4-resolution spatial MVs
341
 * into 8x8-resolution refmvs_temporal_block structures. Then, for subsequent
342
 * frames, at the start of each tile/sbrow (when tile column threading is
343
 * enabled) or at the start of each interleaved sbrow (when tile column
344
 * threading is disabled), we call load_tmvs(), which will project the MVs to
345
 * their respective position in the current frame.
346
 */
347
348
void dav1d_refmvs_find(const refmvs_tile *const rt,
349
                       refmvs_candidate mvstack[8], int *const cnt,
350
                       int *const ctx,
351
                       const union refmvs_refpair ref, const enum BlockSize bs,
352
                       const enum EdgeFlags edge_flags,
353
                       const int by4, const int bx4)
354
675k
{
355
675k
    const refmvs_frame *const rf = rt->rf;
356
675k
    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
357
675k
    const int bw4 = b_dim[0], w4 = imin(imin(bw4, 16), rt->tile_col.end - bx4);
358
675k
    const int bh4 = b_dim[1], h4 = imin(imin(bh4, 16), rt->tile_row.end - by4);
359
675k
    mv gmv[2], tgmv[2];
360
361
675k
    *cnt = 0;
362
675k
    assert(ref.ref[0] >=  0 && ref.ref[0] <= 8 &&
363
675k
           ref.ref[1] >= -1 && ref.ref[1] <= 8);
364
675k
    if (ref.ref[0] > 0) {
365
603k
        tgmv[0] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[0] - 1],
366
603k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
367
603k
        gmv[0] = rf->frm_hdr->gmv[ref.ref[0] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
368
450k
                 tgmv[0] : (mv) { .n = INVALID_MV };
369
603k
    } else {
370
72.0k
        tgmv[0] = (mv) { .n = 0 };
371
72.0k
        gmv[0] = (mv) { .n = INVALID_MV };
372
72.0k
    }
373
675k
    if (ref.ref[1] > 0) {
374
99.2k
        tgmv[1] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[1] - 1],
375
99.2k
                             bx4, by4, bw4, bh4, rf->frm_hdr);
376
99.2k
        gmv[1] = rf->frm_hdr->gmv[ref.ref[1] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
377
57.3k
                 tgmv[1] : (mv) { .n = INVALID_MV };
378
99.2k
    }
379
380
    // top
381
675k
    int have_newmv = 0, have_col_mvs = 0, have_row_mvs = 0;
382
675k
    unsigned max_rows = 0, n_rows = ~0;
383
675k
    const refmvs_block *b_top;
384
675k
    if (by4 > rt->tile_row.start) {
385
551k
        max_rows = imin((by4 - rt->tile_row.start + 1) >> 1, 2 + (bh4 > 1));
386
551k
        b_top = &rt->r[(by4 & 31) - 1 + 5][bx4];
387
551k
        n_rows = scan_row(mvstack, cnt, ref, gmv, b_top,
388
551k
                          bw4, w4, max_rows, bw4 >= 16 ? 4 : 1,
389
551k
                          &have_newmv, &have_row_mvs);
390
551k
    }
391
392
    // left
393
675k
    unsigned max_cols = 0, n_cols = ~0U;
394
675k
    refmvs_block *const *b_left;
395
675k
    if (bx4 > rt->tile_col.start) {
396
599k
        max_cols = imin((bx4 - rt->tile_col.start + 1) >> 1, 2 + (bw4 > 1));
397
599k
        b_left = &rt->r[(by4 & 31) + 5];
398
599k
        n_cols = scan_col(mvstack, cnt, ref, gmv, b_left,
399
599k
                          bh4, h4, bx4 - 1, max_cols, bh4 >= 16 ? 4 : 1,
400
599k
                          &have_newmv, &have_col_mvs);
401
599k
    }
402
403
    // top/right
404
675k
    if (n_rows != ~0U && edge_flags & EDGE_I444_TOP_HAS_RIGHT &&
405
316k
        imax(bw4, bh4) <= 16 && bw4 + bx4 < rt->tile_col.end)
406
299k
    {
407
299k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[bw4], ref, gmv,
408
299k
                              &have_newmv, &have_row_mvs);
409
299k
    }
410
411
675k
    const int nearest_match = have_col_mvs + have_row_mvs;
412
675k
    const int nearest_cnt = *cnt;
413
1.40M
    for (int n = 0; n < nearest_cnt; n++)
414
733k
        mvstack[n].weight += 640;
415
416
    // temporal
417
675k
    int globalmv_ctx = rf->frm_hdr->use_ref_frame_mvs;
418
675k
    if (rf->use_ref_frame_mvs) {
419
13.0k
        const ptrdiff_t stride = rf->rp_stride;
420
13.0k
        const int by8 = by4 >> 1, bx8 = bx4 >> 1;
421
13.0k
        const refmvs_temporal_block *const rbi = &rt->rp_proj[(by8 & 15) * stride + bx8];
422
13.0k
        const refmvs_temporal_block *rb = rbi;
423
13.0k
        const int step_h = bw4 >= 16 ? 2 : 1, step_v = bh4 >= 16 ? 2 : 1;
424
13.0k
        const int w8 = imin((w4 + 1) >> 1, 8), h8 = imin((h4 + 1) >> 1, 8);
425
41.2k
        for (int y = 0; y < h8; y += step_v) {
426
70.0k
            for (int x = 0; x < w8; x+= step_h) {
427
41.9k
                add_temporal_candidate(rf, mvstack, cnt, &rb[x], ref,
428
41.9k
                                       !(x | y) ? &globalmv_ctx : NULL, tgmv);
429
41.9k
            }
430
28.1k
            rb += stride * step_v;
431
28.1k
        }
432
13.0k
        if (imin(bw4, bh4) >= 2 && imax(bw4, bh4) < 16) {
433
6.78k
            const int bh8 = bh4 >> 1, bw8 = bw4 >> 1;
434
6.78k
            rb = &rbi[bh8 * stride];
435
6.78k
            const int has_bottom = by8 + bh8 < imin(rt->tile_row.end >> 1,
436
6.78k
                                                    (by8 & ~7) + 8);
437
6.78k
            if (has_bottom && bx8 - 1 >= imax(rt->tile_col.start >> 1, bx8 & ~7)) {
438
1.09k
                add_temporal_candidate(rf, mvstack, cnt, &rb[-1], ref,
439
1.09k
                                       NULL, NULL);
440
1.09k
            }
441
6.78k
            if (bx8 + bw8 < imin(rt->tile_col.end >> 1, (bx8 & ~7) + 8)) {
442
1.51k
                if (has_bottom) {
443
822
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8], ref,
444
822
                                           NULL, NULL);
445
822
                }
446
1.51k
                if (by8 + bh8 - 1 < imin(rt->tile_row.end >> 1, (by8 & ~7) + 8)) {
447
1.36k
                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8 - stride],
448
1.36k
                                           ref, NULL, NULL);
449
1.36k
                }
450
1.51k
            }
451
6.78k
        }
452
13.0k
    }
453
675k
    assert(*cnt <= 8);
454
455
    // top/left (which, confusingly, is part of "secondary" references)
456
675k
    int have_dummy_newmv_match;
457
675k
    if ((n_rows | n_cols) != ~0U) {
458
529k
        add_spatial_candidate(mvstack, cnt, 4, &b_top[-1], ref, gmv,
459
529k
                              &have_dummy_newmv_match, &have_row_mvs);
460
529k
    }
461
462
    // "secondary" (non-direct neighbour) top & left edges
463
    // what is different about secondary is that everything is now in 8x8 resolution
464
2.02M
    for (int n = 2; n <= 3; n++) {
465
1.35M
        if ((unsigned) n > n_rows && (unsigned) n <= max_rows) {
466
607k
            n_rows += scan_row(mvstack, cnt, ref, gmv,
467
607k
                               &rt->r[(((by4 & 31) - 2 * n + 1) | 1) + 5][bx4 | 1],
468
607k
                               bw4, w4, 1 + max_rows - n, bw4 >= 16 ? 4 : 2,
469
607k
                               &have_dummy_newmv_match, &have_row_mvs);
470
607k
        }
471
472
1.35M
        if ((unsigned) n > n_cols && (unsigned) n <= max_cols) {
473
725k
            n_cols += scan_col(mvstack, cnt, ref, gmv, &rt->r[((by4 & 31) | 1) + 5],
474
725k
                               bh4, h4, (bx4 - n * 2 + 1) | 1,
475
725k
                               1 + max_cols - n, bh4 >= 16 ? 4 : 2,
476
725k
                               &have_dummy_newmv_match, &have_col_mvs);
477
725k
        }
478
1.35M
    }
479
675k
    assert(*cnt <= 8);
480
481
675k
    const int ref_match_count = have_col_mvs + have_row_mvs;
482
483
    // context build-up
484
675k
    int refmv_ctx, newmv_ctx;
485
675k
    switch (nearest_match) {
486
145k
    case 0:
487
145k
        refmv_ctx = imin(2, ref_match_count);
488
145k
        newmv_ctx = ref_match_count > 0;
489
145k
        break;
490
204k
    case 1:
491
204k
        refmv_ctx = imin(ref_match_count * 3, 4);
492
204k
        newmv_ctx = 3 - have_newmv;
493
204k
        break;
494
326k
    case 2:
495
326k
        refmv_ctx = 5;
496
326k
        newmv_ctx = 5 - have_newmv;
497
326k
        break;
498
675k
    }
499
500
    // sorting (nearest, then "secondary")
501
676k
    int len = nearest_cnt;
502
1.28M
    while (len) {
503
609k
        int last = 0;
504
836k
        for (int n = 1; n < len; n++) {
505
226k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
506
116k
#define EXCHANGE(a, b) do { refmvs_candidate tmp = a; a = b; b = tmp; } while (0)
507
86.1k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
508
86.1k
                last = n;
509
86.1k
            }
510
226k
        }
511
609k
        len = last;
512
609k
    }
513
676k
    len = *cnt;
514
919k
    while (len > nearest_cnt) {
515
243k
        int last = nearest_cnt;
516
359k
        for (int n = nearest_cnt + 1; n < len; n++) {
517
116k
            if (mvstack[n - 1].weight < mvstack[n].weight) {
518
30.5k
                EXCHANGE(mvstack[n - 1], mvstack[n]);
519
30.5k
#undef EXCHANGE
520
30.5k
                last = n;
521
30.5k
            }
522
116k
        }
523
243k
        len = last;
524
243k
    }
525
526
676k
    if (ref.ref[1] > 0) {
527
99.3k
        if (*cnt < 2) {
528
68.8k
            const int sign0 = rf->sign_bias[ref.ref[0] - 1];
529
68.8k
            const int sign1 = rf->sign_bias[ref.ref[1] - 1];
530
68.8k
            const int sz4 = imin(w4, h4);
531
68.8k
            refmvs_candidate *const same = &mvstack[*cnt];
532
68.8k
            int same_count[4] = { 0 };
533
534
            // non-self references in top
535
100k
            if (n_rows != ~0U) for (int x = 0; x < sz4;) {
536
52.3k
                const refmvs_block *const cand_b = &b_top[x];
537
52.3k
                add_compound_extended_candidate(same, same_count, cand_b,
538
52.3k
                                                sign0, sign1, ref, rf->sign_bias);
539
52.3k
                x += dav1d_block_dimensions[cand_b->bs][0];
540
52.3k
            }
541
542
            // non-self references in left
543
117k
            if (n_cols != ~0U) for (int y = 0; y < sz4;) {
544
62.6k
                const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
545
62.6k
                add_compound_extended_candidate(same, same_count, cand_b,
546
62.6k
                                                sign0, sign1, ref, rf->sign_bias);
547
62.6k
                y += dav1d_block_dimensions[cand_b->bs][1];
548
62.6k
            }
549
550
68.8k
            refmvs_candidate *const diff = &same[2];
551
68.8k
            const int *const diff_count = &same_count[2];
552
553
            // merge together
554
206k
            for (int n = 0; n < 2; n++) {
555
137k
                int m = same_count[n];
556
557
137k
                if (m >= 2) continue;
558
559
104k
                const int l = diff_count[n];
560
104k
                if (l) {
561
77.0k
                    same[m].mv.mv[n] = diff[0].mv.mv[n];
562
77.0k
                    if (++m == 2) continue;
563
27.2k
                    if (l == 2) {
564
22.9k
                        same[1].mv.mv[n] = diff[1].mv.mv[n];
565
22.9k
                        continue;
566
22.9k
                    }
567
27.2k
                }
568
56.7k
                do {
569
56.7k
                    same[m].mv.mv[n] = tgmv[n];
570
56.7k
                } while (++m < 2);
571
31.9k
            }
572
573
            // if the first extended was the same as the non-extended one,
574
            // then replace it with the second extended one
575
68.8k
            int n = *cnt;
576
68.8k
            if (n == 1 && mvstack[0].mv.n == same[0].mv.n)
577
20.7k
                mvstack[1].mv = mvstack[2].mv;
578
108k
            do {
579
108k
                mvstack[n].weight = 2;
580
108k
            } while (++n < 2);
581
68.8k
            *cnt = 2;
582
68.8k
        }
583
584
        // clamping
585
99.3k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
586
99.3k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
587
99.3k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
588
99.3k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
589
590
99.3k
        const int n_refmvs = *cnt;
591
99.3k
        int n = 0;
592
220k
        do {
593
220k
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
594
220k
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
595
220k
            mvstack[n].mv.mv[1].x = iclip(mvstack[n].mv.mv[1].x, left, right);
596
220k
            mvstack[n].mv.mv[1].y = iclip(mvstack[n].mv.mv[1].y, top, bottom);
597
220k
        } while (++n < n_refmvs);
598
599
99.3k
        switch (refmv_ctx >> 1) {
600
42.7k
        case 0:
601
42.7k
            *ctx = imin(newmv_ctx, 1);
602
42.7k
            break;
603
33.1k
        case 1:
604
33.1k
            *ctx = 1 + imin(newmv_ctx, 3);
605
33.1k
            break;
606
23.4k
        case 2:
607
23.4k
            *ctx = iclip(3 + newmv_ctx, 4, 7);
608
23.4k
            break;
609
99.3k
        }
610
611
99.3k
        return;
612
576k
    } else if (*cnt < 2 && ref.ref[0] > 0) {
613
325k
        const int sign = rf->sign_bias[ref.ref[0] - 1];
614
325k
        const int sz4 = imin(w4, h4);
615
616
        // non-self references in top
617
514k
        if (n_rows != ~0U) for (int x = 0; x < sz4 && *cnt < 2;) {
618
264k
            const refmvs_block *const cand_b = &b_top[x];
619
264k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
620
264k
            x += dav1d_block_dimensions[cand_b->bs][0];
621
264k
        }
622
623
        // non-self references in left
624
534k
        if (n_cols != ~0U) for (int y = 0; y < sz4 && *cnt < 2;) {
625
265k
            const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
626
265k
            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
627
265k
            y += dav1d_block_dimensions[cand_b->bs][1];
628
265k
        }
629
325k
    }
630
576k
    assert(*cnt <= 8);
631
632
    // clamping
633
576k
    int n_refmvs = *cnt;
634
576k
    if (n_refmvs) {
635
518k
        const int left = -(bx4 + bw4 + 4) * 4 * 8;
636
518k
        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
637
518k
        const int top = -(by4 + bh4 + 4) * 4 * 8;
638
518k
        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
639
640
518k
        int n = 0;
641
1.03M
        do {
642
1.03M
            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
643
1.03M
            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
644
1.03M
        } while (++n < n_refmvs);
645
518k
    }
646
647
923k
    for (int n = *cnt; n < 2; n++)
648
346k
        mvstack[n].mv.mv[0] = tgmv[0];
649
650
576k
    *ctx = (refmv_ctx << 4) | (globalmv_ctx << 3) | newmv_ctx;
651
576k
}
652
653
void dav1d_refmvs_tile_sbrow_init(refmvs_tile *const rt, const refmvs_frame *const rf,
654
                                  const int tile_col_start4, const int tile_col_end4,
655
                                  const int tile_row_start4, const int tile_row_end4,
656
                                  const int sby, int tile_row_idx, const int pass)
657
138k
{
658
138k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
659
138k
    rt->rp_proj = &rf->rp_proj[16 * rf->rp_stride * tile_row_idx];
660
138k
    const ptrdiff_t r_stride = rf->rp_stride * 2;
661
138k
    const ptrdiff_t pass_off = (rf->n_frame_threads > 1 && pass == 2) ?
662
72.4k
        35 * 2 * rf->n_blocks : 0;
663
138k
    refmvs_block *r = &rf->r[35 * r_stride * tile_row_idx + pass_off];
664
138k
    const int sbsz = rf->sbsz;
665
138k
    const int off = (sbsz * sby) & 16;
666
2.91M
    for (int i = 0; i < sbsz; i++, r += r_stride)
667
2.77M
        rt->r[off + 5 + i] = r;
668
138k
    rt->r[off + 0] = r;
669
138k
    r += r_stride;
670
138k
    rt->r[off + 1] = NULL;
671
138k
    rt->r[off + 2] = r;
672
138k
    r += r_stride;
673
138k
    rt->r[off + 3] = NULL;
674
138k
    rt->r[off + 4] = r;
675
138k
    if (sby & 1) {
676
41.1k
#define EXCHANGE(a, b) do { void *const tmp = a; a = b; b = tmp; } while (0)
677
13.7k
        EXCHANGE(rt->r[off + 0], rt->r[off + sbsz + 0]);
678
13.7k
        EXCHANGE(rt->r[off + 2], rt->r[off + sbsz + 2]);
679
13.7k
        EXCHANGE(rt->r[off + 4], rt->r[off + sbsz + 4]);
680
13.7k
#undef EXCHANGE
681
13.7k
    }
682
683
138k
    rt->rf = rf;
684
138k
    rt->tile_row.start = tile_row_start4;
685
138k
    rt->tile_row.end = imin(tile_row_end4, rf->ih4);
686
138k
    rt->tile_col.start = tile_col_start4;
687
138k
    rt->tile_col.end = imin(tile_col_end4, rf->iw4);
688
138k
}
689
690
static void load_tmvs_c(const refmvs_frame *const rf, int tile_row_idx,
691
                        const int col_start8, const int col_end8,
692
                        const int row_start8, int row_end8)
693
8.21k
{
694
8.21k
    if (rf->n_tile_threads == 1) tile_row_idx = 0;
695
8.21k
    assert(row_start8 >= 0);
696
8.21k
    assert((unsigned) (row_end8 - row_start8) <= 16U);
697
8.21k
    row_end8 = imin(row_end8, rf->ih8);
698
8.21k
    const int col_start8i = imax(col_start8 - 8, 0);
699
8.21k
    const int col_end8i = imin(col_end8 + 8, rf->iw8);
700
701
8.21k
    const ptrdiff_t stride = rf->rp_stride;
702
8.21k
    refmvs_temporal_block *rp_proj =
703
8.21k
        &rf->rp_proj[16 * stride * tile_row_idx + (row_start8 & 15) * stride];
704
55.8k
    for (int y = row_start8; y < row_end8; y++) {
705
122k
        for (int x = col_start8; x < col_end8; x++)
706
74.7k
            rp_proj[x].mv.n = INVALID_MV;
707
47.6k
        rp_proj += stride;
708
47.6k
    }
709
710
8.21k
    rp_proj = &rf->rp_proj[16 * stride * tile_row_idx];
711
18.0k
    for (int n = 0; n < rf->n_mfmvs; n++) {
712
9.84k
        const int ref2cur = rf->mfmv_ref2cur[n];
713
9.84k
        if (ref2cur == INVALID_REF2CUR) continue;
714
715
8.05k
        const int ref = rf->mfmv_ref[n];
716
8.05k
        const int ref_sign = ref - 4;
717
8.05k
        const refmvs_temporal_block *r = &rf->rp_ref[ref][row_start8 * stride];
718
55.7k
        for (int y = row_start8; y < row_end8; y++) {
719
47.6k
            const int y_sb_align = y & ~7;
720
47.6k
            const int y_proj_start = imax(y_sb_align, row_start8);
721
47.6k
            const int y_proj_end = imin(y_sb_align + 8, row_end8);
722
109k
            for (int x = col_start8i; x < col_end8i; x++) {
723
61.6k
                const refmvs_temporal_block *rb = &r[x];
724
61.6k
                const int b_ref = rb->ref;
725
61.6k
                if (!b_ref) continue;
726
17.8k
                const int ref2ref = rf->mfmv_ref2ref[n][b_ref - 1];
727
17.8k
                if (!ref2ref) continue;
728
13.8k
                const mv b_mv = rb->mv;
729
13.8k
                const mv offset = mv_projection(b_mv, ref2cur, ref2ref);
730
13.8k
                int pos_x = x + apply_sign(abs(offset.x) >> 6,
731
13.8k
                                           offset.x ^ ref_sign);
732
13.8k
                const int pos_y = y + apply_sign(abs(offset.y) >> 6,
733
13.8k
                                                 offset.y ^ ref_sign);
734
13.8k
                if (pos_y >= y_proj_start && pos_y < y_proj_end) {
735
12.7k
                    const ptrdiff_t pos = (pos_y & 15) * stride;
736
19.6k
                    for (;;) {
737
19.6k
                        const int x_sb_align = x & ~7;
738
19.6k
                        if (pos_x >= imax(x_sb_align - 8, col_start8) &&
739
19.3k
                            pos_x < imin(x_sb_align + 16, col_end8))
740
18.6k
                        {
741
18.6k
                            rp_proj[pos + pos_x].mv = rb->mv;
742
18.6k
                            rp_proj[pos + pos_x].ref = ref2ref;
743
18.6k
                        }
744
19.6k
                        if (++x >= col_end8i) break;
745
11.5k
                        rb++;
746
11.5k
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
747
6.86k
                        pos_x++;
748
6.86k
                    }
749
12.7k
                } else {
750
1.25k
                    for (;;) {
751
1.25k
                        if (++x >= col_end8i) break;
752
901
                        rb++;
753
901
                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
754
901
                    }
755
1.13k
                }
756
13.8k
                x--;
757
13.8k
            }
758
47.6k
            r += stride;
759
47.6k
        }
760
8.05k
    }
761
8.21k
}
762
763
static void save_tmvs_c(refmvs_temporal_block *rp, const ptrdiff_t stride,
764
                        refmvs_block *const *const rr,
765
                        const uint8_t *const ref_sign,
766
                        const int col_end8, const int row_end8,
767
                        const int col_start8, const int row_start8)
768
20.0k
{
769
99.0k
    for (int y = row_start8; y < row_end8; y++) {
770
78.9k
        const refmvs_block *const b = rr[(y & 15) * 2];
771
772
171k
        for (int x = col_start8; x < col_end8;) {
773
92.9k
            const refmvs_block *const cand_b = &b[x * 2 + 1];
774
92.9k
            const int bw8 = (dav1d_block_dimensions[cand_b->bs][0] + 1) >> 1;
775
776
92.9k
            if (cand_b->ref.ref[1] > 0 && ref_sign[cand_b->ref.ref[1] - 1] &&
777
6.49k
                (abs(cand_b->mv.mv[1].y) | abs(cand_b->mv.mv[1].x)) < 4096)
778
5.84k
            {
779
5.84k
                const refmvs_temporal_block tmv = {
780
5.84k
                    .mv = cand_b->mv.mv[1],
781
5.84k
                    .ref = cand_b->ref.ref[1],
782
5.84k
                };
783
23.5k
                for (int n = 0; n < bw8; n++, x++)
784
17.6k
                    rp[x] = tmv;
785
87.0k
            } else if (cand_b->ref.ref[0] > 0 && ref_sign[cand_b->ref.ref[0] - 1] &&
786
19.0k
                       (abs(cand_b->mv.mv[0].y) | abs(cand_b->mv.mv[0].x)) < 4096)
787
18.3k
            {
788
18.3k
                const refmvs_temporal_block tmv = {
789
18.3k
                    .mv = cand_b->mv.mv[0],
790
18.3k
                    .ref = cand_b->ref.ref[0],
791
18.3k
                };
792
107k
                for (int n = 0; n < bw8; n++, x++)
793
88.8k
                    rp[x] = tmv;
794
68.7k
            } else {
795
68.7k
                const refmvs_temporal_block tmv = { .mv = { .n = 0 }, .ref = 0 };
796
445k
                for (int n = 0; n < bw8; n++, x++)
797
376k
                    rp[x] = tmv;
798
68.7k
            }
799
92.9k
        }
800
78.9k
        rp += stride;
801
78.9k
    }
802
20.0k
}
803
804
int dav1d_refmvs_init_frame(refmvs_frame *const rf,
805
                            const Dav1dSequenceHeader *const seq_hdr,
806
                            const Dav1dFrameHeader *const frm_hdr,
807
                            const uint8_t ref_poc[7],
808
                            refmvs_temporal_block *const rp,
809
                            const uint8_t ref_ref_poc[7][7],
810
                            /*const*/ refmvs_temporal_block *const rp_ref[7],
811
                            const int n_tile_threads, const int n_frame_threads)
812
62.4k
{
813
62.4k
    const int rp_stride = ((frm_hdr->width[0] + 127) & ~127) >> 3;
814
62.4k
    const int n_tile_rows = n_tile_threads > 1 ? frm_hdr->tiling.rows : 1;
815
62.4k
    const int n_blocks = rp_stride * n_tile_rows;
816
817
62.4k
    rf->sbsz = 16 << seq_hdr->sb128;
818
62.4k
    rf->frm_hdr = frm_hdr;
819
62.4k
    rf->iw8 = (frm_hdr->width[0] + 7) >> 3;
820
62.4k
    rf->ih8 = (frm_hdr->height + 7) >> 3;
821
62.4k
    rf->iw4 = rf->iw8 << 1;
822
62.4k
    rf->ih4 = rf->ih8 << 1;
823
62.4k
    rf->rp = rp;
824
62.4k
    rf->rp_stride = rp_stride;
825
62.4k
    rf->n_tile_threads = n_tile_threads;
826
62.4k
    rf->n_frame_threads = n_frame_threads;
827
828
62.4k
    if (n_blocks != rf->n_blocks) {
829
16.6k
        const size_t r_sz = sizeof(*rf->r) * 35 * 2 * n_blocks * (1 + (n_frame_threads > 1));
830
16.6k
        const size_t rp_proj_sz = sizeof(*rf->rp_proj) * 16 * n_blocks;
831
        /* Note that sizeof(*rf->r) == 12, but it's accessed using 16-byte unaligned
832
         * loads in save_tmvs() asm which can overread 4 bytes into rp_proj. */
833
16.6k
        dav1d_free_aligned(rf->r);
834
16.6k
        rf->r = dav1d_alloc_aligned(ALLOC_REFMVS, r_sz + rp_proj_sz, 64);
835
16.6k
        if (!rf->r) {
836
0
            rf->n_blocks = 0;
837
0
            return DAV1D_ERR(ENOMEM);
838
0
        }
839
840
16.6k
        rf->rp_proj = (refmvs_temporal_block*)((uintptr_t)rf->r + r_sz);
841
16.6k
        rf->n_blocks = n_blocks;
842
16.6k
    }
843
844
62.4k
    const int poc = frm_hdr->frame_offset;
845
499k
    for (int i = 0; i < 7; i++) {
846
436k
        const int poc_diff = get_poc_diff(seq_hdr->order_hint_n_bits,
847
436k
                                          ref_poc[i], poc);
848
436k
        rf->sign_bias[i] = poc_diff > 0;
849
436k
        rf->mfmv_sign[i] = poc_diff < 0;
850
436k
        rf->pocdiff[i] = iclip(get_poc_diff(seq_hdr->order_hint_n_bits,
851
436k
                                            poc, ref_poc[i]), -31, 31);
852
436k
    }
853
854
    // temporal MV setup
855
62.4k
    rf->n_mfmvs = 0;
856
62.4k
    rf->rp_ref = rp_ref;
857
62.4k
    if (frm_hdr->use_ref_frame_mvs && seq_hdr->order_hint_n_bits) {
858
7.67k
        int total = 2;
859
7.67k
        if (rp_ref[0] && ref_ref_poc[0][6] != ref_poc[3] /* alt-of-last != gold */) {
860
2.00k
            rf->mfmv_ref[rf->n_mfmvs++] = 0; // last
861
2.00k
            total = 3;
862
2.00k
        }
863
7.67k
        if (rp_ref[4] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[4],
864
6.31k
                                      frm_hdr->frame_offset) > 0)
865
182
        {
866
182
            rf->mfmv_ref[rf->n_mfmvs++] = 4; // bwd
867
182
        }
868
7.67k
        if (rp_ref[5] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[5],
869
5.54k
                                      frm_hdr->frame_offset) > 0)
870
240
        {
871
240
            rf->mfmv_ref[rf->n_mfmvs++] = 5; // altref2
872
240
        }
873
7.67k
        if (rf->n_mfmvs < total && rp_ref[6] &&
874
3.40k
            get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[6],
875
3.40k
                         frm_hdr->frame_offset) > 0)
876
1.37k
        {
877
1.37k
            rf->mfmv_ref[rf->n_mfmvs++] = 6; // altref
878
1.37k
        }
879
7.67k
        if (rf->n_mfmvs < total && rp_ref[1])
880
5.63k
            rf->mfmv_ref[rf->n_mfmvs++] = 1; // last2
881
882
17.1k
        for (int n = 0; n < rf->n_mfmvs; n++) {
883
9.43k
            const int rpoc = ref_poc[rf->mfmv_ref[n]];
884
9.43k
            const int diff1 = get_poc_diff(seq_hdr->order_hint_n_bits,
885
9.43k
                                           rpoc, frm_hdr->frame_offset);
886
9.43k
            if (abs(diff1) > 31) {
887
1.58k
                rf->mfmv_ref2cur[n] = INVALID_REF2CUR;
888
7.85k
            } else {
889
7.85k
                rf->mfmv_ref2cur[n] = rf->mfmv_ref[n] < 4 ? -diff1 : diff1;
890
62.8k
                for (int m = 0; m < 7; m++) {
891
54.9k
                    const int rrpoc = ref_ref_poc[rf->mfmv_ref[n]][m];
892
54.9k
                    const int diff2 = get_poc_diff(seq_hdr->order_hint_n_bits,
893
54.9k
                                                   rpoc, rrpoc);
894
                    // unsigned comparison also catches the < 0 case
895
54.9k
                    rf->mfmv_ref2ref[n][m] = (unsigned) diff2 > 31U ? 0 : diff2;
896
54.9k
                }
897
7.85k
            }
898
9.43k
        }
899
7.67k
    }
900
62.4k
    rf->use_ref_frame_mvs = rf->n_mfmvs > 0;
901
902
62.4k
    return 0;
903
62.4k
}
904
905
static void splat_mv_c(refmvs_block **rr, const refmvs_block *const rmv,
906
                       const int bx4, const int bw4, int bh4)
907
1.03M
{
908
4.26M
    do {
909
4.26M
        refmvs_block *const r = *rr++ + bx4;
910
38.9M
        for (int x = 0; x < bw4; x++)
911
34.6M
            r[x] = *rmv;
912
4.26M
    } while (--bh4);
913
1.03M
}
914
915
#if HAVE_ASM
916
#if ARCH_AARCH64 || ARCH_ARM
917
#include "src/arm/refmvs.h"
918
#elif ARCH_LOONGARCH64
919
#include "src/loongarch/refmvs.h"
920
#elif ARCH_X86
921
#include "src/x86/refmvs.h"
922
#endif
923
#endif
924
925
COLD void dav1d_refmvs_dsp_init(Dav1dRefmvsDSPContext *const c)
926
18.9k
{
927
18.9k
    c->load_tmvs = load_tmvs_c;
928
18.9k
    c->save_tmvs = save_tmvs_c;
929
18.9k
    c->splat_mv = splat_mv_c;
930
931
#if HAVE_ASM
932
#if ARCH_AARCH64 || ARCH_ARM
933
    refmvs_dsp_init_arm(c);
934
#elif ARCH_LOONGARCH64
935
    refmvs_dsp_init_loongarch(c);
936
#elif ARCH_X86
937
    refmvs_dsp_init_x86(c);
938
#endif
939
#endif
940
18.9k
}