From 573ecf80e3da01cfa2e4cc8bf11b769b1bce7daa Mon Sep 17 00:00:00 2001 From: siivonek Date: Wed, 17 Aug 2022 15:23:35 +0300 Subject: [PATCH] [isp] Move can_use_lfnst_with_isp to intra.c. Remove duplicate functions. Move isp related functions from search to intra. Make isp_split_dim static. Move isp related defines from search to intra. --- src/encode_coding_tree.c | 111 ++++++++++++--------------------------- src/intra.c | 92 +++++++++++++++++++++++++++++++- src/intra.h | 11 ++++ src/search.h | 8 --- src/search_intra.c | 75 +------------------------- 5 files changed, 139 insertions(+), 158 deletions(-) diff --git a/src/encode_coding_tree.c b/src/encode_coding_tree.c index 2199f5bc..8fb45396 100644 --- a/src/encode_coding_tree.c +++ b/src/encode_coding_tree.c @@ -102,63 +102,8 @@ static void encode_mts_idx(encoder_state_t * const state, } } -// ISP_TODO: move these defines to a proper place when ISP is implemented -// As of now, these are only needed in lfnst checks -#define NOT_INTRA_SUBPARTITIONS 0 -#define HOR_INTRA_SUBPARTITIONS 1 -#define VER_INTRA_SUBPARTITIONS 2 -#define NUM_INTRA_SUBPARTITIONS_MODES 3 -#define INTRA_SUBPARTITIONS_RESERVED 4 -#define TU_1D_HOR_SPLIT 8 -#define TU_1D_VER_SPLIT 9 -#define MIN_TB_SIZE_X 4 -#define MIN_TB_SIZE_Y 4 - -static int get_isp_split_dim(const int width, const int height, const int isp_split_type) -{ - bool divide_tu_in_rows = isp_split_type == TU_1D_HOR_SPLIT; - uint32_t split_dim_size, non_split_dim_size, partition_size, div_shift = 2; - - if (divide_tu_in_rows) - { - split_dim_size = height; - non_split_dim_size = width; - } - else - { - split_dim_size = width; - non_split_dim_size = height; - } - - const unsigned min_num_samples_cu = 1 << ((uvg_math_floor_log2(MIN_TB_SIZE_Y) << 1)); - const unsigned factor_to_min_samples = non_split_dim_size < min_num_samples_cu ? min_num_samples_cu >> uvg_math_floor_log2(non_split_dim_size) : 1; - partition_size = (split_dim_size >> div_shift) < factor_to_min_samples ? factor_to_min_samples : (split_dim_size >> div_shift); - - assert(!(uvg_math_floor_log2(partition_size) + uvg_math_floor_log2(non_split_dim_size) < uvg_math_floor_log2(min_num_samples_cu)) && "Partition has less than minimum amount of samples."); - return partition_size; -} - -static bool can_use_lfnst_with_isp(const int width, const int height, const int isp_split_type, const enum uvg_tree_type tree_type) -{ - if (tree_type == UVG_CHROMA_T) { - return false; - } - if (isp_split_type == NOT_INTRA_SUBPARTITIONS) { - return false; - } - - const int tu_width = (isp_split_type == HOR_INTRA_SUBPARTITIONS) ? width : get_isp_split_dim(width, height, TU_1D_VER_SPLIT); - const int tu_height = (isp_split_type == HOR_INTRA_SUBPARTITIONS) ? get_isp_split_dim(width, height, TU_1D_HOR_SPLIT) : height; - - if (!(tu_width >= MIN_TB_SIZE_Y && tu_height >= MIN_TB_SIZE_Y)) - { - return false; - } - return true; -} - - bool uvg_is_lfnst_allowed( +bool uvg_is_lfnst_allowed( const encoder_state_t* const state, const cu_info_t* const pred_cu, const int width, @@ -170,8 +115,7 @@ static bool can_use_lfnst_with_isp(const int width, const int height, const int const lcu_t* lcu) { if (state->encoder_control->cfg.lfnst && pred_cu->type == CU_INTRA) { - const int isp_mode = 0; // ISP_TODO: assign proper ISP mode when ISP is implemented - const int isp_split_type = 0; + const int isp_mode = pred_cu->intra.isp_mode; const int depth = pred_cu->depth; const int chroma_width = width >> 1; const int chroma_height = height >> 1; @@ -181,7 +125,7 @@ static bool can_use_lfnst_with_isp(const int width, const int height, const int bool is_sep_tree = depth == 4 || tree_type != UVG_BOTH_T; bool mip_flag = pred_cu->type == CU_INTRA && color == COLOR_Y ? pred_cu->intra.mip_flag : false; - if ((isp_mode && !can_use_lfnst_with_isp(width, height, isp_split_type, tree_type)) || + if ((isp_mode && !uvg_can_use_isp_with_lfnst(width, height, isp_mode, tree_type)) || (pred_cu->type == CU_INTRA && mip_flag && !can_use_lfnst_with_mip) || (is_sep_tree && MIN(cu_width, cu_height) < 4) || (cu_width > TR_MAX_WIDTH || cu_height > TR_MAX_WIDTH)) { @@ -1064,13 +1008,6 @@ void uvg_encode_intra_luma_coding_unit(const encoder_state_t * const state, uint32_t width = (LCU_WIDTH >> depth); uint32_t height = (LCU_WIDTH >> depth); - // Need at least 16 samples in sub blocks to use isp. If both dimensions are 4, not enough samples. Size cannot be 2 at this point. - bool allow_isp = !(width == 4 && height == 4); - uint8_t isp_mode = 0; - // ToDo: add height comparison - //isp_mode += ((width > TR_MAX_WIDTH) || !enough_samples) ? 1 : 0; - //isp_mode += ((height > TR_MAX_WIDTH) || !enough_samples) ? 2 : 0; - // Code MIP related bits bool enable_mip = state->encoder_control->cfg.mip; int8_t mip_flag = enable_mip ? cur_cu->intra.mip_flag : false; @@ -1127,20 +1064,42 @@ void uvg_encode_intra_luma_coding_unit(const encoder_state_t * const state, } } + bool enable_isp = state->encoder_control->cfg.isp; + // Need at least 16 samples in sub blocks to use isp. If both dimensions are 4, not enough samples. Blocks of size 2 do not exist yet (not for luma at least) + bool allow_isp = enable_isp ? uvg_can_use_isp(width, height, 64 /*MAX_TR_SIZE*/) : false; + uint8_t isp_mode = allow_isp ? cur_cu->intra.isp_mode : 0; - // ToDo: update real usage, these if clauses as such don't make any sense - if (isp_mode != 0 && multi_ref_idx == 0) { - if (isp_mode) { - CABAC_FBITS_UPDATE(cabac, &(cabac->ctx.intra_subpart_model[0]), 0, bits, "intra_subPartitions"); - } else { - CABAC_FBITS_UPDATE(cabac, &(cabac->ctx.intra_subpart_model[0]), 1, bits, "intra_subPartitions"); - // ToDo: complete this if-clause - if (isp_mode == 3) { - CABAC_FBITS_UPDATE(cabac, &(cabac->ctx.intra_subpart_model[0]), allow_isp - 1, bits, "intra_subPart_ver_hor"); - } + // ToDo: add height comparison + //isp_mode += ((width > TR_MAX_WIDTH) || !enough_samples) ? 1 : 0; + //isp_mode += ((height > TR_MAX_WIDTH) || !enough_samples) ? 2 : 0; + + if (allow_isp && !multi_ref_idx /*&& !bdpcm && !color_transform*/) { + if (isp_mode == ISP_MODE_NO_ISP) { + CABAC_FBITS_UPDATE(cabac, &(cabac->ctx.intra_subpart_model[0]), 0, bits, "intra_subpartitions_mode"); + } + else { + CABAC_FBITS_UPDATE(cabac, &(cabac->ctx.intra_subpart_model[0]), 1, bits, "intra_subpartitions_mode"); + CABAC_FBITS_UPDATE(cabac, &(cabac->ctx.intra_subpart_model[1]), isp_mode - 1, bits, "intra_subpartitions_split_type"); // Vertical or horizontal split } } + + //if (allow_isp && !multi_ref_idx /*&& !bdpcm && !color_transform*/) { + // if (isp_mode == ISP_MODE_NO_ISP) { + // if (isp_mode) { + // CABAC_FBITS_UPDATE(cabac, &(cabac->ctx.intra_subpart_model[0]), 0, bits, "intra_subPartitions"); + // } + // else { + // CABAC_FBITS_UPDATE(cabac, &(cabac->ctx.intra_subpart_model[0]), 1, bits, "intra_subPartitions"); + // // ToDo: complete this if-clause + // if (isp_mode == 3) { + // CABAC_FBITS_UPDATE(cabac, &(cabac->ctx.intra_subpart_model[0]), allow_isp - 1, bits, "intra_subPart_ver_hor"); + // } + // } + // } + //} + + const int cu_width = LCU_WIDTH >> depth; // PREDINFO CODING // If intra prediction mode is found from the predictors, diff --git a/src/intra.c b/src/intra.c index ea848faa..1a1e3817 100644 --- a/src/intra.c +++ b/src/intra.c @@ -1471,6 +1471,41 @@ const cu_info_t* uvg_get_co_located_luma_cu( } +/** +* \brief Returns ISP split partition size based on block dimensions and split type. +* +* Returns ISP split partition size based on block dimensions and split type. +* Will fail if resulting partition size has less than 16 samples. +* +* \param width Block width. +* \param height Block height. +* \param split_type Horizontal or vertical split. +*/ +static int get_isp_split_dim(const int width, const int height, const int split_type) +{ + bool divide_in_rows = split_type == SPLIT_TYPE_HOR; + int split_dim_size, non_split_dim_size, partition_size, div_shift = 2; + + if (divide_in_rows) { + split_dim_size = height; + non_split_dim_size = width; + } + else { + split_dim_size = width; + non_split_dim_size = height; + } + + // ISP_TODO: make a define for this. Depends on minimum transform block log2 side length + const int min_num_samples = 16; // Minimum allowed number of samples for split block + const int factor_to_min_samples = non_split_dim_size < min_num_samples ? min_num_samples >> uvg_math_floor_log2(non_split_dim_size) : 1; + partition_size = (split_dim_size >> div_shift) < factor_to_min_samples ? factor_to_min_samples : (split_dim_size >> div_shift); + + assert((uvg_math_floor_log2(partition_size) + uvg_math_floor_log2(non_split_dim_size) < uvg_math_floor_log2(min_num_samples)) && + "Partition has less than allowed minimum number of samples."); + return partition_size; +} + + static void intra_recon_tb_leaf( encoder_state_t* const state, const cu_loc_t* cu_loc, @@ -1631,7 +1666,7 @@ void uvg_intra_recon_cu( // ISP split is done horizontally or vertically depending on ISP mode, 2 or 4 times depending on block dimensions. // Small blocks are split only twice. int split_type = search_data->pred_cu.intra.isp_mode; - int part_dim = uvg_get_isp_split_dim(width, height, split_type); + int part_dim = get_isp_split_dim(width, height, split_type); int limit = split_type == ISP_MODE_HOR ? height : width; for (int part = 0; part < limit; part + part_dim) { const int part_x = split_type == ISP_MODE_HOR ? x : x + part; @@ -1668,3 +1703,58 @@ void uvg_intra_recon_cu( &loc, depth, cur_cu, lcu, false, tree_type); } + + +/** +* \brief Check if ISP can be used for block size. +* +* \return True if isp can be used. +* \param width Block width. +* \param height Block height. +* \param max_tr_size Maximum supported transform block size (64). +*/ +bool uvg_can_use_isp(const int width, const int height, const int max_tr_size) +{ + assert(!(width > LCU_WIDTH || height > LCU_WIDTH) && "Block size larger than max LCU size."); + assert(!(width < TR_MIN_WIDTH || height < TR_MIN_WIDTH) && "Block size smaller than min TR_WIDTH."); + + const int log2_width = uvg_g_convert_to_log2[width]; + const int log2_height = uvg_g_convert_to_log2[height]; + + // Each split block must have at least 16 samples. + bool not_enough_samples = (log2_width + log2_height <= 4); + bool cu_size_larger_than_max_tr_size = width > max_tr_size || height > max_tr_size; + if (not_enough_samples || cu_size_larger_than_max_tr_size) { + return false; + } + return true; +} + + +/** +* \brief Check if given ISP mode can be used with LFNST. +* +* \return True if isp can be used. +* \param width Block width. +* \param height Block height. +* \param isp_mode ISP mode. +* \param tree_type Tree type. Dual, luma or chroma tree. +*/ +bool uvg_can_use_isp_with_lfnst(const int width, const int height, const int isp_split_type, const enum uvg_tree_type tree_type) +{ + if (tree_type == UVG_CHROMA_T) { + return false; + } + if (isp_split_type == ISP_MODE_NO_ISP) { + return false; + } + + const int tu_width = (isp_split_type == ISP_MODE_HOR) ? width : get_isp_split_dim(width, height, SPLIT_TYPE_VER); + const int tu_height = (isp_split_type == ISP_MODE_HOR) ? get_isp_split_dim(width, height, SPLIT_TYPE_HOR) : height; + + if (!(tu_width >= TR_MIN_WIDTH && tu_height >= TR_MIN_WIDTH)) + { + return false; + } + return true; +} diff --git a/src/intra.h b/src/intra.h index 6c7a648e..75b969b3 100644 --- a/src/intra.h +++ b/src/intra.h @@ -159,3 +159,14 @@ const cu_info_t* uvg_get_co_located_luma_cu( enum uvg_tree_type tree_type); int uvg_get_mip_flag_context(int x, int y, int width, int height, const lcu_t* lcu, cu_array_t* const cu_a); + +// ISP related defines +#define NUM_ISP_MODES 3 +#define ISP_MODE_NO_ISP 0 +#define ISP_MODE_HOR 1 +#define ISP_MODE_VER 2 +#define SPLIT_TYPE_HOR 1 +#define SPLIT_TYPE_VER 2 + +bool uvg_can_use_isp(const int width, const int height, const int max_tr_size); +bool uvg_can_use_isp_with_lfnst(const int width, const int height, const int isp_mode, const enum uvg_tree_type tree_type); diff --git a/src/search.h b/src/search.h index 2a5a6867..7566fb96 100644 --- a/src/search.h +++ b/src/search.h @@ -77,14 +77,6 @@ typedef struct unit_stats_map_t { #define NUM_MIP_MODES_FULL(width, height) (((width) == 4 && (height) == 4) ? 32 : ((width) == 4 || (height) == 4 || ((width) == 8 && (height) == 8) ? 16 : 12)) #define NUM_MIP_MODES_HALF(width, height) (NUM_MIP_MODES_FULL((width), (height)) >> 1) -// ISP related defines -#define NUM_ISP_MODES 3 -#define ISP_MODE_NO_ISP 0 -#define ISP_MODE_HOR 1 -#define ISP_MODE_VER 2 -#define SPLIT_TYPE_HOR 1 -#define SPLIT_TYPE_VER 2 - void uvg_sort_modes(int8_t *__restrict modes, double *__restrict costs, uint8_t length); void uvg_sort_modes_intra_luma(int8_t *__restrict modes, int8_t *__restrict trafo, double *__restrict costs, uint8_t length); diff --git a/src/search_intra.c b/src/search_intra.c index f36708b7..71964022 100644 --- a/src/search_intra.c +++ b/src/search_intra.c @@ -257,77 +257,6 @@ static void derive_mts_constraints(cu_info_t *const pred_cu, } -// ISP_TODO: move this function if it is used elsewhere -static INLINE bool can_use_isp(const int width, const int height, const int max_tr_size) -{ - assert(!(width > LCU_WIDTH || height > LCU_WIDTH) && "Block size larger than max LCU size."); - assert(!(width < TR_MIN_WIDTH || height < TR_MIN_WIDTH) && "Block size smaller than min TR_WIDTH."); - - const int log2_width = uvg_g_convert_to_log2[width]; - const int log2_height = uvg_g_convert_to_log2[height]; - - // Each split block must have at least 16 samples. - bool not_enough_samples = (log2_width + log2_height <= 4); - bool cu_size_larger_than_max_tr_size = width > max_tr_size || height > max_tr_size; - if (not_enough_samples || cu_size_larger_than_max_tr_size) { - return false; - } - return true; -} - - -/** -* \brief Returns ISP split partition size based on block dimensions and split type. -* -* Returns ISP split partition size based on block dimensions and split type. -* Will fail if resulting partition size has less than 16 samples. -* -* \param width Block width. -* \param height Block height. -* \param split_type Horizontal or vertical split. -*/ -int uvg_get_isp_split_dim(const int width, const int height, const int split_type) -{ - bool divide_in_rows = split_type == SPLIT_TYPE_HOR; - int split_dim_size, non_split_dim_size, partition_size, div_shift = 2; - - if (divide_in_rows) { - split_dim_size = height; - non_split_dim_size = width; - } - else { - split_dim_size = width; - non_split_dim_size = height; - } - - // ISP_TODO: make a define for this. Depends on minimum transform block log2 side length - const int min_num_samples = 16; // Minimum allowed number of samples for split block - const int factor_to_min_samples = non_split_dim_size < min_num_samples ? min_num_samples >> uvg_math_floor_log2(non_split_dim_size) : 1; - partition_size = (split_dim_size >> div_shift) < factor_to_min_samples ? factor_to_min_samples : (split_dim_size >> div_shift); - - assert((uvg_math_floor_log2(partition_size) + uvg_math_floor_log2(non_split_dim_size) < uvg_math_floor_log2(min_num_samples)) && - "Partition has less than allowed minimum number of samples."); - return partition_size; -} - - -// ISP_TODO: move this function if it is used elsewhere -static INLINE bool can_use_isp_with_lfnst(const int width, const int height, const int isp_mode) -{ - if (isp_mode == ISP_MODE_NO_ISP) { - return false; - } - const int tu_width = isp_mode == ISP_MODE_HOR ? width : uvg_get_isp_split_dim(width, height, SPLIT_TYPE_VER); - const int tu_height = isp_mode == ISP_MODE_HOR ? uvg_get_isp_split_dim(width, height, SPLIT_TYPE_HOR) : height; - const int min_tb_size = TR_MIN_WIDTH; - - if (!(tu_width >= min_tb_size && tu_height >= min_tb_size)) { - return false; - } - return true; -} - - /** * \brief Perform search for best intra transform split configuration. * @@ -445,7 +374,7 @@ static double search_intra_trdepth( if (pred_cu->lfnst_idx != 0) { // Cannot use ISP with LFNST for small blocks - pred_cu->intra.isp_mode = can_use_isp_with_lfnst(width, height, pred_cu->intra.isp_mode) ? pred_cu->intra.isp_mode : ISP_MODE_NO_ISP; + pred_cu->intra.isp_mode = uvg_can_use_isp_with_lfnst(width, height, pred_cu->intra.isp_mode, tree_type) ? pred_cu->intra.isp_mode : ISP_MODE_NO_ISP; } for (trafo = mts_start; trafo < num_transforms; trafo++) { @@ -1465,7 +1394,7 @@ static int8_t search_intra_rdo( for (int mode = 0; mode < modes_to_check; mode++) { bool can_do_isp_search = search_data[mode].pred_cu.intra.mip_flag ? false: true; // Cannot use ISP with MIP can_do_isp_search = search_data[mode].pred_cu.intra.multi_ref_idx == 0 ? can_do_isp_search : false; // Cannot use ISP with MRL - int max_isp_modes = can_do_isp_search && can_use_isp(width, height, 64 /*MAX_TR_SIZE*/) && state->encoder_control->cfg.isp ? NUM_ISP_MODES : 1; + int max_isp_modes = can_do_isp_search && uvg_can_use_isp(width, height, 64 /*MAX_TR_SIZE*/) && state->encoder_control->cfg.isp ? NUM_ISP_MODES : 1; for (int isp_mode = 0; isp_mode < max_isp_modes; ++isp_mode) { search_data[mode].pred_cu.intra.isp_mode = isp_mode;