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.liu@amd.com>
Reviewed-by: Boyuan Zhang <Boyuan.Zhang@amd.com>
Signed-off-by: Ruijing Dong <ruijing.dong@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26133>
This commit is contained in:
Ruijing Dong 2023-11-09 11:58:51 -05:00 committed by Marge Bot
parent 5524faa22c
commit 7fae1c46ad
4 changed files with 83 additions and 7 deletions

View file

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

View file

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

View file

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

View file

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