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