Commit 7bb501d5 authored by Lei's avatar Lei Committed by Ryan Lei

add new experiment loopfiltering_across_tiles_ext

based on the latest discussion in the HW working group about how loop
filter should be integrated with tiles, the following decisions have been
made:
1. two seperated flages should be added for
loop_filter_across_tiles_enabled for horizontal tile boundary and
vertical tile boundary.
2. encoder and decoder should only check these two flags to determine
whether loop filtering (including deblocking, CDEF and loop restoration)
should cross tile boundaries (vertical and/or horizontal) or not
regardless the horitontal depepdent tile flag.

This change list implemented the support for two seperated
loop_filter_across_tiles_enabled flags for vertical and horizontal tile
boundaries. The new experiment is disabled as default before it is
adopted.

Change-Id: I814377947517f5419c08b004a3b71b950d01eadd
parent f263044f
......@@ -553,6 +553,21 @@ enum aome_enc_control_id {
*/
AV1E_SET_DISABLE_TEMPMV,
/*!\brief Codec control function to set loop_filter_across_tiles_v_enabled
* and loop_filter_across_tiles_h_enabled.
* In encoding and decoding, AV1 allows disabling loop filter across tile
* boundary The parameter for this control describes the value of this flag,
* which has a valid range [0, 1]:
* 0 = disable loop filter across tile boundary
* 1 = enable loop filter across tile boundary
*
* By default, the value is 1, i.e. enable loop filter across tile boundary.
*
* Experiment: LOOPFILTERING_ACROSS_TILES_EXT
*/
AV1E_SET_TILE_LOOPFILTER_V,
AV1E_SET_TILE_LOOPFILTER_H,
/*!\brief Codec control function to set loop_filter_across_tiles_enabled.
*
* In encoding and decoding, AV1 allows disabling loop filter across tile
......@@ -726,6 +741,10 @@ AOM_CTRL_USE_TYPE(AV1E_SET_TILE_ROWS, int)
AOM_CTRL_USE_TYPE(AV1E_SET_TILE_DEPENDENT_ROWS, int)
#define AOM_CTRL_AV1E_SET_TILE_DEPENDENT_ROWS
AOM_CTRL_USE_TYPE(AV1E_SET_TILE_LOOPFILTER_V, int)
#define AOM_CTRL_AV1E_SET_TILE_LOOPFILTER_V
AOM_CTRL_USE_TYPE(AV1E_SET_TILE_LOOPFILTER_H, int)
#define AOM_CTRL_AV1E_SET_TILE_LOOPFILTER_H
AOM_CTRL_USE_TYPE(AV1E_SET_TILE_LOOPFILTER, int)
#define AOM_CTRL_AV1E_SET_TILE_LOOPFILTER
......
......@@ -434,8 +434,17 @@ static const arg_def_t tile_dependent_rows =
ARG_DEF(NULL, "tile-dependent-rows", 1, "Enable dependent Tile rows");
#endif
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
static const arg_def_t tile_loopfilter_v =
ARG_DEF(NULL, "tile-loopfilter-v", 1,
"Enable loop filter across vertical tile boundary");
static const arg_def_t tile_loopfilter_h =
ARG_DEF(NULL, "tile-loopfilter-h", 1,
"Enable loop filter across horizontal tile boundary");
#else
static const arg_def_t tile_loopfilter = ARG_DEF(
NULL, "tile-loopfilter", 1, "Enable loop filter across tile boundary");
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES
static const arg_def_t lossless =
ARG_DEF(NULL, "lossless", 1, "Lossless mode (0: false (default), 1: true)");
......@@ -579,7 +588,12 @@ static const arg_def_t *av1_args[] = { &cpu_used_av1,
&tile_dependent_rows,
#endif
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
&tile_loopfilter_v,
&tile_loopfilter_h,
#else
&tile_loopfilter,
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES
&arnr_maxframes,
&arnr_strength,
......@@ -638,7 +652,12 @@ static const int av1_arg_ctrl_map[] = { AOME_SET_CPUUSED,
AV1E_SET_TILE_DEPENDENT_ROWS,
#endif
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
AV1E_SET_TILE_LOOPFILTER_V,
AV1E_SET_TILE_LOOPFILTER_H,
#else
AV1E_SET_TILE_LOOPFILTER,
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES
AOME_SET_ARNR_MAXFRAMES,
AOME_SET_ARNR_STRENGTH,
......
......@@ -43,7 +43,12 @@ struct av1_extracfg {
unsigned int dependent_horz_tiles;
#endif
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
unsigned int loop_filter_across_tiles_v_enabled;
unsigned int loop_filter_across_tiles_h_enabled;
#else
unsigned int loop_filter_across_tiles_enabled;
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES
unsigned int arnr_max_frames;
unsigned int arnr_strength;
......@@ -105,7 +110,12 @@ static struct av1_extracfg default_extra_cfg = {
0, // Dependent Horizontal tiles
#endif
#if CONFIG_LOOPFILTERING_ACROSS_TILES
1, // loop_filter_across_tiles_enabled
#if CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
1, // loop_filter_across_tiles_v_enabled
1, // loop_filter_across_tiles_h_enabled
#else
1, // loop_filter_across_tiles_enabled
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES
7, // arnr_max_frames
5, // arnr_strength
......@@ -324,7 +334,12 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx,
RANGE_CHECK_HI(extra_cfg, dependent_horz_tiles, 1);
#endif
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
RANGE_CHECK_HI(extra_cfg, loop_filter_across_tiles_v_enabled, 1);
RANGE_CHECK_HI(extra_cfg, loop_filter_across_tiles_h_enabled, 1);
#else
RANGE_CHECK_HI(extra_cfg, loop_filter_across_tiles_enabled, 1);
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES
RANGE_CHECK_HI(extra_cfg, sharpness, 7);
RANGE_CHECK_HI(extra_cfg, arnr_max_frames, 15);
......@@ -658,8 +673,15 @@ static aom_codec_err_t set_encoder_config(
extra_cfg->dependent_horz_tiles;
#endif
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
oxcf->loop_filter_across_tiles_v_enabled =
extra_cfg->loop_filter_across_tiles_v_enabled;
oxcf->loop_filter_across_tiles_h_enabled =
extra_cfg->loop_filter_across_tiles_h_enabled;
#else
oxcf->loop_filter_across_tiles_enabled =
extra_cfg->loop_filter_across_tiles_enabled;
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES
oxcf->error_resilient_mode = cfg->g_error_resilient;
oxcf->frame_parallel_decoding_mode = extra_cfg->frame_parallel_decoding_mode;
......@@ -808,6 +830,22 @@ static aom_codec_err_t ctrl_set_tile_dependent_rows(aom_codec_alg_priv_t *ctx,
}
#endif
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
static aom_codec_err_t ctrl_set_tile_loopfilter_v(aom_codec_alg_priv_t *ctx,
va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
extra_cfg.loop_filter_across_tiles_v_enabled =
CAST(AV1E_SET_TILE_LOOPFILTER_V, args);
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_tile_loopfilter_h(aom_codec_alg_priv_t *ctx,
va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
extra_cfg.loop_filter_across_tiles_h_enabled =
CAST(AV1E_SET_TILE_LOOPFILTER_H, args);
return update_extra_cfg(ctx, &extra_cfg);
}
#else
static aom_codec_err_t ctrl_set_tile_loopfilter(aom_codec_alg_priv_t *ctx,
va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
......@@ -815,6 +853,7 @@ static aom_codec_err_t ctrl_set_tile_loopfilter(aom_codec_alg_priv_t *ctx,
CAST(AV1E_SET_TILE_LOOPFILTER, args);
return update_extra_cfg(ctx, &extra_cfg);
}
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES
static aom_codec_err_t ctrl_set_arnr_max_frames(aom_codec_alg_priv_t *ctx,
......@@ -1593,7 +1632,12 @@ static aom_codec_ctrl_fn_map_t encoder_ctrl_maps[] = {
{ AV1E_SET_TILE_DEPENDENT_ROWS, ctrl_set_tile_dependent_rows },
#endif
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
{ AV1E_SET_TILE_LOOPFILTER_V, ctrl_set_tile_loopfilter_v },
{ AV1E_SET_TILE_LOOPFILTER_H, ctrl_set_tile_loopfilter_h },
#else
{ AV1E_SET_TILE_LOOPFILTER, ctrl_set_tile_loopfilter },
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES
{ AOME_SET_ARNR_MAXFRAMES, ctrl_set_arnr_max_frames },
{ AOME_SET_ARNR_STRENGTH, ctrl_set_arnr_strength },
......
......@@ -1018,7 +1018,7 @@ static void build_y_mask(AV1_COMMON *const cm,
*int_4x4_y |= (size_mask[block_size] & 0xffffffffffffffffULL) << shift_y;
}
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES || CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
// This function update the bit masks for the entire 64x64 region represented
// by mi_row, mi_col. In case one of the edge is a tile boundary, loop filtering
// for that edge is disabled. This function only check the tile boundary info
......@@ -1281,7 +1281,7 @@ void av1_setup_mask(AV1_COMMON *const cm, const int mi_row, const int mi_col,
}
}
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES || CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
if (av1_disable_loopfilter_on_tile_boundary(cm)) {
update_tile_boundary_filter_mask(cm, mi_row, mi_col, lfm);
}
......@@ -1595,7 +1595,7 @@ void av1_filter_block_plane_non420_ver(AV1_COMMON *const cm,
// Disable filtering on the leftmost column or tile boundary
unsigned int border_mask = ~(mi_col == 0 ? 1 : 0);
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES || CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
MODE_INFO *const mi = cm->mi + (mi_row + idx_r) * cm->mi_stride + mi_col;
if (av1_disable_loopfilter_on_tile_boundary(cm) &&
((mi->mbmi.boundary_info & TILE_LEFT_BOUNDARY) != 0)) {
......@@ -1643,7 +1643,7 @@ void av1_filter_block_plane_non420_hor(AV1_COMMON *const cm,
&lfl[r][0], &mask_4x4_int, NULL,
&row_masks, NULL);
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES || CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
// Disable filtering on the abovemost row or tile boundary
const MODE_INFO *mi = cm->mi + (mi_row + idx_r) * cm->mi_stride + mi_col;
if ((av1_disable_loopfilter_on_tile_boundary(cm) &&
......@@ -2111,13 +2111,15 @@ static void set_lpf_parameters(
uint32_t level = curr_level;
// prepare outer edge parameters. deblock the edge if it's an edge of a TU
if (coord) {
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES || CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
MODE_INFO *const mi_bound = cm->mi + mi_row * cm->mi_stride + mi_col;
if (!av1_disable_loopfilter_on_tile_boundary(cm) ||
((VERT_EDGE == edge_dir) &&
(0 == (mi_bound->mbmi.boundary_info & TILE_LEFT_BOUNDARY))) ||
((HORZ_EDGE == edge_dir) &&
(0 == (mi_bound->mbmi.boundary_info & TILE_ABOVE_BOUNDARY))))
// here, assuming bounfary_info is set correctly based on the
// loop_filter_across_tiles_enabled flag, i.e, tile boundary should
// only be set to true when this flag is set to 0.
int left_boundary = (mi_bound->mbmi.boundary_info & TILE_LEFT_BOUNDARY);
int top_boundary = (mi_bound->mbmi.boundary_info & TILE_ABOVE_BOUNDARY);
if (((VERT_EDGE == edge_dir) && (0 == left_boundary)) ||
((HORZ_EDGE == edge_dir) && (0 == top_boundary)))
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES
{
const int32_t tu_edge =
......
......@@ -218,23 +218,40 @@ void av1_cdef_frame(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm,
nhb = AOMMIN(MI_SIZE_64X64, cm->mi_cols - MI_SIZE_64X64 * fbc);
nvb = AOMMIN(MI_SIZE_64X64, cm->mi_rows - MI_SIZE_64X64 * fbr);
int tile_top, tile_left, tile_bottom, tile_right;
int mi_idx = MI_SIZE_64X64 * fbr * cm->mi_stride + MI_SIZE_64X64 * fbc;
MODE_INFO *const mi_tl = cm->mi + mi_idx;
int mi_row = MI_SIZE_64X64 * fbr;
int mi_col = MI_SIZE_64X64 * fbc;
int mi_idx_tl = mi_row * cm->mi_stride + mi_col;
int mi_idx_tr = mi_row * cm->mi_stride + (mi_col + MI_SIZE_64X64 - 1);
int mi_idx_bl = (mi_row + MI_SIZE_64X64 - 1) * cm->mi_stride + mi_col;
// for the current filter block, it's top left corner mi structure (mi_tl)
// is first accessed to check whether the top and left boundaries are
// tile boundaries. Then bottom-left and top-right mi structures are
// accessed to check whether the bottom and right boundaries
// (respectively) are tile boundaries.
//
// Note that we can't just check the bottom-right mi structure - eg. if
// we're at the right-hand edge of the frame but not the bottom, then
// the bottom-right mi is NULL but the bottom-left is not.
//
// We assume the boundary information is set correctly based on the
// loop_filter_across_tiles_enabled flag, i.e, if this flag is set to 1,
// then boundary_info should not be treated as tile boundaries. Also
// assume CDEF filter block size is 64x64.
MODE_INFO *const mi_tl = cm->mi + mi_idx_tl;
MODE_INFO *const mi_tr = cm->mi + mi_idx_tr;
MODE_INFO *const mi_bl = cm->mi + mi_idx_bl;
BOUNDARY_TYPE boundary_tl = mi_tl->mbmi.boundary_info;
tile_top = boundary_tl & TILE_ABOVE_BOUNDARY;
tile_left = boundary_tl & TILE_LEFT_BOUNDARY;
if (fbr != nvfb - 1 &&
(&cm->mi[mi_idx + (MI_SIZE_64X64 - 1) * cm->mi_stride]))
tile_bottom = cm->mi[mi_idx + (MI_SIZE_64X64 - 1) * cm->mi_stride]
.mbmi.boundary_info &
TILE_BOTTOM_BOUNDARY;
if (fbr != nvfb - 1 && mi_bl)
tile_bottom = mi_bl->mbmi.boundary_info & TILE_BOTTOM_BOUNDARY;
else
tile_bottom = 1;
if (fbc != nhfb - 1 && (&cm->mi[mi_idx + MI_SIZE_64X64 - 1]))
tile_right = cm->mi[mi_idx + MI_SIZE_64X64 - 1].mbmi.boundary_info &
TILE_RIGHT_BOUNDARY;
if (fbc != nhfb - 1 && mi_tr)
tile_right = mi_tr->mbmi.boundary_info & TILE_RIGHT_BOUNDARY;
else
tile_right = 1;
......
......@@ -495,7 +495,12 @@ typedef struct AV1Common {
int tile_group_start_col[MAX_TILE_ROWS][MAX_TILE_COLS];
#endif
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
int loop_filter_across_tiles_v_enabled;
int loop_filter_across_tiles_h_enabled;
#else
int loop_filter_across_tiles_enabled;
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES
int byte_alignment;
......
......@@ -237,37 +237,25 @@ static void copy_tile(int width, int height, const uint8_t *src, int src_stride,
// Helper function: Save one column of left/right context to the appropriate
// column buffers, then extend the edge of the current tile into that column.
//
// Note: The code to deal with above/below boundaries may have filled out
// the corners of the border with data from the tiles to our left or right,
// which isn't allowed. To fix that up, we need to include the top and
// bottom context regions in the area which we extend.
// But note that we don't need to store the pixels we overwrite in the
// corners of the context area - those have already been overwritten once,
// so their original values are already in rlbs->tmp_save_{above,below}.
#if CONFIG_LOOPFILTERING_ACROSS_TILES
// Note: The height passed in should be the height of this processing unit,
// but we actually save/restore an extra RESTORATION_BORDER pixels above and
// below the stripe.
#if CONFIG_LOOPFILTERING_ACROSS_TILES || CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
static void setup_boundary_column(const uint8_t *src8, int src_stride,
uint8_t *dst8, int dst_stride, uint16_t *buf,
int h, int use_highbd) {
if (use_highbd) {
const uint16_t *src16 = CONVERT_TO_SHORTPTR(src8);
uint16_t *dst16 = CONVERT_TO_SHORTPTR(dst8);
for (int i = -RESTORATION_BORDER; i < 0; i++)
dst16[i * dst_stride] = src16[i * src_stride];
for (int i = 0; i < h; i++) {
buf[i] = dst16[i * dst_stride];
for (int i = -RESTORATION_BORDER; i < h + RESTORATION_BORDER; i++) {
buf[i + RESTORATION_BORDER] = dst16[i * dst_stride];
dst16[i * dst_stride] = src16[i * src_stride];
}
for (int i = h; i < h + RESTORATION_BORDER; i++)
dst16[i * dst_stride] = src16[i * src_stride];
} else {
for (int i = -RESTORATION_BORDER; i < 0; i++)
dst8[i * dst_stride] = src8[i * src_stride];
for (int i = 0; i < h; i++) {
buf[i] = dst8[i * dst_stride];
for (int i = -RESTORATION_BORDER; i < h + RESTORATION_BORDER; i++) {
buf[i + RESTORATION_BORDER] = dst8[i * dst_stride];
dst8[i * dst_stride] = src8[i * src_stride];
}
for (int i = h; i < h + RESTORATION_BORDER; i++)
dst8[i * dst_stride] = src8[i * src_stride];
}
}
......@@ -276,9 +264,11 @@ static void restore_boundary_column(uint8_t *dst8, int dst_stride,
int use_highbd) {
if (use_highbd) {
uint16_t *dst16 = CONVERT_TO_SHORTPTR(dst8);
for (int i = 0; i < h; i++) dst16[i * dst_stride] = buf[i];
for (int i = -RESTORATION_BORDER; i < h + RESTORATION_BORDER; i++)
dst16[i * dst_stride] = buf[i + RESTORATION_BORDER];
} else {
for (int i = 0; i < h; i++) dst8[i * dst_stride] = (uint8_t)(buf[i]);
for (int i = -RESTORATION_BORDER; i < h + RESTORATION_BORDER; i++)
dst8[i * dst_stride] = buf[i + RESTORATION_BORDER];
}
}
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES
......@@ -320,15 +310,23 @@ static void restore_boundary_column(uint8_t *dst8, int dst_stride,
static void get_stripe_boundary_info(const RestorationTileLimits *limits,
const AV1PixelRect *tile_rect, int ss_y,
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
int loop_filter_across_tiles_h_enabled,
#else
int loop_filter_across_tiles_enabled,
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES
int *copy_above, int *copy_below) {
*copy_above = 1;
*copy_below = 1;
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
if (loop_filter_across_tiles_h_enabled) {
#else
if (loop_filter_across_tiles_enabled) {
#endif
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES
const int full_stripe_height = RESTORATION_PROC_UNIT_SIZE >> ss_y;
const int rtile_offset = RESTORATION_TILE_OFFSET >> ss_y;
......@@ -340,7 +338,7 @@ static void get_stripe_boundary_info(const RestorationTileLimits *limits,
if (first_stripe_in_tile) *copy_above = 0;
if (last_stripe_in_tile) *copy_below = 0;
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES || CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
}
#endif
}
......@@ -362,7 +360,11 @@ static void setup_processing_stripe_boundary(
const RestorationTileLimits *limits, const RestorationStripeBoundaries *rsb,
int rsb_row, int use_highbd, int h,
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
const AV1PixelRect *tile_rect, int loop_filter_across_tiles_v_enabled,
#else
const AV1PixelRect *tile_rect, int loop_filter_across_tiles_enabled,
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES
uint8_t *data8, int data_stride, RestorationLineBuffers *rlbs,
int copy_above, int copy_below) {
......@@ -425,7 +427,8 @@ static void setup_processing_stripe_boundary(
}
#if CONFIG_LOOPFILTERING_ACROSS_TILES
if (!loop_filter_across_tiles_enabled) {
#if CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
if (!loop_filter_across_tiles_v_enabled) {
// If loopfiltering across tiles is disabled, we need to check if we're at
// the edge of the current tile column. If we are, we need to extend the
// leftmost/rightmost column within the tile by 3 pixels, so that the output
......@@ -450,16 +453,55 @@ static void setup_processing_stripe_boundary(
rlbs->tmp_save_right[j], h, use_highbd);
}
}
#else
if (!loop_filter_across_tiles_enabled) {
// If loopfiltering across tiles is disabled, we need to extend tile edges
// by 3 pixels, to ensure that we don't sample from the tiles to our left
// or right.
const int at_tile_left_border = (limits->h_start == tile_rect->left);
const int at_tile_right_border = (limits->h_end == tile_rect->right);
if (at_tile_left_border) {
uint8_t *dst8 = data8 + limits->h_start + limits->v_start * data_stride;
for (int j = -RESTORATION_BORDER; j < 0; j++)
setup_boundary_column(dst8, data_stride, dst8 + j, data_stride,
rlbs->tmp_save_left[j + RESTORATION_BORDER], h,
use_highbd);
}
if (at_tile_right_border) {
uint8_t *dst8 = data8 + limits->h_end + limits->v_start * data_stride;
for (int j = 0; j < RESTORATION_BORDER; j++)
setup_boundary_column(dst8 - 1, data_stride, dst8 + j, data_stride,
rlbs->tmp_save_right[j], h, use_highbd);
}
}
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES
}
// This function restores the boundary lines modified by
// setup_processing_stripe_boundary.
//
// Note: We need to be careful when handling the corners of the processing
// unit, because (eg.) the top-left corner is considered to be part of
// both the left and top borders. This means that, depending on the
// loop_filter_across_tiles_enabled flag, the corner pixels might get
// overwritten twice, once as part of the "top" border and once as part
// of the "left" border (or similar for other corners).
//
// Everything works out fine as long as we make sure to reverse the order
// when restoring, ie. we need to restore the left/right borders followed
// by the top/bottom borders.
static void restore_processing_stripe_boundary(
const RestorationTileLimits *limits, const RestorationLineBuffers *rlbs,
int use_highbd, int h,
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
const AV1PixelRect *tile_rect, int loop_filter_across_tiles_v_enabled,
#else
const AV1PixelRect *tile_rect, int loop_filter_across_tiles_enabled,
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES
uint8_t *data8, int data_stride, int copy_above, int copy_below) {
assert(CONFIG_HIGHBITDEPTH || !use_highbd);
......@@ -470,35 +512,33 @@ static void restore_processing_stripe_boundary(
const int data_x0 = limits->h_start - RESTORATION_EXTRA_HORZ;
if (copy_above) {
uint8_t *data8_tl = data8 + data_x0 + limits->v_start * data_stride;
for (int i = -RESTORATION_BORDER; i < 0; ++i) {
uint8_t *dst8 = data8_tl + i * data_stride;
memcpy(REAL_PTR(use_highbd, dst8),
rlbs->tmp_save_above[i + RESTORATION_BORDER], line_size);
}
}
if (copy_below) {
const int stripe_bottom = limits->v_start + h;
uint8_t *data8_bl = data8 + data_x0 + stripe_bottom * data_stride;
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#if CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
if (!loop_filter_across_tiles_v_enabled) {
// Restore any pixels we overwrote at the left/right edge of this
// processing unit.
const int at_tile_left_border = (limits->h_start == tile_rect->left);
const int at_tile_right_border = (limits->h_end == tile_rect->right);
for (int i = 0; i < RESTORATION_BORDER; ++i) {
if (stripe_bottom + i >= limits->v_end + RESTORATION_BORDER) break;
if (at_tile_left_border) {
uint8_t *dst8 = data8 + limits->h_start + limits->v_start * data_stride;
for (int j = -RESTORATION_BORDER; j < 0; j++)
restore_boundary_column(dst8 + j, data_stride,
rlbs->tmp_save_left[j + RESTORATION_BORDER], h,
use_highbd);
}
uint8_t *dst8 = data8_bl + i * data_stride;
memcpy(REAL_PTR(use_highbd, dst8), rlbs->tmp_save_below[i], line_size);
if (at_tile_right_border) {
uint8_t *dst8 = data8 + limits->h_end + limits->v_start * data_stride;
for (int j = 0; j < RESTORATION_BORDER; j++)
restore_boundary_column(dst8 + j, data_stride, rlbs->tmp_save_right[j],
h, use_highbd);
}
}
#if CONFIG_LOOPFILTERING_ACROSS_TILES
#else
if (!loop_filter_across_tiles_enabled) {
// Restore any pixels we overwrote at the left/right edge of this
// processing unit
// Note: We don't need to restore the corner pixels, even if we overwrote
// them in the equivalent place in setup_processing_stripe_boundary:
// Because !loop_filter_across_tiles_enabled => copy_above = copy_below = 1,
// the corner pixels will already have been restored before we get here.
// processing unit.
const int at_tile_left_border = (limits->h_start == tile_rect->left);
const int at_tile_right_border = (limits->h_end == tile_rect->right);
......@@ -517,7 +557,29 @@ static void restore_processing_stripe_boundary(
h, use_highbd);
}
}
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES_EXT
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES
if (copy_above) {
uint8_t *data8_tl = data8 + data_x0 + limits->v_start * data_stride;
for (int i = -RESTORATION_BORDER; i < 0; ++i) {
uint8_t *dst8 = data8_tl + i * data_stride;
memcpy(REAL_PTR(use_highbd, dst8),
rlbs->tmp_save_above[i + RESTORATION_BORDER], line_size);
}
}
if (copy_below) {
const int stripe_bottom = limits->v_start + h;
uint8_t *data8_bl = data8 + data_x0 + stripe_bottom * data_stride;
for (int i = 0; i < RESTORATION_BORDER; ++i) {
if (stripe_bottom + i >= limits->v_end + RESTORATION_BORDER) break;
uint8_t *dst8 = data8_bl + i * data_stride;
memcpy(REAL_PTR(use_highbd, dst8), rlbs->tmp_save_below[i], line_size);
}
}
}
#endif
......@@ -931,11 +993,56 @@ const int32_t x_by_xplus1[256] = {
};
const int32_t one_by_x[MAX_NELEM] = {
4096, 2048, 1365, 1024, 819, 683, 585, 512, 455, 410, 372, 341, 315,
293, 273, 256, 241, 228, 216, 205, 195, 186, 178, 171, 164,
4096,
2048,
1365,
1024,
819,
683,
585,
512,
455,
410,
372,
341,
315,
293,
273,
256,
241,
228,
216,
205,
195,
186,
178,
171,
164,
#if MAX_RADIUS > 2
158, 152, 146, 141, 137, 132, 128, 124, 120, 117, 114, 111, 108,
105, 102, 100, 98, 95, 93, 91, 89, 87, 85, 84
158,
152,
146,
141,
137,
132,
128,
124,
120,
117,
114,
111,
108,
105,
102,
100,
98,
95,
93,
91,
89,
87,
85,
84
#endif // MAX_RADIUS > 2
};