Module: Mesa Branch: main Commit: 7fae1c46adcb33829786686c5232664a95ec10cf URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=7fae1c46adcb33829786686c5232664a95ec10cf
Author: Ruijing Dong <ruijing.d...@amd.com> Date: Thu Nov 9 11:58:51 2023 -0500 radonesi/vcn: enable intra-refresh in vcn encoders Enable intra-fresh in vcn encoders and support avc/hevc/av1 codecs. Just if B frames is enabled or the number of temporal layers is larger than 1, intra-refresh will be disabled, because it doesn't support intra-refresh on B frames, and on sub-temporal layers. Reviewed-by: Leo Liu <leo....@amd.com> Reviewed-by: Boyuan Zhang <boyuan.zh...@amd.com> Signed-off-by: Ruijing Dong <ruijing.d...@amd.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26133> --- src/gallium/drivers/radeonsi/radeon_vcn_enc.c | 70 +++++++++++++++++++++++ src/gallium/drivers/radeonsi/radeon_vcn_enc_1_2.c | 8 +-- src/gallium/drivers/radeonsi/radeon_vcn_enc_4_0.c | 2 +- src/gallium/drivers/radeonsi/si_get.c | 10 ++++ 4 files changed, 83 insertions(+), 7 deletions(-) diff --git a/src/gallium/drivers/radeonsi/radeon_vcn_enc.c b/src/gallium/drivers/radeonsi/radeon_vcn_enc.c index 49cedd12b28..73379aa221b 100644 --- a/src/gallium/drivers/radeonsi/radeon_vcn_enc.c +++ b/src/gallium/drivers/radeonsi/radeon_vcn_enc.c @@ -63,6 +63,64 @@ static uint32_t radeon_vcn_per_frame_frac(uint32_t bitrate, uint32_t den, uint32 return (uint32_t)((remainder << 32) / num); } +static void radeon_vcn_enc_get_intra_refresh_param(struct radeon_encoder *enc, + bool need_filter_overlap, + struct pipe_enc_intra_refresh *intra_refresh) +{ + bool is_h264; + uint32_t block_length, width_in_block, height_in_block; + + enc->enc_pic.intra_refresh.intra_refresh_mode = RENCODE_INTRA_REFRESH_MODE_NONE; + /* some exceptions where intra-refresh is disabled: + * 1. if B frame is enabled + * 2. if SVC (number of temproal layers is larger than 1) is enabled + */ + if (enc->enc_pic.spec_misc.b_picture_enabled || enc->enc_pic.num_temporal_layers > 1) { + enc->enc_pic.intra_refresh.region_size = 0; + enc->enc_pic.intra_refresh.offset = 0; + enc->enc_pic.need_sequence_header = 0; + return; + } + + is_h264 = u_reduce_video_profile(enc->base.profile) == PIPE_VIDEO_FORMAT_MPEG4_AVC; + /* hevc and av1 are sharing the same alignment size 64 */ + block_length = is_h264 ? PIPE_H264_MB_SIZE : PIPE_H265_ENC_CTB_SIZE; + width_in_block = PIPE_ALIGN_IN_BLOCK_SIZE(enc->base.width, block_length); + height_in_block = PIPE_ALIGN_IN_BLOCK_SIZE(enc->base.height, block_length); + + switch(intra_refresh->mode) { + case INTRA_REFRESH_MODE_UNIT_ROWS: + if (intra_refresh->offset < height_in_block) + enc->enc_pic.intra_refresh.intra_refresh_mode + = RENCODE_INTRA_REFRESH_MODE_CTB_MB_ROWS; + break; + case INTRA_REFRESH_MODE_UNIT_COLUMNS: + if (intra_refresh->offset < width_in_block) + enc->enc_pic.intra_refresh.intra_refresh_mode + = RENCODE_INTRA_REFRESH_MODE_CTB_MB_COLUMNS; + break; + case INTRA_REFRESH_MODE_NONE: + default: + break; + }; + + /* with loop filters (avc/hevc/av1) enabled the region_size has to increase 1 to + * get overlapped (av1 is enabling it all the time). The region_size and offset + * require to be in unit of MB or CTB or SB according to different codecs. + */ + if (enc->enc_pic.intra_refresh.intra_refresh_mode != RENCODE_INTRA_REFRESH_MODE_NONE) { + enc->enc_pic.intra_refresh.region_size = (need_filter_overlap) ? + intra_refresh->region_size + 1 : + intra_refresh->region_size; + enc->enc_pic.intra_refresh.offset = intra_refresh->offset; + enc->enc_pic.need_sequence_header = !!(intra_refresh->need_sequence_header); + } else { + enc->enc_pic.intra_refresh.region_size = 0; + enc->enc_pic.intra_refresh.offset = 0; + enc->enc_pic.need_sequence_header = 0; + } +} + static void radeon_vcn_enc_h264_get_cropping_param(struct radeon_encoder *enc, struct pipe_h264_enc_picture_desc *pic) { @@ -282,6 +340,8 @@ static void radeon_vcn_enc_get_input_format_param(struct radeon_encoder *enc, static void radeon_vcn_enc_h264_get_param(struct radeon_encoder *enc, struct pipe_h264_enc_picture_desc *pic) { + bool use_filter; + enc->enc_pic.picture_type = pic->picture_type; enc->enc_pic.bit_depth_luma_minus8 = 0; enc->enc_pic.bit_depth_chroma_minus8 = 0; @@ -305,6 +365,9 @@ static void radeon_vcn_enc_h264_get_param(struct radeon_encoder *enc, radeon_vcn_enc_h264_get_slice_ctrl_param(enc, pic); radeon_vcn_enc_get_input_format_param(enc, &pic->base); radeon_vcn_enc_get_output_format_param(enc, pic->seq.video_full_range_flag); + + use_filter = enc->enc_pic.h264_deblock.disable_deblocking_filter_idc != 1; + radeon_vcn_enc_get_intra_refresh_param(enc, use_filter, &pic->intra_refresh); } static void radeon_vcn_enc_hevc_get_cropping_param(struct radeon_encoder *enc, @@ -516,6 +579,9 @@ static void radeon_vcn_enc_hevc_get_param(struct radeon_encoder *enc, radeon_vcn_enc_hevc_get_slice_ctrl_param(enc, pic); radeon_vcn_enc_get_input_format_param(enc, &pic->base); radeon_vcn_enc_get_output_format_param(enc, pic->seq.video_full_range_flag); + radeon_vcn_enc_get_intra_refresh_param(enc, + !(enc->enc_pic.hevc_deblock.deblocking_filter_disabled), + &pic->intra_refresh); } static void radeon_vcn_enc_av1_get_spec_misc_param(struct radeon_encoder *enc, @@ -659,6 +725,10 @@ static void radeon_vcn_enc_av1_get_param(struct radeon_encoder *enc, radeon_vcn_enc_av1_get_rc_param(enc, pic); radeon_vcn_enc_get_input_format_param(enc, &pic->base); radeon_vcn_enc_get_output_format_param(enc, pic->seq.color_config.color_range); + /* loop filter enabled all the time */ + radeon_vcn_enc_get_intra_refresh_param(enc, + true, + &pic->intra_refresh); } static void radeon_vcn_enc_get_param(struct radeon_encoder *enc, struct pipe_picture_desc *picture) 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 1b2ced9d57a..6167c9575ab 100644 --- a/src/gallium/drivers/radeonsi/radeon_vcn_enc_1_2.c +++ b/src/gallium/drivers/radeonsi/radeon_vcn_enc_1_2.c @@ -1176,10 +1176,6 @@ static void radeon_enc_feedback(struct radeon_encoder *enc) static void radeon_enc_intra_refresh(struct radeon_encoder *enc) { - enc->enc_pic.intra_refresh.intra_refresh_mode = RENCODE_INTRA_REFRESH_MODE_NONE; - enc->enc_pic.intra_refresh.offset = 0; - enc->enc_pic.intra_refresh.region_size = 0; - RADEON_ENC_BEGIN(enc->cmd.intra_refresh); RADEON_ENC_CS(enc->enc_pic.intra_refresh.intra_refresh_mode); RADEON_ENC_CS(enc->enc_pic.intra_refresh.offset); @@ -1354,7 +1350,7 @@ static void radeon_enc_headers_h264(struct radeon_encoder *enc) enc->nalu_aud(enc); if (enc->enc_pic.layer_ctrl.num_temporal_layers > 1) enc->nalu_prefix(enc); - if (enc->enc_pic.is_idr) { + if (enc->enc_pic.is_idr || enc->enc_pic.need_sequence_header) { if (enc->enc_pic.layer_ctrl.num_temporal_layers > 1) enc->nalu_sei(enc); enc->nalu_sps(enc); @@ -1368,7 +1364,7 @@ static void radeon_enc_headers_h264(struct radeon_encoder *enc) static void radeon_enc_headers_hevc(struct radeon_encoder *enc) { enc->nalu_aud(enc); - if (enc->enc_pic.is_idr) { + if (enc->enc_pic.is_idr || enc->enc_pic.need_sequence_header) { enc->nalu_vps(enc); enc->nalu_pps(enc); enc->nalu_sps(enc); diff --git a/src/gallium/drivers/radeonsi/radeon_vcn_enc_4_0.c b/src/gallium/drivers/radeonsi/radeon_vcn_enc_4_0.c index 80214b2f4f9..5255922a555 100644 --- a/src/gallium/drivers/radeonsi/radeon_vcn_enc_4_0.c +++ b/src/gallium/drivers/radeonsi/radeon_vcn_enc_4_0.c @@ -863,7 +863,7 @@ static void radeon_enc_obu_instruction(struct radeon_encoder *enc) radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_COPY, 0); radeon_enc_av1_temporal_delimiter(enc); - if (enc->enc_pic.need_av1_seq) + if (enc->enc_pic.need_av1_seq || enc->enc_pic.need_sequence_header) radeon_enc_av1_sequence_header(enc); /* if others OBU types are needed such as meta data, then they need to be byte aligned and added here diff --git a/src/gallium/drivers/radeonsi/si_get.c b/src/gallium/drivers/radeonsi/si_get.c index b79a915126c..5c9d7ab1073 100644 --- a/src/gallium/drivers/radeonsi/si_get.c +++ b/src/gallium/drivers/radeonsi/si_get.c @@ -759,6 +759,16 @@ static int si_get_video_param(struct pipe_screen *screen, enum pipe_video_profil } else return 1; + case PIPE_VIDEO_CAP_ENC_INTRA_REFRESH: + if (sscreen->info.vcn_ip_version >= VCN_1_0_0) { + int value = PIPE_VIDEO_ENC_INTRA_REFRESH_ROW | + PIPE_VIDEO_ENC_INTRA_REFRESH_COLUMN | + PIPE_VIDEO_ENC_INTRA_REFRESH_P_FRAME; + return value; + } + else + return 0; + default: return 0; }