Commit 09b5b168 authored by Rupert Swarbrick's avatar Rupert Swarbrick Committed by Debargha Mukherjee

Encode loop restoration coefficients per tile

This is a baby-step towards encoding the coefficients at the start of
superblocks at the top-left of loop restoration tiles. Note that this
patch causes us to reset "wiener_info" and "sgrproj_info" at each tile
boundary, which will cause a performance drop.

This is necessary because, in order for tiles to be processed in
parallel, we cannot delta-encode coefficients across tile boundaries
if the coefficients are signalled within tiles. We could probably do
better than the current patch by, say, delta-encoding against previous
frames.

This patch also fixes up the costing in pickrst.c to match

Change-Id: I5b8b91d63aaf49627cde40219c31c0ac776dfd38
parent 43fb4f57
......@@ -2743,8 +2743,77 @@ static void read_sgrproj_filter(SgrprojInfo *sgrproj_info,
memcpy(ref_sgrproj_info, sgrproj_info, sizeof(*sgrproj_info));
}
static void decode_restoration_for_tile(AV1_COMMON *cm, aom_reader *rb,
int tile_row, int tile_col,
const int nrtiles_x[2],
const int nrtiles_y[2]) {
for (int p = 0; p < MAX_MB_PLANE; ++p) {
RestorationInfo *rsi = &cm->rst_info[p];
if (rsi->frame_restoration_type == RESTORE_NONE) continue;
const int tile_width =
(p > 0) ? ROUND_POWER_OF_TWO(cm->tile_width, cm->subsampling_x)
: cm->tile_width;
const int tile_height =
(p > 0) ? ROUND_POWER_OF_TWO(cm->tile_height, cm->subsampling_y)
: cm->tile_height;
const int rtile_size = rsi->restoration_tilesize;
const int rtiles_per_tile_x = tile_width * MI_SIZE / rtile_size;
const int rtiles_per_tile_y = tile_height * MI_SIZE / rtile_size;
const int rtile_row0 = rtiles_per_tile_y * tile_row;
const int rtile_row1 =
AOMMIN(rtile_row0 + rtiles_per_tile_y, nrtiles_y[p > 0]);
const int rtile_col0 = rtiles_per_tile_x * tile_col;
const int rtile_col1 =
AOMMIN(rtile_col0 + rtiles_per_tile_x, nrtiles_x[p > 0]);
WienerInfo wiener_info;
SgrprojInfo sgrproj_info;
set_default_wiener(&wiener_info);
set_default_sgrproj(&sgrproj_info);
const int wiener_win = (p > 0) ? WIENER_WIN_CHROMA : WIENER_WIN;
for (int rtile_row = rtile_row0; rtile_row < rtile_row1; ++rtile_row) {
for (int rtile_col = rtile_col0; rtile_col < rtile_col1; ++rtile_col) {
const int rtile_idx = rtile_row * nrtiles_x[p > 0] + rtile_col;
if (rsi->frame_restoration_type == RESTORE_SWITCHABLE) {
assert(p == 0);
rsi->restoration_type[rtile_idx] =
aom_read_tree(rb, av1_switchable_restore_tree,
cm->fc->switchable_restore_prob, ACCT_STR);
if (rsi->restoration_type[rtile_idx] == RESTORE_WIENER) {
read_wiener_filter(wiener_win, &rsi->wiener_info[rtile_idx],
&wiener_info, rb);
} else if (rsi->restoration_type[rtile_idx] == RESTORE_SGRPROJ) {
read_sgrproj_filter(&rsi->sgrproj_info[rtile_idx], &sgrproj_info,
rb);
}
} else if (rsi->frame_restoration_type == RESTORE_WIENER) {
if (aom_read(rb, RESTORE_NONE_WIENER_PROB, ACCT_STR)) {
rsi->restoration_type[rtile_idx] = RESTORE_WIENER;
read_wiener_filter(wiener_win, &rsi->wiener_info[rtile_idx],
&wiener_info, rb);
} else {
rsi->restoration_type[rtile_idx] = RESTORE_NONE;
}
} else if (rsi->frame_restoration_type == RESTORE_SGRPROJ) {
if (aom_read(rb, RESTORE_NONE_SGRPROJ_PROB, ACCT_STR)) {
rsi->restoration_type[rtile_idx] = RESTORE_SGRPROJ;
read_sgrproj_filter(&rsi->sgrproj_info[rtile_idx], &sgrproj_info,
rb);
} else {
rsi->restoration_type[rtile_idx] = RESTORE_NONE;
}
}
}
}
}
}
static void decode_restoration(AV1_COMMON *cm, aom_reader *rb) {
int i, p;
#if CONFIG_FRAME_SUPERRES
const int width = cm->superres_upscaled_width;
const int height = cm->superres_upscaled_height;
......@@ -2752,84 +2821,19 @@ static void decode_restoration(AV1_COMMON *cm, aom_reader *rb) {
const int width = cm->width;
const int height = cm->height;
#endif // CONFIG_FRAME_SUPERRES
SgrprojInfo ref_sgrproj_info;
WienerInfo ref_wiener_info;
set_default_wiener(&ref_wiener_info);
set_default_sgrproj(&ref_sgrproj_info);
const int ntiles =
av1_get_rest_ntiles(width, height, cm->rst_info[0].restoration_tilesize,
NULL, NULL, NULL, NULL);
const int ntiles_uv = av1_get_rest_ntiles(
ROUND_POWER_OF_TWO(width, cm->subsampling_x),
ROUND_POWER_OF_TWO(height, cm->subsampling_y),
cm->rst_info[1].restoration_tilesize, NULL, NULL, NULL, NULL);
RestorationInfo *rsi = &cm->rst_info[0];
if (rsi->frame_restoration_type != RESTORE_NONE) {
if (rsi->frame_restoration_type == RESTORE_SWITCHABLE) {
for (i = 0; i < ntiles; ++i) {
rsi->restoration_type[i] =
aom_read_tree(rb, av1_switchable_restore_tree,
cm->fc->switchable_restore_prob, ACCT_STR);
if (rsi->restoration_type[i] == RESTORE_WIENER) {
read_wiener_filter(WIENER_WIN, &rsi->wiener_info[i], &ref_wiener_info,
rb);
} else if (rsi->restoration_type[i] == RESTORE_SGRPROJ) {
read_sgrproj_filter(&rsi->sgrproj_info[i], &ref_sgrproj_info, rb);
}
}
} else if (rsi->frame_restoration_type == RESTORE_WIENER) {
for (i = 0; i < ntiles; ++i) {
if (aom_read(rb, RESTORE_NONE_WIENER_PROB, ACCT_STR)) {
rsi->restoration_type[i] = RESTORE_WIENER;
read_wiener_filter(WIENER_WIN, &rsi->wiener_info[i], &ref_wiener_info,
rb);
} else {
rsi->restoration_type[i] = RESTORE_NONE;
}
}
} else if (rsi->frame_restoration_type == RESTORE_SGRPROJ) {
for (i = 0; i < ntiles; ++i) {
if (aom_read(rb, RESTORE_NONE_SGRPROJ_PROB, ACCT_STR)) {
rsi->restoration_type[i] = RESTORE_SGRPROJ;
read_sgrproj_filter(&rsi->sgrproj_info[i], &ref_sgrproj_info, rb);
} else {
rsi->restoration_type[i] = RESTORE_NONE;
}
}
}
}
for (p = 1; p < MAX_MB_PLANE; ++p) {
set_default_wiener(&ref_wiener_info);
set_default_sgrproj(&ref_sgrproj_info);
rsi = &cm->rst_info[p];
if (rsi->frame_restoration_type == RESTORE_WIENER) {
for (i = 0; i < ntiles_uv; ++i) {
if (ntiles_uv > 1)
rsi->restoration_type[i] =
aom_read(rb, RESTORE_NONE_WIENER_PROB, ACCT_STR) ? RESTORE_WIENER
: RESTORE_NONE;
else
rsi->restoration_type[i] = RESTORE_WIENER;
if (rsi->restoration_type[i] == RESTORE_WIENER) {
read_wiener_filter(WIENER_WIN_CHROMA, &rsi->wiener_info[i],
&ref_wiener_info, rb);
}
}
} else if (rsi->frame_restoration_type == RESTORE_SGRPROJ) {
for (i = 0; i < ntiles_uv; ++i) {
if (ntiles_uv > 1)
rsi->restoration_type[i] =
aom_read(rb, RESTORE_NONE_SGRPROJ_PROB, ACCT_STR)
? RESTORE_SGRPROJ
: RESTORE_NONE;
else
rsi->restoration_type[i] = RESTORE_SGRPROJ;
if (rsi->restoration_type[i] == RESTORE_SGRPROJ) {
read_sgrproj_filter(&rsi->sgrproj_info[i], &ref_sgrproj_info, rb);
}
}
} else if (rsi->frame_restoration_type != RESTORE_NONE) {
assert(0);
int nrtiles_x[2], nrtiles_y[2];
av1_get_rest_ntiles(width, height, cm->rst_info[0].restoration_tilesize, NULL,
NULL, &nrtiles_x[0], &nrtiles_y[0]);
av1_get_rest_ntiles(ROUND_POWER_OF_TWO(width, cm->subsampling_x),
ROUND_POWER_OF_TWO(height, cm->subsampling_y),
cm->rst_info[1].restoration_tilesize, NULL, NULL,
&nrtiles_x[1], &nrtiles_y[1]);
for (int tile_row = 0; tile_row < cm->tile_rows; ++tile_row) {
for (int tile_col = 0; tile_col < cm->tile_cols; ++tile_col) {
decode_restoration_for_tile(cm, rb, tile_row, tile_col, nrtiles_x,
nrtiles_y);
}
}
}
......
......@@ -3341,8 +3341,75 @@ static void write_sgrproj_filter(SgrprojInfo *sgrproj_info,
memcpy(ref_sgrproj_info, sgrproj_info, sizeof(*sgrproj_info));
}
static void encode_restoration_for_tile(AV1_COMMON *cm, aom_writer *wb,
int tile_row, int tile_col,
const int nrtiles_x[2],
const int nrtiles_y[2]) {
for (int p = 0; p < MAX_MB_PLANE; ++p) {
RestorationInfo *rsi = &cm->rst_info[p];
if (rsi->frame_restoration_type == RESTORE_NONE) continue;
const int tile_width =
(p > 0) ? ROUND_POWER_OF_TWO(cm->tile_width, cm->subsampling_x)
: cm->tile_width;
const int tile_height =
(p > 0) ? ROUND_POWER_OF_TWO(cm->tile_height, cm->subsampling_y)
: cm->tile_height;
const int rtile_size = rsi->restoration_tilesize;
const int rtiles_per_tile_x = tile_width * MI_SIZE / rtile_size;
const int rtiles_per_tile_y = tile_height * MI_SIZE / rtile_size;
const int rtile_row0 = rtiles_per_tile_y * tile_row;
const int rtile_row1 =
AOMMIN(rtile_row0 + rtiles_per_tile_y, nrtiles_y[p > 0]);
const int rtile_col0 = rtiles_per_tile_x * tile_col;
const int rtile_col1 =
AOMMIN(rtile_col0 + rtiles_per_tile_x, nrtiles_x[p > 0]);
WienerInfo wiener_info;
SgrprojInfo sgrproj_info;
set_default_wiener(&wiener_info);
set_default_sgrproj(&sgrproj_info);
const int wiener_win = (p > 0) ? WIENER_WIN_CHROMA : WIENER_WIN;
for (int rtile_row = rtile_row0; rtile_row < rtile_row1; ++rtile_row) {
for (int rtile_col = rtile_col0; rtile_col < rtile_col1; ++rtile_col) {
const int rtile_idx = rtile_row * nrtiles_x[p > 0] + rtile_col;
if (rsi->frame_restoration_type == RESTORE_SWITCHABLE) {
assert(p == 0);
av1_write_token(
wb, av1_switchable_restore_tree, cm->fc->switchable_restore_prob,
&switchable_restore_encodings[rsi->restoration_type[rtile_idx]]);
if (rsi->restoration_type[rtile_idx] == RESTORE_WIENER) {
write_wiener_filter(wiener_win, &rsi->wiener_info[rtile_idx],
&wiener_info, wb);
} else if (rsi->restoration_type[rtile_idx] == RESTORE_SGRPROJ) {
write_sgrproj_filter(&rsi->sgrproj_info[rtile_idx], &sgrproj_info,
wb);
}
} else if (rsi->frame_restoration_type == RESTORE_WIENER) {
aom_write(wb, rsi->restoration_type[rtile_idx] != RESTORE_NONE,
RESTORE_NONE_WIENER_PROB);
if (rsi->restoration_type[rtile_idx] != RESTORE_NONE) {
write_wiener_filter(wiener_win, &rsi->wiener_info[rtile_idx],
&wiener_info, wb);
}
} else if (rsi->frame_restoration_type == RESTORE_SGRPROJ) {
aom_write(wb, rsi->restoration_type[rtile_idx] != RESTORE_NONE,
RESTORE_NONE_SGRPROJ_PROB);
if (rsi->restoration_type[rtile_idx] != RESTORE_NONE) {
write_sgrproj_filter(&rsi->sgrproj_info[rtile_idx], &sgrproj_info,
wb);
}
}
}
}
}
}
static void encode_restoration(AV1_COMMON *cm, aom_writer *wb) {
int i, p;
#if CONFIG_FRAME_SUPERRES
const int width = cm->superres_upscaled_width;
const int height = cm->superres_upscaled_height;
......@@ -3350,76 +3417,19 @@ static void encode_restoration(AV1_COMMON *cm, aom_writer *wb) {
const int width = cm->width;
const int height = cm->height;
#endif // CONFIG_FRAME_SUPERRES
const int ntiles =
av1_get_rest_ntiles(width, height, cm->rst_info[0].restoration_tilesize,
NULL, NULL, NULL, NULL);
WienerInfo ref_wiener_info;
SgrprojInfo ref_sgrproj_info;
set_default_wiener(&ref_wiener_info);
set_default_sgrproj(&ref_sgrproj_info);
const int ntiles_uv = av1_get_rest_ntiles(
ROUND_POWER_OF_TWO(width, cm->subsampling_x),
ROUND_POWER_OF_TWO(height, cm->subsampling_y),
cm->rst_info[1].restoration_tilesize, NULL, NULL, NULL, NULL);
RestorationInfo *rsi = &cm->rst_info[0];
if (rsi->frame_restoration_type != RESTORE_NONE) {
if (rsi->frame_restoration_type == RESTORE_SWITCHABLE) {
// RESTORE_SWITCHABLE
for (i = 0; i < ntiles; ++i) {
av1_write_token(
wb, av1_switchable_restore_tree, cm->fc->switchable_restore_prob,
&switchable_restore_encodings[rsi->restoration_type[i]]);
if (rsi->restoration_type[i] == RESTORE_WIENER) {
write_wiener_filter(WIENER_WIN, &rsi->wiener_info[i],
&ref_wiener_info, wb);
} else if (rsi->restoration_type[i] == RESTORE_SGRPROJ) {
write_sgrproj_filter(&rsi->sgrproj_info[i], &ref_sgrproj_info, wb);
}
}
} else if (rsi->frame_restoration_type == RESTORE_WIENER) {
for (i = 0; i < ntiles; ++i) {
aom_write(wb, rsi->restoration_type[i] != RESTORE_NONE,
RESTORE_NONE_WIENER_PROB);
if (rsi->restoration_type[i] != RESTORE_NONE) {
write_wiener_filter(WIENER_WIN, &rsi->wiener_info[i],
&ref_wiener_info, wb);
}
}
} else if (rsi->frame_restoration_type == RESTORE_SGRPROJ) {
for (i = 0; i < ntiles; ++i) {
aom_write(wb, rsi->restoration_type[i] != RESTORE_NONE,
RESTORE_NONE_SGRPROJ_PROB);
if (rsi->restoration_type[i] != RESTORE_NONE) {
write_sgrproj_filter(&rsi->sgrproj_info[i], &ref_sgrproj_info, wb);
}
}
}
}
for (p = 1; p < MAX_MB_PLANE; ++p) {
set_default_wiener(&ref_wiener_info);
set_default_sgrproj(&ref_sgrproj_info);
rsi = &cm->rst_info[p];
if (rsi->frame_restoration_type == RESTORE_WIENER) {
for (i = 0; i < ntiles_uv; ++i) {
if (ntiles_uv > 1)
aom_write(wb, rsi->restoration_type[i] != RESTORE_NONE,
RESTORE_NONE_WIENER_PROB);
if (rsi->restoration_type[i] != RESTORE_NONE) {
write_wiener_filter(WIENER_WIN_CHROMA, &rsi->wiener_info[i],
&ref_wiener_info, wb);
}
}
} else if (rsi->frame_restoration_type == RESTORE_SGRPROJ) {
for (i = 0; i < ntiles_uv; ++i) {
if (ntiles_uv > 1)
aom_write(wb, rsi->restoration_type[i] != RESTORE_NONE,
RESTORE_NONE_SGRPROJ_PROB);
if (rsi->restoration_type[i] != RESTORE_NONE) {
write_sgrproj_filter(&rsi->sgrproj_info[i], &ref_sgrproj_info, wb);
}
}
} else if (rsi->frame_restoration_type != RESTORE_NONE) {
assert(0);
int nrtiles_x[2], nrtiles_y[2];
av1_get_rest_ntiles(width, height, cm->rst_info[0].restoration_tilesize, NULL,
NULL, &nrtiles_x[0], &nrtiles_y[0]);
av1_get_rest_ntiles(ROUND_POWER_OF_TWO(width, cm->subsampling_x),
ROUND_POWER_OF_TWO(height, cm->subsampling_y),
cm->rst_info[1].restoration_tilesize, NULL, NULL,
&nrtiles_x[1], &nrtiles_y[1]);
for (int tile_row = 0; tile_row < cm->tile_rows; ++tile_row) {
for (int tile_col = 0; tile_col < cm->tile_cols; ++tile_col) {
encode_restoration_for_tile(cm, wb, tile_row, tile_col, nrtiles_x,
nrtiles_y);
}
}
}
......
......@@ -172,8 +172,8 @@ static int64_t try_restoration_frame(const YV12_BUFFER_CONFIG *src,
return filt_err;
}
static int64_t get_pixel_proj_error(uint8_t *src8, int width, int height,
int src_stride, uint8_t *dat8,
static int64_t get_pixel_proj_error(const uint8_t *src8, int width, int height,
int src_stride, const uint8_t *dat8,
int dat_stride, int bit_depth,
int32_t *flt1, int flt1_stride,
int32_t *flt2, int flt2_stride, int *xqd) {
......@@ -219,9 +219,9 @@ static int64_t get_pixel_proj_error(uint8_t *src8, int width, int height,
#define USE_SGRPROJ_REFINEMENT_SEARCH 1
static int64_t finer_search_pixel_proj_error(
uint8_t *src8, int width, int height, int src_stride, uint8_t *dat8,
int dat_stride, int bit_depth, int32_t *flt1, int flt1_stride,
int32_t *flt2, int flt2_stride, int start_step, int *xqd) {
const uint8_t *src8, int width, int height, int src_stride,
const uint8_t *dat8, int dat_stride, int bit_depth, int32_t *flt1,
int flt1_stride, int32_t *flt2, int flt2_stride, int start_step, int *xqd) {
int64_t err = get_pixel_proj_error(src8, width, height, src_stride, dat8,
dat_stride, bit_depth, flt1, flt1_stride,
flt2, flt2_stride, xqd);
......@@ -273,7 +273,7 @@ static int64_t finer_search_pixel_proj_error(
return err;
}
static void get_proj_subspace(uint8_t *src8, int width, int height,
static void get_proj_subspace(const uint8_t *src8, int width, int height,
int src_stride, uint8_t *dat8, int dat_stride,
int bit_depth, int32_t *flt1, int flt1_stride,
int32_t *flt2, int flt2_stride, int *xq) {
......@@ -346,7 +346,7 @@ void encode_xq(int *xq, int *xqd) {
}
static void search_selfguided_restoration(uint8_t *dat8, int width, int height,
int dat_stride, uint8_t *src8,
int dat_stride, const uint8_t *src8,
int src_stride, int bit_depth,
int *eps, int *xqd, int32_t *rstbuf) {
int32_t *flt1 = rstbuf;
......@@ -420,124 +420,227 @@ static int count_sgrproj_bits(SgrprojInfo *sgrproj_info,
return bits;
}
static double search_sgrproj(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
int partial_frame, int plane,
RestorationInfo *info, RestorationType *type,
double *best_tile_cost,
YV12_BUFFER_CONFIG *dst_frame) {
SgrprojInfo *sgrproj_info = info->sgrproj_info;
double err, cost_norestore, cost_sgrproj;
int bits;
MACROBLOCK *x = &cpi->td.mb;
struct rest_search_ctxt {
const YV12_BUFFER_CONFIG *src;
AV1_COMP *cpi;
uint8_t *dgd_buffer;
const uint8_t *src_buffer;
int dgd_stride;
int src_stride;
int partial_frame;
RestorationInfo *info;
RestorationType *type;
double *best_tile_cost;
int plane;
int plane_width;
int plane_height;
int nrtiles_x;
int nrtiles_y;
YV12_BUFFER_CONFIG *dst_frame;
};
// Fill in ctxt. Returns the number of restoration tiles for this plane
static INLINE int init_rest_search_ctxt(
const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi, int partial_frame, int plane,
RestorationInfo *info, RestorationType *type, double *best_tile_cost,
YV12_BUFFER_CONFIG *dst_frame, struct rest_search_ctxt *ctxt) {
AV1_COMMON *const cm = &cpi->common;
ctxt->src = src;
ctxt->cpi = cpi;
ctxt->partial_frame = partial_frame;
ctxt->info = info;
ctxt->type = type;
ctxt->best_tile_cost = best_tile_cost;
ctxt->plane = plane;
ctxt->dst_frame = dst_frame;
const YV12_BUFFER_CONFIG *dgd = cm->frame_to_show;
RestorationInfo *rsi = &cpi->rst_search[0];
int tile_idx, tile_width, tile_height, nhtiles, nvtiles;
int h_start, h_end, v_start, v_end;
int width, height, src_stride, dgd_stride;
uint8_t *dgd_buffer, *src_buffer;
if (plane == AOM_PLANE_Y) {
width = src->y_crop_width;
height = src->y_crop_height;
src_buffer = src->y_buffer;
src_stride = src->y_stride;
dgd_buffer = dgd->y_buffer;
dgd_stride = dgd->y_stride;
assert(width == dgd->y_crop_width);
assert(height == dgd->y_crop_height);
assert(width == src->y_crop_width);
assert(height == src->y_crop_height);
ctxt->plane_width = src->y_crop_width;
ctxt->plane_height = src->y_crop_height;
ctxt->src_buffer = src->y_buffer;
ctxt->src_stride = src->y_stride;
ctxt->dgd_buffer = dgd->y_buffer;
ctxt->dgd_stride = dgd->y_stride;
assert(ctxt->plane_width == dgd->y_crop_width);
assert(ctxt->plane_height == dgd->y_crop_height);
assert(ctxt->plane_width == src->y_crop_width);
assert(ctxt->plane_height == src->y_crop_height);
} else {
width = src->uv_crop_width;
height = src->uv_crop_height;
src_stride = src->uv_stride;
dgd_stride = dgd->uv_stride;
src_buffer = plane == AOM_PLANE_U ? src->u_buffer : src->v_buffer;
dgd_buffer = plane == AOM_PLANE_U ? dgd->u_buffer : dgd->v_buffer;
assert(width == dgd->uv_crop_width);
assert(height == dgd->uv_crop_height);
ctxt->plane_width = src->uv_crop_width;
ctxt->plane_height = src->uv_crop_height;
ctxt->src_stride = src->uv_stride;
ctxt->dgd_stride = dgd->uv_stride;
ctxt->src_buffer = plane == AOM_PLANE_U ? src->u_buffer : src->v_buffer;
ctxt->dgd_buffer = plane == AOM_PLANE_U ? dgd->u_buffer : dgd->v_buffer;
assert(ctxt->plane_width == dgd->uv_crop_width);
assert(ctxt->plane_height == dgd->uv_crop_height);
}
const int ntiles =
av1_get_rest_ntiles(width, height, cm->rst_info[0].restoration_tilesize,
&tile_width, &tile_height, &nhtiles, &nvtiles);
SgrprojInfo ref_sgrproj_info;
set_default_sgrproj(&ref_sgrproj_info);
rsi[plane].frame_restoration_type = RESTORE_SGRPROJ;
return av1_get_rest_ntiles(ctxt->plane_width, ctxt->plane_height,
cm->rst_info[plane].restoration_tilesize, NULL,
NULL, &ctxt->nrtiles_x, &ctxt->nrtiles_y);
}
for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
rsi[plane].restoration_type[tile_idx] = RESTORE_NONE;
typedef void (*rtile_visitor_t)(const struct rest_search_ctxt *search_ctxt,
int rtile_idx, int h_start, int h_end,
int v_start, int v_end, void *arg);
static void foreach_rtile_in_tile(const struct rest_search_ctxt *ctxt,
int tile_row, int tile_col,
rtile_visitor_t fun, void *arg) {
const AV1_COMMON *const cm = &ctxt->cpi->common;
const RestorationInfo *rsi = ctxt->cpi->rst_search;
const int tile_width_y = cm->tile_width * MI_SIZE;
const int tile_height_y = cm->tile_height * MI_SIZE;
const int tile_width =
(ctxt->plane > 0) ? ROUND_POWER_OF_TWO(tile_width_y, cm->subsampling_x)
: tile_width_y;
const int tile_height =
(ctxt->plane > 0) ? ROUND_POWER_OF_TWO(tile_height_y, cm->subsampling_y)
: tile_height_y;
const int rtile_size = rsi->restoration_tilesize;
const int rtiles_per_tile_x = tile_width * MI_SIZE / rtile_size;
const int rtiles_per_tile_y = tile_height * MI_SIZE / rtile_size;
const int rtile_row0 = rtiles_per_tile_y * tile_row;
const int rtile_row1 =
AOMMIN(rtile_row0 + rtiles_per_tile_y, ctxt->nrtiles_y);
const int rtile_col0 = rtiles_per_tile_x * tile_col;
const int rtile_col1 =
AOMMIN(rtile_col0 + rtiles_per_tile_x, ctxt->nrtiles_x);
const int rtile_width = AOMMIN(tile_width, rtile_size);
const int rtile_height = AOMMIN(tile_height, rtile_size);
for (int rtile_row = rtile_row0; rtile_row < rtile_row1; ++rtile_row) {
for (int rtile_col = rtile_col0; rtile_col < rtile_col1; ++rtile_col) {
const int rtile_idx = rtile_row * ctxt->nrtiles_x + rtile_col;
int h_start, h_end, v_start, v_end;
av1_get_rest_tile_limits(rtile_idx, 0, 0, ctxt->nrtiles_x,
ctxt->nrtiles_y, rtile_width, rtile_height,
ctxt->plane_width, ctxt->plane_height, 0, 0,
&h_start, &h_end, &v_start, &v_end);
fun(ctxt, rtile_idx, h_start, h_end, v_start, v_end, arg);
}
}
// Compute best Sgrproj filters for each tile
for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
av1_get_rest_tile_limits(tile_idx, 0, 0, nhtiles, nvtiles, tile_width,
tile_height, width, height, 0, 0, &h_start, &h_end,
&v_start, &v_end);
err = sse_restoration_tile(src, cm->frame_to_show, cm, h_start,
h_end - h_start, v_start, v_end - v_start,
(1 << plane));
// #bits when a tile is not restored
bits = av1_cost_bit(RESTORE_NONE_SGRPROJ_PROB, 0);
cost_norestore = RDCOST_DBL(x->rdmult, (bits >> 4), err);
best_tile_cost[tile_idx] = DBL_MAX;
search_selfguided_restoration(
dgd_buffer + v_start * dgd_stride + h_start, h_end - h_start,
v_end - v_start, dgd_stride,
src_buffer + v_start * src_stride + h_start, src_stride,
}
static void search_sgrproj_for_rtile(const struct rest_search_ctxt *ctxt,
int rtile_idx, int h_start, int h_end,
int v_start, int v_end, void *arg) {
const MACROBLOCK *const x = &ctxt->cpi->td.mb;
const AV1_COMMON *const cm = &ctxt->cpi->common;
RestorationInfo *rsi = ctxt->cpi->rst_search;
SgrprojInfo *sgrproj_info = ctxt->info->sgrproj_info;
SgrprojInfo *ref_sgrproj_info = (SgrprojInfo *)arg;
int64_t err = sse_restoration_tile(ctxt->src, cm->frame_to_show, cm, h_start,
h_end - h_start, v_start, v_end - v_start,
(1 << ctxt->plane));
// #bits when a tile is not restored
int bits = av1_cost_bit(RESTORE_NONE_SGRPROJ_PROB, 0);
double cost_norestore = RDCOST_DBL(x->rdmult, (bits >> 4), err);
ctxt->best_tile_cost[rtile_idx] = DBL_MAX;
RestorationInfo *plane_rsi = &rsi[ctxt->plane];
SgrprojInfo *rtile_sgrproj_info = &plane_rsi->sgrproj_info[rtile_idx];
uint8_t *dgd_start = ctxt->dgd_buffer + v_start * ctxt->dgd_stride + h_start;
const uint8_t *src_start =
ctxt->src_buffer + v_start * ctxt->src_stride + h_start;
search_selfguided_restoration(dgd_start, h_end - h_start, v_end - v_start,
ctxt->dgd_stride, src_start, ctxt->src_stride,
#if CONFIG_HIGHBITDEPTH
cm->bit_depth,
cm->bit_depth,
#else
8,
8,
#endif // CONFIG_HIGHBITDEPTH
&rsi[plane].sgrproj_info[tile_idx].ep,
rsi[plane].sgrproj_info[tile_idx].xqd, cm->rst_internal.tmpbuf);
rsi[plane].restoration_type[tile_idx] = RESTORE_SGRPROJ;
err = try_restoration_tile(src, cpi, rsi, (1 << plane), partial_frame,
tile_idx, 0, 0, dst_frame);
bits = count_sgrproj_bits(&rsi[plane].sgrproj_info[tile_idx],
&ref_sgrproj_info)
<< AV1_PROB_COST_SHIFT;
bits += av1_cost_bit(RESTORE_NONE_SGRPROJ_PROB, 1);
cost_sgrproj = RDCOST_DBL(x->rdmult, (bits >> 4), err);
if (cost_sgrproj >= cost_norestore) {
type[tile_idx] = RESTORE_NONE;
} else {
type[tile_idx] = RESTORE_SGRPROJ;
memcpy(&sgrproj_info[tile_idx], &rsi[plane].sgrproj_info[tile_idx],
sizeof(sgrproj_info[tile_idx]));
memcpy(&ref_sgrproj_info, &sgrproj_info[tile_idx],
sizeof(ref_sgrproj_info));
best_tile_cost[tile_idx] = err;
&rtile_sgrproj_info->ep,
rtile_sgrproj_info->xqd,
cm->rst_internal.tmpbuf);
plane_rsi->restoration_type[rtile_idx] = RESTORE_SGRPROJ;
err = try_restoration_tile(ctxt->src, ctxt->cpi, rsi, (1 << ctxt->plane),
ctxt->partial_frame, rtile_idx, 0, 0,
ctxt->dst_frame);
bits =
count_sgrproj_bits(&plane_rsi->sgrproj_info[rtile_idx], ref_sgrproj_info)
<< AV1_PROB_COST_SHIFT;
bits += av1_cost_bit(RESTORE_NONE_SGRPROJ_PROB, 1);
double cost_sgrproj = RDCOST_DBL(x->rdmult, (bits >> 4), err);
if (cost_sgrproj >= cost_norestore) {
ctxt->type[rtile_idx] = RESTORE_NONE;
} else {
ctxt->type[rtile_idx] = RESTORE_SGRPROJ;
*ref_sgrproj_info = sgrproj_info[rtile_idx] =
plane_rsi->sgrproj_info[rtile_idx];
ctxt->best_tile_cost[rtile_idx] = err;
}
plane_rsi->restoration_type[rtile_idx] = RESTORE_NONE;
}
static double search_sgrproj(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
int partial_frame, int plane,
RestorationInfo *info, RestorationType *type,
double *best_tile_cost,
YV12_BUFFER_CONFIG *dst_frame) {
struct rest_search_ctxt ctxt;
const int nrtiles =
init_rest_search_ctxt(src, cpi, partial_frame, plane, info, type,
best_tile_cost, dst_frame, &ctxt);
RestorationInfo *plane_rsi = &cpi->rst_search[plane];
plane_rsi->frame_restoration_type = RESTORE_SGRPROJ;
for (int rtile_idx = 0; rtile_idx < nrtiles; ++rtile_idx) {
plane_rsi->restoration_type[rtile_idx] = RESTORE_NONE;
}
// Compute best Sgrproj filters for each rtile, one (encoder/decoder)
// tile at a time.
const AV1_COMMON *const cm = &cpi->common;
for (int tile_row = 0; tile_row < cm->tile_rows; ++tile_row) {
for (int tile_col = 0; tile_col < cm->tile_cols; ++tile_col) {
SgrprojInfo ref_sgrproj_info;
set_default_sgrproj(&ref_sgrproj_info);
foreach_rtile_in_tile(&ctxt, tile_row, tile_col, search_sgrproj_for_rtile,
&ref_sgrproj_info);
}
rsi[plane].restoration_type[tile_idx] = RESTORE_NONE;
}
// Cost for Sgrproj filtering
SgrprojInfo ref_sgrproj_info;
set_default_sgrproj(&ref_sgrproj_info);
bits = frame_level_restore_bits[rsi[plane].frame_restoration_type]
<< AV1_PROB_COST_SHIFT;
for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
bits +=
av1_cost_bit(RESTORE_NONE_SGRPROJ_PROB, type[tile_idx] != RESTORE_NONE);
memcpy(&rsi[plane].sgrproj_info[tile_idx], &sgrproj_info[tile_idx],
sizeof(sgrproj_info[tile_idx]));
if (type[tile_idx] == RESTORE_SGRPROJ) {
bits += count_sgrproj_bits(&rsi[plane].sgrproj_info[tile_idx],
SgrprojInfo *sgrproj_info = info->sgrproj_info;
int bits = frame_level_restore_bits[plane_rsi->frame_restoration_type]
<< AV1_PROB_COST_SHIFT;
for (int rtile_idx = 0; rtile_idx < nrtiles; ++rtile_idx) {
bits += av1_cost_bit(RESTORE_NONE_SGRPROJ_PROB,
type[rtile_idx] != RESTORE_NONE);
plane_rsi->sgrproj_info[rtile_idx] = sgrproj_info[rtile_idx];
if (type[rtile_idx] == RESTORE_SGRPROJ) {
bits += count_sgrproj_bits(&plane_rsi->sgrproj_info[rtile_idx],
&ref_sgrproj_info)
<< AV1_PROB_COST_SHIFT;
memcpy(&ref_sgrproj_info, &rsi[plane].sgrproj_info[tile_idx],