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 INTER_INTRA_RD_THRESH_SCALE 9
27 #define INTER_INTRA_RD_THRESH_SHIFT 4
28 
29 typedef struct {
30   PREDICTION_MODE mode;
31   MV_REFERENCE_FRAME ref_frame[2];
32 } MODE_DEFINITION;
33 
34 // This array defines the mapping from the enums in THR_MODES to the actual
35 // prediction modes and refrence frames
36 static const MODE_DEFINITION av1_mode_defs[MAX_MODES] = {
37   { NEARESTMV, { LAST_FRAME, NONE_FRAME } },
38   { NEARESTMV, { LAST2_FRAME, NONE_FRAME } },
39   { NEARESTMV, { LAST3_FRAME, NONE_FRAME } },
40   { NEARESTMV, { BWDREF_FRAME, NONE_FRAME } },
41   { NEARESTMV, { ALTREF2_FRAME, NONE_FRAME } },
42   { NEARESTMV, { ALTREF_FRAME, NONE_FRAME } },
43   { NEARESTMV, { GOLDEN_FRAME, NONE_FRAME } },
44 
45   { NEWMV, { LAST_FRAME, NONE_FRAME } },
46   { NEWMV, { LAST2_FRAME, NONE_FRAME } },
47   { NEWMV, { LAST3_FRAME, NONE_FRAME } },
48   { NEWMV, { BWDREF_FRAME, NONE_FRAME } },
49   { NEWMV, { ALTREF2_FRAME, NONE_FRAME } },
50   { NEWMV, { ALTREF_FRAME, NONE_FRAME } },
51   { NEWMV, { GOLDEN_FRAME, NONE_FRAME } },
52 
53   { NEARMV, { LAST_FRAME, NONE_FRAME } },
54   { NEARMV, { LAST2_FRAME, NONE_FRAME } },
55   { NEARMV, { LAST3_FRAME, NONE_FRAME } },
56   { NEARMV, { BWDREF_FRAME, NONE_FRAME } },
57   { NEARMV, { ALTREF2_FRAME, NONE_FRAME } },
58   { NEARMV, { ALTREF_FRAME, NONE_FRAME } },
59   { NEARMV, { GOLDEN_FRAME, NONE_FRAME } },
60 
61   { GLOBALMV, { LAST_FRAME, NONE_FRAME } },
62   { GLOBALMV, { LAST2_FRAME, NONE_FRAME } },
63   { GLOBALMV, { LAST3_FRAME, NONE_FRAME } },
64   { GLOBALMV, { BWDREF_FRAME, NONE_FRAME } },
65   { GLOBALMV, { ALTREF2_FRAME, NONE_FRAME } },
66   { GLOBALMV, { ALTREF_FRAME, NONE_FRAME } },
67   { GLOBALMV, { GOLDEN_FRAME, NONE_FRAME } },
68 
69   // TODO(zoeliu): May need to reconsider the order on the modes to check
70 
71   { NEAREST_NEARESTMV, { LAST_FRAME, ALTREF_FRAME } },
72   { NEAREST_NEARESTMV, { LAST2_FRAME, ALTREF_FRAME } },
73   { NEAREST_NEARESTMV, { LAST3_FRAME, ALTREF_FRAME } },
74   { NEAREST_NEARESTMV, { GOLDEN_FRAME, ALTREF_FRAME } },
75   { NEAREST_NEARESTMV, { LAST_FRAME, BWDREF_FRAME } },
76   { NEAREST_NEARESTMV, { LAST2_FRAME, BWDREF_FRAME } },
77   { NEAREST_NEARESTMV, { LAST3_FRAME, BWDREF_FRAME } },
78   { NEAREST_NEARESTMV, { GOLDEN_FRAME, BWDREF_FRAME } },
79   { NEAREST_NEARESTMV, { LAST_FRAME, ALTREF2_FRAME } },
80   { NEAREST_NEARESTMV, { LAST2_FRAME, ALTREF2_FRAME } },
81   { NEAREST_NEARESTMV, { LAST3_FRAME, ALTREF2_FRAME } },
82   { NEAREST_NEARESTMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
83 
84   { NEAREST_NEARESTMV, { LAST_FRAME, LAST2_FRAME } },
85   { NEAREST_NEARESTMV, { LAST_FRAME, LAST3_FRAME } },
86   { NEAREST_NEARESTMV, { LAST_FRAME, GOLDEN_FRAME } },
87   { NEAREST_NEARESTMV, { BWDREF_FRAME, ALTREF_FRAME } },
88 
89   { NEAR_NEARMV, { LAST_FRAME, ALTREF_FRAME } },
90   { NEW_NEARESTMV, { LAST_FRAME, ALTREF_FRAME } },
91   { NEAREST_NEWMV, { LAST_FRAME, ALTREF_FRAME } },
92   { NEW_NEARMV, { LAST_FRAME, ALTREF_FRAME } },
93   { NEAR_NEWMV, { LAST_FRAME, ALTREF_FRAME } },
94   { NEW_NEWMV, { LAST_FRAME, ALTREF_FRAME } },
95   { GLOBAL_GLOBALMV, { LAST_FRAME, ALTREF_FRAME } },
96 
97   { NEAR_NEARMV, { LAST2_FRAME, ALTREF_FRAME } },
98   { NEW_NEARESTMV, { LAST2_FRAME, ALTREF_FRAME } },
99   { NEAREST_NEWMV, { LAST2_FRAME, ALTREF_FRAME } },
100   { NEW_NEARMV, { LAST2_FRAME, ALTREF_FRAME } },
101   { NEAR_NEWMV, { LAST2_FRAME, ALTREF_FRAME } },
102   { NEW_NEWMV, { LAST2_FRAME, ALTREF_FRAME } },
103   { GLOBAL_GLOBALMV, { LAST2_FRAME, ALTREF_FRAME } },
104 
105   { NEAR_NEARMV, { LAST3_FRAME, ALTREF_FRAME } },
106   { NEW_NEARESTMV, { LAST3_FRAME, ALTREF_FRAME } },
107   { NEAREST_NEWMV, { LAST3_FRAME, ALTREF_FRAME } },
108   { NEW_NEARMV, { LAST3_FRAME, ALTREF_FRAME } },
109   { NEAR_NEWMV, { LAST3_FRAME, ALTREF_FRAME } },
110   { NEW_NEWMV, { LAST3_FRAME, ALTREF_FRAME } },
111   { GLOBAL_GLOBALMV, { LAST3_FRAME, ALTREF_FRAME } },
112 
113   { NEAR_NEARMV, { GOLDEN_FRAME, ALTREF_FRAME } },
114   { NEW_NEARESTMV, { GOLDEN_FRAME, ALTREF_FRAME } },
115   { NEAREST_NEWMV, { GOLDEN_FRAME, ALTREF_FRAME } },
116   { NEW_NEARMV, { GOLDEN_FRAME, ALTREF_FRAME } },
117   { NEAR_NEWMV, { GOLDEN_FRAME, ALTREF_FRAME } },
118   { NEW_NEWMV, { GOLDEN_FRAME, ALTREF_FRAME } },
119   { GLOBAL_GLOBALMV, { GOLDEN_FRAME, ALTREF_FRAME } },
120 
121   { NEAR_NEARMV, { LAST_FRAME, BWDREF_FRAME } },
122   { NEW_NEARESTMV, { LAST_FRAME, BWDREF_FRAME } },
123   { NEAREST_NEWMV, { LAST_FRAME, BWDREF_FRAME } },
124   { NEW_NEARMV, { LAST_FRAME, BWDREF_FRAME } },
125   { NEAR_NEWMV, { LAST_FRAME, BWDREF_FRAME } },
126   { NEW_NEWMV, { LAST_FRAME, BWDREF_FRAME } },
127   { GLOBAL_GLOBALMV, { LAST_FRAME, BWDREF_FRAME } },
128 
129   { NEAR_NEARMV, { LAST2_FRAME, BWDREF_FRAME } },
130   { NEW_NEARESTMV, { LAST2_FRAME, BWDREF_FRAME } },
131   { NEAREST_NEWMV, { LAST2_FRAME, BWDREF_FRAME } },
132   { NEW_NEARMV, { LAST2_FRAME, BWDREF_FRAME } },
133   { NEAR_NEWMV, { LAST2_FRAME, BWDREF_FRAME } },
134   { NEW_NEWMV, { LAST2_FRAME, BWDREF_FRAME } },
135   { GLOBAL_GLOBALMV, { LAST2_FRAME, BWDREF_FRAME } },
136 
137   { NEAR_NEARMV, { LAST3_FRAME, BWDREF_FRAME } },
138   { NEW_NEARESTMV, { LAST3_FRAME, BWDREF_FRAME } },
139   { NEAREST_NEWMV, { LAST3_FRAME, BWDREF_FRAME } },
140   { NEW_NEARMV, { LAST3_FRAME, BWDREF_FRAME } },
141   { NEAR_NEWMV, { LAST3_FRAME, BWDREF_FRAME } },
142   { NEW_NEWMV, { LAST3_FRAME, BWDREF_FRAME } },
143   { GLOBAL_GLOBALMV, { LAST3_FRAME, BWDREF_FRAME } },
144 
145   { NEAR_NEARMV, { GOLDEN_FRAME, BWDREF_FRAME } },
146   { NEW_NEARESTMV, { GOLDEN_FRAME, BWDREF_FRAME } },
147   { NEAREST_NEWMV, { GOLDEN_FRAME, BWDREF_FRAME } },
148   { NEW_NEARMV, { GOLDEN_FRAME, BWDREF_FRAME } },
149   { NEAR_NEWMV, { GOLDEN_FRAME, BWDREF_FRAME } },
150   { NEW_NEWMV, { GOLDEN_FRAME, BWDREF_FRAME } },
151   { GLOBAL_GLOBALMV, { GOLDEN_FRAME, BWDREF_FRAME } },
152 
153   { NEAR_NEARMV, { LAST_FRAME, ALTREF2_FRAME } },
154   { NEW_NEARESTMV, { LAST_FRAME, ALTREF2_FRAME } },
155   { NEAREST_NEWMV, { LAST_FRAME, ALTREF2_FRAME } },
156   { NEW_NEARMV, { LAST_FRAME, ALTREF2_FRAME } },
157   { NEAR_NEWMV, { LAST_FRAME, ALTREF2_FRAME } },
158   { NEW_NEWMV, { LAST_FRAME, ALTREF2_FRAME } },
159   { GLOBAL_GLOBALMV, { LAST_FRAME, ALTREF2_FRAME } },
160 
161   { NEAR_NEARMV, { LAST2_FRAME, ALTREF2_FRAME } },
162   { NEW_NEARESTMV, { LAST2_FRAME, ALTREF2_FRAME } },
163   { NEAREST_NEWMV, { LAST2_FRAME, ALTREF2_FRAME } },
164   { NEW_NEARMV, { LAST2_FRAME, ALTREF2_FRAME } },
165   { NEAR_NEWMV, { LAST2_FRAME, ALTREF2_FRAME } },
166   { NEW_NEWMV, { LAST2_FRAME, ALTREF2_FRAME } },
167   { GLOBAL_GLOBALMV, { LAST2_FRAME, ALTREF2_FRAME } },
168 
169   { NEAR_NEARMV, { LAST3_FRAME, ALTREF2_FRAME } },
170   { NEW_NEARESTMV, { LAST3_FRAME, ALTREF2_FRAME } },
171   { NEAREST_NEWMV, { LAST3_FRAME, ALTREF2_FRAME } },
172   { NEW_NEARMV, { LAST3_FRAME, ALTREF2_FRAME } },
173   { NEAR_NEWMV, { LAST3_FRAME, ALTREF2_FRAME } },
174   { NEW_NEWMV, { LAST3_FRAME, ALTREF2_FRAME } },
175   { GLOBAL_GLOBALMV, { LAST3_FRAME, ALTREF2_FRAME } },
176 
177   { NEAR_NEARMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
178   { NEW_NEARESTMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
179   { NEAREST_NEWMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
180   { NEW_NEARMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
181   { NEAR_NEWMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
182   { NEW_NEWMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
183   { GLOBAL_GLOBALMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
184 
185   { NEAR_NEARMV, { LAST_FRAME, LAST2_FRAME } },
186   { NEW_NEARESTMV, { LAST_FRAME, LAST2_FRAME } },
187   { NEAREST_NEWMV, { LAST_FRAME, LAST2_FRAME } },
188   { NEW_NEARMV, { LAST_FRAME, LAST2_FRAME } },
189   { NEAR_NEWMV, { LAST_FRAME, LAST2_FRAME } },
190   { NEW_NEWMV, { LAST_FRAME, LAST2_FRAME } },
191   { GLOBAL_GLOBALMV, { LAST_FRAME, LAST2_FRAME } },
192 
193   { NEAR_NEARMV, { LAST_FRAME, LAST3_FRAME } },
194   { NEW_NEARESTMV, { LAST_FRAME, LAST3_FRAME } },
195   { NEAREST_NEWMV, { LAST_FRAME, LAST3_FRAME } },
196   { NEW_NEARMV, { LAST_FRAME, LAST3_FRAME } },
197   { NEAR_NEWMV, { LAST_FRAME, LAST3_FRAME } },
198   { NEW_NEWMV, { LAST_FRAME, LAST3_FRAME } },
199   { GLOBAL_GLOBALMV, { LAST_FRAME, LAST3_FRAME } },
200 
201   { NEAR_NEARMV, { LAST_FRAME, GOLDEN_FRAME } },
202   { NEW_NEARESTMV, { LAST_FRAME, GOLDEN_FRAME } },
203   { NEAREST_NEWMV, { LAST_FRAME, GOLDEN_FRAME } },
204   { NEW_NEARMV, { LAST_FRAME, GOLDEN_FRAME } },
205   { NEAR_NEWMV, { LAST_FRAME, GOLDEN_FRAME } },
206   { NEW_NEWMV, { LAST_FRAME, GOLDEN_FRAME } },
207   { GLOBAL_GLOBALMV, { LAST_FRAME, GOLDEN_FRAME } },
208 
209   { NEAR_NEARMV, { BWDREF_FRAME, ALTREF_FRAME } },
210   { NEW_NEARESTMV, { BWDREF_FRAME, ALTREF_FRAME } },
211   { NEAREST_NEWMV, { BWDREF_FRAME, ALTREF_FRAME } },
212   { NEW_NEARMV, { BWDREF_FRAME, ALTREF_FRAME } },
213   { NEAR_NEWMV, { BWDREF_FRAME, ALTREF_FRAME } },
214   { NEW_NEWMV, { BWDREF_FRAME, ALTREF_FRAME } },
215   { GLOBAL_GLOBALMV, { BWDREF_FRAME, ALTREF_FRAME } },
216 
217   // intra modes
218   { DC_PRED, { INTRA_FRAME, NONE_FRAME } },
219   { PAETH_PRED, { INTRA_FRAME, NONE_FRAME } },
220   { SMOOTH_PRED, { INTRA_FRAME, NONE_FRAME } },
221   { SMOOTH_V_PRED, { INTRA_FRAME, NONE_FRAME } },
222   { SMOOTH_H_PRED, { INTRA_FRAME, NONE_FRAME } },
223   { H_PRED, { INTRA_FRAME, NONE_FRAME } },
224   { V_PRED, { INTRA_FRAME, NONE_FRAME } },
225   { D135_PRED, { INTRA_FRAME, NONE_FRAME } },
226   { D203_PRED, { INTRA_FRAME, NONE_FRAME } },
227   { D157_PRED, { INTRA_FRAME, NONE_FRAME } },
228   { D67_PRED, { INTRA_FRAME, NONE_FRAME } },
229   { D113_PRED, { INTRA_FRAME, NONE_FRAME } },
230   { D45_PRED, { INTRA_FRAME, NONE_FRAME } },
231 };
232 
restore_dst_buf(MACROBLOCKD * xd,const BUFFER_SET dst,const int num_planes)233 static AOM_INLINE void restore_dst_buf(MACROBLOCKD *xd, const BUFFER_SET dst,
234                                        const int num_planes) {
235   for (int i = 0; i < num_planes; i++) {
236     xd->plane[i].dst.buf = dst.plane[i];
237     xd->plane[i].dst.stride = dst.stride[i];
238   }
239 }
240 
241 /* clang-format on */
242 // 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)243 static AOM_INLINE int64_t get_rd_thresh_from_best_rd(int64_t ref_best_rd,
244                                                      int mul_factor,
245                                                      int div_factor) {
246   int64_t rd_thresh = ref_best_rd;
247   if (div_factor != 0) {
248     rd_thresh = ref_best_rd < (div_factor * (INT64_MAX / mul_factor))
249                     ? ((ref_best_rd / div_factor) * mul_factor)
250                     : INT64_MAX;
251   }
252   return rd_thresh;
253 }
254 
255 static AOM_INLINE THR_MODES
get_prediction_mode_idx(PREDICTION_MODE this_mode,MV_REFERENCE_FRAME ref_frame,MV_REFERENCE_FRAME second_ref_frame)256 get_prediction_mode_idx(PREDICTION_MODE this_mode, MV_REFERENCE_FRAME ref_frame,
257                         MV_REFERENCE_FRAME second_ref_frame) {
258   if (this_mode < INTRA_MODE_END) {
259     assert(ref_frame == INTRA_FRAME);
260     assert(second_ref_frame == NONE_FRAME);
261     return intra_to_mode_idx[this_mode - INTRA_MODE_START];
262   }
263   if (this_mode >= SINGLE_INTER_MODE_START &&
264       this_mode < SINGLE_INTER_MODE_END) {
265     assert((ref_frame > INTRA_FRAME) && (ref_frame <= ALTREF_FRAME));
266     return single_inter_to_mode_idx[this_mode - SINGLE_INTER_MODE_START]
267                                    [ref_frame];
268   }
269   if (this_mode >= COMP_INTER_MODE_START && this_mode < COMP_INTER_MODE_END) {
270     assert((ref_frame > INTRA_FRAME) && (ref_frame <= ALTREF_FRAME));
271     assert((second_ref_frame > INTRA_FRAME) &&
272            (second_ref_frame <= ALTREF_FRAME));
273     return comp_inter_to_mode_idx[this_mode - COMP_INTER_MODE_START][ref_frame]
274                                  [second_ref_frame];
275   }
276   assert(0);
277   return THR_INVALID;
278 }
279 
inter_mode_data_block_idx(BLOCK_SIZE bsize)280 static AOM_INLINE int inter_mode_data_block_idx(BLOCK_SIZE bsize) {
281   if (bsize == BLOCK_4X4 || bsize == BLOCK_4X8 || bsize == BLOCK_8X4 ||
282       bsize == BLOCK_4X16 || bsize == BLOCK_16X4) {
283     return -1;
284   }
285   return 1;
286 }
287 
288 // 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)289 static AOM_INLINE void get_txb_dimensions(const MACROBLOCKD *xd, int plane,
290                                           BLOCK_SIZE plane_bsize, int blk_row,
291                                           int blk_col, BLOCK_SIZE tx_bsize,
292                                           int *width, int *height,
293                                           int *visible_width,
294                                           int *visible_height) {
295   assert(tx_bsize <= plane_bsize);
296   const int txb_height = block_size_high[tx_bsize];
297   const int txb_width = block_size_wide[tx_bsize];
298   const struct macroblockd_plane *const pd = &xd->plane[plane];
299 
300   // TODO(aconverse@google.com): Investigate using crop_width/height here rather
301   // than the MI size
302   if (xd->mb_to_bottom_edge >= 0) {
303     *visible_height = txb_height;
304   } else {
305     const int block_height = block_size_high[plane_bsize];
306     const int block_rows =
307         (xd->mb_to_bottom_edge >> (3 + pd->subsampling_y)) + block_height;
308     *visible_height =
309         clamp(block_rows - (blk_row << MI_SIZE_LOG2), 0, txb_height);
310   }
311   if (height) *height = txb_height;
312 
313   if (xd->mb_to_right_edge >= 0) {
314     *visible_width = txb_width;
315   } else {
316     const int block_width = block_size_wide[plane_bsize];
317     const int block_cols =
318         (xd->mb_to_right_edge >> (3 + pd->subsampling_x)) + block_width;
319     *visible_width =
320         clamp(block_cols - (blk_col << MI_SIZE_LOG2), 0, txb_width);
321   }
322   if (width) *width = txb_width;
323 }
324 
bsize_to_num_blk(BLOCK_SIZE bsize)325 static AOM_INLINE int bsize_to_num_blk(BLOCK_SIZE bsize) {
326   int num_blk = 1 << (num_pels_log2_lookup[bsize] - 2 * MI_SIZE_LOG2);
327   return num_blk;
328 }
329 
check_txfm_eval(MACROBLOCK * const x,BLOCK_SIZE bsize,int64_t best_skip_rd,int64_t skip_rd,int level,int is_luma_only)330 static INLINE int check_txfm_eval(MACROBLOCK *const x, BLOCK_SIZE bsize,
331                                   int64_t best_skip_rd, int64_t skip_rd,
332                                   int level, int is_luma_only) {
333   int eval_txfm = 1;
334   // Derive aggressiveness factor for gating the transform search
335   // Lower value indicates more aggressiveness. Be more conservative (high
336   // value) for (i) low quantizers (ii) regions where prediction is poor
337   const int scale[6] = { INT_MAX, 4, 3, 3, 2, 2 };
338   const int qslope = 2 * (!is_luma_only);
339   const int level_to_qindex_map[6] = { 0, 0, 0, 0, 80, 100 };
340   int aggr_factor = 1;
341   const int pred_qindex_thresh = level_to_qindex_map[level];
342   if (!is_luma_only && level <= 3) {
343     aggr_factor = AOMMAX(
344         1, ((MAXQ - x->qindex) * qslope + QINDEX_RANGE / 2) >> QINDEX_BITS);
345   }
346   if ((best_skip_rd >
347        (x->source_variance << (num_pels_log2_lookup[bsize] + RDDIV_BITS))) &&
348       (x->qindex >= pred_qindex_thresh))
349     aggr_factor *= scale[level];
350   // For level setting 1, be more conservative for non-luma-only case even when
351   // prediction is good.
352   else if ((level <= 1) && !is_luma_only)
353     aggr_factor *= 2;
354 
355   // Be more conservative for luma only cases (called from compound type rd)
356   // since best_skip_rd is computed after and skip_rd is computed (with 8-bit
357   // prediction signals blended for WEDGE/DIFFWTD rather than 16-bit) before
358   // interpolation filter search
359   const int luma_mul[6] = { INT_MAX, 32, 29, 20, 17, 17 };
360   int mul_factor = is_luma_only ? luma_mul[level] : 16;
361   int64_t rd_thresh =
362       (best_skip_rd == INT64_MAX)
363           ? best_skip_rd
364           : (int64_t)(best_skip_rd * aggr_factor * mul_factor >> 4);
365   if (skip_rd > rd_thresh) eval_txfm = 0;
366   return eval_txfm;
367 }
368 
select_tx_mode(const AV1_COMMON * cm,const TX_SIZE_SEARCH_METHOD tx_size_search_method)369 static TX_MODE select_tx_mode(
370     const AV1_COMMON *cm, const TX_SIZE_SEARCH_METHOD tx_size_search_method) {
371   if (cm->features.coded_lossless) return ONLY_4X4;
372   if (tx_size_search_method == USE_LARGESTALL) {
373     return TX_MODE_LARGEST;
374   } else {
375     assert(tx_size_search_method == USE_FULL_RD ||
376            tx_size_search_method == USE_FAST_RD);
377     return TX_MODE_SELECT;
378   }
379 }
380 // Checks the conditions to enable winner mode processing
is_winner_mode_processing_enabled(const struct AV1_COMP * cpi,MB_MODE_INFO * const mbmi,const PREDICTION_MODE best_mode)381 static INLINE int is_winner_mode_processing_enabled(
382     const struct AV1_COMP *cpi, MB_MODE_INFO *const mbmi,
383     const PREDICTION_MODE best_mode) {
384   const SPEED_FEATURES *sf = &cpi->sf;
385 
386   // TODO(any): Move block independent condition checks to frame level
387   if (is_inter_block(mbmi)) {
388     if (is_inter_mode(best_mode) &&
389         sf->tx_sf.tx_type_search.fast_inter_tx_type_search &&
390         !cpi->oxcf.txfm_cfg.use_inter_dct_only)
391       return 1;
392   } else {
393     if (sf->tx_sf.tx_type_search.fast_intra_tx_type_search &&
394         !cpi->oxcf.txfm_cfg.use_intra_default_tx_only &&
395         !cpi->oxcf.txfm_cfg.use_intra_dct_only)
396       return 1;
397   }
398 
399   // Check speed feature related to winner mode processing
400   if (sf->winner_mode_sf.enable_winner_mode_for_coeff_opt &&
401       cpi->optimize_seg_arr[mbmi->segment_id] != NO_TRELLIS_OPT &&
402       cpi->optimize_seg_arr[mbmi->segment_id] != FINAL_PASS_TRELLIS_OPT)
403     return 1;
404   if (sf->winner_mode_sf.enable_winner_mode_for_tx_size_srch) return 1;
405 
406   return 0;
407 }
408 
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)409 static INLINE void set_tx_size_search_method(
410     const AV1_COMMON *cm, const WinnerModeParams *winner_mode_params,
411     TxfmSearchParams *txfm_params, int enable_winner_mode_for_tx_size_srch,
412     int is_winner_mode) {
413   // Populate transform size search method/transform mode appropriately
414   txfm_params->tx_size_search_method =
415       winner_mode_params->tx_size_search_methods[DEFAULT_EVAL];
416   if (enable_winner_mode_for_tx_size_srch) {
417     if (is_winner_mode)
418       txfm_params->tx_size_search_method =
419           winner_mode_params->tx_size_search_methods[WINNER_MODE_EVAL];
420     else
421       txfm_params->tx_size_search_method =
422           winner_mode_params->tx_size_search_methods[MODE_EVAL];
423   }
424   txfm_params->tx_mode_search_type =
425       select_tx_mode(cm, txfm_params->tx_size_search_method);
426 }
427 
set_tx_type_prune(const SPEED_FEATURES * sf,TxfmSearchParams * txfm_params,int winner_mode_tx_type_pruning,int is_winner_mode)428 static INLINE void set_tx_type_prune(const SPEED_FEATURES *sf,
429                                      TxfmSearchParams *txfm_params,
430                                      int winner_mode_tx_type_pruning,
431                                      int is_winner_mode) {
432   // Populate prune transform mode appropriately
433   txfm_params->prune_2d_txfm_mode = sf->tx_sf.tx_type_search.prune_2d_txfm_mode;
434   if (!winner_mode_tx_type_pruning) return;
435 
436   const int prune_mode[2][2] = { { TX_TYPE_PRUNE_4, TX_TYPE_PRUNE_0 },
437                                  { TX_TYPE_PRUNE_5, TX_TYPE_PRUNE_2 } };
438   txfm_params->prune_2d_txfm_mode =
439       prune_mode[winner_mode_tx_type_pruning - 1][is_winner_mode];
440 }
441 
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)442 static INLINE void set_tx_domain_dist_params(
443     const WinnerModeParams *winner_mode_params, TxfmSearchParams *txfm_params,
444     int enable_winner_mode_for_tx_domain_dist, int is_winner_mode) {
445   if (!enable_winner_mode_for_tx_domain_dist) {
446     txfm_params->use_transform_domain_distortion =
447         winner_mode_params->use_transform_domain_distortion[DEFAULT_EVAL];
448     txfm_params->tx_domain_dist_threshold =
449         winner_mode_params->tx_domain_dist_threshold[DEFAULT_EVAL];
450     return;
451   }
452 
453   if (is_winner_mode) {
454     txfm_params->use_transform_domain_distortion =
455         winner_mode_params->use_transform_domain_distortion[WINNER_MODE_EVAL];
456     txfm_params->tx_domain_dist_threshold =
457         winner_mode_params->tx_domain_dist_threshold[WINNER_MODE_EVAL];
458   } else {
459     txfm_params->use_transform_domain_distortion =
460         winner_mode_params->use_transform_domain_distortion[MODE_EVAL];
461     txfm_params->tx_domain_dist_threshold =
462         winner_mode_params->tx_domain_dist_threshold[MODE_EVAL];
463   }
464 }
465 
466 // 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)467 static INLINE void set_mode_eval_params(const struct AV1_COMP *cpi,
468                                         MACROBLOCK *x,
469                                         MODE_EVAL_TYPE mode_eval_type) {
470   const AV1_COMMON *cm = &cpi->common;
471   const SPEED_FEATURES *sf = &cpi->sf;
472   const WinnerModeParams *winner_mode_params = &cpi->winner_mode_params;
473   TxfmSearchParams *txfm_params = &x->txfm_search_params;
474   TxfmSearchInfo *txfm_info = &x->txfm_search_info;
475 
476   switch (mode_eval_type) {
477     case DEFAULT_EVAL:
478       txfm_params->use_default_inter_tx_type = 0;
479       txfm_params->use_default_intra_tx_type = 0;
480       txfm_params->skip_txfm_level =
481           winner_mode_params->skip_txfm_level[DEFAULT_EVAL];
482       txfm_params->predict_dc_level =
483           winner_mode_params->predict_dc_level[DEFAULT_EVAL];
484       // Set default transform domain distortion type
485       set_tx_domain_dist_params(winner_mode_params, txfm_params, 0, 0);
486 
487       // Get default threshold for R-D optimization of coefficients
488       txfm_params->coeff_opt_dist_threshold = get_rd_opt_coeff_thresh(
489           winner_mode_params->coeff_opt_dist_threshold, 0, 0);
490       txfm_params->coeff_opt_satd_threshold = get_rd_opt_coeff_thresh(
491           winner_mode_params->coeff_opt_satd_threshold, 0, 0);
492 
493       // Set default transform size search method
494       set_tx_size_search_method(cm, winner_mode_params, txfm_params, 0, 0);
495       // Set default transform type prune
496       set_tx_type_prune(sf, txfm_params, 0, 0);
497       break;
498     case MODE_EVAL:
499       txfm_params->use_default_intra_tx_type =
500           (cpi->sf.tx_sf.tx_type_search.fast_intra_tx_type_search ||
501            cpi->oxcf.txfm_cfg.use_intra_default_tx_only);
502       txfm_params->use_default_inter_tx_type =
503           cpi->sf.tx_sf.tx_type_search.fast_inter_tx_type_search;
504       txfm_params->skip_txfm_level =
505           winner_mode_params->skip_txfm_level[MODE_EVAL];
506       txfm_params->predict_dc_level =
507           winner_mode_params->predict_dc_level[MODE_EVAL];
508       // Set transform domain distortion type for mode evaluation
509       set_tx_domain_dist_params(
510           winner_mode_params, txfm_params,
511           sf->winner_mode_sf.enable_winner_mode_for_use_tx_domain_dist, 0);
512 
513       // Get threshold for R-D optimization of coefficients during mode
514       // evaluation
515       txfm_params->coeff_opt_dist_threshold = get_rd_opt_coeff_thresh(
516           winner_mode_params->coeff_opt_dist_threshold,
517           sf->winner_mode_sf.enable_winner_mode_for_coeff_opt, 0);
518       txfm_params->coeff_opt_satd_threshold = get_rd_opt_coeff_thresh(
519           winner_mode_params->coeff_opt_satd_threshold,
520           sf->winner_mode_sf.enable_winner_mode_for_coeff_opt, 0);
521 
522       // Set the transform size search method for mode evaluation
523       set_tx_size_search_method(
524           cm, winner_mode_params, txfm_params,
525           sf->winner_mode_sf.enable_winner_mode_for_tx_size_srch, 0);
526       // Set transform type prune for mode evaluation
527       set_tx_type_prune(sf, txfm_params,
528                         sf->tx_sf.tx_type_search.winner_mode_tx_type_pruning,
529                         0);
530       break;
531     case WINNER_MODE_EVAL:
532       txfm_params->use_default_inter_tx_type = 0;
533       txfm_params->use_default_intra_tx_type = 0;
534       txfm_params->skip_txfm_level =
535           winner_mode_params->skip_txfm_level[WINNER_MODE_EVAL];
536       txfm_params->predict_dc_level =
537           winner_mode_params->predict_dc_level[WINNER_MODE_EVAL];
538 
539       // Set transform domain distortion type for winner mode evaluation
540       set_tx_domain_dist_params(
541           winner_mode_params, txfm_params,
542           sf->winner_mode_sf.enable_winner_mode_for_use_tx_domain_dist, 1);
543 
544       // Get threshold for R-D optimization of coefficients for winner mode
545       // evaluation
546       txfm_params->coeff_opt_dist_threshold = get_rd_opt_coeff_thresh(
547           winner_mode_params->coeff_opt_dist_threshold,
548           sf->winner_mode_sf.enable_winner_mode_for_coeff_opt, 1);
549       txfm_params->coeff_opt_satd_threshold = get_rd_opt_coeff_thresh(
550           winner_mode_params->coeff_opt_satd_threshold,
551           sf->winner_mode_sf.enable_winner_mode_for_coeff_opt, 1);
552 
553       // Set the transform size search method for winner mode evaluation
554       set_tx_size_search_method(
555           cm, winner_mode_params, txfm_params,
556           sf->winner_mode_sf.enable_winner_mode_for_tx_size_srch, 1);
557       // Set default transform type prune mode for winner mode evaluation
558       set_tx_type_prune(sf, txfm_params,
559                         sf->tx_sf.tx_type_search.winner_mode_tx_type_pruning,
560                         1);
561 
562       // Reset hash state for winner mode processing. Winner mode and subsequent
563       // transform/mode evaluations (palette/IntraBC) cann't reuse old data as
564       // the decisions would have been sub-optimal
565       // TODO(any): Move the evaluation of palette/IntraBC modes before winner
566       // mode is processed and clean-up the code below
567       reset_hash_records(txfm_info, cpi->sf.tx_sf.use_inter_txb_hash);
568 
569       break;
570     default: assert(0);
571   }
572 }
573 
574 // Similar to store_cfl_required(), but for use during the RDO process,
575 // where we haven't yet determined whether this block uses CfL.
store_cfl_required_rdo(const AV1_COMMON * cm,const MACROBLOCK * x)576 static INLINE CFL_ALLOWED_TYPE store_cfl_required_rdo(const AV1_COMMON *cm,
577                                                       const MACROBLOCK *x) {
578   const MACROBLOCKD *xd = &x->e_mbd;
579 
580   if (cm->seq_params.monochrome || !xd->is_chroma_ref) return CFL_DISALLOWED;
581 
582   if (!xd->is_chroma_ref) {
583     // For non-chroma-reference blocks, we should always store the luma pixels,
584     // in case the corresponding chroma-reference block uses CfL.
585     // Note that this can only happen for block sizes which are <8 on
586     // their shortest side, as otherwise they would be chroma reference
587     // blocks.
588     return CFL_ALLOWED;
589   }
590 
591   // For chroma reference blocks, we should store data in the encoder iff we're
592   // allowed to try out CfL.
593   return is_cfl_allowed(xd);
594 }
595 
init_sbuv_mode(MB_MODE_INFO * const mbmi)596 static AOM_INLINE void init_sbuv_mode(MB_MODE_INFO *const mbmi) {
597   mbmi->uv_mode = UV_DC_PRED;
598   mbmi->palette_mode_info.palette_size[1] = 0;
599 }
600 
601 // 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)602 static INLINE void store_winner_mode_stats(
603     const AV1_COMMON *const cm, MACROBLOCK *x, const MB_MODE_INFO *mbmi,
604     RD_STATS *rd_cost, RD_STATS *rd_cost_y, RD_STATS *rd_cost_uv,
605     THR_MODES mode_index, uint8_t *color_map, BLOCK_SIZE bsize, int64_t this_rd,
606     int multi_winner_mode_type, int txfm_search_done) {
607   WinnerModeStats *winner_mode_stats = x->winner_mode_stats;
608   int mode_idx = 0;
609   int is_palette_mode = mbmi->palette_mode_info.palette_size[PLANE_TYPE_Y] > 0;
610   // Mode stat is not required when multiwinner mode processing is disabled
611   if (multi_winner_mode_type == MULTI_WINNER_MODE_OFF) return;
612   // Ignore mode with maximum rd
613   if (this_rd == INT64_MAX) return;
614   // TODO(any): Winner mode processing is currently not applicable for palette
615   // mode in Inter frames. Clean-up the following code, once support is added
616   if (!frame_is_intra_only(cm) && is_palette_mode) return;
617 
618   int max_winner_mode_count = frame_is_intra_only(cm)
619                                   ? MAX_WINNER_MODE_COUNT_INTRA
620                                   : MAX_WINNER_MODE_COUNT_INTER;
621   max_winner_mode_count = (multi_winner_mode_type == MULTI_WINNER_MODE_FAST)
622                               ? AOMMIN(max_winner_mode_count, 2)
623                               : max_winner_mode_count;
624   assert(x->winner_mode_count >= 0 &&
625          x->winner_mode_count <= max_winner_mode_count);
626 
627   if (x->winner_mode_count) {
628     // Find the mode which has higher rd cost than this_rd
629     for (mode_idx = 0; mode_idx < x->winner_mode_count; mode_idx++)
630       if (winner_mode_stats[mode_idx].rd > this_rd) break;
631 
632     if (mode_idx == max_winner_mode_count) {
633       // No mode has higher rd cost than this_rd
634       return;
635     } else if (mode_idx < max_winner_mode_count - 1) {
636       // Create a slot for current mode and move others to the next slot
637       memmove(
638           &winner_mode_stats[mode_idx + 1], &winner_mode_stats[mode_idx],
639           (max_winner_mode_count - mode_idx - 1) * sizeof(*winner_mode_stats));
640     }
641   }
642   // Add a mode stat for winner mode processing
643   winner_mode_stats[mode_idx].mbmi = *mbmi;
644   winner_mode_stats[mode_idx].rd = this_rd;
645   winner_mode_stats[mode_idx].mode_index = mode_index;
646 
647   // Update rd stats required for inter frame
648   if (!frame_is_intra_only(cm) && rd_cost && rd_cost_y && rd_cost_uv) {
649     const MACROBLOCKD *xd = &x->e_mbd;
650     const int skip_ctx = av1_get_skip_txfm_context(xd);
651     const int is_intra_mode = av1_mode_defs[mode_index].mode < INTRA_MODE_END;
652     const int skip_txfm = mbmi->skip_txfm && !is_intra_mode;
653 
654     winner_mode_stats[mode_idx].rd_cost = *rd_cost;
655     if (txfm_search_done) {
656       winner_mode_stats[mode_idx].rate_y =
657           rd_cost_y->rate +
658           x->mode_costs
659               .skip_txfm_cost[skip_ctx][rd_cost->skip_txfm || skip_txfm];
660       winner_mode_stats[mode_idx].rate_uv = rd_cost_uv->rate;
661     }
662   }
663 
664   if (color_map) {
665     // Store color_index_map for palette mode
666     const MACROBLOCKD *const xd = &x->e_mbd;
667     int block_width, block_height;
668     av1_get_block_dimensions(bsize, AOM_PLANE_Y, xd, &block_width,
669                              &block_height, NULL, NULL);
670     memcpy(winner_mode_stats[mode_idx].color_index_map, color_map,
671            block_width * block_height * sizeof(color_map[0]));
672   }
673 
674   x->winner_mode_count =
675       AOMMIN(x->winner_mode_count + 1, max_winner_mode_count);
676 }
677 
678 unsigned int av1_get_sby_perpixel_variance(const struct AV1_COMP *cpi,
679                                            const struct buf_2d *ref,
680                                            BLOCK_SIZE bs);
681 
682 unsigned int av1_high_get_sby_perpixel_variance(const struct AV1_COMP *cpi,
683                                                 const struct buf_2d *ref,
684                                                 BLOCK_SIZE bs, int bd);
685 
is_mode_intra(PREDICTION_MODE mode)686 static INLINE int is_mode_intra(PREDICTION_MODE mode) {
687   return mode < INTRA_MODE_END;
688 }
689 
690 #ifdef __cplusplus
691 }  // extern "C"
692 #endif
693 
694 #endif  // AOM_AV1_ENCODER_RDOPT_UTILS_H_
695