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

Reply via email to