From ac45a57bfcae873875a7e65ee152f2a9555f10e7 Mon Sep 17 00:00:00 2001 From: David Rosca Date: Fri, 9 Feb 2024 13:13:41 +0100 Subject: [PATCH] radeonsi/vcn: Don't reinitialize encode session on bitrate/fps change When bitrate or fps change is detected, only update rate control parameters instead of completely reinitializing encode session. This fixes an issue where if application changed bitrate or fps often, the output bitrate would significantly overshoot the target bitrate in some cases. In other cases, the output bitrate would be extremely low instead. Cc: mesa-stable Reviewed-by: Ruijing Dong Part-of: (cherry picked from commit 8d44a115080645c210e055fa410fb18accf510aa) --- .pick_status.json | 2 +- src/gallium/drivers/radeonsi/radeon_vcn_enc.c | 27 +++++++++---------- src/gallium/drivers/radeonsi/radeon_vcn_enc.h | 1 + .../drivers/radeonsi/radeon_vcn_enc_1_2.c | 11 ++++++++ .../drivers/radeonsi/radeon_vcn_enc_2_0.c | 11 ++++++++ 5 files changed, 37 insertions(+), 15 deletions(-) diff --git a/.pick_status.json b/.pick_status.json index 53d5ce9da1a..adee376706d 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -1544,7 +1544,7 @@ "description": "radeonsi/vcn: Don't reinitialize encode session on bitrate/fps change", "nominated": true, "nomination_type": 0, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": null, "notes": null diff --git a/src/gallium/drivers/radeonsi/radeon_vcn_enc.c b/src/gallium/drivers/radeonsi/radeon_vcn_enc.c index 49cedd12b28..ef30952d31f 100644 --- a/src/gallium/drivers/radeonsi/radeon_vcn_enc.c +++ b/src/gallium/drivers/radeonsi/radeon_vcn_enc.c @@ -840,23 +840,23 @@ static void radeon_enc_begin_frame(struct pipe_video_codec *encoder, { struct radeon_encoder *enc = (struct radeon_encoder *)encoder; struct vl_video_buffer *vid_buf = (struct vl_video_buffer *)source; - bool need_rate_control = false; + enc->need_rate_control = 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; - need_rate_control = + 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) || (enc->enc_pic.rc_layer_init[0].frame_rate_den != pic->rate_ctrl[0].frame_rate_den); } 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; - need_rate_control = + enc->need_rate_control = (enc->enc_pic.rc_layer_init[0].target_bit_rate != pic->rc.target_bitrate) || (enc->enc_pic.rc_layer_init[0].frame_rate_num != pic->rc.frame_rate_num) || (enc->enc_pic.rc_layer_init[0].frame_rate_den != pic->rc.frame_rate_den); } else if (u_reduce_video_profile(picture->profile) == PIPE_VIDEO_FORMAT_AV1) { struct pipe_av1_enc_picture_desc *pic = (struct pipe_av1_enc_picture_desc *)picture; - need_rate_control = + 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) || (enc->enc_pic.rc_layer_init[0].frame_rate_den != pic->rc[0].frame_rate_den); @@ -894,23 +894,22 @@ static void radeon_enc_begin_frame(struct pipe_video_codec *encoder, enc->need_feedback = false; - if (!enc->stream_handle || need_rate_control) { + if (!enc->stream_handle) { struct rvid_buffer fb; - if (!enc->stream_handle) { - enc->stream_handle = si_vid_alloc_stream_handle(); - enc->si = CALLOC_STRUCT(rvid_buffer); - if (!enc->si || - !enc->stream_handle || - !si_vid_create_buffer(enc->screen, enc->si, 128 * 1024, PIPE_USAGE_STAGING)) { - RVID_ERR("Can't create session buffer.\n"); - goto error; - } + enc->stream_handle = si_vid_alloc_stream_handle(); + enc->si = CALLOC_STRUCT(rvid_buffer); + if (!enc->si || + !enc->stream_handle || + !si_vid_create_buffer(enc->screen, enc->si, 128 * 1024, PIPE_USAGE_STAGING)) { + RVID_ERR("Can't create session buffer.\n"); + goto error; } si_vid_create_buffer(enc->screen, &fb, 4096, PIPE_USAGE_STAGING); enc->fb = &fb; enc->begin(enc); flush(enc); si_vid_destroy_buffer(&fb); + enc->need_rate_control = false; } return; diff --git a/src/gallium/drivers/radeonsi/radeon_vcn_enc.h b/src/gallium/drivers/radeonsi/radeon_vcn_enc.h index 99aab4ff2cd..5defa68d6cd 100644 --- a/src/gallium/drivers/radeonsi/radeon_vcn_enc.h +++ b/src/gallium/drivers/radeonsi/radeon_vcn_enc.h @@ -258,6 +258,7 @@ struct radeon_encoder { bool emulation_prevention; bool need_feedback; + bool need_rate_control; unsigned dpb_size; rvcn_enc_picture_info_t dpb_info[RENCODE_MAX_NUM_RECONSTRUCTED_PICTURES]; unsigned max_ltr_idx; 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 6ad6aa23c30..9eb6290a593 100644 --- a/src/gallium/drivers/radeonsi/radeon_vcn_enc_1_2.c +++ b/src/gallium/drivers/radeonsi/radeon_vcn_enc_1_2.c @@ -1381,11 +1381,22 @@ static void radeon_enc_headers_hevc(struct radeon_encoder *enc) static void encode(struct radeon_encoder *enc) { + unsigned i; + enc->before_encode(enc); enc->session_info(enc); enc->total_task_size = 0; enc->task_info(enc, enc->need_feedback); + if (enc->need_rate_control) { + i = 0; + do { + enc->enc_pic.temporal_id = i; + enc->layer_select(enc); + enc->rc_layer_init(enc); + } while (++i < enc->enc_pic.num_temporal_layers); + } + enc->encode_headers(enc); enc->ctx(enc); enc->bitstream(enc); diff --git a/src/gallium/drivers/radeonsi/radeon_vcn_enc_2_0.c b/src/gallium/drivers/radeonsi/radeon_vcn_enc_2_0.c index 7682af34f70..34e75033fab 100644 --- a/src/gallium/drivers/radeonsi/radeon_vcn_enc_2_0.c +++ b/src/gallium/drivers/radeonsi/radeon_vcn_enc_2_0.c @@ -503,11 +503,22 @@ static void radeon_enc_ctx(struct radeon_encoder *enc) } static void encode(struct radeon_encoder *enc) { + unsigned i; + enc->before_encode(enc); enc->session_info(enc); enc->total_task_size = 0; enc->task_info(enc, enc->need_feedback); + if (enc->need_rate_control) { + i = 0; + do { + enc->enc_pic.temporal_id = i; + enc->layer_select(enc); + enc->rc_layer_init(enc); + } while (++i < enc->enc_pic.num_temporal_layers); + } + enc->encode_headers(enc); enc->ctx(enc); enc->bitstream(enc);