Coverage Report

Created: 2026-07-25 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/aom/av1/encoder/tx_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 <inttypes.h>
13
14
#include "av1/common/cfl.h"
15
#include "av1/common/reconintra.h"
16
#include "av1/encoder/block.h"
17
#include "av1/encoder/hybrid_fwd_txfm.h"
18
#include "av1/common/idct.h"
19
#include "av1/encoder/model_rd.h"
20
#include "av1/encoder/random.h"
21
#include "av1/encoder/rdopt_utils.h"
22
#include "av1/encoder/sorting_network.h"
23
#include "av1/encoder/tx_prune_model_weights.h"
24
#include "av1/encoder/tx_search.h"
25
#include "av1/encoder/txb_rdopt.h"
26
27
0
#define PROB_THRESH_OFFSET_TX_TYPE 100
28
29
struct rdcost_block_args {
30
  const AV1_COMP *cpi;
31
  MACROBLOCK *x;
32
  ENTROPY_CONTEXT t_above[MAX_MIB_SIZE];
33
  ENTROPY_CONTEXT t_left[MAX_MIB_SIZE];
34
  RD_STATS rd_stats;
35
  int64_t current_rd;
36
  int64_t best_rd;
37
  int exit_early;
38
  int incomplete_exit;
39
  FAST_TX_SEARCH_MODE ftxs_mode;
40
  int skip_trellis;
41
};
42
43
typedef struct {
44
  int64_t rd;
45
  int txb_entropy_ctx;
46
  TX_TYPE tx_type;
47
} TxCandidateInfo;
48
49
// origin_threshold * 128 / 100
50
static const uint32_t skip_pred_threshold[3][BLOCK_SIZES_ALL] = {
51
  {
52
      64, 64, 64, 70, 60, 60, 68, 68, 68, 68, 68,
53
      68, 68, 68, 68, 68, 64, 64, 70, 70, 68, 68,
54
  },
55
  {
56
      88, 88, 88, 86, 87, 87, 68, 68, 68, 68, 68,
57
      68, 68, 68, 68, 68, 88, 88, 86, 86, 68, 68,
58
  },
59
  {
60
      90, 93, 93, 90, 93, 93, 74, 74, 74, 74, 74,
61
      74, 74, 74, 74, 74, 90, 90, 90, 90, 74, 74,
62
  },
63
};
64
65
// lookup table for predict_skip_txfm
66
// int max_tx_size = max_txsize_rect_lookup[bsize];
67
// if (tx_size_high[max_tx_size] > 16 || tx_size_wide[max_tx_size] > 16)
68
//   max_tx_size = AOMMIN(max_txsize_lookup[bsize], TX_16X16);
69
static const TX_SIZE max_predict_sf_tx_size[BLOCK_SIZES_ALL] = {
70
  TX_4X4,   TX_4X8,   TX_8X4,   TX_8X8,   TX_8X16,  TX_16X8,
71
  TX_16X16, TX_16X16, TX_16X16, TX_16X16, TX_16X16, TX_16X16,
72
  TX_16X16, TX_16X16, TX_16X16, TX_16X16, TX_4X16,  TX_16X4,
73
  TX_8X8,   TX_8X8,   TX_16X16, TX_16X16,
74
};
75
76
// look-up table for sqrt of number of pixels in a transform block
77
// rounded up to the nearest integer.
78
static const int sqrt_tx_pixels_2d[TX_SIZES_ALL] = { 4,  8,  16, 32, 32, 6,  6,
79
                                                     12, 12, 23, 23, 32, 32, 8,
80
                                                     8,  16, 16, 23, 23 };
81
82
// look-up table for number of top no-split RD Costs that should be considered
83
// based on prune_inter_tx_split_rd_eval_lvl speed feature.
84
static const int num_inter_tx_no_split_cand[2] = { 4, 3 };
85
86
0
static inline uint32_t get_block_residue_hash(MACROBLOCK *x, BLOCK_SIZE bsize) {
87
0
  const int rows = block_size_high[bsize];
88
0
  const int cols = block_size_wide[bsize];
89
0
  const int16_t *diff = x->plane[0].src_diff;
90
0
  const uint32_t hash =
91
0
      av1_get_crc32c_value(&x->txfm_search_info.mb_rd_record->crc_calculator,
92
0
                           (uint8_t *)diff, 2 * rows * cols);
93
0
  return (hash << 5) + bsize;
94
0
}
95
96
static inline int32_t find_mb_rd_info(const MB_RD_RECORD *const mb_rd_record,
97
                                      const int64_t ref_best_rd,
98
0
                                      const uint32_t hash) {
99
0
  int32_t match_index = -1;
100
0
  if (ref_best_rd != INT64_MAX) {
101
0
    for (int i = 0; i < mb_rd_record->num; ++i) {
102
0
      const int index = (mb_rd_record->index_start + i) % RD_RECORD_BUFFER_LEN;
103
      // If there is a match in the mb_rd_record, fetch the RD decision and
104
      // terminate early.
105
0
      if (mb_rd_record->mb_rd_info[index].hash_value == hash) {
106
0
        match_index = index;
107
0
        break;
108
0
      }
109
0
    }
110
0
  }
111
0
  return match_index;
112
0
}
113
114
static inline void fetch_mb_rd_info(int n4, const MB_RD_INFO *const mb_rd_info,
115
                                    RD_STATS *const rd_stats,
116
0
                                    MACROBLOCK *const x) {
117
0
  MACROBLOCKD *const xd = &x->e_mbd;
118
0
  MB_MODE_INFO *const mbmi = xd->mi[0];
119
0
  mbmi->tx_size = mb_rd_info->tx_size;
120
0
  av1_copy(mbmi->inter_tx_size, mb_rd_info->inter_tx_size);
121
0
  av1_copy_array(xd->tx_type_map, mb_rd_info->tx_type_map, n4);
122
0
  *rd_stats = mb_rd_info->rd_stats;
123
0
}
124
125
int64_t av1_pixel_diff_dist(const MACROBLOCK *x, int plane, int blk_row,
126
                            int blk_col, const BLOCK_SIZE plane_bsize,
127
                            const BLOCK_SIZE tx_bsize,
128
0
                            unsigned int *block_mse_q8) {
129
0
  int visible_rows, visible_cols;
130
0
  const int txb_cols = block_size_wide[tx_bsize];
131
0
  const int txb_rows = block_size_high[tx_bsize];
132
0
  get_visible_dimensions(x, plane, plane_bsize, blk_col, blk_row, txb_cols,
133
0
                         txb_rows, /*clip_dims=*/true, &visible_cols,
134
0
                         &visible_rows);
135
136
0
  uint64_t sse = 0;
137
0
  if (visible_cols > 0 && visible_rows > 0) {
138
0
    const int diff_stride = block_size_wide[plane_bsize];
139
0
    const int16_t *diff = x->plane[plane].src_diff;
140
141
0
    diff += ((blk_row * diff_stride + blk_col) << MI_SIZE_LOG2);
142
0
    sse = aom_sum_squares_2d_i16(diff, diff_stride, visible_cols, visible_rows);
143
0
    if (block_mse_q8 != NULL) {
144
0
      *block_mse_q8 =
145
0
          (unsigned int)((256 * sse) / (visible_cols * visible_rows));
146
0
    }
147
0
  } else {
148
0
    if (block_mse_q8 != NULL) *block_mse_q8 = 0;
149
0
  }
150
0
  return sse;
151
0
}
152
153
// Computes the residual block's SSE and mean on all visible 4x4s in the
154
// transform block
155
static inline int64_t pixel_diff_stats(
156
    MACROBLOCK *x, int plane, int blk_row, int blk_col,
157
    const BLOCK_SIZE plane_bsize, const BLOCK_SIZE tx_bsize,
158
0
    unsigned int *block_mse_q8, int64_t *per_px_mean, uint64_t *block_var) {
159
0
  int visible_rows, visible_cols;
160
0
  const int txb_cols = block_size_wide[tx_bsize];
161
0
  const int txb_rows = block_size_high[tx_bsize];
162
0
  get_visible_dimensions(x, plane, plane_bsize, blk_col, blk_row, txb_cols,
163
0
                         txb_rows, /*clip_dims=*/true, &visible_cols,
164
0
                         &visible_rows);
165
166
0
  uint64_t sse = 0;
167
0
  if (visible_cols > 0 && visible_rows > 0) {
168
0
    const int diff_stride = block_size_wide[plane_bsize];
169
0
    const int16_t *diff = x->plane[plane].src_diff;
170
171
0
    diff += ((blk_row * diff_stride + blk_col) << MI_SIZE_LOG2);
172
0
    int sum = 0;
173
0
    sse =
174
0
        aom_sum_sse_2d_i16(diff, diff_stride, visible_cols, visible_rows, &sum);
175
0
    double norm_factor = 1.0 / (visible_cols * visible_rows);
176
0
    int sign_sum = sum > 0 ? 1 : -1;
177
    // Conversion to transform domain
178
0
    *per_px_mean = (int64_t)(norm_factor * abs(sum)) << 7;
179
0
    *per_px_mean = sign_sum * (*per_px_mean);
180
0
    *block_mse_q8 = (unsigned int)(norm_factor * (256 * sse));
181
0
    *block_var = (uint64_t)(sse - (uint64_t)(norm_factor * sum * sum));
182
0
  } else {
183
0
    *block_mse_q8 = 0;
184
0
    *block_var = 0;
185
0
    *per_px_mean = 0;
186
0
  }
187
0
  return sse;
188
0
}
189
190
// Uses simple features on top of DCT coefficients to quickly predict
191
// whether optimal RD decision is to skip encoding the residual.
192
// The sse value is stored in dist.
193
static int predict_skip_txfm(MACROBLOCK *x, BLOCK_SIZE bsize, int64_t *dist,
194
0
                             int reduced_tx_set) {
195
0
  const TxfmSearchParams *txfm_params = &x->txfm_search_params;
196
0
  const int bw = block_size_wide[bsize];
197
0
  const int bh = block_size_high[bsize];
198
0
  const MACROBLOCKD *xd = &x->e_mbd;
199
0
  const int16_t dc_q = av1_dc_quant_QTX(x->qindex, 0, xd->bd);
200
201
0
  *dist = av1_pixel_diff_dist(x, 0, 0, 0, bsize, bsize, NULL);
202
203
0
  const int64_t mse = *dist / bw / bh;
204
  // Normalized quantizer takes the transform upscaling factor (8 for tx size
205
  // smaller than 32) into account.
206
0
  const int16_t normalized_dc_q = dc_q >> 3;
207
0
  const int64_t mse_thresh = (int64_t)normalized_dc_q * normalized_dc_q / 8;
208
  // For faster early skip decision, use dist to compare against threshold so
209
  // that quality risk is less for the skip=1 decision. Otherwise, use mse
210
  // since the fwd_txfm coeff checks will take care of quality
211
  // TODO(any): Use dist to return 0 when skip_txfm_level is 1
212
0
  int64_t pred_err = (txfm_params->skip_txfm_level >= 2) ? *dist : mse;
213
  // Predict not to skip when error is larger than threshold.
214
0
  if (pred_err > mse_thresh) return 0;
215
  // Return as skip otherwise for aggressive early skip
216
0
  else if (txfm_params->skip_txfm_level >= 2)
217
0
    return 1;
218
219
0
  const int max_tx_size = max_predict_sf_tx_size[bsize];
220
0
  const int tx_h = tx_size_high[max_tx_size];
221
0
  const int tx_w = tx_size_wide[max_tx_size];
222
0
  DECLARE_ALIGNED(32, tran_low_t, coefs[32 * 32]);
223
0
  TxfmParam param;
224
0
  param.tx_type = DCT_DCT;
225
0
  param.tx_size = max_tx_size;
226
0
  param.bd = xd->bd;
227
0
  param.is_hbd = is_cur_buf_hbd(xd);
228
0
  param.lossless = 0;
229
0
  param.tx_set_type = av1_get_ext_tx_set_type(
230
0
      param.tx_size, is_inter_block(xd->mi[0]), reduced_tx_set);
231
0
  const int bd_idx = (xd->bd == 8) ? 0 : ((xd->bd == 10) ? 1 : 2);
232
0
  const uint32_t max_qcoef_thresh = skip_pred_threshold[bd_idx][bsize];
233
0
  const int16_t *src_diff = x->plane[0].src_diff;
234
0
  const int n_coeff = tx_w * tx_h;
235
0
  const int16_t ac_q = av1_ac_quant_QTX(x->qindex, 0, xd->bd);
236
0
  const uint32_t dc_thresh = max_qcoef_thresh * dc_q;
237
0
  const uint32_t ac_thresh = max_qcoef_thresh * ac_q;
238
0
  for (int row = 0; row < bh; row += tx_h) {
239
0
    for (int col = 0; col < bw; col += tx_w) {
240
0
      av1_fwd_txfm(src_diff + col, coefs, bw, &param);
241
      // Operating on TX domain, not pixels; we want the QTX quantizers
242
0
      const uint32_t dc_coef = (((uint32_t)abs(coefs[0])) << 7);
243
0
      if (dc_coef >= dc_thresh) return 0;
244
0
      for (int i = 1; i < n_coeff; ++i) {
245
0
        const uint32_t ac_coef = (((uint32_t)abs(coefs[i])) << 7);
246
0
        if (ac_coef >= ac_thresh) return 0;
247
0
      }
248
0
    }
249
0
    src_diff += tx_h * bw;
250
0
  }
251
0
  return 1;
252
0
}
253
254
// Used to set proper context for early termination with skip = 1.
255
static inline void set_skip_txfm(MACROBLOCK *x, RD_STATS *rd_stats,
256
0
                                 BLOCK_SIZE bsize, int64_t dist) {
257
0
  MACROBLOCKD *const xd = &x->e_mbd;
258
0
  MB_MODE_INFO *const mbmi = xd->mi[0];
259
0
  const int n4 = bsize_to_num_blk(bsize);
260
0
  const TX_SIZE tx_size = max_txsize_rect_lookup[bsize];
261
0
  memset(xd->tx_type_map, DCT_DCT, sizeof(xd->tx_type_map[0]) * n4);
262
0
  memset(mbmi->inter_tx_size, tx_size, sizeof(mbmi->inter_tx_size));
263
0
  mbmi->tx_size = tx_size;
264
0
  rd_stats->skip_txfm = 1;
265
0
  if (is_cur_buf_hbd(xd)) dist = ROUND_POWER_OF_TWO(dist, (xd->bd - 8) * 2);
266
0
  rd_stats->dist = rd_stats->sse = (dist << 4);
267
  // Though decision is to make the block as skip based on luma stats,
268
  // it is possible that block becomes non skip after chroma rd. In addition
269
  // intermediate non skip costs calculated by caller function will be
270
  // incorrect, if rate is set as  zero (i.e., if zero_blk_rate is not
271
  // accounted). Hence intermediate rate is populated to code the luma tx blks
272
  // as skip, the caller function based on final rd decision (i.e., skip vs
273
  // non-skip) sets the final rate accordingly. Here the rate populated
274
  // corresponds to coding all the tx blocks with zero_blk_rate (based on max tx
275
  // size possible) in the current block. Eg: For 128*128 block, rate would be
276
  // 4 * zero_blk_rate where zero_blk_rate corresponds to coding of one 64x64 tx
277
  // block as 'all zeros'
278
0
  ENTROPY_CONTEXT ctxa[MAX_MIB_SIZE];
279
0
  ENTROPY_CONTEXT ctxl[MAX_MIB_SIZE];
280
0
  av1_get_entropy_contexts(bsize, &xd->plane[0], ctxa, ctxl);
281
0
  ENTROPY_CONTEXT *ta = ctxa;
282
0
  ENTROPY_CONTEXT *tl = ctxl;
283
0
  const TX_SIZE txs_ctx = get_txsize_entropy_ctx(tx_size);
284
0
  TXB_CTX txb_ctx;
285
0
  get_txb_ctx(bsize, tx_size, 0, ta, tl, &txb_ctx);
286
0
  const int zero_blk_rate = x->coeff_costs.coeff_costs[txs_ctx][PLANE_TYPE_Y]
287
0
                                .txb_skip_cost[txb_ctx.txb_skip_ctx][1];
288
0
  rd_stats->rate = zero_blk_rate *
289
0
                   (block_size_wide[bsize] >> tx_size_wide_log2[tx_size]) *
290
0
                   (block_size_high[bsize] >> tx_size_high_log2[tx_size]);
291
0
}
292
293
static inline void save_mb_rd_info(int n4, uint32_t hash,
294
                                   const MACROBLOCK *const x,
295
                                   const RD_STATS *const rd_stats,
296
0
                                   MB_RD_RECORD *mb_rd_record) {
297
0
  int index;
298
0
  if (mb_rd_record->num < RD_RECORD_BUFFER_LEN) {
299
0
    index =
300
0
        (mb_rd_record->index_start + mb_rd_record->num) % RD_RECORD_BUFFER_LEN;
301
0
    ++mb_rd_record->num;
302
0
  } else {
303
0
    index = mb_rd_record->index_start;
304
0
    mb_rd_record->index_start =
305
0
        (mb_rd_record->index_start + 1) % RD_RECORD_BUFFER_LEN;
306
0
  }
307
0
  MB_RD_INFO *const mb_rd_info = &mb_rd_record->mb_rd_info[index];
308
0
  const MACROBLOCKD *const xd = &x->e_mbd;
309
0
  const MB_MODE_INFO *const mbmi = xd->mi[0];
310
0
  mb_rd_info->hash_value = hash;
311
0
  mb_rd_info->tx_size = mbmi->tx_size;
312
0
  av1_copy(mb_rd_info->inter_tx_size, mbmi->inter_tx_size);
313
0
  av1_copy_array(mb_rd_info->tx_type_map, xd->tx_type_map, n4);
314
0
  mb_rd_info->rd_stats = *rd_stats;
315
0
}
316
317
// Store the RD Cost of transform no-split.
318
static inline void push_inter_block_tx_no_split_rd(
319
    MACROBLOCK *x, const MB_MODE_INFO *mbmi, int64_t tmp_rd, int blk_idx,
320
0
    int prune_inter_tx_split_rd_eval_lvl) {
321
0
  assert(blk_idx < MAX_TX_BLOCKS_IN_MAX_SB);
322
0
  if (!prune_inter_tx_split_rd_eval_lvl) return;
323
324
0
  if (blk_idx == -1 || tmp_rd == INT64_MAX) return;
325
326
  // Do not store for skip and intraBC modes
327
0
  if (mbmi->skip_mode != 0 || is_intrabc_block(mbmi)) return;
328
329
0
  assert(prune_inter_tx_split_rd_eval_lvl <= 2);
330
0
  const int num_top_cand =
331
0
      num_inter_tx_no_split_cand[prune_inter_tx_split_rd_eval_lvl - 1];
332
0
  assert(num_top_cand <= TOP_INTER_TX_NO_SPLIT_COUNT);
333
334
  // Insert the RD Cost in sorted order
335
0
  for (int i = 0; i < num_top_cand; i++) {
336
0
    if (tmp_rd < x->top_inter_tx_no_split_rd[blk_idx][i]) {
337
0
      for (int j = num_top_cand - 1; j > i; j--) {
338
0
        x->top_inter_tx_no_split_rd[blk_idx][j] =
339
0
            x->top_inter_tx_no_split_rd[blk_idx][j - 1];
340
0
      }
341
0
      x->top_inter_tx_no_split_rd[blk_idx][i] = tmp_rd;
342
0
      break;
343
0
    }
344
0
  }
345
0
}
346
347
// Prune the evaluation of transform split.
348
static inline bool prune_tx_split_eval_using_no_split_rd(
349
    const MACROBLOCK *x, const MB_MODE_INFO *mbmi, int64_t tmp_rd, int blk_idx,
350
0
    int prune_inter_tx_split_rd_eval_lvl) {
351
0
  if (!prune_inter_tx_split_rd_eval_lvl) return false;
352
353
0
  if (blk_idx == -1 || tmp_rd == INT64_MAX) return false;
354
355
  // Do not prune for skip and intraBC modes
356
0
  if (mbmi->skip_mode != 0 || is_intrabc_block(mbmi)) return false;
357
358
0
  assert(prune_inter_tx_split_rd_eval_lvl <= 2);
359
0
  const int num_top_cand =
360
0
      num_inter_tx_no_split_cand[prune_inter_tx_split_rd_eval_lvl - 1];
361
0
  assert(num_top_cand <= TOP_INTER_TX_NO_SPLIT_COUNT);
362
363
  // Do not prune if there is no valid top RD Cost for comparison
364
0
  if (x->top_inter_tx_no_split_rd[blk_idx][num_top_cand - 1] == INT64_MAX)
365
0
    return false;
366
367
0
  if (tmp_rd > x->top_inter_tx_no_split_rd[blk_idx][num_top_cand - 1])
368
0
    return true;
369
370
0
  return false;
371
0
}
372
373
static int get_search_init_depth(int mi_width, int mi_height, int is_inter,
374
                                 const SPEED_FEATURES *sf,
375
0
                                 int tx_size_search_method) {
376
0
  if (tx_size_search_method == USE_LARGESTALL) return MAX_VARTX_DEPTH;
377
378
0
  if (sf->tx_sf.tx_size_search_lgr_block) {
379
0
    if (mi_width > mi_size_wide[BLOCK_64X64] ||
380
0
        mi_height > mi_size_high[BLOCK_64X64])
381
0
      return MAX_VARTX_DEPTH;
382
0
  }
383
384
0
  if (is_inter) {
385
0
    return (mi_height != mi_width)
386
0
               ? sf->tx_sf.inter_tx_size_search_init_depth_rect
387
0
               : sf->tx_sf.inter_tx_size_search_init_depth_sqr;
388
0
  } else {
389
0
    return (mi_height != mi_width)
390
0
               ? sf->tx_sf.intra_tx_size_search_init_depth_rect
391
0
               : sf->tx_sf.intra_tx_size_search_init_depth_sqr;
392
0
  }
393
0
}
394
395
static inline void select_tx_block(
396
    const AV1_COMP *cpi, MACROBLOCK *x, int blk_row, int blk_col, int block,
397
    TX_SIZE tx_size, int depth, BLOCK_SIZE plane_bsize, ENTROPY_CONTEXT *ta,
398
    ENTROPY_CONTEXT *tl, TXFM_CONTEXT *tx_above, TXFM_CONTEXT *tx_left,
399
    RD_STATS *rd_stats, int64_t prev_level_rd, int64_t ref_best_rd,
400
    int *is_cost_valid, FAST_TX_SEARCH_MODE ftxs_mode, int blk_idx);
401
402
// NOTE: CONFIG_COLLECT_RD_STATS has 3 possible values
403
// 0: Do not collect any RD stats
404
// 1: Collect RD stats for transform units
405
// 2: Collect RD stats for partition units
406
#if CONFIG_COLLECT_RD_STATS
407
408
static inline void get_energy_distribution_fine(
409
    const AV1_COMP *cpi, BLOCK_SIZE bsize, const uint8_t *src, int src_stride,
410
    const uint8_t *dst, int dst_stride, int need_4th, double *hordist,
411
    double *verdist) {
412
  const int bw = block_size_wide[bsize];
413
  const int bh = block_size_high[bsize];
414
  unsigned int esq[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
415
416
  if (bsize < BLOCK_16X16 || (bsize >= BLOCK_4X16 && bsize <= BLOCK_32X8)) {
417
    // Special cases: calculate 'esq' values manually, as we don't have 'vf'
418
    // functions for the 16 (very small) sub-blocks of this block.
419
    const int w_shift = (bw == 4) ? 0 : (bw == 8) ? 1 : (bw == 16) ? 2 : 3;
420
    const int h_shift = (bh == 4) ? 0 : (bh == 8) ? 1 : (bh == 16) ? 2 : 3;
421
    assert(bw <= 32);
422
    assert(bh <= 32);
423
    assert(((bw - 1) >> w_shift) + (((bh - 1) >> h_shift) << 2) == 15);
424
    if (cpi->common.seq_params->use_highbitdepth) {
425
      const uint16_t *src16 = CONVERT_TO_SHORTPTR(src);
426
      const uint16_t *dst16 = CONVERT_TO_SHORTPTR(dst);
427
      for (int i = 0; i < bh; ++i)
428
        for (int j = 0; j < bw; ++j) {
429
          const int index = (j >> w_shift) + ((i >> h_shift) << 2);
430
          esq[index] +=
431
              (src16[j + i * src_stride] - dst16[j + i * dst_stride]) *
432
              (src16[j + i * src_stride] - dst16[j + i * dst_stride]);
433
        }
434
    } else {
435
      for (int i = 0; i < bh; ++i)
436
        for (int j = 0; j < bw; ++j) {
437
          const int index = (j >> w_shift) + ((i >> h_shift) << 2);
438
          esq[index] += (src[j + i * src_stride] - dst[j + i * dst_stride]) *
439
                        (src[j + i * src_stride] - dst[j + i * dst_stride]);
440
        }
441
    }
442
  } else {  // Calculate 'esq' values using 'vf' functions on the 16 sub-blocks.
443
    const int f_index =
444
        (bsize < BLOCK_SIZES) ? bsize - BLOCK_16X16 : bsize - BLOCK_8X16;
445
    assert(f_index >= 0 && f_index < BLOCK_SIZES_ALL);
446
    const BLOCK_SIZE subsize = (BLOCK_SIZE)f_index;
447
    assert(block_size_wide[bsize] == 4 * block_size_wide[subsize]);
448
    assert(block_size_high[bsize] == 4 * block_size_high[subsize]);
449
    cpi->ppi->fn_ptr[subsize].vf(src, src_stride, dst, dst_stride, &esq[0]);
450
    cpi->ppi->fn_ptr[subsize].vf(src + bw / 4, src_stride, dst + bw / 4,
451
                                 dst_stride, &esq[1]);
452
    cpi->ppi->fn_ptr[subsize].vf(src + bw / 2, src_stride, dst + bw / 2,
453
                                 dst_stride, &esq[2]);
454
    cpi->ppi->fn_ptr[subsize].vf(src + 3 * bw / 4, src_stride, dst + 3 * bw / 4,
455
                                 dst_stride, &esq[3]);
456
    src += bh / 4 * src_stride;
457
    dst += bh / 4 * dst_stride;
458
459
    cpi->ppi->fn_ptr[subsize].vf(src, src_stride, dst, dst_stride, &esq[4]);
460
    cpi->ppi->fn_ptr[subsize].vf(src + bw / 4, src_stride, dst + bw / 4,
461
                                 dst_stride, &esq[5]);
462
    cpi->ppi->fn_ptr[subsize].vf(src + bw / 2, src_stride, dst + bw / 2,
463
                                 dst_stride, &esq[6]);
464
    cpi->ppi->fn_ptr[subsize].vf(src + 3 * bw / 4, src_stride, dst + 3 * bw / 4,
465
                                 dst_stride, &esq[7]);
466
    src += bh / 4 * src_stride;
467
    dst += bh / 4 * dst_stride;
468
469
    cpi->ppi->fn_ptr[subsize].vf(src, src_stride, dst, dst_stride, &esq[8]);
470
    cpi->ppi->fn_ptr[subsize].vf(src + bw / 4, src_stride, dst + bw / 4,
471
                                 dst_stride, &esq[9]);
472
    cpi->ppi->fn_ptr[subsize].vf(src + bw / 2, src_stride, dst + bw / 2,
473
                                 dst_stride, &esq[10]);
474
    cpi->ppi->fn_ptr[subsize].vf(src + 3 * bw / 4, src_stride, dst + 3 * bw / 4,
475
                                 dst_stride, &esq[11]);
476
    src += bh / 4 * src_stride;
477
    dst += bh / 4 * dst_stride;
478
479
    cpi->ppi->fn_ptr[subsize].vf(src, src_stride, dst, dst_stride, &esq[12]);
480
    cpi->ppi->fn_ptr[subsize].vf(src + bw / 4, src_stride, dst + bw / 4,
481
                                 dst_stride, &esq[13]);
482
    cpi->ppi->fn_ptr[subsize].vf(src + bw / 2, src_stride, dst + bw / 2,
483
                                 dst_stride, &esq[14]);
484
    cpi->ppi->fn_ptr[subsize].vf(src + 3 * bw / 4, src_stride, dst + 3 * bw / 4,
485
                                 dst_stride, &esq[15]);
486
  }
487
488
  double total = (double)esq[0] + esq[1] + esq[2] + esq[3] + esq[4] + esq[5] +
489
                 esq[6] + esq[7] + esq[8] + esq[9] + esq[10] + esq[11] +
490
                 esq[12] + esq[13] + esq[14] + esq[15];
491
  if (total > 0) {
492
    const double e_recip = 1.0 / total;
493
    hordist[0] = ((double)esq[0] + esq[4] + esq[8] + esq[12]) * e_recip;
494
    hordist[1] = ((double)esq[1] + esq[5] + esq[9] + esq[13]) * e_recip;
495
    hordist[2] = ((double)esq[2] + esq[6] + esq[10] + esq[14]) * e_recip;
496
    if (need_4th) {
497
      hordist[3] = ((double)esq[3] + esq[7] + esq[11] + esq[15]) * e_recip;
498
    }
499
    verdist[0] = ((double)esq[0] + esq[1] + esq[2] + esq[3]) * e_recip;
500
    verdist[1] = ((double)esq[4] + esq[5] + esq[6] + esq[7]) * e_recip;
501
    verdist[2] = ((double)esq[8] + esq[9] + esq[10] + esq[11]) * e_recip;
502
    if (need_4th) {
503
      verdist[3] = ((double)esq[12] + esq[13] + esq[14] + esq[15]) * e_recip;
504
    }
505
  } else {
506
    hordist[0] = verdist[0] = 0.25;
507
    hordist[1] = verdist[1] = 0.25;
508
    hordist[2] = verdist[2] = 0.25;
509
    if (need_4th) {
510
      hordist[3] = verdist[3] = 0.25;
511
    }
512
  }
513
}
514
515
static double get_sse_norm(const int16_t *diff, int stride, int w, int h) {
516
  double sum = 0.0;
517
  for (int j = 0; j < h; ++j) {
518
    for (int i = 0; i < w; ++i) {
519
      const int err = diff[j * stride + i];
520
      sum += err * err;
521
    }
522
  }
523
  assert(w > 0 && h > 0);
524
  return sum / (w * h);
525
}
526
527
static double get_sad_norm(const int16_t *diff, int stride, int w, int h) {
528
  double sum = 0.0;
529
  for (int j = 0; j < h; ++j) {
530
    for (int i = 0; i < w; ++i) {
531
      sum += abs(diff[j * stride + i]);
532
    }
533
  }
534
  assert(w > 0 && h > 0);
535
  return sum / (w * h);
536
}
537
538
static inline void get_2x2_normalized_sses_and_sads(
539
    const AV1_COMP *const cpi, BLOCK_SIZE tx_bsize, const uint8_t *const src,
540
    int src_stride, const uint8_t *const dst, int dst_stride,
541
    const int16_t *const src_diff, int diff_stride, double *const sse_norm_arr,
542
    double *const sad_norm_arr) {
543
  const BLOCK_SIZE tx_bsize_half =
544
      get_partition_subsize(tx_bsize, PARTITION_SPLIT);
545
  if (tx_bsize_half == BLOCK_INVALID) {  // manually calculate stats
546
    const int half_width = block_size_wide[tx_bsize] / 2;
547
    const int half_height = block_size_high[tx_bsize] / 2;
548
    for (int row = 0; row < 2; ++row) {
549
      for (int col = 0; col < 2; ++col) {
550
        const int16_t *const this_src_diff =
551
            src_diff + row * half_height * diff_stride + col * half_width;
552
        if (sse_norm_arr) {
553
          sse_norm_arr[row * 2 + col] =
554
              get_sse_norm(this_src_diff, diff_stride, half_width, half_height);
555
        }
556
        if (sad_norm_arr) {
557
          sad_norm_arr[row * 2 + col] =
558
              get_sad_norm(this_src_diff, diff_stride, half_width, half_height);
559
        }
560
      }
561
    }
562
  } else {  // use function pointers to calculate stats
563
    const int half_width = block_size_wide[tx_bsize_half];
564
    const int half_height = block_size_high[tx_bsize_half];
565
    const int num_samples_half = half_width * half_height;
566
    for (int row = 0; row < 2; ++row) {
567
      for (int col = 0; col < 2; ++col) {
568
        const uint8_t *const this_src =
569
            src + row * half_height * src_stride + col * half_width;
570
        const uint8_t *const this_dst =
571
            dst + row * half_height * dst_stride + col * half_width;
572
573
        if (sse_norm_arr) {
574
          unsigned int this_sse;
575
          cpi->ppi->fn_ptr[tx_bsize_half].vf(this_src, src_stride, this_dst,
576
                                             dst_stride, &this_sse);
577
          sse_norm_arr[row * 2 + col] = (double)this_sse / num_samples_half;
578
        }
579
580
        if (sad_norm_arr) {
581
          const unsigned int this_sad = cpi->ppi->fn_ptr[tx_bsize_half].sdf(
582
              this_src, src_stride, this_dst, dst_stride);
583
          sad_norm_arr[row * 2 + col] = (double)this_sad / num_samples_half;
584
        }
585
      }
586
    }
587
  }
588
}
589
590
#if CONFIG_COLLECT_RD_STATS == 1
591
static double get_mean(const int16_t *diff, int stride, int w, int h) {
592
  double sum = 0.0;
593
  for (int j = 0; j < h; ++j) {
594
    for (int i = 0; i < w; ++i) {
595
      sum += diff[j * stride + i];
596
    }
597
  }
598
  assert(w > 0 && h > 0);
599
  return sum / (w * h);
600
}
601
static inline void PrintTransformUnitStats(
602
    const AV1_COMP *const cpi, MACROBLOCK *x, const RD_STATS *const rd_stats,
603
    int blk_row, int blk_col, BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
604
    TX_TYPE tx_type, int64_t rd) {
605
  if (rd_stats->rate == INT_MAX || rd_stats->dist == INT64_MAX) return;
606
607
  // Generate small sample to restrict output size.
608
  static unsigned int seed = 21743;
609
  if (lcg_rand16(&seed) % 256 > 0) return;
610
611
  const char output_file[] = "tu_stats.txt";
612
  FILE *fout = fopen(output_file, "a");
613
  if (!fout) return;
614
615
  const BLOCK_SIZE tx_bsize = txsize_to_bsize[tx_size];
616
  const MACROBLOCKD *const xd = &x->e_mbd;
617
  const int plane = 0;
618
  struct macroblock_plane *const p = &x->plane[plane];
619
  const struct macroblockd_plane *const pd = &xd->plane[plane];
620
  const int txw = tx_size_wide[tx_size];
621
  const int txh = tx_size_high[tx_size];
622
  const int dequant_shift = (is_cur_buf_hbd(xd)) ? xd->bd - 5 : 3;
623
  const int q_step = p->dequant_QTX[1] >> dequant_shift;
624
  const int num_samples = txw * txh;
625
626
  const double rate_norm = (double)rd_stats->rate / num_samples;
627
  const double dist_norm = (double)rd_stats->dist / num_samples;
628
629
  fprintf(fout, "%g %g", rate_norm, dist_norm);
630
631
  const int src_stride = p->src.stride;
632
  const uint8_t *const src =
633
      &p->src.buf[(blk_row * src_stride + blk_col) << MI_SIZE_LOG2];
634
  const int dst_stride = pd->dst.stride;
635
  const uint8_t *const dst =
636
      &pd->dst.buf[(blk_row * dst_stride + blk_col) << MI_SIZE_LOG2];
637
  unsigned int sse;
638
  cpi->ppi->fn_ptr[tx_bsize].vf(src, src_stride, dst, dst_stride, &sse);
639
  const double sse_norm = (double)sse / num_samples;
640
641
  const unsigned int sad =
642
      cpi->ppi->fn_ptr[tx_bsize].sdf(src, src_stride, dst, dst_stride);
643
  const double sad_norm = (double)sad / num_samples;
644
645
  fprintf(fout, " %g %g", sse_norm, sad_norm);
646
647
  const int diff_stride = block_size_wide[plane_bsize];
648
  const int16_t *const src_diff =
649
      &p->src_diff[(blk_row * diff_stride + blk_col) << MI_SIZE_LOG2];
650
651
  double sse_norm_arr[4], sad_norm_arr[4];
652
  get_2x2_normalized_sses_and_sads(cpi, tx_bsize, src, src_stride, dst,
653
                                   dst_stride, src_diff, diff_stride,
654
                                   sse_norm_arr, sad_norm_arr);
655
  for (int i = 0; i < 4; ++i) {
656
    fprintf(fout, " %g", sse_norm_arr[i]);
657
  }
658
  for (int i = 0; i < 4; ++i) {
659
    fprintf(fout, " %g", sad_norm_arr[i]);
660
  }
661
662
  const TX_TYPE_1D tx_type_1d_row = htx_tab[tx_type];
663
  const TX_TYPE_1D tx_type_1d_col = vtx_tab[tx_type];
664
665
  fprintf(fout, " %d %d %d %d %d", q_step, tx_size_wide[tx_size],
666
          tx_size_high[tx_size], tx_type_1d_row, tx_type_1d_col);
667
668
  int model_rate;
669
  int64_t model_dist;
670
  model_rd_sse_fn[MODELRD_CURVFIT](cpi, x, tx_bsize, plane, sse, num_samples,
671
                                   &model_rate, &model_dist);
672
  const double model_rate_norm = (double)model_rate / num_samples;
673
  const double model_dist_norm = (double)model_dist / num_samples;
674
  fprintf(fout, " %g %g", model_rate_norm, model_dist_norm);
675
676
  const double mean = get_mean(src_diff, diff_stride, txw, txh);
677
  float hor_corr, vert_corr;
678
  av1_get_horver_correlation_full(src_diff, diff_stride, txw, txh, &hor_corr,
679
                                  &vert_corr);
680
  fprintf(fout, " %g %g %g", mean, hor_corr, vert_corr);
681
682
  double hdist[4] = { 0 }, vdist[4] = { 0 };
683
  get_energy_distribution_fine(cpi, tx_bsize, src, src_stride, dst, dst_stride,
684
                               1, hdist, vdist);
685
  fprintf(fout, " %g %g %g %g %g %g %g %g", hdist[0], hdist[1], hdist[2],
686
          hdist[3], vdist[0], vdist[1], vdist[2], vdist[3]);
687
688
  fprintf(fout, " %d %" PRId64, x->rdmult, rd);
689
690
  fprintf(fout, "\n");
691
  fclose(fout);
692
}
693
#endif  // CONFIG_COLLECT_RD_STATS == 1
694
695
#if CONFIG_COLLECT_RD_STATS >= 2
696
static int64_t get_sse(const AV1_COMP *cpi, const MACROBLOCK *x) {
697
  const AV1_COMMON *cm = &cpi->common;
698
  const int num_planes = av1_num_planes(cm);
699
  const MACROBLOCKD *xd = &x->e_mbd;
700
  const MB_MODE_INFO *mbmi = xd->mi[0];
701
  int64_t total_sse = 0;
702
  for (int plane = 0; plane < num_planes; ++plane) {
703
    const struct macroblock_plane *const p = &x->plane[plane];
704
    const struct macroblockd_plane *const pd = &xd->plane[plane];
705
    const BLOCK_SIZE bs =
706
        get_plane_block_size(mbmi->bsize, pd->subsampling_x, pd->subsampling_y);
707
    unsigned int sse;
708
709
    if (plane) continue;
710
711
    cpi->ppi->fn_ptr[bs].vf(p->src.buf, p->src.stride, pd->dst.buf,
712
                            pd->dst.stride, &sse);
713
    total_sse += sse;
714
  }
715
  total_sse <<= 4;
716
  return total_sse;
717
}
718
719
static int get_est_rate_dist(const TileDataEnc *tile_data, BLOCK_SIZE bsize,
720
                             int64_t sse, int *est_residue_cost,
721
                             int64_t *est_dist) {
722
  const InterModeRdModel *md = &tile_data->inter_mode_rd_models[bsize];
723
  if (md->ready) {
724
    if (sse < md->dist_mean) {
725
      *est_residue_cost = 0;
726
      *est_dist = sse;
727
    } else {
728
      *est_dist = (int64_t)round(md->dist_mean);
729
      const double est_ld = md->a * sse + md->b;
730
      // Clamp estimated rate cost by INT_MAX / 2.
731
      // TODO(angiebird@google.com): find better solution than clamping.
732
      if (fabs(est_ld) < 1e-2) {
733
        *est_residue_cost = INT_MAX / 2;
734
      } else {
735
        double est_residue_cost_dbl = ((sse - md->dist_mean) / est_ld);
736
        if (est_residue_cost_dbl < 0) {
737
          *est_residue_cost = 0;
738
        } else {
739
          *est_residue_cost =
740
              (int)AOMMIN((int64_t)round(est_residue_cost_dbl), INT_MAX / 2);
741
        }
742
      }
743
      if (*est_residue_cost <= 0) {
744
        *est_residue_cost = 0;
745
        *est_dist = sse;
746
      }
747
    }
748
    return 1;
749
  }
750
  return 0;
751
}
752
753
static double get_highbd_diff_mean(const uint8_t *src8, int src_stride,
754
                                   const uint8_t *dst8, int dst_stride, int w,
755
                                   int h) {
756
  const uint16_t *src = CONVERT_TO_SHORTPTR(src8);
757
  const uint16_t *dst = CONVERT_TO_SHORTPTR(dst8);
758
  double sum = 0.0;
759
  for (int j = 0; j < h; ++j) {
760
    for (int i = 0; i < w; ++i) {
761
      const int diff = src[j * src_stride + i] - dst[j * dst_stride + i];
762
      sum += diff;
763
    }
764
  }
765
  assert(w > 0 && h > 0);
766
  return sum / (w * h);
767
}
768
769
static double get_diff_mean(const uint8_t *src, int src_stride,
770
                            const uint8_t *dst, int dst_stride, int w, int h) {
771
  double sum = 0.0;
772
  for (int j = 0; j < h; ++j) {
773
    for (int i = 0; i < w; ++i) {
774
      const int diff = src[j * src_stride + i] - dst[j * dst_stride + i];
775
      sum += diff;
776
    }
777
  }
778
  assert(w > 0 && h > 0);
779
  return sum / (w * h);
780
}
781
782
static inline void PrintPredictionUnitStats(const AV1_COMP *const cpi,
783
                                            const TileDataEnc *tile_data,
784
                                            MACROBLOCK *x,
785
                                            const RD_STATS *const rd_stats,
786
                                            BLOCK_SIZE plane_bsize) {
787
  if (rd_stats->rate == INT_MAX || rd_stats->dist == INT64_MAX) return;
788
789
  if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1 &&
790
      (tile_data == NULL ||
791
       !tile_data->inter_mode_rd_models[plane_bsize].ready))
792
    return;
793
  (void)tile_data;
794
  // Generate small sample to restrict output size.
795
  static unsigned int seed = 95014;
796
797
  if ((lcg_rand16(&seed) % (1 << (14 - num_pels_log2_lookup[plane_bsize]))) !=
798
      1)
799
    return;
800
801
  const char output_file[] = "pu_stats.txt";
802
  FILE *fout = fopen(output_file, "a");
803
  if (!fout) return;
804
805
  MACROBLOCKD *const xd = &x->e_mbd;
806
  const int plane = 0;
807
  struct macroblock_plane *const p = &x->plane[plane];
808
  struct macroblockd_plane *pd = &xd->plane[plane];
809
  const int diff_stride = block_size_wide[plane_bsize];
810
  int bw, bh;
811
  get_txb_dimensions(xd, plane, plane_bsize, 0, 0, plane_bsize, NULL, NULL, &bw,
812
                     &bh);
813
  const int num_samples = bw * bh;
814
  const int dequant_shift = (is_cur_buf_hbd(xd)) ? xd->bd - 5 : 3;
815
  const int q_step = p->dequant_QTX[1] >> dequant_shift;
816
  const int shift = (xd->bd - 8);
817
818
  const double rate_norm = (double)rd_stats->rate / num_samples;
819
  const double dist_norm = (double)rd_stats->dist / num_samples;
820
  const double rdcost_norm =
821
      (double)RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist) / num_samples;
822
823
  fprintf(fout, "%g %g %g", rate_norm, dist_norm, rdcost_norm);
824
825
  const int src_stride = p->src.stride;
826
  const uint8_t *const src = p->src.buf;
827
  const int dst_stride = pd->dst.stride;
828
  const uint8_t *const dst = pd->dst.buf;
829
  const int16_t *const src_diff = p->src_diff;
830
831
  int64_t sse = calculate_sse(xd, p, pd, bw, bh);
832
  const double sse_norm = (double)sse / num_samples;
833
834
  const unsigned int sad =
835
      cpi->ppi->fn_ptr[plane_bsize].sdf(src, src_stride, dst, dst_stride);
836
  const double sad_norm =
837
      (double)sad / (1 << num_pels_log2_lookup[plane_bsize]);
838
839
  fprintf(fout, " %g %g", sse_norm, sad_norm);
840
841
  double sse_norm_arr[4], sad_norm_arr[4];
842
  get_2x2_normalized_sses_and_sads(cpi, plane_bsize, src, src_stride, dst,
843
                                   dst_stride, src_diff, diff_stride,
844
                                   sse_norm_arr, sad_norm_arr);
845
  if (shift) {
846
    for (int k = 0; k < 4; ++k) sse_norm_arr[k] /= (1 << (2 * shift));
847
    for (int k = 0; k < 4; ++k) sad_norm_arr[k] /= (1 << shift);
848
  }
849
  for (int i = 0; i < 4; ++i) {
850
    fprintf(fout, " %g", sse_norm_arr[i]);
851
  }
852
  for (int i = 0; i < 4; ++i) {
853
    fprintf(fout, " %g", sad_norm_arr[i]);
854
  }
855
856
  fprintf(fout, " %d %d %d %d", q_step, x->rdmult, bw, bh);
857
858
  int model_rate;
859
  int64_t model_dist;
860
  model_rd_sse_fn[MODELRD_CURVFIT](cpi, x, plane_bsize, plane, sse, num_samples,
861
                                   &model_rate, &model_dist);
862
  const double model_rdcost_norm =
863
      (double)RDCOST(x->rdmult, model_rate, model_dist) / num_samples;
864
  const double model_rate_norm = (double)model_rate / num_samples;
865
  const double model_dist_norm = (double)model_dist / num_samples;
866
  fprintf(fout, " %g %g %g", model_rate_norm, model_dist_norm,
867
          model_rdcost_norm);
868
869
  double mean;
870
  if (is_cur_buf_hbd(xd)) {
871
    mean = get_highbd_diff_mean(p->src.buf, p->src.stride, pd->dst.buf,
872
                                pd->dst.stride, bw, bh);
873
  } else {
874
    mean = get_diff_mean(p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride,
875
                         bw, bh);
876
  }
877
  mean /= (1 << shift);
878
  float hor_corr, vert_corr;
879
  av1_get_horver_correlation_full(src_diff, diff_stride, bw, bh, &hor_corr,
880
                                  &vert_corr);
881
  fprintf(fout, " %g %g %g", mean, hor_corr, vert_corr);
882
883
  double hdist[4] = { 0 }, vdist[4] = { 0 };
884
  get_energy_distribution_fine(cpi, plane_bsize, src, src_stride, dst,
885
                               dst_stride, 1, hdist, vdist);
886
  fprintf(fout, " %g %g %g %g %g %g %g %g", hdist[0], hdist[1], hdist[2],
887
          hdist[3], vdist[0], vdist[1], vdist[2], vdist[3]);
888
889
  if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1) {
890
    assert(tile_data->inter_mode_rd_models[plane_bsize].ready);
891
    const int64_t overall_sse = get_sse(cpi, x);
892
    int est_residue_cost = 0;
893
    int64_t est_dist = 0;
894
    get_est_rate_dist(tile_data, plane_bsize, overall_sse, &est_residue_cost,
895
                      &est_dist);
896
    const double est_residue_cost_norm = (double)est_residue_cost / num_samples;
897
    const double est_dist_norm = (double)est_dist / num_samples;
898
    const double est_rdcost_norm =
899
        (double)RDCOST(x->rdmult, est_residue_cost, est_dist) / num_samples;
900
    fprintf(fout, " %g %g %g", est_residue_cost_norm, est_dist_norm,
901
            est_rdcost_norm);
902
  }
903
904
  fprintf(fout, "\n");
905
  fclose(fout);
906
}
907
#endif  // CONFIG_COLLECT_RD_STATS >= 2
908
#endif  // CONFIG_COLLECT_RD_STATS
909
910
static inline void inverse_transform_block_facade(MACROBLOCK *const x,
911
                                                  int plane, int block,
912
                                                  int blk_row, int blk_col,
913
0
                                                  int eob, int reduced_tx_set) {
914
0
  if (!eob) return;
915
0
  struct macroblock_plane *const p = &x->plane[plane];
916
0
  MACROBLOCKD *const xd = &x->e_mbd;
917
0
  tran_low_t *dqcoeff = p->dqcoeff + BLOCK_OFFSET(block);
918
0
  const PLANE_TYPE plane_type = get_plane_type(plane);
919
0
  const TX_SIZE tx_size = av1_get_tx_size(plane, xd);
920
0
  const TX_TYPE tx_type = av1_get_tx_type(xd, plane_type, blk_row, blk_col,
921
0
                                          tx_size, reduced_tx_set);
922
923
0
  struct macroblockd_plane *const pd = &xd->plane[plane];
924
0
  const int dst_stride = pd->dst.stride;
925
0
  uint8_t *dst = &pd->dst.buf[(blk_row * dst_stride + blk_col) << MI_SIZE_LOG2];
926
0
  av1_inverse_transform_block(xd, dqcoeff, plane, tx_type, tx_size, dst,
927
0
                              dst_stride, eob, reduced_tx_set);
928
0
}
929
930
static inline void recon_intra(const AV1_COMP *cpi, MACROBLOCK *x, int plane,
931
                               int block, int blk_row, int blk_col,
932
                               BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
933
                               const TXB_CTX *const txb_ctx, int skip_trellis,
934
                               TX_TYPE best_tx_type, int do_quant,
935
0
                               int *rate_cost, uint16_t best_eob) {
936
0
  const AV1_COMMON *cm = &cpi->common;
937
0
  MACROBLOCKD *xd = &x->e_mbd;
938
0
  MB_MODE_INFO *mbmi = xd->mi[0];
939
0
  const int is_inter = is_inter_block(mbmi);
940
0
  if (!is_inter && best_eob &&
941
0
      (blk_row + tx_size_high_unit[tx_size] < mi_size_high[plane_bsize] ||
942
0
       blk_col + tx_size_wide_unit[tx_size] < mi_size_wide[plane_bsize])) {
943
    // if the quantized coefficients are stored in the dqcoeff buffer, we don't
944
    // need to do transform and quantization again.
945
0
    if (do_quant) {
946
0
      TxfmParam txfm_param_intra;
947
0
      QUANT_PARAM quant_param_intra;
948
0
      av1_setup_xform(cm, x, tx_size, best_tx_type, &txfm_param_intra);
949
0
      av1_setup_quant(tx_size, !skip_trellis,
950
0
                      skip_trellis
951
0
                          ? (USE_B_QUANT_NO_TRELLIS ? AV1_XFORM_QUANT_B
952
0
                                                    : AV1_XFORM_QUANT_FP)
953
0
                          : AV1_XFORM_QUANT_FP,
954
0
                      cpi->oxcf.q_cfg.quant_b_adapt, &quant_param_intra);
955
0
      av1_setup_qmatrix(&cm->quant_params, xd, plane, tx_size, best_tx_type,
956
0
                        &quant_param_intra);
957
0
      av1_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize,
958
0
                      &txfm_param_intra, &quant_param_intra);
959
0
      if (quant_param_intra.use_optimize_b) {
960
0
        av1_optimize_b(cpi, x, plane, block, tx_size, best_tx_type, txb_ctx,
961
0
                       rate_cost);
962
0
      }
963
0
    }
964
965
0
    inverse_transform_block_facade(x, plane, block, blk_row, blk_col,
966
0
                                   x->plane[plane].eobs[block],
967
0
                                   cm->features.reduced_tx_set_used);
968
969
    // This may happen because of hash collision. The eob stored in the hash
970
    // table is non-zero, but the real eob is zero. We need to make sure tx_type
971
    // is DCT_DCT in this case.
972
0
    if (plane == 0 && x->plane[plane].eobs[block] == 0 &&
973
0
        best_tx_type != DCT_DCT) {
974
0
      update_txk_array(xd, blk_row, blk_col, tx_size, DCT_DCT);
975
0
    }
976
0
  }
977
0
}
978
979
// Compute the pixel domain distortion from src and dst on all visible 4x4s in
980
// the transform block.
981
static unsigned pixel_dist(const AV1_COMP *const cpi, const MACROBLOCK *x,
982
                           int plane, const uint8_t *src, const int src_stride,
983
                           const uint8_t *dst, const int dst_stride,
984
                           int blk_row, int blk_col,
985
                           const BLOCK_SIZE plane_bsize,
986
0
                           const BLOCK_SIZE tx_bsize) {
987
0
  int txb_rows, txb_cols, visible_rows, visible_cols;
988
0
  txb_cols = block_size_wide[tx_bsize];
989
0
  txb_rows = block_size_high[tx_bsize];
990
991
0
  get_visible_dimensions(x, plane, plane_bsize, blk_col, blk_row, txb_cols,
992
0
                         txb_rows, /*clip_dims=*/true, &visible_cols,
993
0
                         &visible_rows);
994
0
  assert(visible_rows > 0);
995
0
  assert(visible_cols > 0);
996
997
0
  unsigned sse = pixel_dist_visible_only(cpi, x, src, src_stride, dst,
998
0
                                         dst_stride, tx_bsize, txb_rows,
999
0
                                         txb_cols, visible_rows, visible_cols);
1000
1001
0
  return sse;
1002
0
}
1003
1004
static inline int64_t dist_block_px_domain(const AV1_COMP *cpi, MACROBLOCK *x,
1005
                                           int plane, BLOCK_SIZE plane_bsize,
1006
                                           int block, int blk_row, int blk_col,
1007
0
                                           TX_SIZE tx_size) {
1008
0
  MACROBLOCKD *const xd = &x->e_mbd;
1009
0
  const struct macroblock_plane *const p = &x->plane[plane];
1010
0
  const uint16_t eob = p->eobs[block];
1011
0
  const BLOCK_SIZE tx_bsize = txsize_to_bsize[tx_size];
1012
0
  const int bsw = block_size_wide[tx_bsize];
1013
0
  const int bsh = block_size_high[tx_bsize];
1014
0
  const int src_stride = x->plane[plane].src.stride;
1015
0
  const int dst_stride = xd->plane[plane].dst.stride;
1016
  // Scale the transform block index to pixel unit.
1017
0
  const int src_idx = (blk_row * src_stride + blk_col) << MI_SIZE_LOG2;
1018
0
  const int dst_idx = (blk_row * dst_stride + blk_col) << MI_SIZE_LOG2;
1019
0
  const uint8_t *src = &x->plane[plane].src.buf[src_idx];
1020
0
  const uint8_t *dst = &xd->plane[plane].dst.buf[dst_idx];
1021
0
  const tran_low_t *dqcoeff = p->dqcoeff + BLOCK_OFFSET(block);
1022
1023
0
  assert(cpi != NULL);
1024
0
  assert(tx_size_wide_log2[0] == tx_size_high_log2[0]);
1025
1026
0
  uint8_t *recon;
1027
0
  DECLARE_ALIGNED(16, uint16_t, recon16[MAX_TX_SQUARE]);
1028
1029
0
#if CONFIG_AV1_HIGHBITDEPTH
1030
0
  if (is_cur_buf_hbd(xd)) {
1031
0
    recon = CONVERT_TO_BYTEPTR(recon16);
1032
0
    aom_highbd_convolve_copy(CONVERT_TO_SHORTPTR(dst), dst_stride,
1033
0
                             CONVERT_TO_SHORTPTR(recon), MAX_TX_SIZE, bsw, bsh);
1034
0
  } else {
1035
0
    recon = (uint8_t *)recon16;
1036
0
    aom_convolve_copy(dst, dst_stride, recon, MAX_TX_SIZE, bsw, bsh);
1037
0
  }
1038
#else
1039
  recon = (uint8_t *)recon16;
1040
  aom_convolve_copy(dst, dst_stride, recon, MAX_TX_SIZE, bsw, bsh);
1041
#endif
1042
1043
0
  const PLANE_TYPE plane_type = get_plane_type(plane);
1044
0
  TX_TYPE tx_type = av1_get_tx_type(xd, plane_type, blk_row, blk_col, tx_size,
1045
0
                                    cpi->common.features.reduced_tx_set_used);
1046
0
  av1_inverse_transform_block(xd, dqcoeff, plane, tx_type, tx_size, recon,
1047
0
                              MAX_TX_SIZE, eob,
1048
0
                              cpi->common.features.reduced_tx_set_used);
1049
1050
0
  return 16 * pixel_dist(cpi, x, plane, src, src_stride, recon, MAX_TX_SIZE,
1051
0
                         blk_row, blk_col, plane_bsize, tx_bsize);
1052
0
}
1053
1054
// pruning thresholds for prune_txk_type and prune_txk_type_separ
1055
static const int prune_factors[5] = { 200, 200, 120, 80, 40 };  // scale 1000
1056
static const int mul_factors[5] = { 80, 80, 70, 50, 30 };       // scale 100
1057
1058
// R-D costs are sorted in ascending order.
1059
0
static inline void sort_rd(int64_t rds[], int txk[], int len) {
1060
0
  int i, j, k;
1061
1062
0
  for (i = 1; i <= len - 1; ++i) {
1063
0
    for (j = 0; j < i; ++j) {
1064
0
      if (rds[j] > rds[i]) {
1065
0
        int64_t temprd;
1066
0
        int tempi;
1067
1068
0
        temprd = rds[i];
1069
0
        tempi = txk[i];
1070
1071
0
        for (k = i; k > j; k--) {
1072
0
          rds[k] = rds[k - 1];
1073
0
          txk[k] = txk[k - 1];
1074
0
        }
1075
1076
0
        rds[j] = temprd;
1077
0
        txk[j] = tempi;
1078
0
        break;
1079
0
      }
1080
0
    }
1081
0
  }
1082
0
}
1083
1084
static inline int64_t av1_block_error_qm(
1085
    const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size,
1086
0
    const qm_val_t *qmatrix, const int16_t *scan, int64_t *ssz, int bd) {
1087
0
  int i;
1088
0
  int64_t error = 0, sqcoeff = 0;
1089
0
  int shift = 2 * (bd - 8);
1090
0
  int rounding = (1 << shift) >> 1;
1091
1092
0
  for (i = 0; i < block_size; i++) {
1093
0
    int64_t weight = qmatrix[scan[i]];
1094
0
    int64_t dd = coeff[i] - dqcoeff[i];
1095
0
    dd *= weight;
1096
0
    int64_t cc = coeff[i];
1097
0
    cc *= weight;
1098
    // The ranges of coeff and dqcoeff are
1099
    //  bd8 : 18 bits (including sign)
1100
    //  bd10: 20 bits (including sign)
1101
    //  bd12: 22 bits (including sign)
1102
    // As AOM_QM_BITS is 5, the intermediate quantities in the calculation
1103
    // below should fit in 54 bits, thus no overflow should happen.
1104
0
    error += (dd * dd + (1 << (2 * AOM_QM_BITS - 1))) >> (2 * AOM_QM_BITS);
1105
0
    sqcoeff += (cc * cc + (1 << (2 * AOM_QM_BITS - 1))) >> (2 * AOM_QM_BITS);
1106
0
  }
1107
1108
0
  error = (error + rounding) >> shift;
1109
0
  sqcoeff = (sqcoeff + rounding) >> shift;
1110
1111
0
  *ssz = sqcoeff;
1112
0
  return error;
1113
0
}
1114
1115
static inline void dist_block_tx_domain(MACROBLOCK *x, int plane, int block,
1116
                                        TX_SIZE tx_size,
1117
                                        const qm_val_t *qmatrix,
1118
                                        const int16_t *scan, int64_t *out_dist,
1119
0
                                        int64_t *out_sse) {
1120
0
  const struct macroblock_plane *const p = &x->plane[plane];
1121
  // Transform domain distortion computation is more efficient as it does
1122
  // not involve an inverse transform, but it is less accurate.
1123
0
  const int buffer_length = av1_get_max_eob(tx_size);
1124
0
  int64_t this_sse;
1125
  // TX-domain results need to shift down to Q2/D10 to match pixel
1126
  // domain distortion values which are in Q2^2
1127
0
  int shift = (MAX_TX_SCALE - av1_get_tx_scale(tx_size)) * 2;
1128
0
  const int block_offset = BLOCK_OFFSET(block);
1129
0
  tran_low_t *const coeff = p->coeff + block_offset;
1130
0
  tran_low_t *const dqcoeff = p->dqcoeff + block_offset;
1131
0
#if CONFIG_AV1_HIGHBITDEPTH
1132
0
  MACROBLOCKD *const xd = &x->e_mbd;
1133
0
  if (is_cur_buf_hbd(xd)) {
1134
0
    if (qmatrix == NULL || !x->txfm_search_params.use_qm_dist_metric) {
1135
0
      *out_dist = av1_highbd_block_error(coeff, dqcoeff, buffer_length,
1136
0
                                         &this_sse, xd->bd);
1137
0
    } else {
1138
0
      *out_dist = av1_block_error_qm(coeff, dqcoeff, buffer_length, qmatrix,
1139
0
                                     scan, &this_sse, xd->bd);
1140
0
    }
1141
0
  } else {
1142
0
#endif
1143
0
    if (qmatrix == NULL || !x->txfm_search_params.use_qm_dist_metric) {
1144
0
      *out_dist = av1_block_error(coeff, dqcoeff, buffer_length, &this_sse);
1145
0
    } else {
1146
0
      *out_dist = av1_block_error_qm(coeff, dqcoeff, buffer_length, qmatrix,
1147
0
                                     scan, &this_sse, 8);
1148
0
    }
1149
0
#if CONFIG_AV1_HIGHBITDEPTH
1150
0
  }
1151
0
#endif
1152
1153
0
  *out_dist = RIGHT_SIGNED_SHIFT(*out_dist, shift);
1154
0
  *out_sse = RIGHT_SIGNED_SHIFT(this_sse, shift);
1155
0
}
1156
1157
static uint16_t prune_txk_type_separ(
1158
    const AV1_COMP *cpi, MACROBLOCK *x, int plane, int block, TX_SIZE tx_size,
1159
    int blk_row, int blk_col, BLOCK_SIZE plane_bsize, int *txk_map,
1160
    int16_t allowed_tx_mask, int prune_factor, const TXB_CTX *const txb_ctx,
1161
0
    int reduced_tx_set_used, int64_t ref_best_rd, int num_sel) {
1162
0
  const AV1_COMMON *cm = &cpi->common;
1163
0
  MACROBLOCKD *xd = &x->e_mbd;
1164
1165
0
  int idx;
1166
1167
0
  int64_t rds_v[4];
1168
0
  int64_t rds_h[4];
1169
0
  int idx_v[4] = { 0, 1, 2, 3 };
1170
0
  int idx_h[4] = { 0, 1, 2, 3 };
1171
0
  int skip_v[4] = { 0 };
1172
0
  int skip_h[4] = { 0 };
1173
0
  const int idx_map[16] = {
1174
0
    DCT_DCT,      DCT_ADST,      DCT_FLIPADST,      V_DCT,
1175
0
    ADST_DCT,     ADST_ADST,     ADST_FLIPADST,     V_ADST,
1176
0
    FLIPADST_DCT, FLIPADST_ADST, FLIPADST_FLIPADST, V_FLIPADST,
1177
0
    H_DCT,        H_ADST,        H_FLIPADST,        IDTX
1178
0
  };
1179
1180
0
  const int sel_pattern_v[16] = {
1181
0
    0, 0, 1, 1, 0, 2, 1, 2, 2, 0, 3, 1, 3, 2, 3, 3
1182
0
  };
1183
0
  const int sel_pattern_h[16] = {
1184
0
    0, 1, 0, 1, 2, 0, 2, 1, 2, 3, 0, 3, 1, 3, 2, 3
1185
0
  };
1186
1187
0
  QUANT_PARAM quant_param;
1188
0
  TxfmParam txfm_param;
1189
0
  av1_setup_xform(cm, x, tx_size, DCT_DCT, &txfm_param);
1190
0
  av1_setup_quant(tx_size, 1, AV1_XFORM_QUANT_B, cpi->oxcf.q_cfg.quant_b_adapt,
1191
0
                  &quant_param);
1192
0
  int tx_type;
1193
  // to ensure we can try ones even outside of ext_tx_set of current block
1194
  // this function should only be called for size < 16
1195
0
  assert(txsize_sqr_up_map[tx_size] <= TX_16X16);
1196
0
  txfm_param.tx_set_type = EXT_TX_SET_ALL16;
1197
1198
0
  int rate_cost = 0;
1199
0
  int64_t dist = 0, sse = 0;
1200
  // evaluate horizontal with vertical DCT
1201
0
  for (idx = 0; idx < 4; ++idx) {
1202
0
    tx_type = idx_map[idx];
1203
0
    txfm_param.tx_type = tx_type;
1204
1205
0
    av1_setup_qmatrix(&cm->quant_params, xd, plane, tx_size, tx_type,
1206
0
                      &quant_param);
1207
1208
0
    av1_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize, &txfm_param,
1209
0
                    &quant_param);
1210
1211
0
    const SCAN_ORDER *const scan_order =
1212
0
        get_scan(txfm_param.tx_size, txfm_param.tx_type);
1213
0
    dist_block_tx_domain(x, plane, block, tx_size, quant_param.qmatrix,
1214
0
                         scan_order->scan, &dist, &sse);
1215
1216
0
    rate_cost = av1_cost_coeffs_txb_laplacian(x, plane, block, tx_size, tx_type,
1217
0
                                              txb_ctx, reduced_tx_set_used, 0);
1218
1219
0
    rds_h[idx] = RDCOST(x->rdmult, rate_cost, dist);
1220
1221
0
    if ((rds_h[idx] - (rds_h[idx] >> 2)) > ref_best_rd) {
1222
0
      skip_h[idx] = 1;
1223
0
    }
1224
0
  }
1225
0
  sort_rd(rds_h, idx_h, 4);
1226
0
  for (idx = 1; idx < 4; idx++) {
1227
0
    if (rds_h[idx] > rds_h[0] * 1.2) skip_h[idx_h[idx]] = 1;
1228
0
  }
1229
1230
0
  if (skip_h[idx_h[0]]) return (uint16_t)0xFFFF;
1231
1232
  // evaluate vertical with the best horizontal chosen
1233
0
  rds_v[0] = rds_h[0];
1234
0
  int start_v = 1, end_v = 4;
1235
0
  const int *idx_map_v = idx_map + idx_h[0];
1236
1237
0
  for (idx = start_v; idx < end_v; ++idx) {
1238
0
    tx_type = idx_map_v[idx_v[idx] * 4];
1239
0
    txfm_param.tx_type = tx_type;
1240
1241
0
    av1_setup_qmatrix(&cm->quant_params, xd, plane, tx_size, tx_type,
1242
0
                      &quant_param);
1243
1244
0
    av1_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize, &txfm_param,
1245
0
                    &quant_param);
1246
1247
0
    const SCAN_ORDER *const scan_order =
1248
0
        get_scan(txfm_param.tx_size, txfm_param.tx_type);
1249
0
    dist_block_tx_domain(x, plane, block, tx_size, quant_param.qmatrix,
1250
0
                         scan_order->scan, &dist, &sse);
1251
1252
0
    rate_cost = av1_cost_coeffs_txb_laplacian(x, plane, block, tx_size, tx_type,
1253
0
                                              txb_ctx, reduced_tx_set_used, 0);
1254
1255
0
    rds_v[idx] = RDCOST(x->rdmult, rate_cost, dist);
1256
1257
0
    if ((rds_v[idx] - (rds_v[idx] >> 2)) > ref_best_rd) {
1258
0
      skip_v[idx] = 1;
1259
0
    }
1260
0
  }
1261
0
  sort_rd(rds_v, idx_v, 4);
1262
0
  for (idx = 1; idx < 4; idx++) {
1263
0
    if (rds_v[idx] > rds_v[0] * 1.2) skip_v[idx_v[idx]] = 1;
1264
0
  }
1265
1266
  // combine rd_h and rd_v to prune tx candidates
1267
0
  int i_v, i_h;
1268
0
  int64_t rds[16];
1269
0
  int num_cand = 0, last = TX_TYPES - 1;
1270
1271
0
  for (int i = 0; i < 16; i++) {
1272
0
    i_v = sel_pattern_v[i];
1273
0
    i_h = sel_pattern_h[i];
1274
0
    tx_type = idx_map[idx_v[i_v] * 4 + idx_h[i_h]];
1275
0
    if (!(allowed_tx_mask & (1 << tx_type)) || skip_h[idx_h[i_h]] ||
1276
0
        skip_v[idx_v[i_v]]) {
1277
0
      txk_map[last] = tx_type;
1278
0
      last--;
1279
0
    } else {
1280
0
      txk_map[num_cand] = tx_type;
1281
0
      rds[num_cand] = rds_v[i_v] + rds_h[i_h];
1282
0
      if (rds[num_cand] == 0) rds[num_cand] = 1;
1283
0
      num_cand++;
1284
0
    }
1285
0
  }
1286
0
  sort_rd(rds, txk_map, num_cand);
1287
1288
0
  uint16_t prune = (uint16_t)(~(1 << txk_map[0]));
1289
0
  num_sel = AOMMIN(num_sel, num_cand);
1290
1291
0
  for (int i = 1; i < num_sel; i++) {
1292
0
    int64_t factor = 1800 * (rds[i] - rds[0]) / (rds[0]);
1293
0
    if (factor < (int64_t)prune_factor)
1294
0
      prune &= ~(1 << txk_map[i]);
1295
0
    else
1296
0
      break;
1297
0
  }
1298
0
  return prune;
1299
0
}
1300
1301
static uint16_t prune_txk_type(const AV1_COMP *cpi, MACROBLOCK *x, int plane,
1302
                               int block, TX_SIZE tx_size, int blk_row,
1303
                               int blk_col, BLOCK_SIZE plane_bsize,
1304
                               int *txk_map, uint16_t allowed_tx_mask,
1305
                               int prune_factor, const TXB_CTX *const txb_ctx,
1306
0
                               int reduced_tx_set_used) {
1307
0
  const AV1_COMMON *cm = &cpi->common;
1308
0
  MACROBLOCKD *xd = &x->e_mbd;
1309
0
  int tx_type;
1310
1311
0
  int64_t rds[TX_TYPES];
1312
1313
0
  int num_cand = 0;
1314
0
  int last = TX_TYPES - 1;
1315
1316
0
  TxfmParam txfm_param;
1317
0
  QUANT_PARAM quant_param;
1318
0
  av1_setup_xform(cm, x, tx_size, DCT_DCT, &txfm_param);
1319
0
  av1_setup_quant(tx_size, 1, AV1_XFORM_QUANT_B, cpi->oxcf.q_cfg.quant_b_adapt,
1320
0
                  &quant_param);
1321
1322
0
  for (int idx = 0; idx < TX_TYPES; idx++) {
1323
0
    tx_type = idx;
1324
0
    int rate_cost = 0;
1325
0
    int64_t dist = 0, sse = 0;
1326
0
    if (!(allowed_tx_mask & (1 << tx_type))) {
1327
0
      txk_map[last] = tx_type;
1328
0
      last--;
1329
0
      continue;
1330
0
    }
1331
0
    txfm_param.tx_type = tx_type;
1332
1333
0
    av1_setup_qmatrix(&cm->quant_params, xd, plane, tx_size, tx_type,
1334
0
                      &quant_param);
1335
1336
    // do txfm and quantization
1337
0
    av1_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize, &txfm_param,
1338
0
                    &quant_param);
1339
    // estimate rate cost
1340
0
    rate_cost = av1_cost_coeffs_txb_laplacian(x, plane, block, tx_size, tx_type,
1341
0
                                              txb_ctx, reduced_tx_set_used, 0);
1342
    // tx domain dist
1343
0
    const SCAN_ORDER *const scan_order =
1344
0
        get_scan(txfm_param.tx_size, txfm_param.tx_type);
1345
0
    dist_block_tx_domain(x, plane, block, tx_size, quant_param.qmatrix,
1346
0
                         scan_order->scan, &dist, &sse);
1347
1348
0
    txk_map[num_cand] = tx_type;
1349
0
    rds[num_cand] = RDCOST(x->rdmult, rate_cost, dist);
1350
0
    if (rds[num_cand] == 0) rds[num_cand] = 1;
1351
0
    num_cand++;
1352
0
  }
1353
1354
0
  if (num_cand == 0) return (uint16_t)0xFFFF;
1355
1356
0
  sort_rd(rds, txk_map, num_cand);
1357
0
  uint16_t prune = (uint16_t)(~(1 << txk_map[0]));
1358
1359
  // 0 < prune_factor <= 1000 controls aggressiveness
1360
0
  int64_t factor = 0;
1361
0
  for (int idx = 1; idx < num_cand; idx++) {
1362
0
    factor = 1000 * (rds[idx] - rds[0]) / rds[0];
1363
0
    if (factor < (int64_t)prune_factor)
1364
0
      prune &= ~(1 << txk_map[idx]);
1365
0
    else
1366
0
      break;
1367
0
  }
1368
0
  return prune;
1369
0
}
1370
1371
// These thresholds were calibrated to provide a certain number of TX types
1372
// pruned by the model on average, i.e. selecting a threshold with index i
1373
// will lead to pruning i+1 TX types on average
1374
static const float *prune_2D_adaptive_thresholds[] = {
1375
  // TX_4X4
1376
  (float[]){ 0.00549f, 0.01306f, 0.02039f, 0.02747f, 0.03406f, 0.04065f,
1377
             0.04724f, 0.05383f, 0.06067f, 0.06799f, 0.07605f, 0.08533f,
1378
             0.09778f, 0.11780f },
1379
  // TX_8X8
1380
  (float[]){ 0.00037f, 0.00183f, 0.00525f, 0.01038f, 0.01697f, 0.02502f,
1381
             0.03381f, 0.04333f, 0.05286f, 0.06287f, 0.07434f, 0.08850f,
1382
             0.10803f, 0.14124f },
1383
  // TX_16X16
1384
  (float[]){ 0.01404f, 0.02000f, 0.04211f, 0.05164f, 0.05798f, 0.06335f,
1385
             0.06897f, 0.07629f, 0.08875f, 0.11169f },
1386
  // TX_32X32
1387
  NULL,
1388
  // TX_64X64
1389
  NULL,
1390
  // TX_4X8
1391
  (float[]){ 0.00183f, 0.00745f, 0.01428f, 0.02185f, 0.02966f, 0.03723f,
1392
             0.04456f, 0.05188f, 0.05920f, 0.06702f, 0.07605f, 0.08704f,
1393
             0.10168f, 0.12585f },
1394
  // TX_8X4
1395
  (float[]){ 0.00085f, 0.00476f, 0.01135f, 0.01892f, 0.02698f, 0.03528f,
1396
             0.04358f, 0.05164f, 0.05994f, 0.06848f, 0.07849f, 0.09021f,
1397
             0.10583f, 0.13123f },
1398
  // TX_8X16
1399
  (float[]){ 0.00037f, 0.00232f, 0.00671f, 0.01257f, 0.01965f, 0.02722f,
1400
             0.03552f, 0.04382f, 0.05237f, 0.06189f, 0.07336f, 0.08728f,
1401
             0.10730f, 0.14221f },
1402
  // TX_16X8
1403
  (float[]){ 0.00061f, 0.00330f, 0.00818f, 0.01453f, 0.02185f, 0.02966f,
1404
             0.03772f, 0.04578f, 0.05383f, 0.06262f, 0.07288f, 0.08582f,
1405
             0.10339f, 0.13464f },
1406
  // TX_16X32
1407
  NULL,
1408
  // TX_32X16
1409
  NULL,
1410
  // TX_32X64
1411
  NULL,
1412
  // TX_64X32
1413
  NULL,
1414
  // TX_4X16
1415
  (float[]){ 0.00232f, 0.00671f, 0.01257f, 0.01941f, 0.02673f, 0.03430f,
1416
             0.04211f, 0.04968f, 0.05750f, 0.06580f, 0.07507f, 0.08655f,
1417
             0.10242f, 0.12878f },
1418
  // TX_16X4
1419
  (float[]){ 0.00110f, 0.00525f, 0.01208f, 0.01990f, 0.02795f, 0.03601f,
1420
             0.04358f, 0.05115f, 0.05896f, 0.06702f, 0.07629f, 0.08752f,
1421
             0.10217f, 0.12610f },
1422
  // TX_8X32
1423
  NULL,
1424
  // TX_32X8
1425
  NULL,
1426
  // TX_16X64
1427
  NULL,
1428
  // TX_64X16
1429
  NULL,
1430
};
1431
1432
static inline float get_adaptive_thresholds(
1433
    TX_SIZE tx_size, TxSetType tx_set_type,
1434
0
    TX_TYPE_PRUNE_MODE prune_2d_txfm_mode) {
1435
0
  const int prune_aggr_table[5][2] = {
1436
0
    { 4, 1 }, { 6, 3 }, { 9, 6 }, { 9, 6 }, { 12, 9 }
1437
0
  };
1438
0
  int pruning_aggressiveness = 0;
1439
0
  if (tx_set_type == EXT_TX_SET_ALL16)
1440
0
    pruning_aggressiveness =
1441
0
        prune_aggr_table[prune_2d_txfm_mode - TX_TYPE_PRUNE_1][0];
1442
0
  else if (tx_set_type == EXT_TX_SET_DTT9_IDTX_1DDCT)
1443
0
    pruning_aggressiveness =
1444
0
        prune_aggr_table[prune_2d_txfm_mode - TX_TYPE_PRUNE_1][1];
1445
1446
0
  return prune_2D_adaptive_thresholds[tx_size][pruning_aggressiveness];
1447
0
}
1448
1449
static inline void get_energy_distribution_finer(const int16_t *diff,
1450
                                                 int stride, int bw, int bh,
1451
                                                 float *hordist,
1452
0
                                                 float *verdist) {
1453
  // First compute downscaled block energy values (esq); downscale factors
1454
  // are defined by w_shift and h_shift.
1455
0
  unsigned int esq[256];
1456
0
  const int w_shift = bw <= 8 ? 0 : 1;
1457
0
  const int h_shift = bh <= 8 ? 0 : 1;
1458
0
  const int esq_w = bw >> w_shift;
1459
0
  const int esq_h = bh >> h_shift;
1460
0
  const int esq_sz = esq_w * esq_h;
1461
0
  int i, j;
1462
0
  memset(esq, 0, esq_sz * sizeof(esq[0]));
1463
0
  if (w_shift) {
1464
0
    for (i = 0; i < bh; i++) {
1465
0
      unsigned int *cur_esq_row = esq + (i >> h_shift) * esq_w;
1466
0
      const int16_t *cur_diff_row = diff + i * stride;
1467
0
      for (j = 0; j < bw; j += 2) {
1468
0
        cur_esq_row[j >> 1] += (cur_diff_row[j] * cur_diff_row[j] +
1469
0
                                cur_diff_row[j + 1] * cur_diff_row[j + 1]);
1470
0
      }
1471
0
    }
1472
0
  } else {
1473
0
    for (i = 0; i < bh; i++) {
1474
0
      unsigned int *cur_esq_row = esq + (i >> h_shift) * esq_w;
1475
0
      const int16_t *cur_diff_row = diff + i * stride;
1476
0
      for (j = 0; j < bw; j++) {
1477
0
        cur_esq_row[j] += cur_diff_row[j] * cur_diff_row[j];
1478
0
      }
1479
0
    }
1480
0
  }
1481
1482
0
  uint64_t total = 0;
1483
0
  for (i = 0; i < esq_sz; i++) total += esq[i];
1484
1485
  // Output hordist and verdist arrays are normalized 1D projections of esq
1486
0
  if (total == 0) {
1487
0
    float hor_val = 1.0f / esq_w;
1488
0
    for (j = 0; j < esq_w - 1; j++) hordist[j] = hor_val;
1489
0
    float ver_val = 1.0f / esq_h;
1490
0
    for (i = 0; i < esq_h - 1; i++) verdist[i] = ver_val;
1491
0
    return;
1492
0
  }
1493
1494
0
  const float e_recip = 1.0f / (float)total;
1495
0
  memset(hordist, 0, (esq_w - 1) * sizeof(hordist[0]));
1496
0
  memset(verdist, 0, (esq_h - 1) * sizeof(verdist[0]));
1497
0
  const unsigned int *cur_esq_row;
1498
0
  for (i = 0; i < esq_h - 1; i++) {
1499
0
    cur_esq_row = esq + i * esq_w;
1500
0
    for (j = 0; j < esq_w - 1; j++) {
1501
0
      hordist[j] += (float)cur_esq_row[j];
1502
0
      verdist[i] += (float)cur_esq_row[j];
1503
0
    }
1504
0
    verdist[i] += (float)cur_esq_row[j];
1505
0
  }
1506
0
  cur_esq_row = esq + i * esq_w;
1507
0
  for (j = 0; j < esq_w - 1; j++) hordist[j] += (float)cur_esq_row[j];
1508
1509
0
  for (j = 0; j < esq_w - 1; j++) hordist[j] *= e_recip;
1510
0
  for (i = 0; i < esq_h - 1; i++) verdist[i] *= e_recip;
1511
0
}
1512
1513
0
static inline bool check_bit_mask(uint16_t mask, int val) {
1514
0
  return mask & (1 << val);
1515
0
}
1516
1517
0
static inline void set_bit_mask(uint16_t *mask, int val) {
1518
0
  *mask |= (1 << val);
1519
0
}
1520
1521
0
static inline void unset_bit_mask(uint16_t *mask, int val) {
1522
0
  *mask &= ~(1 << val);
1523
0
}
1524
1525
static void prune_tx_2D(MACROBLOCK *x, BLOCK_SIZE bsize, TX_SIZE tx_size,
1526
                        int blk_row, int blk_col, TxSetType tx_set_type,
1527
                        TX_TYPE_PRUNE_MODE prune_2d_txfm_mode, int *txk_map,
1528
0
                        uint16_t *allowed_tx_mask) {
1529
  // This table is used because the search order is different from the enum
1530
  // order.
1531
0
  static const int tx_type_table_2D[16] = {
1532
0
    DCT_DCT,      DCT_ADST,      DCT_FLIPADST,      V_DCT,
1533
0
    ADST_DCT,     ADST_ADST,     ADST_FLIPADST,     V_ADST,
1534
0
    FLIPADST_DCT, FLIPADST_ADST, FLIPADST_FLIPADST, V_FLIPADST,
1535
0
    H_DCT,        H_ADST,        H_FLIPADST,        IDTX
1536
0
  };
1537
0
  if (tx_set_type != EXT_TX_SET_ALL16 &&
1538
0
      tx_set_type != EXT_TX_SET_DTT9_IDTX_1DDCT)
1539
0
    return;
1540
#if CONFIG_NN_V2
1541
  NN_CONFIG_V2 *nn_config_hor = av1_tx_type_nnconfig_map_hor[tx_size];
1542
  NN_CONFIG_V2 *nn_config_ver = av1_tx_type_nnconfig_map_ver[tx_size];
1543
#else
1544
0
  const NN_CONFIG *nn_config_hor = av1_tx_type_nnconfig_map_hor[tx_size];
1545
0
  const NN_CONFIG *nn_config_ver = av1_tx_type_nnconfig_map_ver[tx_size];
1546
0
#endif
1547
0
  if (!nn_config_hor || !nn_config_ver) return;  // Model not established yet.
1548
1549
0
  float hfeatures[16], vfeatures[16];
1550
0
  float hscores[4], vscores[4];
1551
0
  float scores_2D_raw[16];
1552
0
  const int bw = tx_size_wide[tx_size];
1553
0
  const int bh = tx_size_high[tx_size];
1554
0
  const int hfeatures_num = bw <= 8 ? bw : bw / 2;
1555
0
  const int vfeatures_num = bh <= 8 ? bh : bh / 2;
1556
0
  assert(hfeatures_num <= 16);
1557
0
  assert(vfeatures_num <= 16);
1558
1559
0
  const struct macroblock_plane *const p = &x->plane[0];
1560
0
  const int diff_stride = block_size_wide[bsize];
1561
0
  const int16_t *diff = p->src_diff + 4 * blk_row * diff_stride + 4 * blk_col;
1562
0
  get_energy_distribution_finer(diff, diff_stride, bw, bh, hfeatures,
1563
0
                                vfeatures);
1564
1565
0
  av1_get_horver_correlation_full(diff, diff_stride, bw, bh,
1566
0
                                  &hfeatures[hfeatures_num - 1],
1567
0
                                  &vfeatures[vfeatures_num - 1]);
1568
1569
#if CONFIG_NN_V2
1570
  av1_nn_predict_v2(hfeatures, nn_config_hor, 0, hscores);
1571
  av1_nn_predict_v2(vfeatures, nn_config_ver, 0, vscores);
1572
#else
1573
0
  av1_nn_predict(hfeatures, nn_config_hor, 1, hscores);
1574
0
  av1_nn_predict(vfeatures, nn_config_ver, 1, vscores);
1575
0
#endif
1576
1577
0
  for (int i = 0; i < 4; i++) {
1578
0
    float *cur_scores_2D = scores_2D_raw + i * 4;
1579
0
    cur_scores_2D[0] = vscores[i] * hscores[0];
1580
0
    cur_scores_2D[1] = vscores[i] * hscores[1];
1581
0
    cur_scores_2D[2] = vscores[i] * hscores[2];
1582
0
    cur_scores_2D[3] = vscores[i] * hscores[3];
1583
0
  }
1584
1585
0
  assert(TX_TYPES == 16);
1586
  // This version of the function only works when there are at most 16 classes.
1587
  // So we will need to change the optimization or use av1_nn_softmax instead if
1588
  // this ever gets changed.
1589
0
  av1_nn_fast_softmax_16(scores_2D_raw, scores_2D_raw);
1590
1591
0
  const float score_thresh =
1592
0
      get_adaptive_thresholds(tx_size, tx_set_type, prune_2d_txfm_mode);
1593
1594
  // Always keep the TX type with the highest score, prune all others with
1595
  // score below score_thresh.
1596
0
  int max_score_i = 0;
1597
0
  float max_score = 0.0f;
1598
0
  uint16_t allow_bitmask = 0;
1599
0
  float sum_score = 0.0;
1600
  // Calculate sum of allowed tx type score and Populate allow bit mask based
1601
  // on score_thresh and allowed_tx_mask
1602
0
  int allow_count = 0;
1603
0
  int tx_type_allowed[16] = { TX_TYPE_INVALID, TX_TYPE_INVALID, TX_TYPE_INVALID,
1604
0
                              TX_TYPE_INVALID, TX_TYPE_INVALID, TX_TYPE_INVALID,
1605
0
                              TX_TYPE_INVALID, TX_TYPE_INVALID, TX_TYPE_INVALID,
1606
0
                              TX_TYPE_INVALID, TX_TYPE_INVALID, TX_TYPE_INVALID,
1607
0
                              TX_TYPE_INVALID, TX_TYPE_INVALID, TX_TYPE_INVALID,
1608
0
                              TX_TYPE_INVALID };
1609
0
  float scores_2D[16] = {
1610
0
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1611
0
  };
1612
0
  for (int tx_idx = 0; tx_idx < TX_TYPES; tx_idx++) {
1613
0
    const int allow_tx_type =
1614
0
        check_bit_mask(*allowed_tx_mask, tx_type_table_2D[tx_idx]);
1615
0
    if (!allow_tx_type) {
1616
0
      continue;
1617
0
    }
1618
0
    if (scores_2D_raw[tx_idx] > max_score) {
1619
0
      max_score = scores_2D_raw[tx_idx];
1620
0
      max_score_i = tx_idx;
1621
0
    }
1622
0
    if (scores_2D_raw[tx_idx] >= score_thresh) {
1623
      // Set allow mask based on score_thresh
1624
0
      set_bit_mask(&allow_bitmask, tx_type_table_2D[tx_idx]);
1625
1626
      // Accumulate score of allowed tx type
1627
0
      sum_score += scores_2D_raw[tx_idx];
1628
1629
0
      scores_2D[allow_count] = scores_2D_raw[tx_idx];
1630
0
      tx_type_allowed[allow_count] = tx_type_table_2D[tx_idx];
1631
0
      allow_count += 1;
1632
0
    }
1633
0
  }
1634
0
  if (!check_bit_mask(allow_bitmask, tx_type_table_2D[max_score_i])) {
1635
    // If even the tx_type with max score is pruned, this means that no other
1636
    // tx_type is feasible. When this happens, we force enable max_score_i and
1637
    // end the search.
1638
0
    set_bit_mask(&allow_bitmask, tx_type_table_2D[max_score_i]);
1639
0
    memcpy(txk_map, tx_type_table_2D, sizeof(tx_type_table_2D));
1640
0
    *allowed_tx_mask = allow_bitmask;
1641
0
    return;
1642
0
  }
1643
1644
  // Sort tx type probability of all types
1645
0
  if (allow_count <= 8) {
1646
0
    av1_sort_fi32_8(scores_2D, tx_type_allowed);
1647
0
  } else {
1648
0
    av1_sort_fi32_16(scores_2D, tx_type_allowed);
1649
0
  }
1650
1651
  // Enable more pruning based on tx type probability and number of allowed tx
1652
  // types
1653
0
  if (prune_2d_txfm_mode >= TX_TYPE_PRUNE_4) {
1654
0
    float temp_score = 0.0;
1655
0
    float score_ratio = 0.0;
1656
0
    int tx_idx, tx_count = 0;
1657
0
    const float inv_sum_score = 100 / sum_score;
1658
    // Get allowed tx types based on sorted probability score and tx count
1659
0
    for (tx_idx = 0; tx_idx < allow_count; tx_idx++) {
1660
      // Skip the tx type which has more than 30% of cumulative
1661
      // probability and allowed tx type count is more than 2
1662
0
      if (score_ratio > 30.0 && tx_count >= 2) break;
1663
1664
0
      assert(check_bit_mask(allow_bitmask, tx_type_allowed[tx_idx]));
1665
      // Calculate cumulative probability
1666
0
      temp_score += scores_2D[tx_idx];
1667
1668
      // Calculate percentage of cumulative probability of allowed tx type
1669
0
      score_ratio = temp_score * inv_sum_score;
1670
0
      tx_count++;
1671
0
    }
1672
    // Set remaining tx types as pruned
1673
0
    for (; tx_idx < allow_count; tx_idx++)
1674
0
      unset_bit_mask(&allow_bitmask, tx_type_allowed[tx_idx]);
1675
0
  }
1676
1677
0
  memcpy(txk_map, tx_type_allowed, sizeof(tx_type_table_2D));
1678
0
  *allowed_tx_mask = allow_bitmask;
1679
0
}
1680
1681
0
static float get_dev(float mean, double x2_sum, int num) {
1682
0
  const float e_x2 = (float)(x2_sum / num);
1683
0
  const float diff = e_x2 - mean * mean;
1684
0
  const float dev = (diff > 0) ? sqrtf(diff) : 0;
1685
0
  return dev;
1686
0
}
1687
1688
// Writes the features required by the ML model to predict tx split based on
1689
// mean and standard deviation values of the block and sub-blocks.
1690
// Returns the number of elements written to the output array which is at most
1691
// 12 currently. Hence 'features' buffer should be able to accommodate at least
1692
// 12 elements.
1693
static inline int get_mean_dev_features(const int16_t *data, int stride, int bw,
1694
0
                                        int bh, float *features) {
1695
0
  const int16_t *const data_ptr = &data[0];
1696
0
  const int subh = (bh >= bw) ? (bh >> 1) : bh;
1697
0
  const int subw = (bw >= bh) ? (bw >> 1) : bw;
1698
0
  const int num = bw * bh;
1699
0
  const int sub_num = subw * subh;
1700
0
  int feature_idx = 2;
1701
0
  int total_x_sum = 0;
1702
0
  int64_t total_x2_sum = 0;
1703
0
  int num_sub_blks = 0;
1704
0
  double mean2_sum = 0.0f;
1705
0
  float dev_sum = 0.0f;
1706
1707
0
  for (int row = 0; row < bh; row += subh) {
1708
0
    for (int col = 0; col < bw; col += subw) {
1709
0
      int x_sum;
1710
0
      int64_t x2_sum;
1711
      // TODO(any): Write a SIMD version. Clear registers.
1712
0
      aom_get_blk_sse_sum(data_ptr + row * stride + col, stride, subw, subh,
1713
0
                          &x_sum, &x2_sum);
1714
0
      total_x_sum += x_sum;
1715
0
      total_x2_sum += x2_sum;
1716
1717
0
      const float mean = (float)x_sum / sub_num;
1718
0
      const float dev = get_dev(mean, (double)x2_sum, sub_num);
1719
0
      features[feature_idx++] = mean;
1720
0
      features[feature_idx++] = dev;
1721
0
      mean2_sum += (double)(mean * mean);
1722
0
      dev_sum += dev;
1723
0
      num_sub_blks++;
1724
0
    }
1725
0
  }
1726
1727
0
  const float lvl0_mean = (float)total_x_sum / num;
1728
0
  features[0] = lvl0_mean;
1729
0
  features[1] = get_dev(lvl0_mean, (double)total_x2_sum, num);
1730
1731
  // Deviation of means.
1732
0
  features[feature_idx++] = get_dev(lvl0_mean, mean2_sum, num_sub_blks);
1733
  // Mean of deviations.
1734
0
  features[feature_idx++] = dev_sum / num_sub_blks;
1735
1736
0
  return feature_idx;
1737
0
}
1738
1739
static int ml_predict_tx_split(MACROBLOCK *x, BLOCK_SIZE bsize, int blk_row,
1740
0
                               int blk_col, TX_SIZE tx_size) {
1741
0
  const NN_CONFIG *nn_config = av1_tx_split_nnconfig_map[tx_size];
1742
0
  if (!nn_config) return -1;
1743
1744
0
  const int diff_stride = block_size_wide[bsize];
1745
0
  const int16_t *diff =
1746
0
      x->plane[0].src_diff + 4 * blk_row * diff_stride + 4 * blk_col;
1747
0
  const int bw = tx_size_wide[tx_size];
1748
0
  const int bh = tx_size_high[tx_size];
1749
1750
0
  float features[64] = { 0.0f };
1751
0
  get_mean_dev_features(diff, diff_stride, bw, bh, features);
1752
1753
0
  float score = 0.0f;
1754
0
  av1_nn_predict(features, nn_config, 1, &score);
1755
1756
0
  int int_score = (int)(score * 10000);
1757
0
  return clamp(int_score, -80000, 80000);
1758
0
}
1759
1760
static inline uint16_t get_tx_mask(
1761
    const AV1_COMP *cpi, MACROBLOCK *x, int plane, int block, int blk_row,
1762
    int blk_col, BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
1763
    const TXB_CTX *const txb_ctx, FAST_TX_SEARCH_MODE ftxs_mode,
1764
0
    int64_t ref_best_rd, TX_TYPE *allowed_txk_types, int *txk_map) {
1765
0
  const AV1_COMMON *cm = &cpi->common;
1766
0
  MACROBLOCKD *xd = &x->e_mbd;
1767
0
  MB_MODE_INFO *mbmi = xd->mi[0];
1768
0
  const TxfmSearchParams *txfm_params = &x->txfm_search_params;
1769
0
  const int is_inter = is_inter_block(mbmi);
1770
0
  const int fast_tx_search = ftxs_mode & FTXS_DCT_AND_1D_DCT_ONLY;
1771
  // if txk_allowed = TX_TYPES, >1 tx types are allowed, else, if txk_allowed <
1772
  // TX_TYPES, only that specific tx type is allowed.
1773
0
  TX_TYPE txk_allowed = TX_TYPES;
1774
1775
0
  const FRAME_UPDATE_TYPE update_type =
1776
0
      get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index);
1777
0
  int use_actual_frame_probs = 1;
1778
0
  const int *tx_type_probs;
1779
#if CONFIG_FPMT_TEST
1780
  use_actual_frame_probs =
1781
      (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) ? 0 : 1;
1782
  if (!use_actual_frame_probs) {
1783
    tx_type_probs =
1784
        (int *)cpi->ppi->temp_frame_probs.tx_type_probs[update_type][tx_size];
1785
  }
1786
#endif
1787
0
  if (use_actual_frame_probs) {
1788
0
    tx_type_probs = cpi->ppi->frame_probs.tx_type_probs[update_type][tx_size];
1789
0
  }
1790
1791
0
  if ((!is_inter && txfm_params->use_default_intra_tx_type) ||
1792
0
      (is_inter && txfm_params->default_inter_tx_type_prob_thresh == 0)) {
1793
0
    txk_allowed =
1794
0
        get_default_tx_type(0, xd, tx_size, cpi->use_screen_content_tools);
1795
0
  } else if (is_inter &&
1796
0
             txfm_params->default_inter_tx_type_prob_thresh != INT_MAX) {
1797
0
    if (tx_type_probs[DEFAULT_INTER_TX_TYPE] >
1798
0
        txfm_params->default_inter_tx_type_prob_thresh) {
1799
0
      txk_allowed = DEFAULT_INTER_TX_TYPE;
1800
0
    } else {
1801
0
      int force_tx_type = 0;
1802
0
      int max_prob = 0;
1803
0
      const int tx_type_prob_threshold =
1804
0
          txfm_params->default_inter_tx_type_prob_thresh +
1805
0
          PROB_THRESH_OFFSET_TX_TYPE;
1806
0
      for (int i = 1; i < TX_TYPES; i++) {  // find maximum probability.
1807
0
        if (tx_type_probs[i] > max_prob) {
1808
0
          max_prob = tx_type_probs[i];
1809
0
          force_tx_type = i;
1810
0
        }
1811
0
      }
1812
0
      if (max_prob > tx_type_prob_threshold)  // force tx type with max prob.
1813
0
        txk_allowed = force_tx_type;
1814
0
      else if (x->rd_model == LOW_TXFM_RD) {
1815
0
        if (plane == 0) txk_allowed = DCT_DCT;
1816
0
      }
1817
0
    }
1818
0
  } else if (x->rd_model == LOW_TXFM_RD) {
1819
0
    if (plane == 0) txk_allowed = DCT_DCT;
1820
0
  }
1821
1822
0
  const TxSetType tx_set_type = av1_get_ext_tx_set_type(
1823
0
      tx_size, is_inter, cm->features.reduced_tx_set_used);
1824
1825
0
  TX_TYPE uv_tx_type = DCT_DCT;
1826
0
  if (plane) {
1827
    // tx_type of PLANE_TYPE_UV should be the same as PLANE_TYPE_Y
1828
0
    uv_tx_type = txk_allowed =
1829
0
        av1_get_tx_type(xd, get_plane_type(plane), blk_row, blk_col, tx_size,
1830
0
                        cm->features.reduced_tx_set_used);
1831
0
  }
1832
0
  PREDICTION_MODE intra_dir =
1833
0
      mbmi->filter_intra_mode_info.use_filter_intra
1834
0
          ? fimode_to_intradir[mbmi->filter_intra_mode_info.filter_intra_mode]
1835
0
          : mbmi->mode;
1836
0
  uint16_t ext_tx_used_flag =
1837
0
      cpi->sf.tx_sf.tx_type_search.use_reduced_intra_txset != 0 &&
1838
0
              tx_set_type == EXT_TX_SET_DTT4_IDTX_1DDCT
1839
0
          ? av1_reduced_intra_tx_used_flag[intra_dir]
1840
0
          : av1_ext_tx_used_flag[tx_set_type];
1841
1842
0
  if (cpi->sf.tx_sf.tx_type_search.use_reduced_intra_txset == 2)
1843
0
    ext_tx_used_flag &= av1_derived_intra_tx_used_flag[intra_dir];
1844
1845
0
  if (xd->lossless[mbmi->segment_id] || txsize_sqr_up_map[tx_size] > TX_32X32 ||
1846
0
      ext_tx_used_flag == 0x0001 ||
1847
0
      (is_inter && cpi->oxcf.txfm_cfg.use_inter_dct_only) ||
1848
0
      (!is_inter && cpi->oxcf.txfm_cfg.use_intra_dct_only)) {
1849
0
    txk_allowed = DCT_DCT;
1850
0
  }
1851
1852
0
  if (cpi->oxcf.txfm_cfg.enable_flip_idtx == 0)
1853
0
    ext_tx_used_flag &= DCT_ADST_TX_MASK;
1854
1855
0
  uint16_t allowed_tx_mask = 0;  // 1: allow; 0: skip.
1856
0
  if (txk_allowed < TX_TYPES) {
1857
0
    allowed_tx_mask = 1 << txk_allowed;
1858
0
    allowed_tx_mask &= ext_tx_used_flag;
1859
0
  } else if (fast_tx_search) {
1860
0
    allowed_tx_mask = 0x0c01;  // V_DCT, H_DCT, DCT_DCT
1861
0
    allowed_tx_mask &= ext_tx_used_flag;
1862
0
  } else if (!is_inter && txfm_params->use_derived_intra_tx_type_set) {
1863
0
    allowed_tx_mask = av1_derived_intra_tx_used_flag[intra_dir];
1864
0
    allowed_tx_mask &= ext_tx_used_flag;
1865
0
  } else {
1866
0
    assert(plane == 0);
1867
0
    allowed_tx_mask = ext_tx_used_flag;
1868
0
    int num_allowed = 0;
1869
0
    int i;
1870
1871
0
    if (cpi->sf.tx_sf.tx_type_search.prune_tx_type_using_stats) {
1872
0
      static const int thresh_arr[2][7] = { { 10, 15, 15, 10, 15, 15, 15 },
1873
0
                                            { 10, 17, 17, 10, 17, 17, 17 } };
1874
0
      const int thresh =
1875
0
          thresh_arr[cpi->sf.tx_sf.tx_type_search.prune_tx_type_using_stats - 1]
1876
0
                    [update_type];
1877
0
      uint16_t prune = 0;
1878
0
      int max_prob = -1;
1879
0
      int max_idx = 0;
1880
0
      for (i = 0; i < TX_TYPES; i++) {
1881
0
        if (tx_type_probs[i] > max_prob && (allowed_tx_mask & (1 << i))) {
1882
0
          max_prob = tx_type_probs[i];
1883
0
          max_idx = i;
1884
0
        }
1885
0
        if (tx_type_probs[i] < thresh) prune |= (1 << i);
1886
0
      }
1887
0
      if ((prune >> max_idx) & 0x01) prune &= ~(1 << max_idx);
1888
0
      allowed_tx_mask &= (~prune);
1889
0
    }
1890
0
    for (i = 0; i < TX_TYPES; i++) {
1891
0
      if (allowed_tx_mask & (1 << i)) num_allowed++;
1892
0
    }
1893
0
    assert(num_allowed > 0);
1894
1895
0
    if (num_allowed > 2 && cpi->sf.tx_sf.tx_type_search.prune_tx_type_est_rd) {
1896
0
      int pf = prune_factors[txfm_params->prune_2d_txfm_mode];
1897
0
      int mf = mul_factors[txfm_params->prune_2d_txfm_mode];
1898
0
      if (num_allowed <= 7) {
1899
0
        const uint16_t prune =
1900
0
            prune_txk_type(cpi, x, plane, block, tx_size, blk_row, blk_col,
1901
0
                           plane_bsize, txk_map, allowed_tx_mask, pf, txb_ctx,
1902
0
                           cm->features.reduced_tx_set_used);
1903
0
        allowed_tx_mask &= (~prune);
1904
0
      } else {
1905
0
        const int num_sel = (num_allowed * mf + 50) / 100;
1906
0
        const uint16_t prune = prune_txk_type_separ(
1907
0
            cpi, x, plane, block, tx_size, blk_row, blk_col, plane_bsize,
1908
0
            txk_map, allowed_tx_mask, pf, txb_ctx,
1909
0
            cm->features.reduced_tx_set_used, ref_best_rd, num_sel);
1910
1911
0
        allowed_tx_mask &= (~prune);
1912
0
      }
1913
0
    } else {
1914
0
      assert(num_allowed > 0);
1915
0
      int allowed_tx_count =
1916
0
          (txfm_params->prune_2d_txfm_mode >= TX_TYPE_PRUNE_4) ? 1 : 5;
1917
      // !fast_tx_search && txk_end != txk_start && plane == 0
1918
0
      if (txfm_params->prune_2d_txfm_mode >= TX_TYPE_PRUNE_1 && is_inter &&
1919
0
          num_allowed > allowed_tx_count) {
1920
0
        prune_tx_2D(x, plane_bsize, tx_size, blk_row, blk_col, tx_set_type,
1921
0
                    txfm_params->prune_2d_txfm_mode, txk_map, &allowed_tx_mask);
1922
0
      }
1923
0
    }
1924
0
  }
1925
1926
  // Need to have at least one transform type allowed.
1927
0
  if (allowed_tx_mask == 0) {
1928
0
    txk_allowed = (plane ? uv_tx_type : DCT_DCT);
1929
0
    allowed_tx_mask = (1 << txk_allowed);
1930
0
  }
1931
1932
0
  assert(IMPLIES(txk_allowed < TX_TYPES, allowed_tx_mask == 1 << txk_allowed));
1933
0
  *allowed_txk_types = txk_allowed;
1934
0
  return allowed_tx_mask;
1935
0
}
1936
1937
#if CONFIG_RD_DEBUG
1938
static inline void update_txb_coeff_cost(RD_STATS *rd_stats, int plane,
1939
                                         int txb_coeff_cost) {
1940
  rd_stats->txb_coeff_cost[plane] += txb_coeff_cost;
1941
}
1942
#endif
1943
1944
static inline int cost_coeffs(MACROBLOCK *x, int plane, int block,
1945
                              TX_SIZE tx_size, const TX_TYPE tx_type,
1946
                              const TXB_CTX *const txb_ctx,
1947
0
                              int reduced_tx_set_used) {
1948
#if TXCOEFF_COST_TIMER
1949
  struct aom_usec_timer timer;
1950
  aom_usec_timer_start(&timer);
1951
#endif
1952
0
  const int cost = av1_cost_coeffs_txb(x, plane, block, tx_size, tx_type,
1953
0
                                       txb_ctx, reduced_tx_set_used);
1954
#if TXCOEFF_COST_TIMER
1955
  AV1_COMMON *tmp_cm = (AV1_COMMON *)&cpi->common;
1956
  aom_usec_timer_mark(&timer);
1957
  const int64_t elapsed_time = aom_usec_timer_elapsed(&timer);
1958
  tmp_cm->txcoeff_cost_timer += elapsed_time;
1959
  ++tmp_cm->txcoeff_cost_count;
1960
#endif
1961
0
  return cost;
1962
0
}
1963
1964
static int skip_trellis_opt_based_on_satd(MACROBLOCK *x,
1965
                                          QUANT_PARAM *quant_param, int plane,
1966
                                          int block, TX_SIZE tx_size,
1967
                                          int quant_b_adapt, int qstep,
1968
                                          unsigned int coeff_opt_satd_threshold,
1969
0
                                          int skip_trellis, int dc_only_blk) {
1970
0
  if (skip_trellis || (coeff_opt_satd_threshold == UINT_MAX))
1971
0
    return skip_trellis;
1972
1973
0
  const struct macroblock_plane *const p = &x->plane[plane];
1974
0
  const int block_offset = BLOCK_OFFSET(block);
1975
0
  tran_low_t *const coeff_ptr = p->coeff + block_offset;
1976
0
  const int n_coeffs = av1_get_max_eob(tx_size);
1977
0
  const int shift = (MAX_TX_SCALE - av1_get_tx_scale(tx_size));
1978
0
  int satd = (dc_only_blk) ? abs(coeff_ptr[0]) : aom_satd(coeff_ptr, n_coeffs);
1979
0
  satd = RIGHT_SIGNED_SHIFT(satd, shift);
1980
0
  satd >>= (x->e_mbd.bd - 8);
1981
1982
0
  const int skip_block_trellis =
1983
0
      ((uint64_t)satd >
1984
0
       (uint64_t)coeff_opt_satd_threshold * qstep * sqrt_tx_pixels_2d[tx_size]);
1985
1986
0
  av1_setup_quant(
1987
0
      tx_size, !skip_block_trellis,
1988
0
      skip_block_trellis
1989
0
          ? (USE_B_QUANT_NO_TRELLIS ? AV1_XFORM_QUANT_B : AV1_XFORM_QUANT_FP)
1990
0
          : AV1_XFORM_QUANT_FP,
1991
0
      quant_b_adapt, quant_param);
1992
1993
0
  return skip_block_trellis;
1994
0
}
1995
1996
// Predict DC only blocks if the residual variance is below a qstep based
1997
// threshold.For such blocks, transform type search is bypassed.
1998
static inline void predict_dc_only_block(
1999
    MACROBLOCK *x, int plane, BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
2000
    int block, int blk_row, int blk_col, RD_STATS *best_rd_stats,
2001
    int64_t *block_sse, unsigned int *block_mse_q8, int64_t *per_px_mean,
2002
0
    int *dc_only_blk) {
2003
0
  MACROBLOCKD *xd = &x->e_mbd;
2004
0
  MB_MODE_INFO *mbmi = xd->mi[0];
2005
0
  const int dequant_shift = (is_cur_buf_hbd(xd)) ? xd->bd - 5 : 3;
2006
0
  const int qstep = x->plane[plane].dequant_QTX[1] >> dequant_shift;
2007
0
  uint64_t block_var = UINT64_MAX;
2008
0
  const int dc_qstep = x->plane[plane].dequant_QTX[0] >> 3;
2009
0
  *block_sse = pixel_diff_stats(x, plane, blk_row, blk_col, plane_bsize,
2010
0
                                txsize_to_bsize[tx_size], block_mse_q8,
2011
0
                                per_px_mean, &block_var);
2012
0
  assert((*block_mse_q8) != UINT_MAX);
2013
0
  uint64_t var_threshold = (uint64_t)(1.8 * qstep * qstep);
2014
0
  if (is_cur_buf_hbd(xd))
2015
0
    block_var = ROUND_POWER_OF_TWO(block_var, (xd->bd - 8) * 2);
2016
2017
0
  if (block_var >= var_threshold) return;
2018
0
  const unsigned int predict_dc_level = x->txfm_search_params.predict_dc_level;
2019
0
  assert(predict_dc_level != 0);
2020
2021
  // Prediction of skip block if residual mean and variance are less
2022
  // than qstep based threshold
2023
0
  if ((llabs(*per_px_mean) * dc_coeff_scale[tx_size]) < (dc_qstep << 12)) {
2024
    // If the normalized mean of residual block is less than the dc qstep and
2025
    // the  normalized block variance is less than ac qstep, then the block is
2026
    // assumed to be a skip block and its rdcost is updated accordingly.
2027
0
    best_rd_stats->skip_txfm = 1;
2028
2029
0
    x->plane[plane].eobs[block] = 0;
2030
2031
0
    if (is_cur_buf_hbd(xd))
2032
0
      *block_sse = ROUND_POWER_OF_TWO((*block_sse), (xd->bd - 8) * 2);
2033
2034
0
    best_rd_stats->dist = (*block_sse) << 4;
2035
0
    best_rd_stats->sse = best_rd_stats->dist;
2036
2037
0
    ENTROPY_CONTEXT ctxa[MAX_MIB_SIZE];
2038
0
    ENTROPY_CONTEXT ctxl[MAX_MIB_SIZE];
2039
0
    av1_get_entropy_contexts(plane_bsize, &xd->plane[plane], ctxa, ctxl);
2040
0
    ENTROPY_CONTEXT *ta = ctxa;
2041
0
    ENTROPY_CONTEXT *tl = ctxl;
2042
0
    const TX_SIZE txs_ctx = get_txsize_entropy_ctx(tx_size);
2043
0
    TXB_CTX txb_ctx_tmp;
2044
0
    const PLANE_TYPE plane_type = get_plane_type(plane);
2045
0
    get_txb_ctx(plane_bsize, tx_size, plane, ta, tl, &txb_ctx_tmp);
2046
0
    const int zero_blk_rate = x->coeff_costs.coeff_costs[txs_ctx][plane_type]
2047
0
                                  .txb_skip_cost[txb_ctx_tmp.txb_skip_ctx][1];
2048
0
    best_rd_stats->rate = zero_blk_rate;
2049
2050
0
    best_rd_stats->rdcost =
2051
0
        RDCOST(x->rdmult, best_rd_stats->rate, best_rd_stats->sse);
2052
2053
0
    x->plane[plane].txb_entropy_ctx[block] = 0;
2054
0
  } else if (predict_dc_level > 1) {
2055
    // Predict DC only blocks based on residual variance.
2056
    // For chroma plane, this prediction is disabled for intra blocks.
2057
0
    if ((plane == 0) || (plane > 0 && is_inter_block(mbmi))) *dc_only_blk = 1;
2058
0
  }
2059
0
}
2060
2061
// Search for the best transform type for a given transform block.
2062
// This function can be used for both inter and intra, both luma and chroma.
2063
static void search_tx_type(const AV1_COMP *cpi, MACROBLOCK *x, int plane,
2064
                           int block, int blk_row, int blk_col,
2065
                           BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
2066
                           const TXB_CTX *const txb_ctx,
2067
                           FAST_TX_SEARCH_MODE ftxs_mode, int64_t ref_best_rd,
2068
0
                           RD_STATS *best_rd_stats) {
2069
0
  const AV1_COMMON *cm = &cpi->common;
2070
0
  MACROBLOCKD *xd = &x->e_mbd;
2071
0
  MB_MODE_INFO *mbmi = xd->mi[0];
2072
0
  const TxfmSearchParams *txfm_params = &x->txfm_search_params;
2073
0
  int64_t best_rd = INT64_MAX;
2074
0
  uint16_t best_eob = 0;
2075
0
  TX_TYPE best_tx_type = DCT_DCT;
2076
0
  int rate_cost = 0;
2077
0
  struct macroblock_plane *const p = &x->plane[plane];
2078
0
  tran_low_t *orig_dqcoeff = p->dqcoeff;
2079
0
  tran_low_t *best_dqcoeff = x->dqcoeff_buf;
2080
0
  const int tx_type_map_idx =
2081
0
      plane ? 0 : blk_row * xd->tx_type_map_stride + blk_col;
2082
0
  av1_invalid_rd_stats(best_rd_stats);
2083
2084
0
  int skip_trellis = !is_trellis_used(
2085
0
      cpi->optimize_seg_arr[xd->mi[0]->segment_id], DRY_RUN_NORMAL);
2086
2087
0
  uint8_t best_txb_ctx = 0;
2088
  // txk_allowed = TX_TYPES: >1 tx types are allowed
2089
  // txk_allowed < TX_TYPES: only that specific tx type is allowed.
2090
0
  TX_TYPE txk_allowed = TX_TYPES;
2091
0
  int txk_map[TX_TYPES] = {
2092
0
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
2093
0
  };
2094
0
  const int dequant_shift = (is_cur_buf_hbd(xd)) ? xd->bd - 5 : 3;
2095
0
  const int qstep = x->plane[plane].dequant_QTX[1] >> dequant_shift;
2096
2097
0
  const uint8_t txw = tx_size_wide[tx_size];
2098
0
  const uint8_t txh = tx_size_high[tx_size];
2099
0
  int64_t block_sse;
2100
0
  unsigned int block_mse_q8;
2101
0
  int dc_only_blk = 0;
2102
0
  const bool predict_dc_block =
2103
0
      txfm_params->predict_dc_level >= 1 && txw != 64 && txh != 64;
2104
0
  int64_t per_px_mean = INT64_MAX;
2105
2106
0
  int is_border_block = 0;
2107
0
  if (cpi->do_border_pad) {
2108
0
    is_border_block =
2109
0
        get_visible_dimensions(x, plane, plane_bsize, blk_col, blk_row, txw,
2110
0
                               txh, /*clip_dims=*/true, NULL, NULL);
2111
0
    if (is_border_block)
2112
0
      av1_subtract_txb(x, plane, plane_bsize, blk_col, blk_row, tx_size,
2113
0
                       best_tx_type, cpi->do_border_pad);
2114
0
  }
2115
2116
0
  if (predict_dc_block) {
2117
0
    predict_dc_only_block(x, plane, plane_bsize, tx_size, block, blk_row,
2118
0
                          blk_col, best_rd_stats, &block_sse, &block_mse_q8,
2119
0
                          &per_px_mean, &dc_only_blk);
2120
0
    if (best_rd_stats->skip_txfm == 1) {
2121
0
      const TX_TYPE tx_type = DCT_DCT;
2122
0
      if (plane == 0) xd->tx_type_map[tx_type_map_idx] = tx_type;
2123
0
      return;
2124
0
    }
2125
0
  } else {
2126
0
    block_sse = av1_pixel_diff_dist(x, plane, blk_row, blk_col, plane_bsize,
2127
0
                                    txsize_to_bsize[tx_size], &block_mse_q8);
2128
0
    assert(block_mse_q8 != UINT_MAX);
2129
0
  }
2130
2131
  // Bit mask to indicate which transform types are allowed in the RD search.
2132
0
  uint16_t tx_mask;
2133
2134
  // Use DCT_DCT transform for DC only block.
2135
0
  if (dc_only_blk || cpi->sf.rt_sf.dct_only_palette_nonrd == 1)
2136
0
    tx_mask = 1 << DCT_DCT;
2137
0
  else
2138
0
    tx_mask = get_tx_mask(cpi, x, plane, block, blk_row, blk_col, plane_bsize,
2139
0
                          tx_size, txb_ctx, ftxs_mode, ref_best_rd,
2140
0
                          &txk_allowed, txk_map);
2141
0
  const uint16_t allowed_tx_mask = tx_mask;
2142
2143
0
  if (is_cur_buf_hbd(xd)) {
2144
0
    block_sse = ROUND_POWER_OF_TWO(block_sse, (xd->bd - 8) * 2);
2145
0
    block_mse_q8 = ROUND_POWER_OF_TWO(block_mse_q8, (xd->bd - 8) * 2);
2146
0
  }
2147
0
  block_sse *= 16;
2148
  // Use mse / qstep^2 based threshold logic to take decision of R-D
2149
  // optimization of coeffs. For smaller residuals, coeff optimization
2150
  // would be helpful. For larger residuals, R-D optimization may not be
2151
  // effective.
2152
  // TODO(any): Experiment with variance and mean based thresholds
2153
0
  const int perform_block_coeff_opt =
2154
0
      ((uint64_t)block_mse_q8 <=
2155
0
       (uint64_t)txfm_params->coeff_opt_thresholds[0] * qstep * qstep);
2156
0
  skip_trellis |= !perform_block_coeff_opt;
2157
2158
  // Flag to indicate if distortion should be calculated in transform domain or
2159
  // not during iterating through transform type candidates.
2160
  // Transform domain distortion is accurate for higher residuals.
2161
  // TODO(any): Experiment with variance and mean based thresholds
2162
0
  int use_transform_domain_distortion =
2163
0
      (txfm_params->use_transform_domain_distortion > 0) &&
2164
0
      (block_mse_q8 >= txfm_params->tx_domain_dist_threshold) &&
2165
      // Any 64-pt transforms only preserves half the coefficients.
2166
      // Therefore transform domain distortion is not valid for these
2167
      // transform sizes.
2168
0
      (txsize_sqr_up_map[tx_size] != TX_64X64) &&
2169
      // Use pixel domain distortion for DC only blocks
2170
0
      !dc_only_blk;
2171
  // Flag to indicate if an extra calculation of distortion in the pixel domain
2172
  // should be performed at the end, after the best transform type has been
2173
  // decided.
2174
0
  int calc_pixel_domain_distortion_final =
2175
0
      txfm_params->use_transform_domain_distortion == 1 &&
2176
0
      use_transform_domain_distortion && x->rd_model != LOW_TXFM_RD;
2177
0
  if (calc_pixel_domain_distortion_final &&
2178
0
      (txk_allowed < TX_TYPES || allowed_tx_mask == 0x0001))
2179
0
    calc_pixel_domain_distortion_final = use_transform_domain_distortion = 0;
2180
2181
0
  const uint16_t *eobs_ptr = x->plane[plane].eobs;
2182
2183
0
  TxfmParam txfm_param;
2184
0
  QUANT_PARAM quant_param;
2185
0
  int skip_trellis_based_on_satd[TX_TYPES] = { 0 };
2186
0
  av1_setup_xform(cm, x, tx_size, DCT_DCT, &txfm_param);
2187
0
  av1_setup_quant(tx_size, !skip_trellis,
2188
0
                  skip_trellis ? (USE_B_QUANT_NO_TRELLIS ? AV1_XFORM_QUANT_B
2189
0
                                                         : AV1_XFORM_QUANT_FP)
2190
0
                               : AV1_XFORM_QUANT_FP,
2191
0
                  cpi->oxcf.q_cfg.quant_b_adapt, &quant_param);
2192
2193
  // Iterate through all transform type candidates.
2194
0
  for (int idx = 0; idx < TX_TYPES; ++idx) {
2195
0
    const TX_TYPE tx_type = (TX_TYPE)txk_map[idx];
2196
0
    if (tx_type == TX_TYPE_INVALID || !check_bit_mask(allowed_tx_mask, tx_type))
2197
0
      continue;
2198
0
    txfm_param.tx_type = tx_type;
2199
0
    if (av1_use_qmatrix(&cm->quant_params, xd, mbmi->segment_id)) {
2200
0
      av1_setup_qmatrix(&cm->quant_params, xd, plane, tx_size, tx_type,
2201
0
                        &quant_param);
2202
0
    }
2203
0
    if (plane == 0) xd->tx_type_map[tx_type_map_idx] = tx_type;
2204
0
    RD_STATS this_rd_stats;
2205
0
    av1_invalid_rd_stats(&this_rd_stats);
2206
2207
0
    if (is_border_block)
2208
0
      av1_subtract_txb(x, plane, plane_bsize, blk_col, blk_row, tx_size,
2209
0
                       tx_type, cpi->do_border_pad);
2210
2211
0
    if (!dc_only_blk)
2212
0
      av1_xform(x, plane, block, blk_row, blk_col, plane_bsize, &txfm_param);
2213
0
    else
2214
0
      av1_xform_dc_only(x, plane, block, &txfm_param, per_px_mean);
2215
2216
0
    skip_trellis_based_on_satd[tx_type] = skip_trellis_opt_based_on_satd(
2217
0
        x, &quant_param, plane, block, tx_size, cpi->oxcf.q_cfg.quant_b_adapt,
2218
0
        qstep, txfm_params->coeff_opt_thresholds[1], skip_trellis, dc_only_blk);
2219
2220
0
    av1_quant(x, plane, block, &txfm_param, &quant_param);
2221
2222
    // Calculate rate cost of quantized coefficients.
2223
0
    if (quant_param.use_optimize_b) {
2224
      // TODO(aomedia:3209): update Trellis quantization to take into account
2225
      // quantization matrices.
2226
0
      av1_optimize_b(cpi, x, plane, block, tx_size, tx_type, txb_ctx,
2227
0
                     &rate_cost);
2228
0
    } else {
2229
0
      rate_cost = cost_coeffs(x, plane, block, tx_size, tx_type, txb_ctx,
2230
0
                              cm->features.reduced_tx_set_used);
2231
0
    }
2232
2233
    // If rd cost based on coeff rate alone is already more than best_rd,
2234
    // terminate early.
2235
0
    if (RDCOST(x->rdmult, rate_cost, 0) > best_rd) continue;
2236
2237
    // Calculate distortion.
2238
0
    if (eobs_ptr[block] == 0) {
2239
      // When eob is 0, pixel domain distortion is more efficient and accurate.
2240
0
      this_rd_stats.dist = this_rd_stats.sse = block_sse;
2241
0
    } else if (dc_only_blk) {
2242
0
      this_rd_stats.sse = block_sse;
2243
0
      this_rd_stats.dist = dist_block_px_domain(
2244
0
          cpi, x, plane, plane_bsize, block, blk_row, blk_col, tx_size);
2245
0
    } else if (use_transform_domain_distortion) {
2246
0
      const SCAN_ORDER *const scan_order =
2247
0
          get_scan(txfm_param.tx_size, txfm_param.tx_type);
2248
0
      dist_block_tx_domain(x, plane, block, tx_size, quant_param.qmatrix,
2249
0
                           scan_order->scan, &this_rd_stats.dist,
2250
0
                           &this_rd_stats.sse);
2251
0
    } else {
2252
0
      int64_t sse_diff = INT64_MAX;
2253
      // high_energy threshold assumes that every pixel within a txfm block
2254
      // has a residue energy of at least 25% of the maximum, i.e. 128 * 128
2255
      // for 8 bit.
2256
0
      const int64_t high_energy_thresh =
2257
0
          ((int64_t)128 * 128 * tx_size_2d[tx_size]);
2258
0
      const int is_high_energy = (block_sse >= high_energy_thresh);
2259
0
      if (tx_size == TX_64X64 || is_high_energy) {
2260
        // Because 3 out 4 quadrants of transform coefficients are forced to
2261
        // zero, the inverse transform has a tendency to overflow. sse_diff
2262
        // is effectively the energy of those 3 quadrants, here we use it
2263
        // to decide if we should do pixel domain distortion. If the energy
2264
        // is mostly in first quadrant, then it is unlikely that we have
2265
        // overflow issue in inverse transform.
2266
0
        const SCAN_ORDER *const scan_order =
2267
0
            get_scan(txfm_param.tx_size, txfm_param.tx_type);
2268
0
        dist_block_tx_domain(x, plane, block, tx_size, quant_param.qmatrix,
2269
0
                             scan_order->scan, &this_rd_stats.dist,
2270
0
                             &this_rd_stats.sse);
2271
0
        sse_diff = block_sse - this_rd_stats.sse;
2272
0
      }
2273
0
      if (tx_size != TX_64X64 || !is_high_energy ||
2274
0
          (sse_diff * 2) < this_rd_stats.sse) {
2275
0
        const int64_t tx_domain_dist = this_rd_stats.dist;
2276
0
        this_rd_stats.dist = dist_block_px_domain(
2277
0
            cpi, x, plane, plane_bsize, block, blk_row, blk_col, tx_size);
2278
        // For high energy blocks, occasionally, the pixel domain distortion
2279
        // can be artificially low due to clamping at reconstruction stage
2280
        // even when inverse transform output is hugely different from the
2281
        // actual residue.
2282
0
        if (is_high_energy && this_rd_stats.dist < tx_domain_dist)
2283
0
          this_rd_stats.dist = tx_domain_dist;
2284
0
      } else {
2285
0
        assert(sse_diff < INT64_MAX);
2286
0
        this_rd_stats.dist += sse_diff;
2287
0
      }
2288
0
      this_rd_stats.sse = block_sse;
2289
0
    }
2290
2291
0
    this_rd_stats.rate = rate_cost;
2292
2293
0
    const int64_t rd =
2294
0
        RDCOST(x->rdmult, this_rd_stats.rate, this_rd_stats.dist);
2295
2296
0
    if (rd < best_rd) {
2297
0
      best_rd = rd;
2298
0
      *best_rd_stats = this_rd_stats;
2299
0
      best_tx_type = tx_type;
2300
0
      best_txb_ctx = x->plane[plane].txb_entropy_ctx[block];
2301
0
      best_eob = x->plane[plane].eobs[block];
2302
      // Swap dqcoeff buffers
2303
0
      tran_low_t *const tmp_dqcoeff = best_dqcoeff;
2304
0
      best_dqcoeff = p->dqcoeff;
2305
0
      p->dqcoeff = tmp_dqcoeff;
2306
0
    }
2307
2308
#if CONFIG_COLLECT_RD_STATS == 1
2309
    if (plane == 0) {
2310
      PrintTransformUnitStats(cpi, x, &this_rd_stats, blk_row, blk_col,
2311
                              plane_bsize, tx_size, tx_type, rd);
2312
    }
2313
#endif  // CONFIG_COLLECT_RD_STATS == 1
2314
2315
#if COLLECT_TX_SIZE_DATA
2316
    // Generate small sample to restrict output size.
2317
    static unsigned int seed = 21743;
2318
    if (lcg_rand16(&seed) % 200 == 0) {
2319
      FILE *fp = NULL;
2320
2321
      if (within_border) {
2322
        fp = fopen(av1_tx_size_data_output_file, "a");
2323
      }
2324
2325
      if (fp) {
2326
        // Transform info and RD
2327
        const int txb_w = tx_size_wide[tx_size];
2328
        const int txb_h = tx_size_high[tx_size];
2329
2330
        // Residue signal.
2331
        const int diff_stride = block_size_wide[plane_bsize];
2332
        struct macroblock_plane *const p = &x->plane[plane];
2333
        const int16_t *src_diff =
2334
            &p->src_diff[(blk_row * diff_stride + blk_col) * 4];
2335
2336
        for (int r = 0; r < txb_h; ++r) {
2337
          for (int c = 0; c < txb_w; ++c) {
2338
            fprintf(fp, "%d,", src_diff[c]);
2339
          }
2340
          src_diff += diff_stride;
2341
        }
2342
2343
        fprintf(fp, "%d,%d,%d,%" PRId64, txb_w, txb_h, tx_type, rd);
2344
        fprintf(fp, "\n");
2345
        fclose(fp);
2346
      }
2347
    }
2348
#endif  // COLLECT_TX_SIZE_DATA
2349
2350
    // If the current best RD cost is much worse than the reference RD cost,
2351
    // terminate early.
2352
0
    if (cpi->sf.tx_sf.adaptive_txb_search_level) {
2353
0
      if ((best_rd - (best_rd >> cpi->sf.tx_sf.adaptive_txb_search_level)) >
2354
0
          ref_best_rd) {
2355
0
        break;
2356
0
      }
2357
0
    }
2358
2359
    // Terminate transform type search if the block has been quantized to
2360
    // all zero.
2361
0
    if (cpi->sf.tx_sf.tx_type_search.skip_tx_search && !best_eob) break;
2362
0
  }
2363
2364
0
  assert(best_rd != INT64_MAX);
2365
2366
0
  best_rd_stats->skip_txfm = best_eob == 0;
2367
0
  if (plane == 0) update_txk_array(xd, blk_row, blk_col, tx_size, best_tx_type);
2368
0
  x->plane[plane].txb_entropy_ctx[block] = best_txb_ctx;
2369
0
  x->plane[plane].eobs[block] = best_eob;
2370
0
  skip_trellis = skip_trellis_based_on_satd[best_tx_type];
2371
2372
  // Point dqcoeff to the quantized coefficients corresponding to the best
2373
  // transform type, then we can skip transform and quantization, e.g. in the
2374
  // final pixel domain distortion calculation and recon_intra().
2375
0
  p->dqcoeff = best_dqcoeff;
2376
2377
0
  if (calc_pixel_domain_distortion_final && best_eob) {
2378
0
    best_rd_stats->dist = dist_block_px_domain(
2379
0
        cpi, x, plane, plane_bsize, block, blk_row, blk_col, tx_size);
2380
0
    best_rd_stats->sse = block_sse;
2381
0
  }
2382
2383
0
  if (is_border_block)
2384
0
    av1_subtract_txb(x, plane, plane_bsize, blk_col, blk_row, tx_size,
2385
0
                     best_tx_type, cpi->do_border_pad);
2386
2387
  // Intra mode needs decoded pixels such that the next transform block
2388
  // can use them for prediction.
2389
0
  recon_intra(cpi, x, plane, block, blk_row, blk_col, plane_bsize, tx_size,
2390
0
              txb_ctx, skip_trellis, best_tx_type, 0, &rate_cost, best_eob);
2391
0
  p->dqcoeff = orig_dqcoeff;
2392
0
}
2393
2394
// Pick transform type for a luma transform block of tx_size. Note this function
2395
// is used only for inter-predicted blocks.
2396
static inline void tx_type_rd(const AV1_COMP *cpi, MACROBLOCK *x,
2397
                              TX_SIZE tx_size, int blk_row, int blk_col,
2398
                              int block, int plane_bsize, TXB_CTX *txb_ctx,
2399
                              RD_STATS *rd_stats, FAST_TX_SEARCH_MODE ftxs_mode,
2400
0
                              int64_t ref_rdcost) {
2401
0
  assert(is_inter_block(x->e_mbd.mi[0]));
2402
0
  RD_STATS this_rd_stats;
2403
0
  search_tx_type(cpi, x, 0, block, blk_row, blk_col, plane_bsize, tx_size,
2404
0
                 txb_ctx, ftxs_mode, ref_rdcost, &this_rd_stats);
2405
2406
0
  av1_merge_rd_stats(rd_stats, &this_rd_stats);
2407
0
}
2408
2409
static inline void try_tx_block_no_split(
2410
    const AV1_COMP *cpi, MACROBLOCK *x, int blk_row, int blk_col, int block,
2411
    TX_SIZE tx_size, int depth, BLOCK_SIZE plane_bsize,
2412
    const ENTROPY_CONTEXT *ta, const ENTROPY_CONTEXT *tl,
2413
    int txfm_partition_ctx, RD_STATS *rd_stats, int64_t ref_best_rd,
2414
0
    FAST_TX_SEARCH_MODE ftxs_mode, TxCandidateInfo *no_split) {
2415
0
  MACROBLOCKD *const xd = &x->e_mbd;
2416
0
  MB_MODE_INFO *const mbmi = xd->mi[0];
2417
0
  struct macroblock_plane *const p = &x->plane[0];
2418
0
  const ENTROPY_CONTEXT *const pta = ta + blk_col;
2419
0
  const ENTROPY_CONTEXT *const ptl = tl + blk_row;
2420
0
  const TX_SIZE txs_ctx = get_txsize_entropy_ctx(tx_size);
2421
0
  TXB_CTX txb_ctx;
2422
0
  get_txb_ctx(plane_bsize, tx_size, 0, pta, ptl, &txb_ctx);
2423
0
  const int zero_blk_rate = x->coeff_costs.coeff_costs[txs_ctx][PLANE_TYPE_Y]
2424
0
                                .txb_skip_cost[txb_ctx.txb_skip_ctx][1];
2425
0
  rd_stats->zero_rate = zero_blk_rate;
2426
0
  const int index = av1_get_txb_size_index(plane_bsize, blk_row, blk_col);
2427
0
  mbmi->inter_tx_size[index] = tx_size;
2428
0
  tx_type_rd(cpi, x, tx_size, blk_row, blk_col, block, plane_bsize, &txb_ctx,
2429
0
             rd_stats, ftxs_mode, ref_best_rd);
2430
0
  assert(rd_stats->rate < INT_MAX);
2431
2432
0
  const int pick_skip_txfm =
2433
0
      !xd->lossless[mbmi->segment_id] &&
2434
0
      (rd_stats->skip_txfm == 1 ||
2435
0
       RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist) >=
2436
0
           RDCOST(x->rdmult, zero_blk_rate, rd_stats->sse));
2437
0
  if (pick_skip_txfm) {
2438
#if CONFIG_RD_DEBUG
2439
    update_txb_coeff_cost(rd_stats, 0, zero_blk_rate - rd_stats->rate);
2440
#endif  // CONFIG_RD_DEBUG
2441
0
    rd_stats->rate = zero_blk_rate;
2442
0
    rd_stats->dist = rd_stats->sse;
2443
0
    p->eobs[block] = 0;
2444
0
    update_txk_array(xd, blk_row, blk_col, tx_size, DCT_DCT);
2445
0
  }
2446
0
  rd_stats->skip_txfm = pick_skip_txfm;
2447
2448
0
  if (tx_size > TX_4X4 && depth < MAX_VARTX_DEPTH)
2449
0
    rd_stats->rate += x->mode_costs.txfm_partition_cost[txfm_partition_ctx][0];
2450
2451
0
  no_split->rd = RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist);
2452
0
  no_split->txb_entropy_ctx = p->txb_entropy_ctx[block];
2453
0
  no_split->tx_type =
2454
0
      xd->tx_type_map[blk_row * xd->tx_type_map_stride + blk_col];
2455
0
}
2456
2457
static inline void try_tx_block_split(
2458
    const AV1_COMP *cpi, MACROBLOCK *x, int blk_row, int blk_col, int block,
2459
    TX_SIZE tx_size, int depth, BLOCK_SIZE plane_bsize, ENTROPY_CONTEXT *ta,
2460
    ENTROPY_CONTEXT *tl, TXFM_CONTEXT *tx_above, TXFM_CONTEXT *tx_left,
2461
    int txfm_partition_ctx, int64_t no_split_rd, int64_t ref_best_rd,
2462
0
    FAST_TX_SEARCH_MODE ftxs_mode, RD_STATS *split_rd_stats) {
2463
0
  assert(tx_size < TX_SIZES_ALL);
2464
0
  MACROBLOCKD *const xd = &x->e_mbd;
2465
0
  const int max_blocks_high = max_block_high(xd, plane_bsize, 0);
2466
0
  const int max_blocks_wide = max_block_wide(xd, plane_bsize, 0);
2467
0
  const int txb_width = tx_size_wide_unit[tx_size];
2468
0
  const int txb_height = tx_size_high_unit[tx_size];
2469
  // Transform size after splitting current block.
2470
0
  const TX_SIZE sub_txs = sub_tx_size_map[tx_size];
2471
0
  const int sub_txb_width = tx_size_wide_unit[sub_txs];
2472
0
  const int sub_txb_height = tx_size_high_unit[sub_txs];
2473
0
  const int sub_step = sub_txb_width * sub_txb_height;
2474
0
  const int nblks = (txb_height / sub_txb_height) * (txb_width / sub_txb_width);
2475
0
  assert(nblks > 0);
2476
0
  av1_init_rd_stats(split_rd_stats);
2477
0
  split_rd_stats->rate =
2478
0
      x->mode_costs.txfm_partition_cost[txfm_partition_ctx][1];
2479
2480
0
  for (int r = 0, blk_idx = 0; r < txb_height; r += sub_txb_height) {
2481
0
    const int offsetr = blk_row + r;
2482
0
    if (offsetr >= max_blocks_high) break;
2483
0
    for (int c = 0; c < txb_width; c += sub_txb_width, ++blk_idx) {
2484
0
      assert(blk_idx < 4);
2485
0
      (void)blk_idx;
2486
0
      const int offsetc = blk_col + c;
2487
0
      if (offsetc >= max_blocks_wide) continue;
2488
2489
0
      RD_STATS this_rd_stats;
2490
0
      int this_cost_valid = 1;
2491
0
      select_tx_block(cpi, x, offsetr, offsetc, block, sub_txs, depth + 1,
2492
0
                      plane_bsize, ta, tl, tx_above, tx_left, &this_rd_stats,
2493
0
                      no_split_rd / nblks, ref_best_rd - split_rd_stats->rdcost,
2494
0
                      &this_cost_valid, ftxs_mode, -1);
2495
0
      if (!this_cost_valid) {
2496
0
        split_rd_stats->rdcost = INT64_MAX;
2497
0
        return;
2498
0
      }
2499
0
      av1_merge_rd_stats(split_rd_stats, &this_rd_stats);
2500
0
      split_rd_stats->rdcost =
2501
0
          RDCOST(x->rdmult, split_rd_stats->rate, split_rd_stats->dist);
2502
0
      if (split_rd_stats->rdcost > ref_best_rd) {
2503
0
        split_rd_stats->rdcost = INT64_MAX;
2504
0
        return;
2505
0
      }
2506
0
      block += sub_step;
2507
0
    }
2508
0
  }
2509
0
}
2510
2511
0
static float get_var(float mean, double x2_sum, int num) {
2512
0
  const float e_x2 = (float)(x2_sum / num);
2513
0
  const float diff = e_x2 - mean * mean;
2514
0
  return diff;
2515
0
}
2516
2517
static inline void get_blk_var_dev(const int16_t *data, int stride, int bw,
2518
                                   int bh, float *dev_of_mean,
2519
0
                                   float *var_of_vars) {
2520
0
  const int16_t *const data_ptr = &data[0];
2521
0
  const int subh = (bh >= bw) ? (bh >> 1) : bh;
2522
0
  const int subw = (bw >= bh) ? (bw >> 1) : bw;
2523
0
  const int num = bw * bh;
2524
0
  const int sub_num = subw * subh;
2525
0
  int total_x_sum = 0;
2526
0
  int64_t total_x2_sum = 0;
2527
0
  int blk_idx = 0;
2528
0
  float var_sum = 0.0f;
2529
0
  float mean_sum = 0.0f;
2530
0
  double var2_sum = 0.0f;
2531
0
  double mean2_sum = 0.0f;
2532
2533
0
  for (int row = 0; row < bh; row += subh) {
2534
0
    for (int col = 0; col < bw; col += subw) {
2535
0
      int x_sum;
2536
0
      int64_t x2_sum;
2537
0
      aom_get_blk_sse_sum(data_ptr + row * stride + col, stride, subw, subh,
2538
0
                          &x_sum, &x2_sum);
2539
0
      total_x_sum += x_sum;
2540
0
      total_x2_sum += x2_sum;
2541
2542
0
      const float mean = (float)x_sum / sub_num;
2543
0
      const float var = get_var(mean, (double)x2_sum, sub_num);
2544
0
      mean_sum += mean;
2545
0
      mean2_sum += (double)(mean * mean);
2546
0
      var_sum += var;
2547
0
      var2_sum += var * var;
2548
0
      blk_idx++;
2549
0
    }
2550
0
  }
2551
2552
0
  const float lvl0_mean = (float)total_x_sum / num;
2553
0
  const float block_var = get_var(lvl0_mean, (double)total_x2_sum, num);
2554
0
  mean_sum += lvl0_mean;
2555
0
  mean2_sum += (double)(lvl0_mean * lvl0_mean);
2556
0
  var_sum += block_var;
2557
0
  var2_sum += block_var * block_var;
2558
0
  const float av_mean = mean_sum / 5;
2559
2560
0
  if (blk_idx > 1) {
2561
    // Deviation of means.
2562
0
    *dev_of_mean = get_dev(av_mean, mean2_sum, (blk_idx + 1));
2563
    // Variance of variances.
2564
0
    const float mean_var = var_sum / (blk_idx + 1);
2565
0
    *var_of_vars = get_var(mean_var, var2_sum, (blk_idx + 1));
2566
0
  }
2567
0
}
2568
2569
static void prune_tx_split_no_split(MACROBLOCK *x, BLOCK_SIZE bsize,
2570
                                    int blk_row, int blk_col, TX_SIZE tx_size,
2571
                                    int *try_no_split, int *try_split,
2572
0
                                    int pruning_level) {
2573
0
  const int diff_stride = block_size_wide[bsize];
2574
0
  const int16_t *diff =
2575
0
      x->plane[0].src_diff + 4 * blk_row * diff_stride + 4 * blk_col;
2576
0
  const int bw = tx_size_wide[tx_size];
2577
0
  const int bh = tx_size_high[tx_size];
2578
0
  float dev_of_means = 0.0f;
2579
0
  float var_of_vars = 0.0f;
2580
2581
  // This function calculates the deviation of means, and the variance of pixel
2582
  // variances of the block as well as it's sub-blocks.
2583
0
  get_blk_var_dev(diff, diff_stride, bw, bh, &dev_of_means, &var_of_vars);
2584
0
  const int dc_q = x->plane[0].dequant_QTX[0] >> 3;
2585
0
  const int ac_q = x->plane[0].dequant_QTX[1] >> 3;
2586
0
  const int no_split_thresh_scales[4] = { 0, 24, 8, 8 };
2587
0
  const int no_split_thresh_scale = no_split_thresh_scales[pruning_level];
2588
0
  const int split_thresh_scales[4] = { 0, 24, 10, 8 };
2589
0
  const int split_thresh_scale = split_thresh_scales[pruning_level];
2590
2591
0
  if ((dev_of_means <= dc_q) &&
2592
0
      (split_thresh_scale * var_of_vars <= ac_q * ac_q)) {
2593
0
    *try_split = 0;
2594
0
  }
2595
0
  if ((dev_of_means > no_split_thresh_scale * dc_q) &&
2596
0
      (var_of_vars > no_split_thresh_scale * ac_q * ac_q)) {
2597
0
    *try_no_split = 0;
2598
0
  }
2599
0
}
2600
2601
// Search for the best transform partition(recursive)/type for a given
2602
// inter-predicted luma block. The obtained transform selection will be saved
2603
// in xd->mi[0], the corresponding RD stats will be saved in rd_stats.
2604
static inline void select_tx_block(
2605
    const AV1_COMP *cpi, MACROBLOCK *x, int blk_row, int blk_col, int block,
2606
    TX_SIZE tx_size, int depth, BLOCK_SIZE plane_bsize, ENTROPY_CONTEXT *ta,
2607
    ENTROPY_CONTEXT *tl, TXFM_CONTEXT *tx_above, TXFM_CONTEXT *tx_left,
2608
    RD_STATS *rd_stats, int64_t prev_level_rd, int64_t ref_best_rd,
2609
0
    int *is_cost_valid, FAST_TX_SEARCH_MODE ftxs_mode, int blk_idx) {
2610
0
  assert(tx_size < TX_SIZES_ALL);
2611
0
  av1_init_rd_stats(rd_stats);
2612
0
  if (ref_best_rd < 0) {
2613
0
    *is_cost_valid = 0;
2614
0
    return;
2615
0
  }
2616
2617
0
  MACROBLOCKD *const xd = &x->e_mbd;
2618
0
  assert(blk_row < max_block_high(xd, plane_bsize, 0) &&
2619
0
         blk_col < max_block_wide(xd, plane_bsize, 0));
2620
0
  MB_MODE_INFO *const mbmi = xd->mi[0];
2621
0
  const int ctx = txfm_partition_context(tx_above + blk_col, tx_left + blk_row,
2622
0
                                         mbmi->bsize, tx_size);
2623
0
  struct macroblock_plane *const p = &x->plane[0];
2624
2625
0
  int try_no_split = (cpi->oxcf.txfm_cfg.enable_tx64 ||
2626
0
                      txsize_sqr_up_map[tx_size] != TX_64X64) &&
2627
0
                     (cpi->oxcf.txfm_cfg.enable_rect_tx ||
2628
0
                      tx_size_wide[tx_size] == tx_size_high[tx_size]);
2629
0
  int try_split = tx_size > TX_4X4 && depth < MAX_VARTX_DEPTH;
2630
0
  TxCandidateInfo no_split = { INT64_MAX, 0, TX_TYPES };
2631
2632
  // Prune tx_split and no-split based on sub-block properties.
2633
0
  if (tx_size != TX_4X4 && try_split == 1 && try_no_split == 1 &&
2634
0
      cpi->sf.tx_sf.prune_tx_size_level > 0) {
2635
0
    prune_tx_split_no_split(x, plane_bsize, blk_row, blk_col, tx_size,
2636
0
                            &try_no_split, &try_split,
2637
0
                            cpi->sf.tx_sf.prune_tx_size_level);
2638
0
  }
2639
2640
0
  if (cpi->sf.rt_sf.skip_tx_no_split_var_based_partition) {
2641
0
    if (x->try_merge_partition && try_split && p->eobs[block]) try_no_split = 0;
2642
0
  }
2643
2644
  // Try using current block as a single transform block without split.
2645
0
  if (try_no_split) {
2646
0
    try_tx_block_no_split(cpi, x, blk_row, blk_col, block, tx_size, depth,
2647
0
                          plane_bsize, ta, tl, ctx, rd_stats, ref_best_rd,
2648
0
                          ftxs_mode, &no_split);
2649
2650
0
    push_inter_block_tx_no_split_rd(
2651
0
        x, mbmi, no_split.rd, blk_idx,
2652
0
        cpi->sf.tx_sf.prune_inter_tx_split_rd_eval_lvl);
2653
2654
    // Speed features for early termination.
2655
0
    const int search_level = cpi->sf.tx_sf.adaptive_txb_search_level;
2656
0
    if (search_level) {
2657
0
      if ((no_split.rd - (no_split.rd >> (1 + search_level))) > ref_best_rd) {
2658
0
        *is_cost_valid = 0;
2659
0
        return;
2660
0
      }
2661
0
      if (no_split.rd - (no_split.rd >> (2 + search_level)) > prev_level_rd) {
2662
0
        try_split = 0;
2663
0
      }
2664
0
    }
2665
0
    if (cpi->sf.tx_sf.txb_split_cap) {
2666
0
      if (p->eobs[block] == 0) try_split = 0;
2667
0
    }
2668
0
    if (prune_tx_split_eval_using_no_split_rd(
2669
0
            x, mbmi, no_split.rd, blk_idx,
2670
0
            cpi->sf.tx_sf.prune_inter_tx_split_rd_eval_lvl)) {
2671
0
      try_split = 0;
2672
0
    }
2673
0
  }
2674
2675
  // ML based speed feature to skip searching for split transform blocks.
2676
0
  if (x->e_mbd.bd == 8 && try_split &&
2677
0
      !(ref_best_rd == INT64_MAX && no_split.rd == INT64_MAX)) {
2678
0
    const int threshold = cpi->sf.tx_sf.tx_type_search.ml_tx_split_thresh;
2679
0
    if (threshold >= 0) {
2680
0
      const int split_score =
2681
0
          ml_predict_tx_split(x, plane_bsize, blk_row, blk_col, tx_size);
2682
0
      if (split_score < -threshold) try_split = 0;
2683
0
    }
2684
0
  }
2685
2686
0
  RD_STATS split_rd_stats;
2687
0
  split_rd_stats.rdcost = INT64_MAX;
2688
  // Try splitting current block into smaller transform blocks.
2689
0
  if (try_split) {
2690
0
    try_tx_block_split(cpi, x, blk_row, blk_col, block, tx_size, depth,
2691
0
                       plane_bsize, ta, tl, tx_above, tx_left, ctx, no_split.rd,
2692
0
                       AOMMIN(no_split.rd, ref_best_rd), ftxs_mode,
2693
0
                       &split_rd_stats);
2694
0
  }
2695
2696
0
  if (no_split.rd < split_rd_stats.rdcost) {
2697
0
    ENTROPY_CONTEXT *pta = ta + blk_col;
2698
0
    ENTROPY_CONTEXT *ptl = tl + blk_row;
2699
0
    p->txb_entropy_ctx[block] = no_split.txb_entropy_ctx;
2700
0
    av1_set_txb_context(x, 0, block, tx_size, pta, ptl);
2701
0
    txfm_partition_update(tx_above + blk_col, tx_left + blk_row, tx_size,
2702
0
                          tx_size);
2703
0
    for (int idy = 0; idy < tx_size_high_unit[tx_size]; ++idy) {
2704
0
      for (int idx = 0; idx < tx_size_wide_unit[tx_size]; ++idx) {
2705
0
        const int index =
2706
0
            av1_get_txb_size_index(plane_bsize, blk_row + idy, blk_col + idx);
2707
0
        mbmi->inter_tx_size[index] = tx_size;
2708
0
      }
2709
0
    }
2710
0
    mbmi->tx_size = tx_size;
2711
0
    update_txk_array(xd, blk_row, blk_col, tx_size, no_split.tx_type);
2712
0
  } else {
2713
0
    *rd_stats = split_rd_stats;
2714
0
    if (split_rd_stats.rdcost == INT64_MAX) *is_cost_valid = 0;
2715
0
  }
2716
0
}
2717
2718
static inline void choose_largest_tx_size(const AV1_COMP *const cpi,
2719
                                          MACROBLOCK *x, RD_STATS *rd_stats,
2720
0
                                          int64_t ref_best_rd, BLOCK_SIZE bs) {
2721
0
  MACROBLOCKD *const xd = &x->e_mbd;
2722
0
  MB_MODE_INFO *const mbmi = xd->mi[0];
2723
0
  const TxfmSearchParams *txfm_params = &x->txfm_search_params;
2724
0
  mbmi->tx_size = tx_size_from_tx_mode(bs, txfm_params->tx_mode_search_type);
2725
2726
  // If tx64 is not enabled, we need to go down to the next available size
2727
0
  if (!cpi->oxcf.txfm_cfg.enable_tx64 && cpi->oxcf.txfm_cfg.enable_rect_tx) {
2728
0
    static const TX_SIZE tx_size_max_32[TX_SIZES_ALL] = {
2729
0
      TX_4X4,    // 4x4 transform
2730
0
      TX_8X8,    // 8x8 transform
2731
0
      TX_16X16,  // 16x16 transform
2732
0
      TX_32X32,  // 32x32 transform
2733
0
      TX_32X32,  // 64x64 transform
2734
0
      TX_4X8,    // 4x8 transform
2735
0
      TX_8X4,    // 8x4 transform
2736
0
      TX_8X16,   // 8x16 transform
2737
0
      TX_16X8,   // 16x8 transform
2738
0
      TX_16X32,  // 16x32 transform
2739
0
      TX_32X16,  // 32x16 transform
2740
0
      TX_32X32,  // 32x64 transform
2741
0
      TX_32X32,  // 64x32 transform
2742
0
      TX_4X16,   // 4x16 transform
2743
0
      TX_16X4,   // 16x4 transform
2744
0
      TX_8X32,   // 8x32 transform
2745
0
      TX_32X8,   // 32x8 transform
2746
0
      TX_16X32,  // 16x64 transform
2747
0
      TX_32X16,  // 64x16 transform
2748
0
    };
2749
0
    mbmi->tx_size = tx_size_max_32[mbmi->tx_size];
2750
0
  } else if (cpi->oxcf.txfm_cfg.enable_tx64 &&
2751
0
             !cpi->oxcf.txfm_cfg.enable_rect_tx) {
2752
0
    static const TX_SIZE tx_size_max_square[TX_SIZES_ALL] = {
2753
0
      TX_4X4,    // 4x4 transform
2754
0
      TX_8X8,    // 8x8 transform
2755
0
      TX_16X16,  // 16x16 transform
2756
0
      TX_32X32,  // 32x32 transform
2757
0
      TX_64X64,  // 64x64 transform
2758
0
      TX_4X4,    // 4x8 transform
2759
0
      TX_4X4,    // 8x4 transform
2760
0
      TX_8X8,    // 8x16 transform
2761
0
      TX_8X8,    // 16x8 transform
2762
0
      TX_16X16,  // 16x32 transform
2763
0
      TX_16X16,  // 32x16 transform
2764
0
      TX_32X32,  // 32x64 transform
2765
0
      TX_32X32,  // 64x32 transform
2766
0
      TX_4X4,    // 4x16 transform
2767
0
      TX_4X4,    // 16x4 transform
2768
0
      TX_8X8,    // 8x32 transform
2769
0
      TX_8X8,    // 32x8 transform
2770
0
      TX_16X16,  // 16x64 transform
2771
0
      TX_16X16,  // 64x16 transform
2772
0
    };
2773
0
    mbmi->tx_size = tx_size_max_square[mbmi->tx_size];
2774
0
  } else if (!cpi->oxcf.txfm_cfg.enable_tx64 &&
2775
0
             !cpi->oxcf.txfm_cfg.enable_rect_tx) {
2776
0
    static const TX_SIZE tx_size_max_32_square[TX_SIZES_ALL] = {
2777
0
      TX_4X4,    // 4x4 transform
2778
0
      TX_8X8,    // 8x8 transform
2779
0
      TX_16X16,  // 16x16 transform
2780
0
      TX_32X32,  // 32x32 transform
2781
0
      TX_32X32,  // 64x64 transform
2782
0
      TX_4X4,    // 4x8 transform
2783
0
      TX_4X4,    // 8x4 transform
2784
0
      TX_8X8,    // 8x16 transform
2785
0
      TX_8X8,    // 16x8 transform
2786
0
      TX_16X16,  // 16x32 transform
2787
0
      TX_16X16,  // 32x16 transform
2788
0
      TX_32X32,  // 32x64 transform
2789
0
      TX_32X32,  // 64x32 transform
2790
0
      TX_4X4,    // 4x16 transform
2791
0
      TX_4X4,    // 16x4 transform
2792
0
      TX_8X8,    // 8x32 transform
2793
0
      TX_8X8,    // 32x8 transform
2794
0
      TX_16X16,  // 16x64 transform
2795
0
      TX_16X16,  // 64x16 transform
2796
0
    };
2797
2798
0
    mbmi->tx_size = tx_size_max_32_square[mbmi->tx_size];
2799
0
  }
2800
2801
0
  const int skip_ctx = av1_get_skip_txfm_context(xd);
2802
0
  const int no_skip_txfm_rate = x->mode_costs.skip_txfm_cost[skip_ctx][0];
2803
0
  const int skip_txfm_rate = x->mode_costs.skip_txfm_cost[skip_ctx][1];
2804
  // Skip RDcost is used only for Inter blocks
2805
0
  const int64_t skip_txfm_rd =
2806
0
      is_inter_block(mbmi) ? RDCOST(x->rdmult, skip_txfm_rate, 0) : INT64_MAX;
2807
0
  const int64_t no_skip_txfm_rd = RDCOST(x->rdmult, no_skip_txfm_rate, 0);
2808
0
  av1_txfm_rd_in_plane(x, cpi, rd_stats, ref_best_rd,
2809
0
                       AOMMIN(no_skip_txfm_rd, skip_txfm_rd), AOM_PLANE_Y, bs,
2810
0
                       mbmi->tx_size, FTXS_NONE);
2811
0
}
2812
2813
static inline void choose_smallest_tx_size(const AV1_COMP *const cpi,
2814
                                           MACROBLOCK *x, RD_STATS *rd_stats,
2815
0
                                           int64_t ref_best_rd, BLOCK_SIZE bs) {
2816
0
  MACROBLOCKD *const xd = &x->e_mbd;
2817
0
  MB_MODE_INFO *const mbmi = xd->mi[0];
2818
2819
0
  mbmi->tx_size = TX_4X4;
2820
  // TODO(any) : Pass this_rd based on skip/non-skip cost
2821
0
  av1_txfm_rd_in_plane(x, cpi, rd_stats, ref_best_rd, 0, 0, bs, mbmi->tx_size,
2822
0
                       FTXS_NONE);
2823
0
}
2824
2825
#if !CONFIG_REALTIME_ONLY
2826
static void ml_predict_intra_tx_depth_prune(MACROBLOCK *x, int blk_row,
2827
                                            int blk_col, BLOCK_SIZE bsize,
2828
0
                                            TX_SIZE tx_size) {
2829
0
  const MACROBLOCKD *const xd = &x->e_mbd;
2830
0
  const MB_MODE_INFO *const mbmi = xd->mi[0];
2831
2832
  // Disable the pruning logic using NN model for the following cases:
2833
  // 1) Lossless coding as only 4x4 transform is evaluated in this case
2834
  // 2) When transform and current block sizes do not match as the features are
2835
  // obtained over the current block
2836
  // 3) When operating bit-depth is not 8-bit as the input features are not
2837
  // scaled according to bit-depth.
2838
0
  if (xd->lossless[mbmi->segment_id] || txsize_to_bsize[tx_size] != bsize ||
2839
0
      xd->bd != 8)
2840
0
    return;
2841
2842
  // Currently NN model based pruning is supported only when largest transform
2843
  // size is 8x8
2844
0
  if (tx_size != TX_8X8) return;
2845
2846
  // Neural network model is a sequential neural net and was trained using SGD
2847
  // optimizer. The model can be further improved in terms of speed/quality by
2848
  // considering the following experiments:
2849
  // 1) Generate ML model by training with balanced data for different learning
2850
  // rates and optimizers.
2851
  // 2) Experiment with ML model by adding features related to the statistics of
2852
  // top and left pixels to capture the accuracy of reconstructed neighbouring
2853
  // pixels for 4x4 blocks numbered 1, 2, 3 in 8x8 block, source variance of 4x4
2854
  // sub-blocks, etc.
2855
  // 3) Generate ML models for transform blocks other than 8x8.
2856
0
  const NN_CONFIG *const nn_config = &av1_intra_tx_split_nnconfig_8x8;
2857
0
  const float *const intra_tx_prune_thresh = av1_intra_tx_prune_nn_thresh_8x8;
2858
2859
0
  float features[NUM_INTRA_TX_SPLIT_FEATURES] = { 0.0f };
2860
0
  const int diff_stride = block_size_wide[bsize];
2861
2862
0
  const int16_t *diff = x->plane[0].src_diff + MI_SIZE * blk_row * diff_stride +
2863
0
                        MI_SIZE * blk_col;
2864
0
  const int bw = tx_size_wide[tx_size];
2865
0
  const int bh = tx_size_high[tx_size];
2866
2867
0
  int feature_idx = get_mean_dev_features(diff, diff_stride, bw, bh, features);
2868
2869
0
  features[feature_idx++] = log1pf((float)x->source_variance);
2870
2871
0
  const int dc_q = av1_dc_quant_QTX(x->qindex, 0, xd->bd) >> (xd->bd - 8);
2872
0
  const float log_dc_q_square = log1pf((float)(dc_q * dc_q) / 256.0f);
2873
0
  features[feature_idx++] = log_dc_q_square;
2874
0
  assert(feature_idx == NUM_INTRA_TX_SPLIT_FEATURES);
2875
0
  for (int i = 0; i < NUM_INTRA_TX_SPLIT_FEATURES; i++) {
2876
0
    features[i] = (features[i] - av1_intra_tx_split_8x8_mean[i]) /
2877
0
                  av1_intra_tx_split_8x8_std[i];
2878
0
  }
2879
2880
0
  float score;
2881
0
  av1_nn_predict(features, nn_config, 1, &score);
2882
2883
0
  TxfmSearchParams *const txfm_params = &x->txfm_search_params;
2884
0
  if (score <= intra_tx_prune_thresh[0])
2885
0
    txfm_params->nn_prune_depths_for_intra_tx = TX_PRUNE_SPLIT;
2886
0
  else if (score > intra_tx_prune_thresh[1])
2887
0
    txfm_params->nn_prune_depths_for_intra_tx = TX_PRUNE_LARGEST;
2888
0
}
2889
#endif  // !CONFIG_REALTIME_ONLY
2890
2891
/*!\brief Transform type search for luma macroblock with fixed transform size.
2892
 *
2893
 * \ingroup transform_search
2894
 * Search for the best transform type and return the transform coefficients RD
2895
 * cost of current luma macroblock with the given uniform transform size.
2896
 *
2897
 * \param[in]    x              Pointer to structure holding the data for the
2898
                                current encoding macroblock
2899
 * \param[in]    cpi            Top-level encoder structure
2900
 * \param[in]    rd_stats       Pointer to struct to keep track of the RD stats
2901
 * \param[in]    ref_best_rd    Best RD cost seen for this block so far
2902
 * \param[in]    bs             Size of the current macroblock
2903
 * \param[in]    tx_size        The given transform size
2904
 * \param[in]    ftxs_mode      Transform search mode specifying desired speed
2905
                                and quality tradeoff
2906
 * \return       An int64_t value that is the best RD cost found.
2907
 */
2908
static int64_t uniform_txfm_yrd(const AV1_COMP *const cpi, MACROBLOCK *x,
2909
                                RD_STATS *rd_stats, int64_t ref_best_rd,
2910
                                BLOCK_SIZE bs, TX_SIZE tx_size,
2911
0
                                FAST_TX_SEARCH_MODE ftxs_mode) {
2912
0
  assert(IMPLIES(is_rect_tx(tx_size), is_rect_tx_allowed_bsize(bs)));
2913
0
  MACROBLOCKD *const xd = &x->e_mbd;
2914
0
  MB_MODE_INFO *const mbmi = xd->mi[0];
2915
0
  const TxfmSearchParams *txfm_params = &x->txfm_search_params;
2916
0
  const ModeCosts *mode_costs = &x->mode_costs;
2917
0
  const int is_inter = is_inter_block(mbmi);
2918
0
  const int tx_select = txfm_params->tx_mode_search_type == TX_MODE_SELECT &&
2919
0
                        block_signals_txsize(mbmi->bsize);
2920
0
  int tx_size_rate = 0;
2921
0
  if (tx_select) {
2922
0
    const int ctx = txfm_partition_context(
2923
0
        xd->above_txfm_context, xd->left_txfm_context, mbmi->bsize, tx_size);
2924
0
    tx_size_rate = is_inter ? mode_costs->txfm_partition_cost[ctx][0]
2925
0
                            : tx_size_cost(x, bs, tx_size);
2926
0
  }
2927
0
  const int skip_ctx = av1_get_skip_txfm_context(xd);
2928
0
  const int no_skip_txfm_rate = mode_costs->skip_txfm_cost[skip_ctx][0];
2929
0
  const int skip_txfm_rate = mode_costs->skip_txfm_cost[skip_ctx][1];
2930
0
  const int64_t skip_txfm_rd =
2931
0
      is_inter ? RDCOST(x->rdmult, skip_txfm_rate, 0) : INT64_MAX;
2932
0
  const int64_t no_this_rd =
2933
0
      RDCOST(x->rdmult, no_skip_txfm_rate + tx_size_rate, 0);
2934
2935
0
  mbmi->tx_size = tx_size;
2936
0
  av1_txfm_rd_in_plane(x, cpi, rd_stats, ref_best_rd,
2937
0
                       AOMMIN(no_this_rd, skip_txfm_rd), AOM_PLANE_Y, bs,
2938
0
                       tx_size, ftxs_mode);
2939
0
  if (rd_stats->rate == INT_MAX) return INT64_MAX;
2940
2941
0
  int64_t rd;
2942
  // rdstats->rate should include all the rate except skip/non-skip cost as the
2943
  // same is accounted in the caller functions after rd evaluation of all
2944
  // planes. However the decisions should be done after considering the
2945
  // skip/non-skip header cost
2946
0
  if (rd_stats->skip_txfm && is_inter) {
2947
0
    rd = RDCOST(x->rdmult, skip_txfm_rate, rd_stats->sse);
2948
0
  } else {
2949
    // Intra blocks are always signalled as non-skip
2950
0
    rd = RDCOST(x->rdmult, rd_stats->rate + no_skip_txfm_rate + tx_size_rate,
2951
0
                rd_stats->dist);
2952
0
    rd_stats->rate += tx_size_rate;
2953
0
  }
2954
  // Check if forcing the block to skip transform leads to smaller RD cost.
2955
0
  if (is_inter && !rd_stats->skip_txfm && !xd->lossless[mbmi->segment_id]) {
2956
0
    int64_t temp_skip_txfm_rd =
2957
0
        RDCOST(x->rdmult, skip_txfm_rate, rd_stats->sse);
2958
0
    if (temp_skip_txfm_rd <= rd) {
2959
0
      rd = temp_skip_txfm_rd;
2960
0
      rd_stats->rate = 0;
2961
0
      rd_stats->dist = rd_stats->sse;
2962
0
      rd_stats->skip_txfm = 1;
2963
0
    }
2964
0
  }
2965
2966
0
  return rd;
2967
0
}
2968
2969
// Search for the best uniform transform size and type for current coding block.
2970
static inline void choose_tx_size_type_from_rd(const AV1_COMP *const cpi,
2971
                                               MACROBLOCK *x,
2972
                                               RD_STATS *rd_stats,
2973
                                               int64_t ref_best_rd,
2974
0
                                               BLOCK_SIZE bs) {
2975
0
  av1_invalid_rd_stats(rd_stats);
2976
2977
0
  MACROBLOCKD *const xd = &x->e_mbd;
2978
0
  MB_MODE_INFO *const mbmi = xd->mi[0];
2979
0
  TxfmSearchParams *const txfm_params = &x->txfm_search_params;
2980
0
  const TX_SIZE max_rect_tx_size = max_txsize_rect_lookup[bs];
2981
0
  const int tx_select = txfm_params->tx_mode_search_type == TX_MODE_SELECT;
2982
0
  int start_tx;
2983
  // The split depth can be at most MAX_TX_DEPTH, so the init_depth controls
2984
  // how many times of splitting is allowed during the RD search.
2985
0
  int init_depth;
2986
2987
0
  if (tx_select) {
2988
0
    start_tx = max_rect_tx_size;
2989
0
    init_depth = get_search_init_depth(mi_size_wide[bs], mi_size_high[bs],
2990
0
                                       is_inter_block(mbmi), &cpi->sf,
2991
0
                                       txfm_params->tx_size_search_method);
2992
0
    if (init_depth == MAX_TX_DEPTH && !cpi->oxcf.txfm_cfg.enable_tx64 &&
2993
0
        txsize_sqr_up_map[start_tx] == TX_64X64) {
2994
0
      start_tx = sub_tx_size_map[start_tx];
2995
0
    }
2996
0
  } else {
2997
0
    const TX_SIZE chosen_tx_size =
2998
0
        tx_size_from_tx_mode(bs, txfm_params->tx_mode_search_type);
2999
0
    start_tx = chosen_tx_size;
3000
0
    init_depth = MAX_TX_DEPTH;
3001
0
  }
3002
3003
0
  uint8_t best_txk_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE];
3004
0
  TX_SIZE best_tx_size = max_rect_tx_size;
3005
0
  int64_t best_rd = INT64_MAX;
3006
0
  const int num_blks = bsize_to_num_blk(bs);
3007
0
  x->rd_model = FULL_TXFM_RD;
3008
0
  int64_t rd[MAX_TX_DEPTH + 1] = { INT64_MAX, INT64_MAX, INT64_MAX };
3009
0
  for (int tx_size = start_tx, depth = init_depth; depth <= MAX_TX_DEPTH;
3010
0
       depth++, tx_size = sub_tx_size_map[tx_size]) {
3011
0
    if ((!cpi->oxcf.txfm_cfg.enable_tx64 &&
3012
0
         txsize_sqr_up_map[tx_size] == TX_64X64) ||
3013
0
        (!cpi->oxcf.txfm_cfg.enable_rect_tx &&
3014
0
         tx_size_wide[tx_size] != tx_size_high[tx_size])) {
3015
0
      continue;
3016
0
    }
3017
3018
0
#if !CONFIG_REALTIME_ONLY
3019
0
    if (txfm_params->nn_prune_depths_for_intra_tx == TX_PRUNE_SPLIT) break;
3020
3021
    // Set the flag to enable the evaluation of NN classifier to prune transform
3022
    // depths. As the features are based on intra residual information of
3023
    // largest transform, the evaluation of NN model is enabled only for this
3024
    // case.
3025
0
    txfm_params->enable_nn_prune_intra_tx_depths =
3026
0
        (cpi->sf.tx_sf.prune_intra_tx_depths_using_nn && tx_size == start_tx);
3027
0
#endif
3028
3029
0
    RD_STATS this_rd_stats;
3030
    // When the speed feature use_rd_based_breakout_for_intra_tx_search is
3031
    // enabled, use the known minimum best_rd for early termination.
3032
0
    const int64_t rd_thresh =
3033
0
        cpi->sf.tx_sf.use_rd_based_breakout_for_intra_tx_search
3034
0
            ? AOMMIN(ref_best_rd, best_rd)
3035
0
            : ref_best_rd;
3036
0
    rd[depth] = uniform_txfm_yrd(cpi, x, &this_rd_stats, rd_thresh, bs, tx_size,
3037
0
                                 FTXS_NONE);
3038
0
    if (rd[depth] < best_rd) {
3039
0
      av1_copy_array(best_txk_type_map, xd->tx_type_map, num_blks);
3040
0
      best_tx_size = tx_size;
3041
0
      best_rd = rd[depth];
3042
0
      *rd_stats = this_rd_stats;
3043
0
    }
3044
0
    if (tx_size == TX_4X4) break;
3045
    // If we are searching three depths, prune the smallest size depending
3046
    // on rd results for the first two depths for low contrast blocks.
3047
0
    if (depth > init_depth && depth != MAX_TX_DEPTH &&
3048
0
        x->source_variance < 256) {
3049
0
      if (rd[depth - 1] != INT64_MAX && rd[depth] > rd[depth - 1]) break;
3050
0
    }
3051
0
  }
3052
3053
0
  if (rd_stats->rate != INT_MAX) {
3054
0
    mbmi->tx_size = best_tx_size;
3055
0
    av1_copy_array(xd->tx_type_map, best_txk_type_map, num_blks);
3056
0
  }
3057
3058
0
#if !CONFIG_REALTIME_ONLY
3059
  // Reset the flags to avoid any unintentional evaluation of NN model and
3060
  // consumption of prune depths.
3061
0
  txfm_params->enable_nn_prune_intra_tx_depths = false;
3062
0
  txfm_params->nn_prune_depths_for_intra_tx = TX_PRUNE_NONE;
3063
0
#endif
3064
0
}
3065
3066
// Search for the best transform type for the given transform block in the
3067
// given plane/channel, and calculate the corresponding RD cost.
3068
static inline void block_rd_txfm(int plane, int block, int blk_row, int blk_col,
3069
                                 BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
3070
0
                                 void *arg) {
3071
0
  struct rdcost_block_args *args = arg;
3072
0
  if (args->exit_early) {
3073
0
    args->incomplete_exit = 1;
3074
0
    return;
3075
0
  }
3076
3077
0
  MACROBLOCK *const x = args->x;
3078
0
  MACROBLOCKD *const xd = &x->e_mbd;
3079
0
  const int is_inter = is_inter_block(xd->mi[0]);
3080
0
  const AV1_COMP *cpi = args->cpi;
3081
0
  ENTROPY_CONTEXT *a = args->t_above + blk_col;
3082
0
  ENTROPY_CONTEXT *l = args->t_left + blk_row;
3083
0
  const AV1_COMMON *cm = &cpi->common;
3084
0
  RD_STATS this_rd_stats;
3085
0
  av1_init_rd_stats(&this_rd_stats);
3086
3087
0
  if (!is_inter) {
3088
0
    av1_predict_intra_block_facade(cm, xd, plane, blk_col, blk_row, tx_size);
3089
0
    av1_subtract_txb(x, plane, plane_bsize, blk_col, blk_row, tx_size, DCT_DCT,
3090
0
                     false);
3091
0
#if !CONFIG_REALTIME_ONLY
3092
0
    const TxfmSearchParams *const txfm_params = &x->txfm_search_params;
3093
0
    if (txfm_params->enable_nn_prune_intra_tx_depths) {
3094
0
      ml_predict_intra_tx_depth_prune(x, blk_row, blk_col, plane_bsize,
3095
0
                                      tx_size);
3096
0
      if (txfm_params->nn_prune_depths_for_intra_tx == TX_PRUNE_LARGEST) {
3097
0
        av1_invalid_rd_stats(&args->rd_stats);
3098
0
        args->exit_early = 1;
3099
0
        return;
3100
0
      }
3101
0
    }
3102
0
#endif
3103
0
  }
3104
3105
0
  TXB_CTX txb_ctx;
3106
0
  get_txb_ctx(plane_bsize, tx_size, plane, a, l, &txb_ctx);
3107
0
  search_tx_type(cpi, x, plane, block, blk_row, blk_col, plane_bsize, tx_size,
3108
0
                 &txb_ctx, args->ftxs_mode, args->best_rd - args->current_rd,
3109
0
                 &this_rd_stats);
3110
3111
0
#if !CONFIG_REALTIME_ONLY
3112
0
  if (plane == AOM_PLANE_Y && xd->cfl.store_y) {
3113
0
    assert(!is_inter || plane_bsize < BLOCK_8X8);
3114
0
    cfl_store_tx(xd, blk_row, blk_col, tx_size, plane_bsize);
3115
0
  }
3116
0
#endif
3117
3118
#if CONFIG_RD_DEBUG
3119
  update_txb_coeff_cost(&this_rd_stats, plane, this_rd_stats.rate);
3120
#endif  // CONFIG_RD_DEBUG
3121
0
  av1_set_txb_context(x, plane, block, tx_size, a, l);
3122
3123
0
  int64_t rd;
3124
0
  if (is_inter) {
3125
0
    const int64_t no_skip_txfm_rd =
3126
0
        RDCOST(x->rdmult, this_rd_stats.rate, this_rd_stats.dist);
3127
0
    const int64_t skip_txfm_rd = RDCOST(x->rdmult, 0, this_rd_stats.sse);
3128
0
    rd = AOMMIN(no_skip_txfm_rd, skip_txfm_rd);
3129
0
    this_rd_stats.skip_txfm &= !x->plane[plane].eobs[block];
3130
0
  } else {
3131
    // Signal non-skip_txfm for Intra blocks
3132
0
    rd = RDCOST(x->rdmult, this_rd_stats.rate, this_rd_stats.dist);
3133
0
    this_rd_stats.skip_txfm = 0;
3134
0
  }
3135
3136
0
  av1_merge_rd_stats(&args->rd_stats, &this_rd_stats);
3137
3138
0
  args->current_rd += rd;
3139
0
  if (args->current_rd > args->best_rd) args->exit_early = 1;
3140
0
}
3141
3142
int64_t av1_estimate_txfm_yrd(const AV1_COMP *const cpi, MACROBLOCK *x,
3143
                              RD_STATS *rd_stats, int64_t ref_best_rd,
3144
0
                              BLOCK_SIZE bs, TX_SIZE tx_size) {
3145
0
  MACROBLOCKD *const xd = &x->e_mbd;
3146
0
  MB_MODE_INFO *const mbmi = xd->mi[0];
3147
0
  const TxfmSearchParams *txfm_params = &x->txfm_search_params;
3148
0
  const ModeCosts *mode_costs = &x->mode_costs;
3149
0
  const int is_inter = is_inter_block(mbmi);
3150
0
  const int tx_select = txfm_params->tx_mode_search_type == TX_MODE_SELECT &&
3151
0
                        block_signals_txsize(mbmi->bsize);
3152
0
  int tx_size_rate = 0;
3153
0
  if (tx_select) {
3154
0
    const int ctx = txfm_partition_context(
3155
0
        xd->above_txfm_context, xd->left_txfm_context, mbmi->bsize, tx_size);
3156
0
    tx_size_rate = mode_costs->txfm_partition_cost[ctx][0];
3157
0
  }
3158
0
  const int skip_ctx = av1_get_skip_txfm_context(xd);
3159
0
  const int no_skip_txfm_rate = mode_costs->skip_txfm_cost[skip_ctx][0];
3160
0
  const int skip_txfm_rate = mode_costs->skip_txfm_cost[skip_ctx][1];
3161
0
  const int64_t skip_txfm_rd = RDCOST(x->rdmult, skip_txfm_rate, 0);
3162
0
  const int64_t no_this_rd =
3163
0
      RDCOST(x->rdmult, no_skip_txfm_rate + tx_size_rate, 0);
3164
0
  mbmi->tx_size = tx_size;
3165
3166
0
  const uint8_t txw_unit = tx_size_wide_unit[tx_size];
3167
0
  const uint8_t txh_unit = tx_size_high_unit[tx_size];
3168
0
  const int step = txw_unit * txh_unit;
3169
0
  const int max_blocks_wide = max_block_wide(xd, bs, 0);
3170
0
  const int max_blocks_high = max_block_high(xd, bs, 0);
3171
3172
0
  struct rdcost_block_args args;
3173
0
  av1_zero(args);
3174
0
  args.x = x;
3175
0
  args.cpi = cpi;
3176
0
  args.best_rd = ref_best_rd;
3177
0
  args.current_rd = AOMMIN(no_this_rd, skip_txfm_rd);
3178
0
  av1_init_rd_stats(&args.rd_stats);
3179
0
  av1_get_entropy_contexts(bs, &xd->plane[0], args.t_above, args.t_left);
3180
0
  int i = 0;
3181
0
  for (int blk_row = 0; blk_row < max_blocks_high && !args.incomplete_exit;
3182
0
       blk_row += txh_unit) {
3183
0
    for (int blk_col = 0; blk_col < max_blocks_wide; blk_col += txw_unit) {
3184
0
      RD_STATS this_rd_stats;
3185
0
      av1_init_rd_stats(&this_rd_stats);
3186
3187
0
      if (args.exit_early) {
3188
0
        args.incomplete_exit = 1;
3189
0
        break;
3190
0
      }
3191
3192
0
      ENTROPY_CONTEXT *a = args.t_above + blk_col;
3193
0
      ENTROPY_CONTEXT *l = args.t_left + blk_row;
3194
0
      TXB_CTX txb_ctx;
3195
0
      get_txb_ctx(bs, tx_size, 0, a, l, &txb_ctx);
3196
3197
0
      TxfmParam txfm_param;
3198
0
      QUANT_PARAM quant_param;
3199
0
      av1_setup_xform(&cpi->common, x, tx_size, DCT_DCT, &txfm_param);
3200
0
      av1_setup_quant(tx_size, 0, AV1_XFORM_QUANT_B, 0, &quant_param);
3201
0
      av1_subtract_txb(x, PLANE_TYPE_Y, bs, blk_col, blk_row, tx_size, DCT_DCT,
3202
0
                       cpi->do_border_pad);
3203
3204
0
      av1_xform(x, 0, i, blk_row, blk_col, bs, &txfm_param);
3205
0
      av1_quant(x, 0, i, &txfm_param, &quant_param);
3206
3207
0
      this_rd_stats.rate =
3208
0
          cost_coeffs(x, 0, i, tx_size, txfm_param.tx_type, &txb_ctx, 0);
3209
3210
0
      const SCAN_ORDER *const scan_order =
3211
0
          get_scan(txfm_param.tx_size, txfm_param.tx_type);
3212
0
      dist_block_tx_domain(x, 0, i, tx_size, quant_param.qmatrix,
3213
0
                           scan_order->scan, &this_rd_stats.dist,
3214
0
                           &this_rd_stats.sse);
3215
3216
0
      const int64_t no_skip_txfm_rd =
3217
0
          RDCOST(x->rdmult, this_rd_stats.rate, this_rd_stats.dist);
3218
0
      const int64_t skip_rd = RDCOST(x->rdmult, 0, this_rd_stats.sse);
3219
3220
0
      this_rd_stats.skip_txfm &= !x->plane[0].eobs[i];
3221
3222
0
      av1_merge_rd_stats(&args.rd_stats, &this_rd_stats);
3223
0
      args.current_rd += AOMMIN(no_skip_txfm_rd, skip_rd);
3224
3225
0
      if (args.current_rd > ref_best_rd) {
3226
0
        args.exit_early = 1;
3227
0
        break;
3228
0
      }
3229
3230
0
      av1_set_txb_context(x, 0, i, tx_size, a, l);
3231
0
      i += step;
3232
0
    }
3233
0
  }
3234
3235
0
  if (args.incomplete_exit) av1_invalid_rd_stats(&args.rd_stats);
3236
3237
0
  *rd_stats = args.rd_stats;
3238
0
  if (rd_stats->rate == INT_MAX) return INT64_MAX;
3239
3240
0
  int64_t rd;
3241
  // rdstats->rate should include all the rate except skip/non-skip cost as the
3242
  // same is accounted in the caller functions after rd evaluation of all
3243
  // planes. However the decisions should be done after considering the
3244
  // skip/non-skip header cost
3245
0
  if (rd_stats->skip_txfm && is_inter) {
3246
0
    rd = RDCOST(x->rdmult, skip_txfm_rate, rd_stats->sse);
3247
0
  } else {
3248
    // Intra blocks are always signalled as non-skip
3249
0
    rd = RDCOST(x->rdmult, rd_stats->rate + no_skip_txfm_rate + tx_size_rate,
3250
0
                rd_stats->dist);
3251
0
    rd_stats->rate += tx_size_rate;
3252
0
  }
3253
  // Check if forcing the block to skip transform leads to smaller RD cost.
3254
0
  if (is_inter && !rd_stats->skip_txfm && !xd->lossless[mbmi->segment_id]) {
3255
0
    int64_t temp_skip_txfm_rd =
3256
0
        RDCOST(x->rdmult, skip_txfm_rate, rd_stats->sse);
3257
0
    if (temp_skip_txfm_rd <= rd) {
3258
0
      rd = temp_skip_txfm_rd;
3259
0
      rd_stats->rate = 0;
3260
0
      rd_stats->dist = rd_stats->sse;
3261
0
      rd_stats->skip_txfm = 1;
3262
0
    }
3263
0
  }
3264
3265
0
  return rd;
3266
0
}
3267
3268
// Search for the best transform type for a luma inter-predicted block, given
3269
// the transform block partitions.
3270
// This function is used only when some speed features are enabled.
3271
static inline void tx_block_yrd(const AV1_COMP *cpi, MACROBLOCK *x, int blk_row,
3272
                                int blk_col, int block, TX_SIZE tx_size,
3273
                                BLOCK_SIZE plane_bsize, int depth,
3274
                                ENTROPY_CONTEXT *above_ctx,
3275
                                ENTROPY_CONTEXT *left_ctx,
3276
                                TXFM_CONTEXT *tx_above, TXFM_CONTEXT *tx_left,
3277
                                int64_t ref_best_rd, RD_STATS *rd_stats,
3278
0
                                FAST_TX_SEARCH_MODE ftxs_mode) {
3279
0
  assert(tx_size < TX_SIZES_ALL);
3280
0
  MACROBLOCKD *const xd = &x->e_mbd;
3281
0
  MB_MODE_INFO *const mbmi = xd->mi[0];
3282
0
  assert(is_inter_block(mbmi));
3283
0
  const int max_blocks_high = max_block_high(xd, plane_bsize, 0);
3284
0
  const int max_blocks_wide = max_block_wide(xd, plane_bsize, 0);
3285
3286
0
  if (blk_row >= max_blocks_high || blk_col >= max_blocks_wide) return;
3287
3288
0
  const TX_SIZE plane_tx_size = mbmi->inter_tx_size[av1_get_txb_size_index(
3289
0
      plane_bsize, blk_row, blk_col)];
3290
0
  const int ctx = txfm_partition_context(tx_above + blk_col, tx_left + blk_row,
3291
0
                                         mbmi->bsize, tx_size);
3292
3293
0
  av1_init_rd_stats(rd_stats);
3294
0
  if (tx_size == plane_tx_size) {
3295
0
    ENTROPY_CONTEXT *ta = above_ctx + blk_col;
3296
0
    ENTROPY_CONTEXT *tl = left_ctx + blk_row;
3297
0
    const TX_SIZE txs_ctx = get_txsize_entropy_ctx(tx_size);
3298
0
    TXB_CTX txb_ctx;
3299
0
    get_txb_ctx(plane_bsize, tx_size, 0, ta, tl, &txb_ctx);
3300
3301
0
    const int zero_blk_rate =
3302
0
        x->coeff_costs.coeff_costs[txs_ctx][get_plane_type(0)]
3303
0
            .txb_skip_cost[txb_ctx.txb_skip_ctx][1];
3304
0
    rd_stats->zero_rate = zero_blk_rate;
3305
0
    tx_type_rd(cpi, x, tx_size, blk_row, blk_col, block, plane_bsize, &txb_ctx,
3306
0
               rd_stats, ftxs_mode, ref_best_rd);
3307
0
    if (RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist) >=
3308
0
            RDCOST(x->rdmult, zero_blk_rate, rd_stats->sse) ||
3309
0
        rd_stats->skip_txfm == 1) {
3310
0
      rd_stats->rate = zero_blk_rate;
3311
0
      rd_stats->dist = rd_stats->sse;
3312
0
      rd_stats->skip_txfm = 1;
3313
0
      x->plane[0].eobs[block] = 0;
3314
0
      x->plane[0].txb_entropy_ctx[block] = 0;
3315
0
      update_txk_array(xd, blk_row, blk_col, tx_size, DCT_DCT);
3316
0
    } else {
3317
0
      rd_stats->skip_txfm = 0;
3318
0
    }
3319
0
    if (tx_size > TX_4X4 && depth < MAX_VARTX_DEPTH)
3320
0
      rd_stats->rate += x->mode_costs.txfm_partition_cost[ctx][0];
3321
0
    av1_set_txb_context(x, 0, block, tx_size, ta, tl);
3322
0
    txfm_partition_update(tx_above + blk_col, tx_left + blk_row, tx_size,
3323
0
                          tx_size);
3324
0
  } else {
3325
0
    const TX_SIZE sub_txs = sub_tx_size_map[tx_size];
3326
0
    const int txb_width = tx_size_wide_unit[sub_txs];
3327
0
    const int txb_height = tx_size_high_unit[sub_txs];
3328
0
    const int step = txb_height * txb_width;
3329
0
    const int row_end =
3330
0
        AOMMIN(tx_size_high_unit[tx_size], max_blocks_high - blk_row);
3331
0
    const int col_end =
3332
0
        AOMMIN(tx_size_wide_unit[tx_size], max_blocks_wide - blk_col);
3333
0
    RD_STATS pn_rd_stats;
3334
0
    int64_t this_rd = 0;
3335
0
    assert(txb_width > 0 && txb_height > 0);
3336
3337
0
    for (int row = 0; row < row_end; row += txb_height) {
3338
0
      const int offsetr = blk_row + row;
3339
0
      for (int col = 0; col < col_end; col += txb_width) {
3340
0
        const int offsetc = blk_col + col;
3341
3342
0
        av1_init_rd_stats(&pn_rd_stats);
3343
0
        tx_block_yrd(cpi, x, offsetr, offsetc, block, sub_txs, plane_bsize,
3344
0
                     depth + 1, above_ctx, left_ctx, tx_above, tx_left,
3345
0
                     ref_best_rd - this_rd, &pn_rd_stats, ftxs_mode);
3346
0
        if (pn_rd_stats.rate == INT_MAX) {
3347
0
          av1_invalid_rd_stats(rd_stats);
3348
0
          return;
3349
0
        }
3350
0
        av1_merge_rd_stats(rd_stats, &pn_rd_stats);
3351
0
        this_rd += RDCOST(x->rdmult, pn_rd_stats.rate, pn_rd_stats.dist);
3352
0
        block += step;
3353
0
      }
3354
0
    }
3355
3356
0
    if (tx_size > TX_4X4 && depth < MAX_VARTX_DEPTH)
3357
0
      rd_stats->rate += x->mode_costs.txfm_partition_cost[ctx][1];
3358
0
  }
3359
0
}
3360
3361
// search for tx type with tx sizes already decided for a inter-predicted luma
3362
// partition block. It's used only when some speed features are enabled.
3363
// Return value 0: early termination triggered, no valid rd cost available;
3364
//              1: rd cost values are valid.
3365
static int inter_block_yrd(const AV1_COMP *cpi, MACROBLOCK *x,
3366
                           RD_STATS *rd_stats, BLOCK_SIZE bsize,
3367
0
                           int64_t ref_best_rd, FAST_TX_SEARCH_MODE ftxs_mode) {
3368
0
  if (ref_best_rd < 0) {
3369
0
    av1_invalid_rd_stats(rd_stats);
3370
0
    return 0;
3371
0
  }
3372
3373
0
  av1_init_rd_stats(rd_stats);
3374
3375
0
  MACROBLOCKD *const xd = &x->e_mbd;
3376
0
  const TxfmSearchParams *txfm_params = &x->txfm_search_params;
3377
0
  const struct macroblockd_plane *const pd = &xd->plane[0];
3378
0
  const int mi_width = mi_size_wide[bsize];
3379
0
  const int mi_height = mi_size_high[bsize];
3380
0
  const TX_SIZE max_tx_size = get_vartx_max_txsize(xd, bsize, 0);
3381
0
  const int bh = tx_size_high_unit[max_tx_size];
3382
0
  const int bw = tx_size_wide_unit[max_tx_size];
3383
0
  const int step = bw * bh;
3384
0
  const int init_depth = get_search_init_depth(
3385
0
      mi_width, mi_height, 1, &cpi->sf, txfm_params->tx_size_search_method);
3386
0
  ENTROPY_CONTEXT ctxa[MAX_MIB_SIZE];
3387
0
  ENTROPY_CONTEXT ctxl[MAX_MIB_SIZE];
3388
0
  TXFM_CONTEXT tx_above[MAX_MIB_SIZE];
3389
0
  TXFM_CONTEXT tx_left[MAX_MIB_SIZE];
3390
0
  av1_get_entropy_contexts(bsize, pd, ctxa, ctxl);
3391
0
  memcpy(tx_above, xd->above_txfm_context, sizeof(TXFM_CONTEXT) * mi_width);
3392
0
  memcpy(tx_left, xd->left_txfm_context, sizeof(TXFM_CONTEXT) * mi_height);
3393
3394
0
  int64_t this_rd = 0;
3395
0
  for (int idy = 0, block = 0; idy < mi_height; idy += bh) {
3396
0
    for (int idx = 0; idx < mi_width; idx += bw) {
3397
0
      RD_STATS pn_rd_stats;
3398
0
      av1_init_rd_stats(&pn_rd_stats);
3399
0
      tx_block_yrd(cpi, x, idy, idx, block, max_tx_size, bsize, init_depth,
3400
0
                   ctxa, ctxl, tx_above, tx_left, ref_best_rd - this_rd,
3401
0
                   &pn_rd_stats, ftxs_mode);
3402
0
      if (pn_rd_stats.rate == INT_MAX) {
3403
0
        av1_invalid_rd_stats(rd_stats);
3404
0
        return 0;
3405
0
      }
3406
0
      av1_merge_rd_stats(rd_stats, &pn_rd_stats);
3407
0
      this_rd +=
3408
0
          AOMMIN(RDCOST(x->rdmult, pn_rd_stats.rate, pn_rd_stats.dist),
3409
0
                 RDCOST(x->rdmult, pn_rd_stats.zero_rate, pn_rd_stats.sse));
3410
0
      block += step;
3411
0
    }
3412
0
  }
3413
3414
0
  const int skip_ctx = av1_get_skip_txfm_context(xd);
3415
0
  const int no_skip_txfm_rate = x->mode_costs.skip_txfm_cost[skip_ctx][0];
3416
0
  const int skip_txfm_rate = x->mode_costs.skip_txfm_cost[skip_ctx][1];
3417
0
  const int64_t skip_txfm_rd = RDCOST(x->rdmult, skip_txfm_rate, rd_stats->sse);
3418
0
  this_rd =
3419
0
      RDCOST(x->rdmult, rd_stats->rate + no_skip_txfm_rate, rd_stats->dist);
3420
0
  if (skip_txfm_rd < this_rd) {
3421
0
    this_rd = skip_txfm_rd;
3422
0
    rd_stats->rate = 0;
3423
0
    rd_stats->dist = rd_stats->sse;
3424
0
    rd_stats->skip_txfm = 1;
3425
0
  }
3426
3427
0
  const int is_cost_valid = this_rd > ref_best_rd;
3428
0
  if (!is_cost_valid) {
3429
    // reset cost value
3430
0
    av1_invalid_rd_stats(rd_stats);
3431
0
  }
3432
0
  return is_cost_valid;
3433
0
}
3434
3435
// Search for the best transform size and type for current inter-predicted
3436
// luma block with recursive transform block partitioning. The obtained
3437
// transform selection will be saved in xd->mi[0], the corresponding RD stats
3438
// will be saved in rd_stats. The returned value is the corresponding RD cost.
3439
static int64_t select_tx_size_and_type(const AV1_COMP *cpi, MACROBLOCK *x,
3440
                                       RD_STATS *rd_stats, BLOCK_SIZE bsize,
3441
0
                                       int64_t ref_best_rd) {
3442
0
  MACROBLOCKD *const xd = &x->e_mbd;
3443
0
  const TxfmSearchParams *txfm_params = &x->txfm_search_params;
3444
0
  assert(is_inter_block(xd->mi[0]));
3445
0
  assert(bsize < BLOCK_SIZES_ALL);
3446
0
  const int fast_tx_search = txfm_params->tx_size_search_method > USE_FULL_RD;
3447
0
  int64_t rd_thresh = ref_best_rd;
3448
0
  if (rd_thresh == 0) {
3449
0
    av1_invalid_rd_stats(rd_stats);
3450
0
    return INT64_MAX;
3451
0
  }
3452
0
  if (fast_tx_search && rd_thresh < INT64_MAX) {
3453
0
    if (INT64_MAX - rd_thresh > (rd_thresh >> 3)) rd_thresh += (rd_thresh >> 3);
3454
0
  }
3455
0
  assert(rd_thresh > 0);
3456
0
  const FAST_TX_SEARCH_MODE ftxs_mode =
3457
0
      fast_tx_search ? FTXS_DCT_AND_1D_DCT_ONLY : FTXS_NONE;
3458
0
  const struct macroblockd_plane *const pd = &xd->plane[0];
3459
0
  assert(bsize < BLOCK_SIZES_ALL);
3460
0
  const int mi_width = mi_size_wide[bsize];
3461
0
  const int mi_height = mi_size_high[bsize];
3462
0
  ENTROPY_CONTEXT ctxa[MAX_MIB_SIZE];
3463
0
  ENTROPY_CONTEXT ctxl[MAX_MIB_SIZE];
3464
0
  TXFM_CONTEXT tx_above[MAX_MIB_SIZE];
3465
0
  TXFM_CONTEXT tx_left[MAX_MIB_SIZE];
3466
0
  av1_get_entropy_contexts(bsize, pd, ctxa, ctxl);
3467
0
  memcpy(tx_above, xd->above_txfm_context, sizeof(TXFM_CONTEXT) * mi_width);
3468
0
  memcpy(tx_left, xd->left_txfm_context, sizeof(TXFM_CONTEXT) * mi_height);
3469
0
  const int init_depth = get_search_init_depth(
3470
0
      mi_width, mi_height, 1, &cpi->sf, txfm_params->tx_size_search_method);
3471
0
  const TX_SIZE max_tx_size = max_txsize_rect_lookup[bsize];
3472
0
  const int bh = tx_size_high_unit[max_tx_size];
3473
0
  const int bw = tx_size_wide_unit[max_tx_size];
3474
0
  const int step = bw * bh;
3475
0
  const int skip_ctx = av1_get_skip_txfm_context(xd);
3476
0
  const int no_skip_txfm_cost = x->mode_costs.skip_txfm_cost[skip_ctx][0];
3477
0
  const int skip_txfm_cost = x->mode_costs.skip_txfm_cost[skip_ctx][1];
3478
0
  int64_t skip_txfm_rd = RDCOST(x->rdmult, skip_txfm_cost, 0);
3479
0
  int64_t no_skip_txfm_rd = RDCOST(x->rdmult, no_skip_txfm_cost, 0);
3480
0
  int block = 0;
3481
0
  int blk_idx = 0;
3482
3483
0
  av1_init_rd_stats(rd_stats);
3484
0
  for (int idy = 0; idy < max_block_high(xd, bsize, 0); idy += bh) {
3485
0
    for (int idx = 0; idx < max_block_wide(xd, bsize, 0); idx += bw) {
3486
0
      const int64_t best_rd_sofar =
3487
0
          (rd_thresh == INT64_MAX)
3488
0
              ? INT64_MAX
3489
0
              : (rd_thresh - (AOMMIN(skip_txfm_rd, no_skip_txfm_rd)));
3490
0
      int is_cost_valid = 1;
3491
0
      RD_STATS pn_rd_stats;
3492
      // Search for the best transform block size and type for the sub-block.
3493
0
      select_tx_block(cpi, x, idy, idx, block, max_tx_size, init_depth, bsize,
3494
0
                      ctxa, ctxl, tx_above, tx_left, &pn_rd_stats, INT64_MAX,
3495
0
                      best_rd_sofar, &is_cost_valid, ftxs_mode, blk_idx);
3496
0
      blk_idx++;
3497
0
      if (!is_cost_valid || pn_rd_stats.rate == INT_MAX) {
3498
0
        av1_invalid_rd_stats(rd_stats);
3499
0
        return INT64_MAX;
3500
0
      }
3501
0
      av1_merge_rd_stats(rd_stats, &pn_rd_stats);
3502
0
      skip_txfm_rd = RDCOST(x->rdmult, skip_txfm_cost, rd_stats->sse);
3503
0
      no_skip_txfm_rd =
3504
0
          RDCOST(x->rdmult, rd_stats->rate + no_skip_txfm_cost, rd_stats->dist);
3505
0
      block += step;
3506
0
    }
3507
0
  }
3508
3509
0
  if (rd_stats->rate == INT_MAX) return INT64_MAX;
3510
3511
0
  rd_stats->skip_txfm = (skip_txfm_rd <= no_skip_txfm_rd);
3512
3513
  // If fast_tx_search is true, only DCT and 1D DCT were tested in
3514
  // select_inter_block_yrd() above. Do a better search for tx type with
3515
  // tx sizes already decided.
3516
0
  if (fast_tx_search && cpi->sf.tx_sf.refine_fast_tx_search_results) {
3517
0
    if (!inter_block_yrd(cpi, x, rd_stats, bsize, ref_best_rd, FTXS_NONE))
3518
0
      return INT64_MAX;
3519
0
  }
3520
3521
0
  int64_t final_rd;
3522
0
  if (rd_stats->skip_txfm) {
3523
0
    final_rd = RDCOST(x->rdmult, skip_txfm_cost, rd_stats->sse);
3524
0
  } else {
3525
0
    final_rd =
3526
0
        RDCOST(x->rdmult, rd_stats->rate + no_skip_txfm_cost, rd_stats->dist);
3527
0
    if (!xd->lossless[xd->mi[0]->segment_id]) {
3528
0
      final_rd =
3529
0
          AOMMIN(final_rd, RDCOST(x->rdmult, skip_txfm_cost, rd_stats->sse));
3530
0
    }
3531
0
  }
3532
3533
0
  return final_rd;
3534
0
}
3535
3536
// Return 1 to terminate transform search early. The decision is made based on
3537
// the comparison with the reference RD cost and the model-estimated RD cost.
3538
static inline int model_based_tx_search_prune(const AV1_COMP *cpi,
3539
                                              MACROBLOCK *x, BLOCK_SIZE bsize,
3540
0
                                              int64_t ref_best_rd) {
3541
0
  const int level = cpi->sf.tx_sf.model_based_prune_tx_search_level;
3542
0
  assert(level >= 0 && level <= 2);
3543
0
  int model_rate;
3544
0
  int64_t model_dist;
3545
0
  uint8_t model_skip;
3546
0
  MACROBLOCKD *const xd = &x->e_mbd;
3547
0
  model_rd_sb_fn[MODELRD_TYPE_TX_SEARCH_PRUNE](
3548
0
      cpi, bsize, x, xd, 0, 0, &model_rate, &model_dist, &model_skip, NULL,
3549
0
      NULL, NULL, NULL);
3550
0
  if (model_skip) return 0;
3551
0
  const int64_t model_rd = RDCOST(x->rdmult, model_rate, model_dist);
3552
  // TODO(debargha, urvang): Improve the model and make the check below
3553
  // tighter.
3554
0
  static const int prune_factor_by8[] = { 3, 5 };
3555
0
  const int factor = prune_factor_by8[level - 1];
3556
0
  return ((model_rd * factor) >> 3) > ref_best_rd;
3557
0
}
3558
3559
void av1_pick_recursive_tx_size_type_yrd(const AV1_COMP *cpi, MACROBLOCK *x,
3560
                                         RD_STATS *rd_stats, BLOCK_SIZE bsize,
3561
0
                                         int64_t ref_best_rd) {
3562
0
  MACROBLOCKD *const xd = &x->e_mbd;
3563
0
  const TxfmSearchParams *txfm_params = &x->txfm_search_params;
3564
0
  assert(is_inter_block(xd->mi[0]));
3565
3566
0
  av1_invalid_rd_stats(rd_stats);
3567
3568
  // If modeled RD cost is a lot worse than the best so far, terminate early.
3569
0
  if (cpi->sf.tx_sf.model_based_prune_tx_search_level &&
3570
0
      ref_best_rd != INT64_MAX) {
3571
0
    if (model_based_tx_search_prune(cpi, x, bsize, ref_best_rd)) return;
3572
0
  }
3573
3574
  // Hashing based speed feature. If the hash of the prediction residue block is
3575
  // found in the hash table, use previous search results and terminate early.
3576
0
  uint32_t hash = 0;
3577
0
  MB_RD_RECORD *mb_rd_record = NULL;
3578
0
  const int mi_row = x->e_mbd.mi_row;
3579
0
  const int mi_col = x->e_mbd.mi_col;
3580
0
  const int within_border =
3581
0
      mi_row >= xd->tile.mi_row_start &&
3582
0
      (mi_row + mi_size_high[bsize] < xd->tile.mi_row_end) &&
3583
0
      mi_col >= xd->tile.mi_col_start &&
3584
0
      (mi_col + mi_size_wide[bsize] < xd->tile.mi_col_end);
3585
0
  const int is_mb_rd_hash_enabled =
3586
0
      (within_border && cpi->sf.rd_sf.use_mb_rd_hash);
3587
0
  const int n4 = bsize_to_num_blk(bsize);
3588
0
  if (is_mb_rd_hash_enabled) {
3589
0
    hash = get_block_residue_hash(x, bsize);
3590
0
    mb_rd_record = x->txfm_search_info.mb_rd_record;
3591
0
    const int match_index = find_mb_rd_info(mb_rd_record, ref_best_rd, hash);
3592
0
    if (match_index != -1) {
3593
0
      MB_RD_INFO *mb_rd_info = &mb_rd_record->mb_rd_info[match_index];
3594
0
      fetch_mb_rd_info(n4, mb_rd_info, rd_stats, x);
3595
0
      return;
3596
0
    }
3597
0
  }
3598
3599
  // If we predict that skip is the optimal RD decision - set the respective
3600
  // context and terminate early.
3601
0
  int64_t dist;
3602
0
  if (txfm_params->skip_txfm_level &&
3603
0
      predict_skip_txfm(x, bsize, &dist,
3604
0
                        cpi->common.features.reduced_tx_set_used)) {
3605
0
    set_skip_txfm(x, rd_stats, bsize, dist);
3606
    // Save the RD search results into mb_rd_record.
3607
0
    if (is_mb_rd_hash_enabled)
3608
0
      save_mb_rd_info(n4, hash, x, rd_stats, mb_rd_record);
3609
0
    return;
3610
0
  }
3611
#if CONFIG_SPEED_STATS
3612
  ++x->txfm_search_info.tx_search_count;
3613
#endif  // CONFIG_SPEED_STATS
3614
3615
0
  const int64_t rd =
3616
0
      select_tx_size_and_type(cpi, x, rd_stats, bsize, ref_best_rd);
3617
3618
0
  if (rd == INT64_MAX) {
3619
    // We should always find at least one candidate unless ref_best_rd is less
3620
    // than INT64_MAX (in which case, all the calls to select_tx_size_fix_type
3621
    // might have failed to find something better)
3622
0
    assert(ref_best_rd != INT64_MAX);
3623
0
    av1_invalid_rd_stats(rd_stats);
3624
0
    return;
3625
0
  }
3626
3627
  // Save the RD search results into mb_rd_record.
3628
0
  if (is_mb_rd_hash_enabled) {
3629
0
    assert(mb_rd_record != NULL);
3630
0
    save_mb_rd_info(n4, hash, x, rd_stats, mb_rd_record);
3631
0
  }
3632
0
}
3633
3634
void av1_pick_uniform_tx_size_type_yrd(const AV1_COMP *const cpi, MACROBLOCK *x,
3635
                                       RD_STATS *rd_stats, BLOCK_SIZE bs,
3636
0
                                       int64_t ref_best_rd) {
3637
0
  MACROBLOCKD *const xd = &x->e_mbd;
3638
0
  MB_MODE_INFO *const mbmi = xd->mi[0];
3639
0
  const TxfmSearchParams *tx_params = &x->txfm_search_params;
3640
0
  assert(bs == mbmi->bsize);
3641
0
  const int is_inter = is_inter_block(mbmi);
3642
0
  const int mi_row = xd->mi_row;
3643
0
  const int mi_col = xd->mi_col;
3644
3645
0
  av1_init_rd_stats(rd_stats);
3646
3647
  // Hashing based speed feature for inter blocks. If the hash of the residue
3648
  // block is found in the table, use previously saved search results and
3649
  // terminate early.
3650
0
  uint32_t hash = 0;
3651
0
  MB_RD_RECORD *mb_rd_record = NULL;
3652
0
  const int num_blks = bsize_to_num_blk(bs);
3653
0
  if (is_inter && cpi->sf.rd_sf.use_mb_rd_hash) {
3654
0
    const int within_border =
3655
0
        mi_row >= xd->tile.mi_row_start &&
3656
0
        (mi_row + mi_size_high[bs] < xd->tile.mi_row_end) &&
3657
0
        mi_col >= xd->tile.mi_col_start &&
3658
0
        (mi_col + mi_size_wide[bs] < xd->tile.mi_col_end);
3659
0
    if (within_border) {
3660
0
      hash = get_block_residue_hash(x, bs);
3661
0
      mb_rd_record = x->txfm_search_info.mb_rd_record;
3662
0
      const int match_index = find_mb_rd_info(mb_rd_record, ref_best_rd, hash);
3663
0
      if (match_index != -1) {
3664
0
        MB_RD_INFO *mb_rd_info = &mb_rd_record->mb_rd_info[match_index];
3665
0
        fetch_mb_rd_info(num_blks, mb_rd_info, rd_stats, x);
3666
0
        return;
3667
0
      }
3668
0
    }
3669
0
  }
3670
3671
  // If we predict that skip is the optimal RD decision - set the respective
3672
  // context and terminate early.
3673
0
  int64_t dist;
3674
0
  if (tx_params->skip_txfm_level && is_inter &&
3675
0
      !xd->lossless[mbmi->segment_id] &&
3676
0
      predict_skip_txfm(x, bs, &dist,
3677
0
                        cpi->common.features.reduced_tx_set_used)) {
3678
    // Populate rdstats as per skip decision
3679
0
    set_skip_txfm(x, rd_stats, bs, dist);
3680
    // Save the RD search results into mb_rd_record.
3681
0
    if (mb_rd_record) {
3682
0
      save_mb_rd_info(num_blks, hash, x, rd_stats, mb_rd_record);
3683
0
    }
3684
0
    return;
3685
0
  }
3686
3687
0
  if (xd->lossless[mbmi->segment_id]) {
3688
    // Lossless mode can only pick the smallest (4x4) transform size.
3689
0
    choose_smallest_tx_size(cpi, x, rd_stats, ref_best_rd, bs);
3690
0
  } else if (tx_params->tx_size_search_method == USE_LARGESTALL) {
3691
0
    choose_largest_tx_size(cpi, x, rd_stats, ref_best_rd, bs);
3692
0
  } else {
3693
0
    choose_tx_size_type_from_rd(cpi, x, rd_stats, ref_best_rd, bs);
3694
0
  }
3695
3696
  // Save the RD search results into mb_rd_record for possible reuse in future.
3697
0
  if (mb_rd_record) {
3698
0
    save_mb_rd_info(num_blks, hash, x, rd_stats, mb_rd_record);
3699
0
  }
3700
0
}
3701
3702
int av1_txfm_uvrd(const AV1_COMP *const cpi, MACROBLOCK *x, RD_STATS *rd_stats,
3703
0
                  BLOCK_SIZE bsize, int64_t ref_best_rd) {
3704
0
  av1_init_rd_stats(rd_stats);
3705
0
  if (ref_best_rd < 0) return 0;
3706
0
  if (!x->e_mbd.is_chroma_ref) return 1;
3707
3708
0
  MACROBLOCKD *const xd = &x->e_mbd;
3709
0
  MB_MODE_INFO *const mbmi = xd->mi[0];
3710
0
  struct macroblockd_plane *const pd = &xd->plane[AOM_PLANE_U];
3711
0
  const int is_inter = is_inter_block(mbmi);
3712
0
  int64_t this_rd = 0, skip_txfm_rd = 0;
3713
0
  const BLOCK_SIZE plane_bsize =
3714
0
      get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y);
3715
3716
0
  if (is_inter) {
3717
0
    for (int plane = 1; plane < MAX_MB_PLANE; ++plane)
3718
0
      av1_subtract_plane(x, plane_bsize, plane, cpi->do_border_pad);
3719
0
  }
3720
3721
0
  const TX_SIZE uv_tx_size = av1_get_tx_size(AOM_PLANE_U, xd);
3722
0
  int is_cost_valid = 1;
3723
0
  for (int plane = 1; plane < MAX_MB_PLANE; ++plane) {
3724
0
    RD_STATS this_rd_stats;
3725
0
    int64_t chroma_ref_best_rd = ref_best_rd;
3726
    // For inter blocks, refined ref_best_rd is used for early exit
3727
    // For intra blocks, even though current rd crosses ref_best_rd, early
3728
    // exit is not recommended as current rd is used for gating subsequent
3729
    // modes as well (say, for angular modes)
3730
    // TODO(any): Extend the early exit mechanism for intra modes as well
3731
0
    if (cpi->sf.inter_sf.perform_best_rd_based_gating_for_chroma && is_inter &&
3732
0
        chroma_ref_best_rd != INT64_MAX)
3733
0
      chroma_ref_best_rd = ref_best_rd - AOMMIN(this_rd, skip_txfm_rd);
3734
0
    av1_txfm_rd_in_plane(x, cpi, &this_rd_stats, chroma_ref_best_rd, 0, plane,
3735
0
                         plane_bsize, uv_tx_size, FTXS_NONE);
3736
0
    if (this_rd_stats.rate == INT_MAX) {
3737
0
      is_cost_valid = 0;
3738
0
      break;
3739
0
    }
3740
0
    av1_merge_rd_stats(rd_stats, &this_rd_stats);
3741
0
    this_rd = RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist);
3742
0
    skip_txfm_rd = RDCOST(x->rdmult, 0, rd_stats->sse);
3743
0
    if (AOMMIN(this_rd, skip_txfm_rd) > ref_best_rd) {
3744
0
      is_cost_valid = 0;
3745
0
      break;
3746
0
    }
3747
0
  }
3748
3749
0
  if (!is_cost_valid) {
3750
    // reset cost value
3751
0
    av1_invalid_rd_stats(rd_stats);
3752
0
  }
3753
3754
0
  return is_cost_valid;
3755
0
}
3756
3757
void av1_txfm_rd_in_plane(MACROBLOCK *x, const AV1_COMP *cpi,
3758
                          RD_STATS *rd_stats, int64_t ref_best_rd,
3759
                          int64_t current_rd, int plane, BLOCK_SIZE plane_bsize,
3760
0
                          TX_SIZE tx_size, FAST_TX_SEARCH_MODE ftxs_mode) {
3761
0
  assert(IMPLIES(plane == 0, x->e_mbd.mi[0]->tx_size == tx_size));
3762
3763
0
  if (!cpi->oxcf.txfm_cfg.enable_tx64 &&
3764
0
      txsize_sqr_up_map[tx_size] == TX_64X64) {
3765
0
    av1_invalid_rd_stats(rd_stats);
3766
0
    return;
3767
0
  }
3768
3769
0
  if (current_rd > ref_best_rd) {
3770
0
    av1_invalid_rd_stats(rd_stats);
3771
0
    return;
3772
0
  }
3773
3774
0
  MACROBLOCKD *const xd = &x->e_mbd;
3775
0
  const struct macroblockd_plane *const pd = &xd->plane[plane];
3776
0
  struct rdcost_block_args args;
3777
0
  av1_zero(args);
3778
0
  args.x = x;
3779
0
  args.cpi = cpi;
3780
0
  args.best_rd = ref_best_rd;
3781
0
  args.current_rd = current_rd;
3782
0
  args.ftxs_mode = ftxs_mode;
3783
0
  args.skip_trellis = 0;
3784
0
  av1_init_rd_stats(&args.rd_stats);
3785
3786
0
  av1_get_entropy_contexts(plane_bsize, pd, args.t_above, args.t_left);
3787
0
  av1_foreach_transformed_block_in_plane(xd, plane_bsize, plane, block_rd_txfm,
3788
0
                                         &args);
3789
3790
0
  MB_MODE_INFO *const mbmi = xd->mi[0];
3791
0
  const int is_inter = is_inter_block(mbmi);
3792
0
  const int invalid_rd = is_inter ? args.incomplete_exit : args.exit_early;
3793
3794
0
  if (invalid_rd) {
3795
0
    av1_invalid_rd_stats(rd_stats);
3796
0
  } else {
3797
0
    *rd_stats = args.rd_stats;
3798
0
  }
3799
0
}
3800
3801
int av1_txfm_search(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize,
3802
                    RD_STATS *rd_stats, RD_STATS *rd_stats_y,
3803
0
                    RD_STATS *rd_stats_uv, int mode_rate, int64_t ref_best_rd) {
3804
0
  MACROBLOCKD *const xd = &x->e_mbd;
3805
0
  TxfmSearchParams *txfm_params = &x->txfm_search_params;
3806
0
  const int skip_ctx = av1_get_skip_txfm_context(xd);
3807
0
  const int skip_txfm_cost[2] = { x->mode_costs.skip_txfm_cost[skip_ctx][0],
3808
0
                                  x->mode_costs.skip_txfm_cost[skip_ctx][1] };
3809
0
  const int64_t min_header_rate =
3810
0
      mode_rate + AOMMIN(skip_txfm_cost[0], skip_txfm_cost[1]);
3811
  // Account for minimum skip and non_skip rd.
3812
  // Eventually either one of them will be added to mode_rate
3813
0
  const int64_t min_header_rd_possible = RDCOST(x->rdmult, min_header_rate, 0);
3814
0
  if (min_header_rd_possible > ref_best_rd) {
3815
0
    av1_invalid_rd_stats(rd_stats_y);
3816
0
    return 0;
3817
0
  }
3818
3819
0
  const AV1_COMMON *cm = &cpi->common;
3820
0
  MB_MODE_INFO *const mbmi = xd->mi[0];
3821
0
  const int64_t mode_rd = RDCOST(x->rdmult, mode_rate, 0);
3822
0
  const int64_t rd_thresh =
3823
0
      ref_best_rd == INT64_MAX ? INT64_MAX : ref_best_rd - mode_rd;
3824
0
  av1_init_rd_stats(rd_stats);
3825
0
  av1_init_rd_stats(rd_stats_y);
3826
0
  rd_stats->rate = mode_rate;
3827
3828
  // cost and distortion
3829
0
  av1_subtract_plane(x, bsize, PLANE_TYPE_Y, cpi->do_border_pad);
3830
0
  if (txfm_params->tx_mode_search_type == TX_MODE_SELECT &&
3831
0
      !xd->lossless[mbmi->segment_id]) {
3832
0
    av1_pick_recursive_tx_size_type_yrd(cpi, x, rd_stats_y, bsize, rd_thresh);
3833
#if CONFIG_COLLECT_RD_STATS == 2
3834
    PrintPredictionUnitStats(cpi, tile_data, x, rd_stats_y, bsize);
3835
#endif  // CONFIG_COLLECT_RD_STATS == 2
3836
0
  } else {
3837
0
    av1_pick_uniform_tx_size_type_yrd(cpi, x, rd_stats_y, bsize, rd_thresh);
3838
0
    memset(mbmi->inter_tx_size, mbmi->tx_size, sizeof(mbmi->inter_tx_size));
3839
0
  }
3840
3841
0
  if (rd_stats_y->rate == INT_MAX) return 0;
3842
3843
0
  av1_merge_rd_stats(rd_stats, rd_stats_y);
3844
3845
0
  const int64_t non_skip_txfm_rdcosty =
3846
0
      RDCOST(x->rdmult, rd_stats->rate + skip_txfm_cost[0], rd_stats->dist);
3847
0
  const int64_t skip_txfm_rdcosty =
3848
0
      RDCOST(x->rdmult, mode_rate + skip_txfm_cost[1], rd_stats->sse);
3849
0
  const int64_t min_rdcosty = AOMMIN(non_skip_txfm_rdcosty, skip_txfm_rdcosty);
3850
0
  if (min_rdcosty > ref_best_rd) return 0;
3851
3852
0
  av1_init_rd_stats(rd_stats_uv);
3853
0
  const int num_planes = av1_num_planes(cm);
3854
0
  if (num_planes > 1) {
3855
0
    int64_t ref_best_chroma_rd = ref_best_rd;
3856
    // Calculate best rd cost possible for chroma
3857
0
    if (cpi->sf.inter_sf.perform_best_rd_based_gating_for_chroma &&
3858
0
        (ref_best_chroma_rd != INT64_MAX)) {
3859
0
      ref_best_chroma_rd = (ref_best_chroma_rd -
3860
0
                            AOMMIN(non_skip_txfm_rdcosty, skip_txfm_rdcosty));
3861
0
    }
3862
0
    const int is_cost_valid_uv =
3863
0
        av1_txfm_uvrd(cpi, x, rd_stats_uv, bsize, ref_best_chroma_rd);
3864
0
    if (!is_cost_valid_uv) return 0;
3865
3866
0
    if (cpi->sf.hl_sf.weighted_chroma_distortion) {
3867
      // Apply weighted distortion/SSE accumulation while merging uv rd stats to
3868
      // y rd stats.
3869
0
      av1_merge_rd_stats_weighted(rd_stats, rd_stats_uv);
3870
0
    } else {
3871
0
      av1_merge_rd_stats(rd_stats, rd_stats_uv);
3872
0
    }
3873
0
  }
3874
3875
0
  int choose_skip_txfm = rd_stats->skip_txfm;
3876
0
  if (!choose_skip_txfm && !xd->lossless[mbmi->segment_id]) {
3877
0
    const int64_t rdcost_no_skip_txfm = RDCOST(
3878
0
        x->rdmult, rd_stats_y->rate + rd_stats_uv->rate + skip_txfm_cost[0],
3879
0
        rd_stats->dist);
3880
0
    const int64_t rdcost_skip_txfm =
3881
0
        RDCOST(x->rdmult, skip_txfm_cost[1], rd_stats->sse);
3882
0
    if (rdcost_no_skip_txfm >= rdcost_skip_txfm) choose_skip_txfm = 1;
3883
0
  }
3884
0
  if (choose_skip_txfm) {
3885
0
    rd_stats_y->rate = 0;
3886
0
    rd_stats_uv->rate = 0;
3887
0
    rd_stats->rate = mode_rate + skip_txfm_cost[1];
3888
0
    rd_stats->dist = rd_stats->sse;
3889
0
    rd_stats_y->dist = rd_stats_y->sse;
3890
0
    rd_stats_uv->dist = rd_stats_uv->sse;
3891
0
    mbmi->skip_txfm = 1;
3892
0
    if (rd_stats->skip_txfm) {
3893
0
      const int64_t tmprd = RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist);
3894
0
      if (tmprd > ref_best_rd) return 0;
3895
0
    }
3896
0
  } else {
3897
0
    rd_stats->rate += skip_txfm_cost[0];
3898
0
    mbmi->skip_txfm = 0;
3899
0
  }
3900
3901
0
  return 1;
3902
0
}