Make gm_get_motion_vector respect allow_high_precision_mv

This fixes a rare encode/decode mismatch due to inconsistent
rounding of NEARMV/NEARESTMV vs. ZEROMV motion vectors when both
global motion and ref-mv are enabled.

Change-Id: Ia2bbaf63020f5ce7762e027f9bf835fd96797bec
diff --git a/av1/common/mv.h b/av1/common/mv.h
index 4b7bb6c..17ebdea 100644
--- a/av1/common/mv.h
+++ b/av1/common/mv.h
@@ -131,12 +131,19 @@
 
 // Convert a global motion translation vector (which may have more bits than a
 // regular motion vector) into a motion vector
-static INLINE int_mv gm_get_motion_vector(const WarpedMotionParams *gm) {
+static INLINE int_mv gm_get_motion_vector(const WarpedMotionParams *gm,
+                                          int allow_hp) {
   int_mv res;
-  res.as_mv.row = (int16_t)ROUND_POWER_OF_TWO_SIGNED(gm->wmmat[1],
-                                                     WARPEDMODEL_PREC_BITS - 3);
-  res.as_mv.col = (int16_t)ROUND_POWER_OF_TWO_SIGNED(gm->wmmat[0],
-                                                     WARPEDMODEL_PREC_BITS - 3);
+  res.as_mv.row = allow_hp ? (int16_t)ROUND_POWER_OF_TWO_SIGNED(
+                                 gm->wmmat[1], WARPEDMODEL_PREC_BITS - 3)
+                           : (int16_t)ROUND_POWER_OF_TWO_SIGNED(
+                                 gm->wmmat[1], WARPEDMODEL_PREC_BITS - 2) *
+                                 2;
+  res.as_mv.col = allow_hp ? (int16_t)ROUND_POWER_OF_TWO_SIGNED(
+                                 gm->wmmat[0], WARPEDMODEL_PREC_BITS - 3)
+                           : (int16_t)ROUND_POWER_OF_TWO_SIGNED(
+                                 gm->wmmat[0], WARPEDMODEL_PREC_BITS - 2) *
+                                 2;
   return res;
 }
 
diff --git a/av1/common/mvref_common.c b/av1/common/mvref_common.c
index 6f6fe90..abf3c87 100644
--- a/av1/common/mvref_common.c
+++ b/av1/common/mvref_common.c
@@ -499,7 +499,8 @@
                              MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
                              int_mv *mv_ref_list, int block, int mi_row,
                              int mi_col, find_mv_refs_sync sync,
-                             void *const data, int16_t *mode_context) {
+                             void *const data, int16_t *mode_context,
+                             int_mv zeromv) {
   const int *ref_sign_bias = cm->ref_frame_sign_bias;
   int i, refmv_count = 0;
 #if !CONFIG_REF_MV
@@ -661,7 +662,7 @@
   if (mode_context)
     mode_context[ref_frame] = counter_to_context[context_counter];
   for (i = refmv_count; i < MAX_MV_REF_CANDIDATES; ++i)
-    mv_ref_list[i].as_int = 0;
+    mv_ref_list[i].as_int = zeromv.as_int;
 }
 
 #if CONFIG_EXT_INTER
@@ -745,8 +746,12 @@
                       int_mv *mv_ref_list, int mi_row, int mi_col,
                       find_mv_refs_sync sync, void *const data,
                       int16_t *mode_context) {
+  int_mv zeromv[2];
 #if CONFIG_REF_MV
-  int all_zero = 1;
+  int idx, all_zero = 1;
+#endif
+#if CONFIG_GLOBAL_MOTION
+  MV_REFERENCE_FRAME rf[2];
 #endif
 #if CONFIG_EXT_INTER
   av1_update_mv_context(xd, mi, ref_frame, mv_ref_list, -1, mi_row, mi_col,
@@ -756,47 +761,58 @@
                         mode_context);
 #endif  // CONFIG_REF_MV
 #endif  // CONFIG_EXT_INTER
+
+#if CONFIG_GLOBAL_MOTION
+  av1_set_ref_frame(rf, ref_frame);
+  zeromv[0].as_int = gm_get_motion_vector(&cm->global_motion[rf[0]],
+                                          cm->allow_high_precision_mv)
+                         .as_int;
+  zeromv[1].as_int = (rf[1] != NONE)
+                         ? gm_get_motion_vector(&cm->global_motion[rf[1]],
+                                                cm->allow_high_precision_mv)
+                               .as_int
+                         : 0;
+#else
+  zeromv[0].as_int = zeromv[1].as_int = 0;
+#endif
+
 #if CONFIG_REF_MV
   if (ref_frame <= ALTREF_FRAME)
-    find_mv_refs_idx(cm, xd, mi, ref_frame, mv_ref_list, -1, mi_row, mi_col,
-                     sync, data, mode_context);
-#else
-  find_mv_refs_idx(cm, xd, mi, ref_frame, mv_ref_list, -1, mi_row, mi_col, sync,
-                   data, mode_context);
 #endif  // CONFIG_REF_MV
+    find_mv_refs_idx(cm, xd, mi, ref_frame, mv_ref_list, -1, mi_row, mi_col,
+                     sync, data, mode_context, zeromv[0]);
 
 #if CONFIG_REF_MV
   setup_ref_mv_list(cm, xd, ref_frame, ref_mv_count, ref_mv_stack, mv_ref_list,
                     -1, mi_row, mi_col, mode_context);
-
+  /* Note: If global motion is enabled, then we want to set the ALL_ZERO flag
+     iff all of the MVs we could generate with NEARMV/NEARESTMV are equivalent
+     to the global motion vector.
+     Note: For the following to work properly, the encoder can't throw away
+     any global motion models after calling this function, even if they are
+     unused. Instead we rely on the recode loop: If any non-IDENTITY model
+     is unused, the whole frame will be re-encoded without it.
+     The problem is that, otherwise, we can end up in the following situation:
+     * Encoder has a global motion model with nonzero translational part,
+       and all candidate MVs are zero. So the ALL_ZERO flag is unset.
+     * Encoder throws away global motion because it is never used.
+     * Decoder sees that there is no global motion and all candidate MVs are
+       zero, so sets the ALL_ZERO flag.
+     * This leads to an encode/decode mismatch.
+  */
   if (*ref_mv_count >= 2) {
-    int idx;
     for (idx = 0; idx < AOMMIN(3, *ref_mv_count); ++idx) {
-      if (ref_mv_stack[idx].this_mv.as_int != 0) all_zero = 0;
+      if (ref_mv_stack[idx].this_mv.as_int != zeromv[0].as_int) all_zero = 0;
       if (ref_frame > ALTREF_FRAME)
-        if (ref_mv_stack[idx].comp_mv.as_int != 0) all_zero = 0;
+        if (ref_mv_stack[idx].comp_mv.as_int != zeromv[1].as_int) all_zero = 0;
     }
   } else if (ref_frame <= ALTREF_FRAME) {
-    int idx;
     for (idx = 0; idx < MAX_MV_REF_CANDIDATES; ++idx)
-      if (mv_ref_list[idx].as_int != 0) all_zero = 0;
+      if (mv_ref_list[idx].as_int != zeromv[0].as_int) all_zero = 0;
   }
-#if CONFIG_GLOBAL_MOTION
-  if (all_zero) {
-    MV_REFERENCE_FRAME rf[2];
-    av1_set_ref_frame(rf, ref_frame);
-
-    if (gm_get_motion_vector(&cm->global_motion[rf[0]]).as_int != 0) {
-      all_zero = 0;
-    } else if (rf[1] != NONE &&
-               gm_get_motion_vector(&cm->global_motion[rf[1]]).as_int != 0) {
-      all_zero = 0;
-    }
-  }
-#endif  // CONFIG_GLOBAL_MOTION
 
   if (all_zero) mode_context[ref_frame] |= (1 << ALL_ZERO_FLAG_OFFSET);
-#endif  // CONFIG_REF_MV
+#endif
 }
 
 void av1_find_best_ref_mvs(int allow_hp, int_mv *mvlist, int_mv *nearest_mv,
@@ -826,6 +842,7 @@
   MODE_INFO *const mi = xd->mi[0];
   b_mode_info *bmi = mi->bmi;
   int n;
+  int_mv zeromv;
 #if CONFIG_REF_MV
   CANDIDATE_MV tmp_mv;
   uint8_t idx;
@@ -836,8 +853,15 @@
 
   assert(MAX_MV_REF_CANDIDATES == 2);
 
+#if CONFIG_GLOBAL_MOTION
+  zeromv.as_int =
+      gm_get_motion_vector(&cm->global_motion[ref], cm->allow_high_precision_mv)
+          .as_int;
+#else
+  zeromv.as_int = 0;
+#endif
   find_mv_refs_idx(cm, xd, mi, mi->mbmi.ref_frame[ref], mv_list, block, mi_row,
-                   mi_col, NULL, NULL, NULL);
+                   mi_col, NULL, NULL, NULL, zeromv);
 
 #if CONFIG_REF_MV
   scan_blk_mbmi(cm, xd, mi_row, mi_col, block, rf, -1, 0, ref_mv_stack,
@@ -922,8 +946,8 @@
       mi_step = AOMMIN(xd->n8_w, num_8x8_blocks_wide_lookup[mbmi->sb_type]);
 
       if (mbmi->ref_frame[0] == ref_frame && mbmi->ref_frame[1] == NONE) {
-        int bw = num_4x4_blocks_wide_lookup[mbmi->sb_type] * 4;
-        int bh = num_4x4_blocks_high_lookup[mbmi->sb_type] * 4;
+        int bw = block_size_wide[mbmi->sb_type];
+        int bh = block_size_high[mbmi->sb_type];
         int mv_row = mbmi->mv[0].as_mv.row;
         int mv_col = mbmi->mv[0].as_mv.col;
         int cr_offset = -AOMMAX(bh, 8) / 2 - 1;
@@ -977,8 +1001,8 @@
       mi_step = AOMMIN(xd->n8_h, num_8x8_blocks_high_lookup[mbmi->sb_type]);
 
       if (mbmi->ref_frame[0] == ref_frame && mbmi->ref_frame[1] == NONE) {
-        int bw = num_4x4_blocks_wide_lookup[mbmi->sb_type] * 4;
-        int bh = num_4x4_blocks_high_lookup[mbmi->sb_type] * 4;
+        int bw = block_size_wide[mbmi->sb_type];
+        int bh = block_size_high[mbmi->sb_type];
         int mv_row = mbmi->mv[0].as_mv.row;
         int mv_col = mbmi->mv[0].as_mv.col;
         int cr_offset = i * 8 + AOMMAX(bh, 8) / 2 - 1;
@@ -1028,8 +1052,8 @@
     MB_MODE_INFO *mbmi = &mi->mbmi;
 
     if (mbmi->ref_frame[0] == ref_frame && mbmi->ref_frame[1] == NONE) {
-      int bw = num_4x4_blocks_wide_lookup[mbmi->sb_type] * 4;
-      int bh = num_4x4_blocks_high_lookup[mbmi->sb_type] * 4;
+      int bw = block_size_wide[mbmi->sb_type];
+      int bh = block_size_high[mbmi->sb_type];
       int mv_row = mbmi->mv[0].as_mv.row;
       int mv_col = mbmi->mv[0].as_mv.col;
       int cr_offset = -AOMMAX(bh, 8) / 2 - 1;
@@ -1078,8 +1102,8 @@
   } else {
     MODE_INFO *mi = xd->mi[0];
     MB_MODE_INFO *mbmi = &mi->mbmi;
-    int bw = num_4x4_blocks_wide_lookup[mbmi->sb_type] * 4;
-    int bh = num_4x4_blocks_high_lookup[mbmi->sb_type] * 4;
+    int bw = block_size_wide[mbmi->sb_type];
+    int bh = block_size_high[mbmi->sb_type];
     int mv_row = mbmi->mv[0].as_mv.row;
     int mv_col = mbmi->mv[0].as_mv.col;
     int cr_offset = AOMMAX(bh, 8) / 2 - 1;
diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c
index 05dc0fa..838c9af 100644
--- a/av1/decoder/decodemv.c
+++ b/av1/decoder/decodemv.c
@@ -1230,11 +1230,13 @@
     }
     case ZEROMV: {
 #if CONFIG_GLOBAL_MOTION
-      mv[0].as_int =
-          gm_get_motion_vector(&cm->global_motion[ref_frame[0]]).as_int;
+      mv[0].as_int = gm_get_motion_vector(&cm->global_motion[ref_frame[0]],
+                                          cm->allow_high_precision_mv)
+                         .as_int;
       if (is_compound)
-        mv[1].as_int =
-            gm_get_motion_vector(&cm->global_motion[ref_frame[1]]).as_int;
+        mv[1].as_int = gm_get_motion_vector(&cm->global_motion[ref_frame[1]],
+                                            cm->allow_high_precision_mv)
+                           .as_int;
 #else
       mv[0].as_int = 0;
       if (is_compound) mv[1].as_int = 0;
@@ -1479,14 +1481,29 @@
 
     if (xd->ref_mv_count[ref_frame] < 2) {
       MV_REFERENCE_FRAME rf[2];
+      int_mv zeromv[2];
       av1_set_ref_frame(rf, ref_frame);
+#if CONFIG_GLOBAL_MOTION
+      zeromv[0].as_int = gm_get_motion_vector(&cm->global_motion[rf[0]],
+                                              cm->allow_high_precision_mv)
+                             .as_int;
+      zeromv[1].as_int = (rf[1] != NONE)
+                             ? gm_get_motion_vector(&cm->global_motion[rf[1]],
+                                                    cm->allow_high_precision_mv)
+                                   .as_int
+                             : 0;
+#else
+      zeromv[0].as_int = zeromv[1].as_int = 0;
+#endif
       for (ref = 0; ref < 2; ++ref) {
         lower_mv_precision(&ref_mvs[rf[ref]][0].as_mv, allow_hp);
         lower_mv_precision(&ref_mvs[rf[ref]][1].as_mv, allow_hp);
       }
 
-      if (ref_mvs[rf[0]][0].as_int != 0 || ref_mvs[rf[0]][1].as_int != 0 ||
-          ref_mvs[rf[1]][0].as_int != 0 || ref_mvs[rf[1]][1].as_int != 0)
+      if (ref_mvs[rf[0]][0].as_int != zeromv[0].as_int ||
+          ref_mvs[rf[0]][1].as_int != zeromv[0].as_int ||
+          ref_mvs[rf[1]][0].as_int != zeromv[1].as_int ||
+          ref_mvs[rf[1]][1].as_int != zeromv[1].as_int)
         inter_mode_ctx[ref_frame] &= ~(1 << ALL_ZERO_FLAG_OFFSET);
     }
   }
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index 8ead4ac..7b24b32 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -4400,12 +4400,14 @@
     case ZEROMV:
 #if CONFIG_GLOBAL_MOTION
       this_mv[0].as_int =
-          gm_get_motion_vector(&cpi->common.global_motion[mbmi->ref_frame[0]])
+          gm_get_motion_vector(&cpi->common.global_motion[mbmi->ref_frame[0]],
+                               cpi->common.allow_high_precision_mv)
               .as_int;
       thismvcost += GLOBAL_MOTION_RATE(mbmi->ref_frame[0]);
       if (is_compound) {
         this_mv[1].as_int =
-            gm_get_motion_vector(&cpi->common.global_motion[mbmi->ref_frame[1]])
+            gm_get_motion_vector(&cpi->common.global_motion[mbmi->ref_frame[1]],
+                                 cpi->common.allow_high_precision_mv)
                 .as_int;
         thismvcost += GLOBAL_MOTION_RATE(mbmi->ref_frame[1]);
       }
@@ -5193,7 +5195,9 @@
 #endif  // CONFIG_EXT_INTER
 #if CONFIG_GLOBAL_MOTION
         frame_mv[ZEROMV][frame].as_int =
-            gm_get_motion_vector(&cm->global_motion[frame]).as_int;
+            gm_get_motion_vector(&cm->global_motion[frame],
+                                 cm->allow_high_precision_mv)
+                .as_int;
 #else   // CONFIG_GLOBAL_MOTION
         frame_mv[ZEROMV][frame].as_int = 0;
 #endif  // CONFIG_GLOBAL_MOTION
@@ -8649,7 +8653,9 @@
     frame_mv[NEWMV][ref_frame].as_int = INVALID_MV;
 #if CONFIG_GLOBAL_MOTION
     frame_mv[ZEROMV][ref_frame].as_int =
-        gm_get_motion_vector(&cm->global_motion[ref_frame]).as_int;
+        gm_get_motion_vector(&cm->global_motion[ref_frame],
+                             cm->allow_high_precision_mv)
+            .as_int;
 #else   // CONFIG_GLOBAL_MOTION
     frame_mv[ZEROMV][ref_frame].as_int = 0;
 #endif  // CONFIG_GLOBAL_MOTION
@@ -8675,10 +8681,13 @@
     if (mbmi_ext->ref_mv_count[ref_frame] < 2) {
       MV_REFERENCE_FRAME rf[2];
       av1_set_ref_frame(rf, ref_frame);
-      if (mbmi_ext->ref_mvs[rf[0]][0].as_int != 0 ||
-          mbmi_ext->ref_mvs[rf[0]][1].as_int != 0 ||
-          mbmi_ext->ref_mvs[rf[1]][0].as_int != 0 ||
-          mbmi_ext->ref_mvs[rf[1]][1].as_int != 0)
+      if (mbmi_ext->ref_mvs[rf[0]][0].as_int !=
+              frame_mv[ZEROMV][rf[0]].as_int ||
+          mbmi_ext->ref_mvs[rf[0]][1].as_int !=
+              frame_mv[ZEROMV][rf[0]].as_int ||
+          mbmi_ext->ref_mvs[rf[1]][0].as_int !=
+              frame_mv[ZEROMV][rf[1]].as_int ||
+          mbmi_ext->ref_mvs[rf[1]][1].as_int != frame_mv[ZEROMV][rf[1]].as_int)
         mbmi_ext->mode_context[ref_frame] &= ~(1 << ALL_ZERO_FLAG_OFFSET);
     }
   }
@@ -8751,8 +8760,9 @@
       //               BWDREF_FRAME as well.
       mode_skip_mask[ALTREF_FRAME] = ~INTER_NEAREST_NEAR_ZERO;
 #if CONFIG_GLOBAL_MOTION
-      zeromv.as_int =
-          gm_get_motion_vector(&cm->global_motion[ALTREF_FRAME]).as_int;
+      zeromv.as_int = gm_get_motion_vector(&cm->global_motion[ALTREF_FRAME],
+                                           cm->allow_high_precision_mv)
+                          .as_int;
 #else
       zeromv.as_int = 0;
 #endif  // CONFIG_GLOBAL_MOTION
@@ -9898,11 +9908,14 @@
     const uint8_t rf_type = av1_ref_frame_type(best_mbmode.ref_frame);
 #endif  // CONFIG_REF_MV
 #if CONFIG_GLOBAL_MOTION
-    zeromv[0].as_int = gm_get_motion_vector(&cm->global_motion[refs[0]]).as_int;
-    zeromv[1].as_int =
-        comp_pred_mode
-            ? gm_get_motion_vector(&cm->global_motion[refs[1]]).as_int
-            : 0;
+    zeromv[0].as_int = gm_get_motion_vector(&cm->global_motion[refs[0]],
+                                            cm->allow_high_precision_mv)
+                           .as_int;
+    zeromv[1].as_int = comp_pred_mode
+                           ? gm_get_motion_vector(&cm->global_motion[refs[1]],
+                                                  cm->allow_high_precision_mv)
+                                 .as_int
+                           : 0;
 #else
     zeromv[0].as_int = 0;
     zeromv[1].as_int = 0;
@@ -10033,27 +10046,36 @@
   }
 
 #if CONFIG_REF_MV
-  if (best_mbmode.ref_frame[0] > INTRA_FRAME && best_mbmode.mv[0].as_int == 0 &&
-#if CONFIG_EXT_INTER
-      (best_mbmode.ref_frame[1] <= INTRA_FRAME)
-#else
-      (best_mbmode.ref_frame[1] == NONE || best_mbmode.mv[1].as_int == 0)
-#endif  // CONFIG_EXT_INTER
-          ) {
+  {
     int8_t ref_frame_type = av1_ref_frame_type(best_mbmode.ref_frame);
     int16_t mode_ctx = mbmi_ext->mode_context[ref_frame_type];
-
     if (mode_ctx & (1 << ALL_ZERO_FLAG_OFFSET)) {
-      best_mbmode.mode = ZEROMV;
+      int_mv zeromv[2];
 #if CONFIG_GLOBAL_MOTION
-      best_mbmode.mv[0].as_int =
-          gm_get_motion_vector(&cm->global_motion[best_mbmode.ref_frame[0]])
-              .as_int;
-      if (best_mbmode.ref_frame[1] != NONE)
-        best_mbmode.mv[1].as_int =
-            gm_get_motion_vector(&cm->global_motion[best_mbmode.ref_frame[1]])
-                .as_int;
-#endif
+      const MV_REFERENCE_FRAME refs[2] = { best_mbmode.ref_frame[0],
+                                           best_mbmode.ref_frame[1] };
+      zeromv[0].as_int = gm_get_motion_vector(&cm->global_motion[refs[0]],
+                                              cm->allow_high_precision_mv)
+                             .as_int;
+      zeromv[1].as_int = gm_get_motion_vector(&cm->global_motion[refs[1]],
+                                              cm->allow_high_precision_mv)
+                             .as_int;
+      lower_mv_precision(&zeromv[0].as_mv, cm->allow_high_precision_mv);
+      lower_mv_precision(&zeromv[1].as_mv, cm->allow_high_precision_mv);
+#else
+      zeromv[0].as_int = zeromv[1].as_int = 0;
+#endif  // CONFIG_GLOBAL_MOTION
+      if (best_mbmode.ref_frame[0] > INTRA_FRAME &&
+          best_mbmode.mv[0].as_int == zeromv[0].as_int &&
+#if CONFIG_EXT_INTER
+          (best_mbmode.ref_frame[1] <= INTRA_FRAME)
+#else
+          (best_mbmode.ref_frame[1] == NONE ||
+           best_mbmode.mv[1].as_int == zeromv[1].as_int)
+#endif  // CONFIG_EXT_INTER
+              ) {
+        best_mbmode.mode = ZEROMV;
+      }
     }
   }
 #endif
@@ -10170,7 +10192,9 @@
   mbmi->ref_frame[1] = NONE;
 #if CONFIG_GLOBAL_MOTION
   mbmi->mv[0].as_int =
-      gm_get_motion_vector(&cm->global_motion[mbmi->ref_frame[0]]).as_int;
+      gm_get_motion_vector(&cm->global_motion[mbmi->ref_frame[0]],
+                           cm->allow_high_precision_mv)
+          .as_int;
 #else   // CONFIG_GLOBAL_MOTION
   mbmi->mv[0].as_int = 0;
 #endif  // CONFIG_GLOBAL_MOTION