From 9c5edda3ca29cd54fe7b57606878dc3e8702358f Mon Sep 17 00:00:00 2001 From: Kuixi Ren Date: Tue, 23 Aug 2022 20:22:40 +0000 Subject: [PATCH] radeonsi/vcn: Add ability to encode with ltr reads flags field from CurrPic struct in pps for VA_PICTURE_H264_LONG_TERM_REFERENCE. If found, Curr_pic.frame_idx wil be used for the long term reference index In get_picture_storage, check if current frame is ltr, and whether its ref frame is ltr. In radeon_enc_slice_header, adds the ref_pic_list_modification_flag_l0 and long_term_reference_flag for ltr v2: fix code formatting issues Reviewed-by: Ruijing Dong ruijing.dong@amd.com Part-of: --- src/gallium/drivers/radeonsi/radeon_vcn_enc.c | 5 ++ src/gallium/drivers/radeonsi/radeon_vcn_enc.h | 8 +- .../drivers/radeonsi/radeon_vcn_enc_1_2.c | 76 ++++++++++++++++--- src/gallium/frontends/va/picture_h264_enc.c | 16 +++- src/gallium/include/pipe/p_video_state.h | 4 + 5 files changed, 94 insertions(+), 15 deletions(-) diff --git a/src/gallium/drivers/radeonsi/radeon_vcn_enc.c b/src/gallium/drivers/radeonsi/radeon_vcn_enc.c index 2de7ada15b1..50f7efc5609 100644 --- a/src/gallium/drivers/radeonsi/radeon_vcn_enc.c +++ b/src/gallium/drivers/radeonsi/radeon_vcn_enc.c @@ -78,9 +78,13 @@ static void radeon_vcn_enc_get_param(struct radeon_encoder *enc, struct pipe_pic enc->enc_pic.pic_order_cnt = pic->pic_order_cnt; enc->enc_pic.pic_order_cnt_type = pic->pic_order_cnt_type; enc->enc_pic.ref_idx_l0 = pic->ref_idx_l0_list[0]; + enc->enc_pic.ref_idx_l0_is_ltr = pic->l0_is_long_term[0]; enc->enc_pic.ref_idx_l1 = pic->ref_idx_l1_list[0]; + enc->enc_pic.ref_idx_l1_is_ltr = pic->l1_is_long_term[0]; enc->enc_pic.not_referenced = pic->not_referenced; enc->enc_pic.is_idr = (pic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR); + enc->enc_pic.is_ltr = pic->is_ltr; + enc->enc_pic.ltr_idx = pic->is_ltr ? pic->ltr_index : 0; if (pic->pic_ctrl.enc_frame_cropping_flag) { enc->enc_pic.crop_left = pic->pic_ctrl.enc_frame_crop_left_offset; enc->enc_pic.crop_right = pic->pic_ctrl.enc_frame_crop_right_offset; @@ -362,6 +366,7 @@ static int setup_dpb(struct radeon_encoder *enc) enc_pic->ctx_buf.num_reconstructed_pictures = num_reconstructed_pictures; enc_pic->ctx_buf.colloc_buffer_offset = 0; enc->dpb_size = offset; + enc->max_ltr_idx = 0; return offset; } diff --git a/src/gallium/drivers/radeonsi/radeon_vcn_enc.h b/src/gallium/drivers/radeonsi/radeon_vcn_enc.h index f17e6d030af..6bd0c13be65 100644 --- a/src/gallium/drivers/radeonsi/radeon_vcn_enc.h +++ b/src/gallium/drivers/radeonsi/radeon_vcn_enc.h @@ -357,7 +357,8 @@ typedef struct rvcn_enc_reconstructed_picture_s { typedef struct rvcn_enc_picture_info_s { bool in_use; - uint32_t frame_num; + bool is_ltr; + uint32_t pic_num; } rvcn_enc_picture_info_t; typedef struct rvcn_enc_pre_encode_input_picture_s { @@ -458,7 +459,9 @@ struct radeon_enc_pic { unsigned pic_order_cnt; unsigned pic_order_cnt_type; unsigned ref_idx_l0; + bool ref_idx_l0_is_ltr; unsigned ref_idx_l1; + bool ref_idx_l1_is_ltr; unsigned crop_left; unsigned crop_right; unsigned crop_top; @@ -487,6 +490,8 @@ struct radeon_enc_pic { rvcn_enc_quality_modes_t quality_modes; bool not_referenced; + bool is_ltr; + unsigned ltr_idx; bool is_idr; bool is_even_frame; bool sample_adaptive_offset_enabled_flag; @@ -598,6 +603,7 @@ struct radeon_encoder { bool need_feedback; unsigned dpb_size; rvcn_enc_picture_info_t dpb_info[RENCODE_MAX_NUM_RECONSTRUCTED_PICTURES]; + unsigned max_ltr_idx; }; void radeon_enc_add_buffer(struct radeon_encoder *enc, struct pb_buffer *buf, diff --git a/src/gallium/drivers/radeonsi/radeon_vcn_enc_1_2.c b/src/gallium/drivers/radeonsi/radeon_vcn_enc_1_2.c index 86b9efefa0c..d1ea23a2620 100644 --- a/src/gallium/drivers/radeonsi/radeon_vcn_enc_1_2.c +++ b/src/gallium/drivers/radeonsi/radeon_vcn_enc_1_2.c @@ -865,8 +865,17 @@ static void radeon_enc_slice_header(struct radeon_encoder *enc) if (enc->enc_pic.picture_type != PIPE_H2645_ENC_PICTURE_TYPE_IDR) { radeon_enc_code_fixed_bits(enc, 0x0, 1); + /* long-term reference */ + if (enc->enc_pic.ref_idx_l0_is_ltr) { + radeon_enc_code_fixed_bits(enc, 0x1, 1); /* ref_pic_list_modification_flag_l0 */ + radeon_enc_code_ue(enc, 0x2); /* modification_of_pic_nums_idc */ + radeon_enc_code_ue(enc, enc->enc_pic.ref_idx_l0); /* long_term_pic_num */ + radeon_enc_code_ue(enc, 0x3); + } + + /* short-term reference */ /* list_mod_diff_pic_minus1 != 0 */ - if (enc->enc_pic.frame_num - enc->enc_pic.ref_idx_l0 > 1) { + else if (enc->enc_pic.frame_num - enc->enc_pic.ref_idx_l0 > 1) { radeon_enc_code_fixed_bits(enc, 0x1, 1); /* ref_pic_list_modification_flag_l0 */ radeon_enc_code_ue(enc, 0x0); /* modification_of_pic_nums_idc */ /* abs_diff_pic_num_minus1 */ @@ -878,10 +887,22 @@ static void radeon_enc_slice_header(struct radeon_encoder *enc) if (enc->enc_pic.is_idr) { radeon_enc_code_fixed_bits(enc, 0x0, 1); - radeon_enc_code_fixed_bits(enc, 0x0, 1); - } else if (!enc->enc_pic.not_referenced) - radeon_enc_code_fixed_bits(enc, 0x0, 1); - + if (enc->enc_pic.is_ltr) + radeon_enc_code_fixed_bits(enc, 0x1, 1); /* long_term_reference_flag */ + else + radeon_enc_code_fixed_bits(enc, 0x0, 1); + } else if (!enc->enc_pic.not_referenced) { + if (enc->enc_pic.is_ltr) { + radeon_enc_code_fixed_bits(enc, 0x1, 1); + radeon_enc_code_ue(enc, 0x4); /* memory_management_control_operation */ + radeon_enc_code_ue(enc, enc->max_ltr_idx + 1); /* max_long_term_frame_idx_plus1 */ + radeon_enc_code_ue(enc, 0x6); /*memory_management_control_operation */ + radeon_enc_code_ue(enc, enc->enc_pic.ltr_idx); /* long_term_frame_idx */ + radeon_enc_code_ue(enc, 0x0); /*memory_management_control_operation end*/ + } else + radeon_enc_code_fixed_bits(enc, 0x0, 1); + } + if ((enc->enc_pic.picture_type != PIPE_H2645_ENC_PICTURE_TYPE_IDR) && (enc->enc_pic.spec_misc.cabac_enable)) radeon_enc_code_ue(enc, enc->enc_pic.spec_misc.cabac_init_idc); @@ -1312,17 +1333,42 @@ static void destroy(struct radeon_encoder *enc) *enc->p_task_size = (enc->total_task_size); } -static int find_short_ref_idx(struct radeon_encoder *enc, int frame_num) +static int find_ref_idx(struct radeon_encoder *enc, int pic_num, bool is_ltr) { - for (int i = 0; i < enc->base.max_references + 1; i++) - if (enc->dpb_info[i].frame_num == frame_num && enc->dpb_info[i].in_use) + for (int i = 0; i < enc->base.max_references + 1; i++) { + if (enc->dpb_info[i].pic_num == pic_num && + enc->dpb_info[i].in_use && + enc->dpb_info[i].is_ltr == is_ltr) return i; + } return -1; } static int get_picture_storage(struct radeon_encoder *enc) { + if (enc->enc_pic.is_ltr) { + if (enc->enc_pic.is_idr) { + enc->enc_pic.ltr_idx = 0; + enc->max_ltr_idx = 0; + } + /* + find ltr with the same ltr_idx to replace + if this is a new ltr_idx, increase max_ltr_idx and use the normal logic to find slot + */ + if (enc->enc_pic.ltr_idx <= enc->max_ltr_idx) { + for (int i = 0; i < enc->base.max_references + 1; i++) { + if (enc->dpb_info[i].in_use && + enc->dpb_info[i].is_ltr && + enc->enc_pic.ltr_idx == enc->dpb_info[i].pic_num) { + enc->dpb_info[i].in_use = FALSE; + return i; + } + } + } else + enc->max_ltr_idx = enc->enc_pic.ltr_idx; + } + for (int i = 0; i < enc->base.max_references + 1; i++) { if (!enc->dpb_info[i].in_use) { memset(&(enc->dpb_info[i]), 0, sizeof(rvcn_enc_picture_info_t)); @@ -1334,8 +1380,8 @@ static int get_picture_storage(struct radeon_encoder *enc) unsigned int oldest_frame_num = 0xFFFFFFFF; int oldest_idx = -1; for (int i = 0; i < enc->base.max_references + 1; i++) - if (enc->dpb_info[i].frame_num < oldest_frame_num) { - oldest_frame_num = enc->dpb_info[i].frame_num; + if (!enc->dpb_info[i].is_ltr && enc->dpb_info[i].pic_num < oldest_frame_num) { + oldest_frame_num = enc->dpb_info[i].pic_num; oldest_idx = i; } @@ -1358,12 +1404,18 @@ static void manage_dpb_before_encode(struct radeon_encoder *enc) current_pic_idx = get_picture_storage(enc); assert(current_pic_idx >= 0); - int ref0_idx = find_short_ref_idx(enc, enc->enc_pic.ref_idx_l0); + int ref0_idx = find_ref_idx(enc, enc->enc_pic.ref_idx_l0, enc->enc_pic.ref_idx_l0_is_ltr); if (!enc->enc_pic.not_referenced) enc->dpb_info[current_pic_idx].in_use = TRUE; - enc->dpb_info[current_pic_idx].frame_num = enc->enc_pic.frame_num; + if (enc->enc_pic.is_ltr) { + enc->dpb_info[current_pic_idx].pic_num = enc->enc_pic.ltr_idx; + enc->dpb_info[current_pic_idx].is_ltr = TRUE; + } else { + enc->dpb_info[current_pic_idx].pic_num = enc->enc_pic.frame_num; + enc->dpb_info[current_pic_idx].is_ltr = FALSE; + } if (enc->enc_pic.picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR) enc->enc_pic.enc_params.reference_picture_index = 0xFFFFFFFF; diff --git a/src/gallium/frontends/va/picture_h264_enc.c b/src/gallium/frontends/va/picture_h264_enc.c index 9fe12d2a4d6..75a0af2129f 100644 --- a/src/gallium/frontends/va/picture_h264_enc.c +++ b/src/gallium/frontends/va/picture_h264_enc.c @@ -40,6 +40,9 @@ vlVaHandleVAEncPictureParameterBufferTypeH264(vlVaDriver *drv, vlVaContext *cont context->desc.h264enc.frame_num = 0; context->desc.h264enc.not_referenced = !h264->pic_fields.bits.reference_pic_flag; context->desc.h264enc.pic_order_cnt = h264->CurrPic.TopFieldOrderCnt; + context->desc.h264enc.is_ltr = h264->CurrPic.flags & VA_PICTURE_H264_LONG_TERM_REFERENCE; + if (context->desc.h264enc.is_ltr) + context->desc.h264enc.ltr_index = h264->CurrPic.frame_idx; if (context->desc.h264enc.gop_cnt == 0) context->desc.h264enc.i_remain = context->gop_coeff; else if (context->desc.h264enc.frame_num == 1) @@ -53,7 +56,12 @@ vlVaHandleVAEncPictureParameterBufferTypeH264(vlVaDriver *drv, vlVaContext *cont PIPE_USAGE_STREAM, coded_buf->size); context->coded_buf = coded_buf; - _mesa_hash_table_insert(context->desc.h264enc.frame_idx, + if (context->desc.h264enc.is_ltr) + _mesa_hash_table_insert(context->desc.h264enc.frame_idx, + UINT_TO_PTR(h264->CurrPic.picture_id + 1), + UINT_TO_PTR(context->desc.h264enc.ltr_index)); + else + _mesa_hash_table_insert(context->desc.h264enc.frame_idx, UINT_TO_PTR(h264->CurrPic.picture_id + 1), UINT_TO_PTR(context->desc.h264enc.frame_num)); @@ -98,10 +106,14 @@ vlVaHandleVAEncSliceParameterBufferTypeH264(vlVaDriver *drv, vlVaContext *contex if (h264->RefPicList0[i].picture_id != VA_INVALID_ID) { context->desc.h264enc.ref_idx_l0_list[i] = PTR_TO_UINT(util_hash_table_get(context->desc.h264enc.frame_idx, UINT_TO_PTR(h264->RefPicList0[i].picture_id + 1))); + context->desc.h264enc.l0_is_long_term[i] = h264->RefPicList0[i].flags & + VA_PICTURE_H264_LONG_TERM_REFERENCE; } if (h264->RefPicList1[i].picture_id != VA_INVALID_ID && h264->slice_type == 1) { context->desc.h264enc.ref_idx_l1_list[i] = PTR_TO_UINT(util_hash_table_get(context->desc.h264enc.frame_idx, - UINT_TO_PTR(h264->RefPicList1[i].picture_id + 1))); + UINT_TO_PTR(h264->RefPicList1[i].picture_id + 1))); + context->desc.h264enc.l1_is_long_term[i] = h264->RefPicList1[i].flags & + VA_PICTURE_H264_LONG_TERM_REFERENCE; } } diff --git a/src/gallium/include/pipe/p_video_state.h b/src/gallium/include/pipe/p_video_state.h index dbbbc098766..f9d184c7c59 100644 --- a/src/gallium/include/pipe/p_video_state.h +++ b/src/gallium/include/pipe/p_video_state.h @@ -481,12 +481,16 @@ struct pipe_h264_enc_picture_desc unsigned num_ref_idx_l0_active_minus1; unsigned num_ref_idx_l1_active_minus1; unsigned ref_idx_l0_list[32]; + bool l0_is_long_term[32]; unsigned ref_idx_l1_list[32]; + bool l1_is_long_term[32]; unsigned gop_size; unsigned num_temporal_layers; struct pipe_enc_quality_modes quality_modes; bool not_referenced; + bool is_ltr; + unsigned ltr_index; bool enable_vui; struct hash_table *frame_idx;