From f0cb0ff4dc09d77e24db7e46f9a95c249db3038a Mon Sep 17 00:00:00 2001 From: Marco Paniconi Date: Wed, 23 Sep 2026 17:31:45 +0000 Subject: [PATCH 1/3] Update intra modes for realtime screen content speed >= 6 Update intra mode evaluation in inter frames for realtime mode at speed >= 6 when screen content tools are enabled: - Generalize use_only_dc_intra_interframe to prune_intra_mode_in_interframe - For screen content at speed >= 6, set prune_intra_mode_in_interframe = 1: test DC, V, and H intra modes (with 0 delta angle) on blocks <= 16x16, and only DC mode on blocks > 16x16 - For screen content at speed >= 6, set skip_intra_in_interframe = 1: gate intra mode skipping on skip_txfm using a distortion threshold rather than skipping unconditionally Only affects realtime mode for screen content at speed >= 6. On rtc_screen: bdrate gain of ~7%, with ~4% slowdown. --- av2/encoder/rdopt.c | 29 ++++++++++++++++++++++++----- av2/encoder/speed_features.c | 10 ++++++++-- av2/encoder/speed_features.h | 7 +++++-- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/av2/encoder/rdopt.c b/av2/encoder/rdopt.c index 9200e45aeb..c8530b5c5b 100644 --- a/av2/encoder/rdopt.c +++ b/av2/encoder/rdopt.c @@ -8999,10 +8999,19 @@ static void av2_evaluate_intra_modes_in_inter_frame( av2_nn_softmax(scores, probs, 2); if (probs[1] > 0.8) search_state->intra_search_state.skip_intra_modes = 1; - } else if ((search_state->best_mbmode - .skip_txfm[xd->tree_type == CHROMA_PART]) && - (sf->intra_sf.skip_intra_in_interframe >= 2)) { - search_state->intra_search_state.skip_intra_modes = 1; + } else if (search_state->best_mbmode + .skip_txfm[xd->tree_type == CHROMA_PART]) { + if (sf->intra_sf.skip_intra_in_interframe == 1 && + cpi->oxcf.mode == REALTIME) { + const int num_pixels = block_size_wide[bsize] * block_size_high[bsize]; + const int shift = (xd->bd - 8) * 2; + const int64_t dist_thresh = ((int64_t)num_pixels * 5000) << shift; + if (rd_cost->dist <= dist_thresh) { + search_state->intra_search_state.skip_intra_modes = 1; + } + } else if (sf->intra_sf.skip_intra_in_interframe >= 2) { + search_state->intra_search_state.skip_intra_modes = 1; + } } } @@ -9035,6 +9044,7 @@ static void av2_evaluate_intra_modes_in_inter_frame( search_state->intra_search_state.dir_mode_skip_mask_ready = 1; } } + for (int dpcm_idx = 0; dpcm_idx < dpcm_loop_num; dpcm_idx++) { // Dry pass: cap DPCM index. if (apply_dry_pass_shortcuts && dpcm_idx > dry_pass_cfg->intra_dpcm_cap) @@ -9079,7 +9089,10 @@ static void av2_evaluate_intra_modes_in_inter_frame( mode_idx >= AVMMIN((int)mbmi->num_y_intra_mpm, dry_pass_cfg->intra_mpm_cap)) break; - if (sf->rt_sf.use_only_dc_intra_interframe && mode_idx != DC_PRED) + if ((sf->rt_sf.prune_intra_mode_in_interframe == 2 || + (sf->rt_sf.prune_intra_mode_in_interframe == 1 && + bsize > BLOCK_16X16)) && + mode_idx != DC_PRED) continue; if (sf->intra_sf.skip_intra_in_interframe && search_state->intra_search_state.skip_intra_modes) @@ -9088,6 +9101,12 @@ static void av2_evaluate_intra_modes_in_inter_frame( mbmi->joint_y_mode_delta_angle = mbmi->y_intra_mode_list[mode_idx]; av2_set_y_mode_and_delta_angle(mbmi->joint_y_mode_delta_angle, mbmi); + if (sf->rt_sf.prune_intra_mode_in_interframe == 1) { + if (mbmi->mode != DC_PRED && mbmi->mode != V_PRED && + mbmi->mode != H_PRED) + continue; + if (mbmi->angle_delta[PLANE_TYPE_Y] != 0) continue; + } if ((!cpi->oxcf.intra_mode_cfg.enable_smooth_intra || cpi->sf.intra_sf.disable_smooth_intra) && (mbmi->mode == SMOOTH_PRED || mbmi->mode == SMOOTH_H_PRED || diff --git a/av2/encoder/speed_features.c b/av2/encoder/speed_features.c index f1a4a036fa..92083b9fd8 100644 --- a/av2/encoder/speed_features.c +++ b/av2/encoder/speed_features.c @@ -765,6 +765,7 @@ static void set_good_speed_features_lc_dec_framesize_independent( static void set_rt_speed_features_framesize_independent( const AV2_COMP *const cpi, SPEED_FEATURES *const sf, int speed) { + const AV2_COMMON *const cm = &cpi->common; // Set this good features as default for now. set_good_speed_features_framesize_independent(cpi, sf, speed); if (speed >= 6) { @@ -779,11 +780,16 @@ static void set_rt_speed_features_framesize_independent( sf->part_sf.partition_search_type = VAR_BASED_PARTITION; sf->rd_sf.tx_domain_dist_thres_level = 2; sf->rt_sf.use_nonrd_partition = 1; - sf->rt_sf.use_only_dc_intra_interframe = true; sf->rt_sf.source_metrics_sb = 1; sf->winner_mode_sf.tx_size_search_level = USE_FAST_RD; sf->tx_sf.restrict_tx_partition_type_search = 3; sf->tx_sf.enable_tx_partition = true; + sf->intra_sf.skip_intra_in_interframe = 2; + sf->rt_sf.prune_intra_mode_in_interframe = 2; + if (cm->features.allow_screen_content_tools) { + sf->intra_sf.skip_intra_in_interframe = 1; + sf->rt_sf.prune_intra_mode_in_interframe = 1; + } } } @@ -1113,7 +1119,7 @@ static AVM_INLINE void init_lc_sf(LC_DEC_SPEED_FEATURES *lc_sf) { static AVM_INLINE void init_rt_sf(REALTIME_SPEED_FEATURES *rt_sf) { rt_sf->use_nonrd_partition = 0; - rt_sf->use_only_dc_intra_interframe = false; + rt_sf->prune_intra_mode_in_interframe = 0; rt_sf->source_metrics_sb = 0; } diff --git a/av2/encoder/speed_features.h b/av2/encoder/speed_features.h index ca461d00e1..66059ae249 100644 --- a/av2/encoder/speed_features.h +++ b/av2/encoder/speed_features.h @@ -1100,8 +1100,11 @@ typedef struct REALTIME_SPEED_FEATURES { // Use non-rd partition instead of rd partition. int use_nonrd_partition; - // Flag to disable all but DC intra mode for inter frame prediction. - bool use_only_dc_intra_interframe; + // Prune intra mode search in inter frames: + // 0: Search all intra modes + // 1: Test only DC, V, and H modes + // 2: Test only DC mode + int prune_intra_mode_in_interframe; // Compute source sad metrics for superblock. int source_metrics_sb; From f1f11fa3cad90e9d9a1057c89b754d64e66a8f50 Mon Sep 17 00:00:00 2001 From: Marco Paniconi Date: Wed, 23 Sep 2026 23:45:23 +0000 Subject: [PATCH 2/3] update condition for speed feature setting --- av2/encoder/speed_features.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/av2/encoder/speed_features.c b/av2/encoder/speed_features.c index 92083b9fd8..bb5cf6aff0 100644 --- a/av2/encoder/speed_features.c +++ b/av2/encoder/speed_features.c @@ -786,7 +786,7 @@ static void set_rt_speed_features_framesize_independent( sf->tx_sf.enable_tx_partition = true; sf->intra_sf.skip_intra_in_interframe = 2; sf->rt_sf.prune_intra_mode_in_interframe = 2; - if (cm->features.allow_screen_content_tools) { + if (cpi->oxcf.tune_cfg.content == AVM_CONTENT_SCREEN) { sf->intra_sf.skip_intra_in_interframe = 1; sf->rt_sf.prune_intra_mode_in_interframe = 1; } From c40122e3b9f7ddc37c2cc8e975e13ca4b75be234 Mon Sep 17 00:00:00 2001 From: Marco Paniconi Date: Wed, 23 Sep 2026 23:51:24 +0000 Subject: [PATCH 3/3] remove unused variable --- av2/encoder/speed_features.c | 1 - 1 file changed, 1 deletion(-) diff --git a/av2/encoder/speed_features.c b/av2/encoder/speed_features.c index bb5cf6aff0..b4e9d66d9e 100644 --- a/av2/encoder/speed_features.c +++ b/av2/encoder/speed_features.c @@ -765,7 +765,6 @@ static void set_good_speed_features_lc_dec_framesize_independent( static void set_rt_speed_features_framesize_independent( const AV2_COMP *const cpi, SPEED_FEATURES *const sf, int speed) { - const AV2_COMMON *const cm = &cpi->common; // Set this good features as default for now. set_good_speed_features_framesize_independent(cpi, sf, speed); if (speed >= 6) {