| 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 |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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 | { | ||||
| 48 | if (b->mv.mv[0].n == INVALID_MV0x80008000) return; // intra block, no intrabc | ||||
| 49 | |||||
| 50 | if (ref.ref[1] == -1) { | ||||
| 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) { | ||||
| 75 | const refmvs_mvpair cand_mv = { .mv = { | ||||
| 76 | [0] = ((b->mf & 1) && gmv[0].n != INVALID_MV0x80008000) ? gmv[0] : b->mv.mv[0], | ||||
| 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; | ||||
| |||||
| 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 | |||||
| 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 | { | ||||
| 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 | |||||
| 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 | { | ||||
| 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) { | ||||
| 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;;) { | ||||
| 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, | ||||
| 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 | |||||
| 176 | static 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 | |||||
| 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 | { | ||||
| 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 | |||||
| 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 | { | ||||
| 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 | |||||
| 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 | { | ||||
| 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 | |||||
| 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 | { | ||||
| 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__); })) | ||||
| |||||
| 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) { | ||||
| 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) { | ||||
| 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) { | ||||
| 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) { | ||||
| 397 | max_cols = imin((bx4 - rt->tile_col.start + 1) >> 1, 2 + (bw4
| ||||
| 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
| ||||
| 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++) | ||||
| 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) { | ||||
| 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__); })); | ||||
| 483 | |||||
| 484 | // top/left (which, confusingly, is part of "secondary" references) | ||||
| 485 | int have_dummy_newmv_match; | ||||
| 486 | if ((n_rows | n_cols) != ~0U) { | ||||
| 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
| ||||
| 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
| ||||
| 502 | n_cols += scan_col(mvstack, cnt, ref, gmv, &rt->r[((by4 & 31) | 1) + 5], | ||||
| 503 | bh4, h4, (bx4 - n * 2 + 1) | 1, | ||||
| 504 | 1 + max_cols - n, bh4
| ||||
| 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 | |||||
| 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 | { | ||||
| 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 | |||||
| 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 | { | ||||
| 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 | |||||
| 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 | { | ||||
| 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 | |||||
| 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 | { | ||||
| 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 | |||||
| 933 | static 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 | |||||
| 953 | COLD__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 | } |