Move some ref frame pruning logic to frame level
Create a frame level mask to mark which ref frames should be skipped
for encoding current frame during RDO. Before this patch, the pruning
decisions were made on block level repeatedly. A small instruction count
redcution is achieved.
Change-Id: Id2ecf54cc33c9f8a85f55e1f02a37d11c5187e3e
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index eceaf25..8c93bf4 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -5332,8 +5332,7 @@
ref_buf[frame]->y_crop_height == cpi->source->y_crop_height &&
do_gm_search_logic(&cpi->sf, frame) &&
!prune_ref_by_selective_ref_frame(
- cpi, NULL, ref_frame, cm->cur_frame->ref_display_order_hint,
- cm->current_frame.display_order_hint) &&
+ cpi, NULL, ref_frame, cm->cur_frame->ref_display_order_hint) &&
!(cpi->sf.gm_sf.selective_ref_gm && skip_gm_frame(cm, frame))) {
assert(ref_buf[frame] != NULL);
int relative_frame_dist = av1_encoder_get_relative_dist(
@@ -5412,6 +5411,60 @@
}
}
+static AOM_INLINE void setup_prune_ref_frame_mask(AV1_COMP *cpi) {
+ if (!cpi->sf.rt_sf.use_nonrd_pick_mode &&
+ cpi->sf.inter_sf.selective_ref_frame >= 2) {
+ AV1_COMMON *const cm = &cpi->common;
+ const OrderHintInfo *const order_hint_info =
+ &cm->seq_params.order_hint_info;
+ const int cur_frame_display_order_hint =
+ cm->current_frame.display_order_hint;
+ unsigned int *ref_display_order_hint =
+ cm->cur_frame->ref_display_order_hint;
+ const int arf2_dist = av1_encoder_get_relative_dist(
+ order_hint_info, ref_display_order_hint[ALTREF2_FRAME - LAST_FRAME],
+ cur_frame_display_order_hint);
+ const int bwd_dist = av1_encoder_get_relative_dist(
+ order_hint_info, ref_display_order_hint[BWDREF_FRAME - LAST_FRAME],
+ cur_frame_display_order_hint);
+
+ for (int ref_idx = REF_FRAMES; ref_idx < MODE_CTX_REF_FRAMES; ++ref_idx) {
+ MV_REFERENCE_FRAME rf[2];
+ av1_set_ref_frame(rf, ref_idx);
+ if (!(cpi->ref_frame_flags & av1_ref_frame_flag_list[rf[0]]) ||
+ !(cpi->ref_frame_flags & av1_ref_frame_flag_list[rf[1]])) {
+ continue;
+ }
+
+ if (!cpi->all_one_sided_refs) {
+ int ref_dist[2];
+ for (int i = 0; i < 2; ++i) {
+ ref_dist[i] = av1_encoder_get_relative_dist(
+ order_hint_info, ref_display_order_hint[rf[i] - LAST_FRAME],
+ cur_frame_display_order_hint);
+ }
+
+ // One-sided compound is used only when all reference frames are
+ // one-sided.
+ if ((ref_dist[0] > 0) == (ref_dist[1] > 0)) {
+ cpi->prune_ref_frame_mask |= 1 << ref_idx;
+ }
+ }
+
+ if (cpi->sf.inter_sf.selective_ref_frame >= 4 &&
+ (rf[0] == ALTREF2_FRAME || rf[1] == ALTREF2_FRAME) &&
+ (cpi->ref_frame_flags & av1_ref_frame_flag_list[BWDREF_FRAME])) {
+ // Check if both ALTREF2_FRAME and BWDREF_FRAME are future references.
+ if (arf2_dist > 0 && bwd_dist > 0 && bwd_dist <= arf2_dist) {
+ // Drop ALTREF2_FRAME as a reference if BWDREF_FRAME is a closer
+ // reference to the current frame than ALTREF2_FRAME
+ cpi->prune_ref_frame_mask |= 1 << ref_idx;
+ }
+ }
+ }
+ }
+}
+
static AOM_INLINE void encode_frame_internal(AV1_COMP *cpi) {
ThreadData *const td = &cpi->td;
MACROBLOCK *const x = &td->mb;
@@ -5591,6 +5644,13 @@
memcpy(cm->cur_frame->ref_deltas, cm->lf.ref_deltas, REF_FRAMES);
memcpy(cm->cur_frame->mode_deltas, cm->lf.mode_deltas, MAX_MODE_LF_DELTAS);
+ cpi->all_one_sided_refs =
+ frame_is_intra_only(cm) ? 0 : av1_refs_are_one_sided(cm);
+
+ cpi->prune_ref_frame_mask = 0;
+ // Figure out which ref frames can be skipped at frame level.
+ setup_prune_ref_frame_mask(cpi);
+
x->txb_split_count = 0;
#if CONFIG_SPEED_STATS
x->tx_search_count = 0;
@@ -5689,9 +5749,6 @@
end_timing(cpi, av1_setup_motion_field_time);
#endif
- cpi->all_one_sided_refs =
- frame_is_intra_only(cm) ? 0 : av1_refs_are_one_sided(cm);
-
cm->current_frame.skip_mode_info.skip_mode_flag =
check_skip_mode_enabled(cpi);
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 7b6e685..b36b186 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -1029,6 +1029,9 @@
int dv_joint_cost[MV_JOINTS];
int has_lossless_segment;
+ // Mark which ref frames can be skipped for encoding current frame druing RDO.
+ int prune_ref_frame_mask;
+
// Factors to control gating of compound type selection based on best
// approximate rd so far
int max_comp_type_rd_threshold_mul;
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index 4e19e24..6a1c8e4 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -3682,6 +3682,9 @@
return 1;
}
+ const int ref_type = av1_ref_frame_type(ref_frame);
+ if ((cpi->prune_ref_frame_mask >> ref_type) & 1) return 1;
+
// This is only used in motion vector unit test.
if (cpi->oxcf.motion_vector_unit_test && ref_frame[0] == INTRA_FRAME)
return 1;
@@ -3707,7 +3710,6 @@
int skip_motion_mode = 0;
if (mbmi->partition != PARTITION_NONE && mbmi->partition != PARTITION_SPLIT) {
- const int ref_type = av1_ref_frame_type(ref_frame);
int skip_ref = skip_ref_frame_mask & (1 << ref_type);
if (ref_type <= ALTREF_FRAME && skip_ref) {
// Since the compound ref modes depends on the motion estimation result of
@@ -3745,8 +3747,7 @@
}
if (prune_ref_by_selective_ref_frame(cpi, x, ref_frame,
- cm->cur_frame->ref_display_order_hint,
- cm->current_frame.display_order_hint))
+ cm->cur_frame->ref_display_order_hint))
return 1;
if (skip_motion_mode) return 2;
diff --git a/av1/encoder/rdopt.h b/av1/encoder/rdopt.h
index 986ac28..b07f56c 100644
--- a/av1/encoder/rdopt.h
+++ b/av1/encoder/rdopt.h
@@ -182,85 +182,43 @@
static INLINE int prune_ref_by_selective_ref_frame(
const AV1_COMP *const cpi, const MACROBLOCK *const x,
const MV_REFERENCE_FRAME *const ref_frame,
- const unsigned int *const ref_display_order_hint,
- const unsigned int cur_frame_display_order_hint) {
+ const unsigned int *const ref_display_order_hint) {
const SPEED_FEATURES *const sf = &cpi->sf;
+ if (!sf->inter_sf.selective_ref_frame) return 0;
- if (sf->inter_sf.selective_ref_frame) {
- const AV1_COMMON *const cm = &cpi->common;
- const OrderHintInfo *const order_hint_info =
- &cm->seq_params.order_hint_info;
- const int comp_pred = ref_frame[1] > INTRA_FRAME;
- if (sf->inter_sf.selective_ref_frame >= 2 ||
- (sf->inter_sf.selective_ref_frame == 1 && comp_pred)) {
- int ref_frame_list[2] = { LAST3_FRAME, LAST2_FRAME };
+ const AV1_COMMON *const cm = &cpi->common;
+ const OrderHintInfo *const order_hint_info = &cm->seq_params.order_hint_info;
+ const int comp_pred = ref_frame[1] > INTRA_FRAME;
- if (x != NULL) {
- if (x->search_ref_frame[LAST3_FRAME]) ref_frame_list[0] = NONE_FRAME;
- if (x->search_ref_frame[LAST2_FRAME]) ref_frame_list[1] = NONE_FRAME;
- }
+ if (sf->inter_sf.selective_ref_frame >= 2 ||
+ (sf->inter_sf.selective_ref_frame == 1 && comp_pred)) {
+ int ref_frame_list[2] = { LAST3_FRAME, LAST2_FRAME };
- if (prune_ref(ref_frame, order_hint_info, ref_display_order_hint,
- ref_display_order_hint[GOLDEN_FRAME - LAST_FRAME],
- ref_frame_list))
- return 1;
+ if (x != NULL) {
+ if (x->search_ref_frame[LAST3_FRAME]) ref_frame_list[0] = NONE_FRAME;
+ if (x->search_ref_frame[LAST2_FRAME]) ref_frame_list[1] = NONE_FRAME;
}
- // One-sided compound is used only when all reference frames are one-sided.
- if (sf->inter_sf.selective_ref_frame >= 2 && comp_pred &&
- !cpi->all_one_sided_refs) {
- unsigned int ref_offsets[2];
- int ref_dist[2];
- for (int i = 0; i < 2; ++i) {
- const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref_frame[i]);
- assert(buf != NULL);
- ref_offsets[i] = buf->display_order_hint;
- ref_dist[i] = av1_encoder_get_relative_dist(
- order_hint_info, ref_offsets[i], cur_frame_display_order_hint);
- }
-
- // If both references are in same direction
- if ((ref_dist[0] > 0) == (ref_dist[1] > 0)) {
- return 1;
- }
- }
-
- if (sf->inter_sf.selective_ref_frame >= 3) {
- int ref_frame_list[2] = { ALTREF2_FRAME, BWDREF_FRAME };
-
- if (x != NULL) {
- if (x->search_ref_frame[ALTREF2_FRAME]) ref_frame_list[0] = NONE_FRAME;
- if (x->search_ref_frame[BWDREF_FRAME]) ref_frame_list[1] = NONE_FRAME;
- }
-
- if (prune_ref(ref_frame, order_hint_info, ref_display_order_hint,
- ref_display_order_hint[LAST_FRAME - LAST_FRAME],
- ref_frame_list))
- return 1;
- }
-
- if (sf->inter_sf.selective_ref_frame >= 4 && comp_pred) {
- // Check if one of the reference is ALTREF2_FRAME and BWDREF_FRAME is a
- // valid reference.
- if ((ref_frame[0] == ALTREF2_FRAME || ref_frame[1] == ALTREF2_FRAME) &&
- (cpi->ref_frame_flags & av1_ref_frame_flag_list[BWDREF_FRAME])) {
- // Check if both ALTREF2_FRAME and BWDREF_FRAME are future references.
- const int arf2_dist = av1_encoder_get_relative_dist(
- order_hint_info, ref_display_order_hint[ALTREF2_FRAME - LAST_FRAME],
- cur_frame_display_order_hint);
- const int bwd_dist = av1_encoder_get_relative_dist(
- order_hint_info, ref_display_order_hint[BWDREF_FRAME - LAST_FRAME],
- cur_frame_display_order_hint);
- if (arf2_dist > 0 && bwd_dist > 0 && bwd_dist <= arf2_dist) {
- // Drop ALTREF2_FRAME as a reference if BWDREF_FRAME is a closer
- // reference to the current frame than ALTREF2_FRAME
- assert(get_ref_frame_buf(cm, ALTREF2_FRAME) != NULL);
- assert(get_ref_frame_buf(cm, BWDREF_FRAME) != NULL);
- return 1;
- }
- }
- }
+ if (prune_ref(ref_frame, order_hint_info, ref_display_order_hint,
+ ref_display_order_hint[GOLDEN_FRAME - LAST_FRAME],
+ ref_frame_list))
+ return 1;
}
+
+ if (sf->inter_sf.selective_ref_frame >= 3) {
+ int ref_frame_list[2] = { ALTREF2_FRAME, BWDREF_FRAME };
+
+ if (x != NULL) {
+ if (x->search_ref_frame[ALTREF2_FRAME]) ref_frame_list[0] = NONE_FRAME;
+ if (x->search_ref_frame[BWDREF_FRAME]) ref_frame_list[1] = NONE_FRAME;
+ }
+
+ if (prune_ref(ref_frame, order_hint_info, ref_display_order_hint,
+ ref_display_order_hint[LAST_FRAME - LAST_FRAME],
+ ref_frame_list))
+ return 1;
+ }
+
return 0;
}
#ifdef __cplusplus