Add speed feature to control global motion compute

Adds a speed feature to control which references to use
to compute global motion.
Also adds logic to not compute duplicate sets of
parameters when reference frames point to the same
buffers.
Includes some renaming of functions to set good speed
features to make things clearer.

Change-Id: I641d33441fde98af18cad8d4db49cf7d5d153ead
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index 302d409..641c212 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -5124,6 +5124,24 @@
   }
   return (params_cost << AV1_PROB_COST_SHIFT);
 }
+
+static int do_gm_search_logic(SPEED_FEATURES *const sf, int num_refs_using_gm,
+                              int frame) {
+  (void)num_refs_using_gm;
+  (void)frame;
+  switch (sf->gm_search_type) {
+    case GM_FULL_SEARCH: return 1;
+    case GM_REDUCED_REF_SEARCH:
+#if CONFIG_EXT_REFS
+      return !(frame == LAST2_FRAME || frame == LAST3_FRAME);
+#else
+      return (num_refs_using_gm < 2);
+#endif  // CONFIG_EXT_REFS
+    case GM_DISABLE_SEARCH: return 0;
+    default: assert(0);
+  }
+  return 1;
+}
 #endif  // CONFIG_GLOBAL_MOTION
 
 static void encode_frame_internal(AV1_COMP *cpi) {
@@ -5154,9 +5172,10 @@
 
 #if CONFIG_GLOBAL_MOTION
   av1_zero(rdc->global_motion_used);
+  av1_zero(cpi->gmparams_cost);
   if (cpi->common.frame_type == INTER_FRAME && cpi->source &&
       !cpi->global_motion_search_done) {
-    YV12_BUFFER_CONFIG *ref_buf;
+    YV12_BUFFER_CONFIG *ref_buf[TOTAL_REFS_PER_FRAME];
     int frame;
     double params_by_motion[RANSAC_NUM_MOTIONS * (MAX_PARAMDIM - 1)];
     const double *params_this_motion;
@@ -5166,10 +5185,20 @@
     static const double kIdentityParams[MAX_PARAMDIM - 1] = {
       0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0
     };
+    int num_refs_using_gm = 0;
 
     for (frame = LAST_FRAME; frame <= ALTREF_FRAME; ++frame) {
-      ref_buf = get_ref_frame_buffer(cpi, frame);
-      if (ref_buf) {
+      ref_buf[frame] = get_ref_frame_buffer(cpi, frame);
+      int pframe;
+      // check for duplicate buffer
+      for (pframe = LAST_FRAME; pframe < frame; ++pframe) {
+        if (ref_buf[frame] == ref_buf[pframe]) break;
+      }
+      if (pframe < frame) {
+        memcpy(&cm->global_motion[frame], &cm->global_motion[pframe],
+               sizeof(WarpedMotionParams));
+      } else if (ref_buf[frame] &&
+                 do_gm_search_logic(&cpi->sf, num_refs_using_gm, frame)) {
         TransformationType model;
         aom_clear_system_state();
         for (model = ROTZOOM; model < GLOBAL_TRANS_TYPES_ENC; ++model) {
@@ -5182,7 +5211,7 @@
           }
 
           compute_global_motion_feature_based(
-              model, cpi->source, ref_buf,
+              model, cpi->source, ref_buf[frame],
 #if CONFIG_HIGHBITDEPTH
               cpi->common.bit_depth,
 #endif  // CONFIG_HIGHBITDEPTH
@@ -5200,10 +5229,10 @@
 #if CONFIG_HIGHBITDEPTH
                   xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH, xd->bd,
 #endif  // CONFIG_HIGHBITDEPTH
-                  ref_buf->y_buffer, ref_buf->y_width, ref_buf->y_height,
-                  ref_buf->y_stride, cpi->source->y_buffer,
-                  cpi->source->y_width, cpi->source->y_height,
-                  cpi->source->y_stride, 3);
+                  ref_buf[frame]->y_buffer, ref_buf[frame]->y_width,
+                  ref_buf[frame]->y_height, ref_buf[frame]->y_stride,
+                  cpi->source->y_buffer, cpi->source->y_width,
+                  cpi->source->y_height, cpi->source->y_stride, 3);
               if (erroradv_this_motion < best_erroradvantage) {
                 best_erroradvantage = erroradv_this_motion;
                 // Save the wm_params modified by refine_integerized_param()
@@ -5237,11 +5266,11 @@
                                      cm->allow_high_precision_mv))) {
             set_default_warp_params(&cm->global_motion[frame]);
           }
-
           if (cm->global_motion[frame].wmtype != IDENTITY) break;
         }
         aom_clear_system_state();
       }
+      if (cm->global_motion[frame].wmtype != IDENTITY) num_refs_using_gm++;
       cpi->gmparams_cost[frame] =
           gm_get_params_cost(&cm->global_motion[frame],
                              &cm->prev_frame->global_motion[frame],
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index 20c9676..9687a7f 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -139,8 +139,10 @@
   }
 }
 
-static void set_good_speed_feature(AV1_COMP *cpi, AV1_COMMON *cm,
-                                   SPEED_FEATURES *sf, int speed) {
+static void set_good_speed_features_framesize_independent(AV1_COMP *cpi,
+                                                          SPEED_FEATURES *sf,
+                                                          int speed) {
+  AV1_COMMON *const cm = &cpi->common;
   const int boosted = frame_is_boosted(cpi);
 
   if (speed >= 1) {
@@ -205,6 +207,9 @@
 #if CONFIG_EXT_TX
     sf->tx_type_search.prune_mode = PRUNE_TWO;
 #endif
+#if CONFIG_GLOBAL_MOTION
+    sf->gm_search_type = GM_DISABLE_SEARCH;
+#endif  // CONFIG_GLOBAL_MOTION
   }
 
   if (speed >= 4) {
@@ -339,12 +344,13 @@
 }
 
 void av1_set_speed_features_framesize_independent(AV1_COMP *cpi) {
-  SPEED_FEATURES *const sf = &cpi->sf;
   AV1_COMMON *const cm = &cpi->common;
+  SPEED_FEATURES *const sf = &cpi->sf;
   MACROBLOCK *const x = &cpi->td.mb;
   const AV1EncoderConfig *const oxcf = &cpi->oxcf;
   int i;
 
+  (void)cm;
   // best quality defaults
   sf->frame_parameter_update = 1;
   sf->mv.search_method = NSTEP;
@@ -418,13 +424,16 @@
 
   // Set this at the appropriate speed levels
   sf->use_transform_domain_distortion = 0;
+#if CONFIG_GLOBAL_MOTION
+  sf->gm_search_type = GM_FULL_SEARCH;
+#endif  // CONFIG_GLOBAL_MOTION
 
   if (oxcf->mode == GOOD
 #if CONFIG_XIPHRC
       || oxcf->pass == 1
 #endif
       )
-    set_good_speed_feature(cpi, cm, sf, oxcf->speed);
+    set_good_speed_features_framesize_independent(cpi, sf, oxcf->speed);
 
   // sf->partition_search_breakout_dist_thr is set assuming max 64x64
   // blocks. Normalise this if the blocks are bigger.
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h
index af54a1a..cb57c6b 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -251,6 +251,14 @@
   int interval;
 } MESH_PATTERN;
 
+#if CONFIG_GLOBAL_MOTION
+typedef enum {
+  GM_FULL_SEARCH,
+  GM_REDUCED_REF_SEARCH,
+  GM_DISABLE_SEARCH
+} GM_SEARCH_TYPE;
+#endif  // CONFIG_GLOBAL_MOTION
+
 typedef struct SPEED_FEATURES {
   MV_SPEED_FEATURES mv;
 
@@ -470,6 +478,10 @@
   // Whether to compute distortion in the image domain (slower but
   // more accurate), or in the transform domain (faster but less acurate).
   int use_transform_domain_distortion;
+
+#if CONFIG_GLOBAL_MOTION
+  GM_SEARCH_TYPE gm_search_type;
+#endif  // CONFIG_GLOBAL_MOTION
 } SPEED_FEATURES;
 
 struct AV1_COMP;