Commit f190a165 authored by Yi Luo's avatar Yi Luo

Refactor av1_update_boundary_info function

- Split av1_update_boundary_info() into two functions to avoid
  unnecessarily checking which goes through each mi block.
- av1_setup_frame_boundary_info() sets up frame level boundary,
  i.e. non-tile case, which is called in frame level only.
- av1_setup_across_tile_boundary_info sets up tiles boundary,
  which is called per tile, in multiple tile case.
- Decoder running time reduction: 8.72% (1080p, 25 frames, 4Mbps).

Change-Id: I2fc42d4281c77bce4a7dab5d208347308cfbe579
parent 97ad058e
......@@ -75,64 +75,82 @@ void av1_get_tile_n_bits(int mi_cols, int *min_log2_tile_cols,
assert(*min_log2_tile_cols <= *max_log2_tile_cols);
}
void av1_update_boundary_info(const struct AV1Common *cm,
const TileInfo *const tile_info, int mi_row,
int mi_col) {
int row, col;
for (row = mi_row; ((row < (mi_row + cm->mib_size)) && (row < cm->mi_rows));
row++)
for (col = mi_col; ((col < (mi_col + cm->mib_size)) && (col < cm->mi_cols));
col++) {
MODE_INFO *const mi = cm->mi + row * cm->mi_stride + col;
mi->mbmi.boundary_info = 0;
// If horizontal dependent tile is enabled, then the horizontal
// tile boundary is not treated as real tile boundary for loop
// filtering, only the horizontal tile group boundary is treated
// as tile boundary.
// Otherwise, tile group boundary is treated the same as tile boundary.
// Loop filtering operation is done based on the
// loopfilter_across_tiles_enabled flag for both tile boundary and tile
// group boundary.
// the tile boundary flag is updated only when
// loopfilter_across_tiles_enabled value is 0.
int lpf_across_tiles_enabled = 1;
void av1_setup_frame_boundary_info(const AV1_COMMON *const cm) {
MODE_INFO *mi = cm->mi;
int col;
for (col = 0; col < cm->mi_cols; ++col) {
mi->mbmi.boundary_info |= FRAME_ABOVE_BOUNDARY | TILE_ABOVE_BOUNDARY;
mi += 1;
}
mi = cm->mi;
int row;
for (row = 0; row < cm->mi_rows; ++row) {
mi->mbmi.boundary_info |= FRAME_LEFT_BOUNDARY | TILE_LEFT_BOUNDARY;
mi += cm->mi_stride;
}
mi = cm->mi + (cm->mi_rows - 1) * cm->mi_stride;
for (col = 0; col < cm->mi_cols; ++col) {
mi->mbmi.boundary_info |= FRAME_BOTTOM_BOUNDARY | TILE_BOTTOM_BOUNDARY;
mi += 1;
}
mi = cm->mi + cm->mi_cols - 1;
for (row = 0; row < cm->mi_rows; ++row) {
mi->mbmi.boundary_info |= FRAME_RIGHT_BOUNDARY | TILE_RIGHT_BOUNDARY;
mi += cm->mi_stride;
}
}
void av1_setup_across_tile_boundary_info(const AV1_COMMON *const cm,
const TileInfo *const tile_info) {
int lpf_across_tiles_enabled = 1;
#if CONFIG_LOOPFILTERING_ACROSS_TILES
lpf_across_tiles_enabled = cm->loop_filter_across_tiles_enabled;
lpf_across_tiles_enabled = cm->loop_filter_across_tiles_enabled;
#endif
if ((cm->tile_cols * cm->tile_rows > 1) && (!lpf_across_tiles_enabled)) {
const int mi_row = tile_info->mi_row_start;
const int mi_col = tile_info->mi_col_start;
MODE_INFO *const mi_start = cm->mi + mi_row * cm->mi_stride + mi_col;
MODE_INFO *mi = 0;
const int row_diff = tile_info->mi_row_end - tile_info->mi_row_start;
const int col_diff = tile_info->mi_col_end - tile_info->mi_col_start;
int row, col;
if ((cm->tile_cols * cm->tile_rows > 1) && (!lpf_across_tiles_enabled)) {
#if CONFIG_DEPENDENT_HORZTILES
#if CONFIG_TILE_GROUPS
if (row == tile_info->mi_row_start &&
(!cm->dependent_horz_tiles || tile_info->tg_horz_boundary))
if (!cm->dependent_horz_tiles || tile_info->tg_horz_boundary)
#else
if (row == tile_info->mi_row_start && !cm->dependent_horz_tiles)
if (!cm->dependent_horz_tiles)
#endif // CONFIG_TILE_GROUPS
#else
if (row == tile_info->mi_row_start)
#endif // CONFIG_DEPENDENT_HORZTILES
mi->mbmi.boundary_info |= TILE_ABOVE_BOUNDARY;
if (col == tile_info->mi_col_start)
mi->mbmi.boundary_info |= TILE_LEFT_BOUNDARY;
if ((row + 1) >= tile_info->mi_row_end)
mi->mbmi.boundary_info |= TILE_BOTTOM_BOUNDARY;
if ((col + 1) >= tile_info->mi_col_end)
mi->mbmi.boundary_info |= TILE_RIGHT_BOUNDARY;
{
mi = mi_start;
for (col = 0; col < col_diff; ++col) {
mi->mbmi.boundary_info |= TILE_ABOVE_BOUNDARY;
mi += 1;
}
// Frame boundary is treated as tile boundary
if (row == 0)
mi->mbmi.boundary_info |= FRAME_ABOVE_BOUNDARY | TILE_ABOVE_BOUNDARY;
if (col == 0)
mi->mbmi.boundary_info |= FRAME_LEFT_BOUNDARY | TILE_LEFT_BOUNDARY;
if ((row + 1) >= cm->mi_rows)
mi->mbmi.boundary_info |= FRAME_BOTTOM_BOUNDARY | TILE_BOTTOM_BOUNDARY;
if ((col + 1) >= cm->mi_cols)
mi->mbmi.boundary_info |= FRAME_RIGHT_BOUNDARY | TILE_RIGHT_BOUNDARY;
}
mi = mi_start;
for (row = 0; row < row_diff; ++row) {
mi->mbmi.boundary_info |= TILE_LEFT_BOUNDARY;
mi += cm->mi_stride;
}
mi = mi_start + (row_diff - 1) * cm->mi_stride;
for (col = 0; col < col_diff; ++col) {
mi->mbmi.boundary_info |= TILE_BOTTOM_BOUNDARY;
mi += 1;
}
mi = mi_start + col_diff - 1;
for (row = 0; row < row_diff; ++row) {
mi->mbmi.boundary_info |= TILE_RIGHT_BOUNDARY;
mi += cm->mi_stride;
}
}
}
#if CONFIG_LOOPFILTERING_ACROSS_TILES
......
......@@ -44,9 +44,9 @@ void av1_tile_set_tg_boundary(TileInfo *tile, const struct AV1Common *const cm,
void av1_get_tile_n_bits(int mi_cols, int *min_log2_tile_cols,
int *max_log2_tile_cols);
void av1_update_boundary_info(const struct AV1Common *cm,
const TileInfo *const tile_info, int mi_row,
int mi_col);
void av1_setup_frame_boundary_info(const struct AV1Common *const cm);
void av1_setup_across_tile_boundary_info(const struct AV1Common *const cm,
const TileInfo *const tile_info);
#if CONFIG_LOOPFILTERING_ACROSS_TILES
int av1_disable_loopfilter_on_tile_boundary(const struct AV1Common *cm);
......
......@@ -3863,6 +3863,8 @@ static const uint8_t *decode_tiles(AV1Decoder *pbi, const uint8_t *data,
av1_zero_above_context(cm, tile_info.mi_col_start, tile_info.mi_col_end);
#endif
av1_setup_across_tile_boundary_info(cm, &tile_info);
for (mi_row = tile_info.mi_row_start; mi_row < tile_info.mi_row_end;
mi_row += cm->mib_size) {
int mi_col;
......@@ -3871,7 +3873,6 @@ static const uint8_t *decode_tiles(AV1Decoder *pbi, const uint8_t *data,
for (mi_col = tile_info.mi_col_start; mi_col < tile_info.mi_col_end;
mi_col += cm->mib_size) {
av1_update_boundary_info(cm, &tile_info, mi_row, mi_col);
decode_partition(pbi, &td->xd,
#if CONFIG_SUPERTX
0,
......@@ -4178,6 +4179,9 @@ static const uint8_t *decode_tiles_mt(AV1Decoder *pbi, const uint8_t *data,
av1_zero(twd->dqcoeff);
av1_tile_init(tile_info, cm, tile_row, buf->col);
av1_tile_init(&twd->xd.tile, cm, tile_row, buf->col);
av1_setup_across_tile_boundary_info(cm, tile_info);
setup_bool_decoder(buf->data, data_end, buf->size, &cm->error,
&twd->bit_reader,
#if CONFIG_ANS && ANS_MAX_SYMBOLS
......@@ -5369,6 +5373,8 @@ void av1_decode_frame(AV1Decoder *pbi, const uint8_t *data,
av1_frameworker_unlock_stats(worker);
}
av1_setup_frame_boundary_info(cm);
if (pbi->max_threads > 1 && !CONFIG_CB4X4 &&
#if CONFIG_EXT_TILE
pbi->dec_tile_col < 0 && // Decoding all columns
......
......@@ -4503,8 +4503,6 @@ static void encode_rd_sb_row(AV1_COMP *cpi, ThreadData *td,
MODE_INFO **mi = cm->mi_grid_visible + idx_str;
PC_TREE *const pc_root = td->pc_root[cm->mib_size_log2 - MIN_MIB_SIZE_LOG2];
av1_update_boundary_info(cm, tile_info, mi_row, mi_col);
if (sf->adaptive_pred_interp_filter) {
for (i = 0; i < leaf_nodes; ++i)
td->leaf_tree[i].pred_interp_filter = SWITCHABLE;
......@@ -4878,6 +4876,8 @@ void av1_encode_tile(AV1_COMP *cpi, ThreadData *td, int tile_row,
td->mb.daala_enc.state.adapt = &this_tile->tctx.pvq_context;
#endif // CONFIG_PVQ
av1_setup_across_tile_boundary_info(cm, tile_info);
for (mi_row = tile_info->mi_row_start; mi_row < tile_info->mi_row_end;
mi_row += cm->mib_size) {
encode_rd_sb_row(cpi, td, this_tile, mi_row, &tok);
......@@ -5316,6 +5316,8 @@ static void encode_frame_internal(AV1_COMP *cpi) {
}
#endif
av1_setup_frame_boundary_info(cm);
// If allowed, encoding tiles in parallel with one thread handling one tile.
// TODO(geza.lore): The multi-threaded encoder is not safe with more than
// 1 tile rows, as it uses the single above_context et al arrays from
......
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