Commit 29824a42 authored by Rupert Swarbrick's avatar Rupert Swarbrick Committed by Debargha Mukherjee
Browse files

Refactor and generalise OBMC prediction code

When doing OBMC prediction, the code must iterate over the blocks
above or to the left of the current block. In reconinter.c and
rdopt.c, there are several pieces of code that do this. These all work
in roughly the same way, iterating over the xd->mi array (although
some are written with for loops and others with do/while). To visit
each neighbouring block exactly once, each of these loops used an
"mi_step" variable which was set to the width or height of the
neighbouring block in mi-units and the loop counter got incremented by
mi_step to jump to the next block.

This patch unifies the code slightly (just using for loops) and
simplifies it when the CHROMA_SUB8X8 experiment is enabled. In this
case, chroma information is stored in the bottom right block of each
8x8 pixel region. That is, if a block has width 4 and an even mi_col,
the chroma information we need is actually found in the block
immediately to its right.

The existing code implemented this by bumping the current column or
row counter (usually mi_col_offset or mi_row_offset) and duplicating
the first part of the loop body to do it again with the new
counter. It also had to double mi_step to avoid visiting the next-door
block again.

The new code essentially just uses the "continue" keyword to restart
the loop. There's a little more book-keeping required: we might have
to increment "ilimit", the maximum loop index, to ensure we don't exit
the loop too early.

The result is hopefully easier to read, but it's also more general (in
the CHROMA_SUB8X8 case). The existing code assumed the current block
never had width or height below 8 and thus mi_col and mi_row were
always even. As such, whenever the neighbouring block had a width or
height of 4, we knew that we needed to skip to the next neighbouring
block to get the required chroma information. This version of the code
can deal with the current block being smaller. The main difference is
that it decides whether to skip forward by examining the parity of
(mi_col + i) or (mi_row + i).

This change will be needed for 16x4/4x16 block support.

Change-Id: I39c1bbc00a6e2ad1ac17b8eed3980a8bcc040074
parent d9e0e0be
......@@ -1944,47 +1944,42 @@ void av1_count_overlappable_neighbors(const AV1_COMMON *cm, MACROBLOCKD *xd,
if (!is_motion_variation_allowed_bsize(mbmi->sb_type)) return;
if (xd->up_available) {
const int ilimit = AOMMIN(xd->n8_w, cm->mi_cols - mi_col);
const int cols_remaining = cm->mi_cols - mi_col;
int ilimit = AOMMIN(xd->n8_w, cols_remaining);
for (i = 0; i < ilimit; i += mi_step) {
int mi_row_offset = -1;
int mi_col_offset = i;
MODE_INFO *above_mi =
xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride];
MB_MODE_INFO *above_mbmi = &above_mi->mbmi;
MB_MODE_INFO *above_mbmi = &xd->mi[i - 1 * xd->mi_stride]->mbmi;
mi_step = mi_size_wide[above_mbmi->sb_type];
#if CONFIG_CHROMA_SUB8X8
if (above_mbmi->sb_type < BLOCK_8X8) {
++mi_col_offset;
above_mbmi =
&xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride]->mbmi;
// With chroma-sub8x8, the chroma information is found to the right
// (i.e. with odd mi_col) when blocks are narrower than 8x8. This will
// only make a difference when the block immediately above has width less
// than 8 (which means that mi_step is 1) and when mi_col + i is even. In
// that case, skip that block and start again at the one to its
// right. Bump ilimit if necessary to make sure we actually do the loop
// again.
if (mi_step == 1 && ((mi_col + i) % 2 == 0)) {
ilimit = AOMMIN(AOMMAX(ilimit, i + 1), cols_remaining);
continue;
}
#endif
BLOCK_SIZE above_bsize = AOMMAX(above_mbmi->sb_type, BLOCK_8X8);
mi_step = AOMMIN(xd->n8_w, mi_size_wide[above_bsize]);
if (is_neighbor_overlappable(above_mbmi))
xd->mi[0]->mbmi.overlappable_neighbors[0]++;
}
}
if (xd->left_available) {
const int ilimit = AOMMIN(xd->n8_h, cm->mi_rows - mi_row);
const int rows_remaining = cm->mi_rows - mi_row;
int ilimit = AOMMIN(xd->n8_h, rows_remaining);
for (i = 0; i < ilimit; i += mi_step) {
int mi_row_offset = i;
int mi_col_offset = -1;
MODE_INFO *left_mi =
xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride];
MB_MODE_INFO *left_mbmi = &left_mi->mbmi;
MB_MODE_INFO *left_mbmi = &xd->mi[-1 + i * xd->mi_stride]->mbmi;
mi_step = mi_size_high[left_mbmi->sb_type];
#if CONFIG_CHROMA_SUB8X8
if (left_mbmi->sb_type < BLOCK_8X8) {
++mi_row_offset;
left_mbmi =
&xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride]->mbmi;
// See note above about blocks with width < 8
if (mi_step == 1 && ((mi_row + i) % 2 == 0)) {
ilimit = AOMMIN(AOMMAX(ilimit, i + 1), rows_remaining);
continue;
}
#endif
BLOCK_SIZE left_bsize = AOMMAX(left_mbmi->sb_type, BLOCK_8X8);
mi_step = AOMMIN(xd->n8_h, mi_size_high[left_bsize]);
if (is_neighbor_overlappable(left_mbmi))
xd->mi[0]->mbmi.overlappable_neighbors[1]++;
}
......@@ -2039,38 +2034,36 @@ void av1_build_obmc_inter_prediction(const AV1_COMMON *cm, MACROBLOCKD *xd,
// handle above row
if (xd->up_available) {
const int overlap =
AOMMIN(block_size_high[bsize] >> 1, block_size_high[BLOCK_64X64] >> 1);
const int miw = AOMMIN(xd->n8_w, cm->mi_cols - mi_col);
const int mi_row_offset = -1;
AOMMIN(block_size_high[bsize], block_size_high[BLOCK_64X64]) >> 1;
const int cols_remaining = cm->mi_cols - mi_col;
int ilimit = AOMMIN(xd->n8_w, cols_remaining);
assert(ilimit > 0);
int mi_step;
const int neighbor_limit = max_neighbor_obmc[b_width_log2_lookup[bsize]];
int neighbor_count = 0;
assert(miw > 0);
i = 0;
do { // for each mi in the above row
int mi_col_offset = i;
MB_MODE_INFO *above_mbmi =
&xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride]->mbmi;
for (i = 0; i < ilimit; i += mi_step) {
MB_MODE_INFO *above_mbmi = &xd->mi[i - 1 * xd->mi_stride]->mbmi;
mi_step = mi_size_wide[above_mbmi->sb_type];
#if CONFIG_CHROMA_SUB8X8
if (above_mbmi->sb_type < BLOCK_8X8) {
++mi_col_offset;
above_mbmi =
&xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride]->mbmi;
// With chroma-sub8x8, the chroma information is found to the right
// (i.e. with odd mi_col) when blocks are narrower than 8x8. See
// av1_count_overlappable_neighbors for details.
if (mi_step == 1 && ((mi_col + i) % 2 == 0)) {
ilimit = AOMMIN(AOMMAX(ilimit, i + 1), cols_remaining);
continue;
}
#endif
const BLOCK_SIZE a_bsize = AOMMAX(BLOCK_8X8, above_mbmi->sb_type);
const int above_step =
AOMMIN(mi_size_wide[a_bsize], mi_size_wide[BLOCK_64X64]);
const int mi_step = AOMMIN(xd->n8_w, above_step);
if (is_neighbor_overlappable(above_mbmi)) {
neighbor_count++;
if (neighbor_count > neighbor_limit) break;
const int trunc_width = AOMMIN(xd->n8_w, mi_step);
for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
const struct macroblockd_plane *pd = &xd->plane[plane];
const int bw = (mi_step * MI_SIZE) >> pd->subsampling_x;
const int bw =
AOMMAX((trunc_width * MI_SIZE) >> pd->subsampling_x, 4);
const int bh = overlap >> pd->subsampling_y;
if (skip_u4x4_pred_in_obmc(bsize, pd, 0)) continue;
......@@ -2092,46 +2085,44 @@ void av1_build_obmc_inter_prediction(const AV1_COMMON *cm, MACROBLOCKD *xd,
tmp_stride, mask, bh, bw);
}
}
i += mi_step;
} while (i < miw);
}
}
// handle left column
if (xd->left_available) {
const int overlap =
AOMMIN(block_size_wide[bsize] >> 1, block_size_wide[BLOCK_64X64] >> 1);
const int mih = AOMMIN(xd->n8_h, cm->mi_rows - mi_row);
const int mi_col_offset = -1;
const int rows_remaining = cm->mi_rows - mi_row;
int ilimit = AOMMIN(xd->n8_h, rows_remaining);
assert(ilimit > 0);
int mi_step;
const int neighbor_limit = max_neighbor_obmc[b_height_log2_lookup[bsize]];
int neighbor_count = 0;
assert(mih > 0);
i = 0;
do { // for each mi in the left column
int mi_row_offset = i;
MB_MODE_INFO *left_mbmi =
&xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride]->mbmi;
// for each mi in the left column
for (i = 0; i < ilimit; i += mi_step) {
MB_MODE_INFO *left_mbmi = &xd->mi[-1 + i * xd->mi_stride]->mbmi;
mi_step = mi_size_high[left_mbmi->sb_type];
#if CONFIG_CHROMA_SUB8X8
if (left_mbmi->sb_type < BLOCK_8X8) {
++mi_row_offset;
left_mbmi =
&xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride]->mbmi;
// With chroma-sub8x8, the chroma information is found in the lower half
// (i.e. with odd mi_row) when blocks are shorter than 8x8. See
// av1_count_overlappable_neighbors for details.
if (mi_step == 1 && ((mi_row + i) % 2 == 0)) {
ilimit = AOMMIN(AOMMAX(ilimit, i + 1), rows_remaining);
continue;
}
#endif
const BLOCK_SIZE l_bsize = AOMMAX(BLOCK_8X8, left_mbmi->sb_type);
const int left_step =
AOMMIN(mi_size_high[l_bsize], mi_size_high[BLOCK_64X64]);
const int mi_step = AOMMIN(xd->n8_h, left_step);
if (is_neighbor_overlappable(left_mbmi)) {
neighbor_count++;
if (neighbor_count > neighbor_limit) break;
const int trunc_height = AOMMIN(xd->n8_h, mi_step);
for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
const struct macroblockd_plane *pd = &xd->plane[plane];
const int bw = overlap >> pd->subsampling_x;
const int bh = (mi_step * MI_SIZE) >> pd->subsampling_y;
const int bh =
AOMMAX((trunc_height * MI_SIZE) >> pd->subsampling_y, 4);
if (skip_u4x4_pred_in_obmc(bsize, pd, 1)) continue;
......@@ -2153,8 +2144,7 @@ void av1_build_obmc_inter_prediction(const AV1_COMMON *cm, MACROBLOCKD *xd,
tmp_stride, mask, bh, bw);
}
}
i += mi_step;
} while (i < mih);
}
}
}
......@@ -2189,7 +2179,8 @@ void av1_build_prediction_by_above_preds(const AV1_COMMON *cm, MACROBLOCKD *xd,
const TileInfo *const tile = &xd->tile;
BLOCK_SIZE bsize = xd->mi[0]->mbmi.sb_type;
int i, j, mi_step, ref;
const int ilimit = AOMMIN(xd->n8_w, cm->mi_cols - mi_col);
const int cols_remaining = cm->mi_cols - mi_col;
int ilimit = AOMMIN(xd->n8_w, cols_remaining);
int mb_to_right_edge_base = xd->mb_to_right_edge;
const int neighbor_limit = max_neighbor_obmc[b_width_log2_lookup[bsize]];
int neighbor_count = 0;
......@@ -2198,26 +2189,20 @@ void av1_build_prediction_by_above_preds(const AV1_COMMON *cm, MACROBLOCKD *xd,
xd->mb_to_bottom_edge += xd->n8_h * 32;
for (i = 0; i < ilimit; i += mi_step) {
int mi_row_offset = -1;
int mi_col_offset = i;
int mi_x, mi_y, bw, bh;
MODE_INFO *above_mi = xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride];
MB_MODE_INFO *above_mbmi = &above_mi->mbmi;
MB_MODE_INFO *above_mbmi = &xd->mi[i - 1 * xd->mi_stride]->mbmi;
mi_step = mi_size_wide[above_mbmi->sb_type];
#if CONFIG_CHROMA_SUB8X8
if (above_mbmi->sb_type < BLOCK_8X8) {
++mi_col_offset;
above_mbmi = &xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride]->mbmi;
// See note in av1_count_overlappable_neighbors for how this works
if (mi_step == 1 && ((mi_col + i) % 2 == 0)) {
ilimit = AOMMIN(AOMMAX(ilimit, i + 1), cols_remaining);
continue;
}
#endif
const BLOCK_SIZE a_bsize = AOMMAX(BLOCK_8X8, above_mbmi->sb_type);
MB_MODE_INFO backup_mbmi;
const int above_step =
AOMMIN(mi_size_wide[a_bsize], mi_size_wide[BLOCK_64X64]);
mi_step = AOMMIN(xd->n8_w, above_step);
if (!is_neighbor_overlappable(above_mbmi)) continue;
neighbor_count++;
......@@ -2259,13 +2244,16 @@ void av1_build_prediction_by_above_preds(const AV1_COMMON *cm, MACROBLOCKD *xd,
xd->mb_to_left_edge = -(((mi_col + i) * MI_SIZE) * 8);
xd->mb_to_right_edge =
mb_to_right_edge_base + (xd->n8_w - i - mi_step) * 64;
mb_to_right_edge_base + (xd->n8_w - AOMMIN(i + mi_step, xd->n8_w)) * 64;
mi_x = (mi_col + i) << MI_SIZE_LOG2;
mi_y = mi_row << MI_SIZE_LOG2;
int mi_row_offset = -1;
int mi_col_offset = i;
for (j = 0; j < MAX_MB_PLANE; ++j) {
const struct macroblockd_plane *pd = &xd->plane[j];
bw = (mi_step * MI_SIZE) >> pd->subsampling_x;
bw = AOMMAX((mi_step * MI_SIZE) >> pd->subsampling_x, 4);
bh = AOMMAX((num_4x4_blocks_high_lookup[bsize] * 2) >> pd->subsampling_y,
4);
bh = AOMMIN(bh, block_size_high[BLOCK_64X64] >> (pd->subsampling_y + 1));
......@@ -2294,7 +2282,9 @@ void av1_build_prediction_by_left_preds(const AV1_COMMON *cm, MACROBLOCKD *xd,
const TileInfo *const tile = &xd->tile;
BLOCK_SIZE bsize = xd->mi[0]->mbmi.sb_type;
int i, j, mi_step, ref;
const int ilimit = AOMMIN(xd->n8_h, cm->mi_rows - mi_row);
const int rows_remaining = cm->mi_rows - mi_row;
int ilimit = AOMMIN(xd->n8_h, rows_remaining);
int mb_to_bottom_edge_base = xd->mb_to_bottom_edge;
const int neighbor_limit = max_neighbor_obmc[b_height_log2_lookup[bsize]];
int neighbor_count = 0;
......@@ -2303,24 +2293,19 @@ void av1_build_prediction_by_left_preds(const AV1_COMMON *cm, MACROBLOCKD *xd,
xd->mb_to_right_edge += xd->n8_w * 32;
for (i = 0; i < ilimit; i += mi_step) {
int mi_row_offset = i;
int mi_col_offset = -1;
int mi_x, mi_y, bw, bh;
MODE_INFO *left_mi = xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride];
MB_MODE_INFO *left_mbmi = &left_mi->mbmi;
MB_MODE_INFO *left_mbmi = &xd->mi[-1 + i * xd->mi_stride]->mbmi;
mi_step = mi_size_high[left_mbmi->sb_type];
#if CONFIG_CHROMA_SUB8X8
if (left_mbmi->sb_type < BLOCK_8X8) {
++mi_row_offset;
left_mbmi = &xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride]->mbmi;
// See note in av1_count_overlappable_neighbors for how this works
if (mi_step == 1 && ((mi_row + i) % 2 == 0)) {
ilimit = AOMMIN(AOMMAX(ilimit, i + 1), rows_remaining);
continue;
}
#endif
const BLOCK_SIZE l_bsize = AOMMAX(left_mbmi->sb_type, BLOCK_8X8);
MB_MODE_INFO backup_mbmi;
const int left_step =
AOMMIN(mi_size_high[l_bsize], mi_size_high[BLOCK_64X64]);
mi_step = AOMMIN(xd->n8_h, left_step);
if (!is_neighbor_overlappable(left_mbmi)) continue;
......@@ -2360,17 +2345,20 @@ void av1_build_prediction_by_left_preds(const AV1_COMMON *cm, MACROBLOCKD *xd,
}
xd->mb_to_top_edge = -(((mi_row + i) * MI_SIZE) * 8);
xd->mb_to_bottom_edge =
mb_to_bottom_edge_base + (xd->n8_h - i - mi_step) * 64;
xd->mb_to_bottom_edge = mb_to_bottom_edge_base +
(xd->n8_h - AOMMIN(i + mi_step, xd->n8_h)) * 64;
mi_x = mi_col << MI_SIZE_LOG2;
mi_y = (mi_row + i) << MI_SIZE_LOG2;
int mi_row_offset = i;
int mi_col_offset = -1;
for (j = 0; j < MAX_MB_PLANE; ++j) {
const struct macroblockd_plane *pd = &xd->plane[j];
bw = AOMMAX((num_4x4_blocks_wide_lookup[bsize] * 2) >> pd->subsampling_x,
4);
bw = AOMMIN(bw, block_size_wide[BLOCK_64X64] >> (pd->subsampling_x + 1));
bh = (mi_step << MI_SIZE_LOG2) >> pd->subsampling_y;
bh = AOMMAX((mi_step << MI_SIZE_LOG2) >> pd->subsampling_y, 4);
if (skip_u4x4_pred_in_obmc(bsize, pd, 1)) continue;
build_inter_predictors(cm, xd, j, mi_col_offset, mi_row_offset, 0, bw, bh,
......
......@@ -12516,7 +12516,6 @@ static void calc_target_weighted_pred(const AV1_COMMON *cm, const MACROBLOCK *x,
const int overlap =
AOMMIN(block_size_high[bsize] >> 1, block_size_high[BLOCK_64X64] >> 1);
const int miw = AOMMIN(xd->n8_w, cm->mi_cols - mi_col);
const int mi_row_offset = -1;
const uint8_t *const mask1d = av1_get_obmc_mask(overlap);
const int neighbor_limit = max_neighbor_obmc[b_width_log2_lookup[bsize]];
int neighbor_count = 0;
......@@ -12525,22 +12524,24 @@ static void calc_target_weighted_pred(const AV1_COMMON *cm, const MACROBLOCK *x,
i = 0;
do { // for each mi in the above row
const int mi_col_offset = i;
const MB_MODE_INFO *above_mbmi =
&xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride]->mbmi;
const MB_MODE_INFO *above_mbmi = &xd->mi[i + (-1) * xd->mi_stride]->mbmi;
const int above_width = mi_size_wide[above_mbmi->sb_type];
int above_step = AOMMIN(above_width, mi_size_wide[BLOCK_64X64]);
#if CONFIG_CHROMA_SUB8X8
if (above_mbmi->sb_type < BLOCK_8X8)
above_mbmi =
&xd->mi[mi_col_offset + 1 + mi_row_offset * xd->mi_stride]->mbmi;
// If the block above is narrower than 8x8 and starts at an even column,
// we need to skip right one to get to the block with the correct chroma
// information.
if (above_width == 1 && ((mi_col + i) % 2 == 0)) {
above_mbmi = &xd->mi[i + 1 + (-1) * xd->mi_stride]->mbmi;
above_step = 2;
}
#endif
const BLOCK_SIZE a_bsize = AOMMAX(above_mbmi->sb_type, BLOCK_8X8);
const int above_step =
AOMMIN(mi_size_wide[a_bsize], mi_size_wide[BLOCK_64X64]);
const int mi_step = AOMMIN(xd->n8_w, above_step);
const int neighbor_bw = mi_step * MI_SIZE;
if (is_neighbor_overlappable(above_mbmi)) {
if (!CONFIG_CB4X4 && (a_bsize == BLOCK_4X4 || a_bsize == BLOCK_4X8))
if (!CONFIG_CB4X4 && above_width == mi_size_wide[BLOCK_4X4])
neighbor_count += 2;
else
neighbor_count++;
......@@ -12598,7 +12599,6 @@ static void calc_target_weighted_pred(const AV1_COMMON *cm, const MACROBLOCK *x,
const int overlap =
AOMMIN(block_size_wide[bsize] >> 1, block_size_wide[BLOCK_64X64] >> 1);
const int mih = AOMMIN(xd->n8_h, cm->mi_rows - mi_row);
const int mi_col_offset = -1;
const uint8_t *const mask1d = av1_get_obmc_mask(overlap);
const int neighbor_limit = max_neighbor_obmc[b_height_log2_lookup[bsize]];
int neighbor_count = 0;
......@@ -12607,23 +12607,23 @@ static void calc_target_weighted_pred(const AV1_COMMON *cm, const MACROBLOCK *x,
i = 0;
do { // for each mi in the left column
const int mi_row_offset = i;
MB_MODE_INFO *left_mbmi =
&xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride]->mbmi;
const MB_MODE_INFO *left_mbmi = &xd->mi[-1 + i * xd->mi_stride]->mbmi;
const int left_height = mi_size_high[left_mbmi->sb_type];
int left_step = AOMMIN(left_height, mi_size_high[BLOCK_64X64]);
#if CONFIG_CHROMA_SUB8X8
if (left_mbmi->sb_type < BLOCK_8X8)
left_mbmi =
&xd->mi[mi_col_offset + (mi_row_offset + 1) * xd->mi_stride]->mbmi;
// If the block is shorter than 8x8 and starts on an even row, we need to
// skip down one to get to the block with the correct chroma information.
if (left_height == 1 && ((mi_row + i) % 2 == 0)) {
left_mbmi = &xd->mi[-1 + (i + 1) * xd->mi_stride]->mbmi;
left_step = 2;
}
#endif
const BLOCK_SIZE l_bsize = AOMMAX(left_mbmi->sb_type, BLOCK_8X8);
const int left_step =
AOMMIN(mi_size_high[l_bsize], mi_size_high[BLOCK_64X64]);
const int mi_step = AOMMIN(xd->n8_h, left_step);
const int neighbor_bh = mi_step * MI_SIZE;
if (is_neighbor_overlappable(left_mbmi)) {
if (!CONFIG_CB4X4 && (l_bsize == BLOCK_4X4 || l_bsize == BLOCK_8X4))
if (!CONFIG_CB4X4 && (left_height == mi_size_wide[BLOCK_4X4]))
neighbor_count += 2;
else
neighbor_count++;
......
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