Bug Summary

File:root/firefox-clang/third_party/dav1d/src/refmvs.c
Warning:line 81, column 27
The left expression of the compound assignment uses uninitialized memory

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name refmvs.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/media/libdav1d -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/media/libdav1d -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D DAV1D_API= -D STACK_ALIGNMENT=16 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/media/libdav1d -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/media/libdav1d -I /root/firefox-clang/third_party/dav1d -I /root/firefox-clang/third_party/dav1d/include -I /root/firefox-clang/third_party/dav1d/include/dav1d -I /root/firefox-clang/third_party/dav1d/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=tautological-type-limit-compare -Wno-range-loop-analysis -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-unknown-warning-option -Wno-character-conversion -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-10-17-231001-351276-1 -x c /root/firefox-clang/third_party/dav1d/src/refmvs.c
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
42static 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{
48 if (b->mv.mv[0].n == INVALID_MV0x80008000) return; // intra block, no intrabc
28
Assuming field 'n' is not equal to INVALID_MV
29
Taking false branch
49
50 if (ref.ref[1] == -1) {
30
Taking false branch
51 for (int n = 0; n < 2; n++) {
52 if (b->ref.ref[n] == ref.ref[0]) {
53 const mv cand_mv = ((b->mf & 1) && gmv[0].n != INVALID_MV0x80008000) ?
54 gmv[0] : b->mv.mv[n];
55
56 *have_refmv_match = 1;
57 *have_newmv_match |= b->mf >> 1;
58
59 const int last = *cnt;
60 for (int m = 0; m < last; m++)
61 if (mvstack[m].mv.mv[0].n == cand_mv.n) {
62 mvstack[m].weight += weight;
63 return;
64 }
65
66 if (last < 8) {
67 mvstack[last].mv.mv[0] = cand_mv;
68 mvstack[last].weight = weight;
69 *cnt = last + 1;
70 }
71 return;
72 }
73 }
74 } else if (b->ref.pair == ref.pair) {
31
Assuming 'b->ref.pair' is equal to 'ref.pair'
75 const refmvs_mvpair cand_mv = { .mv = {
76 [0] = ((b->mf & 1) && gmv[0].n != INVALID_MV0x80008000) ? gmv[0] : b->mv.mv[0],
32
Assuming the condition is false
77 [1] = ((b->mf & 1) && gmv[1].n != INVALID_MV0x80008000) ? gmv[1] : b->mv.mv[1],
78 }};
79
80 *have_refmv_match = 1;
81 *have_newmv_match |= b->mf >> 1;
33
The left expression of the compound assignment uses uninitialized memory
82
83 const int last = *cnt;
84 for (int n = 0; n < last; n++)
85 if (mvstack[n].mv.n == cand_mv.n) {
86 mvstack[n].weight += weight;
87 return;
88 }
89
90 if (last < 8) {
91 mvstack[last].mv = cand_mv;
92 mvstack[last].weight = weight;
93 *cnt = last + 1;
94 }
95 }
96}
97
98static 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{
104 const refmvs_block *cand_b = b;
105 const enum BlockSize first_cand_bs = cand_b->bs;
106 const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
107 int cand_bw4 = first_cand_b_dim[0];
108 int len = imax(step, imin(bw4, cand_bw4));
109
110 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 const int weight = bw4 == 1 ? 2 :
116 imax(2, imin(2 * max_rows, first_cand_b_dim[1]));
117 add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
118 have_newmv_match, have_refmv_match);
119 return weight >> 1;
120 }
121
122 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 add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
127 have_newmv_match, have_refmv_match);
128 x += len;
129 if (x >= w4) return 1;
130 cand_b = &b[x];
131 cand_bw4 = dav1d_block_dimensions[cand_b->bs][0];
132 assert(cand_bw4 < bw4)((void) sizeof ((cand_bw4 < bw4) ? 1 : 0), __extension__ (
{ if (cand_bw4 < bw4) ; else __assert_fail ("cand_bw4 < bw4"
, "/root/firefox-clang/third_party/dav1d/src/refmvs.c", 132, __extension__
__PRETTY_FUNCTION__); }))
;
133 len = imax(step, cand_bw4);
134 }
135}
136
137static 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{
143 const refmvs_block *cand_b = &b[0][bx4];
144 const enum BlockSize first_cand_bs = cand_b->bs;
145 const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
146 int cand_bh4 = first_cand_b_dim[1];
147 int len = imax(step, imin(bh4, cand_bh4));
148
149 if (bh4 <= cand_bh4) {
24
Assuming 'bh4' is > 'cand_bh4'
25
Taking false branch
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 const int weight = bh4 == 1 ? 2 :
155 imax(2, imin(2 * max_cols, first_cand_b_dim[0]));
156 add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
157 have_newmv_match, have_refmv_match);
158 return weight >> 1;
159 }
160
161 for (int y = 0;;) {
26
Loop condition is true. Entering loop body
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 add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
27
Calling 'add_spatial_candidate'
166 have_newmv_match, have_refmv_match);
167 y += len;
168 if (y >= h4) return 1;
169 cand_b = &b[y][bx4];
170 cand_bh4 = dav1d_block_dimensions[cand_b->bs][1];
171 assert(cand_bh4 < bh4)((void) sizeof ((cand_bh4 < bh4) ? 1 : 0), __extension__ (
{ if (cand_bh4 < bh4) ; else __assert_fail ("cand_bh4 < bh4"
, "/root/firefox-clang/third_party/dav1d/src/refmvs.c", 171, __extension__
__PRETTY_FUNCTION__); }))
;
172 len = imax(step, cand_bh4);
173 }
174}
175
176static inline union mv mv_projection(const union mv mv, const int num, const int den) {
177 static const uint16_t div_mult[32] = {
178 0, 16384, 8192, 5461, 4096, 3276, 2730, 2340,
179 2048, 1820, 1638, 1489, 1365, 1260, 1170, 1092,
180 1024, 963, 910, 862, 819, 780, 744, 712,
181 682, 655, 630, 606, 585, 564, 546, 528
182 };
183 assert(den > 0 && den < 32)((void) sizeof ((den > 0 && den < 32) ? 1 : 0),
__extension__ ({ if (den > 0 && den < 32) ; else
__assert_fail ("den > 0 && den < 32", "/root/firefox-clang/third_party/dav1d/src/refmvs.c"
, 183, __extension__ __PRETTY_FUNCTION__); }))
;
184 assert(num > -32 && num < 32)((void) sizeof ((num > -32 && num < 32) ? 1 : 0
), __extension__ ({ if (num > -32 && num < 32) ;
else __assert_fail ("num > -32 && num < 32", "/root/firefox-clang/third_party/dav1d/src/refmvs.c"
, 184, __extension__ __PRETTY_FUNCTION__); }))
;
185 const int frac = num * div_mult[den];
186 const int y = mv.y * frac, x = mv.x * frac;
187 // Round and clip according to AV1 spec section 7.9.3
188 return (union mv) { // 0x3fff == (1 << 14) - 1
189 .y = iclip((y + 8192 + (y >> 31)) >> 14, -0x3fff, 0x3fff),
190 .x = iclip((x + 8192 + (x >> 31)) >> 14, -0x3fff, 0x3fff)
191 };
192}
193
194static 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{
200 if (rb->mv.n == INVALID_MV0x80008000) return;
201
202 union mv mv = mv_projection(rb->mv, rf->pocdiff[ref.ref[0] - 1], rb->ref);
203 fix_mv_precision(rf->frm_hdr, &mv);
204
205 const int last = *cnt;
206 if (ref.ref[1] == -1) {
207 if (globalmv_ctx)
208 *globalmv_ctx = (abs(mv.x - gmv[0].x) | abs(mv.y - gmv[0].y)) >= 16;
209
210 for (int n = 0; n < last; n++)
211 if (mvstack[n].mv.mv[0].n == mv.n) {
212 mvstack[n].weight += weight;
213 return;
214 }
215 if (last < 8) {
216 mvstack[last].mv.mv[0] = mv;
217 mvstack[last].weight = weight;
218 *cnt = last + 1;
219 }
220 } else {
221 refmvs_mvpair mvp = { .mv = {
222 [0] = mv,
223 [1] = mv_projection(rb->mv, rf->pocdiff[ref.ref[1] - 1], rb->ref),
224 }};
225 fix_mv_precision(rf->frm_hdr, &mvp.mv[1]);
226
227 for (int n = 0; n < last; n++)
228 if (mvstack[n].mv.n == mvp.n) {
229 mvstack[n].weight += weight;
230 return;
231 }
232 if (last < 8) {
233 mvstack[last].mv = mvp;
234 mvstack[last].weight = weight;
235 *cnt = last + 1;
236 }
237 }
238}
239
240static 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{
247 refmvs_candidate *const diff = &same[2];
248 int *const diff_count = &same_count[2];
249
250 for (int n = 0; n < 2; n++) {
251 const int cand_ref = cand_b->ref.ref[n];
252
253 if (cand_ref <= 0) break;
254
255 mv cand_mv = cand_b->mv.mv[n];
256 if (cand_ref == ref.ref[0]) {
257 if (same_count[0] < 2)
258 same[same_count[0]++].mv.mv[0] = cand_mv;
259 if (diff_count[1] < 2) {
260 if (sign1 ^ sign_bias[cand_ref - 1]) {
261 cand_mv.y = -cand_mv.y;
262 cand_mv.x = -cand_mv.x;
263 }
264 diff[diff_count[1]++].mv.mv[1] = cand_mv;
265 }
266 } else if (cand_ref == ref.ref[1]) {
267 if (same_count[1] < 2)
268 same[same_count[1]++].mv.mv[1] = cand_mv;
269 if (diff_count[0] < 2) {
270 if (sign0 ^ sign_bias[cand_ref - 1]) {
271 cand_mv.y = -cand_mv.y;
272 cand_mv.x = -cand_mv.x;
273 }
274 diff[diff_count[0]++].mv.mv[0] = cand_mv;
275 }
276 } else {
277 mv i_cand_mv = (union mv) {
278 .x = -cand_mv.x,
279 .y = -cand_mv.y
280 };
281
282 if (diff_count[0] < 2) {
283 diff[diff_count[0]++].mv.mv[0] =
284 sign0 ^ sign_bias[cand_ref - 1] ?
285 i_cand_mv : cand_mv;
286 }
287
288 if (diff_count[1] < 2) {
289 diff[diff_count[1]++].mv.mv[1] =
290 sign1 ^ sign_bias[cand_ref - 1] ?
291 i_cand_mv : cand_mv;
292 }
293 }
294 }
295}
296
297static 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{
301 for (int n = 0; n < 2; n++) {
302 const int cand_ref = cand_b->ref.ref[n];
303
304 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 mv cand_mv = cand_b->mv.mv[n];
312 if (sign ^ sign_bias[cand_ref - 1]) {
313 cand_mv.y = -cand_mv.y;
314 cand_mv.x = -cand_mv.x;
315 }
316
317 int m;
318 const int last = *cnt;
319 for (m = 0; m < last; m++)
320 if (cand_mv.n == mvstack[m].mv.mv[0].n)
321 break;
322 if (m == last) {
323 mvstack[m].mv.mv[0] = cand_mv;
324 mvstack[m].weight = 2; // "minimal"
325 *cnt = last + 1;
326 }
327 }
328}
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
349void 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{
356 const refmvs_frame *const rf = rt->rf;
357 const uint8_t *const b_dim = dav1d_block_dimensions[bs];
358 const int bw4 = b_dim[0], w4 = imin(imin(bw4, 16), rt->tile_col.end - bx4);
359 const int bh4 = b_dim[1], h4 = imin(imin(bh4, 16), rt->tile_row.end - by4);
360 mv gmv[2], tgmv[2];
361
362 *cnt = 0;
363 assert(ref.ref[0] >= 0 && ref.ref[0] <= 8 &&((void) sizeof ((ref.ref[0] >= 0 && ref.ref[0] <=
8 && ref.ref[1] >= -1 && ref.ref[1] <=
8) ? 1 : 0), __extension__ ({ if (ref.ref[0] >= 0 &&
ref.ref[0] <= 8 && ref.ref[1] >= -1 &&
ref.ref[1] <= 8) ; else __assert_fail ("ref.ref[0] >= 0 && ref.ref[0] <= 8 && ref.ref[1] >= -1 && ref.ref[1] <= 8"
, "/root/firefox-clang/third_party/dav1d/src/refmvs.c", 364, __extension__
__PRETTY_FUNCTION__); }))
1
Assuming the condition is true
2
Assuming the condition is true
3
Assuming the condition is true
4
Assuming the condition is true
5
Taking true branch
364 ref.ref[1] >= -1 && ref.ref[1] <= 8)((void) sizeof ((ref.ref[0] >= 0 && ref.ref[0] <=
8 && ref.ref[1] >= -1 && ref.ref[1] <=
8) ? 1 : 0), __extension__ ({ if (ref.ref[0] >= 0 &&
ref.ref[0] <= 8 && ref.ref[1] >= -1 &&
ref.ref[1] <= 8) ; else __assert_fail ("ref.ref[0] >= 0 && ref.ref[0] <= 8 && ref.ref[1] >= -1 && ref.ref[1] <= 8"
, "/root/firefox-clang/third_party/dav1d/src/refmvs.c", 364, __extension__
__PRETTY_FUNCTION__); }))
;
365 if (ref.ref[0] > 0) {
6
Assuming the condition is false
7
Taking false branch
366 tgmv[0] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[0] - 1],
367 bx4, by4, bw4, bh4, rf->frm_hdr);
368 gmv[0] = rf->frm_hdr->gmv[ref.ref[0] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
369 tgmv[0] : (mv) { .n = INVALID_MV0x80008000 };
370 } else {
371 tgmv[0] = (mv) { .n = 0 };
372 gmv[0] = (mv) { .n = INVALID_MV0x80008000 };
373 }
374 if (ref.ref[1] > 0) {
8
Assuming the condition is false
9
Taking false branch
375 tgmv[1] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[1] - 1],
376 bx4, by4, bw4, bh4, rf->frm_hdr);
377 gmv[1] = rf->frm_hdr->gmv[ref.ref[1] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
378 tgmv[1] : (mv) { .n = INVALID_MV0x80008000 };
379 }
380
381 // top
382 int have_newmv = 0, have_col_mvs = 0, have_row_mvs = 0;
383 unsigned max_rows = 0, n_rows = ~0;
384 const refmvs_block *b_top;
385 if (by4 > rt->tile_row.start) {
10
Assuming 'by4' is <= field 'start'
11
Taking false branch
386 max_rows = imin((by4 - rt->tile_row.start + 1) >> 1, 2 + (bh4 > 1));
387 b_top = &rt->r[(by4 & 31) - 1 + 5][bx4];
388 n_rows = scan_row(mvstack, cnt, ref, gmv, b_top,
389 bw4, w4, max_rows, bw4 >= 16 ? 4 : 1,
390 &have_newmv, &have_row_mvs);
391 }
392
393 // left
394 unsigned max_cols = 0, n_cols = ~0U;
395 refmvs_block *const *b_left;
396 if (bx4 > rt->tile_col.start) {
12
Assuming 'bx4' is > field 'start'
13
Taking true branch
397 max_cols = imin((bx4 - rt->tile_col.start + 1) >> 1, 2 + (bw4
13.1
'bw4' is > 1
> 1));
398 b_left = &rt->r[(by4 & 31) + 5];
399 n_cols = scan_col(mvstack, cnt, ref, gmv, b_left,
400 bh4, h4, bx4 - 1, max_cols, bh4
13.2
'bh4' is >= 16
>= 16 ? 4 : 1,
14
'?' condition is true
401 &have_newmv, &have_col_mvs);
402 }
403
404 // top/right
405 if (n_rows != ~0U && edge_flags & EDGE_I444_TOP_HAS_RIGHT &&
406 imax(bw4, bh4) <= 16 && bw4 + bx4 < rt->tile_col.end)
407 {
408 add_spatial_candidate(mvstack, cnt, 4, &b_top[bw4], ref, gmv,
409 &have_newmv, &have_row_mvs);
410 }
411
412 const int nearest_match = have_col_mvs + have_row_mvs;
413 const int nearest_cnt = *cnt;
414 for (int n = 0; n < nearest_cnt; n++)
15
Loop condition is false. Execution continues on line 418
415 mvstack[n].weight += 640;
416
417 // temporal
418 int globalmv_ctx = rf->frm_hdr->use_ref_frame_mvs;
419 if (rf->use_ref_frame_mvs) {
16
Assuming field 'use_ref_frame_mvs' is 0
17
Taking false branch
420 const ptrdiff_t stride = rf->rp_stride;
421 const int by8 = by4 >> 1, bx8 = bx4 >> 1;
422 const refmvs_temporal_block *const rbi = &rt->rp_proj[(by8 & 15) * stride + bx8];
423 const refmvs_temporal_block *rb = rbi;
424 const int step_h = bw4 >= 16 ? 2 : 1, step_v = bh4 >= 16 ? 2 : 1;
425 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 const refmvs_temporal_block *run = &rb[0];
440 int run_len = 1;
441 int *run_gmv_ctx = &globalmv_ctx;
442 for (int y = 0; y < h8; y += step_v) {
443 for (int x = y ? 0 : step_h; x < w8; x += step_h) {
444 const unsigned mvn = rb[x].mv.n;
445 if (mvn == run->mv.n &&
446 (mvn == INVALID_MV0x80008000 || rb[x].ref == run->ref))
447 {
448 run_len++;
449 continue;
450 }
451 add_temporal_candidate(rf, mvstack, cnt, run, ref,
452 run_gmv_ctx, tgmv, 2 * run_len);
453 run_gmv_ctx = NULL((void*)0);
454 run = &rb[x];
455 run_len = 1;
456 }
457 rb += stride * step_v;
458 }
459 add_temporal_candidate(rf, mvstack, cnt, run, ref,
460 run_gmv_ctx, tgmv, 2 * run_len);
461 if (imin(bw4, bh4) >= 2 && imax(bw4, bh4) < 16) {
462 const int bh8 = bh4 >> 1, bw8 = bw4 >> 1;
463 rb = &rbi[bh8 * stride];
464 const int has_bottom = by8 + bh8 < imin(rt->tile_row.end >> 1,
465 (by8 & ~7) + 8);
466 if (has_bottom && bx8 - 1 >= imax(rt->tile_col.start >> 1, bx8 & ~7)) {
467 add_temporal_candidate(rf, mvstack, cnt, &rb[-1], ref,
468 NULL((void*)0), NULL((void*)0), 2);
469 }
470 if (bx8 + bw8 < imin(rt->tile_col.end >> 1, (bx8 & ~7) + 8)) {
471 if (has_bottom) {
472 add_temporal_candidate(rf, mvstack, cnt, &rb[bw8], ref,
473 NULL((void*)0), NULL((void*)0), 2);
474 }
475 if (by8 + bh8 - 1 < imin(rt->tile_row.end >> 1, (by8 & ~7) + 8)) {
476 add_temporal_candidate(rf, mvstack, cnt, &rb[bw8 - stride],
477 ref, NULL((void*)0), NULL((void*)0), 2);
478 }
479 }
480 }
481 }
482 assert(*cnt <= 8)((void) sizeof ((*cnt <= 8) ? 1 : 0), __extension__ ({ if (
*cnt <= 8) ; else __assert_fail ("*cnt <= 8", "/root/firefox-clang/third_party/dav1d/src/refmvs.c"
, 482, __extension__ __PRETTY_FUNCTION__); }))
;
18
Taking true branch
483
484 // top/left (which, confusingly, is part of "secondary" references)
485 int have_dummy_newmv_match;
19
'have_dummy_newmv_match' declared without an initial value
486 if ((n_rows | n_cols) != ~0U) {
20
Taking false branch
487 add_spatial_candidate(mvstack, cnt, 4, &b_top[-1], ref, gmv,
488 &have_dummy_newmv_match, &have_row_mvs);
489 }
490
491 // "secondary" (non-direct neighbour) top & left edges
492 // what is different about secondary is that everything is now in 8x8 resolution
493 for (int n = 2; n <= 3; n++) {
494 if ((unsigned) n
20.1
'n' is <= 'n_rows'
> n_rows && (unsigned) n <= max_rows) {
495 n_rows += scan_row(mvstack, cnt, ref, gmv,
496 &rt->r[(((by4 & 31) - 2 * n + 1) | 1) + 5][bx4 | 1],
497 bw4, w4, 1 + max_rows - n, bw4 >= 16 ? 4 : 2,
498 &have_dummy_newmv_match, &have_row_mvs);
499 }
500
501 if ((unsigned) n
20.2
'n' is > 'n_cols'
> n_cols && (unsigned) n
20.3
'n' is <= 'max_cols'
<= max_cols) {
21
Taking true branch
502 n_cols += scan_col(mvstack, cnt, ref, gmv, &rt->r[((by4 & 31) | 1) + 5],
23
Calling 'scan_col'
503 bh4, h4, (bx4 - n * 2 + 1) | 1,
504 1 + max_cols - n, bh4
21.1
'bh4' is >= 16
>= 16 ? 4 : 2,
22
'?' condition is true
505 &have_dummy_newmv_match, &have_col_mvs);
506 }
507 }
508 assert(*cnt <= 8)((void) sizeof ((*cnt <= 8) ? 1 : 0), __extension__ ({ if (
*cnt <= 8) ; else __assert_fail ("*cnt <= 8", "/root/firefox-clang/third_party/dav1d/src/refmvs.c"
, 508, __extension__ __PRETTY_FUNCTION__); }))
;
509
510 const int ref_match_count = have_col_mvs + have_row_mvs;
511
512 // context build-up
513 int refmv_ctx, newmv_ctx;
514 switch (nearest_match) {
515 case 0:
516 refmv_ctx = imin(2, ref_match_count);
517 newmv_ctx = ref_match_count > 0;
518 break;
519 case 1:
520 refmv_ctx = imin(ref_match_count * 3, 4);
521 newmv_ctx = 3 - have_newmv;
522 break;
523 case 2:
524 refmv_ctx = 5;
525 newmv_ctx = 5 - have_newmv;
526 break;
527 }
528
529 // sorting (nearest, then "secondary")
530 int len = nearest_cnt;
531 while (len) {
532 int last = 0;
533 for (int n = 1; n < len; n++) {
534 if (mvstack[n - 1].weight < mvstack[n].weight) {
535#define EXCHANGE(a, b) do { refmvs_candidate tmp = a; a = b; b = tmp; } while (0)
536 EXCHANGE(mvstack[n - 1], mvstack[n]);
537 last = n;
538 }
539 }
540 len = last;
541 }
542 len = *cnt;
543 while (len > nearest_cnt) {
544 int last = nearest_cnt;
545 for (int n = nearest_cnt + 1; n < len; n++) {
546 if (mvstack[n - 1].weight < mvstack[n].weight) {
547 EXCHANGE(mvstack[n - 1], mvstack[n]);
548#undef EXCHANGE
549 last = n;
550 }
551 }
552 len = last;
553 }
554
555 if (ref.ref[1] > 0) {
556 if (*cnt < 2) {
557 const int sign0 = rf->sign_bias[ref.ref[0] - 1];
558 const int sign1 = rf->sign_bias[ref.ref[1] - 1];
559 const int sz4 = imin(w4, h4);
560 refmvs_candidate *const same = &mvstack[*cnt];
561 int same_count[4] = { 0 };
562
563 // non-self references in top
564 if (n_rows != ~0U) for (int x = 0; x < sz4;) {
565 const refmvs_block *const cand_b = &b_top[x];
566 add_compound_extended_candidate(same, same_count, cand_b,
567 sign0, sign1, ref, rf->sign_bias);
568 x += dav1d_block_dimensions[cand_b->bs][0];
569 }
570
571 // non-self references in left
572 if (n_cols != ~0U) for (int y = 0; y < sz4;) {
573 const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
574 add_compound_extended_candidate(same, same_count, cand_b,
575 sign0, sign1, ref, rf->sign_bias);
576 y += dav1d_block_dimensions[cand_b->bs][1];
577 }
578
579 refmvs_candidate *const diff = &same[2];
580 const int *const diff_count = &same_count[2];
581
582 // merge together
583 for (int n = 0; n < 2; n++) {
584 int m = same_count[n];
585
586 if (m >= 2) continue;
587
588 const int l = diff_count[n];
589 if (l) {
590 same[m].mv.mv[n] = diff[0].mv.mv[n];
591 if (++m == 2) continue;
592 if (l == 2) {
593 same[1].mv.mv[n] = diff[1].mv.mv[n];
594 continue;
595 }
596 }
597 do {
598 same[m].mv.mv[n] = tgmv[n];
599 } while (++m < 2);
600 }
601
602 // if the first extended was the same as the non-extended one,
603 // then replace it with the second extended one
604 int n = *cnt;
605 if (n == 1 && mvstack[0].mv.n == same[0].mv.n)
606 mvstack[1].mv = mvstack[2].mv;
607 do {
608 mvstack[n].weight = 2;
609 } while (++n < 2);
610 *cnt = 2;
611 }
612
613 // clamping
614 const int left = -(bx4 + bw4 + 4) * 4 * 8;
615 const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
616 const int top = -(by4 + bh4 + 4) * 4 * 8;
617 const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
618
619 const int n_refmvs = *cnt;
620 int n = 0;
621 do {
622 mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
623 mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
624 mvstack[n].mv.mv[1].x = iclip(mvstack[n].mv.mv[1].x, left, right);
625 mvstack[n].mv.mv[1].y = iclip(mvstack[n].mv.mv[1].y, top, bottom);
626 } while (++n < n_refmvs);
627
628 switch (refmv_ctx >> 1) {
629 case 0:
630 *ctx = imin(newmv_ctx, 1);
631 break;
632 case 1:
633 *ctx = 1 + imin(newmv_ctx, 3);
634 break;
635 case 2:
636 *ctx = iclip(3 + newmv_ctx, 4, 7);
637 break;
638 }
639
640 return;
641 } else if (*cnt < 2 && ref.ref[0] > 0) {
642 const int sign = rf->sign_bias[ref.ref[0] - 1];
643 const int sz4 = imin(w4, h4);
644
645 // non-self references in top
646 if (n_rows != ~0U) for (int x = 0; x < sz4 && *cnt < 2;) {
647 const refmvs_block *const cand_b = &b_top[x];
648 add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
649 x += dav1d_block_dimensions[cand_b->bs][0];
650 }
651
652 // non-self references in left
653 if (n_cols != ~0U) for (int y = 0; y < sz4 && *cnt < 2;) {
654 const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
655 add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
656 y += dav1d_block_dimensions[cand_b->bs][1];
657 }
658 }
659 assert(*cnt <= 8)((void) sizeof ((*cnt <= 8) ? 1 : 0), __extension__ ({ if (
*cnt <= 8) ; else __assert_fail ("*cnt <= 8", "/root/firefox-clang/third_party/dav1d/src/refmvs.c"
, 659, __extension__ __PRETTY_FUNCTION__); }))
;
660
661 // clamping
662 int n_refmvs = *cnt;
663 if (n_refmvs) {
664 const int left = -(bx4 + bw4 + 4) * 4 * 8;
665 const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
666 const int top = -(by4 + bh4 + 4) * 4 * 8;
667 const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
668
669 int n = 0;
670 do {
671 mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
672 mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
673 } while (++n < n_refmvs);
674 }
675
676 for (int n = *cnt; n < 2; n++)
677 mvstack[n].mv.mv[0] = tgmv[0];
678
679 *ctx = (refmv_ctx << 4) | (globalmv_ctx << 3) | newmv_ctx;
680}
681
682void 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{
687 if (rf->n_tile_threads == 1) tile_row_idx = 0;
688 rt->rp_proj = &rf->rp_proj[16 * rf->rp_stride * tile_row_idx];
689 const ptrdiff_t r_stride = rf->rp_stride * 2;
690 const ptrdiff_t pass_off = (rf->n_frame_threads > 1 && pass == 2) ?
691 35 * 2 * rf->n_blocks : 0;
692 refmvs_block *r = &rf->r[35 * r_stride * tile_row_idx + pass_off];
693 const int sbsz = rf->sbsz;
694 const int off = (sbsz * sby) & 16;
695 for (int i = 0; i < sbsz; i++, r += r_stride)
696 rt->r[off + 5 + i] = r;
697 rt->r[off + 0] = r;
698 r += r_stride;
699 rt->r[off + 1] = NULL((void*)0);
700 rt->r[off + 2] = r;
701 r += r_stride;
702 rt->r[off + 3] = NULL((void*)0);
703 rt->r[off + 4] = r;
704 if (sby & 1) {
705#define EXCHANGE(a, b) do { void *const tmp = a; a = b; b = tmp; } while (0)
706 EXCHANGE(rt->r[off + 0], rt->r[off + sbsz + 0]);
707 EXCHANGE(rt->r[off + 2], rt->r[off + sbsz + 2]);
708 EXCHANGE(rt->r[off + 4], rt->r[off + sbsz + 4]);
709#undef EXCHANGE
710 }
711
712 rt->rf = rf;
713 rt->tile_row.start = tile_row_start4;
714 rt->tile_row.end = imin(tile_row_end4, rf->ih4);
715 rt->tile_col.start = tile_col_start4;
716 rt->tile_col.end = imin(tile_col_end4, rf->iw4);
717}
718
719static 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{
723 if (rf->n_tile_threads == 1) tile_row_idx = 0;
724 assert(row_start8 >= 0)((void) sizeof ((row_start8 >= 0) ? 1 : 0), __extension__ (
{ if (row_start8 >= 0) ; else __assert_fail ("row_start8 >= 0"
, "/root/firefox-clang/third_party/dav1d/src/refmvs.c", 724, __extension__
__PRETTY_FUNCTION__); }))
;
725 assert((unsigned) (row_end8 - row_start8) <= 16U)((void) sizeof (((unsigned) (row_end8 - row_start8) <= 16U
) ? 1 : 0), __extension__ ({ if ((unsigned) (row_end8 - row_start8
) <= 16U) ; else __assert_fail ("(unsigned) (row_end8 - row_start8) <= 16U"
, "/root/firefox-clang/third_party/dav1d/src/refmvs.c", 725, __extension__
__PRETTY_FUNCTION__); }))
;
726 row_end8 = imin(row_end8, rf->ih8);
727 const int col_start8i = imax(col_start8 - 8, 0);
728 const int col_end8i = imin(col_end8 + 8, rf->iw8);
729
730 const ptrdiff_t stride = rf->rp_stride;
731 refmvs_temporal_block *rp_proj =
732 &rf->rp_proj[16 * stride * tile_row_idx + (row_start8 & 15) * stride];
733 for (int y = row_start8; y < row_end8; y++) {
734 for (int x = col_start8; x < col_end8; x++)
735 rp_proj[x].mv.n = INVALID_MV0x80008000;
736 rp_proj += stride;
737 }
738
739 rp_proj = &rf->rp_proj[16 * stride * tile_row_idx];
740 for (int n = 0; n < rf->n_mfmvs; n++) {
741 const int ref2cur = rf->mfmv_ref2cur[n];
742 if (ref2cur == INVALID_REF2CUR(-32)) continue;
743
744 const int ref = rf->mfmv_ref[n];
745 const int ref_sign = ref - 4;
746 const refmvs_temporal_block *r = &rf->rp_ref[ref][row_start8 * stride];
747 for (int y = row_start8; y < row_end8; y++) {
748 const int y_sb_align = y & ~7;
749 const int y_proj_start = imax(y_sb_align, row_start8);
750 const int y_proj_end = imin(y_sb_align + 8, row_end8);
751 for (int x = col_start8i; x < col_end8i; x++) {
752 const refmvs_temporal_block *rb = &r[x];
753 const int b_ref = rb->ref;
754 if (!b_ref) continue;
755 const int ref2ref = rf->mfmv_ref2ref[n][b_ref - 1];
756 if (!ref2ref) continue;
757 const mv b_mv = rb->mv;
758 const mv offset = mv_projection(b_mv, ref2cur, ref2ref);
759 int pos_x = x + apply_sign(abs(offset.x) >> 6,
760 offset.x ^ ref_sign);
761 const int pos_y = y + apply_sign(abs(offset.y) >> 6,
762 offset.y ^ ref_sign);
763 if (pos_y >= y_proj_start && pos_y < y_proj_end) {
764 const ptrdiff_t pos = (pos_y & 15) * stride;
765 for (;;) {
766 const int x_sb_align = x & ~7;
767 if (pos_x >= imax(x_sb_align - 8, col_start8) &&
768 pos_x < imin(x_sb_align + 16, col_end8))
769 {
770 rp_proj[pos + pos_x].mv = rb->mv;
771 rp_proj[pos + pos_x].ref = ref2ref;
772 }
773 if (++x >= col_end8i) break;
774 rb++;
775 if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
776 pos_x++;
777 }
778 } else {
779 for (;;) {
780 if (++x >= col_end8i) break;
781 rb++;
782 if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
783 }
784 }
785 x--;
786 }
787 r += stride;
788 }
789 }
790}
791
792static 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{
798 for (int y = row_start8; y < row_end8; y++) {
799 const refmvs_block *const b = rr[(y & 15) * 2];
800
801 for (int x = col_start8; x < col_end8;) {
802 const refmvs_block *const cand_b = &b[x * 2 + 1];
803 const int bw8 = (dav1d_block_dimensions[cand_b->bs][0] + 1) >> 1;
804
805 if (cand_b->ref.ref[1] > 0 && ref_sign[cand_b->ref.ref[1] - 1] &&
806 (abs(cand_b->mv.mv[1].y) | abs(cand_b->mv.mv[1].x)) < 4096)
807 {
808 const refmvs_temporal_block tmv = {
809 .mv = cand_b->mv.mv[1],
810 .ref = cand_b->ref.ref[1],
811 };
812 for (int n = 0; n < bw8; n++, x++)
813 rp[x] = tmv;
814 } else if (cand_b->ref.ref[0] > 0 && ref_sign[cand_b->ref.ref[0] - 1] &&
815 (abs(cand_b->mv.mv[0].y) | abs(cand_b->mv.mv[0].x)) < 4096)
816 {
817 const refmvs_temporal_block tmv = {
818 .mv = cand_b->mv.mv[0],
819 .ref = cand_b->ref.ref[0],
820 };
821 for (int n = 0; n < bw8; n++, x++)
822 rp[x] = tmv;
823 } else {
824 memset(&rp[x], 0, bw8 * sizeof(*rp));
825 x += bw8;
826 }
827 }
828 rp += stride;
829 }
830}
831
832int 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{
841 const int rp_stride = ((frm_hdr->width[0] + 127) & ~127) >> 3;
842 const int n_tile_rows = n_tile_threads > 1 ? frm_hdr->tiling.rows : 1;
843 const int n_blocks = rp_stride * n_tile_rows;
844
845 rf->sbsz = 16 << seq_hdr->sb128;
846 rf->frm_hdr = frm_hdr;
847 rf->iw8 = (frm_hdr->width[0] + 7) >> 3;
848 rf->ih8 = (frm_hdr->height + 7) >> 3;
849 rf->iw4 = rf->iw8 << 1;
850 rf->ih4 = rf->ih8 << 1;
851 rf->rp = rp;
852 rf->rp_stride = rp_stride;
853 rf->n_tile_threads = n_tile_threads;
854 rf->n_frame_threads = n_frame_threads;
855
856 if (n_blocks != rf->n_blocks) {
857 const size_t r_sz = sizeof(*rf->r) * 35 * 2 * n_blocks * (1 + (n_frame_threads > 1));
858 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 dav1d_free_aligned(rf->r)dav1d_free_aligned_internal(rf->r);
862 rf->r = dav1d_alloc_aligned(ALLOC_REFMVS, r_sz + rp_proj_sz, 64)dav1d_alloc_aligned_internal(r_sz + rp_proj_sz, 64);
863 if (!rf->r) {
864 rf->n_blocks = 0;
865 return DAV1D_ERR(ENOMEM)(-(12));
866 }
867
868 rf->rp_proj = (refmvs_temporal_block*)((uintptr_t)rf->r + r_sz);
869 rf->n_blocks = n_blocks;
870 }
871
872 const int poc = frm_hdr->frame_offset;
873 for (int i = 0; i < 7; i++) {
874 const int poc_diff = get_poc_diff(seq_hdr->order_hint_n_bits,
875 ref_poc[i], poc);
876 rf->sign_bias[i] = poc_diff > 0;
877 rf->mfmv_sign[i] = poc_diff < 0;
878 rf->pocdiff[i] = iclip(get_poc_diff(seq_hdr->order_hint_n_bits,
879 poc, ref_poc[i]), -31, 31);
880 }
881
882 // temporal MV setup
883 rf->n_mfmvs = 0;
884 rf->rp_ref = rp_ref;
885 if (frm_hdr->use_ref_frame_mvs && seq_hdr->order_hint_n_bits) {
886 int total = 2;
887 if (rp_ref[0] && ref_ref_poc[0][6] != ref_poc[3] /* alt-of-last != gold */) {
888 rf->mfmv_ref[rf->n_mfmvs++] = 0; // last
889 total = 3;
890 }
891 if (rp_ref[4] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[4],
892 frm_hdr->frame_offset) > 0)
893 {
894 rf->mfmv_ref[rf->n_mfmvs++] = 4; // bwd
895 }
896 if (rp_ref[5] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[5],
897 frm_hdr->frame_offset) > 0)
898 {
899 rf->mfmv_ref[rf->n_mfmvs++] = 5; // altref2
900 }
901 if (rf->n_mfmvs < total && rp_ref[6] &&
902 get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[6],
903 frm_hdr->frame_offset) > 0)
904 {
905 rf->mfmv_ref[rf->n_mfmvs++] = 6; // altref
906 }
907 if (rf->n_mfmvs < total && rp_ref[1])
908 rf->mfmv_ref[rf->n_mfmvs++] = 1; // last2
909
910 for (int n = 0; n < rf->n_mfmvs; n++) {
911 const int rpoc = ref_poc[rf->mfmv_ref[n]];
912 const int diff1 = get_poc_diff(seq_hdr->order_hint_n_bits,
913 rpoc, frm_hdr->frame_offset);
914 if (abs(diff1) > 31) {
915 rf->mfmv_ref2cur[n] = INVALID_REF2CUR(-32);
916 } else {
917 rf->mfmv_ref2cur[n] = rf->mfmv_ref[n] < 4 ? -diff1 : diff1;
918 for (int m = 0; m < 7; m++) {
919 const int rrpoc = ref_ref_poc[rf->mfmv_ref[n]][m];
920 const int diff2 = get_poc_diff(seq_hdr->order_hint_n_bits,
921 rpoc, rrpoc);
922 // unsigned comparison also catches the < 0 case
923 rf->mfmv_ref2ref[n][m] = (unsigned) diff2 > 31U ? 0 : diff2;
924 }
925 }
926 }
927 }
928 rf->use_ref_frame_mvs = rf->n_mfmvs > 0;
929
930 return 0;
931}
932
933static void splat_mv_c(refmvs_block **rr, const refmvs_block *const rmv,
934 const int bx4, const int bw4, int bh4)
935{
936 do {
937 refmvs_block *const r = *rr++ + bx4;
938 for (int x = 0; x < bw4; x++)
939 r[x] = *rmv;
940 } while (--bh4);
941}
942
943#if HAVE_ASM1
944#if ARCH_AARCH640 || ARCH_ARM0
945#include "src/arm/refmvs.h"
946#elif ARCH_LOONGARCH64
947#include "src/loongarch/refmvs.h"
948#elif ARCH_X861
949#include "src/x86/refmvs.h"
950#endif
951#endif
952
953COLD__attribute__((cold)) void dav1d_refmvs_dsp_init(Dav1dRefmvsDSPContext *const c)
954{
955 c->load_tmvs = load_tmvs_c;
956 c->save_tmvs = save_tmvs_c;
957 c->splat_mv = splat_mv_c;
958
959#if HAVE_ASM1
960#if ARCH_AARCH640 || ARCH_ARM0
961 refmvs_dsp_init_arm(c);
962#elif ARCH_LOONGARCH64
963 refmvs_dsp_init_loongarch(c);
964#elif ARCH_X861
965 refmvs_dsp_init_x86(c);
966#endif
967#endif
968}