xref: /aosp_15_r20/external/libaom/av1/encoder/rdopt_utils.h (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
1 /*
2  * Copyright (c) 2019, Alliance for Open Media. All rights reserved.
3  *
4  * This source code is subject to the terms of the BSD 2 Clause License and
5  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6  * was not distributed with this source code in the LICENSE file, you can
7  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8  * Media Patent License 1.0 was not distributed with this source code in the
9  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10  */
11 
12 #ifndef AOM_AV1_ENCODER_RDOPT_UTILS_H_
13 #define AOM_AV1_ENCODER_RDOPT_UTILS_H_
14 
15 #include "aom/aom_integer.h"
16 #include "av1/encoder/block.h"
17 #include "av1/common/cfl.h"
18 #include "av1/common/pred_common.h"
19 #include "av1/encoder/rdopt_data_defs.h"
20 
21 #ifdef __cplusplus
22 extern "C" {
23 #endif
24 
25 #define MAX_REF_MV_SEARCH 3
26 #define MAX_TX_RD_GATE_LEVEL 5
27 #define INTER_INTRA_RD_THRESH_SCALE 9
28 #define INTER_INTRA_RD_THRESH_SHIFT 4
29 
30 typedef struct {
31   PREDICTION_MODE mode;
32   MV_REFERENCE_FRAME ref_frame[2];
33 } MODE_DEFINITION;
34 
35 // This array defines the mapping from the enums in THR_MODES to the actual
36 // prediction modes and refrence frames
37 static const MODE_DEFINITION av1_mode_defs[MAX_MODES] = {
38   { NEARESTMV, { LAST_FRAME, NONE_FRAME } },
39   { NEARESTMV, { LAST2_FRAME, NONE_FRAME } },
40   { NEARESTMV, { LAST3_FRAME, NONE_FRAME } },
41   { NEARESTMV, { BWDREF_FRAME, NONE_FRAME } },
42   { NEARESTMV, { ALTREF2_FRAME, NONE_FRAME } },
43   { NEARESTMV, { ALTREF_FRAME, NONE_FRAME } },
44   { NEARESTMV, { GOLDEN_FRAME, NONE_FRAME } },
45 
46   { NEWMV, { LAST_FRAME, NONE_FRAME } },
47   { NEWMV, { LAST2_FRAME, NONE_FRAME } },
48   { NEWMV, { LAST3_FRAME, NONE_FRAME } },
49   { NEWMV, { BWDREF_FRAME, NONE_FRAME } },
50   { NEWMV, { ALTREF2_FRAME, NONE_FRAME } },
51   { NEWMV, { ALTREF_FRAME, NONE_FRAME } },
52   { NEWMV, { GOLDEN_FRAME, NONE_FRAME } },
53 
54   { NEARMV, { LAST_FRAME, NONE_FRAME } },
55   { NEARMV, { LAST2_FRAME, NONE_FRAME } },
56   { NEARMV, { LAST3_FRAME, NONE_FRAME } },
57   { NEARMV, { BWDREF_FRAME, NONE_FRAME } },
58   { NEARMV, { ALTREF2_FRAME, NONE_FRAME } },
59   { NEARMV, { ALTREF_FRAME, NONE_FRAME } },
60   { NEARMV, { GOLDEN_FRAME, NONE_FRAME } },
61 
62   { GLOBALMV, { LAST_FRAME, NONE_FRAME } },
63   { GLOBALMV, { LAST2_FRAME, NONE_FRAME } },
64   { GLOBALMV, { LAST3_FRAME, NONE_FRAME } },
65   { GLOBALMV, { BWDREF_FRAME, NONE_FRAME } },
66   { GLOBALMV, { ALTREF2_FRAME, NONE_FRAME } },
67   { GLOBALMV, { ALTREF_FRAME, NONE_FRAME } },
68   { GLOBALMV, { GOLDEN_FRAME, NONE_FRAME } },
69 
70   // TODO(zoeliu): May need to reconsider the order on the modes to check
71 
72   { NEAREST_NEARESTMV, { LAST_FRAME, ALTREF_FRAME } },
73   { NEAREST_NEARESTMV, { LAST2_FRAME, ALTREF_FRAME } },
74   { NEAREST_NEARESTMV, { LAST3_FRAME, ALTREF_FRAME } },
75   { NEAREST_NEARESTMV, { GOLDEN_FRAME, ALTREF_FRAME } },
76   { NEAREST_NEARESTMV, { LAST_FRAME, BWDREF_FRAME } },
77   { NEAREST_NEARESTMV, { LAST2_FRAME, BWDREF_FRAME } },
78   { NEAREST_NEARESTMV, { LAST3_FRAME, BWDREF_FRAME } },
79   { NEAREST_NEARESTMV, { GOLDEN_FRAME, BWDREF_FRAME } },
80   { NEAREST_NEARESTMV, { LAST_FRAME, ALTREF2_FRAME } },
81   { NEAREST_NEARESTMV, { LAST2_FRAME, ALTREF2_FRAME } },
82   { NEAREST_NEARESTMV, { LAST3_FRAME, ALTREF2_FRAME } },
83   { NEAREST_NEARESTMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
84 
85   { NEAREST_NEARESTMV, { LAST_FRAME, LAST2_FRAME } },
86   { NEAREST_NEARESTMV, { LAST_FRAME, LAST3_FRAME } },
87   { NEAREST_NEARESTMV, { LAST_FRAME, GOLDEN_FRAME } },
88   { NEAREST_NEARESTMV, { BWDREF_FRAME, ALTREF_FRAME } },
89 
90   { NEAR_NEARMV, { LAST_FRAME, BWDREF_FRAME } },
91   { NEW_NEWMV, { LAST_FRAME, BWDREF_FRAME } },
92   { NEW_NEARESTMV, { LAST_FRAME, BWDREF_FRAME } },
93   { NEAREST_NEWMV, { LAST_FRAME, BWDREF_FRAME } },
94   { NEW_NEARMV, { LAST_FRAME, BWDREF_FRAME } },
95   { NEAR_NEWMV, { LAST_FRAME, BWDREF_FRAME } },
96   { GLOBAL_GLOBALMV, { LAST_FRAME, BWDREF_FRAME } },
97 
98   { NEAR_NEARMV, { LAST_FRAME, ALTREF_FRAME } },
99   { NEW_NEWMV, { LAST_FRAME, ALTREF_FRAME } },
100   { NEW_NEARESTMV, { LAST_FRAME, ALTREF_FRAME } },
101   { NEAREST_NEWMV, { LAST_FRAME, ALTREF_FRAME } },
102   { NEW_NEARMV, { LAST_FRAME, ALTREF_FRAME } },
103   { NEAR_NEWMV, { LAST_FRAME, ALTREF_FRAME } },
104   { GLOBAL_GLOBALMV, { LAST_FRAME, ALTREF_FRAME } },
105 
106   { NEAR_NEARMV, { LAST2_FRAME, ALTREF_FRAME } },
107   { NEW_NEWMV, { LAST2_FRAME, ALTREF_FRAME } },
108   { NEW_NEARESTMV, { LAST2_FRAME, ALTREF_FRAME } },
109   { NEAREST_NEWMV, { LAST2_FRAME, ALTREF_FRAME } },
110   { NEW_NEARMV, { LAST2_FRAME, ALTREF_FRAME } },
111   { NEAR_NEWMV, { LAST2_FRAME, ALTREF_FRAME } },
112   { GLOBAL_GLOBALMV, { LAST2_FRAME, ALTREF_FRAME } },
113 
114   { NEAR_NEARMV, { LAST3_FRAME, ALTREF_FRAME } },
115   { NEW_NEWMV, { LAST3_FRAME, ALTREF_FRAME } },
116   { NEW_NEARESTMV, { LAST3_FRAME, ALTREF_FRAME } },
117   { NEAREST_NEWMV, { LAST3_FRAME, ALTREF_FRAME } },
118   { NEW_NEARMV, { LAST3_FRAME, ALTREF_FRAME } },
119   { NEAR_NEWMV, { LAST3_FRAME, ALTREF_FRAME } },
120   { GLOBAL_GLOBALMV, { LAST3_FRAME, ALTREF_FRAME } },
121 
122   { NEAR_NEARMV, { GOLDEN_FRAME, ALTREF_FRAME } },
123   { NEW_NEWMV, { GOLDEN_FRAME, ALTREF_FRAME } },
124   { NEW_NEARESTMV, { GOLDEN_FRAME, ALTREF_FRAME } },
125   { NEAREST_NEWMV, { GOLDEN_FRAME, ALTREF_FRAME } },
126   { NEW_NEARMV, { GOLDEN_FRAME, ALTREF_FRAME } },
127   { NEAR_NEWMV, { GOLDEN_FRAME, ALTREF_FRAME } },
128   { GLOBAL_GLOBALMV, { GOLDEN_FRAME, ALTREF_FRAME } },
129 
130   { NEAR_NEARMV, { LAST2_FRAME, BWDREF_FRAME } },
131   { NEW_NEWMV, { LAST2_FRAME, BWDREF_FRAME } },
132   { NEW_NEARESTMV, { LAST2_FRAME, BWDREF_FRAME } },
133   { NEAREST_NEWMV, { LAST2_FRAME, BWDREF_FRAME } },
134   { NEW_NEARMV, { LAST2_FRAME, BWDREF_FRAME } },
135   { NEAR_NEWMV, { LAST2_FRAME, BWDREF_FRAME } },
136   { GLOBAL_GLOBALMV, { LAST2_FRAME, BWDREF_FRAME } },
137 
138   { NEAR_NEARMV, { LAST3_FRAME, BWDREF_FRAME } },
139   { NEW_NEWMV, { LAST3_FRAME, BWDREF_FRAME } },
140   { NEW_NEARESTMV, { LAST3_FRAME, BWDREF_FRAME } },
141   { NEAREST_NEWMV, { LAST3_FRAME, BWDREF_FRAME } },
142   { NEW_NEARMV, { LAST3_FRAME, BWDREF_FRAME } },
143   { NEAR_NEWMV, { LAST3_FRAME, BWDREF_FRAME } },
144   { GLOBAL_GLOBALMV, { LAST3_FRAME, BWDREF_FRAME } },
145 
146   { NEAR_NEARMV, { GOLDEN_FRAME, BWDREF_FRAME } },
147   { NEW_NEWMV, { GOLDEN_FRAME, BWDREF_FRAME } },
148   { NEW_NEARESTMV, { GOLDEN_FRAME, BWDREF_FRAME } },
149   { NEAREST_NEWMV, { GOLDEN_FRAME, BWDREF_FRAME } },
150   { NEW_NEARMV, { GOLDEN_FRAME, BWDREF_FRAME } },
151   { NEAR_NEWMV, { GOLDEN_FRAME, BWDREF_FRAME } },
152   { GLOBAL_GLOBALMV, { GOLDEN_FRAME, BWDREF_FRAME } },
153 
154   { NEAR_NEARMV, { LAST_FRAME, ALTREF2_FRAME } },
155   { NEW_NEWMV, { LAST_FRAME, ALTREF2_FRAME } },
156   { NEW_NEARESTMV, { LAST_FRAME, ALTREF2_FRAME } },
157   { NEAREST_NEWMV, { LAST_FRAME, ALTREF2_FRAME } },
158   { NEW_NEARMV, { LAST_FRAME, ALTREF2_FRAME } },
159   { NEAR_NEWMV, { LAST_FRAME, ALTREF2_FRAME } },
160   { GLOBAL_GLOBALMV, { LAST_FRAME, ALTREF2_FRAME } },
161 
162   { NEAR_NEARMV, { LAST2_FRAME, ALTREF2_FRAME } },
163   { NEW_NEWMV, { LAST2_FRAME, ALTREF2_FRAME } },
164   { NEW_NEARESTMV, { LAST2_FRAME, ALTREF2_FRAME } },
165   { NEAREST_NEWMV, { LAST2_FRAME, ALTREF2_FRAME } },
166   { NEW_NEARMV, { LAST2_FRAME, ALTREF2_FRAME } },
167   { NEAR_NEWMV, { LAST2_FRAME, ALTREF2_FRAME } },
168   { GLOBAL_GLOBALMV, { LAST2_FRAME, ALTREF2_FRAME } },
169 
170   { NEAR_NEARMV, { LAST3_FRAME, ALTREF2_FRAME } },
171   { NEW_NEWMV, { LAST3_FRAME, ALTREF2_FRAME } },
172   { NEW_NEARESTMV, { LAST3_FRAME, ALTREF2_FRAME } },
173   { NEAREST_NEWMV, { LAST3_FRAME, ALTREF2_FRAME } },
174   { NEW_NEARMV, { LAST3_FRAME, ALTREF2_FRAME } },
175   { NEAR_NEWMV, { LAST3_FRAME, ALTREF2_FRAME } },
176   { GLOBAL_GLOBALMV, { LAST3_FRAME, ALTREF2_FRAME } },
177 
178   { NEAR_NEARMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
179   { NEW_NEWMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
180   { NEW_NEARESTMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
181   { NEAREST_NEWMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
182   { NEW_NEARMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
183   { NEAR_NEWMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
184   { GLOBAL_GLOBALMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
185 
186   { NEAR_NEARMV, { LAST_FRAME, LAST2_FRAME } },
187   { NEW_NEWMV, { LAST_FRAME, LAST2_FRAME } },
188   { NEW_NEARESTMV, { LAST_FRAME, LAST2_FRAME } },
189   { NEAREST_NEWMV, { LAST_FRAME, LAST2_FRAME } },
190   { NEW_NEARMV, { LAST_FRAME, LAST2_FRAME } },
191   { NEAR_NEWMV, { LAST_FRAME, LAST2_FRAME } },
192   { GLOBAL_GLOBALMV, { LAST_FRAME, LAST2_FRAME } },
193 
194   { NEAR_NEARMV, { LAST_FRAME, LAST3_FRAME } },
195   { NEW_NEWMV, { LAST_FRAME, LAST3_FRAME } },
196   { NEW_NEARESTMV, { LAST_FRAME, LAST3_FRAME } },
197   { NEAREST_NEWMV, { LAST_FRAME, LAST3_FRAME } },
198   { NEW_NEARMV, { LAST_FRAME, LAST3_FRAME } },
199   { NEAR_NEWMV, { LAST_FRAME, LAST3_FRAME } },
200   { GLOBAL_GLOBALMV, { LAST_FRAME, LAST3_FRAME } },
201 
202   { NEAR_NEARMV, { LAST_FRAME, GOLDEN_FRAME } },
203   { NEW_NEWMV, { LAST_FRAME, GOLDEN_FRAME } },
204   { NEW_NEARESTMV, { LAST_FRAME, GOLDEN_FRAME } },
205   { NEAREST_NEWMV, { LAST_FRAME, GOLDEN_FRAME } },
206   { NEW_NEARMV, { LAST_FRAME, GOLDEN_FRAME } },
207   { NEAR_NEWMV, { LAST_FRAME, GOLDEN_FRAME } },
208   { GLOBAL_GLOBALMV, { LAST_FRAME, GOLDEN_FRAME } },
209 
210   { NEAR_NEARMV, { BWDREF_FRAME, ALTREF_FRAME } },
211   { NEW_NEWMV, { BWDREF_FRAME, ALTREF_FRAME } },
212   { NEW_NEARESTMV, { BWDREF_FRAME, ALTREF_FRAME } },
213   { NEAREST_NEWMV, { BWDREF_FRAME, ALTREF_FRAME } },
214   { NEW_NEARMV, { BWDREF_FRAME, ALTREF_FRAME } },
215   { NEAR_NEWMV, { BWDREF_FRAME, ALTREF_FRAME } },
216   { GLOBAL_GLOBALMV, { BWDREF_FRAME, ALTREF_FRAME } },
217 
218   // intra modes
219   { DC_PRED, { INTRA_FRAME, NONE_FRAME } },
220   { PAETH_PRED, { INTRA_FRAME, NONE_FRAME } },
221   { SMOOTH_PRED, { INTRA_FRAME, NONE_FRAME } },
222   { SMOOTH_V_PRED, { INTRA_FRAME, NONE_FRAME } },
223   { SMOOTH_H_PRED, { INTRA_FRAME, NONE_FRAME } },
224   { H_PRED, { INTRA_FRAME, NONE_FRAME } },
225   { V_PRED, { INTRA_FRAME, NONE_FRAME } },
226   { D135_PRED, { INTRA_FRAME, NONE_FRAME } },
227   { D203_PRED, { INTRA_FRAME, NONE_FRAME } },
228   { D157_PRED, { INTRA_FRAME, NONE_FRAME } },
229   { D67_PRED, { INTRA_FRAME, NONE_FRAME } },
230   { D113_PRED, { INTRA_FRAME, NONE_FRAME } },
231   { D45_PRED, { INTRA_FRAME, NONE_FRAME } },
232 };
233 
234 // Number of winner modes allowed for different values of the speed feature
235 // multi_winner_mode_type.
236 static const int winner_mode_count_allowed[MULTI_WINNER_MODE_LEVELS] = {
237   1,  // MULTI_WINNER_MODE_OFF
238   2,  // MULTI_WINNER_MODE_FAST
239   3   // MULTI_WINNER_MODE_DEFAULT
240 };
241 
restore_dst_buf(MACROBLOCKD * xd,const BUFFER_SET dst,const int num_planes)242 static inline void restore_dst_buf(MACROBLOCKD *xd, const BUFFER_SET dst,
243                                    const int num_planes) {
244   for (int i = 0; i < num_planes; i++) {
245     xd->plane[i].dst.buf = dst.plane[i];
246     xd->plane[i].dst.stride = dst.stride[i];
247   }
248 }
249 
swap_dst_buf(MACROBLOCKD * xd,const BUFFER_SET * dst_bufs[2],int num_planes)250 static inline void swap_dst_buf(MACROBLOCKD *xd, const BUFFER_SET *dst_bufs[2],
251                                 int num_planes) {
252   const BUFFER_SET *buf0 = dst_bufs[0];
253   dst_bufs[0] = dst_bufs[1];
254   dst_bufs[1] = buf0;
255   restore_dst_buf(xd, *dst_bufs[0], num_planes);
256 }
257 
258 /* clang-format on */
259 // Calculate rd threshold based on ref best rd and relevant scaling factors
get_rd_thresh_from_best_rd(int64_t ref_best_rd,int mul_factor,int div_factor)260 static inline int64_t get_rd_thresh_from_best_rd(int64_t ref_best_rd,
261                                                  int mul_factor,
262                                                  int div_factor) {
263   int64_t rd_thresh = ref_best_rd;
264   if (div_factor != 0) {
265     rd_thresh = ref_best_rd < (div_factor * (INT64_MAX / mul_factor))
266                     ? ((ref_best_rd / div_factor) * mul_factor)
267                     : INT64_MAX;
268   }
269   return rd_thresh;
270 }
271 
get_prediction_mode_idx(PREDICTION_MODE this_mode,MV_REFERENCE_FRAME ref_frame,MV_REFERENCE_FRAME second_ref_frame)272 static inline THR_MODES get_prediction_mode_idx(
273     PREDICTION_MODE this_mode, MV_REFERENCE_FRAME ref_frame,
274     MV_REFERENCE_FRAME second_ref_frame) {
275   if (this_mode < INTRA_MODE_END) {
276     assert(ref_frame == INTRA_FRAME);
277     assert(second_ref_frame == NONE_FRAME);
278     return intra_to_mode_idx[this_mode - INTRA_MODE_START];
279   }
280   if (this_mode >= SINGLE_INTER_MODE_START &&
281       this_mode < SINGLE_INTER_MODE_END) {
282     assert((ref_frame > INTRA_FRAME) && (ref_frame <= ALTREF_FRAME));
283     return single_inter_to_mode_idx[this_mode - SINGLE_INTER_MODE_START]
284                                    [ref_frame];
285   }
286   if (this_mode >= COMP_INTER_MODE_START && this_mode < COMP_INTER_MODE_END &&
287       second_ref_frame != NONE_FRAME) {
288     assert((ref_frame > INTRA_FRAME) && (ref_frame <= ALTREF_FRAME));
289     assert((second_ref_frame > INTRA_FRAME) &&
290            (second_ref_frame <= ALTREF_FRAME));
291     return comp_inter_to_mode_idx[this_mode - COMP_INTER_MODE_START][ref_frame]
292                                  [second_ref_frame];
293   }
294   assert(0);
295   return THR_INVALID;
296 }
297 
inter_mode_data_block_idx(BLOCK_SIZE bsize)298 static inline int inter_mode_data_block_idx(BLOCK_SIZE bsize) {
299   if (bsize == BLOCK_4X4 || bsize == BLOCK_4X8 || bsize == BLOCK_8X4 ||
300       bsize == BLOCK_4X16 || bsize == BLOCK_16X4) {
301     return -1;
302   }
303   return 1;
304 }
305 
306 // Get transform block visible dimensions cropped to the MI units.
get_txb_dimensions(const MACROBLOCKD * xd,int plane,BLOCK_SIZE plane_bsize,int blk_row,int blk_col,BLOCK_SIZE tx_bsize,int * width,int * height,int * visible_width,int * visible_height)307 static inline void get_txb_dimensions(const MACROBLOCKD *xd, int plane,
308                                       BLOCK_SIZE plane_bsize, int blk_row,
309                                       int blk_col, BLOCK_SIZE tx_bsize,
310                                       int *width, int *height,
311                                       int *visible_width, int *visible_height) {
312   assert(tx_bsize <= plane_bsize);
313   const int txb_height = block_size_high[tx_bsize];
314   const int txb_width = block_size_wide[tx_bsize];
315   const struct macroblockd_plane *const pd = &xd->plane[plane];
316 
317   // TODO([email protected]): Investigate using crop_width/height here rather
318   // than the MI size
319   if (xd->mb_to_bottom_edge >= 0) {
320     *visible_height = txb_height;
321   } else {
322     const int block_height = block_size_high[plane_bsize];
323     const int block_rows =
324         (xd->mb_to_bottom_edge >> (3 + pd->subsampling_y)) + block_height;
325     *visible_height =
326         clamp(block_rows - (blk_row << MI_SIZE_LOG2), 0, txb_height);
327   }
328   if (height) *height = txb_height;
329 
330   if (xd->mb_to_right_edge >= 0) {
331     *visible_width = txb_width;
332   } else {
333     const int block_width = block_size_wide[plane_bsize];
334     const int block_cols =
335         (xd->mb_to_right_edge >> (3 + pd->subsampling_x)) + block_width;
336     *visible_width =
337         clamp(block_cols - (blk_col << MI_SIZE_LOG2), 0, txb_width);
338   }
339   if (width) *width = txb_width;
340 }
341 
bsize_to_num_blk(BLOCK_SIZE bsize)342 static inline int bsize_to_num_blk(BLOCK_SIZE bsize) {
343   int num_blk = 1 << (num_pels_log2_lookup[bsize] - 2 * MI_SIZE_LOG2);
344   return num_blk;
345 }
346 
check_txfm_eval(MACROBLOCK * const x,BLOCK_SIZE bsize,int64_t best_skip_rd,int64_t skip_rd,int level,int is_luma_only)347 static inline int check_txfm_eval(MACROBLOCK *const x, BLOCK_SIZE bsize,
348                                   int64_t best_skip_rd, int64_t skip_rd,
349                                   int level, int is_luma_only) {
350   int eval_txfm = 1;
351   // Derive aggressiveness factor for gating the transform search
352   // Lower value indicates more aggressiveness. Be more conservative (high
353   // value) for (i) low quantizers (ii) regions where prediction is poor
354   const int scale[MAX_TX_RD_GATE_LEVEL + 1] = { INT_MAX, 4, 3, 2, 2, 1 };
355   const int qslope = 2 * (!is_luma_only);
356   const int level_to_qindex_map[MAX_TX_RD_GATE_LEVEL + 1] = { 0,  0,   0,
357                                                               80, 100, 140 };
358   int aggr_factor = 4;
359   assert(level <= MAX_TX_RD_GATE_LEVEL);
360   const int pred_qindex_thresh = level_to_qindex_map[level];
361   if (!is_luma_only && level <= 2) {
362     aggr_factor = 4 * AOMMAX(1, ROUND_POWER_OF_TWO((MAXQ - x->qindex) * qslope,
363                                                    QINDEX_BITS));
364   }
365   if ((best_skip_rd >
366        (x->source_variance << (num_pels_log2_lookup[bsize] + RDDIV_BITS))) &&
367       (x->qindex >= pred_qindex_thresh))
368     aggr_factor *= scale[level];
369   // For level setting 1, be more conservative for non-luma-only case even when
370   // prediction is good.
371   else if ((level <= 1) && !is_luma_only)
372     aggr_factor = (aggr_factor >> 2) * 6;
373 
374   // Be more conservative for luma only cases (called from compound type rd)
375   // since best_skip_rd is computed after and skip_rd is computed (with 8-bit
376   // prediction signals blended for WEDGE/DIFFWTD rather than 16-bit) before
377   // interpolation filter search
378   const int luma_mul[MAX_TX_RD_GATE_LEVEL + 1] = {
379     INT_MAX, 32, 29, 17, 17, 17
380   };
381   int mul_factor = is_luma_only ? luma_mul[level] : 16;
382   int64_t rd_thresh =
383       (best_skip_rd == INT64_MAX)
384           ? best_skip_rd
385           : (int64_t)(best_skip_rd * aggr_factor * mul_factor >> 6);
386   if (skip_rd > rd_thresh) eval_txfm = 0;
387   return eval_txfm;
388 }
389 
select_tx_mode(const AV1_COMMON * cm,const TX_SIZE_SEARCH_METHOD tx_size_search_method)390 static TX_MODE select_tx_mode(
391     const AV1_COMMON *cm, const TX_SIZE_SEARCH_METHOD tx_size_search_method) {
392   if (cm->features.coded_lossless) return ONLY_4X4;
393   if (tx_size_search_method == USE_LARGESTALL) {
394     return TX_MODE_LARGEST;
395   } else {
396     assert(tx_size_search_method == USE_FULL_RD ||
397            tx_size_search_method == USE_FAST_RD);
398     return TX_MODE_SELECT;
399   }
400 }
401 
402 // Checks the conditions to disable winner mode processing
bypass_winner_mode_processing(const MACROBLOCK * const x,const SPEED_FEATURES * sf,int use_txfm_skip,int actual_txfm_skip,PREDICTION_MODE best_mode)403 static inline int bypass_winner_mode_processing(const MACROBLOCK *const x,
404                                                 const SPEED_FEATURES *sf,
405                                                 int use_txfm_skip,
406                                                 int actual_txfm_skip,
407                                                 PREDICTION_MODE best_mode) {
408   const int prune_winner_mode_eval_level =
409       sf->winner_mode_sf.prune_winner_mode_eval_level;
410 
411   // Disable winner mode processing for blocks with low source variance.
412   // The aggressiveness of this pruning logic reduces as qindex increases.
413   // The threshold decreases linearly from 64 as qindex varies from 0 to 255.
414   if (prune_winner_mode_eval_level == 1) {
415     const unsigned int src_var_thresh = 64 - 48 * x->qindex / (MAXQ + 1);
416     if (x->source_variance < src_var_thresh) return 1;
417   } else if (prune_winner_mode_eval_level == 2) {
418     // Skip winner mode processing of blocks for which transform turns out to be
419     // skip due to nature of eob alone except NEWMV mode.
420     if (!have_newmv_in_inter_mode(best_mode) && actual_txfm_skip) return 1;
421   } else if (prune_winner_mode_eval_level == 3) {
422     // Skip winner mode processing of blocks for which transform turns out to be
423     // skip except NEWMV mode and considered based on the quantizer.
424     // At high quantizers: Take conservative approach by considering transform
425     // skip based on eob alone.
426     // At low quantizers: Consider transform skip based on eob nature or RD cost
427     // evaluation.
428     const int is_txfm_skip =
429         x->qindex > 127 ? actual_txfm_skip : actual_txfm_skip || use_txfm_skip;
430 
431     if (!have_newmv_in_inter_mode(best_mode) && is_txfm_skip) return 1;
432   } else if (prune_winner_mode_eval_level >= 4) {
433     // Do not skip winner mode evaluation at low quantizers if normal mode's
434     // transform search was too aggressive.
435     if (sf->rd_sf.perform_coeff_opt >= 5 && x->qindex <= 70) return 0;
436 
437     if (use_txfm_skip || actual_txfm_skip) return 1;
438   }
439 
440   return 0;
441 }
442 
443 // Checks the conditions to enable winner mode processing
is_winner_mode_processing_enabled(const struct AV1_COMP * cpi,const MACROBLOCK * const x,MB_MODE_INFO * const mbmi,int actual_txfm_skip)444 static inline int is_winner_mode_processing_enabled(const struct AV1_COMP *cpi,
445                                                     const MACROBLOCK *const x,
446                                                     MB_MODE_INFO *const mbmi,
447                                                     int actual_txfm_skip) {
448   const SPEED_FEATURES *sf = &cpi->sf;
449   const PREDICTION_MODE best_mode = mbmi->mode;
450 
451   if (bypass_winner_mode_processing(x, sf, mbmi->skip_txfm, actual_txfm_skip,
452                                     best_mode))
453     return 0;
454 
455   // TODO(any): Move block independent condition checks to frame level
456   if (is_inter_block(mbmi)) {
457     if (is_inter_mode(best_mode) &&
458         (sf->tx_sf.tx_type_search.fast_inter_tx_type_prob_thresh != INT_MAX) &&
459         !cpi->oxcf.txfm_cfg.use_inter_dct_only)
460       return 1;
461   } else {
462     if (sf->tx_sf.tx_type_search.fast_intra_tx_type_search &&
463         !cpi->oxcf.txfm_cfg.use_intra_default_tx_only &&
464         !cpi->oxcf.txfm_cfg.use_intra_dct_only)
465       return 1;
466   }
467 
468   // Check speed feature related to winner mode processing
469   if (sf->winner_mode_sf.enable_winner_mode_for_coeff_opt &&
470       cpi->optimize_seg_arr[mbmi->segment_id] != NO_TRELLIS_OPT &&
471       cpi->optimize_seg_arr[mbmi->segment_id] != FINAL_PASS_TRELLIS_OPT)
472     return 1;
473   if (sf->winner_mode_sf.enable_winner_mode_for_tx_size_srch) return 1;
474 
475   return 0;
476 }
477 
set_tx_size_search_method(const AV1_COMMON * cm,const WinnerModeParams * winner_mode_params,TxfmSearchParams * txfm_params,int enable_winner_mode_for_tx_size_srch,int is_winner_mode)478 static inline void set_tx_size_search_method(
479     const AV1_COMMON *cm, const WinnerModeParams *winner_mode_params,
480     TxfmSearchParams *txfm_params, int enable_winner_mode_for_tx_size_srch,
481     int is_winner_mode) {
482   // Populate transform size search method/transform mode appropriately
483   txfm_params->tx_size_search_method =
484       winner_mode_params->tx_size_search_methods[DEFAULT_EVAL];
485   if (enable_winner_mode_for_tx_size_srch) {
486     if (is_winner_mode)
487       txfm_params->tx_size_search_method =
488           winner_mode_params->tx_size_search_methods[WINNER_MODE_EVAL];
489     else
490       txfm_params->tx_size_search_method =
491           winner_mode_params->tx_size_search_methods[MODE_EVAL];
492   }
493   txfm_params->tx_mode_search_type =
494       select_tx_mode(cm, txfm_params->tx_size_search_method);
495 }
496 
set_tx_type_prune(const SPEED_FEATURES * sf,TxfmSearchParams * txfm_params,int winner_mode_tx_type_pruning,int is_winner_mode)497 static inline void set_tx_type_prune(const SPEED_FEATURES *sf,
498                                      TxfmSearchParams *txfm_params,
499                                      int winner_mode_tx_type_pruning,
500                                      int is_winner_mode) {
501   // Populate prune transform mode appropriately
502   txfm_params->prune_2d_txfm_mode = sf->tx_sf.tx_type_search.prune_2d_txfm_mode;
503   if (!winner_mode_tx_type_pruning) return;
504 
505   const int prune_mode[4][2] = { { TX_TYPE_PRUNE_3, TX_TYPE_PRUNE_0 },
506                                  { TX_TYPE_PRUNE_4, TX_TYPE_PRUNE_0 },
507                                  { TX_TYPE_PRUNE_5, TX_TYPE_PRUNE_2 },
508                                  { TX_TYPE_PRUNE_5, TX_TYPE_PRUNE_3 } };
509   txfm_params->prune_2d_txfm_mode =
510       prune_mode[winner_mode_tx_type_pruning - 1][is_winner_mode];
511 }
512 
set_tx_domain_dist_params(const WinnerModeParams * winner_mode_params,TxfmSearchParams * txfm_params,int enable_winner_mode_for_tx_domain_dist,int is_winner_mode)513 static inline void set_tx_domain_dist_params(
514     const WinnerModeParams *winner_mode_params, TxfmSearchParams *txfm_params,
515     int enable_winner_mode_for_tx_domain_dist, int is_winner_mode) {
516   if (txfm_params->use_qm_dist_metric) {
517     // QM-weighted PSNR is computed in transform space, so we need to forcibly
518     // enable the use of tx domain distortion.
519     txfm_params->use_transform_domain_distortion = 1;
520     txfm_params->tx_domain_dist_threshold = 0;
521     return;
522   }
523 
524   if (!enable_winner_mode_for_tx_domain_dist) {
525     txfm_params->use_transform_domain_distortion =
526         winner_mode_params->use_transform_domain_distortion[DEFAULT_EVAL];
527     txfm_params->tx_domain_dist_threshold =
528         winner_mode_params->tx_domain_dist_threshold[DEFAULT_EVAL];
529     return;
530   }
531 
532   if (is_winner_mode) {
533     txfm_params->use_transform_domain_distortion =
534         winner_mode_params->use_transform_domain_distortion[WINNER_MODE_EVAL];
535     txfm_params->tx_domain_dist_threshold =
536         winner_mode_params->tx_domain_dist_threshold[WINNER_MODE_EVAL];
537   } else {
538     txfm_params->use_transform_domain_distortion =
539         winner_mode_params->use_transform_domain_distortion[MODE_EVAL];
540     txfm_params->tx_domain_dist_threshold =
541         winner_mode_params->tx_domain_dist_threshold[MODE_EVAL];
542   }
543 }
544 
545 // This function sets mode parameters for different mode evaluation stages
set_mode_eval_params(const struct AV1_COMP * cpi,MACROBLOCK * x,MODE_EVAL_TYPE mode_eval_type)546 static inline void set_mode_eval_params(const struct AV1_COMP *cpi,
547                                         MACROBLOCK *x,
548                                         MODE_EVAL_TYPE mode_eval_type) {
549   const AV1_COMMON *cm = &cpi->common;
550   const SPEED_FEATURES *sf = &cpi->sf;
551   const WinnerModeParams *winner_mode_params = &cpi->winner_mode_params;
552   TxfmSearchParams *txfm_params = &x->txfm_search_params;
553 
554   txfm_params->use_qm_dist_metric =
555       cpi->oxcf.tune_cfg.dist_metric == AOM_DIST_METRIC_QM_PSNR;
556 
557   switch (mode_eval_type) {
558     case DEFAULT_EVAL:
559       txfm_params->default_inter_tx_type_prob_thresh = INT_MAX;
560       txfm_params->use_default_intra_tx_type = 0;
561       txfm_params->skip_txfm_level =
562           winner_mode_params->skip_txfm_level[DEFAULT_EVAL];
563       txfm_params->predict_dc_level =
564           winner_mode_params->predict_dc_level[DEFAULT_EVAL];
565       // Set default transform domain distortion type
566       set_tx_domain_dist_params(winner_mode_params, txfm_params, 0, 0);
567 
568       // Get default threshold for R-D optimization of coefficients
569       get_rd_opt_coeff_thresh(winner_mode_params->coeff_opt_thresholds,
570                               txfm_params, 0, 0);
571 
572       // Set default transform size search method
573       set_tx_size_search_method(cm, winner_mode_params, txfm_params, 0, 0);
574       // Set default transform type prune
575       set_tx_type_prune(sf, txfm_params, 0, 0);
576       break;
577     case MODE_EVAL:
578       txfm_params->use_default_intra_tx_type =
579           (cpi->sf.tx_sf.tx_type_search.fast_intra_tx_type_search ||
580            cpi->oxcf.txfm_cfg.use_intra_default_tx_only);
581       txfm_params->default_inter_tx_type_prob_thresh =
582           cpi->sf.tx_sf.tx_type_search.fast_inter_tx_type_prob_thresh;
583       txfm_params->skip_txfm_level =
584           winner_mode_params->skip_txfm_level[MODE_EVAL];
585       txfm_params->predict_dc_level =
586           winner_mode_params->predict_dc_level[MODE_EVAL];
587       // Set transform domain distortion type for mode evaluation
588       set_tx_domain_dist_params(
589           winner_mode_params, txfm_params,
590           sf->winner_mode_sf.enable_winner_mode_for_use_tx_domain_dist, 0);
591 
592       // Get threshold for R-D optimization of coefficients during mode
593       // evaluation
594       get_rd_opt_coeff_thresh(
595           winner_mode_params->coeff_opt_thresholds, txfm_params,
596           sf->winner_mode_sf.enable_winner_mode_for_coeff_opt, 0);
597 
598       // Set the transform size search method for mode evaluation
599       set_tx_size_search_method(
600           cm, winner_mode_params, txfm_params,
601           sf->winner_mode_sf.enable_winner_mode_for_tx_size_srch, 0);
602       // Set transform type prune for mode evaluation
603       set_tx_type_prune(sf, txfm_params,
604                         sf->tx_sf.tx_type_search.winner_mode_tx_type_pruning,
605                         0);
606       break;
607     case WINNER_MODE_EVAL:
608       txfm_params->default_inter_tx_type_prob_thresh = INT_MAX;
609       txfm_params->use_default_intra_tx_type = 0;
610       txfm_params->skip_txfm_level =
611           winner_mode_params->skip_txfm_level[WINNER_MODE_EVAL];
612       txfm_params->predict_dc_level =
613           winner_mode_params->predict_dc_level[WINNER_MODE_EVAL];
614 
615       // Set transform domain distortion type for winner mode evaluation
616       set_tx_domain_dist_params(
617           winner_mode_params, txfm_params,
618           sf->winner_mode_sf.enable_winner_mode_for_use_tx_domain_dist, 1);
619 
620       // Get threshold for R-D optimization of coefficients for winner mode
621       // evaluation
622       get_rd_opt_coeff_thresh(
623           winner_mode_params->coeff_opt_thresholds, txfm_params,
624           sf->winner_mode_sf.enable_winner_mode_for_coeff_opt, 1);
625 
626       // Set the transform size search method for winner mode evaluation
627       set_tx_size_search_method(
628           cm, winner_mode_params, txfm_params,
629           sf->winner_mode_sf.enable_winner_mode_for_tx_size_srch, 1);
630       // Set default transform type prune mode for winner mode evaluation
631       set_tx_type_prune(sf, txfm_params,
632                         sf->tx_sf.tx_type_search.winner_mode_tx_type_pruning,
633                         1);
634       break;
635     default: assert(0);
636   }
637 
638   // Rd record collected at a specific mode evaluation stage can not be used
639   // across other evaluation stages as the transform parameters are different.
640   // Hence, reset mb rd record whenever mode evaluation stage type changes.
641   if (txfm_params->mode_eval_type != mode_eval_type)
642     reset_mb_rd_record(x->txfm_search_info.mb_rd_record);
643 
644   txfm_params->mode_eval_type = mode_eval_type;
645 }
646 
647 // Similar to store_cfl_required(), but for use during the RDO process,
648 // where we haven't yet determined whether this block uses CfL.
store_cfl_required_rdo(const AV1_COMMON * cm,const MACROBLOCK * x)649 static inline CFL_ALLOWED_TYPE store_cfl_required_rdo(const AV1_COMMON *cm,
650                                                       const MACROBLOCK *x) {
651   const MACROBLOCKD *xd = &x->e_mbd;
652 
653   if (cm->seq_params->monochrome || !xd->is_chroma_ref) return CFL_DISALLOWED;
654 
655   if (!xd->is_chroma_ref) {
656     // For non-chroma-reference blocks, we should always store the luma pixels,
657     // in case the corresponding chroma-reference block uses CfL.
658     // Note that this can only happen for block sizes which are <8 on
659     // their shortest side, as otherwise they would be chroma reference
660     // blocks.
661     return CFL_ALLOWED;
662   }
663 
664   // For chroma reference blocks, we should store data in the encoder iff we're
665   // allowed to try out CfL.
666   return is_cfl_allowed(xd);
667 }
668 
init_sbuv_mode(MB_MODE_INFO * const mbmi)669 static inline void init_sbuv_mode(MB_MODE_INFO *const mbmi) {
670   mbmi->uv_mode = UV_DC_PRED;
671   mbmi->palette_mode_info.palette_size[1] = 0;
672 }
673 
674 // Store best mode stats for winner mode processing
store_winner_mode_stats(const AV1_COMMON * const cm,MACROBLOCK * x,const MB_MODE_INFO * mbmi,RD_STATS * rd_cost,RD_STATS * rd_cost_y,RD_STATS * rd_cost_uv,THR_MODES mode_index,uint8_t * color_map,BLOCK_SIZE bsize,int64_t this_rd,int multi_winner_mode_type,int txfm_search_done)675 static inline void store_winner_mode_stats(
676     const AV1_COMMON *const cm, MACROBLOCK *x, const MB_MODE_INFO *mbmi,
677     RD_STATS *rd_cost, RD_STATS *rd_cost_y, RD_STATS *rd_cost_uv,
678     THR_MODES mode_index, uint8_t *color_map, BLOCK_SIZE bsize, int64_t this_rd,
679     int multi_winner_mode_type, int txfm_search_done) {
680   WinnerModeStats *winner_mode_stats = x->winner_mode_stats;
681   int mode_idx = 0;
682   int is_palette_mode = mbmi->palette_mode_info.palette_size[PLANE_TYPE_Y] > 0;
683   // Mode stat is not required when multiwinner mode processing is disabled
684   if (multi_winner_mode_type == MULTI_WINNER_MODE_OFF) return;
685   // Ignore mode with maximum rd
686   if (this_rd == INT64_MAX) return;
687   // TODO(any): Winner mode processing is currently not applicable for palette
688   // mode in Inter frames. Clean-up the following code, once support is added
689   if (!frame_is_intra_only(cm) && is_palette_mode) return;
690 
691   int max_winner_mode_count = winner_mode_count_allowed[multi_winner_mode_type];
692   assert(x->winner_mode_count >= 0 &&
693          x->winner_mode_count <= max_winner_mode_count);
694 
695   if (x->winner_mode_count) {
696     // Find the mode which has higher rd cost than this_rd
697     for (mode_idx = 0; mode_idx < x->winner_mode_count; mode_idx++)
698       if (winner_mode_stats[mode_idx].rd > this_rd) break;
699 
700     if (mode_idx == max_winner_mode_count) {
701       // No mode has higher rd cost than this_rd
702       return;
703     } else if (mode_idx < max_winner_mode_count - 1) {
704       // Create a slot for current mode and move others to the next slot
705       memmove(
706           &winner_mode_stats[mode_idx + 1], &winner_mode_stats[mode_idx],
707           (max_winner_mode_count - mode_idx - 1) * sizeof(*winner_mode_stats));
708     }
709   }
710   // Add a mode stat for winner mode processing
711   winner_mode_stats[mode_idx].mbmi = *mbmi;
712   winner_mode_stats[mode_idx].rd = this_rd;
713   winner_mode_stats[mode_idx].mode_index = mode_index;
714 
715   // Update rd stats required for inter frame
716   if (!frame_is_intra_only(cm) && rd_cost && rd_cost_y && rd_cost_uv) {
717     const MACROBLOCKD *xd = &x->e_mbd;
718     const int skip_ctx = av1_get_skip_txfm_context(xd);
719     const int is_intra_mode = av1_mode_defs[mode_index].mode < INTRA_MODE_END;
720     const int skip_txfm = mbmi->skip_txfm && !is_intra_mode;
721 
722     winner_mode_stats[mode_idx].rd_cost = *rd_cost;
723     if (txfm_search_done) {
724       winner_mode_stats[mode_idx].rate_y =
725           rd_cost_y->rate +
726           x->mode_costs
727               .skip_txfm_cost[skip_ctx][rd_cost->skip_txfm || skip_txfm];
728       winner_mode_stats[mode_idx].rate_uv = rd_cost_uv->rate;
729     }
730   }
731 
732   if (color_map) {
733     // Store color_index_map for palette mode
734     const MACROBLOCKD *const xd = &x->e_mbd;
735     int block_width, block_height;
736     av1_get_block_dimensions(bsize, AOM_PLANE_Y, xd, &block_width,
737                              &block_height, NULL, NULL);
738     memcpy(winner_mode_stats[mode_idx].color_index_map, color_map,
739            block_width * block_height * sizeof(color_map[0]));
740   }
741 
742   x->winner_mode_count =
743       AOMMIN(x->winner_mode_count + 1, max_winner_mode_count);
744 }
745 
746 unsigned int av1_get_perpixel_variance(const AV1_COMP *cpi,
747                                        const MACROBLOCKD *xd,
748                                        const struct buf_2d *ref,
749                                        BLOCK_SIZE bsize, int plane,
750                                        int use_hbd);
751 
752 unsigned int av1_get_perpixel_variance_facade(const struct AV1_COMP *cpi,
753                                               const MACROBLOCKD *xd,
754                                               const struct buf_2d *ref,
755                                               BLOCK_SIZE bsize, int plane);
756 
is_mode_intra(PREDICTION_MODE mode)757 static inline int is_mode_intra(PREDICTION_MODE mode) {
758   return mode < INTRA_MODE_END;
759 }
760 
761 // This function will copy usable ref_mv_stack[ref_frame][4] and
762 // weight[ref_frame][4] information from ref_mv_stack[ref_frame][8] and
763 // weight[ref_frame][8].
av1_copy_usable_ref_mv_stack_and_weight(const MACROBLOCKD * xd,MB_MODE_INFO_EXT * const mbmi_ext,MV_REFERENCE_FRAME ref_frame)764 static inline void av1_copy_usable_ref_mv_stack_and_weight(
765     const MACROBLOCKD *xd, MB_MODE_INFO_EXT *const mbmi_ext,
766     MV_REFERENCE_FRAME ref_frame) {
767   memcpy(mbmi_ext->weight[ref_frame], xd->weight[ref_frame],
768          USABLE_REF_MV_STACK_SIZE * sizeof(xd->weight[0][0]));
769   memcpy(mbmi_ext->ref_mv_stack[ref_frame], xd->ref_mv_stack[ref_frame],
770          USABLE_REF_MV_STACK_SIZE * sizeof(xd->ref_mv_stack[0][0]));
771 }
772 
773 // Get transform rd gate level for the given transform search case.
get_txfm_rd_gate_level(const int is_masked_compound_enabled,const int txfm_rd_gate_level[TX_SEARCH_CASES],BLOCK_SIZE bsize,TX_SEARCH_CASE tx_search_case,int eval_motion_mode)774 static inline int get_txfm_rd_gate_level(
775     const int is_masked_compound_enabled,
776     const int txfm_rd_gate_level[TX_SEARCH_CASES], BLOCK_SIZE bsize,
777     TX_SEARCH_CASE tx_search_case, int eval_motion_mode) {
778   assert(tx_search_case < TX_SEARCH_CASES);
779   if (tx_search_case == TX_SEARCH_MOTION_MODE && !eval_motion_mode &&
780       num_pels_log2_lookup[bsize] > 8)
781     return txfm_rd_gate_level[TX_SEARCH_MOTION_MODE];
782   // Enable aggressive gating of transform search only when masked compound type
783   // is enabled.
784   else if (tx_search_case == TX_SEARCH_COMP_TYPE_MODE &&
785            is_masked_compound_enabled)
786     return txfm_rd_gate_level[TX_SEARCH_COMP_TYPE_MODE];
787 
788   return txfm_rd_gate_level[TX_SEARCH_DEFAULT];
789 }
790 
791 #ifdef __cplusplus
792 }  // extern "C"
793 #endif
794 
795 #endif  // AOM_AV1_ENCODER_RDOPT_UTILS_H_
796