Commit 72030e86dd for aom

commit 72030e86dd631921628417d0d34c3820eb948c7a
Author: Ranjit Kumar Tulabandu <ranjit.tulabandu@ittiam.com>
Date:   Tue Jul 7 21:32:23 2026 +0530

    lc-dec: Bias against GLOBALMV and GLOBAL_GLOBALMV modes

    In this CL, RD_STATS of GLOBALMV and GLOBAL_GLOBALMV modes are scaled
    if transformation wrt either of reference frames is non-translation.

    The Performance results of encoder and decoder for streams
    generated with low complexity decode enabled is given below:

         Decode Time                   BD-Rate Loss(%)
    cpu  Reduction(%)  avg.psnr   ssim     vmaf   vmaf_neg  uvq_1p5
     1      0.605       0.0270   0.0251   0.0670   0.0515    0.2203
     2      0.590       0.0339   0.0457   0.0603   0.0516    0.1501
     3      0.356       0.0210   0.0143   0.0260   0.0358   -0.1295

    STATS_CHANGED for low complexity decode

    Change-Id: I328356ed2556aadea92109cfeb8a0ce269afba3f

diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index a11d58e4d0..e805c2c3a4 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -1456,22 +1456,24 @@ static inline void scale_rdstats(RD_STATS *rd_stats, double rd_scale_pct) {

 // Increase rate, distortion and SSE in RD_STATS structure of warp and obmc
 // motion modes for low complexity decoding.
-static inline void increase_motion_mode_rdstats(const MB_MODE_INFO *this_mbmi,
+static inline void increase_motion_mode_rdstats(const AV1_COMP *cpi,
+                                                const MB_MODE_INFO *this_mbmi,
                                                 RD_STATS *rd_stats,
                                                 RD_STATS *rd_stats_y,
-                                                RD_STATS *rd_stats_uv,
-                                                float rd_warp_bias_scale_pct,
-                                                float rd_obmc_bias_scale_pct) {
+                                                RD_STATS *rd_stats_uv) {
   if (rd_stats->rate == INT_MAX ||
       (rd_stats_y != NULL && rd_stats_y->rate == INT_MAX) ||
       (rd_stats_uv != NULL && rd_stats_uv->rate == INT_MAX))
     return;
-
+  const INTER_MODE_SPEED_FEATURES *const inter_sf = &cpi->sf.inter_sf;
   double rd_bias_scale = 0.0;
   if (this_mbmi->motion_mode == WARPED_CAUSAL) {
-    rd_bias_scale = rd_warp_bias_scale_pct / 100.0;
+    rd_bias_scale = inter_sf->bias_warp_mode_rd_scale_pct / 100.0;
   } else if (this_mbmi->motion_mode == OBMC_CAUSAL) {
-    rd_bias_scale = rd_obmc_bias_scale_pct / 100.0;
+    rd_bias_scale = inter_sf->bias_obmc_mode_rd_scale_pct / 100.0;
+  } else if (this_mbmi->mode == GLOBALMV ||
+             this_mbmi->mode == GLOBAL_GLOBALMV) {
+    rd_bias_scale = get_global_mv_mode_bias(cpi, this_mbmi);
   }
   if (rd_bias_scale <= 0.0) return;

@@ -1848,10 +1850,7 @@ static int64_t motion_mode_rd(
                               rd_stats_uv, mbmi);
       }
       mbmi->skip_txfm = 0;
-      increase_motion_mode_rdstats(
-          mbmi, rd_stats, NULL, NULL,
-          cpi->sf.inter_sf.bias_warp_mode_rd_scale_pct,
-          cpi->sf.inter_sf.bias_obmc_mode_rd_scale_pct);
+      increase_motion_mode_rdstats(cpi, mbmi, rd_stats, NULL, NULL);

     } else {
       // Perform full transform search
@@ -1888,16 +1887,13 @@ static int64_t motion_mode_rd(
       }
       // Scale RD_STATS after mode stats are collected. Thus unscaled metrics
       // are used for model generation
-      increase_motion_mode_rdstats(
-          mbmi, rd_stats, rd_stats_y, rd_stats_uv,
-          cpi->sf.inter_sf.bias_warp_mode_rd_scale_pct,
-          cpi->sf.inter_sf.bias_obmc_mode_rd_scale_pct);
+      increase_motion_mode_rdstats(cpi, mbmi, rd_stats, rd_stats_y,
+                                   rd_stats_uv);
       const int skip_rate =
           rd_stats->skip_txfm ? skip_txfm_cost_ptr[1] : skip_txfm_cost_ptr[0];

-      const int32_t scaled_skip_rate = increase_motion_mode_rate(
-          mbmi, skip_rate, cpi->sf.inter_sf.bias_warp_mode_rd_scale_pct,
-          cpi->sf.inter_sf.bias_obmc_mode_rd_scale_pct);
+      const int32_t scaled_skip_rate =
+          increase_motion_mode_rate(cpi, mbmi, skip_rate);
       const int y_rate =
           scaled_skip_rate + (rd_stats->skip_txfm ? 0 : rd_stats_y->rate);
       this_yrd = RDCOST(x->rdmult, y_rate + mode_rate, rd_stats_y->dist);
@@ -4013,10 +4009,8 @@ static inline void refine_winner_mode_tx(
         skip_blk = 0;
         rd_stats_y.rate += mode_costs->skip_txfm_cost[skip_ctx][0];
       }
-      increase_motion_mode_rdstats(
-          mbmi, &rd_stats, &rd_stats_y, &rd_stats_uv,
-          cpi->sf.inter_sf.bias_warp_mode_rd_scale_pct,
-          cpi->sf.inter_sf.bias_obmc_mode_rd_scale_pct);
+      increase_motion_mode_rdstats(cpi, mbmi, &rd_stats, &rd_stats_y,
+                                   &rd_stats_uv);
       int this_rate = rd_stats.rate + rd_stats_y.rate + rd_stats_uv.rate -
                       winner_rate_y - winner_rate_uv;
       int64_t this_rd = RDCOST(x->rdmult, this_rate, this_dist);
@@ -5209,9 +5203,8 @@ static inline void update_search_state(
     const int32_t skip_rate =
         x->mode_costs.skip_txfm_cost[skip_ctx]
                                     [new_best_rd_stats->skip_txfm || skip_txfm];
-    const int32_t scaled_skip_rate = increase_motion_mode_rate(
-        mbmi, skip_rate, cpi->sf.inter_sf.bias_warp_mode_rd_scale_pct,
-        cpi->sf.inter_sf.bias_obmc_mode_rd_scale_pct);
+    const int32_t scaled_skip_rate =
+        increase_motion_mode_rate(cpi, mbmi, skip_rate);
     search_state->best_rate_y = new_best_rd_stats_y->rate + scaled_skip_rate;
     search_state->best_rate_uv = new_best_rd_stats_uv->rate;
   }
@@ -5634,16 +5627,13 @@ static void tx_search_best_inter_candidates(
             rd_stats_y.rate + rd_stats_uv.rate +
                 mode_costs->skip_txfm_cost[skip_ctx][mbmi->skip_txfm]);
       }
-      increase_motion_mode_rdstats(
-          mbmi, &rd_stats, &rd_stats_y, &rd_stats_uv,
-          cpi->sf.inter_sf.bias_warp_mode_rd_scale_pct,
-          cpi->sf.inter_sf.bias_obmc_mode_rd_scale_pct);
+      increase_motion_mode_rdstats(cpi, mbmi, &rd_stats, &rd_stats_y,
+                                   &rd_stats_uv);
       const int *skip_txfm_cost_ptr = mode_costs->skip_txfm_cost[skip_ctx];
       const int skip_rate =
           rd_stats.skip_txfm ? skip_txfm_cost_ptr[1] : skip_txfm_cost_ptr[0];
-      const int32_t scaled_skip_rate = increase_motion_mode_rate(
-          mbmi, skip_rate, cpi->sf.inter_sf.bias_warp_mode_rd_scale_pct,
-          cpi->sf.inter_sf.bias_obmc_mode_rd_scale_pct);
+      const int32_t scaled_skip_rate =
+          increase_motion_mode_rate(cpi, mbmi, skip_rate);
       const int y_rate =
           scaled_skip_rate + (rd_stats.skip_txfm ? 0 : rd_stats_y.rate);
       this_yrd = RDCOST(x->rdmult, y_rate + mode_rate, rd_stats_y.dist);
diff --git a/av1/encoder/rdopt_utils.h b/av1/encoder/rdopt_utils.h
index 89d9c93592..04d46d01b5 100644
--- a/av1/encoder/rdopt_utils.h
+++ b/av1/encoder/rdopt_utils.h
@@ -709,15 +709,43 @@ static inline void set_mode_eval_params(const struct AV1_COMP *cpi,
   txfm_params->mode_eval_type = mode_eval_type;
 }

-static inline int increase_motion_mode_rate(const MB_MODE_INFO *this_mbmi,
-                                            int rate,
-                                            float rd_warp_bias_scale_pct,
-                                            float rd_obmc_bias_scale_pct) {
+// Calculate global motion weight and transformation types for RD bias.
+// Returns the weight to apply to scaled RD cost for global motion blocks.
+static inline float get_global_mv_mode_bias(const AV1_COMP *cpi,
+                                            const MB_MODE_INFO *mbmi) {
+  if (cpi->sf.inter_sf.bias_gm_mode_rd_scale_pct <= 0.0f) return 0.0f;
+  if (cpi->common.features.cur_frame_force_integer_mv) return 0.0f;
+
+  assert(mbmi->mode == GLOBALMV || mbmi->mode == GLOBAL_GLOBALMV);
+
+  TransformationType ref_trans_type =
+      cpi->common.global_motion[mbmi->ref_frame[0]].wmtype;
+  if (is_global_mv_block(mbmi, ref_trans_type)) {
+    return cpi->sf.inter_sf.bias_gm_mode_rd_scale_pct / 100.0f;
+  }
+
+  if (has_second_ref(mbmi)) {
+    ref_trans_type = cpi->common.global_motion[mbmi->ref_frame[1]].wmtype;
+    if (is_global_mv_block(mbmi, ref_trans_type)) {
+      return cpi->sf.inter_sf.bias_gm_mode_rd_scale_pct / 100.0f;
+    }
+  }
+
+  return 0.0f;
+}
+
+static inline int increase_motion_mode_rate(const AV1_COMP *cpi,
+                                            const MB_MODE_INFO *this_mbmi,
+                                            int rate) {
+  const INTER_MODE_SPEED_FEATURES *const inter_sf = &cpi->sf.inter_sf;
   double rd_bias_scale = 0.0;
   if (this_mbmi->motion_mode == WARPED_CAUSAL) {
-    rd_bias_scale = rd_warp_bias_scale_pct / 100.0;
+    rd_bias_scale = inter_sf->bias_warp_mode_rd_scale_pct / 100.0;
   } else if (this_mbmi->motion_mode == OBMC_CAUSAL) {
-    rd_bias_scale = rd_obmc_bias_scale_pct / 100.0;
+    rd_bias_scale = inter_sf->bias_obmc_mode_rd_scale_pct / 100.0;
+  } else if (this_mbmi->mode == GLOBALMV ||
+             this_mbmi->mode == GLOBAL_GLOBALMV) {
+    rd_bias_scale = get_global_mv_mode_bias(cpi, this_mbmi);
   }
   if (rd_bias_scale <= 0.0) return rate;

@@ -807,9 +835,8 @@ static inline void store_winner_mode_stats(
       const int skip_rate =
           x->mode_costs
               .skip_txfm_cost[skip_ctx][rd_cost->skip_txfm || skip_txfm];
-      const int scaled_skip_rate = increase_motion_mode_rate(
-          mbmi, skip_rate, cpi->sf.inter_sf.bias_warp_mode_rd_scale_pct,
-          cpi->sf.inter_sf.bias_obmc_mode_rd_scale_pct);
+      const int scaled_skip_rate =
+          increase_motion_mode_rate(cpi, mbmi, skip_rate);
       winner_mode_stats[mode_idx].rate_y = rd_cost_y->rate + scaled_skip_rate;
       winner_mode_stats[mode_idx].rate_uv = rd_cost_uv->rate;
     }
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index d9add56561..6904276930 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -656,6 +656,7 @@ static void set_good_speed_features_lc_dec_framesize_dependent(

     sf->inter_sf.bias_warp_mode_rd_scale_pct = 2.5f;
     sf->inter_sf.bias_obmc_mode_rd_scale_pct = 1.5f;
+    sf->inter_sf.bias_gm_mode_rd_scale_pct = 2.0f;

     sf->part_sf.split_partition_penalty_level = is_key_frame ? 0 : 2;

@@ -680,6 +681,7 @@ static void set_good_speed_features_lc_dec_framesize_dependent(

     sf->inter_sf.bias_warp_mode_rd_scale_pct = 2.5f;
     sf->inter_sf.bias_obmc_mode_rd_scale_pct = 1.5f;
+    sf->inter_sf.bias_gm_mode_rd_scale_pct = 2.0f;

     sf->part_sf.split_partition_penalty_level = is_key_frame ? 0 : 2;

@@ -2417,6 +2419,7 @@ static inline void init_inter_sf(INTER_MODE_SPEED_FEATURES *inter_sf) {
   inter_sf->skip_arf_compound = 0;
   inter_sf->bias_warp_mode_rd_scale_pct = 0.0f;
   inter_sf->bias_obmc_mode_rd_scale_pct = 0.0f;
+  inter_sf->bias_gm_mode_rd_scale_pct = 0.0f;
   inter_sf->skip_cmp_using_top_cmp_avg_est_rd_lvl = 0;
   inter_sf->skip_interinter_wedge_search_based_on_mse = 0;
   inter_sf->enable_comp_wedge_search_using_model_rd = 0;
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h
index d1667ea64a..dd5cf57f84 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -1255,6 +1255,11 @@ typedef struct INTER_MODE_SPEED_FEATURES {
   // complexity modes.
   float bias_obmc_mode_rd_scale_pct;

+  // Percentage of scaling used to increase the rd cost of GLOBALMV and
+  // GLOBAL_GLOBALMV modes of type ROTZOOM so that encoder decisions are biased
+  // against these modes, favoring low complexity modes.
+  float bias_gm_mode_rd_scale_pct;
+
   // Avoid further evaluation of compound modes using top estimate RD Costs of
   // compound average.
   // Values are 0 (not used),1 - 3 with progressively increasing