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;