1*77c1e3ccSAndroid Build Coastguard Worker /*
2*77c1e3ccSAndroid Build Coastguard Worker * Copyright (c) 2020, Alliance for Open Media. All rights reserved.
3*77c1e3ccSAndroid Build Coastguard Worker *
4*77c1e3ccSAndroid Build Coastguard Worker * This source code is subject to the terms of the BSD 2 Clause License and
5*77c1e3ccSAndroid Build Coastguard Worker * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6*77c1e3ccSAndroid Build Coastguard Worker * was not distributed with this source code in the LICENSE file, you can
7*77c1e3ccSAndroid Build Coastguard Worker * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8*77c1e3ccSAndroid Build Coastguard Worker * Media Patent License 1.0 was not distributed with this source code in the
9*77c1e3ccSAndroid Build Coastguard Worker * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10*77c1e3ccSAndroid Build Coastguard Worker */
11*77c1e3ccSAndroid Build Coastguard Worker
12*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/pred_common.h"
13*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/interp_search.h"
14*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/model_rd.h"
15*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/rdopt_utils.h"
16*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/reconinter_enc.h"
17*77c1e3ccSAndroid Build Coastguard Worker
18*77c1e3ccSAndroid Build Coastguard Worker // return mv_diff
is_interp_filter_good_match(const INTERPOLATION_FILTER_STATS * st,MB_MODE_INFO * const mi,int skip_level)19*77c1e3ccSAndroid Build Coastguard Worker static inline int is_interp_filter_good_match(
20*77c1e3ccSAndroid Build Coastguard Worker const INTERPOLATION_FILTER_STATS *st, MB_MODE_INFO *const mi,
21*77c1e3ccSAndroid Build Coastguard Worker int skip_level) {
22*77c1e3ccSAndroid Build Coastguard Worker const int is_comp = has_second_ref(mi);
23*77c1e3ccSAndroid Build Coastguard Worker int i;
24*77c1e3ccSAndroid Build Coastguard Worker
25*77c1e3ccSAndroid Build Coastguard Worker for (i = 0; i < 1 + is_comp; ++i) {
26*77c1e3ccSAndroid Build Coastguard Worker if (st->ref_frames[i] != mi->ref_frame[i]) return INT_MAX;
27*77c1e3ccSAndroid Build Coastguard Worker }
28*77c1e3ccSAndroid Build Coastguard Worker
29*77c1e3ccSAndroid Build Coastguard Worker if (skip_level == 1 && is_comp) {
30*77c1e3ccSAndroid Build Coastguard Worker if (st->comp_type != mi->interinter_comp.type) return INT_MAX;
31*77c1e3ccSAndroid Build Coastguard Worker if (st->compound_idx != mi->compound_idx) return INT_MAX;
32*77c1e3ccSAndroid Build Coastguard Worker }
33*77c1e3ccSAndroid Build Coastguard Worker
34*77c1e3ccSAndroid Build Coastguard Worker int mv_diff = 0;
35*77c1e3ccSAndroid Build Coastguard Worker for (i = 0; i < 1 + is_comp; ++i) {
36*77c1e3ccSAndroid Build Coastguard Worker mv_diff += abs(st->mv[i].as_mv.row - mi->mv[i].as_mv.row) +
37*77c1e3ccSAndroid Build Coastguard Worker abs(st->mv[i].as_mv.col - mi->mv[i].as_mv.col);
38*77c1e3ccSAndroid Build Coastguard Worker }
39*77c1e3ccSAndroid Build Coastguard Worker return mv_diff;
40*77c1e3ccSAndroid Build Coastguard Worker }
41*77c1e3ccSAndroid Build Coastguard Worker
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)42*77c1e3ccSAndroid Build Coastguard Worker static inline int save_interp_filter_search_stat(
43*77c1e3ccSAndroid Build Coastguard Worker MB_MODE_INFO *const mbmi, int64_t rd, unsigned int pred_sse,
44*77c1e3ccSAndroid Build Coastguard Worker INTERPOLATION_FILTER_STATS *interp_filter_stats,
45*77c1e3ccSAndroid Build Coastguard Worker int interp_filter_stats_idx) {
46*77c1e3ccSAndroid Build Coastguard Worker if (interp_filter_stats_idx < MAX_INTERP_FILTER_STATS) {
47*77c1e3ccSAndroid Build Coastguard Worker INTERPOLATION_FILTER_STATS stat = { mbmi->interp_filters,
48*77c1e3ccSAndroid Build Coastguard Worker { mbmi->mv[0], mbmi->mv[1] },
49*77c1e3ccSAndroid Build Coastguard Worker { mbmi->ref_frame[0],
50*77c1e3ccSAndroid Build Coastguard Worker mbmi->ref_frame[1] },
51*77c1e3ccSAndroid Build Coastguard Worker mbmi->interinter_comp.type,
52*77c1e3ccSAndroid Build Coastguard Worker mbmi->compound_idx,
53*77c1e3ccSAndroid Build Coastguard Worker rd,
54*77c1e3ccSAndroid Build Coastguard Worker pred_sse };
55*77c1e3ccSAndroid Build Coastguard Worker interp_filter_stats[interp_filter_stats_idx] = stat;
56*77c1e3ccSAndroid Build Coastguard Worker interp_filter_stats_idx++;
57*77c1e3ccSAndroid Build Coastguard Worker }
58*77c1e3ccSAndroid Build Coastguard Worker return interp_filter_stats_idx;
59*77c1e3ccSAndroid Build Coastguard Worker }
60*77c1e3ccSAndroid Build Coastguard Worker
find_interp_filter_in_stats(MB_MODE_INFO * const mbmi,INTERPOLATION_FILTER_STATS * interp_filter_stats,int interp_filter_stats_idx,int skip_level)61*77c1e3ccSAndroid Build Coastguard Worker static inline int find_interp_filter_in_stats(
62*77c1e3ccSAndroid Build Coastguard Worker MB_MODE_INFO *const mbmi, INTERPOLATION_FILTER_STATS *interp_filter_stats,
63*77c1e3ccSAndroid Build Coastguard Worker int interp_filter_stats_idx, int skip_level) {
64*77c1e3ccSAndroid Build Coastguard Worker // [skip_levels][single or comp]
65*77c1e3ccSAndroid Build Coastguard Worker const int thr[2][2] = { { 0, 0 }, { 3, 7 } };
66*77c1e3ccSAndroid Build Coastguard Worker const int is_comp = has_second_ref(mbmi);
67*77c1e3ccSAndroid Build Coastguard Worker
68*77c1e3ccSAndroid Build Coastguard Worker // Find good enough match.
69*77c1e3ccSAndroid Build Coastguard Worker // TODO(yunqing): Separate single-ref mode and comp mode stats for fast
70*77c1e3ccSAndroid Build Coastguard Worker // search.
71*77c1e3ccSAndroid Build Coastguard Worker int best = INT_MAX;
72*77c1e3ccSAndroid Build Coastguard Worker int match = -1;
73*77c1e3ccSAndroid Build Coastguard Worker for (int j = 0; j < interp_filter_stats_idx; ++j) {
74*77c1e3ccSAndroid Build Coastguard Worker const INTERPOLATION_FILTER_STATS *st = &interp_filter_stats[j];
75*77c1e3ccSAndroid Build Coastguard Worker const int mv_diff = is_interp_filter_good_match(st, mbmi, skip_level);
76*77c1e3ccSAndroid Build Coastguard Worker // Exact match is found.
77*77c1e3ccSAndroid Build Coastguard Worker if (mv_diff == 0) {
78*77c1e3ccSAndroid Build Coastguard Worker match = j;
79*77c1e3ccSAndroid Build Coastguard Worker break;
80*77c1e3ccSAndroid Build Coastguard Worker } else if (mv_diff < best && mv_diff <= thr[skip_level - 1][is_comp]) {
81*77c1e3ccSAndroid Build Coastguard Worker best = mv_diff;
82*77c1e3ccSAndroid Build Coastguard Worker match = j;
83*77c1e3ccSAndroid Build Coastguard Worker }
84*77c1e3ccSAndroid Build Coastguard Worker }
85*77c1e3ccSAndroid Build Coastguard Worker
86*77c1e3ccSAndroid Build Coastguard Worker if (match != -1) {
87*77c1e3ccSAndroid Build Coastguard Worker mbmi->interp_filters = interp_filter_stats[match].filters;
88*77c1e3ccSAndroid Build Coastguard Worker return match;
89*77c1e3ccSAndroid Build Coastguard Worker }
90*77c1e3ccSAndroid Build Coastguard Worker return -1; // no match result found
91*77c1e3ccSAndroid Build Coastguard Worker }
92*77c1e3ccSAndroid Build Coastguard Worker
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)93*77c1e3ccSAndroid Build Coastguard Worker static int find_interp_filter_match(
94*77c1e3ccSAndroid Build Coastguard Worker MB_MODE_INFO *const mbmi, const AV1_COMP *const cpi,
95*77c1e3ccSAndroid Build Coastguard Worker const InterpFilter assign_filter, const int need_search,
96*77c1e3ccSAndroid Build Coastguard Worker INTERPOLATION_FILTER_STATS *interp_filter_stats,
97*77c1e3ccSAndroid Build Coastguard Worker int interp_filter_stats_idx) {
98*77c1e3ccSAndroid Build Coastguard Worker int match_found_idx = -1;
99*77c1e3ccSAndroid Build Coastguard Worker if (cpi->sf.interp_sf.use_interp_filter && need_search)
100*77c1e3ccSAndroid Build Coastguard Worker match_found_idx = find_interp_filter_in_stats(
101*77c1e3ccSAndroid Build Coastguard Worker mbmi, interp_filter_stats, interp_filter_stats_idx,
102*77c1e3ccSAndroid Build Coastguard Worker cpi->sf.interp_sf.use_interp_filter);
103*77c1e3ccSAndroid Build Coastguard Worker
104*77c1e3ccSAndroid Build Coastguard Worker if (!need_search || match_found_idx == -1)
105*77c1e3ccSAndroid Build Coastguard Worker set_default_interp_filters(mbmi, assign_filter);
106*77c1e3ccSAndroid Build Coastguard Worker return match_found_idx;
107*77c1e3ccSAndroid Build Coastguard Worker }
108*77c1e3ccSAndroid Build Coastguard Worker
get_switchable_rate(MACROBLOCK * const x,const int_interpfilters filters,const int ctx[2],int dual_filter)109*77c1e3ccSAndroid Build Coastguard Worker static inline int get_switchable_rate(MACROBLOCK *const x,
110*77c1e3ccSAndroid Build Coastguard Worker const int_interpfilters filters,
111*77c1e3ccSAndroid Build Coastguard Worker const int ctx[2], int dual_filter) {
112*77c1e3ccSAndroid Build Coastguard Worker const InterpFilter filter0 = filters.as_filters.y_filter;
113*77c1e3ccSAndroid Build Coastguard Worker int inter_filter_cost =
114*77c1e3ccSAndroid Build Coastguard Worker x->mode_costs.switchable_interp_costs[ctx[0]][filter0];
115*77c1e3ccSAndroid Build Coastguard Worker if (dual_filter) {
116*77c1e3ccSAndroid Build Coastguard Worker const InterpFilter filter1 = filters.as_filters.x_filter;
117*77c1e3ccSAndroid Build Coastguard Worker inter_filter_cost += x->mode_costs.switchable_interp_costs[ctx[1]][filter1];
118*77c1e3ccSAndroid Build Coastguard Worker }
119*77c1e3ccSAndroid Build Coastguard Worker return SWITCHABLE_INTERP_RATE_FACTOR * inter_filter_cost;
120*77c1e3ccSAndroid Build Coastguard Worker }
121*77c1e3ccSAndroid Build Coastguard Worker
122*77c1e3ccSAndroid Build Coastguard Worker // Build inter predictor and calculate model rd
123*77c1e3ccSAndroid Build Coastguard Worker // for a given plane.
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)124*77c1e3ccSAndroid Build Coastguard Worker static inline void interp_model_rd_eval(
125*77c1e3ccSAndroid Build Coastguard Worker MACROBLOCK *const x, const AV1_COMP *const cpi, BLOCK_SIZE bsize,
126*77c1e3ccSAndroid Build Coastguard Worker const BUFFER_SET *const orig_dst, int plane_from, int plane_to,
127*77c1e3ccSAndroid Build Coastguard Worker RD_STATS *rd_stats, int is_skip_build_pred) {
128*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMMON *cm = &cpi->common;
129*77c1e3ccSAndroid Build Coastguard Worker MACROBLOCKD *const xd = &x->e_mbd;
130*77c1e3ccSAndroid Build Coastguard Worker RD_STATS tmp_rd_stats;
131*77c1e3ccSAndroid Build Coastguard Worker av1_init_rd_stats(&tmp_rd_stats);
132*77c1e3ccSAndroid Build Coastguard Worker
133*77c1e3ccSAndroid Build Coastguard Worker // Skip inter predictor if the predictor is already available.
134*77c1e3ccSAndroid Build Coastguard Worker if (!is_skip_build_pred) {
135*77c1e3ccSAndroid Build Coastguard Worker const int mi_row = xd->mi_row;
136*77c1e3ccSAndroid Build Coastguard Worker const int mi_col = xd->mi_col;
137*77c1e3ccSAndroid Build Coastguard Worker av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize,
138*77c1e3ccSAndroid Build Coastguard Worker plane_from, plane_to);
139*77c1e3ccSAndroid Build Coastguard Worker }
140*77c1e3ccSAndroid Build Coastguard Worker
141*77c1e3ccSAndroid Build Coastguard Worker model_rd_sb_fn[cpi->sf.rt_sf.use_simple_rd_model
142*77c1e3ccSAndroid Build Coastguard Worker ? MODELRD_LEGACY
143*77c1e3ccSAndroid Build Coastguard Worker : MODELRD_TYPE_INTERP_FILTER](
144*77c1e3ccSAndroid Build Coastguard Worker cpi, bsize, x, xd, plane_from, plane_to, &tmp_rd_stats.rate,
145*77c1e3ccSAndroid Build Coastguard Worker &tmp_rd_stats.dist, &tmp_rd_stats.skip_txfm, &tmp_rd_stats.sse, NULL,
146*77c1e3ccSAndroid Build Coastguard Worker NULL, NULL);
147*77c1e3ccSAndroid Build Coastguard Worker
148*77c1e3ccSAndroid Build Coastguard Worker av1_merge_rd_stats(rd_stats, &tmp_rd_stats);
149*77c1e3ccSAndroid Build Coastguard Worker }
150*77c1e3ccSAndroid Build Coastguard Worker
151*77c1e3ccSAndroid Build Coastguard Worker // calculate the rdcost of given interpolation_filter
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)152*77c1e3ccSAndroid Build Coastguard Worker static inline int64_t interpolation_filter_rd(
153*77c1e3ccSAndroid Build Coastguard Worker MACROBLOCK *const x, const AV1_COMP *const cpi,
154*77c1e3ccSAndroid Build Coastguard Worker const TileDataEnc *tile_data, BLOCK_SIZE bsize,
155*77c1e3ccSAndroid Build Coastguard Worker const BUFFER_SET *const orig_dst, int64_t *const rd,
156*77c1e3ccSAndroid Build Coastguard Worker RD_STATS *rd_stats_luma, RD_STATS *rd_stats, int *const switchable_rate,
157*77c1e3ccSAndroid Build Coastguard Worker const BUFFER_SET *dst_bufs[2], int filter_idx, const int switchable_ctx[2],
158*77c1e3ccSAndroid Build Coastguard Worker const int skip_pred) {
159*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMMON *cm = &cpi->common;
160*77c1e3ccSAndroid Build Coastguard Worker const InterpSearchFlags *interp_search_flags = &cpi->interp_search_flags;
161*77c1e3ccSAndroid Build Coastguard Worker const int num_planes = av1_num_planes(cm);
162*77c1e3ccSAndroid Build Coastguard Worker MACROBLOCKD *const xd = &x->e_mbd;
163*77c1e3ccSAndroid Build Coastguard Worker MB_MODE_INFO *const mbmi = xd->mi[0];
164*77c1e3ccSAndroid Build Coastguard Worker RD_STATS this_rd_stats_luma, this_rd_stats;
165*77c1e3ccSAndroid Build Coastguard Worker
166*77c1e3ccSAndroid Build Coastguard Worker // Initialize rd_stats structures to default values.
167*77c1e3ccSAndroid Build Coastguard Worker av1_init_rd_stats(&this_rd_stats_luma);
168*77c1e3ccSAndroid Build Coastguard Worker this_rd_stats = *rd_stats_luma;
169*77c1e3ccSAndroid Build Coastguard Worker const int_interpfilters last_best = mbmi->interp_filters;
170*77c1e3ccSAndroid Build Coastguard Worker mbmi->interp_filters = filter_sets[filter_idx];
171*77c1e3ccSAndroid Build Coastguard Worker const int tmp_rs =
172*77c1e3ccSAndroid Build Coastguard Worker get_switchable_rate(x, mbmi->interp_filters, switchable_ctx,
173*77c1e3ccSAndroid Build Coastguard Worker cm->seq_params->enable_dual_filter);
174*77c1e3ccSAndroid Build Coastguard Worker
175*77c1e3ccSAndroid Build Coastguard Worker int64_t min_rd = RDCOST(x->rdmult, tmp_rs, 0);
176*77c1e3ccSAndroid Build Coastguard Worker if (min_rd > *rd) {
177*77c1e3ccSAndroid Build Coastguard Worker mbmi->interp_filters = last_best;
178*77c1e3ccSAndroid Build Coastguard Worker return 0;
179*77c1e3ccSAndroid Build Coastguard Worker }
180*77c1e3ccSAndroid Build Coastguard Worker
181*77c1e3ccSAndroid Build Coastguard Worker (void)tile_data;
182*77c1e3ccSAndroid Build Coastguard Worker
183*77c1e3ccSAndroid Build Coastguard Worker assert(skip_pred != 2);
184*77c1e3ccSAndroid Build Coastguard Worker assert((rd_stats_luma->rate >= 0) && (rd_stats->rate >= 0));
185*77c1e3ccSAndroid Build Coastguard Worker assert((rd_stats_luma->dist >= 0) && (rd_stats->dist >= 0));
186*77c1e3ccSAndroid Build Coastguard Worker assert((rd_stats_luma->sse >= 0) && (rd_stats->sse >= 0));
187*77c1e3ccSAndroid Build Coastguard Worker assert((rd_stats_luma->skip_txfm == 0) || (rd_stats_luma->skip_txfm == 1));
188*77c1e3ccSAndroid Build Coastguard Worker assert((rd_stats->skip_txfm == 0) || (rd_stats->skip_txfm == 1));
189*77c1e3ccSAndroid Build Coastguard Worker assert((skip_pred >= 0) &&
190*77c1e3ccSAndroid Build Coastguard Worker (skip_pred <= interp_search_flags->default_interp_skip_flags));
191*77c1e3ccSAndroid Build Coastguard Worker
192*77c1e3ccSAndroid Build Coastguard Worker // When skip_txfm pred is equal to default_interp_skip_flags,
193*77c1e3ccSAndroid Build Coastguard Worker // skip both luma and chroma MC.
194*77c1e3ccSAndroid Build Coastguard Worker // For mono-chrome images:
195*77c1e3ccSAndroid Build Coastguard Worker // num_planes = 1 and cpi->default_interp_skip_flags = 1,
196*77c1e3ccSAndroid Build Coastguard Worker // skip_pred = 1: skip both luma and chroma
197*77c1e3ccSAndroid Build Coastguard Worker // skip_pred = 0: Evaluate luma and as num_planes=1,
198*77c1e3ccSAndroid Build Coastguard Worker // skip chroma evaluation
199*77c1e3ccSAndroid Build Coastguard Worker int tmp_skip_pred =
200*77c1e3ccSAndroid Build Coastguard Worker (skip_pred == interp_search_flags->default_interp_skip_flags)
201*77c1e3ccSAndroid Build Coastguard Worker ? INTERP_SKIP_LUMA_SKIP_CHROMA
202*77c1e3ccSAndroid Build Coastguard Worker : skip_pred;
203*77c1e3ccSAndroid Build Coastguard Worker
204*77c1e3ccSAndroid Build Coastguard Worker switch (tmp_skip_pred) {
205*77c1e3ccSAndroid Build Coastguard Worker case INTERP_EVAL_LUMA_EVAL_CHROMA:
206*77c1e3ccSAndroid Build Coastguard Worker // skip_pred = 0: Evaluate both luma and chroma.
207*77c1e3ccSAndroid Build Coastguard Worker // Luma MC
208*77c1e3ccSAndroid Build Coastguard Worker interp_model_rd_eval(x, cpi, bsize, orig_dst, AOM_PLANE_Y, AOM_PLANE_Y,
209*77c1e3ccSAndroid Build Coastguard Worker &this_rd_stats_luma, 0);
210*77c1e3ccSAndroid Build Coastguard Worker this_rd_stats = this_rd_stats_luma;
211*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_RD_STATS == 3
212*77c1e3ccSAndroid Build Coastguard Worker RD_STATS rd_stats_y;
213*77c1e3ccSAndroid Build Coastguard Worker av1_pick_recursive_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize,
214*77c1e3ccSAndroid Build Coastguard Worker INT64_MAX);
215*77c1e3ccSAndroid Build Coastguard Worker PrintPredictionUnitStats(cpi, tile_data, x, &rd_stats_y, bsize);
216*77c1e3ccSAndroid Build Coastguard Worker #endif // CONFIG_COLLECT_RD_STATS == 3
217*77c1e3ccSAndroid Build Coastguard Worker AOM_FALLTHROUGH_INTENDED;
218*77c1e3ccSAndroid Build Coastguard Worker case INTERP_SKIP_LUMA_EVAL_CHROMA:
219*77c1e3ccSAndroid Build Coastguard Worker // skip_pred = 1: skip luma evaluation (retain previous best luma stats)
220*77c1e3ccSAndroid Build Coastguard Worker // and do chroma evaluation.
221*77c1e3ccSAndroid Build Coastguard Worker for (int plane = 1; plane < num_planes; ++plane) {
222*77c1e3ccSAndroid Build Coastguard Worker int64_t tmp_rd =
223*77c1e3ccSAndroid Build Coastguard Worker RDCOST(x->rdmult, tmp_rs + this_rd_stats.rate, this_rd_stats.dist);
224*77c1e3ccSAndroid Build Coastguard Worker if (tmp_rd >= *rd) {
225*77c1e3ccSAndroid Build Coastguard Worker mbmi->interp_filters = last_best;
226*77c1e3ccSAndroid Build Coastguard Worker return 0;
227*77c1e3ccSAndroid Build Coastguard Worker }
228*77c1e3ccSAndroid Build Coastguard Worker interp_model_rd_eval(x, cpi, bsize, orig_dst, plane, plane,
229*77c1e3ccSAndroid Build Coastguard Worker &this_rd_stats, 0);
230*77c1e3ccSAndroid Build Coastguard Worker }
231*77c1e3ccSAndroid Build Coastguard Worker break;
232*77c1e3ccSAndroid Build Coastguard Worker case INTERP_SKIP_LUMA_SKIP_CHROMA:
233*77c1e3ccSAndroid Build Coastguard Worker // both luma and chroma evaluation is skipped
234*77c1e3ccSAndroid Build Coastguard Worker this_rd_stats = *rd_stats;
235*77c1e3ccSAndroid Build Coastguard Worker break;
236*77c1e3ccSAndroid Build Coastguard Worker case INTERP_EVAL_INVALID:
237*77c1e3ccSAndroid Build Coastguard Worker default: assert(0); return 0;
238*77c1e3ccSAndroid Build Coastguard Worker }
239*77c1e3ccSAndroid Build Coastguard Worker int64_t tmp_rd =
240*77c1e3ccSAndroid Build Coastguard Worker RDCOST(x->rdmult, tmp_rs + this_rd_stats.rate, this_rd_stats.dist);
241*77c1e3ccSAndroid Build Coastguard Worker
242*77c1e3ccSAndroid Build Coastguard Worker if (tmp_rd < *rd) {
243*77c1e3ccSAndroid Build Coastguard Worker *rd = tmp_rd;
244*77c1e3ccSAndroid Build Coastguard Worker *switchable_rate = tmp_rs;
245*77c1e3ccSAndroid Build Coastguard Worker if (skip_pred != interp_search_flags->default_interp_skip_flags) {
246*77c1e3ccSAndroid Build Coastguard Worker if (skip_pred == INTERP_EVAL_LUMA_EVAL_CHROMA) {
247*77c1e3ccSAndroid Build Coastguard Worker // Overwrite the data as current filter is the best one
248*77c1e3ccSAndroid Build Coastguard Worker *rd_stats_luma = this_rd_stats_luma;
249*77c1e3ccSAndroid Build Coastguard Worker *rd_stats = this_rd_stats;
250*77c1e3ccSAndroid Build Coastguard Worker // As luma MC data is computed, no need to recompute after the search
251*77c1e3ccSAndroid Build Coastguard Worker x->recalc_luma_mc_data = 0;
252*77c1e3ccSAndroid Build Coastguard Worker } else if (skip_pred == INTERP_SKIP_LUMA_EVAL_CHROMA) {
253*77c1e3ccSAndroid Build Coastguard Worker // As luma MC data is not computed, update of luma data can be skipped
254*77c1e3ccSAndroid Build Coastguard Worker *rd_stats = this_rd_stats;
255*77c1e3ccSAndroid Build Coastguard Worker // As luma MC data is not recomputed and current filter is the best,
256*77c1e3ccSAndroid Build Coastguard Worker // indicate the possibility of recomputing MC data
257*77c1e3ccSAndroid Build Coastguard Worker // If current buffer contains valid MC data, toggle to indicate that
258*77c1e3ccSAndroid Build Coastguard Worker // luma MC data needs to be recomputed
259*77c1e3ccSAndroid Build Coastguard Worker x->recalc_luma_mc_data ^= 1;
260*77c1e3ccSAndroid Build Coastguard Worker }
261*77c1e3ccSAndroid Build Coastguard Worker swap_dst_buf(xd, dst_bufs, num_planes);
262*77c1e3ccSAndroid Build Coastguard Worker }
263*77c1e3ccSAndroid Build Coastguard Worker return 1;
264*77c1e3ccSAndroid Build Coastguard Worker }
265*77c1e3ccSAndroid Build Coastguard Worker mbmi->interp_filters = last_best;
266*77c1e3ccSAndroid Build Coastguard Worker return 0;
267*77c1e3ccSAndroid Build Coastguard Worker }
268*77c1e3ccSAndroid Build Coastguard Worker
is_pred_filter_search_allowed(const AV1_COMP * const cpi,MACROBLOCKD * xd,BLOCK_SIZE bsize,int_interpfilters * af,int_interpfilters * lf)269*77c1e3ccSAndroid Build Coastguard Worker static inline INTERP_PRED_TYPE is_pred_filter_search_allowed(
270*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMP *const cpi, MACROBLOCKD *xd, BLOCK_SIZE bsize,
271*77c1e3ccSAndroid Build Coastguard Worker int_interpfilters *af, int_interpfilters *lf) {
272*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMMON *cm = &cpi->common;
273*77c1e3ccSAndroid Build Coastguard Worker const MB_MODE_INFO *const above_mbmi = xd->above_mbmi;
274*77c1e3ccSAndroid Build Coastguard Worker const MB_MODE_INFO *const left_mbmi = xd->left_mbmi;
275*77c1e3ccSAndroid Build Coastguard Worker const int bsl = mi_size_wide_log2[bsize];
276*77c1e3ccSAndroid Build Coastguard Worker int is_horiz_eq = 0, is_vert_eq = 0;
277*77c1e3ccSAndroid Build Coastguard Worker
278*77c1e3ccSAndroid Build Coastguard Worker if (above_mbmi && is_inter_block(above_mbmi))
279*77c1e3ccSAndroid Build Coastguard Worker *af = above_mbmi->interp_filters;
280*77c1e3ccSAndroid Build Coastguard Worker
281*77c1e3ccSAndroid Build Coastguard Worker if (left_mbmi && is_inter_block(left_mbmi)) *lf = left_mbmi->interp_filters;
282*77c1e3ccSAndroid Build Coastguard Worker
283*77c1e3ccSAndroid Build Coastguard Worker if (af->as_filters.x_filter != INTERP_INVALID)
284*77c1e3ccSAndroid Build Coastguard Worker is_horiz_eq = af->as_filters.x_filter == lf->as_filters.x_filter;
285*77c1e3ccSAndroid Build Coastguard Worker if (af->as_filters.y_filter != INTERP_INVALID)
286*77c1e3ccSAndroid Build Coastguard Worker is_vert_eq = af->as_filters.y_filter == lf->as_filters.y_filter;
287*77c1e3ccSAndroid Build Coastguard Worker
288*77c1e3ccSAndroid Build Coastguard Worker INTERP_PRED_TYPE pred_filter_type = (is_vert_eq << 1) + is_horiz_eq;
289*77c1e3ccSAndroid Build Coastguard Worker const int mi_row = xd->mi_row;
290*77c1e3ccSAndroid Build Coastguard Worker const int mi_col = xd->mi_col;
291*77c1e3ccSAndroid Build Coastguard Worker int pred_filter_enable =
292*77c1e3ccSAndroid Build Coastguard Worker cpi->sf.interp_sf.cb_pred_filter_search
293*77c1e3ccSAndroid Build Coastguard Worker ? (((mi_row + mi_col) >> bsl) +
294*77c1e3ccSAndroid Build Coastguard Worker get_chessboard_index(cm->current_frame.frame_number)) &
295*77c1e3ccSAndroid Build Coastguard Worker 0x1
296*77c1e3ccSAndroid Build Coastguard Worker : 0;
297*77c1e3ccSAndroid Build Coastguard Worker pred_filter_enable &= is_horiz_eq || is_vert_eq;
298*77c1e3ccSAndroid Build Coastguard Worker // pred_filter_search = 0: pred_filter is disabled
299*77c1e3ccSAndroid Build Coastguard Worker // pred_filter_search = 1: pred_filter is enabled and only horz pred matching
300*77c1e3ccSAndroid Build Coastguard Worker // pred_filter_search = 2: pred_filter is enabled and only vert pred matching
301*77c1e3ccSAndroid Build Coastguard Worker // pred_filter_search = 3: pred_filter is enabled and
302*77c1e3ccSAndroid Build Coastguard Worker // both vert, horz pred matching
303*77c1e3ccSAndroid Build Coastguard Worker return pred_filter_enable * pred_filter_type;
304*77c1e3ccSAndroid Build Coastguard Worker }
305*77c1e3ccSAndroid Build Coastguard Worker
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)306*77c1e3ccSAndroid Build Coastguard Worker static DUAL_FILTER_TYPE find_best_interp_rd_facade(
307*77c1e3ccSAndroid Build Coastguard Worker MACROBLOCK *const x, const AV1_COMP *const cpi,
308*77c1e3ccSAndroid Build Coastguard Worker const TileDataEnc *tile_data, BLOCK_SIZE bsize,
309*77c1e3ccSAndroid Build Coastguard Worker const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y,
310*77c1e3ccSAndroid Build Coastguard Worker RD_STATS *rd_stats, int *const switchable_rate,
311*77c1e3ccSAndroid Build Coastguard Worker const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2],
312*77c1e3ccSAndroid Build Coastguard Worker const int skip_pred, uint16_t allow_interp_mask, int is_w4_or_h4) {
313*77c1e3ccSAndroid Build Coastguard Worker int tmp_skip_pred = skip_pred;
314*77c1e3ccSAndroid Build Coastguard Worker DUAL_FILTER_TYPE best_filt_type = REG_REG;
315*77c1e3ccSAndroid Build Coastguard Worker
316*77c1e3ccSAndroid Build Coastguard Worker // If no filter are set to be evaluated, return from function
317*77c1e3ccSAndroid Build Coastguard Worker if (allow_interp_mask == 0x0) return best_filt_type;
318*77c1e3ccSAndroid Build Coastguard Worker // For block width or height is 4, skip the pred evaluation of SHARP_SHARP
319*77c1e3ccSAndroid Build Coastguard Worker tmp_skip_pred = is_w4_or_h4
320*77c1e3ccSAndroid Build Coastguard Worker ? cpi->interp_search_flags.default_interp_skip_flags
321*77c1e3ccSAndroid Build Coastguard Worker : skip_pred;
322*77c1e3ccSAndroid Build Coastguard Worker
323*77c1e3ccSAndroid Build Coastguard Worker // Loop over the all filter types and evaluate for only allowed filter types
324*77c1e3ccSAndroid Build Coastguard Worker for (int filt_type = SHARP_SHARP; filt_type >= REG_REG; --filt_type) {
325*77c1e3ccSAndroid Build Coastguard Worker const int is_filter_allowed =
326*77c1e3ccSAndroid Build Coastguard Worker get_interp_filter_allowed_mask(allow_interp_mask, filt_type);
327*77c1e3ccSAndroid Build Coastguard Worker if (is_filter_allowed)
328*77c1e3ccSAndroid Build Coastguard Worker if (interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
329*77c1e3ccSAndroid Build Coastguard Worker rd_stats_y, rd_stats, switchable_rate,
330*77c1e3ccSAndroid Build Coastguard Worker dst_bufs, filt_type, switchable_ctx,
331*77c1e3ccSAndroid Build Coastguard Worker tmp_skip_pred))
332*77c1e3ccSAndroid Build Coastguard Worker best_filt_type = filt_type;
333*77c1e3ccSAndroid Build Coastguard Worker tmp_skip_pred = skip_pred;
334*77c1e3ccSAndroid Build Coastguard Worker }
335*77c1e3ccSAndroid Build Coastguard Worker return best_filt_type;
336*77c1e3ccSAndroid Build Coastguard Worker }
337*77c1e3ccSAndroid Build Coastguard Worker
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)338*77c1e3ccSAndroid Build Coastguard Worker static inline void pred_dual_interp_filter_rd(
339*77c1e3ccSAndroid Build Coastguard Worker MACROBLOCK *const x, const AV1_COMP *const cpi,
340*77c1e3ccSAndroid Build Coastguard Worker const TileDataEnc *tile_data, BLOCK_SIZE bsize,
341*77c1e3ccSAndroid Build Coastguard Worker const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y,
342*77c1e3ccSAndroid Build Coastguard Worker RD_STATS *rd_stats, int *const switchable_rate,
343*77c1e3ccSAndroid Build Coastguard Worker const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2],
344*77c1e3ccSAndroid Build Coastguard Worker const int skip_pred, INTERP_PRED_TYPE pred_filt_type, int_interpfilters *af,
345*77c1e3ccSAndroid Build Coastguard Worker int_interpfilters *lf) {
346*77c1e3ccSAndroid Build Coastguard Worker (void)lf;
347*77c1e3ccSAndroid Build Coastguard Worker assert(pred_filt_type > INTERP_HORZ_NEQ_VERT_NEQ);
348*77c1e3ccSAndroid Build Coastguard Worker assert(pred_filt_type < INTERP_PRED_TYPE_ALL);
349*77c1e3ccSAndroid Build Coastguard Worker uint16_t allowed_interp_mask = 0;
350*77c1e3ccSAndroid Build Coastguard Worker
351*77c1e3ccSAndroid Build Coastguard Worker if (pred_filt_type == INTERP_HORZ_EQ_VERT_NEQ) {
352*77c1e3ccSAndroid Build Coastguard Worker // pred_filter_search = 1: Only horizontal filter is matching
353*77c1e3ccSAndroid Build Coastguard Worker allowed_interp_mask =
354*77c1e3ccSAndroid Build Coastguard Worker av1_interp_dual_filt_mask[pred_filt_type - 1][af->as_filters.x_filter];
355*77c1e3ccSAndroid Build Coastguard Worker } else if (pred_filt_type == INTERP_HORZ_NEQ_VERT_EQ) {
356*77c1e3ccSAndroid Build Coastguard Worker // pred_filter_search = 2: Only vertical filter is matching
357*77c1e3ccSAndroid Build Coastguard Worker allowed_interp_mask =
358*77c1e3ccSAndroid Build Coastguard Worker av1_interp_dual_filt_mask[pred_filt_type - 1][af->as_filters.y_filter];
359*77c1e3ccSAndroid Build Coastguard Worker } else {
360*77c1e3ccSAndroid Build Coastguard Worker // pred_filter_search = 3: Both horizontal and vertical filter are matching
361*77c1e3ccSAndroid Build Coastguard Worker int filt_type =
362*77c1e3ccSAndroid Build Coastguard Worker af->as_filters.x_filter + af->as_filters.y_filter * SWITCHABLE_FILTERS;
363*77c1e3ccSAndroid Build Coastguard Worker set_interp_filter_allowed_mask(&allowed_interp_mask, filt_type);
364*77c1e3ccSAndroid Build Coastguard Worker }
365*77c1e3ccSAndroid Build Coastguard Worker // REG_REG is already been evaluated in the beginning
366*77c1e3ccSAndroid Build Coastguard Worker reset_interp_filter_allowed_mask(&allowed_interp_mask, REG_REG);
367*77c1e3ccSAndroid Build Coastguard Worker find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd, rd_stats_y,
368*77c1e3ccSAndroid Build Coastguard Worker rd_stats, switchable_rate, dst_bufs,
369*77c1e3ccSAndroid Build Coastguard Worker switchable_ctx, skip_pred, allowed_interp_mask, 0);
370*77c1e3ccSAndroid Build Coastguard Worker }
371*77c1e3ccSAndroid Build Coastguard Worker // Evaluate dual filter type
372*77c1e3ccSAndroid Build Coastguard Worker // a) Using above, left block interp filter
373*77c1e3ccSAndroid Build Coastguard Worker // b) Find the best horizontal filter and
374*77c1e3ccSAndroid Build Coastguard Worker // then evaluate corresponding vertical filters.
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)375*77c1e3ccSAndroid Build Coastguard Worker static inline void fast_dual_interp_filter_rd(
376*77c1e3ccSAndroid Build Coastguard Worker MACROBLOCK *const x, const AV1_COMP *const cpi,
377*77c1e3ccSAndroid Build Coastguard Worker const TileDataEnc *tile_data, BLOCK_SIZE bsize,
378*77c1e3ccSAndroid Build Coastguard Worker const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y,
379*77c1e3ccSAndroid Build Coastguard Worker RD_STATS *rd_stats, int *const switchable_rate,
380*77c1e3ccSAndroid Build Coastguard Worker const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2],
381*77c1e3ccSAndroid Build Coastguard Worker const int skip_hor, const int skip_ver) {
382*77c1e3ccSAndroid Build Coastguard Worker const InterpSearchFlags *interp_search_flags = &cpi->interp_search_flags;
383*77c1e3ccSAndroid Build Coastguard Worker MACROBLOCKD *const xd = &x->e_mbd;
384*77c1e3ccSAndroid Build Coastguard Worker MB_MODE_INFO *const mbmi = xd->mi[0];
385*77c1e3ccSAndroid Build Coastguard Worker INTERP_PRED_TYPE pred_filter_type = INTERP_HORZ_NEQ_VERT_NEQ;
386*77c1e3ccSAndroid Build Coastguard Worker int_interpfilters af = av1_broadcast_interp_filter(INTERP_INVALID);
387*77c1e3ccSAndroid Build Coastguard Worker int_interpfilters lf = af;
388*77c1e3ccSAndroid Build Coastguard Worker
389*77c1e3ccSAndroid Build Coastguard Worker if (!have_newmv_in_inter_mode(mbmi->mode)) {
390*77c1e3ccSAndroid Build Coastguard Worker pred_filter_type = is_pred_filter_search_allowed(cpi, xd, bsize, &af, &lf);
391*77c1e3ccSAndroid Build Coastguard Worker }
392*77c1e3ccSAndroid Build Coastguard Worker
393*77c1e3ccSAndroid Build Coastguard Worker if (pred_filter_type) {
394*77c1e3ccSAndroid Build Coastguard Worker pred_dual_interp_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
395*77c1e3ccSAndroid Build Coastguard Worker rd_stats_y, rd_stats, switchable_rate, dst_bufs,
396*77c1e3ccSAndroid Build Coastguard Worker switchable_ctx, (skip_hor & skip_ver),
397*77c1e3ccSAndroid Build Coastguard Worker pred_filter_type, &af, &lf);
398*77c1e3ccSAndroid Build Coastguard Worker } else {
399*77c1e3ccSAndroid Build Coastguard Worker const int bw = block_size_wide[bsize];
400*77c1e3ccSAndroid Build Coastguard Worker const int bh = block_size_high[bsize];
401*77c1e3ccSAndroid Build Coastguard Worker int best_dual_mode = 0;
402*77c1e3ccSAndroid Build Coastguard Worker int skip_pred =
403*77c1e3ccSAndroid Build Coastguard Worker bw <= 4 ? interp_search_flags->default_interp_skip_flags : skip_hor;
404*77c1e3ccSAndroid Build Coastguard Worker // TODO(any): Make use of find_best_interp_rd_facade()
405*77c1e3ccSAndroid Build Coastguard Worker // if speed impact is negligible
406*77c1e3ccSAndroid Build Coastguard Worker for (int i = (SWITCHABLE_FILTERS - 1); i >= 1; --i) {
407*77c1e3ccSAndroid Build Coastguard Worker if (interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
408*77c1e3ccSAndroid Build Coastguard Worker rd_stats_y, rd_stats, switchable_rate,
409*77c1e3ccSAndroid Build Coastguard Worker dst_bufs, i, switchable_ctx, skip_pred)) {
410*77c1e3ccSAndroid Build Coastguard Worker best_dual_mode = i;
411*77c1e3ccSAndroid Build Coastguard Worker }
412*77c1e3ccSAndroid Build Coastguard Worker skip_pred = skip_hor;
413*77c1e3ccSAndroid Build Coastguard Worker }
414*77c1e3ccSAndroid Build Coastguard Worker // From best of horizontal EIGHTTAP_REGULAR modes, check vertical modes
415*77c1e3ccSAndroid Build Coastguard Worker skip_pred =
416*77c1e3ccSAndroid Build Coastguard Worker bh <= 4 ? interp_search_flags->default_interp_skip_flags : skip_ver;
417*77c1e3ccSAndroid Build Coastguard Worker for (int i = (best_dual_mode + (SWITCHABLE_FILTERS * 2));
418*77c1e3ccSAndroid Build Coastguard Worker i >= (best_dual_mode + SWITCHABLE_FILTERS); i -= SWITCHABLE_FILTERS) {
419*77c1e3ccSAndroid Build Coastguard Worker interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
420*77c1e3ccSAndroid Build Coastguard Worker rd_stats_y, rd_stats, switchable_rate, dst_bufs,
421*77c1e3ccSAndroid Build Coastguard Worker i, switchable_ctx, skip_pred);
422*77c1e3ccSAndroid Build Coastguard Worker skip_pred = skip_ver;
423*77c1e3ccSAndroid Build Coastguard Worker }
424*77c1e3ccSAndroid Build Coastguard Worker }
425*77c1e3ccSAndroid Build Coastguard Worker }
426*77c1e3ccSAndroid Build Coastguard Worker
427*77c1e3ccSAndroid Build Coastguard Worker // Find the best interp filter if dual_interp_filter = 0
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)428*77c1e3ccSAndroid Build Coastguard Worker static inline void find_best_non_dual_interp_filter(
429*77c1e3ccSAndroid Build Coastguard Worker MACROBLOCK *const x, const AV1_COMP *const cpi,
430*77c1e3ccSAndroid Build Coastguard Worker const TileDataEnc *tile_data, BLOCK_SIZE bsize,
431*77c1e3ccSAndroid Build Coastguard Worker const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y,
432*77c1e3ccSAndroid Build Coastguard Worker RD_STATS *rd_stats, int *const switchable_rate,
433*77c1e3ccSAndroid Build Coastguard Worker const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2],
434*77c1e3ccSAndroid Build Coastguard Worker const int skip_ver, const int skip_hor) {
435*77c1e3ccSAndroid Build Coastguard Worker const InterpSearchFlags *interp_search_flags = &cpi->interp_search_flags;
436*77c1e3ccSAndroid Build Coastguard Worker int8_t i;
437*77c1e3ccSAndroid Build Coastguard Worker MACROBLOCKD *const xd = &x->e_mbd;
438*77c1e3ccSAndroid Build Coastguard Worker MB_MODE_INFO *const mbmi = xd->mi[0];
439*77c1e3ccSAndroid Build Coastguard Worker
440*77c1e3ccSAndroid Build Coastguard Worker uint16_t interp_filter_search_mask =
441*77c1e3ccSAndroid Build Coastguard Worker interp_search_flags->interp_filter_search_mask;
442*77c1e3ccSAndroid Build Coastguard Worker
443*77c1e3ccSAndroid Build Coastguard Worker if (cpi->sf.interp_sf.adaptive_interp_filter_search == 2) {
444*77c1e3ccSAndroid Build Coastguard Worker const FRAME_UPDATE_TYPE update_type =
445*77c1e3ccSAndroid Build Coastguard Worker get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index);
446*77c1e3ccSAndroid Build Coastguard Worker const int ctx0 = av1_get_pred_context_switchable_interp(xd, 0);
447*77c1e3ccSAndroid Build Coastguard Worker const int ctx1 = av1_get_pred_context_switchable_interp(xd, 1);
448*77c1e3ccSAndroid Build Coastguard Worker int use_actual_frame_probs = 1;
449*77c1e3ccSAndroid Build Coastguard Worker const int *switchable_interp_p0;
450*77c1e3ccSAndroid Build Coastguard Worker const int *switchable_interp_p1;
451*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_FPMT_TEST
452*77c1e3ccSAndroid Build Coastguard Worker use_actual_frame_probs =
453*77c1e3ccSAndroid Build Coastguard Worker (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) ? 0 : 1;
454*77c1e3ccSAndroid Build Coastguard Worker if (!use_actual_frame_probs) {
455*77c1e3ccSAndroid Build Coastguard Worker switchable_interp_p0 = (int *)cpi->ppi->temp_frame_probs
456*77c1e3ccSAndroid Build Coastguard Worker .switchable_interp_probs[update_type][ctx0];
457*77c1e3ccSAndroid Build Coastguard Worker switchable_interp_p1 = (int *)cpi->ppi->temp_frame_probs
458*77c1e3ccSAndroid Build Coastguard Worker .switchable_interp_probs[update_type][ctx1];
459*77c1e3ccSAndroid Build Coastguard Worker }
460*77c1e3ccSAndroid Build Coastguard Worker #endif
461*77c1e3ccSAndroid Build Coastguard Worker if (use_actual_frame_probs) {
462*77c1e3ccSAndroid Build Coastguard Worker switchable_interp_p0 =
463*77c1e3ccSAndroid Build Coastguard Worker cpi->ppi->frame_probs.switchable_interp_probs[update_type][ctx0];
464*77c1e3ccSAndroid Build Coastguard Worker switchable_interp_p1 =
465*77c1e3ccSAndroid Build Coastguard Worker cpi->ppi->frame_probs.switchable_interp_probs[update_type][ctx1];
466*77c1e3ccSAndroid Build Coastguard Worker }
467*77c1e3ccSAndroid Build Coastguard Worker static const int thr[7] = { 0, 8, 8, 8, 8, 0, 8 };
468*77c1e3ccSAndroid Build Coastguard Worker const int thresh = thr[update_type];
469*77c1e3ccSAndroid Build Coastguard Worker for (i = 0; i < SWITCHABLE_FILTERS; i++) {
470*77c1e3ccSAndroid Build Coastguard Worker // For non-dual case, the 2 dir's prob should be identical.
471*77c1e3ccSAndroid Build Coastguard Worker assert(switchable_interp_p0[i] == switchable_interp_p1[i]);
472*77c1e3ccSAndroid Build Coastguard Worker if (switchable_interp_p0[i] < thresh &&
473*77c1e3ccSAndroid Build Coastguard Worker switchable_interp_p1[i] < thresh) {
474*77c1e3ccSAndroid Build Coastguard Worker DUAL_FILTER_TYPE filt_type = i + SWITCHABLE_FILTERS * i;
475*77c1e3ccSAndroid Build Coastguard Worker reset_interp_filter_allowed_mask(&interp_filter_search_mask, filt_type);
476*77c1e3ccSAndroid Build Coastguard Worker }
477*77c1e3ccSAndroid Build Coastguard Worker }
478*77c1e3ccSAndroid Build Coastguard Worker }
479*77c1e3ccSAndroid Build Coastguard Worker
480*77c1e3ccSAndroid Build Coastguard Worker // Regular filter evaluation should have been done and hence the same should
481*77c1e3ccSAndroid Build Coastguard Worker // be the winner
482*77c1e3ccSAndroid Build Coastguard Worker assert(x->e_mbd.mi[0]->interp_filters.as_int == filter_sets[0].as_int);
483*77c1e3ccSAndroid Build Coastguard Worker if ((skip_hor & skip_ver) != interp_search_flags->default_interp_skip_flags) {
484*77c1e3ccSAndroid Build Coastguard Worker INTERP_PRED_TYPE pred_filter_type = INTERP_HORZ_NEQ_VERT_NEQ;
485*77c1e3ccSAndroid Build Coastguard Worker int_interpfilters af = av1_broadcast_interp_filter(INTERP_INVALID);
486*77c1e3ccSAndroid Build Coastguard Worker int_interpfilters lf = af;
487*77c1e3ccSAndroid Build Coastguard Worker
488*77c1e3ccSAndroid Build Coastguard Worker pred_filter_type = is_pred_filter_search_allowed(cpi, xd, bsize, &af, &lf);
489*77c1e3ccSAndroid Build Coastguard Worker if (pred_filter_type) {
490*77c1e3ccSAndroid Build Coastguard Worker assert(af.as_filters.x_filter != INTERP_INVALID);
491*77c1e3ccSAndroid Build Coastguard Worker int filter_idx = SWITCHABLE * af.as_filters.x_filter;
492*77c1e3ccSAndroid Build Coastguard Worker // This assert tells that (filter_x == filter_y) for non-dual filter case
493*77c1e3ccSAndroid Build Coastguard Worker assert(filter_sets[filter_idx].as_filters.x_filter ==
494*77c1e3ccSAndroid Build Coastguard Worker filter_sets[filter_idx].as_filters.y_filter);
495*77c1e3ccSAndroid Build Coastguard Worker if (cpi->sf.interp_sf.adaptive_interp_filter_search &&
496*77c1e3ccSAndroid Build Coastguard Worker !(get_interp_filter_allowed_mask(interp_filter_search_mask,
497*77c1e3ccSAndroid Build Coastguard Worker filter_idx))) {
498*77c1e3ccSAndroid Build Coastguard Worker return;
499*77c1e3ccSAndroid Build Coastguard Worker }
500*77c1e3ccSAndroid Build Coastguard Worker if (filter_idx) {
501*77c1e3ccSAndroid Build Coastguard Worker interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
502*77c1e3ccSAndroid Build Coastguard Worker rd_stats_y, rd_stats, switchable_rate, dst_bufs,
503*77c1e3ccSAndroid Build Coastguard Worker filter_idx, switchable_ctx,
504*77c1e3ccSAndroid Build Coastguard Worker (skip_hor & skip_ver));
505*77c1e3ccSAndroid Build Coastguard Worker }
506*77c1e3ccSAndroid Build Coastguard Worker return;
507*77c1e3ccSAndroid Build Coastguard Worker }
508*77c1e3ccSAndroid Build Coastguard Worker }
509*77c1e3ccSAndroid Build Coastguard Worker // Reuse regular filter's modeled rd data for sharp filter for following
510*77c1e3ccSAndroid Build Coastguard Worker // cases
511*77c1e3ccSAndroid Build Coastguard Worker // 1) When bsize is 4x4
512*77c1e3ccSAndroid Build Coastguard Worker // 2) When block width is 4 (i.e. 4x8/4x16 blocks) and MV in vertical
513*77c1e3ccSAndroid Build Coastguard Worker // direction is full-pel
514*77c1e3ccSAndroid Build Coastguard Worker // 3) When block height is 4 (i.e. 8x4/16x4 blocks) and MV in horizontal
515*77c1e3ccSAndroid Build Coastguard Worker // direction is full-pel
516*77c1e3ccSAndroid Build Coastguard Worker // TODO(any): Optimize cases 2 and 3 further if luma MV in relavant direction
517*77c1e3ccSAndroid Build Coastguard Worker // alone is full-pel
518*77c1e3ccSAndroid Build Coastguard Worker
519*77c1e3ccSAndroid Build Coastguard Worker if ((bsize == BLOCK_4X4) ||
520*77c1e3ccSAndroid Build Coastguard Worker (block_size_wide[bsize] == 4 &&
521*77c1e3ccSAndroid Build Coastguard Worker skip_ver == interp_search_flags->default_interp_skip_flags) ||
522*77c1e3ccSAndroid Build Coastguard Worker (block_size_high[bsize] == 4 &&
523*77c1e3ccSAndroid Build Coastguard Worker skip_hor == interp_search_flags->default_interp_skip_flags)) {
524*77c1e3ccSAndroid Build Coastguard Worker int skip_pred = skip_hor & skip_ver;
525*77c1e3ccSAndroid Build Coastguard Worker uint16_t allowed_interp_mask = 0;
526*77c1e3ccSAndroid Build Coastguard Worker
527*77c1e3ccSAndroid Build Coastguard Worker // REG_REG filter type is evaluated beforehand, hence skip it
528*77c1e3ccSAndroid Build Coastguard Worker set_interp_filter_allowed_mask(&allowed_interp_mask, SHARP_SHARP);
529*77c1e3ccSAndroid Build Coastguard Worker set_interp_filter_allowed_mask(&allowed_interp_mask, SMOOTH_SMOOTH);
530*77c1e3ccSAndroid Build Coastguard Worker if (cpi->sf.interp_sf.adaptive_interp_filter_search)
531*77c1e3ccSAndroid Build Coastguard Worker allowed_interp_mask &= interp_filter_search_mask;
532*77c1e3ccSAndroid Build Coastguard Worker
533*77c1e3ccSAndroid Build Coastguard Worker find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd,
534*77c1e3ccSAndroid Build Coastguard Worker rd_stats_y, rd_stats, switchable_rate, dst_bufs,
535*77c1e3ccSAndroid Build Coastguard Worker switchable_ctx, skip_pred, allowed_interp_mask,
536*77c1e3ccSAndroid Build Coastguard Worker 1);
537*77c1e3ccSAndroid Build Coastguard Worker } else {
538*77c1e3ccSAndroid Build Coastguard Worker int skip_pred = (skip_hor & skip_ver);
539*77c1e3ccSAndroid Build Coastguard Worker for (i = (SWITCHABLE_FILTERS + 1); i < DUAL_FILTER_SET_SIZE;
540*77c1e3ccSAndroid Build Coastguard Worker i += (SWITCHABLE_FILTERS + 1)) {
541*77c1e3ccSAndroid Build Coastguard Worker // This assert tells that (filter_x == filter_y) for non-dual filter case
542*77c1e3ccSAndroid Build Coastguard Worker assert(filter_sets[i].as_filters.x_filter ==
543*77c1e3ccSAndroid Build Coastguard Worker filter_sets[i].as_filters.y_filter);
544*77c1e3ccSAndroid Build Coastguard Worker if (cpi->sf.interp_sf.adaptive_interp_filter_search &&
545*77c1e3ccSAndroid Build Coastguard Worker !(get_interp_filter_allowed_mask(interp_filter_search_mask, i))) {
546*77c1e3ccSAndroid Build Coastguard Worker continue;
547*77c1e3ccSAndroid Build Coastguard Worker }
548*77c1e3ccSAndroid Build Coastguard Worker interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
549*77c1e3ccSAndroid Build Coastguard Worker rd_stats_y, rd_stats, switchable_rate, dst_bufs,
550*77c1e3ccSAndroid Build Coastguard Worker i, switchable_ctx, skip_pred);
551*77c1e3ccSAndroid Build Coastguard Worker // In first iteration, smooth filter is evaluated. If smooth filter
552*77c1e3ccSAndroid Build Coastguard Worker // (which is less sharper) is the winner among regular and smooth filters,
553*77c1e3ccSAndroid Build Coastguard Worker // sharp filter evaluation is skipped
554*77c1e3ccSAndroid Build Coastguard Worker // TODO(any): Refine this gating based on modelled rd only (i.e., by not
555*77c1e3ccSAndroid Build Coastguard Worker // accounting switchable filter rate)
556*77c1e3ccSAndroid Build Coastguard Worker if (cpi->sf.interp_sf.skip_sharp_interp_filter_search &&
557*77c1e3ccSAndroid Build Coastguard Worker skip_pred != interp_search_flags->default_interp_skip_flags) {
558*77c1e3ccSAndroid Build Coastguard Worker if (mbmi->interp_filters.as_int == filter_sets[SMOOTH_SMOOTH].as_int)
559*77c1e3ccSAndroid Build Coastguard Worker break;
560*77c1e3ccSAndroid Build Coastguard Worker }
561*77c1e3ccSAndroid Build Coastguard Worker }
562*77c1e3ccSAndroid Build Coastguard Worker }
563*77c1e3ccSAndroid Build Coastguard Worker }
564*77c1e3ccSAndroid Build Coastguard Worker
calc_interp_skip_pred_flag(MACROBLOCK * const x,const AV1_COMP * const cpi,int * skip_hor,int * skip_ver)565*77c1e3ccSAndroid Build Coastguard Worker static inline void calc_interp_skip_pred_flag(MACROBLOCK *const x,
566*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMP *const cpi,
567*77c1e3ccSAndroid Build Coastguard Worker int *skip_hor, int *skip_ver) {
568*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMMON *cm = &cpi->common;
569*77c1e3ccSAndroid Build Coastguard Worker MACROBLOCKD *const xd = &x->e_mbd;
570*77c1e3ccSAndroid Build Coastguard Worker MB_MODE_INFO *const mbmi = xd->mi[0];
571*77c1e3ccSAndroid Build Coastguard Worker const int num_planes = av1_num_planes(cm);
572*77c1e3ccSAndroid Build Coastguard Worker const int is_compound = has_second_ref(mbmi);
573*77c1e3ccSAndroid Build Coastguard Worker assert(is_intrabc_block(mbmi) == 0);
574*77c1e3ccSAndroid Build Coastguard Worker for (int ref = 0; ref < 1 + is_compound; ++ref) {
575*77c1e3ccSAndroid Build Coastguard Worker const struct scale_factors *const sf =
576*77c1e3ccSAndroid Build Coastguard Worker get_ref_scale_factors_const(cm, mbmi->ref_frame[ref]);
577*77c1e3ccSAndroid Build Coastguard Worker // TODO(any): Refine skip flag calculation considering scaling
578*77c1e3ccSAndroid Build Coastguard Worker if (av1_is_scaled(sf)) {
579*77c1e3ccSAndroid Build Coastguard Worker *skip_hor = 0;
580*77c1e3ccSAndroid Build Coastguard Worker *skip_ver = 0;
581*77c1e3ccSAndroid Build Coastguard Worker break;
582*77c1e3ccSAndroid Build Coastguard Worker }
583*77c1e3ccSAndroid Build Coastguard Worker const MV mv = mbmi->mv[ref].as_mv;
584*77c1e3ccSAndroid Build Coastguard Worker int skip_hor_plane = 0;
585*77c1e3ccSAndroid Build Coastguard Worker int skip_ver_plane = 0;
586*77c1e3ccSAndroid Build Coastguard Worker for (int plane_idx = 0; plane_idx < AOMMAX(1, (num_planes - 1));
587*77c1e3ccSAndroid Build Coastguard Worker ++plane_idx) {
588*77c1e3ccSAndroid Build Coastguard Worker struct macroblockd_plane *const pd = &xd->plane[plane_idx];
589*77c1e3ccSAndroid Build Coastguard Worker const int bw = pd->width;
590*77c1e3ccSAndroid Build Coastguard Worker const int bh = pd->height;
591*77c1e3ccSAndroid Build Coastguard Worker const MV mv_q4 = clamp_mv_to_umv_border_sb(
592*77c1e3ccSAndroid Build Coastguard Worker xd, &mv, bw, bh, pd->subsampling_x, pd->subsampling_y);
593*77c1e3ccSAndroid Build Coastguard Worker const int sub_x = (mv_q4.col & SUBPEL_MASK) << SCALE_EXTRA_BITS;
594*77c1e3ccSAndroid Build Coastguard Worker const int sub_y = (mv_q4.row & SUBPEL_MASK) << SCALE_EXTRA_BITS;
595*77c1e3ccSAndroid Build Coastguard Worker skip_hor_plane |= ((sub_x == 0) << plane_idx);
596*77c1e3ccSAndroid Build Coastguard Worker skip_ver_plane |= ((sub_y == 0) << plane_idx);
597*77c1e3ccSAndroid Build Coastguard Worker }
598*77c1e3ccSAndroid Build Coastguard Worker *skip_hor &= skip_hor_plane;
599*77c1e3ccSAndroid Build Coastguard Worker *skip_ver &= skip_ver_plane;
600*77c1e3ccSAndroid Build Coastguard Worker // It is not valid that "luma MV is sub-pel, whereas chroma MV is not"
601*77c1e3ccSAndroid Build Coastguard Worker assert(*skip_hor != 2);
602*77c1e3ccSAndroid Build Coastguard Worker assert(*skip_ver != 2);
603*77c1e3ccSAndroid Build Coastguard Worker }
604*77c1e3ccSAndroid Build Coastguard Worker // When compond prediction type is compound segment wedge, luma MC and chroma
605*77c1e3ccSAndroid Build Coastguard Worker // MC need to go hand in hand as mask generated during luma MC is reuired for
606*77c1e3ccSAndroid Build Coastguard Worker // chroma MC. If skip_hor = 0 and skip_ver = 1, mask used for chroma MC during
607*77c1e3ccSAndroid Build Coastguard Worker // vertical filter decision may be incorrect as temporary MC evaluation
608*77c1e3ccSAndroid Build Coastguard Worker // overwrites the mask. Make skip_ver as 0 for this case so that mask is
609*77c1e3ccSAndroid Build Coastguard Worker // populated during luma MC
610*77c1e3ccSAndroid Build Coastguard Worker if (is_compound && mbmi->compound_idx == 1 &&
611*77c1e3ccSAndroid Build Coastguard Worker mbmi->interinter_comp.type == COMPOUND_DIFFWTD) {
612*77c1e3ccSAndroid Build Coastguard Worker assert(mbmi->comp_group_idx == 1);
613*77c1e3ccSAndroid Build Coastguard Worker if (*skip_hor == 0 && *skip_ver == 1) *skip_ver = 0;
614*77c1e3ccSAndroid Build Coastguard Worker }
615*77c1e3ccSAndroid Build Coastguard Worker }
616*77c1e3ccSAndroid Build Coastguard Worker
617*77c1e3ccSAndroid Build Coastguard Worker /*!\brief AV1 interpolation filter search
618*77c1e3ccSAndroid Build Coastguard Worker *
619*77c1e3ccSAndroid Build Coastguard Worker * \ingroup inter_mode_search
620*77c1e3ccSAndroid Build Coastguard Worker *
621*77c1e3ccSAndroid Build Coastguard Worker * \param[in] cpi Top-level encoder structure.
622*77c1e3ccSAndroid Build Coastguard Worker * \param[in] tile_data Pointer to struct holding adaptive
623*77c1e3ccSAndroid Build Coastguard Worker * data/contexts/models for the tile during
624*77c1e3ccSAndroid Build Coastguard Worker * encoding.
625*77c1e3ccSAndroid Build Coastguard Worker * \param[in] x Pointer to struc holding all the data for
626*77c1e3ccSAndroid Build Coastguard Worker * the current macroblock.
627*77c1e3ccSAndroid Build Coastguard Worker * \param[in] bsize Current block size.
628*77c1e3ccSAndroid Build Coastguard Worker * \param[in] tmp_dst A temporary prediction buffer to hold a
629*77c1e3ccSAndroid Build Coastguard Worker * computed prediction.
630*77c1e3ccSAndroid Build Coastguard Worker * \param[in,out] orig_dst A prediction buffer to hold a computed
631*77c1e3ccSAndroid Build Coastguard Worker * prediction. This will eventually hold the
632*77c1e3ccSAndroid Build Coastguard Worker * final prediction, and the tmp_dst info will
633*77c1e3ccSAndroid Build Coastguard Worker * be copied here.
634*77c1e3ccSAndroid Build Coastguard Worker * \param[in,out] rd The RD cost associated with the selected
635*77c1e3ccSAndroid Build Coastguard Worker * interpolation filter parameters.
636*77c1e3ccSAndroid Build Coastguard Worker * \param[in,out] switchable_rate The rate associated with using a SWITCHABLE
637*77c1e3ccSAndroid Build Coastguard Worker * filter mode.
638*77c1e3ccSAndroid Build Coastguard Worker * \param[in,out] skip_build_pred Indicates whether or not to build the inter
639*77c1e3ccSAndroid Build Coastguard Worker * predictor. If this is 0, the inter predictor
640*77c1e3ccSAndroid Build Coastguard Worker * has already been built and thus we can avoid
641*77c1e3ccSAndroid Build Coastguard Worker * repeating computation.
642*77c1e3ccSAndroid Build Coastguard Worker * \param[in] args HandleInterModeArgs struct holding
643*77c1e3ccSAndroid Build Coastguard Worker * miscellaneous arguments for inter mode
644*77c1e3ccSAndroid Build Coastguard Worker * search. See the documentation for this
645*77c1e3ccSAndroid Build Coastguard Worker * struct for a description of each member.
646*77c1e3ccSAndroid Build Coastguard Worker * \param[in] ref_best_rd Best RD found so far for this block.
647*77c1e3ccSAndroid Build Coastguard Worker * It is used for early termination of this
648*77c1e3ccSAndroid Build Coastguard Worker * search if the RD exceeds this value.
649*77c1e3ccSAndroid Build Coastguard Worker *
650*77c1e3ccSAndroid Build Coastguard Worker * \return Returns INT64_MAX if the filter parameters are invalid and the
651*77c1e3ccSAndroid Build Coastguard Worker * current motion mode being tested should be skipped. It returns 0 if the
652*77c1e3ccSAndroid Build Coastguard Worker * parameter search is a success.
653*77c1e3ccSAndroid Build Coastguard Worker */
av1_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)654*77c1e3ccSAndroid Build Coastguard Worker int64_t av1_interpolation_filter_search(
655*77c1e3ccSAndroid Build Coastguard Worker MACROBLOCK *const x, const AV1_COMP *const cpi,
656*77c1e3ccSAndroid Build Coastguard Worker const TileDataEnc *tile_data, BLOCK_SIZE bsize,
657*77c1e3ccSAndroid Build Coastguard Worker const BUFFER_SET *const tmp_dst, const BUFFER_SET *const orig_dst,
658*77c1e3ccSAndroid Build Coastguard Worker int64_t *const rd, int *const switchable_rate, int *skip_build_pred,
659*77c1e3ccSAndroid Build Coastguard Worker HandleInterModeArgs *args, int64_t ref_best_rd) {
660*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMMON *cm = &cpi->common;
661*77c1e3ccSAndroid Build Coastguard Worker const InterpSearchFlags *interp_search_flags = &cpi->interp_search_flags;
662*77c1e3ccSAndroid Build Coastguard Worker const int num_planes = av1_num_planes(cm);
663*77c1e3ccSAndroid Build Coastguard Worker MACROBLOCKD *const xd = &x->e_mbd;
664*77c1e3ccSAndroid Build Coastguard Worker MB_MODE_INFO *const mbmi = xd->mi[0];
665*77c1e3ccSAndroid Build Coastguard Worker const int need_search = av1_is_interp_needed(xd);
666*77c1e3ccSAndroid Build Coastguard Worker const int ref_frame = xd->mi[0]->ref_frame[0];
667*77c1e3ccSAndroid Build Coastguard Worker RD_STATS rd_stats_luma, rd_stats;
668*77c1e3ccSAndroid Build Coastguard Worker
669*77c1e3ccSAndroid Build Coastguard Worker // Initialization of rd_stats structures with default values
670*77c1e3ccSAndroid Build Coastguard Worker av1_init_rd_stats(&rd_stats_luma);
671*77c1e3ccSAndroid Build Coastguard Worker av1_init_rd_stats(&rd_stats);
672*77c1e3ccSAndroid Build Coastguard Worker
673*77c1e3ccSAndroid Build Coastguard Worker int match_found_idx = -1;
674*77c1e3ccSAndroid Build Coastguard Worker const InterpFilter assign_filter = cm->features.interp_filter;
675*77c1e3ccSAndroid Build Coastguard Worker
676*77c1e3ccSAndroid Build Coastguard Worker match_found_idx = find_interp_filter_match(
677*77c1e3ccSAndroid Build Coastguard Worker mbmi, cpi, assign_filter, need_search, args->interp_filter_stats,
678*77c1e3ccSAndroid Build Coastguard Worker args->interp_filter_stats_idx);
679*77c1e3ccSAndroid Build Coastguard Worker
680*77c1e3ccSAndroid Build Coastguard Worker if (match_found_idx != -1) {
681*77c1e3ccSAndroid Build Coastguard Worker *rd = args->interp_filter_stats[match_found_idx].rd;
682*77c1e3ccSAndroid Build Coastguard Worker x->pred_sse[ref_frame] =
683*77c1e3ccSAndroid Build Coastguard Worker args->interp_filter_stats[match_found_idx].pred_sse;
684*77c1e3ccSAndroid Build Coastguard Worker *skip_build_pred = 0;
685*77c1e3ccSAndroid Build Coastguard Worker return 0;
686*77c1e3ccSAndroid Build Coastguard Worker }
687*77c1e3ccSAndroid Build Coastguard Worker
688*77c1e3ccSAndroid Build Coastguard Worker int switchable_ctx[2];
689*77c1e3ccSAndroid Build Coastguard Worker switchable_ctx[0] = av1_get_pred_context_switchable_interp(xd, 0);
690*77c1e3ccSAndroid Build Coastguard Worker switchable_ctx[1] = av1_get_pred_context_switchable_interp(xd, 1);
691*77c1e3ccSAndroid Build Coastguard Worker *switchable_rate =
692*77c1e3ccSAndroid Build Coastguard Worker get_switchable_rate(x, mbmi->interp_filters, switchable_ctx,
693*77c1e3ccSAndroid Build Coastguard Worker cm->seq_params->enable_dual_filter);
694*77c1e3ccSAndroid Build Coastguard Worker
695*77c1e3ccSAndroid Build Coastguard Worker // Do MC evaluation for default filter_type.
696*77c1e3ccSAndroid Build Coastguard Worker // Luma MC
697*77c1e3ccSAndroid Build Coastguard Worker interp_model_rd_eval(x, cpi, bsize, orig_dst, AOM_PLANE_Y, AOM_PLANE_Y,
698*77c1e3ccSAndroid Build Coastguard Worker &rd_stats_luma, *skip_build_pred);
699*77c1e3ccSAndroid Build Coastguard Worker
700*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_COLLECT_RD_STATS == 3
701*77c1e3ccSAndroid Build Coastguard Worker RD_STATS rd_stats_y;
702*77c1e3ccSAndroid Build Coastguard Worker av1_pick_recursive_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize, INT64_MAX);
703*77c1e3ccSAndroid Build Coastguard Worker PrintPredictionUnitStats(cpi, tile_data, x, &rd_stats_y, bsize);
704*77c1e3ccSAndroid Build Coastguard Worker #endif // CONFIG_COLLECT_RD_STATS == 3
705*77c1e3ccSAndroid Build Coastguard Worker // Chroma MC
706*77c1e3ccSAndroid Build Coastguard Worker if (num_planes > 1) {
707*77c1e3ccSAndroid Build Coastguard Worker interp_model_rd_eval(x, cpi, bsize, orig_dst, AOM_PLANE_U, AOM_PLANE_V,
708*77c1e3ccSAndroid Build Coastguard Worker &rd_stats, *skip_build_pred);
709*77c1e3ccSAndroid Build Coastguard Worker }
710*77c1e3ccSAndroid Build Coastguard Worker *skip_build_pred = 1;
711*77c1e3ccSAndroid Build Coastguard Worker
712*77c1e3ccSAndroid Build Coastguard Worker av1_merge_rd_stats(&rd_stats, &rd_stats_luma);
713*77c1e3ccSAndroid Build Coastguard Worker
714*77c1e3ccSAndroid Build Coastguard Worker assert(rd_stats.rate >= 0);
715*77c1e3ccSAndroid Build Coastguard Worker
716*77c1e3ccSAndroid Build Coastguard Worker *rd = RDCOST(x->rdmult, *switchable_rate + rd_stats.rate, rd_stats.dist);
717*77c1e3ccSAndroid Build Coastguard Worker x->pred_sse[ref_frame] = (unsigned int)(rd_stats_luma.sse >> 4);
718*77c1e3ccSAndroid Build Coastguard Worker
719*77c1e3ccSAndroid Build Coastguard Worker if (assign_filter != SWITCHABLE || match_found_idx != -1) {
720*77c1e3ccSAndroid Build Coastguard Worker return 0;
721*77c1e3ccSAndroid Build Coastguard Worker }
722*77c1e3ccSAndroid Build Coastguard Worker if (!need_search) {
723*77c1e3ccSAndroid Build Coastguard Worker int_interpfilters filters = av1_broadcast_interp_filter(EIGHTTAP_REGULAR);
724*77c1e3ccSAndroid Build Coastguard Worker assert(mbmi->interp_filters.as_int == filters.as_int);
725*77c1e3ccSAndroid Build Coastguard Worker (void)filters;
726*77c1e3ccSAndroid Build Coastguard Worker return 0;
727*77c1e3ccSAndroid Build Coastguard Worker }
728*77c1e3ccSAndroid Build Coastguard Worker if (args->modelled_rd != NULL) {
729*77c1e3ccSAndroid Build Coastguard Worker if (has_second_ref(mbmi)) {
730*77c1e3ccSAndroid Build Coastguard Worker const int ref_mv_idx = mbmi->ref_mv_idx;
731*77c1e3ccSAndroid Build Coastguard Worker MV_REFERENCE_FRAME *refs = mbmi->ref_frame;
732*77c1e3ccSAndroid Build Coastguard Worker const int mode0 = compound_ref0_mode(mbmi->mode);
733*77c1e3ccSAndroid Build Coastguard Worker const int mode1 = compound_ref1_mode(mbmi->mode);
734*77c1e3ccSAndroid Build Coastguard Worker const int64_t mrd = AOMMIN(args->modelled_rd[mode0][ref_mv_idx][refs[0]],
735*77c1e3ccSAndroid Build Coastguard Worker args->modelled_rd[mode1][ref_mv_idx][refs[1]]);
736*77c1e3ccSAndroid Build Coastguard Worker if ((*rd >> 1) > mrd && ref_best_rd < INT64_MAX) {
737*77c1e3ccSAndroid Build Coastguard Worker return INT64_MAX;
738*77c1e3ccSAndroid Build Coastguard Worker }
739*77c1e3ccSAndroid Build Coastguard Worker }
740*77c1e3ccSAndroid Build Coastguard Worker }
741*77c1e3ccSAndroid Build Coastguard Worker
742*77c1e3ccSAndroid Build Coastguard Worker x->recalc_luma_mc_data = 0;
743*77c1e3ccSAndroid Build Coastguard Worker // skip_flag=xx (in binary form)
744*77c1e3ccSAndroid Build Coastguard Worker // Setting 0th flag corresonds to skipping luma MC and setting 1st bt
745*77c1e3ccSAndroid Build Coastguard Worker // corresponds to skipping chroma MC skip_flag=0 corresponds to "Don't skip
746*77c1e3ccSAndroid Build Coastguard Worker // luma and chroma MC" Skip flag=1 corresponds to "Skip Luma MC only"
747*77c1e3ccSAndroid Build Coastguard Worker // Skip_flag=2 is not a valid case
748*77c1e3ccSAndroid Build Coastguard Worker // skip_flag=3 corresponds to "Skip both luma and chroma MC"
749*77c1e3ccSAndroid Build Coastguard Worker int skip_hor = interp_search_flags->default_interp_skip_flags;
750*77c1e3ccSAndroid Build Coastguard Worker int skip_ver = interp_search_flags->default_interp_skip_flags;
751*77c1e3ccSAndroid Build Coastguard Worker calc_interp_skip_pred_flag(x, cpi, &skip_hor, &skip_ver);
752*77c1e3ccSAndroid Build Coastguard Worker
753*77c1e3ccSAndroid Build Coastguard Worker // do interp_filter search
754*77c1e3ccSAndroid Build Coastguard Worker restore_dst_buf(xd, *tmp_dst, num_planes);
755*77c1e3ccSAndroid Build Coastguard Worker const BUFFER_SET *dst_bufs[2] = { tmp_dst, orig_dst };
756*77c1e3ccSAndroid Build Coastguard Worker // Evaluate dual interp filters
757*77c1e3ccSAndroid Build Coastguard Worker if (cm->seq_params->enable_dual_filter) {
758*77c1e3ccSAndroid Build Coastguard Worker if (cpi->sf.interp_sf.use_fast_interpolation_filter_search) {
759*77c1e3ccSAndroid Build Coastguard Worker fast_dual_interp_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
760*77c1e3ccSAndroid Build Coastguard Worker &rd_stats_luma, &rd_stats, switchable_rate,
761*77c1e3ccSAndroid Build Coastguard Worker dst_bufs, switchable_ctx, skip_hor, skip_ver);
762*77c1e3ccSAndroid Build Coastguard Worker } else {
763*77c1e3ccSAndroid Build Coastguard Worker // Use full interpolation filter search
764*77c1e3ccSAndroid Build Coastguard Worker uint16_t allowed_interp_mask = ALLOW_ALL_INTERP_FILT_MASK;
765*77c1e3ccSAndroid Build Coastguard Worker // REG_REG filter type is evaluated beforehand, so loop is repeated over
766*77c1e3ccSAndroid Build Coastguard Worker // REG_SMOOTH to SHARP_SHARP for full interpolation filter search
767*77c1e3ccSAndroid Build Coastguard Worker reset_interp_filter_allowed_mask(&allowed_interp_mask, REG_REG);
768*77c1e3ccSAndroid Build Coastguard Worker find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd,
769*77c1e3ccSAndroid Build Coastguard Worker &rd_stats_luma, &rd_stats, switchable_rate,
770*77c1e3ccSAndroid Build Coastguard Worker dst_bufs, switchable_ctx,
771*77c1e3ccSAndroid Build Coastguard Worker (skip_hor & skip_ver), allowed_interp_mask, 0);
772*77c1e3ccSAndroid Build Coastguard Worker }
773*77c1e3ccSAndroid Build Coastguard Worker } else {
774*77c1e3ccSAndroid Build Coastguard Worker // Evaluate non-dual interp filters
775*77c1e3ccSAndroid Build Coastguard Worker find_best_non_dual_interp_filter(
776*77c1e3ccSAndroid Build Coastguard Worker x, cpi, tile_data, bsize, orig_dst, rd, &rd_stats_luma, &rd_stats,
777*77c1e3ccSAndroid Build Coastguard Worker switchable_rate, dst_bufs, switchable_ctx, skip_ver, skip_hor);
778*77c1e3ccSAndroid Build Coastguard Worker }
779*77c1e3ccSAndroid Build Coastguard Worker swap_dst_buf(xd, dst_bufs, num_planes);
780*77c1e3ccSAndroid Build Coastguard Worker // Recompute final MC data if required
781*77c1e3ccSAndroid Build Coastguard Worker if (x->recalc_luma_mc_data == 1) {
782*77c1e3ccSAndroid Build Coastguard Worker // Recomputing final luma MC data is required only if the same was skipped
783*77c1e3ccSAndroid Build Coastguard Worker // in either of the directions Condition below is necessary, but not
784*77c1e3ccSAndroid Build Coastguard Worker // sufficient
785*77c1e3ccSAndroid Build Coastguard Worker assert((skip_hor == 1) || (skip_ver == 1));
786*77c1e3ccSAndroid Build Coastguard Worker const int mi_row = xd->mi_row;
787*77c1e3ccSAndroid Build Coastguard Worker const int mi_col = xd->mi_col;
788*77c1e3ccSAndroid Build Coastguard Worker av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize,
789*77c1e3ccSAndroid Build Coastguard Worker AOM_PLANE_Y, AOM_PLANE_Y);
790*77c1e3ccSAndroid Build Coastguard Worker }
791*77c1e3ccSAndroid Build Coastguard Worker x->pred_sse[ref_frame] = (unsigned int)(rd_stats_luma.sse >> 4);
792*77c1e3ccSAndroid Build Coastguard Worker
793*77c1e3ccSAndroid Build Coastguard Worker // save search results
794*77c1e3ccSAndroid Build Coastguard Worker if (cpi->sf.interp_sf.use_interp_filter) {
795*77c1e3ccSAndroid Build Coastguard Worker assert(match_found_idx == -1);
796*77c1e3ccSAndroid Build Coastguard Worker args->interp_filter_stats_idx = save_interp_filter_search_stat(
797*77c1e3ccSAndroid Build Coastguard Worker mbmi, *rd, x->pred_sse[ref_frame], args->interp_filter_stats,
798*77c1e3ccSAndroid Build Coastguard Worker args->interp_filter_stats_idx);
799*77c1e3ccSAndroid Build Coastguard Worker }
800*77c1e3ccSAndroid Build Coastguard Worker return 0;
801*77c1e3ccSAndroid Build Coastguard Worker }
802