Modularize fullpel mv search functions

This CL removes all references to the large MACROBLOCK struct in fullpel
search functions to make motion compensation more modular.

There is a 0.1% slow down across speed settings due to inefficient
copying of functional parameters, but this can be fixed later with caching.

BUG=aomedia:2594

Change-Id: I40816f63dd33306d85faa335c8a08a733bc12f69
diff --git a/av1/encoder/firstpass.c b/av1/encoder/firstpass.c
index 31b9283..9183c28 100644
--- a/av1/encoder/firstpass.c
+++ b/av1/encoder/firstpass.c
@@ -229,12 +229,16 @@
   aom_variance_fn_ptr_t v_fn_ptr = cpi->fn_ptr[bsize];
   const int new_mv_mode_penalty = NEW_MV_MODE_PENALTY;
   const int sr = get_search_range(cpi);
-  int step_param = 3 + sr;
+  const int step_param = 3 + sr;
   int cost_list[5];
 
-  tmp_err = av1_full_pixel_search(cpi, x, bsize, start_mv, step_param, NSTEP, 0,
-                                  x->sadperbit, cond_cost_list(cpi, cost_list),
-                                  ref_mv, 0, &cpi->ss_cfg[SS_CFG_FPF],
+  const search_site_config *first_pass_search_sites = &cpi->ss_cfg[SS_CFG_FPF];
+  FULLPEL_MOTION_SEARCH_PARAMS ms_params;
+  av1_make_default_fullpel_ms_params(&ms_params, cpi, x, bsize, ref_mv,
+                                     first_pass_search_sites);
+  ms_params.search_method = NSTEP;
+
+  tmp_err = av1_full_pixel_search(start_mv, &ms_params, step_param, cost_list,
                                   &x->best_mv.as_fullmv, NULL);
 
   if (tmp_err < INT_MAX) {
diff --git a/av1/encoder/mcomp.c b/av1/encoder/mcomp.c
index 35a0463..8600571 100644
--- a/av1/encoder/mcomp.c
+++ b/av1/encoder/mcomp.c
@@ -13,7 +13,6 @@
 #include <math.h>
 #include <stdio.h>
 
-#include "av1/common/filter.h"
 #include "config/aom_config.h"
 #include "config/aom_dsp_rtcd.h"
 
@@ -23,6 +22,7 @@
 
 #include "av1/common/av1_common_int.h"
 #include "av1/common/common.h"
+#include "av1/common/filter.h"
 #include "av1/common/mvref_common.h"
 #include "av1/common/reconinter.h"
 
@@ -47,6 +47,49 @@
 #define SSE_LAMBDA_HDRES 1  // Used by mv_cost_err_fn
 #define SAD_LAMBDA_HDRES 8  // Used by mvsad_err_cost during full pixel search
 
+void av1_make_default_fullpel_ms_params(
+    FULLPEL_MOTION_SEARCH_PARAMS *ms_params, const struct AV1_COMP *cpi,
+    const MACROBLOCK *x, BLOCK_SIZE bsize, const MV *ref_mv,
+    const search_site_config *search_sites) {
+  // High level params
+  ms_params->bsize = bsize;
+  ms_params->vfp = &cpi->fn_ptr[bsize];
+
+  ms_params->src = &x->plane[0].src;
+  ms_params->ref = &x->e_mbd.plane[0].pre[0];
+
+  ms_params->second_pred = NULL;
+  ms_params->mask = NULL;
+  ms_params->mask_stride = 0;
+  ms_params->inv_mask = 0;
+
+  ms_params->search_method = cpi->sf.mv_sf.search_method;
+  ms_params->search_sites = search_sites;
+
+  ms_params->mesh_patterns[0] = cpi->sf.mv_sf.mesh_patterns;
+  ms_params->mesh_patterns[1] = cpi->sf.mv_sf.intrabc_mesh_patterns;
+  ms_params->force_mesh_thresh = cpi->sf.mv_sf.exhaustive_searches_thresh;
+  ms_params->prune_mesh_search = cpi->sf.mv_sf.prune_mesh_search;
+  ms_params->run_mesh_search = 0;
+
+  ms_params->is_intra_mode = 0;
+
+  ms_params->fast_obmc_search = cpi->sf.mv_sf.obmc_full_pixel_search_level;
+
+  ms_params->mv_limits = x->mv_limits;
+  av1_set_mv_search_range(&ms_params->mv_limits, ref_mv);
+
+  // Mvcost params
+  ms_params->mv_cost_params.ref_mv = ref_mv;
+  ms_params->mv_cost_params.full_ref_mv = get_fullmv_from_mv(ref_mv);
+  ms_params->mv_cost_params.error_per_bit = x->errorperbit;
+  ms_params->mv_cost_params.sad_per_bit = x->sadperbit;
+  ms_params->mv_cost_params.mvjcost = x->nmv_vec_cost;
+  ms_params->mv_cost_params.mvcost[0] = x->mv_cost_stack[0];
+  ms_params->mv_cost_params.mvcost[1] = x->mv_cost_stack[1];
+  ms_params->mv_cost_params.mv_cost_type = x->mv_cost_type;
+}
+
 void av1_make_default_subpel_ms_params(
     SUBPEL_MOTION_SEARCH_PARAMS *ms_params, const struct AV1_COMP *cpi,
     const MACROBLOCK *x, BLOCK_SIZE bsize, const MV *ref_mv,
@@ -63,6 +106,7 @@
   // Mvcost params
   ms_params->mv_cost_params.ref_mv = ref_mv;
   ms_params->mv_cost_params.error_per_bit = x->errorperbit;
+  ms_params->mv_cost_params.sad_per_bit = x->sadperbit;
   ms_params->mv_cost_params.mvjcost = x->nmv_vec_cost;
   ms_params->mv_cost_params.mvcost[0] = x->mv_cost_stack[0];
   ms_params->mv_cost_params.mvcost[1] = x->mv_cost_stack[1];
@@ -150,9 +194,9 @@
 // Returns the cost of using the current mv during the motion search. This is
 // used when var is used as the error metric.
 #define PIXEL_TRANSFORM_ERROR_SCALE 4
-static int mv_err_cost(const MV *mv, const MV *ref_mv, const int *mvjcost,
-                       const int *const mvcost[2], int error_per_bit,
-                       MV_COST_TYPE mv_cost_type) {
+static INLINE int mv_err_cost(const MV *mv, const MV *ref_mv,
+                              const int *mvjcost, const int *const mvcost[2],
+                              int error_per_bit, MV_COST_TYPE mv_cost_type) {
   const MV diff = { mv->row - ref_mv->row, mv->col - ref_mv->col };
   const MV abs_diff = { abs(diff.row), abs(diff.col) };
 
@@ -185,18 +229,17 @@
 
 // Returns the cost of using the current mv during the motion search. This is
 // only used during full pixel motion search when sad is used as the error
-// metric.
-static int mvsad_err_cost(const MACROBLOCK *x, const FULLPEL_MV *mv,
-                          const FULLPEL_MV *ref_mv, int sad_per_bit) {
+// metric
+static INLINE int mvsad_err_cost(const FULLPEL_MV *mv, const FULLPEL_MV *ref_mv,
+                                 const int *mvjcost, const int *const mvcost[2],
+                                 int sad_per_bit, MV_COST_TYPE mv_cost_type) {
   const MV diff = { GET_MV_SUBPEL(mv->row - ref_mv->row),
                     GET_MV_SUBPEL(mv->col - ref_mv->col) };
-  const MV_COST_TYPE mv_cost_type = x->mv_cost_type;
 
   switch (mv_cost_type) {
     case MV_COST_ENTROPY:
       return ROUND_POWER_OF_TWO(
-          (unsigned)mv_cost(&diff, x->nmv_vec_cost,
-                            CONVERT_TO_CONST_MVCOST(x->mv_cost_stack)) *
+          (unsigned)mv_cost(&diff, mvjcost, CONVERT_TO_CONST_MVCOST(mvcost)) *
               sad_per_bit,
           AV1_PROB_COST_SHIFT);
     case MV_COST_L1_LOWRES:
@@ -210,6 +253,14 @@
   }
 }
 
+static INLINE int mvsad_err_cost_(const FULLPEL_MV *mv,
+                                  const MV_COST_PARAMS *mv_cost_params) {
+  return mvsad_err_cost(mv, &mv_cost_params->full_ref_mv,
+                        mv_cost_params->mvjcost, mv_cost_params->mvcost,
+                        mv_cost_params->sad_per_bit,
+                        mv_cost_params->mv_cost_type);
+}
+
 // =============================================================================
 //  Fullpixel Motion Search: Translational
 // =============================================================================
@@ -343,6 +394,38 @@
          ((col + range) <= mv_limits->col_max);
 }
 
+static INLINE int get_mvpred_var_cost(
+    const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, const FULLPEL_MV *this_mv) {
+  const aom_variance_fn_ptr_t *vfp = ms_params->vfp;
+  const MV sub_this_mv = get_mv_from_fullmv(this_mv);
+  const struct buf_2d *const src = ms_params->src;
+  const struct buf_2d *const ref = ms_params->ref;
+  const uint8_t *src_buf = src->buf;
+  const int src_stride = src->stride;
+  const int ref_stride = ref->stride;
+
+  unsigned unused;
+  int bestsme;
+
+  bestsme = vfp->vf(src_buf, src_stride, get_buf_from_mv(ref, this_mv),
+                    ref_stride, &unused);
+
+  bestsme += mv_err_cost_(&sub_this_mv, &ms_params->mv_cost_params);
+
+  return bestsme;
+}
+
+static INLINE int get_mvpred_sad(const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
+                                 const struct buf_2d *const src,
+                                 const uint8_t *const ref_address,
+                                 const int ref_stride) {
+  const aom_variance_fn_ptr_t *vfp = ms_params->vfp;
+  const uint8_t *src_buf = src->buf;
+  const int src_stride = src->stride;
+
+  return vfp->sdf(src_buf, src_stride, ref_address, ref_stride);
+}
+
 // Calculates and returns a sad+mvcost list around an integer best pel during
 // fullpixel motion search. The resulting list can be used to speed up subpel
 // motion search later.
@@ -350,128 +433,99 @@
 
 // calc_int_cost_list uses var to populate the costlist, which is more accurate
 // than sad but slightly slower.
-static INLINE void calc_int_cost_list(const MACROBLOCK *x,
-                                      const MV *const ref_mv,
-                                      const aom_variance_fn_ptr_t *fn_ptr,
-                                      const FULLPEL_MV *best_mv,
-                                      int *cost_list) {
+static AOM_FORCE_INLINE void calc_int_cost_list(
+    const FULLPEL_MV best_mv, const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
+    int *cost_list) {
   static const FULLPEL_MV neighbors[4] = {
     { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 }
   };
-  const struct buf_2d *const what = &x->plane[0].src;
-  const struct buf_2d *const in_what = &x->e_mbd.plane[0].pre[0];
-  const MV sub_best_mv = get_mv_from_fullmv(best_mv);
-  const int br = best_mv->row;
-  const int bc = best_mv->col;
-  const MV_COST_TYPE mv_cost_type = x->mv_cost_type;
-  unsigned int sse;
+  const int br = best_mv.row;
+  const int bc = best_mv.col;
 
-  cost_list[0] =
-      fn_ptr->vf(what->buf, what->stride, get_buf_from_mv(in_what, best_mv),
-                 in_what->stride, &sse) +
-      mv_err_cost(&sub_best_mv, ref_mv, x->nmv_vec_cost,
-                  CONVERT_TO_CONST_MVCOST(x->mv_cost_stack), x->errorperbit,
-                  mv_cost_type);
-  if (check_bounds(&x->mv_limits, br, bc, 1)) {
+  cost_list[0] = get_mvpred_var_cost(ms_params, &best_mv);
+
+  if (check_bounds(&ms_params->mv_limits, br, bc, 1)) {
     for (int i = 0; i < 4; i++) {
       const FULLPEL_MV neighbor_mv = { br + neighbors[i].row,
                                        bc + neighbors[i].col };
-      const MV sub_neighbor_mv = get_mv_from_fullmv(&neighbor_mv);
-      cost_list[i + 1] = fn_ptr->vf(what->buf, what->stride,
-                                    get_buf_from_mv(in_what, &neighbor_mv),
-                                    in_what->stride, &sse) +
-                         mv_err_cost(&sub_neighbor_mv, ref_mv, x->nmv_vec_cost,
-                                     CONVERT_TO_CONST_MVCOST(x->mv_cost_stack),
-                                     x->errorperbit, mv_cost_type);
+      cost_list[i + 1] = get_mvpred_var_cost(ms_params, &neighbor_mv);
     }
   } else {
     for (int i = 0; i < 4; i++) {
       const FULLPEL_MV neighbor_mv = { br + neighbors[i].row,
                                        bc + neighbors[i].col };
-      if (!av1_is_fullmv_in_range(&x->mv_limits, neighbor_mv)) {
+      if (!av1_is_fullmv_in_range(&ms_params->mv_limits, neighbor_mv)) {
         cost_list[i + 1] = INT_MAX;
       } else {
-        const MV sub_neighbor_mv = get_mv_from_fullmv(&neighbor_mv);
-        cost_list[i + 1] =
-            fn_ptr->vf(what->buf, what->stride,
-                       get_buf_from_mv(in_what, &neighbor_mv), in_what->stride,
-                       &sse) +
-            mv_err_cost(&sub_neighbor_mv, ref_mv, x->nmv_vec_cost,
-                        CONVERT_TO_CONST_MVCOST(x->mv_cost_stack),
-                        x->errorperbit, mv_cost_type);
+        cost_list[i + 1] = get_mvpred_var_cost(ms_params, &neighbor_mv);
       }
     }
   }
 }
 
-// calc_int_cost_list uses sad to populate the costlist, which is less accurate
+// calc_int_sad_list uses sad to populate the costlist, which is less accurate
 // than var but faster.
-static INLINE void calc_int_sad_list(const MACROBLOCK *x,
-                                     const MV *const ref_mv, int sadpb,
-                                     const aom_variance_fn_ptr_t *fn_ptr,
-                                     const FULLPEL_MV *best_mv, int *cost_list,
-                                     int costlist_has_sad) {
+static AOM_FORCE_INLINE void calc_int_sad_list(
+    const FULLPEL_MV best_mv, const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
+    int *cost_list, int costlist_has_sad) {
   static const FULLPEL_MV neighbors[4] = {
     { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 }
   };
-  const struct buf_2d *const what = &x->plane[0].src;
-  const struct buf_2d *const in_what = &x->e_mbd.plane[0].pre[0];
-  const int br = best_mv->row;
-  const int bc = best_mv->col;
-  const FULLPEL_MV full_ref_mv = get_fullmv_from_mv(ref_mv);
+  const struct buf_2d *const src = ms_params->src;
+  const struct buf_2d *const ref = ms_params->ref;
+  const int ref_stride = ref->stride;
+  const int br = best_mv.row;
+  const int bc = best_mv.col;
 
-  assert(av1_is_fullmv_in_range(&x->mv_limits, *best_mv));
+  assert(av1_is_fullmv_in_range(&ms_params->mv_limits, best_mv));
 
   // Refresh the costlist it does not contain valid sad
   if (!costlist_has_sad) {
-    cost_list[0] =
-        fn_ptr->sdf(what->buf, what->stride, get_buf_from_mv(in_what, best_mv),
-                    in_what->stride);
+    cost_list[0] = get_mvpred_sad(ms_params, src,
+                                  get_buf_from_mv(ref, &best_mv), ref_stride);
 
-    if (check_bounds(&x->mv_limits, br, bc, 1)) {
+    if (check_bounds(&ms_params->mv_limits, br, bc, 1)) {
       for (int i = 0; i < 4; i++) {
         const FULLPEL_MV this_mv = { br + neighbors[i].row,
                                      bc + neighbors[i].col };
-        cost_list[i + 1] =
-            fn_ptr->sdf(what->buf, what->stride,
-                        get_buf_from_mv(in_what, &this_mv), in_what->stride);
+        cost_list[i + 1] = get_mvpred_sad(
+            ms_params, src, get_buf_from_mv(ref, &this_mv), ref_stride);
       }
     } else {
       for (int i = 0; i < 4; i++) {
         const FULLPEL_MV this_mv = { br + neighbors[i].row,
                                      bc + neighbors[i].col };
-        if (!av1_is_fullmv_in_range(&x->mv_limits, this_mv)) {
+        if (!av1_is_fullmv_in_range(&ms_params->mv_limits, this_mv)) {
           cost_list[i + 1] = INT_MAX;
         } else {
-          cost_list[i + 1] =
-              fn_ptr->sdf(what->buf, what->stride,
-                          get_buf_from_mv(in_what, &this_mv), in_what->stride);
+          cost_list[i + 1] = get_mvpred_sad(
+              ms_params, src, get_buf_from_mv(ref, &this_mv), ref_stride);
         }
       }
     }
   }
 
-  cost_list[0] += mvsad_err_cost(x, best_mv, &full_ref_mv, sadpb);
+  const MV_COST_PARAMS *mv_cost_params = &ms_params->mv_cost_params;
+  cost_list[0] += mvsad_err_cost_(&best_mv, mv_cost_params);
 
   for (int idx = 0; idx < 4; idx++) {
     if (cost_list[idx + 1] != INT_MAX) {
       const FULLPEL_MV this_mv = { br + neighbors[idx].row,
                                    bc + neighbors[idx].col };
-      cost_list[idx + 1] += mvsad_err_cost(x, &this_mv, &full_ref_mv, sadpb);
+      cost_list[idx + 1] += mvsad_err_cost_(&this_mv, mv_cost_params);
     }
   }
 }
 
-#define CHECK_BETTER                                                     \
-  if (thissad < bestsad) {                                               \
-    int tmp_thissad = thissad;                                           \
-    if (use_mvcost)                                                      \
-      thissad += mvsad_err_cost(x, &this_mv, &full_ref_mv, sad_per_bit); \
-    if (thissad < bestsad) {                                             \
-      raw_bestsad = tmp_thissad;                                         \
-      bestsad = thissad;                                                 \
-      best_site = i;                                                     \
-    }                                                                    \
+#define CHECK_BETTER                                                      \
+  if (thissad < bestsad) {                                                \
+    int tmp_thissad = thissad;                                            \
+    if (use_mvcost) thissad += mvsad_err_cost_(&this_mv, mv_cost_params); \
+    if (thissad < bestsad) {                                              \
+      raw_bestsad = tmp_thissad;                                          \
+      bestsad = thissad;                                                  \
+      best_site = i;                                                      \
+    }                                                                     \
   }
 
 // Generic pattern search function that searches over multiple scales.
@@ -479,29 +533,30 @@
 // candidates as indicated in the num_candidates and candidates arrays
 // passed into this function
 static int pattern_search(
-    const MACROBLOCK *x, FULLPEL_MV start_mv, int search_param, int sad_per_bit,
-    int do_init_search, int *cost_list, const aom_variance_fn_ptr_t *vfp,
-    const MV *ref_mv, const int num_candidates[MAX_PATTERN_SCALES],
+    FULLPEL_MV start_mv, const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
+    const int search_param, const int do_init_search,
+    const int num_candidates[MAX_PATTERN_SCALES],
     const MV candidates[MAX_PATTERN_SCALES][MAX_PATTERN_CANDIDATES],
-    FULLPEL_MV *best_mv) {
-  const MACROBLOCKD *const xd = &x->e_mbd;
+    int *cost_list, FULLPEL_MV *best_mv) {
   static const int search_param_to_steps[MAX_MVSEARCH_STEPS] = {
     10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
   };
   int i, s, t;
-  const struct buf_2d *const what = &x->plane[0].src;
-  const struct buf_2d *const in_what = &xd->plane[0].pre[0];
+
+  const struct buf_2d *const src = ms_params->src;
+  const struct buf_2d *const ref = ms_params->ref;
+  const int ref_stride = ref->stride;
   const int last_is_4 = num_candidates[0] == 4;
   int br, bc;
   int bestsad = INT_MAX, raw_bestsad = INT_MAX;
   int thissad;
   int k = -1;
-  const FULLPEL_MV full_ref_mv = get_fullmv_from_mv(ref_mv);
-  const int use_mvcost = x->mv_cost_type != MV_COST_NONE;
+  const int use_mvcost = ms_params->mv_cost_params.mv_cost_type != MV_COST_NONE;
+  const MV_COST_PARAMS *mv_cost_params = &ms_params->mv_cost_params;
   assert(search_param < MAX_MVSEARCH_STEPS);
   int best_init_s = search_param_to_steps[search_param];
   // adjust ref_mv to make sure it is within MV range
-  clamp_fullmv(&start_mv, &x->mv_limits);
+  clamp_fullmv(&start_mv, &ms_params->mv_limits);
   br = start_mv.row;
   bc = start_mv.col;
   if (cost_list != NULL) {
@@ -511,10 +566,9 @@
   int costlist_has_sad = 0;
 
   // Work out the start point for the search
-  raw_bestsad = vfp->sdf(what->buf, what->stride,
-                         get_buf_from_mv(in_what, &start_mv), in_what->stride);
-  bestsad =
-      raw_bestsad + mvsad_err_cost(x, &start_mv, &full_ref_mv, sad_per_bit);
+  raw_bestsad = get_mvpred_sad(ms_params, src, get_buf_from_mv(ref, &start_mv),
+                               ref_stride);
+  bestsad = raw_bestsad + mvsad_err_cost_(&start_mv, mv_cost_params);
 
   // Search all possible scales up to the search param around the center point
   // pick the scale of the point that is best as the starting scale of
@@ -524,23 +578,21 @@
     best_init_s = -1;
     for (t = 0; t <= s; ++t) {
       int best_site = -1;
-      if (check_bounds(&x->mv_limits, br, bc, 1 << t)) {
+      if (check_bounds(&ms_params->mv_limits, br, bc, 1 << t)) {
         for (i = 0; i < num_candidates[t]; i++) {
           const FULLPEL_MV this_mv = { br + candidates[t][i].row,
                                        bc + candidates[t][i].col };
-          thissad =
-              vfp->sdf(what->buf, what->stride,
-                       get_buf_from_mv(in_what, &this_mv), in_what->stride);
+          thissad = get_mvpred_sad(ms_params, src,
+                                   get_buf_from_mv(ref, &this_mv), ref_stride);
           CHECK_BETTER
         }
       } else {
         for (i = 0; i < num_candidates[t]; i++) {
           const FULLPEL_MV this_mv = { br + candidates[t][i].row,
                                        bc + candidates[t][i].col };
-          if (!av1_is_fullmv_in_range(&x->mv_limits, this_mv)) continue;
-          thissad =
-              vfp->sdf(what->buf, what->stride,
-                       get_buf_from_mv(in_what, &this_mv), in_what->stride);
+          if (!av1_is_fullmv_in_range(&ms_params->mv_limits, this_mv)) continue;
+          thissad = get_mvpred_sad(ms_params, src,
+                                   get_buf_from_mv(ref, &this_mv), ref_stride);
           CHECK_BETTER
         }
       }
@@ -567,23 +619,22 @@
     for (; s >= last_s; s--) {
       // No need to search all points the 1st time if initial search was used
       if (!do_init_search || s != best_init_s) {
-        if (check_bounds(&x->mv_limits, br, bc, 1 << s)) {
+        if (check_bounds(&ms_params->mv_limits, br, bc, 1 << s)) {
           for (i = 0; i < num_candidates[s]; i++) {
             const FULLPEL_MV this_mv = { br + candidates[s][i].row,
                                          bc + candidates[s][i].col };
-            thissad =
-                vfp->sdf(what->buf, what->stride,
-                         get_buf_from_mv(in_what, &this_mv), in_what->stride);
+            thissad = get_mvpred_sad(
+                ms_params, src, get_buf_from_mv(ref, &this_mv), ref_stride);
             CHECK_BETTER
           }
         } else {
           for (i = 0; i < num_candidates[s]; i++) {
             const FULLPEL_MV this_mv = { br + candidates[s][i].row,
                                          bc + candidates[s][i].col };
-            if (!av1_is_fullmv_in_range(&x->mv_limits, this_mv)) continue;
-            thissad =
-                vfp->sdf(what->buf, what->stride,
-                         get_buf_from_mv(in_what, &this_mv), in_what->stride);
+            if (!av1_is_fullmv_in_range(&ms_params->mv_limits, this_mv))
+              continue;
+            thissad = get_mvpred_sad(
+                ms_params, src, get_buf_from_mv(ref, &this_mv), ref_stride);
             CHECK_BETTER
           }
         }
@@ -604,15 +655,14 @@
         next_chkpts_indices[1] = k;
         next_chkpts_indices[2] = (k == num_candidates[s] - 1) ? 0 : k + 1;
 
-        if (check_bounds(&x->mv_limits, br, bc, 1 << s)) {
+        if (check_bounds(&ms_params->mv_limits, br, bc, 1 << s)) {
           for (i = 0; i < PATTERN_CANDIDATES_REF; i++) {
             const FULLPEL_MV this_mv = {
               br + candidates[s][next_chkpts_indices[i]].row,
               bc + candidates[s][next_chkpts_indices[i]].col
             };
-            thissad =
-                vfp->sdf(what->buf, what->stride,
-                         get_buf_from_mv(in_what, &this_mv), in_what->stride);
+            thissad = get_mvpred_sad(
+                ms_params, src, get_buf_from_mv(ref, &this_mv), ref_stride);
             CHECK_BETTER
           }
         } else {
@@ -621,10 +671,10 @@
               br + candidates[s][next_chkpts_indices[i]].row,
               bc + candidates[s][next_chkpts_indices[i]].col
             };
-            if (!av1_is_fullmv_in_range(&x->mv_limits, this_mv)) continue;
-            thissad =
-                vfp->sdf(what->buf, what->stride,
-                         get_buf_from_mv(in_what, &this_mv), in_what->stride);
+            if (!av1_is_fullmv_in_range(&ms_params->mv_limits, this_mv))
+              continue;
+            thissad = get_mvpred_sad(
+                ms_params, src, get_buf_from_mv(ref, &this_mv), ref_stride);
             CHECK_BETTER
           }
         }
@@ -642,23 +692,22 @@
       cost_list[0] = raw_bestsad;
       costlist_has_sad = 1;
       if (!do_init_search || s != best_init_s) {
-        if (check_bounds(&x->mv_limits, br, bc, 1 << s)) {
+        if (check_bounds(&ms_params->mv_limits, br, bc, 1 << s)) {
           for (i = 0; i < num_candidates[s]; i++) {
             const FULLPEL_MV this_mv = { br + candidates[s][i].row,
                                          bc + candidates[s][i].col };
-            cost_list[i + 1] = thissad =
-                vfp->sdf(what->buf, what->stride,
-                         get_buf_from_mv(in_what, &this_mv), in_what->stride);
+            cost_list[i + 1] = thissad = get_mvpred_sad(
+                ms_params, src, get_buf_from_mv(ref, &this_mv), ref_stride);
             CHECK_BETTER
           }
         } else {
           for (i = 0; i < num_candidates[s]; i++) {
             const FULLPEL_MV this_mv = { br + candidates[s][i].row,
                                          bc + candidates[s][i].col };
-            if (!av1_is_fullmv_in_range(&x->mv_limits, this_mv)) continue;
-            cost_list[i + 1] = thissad =
-                vfp->sdf(what->buf, what->stride,
-                         get_buf_from_mv(in_what, &this_mv), in_what->stride);
+            if (!av1_is_fullmv_in_range(&ms_params->mv_limits, this_mv))
+              continue;
+            cost_list[i + 1] = thissad = get_mvpred_sad(
+                ms_params, src, get_buf_from_mv(ref, &this_mv), ref_stride);
             CHECK_BETTER
           }
         }
@@ -679,15 +728,14 @@
         cost_list[((k + 2) % 4) + 1] = cost_list[0];
         cost_list[0] = raw_bestsad;
 
-        if (check_bounds(&x->mv_limits, br, bc, 1 << s)) {
+        if (check_bounds(&ms_params->mv_limits, br, bc, 1 << s)) {
           for (i = 0; i < PATTERN_CANDIDATES_REF; i++) {
             const FULLPEL_MV this_mv = {
               br + candidates[s][next_chkpts_indices[i]].row,
               bc + candidates[s][next_chkpts_indices[i]].col
             };
-            cost_list[next_chkpts_indices[i] + 1] = thissad =
-                vfp->sdf(what->buf, what->stride,
-                         get_buf_from_mv(in_what, &this_mv), in_what->stride);
+            cost_list[next_chkpts_indices[i] + 1] = thissad = get_mvpred_sad(
+                ms_params, src, get_buf_from_mv(ref, &this_mv), ref_stride);
             CHECK_BETTER
           }
         } else {
@@ -696,13 +744,12 @@
               br + candidates[s][next_chkpts_indices[i]].row,
               bc + candidates[s][next_chkpts_indices[i]].col
             };
-            if (!av1_is_fullmv_in_range(&x->mv_limits, this_mv)) {
+            if (!av1_is_fullmv_in_range(&ms_params->mv_limits, this_mv)) {
               cost_list[next_chkpts_indices[i] + 1] = INT_MAX;
               continue;
             }
-            cost_list[next_chkpts_indices[i] + 1] = thissad =
-                vfp->sdf(what->buf, what->stride,
-                         get_buf_from_mv(in_what, &this_mv), in_what->stride);
+            cost_list[next_chkpts_indices[i] + 1] = thissad = get_mvpred_sad(
+                ms_params, src, get_buf_from_mv(ref, &this_mv), ref_stride);
             CHECK_BETTER
           }
         }
@@ -727,14 +774,15 @@
   // cost_list[4]: cost/sad at delta {-1, 0} (top)    from the best integer pel
   if (cost_list) {
     if (USE_SAD_COSTLIST) {
-      calc_int_sad_list(x, ref_mv, sad_per_bit, vfp, best_mv, cost_list,
-                        costlist_has_sad);
+      calc_int_sad_list(*best_mv, ms_params, cost_list, costlist_has_sad);
     } else {
-      calc_int_cost_list(x, ref_mv, vfp, best_mv, cost_list);
+      calc_int_cost_list(*best_mv, ms_params, cost_list);
     }
   }
+  best_mv->row = br;
+  best_mv->col = bc;
 
-  const int var_cost = av1_get_mvpred_var(x, best_mv, ref_mv, vfp);
+  const int var_cost = get_mvpred_var_cost(ms_params, best_mv);
   return var_cost;
 }
 #undef CHECK_BETTER
@@ -753,10 +801,10 @@
 // vfp: a function pointer to the simd function so we can compute the cost
 //   efficiently
 // ref_mv: the reference mv used to compute the mv cost
-static int hex_search(const MACROBLOCK *x, const FULLPEL_MV start_mv,
-                      int search_param, int sad_per_bit, int do_init_search,
-                      int *cost_list, const aom_variance_fn_ptr_t *vfp,
-                      const MV *ref_mv, FULLPEL_MV *best_mv) {
+static int hex_search(const FULLPEL_MV start_mv,
+                      const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
+                      const int search_param, const int do_init_search,
+                      int *cost_list, FULLPEL_MV *best_mv) {
   // First scale has 8-closest points, the rest have 6 points in hex shape
   // at increasing scales
   static const int hex_num_candidates[MAX_PATTERN_SCALES] = { 8, 6, 6, 6, 6, 6,
@@ -784,15 +832,14 @@
       { -512, 1024 }, { -1024, 0 } },
   };
   /* clang-format on */
-  return pattern_search(x, start_mv, search_param, sad_per_bit, do_init_search,
-                        cost_list, vfp, ref_mv, hex_num_candidates,
-                        hex_candidates, best_mv);
+  return pattern_search(start_mv, ms_params, search_param, do_init_search,
+                        hex_num_candidates, hex_candidates, cost_list, best_mv);
 }
 
-static int bigdia_search(const MACROBLOCK *x, const FULLPEL_MV start_mv,
-                         int search_param, int sad_per_bit, int do_init_search,
-                         int *cost_list, const aom_variance_fn_ptr_t *vfp,
-                         const MV *ref_mv, FULLPEL_MV *best_mv) {
+static int bigdia_search(const FULLPEL_MV start_mv,
+                         const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
+                         const int search_param, const int do_init_search,
+                         int *cost_list, FULLPEL_MV *best_mv) {
   // First scale has 4-closest points, the rest have 8 points in diamond
   // shape at increasing scales
   static const int bigdia_num_candidates[MAX_PATTERN_SCALES] = {
@@ -825,15 +872,15 @@
           { 512, 512 }, { 0, 1024 }, { -512, 512 }, { -1024, 0 } },
       };
   /* clang-format on */
-  return pattern_search(x, start_mv, search_param, sad_per_bit, do_init_search,
-                        cost_list, vfp, ref_mv, bigdia_num_candidates,
-                        bigdia_candidates, best_mv);
+  return pattern_search(start_mv, ms_params, search_param, do_init_search,
+                        bigdia_num_candidates, bigdia_candidates, cost_list,
+                        best_mv);
 }
 
-static int square_search(const MACROBLOCK *x, const FULLPEL_MV start_mv,
-                         int search_param, int sad_per_bit, int do_init_search,
-                         int *cost_list, const aom_variance_fn_ptr_t *vfp,
-                         const MV *ref_mv, FULLPEL_MV *best_mv) {
+static int square_search(const FULLPEL_MV start_mv,
+                         const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
+                         const int search_param, const int do_init_search,
+                         int *cost_list, FULLPEL_MV *best_mv) {
   // All scales have 8 closest points in square shape
   static const int square_num_candidates[MAX_PATTERN_SCALES] = {
     8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
@@ -866,173 +913,120 @@
           { 1024, 1024 }, { 0, 1024 }, { -1024, 1024 }, { -1024, 0 } },
       };
   /* clang-format on */
-  return pattern_search(x, start_mv, search_param, sad_per_bit, do_init_search,
-                        cost_list, vfp, ref_mv, square_num_candidates,
-                        square_candidates, best_mv);
+  return pattern_search(start_mv, ms_params, search_param, do_init_search,
+                        square_num_candidates, square_candidates, cost_list,
+                        best_mv);
 }
 
-static int fast_hex_search(const MACROBLOCK *x, const FULLPEL_MV start_mv,
-                           int search_param, int sad_per_bit,
-                           int do_init_search,  // must be zero for fast_hex
-                           int *cost_list, const aom_variance_fn_ptr_t *vfp,
-                           const MV *ref_mv, FULLPEL_MV *best_mv) {
-  return hex_search(x, start_mv, AOMMAX(MAX_MVSEARCH_STEPS - 2, search_param),
-                    sad_per_bit, do_init_search, cost_list, vfp, ref_mv,
-                    best_mv);
+static int fast_hex_search(const FULLPEL_MV start_mv,
+                           const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
+                           const int search_param, const int do_init_search,
+                           int *cost_list, FULLPEL_MV *best_mv) {
+  return hex_search(start_mv, ms_params,
+                    AOMMAX(MAX_MVSEARCH_STEPS - 2, search_param),
+                    do_init_search, cost_list, best_mv);
 }
 
-static int fast_dia_search(const MACROBLOCK *x, const FULLPEL_MV start_mv,
-                           int search_param, int sad_per_bit,
-                           int do_init_search, int *cost_list,
-                           const aom_variance_fn_ptr_t *vfp, const MV *ref_mv,
-                           FULLPEL_MV *best_mv) {
-  return bigdia_search(
-      x, start_mv, AOMMAX(MAX_MVSEARCH_STEPS - 2, search_param), sad_per_bit,
-      do_init_search, cost_list, vfp, ref_mv, best_mv);
+static int fast_dia_search(const FULLPEL_MV start_mv,
+                           const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
+                           const int search_param, const int do_init_search,
+                           int *cost_list, FULLPEL_MV *best_mv) {
+  return bigdia_search(start_mv, ms_params,
+                       AOMMAX(MAX_MVSEARCH_STEPS - 2, search_param),
+                       do_init_search, cost_list, best_mv);
 }
 
-// Exhaustive motion search around a given centre position with a given
-// step size.
-static int exhuastive_mesh_search(const MACROBLOCK *x, FULLPEL_MV *ref_mv,
-                                  FULLPEL_MV *best_mv,
-                                  FULLPEL_MV *second_best_mv, int range,
-                                  int step, int sad_per_bit,
-                                  const aom_variance_fn_ptr_t *fn_ptr,
-                                  FULLPEL_MV start_mv) {
-  const MACROBLOCKD *const xd = &x->e_mbd;
-  const struct buf_2d *const what = &x->plane[0].src;
-  const struct buf_2d *const in_what = &xd->plane[0].pre[0];
-  unsigned int best_sad = INT_MAX;
-  int r, c, i;
-  int start_col, end_col, start_row, end_row;
-  int col_step = (step > 1) ? step : 4;
+static INLINE int get_mvpred_compound_var_cost(
+    const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, const FULLPEL_MV *this_mv) {
+  const aom_variance_fn_ptr_t *vfp = ms_params->vfp;
+  const struct buf_2d *const src = ms_params->src;
+  const struct buf_2d *const ref = ms_params->ref;
+  const uint8_t *src_buf = src->buf;
+  const int src_stride = src->stride;
+  const int ref_stride = ref->stride;
 
-  assert(step >= 1);
+  const uint8_t *mask = ms_params->mask;
+  const uint8_t *second_pred = ms_params->second_pred;
+  const int mask_stride = ms_params->mask_stride;
+  const int invert_mask = ms_params->inv_mask;
+  unsigned unused;
+  int bestsme;
 
-  clamp_fullmv(&start_mv, &x->mv_limits);
-  *best_mv = start_mv;
-  best_sad = fn_ptr->sdf(what->buf, what->stride,
-                         get_buf_from_mv(in_what, &start_mv), in_what->stride) +
-             mvsad_err_cost(x, &start_mv, ref_mv, sad_per_bit);
-  start_row = AOMMAX(-range, x->mv_limits.row_min - start_mv.row);
-  start_col = AOMMAX(-range, x->mv_limits.col_min - start_mv.col);
-  end_row = AOMMIN(range, x->mv_limits.row_max - start_mv.row);
-  end_col = AOMMIN(range, x->mv_limits.col_max - start_mv.col);
-
-  for (r = start_row; r <= end_row; r += step) {
-    for (c = start_col; c <= end_col; c += col_step) {
-      // Step > 1 means we are not checking every location in this pass.
-      if (step > 1) {
-        const FULLPEL_MV mv = { start_mv.row + r, start_mv.col + c };
-        unsigned int sad =
-            fn_ptr->sdf(what->buf, what->stride, get_buf_from_mv(in_what, &mv),
-                        in_what->stride);
-        if (sad < best_sad) {
-          sad += mvsad_err_cost(x, &mv, ref_mv, sad_per_bit);
-          if (sad < best_sad) {
-            best_sad = sad;
-            if (second_best_mv) {
-              *second_best_mv = *best_mv;
-            }
-            *best_mv = mv;
-          }
-        }
-      } else {
-        // 4 sads in a single call if we are checking every location
-        if (c + 3 <= end_col) {
-          unsigned int sads[4];
-          const uint8_t *addrs[4];
-          for (i = 0; i < 4; ++i) {
-            const FULLPEL_MV mv = { start_mv.row + r, start_mv.col + c + i };
-            addrs[i] = get_buf_from_mv(in_what, &mv);
-          }
-          fn_ptr->sdx4df(what->buf, what->stride, addrs, in_what->stride, sads);
-
-          for (i = 0; i < 4; ++i) {
-            if (sads[i] < best_sad) {
-              const FULLPEL_MV mv = { start_mv.row + r, start_mv.col + c + i };
-              const unsigned int sad =
-                  sads[i] + mvsad_err_cost(x, &mv, ref_mv, sad_per_bit);
-              if (sad < best_sad) {
-                best_sad = sad;
-                if (second_best_mv) {
-                  *second_best_mv = *best_mv;
-                }
-                *best_mv = mv;
-              }
-            }
-          }
-        } else {
-          for (i = 0; i < end_col - c; ++i) {
-            const FULLPEL_MV mv = { start_mv.row + r, start_mv.col + c + i };
-            unsigned int sad =
-                fn_ptr->sdf(what->buf, what->stride,
-                            get_buf_from_mv(in_what, &mv), in_what->stride);
-            if (sad < best_sad) {
-              sad += mvsad_err_cost(x, &mv, ref_mv, sad_per_bit);
-              if (sad < best_sad) {
-                best_sad = sad;
-                if (second_best_mv) {
-                  *second_best_mv = *best_mv;
-                }
-                *best_mv = mv;
-              }
-            }
-          }
-        }
-      }
-    }
+  if (mask) {
+    bestsme = vfp->msvf(src_buf, src_stride, 0, 0,
+                        get_buf_from_mv(ref, this_mv), ref_stride, second_pred,
+                        mask, mask_stride, invert_mask, &unused);
+  } else if (second_pred) {
+    bestsme = vfp->svaf(get_buf_from_mv(ref, this_mv), ref_stride, 0, 0,
+                        src_buf, src_stride, &unused, second_pred);
+  } else {
+    bestsme = vfp->vf(src_buf, src_stride, get_buf_from_mv(ref, this_mv),
+                      ref_stride, &unused);
   }
 
-  return best_sad;
+  const MV sub_this_mv = get_mv_from_fullmv(this_mv);
+  bestsme += mv_err_cost_(&sub_this_mv, &ms_params->mv_cost_params);
+
+  return bestsme;
 }
 
-static int diamond_search_sad(const MACROBLOCK *x,
-                              const search_site_config *cfg,
-                              FULLPEL_MV start_mv, FULLPEL_MV *best_mv,
-                              FULLPEL_MV *second_best_mv, int search_param,
-                              int sad_per_bit, int *num00,
-                              const aom_variance_fn_ptr_t *fn_ptr,
-                              const MV *ref_mv, uint8_t *second_pred,
-                              uint8_t *mask, int mask_stride, int inv_mask) {
-  const MACROBLOCKD *const xd = &x->e_mbd;
-  uint8_t *what = x->plane[0].src.buf;
-  const int what_stride = x->plane[0].src.stride;
-  const uint8_t *in_what;
-  const int in_what_stride = xd->plane[0].pre[0].stride;
+static INLINE int get_mvpred_compound_sad(
+    const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
+    const struct buf_2d *const src, const uint8_t *const ref_address,
+    const int ref_stride) {
+  const aom_variance_fn_ptr_t *vfp = ms_params->vfp;
+  const uint8_t *src_buf = src->buf;
+  const int src_stride = src->stride;
+
+  const uint8_t *mask = ms_params->mask;
+  const uint8_t *second_pred = ms_params->second_pred;
+  const int mask_stride = ms_params->mask_stride;
+  const int invert_mask = ms_params->inv_mask;
+
+  if (mask) {
+    return vfp->msdf(src_buf, src_stride, ref_address, ref_stride, second_pred,
+                     mask, mask_stride, invert_mask);
+  } else if (second_pred) {
+    return vfp->sdaf(src_buf, src_stride, ref_address, ref_stride, second_pred);
+  } else {
+    return vfp->sdf(src_buf, src_stride, ref_address, ref_stride);
+  }
+}
+
+static int diamond_search_sad(FULLPEL_MV start_mv,
+                              const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
+                              const int search_param, int *num00,
+                              FULLPEL_MV *best_mv, FULLPEL_MV *second_best_mv) {
+  const struct buf_2d *const src = ms_params->src;
+  const struct buf_2d *const ref = ms_params->ref;
+
+  const int ref_stride = ref->stride;
   const uint8_t *best_address;
 
+  const aom_variance_fn_ptr_t *vfp = ms_params->vfp;
+  const uint8_t *mask = ms_params->mask;
+  const uint8_t *second_pred = ms_params->second_pred;
+  const MV_COST_PARAMS *mv_cost_params = &ms_params->mv_cost_params;
+
+  const search_site_config *cfg = ms_params->search_sites;
+
   unsigned int bestsad = INT_MAX;
   int best_site = 0;
   int is_off_center = 0;
 
-  clamp_fullmv(&start_mv, &x->mv_limits);
+  clamp_fullmv(&start_mv, &ms_params->mv_limits);
 
   // search_param determines the length of the initial step and hence the number
   // of iterations.
   const int tot_steps = cfg->ss_count - search_param;
 
-  const FULLPEL_MV full_ref_mv = get_fullmv_from_mv(ref_mv);
   *num00 = 0;
   *best_mv = start_mv;
 
-  // Work out the start point for the search
-  in_what = get_buf_from_mv(&xd->plane[0].pre[0], &start_mv);
-  best_address = in_what;
-
   // Check the starting position
-  // TODO(jingning): unify the parameter interface for the following
-  // computation modes.
-  if (mask)
-    bestsad = fn_ptr->msdf(what, what_stride, in_what, in_what_stride,
-                           second_pred, mask, mask_stride, inv_mask);
-  else if (second_pred)
-    bestsad =
-        fn_ptr->sdaf(what, what_stride, in_what, in_what_stride, second_pred);
-  else
-    bestsad = fn_ptr->sdf(what, what_stride, in_what, in_what_stride);
-
-  bestsad += mvsad_err_cost(x, best_mv, &full_ref_mv, sad_per_bit);
+  best_address = get_buf_from_mv(ref, &start_mv);
+  bestsad = get_mvpred_compound_sad(ms_params, src, best_address, ref_stride);
+  bestsad += mvsad_err_cost_(best_mv, &ms_params->mv_cost_params);
 
   int next_step_size = tot_steps > 2 ? cfg->radius[tot_steps - 2] : 1;
   for (int step = tot_steps - 1; step >= 0; --step) {
@@ -1042,13 +1036,15 @@
 
     int all_in = 1, j;
     // Trap illegal vectors
-    all_in &= best_mv->row + ss[1].mv.row >= x->mv_limits.row_min;
-    all_in &= best_mv->row + ss[2].mv.row <= x->mv_limits.row_max;
-    all_in &= best_mv->col + ss[3].mv.col >= x->mv_limits.col_min;
-    all_in &= best_mv->col + ss[4].mv.col <= x->mv_limits.col_max;
+    all_in &= best_mv->row + ss[1].mv.row >= ms_params->mv_limits.row_min;
+    all_in &= best_mv->row + ss[2].mv.row <= ms_params->mv_limits.row_max;
+    all_in &= best_mv->col + ss[3].mv.col >= ms_params->mv_limits.col_min;
+    all_in &= best_mv->col + ss[4].mv.col <= ms_params->mv_limits.col_max;
 
     // TODO(anyone): Implement 4 points search for msdf&sdaf
     if (all_in && !mask && !second_pred) {
+      const uint8_t *src_buf = src->buf;
+      const int src_stride = src->stride;
       for (int idx = 1; idx <= cfg->searches_per_step[step]; idx += 4) {
         unsigned char const *block_offset[4];
         unsigned int sads[4];
@@ -1056,14 +1052,13 @@
         for (j = 0; j < 4; j++)
           block_offset[j] = ss[idx + j].offset + best_address;
 
-        fn_ptr->sdx4df(what, what_stride, block_offset, in_what_stride, sads);
+        vfp->sdx4df(src_buf, src_stride, block_offset, ref_stride, sads);
         for (j = 0; j < 4; j++) {
           if (sads[j] < bestsad) {
             const FULLPEL_MV this_mv = { best_mv->row + ss[idx + j].mv.row,
                                          best_mv->col + ss[idx + j].mv.col };
             unsigned int thissad =
-                sads[j] +
-                mvsad_err_cost(x, &this_mv, &full_ref_mv, sad_per_bit);
+                sads[j] + mvsad_err_cost_(&this_mv, mv_cost_params);
             if (thissad < bestsad) {
               bestsad = thissad;
               best_site = idx + j;
@@ -1076,23 +1071,15 @@
         const FULLPEL_MV this_mv = { best_mv->row + ss[idx].mv.row,
                                      best_mv->col + ss[idx].mv.col };
 
-        if (av1_is_fullmv_in_range(&x->mv_limits, this_mv)) {
+        if (av1_is_fullmv_in_range(&ms_params->mv_limits, this_mv)) {
           const uint8_t *const check_here = ss[idx].offset + best_address;
           unsigned int thissad;
 
-          if (mask)
-            thissad =
-                fn_ptr->msdf(what, what_stride, check_here, in_what_stride,
-                             second_pred, mask, mask_stride, inv_mask);
-          else if (second_pred)
-            thissad = fn_ptr->sdaf(what, what_stride, check_here,
-                                   in_what_stride, second_pred);
-          else
-            thissad =
-                fn_ptr->sdf(what, what_stride, check_here, in_what_stride);
+          thissad =
+              get_mvpred_compound_sad(ms_params, src, check_here, ref_stride);
 
           if (thissad < bestsad) {
-            thissad += mvsad_err_cost(x, &this_mv, &full_ref_mv, sad_per_bit);
+            thissad += mvsad_err_cost_(&this_mv, mv_cost_params);
             if (thissad < bestsad) {
               bestsad = thissad;
               best_site = idx;
@@ -1129,29 +1116,17 @@
 /* do_refine: If last step (1-away) of n-step search doesn't pick the center
               point as the best match, we will do a final 1-away diamond
               refining search  */
-static int full_pixel_diamond(const MACROBLOCK *x, const FULLPEL_MV start_mv,
-                              int step_param, int sadpb, int *cost_list,
-                              const aom_variance_fn_ptr_t *fn_ptr,
-                              const MV *ref_mv, const search_site_config *cfg,
-                              uint8_t *second_pred, uint8_t *mask,
-                              int mask_stride, int inv_mask,
+static int full_pixel_diamond(const FULLPEL_MV start_mv,
+                              const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
+                              const int step_param, int *cost_list,
                               FULLPEL_MV *best_mv, FULLPEL_MV *second_best_mv) {
+  const search_site_config *cfg = ms_params->search_sites;
   int thissme, n, num00 = 0;
-  int bestsme = diamond_search_sad(x, cfg, start_mv, best_mv, second_best_mv,
-                                   step_param, sadpb, &n, fn_ptr, ref_mv,
-                                   second_pred, mask, mask_stride, inv_mask);
+  int bestsme = diamond_search_sad(start_mv, ms_params, step_param, &n, best_mv,
+                                   second_best_mv);
 
   if (bestsme < INT_MAX) {
-    if (mask)
-      bestsme = av1_get_mvpred_mask_var(
-          x, best_mv, ref_mv, second_pred, mask, mask_stride, inv_mask, fn_ptr,
-          &x->plane[0].src, &x->e_mbd.plane[0].pre[0]);
-    else if (second_pred)
-      bestsme =
-          av1_get_mvpred_av_var(x, best_mv, ref_mv, second_pred, fn_ptr,
-                                &x->plane[0].src, &x->e_mbd.plane[0].pre[0]);
-    else
-      bestsme = av1_get_mvpred_var(x, best_mv, ref_mv, fn_ptr);
+    bestsme = get_mvpred_compound_var_cost(ms_params, best_mv);
   }
 
   // If there won't be more n-step search, check to see if refining search is
@@ -1159,28 +1134,18 @@
   const int further_steps = cfg->ss_count - 1 - step_param;
   while (n < further_steps) {
     ++n;
-    FULLPEL_MV tmp_best_mv;
 
     if (num00) {
       num00--;
     } else {
       // TODO(chiyotsai@google.com): There is another bug here where the second
       // best mv gets incorrectly overwritten. Fix it later.
-      thissme = diamond_search_sad(
-          x, cfg, start_mv, &tmp_best_mv, second_best_mv, step_param + n, sadpb,
-          &num00, fn_ptr, ref_mv, second_pred, mask, mask_stride, inv_mask);
+      FULLPEL_MV tmp_best_mv;
+      thissme = diamond_search_sad(start_mv, ms_params, step_param + n, &num00,
+                                   &tmp_best_mv, second_best_mv);
 
       if (thissme < INT_MAX) {
-        if (mask)
-          thissme = av1_get_mvpred_mask_var(
-              x, &tmp_best_mv, ref_mv, second_pred, mask, mask_stride, inv_mask,
-              fn_ptr, &x->plane[0].src, &x->e_mbd.plane[0].pre[0]);
-        else if (second_pred)
-          thissme = av1_get_mvpred_av_var(x, &tmp_best_mv, ref_mv, second_pred,
-                                          fn_ptr, &x->plane[0].src,
-                                          &x->e_mbd.plane[0].pre[0]);
-        else
-          thissme = av1_get_mvpred_var(x, &tmp_best_mv, ref_mv, fn_ptr);
+        thissme = get_mvpred_compound_var_cost(ms_params, &tmp_best_mv);
       }
 
       if (thissme < bestsme) {
@@ -1194,26 +1159,120 @@
   if (cost_list) {
     if (USE_SAD_COSTLIST) {
       const int costlist_has_sad = 0;
-      calc_int_sad_list(x, ref_mv, sadpb, fn_ptr, &x->best_mv.as_fullmv,
-                        cost_list, costlist_has_sad);
+      calc_int_sad_list(*best_mv, ms_params, cost_list, costlist_has_sad);
     } else {
-      calc_int_cost_list(x, ref_mv, fn_ptr, &x->best_mv.as_fullmv, cost_list);
+      calc_int_cost_list(*best_mv, ms_params, cost_list);
     }
   }
   return bestsme;
 }
 
-#define MIN_RANGE 7
-#define MAX_RANGE 256
-#define MIN_INTERVAL 1
+// Exhaustive motion search around a given centre position with a given
+// step size.
+static int exhaustive_mesh_search(FULLPEL_MV start_mv,
+                                  const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
+                                  const int range, const int step,
+                                  FULLPEL_MV *best_mv,
+                                  FULLPEL_MV *second_best_mv) {
+  const aom_variance_fn_ptr_t *vfp = ms_params->vfp;
+  const MV_COST_PARAMS *mv_cost_params = &ms_params->mv_cost_params;
+  const struct buf_2d *const src = ms_params->src;
+  const struct buf_2d *const ref = ms_params->ref;
+  const int ref_stride = ref->stride;
+  unsigned int best_sad = INT_MAX;
+  int r, c, i;
+  int start_col, end_col, start_row, end_row;
+  int col_step = (step > 1) ? step : 4;
+
+  assert(step >= 1);
+
+  clamp_fullmv(&start_mv, &ms_params->mv_limits);
+  *best_mv = start_mv;
+  best_sad = get_mvpred_sad(ms_params, src, get_buf_from_mv(ref, &start_mv),
+                            ref_stride);
+  best_sad += mvsad_err_cost_(&start_mv, mv_cost_params);
+  start_row = AOMMAX(-range, ms_params->mv_limits.row_min - start_mv.row);
+  start_col = AOMMAX(-range, ms_params->mv_limits.col_min - start_mv.col);
+  end_row = AOMMIN(range, ms_params->mv_limits.row_max - start_mv.row);
+  end_col = AOMMIN(range, ms_params->mv_limits.col_max - start_mv.col);
+
+  for (r = start_row; r <= end_row; r += step) {
+    for (c = start_col; c <= end_col; c += col_step) {
+      // Step > 1 means we are not checking every location in this pass.
+      if (step > 1) {
+        const FULLPEL_MV mv = { start_mv.row + r, start_mv.col + c };
+        unsigned int sad = get_mvpred_sad(
+            ms_params, src, get_buf_from_mv(ref, &mv), ref_stride);
+        if (sad < best_sad) {
+          sad += mvsad_err_cost_(&mv, mv_cost_params);
+          if (sad < best_sad) {
+            best_sad = sad;
+            if (second_best_mv) {
+              *second_best_mv = *best_mv;
+            }
+            *best_mv = mv;
+          }
+        }
+      } else {
+        // 4 sads in a single call if we are checking every location
+        if (c + 3 <= end_col) {
+          unsigned int sads[4];
+          const uint8_t *addrs[4];
+          for (i = 0; i < 4; ++i) {
+            const FULLPEL_MV mv = { start_mv.row + r, start_mv.col + c + i };
+            addrs[i] = get_buf_from_mv(ref, &mv);
+          }
+          vfp->sdx4df(src->buf, src->stride, addrs, ref_stride, sads);
+
+          for (i = 0; i < 4; ++i) {
+            if (sads[i] < best_sad) {
+              const FULLPEL_MV mv = { start_mv.row + r, start_mv.col + c + i };
+              const unsigned int sad =
+                  sads[i] + mvsad_err_cost_(&mv, mv_cost_params);
+              if (sad < best_sad) {
+                best_sad = sad;
+                if (second_best_mv) {
+                  *second_best_mv = *best_mv;
+                }
+                *best_mv = mv;
+              }
+            }
+          }
+        } else {
+          for (i = 0; i < end_col - c; ++i) {
+            const FULLPEL_MV mv = { start_mv.row + r, start_mv.col + c + i };
+            unsigned int sad = get_mvpred_sad(
+                ms_params, src, get_buf_from_mv(ref, &mv), ref_stride);
+            if (sad < best_sad) {
+              sad += mvsad_err_cost_(&mv, mv_cost_params);
+              if (sad < best_sad) {
+                best_sad = sad;
+                if (second_best_mv) {
+                  *second_best_mv = *best_mv;
+                }
+                *best_mv = mv;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return best_sad;
+}
+
 // Runs an limited range exhaustive mesh search using a pattern set
 // according to the encode speed profile.
-static int full_pixel_exhaustive(
-    const MACROBLOCK *x, const FULLPEL_MV start_mv, int sadpb, int *cost_list,
-    const aom_variance_fn_ptr_t *fn_ptr, const MV *ref_mv, FULLPEL_MV *best_mv,
-    FULLPEL_MV *second_best_mv,
-    const struct MESH_PATTERN *const mesh_patterns) {
-  FULLPEL_MV full_ref_mv = get_fullmv_from_mv(ref_mv);
+static int full_pixel_exhaustive(const FULLPEL_MV start_mv,
+                                 const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
+                                 const struct MESH_PATTERN *const mesh_patterns,
+                                 int *cost_list, FULLPEL_MV *best_mv,
+                                 FULLPEL_MV *second_best_mv) {
+  const int kMinRange = 7;
+  const int kMaxRange = 256;
+  const int kMinInterval = 1;
+
   int bestsme;
   int i;
   int interval = mesh_patterns[0].interval;
@@ -1223,7 +1282,7 @@
   *best_mv = start_mv;
 
   // Trap illegal values for interval and range for this function.
-  if ((range < MIN_RANGE) || (range > MAX_RANGE) || (interval < MIN_INTERVAL) ||
+  if ((range < kMinRange) || (range > kMaxRange) || (interval < kMinInterval) ||
       (interval > range))
     return INT_MAX;
 
@@ -1232,37 +1291,37 @@
   // Check size of proposed first range against magnitude of the centre
   // value used as a starting point.
   range = AOMMAX(range, (5 * AOMMAX(abs(best_mv->row), abs(best_mv->col))) / 4);
-  range = AOMMIN(range, MAX_RANGE);
+  range = AOMMIN(range, kMaxRange);
   interval = AOMMAX(interval, range / baseline_interval_divisor);
 
   // initial search
-  bestsme = exhuastive_mesh_search(x, &full_ref_mv, best_mv, second_best_mv,
-                                   range, interval, sadpb, fn_ptr, *best_mv);
+  bestsme = exhaustive_mesh_search(*best_mv, ms_params, range, interval,
+                                   best_mv, second_best_mv);
 
-  if ((interval > MIN_INTERVAL) && (range > MIN_RANGE)) {
+  if ((interval > kMinInterval) && (range > kMinRange)) {
     // Progressive searches with range and step size decreasing each time
     // till we reach a step size of 1. Then break out.
     for (i = 1; i < MAX_MESH_STEP; ++i) {
       // First pass with coarser step and longer range
-      bestsme = exhuastive_mesh_search(
-          x, &full_ref_mv, best_mv, second_best_mv, mesh_patterns[i].range,
-          mesh_patterns[i].interval, sadpb, fn_ptr, *best_mv);
+      bestsme = exhaustive_mesh_search(
+          *best_mv, ms_params, mesh_patterns[i].range,
+          mesh_patterns[i].interval, best_mv, second_best_mv);
 
       if (mesh_patterns[i].interval == 1) break;
     }
   }
 
-  if (bestsme < INT_MAX)
-    bestsme = av1_get_mvpred_var(x, best_mv, ref_mv, fn_ptr);
+  if (bestsme < INT_MAX) {
+    bestsme = get_mvpred_var_cost(ms_params, best_mv);
+  }
 
   // Return cost list.
   if (cost_list) {
     if (USE_SAD_COSTLIST) {
       const int costlist_has_sad = 0;
-      calc_int_sad_list(x, ref_mv, sadpb, fn_ptr, best_mv, cost_list,
-                        costlist_has_sad);
+      calc_int_sad_list(*best_mv, ms_params, cost_list, costlist_has_sad);
     } else {
-      calc_int_cost_list(x, ref_mv, fn_ptr, best_mv, cost_list);
+      calc_int_cost_list(*best_mv, ms_params, cost_list);
     }
   }
   return bestsme;
@@ -1303,12 +1362,16 @@
     best_sad = fn_ptr->msdf(what->buf, what->stride,
                             get_buf_from_mv(in_what, best_mv), in_what->stride,
                             second_pred, mask, mask_stride, invert_mask) +
-               mvsad_err_cost(x, best_mv, &full_ref_mv, error_per_bit);
+               mvsad_err_cost(best_mv, &full_ref_mv, x->nmv_vec_cost,
+                              CONVERT_TO_CONST_MVCOST(x->mv_cost_stack),
+                              error_per_bit, x->mv_cost_type);
   } else {
     best_sad =
         fn_ptr->sdaf(what->buf, what->stride, get_buf_from_mv(in_what, best_mv),
                      in_what->stride, second_pred) +
-        mvsad_err_cost(x, best_mv, &full_ref_mv, error_per_bit);
+        mvsad_err_cost(best_mv, &full_ref_mv, x->nmv_vec_cost,
+                       CONVERT_TO_CONST_MVCOST(x->mv_cost_stack), error_per_bit,
+                       x->mv_cost_type);
   }
 
   do_refine_search_grid[grid_coord] = 1;
@@ -1337,7 +1400,10 @@
                              second_pred);
         }
         if (sad < best_sad) {
-          sad += mvsad_err_cost(x, &mv, &full_ref_mv, error_per_bit);
+          sad += mvsad_err_cost(&mv, &full_ref_mv, x->nmv_vec_cost,
+                                CONVERT_TO_CONST_MVCOST(x->mv_cost_stack),
+                                error_per_bit, x->mv_cost_type);
+
           if (sad < best_sad) {
             best_sad = sad;
             best_site = j;
@@ -1357,15 +1423,22 @@
   return best_sad;
 }
 
-int av1_full_pixel_search(const AV1_COMP *cpi, const MACROBLOCK *x,
-                          BLOCK_SIZE bsize, const FULLPEL_MV start_mv,
-                          int step_param, int method, int run_mesh_search,
-                          int error_per_bit, int *cost_list, const MV *ref_mv,
-                          int is_intra_mode, const search_site_config *cfg,
+int av1_full_pixel_search(const FULLPEL_MV start_mv,
+                          const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
+                          const int step_param, int *cost_list,
                           FULLPEL_MV *best_mv, FULLPEL_MV *second_best_mv) {
-  const SPEED_FEATURES *const sf = &cpi->sf;
-  const aom_variance_fn_ptr_t *fn_ptr = &cpi->fn_ptr[bsize];
-  int bestsme = 0;
+  const BLOCK_SIZE bsize = ms_params->bsize;
+
+  const SEARCH_METHODS search_method = ms_params->search_method;
+
+  const int is_intra_mode = ms_params->is_intra_mode;
+  int run_mesh_search = ms_params->run_mesh_search;
+
+  int var = 0;
+
+  assert(ms_params->second_pred == NULL && ms_params->mask == NULL &&
+         ms_params->mask_stride == 0 &&
+         "av1_full_pixel_search does not support compound pred");
 
   if (cost_list) {
     cost_list[0] = INT_MAX;
@@ -1375,48 +1448,46 @@
     cost_list[4] = INT_MAX;
   }
 
-  switch (method) {
+  switch (search_method) {
     case FAST_DIAMOND:
-      bestsme = fast_dia_search(x, start_mv, step_param, error_per_bit, 0,
-                                cost_list, fn_ptr, ref_mv, best_mv);
+      var = fast_dia_search(start_mv, ms_params, step_param, 0, cost_list,
+                            best_mv);
       break;
     case FAST_HEX:
-      bestsme = fast_hex_search(x, start_mv, step_param, error_per_bit, 0,
-                                cost_list, fn_ptr, ref_mv, best_mv);
+      var = fast_hex_search(start_mv, ms_params, step_param, 0, cost_list,
+                            best_mv);
       break;
     case HEX:
-      bestsme = hex_search(x, start_mv, step_param, error_per_bit, 1, cost_list,
-                           fn_ptr, ref_mv, best_mv);
+      var = hex_search(start_mv, ms_params, step_param, 1, cost_list, best_mv);
       break;
     case SQUARE:
-      bestsme = square_search(x, start_mv, step_param, error_per_bit, 1,
-                              cost_list, fn_ptr, ref_mv, best_mv);
+      var =
+          square_search(start_mv, ms_params, step_param, 1, cost_list, best_mv);
       break;
     case BIGDIA:
-      bestsme = bigdia_search(x, start_mv, step_param, error_per_bit, 1,
-                              cost_list, fn_ptr, ref_mv, best_mv);
+      var =
+          bigdia_search(start_mv, ms_params, step_param, 1, cost_list, best_mv);
       break;
     case NSTEP:
     case DIAMOND:
-      bestsme = full_pixel_diamond(x, start_mv, step_param, error_per_bit,
-                                   cost_list, fn_ptr, ref_mv, cfg, NULL, NULL,
-                                   0, 0, best_mv, second_best_mv);
+      var = full_pixel_diamond(start_mv, ms_params, step_param, cost_list,
+                               best_mv, second_best_mv);
       break;
     default: assert(0 && "Invalid search method.");
   }
 
   // Should we allow a follow on exhaustive search?
-  if (!run_mesh_search && method == NSTEP) {
-    int exhuastive_thr = sf->mv_sf.exhaustive_searches_thresh;
+  if (!run_mesh_search && search_method == NSTEP) {
+    int exhuastive_thr = ms_params->force_mesh_thresh;
     exhuastive_thr >>=
         10 - (mi_size_wide_log2[bsize] + mi_size_high_log2[bsize]);
     // Threshold variance for an exhaustive full search.
-    if (bestsme > exhuastive_thr) run_mesh_search = 1;
+    if (var > exhuastive_thr) run_mesh_search = 1;
   }
 
   // TODO(yunqing): the following is used to reduce mesh search in temporal
   // filtering. Can extend it to intrabc.
-  if (!is_intra_mode && sf->mv_sf.prune_mesh_search) {
+  if (!is_intra_mode && ms_params->prune_mesh_search) {
     const int full_pel_mv_diff = AOMMAX(abs(start_mv.row - best_mv->row),
                                         abs(start_mv.col - best_mv->col));
     if (full_pel_mv_diff <= 4) {
@@ -1429,21 +1500,21 @@
     FULLPEL_MV tmp_mv_ex;
     // Pick the mesh pattern for exhaustive search based on the toolset (intraBC
     // or non-intraBC)
-    const MESH_PATTERN *const mesh_patterns =
-        is_intra_mode ? sf->mv_sf.intrabc_mesh_patterns
-                      : sf->mv_sf.mesh_patterns;
     // TODO(chiyotsai@google.com):  There is a bug here where the second best mv
     // gets overwritten without actually comparing the rdcost.
-    var_ex = full_pixel_exhaustive(x, *best_mv, error_per_bit, cost_list,
-                                   fn_ptr, ref_mv, &tmp_mv_ex, second_best_mv,
-                                   mesh_patterns);
-    if (var_ex < bestsme) {
-      bestsme = var_ex;
+    const MESH_PATTERN *const mesh_patterns =
+        ms_params->mesh_patterns[is_intra_mode];
+    // TODO(chiyotsai@google.com): the second best mv is not set correctly by
+    // full_pixel_exhaustive, which can incorrectly override it.
+    var_ex = full_pixel_exhaustive(*best_mv, ms_params, mesh_patterns,
+                                   cost_list, &tmp_mv_ex, second_best_mv);
+    if (var_ex < var) {
+      var = var_ex;
       *best_mv = tmp_mv_ex;
     }
   }
 
-  return bestsme;
+  return var;
 }
 
 void av1_intrabc_hash_search(const AV1_COMP *cpi, MACROBLOCK *x,
@@ -1508,214 +1579,6 @@
   }
 }
 
-// =============================================================================
-//  Fullpixel Motion Search: OBMC
-// =============================================================================
-static int get_obmc_mvpred_var(const MACROBLOCK *x, const int32_t *wsrc,
-                               const int32_t *mask, const FULLPEL_MV *best_mv,
-                               const MV *ref_mv,
-                               const aom_variance_fn_ptr_t *vfp) {
-  const MACROBLOCKD *const xd = &x->e_mbd;
-  const struct buf_2d *const in_what = xd->plane[0].pre;
-  const MV mv = get_mv_from_fullmv(best_mv);
-  const MV_COST_TYPE mv_cost_type = x->mv_cost_type;
-  unsigned int unused;
-
-  return vfp->ovf(get_buf_from_mv(in_what, best_mv), in_what->stride, wsrc,
-                  mask, &unused) +
-         mv_err_cost(&mv, ref_mv, x->nmv_vec_cost,
-                     CONVERT_TO_CONST_MVCOST(x->mv_cost_stack), x->errorperbit,
-                     mv_cost_type);
-}
-
-static int obmc_refining_search_sad(const MACROBLOCK *x, const int32_t *wsrc,
-                                    const int32_t *mask, FULLPEL_MV *best_mv,
-                                    int error_per_bit, int search_range,
-                                    const aom_variance_fn_ptr_t *fn_ptr,
-                                    const MV *ref_mv) {
-  const MV neighbors[4] = { { -1, 0 }, { 0, -1 }, { 0, 1 }, { 1, 0 } };
-  const MACROBLOCKD *const xd = &x->e_mbd;
-  const struct buf_2d *const in_what = xd->plane[0].pre;
-  const FULLPEL_MV full_ref_mv = get_fullmv_from_mv(ref_mv);
-  unsigned int best_sad =
-      fn_ptr->osdf(get_buf_from_mv(in_what, best_mv), in_what->stride, wsrc,
-                   mask) +
-      mvsad_err_cost(x, best_mv, &full_ref_mv, error_per_bit);
-  int i, j;
-
-  for (i = 0; i < search_range; i++) {
-    int best_site = -1;
-
-    for (j = 0; j < 4; j++) {
-      const FULLPEL_MV mv = { best_mv->row + neighbors[j].row,
-                              best_mv->col + neighbors[j].col };
-      if (av1_is_fullmv_in_range(&x->mv_limits, mv)) {
-        unsigned int sad = fn_ptr->osdf(get_buf_from_mv(in_what, &mv),
-                                        in_what->stride, wsrc, mask);
-        if (sad < best_sad) {
-          sad += mvsad_err_cost(x, &mv, &full_ref_mv, error_per_bit);
-          if (sad < best_sad) {
-            best_sad = sad;
-            best_site = j;
-          }
-        }
-      }
-    }
-
-    if (best_site == -1) {
-      break;
-    } else {
-      best_mv->row += neighbors[best_site].row;
-      best_mv->col += neighbors[best_site].col;
-    }
-  }
-  return best_sad;
-}
-
-static int obmc_diamond_search_sad(
-    const MACROBLOCK *x, const search_site_config *cfg, const int32_t *wsrc,
-    const int32_t *mask, FULLPEL_MV start_mv, FULLPEL_MV *best_mv,
-    int search_param, int sad_per_bit, int *num00,
-    const aom_variance_fn_ptr_t *fn_ptr, const MV *ref_mv) {
-  const MACROBLOCKD *const xd = &x->e_mbd;
-  const struct buf_2d *const in_what = xd->plane[0].pre;
-  // search_param determines the length of the initial step and hence the number
-  // of iterations
-  // 0 = initial step (MAX_FIRST_STEP) pel : 1 = (MAX_FIRST_STEP/2) pel, 2 =
-  // (MAX_FIRST_STEP/4) pel... etc.
-
-  const int tot_steps = MAX_MVSEARCH_STEPS - 1 - search_param;
-  const FULLPEL_MV full_ref_mv = get_fullmv_from_mv(ref_mv);
-  const uint8_t *best_address, *in_what_ref;
-  int best_sad = INT_MAX;
-  int best_site = 0;
-  int step;
-
-  clamp_fullmv(&start_mv, &x->mv_limits);
-  in_what_ref = get_buf_from_mv(in_what, &start_mv);
-  best_address = in_what_ref;
-  *num00 = 0;
-  *best_mv = start_mv;
-
-  // Check the starting position
-  best_sad = fn_ptr->osdf(best_address, in_what->stride, wsrc, mask) +
-             mvsad_err_cost(x, best_mv, &full_ref_mv, sad_per_bit);
-
-  for (step = tot_steps; step >= 0; --step) {
-    const search_site *const ss = cfg->ss[step];
-    best_site = 0;
-    for (int idx = 1; idx <= cfg->searches_per_step[step]; ++idx) {
-      const FULLPEL_MV mv = { best_mv->row + ss[idx].mv.row,
-                              best_mv->col + ss[idx].mv.col };
-      if (av1_is_fullmv_in_range(&x->mv_limits, mv)) {
-        int sad = fn_ptr->osdf(best_address + ss[idx].offset, in_what->stride,
-                               wsrc, mask);
-        if (sad < best_sad) {
-          sad += mvsad_err_cost(x, &mv, &full_ref_mv, sad_per_bit);
-          if (sad < best_sad) {
-            best_sad = sad;
-            best_site = idx;
-          }
-        }
-      }
-    }
-
-    if (best_site != 0) {
-      best_mv->row += ss[best_site].mv.row;
-      best_mv->col += ss[best_site].mv.col;
-      best_address += ss[best_site].offset;
-    } else if (best_address == in_what_ref) {
-      (*num00)++;
-    }
-  }
-  return best_sad;
-}
-
-static int obmc_full_pixel_diamond(const AV1_COMP *cpi, const MACROBLOCK *x,
-                                   const FULLPEL_MV start_mv, int step_param,
-                                   int sadpb, int do_refine,
-                                   const aom_variance_fn_ptr_t *fn_ptr,
-                                   const MV *ref_mv, FULLPEL_MV *best_mv,
-                                   const search_site_config *cfg) {
-  (void)cpi;  // to silence compiler warning
-  const int32_t *wsrc = x->wsrc_buf;
-  const int32_t *mask = x->mask_buf;
-  FULLPEL_MV tmp_mv;
-  int thissme, n, num00 = 0;
-  int bestsme = obmc_diamond_search_sad(x, cfg, wsrc, mask, start_mv, &tmp_mv,
-                                        step_param, sadpb, &n, fn_ptr, ref_mv);
-  if (bestsme < INT_MAX)
-    bestsme = get_obmc_mvpred_var(x, wsrc, mask, &tmp_mv, ref_mv, fn_ptr);
-  *best_mv = tmp_mv;
-
-  // If there won't be more n-step search, check to see if refining search is
-  // needed.
-  const int further_steps = cfg->ss_count - 1 - step_param;
-  if (n > further_steps) do_refine = 0;
-
-  while (n < further_steps) {
-    ++n;
-
-    if (num00) {
-      num00--;
-    } else {
-      thissme = obmc_diamond_search_sad(x, cfg, wsrc, mask, start_mv, &tmp_mv,
-                                        step_param + n, sadpb, &num00, fn_ptr,
-                                        ref_mv);
-      if (thissme < INT_MAX)
-        thissme = get_obmc_mvpred_var(x, wsrc, mask, &tmp_mv, ref_mv, fn_ptr);
-
-      // check to see if refining search is needed.
-      if (num00 > further_steps - n) do_refine = 0;
-
-      if (thissme < bestsme) {
-        bestsme = thissme;
-        *best_mv = tmp_mv;
-      }
-    }
-  }
-
-  // final 1-away diamond refining search
-  if (do_refine) {
-    const int search_range = 8;
-    tmp_mv = *best_mv;
-    thissme = obmc_refining_search_sad(x, wsrc, mask, &tmp_mv, sadpb,
-                                       search_range, fn_ptr, ref_mv);
-    if (thissme < INT_MAX)
-      thissme = get_obmc_mvpred_var(x, wsrc, mask, &tmp_mv, ref_mv, fn_ptr);
-    if (thissme < bestsme) {
-      bestsme = thissme;
-      *best_mv = tmp_mv;
-    }
-  }
-  return bestsme;
-}
-
-int av1_obmc_full_pixel_search(const AV1_COMP *cpi, const MACROBLOCK *x,
-                               const FULLPEL_MV start_mv, int step_param,
-                               int sadpb, const aom_variance_fn_ptr_t *fn_ptr,
-                               const MV *ref_mv, FULLPEL_MV *best_mv,
-                               const search_site_config *cfg) {
-  if (cpi->sf.inter_sf.obmc_full_pixel_search_level == 0) {
-    const int do_refine = 1;
-    const int bestsme =
-        obmc_full_pixel_diamond(cpi, x, start_mv, step_param, sadpb, do_refine,
-                                fn_ptr, ref_mv, best_mv, cfg);
-    return bestsme;
-  } else {
-    const int32_t *wsrc = x->wsrc_buf;
-    const int32_t *mask = x->mask_buf;
-    const int search_range = 8;
-    *best_mv = start_mv;
-    clamp_fullmv(best_mv, &x->mv_limits);
-    int thissme = obmc_refining_search_sad(x, wsrc, mask, best_mv, sadpb,
-                                           search_range, fn_ptr, ref_mv);
-    if (thissme < INT_MAX)
-      thissme = get_obmc_mvpred_var(x, wsrc, mask, best_mv, ref_mv, fn_ptr);
-    return thissme;
-  }
-}
-
 static int vector_match(int16_t *ref, int16_t *src, int bwl) {
   int best_sad = INT_MAX;
   int this_sad;
@@ -1923,6 +1786,228 @@
 }
 
 // =============================================================================
+//  Fullpixel Motion Search: OBMC
+// =============================================================================
+static int get_obmc_mvpred_var(const MACROBLOCK *x, const int32_t *wsrc,
+                               const int32_t *mask, const FULLPEL_MV *best_mv,
+                               const MV *ref_mv,
+                               const aom_variance_fn_ptr_t *vfp) {
+  const MACROBLOCKD *const xd = &x->e_mbd;
+  const struct buf_2d *const in_what = xd->plane[0].pre;
+  const MV mv = get_mv_from_fullmv(best_mv);
+  const MV_COST_TYPE mv_cost_type = x->mv_cost_type;
+  unsigned int unused;
+
+  return vfp->ovf(get_buf_from_mv(in_what, best_mv), in_what->stride, wsrc,
+                  mask, &unused) +
+         mv_err_cost(&mv, ref_mv, x->nmv_vec_cost,
+                     CONVERT_TO_CONST_MVCOST(x->mv_cost_stack), x->errorperbit,
+                     mv_cost_type);
+}
+
+static int obmc_refining_search_sad(const MACROBLOCK *x, const int32_t *wsrc,
+                                    const int32_t *mask, FULLPEL_MV *best_mv,
+                                    int error_per_bit, int search_range,
+                                    const aom_variance_fn_ptr_t *fn_ptr,
+                                    const MV *ref_mv) {
+  const MV neighbors[4] = { { -1, 0 }, { 0, -1 }, { 0, 1 }, { 1, 0 } };
+  const MACROBLOCKD *const xd = &x->e_mbd;
+  const struct buf_2d *const in_what = xd->plane[0].pre;
+  const FULLPEL_MV full_ref_mv = get_fullmv_from_mv(ref_mv);
+  unsigned int best_sad =
+      fn_ptr->osdf(get_buf_from_mv(in_what, best_mv), in_what->stride, wsrc,
+                   mask) +
+      mvsad_err_cost(best_mv, &full_ref_mv, x->nmv_vec_cost,
+                     CONVERT_TO_CONST_MVCOST(x->mv_cost_stack), error_per_bit,
+                     x->mv_cost_type);
+
+  int i, j;
+
+  for (i = 0; i < search_range; i++) {
+    int best_site = -1;
+
+    for (j = 0; j < 4; j++) {
+      const FULLPEL_MV mv = { best_mv->row + neighbors[j].row,
+                              best_mv->col + neighbors[j].col };
+      if (av1_is_fullmv_in_range(&x->mv_limits, mv)) {
+        unsigned int sad = fn_ptr->osdf(get_buf_from_mv(in_what, &mv),
+                                        in_what->stride, wsrc, mask);
+        if (sad < best_sad) {
+          sad += mvsad_err_cost(&mv, &full_ref_mv, x->nmv_vec_cost,
+                                CONVERT_TO_CONST_MVCOST(x->mv_cost_stack),
+                                error_per_bit, x->mv_cost_type);
+
+          if (sad < best_sad) {
+            best_sad = sad;
+            best_site = j;
+          }
+        }
+      }
+    }
+
+    if (best_site == -1) {
+      break;
+    } else {
+      best_mv->row += neighbors[best_site].row;
+      best_mv->col += neighbors[best_site].col;
+    }
+  }
+  return best_sad;
+}
+
+static int obmc_diamond_search_sad(
+    const MACROBLOCK *x, const search_site_config *cfg, const int32_t *wsrc,
+    const int32_t *mask, FULLPEL_MV start_mv, FULLPEL_MV *best_mv,
+    int search_param, int sad_per_bit, int *num00,
+    const aom_variance_fn_ptr_t *fn_ptr, const MV *ref_mv) {
+  const MACROBLOCKD *const xd = &x->e_mbd;
+  const struct buf_2d *const in_what = xd->plane[0].pre;
+  // search_param determines the length of the initial step and hence the number
+  // of iterations
+  // 0 = initial step (MAX_FIRST_STEP) pel : 1 = (MAX_FIRST_STEP/2) pel, 2 =
+  // (MAX_FIRST_STEP/4) pel... etc.
+
+  const int tot_steps = MAX_MVSEARCH_STEPS - 1 - search_param;
+  const FULLPEL_MV full_ref_mv = get_fullmv_from_mv(ref_mv);
+  const uint8_t *best_address, *in_what_ref;
+  int best_sad = INT_MAX;
+  int best_site = 0;
+  int step;
+
+  clamp_fullmv(&start_mv, &x->mv_limits);
+  in_what_ref = get_buf_from_mv(in_what, &start_mv);
+  best_address = in_what_ref;
+  *num00 = 0;
+  *best_mv = start_mv;
+
+  // Check the starting position
+  best_sad = fn_ptr->osdf(best_address, in_what->stride, wsrc, mask) +
+             mvsad_err_cost(best_mv, &full_ref_mv, x->nmv_vec_cost,
+                            CONVERT_TO_CONST_MVCOST(x->mv_cost_stack),
+                            sad_per_bit, x->mv_cost_type);
+
+  for (step = tot_steps; step >= 0; --step) {
+    const search_site *const ss = cfg->ss[step];
+    best_site = 0;
+    for (int idx = 1; idx <= cfg->searches_per_step[step]; ++idx) {
+      const FULLPEL_MV mv = { best_mv->row + ss[idx].mv.row,
+                              best_mv->col + ss[idx].mv.col };
+      if (av1_is_fullmv_in_range(&x->mv_limits, mv)) {
+        int sad = fn_ptr->osdf(best_address + ss[idx].offset, in_what->stride,
+                               wsrc, mask);
+        if (sad < best_sad) {
+          sad += mvsad_err_cost(&mv, &full_ref_mv, x->nmv_vec_cost,
+                                CONVERT_TO_CONST_MVCOST(x->mv_cost_stack),
+                                sad_per_bit, x->mv_cost_type);
+
+          if (sad < best_sad) {
+            best_sad = sad;
+            best_site = idx;
+          }
+        }
+      }
+    }
+
+    if (best_site != 0) {
+      best_mv->row += ss[best_site].mv.row;
+      best_mv->col += ss[best_site].mv.col;
+      best_address += ss[best_site].offset;
+    } else if (best_address == in_what_ref) {
+      (*num00)++;
+    }
+  }
+  return best_sad;
+}
+
+static int obmc_full_pixel_diamond(const MACROBLOCK *x,
+                                   const FULLPEL_MV start_mv, int step_param,
+                                   int sadpb, int do_refine,
+                                   const aom_variance_fn_ptr_t *fn_ptr,
+                                   const MV *ref_mv, FULLPEL_MV *best_mv,
+                                   const search_site_config *cfg) {
+  const int32_t *wsrc = x->wsrc_buf;
+  const int32_t *mask = x->mask_buf;
+  FULLPEL_MV tmp_mv;
+  int thissme, n, num00 = 0;
+  int bestsme = obmc_diamond_search_sad(x, cfg, wsrc, mask, start_mv, &tmp_mv,
+                                        step_param, sadpb, &n, fn_ptr, ref_mv);
+  if (bestsme < INT_MAX)
+    bestsme = get_obmc_mvpred_var(x, wsrc, mask, &tmp_mv, ref_mv, fn_ptr);
+  *best_mv = tmp_mv;
+
+  // If there won't be more n-step search, check to see if refining search is
+  // needed.
+  const int further_steps = cfg->ss_count - 1 - step_param;
+  if (n > further_steps) do_refine = 0;
+
+  while (n < further_steps) {
+    ++n;
+
+    if (num00) {
+      num00--;
+    } else {
+      thissme = obmc_diamond_search_sad(x, cfg, wsrc, mask, start_mv, &tmp_mv,
+                                        step_param + n, sadpb, &num00, fn_ptr,
+                                        ref_mv);
+      if (thissme < INT_MAX)
+        thissme = get_obmc_mvpred_var(x, wsrc, mask, &tmp_mv, ref_mv, fn_ptr);
+
+      // check to see if refining search is needed.
+      if (num00 > further_steps - n) do_refine = 0;
+
+      if (thissme < bestsme) {
+        bestsme = thissme;
+        *best_mv = tmp_mv;
+      }
+    }
+  }
+
+  // final 1-away diamond refining search
+  if (do_refine) {
+    const int search_range = 8;
+    tmp_mv = *best_mv;
+    thissme = obmc_refining_search_sad(x, wsrc, mask, &tmp_mv, sadpb,
+                                       search_range, fn_ptr, ref_mv);
+    if (thissme < INT_MAX)
+      thissme = get_obmc_mvpred_var(x, wsrc, mask, &tmp_mv, ref_mv, fn_ptr);
+    if (thissme < bestsme) {
+      bestsme = thissme;
+      *best_mv = tmp_mv;
+    }
+  }
+  return bestsme;
+}
+
+int av1_obmc_full_pixel_search(const MACROBLOCK *x, const FULLPEL_MV start_mv,
+                               const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
+                               const int step_param, FULLPEL_MV *best_mv) {
+  const aom_variance_fn_ptr_t *fn_ptr = ms_params->vfp;
+  const int sadpb = ms_params->mv_cost_params.sad_per_bit;
+  const MV *ref_mv = ms_params->mv_cost_params.ref_mv;
+
+  if (!ms_params->fast_obmc_search) {
+    const search_site_config *search_sites = ms_params->search_sites;
+
+    const int do_refine = 1;
+    const int bestsme =
+        obmc_full_pixel_diamond(x, start_mv, step_param, sadpb, do_refine,
+                                fn_ptr, ref_mv, best_mv, search_sites);
+    return bestsme;
+  } else {
+    const int32_t *wsrc = x->wsrc_buf;
+    const int32_t *mask = x->mask_buf;
+    const int search_range = 8;
+    *best_mv = start_mv;
+    clamp_fullmv(best_mv, &x->mv_limits);
+    int thissme = obmc_refining_search_sad(x, wsrc, mask, best_mv, sadpb,
+                                           search_range, fn_ptr, ref_mv);
+    if (thissme < INT_MAX)
+      thissme = get_obmc_mvpred_var(x, wsrc, mask, best_mv, ref_mv, fn_ptr);
+    return thissme;
+  }
+}
+
+// =============================================================================
 //  Subpixel Motion Search: Translational
 // =============================================================================
 #define INIT_SUBPEL_STEP_SIZE (4)
diff --git a/av1/encoder/mcomp.h b/av1/encoder/mcomp.h
index a251d03..5d6f424 100644
--- a/av1/encoder/mcomp.h
+++ b/av1/encoder/mcomp.h
@@ -62,9 +62,11 @@
 // =============================================================================
 typedef struct {
   const MV *ref_mv;
+  FULLPEL_MV full_ref_mv;
   const int *mvjcost;
   const int *mvcost[2];
   int error_per_bit;
+  int sad_per_bit;
   MV_COST_TYPE mv_cost_type;
 } MV_COST_PARAMS;
 
@@ -92,6 +94,56 @@
 // =============================================================================
 //  Fullpixel Motion Search
 // =============================================================================
+enum {
+  DIAMOND = 0,
+  NSTEP = 1,
+  HEX = 2,
+  BIGDIA = 3,
+  SQUARE = 4,
+  FAST_HEX = 5,
+  FAST_DIAMOND = 6
+} UENUM1BYTE(SEARCH_METHODS);
+
+// This struct holds fullpixel motion search parameters that should be constant
+// during the search
+typedef struct {
+  BLOCK_SIZE bsize;
+  const aom_variance_fn_ptr_t *vfp;
+
+  SEARCH_METHODS search_method;
+  const search_site_config *search_sites;
+  FullMvLimits mv_limits;
+
+  int run_mesh_search;    // Sets mesh search unless it got pruned by
+                          // prune_mesh_search.
+  int prune_mesh_search;  // Disables mesh search if the best_mv after a normal
+                          // search if close to the start_mv.
+  int force_mesh_thresh;  // Forces mesh search if the residue variance is
+                          // higher than the threshold.
+  const struct MESH_PATTERN *mesh_patterns[2];
+
+  int is_intra_mode;
+
+  const struct buf_2d *src;
+  const struct buf_2d *ref;
+
+  const uint8_t *second_pred;
+  const uint8_t *mask;
+  int mask_stride;
+  int inv_mask;
+
+  int fast_obmc_search;
+
+  // For calculating mv cost
+  MV_COST_PARAMS mv_cost_params;
+} FULLPEL_MOTION_SEARCH_PARAMS;
+
+void av1_make_default_fullpel_ms_params(FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
+                                        const struct AV1_COMP *cpi,
+                                        const MACROBLOCK *x, BLOCK_SIZE bsize,
+                                        const MV *ref_mv,
+                                        const search_site_config *search_sites);
+
 // Sets up configs for fullpixel diamond search
 void av1_init_dsmotion_compensation(search_site_config *cfg, int stride);
 // Sets up configs for firstpass motion search
@@ -150,22 +202,18 @@
                              const struct buf_2d *src,
                              const struct buf_2d *pre);
 
-int av1_full_pixel_search(const struct AV1_COMP *cpi, const MACROBLOCK *x,
-                          BLOCK_SIZE bsize, const FULLPEL_MV start_mv,
-                          int step_param, int method, int run_mesh_search,
-                          int error_per_bit, int *cost_list, const MV *ref_mv,
-                          int is_intra_mode, const search_site_config *cfg,
+int av1_full_pixel_search(const FULLPEL_MV start_mv,
+                          const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
+                          const int step_param, int *cost_list,
                           FULLPEL_MV *best_mv, FULLPEL_MV *second_best_mv);
 
 void av1_intrabc_hash_search(const struct AV1_COMP *cpi, MACROBLOCK *x,
                              BLOCK_SIZE bsize, const MV *ref_mv, int *bestsme,
                              FULLPEL_MV *best_mv);
 
-int av1_obmc_full_pixel_search(const struct AV1_COMP *cpi, const MACROBLOCK *x,
-                               const FULLPEL_MV start_mv, int step_param,
-                               int sadpb, const aom_variance_fn_ptr_t *fn_ptr,
-                               const MV *ref_mv, FULLPEL_MV *best_mv,
-                               const search_site_config *cfg);
+int av1_obmc_full_pixel_search(const MACROBLOCK *x, const FULLPEL_MV start_mv,
+                               const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
+                               const int step_param, FULLPEL_MV *best_mv);
 
 unsigned int av1_refine_warped_mv(const struct AV1_COMP *cpi,
                                   MACROBLOCK *const x, BLOCK_SIZE bsize,
diff --git a/av1/encoder/motion_search_facade.c b/av1/encoder/motion_search_facade.c
index 43a7cf8..ea71088 100644
--- a/av1/encoder/motion_search_facade.c
+++ b/av1/encoder/motion_search_facade.c
@@ -14,6 +14,7 @@
 #include "av1/common/reconinter.h"
 
 #include "av1/encoder/encodemv.h"
+#include "av1/encoder/encoder.h"
 #include "av1/encoder/motion_search_facade.h"
 #include "av1/encoder/partition_strategy.h"
 #include "av1/encoder/reconinter_enc.h"
@@ -123,22 +124,24 @@
   else
     start_mv = get_fullmv_from_mv(&ref_mv);
 
-  const int sadpb = x->sadperbit;
   int cost_list[5];
   int_mv second_best_mv;
   x->best_mv.as_int = second_best_mv.as_int = INVALID_MV;
+
+  const search_site_config *src_search_sites = &cpi->ss_cfg[SS_CFG_SRC];
+  FULLPEL_MOTION_SEARCH_PARAMS full_ms_params;
+  av1_make_default_fullpel_ms_params(&full_ms_params, cpi, x, bsize, &ref_mv,
+                                     src_search_sites);
+
   switch (mbmi->motion_mode) {
     case SIMPLE_TRANSLATION:
       bestsme = av1_full_pixel_search(
-          cpi, x, bsize, start_mv, step_param, cpi->sf.mv_sf.search_method, 0,
-          sadpb, cond_cost_list(cpi, cost_list), &ref_mv, 0,
-          &cpi->ss_cfg[SS_CFG_SRC], &x->best_mv.as_fullmv,
-          &second_best_mv.as_fullmv);
+          start_mv, &full_ms_params, step_param, cond_cost_list(cpi, cost_list),
+          &x->best_mv.as_fullmv, &second_best_mv.as_fullmv);
       break;
     case OBMC_CAUSAL:
-      bestsme = av1_obmc_full_pixel_search(
-          cpi, x, start_mv, step_param, sadpb, &cpi->fn_ptr[bsize], &ref_mv,
-          &(x->best_mv.as_fullmv), &cpi->ss_cfg[SS_CFG_SRC]);
+      bestsme = av1_obmc_full_pixel_search(x, start_mv, &full_ms_params,
+                                           step_param, &(x->best_mv.as_fullmv));
       break;
     default: assert(0 && "Invalid motion mode!\n");
   }
@@ -690,9 +693,7 @@
   const MV ref_mv = kZeroMv;
   const int step_param = cpi->mv_step_param;
   const FullMvLimits tmp_mv_limits = x->mv_limits;
-  const SEARCH_METHODS search_methods = cpi->sf.mv_sf.search_method;
-  const int do_mesh_search = 0;
-  const int sadpb = x->sadperbit;
+  const search_site_config *src_search_sites = &cpi->ss_cfg[SS_CFG_SRC];
   int cost_list[5];
   const int ref_idx = 0;
   int var;
@@ -706,12 +707,16 @@
                          num_planes);
   }
 
+  FULLPEL_MOTION_SEARCH_PARAMS full_ms_params;
+  av1_make_default_fullpel_ms_params(&full_ms_params, cpi, x, bsize, &ref_mv,
+                                     src_search_sites);
+
   // This overwrites the mv_limits so we will need to restore it later.
   av1_set_mv_search_range(&x->mv_limits, &ref_mv);
-  var = av1_full_pixel_search(
-      cpi, x, bsize, start_mv, step_param, search_methods, do_mesh_search,
-      sadpb, cond_cost_list(cpi, cost_list), &ref_mv, 0,
-      &cpi->ss_cfg[SS_CFG_SRC], &x->best_mv.as_fullmv, NULL);
+  var = av1_full_pixel_search(start_mv, &full_ms_params, step_param,
+                              cond_cost_list(cpi, cost_list),
+                              &x->best_mv.as_fullmv, NULL);
+
   // Restore
   x->mv_limits = tmp_mv_limits;
 
diff --git a/av1/encoder/nonrd_pickmode.c b/av1/encoder/nonrd_pickmode.c
index bcfd8d7..479304f 100644
--- a/av1/encoder/nonrd_pickmode.c
+++ b/av1/encoder/nonrd_pickmode.c
@@ -125,7 +125,6 @@
   MB_MODE_INFO *mi = xd->mi[0];
   struct buf_2d backup_yv12[MAX_MB_PLANE] = { { 0, 0, 0, 0, 0 } };
   int step_param = cpi->mv_step_param;
-  const int sadpb = x->sadperbit;
   FULLPEL_MV start_mv;
   const int ref = mi->ref_frame[0];
   const MV ref_mv = av1_get_ref_mv(x, mi->ref_mv_idx).as_mv;
@@ -156,10 +155,14 @@
   else
     center_mv = tmp_mv->as_mv;
 
-  av1_full_pixel_search(cpi, x, bsize, start_mv, step_param,
-                        cpi->sf.mv_sf.search_method, 0, sadpb,
-                        cond_cost_list(cpi, cost_list), &center_mv, 0,
-                        &cpi->ss_cfg[SS_CFG_SRC], &x->best_mv.as_fullmv, NULL);
+  const search_site_config *src_search_sites = &cpi->ss_cfg[SS_CFG_SRC];
+  FULLPEL_MOTION_SEARCH_PARAMS full_ms_params;
+  av1_make_default_fullpel_ms_params(&full_ms_params, cpi, x, bsize, &center_mv,
+                                     src_search_sites);
+
+  av1_full_pixel_search(start_mv, &full_ms_params, step_param,
+                        cond_cost_list(cpi, cost_list), &x->best_mv.as_fullmv,
+                        NULL);
 
   x->mv_limits = tmp_mv_limits;
   *tmp_mv = x->best_mv;
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index c8c0f6d..d7f2c6d 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -2732,14 +2732,19 @@
       continue;
     }
 
-    int step_param = cpi->mv_step_param;
-    FULLPEL_MV start_mv = get_fullmv_from_mv(&dv_ref.as_mv);
-    const int sadpb = x->sadperbit;
+    const int step_param = cpi->mv_step_param;
+    const FULLPEL_MV start_mv = get_fullmv_from_mv(&dv_ref.as_mv);
+    const search_site_config *lookahead_search_sites =
+        &cpi->ss_cfg[SS_CFG_LOOKAHEAD];
+    FULLPEL_MOTION_SEARCH_PARAMS full_ms_params;
+    av1_make_default_fullpel_ms_params(&full_ms_params, cpi, x, bsize,
+                                       &dv_ref.as_mv, lookahead_search_sites);
+    full_ms_params.is_intra_mode = 1;
     int cost_list[5];
-    int bestsme = av1_full_pixel_search(
-        cpi, x, bsize, start_mv, step_param, cpi->sf.mv_sf.search_method, 0,
-        sadpb, cond_cost_list(cpi, cost_list), &dv_ref.as_mv, 1,
-        &cpi->ss_cfg[SS_CFG_LOOKAHEAD], &x->best_mv.as_fullmv, NULL);
+
+    int bestsme = av1_full_pixel_search(start_mv, &full_ms_params, step_param,
+                                        cond_cost_list(cpi, cost_list),
+                                        &x->best_mv.as_fullmv, NULL);
     av1_intrabc_hash_search(cpi, x, bsize, &dv_ref.as_mv, &bestsme,
                             &x->best_mv.as_fullmv);
 
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index 4fe5cb0..0eb0241 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -335,11 +335,11 @@
     // speed feature accordingly
     sf->part_sf.simple_motion_search_split = allow_screen_content_tools ? 1 : 2;
 
-    sf->mv_sf.use_accurate_subpel_search = USE_4_TAPS;
     sf->mv_sf.exhaustive_searches_thresh <<= 1;
+    sf->mv_sf.obmc_full_pixel_search_level = 1;
+    sf->mv_sf.use_accurate_subpel_search = USE_4_TAPS;
 
     sf->inter_sf.disable_interinter_wedge_newmv_search = boosted ? 0 : 1;
-    sf->inter_sf.obmc_full_pixel_search_level = 1;
     sf->inter_sf.prune_comp_search_by_single_result = boosted ? 2 : 1;
     sf->inter_sf.prune_comp_type_by_comp_avg = 1;
     sf->inter_sf.prune_comp_type_by_model_rd = boosted ? 0 : 1;
@@ -645,9 +645,9 @@
     sf->part_sf.prune_ext_partition_types_search_level = 2;
     sf->part_sf.simple_motion_search_prune_rect = 1;
 
+    sf->mv_sf.obmc_full_pixel_search_level = 1;
     sf->mv_sf.use_accurate_subpel_search = USE_4_TAPS;
 
-    sf->inter_sf.obmc_full_pixel_search_level = 1;
     sf->inter_sf.prune_comp_search_by_single_result = 1;
     sf->inter_sf.reuse_inter_intra_mode = 1;
     sf->inter_sf.selective_ref_frame = 2;
@@ -933,16 +933,17 @@
 }
 
 static AOM_INLINE void init_mv_sf(MV_SPEED_FEATURES *mv_sf) {
-  mv_sf->search_method = NSTEP;
-  mv_sf->subpel_search_method = SUBPEL_TREE;
-  mv_sf->subpel_iters_per_step = 2;
-  mv_sf->subpel_force_stop = EIGHTH_PEL;
-  mv_sf->auto_mv_step_size = 0;
   mv_sf->adaptive_motion_search = 0;
-  mv_sf->use_accurate_subpel_search = USE_8_TAPS;
-  mv_sf->reduce_search_range = 0;
-  mv_sf->prune_mesh_search = 0;
+  mv_sf->auto_mv_step_size = 0;
   mv_sf->exhaustive_searches_thresh = 0;
+  mv_sf->obmc_full_pixel_search_level = 0;
+  mv_sf->prune_mesh_search = 0;
+  mv_sf->reduce_search_range = 0;
+  mv_sf->search_method = NSTEP;
+  mv_sf->subpel_force_stop = EIGHTH_PEL;
+  mv_sf->subpel_iters_per_step = 2;
+  mv_sf->subpel_search_method = SUBPEL_TREE;
+  mv_sf->use_accurate_subpel_search = USE_8_TAPS;
   mv_sf->use_fullpel_costlist = 0;
 }
 
@@ -973,7 +974,6 @@
   inter_sf->prune_compound_using_single_ref = 0;
   inter_sf->disable_onesided_comp = 0;
   inter_sf->prune_mode_search_simple_translation = 0;
-  inter_sf->obmc_full_pixel_search_level = 0;
   inter_sf->prune_comp_type_by_comp_avg = 0;
   inter_sf->disable_interinter_wedge_newmv_search = 0;
   inter_sf->enable_interinter_diffwtd_newmv_search = 0;
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h
index 36e0f71..923c0a5 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -124,16 +124,6 @@
 } UENUM1BYTE(DEV_SPEED_FEATURES);
 
 enum {
-  DIAMOND = 0,
-  NSTEP = 1,
-  HEX = 2,
-  BIGDIA = 3,
-  SQUARE = 4,
-  FAST_HEX = 5,
-  FAST_DIAMOND = 6
-} UENUM1BYTE(SEARCH_METHODS);
-
-enum {
   // No recode.
   DISALLOW_RECODE = 0,
   // Allow recode for KF and exceeding maximum frame bandwidth.
@@ -482,6 +472,11 @@
 
   // Use the rd cost around the best FULLPEL_MV to speed up subpel search
   int use_fullpel_costlist;
+
+  // Set the full pixel search level of obmc
+  // 0: obmc_full_pixel_diamond
+  // 1: obmc_refining_search_sad (faster)
+  int obmc_full_pixel_search_level;
 } MV_SPEED_FEATURES;
 
 typedef struct INTER_MODE_SPEED_FEATURES {
@@ -594,11 +589,6 @@
   // aggressiveness
   int prune_motion_mode_level;
 
-  // Set the full pixel search level of obmc
-  // 0: obmc_full_pixel_diamond
-  // 1: obmc_refining_search_sad (faster)
-  int obmc_full_pixel_search_level;
-
   // Prune obmc search using previous frame stats.
   int prune_obmc_prob_thresh;
 
diff --git a/av1/encoder/temporal_filter.c b/av1/encoder/temporal_filter.c
index 465cfb8..6dd6f91 100644
--- a/av1/encoder/temporal_filter.c
+++ b/av1/encoder/temporal_filter.c
@@ -87,9 +87,9 @@
   const int mask_stride = 0;
   const int invert_mask = 0;
   const int do_reset_fractional_mv = 1;
+  FULLPEL_MOTION_SEARCH_PARAMS full_ms_params;
   SUBPEL_MOTION_SEARCH_PARAMS ms_params;
 
-  const int sadperbit = mb->sadperbit;
   const search_site_config ss_cfg = cpi->ss_cfg[SS_CFG_LOOKAHEAD];
   const SEARCH_METHODS full_search_method = NSTEP;
   const int step_param = av1_init_search_range(
@@ -122,10 +122,15 @@
   // searched result will be stored in `mb->best_mv`.
   int block_error = INT_MAX;
   mb->mv_cost_type = mv_cost_type;
-  av1_full_pixel_search(cpi, mb, block_size, start_mv, step_param,
-                        full_search_method, 1, sadperbit,
-                        cond_cost_list(cpi, cost_list), &baseline_mv, 0,
-                        &ss_cfg, &mb->best_mv.as_fullmv, NULL);
+
+  av1_make_default_fullpel_ms_params(&full_ms_params, cpi, mb, block_size,
+                                     &baseline_mv, &ss_cfg);
+  full_ms_params.run_mesh_search = 1;
+  full_ms_params.search_method = full_search_method;
+  av1_full_pixel_search(start_mv, &full_ms_params, step_param,
+                        cond_cost_list(cpi, cost_list), &mb->best_mv.as_fullmv,
+                        NULL);
+
   // Since we are merely refining the result from full pixel search, we don't
   // need regularization for subpel search
   mb->mv_cost_type = MV_COST_NONE;
@@ -164,10 +169,15 @@
         mbd->plane[0].pre[0].buf = ref_frame->y_buffer + y_offset + offset;
         av1_set_mv_search_range(&mb->mv_limits, &baseline_mv);
         mb->mv_cost_type = mv_cost_type;
-        av1_full_pixel_search(cpi, mb, subblock_size, start_mv, step_param,
-                              full_search_method, 1, sadperbit,
-                              cond_cost_list(cpi, cost_list), &baseline_mv, 0,
-                              &ss_cfg, &mb->best_mv.as_fullmv, NULL);
+
+        av1_make_default_fullpel_ms_params(
+            &full_ms_params, cpi, mb, subblock_size, &baseline_mv, &ss_cfg);
+        full_ms_params.run_mesh_search = 1;
+        full_ms_params.search_method = full_search_method;
+        av1_full_pixel_search(start_mv, &full_ms_params, step_param,
+                              cond_cost_list(cpi, cost_list),
+                              &mb->best_mv.as_fullmv, NULL);
+
         // Since we are merely refining the result from full pixel search, we
         // don't need regularization for subpel search
         mb->mv_cost_type = MV_COST_NONE;
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index fe7649e..60facf8 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -125,11 +125,8 @@
                                   MV center_mv) {
   AV1_COMMON *cm = &cpi->common;
   MACROBLOCKD *const xd = &x->e_mbd;
-  MV_SPEED_FEATURES *const mv_sf = &cpi->sf.mv_sf;
   TPL_SPEED_FEATURES *tpl_sf = &cpi->sf.tpl_sf;
-  const SEARCH_METHODS search_method = mv_sf->search_method;
   int step_param;
-  int sadpb = x->sadperbit;
   uint32_t bestsme = UINT_MAX;
   int distortion;
   uint32_t sse;
@@ -153,9 +150,13 @@
 
   assert(ss_cfg->stride == stride_ref);
 
-  av1_full_pixel_search(cpi, x, bsize, start_mv, step_param, search_method, 0,
-                        sadpb, cond_cost_list(cpi, cost_list), &center_mv, 0,
-                        ss_cfg, &x->best_mv.as_fullmv, NULL);
+  FULLPEL_MOTION_SEARCH_PARAMS full_ms_params;
+  av1_make_default_fullpel_ms_params(&full_ms_params, cpi, x, bsize, &center_mv,
+                                     ss_cfg);
+
+  av1_full_pixel_search(start_mv, &full_ms_params, step_param,
+                        cond_cost_list(cpi, cost_list), &x->best_mv.as_fullmv,
+                        NULL);
 
   /* restore UMV window */
   x->mv_limits = tmp_mv_limits;