xref: /aosp_15_r20/external/libaom/av1/encoder/interp_search.c (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
1 /*
2  * Copyright (c) 2020, 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 #include "av1/common/pred_common.h"
13 #include "av1/encoder/interp_search.h"
14 #include "av1/encoder/model_rd.h"
15 #include "av1/encoder/rdopt_utils.h"
16 #include "av1/encoder/reconinter_enc.h"
17 
18 // return mv_diff
is_interp_filter_good_match(const INTERPOLATION_FILTER_STATS * st,MB_MODE_INFO * const mi,int skip_level)19 static inline int is_interp_filter_good_match(
20     const INTERPOLATION_FILTER_STATS *st, MB_MODE_INFO *const mi,
21     int skip_level) {
22   const int is_comp = has_second_ref(mi);
23   int i;
24 
25   for (i = 0; i < 1 + is_comp; ++i) {
26     if (st->ref_frames[i] != mi->ref_frame[i]) return INT_MAX;
27   }
28 
29   if (skip_level == 1 && is_comp) {
30     if (st->comp_type != mi->interinter_comp.type) return INT_MAX;
31     if (st->compound_idx != mi->compound_idx) return INT_MAX;
32   }
33 
34   int mv_diff = 0;
35   for (i = 0; i < 1 + is_comp; ++i) {
36     mv_diff += abs(st->mv[i].as_mv.row - mi->mv[i].as_mv.row) +
37                abs(st->mv[i].as_mv.col - mi->mv[i].as_mv.col);
38   }
39   return mv_diff;
40 }
41 
save_interp_filter_search_stat(MB_MODE_INFO * const mbmi,int64_t rd,unsigned int pred_sse,INTERPOLATION_FILTER_STATS * interp_filter_stats,int interp_filter_stats_idx)42 static inline int save_interp_filter_search_stat(
43     MB_MODE_INFO *const mbmi, int64_t rd, unsigned int pred_sse,
44     INTERPOLATION_FILTER_STATS *interp_filter_stats,
45     int interp_filter_stats_idx) {
46   if (interp_filter_stats_idx < MAX_INTERP_FILTER_STATS) {
47     INTERPOLATION_FILTER_STATS stat = { mbmi->interp_filters,
48                                         { mbmi->mv[0], mbmi->mv[1] },
49                                         { mbmi->ref_frame[0],
50                                           mbmi->ref_frame[1] },
51                                         mbmi->interinter_comp.type,
52                                         mbmi->compound_idx,
53                                         rd,
54                                         pred_sse };
55     interp_filter_stats[interp_filter_stats_idx] = stat;
56     interp_filter_stats_idx++;
57   }
58   return interp_filter_stats_idx;
59 }
60 
find_interp_filter_in_stats(MB_MODE_INFO * const mbmi,INTERPOLATION_FILTER_STATS * interp_filter_stats,int interp_filter_stats_idx,int skip_level)61 static inline int find_interp_filter_in_stats(
62     MB_MODE_INFO *const mbmi, INTERPOLATION_FILTER_STATS *interp_filter_stats,
63     int interp_filter_stats_idx, int skip_level) {
64   // [skip_levels][single or comp]
65   const int thr[2][2] = { { 0, 0 }, { 3, 7 } };
66   const int is_comp = has_second_ref(mbmi);
67 
68   // Find good enough match.
69   // TODO(yunqing): Separate single-ref mode and comp mode stats for fast
70   // search.
71   int best = INT_MAX;
72   int match = -1;
73   for (int j = 0; j < interp_filter_stats_idx; ++j) {
74     const INTERPOLATION_FILTER_STATS *st = &interp_filter_stats[j];
75     const int mv_diff = is_interp_filter_good_match(st, mbmi, skip_level);
76     // Exact match is found.
77     if (mv_diff == 0) {
78       match = j;
79       break;
80     } else if (mv_diff < best && mv_diff <= thr[skip_level - 1][is_comp]) {
81       best = mv_diff;
82       match = j;
83     }
84   }
85 
86   if (match != -1) {
87     mbmi->interp_filters = interp_filter_stats[match].filters;
88     return match;
89   }
90   return -1;  // no match result found
91 }
92 
find_interp_filter_match(MB_MODE_INFO * const mbmi,const AV1_COMP * const cpi,const InterpFilter assign_filter,const int need_search,INTERPOLATION_FILTER_STATS * interp_filter_stats,int interp_filter_stats_idx)93 static int find_interp_filter_match(
94     MB_MODE_INFO *const mbmi, const AV1_COMP *const cpi,
95     const InterpFilter assign_filter, const int need_search,
96     INTERPOLATION_FILTER_STATS *interp_filter_stats,
97     int interp_filter_stats_idx) {
98   int match_found_idx = -1;
99   if (cpi->sf.interp_sf.use_interp_filter && need_search)
100     match_found_idx = find_interp_filter_in_stats(
101         mbmi, interp_filter_stats, interp_filter_stats_idx,
102         cpi->sf.interp_sf.use_interp_filter);
103 
104   if (!need_search || match_found_idx == -1)
105     set_default_interp_filters(mbmi, assign_filter);
106   return match_found_idx;
107 }
108 
get_switchable_rate(MACROBLOCK * const x,const int_interpfilters filters,const int ctx[2],int dual_filter)109 static inline int get_switchable_rate(MACROBLOCK *const x,
110                                       const int_interpfilters filters,
111                                       const int ctx[2], int dual_filter) {
112   const InterpFilter filter0 = filters.as_filters.y_filter;
113   int inter_filter_cost =
114       x->mode_costs.switchable_interp_costs[ctx[0]][filter0];
115   if (dual_filter) {
116     const InterpFilter filter1 = filters.as_filters.x_filter;
117     inter_filter_cost += x->mode_costs.switchable_interp_costs[ctx[1]][filter1];
118   }
119   return SWITCHABLE_INTERP_RATE_FACTOR * inter_filter_cost;
120 }
121 
122 // Build inter predictor and calculate model rd
123 // for a given plane.
interp_model_rd_eval(MACROBLOCK * const x,const AV1_COMP * const cpi,BLOCK_SIZE bsize,const BUFFER_SET * const orig_dst,int plane_from,int plane_to,RD_STATS * rd_stats,int is_skip_build_pred)124 static inline void interp_model_rd_eval(
125     MACROBLOCK *const x, const AV1_COMP *const cpi, BLOCK_SIZE bsize,
126     const BUFFER_SET *const orig_dst, int plane_from, int plane_to,
127     RD_STATS *rd_stats, int is_skip_build_pred) {
128   const AV1_COMMON *cm = &cpi->common;
129   MACROBLOCKD *const xd = &x->e_mbd;
130   RD_STATS tmp_rd_stats;
131   av1_init_rd_stats(&tmp_rd_stats);
132 
133   // Skip inter predictor if the predictor is already available.
134   if (!is_skip_build_pred) {
135     const int mi_row = xd->mi_row;
136     const int mi_col = xd->mi_col;
137     av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize,
138                                   plane_from, plane_to);
139   }
140 
141   model_rd_sb_fn[cpi->sf.rt_sf.use_simple_rd_model
142                      ? MODELRD_LEGACY
143                      : MODELRD_TYPE_INTERP_FILTER](
144       cpi, bsize, x, xd, plane_from, plane_to, &tmp_rd_stats.rate,
145       &tmp_rd_stats.dist, &tmp_rd_stats.skip_txfm, &tmp_rd_stats.sse, NULL,
146       NULL, NULL);
147 
148   av1_merge_rd_stats(rd_stats, &tmp_rd_stats);
149 }
150 
151 // calculate the rdcost of given interpolation_filter
interpolation_filter_rd(MACROBLOCK * const x,const AV1_COMP * const cpi,const TileDataEnc * tile_data,BLOCK_SIZE bsize,const BUFFER_SET * const orig_dst,int64_t * const rd,RD_STATS * rd_stats_luma,RD_STATS * rd_stats,int * const switchable_rate,const BUFFER_SET * dst_bufs[2],int filter_idx,const int switchable_ctx[2],const int skip_pred)152 static inline int64_t interpolation_filter_rd(
153     MACROBLOCK *const x, const AV1_COMP *const cpi,
154     const TileDataEnc *tile_data, BLOCK_SIZE bsize,
155     const BUFFER_SET *const orig_dst, int64_t *const rd,
156     RD_STATS *rd_stats_luma, RD_STATS *rd_stats, int *const switchable_rate,
157     const BUFFER_SET *dst_bufs[2], int filter_idx, const int switchable_ctx[2],
158     const int skip_pred) {
159   const AV1_COMMON *cm = &cpi->common;
160   const InterpSearchFlags *interp_search_flags = &cpi->interp_search_flags;
161   const int num_planes = av1_num_planes(cm);
162   MACROBLOCKD *const xd = &x->e_mbd;
163   MB_MODE_INFO *const mbmi = xd->mi[0];
164   RD_STATS this_rd_stats_luma, this_rd_stats;
165 
166   // Initialize rd_stats structures to default values.
167   av1_init_rd_stats(&this_rd_stats_luma);
168   this_rd_stats = *rd_stats_luma;
169   const int_interpfilters last_best = mbmi->interp_filters;
170   mbmi->interp_filters = filter_sets[filter_idx];
171   const int tmp_rs =
172       get_switchable_rate(x, mbmi->interp_filters, switchable_ctx,
173                           cm->seq_params->enable_dual_filter);
174 
175   int64_t min_rd = RDCOST(x->rdmult, tmp_rs, 0);
176   if (min_rd > *rd) {
177     mbmi->interp_filters = last_best;
178     return 0;
179   }
180 
181   (void)tile_data;
182 
183   assert(skip_pred != 2);
184   assert((rd_stats_luma->rate >= 0) && (rd_stats->rate >= 0));
185   assert((rd_stats_luma->dist >= 0) && (rd_stats->dist >= 0));
186   assert((rd_stats_luma->sse >= 0) && (rd_stats->sse >= 0));
187   assert((rd_stats_luma->skip_txfm == 0) || (rd_stats_luma->skip_txfm == 1));
188   assert((rd_stats->skip_txfm == 0) || (rd_stats->skip_txfm == 1));
189   assert((skip_pred >= 0) &&
190          (skip_pred <= interp_search_flags->default_interp_skip_flags));
191 
192   // When skip_txfm pred is equal to default_interp_skip_flags,
193   // skip both luma and chroma MC.
194   // For mono-chrome images:
195   // num_planes = 1 and cpi->default_interp_skip_flags = 1,
196   // skip_pred = 1: skip both luma and chroma
197   // skip_pred = 0: Evaluate luma and as num_planes=1,
198   // skip chroma evaluation
199   int tmp_skip_pred =
200       (skip_pred == interp_search_flags->default_interp_skip_flags)
201           ? INTERP_SKIP_LUMA_SKIP_CHROMA
202           : skip_pred;
203 
204   switch (tmp_skip_pred) {
205     case INTERP_EVAL_LUMA_EVAL_CHROMA:
206       // skip_pred = 0: Evaluate both luma and chroma.
207       // Luma MC
208       interp_model_rd_eval(x, cpi, bsize, orig_dst, AOM_PLANE_Y, AOM_PLANE_Y,
209                            &this_rd_stats_luma, 0);
210       this_rd_stats = this_rd_stats_luma;
211 #if CONFIG_COLLECT_RD_STATS == 3
212       RD_STATS rd_stats_y;
213       av1_pick_recursive_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize,
214                                           INT64_MAX);
215       PrintPredictionUnitStats(cpi, tile_data, x, &rd_stats_y, bsize);
216 #endif  // CONFIG_COLLECT_RD_STATS == 3
217       AOM_FALLTHROUGH_INTENDED;
218     case INTERP_SKIP_LUMA_EVAL_CHROMA:
219       // skip_pred = 1: skip luma evaluation (retain previous best luma stats)
220       // and do chroma evaluation.
221       for (int plane = 1; plane < num_planes; ++plane) {
222         int64_t tmp_rd =
223             RDCOST(x->rdmult, tmp_rs + this_rd_stats.rate, this_rd_stats.dist);
224         if (tmp_rd >= *rd) {
225           mbmi->interp_filters = last_best;
226           return 0;
227         }
228         interp_model_rd_eval(x, cpi, bsize, orig_dst, plane, plane,
229                              &this_rd_stats, 0);
230       }
231       break;
232     case INTERP_SKIP_LUMA_SKIP_CHROMA:
233       // both luma and chroma evaluation is skipped
234       this_rd_stats = *rd_stats;
235       break;
236     case INTERP_EVAL_INVALID:
237     default: assert(0); return 0;
238   }
239   int64_t tmp_rd =
240       RDCOST(x->rdmult, tmp_rs + this_rd_stats.rate, this_rd_stats.dist);
241 
242   if (tmp_rd < *rd) {
243     *rd = tmp_rd;
244     *switchable_rate = tmp_rs;
245     if (skip_pred != interp_search_flags->default_interp_skip_flags) {
246       if (skip_pred == INTERP_EVAL_LUMA_EVAL_CHROMA) {
247         // Overwrite the data as current filter is the best one
248         *rd_stats_luma = this_rd_stats_luma;
249         *rd_stats = this_rd_stats;
250         // As luma MC data is computed, no need to recompute after the search
251         x->recalc_luma_mc_data = 0;
252       } else if (skip_pred == INTERP_SKIP_LUMA_EVAL_CHROMA) {
253         // As luma MC data is not computed, update of luma data can be skipped
254         *rd_stats = this_rd_stats;
255         // As luma MC data is not recomputed and current filter is the best,
256         // indicate the possibility of recomputing MC data
257         // If current buffer contains valid MC data, toggle to indicate that
258         // luma MC data needs to be recomputed
259         x->recalc_luma_mc_data ^= 1;
260       }
261       swap_dst_buf(xd, dst_bufs, num_planes);
262     }
263     return 1;
264   }
265   mbmi->interp_filters = last_best;
266   return 0;
267 }
268 
is_pred_filter_search_allowed(const AV1_COMP * const cpi,MACROBLOCKD * xd,BLOCK_SIZE bsize,int_interpfilters * af,int_interpfilters * lf)269 static inline INTERP_PRED_TYPE is_pred_filter_search_allowed(
270     const AV1_COMP *const cpi, MACROBLOCKD *xd, BLOCK_SIZE bsize,
271     int_interpfilters *af, int_interpfilters *lf) {
272   const AV1_COMMON *cm = &cpi->common;
273   const MB_MODE_INFO *const above_mbmi = xd->above_mbmi;
274   const MB_MODE_INFO *const left_mbmi = xd->left_mbmi;
275   const int bsl = mi_size_wide_log2[bsize];
276   int is_horiz_eq = 0, is_vert_eq = 0;
277 
278   if (above_mbmi && is_inter_block(above_mbmi))
279     *af = above_mbmi->interp_filters;
280 
281   if (left_mbmi && is_inter_block(left_mbmi)) *lf = left_mbmi->interp_filters;
282 
283   if (af->as_filters.x_filter != INTERP_INVALID)
284     is_horiz_eq = af->as_filters.x_filter == lf->as_filters.x_filter;
285   if (af->as_filters.y_filter != INTERP_INVALID)
286     is_vert_eq = af->as_filters.y_filter == lf->as_filters.y_filter;
287 
288   INTERP_PRED_TYPE pred_filter_type = (is_vert_eq << 1) + is_horiz_eq;
289   const int mi_row = xd->mi_row;
290   const int mi_col = xd->mi_col;
291   int pred_filter_enable =
292       cpi->sf.interp_sf.cb_pred_filter_search
293           ? (((mi_row + mi_col) >> bsl) +
294              get_chessboard_index(cm->current_frame.frame_number)) &
295                 0x1
296           : 0;
297   pred_filter_enable &= is_horiz_eq || is_vert_eq;
298   // pred_filter_search = 0: pred_filter is disabled
299   // pred_filter_search = 1: pred_filter is enabled and only horz pred matching
300   // pred_filter_search = 2: pred_filter is enabled and only vert pred matching
301   // pred_filter_search = 3: pred_filter is enabled and
302   //                         both vert, horz pred matching
303   return pred_filter_enable * pred_filter_type;
304 }
305 
find_best_interp_rd_facade(MACROBLOCK * const x,const AV1_COMP * const cpi,const TileDataEnc * tile_data,BLOCK_SIZE bsize,const BUFFER_SET * const orig_dst,int64_t * const rd,RD_STATS * rd_stats_y,RD_STATS * rd_stats,int * const switchable_rate,const BUFFER_SET * dst_bufs[2],const int switchable_ctx[2],const int skip_pred,uint16_t allow_interp_mask,int is_w4_or_h4)306 static DUAL_FILTER_TYPE find_best_interp_rd_facade(
307     MACROBLOCK *const x, const AV1_COMP *const cpi,
308     const TileDataEnc *tile_data, BLOCK_SIZE bsize,
309     const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y,
310     RD_STATS *rd_stats, int *const switchable_rate,
311     const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2],
312     const int skip_pred, uint16_t allow_interp_mask, int is_w4_or_h4) {
313   int tmp_skip_pred = skip_pred;
314   DUAL_FILTER_TYPE best_filt_type = REG_REG;
315 
316   // If no filter are set to be evaluated, return from function
317   if (allow_interp_mask == 0x0) return best_filt_type;
318   // For block width or height is 4, skip the pred evaluation of SHARP_SHARP
319   tmp_skip_pred = is_w4_or_h4
320                       ? cpi->interp_search_flags.default_interp_skip_flags
321                       : skip_pred;
322 
323   // Loop over the all filter types and evaluate for only allowed filter types
324   for (int filt_type = SHARP_SHARP; filt_type >= REG_REG; --filt_type) {
325     const int is_filter_allowed =
326         get_interp_filter_allowed_mask(allow_interp_mask, filt_type);
327     if (is_filter_allowed)
328       if (interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
329                                   rd_stats_y, rd_stats, switchable_rate,
330                                   dst_bufs, filt_type, switchable_ctx,
331                                   tmp_skip_pred))
332         best_filt_type = filt_type;
333     tmp_skip_pred = skip_pred;
334   }
335   return best_filt_type;
336 }
337 
pred_dual_interp_filter_rd(MACROBLOCK * const x,const AV1_COMP * const cpi,const TileDataEnc * tile_data,BLOCK_SIZE bsize,const BUFFER_SET * const orig_dst,int64_t * const rd,RD_STATS * rd_stats_y,RD_STATS * rd_stats,int * const switchable_rate,const BUFFER_SET * dst_bufs[2],const int switchable_ctx[2],const int skip_pred,INTERP_PRED_TYPE pred_filt_type,int_interpfilters * af,int_interpfilters * lf)338 static inline void pred_dual_interp_filter_rd(
339     MACROBLOCK *const x, const AV1_COMP *const cpi,
340     const TileDataEnc *tile_data, BLOCK_SIZE bsize,
341     const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y,
342     RD_STATS *rd_stats, int *const switchable_rate,
343     const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2],
344     const int skip_pred, INTERP_PRED_TYPE pred_filt_type, int_interpfilters *af,
345     int_interpfilters *lf) {
346   (void)lf;
347   assert(pred_filt_type > INTERP_HORZ_NEQ_VERT_NEQ);
348   assert(pred_filt_type < INTERP_PRED_TYPE_ALL);
349   uint16_t allowed_interp_mask = 0;
350 
351   if (pred_filt_type == INTERP_HORZ_EQ_VERT_NEQ) {
352     // pred_filter_search = 1: Only horizontal filter is matching
353     allowed_interp_mask =
354         av1_interp_dual_filt_mask[pred_filt_type - 1][af->as_filters.x_filter];
355   } else if (pred_filt_type == INTERP_HORZ_NEQ_VERT_EQ) {
356     // pred_filter_search = 2: Only vertical filter is matching
357     allowed_interp_mask =
358         av1_interp_dual_filt_mask[pred_filt_type - 1][af->as_filters.y_filter];
359   } else {
360     // pred_filter_search = 3: Both horizontal and vertical filter are matching
361     int filt_type =
362         af->as_filters.x_filter + af->as_filters.y_filter * SWITCHABLE_FILTERS;
363     set_interp_filter_allowed_mask(&allowed_interp_mask, filt_type);
364   }
365   // REG_REG is already been evaluated in the beginning
366   reset_interp_filter_allowed_mask(&allowed_interp_mask, REG_REG);
367   find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd, rd_stats_y,
368                              rd_stats, switchable_rate, dst_bufs,
369                              switchable_ctx, skip_pred, allowed_interp_mask, 0);
370 }
371 // Evaluate dual filter type
372 // a) Using above, left block interp filter
373 // b) Find the best horizontal filter and
374 //    then evaluate corresponding vertical filters.
fast_dual_interp_filter_rd(MACROBLOCK * const x,const AV1_COMP * const cpi,const TileDataEnc * tile_data,BLOCK_SIZE bsize,const BUFFER_SET * const orig_dst,int64_t * const rd,RD_STATS * rd_stats_y,RD_STATS * rd_stats,int * const switchable_rate,const BUFFER_SET * dst_bufs[2],const int switchable_ctx[2],const int skip_hor,const int skip_ver)375 static inline void fast_dual_interp_filter_rd(
376     MACROBLOCK *const x, const AV1_COMP *const cpi,
377     const TileDataEnc *tile_data, BLOCK_SIZE bsize,
378     const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y,
379     RD_STATS *rd_stats, int *const switchable_rate,
380     const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2],
381     const int skip_hor, const int skip_ver) {
382   const InterpSearchFlags *interp_search_flags = &cpi->interp_search_flags;
383   MACROBLOCKD *const xd = &x->e_mbd;
384   MB_MODE_INFO *const mbmi = xd->mi[0];
385   INTERP_PRED_TYPE pred_filter_type = INTERP_HORZ_NEQ_VERT_NEQ;
386   int_interpfilters af = av1_broadcast_interp_filter(INTERP_INVALID);
387   int_interpfilters lf = af;
388 
389   if (!have_newmv_in_inter_mode(mbmi->mode)) {
390     pred_filter_type = is_pred_filter_search_allowed(cpi, xd, bsize, &af, &lf);
391   }
392 
393   if (pred_filter_type) {
394     pred_dual_interp_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
395                                rd_stats_y, rd_stats, switchable_rate, dst_bufs,
396                                switchable_ctx, (skip_hor & skip_ver),
397                                pred_filter_type, &af, &lf);
398   } else {
399     const int bw = block_size_wide[bsize];
400     const int bh = block_size_high[bsize];
401     int best_dual_mode = 0;
402     int skip_pred =
403         bw <= 4 ? interp_search_flags->default_interp_skip_flags : skip_hor;
404     // TODO(any): Make use of find_best_interp_rd_facade()
405     // if speed impact is negligible
406     for (int i = (SWITCHABLE_FILTERS - 1); i >= 1; --i) {
407       if (interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
408                                   rd_stats_y, rd_stats, switchable_rate,
409                                   dst_bufs, i, switchable_ctx, skip_pred)) {
410         best_dual_mode = i;
411       }
412       skip_pred = skip_hor;
413     }
414     // From best of horizontal EIGHTTAP_REGULAR modes, check vertical modes
415     skip_pred =
416         bh <= 4 ? interp_search_flags->default_interp_skip_flags : skip_ver;
417     for (int i = (best_dual_mode + (SWITCHABLE_FILTERS * 2));
418          i >= (best_dual_mode + SWITCHABLE_FILTERS); i -= SWITCHABLE_FILTERS) {
419       interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
420                               rd_stats_y, rd_stats, switchable_rate, dst_bufs,
421                               i, switchable_ctx, skip_pred);
422       skip_pred = skip_ver;
423     }
424   }
425 }
426 
427 // Find the best interp filter if dual_interp_filter = 0
find_best_non_dual_interp_filter(MACROBLOCK * const x,const AV1_COMP * const cpi,const TileDataEnc * tile_data,BLOCK_SIZE bsize,const BUFFER_SET * const orig_dst,int64_t * const rd,RD_STATS * rd_stats_y,RD_STATS * rd_stats,int * const switchable_rate,const BUFFER_SET * dst_bufs[2],const int switchable_ctx[2],const int skip_ver,const int skip_hor)428 static inline void find_best_non_dual_interp_filter(
429     MACROBLOCK *const x, const AV1_COMP *const cpi,
430     const TileDataEnc *tile_data, BLOCK_SIZE bsize,
431     const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y,
432     RD_STATS *rd_stats, int *const switchable_rate,
433     const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2],
434     const int skip_ver, const int skip_hor) {
435   const InterpSearchFlags *interp_search_flags = &cpi->interp_search_flags;
436   int8_t i;
437   MACROBLOCKD *const xd = &x->e_mbd;
438   MB_MODE_INFO *const mbmi = xd->mi[0];
439 
440   uint16_t interp_filter_search_mask =
441       interp_search_flags->interp_filter_search_mask;
442 
443   if (cpi->sf.interp_sf.adaptive_interp_filter_search == 2) {
444     const FRAME_UPDATE_TYPE update_type =
445         get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index);
446     const int ctx0 = av1_get_pred_context_switchable_interp(xd, 0);
447     const int ctx1 = av1_get_pred_context_switchable_interp(xd, 1);
448     int use_actual_frame_probs = 1;
449     const int *switchable_interp_p0;
450     const int *switchable_interp_p1;
451 #if CONFIG_FPMT_TEST
452     use_actual_frame_probs =
453         (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) ? 0 : 1;
454     if (!use_actual_frame_probs) {
455       switchable_interp_p0 = (int *)cpi->ppi->temp_frame_probs
456                                  .switchable_interp_probs[update_type][ctx0];
457       switchable_interp_p1 = (int *)cpi->ppi->temp_frame_probs
458                                  .switchable_interp_probs[update_type][ctx1];
459     }
460 #endif
461     if (use_actual_frame_probs) {
462       switchable_interp_p0 =
463           cpi->ppi->frame_probs.switchable_interp_probs[update_type][ctx0];
464       switchable_interp_p1 =
465           cpi->ppi->frame_probs.switchable_interp_probs[update_type][ctx1];
466     }
467     static const int thr[7] = { 0, 8, 8, 8, 8, 0, 8 };
468     const int thresh = thr[update_type];
469     for (i = 0; i < SWITCHABLE_FILTERS; i++) {
470       // For non-dual case, the 2 dir's prob should be identical.
471       assert(switchable_interp_p0[i] == switchable_interp_p1[i]);
472       if (switchable_interp_p0[i] < thresh &&
473           switchable_interp_p1[i] < thresh) {
474         DUAL_FILTER_TYPE filt_type = i + SWITCHABLE_FILTERS * i;
475         reset_interp_filter_allowed_mask(&interp_filter_search_mask, filt_type);
476       }
477     }
478   }
479 
480   // Regular filter evaluation should have been done and hence the same should
481   // be the winner
482   assert(x->e_mbd.mi[0]->interp_filters.as_int == filter_sets[0].as_int);
483   if ((skip_hor & skip_ver) != interp_search_flags->default_interp_skip_flags) {
484     INTERP_PRED_TYPE pred_filter_type = INTERP_HORZ_NEQ_VERT_NEQ;
485     int_interpfilters af = av1_broadcast_interp_filter(INTERP_INVALID);
486     int_interpfilters lf = af;
487 
488     pred_filter_type = is_pred_filter_search_allowed(cpi, xd, bsize, &af, &lf);
489     if (pred_filter_type) {
490       assert(af.as_filters.x_filter != INTERP_INVALID);
491       int filter_idx = SWITCHABLE * af.as_filters.x_filter;
492       // This assert tells that (filter_x == filter_y) for non-dual filter case
493       assert(filter_sets[filter_idx].as_filters.x_filter ==
494              filter_sets[filter_idx].as_filters.y_filter);
495       if (cpi->sf.interp_sf.adaptive_interp_filter_search &&
496           !(get_interp_filter_allowed_mask(interp_filter_search_mask,
497                                            filter_idx))) {
498         return;
499       }
500       if (filter_idx) {
501         interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
502                                 rd_stats_y, rd_stats, switchable_rate, dst_bufs,
503                                 filter_idx, switchable_ctx,
504                                 (skip_hor & skip_ver));
505       }
506       return;
507     }
508   }
509   // Reuse regular filter's modeled rd data for sharp filter for following
510   // cases
511   // 1) When bsize is 4x4
512   // 2) When block width is 4 (i.e. 4x8/4x16 blocks) and MV in vertical
513   // direction is full-pel
514   // 3) When block height is 4 (i.e. 8x4/16x4 blocks) and MV in horizontal
515   // direction is full-pel
516   // TODO(any): Optimize cases 2 and 3 further if luma MV in relavant direction
517   // alone is full-pel
518 
519   if ((bsize == BLOCK_4X4) ||
520       (block_size_wide[bsize] == 4 &&
521        skip_ver == interp_search_flags->default_interp_skip_flags) ||
522       (block_size_high[bsize] == 4 &&
523        skip_hor == interp_search_flags->default_interp_skip_flags)) {
524     int skip_pred = skip_hor & skip_ver;
525     uint16_t allowed_interp_mask = 0;
526 
527     // REG_REG filter type is evaluated beforehand, hence skip it
528     set_interp_filter_allowed_mask(&allowed_interp_mask, SHARP_SHARP);
529     set_interp_filter_allowed_mask(&allowed_interp_mask, SMOOTH_SMOOTH);
530     if (cpi->sf.interp_sf.adaptive_interp_filter_search)
531       allowed_interp_mask &= interp_filter_search_mask;
532 
533     find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd,
534                                rd_stats_y, rd_stats, switchable_rate, dst_bufs,
535                                switchable_ctx, skip_pred, allowed_interp_mask,
536                                1);
537   } else {
538     int skip_pred = (skip_hor & skip_ver);
539     for (i = (SWITCHABLE_FILTERS + 1); i < DUAL_FILTER_SET_SIZE;
540          i += (SWITCHABLE_FILTERS + 1)) {
541       // This assert tells that (filter_x == filter_y) for non-dual filter case
542       assert(filter_sets[i].as_filters.x_filter ==
543              filter_sets[i].as_filters.y_filter);
544       if (cpi->sf.interp_sf.adaptive_interp_filter_search &&
545           !(get_interp_filter_allowed_mask(interp_filter_search_mask, i))) {
546         continue;
547       }
548       interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
549                               rd_stats_y, rd_stats, switchable_rate, dst_bufs,
550                               i, switchable_ctx, skip_pred);
551       // In first iteration, smooth filter is evaluated. If smooth filter
552       // (which is less sharper) is the winner among regular and smooth filters,
553       // sharp filter evaluation is skipped
554       // TODO(any): Refine this gating based on modelled rd only (i.e., by not
555       // accounting switchable filter rate)
556       if (cpi->sf.interp_sf.skip_sharp_interp_filter_search &&
557           skip_pred != interp_search_flags->default_interp_skip_flags) {
558         if (mbmi->interp_filters.as_int == filter_sets[SMOOTH_SMOOTH].as_int)
559           break;
560       }
561     }
562   }
563 }
564 
calc_interp_skip_pred_flag(MACROBLOCK * const x,const AV1_COMP * const cpi,int * skip_hor,int * skip_ver)565 static inline void calc_interp_skip_pred_flag(MACROBLOCK *const x,
566                                               const AV1_COMP *const cpi,
567                                               int *skip_hor, int *skip_ver) {
568   const AV1_COMMON *cm = &cpi->common;
569   MACROBLOCKD *const xd = &x->e_mbd;
570   MB_MODE_INFO *const mbmi = xd->mi[0];
571   const int num_planes = av1_num_planes(cm);
572   const int is_compound = has_second_ref(mbmi);
573   assert(is_intrabc_block(mbmi) == 0);
574   for (int ref = 0; ref < 1 + is_compound; ++ref) {
575     const struct scale_factors *const sf =
576         get_ref_scale_factors_const(cm, mbmi->ref_frame[ref]);
577     // TODO(any): Refine skip flag calculation considering scaling
578     if (av1_is_scaled(sf)) {
579       *skip_hor = 0;
580       *skip_ver = 0;
581       break;
582     }
583     const MV mv = mbmi->mv[ref].as_mv;
584     int skip_hor_plane = 0;
585     int skip_ver_plane = 0;
586     for (int plane_idx = 0; plane_idx < AOMMAX(1, (num_planes - 1));
587          ++plane_idx) {
588       struct macroblockd_plane *const pd = &xd->plane[plane_idx];
589       const int bw = pd->width;
590       const int bh = pd->height;
591       const MV mv_q4 = clamp_mv_to_umv_border_sb(
592           xd, &mv, bw, bh, pd->subsampling_x, pd->subsampling_y);
593       const int sub_x = (mv_q4.col & SUBPEL_MASK) << SCALE_EXTRA_BITS;
594       const int sub_y = (mv_q4.row & SUBPEL_MASK) << SCALE_EXTRA_BITS;
595       skip_hor_plane |= ((sub_x == 0) << plane_idx);
596       skip_ver_plane |= ((sub_y == 0) << plane_idx);
597     }
598     *skip_hor &= skip_hor_plane;
599     *skip_ver &= skip_ver_plane;
600     // It is not valid that "luma MV is sub-pel, whereas chroma MV is not"
601     assert(*skip_hor != 2);
602     assert(*skip_ver != 2);
603   }
604   // When compond prediction type is compound segment wedge, luma MC and chroma
605   // MC need to go hand in hand as mask generated during luma MC is reuired for
606   // chroma MC. If skip_hor = 0 and skip_ver = 1, mask used for chroma MC during
607   // vertical filter decision may be incorrect as temporary MC evaluation
608   // overwrites the mask. Make skip_ver as 0 for this case so that mask is
609   // populated during luma MC
610   if (is_compound && mbmi->compound_idx == 1 &&
611       mbmi->interinter_comp.type == COMPOUND_DIFFWTD) {
612     assert(mbmi->comp_group_idx == 1);
613     if (*skip_hor == 0 && *skip_ver == 1) *skip_ver = 0;
614   }
615 }
616 
617 /*!\brief AV1 interpolation filter search
618  *
619  * \ingroup inter_mode_search
620  *
621  * \param[in]     cpi               Top-level encoder structure.
622  * \param[in]     tile_data         Pointer to struct holding adaptive
623  *                                  data/contexts/models for the tile during
624  *                                  encoding.
625  * \param[in]     x                 Pointer to struc holding all the data for
626  *                                  the current macroblock.
627  * \param[in]     bsize             Current block size.
628  * \param[in]     tmp_dst           A temporary prediction buffer to hold a
629  *                                  computed prediction.
630  * \param[in,out] orig_dst          A prediction buffer to hold a computed
631  *                                  prediction. This will eventually hold the
632  *                                  final prediction, and the tmp_dst info will
633  *                                  be copied here.
634  * \param[in,out] rd                The RD cost associated with the selected
635  *                                  interpolation filter parameters.
636  * \param[in,out] switchable_rate   The rate associated with using a SWITCHABLE
637  *                                  filter mode.
638  * \param[in,out] skip_build_pred   Indicates whether or not to build the inter
639  *                                  predictor. If this is 0, the inter predictor
640  *                                  has already been built and thus we can avoid
641  *                                  repeating computation.
642  * \param[in]     args              HandleInterModeArgs struct holding
643  *                                  miscellaneous arguments for inter mode
644  *                                  search. See the documentation for this
645  *                                  struct for a description of each member.
646  * \param[in]     ref_best_rd       Best RD found so far for this block.
647  *                                  It is used for early termination of this
648  *                                  search if the RD exceeds this value.
649  *
650  * \return Returns INT64_MAX if the filter parameters are invalid and the
651  * current motion mode being tested should be skipped. It returns 0 if the
652  * parameter search is a success.
653  */
av1_interpolation_filter_search(MACROBLOCK * const x,const AV1_COMP * const cpi,const TileDataEnc * tile_data,BLOCK_SIZE bsize,const BUFFER_SET * const tmp_dst,const BUFFER_SET * const orig_dst,int64_t * const rd,int * const switchable_rate,int * skip_build_pred,HandleInterModeArgs * args,int64_t ref_best_rd)654 int64_t av1_interpolation_filter_search(
655     MACROBLOCK *const x, const AV1_COMP *const cpi,
656     const TileDataEnc *tile_data, BLOCK_SIZE bsize,
657     const BUFFER_SET *const tmp_dst, const BUFFER_SET *const orig_dst,
658     int64_t *const rd, int *const switchable_rate, int *skip_build_pred,
659     HandleInterModeArgs *args, int64_t ref_best_rd) {
660   const AV1_COMMON *cm = &cpi->common;
661   const InterpSearchFlags *interp_search_flags = &cpi->interp_search_flags;
662   const int num_planes = av1_num_planes(cm);
663   MACROBLOCKD *const xd = &x->e_mbd;
664   MB_MODE_INFO *const mbmi = xd->mi[0];
665   const int need_search = av1_is_interp_needed(xd);
666   const int ref_frame = xd->mi[0]->ref_frame[0];
667   RD_STATS rd_stats_luma, rd_stats;
668 
669   // Initialization of rd_stats structures with default values
670   av1_init_rd_stats(&rd_stats_luma);
671   av1_init_rd_stats(&rd_stats);
672 
673   int match_found_idx = -1;
674   const InterpFilter assign_filter = cm->features.interp_filter;
675 
676   match_found_idx = find_interp_filter_match(
677       mbmi, cpi, assign_filter, need_search, args->interp_filter_stats,
678       args->interp_filter_stats_idx);
679 
680   if (match_found_idx != -1) {
681     *rd = args->interp_filter_stats[match_found_idx].rd;
682     x->pred_sse[ref_frame] =
683         args->interp_filter_stats[match_found_idx].pred_sse;
684     *skip_build_pred = 0;
685     return 0;
686   }
687 
688   int switchable_ctx[2];
689   switchable_ctx[0] = av1_get_pred_context_switchable_interp(xd, 0);
690   switchable_ctx[1] = av1_get_pred_context_switchable_interp(xd, 1);
691   *switchable_rate =
692       get_switchable_rate(x, mbmi->interp_filters, switchable_ctx,
693                           cm->seq_params->enable_dual_filter);
694 
695   // Do MC evaluation for default filter_type.
696   // Luma MC
697   interp_model_rd_eval(x, cpi, bsize, orig_dst, AOM_PLANE_Y, AOM_PLANE_Y,
698                        &rd_stats_luma, *skip_build_pred);
699 
700 #if CONFIG_COLLECT_RD_STATS == 3
701   RD_STATS rd_stats_y;
702   av1_pick_recursive_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize, INT64_MAX);
703   PrintPredictionUnitStats(cpi, tile_data, x, &rd_stats_y, bsize);
704 #endif  // CONFIG_COLLECT_RD_STATS == 3
705   // Chroma MC
706   if (num_planes > 1) {
707     interp_model_rd_eval(x, cpi, bsize, orig_dst, AOM_PLANE_U, AOM_PLANE_V,
708                          &rd_stats, *skip_build_pred);
709   }
710   *skip_build_pred = 1;
711 
712   av1_merge_rd_stats(&rd_stats, &rd_stats_luma);
713 
714   assert(rd_stats.rate >= 0);
715 
716   *rd = RDCOST(x->rdmult, *switchable_rate + rd_stats.rate, rd_stats.dist);
717   x->pred_sse[ref_frame] = (unsigned int)(rd_stats_luma.sse >> 4);
718 
719   if (assign_filter != SWITCHABLE || match_found_idx != -1) {
720     return 0;
721   }
722   if (!need_search) {
723     int_interpfilters filters = av1_broadcast_interp_filter(EIGHTTAP_REGULAR);
724     assert(mbmi->interp_filters.as_int == filters.as_int);
725     (void)filters;
726     return 0;
727   }
728   if (args->modelled_rd != NULL) {
729     if (has_second_ref(mbmi)) {
730       const int ref_mv_idx = mbmi->ref_mv_idx;
731       MV_REFERENCE_FRAME *refs = mbmi->ref_frame;
732       const int mode0 = compound_ref0_mode(mbmi->mode);
733       const int mode1 = compound_ref1_mode(mbmi->mode);
734       const int64_t mrd = AOMMIN(args->modelled_rd[mode0][ref_mv_idx][refs[0]],
735                                  args->modelled_rd[mode1][ref_mv_idx][refs[1]]);
736       if ((*rd >> 1) > mrd && ref_best_rd < INT64_MAX) {
737         return INT64_MAX;
738       }
739     }
740   }
741 
742   x->recalc_luma_mc_data = 0;
743   // skip_flag=xx (in binary form)
744   // Setting 0th flag corresonds to skipping luma MC and setting 1st bt
745   // corresponds to skipping chroma MC  skip_flag=0 corresponds to "Don't skip
746   // luma and chroma MC"  Skip flag=1 corresponds to "Skip Luma MC only"
747   // Skip_flag=2 is not a valid case
748   // skip_flag=3 corresponds to "Skip both luma and chroma MC"
749   int skip_hor = interp_search_flags->default_interp_skip_flags;
750   int skip_ver = interp_search_flags->default_interp_skip_flags;
751   calc_interp_skip_pred_flag(x, cpi, &skip_hor, &skip_ver);
752 
753   // do interp_filter search
754   restore_dst_buf(xd, *tmp_dst, num_planes);
755   const BUFFER_SET *dst_bufs[2] = { tmp_dst, orig_dst };
756   // Evaluate dual interp filters
757   if (cm->seq_params->enable_dual_filter) {
758     if (cpi->sf.interp_sf.use_fast_interpolation_filter_search) {
759       fast_dual_interp_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
760                                  &rd_stats_luma, &rd_stats, switchable_rate,
761                                  dst_bufs, switchable_ctx, skip_hor, skip_ver);
762     } else {
763       // Use full interpolation filter search
764       uint16_t allowed_interp_mask = ALLOW_ALL_INTERP_FILT_MASK;
765       // REG_REG filter type is evaluated beforehand, so loop is repeated over
766       // REG_SMOOTH to SHARP_SHARP for full interpolation filter search
767       reset_interp_filter_allowed_mask(&allowed_interp_mask, REG_REG);
768       find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd,
769                                  &rd_stats_luma, &rd_stats, switchable_rate,
770                                  dst_bufs, switchable_ctx,
771                                  (skip_hor & skip_ver), allowed_interp_mask, 0);
772     }
773   } else {
774     // Evaluate non-dual interp filters
775     find_best_non_dual_interp_filter(
776         x, cpi, tile_data, bsize, orig_dst, rd, &rd_stats_luma, &rd_stats,
777         switchable_rate, dst_bufs, switchable_ctx, skip_ver, skip_hor);
778   }
779   swap_dst_buf(xd, dst_bufs, num_planes);
780   // Recompute final MC data if required
781   if (x->recalc_luma_mc_data == 1) {
782     // Recomputing final luma MC data is required only if the same was skipped
783     // in either of the directions  Condition below is necessary, but not
784     // sufficient
785     assert((skip_hor == 1) || (skip_ver == 1));
786     const int mi_row = xd->mi_row;
787     const int mi_col = xd->mi_col;
788     av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize,
789                                   AOM_PLANE_Y, AOM_PLANE_Y);
790   }
791   x->pred_sse[ref_frame] = (unsigned int)(rd_stats_luma.sse >> 4);
792 
793   // save search results
794   if (cpi->sf.interp_sf.use_interp_filter) {
795     assert(match_found_idx == -1);
796     args->interp_filter_stats_idx = save_interp_filter_search_stat(
797         mbmi, *rd, x->pred_sse[ref_frame], args->interp_filter_stats,
798         args->interp_filter_stats_idx);
799   }
800   return 0;
801 }
802