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
diff --git a/av1/common/blockd.c b/av1/common/blockd.c
index 526d237..3b434be 100644
--- a/av1/common/blockd.c
+++ b/av1/common/blockd.c
@@ -41,6 +41,8 @@
}
#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) {
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index cdbbdcd..c563c80 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -508,7 +508,10 @@
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 @@
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 @@
#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 @@
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;
diff --git a/av1/decoder/detokenize.c b/av1/decoder/detokenize.c
index 4c1408d..bbdc7ad 100644
--- a/av1/decoder/detokenize.c
+++ b/av1/decoder/detokenize.c
@@ -442,6 +442,70 @@
#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 @@
color_map + (rows - 1) * plane_block_width, plane_block_width);
}
}
+#endif // CONFIG_PALETTE_THROUGHPUT
#endif // CONFIG_PALETTE
#if !CONFIG_PVQ
diff --git a/av1/decoder/detokenize.h b/av1/decoder/detokenize.h
index 0574ccc..5a0c7bb 100644
--- a/av1/decoder/detokenize.h
+++ b/av1/decoder/detokenize.h
@@ -25,7 +25,13 @@
#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
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index d788276..7aa459e 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -783,7 +783,7 @@
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 @@
}
++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 @@
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 @@
}
++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 @@
#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 @@
#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 @@
: 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)) {
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index d67d749..8421237 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -5656,9 +5656,11 @@
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
}
}
}
diff --git a/av1/encoder/tokenize.c b/av1/encoder/tokenize.c
index 67aab66..158f795 100644
--- a/av1/encoder/tokenize.c
+++ b/av1/encoder/tokenize.c
@@ -399,7 +399,7 @@
#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 @@
#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 @@
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 @@
!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 @@
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)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)++;
}
diff --git a/av1/encoder/tokenize.h b/av1/encoder/tokenize.h
index 75b3f90..423cc45 100644
--- a/av1/encoder/tokenize.h
+++ b/av1/encoder/tokenize.h
@@ -75,10 +75,15 @@
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,
diff --git a/configure b/configure
index 3051733..f3a706e 100755
--- a/configure
+++ b/configure
@@ -307,6 +307,7 @@
dependent_horztiles
daala_dist
tripred
+ palette_throughput
ref_adapt
"
CONFIG_LIST="
@@ -492,6 +493,7 @@
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