From 9f16bcd58b0c37750497b70a672a96a04df81e3a Mon Sep 17 00:00:00 2001 From: Urvang Joshi Date: Wed, 8 Jul 2026 06:28:41 -0700 Subject: [PATCH 1/7] Prune uneven 4A/4B partitions with neighbor block boundaries Use the best partitioning boundaries of left / above coding blocks to prune uneven 4way partitions -- by checking boundary alignment. Only prune for inter frames. Enabled for speed >= 1. Results for RA CTC 33 frames, speed 1: (Anchor: aa78cfb06) +---------+--------+--------+--------+--------+----------+ | Summary | Y | U | V | YUV | Enc-time | +---------+--------+--------+--------+--------+----------+ | A1 | 0.10% | 0.03% | 0.06% | 0.10% | 97.88% | | A2 | 0.07% | 0.08% | 0.13% | 0.07% | 95.50% | |avg wo b2| 0.07% | 0.12% | 0.07% | 0.07% | 95.23% | +---------+--------+--------+--------+--------+----------+ Note: no changes at speed 4, because uneven 4way partitions seem to be disabled / restricted at this speed. Related: refactor a common av2_get_chroma_start_location() function. STATS_CHANGED for speed >= 1. --- av2/common/av2_common_int.h | 15 ++++++ av2/common/av2_loopfilter.c | 31 ++++--------- av2/encoder/partition_search.c | 83 ++++++++++++++++++++++++++++++++++ av2/encoder/speed_features.c | 3 ++ av2/encoder/speed_features.h | 2 + 5 files changed, 111 insertions(+), 23 deletions(-) diff --git a/av2/common/av2_common_int.h b/av2/common/av2_common_int.h index 079ec30b48..7e692b7196 100644 --- a/av2/common/av2_common_int.h +++ b/av2/common/av2_common_int.h @@ -6050,6 +6050,21 @@ static INLINE bool av2_skip_reference_buffer_update( return clear_multiple_insert_in_one && ref_index != first_ref_index; } +// Returns the starting mi location of chroma reference block for the current +// mbmi, by setting `chroma_mi_row_start` and `chroma_mi_col_start`. +static INLINE void av2_get_chroma_start_location(const MB_MODE_INFO *mbmi, + TREE_TYPE tree_type, + int *chroma_mi_row_start, + int *chroma_mi_col_start) { + if (tree_type == SHARED_PART) { + *chroma_mi_row_start = mbmi->chroma_ref_info.mi_row_chroma_base; + *chroma_mi_col_start = mbmi->chroma_ref_info.mi_col_chroma_base; + } else { + *chroma_mi_row_start = mbmi->chroma_mi_row_start; + *chroma_mi_col_start = mbmi->chroma_mi_col_start; + } +} + #ifdef __cplusplus } // extern "C" #endif diff --git a/av2/common/av2_loopfilter.c b/av2/common/av2_loopfilter.c index edba623d75..036193efb7 100644 --- a/av2/common/av2_loopfilter.c +++ b/av2/common/av2_loopfilter.c @@ -138,22 +138,6 @@ void av2_loop_filter_frame_init(AV2_COMMON *cm, int plane_start, } } -// Returns the starting mi location of chroma reference block for the current -// mbmi, by setting `chroma_mi_row_start` and `chroma_mi_col_start`. -static void get_chroma_start_location(const MB_MODE_INFO *mbmi, - TREE_TYPE tree_type, - int *chroma_mi_row_start, - int *chroma_mi_col_start) { - assert(tree_type == SHARED_PART || tree_type == CHROMA_PART); - if (tree_type == SHARED_PART) { - *chroma_mi_row_start = mbmi->chroma_ref_info.mi_row_chroma_base; - *chroma_mi_col_start = mbmi->chroma_ref_info.mi_col_chroma_base; - } else { - *chroma_mi_row_start = mbmi->chroma_mi_row_start; - *chroma_mi_col_start = mbmi->chroma_mi_col_start; - } -} - // Returns true if we are at the transform boundary. static bool is_tu_edge_helper(TX_SIZE tx_size, EDGE_DIR edge_dir, int relative_row, int relative_col) { @@ -193,7 +177,8 @@ static TX_SIZE get_transform_size(const MACROBLOCKD *const xd, int mi_row_start = mbmi->mi_row_start; int mi_col_start = mbmi->mi_col_start; if (plane != AVM_PLANE_Y) { - get_chroma_start_location(mbmi, tree_type, &mi_row_start, &mi_col_start); + av2_get_chroma_start_location(mbmi, tree_type, &mi_row_start, + &mi_col_start); } *tu_edge = is_tu_edge_helper( tx_size, edge_dir, (mi_row - mi_row_start) >> plane_ptr->subsampling_y, @@ -211,8 +196,8 @@ static TX_SIZE get_transform_size(const MACROBLOCKD *const xd, plane_ptr->subsampling_y); int chroma_mi_row_start; int chroma_mi_col_start; - get_chroma_start_location(mbmi, tree_type, &chroma_mi_row_start, - &chroma_mi_col_start); + av2_get_chroma_start_location(mbmi, tree_type, &chroma_mi_row_start, + &chroma_mi_col_start); *tu_edge = is_tu_edge_helper( tx_size, edge_dir, (mi_row - chroma_mi_row_start) >> plane_ptr->subsampling_y, @@ -329,8 +314,8 @@ static uint32_t get_pu_starting_cooord(const MB_MODE_INFO *const mbmi, } else { int chroma_mi_row_start; int chroma_mi_col_start; - get_chroma_start_location(mbmi, tree_type, &chroma_mi_row_start, - &chroma_mi_col_start); + av2_get_chroma_start_location(mbmi, tree_type, &chroma_mi_row_start, + &chroma_mi_col_start); pu_starting_mi = vert_edge ? chroma_mi_col_start : chroma_mi_row_start; } const uint32_t pu_stating_coord_luma = pu_starting_mi * MI_SIZE; @@ -510,8 +495,8 @@ static int get_remaining_mi_size(const MB_MODE_INFO *mbmi, } else { int mi_row_start_uv; int mi_col_start_uv; - get_chroma_start_location(mbmi, tree_type, &mi_row_start_uv, - &mi_col_start_uv); + av2_get_chroma_start_location(mbmi, tree_type, &mi_row_start_uv, + &mi_col_start_uv); const int mi_pu_start_y = vert_edge ? mi_row_start_uv : mi_col_start_uv; const int scale = vert_edge ? ss_y : ss_x; mi_pu_start = mi_pu_start_y >> scale; diff --git a/av2/encoder/partition_search.c b/av2/encoder/partition_search.c index 54145f09e2..c5108c45f3 100644 --- a/av2/encoder/partition_search.c +++ b/av2/encoder/partition_search.c @@ -2896,6 +2896,83 @@ static AVM_INLINE void init_allowed_partitions( #endif // CONFIG_COLLECT_PARTITION_STATS } +static AVM_INLINE bool is_same_block_for_tree(const MB_MODE_INFO *m1, + const MB_MODE_INFO *m2, + TREE_TYPE tree_type) { + if (!m1 || !m2) return false; + + if (tree_type == CHROMA_PART) { + int m1_r; + int m1_c; + av2_get_chroma_start_location(m1, m1->tree_type, &m1_r, &m1_c); + int m2_r; + int m2_c; + av2_get_chroma_start_location(m2, m2->tree_type, &m2_r, &m2_c); + return m1_r == m2_r && m1_c == m2_c; + } else { + return m1->mi_row_start == m2->mi_row_start && + m1->mi_col_start == m2->mi_col_start; + } +} + +static AVM_INLINE void prune_partitions_with_neighbor_boundaries( + PartitionSearchState *state, const AV2_COMMON *cm, const MACROBLOCKD *xd, + int mi_row, int mi_col, BLOCK_SIZE bsize) { + const int mi_width = mi_size_wide[bsize]; + const int mi_height = mi_size_high[bsize]; + + const int available_mi_height = + AVMMIN(mi_height, cm->mi_params.mi_rows - mi_row); + const int available_mi_width = + AVMMIN(mi_width, cm->mi_params.mi_cols - mi_col); + + bool left_horz_boundaries[MAX_MIB_SIZE] = { false }; + bool top_vert_boundaries[MAX_MIB_SIZE] = { false }; + + // Check left neighbor for horizontal boundaries using mi array + if (xd->left_available && xd->mi_col > 0) { + for (int r = 1; r < available_mi_height; r++) { + const MB_MODE_INFO *m1 = xd->mi[r * xd->mi_stride - 1]; + const MB_MODE_INFO *m2 = xd->mi[(r - 1) * xd->mi_stride - 1]; + if (!is_same_block_for_tree(m1, m2, xd->tree_type)) { + left_horz_boundaries[r] = true; + } + } + } + + // Check top neighbor for vertical boundaries using mi array + if (xd->up_available && xd->mi_row > 0) { + for (int c = 1; c < available_mi_width; c++) { + const MB_MODE_INFO *m1 = xd->mi[-xd->mi_stride + c]; + const MB_MODE_INFO *m2 = xd->mi[-xd->mi_stride + c - 1]; + if (!is_same_block_for_tree(m1, m2, xd->tree_type)) { + top_vert_boundaries[c] = true; + } + } + } + + // Prune 4-way Partitions. + if (xd->left_available && xd->mi_col > 0) { + if (mi_height >= 8 && (!left_horz_boundaries[mi_height / 8] && + !left_horz_boundaries[3 * mi_height / 8] && + !left_horz_boundaries[5 * mi_height / 8] && + !left_horz_boundaries[7 * mi_height / 8])) { + state->prune_partition[PARTITION_HORZ_4A] = true; + state->prune_partition[PARTITION_HORZ_4B] = true; + } + } + + if (xd->up_available && xd->mi_row > 0) { + if (mi_width >= 8 && (!top_vert_boundaries[mi_width / 8] && + !top_vert_boundaries[3 * mi_width / 8] && + !top_vert_boundaries[5 * mi_width / 8] && + !top_vert_boundaries[7 * mi_width / 8])) { + state->prune_partition[PARTITION_VERT_4A] = true; + state->prune_partition[PARTITION_VERT_4B] = true; + } + } +} + // Initialize state variables of partition search used in // av2_rd_pick_partition(). static void init_partition_search_state_params( @@ -5342,6 +5419,12 @@ bool av2_rd_pick_partition( av2_set_offsets(cpi, tile_info, x, mi_row, mi_col, bsize, &pc_tree->chroma_ref_info); + if (cpi->sf.part_sf.prune_part_with_neighbor_boundaries && + !x->must_find_valid_partition && !frame_is_intra_only(cm)) { + prune_partitions_with_neighbor_boundaries(&part_search_state, cm, xd, + mi_row, mi_col, bsize); + } + // Save rdmult before it might be changed, so it can be restored later. const int orig_rdmult = x->rdmult; setup_block_rdmult(cpi, x, mi_row, mi_col, bsize, NO_AQ, NULL); diff --git a/av2/encoder/speed_features.c b/av2/encoder/speed_features.c index 5aaefa7314..dd308f8686 100644 --- a/av2/encoder/speed_features.c +++ b/av2/encoder/speed_features.c @@ -750,6 +750,7 @@ static AVM_INLINE void init_part_sf(PARTITION_SPEED_FEATURES *part_sf) { part_sf->prune_rect_with_split_depth = 0; part_sf->prune_part_h_with_partition_boundary = 0; part_sf->inter_sdp_fast_method_level = 0; + part_sf->prune_part_with_neighbor_boundaries = 0; #if CONFIG_ML_PART_SPLIT part_sf->prune_split_with_ml = 0; part_sf->prune_none_with_ml = 0; @@ -1083,6 +1084,7 @@ static AVM_INLINE void set_erp_speed_features(AV2_COMP *cpi) { sf->part_sf.ext_recur_depth_level = 2; sf->part_sf.simple_motion_search_split = 1; sf->part_sf.simple_motion_search_early_term_none = 1; + sf->part_sf.prune_part_with_neighbor_boundaries = true; AVM_FALLTHROUGH_INTENDED; case 5: sf->part_sf.prune_part_h_with_partition_boundary = true; @@ -1122,6 +1124,7 @@ static AVM_INLINE void set_erp_speed_features(AV2_COMP *cpi) { // Emulate erp_pruning_level = 6. sf->part_sf.ext_recur_depth_level = 1; sf->part_sf.ml_early_term_after_part_split_level = 2; + sf->part_sf.prune_part_with_neighbor_boundaries = true; } if (cpi->speed >= 2) { diff --git a/av2/encoder/speed_features.h b/av2/encoder/speed_features.h index b6c2d42ce7..1193409f34 100644 --- a/av2/encoder/speed_features.h +++ b/av2/encoder/speed_features.h @@ -441,6 +441,8 @@ typedef struct PARTITION_SPEED_FEATURES { // intra coded block, prunes when inter ratio exceeds 50%, and early skips // when current best partitioning is PARTITION_NONE. int inter_sdp_fast_method_level; + // Prune partition types if they don't align with neighbor block boundaries. + bool prune_part_with_neighbor_boundaries; #if CONFIG_ML_PART_SPLIT int prune_split_with_ml; int prune_split_ml_level; From 36fd3387d5f07ca846145765d5422307a4475d71 Mon Sep 17 00:00:00 2001 From: Urvang Joshi Date: Tue, 4 Aug 2026 14:46:10 -0700 Subject: [PATCH 2/7] remove extra conditions, int type, assert --- av2/common/av2_common_int.h | 1 + av2/encoder/partition_search.c | 8 ++++---- av2/encoder/speed_features.c | 4 ++-- av2/encoder/speed_features.h | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/av2/common/av2_common_int.h b/av2/common/av2_common_int.h index 7e692b7196..e16d37c514 100644 --- a/av2/common/av2_common_int.h +++ b/av2/common/av2_common_int.h @@ -6056,6 +6056,7 @@ static INLINE void av2_get_chroma_start_location(const MB_MODE_INFO *mbmi, TREE_TYPE tree_type, int *chroma_mi_row_start, int *chroma_mi_col_start) { + assert(tree_type == SHARED_PART || tree_type == CHROMA_PART); if (tree_type == SHARED_PART) { *chroma_mi_row_start = mbmi->chroma_ref_info.mi_row_chroma_base; *chroma_mi_col_start = mbmi->chroma_ref_info.mi_col_chroma_base; diff --git a/av2/encoder/partition_search.c b/av2/encoder/partition_search.c index c5108c45f3..a75f3be90a 100644 --- a/av2/encoder/partition_search.c +++ b/av2/encoder/partition_search.c @@ -2930,7 +2930,7 @@ static AVM_INLINE void prune_partitions_with_neighbor_boundaries( bool top_vert_boundaries[MAX_MIB_SIZE] = { false }; // Check left neighbor for horizontal boundaries using mi array - if (xd->left_available && xd->mi_col > 0) { + if (xd->left_available) { for (int r = 1; r < available_mi_height; r++) { const MB_MODE_INFO *m1 = xd->mi[r * xd->mi_stride - 1]; const MB_MODE_INFO *m2 = xd->mi[(r - 1) * xd->mi_stride - 1]; @@ -2941,7 +2941,7 @@ static AVM_INLINE void prune_partitions_with_neighbor_boundaries( } // Check top neighbor for vertical boundaries using mi array - if (xd->up_available && xd->mi_row > 0) { + if (xd->up_available) { for (int c = 1; c < available_mi_width; c++) { const MB_MODE_INFO *m1 = xd->mi[-xd->mi_stride + c]; const MB_MODE_INFO *m2 = xd->mi[-xd->mi_stride + c - 1]; @@ -2952,7 +2952,7 @@ static AVM_INLINE void prune_partitions_with_neighbor_boundaries( } // Prune 4-way Partitions. - if (xd->left_available && xd->mi_col > 0) { + if (xd->left_available) { if (mi_height >= 8 && (!left_horz_boundaries[mi_height / 8] && !left_horz_boundaries[3 * mi_height / 8] && !left_horz_boundaries[5 * mi_height / 8] && @@ -2962,7 +2962,7 @@ static AVM_INLINE void prune_partitions_with_neighbor_boundaries( } } - if (xd->up_available && xd->mi_row > 0) { + if (xd->up_available) { if (mi_width >= 8 && (!top_vert_boundaries[mi_width / 8] && !top_vert_boundaries[3 * mi_width / 8] && !top_vert_boundaries[5 * mi_width / 8] && diff --git a/av2/encoder/speed_features.c b/av2/encoder/speed_features.c index dd308f8686..d94faa1932 100644 --- a/av2/encoder/speed_features.c +++ b/av2/encoder/speed_features.c @@ -1084,7 +1084,7 @@ static AVM_INLINE void set_erp_speed_features(AV2_COMP *cpi) { sf->part_sf.ext_recur_depth_level = 2; sf->part_sf.simple_motion_search_split = 1; sf->part_sf.simple_motion_search_early_term_none = 1; - sf->part_sf.prune_part_with_neighbor_boundaries = true; + sf->part_sf.prune_part_with_neighbor_boundaries = 1; AVM_FALLTHROUGH_INTENDED; case 5: sf->part_sf.prune_part_h_with_partition_boundary = true; @@ -1124,7 +1124,7 @@ static AVM_INLINE void set_erp_speed_features(AV2_COMP *cpi) { // Emulate erp_pruning_level = 6. sf->part_sf.ext_recur_depth_level = 1; sf->part_sf.ml_early_term_after_part_split_level = 2; - sf->part_sf.prune_part_with_neighbor_boundaries = true; + sf->part_sf.prune_part_with_neighbor_boundaries = 1; } if (cpi->speed >= 2) { diff --git a/av2/encoder/speed_features.h b/av2/encoder/speed_features.h index 1193409f34..e40168e016 100644 --- a/av2/encoder/speed_features.h +++ b/av2/encoder/speed_features.h @@ -442,7 +442,7 @@ typedef struct PARTITION_SPEED_FEATURES { // when current best partitioning is PARTITION_NONE. int inter_sdp_fast_method_level; // Prune partition types if they don't align with neighbor block boundaries. - bool prune_part_with_neighbor_boundaries; + int prune_part_with_neighbor_boundaries; #if CONFIG_ML_PART_SPLIT int prune_split_with_ml; int prune_split_ml_level; From 521cfcc4e110a357d3d78d52ebb5816c2d9bd235 Mon Sep 17 00:00:00 2001 From: Urvang Joshi Date: Tue, 4 Aug 2026 15:05:38 -0700 Subject: [PATCH 3/7] separate checks for 4A and 4B --- av2/encoder/partition_search.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/av2/encoder/partition_search.c b/av2/encoder/partition_search.c index a75f3be90a..337936288b 100644 --- a/av2/encoder/partition_search.c +++ b/av2/encoder/partition_search.c @@ -2953,22 +2953,32 @@ static AVM_INLINE void prune_partitions_with_neighbor_boundaries( // Prune 4-way Partitions. if (xd->left_available) { - if (mi_height >= 8 && (!left_horz_boundaries[mi_height / 8] && - !left_horz_boundaries[3 * mi_height / 8] && - !left_horz_boundaries[5 * mi_height / 8] && - !left_horz_boundaries[7 * mi_height / 8])) { - state->prune_partition[PARTITION_HORZ_4A] = true; - state->prune_partition[PARTITION_HORZ_4B] = true; + if (mi_height >= 8) { + if (!left_horz_boundaries[mi_height / 8] && + !left_horz_boundaries[3 * mi_height / 8] && + !left_horz_boundaries[7 * mi_height / 8]) { + state->prune_partition[PARTITION_HORZ_4A] = true; + } + if (!left_horz_boundaries[mi_height / 8] && + !left_horz_boundaries[5 * mi_height / 8] && + !left_horz_boundaries[7 * mi_height / 8]) { + state->prune_partition[PARTITION_HORZ_4B] = true; + } } } if (xd->up_available) { - if (mi_width >= 8 && (!top_vert_boundaries[mi_width / 8] && - !top_vert_boundaries[3 * mi_width / 8] && - !top_vert_boundaries[5 * mi_width / 8] && - !top_vert_boundaries[7 * mi_width / 8])) { - state->prune_partition[PARTITION_VERT_4A] = true; - state->prune_partition[PARTITION_VERT_4B] = true; + if (mi_width >= 8) { + if (!top_vert_boundaries[mi_width / 8] && + !top_vert_boundaries[3 * mi_width / 8] && + !top_vert_boundaries[7 * mi_width / 8]) { + state->prune_partition[PARTITION_VERT_4A] = true; + } + if (!top_vert_boundaries[mi_width / 8] && + !top_vert_boundaries[5 * mi_width / 8] && + !top_vert_boundaries[7 * mi_width / 8]) { + state->prune_partition[PARTITION_VERT_4B] = true; + } } } } From 6077a59d73fc32d6e809b9e39f5dc3b02aa70fd7 Mon Sep 17 00:00:00 2001 From: Urvang Joshi Date: Tue, 4 Aug 2026 15:19:24 -0700 Subject: [PATCH 4/7] rename, comment and some added conditions to reduce compute --- av2/encoder/partition_search.c | 57 +++++++++++++++++----------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/av2/encoder/partition_search.c b/av2/encoder/partition_search.c index 337936288b..0608fd8e24 100644 --- a/av2/encoder/partition_search.c +++ b/av2/encoder/partition_search.c @@ -2915,7 +2915,10 @@ static AVM_INLINE bool is_same_block_for_tree(const MB_MODE_INFO *m1, } } -static AVM_INLINE void prune_partitions_with_neighbor_boundaries( +// Prunes uneven 4-way partitions by checking partition boundary alignment with +// neighboring top/left blocks. Neighbor boundaries are detected by checking if +// neighboring top/left MI units share the same block ID. +static AVM_INLINE void prune_4way_partitions_with_neighbor_boundaries( PartitionSearchState *state, const AV2_COMMON *cm, const MACROBLOCKD *xd, int mi_row, int mi_col, BLOCK_SIZE bsize) { const int mi_width = mi_size_wide[bsize]; @@ -2930,7 +2933,7 @@ static AVM_INLINE void prune_partitions_with_neighbor_boundaries( bool top_vert_boundaries[MAX_MIB_SIZE] = { false }; // Check left neighbor for horizontal boundaries using mi array - if (xd->left_available) { + if (xd->left_available && mi_height >= 8) { for (int r = 1; r < available_mi_height; r++) { const MB_MODE_INFO *m1 = xd->mi[r * xd->mi_stride - 1]; const MB_MODE_INFO *m2 = xd->mi[(r - 1) * xd->mi_stride - 1]; @@ -2941,7 +2944,7 @@ static AVM_INLINE void prune_partitions_with_neighbor_boundaries( } // Check top neighbor for vertical boundaries using mi array - if (xd->up_available) { + if (xd->up_available && mi_width >= 8) { for (int c = 1; c < available_mi_width; c++) { const MB_MODE_INFO *m1 = xd->mi[-xd->mi_stride + c]; const MB_MODE_INFO *m2 = xd->mi[-xd->mi_stride + c - 1]; @@ -2952,33 +2955,29 @@ static AVM_INLINE void prune_partitions_with_neighbor_boundaries( } // Prune 4-way Partitions. - if (xd->left_available) { - if (mi_height >= 8) { - if (!left_horz_boundaries[mi_height / 8] && - !left_horz_boundaries[3 * mi_height / 8] && - !left_horz_boundaries[7 * mi_height / 8]) { - state->prune_partition[PARTITION_HORZ_4A] = true; - } - if (!left_horz_boundaries[mi_height / 8] && - !left_horz_boundaries[5 * mi_height / 8] && - !left_horz_boundaries[7 * mi_height / 8]) { - state->prune_partition[PARTITION_HORZ_4B] = true; - } + if (xd->left_available && mi_height >= 8) { + if (!left_horz_boundaries[mi_height / 8] && + !left_horz_boundaries[3 * mi_height / 8] && + !left_horz_boundaries[7 * mi_height / 8]) { + state->prune_partition[PARTITION_HORZ_4A] = true; + } + if (!left_horz_boundaries[mi_height / 8] && + !left_horz_boundaries[5 * mi_height / 8] && + !left_horz_boundaries[7 * mi_height / 8]) { + state->prune_partition[PARTITION_HORZ_4B] = true; } } - if (xd->up_available) { - if (mi_width >= 8) { - if (!top_vert_boundaries[mi_width / 8] && - !top_vert_boundaries[3 * mi_width / 8] && - !top_vert_boundaries[7 * mi_width / 8]) { - state->prune_partition[PARTITION_VERT_4A] = true; - } - if (!top_vert_boundaries[mi_width / 8] && - !top_vert_boundaries[5 * mi_width / 8] && - !top_vert_boundaries[7 * mi_width / 8]) { - state->prune_partition[PARTITION_VERT_4B] = true; - } + if (xd->up_available && mi_width >= 8) { + if (!top_vert_boundaries[mi_width / 8] && + !top_vert_boundaries[3 * mi_width / 8] && + !top_vert_boundaries[7 * mi_width / 8]) { + state->prune_partition[PARTITION_VERT_4A] = true; + } + if (!top_vert_boundaries[mi_width / 8] && + !top_vert_boundaries[5 * mi_width / 8] && + !top_vert_boundaries[7 * mi_width / 8]) { + state->prune_partition[PARTITION_VERT_4B] = true; } } } @@ -5431,8 +5430,8 @@ bool av2_rd_pick_partition( if (cpi->sf.part_sf.prune_part_with_neighbor_boundaries && !x->must_find_valid_partition && !frame_is_intra_only(cm)) { - prune_partitions_with_neighbor_boundaries(&part_search_state, cm, xd, - mi_row, mi_col, bsize); + prune_4way_partitions_with_neighbor_boundaries(&part_search_state, cm, xd, + mi_row, mi_col, bsize); } // Save rdmult before it might be changed, so it can be restored later. From c4d53007719705e2eea53a9f505e612cc30507a3 Mon Sep 17 00:00:00 2001 From: Urvang Joshi Date: Tue, 4 Aug 2026 15:31:58 -0700 Subject: [PATCH 5/7] add extra available row /col check and reorder code --- av2/encoder/partition_search.c | 45 ++++++++++++++-------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/av2/encoder/partition_search.c b/av2/encoder/partition_search.c index 0608fd8e24..62c3163cea 100644 --- a/av2/encoder/partition_search.c +++ b/av2/encoder/partition_search.c @@ -2921,19 +2921,13 @@ static AVM_INLINE bool is_same_block_for_tree(const MB_MODE_INFO *m1, static AVM_INLINE void prune_4way_partitions_with_neighbor_boundaries( PartitionSearchState *state, const AV2_COMMON *cm, const MACROBLOCKD *xd, int mi_row, int mi_col, BLOCK_SIZE bsize) { - const int mi_width = mi_size_wide[bsize]; + // Check left neighbor for horizontal boundaries using mi array const int mi_height = mi_size_high[bsize]; - const int available_mi_height = AVMMIN(mi_height, cm->mi_params.mi_rows - mi_row); - const int available_mi_width = - AVMMIN(mi_width, cm->mi_params.mi_cols - mi_col); - - bool left_horz_boundaries[MAX_MIB_SIZE] = { false }; - bool top_vert_boundaries[MAX_MIB_SIZE] = { false }; - - // Check left neighbor for horizontal boundaries using mi array - if (xd->left_available && mi_height >= 8) { + if (xd->left_available && mi_height >= 8 && + available_mi_height == mi_height) { + bool left_horz_boundaries[MAX_MIB_SIZE] = { false }; for (int r = 1; r < available_mi_height; r++) { const MB_MODE_INFO *m1 = xd->mi[r * xd->mi_stride - 1]; const MB_MODE_INFO *m2 = xd->mi[(r - 1) * xd->mi_stride - 1]; @@ -2941,21 +2935,7 @@ static AVM_INLINE void prune_4way_partitions_with_neighbor_boundaries( left_horz_boundaries[r] = true; } } - } - - // Check top neighbor for vertical boundaries using mi array - if (xd->up_available && mi_width >= 8) { - for (int c = 1; c < available_mi_width; c++) { - const MB_MODE_INFO *m1 = xd->mi[-xd->mi_stride + c]; - const MB_MODE_INFO *m2 = xd->mi[-xd->mi_stride + c - 1]; - if (!is_same_block_for_tree(m1, m2, xd->tree_type)) { - top_vert_boundaries[c] = true; - } - } - } - - // Prune 4-way Partitions. - if (xd->left_available && mi_height >= 8) { + // Prune HORZ 4A/4B partitions. if (!left_horz_boundaries[mi_height / 8] && !left_horz_boundaries[3 * mi_height / 8] && !left_horz_boundaries[7 * mi_height / 8]) { @@ -2968,7 +2948,20 @@ static AVM_INLINE void prune_4way_partitions_with_neighbor_boundaries( } } - if (xd->up_available && mi_width >= 8) { + // Check top neighbor for vertical boundaries using mi array + const int mi_width = mi_size_wide[bsize]; + const int available_mi_width = + AVMMIN(mi_width, cm->mi_params.mi_cols - mi_col); + if (xd->up_available && mi_width >= 8 && available_mi_width == mi_width) { + bool top_vert_boundaries[MAX_MIB_SIZE] = { false }; + for (int c = 1; c < available_mi_width; c++) { + const MB_MODE_INFO *m1 = xd->mi[-xd->mi_stride + c]; + const MB_MODE_INFO *m2 = xd->mi[-xd->mi_stride + c - 1]; + if (!is_same_block_for_tree(m1, m2, xd->tree_type)) { + top_vert_boundaries[c] = true; + } + } + // Prune VERT 4A/4B partitions. if (!top_vert_boundaries[mi_width / 8] && !top_vert_boundaries[3 * mi_width / 8] && !top_vert_boundaries[7 * mi_width / 8]) { From 1bad2ae97dfbaaba01f8359ffee9fe0ba3f9d7be Mon Sep 17 00:00:00 2001 From: Urvang Joshi Date: Wed, 5 Aug 2026 10:05:55 -0700 Subject: [PATCH 6/7] revert to same pruning criteria for 4a/4b --- av2/encoder/partition_search.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/av2/encoder/partition_search.c b/av2/encoder/partition_search.c index 62c3163cea..7f67b76f82 100644 --- a/av2/encoder/partition_search.c +++ b/av2/encoder/partition_search.c @@ -2938,12 +2938,9 @@ static AVM_INLINE void prune_4way_partitions_with_neighbor_boundaries( // Prune HORZ 4A/4B partitions. if (!left_horz_boundaries[mi_height / 8] && !left_horz_boundaries[3 * mi_height / 8] && - !left_horz_boundaries[7 * mi_height / 8]) { - state->prune_partition[PARTITION_HORZ_4A] = true; - } - if (!left_horz_boundaries[mi_height / 8] && !left_horz_boundaries[5 * mi_height / 8] && !left_horz_boundaries[7 * mi_height / 8]) { + state->prune_partition[PARTITION_HORZ_4A] = true; state->prune_partition[PARTITION_HORZ_4B] = true; } } @@ -2964,12 +2961,9 @@ static AVM_INLINE void prune_4way_partitions_with_neighbor_boundaries( // Prune VERT 4A/4B partitions. if (!top_vert_boundaries[mi_width / 8] && !top_vert_boundaries[3 * mi_width / 8] && - !top_vert_boundaries[7 * mi_width / 8]) { - state->prune_partition[PARTITION_VERT_4A] = true; - } - if (!top_vert_boundaries[mi_width / 8] && !top_vert_boundaries[5 * mi_width / 8] && !top_vert_boundaries[7 * mi_width / 8]) { + state->prune_partition[PARTITION_VERT_4A] = true; state->prune_partition[PARTITION_VERT_4B] = true; } } From 489033f42cbe8adc0ba2b5f55b5796215372e602 Mon Sep 17 00:00:00 2001 From: Urvang Joshi Date: Wed, 5 Aug 2026 10:22:51 -0700 Subject: [PATCH 7/7] disable for <= 270p --- av2/encoder/speed_features.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/av2/encoder/speed_features.c b/av2/encoder/speed_features.c index d94faa1932..8c43737c7b 100644 --- a/av2/encoder/speed_features.c +++ b/av2/encoder/speed_features.c @@ -984,6 +984,7 @@ static AVM_INLINE void set_erp_speed_features_framesize_dependent( const int is_1080p_or_larger = AVMMIN(cm->width, cm->height) >= 1080; const unsigned int erp_pruning_level = cpi->oxcf.part_cfg.erp_pruning_level; const int is_720p_or_lesser = AVMMIN(cm->width, cm->height) <= 720; + const int is_270p_or_lesser = AVMMIN(cm->width, cm->height) <= 270; switch (erp_pruning_level) { case 6: AVM_FALLTHROUGH_INTENDED; @@ -1032,6 +1033,10 @@ static AVM_INLINE void set_erp_speed_features_framesize_dependent( sf->part_sf.remove_qp_restriction_with_ml = 1; } #endif // CONFIG_ML_PART_SPLIT + if (is_270p_or_lesser) { + // For small resolutions, this speed feature has a large coding loss. + sf->part_sf.prune_part_with_neighbor_boundaries = 0; + } } if (cpi->speed >= 2) {