From 32c6a61e2b1387c3c12cfd909b1dd08992bf7d85 Mon Sep 17 00:00:00 2001 From: David Rosca Date: Fri, 2 Aug 2024 17:07:57 +0200 Subject: [PATCH] radeonsi/vcn: Switch to app DPB management for H264 and HEVC encode This removes the internal DPB management logic, which was unnecessary as it was duplicating what applications already do, and it was also causing issues when the internal DPB would de-sync from application DPB (eg. driver removes reference that application still intends to use). DPB is now dynamically resized instead of using fixed number of slots. This also saves a lot of memory with HEVC encoding, as that was always using the max_references which va frontend sets to 15. Move reconstructed pictures to the end of the context and meta buffers to ensure resizing works correctly. Reviewed-by: Ruijing Dong Part-of: --- src/amd/common/ac_vcn_enc.h | 7 -- src/gallium/drivers/radeonsi/radeon_vcn_enc.c | 83 ++++++++---- src/gallium/drivers/radeonsi/radeon_vcn_enc.h | 2 +- .../drivers/radeonsi/radeon_vcn_enc_1_2.c | 118 +----------------- 4 files changed, 58 insertions(+), 152 deletions(-) diff --git a/src/amd/common/ac_vcn_enc.h b/src/amd/common/ac_vcn_enc.h index eaa96e284be..a7f5bbf558f 100644 --- a/src/amd/common/ac_vcn_enc.h +++ b/src/amd/common/ac_vcn_enc.h @@ -534,13 +534,6 @@ typedef struct rvcn_enc_reconstructed_picture_s { uint32_t encode_metadata_offset; /* vcn5 only */ } rvcn_enc_reconstructed_picture_t; -typedef struct rvcn_enc_picture_info_s -{ - bool in_use; - bool is_ltr; - uint32_t pic_num; -} rvcn_enc_picture_info_t; - typedef struct rvcn_enc_pre_encode_input_picture_s { union { struct { diff --git a/src/gallium/drivers/radeonsi/radeon_vcn_enc.c b/src/gallium/drivers/radeonsi/radeon_vcn_enc.c index 732284f039f..0fc402f93ac 100644 --- a/src/gallium/drivers/radeonsi/radeon_vcn_enc.c +++ b/src/gallium/drivers/radeonsi/radeon_vcn_enc.c @@ -483,6 +483,12 @@ static void radeon_vcn_enc_h264_get_param(struct radeon_encoder *enc, 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.enc_params.reference_picture_index = + pic->ref_list0[0] == PIPE_H2645_LIST_REF_INVALID_ENTRY ? 0xffffffff : pic->ref_list0[0]; + enc->enc_pic.h264_enc_params.l1_reference_picture0_index = + pic->ref_list1[0] == PIPE_H2645_LIST_REF_INVALID_ENTRY ? 0xffffffff : pic->ref_list1[0]; + enc->enc_pic.enc_params.reconstructed_picture_index = pic->dpb_curr_pic; + enc->enc_pic.h264_enc_params.is_reference = !pic->not_referenced; 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; @@ -729,6 +735,9 @@ static void radeon_vcn_enc_hevc_get_param(struct radeon_encoder *enc, enc->enc_pic.ref_idx_l0 = pic->ref_idx_l0_list[0]; enc->enc_pic.ref_idx_l1 = pic->ref_idx_l1_list[0]; enc->enc_pic.not_referenced = pic->not_referenced; + enc->enc_pic.enc_params.reference_picture_index = + pic->ref_list0[0] == PIPE_H2645_LIST_REF_INVALID_ENTRY ? 0xffffffff : pic->ref_list0[0]; + enc->enc_pic.enc_params.reconstructed_picture_index = pic->dpb_curr_pic; enc->enc_pic.is_idr = (pic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR); radeon_vcn_enc_hevc_get_cropping_param(enc, pic); enc->enc_pic.general_tier_flag = pic->seq.general_tier_flag; @@ -1190,7 +1199,7 @@ static void pre_encode_size(struct radeon_encoder *enc, *offset += align((pre_size * 52 + full_size) * sizeof(uint32_t), enc->alignment); } -static int setup_dpb(struct radeon_encoder *enc) +static int setup_dpb(struct radeon_encoder *enc, uint32_t num_reconstructed_pictures) { struct si_screen *sscreen = (struct si_screen *)enc->screen; bool is_h264 = u_reduce_video_profile(enc->base.profile) @@ -1201,7 +1210,6 @@ static int setup_dpb(struct radeon_encoder *enc) uint32_t aligned_width = align(enc->base.width, rec_alignment); uint32_t aligned_height = align(enc->base.height, rec_alignment); uint32_t pitch = align(aligned_width, enc->alignment); - uint32_t num_reconstructed_pictures = enc->base.max_references + 1; uint32_t luma_size, chroma_size, offset; struct radeon_enc_pic *enc_pic = &enc->enc_pic; int i; @@ -1229,11 +1237,26 @@ static int setup_dpb(struct radeon_encoder *enc) if (sscreen->info.vcn_ip_version < VCN_5_0_0) { enc_pic->ctx_buf.rec_chroma_pitch = pitch; enc_pic->ctx_buf.pre_encode_picture_chroma_pitch = pitch; + if (has_b) { + enc_pic->ctx_buf.colloc_buffer_offset = offset; + offset += total_coloc_bytes; + } else + enc_pic->ctx_buf.colloc_buffer_offset = 0; + if (enc_pic->quality_modes.pre_encode_mode) pre_encode_size(enc, &offset); else enc_pic->ctx_buf.two_pass_search_center_map_offset = 0; + if (enc_pic->quality_modes.pre_encode_mode) { + enc_pic->ctx_buf.pre_encode_input_picture.rgb.red_offset = offset; + offset += luma_size; + enc_pic->ctx_buf.pre_encode_input_picture.rgb.green_offset = offset; + offset += luma_size; + enc_pic->ctx_buf.pre_encode_input_picture.rgb.blue_offset = offset; + offset += luma_size; + } + if (is_av1) { enc_pic->ctx_buf.av1.av1_sdb_intermediate_context_offset = offset; offset += RENCODE_AV1_SDB_FRAME_CONTEXT_SIZE; @@ -1256,21 +1279,6 @@ static int setup_dpb(struct radeon_encoder *enc) NULL, 0, 0, false); } - if (enc_pic->quality_modes.pre_encode_mode) { - enc_pic->ctx_buf.pre_encode_input_picture.rgb.red_offset = offset; - offset += luma_size; - enc_pic->ctx_buf.pre_encode_input_picture.rgb.green_offset = offset; - offset += luma_size; - enc_pic->ctx_buf.pre_encode_input_picture.rgb.blue_offset = offset; - offset += luma_size; - } - - if (has_b) { - enc_pic->ctx_buf.colloc_buffer_offset = offset; - offset += total_coloc_bytes; - } else - enc_pic->ctx_buf.colloc_buffer_offset = 0; - enc->dpb_size = offset; } else { /* vcn 5.0 */ enc_pic->ctx_buf.rec_chroma_pitch = pitch / 2; @@ -1282,6 +1290,15 @@ static int setup_dpb(struct radeon_encoder *enc) } else enc_pic->ctx_buf.av1.av1_sdb_intermediate_context_offset = 0; + if (enc_pic->quality_modes.pre_encode_mode) { + enc_pic->ctx_buf.pre_encode_input_picture.rgb.red_offset = offset; + offset += luma_size; + enc_pic->ctx_buf.pre_encode_input_picture.rgb.green_offset = offset; + offset += luma_size; + enc_pic->ctx_buf.pre_encode_input_picture.rgb.blue_offset = offset; + offset += luma_size; + } + for (i = 0; i < num_reconstructed_pictures; i++) { radeon_enc_rec_offset(&enc_pic->ctx_buf.reconstructed_pictures[i], &offset, luma_size, chroma_size, false); @@ -1299,15 +1316,6 @@ static int setup_dpb(struct radeon_encoder *enc) NULL, 0, 0, false); } - if (enc_pic->quality_modes.pre_encode_mode) { - enc_pic->ctx_buf.pre_encode_input_picture.rgb.red_offset = offset; - offset += luma_size; - enc_pic->ctx_buf.pre_encode_input_picture.rgb.green_offset = offset; - offset += luma_size; - enc_pic->ctx_buf.pre_encode_input_picture.rgb.blue_offset = offset; - offset += luma_size; - } - enc->dpb_size = offset; /* meta buffer*/ @@ -1334,6 +1342,8 @@ static int setup_dpb(struct radeon_encoder *enc) enc->metadata_size = offset; } + enc->dpb_slots = num_reconstructed_pictures; + return offset; } @@ -1418,11 +1428,14 @@ static void radeon_enc_begin_frame(struct pipe_video_codec *encoder, struct radeon_encoder *enc = (struct radeon_encoder *)encoder; struct si_screen *sscreen = (struct si_screen *)enc->screen; struct vl_video_buffer *vid_buf = (struct vl_video_buffer *)source; + unsigned dpb_slots = 0; + enc->need_rate_control = false; enc->need_rc_per_pic = false; if (u_reduce_video_profile(enc->base.profile) == PIPE_VIDEO_FORMAT_MPEG4_AVC) { struct pipe_h264_enc_picture_desc *pic = (struct pipe_h264_enc_picture_desc *)picture; + dpb_slots = MAX2(pic->seq.max_num_ref_frames + 1, pic->dpb_size); enc->need_rate_control = (enc->enc_pic.rc_layer_init[0].target_bit_rate != pic->rate_ctrl[0].target_bitrate) || (enc->enc_pic.rc_layer_init[0].frame_rate_num != pic->rate_ctrl[0].frame_rate_num) || @@ -1441,6 +1454,7 @@ static void radeon_enc_begin_frame(struct pipe_video_codec *encoder, (enc->enc_pic.rc_per_pic.qvbr_quality_level != pic->rate_ctrl[0].vbr_quality_factor); } else if (u_reduce_video_profile(picture->profile) == PIPE_VIDEO_FORMAT_HEVC) { struct pipe_h265_enc_picture_desc *pic = (struct pipe_h265_enc_picture_desc *)picture; + dpb_slots = MAX2(pic->pic.num_ref_idx_l0_default_active_minus1 + 2, pic->dpb_size); enc->need_rate_control = (enc->enc_pic.rc_layer_init[0].target_bit_rate != pic->rc[0].target_bitrate) || (enc->enc_pic.rc_layer_init[0].frame_rate_num != pic->rc[0].frame_rate_num) || @@ -1482,9 +1496,11 @@ static void radeon_enc_begin_frame(struct pipe_video_codec *encoder, } radeon_vcn_enc_get_param(enc, picture); + if (u_reduce_video_profile(picture->profile) == PIPE_VIDEO_FORMAT_AV1) + dpb_slots = enc->base.max_references + 1; if (!enc->dpb) { enc->dpb = CALLOC_STRUCT(rvid_buffer); - setup_dpb(enc); + setup_dpb(enc, dpb_slots); if (!enc->dpb || !si_vid_create_buffer(enc->screen, enc->dpb, enc->dpb_size, PIPE_USAGE_DEFAULT)) { RVID_ERR("Can't create DPB buffer.\n"); @@ -1501,6 +1517,19 @@ static void radeon_enc_begin_frame(struct pipe_video_codec *encoder, } } + if (dpb_slots > enc->dpb_slots) { + setup_dpb(enc, dpb_slots); + if (!si_vid_resize_buffer(enc->base.context, &enc->cs, enc->dpb, enc->dpb_size, NULL)) { + RVID_ERR("Can't resize DPB buffer.\n"); + goto error; + } + if (sscreen->info.vcn_ip_version >= VCN_5_0_0 && enc->metadata_size && + !si_vid_resize_buffer(enc->base.context, &enc->cs, enc->meta, enc->metadata_size, NULL)) { + RVID_ERR("Can't resize meta buffer.\n"); + goto error; + } + } + /* qp map buffer could be created here, and release at the end */ if (enc->enc_pic.enc_qp_map.qp_map_type != RENCODE_QP_MAP_TYPE_NONE) { if (!enc->roi) { diff --git a/src/gallium/drivers/radeonsi/radeon_vcn_enc.h b/src/gallium/drivers/radeonsi/radeon_vcn_enc.h index be60baaa9d7..796b7388f51 100644 --- a/src/gallium/drivers/radeonsi/radeon_vcn_enc.h +++ b/src/gallium/drivers/radeonsi/radeon_vcn_enc.h @@ -296,9 +296,9 @@ struct radeon_encoder { bool need_rate_control; bool need_rc_per_pic; unsigned dpb_size; + unsigned dpb_slots; unsigned roi_size; unsigned metadata_size; - rvcn_enc_picture_info_t dpb_info[RENCODE_MAX_NUM_RECONSTRUCTED_PICTURES]; unsigned max_ltr_idx; struct pipe_context *ectx; 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 8cce71ac21e..2e08171e2d2 100644 --- a/src/gallium/drivers/radeonsi/radeon_vcn_enc_1_2.c +++ b/src/gallium/drivers/radeonsi/radeon_vcn_enc_1_2.c @@ -1546,125 +1546,9 @@ static void destroy(struct radeon_encoder *enc) *enc->p_task_size = (enc->total_task_size); } -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].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)); - return i; - } - } - - /* look for the oldest short term ref pic */ - 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].is_ltr && enc->dpb_info[i].pic_num < oldest_frame_num) { - oldest_frame_num = enc->dpb_info[i].pic_num; - oldest_idx = i; - } - - if (oldest_idx >= 0) - enc->dpb_info[oldest_idx].in_use = false; - - return oldest_idx; -} - -static void manage_dpb_before_encode(struct radeon_encoder *enc) -{ - int current_pic_idx = 0; - - if (enc->enc_pic.picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR) { - /* clear reference frames */ - for (int i = 0; i < enc->base.max_references + 1; i++) - memset(&(enc->dpb_info[i]), 0, sizeof(rvcn_enc_picture_info_t)); - } - - current_pic_idx = get_picture_storage(enc); - assert(current_pic_idx >= 0); - - int ref0_idx = find_ref_idx(enc, enc->enc_pic.ref_idx_l0, enc->enc_pic.ref_idx_l0_is_ltr); - /* B-frames only supported on VCN >= 3.0 */ - int ref1_idx = find_ref_idx(enc, enc->enc_pic.ref_idx_l1, enc->enc_pic.ref_idx_l1_is_ltr); - - assert(enc->enc_pic.picture_type != PIPE_H2645_ENC_PICTURE_TYPE_P || - ref0_idx != -1); - assert(enc->enc_pic.picture_type != PIPE_H2645_ENC_PICTURE_TYPE_B || - (ref0_idx != -1 && ref1_idx != -1)); - - /* In case we didn't find the reference in dpb, we have to pick - * some valid index to prevent GPU hang. */ - if ((enc->enc_pic.picture_type == PIPE_H2645_ENC_PICTURE_TYPE_P || - enc->enc_pic.picture_type == PIPE_H2645_ENC_PICTURE_TYPE_B) && - ref0_idx == -1) { - RVID_ERR("Failed to find ref0 (%u).\n", enc->enc_pic.ref_idx_l0); - ref0_idx = (current_pic_idx + 1) % (enc->base.max_references + 1); - } - - if (enc->enc_pic.picture_type == PIPE_H2645_ENC_PICTURE_TYPE_B && ref1_idx == -1) { - RVID_ERR("Failed to find ref1 (%u).\n", enc->enc_pic.ref_idx_l1); - ref1_idx = (current_pic_idx + 2) % (enc->base.max_references + 1); - } - - if (!enc->enc_pic.not_referenced) - enc->dpb_info[current_pic_idx].in_use = true; - - 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; - enc->enc_pic.h264_enc_params.l1_reference_picture0_index = 0xFFFFFFFF; - } else { - enc->enc_pic.enc_params.reference_picture_index = ref0_idx; - enc->enc_pic.h264_enc_params.l1_reference_picture0_index = ref1_idx; - } - enc->enc_pic.enc_params.reconstructed_picture_index = current_pic_idx; - enc->enc_pic.h264_enc_params.is_reference = !enc->enc_pic.not_referenced; -} - void radeon_enc_1_2_init(struct radeon_encoder *enc) { - enc->before_encode = manage_dpb_before_encode; + enc->before_encode = radeon_enc_dummy; enc->begin = begin; enc->encode = encode; enc->destroy = destroy;