Commit 33bcd117 authored by Fangwen Fu's avatar Fangwen Fu Committed by Urvang Joshi

improving palette throughput

* code the palette color index using 45 wavefront
* interleave the coeff and palette color index in
  transform block level
* the above change does not change code efficiency

Details: 
The 45 wavefront scan allows to compute the ctx of
the diagonal samples' indices  at the same time. 
Interleaving palette indices and palette residual
on a transform block basis means that the entropy
 decoding and further processing of the palette 
residual is not delayed by the entropy decoding 
of all the color indices of the palette encoded 
block.
Change-Id: Ie9f576002a9a68394b99c23b01e9730df06df070
parent 98378137
......@@ -41,6 +41,8 @@ PREDICTION_MODE av1_above_block_mode(const MODE_INFO *cur_mi,
}
#if CONFIG_COEF_INTERLEAVE
// TODO(Fangwen): Make CONFIG_COEF_INTERLEAVE work with
// CONFIG_PALETTE_THROUGHPUT
void av1_foreach_transformed_block_interleave(
const MACROBLOCKD *const xd, BLOCK_SIZE bsize,
foreach_transformed_block_visitor visit, void *arg) {
......
......@@ -508,7 +508,10 @@ static void predict_and_reconstruct_intra_block(
if (mbmi->sb_type < BLOCK_8X8)
if (plane == 0) mode = xd->mi[0]->bmi[block_idx].as_mode;
#endif
#if CONFIG_PALETTE && CONFIG_PALETTE_THROUGHPUT
if (mbmi->palette_mode_info.palette_size[plane > 0] && plane <= 1)
av1_decode_palette_tokens(xd, plane, tx_size, row, col, r);
#endif // CONFIG_PALETTE && CONFIG_PALETTE_THROUGHPUT
av1_predict_intra_block(xd, pd->width, pd->height, txsize_to_bsize[tx_size],
mode, dst, pd->dst.stride, dst, pd->dst.stride, col,
row, plane);
......@@ -1560,6 +1563,8 @@ static void decode_token_and_recon_block(AV1Decoder *const pbi,
int plane;
#if CONFIG_PALETTE
// TODO(fangwen): Make CONFIG_COEF_INTERLEAVE work with
// CONFIG_PALETTE_THROUGHPUT
for (plane = 0; plane <= 1; ++plane) {
if (mbmi->palette_mode_info.palette_size[plane])
av1_decode_palette_tokens(xd, plane, r);
......@@ -1647,12 +1652,12 @@ static void decode_token_and_recon_block(AV1Decoder *const pbi,
#else
if (!is_inter_block(mbmi)) {
int plane;
#if CONFIG_PALETTE
#if CONFIG_PALETTE && !CONFIG_PALETTE_THROUGHPUT
for (plane = 0; plane <= 1; ++plane) {
if (mbmi->palette_mode_info.palette_size[plane])
av1_decode_palette_tokens(xd, plane, r);
}
#endif // CONFIG_PALETTE
#endif // CONFIG_PALETTE && !CONFIG_PALETTE_THROUGHPUT
for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
const struct macroblockd_plane *const pd = &xd->plane[plane];
const TX_SIZE tx_size = plane ? get_uv_tx_size(mbmi, pd) : mbmi->tx_size;
......@@ -1672,7 +1677,6 @@ static void decode_token_and_recon_block(AV1Decoder *const pbi,
int row, col;
const int max_blocks_wide = max_block_wide(xd, plane_bsize, plane);
const int max_blocks_high = max_block_high(xd, plane_bsize, plane);
#if CONFIG_CB4X4
if (bsize < BLOCK_8X8 && plane && !is_chroma_reference(mi_row, mi_col))
continue;
......
......@@ -442,6 +442,70 @@ static int decode_coefs(MACROBLOCKD *xd, PLANE_TYPE type, tran_low_t *dqcoeff,
#endif // !CONFIG_PVQ
#if CONFIG_PALETTE
#if CONFIG_PALETTE_THROUGHPUT
void av1_decode_palette_tokens(MACROBLOCKD *const xd, int plane,
TX_SIZE tx_size, int row, int col,
aom_reader *r) {
const MODE_INFO *const mi = xd->mi[0];
const MB_MODE_INFO *const mbmi = &mi->mbmi;
uint8_t color_order[PALETTE_MAX_SIZE];
const int n = mbmi->palette_mode_info.palette_size[plane];
int i, j;
uint8_t *const color_map = xd->plane[plane].color_index_map;
const aom_prob(
*const prob)[PALETTE_COLOR_INDEX_CONTEXTS][PALETTE_COLORS - 1] =
plane ? av1_default_palette_uv_color_index_prob
: av1_default_palette_y_color_index_prob;
int plane_block_width, plane_block_height, rows, cols;
const int bsize = txsize_to_bsize[tx_size];
const int tx_block_width = 1 << tx_size_wide_log2[0];
const int tx_block_height = 1 << tx_size_high_log2[0];
av1_get_block_dimensions(mbmi->sb_type, plane, xd, &plane_block_width,
&plane_block_height, &rows, &cols);
const int block_width =
AOMMIN(cols - col * tx_block_width, block_size_wide[bsize]);
const int block_height =
AOMMIN(rows - row * tx_block_height, block_size_high[bsize]);
assert(plane == 0 || plane == 1);
// run wavefront on the palette map index decoding per transform block
for (i = ((row == 0 && col == 0) ? 1 : 0); i < block_width + block_height - 1;
++i) {
for (j = AOMMIN(i, block_width - 1); j >= AOMMAX(0, i - block_height + 1);
--j) {
const int color_ctx = av1_get_palette_color_index_context(
color_map, plane_block_width, row * tx_block_height + (i - j),
col * tx_block_width + j, n, color_order, NULL);
const int color_idx =
aom_read_tree(r, av1_palette_color_index_tree[n - 2],
prob[n - 2][color_ctx], ACCT_STR);
assert(color_idx >= 0 && color_idx < n);
color_map[(row * tx_block_height + i - j) * plane_block_width +
col * tx_block_width + j] = color_order[color_idx];
}
}
// Copy last column to extra columns.
if (block_width < block_size_wide[bsize]) {
for (i = 0; i < block_height; ++i) {
memset(color_map + (row * tx_block_height + i) * plane_block_width +
col * tx_block_width + block_width,
color_map[(row * tx_block_height + i) * plane_block_width +
col * tx_block_width + block_width - 1],
(block_size_wide[bsize] - block_width));
}
}
// Copy last row to extra rows.
if (block_height < block_size_high[bsize]) {
for (i = block_height; i < block_size_high[bsize]; ++i) {
memcpy(color_map + (row * tx_block_height + i) * plane_block_width,
color_map +
(row * tx_block_height + block_height - 1) * plane_block_width,
block_size_wide[bsize]);
}
}
}
#else
void av1_decode_palette_tokens(MACROBLOCKD *const xd, int plane,
aom_reader *r) {
const MODE_INFO *const mi = xd->mi[0];
......@@ -479,6 +543,7 @@ void av1_decode_palette_tokens(MACROBLOCKD *const xd, int plane,
color_map + (rows - 1) * plane_block_width, plane_block_width);
}
}
#endif // CONFIG_PALETTE_THROUGHPUT
#endif // CONFIG_PALETTE
#if !CONFIG_PVQ
......
......@@ -25,7 +25,13 @@ extern "C" {
#endif
#if CONFIG_PALETTE
#if CONFIG_PALETTE_THROUGHPUT
void av1_decode_palette_tokens(MACROBLOCKD *const xd, int plane,
TX_SIZE tx_size, int row, int col,
aom_reader *r);
#else
void av1_decode_palette_tokens(MACROBLOCKD *const xd, int plane, aom_reader *r);
#endif // CONFIG_PALETTE_THROUGHPUT
#endif // CONFIG_PALETTE
#if !CONFIG_PVQ
......
......@@ -783,7 +783,7 @@ static void pack_mb_tokens(aom_writer *w, const TOKENEXTRA **tp,
aom_bit_depth_t bit_depth, const TX_SIZE tx_size,
TOKEN_STATS *token_stats) {
const TOKENEXTRA *p = *tp;
#if CONFIG_VAR_TX
#if CONFIG_VAR_TX || CONFIG_PALETTE_THROUGHPUT
int count = 0;
const int seg_eob = tx_size_2d[tx_size];
#endif
......@@ -846,7 +846,7 @@ static void pack_mb_tokens(aom_writer *w, const TOKENEXTRA **tp,
}
++p;
#if CONFIG_VAR_TX
#if CONFIG_VAR_TX || CONFIG_PALETTE_THROUGHPUT
++count;
if (token == EOB_TOKEN || count == seg_eob) break;
#endif
......@@ -860,7 +860,7 @@ static void pack_mb_tokens(aom_writer *w, const TOKENEXTRA **tp,
aom_bit_depth_t bit_depth, const TX_SIZE tx_size,
TOKEN_STATS *token_stats) {
const TOKENEXTRA *p = *tp;
#if CONFIG_VAR_TX
#if CONFIG_VAR_TX || CONFIG_PALETTE_THROUGHPUT
int count = 0;
const int seg_eob = tx_size_2d[tx_size];
#endif
......@@ -951,7 +951,7 @@ static void pack_mb_tokens(aom_writer *w, const TOKENEXTRA **tp,
}
++p;
#if CONFIG_VAR_TX
#if CONFIG_VAR_TX || CONFIG_PALETTE_THROUGHPUT
++count;
if (token == EOB_TOKEN || count == seg_eob) break;
#endif
......@@ -2062,7 +2062,6 @@ static void write_tokens_b(AV1_COMP *cpi, const TileInfo *const tile,
#else
set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols);
#endif
#if CONFIG_PVQ
mbmi = &m->mbmi;
bsize = mbmi->sb_type;
......@@ -2070,18 +2069,23 @@ static void write_tokens_b(AV1_COMP *cpi, const TileInfo *const tile,
#endif
#if CONFIG_PALETTE
for (plane = 0; plane <= 1; ++plane) {
const uint8_t palette_size_plane =
m->mbmi.palette_mode_info.palette_size[plane];
if (palette_size_plane > 0) {
int rows, cols;
av1_get_block_dimensions(m->mbmi.sb_type, plane, xd, NULL, NULL, &rows,
&cols);
assert(*tok < tok_end);
pack_palette_tokens(w, tok, palette_size_plane, rows * cols - 1);
assert(*tok < tok_end + m->mbmi.skip);
#if CONFIG_PALETTE_THROUGHPUT
// when block is skipped, palette index is coded here
// since there is no coeff to be interleaved.
if (m->mbmi.skip)
#endif // CONFIG_PALETTE_THROUGHPUT
for (plane = 0; plane <= 1; ++plane) {
const uint8_t palette_size_plane =
m->mbmi.palette_mode_info.palette_size[plane];
if (palette_size_plane > 0) {
int rows, cols;
av1_get_block_dimensions(m->mbmi.sb_type, plane, xd, NULL, NULL, &rows,
&cols);
assert(*tok < tok_end);
pack_palette_tokens(w, tok, palette_size_plane, rows * cols - 1);
assert(*tok < tok_end + m->mbmi.skip);
}
}
}
#endif // CONFIG_PALETTE
#if !CONFIG_PVQ
......@@ -2219,17 +2223,81 @@ static void write_tokens_b(AV1_COMP *cpi, const TileInfo *const tile,
: m->mbmi.tx_size;
const int bkw = tx_size_wide_unit[tx];
const int bkh = tx_size_high_unit[tx];
for (row = 0; row < num_4x4_h; row += bkh)
for (col = 0; col < num_4x4_w; col += bkw)
#if CONFIG_PALETTE && CONFIG_PALETTE_THROUGHPUT
const uint8_t palette_size_plane =
m->mbmi.palette_mode_info.palette_size[plane > 0];
const int bkw_in_pixel = bkw << tx_size_wide_log2[0];
const int bkh_in_pixel = bkh << tx_size_wide_log2[0];
int rows, cols;
av1_get_block_dimensions(m->mbmi.sb_type, plane, xd, NULL, NULL, &rows,
&cols);
#endif // CONFIG_PALETTE && CONFIG_PALETTE_THROUGHPUT
for (row = 0; row < num_4x4_h; row += bkh) {
for (col = 0; col < num_4x4_w; col += bkw) {
#if CONFIG_PALETTE && CONFIG_PALETTE_THROUGHPUT
if (palette_size_plane > 0 && plane <= 1) {
const int col_in_pixel = col << tx_size_wide_log2[0];
const int row_in_pixel = row << tx_size_high_log2[0];
const int txbkw = AOMMIN(cols - col_in_pixel, bkw_in_pixel);
const int txbkh = AOMMIN(rows - row_in_pixel, bkh_in_pixel);
// first palette index is not coded here but in header instead
const int num_palette_indexes =
txbkw * txbkh - ((row == 0 && col == 0) ? 1 : 0);
pack_palette_tokens(w, tok, palette_size_plane,
num_palette_indexes);
}
#endif // CONFIG_PALETTE && CONFIG_PALETTE_THROUGHPUT
pack_mb_tokens(w, tok, tok_end, cm->bit_depth, tx, &token_stats);
}
}
}
#else
TX_SIZE tx =
plane ? get_uv_tx_size(&m->mbmi, &xd->plane[plane]) : m->mbmi.tx_size;
TOKEN_STATS token_stats;
#if CONFIG_PALETTE && CONFIG_PALETTE_THROUGHPUT
const struct macroblockd_plane *const pd = &xd->plane[plane];
BLOCK_SIZE bsize = mbmi->sb_type;
#if CONFIG_CB4X4
const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, pd);
#else
const BLOCK_SIZE plane_bsize =
get_plane_block_size(AOMMAX(bsize, BLOCK_8X8), pd);
#endif
const int num_4x4_w =
block_size_wide[plane_bsize] >> tx_size_wide_log2[0];
const int num_4x4_h =
block_size_high[plane_bsize] >> tx_size_wide_log2[0];
int row, col;
const int bkw = tx_size_wide_unit[tx];
const int bkh = tx_size_high_unit[tx];
const uint8_t palette_size_plane =
m->mbmi.palette_mode_info.palette_size[plane > 0];
const int bkw_in_pixel = bkw << tx_size_wide_log2[0];
const int bkh_in_pixel = bkh << tx_size_wide_log2[0];
int rows, cols;
av1_get_block_dimensions(m->mbmi.sb_type, plane, xd, NULL, NULL, &rows,
&cols);
for (row = 0; row < num_4x4_h; row += bkh) {
for (col = 0; col < num_4x4_w; col += bkw) {
if (!is_inter_block(mbmi) && palette_size_plane > 0 && plane <= 1) {
const int col_in_pixel = col << tx_size_wide_log2[0];
const int row_in_pixel = row << tx_size_high_log2[0];
const int txbkw = AOMMIN(cols - col_in_pixel, bkw_in_pixel);
const int txbkh = AOMMIN(rows - row_in_pixel, bkh_in_pixel);
// first palette index is not coded here but in header instead
const int num_palette_indexes =
txbkw * txbkh - ((row == 0 && col == 0) ? 1 : 0);
pack_palette_tokens(w, tok, palette_size_plane,
num_palette_indexes);
}
pack_mb_tokens(w, tok, tok_end, cm->bit_depth, tx, &token_stats);
}
}
#else
init_token_stats(&token_stats);
pack_mb_tokens(w, tok, tok_end, cm->bit_depth, tx, &token_stats);
#endif // CONFIG_PALETTE && CONFIG_PALETTE_THROUGHPUT
#if CONFIG_RD_DEBUG
if (is_inter_block(mbmi) && mbmi->sb_type >= BLOCK_8X8 &&
rd_token_stats_mismatch(&m->mbmi.rd_stats, &token_stats, plane)) {
......
......@@ -5656,9 +5656,11 @@ static void encode_superblock(const AV1_COMP *const cpi, ThreadData *td,
if (mbmi->palette_mode_info.palette_size[plane] > 0) {
mbmi->palette_mode_info.palette_first_color_idx[plane] =
xd->plane[plane].color_index_map[0];
// TODO(huisu): this increases the use of token buffer. Needs stretch
// test to verify.
// TODO(huisu): this increases the use of token buffer. Needs stretch
// test to verify.
#if !CONFIG_PALETTE_THROUGHPUT
av1_tokenize_palette_sb(cpi, td, plane, t, dry_run, bsize, rate);
#endif
}
}
}
......
......@@ -399,7 +399,7 @@ static INLINE int get_tx_eob(const struct segmentation *seg, int segment_id,
#endif
#endif // !CONFIG_PVQ
#if CONFIG_PALETTE
#if CONFIG_PALETTE && !CONFIG_PALETTE_THROUGHPUT
void av1_tokenize_palette_sb(const AV1_COMP *cpi,
const struct ThreadData *const td, int plane,
TOKENEXTRA **t, RUN_TYPE dry_run, BLOCK_SIZE bsize,
......@@ -442,6 +442,71 @@ void av1_tokenize_palette_sb(const AV1_COMP *cpi,
#endif // CONFIG_PALETTE
#if !CONFIG_PVQ
#if CONFIG_PALETTE && CONFIG_PALETTE_THROUGHPUT
void tokenize_palette_b(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;
ThreadData *const td = args->td;
MACROBLOCK *const x = &td->mb;
MACROBLOCKD *const xd = &x->e_mbd;
struct macroblockd_plane *pd = &xd->plane[plane];
TOKENEXTRA **t = args->tp;
MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
const uint8_t *const color_map = xd->plane[plane].color_index_map;
const PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info;
const int n = pmi->palette_size[plane];
int i, j;
uint8_t color_order[PALETTE_MAX_SIZE];
const aom_prob(
*const probs)[PALETTE_COLOR_INDEX_CONTEXTS][PALETTE_COLORS - 1] =
plane == 0 ? av1_default_palette_y_color_index_prob
: av1_default_palette_uv_color_index_prob;
int bsize = txsize_to_bsize[tx_size];
int plane_block_width, plane_block_height, rows, cols;
int block_width, block_height, tx_block_width, tx_block_height;
(void)block;
if (n == 0) return;
plane_block_width = block_size_wide[plane_bsize];
plane_block_height = block_size_high[plane_bsize];
rows = (xd->mb_to_bottom_edge >= 0)
? plane_block_height
: (xd->mb_to_bottom_edge >> (3 + pd->subsampling_y)) +
plane_block_height;
cols = (xd->mb_to_right_edge >= 0)
? plane_block_width
: (xd->mb_to_right_edge >> (3 + pd->subsampling_x)) +
plane_block_width;
assert(plane_block_width >= cols);
assert(plane_block_height >= rows);
tx_block_width = 1 << tx_size_wide_log2[0];
tx_block_height = 1 << tx_size_high_log2[0];
block_width = AOMMIN(cols - blk_col * tx_block_width, block_size_wide[bsize]);
block_height =
AOMMIN(rows - blk_row * tx_block_height, block_size_high[bsize]);
assert(plane == 0 || plane == 1);
// run wavefront on the palette map index encoding per transform block
for (i = ((blk_row == 0 && blk_col == 0) ? 1 : 0);
i < block_width + block_height - 1; ++i) {
for (j = AOMMIN(i, block_width - 1); j >= AOMMAX(0, i - block_height + 1);
--j) {
int color_new_idx;
const int color_ctx = av1_get_palette_color_index_context(
color_map, plane_block_width, blk_row * tx_block_width + (i - j),
blk_col * tx_block_height + j, n, color_order, &color_new_idx);
assert(color_new_idx >= 0 && color_new_idx < n);
(*t)->token = color_new_idx;
(*t)->context_tree = probs[n - 2][color_ctx];
(*t)->skip_eob_node = 0;
++(*t);
}
}
}
#endif // CONFIG_PALETTE && CONFIG_PALETTE_THROUGHPUT
static void tokenize_b(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;
......@@ -599,6 +664,16 @@ static void tokenize_b(int plane, int block, int blk_row, int blk_col,
av1_set_contexts(xd, pd, plane, tx_size, c > 0, blk_col, blk_row);
}
#if CONFIG_PALETTE && CONFIG_PALETTE_THROUGHPUT
void tokenize_joint_b(int plane, int block, int blk_row, int blk_col,
BLOCK_SIZE plane_bsize, TX_SIZE tx_size, void *arg) {
if (plane < 2)
tokenize_palette_b(plane, block, blk_row, blk_col, plane_bsize, tx_size,
arg);
tokenize_b(plane, block, blk_row, blk_col, plane_bsize, tx_size, arg);
}
#endif // CONFIG_PALETTE && CONFIG_PALETTE_THROUGHPUT
#endif // !CONFIG_PVQ
struct is_skippable_args {
......@@ -803,6 +878,15 @@ void av1_tokenize_sb(const AV1_COMP *cpi, ThreadData *td, TOKENEXTRA **t,
!segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP);
struct tokenize_b_args arg = { cpi, td, t, 0 };
if (mbmi->skip) {
#if CONFIG_PALETTE && CONFIG_PALETTE_THROUGHPUT
if (!dry_run) {
int plane;
for (plane = 0; plane < 2; ++plane) {
av1_foreach_transformed_block_in_plane(xd, bsize, plane,
tokenize_palette_b, &arg);
}
}
#endif // CONFIG_PALETTE && CONFIG_PALETTE_THROUGHPUT
if (!dry_run) td->counts->skip[ctx][1] += skip_inc;
reset_skip_context(xd, bsize);
return;
......@@ -812,7 +896,12 @@ void av1_tokenize_sb(const AV1_COMP *cpi, ThreadData *td, TOKENEXTRA **t,
if (!dry_run) {
#if CONFIG_COEF_INTERLEAVE
td->counts->skip[ctx][0] += skip_inc;
#if CONFIG_PALETTE && CONFIG_PALETTE_THROUGHPUT
av1_foreach_transformed_block_in_plane(xd, bsize, plane, tokenize_joint_b,
&arg);
#else
av1_foreach_transformed_block_interleave(xd, bsize, tokenize_b, &arg);
#endif // CONFIG_PALETTE && CONFIG_PALETTE_THROUGHPUT
#else
int plane;
......@@ -828,8 +917,13 @@ void av1_tokenize_sb(const AV1_COMP *cpi, ThreadData *td, TOKENEXTRA **t,
(void)mi_row;
(void)mi_col;
#endif
#if CONFIG_PALETTE && CONFIG_PALETTE_THROUGHPUT
av1_foreach_transformed_block_in_plane(xd, bsize, plane, tokenize_joint_b,
&arg);
#else
av1_foreach_transformed_block_in_plane(xd, bsize, plane, tokenize_b,
&arg);
#endif // CONFIG_PALETTE && CONFIG_PALETTE_THROUGHPUT
(*t)->token = EOSB_TOKEN;
(*t)++;
}
......
......@@ -75,10 +75,15 @@ void av1_tokenize_sb_vartx(const struct AV1_COMP *cpi, struct ThreadData *td,
int mi_col, BLOCK_SIZE bsize, int *rate);
#endif
#if CONFIG_PALETTE
#if CONFIG_PALETTE_THROUGHPUT
void tokenize_palette_b(int plane, int block, int blk_row, int blk_col,
BLOCK_SIZE plane_bsize, TX_SIZE tx_size, void *arg);
#else
void av1_tokenize_palette_sb(const struct AV1_COMP *cpi,
const struct ThreadData *const td, int plane,
TOKENEXTRA **t, RUN_TYPE dry_run, BLOCK_SIZE bsize,
int *rate);
#endif // CONFIG_PALETTE_THROUGHPUT
#endif // CONFIG_PALETTE
void av1_tokenize_sb(const struct AV1_COMP *cpi, struct ThreadData *td,
TOKENEXTRA **t, RUN_TYPE dry_run, BLOCK_SIZE bsize,
......
......@@ -307,6 +307,7 @@ EXPERIMENT_LIST="
dependent_horztiles
daala_dist
tripred
palette_throughput
ref_adapt
"
CONFIG_LIST="
......@@ -492,6 +493,7 @@ post_process_cmdline() {
enabled new_tokenset && enable_feature ec_multisymbol
enabled ec_multisymbol && ! enabled ans && soft_enable daala_ec
enabled ec_multisymbol && ! enabled daala_ec && soft_enable ans
enabled palette_throughput && soft_enable palette
if enabled rawbits && ! enabled daala_ec; then
log_echo "rawbits requires daala_ec, so disabling rawbits"
disable_feature rawbits
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment