Separate interp_filter_search functions from rdopt.c
Created interp_search.h and interp_search.c to
improve modularity of rdopt.c
interp_search.c : To keep interpolation related functions
interp_search.h : To keep interpolation related data
structures, defs and enum.
Change-Id: I1d7fcbf35ff2707b248a50b7184c95487d2c7f38
diff --git a/av1/av1.cmake b/av1/av1.cmake
index 569125e..2589185 100644
--- a/av1/av1.cmake
+++ b/av1/av1.cmake
@@ -167,6 +167,8 @@
"${AOM_ROOT}/av1/encoder/hash_motion.h"
"${AOM_ROOT}/av1/encoder/hybrid_fwd_txfm.c"
"${AOM_ROOT}/av1/encoder/hybrid_fwd_txfm.h"
+ "${AOM_ROOT}/av1/encoder/interp_search.c"
+ "${AOM_ROOT}/av1/encoder/interp_search.h"
"${AOM_ROOT}/av1/encoder/level.c"
"${AOM_ROOT}/av1/encoder/level.h"
"${AOM_ROOT}/av1/encoder/lookahead.c"
diff --git a/av1/encoder/interp_search.c b/av1/encoder/interp_search.c
new file mode 100644
index 0000000..91d570b
--- /dev/null
+++ b/av1/encoder/interp_search.c
@@ -0,0 +1,741 @@
+/*
+ * Copyright (c) 2020, Alliance for Open Media. All rights reserved
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#include "av1/common/pred_common.h"
+#include "av1/encoder/interp_search.h"
+#include "av1/encoder/model_rd.h"
+#include "av1/encoder/rdopt_utils.h"
+#include "av1/encoder/reconinter_enc.h"
+
+// return mv_diff
+static INLINE int is_interp_filter_good_match(
+ const INTERPOLATION_FILTER_STATS *st, MB_MODE_INFO *const mi,
+ int skip_level) {
+ const int is_comp = has_second_ref(mi);
+ int i;
+
+ for (i = 0; i < 1 + is_comp; ++i) {
+ if (st->ref_frames[i] != mi->ref_frame[i]) return INT_MAX;
+ }
+
+ if (skip_level == 1 && is_comp) {
+ if (st->comp_type != mi->interinter_comp.type) return INT_MAX;
+ if (st->compound_idx != mi->compound_idx) return INT_MAX;
+ }
+
+ int mv_diff = 0;
+ for (i = 0; i < 1 + is_comp; ++i) {
+ mv_diff += abs(st->mv[i].as_mv.row - mi->mv[i].as_mv.row) +
+ abs(st->mv[i].as_mv.col - mi->mv[i].as_mv.col);
+ }
+ return mv_diff;
+}
+
+static INLINE int save_interp_filter_search_stat(
+ MB_MODE_INFO *const mbmi, int64_t rd, unsigned int pred_sse,
+ INTERPOLATION_FILTER_STATS *interp_filter_stats,
+ int interp_filter_stats_idx) {
+ if (interp_filter_stats_idx < MAX_INTERP_FILTER_STATS) {
+ INTERPOLATION_FILTER_STATS stat = { mbmi->interp_filters,
+ { mbmi->mv[0], mbmi->mv[1] },
+ { mbmi->ref_frame[0],
+ mbmi->ref_frame[1] },
+ mbmi->interinter_comp.type,
+ mbmi->compound_idx,
+ rd,
+ pred_sse };
+ interp_filter_stats[interp_filter_stats_idx] = stat;
+ interp_filter_stats_idx++;
+ }
+ return interp_filter_stats_idx;
+}
+
+static INLINE int find_interp_filter_in_stats(
+ MB_MODE_INFO *const mbmi, INTERPOLATION_FILTER_STATS *interp_filter_stats,
+ int interp_filter_stats_idx, int skip_level) {
+ // [skip_levels][single or comp]
+ const int thr[2][2] = { { 0, 0 }, { 3, 7 } };
+ const int is_comp = has_second_ref(mbmi);
+
+ // Find good enough match.
+ // TODO(yunqing): Separate single-ref mode and comp mode stats for fast
+ // search.
+ int best = INT_MAX;
+ int match = -1;
+ for (int j = 0; j < interp_filter_stats_idx; ++j) {
+ const INTERPOLATION_FILTER_STATS *st = &interp_filter_stats[j];
+ const int mv_diff = is_interp_filter_good_match(st, mbmi, skip_level);
+ // Exact match is found.
+ if (mv_diff == 0) {
+ match = j;
+ break;
+ } else if (mv_diff < best && mv_diff <= thr[skip_level - 1][is_comp]) {
+ best = mv_diff;
+ match = j;
+ }
+ }
+
+ if (match != -1) {
+ mbmi->interp_filters = interp_filter_stats[match].filters;
+ return match;
+ }
+ return -1; // no match result found
+}
+
+int find_interp_filter_match(MB_MODE_INFO *const mbmi,
+ const AV1_COMP *const cpi,
+ const InterpFilter assign_filter,
+ const int need_search,
+ INTERPOLATION_FILTER_STATS *interp_filter_stats,
+ int interp_filter_stats_idx) {
+ int match_found_idx = -1;
+ if (cpi->sf.interp_sf.use_interp_filter && need_search)
+ match_found_idx = find_interp_filter_in_stats(
+ mbmi, interp_filter_stats, interp_filter_stats_idx,
+ cpi->sf.interp_sf.use_interp_filter);
+
+ if (!need_search || match_found_idx == -1)
+ set_default_interp_filters(mbmi, assign_filter);
+ return match_found_idx;
+}
+
+static INLINE void swap_dst_buf(MACROBLOCKD *xd, const BUFFER_SET *dst_bufs[2],
+ int num_planes) {
+ const BUFFER_SET *buf0 = dst_bufs[0];
+ dst_bufs[0] = dst_bufs[1];
+ dst_bufs[1] = buf0;
+ restore_dst_buf(xd, *dst_bufs[0], num_planes);
+}
+
+static INLINE int get_switchable_rate(MACROBLOCK *const x,
+ const int_interpfilters filters,
+ const int ctx[2]) {
+ int inter_filter_cost;
+ const InterpFilter filter0 = filters.as_filters.y_filter;
+ const InterpFilter filter1 = filters.as_filters.x_filter;
+ inter_filter_cost = x->switchable_interp_costs[ctx[0]][filter0];
+ inter_filter_cost += x->switchable_interp_costs[ctx[1]][filter1];
+ return SWITCHABLE_INTERP_RATE_FACTOR * inter_filter_cost;
+}
+
+// Build inter predictor and calculate model rd
+// for a given plane.
+static INLINE void interp_model_rd_eval(
+ MACROBLOCK *const x, const AV1_COMP *const cpi, BLOCK_SIZE bsize,
+ const BUFFER_SET *const orig_dst, int plane_from, int plane_to,
+ RD_STATS *rd_stats, int is_skip_build_pred) {
+ const AV1_COMMON *cm = &cpi->common;
+ MACROBLOCKD *const xd = &x->e_mbd;
+ RD_STATS tmp_rd_stats;
+ av1_init_rd_stats(&tmp_rd_stats);
+
+ // Skip inter predictor if the predictor is already avilable.
+ if (!is_skip_build_pred) {
+ const int mi_row = xd->mi_row;
+ const int mi_col = xd->mi_col;
+ av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize,
+ plane_from, plane_to);
+ }
+
+ model_rd_sb_fn[cpi->sf.rt_sf.use_simple_rd_model
+ ? MODELRD_LEGACY
+ : MODELRD_TYPE_INTERP_FILTER](
+ cpi, bsize, x, xd, plane_from, plane_to, &tmp_rd_stats.rate,
+ &tmp_rd_stats.dist, &tmp_rd_stats.skip, &tmp_rd_stats.sse, NULL, NULL,
+ NULL);
+
+ av1_merge_rd_stats(rd_stats, &tmp_rd_stats);
+}
+
+// calculate the rdcost of given interpolation_filter
+static INLINE int64_t interpolation_filter_rd(
+ MACROBLOCK *const x, const AV1_COMP *const cpi,
+ const TileDataEnc *tile_data, BLOCK_SIZE bsize,
+ const BUFFER_SET *const orig_dst, int64_t *const rd,
+ RD_STATS *rd_stats_luma, RD_STATS *rd_stats, int *const switchable_rate,
+ const BUFFER_SET *dst_bufs[2], int filter_idx, const int switchable_ctx[2],
+ const int skip_pred) {
+ const AV1_COMMON *cm = &cpi->common;
+ const int num_planes = av1_num_planes(cm);
+ MACROBLOCKD *const xd = &x->e_mbd;
+ MB_MODE_INFO *const mbmi = xd->mi[0];
+ RD_STATS this_rd_stats_luma, this_rd_stats;
+
+ // Initialize rd_stats structures to default values.
+ av1_init_rd_stats(&this_rd_stats_luma);
+ this_rd_stats = *rd_stats_luma;
+ const int_interpfilters last_best = mbmi->interp_filters;
+ mbmi->interp_filters = filter_sets[filter_idx];
+ const int tmp_rs =
+ get_switchable_rate(x, mbmi->interp_filters, switchable_ctx);
+
+ int64_t min_rd = RDCOST(x->rdmult, tmp_rs, 0);
+ if (min_rd > *rd) {
+ mbmi->interp_filters = last_best;
+ return 0;
+ }
+
+ (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));
+ assert((rd_stats_luma->skip == 0) || (rd_stats_luma->skip == 1));
+ assert((rd_stats->skip == 0) || (rd_stats->skip == 1));
+ assert((skip_pred >= 0) && (skip_pred <= cpi->default_interp_skip_flags));
+
+ // When skip pred is equal to default_interp_skip_flags,
+ // skip both luma and chroma MC.
+ // For mono-chrome images:
+ // num_planes = 1 and cpi->default_interp_skip_flags = 1,
+ // skip_pred = 1: skip both luma and chroma
+ // skip_pred = 0: Evaluate luma and as num_planes=1,
+ // skip chroma evaluation
+ int tmp_skip_pred = (skip_pred == cpi->default_interp_skip_flags)
+ ? INTERP_SKIP_LUMA_SKIP_CHROMA
+ : skip_pred;
+
+ switch (tmp_skip_pred) {
+ case INTERP_EVAL_LUMA_EVAL_CHROMA:
+ // skip_pred = 0: Evaluate both luma and chroma.
+ // Luma MC
+ 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;
+#if CONFIG_COLLECT_RD_STATS == 3
+ RD_STATS rd_stats_y;
+ pick_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize, 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.
+ 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);
+ if (tmp_rd >= *rd) {
+ mbmi->interp_filters = last_best;
+ return 0;
+ }
+ 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);
+
+ if (tmp_rd < *rd) {
+ *rd = tmp_rd;
+ *switchable_rate = tmp_rs;
+ if (skip_pred != cpi->default_interp_skip_flags) {
+ if (skip_pred == INTERP_EVAL_LUMA_EVAL_CHROMA) {
+ // Overwrite the data as current filter is the best one
+ *rd_stats_luma = this_rd_stats_luma;
+ *rd_stats = this_rd_stats;
+ // As luma MC data is computed, no need to recompute after the search
+ x->recalc_luma_mc_data = 0;
+ } else if (skip_pred == INTERP_SKIP_LUMA_EVAL_CHROMA) {
+ // As luma MC data is not computed, update of luma data can be skipped
+ *rd_stats = this_rd_stats;
+ // As luma MC data is not recomputed and current filter is the best,
+ // indicate the possibility of recomputing MC data
+ // If current buffer contains valid MC data, toggle to indicate that
+ // luma MC data needs to be recomputed
+ x->recalc_luma_mc_data ^= 1;
+ }
+ swap_dst_buf(xd, dst_bufs, num_planes);
+ }
+ return 1;
+ }
+ mbmi->interp_filters = last_best;
+ return 0;
+}
+
+static INLINE INTERP_PRED_TYPE is_pred_filter_search_allowed(
+ const AV1_COMP *const cpi, MACROBLOCKD *xd, BLOCK_SIZE bsize,
+ int_interpfilters *af, int_interpfilters *lf) {
+ const AV1_COMMON *cm = &cpi->common;
+ const MB_MODE_INFO *const above_mbmi = xd->above_mbmi;
+ const MB_MODE_INFO *const left_mbmi = xd->left_mbmi;
+ const int bsl = mi_size_wide_log2[bsize];
+ int is_horiz_eq = 0, is_vert_eq = 0;
+
+ if (above_mbmi && is_inter_block(above_mbmi))
+ *af = above_mbmi->interp_filters;
+
+ if (left_mbmi && is_inter_block(left_mbmi)) *lf = left_mbmi->interp_filters;
+
+ if (af->as_filters.x_filter != INTERP_INVALID)
+ is_horiz_eq = af->as_filters.x_filter == lf->as_filters.x_filter;
+ if (af->as_filters.y_filter != INTERP_INVALID)
+ is_vert_eq = af->as_filters.y_filter == lf->as_filters.y_filter;
+
+ INTERP_PRED_TYPE pred_filter_type = (is_vert_eq << 1) + is_horiz_eq;
+ const int mi_row = xd->mi_row;
+ const int mi_col = xd->mi_col;
+ int pred_filter_enable =
+ cpi->sf.interp_sf.cb_pred_filter_search
+ ? (((mi_row + mi_col) >> bsl) +
+ get_chessboard_index(cm->current_frame.frame_number)) &
+ 0x1
+ : 0;
+ pred_filter_enable &= is_horiz_eq || is_vert_eq;
+ // pred_filter_search = 0: pred_filter is disabled
+ // pred_filter_search = 1: pred_filter is enabled and only horz pred matching
+ // pred_filter_search = 2: pred_filter is enabled and only vert pred matching
+ // pred_filter_search = 3: pred_filter is enabled and
+ // both vert, horz pred matching
+ return pred_filter_enable * pred_filter_type;
+}
+
+static DUAL_FILTER_TYPE find_best_interp_rd_facade(
+ MACROBLOCK *const x, const AV1_COMP *const cpi,
+ const TileDataEnc *tile_data, BLOCK_SIZE bsize,
+ const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y,
+ RD_STATS *rd_stats, int *const switchable_rate,
+ const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2],
+ const int skip_pred, uint16_t allow_interp_mask, int is_w4_or_h4) {
+ int tmp_skip_pred = skip_pred;
+ DUAL_FILTER_TYPE best_filt_type = REG_REG;
+
+ // If no filter are set to be evaluated, return from function
+ if (allow_interp_mask == 0x0) return best_filt_type;
+ // For block width or height is 4, skip the pred evaluation of SHARP_SHARP
+ tmp_skip_pred = is_w4_or_h4 ? cpi->default_interp_skip_flags : skip_pred;
+
+ // Loop over the all filter types and evaluate for only allowed filter types
+ for (int filt_type = SHARP_SHARP; filt_type >= REG_REG; --filt_type) {
+ const int is_filter_allowed =
+ get_interp_filter_allowed_mask(allow_interp_mask, filt_type);
+ if (is_filter_allowed)
+ if (interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
+ rd_stats_y, rd_stats, switchable_rate,
+ dst_bufs, filt_type, switchable_ctx,
+ tmp_skip_pred))
+ best_filt_type = filt_type;
+ tmp_skip_pred = skip_pred;
+ }
+ return best_filt_type;
+}
+
+static INLINE void pred_dual_interp_filter_rd(
+ MACROBLOCK *const x, const AV1_COMP *const cpi,
+ const TileDataEnc *tile_data, BLOCK_SIZE bsize,
+ const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y,
+ RD_STATS *rd_stats, int *const switchable_rate,
+ const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2],
+ const int skip_pred, INTERP_PRED_TYPE pred_filt_type, int_interpfilters *af,
+ int_interpfilters *lf) {
+ (void)lf;
+ assert(pred_filt_type > INTERP_HORZ_NEQ_VERT_NEQ);
+ assert(pred_filt_type < INTERP_PRED_TYPE_ALL);
+ uint16_t allowed_interp_mask = 0;
+
+ if (pred_filt_type == INTERP_HORZ_EQ_VERT_NEQ) {
+ // pred_filter_search = 1: Only horizontal filter is matching
+ allowed_interp_mask =
+ av1_interp_dual_filt_mask[pred_filt_type - 1][af->as_filters.x_filter];
+ } else if (pred_filt_type == INTERP_HORZ_NEQ_VERT_EQ) {
+ // pred_filter_search = 2: Only vertical filter is matching
+ allowed_interp_mask =
+ av1_interp_dual_filt_mask[pred_filt_type - 1][af->as_filters.y_filter];
+ } else {
+ // pred_filter_search = 3: Both horizontal and vertical filter are matching
+ int filt_type =
+ af->as_filters.x_filter + af->as_filters.y_filter * SWITCHABLE_FILTERS;
+ set_interp_filter_allowed_mask(&allowed_interp_mask, filt_type);
+ }
+ // REG_REG is already been evaluated in the beginning
+ reset_interp_filter_allowed_mask(&allowed_interp_mask, REG_REG);
+ find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd, rd_stats_y,
+ rd_stats, switchable_rate, dst_bufs,
+ switchable_ctx, skip_pred, allowed_interp_mask, 0);
+}
+// Evaluate dual filter type
+// a) Using above, left block interp filter
+// b) Find the best horizontal filter and
+// then evaluate corresponding vertical filters.
+static INLINE void fast_dual_interp_filter_rd(
+ MACROBLOCK *const x, const AV1_COMP *const cpi,
+ const TileDataEnc *tile_data, BLOCK_SIZE bsize,
+ const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y,
+ RD_STATS *rd_stats, int *const switchable_rate,
+ const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2],
+ const int skip_hor, const int skip_ver) {
+ MACROBLOCKD *const xd = &x->e_mbd;
+ MB_MODE_INFO *const mbmi = xd->mi[0];
+ INTERP_PRED_TYPE pred_filter_type = INTERP_HORZ_NEQ_VERT_NEQ;
+ int_interpfilters af = av1_broadcast_interp_filter(INTERP_INVALID);
+ int_interpfilters lf = af;
+
+ if (!have_newmv_in_inter_mode(mbmi->mode)) {
+ pred_filter_type = is_pred_filter_search_allowed(cpi, xd, bsize, &af, &lf);
+ }
+
+ if (pred_filter_type) {
+ pred_dual_interp_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
+ rd_stats_y, rd_stats, switchable_rate, dst_bufs,
+ switchable_ctx, (skip_hor & skip_ver),
+ pred_filter_type, &af, &lf);
+ } else {
+ const int bw = block_size_wide[bsize];
+ const int bh = block_size_high[bsize];
+ int best_dual_mode = 0;
+ int skip_pred = bw <= 4 ? cpi->default_interp_skip_flags : skip_hor;
+ // TODO(any): Make use of find_best_interp_rd_facade()
+ // if speed impact is negligible
+ for (int i = (SWITCHABLE_FILTERS - 1); i >= 1; --i) {
+ if (interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
+ rd_stats_y, rd_stats, switchable_rate,
+ dst_bufs, i, switchable_ctx, skip_pred)) {
+ best_dual_mode = i;
+ }
+ skip_pred = skip_hor;
+ }
+ // From best of horizontal EIGHTTAP_REGULAR modes, check vertical modes
+ skip_pred = bh <= 4 ? cpi->default_interp_skip_flags : skip_ver;
+ for (int i = (best_dual_mode + (SWITCHABLE_FILTERS * 2));
+ i >= (best_dual_mode + SWITCHABLE_FILTERS); i -= SWITCHABLE_FILTERS) {
+ interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
+ rd_stats_y, rd_stats, switchable_rate, dst_bufs,
+ i, switchable_ctx, skip_pred);
+ skip_pred = skip_ver;
+ }
+ }
+}
+
+// Find the best interp filter if dual_interp_filter = 0
+static INLINE void find_best_non_dual_interp_filter(
+ MACROBLOCK *const x, const AV1_COMP *const cpi,
+ const TileDataEnc *tile_data, BLOCK_SIZE bsize,
+ const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y,
+ RD_STATS *rd_stats, int *const switchable_rate,
+ const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2],
+ const int skip_ver, const int skip_hor) {
+ int8_t i;
+ MACROBLOCKD *const xd = &x->e_mbd;
+ MB_MODE_INFO *const mbmi = xd->mi[0];
+
+ uint16_t interp_filter_search_mask = cpi->interp_filter_search_mask;
+
+ if (cpi->sf.interp_sf.adaptive_interp_filter_search == 2) {
+ const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->gf_group);
+ const int ctx0 = av1_get_pred_context_switchable_interp(xd, 0);
+ const int ctx1 = av1_get_pred_context_switchable_interp(xd, 1);
+ const int *switchable_interp_p0 =
+ cpi->switchable_interp_probs[update_type][ctx0];
+ const int *switchable_interp_p1 =
+ cpi->switchable_interp_probs[update_type][ctx1];
+
+ const int thresh = cpi->switchable_interp_thresh[update_type];
+ for (i = 0; i < SWITCHABLE_FILTERS; i++) {
+ // For non-dual case, the 2 dir's prob should be identical.
+ assert(switchable_interp_p0[i] == switchable_interp_p1[i]);
+ if (switchable_interp_p0[i] < thresh &&
+ switchable_interp_p1[i] < thresh) {
+ DUAL_FILTER_TYPE filt_type = i + SWITCHABLE_FILTERS * i;
+ reset_interp_filter_allowed_mask(&interp_filter_search_mask, filt_type);
+ }
+ }
+ }
+
+ // Regular filter evaluation should have been done and hence the same should
+ // be the winner
+ assert(x->e_mbd.mi[0]->interp_filters.as_int == filter_sets[0].as_int);
+ if ((skip_hor & skip_ver) != cpi->default_interp_skip_flags) {
+ INTERP_PRED_TYPE pred_filter_type = INTERP_HORZ_NEQ_VERT_NEQ;
+ int_interpfilters af = av1_broadcast_interp_filter(INTERP_INVALID);
+ int_interpfilters lf = af;
+
+ pred_filter_type = is_pred_filter_search_allowed(cpi, xd, bsize, &af, &lf);
+ if (pred_filter_type) {
+ assert(af.as_filters.x_filter != INTERP_INVALID);
+ int filter_idx = SWITCHABLE * af.as_filters.x_filter;
+ // This assert tells that (filter_x == filter_y) for non-dual filter case
+ assert(filter_sets[filter_idx].as_filters.x_filter ==
+ filter_sets[filter_idx].as_filters.y_filter);
+ if (cpi->sf.interp_sf.adaptive_interp_filter_search &&
+ !(get_interp_filter_allowed_mask(interp_filter_search_mask,
+ filter_idx))) {
+ return;
+ }
+ if (filter_idx) {
+ interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
+ rd_stats_y, rd_stats, switchable_rate, dst_bufs,
+ filter_idx, switchable_ctx,
+ (skip_hor & skip_ver));
+ }
+ return;
+ }
+ }
+ // Reuse regular filter's modeled rd data for sharp filter for following
+ // cases
+ // 1) When bsize is 4x4
+ // 2) When block width is 4 (i.e. 4x8/4x16 blocks) and MV in vertical
+ // direction is full-pel
+ // 3) When block height is 4 (i.e. 8x4/16x4 blocks) and MV in horizontal
+ // direction is full-pel
+ // TODO(any): Optimize cases 2 and 3 further if luma MV in relavant direction
+ // alone is full-pel
+
+ if ((bsize == BLOCK_4X4) ||
+ (block_size_wide[bsize] == 4 &&
+ skip_ver == cpi->default_interp_skip_flags) ||
+ (block_size_high[bsize] == 4 &&
+ skip_hor == cpi->default_interp_skip_flags)) {
+ int skip_pred = skip_hor & skip_ver;
+ uint16_t allowed_interp_mask = 0;
+
+ // REG_REG filter type is evaluated beforehand, hence skip it
+ set_interp_filter_allowed_mask(&allowed_interp_mask, SHARP_SHARP);
+ set_interp_filter_allowed_mask(&allowed_interp_mask, SMOOTH_SMOOTH);
+ if (cpi->sf.interp_sf.adaptive_interp_filter_search)
+ allowed_interp_mask &= interp_filter_search_mask;
+
+ find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd,
+ rd_stats_y, rd_stats, switchable_rate, dst_bufs,
+ switchable_ctx, skip_pred, allowed_interp_mask,
+ 1);
+ } else {
+ int skip_pred = (skip_hor & skip_ver);
+ for (i = (SWITCHABLE_FILTERS + 1); i < DUAL_FILTER_SET_SIZE;
+ i += (SWITCHABLE_FILTERS + 1)) {
+ // This assert tells that (filter_x == filter_y) for non-dual filter case
+ assert(filter_sets[i].as_filters.x_filter ==
+ filter_sets[i].as_filters.y_filter);
+ if (cpi->sf.interp_sf.adaptive_interp_filter_search &&
+ !(get_interp_filter_allowed_mask(interp_filter_search_mask, i))) {
+ continue;
+ }
+ interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
+ rd_stats_y, rd_stats, switchable_rate, dst_bufs,
+ i, switchable_ctx, skip_pred);
+ // In first iteration, smooth filter is evaluated. If smooth filter
+ // (which is less sharper) is the winner among regular and smooth filters,
+ // sharp filter evaluation is skipped
+ // TODO(any): Refine this gating based on modelled rd only (i.e., by not
+ // accounting switchable filter rate)
+ if (cpi->sf.interp_sf.skip_sharp_interp_filter_search &&
+ skip_pred != cpi->default_interp_skip_flags) {
+ if (mbmi->interp_filters.as_int == filter_sets[SMOOTH_SMOOTH].as_int)
+ break;
+ }
+ }
+ }
+}
+
+static INLINE void calc_interp_skip_pred_flag(MACROBLOCK *const x,
+ const AV1_COMP *const cpi,
+ int *skip_hor, int *skip_ver) {
+ const AV1_COMMON *cm = &cpi->common;
+ MACROBLOCKD *const xd = &x->e_mbd;
+ MB_MODE_INFO *const mbmi = xd->mi[0];
+ const int num_planes = av1_num_planes(cm);
+ const int is_compound = has_second_ref(mbmi);
+ assert(is_intrabc_block(mbmi) == 0);
+ for (int ref = 0; ref < 1 + is_compound; ++ref) {
+ const struct scale_factors *const sf =
+ get_ref_scale_factors_const(cm, mbmi->ref_frame[ref]);
+ // TODO(any): Refine skip flag calculation considering scaling
+ if (av1_is_scaled(sf)) {
+ *skip_hor = 0;
+ *skip_ver = 0;
+ break;
+ }
+ const MV mv = mbmi->mv[ref].as_mv;
+ int skip_hor_plane = 0;
+ int skip_ver_plane = 0;
+ for (int plane_idx = 0; plane_idx < AOMMAX(1, (num_planes - 1));
+ ++plane_idx) {
+ struct macroblockd_plane *const pd = &xd->plane[plane_idx];
+ const int bw = pd->width;
+ const int bh = pd->height;
+ const MV mv_q4 = clamp_mv_to_umv_border_sb(
+ xd, &mv, bw, bh, pd->subsampling_x, pd->subsampling_y);
+ const int sub_x = (mv_q4.col & SUBPEL_MASK) << SCALE_EXTRA_BITS;
+ const int sub_y = (mv_q4.row & SUBPEL_MASK) << SCALE_EXTRA_BITS;
+ skip_hor_plane |= ((sub_x == 0) << plane_idx);
+ skip_ver_plane |= ((sub_y == 0) << plane_idx);
+ }
+ *skip_hor &= skip_hor_plane;
+ *skip_ver &= skip_ver_plane;
+ // It is not valid that "luma MV is sub-pel, whereas chroma MV is not"
+ assert(*skip_hor != 2);
+ assert(*skip_ver != 2);
+ }
+ // When compond prediction type is compound segment wedge, luma MC and chroma
+ // MC need to go hand in hand as mask generated during luma MC is reuired for
+ // chroma MC. If skip_hor = 0 and skip_ver = 1, mask used for chroma MC during
+ // vertical filter decision may be incorrect as temporary MC evaluation
+ // overwrites the mask. Make skip_ver as 0 for this case so that mask is
+ // populated during luma MC
+ if (is_compound && mbmi->compound_idx == 1 &&
+ mbmi->interinter_comp.type == COMPOUND_DIFFWTD) {
+ assert(mbmi->comp_group_idx == 1);
+ if (*skip_hor == 0 && *skip_ver == 1) *skip_ver = 0;
+ }
+}
+
+int64_t interpolation_filter_search(
+ MACROBLOCK *const x, const AV1_COMP *const cpi,
+ const TileDataEnc *tile_data, BLOCK_SIZE bsize,
+ const BUFFER_SET *const tmp_dst, const BUFFER_SET *const orig_dst,
+ int64_t *const rd, int *const switchable_rate, int *skip_build_pred,
+ HandleInterModeArgs *args, int64_t ref_best_rd) {
+ const AV1_COMMON *cm = &cpi->common;
+ const int num_planes = av1_num_planes(cm);
+ MACROBLOCKD *const xd = &x->e_mbd;
+ MB_MODE_INFO *const mbmi = xd->mi[0];
+ const int need_search =
+ av1_is_interp_needed(xd) && !cpi->sf.rt_sf.skip_interp_filter_search;
+ const int ref_frame = xd->mi[0]->ref_frame[0];
+ RD_STATS rd_stats_luma, rd_stats;
+
+ // Initialization of rd_stats structures with default values
+ av1_init_rd_stats(&rd_stats_luma);
+ av1_init_rd_stats(&rd_stats);
+
+ int match_found_idx = -1;
+ const InterpFilter assign_filter = cm->interp_filter;
+
+ match_found_idx = find_interp_filter_match(
+ mbmi, cpi, assign_filter, need_search, args->interp_filter_stats,
+ args->interp_filter_stats_idx);
+
+ if (match_found_idx != -1) {
+ *rd = args->interp_filter_stats[match_found_idx].rd;
+ x->pred_sse[ref_frame] =
+ args->interp_filter_stats[match_found_idx].pred_sse;
+ return 0;
+ }
+
+ int switchable_ctx[2];
+ switchable_ctx[0] = av1_get_pred_context_switchable_interp(xd, 0);
+ switchable_ctx[1] = av1_get_pred_context_switchable_interp(xd, 1);
+ *switchable_rate =
+ get_switchable_rate(x, mbmi->interp_filters, switchable_ctx);
+
+ // Do MC evaluation for default filter_type.
+ // Luma MC
+ interp_model_rd_eval(x, cpi, bsize, orig_dst, AOM_PLANE_Y, AOM_PLANE_Y,
+ &rd_stats_luma, *skip_build_pred);
+
+#if CONFIG_COLLECT_RD_STATS == 3
+ RD_STATS rd_stats_y;
+ pick_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize, INT64_MAX);
+ PrintPredictionUnitStats(cpi, tile_data, x, &rd_stats_y, bsize);
+#endif // CONFIG_COLLECT_RD_STATS == 3
+ // Chroma MC
+ if (num_planes > 1) {
+ interp_model_rd_eval(x, cpi, bsize, orig_dst, AOM_PLANE_U, AOM_PLANE_V,
+ &rd_stats, *skip_build_pred);
+ }
+ *skip_build_pred = 1;
+
+ av1_merge_rd_stats(&rd_stats, &rd_stats_luma);
+
+ assert(rd_stats.rate >= 0);
+
+ *rd = RDCOST(x->rdmult, *switchable_rate + rd_stats.rate, rd_stats.dist);
+ x->pred_sse[ref_frame] = (unsigned int)(rd_stats_luma.sse >> 4);
+
+ if (assign_filter != SWITCHABLE || match_found_idx != -1) {
+ return 0;
+ }
+ if (!need_search) {
+ int_interpfilters filters = av1_broadcast_interp_filter(EIGHTTAP_REGULAR);
+ assert(mbmi->interp_filters.as_int == filters.as_int);
+ (void)filters;
+ return 0;
+ }
+ if (args->modelled_rd != NULL) {
+ if (has_second_ref(mbmi)) {
+ const int ref_mv_idx = mbmi->ref_mv_idx;
+ MV_REFERENCE_FRAME *refs = mbmi->ref_frame;
+ const int mode0 = compound_ref0_mode(mbmi->mode);
+ const int mode1 = compound_ref1_mode(mbmi->mode);
+ const int64_t mrd = AOMMIN(args->modelled_rd[mode0][ref_mv_idx][refs[0]],
+ args->modelled_rd[mode1][ref_mv_idx][refs[1]]);
+ if ((*rd >> 1) > mrd && ref_best_rd < INT64_MAX) {
+ return INT64_MAX;
+ }
+ }
+ }
+
+ x->recalc_luma_mc_data = 0;
+ // skip_flag=xx (in binary form)
+ // 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=3 corresponds to "Skip both luma and chroma MC"
+ int skip_hor = cpi->default_interp_skip_flags;
+ int skip_ver = cpi->default_interp_skip_flags;
+ calc_interp_skip_pred_flag(x, cpi, &skip_hor, &skip_ver);
+
+ // do interp_filter search
+ restore_dst_buf(xd, *tmp_dst, num_planes);
+ const BUFFER_SET *dst_bufs[2] = { tmp_dst, orig_dst };
+ // Evaluate dual interp filters
+ if (cm->seq_params.enable_dual_filter) {
+ if (cpi->sf.interp_sf.use_fast_interpolation_filter_search) {
+ fast_dual_interp_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
+ &rd_stats_luma, &rd_stats, switchable_rate,
+ dst_bufs, switchable_ctx, skip_hor, skip_ver);
+ } else {
+ // Use full interpolation filter search
+ uint16_t allowed_interp_mask = ALLOW_ALL_INTERP_FILT_MASK;
+ // REG_REG filter type is evaluated beforehand, so loop is repeated over
+ // REG_SMOOTH to SHARP_SHARP for full interpolation filter search
+ reset_interp_filter_allowed_mask(&allowed_interp_mask, REG_REG);
+ find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd,
+ &rd_stats_luma, &rd_stats, switchable_rate,
+ dst_bufs, switchable_ctx,
+ (skip_hor & skip_ver), allowed_interp_mask, 0);
+ }
+ } else {
+ // Evaluate non-dual interp filters
+ find_best_non_dual_interp_filter(
+ x, cpi, tile_data, bsize, orig_dst, rd, &rd_stats_luma, &rd_stats,
+ switchable_rate, dst_bufs, switchable_ctx, skip_ver, skip_hor);
+ }
+ swap_dst_buf(xd, dst_bufs, num_planes);
+ // Recompute final MC data if required
+ if (x->recalc_luma_mc_data == 1) {
+ // Recomputing final luma MC data is required only if the same was skipped
+ // in either of the directions Condition below is necessary, but not
+ // sufficient
+ assert((skip_hor == 1) || (skip_ver == 1));
+ const int mi_row = xd->mi_row;
+ const int mi_col = xd->mi_col;
+ av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize,
+ AOM_PLANE_Y, AOM_PLANE_Y);
+ }
+ x->pred_sse[ref_frame] = (unsigned int)(rd_stats_luma.sse >> 4);
+
+ // save search results
+ if (cpi->sf.interp_sf.use_interp_filter) {
+ assert(match_found_idx == -1);
+ args->interp_filter_stats_idx = save_interp_filter_search_stat(
+ mbmi, *rd, x->pred_sse[ref_frame], args->interp_filter_stats,
+ args->interp_filter_stats_idx);
+ }
+ return 0;
+}
diff --git a/av1/encoder/interp_search.h b/av1/encoder/interp_search.h
new file mode 100644
index 0000000..63eec8c
--- /dev/null
+++ b/av1/encoder/interp_search.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2020, Alliance for Open Media. All rights reserved
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#ifndef AOM_AV1_ENCODER_INTERP_FILTER_SEARCH_H_
+#define AOM_AV1_ENCODER_INTERP_FILTER_SEARCH_H_
+
+#include "av1/encoder/block.h"
+#include "av1/encoder/encoder.h"
+#include "av1/encoder/rdopt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_INTERP_FILTER_STATS 128
+#define DUAL_FILTER_SET_SIZE (SWITCHABLE_FILTERS * SWITCHABLE_FILTERS)
+
+typedef struct {
+ int_interpfilters filters;
+ int_mv mv[2];
+ int8_t ref_frames[2];
+ COMPOUND_TYPE comp_type;
+ int compound_idx;
+ int64_t rd;
+ unsigned int pred_sse;
+} INTERPOLATION_FILTER_STATS;
+
+typedef struct {
+ // OBMC secondary prediction buffers and respective strides
+ uint8_t *above_pred_buf[MAX_MB_PLANE];
+ int above_pred_stride[MAX_MB_PLANE];
+ uint8_t *left_pred_buf[MAX_MB_PLANE];
+ int left_pred_stride[MAX_MB_PLANE];
+ int_mv (*single_newmv)[REF_FRAMES];
+ // Pointer to array of motion vectors to use for each ref and their rates
+ // Should point to first of 2 arrays in 2D array
+ int (*single_newmv_rate)[REF_FRAMES];
+ int (*single_newmv_valid)[REF_FRAMES];
+ // Pointer to array of predicted rate-distortion
+ // Should point to first of 2 arrays in 2D array
+ int64_t (*modelled_rd)[MAX_REF_MV_SEARCH][REF_FRAMES];
+ int ref_frame_cost;
+ int single_comp_cost;
+ int64_t (*simple_rd)[MAX_REF_MV_SEARCH][REF_FRAMES];
+ int skip_motion_mode;
+ INTERINTRA_MODE *inter_intra_mode;
+ int single_ref_first_pass;
+ SimpleRDState *simple_rd_state;
+ // [comp_idx][saved stat_idx]
+ INTERPOLATION_FILTER_STATS interp_filter_stats[MAX_INTERP_FILTER_STATS];
+ int interp_filter_stats_idx;
+} HandleInterModeArgs;
+
+static const int_interpfilters filter_sets[DUAL_FILTER_SET_SIZE] = {
+ { 0x00000000 }, { 0x00010000 }, { 0x00020000 }, // y = 0
+ { 0x00000001 }, { 0x00010001 }, { 0x00020001 }, // y = 1
+ { 0x00000002 }, { 0x00010002 }, { 0x00020002 }, // y = 2
+};
+
+int find_interp_filter_match(MB_MODE_INFO *const mbmi,
+ const AV1_COMP *const cpi,
+ const InterpFilter assign_filter,
+ const int need_search,
+ INTERPOLATION_FILTER_STATS *interp_filter_stats,
+ int interp_filter_stats_idx);
+
+int64_t interpolation_filter_search(
+ MACROBLOCK *const x, const AV1_COMP *const cpi,
+ const TileDataEnc *tile_data, BLOCK_SIZE bsize,
+ const BUFFER_SET *const tmp_dst, const BUFFER_SET *const orig_dst,
+ int64_t *const rd, int *const switchable_rate, int *skip_build_pred,
+ HandleInterModeArgs *args, int64_t ref_best_rd);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // AOM_AV1_ENCODER_INTERP_FILTER_SEARCH_H_
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index 972a5df..96738e9 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -49,6 +49,7 @@
#include "av1/encoder/encoder.h"
#include "av1/encoder/encodetxb.h"
#include "av1/encoder/hybrid_fwd_txfm.h"
+#include "av1/encoder/interp_search.h"
#include "av1/encoder/mcomp.h"
#include "av1/encoder/ml.h"
#include "av1/encoder/mode_prune_model_weights.h"
@@ -72,13 +73,6 @@
static const char av1_tx_size_data_output_file[] = "tx_size_data.txt";
#endif
-#define DUAL_FILTER_SET_SIZE (SWITCHABLE_FILTERS * SWITCHABLE_FILTERS)
-static const int_interpfilters filter_sets[DUAL_FILTER_SET_SIZE] = {
- { 0x00000000 }, { 0x00010000 }, { 0x00020000 }, // y = 0
- { 0x00000001 }, { 0x00010001 }, { 0x00020001 }, // y = 1
- { 0x00000002 }, { 0x00010002 }, { 0x00020002 }, // y = 2
-};
-
typedef struct {
PREDICTION_MODE mode;
MV_REFERENCE_FRAME ref_frame[2];
@@ -7989,43 +7983,6 @@
return rd;
}
-#define MAX_INTERP_FILTER_STATS 128
-typedef struct {
- int_interpfilters filters;
- int_mv mv[2];
- int8_t ref_frames[2];
- COMPOUND_TYPE comp_type;
- int compound_idx;
- int64_t rd;
- unsigned int pred_sse;
-} INTERPOLATION_FILTER_STATS;
-
-typedef struct {
- // OBMC secondary prediction buffers and respective strides
- uint8_t *above_pred_buf[MAX_MB_PLANE];
- int above_pred_stride[MAX_MB_PLANE];
- uint8_t *left_pred_buf[MAX_MB_PLANE];
- int left_pred_stride[MAX_MB_PLANE];
- int_mv (*single_newmv)[REF_FRAMES];
- // Pointer to array of motion vectors to use for each ref and their rates
- // Should point to first of 2 arrays in 2D array
- int (*single_newmv_rate)[REF_FRAMES];
- int (*single_newmv_valid)[REF_FRAMES];
- // Pointer to array of predicted rate-distortion
- // Should point to first of 2 arrays in 2D array
- int64_t (*modelled_rd)[MAX_REF_MV_SEARCH][REF_FRAMES];
- int ref_frame_cost;
- int single_comp_cost;
- int64_t (*simple_rd)[MAX_REF_MV_SEARCH][REF_FRAMES];
- int skip_motion_mode;
- INTERINTRA_MODE *inter_intra_mode;
- int single_ref_first_pass;
- SimpleRDState *simple_rd_state;
- // [comp_idx][saved stat_idx]
- INTERPOLATION_FILTER_STATS interp_filter_stats[MAX_INTERP_FILTER_STATS];
- int interp_filter_stats_idx;
-} HandleInterModeArgs;
-
/* If the current mode shares the same mv with other modes with higher cost,
* skip this mode. */
static int skip_repeated_mv(const AV1_COMMON *const cm,
@@ -8195,464 +8152,6 @@
return 0;
}
-static INLINE void swap_dst_buf(MACROBLOCKD *xd, const BUFFER_SET *dst_bufs[2],
- int num_planes) {
- const BUFFER_SET *buf0 = dst_bufs[0];
- dst_bufs[0] = dst_bufs[1];
- dst_bufs[1] = buf0;
- restore_dst_buf(xd, *dst_bufs[0], num_planes);
-}
-
-static INLINE int get_switchable_rate(MACROBLOCK *const x,
- const int_interpfilters filters,
- const int ctx[2]) {
- int inter_filter_cost;
- const InterpFilter filter0 = filters.as_filters.y_filter;
- const InterpFilter filter1 = filters.as_filters.x_filter;
- inter_filter_cost = x->switchable_interp_costs[ctx[0]][filter0];
- inter_filter_cost += x->switchable_interp_costs[ctx[1]][filter1];
- return SWITCHABLE_INTERP_RATE_FACTOR * inter_filter_cost;
-}
-
-// Build inter predictor and calculate model rd
-// for a given plane.
-static INLINE void interp_model_rd_eval(
- MACROBLOCK *const x, const AV1_COMP *const cpi, BLOCK_SIZE bsize,
- const BUFFER_SET *const orig_dst, int plane_from, int plane_to,
- RD_STATS *rd_stats, int is_skip_build_pred) {
- const AV1_COMMON *cm = &cpi->common;
- MACROBLOCKD *const xd = &x->e_mbd;
- RD_STATS tmp_rd_stats;
- av1_init_rd_stats(&tmp_rd_stats);
-
- // Skip inter predictor if the predictor is already avilable.
- if (!is_skip_build_pred) {
- const int mi_row = xd->mi_row;
- const int mi_col = xd->mi_col;
- av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize,
- plane_from, plane_to);
- }
-
- model_rd_sb_fn[cpi->sf.rt_sf.use_simple_rd_model
- ? MODELRD_LEGACY
- : MODELRD_TYPE_INTERP_FILTER](
- cpi, bsize, x, xd, plane_from, plane_to, &tmp_rd_stats.rate,
- &tmp_rd_stats.dist, &tmp_rd_stats.skip, &tmp_rd_stats.sse, NULL, NULL,
- NULL);
-
- av1_merge_rd_stats(rd_stats, &tmp_rd_stats);
-}
-
-// calculate the rdcost of given interpolation_filter
-static INLINE int64_t interpolation_filter_rd(
- MACROBLOCK *const x, const AV1_COMP *const cpi,
- const TileDataEnc *tile_data, BLOCK_SIZE bsize,
- const BUFFER_SET *const orig_dst, int64_t *const rd,
- RD_STATS *rd_stats_luma, RD_STATS *rd_stats, int *const switchable_rate,
- const BUFFER_SET *dst_bufs[2], int filter_idx, const int switchable_ctx[2],
- const int skip_pred) {
- const AV1_COMMON *cm = &cpi->common;
- const int num_planes = av1_num_planes(cm);
- MACROBLOCKD *const xd = &x->e_mbd;
- MB_MODE_INFO *const mbmi = xd->mi[0];
- RD_STATS this_rd_stats_luma, this_rd_stats;
-
- // Initialize rd_stats structures to default values.
- av1_init_rd_stats(&this_rd_stats_luma);
- this_rd_stats = *rd_stats_luma;
- const int_interpfilters last_best = mbmi->interp_filters;
- mbmi->interp_filters = filter_sets[filter_idx];
- const int tmp_rs =
- get_switchable_rate(x, mbmi->interp_filters, switchable_ctx);
-
- int64_t min_rd = RDCOST(x->rdmult, tmp_rs, 0);
- if (min_rd > *rd) {
- mbmi->interp_filters = last_best;
- return 0;
- }
-
- (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));
- assert((rd_stats_luma->skip == 0) || (rd_stats_luma->skip == 1));
- assert((rd_stats->skip == 0) || (rd_stats->skip == 1));
- assert((skip_pred >= 0) && (skip_pred <= cpi->default_interp_skip_flags));
-
- // When skip pred is equal to default_interp_skip_flags,
- // skip both luma and chroma MC.
- // For mono-chrome images:
- // num_planes = 1 and cpi->default_interp_skip_flags = 1,
- // skip_pred = 1: skip both luma and chroma
- // skip_pred = 0: Evaluate luma and as num_planes=1,
- // skip chroma evaluation
- int tmp_skip_pred = (skip_pred == cpi->default_interp_skip_flags)
- ? INTERP_SKIP_LUMA_SKIP_CHROMA
- : skip_pred;
-
- switch (tmp_skip_pred) {
- case INTERP_EVAL_LUMA_EVAL_CHROMA:
- // skip_pred = 0: Evaluate both luma and chroma.
- // Luma MC
- 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;
-#if CONFIG_COLLECT_RD_STATS == 3
- RD_STATS rd_stats_y;
- pick_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize, 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.
- 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);
- if (tmp_rd >= *rd) {
- mbmi->interp_filters = last_best;
- return 0;
- }
- 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);
-
- if (tmp_rd < *rd) {
- *rd = tmp_rd;
- *switchable_rate = tmp_rs;
- if (skip_pred != cpi->default_interp_skip_flags) {
- if (skip_pred == INTERP_EVAL_LUMA_EVAL_CHROMA) {
- // Overwrite the data as current filter is the best one
- *rd_stats_luma = this_rd_stats_luma;
- *rd_stats = this_rd_stats;
- // As luma MC data is computed, no need to recompute after the search
- x->recalc_luma_mc_data = 0;
- } else if (skip_pred == INTERP_SKIP_LUMA_EVAL_CHROMA) {
- // As luma MC data is not computed, update of luma data can be skipped
- *rd_stats = this_rd_stats;
- // As luma MC data is not recomputed and current filter is the best,
- // indicate the possibility of recomputing MC data
- // If current buffer contains valid MC data, toggle to indicate that
- // luma MC data needs to be recomputed
- x->recalc_luma_mc_data ^= 1;
- }
- swap_dst_buf(xd, dst_bufs, num_planes);
- }
- return 1;
- }
- mbmi->interp_filters = last_best;
- return 0;
-}
-
-static INLINE INTERP_PRED_TYPE is_pred_filter_search_allowed(
- const AV1_COMP *const cpi, MACROBLOCKD *xd, BLOCK_SIZE bsize,
- int_interpfilters *af, int_interpfilters *lf) {
- const AV1_COMMON *cm = &cpi->common;
- const MB_MODE_INFO *const above_mbmi = xd->above_mbmi;
- const MB_MODE_INFO *const left_mbmi = xd->left_mbmi;
- const int bsl = mi_size_wide_log2[bsize];
- int is_horiz_eq = 0, is_vert_eq = 0;
-
- if (above_mbmi && is_inter_block(above_mbmi))
- *af = above_mbmi->interp_filters;
-
- if (left_mbmi && is_inter_block(left_mbmi)) *lf = left_mbmi->interp_filters;
-
- if (af->as_filters.x_filter != INTERP_INVALID)
- is_horiz_eq = af->as_filters.x_filter == lf->as_filters.x_filter;
- if (af->as_filters.y_filter != INTERP_INVALID)
- is_vert_eq = af->as_filters.y_filter == lf->as_filters.y_filter;
-
- INTERP_PRED_TYPE pred_filter_type = (is_vert_eq << 1) + is_horiz_eq;
- const int mi_row = xd->mi_row;
- const int mi_col = xd->mi_col;
- int pred_filter_enable =
- cpi->sf.interp_sf.cb_pred_filter_search
- ? (((mi_row + mi_col) >> bsl) +
- get_chessboard_index(cm->current_frame.frame_number)) &
- 0x1
- : 0;
- pred_filter_enable &= is_horiz_eq || is_vert_eq;
- // pred_filter_search = 0: pred_filter is disabled
- // pred_filter_search = 1: pred_filter is enabled and only horz pred matching
- // pred_filter_search = 2: pred_filter is enabled and only vert pred matching
- // pred_filter_search = 3: pred_filter is enabled and
- // both vert, horz pred matching
- return pred_filter_enable * pred_filter_type;
-}
-
-static DUAL_FILTER_TYPE find_best_interp_rd_facade(
- MACROBLOCK *const x, const AV1_COMP *const cpi,
- const TileDataEnc *tile_data, BLOCK_SIZE bsize,
- const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y,
- RD_STATS *rd_stats, int *const switchable_rate,
- const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2],
- const int skip_pred, uint16_t allow_interp_mask, int is_w4_or_h4) {
- int tmp_skip_pred = skip_pred;
- DUAL_FILTER_TYPE best_filt_type = REG_REG;
-
- // If no filter are set to be evaluated, return from function
- if (allow_interp_mask == 0x0) return best_filt_type;
- // For block width or height is 4, skip the pred evaluation of SHARP_SHARP
- tmp_skip_pred = is_w4_or_h4 ? cpi->default_interp_skip_flags : skip_pred;
-
- // Loop over the all filter types and evaluate for only allowed filter types
- for (int filt_type = SHARP_SHARP; filt_type >= REG_REG; --filt_type) {
- const int is_filter_allowed =
- get_interp_filter_allowed_mask(allow_interp_mask, filt_type);
- if (is_filter_allowed)
- if (interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
- rd_stats_y, rd_stats, switchable_rate,
- dst_bufs, filt_type, switchable_ctx,
- tmp_skip_pred))
- best_filt_type = filt_type;
- tmp_skip_pred = skip_pred;
- }
- return best_filt_type;
-}
-
-static INLINE void pred_dual_interp_filter_rd(
- MACROBLOCK *const x, const AV1_COMP *const cpi,
- const TileDataEnc *tile_data, BLOCK_SIZE bsize,
- const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y,
- RD_STATS *rd_stats, int *const switchable_rate,
- const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2],
- const int skip_pred, INTERP_PRED_TYPE pred_filt_type, int_interpfilters *af,
- int_interpfilters *lf) {
- (void)lf;
- assert(pred_filt_type > INTERP_HORZ_NEQ_VERT_NEQ);
- assert(pred_filt_type < INTERP_PRED_TYPE_ALL);
- uint16_t allowed_interp_mask = 0;
-
- if (pred_filt_type == INTERP_HORZ_EQ_VERT_NEQ) {
- // pred_filter_search = 1: Only horizontal filter is matching
- allowed_interp_mask =
- av1_interp_dual_filt_mask[pred_filt_type - 1][af->as_filters.x_filter];
- } else if (pred_filt_type == INTERP_HORZ_NEQ_VERT_EQ) {
- // pred_filter_search = 2: Only vertical filter is matching
- allowed_interp_mask =
- av1_interp_dual_filt_mask[pred_filt_type - 1][af->as_filters.y_filter];
- } else {
- // pred_filter_search = 3: Both horizontal and vertical filter are matching
- int filt_type =
- af->as_filters.x_filter + af->as_filters.y_filter * SWITCHABLE_FILTERS;
- set_interp_filter_allowed_mask(&allowed_interp_mask, filt_type);
- }
- // REG_REG is already been evaluated in the beginning
- reset_interp_filter_allowed_mask(&allowed_interp_mask, REG_REG);
- find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd, rd_stats_y,
- rd_stats, switchable_rate, dst_bufs,
- switchable_ctx, skip_pred, allowed_interp_mask, 0);
-}
-// Evaluate dual filter type
-// a) Using above, left block interp filter
-// b) Find the best horizontal filter and
-// then evaluate corresponding vertical filters.
-static INLINE void fast_dual_interp_filter_rd(
- MACROBLOCK *const x, const AV1_COMP *const cpi,
- const TileDataEnc *tile_data, BLOCK_SIZE bsize,
- const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y,
- RD_STATS *rd_stats, int *const switchable_rate,
- const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2],
- const int skip_hor, const int skip_ver) {
- MACROBLOCKD *const xd = &x->e_mbd;
- MB_MODE_INFO *const mbmi = xd->mi[0];
- INTERP_PRED_TYPE pred_filter_type = INTERP_HORZ_NEQ_VERT_NEQ;
- int_interpfilters af = av1_broadcast_interp_filter(INTERP_INVALID);
- int_interpfilters lf = af;
-
- if (!have_newmv_in_inter_mode(mbmi->mode)) {
- pred_filter_type = is_pred_filter_search_allowed(cpi, xd, bsize, &af, &lf);
- }
-
- if (pred_filter_type) {
- pred_dual_interp_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
- rd_stats_y, rd_stats, switchable_rate, dst_bufs,
- switchable_ctx, (skip_hor & skip_ver),
- pred_filter_type, &af, &lf);
- } else {
- const int bw = block_size_wide[bsize];
- const int bh = block_size_high[bsize];
- int best_dual_mode = 0;
- int skip_pred = bw <= 4 ? cpi->default_interp_skip_flags : skip_hor;
- // TODO(any): Make use of find_best_interp_rd_facade()
- // if speed impact is negligible
- for (int i = (SWITCHABLE_FILTERS - 1); i >= 1; --i) {
- if (interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
- rd_stats_y, rd_stats, switchable_rate,
- dst_bufs, i, switchable_ctx, skip_pred)) {
- best_dual_mode = i;
- }
- skip_pred = skip_hor;
- }
- // From best of horizontal EIGHTTAP_REGULAR modes, check vertical modes
- skip_pred = bh <= 4 ? cpi->default_interp_skip_flags : skip_ver;
- for (int i = (best_dual_mode + (SWITCHABLE_FILTERS * 2));
- i >= (best_dual_mode + SWITCHABLE_FILTERS); i -= SWITCHABLE_FILTERS) {
- interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
- rd_stats_y, rd_stats, switchable_rate, dst_bufs,
- i, switchable_ctx, skip_pred);
- skip_pred = skip_ver;
- }
- }
-}
-
-// Find the best interp filter if dual_interp_filter = 0
-static INLINE void find_best_non_dual_interp_filter(
- MACROBLOCK *const x, const AV1_COMP *const cpi,
- const TileDataEnc *tile_data, BLOCK_SIZE bsize,
- const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y,
- RD_STATS *rd_stats, int *const switchable_rate,
- const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2],
- const int skip_ver, const int skip_hor) {
- int8_t i;
- MACROBLOCKD *const xd = &x->e_mbd;
- MB_MODE_INFO *const mbmi = xd->mi[0];
-
- uint16_t interp_filter_search_mask = cpi->interp_filter_search_mask;
-
- if (cpi->sf.interp_sf.adaptive_interp_filter_search == 2) {
- const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->gf_group);
- const int ctx0 = av1_get_pred_context_switchable_interp(xd, 0);
- const int ctx1 = av1_get_pred_context_switchable_interp(xd, 1);
- const int *switchable_interp_p0 =
- cpi->switchable_interp_probs[update_type][ctx0];
- const int *switchable_interp_p1 =
- cpi->switchable_interp_probs[update_type][ctx1];
-
- const int thresh = cpi->switchable_interp_thresh[update_type];
- for (i = 0; i < SWITCHABLE_FILTERS; i++) {
- // For non-dual case, the 2 dir's prob should be identical.
- assert(switchable_interp_p0[i] == switchable_interp_p1[i]);
- if (switchable_interp_p0[i] < thresh &&
- switchable_interp_p1[i] < thresh) {
- DUAL_FILTER_TYPE filt_type = i + SWITCHABLE_FILTERS * i;
- reset_interp_filter_allowed_mask(&interp_filter_search_mask, filt_type);
- }
- }
- }
-
- // Regular filter evaluation should have been done and hence the same should
- // be the winner
- assert(x->e_mbd.mi[0]->interp_filters.as_int == filter_sets[0].as_int);
- if ((skip_hor & skip_ver) != cpi->default_interp_skip_flags) {
- INTERP_PRED_TYPE pred_filter_type = INTERP_HORZ_NEQ_VERT_NEQ;
- int_interpfilters af = av1_broadcast_interp_filter(INTERP_INVALID);
- int_interpfilters lf = af;
-
- pred_filter_type = is_pred_filter_search_allowed(cpi, xd, bsize, &af, &lf);
- if (pred_filter_type) {
- assert(af.as_filters.x_filter != INTERP_INVALID);
- int filter_idx = SWITCHABLE * af.as_filters.x_filter;
- // This assert tells that (filter_x == filter_y) for non-dual filter case
- assert(filter_sets[filter_idx].as_filters.x_filter ==
- filter_sets[filter_idx].as_filters.y_filter);
- if (cpi->sf.interp_sf.adaptive_interp_filter_search &&
- !(get_interp_filter_allowed_mask(interp_filter_search_mask,
- filter_idx))) {
- return;
- }
- if (filter_idx) {
- interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
- rd_stats_y, rd_stats, switchable_rate, dst_bufs,
- filter_idx, switchable_ctx,
- (skip_hor & skip_ver));
- }
- return;
- }
- }
- // Reuse regular filter's modeled rd data for sharp filter for following
- // cases
- // 1) When bsize is 4x4
- // 2) When block width is 4 (i.e. 4x8/4x16 blocks) and MV in vertical
- // direction is full-pel
- // 3) When block height is 4 (i.e. 8x4/16x4 blocks) and MV in horizontal
- // direction is full-pel
- // TODO(any): Optimize cases 2 and 3 further if luma MV in relavant direction
- // alone is full-pel
-
- if ((bsize == BLOCK_4X4) ||
- (block_size_wide[bsize] == 4 &&
- skip_ver == cpi->default_interp_skip_flags) ||
- (block_size_high[bsize] == 4 &&
- skip_hor == cpi->default_interp_skip_flags)) {
- int skip_pred = skip_hor & skip_ver;
- uint16_t allowed_interp_mask = 0;
-
- // REG_REG filter type is evaluated beforehand, hence skip it
- set_interp_filter_allowed_mask(&allowed_interp_mask, SHARP_SHARP);
- set_interp_filter_allowed_mask(&allowed_interp_mask, SMOOTH_SMOOTH);
- if (cpi->sf.interp_sf.adaptive_interp_filter_search)
- allowed_interp_mask &= interp_filter_search_mask;
-
- find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd,
- rd_stats_y, rd_stats, switchable_rate, dst_bufs,
- switchable_ctx, skip_pred, allowed_interp_mask,
- 1);
- } else {
- int skip_pred = (skip_hor & skip_ver);
- for (i = (SWITCHABLE_FILTERS + 1); i < DUAL_FILTER_SET_SIZE;
- i += (SWITCHABLE_FILTERS + 1)) {
- // This assert tells that (filter_x == filter_y) for non-dual filter case
- assert(filter_sets[i].as_filters.x_filter ==
- filter_sets[i].as_filters.y_filter);
- if (cpi->sf.interp_sf.adaptive_interp_filter_search &&
- !(get_interp_filter_allowed_mask(interp_filter_search_mask, i))) {
- continue;
- }
- interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
- rd_stats_y, rd_stats, switchable_rate, dst_bufs,
- i, switchable_ctx, skip_pred);
- // In first iteration, smooth filter is evaluated. If smooth filter
- // (which is less sharper) is the winner among regular and smooth filters,
- // sharp filter evaluation is skipped
- // TODO(any): Refine this gating based on modelled rd only (i.e., by not
- // accounting switchable filter rate)
- if (cpi->sf.interp_sf.skip_sharp_interp_filter_search &&
- skip_pred != cpi->default_interp_skip_flags) {
- if (mbmi->interp_filters.as_int == filter_sets[SMOOTH_SMOOTH].as_int)
- break;
- }
- }
- }
-}
-
-// return mv_diff
-static INLINE int is_interp_filter_good_match(
- const INTERPOLATION_FILTER_STATS *st, MB_MODE_INFO *const mi,
- int skip_level) {
- const int is_comp = has_second_ref(mi);
- int i;
-
- for (i = 0; i < 1 + is_comp; ++i) {
- if (st->ref_frames[i] != mi->ref_frame[i]) return INT_MAX;
- }
-
- if (skip_level == 1 && is_comp) {
- if (st->comp_type != mi->interinter_comp.type) return INT_MAX;
- if (st->compound_idx != mi->compound_idx) return INT_MAX;
- }
-
- int mv_diff = 0;
- for (i = 0; i < 1 + is_comp; ++i) {
- mv_diff += abs(st->mv[i].as_mv.row - mi->mv[i].as_mv.row) +
- abs(st->mv[i].as_mv.col - mi->mv[i].as_mv.col);
- }
- return mv_diff;
-}
-
// Checks if characteristics of search match
static INLINE int is_comp_rd_match(const AV1_COMP *const cpi,
const MACROBLOCK *const x,
@@ -8706,37 +8205,6 @@
return 1;
}
-static INLINE int find_interp_filter_in_stats(
- MB_MODE_INFO *const mbmi, INTERPOLATION_FILTER_STATS *interp_filter_stats,
- int interp_filter_stats_idx, int skip_level) {
- // [skip_levels][single or comp]
- const int thr[2][2] = { { 0, 0 }, { 3, 7 } };
- const int is_comp = has_second_ref(mbmi);
-
- // Find good enough match.
- // TODO(yunqing): Separate single-ref mode and comp mode stats for fast
- // search.
- int best = INT_MAX;
- int match = -1;
- for (int j = 0; j < interp_filter_stats_idx; ++j) {
- const INTERPOLATION_FILTER_STATS *st = &interp_filter_stats[j];
- const int mv_diff = is_interp_filter_good_match(st, mbmi, skip_level);
- // Exact match is found.
- if (mv_diff == 0) {
- match = j;
- break;
- } else if (mv_diff < best && mv_diff <= thr[skip_level - 1][is_comp]) {
- best = mv_diff;
- match = j;
- }
- }
-
- if (match != -1) {
- mbmi->interp_filters = interp_filter_stats[match].filters;
- return match;
- }
- return -1; // no match result found
-}
// Checks if similar compound type search case is accounted earlier
// If found, returns relevant rd data
static INLINE int find_comp_rd_in_stats(const AV1_COMP *const cpi,
@@ -8757,25 +8225,6 @@
return 0; // no match result found
}
-static INLINE int save_interp_filter_search_stat(
- MB_MODE_INFO *const mbmi, int64_t rd, unsigned int pred_sse,
- INTERPOLATION_FILTER_STATS *interp_filter_stats,
- int interp_filter_stats_idx) {
- if (interp_filter_stats_idx < MAX_INTERP_FILTER_STATS) {
- INTERPOLATION_FILTER_STATS stat = { mbmi->interp_filters,
- { mbmi->mv[0], mbmi->mv[1] },
- { mbmi->ref_frame[0],
- mbmi->ref_frame[1] },
- mbmi->interinter_comp.type,
- mbmi->compound_idx,
- rd,
- pred_sse };
- interp_filter_stats[interp_filter_stats_idx] = stat;
- interp_filter_stats_idx++;
- }
- return interp_filter_stats_idx;
-}
-
static INLINE void save_comp_rd_search_stat(
MACROBLOCK *x, const MB_MODE_INFO *const mbmi, const int32_t *comp_rate,
const int64_t *comp_dist, const int32_t *comp_model_rate,
@@ -8805,221 +8254,6 @@
}
}
-static INLINE int find_interp_filter_match(
- MB_MODE_INFO *const mbmi, const AV1_COMP *const cpi,
- const InterpFilter assign_filter, const int need_search,
- INTERPOLATION_FILTER_STATS *interp_filter_stats,
- int interp_filter_stats_idx) {
- int match_found_idx = -1;
- if (cpi->sf.interp_sf.use_interp_filter && need_search)
- match_found_idx = find_interp_filter_in_stats(
- mbmi, interp_filter_stats, interp_filter_stats_idx,
- cpi->sf.interp_sf.use_interp_filter);
-
- if (!need_search || match_found_idx == -1)
- set_default_interp_filters(mbmi, assign_filter);
- return match_found_idx;
-}
-
-static INLINE void calc_interp_skip_pred_flag(MACROBLOCK *const x,
- const AV1_COMP *const cpi,
- int *skip_hor, int *skip_ver) {
- const AV1_COMMON *cm = &cpi->common;
- MACROBLOCKD *const xd = &x->e_mbd;
- MB_MODE_INFO *const mbmi = xd->mi[0];
- const int num_planes = av1_num_planes(cm);
- const int is_compound = has_second_ref(mbmi);
- assert(is_intrabc_block(mbmi) == 0);
- for (int ref = 0; ref < 1 + is_compound; ++ref) {
- const struct scale_factors *const sf =
- get_ref_scale_factors_const(cm, mbmi->ref_frame[ref]);
- // TODO(any): Refine skip flag calculation considering scaling
- if (av1_is_scaled(sf)) {
- *skip_hor = 0;
- *skip_ver = 0;
- break;
- }
- const MV mv = mbmi->mv[ref].as_mv;
- int skip_hor_plane = 0;
- int skip_ver_plane = 0;
- for (int plane_idx = 0; plane_idx < AOMMAX(1, (num_planes - 1));
- ++plane_idx) {
- struct macroblockd_plane *const pd = &xd->plane[plane_idx];
- const int bw = pd->width;
- const int bh = pd->height;
- const MV mv_q4 = clamp_mv_to_umv_border_sb(
- xd, &mv, bw, bh, pd->subsampling_x, pd->subsampling_y);
- const int sub_x = (mv_q4.col & SUBPEL_MASK) << SCALE_EXTRA_BITS;
- const int sub_y = (mv_q4.row & SUBPEL_MASK) << SCALE_EXTRA_BITS;
- skip_hor_plane |= ((sub_x == 0) << plane_idx);
- skip_ver_plane |= ((sub_y == 0) << plane_idx);
- }
- *skip_hor &= skip_hor_plane;
- *skip_ver &= skip_ver_plane;
- // It is not valid that "luma MV is sub-pel, whereas chroma MV is not"
- assert(*skip_hor != 2);
- assert(*skip_ver != 2);
- }
- // When compond prediction type is compound segment wedge, luma MC and chroma
- // MC need to go hand in hand as mask generated during luma MC is reuired for
- // chroma MC. If skip_hor = 0 and skip_ver = 1, mask used for chroma MC during
- // vertical filter decision may be incorrect as temporary MC evaluation
- // overwrites the mask. Make skip_ver as 0 for this case so that mask is
- // populated during luma MC
- if (is_compound && mbmi->compound_idx == 1 &&
- mbmi->interinter_comp.type == COMPOUND_DIFFWTD) {
- assert(mbmi->comp_group_idx == 1);
- if (*skip_hor == 0 && *skip_ver == 1) *skip_ver = 0;
- }
-}
-
-static int64_t interpolation_filter_search(
- MACROBLOCK *const x, const AV1_COMP *const cpi,
- const TileDataEnc *tile_data, BLOCK_SIZE bsize,
- const BUFFER_SET *const tmp_dst, const BUFFER_SET *const orig_dst,
- int64_t *const rd, int *const switchable_rate, int *skip_build_pred,
- HandleInterModeArgs *args, int64_t ref_best_rd) {
- const AV1_COMMON *cm = &cpi->common;
- const int num_planes = av1_num_planes(cm);
- MACROBLOCKD *const xd = &x->e_mbd;
- MB_MODE_INFO *const mbmi = xd->mi[0];
- const int need_search =
- av1_is_interp_needed(xd) && !cpi->sf.rt_sf.skip_interp_filter_search;
- const int ref_frame = xd->mi[0]->ref_frame[0];
- RD_STATS rd_stats_luma, rd_stats;
-
- // Initialization of rd_stats structures with default values
- av1_init_rd_stats(&rd_stats_luma);
- av1_init_rd_stats(&rd_stats);
-
- int match_found_idx = -1;
- const InterpFilter assign_filter = cm->interp_filter;
-
- match_found_idx = find_interp_filter_match(
- mbmi, cpi, assign_filter, need_search, args->interp_filter_stats,
- args->interp_filter_stats_idx);
-
- if (match_found_idx != -1) {
- *rd = args->interp_filter_stats[match_found_idx].rd;
- x->pred_sse[ref_frame] =
- args->interp_filter_stats[match_found_idx].pred_sse;
- return 0;
- }
-
- int switchable_ctx[2];
- switchable_ctx[0] = av1_get_pred_context_switchable_interp(xd, 0);
- switchable_ctx[1] = av1_get_pred_context_switchable_interp(xd, 1);
- *switchable_rate =
- get_switchable_rate(x, mbmi->interp_filters, switchable_ctx);
-
- // Do MC evaluation for default filter_type.
- // Luma MC
- interp_model_rd_eval(x, cpi, bsize, orig_dst, AOM_PLANE_Y, AOM_PLANE_Y,
- &rd_stats_luma, *skip_build_pred);
-
-#if CONFIG_COLLECT_RD_STATS == 3
- RD_STATS rd_stats_y;
- pick_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize, INT64_MAX);
- PrintPredictionUnitStats(cpi, tile_data, x, &rd_stats_y, bsize);
-#endif // CONFIG_COLLECT_RD_STATS == 3
- // Chroma MC
- if (num_planes > 1) {
- interp_model_rd_eval(x, cpi, bsize, orig_dst, AOM_PLANE_U, AOM_PLANE_V,
- &rd_stats, *skip_build_pred);
- }
- *skip_build_pred = 1;
-
- av1_merge_rd_stats(&rd_stats, &rd_stats_luma);
-
- assert(rd_stats.rate >= 0);
-
- *rd = RDCOST(x->rdmult, *switchable_rate + rd_stats.rate, rd_stats.dist);
- x->pred_sse[ref_frame] = (unsigned int)(rd_stats_luma.sse >> 4);
-
- if (assign_filter != SWITCHABLE || match_found_idx != -1) {
- return 0;
- }
- if (!need_search) {
- int_interpfilters filters = av1_broadcast_interp_filter(EIGHTTAP_REGULAR);
- assert(mbmi->interp_filters.as_int == filters.as_int);
- (void)filters;
- return 0;
- }
- if (args->modelled_rd != NULL) {
- if (has_second_ref(mbmi)) {
- const int ref_mv_idx = mbmi->ref_mv_idx;
- MV_REFERENCE_FRAME *refs = mbmi->ref_frame;
- const int mode0 = compound_ref0_mode(mbmi->mode);
- const int mode1 = compound_ref1_mode(mbmi->mode);
- const int64_t mrd = AOMMIN(args->modelled_rd[mode0][ref_mv_idx][refs[0]],
- args->modelled_rd[mode1][ref_mv_idx][refs[1]]);
- if ((*rd >> 1) > mrd && ref_best_rd < INT64_MAX) {
- return INT64_MAX;
- }
- }
- }
-
- x->recalc_luma_mc_data = 0;
- // skip_flag=xx (in binary form)
- // 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=3 corresponds to "Skip both luma and chroma MC"
- int skip_hor = cpi->default_interp_skip_flags;
- int skip_ver = cpi->default_interp_skip_flags;
- calc_interp_skip_pred_flag(x, cpi, &skip_hor, &skip_ver);
-
- // do interp_filter search
- restore_dst_buf(xd, *tmp_dst, num_planes);
- const BUFFER_SET *dst_bufs[2] = { tmp_dst, orig_dst };
- // Evaluate dual interp filters
- if (cm->seq_params.enable_dual_filter) {
- if (cpi->sf.interp_sf.use_fast_interpolation_filter_search) {
- fast_dual_interp_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
- &rd_stats_luma, &rd_stats, switchable_rate,
- dst_bufs, switchable_ctx, skip_hor, skip_ver);
- } else {
- // Use full interpolation filter search
- uint16_t allowed_interp_mask = ALLOW_ALL_INTERP_FILT_MASK;
- // REG_REG filter type is evaluated beforehand, so loop is repeated over
- // REG_SMOOTH to SHARP_SHARP for full interpolation filter search
- reset_interp_filter_allowed_mask(&allowed_interp_mask, REG_REG);
- find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd,
- &rd_stats_luma, &rd_stats, switchable_rate,
- dst_bufs, switchable_ctx,
- (skip_hor & skip_ver), allowed_interp_mask, 0);
- }
- } else {
- // Evaluate non-dual interp filters
- find_best_non_dual_interp_filter(
- x, cpi, tile_data, bsize, orig_dst, rd, &rd_stats_luma, &rd_stats,
- switchable_rate, dst_bufs, switchable_ctx, skip_ver, skip_hor);
- }
- swap_dst_buf(xd, dst_bufs, num_planes);
- // Recompute final MC data if required
- if (x->recalc_luma_mc_data == 1) {
- // Recomputing final luma MC data is required only if the same was skipped
- // in either of the directions Condition below is necessary, but not
- // sufficient
- assert((skip_hor == 1) || (skip_ver == 1));
- const int mi_row = xd->mi_row;
- const int mi_col = xd->mi_col;
- av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize,
- AOM_PLANE_Y, AOM_PLANE_Y);
- }
- x->pred_sse[ref_frame] = (unsigned int)(rd_stats_luma.sse >> 4);
-
- // save search results
- if (cpi->sf.interp_sf.use_interp_filter) {
- assert(match_found_idx == -1);
- args->interp_filter_stats_idx = save_interp_filter_search_stat(
- mbmi, *rd, x->pred_sse[ref_frame], args->interp_filter_stats,
- args->interp_filter_stats_idx);
- }
- return 0;
-}
-
static int txfm_search(const AV1_COMP *cpi, const TileDataEnc *tile_data,
MACROBLOCK *x, BLOCK_SIZE bsize, RD_STATS *rd_stats,
RD_STATS *rd_stats_y, RD_STATS *rd_stats_uv,