Coverage Report

Created: 2025-11-09 06:20

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