handle_inter_mode: Motion mode RD calc to function

Refactors the end of handle_inter_mode into a new funciton. This code
is responsible for calculating an accurate RD for the SIMPLE_TRANSLATION
motion mode in the simplest case, and does the same for other motion
modes as their experiments are enabled.

This patch aims to do as little as possible to the code inside the
function - that is left to later patches to reduce the complexity of
this diff.

Change-Id: I62bf5aae34594b0a1dc4813aeba99e675d6db374
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index a6c3207..9157e5c 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -8184,12 +8184,405 @@
   return 0;
 }
 
+// TODO(afergs): Refactor the MBMI references in here - there's four
+// TODO(afergs): Refactor optional args - add them to a struct or remove
+static int64_t motion_mode_rd(
+    const AV1_COMP *const cpi, MACROBLOCK *const x, BLOCK_SIZE bsize,
+    RD_STATS *rd_stats, RD_STATS *rd_stats_y, RD_STATS *rd_stats_uv,
+    int *disable_skip, int_mv (*mode_mv)[TOTAL_REFS_PER_FRAME], int mi_row,
+    int mi_col, HandleInterModeArgs *const args, const int64_t ref_best_rd,
+    const int *refs, int rate_mv,
+#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+#if CONFIG_EXT_INTER
+    int rate2_bmc_nocoeff, MB_MODE_INFO *best_bmc_mbmi,
+#if CONFIG_MOTION_VAR
+    int rate_mv_bmc,
+#endif  // CONFIG_MOTION_VAR
+#endif  // CONFIG_EXT_INTER
+#endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+    int rs, int *skip_txfm_sb, int64_t *skip_sse_sb, BUFFER_SET *orig_dst) {
+  const AV1_COMMON *const cm = &cpi->common;
+  MACROBLOCKD *xd = &x->e_mbd;
+  MODE_INFO *mi = xd->mi[0];
+  MB_MODE_INFO *mbmi = &mi->mbmi;
+  const int is_comp_pred = has_second_ref(mbmi);
+  const PREDICTION_MODE this_mode = mbmi->mode;
+
+  (void)mode_mv;
+  (void)mi_row;
+  (void)mi_col;
+  (void)args;
+  (void)refs;
+  (void)rate_mv;
+  (void)is_comp_pred;
+  (void)this_mode;
+
+#if CONFIG_EXT_INTER && CONFIG_MOTION_VAR
+  int mv_idx = (this_mode == NEWFROMNEARMV) ? 1 : 0;
+#endif  // CONFIG_EXT_INTER && CONFIG_MOTION_VAR
+
+#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+  MOTION_MODE motion_mode, last_motion_mode_allowed;
+  int rate2_nocoeff = 0, best_xskip, best_disable_skip = 0;
+  RD_STATS best_rd_stats, best_rd_stats_y, best_rd_stats_uv;
+  MB_MODE_INFO base_mbmi, best_mbmi;
+#if CONFIG_VAR_TX
+  uint8_t best_blk_skip[MAX_MB_PLANE][MAX_MIB_SIZE * MAX_MIB_SIZE * 4];
+#endif  // CONFIG_VAR_TX
+#endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+
+#if CONFIG_WARPED_MOTION
+  int pts[SAMPLES_ARRAY_SIZE], pts_inref[SAMPLES_ARRAY_SIZE];
+#endif  // CONFIG_WARPED_MOTION
+
+#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+  av1_invalid_rd_stats(&best_rd_stats);
+#endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+
+  if (cm->interp_filter == SWITCHABLE) rd_stats->rate += rs;
+#if CONFIG_WARPED_MOTION
+  aom_clear_system_state();
+  mbmi->num_proj_ref[0] = findSamples(cm, xd, mi_row, mi_col, pts, pts_inref);
+#if CONFIG_EXT_INTER
+  best_bmc_mbmi->num_proj_ref[0] = mbmi->num_proj_ref[0];
+#endif  // CONFIG_EXT_INTER
+#endif  // CONFIG_WARPED_MOTION
+#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+  rate2_nocoeff = rd_stats->rate;
+  last_motion_mode_allowed = motion_mode_allowed(
+#if CONFIG_GLOBAL_MOTION && SEPARATE_GLOBAL_MOTION
+      0, xd->global_motion,
+#endif  // CONFIG_GLOBAL_MOTION && SEPARATE_GLOBAL_MOTION
+      mi);
+  base_mbmi = *mbmi;
+#endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+
+#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+  int64_t best_rd = INT64_MAX;
+  for (motion_mode = SIMPLE_TRANSLATION;
+       motion_mode <= last_motion_mode_allowed; motion_mode++) {
+    int64_t tmp_rd = INT64_MAX;
+    int tmp_rate;
+    int64_t tmp_dist;
+#if CONFIG_EXT_INTER
+    int tmp_rate2 =
+        motion_mode != SIMPLE_TRANSLATION ? rate2_bmc_nocoeff : rate2_nocoeff;
+#else
+    int tmp_rate2 = rate2_nocoeff;
+#endif  // CONFIG_EXT_INTER
+
+    *mbmi = base_mbmi;
+    mbmi->motion_mode = motion_mode;
+#if CONFIG_MOTION_VAR
+    if (mbmi->motion_mode == OBMC_CAUSAL) {
+      assert_motion_mode_valid(OBMC_CAUSAL,
+#if CONFIG_GLOBAL_MOTION && SEPARATE_GLOBAL_MOTION
+                               0, cm->global_motion,
+#endif  // CONFIG_GLOBAL_MOTION && SEPARATE_GLOBAL_MOTION
+                               mi);
+#if CONFIG_EXT_INTER
+      *mbmi = *best_bmc_mbmi;
+      mbmi->motion_mode = OBMC_CAUSAL;
+#endif  // CONFIG_EXT_INTER
+      if (!is_comp_pred && have_newmv_in_inter_mode(this_mode)) {
+        int tmp_rate_mv = 0;
+
+        single_motion_search(cpi, x, bsize, mi_row, mi_col,
+#if CONFIG_EXT_INTER
+                             0, mv_idx,
+#endif  // CONFIG_EXT_INTER
+                             &tmp_rate_mv);
+        mbmi->mv[0].as_int = x->best_mv.as_int;
+        if (discount_newmv_test(cpi, this_mode, mbmi->mv[0], mode_mv,
+                                refs[0])) {
+          tmp_rate_mv = AOMMAX((tmp_rate_mv / NEW_MV_DISCOUNT_FACTOR), 1);
+        }
+#if CONFIG_EXT_INTER
+        tmp_rate2 = rate2_bmc_nocoeff - rate_mv_bmc + tmp_rate_mv;
+#else
+        tmp_rate2 = rate2_nocoeff - rate_mv + tmp_rate_mv;
+#endif  // CONFIG_EXT_INTER
+#if CONFIG_DUAL_FILTER
+        if (!has_subpel_mv_component(xd->mi[0], xd, 0))
+          mbmi->interp_filter[0] = EIGHTTAP_REGULAR;
+        if (!has_subpel_mv_component(xd->mi[0], xd, 1))
+          mbmi->interp_filter[1] = EIGHTTAP_REGULAR;
+#endif  // CONFIG_DUAL_FILTER
+        av1_build_inter_predictors_sb(xd, mi_row, mi_col, orig_dst, bsize);
+#if CONFIG_EXT_INTER
+      } else {
+        av1_build_inter_predictors_sb(xd, mi_row, mi_col, orig_dst, bsize);
+#endif  // CONFIG_EXT_INTER
+      }
+      av1_build_obmc_inter_prediction(
+          cm, xd, mi_row, mi_col, args->above_pred_buf, args->above_pred_stride,
+          args->left_pred_buf, args->left_pred_stride);
+      model_rd_for_sb(cpi, bsize, x, xd, 0, MAX_MB_PLANE - 1, &tmp_rate,
+                      &tmp_dist, skip_txfm_sb, skip_sse_sb);
+    }
+#endif  // CONFIG_MOTION_VAR
+
+#if CONFIG_WARPED_MOTION
+    if (mbmi->motion_mode == WARPED_CAUSAL) {
+      assert_motion_mode_valid(WARPED_CAUSAL,
+#if CONFIG_GLOBAL_MOTION && SEPARATE_GLOBAL_MOTION
+                               0, xd->global_motion,
+#endif  // CONFIG_GLOBAL_MOTION && SEPARATE_GLOBAL_MOTION
+                               mi);
+#if CONFIG_EXT_INTER
+      *mbmi = *best_bmc_mbmi;
+      mbmi->motion_mode = WARPED_CAUSAL;
+#endif  // CONFIG_EXT_INTER
+      mbmi->wm_params[0].wmtype = DEFAULT_WMTYPE;
+#if CONFIG_DUAL_FILTER
+      mbmi->interp_filter[0] = cm->interp_filter == SWITCHABLE
+                                   ? EIGHTTAP_REGULAR
+                                   : cm->interp_filter;
+      mbmi->interp_filter[1] = cm->interp_filter == SWITCHABLE
+                                   ? EIGHTTAP_REGULAR
+                                   : cm->interp_filter;
+#else
+      mbmi->interp_filter = cm->interp_filter == SWITCHABLE ? EIGHTTAP_REGULAR
+                                                            : cm->interp_filter;
+#endif  // CONFIG_DUAL_FILTER
+
+      if (find_projection(mbmi->num_proj_ref[0], pts, pts_inref,
+                          &mbmi->wm_params[0], mi_row, mi_col) == 0) {
+        int plane;
+        for (plane = 0; plane < 3; ++plane) {
+          const struct macroblockd_plane *pd = &xd->plane[plane];
+
+          av1_warp_plane(&mbmi->wm_params[0],
+#if CONFIG_AOM_HIGHBITDEPTH
+                         xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH, xd->bd,
+#endif  // CONFIG_AOM_HIGHBITDEPTH
+                         pd->pre[0].buf0, pd->pre[0].width, pd->pre[0].height,
+                         pd->pre[0].stride, pd->dst.buf,
+                         (mi_col * MI_SIZE) >> pd->subsampling_x,
+                         (mi_row * MI_SIZE) >> pd->subsampling_y,
+                         (xd->n8_w * MI_SIZE) >> pd->subsampling_x,
+                         (xd->n8_h * MI_SIZE) >> pd->subsampling_y,
+                         pd->dst.stride, pd->subsampling_x, pd->subsampling_y,
+                         16, 16, 0);
+        }
+
+        model_rd_for_sb(cpi, bsize, x, xd, 0, MAX_MB_PLANE - 1, &tmp_rate,
+                        &tmp_dist, skip_txfm_sb, skip_sse_sb);
+      } else {
+        continue;
+      }
+    }
+#endif  // CONFIG_WARPED_MOTION
+    x->skip = 0;
+
+    rd_stats->dist = 0;
+    rd_stats->sse = 0;
+    rd_stats->skip = 1;
+    rd_stats->rate = tmp_rate2;
+    if (last_motion_mode_allowed > SIMPLE_TRANSLATION) {
+#if CONFIG_WARPED_MOTION && CONFIG_MOTION_VAR
+      if (last_motion_mode_allowed == WARPED_CAUSAL)
+#endif  // CONFIG_WARPED_MOTION && CONFIG_MOTION_VAR
+        rd_stats->rate += cpi->motion_mode_cost[bsize][mbmi->motion_mode];
+#if CONFIG_WARPED_MOTION && CONFIG_MOTION_VAR
+      else
+        rd_stats->rate += cpi->motion_mode_cost1[bsize][mbmi->motion_mode];
+#endif  // CONFIG_WARPED_MOTION && CONFIG_MOTION_VAR
+    }
+#if CONFIG_WARPED_MOTION
+    if (mbmi->motion_mode == WARPED_CAUSAL) {
+      rd_stats->rate -= rs;
+    }
+#endif  // CONFIG_WARPED_MOTION
+#endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+    if (!*skip_txfm_sb) {
+      int64_t rdcosty = INT64_MAX;
+      int is_cost_valid_uv = 0;
+
+      // cost and distortion
+      av1_subtract_plane(x, bsize, 0);
+#if CONFIG_VAR_TX
+      if (cm->tx_mode == TX_MODE_SELECT && !xd->lossless[mbmi->segment_id]) {
+        select_tx_type_yrd(cpi, x, rd_stats_y, bsize, ref_best_rd);
+      } else {
+        int idx, idy;
+        super_block_yrd(cpi, x, rd_stats_y, bsize, ref_best_rd);
+        for (idy = 0; idy < xd->n8_h; ++idy)
+          for (idx = 0; idx < xd->n8_w; ++idx)
+            mbmi->inter_tx_size[idy][idx] = mbmi->tx_size;
+        memset(x->blk_skip[0], rd_stats_y->skip,
+               sizeof(uint8_t) * xd->n8_h * xd->n8_w * 4);
+      }
+#else
+    /* clang-format off */
+      super_block_yrd(cpi, x, rd_stats_y, bsize, ref_best_rd);
+/* clang-format on */
+#endif  // CONFIG_VAR_TX
+
+      if (rd_stats_y->rate == INT_MAX) {
+        av1_invalid_rd_stats(rd_stats);
+#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+        if (mbmi->motion_mode != SIMPLE_TRANSLATION) {
+          continue;
+        } else {
+#endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+          restore_dst_buf(xd, *orig_dst);
+          return INT64_MAX;
+#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+        }
+#endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+      }
+
+      av1_merge_rd_stats(rd_stats, rd_stats_y);
+
+      rdcosty = RDCOST(x->rdmult, x->rddiv, rd_stats->rate, rd_stats->dist);
+      rdcosty = AOMMIN(rdcosty, RDCOST(x->rdmult, x->rddiv, 0, rd_stats->sse));
+/* clang-format off */
+#if CONFIG_VAR_TX
+      is_cost_valid_uv =
+          inter_block_uvrd(cpi, x, rd_stats_uv, bsize, ref_best_rd - rdcosty);
+#else
+      is_cost_valid_uv =
+          super_block_uvrd(cpi, x, rd_stats_uv, bsize, ref_best_rd - rdcosty);
+#endif  // CONFIG_VAR_TX
+      if (!is_cost_valid_uv) {
+#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+        continue;
+#else
+        restore_dst_buf(xd, *orig_dst);
+        return INT64_MAX;
+#endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+      }
+      /* clang-format on */
+      av1_merge_rd_stats(rd_stats, rd_stats_uv);
+#if CONFIG_RD_DEBUG
+      // record transform block coefficient cost
+      // TODO(angiebird): So far rd_debug tool only detects discrepancy of
+      // coefficient cost. Therefore, it is fine to copy rd_stats into mbmi
+      // here because we already collect the coefficient cost. Move this part to
+      // other place when we need to compare non-coefficient cost.
+      mbmi->rd_stats = *rd_stats;
+#endif  // CONFIG_RD_DEBUG
+#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+      if (rd_stats->skip) {
+        rd_stats->rate -= rd_stats_uv->rate + rd_stats_y->rate;
+        rd_stats_y->rate = 0;
+        rd_stats_uv->rate = 0;
+        rd_stats->rate += av1_cost_bit(av1_get_skip_prob(cm, xd), 1);
+        mbmi->skip = 0;
+        // here mbmi->skip temporarily plays a role as what this_skip2 does
+      } else if (!xd->lossless[mbmi->segment_id] &&
+                 (RDCOST(x->rdmult, x->rddiv,
+                         rd_stats_y->rate + rd_stats_uv->rate +
+                             av1_cost_bit(av1_get_skip_prob(cm, xd), 0),
+                         rd_stats->dist) >=
+                  RDCOST(x->rdmult, x->rddiv,
+                         av1_cost_bit(av1_get_skip_prob(cm, xd), 1),
+                         rd_stats->sse))) {
+        rd_stats->rate -= rd_stats_uv->rate + rd_stats_y->rate;
+        rd_stats->rate += av1_cost_bit(av1_get_skip_prob(cm, xd), 1);
+        rd_stats->dist = rd_stats->sse;
+        rd_stats_y->rate = 0;
+        rd_stats_uv->rate = 0;
+        mbmi->skip = 1;
+      } else {
+        rd_stats->rate += av1_cost_bit(av1_get_skip_prob(cm, xd), 0);
+        mbmi->skip = 0;
+      }
+      *disable_skip = 0;
+#endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+    } else {
+      x->skip = 1;
+      *disable_skip = 1;
+      mbmi->tx_size = tx_size_from_tx_mode(bsize, cm->tx_mode, 1);
+
+// The cost of skip bit needs to be added.
+#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+      mbmi->skip = 0;
+#endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+      rd_stats->rate += av1_cost_bit(av1_get_skip_prob(cm, xd), 1);
+
+      rd_stats->dist = *skip_sse_sb;
+      rd_stats->sse = *skip_sse_sb;
+      rd_stats_y->rate = 0;
+      rd_stats_uv->rate = 0;
+      rd_stats->skip = 1;
+    }
+
+#if CONFIG_GLOBAL_MOTION
+    if (this_mode == ZEROMV
+#if CONFIG_EXT_INTER
+        || this_mode == ZERO_ZEROMV
+#endif  // CONFIG_EXT_INTER
+        ) {
+      rd_stats->rate += GLOBAL_MOTION_RATE(cpi, mbmi->ref_frame[0]);
+      if (is_comp_pred)
+        rd_stats->rate += GLOBAL_MOTION_RATE(cpi, mbmi->ref_frame[1]);
+      if (is_nontrans_global_motion(xd)) {
+        rd_stats->rate -= rs;
+#if CONFIG_DUAL_FILTER
+        mbmi->interp_filter[0] = cm->interp_filter == SWITCHABLE
+                                     ? EIGHTTAP_REGULAR
+                                     : cm->interp_filter;
+        mbmi->interp_filter[1] = cm->interp_filter == SWITCHABLE
+                                     ? EIGHTTAP_REGULAR
+                                     : cm->interp_filter;
+#else
+        mbmi->interp_filter = cm->interp_filter == SWITCHABLE
+                                  ? EIGHTTAP_REGULAR
+                                  : cm->interp_filter;
+#endif  // CONFIG_DUAL_FILTER
+      }
+    }
+#endif  // CONFIG_GLOBAL_MOTION
+
+#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+    tmp_rd = RDCOST(x->rdmult, x->rddiv, rd_stats->rate, rd_stats->dist);
+    if (mbmi->motion_mode == SIMPLE_TRANSLATION || (tmp_rd < best_rd)) {
+      best_mbmi = *mbmi;
+      best_rd = tmp_rd;
+      best_rd_stats = *rd_stats;
+      best_rd_stats_y = *rd_stats_y;
+      best_rd_stats_uv = *rd_stats_uv;
+#if CONFIG_VAR_TX
+      for (int i = 0; i < MAX_MB_PLANE; ++i)
+        memcpy(best_blk_skip[i], x->blk_skip[i],
+               sizeof(uint8_t) * xd->n8_h * xd->n8_w * 4);
+#endif  // CONFIG_VAR_TX
+      best_xskip = x->skip;
+      best_disable_skip = *disable_skip;
+    }
+  }
+
+  if (best_rd == INT64_MAX) {
+    av1_invalid_rd_stats(rd_stats);
+    restore_dst_buf(xd, *orig_dst);
+    return INT64_MAX;
+  }
+  *mbmi = best_mbmi;
+  *rd_stats = best_rd_stats;
+  *rd_stats_y = best_rd_stats_y;
+  *rd_stats_uv = best_rd_stats_uv;
+#if CONFIG_VAR_TX
+  for (int i = 0; i < MAX_MB_PLANE; ++i)
+    memcpy(x->blk_skip[i], best_blk_skip[i],
+           sizeof(uint8_t) * xd->n8_h * xd->n8_w * 4);
+#endif  // CONFIG_VAR_TX
+  x->skip = best_xskip;
+  *disable_skip = best_disable_skip;
+#endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
+
+  restore_dst_buf(xd, *orig_dst);
+  return 0;
+}
+
 static int64_t handle_inter_mode(
     const AV1_COMP *const cpi, MACROBLOCK *x, BLOCK_SIZE bsize,
     RD_STATS *rd_stats, RD_STATS *rd_stats_y, RD_STATS *rd_stats_uv,
     int *disable_skip, int_mv (*mode_mv)[TOTAL_REFS_PER_FRAME], int mi_row,
     int mi_col, HandleInterModeArgs *args, const int64_t ref_best_rd) {
   const AV1_COMMON *cm = &cpi->common;
+  (void)cm;
   MACROBLOCKD *xd = &x->e_mbd;
   MODE_INFO *mi = xd->mi[0];
   MB_MODE_INFO *mbmi = &mi->mbmi;
@@ -8224,14 +8617,6 @@
   uint8_t *tmp_buf;
 
 #if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-  MOTION_MODE motion_mode, last_motion_mode_allowed;
-  int rate2_nocoeff = 0, best_xskip, best_disable_skip = 0;
-  RD_STATS best_rd_stats, best_rd_stats_y, best_rd_stats_uv;
-#if CONFIG_VAR_TX
-  uint8_t best_blk_skip[MAX_MB_PLANE][MAX_MIB_SIZE * MAX_MIB_SIZE * 4];
-#endif  // CONFIG_VAR_TX
-  int64_t best_rd = INT64_MAX;
-  MB_MODE_INFO base_mbmi, best_mbmi;
 #if CONFIG_EXT_INTER
   int rate2_bmc_nocoeff;
   MB_MODE_INFO best_bmc_mbmi;
@@ -8240,9 +8625,6 @@
 #endif  // CONFIG_MOTION_VAR
 #endif  // CONFIG_EXT_INTER
 #endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-#if CONFIG_WARPED_MOTION
-  int pts[SAMPLES_ARRAY_SIZE], pts_inref[SAMPLES_ARRAY_SIZE];
-#endif  // CONFIG_WARPED_MOTION
   int64_t rd = INT64_MAX;
   BUFFER_SET orig_dst, tmp_dst;
   int rs = 0;
@@ -8250,9 +8632,6 @@
   int skip_txfm_sb = 0;
   int64_t skip_sse_sb = INT64_MAX;
   int16_t mode_ctx;
-#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-  av1_invalid_rd_stats(&best_rd_stats);
-#endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
 
 #if CONFIG_EXT_INTER
   *args->compmode_interintra_cost = 0;
@@ -8659,7 +9038,7 @@
                     dist_sum);
       best_interintra_rd_nowedge = rd;
 
-      // Disbale wedge search if source variance is small
+      // Disable wedge search if source variance is small
       if (x->source_variance > cpi->sf.disable_wedge_search_var_thresh) {
         mbmi->use_wedge_interintra = 1;
 
@@ -8782,340 +9161,20 @@
     }
   }
 
-  if (cm->interp_filter == SWITCHABLE) rd_stats->rate += rs;
-#if CONFIG_WARPED_MOTION
-  aom_clear_system_state();
-  mbmi->num_proj_ref[0] = findSamples(cm, xd, mi_row, mi_col, pts, pts_inref);
-#if CONFIG_EXT_INTER
-  best_bmc_mbmi.num_proj_ref[0] = mbmi->num_proj_ref[0];
-#endif  // CONFIG_EXT_INTER
-#endif  // CONFIG_WARPED_MOTION
+  ret_val = motion_mode_rd(cpi, x, bsize, rd_stats, rd_stats_y, rd_stats_uv,
+                           disable_skip, mode_mv, mi_row, mi_col, args,
+                           ref_best_rd, refs, rate_mv,
 #if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-  rate2_nocoeff = rd_stats->rate;
-  last_motion_mode_allowed = motion_mode_allowed(
-#if CONFIG_GLOBAL_MOTION && SEPARATE_GLOBAL_MOTION
-      0, xd->global_motion,
-#endif  // CONFIG_GLOBAL_MOTION && SEPARATE_GLOBAL_MOTION
-      mi);
-  base_mbmi = *mbmi;
-#endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-
-#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-  best_rd = INT64_MAX;
-  for (motion_mode = SIMPLE_TRANSLATION;
-       motion_mode <= last_motion_mode_allowed; motion_mode++) {
-    int64_t tmp_rd = INT64_MAX;
-    int tmp_rate;
-    int64_t tmp_dist;
 #if CONFIG_EXT_INTER
-    int tmp_rate2 =
-        motion_mode != SIMPLE_TRANSLATION ? rate2_bmc_nocoeff : rate2_nocoeff;
-#else
-    int tmp_rate2 = rate2_nocoeff;
-#endif  // CONFIG_EXT_INTER
-
-    *mbmi = base_mbmi;
-    mbmi->motion_mode = motion_mode;
+                           rate2_bmc_nocoeff, &best_bmc_mbmi,
 #if CONFIG_MOTION_VAR
-    if (mbmi->motion_mode == OBMC_CAUSAL) {
-      assert_motion_mode_valid(OBMC_CAUSAL,
-#if CONFIG_GLOBAL_MOTION && SEPARATE_GLOBAL_MOTION
-                               0, cm->global_motion,
-#endif  // CONFIG_GLOBAL_MOTION && SEPARATE_GLOBAL_MOTION
-                               mi);
-#if CONFIG_EXT_INTER
-      *mbmi = best_bmc_mbmi;
-      mbmi->motion_mode = OBMC_CAUSAL;
-#endif  // CONFIG_EXT_INTER
-      if (!is_comp_pred && have_newmv_in_inter_mode(this_mode)) {
-        int tmp_rate_mv = 0;
-
-        single_motion_search(cpi, x, bsize, mi_row, mi_col,
-#if CONFIG_EXT_INTER
-                             0, mv_idx,
-#endif  // CONFIG_EXT_INTER
-                             &tmp_rate_mv);
-        mbmi->mv[0].as_int = x->best_mv.as_int;
-        if (discount_newmv_test(cpi, this_mode, mbmi->mv[0], mode_mv,
-                                refs[0])) {
-          tmp_rate_mv = AOMMAX((tmp_rate_mv / NEW_MV_DISCOUNT_FACTOR), 1);
-        }
-#if CONFIG_EXT_INTER
-        tmp_rate2 = rate2_bmc_nocoeff - rate_mv_bmc + tmp_rate_mv;
-#else
-        tmp_rate2 = rate2_nocoeff - rate_mv + tmp_rate_mv;
-#endif  // CONFIG_EXT_INTER
-#if CONFIG_DUAL_FILTER
-        if (!has_subpel_mv_component(xd->mi[0], xd, 0))
-          mbmi->interp_filter[0] = EIGHTTAP_REGULAR;
-        if (!has_subpel_mv_component(xd->mi[0], xd, 1))
-          mbmi->interp_filter[1] = EIGHTTAP_REGULAR;
-#endif  // CONFIG_DUAL_FILTER
-        av1_build_inter_predictors_sb(xd, mi_row, mi_col, &orig_dst, bsize);
-#if CONFIG_EXT_INTER
-      } else {
-        av1_build_inter_predictors_sb(xd, mi_row, mi_col, &orig_dst, bsize);
-#endif  // CONFIG_EXT_INTER
-      }
-      av1_build_obmc_inter_prediction(
-          cm, xd, mi_row, mi_col, args->above_pred_buf, args->above_pred_stride,
-          args->left_pred_buf, args->left_pred_stride);
-      model_rd_for_sb(cpi, bsize, x, xd, 0, MAX_MB_PLANE - 1, &tmp_rate,
-                      &tmp_dist, &skip_txfm_sb, &skip_sse_sb);
-    }
+                           rate_mv_bmc,
 #endif  // CONFIG_MOTION_VAR
-
-#if CONFIG_WARPED_MOTION
-    if (mbmi->motion_mode == WARPED_CAUSAL) {
-      assert_motion_mode_valid(WARPED_CAUSAL,
-#if CONFIG_GLOBAL_MOTION && SEPARATE_GLOBAL_MOTION
-                               0, xd->global_motion,
-#endif  // CONFIG_GLOBAL_MOTION && SEPARATE_GLOBAL_MOTION
-                               mi);
-#if CONFIG_EXT_INTER
-      *mbmi = best_bmc_mbmi;
-      mbmi->motion_mode = WARPED_CAUSAL;
 #endif  // CONFIG_EXT_INTER
-      mbmi->wm_params[0].wmtype = DEFAULT_WMTYPE;
-#if CONFIG_DUAL_FILTER
-      mbmi->interp_filter[0] = cm->interp_filter == SWITCHABLE
-                                   ? EIGHTTAP_REGULAR
-                                   : cm->interp_filter;
-      mbmi->interp_filter[1] = cm->interp_filter == SWITCHABLE
-                                   ? EIGHTTAP_REGULAR
-                                   : cm->interp_filter;
-#else
-      mbmi->interp_filter = cm->interp_filter == SWITCHABLE ? EIGHTTAP_REGULAR
-                                                            : cm->interp_filter;
-#endif  // CONFIG_DUAL_FILTER
-
-      if (find_projection(mbmi->num_proj_ref[0], pts, pts_inref,
-                          &mbmi->wm_params[0], mi_row, mi_col) == 0) {
-        int plane;
-        for (plane = 0; plane < 3; ++plane) {
-          const struct macroblockd_plane *pd = &xd->plane[plane];
-
-          av1_warp_plane(&mbmi->wm_params[0],
-#if CONFIG_AOM_HIGHBITDEPTH
-                         xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH, xd->bd,
-#endif  // CONFIG_AOM_HIGHBITDEPTH
-                         pd->pre[0].buf0, pd->pre[0].width, pd->pre[0].height,
-                         pd->pre[0].stride, pd->dst.buf,
-                         (mi_col * MI_SIZE) >> pd->subsampling_x,
-                         (mi_row * MI_SIZE) >> pd->subsampling_y,
-                         (xd->n8_w * MI_SIZE) >> pd->subsampling_x,
-                         (xd->n8_h * MI_SIZE) >> pd->subsampling_y,
-                         pd->dst.stride, pd->subsampling_x, pd->subsampling_y,
-                         16, 16, 0);
-        }
-
-        model_rd_for_sb(cpi, bsize, x, xd, 0, MAX_MB_PLANE - 1, &tmp_rate,
-                        &tmp_dist, &skip_txfm_sb, &skip_sse_sb);
-      } else {
-        continue;
-      }
-    }
-#endif  // CONFIG_WARPED_MOTION
-    x->skip = 0;
-
-    rd_stats->dist = 0;
-    rd_stats->sse = 0;
-    rd_stats->skip = 1;
-    rd_stats->rate = tmp_rate2;
-    if (last_motion_mode_allowed > SIMPLE_TRANSLATION) {
-#if CONFIG_WARPED_MOTION && CONFIG_MOTION_VAR
-      if (last_motion_mode_allowed == WARPED_CAUSAL)
-#endif  // CONFIG_WARPED_MOTION && CONFIG_MOTION_VAR
-        rd_stats->rate += cpi->motion_mode_cost[bsize][mbmi->motion_mode];
-#if CONFIG_WARPED_MOTION && CONFIG_MOTION_VAR
-      else
-        rd_stats->rate += cpi->motion_mode_cost1[bsize][mbmi->motion_mode];
-#endif  // CONFIG_WARPED_MOTION && CONFIG_MOTION_VAR
-    }
-#if CONFIG_WARPED_MOTION
-    if (mbmi->motion_mode == WARPED_CAUSAL) {
-      rd_stats->rate -= rs;
-    }
-#endif  // CONFIG_WARPED_MOTION
 #endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-    if (!skip_txfm_sb) {
-      int64_t rdcosty = INT64_MAX;
-      int is_cost_valid_uv = 0;
+                           rs, &skip_txfm_sb, &skip_sse_sb, &orig_dst);
+  if (ret_val != 0) return ret_val;
 
-      // cost and distortion
-      av1_subtract_plane(x, bsize, 0);
-#if CONFIG_VAR_TX
-      if (cm->tx_mode == TX_MODE_SELECT && !xd->lossless[mbmi->segment_id]) {
-        select_tx_type_yrd(cpi, x, rd_stats_y, bsize, ref_best_rd);
-      } else {
-        int idx, idy;
-        super_block_yrd(cpi, x, rd_stats_y, bsize, ref_best_rd);
-        for (idy = 0; idy < xd->n8_h; ++idy)
-          for (idx = 0; idx < xd->n8_w; ++idx)
-            mbmi->inter_tx_size[idy][idx] = mbmi->tx_size;
-        memset(x->blk_skip[0], rd_stats_y->skip,
-               sizeof(uint8_t) * xd->n8_h * xd->n8_w * 4);
-      }
-#else
-    /* clang-format off */
-      super_block_yrd(cpi, x, rd_stats_y, bsize, ref_best_rd);
-/* clang-format on */
-#endif  // CONFIG_VAR_TX
-
-      if (rd_stats_y->rate == INT_MAX) {
-        av1_invalid_rd_stats(rd_stats);
-#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-        if (mbmi->motion_mode != SIMPLE_TRANSLATION) {
-          continue;
-        } else {
-#endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-          restore_dst_buf(xd, orig_dst);
-          return INT64_MAX;
-#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-        }
-#endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-      }
-
-      av1_merge_rd_stats(rd_stats, rd_stats_y);
-
-      rdcosty = RDCOST(x->rdmult, x->rddiv, rd_stats->rate, rd_stats->dist);
-      rdcosty = AOMMIN(rdcosty, RDCOST(x->rdmult, x->rddiv, 0, rd_stats->sse));
-/* clang-format off */
-#if CONFIG_VAR_TX
-      is_cost_valid_uv =
-          inter_block_uvrd(cpi, x, rd_stats_uv, bsize, ref_best_rd - rdcosty);
-#else
-      is_cost_valid_uv =
-          super_block_uvrd(cpi, x, rd_stats_uv, bsize, ref_best_rd - rdcosty);
-#endif  // CONFIG_VAR_TX
-      if (!is_cost_valid_uv) {
-#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-        continue;
-#else
-      restore_dst_buf(xd, orig_dst);
-      return INT64_MAX;
-#endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-      }
-      /* clang-format on */
-      av1_merge_rd_stats(rd_stats, rd_stats_uv);
-#if CONFIG_RD_DEBUG
-      // record transform block coefficient cost
-      // TODO(angiebird): So far rd_debug tool only detects discrepancy of
-      // coefficient cost. Therefore, it is fine to copy rd_stats into mbmi
-      // here because we already collect the coefficient cost. Move this part to
-      // other place when we need to compare non-coefficient cost.
-      mbmi->rd_stats = *rd_stats;
-#endif  // CONFIG_RD_DEBUG
-#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-      if (rd_stats->skip) {
-        rd_stats->rate -= rd_stats_uv->rate + rd_stats_y->rate;
-        rd_stats_y->rate = 0;
-        rd_stats_uv->rate = 0;
-        rd_stats->rate += av1_cost_bit(av1_get_skip_prob(cm, xd), 1);
-        mbmi->skip = 0;
-        // here mbmi->skip temporarily plays a role as what this_skip2 does
-      } else if (!xd->lossless[mbmi->segment_id] &&
-                 (RDCOST(x->rdmult, x->rddiv,
-                         rd_stats_y->rate + rd_stats_uv->rate +
-                             av1_cost_bit(av1_get_skip_prob(cm, xd), 0),
-                         rd_stats->dist) >=
-                  RDCOST(x->rdmult, x->rddiv,
-                         av1_cost_bit(av1_get_skip_prob(cm, xd), 1),
-                         rd_stats->sse))) {
-        rd_stats->rate -= rd_stats_uv->rate + rd_stats_y->rate;
-        rd_stats->rate += av1_cost_bit(av1_get_skip_prob(cm, xd), 1);
-        rd_stats->dist = rd_stats->sse;
-        rd_stats_y->rate = 0;
-        rd_stats_uv->rate = 0;
-        mbmi->skip = 1;
-      } else {
-        rd_stats->rate += av1_cost_bit(av1_get_skip_prob(cm, xd), 0);
-        mbmi->skip = 0;
-      }
-      *disable_skip = 0;
-#endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-    } else {
-      x->skip = 1;
-      *disable_skip = 1;
-      mbmi->tx_size = tx_size_from_tx_mode(bsize, cm->tx_mode, 1);
-
-// The cost of skip bit needs to be added.
-#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-      mbmi->skip = 0;
-#endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-      rd_stats->rate += av1_cost_bit(av1_get_skip_prob(cm, xd), 1);
-
-      rd_stats->dist = skip_sse_sb;
-      rd_stats->sse = skip_sse_sb;
-      rd_stats_y->rate = 0;
-      rd_stats_uv->rate = 0;
-      rd_stats->skip = 1;
-    }
-
-#if CONFIG_GLOBAL_MOTION
-    if (this_mode == ZEROMV
-#if CONFIG_EXT_INTER
-        || this_mode == ZERO_ZEROMV
-#endif  // CONFIG_EXT_INTER
-        ) {
-      rd_stats->rate += GLOBAL_MOTION_RATE(cpi, mbmi->ref_frame[0]);
-      if (is_comp_pred)
-        rd_stats->rate += GLOBAL_MOTION_RATE(cpi, mbmi->ref_frame[1]);
-      if (is_nontrans_global_motion(xd)) {
-        rd_stats->rate -= rs;
-#if CONFIG_DUAL_FILTER
-        mbmi->interp_filter[0] = cm->interp_filter == SWITCHABLE
-                                     ? EIGHTTAP_REGULAR
-                                     : cm->interp_filter;
-        mbmi->interp_filter[1] = cm->interp_filter == SWITCHABLE
-                                     ? EIGHTTAP_REGULAR
-                                     : cm->interp_filter;
-#else
-        mbmi->interp_filter = cm->interp_filter == SWITCHABLE
-                                  ? EIGHTTAP_REGULAR
-                                  : cm->interp_filter;
-#endif  // CONFIG_DUAL_FILTER
-      }
-    }
-#endif  // CONFIG_GLOBAL_MOTION
-
-#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-    tmp_rd = RDCOST(x->rdmult, x->rddiv, rd_stats->rate, rd_stats->dist);
-    if (mbmi->motion_mode == SIMPLE_TRANSLATION || (tmp_rd < best_rd)) {
-      best_mbmi = *mbmi;
-      best_rd = tmp_rd;
-      best_rd_stats = *rd_stats;
-      best_rd_stats_y = *rd_stats_y;
-      best_rd_stats_uv = *rd_stats_uv;
-#if CONFIG_VAR_TX
-      for (i = 0; i < MAX_MB_PLANE; ++i)
-        memcpy(best_blk_skip[i], x->blk_skip[i],
-               sizeof(uint8_t) * xd->n8_h * xd->n8_w * 4);
-#endif  // CONFIG_VAR_TX
-      best_xskip = x->skip;
-      best_disable_skip = *disable_skip;
-    }
-  }
-
-  if (best_rd == INT64_MAX) {
-    av1_invalid_rd_stats(rd_stats);
-    restore_dst_buf(xd, orig_dst);
-    return INT64_MAX;
-  }
-  *mbmi = best_mbmi;
-  *rd_stats = best_rd_stats;
-  *rd_stats_y = best_rd_stats_y;
-  *rd_stats_uv = best_rd_stats_uv;
-#if CONFIG_VAR_TX
-  for (i = 0; i < MAX_MB_PLANE; ++i)
-    memcpy(x->blk_skip[i], best_blk_skip[i],
-           sizeof(uint8_t) * xd->n8_h * xd->n8_w * 4);
-#endif  // CONFIG_VAR_TX
-  x->skip = best_xskip;
-  *disable_skip = best_disable_skip;
-#endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-
-  restore_dst_buf(xd, orig_dst);
   return 0;  // The rate-distortion cost will be re-calculated by caller.
 }