tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

interp_search.c (35032B)


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