/*
 * Copyright (c) 2021, Alliance for Open Media. All rights reserved
 *
 * This source code is subject to the terms of the BSD 3-Clause Clear License
 * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
 * License was not distributed with this source code in the LICENSE file, you
 * can obtain it at aomedia.org/license/software-license/bsd-3-c-c/.  If the
 * Alliance for Open Media Patent License 1.0 was not distributed with this
 * source code in the PATENTS file, you can obtain it at
 * aomedia.org/license/patent-license/.
 */

#include <assert.h>
#include <math.h>
#include <stdbool.h>

#include "config/avm_config.h"
#include "config/avm_dsp_rtcd.h"
#include "config/av2_rtcd.h"

#include "avm_dsp/avm_dsp_common.h"
#include "avm_dsp/blend.h"
#include "avm_mem/avm_mem.h"
#include "avm_ports/avm_timer.h"
#include "avm_ports/mem.h"
#include "avm_ports/system_state.h"

#include "av2/common/av2_common_int.h"
#include "av2/common/av2_common_int.h"
#include "av2/common/bru.h"
#include "av2/common/cfl.h"
#include "av2/common/common.h"
#include "av2/common/common_data.h"
#include "av2/common/entropy.h"
#include "av2/common/entropymode.h"
#include "av2/common/idct.h"
#include "av2/common/mvref_common.h"
#include "av2/common/pred_common.h"
#include "av2/common/quant_common.h"
#include "av2/common/reconinter.h"
#include "av2/common/reconintra.h"
#include "av2/common/scan.h"
#include "av2/common/seg_common.h"
#include "av2/common/tip.h"
#include "av2/common/txb_common.h"
#include "av2/common/warped_motion.h"

#include "av2/encoder/aq_variance.h"
#include "av2/encoder/av2_quantize.h"
#include "av2/common/cost.h"
#include "av2/encoder/compound_type.h"
#include "av2/encoder/encodemb.h"
#include "av2/encoder/encodemv.h"
#include "av2/encoder/encoder.h"
#include "av2/encoder/encodetxb.h"
#include "av2/encoder/hybrid_fwd_txfm.h"
#include "av2/encoder/interp_search.h"
#include "av2/encoder/intra_mode_search.h"
#include "av2/encoder/mcomp.h"
#include "av2/encoder/ml.h"
#include "av2/encoder/mode_prune_model_weights.h"
#include "av2/encoder/model_rd.h"
#include "av2/encoder/motion_search_facade.h"
#include "av2/encoder/palette.h"
#include "av2/encoder/random.h"
#include "av2/encoder/ratectrl.h"
#include "av2/encoder/rd.h"
#include "av2/encoder/rdopt.h"
#include "av2/encoder/reconinter_enc.h"
#include "av2/encoder/tokenize.h"
#include "av2/encoder/tpl_model.h"
#include "av2/encoder/tx_search.h"
#include "av2/encoder/partition_strategy.h"

// Mode_threshold multiplication factor table for prune_inter_modes_if_skippable
// The values are kept in Q12 format and equation used to derive is
// (2.5 - ((float)x->qindex / MAXQ) * 1.5)
#define MODE_THRESH_QBITS 12
static const int mode_threshold_mul_factor[QINDEX_RANGE] = {
  10240, 10216, 10192, 10168, 10144, 10120, 10095, 10071, 10047, 10023, 9999,
  9975,  9951,  9927,  9903,  9879,  9854,  9830,  9806,  9782,  9758,  9734,
  9710,  9686,  9662,  9638,  9614,  9589,  9565,  9541,  9517,  9493,  9469,
  9445,  9421,  9397,  9373,  9349,  9324,  9300,  9276,  9252,  9228,  9204,
  9180,  9156,  9132,  9108,  9083,  9059,  9035,  9011,  8987,  8963,  8939,
  8915,  8891,  8867,  8843,  8818,  8794,  8770,  8746,  8722,  8698,  8674,
  8650,  8626,  8602,  8578,  8553,  8529,  8505,  8481,  8457,  8433,  8409,
  8385,  8361,  8337,  8312,  8288,  8264,  8240,  8216,  8192,  8168,  8144,
  8120,  8096,  8072,  8047,  8023,  7999,  7975,  7951,  7927,  7903,  7879,
  7855,  7831,  7806,  7782,  7758,  7734,  7710,  7686,  7662,  7638,  7614,
  7590,  7566,  7541,  7517,  7493,  7469,  7445,  7421,  7397,  7373,  7349,
  7325,  7301,  7276,  7252,  7228,  7204,  7180,  7156,  7132,  7108,  7084,
  7060,  7035,  7011,  6987,  6963,  6939,  6915,  6891,  6867,  6843,  6819,
  6795,  6770,  6746,  6722,  6698,  6674,  6650,  6626,  6602,  6578,  6554,
  6530,  6505,  6481,  6457,  6433,  6409,  6385,  6361,  6337,  6313,  6289,
  6264,  6240,  6216,  6192,  6168,  6144,  6120,  6096,  6072,  6048,  6024,
  5999,  5975,  5951,  5927,  5903,  5879,  5855,  5831,  5807,  5783,  5758,
  5734,  5710,  5686,  5662,  5638,  5614,  5590,  5566,  5542,  5518,  5493,
  5469,  5445,  5421,  5397,  5373,  5349,  5325,  5301,  5277,  5253,  5228,
  5204,  5180,  5156,  5132,  5108,  5084,  5060,  5036,  5012,  4987,  4963,
  4939,  4915,  4891,  4867,  4843,  4819,  4795,  4771,  4747,  4722,  4698,
  4674,  4650,  4626,  4602,  4578,  4554,  4530,  4506,  4482,  4457,  4433,
  4409,  4385,  4361,  4337,  4313,  4289,  4265,  4241,  4216,  4192,  4168,
  4144,  4120,  4096
};

/*!\cond */
typedef struct SingleInterModeState {
  int64_t rd;
  MV_REFERENCE_FRAME ref_frame;
  int valid;
} SingleInterModeState;

typedef struct InterModeSearchState {
  int64_t best_rd;
  int64_t best_skip_rd[2];
  MB_MODE_INFO best_mbmode;
  SUBMB_INFO best_submb[MAX_MIB_SIZE * MAX_MIB_SIZE];
  int best_rate_y;
  int best_rate_uv;
  int best_mode_skippable;
  int best_skip2;
  int64_t dist_refs[REF_FRAMES];
  int dist_order_refs[REF_FRAMES];
  int64_t mode_threshold[MB_MODE_COUNT];
  int64_t best_intra_rd;
  int64_t best_pred_diff[REFERENCE_MODES];

  // Save a set of single_newmv for each checked ref_mv.
  int_mv single_newmv[NUM_MV_PRECISIONS][MAX_REF_MV_SEARCH][SINGLE_REF_FRAMES];
  int single_newmv_rate[NUM_MV_PRECISIONS][MAX_REF_MV_SEARCH]
                       [SINGLE_REF_FRAMES];
  int single_newmv_valid[NUM_MV_PRECISIONS][MAX_REF_MV_SEARCH]
                        [SINGLE_REF_FRAMES];

  int64_t modelled_rd[MB_MODE_COUNT][MAX_REF_MV_SEARCH][SINGLE_REF_FRAMES];
  // The rd of simple translation in single inter modes
  int64_t simple_rd[MB_MODE_COUNT][MAX_REF_MV_SEARCH][SINGLE_REF_FRAMES];
  int64_t best_single_rd[SINGLE_REF_FRAMES];
  PREDICTION_MODE best_single_mode[SINGLE_REF_FRAMES];

  // Single search results by [directions][modes][reference frames]
  int single_state_cnt[2][SINGLE_INTER_MODE_NUM];
  int single_state_modelled_cnt[2][SINGLE_INTER_MODE_NUM];
  SingleInterModeState single_state[2][SINGLE_INTER_MODE_NUM]
                                   [SINGLE_REF_FRAMES];
  SingleInterModeState single_state_modelled[2][SINGLE_INTER_MODE_NUM]
                                            [SINGLE_REF_FRAMES];
  MV_REFERENCE_FRAME single_rd_order[2][SINGLE_INTER_MODE_NUM]
                                    [SINGLE_REF_FRAMES];
  IntraModeSearchState intra_search_state;
} InterModeSearchState;
/*!\endcond */

void av2_inter_mode_data_init(TileDataEnc *tile_data) {
  for (int i = 0; i < BLOCK_SIZES_ALL; ++i) {
    InterModeRdModel *md = &tile_data->inter_mode_rd_models[i];
    md->ready = 0;
    md->num = 0;
    md->dist_sum = 0;
    md->ld_sum = 0;
    md->sse_sum = 0;
    md->sse_sse_sum = 0;
    md->sse_ld_sum = 0;
  }
}

static int get_est_rate_dist(const TileDataEnc *tile_data, BLOCK_SIZE bsize,
                             int64_t sse, int *est_residue_cost,
                             int64_t *est_dist) {
  avm_clear_system_state();
  const InterModeRdModel *md = &tile_data->inter_mode_rd_models[bsize];
  if (md->ready) {
    if (sse < md->dist_mean) {
      *est_residue_cost = 0;
      *est_dist = sse;
    } else {
      *est_dist = (int64_t)round(md->dist_mean);
      const double est_ld = md->a * sse + md->b;
      // Clamp estimated rate cost by INT_MAX / 2.
      // TODO(angiebird@google.com): find better solution than clamping.
      if (fabs(est_ld) < 1e-2) {
        *est_residue_cost = INT_MAX / 2;
      } else {
        double est_residue_cost_dbl = ((sse - md->dist_mean) / est_ld);
        if (est_residue_cost_dbl < 0) {
          *est_residue_cost = 0;
        } else {
          *est_residue_cost =
              (int)AVMMIN((int64_t)round(est_residue_cost_dbl), INT_MAX / 2);
        }
      }
      if (*est_residue_cost <= 0) {
        *est_residue_cost = 0;
        *est_dist = sse;
      }
    }
    return 1;
  }
  return 0;
}

void av2_inter_mode_data_fit(TileDataEnc *tile_data, int rdmult) {
  avm_clear_system_state();
  for (int bsize = 0; bsize < BLOCK_SIZES_ALL; ++bsize) {
    const int block_idx = inter_mode_data_block_idx(bsize);
    InterModeRdModel *md = &tile_data->inter_mode_rd_models[bsize];
    if (block_idx == -1) continue;
    if ((md->ready == 0 && md->num < 200) || (md->ready == 1 && md->num < 64)) {
      continue;
    } else {
      if (md->ready == 0) {
        md->dist_mean = md->dist_sum / md->num;
        md->ld_mean = md->ld_sum / md->num;
        md->sse_mean = md->sse_sum / md->num;
        md->sse_sse_mean = md->sse_sse_sum / md->num;
        md->sse_ld_mean = md->sse_ld_sum / md->num;
      } else {
        const double factor = 3;
        md->dist_mean =
            (md->dist_mean * factor + (md->dist_sum / md->num)) / (factor + 1);
        md->ld_mean =
            (md->ld_mean * factor + (md->ld_sum / md->num)) / (factor + 1);
        md->sse_mean =
            (md->sse_mean * factor + (md->sse_sum / md->num)) / (factor + 1);
        md->sse_sse_mean =
            (md->sse_sse_mean * factor + (md->sse_sse_sum / md->num)) /
            (factor + 1);
        md->sse_ld_mean =
            (md->sse_ld_mean * factor + (md->sse_ld_sum / md->num)) /
            (factor + 1);
      }

      const double my = md->ld_mean;
      const double mx = md->sse_mean;
      const double dx = sqrt(md->sse_sse_mean);
      const double dxy = md->sse_ld_mean;

      if (mx == dx) {
        // Avoid division by 0
        // Reset all mean values and retain all the "sum" variables to continue
        // collecting data
        md->ready = 0;
        md->dist_mean = 0;
        md->ld_mean = 0;
        md->sse_mean = 0;
        md->sse_sse_mean = 0;
        md->sse_ld_mean = 0;
        continue;
      }

      md->a = (dxy - mx * my) / (dx * dx - mx * mx);
      md->b = my - md->a * mx;
      md->ready = 1;

      md->num = 0;
      md->dist_sum = 0;
      md->ld_sum = 0;
      md->sse_sum = 0;
      md->sse_sse_sum = 0;
      md->sse_ld_sum = 0;
    }
    (void)rdmult;
  }
}

static AVM_INLINE void inter_mode_data_push(TileDataEnc *tile_data,
                                            BLOCK_SIZE bsize, int64_t sse,
                                            int64_t dist, int residue_cost) {
  if (residue_cost == 0 || sse == dist) return;
  const int block_idx = inter_mode_data_block_idx(bsize);
  if (block_idx == -1) return;
  InterModeRdModel *rd_model = &tile_data->inter_mode_rd_models[bsize];
  if (rd_model->num < INTER_MODE_RD_DATA_OVERALL_SIZE) {
    avm_clear_system_state();
    const double ld = (sse - dist) * 1. / residue_cost;
    ++rd_model->num;
    rd_model->dist_sum += dist;
    rd_model->ld_sum += ld;
    rd_model->sse_sum += sse;
    rd_model->sse_sse_sum += (double)sse * (double)sse;
    rd_model->sse_ld_sum += sse * ld;
  }
}

static AVM_INLINE void inter_modes_info_push(InterModesInfo *inter_modes_info,
                                             int mode_rate, int64_t sse,
                                             int64_t rd,
                                             const MB_MODE_INFO *mbmi) {
  const int num = inter_modes_info->num;
  assert(num < MAX_INTER_MODES);
  inter_modes_info->mbmi_arr[num] = *mbmi;
  inter_modes_info->mode_rate_arr[num] = mode_rate;
  inter_modes_info->sse_arr[num] = sse;
  inter_modes_info->est_rd_arr[num] = rd;
  ++inter_modes_info->num;
}

static int compare_rd_idx_pair(const void *a, const void *b) {
  if (((RdIdxPair *)a)->rd == ((RdIdxPair *)b)->rd) {
    // To avoid inconsistency in qsort() ordering when two elements are equal,
    // using idx as tie breaker. Refer aomedia:2928
    if (((RdIdxPair *)a)->idx == ((RdIdxPair *)b)->idx)
      return 0;
    else if (((RdIdxPair *)a)->idx > ((RdIdxPair *)b)->idx)
      return 1;
    else
      return -1;
  } else if (((const RdIdxPair *)a)->rd > ((const RdIdxPair *)b)->rd) {
    return 1;
  } else {
    return -1;
  }
}

static AVM_INLINE void inter_modes_info_sort(
    const InterModesInfo *inter_modes_info, RdIdxPair *rd_idx_pair_arr) {
  if (inter_modes_info->num == 0) {
    return;
  }
  for (int i = 0; i < inter_modes_info->num; ++i) {
    rd_idx_pair_arr[i].idx = i;
    rd_idx_pair_arr[i].rd = inter_modes_info->est_rd_arr[i];
  }
  qsort(rd_idx_pair_arr, inter_modes_info->num, sizeof(rd_idx_pair_arr[0]),
        compare_rd_idx_pair);
}

// Similar to get_horver_correlation, but also takes into account first
// row/column, when computing horizontal/vertical correlation.
void av2_get_horver_correlation_full_c(const int16_t *diff, int stride,
                                       int width, int height, float *hcorr,
                                       float *vcorr) {
  // The following notation is used:
  // x - current pixel
  // y - left neighbor pixel
  // z - top neighbor pixel
  int64_t x_sum = 0, x2_sum = 0, xy_sum = 0, xz_sum = 0;
  int64_t x_firstrow = 0, x_finalrow = 0, x_firstcol = 0, x_finalcol = 0;
  int64_t x2_firstrow = 0, x2_finalrow = 0, x2_firstcol = 0, x2_finalcol = 0;

  // First, process horizontal correlation on just the first row
  x_sum += diff[0];
  x2_sum += diff[0] * diff[0];
  x_firstrow += diff[0];
  x2_firstrow += diff[0] * diff[0];
  for (int j = 1; j < width; ++j) {
    const int16_t x = diff[j];
    const int16_t y = diff[j - 1];
    x_sum += x;
    x_firstrow += x;
    x2_sum += x * x;
    x2_firstrow += x * x;
    xy_sum += x * y;
  }

  // Process vertical correlation in the first column
  x_firstcol += diff[0];
  x2_firstcol += diff[0] * diff[0];
  for (int i = 1; i < height; ++i) {
    const int16_t x = diff[i * stride];
    const int16_t z = diff[(i - 1) * stride];
    x_sum += x;
    x_firstcol += x;
    x2_sum += x * x;
    x2_firstcol += x * x;
    xz_sum += x * z;
  }

  // Now process horiz and vert correlation through the rest unit
  for (int i = 1; i < height; ++i) {
    for (int j = 1; j < width; ++j) {
      const int16_t x = diff[i * stride + j];
      const int16_t y = diff[i * stride + j - 1];
      const int16_t z = diff[(i - 1) * stride + j];
      x_sum += x;
      x2_sum += x * x;
      xy_sum += x * y;
      xz_sum += x * z;
    }
  }

  for (int j = 0; j < width; ++j) {
    x_finalrow += diff[(height - 1) * stride + j];
    x2_finalrow +=
        diff[(height - 1) * stride + j] * diff[(height - 1) * stride + j];
  }
  for (int i = 0; i < height; ++i) {
    x_finalcol += diff[i * stride + width - 1];
    x2_finalcol += diff[i * stride + width - 1] * diff[i * stride + width - 1];
  }

  int64_t xhor_sum = x_sum - x_finalcol;
  int64_t xver_sum = x_sum - x_finalrow;
  int64_t y_sum = x_sum - x_firstcol;
  int64_t z_sum = x_sum - x_firstrow;
  int64_t x2hor_sum = x2_sum - x2_finalcol;
  int64_t x2ver_sum = x2_sum - x2_finalrow;
  int64_t y2_sum = x2_sum - x2_firstcol;
  int64_t z2_sum = x2_sum - x2_firstrow;

  const float num_hor = (float)(height * (width - 1));
  const float num_ver = (float)((height - 1) * width);

  const float xhor_var_n = x2hor_sum - (xhor_sum * xhor_sum) / num_hor;
  const float xver_var_n = x2ver_sum - (xver_sum * xver_sum) / num_ver;

  const float y_var_n = y2_sum - (y_sum * y_sum) / num_hor;
  const float z_var_n = z2_sum - (z_sum * z_sum) / num_ver;

  const float xy_var_n = xy_sum - (xhor_sum * y_sum) / num_hor;
  const float xz_var_n = xz_sum - (xver_sum * z_sum) / num_ver;

  if (xhor_var_n > 0 && y_var_n > 0) {
    *hcorr = xy_var_n / sqrtf(xhor_var_n * y_var_n);
    *hcorr = *hcorr < 0 ? 0 : *hcorr;
  } else {
    *hcorr = 1.0;
  }
  if (xver_var_n > 0 && z_var_n > 0) {
    *vcorr = xz_var_n / sqrtf(xver_var_n * z_var_n);
    *vcorr = *vcorr < 0 ? 0 : *vcorr;
  } else {
    *vcorr = 1.0;
  }
}

static int64_t get_sse(const AV2_COMP *cpi, const MACROBLOCK *x,
                       int64_t *sse_y) {
  const AV2_COMMON *cm = &cpi->common;
  const int num_planes = av2_num_planes(cm);
  const MACROBLOCKD *xd = &x->e_mbd;
  const MB_MODE_INFO *mbmi = xd->mi[0];
  int64_t total_sse = 0;
  for (int plane = 0; plane < num_planes; ++plane) {
    if (plane && !xd->is_chroma_ref) break;
    const struct macroblock_plane *const p = &x->plane[plane];
    const struct macroblockd_plane *const pd = &xd->plane[plane];
    const BLOCK_SIZE bs = get_mb_plane_block_size(
        xd, mbmi, plane, pd->subsampling_x, pd->subsampling_y);
    unsigned int sse;

    cpi->fn_ptr[bs].vf(p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride,
                       &sse);
    total_sse += sse;
    if (!plane && sse_y) *sse_y = sse;
  }
  total_sse <<= 4;
  return total_sse;
}

int64_t av2_highbd_block_error_c(const tran_low_t *coeff,
                                 const tran_low_t *dqcoeff, intptr_t block_size,
                                 int64_t *ssz, int bd) {
  int i;
  int64_t error = 0, sqcoeff = 0;
  int shift = 2 * (bd - 8);
  int rounding = shift > 0 ? 1 << (shift - 1) : 0;

  for (i = 0; i < block_size; i++) {
    const int64_t diff = coeff[i] - dqcoeff[i];
    error += diff * diff;
    sqcoeff += (int64_t)coeff[i] * (int64_t)coeff[i];
  }
  assert(error >= 0 && sqcoeff >= 0);
  error = (error + rounding) >> shift;
  sqcoeff = (sqcoeff + rounding) >> shift;

  *ssz = sqcoeff;
  return error;
}

static int cost_prediction_mode(const ModeCosts *const mode_costs,
                                PREDICTION_MODE mode, const AV2_COMMON *cm,
                                const MB_MODE_INFO *const mbmi,
                                const MACROBLOCKD *xd, int16_t mode_context) {
  int amvd_index = amvd_mode_to_index(mbmi->mode);
  int amvd_ctx = get_amvd_context(xd);
  int amvd_mode_cost =
      allow_amvd_mode(mbmi->mode)
          ? mode_costs->amvd_mode_cost[amvd_index][amvd_ctx][mbmi->use_amvd]
          : 0;

  if (is_inter_compound_mode(mode)) {
    int use_optical_flow_cost = 0;
    const int comp_mode_idx = opfl_get_comp_idx(mode);
    if (cm->features.opfl_refine_type == REFINE_SWITCHABLE &&
        opfl_allowed_cur_refs_bsize(cm, xd, mbmi)) {
      const int use_optical_flow = mode >= NEAR_NEARMV_OPTFLOW;
      const int opfl_ctx =
          get_optflow_context(comp_idx_to_opfl_mode[comp_mode_idx]);
      use_optical_flow_cost +=
          mode_costs->use_optflow_cost[opfl_ctx][use_optical_flow];
    }

    if (is_new_nearmv_pred_mode_disallowed(mbmi)) {
      const int signal_mode_idx =
          comp_mode_idx_to_mode_signal_idx[comp_mode_idx];
      return use_optical_flow_cost +
             mode_costs->inter_compound_mode_same_refs_cost[mode_context]
                                                           [signal_mode_idx];
    } else {
      const bool is_joint =
          (comp_mode_idx == INTER_COMPOUND_OFFSET(JOINT_NEWMV));
      int cost_by_inter_by_joint =
          mode_costs->inter_compound_mode_is_joint_cost
              [get_inter_compound_mode_is_joint_context(cm, mbmi)][is_joint];

      if (!is_joint) {
        cost_by_inter_by_joint +=
            mode_costs->inter_compound_mode_non_joint_type_cost[mode_context]
                                                               [comp_mode_idx];
      }
      return use_optical_flow_cost + amvd_mode_cost + cost_by_inter_by_joint;
    }
  }

  assert(is_inter_mode(mode));

  if (is_tip_ref_frame(mbmi->ref_frame[0])) {
    const int tip_pred_index =
        tip_pred_mode_to_index[mode - SINGLE_INTER_MODE_START];
    return mode_costs->tip_mode_cost[tip_pred_index];
  }

  int warp_mode_cost = 0;
  if (is_warpmv_mode_allowed(cm, mbmi, mbmi->sb_type[PLANE_TYPE_Y])) {
    const int16_t iswarpmvmode_ctx = inter_warpmv_mode_ctx(cm, xd, mbmi);
    const BLOCK_SIZE bsize = mbmi->sb_type[xd->tree_type == CHROMA_PART];
    const int is_warpmv_or_warp_newmv = (mode == WARPMV || mode == WARP_NEWMV);
    warp_mode_cost =
        mode_costs
            ->inter_warp_mode_cost[iswarpmvmode_ctx][is_warpmv_or_warp_newmv];
    if (is_warpmv_or_warp_newmv) {
      if (is_warp_newmv_allowed(cm, xd, mbmi, bsize)) {
        warp_mode_cost +=
            mode_costs->is_warpmv_or_warp_newmv_cost[mode == WARPMV];
      }
      return warp_mode_cost;
    }
  }

  const int16_t ismode_ctx = inter_single_mode_ctx(mode_context);
  return (mode_costs->inter_single_mode_cost[ismode_ctx]
                                            [mode - SINGLE_INTER_MODE_START] +
          amvd_mode_cost + warp_mode_cost);
}

static int cost_mv_precision(const ModeCosts *const mode_costs,
                             MvSubpelPrecision max_mv_precision,
                             MvSubpelPrecision pb_mv_precision,
                             const int down_ctx,
                             MvSubpelPrecision most_probable_pb_mv_precision,
                             const int mpp_flag_context,
                             const MB_MODE_INFO *mbmi) {
  int flex_mv_cost = 0;
  const int mpp_flag = (pb_mv_precision == most_probable_pb_mv_precision);
  flex_mv_cost +=
      (mode_costs->pb_block_mv_mpp_flag_costs[mpp_flag_context][mpp_flag]);

  if (!mpp_flag) {
    int down = av2_get_pb_mv_precision_index(mbmi);
    assert(down >= 0);

    flex_mv_cost +=
        (mode_costs->pb_block_mv_precision_costs[down_ctx]
                                                [max_mv_precision -
                                                 MV_PRECISION_HALF_PEL][down]);
  }

  return flex_mv_cost;
}

static INLINE PREDICTION_MODE get_single_mode(PREDICTION_MODE this_mode,
                                              int ref_idx) {
  return ref_idx ? compound_ref1_mode(this_mode)
                 : compound_ref0_mode(this_mode);
}

static AVM_INLINE void estimate_ref_frame_costs(
    const AV2_COMMON *cm, const MACROBLOCKD *xd, const ModeCosts *mode_costs,
    int segment_id, unsigned int *ref_costs_single,
    unsigned int (*ref_costs_comp)[MAX_COMPOUND_REF_INDEX]) {
  (void)segment_id;
  int seg_ref_active = 0;
  if (seg_ref_active) {
    memset(ref_costs_single, 0, SINGLE_REF_FRAMES * sizeof(*ref_costs_single));
    int ref_frame;
    for (ref_frame = 0; ref_frame < MAX_COMPOUND_REF_INDEX; ++ref_frame)
      memset(ref_costs_comp[ref_frame], 0,
             MAX_COMPOUND_REF_INDEX * sizeof((*ref_costs_comp)[0]));
  } else {
    unsigned int base_cost = 0;

    int intra_inter_ctx = av2_get_intra_inter_context(xd);
    int is_intra_allowed = 1;
    MB_MODE_INFO *const mbmi = xd->mi[0];
    if (mbmi->tree_type == SHARED_PART &&
        mbmi->region_type == MIXED_INTER_INTRA_REGION &&
        mbmi->chroma_ref_info.offset_started) {
      is_intra_allowed = 0;
    }
    if (is_intra_allowed) {
      ref_costs_single[INTRA_FRAME_INDEX] =
          base_cost + mode_costs->intra_inter_cost[intra_inter_ctx][0];
      base_cost += mode_costs->intra_inter_cost[intra_inter_ctx][1];
    }
    if (xd->mi[0]->sb_type[PLANE_TYPE_Y] == BLOCK_4X4) {
      ref_costs_single[INTRA_FRAME_INDEX] = 0;
    }

    if (is_tip_allowed(cm, xd)) {
      const int tip_ctx = get_tip_ctx(xd);
      ref_costs_single[TIP_FRAME_INDEX] =
          base_cost + mode_costs->tip_cost[tip_ctx][1];
      base_cost += mode_costs->tip_cost[tip_ctx][0];
    }

    for (int i = 0; i < INTER_REFS_PER_FRAME; ++i)
      ref_costs_single[i] = base_cost;

    const int n_refs = cm->ref_frames_info.num_total_refs;
    for (int i = 0; i < n_refs; i++) {
      if (cm->bru.enabled && i == cm->bru.update_ref_idx) {
        ref_costs_single[i] = INT_MAX;  // set bru ref cost max to prevent
                                        // inter pred from bru ref frames
        continue;
      }
      for (int j = 0; j <= AVMMIN(i, n_refs - 2); j++) {
        if (cm->bru.enabled && j == cm->bru.update_ref_idx) {
          continue;
        }
        avm_cdf_prob ctx = av2_get_ref_pred_context(xd, j, n_refs);
        const int bit = i == j;
        ref_costs_single[i] += mode_costs->single_ref_cost[ctx][j][bit];
      }
    }

    for (int i = n_refs; i < INTER_REFS_PER_FRAME; i++)
      ref_costs_single[i] = INT_MAX;

    if (cm->current_frame.reference_mode != SINGLE_REFERENCE) {
      for (int i = 0; i < MAX_COMPOUND_REF_INDEX; i++) {
        for (int j = 0; j < MAX_COMPOUND_REF_INDEX; j++)
          ref_costs_comp[i][j] = INT_MAX;
      }

      int use_same_ref_comp = cm->ref_frames_info.num_same_ref_compound > 0;
      for (int i = 0; i < n_refs + use_same_ref_comp - 1; i++) {
        if (i >= RANKED_REF0_TO_PRUNE) break;
        if (cm->bru.enabled && i == cm->bru.update_ref_idx) {
          continue;
        }
        if (i == n_refs - 1 && i >= cm->ref_frames_info.num_same_ref_compound)
          break;
        int prev_cost = base_cost;
        for (int j = 0; j < n_refs; j++) {
          int implicit_ref0_bit =
              j >= RANKED_REF0_TO_PRUNE - 1 ||
              (i == j && i < cm->ref_frames_info.num_same_ref_compound &&
               i + 1 >= cm->ref_frames_info.num_same_ref_compound &&
               i >= n_refs - 2);
          int implicit_ref0_ref1_bits =
              j >= n_refs - 2 && j >= cm->ref_frames_info.num_same_ref_compound;
          if (j <= i) {
            if (cm->bru.enabled && j == cm->bru.update_ref_idx) {
              continue;
            }
            // Keep track of the cost to encode the first reference
            avm_cdf_prob ctx = av2_get_ref_pred_context(xd, j, n_refs);
            const int bit = i == j;
            if (!implicit_ref0_bit && !implicit_ref0_ref1_bits)
              prev_cost += mode_costs->comp_ref0_cost[ctx][j][bit];
          }
          if (j > i ||
              (j == i && i < cm->ref_frames_info.num_same_ref_compound)) {
            // Assign the cost of signaling both references
            ref_costs_comp[i][j] = prev_cost;
            if (j < n_refs - 1) {
              if (cm->bru.enabled && j == cm->bru.update_ref_idx) {
                ref_costs_comp[i][j] = INT_MAX;
                ref_costs_comp[j][i] = INT_MAX;
                continue;
              }
              avm_cdf_prob ctx = av2_get_ref_pred_context(xd, j, n_refs);
              const int bit_type =
                  av2_get_compound_ref_bit_type(&cm->ref_frames_info, i, j);
              if (cm->bru.enabled &&
                  (i == cm->bru.update_ref_idx || j == cm->bru.update_ref_idx))
                continue;
              ref_costs_comp[i][j] +=
                  mode_costs->comp_ref1_cost[ctx][bit_type][j][1];
              // Maintain the cost of sending a 0 bit for the 2nd reference to
              // be used in the next iteration.
              prev_cost += mode_costs->comp_ref1_cost[ctx][bit_type][j][0];
            }
          }
        }
      }
#ifndef NDEBUG
      for (int i = 0; i < n_refs - 1; i++) {
        for (int j = i + 1; j < n_refs; j++) {
          if (cm->bru.enabled &&
              (i == cm->bru.update_ref_idx || j == cm->bru.update_ref_idx))
            continue;
          if (i < RANKED_REF0_TO_PRUNE) assert(ref_costs_comp[i][j] != INT_MAX);
        }
      }
#endif  // NDEBUG
    } else {
      for (int ref0 = 0; ref0 < MAX_COMPOUND_REF_INDEX; ++ref0) {
        for (int ref1 = ref0 + 1; ref1 < MAX_COMPOUND_REF_INDEX; ++ref1) {
          ref_costs_comp[ref0][ref1] = 512;
          ref_costs_comp[ref1][ref0] = 512;
        }
      }
    }
  }
}

void store_submi(const MACROBLOCKD *const xd, const AV2_COMMON *cm,
                 SUBMB_INFO *dst_submi, BLOCK_SIZE bsize) {
  const int bw = mi_size_wide[bsize];
  const int bh = mi_size_high[bsize];
  const int mi_row = xd->mi_row;
  const int mi_col = xd->mi_col;
  const int x_inside_boundary = AVMMIN(bw, cm->mi_params.mi_cols - mi_col);
  const int y_inside_boundary = AVMMIN(bh, cm->mi_params.mi_rows - mi_row);
  const int dst_stride = bw;
  const int src_stride = cm->mi_params.mi_stride;
  for (int y = 0; y < y_inside_boundary; y++) {
    for (int x = 0; x < x_inside_boundary; x++) {
      dst_submi[y * dst_stride + x] = *xd->submi[y * src_stride + x];
    }
  }
}

void update_submi(MACROBLOCKD *const xd, const AV2_COMMON *cm,
                  const SUBMB_INFO *src_submi, BLOCK_SIZE bsize) {
  const int bw = mi_size_wide[bsize];
  const int bh = mi_size_high[bsize];
  const int mi_row = xd->mi_row;
  const int mi_col = xd->mi_col;
  const int x_inside_boundary = AVMMIN(bw, cm->mi_params.mi_cols - mi_col);
  const int y_inside_boundary = AVMMIN(bh, cm->mi_params.mi_rows - mi_row);
  const int src_stride = bw;
  const int dst_stride = cm->mi_params.mi_stride;
  for (int y = 0; y < y_inside_boundary; y++) {
    for (int x = 0; x < x_inside_boundary; x++) {
      *xd->submi[y * dst_stride + x] = src_submi[y * src_stride + x];
    }
  }
}

static AVM_INLINE void store_coding_context(
    MACROBLOCK *x, PICK_MODE_CONTEXT *ctx,
    int64_t comp_pred_diff[REFERENCE_MODES], int skippable,
    const AV2_COMMON *cm) {
  MACROBLOCKD *const xd = &x->e_mbd;

  // Take a snapshot of the coding context so it can be
  // restored if we decide to encode this way
  ctx->rd_stats.skip_txfm = x->txfm_search_info.skip_txfm;
  ctx->skippable = skippable;
  ctx->mic = *xd->mi[0];
  if (is_warp_mode(xd->mi[0]->motion_mode)) {
    store_submi(xd, cm, ctx->submic, xd->mi[0]->sb_type[PLANE_TYPE_Y]);
  }
  if (xd->tree_type != CHROMA_PART)
    av2_copy_mbmi_ext_to_mbmi_ext_frame(
        &ctx->mbmi_ext_best, x->mbmi_ext, xd->mi[0], xd->mi[0]->skip_mode,
        av2_ref_frame_type(xd->mi[0]->ref_frame));
  ctx->single_pred_diff = (int)comp_pred_diff[SINGLE_REFERENCE];
  ctx->comp_pred_diff = (int)comp_pred_diff[COMPOUND_REFERENCE];
  ctx->hybrid_pred_diff = (int)comp_pred_diff[REFERENCE_MODE_SELECT];
}

static AVM_INLINE void setup_buffer_ref_mvs_inter(
    const AV2_COMP *const cpi, MACROBLOCK *x, MV_REFERENCE_FRAME ref_frame,
    BLOCK_SIZE block_size,
    struct buf_2d yv12_mb[SINGLE_REF_FRAMES][MAX_MB_PLANE]) {
  const AV2_COMMON *cm = &cpi->common;
  const int num_planes = av2_num_planes(cm);
  const YV12_BUFFER_CONFIG *scaled_ref_frame =
      av2_get_scaled_ref_frame(cpi, ref_frame);
  MACROBLOCKD *const xd = &x->e_mbd;
  MB_MODE_INFO *const mbmi = xd->mi[0];
  MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
  const struct scale_factors *const sf =
      get_ref_scale_factors_const(cm, ref_frame);
  const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_yv12_buf(cm, ref_frame);
  assert(yv12 != NULL);

  const int ref_frame_idx = COMPACT_INDEX0_NRS(ref_frame);

  if (scaled_ref_frame) {
    // Setup pred block based on scaled reference, because av2_mv_pred() doesn't
    // support scaling.
    av2_setup_pred_block(xd, yv12_mb[ref_frame_idx], scaled_ref_frame, NULL,
                         NULL, num_planes);
  } else {
    av2_setup_pred_block(xd, yv12_mb[ref_frame_idx], yv12, sf, sf, num_planes);
  }

  if (mbmi->skip_mode) {
    // Go back to unscaled reference.
    if (scaled_ref_frame) {
      // We had temporarily setup pred block based on scaled reference above. Go
      // back to unscaled reference now, for subsequent use.
      av2_setup_pred_block(xd, yv12_mb[ref_frame_idx], yv12, sf, sf,
                           num_planes);
    }

    return;
  }

  // Gets an initial list of candidate vectors from neighbours and orders them
  av2_find_mv_refs(
      cm, xd, mbmi, ref_frame, mbmi_ext->ref_mv_count, xd->ref_mv_stack,
      xd->weight, NULL, mbmi_ext->global_mvs, xd->warp_param_stack,
      ref_frame < INTER_REFS_PER_FRAME ? MAX_WARP_REF_CANDIDATES : 0,
      xd->valid_num_warp_candidates);

  av2_find_mode_ctx(cm, xd, mbmi_ext->mode_context, ref_frame);

  // TODO(Ravi): Populate mbmi_ext->ref_mv_stack[ref_frame][4] and
  // mbmi_ext->weight[ref_frame][4] inside av2_find_mv_refs.
  av2_copy_usable_ref_mv_stack_and_weight(xd, mbmi_ext, ref_frame);
  // Further refinement that is encode side only to test the top few candidates
  // in full and choose the best as the center point for subsequent searches.
  // The current implementation doesn't support scaling.
  av2_mv_pred(cpi, x, yv12_mb[ref_frame_idx][0].buf,
              yv12_mb[ref_frame_idx][0].stride, ref_frame, block_size);

  // Go back to unscaled reference.
  if (scaled_ref_frame) {
    // We had temporarily setup pred block based on scaled reference above. Go
    // back to unscaled reference now, for subsequent use.
    av2_setup_pred_block(xd, yv12_mb[ref_frame_idx], yv12, sf, sf, num_planes);
  }
}

#define LEFT_TOP_MARGIN ((AVM_BORDER_IN_PIXELS - AVM_INTERP_EXTEND) << 3)
#define RIGHT_BOTTOM_MARGIN ((AVM_BORDER_IN_PIXELS - AVM_INTERP_EXTEND) << 3)

// TODO(jingning): this mv clamping function should be block size dependent.
static INLINE void clamp_mv2(MV *mv, const MACROBLOCKD *xd) {
  const SubpelMvLimits mv_limits = { xd->mb_to_left_edge - LEFT_TOP_MARGIN,
                                     xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN,
                                     xd->mb_to_top_edge - LEFT_TOP_MARGIN,
                                     xd->mb_to_bottom_edge +
                                         RIGHT_BOTTOM_MARGIN };
  clamp_mv(mv, &mv_limits);
}

/* If the current mode shares the same mv with other modes with higher cost,
 * skip this mode. */
static int skip_repeated_mv(const AV2_COMMON *const cm,
                            const MACROBLOCK *const x,
                            PREDICTION_MODE this_mode,
                            const MV_REFERENCE_FRAME ref_frames[2],
                            InterModeSearchState *search_state) {
  if (is_tip_ref_frame(ref_frames[0])) return 0;
  const int is_comp_pred = is_inter_ref_frame(ref_frames[1]);
  if (is_comp_pred) {
    return 0;
  }
  if (!(this_mode == GLOBALMV || this_mode == NEARMV)) {
    return 0;
  }
  const uint8_t ref_frame_type = av2_ref_frame_type(ref_frames);
  const MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
  const int ref_mv_count = mbmi_ext->ref_mv_count[ref_frame_type];
  if (ref_mv_count > 1) {
    return 0;
  }
  PREDICTION_MODE compare_mode = MB_MODE_COUNT;
  if (this_mode == NEARMV && ref_mv_count == 1 &&
      cm->global_motion[ref_frames[0]].wmtype <= TRANSLATION) {
    compare_mode = GLOBALMV;
  }
  if (this_mode == GLOBALMV && ref_mv_count == 0 &&
      cm->global_motion[ref_frames[0]].wmtype <= TRANSLATION) {
    compare_mode = NEARMV;
  }
  if (this_mode == GLOBALMV && ref_mv_count == 1) {
    compare_mode = NEARMV;
  }
  if (compare_mode == MB_MODE_COUNT) {
    return 0;
  }

  const MV_REFERENCE_FRAME ref_frame0 = COMPACT_INDEX0_NRS(ref_frames[0]);
  if (search_state->modelled_rd[compare_mode][0][ref_frame0] == INT64_MAX) {
    return 0;
  }
  const int16_t mode_ctx =
      av2_mode_context_analyzer(mbmi_ext->mode_context, ref_frames);
  const MB_MODE_INFO *const mbmi = x->e_mbd.mi[0];
  const int compare_cost = cost_prediction_mode(&x->mode_costs, compare_mode,
                                                cm, mbmi, &x->e_mbd, mode_ctx);
  const int this_cost = cost_prediction_mode(&x->mode_costs, this_mode, cm,
                                             mbmi, &x->e_mbd, mode_ctx);

  // Only skip if the mode cost is larger than compare mode cost
  if (this_cost > compare_cost) {
    search_state->modelled_rd[this_mode][0][ref_frame0] =
        search_state->modelled_rd[compare_mode][0][ref_frame0];
    return 1;
  }
  return 0;
}

static INLINE int clamp_and_check_mv(int_mv *out_mv, int_mv in_mv,
                                     const AV2_COMMON *cm,
                                     const MACROBLOCK *x) {
  const MACROBLOCKD *const xd = &x->e_mbd;
  *out_mv = in_mv;
  clamp_mv2(&out_mv->as_mv, xd);
  return av2_is_fullmv_in_range(&x->mv_limits,
                                get_fullmv_from_mv(&out_mv->as_mv),
                                cm->features.fr_mv_precision);
}

// To use single newmv directly for compound modes, need to clamp the mv to the
// valid mv range. Without this, encoder would generate out of range mv, and
// this is seen in 8k encoding.
static INLINE void clamp_mv_in_range(MACROBLOCK *const x, int_mv *mv,
                                     int ref_idx

                                     ,
                                     MvSubpelPrecision pb_mv_precision

) {
  const int_mv ref_mv = av2_get_ref_mv(x, ref_idx);
  SubpelMvLimits mv_limits;

  av2_set_subpel_mv_search_range(&mv_limits, &x->mv_limits, &ref_mv.as_mv

                                 ,
                                 pb_mv_precision

  );
  clamp_mv(&mv->as_mv, &mv_limits);
}

static INLINE void save_comp_mv_search_stat(MACROBLOCK *const x,
                                            HandleInterModeArgs *const args,
                                            int_mv *cur_mv, int_mv start_mv) {
  MACROBLOCKD *const xd = &x->e_mbd;
  MB_MODE_INFO *const mbmi = xd->mi[0];
  if (mbmi->mode == NEW_NEWMV && mbmi->use_amvd == 0) {
    if (args->new_newmv_stats_idx < MAX_COMP_MV_STATS) {
      NEW_NEWMV_STATS stat = {
        av2_ref_frame_type(mbmi->ref_frame),
        av2_ref_mv_idx_type(mbmi, mbmi->ref_mv_idx),
        mbmi->pb_mv_precision,
        mbmi->use_amvd,
        { cur_mv[0], cur_mv[1] },
      };
      args->new_newmv_stats[args->new_newmv_stats_idx] = stat;
      args->new_newmv_stats_idx++;
    }
  } else if (mbmi->mode == NEW_NEWMV && mbmi->use_amvd == 1) {
    if (args->new_newmv_amvd_stats_idx < MAX_COMP_MV_STATS) {
      NEW_NEWMV_AMVD_STATS stat = {
        av2_ref_frame_type(mbmi->ref_frame),
        av2_ref_mv_idx_type(mbmi, mbmi->ref_mv_idx),
        { av2_get_ref_mv(x, 0), av2_get_ref_mv(x, 1) },
        mbmi->use_amvd,
        { cur_mv[0], cur_mv[1] },
      };
      args->new_newmv_amvd_stats[args->new_newmv_amvd_stats_idx] = stat;
      args->new_newmv_amvd_stats_idx++;
    }
  } else if (mbmi->mode == NEAR_NEWMV && mbmi->use_amvd == 0) {
    if (args->near_newmv_stats_idx < MAX_COMP_MV_STATS) {
      NEAR_NEWMV_STATS stat = {
        av2_ref_frame_type(mbmi->ref_frame),
        start_mv,
        av2_get_ref_mv(x, 1),
        mbmi->pb_mv_precision,
        mbmi->use_amvd,
        { cur_mv[0], cur_mv[1] },
      };
      args->near_newmv_stats[args->near_newmv_stats_idx] = stat;
      args->near_newmv_stats_idx++;
    }
  } else if (mbmi->mode == NEAR_NEWMV && mbmi->use_amvd == 1) {
    if (args->near_newmv_amvd_stats_idx < MAX_COMP_MV_STATS) {
      NEAR_NEWMV_AMVD_STATS stat = {
        av2_ref_frame_type(mbmi->ref_frame),
        start_mv,
        av2_get_ref_mv(x, 1),
        mbmi->use_amvd,
        { cur_mv[0], cur_mv[1] },
      };
      args->near_newmv_amvd_stats[args->near_newmv_amvd_stats_idx] = stat;
      args->near_newmv_amvd_stats_idx++;
    }
  } else if (mbmi->mode == NEW_NEARMV && mbmi->use_amvd == 0) {
    if (args->new_nearmv_stats_idx < MAX_COMP_MV_STATS) {
      NEW_NEARMV_STATS stat = { av2_ref_frame_type(mbmi->ref_frame),
                                av2_ref_mv_idx_type(mbmi, mbmi->ref_mv_idx),
                                mbmi->pb_mv_precision, mbmi->use_amvd,
                                cur_mv[0] };
      args->new_nearmv_stats[args->new_nearmv_stats_idx] = stat;
      args->new_nearmv_stats_idx++;
    }
  } else if (mbmi->mode == NEW_NEARMV && mbmi->use_amvd == 1) {
    if (args->new_nearmv_amvd_stats_idx < MAX_COMP_MV_STATS) {
      NEW_NEARMV_AMVD_STATS stat = {
        av2_ref_frame_type(mbmi->ref_frame),
        av2_ref_mv_idx_type(mbmi, mbmi->ref_mv_idx), mbmi->use_amvd, cur_mv[0]
      };
      args->new_nearmv_amvd_stats[args->new_nearmv_amvd_stats_idx] = stat;
      args->new_nearmv_amvd_stats_idx++;
    }
  } else if (mbmi->mode == JOINT_NEWMV && !mbmi->use_amvd) {
    if (args->joint_newmv_stats_idx < MAX_COMP_MV_STATS) {
      JOINT_NEWMV_STATS stat = { av2_ref_frame_type(mbmi->ref_frame),
                                 av2_ref_mv_idx_type(mbmi, mbmi->ref_mv_idx),
                                 mbmi->pb_mv_precision,
                                 mbmi->jmvd_scale_mode,
                                 mbmi->cwp_idx,
                                 mbmi->use_amvd,
                                 { cur_mv[0], cur_mv[1] } };
      args->joint_newmv_stats[args->joint_newmv_stats_idx] = stat;
      args->joint_newmv_stats_idx++;
    }
  } else if (mbmi->mode == JOINT_NEWMV && mbmi->use_amvd) {
    if (args->joint_amvdnewmv_stats_idx < MAX_COMP_MV_STATS) {
      JOINT_AMVDNEWMV_STATS stat = { av2_ref_frame_type(mbmi->ref_frame),
                                     av2_ref_mv_idx_type(mbmi,
                                                         mbmi->ref_mv_idx),
                                     mbmi->jmvd_scale_mode,
                                     mbmi->cwp_idx,
                                     mbmi->use_amvd,
                                     { cur_mv[0], cur_mv[1] } };
      args->joint_amvdnewmv_stats[args->joint_amvdnewmv_stats_idx] = stat;
      args->joint_amvdnewmv_stats_idx++;
    }
  }
}

static INLINE int reuse_comp_mv_for_opfl(const AV2_COMMON *const cm,
                                         MACROBLOCK *const x,
                                         HandleInterModeArgs *const args,
                                         int_mv *cur_mv, int *rate_mv) {
  MACROBLOCKD *const xd = &x->e_mbd;
  MB_MODE_INFO *const mbmi = xd->mi[0];
  MvSubpelPrecision cur_mv_precision = mbmi->pb_mv_precision;
  int is_adaptive_mvd = enable_adaptive_mvd_resolution(cm, mbmi);
  if (is_adaptive_mvd) {
    cur_mv_precision = mbmi->max_mv_precision;
  }
  int match_idx = -1;
  int ref_mv_idx = 0;

  if (mbmi->mode == NEW_NEWMV_OPTFLOW && mbmi->use_amvd == 0) {
    for (int i = 0; i < args->new_newmv_stats_idx; i++) {
      NEW_NEWMV_STATS st = args->new_newmv_stats[i];
      if (st.ref_frame_type == av2_ref_frame_type(mbmi->ref_frame) &&
          st.ref_mv_idx_type == av2_ref_mv_idx_type(mbmi, mbmi->ref_mv_idx) &&
          st.mv_precision == cur_mv_precision &&
          st.use_amvd == mbmi->use_amvd) {
        match_idx = i;
        break;
      }
    }

    if (match_idx != -1) {
      cur_mv[0].as_int = args->new_newmv_stats[match_idx].mv[0].as_int;
      cur_mv[1].as_int = args->new_newmv_stats[match_idx].mv[1].as_int;
    }
  } else if (mbmi->mode == NEW_NEWMV_OPTFLOW && mbmi->use_amvd == 1) {
    for (int i = 0; i < args->new_newmv_amvd_stats_idx; i++) {
      NEW_NEWMV_AMVD_STATS st = args->new_newmv_amvd_stats[i];
      if (st.ref_frame_type == av2_ref_frame_type(mbmi->ref_frame) &&
          st.ref_mv_idx_type == av2_ref_mv_idx_type(mbmi, mbmi->ref_mv_idx) &&
          st.ref_mv[0].as_int == av2_get_ref_mv(x, 0).as_int &&
          st.ref_mv[1].as_int == av2_get_ref_mv(x, 1).as_int &&
          st.use_amvd == mbmi->use_amvd) {
        match_idx = i;
        break;
      }
    }

    if (match_idx != -1) {
      cur_mv[0].as_int = args->new_newmv_amvd_stats[match_idx].mv[0].as_int;
      cur_mv[1].as_int = args->new_newmv_amvd_stats[match_idx].mv[1].as_int;
    }
  } else if (mbmi->mode == NEAR_NEWMV_OPTFLOW && mbmi->use_amvd == 0) {
    for (int i = 0; i < args->near_newmv_stats_idx; i++) {
      NEAR_NEWMV_STATS st = args->near_newmv_stats[i];
      if (st.ref_frame_type == av2_ref_frame_type(mbmi->ref_frame) &&
          st.mv[0].as_int == cur_mv[0].as_int &&
          st.start_mv.as_int == cur_mv[1].as_int &&
          st.ref_mv.as_int == av2_get_ref_mv(x, 1).as_int &&
          st.mv_precision == cur_mv_precision &&
          st.use_amvd == mbmi->use_amvd) {
        match_idx = i;
        break;
      }
    }

    if (match_idx != -1) {
      cur_mv[1].as_int = args->near_newmv_stats[match_idx].mv[1].as_int;
      ref_mv_idx = 1;
    }
  } else if (mbmi->mode == NEAR_NEWMV_OPTFLOW && mbmi->use_amvd == 1) {
    for (int i = 0; i < args->near_newmv_amvd_stats_idx; i++) {
      NEAR_NEWMV_AMVD_STATS st = args->near_newmv_amvd_stats[i];
      if (st.ref_frame_type == av2_ref_frame_type(mbmi->ref_frame) &&
          st.mv[0].as_int == cur_mv[0].as_int &&
          st.start_mv.as_int == cur_mv[1].as_int &&
          st.ref_mv.as_int == av2_get_ref_mv(x, 1).as_int &&
          st.use_amvd == mbmi->use_amvd) {
        match_idx = i;
        break;
      }
    }

    if (match_idx != -1) {
      cur_mv[1].as_int = args->near_newmv_amvd_stats[match_idx].mv[1].as_int;
      ref_mv_idx = 1;
    }
  } else if (mbmi->mode == NEW_NEARMV_OPTFLOW && mbmi->use_amvd == 0) {
    for (int i = 0; i < args->new_nearmv_stats_idx; i++) {
      NEW_NEARMV_STATS st = args->new_nearmv_stats[i];
      if (st.ref_frame_type == av2_ref_frame_type(mbmi->ref_frame) &&
          st.ref_mv_idx_type == av2_ref_mv_idx_type(mbmi, mbmi->ref_mv_idx) &&
          st.mv_precision == cur_mv_precision &&
          st.use_amvd == mbmi->use_amvd) {
        match_idx = i;
        break;
      }
    }

    if (match_idx != -1) {
      cur_mv[0].as_int = args->new_nearmv_stats[match_idx].mv.as_int;
      ref_mv_idx = 0;
    }
  } else if (mbmi->mode == NEW_NEARMV_OPTFLOW && mbmi->use_amvd == 1) {
    for (int i = 0; i < args->new_nearmv_amvd_stats_idx; i++) {
      NEW_NEARMV_AMVD_STATS st = args->new_nearmv_amvd_stats[i];
      if (st.ref_frame_type == av2_ref_frame_type(mbmi->ref_frame) &&
          st.ref_mv_idx_type == av2_ref_mv_idx_type(mbmi, mbmi->ref_mv_idx) &&
          st.use_amvd == mbmi->use_amvd) {
        match_idx = i;
        break;
      }
    }

    if (match_idx != -1) {
      cur_mv[0].as_int = args->new_nearmv_amvd_stats[match_idx].mv.as_int;
      ref_mv_idx = 0;
    }
  } else if (mbmi->mode == JOINT_NEWMV_OPTFLOW && !mbmi->use_amvd) {
    for (int i = 0; i < args->joint_newmv_stats_idx; i++) {
      JOINT_NEWMV_STATS st = args->joint_newmv_stats[i];
      if (st.ref_frame_type == av2_ref_frame_type(mbmi->ref_frame) &&
          st.ref_mv_idx_type == av2_ref_mv_idx_type(mbmi, mbmi->ref_mv_idx) &&
          st.mv_precision == cur_mv_precision &&
          st.joint_newmv_scale_idx == mbmi->jmvd_scale_mode &&
          st.cwp_idx == mbmi->cwp_idx && st.use_amvd == mbmi->use_amvd) {
        match_idx = i;
        break;
      }
    }

    if (match_idx != -1) {
      cur_mv[0].as_int = args->joint_newmv_stats[match_idx].mv[0].as_int;
      cur_mv[1].as_int = args->joint_newmv_stats[match_idx].mv[1].as_int;
      ref_mv_idx = get_joint_mvd_base_ref_list(cm, mbmi);
    }
  } else if (mbmi->mode == JOINT_NEWMV_OPTFLOW && mbmi->use_amvd) {
    for (int i = 0; i < args->joint_amvdnewmv_stats_idx; i++) {
      JOINT_AMVDNEWMV_STATS st = args->joint_amvdnewmv_stats[i];
      if (st.ref_frame_type == av2_ref_frame_type(mbmi->ref_frame) &&
          st.ref_mv_idx_type == av2_ref_mv_idx_type(mbmi, mbmi->ref_mv_idx) &&
          st.joint_amvd_scale_idx == mbmi->jmvd_scale_mode &&
          st.cwp_idx == mbmi->cwp_idx && st.use_amvd == mbmi->use_amvd) {
        match_idx = i;
        break;
      }
    }

    if (match_idx != -1) {
      cur_mv[0].as_int = args->joint_amvdnewmv_stats[match_idx].mv[0].as_int;
      cur_mv[1].as_int = args->joint_amvdnewmv_stats[match_idx].mv[1].as_int;
      ref_mv_idx = get_joint_mvd_base_ref_list(cm, mbmi);
    }
  }

  if (match_idx != -1) {
    *rate_mv = 0;
    int is_new_new_mv_optflow = (mbmi->mode == NEW_NEWMV_OPTFLOW);
    for (int i = ref_mv_idx; i <= (ref_mv_idx + is_new_new_mv_optflow); ++i) {
      const int_mv ref_mv = av2_get_ref_mv(x, i);
      *rate_mv +=
          av2_mv_bit_cost(&cur_mv[i].as_mv, &ref_mv.as_mv, cur_mv_precision,
                          &x->mv_costs, MV_COST_WEIGHT, is_adaptive_mvd);
    }
    if (is_adaptive_mvd) {
      set_amvd_mv_precision(mbmi, mbmi->max_mv_precision);
    }
    return 1;
  }
  return 0;
}

static int64_t handle_newmv(const AV2_COMP *const cpi, MACROBLOCK *const x,
                            const BLOCK_SIZE bsize, int_mv *cur_mv,
                            int *const rate_mv, HandleInterModeArgs *const args,
                            inter_mode_info *mode_info) {
  MACROBLOCKD *const xd = &x->e_mbd;
  MB_MODE_INFO *const mbmi = xd->mi[0];
  const AV2_COMMON *const cm = &cpi->common;
  const int is_comp_pred = has_second_ref(mbmi);
  const PREDICTION_MODE this_mode = mbmi->mode;
  const MV_REFERENCE_FRAME refs[2] = { COMPACT_INDEX0_NRS(mbmi->ref_frame[0]),
                                       COMPACT_INDEX1_NRS(mbmi->ref_frame[1]) };

  const MvSubpelPrecision pb_mv_precision = mbmi->pb_mv_precision;

  if (is_comp_pred) {
    int valid_mv0_found = 0;
    int valid_precision_mv0 = NUM_MV_PRECISIONS;
    for (int prev_mv_precision = pb_mv_precision;
         prev_mv_precision <= mbmi->max_mv_precision; prev_mv_precision++) {
      if (args->single_newmv_valid[prev_mv_precision][get_ref_mv_idx(mbmi, 0)]
                                  [refs[0]]) {
        valid_mv0_found = 1;
        valid_precision_mv0 = prev_mv_precision;
        break;
      }
    }

    int valid_mv1_found = 0;
    int valid_precision_mv1 = NUM_MV_PRECISIONS;
    for (int prev_mv_precision = pb_mv_precision;
         prev_mv_precision <= mbmi->max_mv_precision; prev_mv_precision++) {
      if (args->single_newmv_valid[prev_mv_precision][get_ref_mv_idx(mbmi, 1)]
                                  [refs[1]]) {
        valid_mv1_found = 1;
        valid_precision_mv1 = prev_mv_precision;
        break;
      }
    }
    const int valid_mv0 = valid_mv0_found;
    const int valid_mv1 = valid_mv1_found;

    if (this_mode == NEW_NEWMV || this_mode == NEW_NEWMV_OPTFLOW) {
      if (reuse_comp_mv_for_opfl(cm, x, args, cur_mv, rate_mv)) {
        return 0;
      } else {
        if (valid_mv0) {
          cur_mv[0].as_int =
              args->single_newmv[valid_precision_mv0][get_ref_mv_idx(mbmi, 0)]
                                [refs[0]]
                                    .as_int;

          lower_mv_precision(&cur_mv[0].as_mv, pb_mv_precision);

          clamp_mv_in_range(x, &cur_mv[0], 0, pb_mv_precision

          );
        }
        if (valid_mv1) {
          cur_mv[1].as_int =
              args->single_newmv[valid_precision_mv1][get_ref_mv_idx(mbmi, 1)]
                                [refs[1]]
                                    .as_int;
          lower_mv_precision(&cur_mv[1].as_mv, pb_mv_precision);
          clamp_mv_in_range(x, &cur_mv[1], 1, pb_mv_precision

          );
        }

        // avmenc1
        if (mbmi->use_amvd ||
            cpi->sf.inter_sf.comp_inter_joint_search_thresh <= bsize ||
            !valid_mv0 || !valid_mv1) {
          // uint8_t mask_value = 32;
          if (mbmi->use_amvd)
            av2_amvd_joint_motion_search(cpi, x, bsize, cur_mv, NULL, 0,
                                         rate_mv);
          else
            av2_joint_motion_search(cpi, x, bsize, cur_mv, NULL, 0, rate_mv);
        } else {
          *rate_mv = 0;
          for (int i = 0; i < 2; ++i) {
            const int_mv ref_mv = av2_get_ref_mv(x, i);
            update_mv_precision(ref_mv.as_mv, pb_mv_precision,
                                &cur_mv[i].as_mv);
            *rate_mv += av2_mv_bit_cost(&cur_mv[i].as_mv, &ref_mv.as_mv,
                                        pb_mv_precision, &x->mv_costs,
                                        MV_COST_WEIGHT, 0);
          }
        }
        int_mv start_mv = { 0 };
        save_comp_mv_search_stat(x, args, cur_mv, start_mv);
      }
    } else if (this_mode == NEAR_NEWMV || this_mode == NEAR_NEWMV_OPTFLOW) {
      if (valid_mv1) {
        cur_mv[1].as_int = args->single_newmv[valid_precision_mv1]
                                             [get_ref_mv_idx(mbmi, 1)][refs[1]]
                                                 .as_int;

        lower_mv_precision(&cur_mv[1].as_mv, pb_mv_precision);

        clamp_mv_in_range(x, &cur_mv[1], 1, pb_mv_precision

        );
      }
      if (cm->seq_params.enable_adaptive_mvd) {
        if (reuse_comp_mv_for_opfl(cm, x, args, cur_mv, rate_mv)) {
          return 0;
        }

        int_mv start_mv = cur_mv[1];

        av2_compound_single_motion_search_interinter(cpi, x, bsize, cur_mv,
                                                     NULL, 0, rate_mv, 1);

        if (cur_mv->as_int == INVALID_MV) return INT64_MAX;
        save_comp_mv_search_stat(x, args, cur_mv, start_mv);
      } else {
        // avmenc2
        if (cpi->sf.inter_sf.comp_inter_joint_search_thresh <= bsize ||
            !valid_mv1) {
          av2_compound_single_motion_search_interinter(cpi, x, bsize, cur_mv,
                                                       NULL, 0, rate_mv, 1);
        } else {
          const int_mv ref_mv = av2_get_ref_mv(x, 1);
          update_mv_precision(ref_mv.as_mv, pb_mv_precision,

                              &cur_mv[1].as_mv);
          *rate_mv =
              av2_mv_bit_cost(&cur_mv[1].as_mv, &ref_mv.as_mv, pb_mv_precision,
                              &x->mv_costs, MV_COST_WEIGHT

                              ,
                              0

              );
        }
      }
    } else if (is_joint_mvd_coding_mode(this_mode)) {
      if (!cm->seq_params.enable_joint_mvd) return INT64_MAX;
      const int same_side = is_ref_frame_same_side(cm, mbmi);
      // skip JOINT_NEWMV mode when two reference frames are from same side
      if (same_side) return INT64_MAX;

      const int first_ref_dist =
          cm->ref_frame_relative_dist[mbmi->ref_frame[0]];
      const int sec_ref_dist = cm->ref_frame_relative_dist[mbmi->ref_frame[1]];
      if (first_ref_dist != sec_ref_dist) return INT64_MAX;

      if (reuse_comp_mv_for_opfl(cm, x, args, cur_mv, rate_mv)) {
        return 0;
      }

      const int jmvd_base_ref_list = get_joint_mvd_base_ref_list(cm, mbmi);
      const int valid_mv_base = (!jmvd_base_ref_list && valid_mv0) ||
                                (jmvd_base_ref_list && valid_mv1);
      if (valid_mv_base &&
          !is_joint_amvd_coding_mode(mbmi->mode, mbmi->use_amvd)) {
        cur_mv[jmvd_base_ref_list].as_int =
            args->single_newmv[jmvd_base_ref_list == 0 ? valid_precision_mv0
                                                       : valid_precision_mv1]
                              [get_ref_mv_idx(mbmi, 1)]
                              [refs[jmvd_base_ref_list]]
                                  .as_int;

        lower_mv_precision(&cur_mv[jmvd_base_ref_list].as_mv, pb_mv_precision);

        clamp_mv_in_range(x, &cur_mv[jmvd_base_ref_list], jmvd_base_ref_list

                          ,
                          pb_mv_precision);
      }
      av2_compound_single_motion_search_interinter(
          cpi, x, bsize, cur_mv, NULL, 0, rate_mv, jmvd_base_ref_list);
      if (cur_mv->as_int == INVALID_MV) return INT64_MAX;
      int_mv start_mv = { 0 };
      save_comp_mv_search_stat(x, args, cur_mv, start_mv);
    } else {
      assert(this_mode == NEW_NEARMV || this_mode == NEW_NEARMV_OPTFLOW);
      if (reuse_comp_mv_for_opfl(cm, x, args, cur_mv, rate_mv)) {
        return 0;
      }
      if (valid_mv0) {
        cur_mv[0].as_int = args->single_newmv[valid_precision_mv0]
                                             [get_ref_mv_idx(mbmi, 0)][refs[0]]
                                                 .as_int;

        lower_mv_precision(&cur_mv[0].as_mv, pb_mv_precision);
        clamp_mv_in_range(x, &cur_mv[0], 0, pb_mv_precision

        );
      }
      if (cm->seq_params.enable_adaptive_mvd) {
        av2_compound_single_motion_search_interinter(cpi, x, bsize, cur_mv,
                                                     NULL, 0, rate_mv, 0);
        if (cur_mv->as_int == INVALID_MV) return INT64_MAX;
        int_mv start_mv = { 0 };
        save_comp_mv_search_stat(x, args, cur_mv, start_mv);
      } else {
        // avmenc3
        if (cpi->sf.inter_sf.comp_inter_joint_search_thresh <= bsize ||
            !valid_mv0) {
          av2_compound_single_motion_search_interinter(cpi, x, bsize, cur_mv,
                                                       NULL, 0, rate_mv, 0);
        } else {
          const int_mv ref_mv = av2_get_ref_mv(x, 0);
          update_mv_precision(ref_mv.as_mv, pb_mv_precision, &cur_mv[0].as_mv);
          *rate_mv =
              av2_mv_bit_cost(&cur_mv[0].as_mv, &ref_mv.as_mv, pb_mv_precision,
                              &x->mv_costs, MV_COST_WEIGHT, 0

              );
        }
      }
    }
  } else if (this_mode == NEWMV && mbmi->use_amvd) {
    const int ref_idx = 0;
    int_mv best_mv;
    assert(mbmi->pb_mv_precision == mbmi->max_mv_precision);
    av2_amvd_single_motion_search(cpi, x, bsize, &best_mv.as_mv, rate_mv,
                                  ref_idx);
    if (best_mv.as_int == INVALID_MV) return INT64_MAX;
    cur_mv[0].as_int = best_mv.as_int;
  } else {
    // Single ref case.
    if (this_mode == WARP_NEWMV) {
      const int ref_mv_idx = get_ref_mv_idx(mbmi, 0);
      if (args->single_newmv_valid[pb_mv_precision][ref_mv_idx][refs[0]]) {
        cur_mv[0].as_int =
            args->single_newmv[pb_mv_precision][ref_mv_idx][refs[0]].as_int;
        *rate_mv =
            args->single_newmv_rate[pb_mv_precision][ref_mv_idx][refs[0]];
        return 0;
      }
    }

    const int ref_idx = 0;
    int_mv best_mv;
    int valid_precision_mv0 = NUM_MV_PRECISIONS;
    int do_refine_ms = (cpi->sf.flexmv_sf.fast_motion_search_low_precision &&
                        pb_mv_precision < mbmi->max_mv_precision) &&
                       is_pb_mv_precision_active(&cpi->common, mbmi, bsize);
    if (do_refine_ms) {
      int valid_mv0_found = 0;
      for (int prev_mv_precision = pb_mv_precision;
           prev_mv_precision <= mbmi->max_mv_precision; prev_mv_precision++) {
        assert(get_ref_mv_idx(mbmi, 1) == get_ref_mv_idx(mbmi, 0));
        if (args->single_newmv_valid[prev_mv_precision][get_ref_mv_idx(mbmi, 0)]
                                    [refs[0]]) {
          valid_mv0_found = 1;
          valid_precision_mv0 = prev_mv_precision;
          break;
        }
      }

      do_refine_ms &= valid_mv0_found;
    }

    if (do_refine_ms) {
      int_mv start_mv;
      assert(valid_precision_mv0 > pb_mv_precision &&
             valid_precision_mv0 < NUM_MV_PRECISIONS);
      start_mv.as_int = args->single_newmv[valid_precision_mv0]
                                          [get_ref_mv_idx(mbmi, 0)][refs[0]]
                                              .as_int;
      lower_mv_precision(&start_mv.as_mv, pb_mv_precision);
      clamp_mv_in_range(x, &start_mv, 0, pb_mv_precision);

      av2_single_motion_search_high_precision(cpi, x, bsize, ref_idx, rate_mv,
                                              mode_info, &start_mv, &best_mv);

    } else {
      int search_range = INT_MAX;
      if (cpi->sf.mv_sf.reduce_search_range && mbmi->ref_mv_idx[0] > 0) {
        const MV ref_mv = av2_get_ref_mv(x, ref_idx).as_mv;
        int min_mv_diff = INT_MAX;
        int best_match = -1;
        MV best_mv1 = { 0 };
        assert(ref_idx == 0);
        for (int idx = 0; idx < mbmi->ref_mv_idx[ref_idx]; ++idx) {
          MV prev_ref_mv = av2_get_ref_mv_from_stack(ref_idx, mbmi->ref_frame,
                                                     idx, x->mbmi_ext, mbmi)
                               .as_mv;
          const int ref_mv_diff = AVMMAX(abs(ref_mv.row - prev_ref_mv.row),
                                         abs(ref_mv.col - prev_ref_mv.col));

          if (min_mv_diff > ref_mv_diff) {
            min_mv_diff = ref_mv_diff;
            best_match = idx;
            best_mv1 = prev_ref_mv;
          }
        }

        if (min_mv_diff < (16 << 3)) {
          if (args->single_newmv_valid[pb_mv_precision][best_match][refs[0]]) {
            search_range = min_mv_diff;
            search_range += AVMMAX(
                abs(args->single_newmv[pb_mv_precision][best_match][refs[0]]
                        .as_mv.row -
                    best_mv1.row),
                abs(args->single_newmv[pb_mv_precision][best_match][refs[0]]
                        .as_mv.col -
                    best_mv1.col));
            // Get full pixel search range.
            search_range = (search_range + 4) >> 3;
          }
        }
      }
      if (mbmi->use_amvd) {
        av2_amvd_single_motion_search(cpi, x, bsize, &best_mv.as_mv, rate_mv,
                                      0);
      } else {
        av2_single_motion_search(cpi, x, bsize, ref_idx, rate_mv, search_range,
                                 mode_info, &best_mv, NULL);
      }
    }

    if (best_mv.as_int == INVALID_MV) return INT64_MAX;

    args->single_newmv[pb_mv_precision][get_ref_mv_idx(mbmi, 0)][refs[0]] =
        best_mv;
    args->single_newmv_rate[pb_mv_precision][get_ref_mv_idx(mbmi, 0)][refs[0]] =
        *rate_mv;
    args->single_newmv_valid[pb_mv_precision][get_ref_mv_idx(mbmi, 0)]
                            [refs[0]] = 1;
    cur_mv[0].as_int = best_mv.as_int;
  }

  return 0;
}

// Compute the cost of a single warp-delta parameter.
static int cost_warp_delta_param(int index, int coded_value,
                                 const ModeCosts *mode_costs,
                                 int max_coded_index) {
  assert(2 <= index && index <= 5);
  int index_type = (index == 2 || index == 5) ? 0 : 1;
  int coded_value_low_max = (WARP_DELTA_NUMSYMBOLS_LOW - 1);
  int cost =
      mode_costs
          ->warp_delta_param_cost[index_type][coded_value >= coded_value_low_max
                                                  ? coded_value_low_max
                                                  : coded_value];

  if (max_coded_index >= WARP_DELTA_NUMSYMBOLS_LOW &&
      coded_value >= coded_value_low_max) {
    cost += mode_costs->warp_delta_param_high_cost[index_type][coded_value - 7];
  }

  return cost;
}

// Compute the total cost of the all warp-delta model parameter.
// Since MVs are signaled separately, the number of model parameters are 4 and 2
// for six and four parameter models, respectively.
int av2_cost_model_param(const MB_MODE_INFO *mbmi, const ModeCosts *mode_costs,
                         int step_size, int max_coded_index,
                         WarpedMotionParams *base_params) {
  const WarpedMotionParams *params = &mbmi->wm_params[0];
  assert(!params->invalid);
  int rate = 0;
  for (uint8_t index = 2; index < (mbmi->six_param_warp_model_flag ? 6 : 4);
       index++) {
    int32_t value = params->wmmat[index] - base_params->wmmat[index];
    int coded_value = (value / step_size);
    rate += cost_warp_delta_param(index, abs(coded_value), mode_costs,
                                  max_coded_index);
    if (coded_value) {
      rate += mode_costs->warp_param_sign_cost[coded_value < 0];
    }
  }

  return rate;
}

int av2_cost_warp_delta(const AV2_COMMON *cm, const MACROBLOCKD *xd,
                        const MB_MODE_INFO *mbmi,
                        const MB_MODE_INFO_EXT *mbmi_ext,
                        const ModeCosts *mode_costs) {
  (void)xd;
  assert(allow_warp_parameter_signaling(cm, mbmi));
  const WarpedMotionParams *params = &mbmi->wm_params[0];
  WarpedMotionParams base_params;

  av2_get_warp_base_params(
      cm, mbmi, &base_params, NULL,
      mbmi_ext->warp_param_stack[av2_ref_frame_type(mbmi->ref_frame)]);

  // The RDO stage should not give us a model which is not warpable.
  // Such models can still be signalled, but are effectively useless
  // as we'll just fall back to translational motion
  assert(!params->invalid);

  int step_size = 0;
  int max_coded_index = 0;
  get_warp_model_steps(mbmi, &step_size, &max_coded_index);

  int rate = 0;

  rate +=
      mode_costs
          ->warp_precision_idx_cost[mbmi->sb_type[xd->tree_type == CHROMA_PART]]
                                   [mbmi->warp_precision_idx];

  for (uint8_t index = 2; index < (mbmi->six_param_warp_model_flag ? 6 : 4);
       index++) {
    int32_t value = params->wmmat[index] - base_params.wmmat[index];
    int coded_value = (value / step_size);
    rate += cost_warp_delta_param(index, abs(coded_value), mode_costs,
                                  max_coded_index);
    if (coded_value) {
      rate += mode_costs->warp_param_sign_cost[coded_value < 0];
    }
  }

  return rate;
}

static INLINE int select_modes_to_search(const AV2_COMP *const cpi,
                                         int allowed_motion_modes,
                                         int eval_motion_mode,
                                         int skip_motion_mode) {
  int modes_to_search = allowed_motion_modes;

  // Modify the set of motion modes to consider according to speed features.
  // For example, if SIMPLE_TRANSLATION has already been searched according to
  // the motion_mode_for_winner_cand speed feature, avoid searching it again.
  if (cpi->sf.winner_mode_sf.motion_mode_for_winner_cand) {
    if (!eval_motion_mode) {
      modes_to_search = (1 << SIMPLE_TRANSLATION);
    } else {
      // Skip translation, as will have already been evaluated
      modes_to_search &= ~(1 << SIMPLE_TRANSLATION);
    }
  }

  if (skip_motion_mode) {
    modes_to_search &= (1 << SIMPLE_TRANSLATION);
  }

  return modes_to_search;
}

// Find the bit cost of signaling the warp_ref_idx
static INLINE int get_warp_ref_idx_cost(const MB_MODE_INFO *mbmi,
                                        const MACROBLOCK *x) {
  if (mbmi->max_num_warp_candidates <= 1) {
    assert(mbmi->warp_ref_idx == 0);
    return 0;
  }

  int cost = 0;
  const ModeCosts *mode_costs = &x->mode_costs;
  int max_idx_bits = mbmi->max_num_warp_candidates - 1;
  for (int bit_idx = 0; bit_idx < max_idx_bits; ++bit_idx) {
    int warp_ctx = 0;
    int bit_ctx = bit_idx < 2 ? bit_idx : 2;
    int codec_bit = (mbmi->warp_ref_idx != bit_idx);
    cost += mode_costs->warp_ref_idx_cost[bit_ctx][warp_ctx][codec_bit];
    if (mbmi->warp_ref_idx == bit_idx) break;
  }
  return cost;
}

#define NUMBER_OF_ITER_PER_COMP 4
// Get the other non-signaled MVD for joint MVD mode
static int get_othermv_for_jointmv_mode(
    const AV2_COMP *const cpi, BLOCK_SIZE bsize, MACROBLOCK *x,
    MB_MODE_INFO *mbmi, MV this_mv, MV *other_mv, MvSubpelPrecision precision,
    int is_adaptive_mvd, int jmvd_base_ref_list) {
  const AV2_COMMON *cm = &cpi->common;
  const int same_side = is_ref_frame_same_side(cm, mbmi);
  assert(jmvd_base_ref_list == get_joint_mvd_base_ref_list(cm, mbmi));
  assert(is_joint_mvd_coding_mode(mbmi->mode));
  const int_mv ref_mvs[2] = { av2_get_ref_mv(x, 0), av2_get_ref_mv(x, 1) };

  int first_ref_dist =
      cm->ref_frame_relative_dist[mbmi->ref_frame[jmvd_base_ref_list]];
  int sec_ref_dist =
      cm->ref_frame_relative_dist[mbmi->ref_frame[1 - jmvd_base_ref_list]];
  assert(first_ref_dist >= sec_ref_dist);
  sec_ref_dist = same_side ? sec_ref_dist : -sec_ref_dist;

  MV other_mvd = { 0, 0 };
  MV diff = { 0, 0 };
  MV low_prec_refmv = ref_mvs[jmvd_base_ref_list].as_mv;
  if (!is_adaptive_mvd && precision < MV_PRECISION_HALF_PEL)
    lower_mv_precision(&low_prec_refmv, precision);
  diff.row = this_mv.row - low_prec_refmv.row;
  diff.col = this_mv.col - low_prec_refmv.col;

  get_mv_projection(&other_mvd, diff, sec_ref_dist, first_ref_dist);
  scale_other_mvd(&other_mvd, mbmi->jmvd_scale_mode, mbmi->mode,
                  mbmi->use_amvd);
  other_mv->row =
      (int)(ref_mvs[1 - jmvd_base_ref_list].as_mv.row + other_mvd.row);
  other_mv->col =
      (int)(ref_mvs[1 - jmvd_base_ref_list].as_mv.col + other_mvd.col);

  SUBPEL_MOTION_SEARCH_PARAMS ms_params;
  av2_make_default_subpel_ms_params(&ms_params, cpi, x, bsize,
                                    &ref_mvs[1 - jmvd_base_ref_list].as_mv,
                                    mbmi->pb_mv_precision, 0, NULL);
  const SubpelMvLimits *other_mv_limits = &ms_params.mv_limits;
  return av2_is_subpelmv_in_range(other_mv_limits, *other_mv);
}
// Cost of signaling sign of last non-zero MVD component
static int get_last_sign_cost(MACROBLOCK *x, int is_adaptive_mvd, MV mv_diff[2],
                              int start_signaled_mv_ref_idx,
                              int num_signaled_mvd) {
  int last_sign = -1;
  int last_comp = -1;
  for (int ref_idx = start_signaled_mv_ref_idx;
       ref_idx < start_signaled_mv_ref_idx + num_signaled_mvd; ++ref_idx) {
    for (int comp = 0; comp < 2; comp++) {
      int16_t this_mvd_comp =
          comp == 0 ? mv_diff[ref_idx].row : mv_diff[ref_idx].col;
      if (this_mvd_comp) {
        last_sign = (this_mvd_comp < 0);
        last_comp = comp;
      }
    }
  }
  assert(last_sign == 0 || last_sign == 1);
  return (av2_mv_sign_cost(last_sign, last_comp, &x->mv_costs, MV_COST_WEIGHT,
                           7, is_adaptive_mvd));
}

// Generate the prediction and compute model RD for a given MV
static void av2_get_model_rd(const AV2_COMP *const cpi, MACROBLOCKD *xd,
                             MACROBLOCK *x, BLOCK_SIZE bsize,
                             const BUFFER_SET *orig_dst, MV this_mvs[2],
                             MV ref_mvs[2], int num_signaled_mvd, int *rate_sum,
                             int64_t *dist_sum, int *mv_rate,
                             int signaled_mv_ref_idx) {
  const AV2_COMMON *cm = &cpi->common;
  MB_MODE_INFO *mbmi = xd->mi[0];
  const int is_adaptive_mvd = enable_adaptive_mvd_resolution(cm, mbmi);
  int is_compound = has_second_ref(mbmi);
  int tmp_skip_txfm_sb;
  int64_t tmp_skip_sse_sb;
  int plane_from = AVM_PLANE_Y;
  int plane_to = AVM_PLANE_Y;

  // build the predictor
  av2_enc_build_inter_predictor(cm, xd, xd->mi_row, xd->mi_col, orig_dst, bsize,
                                plane_from, plane_to);

  // Compute the MVcosts for all signaled MVDs
  int this_mv_rate = av2_mv_bit_cost(
      &this_mvs[signaled_mv_ref_idx], &ref_mvs[signaled_mv_ref_idx],
      mbmi->pb_mv_precision, &x->mv_costs, MV_COST_WEIGHT, is_adaptive_mvd);
  if (num_signaled_mvd == 2) {
    this_mv_rate += av2_mv_bit_cost(
        &this_mvs[!signaled_mv_ref_idx], &ref_mvs[!signaled_mv_ref_idx],
        mbmi->pb_mv_precision, &x->mv_costs, MV_COST_WEIGHT, is_adaptive_mvd);
  }
  if (is_compound) {
    model_rd_sb_fn[MODELRD_TYPE_MASKED_COMPOUND](
        cpi, bsize, x, xd, plane_from, plane_to, rate_sum, dist_sum,
        &tmp_skip_txfm_sb, &tmp_skip_sse_sb, NULL, NULL, NULL);
  } else {
    if (mbmi->motion_mode == INTERINTRA) {
      model_rd_sb_fn[MODELRD_TYPE_INTERINTRA](cpi, bsize, x, xd, plane_from,
                                              plane_to, rate_sum, dist_sum,
                                              NULL, NULL, NULL, NULL, NULL);
    } else {
      model_rd_sb_fn[MODELRD_CURVFIT](cpi, bsize, x, xd, plane_from, plane_to,
                                      rate_sum, dist_sum, NULL, NULL, NULL,
                                      NULL, NULL);
    }
  }

  *mv_rate = this_mv_rate;
}

// Check if this MVD is valid for derive sign
static INLINE int is_this_mvds_valid_for_derivesign(
    const MV mvd[2], const MvSubpelPrecision precision,
    const int is_adaptive_mvd, const int start_signaled_mv_ref_idx,
    const int num_signaled_mvd, int *modified_last_sign,
    int *modified_last_comp, int *modified_num_non_zero_comp,
    int th_for_num_nonzero) {
  (void)is_adaptive_mvd;
  int num_nonzero_mvd_comp = 0;
  int precision_shift = MV_PRECISION_ONE_EIGHTH_PEL - precision;
  int last_sign = -1;
  int sum_mvd = 0;
  int last_comp = -1;
  for (int ref_idx = start_signaled_mv_ref_idx;
       ref_idx < start_signaled_mv_ref_idx + num_signaled_mvd; ++ref_idx) {
    for (int comp = 0; comp < 2; comp++) {
      int this_mvd_comp = comp == 0 ? mvd[ref_idx].row : mvd[ref_idx].col;
      if (this_mvd_comp) {
        last_sign = (this_mvd_comp < 0);
        num_nonzero_mvd_comp++;
        last_comp = comp;
        sum_mvd += (abs(this_mvd_comp) >> precision_shift);
      }
    }
  }
  if (modified_last_sign) *modified_last_sign = last_sign;
  if (modified_last_comp) *modified_last_comp = last_comp;
  if (modified_num_non_zero_comp)
    *modified_num_non_zero_comp = num_nonzero_mvd_comp;

  if (num_nonzero_mvd_comp < th_for_num_nonzero) return 1;
  return (last_sign == (sum_mvd & 0x1));
}
// Motion search for sign derivation  if only one MVD is signaled
static int av2_adjust_mvs_for_derive_sign_single_mvd(
    const AV2_COMP *const cpi, MACROBLOCK *x, BLOCK_SIZE bsize,
    const BUFFER_SET *orig_dst, int signaled_mv_ref_idx, int num_signaled_mvd,
    MV mv_diff[2], MV ref_mvs[2], int rate2_nocoeff, int rate_mv0,
    int *tmp_rate_mv) {
  const AV2_COMMON *cm = &cpi->common;
  MACROBLOCKD *xd = &x->e_mbd;
  MB_MODE_INFO *mbmi = xd->mi[0];
  int is_compound = has_second_ref(mbmi);
  const int is_adaptive_mvd = enable_adaptive_mvd_resolution(cm, mbmi);
  int th_for_num_nonzero = get_derive_sign_nzero_th(mbmi);
  const int joint_mvd_mode = is_joint_mvd_coding_mode(mbmi->mode);
  assert(!is_adaptive_mvd);
  assert(num_signaled_mvd == 1);
  (void)num_signaled_mvd;
  int rate_sum;
  int64_t dist_sum;
  int rate_without_mv = rate2_nocoeff - rate_mv0;
  int best_mv_rate = rate_mv0;
  SubpelMvLimits *mv_limits[2] = { NULL, NULL };

  assert(
      IMPLIES(is_adaptive_mvd, mbmi->pb_mv_precision == MV_PRECISION_QTR_PEL));
  assert(
      IMPLIES(!is_compound, signaled_mv_ref_idx == 0 && num_signaled_mvd == 1));
  const int mv_delta =
      1 << (MV_PRECISION_ONE_EIGHTH_PEL - mbmi->pb_mv_precision);
  assert(!is_valid_sign_mvd_single(mv_diff[signaled_mv_ref_idx],
                                   mbmi->pb_mv_precision, is_adaptive_mvd,
                                   th_for_num_nonzero));

  // Get the MV limits for both references
  SUBPEL_MOTION_SEARCH_PARAMS ms_params[2];
  for (int ref_idx = 0; ref_idx < 1 + is_compound; ref_idx++) {
    av2_make_default_subpel_ms_params(&ms_params[ref_idx], cpi, x, bsize,
                                      &ref_mvs[ref_idx], mbmi->pb_mv_precision,
                                      0, NULL);
    mv_limits[ref_idx] = &ms_params[ref_idx].mv_limits;
  }

  int64_t best_model_rd = INT64_MAX;
  const MV initial_mvs[2] = { mbmi->mv[0].as_mv, mbmi->mv[1].as_mv };
  MV best_mvs[2] = { mbmi->mv[0].as_mv, mbmi->mv[1].as_mv };
  const MV initial_mvd[2] = { mv_diff[0], mv_diff[1] };

  int search_range = 1;
  for (int row_mvd_idx = -search_range; row_mvd_idx <= search_range;
       row_mvd_idx++) {
    for (int col_mvd_idx = -search_range; col_mvd_idx <= search_range;
         col_mvd_idx++) {
      const MV this_mvd = {
        initial_mvd[signaled_mv_ref_idx].row + row_mvd_idx * mv_delta,
        initial_mvd[signaled_mv_ref_idx].col + col_mvd_idx * mv_delta
      };
      if (!is_valid_sign_mvd_single(this_mvd, mbmi->pb_mv_precision,
                                    is_adaptive_mvd, th_for_num_nonzero))
        continue;

      // Get the last sign
      int last_nonzero_sign = -1;
      int last_comp = -1;
      int num_nonzero_mvd_comp = (this_mvd.row != 0) + (this_mvd.col != 0);
      if (this_mvd.col) {
        last_nonzero_sign = this_mvd.col < 0;
        last_comp = 1;
      } else if (this_mvd.row) {
        last_nonzero_sign = this_mvd.row < 0;
        last_comp = 0;
      }

      MV this_mvs[2] = { initial_mvs[0], initial_mvs[1] };
      update_mv_component_from_mvd(this_mvd.row, ref_mvs[signaled_mv_ref_idx],
                                   0, is_adaptive_mvd, mbmi->pb_mv_precision,
                                   &this_mvs[signaled_mv_ref_idx]);
      update_mv_component_from_mvd(this_mvd.col, ref_mvs[signaled_mv_ref_idx],
                                   1, is_adaptive_mvd, mbmi->pb_mv_precision,
                                   &this_mvs[signaled_mv_ref_idx]);
      if (av2_is_subpelmv_in_range(mv_limits[signaled_mv_ref_idx],
                                   this_mvs[signaled_mv_ref_idx])) {
        mbmi->mv[signaled_mv_ref_idx].as_mv = this_mvs[signaled_mv_ref_idx];
        if (is_compound) {
          if (joint_mvd_mode) {
            MV other_mv;
            int valid = get_othermv_for_jointmv_mode(
                cpi, bsize, x, mbmi, this_mvs[signaled_mv_ref_idx], &other_mv,
                mbmi->pb_mv_precision, is_adaptive_mvd, signaled_mv_ref_idx);
            if (!valid) continue;
            mbmi->mv[!signaled_mv_ref_idx].as_mv = other_mv;
          } else {
            mbmi->mv[!signaled_mv_ref_idx].as_mv =
                this_mvs[!signaled_mv_ref_idx];
          }
        }
        int this_mv_rate;
        MV this_mv[2] = { mbmi->mv[0].as_mv, mbmi->mv[1].as_mv };
        av2_get_model_rd(cpi, xd, x, bsize, orig_dst, this_mv, ref_mvs,
                         num_signaled_mvd, &rate_sum, &dist_sum, &this_mv_rate,
                         signaled_mv_ref_idx);
        if (num_nonzero_mvd_comp >= th_for_num_nonzero) {
          assert(last_comp != -1);
          assert(last_nonzero_sign != -1);
          int last_sign_cost =
              av2_mv_sign_cost(last_nonzero_sign, last_comp, &x->mv_costs,
                               MV_COST_WEIGHT, 7, is_adaptive_mvd);
          this_mv_rate -= last_sign_cost;
        }
        int64_t comp_model_rd_cur = RDCOST(
            x->rdmult, rate_without_mv + this_mv_rate + rate_sum, dist_sum);
        if (comp_model_rd_cur < best_model_rd) {
          best_model_rd = comp_model_rd_cur;
          best_mvs[signaled_mv_ref_idx] = mbmi->mv[signaled_mv_ref_idx].as_mv;
          if (is_compound)
            best_mvs[!signaled_mv_ref_idx] =
                mbmi->mv[!signaled_mv_ref_idx].as_mv;
          best_mv_rate = this_mv_rate;

          assert(this_mvs[signaled_mv_ref_idx].row ==
                 mbmi->mv[signaled_mv_ref_idx].as_mv.row);
          assert(this_mvs[signaled_mv_ref_idx].col ==
                 mbmi->mv[signaled_mv_ref_idx].as_mv.col);
          if (is_compound && !joint_mvd_mode) {
            assert(this_mvs[!signaled_mv_ref_idx].row ==
                   mbmi->mv[!signaled_mv_ref_idx].as_mv.row);
            assert(this_mvs[!signaled_mv_ref_idx].col ==
                   mbmi->mv[!signaled_mv_ref_idx].as_mv.col);
          }
        }
      }
    }
  }

  mbmi->mv[0].as_mv = best_mvs[0];
  if (is_compound) mbmi->mv[1].as_mv = best_mvs[1];
  *tmp_rate_mv = best_mv_rate;

  return (best_model_rd != INT64_MAX);
}

// Perform refinement for sign derivation
static int av2_adjust_mvs_for_derive_sign(const AV2_COMP *const cpi,
                                          MACROBLOCK *x, BLOCK_SIZE bsize,
                                          const BUFFER_SET *orig_dst,
                                          int start_signaled_mv_ref_idx,
                                          int num_signaled_mvd, MV mv_diff[2],
                                          MV ref_mvs[2], int rate2_nocoeff,
                                          int rate_mv0, int *tmp_rate_mv) {
  const AV2_COMMON *cm = &cpi->common;
  MACROBLOCKD *xd = &x->e_mbd;
  MB_MODE_INFO *mbmi = xd->mi[0];
  int is_compound = has_second_ref(mbmi);
  const int is_adaptive_mvd = enable_adaptive_mvd_resolution(cm, mbmi);
  int th_for_num_nonzero = get_derive_sign_nzero_th(mbmi);
  assert(is_adaptive_mvd == 0);
  const int joint_mvd_mode = is_joint_mvd_coding_mode(mbmi->mode);
  int rate_sum;      //, tmp_skip_txfm_sb;
  int64_t dist_sum;  //, tmp_skip_sse_sb;
  int rate_without_mv = rate2_nocoeff - rate_mv0;
  int best_mv_rate = rate_mv0;

  if (num_signaled_mvd < 2) {
    return av2_adjust_mvs_for_derive_sign_single_mvd(
        cpi, x, bsize, orig_dst, start_signaled_mv_ref_idx, num_signaled_mvd,
        mv_diff, ref_mvs, rate2_nocoeff, rate_mv0, tmp_rate_mv);
  }

  SubpelMvLimits *mv_limits[2] = { NULL, NULL };

  assert(
      IMPLIES(is_adaptive_mvd, mbmi->pb_mv_precision == MV_PRECISION_QTR_PEL));
  const int mv_delta =
      1 << (MV_PRECISION_ONE_EIGHTH_PEL - mbmi->pb_mv_precision);
  assert(IMPLIES(!is_compound,
                 start_signaled_mv_ref_idx == 0 && num_signaled_mvd == 1));

  SUBPEL_MOTION_SEARCH_PARAMS ms_params[2];
  for (int ref_idx = start_signaled_mv_ref_idx;
       ref_idx < start_signaled_mv_ref_idx + num_signaled_mvd; ++ref_idx) {
    av2_make_default_subpel_ms_params(&ms_params[ref_idx], cpi, x, bsize,
                                      &ref_mvs[ref_idx], mbmi->pb_mv_precision,
                                      0, NULL);
    mv_limits[ref_idx] = &ms_params[ref_idx].mv_limits;
  }
  int64_t best_model_rd = INT64_MAX;
  const MV initial_mvs[2] = { mbmi->mv[0].as_mv, mbmi->mv[1].as_mv };
  MV best_mvs[2] = { mbmi->mv[0].as_mv, mbmi->mv[1].as_mv };

  // Get the position of the last non-zero mv component
  int initial_last_non_zero_pos = 0;
  int curr_pos = 0;
  int initial_num_nonzero_mvd_comp = 0;
  int initial_last_sign = -1;

  for (int ref_idx = start_signaled_mv_ref_idx;
       ref_idx < start_signaled_mv_ref_idx + num_signaled_mvd; ++ref_idx) {
    for (int comp = 0; comp < 2; comp++) {
      int16_t this_mvd_comp =
          comp == 0 ? mv_diff[ref_idx].row : mv_diff[ref_idx].col;
      if (this_mvd_comp) {
        initial_last_non_zero_pos = curr_pos;
        initial_last_sign = (this_mvd_comp < 0);
        initial_num_nonzero_mvd_comp++;
      }
      curr_pos++;
    }
  }

  curr_pos = 0;
  int offsets[NUMBER_OF_ITER_PER_COMP] = { 1, -1, 3, -3 };

  assert(initial_num_nonzero_mvd_comp >= th_for_num_nonzero);

  // int max_num_iterations = is_4k_or_larger ? 2 : 4;

  for (int ref_idx = start_signaled_mv_ref_idx;
       ref_idx < start_signaled_mv_ref_idx + num_signaled_mvd; ++ref_idx) {
    for (int comp = 0; comp < 2; comp++) {
      int16_t this_mvd_comp =
          comp == 0 ? mv_diff[ref_idx].row : mv_diff[ref_idx].col;
      assert(IMPLIES(curr_pos > initial_last_non_zero_pos, this_mvd_comp == 0));

      if (curr_pos <= initial_last_non_zero_pos || best_model_rd == INT64_MAX) {
        const int max_num_iterations = 2;
        for (int iteration = 0; iteration < max_num_iterations; iteration++) {
          int16_t modified_mvd_comp =
              this_mvd_comp + mv_delta * offsets[iteration];
          if (abs(modified_mvd_comp) > MV_MAX) continue;

          MV modified_mvds[2] = { mv_diff[0], mv_diff[1] };
          if (comp == 0) {
            modified_mvds[ref_idx].row = modified_mvd_comp;
          } else {
            modified_mvds[ref_idx].col = modified_mvd_comp;
          }
          int modified_last_sign = -1;
          int modified_last_comp = -1;
          int modified_num_non_zero_comp = 0;
          if (!is_this_mvds_valid_for_derivesign(
                  modified_mvds, mbmi->pb_mv_precision, is_adaptive_mvd,
                  start_signaled_mv_ref_idx, num_signaled_mvd,
                  &modified_last_sign, &modified_last_comp,
                  &modified_num_non_zero_comp, th_for_num_nonzero))
            continue;
          // It is not allowed to modify the last non-zero MVD to 0
          // It is also not allowed to modify any coeff to 0 if
          // (num_nonzero_mvd_comp == get_derive_sign_nzero_th(mbmi);)
          if (modified_mvd_comp == 0 &&
              (initial_num_nonzero_mvd_comp == th_for_num_nonzero ||
               curr_pos == initial_last_non_zero_pos))
            continue;

          // Not allowed to change the sign of the last component
          if (curr_pos == initial_last_non_zero_pos &&
              ((initial_last_sign != (modified_mvd_comp < 0))))
            continue;

          MV this_mvs[2] = { initial_mvs[0], initial_mvs[1] };
          update_mv_component_from_mvd(
              modified_mvd_comp, ref_mvs[ref_idx], comp,
              enable_adaptive_mvd_resolution(cm, mbmi), mbmi->pb_mv_precision,
              &this_mvs[ref_idx]);

          if (av2_is_subpelmv_in_range(mv_limits[ref_idx], this_mvs[ref_idx])) {
            mbmi->mv[ref_idx].as_mv = this_mvs[ref_idx];
            if (is_compound) {
              if (joint_mvd_mode) {
                MV other_mv;
                int valid = get_othermv_for_jointmv_mode(
                    cpi, bsize, x, mbmi, this_mvs[ref_idx], &other_mv,
                    mbmi->pb_mv_precision, is_adaptive_mvd,
                    start_signaled_mv_ref_idx);
                if (!valid) continue;
                mbmi->mv[!ref_idx].as_mv = other_mv;
              } else {
                // assert(av2_is_subpelmv_in_range(mv_limits[!ref_idx],
                // this_mvs[!ref_idx]));
                mbmi->mv[!ref_idx].as_mv = this_mvs[!ref_idx];
              }
            }
            int this_mv_rate;
            MV this_mv[2] = { mbmi->mv[0].as_mv, mbmi->mv[1].as_mv };
            av2_get_model_rd(cpi, xd, x, bsize, orig_dst, this_mv, ref_mvs,
                             num_signaled_mvd, &rate_sum, &dist_sum,
                             &this_mv_rate, start_signaled_mv_ref_idx);
            if (modified_num_non_zero_comp >= th_for_num_nonzero) {
              this_mv_rate -= av2_mv_sign_cost(
                  modified_last_sign, modified_last_comp, &x->mv_costs,
                  MV_COST_WEIGHT, 7, is_adaptive_mvd);
            }
            int64_t comp_model_rd_cur = RDCOST(
                x->rdmult, rate_without_mv + this_mv_rate + rate_sum, dist_sum);
            if (comp_model_rd_cur < best_model_rd) {
              best_model_rd = comp_model_rd_cur;
              best_mvs[ref_idx] = mbmi->mv[ref_idx].as_mv;
              if (is_compound) best_mvs[!ref_idx] = mbmi->mv[!ref_idx].as_mv;
              best_mv_rate = this_mv_rate;

              assert(this_mvs[ref_idx].row == mbmi->mv[ref_idx].as_mv.row);
              assert(this_mvs[ref_idx].col == mbmi->mv[ref_idx].as_mv.col);
              if (is_compound && !joint_mvd_mode) {
                assert(this_mvs[!ref_idx].row == mbmi->mv[!ref_idx].as_mv.row);
                assert(this_mvs[!ref_idx].col == mbmi->mv[!ref_idx].as_mv.col);
              }
            }
          }
        }
      }
      curr_pos++;
    }
  }

  mbmi->mv[0].as_mv = best_mvs[0];
  if (is_compound) mbmi->mv[1].as_mv = best_mvs[1];
  *tmp_rate_mv = best_mv_rate;
  assert(IMPLIES(best_model_rd != INT64_MAX,
                 !(mbmi->mv[0].as_mv.row == initial_mvs[0].row &&
                   mbmi->mv[0].as_mv.col == initial_mvs[0].col &&
                   mbmi->mv[1].as_mv.row == initial_mvs[1].row &&
                   mbmi->mv[1].as_mv.col == initial_mvs[1].col)));

  return (best_model_rd != INT64_MAX);
}

// Reject this motion mode if modelrd is larder that the stored model rd values
//  Return 1 means reject this mode
//  Return 0 means compute full RD
static int prune_motion_mode(int64_t this_model_rd,
                             int64_t top_motion_mode_model_rd[]) {
  const double thresh_top = 1.00;
  for (int i = 0; i < TOP_MOTION_MODE_MODEL_COUNT; i++) {
    if (this_model_rd < top_motion_mode_model_rd[i]) {
      for (int j = TOP_MOTION_MODE_MODEL_COUNT - 1; j > i; j--) {
        top_motion_mode_model_rd[j] = top_motion_mode_model_rd[j - 1];
      }
      top_motion_mode_model_rd[i] = this_model_rd;
      break;
    }
  }
  if (top_motion_mode_model_rd[TOP_MOTION_MODE_MODEL_COUNT - 1] != INT64_MAX &&
      this_model_rd >
          thresh_top *
              top_motion_mode_model_rd[TOP_MOTION_MODE_MODEL_COUNT - 1])
    return 1;

  return 0;
}
/*!\brief AV2 motion mode search
 *
 * \ingroup inter_mode_search
 * Function to search over and determine the motion mode. It will update
 * mbmi->motion_mode and determine any necessary side information for the
 * selected motion mode. It will also perform the full transform search, unless
 * the input parameter do_tx_search indicates to do an estimation of the RD
 * rather than an RD corresponding to a full transform search. It will return
 * the RD for the final motion_mode.
 * Do the RD search for a given inter mode and compute all information relevant
 * to the input mode. It will compute the best MV,
 * compound parameters (if the mode is a compound mode) and interpolation filter
 * parameters.
 *
 * \param[in]     cpi               Top-level encoder structure.
 * \param[in]     tile_data         Pointer to struct holding adaptive
 *                                  data/contexts/models for the tile during
 *                                  encoding.
 * \param[in]     x                 Pointer to struct holding all the data for
 *                                  the current macroblock.
 * \param[in]     bsize             Current block size.
 * \param[in,out] rd_stats          Struct to keep track of the overall RD
 *                                  information.
 * \param[in,out] rd_stats_y        Struct to keep track of the RD information
 *                                  for only the Y plane.
 * \param[in,out] rd_stats_uv       Struct to keep track of the RD information
 *                                  for only the UV planes.
 * \param[in]     args              HandleInterModeArgs struct holding
 *                                  miscellaneous arguments for inter mode
 *                                  search. See the documentation for this
 *                                  struct for a description of each member.
 * \param[in]     ref_best_rd       Best RD found so far for this block.
 *                                  It is used for early termination of this
 *                                  search if the RD exceeds this value.
 * \param[in,out] ref_skip_rd       A length 2 array, where skip_rd[0] is the
 *                                  best total RD for a skip mode so far, and
 *                                  skip_rd[1] is the best RD for a skip mode so
 *                                  far in luma. This is used as a speed feature
 *                                  to skip the transform search if the computed
 *                                  skip RD for the current mode is not better
 *                                  than the best skip_rd so far.
 * \param[in,out] rate_mv           The rate associated with the motion vectors.
 *                                  This will be modified if a motion search is
 *                                  done in the motion mode search.
 * \param[in,out] orig_dst          A prediction buffer to hold a computed
 *                                  prediction. This will eventually hold the
 *                                  final prediction, and the tmp_dst info will
 *                                  be copied here.
 * \param[in,out] best_est_rd       Estimated RD for motion mode search if
 *                                  do_tx_search (see below) is 0.
 * \param[in]     do_tx_search      Parameter to indicate whether or not to do
 *                                  a full transform search. This will compute
 *                                  an estimated RD for the modes without the
 *                                  transform search and later perform the full
 *                                  transform search on the best candidates.
 * \param[in]     inter_modes_info  InterModesInfo struct to hold inter mode
 *                                  information to perform a full transform
 *                                  search only on winning candidates searched
 *                                  with an estimate for transform coding RD.
 * \param[in,out] top_motion_mode_model_rd       Top motion mode model RDs.
 * \param[in]     eval_motion_mode  Boolean whether or not to evaluate motion
 *                                  motion modes other than SIMPLE_TRANSLATION.
 * \return Returns INT64_MAX if the determined motion mode is invalid and the
 * current motion mode being tested should be skipped. It returns 0 if the
 * motion mode search is a success.
 */
static int64_t motion_mode_rd(
    const AV2_COMP *const cpi, TileDataEnc *tile_data, MACROBLOCK *const x,
    BLOCK_SIZE bsize, RD_STATS *rd_stats, RD_STATS *rd_stats_y,
    RD_STATS *rd_stats_uv, HandleInterModeArgs *const args, int64_t ref_best_rd,
    int64_t *ref_skip_rd, int *rate_mv, const BUFFER_SET *orig_dst,
    int64_t *best_est_rd, int do_tx_search, InterModesInfo *inter_modes_info,
    int64_t top_motion_mode_model_rd[], int eval_motion_mode) {
  const AV2_COMMON *const cm = &cpi->common;
  const FeatureFlags *const features = &cm->features;
  TxfmSearchInfo *txfm_info = &x->txfm_search_info;
  const int num_planes = av2_num_planes(cm);
  MACROBLOCKD *xd = &x->e_mbd;
  MB_MODE_INFO *mbmi = xd->mi[0];
  MB_MODE_INFO_EXT *mbmi_ext = x->mbmi_ext;
  const int is_comp_pred = has_second_ref(mbmi);
  const PREDICTION_MODE this_mode = mbmi->mode;
  const int rate2_nocoeff = rd_stats->rate;
  int best_xskip_txfm = 0;
  RD_STATS best_rd_stats, best_rd_stats_y, best_rd_stats_uv;
  uint8_t best_blk_skip[MAX_MB_PLANE][MAX_MIB_SIZE * MAX_MIB_SIZE];
  TX_TYPE best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE];
  CctxType best_cctx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE];
  const int rate_mv0 = this_mode == WARPMV ? 0 : *rate_mv;
  int pts0[SAMPLES_ARRAY_SIZE], pts_inref0[SAMPLES_ARRAY_SIZE];
  int pts1[SAMPLES_ARRAY_SIZE], pts_inref1[SAMPLES_ARRAY_SIZE];
  assert(IMPLIES(mbmi->mode == WARPMV, (rate_mv0 == 0)));

  assert(mbmi->ref_frame[1] != INTRA_FRAME);
  const MV_REFERENCE_FRAME ref_frame_1 = mbmi->ref_frame[1];
  (void)tile_data;
  av2_invalid_rd_stats(&best_rd_stats);
  avm_clear_system_state();
  mbmi->num_proj_ref[0] = 1;  // assume num_proj_ref >=1
  mbmi->num_proj_ref[1] = 1;  // assume num_proj_ref >=1
  mbmi->wm_params[0].invalid = 1;
  mbmi->wm_params[1].invalid = 1;

  mbmi->warp_ref_idx = 0;
  mbmi->max_num_warp_candidates = 0;
  mbmi->warpmv_with_mvd_flag = 0;
  mbmi->six_param_warp_model_flag = 0;

  mbmi->warp_precision_idx = 0;
  // Buffer to store the previously searched warp models
  warp_mode_info_array prev_best_models;
  reset_warp_stats_buffer(&prev_best_models);

  mbmi->warp_inter_intra = 0;
  const uint8_t is_low_delay_enc = (cpi->oxcf.gf_cfg.lag_in_frames == 0);

  int allowed_motion_modes = motion_mode_allowed(
      cm, xd, mbmi_ext->ref_mv_stack[mbmi->ref_frame[0]], mbmi);
  if ((allowed_motion_modes & (1 << WARP_CAUSAL))) {
    // Collect projection samples used in least squares approximation of
    // the warped motion parameters if WARP_CAUSAL is going to be searched.
    mbmi->num_proj_ref[0] = av2_findSamples(cm, xd, pts0, pts_inref0, 0);
    if (has_second_ref(mbmi))
      mbmi->num_proj_ref[1] = av2_findSamples(cm, xd, pts1, pts_inref1, 1);
    else
      mbmi->num_proj_ref[1] = 0;
  }
  const int total_samples0 = mbmi->num_proj_ref[0];
  const int total_samples1 = mbmi->num_proj_ref[1];
  if ((total_samples0 == 0 && total_samples1 == 0)) {
    // Do not search WARP_CAUSAL if there are no samples to use to determine
    // warped parameters.
    allowed_motion_modes &= ~(1 << WARP_CAUSAL);
  }

  int_mv previous_mvs[MAX_WARP_REF_CANDIDATES];
  for (int w_ref_idx = 0; w_ref_idx < MAX_WARP_REF_CANDIDATES; w_ref_idx++) {
    previous_mvs[w_ref_idx].as_int = INVALID_MV;
  }

  mbmi->num_proj_ref[0] = 0;  // assume num_proj_ref >=1 ??????????
  mbmi->num_proj_ref[1] = 0;  // assume num_proj_ref >=1
  int num_rd_check = 0;
  const MB_MODE_INFO base_mbmi = *mbmi;
  MB_MODE_INFO best_mbmi;
  SUBMB_INFO best_submi[MAX_MIB_SIZE * MAX_MIB_SIZE];
  SUBMB_INFO base_submi[MAX_MIB_SIZE * MAX_MIB_SIZE];
  store_submi(xd, cm, base_submi, bsize);
  const int interp_filter = features->interp_filter;
  const int switchable_rate =
      av2_is_interp_needed(cm, xd)
          ? av2_get_switchable_rate(x, xd, interp_filter)
          : 0;
  int64_t best_rd = INT64_MAX;
  int best_rate_mv = rate_mv0;
  const int mi_row = xd->mi_row;
  const int mi_col = xd->mi_col;
  int modes_to_search =
      (base_mbmi.mode == WARPMV || base_mbmi.mode == WARP_NEWMV)
          ? allowed_motion_modes
          : select_modes_to_search(cpi, allowed_motion_modes, eval_motion_mode,
                                   args->skip_motion_mode);

  uint8_t enable_tx_prune =
      top_motion_mode_model_rd && do_tx_search && !eval_motion_mode;

  // Main function loop. This loops over all of the possible motion modes and
  // computes RD to determine the best one. This process includes computing
  // any necessary side information for the motion mode and performing the
  // transform search.
  for (int mode_index = SIMPLE_TRANSLATION; mode_index < MOTION_MODES;
       mode_index++) {
    if ((modes_to_search & (1 << mode_index)) == 0) continue;
    if (base_mbmi.refinemv_flag && mode_index != SIMPLE_TRANSLATION) continue;
    for (int warp_inter_intra = 0;
         warp_inter_intra < 1 + allow_warp_inter_intra(&base_mbmi);
         warp_inter_intra++) {
      // Disable searching of warp-intra mode for low-delay configuration
      if (is_low_delay_enc && warp_inter_intra) continue;

      int max_warp_ref_idx = 1;
      uint8_t valid_num_candidates = 0;
      if (mode_index == WARP_DELTA) {
        max_warp_ref_idx = MAX_WARP_REF_CANDIDATES;

        av2_find_warp_delta_base_candidates(
            xd, &base_mbmi,
            mbmi_ext->warp_param_stack[av2_ref_frame_type(base_mbmi.ref_frame)],
            xd->warp_param_stack[av2_ref_frame_type(base_mbmi.ref_frame)],
            xd->valid_num_warp_candidates[av2_ref_frame_type(
                base_mbmi.ref_frame)],
            &valid_num_candidates);
      }
      for (int warp_ref_idx = 0; warp_ref_idx < max_warp_ref_idx;
           warp_ref_idx++) {
        if (mode_index == WARP_DELTA && warp_ref_idx >= valid_num_candidates)
          continue;

        for (int warpmv_with_mvd_flag = 0;
             warpmv_with_mvd_flag < (1 + (base_mbmi.mode == WARPMV));
             warpmv_with_mvd_flag++) {
          for (int warp_precision_idx = 0;
               warp_precision_idx <
               ((mode_index == WARP_DELTA) ? NUM_WARP_PRECISION_MODES : 1);
               warp_precision_idx++) {
            if (warp_precision_idx && base_mbmi.mode == WARPMV) continue;
            int tmp_rate2 = rate2_nocoeff;
            int tmp_rate_mv = rate_mv0;

            *mbmi = base_mbmi;
            update_submi(xd, cm, base_submi, bsize);
            mbmi->warp_ref_idx = warp_ref_idx;
            mbmi->max_num_warp_candidates =
                (mode_index == WARP_DELTA) ? max_warp_ref_idx : 0;
            assert(valid_num_candidates <= mbmi->max_num_warp_candidates);

            mbmi->motion_mode = (MOTION_MODE)mode_index;
            if (mbmi->motion_mode != INTERINTRA) {
              assert(mbmi->ref_frame[1] != INTRA_FRAME);
            }

            if (warpmv_with_mvd_flag && !allow_warpmv_with_mvd_coding(cm, mbmi))
              continue;

            mbmi->warpmv_with_mvd_flag = warpmv_with_mvd_flag;

            mbmi->warp_inter_intra = 0;  // initialize to 0 so that warp search
                                         // can-be performed without inter-intra
            const uint8_t org_warp_inter_intra = warp_inter_intra;

            mbmi->warp_precision_idx = warp_precision_idx;
            if (mbmi->warp_precision_idx &&
                !allow_warp_parameter_signaling(cm, mbmi))
              continue;

            // Only WARP_DELTA is supported for WARPMV mode
            assert(
                IMPLIES(mbmi->mode == WARPMV, mbmi->motion_mode == WARP_DELTA));

            if (is_warp_mode(mbmi->motion_mode)) {
              mbmi->interp_fltr = av2_unswitchable_filter(interp_filter);
            }

            if (mbmi->motion_mode == SIMPLE_TRANSLATION) {
              // SIMPLE_TRANSLATION mode: no need to recalculate.
              // The prediction is calculated before motion_mode_rd() is called
              // in handle_inter_mode()
              if (is_mvd_sign_derive_allowed(cm, xd, mbmi)) {
                MV mv_diff[2] = { kZeroMv, kZeroMv };
                MV ref_mvs[2] = { kZeroMv, kZeroMv };
                int num_signaled_mvd = 0;
                int start_signaled_mvd_idx = 0;
                int num_nonzero_mvd = 0;
                int th_for_num_nonzero = get_derive_sign_nzero_th(mbmi);
                if (need_mv_adjustment(xd, cm, x, mbmi, bsize, mv_diff, ref_mvs,
                                       mbmi->pb_mv_precision, &num_signaled_mvd,
                                       &start_signaled_mvd_idx,
                                       &num_nonzero_mvd)) {
                  if (!av2_adjust_mvs_for_derive_sign(
                          cpi, x, bsize, orig_dst, start_signaled_mvd_idx,
                          num_signaled_mvd, mv_diff, ref_mvs, rate2_nocoeff,
                          rate_mv0, &tmp_rate_mv))
                    continue;

                  tmp_rate2 = rate2_nocoeff - rate_mv0 + tmp_rate_mv;

                  assert(!need_mv_adjustment(
                      xd, cm, x, mbmi, bsize, mv_diff, ref_mvs,
                      mbmi->pb_mv_precision, &num_signaled_mvd,
                      &start_signaled_mvd_idx, &num_nonzero_mvd));

                  // Rebuild the predictor with updated MV
                  av2_enc_build_inter_predictor(cm, xd, mi_row, mi_col,
                                                orig_dst, bsize, 0,
                                                av2_num_planes(cm) - 1);

                } else if (num_nonzero_mvd >= th_for_num_nonzero) {
                  int last_sign_cost = get_last_sign_cost(
                      x, enable_adaptive_mvd_resolution(cm, mbmi), mv_diff,
                      start_signaled_mvd_idx, num_signaled_mvd);
                  tmp_rate_mv = rate_mv0 - last_sign_cost;
                  tmp_rate2 = rate2_nocoeff - last_sign_cost;
                  assert(tmp_rate_mv >= 0);
                }
              }
            } else if (mbmi->motion_mode == WARP_CAUSAL) {
              int pts[SAMPLES_ARRAY_SIZE], pts_inref[SAMPLES_ARRAY_SIZE];
              mbmi->wm_params[0].wmtype = DEFAULT_WMTYPE;
              mbmi->wm_params[1].wmtype = DEFAULT_WMTYPE;

              mbmi->warp_inter_intra =
                  0;  // initialize to 0 so that warp search can-be performed
                      // without inter-intra

              int l0_invalid = 1, l1_invalid = 1;
              mbmi->num_proj_ref[0] = total_samples0;
              mbmi->num_proj_ref[1] = total_samples1;
              memcpy(pts, pts0, total_samples0 * 2 * sizeof(*pts0));
              memcpy(pts_inref, pts_inref0,
                     total_samples0 * 2 * sizeof(*pts_inref0));
              // Compute the warped motion parameters with a least squares fit
              //  using the collected samples
              av2_find_projection(
                  mbmi->num_proj_ref[0], pts, pts_inref, bsize,
                  mbmi->mv[0].as_mv, &mbmi->wm_params[0], mi_row, mi_col

                  ,
                  get_ref_scale_factors_const(cm, mbmi->ref_frame[0])

              );
              mbmi->wm_params[0].invalid = l0_invalid = 0;

              if (has_second_ref(mbmi)) {
                memcpy(pts, pts1, total_samples1 * 2 * sizeof(*pts1));
                memcpy(pts_inref, pts_inref1,
                       total_samples1 * 2 * sizeof(*pts_inref1));
                //  Compute the warped motion parameters with a least squares
                //  fit
                //   using the collected samples
                av2_find_projection(
                    mbmi->num_proj_ref[1], pts, pts_inref, bsize,
                    mbmi->mv[1].as_mv, &mbmi->wm_params[1], mi_row, mi_col

                    ,
                    get_ref_scale_factors_const(cm, mbmi->ref_frame[1])

                );
                mbmi->wm_params[1].invalid = l1_invalid = 0;
              }

              if (!l0_invalid && (!has_second_ref(mbmi) || !l1_invalid)) {
                if (((this_mode == WARP_NEWMV || this_mode == NEW_NEWMV) &&
                     !l0_invalid) &&
                    (mbmi->pb_mv_precision >= MV_PRECISION_ONE_PEL)) {
                  // Refine MV for NEWMV mode
                  const int_mv mv0 = mbmi->mv[0];
                  const int_mv ref_mv = av2_get_ref_mv(x, 0);
                  const MvSubpelPrecision pb_mv_precision =
                      mbmi->pb_mv_precision;

                  SUBPEL_MOTION_SEARCH_PARAMS ms_params;
                  av2_make_default_subpel_ms_params(&ms_params, cpi, x, bsize,
                                                    &ref_mv.as_mv,
                                                    pb_mv_precision, 0, NULL);
                  // Refine MV in a small range.
                  av2_refine_warped_mv(xd, cm, &ms_params, bsize, pts0,
                                       pts_inref0, total_samples0, 0,
                                       cpi->sf.mv_sf.warp_search_method,
                                       cpi->sf.mv_sf.warp_search_iters);
                  if (mv0.as_int != mbmi->mv[0].as_int) {
                    // Keep the refined MV and WM parameters.
                    // Keep the refined MV and WM parameters.
                    if (mbmi->mode == NEW_NEWMV) {
                      int tmp_rate_mv0 = av2_mv_bit_cost(
                          &mv0.as_mv, &ref_mv.as_mv, pb_mv_precision,
                          &x->mv_costs, MV_COST_WEIGHT,
                          ms_params.mv_cost_params.is_adaptive_mvd);
                      tmp_rate_mv = av2_mv_bit_cost(
                          &mbmi->mv[0].as_mv, &ref_mv.as_mv, pb_mv_precision,
                          &x->mv_costs, MV_COST_WEIGHT,
                          ms_params.mv_cost_params.is_adaptive_mvd);

                      tmp_rate2 = rate2_nocoeff - tmp_rate_mv0 + tmp_rate_mv;
                    } else {
                      tmp_rate_mv = av2_mv_bit_cost(
                          &mbmi->mv[0].as_mv, &ref_mv.as_mv, pb_mv_precision,
                          &x->mv_costs, MV_COST_WEIGHT,
                          ms_params.mv_cost_params.is_adaptive_mvd);
                      tmp_rate2 = rate2_nocoeff - rate_mv0 + tmp_rate_mv;
                    }
                  }
                }
                if (!l1_invalid && this_mode == NEW_NEWMV) {
                  // Refine MV for NEWMV mode
                  const int_mv mv1 = mbmi->mv[1];
                  const int_mv ref_mv = av2_get_ref_mv(x, 1);

                  const MvSubpelPrecision pb_mv_precision =
                      mbmi->pb_mv_precision;

                  SUBPEL_MOTION_SEARCH_PARAMS ms_params;
                  av2_make_default_subpel_ms_params(&ms_params, cpi, x, bsize,
                                                    &ref_mv.as_mv,

                                                    pb_mv_precision, 0, NULL);
                  // Refine MV in a small range.
                  av2_refine_warped_mv(xd, cm, &ms_params, bsize, pts1,
                                       pts_inref1, total_samples1, 1,
                                       cpi->sf.mv_sf.warp_search_method,
                                       cpi->sf.mv_sf.warp_search_iters);

                  if (mv1.as_int != mbmi->mv[1].as_int) {
                    // Keep the refined MV and WM parameters.
                    int tmp_rate_mv1 = av2_mv_bit_cost(
                        &mv1.as_mv, &ref_mv.as_mv, pb_mv_precision,
                        &x->mv_costs, MV_COST_WEIGHT,
                        ms_params.mv_cost_params.is_adaptive_mvd);
                    tmp_rate_mv = av2_mv_bit_cost(
                        &mbmi->mv[1].as_mv, &ref_mv.as_mv, pb_mv_precision,
                        &x->mv_costs, MV_COST_WEIGHT,
                        ms_params.mv_cost_params.is_adaptive_mvd);

                    tmp_rate2 = tmp_rate2 - tmp_rate_mv1 + tmp_rate_mv;
                  }
                }
                if (!mbmi->wm_params[0].invalid)
                  assign_warpmv(cm, xd->submi, bsize, &mbmi->wm_params[0],
                                mi_row, mi_col, 0);
                if (!mbmi->wm_params[1].invalid)
                  assign_warpmv(cm, xd->submi, bsize, &mbmi->wm_params[1],
                                mi_row, mi_col, 1);

                // Build the warped predictor
                av2_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL,
                                              bsize, 0, av2_num_planes(cm) - 1);
              } else {
                continue;
              }
            } else if (mbmi->motion_mode == INTERINTRA) {
              const int ret = av2_handle_inter_intra_mode(
                  cpi, x, bsize, mbmi, args, ref_best_rd, &tmp_rate_mv,
                  &tmp_rate2, orig_dst);
              if (ret < 0) continue;
              assert(mbmi->motion_mode == INTERINTRA);
            } else if (mbmi->motion_mode == WARP_DELTA) {
              if (mbmi->mode == WARP_NEWMV &&
                  mbmi->pb_mv_precision < MV_PRECISION_ONE_PEL) {
                // Don't bother with warp modes for MV precisions >1px
                continue;
              }

              int_mv wrl_ref_mv = mbmi->mv[0];
              mbmi->warp_inter_intra =
                  0;  // initialize to 0 so that warp search can-be performed
                      // without inter-intra

              // Build the motion vector of the WARPMV mode
              if (mbmi->mode == WARPMV) {
                WarpedMotionParams ref_model =
                    mbmi_ext
                        ->warp_param_stack[av2_ref_frame_type(mbmi->ref_frame)]
                                          [mbmi->warp_ref_idx]
                        .wm_params;
                mbmi->mv[0] = get_mv_from_wrl(
                    xd, &ref_model,

                    mbmi->warpmv_with_mvd_flag ? mbmi->pb_mv_precision :

                                               MV_PRECISION_ONE_EIGHTH_PEL,
                    bsize, xd->mi_col, xd->mi_row);

                assert(mbmi->pb_mv_precision == mbmi->max_mv_precision);

                if (!is_warp_candidate_inside_of_frame(cm, xd, mbmi->mv[0]))
                  continue;
                wrl_ref_mv = mbmi->mv[0];
              }
              int_mv mv0 = mbmi->mv[0];
              const int_mv ref_mv =
                  (mbmi->mode == WARPMV) ? wrl_ref_mv : av2_get_ref_mv(x, 0);
              SUBPEL_MOTION_SEARCH_PARAMS ms_params;
              av2_make_default_subpel_ms_params(&ms_params, cpi, x, bsize,
                                                &ref_mv.as_mv,

                                                mbmi->pb_mv_precision, 0, NULL);
              int valid = 0;

              mbmi->six_param_warp_model_flag = 0;
              if (!allow_warp_parameter_signaling(cm, mbmi)) {
                if (mbmi->warp_precision_idx) continue;

                // Default parameters are not searched if the delta is not
                // signalled
                if (mbmi_ext
                        ->warp_param_stack[av2_ref_frame_type(mbmi->ref_frame)]
                                          [mbmi->warp_ref_idx]
                        .proj_type == PROJ_DEFAULT)
                  continue;
                // search MVD if mbmi->warpmv_with_mvd_flag is used.
                if (mbmi->mode == WARPMV && mbmi->warpmv_with_mvd_flag) {
                  if (previous_mvs[mbmi->warp_ref_idx].as_int == INVALID_MV) {
                    int tmp_trans_ratemv = 0;
                    av2_single_motion_search(cpi, x, bsize, 0,
                                             &tmp_trans_ratemv, 16, NULL,
                                             &mbmi->mv[0], &ref_mv);
                    previous_mvs[mbmi->warp_ref_idx].as_int =
                        mbmi->mv[0].as_int;
                  } else {
                    mbmi->mv[0].as_int =
                        previous_mvs[mbmi->warp_ref_idx].as_int;
                  }
                }
                valid = av2_refine_mv_for_base_param_warp_model(
                    cm, xd, mbmi, mbmi_ext, &ms_params,
                    cpi->sf.mv_sf.warp_search_method,
                    cpi->sf.mv_sf.warp_search_iters);
              } else {
                mbmi->six_param_warp_model_flag =
                    get_default_six_param_flag(cm, mbmi);
                valid = av2_pick_warp_delta(
                    cm, xd, mbmi, &ms_params, &x->mode_costs, &prev_best_models,
                    mbmi_ext->warp_param_stack[av2_ref_frame_type(
                        mbmi->ref_frame)]);
              }

              if (!valid) {
                continue;
              }

              // If we changed the MV, update costs
              if (mv0.as_int != mbmi->mv[0].as_int ||
                  mbmi->warpmv_with_mvd_flag) {
                // Keep the refined MV and WM parameters.
                tmp_rate_mv = av2_mv_bit_cost(
                    &mbmi->mv[0].as_mv, &ref_mv.as_mv, mbmi->pb_mv_precision,
                    &x->mv_costs, MV_COST_WEIGHT,
                    ms_params.mv_cost_params.is_adaptive_mvd);

                tmp_rate2 = rate2_nocoeff - rate_mv0 + tmp_rate_mv;
                assert(mbmi->mode == WARP_NEWMV || mbmi->warpmv_with_mvd_flag);
                assert(IMPLIES(mbmi->mode == WARPMV, rate_mv0 == 0));
              }
              assign_warpmv(cm, xd->submi, bsize, &mbmi->wm_params[0], mi_row,
                            mi_col, 0);
              mbmi->warp_inter_intra = org_warp_inter_intra;
              if (mbmi->warp_inter_intra) {
                const int ret = av2_handle_inter_intra_mode(
                    cpi, x, bsize, mbmi, args, ref_best_rd, &tmp_rate_mv,
                    &tmp_rate2, orig_dst);
                if (ret < 0) continue;
              }
              av2_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize,
                                            0, av2_num_planes(cm) - 1);
            } else if (mbmi->motion_mode == WARP_EXTEND) {
              if (mbmi->pb_mv_precision < MV_PRECISION_ONE_PEL) {
                // Don't bother with warp modes for MV precisions >1px
                continue;
              }
              mbmi->warp_inter_intra =
                  0;  // initialize to 0 so that warp search can-be performed
                      // without inter-intra
              CANDIDATE_MV *neighbor =
                  &mbmi_ext->ref_mv_stack[mbmi->ref_frame[0]]
                                         [get_ref_mv_idx(mbmi, 0)];
              POSITION base_pos = { 0, 0 };
              if (!get_extend_base_pos(cm, xd, mbmi, neighbor->row_offset,
                                       neighbor->col_offset, &base_pos)) {
                continue;
              }
              const MB_MODE_INFO *neighbor_mi =
                  xd->mi[base_pos.row * xd->mi_stride + base_pos.col];

              assert(!is_tip_ref_frame(neighbor_mi->ref_frame[0]));

              assert(mbmi->mode == WARP_NEWMV);

              bool neighbor_is_above =
                  xd->up_available && (base_pos.row == -1 && base_pos.col >= 0);

              WarpedMotionParams neighbor_params;
              av2_get_neighbor_warp_model(cm, xd, neighbor_mi,
                                          &neighbor_params);

              const int_mv ref_mv = av2_get_ref_mv(x, 0);
              SUBPEL_MOTION_SEARCH_PARAMS ms_params;
              av2_make_default_subpel_ms_params(&ms_params, cpi, x, bsize,
                                                &ref_mv.as_mv,
                                                mbmi->pb_mv_precision, 0, NULL);
              const SubpelMvLimits *mv_limits = &ms_params.mv_limits;

              // Note: The warp filter is only able to accept small deviations
              // from the identity transform, up to 1/4 pel of shift per
              // pixel. Especially for small blocks, it is likely that the
              // motion vector estimated by the newmv search will be too
              // distant from the neighbor's motion vectors for the warp
              // filter to be applied. However, we don't want to give up the
              // benefits of a good initial MV in the cases where a suitable
              // one has already been found.
              //
              // To get the best of both worlds, we run an initial test to see
              // if the motion vector found by newmv search gives a valid
              // motion model. If so, we use that as the starting point for
              // refinement. Otherwise, we use the MV which is predicted by
              // the neighbor's warp model
              // TODO(rachelbarker): Do we need this logic?

              // Backup initial motion vector and resulting warp params
              int_mv mv0 = mbmi->mv[0];
              WarpedMotionParams wm_params0;
              if (!av2_extend_warp_model(
                      neighbor_is_above, bsize, &mbmi->mv[0].as_mv, mi_row,
                      mi_col, &neighbor_params, &wm_params0

                      ,
                      get_ref_scale_factors_const(cm, mbmi->ref_frame[0])

                          )) {
                // NEWMV search produced a valid model
                mbmi->wm_params[0] = wm_params0;
              } else {
                // NEWMV search did not produce a valid model, so fall back to
                // starting with the motion vector predicted by the neighbor's
                // warp model (if any)
                mbmi->mv[0] = get_warp_motion_vector(xd, &neighbor_params,
                                                     mbmi->pb_mv_precision,
                                                     bsize, mi_col, mi_row);

                if (mbmi->pb_mv_precision >= MV_PRECISION_HALF_PEL) {
                  FULLPEL_MV tmp_full_mv =
                      get_fullmv_from_mv(&mbmi->mv[0].as_mv);
                  MV tmp_sub_mv = get_mv_from_fullmv(&tmp_full_mv);
                  MV sub_mv_offset = { 0, 0 };
                  get_phase_from_mv(ref_mv.as_mv, &sub_mv_offset,
                                    mbmi->pb_mv_precision);
                  mbmi->mv[0].as_mv.col = tmp_sub_mv.col + sub_mv_offset.col;
                  mbmi->mv[0].as_mv.row = tmp_sub_mv.row + sub_mv_offset.row;
                }
                // Check that the prediction is in range
                if (!av2_is_subpelmv_in_range(mv_limits, mbmi->mv[0].as_mv)) {
                  continue;
                }

                // Regenerate model with this new MV
                //
                // Note: This should be very close to the neighbor's warp
                // model, but may be slightly different due to rounding. So it
                // may be invalid even if the neighbor's warp model is valid.
                // Because an exact copy will already have been tried using
                // the NEARMV mode, we can just detect an invalid model and
                // bail out.
                //
                // TODO(rachelbarker): Is it worth trying to search anyway in
                // this case, in order to try to find a valid model?
                if (av2_extend_warp_model(
                        neighbor_is_above, bsize, &mbmi->mv[0].as_mv, mi_row,
                        mi_col, &neighbor_params, &mbmi->wm_params[0]

                        ,
                        get_ref_scale_factors_const(cm, mbmi->ref_frame[0])

                            )) {
                  continue;
                }
              }

              // Refine motion vector. The final choice of MV and warp model
              // are stored directly into `mbmi`
              av2_refine_mv_for_warp_extend(
                  cm, xd, &ms_params, neighbor_is_above, bsize,
                  &neighbor_params, cpi->sf.mv_sf.warp_search_method,
                  cpi->sf.mv_sf.warp_search_iters);

              // If we changed the MV, update costs
              if (mv0.as_int != mbmi->mv[0].as_int) {
                // Keep the refined MV and WM parameters.
                tmp_rate_mv = av2_mv_bit_cost(
                    &mbmi->mv[0].as_mv, &ref_mv.as_mv, mbmi->pb_mv_precision,
                    &x->mv_costs, MV_COST_WEIGHT,
                    ms_params.mv_cost_params.is_adaptive_mvd);
                tmp_rate2 = rate2_nocoeff - rate_mv0 + tmp_rate_mv;
              } else {
                // Restore the old MV and WM parameters.
                mbmi->mv[0] = mv0;
                mbmi->wm_params[0] = wm_params0;
              }

              assign_warpmv(cm, xd->submi, bsize, &mbmi->wm_params[0], mi_row,
                            mi_col, 0);

              // Build the warped predictor
              av2_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize,
                                            0, av2_num_planes(cm) - 1);
            }

            // If we are searching newmv and the mv is the same as refmv, skip
            // the current mode
            if (!av2_check_newmv_joint_nonzero(cm, x)) continue;

            // Update rd_stats for the current motion mode
            txfm_info->skip_txfm = 0;
            rd_stats->dist = 0;
            rd_stats->sse = 0;
            rd_stats->skip_txfm = 1;
            rd_stats->rate = tmp_rate2;
            const ModeCosts *mode_costs = &x->mode_costs;
            if (!is_warp_mode(mbmi->motion_mode))
              rd_stats->rate += switchable_rate;

            if (cm->features.enable_bawp &&
                av2_allow_bawp(cm, mbmi, mi_row, mi_col)) {
              rd_stats->rate +=
                  mode_costs->bawp_flg_cost[0][mbmi->bawp_flag[0] > 0];
              const int ctx_index =
                  (mbmi->mode == NEARMV)
                      ? 0
                      : ((mbmi->mode == NEWMV && mbmi->use_amvd) ? 1 : 2);
              if (mbmi->bawp_flag[0] > 0 && av2_allow_explicit_bawp(mbmi))
                rd_stats->rate +=
                    mode_costs
                        ->explicit_bawp_cost[ctx_index][mbmi->bawp_flag[0] > 1];
              if (mbmi->bawp_flag[0] > 1)
                rd_stats->rate +=
                    mode_costs
                        ->explicit_bawp_scale_cost[mbmi->bawp_flag[0] - 2];
            }
            if (!cm->seq_params.monochrome && xd->is_chroma_ref &&
                mbmi->bawp_flag[0]) {
              rd_stats->rate +=
                  mode_costs->bawp_flg_cost[1][mbmi->bawp_flag[1] == 1];
            }

            MOTION_MODE motion_mode = mbmi->motion_mode;
            bool continue_motion_mode_signaling =
                (mbmi->mode != WARPMV && mbmi->mode != WARP_NEWMV);

            if (continue_motion_mode_signaling &&
                allowed_motion_modes & (1 << INTERINTRA)) {
              rd_stats->rate +=
                  mode_costs->interintra_cost[size_group_lookup[bsize]]
                                             [motion_mode == INTERINTRA];
              if (motion_mode == INTERINTRA) {
                // Note(rachelbarker): Costs for other interintra-related
                // signaling are already accounted for by
                // `av2_handle_inter_intra_mode`
                continue_motion_mode_signaling = false;
              }
            }

            if (continue_motion_mode_signaling &&
                allowed_motion_modes & (1 << WARP_CAUSAL)) {
              const int ctx = av2_get_warp_causal_ctx(xd);
              rd_stats->rate +=
                  mode_costs->warp_causal_cost[ctx][motion_mode == WARP_CAUSAL];
            }

            if (is_warp_newmv_allowed(cm, xd, mbmi, bsize) &&
                mbmi->mode == WARP_NEWMV) {
              continue_motion_mode_signaling =
                  (allowed_motion_modes & (1 << WARP_CAUSAL)) ||
                  (allowed_motion_modes & (1 << WARP_DELTA));

              if (continue_motion_mode_signaling &&
                  (allowed_motion_modes & (1 << WARP_EXTEND))) {
                const int ctx = av2_get_warp_extend_ctx(xd);
                rd_stats->rate +=
                    mode_costs
                        ->warp_extend_cost[ctx][motion_mode == WARP_EXTEND];
                if (motion_mode == WARP_EXTEND) {
                  continue_motion_mode_signaling = false;
                }
              }

              if (continue_motion_mode_signaling &&
                  (allowed_motion_modes & (1 << WARP_DELTA)) &&
                  (allowed_motion_modes & (1 << WARP_CAUSAL))) {
                const int ctx = av2_get_warp_causal_ctx(xd);
                rd_stats->rate +=
                    mode_costs
                        ->warp_causal_cost[ctx][motion_mode == WARP_CAUSAL];
              }
            }

            if (mbmi->mode == WARPMV) {
              assert(motion_mode == WARP_DELTA);
              if (allow_warpmv_with_mvd_coding(cm, mbmi)) {
                rd_stats->rate +=
                    mode_costs
                        ->warpmv_with_mvd_flag_cost[mbmi->warpmv_with_mvd_flag];
              }
            }

            if (motion_mode == WARP_DELTA) {
              rd_stats->rate += get_warp_ref_idx_cost(mbmi, x);

              if (allow_warp_parameter_signaling(cm, mbmi)) {
                rd_stats->rate +=
                    av2_cost_warp_delta(cm, xd, mbmi, mbmi_ext, mode_costs);
              }

              // The following line is commented out to remove a spurious
              // static analysis warning. Uncomment when adding a new motion
              // mode continue_motion_mode_signaling = false;
            }

            if (allow_warp_inter_intra(mbmi)) {
              rd_stats->rate +=
                  mode_costs->warp_interintra_cost[size_group_lookup[bsize]]
                                                  [mbmi->warp_inter_intra];
            }

            if (!do_tx_search) {
              // Avoid doing a transform search here to speed up the overall
              // mode search. It will be done later in the mode search if the
              // current motion mode seems promising.
              int64_t curr_sse = -1;
              int64_t sse_y = -1;
              int est_residue_cost = 0;
              int64_t est_dist = 0;
              int64_t est_rd = 0;
              if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1) {
                curr_sse = get_sse(cpi, x, &sse_y);
                const int has_est_rd = get_est_rate_dist(
                    tile_data, bsize, curr_sse, &est_residue_cost, &est_dist);
                (void)has_est_rd;
                assert(has_est_rd);
              } else if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 2) {
                model_rd_sb_fn[MODELRD_TYPE_MOTION_MODE_RD](
                    cpi, bsize, x, xd, 0, num_planes - 1, &est_residue_cost,
                    &est_dist, NULL, &curr_sse, NULL, NULL, NULL);
                sse_y =
                    x->pred_sse[COMPACT_INDEX0_NRS(xd->mi[0]->ref_frame[0])];
              }
              est_rd = RDCOST(x->rdmult, rd_stats->rate + est_residue_cost,
                              est_dist);
              if (est_rd * 0.80 > *best_est_rd) {
                mbmi->ref_frame[1] = ref_frame_1;
                continue;
              }
              const int mode_rate = rd_stats->rate;
              rd_stats->rate += est_residue_cost;
              rd_stats->dist = est_dist;
              rd_stats->rdcost = est_rd;
              if (rd_stats->rdcost < *best_est_rd) {
                *best_est_rd = rd_stats->rdcost;
                assert(sse_y >= 0);
                ref_skip_rd[1] =
                    cpi->sf.inter_sf.txfm_rd_gate_level
                        ? RDCOST(x->rdmult, mode_rate, (sse_y << 4))
                        : INT64_MAX;
              }
              if (cm->current_frame.reference_mode == SINGLE_REFERENCE) {
                if (!is_comp_pred) {
                  assert(curr_sse >= 0);
                  inter_modes_info_push(inter_modes_info, mode_rate, curr_sse,
                                        rd_stats->rdcost, mbmi);
                }
              } else {
                assert(curr_sse >= 0);
                inter_modes_info_push(inter_modes_info, mode_rate, curr_sse,
                                      rd_stats->rdcost, mbmi);
              }
              mbmi->skip_txfm[xd->tree_type == CHROMA_PART] = 0;
            } else {
              // Perform full transform search
              int64_t skip_rd = INT64_MAX;
              int64_t skip_rdy = INT64_MAX;
              if (cpi->sf.inter_sf.txfm_rd_gate_level) {
                // Check if the mode is good enough based on skip RD
                int64_t sse_y = INT64_MAX;
                int64_t curr_sse = get_sse(cpi, x, &sse_y);
                skip_rd = RDCOST(x->rdmult, rd_stats->rate, curr_sse);
                skip_rdy = RDCOST(x->rdmult, rd_stats->rate, (sse_y << 4));
                int eval_txfm =
                    check_txfm_eval(x, bsize, ref_skip_rd[0], skip_rd,
                                    cpi->sf.inter_sf.txfm_rd_gate_level, 0);
                if (!eval_txfm) continue;
              }

              if (enable_tx_prune) {
                int est_residue_cost = 0;
                int64_t est_dist = 0;
                int64_t curr_sse = -1;
                model_rd_sb_fn[MODELRD_TYPE_MOTION_MODE_RD](
                    cpi, bsize, x, xd, 0, num_planes - 1, &est_residue_cost,
                    &est_dist, NULL, &curr_sse, NULL, NULL, NULL);
                int64_t est_rd = RDCOST(
                    x->rdmult, rd_stats->rate + est_residue_cost, est_dist);
                if (prune_motion_mode(est_rd, top_motion_mode_model_rd))
                  continue;
              }

              // Do transform search
              if (!av2_txfm_search(cpi, x, bsize, rd_stats, rd_stats_y,
                                   rd_stats_uv, rd_stats->rate,
                                   enable_tx_prune ? 0 : 1, ref_best_rd)) {
                if (rd_stats_y->rate == INT_MAX && mode_index == 0) {
                  return INT64_MAX;
                }
                continue;
              }
              const int64_t curr_rd =
                  RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist);
              if (curr_rd < ref_best_rd) {
                ref_best_rd = curr_rd;
                ref_skip_rd[0] = skip_rd;
                ref_skip_rd[1] = skip_rdy;
              }
              if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1) {
                const int skip_ctx = av2_get_skip_txfm_context(xd);
                inter_mode_data_push(
                    tile_data, mbmi->sb_type[PLANE_TYPE_Y], rd_stats->sse,
                    rd_stats->dist,
                    rd_stats_y->rate + rd_stats_uv->rate +
                        mode_costs->skip_txfm_cost
                            [skip_ctx]
                            [mbmi->skip_txfm[xd->tree_type == CHROMA_PART]]);
              }
            }

            if (this_mode == GLOBALMV || this_mode == GLOBAL_GLOBALMV) {
              if (is_nontrans_global_motion(xd, xd->mi[0])) {
                mbmi->interp_fltr = av2_unswitchable_filter(interp_filter);
              }
            }

            const int64_t tmp_rd =
                RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist);

            if (num_rd_check == 0) {
              args->simple_rd[this_mode][get_ref_mv_idx(mbmi, 0)]
                             [COMPACT_INDEX0_NRS(mbmi->ref_frame[0])] = tmp_rd;
            }

            if (num_rd_check == 0 || tmp_rd < best_rd) {
              // Update best_rd data if this is the best motion mode so far
              best_mbmi = *mbmi;
              if (is_warp_mode(mbmi->motion_mode)) {
                store_submi(xd, cm, best_submi, bsize);
              }
              best_rd = tmp_rd;
              best_rd_stats = *rd_stats;
              best_rd_stats_y = *rd_stats_y;
              best_rate_mv = tmp_rate_mv;
              if (num_planes > 1) best_rd_stats_uv = *rd_stats_uv;
              for (int i = 0; i < num_planes; ++i) {
                const int num_blk_plane =
                    (xd->plane[i].height * xd->plane[i].width) >>
                    (2 * MI_SIZE_LOG2);
                memcpy(best_blk_skip[i], txfm_info->blk_skip[i],
                       sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
              }
              av2_copy_array(best_tx_type_map, xd->tx_type_map,
                             xd->height * xd->width);
              av2_copy_array(best_cctx_type_map, xd->cctx_type_map,
                             (xd->plane[1].height * xd->plane[1].width) >>
                                 (2 * MI_SIZE_LOG2));
              best_xskip_txfm = mbmi->skip_txfm[xd->tree_type == CHROMA_PART];
            }
            num_rd_check++;
          }
        }
      }
    }
  }
  // Update RD and mbmi stats for selected motion mode
  mbmi->ref_frame[1] = ref_frame_1;
  *rate_mv = best_rate_mv;
  if (best_rd == INT64_MAX || !av2_check_newmv_joint_nonzero(cm, x)) {
    av2_invalid_rd_stats(rd_stats);
    restore_dst_buf(xd, *orig_dst, num_planes);
    return INT64_MAX;
  }
  *mbmi = best_mbmi;
  if (is_warp_mode(mbmi->motion_mode)) update_submi(xd, cm, best_submi, bsize);
  *rd_stats = best_rd_stats;
  *rd_stats_y = best_rd_stats_y;
  if (num_planes > 1) *rd_stats_uv = best_rd_stats_uv;
  for (int i = 0; i < num_planes; ++i) {
    const int num_blk_plane =
        (xd->plane[i].height * xd->plane[i].width) >> (2 * MI_SIZE_LOG2);
    memcpy(txfm_info->blk_skip[i], best_blk_skip[i],
           sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
  }
  av2_copy_array(xd->tx_type_map, best_tx_type_map, xd->height * xd->width);
  av2_copy_array(
      xd->cctx_type_map, best_cctx_type_map,
      (xd->plane[1].height * xd->plane[1].width) >> (2 * MI_SIZE_LOG2));
  txfm_info->skip_txfm = best_xskip_txfm;

  restore_dst_buf(xd, *orig_dst, num_planes);
  return 0;
}

// Check NEARMV and GLOBALMV ref mvs for duplicate and skip the relevant mode
static INLINE int check_repeat_ref_mv(const MB_MODE_INFO_EXT *mbmi_ext,
                                      int ref_idx,
                                      const MV_REFERENCE_FRAME *ref_frame,
                                      PREDICTION_MODE this_mode,
                                      PREDICTION_MODE single_mode) {
  const int8_t ref_frame_type = has_second_drl_by_mode(this_mode, ref_frame)
                                    ? ref_frame[ref_idx]
                                    : av2_ref_frame_type(ref_frame);
  if (is_tip_ref_frame(ref_frame_type)) return 0;
  const int ref_mv_count = mbmi_ext->ref_mv_count[ref_frame_type];
  assert(single_mode != NEWMV && single_mode != WARP_NEWMV);
  // when ref_mv_count = 0 or 1, NEARMV is same as GLOBALMV
  if (single_mode == NEARMV && ref_mv_count < 2) {
    return 1;
  }
  if (single_mode != GLOBALMV) {
    return 0;
  }
  // when ref_mv_count == 0, GLOBALMV is same as NEARMV
  if (ref_mv_count == 0) {
    return 1;
  } else if (ref_mv_count == 1) {
    // when ref_mv_count == 1, NEARMV is same as GLOBALMV
    return 0;
  }

  int stack_size = AVMMIN(USABLE_REF_MV_STACK_SIZE, ref_mv_count);
  // Check GLOBALMV is matching with any mv in ref_mv_stack
  for (int ref_mv_idx = 0; ref_mv_idx < stack_size; ref_mv_idx++) {
    int_mv this_mv;

    if (ref_idx == 0 || has_second_drl_by_mode(this_mode, ref_frame))
      this_mv = mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_idx].this_mv;
    else
      this_mv = mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_idx].comp_mv;

    if (this_mv.as_int == mbmi_ext->global_mvs[ref_frame[ref_idx]].as_int)
      return 1;
  }
  return 0;
}

static INLINE int get_this_mv(int_mv *this_mv, PREDICTION_MODE this_mode,
                              int ref_idx, int ref_mv_idx,
                              int skip_repeated_ref_mv,
                              const MV_REFERENCE_FRAME *ref_frame,
                              const MB_MODE_INFO_EXT *mbmi_ext) {
  const PREDICTION_MODE single_mode = get_single_mode(this_mode, ref_idx);
  assert(is_inter_singleref_mode(single_mode));
  if (single_mode == NEWMV || single_mode == WARP_NEWMV) {
    this_mv->as_int = INVALID_MV;
  } else if (single_mode == GLOBALMV) {
    if (skip_repeated_ref_mv &&
        check_repeat_ref_mv(mbmi_ext, ref_idx, ref_frame, this_mode,
                            single_mode))
      return 0;
    *this_mv = mbmi_ext->global_mvs[ref_frame[ref_idx]];
  }
  // For WARPMV mode we will extract the MV in motion_mode_rd
  // Here we just return zero MVs.
  else if (single_mode == WARPMV) {
    this_mv->as_int = 0;
  } else {
    assert(single_mode == NEARMV);
    const int ref_mv_offset = ref_mv_idx;
    const int8_t ref_frame_type = has_second_drl_by_mode(this_mode, ref_frame)
                                      ? ref_frame[ref_idx]
                                      : av2_ref_frame_type(ref_frame);
    if (ref_frame_type > NONE_FRAME &&
        ref_mv_offset < mbmi_ext->ref_mv_count[ref_frame_type]) {
      assert(ref_mv_offset >= 0);
      if (ref_idx == 0) {
        *this_mv =
            mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_offset].this_mv;
      } else {
        *this_mv =
            has_second_drl_by_mode(this_mode, ref_frame)
                ? mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_offset].this_mv
                : mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_offset].comp_mv;
      }
    } else {
      if (skip_repeated_ref_mv &&
          check_repeat_ref_mv(mbmi_ext, ref_idx, ref_frame, this_mode,
                              single_mode))
        return 0;

      if (is_tip_ref_frame(ref_frame_type)) {
        this_mv->as_int = 0;
      } else {
        *this_mv = mbmi_ext->global_mvs[ref_frame[ref_idx]];
      }
    }
  }
  return 1;
}

// This function update the non-new mv for the current prediction mode
static INLINE int build_cur_mv(int_mv *cur_mv, PREDICTION_MODE this_mode,
                               const AV2_COMMON *cm, const MACROBLOCK *x,
                               int skip_repeated_ref_mv) {
  const MACROBLOCKD *xd = &x->e_mbd;
  const MB_MODE_INFO *mbmi = xd->mi[0];
  const int is_comp_pred = has_second_ref(mbmi);

  if (mbmi->skip_mode) {
    int ret = 1;
    assert(get_ref_mv_idx(mbmi, 0) < xd->skip_mvp_candidate_list.ref_mv_count);
    assert(get_ref_mv_idx(mbmi, 1) == get_ref_mv_idx(mbmi, 0));
    int_mv this_mv;
    this_mv.as_int = INVALID_MV;
    this_mv = xd->skip_mvp_candidate_list.ref_mv_stack[get_ref_mv_idx(mbmi, 0)]
                  .this_mv;

    cur_mv[0] = this_mv;
    ret &= clamp_and_check_mv(cur_mv, this_mv, cm, x);

    this_mv = xd->skip_mvp_candidate_list.ref_mv_stack[get_ref_mv_idx(mbmi, 1)]
                  .comp_mv;
    cur_mv[1] = this_mv;
    ret &= clamp_and_check_mv(cur_mv + 1, this_mv, cm, x);
    return ret;
  }

  int ret = 1;
  for (int i = 0; i < is_comp_pred + 1; ++i) {
    int_mv this_mv;
    this_mv.as_int = INVALID_MV;
    int ref_mv_idx = get_ref_mv_idx(mbmi, i);
    ret = get_this_mv(&this_mv, this_mode, i, ref_mv_idx, skip_repeated_ref_mv,
                      mbmi->ref_frame, x->mbmi_ext);
    if (!ret) return 0;
    const PREDICTION_MODE single_mode = get_single_mode(this_mode, i);
    if (single_mode == NEWMV || single_mode == WARP_NEWMV) {
      const uint8_t ref_frame_type = av2_ref_frame_type(mbmi->ref_frame);
      if (has_second_drl(mbmi))
        cur_mv[i] =
            x->mbmi_ext->ref_mv_stack[mbmi->ref_frame[i]][ref_mv_idx].this_mv;
      else
        cur_mv[i] =
            (i == 0)
                ? x->mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_idx].this_mv
                : x->mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_idx].comp_mv;
    } else {
      ret &= clamp_and_check_mv(cur_mv + i, this_mv, cm, x);
    }
  }
  return ret;
}

static INLINE int get_skip_drl_cost(int max_drl_bits, const MB_MODE_INFO *mbmi,
                                    const MACROBLOCK *x) {
  assert(get_ref_mv_idx(mbmi, 0) < max_drl_bits + 1);
  assert(mbmi->skip_mode || is_tip_ref_frame(mbmi->ref_frame[0]));
  if (!have_drl_index(mbmi->mode)) {
    return 0;
  }
  int cost = 0;
  const int ref_mv_idx = get_ref_mv_idx(mbmi, 0);
  for (int idx = 0; idx < max_drl_bits; ++idx) {
    if (!is_tip_ref_frame(mbmi->ref_frame[0])) {
      cost +=
          x->mode_costs.skip_drl_mode_cost[AVMMIN(idx, 2)][ref_mv_idx != idx];
    } else {
      cost +=
          x->mode_costs.tip_drl_mode_cost[AVMMIN(idx, 2)][ref_mv_idx != idx];
    }
    if (ref_mv_idx == idx) return cost;
  }

  return cost;
}

// Computes the bit cost of writing the DRL index with max_drl_bits possible
// values. It will also guarantee a DRL cost of zero if the mode does not need
// a DRL index.
// Also see related function write_drl_idx() for more info.
int get_drl_cost(int max_drl_bits, const MB_MODE_INFO *mbmi,
                 const MB_MODE_INFO_EXT *mbmi_ext, const MACROBLOCK *x) {
  if (is_tip_ref_frame(mbmi->ref_frame[0])) {
    return get_skip_drl_cost(max_drl_bits, mbmi, x);
  }

  assert(get_ref_mv_idx(mbmi, 0) < max_drl_bits + 1);
  assert(get_ref_mv_idx(mbmi, 1) < max_drl_bits + 1);
  if (!have_drl_index(mbmi->mode)) {
    return 0;
  }
  int16_t mode_ctx_pristine =
      av2_mode_context_pristine(mbmi_ext->mode_context, mbmi->ref_frame);
  int cost = 0;
  for (int ref_idx = 0; ref_idx < 1 + has_second_drl(mbmi); ref_idx++) {
    for (int idx = 0; idx < max_drl_bits; ++idx) {
      int drl_ctx = av2_drl_ctx(mode_ctx_pristine);
      int ref_mv_idx = get_ref_mv_idx(mbmi, ref_idx);
      if (ref_idx && mbmi->ref_frame[0] == mbmi->ref_frame[1] &&
          mbmi->mode == NEAR_NEARMV && idx <= mbmi->ref_mv_idx[0])
        continue;
      switch (idx) {
        case 0:
          cost += x->mode_costs.drl_mode_cost[0][drl_ctx][ref_mv_idx != idx];
          break;
        case 1:
          cost += x->mode_costs.drl_mode_cost[1][drl_ctx][ref_mv_idx != idx];
          break;
        default:
          cost += x->mode_costs.drl_mode_cost[2][drl_ctx][ref_mv_idx != idx];
          break;
      }
      if (ref_mv_idx == idx) break;
    }
  }
  return cost;
}

static INLINE int is_single_newmv_valid(const HandleInterModeArgs *const args,
                                        const MB_MODE_INFO *const mbmi,
                                        PREDICTION_MODE this_mode) {
  for (int ref_idx = 0; ref_idx < 2; ++ref_idx) {
    const PREDICTION_MODE single_mode = get_single_mode(this_mode, ref_idx);
    const MV_REFERENCE_FRAME ref =
        ref_idx == 0 ? COMPACT_INDEX0_NRS(mbmi->ref_frame[ref_idx])
                     : COMPACT_INDEX1_NRS(mbmi->ref_frame[ref_idx]);
    if ((single_mode == NEWMV || single_mode == WARP_NEWMV) &&
        args->single_newmv_valid[mbmi->pb_mv_precision]
                                [get_ref_mv_idx(mbmi, ref_idx)][ref] == 0) {
      return 0;
    }
  }
  return 1;
}

static int get_drl_refmv_count(int max_drl_bits, const MACROBLOCK *const x,
                               const MV_REFERENCE_FRAME *ref_frame,
                               PREDICTION_MODE mode, int ref_idx) {
  MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
  int has_drl = have_drl_index(mode);
  if (!has_drl) {
    assert(mode == GLOBALMV || mode == GLOBAL_GLOBALMV || mode == WARPMV);
    return 1;
  }

  MB_MODE_INFO *mbmi = x->e_mbd.mi[0];
  if (has_second_drl(mbmi)) {
    return AVMMIN(max_drl_bits + 1, mbmi_ext->ref_mv_count[ref_frame[ref_idx]]);
  }

  const int8_t ref_frame_type = av2_ref_frame_type(ref_frame);

  int ref_mv_count =
      ref_frame_type > NONE_FRAME ? mbmi_ext->ref_mv_count[ref_frame_type] : 0;

  if (mode == NEWMV && mbmi->use_amvd) ref_mv_count = AVMMIN(ref_mv_count, 4);

  if (x->e_mbd.mi[0]->skip_mode) {
    ref_mv_count = mbmi_ext->skip_mvp_candidate_list.ref_mv_count;
  }

  return AVMMIN(max_drl_bits + 1, ref_mv_count);
}

// Whether this reference motion vector can be skipped, based on initial
// heuristics.
static bool ref_mv_idx_early_breakout(
    const AV2_COMP *const cpi,
    const RefFrameDistanceInfo *const ref_frame_dist_info, MACROBLOCK *x,
    const HandleInterModeArgs *const args, int64_t ref_best_rd,
    int *ref_mv_idx) {
  (void)ref_frame_dist_info;
  MACROBLOCKD *xd = &x->e_mbd;
  MB_MODE_INFO *mbmi = xd->mi[0];
  const MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
  const int is_comp_pred = has_second_ref(mbmi);
  if (is_comp_pred && mbmi->ref_frame[0] == mbmi->ref_frame[1] &&
      mbmi->mode == NEAR_NEARMV && ref_mv_idx[0] >= ref_mv_idx[1])
    return true;

  mbmi->ref_mv_idx[0] = ref_mv_idx[0];
  mbmi->ref_mv_idx[1] = ref_mv_idx[1];

  if (is_comp_pred && (!is_single_newmv_valid(args, mbmi, mbmi->mode))) {
    return true;
  }
  size_t est_rd_rate = args->ref_frame_cost + args->single_comp_cost;
  const int drl_cost =
      get_drl_cost(cpi->common.features.max_drl_bits, mbmi, mbmi_ext, x);
  est_rd_rate += drl_cost;
  if (RDCOST(x->rdmult, est_rd_rate, 0) > ref_best_rd) {
    return true;
  }
  return false;
}

// Returns MVD scaling cost for joint MVD coding mode.
static INLINE int get_jmvd_scale_mode_cost(const MB_MODE_INFO *mbmi,
                                           const ModeCosts *mode_costs) {
  if (!is_joint_mvd_coding_mode(mbmi->mode)) return 0;

  int jmvd_scale_mode_cost =
      is_joint_amvd_coding_mode(mbmi->mode, mbmi->use_amvd)
          ? mode_costs->jmvd_amvd_scale_mode_cost[mbmi->jmvd_scale_mode]
          : mode_costs->jmvd_scale_mode_cost[mbmi->jmvd_scale_mode];

  return jmvd_scale_mode_cost;
}

// Compute the estimated RD cost for the motion vector with simple translation.
static int64_t simple_translation_pred_rd(AV2_COMP *const cpi, MACROBLOCK *x,
                                          RD_STATS *rd_stats,
                                          HandleInterModeArgs *args,
                                          int *ref_mv_idx,
                                          inter_mode_info *mode_info,
                                          int64_t ref_best_rd, BLOCK_SIZE bsize

                                          ,
                                          const int flex_mv_cost

) {
  MACROBLOCKD *xd = &x->e_mbd;
  MB_MODE_INFO *mbmi = xd->mi[0];
  MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
  const AV2_COMMON *cm = &cpi->common;
  const int is_comp_pred = has_second_ref(mbmi);
  const ModeCosts *mode_costs = &x->mode_costs;

  struct macroblockd_plane *p = xd->plane;
  const BUFFER_SET orig_dst = {
    { p[0].dst.buf, p[1].dst.buf, p[2].dst.buf },
    { p[0].dst.stride, p[1].dst.stride, p[2].dst.stride },
  };
  av2_init_rd_stats(rd_stats);

  mbmi->interinter_comp.type = COMPOUND_AVERAGE;
  mbmi->comp_group_idx = 0;
  if (mbmi->ref_frame[1] == INTRA_FRAME) {
    mbmi->ref_frame[1] = NONE_FRAME;
  }
  int16_t mode_ctx =
      av2_mode_context_analyzer(mbmi_ext->mode_context, mbmi->ref_frame);

  mbmi->num_proj_ref[0] = mbmi->num_proj_ref[1] = 0;
  mbmi->motion_mode = SIMPLE_TRANSLATION;
  mbmi->ref_mv_idx[0] = ref_mv_idx[0];
  mbmi->ref_mv_idx[1] = ref_mv_idx[1];
  int ref_mv_idx_type = av2_ref_mv_idx_type(mbmi, ref_mv_idx);

  rd_stats->rate += args->ref_frame_cost + args->single_comp_cost;

  rd_stats->rate += flex_mv_cost;

  const int drl_cost =
      get_drl_cost(cpi->common.features.max_drl_bits, mbmi, mbmi_ext, x);

  rd_stats->rate += drl_cost;
  mode_info[ref_mv_idx_type].drl_cost = drl_cost;

  int_mv cur_mv[2];
  if (!build_cur_mv(cur_mv, mbmi->mode, cm, x, 0)) {
    return INT64_MAX;
  }
  assert(have_nearmv_in_inter_mode(mbmi->mode));
  for (int i = 0; i < is_comp_pred + 1; ++i) {
    lower_mv_precision(&cur_mv[i].as_mv, mbmi->pb_mv_precision);

    mbmi->mv[i].as_int = cur_mv[i].as_int;
  }
  const int prediction_mode_cost =
      cost_prediction_mode(mode_costs, mbmi->mode, cm, mbmi, xd, mode_ctx);
  rd_stats->rate += prediction_mode_cost;

  rd_stats->rate += get_jmvd_scale_mode_cost(mbmi, mode_costs);

  if (RDCOST(x->rdmult, rd_stats->rate, 0) > ref_best_rd) {
    return INT64_MAX;
  }

  mbmi->motion_mode = SIMPLE_TRANSLATION;
  mbmi->cwp_idx = CWP_EQUAL;
  mbmi->num_proj_ref[0] = mbmi->num_proj_ref[1] = 0;
  if (is_comp_pred) {
    // Only compound_average
    mbmi->interinter_comp.type = COMPOUND_AVERAGE;
    mbmi->comp_group_idx = 0;
  }
  set_default_interp_filters(mbmi, cm, xd, cm->features.interp_filter);

  const int mi_row = xd->mi_row;
  const int mi_col = xd->mi_col;

  av2_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst, bsize,
                                AVM_PLANE_Y, AVM_PLANE_Y);
  int est_rate;
  int64_t est_dist;
  model_rd_sb_fn[MODELRD_CURVFIT](cpi, bsize, x, xd, 0, 0, &est_rate, &est_dist,
                                  NULL, NULL, NULL, NULL, NULL);
  return RDCOST(x->rdmult, rd_stats->rate + est_rate, est_dist);
}

// Represents a set of integers, from 0 to sizeof(int) * 8, as bits in
// an integer. 0 for the i-th bit means that integer is excluded, 1 means
// it is included.
static INLINE void mask_set_bit(int *mask, int index) { *mask |= (1 << index); }

static INLINE bool mask_check_bit(int mask, int index) {
  return (mask >> index) & 0x1;
}

static int skip_similar_ref_mv(AV2_COMP *const cpi, MACROBLOCK *x,
                               BLOCK_SIZE bsize) {
  AV2_COMMON *const cm = &cpi->common;
  const MACROBLOCKD *const xd = &x->e_mbd;
  const MB_MODE_INFO *const mbmi = xd->mi[0];
  const MB_MODE_INFO_EXT *mbmi_ext = x->mbmi_ext;

  if (is_pb_mv_precision_active(cm, mbmi, bsize) &&
      (mbmi->pb_mv_precision < mbmi->max_mv_precision) &&
      (mbmi->ref_mv_idx[0] > 0 || mbmi->ref_mv_idx[1] > 0)) {
    const int is_comp_pred = has_second_ref(mbmi);
    const uint8_t ref_frame_type = av2_ref_frame_type(mbmi->ref_frame);
    int_mv this_refmv[2];
    this_refmv[0].as_int = 0;
    this_refmv[1].as_int = 0;
    for (int i = 0; i < is_comp_pred + 1; ++i) {
      if (has_second_drl(mbmi))
        this_refmv[i] =
            mbmi_ext->ref_mv_stack[mbmi->ref_frame[i]][mbmi->ref_mv_idx[i]]
                .this_mv;
      else
        this_refmv[i] =
            (i == 0)
                ? mbmi_ext->ref_mv_stack[ref_frame_type][mbmi->ref_mv_idx[0]]
                      .this_mv
                : mbmi_ext->ref_mv_stack[ref_frame_type][mbmi->ref_mv_idx[0]]
                      .comp_mv;

      if (mbmi->pb_mv_precision < MV_PRECISION_HALF_PEL)
        lower_mv_precision(&this_refmv[i].as_mv, mbmi->pb_mv_precision);
    }

    const uint8_t ref_mv_idx_type = av2_ref_mv_idx_type(mbmi, mbmi->ref_mv_idx);
    for (int prev_ref_mv_idx = 0; prev_ref_mv_idx < ref_mv_idx_type;
         prev_ref_mv_idx++) {
      int_mv prev_refmv[2];
      prev_refmv[0].as_int = INVALID_MV;
      prev_refmv[1].as_int = INVALID_MV;

      for (int i = 0; i < is_comp_pred + 1; ++i) {
        if (has_second_drl(mbmi)) {
          int temp_idx[2];
          av2_set_ref_mv_idx(temp_idx, prev_ref_mv_idx);
          prev_refmv[i] =
              mbmi_ext->ref_mv_stack[mbmi->ref_frame[i]][temp_idx[i]].this_mv;
        } else
          prev_refmv[i] =
              (i == 0) ? mbmi_ext->ref_mv_stack[ref_frame_type][prev_ref_mv_idx]
                             .this_mv
                       : mbmi_ext->ref_mv_stack[ref_frame_type][prev_ref_mv_idx]
                             .comp_mv;

        if (mbmi->pb_mv_precision < MV_PRECISION_HALF_PEL)
          lower_mv_precision(&prev_refmv[i].as_mv, mbmi->pb_mv_precision);
      }
      int prev_refmv_same_as_curr_ref_mv =
          (this_refmv[0].as_int == prev_refmv[0].as_int);
      if (is_comp_pred)
        prev_refmv_same_as_curr_ref_mv &=
            (this_refmv[1].as_int == prev_refmv[1].as_int);
      if (prev_refmv_same_as_curr_ref_mv) return 1;
    }
  }
  return 0;
}

// Before performing the full MV search in handle_inter_mode, do a simple
// translation search and see if we can eliminate any motion vectors.
// Returns an integer where, if the i-th bit is set, it means that the i-th
// motion vector should be searched. This is only set for NEAR_MV.
static int ref_mv_idx_to_search(AV2_COMP *const cpi, MACROBLOCK *x,
                                RD_STATS *rd_stats,
                                HandleInterModeArgs *const args,
                                int64_t ref_best_rd, inter_mode_info *mode_info,
                                BLOCK_SIZE bsize, const int *ref_set,
                                const int flex_mv_cost

) {
  AV2_COMMON *const cm = &cpi->common;
  const MACROBLOCKD *const xd = &x->e_mbd;
  const MB_MODE_INFO *const mbmi = xd->mi[0];
  const PREDICTION_MODE this_mode = mbmi->mode;

  if (this_mode == WARPMV) return 1;  // Always search WARPMV mode

  // Only search indices if they have some chance of being good.
  int good_indices = 0;

  int ref_mv_idx[2];
  for (ref_mv_idx[1] = 0; ref_mv_idx[1] < ref_set[1]; ++ref_mv_idx[1]) {
    for (ref_mv_idx[0] = 0; ref_mv_idx[0] < ref_set[0]; ++ref_mv_idx[0]) {
      int i = av2_ref_mv_idx_type(mbmi, ref_mv_idx);
      if (ref_mv_idx_early_breakout(cpi, &cpi->ref_frame_dist_info, x, args,
                                    ref_best_rd, ref_mv_idx)) {
        continue;
      }
      mask_set_bit(&good_indices, i);
    }
  }

  // Always have at least one motion vector searched.
  if (!good_indices) {
    good_indices = 0x1;
    // If reference frames are the same, drl_idx0 < drl_idx1 is required,
    // so drl_idx0=0, drl_idx1=1 is searched instead
    if (has_second_ref(mbmi) && mbmi->ref_frame[0] == mbmi->ref_frame[1] &&
        mbmi->mode == NEAR_NEARMV)
      good_indices = MAX_REF_MV_STACK_SIZE;
  }

  // Only prune in NEARMV mode, if the speed feature is set, and the block
  // size is large enough. If these conditions are not met, return all good
  // indices found so far.
  if (!cpi->sf.inter_sf.prune_mode_search_simple_translation)
    return good_indices;
  if (!have_nearmv_in_inter_mode(this_mode)) return good_indices;
  if (num_pels_log2_lookup[bsize] <= 6) return good_indices;
  // Do not prune when there is internal resizing. TODO(elliottk) fix this
  // so b/2384 can be resolved.
  if (av2_is_scaled(get_ref_scale_factors(cm, mbmi->ref_frame[0])) ||
      (is_inter_ref_frame(mbmi->ref_frame[1]) &&
       av2_is_scaled(get_ref_scale_factors(cm, mbmi->ref_frame[1])))) {
    return good_indices;
  }

  // Calculate the RD cost for the motion vectors using simple translation.
  int64_t idx_rdcost[MAX_REF_MV_SEARCH * MAX_REF_MV_SEARCH];
  for (int i = 0; i < MAX_REF_MV_SEARCH * MAX_REF_MV_SEARCH; i++)
    idx_rdcost[i] = INT64_MAX;

  for (ref_mv_idx[1] = 0; ref_mv_idx[1] < ref_set[1]; ++ref_mv_idx[1]) {
    for (ref_mv_idx[0] = 0; ref_mv_idx[0] < ref_set[0]; ++ref_mv_idx[0]) {
      int i = av2_ref_mv_idx_type(mbmi, ref_mv_idx);

      // If this index is bad, ignore it.
      if (!mask_check_bit(good_indices, i)) {
        continue;
      }
      idx_rdcost[i] = simple_translation_pred_rd(
          cpi, x, rd_stats, args, ref_mv_idx, mode_info, ref_best_rd, bsize

          ,
          flex_mv_cost

      );
    }
  }

  // Find the index with the best RD cost.
  int best_idx = 0;
  // Find the 2nd best motion vector and search motion vectors within a
  // percentage of it.
  int best2_idx = 1;
  assert(MAX_REF_MV_SEARCH >= 2);
  if (idx_rdcost[0] > idx_rdcost[1]) {
    best_idx = 1;
    best2_idx = 0;
  }
  for (int i = 2; i < cm->features.max_drl_bits + 1; ++i) {
    if (idx_rdcost[i] < idx_rdcost[best_idx]) {
      best2_idx = best_idx;
      best_idx = i;
    } else if (idx_rdcost[i] < idx_rdcost[best2_idx]) {
      best2_idx = i;
    }
  }
  // The rest of the code uses best_idx as the reference.
  best_idx = best2_idx;
  // Only include indices that are good and within a % of the best.
  const double dth = has_second_ref(mbmi) ? 1.02 : 1.001;
  // If the simple translation cost is not within this multiple of the
  // best RD, skip it. Note that the cutoff is derived experimentally.
  const double ref_dth = 5;
  int result = 0;

  for (ref_mv_idx[1] = 0; ref_mv_idx[1] < ref_set[1]; ++ref_mv_idx[1]) {
    for (ref_mv_idx[0] = 0; ref_mv_idx[0] < ref_set[0]; ++ref_mv_idx[0]) {
      int i = av2_ref_mv_idx_type(mbmi, ref_mv_idx);
      if (mask_check_bit(good_indices, i) &&
          (1.0 * idx_rdcost[i]) < idx_rdcost[best_idx] * dth &&
          (1.0 * idx_rdcost[i]) < ref_best_rd * ref_dth) {
        mask_set_bit(&result, i);
      }
    }
  }

  return result;
}

/*!\brief Motion mode information for inter mode search speedup.
 *
 * Used in a speed feature to search motion modes other than
 * SIMPLE_TRANSLATION only on winning candidates.
 */
typedef struct motion_mode_candidate {
  /*!
   * Mode info for the motion mode candidate.
   */
  MB_MODE_INFO mbmi;
  /*!
   * Rate describing the cost of the motion vectors for this candidate.
   */
  int rate_mv;
  /*!
   * Rate before motion mode search and transform coding is applied.
   */
  int rate2_nocoeff;
  /*!
   * An integer value 0 or 1 which indicates whether or not to skip the motion
   * mode search and default to SIMPLE_TRANSLATION as a speed feature for this
   * candidate.
   */
  int skip_motion_mode;
  /*!
   * Total RD cost for this candidate.
   */
  int64_t rd_cost;
} motion_mode_candidate;

/*!\cond */
typedef struct motion_mode_best_st_candidate {
  motion_mode_candidate motion_mode_cand[MAX_WINNER_MOTION_MODES];
  int num_motion_mode_cand;
} motion_mode_best_st_candidate;

// Checks if the current reference frame matches with neighbouring block's
// (top/left) reference frames
static AVM_INLINE int ref_match_found_in_nb_blocks(MB_MODE_INFO *cur_mbmi,
                                                   MB_MODE_INFO *nb_mbmi) {
  MV_REFERENCE_FRAME nb_ref_frames[2] = { nb_mbmi->ref_frame[0],
                                          nb_mbmi->ref_frame[1] };
  MV_REFERENCE_FRAME cur_ref_frames[2] = { cur_mbmi->ref_frame[0],
                                           cur_mbmi->ref_frame[1] };
  const int is_cur_comp_pred = has_second_ref(cur_mbmi);
  int match_found = 0;

  if (cur_ref_frames[0] == nb_ref_frames[0] ||
      cur_ref_frames[0] == nb_ref_frames[1] ||
      (is_cur_comp_pred && (cur_ref_frames[1] == nb_ref_frames[0] ||
                            cur_ref_frames[1] == nb_ref_frames[1])))
    match_found = 1;
  return match_found;
}

static AVM_INLINE int find_ref_match_in_above_nbs(const int total_mi_cols,
                                                  MACROBLOCKD *xd) {
  if (!xd->up_available) return 0;
  const int mi_col = xd->mi_col;
  MB_MODE_INFO **cur_mbmi = xd->mi;
  // prev_row_mi points into the mi array, starting at the beginning of the
  // previous row.
  MB_MODE_INFO **prev_row_mi = xd->mi - mi_col - 1 * xd->mi_stride;
  const int end_col = AVMMIN(mi_col + xd->width, total_mi_cols);
  uint8_t mi_step;
  for (int above_mi_col = mi_col; above_mi_col < end_col;
       above_mi_col += mi_step) {
    MB_MODE_INFO **above_mi = prev_row_mi + above_mi_col;
    mi_step = mi_size_wide[above_mi[0]->sb_type[PLANE_TYPE_Y]];
    int match_found = 0;
    if (is_inter_block(*above_mi, xd->tree_type))
      match_found = ref_match_found_in_nb_blocks(*cur_mbmi, *above_mi);
    if (match_found) return 1;
  }
  return 0;
}

static AVM_INLINE int find_ref_match_in_left_nbs(const int total_mi_rows,
                                                 MACROBLOCKD *xd) {
  if (!xd->left_available) return 0;
  const int mi_row = xd->mi_row;
  MB_MODE_INFO **cur_mbmi = xd->mi;
  // prev_col_mi points into the mi array, starting at the top of the
  // previous column
  MB_MODE_INFO **prev_col_mi = xd->mi - 1 - mi_row * xd->mi_stride;
  const int end_row = AVMMIN(mi_row + xd->height, total_mi_rows);
  uint8_t mi_step;
  for (int left_mi_row = mi_row; left_mi_row < end_row;
       left_mi_row += mi_step) {
    MB_MODE_INFO **left_mi = prev_col_mi + left_mi_row * xd->mi_stride;
    mi_step = mi_size_high[left_mi[0]->sb_type[PLANE_TYPE_Y]];
    int match_found = 0;
    if (is_inter_block(*left_mi, xd->tree_type))
      match_found = ref_match_found_in_nb_blocks(*cur_mbmi, *left_mi);
    if (match_found) return 1;
  }
  return 0;
}
/*!\endcond */

/*! \brief Struct used to hold TPL data to
 * narrow down parts of the inter mode search.
 */
typedef struct {
  /*!
   * The best inter cost out of all of the reference frames.
   */
  int64_t best_inter_cost;
  /*!
   * The inter cost for each reference frame.
   */
  int64_t ref_inter_cost[INTER_REFS_PER_FRAME];
} PruneInfoFromTpl;

// TODO(Remya): Check if get_tpl_stats_b() can be reused
static AVM_INLINE void get_block_level_tpl_stats(
    AV2_COMP *cpi, BLOCK_SIZE bsize, int mi_row, int mi_col, int *valid_refs,
    PruneInfoFromTpl *inter_cost_info_from_tpl) {
  const GF_GROUP *const gf_group = &cpi->gf_group;

  assert(IMPLIES(gf_group->size > 0, gf_group->index < gf_group->size));
  const int tpl_idx = gf_group->index;
  TplParams *const tpl_data = &cpi->tpl_data;
  const TplDepFrame *tpl_frame = &tpl_data->tpl_frame[tpl_idx];
  if (tpl_idx >= MAX_TPL_FRAME_IDX || !tpl_frame->is_valid) {
    return;
  }

  AV2_COMMON *const cm = &cpi->common;
  const TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr;
  const int mi_wide = mi_size_wide[bsize];
  const int mi_high = mi_size_high[bsize];
  const int tpl_stride = tpl_frame->stride;
  const int step = 1 << tpl_data->tpl_stats_block_mis_log2;
  const int mi_col_sr = mi_col;
  const int mi_col_end_sr = mi_col + mi_wide;
  const int mi_cols_sr = av2_pixels_to_mi(cm->width);
  const int row_step = step;
  const int col_step_sr = step;
  for (int row = mi_row; row < AVMMIN(mi_row + mi_high, cm->mi_params.mi_rows);
       row += row_step) {
    for (int col = mi_col_sr; col < AVMMIN(mi_col_end_sr, mi_cols_sr);
         col += col_step_sr) {
      const TplDepStats *this_stats = &tpl_stats[av2_tpl_ptr_pos(
          row, col, tpl_stride, tpl_data->tpl_stats_block_mis_log2)];

      // Sums up the inter cost of corresponding ref frames
      for (int ref_idx = 0; ref_idx < INTER_REFS_PER_FRAME; ref_idx++) {
        inter_cost_info_from_tpl->ref_inter_cost[ref_idx] +=
            this_stats->pred_error[ref_idx];
      }
    }
  }

  // Computes the best inter cost (minimum inter_cost)
  int64_t best_inter_cost = INT64_MAX;
  for (int ref_idx = 0; ref_idx < INTER_REFS_PER_FRAME; ref_idx++) {
    const int64_t cur_inter_cost =
        inter_cost_info_from_tpl->ref_inter_cost[ref_idx];
    // For invalid ref frames, cur_inter_cost = 0 and has to be handled while
    // calculating the minimum inter_cost
    if (cur_inter_cost != 0 && (cur_inter_cost < best_inter_cost) &&
        valid_refs[ref_idx])
      best_inter_cost = cur_inter_cost;
  }
  inter_cost_info_from_tpl->best_inter_cost = best_inter_cost;
}

static AVM_INLINE int prune_modes_based_on_tpl_stats(
    const FeatureFlags *const features,
    PruneInfoFromTpl *inter_cost_info_from_tpl, const MV_REFERENCE_FRAME *refs,
    int ref_mv_idx, const PREDICTION_MODE this_mode, int prune_mode_level) {
  (void)features;
  const int have_newmv = have_newmv_in_inter_mode(this_mode);
  if ((prune_mode_level < 3) && have_newmv) return 0;

  if (refs[0] == TIP_FRAME_INDEX) return 0;

  static const int prune_level_idx[3] = { 0, 1, 1 };
  const int prune_level = prune_level_idx[prune_mode_level - 1];
  int64_t cur_inter_cost;

  const int is_globalmv =
      (this_mode == GLOBALMV) || (this_mode == GLOBAL_GLOBALMV);
  const int prune_index = is_globalmv ? features->max_drl_bits + 1 : ref_mv_idx;

  // Thresholds used for pruning:
  // Lower value indicates aggressive pruning and higher value indicates
  // conservative pruning which is set based on ref_mv_idx and speed feature.
  // 'prune_index' 0, 1, 2 corresponds to ref_mv indices 0, 1 and 2.
  // prune_index 3 corresponds to GLOBALMV/GLOBAL_GLOBALMV
  static const int tpl_inter_mode_prune_mul_factor[2][MAX_REF_MV_SEARCH + 1] = {
    { 3, 3, 3, 2, 2, 2 },
    { 3, 2, 2, 2, 2, 2 },
  };

  const int is_comp_pred = is_inter_ref_frame(refs[1]);
  if (!is_comp_pred) {
    cur_inter_cost = inter_cost_info_from_tpl->ref_inter_cost[refs[0]];
  } else {
    const int64_t inter_cost_ref0 =
        inter_cost_info_from_tpl->ref_inter_cost[refs[0]];
    const int64_t inter_cost_ref1 =
        inter_cost_info_from_tpl->ref_inter_cost[refs[1]];
    // Choose maximum inter_cost among inter_cost_ref0 and inter_cost_ref1 for
    // more aggressive pruning
    cur_inter_cost = AVMMAX(inter_cost_ref0, inter_cost_ref1);
  }

  // Prune the mode if cur_inter_cost is greater than threshold times
  // best_inter_cost
  const int64_t best_inter_cost = inter_cost_info_from_tpl->best_inter_cost;
  if (best_inter_cost == INT64_MAX) return 0;
  if (cur_inter_cost >
      ((tpl_inter_mode_prune_mul_factor[prune_level][prune_index] *
        best_inter_cost) >>
       1))
    return 1;
  return 0;
}

// If the current mode being searched is NEWMV, this function will look
// at previously searched MVs and check if they are the same
// as the current MV. If it finds that this MV is repeated, it compares
// the cost to the previous MV and skips the rest of the search if it is
// more expensive.
static int skip_repeated_newmv(
    AV2_COMP *const cpi, MACROBLOCK *x, BLOCK_SIZE bsize,
    const int do_tx_search, const PREDICTION_MODE this_mode,
    const MvSubpelPrecision pb_mv_precision, const int bawp_flag_y,
    const int bawp_flag_uv, MB_MODE_INFO *best_mbmi,
    motion_mode_candidate *motion_mode_cand, int64_t *ref_best_rd,
    RD_STATS *best_rd_stats, RD_STATS *best_rd_stats_y,
    RD_STATS *best_rd_stats_uv, inter_mode_info *mode_info,
    HandleInterModeArgs *args, int drl_cost, const MV_REFERENCE_FRAME *refs,
    int_mv *cur_mv, int64_t *best_rd, const BUFFER_SET orig_dst,
    int ref_mv_idx[2]) {
  // This feature only works for NEWMV when a previous mv has been searched
  if ((this_mode != NEWMV && this_mode != WARP_NEWMV) ||
      (ref_mv_idx[0] == 0 && ref_mv_idx[1] == 0))
    return 0;

  MACROBLOCKD *xd = &x->e_mbd;
  const AV2_COMMON *cm = &cpi->common;
  const int num_planes = av2_num_planes(cm);

  MB_MODE_INFO *mbmi = xd->mi[0];
  const int is_adaptive_mvd = enable_adaptive_mvd_resolution(cm, mbmi);

  // We can-not change the ref_mv_idx of best_mbmi becasue motion mode is tied
  // with ref_mv_idx
  if (is_warp_mode(best_mbmi->motion_mode)) return 0;
  if (mbmi->use_amvd) return 0;
  if (is_mvd_sign_derive_allowed(cm, xd, mbmi)) return 0;

  int skip = 0;
  int this_rate_mv = 0;
  int i = -1;

  int ref_mv_idx_type = av2_ref_mv_idx_type(mbmi, ref_mv_idx);
  int temp_mv_idx[2];
  for (temp_mv_idx[1] = 0; temp_mv_idx[1] <= ref_mv_idx[1]; ++temp_mv_idx[1]) {
    for (temp_mv_idx[0] = 0; temp_mv_idx[0] <= ref_mv_idx[0];
         ++temp_mv_idx[0]) {
      if (temp_mv_idx[0] == ref_mv_idx[0] && temp_mv_idx[1] == ref_mv_idx[1])
        continue;
      i = av2_ref_mv_idx_type(mbmi, temp_mv_idx);

      // Check if the motion search result same as previous results
      if (cur_mv[0].as_int ==
              args->single_newmv[pb_mv_precision][temp_mv_idx[0]][refs[0]]
                  .as_int &&
          args->single_newmv_valid[pb_mv_precision][temp_mv_idx[0]][refs[0]]) {
        // If the compared mode has no valid rd, it is unlikely this
        // mode will be the best mode
        if (mode_info[i].rd == INT64_MAX) {
          skip = 1;
          break;
        }
        // Compare the cost difference including drl cost and mv cost
        if (mode_info[i].mv.as_int != INVALID_MV) {
          const int compare_cost = mode_info[i].rate_mv + mode_info[i].drl_cost;
          const int_mv ref_mv = av2_get_ref_mv(x, 0);
          // Check if this MV is within mv_limit
          SubpelMvLimits mv_limits;
          av2_set_subpel_mv_search_range(&mv_limits, &x->mv_limits,
                                         &ref_mv.as_mv, pb_mv_precision);
          if (!av2_is_subpelmv_in_range(&mv_limits, mode_info[i].mv.as_mv))
            continue;

          this_rate_mv = av2_mv_bit_cost(&mode_info[i].mv.as_mv, &ref_mv.as_mv,
                                         pb_mv_precision, &x->mv_costs,
                                         MV_COST_WEIGHT, is_adaptive_mvd);

          const int this_cost = this_rate_mv + drl_cost;

          if (compare_cost <= this_cost) {
            // Skip this mode if it is more expensive as the previous result
            // for this MV
            skip = 1;
            break;
          } else {
            // If the cost is less than current best result, make this
            // the best and update corresponding variables unless the
            // best_mv is the same as ref_mv. In this case we skip and
            // rely on NEAR(EST)MV instead
            if (best_mbmi->mode == this_mode &&
                best_mbmi->ref_frame[0] == refs[0] &&
                best_mbmi->ref_frame[1] == refs[1] &&
                av2_ref_mv_idx_type(best_mbmi, best_mbmi->ref_mv_idx) == i &&

                best_mbmi->mv[0].as_int != ref_mv.as_int &&
                best_mbmi->pb_mv_precision == pb_mv_precision &&
                best_mbmi->bawp_flag[0] == bawp_flag_y &&
                best_mbmi->bawp_flag[1] == bawp_flag_uv) {
              assert(*best_rd != INT64_MAX);
              assert(best_mbmi->mv[0].as_int == mode_info[i].mv.as_int);
              best_mbmi->ref_mv_idx[0] = ref_mv_idx[0];
              best_mbmi->ref_mv_idx[1] = ref_mv_idx[1];
              motion_mode_cand->rate_mv = this_rate_mv;
              best_rd_stats->rate += this_cost - compare_cost;
              *best_rd =
                  RDCOST(x->rdmult, best_rd_stats->rate, best_rd_stats->dist);
              // We also need to update mode_info here because we are setting
              // (ref_)best_rd here. So we will not be able to search the same
              // mode again with the current configuration
              mode_info[ref_mv_idx_type].mv.as_int = best_mbmi->mv[0].as_int;
              mode_info[ref_mv_idx_type].rate_mv = this_rate_mv;
              mode_info[ref_mv_idx_type].rd = *best_rd;

              if (*best_rd < *ref_best_rd) *ref_best_rd = *best_rd;
              break;
            }
          }
        }
      }
    }
  }
  if (skip) {
    // Collect mode stats for multiwinner mode processing
    store_winner_mode_stats(
        &cpi->common, x, best_mbmi, best_rd_stats, best_rd_stats_y,
        best_rd_stats_uv, refs, best_mbmi->mode, NULL, bsize, *best_rd,
        cpi->sf.winner_mode_sf.multi_winner_mode_type, do_tx_search);
    assert(i != -1);

    args->modelled_rd[this_mode][ref_mv_idx[0]][refs[0]] =
        args->modelled_rd[this_mode][i][refs[0]];
    args->simple_rd[this_mode][ref_mv_idx[0]][refs[0]] =
        args->simple_rd[this_mode][i][refs[0]];
    mode_info[ref_mv_idx_type].rd = mode_info[i].rd;
    mode_info[ref_mv_idx_type].rate_mv = this_rate_mv;

    int_mv temp_mv = mode_info[i].mv;
    clamp_mv_in_range(x, &temp_mv, 0, pb_mv_precision);
    mode_info[ref_mv_idx_type].mv.as_int = temp_mv.as_int;

    restore_dst_buf(xd, orig_dst, num_planes);
    return 1;
  }
  return 0;
}

/*!\brief High level function to select parameters for compound mode.
 *
 * \ingroup inter_mode_search
 * The main search functionality is done in the call to
 av2_compound_type_rd().
 *
 * \param[in]     cpi               Top-level encoder structure.
 * \param[in]     x                 Pointer to struct holding all the data for
 *                                  the current macroblock.
 * \param[in]     args              HandleInterModeArgs struct holding
 *                                  miscellaneous arguments for inter mode
 *                                  search. See the documentation for this
 *                                  struct for a description of each member.
 * \param[in]     ref_best_rd       Best RD found so far for this block.
 *                                  It is used for early termination of this
 *                                  search if the RD exceeds this value.
 * \param[in,out] cur_mv            Current motion vector.
 * \param[in]     bsize             Current block size.
 * \param[in,out] compmode_interinter_cost  RD of the selected interinter
                                    compound mode.
 * \param[in,out] rd_buffers        CompoundTypeRdBuffers struct to hold all
 *                                  allocated buffers for the compound
 *                                  predictors and masks in the compound type
 *                                  search.
 * \param[in,out] orig_dst          A prediction buffer to hold a computed
 *                                  prediction. This will eventually hold the
 *                                  final prediction, and the tmp_dst info
 will
 *                                  be copied here.
 * \param[in]     tmp_dst           A temporary prediction buffer to hold a
 *                                  computed prediction.
 * \param[in,out] rate_mv           The rate associated with the motion
 vectors.
 *                                  This will be modified if a motion search
 is
 *                                  done in the motion mode search.
 * \param[in,out] rd_stats          Struct to keep track of the overall RD
 *                                  information.
 * \param[in,out] skip_rd           An array of length 2 where skip_rd[0] is
 the
 *                                  best total RD for a skip mode so far, and
 *                                  skip_rd[1] is the best RD for a skip mode
 so
 *                                  far in luma. This is used as a speed
 feature
 *                                  to skip the transform search if the
 computed
 *                                  skip RD for the current mode is not better
 *                                  than the best skip_rd so far.
 * \param[in,out] skip_build_pred   Indicates whether or not to build the
 inter
 *                                  predictor. If this is 0, the inter
 predictor
 *                                  has already been built and thus we can
 avoid
 *                                  repeating computation.
 * \return Returns 1 if this mode is worse than one already seen and 0 if it
 is
 * a viable candidate.
 */
static int process_compound_inter_mode(
    AV2_COMP *const cpi, MACROBLOCK *x, HandleInterModeArgs *args,
    int64_t ref_best_rd, int_mv *cur_mv, BLOCK_SIZE bsize,
    int *compmode_interinter_cost, const CompoundTypeRdBuffers *rd_buffers,
    const BUFFER_SET *orig_dst, const BUFFER_SET *tmp_dst, int *rate_mv,
    RD_STATS *rd_stats, int64_t *skip_rd, int *skip_build_pred) {
  MACROBLOCKD *xd = &x->e_mbd;
  MB_MODE_INFO *mbmi = xd->mi[0];
  const AV2_COMMON *cm = &cpi->common;
  const int masked_compound_used =
      is_any_masked_compound_used(bsize) &&
      cm->seq_params.enable_masked_compound &&
      (!mbmi->refinemv_flag || !switchable_refinemv_flag(cm, mbmi)) &&
      !opfl_allowed_cur_pred_mode(cm, xd, mbmi);
  int mode_search_mask =
      (1 << COMPOUND_AVERAGE) | (1 << COMPOUND_WEDGE) | (1 << COMPOUND_DIFFWTD);

  if (get_cwp_idx(mbmi) != CWP_EQUAL) {
    mode_search_mask = (1 << COMPOUND_AVERAGE);
  }
  const int num_planes = av2_num_planes(cm);
  const int mi_row = xd->mi_row;
  const int mi_col = xd->mi_col;
  // Find matching interp filter or set to default interp filter
  const int need_search = av2_is_interp_needed(cm, xd);
  const InterpFilter assign_filter = cm->features.interp_filter;
  int is_luma_interp_done = 0;
  av2_find_interp_filter_match(mbmi, cpi, assign_filter, need_search,
                               args->interp_filter_stats, xd,
                               args->interp_filter_stats_idx);

  int64_t best_rd_compound;
  int64_t rd_thresh;
  const int comp_type_rd_shift = COMP_TYPE_RD_THRESH_SHIFT;
  const int comp_type_rd_scale = COMP_TYPE_RD_THRESH_SCALE;
  rd_thresh = get_rd_thresh_from_best_rd(ref_best_rd, (1 << comp_type_rd_shift),
                                         comp_type_rd_scale);
  // Select compound type and any parameters related to that type
  // (for example, the mask parameters if it is a masked mode) and compute
  // the RD
  *compmode_interinter_cost = av2_compound_type_rd(
      cpi, x, bsize, cur_mv, mode_search_mask, masked_compound_used, orig_dst,
      tmp_dst, rd_buffers, rate_mv, &best_rd_compound, rd_stats, ref_best_rd,
      skip_rd[1], &is_luma_interp_done, rd_thresh);

  if (ref_best_rd < INT64_MAX &&
      (best_rd_compound >> comp_type_rd_shift) * comp_type_rd_scale >
          ref_best_rd) {
    restore_dst_buf(xd, *orig_dst, num_planes);
    return 1;
  }

  // Build only uv predictor for COMPOUND_AVERAGE.
  // Note there is no need to call av2_enc_build_inter_predictor
  // for luma if COMPOUND_AVERAGE is selected because it is the first
  // candidate in av2_compound_type_rd, which means it used the dst_buf
  // rather than the tmp_buf.
  if (mbmi->interinter_comp.type == COMPOUND_AVERAGE && is_luma_interp_done) {
    if (num_planes > 1) {
      av2_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize,
                                    AVM_PLANE_U, num_planes - 1);
    }
    *skip_build_pred = 1;
  }
  return 0;
}

// Speed feature to prune out MVs that are similar to previous MVs if they
// don't achieve the best RD advantage.
static int prune_ref_mv_idx_search(const FeatureFlags *const features,
                                   int ref_mv_idx[2], int best_ref_mv_idx[2],
                                   int_mv save_mv[MAX_REF_MV_SEARCH - 1][2],
                                   MB_MODE_INFO *mbmi, int pruning_factor) {
  (void)features;
  int i;
  const int is_comp_pred = has_second_ref(mbmi);
  const int thr = (1 + is_comp_pred) << (pruning_factor + 1);

  // Skip the evaluation if an MV match is found.
  if (ref_mv_idx[0] > 0 || ref_mv_idx[1] > 0) {
    int idx[2];
    for (idx[1] = 0; idx[1] <= ref_mv_idx[1]; ++idx[1]) {
      for (idx[0] = 0; idx[0] <= ref_mv_idx[0]; ++idx[0]) {
        if (idx[1] == ref_mv_idx[1] && idx[0] == ref_mv_idx[0]) continue;

        int idx_type = av2_ref_mv_idx_type(mbmi, idx);

        if (save_mv[idx_type][0].as_int == INVALID_MV) continue;

        int mv_diff = 0;
        for (i = 0; i < 1 + is_comp_pred; ++i) {
          mv_diff +=
              abs(save_mv[idx_type][i].as_mv.row - mbmi->mv[i].as_mv.row) +
              abs(save_mv[idx_type][i].as_mv.col - mbmi->mv[i].as_mv.col);
        }

        // If this mode is not the best one, and current MV is similar to
        // previous stored MV, terminate this ref_mv_idx evaluation.
        if ((best_ref_mv_idx[0] == -1 || best_ref_mv_idx[1] == -1) &&
            mv_diff <= thr)
          return 1;
      }
    }
  }

  if (ref_mv_idx[0] < features->max_drl_bits &&
      ref_mv_idx[1] < features->max_drl_bits) {
    for (i = 0; i < is_comp_pred + 1; ++i)
      save_mv[av2_ref_mv_idx_type(mbmi, ref_mv_idx)][i].as_int =
          mbmi->mv[i].as_int;
  }

  return 0;
}

// Calculate SSE when using compound weighted prediction
uint64_t av2_cwp_sse_from_residuals_c(const int16_t *r1, const int16_t *d,
                                      const int8_t *m, int N) {
  uint64_t csse = 0;
  int i;

  for (i = 0; i < N; i++) {
    int32_t t = (1 << WEDGE_WEIGHT_BITS) * r1[i] + m[i] * d[i];
    t = clamp(t, INT16_MIN, INT16_MAX);
    csse += t * t;
  }
  return ROUND_POWER_OF_TWO(csse, 2 * WEDGE_WEIGHT_BITS);
}

// Select a subset of cwp weighting factors
static void set_cwp_search_mask(const AV2_COMP *const cpi, MACROBLOCK *const x,
                                const BLOCK_SIZE bsize, uint16_t *const p0,
                                uint16_t *const p1, int16_t *residual1,
                                int16_t *diff10, int stride, int *mask) {
  MACROBLOCKD *xd = &x->e_mbd;
  const int bw = block_size_wide[bsize];
  const int bh = block_size_high[bsize];
  // get inter predictors to use for masked compound modes
  av2_build_inter_predictor_single_buf_y(xd, bsize, 0, p0, stride);
  av2_build_inter_predictor_single_buf_y(xd, bsize, 1, p1, stride);
  const struct buf_2d *const src = &x->plane[0].src;

  avm_highbd_subtract_block(bh, bw, residual1, bw, src->buf, src->stride, p1,
                            bw, xd->bd);
  avm_highbd_subtract_block(bh, bw, diff10, bw, p1, bw, p0, bw, xd->bd);

  MB_MODE_INFO *const mbmi = xd->mi[0];

  const AV2_COMMON *const cm = &cpi->common;
  const int same_side = is_ref_frame_same_side(cm, mbmi);

  const int N = 1 << num_pels_log2_lookup[bsize];
  int rate;
  int64_t dist;
  int cwp_index;
  int64_t best_rd = INT64_MAX;
  const int bd_round = (xd->bd - 8) * 2;

  const int8_t *tmp_mask;
  int rate_cwp_idx;

  int idx_list[MAX_CWP_NUM];
  int64_t cost_list[MAX_CWP_NUM];

  for (int i = 0; i < MAX_CWP_NUM; i++) {
    idx_list[i] = i;
    cost_list[i] = INT64_MAX;
  }

  for (cwp_index = 0; cwp_index < MAX_CWP_NUM; cwp_index++) {
    if (cwp_index == 0) continue;

    tmp_mask = av2_get_cwp_mask(same_side, cwp_index);

    // compute rd for mask
    uint64_t sse = av2_cwp_sse_from_residuals_c(residual1, diff10, tmp_mask, N);
    sse = ROUND_POWER_OF_TWO(sse, bd_round);

    model_rd_sse_fn[MODELRD_TYPE_MASKED_COMPOUND](cpi, x, bsize, 0, sse, N,
                                                  &rate, &dist);
    int8_t cur_cwp = cwp_weighting_factor[same_side][cwp_index];
    rate_cwp_idx = av2_get_cwp_idx_cost(cur_cwp, cm, x);
    const int64_t rd0 = RDCOST(x->rdmult, rate + rate_cwp_idx, dist);
    if (rd0 < best_rd) {
      best_rd = rd0;
    }

    cost_list[cwp_index] = rd0;
  }

  // sort cwp in ascending order
  for (int i = 0; i < MAX_CWP_NUM - 1; i++) {
    for (int j = 0; j < (MAX_CWP_NUM - 1) - i; j++) {
      if (cost_list[j] > cost_list[j + 1]) {
        int64_t tmp_cost = cost_list[j];
        cost_list[j] = cost_list[j + 1];
        cost_list[j + 1] = tmp_cost;

        int tmp_idx = idx_list[j];
        idx_list[j] = idx_list[j + 1];
        idx_list[j + 1] = tmp_idx;
      }
    }
  }

  int th = 2;
  for (int i = 0; i < MAX_CWP_NUM; i++) {
    if (i < th) {
      mask[idx_list[i]] = 1;
    } else {
      mask[idx_list[i]] = 0;
    }
  }

  return;
}

/*!\brief AV2 inter mode RD computation
 *
 * \ingroup inter_mode_search
 * Do the RD search for a given inter mode and compute all information
 * relevant to the input mode. It will compute the best MV, compound
 * parameters (if the mode is a compound mode) and interpolation filter
 * parameters.
 *
 * \param[in]     cpi               Top-level encoder structure.
 * \param[in]     tile_data         Pointer to struct holding adaptive
 *                                  data/contexts/models for the tile during
 *                                  encoding.
 * \param[in]     x                 Pointer to structure holding all the data
 *                                  for the current macroblock.
 * \param[in]     bsize             Current block size.
 * \param[in,out] rd_stats          Struct to keep track of the overall RD
 *                                  information.
 * \param[in,out] rd_stats_y        Struct to keep track of the RD information
 *                                  for only the Y plane.
 * \param[in,out] rd_stats_uv       Struct to keep track of the RD information
 *                                  for only the UV planes.
 * \param[in]     args              HandleInterModeArgs struct holding
 *                                  miscellaneous arguments for inter mode
 *                                  search. See the documentation for this
 *                                  struct for a description of each member.
 * \param[in]     ref_best_rd       Best RD found so far for this block.
 *                                  It is used for early termination of this
 *                                  search if the RD exceeds this value.
 * \param[in]     tmp_buf           Temporary buffer used to hold predictors
 *                                  built in this search.
 * \param[in,out] rd_buffers        CompoundTypeRdBuffers struct to hold all
 *                                  allocated buffers for the compound
 *                                  predictors and masks in the compound type
 *                                  search.
 * \param[in,out] best_est_rd       Estimated RD for motion mode search if
 *                                  do_tx_search (see below) is 0.
 * \param[in]     do_tx_search      Parameter to indicate whether or not to do
 *                                  a full transform search. This will compute
 *                                  an estimated RD for the modes without the
 *                                  transform search and later perform the
 * full transform search on the best candidates. \param[in,out]
 * inter_modes_info  InterModesInfo struct to hold inter mode information to
 * perform a full transform search only on winning candidates searched with an
 * estimate for transform coding RD. \param[in,out] motion_mode_cand  A
 * motion_mode_candidate struct to store motion mode information used in a
 * speed feature to search motion modes other than SIMPLE_TRANSLATION only on
 * winning candidates. \param[in,out] skip_rd           A length 2 array,
 * where skip_rd[0] is the best total RD for a skip mode so far, and
 *                                  skip_rd[1] is the best RD for a skip mode
 * so far in luma. This is used as a speed feature to skip the transform
 * search if the computed skip RD for the current mode is not better than the
 * best skip_rd so far. \param[in] best_ref_mode         Parameter to indicate
 * the best mode so far. This is used as a speed feature to skip the
 *                                  additional scaling factors for joint mvd
 *                                  coding mode.
 * \param[in]     inter_cost_info_from_tpl A PruneInfoFromTpl struct used to
 *                                         narrow down the search based on
 * data collected in the TPL model.
 * \param[in]     top_motion_mode_model_rd A buffer to store N number of model
 * RD
 *
 * \return The RD cost for the mode being searched.
 */
static int64_t handle_inter_mode(
    AV2_COMP *const cpi, TileDataEnc *tile_data, MACROBLOCK *x,
    BLOCK_SIZE bsize, RD_STATS *rd_stats, RD_STATS *rd_stats_y,
    RD_STATS *rd_stats_uv, HandleInterModeArgs *args, int64_t ref_best_rd,
    uint16_t *const tmp_buf, const CompoundTypeRdBuffers *rd_buffers,
    int64_t *best_est_rd, const int do_tx_search,
    InterModesInfo *inter_modes_info, motion_mode_candidate *motion_mode_cand,
    int64_t *skip_rd, PREDICTION_MODE best_ref_mode,
    int64_t top_motion_mode_model_rd[],
    PruneInfoFromTpl *inter_cost_info_from_tpl) {
  const AV2_COMMON *cm = &cpi->common;
  const int num_planes = av2_num_planes(cm);
  MACROBLOCKD *xd = &x->e_mbd;
  MB_MODE_INFO *mbmi = xd->mi[0];
  MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
  TxfmSearchInfo *txfm_info = &x->txfm_search_info;
  const int is_comp_pred = has_second_ref(mbmi);
  const PREDICTION_MODE this_mode = mbmi->mode;

  const GF_GROUP *const gf_group = &cpi->gf_group;
  const int tpl_idx = gf_group->index;
  TplDepFrame *tpl_frame = &cpi->tpl_data.tpl_frame[tpl_idx];
  const int prune_modes_based_on_tpl =
      cpi->sf.inter_sf.prune_inter_modes_based_on_tpl &&
      tpl_idx < MAX_TPL_FRAME_IDX && tpl_frame->is_valid;
  int i;
  // Reference frames for this mode
  const MV_REFERENCE_FRAME refs[2] = { COMPACT_INDEX0_NRS(mbmi->ref_frame[0]),
                                       COMPACT_INDEX1_NRS(mbmi->ref_frame[1]) };
  int rate_mv = 0;
  int64_t rd = INT64_MAX;
  // Do first prediction into the destination buffer. Do the next
  // prediction into a temporary buffer. Then keep track of which one
  // of these currently holds the best predictor, and use the other
  // one for future predictions. In the end, copy from tmp_buf to
  // dst if necessary.
  struct macroblockd_plane *p = xd->plane;
  const BUFFER_SET orig_dst = {
    { p[0].dst.buf, p[1].dst.buf, p[2].dst.buf },
    { p[0].dst.stride, p[1].dst.stride, p[2].dst.stride },
  };
  const BUFFER_SET tmp_dst = { { tmp_buf, tmp_buf + 1 * MAX_SB_SQUARE,
                                 tmp_buf + 2 * MAX_SB_SQUARE },
                               { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE } };

  int64_t ret_val = INT64_MAX;
  RD_STATS best_rd_stats, best_rd_stats_y, best_rd_stats_uv;
  int64_t best_rd = INT64_MAX;
  uint8_t best_blk_skip[MAX_MB_PLANE][MAX_MIB_SIZE * MAX_MIB_SIZE];
  TX_TYPE best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE];
  CctxType best_cctx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE];
  MB_MODE_INFO best_mbmi = *mbmi;
  SUBMB_INFO best_submi[MAX_MIB_SIZE * MAX_MIB_SIZE];
  store_submi(xd, cm, best_submi, bsize);
  int best_xskip_txfm = 0;
  int64_t newmv_ret_val = INT64_MAX;
  const int is_pb_mv_prec_active = is_pb_mv_precision_active(cm, mbmi, bsize);
  const int has_two_drls = has_second_drl(mbmi);

  // First, perform a simple translation search for each of the indices. If
  // an index performs well, it will be fully searched in the main loop
  // of this function.
  int ref_set[2];
  ref_set[0] = get_drl_refmv_count(cm->features.max_drl_bits, x,
                                   mbmi->ref_frame, this_mode, 0);
  ref_set[1] = 1;
  if (has_two_drls) {
    ref_set[1] = get_drl_refmv_count(cm->features.max_drl_bits, x,
                                     mbmi->ref_frame, this_mode, 1);
  }

  inter_mode_info mode_info[BAWP_OPTION_CNT][NUM_MV_PRECISIONS]
                           [MAX_REF_MV_SEARCH * MAX_REF_MV_SEARCH];
  // initialize mode_info
  for (int bawp = 0; bawp < BAWP_OPTION_CNT; bawp++) {
    for (int prec = MV_PRECISION_8_PEL; prec <= mbmi->max_mv_precision;
         ++prec) {
      for (int ref_mv_id_1 = 0; ref_mv_id_1 < ref_set[1]; ++ref_mv_id_1) {
        for (int ref_mv_id_0 = 0; ref_mv_id_0 < ref_set[0]; ++ref_mv_id_0) {
          const int idx = has_two_drls
                              ? ref_mv_id_1 * MAX_REF_MV_SEARCH + ref_mv_id_0
                              : ref_mv_id_0;
          mode_info[bawp][prec][idx].full_search_mv.as_int = INVALID_MV;
          mode_info[bawp][prec][idx].mv.as_int = INVALID_MV;
          mode_info[bawp][prec][idx].rd = INT64_MAX;
          mode_info[bawp][prec][idx].drl_cost = 0;
          mode_info[bawp][prec][idx].rate_mv = 0;
          mode_info[bawp][prec][idx].full_mv_rate = 0;
        }
      }
    }
  }

  mbmi->bawp_flag[0] = 0;
  mbmi->bawp_flag[1] = 0;
  mbmi->refinemv_flag = 0;

  // Do not prune the mode based on inter cost from tpl if the current ref
  // frame is the winner ref in neighbouring blocks.
  int ref_match_found_in_above_nb = 0;
  int ref_match_found_in_left_nb = 0;
  if (prune_modes_based_on_tpl) {
    ref_match_found_in_above_nb =
        find_ref_match_in_above_nbs(cm->mi_params.mi_cols, xd);
    ref_match_found_in_left_nb =
        find_ref_match_in_left_nbs(cm->mi_params.mi_rows, xd);
  }

  assert(IMPLIES(this_mode == WARPMV, ref_set[0] == 1));

  // Save MV results from first 2 ref_mv_idx.

  int_mv save_mv[NUM_MV_PRECISIONS][MAX_REF_MV_SEARCH * MAX_REF_MV_SEARCH][2];

  int best_ref_mv_idx[2] = { -1, -1 };

  const int16_t mode_ctx =
      av2_mode_context_analyzer(mbmi_ext->mode_context, mbmi->ref_frame);

  const ModeCosts *mode_costs = &x->mode_costs;
  const int prediction_mode_cost =
      cost_prediction_mode(mode_costs, this_mode, cm, mbmi, xd, mode_ctx);

  const int base_rate =
      args->ref_frame_cost + args->single_comp_cost + prediction_mode_cost;

  for (int pb_mv_precision = mbmi->max_mv_precision;
       pb_mv_precision >= MV_PRECISION_8_PEL; pb_mv_precision--) {
    for (i = 0; i < MAX_REF_MV_SEARCH * MAX_REF_MV_SEARCH - 1; ++i) {
      save_mv[pb_mv_precision][i][0].as_int = INVALID_MV;
      save_mv[pb_mv_precision][i][1].as_int = INVALID_MV;
    }
  }

  int flex_mv_cost[NUM_MV_PRECISIONS] = { 0, 0, 0, 0, 0, 0, 0 };
  int idx_mask[BAWP_OPTION_CNT][NUM_MV_PRECISIONS] = { 0 };
  if (is_pb_mv_prec_active) {
    const int down_ctx = av2_get_pb_mv_precision_down_context(cm, xd);
    const int mpp_flag_context = av2_get_mpp_flag_context(cm, xd);
    set_precision_set(cm, xd, mbmi, bsize, 0);
    set_most_probable_mv_precision(cm, mbmi, bsize);
    const PRECISION_SET *precision_def =
        &av2_mv_precision_sets[mbmi->mb_precision_set];
    for (int precision_dx = precision_def->num_precisions - 1;
         precision_dx >= 0; precision_dx--) {
      MvSubpelPrecision pb_mv_precision =
          precision_def->precision[precision_dx];
      assert(pb_mv_precision <= mbmi->max_mv_precision);
      set_mv_precision(mbmi, pb_mv_precision);

      flex_mv_cost[pb_mv_precision] = cost_mv_precision(
          mode_costs, mbmi->max_mv_precision, pb_mv_precision, down_ctx,
          mbmi->most_probable_pb_mv_precision, mpp_flag_context, mbmi);
      set_mv_precision(mbmi, pb_mv_precision);
      mbmi->bawp_flag[0] = 0;
      mbmi->bawp_flag[1] = 0;

      idx_mask[0][pb_mv_precision] = ref_mv_idx_to_search(
          cpi, x, rd_stats, args, ref_best_rd, mode_info[0][pb_mv_precision],
          bsize, ref_set, flex_mv_cost[pb_mv_precision]);

      if (cm->features.enable_bawp &&
          av2_allow_bawp(cm, mbmi, xd->mi_row, xd->mi_col)) {
        for (int bawp = 1; bawp < BAWP_OPTION_CNT; bawp++) {
          mbmi->bawp_flag[0] = bawp;
          idx_mask[bawp][pb_mv_precision] =
              ref_mv_idx_to_search(cpi, x, rd_stats, args, ref_best_rd,
                                   mode_info[bawp][pb_mv_precision], bsize,
                                   ref_set, flex_mv_cost[pb_mv_precision]);
        }
        mbmi->bawp_flag[0] = 0;
      }
    }

    // restore the MV precision to max value
    set_mv_precision(mbmi, mbmi->max_mv_precision);
  } else {
    set_mv_precision(mbmi, mbmi->max_mv_precision);

    mbmi->bawp_flag[0] = 0;
    mbmi->bawp_flag[1] = 0;

    idx_mask[0][mbmi->max_mv_precision] = ref_mv_idx_to_search(
        cpi, x, rd_stats, args, ref_best_rd,
        mode_info[0][mbmi->max_mv_precision], bsize, ref_set, 0);

    if (cm->features.enable_bawp &&
        av2_allow_bawp(cm, mbmi, xd->mi_row, xd->mi_col)) {
      for (int bawp = 1; bawp < BAWP_OPTION_CNT; bawp++) {
        mbmi->bawp_flag[0] = bawp;
        idx_mask[bawp][mbmi->max_mv_precision] = ref_mv_idx_to_search(
            cpi, x, rd_stats, args, ref_best_rd,
            mode_info[bawp][mbmi->max_mv_precision], bsize, ref_set, 0);
      }
      mbmi->bawp_flag[0] = 0;
    }
  }

  // Main loop of this function. This will  iterate over all of the ref mvs
  // in the dynamic reference list and do the following:
  //    1.) Get the current MV. Create newmv MV if necessary
  //    2.) Search compound type and parameters if applicable
  //    3.) Do interpolation filter search
  //    4.) Build the inter predictor
  //    5.) Pick the motion mode
  //    6.) Update stats if best so far
  mbmi->refinemv_flag =
      0;  // initialize to 0; later on the default value is assigned
  const int jmvd_scaling_factor_num =
      is_joint_mvd_coding_mode(mbmi->mode) ? JOINT_NEWMV_SCALE_FACTOR_CNT : 1;
  for (int scale_index = 0; scale_index < jmvd_scaling_factor_num;
       ++scale_index) {
    mbmi->jmvd_scale_mode = scale_index;
    if (is_joint_amvd_coding_mode(mbmi->mode, mbmi->use_amvd)) {
      if (scale_index > JOINT_AMVD_SCALE_FACTOR_CNT - 1) continue;
    }
    if (cpi->sf.inter_sf.early_terminate_jmvd_scale_factor) {
      if (scale_index > 0 && best_rd > 1.5 * ref_best_rd &&
          (!is_inter_compound_mode(best_ref_mode)))
        continue;
    }
    int best_cwp_idx = CWP_EQUAL;
    int64_t best_cwp_cost = INT64_MAX;

    int ref_mv_idx[2];
    for (ref_mv_idx[1] = 0; ref_mv_idx[1] < ref_set[1]; ++ref_mv_idx[1]) {
      for (ref_mv_idx[0] = 0; ref_mv_idx[0] < ref_set[0]; ++ref_mv_idx[0]) {
        // apply early termination method to jmvd scaling factors
        if (cpi->sf.inter_sf.early_terminate_jmvd_scale_factor) {
          if (scale_index > 0 && (ref_mv_idx[0] > 0 || ref_mv_idx[1] > 0) &&
              best_mbmi.jmvd_scale_mode == 0 &&
              (best_mbmi.ref_mv_idx[0] < ref_mv_idx[0] ||
               best_mbmi.ref_mv_idx[1] < ref_mv_idx[1]))
            continue;
        }
        if (mbmi->ref_frame[0] == mbmi->ref_frame[1] &&
            mbmi->mode == NEAR_NEARMV && ref_mv_idx[0] >= ref_mv_idx[1])
          continue;
        mbmi->cwp_idx = CWP_EQUAL;
        const int same_side = is_ref_frame_same_side(cm, mbmi);
        int cwp_loop_num = cm->features.enable_cwp ? MAX_CWP_NUM : 1;
        if (best_cwp_idx == CWP_EQUAL &&
            (ref_mv_idx[0] > 0 || ref_mv_idx[1] > 0))
          cwp_loop_num = 1;

        int cwp_search_mask[MAX_CWP_NUM] = { 0 };
        av2_zero(cwp_search_mask);
        // Loop all supported weighting factors for CWP
        for (int cwp_search_idx = 0; cwp_search_idx < cwp_loop_num;
             cwp_search_idx++) {
          mbmi->ref_mv_idx[1] = ref_mv_idx[1];
          mbmi->ref_mv_idx[0] = ref_mv_idx[0];
          mbmi->interinter_comp.type = COMPOUND_AVERAGE;
          mbmi->comp_group_idx = 0;
          mbmi->motion_mode = SIMPLE_TRANSLATION;

          mbmi->cwp_idx = cwp_weighting_factor[same_side][cwp_search_idx];

          if (mbmi->cwp_idx != CWP_EQUAL) {
            if (!is_cwp_allowed(mbmi)) break;
            if (cwp_search_mask[cwp_search_idx] == 0) {
              continue;
            }
          }
          if (mbmi->cwp_idx == -1) {
            break;
          }

          // Initialize compound mode data
          mbmi->interinter_comp.type = COMPOUND_AVERAGE;
          mbmi->comp_group_idx = 0;
          if (mbmi->ref_frame[1] == INTRA_FRAME)
            mbmi->ref_frame[1] = NONE_FRAME;

          mbmi->num_proj_ref[0] = mbmi->num_proj_ref[1] = 0;
          mbmi->motion_mode = SIMPLE_TRANSLATION;
          mbmi->ref_mv_idx[1] = ref_mv_idx[1];
          mbmi->ref_mv_idx[0] = ref_mv_idx[0];
          int ref_mv_idx_type = av2_ref_mv_idx_type(mbmi, ref_mv_idx);
          set_mv_precision(mbmi, mbmi->max_mv_precision);
          if (mbmi->mode != WARPMV && prune_modes_based_on_tpl &&
              !ref_match_found_in_above_nb && !ref_match_found_in_left_nb &&
              (ref_best_rd != INT64_MAX)) {
            // Skip mode if TPL model indicates it will not be beneficial.
            if (prune_modes_based_on_tpl_stats(
                    &cm->features, inter_cost_info_from_tpl, refs,
                    ref_mv_idx[0], this_mode,
                    cpi->sf.inter_sf.prune_inter_modes_based_on_tpl))
              continue;
          }
          const int drl_cost =
              get_drl_cost(cm->features.max_drl_bits, mbmi, mbmi_ext, x);

          MvSubpelPrecision best_precision_so_far = mbmi->max_mv_precision;
          int64_t best_precision_rd_so_far = INT64_MAX;
          set_precision_set(cm, xd, mbmi, bsize, ref_mv_idx);
          set_most_probable_mv_precision(cm, mbmi, bsize);
          const PRECISION_SET *precision_def =
              &av2_mv_precision_sets[mbmi->mb_precision_set];
          int best_precision_dx_so_far = precision_def->num_precisions;
          for (int precision_dx = precision_def->num_precisions - 1;
               precision_dx >= 0; precision_dx--) {
            MvSubpelPrecision pb_mv_precision =
                precision_def->precision[precision_dx];
            mbmi->pb_mv_precision = pb_mv_precision;
            if (!is_pb_mv_prec_active &&
                (pb_mv_precision != mbmi->max_mv_precision)) {
              continue;
            }
            assert(pb_mv_precision <= mbmi->max_mv_precision);

            const int jmvd_scale_mode_cost =
                get_jmvd_scale_mode_cost(mbmi, mode_costs);
            const int rate_so_far = base_rate + drl_cost +
                                    flex_mv_cost[mbmi->pb_mv_precision] +
                                    jmvd_scale_mode_cost;
            if (cpi->sf.inter_sf.skip_mode_eval_based_on_rate_cost &&
                ref_best_rd != INT64_MAX &&
                RDCOST(x->rdmult, rate_so_far, 0) > ref_best_rd) {
              continue;
            }

            // apply early termination method to jmvd scaling factors
            if (cpi->sf.inter_sf.early_terminate_jmvd_scale_factor) {
              if (scale_index > 0 && (!is_inter_compound_mode(best_ref_mode)) &&
                  mbmi->pb_mv_precision <= MV_PRECISION_HALF_PEL &&
                  best_mbmi.jmvd_scale_mode == 0 &&
                  best_mbmi.pb_mv_precision > MV_PRECISION_HALF_PEL)
                continue;
            }

            if (is_pb_mv_prec_active) {
              if (cpi->sf.flexmv_sf.terminate_early_4_pel_precision &&
                  pb_mv_precision < MV_PRECISION_FOUR_PEL &&
                  best_precision_so_far >= MV_PRECISION_QTR_PEL)
                continue;
              if (prune_curr_mv_precision_eval(
                      cpi->sf.flexmv_sf.prune_mv_prec_using_best_mv_prec_so_far,
                      precision_dx, best_precision_dx_so_far))
                continue;
              if (mbmi->ref_mv_idx[0] || mbmi->ref_mv_idx[1]) {
                if (cpi->sf.flexmv_sf.do_not_search_8_pel_precision &&
                    mbmi->pb_mv_precision == MV_PRECISION_8_PEL)
                  continue;

                if (cpi->sf.flexmv_sf.do_not_search_4_pel_precision &&
                    mbmi->pb_mv_precision == MV_PRECISION_FOUR_PEL)
                  continue;
              }
            }

            // Get the default value of DMVR flag based on mode
            assert(mbmi->motion_mode == SIMPLE_TRANSLATION);
            mbmi->refinemv_flag = get_default_refinemv_flag(cm, mbmi);

            int rs = 0;
            int compmode_interinter_cost = 0;
            int_mv cur_mv[2];
            // TODO(Cherma): Extend this speed feature to support compound mode
            int skip_repeated_ref_mv =
                is_comp_pred ? 0 : cpi->sf.inter_sf.skip_repeated_ref_mv;
            // Generate the current mv according to the prediction mode
            if (mbmi->mode != WARPMV &&
                !build_cur_mv(cur_mv, this_mode, cm, x, skip_repeated_ref_mv)) {
              continue;
            }
            // For WARPMV mode we will build MV in the later stage
            // Currently initialize to 0
            if (mbmi->mode == WARPMV) {
              cur_mv[0].as_int = 0;
              cur_mv[1].as_int = 0;

              assert(ref_mv_idx[0] == 0 && ref_mv_idx[1] == 0);
            }

            if (mbmi->mode != WARPMV && cpi->sf.flexmv_sf.skip_similar_ref_mv &&
                skip_similar_ref_mv(cpi, x, bsize)) {
              continue;
            }

            assert(IMPLIES(mbmi->mode == WARPMV,
                           mbmi->pb_mv_precision == mbmi->max_mv_precision));

            int_mv bawp_off_mv[2];
            int64_t bawp_off_newmv_ret_val = 0;
            int bawp_off_rate_mv = 0;
            for (i = 0; i < is_comp_pred + 1; ++i) {
              bawp_off_mv[i].as_int = cur_mv[i].as_int;
            }

            int bawp_eanbled = cm->features.enable_bawp &&
                               !mbmi->refinemv_flag &&
                               av2_allow_bawp(cm, mbmi, xd->mi_row, xd->mi_col);
            if (bawp_eanbled && av2_allow_explicit_bawp(mbmi))
              bawp_eanbled += EXPLICIT_BAWP_SCALE_CNT;
            for (int bawp_flag = 0; bawp_flag <= bawp_eanbled; bawp_flag++) {
              if (mbmi->ref_mv_idx[0] > 0 && bawp_flag > 1 &&
                  best_mbmi.bawp_flag[0] == 0)
                continue;

              mbmi->bawp_flag[0] = bawp_flag;

              for (int bawp_flag_uv = 0; bawp_flag_uv <= AVMMIN(1, bawp_flag);
                   bawp_flag_uv++) {
                if (bawp_flag_uv &&
                    (!xd->is_chroma_ref || cm->seq_params.monochrome)) {
                  mbmi->bawp_flag[1] = 0;
                  continue;
                }
                mbmi->bawp_flag[1] = bawp_flag_uv;

                mode_info[bawp_flag][mbmi->pb_mv_precision][ref_mv_idx_type]
                    .full_search_mv.as_int = INVALID_MV;
                mode_info[bawp_flag][mbmi->pb_mv_precision][ref_mv_idx_type]
                    .mv.as_int = INVALID_MV;
                mode_info[bawp_flag][mbmi->pb_mv_precision][ref_mv_idx_type]
                    .rd = INT64_MAX;
                mode_info[bawp_flag][mbmi->pb_mv_precision][ref_mv_idx_type]
                    .drl_cost = drl_cost;
                if (mbmi->mode != WARPMV && !mbmi->refinemv_flag &&
                    !mask_check_bit(idx_mask[bawp_flag][mbmi->pb_mv_precision],
                                    ref_mv_idx_type)) {
                  // MV did not perform well in simple translation search. Skip
                  // it.
                  continue;
                }

                assert(!(mbmi->bawp_flag[0] && mbmi->refinemv_flag));

                if (mbmi->bawp_flag[0] >= 1) {
                  bawp_off_mv[1].as_int = -1;  // bawp_off_mv[1] won't be used
                                               // when mbmi->bawp_flag==1.
                  assert(is_comp_pred == 0);
                  for (i = 0; i < is_comp_pred + 1; ++i) {
                    mbmi->mv[i].as_int = bawp_off_mv[i].as_int;
                    cur_mv[i].as_int = bawp_off_mv[i].as_int;
                  }

                  mode_info[mbmi->bawp_flag[0]][mbmi->pb_mv_precision]
                           [ref_mv_idx_type]
                               .full_search_mv.as_int =
                      mode_info[0][mbmi->pb_mv_precision][ref_mv_idx_type]
                          .full_search_mv.as_int;
                  mode_info[mbmi->bawp_flag[0]][mbmi->pb_mv_precision]
                           [ref_mv_idx_type]
                               .full_mv_rate =
                      mode_info[0][mbmi->pb_mv_precision][ref_mv_idx_type]
                          .full_mv_rate;

                  rate_mv = bawp_off_rate_mv;
                  if (bawp_off_newmv_ret_val != 0) continue;
                } else {
                  // The above call to build_cur_mv does not handle NEWMV modes.
                  // Build the mv here if we have NEWMV for any predictors.
                  if (have_newmv_in_inter_mode(this_mode)) {
#if CONFIG_COLLECT_COMPONENT_TIMING
                    start_timing(cpi, handle_newmv_time);
#endif
                    newmv_ret_val = handle_newmv(
                        cpi, x, bsize, cur_mv, &rate_mv, args,
                        mode_info[bawp_flag][mbmi->pb_mv_precision]);

#if CONFIG_COLLECT_COMPONENT_TIMING
                    end_timing(cpi, handle_newmv_time);
#endif
                    bawp_off_rate_mv = rate_mv;
                    for (i = 0; i < is_comp_pred + 1; ++i) {
                      bawp_off_mv[i].as_int = cur_mv[i].as_int;
                    }
                    bawp_off_newmv_ret_val = newmv_ret_val;
                    if (newmv_ret_val != 0) continue;
                  }
                }
                if (have_newmv_in_inter_mode(this_mode)) {
                  int mv_outlim = 0;
                  for (int ref = 0; ref < is_comp_pred + 1; ref++) {
                    const PREDICTION_MODE single_mode =
                        get_single_mode(this_mode, ref);
                    if (single_mode == NEWMV || single_mode == WARP_NEWMV) {
                      SUBPEL_MOTION_SEARCH_PARAMS ms_params;
                      MV ref_mv = av2_get_ref_mv(x, ref).as_mv;
                      if (mbmi->pb_mv_precision < MV_PRECISION_HALF_PEL)
                        lower_mv_precision(&ref_mv, mbmi->pb_mv_precision);
                      av2_make_default_subpel_ms_params(
                          &ms_params, cpi, x, bsize, &ref_mv, pb_mv_precision,
                          0, NULL);
                      if (!av2_is_subpelmv_in_range(&ms_params.mv_limits,
                                                    cur_mv[ref].as_mv)) {
                        mv_outlim = 1;
                        break;
                      }
                    }
                  }
                  if (mv_outlim) continue;

                  // skip NEWMV mode in drl if the motion search result is the
                  // same as a previous result
                  int skip_new_mv =
                      cpi->sf.inter_sf.skip_repeated_newmv ||
                      (mbmi->pb_mv_precision != mbmi->max_mv_precision &&
                       cpi->sf.flexmv_sf.skip_repeated_newmv_low_prec);
                  if (skip_new_mv &&
                      skip_repeated_newmv(
                          cpi, x, bsize, do_tx_search, this_mode,
                          mbmi->pb_mv_precision, mbmi->bawp_flag[0],
                          mbmi->bawp_flag[1], &best_mbmi, motion_mode_cand,
                          &ref_best_rd, &best_rd_stats, &best_rd_stats_y,
                          &best_rd_stats_uv,
                          mode_info[bawp_flag][mbmi->pb_mv_precision], args,
                          drl_cost, refs, cur_mv, &best_rd, orig_dst,
                          ref_mv_idx))
                    continue;
                }

                const MB_MODE_INFO base_mbmi = *mbmi;
                for (int refinemv_loop = 0; refinemv_loop < REFINEMV_NUM_MODES;
                     refinemv_loop++) {
                  *mbmi = base_mbmi;
                  int_mv tmp_cur_mv[2];
                  for (i = 0; i < 2; ++i) {
                    tmp_cur_mv[i].as_int = cur_mv[i].as_int;
                  }
                  int tmp_rate_mv = rate_mv;
                  av2_init_rd_stats(rd_stats);
                  // Initialize compound mode data
                  mbmi->interinter_comp.type = COMPOUND_AVERAGE;
                  mbmi->comp_group_idx = 0;
                  if (mbmi->ref_frame[1] == INTRA_FRAME)
                    mbmi->ref_frame[1] = NONE_FRAME;

                  mbmi->num_proj_ref[0] = mbmi->num_proj_ref[1] = 0;
                  mbmi->motion_mode = SIMPLE_TRANSLATION;
                  mbmi->ref_mv_idx[0] = ref_mv_idx[0];
                  mbmi->ref_mv_idx[1] = ref_mv_idx[1];

                  // Compute cost for signalling this DRL index
                  rd_stats->rate = base_rate;
                  rd_stats->rate += flex_mv_cost[mbmi->pb_mv_precision];
                  rd_stats->rate += drl_cost;
                  rd_stats->rate += jmvd_scale_mode_cost;

                  if (refinemv_loop && !switchable_refinemv_flag(cm, mbmi))
                    continue;
                  mbmi->refinemv_flag =
                      switchable_refinemv_flag(cm, mbmi)
                          ? refinemv_loop
                          : get_default_refinemv_flag(cm, mbmi);
                  if (mbmi->refinemv_flag &&
                      !is_refinemv_allowed(cm, mbmi, bsize)) {
                    continue;
                  }
                  if (mbmi->refinemv_flag && mbmi->cwp_idx != CWP_EQUAL)
                    continue;

                  rd_stats->rate += tmp_rate_mv;
                  if (switchable_refinemv_flag(cm, mbmi)) {
                    rd_stats->rate +=
                        mode_costs->refinemv_flag_cost[av2_get_refinemv_context(
                            cm, xd, bsize)][mbmi->refinemv_flag];
                  }

                  // Copy the motion vector for this mode into mbmi struct
                  for (i = 0; i < is_comp_pred + 1; ++i) {
                    mbmi->mv[i].as_int = tmp_cur_mv[i].as_int;
                  }
                  assert(check_mv_precision(cm, mbmi, x));

                  const int like_nearest =
                      (mbmi->mode == NEARMV || mbmi->mode == WARPMV ||
                       mbmi->mode == NEAR_NEARMV_OPTFLOW ||
                       mbmi->mode == NEAR_NEARMV) &&
                      mbmi->ref_mv_idx[0] == 0 && mbmi->ref_mv_idx[1] == 0;
                  if (RDCOST(x->rdmult, rd_stats->rate, 0) > ref_best_rd &&
                      !like_nearest) {
                    continue;
                  }

                  // Skip the rest of the search if prune_ref_mv_idx_search
                  // speed feature is enabled, and the current MV is similar to
                  // a previous one.
                  if (cpi->sf.inter_sf.prune_ref_mv_idx_search &&
                      is_comp_pred &&
                      prune_ref_mv_idx_search(
                          &cm->features, ref_mv_idx, best_ref_mv_idx,
                          save_mv[mbmi->pb_mv_precision], mbmi,

                          cpi->sf.inter_sf.prune_ref_mv_idx_search))
                    continue;

#if CONFIG_COLLECT_COMPONENT_TIMING
                  start_timing(cpi, compound_type_rd_time);
#endif
                  int skip_build_pred = 0;
                  const int mi_row = xd->mi_row;
                  const int mi_col = xd->mi_col;

                  // set cwp_search_mask
                  if (is_cwp_allowed(mbmi) && mbmi->cwp_idx == CWP_EQUAL) {
                    set_cwp_search_mask(
                        cpi, x, bsize, rd_buffers->pred0, rd_buffers->pred1,
                        rd_buffers->residual1, rd_buffers->diff10,
                        block_size_wide[bsize], cwp_search_mask);
                  }

                  // Handle a compound predictor, continue if it is determined
                  // this cannot be the best compound mode
                  if (is_comp_pred &&
                      !is_joint_amvd_coding_mode(mbmi->mode, mbmi->use_amvd) &&
                      (!mbmi->refinemv_flag ||
                       !switchable_refinemv_flag(cm, mbmi))) {
                    const int not_best_mode = process_compound_inter_mode(
                        cpi, x, args, ref_best_rd, tmp_cur_mv, bsize,
                        &compmode_interinter_cost, rd_buffers, &orig_dst,
                        &tmp_dst, &tmp_rate_mv, rd_stats, skip_rd,
                        &skip_build_pred);
                    if (not_best_mode) continue;
                  }

                  if (cm->features.enable_cwp && is_comp_pred &&
                      is_joint_amvd_coding_mode(mbmi->mode, mbmi->use_amvd)) {
                    if (is_cwp_allowed(mbmi)) {
                      compmode_interinter_cost =
                          av2_get_cwp_idx_cost(mbmi->cwp_idx, cm, x);
                    }
                  }
                  assert(check_mv_precision(cm, mbmi, x));

#if CONFIG_COLLECT_COMPONENT_TIMING
                  end_timing(cpi, compound_type_rd_time);
#endif

#if CONFIG_COLLECT_COMPONENT_TIMING
                  start_timing(cpi, interpolation_filter_search_time);
#endif
                  // Determine the interpolation filter for this mode
                  ret_val = av2_interpolation_filter_search(
                      x, cpi, tile_data, bsize, &tmp_dst, &orig_dst, &rd, &rs,
                      &skip_build_pred, args, ref_best_rd);

                  assert(check_mv_precision(cm, mbmi, x));

#if CONFIG_COLLECT_COMPONENT_TIMING
                  end_timing(cpi, interpolation_filter_search_time);
#endif
                  if (args->modelled_rd != NULL && !is_comp_pred) {
                    args->modelled_rd[this_mode][ref_mv_idx_type][refs[0]] = rd;
                  }

                  if (mbmi->mode != WARPMV) {
                    if (ret_val != 0) {
                      restore_dst_buf(xd, orig_dst, num_planes);
                      continue;
                    } else if (cpi->sf.inter_sf
                                   .model_based_post_interp_filter_breakout &&
                               ref_best_rd != INT64_MAX &&
                               (rd >> 3) * 3 > ref_best_rd) {
                      restore_dst_buf(xd, orig_dst, num_planes);
                      continue;
                    }
                  }
                  // Compute modelled RD if enabled
                  if (args->modelled_rd != NULL) {
                    if (is_comp_pred && this_mode < NEAR_NEARMV_OPTFLOW) {
                      const int mode0 = compound_ref0_mode(this_mode);
                      const int mode1 = compound_ref1_mode(this_mode);
                      const int64_t mrd = AVMMIN(
                          args->modelled_rd[mode0][get_ref_mv_idx(mbmi, 0)]
                                           [refs[0]],
                          args->modelled_rd[mode1][get_ref_mv_idx(mbmi, 1)]
                                           [refs[1]]);

                      if ((rd >> 3) * 6 > mrd && ref_best_rd < INT64_MAX) {
                        restore_dst_buf(xd, orig_dst, num_planes);
                        continue;
                      }
                    }
                  }
                  rd_stats->rate += compmode_interinter_cost;
                  if ((skip_build_pred != 1 && (mbmi->mode != WARPMV)) ||
                      is_comp_pred) {
                    // Build this inter predictor if it has not been previously
                    // built
                    av2_enc_build_inter_predictor(cm, xd, mi_row, mi_col,
                                                  &orig_dst, bsize, 0,
                                                  av2_num_planes(cm) - 1);
                  }

                  // So far we did not make prediction for WARPMV mode
                  assert(IMPLIES(mbmi->mode == WARPMV, skip_build_pred != 1));

#if CONFIG_COLLECT_COMPONENT_TIMING
                  start_timing(cpi, motion_mode_rd_time);
#endif
                  int rate2_nocoeff = rd_stats->rate;
                  assert(IMPLIES(
                      mbmi->mode == WARPMV,
                      (rd_stats->rate == base_rate && tmp_rate_mv == 0)));
                  // Determine the motion mode. This will be one of
                  // SIMPLE_TRANSLATION, WARP_CAUSAL or WARP_EXTEND or
                  // WARP_DELTA
                  ret_val = motion_mode_rd(
                      cpi, tile_data, x, bsize, rd_stats, rd_stats_y,
                      rd_stats_uv, args, ref_best_rd, skip_rd, &tmp_rate_mv,
                      &orig_dst, best_est_rd, do_tx_search, inter_modes_info,
                      top_motion_mode_model_rd, 0);
#if CONFIG_COLLECT_COMPONENT_TIMING
                  end_timing(cpi, motion_mode_rd_time);
#endif
                  assert(IMPLIES(!av2_check_newmv_joint_nonzero(cm, x),
                                 ret_val == INT64_MAX));

                  assert(check_mv_precision(cm, mbmi, x));

                  if (ret_val != INT64_MAX) {
                    int64_t tmp_rd =
                        RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist);

                    if (is_pb_mv_prec_active &&
                        tmp_rd < best_precision_rd_so_far) {
                      best_precision_so_far = mbmi->pb_mv_precision;
                      best_precision_dx_so_far = precision_dx;
                      best_precision_rd_so_far = tmp_rd;
                    }

                    if (tmp_rd < mode_info[bawp_flag][mbmi->pb_mv_precision]
                                          [ref_mv_idx_type]
                                              .rd) {
                      // Only update mode_info if the new result is actually
                      // better.
                      mode_info[bawp_flag][mbmi->pb_mv_precision]
                               [ref_mv_idx_type]
                                   .mv.as_int = mbmi->mv[0].as_int;
                      mode_info[bawp_flag][mbmi->pb_mv_precision]
                               [ref_mv_idx_type]
                                   .rate_mv = tmp_rate_mv;
                      mode_info[bawp_flag][mbmi->pb_mv_precision]
                               [ref_mv_idx_type]
                                   .rd = tmp_rd;
                    }

                    // Collect mode stats for multiwinner mode processing
                    store_winner_mode_stats(
                        &cpi->common, x, mbmi, rd_stats, rd_stats_y,
                        rd_stats_uv, refs, mbmi->mode, NULL, bsize, tmp_rd,
                        cpi->sf.winner_mode_sf.multi_winner_mode_type,
                        do_tx_search);
                    if (tmp_rd < best_rd) {
                      // Update the best rd stats if we found the best mode so
                      // far
                      best_rd_stats = *rd_stats;
                      best_rd_stats_y = *rd_stats_y;
                      best_rd_stats_uv = *rd_stats_uv;
                      best_rd = tmp_rd;
                      best_mbmi = *mbmi;
                      if (is_warp_mode(mbmi->motion_mode)) {
                        store_submi(xd, cm, best_submi, bsize);
                      }
                      best_xskip_txfm = txfm_info->skip_txfm;
                      for (i = 0; i < num_planes; ++i) {
                        const int num_blk_plane =
                            (xd->plane[i].height * xd->plane[i].width) >>
                            (2 * MI_SIZE_LOG2);
                        memcpy(best_blk_skip[i], txfm_info->blk_skip[i],
                               sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
                      }
                      av2_copy_array(best_tx_type_map, xd->tx_type_map,
                                     xd->height * xd->width);
                      av2_copy_array(
                          best_cctx_type_map, xd->cctx_type_map,
                          (xd->plane[1].height * xd->plane[1].width) >>
                              (2 * MI_SIZE_LOG2));
                      motion_mode_cand->rate_mv = tmp_rate_mv;
                      motion_mode_cand->rate2_nocoeff = rate2_nocoeff;
                    }

                    assert(check_mv_precision(cm, mbmi, x));

                    if (is_cwp_allowed(mbmi)) {
                      if (tmp_rd < best_cwp_cost) {
                        best_cwp_cost = tmp_rd;
                        best_cwp_idx = mbmi->cwp_idx;
                      }
                    }
                    if (tmp_rd < ref_best_rd) {
                      ref_best_rd = tmp_rd;
                      best_ref_mv_idx[0] = ref_mv_idx[0];
                      best_ref_mv_idx[1] = ref_mv_idx[1];
                    }
                  }
                  restore_dst_buf(xd, orig_dst, num_planes);
                }
              }
            }
          }
        }
      }
    }
  }

  if (best_rd == INT64_MAX) return INT64_MAX;

  // re-instate status of the best choice
  *rd_stats = best_rd_stats;
  *rd_stats_y = best_rd_stats_y;
  *rd_stats_uv = best_rd_stats_uv;
  *mbmi = best_mbmi;
  if (is_warp_mode(mbmi->motion_mode)) update_submi(xd, cm, best_submi, bsize);
  txfm_info->skip_txfm = best_xskip_txfm;
  assert(IMPLIES(mbmi->comp_group_idx == 1,
                 mbmi->interinter_comp.type != COMPOUND_AVERAGE));
  for (i = 0; i < num_planes; ++i) {
    const int num_blk_plane =
        (xd->plane[i].height * xd->plane[i].width) >> (2 * MI_SIZE_LOG2);
    memcpy(txfm_info->blk_skip[i], best_blk_skip[i],
           sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
  }
  av2_copy_array(xd->tx_type_map, best_tx_type_map, xd->height * xd->width);
  av2_copy_array(
      xd->cctx_type_map, best_cctx_type_map,
      (xd->plane[1].height * xd->plane[1].width) >> (2 * MI_SIZE_LOG2));

  rd_stats->rdcost = RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist);
  assert(av2_check_newmv_joint_nonzero(cm, x));

  return rd_stats->rdcost;
}

// Check if BV is valid
static INLINE int is_bv_valid(const FULLPEL_MV *full_mv, const AV2_COMMON *cm,
                              const MACROBLOCKD *xd, int mi_row, int mi_col,
                              BLOCK_SIZE bsize,
                              FULLPEL_MOTION_SEARCH_PARAMS fullms_params) {
  const MV dv = get_mv_from_fullmv(full_mv);
  if (!av2_is_fullmv_in_range(&fullms_params.mv_limits, *full_mv

                              ,
                              fullms_params.mv_cost_params.pb_mv_precision

                              ))
    return 0;
  if (!av2_is_dv_valid(dv, cm, xd, mi_row, mi_col, bsize, cm->mib_size_log2))
    return 0;
  return 1;
}

// Search for the best ref BV
int rd_pick_ref_bv_sub_pel(const AV2_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize,
                           FULLPEL_MOTION_SEARCH_PARAMS fullms_params_init,
                           int_mv *bv, int *cost) {
  const AV2_COMMON *const cm = &cpi->common;
  MACROBLOCKD *const xd = &x->e_mbd;
  MB_MODE_INFO *mbmi = xd->mi[0];
  MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
  const TileInfo *tile = &xd->tile;

  if (mbmi_ext->ref_mv_count[INTRA_FRAME] > 0) {
    int_mv best_bv;
    int best_intrabc_mode;
    int best_intrabc_drl_idx;
    int best_cost = INT_MAX;

    int intrabc_drl_idx;
    int_mv cur_ref_bv;
    int cur_cost = INT_MAX;

    best_bv.as_int = 0;
    best_intrabc_drl_idx = 0;
    best_intrabc_mode = 0;

    const int mi_row = xd->mi_row;
    const int mi_col = xd->mi_col;

    FULLPEL_MOTION_SEARCH_PARAMS fullms_params;

    for (intrabc_drl_idx = 0;
         intrabc_drl_idx < mbmi_ext->ref_mv_count[INTRA_FRAME];
         intrabc_drl_idx++) {
      if (intrabc_drl_idx > cm->features.max_bvp_drl_bits) break;
      cur_ref_bv = xd->ref_mv_stack[INTRA_FRAME][intrabc_drl_idx].this_mv;

      if (cur_ref_bv.as_int == 0 || cur_ref_bv.as_int == INVALID_MV) {
        cur_ref_bv.as_int = 0;
      }
      if (cur_ref_bv.as_int == 0) {
        av2_find_ref_dv(&cur_ref_bv, tile, cm->mib_size, mi_row);
      }

      mbmi_ext->ref_mv_stack[INTRA_FRAME][0].this_mv = cur_ref_bv;
      fullms_params = fullms_params_init;
      av2_init_ref_mv(&fullms_params.mv_cost_params, &cur_ref_bv.as_mv);
      av2_set_mv_search_range(&fullms_params.mv_limits, &cur_ref_bv.as_mv

                              ,
                              mbmi->pb_mv_precision

      );
      if (fullms_params.mv_limits.col_max < fullms_params.mv_limits.col_min ||
          fullms_params.mv_limits.row_max < fullms_params.mv_limits.row_min) {
        continue;
      }

      is_this_mv_precision_compliant(cur_ref_bv.as_mv, mbmi->pb_mv_precision);
      assert(mbmi->pb_mv_precision ==
             fullms_params.mv_cost_params.pb_mv_precision);

      SUBPEL_MOTION_SEARCH_PARAMS sub_pel_ms_params;
      av2_make_default_subpel_ms_params(&sub_pel_ms_params, cpi, x, bsize,
                                        &cur_ref_bv.as_mv,
                                        mbmi->pb_mv_precision, 1, NULL);
      sub_pel_ms_params.forced_stop =
          cpi->sf.mv_sf.simple_motion_subpel_force_stop;
      av2_set_subpel_mv_search_range(&sub_pel_ms_params.mv_limits,
                                     &fullms_params.mv_limits,
                                     &cur_ref_bv.as_mv, mbmi->pb_mv_precision);

      unsigned int not_used = 0;
      if (is_sub_pel_bv_valid(cur_ref_bv.as_mv, cm, xd, mi_row, mi_col, bsize,
                              &sub_pel_ms_params.mv_limits,
                              &fullms_params.mv_limits,
                              mbmi->pb_mv_precision)) {
        cur_cost =
            upsampled_pref_error(xd, cm, &cur_ref_bv.as_mv,
                                 &sub_pel_ms_params.var_params, &not_used);

        if (cur_cost != INT_MAX)
          cur_cost += av2_get_ref_bv_rate_cost(
              1, intrabc_drl_idx, cm->features.max_bvp_drl_bits, x,
              sub_pel_ms_params.mv_cost_params.mv_costs->errorperbit,
              mbmi_ext->ref_mv_count[INTRA_FRAME]);

        if (cur_cost < best_cost) {
          best_bv.as_mv = cur_ref_bv.as_mv;
          best_cost = cur_cost;
          best_intrabc_mode = 1;
          best_intrabc_drl_idx = intrabc_drl_idx;
        }

      }  // is_sub_pel_bv_valid
    }

    if (best_cost < INT_MAX) {
      bv->as_mv = best_bv.as_mv;
      mbmi->intrabc_drl_idx = best_intrabc_drl_idx;
      mbmi->intrabc_mode = best_intrabc_mode;
    } else {
      bv->as_int = 0;
      mbmi->intrabc_drl_idx = 0;
      mbmi->intrabc_mode = 0;
    }

    // set best ref_bv
    *cost = best_cost;
    cur_ref_bv = xd->ref_mv_stack[INTRA_FRAME][best_intrabc_drl_idx].this_mv;

    if (cur_ref_bv.as_int == 0 || cur_ref_bv.as_int == INVALID_MV) {
      cur_ref_bv.as_int = 0;
    }
    if (cur_ref_bv.as_int == 0) {
      av2_find_ref_dv(&cur_ref_bv, tile, cm->mib_size, mi_row);
    }
    is_this_mv_precision_compliant(cur_ref_bv.as_mv, mbmi->pb_mv_precision);
    mbmi_ext->ref_mv_stack[INTRA_FRAME][0].this_mv = cur_ref_bv;
    return 1;
  }
  return 0;
}

static int av2_pick_ref_bv_subpel(
    const AV2_COMP *cpi, BLOCK_SIZE bsize, const MV best_mv,
    int max_bvp_drl_bits, const FULLPEL_MOTION_SEARCH_PARAMS *fullms_params) {
  const AV2_COMMON *const cm = &cpi->common;
  MACROBLOCK *x = fullms_params->x;
  const MACROBLOCKD *const xd = fullms_params->xd;
  MB_MODE_INFO *const mbmi = xd->mi[0];
  int ref_bv_cnt = fullms_params->ref_bv_cnt;
  int cur_intrabc_drl_idx = 0;
  int_mv cur_ref_bv;
  cur_ref_bv.as_int = 0;
  int cur_ref_bv_cost = INT_MAX;
  int best_ref_bv_cost = INT_MAX;
  FULLPEL_MOTION_SEARCH_PARAMS ref_bv_ms_params = *fullms_params;

  for (cur_intrabc_drl_idx = 0; cur_intrabc_drl_idx < ref_bv_cnt;
       cur_intrabc_drl_idx++) {
    if (cur_intrabc_drl_idx > max_bvp_drl_bits) break;
    cur_ref_bv = xd->ref_mv_stack[INTRA_FRAME][cur_intrabc_drl_idx].this_mv;
    get_default_ref_bv(&cur_ref_bv, fullms_params);

    ref_bv_ms_params.mv_limits = fullms_params->mv_limits;
    av2_init_ref_mv(&ref_bv_ms_params.mv_cost_params, &cur_ref_bv.as_mv);

    // ref_mv value is changed. mv_limits need to recalculate
    av2_set_mv_search_range(&ref_bv_ms_params.mv_limits, &cur_ref_bv.as_mv,
                            mbmi->pb_mv_precision);

    SUBPEL_MOTION_SEARCH_PARAMS sub_pel_ms_params;
    av2_make_default_subpel_ms_params(&sub_pel_ms_params, cpi, x, bsize,
                                      &cur_ref_bv.as_mv, mbmi->pb_mv_precision,
                                      1, NULL);
    sub_pel_ms_params.forced_stop =
        cpi->sf.mv_sf.simple_motion_subpel_force_stop;
    av2_set_subpel_mv_search_range(&sub_pel_ms_params.mv_limits,
                                   &ref_bv_ms_params.mv_limits,
                                   &cur_ref_bv.as_mv, mbmi->pb_mv_precision);

    if (!is_sub_pel_bv_valid(best_mv, cm, xd, xd->mi_row, xd->mi_col, bsize,
                             &sub_pel_ms_params.mv_limits,
                             &ref_bv_ms_params.mv_limits,
                             mbmi->pb_mv_precision))
      continue;

    cur_ref_bv_cost =
        av2_get_ref_bv_rate_cost(
            0, cur_intrabc_drl_idx, max_bvp_drl_bits, x,
            sub_pel_ms_params.mv_cost_params.mv_costs->errorperbit,
            ref_bv_cnt) +
        av2_get_mv_err_cost(&best_mv, &sub_pel_ms_params.mv_cost_params);

    if (cur_ref_bv_cost < best_ref_bv_cost) {
      best_ref_bv_cost = cur_ref_bv_cost;
      mbmi->intrabc_mode = 0;
      mbmi->intrabc_drl_idx = cur_intrabc_drl_idx;
      mbmi->ref_bv = cur_ref_bv;
    }
  }

  if (best_ref_bv_cost != INT_MAX) {
    assert(mbmi->intrabc_drl_idx >= 0);
    return best_ref_bv_cost;
  }
  return INT_MAX;
}

/*!\brief Search for the best intrabc predictor
 *
 * \ingroup intra_mode_search
 * \callergraph
 * This function performs a motion search to find the best intrabc predictor.
 *
 * \returns Returns the best overall rdcost (including the non-intrabc modes
 * search before this function).
 */
static int64_t rd_pick_intrabc_mode_sb(const AV2_COMP *cpi, MACROBLOCK *x,
                                       PICK_MODE_CONTEXT *ctx,
                                       RD_STATS *rd_stats, BLOCK_SIZE bsize,
                                       int64_t best_rd) {
  const AV2_COMMON *const cm = &cpi->common;
  MACROBLOCKD *const xd = &x->e_mbd;
  if (!av2_allow_intrabc(cm, xd, bsize) || (xd->tree_type == CHROMA_PART) ||
      !cpi->oxcf.kf_cfg.enable_intrabc)
    return INT64_MAX;
  const int num_planes = av2_num_planes(cm);
  const TileInfo *tile = &xd->tile;
  MB_MODE_INFO *mbmi = xd->mi[0];
  TxfmSearchInfo *txfm_info = &x->txfm_search_info;

  set_default_max_mv_precision(mbmi, xd->sbi->sb_mv_precision);
  set_default_intraBC_bv_precision(cm, mbmi);
  const MvSubpelPrecision default_mv_precision = mbmi->pb_mv_precision;

  set_default_precision_set(cm, mbmi, bsize);
  set_most_probable_mv_precision(cm, mbmi, bsize);
  const int is_ibc_cost = 1;

  mbmi->bawp_flag[0] = 0;
  mbmi->bawp_flag[1] = 0;
  mbmi->refinemv_flag = 0;
  assert(xd->sbi->sb_active_mode == BRU_ACTIVE_SB);

  const int mi_row = xd->mi_row;
  const int mi_col = xd->mi_col;
  const int w = block_size_wide[bsize];
  const int h = block_size_high[bsize];
  const int sb_row = mi_row >> cm->mib_size_log2;
  const int sb_col = mi_col >> cm->mib_size_log2;

  MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
  MV_REFERENCE_FRAME ref_frame = INTRA_FRAME;
  mbmi->use_intrabc[xd->tree_type == CHROMA_PART] = 1;
  av2_find_mv_refs(cm, xd, mbmi, ref_frame, mbmi_ext->ref_mv_count,
                   xd->ref_mv_stack, xd->weight, NULL, mbmi_ext->global_mvs,
                   NULL, 0, NULL);
  mbmi->use_intrabc[xd->tree_type == CHROMA_PART] = 0;
  // TODO(Ravi): Populate mbmi_ext->ref_mv_stack[ref_frame][4] and
  // mbmi_ext->weight[ref_frame][4] inside av2_find_mv_refs.
  av2_copy_usable_ref_mv_stack_and_weight(xd, mbmi_ext, ref_frame);

  int_mv dv_ref = av2_find_best_ref_mv_from_stack(mbmi_ext, mbmi, ref_frame,
                                                  mbmi->pb_mv_precision);

  dv_ref.as_int = dv_ref.as_int == INVALID_MV ? 0 : dv_ref.as_int;
  if (mbmi_ext->ref_mv_count[INTRA_FRAME] == 0) {
    dv_ref.as_int = 0;
  }
  if (dv_ref.as_int == 0) {
    av2_find_ref_dv(&dv_ref, tile, cm->mib_size, mi_row);
  }

  assert(is_this_mv_precision_compliant(dv_ref.as_mv, mbmi->pb_mv_precision));

  mbmi_ext->ref_mv_stack[INTRA_FRAME][0].this_mv = dv_ref;

  struct buf_2d yv12_mb[MAX_MB_PLANE];
  av2_setup_pred_block(xd, yv12_mb, xd->cur_buf, NULL, NULL, num_planes);
  for (int i = 0; i < num_planes; ++i) {
    xd->plane[i].pre[0] = yv12_mb[i];
  }

  enum IntrabcMotionDirection {
    IBC_MOTION_ABOVE,
    IBC_MOTION_LEFT,
    IBC_MOTION_DIRECTIONS
  };

  mbmi->morph_pred = 0;
  MB_MODE_INFO best_mbmi = *mbmi;
  RD_STATS best_rdstats = *rd_stats;
  uint8_t best_blk_skip[MAX_MB_PLANE][MAX_MIB_SIZE * MAX_MIB_SIZE] = { 0 };
  TX_TYPE best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE];
  av2_copy_array(best_tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
  CctxType best_cctx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE];
  av2_copy_array(best_cctx_type_map, xd->cctx_type_map,
                 ctx->num_4x4_blk_chroma);

  FULLPEL_MOTION_SEARCH_PARAMS fullms_params;
  const search_site_config *lookahead_search_sites =
      cpi->mv_search_params.search_site_cfg[SS_CFG_LOOKAHEAD];
  // TODO(chiyotsai@google.com): Change the resolution here to MV_SUBPEL_NONE
  // in a separate commit.

  av2_make_default_fullpel_ms_params(&fullms_params, cpi, x, bsize,
                                     &dv_ref.as_mv, mbmi->pb_mv_precision,
                                     is_ibc_cost, lookahead_search_sites,
                                     /*fine_search_interval=*/0);

  fullms_params.is_intra_mode = 1;
  fullms_params.xd = xd;
  fullms_params.cm = cm;
  fullms_params.mib_size_log2 = cm->mib_size_log2;
  fullms_params.mi_col = mi_col;
  fullms_params.mi_row = mi_row;
  fullms_params.x = x;
  fullms_params.cm = cm;
  fullms_params.ref_bv_cnt = mbmi_ext->ref_mv_count[INTRA_FRAME];
  mbmi->intrabc_mode = 0;
  mbmi->intrabc_drl_idx = 0;
  mbmi->ref_bv.as_int = 0;
  mbmi->warp_ref_idx = 0;
  mbmi->max_num_warp_candidates = 0;
  mbmi->warpmv_with_mvd_flag = 0;
  mbmi->motion_mode = SIMPLE_TRANSLATION;
  mbmi->six_param_warp_model_flag = 0;

  mbmi->warp_precision_idx = 0;
  mbmi->warp_inter_intra = 0;
  mbmi->use_amvd = 0;
  const int ibc_loop_start =
      (frame_is_intra_only(cm) && cm->features.allow_global_intrabc) ? 0 : 1;
  const int ibc_loop_end = (cm->features.allow_local_intrabc) ? 2 : 1;
  for (int ibc_loop = ibc_loop_start; ibc_loop < ibc_loop_end; ++ibc_loop) {
    for (enum IntrabcMotionDirection dir = IBC_MOTION_ABOVE;
         dir < IBC_MOTION_DIRECTIONS; ++dir) {
      set_default_intraBC_bv_precision(cm, mbmi);
      if (frame_is_intra_only(cm) && cm->features.allow_global_intrabc &&
          ibc_loop == 0) {
        switch (dir) {
          case IBC_MOTION_ABOVE:
            fullms_params.mv_limits.col_min =
                (tile->mi_col_start - mi_col) * MI_SIZE;
            fullms_params.mv_limits.col_max =
                (tile->mi_col_end - mi_col) * MI_SIZE - w;
            fullms_params.mv_limits.row_min =
                (tile->mi_row_start - mi_row) * MI_SIZE;
            fullms_params.mv_limits.row_max =
                (sb_row * cm->mib_size - mi_row) * MI_SIZE - h;
            break;
          case IBC_MOTION_LEFT:
            fullms_params.mv_limits.col_min =
                (tile->mi_col_start - mi_col) * MI_SIZE;
            fullms_params.mv_limits.col_max =
                (sb_col * cm->mib_size - mi_col) * MI_SIZE - w;
            //  TODO(aconverse@google.com): Minimize the overlap between above
            //  and left areas.
            fullms_params.mv_limits.row_min =
                (tile->mi_row_start - mi_row) * MI_SIZE;
            int bottom_coded_mi_edge =
                AVMMIN((sb_row + 1) * cm->mib_size, tile->mi_row_end);
            fullms_params.mv_limits.row_max =
                (bottom_coded_mi_edge - mi_row) * MI_SIZE - h;
            break;
          default: assert(0);
        }
      }
      if (cm->features.allow_local_intrabc && ibc_loop == 1) {
        // num_left_sb=round_up(num_samples_in_IBC_ref_buffer/num_samples_in_superblock)
        const int num_left_sb =
            (INTRABC_BUFFER_NUM * (1 << (2 * INTRABC_BUFFER_SIZE_LOG2)) +
             (1 << 2 * (cm->mib_size_log2 + MI_SIZE_LOG2)) - 1) >>
            (2 * (cm->mib_size_log2 + MI_SIZE_LOG2));
        int num_left_active_sb = num_left_sb;
        if (cm->mib_size_log2 == mi_size_wide_log2[BLOCK_64X64] &&
            cm->bru.enabled) {
          // check SB activity, once inactive, stop
          num_left_active_sb = 1;
          while (num_left_active_sb < num_left_sb) {
            if (!bru_is_sb_available(
                    cm, (sb_col - num_left_active_sb - 1) * cm->mib_size,
                    sb_row * cm->mib_size)) {
              break;
            }
            num_left_active_sb++;
          }
        }
        int left_coded_mi_edge = AVMMAX(
            (sb_col - num_left_active_sb) * cm->mib_size, tile->mi_col_start);
        int right_coded_mi_edge =
            AVMMIN((sb_col + 1) * cm->mib_size, tile->mi_col_end);
        int up_coded_mi_edge =
            AVMMAX((sb_row)*cm->mib_size, tile->mi_row_start);
        int bottom_coded_mi_edge =
            AVMMIN((sb_row + 1) * cm->mib_size, tile->mi_row_end);

        switch (dir) {
          case IBC_MOTION_ABOVE:
            fullms_params.mv_limits.col_min =
                (left_coded_mi_edge - mi_col) * MI_SIZE;
            fullms_params.mv_limits.col_max =
                (right_coded_mi_edge - mi_col) * MI_SIZE - w;
            fullms_params.mv_limits.row_min =
                (up_coded_mi_edge - mi_row) * MI_SIZE;
            fullms_params.mv_limits.row_max = -h;
            break;
          case IBC_MOTION_LEFT:
            fullms_params.mv_limits.col_min =
                (left_coded_mi_edge - mi_col) * MI_SIZE;
            fullms_params.mv_limits.col_max = -w;
            fullms_params.mv_limits.row_min =
                (up_coded_mi_edge - mi_row) * MI_SIZE;
            fullms_params.mv_limits.row_max =
                (bottom_coded_mi_edge - mi_row) * MI_SIZE - h;
            break;
          default: assert(0);
        }
      }

      assert(fullms_params.mv_limits.col_min >=
             fullms_params.mv_limits.col_min);
      assert(fullms_params.mv_limits.col_max <=
             fullms_params.mv_limits.col_max);
      assert(fullms_params.mv_limits.row_min >=
             fullms_params.mv_limits.row_min);
      assert(fullms_params.mv_limits.row_max <=
             fullms_params.mv_limits.row_max);

      FULLPEL_MOTION_SEARCH_PARAMS fullms_params_init = fullms_params;
      int best_ref_bv_cost = INT_MAX;
      int_mv best_bv;
      int_mv best_ref_bv;
      best_bv.as_int = 0;
      best_ref_bv.as_int = dv_ref.as_int;

      if (rd_pick_ref_bv_sub_pel(cpi, x, bsize, fullms_params_init, &best_bv,
                                 &best_ref_bv_cost)) {
        fullms_params = fullms_params_init;
        best_ref_bv = mbmi_ext->ref_mv_stack[INTRA_FRAME][0].this_mv;
        av2_init_ref_mv(&fullms_params.mv_cost_params, &best_ref_bv.as_mv);
        av2_set_mv_search_range(&fullms_params.mv_limits, &best_ref_bv.as_mv

                                ,
                                mbmi->pb_mv_precision

        );
        dv_ref.as_mv = best_ref_bv.as_mv;
        // dv_ref is changed, so it is required to re-initialize mv cost
        // parameters
        init_mv_cost_params(&fullms_params.mv_cost_params, &x->mv_costs, 0,
                            &dv_ref.as_mv, mbmi->pb_mv_precision, is_ibc_cost

        );
      }
      mbmi->ref_bv = dv_ref;
      int best_intrabc_drl_idx = mbmi->intrabc_drl_idx;
      int best_intrabc_mode = mbmi->intrabc_mode;

      // Do we need to call it again?
      av2_set_mv_search_range(&fullms_params.mv_limits, &dv_ref.as_mv

                              ,
                              mbmi->pb_mv_precision

      );

      if (fullms_params.mv_limits.col_max < fullms_params.mv_limits.col_min ||
          fullms_params.mv_limits.row_max < fullms_params.mv_limits.row_min) {
        continue;
      }

      const int step_param = cpi->mv_search_params.mv_step_param;
      const FULLPEL_MV start_mv = get_fullmv_from_mv(&dv_ref.as_mv);
      IntraBCHashInfo *intrabc_hash_info = &x->intrabc_hash_info;
      int_mv best_mv, best_hash_mv;

      int bestsme = av2_full_pixel_search(start_mv, &fullms_params, step_param,
                                          NULL, &best_mv.as_fullmv, NULL);
      int_mv best_subpel_mv;
      FULLPEL_MV best_full_pel_mv = best_mv.as_fullmv;
      best_subpel_mv.as_mv = get_mv_from_fullmv(&best_mv.as_fullmv);
      int best_dist =
          bestsme - av2_get_mv_err_cost(&best_subpel_mv.as_mv,
                                        &fullms_params.mv_cost_params);

      const int use_subpel_search =
          bestsme < INT_MAX &&
          !cpi->common.features.cur_frame_force_integer_mv &&
          mbmi->pb_mv_precision > MV_PRECISION_ONE_PEL &&
          is_bv_valid(&best_full_pel_mv, cm, xd, mi_row, mi_col, bsize,
                      fullms_params);
      if (use_subpel_search) {
        int not_used = 0;

        SUBPEL_MOTION_SEARCH_PARAMS sub_pel_ms_params;
        av2_make_default_subpel_ms_params(&sub_pel_ms_params, cpi, x, bsize,
                                          &dv_ref.as_mv, mbmi->pb_mv_precision,
                                          1, NULL);
        // TODO(yunqing): integrate this into
        // av2_make_default_subpel_ms_params().
        sub_pel_ms_params.forced_stop =
            cpi->sf.mv_sf.simple_motion_subpel_force_stop;
        av2_set_subpel_mv_search_range(&sub_pel_ms_params.mv_limits,
                                       &fullms_params.mv_limits, &dv_ref.as_mv,
                                       mbmi->pb_mv_precision);

        MV subpel_start_mv = best_subpel_mv.as_mv;
        assert(av2_is_subpelmv_in_range(&sub_pel_ms_params.mv_limits,
                                        subpel_start_mv));

        bestsme = av2_find_best_sub_pixel_intraBC_dv(
            xd, cm, &sub_pel_ms_params, subpel_start_mv, &best_subpel_mv.as_mv,
            &not_used, &x->pred_sse[COMPACT_INDEX0_NRS(ref_frame)],
            &fullms_params.mv_limits, bsize);
        best_dist =
            bestsme - av2_get_mv_err_cost(&best_subpel_mv.as_mv,
                                          &sub_pel_ms_params.mv_cost_params);
        best_full_pel_mv = get_fullmv_from_mv(&best_subpel_mv.as_mv);
      }

      if (bestsme != INT_MAX && is_bv_valid(&best_full_pel_mv, cm, xd, mi_row,
                                            mi_col, bsize, fullms_params)) {
        int cur_ref_bv_cost = bestsme;
        int cur_intrabc_mode = 0;
        int cur_intrabc_drl_idx = 0;
        int_mv cur_ref_bv;
        cur_ref_bv.as_mv = dv_ref.as_mv;
        int_mv cur_bv;
        cur_bv.as_mv = best_subpel_mv.as_mv;
        int cur_dist = best_dist;
        assert(cur_dist >= 0);

        int cur_rate = av2_pick_ref_bv_subpel(cpi, bsize, best_subpel_mv.as_mv,
                                              cm->features.max_bvp_drl_bits,
                                              &fullms_params);

        if (cur_rate != INT_MAX) {
          cur_ref_bv_cost = cur_dist + cur_rate;
          cur_intrabc_mode = mbmi->intrabc_mode;
          assert(cur_intrabc_mode == 0);
          cur_intrabc_drl_idx = mbmi->intrabc_drl_idx;
          cur_ref_bv = mbmi->ref_bv;
        }

        if (cur_ref_bv_cost < best_ref_bv_cost) {
          best_ref_bv_cost = cur_ref_bv_cost;
          best_intrabc_mode = cur_intrabc_mode;
          best_intrabc_drl_idx = cur_intrabc_drl_idx;
          best_ref_bv = cur_ref_bv;
          best_bv.as_mv = cur_bv.as_mv;
        }
      }

      const int hashsme = av2_intrabc_hash_search(
          cpi, xd, &fullms_params, intrabc_hash_info, &best_hash_mv.as_fullmv);

      if (hashsme != INT_MAX &&
          is_bv_valid(&best_hash_mv.as_fullmv, cm, xd, mi_row, mi_col, bsize,
                      fullms_params)) {
        int cur_ref_bv_cost = hashsme;

        int cur_intrabc_mode = mbmi->intrabc_mode;
        int cur_intrabc_drl_idx = mbmi->intrabc_drl_idx;

        int_mv cur_ref_bv;
        cur_ref_bv.as_mv = mbmi->ref_bv.as_mv;

        int_mv cur_bv;
        cur_bv.as_mv = get_mv_from_fullmv(&best_hash_mv.as_fullmv);

        if (cur_ref_bv_cost < best_ref_bv_cost) {
          best_ref_bv_cost = cur_ref_bv_cost;
          best_intrabc_mode = cur_intrabc_mode;
          best_intrabc_drl_idx = cur_intrabc_drl_idx;
          best_ref_bv = cur_ref_bv;
          best_bv.as_mv = cur_bv.as_mv;
        }
      }

      if (best_ref_bv_cost == INT_MAX) continue;

      mbmi->intrabc_mode = best_intrabc_mode;
      mbmi->intrabc_drl_idx = best_intrabc_drl_idx;
      mbmi->ref_bv = best_ref_bv;

      MV dv = best_bv.as_mv;
      dv_ref.as_mv = best_ref_bv.as_mv;

      is_this_mv_precision_compliant(dv, mbmi->pb_mv_precision);
      memset(&mbmi->palette_mode_info, 0, sizeof(mbmi->palette_mode_info));
      mbmi->use_intra_dip = 0;
      mbmi->use_intrabc[xd->tree_type == CHROMA_PART] = 1;
      assert(xd->tree_type != CHROMA_PART);
      mbmi->angle_delta[PLANE_TYPE_Y] = 0;
      mbmi->angle_delta[PLANE_TYPE_UV] = 0;

      mbmi->use_dpcm_y = 0;
      mbmi->dpcm_mode_y = 0;
      mbmi->use_dpcm_uv = 0;
      mbmi->dpcm_mode_uv = 0;

      mbmi->fsc_mode[PLANE_TYPE_Y] = 0;
      mbmi->fsc_mode[PLANE_TYPE_UV] = 0;
      mbmi->mode = DC_PRED;
      mbmi->uv_mode = UV_DC_PRED;
      mbmi->motion_mode = SIMPLE_TRANSLATION;
      mbmi->mv[0].as_mv = dv;
      mbmi->interp_fltr = BILINEAR;
      mbmi->skip_txfm[xd->tree_type == CHROMA_PART] = 0;
      mbmi->cwp_idx = CWP_EQUAL;

      mbmi->warp_ref_idx = 0;
      mbmi->max_num_warp_candidates = 0;
      mbmi->warpmv_with_mvd_flag = 0;
      mbmi->motion_mode = SIMPLE_TRANSLATION;
      mbmi->six_param_warp_model_flag = 0;
      mbmi->warp_precision_idx = 0;
      mbmi->warp_inter_intra = 0;

      assert(is_this_mv_precision_compliant(mbmi->mv[0].as_mv,
                                            mbmi->pb_mv_precision));

      const int_mv default_dv_ref = mbmi->ref_bv;
      assert(mbmi->pb_mv_precision == default_mv_precision);
      const int is_pb_mv_precision_active =
          is_intraBC_bv_precision_active(cm, mbmi->intrabc_mode);
      const int_mv default_best_mv = mbmi->mv[0];
      const FullMvLimits default_full_mv_limits = fullms_params.mv_limits;
      for (int precision_index = av2_intraBc_precision_sets.num_precisions - 1;
           precision_index >= 0; precision_index--) {
        // When precision is OFF only first loop will be evaluated with default
        // MV precision
        if (!is_pb_mv_precision_active) {
          if (precision_index != av2_intraBc_precision_sets.num_precisions - 1)
            continue;
          mbmi->pb_mv_precision = default_mv_precision;
        } else {
          mbmi->pb_mv_precision =
              av2_intraBc_precision_sets.precision[precision_index];
        }

        assert(IMPLIES(!is_pb_mv_precision_active,
                       mbmi->pb_mv_precision == default_mv_precision));

        // Do motion search refinement if the target precision is not default
        // precision
        if (is_pb_mv_precision_active &&
            (mbmi->pb_mv_precision != default_mv_precision)) {
          int not_used = 0;

          SUBPEL_MOTION_SEARCH_PARAMS sub_pel_ms_params;
          av2_make_default_subpel_ms_params(&sub_pel_ms_params, cpi, x, bsize,
                                            &default_dv_ref.as_mv,
                                            mbmi->pb_mv_precision, 1, NULL);
          // TODO(yunqing): integrate this into
          // av2_make_default_subpel_ms_params().
          sub_pel_ms_params.forced_stop =
              cpi->sf.mv_sf.simple_motion_subpel_force_stop;
          av2_set_subpel_mv_search_range(
              &sub_pel_ms_params.mv_limits, &default_full_mv_limits,
              &default_dv_ref.as_mv, mbmi->pb_mv_precision);

          MV subpel_start_mv = default_best_mv.as_mv;
          lower_mv_precision(&subpel_start_mv, mbmi->pb_mv_precision);
          int_mv best_low_prec_mv;
          int this_sme = av2_refine_low_precision_intraBC_dv(
              xd, cm, &sub_pel_ms_params, subpel_start_mv,
              &best_low_prec_mv.as_mv, &not_used,
              &x->pred_sse[COMPACT_INDEX0_NRS(ref_frame)],
              &fullms_params.mv_limits, bsize);

          // valid MV is not found
          if (this_sme == INT_MAX) {
            continue;
          }

          assert(av2_is_subpelmv_in_range(&sub_pel_ms_params.mv_limits,
                                          best_low_prec_mv.as_mv));
          mbmi->mv[0].as_mv = best_low_prec_mv.as_mv;
          assert(default_dv_ref.as_int == mbmi->ref_bv.as_int);
        }
        assert(is_this_mv_precision_compliant(mbmi->mv[0].as_mv,
                                              mbmi->pb_mv_precision));

        const IntraBCMvCosts *const dv_costs = &x->dv_costs;

        int rate_mv = 0;
        if (!mbmi->intrabc_mode)
          rate_mv += av2_intrabc_mv_bit_cost(&dv, &default_dv_ref.as_mv,
                                             dv_costs, MV_COST_WEIGHT_SUB,
                                             mbmi->pb_mv_precision);

        if (is_pb_mv_precision_active) {
          int index = av2_intraBc_precision_to_index[mbmi->pb_mv_precision];
          assert(index < av2_intraBc_precision_sets.num_precisions);
          rate_mv += x->mode_costs.intrabc_bv_precision_cost[0][index];
        }

        const int intrabc_ctx = get_intrabc_ctx(xd);
        int rate_mode = x->mode_costs.intrabc_cost[intrabc_ctx][1];
        rate_mode += x->mode_costs.intrabc_mode_cost[mbmi->intrabc_mode];
        rate_mode += av2_get_intrabc_drl_idx_cost(
            cm->features.max_bvp_drl_bits + 1, mbmi->intrabc_drl_idx);

        int allow_morph_pred = av2_allow_intrabc_morph_pred(cm);
        int num_modes_to_search = 1 + allow_morph_pred;

        if (num_modes_to_search > 1 &&
            !is_bv_valid_for_morph(mbmi->mv[0].as_mv, cm, xd, mi_row, mi_col,
                                   bsize)) {
          num_modes_to_search = 1;
        }
        for (int morph_idx = 0; morph_idx < num_modes_to_search; ++morph_idx) {
          if (morph_idx && !allow_morph_pred) continue;
          mbmi->morph_pred = morph_idx;
          const int morph_pred_ctx = get_morph_pred_ctx(xd);
          const int morph_pred_cost =
              !allow_morph_pred
                  ? 0
                  : x->mode_costs.morph_pred_cost[morph_pred_ctx][morph_idx];
          if (morph_idx == 0) {
            // Build intra bc predictor for yuv planes as baseline.
            av2_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize,
                                          0, av2_num_planes(cm) - 1);
          } else {
            // Build the y predictor using a linear model.
            const bool valid =
                av2_build_morph_pred(cm, xd, bsize, mi_row, mi_col);
            if (!valid) break;
          }
          RD_STATS rd_stats_yuv, rd_stats_y, rd_stats_uv;
          if (!av2_txfm_search(
                  cpi, x, bsize, &rd_stats_yuv, &rd_stats_y, &rd_stats_uv,
                  rate_mode + rate_mv + morph_pred_cost, 1, INT64_MAX))
            continue;
          rd_stats_yuv.rdcost =
              RDCOST(x->rdmult, rd_stats_yuv.rate, rd_stats_yuv.dist);
          if (rd_stats_yuv.rdcost < best_rd) {
            best_rd = rd_stats_yuv.rdcost;
            best_mbmi = *mbmi;
            best_rdstats = rd_stats_yuv;
            for (int i = 0; i < num_planes; ++i) {
              const int num_blk_plane =
                  (xd->plane[i].height * xd->plane[i].width) >>
                  (2 * MI_SIZE_LOG2);
              memcpy(best_blk_skip[i], txfm_info->blk_skip[i],
                     sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
            }
            av2_copy_array(best_tx_type_map, xd->tx_type_map,
                           xd->height * xd->width);
            av2_copy_array(best_cctx_type_map, xd->cctx_type_map,
                           (xd->plane[1].height * xd->plane[1].width) >>
                               (2 * MI_SIZE_LOG2));
          }
        }
      }  //(int index = av2_intraBc_precision_sets.num_precisions - 1; index >
         // 0;
         // index--)
    }
  }
  *mbmi = best_mbmi;
  if (mbmi->use_intrabc[xd->tree_type == CHROMA_PART]) {
    mbmi_ext->ref_mv_stack[INTRA_FRAME][0].this_mv = mbmi->ref_bv;
  } else {
    mbmi_ext->ref_mv_stack[INTRA_FRAME][0].this_mv.as_int = 0;
  }

  *rd_stats = best_rdstats;
  for (int i = 0; i < num_planes; ++i) {
    const int num_blk_plane =
        (xd->plane[i].height * xd->plane[i].width) >> (2 * MI_SIZE_LOG2);
    memcpy(txfm_info->blk_skip[i], best_blk_skip[i],
           sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
  }
  av2_copy_array(xd->tx_type_map, best_tx_type_map, ctx->num_4x4_blk);
  av2_copy_array(xd->cctx_type_map, best_cctx_type_map,
                 ctx->num_4x4_blk_chroma);
#if CONFIG_RD_DEBUG
  mbmi->rd_stats = *rd_stats;
#endif
  assert(av2_check_newmv_joint_nonzero(cm, x));
  return best_rd;
}

// TODO(chiyotsai@google.com): We are using struct $struct_name instead of
// their typedef here because Doxygen doesn't know about the typedefs yet. So
// using the typedef will prevent doxygen from finding this function and
// generating the callgraph. Once documents for AV2_COMP and MACROBLOCK are
// added to doxygen, we can revert back to using the typedefs.
void av2_rd_pick_intra_mode_sb(const struct AV2_COMP *cpi, ThreadData *td,
                               struct macroblock *x, struct RD_STATS *rd_cost,
                               BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx,
                               int64_t best_rd) {
  const AV2_COMMON *const cm = &cpi->common;
  MACROBLOCKD *const xd = &x->e_mbd;
  MB_MODE_INFO *const mbmi = xd->mi[0];
  const int num_planes = av2_num_planes(cm);
  TxfmSearchInfo *txfm_info = &x->txfm_search_info;
  int rate_y = 0, rate_uv = 0, rate_y_tokenonly = 0, rate_uv_tokenonly = 0;
  int y_skip_txfm = 0, uv_skip_txfm = 0;
  int64_t dist_y = 0, dist_uv = 0;

  ctx->rd_stats.skip_txfm = 0;
  mbmi->ref_frame[0] = INTRA_FRAME;
  mbmi->ref_frame[1] = NONE_FRAME;
  mbmi->refinemv_flag = 0;
  mbmi->use_intrabc[xd->tree_type == CHROMA_PART] = 0;
  mbmi->local_rest_type = 1;
  mbmi->local_ccso_blk_flag = 1;
  mbmi->local_gdf_mode = 1;
  if (xd->tree_type != CHROMA_PART) {
    mbmi->mv[0].as_int = 0;
    mbmi->skip_mode = 0;
  }
  const int64_t intra_yrd =
      (xd->tree_type == CHROMA_PART)
          ? 0
          : av2_rd_pick_intra_sby_mode(cpi, td, x, &rate_y, &rate_y_tokenonly,
                                       &dist_y, &y_skip_txfm, bsize, best_rd,
                                       ctx);

  // Initialize default mode evaluation params
  set_mode_eval_params(cpi, x, DEFAULT_EVAL);

  if (intra_yrd < best_rd) {
    // Search intra modes for uv planes if needed
    if (num_planes > 1 && xd->tree_type != LUMA_PART) {
      // Set up the tx variables for reproducing the y predictions in case we
      // need it for chroma-from-luma.
      if (xd->is_chroma_ref && store_cfl_required_rdo(cm, x)) {
        memcpy(txfm_info->blk_skip[AVM_PLANE_Y], ctx->blk_skip[AVM_PLANE_Y],
               sizeof(*txfm_info->blk_skip[AVM_PLANE_Y]) * ctx->num_4x4_blk);
        av2_copy_array(xd->tx_type_map, ctx->tx_type_map, ctx->num_4x4_blk);
      }
      const TX_SIZE max_uv_tx_size = av2_get_tx_size(AVM_PLANE_U, xd);
      av2_rd_pick_intra_sbuv_mode(cpi, x, &rate_uv, &rate_uv_tokenonly,
                                  &dist_uv, &uv_skip_txfm, ctx, bsize,
                                  max_uv_tx_size, NULL /*ModeRDInfoUV*/
      );
      av2_copy_array(ctx->cctx_type_map, xd->cctx_type_map,
                     ctx->num_4x4_blk_chroma);
    }

    // Intra block is always coded as non-skip
    rd_cost->rate = rate_y + rate_uv;
    rd_cost->dist = dist_y + dist_uv;
    rd_cost->rdcost = RDCOST(x->rdmult, rd_cost->rate, rd_cost->dist);
    rd_cost->skip_txfm = 0;
  } else {
    rd_cost->rate = INT_MAX;
  }

  if (rd_cost->rate != INT_MAX && rd_cost->rdcost < best_rd)
    best_rd = rd_cost->rdcost;
  int all_intra = (cpi->oxcf.kf_cfg.key_freq_max == 0) &&
                  (cpi->oxcf.kf_cfg.key_freq_min == 0);
  int nz = 0;
  if (all_intra) {
    struct macroblock_plane *const p = &x->plane[0];
    tran_low_t *const qcoeff = p->qcoeff + BLOCK_OFFSET(0);
    for (int i = 0; i < av2_get_max_eob(mbmi->tx_size); ++i) {
      if (qcoeff[i] > 0) nz++;
    }
  }
  int skip_ibc_search =
      !cm->features.allow_screen_content_tools && all_intra && (nz <= 0);
  if (!skip_ibc_search) {
    if (rd_pick_intrabc_mode_sb(cpi, x, ctx, rd_cost, bsize, best_rd) <
        best_rd) {
      ctx->rd_stats.skip_txfm = mbmi->skip_txfm[xd->tree_type == CHROMA_PART];
      for (int i = 0; i < num_planes; ++i) {
        const int num_blk_plane =
            (i == AVM_PLANE_Y) ? ctx->num_4x4_blk : ctx->num_4x4_blk_chroma;
        memcpy(ctx->blk_skip[i], txfm_info->blk_skip[i],
               sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
      }
      assert(rd_cost->rate != INT_MAX);
    }
  }
  if (rd_cost->rate == INT_MAX) return;

  ctx->mic = *xd->mi[0];
  if (xd->tree_type != CHROMA_PART)
    av2_copy_mbmi_ext_to_mbmi_ext_frame(
        &ctx->mbmi_ext_best, x->mbmi_ext, xd->mi[0], mbmi->skip_mode,
        av2_ref_frame_type(xd->mi[0]->ref_frame));
  av2_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
}

/*!\brief Search for the best skip mode
 *
 * \ingroup inter_mode_search
 *
 * This function performs a rate distortion search to find the best skip mode
 * and compare the existing best mode
 *
 * Nothing is returned. The best mode is saved within the funtion
 */
static AVM_INLINE void rd_pick_skip_mode(
    InterModeSearchState *search_state, const AV2_COMP *cpi, MACROBLOCK *x,
    BLOCK_SIZE bsize, struct buf_2d yv12_mb[SINGLE_REF_FRAMES][MAX_MB_PLANE],
    PICK_MODE_CONTEXT *ctx, RD_STATS *best_rd_cost) {
  const AV2_COMMON *const cm = &cpi->common;
  const SkipModeInfo *const skip_mode_info = &cm->current_frame.skip_mode_info;
  const int num_planes = av2_num_planes(cm);
  MACROBLOCKD *const xd = &x->e_mbd;
  MB_MODE_INFO *const mbmi = xd->mi[0];
  MB_MODE_INFO_EXT *mbmi_ext = x->mbmi_ext;
  TxfmSearchInfo *txfm_info = &x->txfm_search_info;
  const TxfmSearchParams *txfm_params = &x->txfm_search_params;

  if (skip_mode_info->ref_frame_idx_0 == INVALID_IDX ||
      skip_mode_info->ref_frame_idx_1 == INVALID_IDX) {
    return;
  }

  MV_REFERENCE_FRAME ref_frames[2] = { skip_mode_info->ref_frame_idx_0,
                                       skip_mode_info->ref_frame_idx_1 };
  set_skip_mode_ref_frame(cm, xd, ref_frames);
  const MV_REFERENCE_FRAME ref_frame = ref_frames[0];
  const MV_REFERENCE_FRAME second_ref_frame = ref_frames[1];

  if (cm->bru.enabled) {
    if (ref_frame == cm->bru.update_ref_idx ||
        second_ref_frame == cm->bru.update_ref_idx) {
      return;
    }
  }

  assert(second_ref_frame != NONE_FRAME);
  const PREDICTION_MODE this_mode = NEAR_NEARMV;

  if ((!cpi->oxcf.ref_frm_cfg.enable_onesided_comp ||
       cpi->sf.inter_sf.disable_onesided_comp) &&
      cpi->all_one_sided_refs) {
    return;
  }

  mbmi->mode = this_mode;
  mbmi->ref_mv_idx[0] = 0;
  mbmi->ref_mv_idx[1] = 0;
  mbmi->uv_mode = UV_DC_PRED;
  mbmi->ref_frame[0] = ref_frame;
  mbmi->ref_frame[1] = second_ref_frame;
  mbmi->cwp_idx = CWP_EQUAL;
  mbmi->use_intrabc[xd->tree_type == CHROMA_PART] = 0;
  mbmi->warp_ref_idx = 0;
  mbmi->max_num_warp_candidates = 0;
  mbmi->warpmv_with_mvd_flag = 0;
  mbmi->six_param_warp_model_flag = 0;

  mbmi->warp_precision_idx = 0;
  mbmi->warp_inter_intra = 0;

  mbmi->refinemv_flag = 0;
  mbmi->morph_pred = 0;

  assert(this_mode == NEAR_NEARMV);

  mbmi->fsc_mode[xd->tree_type == CHROMA_PART] = 0;
  mbmi->bawp_flag[0] = 0;
  mbmi->bawp_flag[1] = 0;
  mbmi->use_intra_dip = 0;
  mbmi->interintra_mode = (INTERINTRA_MODE)(II_DC_PRED - 1);
  mbmi->comp_group_idx = 0;
  mbmi->interinter_comp.type = COMPOUND_AVERAGE;
  mbmi->motion_mode = SIMPLE_TRANSLATION;
  mbmi->ref_mv_idx[0] = 0;
  mbmi->ref_mv_idx[1] = 0;
  mbmi->skip_mode = mbmi->skip_txfm[xd->tree_type == CHROMA_PART] = 1;

  set_default_max_mv_precision(mbmi, xd->sbi->sb_mv_precision);
  set_mv_precision(mbmi, mbmi->max_mv_precision);  // initialize to max
  set_default_precision_set(cm, mbmi, mbmi->sb_type[PLANE_TYPE_Y]);
  set_most_probable_mv_precision(cm, mbmi, mbmi->sb_type[PLANE_TYPE_Y]);

  mbmi->warp_ref_idx = 0;
  mbmi->max_num_warp_candidates = 0;
  mbmi->warpmv_with_mvd_flag = 0;
  mbmi->six_param_warp_model_flag = 0;

  mbmi->warp_precision_idx = 0;
  mbmi->warp_inter_intra = 0;

  set_default_interp_filters(mbmi, cm, xd, cm->features.interp_filter);

  const int mi_row = xd->mi_row;
  const int mi_col = xd->mi_col;

  // Compare the use of skip_mode with the best intra/inter mode obtained.
  const int skip_mode_ctx = av2_get_skip_mode_context(xd);

  const ModeCosts *mode_costs = &x->mode_costs;
  // Account for non-skip mode rate in total rd stats
  if (best_rd_cost->rate != INT_MAX) {
    best_rd_cost->rate += mode_costs->skip_mode_cost[skip_mode_ctx][0];
    av2_rd_cost_update(x->rdmult, best_rd_cost);
  }
  search_state->best_rd = best_rd_cost->rdcost;

  for (int8_t rf_idx = 0; rf_idx < cpi->common.ref_frames_info.num_total_refs;
       ++rf_idx) {
    if (get_ref_frame_yv12_buf(cm, rf_idx) == NULL) continue;
    setup_buffer_ref_mvs_inter(cpi, x, rf_idx, bsize, yv12_mb);
  }

  const uint8_t ref_frame_type = av2_ref_frame_type(mbmi->ref_frame);

  av2_find_mv_refs(cm, xd, mbmi, ref_frame_type, mbmi_ext->ref_mv_count,
                   xd->ref_mv_stack, xd->weight, NULL, mbmi_ext->global_mvs,
                   NULL, 0, NULL);

  // TODO(Ravi): Populate mbmi_ext->ref_mv_stack[ref_frame][4] and

  // mbmi_ext->weight[ref_frame][4] inside av2_find_mv_refs.
  av2_copy_usable_ref_mv_stack_and_weight(xd, mbmi_ext, ref_frame_type);

  mbmi->mode = this_mode;

  // loop of ref_mv_idx
  assert(!has_second_drl(mbmi));
  int ref_set = get_drl_refmv_count(cm->features.max_drl_bits, x,
                                    mbmi->ref_frame, this_mode, 0);

  for (int ref_mv_idx = 0; ref_mv_idx < ref_set; ref_mv_idx++) {
    mbmi->ref_mv_idx[0] = ref_mv_idx;

    if (cm->bru.enabled) {
      if ((mbmi->ref_frame[0] != INVALID_IDX) &&
          mbmi->ref_frame[0] == cm->bru.update_ref_idx) {
        continue;
      }
      if ((mbmi->ref_frame[1] != INVALID_IDX) &&
          mbmi->ref_frame[1] == cm->bru.update_ref_idx) {
        continue;
      }
    }
    // Infer the index of compound weighted prediction from DRL list
    mbmi->cwp_idx =
        xd->skip_mvp_candidate_list.ref_mv_stack[mbmi->ref_mv_idx[0]].cwp_idx;

    mbmi->refinemv_flag =
        (mbmi->cwp_idx == CWP_EQUAL && is_refinemv_allowed_skip_mode(cm, mbmi))
            ? 1
            : 0;

    if (!build_cur_mv(mbmi->mv, mbmi->mode, cm, x, 0)) {
      assert(av2_check_newmv_joint_nonzero(cm, x));
      continue;
    }

    set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
    for (int i = 0; i < num_planes; i++) {
      xd->plane[i].pre[0] = yv12_mb[COMPACT_INDEX0_NRS(mbmi->ref_frame[0])][i];
      xd->plane[i].pre[1] = yv12_mb[COMPACT_INDEX0_NRS(mbmi->ref_frame[1])][i];
    }

    BUFFER_SET orig_dst;
    for (int i = 0; i < num_planes; i++) {
      orig_dst.plane[i] = xd->plane[i].dst.buf;
      orig_dst.stride[i] = xd->plane[i].dst.stride;
    }

    av2_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst, bsize, 0,
                                  av2_num_planes(cm) - 1);

    RD_STATS skip_mode_rd_stats, skip_mode_rd_stats_y, skip_mode_rd_stats_uv;
    av2_invalid_rd_stats(&skip_mode_rd_stats);
    av2_invalid_rd_stats(&skip_mode_rd_stats_y);
    av2_invalid_rd_stats(&skip_mode_rd_stats_uv);

    skip_mode_rd_stats.rate = mode_costs->skip_mode_cost[skip_mode_ctx][1];

    // add ref_mv_idx rate
    // MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
    // add ref_mv_idx rate
    const int drl_cost =
        get_skip_drl_cost(cpi->common.features.max_drl_bits, mbmi, x);

    skip_mode_rd_stats.rate += drl_cost;

    // Do transform search
    if (av2_txfm_search(cpi, x, bsize, &skip_mode_rd_stats,
                        &skip_mode_rd_stats_y, &skip_mode_rd_stats_uv,
                        skip_mode_rd_stats.rate, 1, search_state->best_rd)) {
      skip_mode_rd_stats.rdcost =
          RDCOST(x->rdmult, skip_mode_rd_stats.rate, skip_mode_rd_stats.dist);
    } else {
      av2_invalid_rd_stats(&skip_mode_rd_stats);
      av2_invalid_rd_stats(&skip_mode_rd_stats_y);
      av2_invalid_rd_stats(&skip_mode_rd_stats_uv);
    }

    if (skip_mode_rd_stats.rdcost < search_state->best_rd &&
        (!xd->lossless[mbmi->segment_id] || skip_mode_rd_stats.dist == 0)) {
      assert(mbmi->skip_txfm[xd->tree_type == CHROMA_PART] ==
             skip_mode_rd_stats.skip_txfm);
      search_state->best_mbmode.skip_mode = 1;
      search_state->best_mbmode = *mbmi;
      search_state->best_mbmode.skip_txfm[xd->tree_type == CHROMA_PART] =
          mbmi->skip_txfm[xd->tree_type == CHROMA_PART];

      search_state->best_mbmode.fsc_mode[xd->tree_type == CHROMA_PART] = 0;

      search_state->best_mbmode.mode = NEAR_NEARMV;
      search_state->best_mbmode.ref_frame[0] = mbmi->ref_frame[0];
      search_state->best_mbmode.ref_frame[1] = mbmi->ref_frame[1];
      search_state->best_mbmode.mv[0].as_int = mbmi->mv[0].as_int;
      search_state->best_mbmode.mv[1].as_int = mbmi->mv[1].as_int;
      search_state->best_mbmode.ref_mv_idx[0] = mbmi->ref_mv_idx[0];
      search_state->best_mbmode.ref_mv_idx[1] = mbmi->ref_mv_idx[1];

      // Set up tx_size related variables for skip-specific loop filtering.
      if (search_state->best_mbmode.skip_txfm[xd->tree_type == CHROMA_PART]) {
        search_state->best_mbmode.tx_size =
            block_signals_txsize(bsize)
                ? tx_size_from_tx_mode(bsize, txfm_params->tx_mode_search_type)
                : max_txsize_rect_lookup[bsize];

        x->txfm_search_info.skip_txfm = 1;
        search_state->best_mode_skippable = 1;
        search_state->best_skip2 = 1;
        search_state->best_rate_y =
            x->mode_costs.skip_txfm_cost[av2_get_skip_txfm_context(xd)][1];

        restore_dst_buf(xd, orig_dst, num_planes);
      } else {
        x->txfm_search_info.skip_txfm = 0;
        for (int i = 0; i < num_planes; ++i) {
          const int num_blk_plane =
              (i == AVM_PLANE_Y) ? ctx->num_4x4_blk : ctx->num_4x4_blk_chroma;
          memcpy(ctx->blk_skip[i], txfm_info->blk_skip[i],
                 sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
        }
        av2_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
        av2_copy_array(ctx->cctx_type_map, xd->cctx_type_map,
                       ctx->num_4x4_blk_chroma);
        search_state->best_mode_skippable = 0;
        search_state->best_skip2 = 0;
        search_state->best_rate_y =
            skip_mode_rd_stats_y.rate +
            x->mode_costs.skip_txfm_cost[av2_get_skip_txfm_context(xd)][0];
        search_state->best_rate_uv = skip_mode_rd_stats_uv.rate;
      }

      // Set up color-related variables for skip mode.
      search_state->best_mbmode.uv_mode = UV_DC_PRED;
      search_state->best_mbmode.palette_mode_info.palette_size[0] = 0;
      search_state->best_mbmode.palette_mode_info.palette_size[1] = 0;

      search_state->best_mbmode.comp_group_idx = 0;
      search_state->best_mbmode.interinter_comp.type = COMPOUND_AVERAGE;
      search_state->best_mbmode.motion_mode = SIMPLE_TRANSLATION;

      search_state->best_mbmode.interintra_mode =
          (INTERINTRA_MODE)(II_DC_PRED - 1);
      search_state->best_mbmode.use_intra_dip = 0;

      set_default_interp_filters(&search_state->best_mbmode, cm, xd,
                                 cm->features.interp_filter);
      search_state->best_mbmode.refinemv_flag = mbmi->refinemv_flag;

      // Update rd_cost
      best_rd_cost->rate = skip_mode_rd_stats.rate;
      best_rd_cost->dist = best_rd_cost->sse = skip_mode_rd_stats.dist;
      best_rd_cost->rdcost = skip_mode_rd_stats.rdcost;

      search_state->best_rd = best_rd_cost->rdcost;
    }
  }
  assert(av2_check_newmv_joint_nonzero(cm, x));
}

// Get winner mode stats of given mode index
static AVM_INLINE MB_MODE_INFO *get_winner_mode_stats(
    MACROBLOCK *x, MB_MODE_INFO *best_mbmode, RD_STATS *best_rd_cost,
    int best_rate_y, int best_rate_uv, RD_STATS **winner_rd_cost,
    int *winner_rate_y, int *winner_rate_uv, PREDICTION_MODE *winner_mode,
    MULTI_WINNER_MODE_TYPE multi_winner_mode_type, int mode_idx) {
  MB_MODE_INFO *winner_mbmi;
  if (multi_winner_mode_type) {
    assert(mode_idx >= 0 && mode_idx < x->winner_mode_count);
    WinnerModeStats *winner_mode_stat = &x->winner_mode_stats[mode_idx];
    winner_mbmi = &winner_mode_stat->mbmi;

    *winner_rd_cost = &winner_mode_stat->rd_cost;
    *winner_rate_y = winner_mode_stat->rate_y;
    *winner_rate_uv = winner_mode_stat->rate_uv;
    *winner_mode = winner_mode_stat->mode;
  } else {
    winner_mbmi = best_mbmode;
    *winner_rd_cost = best_rd_cost;
    *winner_rate_y = best_rate_y;
    *winner_rate_uv = best_rate_uv;
    *winner_mode = best_mbmode->mode;
  }
  return winner_mbmi;
}

// speed feature: fast intra/inter transform type search
// Used for speed >= 3
// When this speed feature is on, in rd mode search, only DCT is used.
// After the mode is determined, this function is called, to select
// transform types and get accurate rdcost.
static AVM_INLINE void refine_winner_mode_tx(
    const AV2_COMP *cpi, MACROBLOCK *x, RD_STATS *rd_cost, BLOCK_SIZE bsize,
    PICK_MODE_CONTEXT *ctx, MB_MODE_INFO *best_mbmode,
    struct buf_2d yv12_mb[SINGLE_REF_FRAMES][MAX_MB_PLANE], int best_rate_y,
    int best_rate_uv, int *best_skip2, int winner_mode_count) {
  const AV2_COMMON *const cm = &cpi->common;
  MACROBLOCKD *const xd = &x->e_mbd;
  MB_MODE_INFO *const mbmi = xd->mi[0];
  TxfmSearchParams *txfm_params = &x->txfm_search_params;
  TxfmSearchInfo *txfm_info = &x->txfm_search_info;
  int64_t best_rd;
  const int num_planes = av2_num_planes(cm);

  if (!is_winner_mode_processing_enabled(cpi, best_mbmode, best_mbmode->mode))
    return;

  // Set params for winner mode evaluation
  set_mode_eval_params(cpi, x, WINNER_MODE_EVAL);

  // No best mode identified so far
  if (best_mbmode->mode == MODE_INVALID) return;

  best_rd = RDCOST(x->rdmult, rd_cost->rate, rd_cost->dist);
  for (int mode_idx = 0; mode_idx < winner_mode_count; mode_idx++) {
    RD_STATS *winner_rd_stats = NULL;
    int winner_rate_y = 0, winner_rate_uv = 0;
    PREDICTION_MODE winner_mode = 0;

    // TODO(any): Combine best mode and multi-winner mode processing paths
    // Get winner mode stats for current mode index
    MB_MODE_INFO *winner_mbmi = get_winner_mode_stats(
        x, best_mbmode, rd_cost, best_rate_y, best_rate_uv, &winner_rd_stats,
        &winner_rate_y, &winner_rate_uv, &winner_mode,
        cpi->sf.winner_mode_sf.multi_winner_mode_type, mode_idx);

    if (xd->lossless[winner_mbmi->segment_id] == 0 &&
        winner_mode != MODE_INVALID &&
        is_winner_mode_processing_enabled(cpi, winner_mbmi,
                                          winner_mbmi->mode)) {
      RD_STATS rd_stats = *winner_rd_stats;
      int skip_blk = 0;
      RD_STATS rd_stats_y, rd_stats_uv;
      const int skip_ctx = av2_get_skip_txfm_context(xd);

      *mbmi = *winner_mbmi;

      set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);

      // Select prediction reference frames.
      for (int i = 0; i < num_planes; i++) {
        xd->plane[i].pre[0] =
            yv12_mb[COMPACT_INDEX0_NRS(mbmi->ref_frame[0])][i];
        if (has_second_ref(mbmi))
          xd->plane[i].pre[1] =
              yv12_mb[COMPACT_INDEX0_NRS(mbmi->ref_frame[1])][i];
      }

      if (is_inter_mode(mbmi->mode)) {
        const int mi_row = xd->mi_row;
        const int mi_col = xd->mi_col;
        av2_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, 0,
                                      av2_num_planes(cm) - 1);

        av2_subtract_plane(x, bsize, 0, cm->width, cm->height);
        if (txfm_params->tx_mode_search_type == TX_MODE_SELECT &&
            !xd->lossless[mbmi->segment_id]) {
          av2_pick_recursive_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize, 1,
                                              INT64_MAX);
          assert(rd_stats_y.rate != INT_MAX);
        } else {
          av2_pick_uniform_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize,
                                            INT64_MAX);
          for (int i = 0; i < xd->height * xd->width; ++i)
            set_blk_skip(txfm_info->blk_skip[0], i, rd_stats_y.skip_txfm);
        }
      } else {
        av2_pick_uniform_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize,
                                          INT64_MAX);
      }
      // Occasionally TX search will be unable to find a best mode decision.
      // This case needs to be skipped to avoid integer overflows.
      if (rd_stats_y.rate == INT_MAX) continue;

      if (num_planes > 1) {
        av2_txfm_uvrd(cpi, x, &rd_stats_uv, INT64_MAX);
      } else {
        av2_init_rd_stats(&rd_stats_uv);
      }

      const ModeCosts *mode_costs = &x->mode_costs;
      if (is_inter_mode(mbmi->mode) &&
          RDCOST(x->rdmult,
                 mode_costs->skip_txfm_cost[skip_ctx][0] + rd_stats_y.rate +
                     rd_stats_uv.rate,
                 (rd_stats_y.dist + rd_stats_uv.dist)) >
              RDCOST(x->rdmult, mode_costs->skip_txfm_cost[skip_ctx][1],
                     (rd_stats_y.sse + rd_stats_uv.sse))) {
        skip_blk = 1;
        rd_stats_y.rate = mode_costs->skip_txfm_cost[skip_ctx][1];
        rd_stats_uv.rate = 0;
        rd_stats_y.dist = rd_stats_y.sse;
        rd_stats_uv.dist = rd_stats_uv.sse;
      } else {
        skip_blk = 0;
        rd_stats_y.rate += is_inter_block(mbmi, xd->tree_type)
                               ? mode_costs->skip_txfm_cost[skip_ctx][0]
                               : 0;
      }
      int this_rate = rd_stats.rate + rd_stats_y.rate + rd_stats_uv.rate -
                      winner_rate_y - winner_rate_uv;
      int64_t this_rd =
          RDCOST(x->rdmult, this_rate, (rd_stats_y.dist + rd_stats_uv.dist));
      if (best_rd > this_rd) {
        *best_mbmode = *mbmi;
        for (int i = 0; i < num_planes; ++i) {
          const int num_blk_plane =
              (i == AVM_PLANE_Y) ? ctx->num_4x4_blk : ctx->num_4x4_blk_chroma;
          av2_copy_array(ctx->blk_skip[i], txfm_info->blk_skip[i],
                         num_blk_plane);
        }
        av2_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
        av2_copy_array(ctx->cctx_type_map, xd->cctx_type_map,
                       ctx->num_4x4_blk_chroma);
        rd_cost->rate = this_rate;
        rd_cost->dist = rd_stats_y.dist + rd_stats_uv.dist;
        rd_cost->sse = rd_stats_y.sse + rd_stats_uv.sse;
        rd_cost->rdcost = this_rd;
        best_rd = this_rd;
        *best_skip2 = skip_blk;
      }
    }
  }
}

/*!\cond */
typedef struct {
  // Mask for each reference frame, specifying which prediction modes to NOT
  // try during search.
  uint32_t pred_modes[MAX_COMPOUND_REF_INDEX];
  // If ref_combo[i][j + 1] is true, do NOT try prediction using combination
  // of reference frames (i, j). Indexing with 'j + 1' is due to the fact that
  // 2nd reference can be -1 (INVALID_FRAME). NOTE: indexing for the reference
  // has the order the INTER references followed by INTRA
  bool ref_combo[MAX_COMPOUND_REF_INDEX][MAX_COMPOUND_REF_INDEX + 1];
} mode_skip_mask_t;
/*!\endcond */

// Update 'ref_combo' mask to disable given 'ref' in single and compound
// modes.
static AVM_INLINE void disable_reference(
    MV_REFERENCE_FRAME ref,
    bool ref_combo[MAX_COMPOUND_REF_INDEX][MAX_COMPOUND_REF_INDEX + 1]) {
  for (MV_REFERENCE_FRAME ref2 = NONE_FRAME; ref2 < MAX_COMPOUND_REF_INDEX;
       ++ref2) {
    ref_combo[COMPACT_INDEX0_NRS(ref)][ref2 + 1] = true;
  }
}

// Disable rank 2 (indexed by 1) to rank 7 references.
static AVM_INLINE void disable_inter_references_except_top(
    bool ref_combo[MAX_COMPOUND_REF_INDEX][MAX_COMPOUND_REF_INDEX + 1]) {
  for (MV_REFERENCE_FRAME ref = 1; ref < MAX_COMPOUND_REF_INDEX; ++ref)
    disable_reference(ref, ref_combo);
}

// Define single and compound reference combinations allowed in
// "enable_reduced_reference_set" speed feature.
static const MV_REFERENCE_FRAME reduced_ref_combos[][2] = {
  { 0, NONE_FRAME },  { 1, NONE_FRAME },  { 2, NONE_FRAME },
  { 3, NONE_FRAME },  { 4, NONE_FRAME },  { INTRA_FRAME, NONE_FRAME },
  { 0, INTRA_FRAME }, { 1, INTRA_FRAME }, { 2, INTRA_FRAME },
  { 3, INTRA_FRAME }, { 0, 1 },           { 0, 2 },
  { 0, 3 },           { 1, 2 },           { 1, 3 },
  { 2, 3 },
};

typedef enum { REF_SET_FULL, REF_SET_REDUCED } REF_SET;

static AVM_INLINE void default_skip_mask(mode_skip_mask_t *mask,
                                         REF_SET ref_set) {
  if (ref_set == REF_SET_FULL) {
    // Everything available by default.
    memset(mask, 0, sizeof(*mask));
  } else {
    // All modes available by default.
    memset(mask->pred_modes, 0, sizeof(mask->pred_modes));
    // All references disabled first.
    bool *mask_ref_combo = &mask->ref_combo[0][0];
    for (int k = 0; k < MAX_COMPOUND_REF_INDEX * (MAX_COMPOUND_REF_INDEX + 1);
         k++)
      mask_ref_combo[k] = true;

    const MV_REFERENCE_FRAME(*ref_set_combos)[2];
    int num_ref_combos;

    // Then enable reduced set of references explicitly.
    switch (ref_set) {
      case REF_SET_REDUCED:
        ref_set_combos = reduced_ref_combos;
        num_ref_combos =
            (int)sizeof(reduced_ref_combos) / sizeof(reduced_ref_combos[0]);
        break;
      default: assert(0); num_ref_combos = 0;
    }

    for (int i = 0; i < num_ref_combos; ++i) {
      const MV_REFERENCE_FRAME *const this_combo = ref_set_combos[i];
      mask->ref_combo[COMPACT_INDEX0_NRS(this_combo[0])]
                     [COMPACT_INDEX0_NRS(this_combo[1]) + 1] = false;
    }
  }
}

static AVM_INLINE void init_mode_skip_mask(mode_skip_mask_t *mask,
                                           const AV2_COMP *cpi, MACROBLOCK *x,
                                           BLOCK_SIZE bsize) {
  const AV2_COMMON *const cm = &cpi->common;
  const SPEED_FEATURES *const sf = &cpi->sf;
  REF_SET ref_set = REF_SET_FULL;

  if (cpi->oxcf.ref_frm_cfg.enable_reduced_reference_set)
    ref_set = REF_SET_REDUCED;

  default_skip_mask(mask, ref_set);

  int min_pred_mv_sad = INT_MAX;
  MV_REFERENCE_FRAME ref_frame;
  for (ref_frame = 0; ref_frame < cm->ref_frames_info.num_total_refs;
       ++ref_frame)
    min_pred_mv_sad = AVMMIN(min_pred_mv_sad, x->pred_mv_sad[ref_frame]);

  min_pred_mv_sad = AVMMIN(min_pred_mv_sad, x->pred_mv_sad[TIP_FRAME_INDEX]);

  for (ref_frame = 0; ref_frame < cm->ref_frames_info.num_total_refs;
       ++ref_frame) {
    if (!(cm->ref_frame_flags & (1 << ref_frame))) {
      // Skip checking missing reference in both single and compound reference
      // modes.
      disable_reference(ref_frame, mask->ref_combo);
    } else {
      // Skip fixed mv modes for poor references
      if ((x->pred_mv_sad[ref_frame] >> 2) > min_pred_mv_sad) {
        mask->pred_modes[ref_frame] |= INTER_NEAR_GLOBAL;
      }
    }
  }

  if (cpi->rc.is_src_frame_alt_ref) {
    if (sf->inter_sf.alt_ref_search_fp) {
      mask->pred_modes[0] = 0;
      disable_inter_references_except_top(mask->ref_combo);
      disable_reference(INTRA_FRAME, mask->ref_combo);
    }
  }

  if (sf->inter_sf.alt_ref_search_fp) {
    if (!cm->immediate_output_picture && x->best_pred_mv_sad < INT_MAX) {
      int sad_thresh = x->best_pred_mv_sad + (x->best_pred_mv_sad >> 3);
      // Conservatively skip the modes w.r.t. BWDREF, ALTREF2 and ALTREF, if
      // those are past frames
      for (ref_frame = 4; ref_frame < INTER_REFS_PER_FRAME; ref_frame++) {
        if (cpi->ref_frame_dist_info.ref_relative_dist[ref_frame] < 0)
          if (x->pred_mv_sad[ref_frame] > sad_thresh)
            mask->pred_modes[ref_frame] |= INTER_ALL;
      }
    }
  }

  if (bsize > sf->part_sf.max_intra_bsize) {
    disable_reference(INTRA_FRAME, mask->ref_combo);
  }

  mask->pred_modes[INTRA_FRAME_INDEX] |=
      ~(sf->intra_sf.intra_y_mode_mask[max_txsize_lookup[bsize]]);
}

static AVM_INLINE int prune_ref_frame(const AV2_COMP *cpi, const MACROBLOCK *x,
                                      const MV_REFERENCE_FRAME ref_frame) {
  const AV2_COMMON *const cm = &cpi->common;
  MV_REFERENCE_FRAME rf[2];
  av2_set_ref_frame(rf, ref_frame);
  const int comp_pred = is_inter_ref_frame(rf[1]);
  if (comp_pred) {
    if (!cpi->oxcf.ref_frm_cfg.enable_onesided_comp ||
        cpi->sf.inter_sf.disable_onesided_comp) {
      // Disable all compound references
      if (cpi->all_one_sided_refs) return 1;
      // If both references are on the same side prune
      if (get_dir_rank(cm, rf[0], NULL) == get_dir_rank(cm, rf[1], NULL))
        return 1;
    } else if (cpi->sf.inter_sf.selective_ref_frame >= 2) {
      // One sided compound is used only when all reference frames are
      // one-sided.
      if (!cpi->all_one_sided_refs &&
          get_dir_rank(cm, rf[0], NULL) == get_dir_rank(cm, rf[1], NULL))
        return 1;
    }
  }

  if (prune_ref_by_selective_ref_frame(cpi, x, rf)) {
    return 1;
  }

  return 0;
}

static AVM_INLINE int is_ref_frame_used_by_compound_ref(
    int ref_frame, uint64_t skip_ref_frame_mask) {
  for (int r = INTER_REFS_PER_FRAME; r < INTRA_FRAME; ++r) {
    if (!(skip_ref_frame_mask & ((uint64_t)1 << r))) {
      MV_REFERENCE_FRAME rf[2];
      av2_set_ref_frame(rf, r);
      if (rf[0] == ref_frame || rf[1] == ref_frame) {
        return 1;
      }
    }
  }
  return 0;
}

static AVM_INLINE int is_ref_frame_used_in_cache(MV_REFERENCE_FRAME ref_frame,
                                                 const MB_MODE_INFO *mi_cache) {
  if (!mi_cache) {
    return 0;
  }
  if (ref_frame < MAX_COMPOUND_REF_INDEX) {
    return (ref_frame == mi_cache->ref_frame[0] ||
            ref_frame == mi_cache->ref_frame[1]);
  }

  // if we are here, then the current mode is compound.
  MV_REFERENCE_FRAME cached_ref_type = av2_ref_frame_type(mi_cache->ref_frame);
  return ref_frame == cached_ref_type;
}

// Please add/modify parameter setting in this function, making it consistent
// and easy to read and maintain.
static AVM_INLINE void set_params_rd_pick_inter_mode(
    const AV2_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize,
    mode_skip_mask_t *mode_skip_mask, uint64_t skip_ref_frame_mask,
    unsigned int *ref_costs_single,
    unsigned int (*ref_costs_comp)[MAX_COMPOUND_REF_INDEX],
    struct buf_2d yv12_mb[SINGLE_REF_FRAMES][MAX_MB_PLANE]) {
  const AV2_COMMON *const cm = &cpi->common;
  MACROBLOCKD *const xd = &x->e_mbd;
  MB_MODE_INFO *const mbmi = xd->mi[0];
  MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
  unsigned char segment_id = mbmi->segment_id;

  av2_collect_neighbors_ref_counts(xd);
  estimate_ref_frame_costs(cm, xd, &x->mode_costs, segment_id, ref_costs_single,
                           ref_costs_comp);

  x->best_pred_mv_sad = INT_MAX;
  MV_REFERENCE_FRAME ref_frame;
  for (ref_frame = 0; ref_frame < INTER_REFS_PER_FRAME; ++ref_frame) {
    x->mbmi_ext->mode_context[ref_frame] = 0;
    mbmi_ext->ref_mv_count[ref_frame] = UINT8_MAX;
    if ((cm->ref_frame_flags & (1 << ref_frame))) {
      x->pred_mv_sad[ref_frame] = INT_MAX;
      if (mbmi->partition != PARTITION_NONE &&
          mbmi->partition != PARTITION_SPLIT) {
        if (skip_ref_frame_mask & ((uint64_t)1 << ref_frame) &&
            !is_ref_frame_used_by_compound_ref(ref_frame,
                                               skip_ref_frame_mask) &&
            !(should_reuse_mode(x, REUSE_INTER_MODE_IN_INTERFRAME_FLAG) &&
              is_ref_frame_used_in_cache(ref_frame, x->inter_mode_cache[0]))) {
          continue;
        }
      }
      assert(get_ref_frame_yv12_buf(cm, ref_frame) != NULL);
      setup_buffer_ref_mvs_inter(cpi, x, ref_frame, bsize, yv12_mb);
    }
  }

  x->mbmi_ext->mode_context[TIP_FRAME] = 0;
  mbmi_ext->ref_mv_count[TIP_FRAME] = UINT8_MAX;
  x->pred_mv_sad[TIP_FRAME_INDEX] = INT_MAX;
  if (cm->seq_params.enable_tip && cm->features.tip_frame_mode) {
    assert(get_ref_frame_yv12_buf(cm, TIP_FRAME) != NULL);
    setup_buffer_ref_mvs_inter(cpi, x, TIP_FRAME, bsize, yv12_mb);
  }

  if (is_comp_ref_allowed(bsize)) {
    // No second reference on RT ref set, so no need to initialize
    for (; ref_frame < MODE_CTX_REF_FRAMES - 1; ++ref_frame) {
      x->mbmi_ext->mode_context[ref_frame] = 0;
      mbmi_ext->ref_mv_count[ref_frame] = UINT8_MAX;
      MV_REFERENCE_FRAME rf[2];
      av2_set_ref_frame(rf, ref_frame);
      if (rf[0] >= cm->ref_frames_info.num_total_refs ||
          rf[1] >= cm->ref_frames_info.num_total_refs)
        continue;
      if (!((cm->ref_frame_flags & (1 << rf[0])) &&
            (cm->ref_frame_flags & (1 << rf[1])))) {
        continue;
      }

      if (mbmi->partition != PARTITION_NONE &&
          mbmi->partition != PARTITION_SPLIT) {
        if (skip_ref_frame_mask & ((uint64_t)1 << ref_frame) &&
            !(should_reuse_mode(x, REUSE_INTER_MODE_IN_INTERFRAME_FLAG) &&
              is_ref_frame_used_in_cache(ref_frame, x->inter_mode_cache[0]))) {
          continue;
        }
      }
      // Ref mv list population is not required, when compound references are
      // pruned.
      if (prune_ref_frame(cpi, x, ref_frame)) continue;
      av2_find_mv_refs(
          cm, xd, mbmi, ref_frame, mbmi_ext->ref_mv_count, xd->ref_mv_stack,
          xd->weight, NULL, mbmi_ext->global_mvs, xd->warp_param_stack,
          ref_frame < INTER_REFS_PER_FRAME ? MAX_WARP_REF_CANDIDATES : 0,
          xd->valid_num_warp_candidates);

      av2_find_mode_ctx(cm, xd, mbmi_ext->mode_context, ref_frame);

      // TODO(Ravi): Populate mbmi_ext->ref_mv_stack[ref_frame][4] and
      // mbmi_ext->weight[ref_frame][4] inside av2_find_mv_refs.
      av2_copy_usable_ref_mv_stack_and_weight(xd, mbmi_ext, ref_frame);
    }
  }

  init_mode_skip_mask(mode_skip_mask, cpi, x, bsize);

  // Set params for mode evaluation
  set_mode_eval_params(cpi, x, MODE_EVAL);

  x->comp_rd_stats_idx = 0;
}

static AVM_INLINE void init_intra_mode_search_state(
    IntraModeSearchState *intra_search_state) {
  intra_search_state->skip_intra_modes = 0;
  intra_search_state->best_intra_mode = DC_PRED;
  intra_search_state->best_mrl_index = 0;
  intra_search_state->dir_mode_skip_mask_ready = 0;
  av2_zero(intra_search_state->directional_mode_skip_mask);
  intra_search_state->rate_uv_intra = INT_MAX;
  av2_zero(intra_search_state->pmi_uv);
  for (int i = 0; i < REFERENCE_MODES; ++i)
    intra_search_state->best_pred_rd[i] = INT64_MAX;
}

static AVM_INLINE void init_inter_mode_search_state(
    InterModeSearchState *search_state, const AV2_COMP *cpi,
    const MACROBLOCK *x, BLOCK_SIZE bsize, int64_t best_rd_so_far) {
  init_intra_mode_search_state(&search_state->intra_search_state);

  search_state->best_rd = best_rd_so_far;
  search_state->best_skip_rd[0] = INT64_MAX;
  search_state->best_skip_rd[1] = INT64_MAX;

  av2_zero(search_state->best_mbmode);
  memset(search_state->best_submb, 0,
         MAX_MIB_SIZE * MAX_MIB_SIZE * sizeof(*search_state->best_submb));

  search_state->best_mbmode.mode = MODE_INVALID;

  search_state->best_rate_y = INT_MAX;

  search_state->best_rate_uv = INT_MAX;

  search_state->best_mode_skippable = 0;

  search_state->best_skip2 = 0;

  const MACROBLOCKD *const xd = &x->e_mbd;
  const MB_MODE_INFO *const mbmi = xd->mi[0];
  const unsigned char segment_id = mbmi->segment_id;

  memset(search_state->dist_refs, -1, sizeof(search_state->dist_refs));
  memset(search_state->dist_order_refs, -1,
         sizeof(search_state->dist_order_refs));

  const int *const rd_threshes = cpi->rd.threshes[segment_id][bsize];
  for (int i = 0; i < MB_MODE_COUNT; ++i)
    search_state->mode_threshold[i] =
        ((int64_t)rd_threshes[i] * x->thresh_freq_fact[bsize][i]) >>
        RD_THRESH_FAC_FRAC_BITS;

  search_state->best_intra_rd = INT64_MAX;

  av2_zero(search_state->single_newmv);
  av2_zero(search_state->single_newmv_rate);
  av2_zero(search_state->single_newmv_valid);

  for (int i = 0; i < MB_MODE_COUNT; ++i) {
    for (int j = 0; j < MAX_REF_MV_SEARCH; ++j) {
      for (int ref_frame = 0; ref_frame < SINGLE_REF_FRAMES; ++ref_frame) {
        search_state->modelled_rd[i][j][ref_frame] = INT64_MAX;
        search_state->simple_rd[i][j][ref_frame] = INT64_MAX;
      }
    }
  }

  for (int dir = 0; dir < 2; ++dir) {
    for (int mode = 0; mode < SINGLE_INTER_MODE_NUM; ++mode) {
      for (int ref_frame = 0; ref_frame < SINGLE_REF_FRAMES; ++ref_frame) {
        SingleInterModeState *state;

        state = &search_state->single_state[dir][mode][ref_frame];
        state->ref_frame = NONE_FRAME;
        state->rd = INT64_MAX;

        state = &search_state->single_state_modelled[dir][mode][ref_frame];
        state->ref_frame = NONE_FRAME;
        state->rd = INT64_MAX;
      }
    }
  }
  for (int dir = 0; dir < 2; ++dir) {
    for (int mode = 0; mode < SINGLE_INTER_MODE_NUM; ++mode) {
      for (int ref_frame = 0; ref_frame < SINGLE_REF_FRAMES; ++ref_frame) {
        search_state->single_rd_order[dir][mode][ref_frame] = NONE_FRAME;
      }
    }
  }

  for (int ref_frame = 0; ref_frame < SINGLE_REF_FRAMES; ++ref_frame) {
    search_state->best_single_rd[ref_frame] = INT64_MAX;
    search_state->best_single_mode[ref_frame] = MB_MODE_COUNT;
  }
  av2_zero(search_state->single_state_cnt);
  av2_zero(search_state->single_state_modelled_cnt);
}

static bool mask_says_skip(const mode_skip_mask_t *mode_skip_mask,
                           const MV_REFERENCE_FRAME *ref_frame,
                           const PREDICTION_MODE this_mode) {
  if (is_tip_ref_frame(ref_frame[0])) return false;

  if (mode_skip_mask->pred_modes[COMPACT_INDEX0_NRS(ref_frame[0])] &
      ((int64_t)1 << this_mode)) {
    return true;
  }

  return mode_skip_mask->ref_combo[COMPACT_INDEX0_NRS(ref_frame[0])]
                                  [COMPACT_INDEX0_NRS(ref_frame[1]) + 1];
}

static int inter_mode_compatible_skip(const AV2_COMP *cpi, const MACROBLOCK *x,
                                      BLOCK_SIZE bsize,
                                      PREDICTION_MODE curr_mode,
                                      const MV_REFERENCE_FRAME *ref_frames) {
  const int comp_pred = is_inter_ref_frame(ref_frames[1]);
  if (comp_pred) {
    if (!is_comp_ref_allowed(bsize)) return 1;
    if (!(cpi->common.ref_frame_flags & (1 << ref_frames[1]))) return 1;

    const AV2_COMMON *const cm = &cpi->common;
    if (frame_is_intra_only(cm)) return 1;

    const CurrentFrame *const current_frame = &cm->current_frame;
    if (current_frame->reference_mode == SINGLE_REFERENCE) return 1;

    (void)x;
  }

  if (is_inter_ref_frame(ref_frames[0]) && ref_frames[1] == INTRA_FRAME) {
    // Mode must be compatible
    if (!is_interintra_allowed_bsize(bsize)) return 1;
    if (!is_interintra_allowed_mode(curr_mode)) return 1;
  }

  return 0;
}

static uint64_t fetch_picked_ref_frames_mask(const MACROBLOCK *const x,
                                             BLOCK_SIZE bsize, int mib_size) {
  const int sb_size_mask = mib_size - 1;
  const MACROBLOCKD *const xd = &x->e_mbd;
  const int mi_row = xd->mi_row;
  const int mi_col = xd->mi_col;
  const int mi_row_in_sb = mi_row & sb_size_mask;
  const int mi_col_in_sb = mi_col & sb_size_mask;
  const int mi_w = mi_size_wide[bsize];
  const int mi_h = mi_size_high[bsize];
  uint64_t picked_ref_frames_mask = 0;
  for (int i = mi_row_in_sb; i < mi_row_in_sb + mi_h; ++i) {
    for (int j = mi_col_in_sb; j < mi_col_in_sb + mi_w; ++j) {
      picked_ref_frames_mask |= x->picked_ref_frames_mask[i * mib_size + j];
    }
  }
  return picked_ref_frames_mask;
}

static INLINE int is_mode_intra(PREDICTION_MODE mode) {
  return mode < INTRA_MODE_END;
}

// Reuse the prediction mode in cache.
// Returns 0 if no pruning is done, 1 if we are skipping the current mod
// completely, 2 if we skip compound only, but still try single motion modes
static INLINE int skip_inter_mode_with_cached_mode(
    const AV2_COMMON *cm, const MACROBLOCK *x, PREDICTION_MODE mode,
    const MV_REFERENCE_FRAME *ref_frame) {
  const MB_MODE_INFO *cached_mi = x->inter_mode_cache[0];

  // If there is no cache, then no pruning is possible.
  // Returns 0 here if we are not reusing inter_modes
  if (!should_reuse_mode(x, REUSE_INTER_MODE_IN_INTERFRAME_FLAG) ||
      !cached_mi) {
    return 0;
  }

  if (should_reuse_mode(x, REUSE_INTER_MODE_IN_INTERFRAME_FLAG)) {
    const int this_mode_is_single = is_inter_singleref_mode(mode);
    for (int k = 0; k < NUMBER_OF_CACHED_MODES; k++) {
      const MB_MODE_INFO *cached_mi2 = x->inter_mode_cache[k];
      if (cached_mi2 && !is_mode_intra(cached_mi2->mode)) {
        const int cached_mode_is_single =
            is_inter_singleref_mode(cached_mi2->mode);
        if (mode == cached_mi2->mode) return 0;
        // if (mode == cached_mi2->mode) {
        if (ref_frame[0] == cached_mi2->ref_frame[0]) return 0;
        if (!cached_mode_is_single &&
            (ref_frame[0] == cached_mi2->ref_frame[1]))
          return 0;
        if (!this_mode_is_single) {
          if (ref_frame[1] == cached_mi2->ref_frame[0]) return 0;
          if (!cached_mode_is_single &&
              (ref_frame[1] == cached_mi2->ref_frame[1]))
            return 0;
        }
        //}
      }
    }
  }

  const PREDICTION_MODE cached_mode = cached_mi->mode;
  const MV_REFERENCE_FRAME *cached_frame = cached_mi->ref_frame;
  const int cached_mode_is_single = is_inter_singleref_mode(cached_mode);

  if (is_mode_intra(cached_mode)) {
    return 1;
  }

  // If the cached mode is single inter mode, then we match the mode and
  // reference frame.
  if (cached_mode_is_single) {
    if (mode != cached_mode || ref_frame[0] != cached_frame[0]) {
      return 1;
    }
  } else {
    // If the cached mode is compound, then we need to consider several cases.
    const int mode_is_single = is_inter_singleref_mode(mode);
    if (mode_is_single) {
      // If the mode is single, we know the modes can't match. But we might
      // still want to search it if compound mode depends on the current mode.
      int skip_motion_mode_only = 0;
      if (cached_mode == NEW_NEARMV || cached_mode == NEW_NEARMV_OPTFLOW) {
        skip_motion_mode_only = (ref_frame[0] == cached_frame[0]);
      } else if (cached_mode == NEAR_NEWMV ||
                 cached_mode == NEAR_NEWMV_OPTFLOW) {
        skip_motion_mode_only = (ref_frame[0] == cached_frame[1]);
      } else if (cached_mode == NEW_NEWMV || cached_mode == NEW_NEWMV_OPTFLOW) {
        skip_motion_mode_only = (ref_frame[0] == cached_frame[0] ||
                                 ref_frame[0] == cached_frame[1]);
      } else if (is_joint_mvd_coding_mode(cached_mode)) {
        const int jmvd_base_ref_list =
            get_joint_mvd_base_ref_list(cm, cached_mi);
        skip_motion_mode_only =
            ref_frame[0] == cached_frame[jmvd_base_ref_list];
      }

      return 1 + skip_motion_mode_only;
    } else {
      // If both modes are compound, then everything must match.
      if (mode != cached_mode || ref_frame[0] != cached_frame[0] ||
          ref_frame[1] != cached_frame[1]) {
        return 1;
      }
    }
  }

  return 0;
}

// Case 1: return 0, means don't skip this mode
// Case 2: return 1, means skip this mode completely
// Case 3: return 2, means skip compound only, but still try single motion
// modes
static int inter_mode_search_order_independent_skip(
    const AV2_COMP *cpi, MACROBLOCK *x, mode_skip_mask_t *mode_skip_mask,
    InterModeSearchState *search_state, uint64_t skip_ref_frame_mask,
    PREDICTION_MODE mode, const MV_REFERENCE_FRAME *ref_frame) {
  if (mask_says_skip(mode_skip_mask, ref_frame, mode)) {
    return 1;
  }
  const uint8_t ref_type = av2_ref_frame_type(ref_frame);
  if (prune_ref_frame(cpi, x, ref_type)) return 1;

  // This is only used in motion vector unit test.
  if (cpi->oxcf.unit_test_cfg.motion_vector_unit_test &&
      ref_frame[0] == INTRA_FRAME)
    return 1;

  const AV2_COMMON *const cm = &cpi->common;
  if (skip_repeated_mv(cm, x, mode, ref_frame, search_state)) {
    return 1;
  }
  const int cached_skip_ret =
      skip_inter_mode_with_cached_mode(cm, x, mode, ref_frame);
  if (cached_skip_ret > 0) {
    return cached_skip_ret;
  }

  const MB_MODE_INFO *const mbmi = x->e_mbd.mi[0];
  // If no valid mode has been found so far in PARTITION_NONE when finding a
  // valid partition is required, do not skip mode.
  if (search_state->best_rd == INT64_MAX && mbmi->partition == PARTITION_NONE &&
      x->must_find_valid_partition)
    return 0;

  int skip_motion_mode = 0;
  if (!x->inter_mode_cache[0] && skip_ref_frame_mask) {
    assert(ref_type <
           (INTER_REFS_PER_FRAME * (INTER_REFS_PER_FRAME + 3) / 2 + 2));
    int skip_ref = (int)(skip_ref_frame_mask & ((uint64_t)1 << ref_type));
    if (ref_type < INTER_REFS_PER_FRAME && skip_ref) {
      // Since the compound ref modes depends on the motion estimation result
      // of two single ref modes( best mv of single ref modes as the start
      // point ) If current single ref mode is marked skip, we need to check
      // if it will be used in compound ref modes.
      for (int r = INTER_REFS_PER_FRAME; r < INTRA_FRAME; ++r) {
        if (skip_ref_frame_mask & ((uint64_t)1 << r)) continue;
        MV_REFERENCE_FRAME rf[2];
        av2_set_ref_frame(rf, r);
        if (rf[0] == ref_type || rf[1] == ref_type) {
          // Found a not skipped compound ref mode which contains current
          // single ref. So this single ref can't be skipped completly
          // Just skip it's motion mode search, still try it's simple
          // transition mode.
          skip_motion_mode = 1;
          skip_ref = 0;
          break;
        }
      }
    }
    // If we are reusing the prediction from cache, and the current frame is
    // required by the cache, then we cannot prune it.
    if (should_reuse_mode(x, REUSE_INTER_MODE_IN_INTERFRAME_FLAG) &&
        is_ref_frame_used_in_cache(ref_type, x->inter_mode_cache[0])) {
      skip_ref = 0;
      // If the cache only needs the current reference type for compound
      // prediction, then we can skip motion mode search.
      assert(x->inter_mode_cache[0]->ref_frame);
      skip_motion_mode = (ref_type < INTER_REFS_PER_FRAME &&
                          x->inter_mode_cache[0]->ref_frame[1] != INTRA_FRAME);
    }
    if (skip_ref) return 1;
  }

  if (skip_motion_mode) return 2;

  return 0;
}

static INLINE void init_mbmi(MB_MODE_INFO *mbmi, PREDICTION_MODE curr_mode,
                             const MV_REFERENCE_FRAME *ref_frames,
                             const AV2_COMMON *cm, MACROBLOCKD *const xd

                             ,
                             const SB_INFO *sbi

) {
  PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info;
  mbmi->ref_mv_idx[0] = 0;
  mbmi->ref_mv_idx[1] = 0;
  mbmi->mode = curr_mode;
  mbmi->uv_mode = UV_DC_PRED;
  mbmi->ref_frame[0] = ref_frames[0];
  mbmi->ref_frame[1] = ref_frames[1];
  pmi->palette_size[0] = 0;
  pmi->palette_size[1] = 0;
  mbmi->use_intra_dip = 0;
  mbmi->mv[0].as_int = mbmi->mv[1].as_int = 0;
  mbmi->cwp_idx = CWP_EQUAL;
  mbmi->motion_mode = SIMPLE_TRANSLATION;
  mbmi->interintra_mode = (INTERINTRA_MODE)(II_DC_PRED - 1);
  mbmi->refinemv_flag = 0;
  for (int i = 0; i < MAX_TX_PARTITIONS; ++i) {
    mbmi->is_wide_angle[0][i] = 0;
    mbmi->is_wide_angle[1][i] = 0;
    mbmi->mapped_intra_mode[0][i] = DC_PRED;
    mbmi->mapped_intra_mode[1][i] = DC_PRED;
  }
  set_default_interp_filters(mbmi, cm, xd, cm->features.interp_filter);
  mbmi->use_intrabc[xd->tree_type == CHROMA_PART] = 0;
  mbmi->morph_pred = 0;
  mbmi->local_rest_type = 1;
  mbmi->local_ccso_blk_flag = 1;
  mbmi->local_gdf_mode = 1;

  set_default_max_mv_precision(mbmi, sbi->sb_mv_precision);
  set_mv_precision(mbmi, mbmi->max_mv_precision);
  set_default_precision_set(cm, mbmi, mbmi->sb_type[PLANE_TYPE_Y]);
  set_most_probable_mv_precision(cm, mbmi, mbmi->sb_type[PLANE_TYPE_Y]);

  mbmi->warp_ref_idx = 0;
  mbmi->max_num_warp_candidates = 0;
  mbmi->warpmv_with_mvd_flag = 0;
  mbmi->six_param_warp_model_flag = 0;
  mbmi->warp_precision_idx = 0;
  mbmi->warp_inter_intra = 0;
  mbmi->bawp_flag[0] = 0;
  mbmi->bawp_flag[1] = 0;
  mbmi->jmvd_scale_mode = 0;
}

static INLINE void init_submi(MACROBLOCKD *const xd, AV2_COMMON *const cm,
                              int mi_row, int mi_col, BLOCK_SIZE bsize) {
  xd->submi[0]->mv[0].as_int = xd->submi[0]->mv[1].as_int = 0;
  span_submv(cm, xd->submi, mi_row, mi_col, bsize, 0);
  span_submv(cm, xd->submi, mi_row, mi_col, bsize, 1);
}

static AVM_INLINE void collect_single_states(const AV2_COMMON *const cm,
                                             MACROBLOCK *x,
                                             InterModeSearchState *search_state,
                                             const MB_MODE_INFO *const mbmi) {
  const FeatureFlags *const features = &cm->features;
  (void)features;
  int i, j;
  const PREDICTION_MODE this_mode = mbmi->mode;
  const MV_REFERENCE_FRAME ref_frame = COMPACT_INDEX0_NRS(mbmi->ref_frame[0]);
  const int dir = get_dir_rank(cm, mbmi->ref_frame[0], NULL);

  // When dir is -1, the reference frame based ranking is not performed.
  // Return as the later stats update assumes that the codec knows the
  // relative position of the reference frame with respect to current frame.
  if (dir == -1) return;

  const int mode_offset = INTER_OFFSET(this_mode);
  const int ref_set = get_drl_refmv_count(features->max_drl_bits, x,
                                          mbmi->ref_frame, this_mode, 0);
  assert(!has_second_drl(mbmi));
  if (mbmi->use_amvd) return;
  // Simple rd
  int64_t simple_rd = search_state->simple_rd[this_mode][0][ref_frame];
  for (int ref_mv_idx = 1; ref_mv_idx < ref_set; ++ref_mv_idx) {
    const int64_t rd =
        search_state->simple_rd[this_mode][ref_mv_idx][ref_frame];
    if (rd < simple_rd) simple_rd = rd;
  }

  // Insertion sort of single_state
  const SingleInterModeState this_state_s = { simple_rd, ref_frame, 1 };
  SingleInterModeState *state_s = search_state->single_state[dir][mode_offset];
  i = search_state->single_state_cnt[dir][mode_offset];
  for (j = i; j > 0 && state_s[j - 1].rd > this_state_s.rd; --j)
    state_s[j] = state_s[j - 1];
  state_s[j] = this_state_s;
  search_state->single_state_cnt[dir][mode_offset]++;

  // Modelled rd
  int64_t modelled_rd = search_state->modelled_rd[this_mode][0][ref_frame];
  for (int ref_mv_idx = 1; ref_mv_idx < ref_set; ++ref_mv_idx) {
    const int64_t rd =
        search_state->modelled_rd[this_mode][ref_mv_idx][ref_frame];
    if (rd < modelled_rd) modelled_rd = rd;
  }

  // Insertion sort of single_state_modelled
  const SingleInterModeState this_state_m = { modelled_rd, ref_frame, 1 };
  SingleInterModeState *state_m =
      search_state->single_state_modelled[dir][mode_offset];
  i = search_state->single_state_modelled_cnt[dir][mode_offset];
  for (j = i; j > 0 && state_m[j - 1].rd > this_state_m.rd; --j)
    state_m[j] = state_m[j - 1];
  state_m[j] = this_state_m;
  search_state->single_state_modelled_cnt[dir][mode_offset]++;
}

static AVM_INLINE void analyze_single_states(
    const AV2_COMP *cpi, InterModeSearchState *search_state) {
  const int prune_level = cpi->sf.inter_sf.prune_comp_search_by_single_result;
  assert(prune_level >= 1);
  int i, j, dir, mode;

  for (dir = 0; dir < 2; ++dir) {
    int64_t best_rd;
    SingleInterModeState(*state)[SINGLE_REF_FRAMES];
    const int prune_factor = prune_level >= 2 ? 6 : 5;

    // Use the best rd of GLOBALMV or NEWMV to prune the unlikely reference
    // frames for all the modes (NEARMV may not have same motion vectors).
    // Always keep the best of each mode because it might form the best
    // possible combination with other mode.
    state = search_state->single_state[dir];
    best_rd = AVMMIN(state[INTER_OFFSET(NEWMV)][0].rd,
                     state[INTER_OFFSET(GLOBALMV)][0].rd);
    for (mode = 0; mode < SINGLE_INTER_MODE_NUM; ++mode) {
      for (i = 1; i < search_state->single_state_cnt[dir][mode]; ++i) {
        if (state[mode][i].rd != INT64_MAX &&
            (state[mode][i].rd >> 3) * prune_factor > best_rd) {
          state[mode][i].valid = 0;
        }
      }
    }

    state = search_state->single_state_modelled[dir];
    best_rd = AVMMIN(state[INTER_OFFSET(NEWMV)][0].rd,
                     state[INTER_OFFSET(GLOBALMV)][0].rd);
    for (mode = 0; mode < SINGLE_INTER_MODE_NUM; ++mode) {
      for (i = 1; i < search_state->single_state_modelled_cnt[dir][mode]; ++i) {
        if (state[mode][i].rd != INT64_MAX &&
            (state[mode][i].rd >> 3) * prune_factor > best_rd) {
          state[mode][i].valid = 0;
        }
      }
    }
  }

  // Ordering by simple rd first, then by modelled rd
  for (dir = 0; dir < 2; ++dir) {
    for (mode = 0; mode < SINGLE_INTER_MODE_NUM; ++mode) {
      const int state_cnt_s = search_state->single_state_cnt[dir][mode];
      const int state_cnt_m =
          search_state->single_state_modelled_cnt[dir][mode];
      SingleInterModeState *state_s = search_state->single_state[dir][mode];
      SingleInterModeState *state_m =
          search_state->single_state_modelled[dir][mode];
      int count = 0;
      const int max_candidates = AVMMAX(state_cnt_s, state_cnt_m);
      for (i = 0; i < state_cnt_s; ++i) {
        if (state_s[i].rd == INT64_MAX) break;
        if (state_s[i].valid) {
          search_state->single_rd_order[dir][mode][count++] =
              state_s[i].ref_frame;
        }
      }
      if (count >= max_candidates) continue;

      for (i = 0; i < state_cnt_m && count < max_candidates; ++i) {
        if (state_m[i].rd == INT64_MAX) break;
        if (!state_m[i].valid) continue;
        const int ref_frame = state_m[i].ref_frame;
        int match = 0;
        // Check if existing already
        for (j = 0; j < count; ++j) {
          if (search_state->single_rd_order[dir][mode][j] == ref_frame) {
            match = 1;
            break;
          }
        }
        if (match) continue;
        // Check if this ref_frame is removed in simple rd
        int valid = 1;
        for (j = 0; j < state_cnt_s; ++j) {
          if (ref_frame == state_s[j].ref_frame) {
            valid = state_s[j].valid;
            break;
          }
        }
        if (valid) {
          search_state->single_rd_order[dir][mode][count++] = ref_frame;
        }
      }
    }
  }
}

static int compound_skip_get_candidates(
    const AV2_COMP *cpi, const InterModeSearchState *search_state,
    const int dir, const PREDICTION_MODE mode) {
  const int mode_offset = INTER_OFFSET(mode);
  const SingleInterModeState *state =
      search_state->single_state[dir][mode_offset];
  const SingleInterModeState *state_modelled =
      search_state->single_state_modelled[dir][mode_offset];

  int max_candidates = 0;
  for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) {
    if (search_state->single_rd_order[dir][mode_offset][i] == NONE_FRAME) break;
    max_candidates++;
  }

  int candidates = max_candidates;
  if (cpi->sf.inter_sf.prune_comp_search_by_single_result >= 2) {
    candidates = AVMMIN(2, max_candidates);
  }
  if (cpi->sf.inter_sf.prune_comp_search_by_single_result >= 3) {
    if (state[0].rd != INT64_MAX && state_modelled[0].rd != INT64_MAX &&
        state[0].ref_frame == state_modelled[0].ref_frame)
      candidates = 1;
    if (mode == NEARMV || mode == GLOBALMV) candidates = 1;
  }

  if (cpi->sf.inter_sf.prune_comp_search_by_single_result >= 4) {
    // Limit the number of candidates to 1 in each direction for compound
    // prediction
    candidates = AVMMIN(1, candidates);
  }
  return candidates;
}

static int compound_skip_by_single_states(
    const AV2_COMP *cpi, const InterModeSearchState *search_state,
    const PREDICTION_MODE this_mode, const MV_REFERENCE_FRAME ref_frame,
    const MV_REFERENCE_FRAME second_ref_frame, const MACROBLOCK *x) {
  const MV_REFERENCE_FRAME refs[2] = { ref_frame, second_ref_frame };
  const int mode[2] = { compound_ref0_mode(this_mode),
                        compound_ref1_mode(this_mode) };
  const int mode_offset[2] = { INTER_OFFSET(mode[0]), INTER_OFFSET(mode[1]) };
  const int mode_dir[2] = { get_dir_rank(&cpi->common, refs[0], NULL),
                            get_dir_rank(&cpi->common, refs[1], NULL) };
  int ref_searched[2] = { 0, 0 };
  int ref_mv_match[2] = { 1, 1 };
  int i, j;
  if (mode_dir[0] == -1 || mode_dir[1] == -1) {
    return 1;
  }
  for (i = 0; i < 2; ++i) {
    const SingleInterModeState *state =
        search_state->single_state[mode_dir[i]][mode_offset[i]];
    const int state_cnt =
        search_state->single_state_cnt[mode_dir[i]][mode_offset[i]];
    for (j = 0; j < state_cnt; ++j) {
      if (state[j].ref_frame == refs[i]) {
        ref_searched[i] = 1;
        break;
      }
    }
  }
  for (i = 0; i < 2; ++i) {
    if (!ref_searched[i] || (mode[i] != NEARMV)) {
      continue;
    }
    const int ref_set = get_drl_refmv_count(cpi->common.features.max_drl_bits,
                                            x, refs, this_mode, i);

    const MV_REFERENCE_FRAME single_refs[2] = { refs[i], NONE_FRAME };
    for (int ref_mv_idx = 0; ref_mv_idx < ref_set; ref_mv_idx++) {
      int_mv single_mv;
      int_mv comp_mv;
      get_this_mv(&single_mv, mode[i], 0, ref_mv_idx, 0, single_refs,
                  x->mbmi_ext);
      get_this_mv(&comp_mv, this_mode, i, ref_mv_idx, 0, refs, x->mbmi_ext);
      if (single_mv.as_int != comp_mv.as_int) {
        ref_mv_match[i] = 0;
        break;
      }
    }
  }

  for (i = 0; i < 2; ++i) {
    if (!ref_searched[i] || !ref_mv_match[i]) continue;
    const int candidates =
        compound_skip_get_candidates(cpi, search_state, mode_dir[i], mode[i]);
    const MV_REFERENCE_FRAME *ref_order =
        search_state->single_rd_order[mode_dir[i]][mode_offset[i]];
    int match = 0;
    for (j = 0; j < candidates; ++j) {
      if (refs[i] == ref_order[j]) {
        match = 1;
        break;
      }
    }
    if (!match) return 1;
  }

  return 0;
}

// Check if ref frames of current block matches with given block.
static INLINE void match_ref_frame(const MB_MODE_INFO *const mbmi,
                                   const MV_REFERENCE_FRAME *ref_frames,
                                   int *const is_ref_match) {
  if (is_inter_block(mbmi, SHARED_PART)) {
    is_ref_match[0] |= ref_frames[0] == mbmi->ref_frame[0];
    is_ref_match[1] |= ref_frames[1] == mbmi->ref_frame[0];
    if (has_second_ref(mbmi)) {
      is_ref_match[0] |= ref_frames[0] == mbmi->ref_frame[1];
      is_ref_match[1] |= ref_frames[1] == mbmi->ref_frame[1];
    }
  }
}

// Prune compound mode using ref frames of neighbor blocks.
static INLINE int compound_skip_using_neighbor_refs(
    MACROBLOCKD *const xd, const PREDICTION_MODE this_mode,
    const MV_REFERENCE_FRAME *ref_frames, int prune_compound_using_neighbors) {
  // Exclude non-extended compound modes from pruning
  if (this_mode == NEAR_NEARMV || this_mode == NEW_NEWMV ||
      this_mode == GLOBAL_GLOBALMV)
    return 0;

  int is_ref_match[2] = { 0 };  // 0 - match for forward refs
                                // 1 - match for backward refs
  // Check if ref frames of this block matches with left neighbor.
  if (xd->left_available)
    match_ref_frame(xd->left_mbmi, ref_frames, is_ref_match);

  // Check if ref frames of this block matches with above neighbor.
  if (xd->up_available)
    match_ref_frame(xd->above_mbmi, ref_frames, is_ref_match);

  // Combine ref frame match with neighbors in forward and backward refs.
  const int track_ref_match = is_ref_match[0] + is_ref_match[1];

  // Pruning based on ref frame match with neighbors.
  if (track_ref_match >= prune_compound_using_neighbors) return 0;
  return 1;
}

// Update best single mode for the given reference frame based on simple rd.
static INLINE void update_best_single_mode(InterModeSearchState *search_state,
                                           const PREDICTION_MODE this_mode,
                                           const MV_REFERENCE_FRAME ref_frame,
                                           int64_t this_rd) {
  const MV_REFERENCE_FRAME rf = COMPACT_INDEX0_NRS(ref_frame);
  if (this_rd < search_state->best_single_rd[rf]) {
    search_state->best_single_rd[rf] = this_rd;
    search_state->best_single_mode[rf] = this_mode;
  }
}

// Prune compound mode using best single mode for the same reference.
static INLINE int skip_compound_using_best_single_mode_ref(
    const PREDICTION_MODE this_mode, const MV_REFERENCE_FRAME *ref_frames,
    const PREDICTION_MODE *best_single_mode,
    int prune_comp_using_best_single_mode_ref) {
  // Exclude non-extended compound modes from pruning
  if (this_mode == NEAR_NEARMV || this_mode == NEW_NEWMV ||
      this_mode == GLOBAL_GLOBALMV)
    return 0;

  const PREDICTION_MODE comp_mode_ref0 = compound_ref0_mode(this_mode);
  // Get ref frame direction corresponding to NEWMV
  // 0 - NEWMV corresponding to forward direction
  // 1 - NEWMV corresponding to backward direction
  const int newmv_dir = comp_mode_ref0 != NEWMV;

  // Avoid pruning the compound mode when ref frame corresponding to NEWMV
  // have NEWMV as single mode winner. Example: For an extended-compound mode,
  // {mode, {fwd_frame, bwd_frame}} = {NEAR_NEWMV, {LAST_FRAME, ALTREF_FRAME}}
  // - Ref frame corresponding to NEWMV is ALTREF_FRAME
  // - Avoid pruning this mode, if best single mode corresponding to ref frame
  //   ALTREF_FRAME is NEWMV
  const PREDICTION_MODE single_mode = best_single_mode[ref_frames[newmv_dir]];
  if (single_mode == NEWMV) return 0;

  // Avoid pruning the compound mode when best single mode is not available
  if (prune_comp_using_best_single_mode_ref == 1)
    if (single_mode == MB_MODE_COUNT) return 0;
  return 1;
}

static int compare_int64(const void *a, const void *b) {
  int64_t a64 = *((int64_t *)a);
  int64_t b64 = *((int64_t *)b);
  if (a64 < b64) {
    return -1;
  } else if (a64 == b64) {
    return 0;
  } else {
    return 1;
  }
}

static INLINE void update_search_state(
    InterModeSearchState *search_state, RD_STATS *best_rd_stats_dst,
    PICK_MODE_CONTEXT *ctx, const RD_STATS *new_best_rd_stats,
    const RD_STATS *new_best_rd_stats_y, const RD_STATS *new_best_rd_stats_uv,
    PREDICTION_MODE new_best_mode, const MACROBLOCK *x, int txfm_search_done,
    const AV2_COMMON *const cm) {
  const MACROBLOCKD *xd = &x->e_mbd;
  const MB_MODE_INFO *mbmi = xd->mi[0];
  const int skip_ctx = av2_get_skip_txfm_context(xd);
  const int mode_is_intra = (new_best_mode < INTRA_MODE_END);
  const int skip_txfm =
      mbmi->skip_txfm[xd->tree_type == CHROMA_PART] && !mode_is_intra;
  const TxfmSearchInfo *txfm_info = &x->txfm_search_info;

  search_state->best_rd = new_best_rd_stats->rdcost;
  *best_rd_stats_dst = *new_best_rd_stats;
  search_state->best_mbmode = *mbmi;
  if (is_warp_mode(mbmi->motion_mode)) {
    store_submi(xd, cm, search_state->best_submb, mbmi->sb_type[PLANE_TYPE_Y]);
  }
  search_state->best_skip2 = skip_txfm;
  search_state->best_mode_skippable = new_best_rd_stats->skip_txfm;
  // When !txfm_search_done, new_best_rd_stats won't provide correct rate_y
  // and rate_uv because av2_txfm_search process is replaced by rd estimation.
  // Therefore, we should avoid updating best_rate_y and best_rate_uv here.
  // These two values will be updated when av2_txfm_search is called.
  if (txfm_search_done) {
    search_state->best_rate_y =
        new_best_rd_stats_y->rate +
        (mode_is_intra
             ? 0
             : (x->mode_costs
                    .skip_txfm_cost[skip_ctx][new_best_rd_stats->skip_txfm ||
                                              skip_txfm]));
    search_state->best_rate_uv = new_best_rd_stats_uv->rate;
  }
  for (int i = 0; i < av2_num_planes(cm); ++i) {
    const int num_blk_plane =
        (i == AVM_PLANE_Y) ? ctx->num_4x4_blk : ctx->num_4x4_blk_chroma;
    memcpy(ctx->blk_skip[i], txfm_info->blk_skip[i],
           sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
  }
  av2_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
  av2_copy_array(ctx->cctx_type_map, xd->cctx_type_map,
                 ctx->num_4x4_blk_chroma);
}

// Find the best RD for a reference frame (among single reference modes)
// and store +10% of it in the 0-th (or last for NRS) element in ref_frame_rd.
static AVM_INLINE void find_top_ref(int64_t *ref_frame_rd) {
  int64_t ref_copy[MAX_COMPOUND_REF_INDEX - 1];
  assert(ref_frame_rd[INTRA_FRAME_INDEX] == INT64_MAX);
  memcpy(ref_copy, ref_frame_rd,
         sizeof(ref_frame_rd[0]) * (MAX_COMPOUND_REF_INDEX - 1));
  qsort(ref_copy, MAX_COMPOUND_REF_INDEX - 1, sizeof(int64_t), compare_int64);

  int64_t cutoff = AVMMIN(ref_copy[0], ref_frame_rd[TIP_FRAME_INDEX]);
  // The cut-off is within 10% of the best.
  if (cutoff != INT64_MAX) {
    assert(cutoff < INT64_MAX / 200);
    cutoff = (110 * cutoff) / 100;
  }
  ref_frame_rd[INTRA_FRAME_INDEX] = cutoff;
}

// Check if either frame is within the cutoff.
static INLINE bool in_single_ref_cutoff(int64_t *ref_frame_rd,
                                        MV_REFERENCE_FRAME frame1,
                                        MV_REFERENCE_FRAME frame2) {
  assert(is_inter_ref_frame(frame2));
  return ref_frame_rd[frame1] <= ref_frame_rd[INTRA_FRAME_INDEX] ||
         ref_frame_rd[frame2] <= ref_frame_rd[INTRA_FRAME_INDEX];
}

static AVM_INLINE void evaluate_motion_mode_for_winner_candidates(
    const AV2_COMP *const cpi, MACROBLOCK *const x, RD_STATS *const rd_cost,
    HandleInterModeArgs *const args, TileDataEnc *const tile_data,
    PICK_MODE_CONTEXT *const ctx,
    struct buf_2d yv12_mb[SINGLE_REF_FRAMES][MAX_MB_PLANE],
    const motion_mode_best_st_candidate *const best_motion_mode_cands,
    int do_tx_search, const BLOCK_SIZE bsize, int64_t *const best_est_rd,
    InterModeSearchState *const search_state) {
  const AV2_COMMON *const cm = &cpi->common;
  const int num_planes = av2_num_planes(cm);
  MACROBLOCKD *const xd = &x->e_mbd;
  MB_MODE_INFO *const mbmi = xd->mi[0];
  InterModesInfo *const inter_modes_info = x->inter_modes_info;
  const int num_best_cand = best_motion_mode_cands->num_motion_mode_cand;

  for (int cand = 0; cand < num_best_cand; cand++) {
    RD_STATS rd_stats;
    RD_STATS rd_stats_y;
    RD_STATS rd_stats_uv;
    av2_init_rd_stats(&rd_stats);
    av2_init_rd_stats(&rd_stats_y);
    av2_init_rd_stats(&rd_stats_uv);
    int rate_mv;

    rate_mv = best_motion_mode_cands->motion_mode_cand[cand].rate_mv;
    args->skip_motion_mode =
        best_motion_mode_cands->motion_mode_cand[cand].skip_motion_mode;
    *mbmi = best_motion_mode_cands->motion_mode_cand[cand].mbmi;
    rd_stats.rate =
        best_motion_mode_cands->motion_mode_cand[cand].rate2_nocoeff;

    // Continue if the best candidate is compound.
    if (!is_inter_singleref_mode(mbmi->mode)) continue;

    x->txfm_search_info.skip_txfm = 0;
    struct macroblockd_plane *p = xd->plane;
    const BUFFER_SET orig_dst = {
      { p[0].dst.buf, p[1].dst.buf, p[2].dst.buf },
      { p[0].dst.stride, p[1].dst.stride, p[2].dst.stride },
    };

    set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
    // Initialize motion mode to simple translation
    // Calculation of switchable rate depends on it.
    mbmi->motion_mode = 0;
    const int is_comp_pred = is_inter_ref_frame(mbmi->ref_frame[1]);
    for (int i = 0; i < num_planes; i++) {
      xd->plane[i].pre[0] = yv12_mb[COMPACT_INDEX0_NRS(mbmi->ref_frame[0])][i];
      if (is_comp_pred)
        xd->plane[i].pre[1] =
            yv12_mb[COMPACT_INDEX0_NRS(mbmi->ref_frame[1])][i];
    }

    int64_t skip_rd[2] = { search_state->best_skip_rd[0],
                           search_state->best_skip_rd[1] };
    int64_t ret_value = motion_mode_rd(
        cpi, tile_data, x, bsize, &rd_stats, &rd_stats_y, &rd_stats_uv, args,
        search_state->best_rd, skip_rd, &rate_mv, &orig_dst, best_est_rd,
        do_tx_search, inter_modes_info, NULL, 1);

    if (ret_value != INT64_MAX) {
      rd_stats.rdcost = RDCOST(x->rdmult, rd_stats.rate, rd_stats.dist);
      MV_REFERENCE_FRAME refs[2] = { mbmi->ref_frame[0], mbmi->ref_frame[1] };
      // Collect mode stats for multiwinner mode processing
      store_winner_mode_stats(
          &cpi->common, x, mbmi, &rd_stats, &rd_stats_y, &rd_stats_uv, refs,
          mbmi->mode, NULL, bsize, rd_stats.rdcost,
          cpi->sf.winner_mode_sf.multi_winner_mode_type, do_tx_search);
      if (rd_stats.rdcost < search_state->best_rd) {
        update_search_state(search_state, rd_cost, ctx, &rd_stats, &rd_stats_y,
                            &rd_stats_uv, mbmi->mode, x, do_tx_search, cm);
        if (do_tx_search) search_state->best_skip_rd[0] = skip_rd[0];
      }
    }
  }
}

/*!\cond */
// Arguments for speed feature pruning of inter mode search
typedef struct {
  int *skip_motion_mode;
  mode_skip_mask_t *mode_skip_mask;
  InterModeSearchState *search_state;
  uint64_t skip_ref_frame_mask;
  int reach_first_comp_mode;
  int mode_thresh_mul_fact;
  int *num_single_modes_processed;
  int prune_cpd_using_sr_stats_ready;
} InterModeSFArgs;
/*!\endcond */

static int skip_inter_mode(AV2_COMP *cpi, MACROBLOCK *x, const BLOCK_SIZE bsize,
                           int64_t *ref_frame_rd, PREDICTION_MODE this_mode,
                           const MV_REFERENCE_FRAME *ref_frames,
                           InterModeSFArgs *args) {
  const SPEED_FEATURES *const sf = &cpi->sf;
  MACROBLOCKD *const xd = &x->e_mbd;
  const MV_REFERENCE_FRAME ref_frame = ref_frames[0];
  const MV_REFERENCE_FRAME second_ref_frame = ref_frames[1];
  const int comp_pred = is_inter_ref_frame(second_ref_frame);

  if (is_tip_ref_frame(ref_frame) &&
      cpi->common.features.tip_frame_mode == TIP_FRAME_DISABLED) {
    return 1;
  } else if (is_tip_ref_frame(ref_frame)) {
    return 0;
  }

  // Check if this mode should be skipped because it is incompatible with the
  // current frame
  if (inter_mode_compatible_skip(cpi, x, bsize, this_mode, ref_frames))
    return 1;

  if (this_mode == WARPMV) return 0;

  const int ret = inter_mode_search_order_independent_skip(
      cpi, x, args->mode_skip_mask, args->search_state,
      args->skip_ref_frame_mask, this_mode, ref_frames);
  if (ret == 1) return 1;
  *(args->skip_motion_mode) = (ret == 2);

  // We've reached the first compound prediction mode, get stats from the
  // single reference predictors to help with pruning
  if (sf->inter_sf.prune_comp_search_by_single_result > 0 && comp_pred &&
      args->reach_first_comp_mode == 0) {
    analyze_single_states(cpi, args->search_state);
    args->reach_first_comp_mode = 1;
  }

  // Prune aggressively when best mode is skippable.
  int mul_fact = args->search_state->best_mode_skippable
                     ? args->mode_thresh_mul_fact
                     : (1 << MODE_THRESH_QBITS);
  int64_t mode_threshold =
      (args->search_state->mode_threshold[this_mode] * mul_fact) >>
      MODE_THRESH_QBITS;

  if (args->search_state->best_rd < mode_threshold) return 1;

  // Skip this compound mode based on the RD results from the single
  // prediction modes
  if (sf->inter_sf.prune_comp_search_by_single_result > 0 &&
      this_mode < NEAR_NEARMV_OPTFLOW && comp_pred &&
      !has_second_drl(xd->mi[0])) {
    if (compound_skip_by_single_states(cpi, args->search_state, this_mode,
                                       ref_frame, second_ref_frame, x))
      return 1;
  }

  // Speed features to prune out INTRA frames
  if (ref_frame == INTRA_FRAME) {
    // Intra modes will be handled in another loop later
    return 1;
  }

  if (sf->inter_sf.prune_compound_using_single_ref && comp_pred) {
    // After we done with single reference modes, find the 2nd best RD
    // for a reference frame. Only search compound modes that have a reference
    // frame at least as good as 110% the best one.
    if (!args->prune_cpd_using_sr_stats_ready &&
        *args->num_single_modes_processed ==
            cpi->common.ref_frames_info.num_total_refs *
                SINGLE_INTER_MODE_NUM) {
      find_top_ref(ref_frame_rd);
      args->prune_cpd_using_sr_stats_ready = 1;
    }
    if (args->prune_cpd_using_sr_stats_ready &&
        !in_single_ref_cutoff(ref_frame_rd, ref_frame, second_ref_frame))
      return 1;
  }

  if (sf->inter_sf.prune_compound_using_neighbors && comp_pred) {
    if (compound_skip_using_neighbor_refs(
            xd, this_mode, ref_frames,
            sf->inter_sf.prune_compound_using_neighbors))
      return 1;
  }

  if (sf->inter_sf.prune_comp_using_best_single_mode_ref && comp_pred) {
    if (skip_compound_using_best_single_mode_ref(
            this_mode, ref_frames, args->search_state->best_single_mode,
            sf->inter_sf.prune_comp_using_best_single_mode_ref))
      return 1;
  }

  return 0;
}

static void record_best_compound(REFERENCE_MODE reference_mode,
                                 RD_STATS *rd_stats, int comp_pred, int rdmult,
                                 InterModeSearchState *search_state,
                                 int compmode_cost) {
  int64_t single_rd, hybrid_rd, single_rate, hybrid_rate;

  if (reference_mode == REFERENCE_MODE_SELECT) {
    single_rate = rd_stats->rate - compmode_cost;
    hybrid_rate = rd_stats->rate;
  } else {
    single_rate = rd_stats->rate;
    hybrid_rate = rd_stats->rate + compmode_cost;
  }

  single_rd = RDCOST(rdmult, single_rate, rd_stats->dist);
  hybrid_rd = RDCOST(rdmult, hybrid_rate, rd_stats->dist);

  if (!comp_pred) {
    if (single_rd <
        search_state->intra_search_state.best_pred_rd[SINGLE_REFERENCE])
      search_state->intra_search_state.best_pred_rd[SINGLE_REFERENCE] =
          single_rd;
  } else {
    if (single_rd <
        search_state->intra_search_state.best_pred_rd[COMPOUND_REFERENCE])
      search_state->intra_search_state.best_pred_rd[COMPOUND_REFERENCE] =
          single_rd;
  }
  if (hybrid_rd <
      search_state->intra_search_state.best_pred_rd[REFERENCE_MODE_SELECT])
    search_state->intra_search_state.best_pred_rd[REFERENCE_MODE_SELECT] =
        hybrid_rd;
}

// Does a transform search over a list of the best inter mode candidates.
// This is called if the original mode search computed an RD estimate
// for the transform search rather than doing a full search.
static void tx_search_best_inter_candidates(
    AV2_COMP *cpi, TileDataEnc *tile_data, MACROBLOCK *x,
    int64_t best_rd_so_far, BLOCK_SIZE bsize,
    struct buf_2d yv12_mb[SINGLE_REF_FRAMES][MAX_MB_PLANE], int mi_row,
    int mi_col, InterModeSearchState *search_state, RD_STATS *rd_cost,
    PICK_MODE_CONTEXT *ctx) {
  AV2_COMMON *const cm = &cpi->common;
  MACROBLOCKD *const xd = &x->e_mbd;
  TxfmSearchInfo *txfm_info = &x->txfm_search_info;
  const ModeCosts *mode_costs = &x->mode_costs;
  const int num_planes = av2_num_planes(cm);
  const int skip_ctx = av2_get_skip_txfm_context(xd);
  MB_MODE_INFO *const mbmi = xd->mi[0];
  InterModesInfo *inter_modes_info = x->inter_modes_info;
  inter_modes_info_sort(inter_modes_info, inter_modes_info->rd_idx_pair_arr);
  search_state->best_rd = best_rd_so_far;
  search_state->best_mbmode.mode = MODE_INVALID;
  // Initialize best mode stats for winner mode processing
  x->winner_mode_count = 0;
  const MV_REFERENCE_FRAME init_refs[2] = { -1, -1 };
  store_winner_mode_stats(&cpi->common, x, mbmi, NULL, NULL, NULL, init_refs,
                          MODE_INVALID, NULL, bsize, best_rd_so_far,
                          cpi->sf.winner_mode_sf.multi_winner_mode_type, 0);
  const int64_t top_est_rd =
      inter_modes_info->num > 0
          ? inter_modes_info
                ->est_rd_arr[inter_modes_info->rd_idx_pair_arr[0].idx]
          : INT64_MAX;
  // Iterate over best inter mode candidates and perform tx search
  for (int j = 0; j < inter_modes_info->num; ++j) {
    const int data_idx = inter_modes_info->rd_idx_pair_arr[j].idx;
    *mbmi = inter_modes_info->mbmi_arr[data_idx];
    if (is_warp_mode(mbmi->motion_mode)) {
      if (!mbmi->wm_params[0].invalid)
        assign_warpmv(cm, xd->submi, bsize, &mbmi->wm_params[0], mi_row, mi_col,
                      0);
      if (!mbmi->wm_params[1].invalid)
        assign_warpmv(cm, xd->submi, bsize, &mbmi->wm_params[1], mi_row, mi_col,
                      1);
    }
    if (cm->bru.enabled) {
      if (mbmi->ref_frame[0] != INVALID_IDX &&
          cm->bru.update_ref_idx == mbmi->ref_frame[0]) {
        continue;
      }
      if (mbmi->ref_frame[1] != INVALID_IDX &&
          cm->bru.update_ref_idx == mbmi->ref_frame[1]) {
        continue;
      }
    }
    int64_t curr_est_rd = inter_modes_info->est_rd_arr[data_idx];
    if (curr_est_rd * 0.80 > top_est_rd) break;

    txfm_info->skip_txfm = 0;
    set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);

    // Select prediction reference frames.
    const int is_comp_pred = is_inter_ref_frame(mbmi->ref_frame[1]);
    for (int i = 0; i < num_planes; i++) {
      xd->plane[i].pre[0] = yv12_mb[COMPACT_INDEX0_NRS(mbmi->ref_frame[0])][i];
      if (is_comp_pred)
        xd->plane[i].pre[1] =
            yv12_mb[COMPACT_INDEX0_NRS(mbmi->ref_frame[1])][i];
    }

    // Build the prediction for this mode
    // Set buf for bawp to access the neigboring samples
    struct macroblockd_plane *p = xd->plane;
    const BUFFER_SET orig_dst = {
      { p[0].dst.buf, p[1].dst.buf, p[2].dst.buf },
      { p[0].dst.stride, p[1].dst.stride, p[2].dst.stride },
    };
    av2_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst, bsize, 0,
                                  av2_num_planes(cm) - 1);

    // Initialize RD stats
    RD_STATS rd_stats;
    RD_STATS rd_stats_y;
    RD_STATS rd_stats_uv;
    const int mode_rate = inter_modes_info->mode_rate_arr[data_idx];
    int64_t skip_rd = INT64_MAX;
    if (cpi->sf.inter_sf.txfm_rd_gate_level) {
      // Check if the mode is good enough based on skip RD
      int64_t curr_sse = inter_modes_info->sse_arr[data_idx];
      skip_rd = RDCOST(x->rdmult, mode_rate, curr_sse);
      int eval_txfm =
          check_txfm_eval(x, bsize, search_state->best_skip_rd[0], skip_rd,
                          cpi->sf.inter_sf.txfm_rd_gate_level, 0);
      if (!eval_txfm) continue;
    }

    // Do the transform search
    if (!av2_txfm_search(cpi, x, bsize, &rd_stats, &rd_stats_y, &rd_stats_uv,
                         mode_rate, 1, search_state->best_rd)) {
      continue;
    } else if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1) {
      inter_mode_data_push(
          tile_data, mbmi->sb_type[PLANE_TYPE_Y], rd_stats.sse, rd_stats.dist,
          rd_stats_y.rate + rd_stats_uv.rate +
              mode_costs->skip_txfm_cost
                  [skip_ctx][mbmi->skip_txfm[xd->tree_type == CHROMA_PART]]);
    }
    rd_stats.rdcost = RDCOST(x->rdmult, rd_stats.rate, rd_stats.dist);

    const MV_REFERENCE_FRAME refs[2] = { mbmi->ref_frame[0],
                                         mbmi->ref_frame[1] };

    // Collect mode stats for multiwinner mode processing
    const int txfm_search_done = 1;
    store_winner_mode_stats(
        &cpi->common, x, mbmi, &rd_stats, &rd_stats_y, &rd_stats_uv, refs,
        mbmi->mode, NULL, bsize, rd_stats.rdcost,
        cpi->sf.winner_mode_sf.multi_winner_mode_type, txfm_search_done);

    if (rd_stats.rdcost < search_state->best_rd) {
      update_search_state(search_state, rd_cost, ctx, &rd_stats, &rd_stats_y,
                          &rd_stats_uv, mbmi->mode, x, txfm_search_done, cm);
      search_state->best_skip_rd[0] = skip_rd;
    }
  }
}

// Indicates number of winner simple translation modes to be used
static const unsigned int num_winner_motion_modes[3] = { 0, 10, 3 };

// Adds a motion mode to the candidate list for motion_mode_for_winner_cand
// speed feature. This list consists of modes that have only searched
// SIMPLE_TRANSLATION. The final list will be used to search other motion
// modes after the initial RD search.
static void handle_winner_cand(
    MB_MODE_INFO *const mbmi,
    motion_mode_best_st_candidate *best_motion_mode_cands,
    int max_winner_motion_mode_cand, int64_t this_rd,
    motion_mode_candidate *motion_mode_cand, int skip_motion_mode) {
  // Number of current motion mode candidates in list
  const int num_motion_mode_cand = best_motion_mode_cands->num_motion_mode_cand;
  int valid_motion_mode_cand_loc = num_motion_mode_cand;

  // find the best location to insert new motion mode candidate
  for (int j = 0; j < num_motion_mode_cand; j++) {
    if (this_rd < best_motion_mode_cands->motion_mode_cand[j].rd_cost) {
      valid_motion_mode_cand_loc = j;
      break;
    }
  }

  // Insert motion mode if location is found
  if (valid_motion_mode_cand_loc < max_winner_motion_mode_cand) {
    if (num_motion_mode_cand > 0 &&
        valid_motion_mode_cand_loc < max_winner_motion_mode_cand - 1)
      memmove(
          &best_motion_mode_cands
               ->motion_mode_cand[valid_motion_mode_cand_loc + 1],
          &best_motion_mode_cands->motion_mode_cand[valid_motion_mode_cand_loc],
          (AVMMIN(num_motion_mode_cand, max_winner_motion_mode_cand - 1) -
           valid_motion_mode_cand_loc) *
              sizeof(best_motion_mode_cands->motion_mode_cand[0]));
    motion_mode_cand->mbmi = *mbmi;
    motion_mode_cand->rd_cost = this_rd;
    motion_mode_cand->skip_motion_mode = skip_motion_mode;
    best_motion_mode_cands->motion_mode_cand[valid_motion_mode_cand_loc] =
        *motion_mode_cand;
    best_motion_mode_cands->num_motion_mode_cand =
        AVMMIN(max_winner_motion_mode_cand,
               best_motion_mode_cands->num_motion_mode_cand + 1);
  }
}

static INLINE int is_tip_mode(PREDICTION_MODE mode) {
  return (mode == NEARMV || mode == NEWMV);
}

static INLINE int is_compound_mode_disallowed(PREDICTION_MODE mode,
                                              int ref_frame0, int ref_frame1) {
  if (ref_frame0 == ref_frame1 &&
      (mode == NEW_NEARMV || mode == NEW_NEARMV_OPTFLOW)) {
    return 1;
  }

  return 0;
}

// Initialize the table that stores best RD Costs of NONE transform partition
static INLINE void init_top_tx_part_rd_for_inter_modes(
    MACROBLOCK *const x, bool prune_inter_tx_part_rd_eval) {
  if (!prune_inter_tx_part_rd_eval) return;

  for (int i = 0; i < MAX_TX_BLOCKS_IN_MAX_SB; i++) {
    for (int j = 0; j < TOP_INTER_TX_PART_COUNT; j++) {
      x->top_tx_part_rd_inter[i][j] = INT64_MAX;
    }
  }
}

// TODO(chiyotsai@google.com): See the todo for av2_rd_pick_intra_mode_sb.
void av2_rd_pick_inter_mode_sb(struct AV2_COMP *cpi,
                               struct TileDataEnc *tile_data,
                               struct macroblock *x, struct RD_STATS *rd_cost,
                               BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx,
                               int64_t best_rd_so_far) {
  AV2_COMMON *const cm = &cpi->common;
  const FeatureFlags *const features = &cm->features;
  const int num_planes = av2_num_planes(cm);
  const SPEED_FEATURES *const sf = &cpi->sf;
  MACROBLOCKD *const xd = &x->e_mbd;
  MB_MODE_INFO *const mbmi = xd->mi[0];
  TxfmSearchInfo *txfm_info = &x->txfm_search_info;
  int i;
  const ModeCosts *mode_costs = &x->mode_costs;
  const int *comp_inter_cost =
      mode_costs->comp_inter_cost[av2_get_reference_mode_context(cm, xd)];
  mbmi->use_intrabc[xd->tree_type == CHROMA_PART] = 0;
  mbmi->local_rest_type = 1;
  mbmi->local_ccso_blk_flag = 1;
  mbmi->local_gdf_mode = 1;
  InterModeSearchState search_state;
  init_inter_mode_search_state(&search_state, cpi, x, bsize, best_rd_so_far);
  INTERINTRA_MODE interintra_modes[MAX_COMPOUND_REF_INDEX] = {
    INTERINTRA_MODES, INTERINTRA_MODES, INTERINTRA_MODES, INTERINTRA_MODES,
    INTERINTRA_MODES, INTERINTRA_MODES, INTERINTRA_MODES, INTERINTRA_MODES
  };
  HandleInterModeArgs args = {
    NULL,
    NULL,
    NULL,
    search_state.modelled_rd,
    INT_MAX,
    INT_MAX,
    search_state.simple_rd,
    0,
    interintra_modes,
    { { 0, { { 0 } }, { 0 }, 0, 0, 0 } },
    0,
    { { 0 } },
    0,
    { { 0 } },
    0,
    { { 0 } },
    0,
    { { 0 } },
    0,
    { { 0 } },
    0,
    { { 0 } },
    0,
    { { 0 } },
    0,
    { { 0 } },
    0,
  };

  // Indicates the appropriate number of simple translation winner modes for
  // exhaustive motion mode evaluation
  const int max_winner_motion_mode_cand =
      num_winner_motion_modes[cpi->sf.winner_mode_sf
                                  .motion_mode_for_winner_cand];
  assert(max_winner_motion_mode_cand <= MAX_WINNER_MOTION_MODES);
  motion_mode_candidate motion_mode_cand;
  motion_mode_best_st_candidate best_motion_mode_cands;
  // Initializing the number of motion mode candidates to zero.
  best_motion_mode_cands.num_motion_mode_cand = 0;
  for (i = 0; i < MAX_WINNER_MOTION_MODES; ++i)
    best_motion_mode_cands.motion_mode_cand[i].rd_cost = INT64_MAX;

  for (i = 0; i < SINGLE_REF_FRAMES; ++i) x->pred_sse[i] = INT_MAX;

  av2_invalid_rd_stats(rd_cost);

  av2_initialize_warp_wrl_list(xd->warp_param_stack,
                               xd->valid_num_warp_candidates);

  // Ref frames that are selected by square partition blocks.
  uint64_t picked_ref_frames_mask = 0;
  if (cpi->sf.inter_sf.prune_ref_frames && !x->inter_mode_cache[0]) {
    bool prune_ref_frames = false;
    assert(should_reuse_mode(x, REUSE_PARTITION_MODE_FLAG));

    // Prune reference frames if we are either a 1:4 block, or if we are a 1:2
    // block, and we have searched any of the rectangular subblock.
    if (!is_partition_point(bsize)) {
      prune_ref_frames = true;
    } else if (bsize > BLOCK_LARGEST) {
      // Check horz sub-blocks at different row offsets.
      BLOCK_SIZE subsize = get_partition_subsize(bsize, PARTITION_HORZ);
      if (subsize != BLOCK_INVALID) {
        for (int r = 0; r <= mi_size_high[bsize] / 2; ++r) {
          const PARTITION_TYPE prev_part =
              av2_get_prev_partition(x, xd->mi_row + r, xd->mi_col, subsize,
                                     cm->sb_size, (int8_t)mbmi->region_type);
          if (prev_part != PARTITION_INVALID) {
            prune_ref_frames = true;
            break;
          }
        }
      }
      // Check vert sub-blocks at different col offsets.
      subsize = get_partition_subsize(bsize, PARTITION_VERT);
      if (subsize != BLOCK_INVALID) {
        for (int c = 0; c <= mi_size_wide[bsize] / 2; ++c) {
          const PARTITION_TYPE prev_part =
              av2_get_prev_partition(x, xd->mi_row, xd->mi_col + c, subsize,
                                     cm->sb_size, (int8_t)mbmi->region_type);
          if (prev_part != PARTITION_INVALID) {
            prune_ref_frames = true;
            break;
          }
        }
      }
    } else {
      for (RECT_PART_TYPE rect_type = HORZ; rect_type < NUM_RECT_PARTS;
           rect_type++) {
        const int mi_pos_rect[NUM_RECT_PARTS][SUB_PARTITIONS_RECT][2] = {
          { { xd->mi_row, xd->mi_col },
            { xd->mi_row + mi_size_high[bsize] / 2, xd->mi_col } },
          { { xd->mi_row, xd->mi_col },
            { xd->mi_row, xd->mi_col + mi_size_wide[bsize] / 2 } }
        };
        const PARTITION_TYPE part =
            (rect_type == HORZ) ? PARTITION_HORZ : PARTITION_VERT;
        const BLOCK_SIZE subsize = get_partition_subsize(bsize, part);
        if (subsize == BLOCK_INVALID) {
          continue;
        }
        for (int sub_idx = 0; sub_idx < 2; sub_idx++) {
          const PARTITION_TYPE prev_part = av2_get_prev_partition(
              x, mi_pos_rect[rect_type][sub_idx][0],
              mi_pos_rect[rect_type][sub_idx][1], subsize, cm->sb_size,
              (int8_t)mbmi->region_type);
          if (prev_part != PARTITION_INVALID) {
            prune_ref_frames = true;
            break;
          }
        }
      }
    }

    if (prune_ref_frames) {
      picked_ref_frames_mask =
          fetch_picked_ref_frames_mask(x, bsize, cm->mib_size);
    }
  }

  // Skip ref frames that never selected by square blocks.
  const uint64_t skip_ref_frame_mask =
      picked_ref_frames_mask ? ~picked_ref_frames_mask : 0;
  mode_skip_mask_t mode_skip_mask;
  unsigned int ref_costs_single[SINGLE_REF_FRAMES];
  struct buf_2d yv12_mb[SINGLE_REF_FRAMES][MAX_MB_PLANE];
  unsigned int ref_costs_comp[MAX_COMPOUND_REF_INDEX][MAX_COMPOUND_REF_INDEX];

  set_default_max_mv_precision(mbmi, xd->sbi->sb_mv_precision);
  set_default_precision_set(cm, mbmi, bsize);
  set_mv_precision(mbmi, mbmi->max_mv_precision);
  set_most_probable_mv_precision(cm, mbmi, bsize);

  mbmi->bawp_flag[0] = 0;
  mbmi->bawp_flag[1] = 0;
  // Reset skip mode flag.
  mbmi->skip_mode = 0;
  mbmi->refinemv_flag = 0;
  mbmi->mode = NEARMV;
  // init params, set frame modes, speed features
  set_params_rd_pick_inter_mode(cpi, x, bsize, &mode_skip_mask,
                                skip_ref_frame_mask, ref_costs_single,
                                ref_costs_comp, yv12_mb);

  int64_t best_est_rd = INT64_MAX;
  const InterModeRdModel *md = &tile_data->inter_mode_rd_models[bsize];
  // If do_tx_search is 0, only estimated RD should be computed.
  // If do_tx_search is 1, all modes have TX search performed.
  const int do_tx_search =
      !((cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1 && md->ready) ||
        (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 2 &&
         num_pels_log2_lookup[bsize] > 8));
  InterModesInfo *inter_modes_info = x->inter_modes_info;
  inter_modes_info->num = 0;

  int num_single_modes_processed = 0;

  // Temporary buffers used by handle_inter_mode().
  uint16_t *const tmp_buf = x->tmp_pred_bufs[0];

  // The best RD found for the reference frame, among single reference modes.
  // Note that the 0-th element will contain a cut-off that is later used
  // to determine if we should skip a compound mode.

  int64_t ref_frame_rd[SINGLE_REF_FRAMES] = { INT64_MAX, INT64_MAX, INT64_MAX,
                                              INT64_MAX, INT64_MAX, INT64_MAX,
                                              INT64_MAX, INT64_MAX, INT64_MAX };

  // Prepared stats used later to check if we could skip intra mode eval.
  int64_t inter_cost = -1;
  int64_t intra_cost = -1;
  // Need to tweak the threshold for hdres speed 0 & 1.
  const int mi_row = xd->mi_row;
  const int mi_col = xd->mi_col;

  // Obtain the relevant tpl stats for pruning inter modes
  PruneInfoFromTpl inter_cost_info_from_tpl;
  if (cpi->sf.inter_sf.prune_inter_modes_based_on_tpl) {
    // x->tpl_keep_ref_frame[id] = 1 => no pruning in
    // prune_ref_by_selective_ref_frame()
    // x->tpl_keep_ref_frame[id] = 0  => ref frame can be pruned in
    // prune_ref_by_selective_ref_frame()
    // Populating valid_refs[idx] = 1 ensures that
    // 'inter_cost_info_from_tpl.best_inter_cost' does not correspond to a
    // pruned ref frame.
    int valid_refs[INTER_REFS_PER_FRAME] = { 0 };
    for (MV_REFERENCE_FRAME frame = 0;
         frame < cm->ref_frames_info.num_total_refs; frame++) {
      const MV_REFERENCE_FRAME refs[2] = { frame, NONE_FRAME };
      valid_refs[frame] = x->tpl_keep_ref_frame[frame] ||
                          !prune_ref_by_selective_ref_frame(cpi, x, refs);
    }
    av2_zero(inter_cost_info_from_tpl);
    get_block_level_tpl_stats(cpi, bsize, mi_row, mi_col, valid_refs,
                              &inter_cost_info_from_tpl);
  }
  const int do_pruning =
      (AVMMIN(cm->width, cm->height) > 480 && cpi->speed <= 2) ? 0 : 1;
  if (do_pruning && sf->intra_sf.skip_intra_in_interframe) {
    // Only consider full SB.
    const BLOCK_SIZE sb_size = cm->sb_size;
    const int tpl_bsize_1d = cpi->tpl_data.tpl_bsize_1d;
    const int len = (block_size_wide[sb_size] / tpl_bsize_1d) *
                    (block_size_high[sb_size] / tpl_bsize_1d);
    SuperBlockEnc *sb_enc = &x->sb_enc;
    if (sb_enc->tpl_data_count == len) {
      const BLOCK_SIZE tpl_bsize = convert_length_to_bsize(tpl_bsize_1d);
      const int tpl_stride = sb_enc->tpl_stride;
      const int tplw = mi_size_wide[tpl_bsize];
      const int tplh = mi_size_high[tpl_bsize];
      const int nw = mi_size_wide[bsize] / tplw;
      const int nh = mi_size_high[bsize] / tplh;
      if (nw >= 1 && nh >= 1) {
        const int of_h = mi_row % mi_size_high[sb_size];
        const int of_w = mi_col % mi_size_wide[sb_size];
        const int start = of_h / tplh * tpl_stride + of_w / tplw;

        for (int k = 0; k < nh; k++) {
          for (int l = 0; l < nw; l++) {
            inter_cost += sb_enc->tpl_inter_cost[start + k * tpl_stride + l];
            intra_cost += sb_enc->tpl_intra_cost[start + k * tpl_stride + l];
          }
        }
        inter_cost /= nw * nh;
        intra_cost /= nw * nh;
      }
    }
  }

  // Initialize best mode stats for winner mode processing
  av2_zero(x->winner_mode_stats);
  x->winner_mode_count = 0;
  const MV_REFERENCE_FRAME init_refs[2] = { -1, -1 };
  store_winner_mode_stats(&cpi->common, x, mbmi, NULL, NULL, NULL, init_refs,
                          MODE_INVALID, NULL, bsize, best_rd_so_far,
                          cpi->sf.winner_mode_sf.multi_winner_mode_type, 0);

  int mode_thresh_mul_fact = (1 << MODE_THRESH_QBITS);
  if (sf->inter_sf.prune_inter_modes_if_skippable) {
    // Higher multiplication factor values for lower quantizers.
    mode_thresh_mul_fact = mode_threshold_mul_factor[x->qindex];
  }

  init_top_tx_part_rd_for_inter_modes(x, sf->tx_sf.prune_inter_tx_part_rd_eval);

  // Initialize arguments for mode loop speed features
  InterModeSFArgs sf_args = { &args.skip_motion_mode,
                              &mode_skip_mask,
                              &search_state,
                              skip_ref_frame_mask,
                              0,
                              mode_thresh_mul_fact,
                              &num_single_modes_processed,
                              0 };
  // This is the main loop of this function. It loops over all possible modes
  // and calls handle_inter_mode() to compute the RD for each.
  // Here midx is just an iterator index that should not be used by itself
  // except to keep track of the number of modes searched. It should be used
  // with av2_default_mode_order to get the enum that defines the mode, which
  // can be used with av2_mode_defs to get the prediction mode and the ref
  // frames.
  for (PREDICTION_MODE this_mode = 0; this_mode < MB_MODE_COUNT; ++this_mode) {
    int64_t top_motion_mode_model_rd[TOP_MOTION_MODE_MODEL_COUNT];
    uint8_t enable_tx_prune = do_tx_search;
    if (enable_tx_prune) {
      for (int k = 0; k < TOP_MOTION_MODE_MODEL_COUNT; k++) {
        top_motion_mode_model_rd[k] = INT64_MAX;
      }
    }

    for (MV_REFERENCE_FRAME rf = NONE_FRAME;
         rf < cm->ref_frames_info.num_total_refs + 1; ++rf) {
      const MV_REFERENCE_FRAME ref_frame =
          (rf == NONE_FRAME)
              ? INTRA_FRAME
              : ((rf == cm->ref_frames_info.num_total_refs) ? TIP_FRAME : rf);
      if (is_tip_ref_frame(ref_frame) &&
          (!is_tip_allowed(cm, xd) || !is_tip_mode(this_mode)))
        continue;

      if (this_mode < INTRA_MODE_END && ref_frame != INTRA_FRAME) continue;
      if (this_mode >= INTRA_MODE_END && ref_frame == INTRA_FRAME) continue;
      if (ref_frame != INTRA_FRAME && bsize == BLOCK_4X4) {
        continue;  // disable 4x4 inter blocks
      }
      for (MV_REFERENCE_FRAME second_rf = NONE_FRAME;
           second_rf < cm->ref_frames_info.num_total_refs; ++second_rf) {
        MV_REFERENCE_FRAME second_ref_frame = second_rf;
        // write this to a function
        if (cm->bru.enabled) {
          assert(xd->sbi->sb_active_mode == BRU_ACTIVE_SB);
          if (xd->sbi->sb_active_mode == BRU_ACTIVE_SB) {
            if (ref_frame != INVALID_IDX &&
                cm->bru.update_ref_idx == ref_frame) {
              continue;
            }
            if (second_ref_frame != INVALID_IDX &&
                cm->bru.update_ref_idx == second_ref_frame) {
              continue;
            }
          }
        }
        if ((ref_frame == second_ref_frame) &&
            (is_joint_mvd_coding_mode(this_mode)))
          continue;

        if (second_ref_frame != NONE_FRAME && this_mode < COMP_INTER_MODE_START)
          continue;
        if (this_mode >= COMP_INTER_MODE_START &&
            this_mode < COMP_INTER_MODE_END && second_ref_frame == NONE_FRAME)
          continue;
        if (is_inter_ref_frame(second_ref_frame) &&
            ((second_ref_frame < ref_frame) ||
             is_compound_mode_disallowed(this_mode, ref_frame,
                                         second_ref_frame) ||
             ((second_ref_frame == ref_frame) &&
              (ref_frame >= cm->ref_frames_info.num_same_ref_compound))))
          continue;

        if (is_tip_ref_frame(ref_frame) && second_ref_frame != NONE_FRAME)
          continue;

        const MV_REFERENCE_FRAME ref_frames[2] = { ref_frame,
                                                   second_ref_frame };

        const int is_single_pred =
            ref_frame != INTRA_FRAME && second_ref_frame == NONE_FRAME;
        const int comp_pred = is_inter_ref_frame(second_ref_frame);

        init_mbmi(mbmi, this_mode, ref_frames, cm, xd, xd->sbi);

        if ((this_mode == WARPMV || this_mode == WARP_NEWMV) &&
            !is_warpmv_mode_allowed(cm, mbmi, bsize))
          continue;

        if (this_mode == WARP_NEWMV &&
            !is_warp_newmv_allowed(cm, xd, mbmi, bsize))
          continue;

        init_submi(xd, cm, mi_row, mi_col, bsize);

        set_mv_precision(mbmi, mbmi->max_mv_precision);
        if (is_pb_mv_precision_active(cm, mbmi, bsize))
          set_most_probable_mv_precision(cm, mbmi, bsize);

        // Initialize compound average type for optical flow refinement
        mbmi->interinter_comp.type = COMPOUND_AVERAGE;

        // Optical flow compound modes are only enabled
        // when prediction is bi-directional
        if (this_mode >= NEAR_NEARMV_OPTFLOW &&
            (!opfl_allowed_cur_refs_bsize(cm, xd, mbmi) ||
             cm->features.opfl_refine_type == REFINE_ALL))
          continue;
        // Optical flow is disabled for 4xn/nx4 blocks
        if (is_thin_4xn_nx4_block(bsize) && (this_mode >= NEAR_NEARMV_OPTFLOW))
          continue;

        int num_amvd_modes = 1 + allow_amvd_mode(mbmi->mode);
        for (int use_amvd_mode = 0; use_amvd_mode < num_amvd_modes;
             ++use_amvd_mode) {
          mbmi->use_amvd = use_amvd_mode;

          if (mbmi->mode == NEW_NEARMV || mbmi->mode == NEAR_NEWMV ||
              mbmi->mode == NEAR_NEWMV_OPTFLOW ||
              mbmi->mode == NEW_NEARMV_OPTFLOW) {
            mbmi->use_amvd = use_amvd_mode ? 0 : 1;

            if (!mbmi->use_amvd &&
                search_state.best_mbmode.mode != mbmi->mode) {
              continue;
            }
          }

          txfm_info->skip_txfm = 0;
          num_single_modes_processed += is_single_pred;
          set_ref_ptrs(cm, xd, ref_frame, second_ref_frame);

          // Apply speed features to decide if this inter mode can be skipped
          if (skip_inter_mode(cpi, x, bsize, ref_frame_rd, this_mode,
                              ref_frames, &sf_args))
            continue;

          if (cm->seq_params.enable_adaptive_mvd == 0 && mbmi->use_amvd == 1)
            continue;

          if (is_joint_mvd_coding_mode(this_mode) &&
              cm->seq_params.enable_joint_mvd == 0)
            continue;

          // Select prediction reference frames.
          for (i = 0; i < num_planes; i++) {
            xd->plane[i].pre[0] = yv12_mb[COMPACT_INDEX0_NRS(ref_frame)][i];
            if (comp_pred)
              xd->plane[i].pre[1] =
                  yv12_mb[COMPACT_INDEX0_NRS(second_ref_frame)][i];
          }

          mbmi->fsc_mode[PLANE_TYPE_Y] = 0;
          mbmi->fsc_mode[PLANE_TYPE_UV] = 0;
          mbmi->use_intrabc[0] = 0;
          mbmi->use_intrabc[1] = 0;
          mbmi->angle_delta[PLANE_TYPE_Y] = 0;
          mbmi->angle_delta[PLANE_TYPE_UV] = 0;
          mbmi->use_intra_dip = 0;
          mbmi->use_dpcm_y = 0;
          mbmi->dpcm_mode_y = 0;
          mbmi->use_dpcm_uv = 0;
          mbmi->dpcm_mode_uv = 0;
          mbmi->ref_mv_idx[0] = 0;
          mbmi->ref_mv_idx[1] = 0;
          mbmi->warp_ref_idx = 0;
          mbmi->max_num_warp_candidates = 0;
          mbmi->warpmv_with_mvd_flag = 0;
          const int64_t ref_best_rd = search_state.best_rd;
          RD_STATS rd_stats, rd_stats_y, rd_stats_uv;
          av2_init_rd_stats(&rd_stats);

          const int ref_frame_index = COMPACT_INDEX0_NRS(ref_frame);

          const int ref_frame_cost =
              comp_pred ? ref_costs_comp[ref_frame][second_ref_frame]
                        : ref_costs_single[ref_frame_index];

          const int compmode_cost =
              (is_comp_ref_allowed(mbmi->sb_type[PLANE_TYPE_Y]) &&
               !is_tip_ref_frame(ref_frame))
                  ? comp_inter_cost[comp_pred]
                  : 0;
          const int real_compmode_cost =
              cm->current_frame.reference_mode == REFERENCE_MODE_SELECT
                  ? compmode_cost
                  : 0;
          // Point to variables that are maintained between loop iterations
          args.single_newmv = search_state.single_newmv;
          args.single_newmv_rate = search_state.single_newmv_rate;
          args.single_newmv_valid = search_state.single_newmv_valid;
          args.single_comp_cost = real_compmode_cost;
          args.ref_frame_cost = ref_frame_cost;

          int64_t skip_rd[2] = { search_state.best_skip_rd[0],
                                 search_state.best_skip_rd[1] };

          int64_t this_rd = handle_inter_mode(
              cpi, tile_data, x, bsize, &rd_stats, &rd_stats_y, &rd_stats_uv,
              &args, ref_best_rd, tmp_buf, &x->comp_rd_buffer, &best_est_rd,
              do_tx_search, inter_modes_info, &motion_mode_cand, skip_rd,
              search_state.best_mbmode.mode,
              enable_tx_prune ? top_motion_mode_model_rd : NULL,
              &inter_cost_info_from_tpl);

          if (sf->inter_sf.prune_comp_search_by_single_result > 0 &&
              is_inter_singleref_mode(this_mode)) {
            collect_single_states(cm, x, &search_state, mbmi);
          }

          if (sf->inter_sf.prune_comp_using_best_single_mode_ref > 0 &&
              is_inter_singleref_mode(this_mode))
            update_best_single_mode(&search_state, this_mode, ref_frame,
                                    this_rd);

          if (this_rd == INT64_MAX) continue;
          if (mbmi->skip_txfm[xd->tree_type == CHROMA_PART]) {
            rd_stats_y.rate = 0;
            rd_stats_uv.rate = 0;
          }

          if (sf->inter_sf.prune_compound_using_single_ref && is_single_pred &&
              this_rd < ref_frame_rd[ref_frame_index]) {
            ref_frame_rd[ref_frame_index] = this_rd;
          }

          // Did this mode help, i.e., is it the new best mode
          if (this_rd < search_state.best_rd) {
            if (is_tip_ref_frame(ref_frame) &&
                this_rd + TIP_RD_CORRECTION > search_state.best_rd) {
              continue;
            }
            assert(IMPLIES(comp_pred, cm->current_frame.reference_mode !=
                                          SINGLE_REFERENCE));
            update_search_state(&search_state, rd_cost, ctx, &rd_stats,
                                &rd_stats_y, &rd_stats_uv, this_mode, x,
                                do_tx_search, cm);
            if (do_tx_search) search_state.best_skip_rd[0] = skip_rd[0];
            search_state.best_skip_rd[1] = skip_rd[1];
          }
          if (cpi->sf.winner_mode_sf.motion_mode_for_winner_cand) {
            // Add this mode to motion mode candidate list for motion mode
            // search if using motion_mode_for_winner_cand speed feature
            handle_winner_cand(mbmi, &best_motion_mode_cands,
                               max_winner_motion_mode_cand, this_rd,
                               &motion_mode_cand, args.skip_motion_mode);
          }

          /* keep record of best compound/single-only prediction */
          record_best_compound(cm->current_frame.reference_mode, &rd_stats,
                               comp_pred, x->rdmult, &search_state,
                               compmode_cost);
        }  // end of use_amvd mode loop
      }  // end of ref1 loop
    }  // end of ref0 loop
  }  // end of mode loop

  if (cpi->sf.winner_mode_sf.motion_mode_for_winner_cand) {
    // For the single ref winner candidates, evaluate other motion modes (non
    // simple translation).
    evaluate_motion_mode_for_winner_candidates(
        cpi, x, rd_cost, &args, tile_data, ctx, yv12_mb,
        &best_motion_mode_cands, do_tx_search, bsize, &best_est_rd,
        &search_state);
  }

#if CONFIG_COLLECT_COMPONENT_TIMING
  start_timing(cpi, do_tx_search_time);
#endif
  if (do_tx_search != 1) {
    // A full tx search has not yet been done, do tx search for
    // top mode candidates
    tx_search_best_inter_candidates(cpi, tile_data, x, best_rd_so_far, bsize,
                                    yv12_mb, mi_row, mi_col, &search_state,
                                    rd_cost, ctx);
  }
#if CONFIG_COLLECT_COMPONENT_TIMING
  end_timing(cpi, do_tx_search_time);
#endif

#if CONFIG_COLLECT_COMPONENT_TIMING
  start_timing(cpi, handle_intra_mode_time);
#endif

  // Gate intra mode evaluation if best of inter is skip except when source
  // variance is extremely low
  if (sf->intra_sf.skip_intra_in_interframe &&
      (x->source_variance > sf->intra_sf.src_var_thresh_intra_skip)) {
    if (inter_cost >= 0 && intra_cost >= 0) {
      avm_clear_system_state();
      const NN_CONFIG *nn_config = (AVMMIN(cm->width, cm->height) <= 480)
                                       ? &av2_intrap_nn_config
                                       : &av2_intrap_hd_nn_config;
      float nn_features[6];
      float scores[2] = { 0.0f };
      float probs[2] = { 0.0f };
      nn_features[0] = (float)search_state.best_mbmode
                           .skip_txfm[xd->tree_type != CHROMA_PART ? 0 : 1];
      nn_features[1] = (float)mi_size_wide_log2[bsize];
      nn_features[2] = (float)mi_size_high_log2[bsize];
      nn_features[3] = (float)intra_cost;
      nn_features[4] = (float)inter_cost;
      const int ac_q = av2_ac_quant_QTX(x->qindex, 0, 0, xd->bd);
      const int ac_q_max = av2_ac_quant_QTX(255, 0, 0, xd->bd);
      nn_features[5] = (float)(ac_q_max / ac_q);

      av2_nn_predict(nn_features, nn_config, 1, scores);
      avm_clear_system_state();
      av2_nn_softmax(scores, probs, 2);

      if (probs[1] > 0.8) search_state.intra_search_state.skip_intra_modes = 1;
    } else if ((search_state.best_mbmode
                    .skip_txfm[xd->tree_type == CHROMA_PART]) &&
               (sf->intra_sf.skip_intra_in_interframe >= 2)) {
      search_state.intra_search_state.skip_intra_modes = 1;
    }
  }

  const unsigned int intra_ref_frame_cost = ref_costs_single[INTRA_FRAME_INDEX];
  int64_t best_model_rd = INT64_MAX;
  int64_t top_intra_model_rd[TOP_INTRA_MODEL_COUNT];
  for (i = 0; i < TOP_INTRA_MODEL_COUNT; i++) {
    top_intra_model_rd[i] = INT64_MAX;
  }

  get_y_intra_mode_set(mbmi, xd);

  int is_intra_mode_allowed = 1;
  if (mbmi->tree_type == SHARED_PART &&
      mbmi->region_type == MIXED_INTER_INTRA_REGION &&
      mbmi->chroma_ref_info.offset_started) {
    is_intra_mode_allowed = 0;
  }

  int dpcm_loop_num = 1;
  if (xd->lossless[mbmi->segment_id]) {
    dpcm_loop_num = 2;
  }
  mbmi->dpcm_mode_y = 0;
  // mbmi->dpcm_angle_delta = 0;
  for (int dpcm_idx = 0; dpcm_idx < dpcm_loop_num; dpcm_idx++) {
    mbmi->use_dpcm_y = dpcm_idx;
    for (int fsc_mode = 0;
         fsc_mode < (allow_fsc_intra(cm, bsize, mbmi) ? FSC_MODES : 1);
         fsc_mode++) {
      uint8_t enable_mrls_flag = cm->seq_params.enable_mrls && !fsc_mode;
      ModeRDInfoUV mode_rd_info_uv = { { false }, { 0 }, { 0 } };
      // When fsc_mode is enabled, rate of the chroma mode across luma modes is
      // different. Hence, the reuse of chroma mode rd_info is not applicable
      // when fsc_mode enabled.
      if (!xd->lossless[mbmi->segment_id]) {
        av2_zero(mode_rd_info_uv.mode_evaluated);
      }
      for (int mrl_index = 0;
           mrl_index < (enable_mrls_flag ? MRL_LINE_NUMBER : 1); mrl_index++) {
        for (int multi_line_mrl = 0; multi_line_mrl < (mrl_index ? 2 : 1);
             multi_line_mrl++) {
          mbmi->multi_line_mrl = multi_line_mrl;
          mbmi->fsc_mode[xd->tree_type == CHROMA_PART] = fsc_mode;
          mbmi->mrl_index = mrl_index;
          if (!is_intra_mode_allowed) break;
          for (int mode_idx = INTRA_MODE_START; mode_idx < LUMA_MODE_COUNT;
               ++mode_idx) {
            if (sf->intra_sf.skip_intra_in_interframe &&
                search_state.intra_search_state.skip_intra_modes)
              break;
            mbmi->y_mode_idx = mode_idx;
            mbmi->joint_y_mode_delta_angle = mbmi->y_intra_mode_list[mode_idx];
            av2_set_y_mode_and_delta_angle(mbmi->joint_y_mode_delta_angle,
                                           mbmi);
            if ((!cpi->oxcf.intra_mode_cfg.enable_smooth_intra ||
                 cpi->sf.intra_sf.disable_smooth_intra) &&
                (mbmi->mode == SMOOTH_PRED || mbmi->mode == SMOOTH_H_PRED ||
                 mbmi->mode == SMOOTH_V_PRED))
              continue;
            if (!cpi->oxcf.intra_mode_cfg.enable_paeth_intra &&
                mbmi->mode == PAETH_PRED)
              continue;
            if (mbmi->mrl_index > 0 &&
                av2_is_directional_mode(mbmi->mode) == 0) {
              continue;
            }
            if (!allow_fsc_intra(cm, bsize, mbmi) &&
                mbmi->fsc_mode[PLANE_TYPE_Y] > 0) {
              continue;
            }
            if (mbmi->mrl_index > 0 && mbmi->fsc_mode[PLANE_TYPE_Y]) {
              continue;
            }
            if (((search_state.intra_search_state.best_mrl_index == 0 &&
                  av2_is_directional_mode(
                      search_state.intra_search_state.best_intra_mode) == 0) ||
                 (search_state.intra_search_state.best_mrl_index &&
                  search_state.intra_search_state.best_multi_line_mrl == 0)) &&
                mbmi->mrl_index > 1 && mbmi->multi_line_mrl) {
              continue;
            }
            const MB_MODE_INFO *cached_mi = x->inter_mode_cache[0];
            if (cached_mi) {
              const PREDICTION_MODE cached_mode = cached_mi->mode;
              if (should_reuse_mode(x, REUSE_INTRA_MODE_IN_INTERFRAME_FLAG) &&
                  is_mode_intra(cached_mode) && mbmi->mode != cached_mode) {
                continue;
              }
              if (should_reuse_mode(x, REUSE_INTER_MODE_IN_INTERFRAME_FLAG) &&
                  !is_mode_intra(cached_mode)) {
                continue;
              }
            }

            if (dpcm_idx > 0 &&
                (mrl_index > 0 ||
                 (mbmi->mode != V_PRED && mbmi->mode != H_PRED) ||
                 ((mbmi->mode == V_PRED || mbmi->mode == H_PRED) &&
                  mbmi->angle_delta[0] != 0))) {
              continue;
            }
            if (fsc_mode == 1 && dpcm_idx > 0 &&
                ((mbmi->mode != V_PRED && mbmi->mode != H_PRED) ||
                 (mbmi->angle_delta[0] != 0))) {
              continue;
            }
            const PREDICTION_MODE this_mode = mbmi->mode;

            MV_REFERENCE_FRAME refs[2] = { INTRA_FRAME, NONE_FRAME };

            init_mbmi(mbmi, this_mode, refs, cm, xd, xd->sbi);
            txfm_info->skip_txfm = 0;

            if (mbmi->use_dpcm_y > 0 &&
                (mbmi->mode == V_PRED || mbmi->mode == H_PRED) &&
                mbmi->angle_delta[0] == 0) {
              mbmi->dpcm_mode_y = mbmi->mode - 1;
            }
            RD_STATS intra_rd_stats, intra_rd_stats_y, intra_rd_stats_uv;
            intra_rd_stats.rdcost = av2_handle_intra_mode(
                &search_state.intra_search_state, cpi, x, bsize,
                intra_ref_frame_cost, ctx, &intra_rd_stats, &intra_rd_stats_y,
                &intra_rd_stats_uv, &mode_rd_info_uv, search_state.best_rd,
                &search_state.best_intra_rd, &best_model_rd,
                top_intra_model_rd);

            // Collect mode stats for multiwinner mode processing
            const int txfm_search_done = 1;
            store_winner_mode_stats(
                &cpi->common, x, mbmi, &intra_rd_stats, &intra_rd_stats_y,
                &intra_rd_stats_uv, refs, this_mode, NULL, bsize,
                intra_rd_stats.rdcost,
                cpi->sf.winner_mode_sf.multi_winner_mode_type,
                txfm_search_done);
            if (intra_rd_stats.rdcost < search_state.best_rd) {
              update_search_state(&search_state, rd_cost, ctx, &intra_rd_stats,
                                  &intra_rd_stats_y, &intra_rd_stats_uv,
                                  this_mode, x, txfm_search_done, cm);
            }
          }

          set_mv_precision(mbmi, mbmi->max_mv_precision);
        }
      }
    }
  }
#if CONFIG_COLLECT_COMPONENT_TIMING
  end_timing(cpi, handle_intra_mode_time);
#endif

  int winner_mode_count =
      cpi->sf.winner_mode_sf.multi_winner_mode_type ? x->winner_mode_count : 1;
  // In effect only when fast tx search speed features are enabled.
  refine_winner_mode_tx(cpi, x, rd_cost, bsize, ctx, &search_state.best_mbmode,
                        yv12_mb, search_state.best_rate_y,
                        search_state.best_rate_uv, &search_state.best_skip2,
                        winner_mode_count);

  // Initialize default mode evaluation params
  set_mode_eval_params(cpi, x, DEFAULT_EVAL);

  // Only try palette mode when the best mode so far is an intra mode.
  const int try_palette =
      cpi->oxcf.tool_cfg.enable_palette &&
      av2_allow_palette(PLANE_TYPE_Y, features->allow_screen_content_tools,
                        mbmi->sb_type[PLANE_TYPE_Y]) &&
      !is_inter_mode(search_state.best_mbmode.mode) && rd_cost->rate < INT_MAX;
  int search_palette_mode = try_palette;
  const MB_MODE_INFO *cached_mode = x->inter_mode_cache[0];
  if (should_reuse_mode(x, REUSE_INTRA_MODE_IN_INTERFRAME_FLAG) &&
      cached_mode &&
      !(cached_mode->mode == DC_PRED &&
        cached_mode->palette_mode_info.palette_size[0] > 0)) {
    search_palette_mode = 0;
  }
  RD_STATS this_rd_cost;
  int this_skippable = 0;
  if (search_palette_mode && is_intra_mode_allowed) {
    this_skippable = av2_search_palette_mode(
        &search_state.intra_search_state, cpi, x, bsize, intra_ref_frame_cost,
        ctx, &this_rd_cost, search_state.best_rd);
    if (this_rd_cost.rdcost < search_state.best_rd) {
      mbmi->mv[0].as_int = 0;
      rd_cost->rate = this_rd_cost.rate;
      rd_cost->dist = this_rd_cost.dist;
      rd_cost->rdcost = this_rd_cost.rdcost;
      search_state.best_rd = rd_cost->rdcost;
      search_state.best_mbmode = *mbmi;
      search_state.best_skip2 = 0;
      search_state.best_mode_skippable = this_skippable;
      for (i = 0; i < num_planes; ++i) {
        const int num_blk_plane =
            (i == AVM_PLANE_Y) ? ctx->num_4x4_blk : ctx->num_4x4_blk_chroma;
        memcpy(ctx->blk_skip[i], txfm_info->blk_skip[i],
               sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
      }
      av2_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
      av2_copy_array(ctx->cctx_type_map, xd->cctx_type_map,
                     ctx->num_4x4_blk_chroma);
    }
  }

  search_state.best_mbmode.skip_mode = 0;
  if (is_skip_mode_allowed(cm, xd)) {
    rd_pick_skip_mode(&search_state, cpi, x, bsize, yv12_mb, ctx, rd_cost);
  }

  if (search_state.best_skip2 == 0) {
    const int try_intrabc = cpi->oxcf.kf_cfg.enable_intrabc &&
                            cpi->oxcf.kf_cfg.enable_intrabc_ext &&
                            !sf->inter_sf.skip_eval_intrabc_in_inter_frame &&
                            av2_allow_intrabc(cm, xd, bsize

                                              ) &&
                            (xd->tree_type != CHROMA_PART);
    if (try_intrabc && is_intra_mode_allowed) {
      this_rd_cost.rdcost = INT64_MAX;
      mbmi->ref_frame[0] = INTRA_FRAME;
      mbmi->ref_frame[1] = NONE_FRAME;
      mbmi->use_intrabc[xd->tree_type == CHROMA_PART] = 0;
      mbmi->mv[0].as_int = 0;
      mbmi->skip_mode = 0;
      mbmi->mode = 0;
      mbmi->motion_mode = SIMPLE_TRANSLATION;
      mbmi->warp_ref_idx = 0;
      mbmi->max_num_warp_candidates = 0;
      mbmi->warpmv_with_mvd_flag = 0;
      mbmi->morph_pred = 0;
      mbmi->six_param_warp_model_flag = 0;
      mbmi->warp_precision_idx = 0;

      mbmi->warp_inter_intra = 0;
      rd_pick_intrabc_mode_sb(cpi, x, ctx, &this_rd_cost, bsize, INT64_MAX);

      if (this_rd_cost.rdcost < search_state.best_rd) {
        rd_cost->rate = this_rd_cost.rate;
        rd_cost->dist = this_rd_cost.dist;
        rd_cost->rdcost = this_rd_cost.rdcost;

        search_state.best_rd = rd_cost->rdcost;
        search_state.best_mbmode = *mbmi;
        search_state.best_skip2 = mbmi->skip_txfm[xd->tree_type == CHROMA_PART];
        search_state.best_mode_skippable =
            mbmi->skip_txfm[xd->tree_type == CHROMA_PART];

        for (i = 0; i < num_planes; ++i) {
          const int num_blk_plane =
              (i == AVM_PLANE_Y) ? ctx->num_4x4_blk : ctx->num_4x4_blk_chroma;
          memcpy(ctx->blk_skip[i], txfm_info->blk_skip[i],
                 sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
        }
        av2_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
        av2_copy_array(ctx->cctx_type_map, xd->cctx_type_map,
                       ctx->num_4x4_blk_chroma);
        ctx->rd_stats.skip_txfm = mbmi->skip_txfm[xd->tree_type == CHROMA_PART];
      }
    }
  }

  // Make sure that the ref_mv_idx is only nonzero when we're
  // using a mode which can support ref_mv_idx
  if ((search_state.best_mbmode.ref_mv_idx[0] != 0 ||
       search_state.best_mbmode.ref_mv_idx[1] != 0) &&
      !(have_newmv_in_each_reference(search_state.best_mbmode.mode) ||
        is_joint_mvd_coding_mode(search_state.best_mbmode.mode) ||
        have_nearmv_in_inter_mode(search_state.best_mbmode.mode))) {
    search_state.best_mbmode.ref_mv_idx[0] = 0;
    search_state.best_mbmode.ref_mv_idx[1] = 0;
  }

  if (search_state.best_mbmode.mode == MODE_INVALID ||
      search_state.best_rd >= best_rd_so_far) {
    rd_cost->rate = INT_MAX;
    rd_cost->rdcost = INT64_MAX;
    return;
  }

  const InterpFilter interp_filter = features->interp_filter;
  (void)interp_filter;
  // TODO(any): Fix issue !92 and re-enable the assert below
  // assert((interp_filter == SWITCHABLE) ||
  //        (interp_filter == search_state.best_mbmode.interp_fltr) ||
  //        !is_inter_block(&search_state.best_mbmode, xd->tree_type));

  if (!cpi->rc.is_src_frame_alt_ref && cpi->sf.inter_sf.adaptive_rd_thresh) {
    av2_update_rd_thresh_fact(cm, x->thresh_freq_fact,
                              sf->inter_sf.adaptive_rd_thresh, bsize,
                              search_state.best_mbmode.mode);
  }
  // macroblock modes
  *mbmi = search_state.best_mbmode;
  if (is_warp_mode(mbmi->motion_mode)) {
    update_submi(xd, cm, search_state.best_submb, bsize);
  }
  assert(av2_check_newmv_joint_nonzero(cm, x));

  assert(check_mv_precision(cm, mbmi, x));

  txfm_info->skip_txfm |= search_state.best_skip2;

  // Note: this section is needed since the mode may have been forced to
  // GLOBALMV by the all-zero mode handling of ref-mv.
  if (mbmi->mode == GLOBALMV || mbmi->mode == GLOBAL_GLOBALMV) {
    // Correct the interp filters for GLOBALMV
    if (is_nontrans_global_motion(xd, xd->mi[0])) {
      assert(mbmi->interp_fltr == av2_unswitchable_filter(interp_filter));
    }
  }

  for (i = 0; i < REFERENCE_MODES; ++i) {
    if (search_state.intra_search_state.best_pred_rd[i] == INT64_MAX) {
      search_state.best_pred_diff[i] = INT_MIN;
    } else {
      search_state.best_pred_diff[i] =
          search_state.best_rd -
          search_state.intra_search_state.best_pred_rd[i];
    }
  }

  assert(check_mv_precision(cm, mbmi, x));

  txfm_info->skip_txfm |= search_state.best_mode_skippable;

  assert(search_state.best_mbmode.mode != MODE_INVALID);

  if (mbmi->motion_mode == WARP_DELTA) {
    // Rebuild the warp candidate list with the best coding results
    av2_find_warp_delta_base_candidates(
        xd, mbmi,
        x->mbmi_ext->warp_param_stack[av2_ref_frame_type(mbmi->ref_frame)],
        xd->warp_param_stack[av2_ref_frame_type(mbmi->ref_frame)],
        xd->valid_num_warp_candidates[av2_ref_frame_type(mbmi->ref_frame)],
        NULL);
  }

  store_coding_context(x, ctx, search_state.best_pred_diff,
                       search_state.best_mode_skippable, cm);

  // TODO(urvang): Remove index from `palette_size` array, as palette is no
  // longer allowed for chroma.
  assert(mbmi->palette_mode_info.palette_size[1] == 0);
}

void av2_rd_pick_inter_mode_sb_seg_skip(const AV2_COMP *cpi,
                                        TileDataEnc *tile_data, MACROBLOCK *x,
                                        int mi_row, int mi_col,
                                        RD_STATS *rd_cost, BLOCK_SIZE bsize,
                                        PICK_MODE_CONTEXT *ctx,
                                        int64_t best_rd_so_far) {
  const AV2_COMMON *const cm = &cpi->common;
  const FeatureFlags *const features = &cm->features;
  MACROBLOCKD *const xd = &x->e_mbd;
  MB_MODE_INFO *const mbmi = xd->mi[0];
  unsigned char segment_id = mbmi->segment_id;
  const int comp_pred = 0;
  int i;
  int64_t best_pred_diff[REFERENCE_MODES];
  unsigned int ref_costs_single[SINGLE_REF_FRAMES];
  unsigned int ref_costs_comp[MAX_COMPOUND_REF_INDEX][MAX_COMPOUND_REF_INDEX];
  const ModeCosts *mode_costs = &x->mode_costs;
  const int *comp_inter_cost =
      mode_costs->comp_inter_cost[av2_get_reference_mode_context(cm, xd)];
  InterpFilter best_filter = SWITCHABLE;
  int64_t this_rd = INT64_MAX;
  int rate2 = 0;
  const int64_t distortion2 = 0;
  (void)mi_row;
  (void)mi_col;
  (void)tile_data;

  av2_collect_neighbors_ref_counts(xd);

  estimate_ref_frame_costs(cm, xd, mode_costs, segment_id, ref_costs_single,
                           ref_costs_comp);
  for (i = 0; i < MAX_COMPOUND_REF_INDEX; ++i) x->pred_sse[i] = INT_MAX;
  for (i = 0; i < MAX_COMPOUND_REF_INDEX; ++i) x->pred_mv_sad[i] = INT_MAX;

  x->pred_sse[TIP_FRAME_INDEX] = INT_MAX;
  x->pred_mv_sad[TIP_FRAME_INDEX] = INT_MAX;
  rd_cost->rate = INT_MAX;

  assert(segfeature_active(&cm->seg, segment_id, SEG_LVL_SKIP));

  // Reset skip mode flag.
  mbmi->skip_mode = 0;
  mbmi->palette_mode_info.palette_size[0] = 0;
  mbmi->palette_mode_info.palette_size[1] = 0;
  mbmi->use_intra_dip = 0;
  mbmi->mode = GLOBALMV;
  mbmi->motion_mode = SIMPLE_TRANSLATION;
  mbmi->uv_mode = UV_DC_PRED;
  const MV_REFERENCE_FRAME last_frame = get_closest_pastcur_ref_or_ref0(cm);
  mbmi->ref_frame[0] = last_frame;
  mbmi->ref_frame[1] = NONE_FRAME;
  if (is_tip_ref_frame(mbmi->ref_frame[0])) {
    mbmi->mv[0].as_int = 0;
  } else {
    mbmi->mv[0].as_int =

        get_warp_motion_vector(xd, &cm->global_motion[mbmi->ref_frame[0]],
                               features->fr_mv_precision, bsize, mi_col, mi_row)

            .as_int;
  }
  mbmi->tx_size = max_txsize_lookup[bsize];
  x->txfm_search_info.skip_txfm = 1;
  mbmi->ref_mv_idx[0] = 0;
  mbmi->ref_mv_idx[1] = 0;
  mbmi->cwp_idx = CWP_EQUAL;

  mbmi->motion_mode = SIMPLE_TRANSLATION;

  set_default_max_mv_precision(mbmi, xd->sbi->sb_mv_precision);
  set_mv_precision(mbmi, mbmi->max_mv_precision);
  set_default_precision_set(cm, mbmi, bsize);
  set_most_probable_mv_precision(cm, mbmi, bsize);

  mbmi->bawp_flag[0] = 0;
  mbmi->bawp_flag[1] = 0;
  mbmi->refinemv_flag = 0;

  assert(xd->sbi->sb_active_mode == BRU_ACTIVE_SB);

  if (is_motion_variation_allowed_bsize(bsize, xd->mi_row, xd->mi_col) &&
      (!has_second_ref(mbmi) ||
       is_compound_warp_causal_allowed(cm, xd, mbmi))) {
    int pts0[SAMPLES_ARRAY_SIZE], pts0_inref[SAMPLES_ARRAY_SIZE];
    mbmi->num_proj_ref[0] = av2_findSamples(cm, xd, pts0, pts0_inref, 0);
    if (has_second_ref(mbmi)) {
      int pts1[SAMPLES_ARRAY_SIZE], pts1_inref[SAMPLES_ARRAY_SIZE];
      mbmi->num_proj_ref[1] = av2_findSamples(cm, xd, pts1, pts1_inref, 1);
    }
  }

  assert(check_mv_precision(cm, mbmi, x));

  const InterpFilter interp_filter = features->interp_filter;
  set_default_interp_filters(mbmi, cm, xd, interp_filter);

  if (interp_filter != SWITCHABLE) {
    best_filter = interp_filter;
  } else {
    best_filter = EIGHTTAP_REGULAR;
    if (av2_is_interp_needed(cm, xd)) {
      int rs;
      int best_rs = INT_MAX;
      for (i = 0; i < SWITCHABLE_FILTERS; ++i) {
        mbmi->interp_fltr = i;
        rs = av2_get_switchable_rate(x, xd, interp_filter);
        if (rs < best_rs) {
          best_rs = rs;
          best_filter = i;
        }
      }
    }
  }
  // Set the appropriate filter
  mbmi->interp_fltr = best_filter;
  rate2 += av2_get_switchable_rate(x, xd, interp_filter);

  if (cm->current_frame.reference_mode == REFERENCE_MODE_SELECT)
    rate2 += comp_inter_cost[comp_pred];

  // Estimate the reference frame signaling cost and add it
  // to the rolling cost variable.

  rate2 += ref_costs_single[last_frame];
  this_rd = RDCOST(x->rdmult, rate2, distortion2);

  rd_cost->rate = rate2;
  rd_cost->dist = distortion2;
  rd_cost->rdcost = this_rd;

  if (this_rd >= best_rd_so_far) {
    rd_cost->rate = INT_MAX;
    rd_cost->rdcost = INT64_MAX;
    return;
  }

  assert((interp_filter == SWITCHABLE) || (interp_filter == mbmi->interp_fltr));

  if (cpi->sf.inter_sf.adaptive_rd_thresh) {
    av2_update_rd_thresh_fact(cm, x->thresh_freq_fact,
                              cpi->sf.inter_sf.adaptive_rd_thresh, bsize,
                              GLOBALMV);
  }

  av2_zero(best_pred_diff);

  store_coding_context(x, ctx, best_pred_diff, 0, cm);
}

/* Use standard 3x3 Sobel matrix. Macro so it can be used for either high or
   low bit-depth arrays. */
#define SOBEL_X(src, stride, i, j)                        \
  ((src)[((i) - 1) + (stride) * ((j) - 1)] -              \
   (src)[((i) + 1) + (stride) * ((j) - 1)] + /* NOLINT */ \
   2 * (src)[((i) - 1) + (stride) * (j)] -   /* NOLINT */ \
   2 * (src)[((i) + 1) + (stride) * (j)] +   /* NOLINT */ \
   (src)[((i) - 1) + (stride) * ((j) + 1)] - /* NOLINT */ \
   (src)[((i) + 1) + (stride) * ((j) + 1)])  /* NOLINT */
#define SOBEL_Y(src, stride, i, j)                        \
  ((src)[((i) - 1) + (stride) * ((j) - 1)] +              \
   2 * (src)[(i) + (stride) * ((j) - 1)] +   /* NOLINT */ \
   (src)[((i) + 1) + (stride) * ((j) - 1)] - /* NOLINT */ \
   (src)[((i) - 1) + (stride) * ((j) + 1)] - /* NOLINT */ \
   2 * (src)[(i) + (stride) * ((j) + 1)] -   /* NOLINT */ \
   (src)[((i) + 1) + (stride) * ((j) + 1)])  /* NOLINT */

sobel_xy av2_sobel(const uint16_t *src, int stride, int i, int j) {
  int16_t s_x;
  int16_t s_y;
  s_x = SOBEL_X(src, stride, i, j);
  s_y = SOBEL_Y(src, stride, i, j);
  sobel_xy r = { .x = s_x, .y = s_y };
  return r;
}

// 8-tap Gaussian convolution filter with sigma = 1.3, sums to 128,
// all co-efficients must be even.
DECLARE_ALIGNED(16, static const int16_t, gauss_filter[8]) = { 2,  12, 30, 40,
                                                               30, 12, 2,  0 };

void av2_gaussian_blur(const uint16_t *src, int src_stride, int w, int h,
                       uint16_t *dst, int bd) {
  ConvolveParams conv_params = get_conv_params(0, 0, bd);
  InterpFilterParams filter = { .filter_ptr = gauss_filter,
                                .taps = 8,
                                .interp_filter = EIGHTTAP_REGULAR };
  // Requirements from the vector-optimized implementations.
  assert(h % 4 == 0);
  assert(w % 8 == 0);
  // Because we use an eight tap filter, the stride should be at least 7 + w.
  assert(src_stride >= w + 7);
  av2_highbd_convolve_2d_sr(src, src_stride, dst, w, w, h, &filter, &filter, 0,
                            0, &conv_params, bd);
}

static EdgeInfo edge_probability(const uint16_t *input, int w, int h, int bd) {
  assert(bd == 8 || bd == 10 || bd == 12);
  // The probability of an edge in the whole image is the same as the highest
  // probability of an edge for any individual pixel. Use Sobel as the metric
  // for finding an edge.
  uint16_t highest = 0;
  uint16_t highest_x = 0;
  uint16_t highest_y = 0;
  // Ignore the 1 pixel border around the image for the computation.
  for (int j = 1; j < h - 1; ++j) {
    for (int i = 1; i < w - 1; ++i) {
      sobel_xy g = av2_sobel(input, w, i, j);
      // Scale down to 8-bit to get same output regardless of bit depth.
      int16_t g_x = g.x >> (bd - 8);
      int16_t g_y = g.y >> (bd - 8);
      uint16_t magnitude = (uint16_t)sqrt(g_x * g_x + g_y * g_y);
      highest = AVMMAX(highest, magnitude);
      highest_x = AVMMAX(highest_x, g_x);
      highest_y = AVMMAX(highest_y, g_y);
    }
  }
  EdgeInfo ei = { .magnitude = highest, .x = highest_x, .y = highest_y };
  return ei;
}

/* Uses most of the Canny edge detection algorithm to find if there are any
 * edges in the image.
 */
EdgeInfo av2_edge_exists(const uint16_t *src, int src_stride, int w, int h,
                         int bd) {
  if (w < 3 || h < 3) {
    EdgeInfo n = { .magnitude = 0, .x = 0, .y = 0 };
    return n;
  }
  uint16_t *blurred = avm_memalign(32, sizeof(uint16_t) * w * h);
  av2_gaussian_blur(src, src_stride, w, h, blurred, bd);
  // Skip the non-maximum suppression step in Canny edge detection. We just
  // want a probability of an edge existing in the buffer, which is determined
  // by the strongest edge in it -- we don't need to eliminate the weaker
  // edges. Use Sobel for the edge detection.
  EdgeInfo prob = edge_probability(blurred, w, h, bd);
  avm_free(blurred);
  return prob;
}
