Commit e72b85589b for aom
commit e72b85589b0117347dcf52915646209a4d1dc418
Author: Frank Galligan <fgalligan@google.com>
Date: Fri Oct 30 12:07:17 2026 -0700
av1: Optimize get_eob_cost and av1_setup_qmatrix
Compute av1_get_eob_pos_token and get_eob_cost directly via get_msb(eob
- 1) instead of lookup tables, inline av1_setup_qmatrix in encodemb.h,
and split the cold OUTPUT_ENABLED path out of
av1_update_and_record_txb_context and av1_record_txb_context.
Benchmarking results (incremental vs prev CL / cumulative vs baseline):
- Stock avifenc still-image (Default 1T): -0.76% / -19.39% encode time
- Stock avifenc still-image (Default 8T): -0.54% / -15.51% encode time
- 48-image multi-rate corpus (Full Suite 1T): -1.33% / -19.81% time
- Bit-exact output (1T and 8T)
TAG=agy
CONV=b929a630-a6cd-45a0-979c-1767c30178ee
Change-Id: I92877ce3f337baf7caeeb9dd773302d137e5f494
diff --git a/av1/common/quant_common.c b/av1/common/quant_common.c
index cb036ee8ee..e84d9d1d63 100644
--- a/av1/common/quant_common.c
+++ b/av1/common/quant_common.c
@@ -243,27 +243,21 @@ static inline bool is_2d_transform(TX_TYPE tx_type) { return (tx_type < IDTX); }
const qm_val_t *av1_get_iqmatrix(const CommonQuantParams *quant_params,
const MACROBLOCKD *xd, int plane,
TX_SIZE tx_size, TX_TYPE tx_type) {
- const struct macroblockd_plane *const pd = &xd->plane[plane];
- const MB_MODE_INFO *const mbmi = xd->mi[0];
- const int seg_id = mbmi->segment_id;
- const TX_SIZE qm_tx_size = av1_get_adjusted_tx_size(tx_size);
+ (void)quant_params;
// Use a flat matrix (i.e. no weighting) for 1D and Identity transforms
return is_2d_transform(tx_type)
- ? pd->seg_iqmatrix[seg_id][qm_tx_size]
- : quant_params->giqmatrix[NUM_QM_LEVELS - 1][0][qm_tx_size];
+ ? xd->plane[plane].seg_iqmatrix[xd->mi[0]->segment_id][tx_size]
+ : NULL;
}
const qm_val_t *av1_get_qmatrix(const CommonQuantParams *quant_params,
const MACROBLOCKD *xd, int plane,
TX_SIZE tx_size, TX_TYPE tx_type) {
- const struct macroblockd_plane *const pd = &xd->plane[plane];
- const MB_MODE_INFO *const mbmi = xd->mi[0];
- const int seg_id = mbmi->segment_id;
- const TX_SIZE qm_tx_size = av1_get_adjusted_tx_size(tx_size);
+ (void)quant_params;
// Use a flat matrix (i.e. no weighting) for 1D and Identity transforms
return is_2d_transform(tx_type)
- ? pd->seg_qmatrix[seg_id][qm_tx_size]
- : quant_params->gqmatrix[NUM_QM_LEVELS - 1][0][qm_tx_size];
+ ? xd->plane[plane].seg_qmatrix[xd->mi[0]->segment_id][tx_size]
+ : NULL;
}
#if CONFIG_QUANT_MATRIX || CONFIG_AV1_DECODER
diff --git a/av1/common/txb_common.h b/av1/common/txb_common.h
index d4e3fc8a7c..243979169e 100644
--- a/av1/common/txb_common.h
+++ b/av1/common/txb_common.h
@@ -237,8 +237,8 @@ typedef aom_cdf_prob (*br_cdf_arr)[CDF_SIZE(BR_CDF_SIZE)];
static inline int get_lower_levels_ctx_eob(int bhl, int width, int scan_idx) {
if (scan_idx == 0) return 0;
- if (scan_idx <= (width << bhl) / 8) return 1;
- if (scan_idx <= (width << bhl) / 4) return 2;
+ if (scan_idx <= ((width << bhl) >> 3)) return 1;
+ if (scan_idx <= ((width << bhl) >> 2)) return 2;
return 3;
}
diff --git a/av1/encoder/encodemb.c b/av1/encoder/encodemb.c
index a6d255dcd4..07c6a921b5 100644
--- a/av1/encoder/encodemb.c
+++ b/av1/encoder/encodemb.c
@@ -488,13 +488,6 @@ void av1_setup_quant(TX_SIZE tx_size, int use_optimize_b, int xform_quant_idx,
qparam->qmatrix = NULL;
qparam->iqmatrix = NULL;
}
-void av1_setup_qmatrix(const CommonQuantParams *quant_params,
- const MACROBLOCKD *xd, int plane, TX_SIZE tx_size,
- TX_TYPE tx_type, QUANT_PARAM *qparam) {
- qparam->qmatrix = av1_get_qmatrix(quant_params, xd, plane, tx_size, tx_type);
- qparam->iqmatrix =
- av1_get_iqmatrix(quant_params, xd, plane, tx_size, tx_type);
-}
static void encode_block(int plane, int block, int blk_row, int blk_col,
BLOCK_SIZE plane_bsize, TX_SIZE tx_size, void *arg,
diff --git a/av1/encoder/encodemb.h b/av1/encoder/encodemb.h
index 822032a903..3f8a5a5d05 100644
--- a/av1/encoder/encodemb.h
+++ b/av1/encoder/encodemb.h
@@ -76,9 +76,21 @@ void av1_setup_xform(const AV1_COMMON *cm, MACROBLOCK *x, TX_SIZE tx_size,
TX_TYPE tx_type, TxfmParam *txfm_param);
void av1_setup_quant(TX_SIZE tx_size, int use_optimize_b, int xform_quant_idx,
int use_quant_b_adapt, QUANT_PARAM *qparam);
-void av1_setup_qmatrix(const CommonQuantParams *quant_params,
- const MACROBLOCKD *xd, int plane, TX_SIZE tx_size,
- TX_TYPE tx_type, QUANT_PARAM *qparam);
+static inline void av1_setup_qmatrix(const CommonQuantParams *quant_params,
+ const MACROBLOCKD *xd, int plane,
+ TX_SIZE tx_size, TX_TYPE tx_type,
+ QUANT_PARAM *qparam) {
+ (void)quant_params;
+ if (tx_type < IDTX) {
+ const struct macroblockd_plane *const pd = &xd->plane[plane];
+ const int seg_id = xd->mi[0]->segment_id;
+ qparam->qmatrix = pd->seg_qmatrix[seg_id][tx_size];
+ qparam->iqmatrix = pd->seg_iqmatrix[seg_id][tx_size];
+ } else {
+ qparam->qmatrix = NULL;
+ qparam->iqmatrix = NULL;
+ }
+}
void av1_xform_dc_only(MACROBLOCK *x, int plane, int block,
TxfmParam *txfm_param, int64_t per_px_mean);
diff --git a/av1/encoder/encodetxb.c b/av1/encoder/encodetxb.c
index 0c9c1a5cc4..51a0fd16c7 100644
--- a/av1/encoder/encodetxb.c
+++ b/av1/encoder/encodetxb.c
@@ -131,36 +131,17 @@ static void write_golomb(aom_writer *w, int level) {
for (i = length - 1; i >= 0; --i) aom_write_bit(w, (x >> i) & 0x01);
}
-static const int8_t eob_to_pos_small[33] = {
- 0, 1, 2, // 0-2
- 3, 3, // 3-4
- 4, 4, 4, 4, // 5-8
- 5, 5, 5, 5, 5, 5, 5, 5, // 9-16
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 // 17-32
-};
-
-static const int8_t eob_to_pos_large[17] = {
- 6, // place holder
- 7, // 33-64
- 8, 8, // 65-128
- 9, 9, 9, 9, // 129-256
- 10, 10, 10, 10, 10, 10, 10, 10, // 257-512
- 11 // 513-
-};
-
int av1_get_eob_pos_token(const int eob, int *const extra) {
- int t;
-
- if (eob < 33) {
- t = eob_to_pos_small[eob];
- } else {
- const int e = AOMMIN((eob - 1) >> 5, 16);
- t = eob_to_pos_large[e];
+ if (eob < 3) {
+ *extra = 0;
+ return eob;
}
-
- *extra = eob - av1_eob_group_start[t];
-
- return t;
+ // For eob >= 3, eob groups double in width starting at 3, so token index is
+ // floor(log2(eob - 1)) + 2 and extra is the offset within that group.
+ const int d = eob - 1;
+ const int k = get_msb(d);
+ *extra = d - (1 << k);
+ return k + 2;
}
#if CONFIG_ENTROPY_STATS
@@ -258,12 +239,7 @@ static inline int get_nz_map_ctx(const uint8_t *const levels,
const int width, const int scan_idx,
const int is_eob, const TX_SIZE tx_size,
const TX_CLASS tx_class) {
- if (is_eob) {
- if (scan_idx == 0) return 0;
- if (scan_idx <= (width << bhl) / 8) return 1;
- if (scan_idx <= (width << bhl) / 4) return 2;
- return 3;
- }
+ if (is_eob) return get_lower_levels_ctx_eob(bhl, width, scan_idx);
const int stats =
get_nz_mag(levels + get_padded_idx(coeff_idx, bhl), bhl, tx_class);
return get_nz_map_ctx_from_stats(stats, coeff_idx, bhl, tx_size, tx_class);
@@ -586,10 +562,12 @@ static void update_tx_type_count(const AV1_COMP *cpi, const AV1_COMMON *cm,
}
}
-void av1_update_and_record_txb_context(int plane, int block, int blk_row,
- int blk_col, BLOCK_SIZE plane_bsize,
- TX_SIZE tx_size, void *arg) {
- struct tokenize_b_args *const args = arg;
+#if defined(__GNUC__) || defined(__clang__)
+__attribute__((noinline))
+#endif
+static void update_and_record_txb_context_output(
+ int plane, int block, int blk_row, int blk_col, BLOCK_SIZE plane_bsize,
+ TX_SIZE tx_size, struct tokenize_b_args *const args) {
const AV1_COMP *cpi = args->cpi;
const AV1_COMMON *cm = &cpi->common;
ThreadData *const td = args->td;
@@ -598,149 +576,141 @@ void av1_update_and_record_txb_context(int plane, int block, int blk_row,
struct macroblock_plane *p = &x->plane[plane];
struct macroblockd_plane *pd = &xd->plane[plane];
const int eob = p->eobs[block];
+ const PLANE_TYPE plane_type = pd->plane_type;
+ MB_MODE_INFO *mbmi = xd->mi[0];
+ TXB_CTX txb_ctx;
+ get_txb_ctx(plane_bsize, tx_size, plane, pd->above_entropy_context + blk_col,
+ pd->left_entropy_context + blk_row, &txb_ctx);
+ const int bhl = get_txb_bhl(tx_size);
+ const int width = get_txb_wide(tx_size);
+ const int height = get_txb_high(tx_size);
+ const uint8_t allow_update_cdf = args->allow_update_cdf;
+ const TX_SIZE txsize_ctx = get_txsize_entropy_ctx(tx_size);
+ FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
+#if CONFIG_ENTROPY_STATS
+ int cdf_idx = cm->coef_cdf_category;
+ ++td->counts->txb_skip[cdf_idx][txsize_ctx][txb_ctx.txb_skip_ctx][eob == 0];
+#endif // CONFIG_ENTROPY_STATS
+ if (allow_update_cdf) {
+ update_cdf(ec_ctx->txb_skip_cdf[txsize_ctx][txb_ctx.txb_skip_ctx], eob == 0,
+ 2);
+ }
+
+ CB_COEFF_BUFFER *cb_coef_buff = x->cb_coef_buff;
+ const int txb_offset = x->mbmi_ext_frame->cb_offset[plane_type] /
+ (TX_SIZE_W_MIN * TX_SIZE_H_MIN);
+ uint16_t *eob_txb = cb_coef_buff->eobs[plane] + txb_offset;
+ uint8_t *const entropy_ctx = cb_coef_buff->entropy_ctx[plane] + txb_offset;
+ entropy_ctx[block] = txb_ctx.txb_skip_ctx;
+ eob_txb[block] = eob;
+
+ if (eob == 0) {
+ av1_set_entropy_contexts(xd, pd, plane, plane_bsize, tx_size, 0, blk_col,
+ blk_row);
+ return;
+ }
const int block_offset = BLOCK_OFFSET(block);
tran_low_t *qcoeff = p->qcoeff + block_offset;
- const PLANE_TYPE plane_type = pd->plane_type;
const TX_TYPE tx_type =
av1_get_tx_type(xd, plane_type, blk_row, blk_col, tx_size,
cm->features.reduced_tx_set_used);
const SCAN_ORDER *const scan_order = get_scan(tx_size, tx_type);
- tran_low_t *tcoeff;
- assert(args->dry_run != DRY_RUN_COSTCOEFFS);
- if (args->dry_run == OUTPUT_ENABLED) {
- MB_MODE_INFO *mbmi = xd->mi[0];
- TXB_CTX txb_ctx;
- get_txb_ctx(plane_bsize, tx_size, plane,
- pd->above_entropy_context + blk_col,
- pd->left_entropy_context + blk_row, &txb_ctx);
- const int bhl = get_txb_bhl(tx_size);
- const int width = get_txb_wide(tx_size);
- const int height = get_txb_high(tx_size);
- const uint8_t allow_update_cdf = args->allow_update_cdf;
- const TX_SIZE txsize_ctx = get_txsize_entropy_ctx(tx_size);
- FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
-#if CONFIG_ENTROPY_STATS
- int cdf_idx = cm->coef_cdf_category;
- ++td->counts->txb_skip[cdf_idx][txsize_ctx][txb_ctx.txb_skip_ctx][eob == 0];
-#endif // CONFIG_ENTROPY_STATS
- if (allow_update_cdf) {
- update_cdf(ec_ctx->txb_skip_cdf[txsize_ctx][txb_ctx.txb_skip_ctx],
- eob == 0, 2);
- }
-
- CB_COEFF_BUFFER *cb_coef_buff = x->cb_coef_buff;
- const int txb_offset = x->mbmi_ext_frame->cb_offset[plane_type] /
- (TX_SIZE_W_MIN * TX_SIZE_H_MIN);
- uint16_t *eob_txb = cb_coef_buff->eobs[plane] + txb_offset;
- uint8_t *const entropy_ctx = cb_coef_buff->entropy_ctx[plane] + txb_offset;
- entropy_ctx[block] = txb_ctx.txb_skip_ctx;
- eob_txb[block] = eob;
-
- if (eob == 0) {
- av1_set_entropy_contexts(xd, pd, plane, plane_bsize, tx_size, 0, blk_col,
- blk_row);
- return;
- }
- const int segment_id = mbmi->segment_id;
- const int seg_eob = av1_get_tx_eob(&cpi->common.seg, segment_id, tx_size);
- tran_low_t *tcoeff_txb =
- cb_coef_buff->tcoeff[plane] + x->mbmi_ext_frame->cb_offset[plane_type];
- tcoeff = tcoeff_txb + block_offset;
- memcpy(tcoeff, qcoeff, sizeof(*tcoeff) * seg_eob);
+ const int segment_id = mbmi->segment_id;
+ const int seg_eob = av1_get_tx_eob(&cpi->common.seg, segment_id, tx_size);
+ tran_low_t *tcoeff_txb =
+ cb_coef_buff->tcoeff[plane] + x->mbmi_ext_frame->cb_offset[plane_type];
+ tran_low_t *tcoeff = tcoeff_txb + block_offset;
+ memcpy(tcoeff, qcoeff, sizeof(*tcoeff) * seg_eob);
- uint8_t levels_buf[TX_PAD_2D];
- uint8_t *const levels = set_levels(levels_buf, height);
- av1_txb_init_levels(tcoeff, width, height, levels);
- update_tx_type_count(cpi, cm, xd, blk_row, blk_col, plane, tx_size,
- td->counts, allow_update_cdf);
+ uint8_t levels_buf[TX_PAD_2D];
+ uint8_t *const levels = set_levels(levels_buf, height);
+ av1_txb_init_levels(tcoeff, width, height, levels);
+ update_tx_type_count(cpi, cm, xd, blk_row, blk_col, plane, tx_size,
+ td->counts, allow_update_cdf);
- const TX_CLASS tx_class = tx_type_to_class[tx_type];
- const int16_t *const scan = scan_order->scan;
+ const TX_CLASS tx_class = tx_type_to_class[tx_type];
+ const int16_t *const scan = scan_order->scan;
- // record tx type usage
- td->rd_counts.tx_type_used[tx_size][tx_type]++;
+ // record tx type usage
+ td->rd_counts.tx_type_used[tx_size][tx_type]++;
#if CONFIG_ENTROPY_STATS
- update_eob_context(cdf_idx, eob, tx_size, tx_class, plane_type, ec_ctx,
- td->counts, allow_update_cdf);
+ update_eob_context(cdf_idx, eob, tx_size, tx_class, plane_type, ec_ctx,
+ td->counts, allow_update_cdf);
#else
- update_eob_context(eob, tx_size, tx_class, plane_type, ec_ctx,
- allow_update_cdf);
+ update_eob_context(eob, tx_size, tx_class, plane_type, ec_ctx,
+ allow_update_cdf);
#endif
- DECLARE_ALIGNED(16, int8_t, coeff_contexts[MAX_TX_SQUARE]);
- av1_get_nz_map_contexts(levels, scan, eob, tx_size, tx_class,
- coeff_contexts);
+ DECLARE_ALIGNED(16, int8_t, coeff_contexts[MAX_TX_SQUARE]);
+ av1_get_nz_map_contexts(levels, scan, eob, tx_size, tx_class, coeff_contexts);
- for (int c = eob - 1; c >= 0; --c) {
- const int pos = scan[c];
- const int coeff_ctx = coeff_contexts[pos];
- const tran_low_t v = qcoeff[pos];
- const tran_low_t level = abs(v);
- /* abs_sum_level is needed to decide the job scheduling order of
- * pack bitstream multi-threading. This data is not needed if
- * multi-threading is disabled. */
- if (cpi->mt_info.pack_bs_mt_enabled) td->abs_sum_level += level;
+ for (int c = eob - 1; c >= 0; --c) {
+ const int pos = scan[c];
+ const int coeff_ctx = coeff_contexts[pos];
+ const tran_low_t v = qcoeff[pos];
+ const tran_low_t level = abs(v);
+ /* abs_sum_level is needed to decide the job scheduling order of
+ * pack bitstream multi-threading. This data is not needed if
+ * multi-threading is disabled. */
+ if (cpi->mt_info.pack_bs_mt_enabled) td->abs_sum_level += level;
- if (allow_update_cdf) {
- if (c == eob - 1) {
- assert(coeff_ctx < 4);
- update_cdf(
- ec_ctx->coeff_base_eob_cdf[txsize_ctx][plane_type][coeff_ctx],
- AOMMIN(level, 3) - 1, 3);
- } else {
- update_cdf(ec_ctx->coeff_base_cdf[txsize_ctx][plane_type][coeff_ctx],
- AOMMIN(level, 3), 4);
- }
- }
+ if (allow_update_cdf) {
if (c == eob - 1) {
assert(coeff_ctx < 4);
-#if CONFIG_ENTROPY_STATS
- ++td->counts->coeff_base_eob_multi[cdf_idx][txsize_ctx][plane_type]
- [coeff_ctx][AOMMIN(level, 3) - 1];
+ update_cdf(
+ ec_ctx->coeff_base_eob_cdf[txsize_ctx][plane_type][coeff_ctx],
+ AOMMIN(level, 3) - 1, 3);
} else {
- ++td->counts->coeff_base_multi[cdf_idx][txsize_ctx][plane_type]
- [coeff_ctx][AOMMIN(level, 3)];
-#endif
+ update_cdf(ec_ctx->coeff_base_cdf[txsize_ctx][plane_type][coeff_ctx],
+ AOMMIN(level, 3), 4);
}
- if (level > NUM_BASE_LEVELS) {
- const int base_range = level - 1 - NUM_BASE_LEVELS;
- const int br_ctx = get_br_ctx(levels, pos, bhl, tx_class);
- for (int idx = 0; idx < COEFF_BASE_RANGE; idx += BR_CDF_SIZE - 1) {
- const int k = AOMMIN(base_range - idx, BR_CDF_SIZE - 1);
- if (allow_update_cdf) {
- update_cdf(ec_ctx->coeff_br_cdf[AOMMIN(txsize_ctx, TX_32X32)]
- [plane_type][br_ctx],
- k, BR_CDF_SIZE);
- }
- for (int lps = 0; lps < BR_CDF_SIZE - 1; lps++) {
+ }
+ if (c == eob - 1) {
+ assert(coeff_ctx < 4);
#if CONFIG_ENTROPY_STATS
- ++td->counts->coeff_lps[AOMMIN(txsize_ctx, TX_32X32)][plane_type]
- [lps][br_ctx][lps == k];
+ ++td->counts->coeff_base_eob_multi[cdf_idx][txsize_ctx][plane_type]
+ [coeff_ctx][AOMMIN(level, 3) - 1];
+ } else {
+ ++td->counts->coeff_base_multi[cdf_idx][txsize_ctx][plane_type][coeff_ctx]
+ [AOMMIN(level, 3)];
+#endif
+ }
+ if (level > NUM_BASE_LEVELS) {
+ const int base_range = level - 1 - NUM_BASE_LEVELS;
+ const int br_ctx = get_br_ctx(levels, pos, bhl, tx_class);
+ for (int idx = 0; idx < COEFF_BASE_RANGE; idx += BR_CDF_SIZE - 1) {
+ const int k = AOMMIN(base_range - idx, BR_CDF_SIZE - 1);
+ if (allow_update_cdf) {
+ update_cdf(ec_ctx->coeff_br_cdf[AOMMIN(txsize_ctx, TX_32X32)]
+ [plane_type][br_ctx],
+ k, BR_CDF_SIZE);
+ }
+ for (int lps = 0; lps < BR_CDF_SIZE - 1; lps++) {
+#if CONFIG_ENTROPY_STATS
+ ++td->counts->coeff_lps[AOMMIN(txsize_ctx, TX_32X32)][plane_type][lps]
+ [br_ctx][lps == k];
#endif // CONFIG_ENTROPY_STATS
- if (lps == k) break;
- }
+ if (lps == k) break;
+ }
#if CONFIG_ENTROPY_STATS
- ++td->counts->coeff_lps_multi[cdf_idx][AOMMIN(txsize_ctx, TX_32X32)]
- [plane_type][br_ctx][k];
+ ++td->counts->coeff_lps_multi[cdf_idx][AOMMIN(txsize_ctx, TX_32X32)]
+ [plane_type][br_ctx][k];
#endif
- if (k < BR_CDF_SIZE - 1) break;
- }
+ if (k < BR_CDF_SIZE - 1) break;
}
}
- // Update the context needed to code the DC sign (if applicable)
- if (tcoeff[0] != 0) {
- const int dc_sign = (tcoeff[0] < 0) ? 1 : 0;
- const int dc_sign_ctx = txb_ctx.dc_sign_ctx;
+ }
+ // Update the context needed to code the DC sign (if applicable)
+ if (tcoeff[0] != 0) {
+ const int dc_sign = (tcoeff[0] < 0) ? 1 : 0;
+ const int dc_sign_ctx = txb_ctx.dc_sign_ctx;
#if CONFIG_ENTROPY_STATS
- ++td->counts->dc_sign[plane_type][dc_sign_ctx][dc_sign];
+ ++td->counts->dc_sign[plane_type][dc_sign_ctx][dc_sign];
#endif // CONFIG_ENTROPY_STATS
- if (allow_update_cdf)
- update_cdf(ec_ctx->dc_sign_cdf[plane_type][dc_sign_ctx], dc_sign, 2);
- entropy_ctx[block] |= dc_sign_ctx << DC_SIGN_CTX_SHIFT;
- }
- } else {
- tcoeff = qcoeff;
+ if (allow_update_cdf)
+ update_cdf(ec_ctx->dc_sign_cdf[plane_type][dc_sign_ctx], dc_sign, 2);
+ entropy_ctx[block] |= dc_sign_ctx << DC_SIGN_CTX_SHIFT;
}
const uint8_t cul_level =
av1_get_txb_entropy_context(tcoeff, scan_order, eob);
@@ -748,10 +718,13 @@ void av1_update_and_record_txb_context(int plane, int block, int blk_row,
blk_col, blk_row);
}
-void av1_record_txb_context(int plane, int block, int blk_row, int blk_col,
- BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
- void *arg) {
- struct tokenize_b_args *const args = arg;
+#if defined(__GNUC__) || defined(__clang__)
+__attribute__((noinline))
+#endif
+static void record_txb_context_output(int plane, int block, int blk_row,
+ int blk_col, BLOCK_SIZE plane_bsize,
+ TX_SIZE tx_size,
+ struct tokenize_b_args *const args) {
const AV1_COMP *cpi = args->cpi;
const AV1_COMMON *cm = &cpi->common;
ThreadData *const td = args->td;
@@ -760,124 +733,116 @@ void av1_record_txb_context(int plane, int block, int blk_row, int blk_col,
struct macroblock_plane *p = &x->plane[plane];
struct macroblockd_plane *pd = &xd->plane[plane];
const int eob = p->eobs[block];
+ const PLANE_TYPE plane_type = pd->plane_type;
+ MB_MODE_INFO *mbmi = xd->mi[0];
+ TXB_CTX txb_ctx;
+ get_txb_ctx(plane_bsize, tx_size, plane, pd->above_entropy_context + blk_col,
+ pd->left_entropy_context + blk_row, &txb_ctx);
+#if CONFIG_ENTROPY_STATS
+ const TX_SIZE txsize_ctx = get_txsize_entropy_ctx(tx_size);
+ const int bhl = get_txb_bhl(tx_size);
+ const int width = get_txb_wide(tx_size);
+ const int height = get_txb_high(tx_size);
+ int cdf_idx = cm->coef_cdf_category;
+ ++td->counts->txb_skip[cdf_idx][txsize_ctx][txb_ctx.txb_skip_ctx][eob == 0];
+#endif // CONFIG_ENTROPY_STATS
+
+ CB_COEFF_BUFFER *cb_coef_buff = x->cb_coef_buff;
+ const int txb_offset = x->mbmi_ext_frame->cb_offset[plane_type] /
+ (TX_SIZE_W_MIN * TX_SIZE_H_MIN);
+ uint16_t *eob_txb = cb_coef_buff->eobs[plane] + txb_offset;
+ uint8_t *const entropy_ctx = cb_coef_buff->entropy_ctx[plane] + txb_offset;
+ entropy_ctx[block] = txb_ctx.txb_skip_ctx;
+ eob_txb[block] = eob;
+
+ if (eob == 0) {
+ av1_set_entropy_contexts(xd, pd, plane, plane_bsize, tx_size, 0, blk_col,
+ blk_row);
+ return;
+ }
const int block_offset = BLOCK_OFFSET(block);
tran_low_t *qcoeff = p->qcoeff + block_offset;
- const PLANE_TYPE plane_type = pd->plane_type;
const TX_TYPE tx_type =
av1_get_tx_type(xd, plane_type, blk_row, blk_col, tx_size,
cm->features.reduced_tx_set_used);
const SCAN_ORDER *const scan_order = get_scan(tx_size, tx_type);
- tran_low_t *tcoeff;
- assert(args->dry_run != DRY_RUN_COSTCOEFFS);
- if (args->dry_run == OUTPUT_ENABLED) {
- MB_MODE_INFO *mbmi = xd->mi[0];
- TXB_CTX txb_ctx;
- get_txb_ctx(plane_bsize, tx_size, plane,
- pd->above_entropy_context + blk_col,
- pd->left_entropy_context + blk_row, &txb_ctx);
-#if CONFIG_ENTROPY_STATS
- const TX_SIZE txsize_ctx = get_txsize_entropy_ctx(tx_size);
- const int bhl = get_txb_bhl(tx_size);
- const int width = get_txb_wide(tx_size);
- const int height = get_txb_high(tx_size);
- int cdf_idx = cm->coef_cdf_category;
- ++td->counts->txb_skip[cdf_idx][txsize_ctx][txb_ctx.txb_skip_ctx][eob == 0];
-#endif // CONFIG_ENTROPY_STATS
-
- CB_COEFF_BUFFER *cb_coef_buff = x->cb_coef_buff;
- const int txb_offset = x->mbmi_ext_frame->cb_offset[plane_type] /
- (TX_SIZE_W_MIN * TX_SIZE_H_MIN);
- uint16_t *eob_txb = cb_coef_buff->eobs[plane] + txb_offset;
- uint8_t *const entropy_ctx = cb_coef_buff->entropy_ctx[plane] + txb_offset;
- entropy_ctx[block] = txb_ctx.txb_skip_ctx;
- eob_txb[block] = eob;
-
- if (eob == 0) {
- av1_set_entropy_contexts(xd, pd, plane, plane_bsize, tx_size, 0, blk_col,
- blk_row);
- return;
- }
- const int segment_id = mbmi->segment_id;
- const int seg_eob = av1_get_tx_eob(&cpi->common.seg, segment_id, tx_size);
- tran_low_t *tcoeff_txb =
- cb_coef_buff->tcoeff[plane] + x->mbmi_ext_frame->cb_offset[plane_type];
- tcoeff = tcoeff_txb + block_offset;
- memcpy(tcoeff, qcoeff, sizeof(*tcoeff) * seg_eob);
+ const int segment_id = mbmi->segment_id;
+ const int seg_eob = av1_get_tx_eob(&cpi->common.seg, segment_id, tx_size);
+ tran_low_t *tcoeff_txb =
+ cb_coef_buff->tcoeff[plane] + x->mbmi_ext_frame->cb_offset[plane_type];
+ tran_low_t *tcoeff = tcoeff_txb + block_offset;
+ memcpy(tcoeff, qcoeff, sizeof(*tcoeff) * seg_eob);
#if CONFIG_ENTROPY_STATS
- uint8_t levels_buf[TX_PAD_2D];
- uint8_t *const levels = set_levels(levels_buf, height);
- av1_txb_init_levels(tcoeff, width, height, levels);
- update_tx_type_count(cpi, cm, xd, blk_row, blk_col, plane, tx_size,
- td->counts, 0 /*allow_update_cdf*/);
-
- const TX_CLASS tx_class = tx_type_to_class[tx_type];
- const bool do_coeff_scan = true;
+ uint8_t levels_buf[TX_PAD_2D];
+ uint8_t *const levels = set_levels(levels_buf, height);
+ av1_txb_init_levels(tcoeff, width, height, levels);
+ update_tx_type_count(cpi, cm, xd, blk_row, blk_col, plane, tx_size,
+ td->counts, 0 /*allow_update_cdf*/);
+
+ const TX_CLASS tx_class = tx_type_to_class[tx_type];
+ const bool do_coeff_scan = true;
#else
- const bool do_coeff_scan = cpi->mt_info.pack_bs_mt_enabled;
+ const bool do_coeff_scan = cpi->mt_info.pack_bs_mt_enabled;
#endif
- const int16_t *const scan = scan_order->scan;
+ const int16_t *const scan = scan_order->scan;
- // record tx type usage
- td->rd_counts.tx_type_used[tx_size][tx_type]++;
+ // record tx type usage
+ td->rd_counts.tx_type_used[tx_size][tx_type]++;
#if CONFIG_ENTROPY_STATS
- FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
- update_eob_context(cdf_idx, eob, tx_size, tx_class, plane_type, ec_ctx,
- td->counts, 0 /*allow_update_cdf*/);
+ FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
+ update_eob_context(cdf_idx, eob, tx_size, tx_class, plane_type, ec_ctx,
+ td->counts, 0 /*allow_update_cdf*/);
- DECLARE_ALIGNED(16, int8_t, coeff_contexts[MAX_TX_SQUARE]);
- av1_get_nz_map_contexts(levels, scan, eob, tx_size, tx_class,
- coeff_contexts);
+ DECLARE_ALIGNED(16, int8_t, coeff_contexts[MAX_TX_SQUARE]);
+ av1_get_nz_map_contexts(levels, scan, eob, tx_size, tx_class, coeff_contexts);
#endif
- for (int c = eob - 1; (c >= 0) && do_coeff_scan; --c) {
- const int pos = scan[c];
- const tran_low_t v = qcoeff[pos];
- const tran_low_t level = abs(v);
- /* abs_sum_level is needed to decide the job scheduling order of
- * pack bitstream multi-threading. This data is not needed if
- * multi-threading is disabled. */
- if (cpi->mt_info.pack_bs_mt_enabled) td->abs_sum_level += level;
+ for (int c = eob - 1; (c >= 0) && do_coeff_scan; --c) {
+ const int pos = scan[c];
+ const tran_low_t v = qcoeff[pos];
+ const tran_low_t level = abs(v);
+ /* abs_sum_level is needed to decide the job scheduling order of
+ * pack bitstream multi-threading. This data is not needed if
+ * multi-threading is disabled. */
+ if (cpi->mt_info.pack_bs_mt_enabled) td->abs_sum_level += level;
#if CONFIG_ENTROPY_STATS
- const int coeff_ctx = coeff_contexts[pos];
- if (c == eob - 1) {
- assert(coeff_ctx < 4);
- ++td->counts->coeff_base_eob_multi[cdf_idx][txsize_ctx][plane_type]
- [coeff_ctx][AOMMIN(level, 3) - 1];
- } else {
- ++td->counts->coeff_base_multi[cdf_idx][txsize_ctx][plane_type]
- [coeff_ctx][AOMMIN(level, 3)];
- }
- if (level > NUM_BASE_LEVELS) {
- const int base_range = level - 1 - NUM_BASE_LEVELS;
- const int br_ctx = get_br_ctx(levels, pos, bhl, tx_class);
- for (int idx = 0; idx < COEFF_BASE_RANGE; idx += BR_CDF_SIZE - 1) {
- const int k = AOMMIN(base_range - idx, BR_CDF_SIZE - 1);
- for (int lps = 0; lps < BR_CDF_SIZE - 1; lps++) {
- ++td->counts->coeff_lps[AOMMIN(txsize_ctx, TX_32X32)][plane_type]
- [lps][br_ctx][lps == k];
- if (lps == k) break;
- }
- ++td->counts->coeff_lps_multi[cdf_idx][AOMMIN(txsize_ctx, TX_32X32)]
- [plane_type][br_ctx][k];
- if (k < BR_CDF_SIZE - 1) break;
+ const int coeff_ctx = coeff_contexts[pos];
+ if (c == eob - 1) {
+ assert(coeff_ctx < 4);
+ ++td->counts->coeff_base_eob_multi[cdf_idx][txsize_ctx][plane_type]
+ [coeff_ctx][AOMMIN(level, 3) - 1];
+ } else {
+ ++td->counts->coeff_base_multi[cdf_idx][txsize_ctx][plane_type][coeff_ctx]
+ [AOMMIN(level, 3)];
+ }
+ if (level > NUM_BASE_LEVELS) {
+ const int base_range = level - 1 - NUM_BASE_LEVELS;
+ const int br_ctx = get_br_ctx(levels, pos, bhl, tx_class);
+ for (int idx = 0; idx < COEFF_BASE_RANGE; idx += BR_CDF_SIZE - 1) {
+ const int k = AOMMIN(base_range - idx, BR_CDF_SIZE - 1);
+ for (int lps = 0; lps < BR_CDF_SIZE - 1; lps++) {
+ ++td->counts->coeff_lps[AOMMIN(txsize_ctx, TX_32X32)][plane_type][lps]
+ [br_ctx][lps == k];
+ if (lps == k) break;
}
+ ++td->counts->coeff_lps_multi[cdf_idx][AOMMIN(txsize_ctx, TX_32X32)]
+ [plane_type][br_ctx][k];
+ if (k < BR_CDF_SIZE - 1) break;
}
-#endif
}
- // Update the context needed to code the DC sign (if applicable)
- if (tcoeff[0] != 0) {
- const int dc_sign_ctx = txb_ctx.dc_sign_ctx;
+#endif
+ }
+ // Update the context needed to code the DC sign (if applicable)
+ if (tcoeff[0] != 0) {
+ const int dc_sign_ctx = txb_ctx.dc_sign_ctx;
#if CONFIG_ENTROPY_STATS
- const int dc_sign = (tcoeff[0] < 0) ? 1 : 0;
- ++td->counts->dc_sign[plane_type][dc_sign_ctx][dc_sign];
+ const int dc_sign = (tcoeff[0] < 0) ? 1 : 0;
+ ++td->counts->dc_sign[plane_type][dc_sign_ctx][dc_sign];
#endif // CONFIG_ENTROPY_STATS
- entropy_ctx[block] |= dc_sign_ctx << DC_SIGN_CTX_SHIFT;
- }
- } else {
- tcoeff = qcoeff;
+ entropy_ctx[block] |= dc_sign_ctx << DC_SIGN_CTX_SHIFT;
}
const uint8_t cul_level =
av1_get_txb_entropy_context(tcoeff, scan_order, eob);
@@ -885,6 +850,55 @@ void av1_record_txb_context(int plane, int block, int blk_row, int blk_col,
blk_col, blk_row);
}
+static inline void record_txb_context_dry_run(
+ int plane, int block, int blk_row, int blk_col, BLOCK_SIZE plane_bsize,
+ TX_SIZE tx_size, const struct tokenize_b_args *args) {
+ assert(args->dry_run != DRY_RUN_COSTCOEFFS);
+ MACROBLOCK *const x = &args->td->mb;
+ MACROBLOCKD *const xd = &x->e_mbd;
+ struct macroblock_plane *p = &x->plane[plane];
+ struct macroblockd_plane *pd = &xd->plane[plane];
+ const int eob = p->eobs[block];
+ uint8_t cul_level = 0;
+ if (eob > 0) {
+ const AV1_COMMON *cm = &args->cpi->common;
+ const TX_TYPE tx_type =
+ av1_get_tx_type(xd, pd->plane_type, blk_row, blk_col, tx_size,
+ cm->features.reduced_tx_set_used);
+ const SCAN_ORDER *const scan_order = get_scan(tx_size, tx_type);
+ const tran_low_t *tcoeff = p->qcoeff + BLOCK_OFFSET(block);
+ cul_level = av1_get_txb_entropy_context(tcoeff, scan_order, eob);
+ }
+ av1_set_entropy_contexts(xd, pd, plane, plane_bsize, tx_size, cul_level,
+ blk_col, blk_row);
+}
+
+void av1_update_and_record_txb_context(int plane, int block, int blk_row,
+ int blk_col, BLOCK_SIZE plane_bsize,
+ TX_SIZE tx_size, void *arg) {
+ struct tokenize_b_args *const args = arg;
+ if (args->dry_run == OUTPUT_ENABLED) {
+ update_and_record_txb_context_output(plane, block, blk_row, blk_col,
+ plane_bsize, tx_size, args);
+ return;
+ }
+ record_txb_context_dry_run(plane, block, blk_row, blk_col, plane_bsize,
+ tx_size, args);
+}
+
+void av1_record_txb_context(int plane, int block, int blk_row, int blk_col,
+ BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
+ void *arg) {
+ struct tokenize_b_args *const args = arg;
+ if (args->dry_run == OUTPUT_ENABLED) {
+ record_txb_context_output(plane, block, blk_row, blk_col, plane_bsize,
+ tx_size, args);
+ return;
+ }
+ record_txb_context_dry_run(plane, block, blk_row, blk_col, plane_bsize,
+ tx_size, args);
+}
+
void av1_update_intra_mb_txb_context(const AV1_COMP *cpi, ThreadData *td,
RUN_TYPE dry_run, BLOCK_SIZE bsize,
uint8_t allow_update_cdf) {
diff --git a/av1/encoder/txb_rdopt.c b/av1/encoder/txb_rdopt.c
index 02f5615b50..3996f86fff 100644
--- a/av1/encoder/txb_rdopt.c
+++ b/av1/encoder/txb_rdopt.c
@@ -420,11 +420,13 @@ int av1_optimize_txb(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane,
int eob = p->eobs[block];
const int16_t *dequant = p->dequant_QTX;
const qm_val_t *iqmatrix =
- av1_get_iqmatrix(&cpi->common.quant_params, xd, plane, tx_size, tx_type);
+ tx_type < IDTX
+ ? xd->plane[plane].seg_iqmatrix[xd->mi[0]->segment_id][tx_size]
+ : NULL;
const qm_val_t *qmatrix =
- cpi->oxcf.tune_cfg.dist_metric == AOM_DIST_METRIC_QM_PSNR
- ? av1_get_qmatrix(&cpi->common.quant_params, xd, plane, tx_size,
- tx_type)
+ (cpi->oxcf.tune_cfg.dist_metric == AOM_DIST_METRIC_QM_PSNR &&
+ tx_type < IDTX)
+ ? xd->plane[plane].seg_qmatrix[xd->mi[0]->segment_id][tx_size]
: NULL;
const int block_offset = BLOCK_OFFSET(block);
tran_low_t *qcoeff = p->qcoeff + block_offset;
diff --git a/av1/encoder/txb_rdopt_utils.h b/av1/encoder/txb_rdopt_utils.h
index 1ceee6610a..2b6874e7f6 100644
--- a/av1/encoder/txb_rdopt_utils.h
+++ b/av1/encoder/txb_rdopt_utils.h
@@ -63,23 +63,21 @@ static inline int64_t get_coeff_dist(tran_low_t tcoeff, tran_low_t dqcoeff,
return error;
}
-static int get_eob_cost(int eob, const LV_MAP_EOB_COST *txb_eob_costs,
- const LV_MAP_COEFF_COST *txb_costs, TX_CLASS tx_class) {
- int eob_extra;
- const int eob_pt = av1_get_eob_pos_token(eob, &eob_extra);
- int eob_cost = 0;
+static inline int get_eob_cost(int eob, const LV_MAP_EOB_COST *txb_eob_costs,
+ const LV_MAP_COEFF_COST *txb_costs,
+ TX_CLASS tx_class) {
const int eob_multi_ctx = (tx_class == TX_CLASS_2D) ? 0 : 1;
- eob_cost = txb_eob_costs->eob_cost[eob_multi_ctx][eob_pt - 1];
-
- if (av1_eob_offset_bits[eob_pt] > 0) {
- const int eob_ctx = eob_pt - 3;
- const int eob_shift = av1_eob_offset_bits[eob_pt] - 1;
- const int bit = (eob_extra & (1 << eob_shift)) ? 1 : 0;
- eob_cost += txb_costs->eob_extra_cost[eob_ctx][bit];
- const int offset_bits = av1_eob_offset_bits[eob_pt];
- if (offset_bits > 1) eob_cost += av1_cost_literal(offset_bits - 1);
+ if (eob < 3) {
+ return txb_eob_costs->eob_cost[eob_multi_ctx][eob - 1];
}
- return eob_cost;
+ // For eob >= 3, eob_pt = k + 2 where k = get_msb(eob - 1), and offset_bits =
+ // k. The top offset bit uses context-coded eob_extra_cost[k - 1][bit], and
+ // the remaining (k - 1) offset bits are coded as literals.
+ const int d = eob - 1;
+ const int k = get_msb(d);
+ const int bit = (d >> (k - 1)) & 1;
+ return txb_eob_costs->eob_cost[eob_multi_ctx][k + 1] +
+ txb_costs->eob_extra_cost[k - 1][bit] + av1_cost_literal(k - 1);
}
static inline int get_golomb_cost(int abs_qc) {