Commit 4df5e0bec9 for aom

commit 4df5e0bec98a220bbe28b9addf344ceeecd4bddb
Author: Deepa K G <deepa.kg@ittiam.com>
Date:   Mon Mar 23 19:18:41 2026 +0530

    Extend sf 'prune_comp_ref_frames' to speed 3

    The speed feature 'prune_comp_ref_frames' is extended to speed 3
    conservatively by disallowing pruning of important reference frame
    pairs decided based on the relative distance to the current frame
    and base_qindex.

    Encoder performance results averaged over all resolutions are as follows:

          Instruction Count           BD-Rate Loss(%)
    cpu     Reduction(%)      avg.psnr  ovr.psnr   ssim     vmaf   vmaf_neg
     3        0.7             0.0215    0.0230    0.0252   0.0369   0.0308

    STATS_CHANGED for speed=3

    Change-Id: I07476268df9c7075826ea956e7d9c2a8f07a11db

diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index 7f824a94bf..54ef94fb71 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -1721,11 +1721,14 @@ static int compare_score_data_asc(const void *a, const void *b) {

 // Determines whether a given reference frame is "good" based on temporal
 // distance and base_qindex. The "good" reference frames are not allowed to be
-// pruned by the speed feature "prune_single_ref" frame at block level.
-static inline void setup_keep_single_ref_frame_mask(AV1_COMP *cpi) {
+// pruned by the speed feature "prune_single_ref" and "prune_comp_ref_frames"
+// at block level.
+static inline void setup_keep_ref_frame_mask(AV1_COMP *cpi) {
   const int prune_single_ref = cpi->sf.inter_sf.prune_single_ref;
+  const int prune_comp_ref_frames = cpi->sf.inter_sf.prune_comp_ref_frames;
   const AV1_COMMON *const cm = &cpi->common;
   cpi->keep_single_ref_frame_mask = 0;
+  cpi->keep_comp_ref_frame_mask = 0;
   if (frame_is_intra_only(cm)) return;

   RefScoreData ref_score_data[INTER_REFS_PER_FRAME];
@@ -1758,13 +1761,35 @@ static inline void setup_keep_single_ref_frame_mask(AV1_COMP *cpi) {
   // prune_single_ref = 1 => The best 5 reference frames are not pruned.
   // prune_single_ref = 2 => The best 3 reference frames are not pruned.
   // prune_single_ref = 3, 4 => All the 7 references are allowed to be pruned.
-  static const int num_frames_to_keep_lookup[5] = { INTER_REFS_PER_FRAME, 5, 3,
-                                                    0, 0 };
-  const int num_frames_to_keep = num_frames_to_keep_lookup[prune_single_ref];
-  for (int i = 0; i < num_frames_to_keep; ++i) {
+  static const int num_single_ref_to_keep_lookup[5] = { INTER_REFS_PER_FRAME, 5,
+                                                        3, 0, 0 };
+  assert(prune_single_ref >= 0 && prune_single_ref <= 4);
+  const int num_single_ref_to_keep =
+      num_single_ref_to_keep_lookup[prune_single_ref];
+  for (int i = 0; i < num_single_ref_to_keep; ++i) {
     const int idx = ref_score_data[i].index;
     cpi->keep_single_ref_frame_mask |= 1 << idx;
   }
+
+  // Decide the number of reference frame pairs for which pruning via the speed
+  // feature "prune_comp_ref_frames" is disallowed.
+  // prune_comp_ref_frames = 0    => None of the allowed reference frame pairs
+  //                                 are pruned.
+  // prune_comp_ref_frames = 1    => The best 3 reference frame pairs are not
+  //                                 allowed to be pruned, i.e, reference frame
+  //                                 pairs with rank (1, 2), (1, 3), (2, 3) are
+  //                                 not  pruned.
+  // prune_comp_ref_frames = 2, 3 => All the reference frame pairs are allowed
+  //                                 to be pruned.
+  static const int num_comp_ref_to_keep_lookup[4] = { INTER_REFS_PER_FRAME, 3,
+                                                      0, 0 };
+  assert(prune_comp_ref_frames >= 0 && prune_comp_ref_frames <= 3);
+  const int num_comp_ref_to_keep =
+      num_comp_ref_to_keep_lookup[prune_comp_ref_frames];
+  for (int i = 0; i < num_comp_ref_to_keep; ++i) {
+    const int idx = ref_score_data[i].index;
+    cpi->keep_comp_ref_frame_mask |= 1 << idx;
+  }
 }

 static inline void setup_prune_ref_frame_mask(AV1_COMP *cpi) {
@@ -2336,7 +2361,7 @@ static inline void encode_frame_internal(AV1_COMP *cpi) {
   setup_prune_ref_frame_mask(cpi);
   // Disable certain reference frame pruning based on temporal distance and
   // quality of that reference frame.
-  setup_keep_single_ref_frame_mask(cpi);
+  setup_keep_ref_frame_mask(cpi);

   x->txfm_search_info.txb_split_count = 0;
 #if CONFIG_SPEED_STATS
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index b4e25d4c23..ec95323d63 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -3329,12 +3329,19 @@ typedef struct AV1_COMP {
   int prune_ref_frame_mask;

   /*!
-   * Mark the reference frames which are important (based on the temporal
+   * Mark the single reference frames which are important (based on the temporal
    * distance and quality) to prevent pruning the reference frame at block
    * level.
    */
   int keep_single_ref_frame_mask;

+  /*!
+   * Mark the compound reference frames which are important (based on the
+   * temporal distance and quality) to prevent pruning the reference frame pair
+   * at block level.
+   */
+  int keep_comp_ref_frame_mask;
+
   /*!
    * Loop Restoration context.
    */
diff --git a/av1/encoder/rdopt.h b/av1/encoder/rdopt.h
index dcdf3d29aa..90eb31543e 100644
--- a/av1/encoder/rdopt.h
+++ b/av1/encoder/rdopt.h
@@ -291,11 +291,18 @@ static inline int prune_ref_by_selective_ref_frame(
     int closest_ref_frames = has_closest_ref_frames(
         ref_frame, cpi->ref_frame_dist_info.nearest_past_ref,
         cpi->ref_frame_dist_info.nearest_future_ref);
-    if (closest_ref_frames == 0) {
+    const int ref_idx0 = ref_frame[0] - LAST_FRAME;
+    const int ref_idx1 = ref_frame[1] - LAST_FRAME;
+    const int keep_comp_ref_pair_mask =
+        (cpi->keep_comp_ref_frame_mask & (1 << ref_idx0)) &&
+        (cpi->keep_comp_ref_frame_mask & (1 << ref_idx1));
+
+    // Don't prune references frame pairs which are important or closest.
+    if (!(keep_comp_ref_pair_mask || closest_ref_frames)) {
       // Prune reference frames which are not the closest to the current frame.
-      if (sf->inter_sf.prune_comp_ref_frames >= 2) {
+      if (sf->inter_sf.prune_comp_ref_frames >= 3) {
         return 1;
-      } else if (sf->inter_sf.prune_comp_ref_frames == 1) {
+      } else if (sf->inter_sf.prune_comp_ref_frames >= 1) {
         // Prune reference frames with non minimum pred_mv_sad.
         if (has_best_pred_mv_sad(ref_frame, x) == 0) return 1;
       }
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index 53983af4b4..3f00173288 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -929,6 +929,12 @@ static void set_good_speed_feature_framesize_dependent(
       sf->lpf_sf.cdef_pick_method = CDEF_FAST_SEARCH_LVL2;
     }

+    if (is_480p_or_lesser) {
+      sf->inter_sf.prune_comp_ref_frames = 0;
+    } else {
+      sf->inter_sf.prune_comp_ref_frames = 1;
+    }
+
     sf->inter_sf.disable_interintra_wedge_var_thresh = UINT_MAX;
   }

@@ -954,9 +960,9 @@ static void set_good_speed_feature_framesize_dependent(
     if (is_480p_or_lesser) sf->inter_sf.skip_newmv_in_drl = 3;

     if (is_720p_or_larger) {
-      sf->inter_sf.prune_comp_ref_frames = 1;
+      sf->inter_sf.prune_comp_ref_frames = 2;
     } else if (is_480p_or_larger) {
-      sf->inter_sf.prune_comp_ref_frames = is_boosted_arf2_bwd_type ? 0 : 1;
+      sf->inter_sf.prune_comp_ref_frames = is_boosted_arf2_bwd_type ? 0 : 2;
     }

     if (is_720p_or_larger)
@@ -978,7 +984,7 @@ static void set_good_speed_feature_framesize_dependent(
     if (is_720p_or_larger) sf->hl_sf.recode_tolerance = 40;

     sf->inter_sf.skip_newmv_in_drl = 4;
-    sf->inter_sf.prune_comp_ref_frames = 1;
+    sf->inter_sf.prune_comp_ref_frames = 2;
     sf->mv_sf.skip_fullpel_search_using_startmv_refmv = boosted ? 0 : 1;

     if (!is_720p_or_larger) {
@@ -1012,7 +1018,7 @@ static void set_good_speed_feature_framesize_dependent(
   if (speed >= 6) {
     sf->tx_sf.tx_type_search.winner_mode_tx_type_pruning = 4;
     sf->inter_sf.prune_nearmv_using_neighbors = PRUNE_NEARMV_LEVEL3;
-    sf->inter_sf.prune_comp_ref_frames = 2;
+    sf->inter_sf.prune_comp_ref_frames = 3;
     sf->inter_sf.prune_nearest_near_mv_using_refmv_weight =
         (boosted || allow_screen_content_tools) ? 0 : 1;
     sf->mv_sf.skip_fullpel_search_using_startmv_refmv = boosted ? 0 : 2;
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h
index 8bb6a0d7d3..1af82a89e8 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -1030,12 +1030,15 @@ typedef struct INTER_MODE_SPEED_FEATURES {

   // Prune compound reference frames
   // 0 no pruning
-  // 1 prune compound references which do not satisfy the two conditions:
+  // 1 prune based on temporal distance and pred_mv_sad. However, disallow
+  //   pruning of important reference frame pairs decided based on temporal
+  //   distance and quality.
+  // 2 prune compound references which do not satisfy the two conditions:
   //   a) The references are at a nearest distance from the current frame in
   //   both past and future direction.
   //   b) The references have minimum pred_mv_sad in both past and future
   //   direction.
-  // 2 prune compound references except the one with nearest distance from the
+  // 3 prune compound references except the one with nearest distance from the
   //   current frame in both past and future direction.
   int prune_comp_ref_frames;