Store and use single_newmv correctly

The motion vector search result at single reference frame mode is stored
for later use. There are some issues in current implementation.
1. single_newmv is only stored for 1st ref_mv, but not for other ref_mv
values tested.
2. If single reference mode is skipped and not tested, single_newmv is
not available.
3. Interintra mode always use single_newmv as its MV, which may not be
available as mentioned above.
To fix it, we store single_newmv for every ref_mv tested. In interintra
mode, if single_newmv is not available, do motion search to find a MV.

This was revealed by a motion vector unit test failure.

BUG=aomedia:1190

Change-Id: I3e690587644d4c8c31337f37380b796a3d71a3f6
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index d14000d..31ab422 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -6049,8 +6049,6 @@
     av1_setup_pre_planes(xd, ref_idx, scaled_ref_frame, mi_row, mi_col, NULL);
   }
 
-  av1_set_mv_search_range(&x->mv_limits, &ref_mv);
-
   av1_set_mvcost(
       x, ref, ref_idx,
       mbmi->ref_mv_idx + (have_nearmv_in_inter_mode(mbmi->mode) ? 1 : 0));
@@ -6105,6 +6103,8 @@
     }
   }
 
+  // Note: MV limits are modified here. Always restore the original values
+  // after full-pixel motion search.
   av1_set_mv_search_range(&x->mv_limits, &ref_mv);
 
   if (mbmi->motion_mode != SIMPLE_TRANSLATION)
@@ -7011,6 +7011,7 @@
   // Pointer to array of motion vectors to use for each ref and their rates
   // Should point to first of 2 arrays in 2D array
   int *single_newmv_rate;
+  int *single_newmv_valid;
   // Pointer to array of predicted rate-distortion
   // Should point to first of 2 arrays in 2D array
   int64_t (*modelled_rd)[TOTAL_REFS_PER_FRAME];
@@ -7088,17 +7089,18 @@
       }
     }
   } else {
-    if (is_comp_interintra_pred) {
+    if (is_comp_interintra_pred && args->single_newmv_valid[refs[0]]) {
       x->best_mv = args->single_newmv[refs[0]];
       *rate_mv = args->single_newmv_rate[refs[0]];
     } else {
       single_motion_search(cpi, x, bsize, mi_row, mi_col, 0, rate_mv);
+      if (x->best_mv.as_int == INVALID_MV) return INT64_MAX;
+
       args->single_newmv[refs[0]] = x->best_mv;
       args->single_newmv_rate[refs[0]] = *rate_mv;
+      args->single_newmv_valid[refs[0]] = 1;
     }
 
-    if (x->best_mv.as_int == INVALID_MV) return INT64_MAX;
-
     frame_mv[refs[0]] = x->best_mv;
 
     // Estimate the rate implications of a new mv but discount this
@@ -7310,9 +7312,8 @@
     int mi_col, HandleInterModeArgs *const args, const int64_t ref_best_rd,
     const int *refs, int rate_mv,
     // only used when WARPED_MOTION is on?
-    int_mv *const single_newmv, int rate2_bmc_nocoeff,
-    MB_MODE_INFO *best_bmc_mbmi, int rate_mv_bmc, int rs, int *skip_txfm_sb,
-    int64_t *skip_sse_sb, BUFFER_SET *orig_dst) {
+    int rate2_bmc_nocoeff, MB_MODE_INFO *best_bmc_mbmi, int rate_mv_bmc, int rs,
+    int *skip_txfm_sb, int64_t *skip_sse_sb, BUFFER_SET *orig_dst) {
   const AV1_COMMON *const cm = &cpi->common;
   MACROBLOCKD *xd = &x->e_mbd;
   MODE_INFO *mi = xd->mi[0];
@@ -7455,8 +7456,6 @@
             if (cpi->sf.adaptive_motion_search)
               x->pred_mv[ref] = mbmi->mv[0].as_mv;
 
-            single_newmv[ref] = mbmi->mv[0];
-
             if (discount_newmv_test(cpi, this_mode, mbmi->mv[0], mode_mv,
                                     refs[0])) {
               tmp_rate_mv = AOMMAX((tmp_rate_mv / NEW_MV_DISCOUNT_FACTOR), 1);
@@ -8381,11 +8380,11 @@
 
     rd_stats->rate += compmode_interinter_cost;
 
-    ret_val = motion_mode_rd(cpi, x, bsize, rd_stats, rd_stats_y, rd_stats_uv,
-                             disable_skip, mode_mv, mi_row, mi_col, args,
-                             ref_best_rd, refs, rate_mv, single_newmv,
-                             rate2_bmc_nocoeff, &best_bmc_mbmi, rate_mv_bmc, rs,
-                             &skip_txfm_sb, &skip_sse_sb, &orig_dst);
+    ret_val =
+        motion_mode_rd(cpi, x, bsize, rd_stats, rd_stats_y, rd_stats_uv,
+                       disable_skip, mode_mv, mi_row, mi_col, args, ref_best_rd,
+                       refs, rate_mv, rate2_bmc_nocoeff, &best_bmc_mbmi,
+                       rate_mv_bmc, rs, &skip_txfm_sb, &skip_sse_sb, &orig_dst);
 #if CONFIG_JNT_COMP
     if (is_comp_pred && ret_val != INT64_MAX) {
       int64_t tmp_rd;
@@ -8975,8 +8974,10 @@
   int comp_pred, i, k;
   int_mv frame_mv[MB_MODE_COUNT][TOTAL_REFS_PER_FRAME];
   struct buf_2d yv12_mb[TOTAL_REFS_PER_FRAME][MAX_MB_PLANE];
-  int_mv single_newmv[TOTAL_REFS_PER_FRAME] = { { 0 } };
-  int single_newmv_rate[TOTAL_REFS_PER_FRAME] = { 0 };
+  // Save a set of single_newmv for each checked ref_mv.
+  int_mv single_newmv[MAX_REF_MV_SERCH][TOTAL_REFS_PER_FRAME] = { { { 0 } } };
+  int single_newmv_rate[MAX_REF_MV_SERCH][TOTAL_REFS_PER_FRAME] = { { 0 } };
+  int single_newmv_valid[MAX_REF_MV_SERCH][TOTAL_REFS_PER_FRAME] = { { 0 } };
   int64_t modelled_rd[MB_MODE_COUNT][TOTAL_REFS_PER_FRAME];
   static const int flag_list[TOTAL_REFS_PER_FRAME] = { 0,
                                                        AOM_LAST_FLAG,
@@ -9031,10 +9032,11 @@
   const int mode_search_skip_flags = sf->mode_search_skip_flags;
 
   HandleInterModeArgs args = {
-    { NULL }, { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE },
-    { NULL }, { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE },
-    NULL,     NULL,
-    NULL,     { { 0 } },
+    { NULL },  { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE },
+    { NULL },  { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE },
+    NULL,      NULL,
+    NULL,      NULL,
+    { { 0 } },
   };
 
   const int rows = block_size_high[bsize];
@@ -9785,8 +9787,9 @@
         rd_stats.rate = rate2;
 
         // Point to variables that are maintained between loop iterations
-        args.single_newmv = single_newmv;
-        args.single_newmv_rate = single_newmv_rate;
+        args.single_newmv = single_newmv[0];
+        args.single_newmv_rate = single_newmv_rate[0];
+        args.single_newmv_valid = single_newmv_valid[0];
         args.modelled_rd = modelled_rd;
         this_rd = handle_inter_mode(cpi, x, bsize, &rd_stats, &rd_stats_y,
                                     &rd_stats_uv, &disable_skip, frame_mv,
@@ -9814,7 +9817,8 @@
         // TODO(jingning): This should be deprecated shortly.
         int idx_offset = have_nearmv_in_inter_mode(mbmi->mode) ? 1 : 0;
         int ref_set =
-            AOMMIN(2, mbmi_ext->ref_mv_count[ref_frame_type] - 1 - idx_offset);
+            AOMMIN(MAX_REF_MV_SERCH - 1,
+                   mbmi_ext->ref_mv_count[ref_frame_type] - 1 - idx_offset);
 
         uint8_t drl_ctx =
             av1_drl_ctx(mbmi_ext->ref_mv_stack[ref_frame_type], idx_offset);
@@ -9904,22 +9908,21 @@
           clamp_mv2(&cur_mv.as_mv, xd);
 
           if (!mv_check_bounds(&x->mv_limits, &cur_mv.as_mv)) {
-            int_mv dummy_single_newmv[TOTAL_REFS_PER_FRAME] = { { 0 } };
-            int dummy_single_newmv_rate[TOTAL_REFS_PER_FRAME] = { 0 };
-
             frame_mv[NEARMV][ref_frame] = cur_mv;
             av1_init_rd_stats(&tmp_rd_stats);
 
-            // Point to variables that are not maintained between iterations
-            args.single_newmv = dummy_single_newmv;
-            args.single_newmv_rate = dummy_single_newmv_rate;
             args.modelled_rd = NULL;
+            args.single_newmv = single_newmv[mbmi->ref_mv_idx];
+            args.single_newmv_rate = single_newmv_rate[mbmi->ref_mv_idx];
+            args.single_newmv_valid = single_newmv_valid[mbmi->ref_mv_idx];
+
             tmp_alt_rd = handle_inter_mode(
                 cpi, x, bsize, &tmp_rd_stats, &tmp_rd_stats_y, &tmp_rd_stats_uv,
                 &dummy_disable_skip, frame_mv, mi_row, mi_col, &args, best_rd);
             // Prevent pointers from escaping local scope
-            args.single_newmv = NULL;
-            args.single_newmv_rate = NULL;
+            args.single_newmv = single_newmv[0];
+            args.single_newmv_rate = single_newmv_rate[0];
+            args.single_newmv_valid = single_newmv_valid[0];
           }
 
           for (i = 0; i < mbmi->ref_mv_idx; ++i) {