diff --git a/src/amd/vulkan/radv_video.c b/src/amd/vulkan/radv_video.c index 3c1b688c2fc..26571767db8 100644 --- a/src/amd/vulkan/radv_video.c +++ b/src/amd/vulkan/radv_video.c @@ -338,6 +338,7 @@ radv_video_patch_session_parameters(struct vk_video_session_parameters *params) default: return; case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR: + case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR: radv_video_patch_encode_session_parameters(params); break; } @@ -407,6 +408,31 @@ radv_CreateVideoSessionKHR(VkDevice _device, const VkVideoSessionCreateInfoKHR * break; } break; + case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR: + vid->encode = true; + vid->enc_session.encode_standard = RENCODE_ENCODE_STANDARD_HEVC; + vid->enc_session.aligned_picture_width = align(vid->vk.max_coded.width, 64); + vid->enc_session.aligned_picture_height = align(vid->vk.max_coded.height, 64); + vid->enc_session.padding_width = vid->enc_session.aligned_picture_width - vid->vk.max_coded.width; + vid->enc_session.padding_height = vid->enc_session.aligned_picture_height - vid->vk.max_coded.height; + vid->enc_session.display_remote = 0; + vid->enc_session.pre_encode_mode = 0; + vid->enc_session.pre_encode_chroma_enabled = 0; + switch (vid->vk.enc_usage.tuning_mode) { + case VK_VIDEO_ENCODE_TUNING_MODE_DEFAULT_KHR: + default: + vid->enc_preset_mode = RENCODE_PRESET_MODE_BALANCE; + break; + case VK_VIDEO_ENCODE_TUNING_MODE_LOW_LATENCY_KHR: + case VK_VIDEO_ENCODE_TUNING_MODE_ULTRA_LOW_LATENCY_KHR: + vid->enc_preset_mode = RENCODE_PRESET_MODE_SPEED; + break; + case VK_VIDEO_ENCODE_TUNING_MODE_HIGH_QUALITY_KHR: + case VK_VIDEO_ENCODE_TUNING_MODE_LOSSLESS_KHR: + vid->enc_preset_mode = RENCODE_PRESET_MODE_QUALITY; + break; + } + break; default: return VK_ERROR_FEATURE_NOT_PRESENT; } @@ -496,6 +522,10 @@ radv_GetPhysicalDeviceVideoCapabilitiesKHR(VkPhysicalDevice physicalDevice, cons cap = &pdev->info.enc_caps.codec_info[AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC]; is_encode = true; break; + case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR: + cap = &pdev->info.enc_caps.codec_info[AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC]; + is_encode = true; + break; #endif default: unreachable("unsupported operation"); @@ -656,6 +686,43 @@ radv_GetPhysicalDeviceVideoCapabilitiesKHR(VkPhysicalDevice physicalDevice, cons pCapabilities->stdHeaderVersion.specVersion = VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_SPEC_VERSION; break; } + case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR: { + struct VkVideoEncodeH265CapabilitiesKHR *ext = (struct VkVideoEncodeH265CapabilitiesKHR *)vk_find_struct( + pCapabilities->pNext, VIDEO_ENCODE_H265_CAPABILITIES_KHR); + ext->flags = 0; + pCapabilities->maxDpbSlots = NUM_H2645_REFS; + pCapabilities->maxActiveReferencePictures = NUM_H2645_REFS; + ext->maxLevelIdc = cap ? cap->max_level : 0; + ext->maxSliceSegmentCount = 128; + ext->maxTiles.width = 1; + ext->maxTiles.height = 1; + ext->ctbSizes = VK_VIDEO_ENCODE_H265_CTB_SIZE_64_BIT_KHR; + ext->transformBlockSizes = + VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_4_BIT_KHR | VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_8_BIT_KHR | + VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_16_BIT_KHR | VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_32_BIT_KHR; + ext->maxPPictureL0ReferenceCount = 1; + ext->maxBPictureL0ReferenceCount = 0; + ext->maxL1ReferenceCount = 0; + ext->maxSubLayerCount = 1; + ext->expectDyadicTemporalSubLayerPattern = false; + ext->minQp = 0; + ext->maxQp = 51; + ext->prefersGopRemainingFrames = false; + ext->requiresGopRemainingFrames = false; + ext->stdSyntaxFlags = VK_VIDEO_ENCODE_H265_STD_CONSTRAINED_INTRA_PRED_FLAG_SET_BIT_KHR | + VK_VIDEO_ENCODE_H265_STD_DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG_SET_BIT_KHR | + VK_VIDEO_ENCODE_H265_STD_CONSTRAINED_INTRA_PRED_FLAG_SET_BIT_KHR | + VK_VIDEO_ENCODE_H265_STD_ENTROPY_CODING_SYNC_ENABLED_FLAG_SET_BIT_KHR; + + if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_2) + ext->stdSyntaxFlags |= VK_VIDEO_ENCODE_H265_STD_SAMPLE_ADAPTIVE_OFFSET_ENABLED_FLAG_SET_BIT_KHR; + + if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_3) + ext->stdSyntaxFlags |= VK_VIDEO_ENCODE_H265_STD_TRANSFORM_SKIP_ENABLED_FLAG_SET_BIT_KHR; + strcpy(pCapabilities->stdHeaderVersion.extensionName, VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_EXTENSION_NAME); + pCapabilities->stdHeaderVersion.specVersion = VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_SPEC_VERSION; + break; + } default: break; } diff --git a/src/amd/vulkan/radv_video_enc.c b/src/amd/vulkan/radv_video_enc.c index 68ada453b8d..53f6b61655e 100644 --- a/src/amd/vulkan/radv_video_enc.c +++ b/src/amd/vulkan/radv_video_enc.c @@ -63,6 +63,10 @@ #define RENCODE_V2_IB_PARAM_FEEDBACK_BUFFER 0x00000015 #define RENCODE_V2_IB_PARAM_ENCODE_STATISTICS 0x00000019 +#define RENCODE_V2_HEVC_IB_PARAM_SLICE_CONTROL 0x00100001 +#define RENCODE_V2_HEVC_IB_PARAM_SPEC_MISC 0x00100002 +#define RENCODE_V2_HEVC_IB_PARAM_LOOP_FILTER 0x00100003 + #define RENCODE_V2_H264_IB_PARAM_SLICE_CONTROL 0x00200001 #define RENCODE_V2_H264_IB_PARAM_SPEC_MISC 0x00200002 #define RENCODE_V2_H264_IB_PARAM_ENCODE_PARAMS 0x00200003 @@ -89,6 +93,10 @@ #define RENCODE_IB_PARAM_DIRECT_OUTPUT_NALU 0x00000020 #define RENCODE_IB_PARAM_ENCODE_STATISTICS 0x00000024 +#define RENCODE_HEVC_IB_PARAM_SLICE_CONTROL 0x00100001 +#define RENCODE_HEVC_IB_PARAM_SPEC_MISC 0x00100002 +#define RENCODE_HEVC_IB_PARAM_DEBLOCKING_FILTER 0x00100003 + #define RENCODE_H264_IB_PARAM_SLICE_CONTROL 0x00200001 #define RENCODE_H264_IB_PARAM_SPEC_MISC 0x00200002 #define RENCODE_H264_IB_PARAM_ENCODE_PARAMS 0x00200003 @@ -137,6 +145,9 @@ radv_init_physical_device_encoder(struct radv_physical_device *pdev) pdev->vcn_enc_cmds.ctx = RENCODE_V2_IB_PARAM_ENCODE_CONTEXT_BUFFER; pdev->vcn_enc_cmds.bitstream = RENCODE_V2_IB_PARAM_VIDEO_BITSTREAM_BUFFER; pdev->vcn_enc_cmds.feedback = RENCODE_V2_IB_PARAM_FEEDBACK_BUFFER; + pdev->vcn_enc_cmds.slice_control_hevc = RENCODE_V2_HEVC_IB_PARAM_SLICE_CONTROL; + pdev->vcn_enc_cmds.spec_misc_hevc = RENCODE_V2_HEVC_IB_PARAM_SPEC_MISC; + pdev->vcn_enc_cmds.deblocking_filter_hevc = RENCODE_V2_HEVC_IB_PARAM_LOOP_FILTER; pdev->vcn_enc_cmds.slice_control_h264 = RENCODE_V2_H264_IB_PARAM_SLICE_CONTROL; pdev->vcn_enc_cmds.spec_misc_h264 = RENCODE_V2_H264_IB_PARAM_SPEC_MISC; pdev->vcn_enc_cmds.enc_params_h264 = RENCODE_V2_H264_IB_PARAM_ENCODE_PARAMS; @@ -162,6 +173,9 @@ radv_init_physical_device_encoder(struct radv_physical_device *pdev) pdev->vcn_enc_cmds.ctx = RENCODE_IB_PARAM_ENCODE_CONTEXT_BUFFER; pdev->vcn_enc_cmds.bitstream = RENCODE_IB_PARAM_VIDEO_BITSTREAM_BUFFER; pdev->vcn_enc_cmds.feedback = RENCODE_IB_PARAM_FEEDBACK_BUFFER; + pdev->vcn_enc_cmds.slice_control_hevc = RENCODE_HEVC_IB_PARAM_SLICE_CONTROL; + pdev->vcn_enc_cmds.spec_misc_hevc = RENCODE_HEVC_IB_PARAM_SPEC_MISC; + pdev->vcn_enc_cmds.deblocking_filter_hevc = RENCODE_HEVC_IB_PARAM_DEBLOCKING_FILTER; pdev->vcn_enc_cmds.slice_control_h264 = RENCODE_H264_IB_PARAM_SLICE_CONTROL; pdev->vcn_enc_cmds.spec_misc_h264 = RENCODE_H264_IB_PARAM_SPEC_MISC; pdev->vcn_enc_cmds.enc_params_h264 = RENCODE_H264_IB_PARAM_ENCODE_PARAMS; @@ -405,6 +419,9 @@ radv_enc_session_init(struct radv_cmd_buffer *cmd_buffer, const struct VkVideoEn struct radv_video_session *vid = cmd_buffer->video.vid; struct radeon_cmdbuf *cs = cmd_buffer->cs; unsigned alignment = 16; + if (vid->vk.op == VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR) { + alignment = 64; + } uint32_t w = enc_info->srcPictureResource.codedExtent.width; uint32_t h = enc_info->srcPictureResource.codedExtent.height; @@ -503,6 +520,62 @@ radv_enc_spec_misc_h264(struct radv_cmd_buffer *cmd_buffer, const struct VkVideo ENC_END; } +static void +radv_enc_spec_misc_hevc(struct radv_cmd_buffer *cmd_buffer, const struct VkVideoEncodeInfoKHR *enc_info) +{ + struct radv_device *device = radv_cmd_buffer_device(cmd_buffer); + const struct radv_physical_device *pdev = radv_device_physical(device); + struct radeon_cmdbuf *cs = cmd_buffer->cs; + const struct VkVideoEncodeH265PictureInfoKHR *h265_picture_info = + vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H265_PICTURE_INFO_KHR); + const StdVideoEncodeH265PictureInfo *pic = h265_picture_info->pStdPictureInfo; + const VkVideoEncodeH265NaluSliceSegmentInfoKHR *h265_slice = &h265_picture_info->pNaluSliceSegmentEntries[0]; + const StdVideoEncodeH265SliceSegmentHeader *slice = h265_slice->pStdSliceSegmentHeader; + const StdVideoH265SequenceParameterSet *sps = + vk_video_find_h265_enc_std_sps(&cmd_buffer->video.params->vk, pic->pps_seq_parameter_set_id); + const StdVideoH265PictureParameterSet *pps = + vk_video_find_h265_enc_std_pps(&cmd_buffer->video.params->vk, pic->pps_pic_parameter_set_id); + ENC_BEGIN; + radeon_emit(cs, pdev->vcn_enc_cmds.spec_misc_hevc); + radeon_emit(cs, sps->log2_min_luma_coding_block_size_minus3); + radeon_emit(cs, !sps->flags.amp_enabled_flag); + radeon_emit(cs, sps->flags.strong_intra_smoothing_enabled_flag); + radeon_emit(cs, pps->flags.constrained_intra_pred_flag); + radeon_emit(cs, slice->flags.cabac_init_flag); + radeon_emit(cs, 1); // enc->enc_pic.hevc_spec_misc.half_pel_enabled + radeon_emit(cs, 1); // enc->enc_pic.hevc_spec_misc.quarter_pel_enabled + if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_3) { + radeon_emit(cs, !pps->flags.transform_skip_enabled_flag); + radeon_emit(cs, pps->flags.cu_qp_delta_enabled_flag); + } + ENC_END; +} + +static void +radv_enc_slice_control_hevc(struct radv_cmd_buffer *cmd_buffer, const struct VkVideoEncodeInfoKHR *enc_info) +{ + struct radv_device *device = radv_cmd_buffer_device(cmd_buffer); + const struct radv_physical_device *pdev = radv_device_physical(device); + struct radeon_cmdbuf *cs = cmd_buffer->cs; + const struct VkVideoEncodeH265PictureInfoKHR *h265_picture_info = + vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H265_PICTURE_INFO_KHR); + const StdVideoEncodeH265PictureInfo *pic = h265_picture_info->pStdPictureInfo; + const StdVideoH265SequenceParameterSet *sps = + vk_video_find_h265_enc_std_sps(&cmd_buffer->video.params->vk, pic->pps_seq_parameter_set_id); + + uint32_t width_in_ctb, height_in_ctb, num_ctbs_in_slice; + + width_in_ctb = sps->pic_width_in_luma_samples / 64; + height_in_ctb = sps->pic_height_in_luma_samples / 64; + num_ctbs_in_slice = width_in_ctb * height_in_ctb; + ENC_BEGIN; + radeon_emit(cs, pdev->vcn_enc_cmds.slice_control_hevc); + radeon_emit(cs, RENCODE_HEVC_SLICE_CONTROL_MODE_FIXED_CTBS); + radeon_emit(cs, num_ctbs_in_slice); // num_ctbs_in_slice + radeon_emit(cs, num_ctbs_in_slice); // num_ctbs_in_slice_segment + ENC_END; +} + static void radv_enc_rc_session_init(struct radv_cmd_buffer *cmd_buffer) { @@ -556,6 +629,33 @@ radv_enc_deblocking_filter_h264(struct radv_cmd_buffer *cmd_buffer, const VkVide ENC_END; } +static void +radv_enc_deblocking_filter_hevc(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info) +{ + struct radv_device *device = radv_cmd_buffer_device(cmd_buffer); + const struct radv_physical_device *pdev = radv_device_physical(device); + struct radeon_cmdbuf *cs = cmd_buffer->cs; + const struct VkVideoEncodeH265PictureInfoKHR *h265_picture_info = + vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H265_PICTURE_INFO_KHR); + const StdVideoEncodeH265PictureInfo *pic = h265_picture_info->pStdPictureInfo; + const VkVideoEncodeH265NaluSliceSegmentInfoKHR *h265_slice = &h265_picture_info->pNaluSliceSegmentEntries[0]; + const StdVideoEncodeH265SliceSegmentHeader *slice = h265_slice->pStdSliceSegmentHeader; + const StdVideoH265SequenceParameterSet *sps = + vk_video_find_h265_enc_std_sps(&cmd_buffer->video.params->vk, pic->pps_seq_parameter_set_id); + + ENC_BEGIN; + radeon_emit(cs, pdev->vcn_enc_cmds.deblocking_filter_hevc); + radeon_emit(cs, slice->flags.slice_loop_filter_across_slices_enabled_flag); + radeon_emit(cs, slice->flags.slice_deblocking_filter_disabled_flag); + radeon_emit(cs, slice->slice_beta_offset_div2); + radeon_emit(cs, slice->slice_tc_offset_div2); + radeon_emit(cs, slice->slice_cb_qp_offset); + radeon_emit(cs, slice->slice_cr_qp_offset); + if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_2) + radeon_emit(cs, !sps->flags.sample_adaptive_offset_enabled_flag); + ENC_END; +} + static void radv_enc_quality_params(struct radv_cmd_buffer *cmd_buffer) { @@ -770,6 +870,221 @@ radv_enc_slice_header(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInf ENC_END; } +static void +radv_enc_slice_header_hevc(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info) +{ + struct radv_enc_state *enc = &cmd_buffer->video.enc; + uint32_t instruction[RENCODE_SLICE_HEADER_TEMPLATE_MAX_NUM_INSTRUCTIONS] = {0}; + uint32_t num_bits[RENCODE_SLICE_HEADER_TEMPLATE_MAX_NUM_INSTRUCTIONS] = {0}; + const struct VkVideoEncodeH265PictureInfoKHR *h265_picture_info = + vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H265_PICTURE_INFO_KHR); + const StdVideoEncodeH265PictureInfo *pic = h265_picture_info->pStdPictureInfo; + const VkVideoEncodeH265NaluSliceSegmentInfoKHR *h265_slice = &h265_picture_info->pNaluSliceSegmentEntries[0]; + const StdVideoEncodeH265SliceSegmentHeader *slice = h265_slice->pStdSliceSegmentHeader; + const StdVideoH265SequenceParameterSet *sps = + vk_video_find_h265_enc_std_sps(&cmd_buffer->video.params->vk, pic->pps_seq_parameter_set_id); + const StdVideoH265PictureParameterSet *pps = + vk_video_find_h265_enc_std_pps(&cmd_buffer->video.params->vk, pic->pps_pic_parameter_set_id); + unsigned int inst_index = 0; + unsigned int cdw_start = 0; + unsigned int cdw_filled = 0; + unsigned int bits_copied = 0; + struct radv_device *device = radv_cmd_buffer_device(cmd_buffer); + const struct radv_physical_device *pdev = radv_device_physical(device); + struct radeon_cmdbuf *cs = cmd_buffer->cs; + unsigned nal_unit_type = vk_video_get_h265_nal_unit(pic->pic_type, pic->flags.IrapPicFlag); + + ENC_BEGIN; + radeon_emit(cs, pdev->vcn_enc_cmds.slice_header); + radv_enc_reset(cmd_buffer); + radv_enc_set_emulation_prevention(cmd_buffer, false); + + cdw_start = cs->cdw; + radv_enc_code_fixed_bits(cmd_buffer, 0x0, 1); + radv_enc_code_fixed_bits(cmd_buffer, nal_unit_type, 6); + radv_enc_code_fixed_bits(cmd_buffer, 0x0, 6); + radv_enc_code_fixed_bits(cmd_buffer, 0x1, 3); + + radv_enc_flush_headers(cmd_buffer); + instruction[inst_index] = RENCODE_HEADER_INSTRUCTION_COPY; + num_bits[inst_index] = enc->bits_output - bits_copied; + bits_copied = enc->bits_output; + inst_index++; + + instruction[inst_index] = RENCODE_HEVC_HEADER_INSTRUCTION_FIRST_SLICE; + inst_index++; + + if ((nal_unit_type >= 16) && (nal_unit_type <= 23)) + radv_enc_code_fixed_bits(cmd_buffer, 0x0, 1); + + radv_enc_code_ue(cmd_buffer, pic->pps_pic_parameter_set_id); + + radv_enc_flush_headers(cmd_buffer); + instruction[inst_index] = RENCODE_HEADER_INSTRUCTION_COPY; + num_bits[inst_index] = enc->bits_output - bits_copied; + bits_copied = enc->bits_output; + inst_index++; + + instruction[inst_index] = RENCODE_HEVC_HEADER_INSTRUCTION_SLICE_SEGMENT; + inst_index++; + + instruction[inst_index] = RENCODE_HEVC_HEADER_INSTRUCTION_DEPENDENT_SLICE_END; + inst_index++; + + /* slice_type */ + switch (pic->pic_type) { + case STD_VIDEO_H265_PICTURE_TYPE_I: + case STD_VIDEO_H265_PICTURE_TYPE_IDR: + radv_enc_code_ue(cmd_buffer, 0x2); + break; + case STD_VIDEO_H265_PICTURE_TYPE_P: + radv_enc_code_ue(cmd_buffer, 0x1); + break; + case STD_VIDEO_H265_PICTURE_TYPE_B: + radv_enc_code_ue(cmd_buffer, 0x0); + break; + default: + radv_enc_code_ue(cmd_buffer, 0x1); + } + + if ((nal_unit_type != 19) && nal_unit_type != 20) { + /* slice_pic_order_cnt_lsb */ + radv_enc_code_fixed_bits(cmd_buffer, pic->PicOrderCntVal, sps->log2_max_pic_order_cnt_lsb_minus4 + 4); + radv_enc_code_fixed_bits(cmd_buffer, pic->flags.short_term_ref_pic_set_sps_flag, 0x1); + if (!pic->flags.short_term_ref_pic_set_sps_flag) { + int st_rps_idx = sps->num_short_term_ref_pic_sets; + const StdVideoH265ShortTermRefPicSet *rps = &pic->pShortTermRefPicSet[st_rps_idx]; + + if (st_rps_idx != 0) + radv_enc_code_fixed_bits(cmd_buffer, rps->flags.inter_ref_pic_set_prediction_flag, 0x1); + + if (rps->flags.inter_ref_pic_set_prediction_flag) { + int ref_rps_idx = st_rps_idx - (rps->delta_idx_minus1 + 1); + if (st_rps_idx == sps->num_short_term_ref_pic_sets) + radv_enc_code_ue(cmd_buffer, rps->delta_idx_minus1); + radv_enc_code_fixed_bits(cmd_buffer, rps->flags.delta_rps_sign, 0x1); + radv_enc_code_ue(cmd_buffer, rps->abs_delta_rps_minus1); + + const StdVideoH265ShortTermRefPicSet *rps_ref = &sps->pShortTermRefPicSet[ref_rps_idx]; + int num_delta_pocs = rps_ref->num_negative_pics + rps_ref->num_positive_pics; + for (int j = 0; j < num_delta_pocs; j++) { + radv_enc_code_fixed_bits(cmd_buffer, !!(rps->used_by_curr_pic_flag & (1 << j)), 0x1); + if (!(rps->used_by_curr_pic_flag & (1 << j))) { + radv_enc_code_fixed_bits(cmd_buffer, !!(rps->use_delta_flag & (1 << j)), 0x1); + } + } + } else { + radv_enc_code_ue(cmd_buffer, rps->num_negative_pics); + radv_enc_code_ue(cmd_buffer, rps->num_positive_pics); + + for (int i = 0; i < rps->num_negative_pics; i++) { + radv_enc_code_ue(cmd_buffer, rps->delta_poc_s0_minus1[i]); + radv_enc_code_fixed_bits(cmd_buffer, !!(rps->used_by_curr_pic_s0_flag & (1 << i)), 0x1); + } + for (int i = 0; i < rps->num_positive_pics; i++) { + radv_enc_code_ue(cmd_buffer, rps->delta_poc_s1_minus1[i]); + radv_enc_code_fixed_bits(cmd_buffer, !!(rps->used_by_curr_pic_s1_flag & (1 << i)), 0x1); + } + } + } else if (sps->num_short_term_ref_pic_sets > 1) + radv_enc_code_ue(cmd_buffer, pic->short_term_ref_pic_set_idx); + + if (sps->flags.sps_temporal_mvp_enabled_flag) + radv_enc_code_fixed_bits(cmd_buffer, pic->flags.slice_temporal_mvp_enabled_flag, 1); + } + + if (sps->flags.sample_adaptive_offset_enabled_flag) { + radv_enc_flush_headers(cmd_buffer); + instruction[inst_index] = RENCODE_HEADER_INSTRUCTION_COPY; + num_bits[inst_index] = enc->bits_output - bits_copied; + bits_copied = enc->bits_output; + inst_index++; + + instruction[inst_index] = RENCODE_HEVC_HEADER_INSTRUCTION_SAO_ENABLE; + inst_index++; + } + + if ((pic->pic_type == STD_VIDEO_H265_PICTURE_TYPE_P) || (pic->pic_type == STD_VIDEO_H265_PICTURE_TYPE_B)) { + radv_enc_code_fixed_bits(cmd_buffer, slice->flags.num_ref_idx_active_override_flag, 1); + if (slice->flags.num_ref_idx_active_override_flag) { + radv_enc_code_ue(cmd_buffer, pic->pRefLists->num_ref_idx_l0_active_minus1); + if (pic->pic_type == STD_VIDEO_H265_PICTURE_TYPE_B) + radv_enc_code_ue(cmd_buffer, pic->pRefLists->num_ref_idx_l1_active_minus1); + } + if (pic->pic_type == STD_VIDEO_H265_PICTURE_TYPE_B) + radv_enc_code_fixed_bits(cmd_buffer, slice->flags.mvd_l1_zero_flag, 1); + if (pps->flags.cabac_init_present_flag) + radv_enc_code_fixed_bits(cmd_buffer, slice->flags.cabac_init_flag, 1); + if (pic->flags.slice_temporal_mvp_enabled_flag) { + if (pic->pic_type == STD_VIDEO_H265_PICTURE_TYPE_B) + radv_enc_code_fixed_bits(cmd_buffer, slice->flags.collocated_from_l0_flag, 1); + } + radv_enc_code_ue(cmd_buffer, 5 - slice->MaxNumMergeCand); + } + + radv_enc_flush_headers(cmd_buffer); + instruction[inst_index] = RENCODE_HEADER_INSTRUCTION_COPY; + num_bits[inst_index] = enc->bits_output - bits_copied; + bits_copied = enc->bits_output; + inst_index++; + + instruction[inst_index] = RENCODE_HEVC_HEADER_INSTRUCTION_SLICE_QP_DELTA; + inst_index++; + + if (pps->flags.pps_slice_chroma_qp_offsets_present_flag) { + radv_enc_code_se(cmd_buffer, slice->slice_cb_qp_offset); + radv_enc_code_se(cmd_buffer, slice->slice_cr_qp_offset); + } + + if (pps->flags.pps_slice_act_qp_offsets_present_flag) { + radv_enc_code_se(cmd_buffer, slice->slice_act_y_qp_offset); + radv_enc_code_se(cmd_buffer, slice->slice_act_cb_qp_offset); + radv_enc_code_se(cmd_buffer, slice->slice_act_cr_qp_offset); + } + + if (pps->flags.chroma_qp_offset_list_enabled_flag) { + radv_enc_code_fixed_bits(cmd_buffer, slice->flags.cu_chroma_qp_offset_enabled_flag, 1); + } + + if (pps->flags.deblocking_filter_override_enabled_flag) { + radv_enc_code_fixed_bits(cmd_buffer, slice->flags.deblocking_filter_override_flag, 1); + if (slice->flags.deblocking_filter_override_flag) { + radv_enc_code_fixed_bits(cmd_buffer, slice->flags.slice_deblocking_filter_disabled_flag, 1); + if (!slice->flags.slice_deblocking_filter_disabled_flag) { + radv_enc_code_se(cmd_buffer, slice->slice_beta_offset_div2); + radv_enc_code_se(cmd_buffer, slice->slice_tc_offset_div2); + } + } + } + if ((pps->flags.pps_loop_filter_across_slices_enabled_flag) && + (!slice->flags.slice_deblocking_filter_disabled_flag || slice->flags.slice_sao_luma_flag || + slice->flags.slice_sao_chroma_flag)) { + + if (slice->flags.slice_sao_luma_flag || slice->flags.slice_sao_chroma_flag) { + instruction[inst_index] = RENCODE_HEVC_HEADER_INSTRUCTION_LOOP_FILTER_ACROSS_SLICES_ENABLE; + inst_index++; + } else { + radv_enc_code_fixed_bits(cmd_buffer, slice->flags.slice_loop_filter_across_slices_enabled_flag, 1); + radv_enc_flush_headers(cmd_buffer); + instruction[inst_index] = RENCODE_HEADER_INSTRUCTION_COPY; + num_bits[inst_index] = enc->bits_output - bits_copied; + bits_copied = enc->bits_output; + inst_index++; + } + } + + instruction[inst_index] = RENCODE_HEADER_INSTRUCTION_END; + + cdw_filled = cs->cdw - cdw_start; + for (int i = 0; i < RENCODE_SLICE_HEADER_TEMPLATE_MAX_TEMPLATE_SIZE_IN_DWORDS - cdw_filled; i++) + radeon_emit(cs, 0x00000000); + for (int j = 0; j < RENCODE_SLICE_HEADER_TEMPLATE_MAX_NUM_INSTRUCTIONS; j++) { + radeon_emit(cs, instruction[j]); + radeon_emit(cs, num_bits[j]); + } + ENC_END; +} + static void radv_enc_ctx(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *info) { @@ -947,6 +1262,13 @@ radv_enc_rc_per_pic(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoK min_qp = max_qp = qp = h264_slice->constantQp; break; } + case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR: { + const struct VkVideoEncodeH265PictureInfoKHR *h265_picture_info = + vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H265_PICTURE_INFO_KHR); + const VkVideoEncodeH265NaluSliceSegmentInfoKHR *h265_slice = &h265_picture_info->pNaluSliceSegmentEntries[0]; + min_qp = max_qp = qp = h265_slice->constantQp; + break; + } default: break; } @@ -968,7 +1290,10 @@ radv_enc_params(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR * { const struct VkVideoEncodeH264PictureInfoKHR *h264_picture_info = vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H264_PICTURE_INFO_KHR); + const struct VkVideoEncodeH265PictureInfoKHR *h265_picture_info = + vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H265_PICTURE_INFO_KHR); const StdVideoEncodeH264PictureInfo *h264_pic = h264_picture_info ? h264_picture_info->pStdPictureInfo : NULL; + const StdVideoEncodeH265PictureInfo *h265_pic = h265_picture_info ? h265_picture_info->pStdPictureInfo : NULL; struct radv_image_view *src_iv = radv_image_view_from_handle(enc_info->srcPictureResource.imageViewBinding); struct radv_image *src_img = src_iv->image; struct radv_device *device = radv_cmd_buffer_device(cmd_buffer); @@ -997,6 +1322,22 @@ radv_enc_params(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR * pic_type = RENCODE_PICTURE_TYPE_I; break; } + } else if (h265_pic) { + switch (h265_pic->pic_type) { + case STD_VIDEO_H265_PICTURE_TYPE_P: + slot_idx = enc_info->pReferenceSlots[0].slotIndex; + pic_type = RENCODE_PICTURE_TYPE_P; + break; + case STD_VIDEO_H265_PICTURE_TYPE_B: + slot_idx = enc_info->pReferenceSlots[0].slotIndex; + pic_type = RENCODE_PICTURE_TYPE_B; + break; + case STD_VIDEO_H265_PICTURE_TYPE_I: + case STD_VIDEO_H265_PICTURE_TYPE_IDR: + default: + pic_type = RENCODE_PICTURE_TYPE_I; + break; + } } else { assert(0); return; @@ -1111,6 +1452,23 @@ radv_enc_op_preset(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKH struct radv_video_session *vid = cmd_buffer->video.vid; uint32_t preset_mode; + switch (vid->vk.op) { + case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR: { + const struct VkVideoEncodeH265PictureInfoKHR *h265_picture_info = + vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H265_PICTURE_INFO_KHR); + const StdVideoEncodeH265PictureInfo *pic = h265_picture_info->pStdPictureInfo; + const StdVideoH265SequenceParameterSet *sps = + vk_video_find_h265_enc_std_sps(&cmd_buffer->video.params->vk, pic->pps_seq_parameter_set_id); + if (sps->flags.sample_adaptive_offset_enabled_flag && vid->enc_preset_mode == RENCODE_PRESET_MODE_SPEED) { + preset_mode = RENCODE_IB_OP_SET_BALANCE_ENCODING_MODE; + return; + } + break; + } + default: + break; + } + if (vid->enc_preset_mode == RENCODE_PRESET_MODE_QUALITY) preset_mode = RENCODE_IB_OP_SET_QUALITY_ENCODING_MODE; else if (vid->enc_preset_mode == RENCODE_PRESET_MODE_BALANCE) @@ -1163,6 +1521,13 @@ radv_enc_headers_h264(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInf radv_enc_params_h264(cmd_buffer); } +static void +radv_enc_headers_hevc(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info) +{ + radv_enc_slice_header_hevc(cmd_buffer, enc_info); + radv_enc_params(cmd_buffer, enc_info); +} + static void begin(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info) { @@ -1178,6 +1543,10 @@ begin(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info) radv_enc_slice_control(cmd_buffer, enc_info); radv_enc_spec_misc_h264(cmd_buffer, enc_info); radv_enc_deblocking_filter_h264(cmd_buffer, enc_info); + } else if (vid->vk.op == VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR) { + radv_enc_slice_control_hevc(cmd_buffer, enc_info); + radv_enc_spec_misc_hevc(cmd_buffer, enc_info); + radv_enc_deblocking_filter_hevc(cmd_buffer, enc_info); } radv_enc_layer_control(cmd_buffer, &vid->rc_layer_control); radv_enc_rc_session_init(cmd_buffer); @@ -1217,6 +1586,7 @@ radv_vcn_encode_video(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInf switch (vid->vk.op) { case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR: + case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR: break; default: assert(0); @@ -1237,6 +1607,9 @@ radv_vcn_encode_video(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInf if (vid->vk.op == VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR) { radv_enc_headers_h264(cmd_buffer, enc_info); radv_enc_ctx(cmd_buffer, enc_info); + } else if (vid->vk.op == VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR) { + radv_enc_headers_hevc(cmd_buffer, enc_info); + radv_enc_ctx(cmd_buffer, enc_info); } // bitstream radv_enc_bitstream(cmd_buffer, dst_buffer, enc_info->dstBufferOffset); @@ -1301,6 +1674,7 @@ radv_video_enc_control_video_coding(struct radv_cmd_buffer *cmd_buffer, const Vk switch (vid->vk.op) { case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR: + case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR: break; default: unreachable("Unsupported\n"); @@ -1318,6 +1692,8 @@ radv_video_enc_control_video_coding(struct radv_cmd_buffer *cmd_buffer, const Vk } const VkVideoEncodeH264RateControlInfoKHR *h264_rate_control = (VkVideoEncodeH264RateControlInfoKHR *) vk_find_struct_const(rate_control->pNext, VIDEO_ENCODE_H264_RATE_CONTROL_INFO_KHR); + const VkVideoEncodeH265RateControlInfoKHR *h265_rate_control = (VkVideoEncodeH265RateControlInfoKHR *) + vk_find_struct_const(rate_control->pNext, VIDEO_ENCODE_H265_RATE_CONTROL_INFO_KHR); vid->enc_rate_control_method = RENCODE_RATE_CONTROL_METHOD_NONE; vid->enc_rate_control_default = false; @@ -1335,12 +1711,17 @@ radv_video_enc_control_video_coding(struct radv_cmd_buffer *cmd_buffer, const Vk if (h264_rate_control) { vid->rc_layer_control.max_num_temporal_layers = h264_rate_control->temporalLayerCount; vid->rc_layer_control.num_temporal_layers = h264_rate_control->temporalLayerCount; + } else if (h265_rate_control) { + vid->rc_layer_control.max_num_temporal_layers = 1; + vid->rc_layer_control.num_temporal_layers = 1; } for (unsigned l = 0; l < rate_control->layerCount; l++) { const VkVideoEncodeRateControlLayerInfoKHR *layer = &rate_control->pLayers[l]; const VkVideoEncodeH264RateControlLayerInfoKHR *h264_layer = (VkVideoEncodeH264RateControlLayerInfoKHR *) vk_find_struct_const(layer->pNext, VIDEO_ENCODE_H264_RATE_CONTROL_LAYER_INFO_KHR); + const VkVideoEncodeH265RateControlLayerInfoKHR *h265_layer = (VkVideoEncodeH265RateControlLayerInfoKHR *) + vk_find_struct_const(layer->pNext, VIDEO_ENCODE_H265_RATE_CONTROL_LAYER_INFO_KHR); uint32_t frame_rate_den, frame_rate_num; vid->rc_layer_init[l].target_bit_rate = layer->averageBitrate; vid->rc_layer_init[l].peak_bit_rate = layer->maxBitrate; @@ -1361,7 +1742,12 @@ radv_video_enc_control_video_coding(struct radv_cmd_buffer *cmd_buffer, const Vk vid->rc_per_pic[l].min_qp_i = h264_layer->useMinQp ? h264_layer->minQp.qpI : 0; vid->rc_per_pic[l].max_qp_i = h264_layer->useMaxQp ? h264_layer->maxQp.qpI : 51; vid->rc_per_pic[l].max_au_size_i = h264_layer->useMaxFrameSize ? h264_layer->maxFrameSize.frameISize : 0; + } else if (h265_layer) { + vid->rc_per_pic[l].min_qp_i = h265_layer->useMinQp ? h265_layer->minQp.qpI : 0; + vid->rc_per_pic[l].max_qp_i = h265_layer->useMaxQp ? h265_layer->maxQp.qpI : 51; + vid->rc_per_pic[l].max_au_size_i = h265_layer->useMaxFrameSize ? h265_layer->maxFrameSize.frameISize : 0; } + vid->rc_per_pic[l].qp_i = vid->rc_per_pic[l].max_qp_i; vid->rc_per_pic[l].enabled_filler_data = 1; vid->rc_per_pic[l].skip_frame_enable = 0; @@ -1389,6 +1775,19 @@ radv_video_patch_encode_session_parameters(struct vk_video_session_parameters *p { switch (params->op) { case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR: + break; + case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR: { + /* + * AMD firmware requires these flags to be set in h265 with RC modes, + * VCN 3 need 1.27 and VCN 4 needs 1.7 or newer to pass the CTS tests, + * dEQP-VK.video.encode.h265_rc_*. + */ + for (unsigned i = 0; i < params->h265_enc.h265_pps_count; i++) { + params->h265_enc.h265_pps[i].base.flags.cu_qp_delta_enabled_flag = 1; + params->h265_enc.h265_pps[i].base.diff_cu_qp_delta_depth = 0; + } + break; + } default: break; } @@ -1426,6 +1825,28 @@ radv_GetEncodedVideoSessionParametersKHR(VkDevice device, } break; } + case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR: { + const struct VkVideoEncodeH265SessionParametersGetInfoKHR *h265_get_info = + vk_find_struct_const(pVideoSessionParametersInfo->pNext, VIDEO_ENCODE_H265_SESSION_PARAMETERS_GET_INFO_KHR); + if (h265_get_info->writeStdVPS) { + const StdVideoH265VideoParameterSet *vps = vk_video_find_h265_enc_std_vps(&templ->vk, h265_get_info->stdVPSId); + assert(vps); + vk_video_encode_h265_vps(vps, size_limit, &total_size, pData); + } + if (h265_get_info->writeStdSPS) { + const StdVideoH265SequenceParameterSet *sps = + vk_video_find_h265_enc_std_sps(&templ->vk, h265_get_info->stdSPSId); + assert(sps); + vk_video_encode_h265_sps(sps, size_limit, &total_size, pData); + } + if (h265_get_info->writeStdPPS) { + const StdVideoH265PictureParameterSet *pps = + vk_video_find_h265_enc_std_pps(&templ->vk, h265_get_info->stdPPSId); + assert(pps); + vk_video_encode_h265_pps(pps, size_limit, &total_size, pData); + } + break; + } default: break; }