svc: Fix interface to svc for compound prediction

For layered encoding in nonrd: rework/refactor the
compound prediction mode and extend interface to
allow for using any combination of the reference pairs:
({last_golden}, {last_last2}, {last_altref}).

Added testcase for this to svc_datarate_test.cc.

No change in behavior for 1 layer/non-svc.

Change-Id: Ie26db5988af4f8d93ce4ff92b9805640e3e7bc7a
diff --git a/aom/aomcx.h b/aom/aomcx.h
index e7ea71f..e92c0a7 100644
--- a/aom/aomcx.h
+++ b/aom/aomcx.h
@@ -1502,8 +1502,10 @@
   int reference[7]; /**< Reference flag for each of the 7 references. */
   /*! Buffer slot index for each of 7 references. */
   int ref_idx[7];
-  int refresh[8];    /**< Refresh flag for each of the 8 slots. */
-  int use_comp_pred; /**< Use compound prediction. */
+  int refresh[8]; /**< Refresh flag for each of the 8 slots. */
+  // Use compound prediction for the ref_frame pairs GOLDEN_LAST (0),
+  // LAST2_LAST (1), and ALTREF_LAST (2).
+  int ref_frame_comp[3]; /**<Compound reference flag. */
 } aom_svc_ref_frame_config_t;
 
 /*!\cond */
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index 5f82e10..2109f54 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -3241,7 +3241,9 @@
   }
   for (unsigned int i = 0; i < REF_FRAMES; ++i)
     cpi->svc.refresh[i] = data->refresh[i];
-  cpi->svc.use_comp_pred = data->use_comp_pred;
+  cpi->svc.ref_frame_comp[0] = data->ref_frame_comp[0];
+  cpi->svc.ref_frame_comp[1] = data->ref_frame_comp[1];
+  cpi->svc.ref_frame_comp[2] = data->ref_frame_comp[2];
   cpi->svc.use_flexible_mode = 1;
   cpi->svc.ksvc_fixed_mode = 0;
   return AOM_CODEC_OK;
diff --git a/av1/encoder/nonrd_pickmode.c b/av1/encoder/nonrd_pickmode.c
index c114920..3402acb 100644
--- a/av1/encoder/nonrd_pickmode.c
+++ b/av1/encoder/nonrd_pickmode.c
@@ -2307,7 +2307,7 @@
 
 void setup_compound_prediction(AV1_COMP *cpi, MACROBLOCK *x,
                                struct buf_2d yv12_mb[8][MAX_MB_PLANE],
-                               int *use_ref_frame_mask, int flag_comp_nonrd,
+                               int *use_ref_frame_mask, int flag_comp,
                                int *ref_mv_idx) {
   AV1_COMMON *const cm = &cpi->common;
   MACROBLOCKD *const xd = &x->e_mbd;
@@ -2315,9 +2315,9 @@
   MB_MODE_INFO_EXT *const mbmi_ext = &x->mbmi_ext;
   MV_REFERENCE_FRAME rf[2] = { LAST_FRAME, GOLDEN_FRAME };
   MV_REFERENCE_FRAME ref_frame_comp;
-  if (flag_comp_nonrd == 1) {
+  if (flag_comp == 1) {
     rf[1] = LAST2_FRAME;
-  } else if (flag_comp_nonrd == 2) {
+  } else if (flag_comp == 2) {
     rf[1] = ALTREF_FRAME;
   }
   if (!use_ref_frame_mask[rf[1]]) {
@@ -2340,8 +2340,8 @@
   *ref_mv_idx = mbmi->ref_mv_idx + 1;
 }
 
-static void set_compound_mode(MACROBLOCK *x, int idx, int num_inter_modes,
-                              int ref_frame, int ref_frame2, int ref_mv_idx,
+static void set_compound_mode(MACROBLOCK *x, int comp_index, int ref_frame,
+                              int ref_frame2, int ref_mv_idx,
                               int_mv frame_mv[MB_MODE_COUNT][REF_FRAMES],
                               PREDICTION_MODE *this_mode) {
   MACROBLOCKD *const xd = &x->e_mbd;
@@ -2353,16 +2353,16 @@
   mi->comp_group_idx = 0;
   mi->interinter_comp.type = COMPOUND_AVERAGE;
   MV_REFERENCE_FRAME ref_frame_comp = av1_ref_frame_type(mi->ref_frame);
-  if (idx == num_inter_modes) {
+  if (comp_index % 3 == 0) {
     frame_mv[*this_mode][ref_frame].as_int = 0;
     frame_mv[*this_mode][ref_frame2].as_int = 0;
-  } else if (idx == num_inter_modes + 1) {
+  } else if (comp_index % 3 == 1) {
     *this_mode = NEAREST_NEARESTMV;
     frame_mv[*this_mode][ref_frame].as_int =
         xd->ref_mv_stack[ref_frame_comp][0].this_mv.as_int;
     frame_mv[*this_mode][ref_frame2].as_int =
         xd->ref_mv_stack[ref_frame_comp][0].comp_mv.as_int;
-  } else if (idx == num_inter_modes + 2) {
+  } else if (comp_index % 3 == 2) {
     *this_mode = NEAR_NEARMV;
     frame_mv[*this_mode][ref_frame].as_int =
         xd->ref_mv_stack[ref_frame_comp][ref_mv_idx].this_mv.as_int;
@@ -2387,6 +2387,7 @@
 #endif
   MV_REFERENCE_FRAME ref_frame, ref_frame2;
   int_mv frame_mv[MB_MODE_COUNT][REF_FRAMES];
+  int_mv frame_mv_best[MB_MODE_COUNT][REF_FRAMES];
   uint8_t mode_checked[MB_MODE_COUNT][REF_FRAMES];
   struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE];
   RD_STATS this_rdc, best_rdc;
@@ -2432,7 +2433,8 @@
   int force_mv_inter_layer = 0;
   int use_modeled_non_rd_cost = 0;
   int comp_pred = 0;
-  int num_comp_modes = 0;
+  int num_comp_modes_ref = 0;
+  int tot_num_comp_modes = 9;
   int ref_mv_idx = 0;
 #if CONFIG_AV1_TEMPORAL_DENOISING
   const int denoise_recheck_zeromv = 1;
@@ -2509,15 +2511,19 @@
   get_ref_frame_use_mask(cpi, x, mi, mi_row, mi_col, bsize, gf_temporal_ref,
                          use_ref_frame_mask, &force_skip_low_temp_var);
 
-  // Compound modes: LAST_GOLDEN/LAST_LAST2/LAST_ALTREF for 0/NEARESST/NEAR.
-  // For now to reduce slowdowm, use only 0/0 for blocks above 16x16
+  // Compound modes per reference pair (GOLDEN_LAST/LAST2_LAST/ALTREF_LAST):
+  // (0_0)/(NEAREST_NEAREST)/(NEAR_NEAR).
+  // For now to reduce slowdowm, use only (0,0) for blocks above 16x16
   // for non-svc case or on enhancement layers for svc.
   if (cpi->sf.rt_sf.use_comp_ref_nonrd && is_comp_ref_allowed(bsize)) {
-    if (cpi->ppi->use_svc && cpi->svc.use_comp_pred &&
-        cpi->svc.temporal_layer_id == 0)
-      num_comp_modes = 3;
+    if (cpi->ppi->use_svc && cpi->svc.temporal_layer_id == 0)
+      num_comp_modes_ref = 2;
     else if (bsize > BLOCK_16X16)
-      num_comp_modes = 1;
+      num_comp_modes_ref = 1;
+    else
+      tot_num_comp_modes = 0;
+  } else {
+    tot_num_comp_modes = 0;
   }
 
   for (MV_REFERENCE_FRAME ref_frame_iter = LAST_FRAME;
@@ -2566,7 +2572,7 @@
              tx_mode_to_biggest_tx_size[txfm_params->tx_mode_search_type]),
       TX_16X16);
 
-  for (int idx = 0; idx < num_inter_modes + num_comp_modes; ++idx) {
+  for (int idx = 0; idx < num_inter_modes + tot_num_comp_modes; ++idx) {
     const struct segmentation *const seg = &cm->seg;
 
     int rate_mv = 0;
@@ -2580,25 +2586,43 @@
     av1_invalid_rd_stats(&nonskip_rdc);
 
     if (idx >= num_inter_modes) {
+      int comp_index = idx - num_inter_modes;
+      if (comp_index % 3 == 0) {
+        int i = 0;
+        ref_mv_idx = 0;
+        // Only needs to be done once per reference pair.
+        if (comp_index == 3) i = 1;
+        if (comp_index == 6) i = 2;
+        if (cpi->sf.rt_sf.ref_frame_comp_nonrd[i])
+          setup_compound_prediction(cpi, x, yv12_mb, use_ref_frame_mask, i,
+                                    &ref_mv_idx);
+      }
+      // num_comp_modes_ref == 1 only do (0,0)
+      if (num_comp_modes_ref == 1 && comp_index % 3 != 0) continue;
+      // num_comp_modes_ref == 2 only do (0,0) and (NEAREST_NEAREST)
+      if (num_comp_modes_ref == 2 && comp_index % 3 == 2) continue;
       ref_frame = LAST_FRAME;
-      if (cpi->sf.rt_sf.ref_frame_comp_nonrd == 2) {
-        ref_frame2 = ALTREF_FRAME;
-        if (!(cpi->ref_frame_flags & AOM_ALT_FLAG)) continue;
-      } else if (cpi->sf.rt_sf.ref_frame_comp_nonrd == 1) {
+      ref_frame2 = GOLDEN_FRAME;
+      if (comp_index >= 0 && comp_index < 3) {
+        // comp_index = 0,1,2 for (0/NEAREST/NEAR) for GOLDEN_LAST.
+        if (cpi->sf.rt_sf.ref_frame_comp_nonrd[0] == 0 ||
+            !(cpi->ref_frame_flags & AOM_GOLD_FLAG))
+          continue;
+      } else if (comp_index >= 3 && comp_index < 6) {
+        // comp_index = 3,4,5 for (0/NEAREST/NEAR) for LAST2_LAST.
         ref_frame2 = LAST2_FRAME;
-        if (!(cpi->ref_frame_flags & AOM_LAST2_FLAG)) continue;
-      } else {
-        ref_frame2 = GOLDEN_FRAME;
-        if (!(cpi->ref_frame_flags & AOM_GOLD_FLAG)) continue;
+        if (cpi->sf.rt_sf.ref_frame_comp_nonrd[1] == 0 ||
+            !(cpi->ref_frame_flags & AOM_LAST2_FLAG))
+          continue;
+      } else if (comp_index >= 6 && comp_index < 9) {
+        // comp_index = 6,7,8 for (0/NEAREST/NEAR) for ALTREF_LAST.
+        ref_frame2 = ALTREF_FRAME;
+        if (cpi->sf.rt_sf.ref_frame_comp_nonrd[2] == 0 ||
+            !(cpi->ref_frame_flags & AOM_ALT_FLAG))
+          continue;
       }
-      if (idx == num_inter_modes) {
-        // Only needs to be done once on first compound mode.
-        setup_compound_prediction(cpi, x, yv12_mb, use_ref_frame_mask,
-                                  cpi->sf.rt_sf.ref_frame_comp_nonrd,
-                                  &ref_mv_idx);
-      }
-      set_compound_mode(x, idx, num_inter_modes, ref_frame, ref_frame2,
-                        ref_mv_idx, frame_mv, &this_mode);
+      set_compound_mode(x, comp_index, ref_frame, ref_frame2, ref_mv_idx,
+                        frame_mv, &this_mode);
       if (this_mode != GLOBAL_GLOBALMV &&
           frame_mv[this_mode][ref_frame].as_int == 0 &&
           frame_mv[this_mode][ref_frame2].as_int == 0)
@@ -2890,6 +2914,13 @@
       best_pickmode.best_mode_initial_skip_flag =
           (nonskip_rdc.rate == INT_MAX && this_rdc.skip_txfm);
 
+      // This is needed for the compoune modes.
+      frame_mv_best[this_mode][ref_frame].as_int =
+          frame_mv[this_mode][ref_frame].as_int;
+      if (ref_frame2 > NONE_FRAME)
+        frame_mv_best[this_mode][ref_frame2].as_int =
+            frame_mv[this_mode][ref_frame2].as_int;
+
       if (reuse_inter_pred) {
         free_pred_buffer(best_pickmode.best_pred);
         best_pickmode.best_pred = this_mode_pred;
@@ -2912,13 +2943,14 @@
   memset(mi->inter_tx_size, mi->tx_size, sizeof(mi->inter_tx_size));
   mi->ref_frame[0] = best_pickmode.best_ref_frame;
   mi->mv[0].as_int =
-      frame_mv[best_pickmode.best_mode][best_pickmode.best_ref_frame].as_int;
+      frame_mv_best[best_pickmode.best_mode][best_pickmode.best_ref_frame]
+          .as_int;
   mi->mv[1].as_int = 0;
   if (best_pickmode.best_second_ref_frame > INTRA_FRAME) {
     mi->ref_frame[1] = best_pickmode.best_second_ref_frame;
-    mi->mv[1].as_int =
-        frame_mv[best_pickmode.best_mode][best_pickmode.best_second_ref_frame]
-            .as_int;
+    mi->mv[1].as_int = frame_mv_best[best_pickmode.best_mode]
+                                    [best_pickmode.best_second_ref_frame]
+                                        .as_int;
   }
   // Perform intra prediction search, if the best SAD is above a certain
   // threshold.
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index da31d50..a19974a 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -2530,7 +2530,7 @@
   ext_flags->ref_frame_flags ^= AOM_ALT_FLAG;
   if (cpi->sf.rt_sf.use_golden_frame)
     ext_flags->ref_frame_flags ^= AOM_GOLD_FLAG;
-  if (cpi->sf.rt_sf.ref_frame_comp_nonrd == 1)
+  if (cpi->sf.rt_sf.ref_frame_comp_nonrd[1])
     ext_flags->ref_frame_flags ^= AOM_LAST2_FLAG;
   const int sh = 7 - gld_fixed_slot;
   // Moving index slot for last: 0 - (sh - 1).
@@ -2549,14 +2549,14 @@
   // Moving index for alt_ref, lag behind LAST by lag_alt frames.
   if (cm->current_frame.frame_number > lag_alt)
     alt_ref_idx = ((cm->current_frame.frame_number - lag_alt) % sh);
-  if (cpi->sf.rt_sf.ref_frame_comp_nonrd == 1) {
+  if (cpi->sf.rt_sf.ref_frame_comp_nonrd[1]) {
     // Moving index for LAST2, lag behind LAST by 2 frames.
     if (cm->current_frame.frame_number > 2)
       last2_idx = ((cm->current_frame.frame_number - 2) % sh);
   }
   svc->ref_idx[0] = last_idx;          // LAST
   svc->ref_idx[1] = last_idx_refresh;  // LAST2 (for refresh of last).
-  if (cpi->sf.rt_sf.ref_frame_comp_nonrd == 1) {
+  if (cpi->sf.rt_sf.ref_frame_comp_nonrd[1]) {
     svc->ref_idx[1] = last2_idx;         // LAST2
     svc->ref_idx[2] = last_idx_refresh;  // LAST3 (for refresh of last).
   }
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index d1d7b80..4a2035c 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -1207,7 +1207,7 @@
   } else {
     if (speed >= 7) {
       sf->rt_sf.use_comp_ref_nonrd = 1;
-      sf->rt_sf.ref_frame_comp_nonrd = 2;  // LAST_ALTREF
+      sf->rt_sf.ref_frame_comp_nonrd[2] = 1;  // LAST_ALTREF
     }
     if (speed == 8 && !cpi->ppi->use_svc) {
       sf->rt_sf.short_circuit_low_temp_var = 0;
@@ -1230,17 +1230,18 @@
       sf->rt_sf.estimate_motion_for_var_based_partition = 0;
     }
   }
-  // TODO(marpan): Fix this for SVC: allow for any combination
-  // of the 3 reference pairs for compound prediction in nonrd.
-  if (cpi->ppi->use_svc && cpi->svc.use_comp_pred &&
-      (cpi->svc.reference[GOLDEN_FRAME - 1] == 1 ||
-       cpi->svc.reference[LAST2_FRAME - 1] == 1 ||
-       cpi->svc.reference[ALTREF_FRAME - 1] == 1)) {
-    sf->rt_sf.use_comp_ref_nonrd = 1;
-    sf->rt_sf.ref_frame_comp_nonrd =
-        (cpi->svc.reference[GOLDEN_FRAME - 1] == 1)
-            ? 0
-            : ((cpi->svc.reference[LAST2_FRAME - 1] == 1) ? 1 : 2);
+  if (cpi->ppi->use_svc) {
+    sf->rt_sf.use_comp_ref_nonrd = 0;
+    if (cpi->svc.ref_frame_comp[0] || cpi->svc.ref_frame_comp[1] ||
+        cpi->svc.ref_frame_comp[2]) {
+      sf->rt_sf.use_comp_ref_nonrd = 1;
+      sf->rt_sf.ref_frame_comp_nonrd[0] =
+          cpi->svc.ref_frame_comp[0] && cpi->svc.reference[GOLDEN_FRAME - 1];
+      sf->rt_sf.ref_frame_comp_nonrd[1] =
+          cpi->svc.ref_frame_comp[1] && cpi->svc.reference[LAST2_FRAME - 1];
+      sf->rt_sf.ref_frame_comp_nonrd[2] =
+          cpi->svc.ref_frame_comp[2] && cpi->svc.reference[ALTREF_FRAME - 1];
+    }
   }
 }
 
@@ -1314,7 +1315,10 @@
   sf->rt_sf.check_intra_pred_nonrd = 1;
   sf->rt_sf.estimate_motion_for_var_based_partition = 1;
   sf->rt_sf.hybrid_intra_pickmode = 1;
-  sf->rt_sf.use_comp_ref_nonrd = 1;
+  sf->rt_sf.use_comp_ref_nonrd = 0;
+  sf->rt_sf.ref_frame_comp_nonrd[0] = 0;
+  sf->rt_sf.ref_frame_comp_nonrd[1] = 0;
+  sf->rt_sf.ref_frame_comp_nonrd[2] = 0;
   sf->rt_sf.use_nonrd_filter_search = 1;
 
   sf->tx_sf.intra_tx_size_search_init_depth_sqr = 1;
@@ -1394,7 +1398,6 @@
     sf->rt_sf.mode_search_skip_flags |= FLAG_SKIP_INTRA_DIRMISMATCH;
     sf->rt_sf.num_inter_modes_for_tx_search = 5;
     sf->rt_sf.skip_interp_filter_search = 1;
-    sf->rt_sf.use_comp_ref_nonrd = 0;
     sf->rt_sf.use_real_time_ref_set = 1;
     sf->rt_sf.use_simple_rd_model = 1;
 
@@ -1444,9 +1447,6 @@
     sf->rt_sf.reuse_inter_pred_nonrd = 0;
     sf->rt_sf.short_circuit_low_temp_var = 0;
     sf->rt_sf.skip_interp_filter_search = 0;
-    sf->rt_sf.use_comp_ref_nonrd = 0;
-    // 1 for LAST_LAST2, otherwise LAST_GOLDEN.
-    sf->rt_sf.ref_frame_comp_nonrd = 0;
     // For spatial layers, only LAST and GOLDEN are currently used in the SVC
     // for nonrd. The flag use_nonrd_altref_frame can disable GOLDEN in the
     // get_ref_frame_flags() for some patterns, so disable it here for
@@ -1790,7 +1790,6 @@
   rt_sf->use_nonrd_altref_frame = 0;
   rt_sf->use_golden_frame = 0;
   rt_sf->use_comp_ref_nonrd = 0;
-  rt_sf->ref_frame_comp_nonrd = 0;
   rt_sf->use_real_time_ref_set = 0;
   rt_sf->short_circuit_low_temp_var = 0;
   rt_sf->use_modeled_non_rd_cost = 0;
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h
index 39ddb12..80a649b 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -1210,8 +1210,8 @@
   int use_comp_ref_nonrd;
 
   // Reference frames for compound prediction for nonrd pickmode:
-  // LAST_GOLDEN (0, default), LAST_LAST2 (1), or LAST_ALTREF (2).
-  int ref_frame_comp_nonrd;
+  // LAST_GOLDEN (0), LAST_LAST2 (1), or LAST_ALTREF (2).
+  int ref_frame_comp_nonrd[3];
 
   // use reduced ref set for real-time mode
   int use_real_time_ref_set;
diff --git a/av1/encoder/svc_layercontext.c b/av1/encoder/svc_layercontext.c
index f74af68..d456d9d 100644
--- a/av1/encoder/svc_layercontext.c
+++ b/av1/encoder/svc_layercontext.c
@@ -86,6 +86,9 @@
   if (svc->number_spatial_layers == 3) {
     svc->downsample_filter_type[0] = EIGHTTAP_SMOOTH;
   }
+  svc->ref_frame_comp[0] = 0;
+  svc->ref_frame_comp[1] = 0;
+  svc->ref_frame_comp[2] = 0;
 }
 
 // Update the layer context from a change_config() call.
diff --git a/av1/encoder/svc_layercontext.h b/av1/encoder/svc_layercontext.h
index bda7be9..a1dff40 100644
--- a/av1/encoder/svc_layercontext.h
+++ b/av1/encoder/svc_layercontext.h
@@ -99,7 +99,7 @@
   int non_reference_frame;
   int use_flexible_mode;
   int ksvc_fixed_mode;
-  int use_comp_pred;
+  int ref_frame_comp[3];
   /*!\endcond */
 
   /*!
diff --git a/examples/svc_encoder_rtc.c b/examples/svc_encoder_rtc.c
index cd179bd..73c46df 100644
--- a/examples/svc_encoder_rtc.c
+++ b/examples/svc_encoder_rtc.c
@@ -568,7 +568,9 @@
   layer_id->spatial_layer_id = spatial_layer_id;
   int lag_index = 0;
   int base_count = superframe_cnt >> 2;
-  ref_frame_config->use_comp_pred = 0;
+  ref_frame_config->ref_frame_comp[0] = 0;  // GOLDEN_LAST
+  ref_frame_config->ref_frame_comp[1] = 0;  // LAST2_LAST
+  ref_frame_config->ref_frame_comp[2] = 0;  // ALTREF_LAST
   // Set the reference map buffer idx for the 7 references:
   // LAST_FRAME (0), LAST2_FRAME(1), LAST3_FRAME(2), GOLDEN_FRAME(3),
   // BWDREF_FRAME(4), ALTREF2_FRAME(5), ALTREF_FRAME(6).
diff --git a/test/svc_datarate_test.cc b/test/svc_datarate_test.cc
index d2839cc..2ba1156 100644
--- a/test/svc_datarate_test.cc
+++ b/test/svc_datarate_test.cc
@@ -81,6 +81,7 @@
     set_frame_level_er_ = 0;
     multi_ref_ = 0;
     use_fixed_mode_svc_ = 0;
+    comp_pred_ = 0;
   }
 
   virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
@@ -110,7 +111,7 @@
     // buffer index.
     frame_flags_ =
         set_layer_pattern(video->frame(), &layer_id_, &ref_frame_config_,
-                          spatial_layer_id, multi_ref_);
+                          spatial_layer_id, multi_ref_, comp_pred_);
     encoder->Control(AV1E_SET_SVC_LAYER_ID, &layer_id_);
     // The SET_SVC_REF_FRAME_CONFIG api is for the flexible SVC mode
     // (i.e., use_fixed_mode_svc == 0).
@@ -172,7 +173,8 @@
   // Layer pattern configuration.
   virtual int set_layer_pattern(int frame_cnt, aom_svc_layer_id_t *layer_id,
                                 aom_svc_ref_frame_config_t *ref_frame_config,
-                                int spatial_layer, int multi_ref) {
+                                int spatial_layer, int multi_ref,
+                                int comp_pred) {
     int lag_index = 0;
     int base_count = frame_cnt >> 2;
     layer_id->spatial_layer_id = spatial_layer;
@@ -184,6 +186,11 @@
       ref_frame_config->reference[i] = 0;
     }
     for (int i = 0; i < REF_FRAMES; i++) ref_frame_config->refresh[i] = 0;
+    if (comp_pred) {
+      ref_frame_config->ref_frame_comp[0] = 1;  // GOLDEN_LAST
+      ref_frame_config->ref_frame_comp[1] = 1;  // LAST2_LAST
+      ref_frame_config->ref_frame_comp[2] = 1;  // ALTREF_LAST
+    }
     // Set layer_flags to 0 when using ref_frame_config->reference.
     int layer_flags = 0;
     // Always reference LAST.
@@ -1132,6 +1139,40 @@
     EXPECT_EQ((int)GetMismatchFrames(), 0);
   }
 
+  virtual void BasicRateTargetingSVC3TL1SLMultiRefCompoundTest() {
+    cfg_.rc_buf_initial_sz = 500;
+    cfg_.rc_buf_optimal_sz = 500;
+    cfg_.rc_buf_sz = 1000;
+    cfg_.rc_dropframe_thresh = 0;
+    cfg_.rc_min_quantizer = 0;
+    cfg_.rc_max_quantizer = 63;
+    cfg_.rc_end_usage = AOM_CBR;
+    cfg_.g_lag_in_frames = 0;
+    cfg_.g_error_resilient = 0;
+
+    ::libaom_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30,
+                                         1, 0, 400);
+    cfg_.g_w = 640;
+    cfg_.g_h = 480;
+    const int bitrate_array[2] = { 400, 800 };
+    cfg_.rc_target_bitrate = bitrate_array[GET_PARAM(4)];
+    ResetModel();
+    multi_ref_ = 1;
+    comp_pred_ = 1;
+    number_temporal_layers_ = 3;
+    number_spatial_layers_ = 1;
+    target_layer_bitrate_[0] = 50 * cfg_.rc_target_bitrate / 100;
+    target_layer_bitrate_[1] = 70 * cfg_.rc_target_bitrate / 100;
+    target_layer_bitrate_[2] = cfg_.rc_target_bitrate;
+    ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+    for (int i = 0; i < number_temporal_layers_ * number_spatial_layers_; i++) {
+      ASSERT_GE(effective_datarate_tl[i], target_layer_bitrate_[i] * 0.80)
+          << " The datarate for the file is lower than target by too much!";
+      ASSERT_LE(effective_datarate_tl[i], target_layer_bitrate_[i] * 1.60)
+          << " The datarate for the file is greater than target by too much!";
+    }
+  }
+
   int layer_frame_cnt_;
   int superframe_cnt_;
   int number_temporal_layers_;
@@ -1150,6 +1191,7 @@
   int set_frame_level_er_;
   int multi_ref_;
   int use_fixed_mode_svc_;
+  int comp_pred_;
 };
 
 // Check basic rate targeting for CBR, for 3 temporal layers, 1 spatial.
@@ -1260,6 +1302,13 @@
   BasicRateTargetingSVC3TL1SLDropAllEnhFrameERTest();
 }
 
+// Check basic rate targeting for CBR, for 3 temporal layers, 1 spatial layer,
+// with compound prediction on, for pattern with two additional refereces
+// (golden and altref), both updated on base TLO frames.
+TEST_P(DatarateTestSVC, BasicRateTargetingSVC3TL1SLMultiRefCompound) {
+  BasicRateTargetingSVC3TL1SLMultiRefCompoundTest();
+}
+
 AV1_INSTANTIATE_TEST_SUITE(DatarateTestSVC,
                            ::testing::Values(::libaom_test::kRealTime),
                            ::testing::Range(7, 10),