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 e952ee8..f43c8df 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 @@ 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 6904276..ef673c0 100644 --- a/av1/encoder/speed_features.c +++ b/av1/encoder/speed_features.c
@@ -1773,6 +1773,7 @@ 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 @@ 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 dd5cf57..3cf4bc2 100644 --- a/av1/encoder/speed_features.h +++ b/av1/encoder/speed_features.h
@@ -1861,6 +1861,12 @@ 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;