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