xref: /aosp_15_r20/external/libaom/av1/encoder/rdopt.c (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
1*77c1e3ccSAndroid Build Coastguard Worker /*
2*77c1e3ccSAndroid Build Coastguard Worker  * Copyright (c) 2016, Alliance for Open Media. All rights reserved.
3*77c1e3ccSAndroid Build Coastguard Worker  *
4*77c1e3ccSAndroid Build Coastguard Worker  * This source code is subject to the terms of the BSD 2 Clause License and
5*77c1e3ccSAndroid Build Coastguard Worker  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6*77c1e3ccSAndroid Build Coastguard Worker  * was not distributed with this source code in the LICENSE file, you can
7*77c1e3ccSAndroid Build Coastguard Worker  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8*77c1e3ccSAndroid Build Coastguard Worker  * Media Patent License 1.0 was not distributed with this source code in the
9*77c1e3ccSAndroid Build Coastguard Worker  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10*77c1e3ccSAndroid Build Coastguard Worker  */
11*77c1e3ccSAndroid Build Coastguard Worker 
12*77c1e3ccSAndroid Build Coastguard Worker #include <assert.h>
13*77c1e3ccSAndroid Build Coastguard Worker #include <math.h>
14*77c1e3ccSAndroid Build Coastguard Worker #include <stdbool.h>
15*77c1e3ccSAndroid Build Coastguard Worker 
16*77c1e3ccSAndroid Build Coastguard Worker #include "config/aom_config.h"
17*77c1e3ccSAndroid Build Coastguard Worker #include "config/aom_dsp_rtcd.h"
18*77c1e3ccSAndroid Build Coastguard Worker #include "config/av1_rtcd.h"
19*77c1e3ccSAndroid Build Coastguard Worker 
20*77c1e3ccSAndroid Build Coastguard Worker #include "aom_dsp/aom_dsp_common.h"
21*77c1e3ccSAndroid Build Coastguard Worker #include "aom_dsp/blend.h"
22*77c1e3ccSAndroid Build Coastguard Worker #include "aom_mem/aom_mem.h"
23*77c1e3ccSAndroid Build Coastguard Worker #include "aom_ports/aom_timer.h"
24*77c1e3ccSAndroid Build Coastguard Worker #include "aom_ports/mem.h"
25*77c1e3ccSAndroid Build Coastguard Worker 
26*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/av1_common_int.h"
27*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/cfl.h"
28*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/blockd.h"
29*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/common.h"
30*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/common_data.h"
31*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/entropy.h"
32*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/entropymode.h"
33*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/idct.h"
34*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/mvref_common.h"
35*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/obmc.h"
36*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/pred_common.h"
37*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/quant_common.h"
38*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/reconinter.h"
39*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/reconintra.h"
40*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/scan.h"
41*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/seg_common.h"
42*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/txb_common.h"
43*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/warped_motion.h"
44*77c1e3ccSAndroid Build Coastguard Worker 
45*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/aq_variance.h"
46*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/av1_quantize.h"
47*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/cost.h"
48*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/compound_type.h"
49*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/encodemb.h"
50*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/encodemv.h"
51*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/encoder.h"
52*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/encodetxb.h"
53*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/hybrid_fwd_txfm.h"
54*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/interp_search.h"
55*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/intra_mode_search.h"
56*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/intra_mode_search_utils.h"
57*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/mcomp.h"
58*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/ml.h"
59*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/mode_prune_model_weights.h"
60*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/model_rd.h"
61*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/motion_search_facade.h"
62*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/palette.h"
63*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/pustats.h"
64*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/random.h"
65*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/ratectrl.h"
66*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/rd.h"
67*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/rdopt.h"
68*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/reconinter_enc.h"
69*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/tokenize.h"
70*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/tpl_model.h"
71*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/tx_search.h"
72*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/var_based_part.h"
73*77c1e3ccSAndroid Build Coastguard Worker 
74*77c1e3ccSAndroid Build Coastguard Worker #define LAST_NEW_MV_INDEX 6
75*77c1e3ccSAndroid Build Coastguard Worker 
76*77c1e3ccSAndroid Build Coastguard Worker // Mode_threshold multiplication factor table for prune_inter_modes_if_skippable
77*77c1e3ccSAndroid Build Coastguard Worker // The values are kept in Q12 format and equation used to derive is
78*77c1e3ccSAndroid Build Coastguard Worker // (2.5 - ((float)x->qindex / MAXQ) * 1.5)
79*77c1e3ccSAndroid Build Coastguard Worker #define MODE_THRESH_QBITS 12
80*77c1e3ccSAndroid Build Coastguard Worker static const int mode_threshold_mul_factor[QINDEX_RANGE] = {
81*77c1e3ccSAndroid Build Coastguard Worker   10240, 10216, 10192, 10168, 10144, 10120, 10095, 10071, 10047, 10023, 9999,
82*77c1e3ccSAndroid Build Coastguard Worker   9975,  9951,  9927,  9903,  9879,  9854,  9830,  9806,  9782,  9758,  9734,
83*77c1e3ccSAndroid Build Coastguard Worker   9710,  9686,  9662,  9638,  9614,  9589,  9565,  9541,  9517,  9493,  9469,
84*77c1e3ccSAndroid Build Coastguard Worker   9445,  9421,  9397,  9373,  9349,  9324,  9300,  9276,  9252,  9228,  9204,
85*77c1e3ccSAndroid Build Coastguard Worker   9180,  9156,  9132,  9108,  9083,  9059,  9035,  9011,  8987,  8963,  8939,
86*77c1e3ccSAndroid Build Coastguard Worker   8915,  8891,  8867,  8843,  8818,  8794,  8770,  8746,  8722,  8698,  8674,
87*77c1e3ccSAndroid Build Coastguard Worker   8650,  8626,  8602,  8578,  8553,  8529,  8505,  8481,  8457,  8433,  8409,
88*77c1e3ccSAndroid Build Coastguard Worker   8385,  8361,  8337,  8312,  8288,  8264,  8240,  8216,  8192,  8168,  8144,
89*77c1e3ccSAndroid Build Coastguard Worker   8120,  8096,  8072,  8047,  8023,  7999,  7975,  7951,  7927,  7903,  7879,
90*77c1e3ccSAndroid Build Coastguard Worker   7855,  7831,  7806,  7782,  7758,  7734,  7710,  7686,  7662,  7638,  7614,
91*77c1e3ccSAndroid Build Coastguard Worker   7590,  7566,  7541,  7517,  7493,  7469,  7445,  7421,  7397,  7373,  7349,
92*77c1e3ccSAndroid Build Coastguard Worker   7325,  7301,  7276,  7252,  7228,  7204,  7180,  7156,  7132,  7108,  7084,
93*77c1e3ccSAndroid Build Coastguard Worker   7060,  7035,  7011,  6987,  6963,  6939,  6915,  6891,  6867,  6843,  6819,
94*77c1e3ccSAndroid Build Coastguard Worker   6795,  6770,  6746,  6722,  6698,  6674,  6650,  6626,  6602,  6578,  6554,
95*77c1e3ccSAndroid Build Coastguard Worker   6530,  6505,  6481,  6457,  6433,  6409,  6385,  6361,  6337,  6313,  6289,
96*77c1e3ccSAndroid Build Coastguard Worker   6264,  6240,  6216,  6192,  6168,  6144,  6120,  6096,  6072,  6048,  6024,
97*77c1e3ccSAndroid Build Coastguard Worker   5999,  5975,  5951,  5927,  5903,  5879,  5855,  5831,  5807,  5783,  5758,
98*77c1e3ccSAndroid Build Coastguard Worker   5734,  5710,  5686,  5662,  5638,  5614,  5590,  5566,  5542,  5518,  5493,
99*77c1e3ccSAndroid Build Coastguard Worker   5469,  5445,  5421,  5397,  5373,  5349,  5325,  5301,  5277,  5253,  5228,
100*77c1e3ccSAndroid Build Coastguard Worker   5204,  5180,  5156,  5132,  5108,  5084,  5060,  5036,  5012,  4987,  4963,
101*77c1e3ccSAndroid Build Coastguard Worker   4939,  4915,  4891,  4867,  4843,  4819,  4795,  4771,  4747,  4722,  4698,
102*77c1e3ccSAndroid Build Coastguard Worker   4674,  4650,  4626,  4602,  4578,  4554,  4530,  4506,  4482,  4457,  4433,
103*77c1e3ccSAndroid Build Coastguard Worker   4409,  4385,  4361,  4337,  4313,  4289,  4265,  4241,  4216,  4192,  4168,
104*77c1e3ccSAndroid Build Coastguard Worker   4144,  4120,  4096
105*77c1e3ccSAndroid Build Coastguard Worker };
106*77c1e3ccSAndroid Build Coastguard Worker 
107*77c1e3ccSAndroid Build Coastguard Worker static const THR_MODES av1_default_mode_order[MAX_MODES] = {
108*77c1e3ccSAndroid Build Coastguard Worker   THR_NEARESTMV,
109*77c1e3ccSAndroid Build Coastguard Worker   THR_NEARESTL2,
110*77c1e3ccSAndroid Build Coastguard Worker   THR_NEARESTL3,
111*77c1e3ccSAndroid Build Coastguard Worker   THR_NEARESTB,
112*77c1e3ccSAndroid Build Coastguard Worker   THR_NEARESTA2,
113*77c1e3ccSAndroid Build Coastguard Worker   THR_NEARESTA,
114*77c1e3ccSAndroid Build Coastguard Worker   THR_NEARESTG,
115*77c1e3ccSAndroid Build Coastguard Worker 
116*77c1e3ccSAndroid Build Coastguard Worker   THR_NEWMV,
117*77c1e3ccSAndroid Build Coastguard Worker   THR_NEWL2,
118*77c1e3ccSAndroid Build Coastguard Worker   THR_NEWL3,
119*77c1e3ccSAndroid Build Coastguard Worker   THR_NEWB,
120*77c1e3ccSAndroid Build Coastguard Worker   THR_NEWA2,
121*77c1e3ccSAndroid Build Coastguard Worker   THR_NEWA,
122*77c1e3ccSAndroid Build Coastguard Worker   THR_NEWG,
123*77c1e3ccSAndroid Build Coastguard Worker 
124*77c1e3ccSAndroid Build Coastguard Worker   THR_NEARMV,
125*77c1e3ccSAndroid Build Coastguard Worker   THR_NEARL2,
126*77c1e3ccSAndroid Build Coastguard Worker   THR_NEARL3,
127*77c1e3ccSAndroid Build Coastguard Worker   THR_NEARB,
128*77c1e3ccSAndroid Build Coastguard Worker   THR_NEARA2,
129*77c1e3ccSAndroid Build Coastguard Worker   THR_NEARA,
130*77c1e3ccSAndroid Build Coastguard Worker   THR_NEARG,
131*77c1e3ccSAndroid Build Coastguard Worker 
132*77c1e3ccSAndroid Build Coastguard Worker   THR_GLOBALMV,
133*77c1e3ccSAndroid Build Coastguard Worker   THR_GLOBALL2,
134*77c1e3ccSAndroid Build Coastguard Worker   THR_GLOBALL3,
135*77c1e3ccSAndroid Build Coastguard Worker   THR_GLOBALB,
136*77c1e3ccSAndroid Build Coastguard Worker   THR_GLOBALA2,
137*77c1e3ccSAndroid Build Coastguard Worker   THR_GLOBALA,
138*77c1e3ccSAndroid Build Coastguard Worker   THR_GLOBALG,
139*77c1e3ccSAndroid Build Coastguard Worker 
140*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEARESTLA,
141*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEARESTL2A,
142*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEARESTL3A,
143*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEARESTGA,
144*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEARESTLB,
145*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEARESTL2B,
146*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEARESTL3B,
147*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEARESTGB,
148*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEARESTLA2,
149*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEARESTL2A2,
150*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEARESTL3A2,
151*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEARESTGA2,
152*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEARESTLL2,
153*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEARESTLL3,
154*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEARESTLG,
155*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEARESTBA,
156*77c1e3ccSAndroid Build Coastguard Worker 
157*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEARLB,
158*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEWLB,
159*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARESTLB,
160*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEWLB,
161*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARLB,
162*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEWLB,
163*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_GLOBAL_GLOBALLB,
164*77c1e3ccSAndroid Build Coastguard Worker 
165*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEARLA,
166*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEWLA,
167*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARESTLA,
168*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEWLA,
169*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARLA,
170*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEWLA,
171*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_GLOBAL_GLOBALLA,
172*77c1e3ccSAndroid Build Coastguard Worker 
173*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEARL2A,
174*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEWL2A,
175*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARESTL2A,
176*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEWL2A,
177*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARL2A,
178*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEWL2A,
179*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_GLOBAL_GLOBALL2A,
180*77c1e3ccSAndroid Build Coastguard Worker 
181*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEARL3A,
182*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEWL3A,
183*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARESTL3A,
184*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEWL3A,
185*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARL3A,
186*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEWL3A,
187*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_GLOBAL_GLOBALL3A,
188*77c1e3ccSAndroid Build Coastguard Worker 
189*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEARGA,
190*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEWGA,
191*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARESTGA,
192*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEWGA,
193*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARGA,
194*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEWGA,
195*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_GLOBAL_GLOBALGA,
196*77c1e3ccSAndroid Build Coastguard Worker 
197*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEARL2B,
198*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEWL2B,
199*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARESTL2B,
200*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEWL2B,
201*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARL2B,
202*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEWL2B,
203*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_GLOBAL_GLOBALL2B,
204*77c1e3ccSAndroid Build Coastguard Worker 
205*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEARL3B,
206*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEWL3B,
207*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARESTL3B,
208*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEWL3B,
209*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARL3B,
210*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEWL3B,
211*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_GLOBAL_GLOBALL3B,
212*77c1e3ccSAndroid Build Coastguard Worker 
213*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEARGB,
214*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEWGB,
215*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARESTGB,
216*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEWGB,
217*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARGB,
218*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEWGB,
219*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_GLOBAL_GLOBALGB,
220*77c1e3ccSAndroid Build Coastguard Worker 
221*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEARLA2,
222*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEWLA2,
223*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARESTLA2,
224*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEWLA2,
225*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARLA2,
226*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEWLA2,
227*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_GLOBAL_GLOBALLA2,
228*77c1e3ccSAndroid Build Coastguard Worker 
229*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEARL2A2,
230*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEWL2A2,
231*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARESTL2A2,
232*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEWL2A2,
233*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARL2A2,
234*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEWL2A2,
235*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_GLOBAL_GLOBALL2A2,
236*77c1e3ccSAndroid Build Coastguard Worker 
237*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEARL3A2,
238*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEWL3A2,
239*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARESTL3A2,
240*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEWL3A2,
241*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARL3A2,
242*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEWL3A2,
243*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_GLOBAL_GLOBALL3A2,
244*77c1e3ccSAndroid Build Coastguard Worker 
245*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEARGA2,
246*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEWGA2,
247*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARESTGA2,
248*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEWGA2,
249*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARGA2,
250*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEWGA2,
251*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_GLOBAL_GLOBALGA2,
252*77c1e3ccSAndroid Build Coastguard Worker 
253*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEARLL2,
254*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEWLL2,
255*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARESTLL2,
256*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEWLL2,
257*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARLL2,
258*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEWLL2,
259*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_GLOBAL_GLOBALLL2,
260*77c1e3ccSAndroid Build Coastguard Worker 
261*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEARLL3,
262*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEWLL3,
263*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARESTLL3,
264*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEWLL3,
265*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARLL3,
266*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEWLL3,
267*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_GLOBAL_GLOBALLL3,
268*77c1e3ccSAndroid Build Coastguard Worker 
269*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEARLG,
270*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEWLG,
271*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARESTLG,
272*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEWLG,
273*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARLG,
274*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEWLG,
275*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_GLOBAL_GLOBALLG,
276*77c1e3ccSAndroid Build Coastguard Worker 
277*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEARBA,
278*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEWBA,
279*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARESTBA,
280*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAREST_NEWBA,
281*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEW_NEARBA,
282*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_NEAR_NEWBA,
283*77c1e3ccSAndroid Build Coastguard Worker   THR_COMP_GLOBAL_GLOBALBA,
284*77c1e3ccSAndroid Build Coastguard Worker 
285*77c1e3ccSAndroid Build Coastguard Worker   THR_DC,
286*77c1e3ccSAndroid Build Coastguard Worker   THR_PAETH,
287*77c1e3ccSAndroid Build Coastguard Worker   THR_SMOOTH,
288*77c1e3ccSAndroid Build Coastguard Worker   THR_SMOOTH_V,
289*77c1e3ccSAndroid Build Coastguard Worker   THR_SMOOTH_H,
290*77c1e3ccSAndroid Build Coastguard Worker   THR_H_PRED,
291*77c1e3ccSAndroid Build Coastguard Worker   THR_V_PRED,
292*77c1e3ccSAndroid Build Coastguard Worker   THR_D135_PRED,
293*77c1e3ccSAndroid Build Coastguard Worker   THR_D203_PRED,
294*77c1e3ccSAndroid Build Coastguard Worker   THR_D157_PRED,
295*77c1e3ccSAndroid Build Coastguard Worker   THR_D67_PRED,
296*77c1e3ccSAndroid Build Coastguard Worker   THR_D113_PRED,
297*77c1e3ccSAndroid Build Coastguard Worker   THR_D45_PRED,
298*77c1e3ccSAndroid Build Coastguard Worker };
299*77c1e3ccSAndroid Build Coastguard Worker 
300*77c1e3ccSAndroid Build Coastguard Worker /*!\cond */
301*77c1e3ccSAndroid Build Coastguard Worker typedef struct SingleInterModeState {
302*77c1e3ccSAndroid Build Coastguard Worker   int64_t rd;
303*77c1e3ccSAndroid Build Coastguard Worker   MV_REFERENCE_FRAME ref_frame;
304*77c1e3ccSAndroid Build Coastguard Worker   int valid;
305*77c1e3ccSAndroid Build Coastguard Worker } SingleInterModeState;
306*77c1e3ccSAndroid Build Coastguard Worker 
307*77c1e3ccSAndroid Build Coastguard Worker typedef struct InterModeSearchState {
308*77c1e3ccSAndroid Build Coastguard Worker   int64_t best_rd;
309*77c1e3ccSAndroid Build Coastguard Worker   int64_t best_skip_rd[2];
310*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO best_mbmode;
311*77c1e3ccSAndroid Build Coastguard Worker   int best_rate_y;
312*77c1e3ccSAndroid Build Coastguard Worker   int best_rate_uv;
313*77c1e3ccSAndroid Build Coastguard Worker   int best_mode_skippable;
314*77c1e3ccSAndroid Build Coastguard Worker   int best_skip2;
315*77c1e3ccSAndroid Build Coastguard Worker   THR_MODES best_mode_index;
316*77c1e3ccSAndroid Build Coastguard Worker   int num_available_refs;
317*77c1e3ccSAndroid Build Coastguard Worker   int64_t dist_refs[REF_FRAMES];
318*77c1e3ccSAndroid Build Coastguard Worker   int dist_order_refs[REF_FRAMES];
319*77c1e3ccSAndroid Build Coastguard Worker   int64_t mode_threshold[MAX_MODES];
320*77c1e3ccSAndroid Build Coastguard Worker   int64_t best_intra_rd;
321*77c1e3ccSAndroid Build Coastguard Worker   unsigned int best_pred_sse;
322*77c1e3ccSAndroid Build Coastguard Worker 
323*77c1e3ccSAndroid Build Coastguard Worker   /*!
324*77c1e3ccSAndroid Build Coastguard Worker    * \brief Keep track of best intra rd for use in compound mode.
325*77c1e3ccSAndroid Build Coastguard Worker    */
326*77c1e3ccSAndroid Build Coastguard Worker   int64_t best_pred_rd[REFERENCE_MODES];
327*77c1e3ccSAndroid Build Coastguard Worker   // Save a set of single_newmv for each checked ref_mv.
328*77c1e3ccSAndroid Build Coastguard Worker   int_mv single_newmv[MAX_REF_MV_SEARCH][REF_FRAMES];
329*77c1e3ccSAndroid Build Coastguard Worker   int single_newmv_rate[MAX_REF_MV_SEARCH][REF_FRAMES];
330*77c1e3ccSAndroid Build Coastguard Worker   int single_newmv_valid[MAX_REF_MV_SEARCH][REF_FRAMES];
331*77c1e3ccSAndroid Build Coastguard Worker   int64_t modelled_rd[MB_MODE_COUNT][MAX_REF_MV_SEARCH][REF_FRAMES];
332*77c1e3ccSAndroid Build Coastguard Worker   // The rd of simple translation in single inter modes
333*77c1e3ccSAndroid Build Coastguard Worker   int64_t simple_rd[MB_MODE_COUNT][MAX_REF_MV_SEARCH][REF_FRAMES];
334*77c1e3ccSAndroid Build Coastguard Worker   int64_t best_single_rd[REF_FRAMES];
335*77c1e3ccSAndroid Build Coastguard Worker   PREDICTION_MODE best_single_mode[REF_FRAMES];
336*77c1e3ccSAndroid Build Coastguard Worker 
337*77c1e3ccSAndroid Build Coastguard Worker   // Single search results by [directions][modes][reference frames]
338*77c1e3ccSAndroid Build Coastguard Worker   SingleInterModeState single_state[2][SINGLE_INTER_MODE_NUM][FWD_REFS];
339*77c1e3ccSAndroid Build Coastguard Worker   int single_state_cnt[2][SINGLE_INTER_MODE_NUM];
340*77c1e3ccSAndroid Build Coastguard Worker   SingleInterModeState single_state_modelled[2][SINGLE_INTER_MODE_NUM]
341*77c1e3ccSAndroid Build Coastguard Worker                                             [FWD_REFS];
342*77c1e3ccSAndroid Build Coastguard Worker   int single_state_modelled_cnt[2][SINGLE_INTER_MODE_NUM];
343*77c1e3ccSAndroid Build Coastguard Worker   MV_REFERENCE_FRAME single_rd_order[2][SINGLE_INTER_MODE_NUM][FWD_REFS];
344*77c1e3ccSAndroid Build Coastguard Worker   IntraModeSearchState intra_search_state;
345*77c1e3ccSAndroid Build Coastguard Worker   RD_STATS best_y_rdcost;
346*77c1e3ccSAndroid Build Coastguard Worker } InterModeSearchState;
347*77c1e3ccSAndroid Build Coastguard Worker /*!\endcond */
348*77c1e3ccSAndroid Build Coastguard Worker 
av1_inter_mode_data_init(TileDataEnc * tile_data)349*77c1e3ccSAndroid Build Coastguard Worker void av1_inter_mode_data_init(TileDataEnc *tile_data) {
350*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < BLOCK_SIZES_ALL; ++i) {
351*77c1e3ccSAndroid Build Coastguard Worker     InterModeRdModel *md = &tile_data->inter_mode_rd_models[i];
352*77c1e3ccSAndroid Build Coastguard Worker     md->ready = 0;
353*77c1e3ccSAndroid Build Coastguard Worker     md->num = 0;
354*77c1e3ccSAndroid Build Coastguard Worker     md->dist_sum = 0;
355*77c1e3ccSAndroid Build Coastguard Worker     md->ld_sum = 0;
356*77c1e3ccSAndroid Build Coastguard Worker     md->sse_sum = 0;
357*77c1e3ccSAndroid Build Coastguard Worker     md->sse_sse_sum = 0;
358*77c1e3ccSAndroid Build Coastguard Worker     md->sse_ld_sum = 0;
359*77c1e3ccSAndroid Build Coastguard Worker   }
360*77c1e3ccSAndroid Build Coastguard Worker }
361*77c1e3ccSAndroid Build Coastguard Worker 
get_est_rate_dist(const TileDataEnc * tile_data,BLOCK_SIZE bsize,int64_t sse,int * est_residue_cost,int64_t * est_dist)362*77c1e3ccSAndroid Build Coastguard Worker static int get_est_rate_dist(const TileDataEnc *tile_data, BLOCK_SIZE bsize,
363*77c1e3ccSAndroid Build Coastguard Worker                              int64_t sse, int *est_residue_cost,
364*77c1e3ccSAndroid Build Coastguard Worker                              int64_t *est_dist) {
365*77c1e3ccSAndroid Build Coastguard Worker   const InterModeRdModel *md = &tile_data->inter_mode_rd_models[bsize];
366*77c1e3ccSAndroid Build Coastguard Worker   if (md->ready) {
367*77c1e3ccSAndroid Build Coastguard Worker     if (sse < md->dist_mean) {
368*77c1e3ccSAndroid Build Coastguard Worker       *est_residue_cost = 0;
369*77c1e3ccSAndroid Build Coastguard Worker       *est_dist = sse;
370*77c1e3ccSAndroid Build Coastguard Worker     } else {
371*77c1e3ccSAndroid Build Coastguard Worker       *est_dist = (int64_t)round(md->dist_mean);
372*77c1e3ccSAndroid Build Coastguard Worker       const double est_ld = md->a * sse + md->b;
373*77c1e3ccSAndroid Build Coastguard Worker       // Clamp estimated rate cost by INT_MAX / 2.
374*77c1e3ccSAndroid Build Coastguard Worker       // TODO([email protected]): find better solution than clamping.
375*77c1e3ccSAndroid Build Coastguard Worker       if (fabs(est_ld) < 1e-2) {
376*77c1e3ccSAndroid Build Coastguard Worker         *est_residue_cost = INT_MAX / 2;
377*77c1e3ccSAndroid Build Coastguard Worker       } else {
378*77c1e3ccSAndroid Build Coastguard Worker         double est_residue_cost_dbl = ((sse - md->dist_mean) / est_ld);
379*77c1e3ccSAndroid Build Coastguard Worker         if (est_residue_cost_dbl < 0) {
380*77c1e3ccSAndroid Build Coastguard Worker           *est_residue_cost = 0;
381*77c1e3ccSAndroid Build Coastguard Worker         } else {
382*77c1e3ccSAndroid Build Coastguard Worker           *est_residue_cost =
383*77c1e3ccSAndroid Build Coastguard Worker               (int)AOMMIN((int64_t)round(est_residue_cost_dbl), INT_MAX / 2);
384*77c1e3ccSAndroid Build Coastguard Worker         }
385*77c1e3ccSAndroid Build Coastguard Worker       }
386*77c1e3ccSAndroid Build Coastguard Worker       if (*est_residue_cost <= 0) {
387*77c1e3ccSAndroid Build Coastguard Worker         *est_residue_cost = 0;
388*77c1e3ccSAndroid Build Coastguard Worker         *est_dist = sse;
389*77c1e3ccSAndroid Build Coastguard Worker       }
390*77c1e3ccSAndroid Build Coastguard Worker     }
391*77c1e3ccSAndroid Build Coastguard Worker     return 1;
392*77c1e3ccSAndroid Build Coastguard Worker   }
393*77c1e3ccSAndroid Build Coastguard Worker   return 0;
394*77c1e3ccSAndroid Build Coastguard Worker }
395*77c1e3ccSAndroid Build Coastguard Worker 
av1_inter_mode_data_fit(TileDataEnc * tile_data,int rdmult)396*77c1e3ccSAndroid Build Coastguard Worker void av1_inter_mode_data_fit(TileDataEnc *tile_data, int rdmult) {
397*77c1e3ccSAndroid Build Coastguard Worker   for (int bsize = 0; bsize < BLOCK_SIZES_ALL; ++bsize) {
398*77c1e3ccSAndroid Build Coastguard Worker     const int block_idx = inter_mode_data_block_idx(bsize);
399*77c1e3ccSAndroid Build Coastguard Worker     InterModeRdModel *md = &tile_data->inter_mode_rd_models[bsize];
400*77c1e3ccSAndroid Build Coastguard Worker     if (block_idx == -1) continue;
401*77c1e3ccSAndroid Build Coastguard Worker     if ((md->ready == 0 && md->num < 200) || (md->ready == 1 && md->num < 64)) {
402*77c1e3ccSAndroid Build Coastguard Worker       continue;
403*77c1e3ccSAndroid Build Coastguard Worker     } else {
404*77c1e3ccSAndroid Build Coastguard Worker       if (md->ready == 0) {
405*77c1e3ccSAndroid Build Coastguard Worker         md->dist_mean = md->dist_sum / md->num;
406*77c1e3ccSAndroid Build Coastguard Worker         md->ld_mean = md->ld_sum / md->num;
407*77c1e3ccSAndroid Build Coastguard Worker         md->sse_mean = md->sse_sum / md->num;
408*77c1e3ccSAndroid Build Coastguard Worker         md->sse_sse_mean = md->sse_sse_sum / md->num;
409*77c1e3ccSAndroid Build Coastguard Worker         md->sse_ld_mean = md->sse_ld_sum / md->num;
410*77c1e3ccSAndroid Build Coastguard Worker       } else {
411*77c1e3ccSAndroid Build Coastguard Worker         const double factor = 3;
412*77c1e3ccSAndroid Build Coastguard Worker         md->dist_mean =
413*77c1e3ccSAndroid Build Coastguard Worker             (md->dist_mean * factor + (md->dist_sum / md->num)) / (factor + 1);
414*77c1e3ccSAndroid Build Coastguard Worker         md->ld_mean =
415*77c1e3ccSAndroid Build Coastguard Worker             (md->ld_mean * factor + (md->ld_sum / md->num)) / (factor + 1);
416*77c1e3ccSAndroid Build Coastguard Worker         md->sse_mean =
417*77c1e3ccSAndroid Build Coastguard Worker             (md->sse_mean * factor + (md->sse_sum / md->num)) / (factor + 1);
418*77c1e3ccSAndroid Build Coastguard Worker         md->sse_sse_mean =
419*77c1e3ccSAndroid Build Coastguard Worker             (md->sse_sse_mean * factor + (md->sse_sse_sum / md->num)) /
420*77c1e3ccSAndroid Build Coastguard Worker             (factor + 1);
421*77c1e3ccSAndroid Build Coastguard Worker         md->sse_ld_mean =
422*77c1e3ccSAndroid Build Coastguard Worker             (md->sse_ld_mean * factor + (md->sse_ld_sum / md->num)) /
423*77c1e3ccSAndroid Build Coastguard Worker             (factor + 1);
424*77c1e3ccSAndroid Build Coastguard Worker       }
425*77c1e3ccSAndroid Build Coastguard Worker 
426*77c1e3ccSAndroid Build Coastguard Worker       const double my = md->ld_mean;
427*77c1e3ccSAndroid Build Coastguard Worker       const double mx = md->sse_mean;
428*77c1e3ccSAndroid Build Coastguard Worker       const double dx = sqrt(md->sse_sse_mean);
429*77c1e3ccSAndroid Build Coastguard Worker       const double dxy = md->sse_ld_mean;
430*77c1e3ccSAndroid Build Coastguard Worker 
431*77c1e3ccSAndroid Build Coastguard Worker       md->a = (dxy - mx * my) / (dx * dx - mx * mx);
432*77c1e3ccSAndroid Build Coastguard Worker       md->b = my - md->a * mx;
433*77c1e3ccSAndroid Build Coastguard Worker       md->ready = 1;
434*77c1e3ccSAndroid Build Coastguard Worker 
435*77c1e3ccSAndroid Build Coastguard Worker       md->num = 0;
436*77c1e3ccSAndroid Build Coastguard Worker       md->dist_sum = 0;
437*77c1e3ccSAndroid Build Coastguard Worker       md->ld_sum = 0;
438*77c1e3ccSAndroid Build Coastguard Worker       md->sse_sum = 0;
439*77c1e3ccSAndroid Build Coastguard Worker       md->sse_sse_sum = 0;
440*77c1e3ccSAndroid Build Coastguard Worker       md->sse_ld_sum = 0;
441*77c1e3ccSAndroid Build Coastguard Worker     }
442*77c1e3ccSAndroid Build Coastguard Worker     (void)rdmult;
443*77c1e3ccSAndroid Build Coastguard Worker   }
444*77c1e3ccSAndroid Build Coastguard Worker }
445*77c1e3ccSAndroid Build Coastguard Worker 
inter_mode_data_push(TileDataEnc * tile_data,BLOCK_SIZE bsize,int64_t sse,int64_t dist,int residue_cost)446*77c1e3ccSAndroid Build Coastguard Worker static inline void inter_mode_data_push(TileDataEnc *tile_data,
447*77c1e3ccSAndroid Build Coastguard Worker                                         BLOCK_SIZE bsize, int64_t sse,
448*77c1e3ccSAndroid Build Coastguard Worker                                         int64_t dist, int residue_cost) {
449*77c1e3ccSAndroid Build Coastguard Worker   if (residue_cost == 0 || sse == dist) return;
450*77c1e3ccSAndroid Build Coastguard Worker   const int block_idx = inter_mode_data_block_idx(bsize);
451*77c1e3ccSAndroid Build Coastguard Worker   if (block_idx == -1) return;
452*77c1e3ccSAndroid Build Coastguard Worker   InterModeRdModel *rd_model = &tile_data->inter_mode_rd_models[bsize];
453*77c1e3ccSAndroid Build Coastguard Worker   if (rd_model->num < INTER_MODE_RD_DATA_OVERALL_SIZE) {
454*77c1e3ccSAndroid Build Coastguard Worker     const double ld = (sse - dist) * 1. / residue_cost;
455*77c1e3ccSAndroid Build Coastguard Worker     ++rd_model->num;
456*77c1e3ccSAndroid Build Coastguard Worker     rd_model->dist_sum += dist;
457*77c1e3ccSAndroid Build Coastguard Worker     rd_model->ld_sum += ld;
458*77c1e3ccSAndroid Build Coastguard Worker     rd_model->sse_sum += sse;
459*77c1e3ccSAndroid Build Coastguard Worker     rd_model->sse_sse_sum += (double)sse * (double)sse;
460*77c1e3ccSAndroid Build Coastguard Worker     rd_model->sse_ld_sum += sse * ld;
461*77c1e3ccSAndroid Build Coastguard Worker   }
462*77c1e3ccSAndroid Build Coastguard Worker }
463*77c1e3ccSAndroid Build Coastguard Worker 
inter_modes_info_push(InterModesInfo * inter_modes_info,int mode_rate,int64_t sse,int64_t rd,RD_STATS * rd_cost,RD_STATS * rd_cost_y,RD_STATS * rd_cost_uv,const MB_MODE_INFO * mbmi)464*77c1e3ccSAndroid Build Coastguard Worker static inline void inter_modes_info_push(InterModesInfo *inter_modes_info,
465*77c1e3ccSAndroid Build Coastguard Worker                                          int mode_rate, int64_t sse, int64_t rd,
466*77c1e3ccSAndroid Build Coastguard Worker                                          RD_STATS *rd_cost, RD_STATS *rd_cost_y,
467*77c1e3ccSAndroid Build Coastguard Worker                                          RD_STATS *rd_cost_uv,
468*77c1e3ccSAndroid Build Coastguard Worker                                          const MB_MODE_INFO *mbmi) {
469*77c1e3ccSAndroid Build Coastguard Worker   const int num = inter_modes_info->num;
470*77c1e3ccSAndroid Build Coastguard Worker   assert(num < MAX_INTER_MODES);
471*77c1e3ccSAndroid Build Coastguard Worker   inter_modes_info->mbmi_arr[num] = *mbmi;
472*77c1e3ccSAndroid Build Coastguard Worker   inter_modes_info->mode_rate_arr[num] = mode_rate;
473*77c1e3ccSAndroid Build Coastguard Worker   inter_modes_info->sse_arr[num] = sse;
474*77c1e3ccSAndroid Build Coastguard Worker   inter_modes_info->est_rd_arr[num] = rd;
475*77c1e3ccSAndroid Build Coastguard Worker   inter_modes_info->rd_cost_arr[num] = *rd_cost;
476*77c1e3ccSAndroid Build Coastguard Worker   inter_modes_info->rd_cost_y_arr[num] = *rd_cost_y;
477*77c1e3ccSAndroid Build Coastguard Worker   inter_modes_info->rd_cost_uv_arr[num] = *rd_cost_uv;
478*77c1e3ccSAndroid Build Coastguard Worker   ++inter_modes_info->num;
479*77c1e3ccSAndroid Build Coastguard Worker }
480*77c1e3ccSAndroid Build Coastguard Worker 
compare_rd_idx_pair(const void * a,const void * b)481*77c1e3ccSAndroid Build Coastguard Worker static int compare_rd_idx_pair(const void *a, const void *b) {
482*77c1e3ccSAndroid Build Coastguard Worker   if (((RdIdxPair *)a)->rd == ((RdIdxPair *)b)->rd) {
483*77c1e3ccSAndroid Build Coastguard Worker     // To avoid inconsistency in qsort() ordering when two elements are equal,
484*77c1e3ccSAndroid Build Coastguard Worker     // using idx as tie breaker. Refer aomedia:2928
485*77c1e3ccSAndroid Build Coastguard Worker     if (((RdIdxPair *)a)->idx == ((RdIdxPair *)b)->idx)
486*77c1e3ccSAndroid Build Coastguard Worker       return 0;
487*77c1e3ccSAndroid Build Coastguard Worker     else if (((RdIdxPair *)a)->idx > ((RdIdxPair *)b)->idx)
488*77c1e3ccSAndroid Build Coastguard Worker       return 1;
489*77c1e3ccSAndroid Build Coastguard Worker     else
490*77c1e3ccSAndroid Build Coastguard Worker       return -1;
491*77c1e3ccSAndroid Build Coastguard Worker   } else if (((const RdIdxPair *)a)->rd > ((const RdIdxPair *)b)->rd) {
492*77c1e3ccSAndroid Build Coastguard Worker     return 1;
493*77c1e3ccSAndroid Build Coastguard Worker   } else {
494*77c1e3ccSAndroid Build Coastguard Worker     return -1;
495*77c1e3ccSAndroid Build Coastguard Worker   }
496*77c1e3ccSAndroid Build Coastguard Worker }
497*77c1e3ccSAndroid Build Coastguard Worker 
inter_modes_info_sort(const InterModesInfo * inter_modes_info,RdIdxPair * rd_idx_pair_arr)498*77c1e3ccSAndroid Build Coastguard Worker static inline void inter_modes_info_sort(const InterModesInfo *inter_modes_info,
499*77c1e3ccSAndroid Build Coastguard Worker                                          RdIdxPair *rd_idx_pair_arr) {
500*77c1e3ccSAndroid Build Coastguard Worker   if (inter_modes_info->num == 0) {
501*77c1e3ccSAndroid Build Coastguard Worker     return;
502*77c1e3ccSAndroid Build Coastguard Worker   }
503*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < inter_modes_info->num; ++i) {
504*77c1e3ccSAndroid Build Coastguard Worker     rd_idx_pair_arr[i].idx = i;
505*77c1e3ccSAndroid Build Coastguard Worker     rd_idx_pair_arr[i].rd = inter_modes_info->est_rd_arr[i];
506*77c1e3ccSAndroid Build Coastguard Worker   }
507*77c1e3ccSAndroid Build Coastguard Worker   qsort(rd_idx_pair_arr, inter_modes_info->num, sizeof(rd_idx_pair_arr[0]),
508*77c1e3ccSAndroid Build Coastguard Worker         compare_rd_idx_pair);
509*77c1e3ccSAndroid Build Coastguard Worker }
510*77c1e3ccSAndroid Build Coastguard Worker 
511*77c1e3ccSAndroid Build Coastguard Worker // Similar to get_horver_correlation, but also takes into account first
512*77c1e3ccSAndroid Build Coastguard Worker // row/column, when computing horizontal/vertical correlation.
av1_get_horver_correlation_full_c(const int16_t * diff,int stride,int width,int height,float * hcorr,float * vcorr)513*77c1e3ccSAndroid Build Coastguard Worker void av1_get_horver_correlation_full_c(const int16_t *diff, int stride,
514*77c1e3ccSAndroid Build Coastguard Worker                                        int width, int height, float *hcorr,
515*77c1e3ccSAndroid Build Coastguard Worker                                        float *vcorr) {
516*77c1e3ccSAndroid Build Coastguard Worker   // The following notation is used:
517*77c1e3ccSAndroid Build Coastguard Worker   // x - current pixel
518*77c1e3ccSAndroid Build Coastguard Worker   // y - left neighbor pixel
519*77c1e3ccSAndroid Build Coastguard Worker   // z - top neighbor pixel
520*77c1e3ccSAndroid Build Coastguard Worker   int64_t x_sum = 0, x2_sum = 0, xy_sum = 0, xz_sum = 0;
521*77c1e3ccSAndroid Build Coastguard Worker   int64_t x_firstrow = 0, x_finalrow = 0, x_firstcol = 0, x_finalcol = 0;
522*77c1e3ccSAndroid Build Coastguard Worker   int64_t x2_firstrow = 0, x2_finalrow = 0, x2_firstcol = 0, x2_finalcol = 0;
523*77c1e3ccSAndroid Build Coastguard Worker 
524*77c1e3ccSAndroid Build Coastguard Worker   // First, process horizontal correlation on just the first row
525*77c1e3ccSAndroid Build Coastguard Worker   x_sum += diff[0];
526*77c1e3ccSAndroid Build Coastguard Worker   x2_sum += diff[0] * diff[0];
527*77c1e3ccSAndroid Build Coastguard Worker   x_firstrow += diff[0];
528*77c1e3ccSAndroid Build Coastguard Worker   x2_firstrow += diff[0] * diff[0];
529*77c1e3ccSAndroid Build Coastguard Worker   for (int j = 1; j < width; ++j) {
530*77c1e3ccSAndroid Build Coastguard Worker     const int16_t x = diff[j];
531*77c1e3ccSAndroid Build Coastguard Worker     const int16_t y = diff[j - 1];
532*77c1e3ccSAndroid Build Coastguard Worker     x_sum += x;
533*77c1e3ccSAndroid Build Coastguard Worker     x_firstrow += x;
534*77c1e3ccSAndroid Build Coastguard Worker     x2_sum += x * x;
535*77c1e3ccSAndroid Build Coastguard Worker     x2_firstrow += x * x;
536*77c1e3ccSAndroid Build Coastguard Worker     xy_sum += x * y;
537*77c1e3ccSAndroid Build Coastguard Worker   }
538*77c1e3ccSAndroid Build Coastguard Worker 
539*77c1e3ccSAndroid Build Coastguard Worker   // Process vertical correlation in the first column
540*77c1e3ccSAndroid Build Coastguard Worker   x_firstcol += diff[0];
541*77c1e3ccSAndroid Build Coastguard Worker   x2_firstcol += diff[0] * diff[0];
542*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 1; i < height; ++i) {
543*77c1e3ccSAndroid Build Coastguard Worker     const int16_t x = diff[i * stride];
544*77c1e3ccSAndroid Build Coastguard Worker     const int16_t z = diff[(i - 1) * stride];
545*77c1e3ccSAndroid Build Coastguard Worker     x_sum += x;
546*77c1e3ccSAndroid Build Coastguard Worker     x_firstcol += x;
547*77c1e3ccSAndroid Build Coastguard Worker     x2_sum += x * x;
548*77c1e3ccSAndroid Build Coastguard Worker     x2_firstcol += x * x;
549*77c1e3ccSAndroid Build Coastguard Worker     xz_sum += x * z;
550*77c1e3ccSAndroid Build Coastguard Worker   }
551*77c1e3ccSAndroid Build Coastguard Worker 
552*77c1e3ccSAndroid Build Coastguard Worker   // Now process horiz and vert correlation through the rest unit
553*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 1; i < height; ++i) {
554*77c1e3ccSAndroid Build Coastguard Worker     for (int j = 1; j < width; ++j) {
555*77c1e3ccSAndroid Build Coastguard Worker       const int16_t x = diff[i * stride + j];
556*77c1e3ccSAndroid Build Coastguard Worker       const int16_t y = diff[i * stride + j - 1];
557*77c1e3ccSAndroid Build Coastguard Worker       const int16_t z = diff[(i - 1) * stride + j];
558*77c1e3ccSAndroid Build Coastguard Worker       x_sum += x;
559*77c1e3ccSAndroid Build Coastguard Worker       x2_sum += x * x;
560*77c1e3ccSAndroid Build Coastguard Worker       xy_sum += x * y;
561*77c1e3ccSAndroid Build Coastguard Worker       xz_sum += x * z;
562*77c1e3ccSAndroid Build Coastguard Worker     }
563*77c1e3ccSAndroid Build Coastguard Worker   }
564*77c1e3ccSAndroid Build Coastguard Worker 
565*77c1e3ccSAndroid Build Coastguard Worker   for (int j = 0; j < width; ++j) {
566*77c1e3ccSAndroid Build Coastguard Worker     x_finalrow += diff[(height - 1) * stride + j];
567*77c1e3ccSAndroid Build Coastguard Worker     x2_finalrow +=
568*77c1e3ccSAndroid Build Coastguard Worker         diff[(height - 1) * stride + j] * diff[(height - 1) * stride + j];
569*77c1e3ccSAndroid Build Coastguard Worker   }
570*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < height; ++i) {
571*77c1e3ccSAndroid Build Coastguard Worker     x_finalcol += diff[i * stride + width - 1];
572*77c1e3ccSAndroid Build Coastguard Worker     x2_finalcol += diff[i * stride + width - 1] * diff[i * stride + width - 1];
573*77c1e3ccSAndroid Build Coastguard Worker   }
574*77c1e3ccSAndroid Build Coastguard Worker 
575*77c1e3ccSAndroid Build Coastguard Worker   int64_t xhor_sum = x_sum - x_finalcol;
576*77c1e3ccSAndroid Build Coastguard Worker   int64_t xver_sum = x_sum - x_finalrow;
577*77c1e3ccSAndroid Build Coastguard Worker   int64_t y_sum = x_sum - x_firstcol;
578*77c1e3ccSAndroid Build Coastguard Worker   int64_t z_sum = x_sum - x_firstrow;
579*77c1e3ccSAndroid Build Coastguard Worker   int64_t x2hor_sum = x2_sum - x2_finalcol;
580*77c1e3ccSAndroid Build Coastguard Worker   int64_t x2ver_sum = x2_sum - x2_finalrow;
581*77c1e3ccSAndroid Build Coastguard Worker   int64_t y2_sum = x2_sum - x2_firstcol;
582*77c1e3ccSAndroid Build Coastguard Worker   int64_t z2_sum = x2_sum - x2_firstrow;
583*77c1e3ccSAndroid Build Coastguard Worker 
584*77c1e3ccSAndroid Build Coastguard Worker   const float num_hor = (float)(height * (width - 1));
585*77c1e3ccSAndroid Build Coastguard Worker   const float num_ver = (float)((height - 1) * width);
586*77c1e3ccSAndroid Build Coastguard Worker 
587*77c1e3ccSAndroid Build Coastguard Worker   const float xhor_var_n = x2hor_sum - (xhor_sum * xhor_sum) / num_hor;
588*77c1e3ccSAndroid Build Coastguard Worker   const float xver_var_n = x2ver_sum - (xver_sum * xver_sum) / num_ver;
589*77c1e3ccSAndroid Build Coastguard Worker 
590*77c1e3ccSAndroid Build Coastguard Worker   const float y_var_n = y2_sum - (y_sum * y_sum) / num_hor;
591*77c1e3ccSAndroid Build Coastguard Worker   const float z_var_n = z2_sum - (z_sum * z_sum) / num_ver;
592*77c1e3ccSAndroid Build Coastguard Worker 
593*77c1e3ccSAndroid Build Coastguard Worker   const float xy_var_n = xy_sum - (xhor_sum * y_sum) / num_hor;
594*77c1e3ccSAndroid Build Coastguard Worker   const float xz_var_n = xz_sum - (xver_sum * z_sum) / num_ver;
595*77c1e3ccSAndroid Build Coastguard Worker 
596*77c1e3ccSAndroid Build Coastguard Worker   if (xhor_var_n > 0 && y_var_n > 0) {
597*77c1e3ccSAndroid Build Coastguard Worker     *hcorr = xy_var_n / sqrtf(xhor_var_n * y_var_n);
598*77c1e3ccSAndroid Build Coastguard Worker     *hcorr = *hcorr < 0 ? 0 : *hcorr;
599*77c1e3ccSAndroid Build Coastguard Worker   } else {
600*77c1e3ccSAndroid Build Coastguard Worker     *hcorr = 1.0;
601*77c1e3ccSAndroid Build Coastguard Worker   }
602*77c1e3ccSAndroid Build Coastguard Worker   if (xver_var_n > 0 && z_var_n > 0) {
603*77c1e3ccSAndroid Build Coastguard Worker     *vcorr = xz_var_n / sqrtf(xver_var_n * z_var_n);
604*77c1e3ccSAndroid Build Coastguard Worker     *vcorr = *vcorr < 0 ? 0 : *vcorr;
605*77c1e3ccSAndroid Build Coastguard Worker   } else {
606*77c1e3ccSAndroid Build Coastguard Worker     *vcorr = 1.0;
607*77c1e3ccSAndroid Build Coastguard Worker   }
608*77c1e3ccSAndroid Build Coastguard Worker }
609*77c1e3ccSAndroid Build Coastguard Worker 
get_sse(const AV1_COMP * cpi,const MACROBLOCK * x,int64_t * sse_y)610*77c1e3ccSAndroid Build Coastguard Worker static int64_t get_sse(const AV1_COMP *cpi, const MACROBLOCK *x,
611*77c1e3ccSAndroid Build Coastguard Worker                        int64_t *sse_y) {
612*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *cm = &cpi->common;
613*77c1e3ccSAndroid Build Coastguard Worker   const int num_planes = av1_num_planes(cm);
614*77c1e3ccSAndroid Build Coastguard Worker   const MACROBLOCKD *xd = &x->e_mbd;
615*77c1e3ccSAndroid Build Coastguard Worker   const MB_MODE_INFO *mbmi = xd->mi[0];
616*77c1e3ccSAndroid Build Coastguard Worker   int64_t total_sse = 0;
617*77c1e3ccSAndroid Build Coastguard Worker   for (int plane = 0; plane < num_planes; ++plane) {
618*77c1e3ccSAndroid Build Coastguard Worker     if (plane && !xd->is_chroma_ref) break;
619*77c1e3ccSAndroid Build Coastguard Worker     const struct macroblock_plane *const p = &x->plane[plane];
620*77c1e3ccSAndroid Build Coastguard Worker     const struct macroblockd_plane *const pd = &xd->plane[plane];
621*77c1e3ccSAndroid Build Coastguard Worker     const BLOCK_SIZE bs =
622*77c1e3ccSAndroid Build Coastguard Worker         get_plane_block_size(mbmi->bsize, pd->subsampling_x, pd->subsampling_y);
623*77c1e3ccSAndroid Build Coastguard Worker     unsigned int sse;
624*77c1e3ccSAndroid Build Coastguard Worker 
625*77c1e3ccSAndroid Build Coastguard Worker     cpi->ppi->fn_ptr[bs].vf(p->src.buf, p->src.stride, pd->dst.buf,
626*77c1e3ccSAndroid Build Coastguard Worker                             pd->dst.stride, &sse);
627*77c1e3ccSAndroid Build Coastguard Worker     total_sse += sse;
628*77c1e3ccSAndroid Build Coastguard Worker     if (!plane && sse_y) *sse_y = sse;
629*77c1e3ccSAndroid Build Coastguard Worker   }
630*77c1e3ccSAndroid Build Coastguard Worker   total_sse <<= 4;
631*77c1e3ccSAndroid Build Coastguard Worker   return total_sse;
632*77c1e3ccSAndroid Build Coastguard Worker }
633*77c1e3ccSAndroid Build Coastguard Worker 
av1_block_error_c(const tran_low_t * coeff,const tran_low_t * dqcoeff,intptr_t block_size,int64_t * ssz)634*77c1e3ccSAndroid Build Coastguard Worker int64_t av1_block_error_c(const tran_low_t *coeff, const tran_low_t *dqcoeff,
635*77c1e3ccSAndroid Build Coastguard Worker                           intptr_t block_size, int64_t *ssz) {
636*77c1e3ccSAndroid Build Coastguard Worker   int i;
637*77c1e3ccSAndroid Build Coastguard Worker   int64_t error = 0, sqcoeff = 0;
638*77c1e3ccSAndroid Build Coastguard Worker 
639*77c1e3ccSAndroid Build Coastguard Worker   for (i = 0; i < block_size; i++) {
640*77c1e3ccSAndroid Build Coastguard Worker     const int diff = coeff[i] - dqcoeff[i];
641*77c1e3ccSAndroid Build Coastguard Worker     error += diff * diff;
642*77c1e3ccSAndroid Build Coastguard Worker     sqcoeff += coeff[i] * coeff[i];
643*77c1e3ccSAndroid Build Coastguard Worker   }
644*77c1e3ccSAndroid Build Coastguard Worker 
645*77c1e3ccSAndroid Build Coastguard Worker   *ssz = sqcoeff;
646*77c1e3ccSAndroid Build Coastguard Worker   return error;
647*77c1e3ccSAndroid Build Coastguard Worker }
648*77c1e3ccSAndroid Build Coastguard Worker 
av1_block_error_lp_c(const int16_t * coeff,const int16_t * dqcoeff,intptr_t block_size)649*77c1e3ccSAndroid Build Coastguard Worker int64_t av1_block_error_lp_c(const int16_t *coeff, const int16_t *dqcoeff,
650*77c1e3ccSAndroid Build Coastguard Worker                              intptr_t block_size) {
651*77c1e3ccSAndroid Build Coastguard Worker   int64_t error = 0;
652*77c1e3ccSAndroid Build Coastguard Worker 
653*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < block_size; i++) {
654*77c1e3ccSAndroid Build Coastguard Worker     const int diff = coeff[i] - dqcoeff[i];
655*77c1e3ccSAndroid Build Coastguard Worker     error += diff * diff;
656*77c1e3ccSAndroid Build Coastguard Worker   }
657*77c1e3ccSAndroid Build Coastguard Worker 
658*77c1e3ccSAndroid Build Coastguard Worker   return error;
659*77c1e3ccSAndroid Build Coastguard Worker }
660*77c1e3ccSAndroid Build Coastguard Worker 
661*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_AV1_HIGHBITDEPTH
av1_highbd_block_error_c(const tran_low_t * coeff,const tran_low_t * dqcoeff,intptr_t block_size,int64_t * ssz,int bd)662*77c1e3ccSAndroid Build Coastguard Worker int64_t av1_highbd_block_error_c(const tran_low_t *coeff,
663*77c1e3ccSAndroid Build Coastguard Worker                                  const tran_low_t *dqcoeff, intptr_t block_size,
664*77c1e3ccSAndroid Build Coastguard Worker                                  int64_t *ssz, int bd) {
665*77c1e3ccSAndroid Build Coastguard Worker   int i;
666*77c1e3ccSAndroid Build Coastguard Worker   int64_t error = 0, sqcoeff = 0;
667*77c1e3ccSAndroid Build Coastguard Worker   int shift = 2 * (bd - 8);
668*77c1e3ccSAndroid Build Coastguard Worker   int rounding = shift > 0 ? 1 << (shift - 1) : 0;
669*77c1e3ccSAndroid Build Coastguard Worker 
670*77c1e3ccSAndroid Build Coastguard Worker   for (i = 0; i < block_size; i++) {
671*77c1e3ccSAndroid Build Coastguard Worker     const int64_t diff = coeff[i] - dqcoeff[i];
672*77c1e3ccSAndroid Build Coastguard Worker     error += diff * diff;
673*77c1e3ccSAndroid Build Coastguard Worker     sqcoeff += (int64_t)coeff[i] * (int64_t)coeff[i];
674*77c1e3ccSAndroid Build Coastguard Worker   }
675*77c1e3ccSAndroid Build Coastguard Worker   assert(error >= 0 && sqcoeff >= 0);
676*77c1e3ccSAndroid Build Coastguard Worker   error = (error + rounding) >> shift;
677*77c1e3ccSAndroid Build Coastguard Worker   sqcoeff = (sqcoeff + rounding) >> shift;
678*77c1e3ccSAndroid Build Coastguard Worker 
679*77c1e3ccSAndroid Build Coastguard Worker   *ssz = sqcoeff;
680*77c1e3ccSAndroid Build Coastguard Worker   return error;
681*77c1e3ccSAndroid Build Coastguard Worker }
682*77c1e3ccSAndroid Build Coastguard Worker #endif
683*77c1e3ccSAndroid Build Coastguard Worker 
conditional_skipintra(PREDICTION_MODE mode,PREDICTION_MODE best_intra_mode)684*77c1e3ccSAndroid Build Coastguard Worker static int conditional_skipintra(PREDICTION_MODE mode,
685*77c1e3ccSAndroid Build Coastguard Worker                                  PREDICTION_MODE best_intra_mode) {
686*77c1e3ccSAndroid Build Coastguard Worker   if (mode == D113_PRED && best_intra_mode != V_PRED &&
687*77c1e3ccSAndroid Build Coastguard Worker       best_intra_mode != D135_PRED)
688*77c1e3ccSAndroid Build Coastguard Worker     return 1;
689*77c1e3ccSAndroid Build Coastguard Worker   if (mode == D67_PRED && best_intra_mode != V_PRED &&
690*77c1e3ccSAndroid Build Coastguard Worker       best_intra_mode != D45_PRED)
691*77c1e3ccSAndroid Build Coastguard Worker     return 1;
692*77c1e3ccSAndroid Build Coastguard Worker   if (mode == D203_PRED && best_intra_mode != H_PRED &&
693*77c1e3ccSAndroid Build Coastguard Worker       best_intra_mode != D45_PRED)
694*77c1e3ccSAndroid Build Coastguard Worker     return 1;
695*77c1e3ccSAndroid Build Coastguard Worker   if (mode == D157_PRED && best_intra_mode != H_PRED &&
696*77c1e3ccSAndroid Build Coastguard Worker       best_intra_mode != D135_PRED)
697*77c1e3ccSAndroid Build Coastguard Worker     return 1;
698*77c1e3ccSAndroid Build Coastguard Worker   return 0;
699*77c1e3ccSAndroid Build Coastguard Worker }
700*77c1e3ccSAndroid Build Coastguard Worker 
cost_mv_ref(const ModeCosts * const mode_costs,PREDICTION_MODE mode,int16_t mode_context)701*77c1e3ccSAndroid Build Coastguard Worker static int cost_mv_ref(const ModeCosts *const mode_costs, PREDICTION_MODE mode,
702*77c1e3ccSAndroid Build Coastguard Worker                        int16_t mode_context) {
703*77c1e3ccSAndroid Build Coastguard Worker   if (is_inter_compound_mode(mode)) {
704*77c1e3ccSAndroid Build Coastguard Worker     return mode_costs
705*77c1e3ccSAndroid Build Coastguard Worker         ->inter_compound_mode_cost[mode_context][INTER_COMPOUND_OFFSET(mode)];
706*77c1e3ccSAndroid Build Coastguard Worker   }
707*77c1e3ccSAndroid Build Coastguard Worker 
708*77c1e3ccSAndroid Build Coastguard Worker   int mode_cost = 0;
709*77c1e3ccSAndroid Build Coastguard Worker   int16_t mode_ctx = mode_context & NEWMV_CTX_MASK;
710*77c1e3ccSAndroid Build Coastguard Worker 
711*77c1e3ccSAndroid Build Coastguard Worker   assert(is_inter_mode(mode));
712*77c1e3ccSAndroid Build Coastguard Worker 
713*77c1e3ccSAndroid Build Coastguard Worker   if (mode == NEWMV) {
714*77c1e3ccSAndroid Build Coastguard Worker     mode_cost = mode_costs->newmv_mode_cost[mode_ctx][0];
715*77c1e3ccSAndroid Build Coastguard Worker     return mode_cost;
716*77c1e3ccSAndroid Build Coastguard Worker   } else {
717*77c1e3ccSAndroid Build Coastguard Worker     mode_cost = mode_costs->newmv_mode_cost[mode_ctx][1];
718*77c1e3ccSAndroid Build Coastguard Worker     mode_ctx = (mode_context >> GLOBALMV_OFFSET) & GLOBALMV_CTX_MASK;
719*77c1e3ccSAndroid Build Coastguard Worker 
720*77c1e3ccSAndroid Build Coastguard Worker     if (mode == GLOBALMV) {
721*77c1e3ccSAndroid Build Coastguard Worker       mode_cost += mode_costs->zeromv_mode_cost[mode_ctx][0];
722*77c1e3ccSAndroid Build Coastguard Worker       return mode_cost;
723*77c1e3ccSAndroid Build Coastguard Worker     } else {
724*77c1e3ccSAndroid Build Coastguard Worker       mode_cost += mode_costs->zeromv_mode_cost[mode_ctx][1];
725*77c1e3ccSAndroid Build Coastguard Worker       mode_ctx = (mode_context >> REFMV_OFFSET) & REFMV_CTX_MASK;
726*77c1e3ccSAndroid Build Coastguard Worker       mode_cost += mode_costs->refmv_mode_cost[mode_ctx][mode != NEARESTMV];
727*77c1e3ccSAndroid Build Coastguard Worker       return mode_cost;
728*77c1e3ccSAndroid Build Coastguard Worker     }
729*77c1e3ccSAndroid Build Coastguard Worker   }
730*77c1e3ccSAndroid Build Coastguard Worker }
731*77c1e3ccSAndroid Build Coastguard Worker 
get_single_mode(PREDICTION_MODE this_mode,int ref_idx)732*77c1e3ccSAndroid Build Coastguard Worker static inline PREDICTION_MODE get_single_mode(PREDICTION_MODE this_mode,
733*77c1e3ccSAndroid Build Coastguard Worker                                               int ref_idx) {
734*77c1e3ccSAndroid Build Coastguard Worker   return ref_idx ? compound_ref1_mode(this_mode)
735*77c1e3ccSAndroid Build Coastguard Worker                  : compound_ref0_mode(this_mode);
736*77c1e3ccSAndroid Build Coastguard Worker }
737*77c1e3ccSAndroid Build Coastguard Worker 
estimate_ref_frame_costs(const AV1_COMMON * cm,const MACROBLOCKD * xd,const ModeCosts * mode_costs,int segment_id,unsigned int * ref_costs_single,unsigned int (* ref_costs_comp)[REF_FRAMES])738*77c1e3ccSAndroid Build Coastguard Worker static inline void estimate_ref_frame_costs(
739*77c1e3ccSAndroid Build Coastguard Worker     const AV1_COMMON *cm, const MACROBLOCKD *xd, const ModeCosts *mode_costs,
740*77c1e3ccSAndroid Build Coastguard Worker     int segment_id, unsigned int *ref_costs_single,
741*77c1e3ccSAndroid Build Coastguard Worker     unsigned int (*ref_costs_comp)[REF_FRAMES]) {
742*77c1e3ccSAndroid Build Coastguard Worker   int seg_ref_active =
743*77c1e3ccSAndroid Build Coastguard Worker       segfeature_active(&cm->seg, segment_id, SEG_LVL_REF_FRAME);
744*77c1e3ccSAndroid Build Coastguard Worker   if (seg_ref_active) {
745*77c1e3ccSAndroid Build Coastguard Worker     memset(ref_costs_single, 0, REF_FRAMES * sizeof(*ref_costs_single));
746*77c1e3ccSAndroid Build Coastguard Worker     int ref_frame;
747*77c1e3ccSAndroid Build Coastguard Worker     for (ref_frame = 0; ref_frame < REF_FRAMES; ++ref_frame)
748*77c1e3ccSAndroid Build Coastguard Worker       memset(ref_costs_comp[ref_frame], 0,
749*77c1e3ccSAndroid Build Coastguard Worker              REF_FRAMES * sizeof((*ref_costs_comp)[0]));
750*77c1e3ccSAndroid Build Coastguard Worker   } else {
751*77c1e3ccSAndroid Build Coastguard Worker     int intra_inter_ctx = av1_get_intra_inter_context(xd);
752*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[INTRA_FRAME] =
753*77c1e3ccSAndroid Build Coastguard Worker         mode_costs->intra_inter_cost[intra_inter_ctx][0];
754*77c1e3ccSAndroid Build Coastguard Worker     unsigned int base_cost = mode_costs->intra_inter_cost[intra_inter_ctx][1];
755*77c1e3ccSAndroid Build Coastguard Worker 
756*77c1e3ccSAndroid Build Coastguard Worker     for (int i = LAST_FRAME; i <= ALTREF_FRAME; ++i)
757*77c1e3ccSAndroid Build Coastguard Worker       ref_costs_single[i] = base_cost;
758*77c1e3ccSAndroid Build Coastguard Worker 
759*77c1e3ccSAndroid Build Coastguard Worker     const int ctx_p1 = av1_get_pred_context_single_ref_p1(xd);
760*77c1e3ccSAndroid Build Coastguard Worker     const int ctx_p2 = av1_get_pred_context_single_ref_p2(xd);
761*77c1e3ccSAndroid Build Coastguard Worker     const int ctx_p3 = av1_get_pred_context_single_ref_p3(xd);
762*77c1e3ccSAndroid Build Coastguard Worker     const int ctx_p4 = av1_get_pred_context_single_ref_p4(xd);
763*77c1e3ccSAndroid Build Coastguard Worker     const int ctx_p5 = av1_get_pred_context_single_ref_p5(xd);
764*77c1e3ccSAndroid Build Coastguard Worker     const int ctx_p6 = av1_get_pred_context_single_ref_p6(xd);
765*77c1e3ccSAndroid Build Coastguard Worker 
766*77c1e3ccSAndroid Build Coastguard Worker     // Determine cost of a single ref frame, where frame types are represented
767*77c1e3ccSAndroid Build Coastguard Worker     // by a tree:
768*77c1e3ccSAndroid Build Coastguard Worker     // Level 0: add cost whether this ref is a forward or backward ref
769*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[LAST_FRAME] += mode_costs->single_ref_cost[ctx_p1][0][0];
770*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[LAST2_FRAME] += mode_costs->single_ref_cost[ctx_p1][0][0];
771*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[LAST3_FRAME] += mode_costs->single_ref_cost[ctx_p1][0][0];
772*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[GOLDEN_FRAME] += mode_costs->single_ref_cost[ctx_p1][0][0];
773*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[BWDREF_FRAME] += mode_costs->single_ref_cost[ctx_p1][0][1];
774*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[ALTREF2_FRAME] +=
775*77c1e3ccSAndroid Build Coastguard Worker         mode_costs->single_ref_cost[ctx_p1][0][1];
776*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[ALTREF_FRAME] += mode_costs->single_ref_cost[ctx_p1][0][1];
777*77c1e3ccSAndroid Build Coastguard Worker 
778*77c1e3ccSAndroid Build Coastguard Worker     // Level 1: if this ref is forward ref,
779*77c1e3ccSAndroid Build Coastguard Worker     // add cost whether it is last/last2 or last3/golden
780*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[LAST_FRAME] += mode_costs->single_ref_cost[ctx_p3][2][0];
781*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[LAST2_FRAME] += mode_costs->single_ref_cost[ctx_p3][2][0];
782*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[LAST3_FRAME] += mode_costs->single_ref_cost[ctx_p3][2][1];
783*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[GOLDEN_FRAME] += mode_costs->single_ref_cost[ctx_p3][2][1];
784*77c1e3ccSAndroid Build Coastguard Worker 
785*77c1e3ccSAndroid Build Coastguard Worker     // Level 1: if this ref is backward ref
786*77c1e3ccSAndroid Build Coastguard Worker     // then add cost whether this ref is altref or backward ref
787*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[BWDREF_FRAME] += mode_costs->single_ref_cost[ctx_p2][1][0];
788*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[ALTREF2_FRAME] +=
789*77c1e3ccSAndroid Build Coastguard Worker         mode_costs->single_ref_cost[ctx_p2][1][0];
790*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[ALTREF_FRAME] += mode_costs->single_ref_cost[ctx_p2][1][1];
791*77c1e3ccSAndroid Build Coastguard Worker 
792*77c1e3ccSAndroid Build Coastguard Worker     // Level 2: further add cost whether this ref is last or last2
793*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[LAST_FRAME] += mode_costs->single_ref_cost[ctx_p4][3][0];
794*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[LAST2_FRAME] += mode_costs->single_ref_cost[ctx_p4][3][1];
795*77c1e3ccSAndroid Build Coastguard Worker 
796*77c1e3ccSAndroid Build Coastguard Worker     // Level 2: last3 or golden
797*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[LAST3_FRAME] += mode_costs->single_ref_cost[ctx_p5][4][0];
798*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[GOLDEN_FRAME] += mode_costs->single_ref_cost[ctx_p5][4][1];
799*77c1e3ccSAndroid Build Coastguard Worker 
800*77c1e3ccSAndroid Build Coastguard Worker     // Level 2: bwdref or altref2
801*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[BWDREF_FRAME] += mode_costs->single_ref_cost[ctx_p6][5][0];
802*77c1e3ccSAndroid Build Coastguard Worker     ref_costs_single[ALTREF2_FRAME] +=
803*77c1e3ccSAndroid Build Coastguard Worker         mode_costs->single_ref_cost[ctx_p6][5][1];
804*77c1e3ccSAndroid Build Coastguard Worker 
805*77c1e3ccSAndroid Build Coastguard Worker     if (cm->current_frame.reference_mode != SINGLE_REFERENCE) {
806*77c1e3ccSAndroid Build Coastguard Worker       // Similar to single ref, determine cost of compound ref frames.
807*77c1e3ccSAndroid Build Coastguard Worker       // cost_compound_refs = cost_first_ref + cost_second_ref
808*77c1e3ccSAndroid Build Coastguard Worker       const int bwdref_comp_ctx_p = av1_get_pred_context_comp_bwdref_p(xd);
809*77c1e3ccSAndroid Build Coastguard Worker       const int bwdref_comp_ctx_p1 = av1_get_pred_context_comp_bwdref_p1(xd);
810*77c1e3ccSAndroid Build Coastguard Worker       const int ref_comp_ctx_p = av1_get_pred_context_comp_ref_p(xd);
811*77c1e3ccSAndroid Build Coastguard Worker       const int ref_comp_ctx_p1 = av1_get_pred_context_comp_ref_p1(xd);
812*77c1e3ccSAndroid Build Coastguard Worker       const int ref_comp_ctx_p2 = av1_get_pred_context_comp_ref_p2(xd);
813*77c1e3ccSAndroid Build Coastguard Worker 
814*77c1e3ccSAndroid Build Coastguard Worker       const int comp_ref_type_ctx = av1_get_comp_reference_type_context(xd);
815*77c1e3ccSAndroid Build Coastguard Worker       unsigned int ref_bicomp_costs[REF_FRAMES] = { 0 };
816*77c1e3ccSAndroid Build Coastguard Worker 
817*77c1e3ccSAndroid Build Coastguard Worker       ref_bicomp_costs[LAST_FRAME] = ref_bicomp_costs[LAST2_FRAME] =
818*77c1e3ccSAndroid Build Coastguard Worker           ref_bicomp_costs[LAST3_FRAME] = ref_bicomp_costs[GOLDEN_FRAME] =
819*77c1e3ccSAndroid Build Coastguard Worker               base_cost + mode_costs->comp_ref_type_cost[comp_ref_type_ctx][1];
820*77c1e3ccSAndroid Build Coastguard Worker       ref_bicomp_costs[BWDREF_FRAME] = ref_bicomp_costs[ALTREF2_FRAME] = 0;
821*77c1e3ccSAndroid Build Coastguard Worker       ref_bicomp_costs[ALTREF_FRAME] = 0;
822*77c1e3ccSAndroid Build Coastguard Worker 
823*77c1e3ccSAndroid Build Coastguard Worker       // cost of first ref frame
824*77c1e3ccSAndroid Build Coastguard Worker       ref_bicomp_costs[LAST_FRAME] +=
825*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->comp_ref_cost[ref_comp_ctx_p][0][0];
826*77c1e3ccSAndroid Build Coastguard Worker       ref_bicomp_costs[LAST2_FRAME] +=
827*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->comp_ref_cost[ref_comp_ctx_p][0][0];
828*77c1e3ccSAndroid Build Coastguard Worker       ref_bicomp_costs[LAST3_FRAME] +=
829*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->comp_ref_cost[ref_comp_ctx_p][0][1];
830*77c1e3ccSAndroid Build Coastguard Worker       ref_bicomp_costs[GOLDEN_FRAME] +=
831*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->comp_ref_cost[ref_comp_ctx_p][0][1];
832*77c1e3ccSAndroid Build Coastguard Worker 
833*77c1e3ccSAndroid Build Coastguard Worker       ref_bicomp_costs[LAST_FRAME] +=
834*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->comp_ref_cost[ref_comp_ctx_p1][1][0];
835*77c1e3ccSAndroid Build Coastguard Worker       ref_bicomp_costs[LAST2_FRAME] +=
836*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->comp_ref_cost[ref_comp_ctx_p1][1][1];
837*77c1e3ccSAndroid Build Coastguard Worker 
838*77c1e3ccSAndroid Build Coastguard Worker       ref_bicomp_costs[LAST3_FRAME] +=
839*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->comp_ref_cost[ref_comp_ctx_p2][2][0];
840*77c1e3ccSAndroid Build Coastguard Worker       ref_bicomp_costs[GOLDEN_FRAME] +=
841*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->comp_ref_cost[ref_comp_ctx_p2][2][1];
842*77c1e3ccSAndroid Build Coastguard Worker 
843*77c1e3ccSAndroid Build Coastguard Worker       // cost of second ref frame
844*77c1e3ccSAndroid Build Coastguard Worker       ref_bicomp_costs[BWDREF_FRAME] +=
845*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->comp_bwdref_cost[bwdref_comp_ctx_p][0][0];
846*77c1e3ccSAndroid Build Coastguard Worker       ref_bicomp_costs[ALTREF2_FRAME] +=
847*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->comp_bwdref_cost[bwdref_comp_ctx_p][0][0];
848*77c1e3ccSAndroid Build Coastguard Worker       ref_bicomp_costs[ALTREF_FRAME] +=
849*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->comp_bwdref_cost[bwdref_comp_ctx_p][0][1];
850*77c1e3ccSAndroid Build Coastguard Worker 
851*77c1e3ccSAndroid Build Coastguard Worker       ref_bicomp_costs[BWDREF_FRAME] +=
852*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->comp_bwdref_cost[bwdref_comp_ctx_p1][1][0];
853*77c1e3ccSAndroid Build Coastguard Worker       ref_bicomp_costs[ALTREF2_FRAME] +=
854*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->comp_bwdref_cost[bwdref_comp_ctx_p1][1][1];
855*77c1e3ccSAndroid Build Coastguard Worker 
856*77c1e3ccSAndroid Build Coastguard Worker       // cost: if one ref frame is forward ref, the other ref is backward ref
857*77c1e3ccSAndroid Build Coastguard Worker       int ref0, ref1;
858*77c1e3ccSAndroid Build Coastguard Worker       for (ref0 = LAST_FRAME; ref0 <= GOLDEN_FRAME; ++ref0) {
859*77c1e3ccSAndroid Build Coastguard Worker         for (ref1 = BWDREF_FRAME; ref1 <= ALTREF_FRAME; ++ref1) {
860*77c1e3ccSAndroid Build Coastguard Worker           ref_costs_comp[ref0][ref1] =
861*77c1e3ccSAndroid Build Coastguard Worker               ref_bicomp_costs[ref0] + ref_bicomp_costs[ref1];
862*77c1e3ccSAndroid Build Coastguard Worker         }
863*77c1e3ccSAndroid Build Coastguard Worker       }
864*77c1e3ccSAndroid Build Coastguard Worker 
865*77c1e3ccSAndroid Build Coastguard Worker       // cost: if both ref frames are the same side.
866*77c1e3ccSAndroid Build Coastguard Worker       const int uni_comp_ref_ctx_p = av1_get_pred_context_uni_comp_ref_p(xd);
867*77c1e3ccSAndroid Build Coastguard Worker       const int uni_comp_ref_ctx_p1 = av1_get_pred_context_uni_comp_ref_p1(xd);
868*77c1e3ccSAndroid Build Coastguard Worker       const int uni_comp_ref_ctx_p2 = av1_get_pred_context_uni_comp_ref_p2(xd);
869*77c1e3ccSAndroid Build Coastguard Worker       ref_costs_comp[LAST_FRAME][LAST2_FRAME] =
870*77c1e3ccSAndroid Build Coastguard Worker           base_cost + mode_costs->comp_ref_type_cost[comp_ref_type_ctx][0] +
871*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->uni_comp_ref_cost[uni_comp_ref_ctx_p][0][0] +
872*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->uni_comp_ref_cost[uni_comp_ref_ctx_p1][1][0];
873*77c1e3ccSAndroid Build Coastguard Worker       ref_costs_comp[LAST_FRAME][LAST3_FRAME] =
874*77c1e3ccSAndroid Build Coastguard Worker           base_cost + mode_costs->comp_ref_type_cost[comp_ref_type_ctx][0] +
875*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->uni_comp_ref_cost[uni_comp_ref_ctx_p][0][0] +
876*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->uni_comp_ref_cost[uni_comp_ref_ctx_p1][1][1] +
877*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->uni_comp_ref_cost[uni_comp_ref_ctx_p2][2][0];
878*77c1e3ccSAndroid Build Coastguard Worker       ref_costs_comp[LAST_FRAME][GOLDEN_FRAME] =
879*77c1e3ccSAndroid Build Coastguard Worker           base_cost + mode_costs->comp_ref_type_cost[comp_ref_type_ctx][0] +
880*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->uni_comp_ref_cost[uni_comp_ref_ctx_p][0][0] +
881*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->uni_comp_ref_cost[uni_comp_ref_ctx_p1][1][1] +
882*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->uni_comp_ref_cost[uni_comp_ref_ctx_p2][2][1];
883*77c1e3ccSAndroid Build Coastguard Worker       ref_costs_comp[BWDREF_FRAME][ALTREF_FRAME] =
884*77c1e3ccSAndroid Build Coastguard Worker           base_cost + mode_costs->comp_ref_type_cost[comp_ref_type_ctx][0] +
885*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->uni_comp_ref_cost[uni_comp_ref_ctx_p][0][1];
886*77c1e3ccSAndroid Build Coastguard Worker     } else {
887*77c1e3ccSAndroid Build Coastguard Worker       int ref0, ref1;
888*77c1e3ccSAndroid Build Coastguard Worker       for (ref0 = LAST_FRAME; ref0 <= GOLDEN_FRAME; ++ref0) {
889*77c1e3ccSAndroid Build Coastguard Worker         for (ref1 = BWDREF_FRAME; ref1 <= ALTREF_FRAME; ++ref1)
890*77c1e3ccSAndroid Build Coastguard Worker           ref_costs_comp[ref0][ref1] = 512;
891*77c1e3ccSAndroid Build Coastguard Worker       }
892*77c1e3ccSAndroid Build Coastguard Worker       ref_costs_comp[LAST_FRAME][LAST2_FRAME] = 512;
893*77c1e3ccSAndroid Build Coastguard Worker       ref_costs_comp[LAST_FRAME][LAST3_FRAME] = 512;
894*77c1e3ccSAndroid Build Coastguard Worker       ref_costs_comp[LAST_FRAME][GOLDEN_FRAME] = 512;
895*77c1e3ccSAndroid Build Coastguard Worker       ref_costs_comp[BWDREF_FRAME][ALTREF_FRAME] = 512;
896*77c1e3ccSAndroid Build Coastguard Worker     }
897*77c1e3ccSAndroid Build Coastguard Worker   }
898*77c1e3ccSAndroid Build Coastguard Worker }
899*77c1e3ccSAndroid Build Coastguard Worker 
store_coding_context(MACROBLOCK * x,PICK_MODE_CONTEXT * ctx,int mode_index,int skippable)900*77c1e3ccSAndroid Build Coastguard Worker static inline void store_coding_context(
901*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_INTERNAL_STATS
902*77c1e3ccSAndroid Build Coastguard Worker     MACROBLOCK *x, PICK_MODE_CONTEXT *ctx, int mode_index,
903*77c1e3ccSAndroid Build Coastguard Worker #else
904*77c1e3ccSAndroid Build Coastguard Worker     MACROBLOCK *x, PICK_MODE_CONTEXT *ctx,
905*77c1e3ccSAndroid Build Coastguard Worker #endif  // CONFIG_INTERNAL_STATS
906*77c1e3ccSAndroid Build Coastguard Worker     int skippable) {
907*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *const xd = &x->e_mbd;
908*77c1e3ccSAndroid Build Coastguard Worker 
909*77c1e3ccSAndroid Build Coastguard Worker   // Take a snapshot of the coding context so it can be
910*77c1e3ccSAndroid Build Coastguard Worker   // restored if we decide to encode this way
911*77c1e3ccSAndroid Build Coastguard Worker   ctx->rd_stats.skip_txfm = x->txfm_search_info.skip_txfm;
912*77c1e3ccSAndroid Build Coastguard Worker   ctx->skippable = skippable;
913*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_INTERNAL_STATS
914*77c1e3ccSAndroid Build Coastguard Worker   ctx->best_mode_index = mode_index;
915*77c1e3ccSAndroid Build Coastguard Worker #endif  // CONFIG_INTERNAL_STATS
916*77c1e3ccSAndroid Build Coastguard Worker   ctx->mic = *xd->mi[0];
917*77c1e3ccSAndroid Build Coastguard Worker   av1_copy_mbmi_ext_to_mbmi_ext_frame(&ctx->mbmi_ext_best, &x->mbmi_ext,
918*77c1e3ccSAndroid Build Coastguard Worker                                       av1_ref_frame_type(xd->mi[0]->ref_frame));
919*77c1e3ccSAndroid Build Coastguard Worker }
920*77c1e3ccSAndroid Build Coastguard Worker 
setup_buffer_ref_mvs_inter(const AV1_COMP * const cpi,MACROBLOCK * x,MV_REFERENCE_FRAME ref_frame,BLOCK_SIZE block_size,struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE])921*77c1e3ccSAndroid Build Coastguard Worker static inline void setup_buffer_ref_mvs_inter(
922*77c1e3ccSAndroid Build Coastguard Worker     const AV1_COMP *const cpi, MACROBLOCK *x, MV_REFERENCE_FRAME ref_frame,
923*77c1e3ccSAndroid Build Coastguard Worker     BLOCK_SIZE block_size, struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE]) {
924*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *cm = &cpi->common;
925*77c1e3ccSAndroid Build Coastguard Worker   const int num_planes = av1_num_planes(cm);
926*77c1e3ccSAndroid Build Coastguard Worker   const YV12_BUFFER_CONFIG *scaled_ref_frame =
927*77c1e3ccSAndroid Build Coastguard Worker       av1_get_scaled_ref_frame(cpi, ref_frame);
928*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *const xd = &x->e_mbd;
929*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *const mbmi = xd->mi[0];
930*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO_EXT *const mbmi_ext = &x->mbmi_ext;
931*77c1e3ccSAndroid Build Coastguard Worker   const struct scale_factors *const sf =
932*77c1e3ccSAndroid Build Coastguard Worker       get_ref_scale_factors_const(cm, ref_frame);
933*77c1e3ccSAndroid Build Coastguard Worker   const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_yv12_buf(cm, ref_frame);
934*77c1e3ccSAndroid Build Coastguard Worker   assert(yv12 != NULL);
935*77c1e3ccSAndroid Build Coastguard Worker 
936*77c1e3ccSAndroid Build Coastguard Worker   if (scaled_ref_frame) {
937*77c1e3ccSAndroid Build Coastguard Worker     // Setup pred block based on scaled reference, because av1_mv_pred() doesn't
938*77c1e3ccSAndroid Build Coastguard Worker     // support scaling.
939*77c1e3ccSAndroid Build Coastguard Worker     av1_setup_pred_block(xd, yv12_mb[ref_frame], scaled_ref_frame, NULL, NULL,
940*77c1e3ccSAndroid Build Coastguard Worker                          num_planes);
941*77c1e3ccSAndroid Build Coastguard Worker   } else {
942*77c1e3ccSAndroid Build Coastguard Worker     av1_setup_pred_block(xd, yv12_mb[ref_frame], yv12, sf, sf, num_planes);
943*77c1e3ccSAndroid Build Coastguard Worker   }
944*77c1e3ccSAndroid Build Coastguard Worker 
945*77c1e3ccSAndroid Build Coastguard Worker   // Gets an initial list of candidate vectors from neighbours and orders them
946*77c1e3ccSAndroid Build Coastguard Worker   av1_find_mv_refs(cm, xd, mbmi, ref_frame, mbmi_ext->ref_mv_count,
947*77c1e3ccSAndroid Build Coastguard Worker                    xd->ref_mv_stack, xd->weight, NULL, mbmi_ext->global_mvs,
948*77c1e3ccSAndroid Build Coastguard Worker                    mbmi_ext->mode_context);
949*77c1e3ccSAndroid Build Coastguard Worker   // TODO(Ravi): Populate mbmi_ext->ref_mv_stack[ref_frame][4] and
950*77c1e3ccSAndroid Build Coastguard Worker   // mbmi_ext->weight[ref_frame][4] inside av1_find_mv_refs.
951*77c1e3ccSAndroid Build Coastguard Worker   av1_copy_usable_ref_mv_stack_and_weight(xd, mbmi_ext, ref_frame);
952*77c1e3ccSAndroid Build Coastguard Worker   // Further refinement that is encode side only to test the top few candidates
953*77c1e3ccSAndroid Build Coastguard Worker   // in full and choose the best as the center point for subsequent searches.
954*77c1e3ccSAndroid Build Coastguard Worker   // The current implementation doesn't support scaling.
955*77c1e3ccSAndroid Build Coastguard Worker   av1_mv_pred(cpi, x, yv12_mb[ref_frame][0].buf, yv12_mb[ref_frame][0].stride,
956*77c1e3ccSAndroid Build Coastguard Worker               ref_frame, block_size);
957*77c1e3ccSAndroid Build Coastguard Worker 
958*77c1e3ccSAndroid Build Coastguard Worker   // Go back to unscaled reference.
959*77c1e3ccSAndroid Build Coastguard Worker   if (scaled_ref_frame) {
960*77c1e3ccSAndroid Build Coastguard Worker     // We had temporarily setup pred block based on scaled reference above. Go
961*77c1e3ccSAndroid Build Coastguard Worker     // back to unscaled reference now, for subsequent use.
962*77c1e3ccSAndroid Build Coastguard Worker     av1_setup_pred_block(xd, yv12_mb[ref_frame], yv12, sf, sf, num_planes);
963*77c1e3ccSAndroid Build Coastguard Worker   }
964*77c1e3ccSAndroid Build Coastguard Worker }
965*77c1e3ccSAndroid Build Coastguard Worker 
966*77c1e3ccSAndroid Build Coastguard Worker #define LEFT_TOP_MARGIN ((AOM_BORDER_IN_PIXELS - AOM_INTERP_EXTEND) << 3)
967*77c1e3ccSAndroid Build Coastguard Worker #define RIGHT_BOTTOM_MARGIN ((AOM_BORDER_IN_PIXELS - AOM_INTERP_EXTEND) << 3)
968*77c1e3ccSAndroid Build Coastguard Worker 
969*77c1e3ccSAndroid Build Coastguard Worker // TODO(jingning): this mv clamping function should be block size dependent.
clamp_mv2(MV * mv,const MACROBLOCKD * xd)970*77c1e3ccSAndroid Build Coastguard Worker static inline void clamp_mv2(MV *mv, const MACROBLOCKD *xd) {
971*77c1e3ccSAndroid Build Coastguard Worker   const SubpelMvLimits mv_limits = { xd->mb_to_left_edge - LEFT_TOP_MARGIN,
972*77c1e3ccSAndroid Build Coastguard Worker                                      xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN,
973*77c1e3ccSAndroid Build Coastguard Worker                                      xd->mb_to_top_edge - LEFT_TOP_MARGIN,
974*77c1e3ccSAndroid Build Coastguard Worker                                      xd->mb_to_bottom_edge +
975*77c1e3ccSAndroid Build Coastguard Worker                                          RIGHT_BOTTOM_MARGIN };
976*77c1e3ccSAndroid Build Coastguard Worker   clamp_mv(mv, &mv_limits);
977*77c1e3ccSAndroid Build Coastguard Worker }
978*77c1e3ccSAndroid Build Coastguard Worker 
979*77c1e3ccSAndroid Build Coastguard Worker /* If the current mode shares the same mv with other modes with higher cost,
980*77c1e3ccSAndroid Build Coastguard Worker  * skip this mode. */
skip_repeated_mv(const AV1_COMMON * const cm,const MACROBLOCK * const x,PREDICTION_MODE this_mode,const MV_REFERENCE_FRAME ref_frames[2],InterModeSearchState * search_state)981*77c1e3ccSAndroid Build Coastguard Worker static int skip_repeated_mv(const AV1_COMMON *const cm,
982*77c1e3ccSAndroid Build Coastguard Worker                             const MACROBLOCK *const x,
983*77c1e3ccSAndroid Build Coastguard Worker                             PREDICTION_MODE this_mode,
984*77c1e3ccSAndroid Build Coastguard Worker                             const MV_REFERENCE_FRAME ref_frames[2],
985*77c1e3ccSAndroid Build Coastguard Worker                             InterModeSearchState *search_state) {
986*77c1e3ccSAndroid Build Coastguard Worker   const int is_comp_pred = ref_frames[1] > INTRA_FRAME;
987*77c1e3ccSAndroid Build Coastguard Worker   const uint8_t ref_frame_type = av1_ref_frame_type(ref_frames);
988*77c1e3ccSAndroid Build Coastguard Worker   const MB_MODE_INFO_EXT *const mbmi_ext = &x->mbmi_ext;
989*77c1e3ccSAndroid Build Coastguard Worker   const int ref_mv_count = mbmi_ext->ref_mv_count[ref_frame_type];
990*77c1e3ccSAndroid Build Coastguard Worker   PREDICTION_MODE compare_mode = MB_MODE_COUNT;
991*77c1e3ccSAndroid Build Coastguard Worker   if (!is_comp_pred) {
992*77c1e3ccSAndroid Build Coastguard Worker     if (this_mode == NEARMV) {
993*77c1e3ccSAndroid Build Coastguard Worker       if (ref_mv_count == 0) {
994*77c1e3ccSAndroid Build Coastguard Worker         // NEARMV has the same motion vector as NEARESTMV
995*77c1e3ccSAndroid Build Coastguard Worker         compare_mode = NEARESTMV;
996*77c1e3ccSAndroid Build Coastguard Worker       }
997*77c1e3ccSAndroid Build Coastguard Worker       if (ref_mv_count == 1 &&
998*77c1e3ccSAndroid Build Coastguard Worker           cm->global_motion[ref_frames[0]].wmtype <= TRANSLATION) {
999*77c1e3ccSAndroid Build Coastguard Worker         // NEARMV has the same motion vector as GLOBALMV
1000*77c1e3ccSAndroid Build Coastguard Worker         compare_mode = GLOBALMV;
1001*77c1e3ccSAndroid Build Coastguard Worker       }
1002*77c1e3ccSAndroid Build Coastguard Worker     }
1003*77c1e3ccSAndroid Build Coastguard Worker     if (this_mode == GLOBALMV) {
1004*77c1e3ccSAndroid Build Coastguard Worker       if (ref_mv_count == 0 &&
1005*77c1e3ccSAndroid Build Coastguard Worker           cm->global_motion[ref_frames[0]].wmtype <= TRANSLATION) {
1006*77c1e3ccSAndroid Build Coastguard Worker         // GLOBALMV has the same motion vector as NEARESTMV
1007*77c1e3ccSAndroid Build Coastguard Worker         compare_mode = NEARESTMV;
1008*77c1e3ccSAndroid Build Coastguard Worker       }
1009*77c1e3ccSAndroid Build Coastguard Worker       if (ref_mv_count == 1) {
1010*77c1e3ccSAndroid Build Coastguard Worker         // GLOBALMV has the same motion vector as NEARMV
1011*77c1e3ccSAndroid Build Coastguard Worker         compare_mode = NEARMV;
1012*77c1e3ccSAndroid Build Coastguard Worker       }
1013*77c1e3ccSAndroid Build Coastguard Worker     }
1014*77c1e3ccSAndroid Build Coastguard Worker 
1015*77c1e3ccSAndroid Build Coastguard Worker     if (compare_mode != MB_MODE_COUNT) {
1016*77c1e3ccSAndroid Build Coastguard Worker       // Use modelled_rd to check whether compare mode was searched
1017*77c1e3ccSAndroid Build Coastguard Worker       if (search_state->modelled_rd[compare_mode][0][ref_frames[0]] !=
1018*77c1e3ccSAndroid Build Coastguard Worker           INT64_MAX) {
1019*77c1e3ccSAndroid Build Coastguard Worker         const int16_t mode_ctx =
1020*77c1e3ccSAndroid Build Coastguard Worker             av1_mode_context_analyzer(mbmi_ext->mode_context, ref_frames);
1021*77c1e3ccSAndroid Build Coastguard Worker         const int compare_cost =
1022*77c1e3ccSAndroid Build Coastguard Worker             cost_mv_ref(&x->mode_costs, compare_mode, mode_ctx);
1023*77c1e3ccSAndroid Build Coastguard Worker         const int this_cost = cost_mv_ref(&x->mode_costs, this_mode, mode_ctx);
1024*77c1e3ccSAndroid Build Coastguard Worker 
1025*77c1e3ccSAndroid Build Coastguard Worker         // Only skip if the mode cost is larger than compare mode cost
1026*77c1e3ccSAndroid Build Coastguard Worker         if (this_cost > compare_cost) {
1027*77c1e3ccSAndroid Build Coastguard Worker           search_state->modelled_rd[this_mode][0][ref_frames[0]] =
1028*77c1e3ccSAndroid Build Coastguard Worker               search_state->modelled_rd[compare_mode][0][ref_frames[0]];
1029*77c1e3ccSAndroid Build Coastguard Worker           return 1;
1030*77c1e3ccSAndroid Build Coastguard Worker         }
1031*77c1e3ccSAndroid Build Coastguard Worker       }
1032*77c1e3ccSAndroid Build Coastguard Worker     }
1033*77c1e3ccSAndroid Build Coastguard Worker   }
1034*77c1e3ccSAndroid Build Coastguard Worker   return 0;
1035*77c1e3ccSAndroid Build Coastguard Worker }
1036*77c1e3ccSAndroid Build Coastguard Worker 
clamp_and_check_mv(int_mv * out_mv,int_mv in_mv,const AV1_COMMON * cm,const MACROBLOCK * x)1037*77c1e3ccSAndroid Build Coastguard Worker static inline int clamp_and_check_mv(int_mv *out_mv, int_mv in_mv,
1038*77c1e3ccSAndroid Build Coastguard Worker                                      const AV1_COMMON *cm,
1039*77c1e3ccSAndroid Build Coastguard Worker                                      const MACROBLOCK *x) {
1040*77c1e3ccSAndroid Build Coastguard Worker   const MACROBLOCKD *const xd = &x->e_mbd;
1041*77c1e3ccSAndroid Build Coastguard Worker   *out_mv = in_mv;
1042*77c1e3ccSAndroid Build Coastguard Worker   lower_mv_precision(&out_mv->as_mv, cm->features.allow_high_precision_mv,
1043*77c1e3ccSAndroid Build Coastguard Worker                      cm->features.cur_frame_force_integer_mv);
1044*77c1e3ccSAndroid Build Coastguard Worker   clamp_mv2(&out_mv->as_mv, xd);
1045*77c1e3ccSAndroid Build Coastguard Worker   return av1_is_fullmv_in_range(&x->mv_limits,
1046*77c1e3ccSAndroid Build Coastguard Worker                                 get_fullmv_from_mv(&out_mv->as_mv));
1047*77c1e3ccSAndroid Build Coastguard Worker }
1048*77c1e3ccSAndroid Build Coastguard Worker 
1049*77c1e3ccSAndroid Build Coastguard Worker // To use single newmv directly for compound modes, need to clamp the mv to the
1050*77c1e3ccSAndroid Build Coastguard Worker // valid mv range. Without this, encoder would generate out of range mv, and
1051*77c1e3ccSAndroid Build Coastguard Worker // this is seen in 8k encoding.
clamp_mv_in_range(MACROBLOCK * const x,int_mv * mv,int ref_idx)1052*77c1e3ccSAndroid Build Coastguard Worker static inline void clamp_mv_in_range(MACROBLOCK *const x, int_mv *mv,
1053*77c1e3ccSAndroid Build Coastguard Worker                                      int ref_idx) {
1054*77c1e3ccSAndroid Build Coastguard Worker   const int_mv ref_mv = av1_get_ref_mv(x, ref_idx);
1055*77c1e3ccSAndroid Build Coastguard Worker   SubpelMvLimits mv_limits;
1056*77c1e3ccSAndroid Build Coastguard Worker 
1057*77c1e3ccSAndroid Build Coastguard Worker   av1_set_subpel_mv_search_range(&mv_limits, &x->mv_limits, &ref_mv.as_mv);
1058*77c1e3ccSAndroid Build Coastguard Worker   clamp_mv(&mv->as_mv, &mv_limits);
1059*77c1e3ccSAndroid Build Coastguard Worker }
1060*77c1e3ccSAndroid Build Coastguard Worker 
handle_newmv(const AV1_COMP * const cpi,MACROBLOCK * const x,const BLOCK_SIZE bsize,int_mv * cur_mv,int * const rate_mv,HandleInterModeArgs * const args,inter_mode_info * mode_info)1061*77c1e3ccSAndroid Build Coastguard Worker static int64_t handle_newmv(const AV1_COMP *const cpi, MACROBLOCK *const x,
1062*77c1e3ccSAndroid Build Coastguard Worker                             const BLOCK_SIZE bsize, int_mv *cur_mv,
1063*77c1e3ccSAndroid Build Coastguard Worker                             int *const rate_mv, HandleInterModeArgs *const args,
1064*77c1e3ccSAndroid Build Coastguard Worker                             inter_mode_info *mode_info) {
1065*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *const xd = &x->e_mbd;
1066*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *const mbmi = xd->mi[0];
1067*77c1e3ccSAndroid Build Coastguard Worker   const int is_comp_pred = has_second_ref(mbmi);
1068*77c1e3ccSAndroid Build Coastguard Worker   const PREDICTION_MODE this_mode = mbmi->mode;
1069*77c1e3ccSAndroid Build Coastguard Worker   const int refs[2] = { mbmi->ref_frame[0],
1070*77c1e3ccSAndroid Build Coastguard Worker                         mbmi->ref_frame[1] < 0 ? 0 : mbmi->ref_frame[1] };
1071*77c1e3ccSAndroid Build Coastguard Worker   const int ref_mv_idx = mbmi->ref_mv_idx;
1072*77c1e3ccSAndroid Build Coastguard Worker 
1073*77c1e3ccSAndroid Build Coastguard Worker   if (is_comp_pred) {
1074*77c1e3ccSAndroid Build Coastguard Worker     const int valid_mv0 = args->single_newmv_valid[ref_mv_idx][refs[0]];
1075*77c1e3ccSAndroid Build Coastguard Worker     const int valid_mv1 = args->single_newmv_valid[ref_mv_idx][refs[1]];
1076*77c1e3ccSAndroid Build Coastguard Worker     if (this_mode == NEW_NEWMV) {
1077*77c1e3ccSAndroid Build Coastguard Worker       if (valid_mv0) {
1078*77c1e3ccSAndroid Build Coastguard Worker         cur_mv[0].as_int = args->single_newmv[ref_mv_idx][refs[0]].as_int;
1079*77c1e3ccSAndroid Build Coastguard Worker         clamp_mv_in_range(x, &cur_mv[0], 0);
1080*77c1e3ccSAndroid Build Coastguard Worker       }
1081*77c1e3ccSAndroid Build Coastguard Worker       if (valid_mv1) {
1082*77c1e3ccSAndroid Build Coastguard Worker         cur_mv[1].as_int = args->single_newmv[ref_mv_idx][refs[1]].as_int;
1083*77c1e3ccSAndroid Build Coastguard Worker         clamp_mv_in_range(x, &cur_mv[1], 1);
1084*77c1e3ccSAndroid Build Coastguard Worker       }
1085*77c1e3ccSAndroid Build Coastguard Worker       *rate_mv = 0;
1086*77c1e3ccSAndroid Build Coastguard Worker       for (int i = 0; i < 2; ++i) {
1087*77c1e3ccSAndroid Build Coastguard Worker         const int_mv ref_mv = av1_get_ref_mv(x, i);
1088*77c1e3ccSAndroid Build Coastguard Worker         *rate_mv += av1_mv_bit_cost(&cur_mv[i].as_mv, &ref_mv.as_mv,
1089*77c1e3ccSAndroid Build Coastguard Worker                                     x->mv_costs->nmv_joint_cost,
1090*77c1e3ccSAndroid Build Coastguard Worker                                     x->mv_costs->mv_cost_stack, MV_COST_WEIGHT);
1091*77c1e3ccSAndroid Build Coastguard Worker       }
1092*77c1e3ccSAndroid Build Coastguard Worker     } else if (this_mode == NEAREST_NEWMV || this_mode == NEAR_NEWMV) {
1093*77c1e3ccSAndroid Build Coastguard Worker       if (valid_mv1) {
1094*77c1e3ccSAndroid Build Coastguard Worker         cur_mv[1].as_int = args->single_newmv[ref_mv_idx][refs[1]].as_int;
1095*77c1e3ccSAndroid Build Coastguard Worker         clamp_mv_in_range(x, &cur_mv[1], 1);
1096*77c1e3ccSAndroid Build Coastguard Worker       }
1097*77c1e3ccSAndroid Build Coastguard Worker       const int_mv ref_mv = av1_get_ref_mv(x, 1);
1098*77c1e3ccSAndroid Build Coastguard Worker       *rate_mv = av1_mv_bit_cost(&cur_mv[1].as_mv, &ref_mv.as_mv,
1099*77c1e3ccSAndroid Build Coastguard Worker                                  x->mv_costs->nmv_joint_cost,
1100*77c1e3ccSAndroid Build Coastguard Worker                                  x->mv_costs->mv_cost_stack, MV_COST_WEIGHT);
1101*77c1e3ccSAndroid Build Coastguard Worker     } else {
1102*77c1e3ccSAndroid Build Coastguard Worker       assert(this_mode == NEW_NEARESTMV || this_mode == NEW_NEARMV);
1103*77c1e3ccSAndroid Build Coastguard Worker       if (valid_mv0) {
1104*77c1e3ccSAndroid Build Coastguard Worker         cur_mv[0].as_int = args->single_newmv[ref_mv_idx][refs[0]].as_int;
1105*77c1e3ccSAndroid Build Coastguard Worker         clamp_mv_in_range(x, &cur_mv[0], 0);
1106*77c1e3ccSAndroid Build Coastguard Worker       }
1107*77c1e3ccSAndroid Build Coastguard Worker       const int_mv ref_mv = av1_get_ref_mv(x, 0);
1108*77c1e3ccSAndroid Build Coastguard Worker       *rate_mv = av1_mv_bit_cost(&cur_mv[0].as_mv, &ref_mv.as_mv,
1109*77c1e3ccSAndroid Build Coastguard Worker                                  x->mv_costs->nmv_joint_cost,
1110*77c1e3ccSAndroid Build Coastguard Worker                                  x->mv_costs->mv_cost_stack, MV_COST_WEIGHT);
1111*77c1e3ccSAndroid Build Coastguard Worker     }
1112*77c1e3ccSAndroid Build Coastguard Worker   } else {
1113*77c1e3ccSAndroid Build Coastguard Worker     // Single ref case.
1114*77c1e3ccSAndroid Build Coastguard Worker     const int ref_idx = 0;
1115*77c1e3ccSAndroid Build Coastguard Worker     int search_range = INT_MAX;
1116*77c1e3ccSAndroid Build Coastguard Worker 
1117*77c1e3ccSAndroid Build Coastguard Worker     if (cpi->sf.mv_sf.reduce_search_range && mbmi->ref_mv_idx > 0) {
1118*77c1e3ccSAndroid Build Coastguard Worker       const MV ref_mv = av1_get_ref_mv(x, ref_idx).as_mv;
1119*77c1e3ccSAndroid Build Coastguard Worker       int min_mv_diff = INT_MAX;
1120*77c1e3ccSAndroid Build Coastguard Worker       int best_match = -1;
1121*77c1e3ccSAndroid Build Coastguard Worker       MV prev_ref_mv[2] = { { 0 } };
1122*77c1e3ccSAndroid Build Coastguard Worker       for (int idx = 0; idx < mbmi->ref_mv_idx; ++idx) {
1123*77c1e3ccSAndroid Build Coastguard Worker         prev_ref_mv[idx] = av1_get_ref_mv_from_stack(ref_idx, mbmi->ref_frame,
1124*77c1e3ccSAndroid Build Coastguard Worker                                                      idx, &x->mbmi_ext)
1125*77c1e3ccSAndroid Build Coastguard Worker                                .as_mv;
1126*77c1e3ccSAndroid Build Coastguard Worker         const int ref_mv_diff = AOMMAX(abs(ref_mv.row - prev_ref_mv[idx].row),
1127*77c1e3ccSAndroid Build Coastguard Worker                                        abs(ref_mv.col - prev_ref_mv[idx].col));
1128*77c1e3ccSAndroid Build Coastguard Worker 
1129*77c1e3ccSAndroid Build Coastguard Worker         if (min_mv_diff > ref_mv_diff) {
1130*77c1e3ccSAndroid Build Coastguard Worker           min_mv_diff = ref_mv_diff;
1131*77c1e3ccSAndroid Build Coastguard Worker           best_match = idx;
1132*77c1e3ccSAndroid Build Coastguard Worker         }
1133*77c1e3ccSAndroid Build Coastguard Worker       }
1134*77c1e3ccSAndroid Build Coastguard Worker 
1135*77c1e3ccSAndroid Build Coastguard Worker       if (min_mv_diff < (16 << 3)) {
1136*77c1e3ccSAndroid Build Coastguard Worker         if (args->single_newmv_valid[best_match][refs[0]]) {
1137*77c1e3ccSAndroid Build Coastguard Worker           search_range = min_mv_diff;
1138*77c1e3ccSAndroid Build Coastguard Worker           search_range +=
1139*77c1e3ccSAndroid Build Coastguard Worker               AOMMAX(abs(args->single_newmv[best_match][refs[0]].as_mv.row -
1140*77c1e3ccSAndroid Build Coastguard Worker                          prev_ref_mv[best_match].row),
1141*77c1e3ccSAndroid Build Coastguard Worker                      abs(args->single_newmv[best_match][refs[0]].as_mv.col -
1142*77c1e3ccSAndroid Build Coastguard Worker                          prev_ref_mv[best_match].col));
1143*77c1e3ccSAndroid Build Coastguard Worker           // Get full pixel search range.
1144*77c1e3ccSAndroid Build Coastguard Worker           search_range = (search_range + 4) >> 3;
1145*77c1e3ccSAndroid Build Coastguard Worker         }
1146*77c1e3ccSAndroid Build Coastguard Worker       }
1147*77c1e3ccSAndroid Build Coastguard Worker     }
1148*77c1e3ccSAndroid Build Coastguard Worker 
1149*77c1e3ccSAndroid Build Coastguard Worker     int_mv best_mv;
1150*77c1e3ccSAndroid Build Coastguard Worker     av1_single_motion_search(cpi, x, bsize, ref_idx, rate_mv, search_range,
1151*77c1e3ccSAndroid Build Coastguard Worker                              mode_info, &best_mv, args);
1152*77c1e3ccSAndroid Build Coastguard Worker     if (best_mv.as_int == INVALID_MV) return INT64_MAX;
1153*77c1e3ccSAndroid Build Coastguard Worker 
1154*77c1e3ccSAndroid Build Coastguard Worker     args->single_newmv[ref_mv_idx][refs[0]] = best_mv;
1155*77c1e3ccSAndroid Build Coastguard Worker     args->single_newmv_rate[ref_mv_idx][refs[0]] = *rate_mv;
1156*77c1e3ccSAndroid Build Coastguard Worker     args->single_newmv_valid[ref_mv_idx][refs[0]] = 1;
1157*77c1e3ccSAndroid Build Coastguard Worker     cur_mv[0].as_int = best_mv.as_int;
1158*77c1e3ccSAndroid Build Coastguard Worker 
1159*77c1e3ccSAndroid Build Coastguard Worker     // Return after single_newmv is set.
1160*77c1e3ccSAndroid Build Coastguard Worker     if (mode_info[mbmi->ref_mv_idx].skip) return INT64_MAX;
1161*77c1e3ccSAndroid Build Coastguard Worker   }
1162*77c1e3ccSAndroid Build Coastguard Worker 
1163*77c1e3ccSAndroid Build Coastguard Worker   return 0;
1164*77c1e3ccSAndroid Build Coastguard Worker }
1165*77c1e3ccSAndroid Build Coastguard Worker 
update_mode_start_end_index(const AV1_COMP * const cpi,const MB_MODE_INFO * const mbmi,int * mode_index_start,int * mode_index_end,int last_motion_mode_allowed,int interintra_allowed,int eval_motion_mode)1166*77c1e3ccSAndroid Build Coastguard Worker static inline void update_mode_start_end_index(
1167*77c1e3ccSAndroid Build Coastguard Worker     const AV1_COMP *const cpi, const MB_MODE_INFO *const mbmi,
1168*77c1e3ccSAndroid Build Coastguard Worker     int *mode_index_start, int *mode_index_end, int last_motion_mode_allowed,
1169*77c1e3ccSAndroid Build Coastguard Worker     int interintra_allowed, int eval_motion_mode) {
1170*77c1e3ccSAndroid Build Coastguard Worker   *mode_index_start = (int)SIMPLE_TRANSLATION;
1171*77c1e3ccSAndroid Build Coastguard Worker   *mode_index_end = (int)last_motion_mode_allowed + interintra_allowed;
1172*77c1e3ccSAndroid Build Coastguard Worker   if (cpi->sf.winner_mode_sf.motion_mode_for_winner_cand) {
1173*77c1e3ccSAndroid Build Coastguard Worker     if (!eval_motion_mode) {
1174*77c1e3ccSAndroid Build Coastguard Worker       *mode_index_end = (int)SIMPLE_TRANSLATION;
1175*77c1e3ccSAndroid Build Coastguard Worker     } else {
1176*77c1e3ccSAndroid Build Coastguard Worker       // Set the start index appropriately to process motion modes other than
1177*77c1e3ccSAndroid Build Coastguard Worker       // simple translation
1178*77c1e3ccSAndroid Build Coastguard Worker       *mode_index_start = 1;
1179*77c1e3ccSAndroid Build Coastguard Worker     }
1180*77c1e3ccSAndroid Build Coastguard Worker   }
1181*77c1e3ccSAndroid Build Coastguard Worker   if (cpi->sf.inter_sf.extra_prune_warped && mbmi->bsize > BLOCK_16X16)
1182*77c1e3ccSAndroid Build Coastguard Worker     *mode_index_end = SIMPLE_TRANSLATION;
1183*77c1e3ccSAndroid Build Coastguard Worker }
1184*77c1e3ccSAndroid Build Coastguard Worker 
1185*77c1e3ccSAndroid Build Coastguard Worker /*!\brief AV1 motion mode search
1186*77c1e3ccSAndroid Build Coastguard Worker  *
1187*77c1e3ccSAndroid Build Coastguard Worker  * \ingroup inter_mode_search
1188*77c1e3ccSAndroid Build Coastguard Worker  * Function to search over and determine the motion mode. It will update
1189*77c1e3ccSAndroid Build Coastguard Worker  * mbmi->motion_mode to one of SIMPLE_TRANSLATION, OBMC_CAUSAL, or
1190*77c1e3ccSAndroid Build Coastguard Worker  * WARPED_CAUSAL and determine any necessary side information for the selected
1191*77c1e3ccSAndroid Build Coastguard Worker  * motion mode. It will also perform the full transform search, unless the
1192*77c1e3ccSAndroid Build Coastguard Worker  * input parameter do_tx_search indicates to do an estimation of the RD rather
1193*77c1e3ccSAndroid Build Coastguard Worker  * than an RD corresponding to a full transform search. It will return the
1194*77c1e3ccSAndroid Build Coastguard Worker  * RD for the final motion_mode.
1195*77c1e3ccSAndroid Build Coastguard Worker  * Do the RD search for a given inter mode and compute all information relevant
1196*77c1e3ccSAndroid Build Coastguard Worker  * to the input mode. It will compute the best MV,
1197*77c1e3ccSAndroid Build Coastguard Worker  * compound parameters (if the mode is a compound mode) and interpolation filter
1198*77c1e3ccSAndroid Build Coastguard Worker  * parameters.
1199*77c1e3ccSAndroid Build Coastguard Worker  *
1200*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     cpi               Top-level encoder structure.
1201*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     tile_data         Pointer to struct holding adaptive
1202*77c1e3ccSAndroid Build Coastguard Worker  *                                  data/contexts/models for the tile during
1203*77c1e3ccSAndroid Build Coastguard Worker  *                                  encoding.
1204*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     x                 Pointer to struct holding all the data for
1205*77c1e3ccSAndroid Build Coastguard Worker  *                                  the current macroblock.
1206*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     bsize             Current block size.
1207*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] rd_stats          Struct to keep track of the overall RD
1208*77c1e3ccSAndroid Build Coastguard Worker  *                                  information.
1209*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] rd_stats_y        Struct to keep track of the RD information
1210*77c1e3ccSAndroid Build Coastguard Worker  *                                  for only the Y plane.
1211*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] rd_stats_uv       Struct to keep track of the RD information
1212*77c1e3ccSAndroid Build Coastguard Worker  *                                  for only the UV planes.
1213*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     args              HandleInterModeArgs struct holding
1214*77c1e3ccSAndroid Build Coastguard Worker  *                                  miscellaneous arguments for inter mode
1215*77c1e3ccSAndroid Build Coastguard Worker  *                                  search. See the documentation for this
1216*77c1e3ccSAndroid Build Coastguard Worker  *                                  struct for a description of each member.
1217*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     ref_best_rd       Best RD found so far for this block.
1218*77c1e3ccSAndroid Build Coastguard Worker  *                                  It is used for early termination of this
1219*77c1e3ccSAndroid Build Coastguard Worker  *                                  search if the RD exceeds this value.
1220*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] ref_skip_rd       A length 2 array, where skip_rd[0] is the
1221*77c1e3ccSAndroid Build Coastguard Worker  *                                  best total RD for a skip mode so far, and
1222*77c1e3ccSAndroid Build Coastguard Worker  *                                  skip_rd[1] is the best RD for a skip mode so
1223*77c1e3ccSAndroid Build Coastguard Worker  *                                  far in luma. This is used as a speed feature
1224*77c1e3ccSAndroid Build Coastguard Worker  *                                  to skip the transform search if the computed
1225*77c1e3ccSAndroid Build Coastguard Worker  *                                  skip RD for the current mode is not better
1226*77c1e3ccSAndroid Build Coastguard Worker  *                                  than the best skip_rd so far.
1227*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] rate_mv           The rate associated with the motion vectors.
1228*77c1e3ccSAndroid Build Coastguard Worker  *                                  This will be modified if a motion search is
1229*77c1e3ccSAndroid Build Coastguard Worker  *                                  done in the motion mode search.
1230*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] orig_dst          A prediction buffer to hold a computed
1231*77c1e3ccSAndroid Build Coastguard Worker  *                                  prediction. This will eventually hold the
1232*77c1e3ccSAndroid Build Coastguard Worker  *                                  final prediction, and the tmp_dst info will
1233*77c1e3ccSAndroid Build Coastguard Worker  *                                  be copied here.
1234*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] best_est_rd       Estimated RD for motion mode search if
1235*77c1e3ccSAndroid Build Coastguard Worker  *                                  do_tx_search (see below) is 0.
1236*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     do_tx_search      Parameter to indicate whether or not to do
1237*77c1e3ccSAndroid Build Coastguard Worker  *                                  a full transform search. This will compute
1238*77c1e3ccSAndroid Build Coastguard Worker  *                                  an estimated RD for the modes without the
1239*77c1e3ccSAndroid Build Coastguard Worker  *                                  transform search and later perform the full
1240*77c1e3ccSAndroid Build Coastguard Worker  *                                  transform search on the best candidates.
1241*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     inter_modes_info  InterModesInfo struct to hold inter mode
1242*77c1e3ccSAndroid Build Coastguard Worker  *                                  information to perform a full transform
1243*77c1e3ccSAndroid Build Coastguard Worker  *                                  search only on winning candidates searched
1244*77c1e3ccSAndroid Build Coastguard Worker  *                                  with an estimate for transform coding RD.
1245*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     eval_motion_mode  Boolean whether or not to evaluate motion
1246*77c1e3ccSAndroid Build Coastguard Worker  *                                  motion modes other than SIMPLE_TRANSLATION.
1247*77c1e3ccSAndroid Build Coastguard Worker  * \param[out]    yrd               Stores the rdcost corresponding to encoding
1248*77c1e3ccSAndroid Build Coastguard Worker  *                                  the luma plane.
1249*77c1e3ccSAndroid Build Coastguard Worker  * \return Returns INT64_MAX if the determined motion mode is invalid and the
1250*77c1e3ccSAndroid Build Coastguard Worker  * current motion mode being tested should be skipped. It returns 0 if the
1251*77c1e3ccSAndroid Build Coastguard Worker  * motion mode search is a success.
1252*77c1e3ccSAndroid Build Coastguard Worker  */
motion_mode_rd(const AV1_COMP * const cpi,TileDataEnc * tile_data,MACROBLOCK * const x,BLOCK_SIZE bsize,RD_STATS * rd_stats,RD_STATS * rd_stats_y,RD_STATS * rd_stats_uv,HandleInterModeArgs * const args,int64_t ref_best_rd,int64_t * ref_skip_rd,int * rate_mv,const BUFFER_SET * orig_dst,int64_t * best_est_rd,int do_tx_search,InterModesInfo * inter_modes_info,int eval_motion_mode,int64_t * yrd)1253*77c1e3ccSAndroid Build Coastguard Worker static int64_t motion_mode_rd(
1254*77c1e3ccSAndroid Build Coastguard Worker     const AV1_COMP *const cpi, TileDataEnc *tile_data, MACROBLOCK *const x,
1255*77c1e3ccSAndroid Build Coastguard Worker     BLOCK_SIZE bsize, RD_STATS *rd_stats, RD_STATS *rd_stats_y,
1256*77c1e3ccSAndroid Build Coastguard Worker     RD_STATS *rd_stats_uv, HandleInterModeArgs *const args, int64_t ref_best_rd,
1257*77c1e3ccSAndroid Build Coastguard Worker     int64_t *ref_skip_rd, int *rate_mv, const BUFFER_SET *orig_dst,
1258*77c1e3ccSAndroid Build Coastguard Worker     int64_t *best_est_rd, int do_tx_search, InterModesInfo *inter_modes_info,
1259*77c1e3ccSAndroid Build Coastguard Worker     int eval_motion_mode, int64_t *yrd) {
1260*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
1261*77c1e3ccSAndroid Build Coastguard Worker   const FeatureFlags *const features = &cm->features;
1262*77c1e3ccSAndroid Build Coastguard Worker   TxfmSearchInfo *txfm_info = &x->txfm_search_info;
1263*77c1e3ccSAndroid Build Coastguard Worker   const int num_planes = av1_num_planes(cm);
1264*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *xd = &x->e_mbd;
1265*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *mbmi = xd->mi[0];
1266*77c1e3ccSAndroid Build Coastguard Worker   const int is_comp_pred = has_second_ref(mbmi);
1267*77c1e3ccSAndroid Build Coastguard Worker   const PREDICTION_MODE this_mode = mbmi->mode;
1268*77c1e3ccSAndroid Build Coastguard Worker   const int rate2_nocoeff = rd_stats->rate;
1269*77c1e3ccSAndroid Build Coastguard Worker   int best_xskip_txfm = 0;
1270*77c1e3ccSAndroid Build Coastguard Worker   RD_STATS best_rd_stats, best_rd_stats_y, best_rd_stats_uv;
1271*77c1e3ccSAndroid Build Coastguard Worker   uint8_t best_blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE];
1272*77c1e3ccSAndroid Build Coastguard Worker   uint8_t best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE];
1273*77c1e3ccSAndroid Build Coastguard Worker   const int rate_mv0 = *rate_mv;
1274*77c1e3ccSAndroid Build Coastguard Worker   const int interintra_allowed = cm->seq_params->enable_interintra_compound &&
1275*77c1e3ccSAndroid Build Coastguard Worker                                  is_interintra_allowed(mbmi) &&
1276*77c1e3ccSAndroid Build Coastguard Worker                                  mbmi->compound_idx;
1277*77c1e3ccSAndroid Build Coastguard Worker   WARP_SAMPLE_INFO *const warp_sample_info =
1278*77c1e3ccSAndroid Build Coastguard Worker       &x->warp_sample_info[mbmi->ref_frame[0]];
1279*77c1e3ccSAndroid Build Coastguard Worker   int *pts0 = warp_sample_info->pts;
1280*77c1e3ccSAndroid Build Coastguard Worker   int *pts_inref0 = warp_sample_info->pts_inref;
1281*77c1e3ccSAndroid Build Coastguard Worker 
1282*77c1e3ccSAndroid Build Coastguard Worker   assert(mbmi->ref_frame[1] != INTRA_FRAME);
1283*77c1e3ccSAndroid Build Coastguard Worker   const MV_REFERENCE_FRAME ref_frame_1 = mbmi->ref_frame[1];
1284*77c1e3ccSAndroid Build Coastguard Worker   av1_invalid_rd_stats(&best_rd_stats);
1285*77c1e3ccSAndroid Build Coastguard Worker   mbmi->num_proj_ref = 1;  // assume num_proj_ref >=1
1286*77c1e3ccSAndroid Build Coastguard Worker   MOTION_MODE last_motion_mode_allowed = SIMPLE_TRANSLATION;
1287*77c1e3ccSAndroid Build Coastguard Worker   *yrd = INT64_MAX;
1288*77c1e3ccSAndroid Build Coastguard Worker   if (features->switchable_motion_mode) {
1289*77c1e3ccSAndroid Build Coastguard Worker     // Determine which motion modes to search if more than SIMPLE_TRANSLATION
1290*77c1e3ccSAndroid Build Coastguard Worker     // is allowed.
1291*77c1e3ccSAndroid Build Coastguard Worker     last_motion_mode_allowed = motion_mode_allowed(
1292*77c1e3ccSAndroid Build Coastguard Worker         xd->global_motion, xd, mbmi, features->allow_warped_motion);
1293*77c1e3ccSAndroid Build Coastguard Worker   }
1294*77c1e3ccSAndroid Build Coastguard Worker 
1295*77c1e3ccSAndroid Build Coastguard Worker   if (last_motion_mode_allowed == WARPED_CAUSAL) {
1296*77c1e3ccSAndroid Build Coastguard Worker     // Collect projection samples used in least squares approximation of
1297*77c1e3ccSAndroid Build Coastguard Worker     // the warped motion parameters if WARPED_CAUSAL is going to be searched.
1298*77c1e3ccSAndroid Build Coastguard Worker     if (warp_sample_info->num < 0) {
1299*77c1e3ccSAndroid Build Coastguard Worker       warp_sample_info->num = av1_findSamples(cm, xd, pts0, pts_inref0);
1300*77c1e3ccSAndroid Build Coastguard Worker     }
1301*77c1e3ccSAndroid Build Coastguard Worker     mbmi->num_proj_ref = warp_sample_info->num;
1302*77c1e3ccSAndroid Build Coastguard Worker   }
1303*77c1e3ccSAndroid Build Coastguard Worker   const int total_samples = mbmi->num_proj_ref;
1304*77c1e3ccSAndroid Build Coastguard Worker   if (total_samples == 0) {
1305*77c1e3ccSAndroid Build Coastguard Worker     // Do not search WARPED_CAUSAL if there are no samples to use to determine
1306*77c1e3ccSAndroid Build Coastguard Worker     // warped parameters.
1307*77c1e3ccSAndroid Build Coastguard Worker     last_motion_mode_allowed = OBMC_CAUSAL;
1308*77c1e3ccSAndroid Build Coastguard Worker   }
1309*77c1e3ccSAndroid Build Coastguard Worker 
1310*77c1e3ccSAndroid Build Coastguard Worker   const MB_MODE_INFO base_mbmi = *mbmi;
1311*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO best_mbmi;
1312*77c1e3ccSAndroid Build Coastguard Worker   const int interp_filter = features->interp_filter;
1313*77c1e3ccSAndroid Build Coastguard Worker   const int switchable_rate =
1314*77c1e3ccSAndroid Build Coastguard Worker       av1_is_interp_needed(xd)
1315*77c1e3ccSAndroid Build Coastguard Worker           ? av1_get_switchable_rate(x, xd, interp_filter,
1316*77c1e3ccSAndroid Build Coastguard Worker                                     cm->seq_params->enable_dual_filter)
1317*77c1e3ccSAndroid Build Coastguard Worker           : 0;
1318*77c1e3ccSAndroid Build Coastguard Worker   int64_t best_rd = INT64_MAX;
1319*77c1e3ccSAndroid Build Coastguard Worker   int best_rate_mv = rate_mv0;
1320*77c1e3ccSAndroid Build Coastguard Worker   const int mi_row = xd->mi_row;
1321*77c1e3ccSAndroid Build Coastguard Worker   const int mi_col = xd->mi_col;
1322*77c1e3ccSAndroid Build Coastguard Worker   int mode_index_start, mode_index_end;
1323*77c1e3ccSAndroid Build Coastguard Worker   const int txfm_rd_gate_level =
1324*77c1e3ccSAndroid Build Coastguard Worker       get_txfm_rd_gate_level(cm->seq_params->enable_masked_compound,
1325*77c1e3ccSAndroid Build Coastguard Worker                              cpi->sf.inter_sf.txfm_rd_gate_level, bsize,
1326*77c1e3ccSAndroid Build Coastguard Worker                              TX_SEARCH_MOTION_MODE, eval_motion_mode);
1327*77c1e3ccSAndroid Build Coastguard Worker 
1328*77c1e3ccSAndroid Build Coastguard Worker   // Modify the start and end index according to speed features. For example,
1329*77c1e3ccSAndroid Build Coastguard Worker   // if SIMPLE_TRANSLATION has already been searched according to
1330*77c1e3ccSAndroid Build Coastguard Worker   // the motion_mode_for_winner_cand speed feature, update the mode_index_start
1331*77c1e3ccSAndroid Build Coastguard Worker   // to avoid searching it again.
1332*77c1e3ccSAndroid Build Coastguard Worker   update_mode_start_end_index(cpi, mbmi, &mode_index_start, &mode_index_end,
1333*77c1e3ccSAndroid Build Coastguard Worker                               last_motion_mode_allowed, interintra_allowed,
1334*77c1e3ccSAndroid Build Coastguard Worker                               eval_motion_mode);
1335*77c1e3ccSAndroid Build Coastguard Worker   // Main function loop. This loops over all of the possible motion modes and
1336*77c1e3ccSAndroid Build Coastguard Worker   // computes RD to determine the best one. This process includes computing
1337*77c1e3ccSAndroid Build Coastguard Worker   // any necessary side information for the motion mode and performing the
1338*77c1e3ccSAndroid Build Coastguard Worker   // transform search.
1339*77c1e3ccSAndroid Build Coastguard Worker   for (int mode_index = mode_index_start; mode_index <= mode_index_end;
1340*77c1e3ccSAndroid Build Coastguard Worker        mode_index++) {
1341*77c1e3ccSAndroid Build Coastguard Worker     if (args->skip_motion_mode && mode_index) continue;
1342*77c1e3ccSAndroid Build Coastguard Worker     int tmp_rate2 = rate2_nocoeff;
1343*77c1e3ccSAndroid Build Coastguard Worker     const int is_interintra_mode = mode_index > (int)last_motion_mode_allowed;
1344*77c1e3ccSAndroid Build Coastguard Worker     int tmp_rate_mv = rate_mv0;
1345*77c1e3ccSAndroid Build Coastguard Worker 
1346*77c1e3ccSAndroid Build Coastguard Worker     *mbmi = base_mbmi;
1347*77c1e3ccSAndroid Build Coastguard Worker     if (is_interintra_mode) {
1348*77c1e3ccSAndroid Build Coastguard Worker       // Only use SIMPLE_TRANSLATION for interintra
1349*77c1e3ccSAndroid Build Coastguard Worker       mbmi->motion_mode = SIMPLE_TRANSLATION;
1350*77c1e3ccSAndroid Build Coastguard Worker     } else {
1351*77c1e3ccSAndroid Build Coastguard Worker       mbmi->motion_mode = (MOTION_MODE)mode_index;
1352*77c1e3ccSAndroid Build Coastguard Worker       assert(mbmi->ref_frame[1] != INTRA_FRAME);
1353*77c1e3ccSAndroid Build Coastguard Worker     }
1354*77c1e3ccSAndroid Build Coastguard Worker 
1355*77c1e3ccSAndroid Build Coastguard Worker     // Do not search OBMC if the probability of selecting it is below a
1356*77c1e3ccSAndroid Build Coastguard Worker     // predetermined threshold for this update_type and block size.
1357*77c1e3ccSAndroid Build Coastguard Worker     const FRAME_UPDATE_TYPE update_type =
1358*77c1e3ccSAndroid Build Coastguard Worker         get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index);
1359*77c1e3ccSAndroid Build Coastguard Worker     int use_actual_frame_probs = 1;
1360*77c1e3ccSAndroid Build Coastguard Worker     int prune_obmc;
1361*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_FPMT_TEST
1362*77c1e3ccSAndroid Build Coastguard Worker     use_actual_frame_probs =
1363*77c1e3ccSAndroid Build Coastguard Worker         (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) ? 0 : 1;
1364*77c1e3ccSAndroid Build Coastguard Worker     if (!use_actual_frame_probs) {
1365*77c1e3ccSAndroid Build Coastguard Worker       prune_obmc = cpi->ppi->temp_frame_probs.obmc_probs[update_type][bsize] <
1366*77c1e3ccSAndroid Build Coastguard Worker                    cpi->sf.inter_sf.prune_obmc_prob_thresh;
1367*77c1e3ccSAndroid Build Coastguard Worker     }
1368*77c1e3ccSAndroid Build Coastguard Worker #endif
1369*77c1e3ccSAndroid Build Coastguard Worker     if (use_actual_frame_probs) {
1370*77c1e3ccSAndroid Build Coastguard Worker       prune_obmc = cpi->ppi->frame_probs.obmc_probs[update_type][bsize] <
1371*77c1e3ccSAndroid Build Coastguard Worker                    cpi->sf.inter_sf.prune_obmc_prob_thresh;
1372*77c1e3ccSAndroid Build Coastguard Worker     }
1373*77c1e3ccSAndroid Build Coastguard Worker     if ((!cpi->oxcf.motion_mode_cfg.enable_obmc || prune_obmc) &&
1374*77c1e3ccSAndroid Build Coastguard Worker         mbmi->motion_mode == OBMC_CAUSAL)
1375*77c1e3ccSAndroid Build Coastguard Worker       continue;
1376*77c1e3ccSAndroid Build Coastguard Worker 
1377*77c1e3ccSAndroid Build Coastguard Worker     if (mbmi->motion_mode == SIMPLE_TRANSLATION && !is_interintra_mode) {
1378*77c1e3ccSAndroid Build Coastguard Worker       // SIMPLE_TRANSLATION mode: no need to recalculate.
1379*77c1e3ccSAndroid Build Coastguard Worker       // The prediction is calculated before motion_mode_rd() is called in
1380*77c1e3ccSAndroid Build Coastguard Worker       // handle_inter_mode()
1381*77c1e3ccSAndroid Build Coastguard Worker     } else if (mbmi->motion_mode == OBMC_CAUSAL) {
1382*77c1e3ccSAndroid Build Coastguard Worker       const uint32_t cur_mv = mbmi->mv[0].as_int;
1383*77c1e3ccSAndroid Build Coastguard Worker       // OBMC_CAUSAL not allowed for compound prediction
1384*77c1e3ccSAndroid Build Coastguard Worker       assert(!is_comp_pred);
1385*77c1e3ccSAndroid Build Coastguard Worker       if (have_newmv_in_inter_mode(this_mode)) {
1386*77c1e3ccSAndroid Build Coastguard Worker         av1_single_motion_search(cpi, x, bsize, 0, &tmp_rate_mv, INT_MAX, NULL,
1387*77c1e3ccSAndroid Build Coastguard Worker                                  &mbmi->mv[0], NULL);
1388*77c1e3ccSAndroid Build Coastguard Worker         tmp_rate2 = rate2_nocoeff - rate_mv0 + tmp_rate_mv;
1389*77c1e3ccSAndroid Build Coastguard Worker       }
1390*77c1e3ccSAndroid Build Coastguard Worker       if ((mbmi->mv[0].as_int != cur_mv) || eval_motion_mode) {
1391*77c1e3ccSAndroid Build Coastguard Worker         // Build the predictor according to the current motion vector if it has
1392*77c1e3ccSAndroid Build Coastguard Worker         // not already been built
1393*77c1e3ccSAndroid Build Coastguard Worker         av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize,
1394*77c1e3ccSAndroid Build Coastguard Worker                                       0, av1_num_planes(cm) - 1);
1395*77c1e3ccSAndroid Build Coastguard Worker       }
1396*77c1e3ccSAndroid Build Coastguard Worker       // Build the inter predictor by blending the predictor corresponding to
1397*77c1e3ccSAndroid Build Coastguard Worker       // this MV, and the neighboring blocks using the OBMC model
1398*77c1e3ccSAndroid Build Coastguard Worker       av1_build_obmc_inter_prediction(
1399*77c1e3ccSAndroid Build Coastguard Worker           cm, xd, args->above_pred_buf, args->above_pred_stride,
1400*77c1e3ccSAndroid Build Coastguard Worker           args->left_pred_buf, args->left_pred_stride);
1401*77c1e3ccSAndroid Build Coastguard Worker #if !CONFIG_REALTIME_ONLY
1402*77c1e3ccSAndroid Build Coastguard Worker     } else if (mbmi->motion_mode == WARPED_CAUSAL) {
1403*77c1e3ccSAndroid Build Coastguard Worker       int pts[SAMPLES_ARRAY_SIZE], pts_inref[SAMPLES_ARRAY_SIZE];
1404*77c1e3ccSAndroid Build Coastguard Worker       mbmi->motion_mode = WARPED_CAUSAL;
1405*77c1e3ccSAndroid Build Coastguard Worker       mbmi->wm_params.wmtype = DEFAULT_WMTYPE;
1406*77c1e3ccSAndroid Build Coastguard Worker       mbmi->interp_filters =
1407*77c1e3ccSAndroid Build Coastguard Worker           av1_broadcast_interp_filter(av1_unswitchable_filter(interp_filter));
1408*77c1e3ccSAndroid Build Coastguard Worker 
1409*77c1e3ccSAndroid Build Coastguard Worker       memcpy(pts, pts0, total_samples * 2 * sizeof(*pts0));
1410*77c1e3ccSAndroid Build Coastguard Worker       memcpy(pts_inref, pts_inref0, total_samples * 2 * sizeof(*pts_inref0));
1411*77c1e3ccSAndroid Build Coastguard Worker       // Select the samples according to motion vector difference
1412*77c1e3ccSAndroid Build Coastguard Worker       if (mbmi->num_proj_ref > 1) {
1413*77c1e3ccSAndroid Build Coastguard Worker         mbmi->num_proj_ref = av1_selectSamples(
1414*77c1e3ccSAndroid Build Coastguard Worker             &mbmi->mv[0].as_mv, pts, pts_inref, mbmi->num_proj_ref, bsize);
1415*77c1e3ccSAndroid Build Coastguard Worker       }
1416*77c1e3ccSAndroid Build Coastguard Worker 
1417*77c1e3ccSAndroid Build Coastguard Worker       // Compute the warped motion parameters with a least squares fit
1418*77c1e3ccSAndroid Build Coastguard Worker       //  using the collected samples
1419*77c1e3ccSAndroid Build Coastguard Worker       if (!av1_find_projection(mbmi->num_proj_ref, pts, pts_inref, bsize,
1420*77c1e3ccSAndroid Build Coastguard Worker                                mbmi->mv[0].as_mv.row, mbmi->mv[0].as_mv.col,
1421*77c1e3ccSAndroid Build Coastguard Worker                                &mbmi->wm_params, mi_row, mi_col)) {
1422*77c1e3ccSAndroid Build Coastguard Worker         assert(!is_comp_pred);
1423*77c1e3ccSAndroid Build Coastguard Worker         if (have_newmv_in_inter_mode(this_mode)) {
1424*77c1e3ccSAndroid Build Coastguard Worker           // Refine MV for NEWMV mode
1425*77c1e3ccSAndroid Build Coastguard Worker           const int_mv mv0 = mbmi->mv[0];
1426*77c1e3ccSAndroid Build Coastguard Worker           const WarpedMotionParams wm_params0 = mbmi->wm_params;
1427*77c1e3ccSAndroid Build Coastguard Worker           const int num_proj_ref0 = mbmi->num_proj_ref;
1428*77c1e3ccSAndroid Build Coastguard Worker 
1429*77c1e3ccSAndroid Build Coastguard Worker           const int_mv ref_mv = av1_get_ref_mv(x, 0);
1430*77c1e3ccSAndroid Build Coastguard Worker           SUBPEL_MOTION_SEARCH_PARAMS ms_params;
1431*77c1e3ccSAndroid Build Coastguard Worker           av1_make_default_subpel_ms_params(&ms_params, cpi, x, bsize,
1432*77c1e3ccSAndroid Build Coastguard Worker                                             &ref_mv.as_mv, NULL);
1433*77c1e3ccSAndroid Build Coastguard Worker 
1434*77c1e3ccSAndroid Build Coastguard Worker           // Refine MV in a small range.
1435*77c1e3ccSAndroid Build Coastguard Worker           av1_refine_warped_mv(xd, cm, &ms_params, bsize, pts0, pts_inref0,
1436*77c1e3ccSAndroid Build Coastguard Worker                                total_samples, cpi->sf.mv_sf.warp_search_method,
1437*77c1e3ccSAndroid Build Coastguard Worker                                cpi->sf.mv_sf.warp_search_iters);
1438*77c1e3ccSAndroid Build Coastguard Worker 
1439*77c1e3ccSAndroid Build Coastguard Worker           if (mv0.as_int != mbmi->mv[0].as_int) {
1440*77c1e3ccSAndroid Build Coastguard Worker             // Keep the refined MV and WM parameters.
1441*77c1e3ccSAndroid Build Coastguard Worker             tmp_rate_mv = av1_mv_bit_cost(
1442*77c1e3ccSAndroid Build Coastguard Worker                 &mbmi->mv[0].as_mv, &ref_mv.as_mv, x->mv_costs->nmv_joint_cost,
1443*77c1e3ccSAndroid Build Coastguard Worker                 x->mv_costs->mv_cost_stack, MV_COST_WEIGHT);
1444*77c1e3ccSAndroid Build Coastguard Worker             tmp_rate2 = rate2_nocoeff - rate_mv0 + tmp_rate_mv;
1445*77c1e3ccSAndroid Build Coastguard Worker           } else {
1446*77c1e3ccSAndroid Build Coastguard Worker             // Restore the old MV and WM parameters.
1447*77c1e3ccSAndroid Build Coastguard Worker             mbmi->mv[0] = mv0;
1448*77c1e3ccSAndroid Build Coastguard Worker             mbmi->wm_params = wm_params0;
1449*77c1e3ccSAndroid Build Coastguard Worker             mbmi->num_proj_ref = num_proj_ref0;
1450*77c1e3ccSAndroid Build Coastguard Worker           }
1451*77c1e3ccSAndroid Build Coastguard Worker         }
1452*77c1e3ccSAndroid Build Coastguard Worker 
1453*77c1e3ccSAndroid Build Coastguard Worker         // Build the warped predictor
1454*77c1e3ccSAndroid Build Coastguard Worker         av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, 0,
1455*77c1e3ccSAndroid Build Coastguard Worker                                       av1_num_planes(cm) - 1);
1456*77c1e3ccSAndroid Build Coastguard Worker       } else {
1457*77c1e3ccSAndroid Build Coastguard Worker         continue;
1458*77c1e3ccSAndroid Build Coastguard Worker       }
1459*77c1e3ccSAndroid Build Coastguard Worker #endif  // !CONFIG_REALTIME_ONLY
1460*77c1e3ccSAndroid Build Coastguard Worker     } else if (is_interintra_mode) {
1461*77c1e3ccSAndroid Build Coastguard Worker       const int ret =
1462*77c1e3ccSAndroid Build Coastguard Worker           av1_handle_inter_intra_mode(cpi, x, bsize, mbmi, args, ref_best_rd,
1463*77c1e3ccSAndroid Build Coastguard Worker                                       &tmp_rate_mv, &tmp_rate2, orig_dst);
1464*77c1e3ccSAndroid Build Coastguard Worker       if (ret < 0) continue;
1465*77c1e3ccSAndroid Build Coastguard Worker     }
1466*77c1e3ccSAndroid Build Coastguard Worker 
1467*77c1e3ccSAndroid Build Coastguard Worker     // If we are searching newmv and the mv is the same as refmv, skip the
1468*77c1e3ccSAndroid Build Coastguard Worker     // current mode
1469*77c1e3ccSAndroid Build Coastguard Worker     if (!av1_check_newmv_joint_nonzero(cm, x)) continue;
1470*77c1e3ccSAndroid Build Coastguard Worker 
1471*77c1e3ccSAndroid Build Coastguard Worker     // Update rd_stats for the current motion mode
1472*77c1e3ccSAndroid Build Coastguard Worker     txfm_info->skip_txfm = 0;
1473*77c1e3ccSAndroid Build Coastguard Worker     rd_stats->dist = 0;
1474*77c1e3ccSAndroid Build Coastguard Worker     rd_stats->sse = 0;
1475*77c1e3ccSAndroid Build Coastguard Worker     rd_stats->skip_txfm = 1;
1476*77c1e3ccSAndroid Build Coastguard Worker     rd_stats->rate = tmp_rate2;
1477*77c1e3ccSAndroid Build Coastguard Worker     const ModeCosts *mode_costs = &x->mode_costs;
1478*77c1e3ccSAndroid Build Coastguard Worker     if (mbmi->motion_mode != WARPED_CAUSAL) rd_stats->rate += switchable_rate;
1479*77c1e3ccSAndroid Build Coastguard Worker     if (interintra_allowed) {
1480*77c1e3ccSAndroid Build Coastguard Worker       rd_stats->rate +=
1481*77c1e3ccSAndroid Build Coastguard Worker           mode_costs->interintra_cost[size_group_lookup[bsize]]
1482*77c1e3ccSAndroid Build Coastguard Worker                                      [mbmi->ref_frame[1] == INTRA_FRAME];
1483*77c1e3ccSAndroid Build Coastguard Worker     }
1484*77c1e3ccSAndroid Build Coastguard Worker     if ((last_motion_mode_allowed > SIMPLE_TRANSLATION) &&
1485*77c1e3ccSAndroid Build Coastguard Worker         (mbmi->ref_frame[1] != INTRA_FRAME)) {
1486*77c1e3ccSAndroid Build Coastguard Worker       if (last_motion_mode_allowed == WARPED_CAUSAL) {
1487*77c1e3ccSAndroid Build Coastguard Worker         rd_stats->rate +=
1488*77c1e3ccSAndroid Build Coastguard Worker             mode_costs->motion_mode_cost[bsize][mbmi->motion_mode];
1489*77c1e3ccSAndroid Build Coastguard Worker       } else {
1490*77c1e3ccSAndroid Build Coastguard Worker         rd_stats->rate +=
1491*77c1e3ccSAndroid Build Coastguard Worker             mode_costs->motion_mode_cost1[bsize][mbmi->motion_mode];
1492*77c1e3ccSAndroid Build Coastguard Worker       }
1493*77c1e3ccSAndroid Build Coastguard Worker     }
1494*77c1e3ccSAndroid Build Coastguard Worker 
1495*77c1e3ccSAndroid Build Coastguard Worker     int64_t this_yrd = INT64_MAX;
1496*77c1e3ccSAndroid Build Coastguard Worker 
1497*77c1e3ccSAndroid Build Coastguard Worker     if (!do_tx_search) {
1498*77c1e3ccSAndroid Build Coastguard Worker       // Avoid doing a transform search here to speed up the overall mode
1499*77c1e3ccSAndroid Build Coastguard Worker       // search. It will be done later in the mode search if the current
1500*77c1e3ccSAndroid Build Coastguard Worker       // motion mode seems promising.
1501*77c1e3ccSAndroid Build Coastguard Worker       int64_t curr_sse = -1;
1502*77c1e3ccSAndroid Build Coastguard Worker       int64_t sse_y = -1;
1503*77c1e3ccSAndroid Build Coastguard Worker       int est_residue_cost = 0;
1504*77c1e3ccSAndroid Build Coastguard Worker       int64_t est_dist = 0;
1505*77c1e3ccSAndroid Build Coastguard Worker       int64_t est_rd = 0;
1506*77c1e3ccSAndroid Build Coastguard Worker       if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1) {
1507*77c1e3ccSAndroid Build Coastguard Worker         curr_sse = get_sse(cpi, x, &sse_y);
1508*77c1e3ccSAndroid Build Coastguard Worker         const int has_est_rd = get_est_rate_dist(tile_data, bsize, curr_sse,
1509*77c1e3ccSAndroid Build Coastguard Worker                                                  &est_residue_cost, &est_dist);
1510*77c1e3ccSAndroid Build Coastguard Worker         (void)has_est_rd;
1511*77c1e3ccSAndroid Build Coastguard Worker         assert(has_est_rd);
1512*77c1e3ccSAndroid Build Coastguard Worker       } else if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 2 ||
1513*77c1e3ccSAndroid Build Coastguard Worker                  cpi->sf.rt_sf.use_nonrd_pick_mode) {
1514*77c1e3ccSAndroid Build Coastguard Worker         model_rd_sb_fn[MODELRD_TYPE_MOTION_MODE_RD](
1515*77c1e3ccSAndroid Build Coastguard Worker             cpi, bsize, x, xd, 0, num_planes - 1, &est_residue_cost, &est_dist,
1516*77c1e3ccSAndroid Build Coastguard Worker             NULL, &curr_sse, NULL, NULL, NULL);
1517*77c1e3ccSAndroid Build Coastguard Worker         sse_y = x->pred_sse[xd->mi[0]->ref_frame[0]];
1518*77c1e3ccSAndroid Build Coastguard Worker       }
1519*77c1e3ccSAndroid Build Coastguard Worker       est_rd = RDCOST(x->rdmult, rd_stats->rate + est_residue_cost, est_dist);
1520*77c1e3ccSAndroid Build Coastguard Worker       if (est_rd * 0.80 > *best_est_rd) {
1521*77c1e3ccSAndroid Build Coastguard Worker         mbmi->ref_frame[1] = ref_frame_1;
1522*77c1e3ccSAndroid Build Coastguard Worker         continue;
1523*77c1e3ccSAndroid Build Coastguard Worker       }
1524*77c1e3ccSAndroid Build Coastguard Worker       const int mode_rate = rd_stats->rate;
1525*77c1e3ccSAndroid Build Coastguard Worker       rd_stats->rate += est_residue_cost;
1526*77c1e3ccSAndroid Build Coastguard Worker       rd_stats->dist = est_dist;
1527*77c1e3ccSAndroid Build Coastguard Worker       rd_stats->rdcost = est_rd;
1528*77c1e3ccSAndroid Build Coastguard Worker       if (rd_stats->rdcost < *best_est_rd) {
1529*77c1e3ccSAndroid Build Coastguard Worker         *best_est_rd = rd_stats->rdcost;
1530*77c1e3ccSAndroid Build Coastguard Worker         assert(sse_y >= 0);
1531*77c1e3ccSAndroid Build Coastguard Worker         ref_skip_rd[1] = txfm_rd_gate_level
1532*77c1e3ccSAndroid Build Coastguard Worker                              ? RDCOST(x->rdmult, mode_rate, (sse_y << 4))
1533*77c1e3ccSAndroid Build Coastguard Worker                              : INT64_MAX;
1534*77c1e3ccSAndroid Build Coastguard Worker       }
1535*77c1e3ccSAndroid Build Coastguard Worker       if (cm->current_frame.reference_mode == SINGLE_REFERENCE) {
1536*77c1e3ccSAndroid Build Coastguard Worker         if (!is_comp_pred) {
1537*77c1e3ccSAndroid Build Coastguard Worker           assert(curr_sse >= 0);
1538*77c1e3ccSAndroid Build Coastguard Worker           inter_modes_info_push(inter_modes_info, mode_rate, curr_sse,
1539*77c1e3ccSAndroid Build Coastguard Worker                                 rd_stats->rdcost, rd_stats, rd_stats_y,
1540*77c1e3ccSAndroid Build Coastguard Worker                                 rd_stats_uv, mbmi);
1541*77c1e3ccSAndroid Build Coastguard Worker         }
1542*77c1e3ccSAndroid Build Coastguard Worker       } else {
1543*77c1e3ccSAndroid Build Coastguard Worker         assert(curr_sse >= 0);
1544*77c1e3ccSAndroid Build Coastguard Worker         inter_modes_info_push(inter_modes_info, mode_rate, curr_sse,
1545*77c1e3ccSAndroid Build Coastguard Worker                               rd_stats->rdcost, rd_stats, rd_stats_y,
1546*77c1e3ccSAndroid Build Coastguard Worker                               rd_stats_uv, mbmi);
1547*77c1e3ccSAndroid Build Coastguard Worker       }
1548*77c1e3ccSAndroid Build Coastguard Worker       mbmi->skip_txfm = 0;
1549*77c1e3ccSAndroid Build Coastguard Worker     } else {
1550*77c1e3ccSAndroid Build Coastguard Worker       // Perform full transform search
1551*77c1e3ccSAndroid Build Coastguard Worker       int64_t skip_rd = INT64_MAX;
1552*77c1e3ccSAndroid Build Coastguard Worker       int64_t skip_rdy = INT64_MAX;
1553*77c1e3ccSAndroid Build Coastguard Worker       if (txfm_rd_gate_level) {
1554*77c1e3ccSAndroid Build Coastguard Worker         // Check if the mode is good enough based on skip RD
1555*77c1e3ccSAndroid Build Coastguard Worker         int64_t sse_y = INT64_MAX;
1556*77c1e3ccSAndroid Build Coastguard Worker         int64_t curr_sse = get_sse(cpi, x, &sse_y);
1557*77c1e3ccSAndroid Build Coastguard Worker         skip_rd = RDCOST(x->rdmult, rd_stats->rate, curr_sse);
1558*77c1e3ccSAndroid Build Coastguard Worker         skip_rdy = RDCOST(x->rdmult, rd_stats->rate, (sse_y << 4));
1559*77c1e3ccSAndroid Build Coastguard Worker         int eval_txfm = check_txfm_eval(x, bsize, ref_skip_rd[0], skip_rd,
1560*77c1e3ccSAndroid Build Coastguard Worker                                         txfm_rd_gate_level, 0);
1561*77c1e3ccSAndroid Build Coastguard Worker         if (!eval_txfm) continue;
1562*77c1e3ccSAndroid Build Coastguard Worker       }
1563*77c1e3ccSAndroid Build Coastguard Worker 
1564*77c1e3ccSAndroid Build Coastguard Worker       // Do transform search
1565*77c1e3ccSAndroid Build Coastguard Worker       const int mode_rate = rd_stats->rate;
1566*77c1e3ccSAndroid Build Coastguard Worker       if (!av1_txfm_search(cpi, x, bsize, rd_stats, rd_stats_y, rd_stats_uv,
1567*77c1e3ccSAndroid Build Coastguard Worker                            rd_stats->rate, ref_best_rd)) {
1568*77c1e3ccSAndroid Build Coastguard Worker         if (rd_stats_y->rate == INT_MAX && mode_index == 0) {
1569*77c1e3ccSAndroid Build Coastguard Worker           return INT64_MAX;
1570*77c1e3ccSAndroid Build Coastguard Worker         }
1571*77c1e3ccSAndroid Build Coastguard Worker         continue;
1572*77c1e3ccSAndroid Build Coastguard Worker       }
1573*77c1e3ccSAndroid Build Coastguard Worker       const int skip_ctx = av1_get_skip_txfm_context(xd);
1574*77c1e3ccSAndroid Build Coastguard Worker       const int y_rate =
1575*77c1e3ccSAndroid Build Coastguard Worker           rd_stats->skip_txfm
1576*77c1e3ccSAndroid Build Coastguard Worker               ? x->mode_costs.skip_txfm_cost[skip_ctx][1]
1577*77c1e3ccSAndroid Build Coastguard Worker               : (rd_stats_y->rate + x->mode_costs.skip_txfm_cost[skip_ctx][0]);
1578*77c1e3ccSAndroid Build Coastguard Worker       this_yrd = RDCOST(x->rdmult, y_rate + mode_rate, rd_stats_y->dist);
1579*77c1e3ccSAndroid Build Coastguard Worker 
1580*77c1e3ccSAndroid Build Coastguard Worker       const int64_t curr_rd = RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist);
1581*77c1e3ccSAndroid Build Coastguard Worker       if (curr_rd < ref_best_rd) {
1582*77c1e3ccSAndroid Build Coastguard Worker         ref_best_rd = curr_rd;
1583*77c1e3ccSAndroid Build Coastguard Worker         ref_skip_rd[0] = skip_rd;
1584*77c1e3ccSAndroid Build Coastguard Worker         ref_skip_rd[1] = skip_rdy;
1585*77c1e3ccSAndroid Build Coastguard Worker       }
1586*77c1e3ccSAndroid Build Coastguard Worker       if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1) {
1587*77c1e3ccSAndroid Build Coastguard Worker         inter_mode_data_push(
1588*77c1e3ccSAndroid Build Coastguard Worker             tile_data, mbmi->bsize, rd_stats->sse, rd_stats->dist,
1589*77c1e3ccSAndroid Build Coastguard Worker             rd_stats_y->rate + rd_stats_uv->rate +
1590*77c1e3ccSAndroid Build Coastguard Worker                 mode_costs->skip_txfm_cost[skip_ctx][mbmi->skip_txfm]);
1591*77c1e3ccSAndroid Build Coastguard Worker       }
1592*77c1e3ccSAndroid Build Coastguard Worker     }
1593*77c1e3ccSAndroid Build Coastguard Worker 
1594*77c1e3ccSAndroid Build Coastguard Worker     if (this_mode == GLOBALMV || this_mode == GLOBAL_GLOBALMV) {
1595*77c1e3ccSAndroid Build Coastguard Worker       if (is_nontrans_global_motion(xd, xd->mi[0])) {
1596*77c1e3ccSAndroid Build Coastguard Worker         mbmi->interp_filters =
1597*77c1e3ccSAndroid Build Coastguard Worker             av1_broadcast_interp_filter(av1_unswitchable_filter(interp_filter));
1598*77c1e3ccSAndroid Build Coastguard Worker       }
1599*77c1e3ccSAndroid Build Coastguard Worker     }
1600*77c1e3ccSAndroid Build Coastguard Worker 
1601*77c1e3ccSAndroid Build Coastguard Worker     const int64_t tmp_rd = RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist);
1602*77c1e3ccSAndroid Build Coastguard Worker     if (mode_index == 0) {
1603*77c1e3ccSAndroid Build Coastguard Worker       args->simple_rd[this_mode][mbmi->ref_mv_idx][mbmi->ref_frame[0]] = tmp_rd;
1604*77c1e3ccSAndroid Build Coastguard Worker     }
1605*77c1e3ccSAndroid Build Coastguard Worker     if (mode_index == 0 || tmp_rd < best_rd) {
1606*77c1e3ccSAndroid Build Coastguard Worker       // Update best_rd data if this is the best motion mode so far
1607*77c1e3ccSAndroid Build Coastguard Worker       best_mbmi = *mbmi;
1608*77c1e3ccSAndroid Build Coastguard Worker       best_rd = tmp_rd;
1609*77c1e3ccSAndroid Build Coastguard Worker       best_rd_stats = *rd_stats;
1610*77c1e3ccSAndroid Build Coastguard Worker       best_rd_stats_y = *rd_stats_y;
1611*77c1e3ccSAndroid Build Coastguard Worker       best_rate_mv = tmp_rate_mv;
1612*77c1e3ccSAndroid Build Coastguard Worker       *yrd = this_yrd;
1613*77c1e3ccSAndroid Build Coastguard Worker       if (num_planes > 1) best_rd_stats_uv = *rd_stats_uv;
1614*77c1e3ccSAndroid Build Coastguard Worker       memcpy(best_blk_skip, txfm_info->blk_skip,
1615*77c1e3ccSAndroid Build Coastguard Worker              sizeof(txfm_info->blk_skip[0]) * xd->height * xd->width);
1616*77c1e3ccSAndroid Build Coastguard Worker       av1_copy_array(best_tx_type_map, xd->tx_type_map, xd->height * xd->width);
1617*77c1e3ccSAndroid Build Coastguard Worker       best_xskip_txfm = mbmi->skip_txfm;
1618*77c1e3ccSAndroid Build Coastguard Worker     }
1619*77c1e3ccSAndroid Build Coastguard Worker   }
1620*77c1e3ccSAndroid Build Coastguard Worker   // Update RD and mbmi stats for selected motion mode
1621*77c1e3ccSAndroid Build Coastguard Worker   mbmi->ref_frame[1] = ref_frame_1;
1622*77c1e3ccSAndroid Build Coastguard Worker   *rate_mv = best_rate_mv;
1623*77c1e3ccSAndroid Build Coastguard Worker   if (best_rd == INT64_MAX || !av1_check_newmv_joint_nonzero(cm, x)) {
1624*77c1e3ccSAndroid Build Coastguard Worker     av1_invalid_rd_stats(rd_stats);
1625*77c1e3ccSAndroid Build Coastguard Worker     restore_dst_buf(xd, *orig_dst, num_planes);
1626*77c1e3ccSAndroid Build Coastguard Worker     return INT64_MAX;
1627*77c1e3ccSAndroid Build Coastguard Worker   }
1628*77c1e3ccSAndroid Build Coastguard Worker   *mbmi = best_mbmi;
1629*77c1e3ccSAndroid Build Coastguard Worker   *rd_stats = best_rd_stats;
1630*77c1e3ccSAndroid Build Coastguard Worker   *rd_stats_y = best_rd_stats_y;
1631*77c1e3ccSAndroid Build Coastguard Worker   if (num_planes > 1) *rd_stats_uv = best_rd_stats_uv;
1632*77c1e3ccSAndroid Build Coastguard Worker   memcpy(txfm_info->blk_skip, best_blk_skip,
1633*77c1e3ccSAndroid Build Coastguard Worker          sizeof(txfm_info->blk_skip[0]) * xd->height * xd->width);
1634*77c1e3ccSAndroid Build Coastguard Worker   av1_copy_array(xd->tx_type_map, best_tx_type_map, xd->height * xd->width);
1635*77c1e3ccSAndroid Build Coastguard Worker   txfm_info->skip_txfm = best_xskip_txfm;
1636*77c1e3ccSAndroid Build Coastguard Worker 
1637*77c1e3ccSAndroid Build Coastguard Worker   restore_dst_buf(xd, *orig_dst, num_planes);
1638*77c1e3ccSAndroid Build Coastguard Worker   return 0;
1639*77c1e3ccSAndroid Build Coastguard Worker }
1640*77c1e3ccSAndroid Build Coastguard Worker 
skip_mode_rd(RD_STATS * rd_stats,const AV1_COMP * const cpi,MACROBLOCK * const x,BLOCK_SIZE bsize,const BUFFER_SET * const orig_dst,int64_t best_rd)1641*77c1e3ccSAndroid Build Coastguard Worker static int64_t skip_mode_rd(RD_STATS *rd_stats, const AV1_COMP *const cpi,
1642*77c1e3ccSAndroid Build Coastguard Worker                             MACROBLOCK *const x, BLOCK_SIZE bsize,
1643*77c1e3ccSAndroid Build Coastguard Worker                             const BUFFER_SET *const orig_dst, int64_t best_rd) {
1644*77c1e3ccSAndroid Build Coastguard Worker   assert(bsize < BLOCK_SIZES_ALL);
1645*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *cm = &cpi->common;
1646*77c1e3ccSAndroid Build Coastguard Worker   const int num_planes = av1_num_planes(cm);
1647*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *const xd = &x->e_mbd;
1648*77c1e3ccSAndroid Build Coastguard Worker   const int mi_row = xd->mi_row;
1649*77c1e3ccSAndroid Build Coastguard Worker   const int mi_col = xd->mi_col;
1650*77c1e3ccSAndroid Build Coastguard Worker   int64_t total_sse = 0;
1651*77c1e3ccSAndroid Build Coastguard Worker   int64_t this_rd = INT64_MAX;
1652*77c1e3ccSAndroid Build Coastguard Worker   const int skip_mode_ctx = av1_get_skip_mode_context(xd);
1653*77c1e3ccSAndroid Build Coastguard Worker   rd_stats->rate = x->mode_costs.skip_mode_cost[skip_mode_ctx][1];
1654*77c1e3ccSAndroid Build Coastguard Worker 
1655*77c1e3ccSAndroid Build Coastguard Worker   for (int plane = 0; plane < num_planes; ++plane) {
1656*77c1e3ccSAndroid Build Coastguard Worker     // Call av1_enc_build_inter_predictor() for one plane at a time.
1657*77c1e3ccSAndroid Build Coastguard Worker     av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize,
1658*77c1e3ccSAndroid Build Coastguard Worker                                   plane, plane);
1659*77c1e3ccSAndroid Build Coastguard Worker     const struct macroblockd_plane *const pd = &xd->plane[plane];
1660*77c1e3ccSAndroid Build Coastguard Worker     const BLOCK_SIZE plane_bsize =
1661*77c1e3ccSAndroid Build Coastguard Worker         get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y);
1662*77c1e3ccSAndroid Build Coastguard Worker 
1663*77c1e3ccSAndroid Build Coastguard Worker     av1_subtract_plane(x, plane_bsize, plane);
1664*77c1e3ccSAndroid Build Coastguard Worker 
1665*77c1e3ccSAndroid Build Coastguard Worker     int64_t sse =
1666*77c1e3ccSAndroid Build Coastguard Worker         av1_pixel_diff_dist(x, plane, 0, 0, plane_bsize, plane_bsize, NULL);
1667*77c1e3ccSAndroid Build Coastguard Worker     if (is_cur_buf_hbd(xd)) sse = ROUND_POWER_OF_TWO(sse, (xd->bd - 8) * 2);
1668*77c1e3ccSAndroid Build Coastguard Worker     sse <<= 4;
1669*77c1e3ccSAndroid Build Coastguard Worker     total_sse += sse;
1670*77c1e3ccSAndroid Build Coastguard Worker     // When current rd cost is more than the best rd, skip evaluation of
1671*77c1e3ccSAndroid Build Coastguard Worker     // remaining planes.
1672*77c1e3ccSAndroid Build Coastguard Worker     this_rd = RDCOST(x->rdmult, rd_stats->rate, total_sse);
1673*77c1e3ccSAndroid Build Coastguard Worker     if (this_rd > best_rd) break;
1674*77c1e3ccSAndroid Build Coastguard Worker   }
1675*77c1e3ccSAndroid Build Coastguard Worker 
1676*77c1e3ccSAndroid Build Coastguard Worker   rd_stats->dist = rd_stats->sse = total_sse;
1677*77c1e3ccSAndroid Build Coastguard Worker   rd_stats->rdcost = this_rd;
1678*77c1e3ccSAndroid Build Coastguard Worker 
1679*77c1e3ccSAndroid Build Coastguard Worker   restore_dst_buf(xd, *orig_dst, num_planes);
1680*77c1e3ccSAndroid Build Coastguard Worker   return 0;
1681*77c1e3ccSAndroid Build Coastguard Worker }
1682*77c1e3ccSAndroid Build Coastguard Worker 
1683*77c1e3ccSAndroid Build Coastguard Worker // Check NEARESTMV, NEARMV, GLOBALMV ref mvs for duplicate and skip the relevant
1684*77c1e3ccSAndroid Build Coastguard Worker // mode
1685*77c1e3ccSAndroid Build Coastguard Worker // Note(rachelbarker): This speed feature currently does not interact correctly
1686*77c1e3ccSAndroid Build Coastguard Worker // with global motion. The issue is that, when global motion is used, GLOBALMV
1687*77c1e3ccSAndroid Build Coastguard Worker // produces a different prediction to NEARESTMV/NEARMV even if the motion
1688*77c1e3ccSAndroid Build Coastguard Worker // vectors are the same. Thus GLOBALMV should not be pruned in this case.
check_repeat_ref_mv(const MB_MODE_INFO_EXT * mbmi_ext,int ref_idx,const MV_REFERENCE_FRAME * ref_frame,PREDICTION_MODE single_mode)1689*77c1e3ccSAndroid Build Coastguard Worker static inline int check_repeat_ref_mv(const MB_MODE_INFO_EXT *mbmi_ext,
1690*77c1e3ccSAndroid Build Coastguard Worker                                       int ref_idx,
1691*77c1e3ccSAndroid Build Coastguard Worker                                       const MV_REFERENCE_FRAME *ref_frame,
1692*77c1e3ccSAndroid Build Coastguard Worker                                       PREDICTION_MODE single_mode) {
1693*77c1e3ccSAndroid Build Coastguard Worker   const uint8_t ref_frame_type = av1_ref_frame_type(ref_frame);
1694*77c1e3ccSAndroid Build Coastguard Worker   const int ref_mv_count = mbmi_ext->ref_mv_count[ref_frame_type];
1695*77c1e3ccSAndroid Build Coastguard Worker   assert(single_mode != NEWMV);
1696*77c1e3ccSAndroid Build Coastguard Worker   if (single_mode == NEARESTMV) {
1697*77c1e3ccSAndroid Build Coastguard Worker     return 0;
1698*77c1e3ccSAndroid Build Coastguard Worker   } else if (single_mode == NEARMV) {
1699*77c1e3ccSAndroid Build Coastguard Worker     // when ref_mv_count = 0, NEARESTMV and NEARMV are same as GLOBALMV
1700*77c1e3ccSAndroid Build Coastguard Worker     // when ref_mv_count = 1, NEARMV is same as GLOBALMV
1701*77c1e3ccSAndroid Build Coastguard Worker     if (ref_mv_count < 2) return 1;
1702*77c1e3ccSAndroid Build Coastguard Worker   } else if (single_mode == GLOBALMV) {
1703*77c1e3ccSAndroid Build Coastguard Worker     // when ref_mv_count == 0, GLOBALMV is same as NEARESTMV
1704*77c1e3ccSAndroid Build Coastguard Worker     if (ref_mv_count == 0) return 1;
1705*77c1e3ccSAndroid Build Coastguard Worker     // when ref_mv_count == 1, NEARMV is same as GLOBALMV
1706*77c1e3ccSAndroid Build Coastguard Worker     else if (ref_mv_count == 1)
1707*77c1e3ccSAndroid Build Coastguard Worker       return 0;
1708*77c1e3ccSAndroid Build Coastguard Worker 
1709*77c1e3ccSAndroid Build Coastguard Worker     int stack_size = AOMMIN(USABLE_REF_MV_STACK_SIZE, ref_mv_count);
1710*77c1e3ccSAndroid Build Coastguard Worker     // Check GLOBALMV is matching with any mv in ref_mv_stack
1711*77c1e3ccSAndroid Build Coastguard Worker     for (int ref_mv_idx = 0; ref_mv_idx < stack_size; ref_mv_idx++) {
1712*77c1e3ccSAndroid Build Coastguard Worker       int_mv this_mv;
1713*77c1e3ccSAndroid Build Coastguard Worker 
1714*77c1e3ccSAndroid Build Coastguard Worker       if (ref_idx == 0)
1715*77c1e3ccSAndroid Build Coastguard Worker         this_mv = mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_idx].this_mv;
1716*77c1e3ccSAndroid Build Coastguard Worker       else
1717*77c1e3ccSAndroid Build Coastguard Worker         this_mv = mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_idx].comp_mv;
1718*77c1e3ccSAndroid Build Coastguard Worker 
1719*77c1e3ccSAndroid Build Coastguard Worker       if (this_mv.as_int == mbmi_ext->global_mvs[ref_frame[ref_idx]].as_int)
1720*77c1e3ccSAndroid Build Coastguard Worker         return 1;
1721*77c1e3ccSAndroid Build Coastguard Worker     }
1722*77c1e3ccSAndroid Build Coastguard Worker   }
1723*77c1e3ccSAndroid Build Coastguard Worker   return 0;
1724*77c1e3ccSAndroid Build Coastguard Worker }
1725*77c1e3ccSAndroid Build Coastguard Worker 
get_this_mv(int_mv * this_mv,PREDICTION_MODE this_mode,int ref_idx,int ref_mv_idx,int skip_repeated_ref_mv,const MV_REFERENCE_FRAME * ref_frame,const MB_MODE_INFO_EXT * mbmi_ext)1726*77c1e3ccSAndroid Build Coastguard Worker static inline int get_this_mv(int_mv *this_mv, PREDICTION_MODE this_mode,
1727*77c1e3ccSAndroid Build Coastguard Worker                               int ref_idx, int ref_mv_idx,
1728*77c1e3ccSAndroid Build Coastguard Worker                               int skip_repeated_ref_mv,
1729*77c1e3ccSAndroid Build Coastguard Worker                               const MV_REFERENCE_FRAME *ref_frame,
1730*77c1e3ccSAndroid Build Coastguard Worker                               const MB_MODE_INFO_EXT *mbmi_ext) {
1731*77c1e3ccSAndroid Build Coastguard Worker   const PREDICTION_MODE single_mode = get_single_mode(this_mode, ref_idx);
1732*77c1e3ccSAndroid Build Coastguard Worker   assert(is_inter_singleref_mode(single_mode));
1733*77c1e3ccSAndroid Build Coastguard Worker   if (single_mode == NEWMV) {
1734*77c1e3ccSAndroid Build Coastguard Worker     this_mv->as_int = INVALID_MV;
1735*77c1e3ccSAndroid Build Coastguard Worker   } else if (single_mode == GLOBALMV) {
1736*77c1e3ccSAndroid Build Coastguard Worker     if (skip_repeated_ref_mv &&
1737*77c1e3ccSAndroid Build Coastguard Worker         check_repeat_ref_mv(mbmi_ext, ref_idx, ref_frame, single_mode))
1738*77c1e3ccSAndroid Build Coastguard Worker       return 0;
1739*77c1e3ccSAndroid Build Coastguard Worker     *this_mv = mbmi_ext->global_mvs[ref_frame[ref_idx]];
1740*77c1e3ccSAndroid Build Coastguard Worker   } else {
1741*77c1e3ccSAndroid Build Coastguard Worker     assert(single_mode == NEARMV || single_mode == NEARESTMV);
1742*77c1e3ccSAndroid Build Coastguard Worker     const uint8_t ref_frame_type = av1_ref_frame_type(ref_frame);
1743*77c1e3ccSAndroid Build Coastguard Worker     const int ref_mv_offset = single_mode == NEARESTMV ? 0 : ref_mv_idx + 1;
1744*77c1e3ccSAndroid Build Coastguard Worker     if (ref_mv_offset < mbmi_ext->ref_mv_count[ref_frame_type]) {
1745*77c1e3ccSAndroid Build Coastguard Worker       assert(ref_mv_offset >= 0);
1746*77c1e3ccSAndroid Build Coastguard Worker       if (ref_idx == 0) {
1747*77c1e3ccSAndroid Build Coastguard Worker         *this_mv =
1748*77c1e3ccSAndroid Build Coastguard Worker             mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_offset].this_mv;
1749*77c1e3ccSAndroid Build Coastguard Worker       } else {
1750*77c1e3ccSAndroid Build Coastguard Worker         *this_mv =
1751*77c1e3ccSAndroid Build Coastguard Worker             mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_offset].comp_mv;
1752*77c1e3ccSAndroid Build Coastguard Worker       }
1753*77c1e3ccSAndroid Build Coastguard Worker     } else {
1754*77c1e3ccSAndroid Build Coastguard Worker       if (skip_repeated_ref_mv &&
1755*77c1e3ccSAndroid Build Coastguard Worker           check_repeat_ref_mv(mbmi_ext, ref_idx, ref_frame, single_mode))
1756*77c1e3ccSAndroid Build Coastguard Worker         return 0;
1757*77c1e3ccSAndroid Build Coastguard Worker       *this_mv = mbmi_ext->global_mvs[ref_frame[ref_idx]];
1758*77c1e3ccSAndroid Build Coastguard Worker     }
1759*77c1e3ccSAndroid Build Coastguard Worker   }
1760*77c1e3ccSAndroid Build Coastguard Worker   return 1;
1761*77c1e3ccSAndroid Build Coastguard Worker }
1762*77c1e3ccSAndroid Build Coastguard Worker 
1763*77c1e3ccSAndroid Build Coastguard Worker // Skip NEARESTMV and NEARMV modes based on refmv weight computed in ref mv list
1764*77c1e3ccSAndroid Build Coastguard Worker // population
skip_nearest_near_mv_using_refmv_weight(const MACROBLOCK * const x,const PREDICTION_MODE this_mode,const int8_t ref_frame_type,PREDICTION_MODE best_mode)1765*77c1e3ccSAndroid Build Coastguard Worker static inline int skip_nearest_near_mv_using_refmv_weight(
1766*77c1e3ccSAndroid Build Coastguard Worker     const MACROBLOCK *const x, const PREDICTION_MODE this_mode,
1767*77c1e3ccSAndroid Build Coastguard Worker     const int8_t ref_frame_type, PREDICTION_MODE best_mode) {
1768*77c1e3ccSAndroid Build Coastguard Worker   if (this_mode != NEARESTMV && this_mode != NEARMV) return 0;
1769*77c1e3ccSAndroid Build Coastguard Worker   // Do not skip the mode if the current block has not yet obtained a valid
1770*77c1e3ccSAndroid Build Coastguard Worker   // inter mode.
1771*77c1e3ccSAndroid Build Coastguard Worker   if (!is_inter_mode(best_mode)) return 0;
1772*77c1e3ccSAndroid Build Coastguard Worker 
1773*77c1e3ccSAndroid Build Coastguard Worker   const MACROBLOCKD *xd = &x->e_mbd;
1774*77c1e3ccSAndroid Build Coastguard Worker   // Do not skip the mode if both the top and left neighboring blocks are not
1775*77c1e3ccSAndroid Build Coastguard Worker   // available.
1776*77c1e3ccSAndroid Build Coastguard Worker   if (!xd->left_available || !xd->up_available) return 0;
1777*77c1e3ccSAndroid Build Coastguard Worker   const MB_MODE_INFO_EXT *const mbmi_ext = &x->mbmi_ext;
1778*77c1e3ccSAndroid Build Coastguard Worker   const uint16_t *const ref_mv_weight = mbmi_ext->weight[ref_frame_type];
1779*77c1e3ccSAndroid Build Coastguard Worker   const int ref_mv_count =
1780*77c1e3ccSAndroid Build Coastguard Worker       AOMMIN(MAX_REF_MV_SEARCH, mbmi_ext->ref_mv_count[ref_frame_type]);
1781*77c1e3ccSAndroid Build Coastguard Worker 
1782*77c1e3ccSAndroid Build Coastguard Worker   if (ref_mv_count == 0) return 0;
1783*77c1e3ccSAndroid Build Coastguard Worker   // If ref mv list has at least one nearest candidate do not prune NEARESTMV
1784*77c1e3ccSAndroid Build Coastguard Worker   if (this_mode == NEARESTMV && ref_mv_weight[0] >= REF_CAT_LEVEL) return 0;
1785*77c1e3ccSAndroid Build Coastguard Worker 
1786*77c1e3ccSAndroid Build Coastguard Worker   // Count number of ref mvs populated from nearest candidates
1787*77c1e3ccSAndroid Build Coastguard Worker   int nearest_refmv_count = 0;
1788*77c1e3ccSAndroid Build Coastguard Worker   for (int ref_mv_idx = 0; ref_mv_idx < ref_mv_count; ref_mv_idx++) {
1789*77c1e3ccSAndroid Build Coastguard Worker     if (ref_mv_weight[ref_mv_idx] >= REF_CAT_LEVEL) nearest_refmv_count++;
1790*77c1e3ccSAndroid Build Coastguard Worker   }
1791*77c1e3ccSAndroid Build Coastguard Worker 
1792*77c1e3ccSAndroid Build Coastguard Worker   // nearest_refmv_count indicates the closeness of block motion characteristics
1793*77c1e3ccSAndroid Build Coastguard Worker   // with respect to its spatial neighbor. Smaller value of nearest_refmv_count
1794*77c1e3ccSAndroid Build Coastguard Worker   // w.r.t to ref_mv_count means less correlation with its spatial neighbors.
1795*77c1e3ccSAndroid Build Coastguard Worker   // Hence less possibility for NEARESTMV and NEARMV modes becoming the best
1796*77c1e3ccSAndroid Build Coastguard Worker   // mode since these modes work well for blocks that shares similar motion
1797*77c1e3ccSAndroid Build Coastguard Worker   // characteristics with its neighbor. Thus, NEARMV mode is pruned when
1798*77c1e3ccSAndroid Build Coastguard Worker   // nearest_refmv_count is relatively smaller than ref_mv_count and NEARESTMV
1799*77c1e3ccSAndroid Build Coastguard Worker   // mode is pruned if none of the ref mvs are populated from nearest candidate.
1800*77c1e3ccSAndroid Build Coastguard Worker   const int prune_thresh = 1 + (ref_mv_count >= 2);
1801*77c1e3ccSAndroid Build Coastguard Worker   if (nearest_refmv_count < prune_thresh) return 1;
1802*77c1e3ccSAndroid Build Coastguard Worker   return 0;
1803*77c1e3ccSAndroid Build Coastguard Worker }
1804*77c1e3ccSAndroid Build Coastguard Worker 
1805*77c1e3ccSAndroid Build Coastguard Worker // This function update the non-new mv for the current prediction mode
build_cur_mv(int_mv * cur_mv,PREDICTION_MODE this_mode,const AV1_COMMON * cm,const MACROBLOCK * x,int skip_repeated_ref_mv)1806*77c1e3ccSAndroid Build Coastguard Worker static inline int build_cur_mv(int_mv *cur_mv, PREDICTION_MODE this_mode,
1807*77c1e3ccSAndroid Build Coastguard Worker                                const AV1_COMMON *cm, const MACROBLOCK *x,
1808*77c1e3ccSAndroid Build Coastguard Worker                                int skip_repeated_ref_mv) {
1809*77c1e3ccSAndroid Build Coastguard Worker   const MACROBLOCKD *xd = &x->e_mbd;
1810*77c1e3ccSAndroid Build Coastguard Worker   const MB_MODE_INFO *mbmi = xd->mi[0];
1811*77c1e3ccSAndroid Build Coastguard Worker   const int is_comp_pred = has_second_ref(mbmi);
1812*77c1e3ccSAndroid Build Coastguard Worker 
1813*77c1e3ccSAndroid Build Coastguard Worker   int ret = 1;
1814*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < is_comp_pred + 1; ++i) {
1815*77c1e3ccSAndroid Build Coastguard Worker     int_mv this_mv;
1816*77c1e3ccSAndroid Build Coastguard Worker     this_mv.as_int = INVALID_MV;
1817*77c1e3ccSAndroid Build Coastguard Worker     ret = get_this_mv(&this_mv, this_mode, i, mbmi->ref_mv_idx,
1818*77c1e3ccSAndroid Build Coastguard Worker                       skip_repeated_ref_mv, mbmi->ref_frame, &x->mbmi_ext);
1819*77c1e3ccSAndroid Build Coastguard Worker     if (!ret) return 0;
1820*77c1e3ccSAndroid Build Coastguard Worker     const PREDICTION_MODE single_mode = get_single_mode(this_mode, i);
1821*77c1e3ccSAndroid Build Coastguard Worker     if (single_mode == NEWMV) {
1822*77c1e3ccSAndroid Build Coastguard Worker       const uint8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
1823*77c1e3ccSAndroid Build Coastguard Worker       cur_mv[i] =
1824*77c1e3ccSAndroid Build Coastguard Worker           (i == 0) ? x->mbmi_ext.ref_mv_stack[ref_frame_type][mbmi->ref_mv_idx]
1825*77c1e3ccSAndroid Build Coastguard Worker                          .this_mv
1826*77c1e3ccSAndroid Build Coastguard Worker                    : x->mbmi_ext.ref_mv_stack[ref_frame_type][mbmi->ref_mv_idx]
1827*77c1e3ccSAndroid Build Coastguard Worker                          .comp_mv;
1828*77c1e3ccSAndroid Build Coastguard Worker     } else {
1829*77c1e3ccSAndroid Build Coastguard Worker       ret &= clamp_and_check_mv(cur_mv + i, this_mv, cm, x);
1830*77c1e3ccSAndroid Build Coastguard Worker     }
1831*77c1e3ccSAndroid Build Coastguard Worker   }
1832*77c1e3ccSAndroid Build Coastguard Worker   return ret;
1833*77c1e3ccSAndroid Build Coastguard Worker }
1834*77c1e3ccSAndroid Build Coastguard Worker 
get_drl_cost(const MB_MODE_INFO * mbmi,const MB_MODE_INFO_EXT * mbmi_ext,const int (* const drl_mode_cost0)[2],int8_t ref_frame_type)1835*77c1e3ccSAndroid Build Coastguard Worker static inline int get_drl_cost(const MB_MODE_INFO *mbmi,
1836*77c1e3ccSAndroid Build Coastguard Worker                                const MB_MODE_INFO_EXT *mbmi_ext,
1837*77c1e3ccSAndroid Build Coastguard Worker                                const int (*const drl_mode_cost0)[2],
1838*77c1e3ccSAndroid Build Coastguard Worker                                int8_t ref_frame_type) {
1839*77c1e3ccSAndroid Build Coastguard Worker   int cost = 0;
1840*77c1e3ccSAndroid Build Coastguard Worker   if (mbmi->mode == NEWMV || mbmi->mode == NEW_NEWMV) {
1841*77c1e3ccSAndroid Build Coastguard Worker     for (int idx = 0; idx < 2; ++idx) {
1842*77c1e3ccSAndroid Build Coastguard Worker       if (mbmi_ext->ref_mv_count[ref_frame_type] > idx + 1) {
1843*77c1e3ccSAndroid Build Coastguard Worker         uint8_t drl_ctx = av1_drl_ctx(mbmi_ext->weight[ref_frame_type], idx);
1844*77c1e3ccSAndroid Build Coastguard Worker         cost += drl_mode_cost0[drl_ctx][mbmi->ref_mv_idx != idx];
1845*77c1e3ccSAndroid Build Coastguard Worker         if (mbmi->ref_mv_idx == idx) return cost;
1846*77c1e3ccSAndroid Build Coastguard Worker       }
1847*77c1e3ccSAndroid Build Coastguard Worker     }
1848*77c1e3ccSAndroid Build Coastguard Worker     return cost;
1849*77c1e3ccSAndroid Build Coastguard Worker   }
1850*77c1e3ccSAndroid Build Coastguard Worker 
1851*77c1e3ccSAndroid Build Coastguard Worker   if (have_nearmv_in_inter_mode(mbmi->mode)) {
1852*77c1e3ccSAndroid Build Coastguard Worker     for (int idx = 1; idx < 3; ++idx) {
1853*77c1e3ccSAndroid Build Coastguard Worker       if (mbmi_ext->ref_mv_count[ref_frame_type] > idx + 1) {
1854*77c1e3ccSAndroid Build Coastguard Worker         uint8_t drl_ctx = av1_drl_ctx(mbmi_ext->weight[ref_frame_type], idx);
1855*77c1e3ccSAndroid Build Coastguard Worker         cost += drl_mode_cost0[drl_ctx][mbmi->ref_mv_idx != (idx - 1)];
1856*77c1e3ccSAndroid Build Coastguard Worker         if (mbmi->ref_mv_idx == (idx - 1)) return cost;
1857*77c1e3ccSAndroid Build Coastguard Worker       }
1858*77c1e3ccSAndroid Build Coastguard Worker     }
1859*77c1e3ccSAndroid Build Coastguard Worker     return cost;
1860*77c1e3ccSAndroid Build Coastguard Worker   }
1861*77c1e3ccSAndroid Build Coastguard Worker   return cost;
1862*77c1e3ccSAndroid Build Coastguard Worker }
1863*77c1e3ccSAndroid Build Coastguard Worker 
is_single_newmv_valid(const HandleInterModeArgs * const args,const MB_MODE_INFO * const mbmi,PREDICTION_MODE this_mode)1864*77c1e3ccSAndroid Build Coastguard Worker static inline int is_single_newmv_valid(const HandleInterModeArgs *const args,
1865*77c1e3ccSAndroid Build Coastguard Worker                                         const MB_MODE_INFO *const mbmi,
1866*77c1e3ccSAndroid Build Coastguard Worker                                         PREDICTION_MODE this_mode) {
1867*77c1e3ccSAndroid Build Coastguard Worker   for (int ref_idx = 0; ref_idx < 2; ++ref_idx) {
1868*77c1e3ccSAndroid Build Coastguard Worker     const PREDICTION_MODE single_mode = get_single_mode(this_mode, ref_idx);
1869*77c1e3ccSAndroid Build Coastguard Worker     const MV_REFERENCE_FRAME ref = mbmi->ref_frame[ref_idx];
1870*77c1e3ccSAndroid Build Coastguard Worker     if (single_mode == NEWMV &&
1871*77c1e3ccSAndroid Build Coastguard Worker         args->single_newmv_valid[mbmi->ref_mv_idx][ref] == 0) {
1872*77c1e3ccSAndroid Build Coastguard Worker       return 0;
1873*77c1e3ccSAndroid Build Coastguard Worker     }
1874*77c1e3ccSAndroid Build Coastguard Worker   }
1875*77c1e3ccSAndroid Build Coastguard Worker   return 1;
1876*77c1e3ccSAndroid Build Coastguard Worker }
1877*77c1e3ccSAndroid Build Coastguard Worker 
get_drl_refmv_count(const MACROBLOCK * const x,const MV_REFERENCE_FRAME * ref_frame,PREDICTION_MODE mode)1878*77c1e3ccSAndroid Build Coastguard Worker static int get_drl_refmv_count(const MACROBLOCK *const x,
1879*77c1e3ccSAndroid Build Coastguard Worker                                const MV_REFERENCE_FRAME *ref_frame,
1880*77c1e3ccSAndroid Build Coastguard Worker                                PREDICTION_MODE mode) {
1881*77c1e3ccSAndroid Build Coastguard Worker   const MB_MODE_INFO_EXT *const mbmi_ext = &x->mbmi_ext;
1882*77c1e3ccSAndroid Build Coastguard Worker   const int8_t ref_frame_type = av1_ref_frame_type(ref_frame);
1883*77c1e3ccSAndroid Build Coastguard Worker   const int has_nearmv = have_nearmv_in_inter_mode(mode) ? 1 : 0;
1884*77c1e3ccSAndroid Build Coastguard Worker   const int ref_mv_count = mbmi_ext->ref_mv_count[ref_frame_type];
1885*77c1e3ccSAndroid Build Coastguard Worker   const int only_newmv = (mode == NEWMV || mode == NEW_NEWMV);
1886*77c1e3ccSAndroid Build Coastguard Worker   const int has_drl =
1887*77c1e3ccSAndroid Build Coastguard Worker       (has_nearmv && ref_mv_count > 2) || (only_newmv && ref_mv_count > 1);
1888*77c1e3ccSAndroid Build Coastguard Worker   const int ref_set =
1889*77c1e3ccSAndroid Build Coastguard Worker       has_drl ? AOMMIN(MAX_REF_MV_SEARCH, ref_mv_count - has_nearmv) : 1;
1890*77c1e3ccSAndroid Build Coastguard Worker 
1891*77c1e3ccSAndroid Build Coastguard Worker   return ref_set;
1892*77c1e3ccSAndroid Build Coastguard Worker }
1893*77c1e3ccSAndroid Build Coastguard Worker 
1894*77c1e3ccSAndroid Build Coastguard Worker // Checks if particular ref_mv_idx should be pruned.
prune_ref_mv_idx_using_qindex(const int reduce_inter_modes,const int qindex,const int ref_mv_idx)1895*77c1e3ccSAndroid Build Coastguard Worker static int prune_ref_mv_idx_using_qindex(const int reduce_inter_modes,
1896*77c1e3ccSAndroid Build Coastguard Worker                                          const int qindex,
1897*77c1e3ccSAndroid Build Coastguard Worker                                          const int ref_mv_idx) {
1898*77c1e3ccSAndroid Build Coastguard Worker   if (reduce_inter_modes >= 3) return 1;
1899*77c1e3ccSAndroid Build Coastguard Worker   // Q-index logic based pruning is enabled only for
1900*77c1e3ccSAndroid Build Coastguard Worker   // reduce_inter_modes = 2.
1901*77c1e3ccSAndroid Build Coastguard Worker   assert(reduce_inter_modes == 2);
1902*77c1e3ccSAndroid Build Coastguard Worker   // When reduce_inter_modes=2, pruning happens as below based on q index.
1903*77c1e3ccSAndroid Build Coastguard Worker   // For q index range between 0 and 85: prune if ref_mv_idx >= 1.
1904*77c1e3ccSAndroid Build Coastguard Worker   // For q index range between 86 and 170: prune if ref_mv_idx == 2.
1905*77c1e3ccSAndroid Build Coastguard Worker   // For q index range between 171 and 255: no pruning.
1906*77c1e3ccSAndroid Build Coastguard Worker   const int min_prune_ref_mv_idx = (qindex * 3 / QINDEX_RANGE) + 1;
1907*77c1e3ccSAndroid Build Coastguard Worker   return (ref_mv_idx >= min_prune_ref_mv_idx);
1908*77c1e3ccSAndroid Build Coastguard Worker }
1909*77c1e3ccSAndroid Build Coastguard Worker 
1910*77c1e3ccSAndroid Build Coastguard Worker // Whether this reference motion vector can be skipped, based on initial
1911*77c1e3ccSAndroid Build Coastguard Worker // heuristics.
ref_mv_idx_early_breakout(const SPEED_FEATURES * const sf,const RefFrameDistanceInfo * const ref_frame_dist_info,MACROBLOCK * x,const HandleInterModeArgs * const args,int64_t ref_best_rd,int ref_mv_idx)1912*77c1e3ccSAndroid Build Coastguard Worker static bool ref_mv_idx_early_breakout(
1913*77c1e3ccSAndroid Build Coastguard Worker     const SPEED_FEATURES *const sf,
1914*77c1e3ccSAndroid Build Coastguard Worker     const RefFrameDistanceInfo *const ref_frame_dist_info, MACROBLOCK *x,
1915*77c1e3ccSAndroid Build Coastguard Worker     const HandleInterModeArgs *const args, int64_t ref_best_rd,
1916*77c1e3ccSAndroid Build Coastguard Worker     int ref_mv_idx) {
1917*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *xd = &x->e_mbd;
1918*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *mbmi = xd->mi[0];
1919*77c1e3ccSAndroid Build Coastguard Worker   const MB_MODE_INFO_EXT *const mbmi_ext = &x->mbmi_ext;
1920*77c1e3ccSAndroid Build Coastguard Worker   const int8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
1921*77c1e3ccSAndroid Build Coastguard Worker   const int is_comp_pred = has_second_ref(mbmi);
1922*77c1e3ccSAndroid Build Coastguard Worker   if (sf->inter_sf.reduce_inter_modes && ref_mv_idx > 0) {
1923*77c1e3ccSAndroid Build Coastguard Worker     if (mbmi->ref_frame[0] == LAST2_FRAME ||
1924*77c1e3ccSAndroid Build Coastguard Worker         mbmi->ref_frame[0] == LAST3_FRAME ||
1925*77c1e3ccSAndroid Build Coastguard Worker         mbmi->ref_frame[1] == LAST2_FRAME ||
1926*77c1e3ccSAndroid Build Coastguard Worker         mbmi->ref_frame[1] == LAST3_FRAME) {
1927*77c1e3ccSAndroid Build Coastguard Worker       const int has_nearmv = have_nearmv_in_inter_mode(mbmi->mode) ? 1 : 0;
1928*77c1e3ccSAndroid Build Coastguard Worker       if (mbmi_ext->weight[ref_frame_type][ref_mv_idx + has_nearmv] <
1929*77c1e3ccSAndroid Build Coastguard Worker           REF_CAT_LEVEL) {
1930*77c1e3ccSAndroid Build Coastguard Worker         return true;
1931*77c1e3ccSAndroid Build Coastguard Worker       }
1932*77c1e3ccSAndroid Build Coastguard Worker     }
1933*77c1e3ccSAndroid Build Coastguard Worker     // TODO(any): Experiment with reduce_inter_modes for compound prediction
1934*77c1e3ccSAndroid Build Coastguard Worker     if (sf->inter_sf.reduce_inter_modes >= 2 && !is_comp_pred &&
1935*77c1e3ccSAndroid Build Coastguard Worker         have_newmv_in_inter_mode(mbmi->mode)) {
1936*77c1e3ccSAndroid Build Coastguard Worker       if (mbmi->ref_frame[0] != ref_frame_dist_info->nearest_past_ref &&
1937*77c1e3ccSAndroid Build Coastguard Worker           mbmi->ref_frame[0] != ref_frame_dist_info->nearest_future_ref) {
1938*77c1e3ccSAndroid Build Coastguard Worker         const int has_nearmv = have_nearmv_in_inter_mode(mbmi->mode) ? 1 : 0;
1939*77c1e3ccSAndroid Build Coastguard Worker         const int do_prune = prune_ref_mv_idx_using_qindex(
1940*77c1e3ccSAndroid Build Coastguard Worker             sf->inter_sf.reduce_inter_modes, x->qindex, ref_mv_idx);
1941*77c1e3ccSAndroid Build Coastguard Worker         if (do_prune &&
1942*77c1e3ccSAndroid Build Coastguard Worker             (mbmi_ext->weight[ref_frame_type][ref_mv_idx + has_nearmv] <
1943*77c1e3ccSAndroid Build Coastguard Worker              REF_CAT_LEVEL)) {
1944*77c1e3ccSAndroid Build Coastguard Worker           return true;
1945*77c1e3ccSAndroid Build Coastguard Worker         }
1946*77c1e3ccSAndroid Build Coastguard Worker       }
1947*77c1e3ccSAndroid Build Coastguard Worker     }
1948*77c1e3ccSAndroid Build Coastguard Worker   }
1949*77c1e3ccSAndroid Build Coastguard Worker 
1950*77c1e3ccSAndroid Build Coastguard Worker   mbmi->ref_mv_idx = ref_mv_idx;
1951*77c1e3ccSAndroid Build Coastguard Worker   if (is_comp_pred && (!is_single_newmv_valid(args, mbmi, mbmi->mode))) {
1952*77c1e3ccSAndroid Build Coastguard Worker     return true;
1953*77c1e3ccSAndroid Build Coastguard Worker   }
1954*77c1e3ccSAndroid Build Coastguard Worker   size_t est_rd_rate = args->ref_frame_cost + args->single_comp_cost;
1955*77c1e3ccSAndroid Build Coastguard Worker   const int drl_cost = get_drl_cost(
1956*77c1e3ccSAndroid Build Coastguard Worker       mbmi, mbmi_ext, x->mode_costs.drl_mode_cost0, ref_frame_type);
1957*77c1e3ccSAndroid Build Coastguard Worker   est_rd_rate += drl_cost;
1958*77c1e3ccSAndroid Build Coastguard Worker   if (RDCOST(x->rdmult, est_rd_rate, 0) > ref_best_rd &&
1959*77c1e3ccSAndroid Build Coastguard Worker       mbmi->mode != NEARESTMV && mbmi->mode != NEAREST_NEARESTMV) {
1960*77c1e3ccSAndroid Build Coastguard Worker     return true;
1961*77c1e3ccSAndroid Build Coastguard Worker   }
1962*77c1e3ccSAndroid Build Coastguard Worker   return false;
1963*77c1e3ccSAndroid Build Coastguard Worker }
1964*77c1e3ccSAndroid Build Coastguard Worker 
1965*77c1e3ccSAndroid Build Coastguard Worker // Compute the estimated RD cost for the motion vector with simple translation.
simple_translation_pred_rd(AV1_COMP * const cpi,MACROBLOCK * x,RD_STATS * rd_stats,HandleInterModeArgs * args,int ref_mv_idx,int64_t ref_best_rd,BLOCK_SIZE bsize)1966*77c1e3ccSAndroid Build Coastguard Worker static int64_t simple_translation_pred_rd(AV1_COMP *const cpi, MACROBLOCK *x,
1967*77c1e3ccSAndroid Build Coastguard Worker                                           RD_STATS *rd_stats,
1968*77c1e3ccSAndroid Build Coastguard Worker                                           HandleInterModeArgs *args,
1969*77c1e3ccSAndroid Build Coastguard Worker                                           int ref_mv_idx, int64_t ref_best_rd,
1970*77c1e3ccSAndroid Build Coastguard Worker                                           BLOCK_SIZE bsize) {
1971*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *xd = &x->e_mbd;
1972*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *mbmi = xd->mi[0];
1973*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO_EXT *const mbmi_ext = &x->mbmi_ext;
1974*77c1e3ccSAndroid Build Coastguard Worker   const int8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
1975*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *cm = &cpi->common;
1976*77c1e3ccSAndroid Build Coastguard Worker   const int is_comp_pred = has_second_ref(mbmi);
1977*77c1e3ccSAndroid Build Coastguard Worker   const ModeCosts *mode_costs = &x->mode_costs;
1978*77c1e3ccSAndroid Build Coastguard Worker 
1979*77c1e3ccSAndroid Build Coastguard Worker   struct macroblockd_plane *p = xd->plane;
1980*77c1e3ccSAndroid Build Coastguard Worker   const BUFFER_SET orig_dst = {
1981*77c1e3ccSAndroid Build Coastguard Worker     { p[0].dst.buf, p[1].dst.buf, p[2].dst.buf },
1982*77c1e3ccSAndroid Build Coastguard Worker     { p[0].dst.stride, p[1].dst.stride, p[2].dst.stride },
1983*77c1e3ccSAndroid Build Coastguard Worker   };
1984*77c1e3ccSAndroid Build Coastguard Worker   av1_init_rd_stats(rd_stats);
1985*77c1e3ccSAndroid Build Coastguard Worker 
1986*77c1e3ccSAndroid Build Coastguard Worker   mbmi->interinter_comp.type = COMPOUND_AVERAGE;
1987*77c1e3ccSAndroid Build Coastguard Worker   mbmi->comp_group_idx = 0;
1988*77c1e3ccSAndroid Build Coastguard Worker   mbmi->compound_idx = 1;
1989*77c1e3ccSAndroid Build Coastguard Worker   if (mbmi->ref_frame[1] == INTRA_FRAME) {
1990*77c1e3ccSAndroid Build Coastguard Worker     mbmi->ref_frame[1] = NONE_FRAME;
1991*77c1e3ccSAndroid Build Coastguard Worker   }
1992*77c1e3ccSAndroid Build Coastguard Worker   int16_t mode_ctx =
1993*77c1e3ccSAndroid Build Coastguard Worker       av1_mode_context_analyzer(mbmi_ext->mode_context, mbmi->ref_frame);
1994*77c1e3ccSAndroid Build Coastguard Worker 
1995*77c1e3ccSAndroid Build Coastguard Worker   mbmi->num_proj_ref = 0;
1996*77c1e3ccSAndroid Build Coastguard Worker   mbmi->motion_mode = SIMPLE_TRANSLATION;
1997*77c1e3ccSAndroid Build Coastguard Worker   mbmi->ref_mv_idx = ref_mv_idx;
1998*77c1e3ccSAndroid Build Coastguard Worker 
1999*77c1e3ccSAndroid Build Coastguard Worker   rd_stats->rate += args->ref_frame_cost + args->single_comp_cost;
2000*77c1e3ccSAndroid Build Coastguard Worker   const int drl_cost =
2001*77c1e3ccSAndroid Build Coastguard Worker       get_drl_cost(mbmi, mbmi_ext, mode_costs->drl_mode_cost0, ref_frame_type);
2002*77c1e3ccSAndroid Build Coastguard Worker   rd_stats->rate += drl_cost;
2003*77c1e3ccSAndroid Build Coastguard Worker 
2004*77c1e3ccSAndroid Build Coastguard Worker   int_mv cur_mv[2];
2005*77c1e3ccSAndroid Build Coastguard Worker   if (!build_cur_mv(cur_mv, mbmi->mode, cm, x, 0)) {
2006*77c1e3ccSAndroid Build Coastguard Worker     return INT64_MAX;
2007*77c1e3ccSAndroid Build Coastguard Worker   }
2008*77c1e3ccSAndroid Build Coastguard Worker   assert(have_nearmv_in_inter_mode(mbmi->mode));
2009*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < is_comp_pred + 1; ++i) {
2010*77c1e3ccSAndroid Build Coastguard Worker     mbmi->mv[i].as_int = cur_mv[i].as_int;
2011*77c1e3ccSAndroid Build Coastguard Worker   }
2012*77c1e3ccSAndroid Build Coastguard Worker   const int ref_mv_cost = cost_mv_ref(mode_costs, mbmi->mode, mode_ctx);
2013*77c1e3ccSAndroid Build Coastguard Worker   rd_stats->rate += ref_mv_cost;
2014*77c1e3ccSAndroid Build Coastguard Worker 
2015*77c1e3ccSAndroid Build Coastguard Worker   if (RDCOST(x->rdmult, rd_stats->rate, 0) > ref_best_rd) {
2016*77c1e3ccSAndroid Build Coastguard Worker     return INT64_MAX;
2017*77c1e3ccSAndroid Build Coastguard Worker   }
2018*77c1e3ccSAndroid Build Coastguard Worker 
2019*77c1e3ccSAndroid Build Coastguard Worker   mbmi->motion_mode = SIMPLE_TRANSLATION;
2020*77c1e3ccSAndroid Build Coastguard Worker   mbmi->num_proj_ref = 0;
2021*77c1e3ccSAndroid Build Coastguard Worker   if (is_comp_pred) {
2022*77c1e3ccSAndroid Build Coastguard Worker     // Only compound_average
2023*77c1e3ccSAndroid Build Coastguard Worker     mbmi->interinter_comp.type = COMPOUND_AVERAGE;
2024*77c1e3ccSAndroid Build Coastguard Worker     mbmi->comp_group_idx = 0;
2025*77c1e3ccSAndroid Build Coastguard Worker     mbmi->compound_idx = 1;
2026*77c1e3ccSAndroid Build Coastguard Worker   }
2027*77c1e3ccSAndroid Build Coastguard Worker   set_default_interp_filters(mbmi, cm->features.interp_filter);
2028*77c1e3ccSAndroid Build Coastguard Worker 
2029*77c1e3ccSAndroid Build Coastguard Worker   const int mi_row = xd->mi_row;
2030*77c1e3ccSAndroid Build Coastguard Worker   const int mi_col = xd->mi_col;
2031*77c1e3ccSAndroid Build Coastguard Worker   av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst, bsize,
2032*77c1e3ccSAndroid Build Coastguard Worker                                 AOM_PLANE_Y, AOM_PLANE_Y);
2033*77c1e3ccSAndroid Build Coastguard Worker   int est_rate;
2034*77c1e3ccSAndroid Build Coastguard Worker   int64_t est_dist;
2035*77c1e3ccSAndroid Build Coastguard Worker   model_rd_sb_fn[MODELRD_CURVFIT](cpi, bsize, x, xd, 0, 0, &est_rate, &est_dist,
2036*77c1e3ccSAndroid Build Coastguard Worker                                   NULL, NULL, NULL, NULL, NULL);
2037*77c1e3ccSAndroid Build Coastguard Worker   return RDCOST(x->rdmult, rd_stats->rate + est_rate, est_dist);
2038*77c1e3ccSAndroid Build Coastguard Worker }
2039*77c1e3ccSAndroid Build Coastguard Worker 
2040*77c1e3ccSAndroid Build Coastguard Worker // Represents a set of integers, from 0 to sizeof(int) * 8, as bits in
2041*77c1e3ccSAndroid Build Coastguard Worker // an integer. 0 for the i-th bit means that integer is excluded, 1 means
2042*77c1e3ccSAndroid Build Coastguard Worker // it is included.
mask_set_bit(int * mask,int index)2043*77c1e3ccSAndroid Build Coastguard Worker static inline void mask_set_bit(int *mask, int index) { *mask |= (1 << index); }
2044*77c1e3ccSAndroid Build Coastguard Worker 
mask_check_bit(int mask,int index)2045*77c1e3ccSAndroid Build Coastguard Worker static inline bool mask_check_bit(int mask, int index) {
2046*77c1e3ccSAndroid Build Coastguard Worker   return (mask >> index) & 0x1;
2047*77c1e3ccSAndroid Build Coastguard Worker }
2048*77c1e3ccSAndroid Build Coastguard Worker 
2049*77c1e3ccSAndroid Build Coastguard Worker // Before performing the full MV search in handle_inter_mode, do a simple
2050*77c1e3ccSAndroid Build Coastguard Worker // translation search and see if we can eliminate any motion vectors.
2051*77c1e3ccSAndroid Build Coastguard Worker // Returns an integer where, if the i-th bit is set, it means that the i-th
2052*77c1e3ccSAndroid Build Coastguard Worker // motion vector should be searched. This is only set for NEAR_MV.
ref_mv_idx_to_search(AV1_COMP * const cpi,MACROBLOCK * x,RD_STATS * rd_stats,HandleInterModeArgs * const args,int64_t ref_best_rd,BLOCK_SIZE bsize,const int ref_set)2053*77c1e3ccSAndroid Build Coastguard Worker static int ref_mv_idx_to_search(AV1_COMP *const cpi, MACROBLOCK *x,
2054*77c1e3ccSAndroid Build Coastguard Worker                                 RD_STATS *rd_stats,
2055*77c1e3ccSAndroid Build Coastguard Worker                                 HandleInterModeArgs *const args,
2056*77c1e3ccSAndroid Build Coastguard Worker                                 int64_t ref_best_rd, BLOCK_SIZE bsize,
2057*77c1e3ccSAndroid Build Coastguard Worker                                 const int ref_set) {
2058*77c1e3ccSAndroid Build Coastguard Worker   // If the number of ref mv count is equal to 1, do not prune the same. It
2059*77c1e3ccSAndroid Build Coastguard Worker   // is better to evaluate the same than to prune it.
2060*77c1e3ccSAndroid Build Coastguard Worker   if (ref_set == 1) return 1;
2061*77c1e3ccSAndroid Build Coastguard Worker   AV1_COMMON *const cm = &cpi->common;
2062*77c1e3ccSAndroid Build Coastguard Worker   const MACROBLOCKD *const xd = &x->e_mbd;
2063*77c1e3ccSAndroid Build Coastguard Worker   const MB_MODE_INFO *const mbmi = xd->mi[0];
2064*77c1e3ccSAndroid Build Coastguard Worker   const PREDICTION_MODE this_mode = mbmi->mode;
2065*77c1e3ccSAndroid Build Coastguard Worker 
2066*77c1e3ccSAndroid Build Coastguard Worker   // Only search indices if they have some chance of being good.
2067*77c1e3ccSAndroid Build Coastguard Worker   int good_indices = 0;
2068*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < ref_set; ++i) {
2069*77c1e3ccSAndroid Build Coastguard Worker     if (ref_mv_idx_early_breakout(&cpi->sf, &cpi->ref_frame_dist_info, x, args,
2070*77c1e3ccSAndroid Build Coastguard Worker                                   ref_best_rd, i)) {
2071*77c1e3ccSAndroid Build Coastguard Worker       continue;
2072*77c1e3ccSAndroid Build Coastguard Worker     }
2073*77c1e3ccSAndroid Build Coastguard Worker     mask_set_bit(&good_indices, i);
2074*77c1e3ccSAndroid Build Coastguard Worker   }
2075*77c1e3ccSAndroid Build Coastguard Worker 
2076*77c1e3ccSAndroid Build Coastguard Worker   // Only prune in NEARMV mode, if the speed feature is set, and the block size
2077*77c1e3ccSAndroid Build Coastguard Worker   // is large enough. If these conditions are not met, return all good indices
2078*77c1e3ccSAndroid Build Coastguard Worker   // found so far.
2079*77c1e3ccSAndroid Build Coastguard Worker   if (!cpi->sf.inter_sf.prune_mode_search_simple_translation)
2080*77c1e3ccSAndroid Build Coastguard Worker     return good_indices;
2081*77c1e3ccSAndroid Build Coastguard Worker   if (!have_nearmv_in_inter_mode(this_mode)) return good_indices;
2082*77c1e3ccSAndroid Build Coastguard Worker   if (num_pels_log2_lookup[bsize] <= 6) return good_indices;
2083*77c1e3ccSAndroid Build Coastguard Worker   // Do not prune when there is internal resizing. TODO(elliottk) fix this
2084*77c1e3ccSAndroid Build Coastguard Worker   // so b/2384 can be resolved.
2085*77c1e3ccSAndroid Build Coastguard Worker   if (av1_is_scaled(get_ref_scale_factors(cm, mbmi->ref_frame[0])) ||
2086*77c1e3ccSAndroid Build Coastguard Worker       (mbmi->ref_frame[1] > 0 &&
2087*77c1e3ccSAndroid Build Coastguard Worker        av1_is_scaled(get_ref_scale_factors(cm, mbmi->ref_frame[1])))) {
2088*77c1e3ccSAndroid Build Coastguard Worker     return good_indices;
2089*77c1e3ccSAndroid Build Coastguard Worker   }
2090*77c1e3ccSAndroid Build Coastguard Worker 
2091*77c1e3ccSAndroid Build Coastguard Worker   // Calculate the RD cost for the motion vectors using simple translation.
2092*77c1e3ccSAndroid Build Coastguard Worker   int64_t idx_rdcost[] = { INT64_MAX, INT64_MAX, INT64_MAX };
2093*77c1e3ccSAndroid Build Coastguard Worker   for (int ref_mv_idx = 0; ref_mv_idx < ref_set; ++ref_mv_idx) {
2094*77c1e3ccSAndroid Build Coastguard Worker     // If this index is bad, ignore it.
2095*77c1e3ccSAndroid Build Coastguard Worker     if (!mask_check_bit(good_indices, ref_mv_idx)) {
2096*77c1e3ccSAndroid Build Coastguard Worker       continue;
2097*77c1e3ccSAndroid Build Coastguard Worker     }
2098*77c1e3ccSAndroid Build Coastguard Worker     idx_rdcost[ref_mv_idx] = simple_translation_pred_rd(
2099*77c1e3ccSAndroid Build Coastguard Worker         cpi, x, rd_stats, args, ref_mv_idx, ref_best_rd, bsize);
2100*77c1e3ccSAndroid Build Coastguard Worker   }
2101*77c1e3ccSAndroid Build Coastguard Worker   // Find the index with the best RD cost.
2102*77c1e3ccSAndroid Build Coastguard Worker   int best_idx = 0;
2103*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 1; i < MAX_REF_MV_SEARCH; ++i) {
2104*77c1e3ccSAndroid Build Coastguard Worker     if (idx_rdcost[i] < idx_rdcost[best_idx]) {
2105*77c1e3ccSAndroid Build Coastguard Worker       best_idx = i;
2106*77c1e3ccSAndroid Build Coastguard Worker     }
2107*77c1e3ccSAndroid Build Coastguard Worker   }
2108*77c1e3ccSAndroid Build Coastguard Worker   // Only include indices that are good and within a % of the best.
2109*77c1e3ccSAndroid Build Coastguard Worker   const double dth = has_second_ref(mbmi) ? 1.05 : 1.001;
2110*77c1e3ccSAndroid Build Coastguard Worker   // If the simple translation cost is not within this multiple of the
2111*77c1e3ccSAndroid Build Coastguard Worker   // best RD, skip it. Note that the cutoff is derived experimentally.
2112*77c1e3ccSAndroid Build Coastguard Worker   const double ref_dth = 5;
2113*77c1e3ccSAndroid Build Coastguard Worker   int result = 0;
2114*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < ref_set; ++i) {
2115*77c1e3ccSAndroid Build Coastguard Worker     if (mask_check_bit(good_indices, i) &&
2116*77c1e3ccSAndroid Build Coastguard Worker         (1.0 * idx_rdcost[i]) / idx_rdcost[best_idx] < dth &&
2117*77c1e3ccSAndroid Build Coastguard Worker         (1.0 * idx_rdcost[i]) / ref_best_rd < ref_dth) {
2118*77c1e3ccSAndroid Build Coastguard Worker       mask_set_bit(&result, i);
2119*77c1e3ccSAndroid Build Coastguard Worker     }
2120*77c1e3ccSAndroid Build Coastguard Worker   }
2121*77c1e3ccSAndroid Build Coastguard Worker   return result;
2122*77c1e3ccSAndroid Build Coastguard Worker }
2123*77c1e3ccSAndroid Build Coastguard Worker 
2124*77c1e3ccSAndroid Build Coastguard Worker /*!\brief Motion mode information for inter mode search speedup.
2125*77c1e3ccSAndroid Build Coastguard Worker  *
2126*77c1e3ccSAndroid Build Coastguard Worker  * Used in a speed feature to search motion modes other than
2127*77c1e3ccSAndroid Build Coastguard Worker  * SIMPLE_TRANSLATION only on winning candidates.
2128*77c1e3ccSAndroid Build Coastguard Worker  */
2129*77c1e3ccSAndroid Build Coastguard Worker typedef struct motion_mode_candidate {
2130*77c1e3ccSAndroid Build Coastguard Worker   /*!
2131*77c1e3ccSAndroid Build Coastguard Worker    * Mode info for the motion mode candidate.
2132*77c1e3ccSAndroid Build Coastguard Worker    */
2133*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO mbmi;
2134*77c1e3ccSAndroid Build Coastguard Worker   /*!
2135*77c1e3ccSAndroid Build Coastguard Worker    * Rate describing the cost of the motion vectors for this candidate.
2136*77c1e3ccSAndroid Build Coastguard Worker    */
2137*77c1e3ccSAndroid Build Coastguard Worker   int rate_mv;
2138*77c1e3ccSAndroid Build Coastguard Worker   /*!
2139*77c1e3ccSAndroid Build Coastguard Worker    * Rate before motion mode search and transform coding is applied.
2140*77c1e3ccSAndroid Build Coastguard Worker    */
2141*77c1e3ccSAndroid Build Coastguard Worker   int rate2_nocoeff;
2142*77c1e3ccSAndroid Build Coastguard Worker   /*!
2143*77c1e3ccSAndroid Build Coastguard Worker    * An integer value 0 or 1 which indicates whether or not to skip the motion
2144*77c1e3ccSAndroid Build Coastguard Worker    * mode search and default to SIMPLE_TRANSLATION as a speed feature for this
2145*77c1e3ccSAndroid Build Coastguard Worker    * candidate.
2146*77c1e3ccSAndroid Build Coastguard Worker    */
2147*77c1e3ccSAndroid Build Coastguard Worker   int skip_motion_mode;
2148*77c1e3ccSAndroid Build Coastguard Worker   /*!
2149*77c1e3ccSAndroid Build Coastguard Worker    * Total RD cost for this candidate.
2150*77c1e3ccSAndroid Build Coastguard Worker    */
2151*77c1e3ccSAndroid Build Coastguard Worker   int64_t rd_cost;
2152*77c1e3ccSAndroid Build Coastguard Worker } motion_mode_candidate;
2153*77c1e3ccSAndroid Build Coastguard Worker 
2154*77c1e3ccSAndroid Build Coastguard Worker /*!\cond */
2155*77c1e3ccSAndroid Build Coastguard Worker typedef struct motion_mode_best_st_candidate {
2156*77c1e3ccSAndroid Build Coastguard Worker   motion_mode_candidate motion_mode_cand[MAX_WINNER_MOTION_MODES];
2157*77c1e3ccSAndroid Build Coastguard Worker   int num_motion_mode_cand;
2158*77c1e3ccSAndroid Build Coastguard Worker } motion_mode_best_st_candidate;
2159*77c1e3ccSAndroid Build Coastguard Worker 
2160*77c1e3ccSAndroid Build Coastguard Worker // Checks if the current reference frame matches with neighbouring block's
2161*77c1e3ccSAndroid Build Coastguard Worker // (top/left) reference frames
ref_match_found_in_nb_blocks(MB_MODE_INFO * cur_mbmi,MB_MODE_INFO * nb_mbmi)2162*77c1e3ccSAndroid Build Coastguard Worker static inline int ref_match_found_in_nb_blocks(MB_MODE_INFO *cur_mbmi,
2163*77c1e3ccSAndroid Build Coastguard Worker                                                MB_MODE_INFO *nb_mbmi) {
2164*77c1e3ccSAndroid Build Coastguard Worker   MV_REFERENCE_FRAME nb_ref_frames[2] = { nb_mbmi->ref_frame[0],
2165*77c1e3ccSAndroid Build Coastguard Worker                                           nb_mbmi->ref_frame[1] };
2166*77c1e3ccSAndroid Build Coastguard Worker   MV_REFERENCE_FRAME cur_ref_frames[2] = { cur_mbmi->ref_frame[0],
2167*77c1e3ccSAndroid Build Coastguard Worker                                            cur_mbmi->ref_frame[1] };
2168*77c1e3ccSAndroid Build Coastguard Worker   const int is_cur_comp_pred = has_second_ref(cur_mbmi);
2169*77c1e3ccSAndroid Build Coastguard Worker   int match_found = 0;
2170*77c1e3ccSAndroid Build Coastguard Worker 
2171*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < (is_cur_comp_pred + 1); i++) {
2172*77c1e3ccSAndroid Build Coastguard Worker     if ((cur_ref_frames[i] == nb_ref_frames[0]) ||
2173*77c1e3ccSAndroid Build Coastguard Worker         (cur_ref_frames[i] == nb_ref_frames[1]))
2174*77c1e3ccSAndroid Build Coastguard Worker       match_found = 1;
2175*77c1e3ccSAndroid Build Coastguard Worker   }
2176*77c1e3ccSAndroid Build Coastguard Worker   return match_found;
2177*77c1e3ccSAndroid Build Coastguard Worker }
2178*77c1e3ccSAndroid Build Coastguard Worker 
find_ref_match_in_above_nbs(const int total_mi_cols,MACROBLOCKD * xd)2179*77c1e3ccSAndroid Build Coastguard Worker static inline int find_ref_match_in_above_nbs(const int total_mi_cols,
2180*77c1e3ccSAndroid Build Coastguard Worker                                               MACROBLOCKD *xd) {
2181*77c1e3ccSAndroid Build Coastguard Worker   if (!xd->up_available) return 1;
2182*77c1e3ccSAndroid Build Coastguard Worker   const int mi_col = xd->mi_col;
2183*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO **cur_mbmi = xd->mi;
2184*77c1e3ccSAndroid Build Coastguard Worker   // prev_row_mi points into the mi array, starting at the beginning of the
2185*77c1e3ccSAndroid Build Coastguard Worker   // previous row.
2186*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO **prev_row_mi = xd->mi - mi_col - 1 * xd->mi_stride;
2187*77c1e3ccSAndroid Build Coastguard Worker   const int end_col = AOMMIN(mi_col + xd->width, total_mi_cols);
2188*77c1e3ccSAndroid Build Coastguard Worker   uint8_t mi_step;
2189*77c1e3ccSAndroid Build Coastguard Worker   for (int above_mi_col = mi_col; above_mi_col < end_col;
2190*77c1e3ccSAndroid Build Coastguard Worker        above_mi_col += mi_step) {
2191*77c1e3ccSAndroid Build Coastguard Worker     MB_MODE_INFO **above_mi = prev_row_mi + above_mi_col;
2192*77c1e3ccSAndroid Build Coastguard Worker     mi_step = mi_size_wide[above_mi[0]->bsize];
2193*77c1e3ccSAndroid Build Coastguard Worker     int match_found = 0;
2194*77c1e3ccSAndroid Build Coastguard Worker     if (is_inter_block(*above_mi))
2195*77c1e3ccSAndroid Build Coastguard Worker       match_found = ref_match_found_in_nb_blocks(*cur_mbmi, *above_mi);
2196*77c1e3ccSAndroid Build Coastguard Worker     if (match_found) return 1;
2197*77c1e3ccSAndroid Build Coastguard Worker   }
2198*77c1e3ccSAndroid Build Coastguard Worker   return 0;
2199*77c1e3ccSAndroid Build Coastguard Worker }
2200*77c1e3ccSAndroid Build Coastguard Worker 
find_ref_match_in_left_nbs(const int total_mi_rows,MACROBLOCKD * xd)2201*77c1e3ccSAndroid Build Coastguard Worker static inline int find_ref_match_in_left_nbs(const int total_mi_rows,
2202*77c1e3ccSAndroid Build Coastguard Worker                                              MACROBLOCKD *xd) {
2203*77c1e3ccSAndroid Build Coastguard Worker   if (!xd->left_available) return 1;
2204*77c1e3ccSAndroid Build Coastguard Worker   const int mi_row = xd->mi_row;
2205*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO **cur_mbmi = xd->mi;
2206*77c1e3ccSAndroid Build Coastguard Worker   // prev_col_mi points into the mi array, starting at the top of the
2207*77c1e3ccSAndroid Build Coastguard Worker   // previous column
2208*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO **prev_col_mi = xd->mi - 1 - mi_row * xd->mi_stride;
2209*77c1e3ccSAndroid Build Coastguard Worker   const int end_row = AOMMIN(mi_row + xd->height, total_mi_rows);
2210*77c1e3ccSAndroid Build Coastguard Worker   uint8_t mi_step;
2211*77c1e3ccSAndroid Build Coastguard Worker   for (int left_mi_row = mi_row; left_mi_row < end_row;
2212*77c1e3ccSAndroid Build Coastguard Worker        left_mi_row += mi_step) {
2213*77c1e3ccSAndroid Build Coastguard Worker     MB_MODE_INFO **left_mi = prev_col_mi + left_mi_row * xd->mi_stride;
2214*77c1e3ccSAndroid Build Coastguard Worker     mi_step = mi_size_high[left_mi[0]->bsize];
2215*77c1e3ccSAndroid Build Coastguard Worker     int match_found = 0;
2216*77c1e3ccSAndroid Build Coastguard Worker     if (is_inter_block(*left_mi))
2217*77c1e3ccSAndroid Build Coastguard Worker       match_found = ref_match_found_in_nb_blocks(*cur_mbmi, *left_mi);
2218*77c1e3ccSAndroid Build Coastguard Worker     if (match_found) return 1;
2219*77c1e3ccSAndroid Build Coastguard Worker   }
2220*77c1e3ccSAndroid Build Coastguard Worker   return 0;
2221*77c1e3ccSAndroid Build Coastguard Worker }
2222*77c1e3ccSAndroid Build Coastguard Worker /*!\endcond */
2223*77c1e3ccSAndroid Build Coastguard Worker 
2224*77c1e3ccSAndroid Build Coastguard Worker /*! \brief Struct used to hold TPL data to
2225*77c1e3ccSAndroid Build Coastguard Worker  * narrow down parts of the inter mode search.
2226*77c1e3ccSAndroid Build Coastguard Worker  */
2227*77c1e3ccSAndroid Build Coastguard Worker typedef struct {
2228*77c1e3ccSAndroid Build Coastguard Worker   /*!
2229*77c1e3ccSAndroid Build Coastguard Worker    * The best inter cost out of all of the reference frames.
2230*77c1e3ccSAndroid Build Coastguard Worker    */
2231*77c1e3ccSAndroid Build Coastguard Worker   int64_t best_inter_cost;
2232*77c1e3ccSAndroid Build Coastguard Worker   /*!
2233*77c1e3ccSAndroid Build Coastguard Worker    * The inter cost for each reference frame.
2234*77c1e3ccSAndroid Build Coastguard Worker    */
2235*77c1e3ccSAndroid Build Coastguard Worker   int64_t ref_inter_cost[INTER_REFS_PER_FRAME];
2236*77c1e3ccSAndroid Build Coastguard Worker } PruneInfoFromTpl;
2237*77c1e3ccSAndroid Build Coastguard Worker 
2238*77c1e3ccSAndroid Build Coastguard Worker #if !CONFIG_REALTIME_ONLY
2239*77c1e3ccSAndroid Build Coastguard Worker // TODO(Remya): Check if get_tpl_stats_b() can be reused
get_block_level_tpl_stats(AV1_COMP * cpi,BLOCK_SIZE bsize,int mi_row,int mi_col,int * valid_refs,PruneInfoFromTpl * inter_cost_info_from_tpl)2240*77c1e3ccSAndroid Build Coastguard Worker static inline void get_block_level_tpl_stats(
2241*77c1e3ccSAndroid Build Coastguard Worker     AV1_COMP *cpi, BLOCK_SIZE bsize, int mi_row, int mi_col, int *valid_refs,
2242*77c1e3ccSAndroid Build Coastguard Worker     PruneInfoFromTpl *inter_cost_info_from_tpl) {
2243*77c1e3ccSAndroid Build Coastguard Worker   AV1_COMMON *const cm = &cpi->common;
2244*77c1e3ccSAndroid Build Coastguard Worker 
2245*77c1e3ccSAndroid Build Coastguard Worker   assert(IMPLIES(cpi->ppi->gf_group.size > 0,
2246*77c1e3ccSAndroid Build Coastguard Worker                  cpi->gf_frame_index < cpi->ppi->gf_group.size));
2247*77c1e3ccSAndroid Build Coastguard Worker   const int tpl_idx = cpi->gf_frame_index;
2248*77c1e3ccSAndroid Build Coastguard Worker   TplParams *const tpl_data = &cpi->ppi->tpl_data;
2249*77c1e3ccSAndroid Build Coastguard Worker   if (!av1_tpl_stats_ready(tpl_data, tpl_idx)) return;
2250*77c1e3ccSAndroid Build Coastguard Worker   const TplDepFrame *tpl_frame = &tpl_data->tpl_frame[tpl_idx];
2251*77c1e3ccSAndroid Build Coastguard Worker   const TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr;
2252*77c1e3ccSAndroid Build Coastguard Worker   const int mi_wide = mi_size_wide[bsize];
2253*77c1e3ccSAndroid Build Coastguard Worker   const int mi_high = mi_size_high[bsize];
2254*77c1e3ccSAndroid Build Coastguard Worker   const int tpl_stride = tpl_frame->stride;
2255*77c1e3ccSAndroid Build Coastguard Worker   const int step = 1 << tpl_data->tpl_stats_block_mis_log2;
2256*77c1e3ccSAndroid Build Coastguard Worker   const int mi_col_sr =
2257*77c1e3ccSAndroid Build Coastguard Worker       coded_to_superres_mi(mi_col, cm->superres_scale_denominator);
2258*77c1e3ccSAndroid Build Coastguard Worker   const int mi_col_end_sr =
2259*77c1e3ccSAndroid Build Coastguard Worker       coded_to_superres_mi(mi_col + mi_wide, cm->superres_scale_denominator);
2260*77c1e3ccSAndroid Build Coastguard Worker   const int mi_cols_sr = av1_pixels_to_mi(cm->superres_upscaled_width);
2261*77c1e3ccSAndroid Build Coastguard Worker 
2262*77c1e3ccSAndroid Build Coastguard Worker   const int row_step = step;
2263*77c1e3ccSAndroid Build Coastguard Worker   const int col_step_sr =
2264*77c1e3ccSAndroid Build Coastguard Worker       coded_to_superres_mi(step, cm->superres_scale_denominator);
2265*77c1e3ccSAndroid Build Coastguard Worker   for (int row = mi_row; row < AOMMIN(mi_row + mi_high, cm->mi_params.mi_rows);
2266*77c1e3ccSAndroid Build Coastguard Worker        row += row_step) {
2267*77c1e3ccSAndroid Build Coastguard Worker     for (int col = mi_col_sr; col < AOMMIN(mi_col_end_sr, mi_cols_sr);
2268*77c1e3ccSAndroid Build Coastguard Worker          col += col_step_sr) {
2269*77c1e3ccSAndroid Build Coastguard Worker       const TplDepStats *this_stats = &tpl_stats[av1_tpl_ptr_pos(
2270*77c1e3ccSAndroid Build Coastguard Worker           row, col, tpl_stride, tpl_data->tpl_stats_block_mis_log2)];
2271*77c1e3ccSAndroid Build Coastguard Worker 
2272*77c1e3ccSAndroid Build Coastguard Worker       // Sums up the inter cost of corresponding ref frames
2273*77c1e3ccSAndroid Build Coastguard Worker       for (int ref_idx = 0; ref_idx < INTER_REFS_PER_FRAME; ref_idx++) {
2274*77c1e3ccSAndroid Build Coastguard Worker         inter_cost_info_from_tpl->ref_inter_cost[ref_idx] +=
2275*77c1e3ccSAndroid Build Coastguard Worker             this_stats->pred_error[ref_idx];
2276*77c1e3ccSAndroid Build Coastguard Worker       }
2277*77c1e3ccSAndroid Build Coastguard Worker     }
2278*77c1e3ccSAndroid Build Coastguard Worker   }
2279*77c1e3ccSAndroid Build Coastguard Worker 
2280*77c1e3ccSAndroid Build Coastguard Worker   // Computes the best inter cost (minimum inter_cost)
2281*77c1e3ccSAndroid Build Coastguard Worker   int64_t best_inter_cost = INT64_MAX;
2282*77c1e3ccSAndroid Build Coastguard Worker   for (int ref_idx = 0; ref_idx < INTER_REFS_PER_FRAME; ref_idx++) {
2283*77c1e3ccSAndroid Build Coastguard Worker     const int64_t cur_inter_cost =
2284*77c1e3ccSAndroid Build Coastguard Worker         inter_cost_info_from_tpl->ref_inter_cost[ref_idx];
2285*77c1e3ccSAndroid Build Coastguard Worker     // For invalid ref frames, cur_inter_cost = 0 and has to be handled while
2286*77c1e3ccSAndroid Build Coastguard Worker     // calculating the minimum inter_cost
2287*77c1e3ccSAndroid Build Coastguard Worker     if (cur_inter_cost != 0 && (cur_inter_cost < best_inter_cost) &&
2288*77c1e3ccSAndroid Build Coastguard Worker         valid_refs[ref_idx])
2289*77c1e3ccSAndroid Build Coastguard Worker       best_inter_cost = cur_inter_cost;
2290*77c1e3ccSAndroid Build Coastguard Worker   }
2291*77c1e3ccSAndroid Build Coastguard Worker   inter_cost_info_from_tpl->best_inter_cost = best_inter_cost;
2292*77c1e3ccSAndroid Build Coastguard Worker }
2293*77c1e3ccSAndroid Build Coastguard Worker #endif
2294*77c1e3ccSAndroid Build Coastguard Worker 
prune_modes_based_on_tpl_stats(PruneInfoFromTpl * inter_cost_info_from_tpl,const int * refs,int ref_mv_idx,const PREDICTION_MODE this_mode,int prune_mode_level)2295*77c1e3ccSAndroid Build Coastguard Worker static inline int prune_modes_based_on_tpl_stats(
2296*77c1e3ccSAndroid Build Coastguard Worker     PruneInfoFromTpl *inter_cost_info_from_tpl, const int *refs, int ref_mv_idx,
2297*77c1e3ccSAndroid Build Coastguard Worker     const PREDICTION_MODE this_mode, int prune_mode_level) {
2298*77c1e3ccSAndroid Build Coastguard Worker   const int have_newmv = have_newmv_in_inter_mode(this_mode);
2299*77c1e3ccSAndroid Build Coastguard Worker   if ((prune_mode_level < 2) && have_newmv) return 0;
2300*77c1e3ccSAndroid Build Coastguard Worker 
2301*77c1e3ccSAndroid Build Coastguard Worker   const int64_t best_inter_cost = inter_cost_info_from_tpl->best_inter_cost;
2302*77c1e3ccSAndroid Build Coastguard Worker   if (best_inter_cost == INT64_MAX) return 0;
2303*77c1e3ccSAndroid Build Coastguard Worker 
2304*77c1e3ccSAndroid Build Coastguard Worker   const int prune_level = prune_mode_level - 1;
2305*77c1e3ccSAndroid Build Coastguard Worker   int64_t cur_inter_cost;
2306*77c1e3ccSAndroid Build Coastguard Worker 
2307*77c1e3ccSAndroid Build Coastguard Worker   const int is_globalmv =
2308*77c1e3ccSAndroid Build Coastguard Worker       (this_mode == GLOBALMV) || (this_mode == GLOBAL_GLOBALMV);
2309*77c1e3ccSAndroid Build Coastguard Worker   const int prune_index = is_globalmv ? MAX_REF_MV_SEARCH : ref_mv_idx;
2310*77c1e3ccSAndroid Build Coastguard Worker 
2311*77c1e3ccSAndroid Build Coastguard Worker   // Thresholds used for pruning:
2312*77c1e3ccSAndroid Build Coastguard Worker   // Lower value indicates aggressive pruning and higher value indicates
2313*77c1e3ccSAndroid Build Coastguard Worker   // conservative pruning which is set based on ref_mv_idx and speed feature.
2314*77c1e3ccSAndroid Build Coastguard Worker   // 'prune_index' 0, 1, 2 corresponds to ref_mv indices 0, 1 and 2. prune_index
2315*77c1e3ccSAndroid Build Coastguard Worker   // 3 corresponds to GLOBALMV/GLOBAL_GLOBALMV
2316*77c1e3ccSAndroid Build Coastguard Worker   static const int tpl_inter_mode_prune_mul_factor[3][MAX_REF_MV_SEARCH + 1] = {
2317*77c1e3ccSAndroid Build Coastguard Worker     { 6, 6, 6, 4 }, { 6, 4, 4, 4 }, { 5, 4, 4, 4 }
2318*77c1e3ccSAndroid Build Coastguard Worker   };
2319*77c1e3ccSAndroid Build Coastguard Worker 
2320*77c1e3ccSAndroid Build Coastguard Worker   const int is_comp_pred = (refs[1] > INTRA_FRAME);
2321*77c1e3ccSAndroid Build Coastguard Worker   if (!is_comp_pred) {
2322*77c1e3ccSAndroid Build Coastguard Worker     cur_inter_cost = inter_cost_info_from_tpl->ref_inter_cost[refs[0] - 1];
2323*77c1e3ccSAndroid Build Coastguard Worker   } else {
2324*77c1e3ccSAndroid Build Coastguard Worker     const int64_t inter_cost_ref0 =
2325*77c1e3ccSAndroid Build Coastguard Worker         inter_cost_info_from_tpl->ref_inter_cost[refs[0] - 1];
2326*77c1e3ccSAndroid Build Coastguard Worker     const int64_t inter_cost_ref1 =
2327*77c1e3ccSAndroid Build Coastguard Worker         inter_cost_info_from_tpl->ref_inter_cost[refs[1] - 1];
2328*77c1e3ccSAndroid Build Coastguard Worker     // Choose maximum inter_cost among inter_cost_ref0 and inter_cost_ref1 for
2329*77c1e3ccSAndroid Build Coastguard Worker     // more aggressive pruning
2330*77c1e3ccSAndroid Build Coastguard Worker     cur_inter_cost = AOMMAX(inter_cost_ref0, inter_cost_ref1);
2331*77c1e3ccSAndroid Build Coastguard Worker   }
2332*77c1e3ccSAndroid Build Coastguard Worker 
2333*77c1e3ccSAndroid Build Coastguard Worker   // Prune the mode if cur_inter_cost is greater than threshold times
2334*77c1e3ccSAndroid Build Coastguard Worker   // best_inter_cost
2335*77c1e3ccSAndroid Build Coastguard Worker   if (cur_inter_cost >
2336*77c1e3ccSAndroid Build Coastguard Worker       ((tpl_inter_mode_prune_mul_factor[prune_level][prune_index] *
2337*77c1e3ccSAndroid Build Coastguard Worker         best_inter_cost) >>
2338*77c1e3ccSAndroid Build Coastguard Worker        2))
2339*77c1e3ccSAndroid Build Coastguard Worker     return 1;
2340*77c1e3ccSAndroid Build Coastguard Worker   return 0;
2341*77c1e3ccSAndroid Build Coastguard Worker }
2342*77c1e3ccSAndroid Build Coastguard Worker 
2343*77c1e3ccSAndroid Build Coastguard Worker /*!\brief High level function to select parameters for compound mode.
2344*77c1e3ccSAndroid Build Coastguard Worker  *
2345*77c1e3ccSAndroid Build Coastguard Worker  * \ingroup inter_mode_search
2346*77c1e3ccSAndroid Build Coastguard Worker  * The main search functionality is done in the call to av1_compound_type_rd().
2347*77c1e3ccSAndroid Build Coastguard Worker  *
2348*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     cpi               Top-level encoder structure.
2349*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     x                 Pointer to struct holding all the data for
2350*77c1e3ccSAndroid Build Coastguard Worker  *                                  the current macroblock.
2351*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     args              HandleInterModeArgs struct holding
2352*77c1e3ccSAndroid Build Coastguard Worker  *                                  miscellaneous arguments for inter mode
2353*77c1e3ccSAndroid Build Coastguard Worker  *                                  search. See the documentation for this
2354*77c1e3ccSAndroid Build Coastguard Worker  *                                  struct for a description of each member.
2355*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     ref_best_rd       Best RD found so far for this block.
2356*77c1e3ccSAndroid Build Coastguard Worker  *                                  It is used for early termination of this
2357*77c1e3ccSAndroid Build Coastguard Worker  *                                  search if the RD exceeds this value.
2358*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] cur_mv            Current motion vector.
2359*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     bsize             Current block size.
2360*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] compmode_interinter_cost  RD of the selected interinter
2361*77c1e3ccSAndroid Build Coastguard Worker                                     compound mode.
2362*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] rd_buffers        CompoundTypeRdBuffers struct to hold all
2363*77c1e3ccSAndroid Build Coastguard Worker  *                                  allocated buffers for the compound
2364*77c1e3ccSAndroid Build Coastguard Worker  *                                  predictors and masks in the compound type
2365*77c1e3ccSAndroid Build Coastguard Worker  *                                  search.
2366*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] orig_dst          A prediction buffer to hold a computed
2367*77c1e3ccSAndroid Build Coastguard Worker  *                                  prediction. This will eventually hold the
2368*77c1e3ccSAndroid Build Coastguard Worker  *                                  final prediction, and the tmp_dst info will
2369*77c1e3ccSAndroid Build Coastguard Worker  *                                  be copied here.
2370*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     tmp_dst           A temporary prediction buffer to hold a
2371*77c1e3ccSAndroid Build Coastguard Worker  *                                  computed prediction.
2372*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] rate_mv           The rate associated with the motion vectors.
2373*77c1e3ccSAndroid Build Coastguard Worker  *                                  This will be modified if a motion search is
2374*77c1e3ccSAndroid Build Coastguard Worker  *                                  done in the motion mode search.
2375*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] rd_stats          Struct to keep track of the overall RD
2376*77c1e3ccSAndroid Build Coastguard Worker  *                                  information.
2377*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] skip_rd           An array of length 2 where skip_rd[0] is the
2378*77c1e3ccSAndroid Build Coastguard Worker  *                                  best total RD for a skip mode so far, and
2379*77c1e3ccSAndroid Build Coastguard Worker  *                                  skip_rd[1] is the best RD for a skip mode so
2380*77c1e3ccSAndroid Build Coastguard Worker  *                                  far in luma. This is used as a speed feature
2381*77c1e3ccSAndroid Build Coastguard Worker  *                                  to skip the transform search if the computed
2382*77c1e3ccSAndroid Build Coastguard Worker  *                                  skip RD for the current mode is not better
2383*77c1e3ccSAndroid Build Coastguard Worker  *                                  than the best skip_rd so far.
2384*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] skip_build_pred   Indicates whether or not to build the inter
2385*77c1e3ccSAndroid Build Coastguard Worker  *                                  predictor. If this is 0, the inter predictor
2386*77c1e3ccSAndroid Build Coastguard Worker  *                                  has already been built and thus we can avoid
2387*77c1e3ccSAndroid Build Coastguard Worker  *                                  repeating computation.
2388*77c1e3ccSAndroid Build Coastguard Worker  * \return Returns 1 if this mode is worse than one already seen and 0 if it is
2389*77c1e3ccSAndroid Build Coastguard Worker  * a viable candidate.
2390*77c1e3ccSAndroid Build Coastguard Worker  */
process_compound_inter_mode(AV1_COMP * const cpi,MACROBLOCK * x,HandleInterModeArgs * args,int64_t ref_best_rd,int_mv * cur_mv,BLOCK_SIZE bsize,int * compmode_interinter_cost,const CompoundTypeRdBuffers * rd_buffers,const BUFFER_SET * orig_dst,const BUFFER_SET * tmp_dst,int * rate_mv,RD_STATS * rd_stats,int64_t * skip_rd,int * skip_build_pred)2391*77c1e3ccSAndroid Build Coastguard Worker static int process_compound_inter_mode(
2392*77c1e3ccSAndroid Build Coastguard Worker     AV1_COMP *const cpi, MACROBLOCK *x, HandleInterModeArgs *args,
2393*77c1e3ccSAndroid Build Coastguard Worker     int64_t ref_best_rd, int_mv *cur_mv, BLOCK_SIZE bsize,
2394*77c1e3ccSAndroid Build Coastguard Worker     int *compmode_interinter_cost, const CompoundTypeRdBuffers *rd_buffers,
2395*77c1e3ccSAndroid Build Coastguard Worker     const BUFFER_SET *orig_dst, const BUFFER_SET *tmp_dst, int *rate_mv,
2396*77c1e3ccSAndroid Build Coastguard Worker     RD_STATS *rd_stats, int64_t *skip_rd, int *skip_build_pred) {
2397*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *xd = &x->e_mbd;
2398*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *mbmi = xd->mi[0];
2399*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *cm = &cpi->common;
2400*77c1e3ccSAndroid Build Coastguard Worker   const int masked_compound_used = is_any_masked_compound_used(bsize) &&
2401*77c1e3ccSAndroid Build Coastguard Worker                                    cm->seq_params->enable_masked_compound;
2402*77c1e3ccSAndroid Build Coastguard Worker   int mode_search_mask = (1 << COMPOUND_AVERAGE) | (1 << COMPOUND_DISTWTD) |
2403*77c1e3ccSAndroid Build Coastguard Worker                          (1 << COMPOUND_WEDGE) | (1 << COMPOUND_DIFFWTD);
2404*77c1e3ccSAndroid Build Coastguard Worker 
2405*77c1e3ccSAndroid Build Coastguard Worker   const int num_planes = av1_num_planes(cm);
2406*77c1e3ccSAndroid Build Coastguard Worker   const int mi_row = xd->mi_row;
2407*77c1e3ccSAndroid Build Coastguard Worker   const int mi_col = xd->mi_col;
2408*77c1e3ccSAndroid Build Coastguard Worker   int is_luma_interp_done = 0;
2409*77c1e3ccSAndroid Build Coastguard Worker   set_default_interp_filters(mbmi, cm->features.interp_filter);
2410*77c1e3ccSAndroid Build Coastguard Worker 
2411*77c1e3ccSAndroid Build Coastguard Worker   int64_t best_rd_compound;
2412*77c1e3ccSAndroid Build Coastguard Worker   int64_t rd_thresh;
2413*77c1e3ccSAndroid Build Coastguard Worker   const int comp_type_rd_shift = COMP_TYPE_RD_THRESH_SHIFT;
2414*77c1e3ccSAndroid Build Coastguard Worker   const int comp_type_rd_scale = COMP_TYPE_RD_THRESH_SCALE;
2415*77c1e3ccSAndroid Build Coastguard Worker   rd_thresh = get_rd_thresh_from_best_rd(ref_best_rd, (1 << comp_type_rd_shift),
2416*77c1e3ccSAndroid Build Coastguard Worker                                          comp_type_rd_scale);
2417*77c1e3ccSAndroid Build Coastguard Worker   // Select compound type and any parameters related to that type
2418*77c1e3ccSAndroid Build Coastguard Worker   // (for example, the mask parameters if it is a masked mode) and compute
2419*77c1e3ccSAndroid Build Coastguard Worker   // the RD
2420*77c1e3ccSAndroid Build Coastguard Worker   *compmode_interinter_cost = av1_compound_type_rd(
2421*77c1e3ccSAndroid Build Coastguard Worker       cpi, x, args, bsize, cur_mv, mode_search_mask, masked_compound_used,
2422*77c1e3ccSAndroid Build Coastguard Worker       orig_dst, tmp_dst, rd_buffers, rate_mv, &best_rd_compound, rd_stats,
2423*77c1e3ccSAndroid Build Coastguard Worker       ref_best_rd, skip_rd[1], &is_luma_interp_done, rd_thresh);
2424*77c1e3ccSAndroid Build Coastguard Worker   if (ref_best_rd < INT64_MAX &&
2425*77c1e3ccSAndroid Build Coastguard Worker       (best_rd_compound >> comp_type_rd_shift) * comp_type_rd_scale >
2426*77c1e3ccSAndroid Build Coastguard Worker           ref_best_rd) {
2427*77c1e3ccSAndroid Build Coastguard Worker     restore_dst_buf(xd, *orig_dst, num_planes);
2428*77c1e3ccSAndroid Build Coastguard Worker     return 1;
2429*77c1e3ccSAndroid Build Coastguard Worker   }
2430*77c1e3ccSAndroid Build Coastguard Worker 
2431*77c1e3ccSAndroid Build Coastguard Worker   // Build only uv predictor for COMPOUND_AVERAGE.
2432*77c1e3ccSAndroid Build Coastguard Worker   // Note there is no need to call av1_enc_build_inter_predictor
2433*77c1e3ccSAndroid Build Coastguard Worker   // for luma if COMPOUND_AVERAGE is selected because it is the first
2434*77c1e3ccSAndroid Build Coastguard Worker   // candidate in av1_compound_type_rd, which means it used the dst_buf
2435*77c1e3ccSAndroid Build Coastguard Worker   // rather than the tmp_buf.
2436*77c1e3ccSAndroid Build Coastguard Worker   if (mbmi->interinter_comp.type == COMPOUND_AVERAGE && is_luma_interp_done) {
2437*77c1e3ccSAndroid Build Coastguard Worker     if (num_planes > 1) {
2438*77c1e3ccSAndroid Build Coastguard Worker       av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize,
2439*77c1e3ccSAndroid Build Coastguard Worker                                     AOM_PLANE_U, num_planes - 1);
2440*77c1e3ccSAndroid Build Coastguard Worker     }
2441*77c1e3ccSAndroid Build Coastguard Worker     *skip_build_pred = 1;
2442*77c1e3ccSAndroid Build Coastguard Worker   }
2443*77c1e3ccSAndroid Build Coastguard Worker   return 0;
2444*77c1e3ccSAndroid Build Coastguard Worker }
2445*77c1e3ccSAndroid Build Coastguard Worker 
2446*77c1e3ccSAndroid Build Coastguard Worker // Speed feature to prune out MVs that are similar to previous MVs if they
2447*77c1e3ccSAndroid Build Coastguard Worker // don't achieve the best RD advantage.
prune_ref_mv_idx_search(int ref_mv_idx,int best_ref_mv_idx,int_mv save_mv[MAX_REF_MV_SEARCH-1][2],MB_MODE_INFO * mbmi,int pruning_factor)2448*77c1e3ccSAndroid Build Coastguard Worker static int prune_ref_mv_idx_search(int ref_mv_idx, int best_ref_mv_idx,
2449*77c1e3ccSAndroid Build Coastguard Worker                                    int_mv save_mv[MAX_REF_MV_SEARCH - 1][2],
2450*77c1e3ccSAndroid Build Coastguard Worker                                    MB_MODE_INFO *mbmi, int pruning_factor) {
2451*77c1e3ccSAndroid Build Coastguard Worker   int i;
2452*77c1e3ccSAndroid Build Coastguard Worker   const int is_comp_pred = has_second_ref(mbmi);
2453*77c1e3ccSAndroid Build Coastguard Worker   const int thr = (1 + is_comp_pred) << (pruning_factor + 1);
2454*77c1e3ccSAndroid Build Coastguard Worker 
2455*77c1e3ccSAndroid Build Coastguard Worker   // Skip the evaluation if an MV match is found.
2456*77c1e3ccSAndroid Build Coastguard Worker   if (ref_mv_idx > 0) {
2457*77c1e3ccSAndroid Build Coastguard Worker     for (int idx = 0; idx < ref_mv_idx; ++idx) {
2458*77c1e3ccSAndroid Build Coastguard Worker       if (save_mv[idx][0].as_int == INVALID_MV) continue;
2459*77c1e3ccSAndroid Build Coastguard Worker 
2460*77c1e3ccSAndroid Build Coastguard Worker       int mv_diff = 0;
2461*77c1e3ccSAndroid Build Coastguard Worker       for (i = 0; i < 1 + is_comp_pred; ++i) {
2462*77c1e3ccSAndroid Build Coastguard Worker         mv_diff += abs(save_mv[idx][i].as_mv.row - mbmi->mv[i].as_mv.row) +
2463*77c1e3ccSAndroid Build Coastguard Worker                    abs(save_mv[idx][i].as_mv.col - mbmi->mv[i].as_mv.col);
2464*77c1e3ccSAndroid Build Coastguard Worker       }
2465*77c1e3ccSAndroid Build Coastguard Worker 
2466*77c1e3ccSAndroid Build Coastguard Worker       // If this mode is not the best one, and current MV is similar to
2467*77c1e3ccSAndroid Build Coastguard Worker       // previous stored MV, terminate this ref_mv_idx evaluation.
2468*77c1e3ccSAndroid Build Coastguard Worker       if (best_ref_mv_idx == -1 && mv_diff <= thr) return 1;
2469*77c1e3ccSAndroid Build Coastguard Worker     }
2470*77c1e3ccSAndroid Build Coastguard Worker   }
2471*77c1e3ccSAndroid Build Coastguard Worker 
2472*77c1e3ccSAndroid Build Coastguard Worker   if (ref_mv_idx < MAX_REF_MV_SEARCH - 1) {
2473*77c1e3ccSAndroid Build Coastguard Worker     for (i = 0; i < is_comp_pred + 1; ++i)
2474*77c1e3ccSAndroid Build Coastguard Worker       save_mv[ref_mv_idx][i].as_int = mbmi->mv[i].as_int;
2475*77c1e3ccSAndroid Build Coastguard Worker   }
2476*77c1e3ccSAndroid Build Coastguard Worker 
2477*77c1e3ccSAndroid Build Coastguard Worker   return 0;
2478*77c1e3ccSAndroid Build Coastguard Worker }
2479*77c1e3ccSAndroid Build Coastguard Worker 
2480*77c1e3ccSAndroid Build Coastguard Worker /*!\brief Prunes ZeroMV Search Using Best NEWMV's SSE
2481*77c1e3ccSAndroid Build Coastguard Worker  *
2482*77c1e3ccSAndroid Build Coastguard Worker  * \ingroup inter_mode_search
2483*77c1e3ccSAndroid Build Coastguard Worker  *
2484*77c1e3ccSAndroid Build Coastguard Worker  * Compares the sse of zero mv and the best sse found in single new_mv. If the
2485*77c1e3ccSAndroid Build Coastguard Worker  * sse of the zero_mv is higher, returns 1 to signal zero_mv can be skipped.
2486*77c1e3ccSAndroid Build Coastguard Worker  * Else returns 0.
2487*77c1e3ccSAndroid Build Coastguard Worker  *
2488*77c1e3ccSAndroid Build Coastguard Worker  * Note that the sse of here comes from single_motion_search. So it is
2489*77c1e3ccSAndroid Build Coastguard Worker  * interpolated with the filter in motion search, not the actual interpolation
2490*77c1e3ccSAndroid Build Coastguard Worker  * filter used in encoding.
2491*77c1e3ccSAndroid Build Coastguard Worker  *
2492*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     fn_ptr            A table of function pointers to compute SSE.
2493*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     x                 Pointer to struct holding all the data for
2494*77c1e3ccSAndroid Build Coastguard Worker  *                                  the current macroblock.
2495*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     bsize             The current block_size.
2496*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     args              The args to handle_inter_mode, used to track
2497*77c1e3ccSAndroid Build Coastguard Worker  *                                  the best SSE.
2498*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]    prune_zero_mv_with_sse  The argument holds speed feature
2499*77c1e3ccSAndroid Build Coastguard Worker  *                                       prune_zero_mv_with_sse value
2500*77c1e3ccSAndroid Build Coastguard Worker  * \return Returns 1 if zero_mv is pruned, 0 otherwise.
2501*77c1e3ccSAndroid Build Coastguard Worker  */
prune_zero_mv_with_sse(const aom_variance_fn_ptr_t * fn_ptr,const MACROBLOCK * x,BLOCK_SIZE bsize,const HandleInterModeArgs * args,int prune_zero_mv_with_sse)2502*77c1e3ccSAndroid Build Coastguard Worker static inline int prune_zero_mv_with_sse(const aom_variance_fn_ptr_t *fn_ptr,
2503*77c1e3ccSAndroid Build Coastguard Worker                                          const MACROBLOCK *x, BLOCK_SIZE bsize,
2504*77c1e3ccSAndroid Build Coastguard Worker                                          const HandleInterModeArgs *args,
2505*77c1e3ccSAndroid Build Coastguard Worker                                          int prune_zero_mv_with_sse) {
2506*77c1e3ccSAndroid Build Coastguard Worker   const MACROBLOCKD *xd = &x->e_mbd;
2507*77c1e3ccSAndroid Build Coastguard Worker   const MB_MODE_INFO *mbmi = xd->mi[0];
2508*77c1e3ccSAndroid Build Coastguard Worker 
2509*77c1e3ccSAndroid Build Coastguard Worker   const int is_comp_pred = has_second_ref(mbmi);
2510*77c1e3ccSAndroid Build Coastguard Worker   const MV_REFERENCE_FRAME *refs = mbmi->ref_frame;
2511*77c1e3ccSAndroid Build Coastguard Worker 
2512*77c1e3ccSAndroid Build Coastguard Worker   for (int idx = 0; idx < 1 + is_comp_pred; idx++) {
2513*77c1e3ccSAndroid Build Coastguard Worker     if (xd->global_motion[refs[idx]].wmtype != IDENTITY) {
2514*77c1e3ccSAndroid Build Coastguard Worker       // Pruning logic only works for IDENTITY type models
2515*77c1e3ccSAndroid Build Coastguard Worker       // Note: In theory we could apply similar logic for TRANSLATION
2516*77c1e3ccSAndroid Build Coastguard Worker       // type models, but we do not code these due to a spec bug
2517*77c1e3ccSAndroid Build Coastguard Worker       // (see comments in gm_get_motion_vector() in av1/common/mv.h)
2518*77c1e3ccSAndroid Build Coastguard Worker       assert(xd->global_motion[refs[idx]].wmtype != TRANSLATION);
2519*77c1e3ccSAndroid Build Coastguard Worker       return 0;
2520*77c1e3ccSAndroid Build Coastguard Worker     }
2521*77c1e3ccSAndroid Build Coastguard Worker 
2522*77c1e3ccSAndroid Build Coastguard Worker     // Don't prune if we have invalid data
2523*77c1e3ccSAndroid Build Coastguard Worker     assert(mbmi->mv[idx].as_int == 0);
2524*77c1e3ccSAndroid Build Coastguard Worker     if (args->best_single_sse_in_refs[refs[idx]] == INT32_MAX) {
2525*77c1e3ccSAndroid Build Coastguard Worker       return 0;
2526*77c1e3ccSAndroid Build Coastguard Worker     }
2527*77c1e3ccSAndroid Build Coastguard Worker   }
2528*77c1e3ccSAndroid Build Coastguard Worker 
2529*77c1e3ccSAndroid Build Coastguard Worker   // Sum up the sse of ZEROMV and best NEWMV
2530*77c1e3ccSAndroid Build Coastguard Worker   unsigned int this_sse_sum = 0;
2531*77c1e3ccSAndroid Build Coastguard Worker   unsigned int best_sse_sum = 0;
2532*77c1e3ccSAndroid Build Coastguard Worker   for (int idx = 0; idx < 1 + is_comp_pred; idx++) {
2533*77c1e3ccSAndroid Build Coastguard Worker     const struct macroblock_plane *const p = &x->plane[AOM_PLANE_Y];
2534*77c1e3ccSAndroid Build Coastguard Worker     const struct macroblockd_plane *pd = xd->plane;
2535*77c1e3ccSAndroid Build Coastguard Worker     const struct buf_2d *src_buf = &p->src;
2536*77c1e3ccSAndroid Build Coastguard Worker     const struct buf_2d *ref_buf = &pd->pre[idx];
2537*77c1e3ccSAndroid Build Coastguard Worker     const uint8_t *src = src_buf->buf;
2538*77c1e3ccSAndroid Build Coastguard Worker     const uint8_t *ref = ref_buf->buf;
2539*77c1e3ccSAndroid Build Coastguard Worker     const int src_stride = src_buf->stride;
2540*77c1e3ccSAndroid Build Coastguard Worker     const int ref_stride = ref_buf->stride;
2541*77c1e3ccSAndroid Build Coastguard Worker 
2542*77c1e3ccSAndroid Build Coastguard Worker     unsigned int this_sse;
2543*77c1e3ccSAndroid Build Coastguard Worker     fn_ptr[bsize].vf(ref, ref_stride, src, src_stride, &this_sse);
2544*77c1e3ccSAndroid Build Coastguard Worker     this_sse_sum += this_sse;
2545*77c1e3ccSAndroid Build Coastguard Worker 
2546*77c1e3ccSAndroid Build Coastguard Worker     const unsigned int best_sse = args->best_single_sse_in_refs[refs[idx]];
2547*77c1e3ccSAndroid Build Coastguard Worker     best_sse_sum += best_sse;
2548*77c1e3ccSAndroid Build Coastguard Worker   }
2549*77c1e3ccSAndroid Build Coastguard Worker 
2550*77c1e3ccSAndroid Build Coastguard Worker   const double mul = prune_zero_mv_with_sse > 1 ? 1.00 : 1.25;
2551*77c1e3ccSAndroid Build Coastguard Worker   if ((double)this_sse_sum > (mul * (double)best_sse_sum)) {
2552*77c1e3ccSAndroid Build Coastguard Worker     return 1;
2553*77c1e3ccSAndroid Build Coastguard Worker   }
2554*77c1e3ccSAndroid Build Coastguard Worker 
2555*77c1e3ccSAndroid Build Coastguard Worker   return 0;
2556*77c1e3ccSAndroid Build Coastguard Worker }
2557*77c1e3ccSAndroid Build Coastguard Worker 
2558*77c1e3ccSAndroid Build Coastguard Worker /*!\brief Searches for interpolation filter in realtime mode during winner eval
2559*77c1e3ccSAndroid Build Coastguard Worker  *
2560*77c1e3ccSAndroid Build Coastguard Worker  * \ingroup inter_mode_search
2561*77c1e3ccSAndroid Build Coastguard Worker  *
2562*77c1e3ccSAndroid Build Coastguard Worker  * Does a simple interpolation filter search during winner mode evaluation. This
2563*77c1e3ccSAndroid Build Coastguard Worker  * is currently only used by realtime mode as \ref
2564*77c1e3ccSAndroid Build Coastguard Worker  * av1_interpolation_filter_search is not called during realtime encoding.
2565*77c1e3ccSAndroid Build Coastguard Worker  *
2566*77c1e3ccSAndroid Build Coastguard Worker  * This function only searches over two possible filters. EIGHTTAP_REGULAR is
2567*77c1e3ccSAndroid Build Coastguard Worker  * always search. For lowres clips (<= 240p), MULTITAP_SHARP is also search. For
2568*77c1e3ccSAndroid Build Coastguard Worker  * higher  res slips (>240p), EIGHTTAP_SMOOTH is also searched.
2569*77c1e3ccSAndroid Build Coastguard Worker  *  *
2570*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     cpi               Pointer to the compressor. Used for feature
2571*77c1e3ccSAndroid Build Coastguard Worker  *                                  flags.
2572*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] x                 Pointer to macroblock. This is primarily
2573*77c1e3ccSAndroid Build Coastguard Worker  *                                  used to access the buffers.
2574*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     mi_row            The current row in mi unit (4X4 pixels).
2575*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     mi_col            The current col in mi unit (4X4 pixels).
2576*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     bsize             The current block_size.
2577*77c1e3ccSAndroid Build Coastguard Worker  * \return Returns true if a predictor is built in xd->dst, false otherwise.
2578*77c1e3ccSAndroid Build Coastguard Worker  */
fast_interp_search(const AV1_COMP * cpi,MACROBLOCK * x,int mi_row,int mi_col,BLOCK_SIZE bsize)2579*77c1e3ccSAndroid Build Coastguard Worker static inline bool fast_interp_search(const AV1_COMP *cpi, MACROBLOCK *x,
2580*77c1e3ccSAndroid Build Coastguard Worker                                       int mi_row, int mi_col,
2581*77c1e3ccSAndroid Build Coastguard Worker                                       BLOCK_SIZE bsize) {
2582*77c1e3ccSAndroid Build Coastguard Worker   static const InterpFilters filters_ref_set[3] = {
2583*77c1e3ccSAndroid Build Coastguard Worker     { EIGHTTAP_REGULAR, EIGHTTAP_REGULAR },
2584*77c1e3ccSAndroid Build Coastguard Worker     { EIGHTTAP_SMOOTH, EIGHTTAP_SMOOTH },
2585*77c1e3ccSAndroid Build Coastguard Worker     { MULTITAP_SHARP, MULTITAP_SHARP }
2586*77c1e3ccSAndroid Build Coastguard Worker   };
2587*77c1e3ccSAndroid Build Coastguard Worker 
2588*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
2589*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *const xd = &x->e_mbd;
2590*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *const mi = xd->mi[0];
2591*77c1e3ccSAndroid Build Coastguard Worker   int64_t best_cost = INT64_MAX;
2592*77c1e3ccSAndroid Build Coastguard Worker   int best_filter_index = -1;
2593*77c1e3ccSAndroid Build Coastguard Worker   // dst_bufs[0] sores the new predictor, and dist_bifs[1] stores the best
2594*77c1e3ccSAndroid Build Coastguard Worker   const int num_planes = av1_num_planes(cm);
2595*77c1e3ccSAndroid Build Coastguard Worker   const int is_240p_or_lesser = AOMMIN(cm->width, cm->height) <= 240;
2596*77c1e3ccSAndroid Build Coastguard Worker   assert(is_inter_mode(mi->mode));
2597*77c1e3ccSAndroid Build Coastguard Worker   assert(mi->motion_mode == SIMPLE_TRANSLATION);
2598*77c1e3ccSAndroid Build Coastguard Worker   assert(!is_inter_compound_mode(mi->mode));
2599*77c1e3ccSAndroid Build Coastguard Worker 
2600*77c1e3ccSAndroid Build Coastguard Worker   if (!av1_is_interp_needed(xd)) {
2601*77c1e3ccSAndroid Build Coastguard Worker     return false;
2602*77c1e3ccSAndroid Build Coastguard Worker   }
2603*77c1e3ccSAndroid Build Coastguard Worker 
2604*77c1e3ccSAndroid Build Coastguard Worker   struct macroblockd_plane *pd = xd->plane;
2605*77c1e3ccSAndroid Build Coastguard Worker   const BUFFER_SET orig_dst = {
2606*77c1e3ccSAndroid Build Coastguard Worker     { pd[0].dst.buf, pd[1].dst.buf, pd[2].dst.buf },
2607*77c1e3ccSAndroid Build Coastguard Worker     { pd[0].dst.stride, pd[1].dst.stride, pd[2].dst.stride },
2608*77c1e3ccSAndroid Build Coastguard Worker   };
2609*77c1e3ccSAndroid Build Coastguard Worker   uint8_t *const tmp_buf = get_buf_by_bd(xd, x->tmp_pred_bufs[0]);
2610*77c1e3ccSAndroid Build Coastguard Worker   const BUFFER_SET tmp_dst = { { tmp_buf, tmp_buf + 1 * MAX_SB_SQUARE,
2611*77c1e3ccSAndroid Build Coastguard Worker                                  tmp_buf + 2 * MAX_SB_SQUARE },
2612*77c1e3ccSAndroid Build Coastguard Worker                                { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE } };
2613*77c1e3ccSAndroid Build Coastguard Worker   const BUFFER_SET *dst_bufs[2] = { &orig_dst, &tmp_dst };
2614*77c1e3ccSAndroid Build Coastguard Worker 
2615*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < 3; ++i) {
2616*77c1e3ccSAndroid Build Coastguard Worker     if (is_240p_or_lesser) {
2617*77c1e3ccSAndroid Build Coastguard Worker       if (filters_ref_set[i].x_filter == EIGHTTAP_SMOOTH) {
2618*77c1e3ccSAndroid Build Coastguard Worker         continue;
2619*77c1e3ccSAndroid Build Coastguard Worker       }
2620*77c1e3ccSAndroid Build Coastguard Worker     } else {
2621*77c1e3ccSAndroid Build Coastguard Worker       if (filters_ref_set[i].x_filter == MULTITAP_SHARP) {
2622*77c1e3ccSAndroid Build Coastguard Worker         continue;
2623*77c1e3ccSAndroid Build Coastguard Worker       }
2624*77c1e3ccSAndroid Build Coastguard Worker     }
2625*77c1e3ccSAndroid Build Coastguard Worker     int64_t cost;
2626*77c1e3ccSAndroid Build Coastguard Worker     RD_STATS tmp_rd = { 0 };
2627*77c1e3ccSAndroid Build Coastguard Worker 
2628*77c1e3ccSAndroid Build Coastguard Worker     mi->interp_filters.as_filters = filters_ref_set[i];
2629*77c1e3ccSAndroid Build Coastguard Worker     av1_enc_build_inter_predictor_y(xd, mi_row, mi_col);
2630*77c1e3ccSAndroid Build Coastguard Worker 
2631*77c1e3ccSAndroid Build Coastguard Worker     model_rd_sb_fn[cpi->sf.rt_sf.use_simple_rd_model
2632*77c1e3ccSAndroid Build Coastguard Worker                        ? MODELRD_LEGACY
2633*77c1e3ccSAndroid Build Coastguard Worker                        : MODELRD_TYPE_INTERP_FILTER](
2634*77c1e3ccSAndroid Build Coastguard Worker         cpi, bsize, x, xd, AOM_PLANE_Y, AOM_PLANE_Y, &tmp_rd.rate, &tmp_rd.dist,
2635*77c1e3ccSAndroid Build Coastguard Worker         &tmp_rd.skip_txfm, &tmp_rd.sse, NULL, NULL, NULL);
2636*77c1e3ccSAndroid Build Coastguard Worker 
2637*77c1e3ccSAndroid Build Coastguard Worker     tmp_rd.rate += av1_get_switchable_rate(x, xd, cm->features.interp_filter,
2638*77c1e3ccSAndroid Build Coastguard Worker                                            cm->seq_params->enable_dual_filter);
2639*77c1e3ccSAndroid Build Coastguard Worker     cost = RDCOST(x->rdmult, tmp_rd.rate, tmp_rd.dist);
2640*77c1e3ccSAndroid Build Coastguard Worker     if (cost < best_cost) {
2641*77c1e3ccSAndroid Build Coastguard Worker       best_filter_index = i;
2642*77c1e3ccSAndroid Build Coastguard Worker       best_cost = cost;
2643*77c1e3ccSAndroid Build Coastguard Worker       swap_dst_buf(xd, dst_bufs, num_planes);
2644*77c1e3ccSAndroid Build Coastguard Worker     }
2645*77c1e3ccSAndroid Build Coastguard Worker   }
2646*77c1e3ccSAndroid Build Coastguard Worker   assert(best_filter_index >= 0);
2647*77c1e3ccSAndroid Build Coastguard Worker 
2648*77c1e3ccSAndroid Build Coastguard Worker   mi->interp_filters.as_filters = filters_ref_set[best_filter_index];
2649*77c1e3ccSAndroid Build Coastguard Worker 
2650*77c1e3ccSAndroid Build Coastguard Worker   const bool is_best_pred_in_orig = &orig_dst == dst_bufs[1];
2651*77c1e3ccSAndroid Build Coastguard Worker 
2652*77c1e3ccSAndroid Build Coastguard Worker   if (is_best_pred_in_orig) {
2653*77c1e3ccSAndroid Build Coastguard Worker     swap_dst_buf(xd, dst_bufs, num_planes);
2654*77c1e3ccSAndroid Build Coastguard Worker   } else {
2655*77c1e3ccSAndroid Build Coastguard Worker     // Note that xd->pd's bufers are kept in sync with dst_bufs[0]. So if
2656*77c1e3ccSAndroid Build Coastguard Worker     // is_best_pred_in_orig is false, that means the current buffer is the
2657*77c1e3ccSAndroid Build Coastguard Worker     // original one.
2658*77c1e3ccSAndroid Build Coastguard Worker     assert(&orig_dst == dst_bufs[0]);
2659*77c1e3ccSAndroid Build Coastguard Worker     assert(xd->plane[AOM_PLANE_Y].dst.buf == orig_dst.plane[AOM_PLANE_Y]);
2660*77c1e3ccSAndroid Build Coastguard Worker     const int width = block_size_wide[bsize];
2661*77c1e3ccSAndroid Build Coastguard Worker     const int height = block_size_high[bsize];
2662*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_AV1_HIGHBITDEPTH
2663*77c1e3ccSAndroid Build Coastguard Worker     const bool is_hbd = is_cur_buf_hbd(xd);
2664*77c1e3ccSAndroid Build Coastguard Worker     if (is_hbd) {
2665*77c1e3ccSAndroid Build Coastguard Worker       aom_highbd_convolve_copy(CONVERT_TO_SHORTPTR(tmp_dst.plane[AOM_PLANE_Y]),
2666*77c1e3ccSAndroid Build Coastguard Worker                                tmp_dst.stride[AOM_PLANE_Y],
2667*77c1e3ccSAndroid Build Coastguard Worker                                CONVERT_TO_SHORTPTR(orig_dst.plane[AOM_PLANE_Y]),
2668*77c1e3ccSAndroid Build Coastguard Worker                                orig_dst.stride[AOM_PLANE_Y], width, height);
2669*77c1e3ccSAndroid Build Coastguard Worker     } else {
2670*77c1e3ccSAndroid Build Coastguard Worker       aom_convolve_copy(tmp_dst.plane[AOM_PLANE_Y], tmp_dst.stride[AOM_PLANE_Y],
2671*77c1e3ccSAndroid Build Coastguard Worker                         orig_dst.plane[AOM_PLANE_Y],
2672*77c1e3ccSAndroid Build Coastguard Worker                         orig_dst.stride[AOM_PLANE_Y], width, height);
2673*77c1e3ccSAndroid Build Coastguard Worker     }
2674*77c1e3ccSAndroid Build Coastguard Worker #else
2675*77c1e3ccSAndroid Build Coastguard Worker     aom_convolve_copy(tmp_dst.plane[AOM_PLANE_Y], tmp_dst.stride[AOM_PLANE_Y],
2676*77c1e3ccSAndroid Build Coastguard Worker                       orig_dst.plane[AOM_PLANE_Y], orig_dst.stride[AOM_PLANE_Y],
2677*77c1e3ccSAndroid Build Coastguard Worker                       width, height);
2678*77c1e3ccSAndroid Build Coastguard Worker #endif
2679*77c1e3ccSAndroid Build Coastguard Worker   }
2680*77c1e3ccSAndroid Build Coastguard Worker 
2681*77c1e3ccSAndroid Build Coastguard Worker   // Build the YUV predictor.
2682*77c1e3ccSAndroid Build Coastguard Worker   if (num_planes > 1) {
2683*77c1e3ccSAndroid Build Coastguard Worker     av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize,
2684*77c1e3ccSAndroid Build Coastguard Worker                                   AOM_PLANE_U, AOM_PLANE_V);
2685*77c1e3ccSAndroid Build Coastguard Worker   }
2686*77c1e3ccSAndroid Build Coastguard Worker 
2687*77c1e3ccSAndroid Build Coastguard Worker   return true;
2688*77c1e3ccSAndroid Build Coastguard Worker }
2689*77c1e3ccSAndroid Build Coastguard Worker 
2690*77c1e3ccSAndroid Build Coastguard Worker /*!\brief AV1 inter mode RD computation
2691*77c1e3ccSAndroid Build Coastguard Worker  *
2692*77c1e3ccSAndroid Build Coastguard Worker  * \ingroup inter_mode_search
2693*77c1e3ccSAndroid Build Coastguard Worker  * Do the RD search for a given inter mode and compute all information relevant
2694*77c1e3ccSAndroid Build Coastguard Worker  * to the input mode. It will compute the best MV,
2695*77c1e3ccSAndroid Build Coastguard Worker  * compound parameters (if the mode is a compound mode) and interpolation filter
2696*77c1e3ccSAndroid Build Coastguard Worker  * parameters.
2697*77c1e3ccSAndroid Build Coastguard Worker  *
2698*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     cpi               Top-level encoder structure.
2699*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     tile_data         Pointer to struct holding adaptive
2700*77c1e3ccSAndroid Build Coastguard Worker  *                                  data/contexts/models for the tile during
2701*77c1e3ccSAndroid Build Coastguard Worker  *                                  encoding.
2702*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     x                 Pointer to structure holding all the data
2703*77c1e3ccSAndroid Build Coastguard Worker  *                                  for the current macroblock.
2704*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     bsize             Current block size.
2705*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] rd_stats          Struct to keep track of the overall RD
2706*77c1e3ccSAndroid Build Coastguard Worker  *                                  information.
2707*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] rd_stats_y        Struct to keep track of the RD information
2708*77c1e3ccSAndroid Build Coastguard Worker  *                                  for only the Y plane.
2709*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] rd_stats_uv       Struct to keep track of the RD information
2710*77c1e3ccSAndroid Build Coastguard Worker  *                                  for only the UV planes.
2711*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     args              HandleInterModeArgs struct holding
2712*77c1e3ccSAndroid Build Coastguard Worker  *                                  miscellaneous arguments for inter mode
2713*77c1e3ccSAndroid Build Coastguard Worker  *                                  search. See the documentation for this
2714*77c1e3ccSAndroid Build Coastguard Worker  *                                  struct for a description of each member.
2715*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     ref_best_rd       Best RD found so far for this block.
2716*77c1e3ccSAndroid Build Coastguard Worker  *                                  It is used for early termination of this
2717*77c1e3ccSAndroid Build Coastguard Worker  *                                  search if the RD exceeds this value.
2718*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     tmp_buf           Temporary buffer used to hold predictors
2719*77c1e3ccSAndroid Build Coastguard Worker  *                                  built in this search.
2720*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] rd_buffers        CompoundTypeRdBuffers struct to hold all
2721*77c1e3ccSAndroid Build Coastguard Worker  *                                  allocated buffers for the compound
2722*77c1e3ccSAndroid Build Coastguard Worker  *                                  predictors and masks in the compound type
2723*77c1e3ccSAndroid Build Coastguard Worker  *                                  search.
2724*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] best_est_rd       Estimated RD for motion mode search if
2725*77c1e3ccSAndroid Build Coastguard Worker  *                                  do_tx_search (see below) is 0.
2726*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     do_tx_search      Parameter to indicate whether or not to do
2727*77c1e3ccSAndroid Build Coastguard Worker  *                                  a full transform search. This will compute
2728*77c1e3ccSAndroid Build Coastguard Worker  *                                  an estimated RD for the modes without the
2729*77c1e3ccSAndroid Build Coastguard Worker  *                                  transform search and later perform the full
2730*77c1e3ccSAndroid Build Coastguard Worker  *                                  transform search on the best candidates.
2731*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] inter_modes_info  InterModesInfo struct to hold inter mode
2732*77c1e3ccSAndroid Build Coastguard Worker  *                                  information to perform a full transform
2733*77c1e3ccSAndroid Build Coastguard Worker  *                                  search only on winning candidates searched
2734*77c1e3ccSAndroid Build Coastguard Worker  *                                  with an estimate for transform coding RD.
2735*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] motion_mode_cand  A motion_mode_candidate struct to store
2736*77c1e3ccSAndroid Build Coastguard Worker  *                                  motion mode information used in a speed
2737*77c1e3ccSAndroid Build Coastguard Worker  *                                  feature to search motion modes other than
2738*77c1e3ccSAndroid Build Coastguard Worker  *                                  SIMPLE_TRANSLATION only on winning
2739*77c1e3ccSAndroid Build Coastguard Worker  *                                  candidates.
2740*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] skip_rd           A length 2 array, where skip_rd[0] is the
2741*77c1e3ccSAndroid Build Coastguard Worker  *                                  best total RD for a skip mode so far, and
2742*77c1e3ccSAndroid Build Coastguard Worker  *                                  skip_rd[1] is the best RD for a skip mode so
2743*77c1e3ccSAndroid Build Coastguard Worker  *                                  far in luma. This is used as a speed feature
2744*77c1e3ccSAndroid Build Coastguard Worker  *                                  to skip the transform search if the computed
2745*77c1e3ccSAndroid Build Coastguard Worker  *                                  skip RD for the current mode is not better
2746*77c1e3ccSAndroid Build Coastguard Worker  *                                  than the best skip_rd so far.
2747*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     inter_cost_info_from_tpl A PruneInfoFromTpl struct used to
2748*77c1e3ccSAndroid Build Coastguard Worker  *                                         narrow down the search based on data
2749*77c1e3ccSAndroid Build Coastguard Worker  *                                         collected in the TPL model.
2750*77c1e3ccSAndroid Build Coastguard Worker  * \param[out]    yrd               Stores the rdcost corresponding to encoding
2751*77c1e3ccSAndroid Build Coastguard Worker  *                                  the luma plane.
2752*77c1e3ccSAndroid Build Coastguard Worker  *
2753*77c1e3ccSAndroid Build Coastguard Worker  * \return The RD cost for the mode being searched.
2754*77c1e3ccSAndroid Build Coastguard Worker  */
handle_inter_mode(AV1_COMP * const cpi,TileDataEnc * tile_data,MACROBLOCK * x,BLOCK_SIZE bsize,RD_STATS * rd_stats,RD_STATS * rd_stats_y,RD_STATS * rd_stats_uv,HandleInterModeArgs * args,int64_t ref_best_rd,uint8_t * const tmp_buf,const CompoundTypeRdBuffers * rd_buffers,int64_t * best_est_rd,const int do_tx_search,InterModesInfo * inter_modes_info,motion_mode_candidate * motion_mode_cand,int64_t * skip_rd,PruneInfoFromTpl * inter_cost_info_from_tpl,int64_t * yrd)2755*77c1e3ccSAndroid Build Coastguard Worker static int64_t handle_inter_mode(
2756*77c1e3ccSAndroid Build Coastguard Worker     AV1_COMP *const cpi, TileDataEnc *tile_data, MACROBLOCK *x,
2757*77c1e3ccSAndroid Build Coastguard Worker     BLOCK_SIZE bsize, RD_STATS *rd_stats, RD_STATS *rd_stats_y,
2758*77c1e3ccSAndroid Build Coastguard Worker     RD_STATS *rd_stats_uv, HandleInterModeArgs *args, int64_t ref_best_rd,
2759*77c1e3ccSAndroid Build Coastguard Worker     uint8_t *const tmp_buf, const CompoundTypeRdBuffers *rd_buffers,
2760*77c1e3ccSAndroid Build Coastguard Worker     int64_t *best_est_rd, const int do_tx_search,
2761*77c1e3ccSAndroid Build Coastguard Worker     InterModesInfo *inter_modes_info, motion_mode_candidate *motion_mode_cand,
2762*77c1e3ccSAndroid Build Coastguard Worker     int64_t *skip_rd, PruneInfoFromTpl *inter_cost_info_from_tpl,
2763*77c1e3ccSAndroid Build Coastguard Worker     int64_t *yrd) {
2764*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *cm = &cpi->common;
2765*77c1e3ccSAndroid Build Coastguard Worker   const int num_planes = av1_num_planes(cm);
2766*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *xd = &x->e_mbd;
2767*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *mbmi = xd->mi[0];
2768*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO_EXT *const mbmi_ext = &x->mbmi_ext;
2769*77c1e3ccSAndroid Build Coastguard Worker   TxfmSearchInfo *txfm_info = &x->txfm_search_info;
2770*77c1e3ccSAndroid Build Coastguard Worker   const int is_comp_pred = has_second_ref(mbmi);
2771*77c1e3ccSAndroid Build Coastguard Worker   const PREDICTION_MODE this_mode = mbmi->mode;
2772*77c1e3ccSAndroid Build Coastguard Worker 
2773*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_REALTIME_ONLY
2774*77c1e3ccSAndroid Build Coastguard Worker   const int prune_modes_based_on_tpl = 0;
2775*77c1e3ccSAndroid Build Coastguard Worker #else   // CONFIG_REALTIME_ONLY
2776*77c1e3ccSAndroid Build Coastguard Worker   const TplParams *const tpl_data = &cpi->ppi->tpl_data;
2777*77c1e3ccSAndroid Build Coastguard Worker   const int prune_modes_based_on_tpl =
2778*77c1e3ccSAndroid Build Coastguard Worker       cpi->sf.inter_sf.prune_inter_modes_based_on_tpl &&
2779*77c1e3ccSAndroid Build Coastguard Worker       av1_tpl_stats_ready(tpl_data, cpi->gf_frame_index);
2780*77c1e3ccSAndroid Build Coastguard Worker #endif  // CONFIG_REALTIME_ONLY
2781*77c1e3ccSAndroid Build Coastguard Worker   int i;
2782*77c1e3ccSAndroid Build Coastguard Worker   // Reference frames for this mode
2783*77c1e3ccSAndroid Build Coastguard Worker   const int refs[2] = { mbmi->ref_frame[0],
2784*77c1e3ccSAndroid Build Coastguard Worker                         (mbmi->ref_frame[1] < 0 ? 0 : mbmi->ref_frame[1]) };
2785*77c1e3ccSAndroid Build Coastguard Worker   int rate_mv = 0;
2786*77c1e3ccSAndroid Build Coastguard Worker   int64_t rd = INT64_MAX;
2787*77c1e3ccSAndroid Build Coastguard Worker   // Do first prediction into the destination buffer. Do the next
2788*77c1e3ccSAndroid Build Coastguard Worker   // prediction into a temporary buffer. Then keep track of which one
2789*77c1e3ccSAndroid Build Coastguard Worker   // of these currently holds the best predictor, and use the other
2790*77c1e3ccSAndroid Build Coastguard Worker   // one for future predictions. In the end, copy from tmp_buf to
2791*77c1e3ccSAndroid Build Coastguard Worker   // dst if necessary.
2792*77c1e3ccSAndroid Build Coastguard Worker   struct macroblockd_plane *pd = xd->plane;
2793*77c1e3ccSAndroid Build Coastguard Worker   const BUFFER_SET orig_dst = {
2794*77c1e3ccSAndroid Build Coastguard Worker     { pd[0].dst.buf, pd[1].dst.buf, pd[2].dst.buf },
2795*77c1e3ccSAndroid Build Coastguard Worker     { pd[0].dst.stride, pd[1].dst.stride, pd[2].dst.stride },
2796*77c1e3ccSAndroid Build Coastguard Worker   };
2797*77c1e3ccSAndroid Build Coastguard Worker   const BUFFER_SET tmp_dst = { { tmp_buf, tmp_buf + 1 * MAX_SB_SQUARE,
2798*77c1e3ccSAndroid Build Coastguard Worker                                  tmp_buf + 2 * MAX_SB_SQUARE },
2799*77c1e3ccSAndroid Build Coastguard Worker                                { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE } };
2800*77c1e3ccSAndroid Build Coastguard Worker 
2801*77c1e3ccSAndroid Build Coastguard Worker   int64_t ret_val = INT64_MAX;
2802*77c1e3ccSAndroid Build Coastguard Worker   const int8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
2803*77c1e3ccSAndroid Build Coastguard Worker   RD_STATS best_rd_stats, best_rd_stats_y, best_rd_stats_uv;
2804*77c1e3ccSAndroid Build Coastguard Worker   int64_t best_rd = INT64_MAX;
2805*77c1e3ccSAndroid Build Coastguard Worker   uint8_t best_blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE];
2806*77c1e3ccSAndroid Build Coastguard Worker   uint8_t best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE];
2807*77c1e3ccSAndroid Build Coastguard Worker   int64_t best_yrd = INT64_MAX;
2808*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO best_mbmi = *mbmi;
2809*77c1e3ccSAndroid Build Coastguard Worker   int best_xskip_txfm = 0;
2810*77c1e3ccSAndroid Build Coastguard Worker   int64_t newmv_ret_val = INT64_MAX;
2811*77c1e3ccSAndroid Build Coastguard Worker   inter_mode_info mode_info[MAX_REF_MV_SEARCH];
2812*77c1e3ccSAndroid Build Coastguard Worker 
2813*77c1e3ccSAndroid Build Coastguard Worker   // Do not prune the mode based on inter cost from tpl if the current ref frame
2814*77c1e3ccSAndroid Build Coastguard Worker   // is the winner ref in neighbouring blocks.
2815*77c1e3ccSAndroid Build Coastguard Worker   int ref_match_found_in_above_nb = 0;
2816*77c1e3ccSAndroid Build Coastguard Worker   int ref_match_found_in_left_nb = 0;
2817*77c1e3ccSAndroid Build Coastguard Worker   if (prune_modes_based_on_tpl) {
2818*77c1e3ccSAndroid Build Coastguard Worker     ref_match_found_in_above_nb =
2819*77c1e3ccSAndroid Build Coastguard Worker         find_ref_match_in_above_nbs(cm->mi_params.mi_cols, xd);
2820*77c1e3ccSAndroid Build Coastguard Worker     ref_match_found_in_left_nb =
2821*77c1e3ccSAndroid Build Coastguard Worker         find_ref_match_in_left_nbs(cm->mi_params.mi_rows, xd);
2822*77c1e3ccSAndroid Build Coastguard Worker   }
2823*77c1e3ccSAndroid Build Coastguard Worker 
2824*77c1e3ccSAndroid Build Coastguard Worker   // First, perform a simple translation search for each of the indices. If
2825*77c1e3ccSAndroid Build Coastguard Worker   // an index performs well, it will be fully searched in the main loop
2826*77c1e3ccSAndroid Build Coastguard Worker   // of this function.
2827*77c1e3ccSAndroid Build Coastguard Worker   const int ref_set = get_drl_refmv_count(x, mbmi->ref_frame, this_mode);
2828*77c1e3ccSAndroid Build Coastguard Worker   // Save MV results from first 2 ref_mv_idx.
2829*77c1e3ccSAndroid Build Coastguard Worker   int_mv save_mv[MAX_REF_MV_SEARCH - 1][2];
2830*77c1e3ccSAndroid Build Coastguard Worker   int best_ref_mv_idx = -1;
2831*77c1e3ccSAndroid Build Coastguard Worker   const int idx_mask =
2832*77c1e3ccSAndroid Build Coastguard Worker       ref_mv_idx_to_search(cpi, x, rd_stats, args, ref_best_rd, bsize, ref_set);
2833*77c1e3ccSAndroid Build Coastguard Worker   const int16_t mode_ctx =
2834*77c1e3ccSAndroid Build Coastguard Worker       av1_mode_context_analyzer(mbmi_ext->mode_context, mbmi->ref_frame);
2835*77c1e3ccSAndroid Build Coastguard Worker   const ModeCosts *mode_costs = &x->mode_costs;
2836*77c1e3ccSAndroid Build Coastguard Worker   const int ref_mv_cost = cost_mv_ref(mode_costs, this_mode, mode_ctx);
2837*77c1e3ccSAndroid Build Coastguard Worker   const int base_rate =
2838*77c1e3ccSAndroid Build Coastguard Worker       args->ref_frame_cost + args->single_comp_cost + ref_mv_cost;
2839*77c1e3ccSAndroid Build Coastguard Worker 
2840*77c1e3ccSAndroid Build Coastguard Worker   for (i = 0; i < MAX_REF_MV_SEARCH - 1; ++i) {
2841*77c1e3ccSAndroid Build Coastguard Worker     save_mv[i][0].as_int = INVALID_MV;
2842*77c1e3ccSAndroid Build Coastguard Worker     save_mv[i][1].as_int = INVALID_MV;
2843*77c1e3ccSAndroid Build Coastguard Worker   }
2844*77c1e3ccSAndroid Build Coastguard Worker   args->start_mv_cnt = 0;
2845*77c1e3ccSAndroid Build Coastguard Worker 
2846*77c1e3ccSAndroid Build Coastguard Worker   // Main loop of this function. This will  iterate over all of the ref mvs
2847*77c1e3ccSAndroid Build Coastguard Worker   // in the dynamic reference list and do the following:
2848*77c1e3ccSAndroid Build Coastguard Worker   //    1.) Get the current MV. Create newmv MV if necessary
2849*77c1e3ccSAndroid Build Coastguard Worker   //    2.) Search compound type and parameters if applicable
2850*77c1e3ccSAndroid Build Coastguard Worker   //    3.) Do interpolation filter search
2851*77c1e3ccSAndroid Build Coastguard Worker   //    4.) Build the inter predictor
2852*77c1e3ccSAndroid Build Coastguard Worker   //    5.) Pick the motion mode (SIMPLE_TRANSLATION, OBMC_CAUSAL,
2853*77c1e3ccSAndroid Build Coastguard Worker   //        WARPED_CAUSAL)
2854*77c1e3ccSAndroid Build Coastguard Worker   //    6.) Update stats if best so far
2855*77c1e3ccSAndroid Build Coastguard Worker   for (int ref_mv_idx = 0; ref_mv_idx < ref_set; ++ref_mv_idx) {
2856*77c1e3ccSAndroid Build Coastguard Worker     mbmi->ref_mv_idx = ref_mv_idx;
2857*77c1e3ccSAndroid Build Coastguard Worker 
2858*77c1e3ccSAndroid Build Coastguard Worker     mode_info[ref_mv_idx].full_search_mv.as_int = INVALID_MV;
2859*77c1e3ccSAndroid Build Coastguard Worker     mode_info[ref_mv_idx].full_mv_bestsme = INT_MAX;
2860*77c1e3ccSAndroid Build Coastguard Worker     const int drl_cost = get_drl_cost(
2861*77c1e3ccSAndroid Build Coastguard Worker         mbmi, mbmi_ext, mode_costs->drl_mode_cost0, ref_frame_type);
2862*77c1e3ccSAndroid Build Coastguard Worker     mode_info[ref_mv_idx].drl_cost = drl_cost;
2863*77c1e3ccSAndroid Build Coastguard Worker     mode_info[ref_mv_idx].skip = 0;
2864*77c1e3ccSAndroid Build Coastguard Worker 
2865*77c1e3ccSAndroid Build Coastguard Worker     if (!mask_check_bit(idx_mask, ref_mv_idx)) {
2866*77c1e3ccSAndroid Build Coastguard Worker       // MV did not perform well in simple translation search. Skip it.
2867*77c1e3ccSAndroid Build Coastguard Worker       continue;
2868*77c1e3ccSAndroid Build Coastguard Worker     }
2869*77c1e3ccSAndroid Build Coastguard Worker     if (prune_modes_based_on_tpl && !ref_match_found_in_above_nb &&
2870*77c1e3ccSAndroid Build Coastguard Worker         !ref_match_found_in_left_nb && (ref_best_rd != INT64_MAX)) {
2871*77c1e3ccSAndroid Build Coastguard Worker       // Skip mode if TPL model indicates it will not be beneficial.
2872*77c1e3ccSAndroid Build Coastguard Worker       if (prune_modes_based_on_tpl_stats(
2873*77c1e3ccSAndroid Build Coastguard Worker               inter_cost_info_from_tpl, refs, ref_mv_idx, this_mode,
2874*77c1e3ccSAndroid Build Coastguard Worker               cpi->sf.inter_sf.prune_inter_modes_based_on_tpl))
2875*77c1e3ccSAndroid Build Coastguard Worker         continue;
2876*77c1e3ccSAndroid Build Coastguard Worker     }
2877*77c1e3ccSAndroid Build Coastguard Worker     av1_init_rd_stats(rd_stats);
2878*77c1e3ccSAndroid Build Coastguard Worker 
2879*77c1e3ccSAndroid Build Coastguard Worker     // Initialize compound mode data
2880*77c1e3ccSAndroid Build Coastguard Worker     mbmi->interinter_comp.type = COMPOUND_AVERAGE;
2881*77c1e3ccSAndroid Build Coastguard Worker     mbmi->comp_group_idx = 0;
2882*77c1e3ccSAndroid Build Coastguard Worker     mbmi->compound_idx = 1;
2883*77c1e3ccSAndroid Build Coastguard Worker     if (mbmi->ref_frame[1] == INTRA_FRAME) mbmi->ref_frame[1] = NONE_FRAME;
2884*77c1e3ccSAndroid Build Coastguard Worker 
2885*77c1e3ccSAndroid Build Coastguard Worker     mbmi->num_proj_ref = 0;
2886*77c1e3ccSAndroid Build Coastguard Worker     mbmi->motion_mode = SIMPLE_TRANSLATION;
2887*77c1e3ccSAndroid Build Coastguard Worker 
2888*77c1e3ccSAndroid Build Coastguard Worker     // Compute cost for signalling this DRL index
2889*77c1e3ccSAndroid Build Coastguard Worker     rd_stats->rate = base_rate;
2890*77c1e3ccSAndroid Build Coastguard Worker     rd_stats->rate += drl_cost;
2891*77c1e3ccSAndroid Build Coastguard Worker 
2892*77c1e3ccSAndroid Build Coastguard Worker     int rs = 0;
2893*77c1e3ccSAndroid Build Coastguard Worker     int compmode_interinter_cost = 0;
2894*77c1e3ccSAndroid Build Coastguard Worker 
2895*77c1e3ccSAndroid Build Coastguard Worker     int_mv cur_mv[2];
2896*77c1e3ccSAndroid Build Coastguard Worker 
2897*77c1e3ccSAndroid Build Coastguard Worker     // TODO(Cherma): Extend this speed feature to support compound mode
2898*77c1e3ccSAndroid Build Coastguard Worker     int skip_repeated_ref_mv =
2899*77c1e3ccSAndroid Build Coastguard Worker         is_comp_pred ? 0 : cpi->sf.inter_sf.skip_repeated_ref_mv;
2900*77c1e3ccSAndroid Build Coastguard Worker     // Generate the current mv according to the prediction mode
2901*77c1e3ccSAndroid Build Coastguard Worker     if (!build_cur_mv(cur_mv, this_mode, cm, x, skip_repeated_ref_mv)) {
2902*77c1e3ccSAndroid Build Coastguard Worker       continue;
2903*77c1e3ccSAndroid Build Coastguard Worker     }
2904*77c1e3ccSAndroid Build Coastguard Worker 
2905*77c1e3ccSAndroid Build Coastguard Worker     // The above call to build_cur_mv does not handle NEWMV modes. Build
2906*77c1e3ccSAndroid Build Coastguard Worker     // the mv here if we have NEWMV for any predictors.
2907*77c1e3ccSAndroid Build Coastguard Worker     if (have_newmv_in_inter_mode(this_mode)) {
2908*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
2909*77c1e3ccSAndroid Build Coastguard Worker       start_timing(cpi, handle_newmv_time);
2910*77c1e3ccSAndroid Build Coastguard Worker #endif
2911*77c1e3ccSAndroid Build Coastguard Worker       newmv_ret_val =
2912*77c1e3ccSAndroid Build Coastguard Worker           handle_newmv(cpi, x, bsize, cur_mv, &rate_mv, args, mode_info);
2913*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
2914*77c1e3ccSAndroid Build Coastguard Worker       end_timing(cpi, handle_newmv_time);
2915*77c1e3ccSAndroid Build Coastguard Worker #endif
2916*77c1e3ccSAndroid Build Coastguard Worker 
2917*77c1e3ccSAndroid Build Coastguard Worker       if (newmv_ret_val != 0) continue;
2918*77c1e3ccSAndroid Build Coastguard Worker 
2919*77c1e3ccSAndroid Build Coastguard Worker       if (is_inter_singleref_mode(this_mode) &&
2920*77c1e3ccSAndroid Build Coastguard Worker           cur_mv[0].as_int != INVALID_MV) {
2921*77c1e3ccSAndroid Build Coastguard Worker         const MV_REFERENCE_FRAME ref = refs[0];
2922*77c1e3ccSAndroid Build Coastguard Worker         const unsigned int this_sse = x->pred_sse[ref];
2923*77c1e3ccSAndroid Build Coastguard Worker         if (this_sse < args->best_single_sse_in_refs[ref]) {
2924*77c1e3ccSAndroid Build Coastguard Worker           args->best_single_sse_in_refs[ref] = this_sse;
2925*77c1e3ccSAndroid Build Coastguard Worker         }
2926*77c1e3ccSAndroid Build Coastguard Worker 
2927*77c1e3ccSAndroid Build Coastguard Worker         if (cpi->sf.rt_sf.skip_newmv_mode_based_on_sse) {
2928*77c1e3ccSAndroid Build Coastguard Worker           const int th_idx = cpi->sf.rt_sf.skip_newmv_mode_based_on_sse - 1;
2929*77c1e3ccSAndroid Build Coastguard Worker           const int pix_idx = num_pels_log2_lookup[bsize] - 4;
2930*77c1e3ccSAndroid Build Coastguard Worker           const double scale_factor[3][11] = {
2931*77c1e3ccSAndroid Build Coastguard Worker             { 0.7, 0.7, 0.7, 0.7, 0.7, 0.8, 0.8, 0.9, 0.9, 0.9, 0.9 },
2932*77c1e3ccSAndroid Build Coastguard Worker             { 0.7, 0.7, 0.7, 0.7, 0.8, 0.8, 1, 1, 1, 1, 1 },
2933*77c1e3ccSAndroid Build Coastguard Worker             { 0.7, 0.7, 0.7, 0.7, 1, 1, 1, 1, 1, 1, 1 }
2934*77c1e3ccSAndroid Build Coastguard Worker           };
2935*77c1e3ccSAndroid Build Coastguard Worker           assert(pix_idx >= 0);
2936*77c1e3ccSAndroid Build Coastguard Worker           assert(th_idx <= 2);
2937*77c1e3ccSAndroid Build Coastguard Worker           if (args->best_pred_sse < scale_factor[th_idx][pix_idx] * this_sse)
2938*77c1e3ccSAndroid Build Coastguard Worker             continue;
2939*77c1e3ccSAndroid Build Coastguard Worker         }
2940*77c1e3ccSAndroid Build Coastguard Worker       }
2941*77c1e3ccSAndroid Build Coastguard Worker 
2942*77c1e3ccSAndroid Build Coastguard Worker       rd_stats->rate += rate_mv;
2943*77c1e3ccSAndroid Build Coastguard Worker     }
2944*77c1e3ccSAndroid Build Coastguard Worker     // Copy the motion vector for this mode into mbmi struct
2945*77c1e3ccSAndroid Build Coastguard Worker     for (i = 0; i < is_comp_pred + 1; ++i) {
2946*77c1e3ccSAndroid Build Coastguard Worker       mbmi->mv[i].as_int = cur_mv[i].as_int;
2947*77c1e3ccSAndroid Build Coastguard Worker     }
2948*77c1e3ccSAndroid Build Coastguard Worker 
2949*77c1e3ccSAndroid Build Coastguard Worker     if (RDCOST(x->rdmult, rd_stats->rate, 0) > ref_best_rd &&
2950*77c1e3ccSAndroid Build Coastguard Worker         mbmi->mode != NEARESTMV && mbmi->mode != NEAREST_NEARESTMV) {
2951*77c1e3ccSAndroid Build Coastguard Worker       continue;
2952*77c1e3ccSAndroid Build Coastguard Worker     }
2953*77c1e3ccSAndroid Build Coastguard Worker 
2954*77c1e3ccSAndroid Build Coastguard Worker     // Skip the rest of the search if prune_ref_mv_idx_search speed feature
2955*77c1e3ccSAndroid Build Coastguard Worker     // is enabled, and the current MV is similar to a previous one.
2956*77c1e3ccSAndroid Build Coastguard Worker     if (cpi->sf.inter_sf.prune_ref_mv_idx_search && is_comp_pred &&
2957*77c1e3ccSAndroid Build Coastguard Worker         prune_ref_mv_idx_search(ref_mv_idx, best_ref_mv_idx, save_mv, mbmi,
2958*77c1e3ccSAndroid Build Coastguard Worker                                 cpi->sf.inter_sf.prune_ref_mv_idx_search))
2959*77c1e3ccSAndroid Build Coastguard Worker       continue;
2960*77c1e3ccSAndroid Build Coastguard Worker 
2961*77c1e3ccSAndroid Build Coastguard Worker     if (cpi->sf.gm_sf.prune_zero_mv_with_sse &&
2962*77c1e3ccSAndroid Build Coastguard Worker         (this_mode == GLOBALMV || this_mode == GLOBAL_GLOBALMV)) {
2963*77c1e3ccSAndroid Build Coastguard Worker       if (prune_zero_mv_with_sse(cpi->ppi->fn_ptr, x, bsize, args,
2964*77c1e3ccSAndroid Build Coastguard Worker                                  cpi->sf.gm_sf.prune_zero_mv_with_sse)) {
2965*77c1e3ccSAndroid Build Coastguard Worker         continue;
2966*77c1e3ccSAndroid Build Coastguard Worker       }
2967*77c1e3ccSAndroid Build Coastguard Worker     }
2968*77c1e3ccSAndroid Build Coastguard Worker 
2969*77c1e3ccSAndroid Build Coastguard Worker     int skip_build_pred = 0;
2970*77c1e3ccSAndroid Build Coastguard Worker     const int mi_row = xd->mi_row;
2971*77c1e3ccSAndroid Build Coastguard Worker     const int mi_col = xd->mi_col;
2972*77c1e3ccSAndroid Build Coastguard Worker 
2973*77c1e3ccSAndroid Build Coastguard Worker     // Handle a compound predictor, continue if it is determined this
2974*77c1e3ccSAndroid Build Coastguard Worker     // cannot be the best compound mode
2975*77c1e3ccSAndroid Build Coastguard Worker     if (is_comp_pred) {
2976*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
2977*77c1e3ccSAndroid Build Coastguard Worker       start_timing(cpi, compound_type_rd_time);
2978*77c1e3ccSAndroid Build Coastguard Worker #endif
2979*77c1e3ccSAndroid Build Coastguard Worker       const int not_best_mode = process_compound_inter_mode(
2980*77c1e3ccSAndroid Build Coastguard Worker           cpi, x, args, ref_best_rd, cur_mv, bsize, &compmode_interinter_cost,
2981*77c1e3ccSAndroid Build Coastguard Worker           rd_buffers, &orig_dst, &tmp_dst, &rate_mv, rd_stats, skip_rd,
2982*77c1e3ccSAndroid Build Coastguard Worker           &skip_build_pred);
2983*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
2984*77c1e3ccSAndroid Build Coastguard Worker       end_timing(cpi, compound_type_rd_time);
2985*77c1e3ccSAndroid Build Coastguard Worker #endif
2986*77c1e3ccSAndroid Build Coastguard Worker       if (not_best_mode) continue;
2987*77c1e3ccSAndroid Build Coastguard Worker     }
2988*77c1e3ccSAndroid Build Coastguard Worker 
2989*77c1e3ccSAndroid Build Coastguard Worker     if (!args->skip_ifs) {
2990*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
2991*77c1e3ccSAndroid Build Coastguard Worker       start_timing(cpi, interpolation_filter_search_time);
2992*77c1e3ccSAndroid Build Coastguard Worker #endif
2993*77c1e3ccSAndroid Build Coastguard Worker       // Determine the interpolation filter for this mode
2994*77c1e3ccSAndroid Build Coastguard Worker       ret_val = av1_interpolation_filter_search(
2995*77c1e3ccSAndroid Build Coastguard Worker           x, cpi, tile_data, bsize, &tmp_dst, &orig_dst, &rd, &rs,
2996*77c1e3ccSAndroid Build Coastguard Worker           &skip_build_pred, args, ref_best_rd);
2997*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
2998*77c1e3ccSAndroid Build Coastguard Worker       end_timing(cpi, interpolation_filter_search_time);
2999*77c1e3ccSAndroid Build Coastguard Worker #endif
3000*77c1e3ccSAndroid Build Coastguard Worker       if (args->modelled_rd != NULL && !is_comp_pred) {
3001*77c1e3ccSAndroid Build Coastguard Worker         args->modelled_rd[this_mode][ref_mv_idx][refs[0]] = rd;
3002*77c1e3ccSAndroid Build Coastguard Worker       }
3003*77c1e3ccSAndroid Build Coastguard Worker       if (ret_val != 0) {
3004*77c1e3ccSAndroid Build Coastguard Worker         restore_dst_buf(xd, orig_dst, num_planes);
3005*77c1e3ccSAndroid Build Coastguard Worker         continue;
3006*77c1e3ccSAndroid Build Coastguard Worker       } else if (cpi->sf.inter_sf.model_based_post_interp_filter_breakout &&
3007*77c1e3ccSAndroid Build Coastguard Worker                  ref_best_rd != INT64_MAX && (rd >> 3) * 3 > ref_best_rd) {
3008*77c1e3ccSAndroid Build Coastguard Worker         restore_dst_buf(xd, orig_dst, num_planes);
3009*77c1e3ccSAndroid Build Coastguard Worker         continue;
3010*77c1e3ccSAndroid Build Coastguard Worker       }
3011*77c1e3ccSAndroid Build Coastguard Worker 
3012*77c1e3ccSAndroid Build Coastguard Worker       // Compute modelled RD if enabled
3013*77c1e3ccSAndroid Build Coastguard Worker       if (args->modelled_rd != NULL) {
3014*77c1e3ccSAndroid Build Coastguard Worker         if (is_comp_pred) {
3015*77c1e3ccSAndroid Build Coastguard Worker           const int mode0 = compound_ref0_mode(this_mode);
3016*77c1e3ccSAndroid Build Coastguard Worker           const int mode1 = compound_ref1_mode(this_mode);
3017*77c1e3ccSAndroid Build Coastguard Worker           const int64_t mrd =
3018*77c1e3ccSAndroid Build Coastguard Worker               AOMMIN(args->modelled_rd[mode0][ref_mv_idx][refs[0]],
3019*77c1e3ccSAndroid Build Coastguard Worker                      args->modelled_rd[mode1][ref_mv_idx][refs[1]]);
3020*77c1e3ccSAndroid Build Coastguard Worker           if ((rd >> 3) * 6 > mrd && ref_best_rd < INT64_MAX) {
3021*77c1e3ccSAndroid Build Coastguard Worker             restore_dst_buf(xd, orig_dst, num_planes);
3022*77c1e3ccSAndroid Build Coastguard Worker             continue;
3023*77c1e3ccSAndroid Build Coastguard Worker           }
3024*77c1e3ccSAndroid Build Coastguard Worker         }
3025*77c1e3ccSAndroid Build Coastguard Worker       }
3026*77c1e3ccSAndroid Build Coastguard Worker     }
3027*77c1e3ccSAndroid Build Coastguard Worker 
3028*77c1e3ccSAndroid Build Coastguard Worker     rd_stats->rate += compmode_interinter_cost;
3029*77c1e3ccSAndroid Build Coastguard Worker     if (skip_build_pred != 1) {
3030*77c1e3ccSAndroid Build Coastguard Worker       // Build this inter predictor if it has not been previously built
3031*77c1e3ccSAndroid Build Coastguard Worker       av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst, bsize, 0,
3032*77c1e3ccSAndroid Build Coastguard Worker                                     av1_num_planes(cm) - 1);
3033*77c1e3ccSAndroid Build Coastguard Worker     }
3034*77c1e3ccSAndroid Build Coastguard Worker 
3035*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
3036*77c1e3ccSAndroid Build Coastguard Worker     start_timing(cpi, motion_mode_rd_time);
3037*77c1e3ccSAndroid Build Coastguard Worker #endif
3038*77c1e3ccSAndroid Build Coastguard Worker     int rate2_nocoeff = rd_stats->rate;
3039*77c1e3ccSAndroid Build Coastguard Worker     // Determine the motion mode. This will be one of SIMPLE_TRANSLATION,
3040*77c1e3ccSAndroid Build Coastguard Worker     // OBMC_CAUSAL or WARPED_CAUSAL
3041*77c1e3ccSAndroid Build Coastguard Worker     int64_t this_yrd;
3042*77c1e3ccSAndroid Build Coastguard Worker     ret_val = motion_mode_rd(cpi, tile_data, x, bsize, rd_stats, rd_stats_y,
3043*77c1e3ccSAndroid Build Coastguard Worker                              rd_stats_uv, args, ref_best_rd, skip_rd, &rate_mv,
3044*77c1e3ccSAndroid Build Coastguard Worker                              &orig_dst, best_est_rd, do_tx_search,
3045*77c1e3ccSAndroid Build Coastguard Worker                              inter_modes_info, 0, &this_yrd);
3046*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
3047*77c1e3ccSAndroid Build Coastguard Worker     end_timing(cpi, motion_mode_rd_time);
3048*77c1e3ccSAndroid Build Coastguard Worker #endif
3049*77c1e3ccSAndroid Build Coastguard Worker     assert(
3050*77c1e3ccSAndroid Build Coastguard Worker         IMPLIES(!av1_check_newmv_joint_nonzero(cm, x), ret_val == INT64_MAX));
3051*77c1e3ccSAndroid Build Coastguard Worker 
3052*77c1e3ccSAndroid Build Coastguard Worker     if (ret_val != INT64_MAX) {
3053*77c1e3ccSAndroid Build Coastguard Worker       int64_t tmp_rd = RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist);
3054*77c1e3ccSAndroid Build Coastguard Worker       const THR_MODES mode_enum = get_prediction_mode_idx(
3055*77c1e3ccSAndroid Build Coastguard Worker           mbmi->mode, mbmi->ref_frame[0], mbmi->ref_frame[1]);
3056*77c1e3ccSAndroid Build Coastguard Worker       // Collect mode stats for multiwinner mode processing
3057*77c1e3ccSAndroid Build Coastguard Worker       store_winner_mode_stats(&cpi->common, x, mbmi, rd_stats, rd_stats_y,
3058*77c1e3ccSAndroid Build Coastguard Worker                               rd_stats_uv, mode_enum, NULL, bsize, tmp_rd,
3059*77c1e3ccSAndroid Build Coastguard Worker                               cpi->sf.winner_mode_sf.multi_winner_mode_type,
3060*77c1e3ccSAndroid Build Coastguard Worker                               do_tx_search);
3061*77c1e3ccSAndroid Build Coastguard Worker       if (tmp_rd < best_rd) {
3062*77c1e3ccSAndroid Build Coastguard Worker         best_yrd = this_yrd;
3063*77c1e3ccSAndroid Build Coastguard Worker         // Update the best rd stats if we found the best mode so far
3064*77c1e3ccSAndroid Build Coastguard Worker         best_rd_stats = *rd_stats;
3065*77c1e3ccSAndroid Build Coastguard Worker         best_rd_stats_y = *rd_stats_y;
3066*77c1e3ccSAndroid Build Coastguard Worker         best_rd_stats_uv = *rd_stats_uv;
3067*77c1e3ccSAndroid Build Coastguard Worker         best_rd = tmp_rd;
3068*77c1e3ccSAndroid Build Coastguard Worker         best_mbmi = *mbmi;
3069*77c1e3ccSAndroid Build Coastguard Worker         best_xskip_txfm = txfm_info->skip_txfm;
3070*77c1e3ccSAndroid Build Coastguard Worker         memcpy(best_blk_skip, txfm_info->blk_skip,
3071*77c1e3ccSAndroid Build Coastguard Worker                sizeof(best_blk_skip[0]) * xd->height * xd->width);
3072*77c1e3ccSAndroid Build Coastguard Worker         av1_copy_array(best_tx_type_map, xd->tx_type_map,
3073*77c1e3ccSAndroid Build Coastguard Worker                        xd->height * xd->width);
3074*77c1e3ccSAndroid Build Coastguard Worker         motion_mode_cand->rate_mv = rate_mv;
3075*77c1e3ccSAndroid Build Coastguard Worker         motion_mode_cand->rate2_nocoeff = rate2_nocoeff;
3076*77c1e3ccSAndroid Build Coastguard Worker       }
3077*77c1e3ccSAndroid Build Coastguard Worker 
3078*77c1e3ccSAndroid Build Coastguard Worker       if (tmp_rd < ref_best_rd) {
3079*77c1e3ccSAndroid Build Coastguard Worker         ref_best_rd = tmp_rd;
3080*77c1e3ccSAndroid Build Coastguard Worker         best_ref_mv_idx = ref_mv_idx;
3081*77c1e3ccSAndroid Build Coastguard Worker       }
3082*77c1e3ccSAndroid Build Coastguard Worker     }
3083*77c1e3ccSAndroid Build Coastguard Worker     restore_dst_buf(xd, orig_dst, num_planes);
3084*77c1e3ccSAndroid Build Coastguard Worker   }
3085*77c1e3ccSAndroid Build Coastguard Worker 
3086*77c1e3ccSAndroid Build Coastguard Worker   if (best_rd == INT64_MAX) return INT64_MAX;
3087*77c1e3ccSAndroid Build Coastguard Worker 
3088*77c1e3ccSAndroid Build Coastguard Worker   // re-instate status of the best choice
3089*77c1e3ccSAndroid Build Coastguard Worker   *rd_stats = best_rd_stats;
3090*77c1e3ccSAndroid Build Coastguard Worker   *rd_stats_y = best_rd_stats_y;
3091*77c1e3ccSAndroid Build Coastguard Worker   *rd_stats_uv = best_rd_stats_uv;
3092*77c1e3ccSAndroid Build Coastguard Worker   *yrd = best_yrd;
3093*77c1e3ccSAndroid Build Coastguard Worker   *mbmi = best_mbmi;
3094*77c1e3ccSAndroid Build Coastguard Worker   txfm_info->skip_txfm = best_xskip_txfm;
3095*77c1e3ccSAndroid Build Coastguard Worker   assert(IMPLIES(mbmi->comp_group_idx == 1,
3096*77c1e3ccSAndroid Build Coastguard Worker                  mbmi->interinter_comp.type != COMPOUND_AVERAGE));
3097*77c1e3ccSAndroid Build Coastguard Worker   memcpy(txfm_info->blk_skip, best_blk_skip,
3098*77c1e3ccSAndroid Build Coastguard Worker          sizeof(best_blk_skip[0]) * xd->height * xd->width);
3099*77c1e3ccSAndroid Build Coastguard Worker   av1_copy_array(xd->tx_type_map, best_tx_type_map, xd->height * xd->width);
3100*77c1e3ccSAndroid Build Coastguard Worker 
3101*77c1e3ccSAndroid Build Coastguard Worker   rd_stats->rdcost = RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist);
3102*77c1e3ccSAndroid Build Coastguard Worker 
3103*77c1e3ccSAndroid Build Coastguard Worker   return rd_stats->rdcost;
3104*77c1e3ccSAndroid Build Coastguard Worker }
3105*77c1e3ccSAndroid Build Coastguard Worker 
3106*77c1e3ccSAndroid Build Coastguard Worker /*!\brief Search for the best intrabc predictor
3107*77c1e3ccSAndroid Build Coastguard Worker  *
3108*77c1e3ccSAndroid Build Coastguard Worker  * \ingroup intra_mode_search
3109*77c1e3ccSAndroid Build Coastguard Worker  * \callergraph
3110*77c1e3ccSAndroid Build Coastguard Worker  * This function performs a motion search to find the best intrabc predictor.
3111*77c1e3ccSAndroid Build Coastguard Worker  *
3112*77c1e3ccSAndroid Build Coastguard Worker  * \returns Returns the best overall rdcost (including the non-intrabc modes
3113*77c1e3ccSAndroid Build Coastguard Worker  * search before this function).
3114*77c1e3ccSAndroid Build Coastguard Worker  */
rd_pick_intrabc_mode_sb(const AV1_COMP * cpi,MACROBLOCK * x,PICK_MODE_CONTEXT * ctx,RD_STATS * rd_stats,BLOCK_SIZE bsize,int64_t best_rd)3115*77c1e3ccSAndroid Build Coastguard Worker static int64_t rd_pick_intrabc_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x,
3116*77c1e3ccSAndroid Build Coastguard Worker                                        PICK_MODE_CONTEXT *ctx,
3117*77c1e3ccSAndroid Build Coastguard Worker                                        RD_STATS *rd_stats, BLOCK_SIZE bsize,
3118*77c1e3ccSAndroid Build Coastguard Worker                                        int64_t best_rd) {
3119*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
3120*77c1e3ccSAndroid Build Coastguard Worker   if (!av1_allow_intrabc(cm) || !cpi->oxcf.kf_cfg.enable_intrabc ||
3121*77c1e3ccSAndroid Build Coastguard Worker       !cpi->sf.mv_sf.use_intrabc || cpi->sf.rt_sf.use_nonrd_pick_mode)
3122*77c1e3ccSAndroid Build Coastguard Worker     return INT64_MAX;
3123*77c1e3ccSAndroid Build Coastguard Worker   const int num_planes = av1_num_planes(cm);
3124*77c1e3ccSAndroid Build Coastguard Worker 
3125*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *const xd = &x->e_mbd;
3126*77c1e3ccSAndroid Build Coastguard Worker   const TileInfo *tile = &xd->tile;
3127*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *mbmi = xd->mi[0];
3128*77c1e3ccSAndroid Build Coastguard Worker   TxfmSearchInfo *txfm_info = &x->txfm_search_info;
3129*77c1e3ccSAndroid Build Coastguard Worker 
3130*77c1e3ccSAndroid Build Coastguard Worker   const int mi_row = xd->mi_row;
3131*77c1e3ccSAndroid Build Coastguard Worker   const int mi_col = xd->mi_col;
3132*77c1e3ccSAndroid Build Coastguard Worker   const int w = block_size_wide[bsize];
3133*77c1e3ccSAndroid Build Coastguard Worker   const int h = block_size_high[bsize];
3134*77c1e3ccSAndroid Build Coastguard Worker   const int sb_row = mi_row >> cm->seq_params->mib_size_log2;
3135*77c1e3ccSAndroid Build Coastguard Worker   const int sb_col = mi_col >> cm->seq_params->mib_size_log2;
3136*77c1e3ccSAndroid Build Coastguard Worker 
3137*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO_EXT *const mbmi_ext = &x->mbmi_ext;
3138*77c1e3ccSAndroid Build Coastguard Worker   const MV_REFERENCE_FRAME ref_frame = INTRA_FRAME;
3139*77c1e3ccSAndroid Build Coastguard Worker   av1_find_mv_refs(cm, xd, mbmi, ref_frame, mbmi_ext->ref_mv_count,
3140*77c1e3ccSAndroid Build Coastguard Worker                    xd->ref_mv_stack, xd->weight, NULL, mbmi_ext->global_mvs,
3141*77c1e3ccSAndroid Build Coastguard Worker                    mbmi_ext->mode_context);
3142*77c1e3ccSAndroid Build Coastguard Worker   // TODO(Ravi): Populate mbmi_ext->ref_mv_stack[ref_frame][4] and
3143*77c1e3ccSAndroid Build Coastguard Worker   // mbmi_ext->weight[ref_frame][4] inside av1_find_mv_refs.
3144*77c1e3ccSAndroid Build Coastguard Worker   av1_copy_usable_ref_mv_stack_and_weight(xd, mbmi_ext, ref_frame);
3145*77c1e3ccSAndroid Build Coastguard Worker   int_mv nearestmv, nearmv;
3146*77c1e3ccSAndroid Build Coastguard Worker   av1_find_best_ref_mvs_from_stack(0, mbmi_ext, ref_frame, &nearestmv, &nearmv,
3147*77c1e3ccSAndroid Build Coastguard Worker                                    0);
3148*77c1e3ccSAndroid Build Coastguard Worker 
3149*77c1e3ccSAndroid Build Coastguard Worker   if (nearestmv.as_int == INVALID_MV) {
3150*77c1e3ccSAndroid Build Coastguard Worker     nearestmv.as_int = 0;
3151*77c1e3ccSAndroid Build Coastguard Worker   }
3152*77c1e3ccSAndroid Build Coastguard Worker   if (nearmv.as_int == INVALID_MV) {
3153*77c1e3ccSAndroid Build Coastguard Worker     nearmv.as_int = 0;
3154*77c1e3ccSAndroid Build Coastguard Worker   }
3155*77c1e3ccSAndroid Build Coastguard Worker 
3156*77c1e3ccSAndroid Build Coastguard Worker   int_mv dv_ref = nearestmv.as_int == 0 ? nearmv : nearestmv;
3157*77c1e3ccSAndroid Build Coastguard Worker   if (dv_ref.as_int == 0) {
3158*77c1e3ccSAndroid Build Coastguard Worker     av1_find_ref_dv(&dv_ref, tile, cm->seq_params->mib_size, mi_row);
3159*77c1e3ccSAndroid Build Coastguard Worker   }
3160*77c1e3ccSAndroid Build Coastguard Worker   // Ref DV should not have sub-pel.
3161*77c1e3ccSAndroid Build Coastguard Worker   assert((dv_ref.as_mv.col & 7) == 0);
3162*77c1e3ccSAndroid Build Coastguard Worker   assert((dv_ref.as_mv.row & 7) == 0);
3163*77c1e3ccSAndroid Build Coastguard Worker   mbmi_ext->ref_mv_stack[INTRA_FRAME][0].this_mv = dv_ref;
3164*77c1e3ccSAndroid Build Coastguard Worker 
3165*77c1e3ccSAndroid Build Coastguard Worker   struct buf_2d yv12_mb[MAX_MB_PLANE];
3166*77c1e3ccSAndroid Build Coastguard Worker   av1_setup_pred_block(xd, yv12_mb, xd->cur_buf, NULL, NULL, num_planes);
3167*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < num_planes; ++i) {
3168*77c1e3ccSAndroid Build Coastguard Worker     xd->plane[i].pre[0] = yv12_mb[i];
3169*77c1e3ccSAndroid Build Coastguard Worker   }
3170*77c1e3ccSAndroid Build Coastguard Worker 
3171*77c1e3ccSAndroid Build Coastguard Worker   enum IntrabcMotionDirection {
3172*77c1e3ccSAndroid Build Coastguard Worker     IBC_MOTION_ABOVE,
3173*77c1e3ccSAndroid Build Coastguard Worker     IBC_MOTION_LEFT,
3174*77c1e3ccSAndroid Build Coastguard Worker     IBC_MOTION_DIRECTIONS
3175*77c1e3ccSAndroid Build Coastguard Worker   };
3176*77c1e3ccSAndroid Build Coastguard Worker 
3177*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO best_mbmi = *mbmi;
3178*77c1e3ccSAndroid Build Coastguard Worker   RD_STATS best_rdstats = *rd_stats;
3179*77c1e3ccSAndroid Build Coastguard Worker   uint8_t best_blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE] = { 0 };
3180*77c1e3ccSAndroid Build Coastguard Worker   uint8_t best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE];
3181*77c1e3ccSAndroid Build Coastguard Worker   av1_copy_array(best_tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
3182*77c1e3ccSAndroid Build Coastguard Worker 
3183*77c1e3ccSAndroid Build Coastguard Worker   FULLPEL_MOTION_SEARCH_PARAMS fullms_params;
3184*77c1e3ccSAndroid Build Coastguard Worker   const SEARCH_METHODS search_method =
3185*77c1e3ccSAndroid Build Coastguard Worker       av1_get_default_mv_search_method(x, &cpi->sf.mv_sf, bsize);
3186*77c1e3ccSAndroid Build Coastguard Worker   const search_site_config *lookahead_search_sites =
3187*77c1e3ccSAndroid Build Coastguard Worker       cpi->mv_search_params.search_site_cfg[SS_CFG_LOOKAHEAD];
3188*77c1e3ccSAndroid Build Coastguard Worker   const FULLPEL_MV start_mv = get_fullmv_from_mv(&dv_ref.as_mv);
3189*77c1e3ccSAndroid Build Coastguard Worker   av1_make_default_fullpel_ms_params(&fullms_params, cpi, x, bsize,
3190*77c1e3ccSAndroid Build Coastguard Worker                                      &dv_ref.as_mv, start_mv,
3191*77c1e3ccSAndroid Build Coastguard Worker                                      lookahead_search_sites, search_method,
3192*77c1e3ccSAndroid Build Coastguard Worker                                      /*fine_search_interval=*/0);
3193*77c1e3ccSAndroid Build Coastguard Worker   const IntraBCMVCosts *const dv_costs = x->dv_costs;
3194*77c1e3ccSAndroid Build Coastguard Worker   av1_set_ms_to_intra_mode(&fullms_params, dv_costs);
3195*77c1e3ccSAndroid Build Coastguard Worker 
3196*77c1e3ccSAndroid Build Coastguard Worker   for (enum IntrabcMotionDirection dir = IBC_MOTION_ABOVE;
3197*77c1e3ccSAndroid Build Coastguard Worker        dir < IBC_MOTION_DIRECTIONS; ++dir) {
3198*77c1e3ccSAndroid Build Coastguard Worker     switch (dir) {
3199*77c1e3ccSAndroid Build Coastguard Worker       case IBC_MOTION_ABOVE:
3200*77c1e3ccSAndroid Build Coastguard Worker         fullms_params.mv_limits.col_min =
3201*77c1e3ccSAndroid Build Coastguard Worker             (tile->mi_col_start - mi_col) * MI_SIZE;
3202*77c1e3ccSAndroid Build Coastguard Worker         fullms_params.mv_limits.col_max =
3203*77c1e3ccSAndroid Build Coastguard Worker             (tile->mi_col_end - mi_col) * MI_SIZE - w;
3204*77c1e3ccSAndroid Build Coastguard Worker         fullms_params.mv_limits.row_min =
3205*77c1e3ccSAndroid Build Coastguard Worker             (tile->mi_row_start - mi_row) * MI_SIZE;
3206*77c1e3ccSAndroid Build Coastguard Worker         fullms_params.mv_limits.row_max =
3207*77c1e3ccSAndroid Build Coastguard Worker             (sb_row * cm->seq_params->mib_size - mi_row) * MI_SIZE - h;
3208*77c1e3ccSAndroid Build Coastguard Worker         break;
3209*77c1e3ccSAndroid Build Coastguard Worker       case IBC_MOTION_LEFT:
3210*77c1e3ccSAndroid Build Coastguard Worker         fullms_params.mv_limits.col_min =
3211*77c1e3ccSAndroid Build Coastguard Worker             (tile->mi_col_start - mi_col) * MI_SIZE;
3212*77c1e3ccSAndroid Build Coastguard Worker         fullms_params.mv_limits.col_max =
3213*77c1e3ccSAndroid Build Coastguard Worker             (sb_col * cm->seq_params->mib_size - mi_col) * MI_SIZE - w;
3214*77c1e3ccSAndroid Build Coastguard Worker         // TODO([email protected]): Minimize the overlap between above and
3215*77c1e3ccSAndroid Build Coastguard Worker         // left areas.
3216*77c1e3ccSAndroid Build Coastguard Worker         fullms_params.mv_limits.row_min =
3217*77c1e3ccSAndroid Build Coastguard Worker             (tile->mi_row_start - mi_row) * MI_SIZE;
3218*77c1e3ccSAndroid Build Coastguard Worker         int bottom_coded_mi_edge =
3219*77c1e3ccSAndroid Build Coastguard Worker             AOMMIN((sb_row + 1) * cm->seq_params->mib_size, tile->mi_row_end);
3220*77c1e3ccSAndroid Build Coastguard Worker         fullms_params.mv_limits.row_max =
3221*77c1e3ccSAndroid Build Coastguard Worker             (bottom_coded_mi_edge - mi_row) * MI_SIZE - h;
3222*77c1e3ccSAndroid Build Coastguard Worker         break;
3223*77c1e3ccSAndroid Build Coastguard Worker       default: assert(0);
3224*77c1e3ccSAndroid Build Coastguard Worker     }
3225*77c1e3ccSAndroid Build Coastguard Worker     assert(fullms_params.mv_limits.col_min >= fullms_params.mv_limits.col_min);
3226*77c1e3ccSAndroid Build Coastguard Worker     assert(fullms_params.mv_limits.col_max <= fullms_params.mv_limits.col_max);
3227*77c1e3ccSAndroid Build Coastguard Worker     assert(fullms_params.mv_limits.row_min >= fullms_params.mv_limits.row_min);
3228*77c1e3ccSAndroid Build Coastguard Worker     assert(fullms_params.mv_limits.row_max <= fullms_params.mv_limits.row_max);
3229*77c1e3ccSAndroid Build Coastguard Worker 
3230*77c1e3ccSAndroid Build Coastguard Worker     av1_set_mv_search_range(&fullms_params.mv_limits, &dv_ref.as_mv);
3231*77c1e3ccSAndroid Build Coastguard Worker 
3232*77c1e3ccSAndroid Build Coastguard Worker     if (fullms_params.mv_limits.col_max < fullms_params.mv_limits.col_min ||
3233*77c1e3ccSAndroid Build Coastguard Worker         fullms_params.mv_limits.row_max < fullms_params.mv_limits.row_min) {
3234*77c1e3ccSAndroid Build Coastguard Worker       continue;
3235*77c1e3ccSAndroid Build Coastguard Worker     }
3236*77c1e3ccSAndroid Build Coastguard Worker 
3237*77c1e3ccSAndroid Build Coastguard Worker     const int step_param = cpi->mv_search_params.mv_step_param;
3238*77c1e3ccSAndroid Build Coastguard Worker     IntraBCHashInfo *intrabc_hash_info = &x->intrabc_hash_info;
3239*77c1e3ccSAndroid Build Coastguard Worker     int_mv best_mv, best_hash_mv;
3240*77c1e3ccSAndroid Build Coastguard Worker     FULLPEL_MV_STATS best_mv_stats;
3241*77c1e3ccSAndroid Build Coastguard Worker 
3242*77c1e3ccSAndroid Build Coastguard Worker     int bestsme =
3243*77c1e3ccSAndroid Build Coastguard Worker         av1_full_pixel_search(start_mv, &fullms_params, step_param, NULL,
3244*77c1e3ccSAndroid Build Coastguard Worker                               &best_mv.as_fullmv, &best_mv_stats, NULL);
3245*77c1e3ccSAndroid Build Coastguard Worker     const int hashsme = av1_intrabc_hash_search(
3246*77c1e3ccSAndroid Build Coastguard Worker         cpi, xd, &fullms_params, intrabc_hash_info, &best_hash_mv.as_fullmv);
3247*77c1e3ccSAndroid Build Coastguard Worker     if (hashsme < bestsme) {
3248*77c1e3ccSAndroid Build Coastguard Worker       best_mv = best_hash_mv;
3249*77c1e3ccSAndroid Build Coastguard Worker       bestsme = hashsme;
3250*77c1e3ccSAndroid Build Coastguard Worker     }
3251*77c1e3ccSAndroid Build Coastguard Worker 
3252*77c1e3ccSAndroid Build Coastguard Worker     if (bestsme == INT_MAX) continue;
3253*77c1e3ccSAndroid Build Coastguard Worker     const MV dv = get_mv_from_fullmv(&best_mv.as_fullmv);
3254*77c1e3ccSAndroid Build Coastguard Worker     if (!av1_is_fullmv_in_range(&fullms_params.mv_limits,
3255*77c1e3ccSAndroid Build Coastguard Worker                                 get_fullmv_from_mv(&dv)))
3256*77c1e3ccSAndroid Build Coastguard Worker       continue;
3257*77c1e3ccSAndroid Build Coastguard Worker     if (!av1_is_dv_valid(dv, cm, xd, mi_row, mi_col, bsize,
3258*77c1e3ccSAndroid Build Coastguard Worker                          cm->seq_params->mib_size_log2))
3259*77c1e3ccSAndroid Build Coastguard Worker       continue;
3260*77c1e3ccSAndroid Build Coastguard Worker 
3261*77c1e3ccSAndroid Build Coastguard Worker     // DV should not have sub-pel.
3262*77c1e3ccSAndroid Build Coastguard Worker     assert((dv.col & 7) == 0);
3263*77c1e3ccSAndroid Build Coastguard Worker     assert((dv.row & 7) == 0);
3264*77c1e3ccSAndroid Build Coastguard Worker     memset(&mbmi->palette_mode_info, 0, sizeof(mbmi->palette_mode_info));
3265*77c1e3ccSAndroid Build Coastguard Worker     mbmi->filter_intra_mode_info.use_filter_intra = 0;
3266*77c1e3ccSAndroid Build Coastguard Worker     mbmi->use_intrabc = 1;
3267*77c1e3ccSAndroid Build Coastguard Worker     mbmi->mode = DC_PRED;
3268*77c1e3ccSAndroid Build Coastguard Worker     mbmi->uv_mode = UV_DC_PRED;
3269*77c1e3ccSAndroid Build Coastguard Worker     mbmi->motion_mode = SIMPLE_TRANSLATION;
3270*77c1e3ccSAndroid Build Coastguard Worker     mbmi->mv[0].as_mv = dv;
3271*77c1e3ccSAndroid Build Coastguard Worker     mbmi->interp_filters = av1_broadcast_interp_filter(BILINEAR);
3272*77c1e3ccSAndroid Build Coastguard Worker     mbmi->skip_txfm = 0;
3273*77c1e3ccSAndroid Build Coastguard Worker     av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, 0,
3274*77c1e3ccSAndroid Build Coastguard Worker                                   av1_num_planes(cm) - 1);
3275*77c1e3ccSAndroid Build Coastguard Worker 
3276*77c1e3ccSAndroid Build Coastguard Worker     // TODO([email protected]): The full motion field defining discount
3277*77c1e3ccSAndroid Build Coastguard Worker     // in MV_COST_WEIGHT is too large. Explore other values.
3278*77c1e3ccSAndroid Build Coastguard Worker     const int rate_mv = av1_mv_bit_cost(&dv, &dv_ref.as_mv, dv_costs->joint_mv,
3279*77c1e3ccSAndroid Build Coastguard Worker                                         dv_costs->dv_costs, MV_COST_WEIGHT_SUB);
3280*77c1e3ccSAndroid Build Coastguard Worker     const int rate_mode = x->mode_costs.intrabc_cost[1];
3281*77c1e3ccSAndroid Build Coastguard Worker     RD_STATS rd_stats_yuv, rd_stats_y, rd_stats_uv;
3282*77c1e3ccSAndroid Build Coastguard Worker     if (!av1_txfm_search(cpi, x, bsize, &rd_stats_yuv, &rd_stats_y,
3283*77c1e3ccSAndroid Build Coastguard Worker                          &rd_stats_uv, rate_mode + rate_mv, INT64_MAX))
3284*77c1e3ccSAndroid Build Coastguard Worker       continue;
3285*77c1e3ccSAndroid Build Coastguard Worker     rd_stats_yuv.rdcost =
3286*77c1e3ccSAndroid Build Coastguard Worker         RDCOST(x->rdmult, rd_stats_yuv.rate, rd_stats_yuv.dist);
3287*77c1e3ccSAndroid Build Coastguard Worker     if (rd_stats_yuv.rdcost < best_rd) {
3288*77c1e3ccSAndroid Build Coastguard Worker       best_rd = rd_stats_yuv.rdcost;
3289*77c1e3ccSAndroid Build Coastguard Worker       best_mbmi = *mbmi;
3290*77c1e3ccSAndroid Build Coastguard Worker       best_rdstats = rd_stats_yuv;
3291*77c1e3ccSAndroid Build Coastguard Worker       memcpy(best_blk_skip, txfm_info->blk_skip,
3292*77c1e3ccSAndroid Build Coastguard Worker              sizeof(txfm_info->blk_skip[0]) * xd->height * xd->width);
3293*77c1e3ccSAndroid Build Coastguard Worker       av1_copy_array(best_tx_type_map, xd->tx_type_map, xd->height * xd->width);
3294*77c1e3ccSAndroid Build Coastguard Worker     }
3295*77c1e3ccSAndroid Build Coastguard Worker   }
3296*77c1e3ccSAndroid Build Coastguard Worker   *mbmi = best_mbmi;
3297*77c1e3ccSAndroid Build Coastguard Worker   *rd_stats = best_rdstats;
3298*77c1e3ccSAndroid Build Coastguard Worker   memcpy(txfm_info->blk_skip, best_blk_skip,
3299*77c1e3ccSAndroid Build Coastguard Worker          sizeof(txfm_info->blk_skip[0]) * xd->height * xd->width);
3300*77c1e3ccSAndroid Build Coastguard Worker   av1_copy_array(xd->tx_type_map, best_tx_type_map, ctx->num_4x4_blk);
3301*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_RD_DEBUG
3302*77c1e3ccSAndroid Build Coastguard Worker   mbmi->rd_stats = *rd_stats;
3303*77c1e3ccSAndroid Build Coastguard Worker #endif
3304*77c1e3ccSAndroid Build Coastguard Worker   return best_rd;
3305*77c1e3ccSAndroid Build Coastguard Worker }
3306*77c1e3ccSAndroid Build Coastguard Worker 
3307*77c1e3ccSAndroid Build Coastguard Worker // TODO([email protected]): We are using struct $struct_name instead of their
3308*77c1e3ccSAndroid Build Coastguard Worker // typedef here because Doxygen doesn't know about the typedefs yet. So using
3309*77c1e3ccSAndroid Build Coastguard Worker // the typedef will prevent doxygen from finding this function and generating
3310*77c1e3ccSAndroid Build Coastguard Worker // the callgraph. Once documents for AV1_COMP and MACROBLOCK are added to
3311*77c1e3ccSAndroid Build Coastguard Worker // doxygen, we can revert back to using the typedefs.
av1_rd_pick_intra_mode_sb(const struct AV1_COMP * cpi,struct macroblock * x,struct RD_STATS * rd_cost,BLOCK_SIZE bsize,PICK_MODE_CONTEXT * ctx,int64_t best_rd)3312*77c1e3ccSAndroid Build Coastguard Worker void av1_rd_pick_intra_mode_sb(const struct AV1_COMP *cpi, struct macroblock *x,
3313*77c1e3ccSAndroid Build Coastguard Worker                                struct RD_STATS *rd_cost, BLOCK_SIZE bsize,
3314*77c1e3ccSAndroid Build Coastguard Worker                                PICK_MODE_CONTEXT *ctx, int64_t best_rd) {
3315*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
3316*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *const xd = &x->e_mbd;
3317*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *const mbmi = xd->mi[0];
3318*77c1e3ccSAndroid Build Coastguard Worker   const int num_planes = av1_num_planes(cm);
3319*77c1e3ccSAndroid Build Coastguard Worker   TxfmSearchInfo *txfm_info = &x->txfm_search_info;
3320*77c1e3ccSAndroid Build Coastguard Worker   int rate_y = 0, rate_uv = 0, rate_y_tokenonly = 0, rate_uv_tokenonly = 0;
3321*77c1e3ccSAndroid Build Coastguard Worker   uint8_t y_skip_txfm = 0, uv_skip_txfm = 0;
3322*77c1e3ccSAndroid Build Coastguard Worker   int64_t dist_y = 0, dist_uv = 0;
3323*77c1e3ccSAndroid Build Coastguard Worker 
3324*77c1e3ccSAndroid Build Coastguard Worker   ctx->rd_stats.skip_txfm = 0;
3325*77c1e3ccSAndroid Build Coastguard Worker   mbmi->ref_frame[0] = INTRA_FRAME;
3326*77c1e3ccSAndroid Build Coastguard Worker   mbmi->ref_frame[1] = NONE_FRAME;
3327*77c1e3ccSAndroid Build Coastguard Worker   mbmi->use_intrabc = 0;
3328*77c1e3ccSAndroid Build Coastguard Worker   mbmi->mv[0].as_int = 0;
3329*77c1e3ccSAndroid Build Coastguard Worker   mbmi->skip_mode = 0;
3330*77c1e3ccSAndroid Build Coastguard Worker 
3331*77c1e3ccSAndroid Build Coastguard Worker   const int64_t intra_yrd =
3332*77c1e3ccSAndroid Build Coastguard Worker       av1_rd_pick_intra_sby_mode(cpi, x, &rate_y, &rate_y_tokenonly, &dist_y,
3333*77c1e3ccSAndroid Build Coastguard Worker                                  &y_skip_txfm, bsize, best_rd, ctx);
3334*77c1e3ccSAndroid Build Coastguard Worker 
3335*77c1e3ccSAndroid Build Coastguard Worker   // Initialize default mode evaluation params
3336*77c1e3ccSAndroid Build Coastguard Worker   set_mode_eval_params(cpi, x, DEFAULT_EVAL);
3337*77c1e3ccSAndroid Build Coastguard Worker 
3338*77c1e3ccSAndroid Build Coastguard Worker   if (intra_yrd < best_rd) {
3339*77c1e3ccSAndroid Build Coastguard Worker     // Search intra modes for uv planes if needed
3340*77c1e3ccSAndroid Build Coastguard Worker     if (num_planes > 1) {
3341*77c1e3ccSAndroid Build Coastguard Worker       // Set up the tx variables for reproducing the y predictions in case we
3342*77c1e3ccSAndroid Build Coastguard Worker       // need it for chroma-from-luma.
3343*77c1e3ccSAndroid Build Coastguard Worker       if (xd->is_chroma_ref && store_cfl_required_rdo(cm, x)) {
3344*77c1e3ccSAndroid Build Coastguard Worker         memcpy(txfm_info->blk_skip, ctx->blk_skip,
3345*77c1e3ccSAndroid Build Coastguard Worker                sizeof(txfm_info->blk_skip[0]) * ctx->num_4x4_blk);
3346*77c1e3ccSAndroid Build Coastguard Worker         av1_copy_array(xd->tx_type_map, ctx->tx_type_map, ctx->num_4x4_blk);
3347*77c1e3ccSAndroid Build Coastguard Worker       }
3348*77c1e3ccSAndroid Build Coastguard Worker       const TX_SIZE max_uv_tx_size = av1_get_tx_size(AOM_PLANE_U, xd);
3349*77c1e3ccSAndroid Build Coastguard Worker       av1_rd_pick_intra_sbuv_mode(cpi, x, &rate_uv, &rate_uv_tokenonly,
3350*77c1e3ccSAndroid Build Coastguard Worker                                   &dist_uv, &uv_skip_txfm, bsize,
3351*77c1e3ccSAndroid Build Coastguard Worker                                   max_uv_tx_size);
3352*77c1e3ccSAndroid Build Coastguard Worker     }
3353*77c1e3ccSAndroid Build Coastguard Worker 
3354*77c1e3ccSAndroid Build Coastguard Worker     // Intra block is always coded as non-skip
3355*77c1e3ccSAndroid Build Coastguard Worker     rd_cost->rate =
3356*77c1e3ccSAndroid Build Coastguard Worker         rate_y + rate_uv +
3357*77c1e3ccSAndroid Build Coastguard Worker         x->mode_costs.skip_txfm_cost[av1_get_skip_txfm_context(xd)][0];
3358*77c1e3ccSAndroid Build Coastguard Worker     rd_cost->dist = dist_y + dist_uv;
3359*77c1e3ccSAndroid Build Coastguard Worker     rd_cost->rdcost = RDCOST(x->rdmult, rd_cost->rate, rd_cost->dist);
3360*77c1e3ccSAndroid Build Coastguard Worker     rd_cost->skip_txfm = 0;
3361*77c1e3ccSAndroid Build Coastguard Worker   } else {
3362*77c1e3ccSAndroid Build Coastguard Worker     rd_cost->rate = INT_MAX;
3363*77c1e3ccSAndroid Build Coastguard Worker   }
3364*77c1e3ccSAndroid Build Coastguard Worker 
3365*77c1e3ccSAndroid Build Coastguard Worker   if (rd_cost->rate != INT_MAX && rd_cost->rdcost < best_rd)
3366*77c1e3ccSAndroid Build Coastguard Worker     best_rd = rd_cost->rdcost;
3367*77c1e3ccSAndroid Build Coastguard Worker   if (rd_pick_intrabc_mode_sb(cpi, x, ctx, rd_cost, bsize, best_rd) < best_rd) {
3368*77c1e3ccSAndroid Build Coastguard Worker     ctx->rd_stats.skip_txfm = mbmi->skip_txfm;
3369*77c1e3ccSAndroid Build Coastguard Worker     memcpy(ctx->blk_skip, txfm_info->blk_skip,
3370*77c1e3ccSAndroid Build Coastguard Worker            sizeof(txfm_info->blk_skip[0]) * ctx->num_4x4_blk);
3371*77c1e3ccSAndroid Build Coastguard Worker     assert(rd_cost->rate != INT_MAX);
3372*77c1e3ccSAndroid Build Coastguard Worker   }
3373*77c1e3ccSAndroid Build Coastguard Worker   if (rd_cost->rate == INT_MAX) return;
3374*77c1e3ccSAndroid Build Coastguard Worker 
3375*77c1e3ccSAndroid Build Coastguard Worker   ctx->mic = *xd->mi[0];
3376*77c1e3ccSAndroid Build Coastguard Worker   av1_copy_mbmi_ext_to_mbmi_ext_frame(&ctx->mbmi_ext_best, &x->mbmi_ext,
3377*77c1e3ccSAndroid Build Coastguard Worker                                       av1_ref_frame_type(xd->mi[0]->ref_frame));
3378*77c1e3ccSAndroid Build Coastguard Worker   av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
3379*77c1e3ccSAndroid Build Coastguard Worker }
3380*77c1e3ccSAndroid Build Coastguard Worker 
3381*77c1e3ccSAndroid Build Coastguard Worker static inline void calc_target_weighted_pred(
3382*77c1e3ccSAndroid Build Coastguard Worker     const AV1_COMMON *cm, const MACROBLOCK *x, const MACROBLOCKD *xd,
3383*77c1e3ccSAndroid Build Coastguard Worker     const uint8_t *above, int above_stride, const uint8_t *left,
3384*77c1e3ccSAndroid Build Coastguard Worker     int left_stride);
3385*77c1e3ccSAndroid Build Coastguard Worker 
rd_pick_skip_mode(RD_STATS * rd_cost,InterModeSearchState * search_state,const AV1_COMP * const cpi,MACROBLOCK * const x,BLOCK_SIZE bsize,struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE])3386*77c1e3ccSAndroid Build Coastguard Worker static inline void rd_pick_skip_mode(
3387*77c1e3ccSAndroid Build Coastguard Worker     RD_STATS *rd_cost, InterModeSearchState *search_state,
3388*77c1e3ccSAndroid Build Coastguard Worker     const AV1_COMP *const cpi, MACROBLOCK *const x, BLOCK_SIZE bsize,
3389*77c1e3ccSAndroid Build Coastguard Worker     struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE]) {
3390*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
3391*77c1e3ccSAndroid Build Coastguard Worker   const SkipModeInfo *const skip_mode_info = &cm->current_frame.skip_mode_info;
3392*77c1e3ccSAndroid Build Coastguard Worker   const int num_planes = av1_num_planes(cm);
3393*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *const xd = &x->e_mbd;
3394*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *const mbmi = xd->mi[0];
3395*77c1e3ccSAndroid Build Coastguard Worker 
3396*77c1e3ccSAndroid Build Coastguard Worker   x->compound_idx = 1;  // COMPOUND_AVERAGE
3397*77c1e3ccSAndroid Build Coastguard Worker   RD_STATS skip_mode_rd_stats;
3398*77c1e3ccSAndroid Build Coastguard Worker   av1_invalid_rd_stats(&skip_mode_rd_stats);
3399*77c1e3ccSAndroid Build Coastguard Worker 
3400*77c1e3ccSAndroid Build Coastguard Worker   if (skip_mode_info->ref_frame_idx_0 == INVALID_IDX ||
3401*77c1e3ccSAndroid Build Coastguard Worker       skip_mode_info->ref_frame_idx_1 == INVALID_IDX) {
3402*77c1e3ccSAndroid Build Coastguard Worker     return;
3403*77c1e3ccSAndroid Build Coastguard Worker   }
3404*77c1e3ccSAndroid Build Coastguard Worker 
3405*77c1e3ccSAndroid Build Coastguard Worker   const MV_REFERENCE_FRAME ref_frame =
3406*77c1e3ccSAndroid Build Coastguard Worker       LAST_FRAME + skip_mode_info->ref_frame_idx_0;
3407*77c1e3ccSAndroid Build Coastguard Worker   const MV_REFERENCE_FRAME second_ref_frame =
3408*77c1e3ccSAndroid Build Coastguard Worker       LAST_FRAME + skip_mode_info->ref_frame_idx_1;
3409*77c1e3ccSAndroid Build Coastguard Worker   const PREDICTION_MODE this_mode = NEAREST_NEARESTMV;
3410*77c1e3ccSAndroid Build Coastguard Worker   const THR_MODES mode_index =
3411*77c1e3ccSAndroid Build Coastguard Worker       get_prediction_mode_idx(this_mode, ref_frame, second_ref_frame);
3412*77c1e3ccSAndroid Build Coastguard Worker 
3413*77c1e3ccSAndroid Build Coastguard Worker   if (mode_index == THR_INVALID) {
3414*77c1e3ccSAndroid Build Coastguard Worker     return;
3415*77c1e3ccSAndroid Build Coastguard Worker   }
3416*77c1e3ccSAndroid Build Coastguard Worker 
3417*77c1e3ccSAndroid Build Coastguard Worker   if ((!cpi->oxcf.ref_frm_cfg.enable_onesided_comp ||
3418*77c1e3ccSAndroid Build Coastguard Worker        cpi->sf.inter_sf.disable_onesided_comp) &&
3419*77c1e3ccSAndroid Build Coastguard Worker       cpi->all_one_sided_refs) {
3420*77c1e3ccSAndroid Build Coastguard Worker     return;
3421*77c1e3ccSAndroid Build Coastguard Worker   }
3422*77c1e3ccSAndroid Build Coastguard Worker 
3423*77c1e3ccSAndroid Build Coastguard Worker   mbmi->mode = this_mode;
3424*77c1e3ccSAndroid Build Coastguard Worker   mbmi->uv_mode = UV_DC_PRED;
3425*77c1e3ccSAndroid Build Coastguard Worker   mbmi->ref_frame[0] = ref_frame;
3426*77c1e3ccSAndroid Build Coastguard Worker   mbmi->ref_frame[1] = second_ref_frame;
3427*77c1e3ccSAndroid Build Coastguard Worker   const uint8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
3428*77c1e3ccSAndroid Build Coastguard Worker   if (x->mbmi_ext.ref_mv_count[ref_frame_type] == UINT8_MAX) {
3429*77c1e3ccSAndroid Build Coastguard Worker     MB_MODE_INFO_EXT *mbmi_ext = &x->mbmi_ext;
3430*77c1e3ccSAndroid Build Coastguard Worker     if (mbmi_ext->ref_mv_count[ref_frame] == UINT8_MAX ||
3431*77c1e3ccSAndroid Build Coastguard Worker         mbmi_ext->ref_mv_count[second_ref_frame] == UINT8_MAX) {
3432*77c1e3ccSAndroid Build Coastguard Worker       return;
3433*77c1e3ccSAndroid Build Coastguard Worker     }
3434*77c1e3ccSAndroid Build Coastguard Worker     av1_find_mv_refs(cm, xd, mbmi, ref_frame_type, mbmi_ext->ref_mv_count,
3435*77c1e3ccSAndroid Build Coastguard Worker                      xd->ref_mv_stack, xd->weight, NULL, mbmi_ext->global_mvs,
3436*77c1e3ccSAndroid Build Coastguard Worker                      mbmi_ext->mode_context);
3437*77c1e3ccSAndroid Build Coastguard Worker     // TODO(Ravi): Populate mbmi_ext->ref_mv_stack[ref_frame][4] and
3438*77c1e3ccSAndroid Build Coastguard Worker     // mbmi_ext->weight[ref_frame][4] inside av1_find_mv_refs.
3439*77c1e3ccSAndroid Build Coastguard Worker     av1_copy_usable_ref_mv_stack_and_weight(xd, mbmi_ext, ref_frame_type);
3440*77c1e3ccSAndroid Build Coastguard Worker   }
3441*77c1e3ccSAndroid Build Coastguard Worker 
3442*77c1e3ccSAndroid Build Coastguard Worker   assert(this_mode == NEAREST_NEARESTMV);
3443*77c1e3ccSAndroid Build Coastguard Worker   if (!build_cur_mv(mbmi->mv, this_mode, cm, x, 0)) {
3444*77c1e3ccSAndroid Build Coastguard Worker     return;
3445*77c1e3ccSAndroid Build Coastguard Worker   }
3446*77c1e3ccSAndroid Build Coastguard Worker 
3447*77c1e3ccSAndroid Build Coastguard Worker   mbmi->filter_intra_mode_info.use_filter_intra = 0;
3448*77c1e3ccSAndroid Build Coastguard Worker   mbmi->interintra_mode = (INTERINTRA_MODE)(II_DC_PRED - 1);
3449*77c1e3ccSAndroid Build Coastguard Worker   mbmi->comp_group_idx = 0;
3450*77c1e3ccSAndroid Build Coastguard Worker   mbmi->compound_idx = x->compound_idx;
3451*77c1e3ccSAndroid Build Coastguard Worker   mbmi->interinter_comp.type = COMPOUND_AVERAGE;
3452*77c1e3ccSAndroid Build Coastguard Worker   mbmi->motion_mode = SIMPLE_TRANSLATION;
3453*77c1e3ccSAndroid Build Coastguard Worker   mbmi->ref_mv_idx = 0;
3454*77c1e3ccSAndroid Build Coastguard Worker   mbmi->skip_mode = mbmi->skip_txfm = 1;
3455*77c1e3ccSAndroid Build Coastguard Worker   mbmi->palette_mode_info.palette_size[0] = 0;
3456*77c1e3ccSAndroid Build Coastguard Worker   mbmi->palette_mode_info.palette_size[1] = 0;
3457*77c1e3ccSAndroid Build Coastguard Worker 
3458*77c1e3ccSAndroid Build Coastguard Worker   set_default_interp_filters(mbmi, cm->features.interp_filter);
3459*77c1e3ccSAndroid Build Coastguard Worker 
3460*77c1e3ccSAndroid Build Coastguard Worker   set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
3461*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < num_planes; i++) {
3462*77c1e3ccSAndroid Build Coastguard Worker     xd->plane[i].pre[0] = yv12_mb[mbmi->ref_frame[0]][i];
3463*77c1e3ccSAndroid Build Coastguard Worker     xd->plane[i].pre[1] = yv12_mb[mbmi->ref_frame[1]][i];
3464*77c1e3ccSAndroid Build Coastguard Worker   }
3465*77c1e3ccSAndroid Build Coastguard Worker 
3466*77c1e3ccSAndroid Build Coastguard Worker   BUFFER_SET orig_dst;
3467*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < num_planes; i++) {
3468*77c1e3ccSAndroid Build Coastguard Worker     orig_dst.plane[i] = xd->plane[i].dst.buf;
3469*77c1e3ccSAndroid Build Coastguard Worker     orig_dst.stride[i] = xd->plane[i].dst.stride;
3470*77c1e3ccSAndroid Build Coastguard Worker   }
3471*77c1e3ccSAndroid Build Coastguard Worker 
3472*77c1e3ccSAndroid Build Coastguard Worker   // Compare the use of skip_mode with the best intra/inter mode obtained.
3473*77c1e3ccSAndroid Build Coastguard Worker   const int skip_mode_ctx = av1_get_skip_mode_context(xd);
3474*77c1e3ccSAndroid Build Coastguard Worker   int64_t best_intra_inter_mode_cost = INT64_MAX;
3475*77c1e3ccSAndroid Build Coastguard Worker   if (rd_cost->dist < INT64_MAX && rd_cost->rate < INT32_MAX) {
3476*77c1e3ccSAndroid Build Coastguard Worker     const ModeCosts *mode_costs = &x->mode_costs;
3477*77c1e3ccSAndroid Build Coastguard Worker     best_intra_inter_mode_cost = RDCOST(
3478*77c1e3ccSAndroid Build Coastguard Worker         x->rdmult, rd_cost->rate + mode_costs->skip_mode_cost[skip_mode_ctx][0],
3479*77c1e3ccSAndroid Build Coastguard Worker         rd_cost->dist);
3480*77c1e3ccSAndroid Build Coastguard Worker     // Account for non-skip mode rate in total rd stats
3481*77c1e3ccSAndroid Build Coastguard Worker     rd_cost->rate += mode_costs->skip_mode_cost[skip_mode_ctx][0];
3482*77c1e3ccSAndroid Build Coastguard Worker     av1_rd_cost_update(x->rdmult, rd_cost);
3483*77c1e3ccSAndroid Build Coastguard Worker   }
3484*77c1e3ccSAndroid Build Coastguard Worker 
3485*77c1e3ccSAndroid Build Coastguard Worker   // Obtain the rdcost for skip_mode.
3486*77c1e3ccSAndroid Build Coastguard Worker   skip_mode_rd(&skip_mode_rd_stats, cpi, x, bsize, &orig_dst,
3487*77c1e3ccSAndroid Build Coastguard Worker                best_intra_inter_mode_cost);
3488*77c1e3ccSAndroid Build Coastguard Worker 
3489*77c1e3ccSAndroid Build Coastguard Worker   if (skip_mode_rd_stats.rdcost <= best_intra_inter_mode_cost &&
3490*77c1e3ccSAndroid Build Coastguard Worker       (!xd->lossless[mbmi->segment_id] || skip_mode_rd_stats.dist == 0)) {
3491*77c1e3ccSAndroid Build Coastguard Worker     assert(mode_index != THR_INVALID);
3492*77c1e3ccSAndroid Build Coastguard Worker     search_state->best_mbmode.skip_mode = 1;
3493*77c1e3ccSAndroid Build Coastguard Worker     search_state->best_mbmode = *mbmi;
3494*77c1e3ccSAndroid Build Coastguard Worker     memset(search_state->best_mbmode.inter_tx_size,
3495*77c1e3ccSAndroid Build Coastguard Worker            search_state->best_mbmode.tx_size,
3496*77c1e3ccSAndroid Build Coastguard Worker            sizeof(search_state->best_mbmode.inter_tx_size));
3497*77c1e3ccSAndroid Build Coastguard Worker     set_txfm_ctxs(search_state->best_mbmode.tx_size, xd->width, xd->height,
3498*77c1e3ccSAndroid Build Coastguard Worker                   search_state->best_mbmode.skip_txfm && is_inter_block(mbmi),
3499*77c1e3ccSAndroid Build Coastguard Worker                   xd);
3500*77c1e3ccSAndroid Build Coastguard Worker     search_state->best_mode_index = mode_index;
3501*77c1e3ccSAndroid Build Coastguard Worker 
3502*77c1e3ccSAndroid Build Coastguard Worker     // Update rd_cost
3503*77c1e3ccSAndroid Build Coastguard Worker     rd_cost->rate = skip_mode_rd_stats.rate;
3504*77c1e3ccSAndroid Build Coastguard Worker     rd_cost->dist = rd_cost->sse = skip_mode_rd_stats.dist;
3505*77c1e3ccSAndroid Build Coastguard Worker     rd_cost->rdcost = skip_mode_rd_stats.rdcost;
3506*77c1e3ccSAndroid Build Coastguard Worker 
3507*77c1e3ccSAndroid Build Coastguard Worker     search_state->best_rd = rd_cost->rdcost;
3508*77c1e3ccSAndroid Build Coastguard Worker     search_state->best_skip2 = 1;
3509*77c1e3ccSAndroid Build Coastguard Worker     search_state->best_mode_skippable = 1;
3510*77c1e3ccSAndroid Build Coastguard Worker 
3511*77c1e3ccSAndroid Build Coastguard Worker     x->txfm_search_info.skip_txfm = 1;
3512*77c1e3ccSAndroid Build Coastguard Worker   }
3513*77c1e3ccSAndroid Build Coastguard Worker }
3514*77c1e3ccSAndroid Build Coastguard Worker 
3515*77c1e3ccSAndroid Build Coastguard Worker // Get winner mode stats of given mode index
get_winner_mode_stats(MACROBLOCK * x,MB_MODE_INFO * best_mbmode,RD_STATS * best_rd_cost,int best_rate_y,int best_rate_uv,THR_MODES * best_mode_index,RD_STATS ** winner_rd_cost,int * winner_rate_y,int * winner_rate_uv,THR_MODES * winner_mode_index,MULTI_WINNER_MODE_TYPE multi_winner_mode_type,int mode_idx)3516*77c1e3ccSAndroid Build Coastguard Worker static inline MB_MODE_INFO *get_winner_mode_stats(
3517*77c1e3ccSAndroid Build Coastguard Worker     MACROBLOCK *x, MB_MODE_INFO *best_mbmode, RD_STATS *best_rd_cost,
3518*77c1e3ccSAndroid Build Coastguard Worker     int best_rate_y, int best_rate_uv, THR_MODES *best_mode_index,
3519*77c1e3ccSAndroid Build Coastguard Worker     RD_STATS **winner_rd_cost, int *winner_rate_y, int *winner_rate_uv,
3520*77c1e3ccSAndroid Build Coastguard Worker     THR_MODES *winner_mode_index, MULTI_WINNER_MODE_TYPE multi_winner_mode_type,
3521*77c1e3ccSAndroid Build Coastguard Worker     int mode_idx) {
3522*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *winner_mbmi;
3523*77c1e3ccSAndroid Build Coastguard Worker   if (multi_winner_mode_type) {
3524*77c1e3ccSAndroid Build Coastguard Worker     assert(mode_idx >= 0 && mode_idx < x->winner_mode_count);
3525*77c1e3ccSAndroid Build Coastguard Worker     WinnerModeStats *winner_mode_stat = &x->winner_mode_stats[mode_idx];
3526*77c1e3ccSAndroid Build Coastguard Worker     winner_mbmi = &winner_mode_stat->mbmi;
3527*77c1e3ccSAndroid Build Coastguard Worker 
3528*77c1e3ccSAndroid Build Coastguard Worker     *winner_rd_cost = &winner_mode_stat->rd_cost;
3529*77c1e3ccSAndroid Build Coastguard Worker     *winner_rate_y = winner_mode_stat->rate_y;
3530*77c1e3ccSAndroid Build Coastguard Worker     *winner_rate_uv = winner_mode_stat->rate_uv;
3531*77c1e3ccSAndroid Build Coastguard Worker     *winner_mode_index = winner_mode_stat->mode_index;
3532*77c1e3ccSAndroid Build Coastguard Worker   } else {
3533*77c1e3ccSAndroid Build Coastguard Worker     winner_mbmi = best_mbmode;
3534*77c1e3ccSAndroid Build Coastguard Worker     *winner_rd_cost = best_rd_cost;
3535*77c1e3ccSAndroid Build Coastguard Worker     *winner_rate_y = best_rate_y;
3536*77c1e3ccSAndroid Build Coastguard Worker     *winner_rate_uv = best_rate_uv;
3537*77c1e3ccSAndroid Build Coastguard Worker     *winner_mode_index = *best_mode_index;
3538*77c1e3ccSAndroid Build Coastguard Worker   }
3539*77c1e3ccSAndroid Build Coastguard Worker   return winner_mbmi;
3540*77c1e3ccSAndroid Build Coastguard Worker }
3541*77c1e3ccSAndroid Build Coastguard Worker 
3542*77c1e3ccSAndroid Build Coastguard Worker // speed feature: fast intra/inter transform type search
3543*77c1e3ccSAndroid Build Coastguard Worker // Used for speed >= 2
3544*77c1e3ccSAndroid Build Coastguard Worker // When this speed feature is on, in rd mode search, only DCT is used.
3545*77c1e3ccSAndroid Build Coastguard Worker // After the mode is determined, this function is called, to select
3546*77c1e3ccSAndroid Build Coastguard Worker // transform types and get accurate rdcost.
refine_winner_mode_tx(const AV1_COMP * cpi,MACROBLOCK * x,RD_STATS * rd_cost,BLOCK_SIZE bsize,PICK_MODE_CONTEXT * ctx,THR_MODES * best_mode_index,MB_MODE_INFO * best_mbmode,struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE],int best_rate_y,int best_rate_uv,int * best_skip2,int winner_mode_count)3547*77c1e3ccSAndroid Build Coastguard Worker static inline void refine_winner_mode_tx(
3548*77c1e3ccSAndroid Build Coastguard Worker     const AV1_COMP *cpi, MACROBLOCK *x, RD_STATS *rd_cost, BLOCK_SIZE bsize,
3549*77c1e3ccSAndroid Build Coastguard Worker     PICK_MODE_CONTEXT *ctx, THR_MODES *best_mode_index,
3550*77c1e3ccSAndroid Build Coastguard Worker     MB_MODE_INFO *best_mbmode, struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE],
3551*77c1e3ccSAndroid Build Coastguard Worker     int best_rate_y, int best_rate_uv, int *best_skip2, int winner_mode_count) {
3552*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
3553*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *const xd = &x->e_mbd;
3554*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *const mbmi = xd->mi[0];
3555*77c1e3ccSAndroid Build Coastguard Worker   TxfmSearchParams *txfm_params = &x->txfm_search_params;
3556*77c1e3ccSAndroid Build Coastguard Worker   TxfmSearchInfo *txfm_info = &x->txfm_search_info;
3557*77c1e3ccSAndroid Build Coastguard Worker   int64_t best_rd;
3558*77c1e3ccSAndroid Build Coastguard Worker   const int num_planes = av1_num_planes(cm);
3559*77c1e3ccSAndroid Build Coastguard Worker 
3560*77c1e3ccSAndroid Build Coastguard Worker   if (!is_winner_mode_processing_enabled(cpi, x, best_mbmode,
3561*77c1e3ccSAndroid Build Coastguard Worker                                          rd_cost->skip_txfm))
3562*77c1e3ccSAndroid Build Coastguard Worker     return;
3563*77c1e3ccSAndroid Build Coastguard Worker 
3564*77c1e3ccSAndroid Build Coastguard Worker   // Set params for winner mode evaluation
3565*77c1e3ccSAndroid Build Coastguard Worker   set_mode_eval_params(cpi, x, WINNER_MODE_EVAL);
3566*77c1e3ccSAndroid Build Coastguard Worker 
3567*77c1e3ccSAndroid Build Coastguard Worker   // No best mode identified so far
3568*77c1e3ccSAndroid Build Coastguard Worker   if (*best_mode_index == THR_INVALID) return;
3569*77c1e3ccSAndroid Build Coastguard Worker 
3570*77c1e3ccSAndroid Build Coastguard Worker   best_rd = RDCOST(x->rdmult, rd_cost->rate, rd_cost->dist);
3571*77c1e3ccSAndroid Build Coastguard Worker   for (int mode_idx = 0; mode_idx < winner_mode_count; mode_idx++) {
3572*77c1e3ccSAndroid Build Coastguard Worker     RD_STATS *winner_rd_stats = NULL;
3573*77c1e3ccSAndroid Build Coastguard Worker     int winner_rate_y = 0, winner_rate_uv = 0;
3574*77c1e3ccSAndroid Build Coastguard Worker     THR_MODES winner_mode_index = 0;
3575*77c1e3ccSAndroid Build Coastguard Worker 
3576*77c1e3ccSAndroid Build Coastguard Worker     // TODO(any): Combine best mode and multi-winner mode processing paths
3577*77c1e3ccSAndroid Build Coastguard Worker     // Get winner mode stats for current mode index
3578*77c1e3ccSAndroid Build Coastguard Worker     MB_MODE_INFO *winner_mbmi = get_winner_mode_stats(
3579*77c1e3ccSAndroid Build Coastguard Worker         x, best_mbmode, rd_cost, best_rate_y, best_rate_uv, best_mode_index,
3580*77c1e3ccSAndroid Build Coastguard Worker         &winner_rd_stats, &winner_rate_y, &winner_rate_uv, &winner_mode_index,
3581*77c1e3ccSAndroid Build Coastguard Worker         cpi->sf.winner_mode_sf.multi_winner_mode_type, mode_idx);
3582*77c1e3ccSAndroid Build Coastguard Worker 
3583*77c1e3ccSAndroid Build Coastguard Worker     if (xd->lossless[winner_mbmi->segment_id] == 0 &&
3584*77c1e3ccSAndroid Build Coastguard Worker         winner_mode_index != THR_INVALID &&
3585*77c1e3ccSAndroid Build Coastguard Worker         is_winner_mode_processing_enabled(cpi, x, winner_mbmi,
3586*77c1e3ccSAndroid Build Coastguard Worker                                           rd_cost->skip_txfm)) {
3587*77c1e3ccSAndroid Build Coastguard Worker       RD_STATS rd_stats = *winner_rd_stats;
3588*77c1e3ccSAndroid Build Coastguard Worker       int skip_blk = 0;
3589*77c1e3ccSAndroid Build Coastguard Worker       RD_STATS rd_stats_y, rd_stats_uv;
3590*77c1e3ccSAndroid Build Coastguard Worker       const int skip_ctx = av1_get_skip_txfm_context(xd);
3591*77c1e3ccSAndroid Build Coastguard Worker 
3592*77c1e3ccSAndroid Build Coastguard Worker       *mbmi = *winner_mbmi;
3593*77c1e3ccSAndroid Build Coastguard Worker 
3594*77c1e3ccSAndroid Build Coastguard Worker       set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
3595*77c1e3ccSAndroid Build Coastguard Worker 
3596*77c1e3ccSAndroid Build Coastguard Worker       // Select prediction reference frames.
3597*77c1e3ccSAndroid Build Coastguard Worker       for (int i = 0; i < num_planes; i++) {
3598*77c1e3ccSAndroid Build Coastguard Worker         xd->plane[i].pre[0] = yv12_mb[mbmi->ref_frame[0]][i];
3599*77c1e3ccSAndroid Build Coastguard Worker         if (has_second_ref(mbmi))
3600*77c1e3ccSAndroid Build Coastguard Worker           xd->plane[i].pre[1] = yv12_mb[mbmi->ref_frame[1]][i];
3601*77c1e3ccSAndroid Build Coastguard Worker       }
3602*77c1e3ccSAndroid Build Coastguard Worker 
3603*77c1e3ccSAndroid Build Coastguard Worker       if (is_inter_mode(mbmi->mode)) {
3604*77c1e3ccSAndroid Build Coastguard Worker         const int mi_row = xd->mi_row;
3605*77c1e3ccSAndroid Build Coastguard Worker         const int mi_col = xd->mi_col;
3606*77c1e3ccSAndroid Build Coastguard Worker         bool is_predictor_built = false;
3607*77c1e3ccSAndroid Build Coastguard Worker         const PREDICTION_MODE prediction_mode = mbmi->mode;
3608*77c1e3ccSAndroid Build Coastguard Worker         // Do interpolation filter search for realtime mode if applicable.
3609*77c1e3ccSAndroid Build Coastguard Worker         if (cpi->sf.winner_mode_sf.winner_mode_ifs &&
3610*77c1e3ccSAndroid Build Coastguard Worker             cpi->oxcf.mode == REALTIME &&
3611*77c1e3ccSAndroid Build Coastguard Worker             cm->current_frame.reference_mode == SINGLE_REFERENCE &&
3612*77c1e3ccSAndroid Build Coastguard Worker             is_inter_mode(prediction_mode) &&
3613*77c1e3ccSAndroid Build Coastguard Worker             mbmi->motion_mode == SIMPLE_TRANSLATION &&
3614*77c1e3ccSAndroid Build Coastguard Worker             !is_inter_compound_mode(prediction_mode)) {
3615*77c1e3ccSAndroid Build Coastguard Worker           is_predictor_built =
3616*77c1e3ccSAndroid Build Coastguard Worker               fast_interp_search(cpi, x, mi_row, mi_col, bsize);
3617*77c1e3ccSAndroid Build Coastguard Worker         }
3618*77c1e3ccSAndroid Build Coastguard Worker         if (!is_predictor_built) {
3619*77c1e3ccSAndroid Build Coastguard Worker           av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, 0,
3620*77c1e3ccSAndroid Build Coastguard Worker                                         av1_num_planes(cm) - 1);
3621*77c1e3ccSAndroid Build Coastguard Worker         }
3622*77c1e3ccSAndroid Build Coastguard Worker         if (mbmi->motion_mode == OBMC_CAUSAL)
3623*77c1e3ccSAndroid Build Coastguard Worker           av1_build_obmc_inter_predictors_sb(cm, xd);
3624*77c1e3ccSAndroid Build Coastguard Worker 
3625*77c1e3ccSAndroid Build Coastguard Worker         av1_subtract_plane(x, bsize, 0);
3626*77c1e3ccSAndroid Build Coastguard Worker         if (txfm_params->tx_mode_search_type == TX_MODE_SELECT &&
3627*77c1e3ccSAndroid Build Coastguard Worker             !xd->lossless[mbmi->segment_id]) {
3628*77c1e3ccSAndroid Build Coastguard Worker           av1_pick_recursive_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize,
3629*77c1e3ccSAndroid Build Coastguard Worker                                               INT64_MAX);
3630*77c1e3ccSAndroid Build Coastguard Worker           assert(rd_stats_y.rate != INT_MAX);
3631*77c1e3ccSAndroid Build Coastguard Worker         } else {
3632*77c1e3ccSAndroid Build Coastguard Worker           av1_pick_uniform_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize,
3633*77c1e3ccSAndroid Build Coastguard Worker                                             INT64_MAX);
3634*77c1e3ccSAndroid Build Coastguard Worker           memset(mbmi->inter_tx_size, mbmi->tx_size,
3635*77c1e3ccSAndroid Build Coastguard Worker                  sizeof(mbmi->inter_tx_size));
3636*77c1e3ccSAndroid Build Coastguard Worker           for (int i = 0; i < xd->height * xd->width; ++i)
3637*77c1e3ccSAndroid Build Coastguard Worker             set_blk_skip(txfm_info->blk_skip, 0, i, rd_stats_y.skip_txfm);
3638*77c1e3ccSAndroid Build Coastguard Worker         }
3639*77c1e3ccSAndroid Build Coastguard Worker       } else {
3640*77c1e3ccSAndroid Build Coastguard Worker         av1_pick_uniform_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize,
3641*77c1e3ccSAndroid Build Coastguard Worker                                           INT64_MAX);
3642*77c1e3ccSAndroid Build Coastguard Worker       }
3643*77c1e3ccSAndroid Build Coastguard Worker 
3644*77c1e3ccSAndroid Build Coastguard Worker       if (num_planes > 1) {
3645*77c1e3ccSAndroid Build Coastguard Worker         av1_txfm_uvrd(cpi, x, &rd_stats_uv, bsize, INT64_MAX);
3646*77c1e3ccSAndroid Build Coastguard Worker       } else {
3647*77c1e3ccSAndroid Build Coastguard Worker         av1_init_rd_stats(&rd_stats_uv);
3648*77c1e3ccSAndroid Build Coastguard Worker       }
3649*77c1e3ccSAndroid Build Coastguard Worker 
3650*77c1e3ccSAndroid Build Coastguard Worker       const ModeCosts *mode_costs = &x->mode_costs;
3651*77c1e3ccSAndroid Build Coastguard Worker       if (is_inter_mode(mbmi->mode) &&
3652*77c1e3ccSAndroid Build Coastguard Worker           RDCOST(x->rdmult,
3653*77c1e3ccSAndroid Build Coastguard Worker                  mode_costs->skip_txfm_cost[skip_ctx][0] + rd_stats_y.rate +
3654*77c1e3ccSAndroid Build Coastguard Worker                      rd_stats_uv.rate,
3655*77c1e3ccSAndroid Build Coastguard Worker                  (rd_stats_y.dist + rd_stats_uv.dist)) >
3656*77c1e3ccSAndroid Build Coastguard Worker               RDCOST(x->rdmult, mode_costs->skip_txfm_cost[skip_ctx][1],
3657*77c1e3ccSAndroid Build Coastguard Worker                      (rd_stats_y.sse + rd_stats_uv.sse))) {
3658*77c1e3ccSAndroid Build Coastguard Worker         skip_blk = 1;
3659*77c1e3ccSAndroid Build Coastguard Worker         rd_stats_y.rate = mode_costs->skip_txfm_cost[skip_ctx][1];
3660*77c1e3ccSAndroid Build Coastguard Worker         rd_stats_uv.rate = 0;
3661*77c1e3ccSAndroid Build Coastguard Worker         rd_stats_y.dist = rd_stats_y.sse;
3662*77c1e3ccSAndroid Build Coastguard Worker         rd_stats_uv.dist = rd_stats_uv.sse;
3663*77c1e3ccSAndroid Build Coastguard Worker       } else {
3664*77c1e3ccSAndroid Build Coastguard Worker         skip_blk = 0;
3665*77c1e3ccSAndroid Build Coastguard Worker         rd_stats_y.rate += mode_costs->skip_txfm_cost[skip_ctx][0];
3666*77c1e3ccSAndroid Build Coastguard Worker       }
3667*77c1e3ccSAndroid Build Coastguard Worker       int this_rate = rd_stats.rate + rd_stats_y.rate + rd_stats_uv.rate -
3668*77c1e3ccSAndroid Build Coastguard Worker                       winner_rate_y - winner_rate_uv;
3669*77c1e3ccSAndroid Build Coastguard Worker       int64_t this_rd =
3670*77c1e3ccSAndroid Build Coastguard Worker           RDCOST(x->rdmult, this_rate, (rd_stats_y.dist + rd_stats_uv.dist));
3671*77c1e3ccSAndroid Build Coastguard Worker       if (best_rd > this_rd) {
3672*77c1e3ccSAndroid Build Coastguard Worker         *best_mbmode = *mbmi;
3673*77c1e3ccSAndroid Build Coastguard Worker         *best_mode_index = winner_mode_index;
3674*77c1e3ccSAndroid Build Coastguard Worker         av1_copy_array(ctx->blk_skip, txfm_info->blk_skip, ctx->num_4x4_blk);
3675*77c1e3ccSAndroid Build Coastguard Worker         av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
3676*77c1e3ccSAndroid Build Coastguard Worker         rd_cost->rate = this_rate;
3677*77c1e3ccSAndroid Build Coastguard Worker         rd_cost->dist = rd_stats_y.dist + rd_stats_uv.dist;
3678*77c1e3ccSAndroid Build Coastguard Worker         rd_cost->sse = rd_stats_y.sse + rd_stats_uv.sse;
3679*77c1e3ccSAndroid Build Coastguard Worker         rd_cost->rdcost = this_rd;
3680*77c1e3ccSAndroid Build Coastguard Worker         best_rd = this_rd;
3681*77c1e3ccSAndroid Build Coastguard Worker         *best_skip2 = skip_blk;
3682*77c1e3ccSAndroid Build Coastguard Worker       }
3683*77c1e3ccSAndroid Build Coastguard Worker     }
3684*77c1e3ccSAndroid Build Coastguard Worker   }
3685*77c1e3ccSAndroid Build Coastguard Worker }
3686*77c1e3ccSAndroid Build Coastguard Worker 
3687*77c1e3ccSAndroid Build Coastguard Worker /*!\cond */
3688*77c1e3ccSAndroid Build Coastguard Worker typedef struct {
3689*77c1e3ccSAndroid Build Coastguard Worker   // Mask for each reference frame, specifying which prediction modes to NOT try
3690*77c1e3ccSAndroid Build Coastguard Worker   // during search.
3691*77c1e3ccSAndroid Build Coastguard Worker   uint32_t pred_modes[REF_FRAMES];
3692*77c1e3ccSAndroid Build Coastguard Worker   // If ref_combo[i][j + 1] is true, do NOT try prediction using combination of
3693*77c1e3ccSAndroid Build Coastguard Worker   // reference frames (i, j).
3694*77c1e3ccSAndroid Build Coastguard Worker   // Note: indexing with 'j + 1' is due to the fact that 2nd reference can be -1
3695*77c1e3ccSAndroid Build Coastguard Worker   // (NONE_FRAME).
3696*77c1e3ccSAndroid Build Coastguard Worker   bool ref_combo[REF_FRAMES][REF_FRAMES + 1];
3697*77c1e3ccSAndroid Build Coastguard Worker } mode_skip_mask_t;
3698*77c1e3ccSAndroid Build Coastguard Worker /*!\endcond */
3699*77c1e3ccSAndroid Build Coastguard Worker 
3700*77c1e3ccSAndroid Build Coastguard Worker // Update 'ref_combo' mask to disable given 'ref' in single and compound modes.
disable_reference(MV_REFERENCE_FRAME ref,bool ref_combo[REF_FRAMES][REF_FRAMES+1])3701*77c1e3ccSAndroid Build Coastguard Worker static inline void disable_reference(
3702*77c1e3ccSAndroid Build Coastguard Worker     MV_REFERENCE_FRAME ref, bool ref_combo[REF_FRAMES][REF_FRAMES + 1]) {
3703*77c1e3ccSAndroid Build Coastguard Worker   for (MV_REFERENCE_FRAME ref2 = NONE_FRAME; ref2 < REF_FRAMES; ++ref2) {
3704*77c1e3ccSAndroid Build Coastguard Worker     ref_combo[ref][ref2 + 1] = true;
3705*77c1e3ccSAndroid Build Coastguard Worker   }
3706*77c1e3ccSAndroid Build Coastguard Worker }
3707*77c1e3ccSAndroid Build Coastguard Worker 
3708*77c1e3ccSAndroid Build Coastguard Worker // Update 'ref_combo' mask to disable all inter references except ALTREF.
disable_inter_references_except_altref(bool ref_combo[REF_FRAMES][REF_FRAMES+1])3709*77c1e3ccSAndroid Build Coastguard Worker static inline void disable_inter_references_except_altref(
3710*77c1e3ccSAndroid Build Coastguard Worker     bool ref_combo[REF_FRAMES][REF_FRAMES + 1]) {
3711*77c1e3ccSAndroid Build Coastguard Worker   disable_reference(LAST_FRAME, ref_combo);
3712*77c1e3ccSAndroid Build Coastguard Worker   disable_reference(LAST2_FRAME, ref_combo);
3713*77c1e3ccSAndroid Build Coastguard Worker   disable_reference(LAST3_FRAME, ref_combo);
3714*77c1e3ccSAndroid Build Coastguard Worker   disable_reference(GOLDEN_FRAME, ref_combo);
3715*77c1e3ccSAndroid Build Coastguard Worker   disable_reference(BWDREF_FRAME, ref_combo);
3716*77c1e3ccSAndroid Build Coastguard Worker   disable_reference(ALTREF2_FRAME, ref_combo);
3717*77c1e3ccSAndroid Build Coastguard Worker }
3718*77c1e3ccSAndroid Build Coastguard Worker 
3719*77c1e3ccSAndroid Build Coastguard Worker static const MV_REFERENCE_FRAME reduced_ref_combos[][2] = {
3720*77c1e3ccSAndroid Build Coastguard Worker   { LAST_FRAME, NONE_FRAME },     { ALTREF_FRAME, NONE_FRAME },
3721*77c1e3ccSAndroid Build Coastguard Worker   { LAST_FRAME, ALTREF_FRAME },   { GOLDEN_FRAME, NONE_FRAME },
3722*77c1e3ccSAndroid Build Coastguard Worker   { INTRA_FRAME, NONE_FRAME },    { GOLDEN_FRAME, ALTREF_FRAME },
3723*77c1e3ccSAndroid Build Coastguard Worker   { LAST_FRAME, GOLDEN_FRAME },   { LAST_FRAME, INTRA_FRAME },
3724*77c1e3ccSAndroid Build Coastguard Worker   { LAST_FRAME, BWDREF_FRAME },   { LAST_FRAME, LAST3_FRAME },
3725*77c1e3ccSAndroid Build Coastguard Worker   { GOLDEN_FRAME, BWDREF_FRAME }, { GOLDEN_FRAME, INTRA_FRAME },
3726*77c1e3ccSAndroid Build Coastguard Worker   { BWDREF_FRAME, NONE_FRAME },   { BWDREF_FRAME, ALTREF_FRAME },
3727*77c1e3ccSAndroid Build Coastguard Worker   { ALTREF_FRAME, INTRA_FRAME },  { BWDREF_FRAME, INTRA_FRAME },
3728*77c1e3ccSAndroid Build Coastguard Worker };
3729*77c1e3ccSAndroid Build Coastguard Worker 
3730*77c1e3ccSAndroid Build Coastguard Worker typedef enum { REF_SET_FULL, REF_SET_REDUCED, REF_SET_REALTIME } REF_SET;
3731*77c1e3ccSAndroid Build Coastguard Worker 
default_skip_mask(mode_skip_mask_t * mask,REF_SET ref_set)3732*77c1e3ccSAndroid Build Coastguard Worker static inline void default_skip_mask(mode_skip_mask_t *mask, REF_SET ref_set) {
3733*77c1e3ccSAndroid Build Coastguard Worker   if (ref_set == REF_SET_FULL) {
3734*77c1e3ccSAndroid Build Coastguard Worker     // Everything available by default.
3735*77c1e3ccSAndroid Build Coastguard Worker     memset(mask, 0, sizeof(*mask));
3736*77c1e3ccSAndroid Build Coastguard Worker   } else {
3737*77c1e3ccSAndroid Build Coastguard Worker     // All modes available by default.
3738*77c1e3ccSAndroid Build Coastguard Worker     memset(mask->pred_modes, 0, sizeof(mask->pred_modes));
3739*77c1e3ccSAndroid Build Coastguard Worker     // All references disabled first.
3740*77c1e3ccSAndroid Build Coastguard Worker     for (MV_REFERENCE_FRAME ref1 = INTRA_FRAME; ref1 < REF_FRAMES; ++ref1) {
3741*77c1e3ccSAndroid Build Coastguard Worker       for (MV_REFERENCE_FRAME ref2 = NONE_FRAME; ref2 < REF_FRAMES; ++ref2) {
3742*77c1e3ccSAndroid Build Coastguard Worker         mask->ref_combo[ref1][ref2 + 1] = true;
3743*77c1e3ccSAndroid Build Coastguard Worker       }
3744*77c1e3ccSAndroid Build Coastguard Worker     }
3745*77c1e3ccSAndroid Build Coastguard Worker     const MV_REFERENCE_FRAME(*ref_set_combos)[2];
3746*77c1e3ccSAndroid Build Coastguard Worker     int num_ref_combos;
3747*77c1e3ccSAndroid Build Coastguard Worker 
3748*77c1e3ccSAndroid Build Coastguard Worker     // Then enable reduced set of references explicitly.
3749*77c1e3ccSAndroid Build Coastguard Worker     switch (ref_set) {
3750*77c1e3ccSAndroid Build Coastguard Worker       case REF_SET_REDUCED:
3751*77c1e3ccSAndroid Build Coastguard Worker         ref_set_combos = reduced_ref_combos;
3752*77c1e3ccSAndroid Build Coastguard Worker         num_ref_combos =
3753*77c1e3ccSAndroid Build Coastguard Worker             (int)sizeof(reduced_ref_combos) / sizeof(reduced_ref_combos[0]);
3754*77c1e3ccSAndroid Build Coastguard Worker         break;
3755*77c1e3ccSAndroid Build Coastguard Worker       case REF_SET_REALTIME:
3756*77c1e3ccSAndroid Build Coastguard Worker         ref_set_combos = real_time_ref_combos;
3757*77c1e3ccSAndroid Build Coastguard Worker         num_ref_combos =
3758*77c1e3ccSAndroid Build Coastguard Worker             (int)sizeof(real_time_ref_combos) / sizeof(real_time_ref_combos[0]);
3759*77c1e3ccSAndroid Build Coastguard Worker         break;
3760*77c1e3ccSAndroid Build Coastguard Worker       default: assert(0); num_ref_combos = 0;
3761*77c1e3ccSAndroid Build Coastguard Worker     }
3762*77c1e3ccSAndroid Build Coastguard Worker 
3763*77c1e3ccSAndroid Build Coastguard Worker     for (int i = 0; i < num_ref_combos; ++i) {
3764*77c1e3ccSAndroid Build Coastguard Worker       const MV_REFERENCE_FRAME *const this_combo = ref_set_combos[i];
3765*77c1e3ccSAndroid Build Coastguard Worker       mask->ref_combo[this_combo[0]][this_combo[1] + 1] = false;
3766*77c1e3ccSAndroid Build Coastguard Worker     }
3767*77c1e3ccSAndroid Build Coastguard Worker   }
3768*77c1e3ccSAndroid Build Coastguard Worker }
3769*77c1e3ccSAndroid Build Coastguard Worker 
init_mode_skip_mask(mode_skip_mask_t * mask,const AV1_COMP * cpi,MACROBLOCK * x,BLOCK_SIZE bsize)3770*77c1e3ccSAndroid Build Coastguard Worker static inline void init_mode_skip_mask(mode_skip_mask_t *mask,
3771*77c1e3ccSAndroid Build Coastguard Worker                                        const AV1_COMP *cpi, MACROBLOCK *x,
3772*77c1e3ccSAndroid Build Coastguard Worker                                        BLOCK_SIZE bsize) {
3773*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
3774*77c1e3ccSAndroid Build Coastguard Worker   const struct segmentation *const seg = &cm->seg;
3775*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *const xd = &x->e_mbd;
3776*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *const mbmi = xd->mi[0];
3777*77c1e3ccSAndroid Build Coastguard Worker   unsigned char segment_id = mbmi->segment_id;
3778*77c1e3ccSAndroid Build Coastguard Worker   const SPEED_FEATURES *const sf = &cpi->sf;
3779*77c1e3ccSAndroid Build Coastguard Worker   const INTER_MODE_SPEED_FEATURES *const inter_sf = &sf->inter_sf;
3780*77c1e3ccSAndroid Build Coastguard Worker   REF_SET ref_set = REF_SET_FULL;
3781*77c1e3ccSAndroid Build Coastguard Worker 
3782*77c1e3ccSAndroid Build Coastguard Worker   if (sf->rt_sf.use_real_time_ref_set)
3783*77c1e3ccSAndroid Build Coastguard Worker     ref_set = REF_SET_REALTIME;
3784*77c1e3ccSAndroid Build Coastguard Worker   else if (cpi->oxcf.ref_frm_cfg.enable_reduced_reference_set)
3785*77c1e3ccSAndroid Build Coastguard Worker     ref_set = REF_SET_REDUCED;
3786*77c1e3ccSAndroid Build Coastguard Worker 
3787*77c1e3ccSAndroid Build Coastguard Worker   default_skip_mask(mask, ref_set);
3788*77c1e3ccSAndroid Build Coastguard Worker 
3789*77c1e3ccSAndroid Build Coastguard Worker   int min_pred_mv_sad = INT_MAX;
3790*77c1e3ccSAndroid Build Coastguard Worker   MV_REFERENCE_FRAME ref_frame;
3791*77c1e3ccSAndroid Build Coastguard Worker   if (ref_set == REF_SET_REALTIME) {
3792*77c1e3ccSAndroid Build Coastguard Worker     // For real-time encoding, we only look at a subset of ref frames. So the
3793*77c1e3ccSAndroid Build Coastguard Worker     // threshold for pruning should be computed from this subset as well.
3794*77c1e3ccSAndroid Build Coastguard Worker     const int num_rt_refs =
3795*77c1e3ccSAndroid Build Coastguard Worker         sizeof(real_time_ref_combos) / sizeof(*real_time_ref_combos);
3796*77c1e3ccSAndroid Build Coastguard Worker     for (int r_idx = 0; r_idx < num_rt_refs; r_idx++) {
3797*77c1e3ccSAndroid Build Coastguard Worker       const MV_REFERENCE_FRAME ref = real_time_ref_combos[r_idx][0];
3798*77c1e3ccSAndroid Build Coastguard Worker       if (ref != INTRA_FRAME) {
3799*77c1e3ccSAndroid Build Coastguard Worker         min_pred_mv_sad = AOMMIN(min_pred_mv_sad, x->pred_mv_sad[ref]);
3800*77c1e3ccSAndroid Build Coastguard Worker       }
3801*77c1e3ccSAndroid Build Coastguard Worker     }
3802*77c1e3ccSAndroid Build Coastguard Worker   } else {
3803*77c1e3ccSAndroid Build Coastguard Worker     for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame)
3804*77c1e3ccSAndroid Build Coastguard Worker       min_pred_mv_sad = AOMMIN(min_pred_mv_sad, x->pred_mv_sad[ref_frame]);
3805*77c1e3ccSAndroid Build Coastguard Worker   }
3806*77c1e3ccSAndroid Build Coastguard Worker 
3807*77c1e3ccSAndroid Build Coastguard Worker   for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
3808*77c1e3ccSAndroid Build Coastguard Worker     if (!(cpi->ref_frame_flags & av1_ref_frame_flag_list[ref_frame])) {
3809*77c1e3ccSAndroid Build Coastguard Worker       // Skip checking missing reference in both single and compound reference
3810*77c1e3ccSAndroid Build Coastguard Worker       // modes.
3811*77c1e3ccSAndroid Build Coastguard Worker       disable_reference(ref_frame, mask->ref_combo);
3812*77c1e3ccSAndroid Build Coastguard Worker     } else {
3813*77c1e3ccSAndroid Build Coastguard Worker       // Skip fixed mv modes for poor references
3814*77c1e3ccSAndroid Build Coastguard Worker       if ((x->pred_mv_sad[ref_frame] >> 2) > min_pred_mv_sad) {
3815*77c1e3ccSAndroid Build Coastguard Worker         mask->pred_modes[ref_frame] |= INTER_NEAREST_NEAR_ZERO;
3816*77c1e3ccSAndroid Build Coastguard Worker       }
3817*77c1e3ccSAndroid Build Coastguard Worker     }
3818*77c1e3ccSAndroid Build Coastguard Worker     if (segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME) &&
3819*77c1e3ccSAndroid Build Coastguard Worker         get_segdata(seg, segment_id, SEG_LVL_REF_FRAME) != (int)ref_frame) {
3820*77c1e3ccSAndroid Build Coastguard Worker       // Reference not used for the segment.
3821*77c1e3ccSAndroid Build Coastguard Worker       disable_reference(ref_frame, mask->ref_combo);
3822*77c1e3ccSAndroid Build Coastguard Worker     }
3823*77c1e3ccSAndroid Build Coastguard Worker   }
3824*77c1e3ccSAndroid Build Coastguard Worker   // Note: We use the following drop-out only if the SEG_LVL_REF_FRAME feature
3825*77c1e3ccSAndroid Build Coastguard Worker   // is disabled for this segment. This is to prevent the possibility that we
3826*77c1e3ccSAndroid Build Coastguard Worker   // end up unable to pick any mode.
3827*77c1e3ccSAndroid Build Coastguard Worker   if (!segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME)) {
3828*77c1e3ccSAndroid Build Coastguard Worker     // Only consider GLOBALMV/ALTREF_FRAME for alt ref frame,
3829*77c1e3ccSAndroid Build Coastguard Worker     // unless ARNR filtering is enabled in which case we want
3830*77c1e3ccSAndroid Build Coastguard Worker     // an unfiltered alternative. We allow near/nearest as well
3831*77c1e3ccSAndroid Build Coastguard Worker     // because they may result in zero-zero MVs but be cheaper.
3832*77c1e3ccSAndroid Build Coastguard Worker     if (cpi->rc.is_src_frame_alt_ref &&
3833*77c1e3ccSAndroid Build Coastguard Worker         (cpi->oxcf.algo_cfg.arnr_max_frames == 0)) {
3834*77c1e3ccSAndroid Build Coastguard Worker       disable_inter_references_except_altref(mask->ref_combo);
3835*77c1e3ccSAndroid Build Coastguard Worker 
3836*77c1e3ccSAndroid Build Coastguard Worker       mask->pred_modes[ALTREF_FRAME] = ~INTER_NEAREST_NEAR_ZERO;
3837*77c1e3ccSAndroid Build Coastguard Worker       const MV_REFERENCE_FRAME tmp_ref_frames[2] = { ALTREF_FRAME, NONE_FRAME };
3838*77c1e3ccSAndroid Build Coastguard Worker       int_mv near_mv, nearest_mv, global_mv;
3839*77c1e3ccSAndroid Build Coastguard Worker       get_this_mv(&nearest_mv, NEARESTMV, 0, 0, 0, tmp_ref_frames,
3840*77c1e3ccSAndroid Build Coastguard Worker                   &x->mbmi_ext);
3841*77c1e3ccSAndroid Build Coastguard Worker       get_this_mv(&near_mv, NEARMV, 0, 0, 0, tmp_ref_frames, &x->mbmi_ext);
3842*77c1e3ccSAndroid Build Coastguard Worker       get_this_mv(&global_mv, GLOBALMV, 0, 0, 0, tmp_ref_frames, &x->mbmi_ext);
3843*77c1e3ccSAndroid Build Coastguard Worker 
3844*77c1e3ccSAndroid Build Coastguard Worker       if (near_mv.as_int != global_mv.as_int)
3845*77c1e3ccSAndroid Build Coastguard Worker         mask->pred_modes[ALTREF_FRAME] |= (1 << NEARMV);
3846*77c1e3ccSAndroid Build Coastguard Worker       if (nearest_mv.as_int != global_mv.as_int)
3847*77c1e3ccSAndroid Build Coastguard Worker         mask->pred_modes[ALTREF_FRAME] |= (1 << NEARESTMV);
3848*77c1e3ccSAndroid Build Coastguard Worker     }
3849*77c1e3ccSAndroid Build Coastguard Worker   }
3850*77c1e3ccSAndroid Build Coastguard Worker 
3851*77c1e3ccSAndroid Build Coastguard Worker   if (cpi->rc.is_src_frame_alt_ref) {
3852*77c1e3ccSAndroid Build Coastguard Worker     if (inter_sf->alt_ref_search_fp &&
3853*77c1e3ccSAndroid Build Coastguard Worker         (cpi->ref_frame_flags & av1_ref_frame_flag_list[ALTREF_FRAME])) {
3854*77c1e3ccSAndroid Build Coastguard Worker       mask->pred_modes[ALTREF_FRAME] = 0;
3855*77c1e3ccSAndroid Build Coastguard Worker       disable_inter_references_except_altref(mask->ref_combo);
3856*77c1e3ccSAndroid Build Coastguard Worker       disable_reference(INTRA_FRAME, mask->ref_combo);
3857*77c1e3ccSAndroid Build Coastguard Worker     }
3858*77c1e3ccSAndroid Build Coastguard Worker   }
3859*77c1e3ccSAndroid Build Coastguard Worker 
3860*77c1e3ccSAndroid Build Coastguard Worker   if (inter_sf->alt_ref_search_fp) {
3861*77c1e3ccSAndroid Build Coastguard Worker     if (!cm->show_frame && x->best_pred_mv_sad[0] < INT_MAX) {
3862*77c1e3ccSAndroid Build Coastguard Worker       int sad_thresh = x->best_pred_mv_sad[0] + (x->best_pred_mv_sad[0] >> 3);
3863*77c1e3ccSAndroid Build Coastguard Worker       // Conservatively skip the modes w.r.t. BWDREF, ALTREF2 and ALTREF, if
3864*77c1e3ccSAndroid Build Coastguard Worker       // those are past frames
3865*77c1e3ccSAndroid Build Coastguard Worker       MV_REFERENCE_FRAME start_frame =
3866*77c1e3ccSAndroid Build Coastguard Worker           inter_sf->alt_ref_search_fp == 1 ? ALTREF2_FRAME : BWDREF_FRAME;
3867*77c1e3ccSAndroid Build Coastguard Worker       for (ref_frame = start_frame; ref_frame <= ALTREF_FRAME; ref_frame++) {
3868*77c1e3ccSAndroid Build Coastguard Worker         if (cpi->ref_frame_dist_info.ref_relative_dist[ref_frame - LAST_FRAME] <
3869*77c1e3ccSAndroid Build Coastguard Worker             0) {
3870*77c1e3ccSAndroid Build Coastguard Worker           // Prune inter modes when relative dist of ALTREF2 and ALTREF is close
3871*77c1e3ccSAndroid Build Coastguard Worker           // to the relative dist of LAST_FRAME.
3872*77c1e3ccSAndroid Build Coastguard Worker           if (inter_sf->alt_ref_search_fp == 1 &&
3873*77c1e3ccSAndroid Build Coastguard Worker               (abs(cpi->ref_frame_dist_info
3874*77c1e3ccSAndroid Build Coastguard Worker                        .ref_relative_dist[ref_frame - LAST_FRAME]) >
3875*77c1e3ccSAndroid Build Coastguard Worker                1.5 * abs(cpi->ref_frame_dist_info
3876*77c1e3ccSAndroid Build Coastguard Worker                              .ref_relative_dist[LAST_FRAME - LAST_FRAME]))) {
3877*77c1e3ccSAndroid Build Coastguard Worker             continue;
3878*77c1e3ccSAndroid Build Coastguard Worker           }
3879*77c1e3ccSAndroid Build Coastguard Worker           if (x->pred_mv_sad[ref_frame] > sad_thresh)
3880*77c1e3ccSAndroid Build Coastguard Worker             mask->pred_modes[ref_frame] |= INTER_ALL;
3881*77c1e3ccSAndroid Build Coastguard Worker         }
3882*77c1e3ccSAndroid Build Coastguard Worker       }
3883*77c1e3ccSAndroid Build Coastguard Worker     }
3884*77c1e3ccSAndroid Build Coastguard Worker   }
3885*77c1e3ccSAndroid Build Coastguard Worker 
3886*77c1e3ccSAndroid Build Coastguard Worker   if (sf->rt_sf.prune_inter_modes_wrt_gf_arf_based_on_sad) {
3887*77c1e3ccSAndroid Build Coastguard Worker     if (x->best_pred_mv_sad[0] < INT_MAX) {
3888*77c1e3ccSAndroid Build Coastguard Worker       int sad_thresh = x->best_pred_mv_sad[0] + (x->best_pred_mv_sad[0] >> 1);
3889*77c1e3ccSAndroid Build Coastguard Worker       const int prune_ref_list[2] = { GOLDEN_FRAME, ALTREF_FRAME };
3890*77c1e3ccSAndroid Build Coastguard Worker 
3891*77c1e3ccSAndroid Build Coastguard Worker       // Conservatively skip the modes w.r.t. GOLDEN and ALTREF references
3892*77c1e3ccSAndroid Build Coastguard Worker       for (int ref_idx = 0; ref_idx < 2; ref_idx++) {
3893*77c1e3ccSAndroid Build Coastguard Worker         ref_frame = prune_ref_list[ref_idx];
3894*77c1e3ccSAndroid Build Coastguard Worker         if (x->pred_mv_sad[ref_frame] > sad_thresh)
3895*77c1e3ccSAndroid Build Coastguard Worker           mask->pred_modes[ref_frame] |= INTER_NEAREST_NEAR_ZERO;
3896*77c1e3ccSAndroid Build Coastguard Worker       }
3897*77c1e3ccSAndroid Build Coastguard Worker     }
3898*77c1e3ccSAndroid Build Coastguard Worker   }
3899*77c1e3ccSAndroid Build Coastguard Worker 
3900*77c1e3ccSAndroid Build Coastguard Worker   if (bsize > sf->part_sf.max_intra_bsize) {
3901*77c1e3ccSAndroid Build Coastguard Worker     disable_reference(INTRA_FRAME, mask->ref_combo);
3902*77c1e3ccSAndroid Build Coastguard Worker   }
3903*77c1e3ccSAndroid Build Coastguard Worker 
3904*77c1e3ccSAndroid Build Coastguard Worker   if (!cpi->oxcf.tool_cfg.enable_global_motion) {
3905*77c1e3ccSAndroid Build Coastguard Worker     for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
3906*77c1e3ccSAndroid Build Coastguard Worker       mask->pred_modes[ref_frame] |= (1 << GLOBALMV);
3907*77c1e3ccSAndroid Build Coastguard Worker       mask->pred_modes[ref_frame] |= (1 << GLOBAL_GLOBALMV);
3908*77c1e3ccSAndroid Build Coastguard Worker     }
3909*77c1e3ccSAndroid Build Coastguard Worker   }
3910*77c1e3ccSAndroid Build Coastguard Worker 
3911*77c1e3ccSAndroid Build Coastguard Worker   mask->pred_modes[INTRA_FRAME] |=
3912*77c1e3ccSAndroid Build Coastguard Worker       ~(uint32_t)sf->intra_sf.intra_y_mode_mask[max_txsize_lookup[bsize]];
3913*77c1e3ccSAndroid Build Coastguard Worker 
3914*77c1e3ccSAndroid Build Coastguard Worker   // Prune reference frames which are not the closest to the current
3915*77c1e3ccSAndroid Build Coastguard Worker   // frame and with large pred_mv_sad.
3916*77c1e3ccSAndroid Build Coastguard Worker   if (inter_sf->prune_single_ref) {
3917*77c1e3ccSAndroid Build Coastguard Worker     assert(inter_sf->prune_single_ref > 0 && inter_sf->prune_single_ref < 3);
3918*77c1e3ccSAndroid Build Coastguard Worker     const double prune_threshes[2] = { 1.20, 1.05 };
3919*77c1e3ccSAndroid Build Coastguard Worker 
3920*77c1e3ccSAndroid Build Coastguard Worker     for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
3921*77c1e3ccSAndroid Build Coastguard Worker       const RefFrameDistanceInfo *const ref_frame_dist_info =
3922*77c1e3ccSAndroid Build Coastguard Worker           &cpi->ref_frame_dist_info;
3923*77c1e3ccSAndroid Build Coastguard Worker       const int is_closest_ref =
3924*77c1e3ccSAndroid Build Coastguard Worker           (ref_frame == ref_frame_dist_info->nearest_past_ref) ||
3925*77c1e3ccSAndroid Build Coastguard Worker           (ref_frame == ref_frame_dist_info->nearest_future_ref);
3926*77c1e3ccSAndroid Build Coastguard Worker 
3927*77c1e3ccSAndroid Build Coastguard Worker       if (!is_closest_ref) {
3928*77c1e3ccSAndroid Build Coastguard Worker         const int dir =
3929*77c1e3ccSAndroid Build Coastguard Worker             (ref_frame_dist_info->ref_relative_dist[ref_frame - LAST_FRAME] < 0)
3930*77c1e3ccSAndroid Build Coastguard Worker                 ? 0
3931*77c1e3ccSAndroid Build Coastguard Worker                 : 1;
3932*77c1e3ccSAndroid Build Coastguard Worker         if (x->best_pred_mv_sad[dir] < INT_MAX &&
3933*77c1e3ccSAndroid Build Coastguard Worker             x->pred_mv_sad[ref_frame] >
3934*77c1e3ccSAndroid Build Coastguard Worker                 prune_threshes[inter_sf->prune_single_ref - 1] *
3935*77c1e3ccSAndroid Build Coastguard Worker                     x->best_pred_mv_sad[dir])
3936*77c1e3ccSAndroid Build Coastguard Worker           mask->pred_modes[ref_frame] |= INTER_SINGLE_ALL;
3937*77c1e3ccSAndroid Build Coastguard Worker       }
3938*77c1e3ccSAndroid Build Coastguard Worker     }
3939*77c1e3ccSAndroid Build Coastguard Worker   }
3940*77c1e3ccSAndroid Build Coastguard Worker }
3941*77c1e3ccSAndroid Build Coastguard Worker 
init_neighbor_pred_buf(const OBMCBuffer * const obmc_buffer,HandleInterModeArgs * const args,int is_hbd)3942*77c1e3ccSAndroid Build Coastguard Worker static inline void init_neighbor_pred_buf(const OBMCBuffer *const obmc_buffer,
3943*77c1e3ccSAndroid Build Coastguard Worker                                           HandleInterModeArgs *const args,
3944*77c1e3ccSAndroid Build Coastguard Worker                                           int is_hbd) {
3945*77c1e3ccSAndroid Build Coastguard Worker   if (is_hbd) {
3946*77c1e3ccSAndroid Build Coastguard Worker     const int len = sizeof(uint16_t);
3947*77c1e3ccSAndroid Build Coastguard Worker     args->above_pred_buf[0] = CONVERT_TO_BYTEPTR(obmc_buffer->above_pred);
3948*77c1e3ccSAndroid Build Coastguard Worker     args->above_pred_buf[1] = CONVERT_TO_BYTEPTR(obmc_buffer->above_pred +
3949*77c1e3ccSAndroid Build Coastguard Worker                                                  (MAX_SB_SQUARE >> 1) * len);
3950*77c1e3ccSAndroid Build Coastguard Worker     args->above_pred_buf[2] =
3951*77c1e3ccSAndroid Build Coastguard Worker         CONVERT_TO_BYTEPTR(obmc_buffer->above_pred + MAX_SB_SQUARE * len);
3952*77c1e3ccSAndroid Build Coastguard Worker     args->left_pred_buf[0] = CONVERT_TO_BYTEPTR(obmc_buffer->left_pred);
3953*77c1e3ccSAndroid Build Coastguard Worker     args->left_pred_buf[1] =
3954*77c1e3ccSAndroid Build Coastguard Worker         CONVERT_TO_BYTEPTR(obmc_buffer->left_pred + (MAX_SB_SQUARE >> 1) * len);
3955*77c1e3ccSAndroid Build Coastguard Worker     args->left_pred_buf[2] =
3956*77c1e3ccSAndroid Build Coastguard Worker         CONVERT_TO_BYTEPTR(obmc_buffer->left_pred + MAX_SB_SQUARE * len);
3957*77c1e3ccSAndroid Build Coastguard Worker   } else {
3958*77c1e3ccSAndroid Build Coastguard Worker     args->above_pred_buf[0] = obmc_buffer->above_pred;
3959*77c1e3ccSAndroid Build Coastguard Worker     args->above_pred_buf[1] = obmc_buffer->above_pred + (MAX_SB_SQUARE >> 1);
3960*77c1e3ccSAndroid Build Coastguard Worker     args->above_pred_buf[2] = obmc_buffer->above_pred + MAX_SB_SQUARE;
3961*77c1e3ccSAndroid Build Coastguard Worker     args->left_pred_buf[0] = obmc_buffer->left_pred;
3962*77c1e3ccSAndroid Build Coastguard Worker     args->left_pred_buf[1] = obmc_buffer->left_pred + (MAX_SB_SQUARE >> 1);
3963*77c1e3ccSAndroid Build Coastguard Worker     args->left_pred_buf[2] = obmc_buffer->left_pred + MAX_SB_SQUARE;
3964*77c1e3ccSAndroid Build Coastguard Worker   }
3965*77c1e3ccSAndroid Build Coastguard Worker }
3966*77c1e3ccSAndroid Build Coastguard Worker 
prune_ref_frame(const AV1_COMP * cpi,const MACROBLOCK * x,MV_REFERENCE_FRAME ref_frame)3967*77c1e3ccSAndroid Build Coastguard Worker static inline int prune_ref_frame(const AV1_COMP *cpi, const MACROBLOCK *x,
3968*77c1e3ccSAndroid Build Coastguard Worker                                   MV_REFERENCE_FRAME ref_frame) {
3969*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
3970*77c1e3ccSAndroid Build Coastguard Worker   MV_REFERENCE_FRAME rf[2];
3971*77c1e3ccSAndroid Build Coastguard Worker   av1_set_ref_frame(rf, ref_frame);
3972*77c1e3ccSAndroid Build Coastguard Worker 
3973*77c1e3ccSAndroid Build Coastguard Worker   if ((cpi->prune_ref_frame_mask >> ref_frame) & 1) return 1;
3974*77c1e3ccSAndroid Build Coastguard Worker 
3975*77c1e3ccSAndroid Build Coastguard Worker   if (prune_ref_by_selective_ref_frame(cpi, x, rf,
3976*77c1e3ccSAndroid Build Coastguard Worker                                        cm->cur_frame->ref_display_order_hint)) {
3977*77c1e3ccSAndroid Build Coastguard Worker     return 1;
3978*77c1e3ccSAndroid Build Coastguard Worker   }
3979*77c1e3ccSAndroid Build Coastguard Worker 
3980*77c1e3ccSAndroid Build Coastguard Worker   return 0;
3981*77c1e3ccSAndroid Build Coastguard Worker }
3982*77c1e3ccSAndroid Build Coastguard Worker 
is_ref_frame_used_by_compound_ref(int ref_frame,int skip_ref_frame_mask)3983*77c1e3ccSAndroid Build Coastguard Worker static inline int is_ref_frame_used_by_compound_ref(int ref_frame,
3984*77c1e3ccSAndroid Build Coastguard Worker                                                     int skip_ref_frame_mask) {
3985*77c1e3ccSAndroid Build Coastguard Worker   for (int r = ALTREF_FRAME + 1; r < MODE_CTX_REF_FRAMES; ++r) {
3986*77c1e3ccSAndroid Build Coastguard Worker     if (!(skip_ref_frame_mask & (1 << r))) {
3987*77c1e3ccSAndroid Build Coastguard Worker       const MV_REFERENCE_FRAME *rf = ref_frame_map[r - REF_FRAMES];
3988*77c1e3ccSAndroid Build Coastguard Worker       if (rf[0] == ref_frame || rf[1] == ref_frame) {
3989*77c1e3ccSAndroid Build Coastguard Worker         return 1;
3990*77c1e3ccSAndroid Build Coastguard Worker       }
3991*77c1e3ccSAndroid Build Coastguard Worker     }
3992*77c1e3ccSAndroid Build Coastguard Worker   }
3993*77c1e3ccSAndroid Build Coastguard Worker   return 0;
3994*77c1e3ccSAndroid Build Coastguard Worker }
3995*77c1e3ccSAndroid Build Coastguard Worker 
is_ref_frame_used_in_cache(MV_REFERENCE_FRAME ref_frame,const MB_MODE_INFO * mi_cache)3996*77c1e3ccSAndroid Build Coastguard Worker static inline int is_ref_frame_used_in_cache(MV_REFERENCE_FRAME ref_frame,
3997*77c1e3ccSAndroid Build Coastguard Worker                                              const MB_MODE_INFO *mi_cache) {
3998*77c1e3ccSAndroid Build Coastguard Worker   if (!mi_cache) {
3999*77c1e3ccSAndroid Build Coastguard Worker     return 0;
4000*77c1e3ccSAndroid Build Coastguard Worker   }
4001*77c1e3ccSAndroid Build Coastguard Worker 
4002*77c1e3ccSAndroid Build Coastguard Worker   if (ref_frame < REF_FRAMES) {
4003*77c1e3ccSAndroid Build Coastguard Worker     return (ref_frame == mi_cache->ref_frame[0] ||
4004*77c1e3ccSAndroid Build Coastguard Worker             ref_frame == mi_cache->ref_frame[1]);
4005*77c1e3ccSAndroid Build Coastguard Worker   }
4006*77c1e3ccSAndroid Build Coastguard Worker 
4007*77c1e3ccSAndroid Build Coastguard Worker   // if we are here, then the current mode is compound.
4008*77c1e3ccSAndroid Build Coastguard Worker   MV_REFERENCE_FRAME cached_ref_type = av1_ref_frame_type(mi_cache->ref_frame);
4009*77c1e3ccSAndroid Build Coastguard Worker   return ref_frame == cached_ref_type;
4010*77c1e3ccSAndroid Build Coastguard Worker }
4011*77c1e3ccSAndroid Build Coastguard Worker 
4012*77c1e3ccSAndroid Build Coastguard Worker // Please add/modify parameter setting in this function, making it consistent
4013*77c1e3ccSAndroid Build Coastguard Worker // and easy to read and maintain.
set_params_rd_pick_inter_mode(const AV1_COMP * cpi,MACROBLOCK * x,HandleInterModeArgs * args,BLOCK_SIZE bsize,mode_skip_mask_t * mode_skip_mask,int skip_ref_frame_mask,unsigned int * ref_costs_single,unsigned int (* ref_costs_comp)[REF_FRAMES],struct buf_2d (* yv12_mb)[MAX_MB_PLANE])4014*77c1e3ccSAndroid Build Coastguard Worker static inline void set_params_rd_pick_inter_mode(
4015*77c1e3ccSAndroid Build Coastguard Worker     const AV1_COMP *cpi, MACROBLOCK *x, HandleInterModeArgs *args,
4016*77c1e3ccSAndroid Build Coastguard Worker     BLOCK_SIZE bsize, mode_skip_mask_t *mode_skip_mask, int skip_ref_frame_mask,
4017*77c1e3ccSAndroid Build Coastguard Worker     unsigned int *ref_costs_single, unsigned int (*ref_costs_comp)[REF_FRAMES],
4018*77c1e3ccSAndroid Build Coastguard Worker     struct buf_2d (*yv12_mb)[MAX_MB_PLANE]) {
4019*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
4020*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *const xd = &x->e_mbd;
4021*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *const mbmi = xd->mi[0];
4022*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO_EXT *const mbmi_ext = &x->mbmi_ext;
4023*77c1e3ccSAndroid Build Coastguard Worker   unsigned char segment_id = mbmi->segment_id;
4024*77c1e3ccSAndroid Build Coastguard Worker 
4025*77c1e3ccSAndroid Build Coastguard Worker   init_neighbor_pred_buf(&x->obmc_buffer, args, is_cur_buf_hbd(&x->e_mbd));
4026*77c1e3ccSAndroid Build Coastguard Worker   av1_collect_neighbors_ref_counts(xd);
4027*77c1e3ccSAndroid Build Coastguard Worker   estimate_ref_frame_costs(cm, xd, &x->mode_costs, segment_id, ref_costs_single,
4028*77c1e3ccSAndroid Build Coastguard Worker                            ref_costs_comp);
4029*77c1e3ccSAndroid Build Coastguard Worker 
4030*77c1e3ccSAndroid Build Coastguard Worker   const int mi_row = xd->mi_row;
4031*77c1e3ccSAndroid Build Coastguard Worker   const int mi_col = xd->mi_col;
4032*77c1e3ccSAndroid Build Coastguard Worker   x->best_pred_mv_sad[0] = INT_MAX;
4033*77c1e3ccSAndroid Build Coastguard Worker   x->best_pred_mv_sad[1] = INT_MAX;
4034*77c1e3ccSAndroid Build Coastguard Worker 
4035*77c1e3ccSAndroid Build Coastguard Worker   for (MV_REFERENCE_FRAME ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME;
4036*77c1e3ccSAndroid Build Coastguard Worker        ++ref_frame) {
4037*77c1e3ccSAndroid Build Coastguard Worker     x->pred_mv_sad[ref_frame] = INT_MAX;
4038*77c1e3ccSAndroid Build Coastguard Worker     mbmi_ext->mode_context[ref_frame] = 0;
4039*77c1e3ccSAndroid Build Coastguard Worker     mbmi_ext->ref_mv_count[ref_frame] = UINT8_MAX;
4040*77c1e3ccSAndroid Build Coastguard Worker     if (cpi->ref_frame_flags & av1_ref_frame_flag_list[ref_frame]) {
4041*77c1e3ccSAndroid Build Coastguard Worker       // Skip the ref frame if the mask says skip and the ref is not used by
4042*77c1e3ccSAndroid Build Coastguard Worker       // compound ref.
4043*77c1e3ccSAndroid Build Coastguard Worker       if (skip_ref_frame_mask & (1 << ref_frame) &&
4044*77c1e3ccSAndroid Build Coastguard Worker           !is_ref_frame_used_by_compound_ref(ref_frame, skip_ref_frame_mask) &&
4045*77c1e3ccSAndroid Build Coastguard Worker           !is_ref_frame_used_in_cache(ref_frame, x->mb_mode_cache)) {
4046*77c1e3ccSAndroid Build Coastguard Worker         continue;
4047*77c1e3ccSAndroid Build Coastguard Worker       }
4048*77c1e3ccSAndroid Build Coastguard Worker       assert(get_ref_frame_yv12_buf(cm, ref_frame) != NULL);
4049*77c1e3ccSAndroid Build Coastguard Worker       setup_buffer_ref_mvs_inter(cpi, x, ref_frame, bsize, yv12_mb);
4050*77c1e3ccSAndroid Build Coastguard Worker     }
4051*77c1e3ccSAndroid Build Coastguard Worker     if (cpi->sf.inter_sf.alt_ref_search_fp ||
4052*77c1e3ccSAndroid Build Coastguard Worker         cpi->sf.inter_sf.prune_single_ref ||
4053*77c1e3ccSAndroid Build Coastguard Worker         cpi->sf.rt_sf.prune_inter_modes_wrt_gf_arf_based_on_sad) {
4054*77c1e3ccSAndroid Build Coastguard Worker       // Store the best pred_mv_sad across all past frames
4055*77c1e3ccSAndroid Build Coastguard Worker       if (cpi->ref_frame_dist_info.ref_relative_dist[ref_frame - LAST_FRAME] <
4056*77c1e3ccSAndroid Build Coastguard Worker           0)
4057*77c1e3ccSAndroid Build Coastguard Worker         x->best_pred_mv_sad[0] =
4058*77c1e3ccSAndroid Build Coastguard Worker             AOMMIN(x->best_pred_mv_sad[0], x->pred_mv_sad[ref_frame]);
4059*77c1e3ccSAndroid Build Coastguard Worker       else
4060*77c1e3ccSAndroid Build Coastguard Worker         // Store the best pred_mv_sad across all future frames
4061*77c1e3ccSAndroid Build Coastguard Worker         x->best_pred_mv_sad[1] =
4062*77c1e3ccSAndroid Build Coastguard Worker             AOMMIN(x->best_pred_mv_sad[1], x->pred_mv_sad[ref_frame]);
4063*77c1e3ccSAndroid Build Coastguard Worker     }
4064*77c1e3ccSAndroid Build Coastguard Worker   }
4065*77c1e3ccSAndroid Build Coastguard Worker 
4066*77c1e3ccSAndroid Build Coastguard Worker   if (!cpi->sf.rt_sf.use_real_time_ref_set && is_comp_ref_allowed(bsize)) {
4067*77c1e3ccSAndroid Build Coastguard Worker     // No second reference on RT ref set, so no need to initialize
4068*77c1e3ccSAndroid Build Coastguard Worker     for (MV_REFERENCE_FRAME ref_frame = EXTREF_FRAME;
4069*77c1e3ccSAndroid Build Coastguard Worker          ref_frame < MODE_CTX_REF_FRAMES; ++ref_frame) {
4070*77c1e3ccSAndroid Build Coastguard Worker       mbmi_ext->mode_context[ref_frame] = 0;
4071*77c1e3ccSAndroid Build Coastguard Worker       mbmi_ext->ref_mv_count[ref_frame] = UINT8_MAX;
4072*77c1e3ccSAndroid Build Coastguard Worker       const MV_REFERENCE_FRAME *rf = ref_frame_map[ref_frame - REF_FRAMES];
4073*77c1e3ccSAndroid Build Coastguard Worker       if (!((cpi->ref_frame_flags & av1_ref_frame_flag_list[rf[0]]) &&
4074*77c1e3ccSAndroid Build Coastguard Worker             (cpi->ref_frame_flags & av1_ref_frame_flag_list[rf[1]]))) {
4075*77c1e3ccSAndroid Build Coastguard Worker         continue;
4076*77c1e3ccSAndroid Build Coastguard Worker       }
4077*77c1e3ccSAndroid Build Coastguard Worker 
4078*77c1e3ccSAndroid Build Coastguard Worker       if (skip_ref_frame_mask & (1 << ref_frame) &&
4079*77c1e3ccSAndroid Build Coastguard Worker           !is_ref_frame_used_in_cache(ref_frame, x->mb_mode_cache)) {
4080*77c1e3ccSAndroid Build Coastguard Worker         continue;
4081*77c1e3ccSAndroid Build Coastguard Worker       }
4082*77c1e3ccSAndroid Build Coastguard Worker       // Ref mv list population is not required, when compound references are
4083*77c1e3ccSAndroid Build Coastguard Worker       // pruned.
4084*77c1e3ccSAndroid Build Coastguard Worker       if (prune_ref_frame(cpi, x, ref_frame)) continue;
4085*77c1e3ccSAndroid Build Coastguard Worker 
4086*77c1e3ccSAndroid Build Coastguard Worker       av1_find_mv_refs(cm, xd, mbmi, ref_frame, mbmi_ext->ref_mv_count,
4087*77c1e3ccSAndroid Build Coastguard Worker                        xd->ref_mv_stack, xd->weight, NULL, mbmi_ext->global_mvs,
4088*77c1e3ccSAndroid Build Coastguard Worker                        mbmi_ext->mode_context);
4089*77c1e3ccSAndroid Build Coastguard Worker       // TODO(Ravi): Populate mbmi_ext->ref_mv_stack[ref_frame][4] and
4090*77c1e3ccSAndroid Build Coastguard Worker       // mbmi_ext->weight[ref_frame][4] inside av1_find_mv_refs.
4091*77c1e3ccSAndroid Build Coastguard Worker       av1_copy_usable_ref_mv_stack_and_weight(xd, mbmi_ext, ref_frame);
4092*77c1e3ccSAndroid Build Coastguard Worker     }
4093*77c1e3ccSAndroid Build Coastguard Worker   }
4094*77c1e3ccSAndroid Build Coastguard Worker 
4095*77c1e3ccSAndroid Build Coastguard Worker   av1_count_overlappable_neighbors(cm, xd);
4096*77c1e3ccSAndroid Build Coastguard Worker   const FRAME_UPDATE_TYPE update_type =
4097*77c1e3ccSAndroid Build Coastguard Worker       get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index);
4098*77c1e3ccSAndroid Build Coastguard Worker   int use_actual_frame_probs = 1;
4099*77c1e3ccSAndroid Build Coastguard Worker   int prune_obmc;
4100*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_FPMT_TEST
4101*77c1e3ccSAndroid Build Coastguard Worker   use_actual_frame_probs =
4102*77c1e3ccSAndroid Build Coastguard Worker       (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) ? 0 : 1;
4103*77c1e3ccSAndroid Build Coastguard Worker   if (!use_actual_frame_probs) {
4104*77c1e3ccSAndroid Build Coastguard Worker     prune_obmc = cpi->ppi->temp_frame_probs.obmc_probs[update_type][bsize] <
4105*77c1e3ccSAndroid Build Coastguard Worker                  cpi->sf.inter_sf.prune_obmc_prob_thresh;
4106*77c1e3ccSAndroid Build Coastguard Worker   }
4107*77c1e3ccSAndroid Build Coastguard Worker #endif
4108*77c1e3ccSAndroid Build Coastguard Worker   if (use_actual_frame_probs) {
4109*77c1e3ccSAndroid Build Coastguard Worker     prune_obmc = cpi->ppi->frame_probs.obmc_probs[update_type][bsize] <
4110*77c1e3ccSAndroid Build Coastguard Worker                  cpi->sf.inter_sf.prune_obmc_prob_thresh;
4111*77c1e3ccSAndroid Build Coastguard Worker   }
4112*77c1e3ccSAndroid Build Coastguard Worker   if (cpi->oxcf.motion_mode_cfg.enable_obmc && !prune_obmc) {
4113*77c1e3ccSAndroid Build Coastguard Worker     if (check_num_overlappable_neighbors(mbmi) &&
4114*77c1e3ccSAndroid Build Coastguard Worker         is_motion_variation_allowed_bsize(bsize)) {
4115*77c1e3ccSAndroid Build Coastguard Worker       int dst_width1[MAX_MB_PLANE] = { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE };
4116*77c1e3ccSAndroid Build Coastguard Worker       int dst_width2[MAX_MB_PLANE] = { MAX_SB_SIZE >> 1, MAX_SB_SIZE >> 1,
4117*77c1e3ccSAndroid Build Coastguard Worker                                        MAX_SB_SIZE >> 1 };
4118*77c1e3ccSAndroid Build Coastguard Worker       int dst_height1[MAX_MB_PLANE] = { MAX_SB_SIZE >> 1, MAX_SB_SIZE >> 1,
4119*77c1e3ccSAndroid Build Coastguard Worker                                         MAX_SB_SIZE >> 1 };
4120*77c1e3ccSAndroid Build Coastguard Worker       int dst_height2[MAX_MB_PLANE] = { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE };
4121*77c1e3ccSAndroid Build Coastguard Worker       av1_build_prediction_by_above_preds(cm, xd, args->above_pred_buf,
4122*77c1e3ccSAndroid Build Coastguard Worker                                           dst_width1, dst_height1,
4123*77c1e3ccSAndroid Build Coastguard Worker                                           args->above_pred_stride);
4124*77c1e3ccSAndroid Build Coastguard Worker       av1_build_prediction_by_left_preds(cm, xd, args->left_pred_buf,
4125*77c1e3ccSAndroid Build Coastguard Worker                                          dst_width2, dst_height2,
4126*77c1e3ccSAndroid Build Coastguard Worker                                          args->left_pred_stride);
4127*77c1e3ccSAndroid Build Coastguard Worker       const int num_planes = av1_num_planes(cm);
4128*77c1e3ccSAndroid Build Coastguard Worker       av1_setup_dst_planes(xd->plane, bsize, &cm->cur_frame->buf, mi_row,
4129*77c1e3ccSAndroid Build Coastguard Worker                            mi_col, 0, num_planes);
4130*77c1e3ccSAndroid Build Coastguard Worker       calc_target_weighted_pred(
4131*77c1e3ccSAndroid Build Coastguard Worker           cm, x, xd, args->above_pred_buf[0], args->above_pred_stride[0],
4132*77c1e3ccSAndroid Build Coastguard Worker           args->left_pred_buf[0], args->left_pred_stride[0]);
4133*77c1e3ccSAndroid Build Coastguard Worker     }
4134*77c1e3ccSAndroid Build Coastguard Worker   }
4135*77c1e3ccSAndroid Build Coastguard Worker 
4136*77c1e3ccSAndroid Build Coastguard Worker   init_mode_skip_mask(mode_skip_mask, cpi, x, bsize);
4137*77c1e3ccSAndroid Build Coastguard Worker 
4138*77c1e3ccSAndroid Build Coastguard Worker   // Set params for mode evaluation
4139*77c1e3ccSAndroid Build Coastguard Worker   set_mode_eval_params(cpi, x, MODE_EVAL);
4140*77c1e3ccSAndroid Build Coastguard Worker 
4141*77c1e3ccSAndroid Build Coastguard Worker   x->comp_rd_stats_idx = 0;
4142*77c1e3ccSAndroid Build Coastguard Worker 
4143*77c1e3ccSAndroid Build Coastguard Worker   for (int idx = 0; idx < REF_FRAMES; idx++) {
4144*77c1e3ccSAndroid Build Coastguard Worker     args->best_single_sse_in_refs[idx] = INT32_MAX;
4145*77c1e3ccSAndroid Build Coastguard Worker   }
4146*77c1e3ccSAndroid Build Coastguard Worker }
4147*77c1e3ccSAndroid Build Coastguard Worker 
init_single_inter_mode_search_state(InterModeSearchState * search_state)4148*77c1e3ccSAndroid Build Coastguard Worker static inline void init_single_inter_mode_search_state(
4149*77c1e3ccSAndroid Build Coastguard Worker     InterModeSearchState *search_state) {
4150*77c1e3ccSAndroid Build Coastguard Worker   for (int dir = 0; dir < 2; ++dir) {
4151*77c1e3ccSAndroid Build Coastguard Worker     for (int mode = 0; mode < SINGLE_INTER_MODE_NUM; ++mode) {
4152*77c1e3ccSAndroid Build Coastguard Worker       for (int ref_frame = 0; ref_frame < FWD_REFS; ++ref_frame) {
4153*77c1e3ccSAndroid Build Coastguard Worker         SingleInterModeState *state;
4154*77c1e3ccSAndroid Build Coastguard Worker 
4155*77c1e3ccSAndroid Build Coastguard Worker         state = &search_state->single_state[dir][mode][ref_frame];
4156*77c1e3ccSAndroid Build Coastguard Worker         state->ref_frame = NONE_FRAME;
4157*77c1e3ccSAndroid Build Coastguard Worker         state->rd = INT64_MAX;
4158*77c1e3ccSAndroid Build Coastguard Worker 
4159*77c1e3ccSAndroid Build Coastguard Worker         state = &search_state->single_state_modelled[dir][mode][ref_frame];
4160*77c1e3ccSAndroid Build Coastguard Worker         state->ref_frame = NONE_FRAME;
4161*77c1e3ccSAndroid Build Coastguard Worker         state->rd = INT64_MAX;
4162*77c1e3ccSAndroid Build Coastguard Worker 
4163*77c1e3ccSAndroid Build Coastguard Worker         search_state->single_rd_order[dir][mode][ref_frame] = NONE_FRAME;
4164*77c1e3ccSAndroid Build Coastguard Worker       }
4165*77c1e3ccSAndroid Build Coastguard Worker     }
4166*77c1e3ccSAndroid Build Coastguard Worker   }
4167*77c1e3ccSAndroid Build Coastguard Worker 
4168*77c1e3ccSAndroid Build Coastguard Worker   for (int ref_frame = 0; ref_frame < REF_FRAMES; ++ref_frame) {
4169*77c1e3ccSAndroid Build Coastguard Worker     search_state->best_single_rd[ref_frame] = INT64_MAX;
4170*77c1e3ccSAndroid Build Coastguard Worker     search_state->best_single_mode[ref_frame] = PRED_MODE_INVALID;
4171*77c1e3ccSAndroid Build Coastguard Worker   }
4172*77c1e3ccSAndroid Build Coastguard Worker   av1_zero(search_state->single_state_cnt);
4173*77c1e3ccSAndroid Build Coastguard Worker   av1_zero(search_state->single_state_modelled_cnt);
4174*77c1e3ccSAndroid Build Coastguard Worker }
4175*77c1e3ccSAndroid Build Coastguard Worker 
init_inter_mode_search_state(InterModeSearchState * search_state,const AV1_COMP * cpi,const MACROBLOCK * x,BLOCK_SIZE bsize,int64_t best_rd_so_far)4176*77c1e3ccSAndroid Build Coastguard Worker static inline void init_inter_mode_search_state(
4177*77c1e3ccSAndroid Build Coastguard Worker     InterModeSearchState *search_state, const AV1_COMP *cpi,
4178*77c1e3ccSAndroid Build Coastguard Worker     const MACROBLOCK *x, BLOCK_SIZE bsize, int64_t best_rd_so_far) {
4179*77c1e3ccSAndroid Build Coastguard Worker   init_intra_mode_search_state(&search_state->intra_search_state);
4180*77c1e3ccSAndroid Build Coastguard Worker   av1_invalid_rd_stats(&search_state->best_y_rdcost);
4181*77c1e3ccSAndroid Build Coastguard Worker 
4182*77c1e3ccSAndroid Build Coastguard Worker   search_state->best_rd = best_rd_so_far;
4183*77c1e3ccSAndroid Build Coastguard Worker   search_state->best_skip_rd[0] = INT64_MAX;
4184*77c1e3ccSAndroid Build Coastguard Worker   search_state->best_skip_rd[1] = INT64_MAX;
4185*77c1e3ccSAndroid Build Coastguard Worker 
4186*77c1e3ccSAndroid Build Coastguard Worker   av1_zero(search_state->best_mbmode);
4187*77c1e3ccSAndroid Build Coastguard Worker 
4188*77c1e3ccSAndroid Build Coastguard Worker   search_state->best_rate_y = INT_MAX;
4189*77c1e3ccSAndroid Build Coastguard Worker 
4190*77c1e3ccSAndroid Build Coastguard Worker   search_state->best_rate_uv = INT_MAX;
4191*77c1e3ccSAndroid Build Coastguard Worker 
4192*77c1e3ccSAndroid Build Coastguard Worker   search_state->best_mode_skippable = 0;
4193*77c1e3ccSAndroid Build Coastguard Worker 
4194*77c1e3ccSAndroid Build Coastguard Worker   search_state->best_skip2 = 0;
4195*77c1e3ccSAndroid Build Coastguard Worker 
4196*77c1e3ccSAndroid Build Coastguard Worker   search_state->best_mode_index = THR_INVALID;
4197*77c1e3ccSAndroid Build Coastguard Worker 
4198*77c1e3ccSAndroid Build Coastguard Worker   const MACROBLOCKD *const xd = &x->e_mbd;
4199*77c1e3ccSAndroid Build Coastguard Worker   const MB_MODE_INFO *const mbmi = xd->mi[0];
4200*77c1e3ccSAndroid Build Coastguard Worker   const unsigned char segment_id = mbmi->segment_id;
4201*77c1e3ccSAndroid Build Coastguard Worker 
4202*77c1e3ccSAndroid Build Coastguard Worker   search_state->num_available_refs = 0;
4203*77c1e3ccSAndroid Build Coastguard Worker   memset(search_state->dist_refs, -1, sizeof(search_state->dist_refs));
4204*77c1e3ccSAndroid Build Coastguard Worker   memset(search_state->dist_order_refs, -1,
4205*77c1e3ccSAndroid Build Coastguard Worker          sizeof(search_state->dist_order_refs));
4206*77c1e3ccSAndroid Build Coastguard Worker 
4207*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i <= LAST_NEW_MV_INDEX; ++i)
4208*77c1e3ccSAndroid Build Coastguard Worker     search_state->mode_threshold[i] = 0;
4209*77c1e3ccSAndroid Build Coastguard Worker   const int *const rd_threshes = cpi->rd.threshes[segment_id][bsize];
4210*77c1e3ccSAndroid Build Coastguard Worker   for (int i = LAST_NEW_MV_INDEX + 1; i < SINGLE_REF_MODE_END; ++i)
4211*77c1e3ccSAndroid Build Coastguard Worker     search_state->mode_threshold[i] =
4212*77c1e3ccSAndroid Build Coastguard Worker         ((int64_t)rd_threshes[i] * x->thresh_freq_fact[bsize][i]) >>
4213*77c1e3ccSAndroid Build Coastguard Worker         RD_THRESH_FAC_FRAC_BITS;
4214*77c1e3ccSAndroid Build Coastguard Worker 
4215*77c1e3ccSAndroid Build Coastguard Worker   search_state->best_intra_rd = INT64_MAX;
4216*77c1e3ccSAndroid Build Coastguard Worker 
4217*77c1e3ccSAndroid Build Coastguard Worker   search_state->best_pred_sse = UINT_MAX;
4218*77c1e3ccSAndroid Build Coastguard Worker 
4219*77c1e3ccSAndroid Build Coastguard Worker   av1_zero(search_state->single_newmv);
4220*77c1e3ccSAndroid Build Coastguard Worker   av1_zero(search_state->single_newmv_rate);
4221*77c1e3ccSAndroid Build Coastguard Worker   av1_zero(search_state->single_newmv_valid);
4222*77c1e3ccSAndroid Build Coastguard Worker   for (int i = SINGLE_INTER_MODE_START; i < SINGLE_INTER_MODE_END; ++i) {
4223*77c1e3ccSAndroid Build Coastguard Worker     for (int j = 0; j < MAX_REF_MV_SEARCH; ++j) {
4224*77c1e3ccSAndroid Build Coastguard Worker       for (int ref_frame = 0; ref_frame < REF_FRAMES; ++ref_frame) {
4225*77c1e3ccSAndroid Build Coastguard Worker         search_state->modelled_rd[i][j][ref_frame] = INT64_MAX;
4226*77c1e3ccSAndroid Build Coastguard Worker         search_state->simple_rd[i][j][ref_frame] = INT64_MAX;
4227*77c1e3ccSAndroid Build Coastguard Worker       }
4228*77c1e3ccSAndroid Build Coastguard Worker     }
4229*77c1e3ccSAndroid Build Coastguard Worker   }
4230*77c1e3ccSAndroid Build Coastguard Worker 
4231*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < REFERENCE_MODES; ++i) {
4232*77c1e3ccSAndroid Build Coastguard Worker     search_state->best_pred_rd[i] = INT64_MAX;
4233*77c1e3ccSAndroid Build Coastguard Worker   }
4234*77c1e3ccSAndroid Build Coastguard Worker 
4235*77c1e3ccSAndroid Build Coastguard Worker   if (cpi->common.current_frame.reference_mode != SINGLE_REFERENCE) {
4236*77c1e3ccSAndroid Build Coastguard Worker     for (int i = SINGLE_REF_MODE_END; i < THR_INTER_MODE_END; ++i)
4237*77c1e3ccSAndroid Build Coastguard Worker       search_state->mode_threshold[i] =
4238*77c1e3ccSAndroid Build Coastguard Worker           ((int64_t)rd_threshes[i] * x->thresh_freq_fact[bsize][i]) >>
4239*77c1e3ccSAndroid Build Coastguard Worker           RD_THRESH_FAC_FRAC_BITS;
4240*77c1e3ccSAndroid Build Coastguard Worker 
4241*77c1e3ccSAndroid Build Coastguard Worker     for (int i = COMP_INTER_MODE_START; i < COMP_INTER_MODE_END; ++i) {
4242*77c1e3ccSAndroid Build Coastguard Worker       for (int j = 0; j < MAX_REF_MV_SEARCH; ++j) {
4243*77c1e3ccSAndroid Build Coastguard Worker         for (int ref_frame = 0; ref_frame < REF_FRAMES; ++ref_frame) {
4244*77c1e3ccSAndroid Build Coastguard Worker           search_state->modelled_rd[i][j][ref_frame] = INT64_MAX;
4245*77c1e3ccSAndroid Build Coastguard Worker           search_state->simple_rd[i][j][ref_frame] = INT64_MAX;
4246*77c1e3ccSAndroid Build Coastguard Worker         }
4247*77c1e3ccSAndroid Build Coastguard Worker       }
4248*77c1e3ccSAndroid Build Coastguard Worker     }
4249*77c1e3ccSAndroid Build Coastguard Worker 
4250*77c1e3ccSAndroid Build Coastguard Worker     init_single_inter_mode_search_state(search_state);
4251*77c1e3ccSAndroid Build Coastguard Worker   }
4252*77c1e3ccSAndroid Build Coastguard Worker }
4253*77c1e3ccSAndroid Build Coastguard Worker 
mask_says_skip(const mode_skip_mask_t * mode_skip_mask,const MV_REFERENCE_FRAME * ref_frame,const PREDICTION_MODE this_mode)4254*77c1e3ccSAndroid Build Coastguard Worker static bool mask_says_skip(const mode_skip_mask_t *mode_skip_mask,
4255*77c1e3ccSAndroid Build Coastguard Worker                            const MV_REFERENCE_FRAME *ref_frame,
4256*77c1e3ccSAndroid Build Coastguard Worker                            const PREDICTION_MODE this_mode) {
4257*77c1e3ccSAndroid Build Coastguard Worker   if (mode_skip_mask->pred_modes[ref_frame[0]] & (1 << this_mode)) {
4258*77c1e3ccSAndroid Build Coastguard Worker     return true;
4259*77c1e3ccSAndroid Build Coastguard Worker   }
4260*77c1e3ccSAndroid Build Coastguard Worker 
4261*77c1e3ccSAndroid Build Coastguard Worker   return mode_skip_mask->ref_combo[ref_frame[0]][ref_frame[1] + 1];
4262*77c1e3ccSAndroid Build Coastguard Worker }
4263*77c1e3ccSAndroid Build Coastguard Worker 
inter_mode_compatible_skip(const AV1_COMP * cpi,const MACROBLOCK * x,BLOCK_SIZE bsize,PREDICTION_MODE curr_mode,const MV_REFERENCE_FRAME * ref_frames)4264*77c1e3ccSAndroid Build Coastguard Worker static int inter_mode_compatible_skip(const AV1_COMP *cpi, const MACROBLOCK *x,
4265*77c1e3ccSAndroid Build Coastguard Worker                                       BLOCK_SIZE bsize,
4266*77c1e3ccSAndroid Build Coastguard Worker                                       PREDICTION_MODE curr_mode,
4267*77c1e3ccSAndroid Build Coastguard Worker                                       const MV_REFERENCE_FRAME *ref_frames) {
4268*77c1e3ccSAndroid Build Coastguard Worker   const int comp_pred = ref_frames[1] > INTRA_FRAME;
4269*77c1e3ccSAndroid Build Coastguard Worker   if (comp_pred) {
4270*77c1e3ccSAndroid Build Coastguard Worker     if (!is_comp_ref_allowed(bsize)) return 1;
4271*77c1e3ccSAndroid Build Coastguard Worker     if (!(cpi->ref_frame_flags & av1_ref_frame_flag_list[ref_frames[1]])) {
4272*77c1e3ccSAndroid Build Coastguard Worker       return 1;
4273*77c1e3ccSAndroid Build Coastguard Worker     }
4274*77c1e3ccSAndroid Build Coastguard Worker 
4275*77c1e3ccSAndroid Build Coastguard Worker     const AV1_COMMON *const cm = &cpi->common;
4276*77c1e3ccSAndroid Build Coastguard Worker     if (frame_is_intra_only(cm)) return 1;
4277*77c1e3ccSAndroid Build Coastguard Worker 
4278*77c1e3ccSAndroid Build Coastguard Worker     const CurrentFrame *const current_frame = &cm->current_frame;
4279*77c1e3ccSAndroid Build Coastguard Worker     if (current_frame->reference_mode == SINGLE_REFERENCE) return 1;
4280*77c1e3ccSAndroid Build Coastguard Worker 
4281*77c1e3ccSAndroid Build Coastguard Worker     const struct segmentation *const seg = &cm->seg;
4282*77c1e3ccSAndroid Build Coastguard Worker     const unsigned char segment_id = x->e_mbd.mi[0]->segment_id;
4283*77c1e3ccSAndroid Build Coastguard Worker     // Do not allow compound prediction if the segment level reference frame
4284*77c1e3ccSAndroid Build Coastguard Worker     // feature is in use as in this case there can only be one reference.
4285*77c1e3ccSAndroid Build Coastguard Worker     if (segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME)) return 1;
4286*77c1e3ccSAndroid Build Coastguard Worker   }
4287*77c1e3ccSAndroid Build Coastguard Worker 
4288*77c1e3ccSAndroid Build Coastguard Worker   if (ref_frames[0] > INTRA_FRAME && ref_frames[1] == INTRA_FRAME) {
4289*77c1e3ccSAndroid Build Coastguard Worker     // Mode must be compatible
4290*77c1e3ccSAndroid Build Coastguard Worker     if (!is_interintra_allowed_bsize(bsize)) return 1;
4291*77c1e3ccSAndroid Build Coastguard Worker     if (!is_interintra_allowed_mode(curr_mode)) return 1;
4292*77c1e3ccSAndroid Build Coastguard Worker   }
4293*77c1e3ccSAndroid Build Coastguard Worker 
4294*77c1e3ccSAndroid Build Coastguard Worker   return 0;
4295*77c1e3ccSAndroid Build Coastguard Worker }
4296*77c1e3ccSAndroid Build Coastguard Worker 
fetch_picked_ref_frames_mask(const MACROBLOCK * const x,BLOCK_SIZE bsize,int mib_size)4297*77c1e3ccSAndroid Build Coastguard Worker static int fetch_picked_ref_frames_mask(const MACROBLOCK *const x,
4298*77c1e3ccSAndroid Build Coastguard Worker                                         BLOCK_SIZE bsize, int mib_size) {
4299*77c1e3ccSAndroid Build Coastguard Worker   const int sb_size_mask = mib_size - 1;
4300*77c1e3ccSAndroid Build Coastguard Worker   const MACROBLOCKD *const xd = &x->e_mbd;
4301*77c1e3ccSAndroid Build Coastguard Worker   const int mi_row = xd->mi_row;
4302*77c1e3ccSAndroid Build Coastguard Worker   const int mi_col = xd->mi_col;
4303*77c1e3ccSAndroid Build Coastguard Worker   const int mi_row_in_sb = mi_row & sb_size_mask;
4304*77c1e3ccSAndroid Build Coastguard Worker   const int mi_col_in_sb = mi_col & sb_size_mask;
4305*77c1e3ccSAndroid Build Coastguard Worker   const int mi_w = mi_size_wide[bsize];
4306*77c1e3ccSAndroid Build Coastguard Worker   const int mi_h = mi_size_high[bsize];
4307*77c1e3ccSAndroid Build Coastguard Worker   int picked_ref_frames_mask = 0;
4308*77c1e3ccSAndroid Build Coastguard Worker   for (int i = mi_row_in_sb; i < mi_row_in_sb + mi_h; ++i) {
4309*77c1e3ccSAndroid Build Coastguard Worker     for (int j = mi_col_in_sb; j < mi_col_in_sb + mi_w; ++j) {
4310*77c1e3ccSAndroid Build Coastguard Worker       picked_ref_frames_mask |= x->picked_ref_frames_mask[i * 32 + j];
4311*77c1e3ccSAndroid Build Coastguard Worker     }
4312*77c1e3ccSAndroid Build Coastguard Worker   }
4313*77c1e3ccSAndroid Build Coastguard Worker   return picked_ref_frames_mask;
4314*77c1e3ccSAndroid Build Coastguard Worker }
4315*77c1e3ccSAndroid Build Coastguard Worker 
4316*77c1e3ccSAndroid Build Coastguard Worker // Check if reference frame pair of the current block matches with the given
4317*77c1e3ccSAndroid Build Coastguard Worker // block.
match_ref_frame_pair(const MB_MODE_INFO * mbmi,const MV_REFERENCE_FRAME * ref_frames)4318*77c1e3ccSAndroid Build Coastguard Worker static inline int match_ref_frame_pair(const MB_MODE_INFO *mbmi,
4319*77c1e3ccSAndroid Build Coastguard Worker                                        const MV_REFERENCE_FRAME *ref_frames) {
4320*77c1e3ccSAndroid Build Coastguard Worker   return ((ref_frames[0] == mbmi->ref_frame[0]) &&
4321*77c1e3ccSAndroid Build Coastguard Worker           (ref_frames[1] == mbmi->ref_frame[1]));
4322*77c1e3ccSAndroid Build Coastguard Worker }
4323*77c1e3ccSAndroid Build Coastguard Worker 
4324*77c1e3ccSAndroid Build Coastguard Worker // Case 1: return 0, means don't skip this mode
4325*77c1e3ccSAndroid Build Coastguard Worker // Case 2: return 1, means skip this mode completely
4326*77c1e3ccSAndroid Build Coastguard Worker // Case 3: return 2, means skip compound only, but still try single motion modes
inter_mode_search_order_independent_skip(const AV1_COMP * cpi,const MACROBLOCK * x,mode_skip_mask_t * mode_skip_mask,InterModeSearchState * search_state,int skip_ref_frame_mask,PREDICTION_MODE mode,const MV_REFERENCE_FRAME * ref_frame)4327*77c1e3ccSAndroid Build Coastguard Worker static int inter_mode_search_order_independent_skip(
4328*77c1e3ccSAndroid Build Coastguard Worker     const AV1_COMP *cpi, const MACROBLOCK *x, mode_skip_mask_t *mode_skip_mask,
4329*77c1e3ccSAndroid Build Coastguard Worker     InterModeSearchState *search_state, int skip_ref_frame_mask,
4330*77c1e3ccSAndroid Build Coastguard Worker     PREDICTION_MODE mode, const MV_REFERENCE_FRAME *ref_frame) {
4331*77c1e3ccSAndroid Build Coastguard Worker   if (mask_says_skip(mode_skip_mask, ref_frame, mode)) {
4332*77c1e3ccSAndroid Build Coastguard Worker     return 1;
4333*77c1e3ccSAndroid Build Coastguard Worker   }
4334*77c1e3ccSAndroid Build Coastguard Worker 
4335*77c1e3ccSAndroid Build Coastguard Worker   const int ref_type = av1_ref_frame_type(ref_frame);
4336*77c1e3ccSAndroid Build Coastguard Worker   if (!cpi->sf.rt_sf.use_real_time_ref_set)
4337*77c1e3ccSAndroid Build Coastguard Worker     if (prune_ref_frame(cpi, x, ref_type)) return 1;
4338*77c1e3ccSAndroid Build Coastguard Worker 
4339*77c1e3ccSAndroid Build Coastguard Worker   // This is only used in motion vector unit test.
4340*77c1e3ccSAndroid Build Coastguard Worker   if (cpi->oxcf.unit_test_cfg.motion_vector_unit_test &&
4341*77c1e3ccSAndroid Build Coastguard Worker       ref_frame[0] == INTRA_FRAME)
4342*77c1e3ccSAndroid Build Coastguard Worker     return 1;
4343*77c1e3ccSAndroid Build Coastguard Worker 
4344*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
4345*77c1e3ccSAndroid Build Coastguard Worker   if (skip_repeated_mv(cm, x, mode, ref_frame, search_state)) {
4346*77c1e3ccSAndroid Build Coastguard Worker     return 1;
4347*77c1e3ccSAndroid Build Coastguard Worker   }
4348*77c1e3ccSAndroid Build Coastguard Worker 
4349*77c1e3ccSAndroid Build Coastguard Worker   // Reuse the prediction mode in cache
4350*77c1e3ccSAndroid Build Coastguard Worker   if (x->use_mb_mode_cache) {
4351*77c1e3ccSAndroid Build Coastguard Worker     const MB_MODE_INFO *cached_mi = x->mb_mode_cache;
4352*77c1e3ccSAndroid Build Coastguard Worker     const PREDICTION_MODE cached_mode = cached_mi->mode;
4353*77c1e3ccSAndroid Build Coastguard Worker     const MV_REFERENCE_FRAME *cached_frame = cached_mi->ref_frame;
4354*77c1e3ccSAndroid Build Coastguard Worker     const int cached_mode_is_single = cached_frame[1] <= INTRA_FRAME;
4355*77c1e3ccSAndroid Build Coastguard Worker 
4356*77c1e3ccSAndroid Build Coastguard Worker     // If the cached mode is intra, then we just need to match the mode.
4357*77c1e3ccSAndroid Build Coastguard Worker     if (is_mode_intra(cached_mode) && mode != cached_mode) {
4358*77c1e3ccSAndroid Build Coastguard Worker       return 1;
4359*77c1e3ccSAndroid Build Coastguard Worker     }
4360*77c1e3ccSAndroid Build Coastguard Worker 
4361*77c1e3ccSAndroid Build Coastguard Worker     // If the cached mode is single inter mode, then we match the mode and
4362*77c1e3ccSAndroid Build Coastguard Worker     // reference frame.
4363*77c1e3ccSAndroid Build Coastguard Worker     if (cached_mode_is_single) {
4364*77c1e3ccSAndroid Build Coastguard Worker       if (mode != cached_mode || ref_frame[0] != cached_frame[0]) {
4365*77c1e3ccSAndroid Build Coastguard Worker         return 1;
4366*77c1e3ccSAndroid Build Coastguard Worker       }
4367*77c1e3ccSAndroid Build Coastguard Worker     } else {
4368*77c1e3ccSAndroid Build Coastguard Worker       // If the cached mode is compound, then we need to consider several cases.
4369*77c1e3ccSAndroid Build Coastguard Worker       const int mode_is_single = ref_frame[1] <= INTRA_FRAME;
4370*77c1e3ccSAndroid Build Coastguard Worker       if (mode_is_single) {
4371*77c1e3ccSAndroid Build Coastguard Worker         // If the mode is single, we know the modes can't match. But we might
4372*77c1e3ccSAndroid Build Coastguard Worker         // still want to search it if compound mode depends on the current mode.
4373*77c1e3ccSAndroid Build Coastguard Worker         int skip_motion_mode_only = 0;
4374*77c1e3ccSAndroid Build Coastguard Worker         if (cached_mode == NEW_NEARMV || cached_mode == NEW_NEARESTMV) {
4375*77c1e3ccSAndroid Build Coastguard Worker           skip_motion_mode_only = (ref_frame[0] == cached_frame[0]);
4376*77c1e3ccSAndroid Build Coastguard Worker         } else if (cached_mode == NEAR_NEWMV || cached_mode == NEAREST_NEWMV) {
4377*77c1e3ccSAndroid Build Coastguard Worker           skip_motion_mode_only = (ref_frame[0] == cached_frame[1]);
4378*77c1e3ccSAndroid Build Coastguard Worker         } else if (cached_mode == NEW_NEWMV) {
4379*77c1e3ccSAndroid Build Coastguard Worker           skip_motion_mode_only = (ref_frame[0] == cached_frame[0] ||
4380*77c1e3ccSAndroid Build Coastguard Worker                                    ref_frame[0] == cached_frame[1]);
4381*77c1e3ccSAndroid Build Coastguard Worker         }
4382*77c1e3ccSAndroid Build Coastguard Worker 
4383*77c1e3ccSAndroid Build Coastguard Worker         return 1 + skip_motion_mode_only;
4384*77c1e3ccSAndroid Build Coastguard Worker       } else {
4385*77c1e3ccSAndroid Build Coastguard Worker         // If both modes are compound, then everything must match.
4386*77c1e3ccSAndroid Build Coastguard Worker         if (mode != cached_mode || ref_frame[0] != cached_frame[0] ||
4387*77c1e3ccSAndroid Build Coastguard Worker             ref_frame[1] != cached_frame[1]) {
4388*77c1e3ccSAndroid Build Coastguard Worker           return 1;
4389*77c1e3ccSAndroid Build Coastguard Worker         }
4390*77c1e3ccSAndroid Build Coastguard Worker       }
4391*77c1e3ccSAndroid Build Coastguard Worker     }
4392*77c1e3ccSAndroid Build Coastguard Worker   }
4393*77c1e3ccSAndroid Build Coastguard Worker 
4394*77c1e3ccSAndroid Build Coastguard Worker   const MB_MODE_INFO *const mbmi = x->e_mbd.mi[0];
4395*77c1e3ccSAndroid Build Coastguard Worker   // If no valid mode has been found so far in PARTITION_NONE when finding a
4396*77c1e3ccSAndroid Build Coastguard Worker   // valid partition is required, do not skip mode.
4397*77c1e3ccSAndroid Build Coastguard Worker   if (search_state->best_rd == INT64_MAX && mbmi->partition == PARTITION_NONE &&
4398*77c1e3ccSAndroid Build Coastguard Worker       x->must_find_valid_partition)
4399*77c1e3ccSAndroid Build Coastguard Worker     return 0;
4400*77c1e3ccSAndroid Build Coastguard Worker 
4401*77c1e3ccSAndroid Build Coastguard Worker   const SPEED_FEATURES *const sf = &cpi->sf;
4402*77c1e3ccSAndroid Build Coastguard Worker   // Prune NEARMV and NEAR_NEARMV based on q index and neighbor's reference
4403*77c1e3ccSAndroid Build Coastguard Worker   // frames
4404*77c1e3ccSAndroid Build Coastguard Worker   if (sf->inter_sf.prune_nearmv_using_neighbors &&
4405*77c1e3ccSAndroid Build Coastguard Worker       (mode == NEAR_NEARMV || mode == NEARMV)) {
4406*77c1e3ccSAndroid Build Coastguard Worker     const MACROBLOCKD *const xd = &x->e_mbd;
4407*77c1e3ccSAndroid Build Coastguard Worker     if (search_state->best_rd != INT64_MAX && xd->left_available &&
4408*77c1e3ccSAndroid Build Coastguard Worker         xd->up_available) {
4409*77c1e3ccSAndroid Build Coastguard Worker       const int thresholds[PRUNE_NEARMV_MAX][3] = { { 1, 0, 0 },
4410*77c1e3ccSAndroid Build Coastguard Worker                                                     { 1, 1, 0 },
4411*77c1e3ccSAndroid Build Coastguard Worker                                                     { 2, 1, 0 } };
4412*77c1e3ccSAndroid Build Coastguard Worker       const int qindex_sub_range = x->qindex * 3 / QINDEX_RANGE;
4413*77c1e3ccSAndroid Build Coastguard Worker 
4414*77c1e3ccSAndroid Build Coastguard Worker       assert(sf->inter_sf.prune_nearmv_using_neighbors <= PRUNE_NEARMV_MAX &&
4415*77c1e3ccSAndroid Build Coastguard Worker              qindex_sub_range < 3);
4416*77c1e3ccSAndroid Build Coastguard Worker       const int num_ref_frame_pair_match_thresh =
4417*77c1e3ccSAndroid Build Coastguard Worker           thresholds[sf->inter_sf.prune_nearmv_using_neighbors - 1]
4418*77c1e3ccSAndroid Build Coastguard Worker                     [qindex_sub_range];
4419*77c1e3ccSAndroid Build Coastguard Worker 
4420*77c1e3ccSAndroid Build Coastguard Worker       assert(num_ref_frame_pair_match_thresh <= 2 &&
4421*77c1e3ccSAndroid Build Coastguard Worker              num_ref_frame_pair_match_thresh >= 0);
4422*77c1e3ccSAndroid Build Coastguard Worker       int num_ref_frame_pair_match = 0;
4423*77c1e3ccSAndroid Build Coastguard Worker 
4424*77c1e3ccSAndroid Build Coastguard Worker       num_ref_frame_pair_match = match_ref_frame_pair(xd->left_mbmi, ref_frame);
4425*77c1e3ccSAndroid Build Coastguard Worker       num_ref_frame_pair_match +=
4426*77c1e3ccSAndroid Build Coastguard Worker           match_ref_frame_pair(xd->above_mbmi, ref_frame);
4427*77c1e3ccSAndroid Build Coastguard Worker 
4428*77c1e3ccSAndroid Build Coastguard Worker       // Pruning based on ref frame pair match with neighbors.
4429*77c1e3ccSAndroid Build Coastguard Worker       if (num_ref_frame_pair_match < num_ref_frame_pair_match_thresh) return 1;
4430*77c1e3ccSAndroid Build Coastguard Worker     }
4431*77c1e3ccSAndroid Build Coastguard Worker   }
4432*77c1e3ccSAndroid Build Coastguard Worker 
4433*77c1e3ccSAndroid Build Coastguard Worker   int skip_motion_mode = 0;
4434*77c1e3ccSAndroid Build Coastguard Worker   if (mbmi->partition != PARTITION_NONE) {
4435*77c1e3ccSAndroid Build Coastguard Worker     int skip_ref = skip_ref_frame_mask & (1 << ref_type);
4436*77c1e3ccSAndroid Build Coastguard Worker     if (ref_type <= ALTREF_FRAME && skip_ref) {
4437*77c1e3ccSAndroid Build Coastguard Worker       // Since the compound ref modes depends on the motion estimation result of
4438*77c1e3ccSAndroid Build Coastguard Worker       // two single ref modes (best mv of single ref modes as the start point),
4439*77c1e3ccSAndroid Build Coastguard Worker       // if current single ref mode is marked skip, we need to check if it will
4440*77c1e3ccSAndroid Build Coastguard Worker       // be used in compound ref modes.
4441*77c1e3ccSAndroid Build Coastguard Worker       if (is_ref_frame_used_by_compound_ref(ref_type, skip_ref_frame_mask)) {
4442*77c1e3ccSAndroid Build Coastguard Worker         // Found a not skipped compound ref mode which contains current
4443*77c1e3ccSAndroid Build Coastguard Worker         // single ref. So this single ref can't be skipped completely
4444*77c1e3ccSAndroid Build Coastguard Worker         // Just skip its motion mode search, still try its simple
4445*77c1e3ccSAndroid Build Coastguard Worker         // transition mode.
4446*77c1e3ccSAndroid Build Coastguard Worker         skip_motion_mode = 1;
4447*77c1e3ccSAndroid Build Coastguard Worker         skip_ref = 0;
4448*77c1e3ccSAndroid Build Coastguard Worker       }
4449*77c1e3ccSAndroid Build Coastguard Worker     }
4450*77c1e3ccSAndroid Build Coastguard Worker     // If we are reusing the prediction from cache, and the current frame is
4451*77c1e3ccSAndroid Build Coastguard Worker     // required by the cache, then we cannot prune it.
4452*77c1e3ccSAndroid Build Coastguard Worker     if (is_ref_frame_used_in_cache(ref_type, x->mb_mode_cache)) {
4453*77c1e3ccSAndroid Build Coastguard Worker       skip_ref = 0;
4454*77c1e3ccSAndroid Build Coastguard Worker       // If the cache only needs the current reference type for compound
4455*77c1e3ccSAndroid Build Coastguard Worker       // prediction, then we can skip motion mode search.
4456*77c1e3ccSAndroid Build Coastguard Worker       skip_motion_mode = (ref_type <= ALTREF_FRAME &&
4457*77c1e3ccSAndroid Build Coastguard Worker                           x->mb_mode_cache->ref_frame[1] > INTRA_FRAME);
4458*77c1e3ccSAndroid Build Coastguard Worker     }
4459*77c1e3ccSAndroid Build Coastguard Worker     if (skip_ref) return 1;
4460*77c1e3ccSAndroid Build Coastguard Worker   }
4461*77c1e3ccSAndroid Build Coastguard Worker 
4462*77c1e3ccSAndroid Build Coastguard Worker   if (ref_frame[0] == INTRA_FRAME) {
4463*77c1e3ccSAndroid Build Coastguard Worker     if (mode != DC_PRED) {
4464*77c1e3ccSAndroid Build Coastguard Worker       // Disable intra modes other than DC_PRED for blocks with low variance
4465*77c1e3ccSAndroid Build Coastguard Worker       // Threshold for intra skipping based on source variance
4466*77c1e3ccSAndroid Build Coastguard Worker       // TODO(debargha): Specialize the threshold for super block sizes
4467*77c1e3ccSAndroid Build Coastguard Worker       const unsigned int skip_intra_var_thresh = 64;
4468*77c1e3ccSAndroid Build Coastguard Worker       if ((sf->rt_sf.mode_search_skip_flags & FLAG_SKIP_INTRA_LOWVAR) &&
4469*77c1e3ccSAndroid Build Coastguard Worker           x->source_variance < skip_intra_var_thresh)
4470*77c1e3ccSAndroid Build Coastguard Worker         return 1;
4471*77c1e3ccSAndroid Build Coastguard Worker     }
4472*77c1e3ccSAndroid Build Coastguard Worker   }
4473*77c1e3ccSAndroid Build Coastguard Worker 
4474*77c1e3ccSAndroid Build Coastguard Worker   if (skip_motion_mode) return 2;
4475*77c1e3ccSAndroid Build Coastguard Worker 
4476*77c1e3ccSAndroid Build Coastguard Worker   return 0;
4477*77c1e3ccSAndroid Build Coastguard Worker }
4478*77c1e3ccSAndroid Build Coastguard Worker 
init_mbmi(MB_MODE_INFO * mbmi,PREDICTION_MODE curr_mode,const MV_REFERENCE_FRAME * ref_frames,const AV1_COMMON * cm)4479*77c1e3ccSAndroid Build Coastguard Worker static inline void init_mbmi(MB_MODE_INFO *mbmi, PREDICTION_MODE curr_mode,
4480*77c1e3ccSAndroid Build Coastguard Worker                              const MV_REFERENCE_FRAME *ref_frames,
4481*77c1e3ccSAndroid Build Coastguard Worker                              const AV1_COMMON *cm) {
4482*77c1e3ccSAndroid Build Coastguard Worker   PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info;
4483*77c1e3ccSAndroid Build Coastguard Worker   mbmi->ref_mv_idx = 0;
4484*77c1e3ccSAndroid Build Coastguard Worker   mbmi->mode = curr_mode;
4485*77c1e3ccSAndroid Build Coastguard Worker   mbmi->uv_mode = UV_DC_PRED;
4486*77c1e3ccSAndroid Build Coastguard Worker   mbmi->ref_frame[0] = ref_frames[0];
4487*77c1e3ccSAndroid Build Coastguard Worker   mbmi->ref_frame[1] = ref_frames[1];
4488*77c1e3ccSAndroid Build Coastguard Worker   pmi->palette_size[0] = 0;
4489*77c1e3ccSAndroid Build Coastguard Worker   pmi->palette_size[1] = 0;
4490*77c1e3ccSAndroid Build Coastguard Worker   mbmi->filter_intra_mode_info.use_filter_intra = 0;
4491*77c1e3ccSAndroid Build Coastguard Worker   mbmi->mv[0].as_int = mbmi->mv[1].as_int = 0;
4492*77c1e3ccSAndroid Build Coastguard Worker   mbmi->motion_mode = SIMPLE_TRANSLATION;
4493*77c1e3ccSAndroid Build Coastguard Worker   mbmi->interintra_mode = (INTERINTRA_MODE)(II_DC_PRED - 1);
4494*77c1e3ccSAndroid Build Coastguard Worker   set_default_interp_filters(mbmi, cm->features.interp_filter);
4495*77c1e3ccSAndroid Build Coastguard Worker }
4496*77c1e3ccSAndroid Build Coastguard Worker 
collect_single_states(MACROBLOCK * x,InterModeSearchState * search_state,const MB_MODE_INFO * const mbmi)4497*77c1e3ccSAndroid Build Coastguard Worker static inline void collect_single_states(MACROBLOCK *x,
4498*77c1e3ccSAndroid Build Coastguard Worker                                          InterModeSearchState *search_state,
4499*77c1e3ccSAndroid Build Coastguard Worker                                          const MB_MODE_INFO *const mbmi) {
4500*77c1e3ccSAndroid Build Coastguard Worker   int i, j;
4501*77c1e3ccSAndroid Build Coastguard Worker   const MV_REFERENCE_FRAME ref_frame = mbmi->ref_frame[0];
4502*77c1e3ccSAndroid Build Coastguard Worker   const PREDICTION_MODE this_mode = mbmi->mode;
4503*77c1e3ccSAndroid Build Coastguard Worker   const int dir = ref_frame <= GOLDEN_FRAME ? 0 : 1;
4504*77c1e3ccSAndroid Build Coastguard Worker   const int mode_offset = INTER_OFFSET(this_mode);
4505*77c1e3ccSAndroid Build Coastguard Worker   const int ref_set = get_drl_refmv_count(x, mbmi->ref_frame, this_mode);
4506*77c1e3ccSAndroid Build Coastguard Worker 
4507*77c1e3ccSAndroid Build Coastguard Worker   // Simple rd
4508*77c1e3ccSAndroid Build Coastguard Worker   int64_t simple_rd = search_state->simple_rd[this_mode][0][ref_frame];
4509*77c1e3ccSAndroid Build Coastguard Worker   for (int ref_mv_idx = 1; ref_mv_idx < ref_set; ++ref_mv_idx) {
4510*77c1e3ccSAndroid Build Coastguard Worker     const int64_t rd =
4511*77c1e3ccSAndroid Build Coastguard Worker         search_state->simple_rd[this_mode][ref_mv_idx][ref_frame];
4512*77c1e3ccSAndroid Build Coastguard Worker     if (rd < simple_rd) simple_rd = rd;
4513*77c1e3ccSAndroid Build Coastguard Worker   }
4514*77c1e3ccSAndroid Build Coastguard Worker 
4515*77c1e3ccSAndroid Build Coastguard Worker   // Insertion sort of single_state
4516*77c1e3ccSAndroid Build Coastguard Worker   const SingleInterModeState this_state_s = { simple_rd, ref_frame, 1 };
4517*77c1e3ccSAndroid Build Coastguard Worker   SingleInterModeState *state_s = search_state->single_state[dir][mode_offset];
4518*77c1e3ccSAndroid Build Coastguard Worker   i = search_state->single_state_cnt[dir][mode_offset];
4519*77c1e3ccSAndroid Build Coastguard Worker   for (j = i; j > 0 && state_s[j - 1].rd > this_state_s.rd; --j)
4520*77c1e3ccSAndroid Build Coastguard Worker     state_s[j] = state_s[j - 1];
4521*77c1e3ccSAndroid Build Coastguard Worker   state_s[j] = this_state_s;
4522*77c1e3ccSAndroid Build Coastguard Worker   search_state->single_state_cnt[dir][mode_offset]++;
4523*77c1e3ccSAndroid Build Coastguard Worker 
4524*77c1e3ccSAndroid Build Coastguard Worker   // Modelled rd
4525*77c1e3ccSAndroid Build Coastguard Worker   int64_t modelled_rd = search_state->modelled_rd[this_mode][0][ref_frame];
4526*77c1e3ccSAndroid Build Coastguard Worker   for (int ref_mv_idx = 1; ref_mv_idx < ref_set; ++ref_mv_idx) {
4527*77c1e3ccSAndroid Build Coastguard Worker     const int64_t rd =
4528*77c1e3ccSAndroid Build Coastguard Worker         search_state->modelled_rd[this_mode][ref_mv_idx][ref_frame];
4529*77c1e3ccSAndroid Build Coastguard Worker     if (rd < modelled_rd) modelled_rd = rd;
4530*77c1e3ccSAndroid Build Coastguard Worker   }
4531*77c1e3ccSAndroid Build Coastguard Worker 
4532*77c1e3ccSAndroid Build Coastguard Worker   // Insertion sort of single_state_modelled
4533*77c1e3ccSAndroid Build Coastguard Worker   const SingleInterModeState this_state_m = { modelled_rd, ref_frame, 1 };
4534*77c1e3ccSAndroid Build Coastguard Worker   SingleInterModeState *state_m =
4535*77c1e3ccSAndroid Build Coastguard Worker       search_state->single_state_modelled[dir][mode_offset];
4536*77c1e3ccSAndroid Build Coastguard Worker   i = search_state->single_state_modelled_cnt[dir][mode_offset];
4537*77c1e3ccSAndroid Build Coastguard Worker   for (j = i; j > 0 && state_m[j - 1].rd > this_state_m.rd; --j)
4538*77c1e3ccSAndroid Build Coastguard Worker     state_m[j] = state_m[j - 1];
4539*77c1e3ccSAndroid Build Coastguard Worker   state_m[j] = this_state_m;
4540*77c1e3ccSAndroid Build Coastguard Worker   search_state->single_state_modelled_cnt[dir][mode_offset]++;
4541*77c1e3ccSAndroid Build Coastguard Worker }
4542*77c1e3ccSAndroid Build Coastguard Worker 
analyze_single_states(const AV1_COMP * cpi,InterModeSearchState * search_state)4543*77c1e3ccSAndroid Build Coastguard Worker static inline void analyze_single_states(const AV1_COMP *cpi,
4544*77c1e3ccSAndroid Build Coastguard Worker                                          InterModeSearchState *search_state) {
4545*77c1e3ccSAndroid Build Coastguard Worker   const int prune_level = cpi->sf.inter_sf.prune_comp_search_by_single_result;
4546*77c1e3ccSAndroid Build Coastguard Worker   assert(prune_level >= 1);
4547*77c1e3ccSAndroid Build Coastguard Worker   int i, j, dir, mode;
4548*77c1e3ccSAndroid Build Coastguard Worker 
4549*77c1e3ccSAndroid Build Coastguard Worker   for (dir = 0; dir < 2; ++dir) {
4550*77c1e3ccSAndroid Build Coastguard Worker     int64_t best_rd;
4551*77c1e3ccSAndroid Build Coastguard Worker     SingleInterModeState(*state)[FWD_REFS];
4552*77c1e3ccSAndroid Build Coastguard Worker     const int prune_factor = prune_level >= 2 ? 6 : 5;
4553*77c1e3ccSAndroid Build Coastguard Worker 
4554*77c1e3ccSAndroid Build Coastguard Worker     // Use the best rd of GLOBALMV or NEWMV to prune the unlikely
4555*77c1e3ccSAndroid Build Coastguard Worker     // reference frames for all the modes (NEARESTMV and NEARMV may not
4556*77c1e3ccSAndroid Build Coastguard Worker     // have same motion vectors). Always keep the best of each mode
4557*77c1e3ccSAndroid Build Coastguard Worker     // because it might form the best possible combination with other mode.
4558*77c1e3ccSAndroid Build Coastguard Worker     state = search_state->single_state[dir];
4559*77c1e3ccSAndroid Build Coastguard Worker     best_rd = AOMMIN(state[INTER_OFFSET(NEWMV)][0].rd,
4560*77c1e3ccSAndroid Build Coastguard Worker                      state[INTER_OFFSET(GLOBALMV)][0].rd);
4561*77c1e3ccSAndroid Build Coastguard Worker     for (mode = 0; mode < SINGLE_INTER_MODE_NUM; ++mode) {
4562*77c1e3ccSAndroid Build Coastguard Worker       for (i = 1; i < search_state->single_state_cnt[dir][mode]; ++i) {
4563*77c1e3ccSAndroid Build Coastguard Worker         if (state[mode][i].rd != INT64_MAX &&
4564*77c1e3ccSAndroid Build Coastguard Worker             (state[mode][i].rd >> 3) * prune_factor > best_rd) {
4565*77c1e3ccSAndroid Build Coastguard Worker           state[mode][i].valid = 0;
4566*77c1e3ccSAndroid Build Coastguard Worker         }
4567*77c1e3ccSAndroid Build Coastguard Worker       }
4568*77c1e3ccSAndroid Build Coastguard Worker     }
4569*77c1e3ccSAndroid Build Coastguard Worker 
4570*77c1e3ccSAndroid Build Coastguard Worker     state = search_state->single_state_modelled[dir];
4571*77c1e3ccSAndroid Build Coastguard Worker     best_rd = AOMMIN(state[INTER_OFFSET(NEWMV)][0].rd,
4572*77c1e3ccSAndroid Build Coastguard Worker                      state[INTER_OFFSET(GLOBALMV)][0].rd);
4573*77c1e3ccSAndroid Build Coastguard Worker     for (mode = 0; mode < SINGLE_INTER_MODE_NUM; ++mode) {
4574*77c1e3ccSAndroid Build Coastguard Worker       for (i = 1; i < search_state->single_state_modelled_cnt[dir][mode]; ++i) {
4575*77c1e3ccSAndroid Build Coastguard Worker         if (state[mode][i].rd != INT64_MAX &&
4576*77c1e3ccSAndroid Build Coastguard Worker             (state[mode][i].rd >> 3) * prune_factor > best_rd) {
4577*77c1e3ccSAndroid Build Coastguard Worker           state[mode][i].valid = 0;
4578*77c1e3ccSAndroid Build Coastguard Worker         }
4579*77c1e3ccSAndroid Build Coastguard Worker       }
4580*77c1e3ccSAndroid Build Coastguard Worker     }
4581*77c1e3ccSAndroid Build Coastguard Worker   }
4582*77c1e3ccSAndroid Build Coastguard Worker 
4583*77c1e3ccSAndroid Build Coastguard Worker   // Ordering by simple rd first, then by modelled rd
4584*77c1e3ccSAndroid Build Coastguard Worker   for (dir = 0; dir < 2; ++dir) {
4585*77c1e3ccSAndroid Build Coastguard Worker     for (mode = 0; mode < SINGLE_INTER_MODE_NUM; ++mode) {
4586*77c1e3ccSAndroid Build Coastguard Worker       const int state_cnt_s = search_state->single_state_cnt[dir][mode];
4587*77c1e3ccSAndroid Build Coastguard Worker       const int state_cnt_m =
4588*77c1e3ccSAndroid Build Coastguard Worker           search_state->single_state_modelled_cnt[dir][mode];
4589*77c1e3ccSAndroid Build Coastguard Worker       SingleInterModeState *state_s = search_state->single_state[dir][mode];
4590*77c1e3ccSAndroid Build Coastguard Worker       SingleInterModeState *state_m =
4591*77c1e3ccSAndroid Build Coastguard Worker           search_state->single_state_modelled[dir][mode];
4592*77c1e3ccSAndroid Build Coastguard Worker       int count = 0;
4593*77c1e3ccSAndroid Build Coastguard Worker       const int max_candidates = AOMMAX(state_cnt_s, state_cnt_m);
4594*77c1e3ccSAndroid Build Coastguard Worker       for (i = 0; i < state_cnt_s; ++i) {
4595*77c1e3ccSAndroid Build Coastguard Worker         if (state_s[i].rd == INT64_MAX) break;
4596*77c1e3ccSAndroid Build Coastguard Worker         if (state_s[i].valid) {
4597*77c1e3ccSAndroid Build Coastguard Worker           search_state->single_rd_order[dir][mode][count++] =
4598*77c1e3ccSAndroid Build Coastguard Worker               state_s[i].ref_frame;
4599*77c1e3ccSAndroid Build Coastguard Worker         }
4600*77c1e3ccSAndroid Build Coastguard Worker       }
4601*77c1e3ccSAndroid Build Coastguard Worker       if (count >= max_candidates) continue;
4602*77c1e3ccSAndroid Build Coastguard Worker 
4603*77c1e3ccSAndroid Build Coastguard Worker       for (i = 0; i < state_cnt_m && count < max_candidates; ++i) {
4604*77c1e3ccSAndroid Build Coastguard Worker         if (state_m[i].rd == INT64_MAX) break;
4605*77c1e3ccSAndroid Build Coastguard Worker         if (!state_m[i].valid) continue;
4606*77c1e3ccSAndroid Build Coastguard Worker         const int ref_frame = state_m[i].ref_frame;
4607*77c1e3ccSAndroid Build Coastguard Worker         int match = 0;
4608*77c1e3ccSAndroid Build Coastguard Worker         // Check if existing already
4609*77c1e3ccSAndroid Build Coastguard Worker         for (j = 0; j < count; ++j) {
4610*77c1e3ccSAndroid Build Coastguard Worker           if (search_state->single_rd_order[dir][mode][j] == ref_frame) {
4611*77c1e3ccSAndroid Build Coastguard Worker             match = 1;
4612*77c1e3ccSAndroid Build Coastguard Worker             break;
4613*77c1e3ccSAndroid Build Coastguard Worker           }
4614*77c1e3ccSAndroid Build Coastguard Worker         }
4615*77c1e3ccSAndroid Build Coastguard Worker         if (match) continue;
4616*77c1e3ccSAndroid Build Coastguard Worker         // Check if this ref_frame is removed in simple rd
4617*77c1e3ccSAndroid Build Coastguard Worker         int valid = 1;
4618*77c1e3ccSAndroid Build Coastguard Worker         for (j = 0; j < state_cnt_s; ++j) {
4619*77c1e3ccSAndroid Build Coastguard Worker           if (ref_frame == state_s[j].ref_frame) {
4620*77c1e3ccSAndroid Build Coastguard Worker             valid = state_s[j].valid;
4621*77c1e3ccSAndroid Build Coastguard Worker             break;
4622*77c1e3ccSAndroid Build Coastguard Worker           }
4623*77c1e3ccSAndroid Build Coastguard Worker         }
4624*77c1e3ccSAndroid Build Coastguard Worker         if (valid) {
4625*77c1e3ccSAndroid Build Coastguard Worker           search_state->single_rd_order[dir][mode][count++] = ref_frame;
4626*77c1e3ccSAndroid Build Coastguard Worker         }
4627*77c1e3ccSAndroid Build Coastguard Worker       }
4628*77c1e3ccSAndroid Build Coastguard Worker     }
4629*77c1e3ccSAndroid Build Coastguard Worker   }
4630*77c1e3ccSAndroid Build Coastguard Worker }
4631*77c1e3ccSAndroid Build Coastguard Worker 
compound_skip_get_candidates(const AV1_COMP * cpi,const InterModeSearchState * search_state,const int dir,const PREDICTION_MODE mode)4632*77c1e3ccSAndroid Build Coastguard Worker static int compound_skip_get_candidates(
4633*77c1e3ccSAndroid Build Coastguard Worker     const AV1_COMP *cpi, const InterModeSearchState *search_state,
4634*77c1e3ccSAndroid Build Coastguard Worker     const int dir, const PREDICTION_MODE mode) {
4635*77c1e3ccSAndroid Build Coastguard Worker   const int mode_offset = INTER_OFFSET(mode);
4636*77c1e3ccSAndroid Build Coastguard Worker   const SingleInterModeState *state =
4637*77c1e3ccSAndroid Build Coastguard Worker       search_state->single_state[dir][mode_offset];
4638*77c1e3ccSAndroid Build Coastguard Worker   const SingleInterModeState *state_modelled =
4639*77c1e3ccSAndroid Build Coastguard Worker       search_state->single_state_modelled[dir][mode_offset];
4640*77c1e3ccSAndroid Build Coastguard Worker 
4641*77c1e3ccSAndroid Build Coastguard Worker   int max_candidates = 0;
4642*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < FWD_REFS; ++i) {
4643*77c1e3ccSAndroid Build Coastguard Worker     if (search_state->single_rd_order[dir][mode_offset][i] == NONE_FRAME) break;
4644*77c1e3ccSAndroid Build Coastguard Worker     max_candidates++;
4645*77c1e3ccSAndroid Build Coastguard Worker   }
4646*77c1e3ccSAndroid Build Coastguard Worker 
4647*77c1e3ccSAndroid Build Coastguard Worker   int candidates = max_candidates;
4648*77c1e3ccSAndroid Build Coastguard Worker   if (cpi->sf.inter_sf.prune_comp_search_by_single_result >= 2) {
4649*77c1e3ccSAndroid Build Coastguard Worker     candidates = AOMMIN(2, max_candidates);
4650*77c1e3ccSAndroid Build Coastguard Worker   }
4651*77c1e3ccSAndroid Build Coastguard Worker   if (cpi->sf.inter_sf.prune_comp_search_by_single_result >= 3) {
4652*77c1e3ccSAndroid Build Coastguard Worker     if (state[0].rd != INT64_MAX && state_modelled[0].rd != INT64_MAX &&
4653*77c1e3ccSAndroid Build Coastguard Worker         state[0].ref_frame == state_modelled[0].ref_frame)
4654*77c1e3ccSAndroid Build Coastguard Worker       candidates = 1;
4655*77c1e3ccSAndroid Build Coastguard Worker     if (mode == NEARMV || mode == GLOBALMV) candidates = 1;
4656*77c1e3ccSAndroid Build Coastguard Worker   }
4657*77c1e3ccSAndroid Build Coastguard Worker 
4658*77c1e3ccSAndroid Build Coastguard Worker   if (cpi->sf.inter_sf.prune_comp_search_by_single_result >= 4) {
4659*77c1e3ccSAndroid Build Coastguard Worker     // Limit the number of candidates to 1 in each direction for compound
4660*77c1e3ccSAndroid Build Coastguard Worker     // prediction
4661*77c1e3ccSAndroid Build Coastguard Worker     candidates = AOMMIN(1, candidates);
4662*77c1e3ccSAndroid Build Coastguard Worker   }
4663*77c1e3ccSAndroid Build Coastguard Worker   return candidates;
4664*77c1e3ccSAndroid Build Coastguard Worker }
4665*77c1e3ccSAndroid Build Coastguard Worker 
compound_skip_by_single_states(const AV1_COMP * cpi,const InterModeSearchState * search_state,const PREDICTION_MODE this_mode,const MV_REFERENCE_FRAME ref_frame,const MV_REFERENCE_FRAME second_ref_frame,const MACROBLOCK * x)4666*77c1e3ccSAndroid Build Coastguard Worker static int compound_skip_by_single_states(
4667*77c1e3ccSAndroid Build Coastguard Worker     const AV1_COMP *cpi, const InterModeSearchState *search_state,
4668*77c1e3ccSAndroid Build Coastguard Worker     const PREDICTION_MODE this_mode, const MV_REFERENCE_FRAME ref_frame,
4669*77c1e3ccSAndroid Build Coastguard Worker     const MV_REFERENCE_FRAME second_ref_frame, const MACROBLOCK *x) {
4670*77c1e3ccSAndroid Build Coastguard Worker   const MV_REFERENCE_FRAME refs[2] = { ref_frame, second_ref_frame };
4671*77c1e3ccSAndroid Build Coastguard Worker   const int mode[2] = { compound_ref0_mode(this_mode),
4672*77c1e3ccSAndroid Build Coastguard Worker                         compound_ref1_mode(this_mode) };
4673*77c1e3ccSAndroid Build Coastguard Worker   const int mode_offset[2] = { INTER_OFFSET(mode[0]), INTER_OFFSET(mode[1]) };
4674*77c1e3ccSAndroid Build Coastguard Worker   const int mode_dir[2] = { refs[0] <= GOLDEN_FRAME ? 0 : 1,
4675*77c1e3ccSAndroid Build Coastguard Worker                             refs[1] <= GOLDEN_FRAME ? 0 : 1 };
4676*77c1e3ccSAndroid Build Coastguard Worker   int ref_searched[2] = { 0, 0 };
4677*77c1e3ccSAndroid Build Coastguard Worker   int ref_mv_match[2] = { 1, 1 };
4678*77c1e3ccSAndroid Build Coastguard Worker   int i, j;
4679*77c1e3ccSAndroid Build Coastguard Worker 
4680*77c1e3ccSAndroid Build Coastguard Worker   for (i = 0; i < 2; ++i) {
4681*77c1e3ccSAndroid Build Coastguard Worker     const SingleInterModeState *state =
4682*77c1e3ccSAndroid Build Coastguard Worker         search_state->single_state[mode_dir[i]][mode_offset[i]];
4683*77c1e3ccSAndroid Build Coastguard Worker     const int state_cnt =
4684*77c1e3ccSAndroid Build Coastguard Worker         search_state->single_state_cnt[mode_dir[i]][mode_offset[i]];
4685*77c1e3ccSAndroid Build Coastguard Worker     for (j = 0; j < state_cnt; ++j) {
4686*77c1e3ccSAndroid Build Coastguard Worker       if (state[j].ref_frame == refs[i]) {
4687*77c1e3ccSAndroid Build Coastguard Worker         ref_searched[i] = 1;
4688*77c1e3ccSAndroid Build Coastguard Worker         break;
4689*77c1e3ccSAndroid Build Coastguard Worker       }
4690*77c1e3ccSAndroid Build Coastguard Worker     }
4691*77c1e3ccSAndroid Build Coastguard Worker   }
4692*77c1e3ccSAndroid Build Coastguard Worker 
4693*77c1e3ccSAndroid Build Coastguard Worker   const int ref_set = get_drl_refmv_count(x, refs, this_mode);
4694*77c1e3ccSAndroid Build Coastguard Worker   for (i = 0; i < 2; ++i) {
4695*77c1e3ccSAndroid Build Coastguard Worker     if (!ref_searched[i] || (mode[i] != NEARESTMV && mode[i] != NEARMV)) {
4696*77c1e3ccSAndroid Build Coastguard Worker       continue;
4697*77c1e3ccSAndroid Build Coastguard Worker     }
4698*77c1e3ccSAndroid Build Coastguard Worker     const MV_REFERENCE_FRAME single_refs[2] = { refs[i], NONE_FRAME };
4699*77c1e3ccSAndroid Build Coastguard Worker     for (int ref_mv_idx = 0; ref_mv_idx < ref_set; ref_mv_idx++) {
4700*77c1e3ccSAndroid Build Coastguard Worker       int_mv single_mv;
4701*77c1e3ccSAndroid Build Coastguard Worker       int_mv comp_mv;
4702*77c1e3ccSAndroid Build Coastguard Worker       get_this_mv(&single_mv, mode[i], 0, ref_mv_idx, 0, single_refs,
4703*77c1e3ccSAndroid Build Coastguard Worker                   &x->mbmi_ext);
4704*77c1e3ccSAndroid Build Coastguard Worker       get_this_mv(&comp_mv, this_mode, i, ref_mv_idx, 0, refs, &x->mbmi_ext);
4705*77c1e3ccSAndroid Build Coastguard Worker       if (single_mv.as_int != comp_mv.as_int) {
4706*77c1e3ccSAndroid Build Coastguard Worker         ref_mv_match[i] = 0;
4707*77c1e3ccSAndroid Build Coastguard Worker         break;
4708*77c1e3ccSAndroid Build Coastguard Worker       }
4709*77c1e3ccSAndroid Build Coastguard Worker     }
4710*77c1e3ccSAndroid Build Coastguard Worker   }
4711*77c1e3ccSAndroid Build Coastguard Worker 
4712*77c1e3ccSAndroid Build Coastguard Worker   for (i = 0; i < 2; ++i) {
4713*77c1e3ccSAndroid Build Coastguard Worker     if (!ref_searched[i] || !ref_mv_match[i]) continue;
4714*77c1e3ccSAndroid Build Coastguard Worker     const int candidates =
4715*77c1e3ccSAndroid Build Coastguard Worker         compound_skip_get_candidates(cpi, search_state, mode_dir[i], mode[i]);
4716*77c1e3ccSAndroid Build Coastguard Worker     const MV_REFERENCE_FRAME *ref_order =
4717*77c1e3ccSAndroid Build Coastguard Worker         search_state->single_rd_order[mode_dir[i]][mode_offset[i]];
4718*77c1e3ccSAndroid Build Coastguard Worker     int match = 0;
4719*77c1e3ccSAndroid Build Coastguard Worker     for (j = 0; j < candidates; ++j) {
4720*77c1e3ccSAndroid Build Coastguard Worker       if (refs[i] == ref_order[j]) {
4721*77c1e3ccSAndroid Build Coastguard Worker         match = 1;
4722*77c1e3ccSAndroid Build Coastguard Worker         break;
4723*77c1e3ccSAndroid Build Coastguard Worker       }
4724*77c1e3ccSAndroid Build Coastguard Worker     }
4725*77c1e3ccSAndroid Build Coastguard Worker     if (!match) return 1;
4726*77c1e3ccSAndroid Build Coastguard Worker   }
4727*77c1e3ccSAndroid Build Coastguard Worker 
4728*77c1e3ccSAndroid Build Coastguard Worker   return 0;
4729*77c1e3ccSAndroid Build Coastguard Worker }
4730*77c1e3ccSAndroid Build Coastguard Worker 
4731*77c1e3ccSAndroid Build Coastguard Worker // Check if ref frames of current block matches with given block.
match_ref_frame(const MB_MODE_INFO * const mbmi,const MV_REFERENCE_FRAME * ref_frames,int * const is_ref_match)4732*77c1e3ccSAndroid Build Coastguard Worker static inline void match_ref_frame(const MB_MODE_INFO *const mbmi,
4733*77c1e3ccSAndroid Build Coastguard Worker                                    const MV_REFERENCE_FRAME *ref_frames,
4734*77c1e3ccSAndroid Build Coastguard Worker                                    int *const is_ref_match) {
4735*77c1e3ccSAndroid Build Coastguard Worker   if (is_inter_block(mbmi)) {
4736*77c1e3ccSAndroid Build Coastguard Worker     is_ref_match[0] |= ref_frames[0] == mbmi->ref_frame[0];
4737*77c1e3ccSAndroid Build Coastguard Worker     is_ref_match[1] |= ref_frames[1] == mbmi->ref_frame[0];
4738*77c1e3ccSAndroid Build Coastguard Worker     if (has_second_ref(mbmi)) {
4739*77c1e3ccSAndroid Build Coastguard Worker       is_ref_match[0] |= ref_frames[0] == mbmi->ref_frame[1];
4740*77c1e3ccSAndroid Build Coastguard Worker       is_ref_match[1] |= ref_frames[1] == mbmi->ref_frame[1];
4741*77c1e3ccSAndroid Build Coastguard Worker     }
4742*77c1e3ccSAndroid Build Coastguard Worker   }
4743*77c1e3ccSAndroid Build Coastguard Worker }
4744*77c1e3ccSAndroid Build Coastguard Worker 
4745*77c1e3ccSAndroid Build Coastguard Worker // Prune compound mode using ref frames of neighbor blocks.
compound_skip_using_neighbor_refs(MACROBLOCKD * const xd,const PREDICTION_MODE this_mode,const MV_REFERENCE_FRAME * ref_frames,int prune_ext_comp_using_neighbors)4746*77c1e3ccSAndroid Build Coastguard Worker static inline int compound_skip_using_neighbor_refs(
4747*77c1e3ccSAndroid Build Coastguard Worker     MACROBLOCKD *const xd, const PREDICTION_MODE this_mode,
4748*77c1e3ccSAndroid Build Coastguard Worker     const MV_REFERENCE_FRAME *ref_frames, int prune_ext_comp_using_neighbors) {
4749*77c1e3ccSAndroid Build Coastguard Worker   // Exclude non-extended compound modes from pruning
4750*77c1e3ccSAndroid Build Coastguard Worker   if (this_mode == NEAREST_NEARESTMV || this_mode == NEAR_NEARMV ||
4751*77c1e3ccSAndroid Build Coastguard Worker       this_mode == NEW_NEWMV || this_mode == GLOBAL_GLOBALMV)
4752*77c1e3ccSAndroid Build Coastguard Worker     return 0;
4753*77c1e3ccSAndroid Build Coastguard Worker 
4754*77c1e3ccSAndroid Build Coastguard Worker   if (prune_ext_comp_using_neighbors >= 3) return 1;
4755*77c1e3ccSAndroid Build Coastguard Worker 
4756*77c1e3ccSAndroid Build Coastguard Worker   int is_ref_match[2] = { 0 };  // 0 - match for forward refs
4757*77c1e3ccSAndroid Build Coastguard Worker                                 // 1 - match for backward refs
4758*77c1e3ccSAndroid Build Coastguard Worker   // Check if ref frames of this block matches with left neighbor.
4759*77c1e3ccSAndroid Build Coastguard Worker   if (xd->left_available)
4760*77c1e3ccSAndroid Build Coastguard Worker     match_ref_frame(xd->left_mbmi, ref_frames, is_ref_match);
4761*77c1e3ccSAndroid Build Coastguard Worker 
4762*77c1e3ccSAndroid Build Coastguard Worker   // Check if ref frames of this block matches with above neighbor.
4763*77c1e3ccSAndroid Build Coastguard Worker   if (xd->up_available)
4764*77c1e3ccSAndroid Build Coastguard Worker     match_ref_frame(xd->above_mbmi, ref_frames, is_ref_match);
4765*77c1e3ccSAndroid Build Coastguard Worker 
4766*77c1e3ccSAndroid Build Coastguard Worker   // Combine ref frame match with neighbors in forward and backward refs.
4767*77c1e3ccSAndroid Build Coastguard Worker   const int track_ref_match = is_ref_match[0] + is_ref_match[1];
4768*77c1e3ccSAndroid Build Coastguard Worker 
4769*77c1e3ccSAndroid Build Coastguard Worker   // Pruning based on ref frame match with neighbors.
4770*77c1e3ccSAndroid Build Coastguard Worker   if (track_ref_match >= prune_ext_comp_using_neighbors) return 0;
4771*77c1e3ccSAndroid Build Coastguard Worker   return 1;
4772*77c1e3ccSAndroid Build Coastguard Worker }
4773*77c1e3ccSAndroid Build Coastguard Worker 
4774*77c1e3ccSAndroid Build Coastguard Worker // Update best single mode for the given reference frame based on simple rd.
update_best_single_mode(InterModeSearchState * search_state,const PREDICTION_MODE this_mode,const MV_REFERENCE_FRAME ref_frame,int64_t this_rd)4775*77c1e3ccSAndroid Build Coastguard Worker static inline void update_best_single_mode(InterModeSearchState *search_state,
4776*77c1e3ccSAndroid Build Coastguard Worker                                            const PREDICTION_MODE this_mode,
4777*77c1e3ccSAndroid Build Coastguard Worker                                            const MV_REFERENCE_FRAME ref_frame,
4778*77c1e3ccSAndroid Build Coastguard Worker                                            int64_t this_rd) {
4779*77c1e3ccSAndroid Build Coastguard Worker   if (this_rd < search_state->best_single_rd[ref_frame]) {
4780*77c1e3ccSAndroid Build Coastguard Worker     search_state->best_single_rd[ref_frame] = this_rd;
4781*77c1e3ccSAndroid Build Coastguard Worker     search_state->best_single_mode[ref_frame] = this_mode;
4782*77c1e3ccSAndroid Build Coastguard Worker   }
4783*77c1e3ccSAndroid Build Coastguard Worker }
4784*77c1e3ccSAndroid Build Coastguard Worker 
4785*77c1e3ccSAndroid Build Coastguard Worker // Prune compound mode using best single mode for the same reference.
skip_compound_using_best_single_mode_ref(const PREDICTION_MODE this_mode,const MV_REFERENCE_FRAME * ref_frames,const PREDICTION_MODE * best_single_mode,int prune_comp_using_best_single_mode_ref)4786*77c1e3ccSAndroid Build Coastguard Worker static inline int skip_compound_using_best_single_mode_ref(
4787*77c1e3ccSAndroid Build Coastguard Worker     const PREDICTION_MODE this_mode, const MV_REFERENCE_FRAME *ref_frames,
4788*77c1e3ccSAndroid Build Coastguard Worker     const PREDICTION_MODE *best_single_mode,
4789*77c1e3ccSAndroid Build Coastguard Worker     int prune_comp_using_best_single_mode_ref) {
4790*77c1e3ccSAndroid Build Coastguard Worker   // Exclude non-extended compound modes from pruning
4791*77c1e3ccSAndroid Build Coastguard Worker   if (this_mode == NEAREST_NEARESTMV || this_mode == NEAR_NEARMV ||
4792*77c1e3ccSAndroid Build Coastguard Worker       this_mode == NEW_NEWMV || this_mode == GLOBAL_GLOBALMV)
4793*77c1e3ccSAndroid Build Coastguard Worker     return 0;
4794*77c1e3ccSAndroid Build Coastguard Worker 
4795*77c1e3ccSAndroid Build Coastguard Worker   assert(this_mode >= NEAREST_NEWMV && this_mode <= NEW_NEARMV);
4796*77c1e3ccSAndroid Build Coastguard Worker   const PREDICTION_MODE comp_mode_ref0 = compound_ref0_mode(this_mode);
4797*77c1e3ccSAndroid Build Coastguard Worker   // Get ref frame direction corresponding to NEWMV
4798*77c1e3ccSAndroid Build Coastguard Worker   // 0 - NEWMV corresponding to forward direction
4799*77c1e3ccSAndroid Build Coastguard Worker   // 1 - NEWMV corresponding to backward direction
4800*77c1e3ccSAndroid Build Coastguard Worker   const int newmv_dir = comp_mode_ref0 != NEWMV;
4801*77c1e3ccSAndroid Build Coastguard Worker 
4802*77c1e3ccSAndroid Build Coastguard Worker   // Avoid pruning the compound mode when ref frame corresponding to NEWMV
4803*77c1e3ccSAndroid Build Coastguard Worker   // have NEWMV as single mode winner.
4804*77c1e3ccSAndroid Build Coastguard Worker   // Example: For an extended-compound mode,
4805*77c1e3ccSAndroid Build Coastguard Worker   // {mode, {fwd_frame, bwd_frame}} = {NEAR_NEWMV, {LAST_FRAME, ALTREF_FRAME}}
4806*77c1e3ccSAndroid Build Coastguard Worker   // - Ref frame corresponding to NEWMV is ALTREF_FRAME
4807*77c1e3ccSAndroid Build Coastguard Worker   // - Avoid pruning this mode, if best single mode corresponding to ref frame
4808*77c1e3ccSAndroid Build Coastguard Worker   //   ALTREF_FRAME is NEWMV
4809*77c1e3ccSAndroid Build Coastguard Worker   const PREDICTION_MODE single_mode = best_single_mode[ref_frames[newmv_dir]];
4810*77c1e3ccSAndroid Build Coastguard Worker   if (single_mode == NEWMV) return 0;
4811*77c1e3ccSAndroid Build Coastguard Worker 
4812*77c1e3ccSAndroid Build Coastguard Worker   // Avoid pruning the compound mode when best single mode is not available
4813*77c1e3ccSAndroid Build Coastguard Worker   if (prune_comp_using_best_single_mode_ref == 1)
4814*77c1e3ccSAndroid Build Coastguard Worker     if (single_mode == MB_MODE_COUNT) return 0;
4815*77c1e3ccSAndroid Build Coastguard Worker   return 1;
4816*77c1e3ccSAndroid Build Coastguard Worker }
4817*77c1e3ccSAndroid Build Coastguard Worker 
compare_int64(const void * a,const void * b)4818*77c1e3ccSAndroid Build Coastguard Worker static int compare_int64(const void *a, const void *b) {
4819*77c1e3ccSAndroid Build Coastguard Worker   int64_t a64 = *((int64_t *)a);
4820*77c1e3ccSAndroid Build Coastguard Worker   int64_t b64 = *((int64_t *)b);
4821*77c1e3ccSAndroid Build Coastguard Worker   if (a64 < b64) {
4822*77c1e3ccSAndroid Build Coastguard Worker     return -1;
4823*77c1e3ccSAndroid Build Coastguard Worker   } else if (a64 == b64) {
4824*77c1e3ccSAndroid Build Coastguard Worker     return 0;
4825*77c1e3ccSAndroid Build Coastguard Worker   } else {
4826*77c1e3ccSAndroid Build Coastguard Worker     return 1;
4827*77c1e3ccSAndroid Build Coastguard Worker   }
4828*77c1e3ccSAndroid Build Coastguard Worker }
4829*77c1e3ccSAndroid Build Coastguard Worker 
update_search_state(InterModeSearchState * search_state,RD_STATS * best_rd_stats_dst,PICK_MODE_CONTEXT * ctx,const RD_STATS * new_best_rd_stats,const RD_STATS * new_best_rd_stats_y,const RD_STATS * new_best_rd_stats_uv,THR_MODES new_best_mode,const MACROBLOCK * x,int txfm_search_done)4830*77c1e3ccSAndroid Build Coastguard Worker static inline void update_search_state(
4831*77c1e3ccSAndroid Build Coastguard Worker     InterModeSearchState *search_state, RD_STATS *best_rd_stats_dst,
4832*77c1e3ccSAndroid Build Coastguard Worker     PICK_MODE_CONTEXT *ctx, const RD_STATS *new_best_rd_stats,
4833*77c1e3ccSAndroid Build Coastguard Worker     const RD_STATS *new_best_rd_stats_y, const RD_STATS *new_best_rd_stats_uv,
4834*77c1e3ccSAndroid Build Coastguard Worker     THR_MODES new_best_mode, const MACROBLOCK *x, int txfm_search_done) {
4835*77c1e3ccSAndroid Build Coastguard Worker   const MACROBLOCKD *xd = &x->e_mbd;
4836*77c1e3ccSAndroid Build Coastguard Worker   const MB_MODE_INFO *mbmi = xd->mi[0];
4837*77c1e3ccSAndroid Build Coastguard Worker   const int skip_ctx = av1_get_skip_txfm_context(xd);
4838*77c1e3ccSAndroid Build Coastguard Worker   const int skip_txfm =
4839*77c1e3ccSAndroid Build Coastguard Worker       mbmi->skip_txfm && !is_mode_intra(av1_mode_defs[new_best_mode].mode);
4840*77c1e3ccSAndroid Build Coastguard Worker   const TxfmSearchInfo *txfm_info = &x->txfm_search_info;
4841*77c1e3ccSAndroid Build Coastguard Worker 
4842*77c1e3ccSAndroid Build Coastguard Worker   search_state->best_rd = new_best_rd_stats->rdcost;
4843*77c1e3ccSAndroid Build Coastguard Worker   search_state->best_mode_index = new_best_mode;
4844*77c1e3ccSAndroid Build Coastguard Worker   *best_rd_stats_dst = *new_best_rd_stats;
4845*77c1e3ccSAndroid Build Coastguard Worker   search_state->best_mbmode = *mbmi;
4846*77c1e3ccSAndroid Build Coastguard Worker   search_state->best_skip2 = skip_txfm;
4847*77c1e3ccSAndroid Build Coastguard Worker   search_state->best_mode_skippable = new_best_rd_stats->skip_txfm;
4848*77c1e3ccSAndroid Build Coastguard Worker   // When !txfm_search_done, new_best_rd_stats won't provide correct rate_y and
4849*77c1e3ccSAndroid Build Coastguard Worker   // rate_uv because av1_txfm_search process is replaced by rd estimation.
4850*77c1e3ccSAndroid Build Coastguard Worker   // Therefore, we should avoid updating best_rate_y and best_rate_uv here.
4851*77c1e3ccSAndroid Build Coastguard Worker   // These two values will be updated when av1_txfm_search is called.
4852*77c1e3ccSAndroid Build Coastguard Worker   if (txfm_search_done) {
4853*77c1e3ccSAndroid Build Coastguard Worker     search_state->best_rate_y =
4854*77c1e3ccSAndroid Build Coastguard Worker         new_best_rd_stats_y->rate +
4855*77c1e3ccSAndroid Build Coastguard Worker         x->mode_costs.skip_txfm_cost[skip_ctx]
4856*77c1e3ccSAndroid Build Coastguard Worker                                     [new_best_rd_stats->skip_txfm || skip_txfm];
4857*77c1e3ccSAndroid Build Coastguard Worker     search_state->best_rate_uv = new_best_rd_stats_uv->rate;
4858*77c1e3ccSAndroid Build Coastguard Worker   }
4859*77c1e3ccSAndroid Build Coastguard Worker   search_state->best_y_rdcost = *new_best_rd_stats_y;
4860*77c1e3ccSAndroid Build Coastguard Worker   memcpy(ctx->blk_skip, txfm_info->blk_skip,
4861*77c1e3ccSAndroid Build Coastguard Worker          sizeof(txfm_info->blk_skip[0]) * ctx->num_4x4_blk);
4862*77c1e3ccSAndroid Build Coastguard Worker   av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
4863*77c1e3ccSAndroid Build Coastguard Worker }
4864*77c1e3ccSAndroid Build Coastguard Worker 
4865*77c1e3ccSAndroid Build Coastguard Worker // Find the best RD for a reference frame (among single reference modes)
4866*77c1e3ccSAndroid Build Coastguard Worker // and store +10% of it in the 0-th element in ref_frame_rd.
find_top_ref(int64_t ref_frame_rd[REF_FRAMES])4867*77c1e3ccSAndroid Build Coastguard Worker static inline void find_top_ref(int64_t ref_frame_rd[REF_FRAMES]) {
4868*77c1e3ccSAndroid Build Coastguard Worker   assert(ref_frame_rd[0] == INT64_MAX);
4869*77c1e3ccSAndroid Build Coastguard Worker   int64_t ref_copy[REF_FRAMES - 1];
4870*77c1e3ccSAndroid Build Coastguard Worker   memcpy(ref_copy, ref_frame_rd + 1,
4871*77c1e3ccSAndroid Build Coastguard Worker          sizeof(ref_frame_rd[0]) * (REF_FRAMES - 1));
4872*77c1e3ccSAndroid Build Coastguard Worker   qsort(ref_copy, REF_FRAMES - 1, sizeof(int64_t), compare_int64);
4873*77c1e3ccSAndroid Build Coastguard Worker 
4874*77c1e3ccSAndroid Build Coastguard Worker   int64_t cutoff = ref_copy[0];
4875*77c1e3ccSAndroid Build Coastguard Worker   // The cut-off is within 10% of the best.
4876*77c1e3ccSAndroid Build Coastguard Worker   if (cutoff != INT64_MAX) {
4877*77c1e3ccSAndroid Build Coastguard Worker     assert(cutoff < INT64_MAX / 200);
4878*77c1e3ccSAndroid Build Coastguard Worker     cutoff = (110 * cutoff) / 100;
4879*77c1e3ccSAndroid Build Coastguard Worker   }
4880*77c1e3ccSAndroid Build Coastguard Worker   ref_frame_rd[0] = cutoff;
4881*77c1e3ccSAndroid Build Coastguard Worker }
4882*77c1e3ccSAndroid Build Coastguard Worker 
4883*77c1e3ccSAndroid Build Coastguard Worker // Check if either frame is within the cutoff.
in_single_ref_cutoff(int64_t ref_frame_rd[REF_FRAMES],MV_REFERENCE_FRAME frame1,MV_REFERENCE_FRAME frame2)4884*77c1e3ccSAndroid Build Coastguard Worker static inline bool in_single_ref_cutoff(int64_t ref_frame_rd[REF_FRAMES],
4885*77c1e3ccSAndroid Build Coastguard Worker                                         MV_REFERENCE_FRAME frame1,
4886*77c1e3ccSAndroid Build Coastguard Worker                                         MV_REFERENCE_FRAME frame2) {
4887*77c1e3ccSAndroid Build Coastguard Worker   assert(frame2 > 0);
4888*77c1e3ccSAndroid Build Coastguard Worker   return ref_frame_rd[frame1] <= ref_frame_rd[0] ||
4889*77c1e3ccSAndroid Build Coastguard Worker          ref_frame_rd[frame2] <= ref_frame_rd[0];
4890*77c1e3ccSAndroid Build Coastguard Worker }
4891*77c1e3ccSAndroid Build Coastguard Worker 
evaluate_motion_mode_for_winner_candidates(const AV1_COMP * const cpi,MACROBLOCK * const x,RD_STATS * const rd_cost,HandleInterModeArgs * const args,TileDataEnc * const tile_data,PICK_MODE_CONTEXT * const ctx,struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE],const motion_mode_best_st_candidate * const best_motion_mode_cands,int do_tx_search,const BLOCK_SIZE bsize,int64_t * const best_est_rd,InterModeSearchState * const search_state,int64_t * yrd)4892*77c1e3ccSAndroid Build Coastguard Worker static inline void evaluate_motion_mode_for_winner_candidates(
4893*77c1e3ccSAndroid Build Coastguard Worker     const AV1_COMP *const cpi, MACROBLOCK *const x, RD_STATS *const rd_cost,
4894*77c1e3ccSAndroid Build Coastguard Worker     HandleInterModeArgs *const args, TileDataEnc *const tile_data,
4895*77c1e3ccSAndroid Build Coastguard Worker     PICK_MODE_CONTEXT *const ctx,
4896*77c1e3ccSAndroid Build Coastguard Worker     struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE],
4897*77c1e3ccSAndroid Build Coastguard Worker     const motion_mode_best_st_candidate *const best_motion_mode_cands,
4898*77c1e3ccSAndroid Build Coastguard Worker     int do_tx_search, const BLOCK_SIZE bsize, int64_t *const best_est_rd,
4899*77c1e3ccSAndroid Build Coastguard Worker     InterModeSearchState *const search_state, int64_t *yrd) {
4900*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
4901*77c1e3ccSAndroid Build Coastguard Worker   const int num_planes = av1_num_planes(cm);
4902*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *const xd = &x->e_mbd;
4903*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *const mbmi = xd->mi[0];
4904*77c1e3ccSAndroid Build Coastguard Worker   InterModesInfo *const inter_modes_info = x->inter_modes_info;
4905*77c1e3ccSAndroid Build Coastguard Worker   const int num_best_cand = best_motion_mode_cands->num_motion_mode_cand;
4906*77c1e3ccSAndroid Build Coastguard Worker 
4907*77c1e3ccSAndroid Build Coastguard Worker   for (int cand = 0; cand < num_best_cand; cand++) {
4908*77c1e3ccSAndroid Build Coastguard Worker     RD_STATS rd_stats;
4909*77c1e3ccSAndroid Build Coastguard Worker     RD_STATS rd_stats_y;
4910*77c1e3ccSAndroid Build Coastguard Worker     RD_STATS rd_stats_uv;
4911*77c1e3ccSAndroid Build Coastguard Worker     av1_init_rd_stats(&rd_stats);
4912*77c1e3ccSAndroid Build Coastguard Worker     av1_init_rd_stats(&rd_stats_y);
4913*77c1e3ccSAndroid Build Coastguard Worker     av1_init_rd_stats(&rd_stats_uv);
4914*77c1e3ccSAndroid Build Coastguard Worker     int rate_mv;
4915*77c1e3ccSAndroid Build Coastguard Worker 
4916*77c1e3ccSAndroid Build Coastguard Worker     rate_mv = best_motion_mode_cands->motion_mode_cand[cand].rate_mv;
4917*77c1e3ccSAndroid Build Coastguard Worker     args->skip_motion_mode =
4918*77c1e3ccSAndroid Build Coastguard Worker         best_motion_mode_cands->motion_mode_cand[cand].skip_motion_mode;
4919*77c1e3ccSAndroid Build Coastguard Worker     *mbmi = best_motion_mode_cands->motion_mode_cand[cand].mbmi;
4920*77c1e3ccSAndroid Build Coastguard Worker     rd_stats.rate =
4921*77c1e3ccSAndroid Build Coastguard Worker         best_motion_mode_cands->motion_mode_cand[cand].rate2_nocoeff;
4922*77c1e3ccSAndroid Build Coastguard Worker 
4923*77c1e3ccSAndroid Build Coastguard Worker     // Continue if the best candidate is compound.
4924*77c1e3ccSAndroid Build Coastguard Worker     if (!is_inter_singleref_mode(mbmi->mode)) continue;
4925*77c1e3ccSAndroid Build Coastguard Worker 
4926*77c1e3ccSAndroid Build Coastguard Worker     x->txfm_search_info.skip_txfm = 0;
4927*77c1e3ccSAndroid Build Coastguard Worker     struct macroblockd_plane *pd = xd->plane;
4928*77c1e3ccSAndroid Build Coastguard Worker     const BUFFER_SET orig_dst = {
4929*77c1e3ccSAndroid Build Coastguard Worker       { pd[0].dst.buf, pd[1].dst.buf, pd[2].dst.buf },
4930*77c1e3ccSAndroid Build Coastguard Worker       { pd[0].dst.stride, pd[1].dst.stride, pd[2].dst.stride },
4931*77c1e3ccSAndroid Build Coastguard Worker     };
4932*77c1e3ccSAndroid Build Coastguard Worker 
4933*77c1e3ccSAndroid Build Coastguard Worker     set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
4934*77c1e3ccSAndroid Build Coastguard Worker     // Initialize motion mode to simple translation
4935*77c1e3ccSAndroid Build Coastguard Worker     // Calculation of switchable rate depends on it.
4936*77c1e3ccSAndroid Build Coastguard Worker     mbmi->motion_mode = 0;
4937*77c1e3ccSAndroid Build Coastguard Worker     const int is_comp_pred = mbmi->ref_frame[1] > INTRA_FRAME;
4938*77c1e3ccSAndroid Build Coastguard Worker     for (int i = 0; i < num_planes; i++) {
4939*77c1e3ccSAndroid Build Coastguard Worker       xd->plane[i].pre[0] = yv12_mb[mbmi->ref_frame[0]][i];
4940*77c1e3ccSAndroid Build Coastguard Worker       if (is_comp_pred) xd->plane[i].pre[1] = yv12_mb[mbmi->ref_frame[1]][i];
4941*77c1e3ccSAndroid Build Coastguard Worker     }
4942*77c1e3ccSAndroid Build Coastguard Worker 
4943*77c1e3ccSAndroid Build Coastguard Worker     int64_t skip_rd[2] = { search_state->best_skip_rd[0],
4944*77c1e3ccSAndroid Build Coastguard Worker                            search_state->best_skip_rd[1] };
4945*77c1e3ccSAndroid Build Coastguard Worker     int64_t this_yrd = INT64_MAX;
4946*77c1e3ccSAndroid Build Coastguard Worker     int64_t ret_value = motion_mode_rd(
4947*77c1e3ccSAndroid Build Coastguard Worker         cpi, tile_data, x, bsize, &rd_stats, &rd_stats_y, &rd_stats_uv, args,
4948*77c1e3ccSAndroid Build Coastguard Worker         search_state->best_rd, skip_rd, &rate_mv, &orig_dst, best_est_rd,
4949*77c1e3ccSAndroid Build Coastguard Worker         do_tx_search, inter_modes_info, 1, &this_yrd);
4950*77c1e3ccSAndroid Build Coastguard Worker 
4951*77c1e3ccSAndroid Build Coastguard Worker     if (ret_value != INT64_MAX) {
4952*77c1e3ccSAndroid Build Coastguard Worker       rd_stats.rdcost = RDCOST(x->rdmult, rd_stats.rate, rd_stats.dist);
4953*77c1e3ccSAndroid Build Coastguard Worker       const THR_MODES mode_enum = get_prediction_mode_idx(
4954*77c1e3ccSAndroid Build Coastguard Worker           mbmi->mode, mbmi->ref_frame[0], mbmi->ref_frame[1]);
4955*77c1e3ccSAndroid Build Coastguard Worker       // Collect mode stats for multiwinner mode processing
4956*77c1e3ccSAndroid Build Coastguard Worker       store_winner_mode_stats(
4957*77c1e3ccSAndroid Build Coastguard Worker           &cpi->common, x, mbmi, &rd_stats, &rd_stats_y, &rd_stats_uv,
4958*77c1e3ccSAndroid Build Coastguard Worker           mode_enum, NULL, bsize, rd_stats.rdcost,
4959*77c1e3ccSAndroid Build Coastguard Worker           cpi->sf.winner_mode_sf.multi_winner_mode_type, do_tx_search);
4960*77c1e3ccSAndroid Build Coastguard Worker       if (rd_stats.rdcost < search_state->best_rd) {
4961*77c1e3ccSAndroid Build Coastguard Worker         *yrd = this_yrd;
4962*77c1e3ccSAndroid Build Coastguard Worker         update_search_state(search_state, rd_cost, ctx, &rd_stats, &rd_stats_y,
4963*77c1e3ccSAndroid Build Coastguard Worker                             &rd_stats_uv, mode_enum, x, do_tx_search);
4964*77c1e3ccSAndroid Build Coastguard Worker         if (do_tx_search) search_state->best_skip_rd[0] = skip_rd[0];
4965*77c1e3ccSAndroid Build Coastguard Worker       }
4966*77c1e3ccSAndroid Build Coastguard Worker     }
4967*77c1e3ccSAndroid Build Coastguard Worker   }
4968*77c1e3ccSAndroid Build Coastguard Worker }
4969*77c1e3ccSAndroid Build Coastguard Worker 
4970*77c1e3ccSAndroid Build Coastguard Worker /*!\cond */
4971*77c1e3ccSAndroid Build Coastguard Worker // Arguments for speed feature pruning of inter mode search
4972*77c1e3ccSAndroid Build Coastguard Worker typedef struct {
4973*77c1e3ccSAndroid Build Coastguard Worker   int *skip_motion_mode;
4974*77c1e3ccSAndroid Build Coastguard Worker   mode_skip_mask_t *mode_skip_mask;
4975*77c1e3ccSAndroid Build Coastguard Worker   InterModeSearchState *search_state;
4976*77c1e3ccSAndroid Build Coastguard Worker   int skip_ref_frame_mask;
4977*77c1e3ccSAndroid Build Coastguard Worker   int reach_first_comp_mode;
4978*77c1e3ccSAndroid Build Coastguard Worker   int mode_thresh_mul_fact;
4979*77c1e3ccSAndroid Build Coastguard Worker   int num_single_modes_processed;
4980*77c1e3ccSAndroid Build Coastguard Worker   int prune_cpd_using_sr_stats_ready;
4981*77c1e3ccSAndroid Build Coastguard Worker } InterModeSFArgs;
4982*77c1e3ccSAndroid Build Coastguard Worker /*!\endcond */
4983*77c1e3ccSAndroid Build Coastguard Worker 
skip_inter_mode(AV1_COMP * cpi,MACROBLOCK * x,const BLOCK_SIZE bsize,int64_t * ref_frame_rd,int midx,InterModeSFArgs * args,int is_low_temp_var)4984*77c1e3ccSAndroid Build Coastguard Worker static int skip_inter_mode(AV1_COMP *cpi, MACROBLOCK *x, const BLOCK_SIZE bsize,
4985*77c1e3ccSAndroid Build Coastguard Worker                            int64_t *ref_frame_rd, int midx,
4986*77c1e3ccSAndroid Build Coastguard Worker                            InterModeSFArgs *args, int is_low_temp_var) {
4987*77c1e3ccSAndroid Build Coastguard Worker   const SPEED_FEATURES *const sf = &cpi->sf;
4988*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *const xd = &x->e_mbd;
4989*77c1e3ccSAndroid Build Coastguard Worker   // Get the actual prediction mode we are trying in this iteration
4990*77c1e3ccSAndroid Build Coastguard Worker   const THR_MODES mode_enum = av1_default_mode_order[midx];
4991*77c1e3ccSAndroid Build Coastguard Worker   const MODE_DEFINITION *mode_def = &av1_mode_defs[mode_enum];
4992*77c1e3ccSAndroid Build Coastguard Worker   const PREDICTION_MODE this_mode = mode_def->mode;
4993*77c1e3ccSAndroid Build Coastguard Worker   const MV_REFERENCE_FRAME *ref_frames = mode_def->ref_frame;
4994*77c1e3ccSAndroid Build Coastguard Worker   const MV_REFERENCE_FRAME ref_frame = ref_frames[0];
4995*77c1e3ccSAndroid Build Coastguard Worker   const MV_REFERENCE_FRAME second_ref_frame = ref_frames[1];
4996*77c1e3ccSAndroid Build Coastguard Worker   const int comp_pred = second_ref_frame > INTRA_FRAME;
4997*77c1e3ccSAndroid Build Coastguard Worker 
4998*77c1e3ccSAndroid Build Coastguard Worker   if (ref_frame == INTRA_FRAME) return 1;
4999*77c1e3ccSAndroid Build Coastguard Worker 
5000*77c1e3ccSAndroid Build Coastguard Worker   const FRAME_UPDATE_TYPE update_type =
5001*77c1e3ccSAndroid Build Coastguard Worker       get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index);
5002*77c1e3ccSAndroid Build Coastguard Worker   if (sf->inter_sf.skip_arf_compound && update_type == ARF_UPDATE &&
5003*77c1e3ccSAndroid Build Coastguard Worker       comp_pred) {
5004*77c1e3ccSAndroid Build Coastguard Worker     return 1;
5005*77c1e3ccSAndroid Build Coastguard Worker   }
5006*77c1e3ccSAndroid Build Coastguard Worker 
5007*77c1e3ccSAndroid Build Coastguard Worker   // This is for real time encoding.
5008*77c1e3ccSAndroid Build Coastguard Worker   if (is_low_temp_var && !comp_pred && ref_frame != LAST_FRAME &&
5009*77c1e3ccSAndroid Build Coastguard Worker       this_mode != NEARESTMV)
5010*77c1e3ccSAndroid Build Coastguard Worker     return 1;
5011*77c1e3ccSAndroid Build Coastguard Worker 
5012*77c1e3ccSAndroid Build Coastguard Worker   // Check if this mode should be skipped because it is incompatible with the
5013*77c1e3ccSAndroid Build Coastguard Worker   // current frame
5014*77c1e3ccSAndroid Build Coastguard Worker   if (inter_mode_compatible_skip(cpi, x, bsize, this_mode, ref_frames))
5015*77c1e3ccSAndroid Build Coastguard Worker     return 1;
5016*77c1e3ccSAndroid Build Coastguard Worker   const int ret = inter_mode_search_order_independent_skip(
5017*77c1e3ccSAndroid Build Coastguard Worker       cpi, x, args->mode_skip_mask, args->search_state,
5018*77c1e3ccSAndroid Build Coastguard Worker       args->skip_ref_frame_mask, this_mode, mode_def->ref_frame);
5019*77c1e3ccSAndroid Build Coastguard Worker   if (ret == 1) return 1;
5020*77c1e3ccSAndroid Build Coastguard Worker   *(args->skip_motion_mode) = (ret == 2);
5021*77c1e3ccSAndroid Build Coastguard Worker 
5022*77c1e3ccSAndroid Build Coastguard Worker   // We've reached the first compound prediction mode, get stats from the
5023*77c1e3ccSAndroid Build Coastguard Worker   // single reference predictors to help with pruning.
5024*77c1e3ccSAndroid Build Coastguard Worker   // Disable this pruning logic if interpolation filter search was skipped for
5025*77c1e3ccSAndroid Build Coastguard Worker   // single prediction modes as it can result in aggressive pruning of compound
5026*77c1e3ccSAndroid Build Coastguard Worker   // prediction modes due to the absence of modelled_rd populated by
5027*77c1e3ccSAndroid Build Coastguard Worker   // av1_interpolation_filter_search().
5028*77c1e3ccSAndroid Build Coastguard Worker   // TODO(Remya): Check the impact of the sf
5029*77c1e3ccSAndroid Build Coastguard Worker   // 'prune_comp_search_by_single_result' if compound prediction modes are
5030*77c1e3ccSAndroid Build Coastguard Worker   // enabled in future for REALTIME encode.
5031*77c1e3ccSAndroid Build Coastguard Worker   if (!sf->interp_sf.skip_interp_filter_search &&
5032*77c1e3ccSAndroid Build Coastguard Worker       sf->inter_sf.prune_comp_search_by_single_result > 0 && comp_pred &&
5033*77c1e3ccSAndroid Build Coastguard Worker       args->reach_first_comp_mode == 0) {
5034*77c1e3ccSAndroid Build Coastguard Worker     analyze_single_states(cpi, args->search_state);
5035*77c1e3ccSAndroid Build Coastguard Worker     args->reach_first_comp_mode = 1;
5036*77c1e3ccSAndroid Build Coastguard Worker   }
5037*77c1e3ccSAndroid Build Coastguard Worker 
5038*77c1e3ccSAndroid Build Coastguard Worker   // Prune aggressively when best mode is skippable.
5039*77c1e3ccSAndroid Build Coastguard Worker   int mul_fact = args->search_state->best_mode_skippable
5040*77c1e3ccSAndroid Build Coastguard Worker                      ? args->mode_thresh_mul_fact
5041*77c1e3ccSAndroid Build Coastguard Worker                      : (1 << MODE_THRESH_QBITS);
5042*77c1e3ccSAndroid Build Coastguard Worker   int64_t mode_threshold =
5043*77c1e3ccSAndroid Build Coastguard Worker       (args->search_state->mode_threshold[mode_enum] * mul_fact) >>
5044*77c1e3ccSAndroid Build Coastguard Worker       MODE_THRESH_QBITS;
5045*77c1e3ccSAndroid Build Coastguard Worker 
5046*77c1e3ccSAndroid Build Coastguard Worker   if (args->search_state->best_rd < mode_threshold) return 1;
5047*77c1e3ccSAndroid Build Coastguard Worker 
5048*77c1e3ccSAndroid Build Coastguard Worker   // Skip this compound mode based on the RD results from the single prediction
5049*77c1e3ccSAndroid Build Coastguard Worker   // modes
5050*77c1e3ccSAndroid Build Coastguard Worker   if (!sf->interp_sf.skip_interp_filter_search &&
5051*77c1e3ccSAndroid Build Coastguard Worker       sf->inter_sf.prune_comp_search_by_single_result > 0 && comp_pred) {
5052*77c1e3ccSAndroid Build Coastguard Worker     if (compound_skip_by_single_states(cpi, args->search_state, this_mode,
5053*77c1e3ccSAndroid Build Coastguard Worker                                        ref_frame, second_ref_frame, x))
5054*77c1e3ccSAndroid Build Coastguard Worker       return 1;
5055*77c1e3ccSAndroid Build Coastguard Worker   }
5056*77c1e3ccSAndroid Build Coastguard Worker 
5057*77c1e3ccSAndroid Build Coastguard Worker   if (sf->inter_sf.prune_compound_using_single_ref && comp_pred) {
5058*77c1e3ccSAndroid Build Coastguard Worker     // After we done with single reference modes, find the 2nd best RD
5059*77c1e3ccSAndroid Build Coastguard Worker     // for a reference frame. Only search compound modes that have a reference
5060*77c1e3ccSAndroid Build Coastguard Worker     // frame at least as good as the 2nd best.
5061*77c1e3ccSAndroid Build Coastguard Worker     if (!args->prune_cpd_using_sr_stats_ready &&
5062*77c1e3ccSAndroid Build Coastguard Worker         args->num_single_modes_processed == NUM_SINGLE_REF_MODES) {
5063*77c1e3ccSAndroid Build Coastguard Worker       find_top_ref(ref_frame_rd);
5064*77c1e3ccSAndroid Build Coastguard Worker       args->prune_cpd_using_sr_stats_ready = 1;
5065*77c1e3ccSAndroid Build Coastguard Worker     }
5066*77c1e3ccSAndroid Build Coastguard Worker     if (args->prune_cpd_using_sr_stats_ready &&
5067*77c1e3ccSAndroid Build Coastguard Worker         !in_single_ref_cutoff(ref_frame_rd, ref_frame, second_ref_frame))
5068*77c1e3ccSAndroid Build Coastguard Worker       return 1;
5069*77c1e3ccSAndroid Build Coastguard Worker   }
5070*77c1e3ccSAndroid Build Coastguard Worker 
5071*77c1e3ccSAndroid Build Coastguard Worker   // Skip NEW_NEARMV and NEAR_NEWMV extended compound modes
5072*77c1e3ccSAndroid Build Coastguard Worker   if (sf->inter_sf.skip_ext_comp_nearmv_mode &&
5073*77c1e3ccSAndroid Build Coastguard Worker       (this_mode == NEW_NEARMV || this_mode == NEAR_NEWMV)) {
5074*77c1e3ccSAndroid Build Coastguard Worker     return 1;
5075*77c1e3ccSAndroid Build Coastguard Worker   }
5076*77c1e3ccSAndroid Build Coastguard Worker 
5077*77c1e3ccSAndroid Build Coastguard Worker   if (sf->inter_sf.prune_ext_comp_using_neighbors && comp_pred) {
5078*77c1e3ccSAndroid Build Coastguard Worker     if (compound_skip_using_neighbor_refs(
5079*77c1e3ccSAndroid Build Coastguard Worker             xd, this_mode, ref_frames,
5080*77c1e3ccSAndroid Build Coastguard Worker             sf->inter_sf.prune_ext_comp_using_neighbors))
5081*77c1e3ccSAndroid Build Coastguard Worker       return 1;
5082*77c1e3ccSAndroid Build Coastguard Worker   }
5083*77c1e3ccSAndroid Build Coastguard Worker 
5084*77c1e3ccSAndroid Build Coastguard Worker   if (sf->inter_sf.prune_comp_using_best_single_mode_ref && comp_pred) {
5085*77c1e3ccSAndroid Build Coastguard Worker     if (skip_compound_using_best_single_mode_ref(
5086*77c1e3ccSAndroid Build Coastguard Worker             this_mode, ref_frames, args->search_state->best_single_mode,
5087*77c1e3ccSAndroid Build Coastguard Worker             sf->inter_sf.prune_comp_using_best_single_mode_ref))
5088*77c1e3ccSAndroid Build Coastguard Worker       return 1;
5089*77c1e3ccSAndroid Build Coastguard Worker   }
5090*77c1e3ccSAndroid Build Coastguard Worker 
5091*77c1e3ccSAndroid Build Coastguard Worker   if (sf->inter_sf.prune_nearest_near_mv_using_refmv_weight && !comp_pred) {
5092*77c1e3ccSAndroid Build Coastguard Worker     const int8_t ref_frame_type = av1_ref_frame_type(ref_frames);
5093*77c1e3ccSAndroid Build Coastguard Worker     if (skip_nearest_near_mv_using_refmv_weight(
5094*77c1e3ccSAndroid Build Coastguard Worker             x, this_mode, ref_frame_type,
5095*77c1e3ccSAndroid Build Coastguard Worker             args->search_state->best_mbmode.mode)) {
5096*77c1e3ccSAndroid Build Coastguard Worker       // Ensure the mode is pruned only when the current block has obtained a
5097*77c1e3ccSAndroid Build Coastguard Worker       // valid inter mode.
5098*77c1e3ccSAndroid Build Coastguard Worker       assert(is_inter_mode(args->search_state->best_mbmode.mode));
5099*77c1e3ccSAndroid Build Coastguard Worker       return 1;
5100*77c1e3ccSAndroid Build Coastguard Worker     }
5101*77c1e3ccSAndroid Build Coastguard Worker   }
5102*77c1e3ccSAndroid Build Coastguard Worker 
5103*77c1e3ccSAndroid Build Coastguard Worker   if (sf->rt_sf.prune_inter_modes_with_golden_ref &&
5104*77c1e3ccSAndroid Build Coastguard Worker       ref_frame == GOLDEN_FRAME && !comp_pred) {
5105*77c1e3ccSAndroid Build Coastguard Worker     const int subgop_size = AOMMIN(cpi->ppi->gf_group.size, FIXED_GF_INTERVAL);
5106*77c1e3ccSAndroid Build Coastguard Worker     if (cpi->rc.frames_since_golden > (subgop_size >> 2) &&
5107*77c1e3ccSAndroid Build Coastguard Worker         args->search_state->best_mbmode.ref_frame[0] != GOLDEN_FRAME) {
5108*77c1e3ccSAndroid Build Coastguard Worker       if ((bsize > BLOCK_16X16 && this_mode == NEWMV) || this_mode == NEARMV)
5109*77c1e3ccSAndroid Build Coastguard Worker         return 1;
5110*77c1e3ccSAndroid Build Coastguard Worker     }
5111*77c1e3ccSAndroid Build Coastguard Worker   }
5112*77c1e3ccSAndroid Build Coastguard Worker 
5113*77c1e3ccSAndroid Build Coastguard Worker   return 0;
5114*77c1e3ccSAndroid Build Coastguard Worker }
5115*77c1e3ccSAndroid Build Coastguard Worker 
record_best_compound(REFERENCE_MODE reference_mode,RD_STATS * rd_stats,int comp_pred,int rdmult,InterModeSearchState * search_state,int compmode_cost)5116*77c1e3ccSAndroid Build Coastguard Worker static void record_best_compound(REFERENCE_MODE reference_mode,
5117*77c1e3ccSAndroid Build Coastguard Worker                                  RD_STATS *rd_stats, int comp_pred, int rdmult,
5118*77c1e3ccSAndroid Build Coastguard Worker                                  InterModeSearchState *search_state,
5119*77c1e3ccSAndroid Build Coastguard Worker                                  int compmode_cost) {
5120*77c1e3ccSAndroid Build Coastguard Worker   int64_t single_rd, hybrid_rd, single_rate, hybrid_rate;
5121*77c1e3ccSAndroid Build Coastguard Worker 
5122*77c1e3ccSAndroid Build Coastguard Worker   if (reference_mode == REFERENCE_MODE_SELECT) {
5123*77c1e3ccSAndroid Build Coastguard Worker     single_rate = rd_stats->rate - compmode_cost;
5124*77c1e3ccSAndroid Build Coastguard Worker     hybrid_rate = rd_stats->rate;
5125*77c1e3ccSAndroid Build Coastguard Worker   } else {
5126*77c1e3ccSAndroid Build Coastguard Worker     single_rate = rd_stats->rate;
5127*77c1e3ccSAndroid Build Coastguard Worker     hybrid_rate = rd_stats->rate + compmode_cost;
5128*77c1e3ccSAndroid Build Coastguard Worker   }
5129*77c1e3ccSAndroid Build Coastguard Worker 
5130*77c1e3ccSAndroid Build Coastguard Worker   single_rd = RDCOST(rdmult, single_rate, rd_stats->dist);
5131*77c1e3ccSAndroid Build Coastguard Worker   hybrid_rd = RDCOST(rdmult, hybrid_rate, rd_stats->dist);
5132*77c1e3ccSAndroid Build Coastguard Worker 
5133*77c1e3ccSAndroid Build Coastguard Worker   if (!comp_pred) {
5134*77c1e3ccSAndroid Build Coastguard Worker     if (single_rd < search_state->best_pred_rd[SINGLE_REFERENCE])
5135*77c1e3ccSAndroid Build Coastguard Worker       search_state->best_pred_rd[SINGLE_REFERENCE] = single_rd;
5136*77c1e3ccSAndroid Build Coastguard Worker   } else {
5137*77c1e3ccSAndroid Build Coastguard Worker     if (single_rd < search_state->best_pred_rd[COMPOUND_REFERENCE])
5138*77c1e3ccSAndroid Build Coastguard Worker       search_state->best_pred_rd[COMPOUND_REFERENCE] = single_rd;
5139*77c1e3ccSAndroid Build Coastguard Worker   }
5140*77c1e3ccSAndroid Build Coastguard Worker   if (hybrid_rd < search_state->best_pred_rd[REFERENCE_MODE_SELECT])
5141*77c1e3ccSAndroid Build Coastguard Worker     search_state->best_pred_rd[REFERENCE_MODE_SELECT] = hybrid_rd;
5142*77c1e3ccSAndroid Build Coastguard Worker }
5143*77c1e3ccSAndroid Build Coastguard Worker 
5144*77c1e3ccSAndroid Build Coastguard Worker // Does a transform search over a list of the best inter mode candidates.
5145*77c1e3ccSAndroid Build Coastguard Worker // This is called if the original mode search computed an RD estimate
5146*77c1e3ccSAndroid Build Coastguard Worker // for the transform search rather than doing a full search.
tx_search_best_inter_candidates(AV1_COMP * cpi,TileDataEnc * tile_data,MACROBLOCK * x,int64_t best_rd_so_far,BLOCK_SIZE bsize,struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE],int mi_row,int mi_col,InterModeSearchState * search_state,RD_STATS * rd_cost,PICK_MODE_CONTEXT * ctx,int64_t * yrd)5147*77c1e3ccSAndroid Build Coastguard Worker static void tx_search_best_inter_candidates(
5148*77c1e3ccSAndroid Build Coastguard Worker     AV1_COMP *cpi, TileDataEnc *tile_data, MACROBLOCK *x,
5149*77c1e3ccSAndroid Build Coastguard Worker     int64_t best_rd_so_far, BLOCK_SIZE bsize,
5150*77c1e3ccSAndroid Build Coastguard Worker     struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE], int mi_row, int mi_col,
5151*77c1e3ccSAndroid Build Coastguard Worker     InterModeSearchState *search_state, RD_STATS *rd_cost,
5152*77c1e3ccSAndroid Build Coastguard Worker     PICK_MODE_CONTEXT *ctx, int64_t *yrd) {
5153*77c1e3ccSAndroid Build Coastguard Worker   AV1_COMMON *const cm = &cpi->common;
5154*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *const xd = &x->e_mbd;
5155*77c1e3ccSAndroid Build Coastguard Worker   TxfmSearchInfo *txfm_info = &x->txfm_search_info;
5156*77c1e3ccSAndroid Build Coastguard Worker   const ModeCosts *mode_costs = &x->mode_costs;
5157*77c1e3ccSAndroid Build Coastguard Worker   const int num_planes = av1_num_planes(cm);
5158*77c1e3ccSAndroid Build Coastguard Worker   const int skip_ctx = av1_get_skip_txfm_context(xd);
5159*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *const mbmi = xd->mi[0];
5160*77c1e3ccSAndroid Build Coastguard Worker   InterModesInfo *inter_modes_info = x->inter_modes_info;
5161*77c1e3ccSAndroid Build Coastguard Worker   inter_modes_info_sort(inter_modes_info, inter_modes_info->rd_idx_pair_arr);
5162*77c1e3ccSAndroid Build Coastguard Worker   search_state->best_rd = best_rd_so_far;
5163*77c1e3ccSAndroid Build Coastguard Worker   search_state->best_mode_index = THR_INVALID;
5164*77c1e3ccSAndroid Build Coastguard Worker   // Initialize best mode stats for winner mode processing
5165*77c1e3ccSAndroid Build Coastguard Worker   x->winner_mode_count = 0;
5166*77c1e3ccSAndroid Build Coastguard Worker   store_winner_mode_stats(&cpi->common, x, mbmi, NULL, NULL, NULL, THR_INVALID,
5167*77c1e3ccSAndroid Build Coastguard Worker                           NULL, bsize, best_rd_so_far,
5168*77c1e3ccSAndroid Build Coastguard Worker                           cpi->sf.winner_mode_sf.multi_winner_mode_type, 0);
5169*77c1e3ccSAndroid Build Coastguard Worker   inter_modes_info->num =
5170*77c1e3ccSAndroid Build Coastguard Worker       inter_modes_info->num < cpi->sf.rt_sf.num_inter_modes_for_tx_search
5171*77c1e3ccSAndroid Build Coastguard Worker           ? inter_modes_info->num
5172*77c1e3ccSAndroid Build Coastguard Worker           : cpi->sf.rt_sf.num_inter_modes_for_tx_search;
5173*77c1e3ccSAndroid Build Coastguard Worker   const int64_t top_est_rd =
5174*77c1e3ccSAndroid Build Coastguard Worker       inter_modes_info->num > 0
5175*77c1e3ccSAndroid Build Coastguard Worker           ? inter_modes_info
5176*77c1e3ccSAndroid Build Coastguard Worker                 ->est_rd_arr[inter_modes_info->rd_idx_pair_arr[0].idx]
5177*77c1e3ccSAndroid Build Coastguard Worker           : INT64_MAX;
5178*77c1e3ccSAndroid Build Coastguard Worker   *yrd = INT64_MAX;
5179*77c1e3ccSAndroid Build Coastguard Worker   int64_t best_rd_in_this_partition = INT64_MAX;
5180*77c1e3ccSAndroid Build Coastguard Worker   int num_inter_mode_cands = inter_modes_info->num;
5181*77c1e3ccSAndroid Build Coastguard Worker   int newmv_mode_evaled = 0;
5182*77c1e3ccSAndroid Build Coastguard Worker   int max_allowed_cands = INT_MAX;
5183*77c1e3ccSAndroid Build Coastguard Worker   if (cpi->sf.inter_sf.limit_inter_mode_cands) {
5184*77c1e3ccSAndroid Build Coastguard Worker     // The bound on the no. of inter mode candidates, beyond which the
5185*77c1e3ccSAndroid Build Coastguard Worker     // candidates are limited if a newmv mode got evaluated, is set as
5186*77c1e3ccSAndroid Build Coastguard Worker     // max_allowed_cands + 1.
5187*77c1e3ccSAndroid Build Coastguard Worker     const int num_allowed_cands[5] = { INT_MAX, 10, 9, 6, 2 };
5188*77c1e3ccSAndroid Build Coastguard Worker     assert(cpi->sf.inter_sf.limit_inter_mode_cands <= 4);
5189*77c1e3ccSAndroid Build Coastguard Worker     max_allowed_cands =
5190*77c1e3ccSAndroid Build Coastguard Worker         num_allowed_cands[cpi->sf.inter_sf.limit_inter_mode_cands];
5191*77c1e3ccSAndroid Build Coastguard Worker   }
5192*77c1e3ccSAndroid Build Coastguard Worker 
5193*77c1e3ccSAndroid Build Coastguard Worker   int num_mode_thresh = INT_MAX;
5194*77c1e3ccSAndroid Build Coastguard Worker   if (cpi->sf.inter_sf.limit_txfm_eval_per_mode) {
5195*77c1e3ccSAndroid Build Coastguard Worker     // Bound the no. of transform searches per prediction mode beyond a
5196*77c1e3ccSAndroid Build Coastguard Worker     // threshold.
5197*77c1e3ccSAndroid Build Coastguard Worker     const int num_mode_thresh_ary[4] = { INT_MAX, 4, 3, 0 };
5198*77c1e3ccSAndroid Build Coastguard Worker     assert(cpi->sf.inter_sf.limit_txfm_eval_per_mode <= 3);
5199*77c1e3ccSAndroid Build Coastguard Worker     num_mode_thresh =
5200*77c1e3ccSAndroid Build Coastguard Worker         num_mode_thresh_ary[cpi->sf.inter_sf.limit_txfm_eval_per_mode];
5201*77c1e3ccSAndroid Build Coastguard Worker   }
5202*77c1e3ccSAndroid Build Coastguard Worker 
5203*77c1e3ccSAndroid Build Coastguard Worker   int num_tx_cands = 0;
5204*77c1e3ccSAndroid Build Coastguard Worker   int num_tx_search_modes[INTER_MODE_END - INTER_MODE_START] = { 0 };
5205*77c1e3ccSAndroid Build Coastguard Worker   // Iterate over best inter mode candidates and perform tx search
5206*77c1e3ccSAndroid Build Coastguard Worker   for (int j = 0; j < num_inter_mode_cands; ++j) {
5207*77c1e3ccSAndroid Build Coastguard Worker     const int data_idx = inter_modes_info->rd_idx_pair_arr[j].idx;
5208*77c1e3ccSAndroid Build Coastguard Worker     *mbmi = inter_modes_info->mbmi_arr[data_idx];
5209*77c1e3ccSAndroid Build Coastguard Worker     const PREDICTION_MODE prediction_mode = mbmi->mode;
5210*77c1e3ccSAndroid Build Coastguard Worker     int64_t curr_est_rd = inter_modes_info->est_rd_arr[data_idx];
5211*77c1e3ccSAndroid Build Coastguard Worker     if (curr_est_rd * 0.80 > top_est_rd) break;
5212*77c1e3ccSAndroid Build Coastguard Worker 
5213*77c1e3ccSAndroid Build Coastguard Worker     if (num_tx_cands > num_mode_thresh) {
5214*77c1e3ccSAndroid Build Coastguard Worker       if ((prediction_mode != NEARESTMV &&
5215*77c1e3ccSAndroid Build Coastguard Worker            num_tx_search_modes[prediction_mode - INTER_MODE_START] >= 1) ||
5216*77c1e3ccSAndroid Build Coastguard Worker           (prediction_mode == NEARESTMV &&
5217*77c1e3ccSAndroid Build Coastguard Worker            num_tx_search_modes[prediction_mode - INTER_MODE_START] >= 2))
5218*77c1e3ccSAndroid Build Coastguard Worker         continue;
5219*77c1e3ccSAndroid Build Coastguard Worker     }
5220*77c1e3ccSAndroid Build Coastguard Worker 
5221*77c1e3ccSAndroid Build Coastguard Worker     txfm_info->skip_txfm = 0;
5222*77c1e3ccSAndroid Build Coastguard Worker     set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
5223*77c1e3ccSAndroid Build Coastguard Worker 
5224*77c1e3ccSAndroid Build Coastguard Worker     // Select prediction reference frames.
5225*77c1e3ccSAndroid Build Coastguard Worker     const int is_comp_pred = mbmi->ref_frame[1] > INTRA_FRAME;
5226*77c1e3ccSAndroid Build Coastguard Worker     for (int i = 0; i < num_planes; i++) {
5227*77c1e3ccSAndroid Build Coastguard Worker       xd->plane[i].pre[0] = yv12_mb[mbmi->ref_frame[0]][i];
5228*77c1e3ccSAndroid Build Coastguard Worker       if (is_comp_pred) xd->plane[i].pre[1] = yv12_mb[mbmi->ref_frame[1]][i];
5229*77c1e3ccSAndroid Build Coastguard Worker     }
5230*77c1e3ccSAndroid Build Coastguard Worker 
5231*77c1e3ccSAndroid Build Coastguard Worker     bool is_predictor_built = false;
5232*77c1e3ccSAndroid Build Coastguard Worker 
5233*77c1e3ccSAndroid Build Coastguard Worker     // Initialize RD stats
5234*77c1e3ccSAndroid Build Coastguard Worker     RD_STATS rd_stats;
5235*77c1e3ccSAndroid Build Coastguard Worker     RD_STATS rd_stats_y;
5236*77c1e3ccSAndroid Build Coastguard Worker     RD_STATS rd_stats_uv;
5237*77c1e3ccSAndroid Build Coastguard Worker     const int mode_rate = inter_modes_info->mode_rate_arr[data_idx];
5238*77c1e3ccSAndroid Build Coastguard Worker     int64_t skip_rd = INT64_MAX;
5239*77c1e3ccSAndroid Build Coastguard Worker     const int txfm_rd_gate_level = get_txfm_rd_gate_level(
5240*77c1e3ccSAndroid Build Coastguard Worker         cm->seq_params->enable_masked_compound,
5241*77c1e3ccSAndroid Build Coastguard Worker         cpi->sf.inter_sf.txfm_rd_gate_level, bsize, TX_SEARCH_DEFAULT,
5242*77c1e3ccSAndroid Build Coastguard Worker         /*eval_motion_mode=*/0);
5243*77c1e3ccSAndroid Build Coastguard Worker     if (txfm_rd_gate_level) {
5244*77c1e3ccSAndroid Build Coastguard Worker       // Check if the mode is good enough based on skip RD
5245*77c1e3ccSAndroid Build Coastguard Worker       int64_t curr_sse = inter_modes_info->sse_arr[data_idx];
5246*77c1e3ccSAndroid Build Coastguard Worker       skip_rd = RDCOST(x->rdmult, mode_rate, curr_sse);
5247*77c1e3ccSAndroid Build Coastguard Worker       int eval_txfm = check_txfm_eval(x, bsize, search_state->best_skip_rd[0],
5248*77c1e3ccSAndroid Build Coastguard Worker                                       skip_rd, txfm_rd_gate_level, 0);
5249*77c1e3ccSAndroid Build Coastguard Worker       if (!eval_txfm) continue;
5250*77c1e3ccSAndroid Build Coastguard Worker     }
5251*77c1e3ccSAndroid Build Coastguard Worker 
5252*77c1e3ccSAndroid Build Coastguard Worker     // Build the prediction for this mode
5253*77c1e3ccSAndroid Build Coastguard Worker     if (!is_predictor_built) {
5254*77c1e3ccSAndroid Build Coastguard Worker       av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, 0,
5255*77c1e3ccSAndroid Build Coastguard Worker                                     av1_num_planes(cm) - 1);
5256*77c1e3ccSAndroid Build Coastguard Worker     }
5257*77c1e3ccSAndroid Build Coastguard Worker     if (mbmi->motion_mode == OBMC_CAUSAL) {
5258*77c1e3ccSAndroid Build Coastguard Worker       av1_build_obmc_inter_predictors_sb(cm, xd);
5259*77c1e3ccSAndroid Build Coastguard Worker     }
5260*77c1e3ccSAndroid Build Coastguard Worker 
5261*77c1e3ccSAndroid Build Coastguard Worker     num_tx_cands++;
5262*77c1e3ccSAndroid Build Coastguard Worker     if (have_newmv_in_inter_mode(prediction_mode)) newmv_mode_evaled = 1;
5263*77c1e3ccSAndroid Build Coastguard Worker     num_tx_search_modes[prediction_mode - INTER_MODE_START]++;
5264*77c1e3ccSAndroid Build Coastguard Worker     int64_t this_yrd = INT64_MAX;
5265*77c1e3ccSAndroid Build Coastguard Worker     // Do the transform search
5266*77c1e3ccSAndroid Build Coastguard Worker     if (!av1_txfm_search(cpi, x, bsize, &rd_stats, &rd_stats_y, &rd_stats_uv,
5267*77c1e3ccSAndroid Build Coastguard Worker                          mode_rate, search_state->best_rd)) {
5268*77c1e3ccSAndroid Build Coastguard Worker       continue;
5269*77c1e3ccSAndroid Build Coastguard Worker     } else {
5270*77c1e3ccSAndroid Build Coastguard Worker       const int y_rate =
5271*77c1e3ccSAndroid Build Coastguard Worker           rd_stats.skip_txfm
5272*77c1e3ccSAndroid Build Coastguard Worker               ? mode_costs->skip_txfm_cost[skip_ctx][1]
5273*77c1e3ccSAndroid Build Coastguard Worker               : (rd_stats_y.rate + mode_costs->skip_txfm_cost[skip_ctx][0]);
5274*77c1e3ccSAndroid Build Coastguard Worker       this_yrd = RDCOST(x->rdmult, y_rate + mode_rate, rd_stats_y.dist);
5275*77c1e3ccSAndroid Build Coastguard Worker 
5276*77c1e3ccSAndroid Build Coastguard Worker       if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1) {
5277*77c1e3ccSAndroid Build Coastguard Worker         inter_mode_data_push(
5278*77c1e3ccSAndroid Build Coastguard Worker             tile_data, mbmi->bsize, rd_stats.sse, rd_stats.dist,
5279*77c1e3ccSAndroid Build Coastguard Worker             rd_stats_y.rate + rd_stats_uv.rate +
5280*77c1e3ccSAndroid Build Coastguard Worker                 mode_costs->skip_txfm_cost[skip_ctx][mbmi->skip_txfm]);
5281*77c1e3ccSAndroid Build Coastguard Worker       }
5282*77c1e3ccSAndroid Build Coastguard Worker     }
5283*77c1e3ccSAndroid Build Coastguard Worker     rd_stats.rdcost = RDCOST(x->rdmult, rd_stats.rate, rd_stats.dist);
5284*77c1e3ccSAndroid Build Coastguard Worker     if (rd_stats.rdcost < best_rd_in_this_partition) {
5285*77c1e3ccSAndroid Build Coastguard Worker       best_rd_in_this_partition = rd_stats.rdcost;
5286*77c1e3ccSAndroid Build Coastguard Worker       *yrd = this_yrd;
5287*77c1e3ccSAndroid Build Coastguard Worker     }
5288*77c1e3ccSAndroid Build Coastguard Worker 
5289*77c1e3ccSAndroid Build Coastguard Worker     const THR_MODES mode_enum = get_prediction_mode_idx(
5290*77c1e3ccSAndroid Build Coastguard Worker         prediction_mode, mbmi->ref_frame[0], mbmi->ref_frame[1]);
5291*77c1e3ccSAndroid Build Coastguard Worker 
5292*77c1e3ccSAndroid Build Coastguard Worker     // Collect mode stats for multiwinner mode processing
5293*77c1e3ccSAndroid Build Coastguard Worker     const int txfm_search_done = 1;
5294*77c1e3ccSAndroid Build Coastguard Worker     store_winner_mode_stats(
5295*77c1e3ccSAndroid Build Coastguard Worker         &cpi->common, x, mbmi, &rd_stats, &rd_stats_y, &rd_stats_uv, mode_enum,
5296*77c1e3ccSAndroid Build Coastguard Worker         NULL, bsize, rd_stats.rdcost,
5297*77c1e3ccSAndroid Build Coastguard Worker         cpi->sf.winner_mode_sf.multi_winner_mode_type, txfm_search_done);
5298*77c1e3ccSAndroid Build Coastguard Worker 
5299*77c1e3ccSAndroid Build Coastguard Worker     if (rd_stats.rdcost < search_state->best_rd) {
5300*77c1e3ccSAndroid Build Coastguard Worker       update_search_state(search_state, rd_cost, ctx, &rd_stats, &rd_stats_y,
5301*77c1e3ccSAndroid Build Coastguard Worker                           &rd_stats_uv, mode_enum, x, txfm_search_done);
5302*77c1e3ccSAndroid Build Coastguard Worker       search_state->best_skip_rd[0] = skip_rd;
5303*77c1e3ccSAndroid Build Coastguard Worker       // Limit the total number of modes to be evaluated if the first is valid
5304*77c1e3ccSAndroid Build Coastguard Worker       // and transform skip or compound
5305*77c1e3ccSAndroid Build Coastguard Worker       if (cpi->sf.inter_sf.inter_mode_txfm_breakout) {
5306*77c1e3ccSAndroid Build Coastguard Worker         if (!j && (search_state->best_mbmode.skip_txfm || rd_stats.skip_txfm)) {
5307*77c1e3ccSAndroid Build Coastguard Worker           // Evaluate more candidates at high quantizers where occurrence of
5308*77c1e3ccSAndroid Build Coastguard Worker           // transform skip is high.
5309*77c1e3ccSAndroid Build Coastguard Worker           const int max_cands_cap[5] = { 2, 3, 5, 7, 9 };
5310*77c1e3ccSAndroid Build Coastguard Worker           const int qindex_band = (5 * x->qindex) >> QINDEX_BITS;
5311*77c1e3ccSAndroid Build Coastguard Worker           num_inter_mode_cands =
5312*77c1e3ccSAndroid Build Coastguard Worker               AOMMIN(max_cands_cap[qindex_band], inter_modes_info->num);
5313*77c1e3ccSAndroid Build Coastguard Worker         } else if (!j && has_second_ref(&search_state->best_mbmode)) {
5314*77c1e3ccSAndroid Build Coastguard Worker           const int aggr = cpi->sf.inter_sf.inter_mode_txfm_breakout - 1;
5315*77c1e3ccSAndroid Build Coastguard Worker           // Evaluate more candidates at low quantizers where occurrence of
5316*77c1e3ccSAndroid Build Coastguard Worker           // single reference mode is high.
5317*77c1e3ccSAndroid Build Coastguard Worker           const int max_cands_cap_cmp[2][4] = { { 10, 7, 5, 4 },
5318*77c1e3ccSAndroid Build Coastguard Worker                                                 { 10, 7, 5, 3 } };
5319*77c1e3ccSAndroid Build Coastguard Worker           const int qindex_band_cmp = (4 * x->qindex) >> QINDEX_BITS;
5320*77c1e3ccSAndroid Build Coastguard Worker           num_inter_mode_cands = AOMMIN(
5321*77c1e3ccSAndroid Build Coastguard Worker               max_cands_cap_cmp[aggr][qindex_band_cmp], inter_modes_info->num);
5322*77c1e3ccSAndroid Build Coastguard Worker         }
5323*77c1e3ccSAndroid Build Coastguard Worker       }
5324*77c1e3ccSAndroid Build Coastguard Worker     }
5325*77c1e3ccSAndroid Build Coastguard Worker     // If the number of candidates evaluated exceeds max_allowed_cands, break if
5326*77c1e3ccSAndroid Build Coastguard Worker     // a newmv mode was evaluated already.
5327*77c1e3ccSAndroid Build Coastguard Worker     if ((num_tx_cands > max_allowed_cands) && newmv_mode_evaled) break;
5328*77c1e3ccSAndroid Build Coastguard Worker   }
5329*77c1e3ccSAndroid Build Coastguard Worker }
5330*77c1e3ccSAndroid Build Coastguard Worker 
5331*77c1e3ccSAndroid Build Coastguard Worker // Indicates number of winner simple translation modes to be used
5332*77c1e3ccSAndroid Build Coastguard Worker static const unsigned int num_winner_motion_modes[3] = { 0, 10, 3 };
5333*77c1e3ccSAndroid Build Coastguard Worker 
5334*77c1e3ccSAndroid Build Coastguard Worker // Adds a motion mode to the candidate list for motion_mode_for_winner_cand
5335*77c1e3ccSAndroid Build Coastguard Worker // speed feature. This list consists of modes that have only searched
5336*77c1e3ccSAndroid Build Coastguard Worker // SIMPLE_TRANSLATION. The final list will be used to search other motion
5337*77c1e3ccSAndroid Build Coastguard Worker // modes after the initial RD search.
handle_winner_cand(MB_MODE_INFO * const mbmi,motion_mode_best_st_candidate * best_motion_mode_cands,int max_winner_motion_mode_cand,int64_t this_rd,motion_mode_candidate * motion_mode_cand,int skip_motion_mode)5338*77c1e3ccSAndroid Build Coastguard Worker static void handle_winner_cand(
5339*77c1e3ccSAndroid Build Coastguard Worker     MB_MODE_INFO *const mbmi,
5340*77c1e3ccSAndroid Build Coastguard Worker     motion_mode_best_st_candidate *best_motion_mode_cands,
5341*77c1e3ccSAndroid Build Coastguard Worker     int max_winner_motion_mode_cand, int64_t this_rd,
5342*77c1e3ccSAndroid Build Coastguard Worker     motion_mode_candidate *motion_mode_cand, int skip_motion_mode) {
5343*77c1e3ccSAndroid Build Coastguard Worker   // Number of current motion mode candidates in list
5344*77c1e3ccSAndroid Build Coastguard Worker   const int num_motion_mode_cand = best_motion_mode_cands->num_motion_mode_cand;
5345*77c1e3ccSAndroid Build Coastguard Worker   int valid_motion_mode_cand_loc = num_motion_mode_cand;
5346*77c1e3ccSAndroid Build Coastguard Worker 
5347*77c1e3ccSAndroid Build Coastguard Worker   // find the best location to insert new motion mode candidate
5348*77c1e3ccSAndroid Build Coastguard Worker   for (int j = 0; j < num_motion_mode_cand; j++) {
5349*77c1e3ccSAndroid Build Coastguard Worker     if (this_rd < best_motion_mode_cands->motion_mode_cand[j].rd_cost) {
5350*77c1e3ccSAndroid Build Coastguard Worker       valid_motion_mode_cand_loc = j;
5351*77c1e3ccSAndroid Build Coastguard Worker       break;
5352*77c1e3ccSAndroid Build Coastguard Worker     }
5353*77c1e3ccSAndroid Build Coastguard Worker   }
5354*77c1e3ccSAndroid Build Coastguard Worker 
5355*77c1e3ccSAndroid Build Coastguard Worker   // Insert motion mode if location is found
5356*77c1e3ccSAndroid Build Coastguard Worker   if (valid_motion_mode_cand_loc < max_winner_motion_mode_cand) {
5357*77c1e3ccSAndroid Build Coastguard Worker     if (num_motion_mode_cand > 0 &&
5358*77c1e3ccSAndroid Build Coastguard Worker         valid_motion_mode_cand_loc < max_winner_motion_mode_cand - 1)
5359*77c1e3ccSAndroid Build Coastguard Worker       memmove(
5360*77c1e3ccSAndroid Build Coastguard Worker           &best_motion_mode_cands
5361*77c1e3ccSAndroid Build Coastguard Worker                ->motion_mode_cand[valid_motion_mode_cand_loc + 1],
5362*77c1e3ccSAndroid Build Coastguard Worker           &best_motion_mode_cands->motion_mode_cand[valid_motion_mode_cand_loc],
5363*77c1e3ccSAndroid Build Coastguard Worker           (AOMMIN(num_motion_mode_cand, max_winner_motion_mode_cand - 1) -
5364*77c1e3ccSAndroid Build Coastguard Worker            valid_motion_mode_cand_loc) *
5365*77c1e3ccSAndroid Build Coastguard Worker               sizeof(best_motion_mode_cands->motion_mode_cand[0]));
5366*77c1e3ccSAndroid Build Coastguard Worker     motion_mode_cand->mbmi = *mbmi;
5367*77c1e3ccSAndroid Build Coastguard Worker     motion_mode_cand->rd_cost = this_rd;
5368*77c1e3ccSAndroid Build Coastguard Worker     motion_mode_cand->skip_motion_mode = skip_motion_mode;
5369*77c1e3ccSAndroid Build Coastguard Worker     best_motion_mode_cands->motion_mode_cand[valid_motion_mode_cand_loc] =
5370*77c1e3ccSAndroid Build Coastguard Worker         *motion_mode_cand;
5371*77c1e3ccSAndroid Build Coastguard Worker     best_motion_mode_cands->num_motion_mode_cand =
5372*77c1e3ccSAndroid Build Coastguard Worker         AOMMIN(max_winner_motion_mode_cand,
5373*77c1e3ccSAndroid Build Coastguard Worker                best_motion_mode_cands->num_motion_mode_cand + 1);
5374*77c1e3ccSAndroid Build Coastguard Worker   }
5375*77c1e3ccSAndroid Build Coastguard Worker }
5376*77c1e3ccSAndroid Build Coastguard Worker 
5377*77c1e3ccSAndroid Build Coastguard Worker /*!\brief Search intra modes in interframes
5378*77c1e3ccSAndroid Build Coastguard Worker  *
5379*77c1e3ccSAndroid Build Coastguard Worker  * \ingroup intra_mode_search
5380*77c1e3ccSAndroid Build Coastguard Worker  *
5381*77c1e3ccSAndroid Build Coastguard Worker  * This function searches for the best intra mode when the current frame is an
5382*77c1e3ccSAndroid Build Coastguard Worker  * interframe. This function however does *not* handle luma palette mode.
5383*77c1e3ccSAndroid Build Coastguard Worker  * Palette mode is currently handled by \ref av1_search_palette_mode.
5384*77c1e3ccSAndroid Build Coastguard Worker  *
5385*77c1e3ccSAndroid Build Coastguard Worker  * This function will first iterate through the luma mode candidates to find the
5386*77c1e3ccSAndroid Build Coastguard Worker  * best luma intra mode. Once the best luma mode it's found, it will then search
5387*77c1e3ccSAndroid Build Coastguard Worker  * for the best chroma mode. Because palette mode is currently not handled by
5388*77c1e3ccSAndroid Build Coastguard Worker  * here, a cache of uv mode is stored in
5389*77c1e3ccSAndroid Build Coastguard Worker  * InterModeSearchState::intra_search_state so it can be reused later by \ref
5390*77c1e3ccSAndroid Build Coastguard Worker  * av1_search_palette_mode.
5391*77c1e3ccSAndroid Build Coastguard Worker  *
5392*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] search_state      Struct keep track of the prediction mode
5393*77c1e3ccSAndroid Build Coastguard Worker  *                                  search state in interframe.
5394*77c1e3ccSAndroid Build Coastguard Worker  *
5395*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     cpi               Top-level encoder structure.
5396*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] x                 Pointer to struct holding all the data for
5397*77c1e3ccSAndroid Build Coastguard Worker  *                                  the current prediction block.
5398*77c1e3ccSAndroid Build Coastguard Worker  * \param[out]    rd_cost           Stores the best rd_cost among all the
5399*77c1e3ccSAndroid Build Coastguard Worker  *                                  prediction modes searched.
5400*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     bsize             Current block size.
5401*77c1e3ccSAndroid Build Coastguard Worker  * \param[in,out] ctx               Structure to hold the number of 4x4 blks to
5402*77c1e3ccSAndroid Build Coastguard Worker  *                                  copy the tx_type and txfm_skip arrays.
5403*77c1e3ccSAndroid Build Coastguard Worker  *                                  for only the Y plane.
5404*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     sf_args           Stores the list of intra mode candidates
5405*77c1e3ccSAndroid Build Coastguard Worker  *                                  to be searched.
5406*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     intra_ref_frame_cost  The entropy cost for signaling that the
5407*77c1e3ccSAndroid Build Coastguard Worker  *                                      current ref frame is an intra frame.
5408*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]     yrd_threshold     The rdcost threshold for luma intra mode to
5409*77c1e3ccSAndroid Build Coastguard Worker  *                                  terminate chroma intra mode search.
5410*77c1e3ccSAndroid Build Coastguard Worker  *
5411*77c1e3ccSAndroid Build Coastguard Worker  * \remark If a new best mode is found, search_state and rd_costs are updated
5412*77c1e3ccSAndroid Build Coastguard Worker  * correspondingly. While x is also modified, it is only used as a temporary
5413*77c1e3ccSAndroid Build Coastguard Worker  * buffer, and the final decisions are stored in search_state.
5414*77c1e3ccSAndroid Build Coastguard Worker  */
search_intra_modes_in_interframe(InterModeSearchState * search_state,const AV1_COMP * cpi,MACROBLOCK * x,RD_STATS * rd_cost,BLOCK_SIZE bsize,PICK_MODE_CONTEXT * ctx,const InterModeSFArgs * sf_args,unsigned int intra_ref_frame_cost,int64_t yrd_threshold)5415*77c1e3ccSAndroid Build Coastguard Worker static inline void search_intra_modes_in_interframe(
5416*77c1e3ccSAndroid Build Coastguard Worker     InterModeSearchState *search_state, const AV1_COMP *cpi, MACROBLOCK *x,
5417*77c1e3ccSAndroid Build Coastguard Worker     RD_STATS *rd_cost, BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx,
5418*77c1e3ccSAndroid Build Coastguard Worker     const InterModeSFArgs *sf_args, unsigned int intra_ref_frame_cost,
5419*77c1e3ccSAndroid Build Coastguard Worker     int64_t yrd_threshold) {
5420*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
5421*77c1e3ccSAndroid Build Coastguard Worker   const SPEED_FEATURES *const sf = &cpi->sf;
5422*77c1e3ccSAndroid Build Coastguard Worker   const IntraModeCfg *const intra_mode_cfg = &cpi->oxcf.intra_mode_cfg;
5423*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *const xd = &x->e_mbd;
5424*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *const mbmi = xd->mi[0];
5425*77c1e3ccSAndroid Build Coastguard Worker   IntraModeSearchState *intra_search_state = &search_state->intra_search_state;
5426*77c1e3ccSAndroid Build Coastguard Worker 
5427*77c1e3ccSAndroid Build Coastguard Worker   int is_best_y_mode_intra = 0;
5428*77c1e3ccSAndroid Build Coastguard Worker   RD_STATS best_intra_rd_stats_y;
5429*77c1e3ccSAndroid Build Coastguard Worker   int64_t best_rd_y = INT64_MAX;
5430*77c1e3ccSAndroid Build Coastguard Worker   int best_mode_cost_y = -1;
5431*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO best_mbmi = *xd->mi[0];
5432*77c1e3ccSAndroid Build Coastguard Worker   THR_MODES best_mode_enum = THR_INVALID;
5433*77c1e3ccSAndroid Build Coastguard Worker   uint8_t best_blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE];
5434*77c1e3ccSAndroid Build Coastguard Worker   uint8_t best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE];
5435*77c1e3ccSAndroid Build Coastguard Worker   const int num_4x4 = bsize_to_num_blk(bsize);
5436*77c1e3ccSAndroid Build Coastguard Worker 
5437*77c1e3ccSAndroid Build Coastguard Worker   // Performs luma search
5438*77c1e3ccSAndroid Build Coastguard Worker   int64_t best_model_rd = INT64_MAX;
5439*77c1e3ccSAndroid Build Coastguard Worker   int64_t top_intra_model_rd[TOP_INTRA_MODEL_COUNT];
5440*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < TOP_INTRA_MODEL_COUNT; i++) {
5441*77c1e3ccSAndroid Build Coastguard Worker     top_intra_model_rd[i] = INT64_MAX;
5442*77c1e3ccSAndroid Build Coastguard Worker   }
5443*77c1e3ccSAndroid Build Coastguard Worker   for (int mode_idx = 0; mode_idx < LUMA_MODE_COUNT; ++mode_idx) {
5444*77c1e3ccSAndroid Build Coastguard Worker     if (sf->intra_sf.skip_intra_in_interframe &&
5445*77c1e3ccSAndroid Build Coastguard Worker         search_state->intra_search_state.skip_intra_modes)
5446*77c1e3ccSAndroid Build Coastguard Worker       break;
5447*77c1e3ccSAndroid Build Coastguard Worker     set_y_mode_and_delta_angle(
5448*77c1e3ccSAndroid Build Coastguard Worker         mode_idx, mbmi, sf->intra_sf.prune_luma_odd_delta_angles_in_intra);
5449*77c1e3ccSAndroid Build Coastguard Worker     assert(mbmi->mode < INTRA_MODE_END);
5450*77c1e3ccSAndroid Build Coastguard Worker 
5451*77c1e3ccSAndroid Build Coastguard Worker     // Use intra_y_mode_mask speed feature to skip intra mode evaluation.
5452*77c1e3ccSAndroid Build Coastguard Worker     if (sf_args->mode_skip_mask->pred_modes[INTRA_FRAME] & (1 << mbmi->mode))
5453*77c1e3ccSAndroid Build Coastguard Worker       continue;
5454*77c1e3ccSAndroid Build Coastguard Worker 
5455*77c1e3ccSAndroid Build Coastguard Worker     const THR_MODES mode_enum =
5456*77c1e3ccSAndroid Build Coastguard Worker         get_prediction_mode_idx(mbmi->mode, INTRA_FRAME, NONE_FRAME);
5457*77c1e3ccSAndroid Build Coastguard Worker     if ((!intra_mode_cfg->enable_smooth_intra ||
5458*77c1e3ccSAndroid Build Coastguard Worker          cpi->sf.intra_sf.disable_smooth_intra) &&
5459*77c1e3ccSAndroid Build Coastguard Worker         (mbmi->mode == SMOOTH_PRED || mbmi->mode == SMOOTH_H_PRED ||
5460*77c1e3ccSAndroid Build Coastguard Worker          mbmi->mode == SMOOTH_V_PRED))
5461*77c1e3ccSAndroid Build Coastguard Worker       continue;
5462*77c1e3ccSAndroid Build Coastguard Worker     if (!intra_mode_cfg->enable_paeth_intra && mbmi->mode == PAETH_PRED)
5463*77c1e3ccSAndroid Build Coastguard Worker       continue;
5464*77c1e3ccSAndroid Build Coastguard Worker     if (av1_is_directional_mode(mbmi->mode) &&
5465*77c1e3ccSAndroid Build Coastguard Worker         !(av1_use_angle_delta(bsize) && intra_mode_cfg->enable_angle_delta) &&
5466*77c1e3ccSAndroid Build Coastguard Worker         mbmi->angle_delta[PLANE_TYPE_Y] != 0)
5467*77c1e3ccSAndroid Build Coastguard Worker       continue;
5468*77c1e3ccSAndroid Build Coastguard Worker     const PREDICTION_MODE this_mode = mbmi->mode;
5469*77c1e3ccSAndroid Build Coastguard Worker 
5470*77c1e3ccSAndroid Build Coastguard Worker     assert(av1_mode_defs[mode_enum].ref_frame[0] == INTRA_FRAME);
5471*77c1e3ccSAndroid Build Coastguard Worker     assert(av1_mode_defs[mode_enum].ref_frame[1] == NONE_FRAME);
5472*77c1e3ccSAndroid Build Coastguard Worker     init_mbmi(mbmi, this_mode, av1_mode_defs[mode_enum].ref_frame, cm);
5473*77c1e3ccSAndroid Build Coastguard Worker     x->txfm_search_info.skip_txfm = 0;
5474*77c1e3ccSAndroid Build Coastguard Worker 
5475*77c1e3ccSAndroid Build Coastguard Worker     if (this_mode != DC_PRED) {
5476*77c1e3ccSAndroid Build Coastguard Worker       // Only search the oblique modes if the best so far is
5477*77c1e3ccSAndroid Build Coastguard Worker       // one of the neighboring directional modes
5478*77c1e3ccSAndroid Build Coastguard Worker       if ((sf->rt_sf.mode_search_skip_flags & FLAG_SKIP_INTRA_BESTINTER) &&
5479*77c1e3ccSAndroid Build Coastguard Worker           (this_mode >= D45_PRED && this_mode <= PAETH_PRED)) {
5480*77c1e3ccSAndroid Build Coastguard Worker         if (search_state->best_mode_index != THR_INVALID &&
5481*77c1e3ccSAndroid Build Coastguard Worker             search_state->best_mbmode.ref_frame[0] > INTRA_FRAME)
5482*77c1e3ccSAndroid Build Coastguard Worker           continue;
5483*77c1e3ccSAndroid Build Coastguard Worker       }
5484*77c1e3ccSAndroid Build Coastguard Worker       if (sf->rt_sf.mode_search_skip_flags & FLAG_SKIP_INTRA_DIRMISMATCH) {
5485*77c1e3ccSAndroid Build Coastguard Worker         if (conditional_skipintra(
5486*77c1e3ccSAndroid Build Coastguard Worker                 this_mode, search_state->intra_search_state.best_intra_mode))
5487*77c1e3ccSAndroid Build Coastguard Worker           continue;
5488*77c1e3ccSAndroid Build Coastguard Worker       }
5489*77c1e3ccSAndroid Build Coastguard Worker     }
5490*77c1e3ccSAndroid Build Coastguard Worker 
5491*77c1e3ccSAndroid Build Coastguard Worker     RD_STATS intra_rd_stats_y;
5492*77c1e3ccSAndroid Build Coastguard Worker     int mode_cost_y;
5493*77c1e3ccSAndroid Build Coastguard Worker     int64_t intra_rd_y = INT64_MAX;
5494*77c1e3ccSAndroid Build Coastguard Worker     const int is_luma_result_valid = av1_handle_intra_y_mode(
5495*77c1e3ccSAndroid Build Coastguard Worker         intra_search_state, cpi, x, bsize, intra_ref_frame_cost, ctx,
5496*77c1e3ccSAndroid Build Coastguard Worker         &intra_rd_stats_y, search_state->best_rd, &mode_cost_y, &intra_rd_y,
5497*77c1e3ccSAndroid Build Coastguard Worker         &best_model_rd, top_intra_model_rd);
5498*77c1e3ccSAndroid Build Coastguard Worker     if (is_luma_result_valid && intra_rd_y < yrd_threshold) {
5499*77c1e3ccSAndroid Build Coastguard Worker       is_best_y_mode_intra = 1;
5500*77c1e3ccSAndroid Build Coastguard Worker       if (intra_rd_y < best_rd_y) {
5501*77c1e3ccSAndroid Build Coastguard Worker         best_intra_rd_stats_y = intra_rd_stats_y;
5502*77c1e3ccSAndroid Build Coastguard Worker         best_mode_cost_y = mode_cost_y;
5503*77c1e3ccSAndroid Build Coastguard Worker         best_rd_y = intra_rd_y;
5504*77c1e3ccSAndroid Build Coastguard Worker         best_mbmi = *mbmi;
5505*77c1e3ccSAndroid Build Coastguard Worker         best_mode_enum = mode_enum;
5506*77c1e3ccSAndroid Build Coastguard Worker         memcpy(best_blk_skip, x->txfm_search_info.blk_skip,
5507*77c1e3ccSAndroid Build Coastguard Worker                sizeof(best_blk_skip[0]) * num_4x4);
5508*77c1e3ccSAndroid Build Coastguard Worker         av1_copy_array(best_tx_type_map, xd->tx_type_map, num_4x4);
5509*77c1e3ccSAndroid Build Coastguard Worker       }
5510*77c1e3ccSAndroid Build Coastguard Worker     }
5511*77c1e3ccSAndroid Build Coastguard Worker   }
5512*77c1e3ccSAndroid Build Coastguard Worker 
5513*77c1e3ccSAndroid Build Coastguard Worker   if (!is_best_y_mode_intra) {
5514*77c1e3ccSAndroid Build Coastguard Worker     return;
5515*77c1e3ccSAndroid Build Coastguard Worker   }
5516*77c1e3ccSAndroid Build Coastguard Worker 
5517*77c1e3ccSAndroid Build Coastguard Worker   assert(best_rd_y < INT64_MAX);
5518*77c1e3ccSAndroid Build Coastguard Worker 
5519*77c1e3ccSAndroid Build Coastguard Worker   // Restores the best luma mode
5520*77c1e3ccSAndroid Build Coastguard Worker   *mbmi = best_mbmi;
5521*77c1e3ccSAndroid Build Coastguard Worker   memcpy(x->txfm_search_info.blk_skip, best_blk_skip,
5522*77c1e3ccSAndroid Build Coastguard Worker          sizeof(best_blk_skip[0]) * num_4x4);
5523*77c1e3ccSAndroid Build Coastguard Worker   av1_copy_array(xd->tx_type_map, best_tx_type_map, num_4x4);
5524*77c1e3ccSAndroid Build Coastguard Worker 
5525*77c1e3ccSAndroid Build Coastguard Worker   // Performs chroma search
5526*77c1e3ccSAndroid Build Coastguard Worker   RD_STATS intra_rd_stats, intra_rd_stats_uv;
5527*77c1e3ccSAndroid Build Coastguard Worker   av1_init_rd_stats(&intra_rd_stats);
5528*77c1e3ccSAndroid Build Coastguard Worker   av1_init_rd_stats(&intra_rd_stats_uv);
5529*77c1e3ccSAndroid Build Coastguard Worker   const int num_planes = av1_num_planes(cm);
5530*77c1e3ccSAndroid Build Coastguard Worker   if (num_planes > 1) {
5531*77c1e3ccSAndroid Build Coastguard Worker     const int intra_uv_mode_valid = av1_search_intra_uv_modes_in_interframe(
5532*77c1e3ccSAndroid Build Coastguard Worker         intra_search_state, cpi, x, bsize, &intra_rd_stats,
5533*77c1e3ccSAndroid Build Coastguard Worker         &best_intra_rd_stats_y, &intra_rd_stats_uv, search_state->best_rd);
5534*77c1e3ccSAndroid Build Coastguard Worker 
5535*77c1e3ccSAndroid Build Coastguard Worker     if (!intra_uv_mode_valid) {
5536*77c1e3ccSAndroid Build Coastguard Worker       return;
5537*77c1e3ccSAndroid Build Coastguard Worker     }
5538*77c1e3ccSAndroid Build Coastguard Worker   }
5539*77c1e3ccSAndroid Build Coastguard Worker 
5540*77c1e3ccSAndroid Build Coastguard Worker   // Merge the luma and chroma rd stats
5541*77c1e3ccSAndroid Build Coastguard Worker   assert(best_mode_cost_y >= 0);
5542*77c1e3ccSAndroid Build Coastguard Worker   intra_rd_stats.rate = best_intra_rd_stats_y.rate + best_mode_cost_y;
5543*77c1e3ccSAndroid Build Coastguard Worker   if (!xd->lossless[mbmi->segment_id] && block_signals_txsize(bsize)) {
5544*77c1e3ccSAndroid Build Coastguard Worker     // av1_pick_uniform_tx_size_type_yrd above includes the cost of the tx_size
5545*77c1e3ccSAndroid Build Coastguard Worker     // in the tokenonly rate, but for intra blocks, tx_size is always coded
5546*77c1e3ccSAndroid Build Coastguard Worker     // (prediction granularity), so we account for it in the full rate,
5547*77c1e3ccSAndroid Build Coastguard Worker     // not the tokenonly rate.
5548*77c1e3ccSAndroid Build Coastguard Worker     best_intra_rd_stats_y.rate -= tx_size_cost(x, bsize, mbmi->tx_size);
5549*77c1e3ccSAndroid Build Coastguard Worker   }
5550*77c1e3ccSAndroid Build Coastguard Worker 
5551*77c1e3ccSAndroid Build Coastguard Worker   const ModeCosts *mode_costs = &x->mode_costs;
5552*77c1e3ccSAndroid Build Coastguard Worker   const PREDICTION_MODE mode = mbmi->mode;
5553*77c1e3ccSAndroid Build Coastguard Worker   if (num_planes > 1 && xd->is_chroma_ref) {
5554*77c1e3ccSAndroid Build Coastguard Worker     const int uv_mode_cost =
5555*77c1e3ccSAndroid Build Coastguard Worker         mode_costs->intra_uv_mode_cost[is_cfl_allowed(xd)][mode][mbmi->uv_mode];
5556*77c1e3ccSAndroid Build Coastguard Worker     intra_rd_stats.rate +=
5557*77c1e3ccSAndroid Build Coastguard Worker         intra_rd_stats_uv.rate +
5558*77c1e3ccSAndroid Build Coastguard Worker         intra_mode_info_cost_uv(cpi, x, mbmi, bsize, uv_mode_cost);
5559*77c1e3ccSAndroid Build Coastguard Worker   }
5560*77c1e3ccSAndroid Build Coastguard Worker 
5561*77c1e3ccSAndroid Build Coastguard Worker   // Intra block is always coded as non-skip
5562*77c1e3ccSAndroid Build Coastguard Worker   intra_rd_stats.skip_txfm = 0;
5563*77c1e3ccSAndroid Build Coastguard Worker   intra_rd_stats.dist = best_intra_rd_stats_y.dist + intra_rd_stats_uv.dist;
5564*77c1e3ccSAndroid Build Coastguard Worker   // Add in the cost of the no skip flag.
5565*77c1e3ccSAndroid Build Coastguard Worker   const int skip_ctx = av1_get_skip_txfm_context(xd);
5566*77c1e3ccSAndroid Build Coastguard Worker   intra_rd_stats.rate += mode_costs->skip_txfm_cost[skip_ctx][0];
5567*77c1e3ccSAndroid Build Coastguard Worker   // Calculate the final RD estimate for this mode.
5568*77c1e3ccSAndroid Build Coastguard Worker   const int64_t this_rd =
5569*77c1e3ccSAndroid Build Coastguard Worker       RDCOST(x->rdmult, intra_rd_stats.rate, intra_rd_stats.dist);
5570*77c1e3ccSAndroid Build Coastguard Worker   // Keep record of best intra rd
5571*77c1e3ccSAndroid Build Coastguard Worker   if (this_rd < search_state->best_intra_rd) {
5572*77c1e3ccSAndroid Build Coastguard Worker     search_state->best_intra_rd = this_rd;
5573*77c1e3ccSAndroid Build Coastguard Worker     intra_search_state->best_intra_mode = mode;
5574*77c1e3ccSAndroid Build Coastguard Worker   }
5575*77c1e3ccSAndroid Build Coastguard Worker 
5576*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < REFERENCE_MODES; ++i) {
5577*77c1e3ccSAndroid Build Coastguard Worker     search_state->best_pred_rd[i] =
5578*77c1e3ccSAndroid Build Coastguard Worker         AOMMIN(search_state->best_pred_rd[i], this_rd);
5579*77c1e3ccSAndroid Build Coastguard Worker   }
5580*77c1e3ccSAndroid Build Coastguard Worker 
5581*77c1e3ccSAndroid Build Coastguard Worker   intra_rd_stats.rdcost = this_rd;
5582*77c1e3ccSAndroid Build Coastguard Worker 
5583*77c1e3ccSAndroid Build Coastguard Worker   // Collect mode stats for multiwinner mode processing
5584*77c1e3ccSAndroid Build Coastguard Worker   const int txfm_search_done = 1;
5585*77c1e3ccSAndroid Build Coastguard Worker   store_winner_mode_stats(
5586*77c1e3ccSAndroid Build Coastguard Worker       &cpi->common, x, mbmi, &intra_rd_stats, &best_intra_rd_stats_y,
5587*77c1e3ccSAndroid Build Coastguard Worker       &intra_rd_stats_uv, best_mode_enum, NULL, bsize, intra_rd_stats.rdcost,
5588*77c1e3ccSAndroid Build Coastguard Worker       cpi->sf.winner_mode_sf.multi_winner_mode_type, txfm_search_done);
5589*77c1e3ccSAndroid Build Coastguard Worker   if (intra_rd_stats.rdcost < search_state->best_rd) {
5590*77c1e3ccSAndroid Build Coastguard Worker     update_search_state(search_state, rd_cost, ctx, &intra_rd_stats,
5591*77c1e3ccSAndroid Build Coastguard Worker                         &best_intra_rd_stats_y, &intra_rd_stats_uv,
5592*77c1e3ccSAndroid Build Coastguard Worker                         best_mode_enum, x, txfm_search_done);
5593*77c1e3ccSAndroid Build Coastguard Worker   }
5594*77c1e3ccSAndroid Build Coastguard Worker }
5595*77c1e3ccSAndroid Build Coastguard Worker 
5596*77c1e3ccSAndroid Build Coastguard Worker #if !CONFIG_REALTIME_ONLY
5597*77c1e3ccSAndroid Build Coastguard Worker // Prepare inter_cost and intra_cost from TPL stats, which are used as ML
5598*77c1e3ccSAndroid Build Coastguard Worker // features in intra mode pruning.
calculate_cost_from_tpl_data(const AV1_COMP * cpi,MACROBLOCK * x,BLOCK_SIZE bsize,int mi_row,int mi_col,int64_t * inter_cost,int64_t * intra_cost)5599*77c1e3ccSAndroid Build Coastguard Worker static inline void calculate_cost_from_tpl_data(const AV1_COMP *cpi,
5600*77c1e3ccSAndroid Build Coastguard Worker                                                 MACROBLOCK *x, BLOCK_SIZE bsize,
5601*77c1e3ccSAndroid Build Coastguard Worker                                                 int mi_row, int mi_col,
5602*77c1e3ccSAndroid Build Coastguard Worker                                                 int64_t *inter_cost,
5603*77c1e3ccSAndroid Build Coastguard Worker                                                 int64_t *intra_cost) {
5604*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
5605*77c1e3ccSAndroid Build Coastguard Worker   // Only consider full SB.
5606*77c1e3ccSAndroid Build Coastguard Worker   const BLOCK_SIZE sb_size = cm->seq_params->sb_size;
5607*77c1e3ccSAndroid Build Coastguard Worker   const int tpl_bsize_1d = cpi->ppi->tpl_data.tpl_bsize_1d;
5608*77c1e3ccSAndroid Build Coastguard Worker   const int len = (block_size_wide[sb_size] / tpl_bsize_1d) *
5609*77c1e3ccSAndroid Build Coastguard Worker                   (block_size_high[sb_size] / tpl_bsize_1d);
5610*77c1e3ccSAndroid Build Coastguard Worker   SuperBlockEnc *sb_enc = &x->sb_enc;
5611*77c1e3ccSAndroid Build Coastguard Worker   if (sb_enc->tpl_data_count == len) {
5612*77c1e3ccSAndroid Build Coastguard Worker     const BLOCK_SIZE tpl_bsize = convert_length_to_bsize(tpl_bsize_1d);
5613*77c1e3ccSAndroid Build Coastguard Worker     const int tpl_stride = sb_enc->tpl_stride;
5614*77c1e3ccSAndroid Build Coastguard Worker     const int tplw = mi_size_wide[tpl_bsize];
5615*77c1e3ccSAndroid Build Coastguard Worker     const int tplh = mi_size_high[tpl_bsize];
5616*77c1e3ccSAndroid Build Coastguard Worker     const int nw = mi_size_wide[bsize] / tplw;
5617*77c1e3ccSAndroid Build Coastguard Worker     const int nh = mi_size_high[bsize] / tplh;
5618*77c1e3ccSAndroid Build Coastguard Worker     if (nw >= 1 && nh >= 1) {
5619*77c1e3ccSAndroid Build Coastguard Worker       const int of_h = mi_row % mi_size_high[sb_size];
5620*77c1e3ccSAndroid Build Coastguard Worker       const int of_w = mi_col % mi_size_wide[sb_size];
5621*77c1e3ccSAndroid Build Coastguard Worker       const int start = of_h / tplh * tpl_stride + of_w / tplw;
5622*77c1e3ccSAndroid Build Coastguard Worker 
5623*77c1e3ccSAndroid Build Coastguard Worker       for (int k = 0; k < nh; k++) {
5624*77c1e3ccSAndroid Build Coastguard Worker         for (int l = 0; l < nw; l++) {
5625*77c1e3ccSAndroid Build Coastguard Worker           *inter_cost += sb_enc->tpl_inter_cost[start + k * tpl_stride + l];
5626*77c1e3ccSAndroid Build Coastguard Worker           *intra_cost += sb_enc->tpl_intra_cost[start + k * tpl_stride + l];
5627*77c1e3ccSAndroid Build Coastguard Worker         }
5628*77c1e3ccSAndroid Build Coastguard Worker       }
5629*77c1e3ccSAndroid Build Coastguard Worker       *inter_cost /= nw * nh;
5630*77c1e3ccSAndroid Build Coastguard Worker       *intra_cost /= nw * nh;
5631*77c1e3ccSAndroid Build Coastguard Worker     }
5632*77c1e3ccSAndroid Build Coastguard Worker   }
5633*77c1e3ccSAndroid Build Coastguard Worker }
5634*77c1e3ccSAndroid Build Coastguard Worker #endif  // !CONFIG_REALTIME_ONLY
5635*77c1e3ccSAndroid Build Coastguard Worker 
5636*77c1e3ccSAndroid Build Coastguard Worker // When the speed feature skip_intra_in_interframe > 0, enable ML model to prune
5637*77c1e3ccSAndroid Build Coastguard Worker // intra mode search.
skip_intra_modes_in_interframe(AV1_COMMON * const cm,struct macroblock * x,BLOCK_SIZE bsize,InterModeSearchState * search_state,const SPEED_FEATURES * const sf,int64_t inter_cost,int64_t intra_cost)5638*77c1e3ccSAndroid Build Coastguard Worker static inline void skip_intra_modes_in_interframe(
5639*77c1e3ccSAndroid Build Coastguard Worker     AV1_COMMON *const cm, struct macroblock *x, BLOCK_SIZE bsize,
5640*77c1e3ccSAndroid Build Coastguard Worker     InterModeSearchState *search_state, const SPEED_FEATURES *const sf,
5641*77c1e3ccSAndroid Build Coastguard Worker     int64_t inter_cost, int64_t intra_cost) {
5642*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *const xd = &x->e_mbd;
5643*77c1e3ccSAndroid Build Coastguard Worker   const int comp_pred = search_state->best_mbmode.ref_frame[1] > INTRA_FRAME;
5644*77c1e3ccSAndroid Build Coastguard Worker   if (sf->rt_sf.prune_intra_mode_based_on_mv_range &&
5645*77c1e3ccSAndroid Build Coastguard Worker       bsize > sf->part_sf.max_intra_bsize && !comp_pred) {
5646*77c1e3ccSAndroid Build Coastguard Worker     const MV best_mv = search_state->best_mbmode.mv[0].as_mv;
5647*77c1e3ccSAndroid Build Coastguard Worker     const int mv_thresh = 16 << sf->rt_sf.prune_intra_mode_based_on_mv_range;
5648*77c1e3ccSAndroid Build Coastguard Worker     if (abs(best_mv.row) < mv_thresh && abs(best_mv.col) < mv_thresh &&
5649*77c1e3ccSAndroid Build Coastguard Worker         x->source_variance > 128) {
5650*77c1e3ccSAndroid Build Coastguard Worker       search_state->intra_search_state.skip_intra_modes = 1;
5651*77c1e3ccSAndroid Build Coastguard Worker       return;
5652*77c1e3ccSAndroid Build Coastguard Worker     }
5653*77c1e3ccSAndroid Build Coastguard Worker   }
5654*77c1e3ccSAndroid Build Coastguard Worker 
5655*77c1e3ccSAndroid Build Coastguard Worker   const unsigned int src_var_thresh_intra_skip = 1;
5656*77c1e3ccSAndroid Build Coastguard Worker   const int skip_intra_in_interframe = sf->intra_sf.skip_intra_in_interframe;
5657*77c1e3ccSAndroid Build Coastguard Worker   if (!(skip_intra_in_interframe &&
5658*77c1e3ccSAndroid Build Coastguard Worker         (x->source_variance > src_var_thresh_intra_skip)))
5659*77c1e3ccSAndroid Build Coastguard Worker     return;
5660*77c1e3ccSAndroid Build Coastguard Worker 
5661*77c1e3ccSAndroid Build Coastguard Worker   // Prune intra search based on best inter mode being transfrom skip.
5662*77c1e3ccSAndroid Build Coastguard Worker   if ((skip_intra_in_interframe >= 2) && search_state->best_mbmode.skip_txfm) {
5663*77c1e3ccSAndroid Build Coastguard Worker     const int qindex_thresh[2] = { 200, MAXQ };
5664*77c1e3ccSAndroid Build Coastguard Worker     const int ind = (skip_intra_in_interframe >= 3) ? 1 : 0;
5665*77c1e3ccSAndroid Build Coastguard Worker     if (!have_newmv_in_inter_mode(search_state->best_mbmode.mode) &&
5666*77c1e3ccSAndroid Build Coastguard Worker         (x->qindex <= qindex_thresh[ind])) {
5667*77c1e3ccSAndroid Build Coastguard Worker       search_state->intra_search_state.skip_intra_modes = 1;
5668*77c1e3ccSAndroid Build Coastguard Worker       return;
5669*77c1e3ccSAndroid Build Coastguard Worker     } else if ((skip_intra_in_interframe >= 4) &&
5670*77c1e3ccSAndroid Build Coastguard Worker                (inter_cost < 0 || intra_cost < 0)) {
5671*77c1e3ccSAndroid Build Coastguard Worker       search_state->intra_search_state.skip_intra_modes = 1;
5672*77c1e3ccSAndroid Build Coastguard Worker       return;
5673*77c1e3ccSAndroid Build Coastguard Worker     }
5674*77c1e3ccSAndroid Build Coastguard Worker   }
5675*77c1e3ccSAndroid Build Coastguard Worker   // Use ML model to prune intra search.
5676*77c1e3ccSAndroid Build Coastguard Worker   if (inter_cost >= 0 && intra_cost >= 0) {
5677*77c1e3ccSAndroid Build Coastguard Worker     const NN_CONFIG *nn_config = (AOMMIN(cm->width, cm->height) <= 480)
5678*77c1e3ccSAndroid Build Coastguard Worker                                      ? &av1_intrap_nn_config
5679*77c1e3ccSAndroid Build Coastguard Worker                                      : &av1_intrap_hd_nn_config;
5680*77c1e3ccSAndroid Build Coastguard Worker     float nn_features[6];
5681*77c1e3ccSAndroid Build Coastguard Worker     float scores[2] = { 0.0f };
5682*77c1e3ccSAndroid Build Coastguard Worker 
5683*77c1e3ccSAndroid Build Coastguard Worker     nn_features[0] = (float)search_state->best_mbmode.skip_txfm;
5684*77c1e3ccSAndroid Build Coastguard Worker     nn_features[1] = (float)mi_size_wide_log2[bsize];
5685*77c1e3ccSAndroid Build Coastguard Worker     nn_features[2] = (float)mi_size_high_log2[bsize];
5686*77c1e3ccSAndroid Build Coastguard Worker     nn_features[3] = (float)intra_cost;
5687*77c1e3ccSAndroid Build Coastguard Worker     nn_features[4] = (float)inter_cost;
5688*77c1e3ccSAndroid Build Coastguard Worker     const int ac_q = av1_ac_quant_QTX(x->qindex, 0, xd->bd);
5689*77c1e3ccSAndroid Build Coastguard Worker     const int ac_q_max = av1_ac_quant_QTX(255, 0, xd->bd);
5690*77c1e3ccSAndroid Build Coastguard Worker     nn_features[5] = (float)(ac_q_max / ac_q);
5691*77c1e3ccSAndroid Build Coastguard Worker 
5692*77c1e3ccSAndroid Build Coastguard Worker     av1_nn_predict(nn_features, nn_config, 1, scores);
5693*77c1e3ccSAndroid Build Coastguard Worker 
5694*77c1e3ccSAndroid Build Coastguard Worker     // For two parameters, the max prob returned from av1_nn_softmax equals
5695*77c1e3ccSAndroid Build Coastguard Worker     // 1.0 / (1.0 + e^(-|diff_score|)). Here use scores directly to avoid the
5696*77c1e3ccSAndroid Build Coastguard Worker     // calling of av1_nn_softmax.
5697*77c1e3ccSAndroid Build Coastguard Worker     const float thresh[5] = { 1.4f, 1.4f, 1.4f, 1.4f, 1.4f };
5698*77c1e3ccSAndroid Build Coastguard Worker     assert(skip_intra_in_interframe <= 5);
5699*77c1e3ccSAndroid Build Coastguard Worker     if (scores[1] > scores[0] + thresh[skip_intra_in_interframe - 1]) {
5700*77c1e3ccSAndroid Build Coastguard Worker       search_state->intra_search_state.skip_intra_modes = 1;
5701*77c1e3ccSAndroid Build Coastguard Worker     }
5702*77c1e3ccSAndroid Build Coastguard Worker   }
5703*77c1e3ccSAndroid Build Coastguard Worker }
5704*77c1e3ccSAndroid Build Coastguard Worker 
skip_interp_filter_search(const AV1_COMP * cpi,int is_single_pred)5705*77c1e3ccSAndroid Build Coastguard Worker static inline bool skip_interp_filter_search(const AV1_COMP *cpi,
5706*77c1e3ccSAndroid Build Coastguard Worker                                              int is_single_pred) {
5707*77c1e3ccSAndroid Build Coastguard Worker   const MODE encoding_mode = cpi->oxcf.mode;
5708*77c1e3ccSAndroid Build Coastguard Worker   if (encoding_mode == REALTIME) {
5709*77c1e3ccSAndroid Build Coastguard Worker     return (cpi->common.current_frame.reference_mode == SINGLE_REFERENCE &&
5710*77c1e3ccSAndroid Build Coastguard Worker             (cpi->sf.interp_sf.skip_interp_filter_search ||
5711*77c1e3ccSAndroid Build Coastguard Worker              cpi->sf.winner_mode_sf.winner_mode_ifs));
5712*77c1e3ccSAndroid Build Coastguard Worker   } else if (encoding_mode == GOOD) {
5713*77c1e3ccSAndroid Build Coastguard Worker     // Skip interpolation filter search for single prediction modes.
5714*77c1e3ccSAndroid Build Coastguard Worker     return (cpi->sf.interp_sf.skip_interp_filter_search && is_single_pred);
5715*77c1e3ccSAndroid Build Coastguard Worker   }
5716*77c1e3ccSAndroid Build Coastguard Worker   return false;
5717*77c1e3ccSAndroid Build Coastguard Worker }
5718*77c1e3ccSAndroid Build Coastguard Worker 
get_block_temp_var(const AV1_COMP * cpi,const MACROBLOCK * x,BLOCK_SIZE bsize)5719*77c1e3ccSAndroid Build Coastguard Worker static inline int get_block_temp_var(const AV1_COMP *cpi, const MACROBLOCK *x,
5720*77c1e3ccSAndroid Build Coastguard Worker                                      BLOCK_SIZE bsize) {
5721*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
5722*77c1e3ccSAndroid Build Coastguard Worker   const SPEED_FEATURES *const sf = &cpi->sf;
5723*77c1e3ccSAndroid Build Coastguard Worker 
5724*77c1e3ccSAndroid Build Coastguard Worker   if (sf->part_sf.partition_search_type != VAR_BASED_PARTITION ||
5725*77c1e3ccSAndroid Build Coastguard Worker       !sf->rt_sf.short_circuit_low_temp_var ||
5726*77c1e3ccSAndroid Build Coastguard Worker       !sf->rt_sf.prune_inter_modes_using_temp_var) {
5727*77c1e3ccSAndroid Build Coastguard Worker     return 0;
5728*77c1e3ccSAndroid Build Coastguard Worker   }
5729*77c1e3ccSAndroid Build Coastguard Worker 
5730*77c1e3ccSAndroid Build Coastguard Worker   const int mi_row = x->e_mbd.mi_row;
5731*77c1e3ccSAndroid Build Coastguard Worker   const int mi_col = x->e_mbd.mi_col;
5732*77c1e3ccSAndroid Build Coastguard Worker   int is_low_temp_var = 0;
5733*77c1e3ccSAndroid Build Coastguard Worker 
5734*77c1e3ccSAndroid Build Coastguard Worker   if (cm->seq_params->sb_size == BLOCK_64X64)
5735*77c1e3ccSAndroid Build Coastguard Worker     is_low_temp_var = av1_get_force_skip_low_temp_var_small_sb(
5736*77c1e3ccSAndroid Build Coastguard Worker         &x->part_search_info.variance_low[0], mi_row, mi_col, bsize);
5737*77c1e3ccSAndroid Build Coastguard Worker   else
5738*77c1e3ccSAndroid Build Coastguard Worker     is_low_temp_var = av1_get_force_skip_low_temp_var(
5739*77c1e3ccSAndroid Build Coastguard Worker         &x->part_search_info.variance_low[0], mi_row, mi_col, bsize);
5740*77c1e3ccSAndroid Build Coastguard Worker 
5741*77c1e3ccSAndroid Build Coastguard Worker   return is_low_temp_var;
5742*77c1e3ccSAndroid Build Coastguard Worker }
5743*77c1e3ccSAndroid Build Coastguard Worker 
5744*77c1e3ccSAndroid Build Coastguard Worker // TODO([email protected]): See the todo for av1_rd_pick_intra_mode_sb.
av1_rd_pick_inter_mode(struct AV1_COMP * cpi,struct TileDataEnc * tile_data,struct macroblock * x,struct RD_STATS * rd_cost,BLOCK_SIZE bsize,PICK_MODE_CONTEXT * ctx,int64_t best_rd_so_far)5745*77c1e3ccSAndroid Build Coastguard Worker void av1_rd_pick_inter_mode(struct AV1_COMP *cpi, struct TileDataEnc *tile_data,
5746*77c1e3ccSAndroid Build Coastguard Worker                             struct macroblock *x, struct RD_STATS *rd_cost,
5747*77c1e3ccSAndroid Build Coastguard Worker                             BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx,
5748*77c1e3ccSAndroid Build Coastguard Worker                             int64_t best_rd_so_far) {
5749*77c1e3ccSAndroid Build Coastguard Worker   AV1_COMMON *const cm = &cpi->common;
5750*77c1e3ccSAndroid Build Coastguard Worker   const FeatureFlags *const features = &cm->features;
5751*77c1e3ccSAndroid Build Coastguard Worker   const int num_planes = av1_num_planes(cm);
5752*77c1e3ccSAndroid Build Coastguard Worker   const SPEED_FEATURES *const sf = &cpi->sf;
5753*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *const xd = &x->e_mbd;
5754*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *const mbmi = xd->mi[0];
5755*77c1e3ccSAndroid Build Coastguard Worker   TxfmSearchInfo *txfm_info = &x->txfm_search_info;
5756*77c1e3ccSAndroid Build Coastguard Worker   int i;
5757*77c1e3ccSAndroid Build Coastguard Worker   const ModeCosts *mode_costs = &x->mode_costs;
5758*77c1e3ccSAndroid Build Coastguard Worker   const int *comp_inter_cost =
5759*77c1e3ccSAndroid Build Coastguard Worker       mode_costs->comp_inter_cost[av1_get_reference_mode_context(xd)];
5760*77c1e3ccSAndroid Build Coastguard Worker 
5761*77c1e3ccSAndroid Build Coastguard Worker   InterModeSearchState search_state;
5762*77c1e3ccSAndroid Build Coastguard Worker   init_inter_mode_search_state(&search_state, cpi, x, bsize, best_rd_so_far);
5763*77c1e3ccSAndroid Build Coastguard Worker   INTERINTRA_MODE interintra_modes[REF_FRAMES] = {
5764*77c1e3ccSAndroid Build Coastguard Worker     INTERINTRA_MODES, INTERINTRA_MODES, INTERINTRA_MODES, INTERINTRA_MODES,
5765*77c1e3ccSAndroid Build Coastguard Worker     INTERINTRA_MODES, INTERINTRA_MODES, INTERINTRA_MODES, INTERINTRA_MODES
5766*77c1e3ccSAndroid Build Coastguard Worker   };
5767*77c1e3ccSAndroid Build Coastguard Worker   HandleInterModeArgs args = { { NULL },
5768*77c1e3ccSAndroid Build Coastguard Worker                                { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE },
5769*77c1e3ccSAndroid Build Coastguard Worker                                { NULL },
5770*77c1e3ccSAndroid Build Coastguard Worker                                { MAX_SB_SIZE >> 1, MAX_SB_SIZE >> 1,
5771*77c1e3ccSAndroid Build Coastguard Worker                                  MAX_SB_SIZE >> 1 },
5772*77c1e3ccSAndroid Build Coastguard Worker                                NULL,
5773*77c1e3ccSAndroid Build Coastguard Worker                                NULL,
5774*77c1e3ccSAndroid Build Coastguard Worker                                NULL,
5775*77c1e3ccSAndroid Build Coastguard Worker                                search_state.modelled_rd,
5776*77c1e3ccSAndroid Build Coastguard Worker                                INT_MAX,
5777*77c1e3ccSAndroid Build Coastguard Worker                                INT_MAX,
5778*77c1e3ccSAndroid Build Coastguard Worker                                search_state.simple_rd,
5779*77c1e3ccSAndroid Build Coastguard Worker                                0,
5780*77c1e3ccSAndroid Build Coastguard Worker                                false,
5781*77c1e3ccSAndroid Build Coastguard Worker                                interintra_modes,
5782*77c1e3ccSAndroid Build Coastguard Worker                                { { { 0 }, { { 0 } }, { 0 }, 0, 0, 0, 0 } },
5783*77c1e3ccSAndroid Build Coastguard Worker                                { { 0, 0 } },
5784*77c1e3ccSAndroid Build Coastguard Worker                                { 0 },
5785*77c1e3ccSAndroid Build Coastguard Worker                                0,
5786*77c1e3ccSAndroid Build Coastguard Worker                                0,
5787*77c1e3ccSAndroid Build Coastguard Worker                                -1,
5788*77c1e3ccSAndroid Build Coastguard Worker                                -1,
5789*77c1e3ccSAndroid Build Coastguard Worker                                -1,
5790*77c1e3ccSAndroid Build Coastguard Worker                                { 0 },
5791*77c1e3ccSAndroid Build Coastguard Worker                                { 0 },
5792*77c1e3ccSAndroid Build Coastguard Worker                                UINT_MAX };
5793*77c1e3ccSAndroid Build Coastguard Worker   // Currently, is_low_temp_var is used in real time encoding.
5794*77c1e3ccSAndroid Build Coastguard Worker   const int is_low_temp_var = get_block_temp_var(cpi, x, bsize);
5795*77c1e3ccSAndroid Build Coastguard Worker 
5796*77c1e3ccSAndroid Build Coastguard Worker   for (i = 0; i < MODE_CTX_REF_FRAMES; ++i) args.cmp_mode[i] = -1;
5797*77c1e3ccSAndroid Build Coastguard Worker   // Indicates the appropriate number of simple translation winner modes for
5798*77c1e3ccSAndroid Build Coastguard Worker   // exhaustive motion mode evaluation
5799*77c1e3ccSAndroid Build Coastguard Worker   const int max_winner_motion_mode_cand =
5800*77c1e3ccSAndroid Build Coastguard Worker       num_winner_motion_modes[sf->winner_mode_sf.motion_mode_for_winner_cand];
5801*77c1e3ccSAndroid Build Coastguard Worker   assert(max_winner_motion_mode_cand <= MAX_WINNER_MOTION_MODES);
5802*77c1e3ccSAndroid Build Coastguard Worker   motion_mode_candidate motion_mode_cand;
5803*77c1e3ccSAndroid Build Coastguard Worker   motion_mode_best_st_candidate best_motion_mode_cands;
5804*77c1e3ccSAndroid Build Coastguard Worker   // Initializing the number of motion mode candidates to zero.
5805*77c1e3ccSAndroid Build Coastguard Worker   best_motion_mode_cands.num_motion_mode_cand = 0;
5806*77c1e3ccSAndroid Build Coastguard Worker   for (i = 0; i < MAX_WINNER_MOTION_MODES; ++i)
5807*77c1e3ccSAndroid Build Coastguard Worker     best_motion_mode_cands.motion_mode_cand[i].rd_cost = INT64_MAX;
5808*77c1e3ccSAndroid Build Coastguard Worker 
5809*77c1e3ccSAndroid Build Coastguard Worker   for (i = 0; i < REF_FRAMES; ++i) x->pred_sse[i] = INT_MAX;
5810*77c1e3ccSAndroid Build Coastguard Worker 
5811*77c1e3ccSAndroid Build Coastguard Worker   av1_invalid_rd_stats(rd_cost);
5812*77c1e3ccSAndroid Build Coastguard Worker 
5813*77c1e3ccSAndroid Build Coastguard Worker   for (i = 0; i < REF_FRAMES; ++i) {
5814*77c1e3ccSAndroid Build Coastguard Worker     x->warp_sample_info[i].num = -1;
5815*77c1e3ccSAndroid Build Coastguard Worker   }
5816*77c1e3ccSAndroid Build Coastguard Worker 
5817*77c1e3ccSAndroid Build Coastguard Worker   // Ref frames that are selected by square partition blocks.
5818*77c1e3ccSAndroid Build Coastguard Worker   int picked_ref_frames_mask = 0;
5819*77c1e3ccSAndroid Build Coastguard Worker   if (sf->inter_sf.prune_ref_frame_for_rect_partitions &&
5820*77c1e3ccSAndroid Build Coastguard Worker       mbmi->partition != PARTITION_NONE) {
5821*77c1e3ccSAndroid Build Coastguard Worker     // prune_ref_frame_for_rect_partitions = 1 implies prune only extended
5822*77c1e3ccSAndroid Build Coastguard Worker     // partition blocks. prune_ref_frame_for_rect_partitions >=2
5823*77c1e3ccSAndroid Build Coastguard Worker     // implies prune for vert, horiz and extended partition blocks.
5824*77c1e3ccSAndroid Build Coastguard Worker     if ((mbmi->partition != PARTITION_VERT &&
5825*77c1e3ccSAndroid Build Coastguard Worker          mbmi->partition != PARTITION_HORZ) ||
5826*77c1e3ccSAndroid Build Coastguard Worker         sf->inter_sf.prune_ref_frame_for_rect_partitions >= 2) {
5827*77c1e3ccSAndroid Build Coastguard Worker       picked_ref_frames_mask =
5828*77c1e3ccSAndroid Build Coastguard Worker           fetch_picked_ref_frames_mask(x, bsize, cm->seq_params->mib_size);
5829*77c1e3ccSAndroid Build Coastguard Worker     }
5830*77c1e3ccSAndroid Build Coastguard Worker   }
5831*77c1e3ccSAndroid Build Coastguard Worker 
5832*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
5833*77c1e3ccSAndroid Build Coastguard Worker   start_timing(cpi, set_params_rd_pick_inter_mode_time);
5834*77c1e3ccSAndroid Build Coastguard Worker #endif
5835*77c1e3ccSAndroid Build Coastguard Worker   // Skip ref frames that never selected by square blocks.
5836*77c1e3ccSAndroid Build Coastguard Worker   const int skip_ref_frame_mask =
5837*77c1e3ccSAndroid Build Coastguard Worker       picked_ref_frames_mask ? ~picked_ref_frames_mask : 0;
5838*77c1e3ccSAndroid Build Coastguard Worker   mode_skip_mask_t mode_skip_mask;
5839*77c1e3ccSAndroid Build Coastguard Worker   unsigned int ref_costs_single[REF_FRAMES];
5840*77c1e3ccSAndroid Build Coastguard Worker   unsigned int ref_costs_comp[REF_FRAMES][REF_FRAMES];
5841*77c1e3ccSAndroid Build Coastguard Worker   struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE];
5842*77c1e3ccSAndroid Build Coastguard Worker   // init params, set frame modes, speed features
5843*77c1e3ccSAndroid Build Coastguard Worker   set_params_rd_pick_inter_mode(cpi, x, &args, bsize, &mode_skip_mask,
5844*77c1e3ccSAndroid Build Coastguard Worker                                 skip_ref_frame_mask, ref_costs_single,
5845*77c1e3ccSAndroid Build Coastguard Worker                                 ref_costs_comp, yv12_mb);
5846*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
5847*77c1e3ccSAndroid Build Coastguard Worker   end_timing(cpi, set_params_rd_pick_inter_mode_time);
5848*77c1e3ccSAndroid Build Coastguard Worker #endif
5849*77c1e3ccSAndroid Build Coastguard Worker 
5850*77c1e3ccSAndroid Build Coastguard Worker   int64_t best_est_rd = INT64_MAX;
5851*77c1e3ccSAndroid Build Coastguard Worker   const InterModeRdModel *md = &tile_data->inter_mode_rd_models[bsize];
5852*77c1e3ccSAndroid Build Coastguard Worker   // If do_tx_search is 0, only estimated RD should be computed.
5853*77c1e3ccSAndroid Build Coastguard Worker   // If do_tx_search is 1, all modes have TX search performed.
5854*77c1e3ccSAndroid Build Coastguard Worker   const int do_tx_search =
5855*77c1e3ccSAndroid Build Coastguard Worker       !((sf->inter_sf.inter_mode_rd_model_estimation == 1 && md->ready) ||
5856*77c1e3ccSAndroid Build Coastguard Worker         (sf->inter_sf.inter_mode_rd_model_estimation == 2 &&
5857*77c1e3ccSAndroid Build Coastguard Worker          num_pels_log2_lookup[bsize] > 8));
5858*77c1e3ccSAndroid Build Coastguard Worker   InterModesInfo *inter_modes_info = x->inter_modes_info;
5859*77c1e3ccSAndroid Build Coastguard Worker   inter_modes_info->num = 0;
5860*77c1e3ccSAndroid Build Coastguard Worker 
5861*77c1e3ccSAndroid Build Coastguard Worker   // Temporary buffers used by handle_inter_mode().
5862*77c1e3ccSAndroid Build Coastguard Worker   uint8_t *const tmp_buf = get_buf_by_bd(xd, x->tmp_pred_bufs[0]);
5863*77c1e3ccSAndroid Build Coastguard Worker 
5864*77c1e3ccSAndroid Build Coastguard Worker   // The best RD found for the reference frame, among single reference modes.
5865*77c1e3ccSAndroid Build Coastguard Worker   // Note that the 0-th element will contain a cut-off that is later used
5866*77c1e3ccSAndroid Build Coastguard Worker   // to determine if we should skip a compound mode.
5867*77c1e3ccSAndroid Build Coastguard Worker   int64_t ref_frame_rd[REF_FRAMES] = { INT64_MAX, INT64_MAX, INT64_MAX,
5868*77c1e3ccSAndroid Build Coastguard Worker                                        INT64_MAX, INT64_MAX, INT64_MAX,
5869*77c1e3ccSAndroid Build Coastguard Worker                                        INT64_MAX, INT64_MAX };
5870*77c1e3ccSAndroid Build Coastguard Worker 
5871*77c1e3ccSAndroid Build Coastguard Worker   // Prepared stats used later to check if we could skip intra mode eval.
5872*77c1e3ccSAndroid Build Coastguard Worker   int64_t inter_cost = -1;
5873*77c1e3ccSAndroid Build Coastguard Worker   int64_t intra_cost = -1;
5874*77c1e3ccSAndroid Build Coastguard Worker   // Need to tweak the threshold for hdres speed 0 & 1.
5875*77c1e3ccSAndroid Build Coastguard Worker   const int mi_row = xd->mi_row;
5876*77c1e3ccSAndroid Build Coastguard Worker   const int mi_col = xd->mi_col;
5877*77c1e3ccSAndroid Build Coastguard Worker 
5878*77c1e3ccSAndroid Build Coastguard Worker   // Obtain the relevant tpl stats for pruning inter modes
5879*77c1e3ccSAndroid Build Coastguard Worker   PruneInfoFromTpl inter_cost_info_from_tpl;
5880*77c1e3ccSAndroid Build Coastguard Worker #if !CONFIG_REALTIME_ONLY
5881*77c1e3ccSAndroid Build Coastguard Worker   if (sf->inter_sf.prune_inter_modes_based_on_tpl) {
5882*77c1e3ccSAndroid Build Coastguard Worker     // x->tpl_keep_ref_frame[id] = 1 => no pruning in
5883*77c1e3ccSAndroid Build Coastguard Worker     // prune_ref_by_selective_ref_frame()
5884*77c1e3ccSAndroid Build Coastguard Worker     // x->tpl_keep_ref_frame[id] = 0  => ref frame can be pruned in
5885*77c1e3ccSAndroid Build Coastguard Worker     // prune_ref_by_selective_ref_frame()
5886*77c1e3ccSAndroid Build Coastguard Worker     // Populating valid_refs[idx] = 1 ensures that
5887*77c1e3ccSAndroid Build Coastguard Worker     // 'inter_cost_info_from_tpl.best_inter_cost' does not correspond to a
5888*77c1e3ccSAndroid Build Coastguard Worker     // pruned ref frame.
5889*77c1e3ccSAndroid Build Coastguard Worker     int valid_refs[INTER_REFS_PER_FRAME];
5890*77c1e3ccSAndroid Build Coastguard Worker     for (MV_REFERENCE_FRAME frame = LAST_FRAME; frame < REF_FRAMES; frame++) {
5891*77c1e3ccSAndroid Build Coastguard Worker       const MV_REFERENCE_FRAME refs[2] = { frame, NONE_FRAME };
5892*77c1e3ccSAndroid Build Coastguard Worker       valid_refs[frame - 1] =
5893*77c1e3ccSAndroid Build Coastguard Worker           x->tpl_keep_ref_frame[frame] ||
5894*77c1e3ccSAndroid Build Coastguard Worker           !prune_ref_by_selective_ref_frame(
5895*77c1e3ccSAndroid Build Coastguard Worker               cpi, x, refs, cm->cur_frame->ref_display_order_hint);
5896*77c1e3ccSAndroid Build Coastguard Worker     }
5897*77c1e3ccSAndroid Build Coastguard Worker     av1_zero(inter_cost_info_from_tpl);
5898*77c1e3ccSAndroid Build Coastguard Worker     get_block_level_tpl_stats(cpi, bsize, mi_row, mi_col, valid_refs,
5899*77c1e3ccSAndroid Build Coastguard Worker                               &inter_cost_info_from_tpl);
5900*77c1e3ccSAndroid Build Coastguard Worker   }
5901*77c1e3ccSAndroid Build Coastguard Worker 
5902*77c1e3ccSAndroid Build Coastguard Worker   const int do_pruning =
5903*77c1e3ccSAndroid Build Coastguard Worker       (AOMMIN(cm->width, cm->height) > 480 && cpi->speed <= 1) ? 0 : 1;
5904*77c1e3ccSAndroid Build Coastguard Worker   if (do_pruning && sf->intra_sf.skip_intra_in_interframe &&
5905*77c1e3ccSAndroid Build Coastguard Worker       cpi->oxcf.algo_cfg.enable_tpl_model)
5906*77c1e3ccSAndroid Build Coastguard Worker     calculate_cost_from_tpl_data(cpi, x, bsize, mi_row, mi_col, &inter_cost,
5907*77c1e3ccSAndroid Build Coastguard Worker                                  &intra_cost);
5908*77c1e3ccSAndroid Build Coastguard Worker #endif  // !CONFIG_REALTIME_ONLY
5909*77c1e3ccSAndroid Build Coastguard Worker 
5910*77c1e3ccSAndroid Build Coastguard Worker   // Initialize best mode stats for winner mode processing.
5911*77c1e3ccSAndroid Build Coastguard Worker   const int max_winner_mode_count =
5912*77c1e3ccSAndroid Build Coastguard Worker       winner_mode_count_allowed[sf->winner_mode_sf.multi_winner_mode_type];
5913*77c1e3ccSAndroid Build Coastguard Worker   zero_winner_mode_stats(bsize, max_winner_mode_count, x->winner_mode_stats);
5914*77c1e3ccSAndroid Build Coastguard Worker   x->winner_mode_count = 0;
5915*77c1e3ccSAndroid Build Coastguard Worker   store_winner_mode_stats(&cpi->common, x, mbmi, NULL, NULL, NULL, THR_INVALID,
5916*77c1e3ccSAndroid Build Coastguard Worker                           NULL, bsize, best_rd_so_far,
5917*77c1e3ccSAndroid Build Coastguard Worker                           sf->winner_mode_sf.multi_winner_mode_type, 0);
5918*77c1e3ccSAndroid Build Coastguard Worker 
5919*77c1e3ccSAndroid Build Coastguard Worker   int mode_thresh_mul_fact = (1 << MODE_THRESH_QBITS);
5920*77c1e3ccSAndroid Build Coastguard Worker   if (sf->inter_sf.prune_inter_modes_if_skippable) {
5921*77c1e3ccSAndroid Build Coastguard Worker     // Higher multiplication factor values for lower quantizers.
5922*77c1e3ccSAndroid Build Coastguard Worker     mode_thresh_mul_fact = mode_threshold_mul_factor[x->qindex];
5923*77c1e3ccSAndroid Build Coastguard Worker   }
5924*77c1e3ccSAndroid Build Coastguard Worker 
5925*77c1e3ccSAndroid Build Coastguard Worker   // Initialize arguments for mode loop speed features
5926*77c1e3ccSAndroid Build Coastguard Worker   InterModeSFArgs sf_args = { &args.skip_motion_mode,
5927*77c1e3ccSAndroid Build Coastguard Worker                               &mode_skip_mask,
5928*77c1e3ccSAndroid Build Coastguard Worker                               &search_state,
5929*77c1e3ccSAndroid Build Coastguard Worker                               skip_ref_frame_mask,
5930*77c1e3ccSAndroid Build Coastguard Worker                               0,
5931*77c1e3ccSAndroid Build Coastguard Worker                               mode_thresh_mul_fact,
5932*77c1e3ccSAndroid Build Coastguard Worker                               0,
5933*77c1e3ccSAndroid Build Coastguard Worker                               0 };
5934*77c1e3ccSAndroid Build Coastguard Worker   int64_t best_inter_yrd = INT64_MAX;
5935*77c1e3ccSAndroid Build Coastguard Worker 
5936*77c1e3ccSAndroid Build Coastguard Worker   // This is the main loop of this function. It loops over all possible inter
5937*77c1e3ccSAndroid Build Coastguard Worker   // modes and calls handle_inter_mode() to compute the RD for each.
5938*77c1e3ccSAndroid Build Coastguard Worker   // Here midx is just an iterator index that should not be used by itself
5939*77c1e3ccSAndroid Build Coastguard Worker   // except to keep track of the number of modes searched. It should be used
5940*77c1e3ccSAndroid Build Coastguard Worker   // with av1_default_mode_order to get the enum that defines the mode, which
5941*77c1e3ccSAndroid Build Coastguard Worker   // can be used with av1_mode_defs to get the prediction mode and the ref
5942*77c1e3ccSAndroid Build Coastguard Worker   // frames.
5943*77c1e3ccSAndroid Build Coastguard Worker   // TODO(yunqing, any): Setting mode_start and mode_end outside for-loop brings
5944*77c1e3ccSAndroid Build Coastguard Worker   // good speedup for real time case. If we decide to use compound mode in real
5945*77c1e3ccSAndroid Build Coastguard Worker   // time, maybe we can modify av1_default_mode_order table.
5946*77c1e3ccSAndroid Build Coastguard Worker   THR_MODES mode_start = THR_INTER_MODE_START;
5947*77c1e3ccSAndroid Build Coastguard Worker   THR_MODES mode_end = THR_INTER_MODE_END;
5948*77c1e3ccSAndroid Build Coastguard Worker   const CurrentFrame *const current_frame = &cm->current_frame;
5949*77c1e3ccSAndroid Build Coastguard Worker   if (current_frame->reference_mode == SINGLE_REFERENCE) {
5950*77c1e3ccSAndroid Build Coastguard Worker     mode_start = SINGLE_REF_MODE_START;
5951*77c1e3ccSAndroid Build Coastguard Worker     mode_end = SINGLE_REF_MODE_END;
5952*77c1e3ccSAndroid Build Coastguard Worker   }
5953*77c1e3ccSAndroid Build Coastguard Worker 
5954*77c1e3ccSAndroid Build Coastguard Worker   for (THR_MODES midx = mode_start; midx < mode_end; ++midx) {
5955*77c1e3ccSAndroid Build Coastguard Worker     // Get the actual prediction mode we are trying in this iteration
5956*77c1e3ccSAndroid Build Coastguard Worker     const THR_MODES mode_enum = av1_default_mode_order[midx];
5957*77c1e3ccSAndroid Build Coastguard Worker     const MODE_DEFINITION *mode_def = &av1_mode_defs[mode_enum];
5958*77c1e3ccSAndroid Build Coastguard Worker     const PREDICTION_MODE this_mode = mode_def->mode;
5959*77c1e3ccSAndroid Build Coastguard Worker     const MV_REFERENCE_FRAME *ref_frames = mode_def->ref_frame;
5960*77c1e3ccSAndroid Build Coastguard Worker 
5961*77c1e3ccSAndroid Build Coastguard Worker     const MV_REFERENCE_FRAME ref_frame = ref_frames[0];
5962*77c1e3ccSAndroid Build Coastguard Worker     const MV_REFERENCE_FRAME second_ref_frame = ref_frames[1];
5963*77c1e3ccSAndroid Build Coastguard Worker     const int is_single_pred =
5964*77c1e3ccSAndroid Build Coastguard Worker         ref_frame > INTRA_FRAME && second_ref_frame == NONE_FRAME;
5965*77c1e3ccSAndroid Build Coastguard Worker     const int comp_pred = second_ref_frame > INTRA_FRAME;
5966*77c1e3ccSAndroid Build Coastguard Worker 
5967*77c1e3ccSAndroid Build Coastguard Worker     init_mbmi(mbmi, this_mode, ref_frames, cm);
5968*77c1e3ccSAndroid Build Coastguard Worker 
5969*77c1e3ccSAndroid Build Coastguard Worker     txfm_info->skip_txfm = 0;
5970*77c1e3ccSAndroid Build Coastguard Worker     sf_args.num_single_modes_processed += is_single_pred;
5971*77c1e3ccSAndroid Build Coastguard Worker     set_ref_ptrs(cm, xd, ref_frame, second_ref_frame);
5972*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
5973*77c1e3ccSAndroid Build Coastguard Worker     start_timing(cpi, skip_inter_mode_time);
5974*77c1e3ccSAndroid Build Coastguard Worker #endif
5975*77c1e3ccSAndroid Build Coastguard Worker     // Apply speed features to decide if this inter mode can be skipped
5976*77c1e3ccSAndroid Build Coastguard Worker     const int is_skip_inter_mode = skip_inter_mode(
5977*77c1e3ccSAndroid Build Coastguard Worker         cpi, x, bsize, ref_frame_rd, midx, &sf_args, is_low_temp_var);
5978*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
5979*77c1e3ccSAndroid Build Coastguard Worker     end_timing(cpi, skip_inter_mode_time);
5980*77c1e3ccSAndroid Build Coastguard Worker #endif
5981*77c1e3ccSAndroid Build Coastguard Worker     if (is_skip_inter_mode) continue;
5982*77c1e3ccSAndroid Build Coastguard Worker 
5983*77c1e3ccSAndroid Build Coastguard Worker     // Select prediction reference frames.
5984*77c1e3ccSAndroid Build Coastguard Worker     for (i = 0; i < num_planes; i++) {
5985*77c1e3ccSAndroid Build Coastguard Worker       xd->plane[i].pre[0] = yv12_mb[ref_frame][i];
5986*77c1e3ccSAndroid Build Coastguard Worker       if (comp_pred) xd->plane[i].pre[1] = yv12_mb[second_ref_frame][i];
5987*77c1e3ccSAndroid Build Coastguard Worker     }
5988*77c1e3ccSAndroid Build Coastguard Worker 
5989*77c1e3ccSAndroid Build Coastguard Worker     mbmi->angle_delta[PLANE_TYPE_Y] = 0;
5990*77c1e3ccSAndroid Build Coastguard Worker     mbmi->angle_delta[PLANE_TYPE_UV] = 0;
5991*77c1e3ccSAndroid Build Coastguard Worker     mbmi->filter_intra_mode_info.use_filter_intra = 0;
5992*77c1e3ccSAndroid Build Coastguard Worker     mbmi->ref_mv_idx = 0;
5993*77c1e3ccSAndroid Build Coastguard Worker 
5994*77c1e3ccSAndroid Build Coastguard Worker     const int64_t ref_best_rd = search_state.best_rd;
5995*77c1e3ccSAndroid Build Coastguard Worker     RD_STATS rd_stats, rd_stats_y, rd_stats_uv;
5996*77c1e3ccSAndroid Build Coastguard Worker     av1_init_rd_stats(&rd_stats);
5997*77c1e3ccSAndroid Build Coastguard Worker 
5998*77c1e3ccSAndroid Build Coastguard Worker     const int ref_frame_cost = comp_pred
5999*77c1e3ccSAndroid Build Coastguard Worker                                    ? ref_costs_comp[ref_frame][second_ref_frame]
6000*77c1e3ccSAndroid Build Coastguard Worker                                    : ref_costs_single[ref_frame];
6001*77c1e3ccSAndroid Build Coastguard Worker     const int compmode_cost =
6002*77c1e3ccSAndroid Build Coastguard Worker         is_comp_ref_allowed(mbmi->bsize) ? comp_inter_cost[comp_pred] : 0;
6003*77c1e3ccSAndroid Build Coastguard Worker     const int real_compmode_cost =
6004*77c1e3ccSAndroid Build Coastguard Worker         cm->current_frame.reference_mode == REFERENCE_MODE_SELECT
6005*77c1e3ccSAndroid Build Coastguard Worker             ? compmode_cost
6006*77c1e3ccSAndroid Build Coastguard Worker             : 0;
6007*77c1e3ccSAndroid Build Coastguard Worker     // Point to variables that are maintained between loop iterations
6008*77c1e3ccSAndroid Build Coastguard Worker     args.single_newmv = search_state.single_newmv;
6009*77c1e3ccSAndroid Build Coastguard Worker     args.single_newmv_rate = search_state.single_newmv_rate;
6010*77c1e3ccSAndroid Build Coastguard Worker     args.single_newmv_valid = search_state.single_newmv_valid;
6011*77c1e3ccSAndroid Build Coastguard Worker     args.single_comp_cost = real_compmode_cost;
6012*77c1e3ccSAndroid Build Coastguard Worker     args.ref_frame_cost = ref_frame_cost;
6013*77c1e3ccSAndroid Build Coastguard Worker     args.best_pred_sse = search_state.best_pred_sse;
6014*77c1e3ccSAndroid Build Coastguard Worker     args.skip_ifs = skip_interp_filter_search(cpi, is_single_pred);
6015*77c1e3ccSAndroid Build Coastguard Worker 
6016*77c1e3ccSAndroid Build Coastguard Worker     int64_t skip_rd[2] = { search_state.best_skip_rd[0],
6017*77c1e3ccSAndroid Build Coastguard Worker                            search_state.best_skip_rd[1] };
6018*77c1e3ccSAndroid Build Coastguard Worker     int64_t this_yrd = INT64_MAX;
6019*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
6020*77c1e3ccSAndroid Build Coastguard Worker     start_timing(cpi, handle_inter_mode_time);
6021*77c1e3ccSAndroid Build Coastguard Worker #endif
6022*77c1e3ccSAndroid Build Coastguard Worker     int64_t this_rd = handle_inter_mode(
6023*77c1e3ccSAndroid Build Coastguard Worker         cpi, tile_data, x, bsize, &rd_stats, &rd_stats_y, &rd_stats_uv, &args,
6024*77c1e3ccSAndroid Build Coastguard Worker         ref_best_rd, tmp_buf, &x->comp_rd_buffer, &best_est_rd, do_tx_search,
6025*77c1e3ccSAndroid Build Coastguard Worker         inter_modes_info, &motion_mode_cand, skip_rd, &inter_cost_info_from_tpl,
6026*77c1e3ccSAndroid Build Coastguard Worker         &this_yrd);
6027*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
6028*77c1e3ccSAndroid Build Coastguard Worker     end_timing(cpi, handle_inter_mode_time);
6029*77c1e3ccSAndroid Build Coastguard Worker #endif
6030*77c1e3ccSAndroid Build Coastguard Worker     if (current_frame->reference_mode != SINGLE_REFERENCE) {
6031*77c1e3ccSAndroid Build Coastguard Worker       if (!args.skip_ifs &&
6032*77c1e3ccSAndroid Build Coastguard Worker           sf->inter_sf.prune_comp_search_by_single_result > 0 &&
6033*77c1e3ccSAndroid Build Coastguard Worker           is_inter_singleref_mode(this_mode)) {
6034*77c1e3ccSAndroid Build Coastguard Worker         collect_single_states(x, &search_state, mbmi);
6035*77c1e3ccSAndroid Build Coastguard Worker       }
6036*77c1e3ccSAndroid Build Coastguard Worker 
6037*77c1e3ccSAndroid Build Coastguard Worker       if (sf->inter_sf.prune_comp_using_best_single_mode_ref > 0 &&
6038*77c1e3ccSAndroid Build Coastguard Worker           is_inter_singleref_mode(this_mode))
6039*77c1e3ccSAndroid Build Coastguard Worker         update_best_single_mode(&search_state, this_mode, ref_frame, this_rd);
6040*77c1e3ccSAndroid Build Coastguard Worker     }
6041*77c1e3ccSAndroid Build Coastguard Worker 
6042*77c1e3ccSAndroid Build Coastguard Worker     if (this_rd == INT64_MAX) continue;
6043*77c1e3ccSAndroid Build Coastguard Worker 
6044*77c1e3ccSAndroid Build Coastguard Worker     if (mbmi->skip_txfm) {
6045*77c1e3ccSAndroid Build Coastguard Worker       rd_stats_y.rate = 0;
6046*77c1e3ccSAndroid Build Coastguard Worker       rd_stats_uv.rate = 0;
6047*77c1e3ccSAndroid Build Coastguard Worker     }
6048*77c1e3ccSAndroid Build Coastguard Worker 
6049*77c1e3ccSAndroid Build Coastguard Worker     if (sf->inter_sf.prune_compound_using_single_ref && is_single_pred &&
6050*77c1e3ccSAndroid Build Coastguard Worker         this_rd < ref_frame_rd[ref_frame]) {
6051*77c1e3ccSAndroid Build Coastguard Worker       ref_frame_rd[ref_frame] = this_rd;
6052*77c1e3ccSAndroid Build Coastguard Worker     }
6053*77c1e3ccSAndroid Build Coastguard Worker 
6054*77c1e3ccSAndroid Build Coastguard Worker     // Did this mode help, i.e., is it the new best mode
6055*77c1e3ccSAndroid Build Coastguard Worker     if (this_rd < search_state.best_rd) {
6056*77c1e3ccSAndroid Build Coastguard Worker       assert(IMPLIES(comp_pred,
6057*77c1e3ccSAndroid Build Coastguard Worker                      cm->current_frame.reference_mode != SINGLE_REFERENCE));
6058*77c1e3ccSAndroid Build Coastguard Worker       search_state.best_pred_sse = x->pred_sse[ref_frame];
6059*77c1e3ccSAndroid Build Coastguard Worker       best_inter_yrd = this_yrd;
6060*77c1e3ccSAndroid Build Coastguard Worker       update_search_state(&search_state, rd_cost, ctx, &rd_stats, &rd_stats_y,
6061*77c1e3ccSAndroid Build Coastguard Worker                           &rd_stats_uv, mode_enum, x, do_tx_search);
6062*77c1e3ccSAndroid Build Coastguard Worker       if (do_tx_search) search_state.best_skip_rd[0] = skip_rd[0];
6063*77c1e3ccSAndroid Build Coastguard Worker       // skip_rd[0] is the best total rd for a skip mode so far.
6064*77c1e3ccSAndroid Build Coastguard Worker       // skip_rd[1] is the best total rd for a skip mode so far in luma.
6065*77c1e3ccSAndroid Build Coastguard Worker       // When do_tx_search = 1, both skip_rd[0] and skip_rd[1] are updated.
6066*77c1e3ccSAndroid Build Coastguard Worker       // When do_tx_search = 0, skip_rd[1] is updated.
6067*77c1e3ccSAndroid Build Coastguard Worker       search_state.best_skip_rd[1] = skip_rd[1];
6068*77c1e3ccSAndroid Build Coastguard Worker     }
6069*77c1e3ccSAndroid Build Coastguard Worker     if (sf->winner_mode_sf.motion_mode_for_winner_cand) {
6070*77c1e3ccSAndroid Build Coastguard Worker       // Add this mode to motion mode candidate list for motion mode search
6071*77c1e3ccSAndroid Build Coastguard Worker       // if using motion_mode_for_winner_cand speed feature
6072*77c1e3ccSAndroid Build Coastguard Worker       handle_winner_cand(mbmi, &best_motion_mode_cands,
6073*77c1e3ccSAndroid Build Coastguard Worker                          max_winner_motion_mode_cand, this_rd,
6074*77c1e3ccSAndroid Build Coastguard Worker                          &motion_mode_cand, args.skip_motion_mode);
6075*77c1e3ccSAndroid Build Coastguard Worker     }
6076*77c1e3ccSAndroid Build Coastguard Worker 
6077*77c1e3ccSAndroid Build Coastguard Worker     /* keep record of best compound/single-only prediction */
6078*77c1e3ccSAndroid Build Coastguard Worker     record_best_compound(cm->current_frame.reference_mode, &rd_stats, comp_pred,
6079*77c1e3ccSAndroid Build Coastguard Worker                          x->rdmult, &search_state, compmode_cost);
6080*77c1e3ccSAndroid Build Coastguard Worker   }
6081*77c1e3ccSAndroid Build Coastguard Worker 
6082*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
6083*77c1e3ccSAndroid Build Coastguard Worker   start_timing(cpi, evaluate_motion_mode_for_winner_candidates_time);
6084*77c1e3ccSAndroid Build Coastguard Worker #endif
6085*77c1e3ccSAndroid Build Coastguard Worker   if (sf->winner_mode_sf.motion_mode_for_winner_cand) {
6086*77c1e3ccSAndroid Build Coastguard Worker     // For the single ref winner candidates, evaluate other motion modes (non
6087*77c1e3ccSAndroid Build Coastguard Worker     // simple translation).
6088*77c1e3ccSAndroid Build Coastguard Worker     evaluate_motion_mode_for_winner_candidates(
6089*77c1e3ccSAndroid Build Coastguard Worker         cpi, x, rd_cost, &args, tile_data, ctx, yv12_mb,
6090*77c1e3ccSAndroid Build Coastguard Worker         &best_motion_mode_cands, do_tx_search, bsize, &best_est_rd,
6091*77c1e3ccSAndroid Build Coastguard Worker         &search_state, &best_inter_yrd);
6092*77c1e3ccSAndroid Build Coastguard Worker   }
6093*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
6094*77c1e3ccSAndroid Build Coastguard Worker   end_timing(cpi, evaluate_motion_mode_for_winner_candidates_time);
6095*77c1e3ccSAndroid Build Coastguard Worker #endif
6096*77c1e3ccSAndroid Build Coastguard Worker 
6097*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
6098*77c1e3ccSAndroid Build Coastguard Worker   start_timing(cpi, do_tx_search_time);
6099*77c1e3ccSAndroid Build Coastguard Worker #endif
6100*77c1e3ccSAndroid Build Coastguard Worker   if (do_tx_search != 1) {
6101*77c1e3ccSAndroid Build Coastguard Worker     // A full tx search has not yet been done, do tx search for
6102*77c1e3ccSAndroid Build Coastguard Worker     // top mode candidates
6103*77c1e3ccSAndroid Build Coastguard Worker     tx_search_best_inter_candidates(cpi, tile_data, x, best_rd_so_far, bsize,
6104*77c1e3ccSAndroid Build Coastguard Worker                                     yv12_mb, mi_row, mi_col, &search_state,
6105*77c1e3ccSAndroid Build Coastguard Worker                                     rd_cost, ctx, &best_inter_yrd);
6106*77c1e3ccSAndroid Build Coastguard Worker   }
6107*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
6108*77c1e3ccSAndroid Build Coastguard Worker   end_timing(cpi, do_tx_search_time);
6109*77c1e3ccSAndroid Build Coastguard Worker #endif
6110*77c1e3ccSAndroid Build Coastguard Worker 
6111*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
6112*77c1e3ccSAndroid Build Coastguard Worker   start_timing(cpi, handle_intra_mode_time);
6113*77c1e3ccSAndroid Build Coastguard Worker #endif
6114*77c1e3ccSAndroid Build Coastguard Worker   // Gate intra mode evaluation if best of inter is skip except when source
6115*77c1e3ccSAndroid Build Coastguard Worker   // variance is extremely low and also based on max intra bsize.
6116*77c1e3ccSAndroid Build Coastguard Worker   skip_intra_modes_in_interframe(cm, x, bsize, &search_state, sf, inter_cost,
6117*77c1e3ccSAndroid Build Coastguard Worker                                  intra_cost);
6118*77c1e3ccSAndroid Build Coastguard Worker 
6119*77c1e3ccSAndroid Build Coastguard Worker   const unsigned int intra_ref_frame_cost = ref_costs_single[INTRA_FRAME];
6120*77c1e3ccSAndroid Build Coastguard Worker   search_intra_modes_in_interframe(&search_state, cpi, x, rd_cost, bsize, ctx,
6121*77c1e3ccSAndroid Build Coastguard Worker                                    &sf_args, intra_ref_frame_cost,
6122*77c1e3ccSAndroid Build Coastguard Worker                                    best_inter_yrd);
6123*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
6124*77c1e3ccSAndroid Build Coastguard Worker   end_timing(cpi, handle_intra_mode_time);
6125*77c1e3ccSAndroid Build Coastguard Worker #endif
6126*77c1e3ccSAndroid Build Coastguard Worker 
6127*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
6128*77c1e3ccSAndroid Build Coastguard Worker   start_timing(cpi, refine_winner_mode_tx_time);
6129*77c1e3ccSAndroid Build Coastguard Worker #endif
6130*77c1e3ccSAndroid Build Coastguard Worker   int winner_mode_count =
6131*77c1e3ccSAndroid Build Coastguard Worker       sf->winner_mode_sf.multi_winner_mode_type ? x->winner_mode_count : 1;
6132*77c1e3ccSAndroid Build Coastguard Worker   // In effect only when fast tx search speed features are enabled.
6133*77c1e3ccSAndroid Build Coastguard Worker   refine_winner_mode_tx(
6134*77c1e3ccSAndroid Build Coastguard Worker       cpi, x, rd_cost, bsize, ctx, &search_state.best_mode_index,
6135*77c1e3ccSAndroid Build Coastguard Worker       &search_state.best_mbmode, yv12_mb, search_state.best_rate_y,
6136*77c1e3ccSAndroid Build Coastguard Worker       search_state.best_rate_uv, &search_state.best_skip2, winner_mode_count);
6137*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
6138*77c1e3ccSAndroid Build Coastguard Worker   end_timing(cpi, refine_winner_mode_tx_time);
6139*77c1e3ccSAndroid Build Coastguard Worker #endif
6140*77c1e3ccSAndroid Build Coastguard Worker 
6141*77c1e3ccSAndroid Build Coastguard Worker   // Initialize default mode evaluation params
6142*77c1e3ccSAndroid Build Coastguard Worker   set_mode_eval_params(cpi, x, DEFAULT_EVAL);
6143*77c1e3ccSAndroid Build Coastguard Worker 
6144*77c1e3ccSAndroid Build Coastguard Worker   // Only try palette mode when the best mode so far is an intra mode.
6145*77c1e3ccSAndroid Build Coastguard Worker   const int try_palette =
6146*77c1e3ccSAndroid Build Coastguard Worker       cpi->oxcf.tool_cfg.enable_palette &&
6147*77c1e3ccSAndroid Build Coastguard Worker       av1_allow_palette(features->allow_screen_content_tools, mbmi->bsize) &&
6148*77c1e3ccSAndroid Build Coastguard Worker       !is_inter_mode(search_state.best_mbmode.mode) && rd_cost->rate != INT_MAX;
6149*77c1e3ccSAndroid Build Coastguard Worker   RD_STATS this_rd_cost;
6150*77c1e3ccSAndroid Build Coastguard Worker   int this_skippable = 0;
6151*77c1e3ccSAndroid Build Coastguard Worker   if (try_palette) {
6152*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
6153*77c1e3ccSAndroid Build Coastguard Worker     start_timing(cpi, av1_search_palette_mode_time);
6154*77c1e3ccSAndroid Build Coastguard Worker #endif
6155*77c1e3ccSAndroid Build Coastguard Worker     this_skippable = av1_search_palette_mode(
6156*77c1e3ccSAndroid Build Coastguard Worker         &search_state.intra_search_state, cpi, x, bsize, intra_ref_frame_cost,
6157*77c1e3ccSAndroid Build Coastguard Worker         ctx, &this_rd_cost, search_state.best_rd);
6158*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_COMPONENT_TIMING
6159*77c1e3ccSAndroid Build Coastguard Worker     end_timing(cpi, av1_search_palette_mode_time);
6160*77c1e3ccSAndroid Build Coastguard Worker #endif
6161*77c1e3ccSAndroid Build Coastguard Worker     if (this_rd_cost.rdcost < search_state.best_rd) {
6162*77c1e3ccSAndroid Build Coastguard Worker       search_state.best_mode_index = THR_DC;
6163*77c1e3ccSAndroid Build Coastguard Worker       mbmi->mv[0].as_int = 0;
6164*77c1e3ccSAndroid Build Coastguard Worker       rd_cost->rate = this_rd_cost.rate;
6165*77c1e3ccSAndroid Build Coastguard Worker       rd_cost->dist = this_rd_cost.dist;
6166*77c1e3ccSAndroid Build Coastguard Worker       rd_cost->rdcost = this_rd_cost.rdcost;
6167*77c1e3ccSAndroid Build Coastguard Worker       search_state.best_rd = rd_cost->rdcost;
6168*77c1e3ccSAndroid Build Coastguard Worker       search_state.best_mbmode = *mbmi;
6169*77c1e3ccSAndroid Build Coastguard Worker       search_state.best_skip2 = 0;
6170*77c1e3ccSAndroid Build Coastguard Worker       search_state.best_mode_skippable = this_skippable;
6171*77c1e3ccSAndroid Build Coastguard Worker       memcpy(ctx->blk_skip, txfm_info->blk_skip,
6172*77c1e3ccSAndroid Build Coastguard Worker              sizeof(txfm_info->blk_skip[0]) * ctx->num_4x4_blk);
6173*77c1e3ccSAndroid Build Coastguard Worker       av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
6174*77c1e3ccSAndroid Build Coastguard Worker     }
6175*77c1e3ccSAndroid Build Coastguard Worker   }
6176*77c1e3ccSAndroid Build Coastguard Worker 
6177*77c1e3ccSAndroid Build Coastguard Worker   search_state.best_mbmode.skip_mode = 0;
6178*77c1e3ccSAndroid Build Coastguard Worker   if (cm->current_frame.skip_mode_info.skip_mode_flag &&
6179*77c1e3ccSAndroid Build Coastguard Worker       is_comp_ref_allowed(bsize)) {
6180*77c1e3ccSAndroid Build Coastguard Worker     const struct segmentation *const seg = &cm->seg;
6181*77c1e3ccSAndroid Build Coastguard Worker     unsigned char segment_id = mbmi->segment_id;
6182*77c1e3ccSAndroid Build Coastguard Worker     if (!segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME)) {
6183*77c1e3ccSAndroid Build Coastguard Worker       rd_pick_skip_mode(rd_cost, &search_state, cpi, x, bsize, yv12_mb);
6184*77c1e3ccSAndroid Build Coastguard Worker     }
6185*77c1e3ccSAndroid Build Coastguard Worker   }
6186*77c1e3ccSAndroid Build Coastguard Worker 
6187*77c1e3ccSAndroid Build Coastguard Worker   // Make sure that the ref_mv_idx is only nonzero when we're
6188*77c1e3ccSAndroid Build Coastguard Worker   // using a mode which can support ref_mv_idx
6189*77c1e3ccSAndroid Build Coastguard Worker   if (search_state.best_mbmode.ref_mv_idx != 0 &&
6190*77c1e3ccSAndroid Build Coastguard Worker       !(search_state.best_mbmode.mode == NEWMV ||
6191*77c1e3ccSAndroid Build Coastguard Worker         search_state.best_mbmode.mode == NEW_NEWMV ||
6192*77c1e3ccSAndroid Build Coastguard Worker         have_nearmv_in_inter_mode(search_state.best_mbmode.mode))) {
6193*77c1e3ccSAndroid Build Coastguard Worker     search_state.best_mbmode.ref_mv_idx = 0;
6194*77c1e3ccSAndroid Build Coastguard Worker   }
6195*77c1e3ccSAndroid Build Coastguard Worker 
6196*77c1e3ccSAndroid Build Coastguard Worker   if (search_state.best_mode_index == THR_INVALID ||
6197*77c1e3ccSAndroid Build Coastguard Worker       search_state.best_rd >= best_rd_so_far) {
6198*77c1e3ccSAndroid Build Coastguard Worker     rd_cost->rate = INT_MAX;
6199*77c1e3ccSAndroid Build Coastguard Worker     rd_cost->rdcost = INT64_MAX;
6200*77c1e3ccSAndroid Build Coastguard Worker     return;
6201*77c1e3ccSAndroid Build Coastguard Worker   }
6202*77c1e3ccSAndroid Build Coastguard Worker 
6203*77c1e3ccSAndroid Build Coastguard Worker   const InterpFilter interp_filter = features->interp_filter;
6204*77c1e3ccSAndroid Build Coastguard Worker   assert((interp_filter == SWITCHABLE) ||
6205*77c1e3ccSAndroid Build Coastguard Worker          (interp_filter ==
6206*77c1e3ccSAndroid Build Coastguard Worker           search_state.best_mbmode.interp_filters.as_filters.y_filter) ||
6207*77c1e3ccSAndroid Build Coastguard Worker          !is_inter_block(&search_state.best_mbmode));
6208*77c1e3ccSAndroid Build Coastguard Worker   assert((interp_filter == SWITCHABLE) ||
6209*77c1e3ccSAndroid Build Coastguard Worker          (interp_filter ==
6210*77c1e3ccSAndroid Build Coastguard Worker           search_state.best_mbmode.interp_filters.as_filters.x_filter) ||
6211*77c1e3ccSAndroid Build Coastguard Worker          !is_inter_block(&search_state.best_mbmode));
6212*77c1e3ccSAndroid Build Coastguard Worker 
6213*77c1e3ccSAndroid Build Coastguard Worker   if (!cpi->rc.is_src_frame_alt_ref && sf->inter_sf.adaptive_rd_thresh) {
6214*77c1e3ccSAndroid Build Coastguard Worker     av1_update_rd_thresh_fact(
6215*77c1e3ccSAndroid Build Coastguard Worker         cm, x->thresh_freq_fact, sf->inter_sf.adaptive_rd_thresh, bsize,
6216*77c1e3ccSAndroid Build Coastguard Worker         search_state.best_mode_index, mode_start, mode_end, THR_DC, MAX_MODES);
6217*77c1e3ccSAndroid Build Coastguard Worker   }
6218*77c1e3ccSAndroid Build Coastguard Worker 
6219*77c1e3ccSAndroid Build Coastguard Worker   // macroblock modes
6220*77c1e3ccSAndroid Build Coastguard Worker   *mbmi = search_state.best_mbmode;
6221*77c1e3ccSAndroid Build Coastguard Worker   txfm_info->skip_txfm |= search_state.best_skip2;
6222*77c1e3ccSAndroid Build Coastguard Worker 
6223*77c1e3ccSAndroid Build Coastguard Worker   // Note: this section is needed since the mode may have been forced to
6224*77c1e3ccSAndroid Build Coastguard Worker   // GLOBALMV by the all-zero mode handling of ref-mv.
6225*77c1e3ccSAndroid Build Coastguard Worker   if (mbmi->mode == GLOBALMV || mbmi->mode == GLOBAL_GLOBALMV) {
6226*77c1e3ccSAndroid Build Coastguard Worker     // Correct the interp filters for GLOBALMV
6227*77c1e3ccSAndroid Build Coastguard Worker     if (is_nontrans_global_motion(xd, xd->mi[0])) {
6228*77c1e3ccSAndroid Build Coastguard Worker       int_interpfilters filters =
6229*77c1e3ccSAndroid Build Coastguard Worker           av1_broadcast_interp_filter(av1_unswitchable_filter(interp_filter));
6230*77c1e3ccSAndroid Build Coastguard Worker       assert(mbmi->interp_filters.as_int == filters.as_int);
6231*77c1e3ccSAndroid Build Coastguard Worker       (void)filters;
6232*77c1e3ccSAndroid Build Coastguard Worker     }
6233*77c1e3ccSAndroid Build Coastguard Worker   }
6234*77c1e3ccSAndroid Build Coastguard Worker 
6235*77c1e3ccSAndroid Build Coastguard Worker   txfm_info->skip_txfm |= search_state.best_mode_skippable;
6236*77c1e3ccSAndroid Build Coastguard Worker 
6237*77c1e3ccSAndroid Build Coastguard Worker   assert(search_state.best_mode_index != THR_INVALID);
6238*77c1e3ccSAndroid Build Coastguard Worker 
6239*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_INTERNAL_STATS
6240*77c1e3ccSAndroid Build Coastguard Worker   store_coding_context(x, ctx, search_state.best_mode_index,
6241*77c1e3ccSAndroid Build Coastguard Worker                        search_state.best_mode_skippable);
6242*77c1e3ccSAndroid Build Coastguard Worker #else
6243*77c1e3ccSAndroid Build Coastguard Worker   store_coding_context(x, ctx, search_state.best_mode_skippable);
6244*77c1e3ccSAndroid Build Coastguard Worker #endif  // CONFIG_INTERNAL_STATS
6245*77c1e3ccSAndroid Build Coastguard Worker 
6246*77c1e3ccSAndroid Build Coastguard Worker   if (mbmi->palette_mode_info.palette_size[1] > 0) {
6247*77c1e3ccSAndroid Build Coastguard Worker     assert(try_palette);
6248*77c1e3ccSAndroid Build Coastguard Worker     av1_restore_uv_color_map(cpi, x);
6249*77c1e3ccSAndroid Build Coastguard Worker   }
6250*77c1e3ccSAndroid Build Coastguard Worker }
6251*77c1e3ccSAndroid Build Coastguard Worker 
av1_rd_pick_inter_mode_sb_seg_skip(const AV1_COMP * cpi,TileDataEnc * tile_data,MACROBLOCK * x,int mi_row,int mi_col,RD_STATS * rd_cost,BLOCK_SIZE bsize,PICK_MODE_CONTEXT * ctx,int64_t best_rd_so_far)6252*77c1e3ccSAndroid Build Coastguard Worker void av1_rd_pick_inter_mode_sb_seg_skip(const AV1_COMP *cpi,
6253*77c1e3ccSAndroid Build Coastguard Worker                                         TileDataEnc *tile_data, MACROBLOCK *x,
6254*77c1e3ccSAndroid Build Coastguard Worker                                         int mi_row, int mi_col,
6255*77c1e3ccSAndroid Build Coastguard Worker                                         RD_STATS *rd_cost, BLOCK_SIZE bsize,
6256*77c1e3ccSAndroid Build Coastguard Worker                                         PICK_MODE_CONTEXT *ctx,
6257*77c1e3ccSAndroid Build Coastguard Worker                                         int64_t best_rd_so_far) {
6258*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
6259*77c1e3ccSAndroid Build Coastguard Worker   const FeatureFlags *const features = &cm->features;
6260*77c1e3ccSAndroid Build Coastguard Worker   MACROBLOCKD *const xd = &x->e_mbd;
6261*77c1e3ccSAndroid Build Coastguard Worker   MB_MODE_INFO *const mbmi = xd->mi[0];
6262*77c1e3ccSAndroid Build Coastguard Worker   unsigned char segment_id = mbmi->segment_id;
6263*77c1e3ccSAndroid Build Coastguard Worker   const int comp_pred = 0;
6264*77c1e3ccSAndroid Build Coastguard Worker   int i;
6265*77c1e3ccSAndroid Build Coastguard Worker   unsigned int ref_costs_single[REF_FRAMES];
6266*77c1e3ccSAndroid Build Coastguard Worker   unsigned int ref_costs_comp[REF_FRAMES][REF_FRAMES];
6267*77c1e3ccSAndroid Build Coastguard Worker   const ModeCosts *mode_costs = &x->mode_costs;
6268*77c1e3ccSAndroid Build Coastguard Worker   const int *comp_inter_cost =
6269*77c1e3ccSAndroid Build Coastguard Worker       mode_costs->comp_inter_cost[av1_get_reference_mode_context(xd)];
6270*77c1e3ccSAndroid Build Coastguard Worker   InterpFilter best_filter = SWITCHABLE;
6271*77c1e3ccSAndroid Build Coastguard Worker   int64_t this_rd = INT64_MAX;
6272*77c1e3ccSAndroid Build Coastguard Worker   int rate2 = 0;
6273*77c1e3ccSAndroid Build Coastguard Worker   const int64_t distortion2 = 0;
6274*77c1e3ccSAndroid Build Coastguard Worker   (void)mi_row;
6275*77c1e3ccSAndroid Build Coastguard Worker   (void)mi_col;
6276*77c1e3ccSAndroid Build Coastguard Worker   (void)tile_data;
6277*77c1e3ccSAndroid Build Coastguard Worker 
6278*77c1e3ccSAndroid Build Coastguard Worker   av1_collect_neighbors_ref_counts(xd);
6279*77c1e3ccSAndroid Build Coastguard Worker 
6280*77c1e3ccSAndroid Build Coastguard Worker   estimate_ref_frame_costs(cm, xd, mode_costs, segment_id, ref_costs_single,
6281*77c1e3ccSAndroid Build Coastguard Worker                            ref_costs_comp);
6282*77c1e3ccSAndroid Build Coastguard Worker 
6283*77c1e3ccSAndroid Build Coastguard Worker   for (i = 0; i < REF_FRAMES; ++i) x->pred_sse[i] = INT_MAX;
6284*77c1e3ccSAndroid Build Coastguard Worker   for (i = LAST_FRAME; i < REF_FRAMES; ++i) x->pred_mv_sad[i] = INT_MAX;
6285*77c1e3ccSAndroid Build Coastguard Worker 
6286*77c1e3ccSAndroid Build Coastguard Worker   rd_cost->rate = INT_MAX;
6287*77c1e3ccSAndroid Build Coastguard Worker 
6288*77c1e3ccSAndroid Build Coastguard Worker   assert(segfeature_active(&cm->seg, segment_id, SEG_LVL_SKIP));
6289*77c1e3ccSAndroid Build Coastguard Worker 
6290*77c1e3ccSAndroid Build Coastguard Worker   mbmi->palette_mode_info.palette_size[0] = 0;
6291*77c1e3ccSAndroid Build Coastguard Worker   mbmi->palette_mode_info.palette_size[1] = 0;
6292*77c1e3ccSAndroid Build Coastguard Worker   mbmi->filter_intra_mode_info.use_filter_intra = 0;
6293*77c1e3ccSAndroid Build Coastguard Worker   mbmi->mode = GLOBALMV;
6294*77c1e3ccSAndroid Build Coastguard Worker   mbmi->motion_mode = SIMPLE_TRANSLATION;
6295*77c1e3ccSAndroid Build Coastguard Worker   mbmi->uv_mode = UV_DC_PRED;
6296*77c1e3ccSAndroid Build Coastguard Worker   if (segfeature_active(&cm->seg, segment_id, SEG_LVL_REF_FRAME))
6297*77c1e3ccSAndroid Build Coastguard Worker     mbmi->ref_frame[0] = get_segdata(&cm->seg, segment_id, SEG_LVL_REF_FRAME);
6298*77c1e3ccSAndroid Build Coastguard Worker   else
6299*77c1e3ccSAndroid Build Coastguard Worker     mbmi->ref_frame[0] = LAST_FRAME;
6300*77c1e3ccSAndroid Build Coastguard Worker   mbmi->ref_frame[1] = NONE_FRAME;
6301*77c1e3ccSAndroid Build Coastguard Worker   mbmi->mv[0].as_int =
6302*77c1e3ccSAndroid Build Coastguard Worker       gm_get_motion_vector(&cm->global_motion[mbmi->ref_frame[0]],
6303*77c1e3ccSAndroid Build Coastguard Worker                            features->allow_high_precision_mv, bsize, mi_col,
6304*77c1e3ccSAndroid Build Coastguard Worker                            mi_row, features->cur_frame_force_integer_mv)
6305*77c1e3ccSAndroid Build Coastguard Worker           .as_int;
6306*77c1e3ccSAndroid Build Coastguard Worker   mbmi->tx_size = max_txsize_lookup[bsize];
6307*77c1e3ccSAndroid Build Coastguard Worker   x->txfm_search_info.skip_txfm = 1;
6308*77c1e3ccSAndroid Build Coastguard Worker 
6309*77c1e3ccSAndroid Build Coastguard Worker   mbmi->ref_mv_idx = 0;
6310*77c1e3ccSAndroid Build Coastguard Worker 
6311*77c1e3ccSAndroid Build Coastguard Worker   mbmi->motion_mode = SIMPLE_TRANSLATION;
6312*77c1e3ccSAndroid Build Coastguard Worker   av1_count_overlappable_neighbors(cm, xd);
6313*77c1e3ccSAndroid Build Coastguard Worker   if (is_motion_variation_allowed_bsize(bsize) && !has_second_ref(mbmi)) {
6314*77c1e3ccSAndroid Build Coastguard Worker     int pts[SAMPLES_ARRAY_SIZE], pts_inref[SAMPLES_ARRAY_SIZE];
6315*77c1e3ccSAndroid Build Coastguard Worker     mbmi->num_proj_ref = av1_findSamples(cm, xd, pts, pts_inref);
6316*77c1e3ccSAndroid Build Coastguard Worker     // Select the samples according to motion vector difference
6317*77c1e3ccSAndroid Build Coastguard Worker     if (mbmi->num_proj_ref > 1) {
6318*77c1e3ccSAndroid Build Coastguard Worker       mbmi->num_proj_ref = av1_selectSamples(&mbmi->mv[0].as_mv, pts, pts_inref,
6319*77c1e3ccSAndroid Build Coastguard Worker                                              mbmi->num_proj_ref, bsize);
6320*77c1e3ccSAndroid Build Coastguard Worker     }
6321*77c1e3ccSAndroid Build Coastguard Worker   }
6322*77c1e3ccSAndroid Build Coastguard Worker 
6323*77c1e3ccSAndroid Build Coastguard Worker   const InterpFilter interp_filter = features->interp_filter;
6324*77c1e3ccSAndroid Build Coastguard Worker   set_default_interp_filters(mbmi, interp_filter);
6325*77c1e3ccSAndroid Build Coastguard Worker 
6326*77c1e3ccSAndroid Build Coastguard Worker   if (interp_filter != SWITCHABLE) {
6327*77c1e3ccSAndroid Build Coastguard Worker     best_filter = interp_filter;
6328*77c1e3ccSAndroid Build Coastguard Worker   } else {
6329*77c1e3ccSAndroid Build Coastguard Worker     best_filter = EIGHTTAP_REGULAR;
6330*77c1e3ccSAndroid Build Coastguard Worker     if (av1_is_interp_needed(xd)) {
6331*77c1e3ccSAndroid Build Coastguard Worker       int rs;
6332*77c1e3ccSAndroid Build Coastguard Worker       int best_rs = INT_MAX;
6333*77c1e3ccSAndroid Build Coastguard Worker       for (i = 0; i < SWITCHABLE_FILTERS; ++i) {
6334*77c1e3ccSAndroid Build Coastguard Worker         mbmi->interp_filters = av1_broadcast_interp_filter(i);
6335*77c1e3ccSAndroid Build Coastguard Worker         rs = av1_get_switchable_rate(x, xd, interp_filter,
6336*77c1e3ccSAndroid Build Coastguard Worker                                      cm->seq_params->enable_dual_filter);
6337*77c1e3ccSAndroid Build Coastguard Worker         if (rs < best_rs) {
6338*77c1e3ccSAndroid Build Coastguard Worker           best_rs = rs;
6339*77c1e3ccSAndroid Build Coastguard Worker           best_filter = mbmi->interp_filters.as_filters.y_filter;
6340*77c1e3ccSAndroid Build Coastguard Worker         }
6341*77c1e3ccSAndroid Build Coastguard Worker       }
6342*77c1e3ccSAndroid Build Coastguard Worker     }
6343*77c1e3ccSAndroid Build Coastguard Worker   }
6344*77c1e3ccSAndroid Build Coastguard Worker   // Set the appropriate filter
6345*77c1e3ccSAndroid Build Coastguard Worker   mbmi->interp_filters = av1_broadcast_interp_filter(best_filter);
6346*77c1e3ccSAndroid Build Coastguard Worker   rate2 += av1_get_switchable_rate(x, xd, interp_filter,
6347*77c1e3ccSAndroid Build Coastguard Worker                                    cm->seq_params->enable_dual_filter);
6348*77c1e3ccSAndroid Build Coastguard Worker 
6349*77c1e3ccSAndroid Build Coastguard Worker   if (cm->current_frame.reference_mode == REFERENCE_MODE_SELECT)
6350*77c1e3ccSAndroid Build Coastguard Worker     rate2 += comp_inter_cost[comp_pred];
6351*77c1e3ccSAndroid Build Coastguard Worker 
6352*77c1e3ccSAndroid Build Coastguard Worker   // Estimate the reference frame signaling cost and add it
6353*77c1e3ccSAndroid Build Coastguard Worker   // to the rolling cost variable.
6354*77c1e3ccSAndroid Build Coastguard Worker   rate2 += ref_costs_single[LAST_FRAME];
6355*77c1e3ccSAndroid Build Coastguard Worker   this_rd = RDCOST(x->rdmult, rate2, distortion2);
6356*77c1e3ccSAndroid Build Coastguard Worker 
6357*77c1e3ccSAndroid Build Coastguard Worker   rd_cost->rate = rate2;
6358*77c1e3ccSAndroid Build Coastguard Worker   rd_cost->dist = distortion2;
6359*77c1e3ccSAndroid Build Coastguard Worker   rd_cost->rdcost = this_rd;
6360*77c1e3ccSAndroid Build Coastguard Worker 
6361*77c1e3ccSAndroid Build Coastguard Worker   if (this_rd >= best_rd_so_far) {
6362*77c1e3ccSAndroid Build Coastguard Worker     rd_cost->rate = INT_MAX;
6363*77c1e3ccSAndroid Build Coastguard Worker     rd_cost->rdcost = INT64_MAX;
6364*77c1e3ccSAndroid Build Coastguard Worker     return;
6365*77c1e3ccSAndroid Build Coastguard Worker   }
6366*77c1e3ccSAndroid Build Coastguard Worker 
6367*77c1e3ccSAndroid Build Coastguard Worker   assert((interp_filter == SWITCHABLE) ||
6368*77c1e3ccSAndroid Build Coastguard Worker          (interp_filter == mbmi->interp_filters.as_filters.y_filter));
6369*77c1e3ccSAndroid Build Coastguard Worker 
6370*77c1e3ccSAndroid Build Coastguard Worker   if (cpi->sf.inter_sf.adaptive_rd_thresh) {
6371*77c1e3ccSAndroid Build Coastguard Worker     av1_update_rd_thresh_fact(cm, x->thresh_freq_fact,
6372*77c1e3ccSAndroid Build Coastguard Worker                               cpi->sf.inter_sf.adaptive_rd_thresh, bsize,
6373*77c1e3ccSAndroid Build Coastguard Worker                               THR_GLOBALMV, THR_INTER_MODE_START,
6374*77c1e3ccSAndroid Build Coastguard Worker                               THR_INTER_MODE_END, THR_DC, MAX_MODES);
6375*77c1e3ccSAndroid Build Coastguard Worker   }
6376*77c1e3ccSAndroid Build Coastguard Worker 
6377*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_INTERNAL_STATS
6378*77c1e3ccSAndroid Build Coastguard Worker   store_coding_context(x, ctx, THR_GLOBALMV, 0);
6379*77c1e3ccSAndroid Build Coastguard Worker #else
6380*77c1e3ccSAndroid Build Coastguard Worker   store_coding_context(x, ctx, 0);
6381*77c1e3ccSAndroid Build Coastguard Worker #endif  // CONFIG_INTERNAL_STATS
6382*77c1e3ccSAndroid Build Coastguard Worker }
6383*77c1e3ccSAndroid Build Coastguard Worker 
6384*77c1e3ccSAndroid Build Coastguard Worker /*!\cond */
6385*77c1e3ccSAndroid Build Coastguard Worker struct calc_target_weighted_pred_ctxt {
6386*77c1e3ccSAndroid Build Coastguard Worker   const OBMCBuffer *obmc_buffer;
6387*77c1e3ccSAndroid Build Coastguard Worker   const uint8_t *tmp;
6388*77c1e3ccSAndroid Build Coastguard Worker   int tmp_stride;
6389*77c1e3ccSAndroid Build Coastguard Worker   int overlap;
6390*77c1e3ccSAndroid Build Coastguard Worker };
6391*77c1e3ccSAndroid Build Coastguard Worker /*!\endcond */
6392*77c1e3ccSAndroid Build Coastguard Worker 
calc_target_weighted_pred_above(MACROBLOCKD * xd,int rel_mi_row,int rel_mi_col,uint8_t op_mi_size,int dir,MB_MODE_INFO * nb_mi,void * fun_ctxt,const int num_planes)6393*77c1e3ccSAndroid Build Coastguard Worker static inline void calc_target_weighted_pred_above(
6394*77c1e3ccSAndroid Build Coastguard Worker     MACROBLOCKD *xd, int rel_mi_row, int rel_mi_col, uint8_t op_mi_size,
6395*77c1e3ccSAndroid Build Coastguard Worker     int dir, MB_MODE_INFO *nb_mi, void *fun_ctxt, const int num_planes) {
6396*77c1e3ccSAndroid Build Coastguard Worker   (void)nb_mi;
6397*77c1e3ccSAndroid Build Coastguard Worker   (void)num_planes;
6398*77c1e3ccSAndroid Build Coastguard Worker   (void)rel_mi_row;
6399*77c1e3ccSAndroid Build Coastguard Worker   (void)dir;
6400*77c1e3ccSAndroid Build Coastguard Worker 
6401*77c1e3ccSAndroid Build Coastguard Worker   struct calc_target_weighted_pred_ctxt *ctxt =
6402*77c1e3ccSAndroid Build Coastguard Worker       (struct calc_target_weighted_pred_ctxt *)fun_ctxt;
6403*77c1e3ccSAndroid Build Coastguard Worker 
6404*77c1e3ccSAndroid Build Coastguard Worker   const int bw = xd->width << MI_SIZE_LOG2;
6405*77c1e3ccSAndroid Build Coastguard Worker   const uint8_t *const mask1d = av1_get_obmc_mask(ctxt->overlap);
6406*77c1e3ccSAndroid Build Coastguard Worker 
6407*77c1e3ccSAndroid Build Coastguard Worker   int32_t *wsrc = ctxt->obmc_buffer->wsrc + (rel_mi_col * MI_SIZE);
6408*77c1e3ccSAndroid Build Coastguard Worker   int32_t *mask = ctxt->obmc_buffer->mask + (rel_mi_col * MI_SIZE);
6409*77c1e3ccSAndroid Build Coastguard Worker   const uint8_t *tmp = ctxt->tmp + rel_mi_col * MI_SIZE;
6410*77c1e3ccSAndroid Build Coastguard Worker   const int is_hbd = is_cur_buf_hbd(xd);
6411*77c1e3ccSAndroid Build Coastguard Worker 
6412*77c1e3ccSAndroid Build Coastguard Worker   if (!is_hbd) {
6413*77c1e3ccSAndroid Build Coastguard Worker     for (int row = 0; row < ctxt->overlap; ++row) {
6414*77c1e3ccSAndroid Build Coastguard Worker       const uint8_t m0 = mask1d[row];
6415*77c1e3ccSAndroid Build Coastguard Worker       const uint8_t m1 = AOM_BLEND_A64_MAX_ALPHA - m0;
6416*77c1e3ccSAndroid Build Coastguard Worker       for (int col = 0; col < op_mi_size * MI_SIZE; ++col) {
6417*77c1e3ccSAndroid Build Coastguard Worker         wsrc[col] = m1 * tmp[col];
6418*77c1e3ccSAndroid Build Coastguard Worker         mask[col] = m0;
6419*77c1e3ccSAndroid Build Coastguard Worker       }
6420*77c1e3ccSAndroid Build Coastguard Worker       wsrc += bw;
6421*77c1e3ccSAndroid Build Coastguard Worker       mask += bw;
6422*77c1e3ccSAndroid Build Coastguard Worker       tmp += ctxt->tmp_stride;
6423*77c1e3ccSAndroid Build Coastguard Worker     }
6424*77c1e3ccSAndroid Build Coastguard Worker   } else {
6425*77c1e3ccSAndroid Build Coastguard Worker     const uint16_t *tmp16 = CONVERT_TO_SHORTPTR(tmp);
6426*77c1e3ccSAndroid Build Coastguard Worker 
6427*77c1e3ccSAndroid Build Coastguard Worker     for (int row = 0; row < ctxt->overlap; ++row) {
6428*77c1e3ccSAndroid Build Coastguard Worker       const uint8_t m0 = mask1d[row];
6429*77c1e3ccSAndroid Build Coastguard Worker       const uint8_t m1 = AOM_BLEND_A64_MAX_ALPHA - m0;
6430*77c1e3ccSAndroid Build Coastguard Worker       for (int col = 0; col < op_mi_size * MI_SIZE; ++col) {
6431*77c1e3ccSAndroid Build Coastguard Worker         wsrc[col] = m1 * tmp16[col];
6432*77c1e3ccSAndroid Build Coastguard Worker         mask[col] = m0;
6433*77c1e3ccSAndroid Build Coastguard Worker       }
6434*77c1e3ccSAndroid Build Coastguard Worker       wsrc += bw;
6435*77c1e3ccSAndroid Build Coastguard Worker       mask += bw;
6436*77c1e3ccSAndroid Build Coastguard Worker       tmp16 += ctxt->tmp_stride;
6437*77c1e3ccSAndroid Build Coastguard Worker     }
6438*77c1e3ccSAndroid Build Coastguard Worker   }
6439*77c1e3ccSAndroid Build Coastguard Worker }
6440*77c1e3ccSAndroid Build Coastguard Worker 
calc_target_weighted_pred_left(MACROBLOCKD * xd,int rel_mi_row,int rel_mi_col,uint8_t op_mi_size,int dir,MB_MODE_INFO * nb_mi,void * fun_ctxt,const int num_planes)6441*77c1e3ccSAndroid Build Coastguard Worker static inline void calc_target_weighted_pred_left(
6442*77c1e3ccSAndroid Build Coastguard Worker     MACROBLOCKD *xd, int rel_mi_row, int rel_mi_col, uint8_t op_mi_size,
6443*77c1e3ccSAndroid Build Coastguard Worker     int dir, MB_MODE_INFO *nb_mi, void *fun_ctxt, const int num_planes) {
6444*77c1e3ccSAndroid Build Coastguard Worker   (void)nb_mi;
6445*77c1e3ccSAndroid Build Coastguard Worker   (void)num_planes;
6446*77c1e3ccSAndroid Build Coastguard Worker   (void)rel_mi_col;
6447*77c1e3ccSAndroid Build Coastguard Worker   (void)dir;
6448*77c1e3ccSAndroid Build Coastguard Worker 
6449*77c1e3ccSAndroid Build Coastguard Worker   struct calc_target_weighted_pred_ctxt *ctxt =
6450*77c1e3ccSAndroid Build Coastguard Worker       (struct calc_target_weighted_pred_ctxt *)fun_ctxt;
6451*77c1e3ccSAndroid Build Coastguard Worker 
6452*77c1e3ccSAndroid Build Coastguard Worker   const int bw = xd->width << MI_SIZE_LOG2;
6453*77c1e3ccSAndroid Build Coastguard Worker   const uint8_t *const mask1d = av1_get_obmc_mask(ctxt->overlap);
6454*77c1e3ccSAndroid Build Coastguard Worker 
6455*77c1e3ccSAndroid Build Coastguard Worker   int32_t *wsrc = ctxt->obmc_buffer->wsrc + (rel_mi_row * MI_SIZE * bw);
6456*77c1e3ccSAndroid Build Coastguard Worker   int32_t *mask = ctxt->obmc_buffer->mask + (rel_mi_row * MI_SIZE * bw);
6457*77c1e3ccSAndroid Build Coastguard Worker   const uint8_t *tmp = ctxt->tmp + (rel_mi_row * MI_SIZE * ctxt->tmp_stride);
6458*77c1e3ccSAndroid Build Coastguard Worker   const int is_hbd = is_cur_buf_hbd(xd);
6459*77c1e3ccSAndroid Build Coastguard Worker 
6460*77c1e3ccSAndroid Build Coastguard Worker   if (!is_hbd) {
6461*77c1e3ccSAndroid Build Coastguard Worker     for (int row = 0; row < op_mi_size * MI_SIZE; ++row) {
6462*77c1e3ccSAndroid Build Coastguard Worker       for (int col = 0; col < ctxt->overlap; ++col) {
6463*77c1e3ccSAndroid Build Coastguard Worker         const uint8_t m0 = mask1d[col];
6464*77c1e3ccSAndroid Build Coastguard Worker         const uint8_t m1 = AOM_BLEND_A64_MAX_ALPHA - m0;
6465*77c1e3ccSAndroid Build Coastguard Worker         wsrc[col] = (wsrc[col] >> AOM_BLEND_A64_ROUND_BITS) * m0 +
6466*77c1e3ccSAndroid Build Coastguard Worker                     (tmp[col] << AOM_BLEND_A64_ROUND_BITS) * m1;
6467*77c1e3ccSAndroid Build Coastguard Worker         mask[col] = (mask[col] >> AOM_BLEND_A64_ROUND_BITS) * m0;
6468*77c1e3ccSAndroid Build Coastguard Worker       }
6469*77c1e3ccSAndroid Build Coastguard Worker       wsrc += bw;
6470*77c1e3ccSAndroid Build Coastguard Worker       mask += bw;
6471*77c1e3ccSAndroid Build Coastguard Worker       tmp += ctxt->tmp_stride;
6472*77c1e3ccSAndroid Build Coastguard Worker     }
6473*77c1e3ccSAndroid Build Coastguard Worker   } else {
6474*77c1e3ccSAndroid Build Coastguard Worker     const uint16_t *tmp16 = CONVERT_TO_SHORTPTR(tmp);
6475*77c1e3ccSAndroid Build Coastguard Worker 
6476*77c1e3ccSAndroid Build Coastguard Worker     for (int row = 0; row < op_mi_size * MI_SIZE; ++row) {
6477*77c1e3ccSAndroid Build Coastguard Worker       for (int col = 0; col < ctxt->overlap; ++col) {
6478*77c1e3ccSAndroid Build Coastguard Worker         const uint8_t m0 = mask1d[col];
6479*77c1e3ccSAndroid Build Coastguard Worker         const uint8_t m1 = AOM_BLEND_A64_MAX_ALPHA - m0;
6480*77c1e3ccSAndroid Build Coastguard Worker         wsrc[col] = (wsrc[col] >> AOM_BLEND_A64_ROUND_BITS) * m0 +
6481*77c1e3ccSAndroid Build Coastguard Worker                     (tmp16[col] << AOM_BLEND_A64_ROUND_BITS) * m1;
6482*77c1e3ccSAndroid Build Coastguard Worker         mask[col] = (mask[col] >> AOM_BLEND_A64_ROUND_BITS) * m0;
6483*77c1e3ccSAndroid Build Coastguard Worker       }
6484*77c1e3ccSAndroid Build Coastguard Worker       wsrc += bw;
6485*77c1e3ccSAndroid Build Coastguard Worker       mask += bw;
6486*77c1e3ccSAndroid Build Coastguard Worker       tmp16 += ctxt->tmp_stride;
6487*77c1e3ccSAndroid Build Coastguard Worker     }
6488*77c1e3ccSAndroid Build Coastguard Worker   }
6489*77c1e3ccSAndroid Build Coastguard Worker }
6490*77c1e3ccSAndroid Build Coastguard Worker 
6491*77c1e3ccSAndroid Build Coastguard Worker // This function has a structure similar to av1_build_obmc_inter_prediction
6492*77c1e3ccSAndroid Build Coastguard Worker //
6493*77c1e3ccSAndroid Build Coastguard Worker // The OBMC predictor is computed as:
6494*77c1e3ccSAndroid Build Coastguard Worker //
6495*77c1e3ccSAndroid Build Coastguard Worker //  PObmc(x,y) =
6496*77c1e3ccSAndroid Build Coastguard Worker //    AOM_BLEND_A64(Mh(x),
6497*77c1e3ccSAndroid Build Coastguard Worker //                  AOM_BLEND_A64(Mv(y), P(x,y), PAbove(x,y)),
6498*77c1e3ccSAndroid Build Coastguard Worker //                  PLeft(x, y))
6499*77c1e3ccSAndroid Build Coastguard Worker //
6500*77c1e3ccSAndroid Build Coastguard Worker // Scaling up by AOM_BLEND_A64_MAX_ALPHA ** 2 and omitting the intermediate
6501*77c1e3ccSAndroid Build Coastguard Worker // rounding, this can be written as:
6502*77c1e3ccSAndroid Build Coastguard Worker //
6503*77c1e3ccSAndroid Build Coastguard Worker //  AOM_BLEND_A64_MAX_ALPHA * AOM_BLEND_A64_MAX_ALPHA * Pobmc(x,y) =
6504*77c1e3ccSAndroid Build Coastguard Worker //    Mh(x) * Mv(y) * P(x,y) +
6505*77c1e3ccSAndroid Build Coastguard Worker //      Mh(x) * Cv(y) * Pabove(x,y) +
6506*77c1e3ccSAndroid Build Coastguard Worker //      AOM_BLEND_A64_MAX_ALPHA * Ch(x) * PLeft(x, y)
6507*77c1e3ccSAndroid Build Coastguard Worker //
6508*77c1e3ccSAndroid Build Coastguard Worker // Where :
6509*77c1e3ccSAndroid Build Coastguard Worker //
6510*77c1e3ccSAndroid Build Coastguard Worker //  Cv(y) = AOM_BLEND_A64_MAX_ALPHA - Mv(y)
6511*77c1e3ccSAndroid Build Coastguard Worker //  Ch(y) = AOM_BLEND_A64_MAX_ALPHA - Mh(y)
6512*77c1e3ccSAndroid Build Coastguard Worker //
6513*77c1e3ccSAndroid Build Coastguard Worker // This function computes 'wsrc' and 'mask' as:
6514*77c1e3ccSAndroid Build Coastguard Worker //
6515*77c1e3ccSAndroid Build Coastguard Worker //  wsrc(x, y) =
6516*77c1e3ccSAndroid Build Coastguard Worker //    AOM_BLEND_A64_MAX_ALPHA * AOM_BLEND_A64_MAX_ALPHA * src(x, y) -
6517*77c1e3ccSAndroid Build Coastguard Worker //      Mh(x) * Cv(y) * Pabove(x,y) +
6518*77c1e3ccSAndroid Build Coastguard Worker //      AOM_BLEND_A64_MAX_ALPHA * Ch(x) * PLeft(x, y)
6519*77c1e3ccSAndroid Build Coastguard Worker //
6520*77c1e3ccSAndroid Build Coastguard Worker //  mask(x, y) = Mh(x) * Mv(y)
6521*77c1e3ccSAndroid Build Coastguard Worker //
6522*77c1e3ccSAndroid Build Coastguard Worker // These can then be used to efficiently approximate the error for any
6523*77c1e3ccSAndroid Build Coastguard Worker // predictor P in the context of the provided neighbouring predictors by
6524*77c1e3ccSAndroid Build Coastguard Worker // computing:
6525*77c1e3ccSAndroid Build Coastguard Worker //
6526*77c1e3ccSAndroid Build Coastguard Worker //  error(x, y) =
6527*77c1e3ccSAndroid Build Coastguard Worker //    wsrc(x, y) - mask(x, y) * P(x, y) / (AOM_BLEND_A64_MAX_ALPHA ** 2)
6528*77c1e3ccSAndroid Build Coastguard Worker //
calc_target_weighted_pred(const AV1_COMMON * cm,const MACROBLOCK * x,const MACROBLOCKD * xd,const uint8_t * above,int above_stride,const uint8_t * left,int left_stride)6529*77c1e3ccSAndroid Build Coastguard Worker static inline void calc_target_weighted_pred(
6530*77c1e3ccSAndroid Build Coastguard Worker     const AV1_COMMON *cm, const MACROBLOCK *x, const MACROBLOCKD *xd,
6531*77c1e3ccSAndroid Build Coastguard Worker     const uint8_t *above, int above_stride, const uint8_t *left,
6532*77c1e3ccSAndroid Build Coastguard Worker     int left_stride) {
6533*77c1e3ccSAndroid Build Coastguard Worker   const BLOCK_SIZE bsize = xd->mi[0]->bsize;
6534*77c1e3ccSAndroid Build Coastguard Worker   const int bw = xd->width << MI_SIZE_LOG2;
6535*77c1e3ccSAndroid Build Coastguard Worker   const int bh = xd->height << MI_SIZE_LOG2;
6536*77c1e3ccSAndroid Build Coastguard Worker   const OBMCBuffer *obmc_buffer = &x->obmc_buffer;
6537*77c1e3ccSAndroid Build Coastguard Worker   int32_t *mask_buf = obmc_buffer->mask;
6538*77c1e3ccSAndroid Build Coastguard Worker   int32_t *wsrc_buf = obmc_buffer->wsrc;
6539*77c1e3ccSAndroid Build Coastguard Worker 
6540*77c1e3ccSAndroid Build Coastguard Worker   const int is_hbd = is_cur_buf_hbd(xd);
6541*77c1e3ccSAndroid Build Coastguard Worker   const int src_scale = AOM_BLEND_A64_MAX_ALPHA * AOM_BLEND_A64_MAX_ALPHA;
6542*77c1e3ccSAndroid Build Coastguard Worker 
6543*77c1e3ccSAndroid Build Coastguard Worker   // plane 0 should not be sub-sampled
6544*77c1e3ccSAndroid Build Coastguard Worker   assert(xd->plane[0].subsampling_x == 0);
6545*77c1e3ccSAndroid Build Coastguard Worker   assert(xd->plane[0].subsampling_y == 0);
6546*77c1e3ccSAndroid Build Coastguard Worker 
6547*77c1e3ccSAndroid Build Coastguard Worker   av1_zero_array(wsrc_buf, bw * bh);
6548*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < bw * bh; ++i) mask_buf[i] = AOM_BLEND_A64_MAX_ALPHA;
6549*77c1e3ccSAndroid Build Coastguard Worker 
6550*77c1e3ccSAndroid Build Coastguard Worker   // handle above row
6551*77c1e3ccSAndroid Build Coastguard Worker   if (xd->up_available) {
6552*77c1e3ccSAndroid Build Coastguard Worker     const int overlap =
6553*77c1e3ccSAndroid Build Coastguard Worker         AOMMIN(block_size_high[bsize], block_size_high[BLOCK_64X64]) >> 1;
6554*77c1e3ccSAndroid Build Coastguard Worker     struct calc_target_weighted_pred_ctxt ctxt = { obmc_buffer, above,
6555*77c1e3ccSAndroid Build Coastguard Worker                                                    above_stride, overlap };
6556*77c1e3ccSAndroid Build Coastguard Worker     foreach_overlappable_nb_above(cm, (MACROBLOCKD *)xd,
6557*77c1e3ccSAndroid Build Coastguard Worker                                   max_neighbor_obmc[mi_size_wide_log2[bsize]],
6558*77c1e3ccSAndroid Build Coastguard Worker                                   calc_target_weighted_pred_above, &ctxt);
6559*77c1e3ccSAndroid Build Coastguard Worker   }
6560*77c1e3ccSAndroid Build Coastguard Worker 
6561*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < bw * bh; ++i) {
6562*77c1e3ccSAndroid Build Coastguard Worker     wsrc_buf[i] *= AOM_BLEND_A64_MAX_ALPHA;
6563*77c1e3ccSAndroid Build Coastguard Worker     mask_buf[i] *= AOM_BLEND_A64_MAX_ALPHA;
6564*77c1e3ccSAndroid Build Coastguard Worker   }
6565*77c1e3ccSAndroid Build Coastguard Worker 
6566*77c1e3ccSAndroid Build Coastguard Worker   // handle left column
6567*77c1e3ccSAndroid Build Coastguard Worker   if (xd->left_available) {
6568*77c1e3ccSAndroid Build Coastguard Worker     const int overlap =
6569*77c1e3ccSAndroid Build Coastguard Worker         AOMMIN(block_size_wide[bsize], block_size_wide[BLOCK_64X64]) >> 1;
6570*77c1e3ccSAndroid Build Coastguard Worker     struct calc_target_weighted_pred_ctxt ctxt = { obmc_buffer, left,
6571*77c1e3ccSAndroid Build Coastguard Worker                                                    left_stride, overlap };
6572*77c1e3ccSAndroid Build Coastguard Worker     foreach_overlappable_nb_left(cm, (MACROBLOCKD *)xd,
6573*77c1e3ccSAndroid Build Coastguard Worker                                  max_neighbor_obmc[mi_size_high_log2[bsize]],
6574*77c1e3ccSAndroid Build Coastguard Worker                                  calc_target_weighted_pred_left, &ctxt);
6575*77c1e3ccSAndroid Build Coastguard Worker   }
6576*77c1e3ccSAndroid Build Coastguard Worker 
6577*77c1e3ccSAndroid Build Coastguard Worker   if (!is_hbd) {
6578*77c1e3ccSAndroid Build Coastguard Worker     const uint8_t *src = x->plane[0].src.buf;
6579*77c1e3ccSAndroid Build Coastguard Worker 
6580*77c1e3ccSAndroid Build Coastguard Worker     for (int row = 0; row < bh; ++row) {
6581*77c1e3ccSAndroid Build Coastguard Worker       for (int col = 0; col < bw; ++col) {
6582*77c1e3ccSAndroid Build Coastguard Worker         wsrc_buf[col] = src[col] * src_scale - wsrc_buf[col];
6583*77c1e3ccSAndroid Build Coastguard Worker       }
6584*77c1e3ccSAndroid Build Coastguard Worker       wsrc_buf += bw;
6585*77c1e3ccSAndroid Build Coastguard Worker       src += x->plane[0].src.stride;
6586*77c1e3ccSAndroid Build Coastguard Worker     }
6587*77c1e3ccSAndroid Build Coastguard Worker   } else {
6588*77c1e3ccSAndroid Build Coastguard Worker     const uint16_t *src = CONVERT_TO_SHORTPTR(x->plane[0].src.buf);
6589*77c1e3ccSAndroid Build Coastguard Worker 
6590*77c1e3ccSAndroid Build Coastguard Worker     for (int row = 0; row < bh; ++row) {
6591*77c1e3ccSAndroid Build Coastguard Worker       for (int col = 0; col < bw; ++col) {
6592*77c1e3ccSAndroid Build Coastguard Worker         wsrc_buf[col] = src[col] * src_scale - wsrc_buf[col];
6593*77c1e3ccSAndroid Build Coastguard Worker       }
6594*77c1e3ccSAndroid Build Coastguard Worker       wsrc_buf += bw;
6595*77c1e3ccSAndroid Build Coastguard Worker       src += x->plane[0].src.stride;
6596*77c1e3ccSAndroid Build Coastguard Worker     }
6597*77c1e3ccSAndroid Build Coastguard Worker   }
6598*77c1e3ccSAndroid Build Coastguard Worker }
6599