From 2d11c2ea9af4e26905659147a4c45bf3e7cf0ca9 Mon Sep 17 00:00:00 2001 From: Ram Mohan M Date: Thu, 20 Aug 2026 09:07:10 +0530 Subject: [PATCH] Ccso: Split parameter search into sub-functions - Split per-plane ccso parameter search into focused sub-functions. - Introduce CcsoCtx/CcsoCtxCommon to carry per-plane-search state, replacing long function-argument lists. - Replace raw memset/memcpy with av2_zero_array/av2_copy_array, and narrow several of them from the full CCSO_BAND_NUM/ CCSO_CLASS_STATS_ENTRIES range down to the max_band/ max_edge_interval range actually used by the current search iteration. - corrects two places that used the horizontal filter-unit log2 for a vertical quantity (derive_blk_md(), get_sb_reuse_dist() and ccso_compute_class_err). no stats changed --- av2/encoder/encoder.c | 11 +- av2/encoder/encoder.h | 8 + av2/encoder/pickccso.c | 1563 +++++++++++++++++++--------------------- av2/encoder/pickccso.h | 111 ++- 4 files changed, 844 insertions(+), 849 deletions(-) diff --git a/av2/encoder/encoder.c b/av2/encoder/encoder.c index d6b3723987..7f124271b3 100644 --- a/av2/encoder/encoder.c +++ b/av2/encoder/encoder.c @@ -3165,15 +3165,10 @@ static void cdef_restoration_frame(AV2_COMP *cpi, AV2_COMMON *cm, src_cpy += ccso_stride; } } - av2_ccso_search(cm, xd, cpi->td.mb.rdmult, ext_rec_y, cpi->ccso_rec_uv, - cpi->ccso_org_uv, cpi->error_resilient_frame_seen -#if CONFIG_ENTROPY_STATS - , - &cpi->td -#endif - , + av2_ccso_search(cpi, ext_rec_y, cpi->ccso_rec_uv, cpi->ccso_org_uv, + cpi->error_resilient_frame_seen, cpi->sf.lpf_sf.early_terminate_ccso_search_by_cost, - cpi->sf.lpf_sf.ccso_chroma_dep, &cpi->ccso_ctx); + cpi->sf.lpf_sf.ccso_chroma_dep); ccso_frame(&cm->cur_frame->buf, cm, xd, ext_rec_y); #if CONFIG_MISMATCH_DEBUG mismatch_record_frame(&cm->cur_frame->buf, num_planes, 2); diff --git a/av2/encoder/encoder.h b/av2/encoder/encoder.h index caf20a5e69..540417ffda 100644 --- a/av2/encoder/encoder.h +++ b/av2/encoder/encoder.h @@ -3140,6 +3140,14 @@ typedef struct AV2_COMP { * freed at encoder close). */ CcsoCtx ccso_ctx; + /*! + * distortion between source and ccso input at sb level + */ + uint64_t *unfiltered_dist_block; + /*! + * Allocated size of unfiltered_dist_block in elements. + */ + int unfiltered_dist_block_alloc_sb_count; /*! * Extended luma reconstruction buffer for CCSO search. */ diff --git a/av2/encoder/pickccso.c b/av2/encoder/pickccso.c index 3e7dc77317..0e97ff4ca8 100644 --- a/av2/encoder/pickccso.c +++ b/av2/encoder/pickccso.c @@ -30,7 +30,7 @@ const int ccso_offset[8] = { -10, -7, -3, -1, 0, 1, 3, 7 }; const int ccso_scale[4] = { 1, 2, 3, 4 }; static INLINE bool reuse_ccso_class_info(const AV2_COMMON *cm) { - return !(cm->bru.enabled); + return !cm->bru.enabled; } // Resets per-frame state in a persistent CcsoCtx while preserving all @@ -67,32 +67,34 @@ void ccso_derive_src_block_c(const uint16_t *src_y, uint8_t *const src_cls0, } /* Derive CCSO filter support information */ -static void ccso_derive_src_info(AV2_COMMON *cm, MACROBLOCKD *xd, - const int plane, const uint16_t *src_y, - const int proc_unit_log2, const uint16_t qstep, - const uint8_t filter_sup, uint8_t *src_cls0, - uint8_t *src_cls1, int edge_clf, - int ccso_stride, int ccso_stride_ext) { - const int pic_height = xd->plane[plane].dst.height; - const int pic_width = xd->plane[plane].dst.width; - const int y_uv_hscale = xd->plane[plane].subsampling_x; - const int y_uv_vscale = xd->plane[plane].subsampling_y; +static void ccso_derive_src_info(AV2_COMMON *cm, CcsoCtx *ctx, + MACROBLOCKD *xd) { + CcsoCtxCommon *s = &ctx->ccso_cm; + uint8_t *src_cls0 = ctx->src_cls0; + uint8_t *src_cls1 = ctx->src_cls1; + const uint16_t qstep = quant_sz[ctx->scale_idx][ctx->quant_idx]; + const uint8_t filter_sup = ctx->ext_filter_support; + const int edge_clf = ctx->edge_clf; + const int ccso_stride = ctx->ccso_stride; + const int ccso_stride_ext = ctx->ccso_stride_ext; + const int pic_height = xd->plane[s->plane].dst.height; + const int pic_width = xd->plane[s->plane].dst.width; + const int y_uv_hscale = xd->plane[s->plane].subsampling_x; + const int y_uv_vscale = xd->plane[s->plane].subsampling_y; + const uint16_t *src_y = s->ext_rec_y; + const int blk_log2_y = s->log2_filter_unit_size_y; + const int blk_log2_x = s->log2_filter_unit_size_x; + const int blk_size_y = 1 << blk_log2_y; + const int blk_size_x = 1 << blk_log2_x; + const int unit_log2_x = AVMMIN(s->log2_proc_unit_size, blk_log2_x); + const int unit_size_x = 1 << unit_log2_x; + const int unit_log2_y = AVMMIN(s->log2_proc_unit_size, blk_log2_y); + const int unit_size_y = 1 << unit_log2_y; const int neg_qstep = qstep * -1; int src_loc[2]; + derive_ccso_sample_pos(src_loc, ccso_stride_ext, filter_sup); - const int ccso_blk_size = get_ccso_unit_size_log2_adaptive_tile( - cm, cm->mib_size_log2 + MI_SIZE_LOG2, CCSO_BLK_SIZE); - const int blk_log2_y = ccso_blk_size - xd->plane[plane].subsampling_y; - const int blk_log2_x = ccso_blk_size - xd->plane[plane].subsampling_x; - const int blk_size_y = 1 << blk_log2_y; - const int blk_size_x = 1 << blk_log2_x; src_y += CCSO_PADDING_SIZE * ccso_stride_ext + CCSO_PADDING_SIZE; - const int unit_log2_x = - proc_unit_log2 > blk_log2_x ? blk_log2_x : proc_unit_log2; - const int unit_size_x = 1 << (unit_log2_x); - const int unit_log2_y = - proc_unit_log2 > blk_log2_y ? blk_log2_y : proc_unit_log2; - const int unit_size_y = 1 << (unit_log2_y); for (int y = 0; y < pic_height; y += blk_size_y) { for (int x = 0; x < pic_width; x += blk_size_x) { // check BRU skip in entire CCSO FU, this means no signal needed @@ -138,40 +140,26 @@ static void ccso_derive_src_info(AV2_COMMON *cm, MACROBLOCKD *xd, /* Compute the aggregated residual between original and reconstructed sample for * each entry of the LUT */ -static void ccso_pre_compute_class_err( - CcsoCtx *ctx, MACROBLOCKD *xd, const int plane, const AV2_COMMON *cm, - const int proc_unit_log2, const uint16_t *src_y, const uint16_t *ref, - const uint16_t *dst, uint8_t *src_cls0, uint8_t *src_cls1, - const uint8_t shift_bits, const uint8_t init_shift_bits) { - const int pic_height = xd->plane[plane].dst.height; - const int pic_width = xd->plane[plane].dst.width; - const int y_uv_hscale = xd->plane[plane].subsampling_x; - const int y_uv_vscale = xd->plane[plane].subsampling_y; - int fb_idx = 0; - uint8_t cur_src_cls0; - uint8_t cur_src_cls1; - const int ccso_blk_size = get_ccso_unit_size_log2_adaptive_tile( - cm, cm->mib_size_log2 + MI_SIZE_LOG2, CCSO_BLK_SIZE); - const int blk_log2_y = ccso_blk_size - xd->plane[plane].subsampling_y; - const int blk_log2_x = ccso_blk_size - xd->plane[plane].subsampling_x; - const CommonModeInfoParams *const mi_params = &cm->mi_params; - const int ccso_nvfb = - ((mi_params->mi_rows >> xd->plane[plane].subsampling_y) + - (1 << blk_log2_y >> 2) - 1) / - (1 << blk_log2_y >> 2); - const int ccso_nhfb = - ((mi_params->mi_cols >> xd->plane[plane].subsampling_x) + - (1 << blk_log2_x >> 2) - 1) / - (1 << blk_log2_x >> 2); - const int sb_count = ccso_nvfb * ccso_nhfb; - +static void ccso_pre_compute_class_err(const AV2_COMMON *cm, CcsoCtx *ctx, + MACROBLOCKD *xd) { + CcsoCtxCommon *s = &ctx->ccso_cm; + const uint8_t shift_bits = ctx->shift_bits; + const uint8_t init_shift_bits = ctx->init_shift_bits; + const int sb_count = s->sb_count; + const int max_band = 1 << (cm->seq_params.bit_depth - shift_bits); + + for (int d0 = 0; d0 < ctx->max_edge_interval; d0++) { + for (int d1 = 0; d1 < ctx->max_edge_interval; d1++) { + av2_zero_array(ctx->total_class_err[d0][d1][0], max_band * sb_count); + av2_zero_array(ctx->total_class_cnt[d0][d1][0], max_band * sb_count); + } + } // Error and count of previously computed bands are reused to compute // error and count of the new lower bands. if ((init_shift_bits != shift_bits) && reuse_ccso_class_info(cm)) { - const int max_band = 1 << (cm->seq_params.bit_depth - shift_bits); const int num_bins_to_be_summed = 1 << (shift_bits - init_shift_bits); - for (int d0 = 0; d0 < CCSO_INPUT_INTERVAL; d0++) { - for (int d1 = 0; d1 < CCSO_INPUT_INTERVAL; d1++) { + for (int d0 = 0; d0 < ctx->max_edge_interval; d0++) { + for (int d1 = 0; d1 < ctx->max_edge_interval; d1++) { for (int fb_cnt = 0; fb_cnt < sb_count; fb_cnt++) { for (int band_num = 0; band_num < max_band; band_num++) { const int bin_index = (band_num * num_bins_to_be_summed); @@ -191,26 +179,30 @@ static void ccso_pre_compute_class_err( return; } + uint8_t *src_cls0 = ctx->src_cls0; + uint8_t *src_cls1 = ctx->src_cls1; + const int pic_height = xd->plane[s->plane].dst.height; + const int pic_width = xd->plane[s->plane].dst.width; + const int y_uv_hscale = xd->plane[s->plane].subsampling_x; + const int y_uv_vscale = xd->plane[s->plane].subsampling_y; + const uint16_t *src_y = s->ext_rec_y; + const uint16_t *ref = s->org_uv; + const uint16_t *dst = s->rec_uv; + const int blk_log2_y = s->log2_filter_unit_size_y; + const int blk_log2_x = s->log2_filter_unit_size_x; const int blk_size_y = 1 << blk_log2_y; const int blk_size_x = 1 << blk_log2_x; const int scaled_ext_stride = (ctx->ccso_stride_ext << y_uv_vscale); const int scaled_stride = (ctx->ccso_stride << y_uv_vscale); - src_y += CCSO_PADDING_SIZE * ctx->ccso_stride_ext + CCSO_PADDING_SIZE; - const int unit_log2_x = - proc_unit_log2 > blk_log2_x ? blk_log2_x : proc_unit_log2; - const int unit_size_x = 1 << (unit_log2_x); - const int unit_log2_y = - proc_unit_log2 > blk_log2_y ? blk_log2_y : proc_unit_log2; - const int unit_size_y = 1 << (unit_log2_y); - - // Initialize total class error and count for each band to reuse - if (reuse_ccso_class_info(cm)) { - av2_zero_array(ctx->reuse_total_class_err[0][0][0], - CCSO_CLASS_STATS_ENTRIES * sb_count); - av2_zero_array(ctx->reuse_total_class_cnt[0][0][0], - CCSO_CLASS_STATS_ENTRIES * sb_count); - } + const int unit_log2_x = AVMMIN(s->log2_proc_unit_size, blk_log2_x); + const int unit_size_x = 1 << unit_log2_x; + const int unit_log2_y = AVMMIN(s->log2_proc_unit_size, blk_log2_y); + const int unit_size_y = 1 << unit_log2_y; + int fb_idx = 0; + uint8_t cur_src_cls0; + uint8_t cur_src_cls1; + src_y += CCSO_PADDING_SIZE * ctx->ccso_stride_ext + CCSO_PADDING_SIZE; for (int y = 0; y < pic_height; y += blk_size_y) { for (int x = 0; x < pic_width; x += blk_size_x) { fb_idx++; @@ -281,39 +273,44 @@ static void ccso_pre_compute_class_err( // Store the computed error and count to reuse the same for a given band if (reuse_ccso_class_info(cm)) { - av2_copy_array(ctx->reuse_total_class_err[0][0][0], - ctx->total_class_err[0][0][0], - CCSO_CLASS_STATS_ENTRIES * sb_count); - av2_copy_array(ctx->reuse_total_class_cnt[0][0][0], - ctx->total_class_cnt[0][0][0], - CCSO_CLASS_STATS_ENTRIES * sb_count); + for (int d0 = 0; d0 < ctx->max_edge_interval; ++d0) { + for (int d1 = 0; d1 < ctx->max_edge_interval; ++d1) { + av2_copy_array(ctx->reuse_total_class_err[d0][d1][0], + ctx->total_class_err[d0][d1][0], max_band * sb_count); + av2_copy_array(ctx->reuse_total_class_cnt[d0][d1][0], + ctx->total_class_cnt[d0][d1][0], max_band * sb_count); + } + } } } // pre compute classes for band offset only option -static void ccso_pre_compute_class_err_bo( - CcsoCtx *ctx, MACROBLOCKD *xd, const int plane, const AV2_COMMON *cm, - const int proc_unit_log2, const uint16_t *src_y, const uint16_t *ref, - const uint16_t *dst, const uint8_t shift_bits) { - const int pic_height = xd->plane[plane].dst.height; - const int pic_width = xd->plane[plane].dst.width; - const int y_uv_hscale = xd->plane[plane].subsampling_x; - const int y_uv_vscale = xd->plane[plane].subsampling_y; - int fb_idx = 0; - const int ccso_blk_size = get_ccso_unit_size_log2_adaptive_tile( - cm, cm->mib_size_log2 + MI_SIZE_LOG2, CCSO_BLK_SIZE); - const int blk_log2_y = ccso_blk_size - xd->plane[plane].subsampling_y; - const int blk_log2_x = ccso_blk_size - xd->plane[plane].subsampling_x; +static void ccso_pre_compute_class_err_bo(const AV2_COMMON *cm, CcsoCtx *ctx, + MACROBLOCKD *xd) { + CcsoCtxCommon *s = &ctx->ccso_cm; + const uint8_t shift_bits = ctx->shift_bits; + const int max_band = 1 << ctx->max_band_log2; + const int pic_height = xd->plane[s->plane].dst.height; + const int pic_width = xd->plane[s->plane].dst.width; + const int y_uv_hscale = xd->plane[s->plane].subsampling_x; + const int y_uv_vscale = xd->plane[s->plane].subsampling_y; + const uint16_t *src_y = s->ext_rec_y; + const uint16_t *ref = s->org_uv; + const uint16_t *dst = s->rec_uv; + const int blk_log2_y = s->log2_filter_unit_size_y; + const int blk_log2_x = s->log2_filter_unit_size_x; const int blk_size_y = 1 << blk_log2_y; const int blk_size_x = 1 << blk_log2_x; const int scaled_ext_stride = (ctx->ccso_stride_ext << y_uv_vscale); + const int unit_log2_x = AVMMIN(s->log2_proc_unit_size, blk_log2_x); + const int unit_size_x = 1 << unit_log2_x; + const int unit_log2_y = AVMMIN(s->log2_proc_unit_size, blk_log2_y); + const int unit_size_y = 1 << unit_log2_y; + int fb_idx = 0; + src_y += CCSO_PADDING_SIZE * ctx->ccso_stride_ext + CCSO_PADDING_SIZE; - const int unit_log2_x = - proc_unit_log2 > blk_log2_x ? blk_log2_x : proc_unit_log2; - const int unit_size_x = 1 << (unit_log2_x); - const int unit_log2_y = - proc_unit_log2 > blk_log2_y ? blk_log2_y : proc_unit_log2; - const int unit_size_y = 1 << (unit_log2_y); + av2_zero_array(ctx->total_class_err_bo[0], max_band * s->sb_count); + av2_zero_array(ctx->total_class_cnt_bo[0], max_band * s->sb_count); for (int y = 0; y < pic_height; y += blk_size_y) { for (int x = 0; x < pic_width; x += blk_size_x) { fb_idx++; @@ -447,21 +444,26 @@ void ccso_filter_block_hbd_with_buf_c( } } /* Apply CCSO on luma component at encoder (high bit-depth) */ -void ccso_try_luma_filter(CcsoCtx *ctx, AV2_COMMON *cm, MACROBLOCKD *xd, - const int plane, const uint16_t *src_y, - uint16_t *dst_yuv, const int dst_stride, - const int8_t *filter_offset, uint8_t *src_cls0, - uint8_t *src_cls1, const uint8_t shift_bits, - const uint8_t ccso_bo_only, int ccso_stride, - int ccso_stride_ext) { +static void ccso_try_luma_filter(AV2_COMMON *cm, CcsoCtx *ctx, MACROBLOCKD *xd, + const int8_t *filter_offset) { + CcsoCtxCommon *s = &ctx->ccso_cm; + const uint16_t *src_y = s->ext_rec_y; + const int blk_log2 = s->log2_filter_unit_size_y; + const int plane = s->plane; + uint16_t *dst_yuv = ctx->temp_rec_uv_buf; + const int dst_stride = ctx->ccso_stride; + uint8_t *src_cls0 = ctx->src_cls0; + uint8_t *src_cls1 = ctx->src_cls1; + const uint8_t shift_bits = ctx->shift_bits; + const uint8_t ccso_bo_only = ctx->ccso_bo_only; + const int ccso_stride = ctx->ccso_stride; + const int ccso_stride_ext = ctx->ccso_stride_ext; const int pic_height = xd->plane[plane].dst.height; const int pic_width = xd->plane[plane].dst.width; const int max_val = (1 << cm->seq_params.bit_depth) - 1; - const int ccso_blk_size = get_ccso_unit_size_log2_adaptive_tile( - cm, cm->mib_size_log2 + MI_SIZE_LOG2, CCSO_BLK_SIZE); - const int blk_log2 = ccso_blk_size - xd->plane[plane].subsampling_y; const int blk_size = 1 << blk_log2; int fb_idx = 0; + src_y += CCSO_PADDING_SIZE * ccso_stride_ext + CCSO_PADDING_SIZE; // luma only int unit_log2 = cm->mib_size_log2 + MI_SIZE_LOG2; @@ -523,35 +525,42 @@ void ccso_try_luma_filter(CcsoCtx *ctx, AV2_COMMON *cm, MACROBLOCKD *xd, } /* Apply CCSO on chroma component at encoder (high bit-depth) */ -static void ccso_try_chroma_filter( - CcsoCtx *ctx, AV2_COMMON *cm, MACROBLOCKD *xd, const int plane, - const uint16_t *src_y, uint16_t *dst_yuv, const int dst_stride, - const int8_t *filter_offset, uint8_t *src_cls0, uint8_t *src_cls1, - const uint8_t shift_bits, const uint8_t ccso_bo_only, int ccso_stride, - int ccso_stride_ext) { +static void ccso_try_chroma_filter(AV2_COMMON *cm, CcsoCtx *ctx, + MACROBLOCKD *xd, + const int8_t *filter_offset) { + CcsoCtxCommon *s = &ctx->ccso_cm; + const uint16_t *src_y = s->ext_rec_y; + const int blk_log2_y = s->log2_filter_unit_size_y; + const int blk_log2_x = s->log2_filter_unit_size_x; + const int plane = s->plane; + uint16_t *dst_yuv = ctx->temp_rec_uv_buf; + const int dst_stride = ctx->ccso_stride; + uint8_t *src_cls0 = ctx->src_cls0; + uint8_t *src_cls1 = ctx->src_cls1; + const uint8_t shift_bits = ctx->shift_bits; + const uint8_t ccso_bo_only = ctx->ccso_bo_only; + const int ccso_stride = ctx->ccso_stride; + const int ccso_stride_ext = ctx->ccso_stride_ext; const int pic_height = xd->plane[plane].dst.height; const int pic_width = xd->plane[plane].dst.width; const int y_uv_hscale = xd->plane[plane].subsampling_x; const int y_uv_vscale = xd->plane[plane].subsampling_y; const int max_val = (1 << cm->seq_params.bit_depth) - 1; - const int ccso_blk_size = get_ccso_unit_size_log2_adaptive_tile( - cm, cm->mib_size_log2 + MI_SIZE_LOG2, CCSO_BLK_SIZE); - const int blk_log2_y = ccso_blk_size - xd->plane[plane].subsampling_y; - const int blk_log2_x = ccso_blk_size - xd->plane[plane].subsampling_x; const int blk_size_y = 1 << blk_log2_y; const int blk_size_x = 1 << blk_log2_x; int fb_idx = 0; + src_y += CCSO_PADDING_SIZE * ccso_stride_ext + CCSO_PADDING_SIZE; int unit_log2_x = cm->mib_size_log2 + MI_SIZE_LOG2 - y_uv_hscale; if (unit_log2_x > blk_log2_x) { unit_log2_x = blk_log2_x; } - const int unit_size_x = 1 << (unit_log2_x); + const int unit_size_x = 1 << unit_log2_x; int unit_log2_y = cm->mib_size_log2 + MI_SIZE_LOG2 - y_uv_vscale; if (unit_log2_y > blk_log2_y) { unit_log2_y = blk_log2_y; } - const int unit_size_y = 1 << (unit_log2_y); + const int unit_size_y = 1 << unit_log2_y; for (int y = 0; y < pic_height; y += blk_size_y) { for (int x = 0; x < pic_width; x += blk_size_x) { fb_idx++; @@ -633,19 +642,28 @@ uint64_t compute_distortion_block_c(const uint16_t *org, const int org_stride, return ssd; } /* Compute SSE */ -static void compute_distortion( - const uint16_t *org, const int org_stride, const uint16_t *rec16, - const int rec_stride, const int log2_filter_unit_size_y, - const int log2_filter_unit_size_x, const int log2_proc_unit_size, - const AV2_COMMON *cm, const int subsampling_y, const int subsampling_x, - const int height, const int width, uint64_t *distortion_buf, - const int distortion_buf_stride, uint64_t *total_distortion) { - const int unit_log2_x = AVMMIN(log2_proc_unit_size, log2_filter_unit_size_x); - const int unit_log2_y = AVMMIN(log2_proc_unit_size, log2_filter_unit_size_y); - const int unit_size_x = 1 << (unit_log2_x); - const int unit_size_y = 1 << (unit_log2_y); - const int blk_size_x = (1 << log2_filter_unit_size_x); - const int blk_size_y = (1 << log2_filter_unit_size_y); +static void compute_distortion(const AV2_COMMON *cm, const CcsoCtx *ctx, + MACROBLOCKD *xd, const uint16_t *rec16, + uint64_t *distortion_buf, + uint64_t *total_distortion) { + const CcsoCtxCommon *s = &ctx->ccso_cm; + const uint16_t *org = s->org_uv; + const int blk_log2_y = s->log2_filter_unit_size_y; + const int blk_log2_x = s->log2_filter_unit_size_x; + const int plane = s->plane; + const int distortion_buf_stride = s->ccso_nhfb; + const int org_stride = ctx->ccso_stride; + const int rec_stride = ctx->ccso_stride; + const int subsampling_y = xd->plane[plane].subsampling_y; + const int subsampling_x = xd->plane[plane].subsampling_x; + const int height = xd->plane[plane].dst.crop_height; + const int width = xd->plane[plane].dst.crop_width; + const int unit_log2_x = AVMMIN(s->log2_proc_unit_size, blk_log2_x); + const int unit_log2_y = AVMMIN(s->log2_proc_unit_size, blk_log2_y); + const int unit_size_x = 1 << unit_log2_x; + const int unit_size_y = 1 << unit_log2_y; + const int blk_size_x = 1 << blk_log2_x; + const int blk_size_y = 1 << blk_log2_y; *total_distortion = 0; for (int y = 0; y < height; y += blk_size_y) { @@ -656,8 +674,8 @@ static void compute_distortion( if (bru_is_fu_skipped_mbmi(cm, x >> h_scale, y >> v_scale, blk_size_x >> h_scale, blk_size_y >> v_scale)) { - distortion_buf[(y >> log2_filter_unit_size_y) * distortion_buf_stride + - (x >> log2_filter_unit_size_x)] = 0; + distortion_buf[(y >> blk_log2_y) * distortion_buf_stride + + (x >> blk_log2_x)] = 0; continue; } // All unified into pixel size @@ -685,12 +703,12 @@ static void compute_distortion( org_unit += (org_stride << unit_log2_x); rec_unit += (rec_stride << unit_log2_x); } - distortion_buf[(y >> log2_filter_unit_size_y) * distortion_buf_stride + - (x >> log2_filter_unit_size_x)] = sb_ssd; + distortion_buf[(y >> blk_log2_y) * distortion_buf_stride + + (x >> blk_log2_x)] = sb_ssd; *total_distortion += sb_ssd; } - org += (org_stride << log2_filter_unit_size_y); - rec16 += (rec_stride << log2_filter_unit_size_y); + org += (org_stride << blk_log2_y); + rec16 += (rec_stride << blk_log2_y); } } @@ -739,35 +757,28 @@ int get_ccso_context(const int sb_y, const int sb_x, const int ccso_nhfb, } /* Derive block level on/off for CCSO */ -static void derive_blk_md(AV2_COMMON *cm, MACROBLOCKD *xd, const int plane, - const uint64_t *unfiltered_dist, - const uint64_t *training_dist, bool *m_filter_control, +static void derive_blk_md(AV2_COMMON *cm, CcsoCtx *ctx, MACROBLOCKD *xd, uint64_t *cur_total_dist, int *cur_total_rate, - bool *filter_enable, const int rdmult) { - avm_cdf_prob ccso_cdf[CCSO_CONTEXT][CDF_SIZE(2)]; - const int ccso_blk_size = get_ccso_unit_size_log2_adaptive_tile( - cm, cm->mib_size_log2 + MI_SIZE_LOG2, CCSO_BLK_SIZE); - const int log2_filter_unit_size = - ccso_blk_size - xd->plane[plane].subsampling_x; - const CommonModeInfoParams *const mi_params = &cm->mi_params; - const int ccso_nhfb = - ((mi_params->mi_cols >> xd->plane[plane].subsampling_x) + - (1 << log2_filter_unit_size >> 2) - 1) / - (1 << log2_filter_unit_size >> 2); - bool cur_filter_enabled = false; - int sb_idx = 0; - + bool *filter_enable) { + const CcsoCtxCommon *s = &ctx->ccso_cm; + bool *m_filter_control = ctx->filter_control; + const int plane = s->plane; + const int ccso_blk_size = s->ccso_blk_size; + const int ccso_nhfb = s->ccso_nhfb; const int ss_x = xd->plane[plane].subsampling_x; const int ss_y = xd->plane[plane].subsampling_y; const int sb_unit_size_x = - (1 << log2_filter_unit_size >> (MI_SIZE_LOG2 - ss_x)); + (1 << s->log2_filter_unit_size_x >> (MI_SIZE_LOG2 - ss_x)); const int sb_unit_size_y = - (1 << log2_filter_unit_size >> (MI_SIZE_LOG2 - ss_y)); + (1 << s->log2_filter_unit_size_y >> (MI_SIZE_LOG2 - ss_y)); const CommonTileParams *const tiles = &cm->tiles; const int tile_cols = tiles->cols; const int tile_rows = tiles->rows; const int blk_size_y = (1 << (ccso_blk_size - MI_SIZE_LOG2)) - 1; const int blk_size_x = (1 << (ccso_blk_size - MI_SIZE_LOG2)) - 1; + avm_cdf_prob ccso_cdf[CCSO_CONTEXT][CDF_SIZE(2)]; + bool cur_filter_enabled = false; + int sb_idx = 0; *cur_total_dist = 0; @@ -819,14 +830,15 @@ static void derive_blk_md(AV2_COMMON *cm, MACROBLOCKD *xd, const int plane, continue; } if (cur_filter_control == 0) { - ssd = unfiltered_dist[sb_idx]; + ssd = s->unfiltered_dist_block[sb_idx]; } else { - ssd = training_dist[sb_idx]; + ssd = ctx->training_dist_block[sb_idx]; } ssd = ROUND_POWER_OF_TWO(ssd, (xd->bd - 8) * 2); - const uint64_t rd_cost = RDCOST( - rdmult, cost_from_cdf[ccso_ctx][cur_filter_control], ssd * 16); + const uint64_t rd_cost = + RDCOST(s->rdmult, cost_from_cdf[ccso_ctx][cur_filter_control], + ssd * 16); if (rd_cost < best_cost) { best_cost = rd_cost; @@ -853,35 +865,27 @@ static void derive_blk_md(AV2_COMMON *cm, MACROBLOCKD *xd, const int plane, *filter_enable = cur_filter_enabled; } -static void get_sb_reuse_dist(AV2_COMMON *cm, MACROBLOCKD *xd, const int plane, - const uint64_t *unfiltered_dist, - const uint64_t *training_dist, - const bool *m_filter_control, +static void get_sb_reuse_dist(AV2_COMMON *cm, CcsoCtx *ctx, MACROBLOCKD *xd, uint64_t *cur_total_dist, int *cur_total_rate, - bool *filter_enable, const int rdmult) { - (void)rdmult; - const int ccso_blk_size = get_ccso_unit_size_log2_adaptive_tile( - cm, cm->mib_size_log2 + MI_SIZE_LOG2, CCSO_BLK_SIZE); - const int log2_filter_unit_size = - ccso_blk_size - xd->plane[plane].subsampling_x; - const CommonModeInfoParams *const mi_params = &cm->mi_params; - const int ccso_nhfb = - ((mi_params->mi_cols >> xd->plane[plane].subsampling_x) + - (1 << log2_filter_unit_size >> 2) - 1) / - (1 << log2_filter_unit_size >> 2); - bool cur_filter_enabled = false; - int sb_idx = 0; + bool *filter_enable) { + const CcsoCtxCommon *s = &ctx->ccso_cm; + const bool *m_filter_control = ctx->filter_control; + const int plane = s->plane; + const int ccso_blk_size = s->ccso_blk_size; + const int ccso_nhfb = s->ccso_nhfb; const int ss_x = xd->plane[plane].subsampling_x; const int ss_y = xd->plane[plane].subsampling_y; const int sb_unit_size_x = - (1 << log2_filter_unit_size >> (MI_SIZE_LOG2 - ss_x)); + (1 << s->log2_filter_unit_size_x >> (MI_SIZE_LOG2 - ss_x)); const int sb_unit_size_y = - (1 << log2_filter_unit_size >> (MI_SIZE_LOG2 - ss_y)); + (1 << s->log2_filter_unit_size_y >> (MI_SIZE_LOG2 - ss_y)); const CommonTileParams *const tiles = &cm->tiles; const int tile_cols = tiles->cols; const int tile_rows = tiles->rows; const int blk_size_y = (1 << (ccso_blk_size - MI_SIZE_LOG2)) - 1; const int blk_size_x = (1 << (ccso_blk_size - MI_SIZE_LOG2)) - 1; + bool cur_filter_enabled = false; + int sb_idx = 0; *cur_total_dist = 0; *cur_total_rate = 0; @@ -917,9 +921,9 @@ static void get_sb_reuse_dist(AV2_COMMON *cm, MACROBLOCKD *xd, const int plane, if (!(*filter_enable)) continue; if (m_filter_control[sb_idx]) - ssd = training_dist[sb_idx]; + ssd = ctx->training_dist_block[sb_idx]; else - ssd = unfiltered_dist[sb_idx]; + ssd = s->unfiltered_dist_block[sb_idx]; ssd = ROUND_POWER_OF_TWO(ssd, (xd->bd - 8) * 2); @@ -937,29 +941,19 @@ static void get_sb_reuse_dist(AV2_COMMON *cm, MACROBLOCKD *xd, const int plane, /* Compute the residual for each entry of the LUT using CCSO enabled filter * blocks */ -static void ccso_compute_class_err(CcsoCtx *ctx, AV2_COMMON *cm, - const int plane, MACROBLOCKD *xd, - const int max_band_log2, - const int max_edge_interval, - const uint8_t ccso_bo_only) { - const CommonModeInfoParams *const mi_params = &cm->mi_params; - const int ccso_blk_size = get_ccso_unit_size_log2_adaptive_tile( - cm, cm->mib_size_log2 + MI_SIZE_LOG2, CCSO_BLK_SIZE); - const int blk_log2 = ccso_blk_size - xd->plane[plane].subsampling_y; - const int nvfb = ((mi_params->mi_rows >> xd->plane[plane].subsampling_y) + - (1 << blk_log2 >> MI_SIZE_LOG2) - 1) / - (1 << blk_log2 >> MI_SIZE_LOG2); - const int nhfb = ((mi_params->mi_cols >> xd->plane[plane].subsampling_x) + - (1 << blk_log2 >> MI_SIZE_LOG2) - 1) / - (1 << blk_log2 >> MI_SIZE_LOG2); - const int fb_count = nvfb * nhfb; +static void ccso_compute_class_err(CcsoCtx *ctx) { + const int max_edge_interval = ctx->max_edge_interval; + const int fb_count = ctx->ccso_cm.sb_count; + const int max_band = 1 << ctx->max_band_log2; + av2_zero_array(ctx->chroma_error, max_band * 16); + av2_zero_array(ctx->chroma_count, max_band * 16); for (int fb_idx = 0; fb_idx < fb_count; fb_idx++) { if (!ctx->filter_control[fb_idx]) continue; - if (ccso_bo_only) { + if (ctx->ccso_bo_only) { int d0 = 0; int d1 = 0; - for (int band_num = 0; band_num < (1 << max_band_log2); band_num++) { + for (int band_num = 0; band_num < max_band; band_num++) { const int lut_idx_ext = (band_num << 4) + (d0 << 2) + d1; ctx->chroma_error[lut_idx_ext] += ctx->total_class_err_bo[band_num][fb_idx]; @@ -969,7 +963,7 @@ static void ccso_compute_class_err(CcsoCtx *ctx, AV2_COMMON *cm, } else { for (int d0 = 0; d0 < max_edge_interval; d0++) { for (int d1 = 0; d1 < max_edge_interval; d1++) { - for (int band_num = 0; band_num < (1 << max_band_log2); band_num++) { + for (int band_num = 0; band_num < max_band; band_num++) { const int lut_idx_ext = (band_num << 4) + (d0 << 2) + d1; ctx->chroma_error[lut_idx_ext] += ctx->total_class_err[d0][d1][band_num][fb_idx]; @@ -983,24 +977,22 @@ static void ccso_compute_class_err(CcsoCtx *ctx, AV2_COMMON *cm, } /* Count the bits for signaling the offset index */ -static INLINE int count_lut_bits(int8_t *temp_filter_offset, int scale_idx, - const int max_band_log2, - const int max_edge_interval, - const uint8_t ccso_bo_only) { +static INLINE int count_lut_bits(const CcsoCtx *ctx, + const int8_t *filter_offset) { int ccso_offset_reordered[8] = { 0, 1, -1, 3, -3, 7, -7, -10 }; for (int idx = 0; idx < 8; ++idx) ccso_offset_reordered[idx] = - ccso_offset_reordered[idx] * ccso_scale[scale_idx]; + ccso_offset_reordered[idx] * ccso_scale[ctx->scale_idx]; int temp_bits = 0; - int num_edge_offset_intervals = ccso_bo_only ? 1 : max_edge_interval; + int num_edge_offset_intervals = + ctx->ccso_bo_only ? 1 : ctx->max_edge_interval; for (int d0 = 0; d0 < num_edge_offset_intervals; d0++) { for (int d1 = 0; d1 < num_edge_offset_intervals; d1++) { - for (int band_num = 0; band_num < (1 << max_band_log2); band_num++) { + for (int band_num = 0; band_num < (1 << ctx->max_band_log2); band_num++) { const int lut_idx_ext = (band_num << 4) + (d0 << 2) + d1; for (int idx = 0; idx < 7; ++idx) { temp_bits++; - if (ccso_offset_reordered[idx] == temp_filter_offset[lut_idx_ext]) - break; + if (ccso_offset_reordered[idx] == filter_offset[lut_idx_ext]) break; } } } @@ -1009,28 +1001,26 @@ static INLINE int count_lut_bits(int8_t *temp_filter_offset, int scale_idx, } /* Derive the offset value in the look-up table */ -static void derive_lut_offset(int8_t *temp_filter_offset, int scale_idx, - const int max_band_log2, - const int max_edge_interval, - const uint8_t ccso_bo_only, - const int chroma_count[CCSO_BAND_NUM * 16], - const int chroma_error[CCSO_BAND_NUM * 16]) { +static void derive_lut_offset(CcsoCtx *ctx, int8_t *filter_offset) { + const int *chroma_count = ctx->chroma_count; float temp_offset = 0; - int num_edge_offset_intervals = ccso_bo_only ? 1 : max_edge_interval; + int num_edge_offset_intervals = + ctx->ccso_bo_only ? 1 : ctx->max_edge_interval; int this_ccso_offset[8] = { 0 }; + av2_zero_array(filter_offset, (1 << ctx->max_band_log2) * 16); for (int idx = 0; idx < 8; ++idx) - this_ccso_offset[idx] = ccso_offset[idx] * ccso_scale[scale_idx]; + this_ccso_offset[idx] = ccso_offset[idx] * ccso_scale[ctx->scale_idx]; for (int d0 = 0; d0 < num_edge_offset_intervals; d0++) { for (int d1 = 0; d1 < num_edge_offset_intervals; d1++) { - for (int band_num = 0; band_num < (1 << max_band_log2); band_num++) { + for (int band_num = 0; band_num < (1 << ctx->max_band_log2); band_num++) { const int lut_idx_ext = (band_num << 4) + (d0 << 2) + d1; if (chroma_count[lut_idx_ext]) { temp_offset = - (float)chroma_error[lut_idx_ext] / chroma_count[lut_idx_ext]; + (float)ctx->chroma_error[lut_idx_ext] / chroma_count[lut_idx_ext]; if ((temp_offset < this_ccso_offset[0]) || (temp_offset >= this_ccso_offset[7])) { - temp_filter_offset[lut_idx_ext] = clamp( + filter_offset[lut_idx_ext] = clamp( (int)temp_offset, this_ccso_offset[0], this_ccso_offset[7]); } else { for (int offset_idx = 0; offset_idx < 7; offset_idx++) { @@ -1038,11 +1028,9 @@ static void derive_lut_offset(int8_t *temp_filter_offset, int scale_idx, (temp_offset <= this_ccso_offset[offset_idx + 1])) { if (fabs(temp_offset - this_ccso_offset[offset_idx]) > fabs(temp_offset - this_ccso_offset[offset_idx + 1])) { - temp_filter_offset[lut_idx_ext] = - this_ccso_offset[offset_idx + 1]; + filter_offset[lut_idx_ext] = this_ccso_offset[offset_idx + 1]; } else { - temp_filter_offset[lut_idx_ext] = - this_ccso_offset[offset_idx]; + filter_offset[lut_idx_ext] = this_ccso_offset[offset_idx]; } break; } @@ -1055,10 +1043,10 @@ static void derive_lut_offset(int8_t *temp_filter_offset, int scale_idx, } // Allocates buffers required for ccso parameter rdo search -static void ccso_alloc_search_buffers(AV2_COMMON *cm, MACROBLOCKD *xd, - CcsoCtx *ctx, int sb_count) { - const size_t luma_size = - (size_t)xd->plane[AVM_PLANE_Y].dst.height * ctx->ccso_stride; +void av2_ccso_alloc_search_buffers(AV2_COMMON *cm, CcsoCtx *ctx, + int ccso_stride, int ccso_height, + int sb_count) { + const size_t luma_size = (size_t)ccso_height * ccso_stride; if (sb_count > ctx->alloc_sb_count) { ctx->alloc_sb_count = 0; @@ -1082,10 +1070,6 @@ static void ccso_alloc_search_buffers(AV2_COMMON *cm, MACROBLOCKD *xd, cm, ctx->class_cnt_bo_slab, avm_malloc(sizeof(*ctx->class_cnt_bo_slab) * CCSO_BAND_NUM * sb_count)); - avm_free(ctx->unfiltered_dist_block); - CHECK_MEM_ERROR(cm, ctx->unfiltered_dist_block, - avm_malloc(sb_count * sizeof(*ctx->unfiltered_dist_block))); - avm_free(ctx->training_dist_block); CHECK_MEM_ERROR(cm, ctx->training_dist_block, avm_malloc(sb_count * sizeof(*ctx->training_dist_block))); @@ -1187,7 +1171,6 @@ void av2_ccso_ctx_free(AV2_COMP *cpi) { avm_free(ctx->class_cnt_bo_slab); avm_free(ctx->reuse_class_err_slab); avm_free(ctx->reuse_class_cnt_slab); - avm_free(ctx->unfiltered_dist_block); avm_free(ctx->training_dist_block); avm_free(ctx->filter_control); avm_free(ctx->best_filter_control); @@ -1195,6 +1178,7 @@ void av2_ccso_ctx_free(AV2_COMP *cpi) { avm_free(ctx->temp_rec_uv_buf); avm_free(ctx->src_cls0); avm_free(ctx->src_cls1); + avm_free(cpi->unfiltered_dist_block); avm_free(cpi->ccso_ext_rec_y); for (int plane = 0; plane < CCSO_NUM_COMPONENTS; ++plane) { avm_free(cpi->ccso_rec_uv[plane]); @@ -1202,6 +1186,317 @@ void av2_ccso_ctx_free(AV2_COMP *cpi) { } } +// Runs the RD-cost training loop for one (candidate, reuse_ccso_idx, +// ref_idx, sb_reuse_idx) combination and updates s->best if it improves +// on the current best for this max_band_log2 iteration. +static AVM_INLINE void run_training(AV2_COMMON *cm, CcsoCtx *ctx, + MACROBLOCKD *xd) { + CcsoCtxCommon *s = &ctx->ccso_cm; + int8_t *const filter_offset = ctx->filter_offset; + const int plane = s->plane; + int training_iter_count = 0; + bool ccso_enable = true; + bool keep_training = true; + bool improvement = false; + uint64_t filtered_dist_frame; + uint64_t prev_total_cost = UINT64_MAX; + + while (keep_training) { + improvement = false; + + if (!ctx->skip_filter_calculation) { + if (ccso_enable) { + if (!ctx->reuse_ccso_idx) { + ccso_compute_class_err(ctx); + derive_lut_offset(ctx, filter_offset); + } else { + const int max_band = 1 << ctx->max_band_log2; + av2_copy_array(filter_offset, + ctx->ref_frame_ccso_info->filter_offset[plane], + max_band * 16); + } + } + av2_copy_array(ctx->temp_rec_uv_buf, s->rec_uv, + xd->plane[plane].dst.height * ctx->ccso_stride); + if (plane > 0) + ccso_try_chroma_filter(cm, ctx, xd, filter_offset); + else + ccso_try_luma_filter(cm, ctx, xd, filter_offset); + + compute_distortion(cm, ctx, xd, ctx->temp_rec_uv_buf, + ctx->training_dist_block, &filtered_dist_frame); + } + + uint64_t cur_total_dist = 0; + int cur_total_rate = 0; + + if (ctx->sb_reuse_idx) { + get_sb_reuse_dist(cm, ctx, xd, &cur_total_dist, &cur_total_rate, + &ccso_enable); + cur_total_rate = av2_cost_literal( + ctx->reuse_ccso_idx ? 0 : avm_ceil_log2(s->num_ref_frames)); + } else { + derive_blk_md(cm, ctx, xd, &cur_total_dist, &cur_total_rate, + &ccso_enable); + } + + if (ccso_enable) { + const int lut_bits = count_lut_bits(ctx, filter_offset); + int cur_total_bits = lut_bits + (ctx->ccso_bo_only ? s->frame_bits_bo_only + : s->frame_bits); + + if (!ctx->ccso_bo_only && !quant_sz[ctx->scale_idx][ctx->quant_idx]) { + // remove one frame bit for quant sz is 0 case + cur_total_bits -= 1; + } + + cur_total_rate += + (ctx->reuse_ccso_idx + ? av2_cost_literal(2 + avm_ceil_log2(s->num_ref_frames)) + : av2_cost_literal(cur_total_bits)); + const uint64_t cur_total_cost = + RDCOST(s->rdmult, cur_total_rate, cur_total_dist * 16); + if (cur_total_cost < prev_total_cost) { + prev_total_cost = cur_total_cost; + improvement = true; + } + if (cur_total_cost < ctx->best.filtered_cost) { + ctx->best.filtered_cost = cur_total_cost; + ctx->best.reuse_ccso = ctx->reuse_ccso_idx; + ctx->best.sb_reuse_ccso = ctx->sb_reuse_idx; + ctx->best.quant_idx = ctx->quant_idx; + ctx->best.scale_idx = ctx->scale_idx; + ctx->best.ext_filter_support = ctx->ext_filter_support; + ctx->best.ccso_bo_only = ctx->ccso_bo_only; + ctx->best.ref_idx = ctx->ref_idx - 1; + av2_copy_array(ctx->best.filter_offset, filter_offset, + (1 << ctx->max_band_log2) * 16); + ctx->best.edge_classifier = ctx->edge_clf; + ctx->best.band_log2 = ctx->max_band_log2; + av2_copy_array(ctx->best_filter_control, ctx->filter_control, + s->sb_count); + } + } + + training_iter_count++; + if (!improvement || training_iter_count > CCSO_MAX_ITERATIONS || + ctx->sb_reuse_idx || ctx->reuse_ccso_idx) { + keep_training = false; + } + } +} + +// Tries sb_reuse_idx = 0 (fresh per-superblock enable decision) and, when +// s->check_sb_reuse allows it, sb_reuse_idx = 1 (reuse s->ref_frame_ccso_info's +// per-superblock pattern instead). +static AVM_INLINE void search_sb_reuse_idx(AV2_COMMON *cm, CcsoCtx *ctx, + MACROBLOCKD *xd) { + CcsoCtxCommon *s = &ctx->ccso_cm; + + for (uint8_t sb_reuse_idx = 0; sb_reuse_idx <= ctx->check_sb_reuse; + ++sb_reuse_idx) { + if (sb_reuse_idx == 0 && ctx->reuse_ccso_idx == 0 && ctx->ref_idx > 0) + continue; + + ctx->sb_reuse_idx = sb_reuse_idx; + + if (sb_reuse_idx) { + // Overwrite filter control + av2_copy_array(ctx->filter_control, + ctx->ref_frame_ccso_info->sb_filter_control[s->plane], + s->sb_count); + } else { + int control_idx = 0; + for (int y = 0; y < s->ccso_nvfb; y++) { + for (int x = 0; x < s->ccso_nhfb; x++) { + ctx->filter_control[control_idx++] = 1; + } + } + } + + run_training(cm, ctx, xd); + } +} + +// Tries ref_idx = 0 (no reference reuse) and each valid reference frame +// index for s->reuse_ccso_idx +static AVM_INLINE void search_ref_idx(AV2_COMMON *cm, CcsoCtx *ctx, + MACROBLOCKD *xd) { + CcsoCtxCommon *s = &ctx->ccso_cm; + const int plane = s->plane; + const int ccso_blk_size = s->ccso_blk_size; + const int ss_x = xd->plane[plane].subsampling_x; + const int ss_y = xd->plane[plane].subsampling_y; + const uint8_t reuse_ccso_idx = ctx->reuse_ccso_idx; + RefCntBuffer *ref_frame = NULL; + CcsoInfo *ccso_info = NULL; + + for (int ref_idx = 0; ref_idx <= s->num_ref_frames; ref_idx++) { + ctx->ref_frame_ccso_info = NULL; + + if (reuse_ccso_idx > 0 && ref_idx == 0) continue; + // do not use BRU frame as ref for now + if (ref_idx == cm->bru.update_ref_idx) continue; + + if (ref_idx > 0) { + ref_frame = get_ref_frame_buf(cm, ref_idx - 1); + if (ref_frame->is_restricted) continue; + + ccso_info = &ref_frame->ccso_info; + if (!ccso_info->ccso_enable[plane]) continue; + + ctx->ref_frame_ccso_info = ccso_info; + + int repeat_ref = 0; + for (int idx = 0; idx < ctx->checked_reuse_ref_idx[reuse_ccso_idx]; + idx++) { + if (ctx->checked_reuse_ref[reuse_ccso_idx][idx] == + ccso_info->reuse_root_ref[plane]) { + repeat_ref = 1; + break; + } + } + if (repeat_ref) continue; + + const int slot = ctx->checked_reuse_ref_idx[reuse_ccso_idx]; + ctx->checked_reuse_ref[reuse_ccso_idx][slot] = + ctx->ref_frame_ccso_info->reuse_root_ref[plane]; + ctx->checked_reuse_ref_idx[reuse_ccso_idx]++; + } + + ctx->ref_idx = ref_idx; + + if (reuse_ccso_idx) { + if (ccso_info == NULL || + !((ctx->scale_idx == ccso_info->scale_idx[plane]) && + (ctx->ccso_bo_only == ccso_info->ccso_bo_only[plane]) && + (ctx->ext_filter_support == ccso_info->ext_filter_support[plane]) && + (ctx->quant_idx == ccso_info->quant_idx[plane]) && + (ctx->edge_clf == ccso_info->edge_clf[plane]) && + (ctx->max_band_log2 == ccso_info->max_band_log2[plane]))) { + continue; + } + } + + ctx->check_sb_reuse = s->check_ccso && (ccso_info != NULL) && + (cm->mi_params.mi_rows == ref_frame->mi_rows) && + (cm->mi_params.mi_cols == ref_frame->mi_cols) && + (ss_y == ccso_info->subsampling_y[plane]) && + (ss_x == ccso_info->subsampling_x[plane]) && + (ccso_blk_size == ccso_info->ccso_blk_size) && + (ccso_blk_size == CCSO_BLK_SIZE); + + search_sb_reuse_idx(cm, ctx, xd); + + if (reuse_ccso_idx == 0) ctx->skip_filter_calculation = true; + } +} + +// Evaluates new filter / reference frame's already-derived filter for the +// current candidate +static AVM_INLINE void search_reuse_ccso_idx(AV2_COMMON *cm, CcsoCtx *ctx, + MACROBLOCKD *xd) { + for (int reuse_ccso_idx = 0; reuse_ccso_idx <= 1; reuse_ccso_idx++) { + ctx->reuse_ccso_idx = reuse_ccso_idx; + ctx->skip_filter_calculation = false; + search_ref_idx(cm, ctx, xd); + } +} + +// Evaluates every max_band_log2 value for the current +// (scale_idx, so mode, filter_support, quant_idx, edge_clf) candidate, +// updates ctx->final whenever a new frame-wide best is found. +static AVM_INLINE bool search_max_band_log2(AV2_COMMON *cm, CcsoCtx *ctx, + MACROBLOCKD *xd) { + CcsoCtxCommon *s = &ctx->ccso_cm; + + for (int max_band_log2 = 0; max_band_log2 < ctx->num_band_iter; + max_band_log2++) { + ctx->max_band_log2 = max_band_log2; + ctx->shift_bits = cm->seq_params.bit_depth - max_band_log2; + if (ctx->ccso_bo_only) { + ccso_pre_compute_class_err_bo(cm, ctx, xd); + } else { + if (ctx->init_shift_bits != ctx->shift_bits || + !reuse_ccso_class_info(cm)) { + ccso_pre_compute_class_err(cm, ctx, xd); + } else { + const int max_band = 1 << max_band_log2; + + for (int d0 = 0; d0 < ctx->max_edge_interval; d0++) { + for (int d1 = 0; d1 < ctx->max_edge_interval; d1++) { + av2_copy_array(ctx->total_class_err[d0][d1][0], + ctx->reuse_total_class_err[d0][d1][0], + max_band * s->sb_count); + av2_copy_array(ctx->total_class_cnt[d0][d1][0], + ctx->reuse_total_class_cnt[d0][d1][0], + max_band * s->sb_count); + } + } + } + } + + memset(ctx->checked_reuse_ref, -1, sizeof(ctx->checked_reuse_ref)); + av2_zero_array(ctx->checked_reuse_ref_idx, 2); + ctx->best.filtered_cost = UINT64_MAX; + + search_reuse_ccso_idx(cm, ctx, xd); + + if (ctx->best.filtered_cost < ctx->final.filtered_cost) { + ctx->final = ctx->best; + av2_copy_array(ctx->final_filter_control, ctx->best_filter_control, + s->sb_count); + } + if (s->early_terminate_ccso_search && + ctx->final.filtered_cost != UINT64_MAX && + 1.001 * ctx->final.filtered_cost > ctx->last_best_cost) { + return true; + } + } + return false; +} + +// Evaluates edge_clf0 and edge_clf1 for the current (scale_idx, so mode, +// filter, qstep) candidate. +static AVM_INLINE bool search_edge_clf(AV2_COMMON *cm, CcsoCtx *ctx, + MACROBLOCKD *xd) { + const int num_edge_clf_iter = ctx->ccso_bo_only ? 1 : 2; + const int total_band_log2_plus1 = ctx->ccso_bo_only ? 7 : 4; + const int total_band_log2 = total_band_log2_plus1 - 1; + + ctx->num_band_iter = total_band_log2_plus1; + for (int edge_clf = 0; edge_clf < num_edge_clf_iter; edge_clf++) { + ctx->edge_clf = edge_clf; + ctx->max_edge_interval = edge_clf_to_edge_interval[edge_clf]; + ctx->last_best_cost = ctx->final.filtered_cost; + + if (quant_sz[ctx->scale_idx][ctx->quant_idx] == 0 && edge_clf == 1) { + continue; + } + if (!ctx->ccso_bo_only) { + ccso_derive_src_info(cm, ctx, xd); + + // compute the total_class_err for minimum shift_bits possible before the + // below loop starts, later use the same in the ccso_pre_compute_class_err + // calls. + ctx->init_shift_bits = cm->seq_params.bit_depth - total_band_log2; + ctx->shift_bits = ctx->init_shift_bits; + ccso_pre_compute_class_err(cm, ctx, xd); + } + + if (search_max_band_log2(cm, ctx, xd)) return true; + } + return false; +} + +// For a given [plane, scale_idx, so mode, eo switchable filter type, qstep], +// this function performs rdo search across all eo classifier types, max bands, +// reference's ccso filter offsets / new filter offsets and selects params with +// best rdo. +bool av2_ccso_param_search(AV2_COMMON *cm, CcsoCtx *ctx, MACROBLOCKD *xd) { + return search_edge_clf(cm, ctx, xd); +} + // Writes val into the MB_MODE_INFO field that stores CCSO's per-block // enable state for `plane`. static void set_mbmi_ccso_blk(MB_MODE_INFO *mbmi, int plane, uint8_t val) { @@ -1214,29 +1509,172 @@ static void set_mbmi_ccso_blk(MB_MODE_INFO *mbmi, int plane, uint8_t val) { } } +static void finalize_ccso_plane(AV2_COMMON *cm, CcsoCtx *ctx, ThreadData *td, + int disable_ccso) { + CcsoInfo *cur_frame_ccso_info = &cm->cur_frame->ccso_info; + CcsoCtxCommon *s = &ctx->ccso_cm; + CcsoCandidate *final = &ctx->final; + MACROBLOCKD *const xd = &td->mb.e_mbd; + const int plane = s->plane; + const int ss_x = xd->plane[plane].subsampling_x; + const int ss_y = xd->plane[plane].subsampling_y; + + cur_frame_ccso_info->subsampling_x[plane] = ss_x; + cur_frame_ccso_info->subsampling_y[plane] = ss_y; + if (disable_ccso) { + av2_zero_array(ctx->final_filter_control, s->sb_count); + cm->ccso_info.ccso_enable[plane] = false; + av2_zero_array(cur_frame_ccso_info->sb_filter_control[plane], s->sb_count); + cm->cur_frame->ccso_info.ccso_enable[plane] = false; + return; + } + + cm->ccso_info.ccso_enable[plane] = true; + cm->ccso_info.sb_reuse_ccso[plane] = final->sb_reuse_ccso; + cm->ccso_info.reuse_ccso[plane] = final->reuse_ccso; + CcsoInfo *ref_frame_ccso_info = NULL; + if (final->reuse_ccso || final->sb_reuse_ccso) { + RefCntBuffer *const ref_frame = get_ref_frame_buf(cm, final->ref_idx); + assert(ref_frame != NULL); + ref_frame_ccso_info = &ref_frame->ccso_info; + cm->ccso_info.ccso_ref_idx[plane] = final->ref_idx; + } + cur_frame_ccso_info->ccso_enable[plane] = true; + cur_frame_ccso_info->ccso_blk_size = s->ccso_blk_size; + cur_frame_ccso_info->reuse_root_ref[plane] = + cm->current_frame.display_order_hint; + + CommonModeInfoParams *const mi_params = &cm->mi_params; + bool *cur_frame_filter_control = + cur_frame_ccso_info->sb_filter_control[plane]; + const BLOCK_SIZE bsize = xd->mi[0]->sb_type[PLANE_TYPE_Y]; + const int f_w = 1 << s->ccso_blk_size >> MI_SIZE_LOG2; + const int f_h = 1 << s->ccso_blk_size >> MI_SIZE_LOG2; + const int step_h = (mi_size_high[bsize] + f_h - 1) / f_h; + const int step_w = (mi_size_wide[bsize] + f_w - 1) / f_w; + const int sb_unit_size_x = + (1 << s->log2_filter_unit_size_x >> (MI_SIZE_LOG2 - ss_x)); + const int sb_unit_size_y = + (1 << s->log2_filter_unit_size_y >> (MI_SIZE_LOG2 - ss_y)); + const int ccso_mib_size_y = (1 << (s->ccso_blk_size - MI_SIZE_LOG2)); + const int ccso_mib_size_x = (1 << (s->ccso_blk_size - MI_SIZE_LOG2)); + + if (!final->sb_reuse_ccso) { + for (int y_sb = 0; y_sb < s->ccso_nvfb; y_sb += step_h) { + for (int x_sb = 0; x_sb < s->ccso_nhfb; x_sb += step_w) { + const bool sb_filter_control = + ctx->final_filter_control[y_sb * s->ccso_nhfb + x_sb]; + for (int row = y_sb; row < y_sb + step_h; row++) { + for (int col = x_sb; col < x_sb + step_w; col++) { + cur_frame_filter_control[row * s->ccso_nhfb + col] = + sb_filter_control; + + const int mi_row = f_h * row; + const int mi_col = f_w * col; + int grid_idx = mi_row * mi_params->mi_stride + mi_col; + MB_MODE_INFO *mbmi = mi_params->mi_grid_base[grid_idx]; + + // for tile skip, no valid mi exist + if (cm->bru.enabled && + bru_is_fu_skipped_mbmi(cm, sb_unit_size_x * col, + sb_unit_size_y * row, f_w, f_h)) { + assert(sb_filter_control == 0); + } + set_mbmi_ccso_blk(mbmi, plane, sb_filter_control); + + for (int j = 0; + j < AVMMIN(ccso_mib_size_y, mi_params->mi_rows - mi_row); + j++) { + for (int k = 0; + k < AVMMIN(ccso_mib_size_x, mi_params->mi_cols - mi_col); + k++) { + grid_idx = get_mi_grid_idx(mi_params, mi_row + j, mi_col + k); + mbmi = mi_params->mi_grid_base[grid_idx]; + set_mbmi_ccso_blk(mbmi, plane, sb_filter_control); + } + } + } + } + +#if CONFIG_ENTROPY_STATS + const int ccso_ctx = get_ccso_context(y_sb, x_sb, s->ccso_nhfb, + ctx->final_filter_control); + + ++td->counts->default_ccso_cnts + [plane][ccso_ctx] + [ctx->final_filter_control[y_sb * s->ccso_nhfb + x_sb]]; +#endif + } + } + } else { + assert(ref_frame_ccso_info != NULL); + bool *ref_frame_filter_control = + ref_frame_ccso_info->sb_filter_control[plane]; + av2_copy_array(cur_frame_filter_control, ref_frame_filter_control, + s->sb_count); + for (int y_sb = 0; y_sb < s->ccso_nvfb; y_sb++) { + for (int x_sb = 0; x_sb < s->ccso_nhfb; x_sb++) { + int grid_idx = f_h * y_sb * mi_params->mi_stride + f_w * x_sb; + MB_MODE_INFO *mbmi = mi_params->mi_grid_base[grid_idx]; + bool filter_control = + ref_frame_filter_control[y_sb * s->ccso_nhfb + x_sb]; + set_mbmi_ccso_blk(mbmi, plane, filter_control); + } + } + } + if (!cm->ccso_info.reuse_ccso[plane]) { + av2_copy_array(cm->ccso_info.filter_offset[plane], final->filter_offset, + (1 << final->band_log2) * 16); + cm->ccso_info.quant_idx[plane] = final->quant_idx; + cm->ccso_info.scale_idx[plane] = final->scale_idx; + cm->ccso_info.ext_filter_support[plane] = final->ext_filter_support; + cm->ccso_info.ccso_bo_only[plane] = final->ccso_bo_only; + cm->ccso_info.max_band_log2[plane] = final->band_log2; + cm->ccso_info.edge_clf[plane] = final->edge_classifier; + + av2_copy_array(cur_frame_ccso_info->filter_offset[plane], + final->filter_offset, (1 << final->band_log2) * 16); + cur_frame_ccso_info->quant_idx[plane] = final->quant_idx; + cur_frame_ccso_info->scale_idx[plane] = final->scale_idx; + cur_frame_ccso_info->ext_filter_support[plane] = final->ext_filter_support; + cur_frame_ccso_info->ccso_bo_only[plane] = final->ccso_bo_only; + cur_frame_ccso_info->max_band_log2[plane] = final->band_log2; + cur_frame_ccso_info->edge_clf[plane] = final->edge_classifier; + } else { + av2_copy_ccso_filters(&cm->ccso_info, ref_frame_ccso_info, plane, 1, 0, + s->sb_count); + av2_copy_ccso_filters(cur_frame_ccso_info, ref_frame_ccso_info, plane, 1, 0, + s->sb_count); + } + + if (final->reuse_ccso && final->sb_reuse_ccso) { + assert(ref_frame_ccso_info != NULL); + cur_frame_ccso_info->reuse_root_ref[plane] = + ref_frame_ccso_info->reuse_root_ref[plane]; + } +} + /* Derive the look-up table for a color component */ -static void derive_ccso_filter(CcsoCtx *ctx, AV2_COMMON *cm, const int plane, - MACROBLOCKD *xd, const uint16_t *org_uv, +static void derive_ccso_filter(AV2_COMP *cpi, const int plane, + const uint16_t *org_uv, const uint16_t *ext_rec_y, const uint16_t *rec_uv, int rdmult, - bool error_resilient_frame_seen -#if CONFIG_ENTROPY_STATS - , - ThreadData *td -#endif - , + bool error_resilient_frame_seen, int early_terminate_ccso_search) { + AV2_COMMON *const cm = &cpi->common; + ThreadData *td = &cpi->td; + MACROBLOCKD *const xd = &td->mb.e_mbd; + const int ccso_stride = xd->plane[AVM_PLANE_Y].dst.width; const CommonModeInfoParams *const mi_params = &cm->mi_params; const int ss_x = xd->plane[plane].subsampling_x; const int ss_y = xd->plane[plane].subsampling_y; - const int ccso_blk_size = get_ccso_unit_size_log2_adaptive_tile( cm, cm->mib_size_log2 + MI_SIZE_LOG2, CCSO_BLK_SIZE); cm->ccso_info.ccso_blk_size = ccso_blk_size; - const int log2_filter_unit_size_y = ccso_blk_size - ss_y; const int log2_filter_unit_size_x = ccso_blk_size - ss_x; - + const int log2_proc_unit_size = + cm->mib_size_log2 - AVMMAX(ss_x, ss_y) + MI_SIZE_LOG2; const int ccso_nvfb = ((mi_params->mi_rows >> ss_y) + (1 << log2_filter_unit_size_y >> 2) - 1) / (1 << log2_filter_unit_size_y >> 2); @@ -1245,45 +1683,9 @@ static void derive_ccso_filter(CcsoCtx *ctx, AV2_COMMON *cm, const int plane, (1 << log2_filter_unit_size_x >> 2); const int sb_count = ccso_nvfb * ccso_nhfb; - // Use cropped dimensions for derivation of ccso filter coeffs at encoder - const int pic_height_c = xd->plane[plane].dst.crop_height; - const int pic_width_c = xd->plane[plane].dst.crop_width; - - const int sb_unit_size_x = - (1 << log2_filter_unit_size_x >> (MI_SIZE_LOG2 - ss_x)); - const int sb_unit_size_y = - (1 << log2_filter_unit_size_y >> (MI_SIZE_LOG2 - ss_y)); - - ccso_alloc_search_buffers(cm, xd, ctx, sb_count); - - compute_distortion(org_uv, ctx->ccso_stride, rec_uv, ctx->ccso_stride, - log2_filter_unit_size_y, log2_filter_unit_size_x, - cm->mib_size_log2 - AVMMAX(ss_x, ss_y) + MI_SIZE_LOG2, cm, - ss_y, ss_x, pic_height_c, pic_width_c, - ctx->unfiltered_dist_block, ccso_nhfb, - &ctx->unfiltered_dist_frame); - ctx->unfiltered_dist_frame = - ROUND_POWER_OF_TWO(ctx->unfiltered_dist_frame, (xd->bd - 8) * 2); - const uint64_t best_unfiltered_cost = - RDCOST(rdmult, av2_cost_literal(1), ctx->unfiltered_dist_frame * 16); - const int total_scale_idx = 4; const int total_filter_support = 7; const int total_quant_idx = 4; - const int total_edge_classifier = 2; - const int total_band_log2_plus1 = 4; - - int best_reuse_ccso = 0; - int best_sb_reuse_ccso = 0; - int best_ref_idx = -1; - uint8_t best_edge_classifier = 0; - uint64_t best_filtered_cost; - - int final_ref_idx = -1; - uint8_t final_edge_classifier = 0; - uint64_t final_filtered_cost = UINT64_MAX; - - int8_t filter_offset[CCSO_BAND_NUM * 16]; uint8_t frame_bits = 1; // ccso_planes[ plane ] frame_bits += 1; // ccso_bo_only[ plane ] @@ -1316,16 +1718,54 @@ static void derive_ccso_filter(CcsoCtx *ctx, AV2_COMMON *cm, const int plane, check_ccso = 1; } - RefCntBuffer *ref_frame = NULL; - CcsoInfo *ref_frame_ccso_info = NULL; - int init_shift_bits = -1; - - cm->cur_frame->ccso_info.ccso_enable[plane] = false; - - memset(cm->cur_frame->ccso_info.sb_filter_control[plane], 0, - sizeof(*cm->cur_frame->ccso_info.sb_filter_control[plane]) * sb_count); + if (cpi->unfiltered_dist_block == NULL || + sb_count > cpi->unfiltered_dist_block_alloc_sb_count) { + avm_free(cpi->unfiltered_dist_block); + CHECK_MEM_ERROR(cm, cpi->unfiltered_dist_block, + avm_malloc(sb_count * sizeof(*cpi->unfiltered_dist_block))); + cpi->unfiltered_dist_block_alloc_sb_count = sb_count; + } + // alloc ccso search context + CcsoCtx *ctx = &cpi->ccso_ctx; + ccso_ctx_reset(ctx); + av2_ccso_alloc_search_buffers(cm, ctx, ccso_stride, + xd->plane[AVM_PLANE_Y].dst.height, sb_count); + + // init ccso search context + CcsoCtxCommon *ccso_cm = &ctx->ccso_cm; + ccso_cm->org_uv = org_uv; + ccso_cm->ext_rec_y = ext_rec_y; + ccso_cm->rec_uv = rec_uv; + ccso_cm->unfiltered_dist_block = cpi->unfiltered_dist_block; + ccso_cm->plane = plane; + ccso_cm->rdmult = rdmult; + ccso_cm->ccso_blk_size = ccso_blk_size; + ccso_cm->log2_filter_unit_size_x = log2_filter_unit_size_x; + ccso_cm->log2_filter_unit_size_y = log2_filter_unit_size_y; + ccso_cm->log2_proc_unit_size = log2_proc_unit_size; + ccso_cm->ccso_nvfb = ccso_nvfb; + ccso_cm->ccso_nhfb = ccso_nhfb; + ccso_cm->sb_count = sb_count; + ccso_cm->frame_bits = frame_bits; + ccso_cm->frame_bits_bo_only = frame_bits_bo_only; + ccso_cm->check_ccso = check_ccso; + ccso_cm->num_ref_frames = num_ref_frames; + ccso_cm->early_terminate_ccso_search = early_terminate_ccso_search; + + ctx->final.filtered_cost = UINT64_MAX; + ctx->final.ref_idx = -1; + ctx->ccso_stride = ccso_stride; + ctx->ccso_stride_ext = ccso_stride + (CCSO_PADDING_SIZE << 1); + + uint64_t unfiltered_dist_frame; + compute_distortion(cm, ctx, xd, rec_uv, cpi->unfiltered_dist_block, + &unfiltered_dist_frame); + unfiltered_dist_frame = + ROUND_POWER_OF_TWO(unfiltered_dist_frame, (xd->bd - 8) * 2); + const uint64_t best_unfiltered_cost = + RDCOST(rdmult, av2_cost_literal(1), unfiltered_dist_frame * 16); - for (int scale_idx = 0; scale_idx < total_scale_idx; ++scale_idx) { + for (uint8_t scale_idx = 0; scale_idx < total_scale_idx; ++scale_idx) { for (uint8_t search_idx = 0; search_idx < 2; search_idx++) { // A BO-only candidate is cheaper and covers a different part of the // search space. Under early termination, evaluate it first so the full @@ -1333,508 +1773,38 @@ static void derive_ccso_filter(CcsoCtx *ctx, AV2_COMMON *cm, const int plane, // for exhaustive search, where ordering should not affect the result. const uint8_t ccso_bo_only = early_terminate_ccso_search ? 1 - search_idx : search_idx; - int num_filter_iter = ccso_bo_only ? 1 : total_filter_support; - int num_quant_iter = ccso_bo_only ? 1 : total_quant_idx; - int num_edge_clf_iter = ccso_bo_only ? 1 : total_edge_classifier; - for (int ext_filter_support = 0; ext_filter_support < num_filter_iter; - ext_filter_support++) { - for (int quant_idx = 0; quant_idx < num_quant_iter; quant_idx++) { - for (int edge_clf = 0; edge_clf < num_edge_clf_iter; edge_clf++) { - const int max_edge_interval = edge_clf_to_edge_interval[edge_clf]; - uint64_t last_best_cost = final_filtered_cost; - - if (quant_sz[scale_idx][quant_idx] == 0 && edge_clf == 1) { - continue; - } - if (!ccso_bo_only) { - ccso_derive_src_info( - cm, xd, plane, ext_rec_y, - cm->mib_size_log2 - AVMMAX(ss_x, ss_y) + MI_SIZE_LOG2, - quant_sz[scale_idx][quant_idx], ext_filter_support, - ctx->src_cls0, ctx->src_cls1, edge_clf, ctx->ccso_stride, - ctx->ccso_stride_ext); - // reset so as to populate ccso_pre_compute_class_err data and - // reuse the same - init_shift_bits = -1; - } - int num_band_iter = total_band_log2_plus1; - if (ccso_bo_only) { - num_band_iter = total_band_log2_plus1 + 3; - } - - // compute the total_class_err for minimum shift_bits possible - // before the below loop starts, later use the same in the - // ccso_pre_compute_class_err calls. - if (!ccso_bo_only && (init_shift_bits == -1)) { - init_shift_bits = cm->seq_params.bit_depth - (num_band_iter - 1); - const int max_band = 1 << (num_band_iter - 1); - for (int d0 = 0; d0 < max_edge_interval; d0++) { - for (int d1 = 0; d1 < max_edge_interval; d1++) { - av2_zero_array(ctx->total_class_err[d0][d1][0], - max_band * sb_count); - av2_zero_array(ctx->total_class_cnt[d0][d1][0], - max_band * sb_count); - } - } - ccso_pre_compute_class_err( - ctx, xd, plane, cm, - cm->mib_size_log2 - AVMMAX(ss_x, ss_y) + MI_SIZE_LOG2, - ext_rec_y, org_uv, rec_uv, ctx->src_cls0, ctx->src_cls1, - init_shift_bits, init_shift_bits); - } - - for (int max_band_log2 = 0; max_band_log2 < num_band_iter; - max_band_log2++) { - const int shift_bits = cm->seq_params.bit_depth - max_band_log2; - const int max_band = 1 << max_band_log2; - if (ccso_bo_only) { - memset(ctx->total_class_err_bo[0], 0, - sizeof(*ctx->total_class_err_bo[0]) * CCSO_BAND_NUM * - sb_count); - memset(ctx->total_class_cnt_bo[0], 0, - sizeof(*ctx->total_class_cnt_bo[0]) * CCSO_BAND_NUM * - sb_count); - ccso_pre_compute_class_err_bo( - ctx, xd, plane, cm, - cm->mib_size_log2 - AVMMAX(ss_x, ss_y) + MI_SIZE_LOG2, - ext_rec_y, org_uv, rec_uv, shift_bits); - } else { - for (int d0 = 0; d0 < max_edge_interval; d0++) { - for (int d1 = 0; d1 < max_edge_interval; d1++) { - memset(ctx->total_class_err[d0][d1][0], 0, - sizeof(*ctx->total_class_err[d0][d1][0]) * max_band * - sb_count); - memset(ctx->total_class_cnt[d0][d1][0], 0, - sizeof(*ctx->total_class_cnt[d0][d1][0]) * max_band * - sb_count); - } - } - if ((init_shift_bits != shift_bits) || - !(reuse_ccso_class_info(cm))) { - ccso_pre_compute_class_err( - ctx, xd, plane, cm, - cm->mib_size_log2 - AVMMAX(ss_x, ss_y) + MI_SIZE_LOG2, - ext_rec_y, org_uv, rec_uv, ctx->src_cls0, ctx->src_cls1, - shift_bits, init_shift_bits); - } else { - memcpy(ctx->total_class_err[0][0][0], - ctx->reuse_total_class_err[0][0][0], - sizeof(*ctx->total_class_err[0][0][0]) * - CCSO_CLASS_STATS_ENTRIES * sb_count); - memcpy(ctx->total_class_cnt[0][0][0], - ctx->reuse_total_class_cnt[0][0][0], - sizeof(*ctx->total_class_cnt[0][0][0]) * - CCSO_CLASS_STATS_ENTRIES * sb_count); - } - } - - unsigned int - checked_reuse_ref[2][7]; // used to store the already checked - // ccso parameters to avoid checking - // for a second time. - memset(checked_reuse_ref, -1, - sizeof(checked_reuse_ref[0][0]) * 14); - int checked_reuse_ref_idx[2] = { 0 }; - - best_filtered_cost = UINT64_MAX; - - for (int reuse_ccso_idx = 0; reuse_ccso_idx <= 1; - reuse_ccso_idx++) { - bool skip_filter_calculation = false; - for (int ref_idx = 0; ref_idx <= num_ref_frames; ref_idx++) { - ref_frame_ccso_info = NULL; - if (reuse_ccso_idx > 0 && ref_idx == 0) continue; - // do not use BRU frame as ref for now - if (ref_idx == cm->bru.update_ref_idx) { - continue; - } - - if (ref_idx > 0) { - ref_frame = get_ref_frame_buf(cm, ref_idx - 1); - if (ref_frame->is_restricted) continue; - CcsoInfo *ccso_tmp = &ref_frame->ccso_info; - if (!ccso_tmp->ccso_enable[plane]) { - continue; - } - ref_frame_ccso_info = ccso_tmp; - - int repeat_ref = 0; - for (int idx = 0; - idx < checked_reuse_ref_idx[reuse_ccso_idx]; idx++) { - if (checked_reuse_ref[reuse_ccso_idx][idx] == - ref_frame_ccso_info->reuse_root_ref[plane]) { - repeat_ref = 1; - } - } - if (repeat_ref) continue; - checked_reuse_ref[reuse_ccso_idx] - [checked_reuse_ref_idx[reuse_ccso_idx]++] = - ref_frame_ccso_info - ->reuse_root_ref[plane]; - } - - if (reuse_ccso_idx) { - if (ref_frame_ccso_info == NULL || - !((scale_idx == - ref_frame_ccso_info->scale_idx[plane]) && - (ccso_bo_only == - ref_frame_ccso_info->ccso_bo_only[plane]) && - (ext_filter_support == - ref_frame_ccso_info->ext_filter_support[plane]) && - (quant_idx == - ref_frame_ccso_info->quant_idx[plane]) && - (edge_clf == ref_frame_ccso_info->edge_clf[plane]) && - (max_band_log2 == - ref_frame_ccso_info->max_band_log2[plane]))) { - continue; - } - } - - bool check_sb_reuse = - check_ccso && (ref_frame_ccso_info != NULL) && - (mi_params->mi_rows == ref_frame->mi_rows) && - (mi_params->mi_cols == ref_frame->mi_cols) && - (xd->plane[plane].subsampling_y == - ref_frame_ccso_info->subsampling_y[plane]) && - (xd->plane[plane].subsampling_x == - ref_frame_ccso_info->subsampling_x[plane]) && - (ccso_blk_size == ref_frame_ccso_info->ccso_blk_size) && - (ccso_blk_size == CCSO_BLK_SIZE); - - for (int sb_reuse_idx = 0; sb_reuse_idx <= check_sb_reuse; - ++sb_reuse_idx) { - if (sb_reuse_idx == 0 && reuse_ccso_idx == 0 && ref_idx > 0) - continue; - - if (sb_reuse_idx) { - // Overwrite filter control - memcpy(ctx->filter_control, - ref_frame_ccso_info->sb_filter_control[plane], - sizeof(*ctx->filter_control) * sb_count); - } else { - int control_idx = 0; - for (int y = 0; y < ccso_nvfb; y++) { - for (int x = 0; x < ccso_nhfb; x++) { - ctx->filter_control[control_idx] = 1; - control_idx++; - } - } - } - - int training_iter_count = 0; - bool ccso_enable = true; - bool keep_training = true; - bool improvement = false; - uint64_t prev_total_cost = UINT64_MAX; - - while (keep_training) { - improvement = false; - - if (!skip_filter_calculation) { - if (ccso_enable) { - if (!reuse_ccso_idx) { - memset(ctx->chroma_error, 0, - sizeof(ctx->chroma_error)); - memset(ctx->chroma_count, 0, - sizeof(ctx->chroma_count)); - memset(filter_offset, 0, sizeof(filter_offset)); - ccso_compute_class_err( - ctx, cm, plane, xd, max_band_log2, - max_edge_interval, ccso_bo_only); - derive_lut_offset(filter_offset, scale_idx, - max_band_log2, max_edge_interval, - ccso_bo_only, ctx->chroma_count, - ctx->chroma_error); - } else { - memcpy(filter_offset, - ref_frame_ccso_info->filter_offset[plane], - sizeof(filter_offset)); - } - } - memcpy(ctx->temp_rec_uv_buf, rec_uv, - sizeof(*ctx->temp_rec_uv_buf) * - xd->plane[plane].dst.height * - ctx->ccso_stride); - if (plane > 0) - ccso_try_chroma_filter( - ctx, cm, xd, plane, ext_rec_y, - ctx->temp_rec_uv_buf, ctx->ccso_stride, - filter_offset, ctx->src_cls0, ctx->src_cls1, - shift_bits, ccso_bo_only, ctx->ccso_stride, - ctx->ccso_stride_ext); - else - ccso_try_luma_filter( - ctx, cm, xd, plane, ext_rec_y, - ctx->temp_rec_uv_buf, ctx->ccso_stride, - filter_offset, ctx->src_cls0, ctx->src_cls1, - shift_bits, ccso_bo_only, ctx->ccso_stride, - ctx->ccso_stride_ext); - - compute_distortion( - org_uv, ctx->ccso_stride, ctx->temp_rec_uv_buf, - ctx->ccso_stride, log2_filter_unit_size_y, - log2_filter_unit_size_x, - cm->mib_size_log2 - AVMMAX(ss_x, ss_y) + - MI_SIZE_LOG2, - cm, ss_y, ss_x, pic_height_c, pic_width_c, - ctx->training_dist_block, ccso_nhfb, - &ctx->filtered_dist_frame); - } - - uint64_t cur_total_dist = 0; - int cur_total_rate = 0; - - if (sb_reuse_idx) { - get_sb_reuse_dist( - cm, xd, plane, ctx->unfiltered_dist_block, - ctx->training_dist_block, ctx->filter_control, - &cur_total_dist, &cur_total_rate, &ccso_enable, - rdmult); - cur_total_rate = av2_cost_literal( - reuse_ccso_idx ? 0 : avm_ceil_log2(num_ref_frames)); - } else { - derive_blk_md(cm, xd, plane, ctx->unfiltered_dist_block, - ctx->training_dist_block, - ctx->filter_control, &cur_total_dist, - &cur_total_rate, &ccso_enable, rdmult); - } - - if (ccso_enable) { - const int lut_bits = count_lut_bits( - filter_offset, scale_idx, max_band_log2, - max_edge_interval, ccso_bo_only); - int cur_total_bits = - lut_bits + - (ccso_bo_only ? frame_bits_bo_only : frame_bits); - - if (!ccso_bo_only && !quant_sz[scale_idx][quant_idx]) { - // remove one frame bit for quant sz is 0 case - cur_total_bits -= 1; - } - - cur_total_rate += - (reuse_ccso_idx - ? av2_cost_literal( - 2 + avm_ceil_log2(num_ref_frames)) - : av2_cost_literal(cur_total_bits)); - const uint64_t cur_total_cost = - RDCOST(rdmult, cur_total_rate, cur_total_dist * 16); - if (cur_total_cost < prev_total_cost) { - prev_total_cost = cur_total_cost; - improvement = true; - } - if (cur_total_cost < best_filtered_cost) { - best_filtered_cost = cur_total_cost; - best_reuse_ccso = reuse_ccso_idx; - best_sb_reuse_ccso = sb_reuse_idx; - ctx->best_filter_enabled = ccso_enable; - best_ref_idx = ref_idx - 1; - memcpy(ctx->best_filter_offset, filter_offset, - sizeof(filter_offset)); - best_edge_classifier = edge_clf; - memcpy(ctx->best_filter_control, ctx->filter_control, - sizeof(*ctx->filter_control) * sb_count); - } - } - - training_iter_count++; - if (!improvement || - training_iter_count > CCSO_MAX_ITERATIONS || - sb_reuse_idx || reuse_ccso_idx) { - keep_training = false; - } - } - } - if (reuse_ccso_idx == 0) skip_filter_calculation = true; - } - } - - if (best_filtered_cost < final_filtered_cost) { - final_filtered_cost = best_filtered_cost; - ctx->final_reuse_ccso = best_reuse_ccso; - ctx->final_sb_reuse_ccso = best_sb_reuse_ccso; - ctx->final_filter_enabled = ctx->best_filter_enabled; - ctx->final_quant_idx = quant_idx; - ctx->final_scale_idx = scale_idx; - ctx->final_ext_filter_support = ext_filter_support; - ctx->final_ccso_bo_only = ccso_bo_only; - final_ref_idx = best_ref_idx; - memcpy(ctx->final_filter_offset, ctx->best_filter_offset, - sizeof(ctx->best_filter_offset)); - ctx->final_band_log2 = max_band_log2; - final_edge_classifier = best_edge_classifier; - memcpy(ctx->final_filter_control, ctx->best_filter_control, - sizeof(*ctx->best_filter_control) * sb_count); - } - if (early_terminate_ccso_search && - final_filtered_cost != UINT64_MAX && - 1.001 * final_filtered_cost > last_best_cost) - goto exit_loops; - } - } + const int num_filter_iter = ccso_bo_only ? 1 : total_filter_support; + for (uint8_t ext_filter_support = 0; ext_filter_support < num_filter_iter; + ++ext_filter_support) { + const uint8_t num_quant_iter = ccso_bo_only ? 1 : total_quant_idx; + for (uint8_t quant_idx = 0; quant_idx < num_quant_iter; ++quant_idx) { + ctx->scale_idx = scale_idx; + ctx->ccso_bo_only = ccso_bo_only; + ctx->ext_filter_support = ext_filter_support; + ctx->quant_idx = quant_idx; + if (av2_ccso_param_search(cm, ctx, xd)) goto exit_loops; } } } } exit_loops: - if (best_unfiltered_cost < final_filtered_cost) { - memset(ctx->final_filter_control, 0, - sizeof(*ctx->final_filter_control) * sb_count); - cm->ccso_info.ccso_enable[plane] = false; - } else { - cm->ccso_info.ccso_enable[plane] = true; - } - - if (cm->ccso_info.ccso_enable[plane] && - (ctx->final_reuse_ccso || ctx->final_sb_reuse_ccso)) { - assert(get_ref_frame_buf(cm, final_ref_idx) != NULL); - ref_frame_ccso_info = &get_ref_frame_buf(cm, final_ref_idx)->ccso_info; - cm->ccso_info.ccso_ref_idx[plane] = final_ref_idx; - } - - cm->ccso_info.sb_reuse_ccso[plane] = false; - cm->ccso_info.reuse_ccso[plane] = false; - cm->cur_frame->ccso_info.subsampling_y[plane] = ss_y; - cm->cur_frame->ccso_info.subsampling_x[plane] = ss_x; - if (cm->ccso_info.ccso_enable[plane]) { - cm->cur_frame->ccso_info.ccso_enable[plane] = 1; - cm->cur_frame->ccso_info.ccso_blk_size = ccso_blk_size; - cm->cur_frame->ccso_info.reuse_root_ref[plane] = - cm->current_frame.display_order_hint; - cm->ccso_info.sb_reuse_ccso[plane] = ctx->final_sb_reuse_ccso; - const BLOCK_SIZE bsize = xd->mi[0]->sb_type[PLANE_TYPE_Y]; - const int bw = mi_size_wide[bsize]; - const int bh = mi_size_high[bsize]; - const int log2_w = ccso_blk_size; - const int log2_h = ccso_blk_size; - const int f_w = 1 << log2_w >> MI_SIZE_LOG2; - const int f_h = 1 << log2_h >> MI_SIZE_LOG2; - const int step_h = (bh + f_h - 1) / f_h; - const int step_w = (bw + f_w - 1) / f_w; - - if (!cm->ccso_info.sb_reuse_ccso[plane]) { - for (int y_sb = 0; y_sb < ccso_nvfb; y_sb += step_h) { - for (int x_sb = 0; x_sb < ccso_nhfb; x_sb += step_w) { - for (int row = y_sb; row < y_sb + step_h; row++) { - for (int col = x_sb; col < x_sb + step_w; col++) { - int sb_idx = row * ccso_nhfb + col; - const bool sb_filter_control = - ctx->final_filter_control[y_sb * ccso_nhfb + x_sb]; - cm->cur_frame->ccso_info.sb_filter_control[plane][sb_idx] = - sb_filter_control; - const int grid_idx_mbmi = - (1 << ccso_blk_size >> MI_SIZE_LOG2) * row * - mi_params->mi_stride + - (1 << ccso_blk_size >> MI_SIZE_LOG2) * col; - MB_MODE_INFO *const mbmi = mi_params->mi_grid_base[grid_idx_mbmi]; - // for tile skip, no valid mi exist - if (cm->bru.enabled && - bru_is_fu_skipped_mbmi(cm, sb_unit_size_x * col, - sb_unit_size_y * row, f_w, f_h)) { - assert(sb_filter_control == 0); - set_mbmi_ccso_blk(mbmi, plane, 0); - } else { - set_mbmi_ccso_blk(mbmi, plane, sb_filter_control); - } - const int ccso_mib_size_y = (1 << (ccso_blk_size - MI_SIZE_LOG2)); - const int ccso_mib_size_x = (1 << (ccso_blk_size - MI_SIZE_LOG2)); - - int mi_row = (1 << ccso_blk_size >> MI_SIZE_LOG2) * row; - int mi_col = (1 << ccso_blk_size >> MI_SIZE_LOG2) * col; - for (int j = 0; - j < AVMMIN(ccso_mib_size_y, cm->mi_params.mi_rows - mi_row); - j++) { - for (int k = 0; k < AVMMIN(ccso_mib_size_x, - cm->mi_params.mi_cols - mi_col); - k++) { - const int grid_idx = - get_mi_grid_idx(mi_params, mi_row + j, mi_col + k); - set_mbmi_ccso_blk(mi_params->mi_grid_base[grid_idx], plane, - sb_filter_control); - } - } - } - } - -#if CONFIG_ENTROPY_STATS - const int ccso_ctx = get_ccso_context(y_sb, x_sb, ccso_nhfb, - ctx->final_filter_control); - - ++td->counts->default_ccso_cnts - [plane][ccso_ctx] - [ctx->final_filter_control[y_sb * ccso_nhfb + x_sb]]; -#endif - } - } - } else { - assert(ref_frame_ccso_info != NULL); - - memcpy(cm->cur_frame->ccso_info.sb_filter_control[plane], - ref_frame_ccso_info->sb_filter_control[plane], - sizeof(*cm->cur_frame->ccso_info.sb_filter_control[plane]) * - sb_count); - - for (int y_sb = 0; y_sb < ccso_nvfb; y_sb++) { - for (int x_sb = 0; x_sb < ccso_nhfb; x_sb++) { - const int grid_idx = (1 << ccso_blk_size >> MI_SIZE_LOG2) * y_sb * - mi_params->mi_stride + - (1 << ccso_blk_size >> MI_SIZE_LOG2) * x_sb; - set_mbmi_ccso_blk( - mi_params->mi_grid_base[grid_idx], plane, - ref_frame_ccso_info - ->sb_filter_control[plane][y_sb * ccso_nhfb + x_sb]); - } - } - } - cm->ccso_info.reuse_ccso[plane] = ctx->final_reuse_ccso; - if (!cm->ccso_info.reuse_ccso[plane]) { - memcpy(cm->ccso_info.filter_offset[plane], ctx->final_filter_offset, - sizeof(ctx->final_filter_offset)); - cm->ccso_info.quant_idx[plane] = ctx->final_quant_idx; - cm->ccso_info.scale_idx[plane] = ctx->final_scale_idx; - cm->ccso_info.ext_filter_support[plane] = ctx->final_ext_filter_support; - cm->ccso_info.ccso_bo_only[plane] = ctx->final_ccso_bo_only; - cm->ccso_info.max_band_log2[plane] = ctx->final_band_log2; - cm->ccso_info.edge_clf[plane] = final_edge_classifier; - memcpy(cm->cur_frame->ccso_info.filter_offset[plane], - ctx->final_filter_offset, sizeof(ctx->final_filter_offset)); - cm->cur_frame->ccso_info.quant_idx[plane] = ctx->final_quant_idx; - cm->cur_frame->ccso_info.scale_idx[plane] = ctx->final_scale_idx; - cm->cur_frame->ccso_info.ext_filter_support[plane] = - ctx->final_ext_filter_support; - cm->cur_frame->ccso_info.ccso_bo_only[plane] = ctx->final_ccso_bo_only; - cm->cur_frame->ccso_info.max_band_log2[plane] = ctx->final_band_log2; - cm->cur_frame->ccso_info.edge_clf[plane] = final_edge_classifier; - } else { - av2_copy_ccso_filters(&cm->ccso_info, ref_frame_ccso_info, plane, 1, 0, - sb_count); - av2_copy_ccso_filters(&cm->cur_frame->ccso_info, ref_frame_ccso_info, - plane, 1, 0, sb_count); - } - - if (cm->ccso_info.reuse_ccso[plane] && cm->ccso_info.sb_reuse_ccso[plane]) { - cm->cur_frame->ccso_info.reuse_root_ref[plane] = - ref_frame_ccso_info->reuse_root_ref[plane]; - } - } + finalize_ccso_plane(cm, ctx, td, + best_unfiltered_cost < ctx->final.filtered_cost); } /* Derive the look-up table for a frame */ -void av2_ccso_search(AV2_COMMON *cm, MACROBLOCKD *xd, int rdmult, - const uint16_t *ext_rec_y, uint16_t *rec_uv[MAX_MB_PLANE], +void av2_ccso_search(struct AV2_COMP *cpi, const uint16_t *ext_rec_y, + uint16_t *rec_uv[MAX_MB_PLANE], uint16_t *org_uv[MAX_MB_PLANE], - bool error_resilient_frame_seen -#if CONFIG_ENTROPY_STATS - , - ThreadData *td -#endif - , - int early_terminate_ccso_search, int ccso_chroma_dep, - CcsoCtx *ctx) { + bool error_resilient_frame_seen, + int early_terminate_ccso_search, int ccso_chroma_dep) { + AV2_COMMON *const cm = &cpi->common; + ThreadData *td = &cpi->td; + MACROBLOCKD *const xd = &td->mb.e_mbd; const int num_planes = av2_num_planes(cm); const int rdmult_weight = clamp(cm->quant_params.base_qindex >> 3, 1, 37); - int rdmult_orig = rdmult; + const int rdmult = td->mb.rdmult; cm->ccso_info.ccso_frame_flag = false; for (int plane = AVM_PLANE_Y; plane < num_planes; ++plane) { @@ -1844,42 +1814,19 @@ void av2_ccso_search(AV2_COMMON *cm, MACROBLOCKD *xd, int rdmult, cm->ccso_info.reuse_ccso[plane] = false; } - if ((int64_t)rdmult * rdmult_weight >= INT_MAX) { - return; - } else { - ccso_ctx_reset(ctx); - + if ((int64_t)rdmult * rdmult_weight < INT_MAX) { av2_setup_dst_planes(xd->plane, &cm->cur_frame->buf, 0, 0, 0, num_planes, NULL); - ctx->ccso_stride = xd->plane[AVM_PLANE_Y].dst.width; - ctx->ccso_stride_ext = ctx->ccso_stride + (CCSO_PADDING_SIZE << 1); - for (int plane = AVM_PLANE_U; plane < num_planes; ++plane) { - if (plane == AVM_PLANE_U) rdmult = (rdmult * 7) >> 3; - derive_ccso_filter(ctx, cm, plane, xd, org_uv[plane], ext_rec_y, - rec_uv[plane], rdmult, error_resilient_frame_seen -#if CONFIG_ENTROPY_STATS - , - td -#endif - , + for (int plane = num_planes - 1; plane >= AVM_PLANE_Y; --plane) { + if (plane == AVM_PLANE_Y && ccso_chroma_dep && num_planes > 1 && + !cm->ccso_info.ccso_frame_flag) { + break; + } + int rdmult_plane = (plane == AVM_PLANE_Y) ? rdmult : ((rdmult * 7) >> 3); + derive_ccso_filter(cpi, plane, org_uv[plane], ext_rec_y, rec_uv[plane], + rdmult_plane, error_resilient_frame_seen, early_terminate_ccso_search); cm->ccso_info.ccso_frame_flag |= cm->ccso_info.ccso_enable[plane]; } - - int check_luma_planes = - (ccso_chroma_dep && num_planes > 1) ? cm->ccso_info.ccso_frame_flag : 1; - - if (check_luma_planes) { - derive_ccso_filter(ctx, cm, AVM_PLANE_Y, xd, org_uv[AVM_PLANE_Y], - ext_rec_y, rec_uv[AVM_PLANE_Y], rdmult_orig, - error_resilient_frame_seen -#if CONFIG_ENTROPY_STATS - , - td -#endif - , - early_terminate_ccso_search); - cm->ccso_info.ccso_frame_flag |= cm->ccso_info.ccso_enable[0]; - } } } diff --git a/av2/encoder/pickccso.h b/av2/encoder/pickccso.h index 6a223bb1b2..dcfdea370b 100644 --- a/av2/encoder/pickccso.h +++ b/av2/encoder/pickccso.h @@ -13,28 +13,87 @@ #ifndef AVM_AV2_ENCODER_PICKCCSO_H_ #define AVM_AV2_ENCODER_PICKCCSO_H_ -#define CCSO_MAX_ITERATIONS 15 - #include "av2/common/ccso.h" #include "av2/encoder/speed_features.h" +#ifdef __cplusplus +extern "C" { +#endif + +#define CCSO_MAX_ITERATIONS 15 + // Number of (d0, d1, band) combinations spanned by total_class_err/cnt. #define CCSO_CLASS_STATS_ENTRIES \ (CCSO_INPUT_INTERVAL * CCSO_INPUT_INTERVAL * CCSO_BAND_NUM) +typedef struct { + const uint16_t *org_uv; + const uint16_t *ext_rec_y; + const uint16_t *rec_uv; + uint64_t *unfiltered_dist_block; + int plane; + int rdmult; + int ccso_blk_size; + int log2_filter_unit_size_x; + int log2_filter_unit_size_y; + int log2_proc_unit_size; + int ccso_nvfb; + int ccso_nhfb; + int sb_count; + uint8_t frame_bits; + uint8_t frame_bits_bo_only; + int check_ccso; + int num_ref_frames; + int early_terminate_ccso_search; +} CcsoCtxCommon; + +typedef struct { + int8_t filter_offset[CCSO_BAND_NUM * 16]; + uint64_t filtered_cost; + int ref_idx; + uint8_t band_log2; + uint8_t ext_filter_support; + uint8_t reuse_ccso; + uint8_t sb_reuse_ccso; + uint8_t scale_idx; + uint8_t quant_idx; + uint8_t ccso_bo_only; + uint8_t edge_classifier; +} CcsoCandidate; + typedef struct { // Per-frame state — zeroed at the start of each av2_ccso_search call. - uint8_t final_band_log2; - int8_t best_filter_offset[CCSO_BAND_NUM * 16]; - int8_t final_filter_offset[CCSO_BAND_NUM * 16]; - bool best_filter_enabled; - bool final_filter_enabled; - uint8_t final_ext_filter_support; - int final_reuse_ccso; - int final_sb_reuse_ccso; - uint8_t final_scale_idx; - uint8_t final_quant_idx; - uint8_t final_ccso_bo_only; + CcsoCtxCommon ccso_cm; + + // Best candidate found across the whole search. + CcsoCandidate final; + + // Best candidate found so far for the current max_band_log2 iteration. + CcsoCandidate best; + + // Coordinates of the candidate currently under evaluation + uint8_t scale_idx; + uint8_t ccso_bo_only; + uint8_t ext_filter_support; + uint8_t quant_idx; + uint8_t edge_clf; + uint8_t max_band_log2; + uint8_t reuse_ccso_idx; + uint8_t sb_reuse_idx; + int ref_idx; + + uint8_t max_edge_interval; + uint8_t num_band_iter; + bool check_sb_reuse; + CcsoInfo *ref_frame_ccso_info; + bool skip_filter_calculation; + int shift_bits; + int init_shift_bits; + uint64_t last_best_cost; + unsigned int checked_reuse_ref[2][7]; + int checked_reuse_ref_idx[2]; + int8_t filter_offset[CCSO_BAND_NUM * 16]; + int chroma_error[CCSO_BAND_NUM * 16]; int chroma_count[CCSO_BAND_NUM * 16]; int *total_class_err[CCSO_INPUT_INTERVAL][CCSO_INPUT_INTERVAL][CCSO_BAND_NUM]; @@ -43,8 +102,6 @@ typedef struct { int *total_class_cnt_bo[CCSO_BAND_NUM]; int ccso_stride; int ccso_stride_ext; - uint64_t unfiltered_dist_frame; - uint64_t filtered_dist_frame; int *reuse_total_class_err[CCSO_INPUT_INTERVAL][CCSO_INPUT_INTERVAL] [CCSO_BAND_NUM]; int *reuse_total_class_cnt[CCSO_INPUT_INTERVAL][CCSO_INPUT_INTERVAL] @@ -60,7 +117,6 @@ typedef struct { int *class_cnt_bo_slab; // backs total_class_cnt_bo int *reuse_class_err_slab; // backs reuse_total_class_err int *reuse_class_cnt_slab; // backs reuse_total_class_cnt - uint64_t *unfiltered_dist_block; uint64_t *training_dist_block; bool *filter_control; bool *best_filter_control; @@ -73,26 +129,15 @@ typedef struct { size_t alloc_luma_size; } CcsoCtx; -#ifdef __cplusplus -extern "C" { -#endif +void av2_ccso_ctx_free(struct AV2_COMP *cpi); -struct AV2_COMP; -struct ThreadData; +bool av2_ccso_param_search(AV2_COMMON *cm, CcsoCtx *ctx, MACROBLOCKD *xd); -void av2_ccso_search(AV2_COMMON *cm, MACROBLOCKD *xd, int rdmult, - const uint16_t *ext_rec_y, uint16_t *rec_uv[MAX_MB_PLANE], +void av2_ccso_search(struct AV2_COMP *cpi, const uint16_t *ext_rec_y, + uint16_t *rec_uv[MAX_MB_PLANE], uint16_t *org_uv[MAX_MB_PLANE], - bool error_resilient_frame_seen -#if CONFIG_ENTROPY_STATS - , - struct ThreadData *td -#endif - , - int early_terminate_ccso_search, int ccso_chroma_dep, - CcsoCtx *ctx); - -void av2_ccso_ctx_free(struct AV2_COMP *cpi); + bool error_resilient_frame_seen, + int early_terminate_ccso_search, int ccso_chroma_dep); #ifdef __cplusplus } // extern "C"