Prune extended compound mode using ref frames of neighbor block

Introduced a speed feature to skip compound mode using reference
frames of above and left neighbor blocks. Pruning is applicable
for extended compound modes only.

This speed feature is enabled for speed 4 and above.

            Encode Time             BD-Rate Loss
cpu-used     Reduction     avg.psnr    ovr.psnr    ssim
    4         5.192%       0.1617%     0.1592%    0.1053%
    5         3.527%       0.1221%     0.1249%    0.0690%

STATS_CHANGED

Change-Id: I4bdcb4f20c2e417b813a6e53b90a52709f8bf3e9
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index 45d6d4c..da9e068 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -4029,6 +4029,42 @@
   return 0;
 }
 
+// Check if ref frames of current block matches with given block.
+static INLINE void match_ref_frame(const MB_MODE_INFO *const mbmi,
+                                   const MV_REFERENCE_FRAME *ref_frames,
+                                   int *const is_ref_match) {
+  if (is_inter_block(mbmi)) {
+    is_ref_match[0] |= ref_frames[0] == mbmi->ref_frame[0];
+    is_ref_match[1] |= ref_frames[1] == mbmi->ref_frame[0];
+    if (has_second_ref(mbmi)) {
+      is_ref_match[0] |= ref_frames[0] == mbmi->ref_frame[1];
+      is_ref_match[1] |= ref_frames[1] == mbmi->ref_frame[1];
+    }
+  }
+}
+
+// Prune compound mode using ref frames of neighbor blocks.
+static INLINE int compound_skip_using_neighbor_refs(
+    MACROBLOCKD *const xd, const PREDICTION_MODE this_mode,
+    const MV_REFERENCE_FRAME *ref_frames) {
+  // Exclude non-extended compound modes from pruning
+  if (this_mode == NEAREST_NEARESTMV || this_mode == NEAR_NEARMV ||
+      this_mode == NEW_NEWMV || this_mode == GLOBAL_GLOBALMV)
+    return 0;
+
+  int is_ref_match[2] = { 0 };  // 0 - match for forward refs
+                                // 1 - match for backward refs
+  // Check if ref frames of this block matches with left neighbor.
+  if (xd->left_available)
+    match_ref_frame(xd->left_mbmi, ref_frames, is_ref_match);
+
+  // Check if ref frames of this block matches with above neighbor.
+  if (xd->up_available)
+    match_ref_frame(xd->above_mbmi, ref_frames, is_ref_match);
+
+  return !(is_ref_match[0] && is_ref_match[1]);
+}
+
 static int compare_int64(const void *a, const void *b) {
   int64_t a64 = *((int64_t *)a);
   int64_t b64 = *((int64_t *)b);
@@ -4277,6 +4313,11 @@
       !in_single_ref_cutoff(ref_frame_rd, ref_frame, second_ref_frame)) {
     return 1;
   }
+
+  if (sf->inter_sf.prune_compound_using_neighbors && comp_pred) {
+    if (compound_skip_using_neighbor_refs(xd, this_mode, ref_frames)) return 1;
+  }
+
   return 0;
 }
 
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index 28af368..a45f665 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -514,6 +514,7 @@
         (boosted || allow_screen_content_tools) ? 0 : 3;
 
     sf->inter_sf.prune_inter_modes_based_on_tpl = boosted ? 0 : 2;
+    sf->inter_sf.prune_compound_using_neighbors = 1;
     sf->inter_sf.disable_smooth_interintra = 1;
 
     sf->interp_sf.cb_pred_filter_search = 1;
@@ -970,6 +971,7 @@
   inter_sf->prune_single_motion_modes_by_simple_trans = 0;
   inter_sf->inter_mode_rd_model_estimation = 0;
   inter_sf->prune_compound_using_single_ref = 0;
+  inter_sf->prune_compound_using_neighbors = 0;
   inter_sf->disable_onesided_comp = 0;
   inter_sf->prune_mode_search_simple_translation = 0;
   inter_sf->prune_comp_type_by_comp_avg = 0;
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h
index 96baf5d..e67f2bc 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -575,6 +575,10 @@
   // the single reference modes, it is one of the two best performers.
   int prune_compound_using_single_ref;
 
+  // Skip extended compound mode using ref frames of above and left neighbor
+  // blocks.
+  int prune_compound_using_neighbors;
+
   // Based on previous ref_mv_idx search result, prune the following search.
   int prune_ref_mv_idx_search;