Commit fccaf78b57 for aom
commit fccaf78b5708a8b61447c3de5b14c4bef21ccb94
Author: Satheesh Kumar <satheesh.kumar@ittiam.com>
Date: Mon Apr 20 12:32:42 2026 +0530
Skip chroma RD evaluation of interpolation filter search
This patch introduces the speed feature 'skip_model_rd_uv' to skip
the RD evaluation of chroma planes during the interpolation filter
search. The chroma predictors are built later using the best
interpolation filter selected by the luma RD. This speed feature is
enabled for speed >= 3.
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 2.260 -0.0128 -0.0099 -0.0090 0.0010 -0.0064
4 0.957 0.0010 -0.0010 0.0003 -0.0214 -0.0330
5 -0.076 -0.0000 0.0042 -0.0079 -0.0103 -0.0140
6 -0.203 -0.0089 -0.0153 -0.0000 -0.0261 -0.0147
STATS_CHANGED for speed >= 3
Change-Id: I354d04a9f4cd4f37288dbcebf1ae3784ee5a9d38
diff --git a/av1/common/filter.h b/av1/common/filter.h
index fb85ab2cf3..13d2902a91 100644
--- a/av1/common/filter.h
+++ b/av1/common/filter.h
@@ -52,7 +52,8 @@ enum {
enum {
INTERP_EVAL_LUMA_EVAL_CHROMA = 0,
INTERP_SKIP_LUMA_EVAL_CHROMA,
- INTERP_EVAL_INVALID,
+ INTERP_EVAL_LUMA_SKIP_CHROMA, // Valid only when skip_model_rd_uv speed
+ // feature is enabled
INTERP_SKIP_LUMA_SKIP_CHROMA,
} UENUM1BYTE(INTERP_EVAL_PLANE);
diff --git a/av1/encoder/interp_search.c b/av1/encoder/interp_search.c
index 994c78b767..3ecd4a497e 100644
--- a/av1/encoder/interp_search.c
+++ b/av1/encoder/interp_search.c
@@ -188,7 +188,6 @@ static inline int64_t interpolation_filter_rd(
(void)tile_data;
- assert(skip_pred != 2);
assert((rd_stats_luma->rate >= 0) && (rd_stats->rate >= 0));
assert((rd_stats_luma->dist >= 0) && (rd_stats->dist >= 0));
assert((rd_stats_luma->sse >= 0) && (rd_stats->sse >= 0));
@@ -208,11 +207,16 @@ static inline int64_t interpolation_filter_rd(
(skip_pred == interp_search_flags->default_interp_skip_flags)
? INTERP_SKIP_LUMA_SKIP_CHROMA
: skip_pred;
+ assert(IMPLIES(tmp_skip_pred == INTERP_EVAL_LUMA_SKIP_CHROMA,
+ cpi->sf.interp_sf.skip_model_rd_uv));
- switch (tmp_skip_pred) {
- case INTERP_EVAL_LUMA_EVAL_CHROMA:
- // skip_pred = 0: Evaluate both luma and chroma.
- // Luma MC
+ if (tmp_skip_pred == INTERP_SKIP_LUMA_SKIP_CHROMA) {
+ // Both luma and chroma evaluation is skipped
+ this_rd_stats = *rd_stats;
+ } else {
+ // Evaluate Luma
+ if (tmp_skip_pred == INTERP_EVAL_LUMA_EVAL_CHROMA ||
+ tmp_skip_pred == INTERP_EVAL_LUMA_SKIP_CHROMA) {
interp_model_rd_eval(x, cpi, bsize, orig_dst, AOM_PLANE_Y, AOM_PLANE_Y,
&this_rd_stats_luma, 0);
this_rd_stats = this_rd_stats_luma;
@@ -222,10 +226,11 @@ static inline int64_t interpolation_filter_rd(
INT64_MAX);
PrintPredictionUnitStats(cpi, tile_data, x, &rd_stats_y, bsize);
#endif // CONFIG_COLLECT_RD_STATS == 3
- AOM_FALLTHROUGH_INTENDED;
- case INTERP_SKIP_LUMA_EVAL_CHROMA:
- // skip_pred = 1: skip luma evaluation (retain previous best luma stats)
- // and do chroma evaluation.
+ }
+
+ // Evaluate Chroma
+ if (tmp_skip_pred == INTERP_EVAL_LUMA_EVAL_CHROMA ||
+ tmp_skip_pred == INTERP_SKIP_LUMA_EVAL_CHROMA) {
for (int plane = 1; plane < num_planes; ++plane) {
int64_t tmp_rd =
RDCOST(x->rdmult, tmp_rs + this_rd_stats.rate, this_rd_stats.dist);
@@ -236,14 +241,9 @@ static inline int64_t interpolation_filter_rd(
interp_model_rd_eval(x, cpi, bsize, orig_dst, plane, plane,
&this_rd_stats, 0);
}
- break;
- case INTERP_SKIP_LUMA_SKIP_CHROMA:
- // both luma and chroma evaluation is skipped
- this_rd_stats = *rd_stats;
- break;
- case INTERP_EVAL_INVALID:
- default: assert(0); return 0;
+ }
}
+
int64_t tmp_rd =
RDCOST(x->rdmult, tmp_rs + this_rd_stats.rate, this_rd_stats.dist);
@@ -625,6 +625,13 @@ static inline void calc_interp_skip_pred_flag(MACROBLOCK *const x,
assert(mbmi->comp_group_idx == 1);
if (*skip_hor == 0 && *skip_ver == 1) *skip_ver = 0;
}
+
+ // Configure flags to skip chroma RD evaluation when skip_model_rd_uv is
+ // enabled
+ if (cpi->sf.interp_sf.skip_model_rd_uv) {
+ *skip_hor |= INTERP_EVAL_LUMA_SKIP_CHROMA;
+ *skip_ver |= INTERP_EVAL_LUMA_SKIP_CHROMA;
+ }
}
/*!\brief AV1 interpolation filter search
@@ -649,7 +656,7 @@ static inline void calc_interp_skip_pred_flag(MACROBLOCK *const x,
* \param[in,out] switchable_rate The rate associated with using a SWITCHABLE
* filter mode.
* \param[in,out] skip_build_pred Indicates whether or not to build the inter
- * predictor. If this is 0, the inter predictor
+ * predictor. If this is 3, the inter predictor
* has already been built and thus we can avoid
* repeating computation.
* \param[in] args HandleInterModeArgs struct holding
@@ -677,6 +684,7 @@ int64_t av1_interpolation_filter_search(
MB_MODE_INFO *const mbmi = xd->mi[0];
const int need_search = av1_is_interp_needed(xd);
const int ref_frame = xd->mi[0]->ref_frame[0];
+ const int skip_model_rd_uv = cpi->sf.interp_sf.skip_model_rd_uv;
RD_STATS rd_stats_luma, rd_stats;
// Initialization of rd_stats structures with default values
@@ -694,7 +702,7 @@ int64_t av1_interpolation_filter_search(
*rd = args->interp_filter_stats[match_found_idx].rd;
x->pred_sse[ref_frame] =
args->interp_filter_stats[match_found_idx].pred_sse;
- *skip_build_pred = 0;
+ *skip_build_pred = INTERP_EVAL_LUMA_EVAL_CHROMA;
return 0;
}
@@ -716,11 +724,13 @@ int64_t av1_interpolation_filter_search(
PrintPredictionUnitStats(cpi, tile_data, x, &rd_stats_y, bsize);
#endif // CONFIG_COLLECT_RD_STATS == 3
// Chroma MC
- if (num_planes > 1) {
+ if (num_planes > 1 && !skip_model_rd_uv) {
interp_model_rd_eval(x, cpi, bsize, orig_dst, AOM_PLANE_U, AOM_PLANE_V,
&rd_stats, *skip_build_pred);
}
- *skip_build_pred = 1;
+ *skip_build_pred = num_planes > 1 && skip_model_rd_uv
+ ? INTERP_SKIP_LUMA_EVAL_CHROMA
+ : INTERP_SKIP_LUMA_SKIP_CHROMA;
av1_merge_rd_stats(&rd_stats, &rd_stats_luma);
@@ -757,7 +767,8 @@ int64_t av1_interpolation_filter_search(
// Setting 0th flag corresonds to skipping luma MC and setting 1st bt
// corresponds to skipping chroma MC skip_flag=0 corresponds to "Don't skip
// luma and chroma MC" Skip flag=1 corresponds to "Skip Luma MC only"
- // Skip_flag=2 is not a valid case
+ // Skip_flag=2 corresponds to "Skip chroma MC only". This is valid only when
+ // skip_model_rd_uv speed feature is enabled
// skip_flag=3 corresponds to "Skip both luma and chroma MC"
int skip_hor = interp_search_flags->default_interp_skip_flags;
int skip_ver = interp_search_flags->default_interp_skip_flags;
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index f099bf46d3..3ebbd10701 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -2689,10 +2689,9 @@ static inline int prune_modes_based_on_tpl_stats(
* to skip the transform search if the computed
* skip RD for the current mode is not better
* than the best skip_rd so far.
- * \param[in,out] skip_build_pred Indicates whether or not to build the inter
- * predictor. If this is 0, the inter predictor
- * has already been built and thus we can avoid
- * repeating computation.
+ * \param[out] skip_build_pred Indicates whether or not to build the inter
+ * predictor during/after interpolation
+ * filter search.
* \return Returns 1 if this mode is worse than one already seen and 0 if it is
* a viable candidate.
*/
@@ -2746,7 +2745,7 @@ static int process_compound_inter_mode(
av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize,
AOM_PLANE_U, num_planes - 1);
}
- *skip_build_pred = 1;
+ *skip_build_pred = INTERP_SKIP_LUMA_SKIP_CHROMA;
}
return 0;
}
@@ -3274,7 +3273,9 @@ static int64_t handle_inter_mode(
}
}
- int skip_build_pred = 0;
+ // Flag to indicate whether to skip av1_enc_build_inter_predictor() after
+ // interpolation filter search
+ int skip_build_pred = INTERP_EVAL_LUMA_EVAL_CHROMA;
const int mi_row = xd->mi_row;
const int mi_col = xd->mi_col;
@@ -3334,12 +3335,19 @@ static int64_t handle_inter_mode(
}
rd_stats->rate += compmode_interinter_cost;
- if (skip_build_pred != 1) {
+ if (skip_build_pred != INTERP_SKIP_LUMA_SKIP_CHROMA) {
+ // Chroma plane of COMPOUND_DIFFWTD mode shares the segment mask of luma
+ // which is stored in xd->seg_mask. Hence, the predictor is populated for
+ // all planes. This should avoid usage of incorrect segment mask when the
+ // call is made only for chroma.
+ const int skip_luma_plane =
+ skip_build_pred == INTERP_SKIP_LUMA_EVAL_CHROMA &&
+ mbmi->interinter_comp.type != COMPOUND_DIFFWTD;
+ const int start_plane = skip_luma_plane ? AOM_PLANE_U : AOM_PLANE_Y;
// Build this inter predictor if it has not been previously built
- av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst, bsize, 0,
- av1_num_planes(cm) - 1);
+ av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst, bsize,
+ start_plane, num_planes - 1);
}
-
#if CONFIG_COLLECT_COMPONENT_TIMING
start_timing(cpi, motion_mode_rd_time);
#endif
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index ac031e2575..4bab891c3d 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -1319,6 +1319,7 @@ static void set_good_speed_features_framesize_independent(
sf->inter_sf.prune_single_ref = 2;
sf->interp_sf.adaptive_interp_filter_search = 2;
+ sf->interp_sf.skip_model_rd_uv = 1;
// TODO(chiyotsai@google.com): the thresholds chosen for intra hog are
// inherited directly from luma hog with some minor tweaking. Eventually we
@@ -2416,6 +2417,7 @@ static inline void init_interp_sf(INTERP_FILTER_SPEED_FEATURES *interp_sf) {
interp_sf->use_interp_filter = 0;
interp_sf->skip_interp_filter_search = 0;
interp_sf->use_more_sharp_interp = 0;
+ interp_sf->skip_model_rd_uv = 0;
}
static inline void init_intra_sf(INTRA_MODE_SPEED_FEATURES *intra_sf) {
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h
index 05db0a921a..342049ecf3 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -1279,6 +1279,10 @@ typedef struct INTERP_FILTER_SPEED_FEATURES {
// Bias towards sharp filter
int use_more_sharp_interp;
+
+ // Skip model RD evaluation of chroma planes during interpolation filter
+ // search.
+ int skip_model_rd_uv;
} INTERP_FILTER_SPEED_FEATURES;
typedef struct INTRA_MODE_SPEED_FEATURES {