radeonsi/vcn: add av1 encoding ib packages and get_info
authorRuijing Dong <ruijing.dong@amd.com>
Wed, 19 Apr 2023 02:33:29 +0000 (22:33 -0400)
committerMarge Bot <emma+marge@anholt.net>
Thu, 27 Apr 2023 15:11:35 +0000 (15:11 +0000)
add av1 encoding ib packages and enable the
get_info functions.

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/22585>

src/gallium/drivers/radeonsi/radeon_vcn_enc.c
src/gallium/drivers/radeonsi/radeon_vcn_enc_4_0.c

index baf5c5d..ad529be 100644 (file)
@@ -482,12 +482,157 @@ static void radeon_vcn_enc_hevc_get_param(struct radeon_encoder *enc,
    radeon_vcn_enc_get_output_format_param(enc);
 }
 
+static void radeon_vcn_enc_av1_get_spec_misc_param(struct radeon_encoder *enc,
+                                                   struct pipe_av1_enc_picture_desc *pic)
+{
+   enc->enc_pic.av1_spec_misc.cdef_mode = pic->seq.seq_bits.enable_cdef;
+   enc->enc_pic.av1_spec_misc.disable_cdf_update = pic->disable_cdf_update;
+   enc->enc_pic.av1_spec_misc.disable_frame_end_update_cdf = pic->disable_frame_end_update_cdf;
+   enc->enc_pic.av1_spec_misc.num_tiles_per_picture = pic->num_tiles_in_pic;
+   enc->enc_pic.av1_spec_misc.palette_mode_enable = pic->palette_mode_enable;
+
+   if (enc->enc_pic.disable_screen_content_tools) {
+       enc->enc_pic.force_integer_mv  = 0;
+       enc->enc_pic.av1_spec_misc.palette_mode_enable = 0;
+   }
+
+   if (enc->enc_pic.force_integer_mv)
+      enc->enc_pic.av1_spec_misc.mv_precision = RENCODE_AV1_MV_PRECISION_FORCE_INTEGER_MV;
+   else
+      enc->enc_pic.av1_spec_misc.mv_precision = RENCODE_AV1_MV_PRECISION_ALLOW_HIGH_PRECISION;
+}
+
+static void radeon_vcn_enc_av1_timing_info(struct radeon_encoder *enc,
+                                           struct pipe_av1_enc_picture_desc *pic)
+{
+   if (pic->seq.seq_bits.timing_info_present_flag)
+   {
+      enc->enc_pic.av1_timing_info.num_units_in_display_tick =
+         pic->seq.num_units_in_display_tick;
+      enc->enc_pic.av1_timing_info.time_scale = pic->seq.time_scale;
+      enc->enc_pic.av1_timing_info.num_tick_per_picture_minus1 =
+         pic->seq.num_tick_per_picture_minus1;
+   }
+}
+
+static void radeon_vcn_enc_av1_color_description(struct radeon_encoder *enc,
+                                                 struct pipe_av1_enc_picture_desc *pic)
+{
+   if (pic->seq.seq_bits.color_description_present_flag)
+   {
+      enc->enc_pic.av1_color_description.color_primaries = pic->seq.color_config.color_primaries;
+      enc->enc_pic.av1_color_description.transfer_characteristics = pic->seq.color_config.transfer_characteristics;
+      enc->enc_pic.av1_color_description.maxtrix_coefficients = pic->seq.color_config.matrix_coefficients;
+      enc->enc_pic.av1_color_description.color_range = pic->seq.color_config.color_range;
+      enc->enc_pic.av1_color_description.chroma_sample_position = pic->seq.color_config.chroma_sample_position;
+   }
+}
+
+static void radeon_vcn_enc_av1_get_rc_param(struct radeon_encoder *enc,
+                                            struct pipe_av1_enc_picture_desc *pic)
+{
+   uint32_t frame_rate_den, frame_rate_num;
+
+   for (int i = 0; i < ARRAY_SIZE(enc->enc_pic.rc_layer_init); i++) {
+      enc->enc_pic.rc_layer_init[i].target_bit_rate = pic->rc[i].target_bitrate;
+      enc->enc_pic.rc_layer_init[i].peak_bit_rate = pic->rc[i].peak_bitrate;
+      frame_rate_den = pic->rc[i].frame_rate_den;
+      frame_rate_num = pic->rc[i].frame_rate_num;
+      radeon_vcn_enc_invalid_frame_rate(&frame_rate_den, &frame_rate_num);
+      enc->enc_pic.rc_layer_init[i].frame_rate_den = frame_rate_den;
+      enc->enc_pic.rc_layer_init[i].frame_rate_num = frame_rate_num;
+      enc->enc_pic.rc_layer_init[i].vbv_buffer_size = pic->rc[i].vbv_buffer_size;
+      enc->enc_pic.rc_layer_init[i].avg_target_bits_per_picture =
+          radeon_vcn_per_frame_integer(pic->rc[i].target_bitrate,
+                                       frame_rate_den,
+                                       frame_rate_num);
+      enc->enc_pic.rc_layer_init[i].peak_bits_per_picture_integer =
+          radeon_vcn_per_frame_integer(pic->rc[i].peak_bitrate,
+                                       frame_rate_den,
+                                       frame_rate_num);
+      enc->enc_pic.rc_layer_init[i].peak_bits_per_picture_fractional =
+          radeon_vcn_per_frame_frac(pic->rc[i].peak_bitrate,
+                                    frame_rate_den,
+                                    frame_rate_num);
+   }
+   enc->enc_pic.rc_session_init.vbv_buffer_level = pic->rc[0].vbv_buf_lv;
+   enc->enc_pic.rc_per_pic.qp = pic->rc[0].qp;
+   enc->enc_pic.rc_per_pic.min_qp_app = pic->rc[0].min_qp ? pic->rc[0].min_qp : 1;
+   enc->enc_pic.rc_per_pic.max_qp_app = pic->rc[0].max_qp ? pic->rc[0].max_qp : 255;
+   enc->enc_pic.rc_per_pic.enabled_filler_data = pic->rc[0].fill_data_enable;
+   enc->enc_pic.rc_per_pic.skip_frame_enable = pic->rc[0].skip_frame_enable;
+   enc->enc_pic.rc_per_pic.enforce_hrd = pic->rc[0].enforce_hrd;
+   switch (pic->rc[0].rate_ctrl_method) {
+      case PIPE_H2645_ENC_RATE_CONTROL_METHOD_DISABLE:
+         enc->enc_pic.rc_session_init.rate_control_method = RENCODE_RATE_CONTROL_METHOD_NONE;
+         break;
+      case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP:
+      case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT:
+         enc->enc_pic.rc_session_init.rate_control_method = RENCODE_RATE_CONTROL_METHOD_CBR;
+         break;
+      case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP:
+      case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE:
+         enc->enc_pic.rc_session_init.rate_control_method =
+            RENCODE_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR;
+         break;
+      default:
+         enc->enc_pic.rc_session_init.rate_control_method = RENCODE_RATE_CONTROL_METHOD_NONE;
+   }
+   enc->enc_pic.rc_per_pic.max_au_size = pic->rc[0].max_au_size;
+}
+
+static void radeon_vcn_enc_av1_get_param(struct radeon_encoder *enc,
+                                         struct pipe_av1_enc_picture_desc *pic)
+{
+   struct radeon_enc_pic *enc_pic = &enc->enc_pic;
+   enc_pic->frame_type = pic->frame_type;
+   enc_pic->frame_num = pic->frame_num;
+   enc_pic->bit_depth_luma_minus8 = enc_pic->bit_depth_chroma_minus8 =
+      pic->seq.bit_depth_minus8;
+   enc_pic->pic_width_in_luma_samples = pic->seq.pic_width_in_luma_samples;
+   enc_pic->pic_height_in_luma_samples = pic->seq.pic_height_in_luma_samples;
+   enc_pic->general_profile_idc = pic->seq.profile;
+   enc_pic->general_level_idc = pic->seq.level;
+   enc_pic->general_tier_flag = pic->seq.tier;
+
+   enc_pic->num_temporal_layers =
+            pic->seq.num_temporal_layers <= RENCODE_MAX_NUM_TEMPORAL_LAYERS ?
+            pic->seq.num_temporal_layers : RENCODE_MAX_NUM_TEMPORAL_LAYERS;
+
+   /* 1, 2 layer needs 1 reference, and 3, 4 layer needs 2 references */
+   enc->base.max_references = (enc_pic->num_temporal_layers + 1) / 2;
+   radeon_vcn_enc_quality_modes(enc, &pic->quality_modes);
+   enc_pic->frame_id_numbers_present = pic->seq.seq_bits.frame_id_number_present_flag;
+   enc_pic->enable_error_resilient_mode = pic->error_resilient_mode;
+   enc_pic->force_integer_mv = pic->force_integer_mv;
+   enc_pic->enable_order_hint = pic->seq.seq_bits.enable_order_hint;
+   enc_pic->order_hint_bits = pic->seq.order_hint_bits;
+   enc_pic->enable_render_size = pic->enable_render_size;
+   enc_pic->render_width = pic->render_width;
+   enc_pic->render_height = pic->render_height;
+   enc_pic->enable_color_description = pic->seq.seq_bits.color_description_present_flag;
+   enc_pic->timing_info_present = pic->seq.seq_bits.timing_info_present_flag;
+   enc_pic->timing_info_equal_picture_interval = pic->seq.seq_bits.equal_picture_interval;
+   enc_pic->disable_screen_content_tools = !pic->allow_screen_content_tools;
+   enc_pic->is_obu_frame = pic->enable_frame_obu;
+   enc_pic->need_av1_seq = (pic->frame_type == PIPE_AV1_ENC_FRAME_TYPE_KEY);
+
+   radeon_vcn_enc_av1_get_spec_misc_param(enc, pic);
+   radeon_vcn_enc_av1_timing_info(enc, pic);
+   radeon_vcn_enc_av1_color_description(enc, pic);
+   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);
+}
+
 static void radeon_vcn_enc_get_param(struct radeon_encoder *enc, struct pipe_picture_desc *picture)
 {
    if (u_reduce_video_profile(picture->profile) == PIPE_VIDEO_FORMAT_MPEG4_AVC)
       radeon_vcn_enc_h264_get_param(enc, (struct pipe_h264_enc_picture_desc *)picture);
    else if (u_reduce_video_profile(picture->profile) == PIPE_VIDEO_FORMAT_HEVC)
       radeon_vcn_enc_hevc_get_param(enc, (struct pipe_h265_enc_picture_desc *)picture);
+   else if (u_reduce_video_profile(picture->profile) == PIPE_VIDEO_FORMAT_AV1)
+      radeon_vcn_enc_av1_get_param(enc, (struct pipe_av1_enc_picture_desc *)picture);
 }
 
 static void flush(struct radeon_encoder *enc)
@@ -532,6 +677,35 @@ static void radeon_enc_rec_offset(rvcn_enc_reconstructed_picture_t *recon,
    }
 }
 
+static int setup_cdf(struct radeon_encoder *enc)
+{
+   unsigned char *p_cdf = NULL;
+
+   if (!enc->cdf ||
+         !si_vid_create_buffer(enc->screen,
+                               enc->cdf,
+                               VCN_ENC_AV1_DEFAULT_CDF_SIZE,
+                               PIPE_USAGE_DYNAMIC)) {
+      RVID_ERR("Can't create CDF buffer.\n");
+      goto error;
+   }
+
+   p_cdf = enc->ws->buffer_map(enc->ws,
+                               enc->cdf->res->buf,
+                              &enc->cs,
+                               PIPE_MAP_READ_WRITE | RADEON_MAP_TEMPORARY);
+   if (!p_cdf)
+      goto error;
+
+   memcpy(p_cdf, rvcn_av1_cdf_default_table, VCN_ENC_AV1_DEFAULT_CDF_SIZE);
+   enc->ws->buffer_unmap(enc->ws, enc->cdf->res->buf);
+
+   return 0;
+
+error:
+   return -1;
+}
+
 static int setup_dpb(struct radeon_encoder *enc)
 {
    bool is_h264 = u_reduce_video_profile(enc->base.profile)
@@ -635,6 +809,20 @@ static void radeon_enc_begin_frame(struct pipe_video_codec *encoder,
    } 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->enc_pic.rc_layer_init[0].target_bit_rate != pic->rc.target_bitrate;
+   } 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->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);
+
+      if (!enc->cdf) {
+         enc->cdf = CALLOC_STRUCT(rvid_buffer);
+         if (setup_cdf(enc)) {
+            RVID_ERR("Can't create cdf buffer.\n");
+            goto error;
+         }
+      }
    }
 
    radeon_vcn_enc_get_param(enc, picture);
@@ -677,6 +865,7 @@ static void radeon_enc_begin_frame(struct pipe_video_codec *encoder,
 error:
    RADEON_ENC_DESTROY_VIDEO_BUFFER(enc->dpb);
    RADEON_ENC_DESTROY_VIDEO_BUFFER(enc->si);
+   RADEON_ENC_DESTROY_VIDEO_BUFFER(enc->cdf);
 }
 
 static void radeon_enc_encode_bitstream(struct pipe_video_codec *encoder,
@@ -734,6 +923,7 @@ static void radeon_enc_destroy(struct pipe_video_codec *encoder)
    }
 
    RADEON_ENC_DESTROY_VIDEO_BUFFER(enc->dpb);
+   RADEON_ENC_DESTROY_VIDEO_BUFFER(enc->cdf);
    enc->ws->cs_destroy(&enc->cs);
    if (enc->ectx)
       enc->ectx->destroy(enc->ectx);
index 21ea5b7..ab912c9 100644 (file)
 #define RENCODE_FW_INTERFACE_MAJOR_VERSION   1
 #define RENCODE_FW_INTERFACE_MINOR_VERSION   0
 
+#define RENCODE_IB_PARAM_CDF_DEFAULT_TABLE_BUFFER  0x00000019
 #define RENCODE_IB_PARAM_ENCODE_STATISTICS         0x0000001a
 
+#define RENCODE_AV1_IB_PARAM_SPEC_MISC             0x00300001
+#define RENCODE_AV1_IB_PARAM_BITSTREAM_INSTRUCTION 0x00300002
+
+#define RENCODE_AV1_BITSTREAM_INSTRUCTION_END   RENCODE_HEADER_INSTRUCTION_END
+#define RENCODE_AV1_BITSTREAM_INSTRUCTION_COPY  RENCODE_HEADER_INSTRUCTION_COPY
+#define RENCODE_AV1_BITSTREAM_INSTRUCTION_ALLOW_HIGH_PRECISION_MV                   0x00000005
+#define RENCODE_AV1_BITSTREAM_INSTRUCTION_DELTA_LF_PARAMS                           0x00000006
+#define RENCODE_AV1_BITSTREAM_INSTRUCTION_READ_INTERPOLATION_FILTER                 0x00000007
+#define RENCODE_AV1_BITSTREAM_INSTRUCTION_LOOP_FILTER_PARAMS                        0x00000008
+#define RENCODE_AV1_BITSTREAM_INSTRUCTION_TILE_INFO                                 0x00000009
+#define RENCODE_AV1_BITSTREAM_INSTRUCTION_QUANTIZATION_PARAMS                       0x0000000a
+#define RENCODE_AV1_BITSTREAM_INSTRUCTION_DELTA_Q_PARAMS                            0x0000000b
+#define RENCODE_AV1_BITSTREAM_INSTRUCTION_CDEF_PARAMS                               0x0000000c
+#define RENCODE_AV1_BITSTREAM_INSTRUCTION_READ_TX_MODE                              0x0000000d
+#define RENCODE_AV1_BITSTREAM_INSTRUCTION_TILE_GROUP_OBU                            0x0000000e
+
 static void radeon_enc_sq_begin(struct radeon_encoder *enc)
 {
    rvcn_sq_header(&enc->cs, &enc->sq, true);
@@ -60,6 +77,866 @@ static void radeon_enc_sq_destroy(struct radeon_encoder *enc)
    rvcn_sq_tail(&enc->cs, &enc->sq);
 }
 
+static void radeon_enc_session_init(struct radeon_encoder *enc)
+{
+   bool av1_encoding = false;
+   uint32_t av1_height = enc->enc_pic.pic_height_in_luma_samples;
+
+   switch (u_reduce_video_profile(enc->base.profile)) {
+      case PIPE_VIDEO_FORMAT_MPEG4_AVC:
+         enc->enc_pic.session_init.encode_standard = RENCODE_ENCODE_STANDARD_H264;
+         enc->enc_pic.session_init.aligned_picture_width = align(enc->base.width, 16);
+         enc->enc_pic.session_init.aligned_picture_height = align(enc->base.height, 16);
+         break;
+      case PIPE_VIDEO_FORMAT_HEVC:
+         enc->enc_pic.session_init.encode_standard = RENCODE_ENCODE_STANDARD_HEVC;
+         enc->enc_pic.session_init.aligned_picture_width = align(enc->base.width, 64);
+         enc->enc_pic.session_init.aligned_picture_height = align(enc->base.height, 16);
+         break;
+      case PIPE_VIDEO_FORMAT_AV1:
+         enc->enc_pic.session_init.encode_standard = RENCODE_ENCODE_STANDARD_AV1;
+         enc->enc_pic.session_init.aligned_picture_width =
+                              align(enc->enc_pic.pic_width_in_luma_samples, 64);
+         enc->enc_pic.session_init.aligned_picture_height =
+                                 align(enc->enc_pic.pic_height_in_luma_samples, 16);
+         if (!(av1_height % 8) && (av1_height % 16) && !(enc->enc_pic.enable_render_size))
+            enc->enc_pic.session_init.aligned_picture_height = av1_height + 2;
+
+         av1_encoding = true;
+         break;
+      default:
+         assert(0);
+         break;
+   }
+
+   enc->enc_pic.session_init.padding_width =
+      enc->enc_pic.session_init.aligned_picture_width - enc->base.width;
+   enc->enc_pic.session_init.padding_height =
+      enc->enc_pic.session_init.aligned_picture_height - enc->base.height;
+
+   if (av1_encoding) {
+      enc->enc_pic.session_init.padding_width =
+         enc->enc_pic.session_init.aligned_picture_width -
+         enc->enc_pic.pic_width_in_luma_samples;
+      enc->enc_pic.session_init.padding_height =
+         enc->enc_pic.session_init.aligned_picture_height - av1_height;
+
+      if (enc->enc_pic.enable_render_size)
+         enc->enc_pic.enable_render_size =
+                        (enc->enc_pic.session_init.aligned_picture_width !=
+                         enc->enc_pic.render_width) ||
+                        (enc->enc_pic.session_init.aligned_picture_height !=
+                         enc->enc_pic.render_height);
+   }
+
+   enc->enc_pic.session_init.slice_output_enabled = 0;
+   enc->enc_pic.session_init.display_remote = 0;
+   enc->enc_pic.session_init.pre_encode_mode = enc->enc_pic.quality_modes.pre_encode_mode;
+   enc->enc_pic.session_init.pre_encode_chroma_enabled = !!(enc->enc_pic.quality_modes.pre_encode_mode);
+
+   RADEON_ENC_BEGIN(enc->cmd.session_init);
+   RADEON_ENC_CS(enc->enc_pic.session_init.encode_standard);
+   RADEON_ENC_CS(enc->enc_pic.session_init.aligned_picture_width);
+   RADEON_ENC_CS(enc->enc_pic.session_init.aligned_picture_height);
+   RADEON_ENC_CS(enc->enc_pic.session_init.padding_width);
+   RADEON_ENC_CS(enc->enc_pic.session_init.padding_height);
+   RADEON_ENC_CS(enc->enc_pic.session_init.pre_encode_mode);
+   RADEON_ENC_CS(enc->enc_pic.session_init.pre_encode_chroma_enabled);
+   RADEON_ENC_CS(enc->enc_pic.session_init.slice_output_enabled);
+   RADEON_ENC_CS(enc->enc_pic.session_init.display_remote);
+   RADEON_ENC_END();
+}
+
+/* for new temporal_id, sequence_num has to be incremented ahead. */
+static uint32_t radeon_enc_av1_calculate_temporal_id(uint32_t sequence_num,
+                                                     uint32_t max_layer)
+{
+   for (uint32_t i = 0; i <= max_layer; i++)
+      if (!(sequence_num % (1 << (max_layer - i))))
+         return i;
+
+   /* never come here */
+   assert(0);
+   return 0;
+}
+
+static uint32_t radeon_enc_av1_alloc_recon_slot(struct radeon_encoder *enc)
+{
+   uint32_t i;
+   for (i = 0; i < ARRAY_SIZE(enc->enc_pic.recon_slots); i++) {
+      if(!enc->enc_pic.recon_slots[i].in_use) {
+         enc->enc_pic.recon_slots[i].in_use = true;
+         break;
+      }
+   }
+   return i;
+}
+
+static void redeon_enc_av1_release_recon_slot(struct radeon_encoder *enc,
+                                              uint32_t index,
+                                              bool is_orphaned)
+{
+   assert(index < (ARRAY_SIZE(enc->enc_pic.recon_slots) - 1));
+   assert(enc->enc_pic.recon_slots[index].in_use);
+
+   if (is_orphaned)
+      enc->enc_pic.recon_slots[index].is_orphaned = true;
+   else
+      enc->enc_pic.recon_slots[index].in_use = false;
+}
+
+static uint32_t radeon_enc_av1_alloc_curr_frame(struct radeon_encoder *enc,
+                                 uint32_t frame_id,
+                                 uint32_t temporal_id,
+                                 enum pipe_av1_enc_frame_type frame_type)
+{
+   uint32_t i = 0;
+
+   for (i = 0; i < ARRAY_SIZE(enc->enc_pic.frames); i++) {
+      rvcn_enc_av1_ref_frame_t *frame = &enc->enc_pic.frames[i];
+      if (!frame->in_use) {
+         frame->in_use = true;
+         frame->frame_id = frame_id;
+         frame->temporal_id = temporal_id;
+         frame->slot_id = radeon_enc_av1_alloc_recon_slot(enc);
+         frame->frame_type = frame_type;
+         break;
+      }
+   }
+
+   return i;
+}
+
+static void radeon_enc_av1_release_ref_frame(struct radeon_encoder *enc,
+                                             uint32_t index,
+                                             bool is_recon_orphan)
+{
+   assert(index < (ARRAY_SIZE(enc->enc_pic.frames) - 1));
+
+   redeon_enc_av1_release_recon_slot(enc,
+                                     enc->enc_pic.frames[index].slot_id,
+                                     is_recon_orphan);
+   enc->enc_pic.frames[index].in_use = false;
+}
+
+/* save 1 recon slot in max temporal layer = 4 case */
+static void radeon_enc_av1_temporal_4_extra_release(struct radeon_encoder *enc,
+                                                    uint32_t temporal_id)
+{
+   uint32_t i = 0;
+
+   if (temporal_id == 0)
+      enc->enc_pic.count_last_layer = 0;
+   else if (temporal_id == 3)
+      enc->enc_pic.count_last_layer++;
+
+   /* since temporal ID = 1 picture will not be used in this
+    * temporal period, that can be released */
+   if (enc->enc_pic.count_last_layer == 4) {
+      for (i = 0; i < ARRAY_SIZE(enc->enc_pic.frames); i++) {
+         rvcn_enc_av1_ref_frame_t *frame = &enc->enc_pic.frames[i];
+         if (frame->in_use && (frame->temporal_id == 1)) {
+            radeon_enc_av1_release_ref_frame(enc, i, false);
+            break;
+         }
+      }
+   }
+}
+
+static void radeon_enc_av1_pre_scan_frames(struct radeon_encoder *enc,
+                                           uint32_t temporal_id)
+{
+   uint32_t i = 0;
+
+   for (i = 0; i < ARRAY_SIZE(enc->enc_pic.recon_slots); i++) {
+      rvcn_enc_av1_recon_slot_t *slot = &enc->enc_pic.recon_slots[i];
+      if (slot->in_use && slot->is_orphaned) {
+         slot->in_use = false;
+         slot->is_orphaned = false;
+      }
+   }
+
+   for (i = 0; i < ARRAY_SIZE(enc->enc_pic.frames); i++) {
+      rvcn_enc_av1_ref_frame_t *frame = &enc->enc_pic.frames[i];
+      if (frame->in_use) {
+         if (temporal_id < frame->temporal_id)
+            radeon_enc_av1_release_ref_frame(enc, i, false);
+         else if (temporal_id == frame->temporal_id)
+            radeon_enc_av1_release_ref_frame(enc, i, true);
+      }
+   }
+}
+
+static uint32_t radeon_enc_av1_obtain_ref0_frame(struct radeon_encoder *enc,
+                                          uint32_t temporal_id)
+{
+   uint32_t i = 0;
+   for (i = ARRAY_SIZE(enc->enc_pic.frames); i > 0; i--) {
+      rvcn_enc_av1_ref_frame_t *frame = &enc->enc_pic.frames[i - 1];
+      if (frame->in_use && frame->temporal_id <= temporal_id)
+         break;
+   }
+   /* not find, ref = 0, or ref = i - 1 */
+   return i == 0 ? i : i - 1;
+}
+
+static void radeon_enc_reset_av1_dpb_frames(struct radeon_encoder *enc)
+{
+   for (int i = 0; i < ARRAY_SIZE(enc->enc_pic.frames); i++) {
+      enc->enc_pic.frames[i].in_use = false;
+      enc->enc_pic.frames[i].frame_id = 0;
+      enc->enc_pic.frames[i].temporal_id = 0;
+      enc->enc_pic.frames[i].slot_id = 0;
+      enc->enc_pic.frames[i].frame_type = 0;
+   }
+
+   for (int i = 0; i < ARRAY_SIZE(enc->enc_pic.recon_slots); i++) {
+      enc->enc_pic.recon_slots[i].in_use = false;
+      enc->enc_pic.recon_slots[i].is_orphaned = false;
+   }
+}
+
+static void radeon_enc_av1_dpb_management(struct radeon_encoder *enc)
+{
+   struct radeon_enc_pic *pic = &enc->enc_pic;
+   uint32_t current_slot;
+   uint32_t ref_slot;
+
+   if (pic->frame_type == PIPE_AV1_ENC_FRAME_TYPE_KEY) {
+      pic->frame_id = 0;
+      pic->temporal_id = 0;
+      pic->reference_delta_frame_id = 0;
+      pic->reference_frame_index = 0;
+      pic->last_frame_type = PIPE_AV1_ENC_FRAME_TYPE_KEY;
+      current_slot = 0;
+      ref_slot = 0;
+      radeon_enc_reset_av1_dpb_frames(enc);
+   } else {
+      pic->temporal_id = radeon_enc_av1_calculate_temporal_id(pic->frame_id,
+                                                              pic->num_temporal_layers - 1);
+      pic->reference_frame_index =
+         radeon_enc_av1_obtain_ref0_frame(enc, pic->temporal_id);
+      ref_slot = pic->frames[pic->reference_frame_index].slot_id;
+      pic->last_frame_type = pic->frames[pic->reference_frame_index].frame_type;
+      radeon_enc_av1_pre_scan_frames(enc, pic->temporal_id);
+   }
+
+   if (pic->num_temporal_layers == 4)
+      radeon_enc_av1_temporal_4_extra_release(enc, pic->temporal_id);
+
+   pic->frame_to_show_map_index = pic->reference_frame_index;
+
+   for (int i = 0; i < ARRAY_SIZE(pic->frames); i++)
+      pic->reference_order_hint[i] = pic->frames[i].frame_id;
+
+   pic->reference_delta_frame_id = pic->frame_id -
+                                   pic->frames[pic->reference_frame_index].frame_id;
+   current_slot = radeon_enc_av1_alloc_curr_frame(enc, pic->frame_id,
+                                                       pic->temporal_id,
+                                                       pic->frame_type);
+   if (pic->frame_type == PIPE_AV1_ENC_FRAME_TYPE_KEY ||
+       pic->frame_type == PIPE_AV1_ENC_FRAME_TYPE_SWITCH ||
+       ((pic->frame_type == PIPE_AV1_ENC_FRAME_TYPE_SHOW_EXISTING) &&
+         pic->last_frame_type == PIPE_AV1_ENC_FRAME_TYPE_KEY))
+      pic->refresh_frame_flags = 255;
+   else
+      pic->refresh_frame_flags = 1 << current_slot;
+
+   pic->enc_params.reference_picture_index = ref_slot;
+   pic->enc_params.reconstructed_picture_index = pic->frames[current_slot].slot_id;
+   pic->display_frame_id = pic->frame_id;
+   pic->order_hint = pic->frame_id;
+}
+
+static void radeon_enc_spec_misc_av1(struct radeon_encoder *enc)
+{
+   uint32_t num_of_tiles = enc->enc_pic.av1_spec_misc.num_tiles_per_picture;
+   uint32_t threshold_low, threshold_high;
+   uint32_t num_rows;
+   uint32_t num_columns;
+
+   num_rows = PIPE_ALIGN_IN_BLOCK_SIZE(enc->enc_pic.session_init.aligned_picture_height,
+                                       PIPE_AV1_ENC_SB_SIZE);
+   num_columns = PIPE_ALIGN_IN_BLOCK_SIZE(enc->enc_pic.session_init.aligned_picture_width,
+                                       PIPE_AV1_ENC_SB_SIZE);
+
+   if (num_rows > 64) {
+      /* max tile size 4096 x 2304 */
+      threshold_low = ((num_rows + 63) / 64) * ((num_columns + 35) / 36);
+      num_of_tiles = (num_of_tiles & 1) ? num_of_tiles - 1 : num_of_tiles;
+   } else
+      threshold_low = 1;
+
+   threshold_high = num_rows > 16 ? 16 : num_rows;
+   threshold_high = num_columns > 64 ? threshold_high * 2 : threshold_high;
+
+   num_of_tiles = CLAMP(num_of_tiles, threshold_low, threshold_high);
+
+   /* in case of multiple tiles, it should be an obu frame */
+   if (num_of_tiles > 1)
+      enc->enc_pic.stream_obu_frame = 1;
+   else
+      enc->enc_pic.stream_obu_frame = enc->enc_pic.is_obu_frame;
+
+   enc->enc_pic.av1_spec_misc.num_tiles_per_picture = num_of_tiles;
+
+   RADEON_ENC_BEGIN(enc->cmd.spec_misc_av1);
+   RADEON_ENC_CS(enc->enc_pic.av1_spec_misc.palette_mode_enable);
+   RADEON_ENC_CS(enc->enc_pic.av1_spec_misc.mv_precision);
+   RADEON_ENC_CS(enc->enc_pic.av1_spec_misc.cdef_mode);
+   RADEON_ENC_CS(enc->enc_pic.av1_spec_misc.disable_cdf_update);
+   RADEON_ENC_CS(enc->enc_pic.av1_spec_misc.disable_frame_end_update_cdf);
+   RADEON_ENC_CS(enc->enc_pic.av1_spec_misc.num_tiles_per_picture);
+   RADEON_ENC_END();
+}
+
+static void radeon_enc_cdf_default_table(struct radeon_encoder *enc)
+{
+   bool use_cdf_default = enc->enc_pic.frame_type == PIPE_AV1_ENC_FRAME_TYPE_KEY ||
+                          enc->enc_pic.frame_type == PIPE_AV1_ENC_FRAME_TYPE_INTRA_ONLY ||
+                          enc->enc_pic.frame_type == PIPE_AV1_ENC_FRAME_TYPE_SWITCH;
+
+   enc->enc_pic.av1_cdf_default_table.use_cdf_default = use_cdf_default ? 1 : 0;
+
+   RADEON_ENC_BEGIN(enc->cmd.cdf_default_table_av1);
+   RADEON_ENC_CS(enc->enc_pic.av1_cdf_default_table.use_cdf_default);
+   RADEON_ENC_READWRITE(enc->cdf->res->buf, enc->cdf->res->domains, 0);
+   RADEON_ENC_ADDR_SWAP();
+   RADEON_ENC_END();
+}
+
+uint8_t *radeon_enc_av1_header_size_offset(struct radeon_encoder *enc)
+{
+   uint32_t *bits_start = enc->enc_pic.copy_start + 3;
+   assert(enc->bits_output % 8 == 0); /* should be always byte aligned */
+   return (uint8_t *)(bits_start) + (enc->bits_output >> 3);
+}
+
+static void radeon_enc_av1_temporal_delimiter(struct radeon_encoder *enc)
+{
+   bool use_extension_flag;
+
+   /* obu header () */
+   /* obu_forbidden_bit */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   /* obu_type */
+   radeon_enc_code_fixed_bits(enc, RENCODE_OBU_TYPE_TEMPORAL_DELIMITER, 4);
+   /* obu_extension_flag */
+   use_extension_flag = (enc->enc_pic.num_temporal_layers) > 1 &&
+                        (enc->enc_pic.temporal_id) > 0 ? 1 : 0;
+   radeon_enc_code_fixed_bits(enc, use_extension_flag ? 1 : 0, 1);
+   /* obu_has_size_field */
+   radeon_enc_code_fixed_bits(enc, 1, 1);
+   /* obu_reserved_1bit */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+
+   if (use_extension_flag) {
+      radeon_enc_code_fixed_bits(enc, enc->enc_pic.temporal_id, 3);
+      radeon_enc_code_fixed_bits(enc, 0, 2);  /* spatial_id should always be zero */
+      radeon_enc_code_fixed_bits(enc, 0, 3);  /* reserved 3 bits */
+   }
+
+   radeon_enc_code_fixed_bits(enc, 0, 8); /* obu has size */
+}
+
+static void radeon_enc_av1_sequence_header(struct radeon_encoder *enc)
+{
+   uint8_t *size_offset;
+   uint8_t obu_size_bin[2];
+   uint32_t obu_size;
+   uint32_t width_bits;
+   uint32_t height_bits;
+   uint32_t max_temporal_layers = enc->enc_pic.num_temporal_layers;
+
+   /*  obu_header() */
+   /* obu_forbidden_bit */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   /*  obu_type */
+   radeon_enc_code_fixed_bits(enc, RENCODE_OBU_TYPE_SEQUENCE_HEADER, 4);
+   /*  obu_extension_flag */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   /*  obu_has_size_field */
+   radeon_enc_code_fixed_bits(enc, 1, 1);
+   /*  obu_reserved_1bit */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+
+   /* obu_size, use two bytes for header, the size will be written in afterwards */
+   size_offset = radeon_enc_av1_header_size_offset(enc);
+   radeon_enc_code_fixed_bits(enc, 0, 2 * 8);
+
+   /* sequence_header_obu() */
+   /*  seq_profile, only seq_profile = 0 is supported  */
+   radeon_enc_code_fixed_bits(enc, 0, 3);
+   /*  still_picture */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   /*  reduced_still_picture_header */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   /*  timing_info_present_flag  */
+   radeon_enc_code_fixed_bits(enc, enc->enc_pic.timing_info_present ? 1 : 0, 1);
+
+   if (enc->enc_pic.timing_info_present) {
+      /*  num_units_in_display_tick  */
+      radeon_enc_code_fixed_bits(enc, enc->enc_pic.av1_timing_info.num_units_in_display_tick, 32);
+      /*  time_scale  */
+      radeon_enc_code_fixed_bits(enc, enc->enc_pic.av1_timing_info.time_scale, 32);
+      /*  equal_picture_interval  */
+      radeon_enc_code_fixed_bits(enc, enc->enc_pic.timing_info_equal_picture_interval, 1);
+      /*  num_ticks_per_picture_minus_1  */
+       if (enc->enc_pic.timing_info_equal_picture_interval)
+           radeon_enc_code_uvlc(enc, enc->enc_pic.av1_timing_info.num_tick_per_picture_minus1);
+       /*  decoder_model_info_present_flag  */
+       radeon_enc_code_fixed_bits(enc, 0, 1);
+   }
+
+   /*  initial_display_delay_present_flag  */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   /*  operating_points_cnt_minus_1  */
+   radeon_enc_code_fixed_bits(enc, max_temporal_layers - 1, 5);
+
+   for (uint32_t i = 0; i < max_temporal_layers; i++) {
+      uint32_t operating_point_idc = 0;
+      if (max_temporal_layers > 1) {
+         operating_point_idc = (1 << (max_temporal_layers - i)) - 1;
+         operating_point_idc |= 0x100;  /* spatial layer not supported */
+      }
+      radeon_enc_code_fixed_bits(enc, operating_point_idc, 12);
+      radeon_enc_code_fixed_bits(enc, enc->enc_pic.general_level_idc, 5);
+      if (enc->enc_pic.general_level_idc > 7)
+         radeon_enc_code_fixed_bits(enc, 0, 1);  /* tier */
+   }
+
+   /*  frame_width_bits_minus_1  */
+   width_bits = radeon_enc_value_bits(enc->enc_pic.session_init.aligned_picture_width - 1);
+   radeon_enc_code_fixed_bits(enc, width_bits - 1, 4);
+   /*  frame_height_bits_minus_1  */
+   height_bits = radeon_enc_value_bits(enc->enc_pic.session_init.aligned_picture_height - 1);
+   radeon_enc_code_fixed_bits(enc, height_bits - 1, 4);
+   /*  max_frame_width_minus_1  */
+   radeon_enc_code_fixed_bits(enc, enc->enc_pic.session_init.aligned_picture_width - 1,
+                                   width_bits);
+   /*  max_frame_height_minus_1  */
+   radeon_enc_code_fixed_bits(enc, enc->enc_pic.session_init.aligned_picture_height - 1,
+                                   height_bits);
+
+   /*  frame_id_numbers_present_flag  */
+   radeon_enc_code_fixed_bits(enc, enc->enc_pic.frame_id_numbers_present, 1);
+   if (enc->enc_pic.frame_id_numbers_present) {
+      /*  delta_frame_id_length_minus_2  */
+      radeon_enc_code_fixed_bits(enc, RENCODE_AV1_DELTA_FRAME_ID_LENGTH - 2, 4);
+      /*  additional_frame_id_length_minus_1  */
+      radeon_enc_code_fixed_bits(enc, RENCODE_AV1_ADDITIONAL_FRAME_ID_LENGTH - 1, 3);
+   }
+
+   /*  use_128x128_superblock  */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   /*  enable_filter_intra  */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   /*  enable_intra_edge_filter  */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   /*  enable_interintra_compound  */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   /*  enable_masked_compound  */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   /*  enable_warped_motion  */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   /*  enable_dual_filter  */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   /*  enable_order_hint  */
+   radeon_enc_code_fixed_bits(enc, enc->enc_pic.enable_order_hint ? 1 : 0, 1);
+
+   if (enc->enc_pic.enable_order_hint) {
+      /*  enable_jnt_comp  */
+      radeon_enc_code_fixed_bits(enc, 0, 1);
+      /*  enable_ref_frame_mvs  */
+      radeon_enc_code_fixed_bits(enc, 0, 1);
+   }
+
+   /*  seq_choose_screen_content_tools  */
+   radeon_enc_code_fixed_bits(enc, enc->enc_pic.disable_screen_content_tools ? 0 : 1, 1);
+   if (enc->enc_pic.disable_screen_content_tools)
+      /*  seq_force_screen_content_tools  */
+      radeon_enc_code_fixed_bits(enc, 0, 1);
+   else
+      /*  seq_choose_integer_mv  */
+      radeon_enc_code_fixed_bits(enc, 1, 1);
+
+   if(enc->enc_pic.enable_order_hint)
+      /*  order_hint_bits_minus_1  */
+      radeon_enc_code_fixed_bits(enc, enc->enc_pic.order_hint_bits - 1, 3);
+
+   /*  enable_superres  */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   /*  enable_cdef  */
+   radeon_enc_code_fixed_bits(enc, enc->enc_pic.av1_spec_misc.cdef_mode ? 1 : 0, 1);
+   /*  enable_restoration  */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   /*  high_bitdepth  */
+   radeon_enc_code_fixed_bits(enc, enc->enc_pic.enc_output_format.output_color_bit_depth, 1);
+   /*  mono_chrome  */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   /*  color_description_present_flag  */
+   radeon_enc_code_fixed_bits(enc, enc->enc_pic.enable_color_description ? 1 : 0, 1);
+
+   if(enc->enc_pic.enable_color_description) {
+      /*  color_primaries  */
+      radeon_enc_code_fixed_bits(enc, enc->enc_pic.av1_color_description.color_primaries, 8);
+      /*  transfer_characteristics  */
+      radeon_enc_code_fixed_bits(enc, enc->enc_pic.av1_color_description.transfer_characteristics, 8);
+      /*  matrix_coefficients  */
+      radeon_enc_code_fixed_bits(enc, enc->enc_pic.av1_color_description.maxtrix_coefficients, 8);
+   }
+   /*  color_range  */
+   radeon_enc_code_fixed_bits(enc, enc->enc_pic.av1_color_description.color_range, 1);
+   /*  chroma_sample_position  */
+   radeon_enc_code_fixed_bits(enc, enc->enc_pic.av1_color_description.chroma_sample_position, 2);
+   /*  separate_uv_delta_q  */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   /*  film_grain_params_present  */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+
+   /*  trailing_one_bit  */
+   radeon_enc_code_fixed_bits(enc, 1, 1);
+   radeon_enc_byte_align(enc);
+
+   /* obu_size doesn't include the bytes within obu_header
+    * or obu_size syntax element (6.2.1), here we use 2 bytes for obu_size syntax
+    * which needs to be removed from the size.
+    */
+   obu_size = (uint32_t)(radeon_enc_av1_header_size_offset(enc) - size_offset - 2);
+   radeon_enc_code_leb128(obu_size_bin, obu_size, 2);
+
+   /* update obu_size */
+   for (int i = 0; i < sizeof(obu_size_bin); i++) {
+      uint8_t *p = (uint8_t *)((((uintptr_t)size_offset & 3) ^ 3) | ((uintptr_t)size_offset & ~3));
+      *p = obu_size_bin[i];
+      size_offset++;
+   }
+}
+
+static void radeon_enc_av1_frame_header(struct radeon_encoder *enc, bool frame_header)
+{
+   uint32_t i;
+   uint32_t extension_flag = enc->enc_pic.num_temporal_layers > 1 ? 1 : 0;
+   bool show_existing = false;
+   bool frame_is_intra = enc->enc_pic.frame_type == PIPE_AV1_ENC_FRAME_TYPE_KEY ||
+                         enc->enc_pic.frame_type == PIPE_AV1_ENC_FRAME_TYPE_INTRA_ONLY;
+
+   radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_COPY, 0);
+   /*  obu_header() */
+   /*  obu_forbidden_bit  */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   /*  obu_type  */
+   radeon_enc_code_fixed_bits(enc, frame_header ? RENCODE_OBU_TYPE_FRAME_HEADER
+                                                : RENCODE_OBU_TYPE_FRAME, 4);
+   /*  obu_extension_flag  */
+   radeon_enc_code_fixed_bits(enc, extension_flag, 1);
+   /*  obu_has_size_field  */
+   radeon_enc_code_fixed_bits(enc, 1, 1);
+   /*  obu_reserved_1bit  */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   if (extension_flag) {
+      radeon_enc_code_fixed_bits(enc, enc->enc_pic.temporal_id, 3);
+      radeon_enc_code_fixed_bits(enc, 0, 2);
+      radeon_enc_code_fixed_bits(enc, 0, 3);
+   }
+
+   radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_OBU_SIZE, 0);
+
+   /*  uncompressed_header() */
+   radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_COPY, 0);
+   /*  show_existing_frame  */
+   show_existing = enc->enc_pic.frame_type == PIPE_AV1_ENC_FRAME_TYPE_SHOW_EXISTING;
+   radeon_enc_code_fixed_bits(enc, show_existing ? 1 : 0, 1);
+   /*  if (show_existing_frame == 1) */
+   if(show_existing) {
+      /*  frame_to_show_map_idx  */
+      radeon_enc_code_fixed_bits(enc, enc->enc_pic.frame_to_show_map_index, 3);
+      /*  display_frame_id  */
+      if (enc->enc_pic.frame_id_numbers_present)
+         radeon_enc_code_fixed_bits(enc, enc->enc_pic.display_frame_id,
+                                                 RENCODE_AV1_DELTA_FRAME_ID_LENGTH +
+                                                 RENCODE_AV1_ADDITIONAL_FRAME_ID_LENGTH);
+   } else {
+      /*  frame_type  */
+      radeon_enc_code_fixed_bits(enc, enc->enc_pic.frame_type, 2);
+      /*  show_frame  */
+      radeon_enc_code_fixed_bits(enc, 1, 1);
+      bool error_resilient_mode = false;
+      if ((enc->enc_pic.frame_type == PIPE_AV1_ENC_FRAME_TYPE_SWITCH) ||
+            (enc->enc_pic.frame_type == PIPE_AV1_ENC_FRAME_TYPE_KEY))
+         error_resilient_mode = true;
+      else {
+         /*  error_resilient_mode  */
+         radeon_enc_code_fixed_bits(enc, enc->enc_pic.enable_error_resilient_mode ? 1 : 0, 1);
+         error_resilient_mode = enc->enc_pic.enable_error_resilient_mode;
+      }
+      /*  disable_cdf_update  */
+      radeon_enc_code_fixed_bits(enc, enc->enc_pic.av1_spec_misc.disable_cdf_update ? 1 : 0, 1);
+
+      bool allow_screen_content_tools = false;
+      if (!enc->enc_pic.disable_screen_content_tools) {
+         /*  allow_screen_content_tools  */
+         allow_screen_content_tools = enc->enc_pic.av1_spec_misc.palette_mode_enable ||
+                                      enc->enc_pic.force_integer_mv;
+         radeon_enc_code_fixed_bits(enc, allow_screen_content_tools ? 1 : 0, 1);
+      }
+
+      if (allow_screen_content_tools)
+         /*  force_integer_mv  */
+         radeon_enc_code_fixed_bits(enc, enc->enc_pic.force_integer_mv ? 1 : 0, 1);
+
+      if (enc->enc_pic.frame_id_numbers_present)
+         /*  current_frame_id  */
+         radeon_enc_code_fixed_bits(enc, enc->enc_pic.frame_id,
+               RENCODE_AV1_DELTA_FRAME_ID_LENGTH +
+               RENCODE_AV1_ADDITIONAL_FRAME_ID_LENGTH);
+
+      bool frame_size_override = false;
+      if (enc->enc_pic.frame_type == PIPE_AV1_ENC_FRAME_TYPE_SWITCH)
+         frame_size_override = true;
+      else {
+         /*  frame_size_override_flag  */
+         frame_size_override = false;
+         radeon_enc_code_fixed_bits(enc, 0, 1);
+      }
+
+      if (enc->enc_pic.enable_order_hint)
+         radeon_enc_code_fixed_bits(enc, enc->enc_pic.order_hint, enc->enc_pic.order_hint_bits);
+
+      if (!frame_is_intra && !error_resilient_mode)
+         /*  primary_ref_frame  */
+         radeon_enc_code_fixed_bits(enc, 0, 3);         /* always LAST_FRAME(1) */
+
+      if ((enc->enc_pic.frame_type != PIPE_AV1_ENC_FRAME_TYPE_SWITCH) &&
+                                 (enc->enc_pic.frame_type != PIPE_AV1_ENC_FRAME_TYPE_KEY))
+         /*  refresh_frame_flags  */
+         radeon_enc_code_fixed_bits(enc, enc->enc_pic.refresh_frame_flags, 8);
+
+      if ((!frame_is_intra || enc->enc_pic.refresh_frame_flags != 0xff) &&
+                     error_resilient_mode && enc->enc_pic.enable_order_hint)
+         for (i = 0; i < RENCDOE_AV1_NUM_REF_FRAMES; i++)
+            /*  ref_order_hint  */
+            radeon_enc_code_fixed_bits(enc, enc->enc_pic.reference_order_hint[i], enc->enc_pic.order_hint_bits);
+
+      if (frame_is_intra) {
+         /*  render_and_frame_size_different  */
+         radeon_enc_code_fixed_bits(enc, enc->enc_pic.enable_render_size ? 1 : 0, 1);
+         if (enc->enc_pic.enable_render_size) {
+            /*  render_width_minus_1  */
+            radeon_enc_code_fixed_bits(enc, enc->enc_pic.render_width - 1, 16);
+            /*  render_height_minus_1  */
+            radeon_enc_code_fixed_bits(enc, enc->enc_pic.render_height - 1, 16);
+         }
+         if (!enc->enc_pic.disable_screen_content_tools &&
+               (enc->enc_pic.av1_spec_misc.palette_mode_enable || enc->enc_pic.force_integer_mv))
+            /*  allow_intrabc  */
+            radeon_enc_code_fixed_bits(enc, 0, 1);
+      } else {
+         if (enc->enc_pic.enable_order_hint)
+            /*  frame_refs_short_signaling  */
+            radeon_enc_code_fixed_bits(enc, 0, 1);
+         for (i = 0; i < RENCDOE_AV1_REFS_PER_FRAME; i++) {
+            /*  ref_frame_idx  */
+            radeon_enc_code_fixed_bits(enc, enc->enc_pic.reference_frame_index, 3);
+            if (enc->enc_pic.frame_id_numbers_present)
+               radeon_enc_code_fixed_bits(enc,
+                                          enc->enc_pic.reference_delta_frame_id - 1,
+                                          RENCODE_AV1_DELTA_FRAME_ID_LENGTH);
+         }
+
+         if (frame_size_override && !error_resilient_mode)
+            /*  found_ref  */
+            radeon_enc_code_fixed_bits(enc, 1, 1);
+         else {
+            if(frame_size_override) {
+               /*  frame_width_minus_1  */
+               uint32_t used_bits =
+                        radeon_enc_value_bits(enc->enc_pic.session_init.aligned_picture_width - 1);
+               radeon_enc_code_fixed_bits(enc, enc->enc_pic.session_init.aligned_picture_width - 1,
+                                               used_bits);
+               /*  frame_height_minus_1  */
+               used_bits = radeon_enc_value_bits(enc->enc_pic.session_init.aligned_picture_height - 1);
+               radeon_enc_code_fixed_bits(enc, enc->enc_pic.session_init.aligned_picture_height - 1,
+                                               used_bits);
+            }
+            /*  render_and_frame_size_different  */
+            radeon_enc_code_fixed_bits(enc, enc->enc_pic.enable_render_size ? 1 : 0, 1);
+            if (enc->enc_pic.enable_render_size) {
+               /*  render_width_minus_1  */
+               radeon_enc_code_fixed_bits(enc, enc->enc_pic.render_width - 1, 16);
+               /*  render_height_minus_1  */
+               radeon_enc_code_fixed_bits(enc, enc->enc_pic.render_height - 1, 16);
+            }
+         }
+
+         if (enc->enc_pic.disable_screen_content_tools || !enc->enc_pic.force_integer_mv)
+            /*  allow_high_precision_mv  */
+            radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_ALLOW_HIGH_PRECISION_MV, 0);
+
+         /*  read_interpolation_filter  */
+         radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_READ_INTERPOLATION_FILTER, 0);
+
+         radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_COPY, 0);
+         /*  is_motion_mode_switchable  */
+         radeon_enc_code_fixed_bits(enc, 0, 1);
+      }
+
+      if (!enc->enc_pic.av1_spec_misc.disable_cdf_update)
+         /*  disable_frame_end_update_cdf  */
+         radeon_enc_code_fixed_bits(enc, enc->enc_pic.av1_spec_misc.disable_frame_end_update_cdf ? 1 : 0, 1);
+
+      /*  tile_info  */
+      radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_TILE_INFO, 0);
+      /*  quantization_params  */
+      radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_QUANTIZATION_PARAMS, 0);
+      /*  segmentation_enable  */
+      radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_COPY, 0);
+      radeon_enc_code_fixed_bits(enc, 0, 1);
+      /*  delta_q_params  */
+      radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_DELTA_Q_PARAMS, 0);
+      /*  delta_lf_params  */
+      radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_DELTA_LF_PARAMS, 0);
+      /*  loop_filter_params  */
+      radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_LOOP_FILTER_PARAMS, 0);
+      /*  cdef_params  */
+      radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_CDEF_PARAMS, 0);
+      /*  lr_params  */
+      /*  read_tx_mode  */
+      radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_READ_TX_MODE, 0);
+
+      radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_COPY, 0);
+      if (!frame_is_intra)
+         /*  reference_select  */
+         radeon_enc_code_fixed_bits(enc, 0, 1);
+
+      radeon_enc_code_fixed_bits(enc, 0, 1);
+      if (!frame_is_intra)
+         for (uint32_t ref = 1 /*LAST_FRAME*/; ref <= 7 /*ALTREF_FRAME*/; ref++)
+            /*  is_global  */
+            radeon_enc_code_fixed_bits(enc, 0, 1);
+      /*  film_grain_params() */
+   }
+}
+
+static void radeon_enc_av1_tile_group(struct radeon_encoder *enc)
+{
+   uint32_t extension_flag = enc->enc_pic.num_temporal_layers > 1 ? 1 : 0;
+
+   radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_OBU_START,
+                                           RENCODE_OBU_START_TYPE_TILE_GROUP);
+   radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_COPY, 0);
+
+   /*  obu_header() */
+   /*  obu_forbidden_bit  */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+   /*  obu_type  */
+   radeon_enc_code_fixed_bits(enc, RENCODE_OBU_TYPE_TILE_GROUP, 4);
+   /*  obu_extension_flag  */
+   radeon_enc_code_fixed_bits(enc, extension_flag, 1);
+   /*  obu_has_size_field  */
+   radeon_enc_code_fixed_bits(enc, 1, 1);
+   /*  obu_reserved_1bit  */
+   radeon_enc_code_fixed_bits(enc, 0, 1);
+
+   if (extension_flag) {
+      radeon_enc_code_fixed_bits(enc, enc->enc_pic.temporal_id, 3);
+      radeon_enc_code_fixed_bits(enc, 0, 2);
+      radeon_enc_code_fixed_bits(enc, 0, 3);
+   }
+
+   radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_OBU_SIZE, 0);
+   radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_TILE_GROUP_OBU, 0);
+   radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_OBU_END, 0);
+}
+
+static void radeon_enc_obu_instruction(struct radeon_encoder *enc)
+{
+   bool frame_header = !enc->enc_pic.stream_obu_frame ||
+                       (enc->enc_pic.frame_type == PIPE_AV1_ENC_FRAME_TYPE_SHOW_EXISTING);
+   radeon_enc_reset(enc);
+   RADEON_ENC_BEGIN(enc->cmd.bitstream_instruction_av1);
+   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)
+      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
+    *
+    * if (others)
+    *    radeon_enc_av1_others(enc); */
+
+   radeon_enc_av1_bs_instruction_type(enc,
+         RENCODE_AV1_BITSTREAM_INSTRUCTION_OBU_START,
+            frame_header ? RENCODE_OBU_START_TYPE_FRAME_HEADER
+                         : RENCODE_OBU_START_TYPE_FRAME);
+
+   radeon_enc_av1_frame_header(enc, frame_header);
+
+   if (!frame_header && (enc->enc_pic.frame_type != PIPE_AV1_ENC_FRAME_TYPE_SHOW_EXISTING))
+      radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_TILE_GROUP_OBU, 0);
+
+   radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_OBU_END, 0);
+
+   if (frame_header && (enc->enc_pic.frame_type != PIPE_AV1_ENC_FRAME_TYPE_SHOW_EXISTING))
+      radeon_enc_av1_tile_group(enc);
+
+   radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_END, 0);
+   RADEON_ENC_END();
+}
+
+/* av1 encode params */
+static void radeon_enc_av1_encode_params(struct radeon_encoder *enc)
+{
+   switch (enc->enc_pic.frame_type) {
+   case PIPE_AV1_ENC_FRAME_TYPE_KEY:
+      enc->enc_pic.enc_params.pic_type = RENCODE_PICTURE_TYPE_I;
+      break;
+   case PIPE_AV1_ENC_FRAME_TYPE_INTRA_ONLY:
+      enc->enc_pic.enc_params.pic_type = RENCODE_PICTURE_TYPE_I;
+      break;
+   case PIPE_AV1_ENC_FRAME_TYPE_INTER:
+   case PIPE_AV1_ENC_FRAME_TYPE_SWITCH:
+   case PIPE_AV1_ENC_FRAME_TYPE_SHOW_EXISTING:
+      enc->enc_pic.enc_params.pic_type = RENCODE_PICTURE_TYPE_P;
+      break;
+   default:
+      assert(0); /* never come to this condition */
+   }
+
+   if (enc->luma->meta_offset) {
+      RVID_ERR("DCC surfaces not supported.\n");
+      return;
+   }
+
+   enc->enc_pic.enc_params.allowed_max_bitstream_size = enc->bs_size;
+   enc->enc_pic.enc_params.input_pic_luma_pitch = enc->luma->u.gfx9.surf_pitch;
+   enc->enc_pic.enc_params.input_pic_chroma_pitch = enc->chroma->u.gfx9.surf_pitch;
+   enc->enc_pic.enc_params.input_pic_swizzle_mode = enc->luma->u.gfx9.swizzle_mode;
+
+   RADEON_ENC_BEGIN(enc->cmd.enc_params);
+   RADEON_ENC_CS(enc->enc_pic.enc_params.pic_type);
+   RADEON_ENC_CS(enc->enc_pic.enc_params.allowed_max_bitstream_size);
+
+   /* show existing type doesn't need input picture */
+   if (enc->enc_pic.frame_type == PIPE_AV1_ENC_FRAME_TYPE_SHOW_EXISTING) {
+      RADEON_ENC_CS(0);
+      RADEON_ENC_CS(0);
+      RADEON_ENC_CS(0);
+      RADEON_ENC_CS(0);
+   } else {
+      RADEON_ENC_READ(enc->handle, RADEON_DOMAIN_VRAM, enc->luma->u.gfx9.surf_offset);
+      RADEON_ENC_READ(enc->handle, RADEON_DOMAIN_VRAM, enc->chroma->u.gfx9.surf_offset);
+   }
+
+   RADEON_ENC_CS(enc->enc_pic.enc_params.input_pic_luma_pitch);
+   RADEON_ENC_CS(enc->enc_pic.enc_params.input_pic_chroma_pitch);
+   RADEON_ENC_CS(enc->enc_pic.enc_params.input_pic_swizzle_mode);
+   RADEON_ENC_CS(enc->enc_pic.enc_params.reference_picture_index);
+   RADEON_ENC_CS(enc->enc_pic.enc_params.reconstructed_picture_index);
+   RADEON_ENC_END();
+}
+
 static uint32_t radeon_enc_ref_swizzle_mode(struct radeon_encoder *enc)
 {
    /* return RENCODE_REC_SWIZZLE_MODE_LINEAR; for debugging purpose */
@@ -131,10 +1008,22 @@ static void radeon_enc_ctx(struct radeon_encoder *enc)
    RADEON_ENC_END();
 }
 
+static void radeon_enc_header_av1(struct radeon_encoder *enc)
+{
+   enc->obu_instructions(enc);
+   enc->encode_params(enc);
+   enc->cdf_default_table(enc);
+
+   enc->enc_pic.frame_id++;
+   if (enc->enc_pic.frame_id > (1 << (RENCODE_AV1_DELTA_FRAME_ID_LENGTH - 2)))
+      enc->enc_pic.frame_id = 0;
+}
+
 void radeon_enc_4_0_init(struct radeon_encoder *enc)
 {
    radeon_enc_3_0_init(enc);
 
+   enc->session_init = radeon_enc_session_init;
    enc->ctx = radeon_enc_ctx;
    enc->mq_begin = enc->begin;
    enc->mq_encode = enc->encode;
@@ -143,6 +1032,21 @@ void radeon_enc_4_0_init(struct radeon_encoder *enc)
    enc->encode = radeon_enc_sq_encode;
    enc->destroy = radeon_enc_sq_destroy;
 
+   if (u_reduce_video_profile(enc->base.profile) == PIPE_VIDEO_FORMAT_AV1) {
+      enc->before_encode = radeon_enc_av1_dpb_management;
+      /* begin function need to set these two functions to dummy */
+      enc->slice_control = radeon_enc_dummy;
+      enc->deblocking_filter = radeon_enc_dummy;
+      enc->cmd.cdf_default_table_av1 = RENCODE_IB_PARAM_CDF_DEFAULT_TABLE_BUFFER;
+      enc->cmd.bitstream_instruction_av1 = RENCODE_AV1_IB_PARAM_BITSTREAM_INSTRUCTION;
+      enc->cmd.spec_misc_av1 = RENCODE_AV1_IB_PARAM_SPEC_MISC;
+      enc->spec_misc = radeon_enc_spec_misc_av1;
+      enc->encode_headers = radeon_enc_header_av1;
+      enc->obu_instructions = radeon_enc_obu_instruction;
+      enc->cdf_default_table = radeon_enc_cdf_default_table;
+      enc->encode_params = radeon_enc_av1_encode_params;
+   }
+
    enc->cmd.enc_statistics = RENCODE_IB_PARAM_ENCODE_STATISTICS;
 
    enc->enc_pic.session_info.interface_version =