[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.

This commit is contained in:
siivonek 2022-08-17 15:23:35 +03:00 committed by Marko Viitanen
parent bcbd952dfd
commit 573ecf80e3
5 changed files with 139 additions and 158 deletions

View file

@ -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,

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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;