Commit 6350573c69 for aom

commit 6350573c69f9e82421af122ac792e07ceedbb8f9
Author: Marco Paniconi <marpan@google.com>
Date:   Sun Jul 12 04:12:53 2026 +0000

    rtc: Speedup for intraBC for nonrd pickmode

    Add speed feature for options to handle hash lookup
    failure: rt_intrabc_miss_mode, with values 0 - 3.
    Set to level 2 for now for speed >= 7.

    Stats change for rtc_screen, with enable-intrabc=1,
    kf-max-dist=kf-min-dist=1,rctype=q, for speeds 10-11:
    ~3-4% overall speedup, 10-15% speedup on two clips
    (youtube and yt_soccer_clip), where intraBC is less effective
    bdrate change neutral/negligble across all speeds.

    Change-Id: I741046f4f1426f35542f489dac3ba5be125e9039

diff --git a/av1/encoder/nonrd_pickmode.c b/av1/encoder/nonrd_pickmode.c
index e952ee8ddd..f43c8df473 100644
--- a/av1/encoder/nonrd_pickmode.c
+++ b/av1/encoder/nonrd_pickmode.c
@@ -14,12 +14,15 @@
 #include <limits.h>
 #include <math.h>
 #include <stdio.h>
+#include <stdlib.h>

+#include "av1/common/mvref_common.h"
 #include "av1/common/reconinter.h"
 #include "av1/common/reconintra.h"

 #include "av1/encoder/encodemv.h"
 #include "av1/encoder/intra_mode_search.h"
+#include "av1/encoder/mcomp.h"
 #include "av1/encoder/model_rd.h"
 #include "av1/encoder/motion_search_facade.h"
 #include "av1/encoder/nonrd_opt.h"
@@ -1651,10 +1654,71 @@ static void av1_search_intrabc_nonrd(AV1_COMP *cpi, MACROBLOCK *x,
         cpi, xd, &fullms_params, &x->intrabc_hash_info, &best_mv.as_fullmv);
   }
   if (bestsme == INT_MAX) {
-    FULLPEL_MV_STATS best_mv_stats;
-    bestsme = av1_full_pixel_search(start_mv, &fullms_params,
-                                    cpi->mv_search_params.mv_step_param, NULL,
-                                    &best_mv.as_fullmv, &best_mv_stats, NULL);
+    const int miss_mode = cpi->sf.rt_sf.rt_intrabc_miss_mode;
+    if (miss_mode == 0) {
+      FULLPEL_MV_STATS best_mv_stats;
+      bestsme = av1_full_pixel_search(start_mv, &fullms_params,
+                                      cpi->mv_search_params.mv_step_param, NULL,
+                                      &best_mv.as_fullmv, &best_mv_stats, NULL);
+    } else if (miss_mode == 1 || miss_mode == 2) {
+      // Evaluate start_mv (BVP candidate)
+      FULLPEL_MV cand_mv = start_mv;
+      if (cand_mv.col >= fullms_params.mv_limits.col_min &&
+          cand_mv.col <= fullms_params.mv_limits.col_max &&
+          cand_mv.row >= fullms_params.mv_limits.row_min &&
+          cand_mv.row <= fullms_params.mv_limits.row_max) {
+        MV dv = get_mv_from_fullmv(&cand_mv);
+        if (av1_is_dv_valid(dv, cm, xd, mi_row, mi_col, bsize,
+                            cm->seq_params->mib_size_log2)) {
+          const struct buf_2d *src = fullms_params.ms_buffers.src;
+          const struct buf_2d *ref = fullms_params.ms_buffers.ref;
+          unsigned int sad = fullms_params.vfp->sdf(
+              src->buf, src->stride, get_buf_from_fullmv(ref, &cand_mv),
+              ref->stride);
+          unsigned int rate =
+              av1_mv_bit_cost(&dv, &dv_ref.as_mv, x->dv_costs->joint_mv,
+                              x->dv_costs->dv_costs, MV_COST_WEIGHT);
+          best_mv.as_fullmv = cand_mv;
+          bestsme = (int)(sad + rate);
+        }
+      }
+
+      // If miss_mode == 2, do a one-shot 12-point offset probe around start_mv
+      if (miss_mode == 2) {
+        const int row_offsets[12] = { -1, 1, 0, 0, -2, 2, 0, 0, -1, -1, 1, 1 };
+        const int col_offsets[12] = { 0, 0, -1, 1, 0, 0, -2, 2, -1, 1, -1, 1 };
+        for (int k = 0; k < 12; ++k) {
+          FULLPEL_MV probe_mv;
+          probe_mv.row = start_mv.row + row_offsets[k];
+          probe_mv.col = start_mv.col + col_offsets[k];
+          if (probe_mv.col >= fullms_params.mv_limits.col_min &&
+              probe_mv.col <= fullms_params.mv_limits.col_max &&
+              probe_mv.row >= fullms_params.mv_limits.row_min &&
+              probe_mv.row <= fullms_params.mv_limits.row_max) {
+            MV dv = get_mv_from_fullmv(&probe_mv);
+            if (av1_is_dv_valid(dv, cm, xd, mi_row, mi_col, bsize,
+                                cm->seq_params->mib_size_log2)) {
+              const struct buf_2d *src = fullms_params.ms_buffers.src;
+              const struct buf_2d *ref = fullms_params.ms_buffers.ref;
+              unsigned int sad = fullms_params.vfp->sdf(
+                  src->buf, src->stride, get_buf_from_fullmv(ref, &probe_mv),
+                  ref->stride);
+              unsigned int rate =
+                  av1_mv_bit_cost(&dv, &dv_ref.as_mv, x->dv_costs->joint_mv,
+                                  x->dv_costs->dv_costs, MV_COST_WEIGHT);
+              int cost = (int)(sad + rate);
+              if (cost < bestsme) {
+                bestsme = cost;
+                best_mv.as_fullmv = probe_mv;
+              }
+            }
+          }
+        }
+      }
+    } else {
+      // miss_mode == 3: skip entirely (hash-only)
+      bestsme = INT_MAX;
+    }
   }
   if (bestsme != INT_MAX) {
     MV dv = get_mv_from_fullmv(&best_mv.as_fullmv);
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index 6904276930..ef673c0d31 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -1773,6 +1773,7 @@ static void set_rt_speed_feature_framesize_dependent(const AV1_COMP *const cpi,
     sf->mv_sf.hash_max_8x8_intrabc_blocks = 1;
     sf->mv_sf.prune_intrabc_candidate_block_hash_search = 1;
     if (speed >= 7) {
+      sf->rt_sf.rt_intrabc_miss_mode = 2;
       sf->rt_sf.reduce_mv_pel_precision_highmotion = 0;
       sf->mv_sf.use_bsize_dependent_search_method = 0;
       sf->rt_sf.skip_cdef_sb = 1;
@@ -2634,6 +2635,7 @@ static inline void init_rt_sf(REAL_TIME_SPEED_FEATURES *rt_sf) {
   rt_sf->selective_cdf_update = 0;
   rt_sf->rt_use_intrabc = 0;
   rt_sf->rt_prune_intrabc_nonrd = 0;
+  rt_sf->rt_intrabc_miss_mode = 0;
   rt_sf->force_only_last_ref = 0;
   rt_sf->higher_thresh_scene_detection = 1;
   rt_sf->skip_newmv_flat_blocks_screen = 0;
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h
index dd5cf57f84..3cf4bc26c6 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -1861,6 +1861,12 @@ typedef struct REAL_TIME_SPEED_FEATURES {
   int rt_use_intrabc;
   // Prune IntraBC for nonrd pickmode.
   int rt_prune_intrabc_nonrd;
+  // Fallback search mode for IntraBC on hash misses in nonrd pickmode.
+  // 0: Full pixel search (Diamond/Hex search)
+  // 1: Block Vector Predictor (BVP) only
+  // 2: BVP + 12-point integer offset probe
+  // 3: Skip fallback search entirely (Hash-only)
+  int rt_intrabc_miss_mode;

   // Force only single reference (LAST) for prediction.
   int force_only_last_ref;