/************************************************************************** * * Copyright 2017 Advanced Micro Devices, Inc. * Copyright 2023 Red Hat Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * **************************************************************************/ #include "radv_buffer.h" #include "radv_cs.h" #include "radv_debug.h" #include "radv_device_memory.h" #include "radv_entrypoints.h" #include "radv_image_view.h" #include "radv_physical_device.h" #include "radv_query.h" #include "radv_video.h" #include "ac_vcn_enc.h" #define RENCODE_V4_FW_INTERFACE_MAJOR_VERSION 1 #define RENCODE_V4_FW_INTERFACE_MINOR_VERSION 7 #define RENCODE_V4_IB_PARAM_ENCODE_STATISTICS 0x0000001a #define RENCODE_V3_FW_INTERFACE_MAJOR_VERSION 1 #define RENCODE_V3_FW_INTERFACE_MINOR_VERSION 27 #define RENCODE_V2_IB_PARAM_SESSION_INFO 0x00000001 #define RENCODE_V2_IB_PARAM_TASK_INFO 0x00000002 #define RENCODE_V2_IB_PARAM_SESSION_INIT 0x00000003 #define RENCODE_V2_IB_PARAM_LAYER_CONTROL 0x00000004 #define RENCODE_V2_IB_PARAM_LAYER_SELECT 0x00000005 #define RENCODE_V2_IB_PARAM_RATE_CONTROL_SESSION_INIT 0x00000006 #define RENCODE_V2_IB_PARAM_RATE_CONTROL_LAYER_INIT 0x00000007 #define RENCODE_V2_IB_PARAM_RATE_CONTROL_PER_PICTURE 0x00000008 #define RENCODE_V2_IB_PARAM_QUALITY_PARAMS 0x00000009 #define RENCODE_V2_IB_PARAM_DIRECT_OUTPUT_NALU 0x0000000a #define RENCODE_V2_IB_PARAM_SLICE_HEADER 0x0000000b #define RENCODE_V2_IB_PARAM_INPUT_FORMAT 0x0000000c #define RENCODE_V2_IB_PARAM_OUTPUT_FORMAT 0x0000000d #define RENCODE_V2_IB_PARAM_ENCODE_PARAMS 0x0000000f #define RENCODE_V2_IB_PARAM_INTRA_REFRESH 0x00000010 #define RENCODE_V2_IB_PARAM_ENCODE_CONTEXT_BUFFER 0x00000011 #define RENCODE_V2_IB_PARAM_VIDEO_BITSTREAM_BUFFER 0x00000012 #define RENCODE_V2_IB_PARAM_FEEDBACK_BUFFER 0x00000015 #define RENCODE_V2_IB_PARAM_ENCODE_STATISTICS 0x00000019 #define RENCODE_V2_IB_PARAM_RATE_CONTROL_PER_PIC_EX 0x0000001d #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 #define RENCODE_V2_H264_IB_PARAM_DEBLOCKING_FILTER 0x00200004 #define RENCODE_V2_FW_INTERFACE_MAJOR_VERSION 1 #define RENCODE_V2_FW_INTERFACE_MINOR_VERSION 18 #define RENCODE_IB_PARAM_SESSION_INFO 0x00000001 #define RENCODE_IB_PARAM_TASK_INFO 0x00000002 #define RENCODE_IB_PARAM_SESSION_INIT 0x00000003 #define RENCODE_IB_PARAM_LAYER_CONTROL 0x00000004 #define RENCODE_IB_PARAM_LAYER_SELECT 0x00000005 #define RENCODE_IB_PARAM_RATE_CONTROL_SESSION_INIT 0x00000006 #define RENCODE_IB_PARAM_RATE_CONTROL_LAYER_INIT 0x00000007 #define RENCODE_IB_PARAM_RATE_CONTROL_PER_PICTURE 0x00000008 #define RENCODE_IB_PARAM_QUALITY_PARAMS 0x00000009 #define RENCODE_IB_PARAM_SLICE_HEADER 0x0000000a #define RENCODE_IB_PARAM_ENCODE_PARAMS 0x0000000b #define RENCODE_IB_PARAM_INTRA_REFRESH 0x0000000c #define RENCODE_IB_PARAM_ENCODE_CONTEXT_BUFFER 0x0000000d #define RENCODE_IB_PARAM_VIDEO_BITSTREAM_BUFFER 0x0000000e #define RENCODE_IB_PARAM_FEEDBACK_BUFFER 0x00000010 #define RENCODE_IB_PARAM_RATE_CONTROL_PER_PIC_EX 0x0000001d #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 #define RENCODE_H264_IB_PARAM_DEBLOCKING_FILTER 0x00200004 #define RENCODE_FW_INTERFACE_MAJOR_VERSION 1 #define RENCODE_FW_INTERFACE_MINOR_VERSION 15 void radv_probe_video_encode(struct radv_physical_device *pdev) { pdev->video_encode_enabled = false; if (pdev->info.vcn_ip_version >= VCN_4_0_0) { if (pdev->info.vcn_enc_major_version != RENCODE_V4_FW_INTERFACE_MAJOR_VERSION) return; if (pdev->info.vcn_enc_minor_version < RENCODE_V4_FW_INTERFACE_MINOR_VERSION) return; /* VCN 4 FW 1.22 has all the necessary pieces to pass CTS */ if (pdev->info.vcn_enc_minor_version >= 22) { pdev->video_encode_enabled = true; return; } } else if (pdev->info.vcn_ip_version >= VCN_3_0_0) { if (pdev->info.vcn_enc_major_version != RENCODE_V3_FW_INTERFACE_MAJOR_VERSION) return; if (pdev->info.vcn_enc_minor_version < RENCODE_V3_FW_INTERFACE_MINOR_VERSION) return; } else if (pdev->info.vcn_ip_version >= VCN_2_0_0) { if (pdev->info.vcn_enc_major_version != RENCODE_V2_FW_INTERFACE_MAJOR_VERSION) return; if (pdev->info.vcn_enc_minor_version < RENCODE_V2_FW_INTERFACE_MINOR_VERSION) return; } else { if (pdev->info.vcn_enc_major_version != RENCODE_FW_INTERFACE_MAJOR_VERSION) return; if (pdev->info.vcn_enc_minor_version < RENCODE_FW_INTERFACE_MINOR_VERSION) return; } struct radv_instance *instance = radv_physical_device_instance(pdev); pdev->video_encode_enabled = !!(instance->perftest_flags & RADV_PERFTEST_VIDEO_ENCODE); } void radv_init_physical_device_encoder(struct radv_physical_device *pdev) { if (pdev->info.vcn_ip_version >= VCN_4_0_0) { pdev->enc_hw_ver = RADV_VIDEO_ENC_HW_4; pdev->encoder_interface_version = ((RENCODE_V4_FW_INTERFACE_MAJOR_VERSION << RENCODE_IF_MAJOR_VERSION_SHIFT) | (RENCODE_V4_FW_INTERFACE_MINOR_VERSION << RENCODE_IF_MINOR_VERSION_SHIFT)); } else if (pdev->info.vcn_ip_version >= VCN_3_0_0) { pdev->enc_hw_ver = RADV_VIDEO_ENC_HW_3; pdev->encoder_interface_version = ((RENCODE_V3_FW_INTERFACE_MAJOR_VERSION << RENCODE_IF_MAJOR_VERSION_SHIFT) | (RENCODE_V3_FW_INTERFACE_MINOR_VERSION << RENCODE_IF_MINOR_VERSION_SHIFT)); } else if (pdev->info.vcn_ip_version >= VCN_2_0_0) { pdev->enc_hw_ver = RADV_VIDEO_ENC_HW_2; pdev->encoder_interface_version = ((RENCODE_V2_FW_INTERFACE_MAJOR_VERSION << RENCODE_IF_MAJOR_VERSION_SHIFT) | (RENCODE_V2_FW_INTERFACE_MINOR_VERSION << RENCODE_IF_MINOR_VERSION_SHIFT)); } else { pdev->enc_hw_ver = RADV_VIDEO_ENC_HW_1_2; pdev->encoder_interface_version = ((RENCODE_FW_INTERFACE_MAJOR_VERSION << RENCODE_IF_MAJOR_VERSION_SHIFT) | (RENCODE_FW_INTERFACE_MINOR_VERSION << RENCODE_IF_MINOR_VERSION_SHIFT)); } if (pdev->info.vcn_ip_version >= VCN_2_0_0) { pdev->vcn_enc_cmds.session_info = RENCODE_V2_IB_PARAM_SESSION_INFO; pdev->vcn_enc_cmds.task_info = RENCODE_V2_IB_PARAM_TASK_INFO; pdev->vcn_enc_cmds.session_init = RENCODE_V2_IB_PARAM_SESSION_INIT; pdev->vcn_enc_cmds.layer_control = RENCODE_V2_IB_PARAM_LAYER_CONTROL; pdev->vcn_enc_cmds.layer_select = RENCODE_V2_IB_PARAM_LAYER_SELECT; pdev->vcn_enc_cmds.rc_session_init = RENCODE_V2_IB_PARAM_RATE_CONTROL_SESSION_INIT; pdev->vcn_enc_cmds.rc_layer_init = RENCODE_V2_IB_PARAM_RATE_CONTROL_LAYER_INIT; pdev->vcn_enc_cmds.rc_per_pic = RENCODE_V2_IB_PARAM_RATE_CONTROL_PER_PIC_EX; pdev->vcn_enc_cmds.quality_params = RENCODE_V2_IB_PARAM_QUALITY_PARAMS; pdev->vcn_enc_cmds.nalu = RENCODE_V2_IB_PARAM_DIRECT_OUTPUT_NALU; pdev->vcn_enc_cmds.slice_header = RENCODE_V2_IB_PARAM_SLICE_HEADER; pdev->vcn_enc_cmds.input_format = RENCODE_V2_IB_PARAM_INPUT_FORMAT; pdev->vcn_enc_cmds.output_format = RENCODE_V2_IB_PARAM_OUTPUT_FORMAT; pdev->vcn_enc_cmds.enc_params = RENCODE_V2_IB_PARAM_ENCODE_PARAMS; pdev->vcn_enc_cmds.intra_refresh = RENCODE_V2_IB_PARAM_INTRA_REFRESH; 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; pdev->vcn_enc_cmds.deblocking_filter_h264 = RENCODE_V2_H264_IB_PARAM_DEBLOCKING_FILTER; if (pdev->enc_hw_ver == RADV_VIDEO_ENC_HW_4) { pdev->vcn_enc_cmds.enc_statistics = RENCODE_V4_IB_PARAM_ENCODE_STATISTICS; } else pdev->vcn_enc_cmds.enc_statistics = RENCODE_V2_IB_PARAM_ENCODE_STATISTICS; } else { pdev->vcn_enc_cmds.session_info = RENCODE_IB_PARAM_SESSION_INFO; pdev->vcn_enc_cmds.task_info = RENCODE_IB_PARAM_TASK_INFO; pdev->vcn_enc_cmds.session_init = RENCODE_IB_PARAM_SESSION_INIT; pdev->vcn_enc_cmds.layer_control = RENCODE_IB_PARAM_LAYER_CONTROL; pdev->vcn_enc_cmds.layer_select = RENCODE_IB_PARAM_LAYER_SELECT; pdev->vcn_enc_cmds.rc_session_init = RENCODE_IB_PARAM_RATE_CONTROL_SESSION_INIT; pdev->vcn_enc_cmds.rc_layer_init = RENCODE_IB_PARAM_RATE_CONTROL_LAYER_INIT; pdev->vcn_enc_cmds.rc_per_pic = RENCODE_IB_PARAM_RATE_CONTROL_PER_PIC_EX; pdev->vcn_enc_cmds.quality_params = RENCODE_IB_PARAM_QUALITY_PARAMS; pdev->vcn_enc_cmds.nalu = RENCODE_IB_PARAM_DIRECT_OUTPUT_NALU; pdev->vcn_enc_cmds.slice_header = RENCODE_IB_PARAM_SLICE_HEADER; pdev->vcn_enc_cmds.enc_params = RENCODE_IB_PARAM_ENCODE_PARAMS; pdev->vcn_enc_cmds.intra_refresh = RENCODE_IB_PARAM_INTRA_REFRESH; 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; pdev->vcn_enc_cmds.deblocking_filter_h264 = RENCODE_H264_IB_PARAM_DEBLOCKING_FILTER; pdev->vcn_enc_cmds.enc_statistics = RENCODE_IB_PARAM_ENCODE_STATISTICS; } } /* to process invalid frame rate */ static void radv_vcn_enc_invalid_frame_rate(uint32_t *den, uint32_t *num) { if (*den == 0 || *num == 0) { *den = 1; *num = 30; } } static uint32_t radv_vcn_per_frame_integer(uint32_t bitrate, uint32_t den, uint32_t num) { uint64_t rate_den = (uint64_t)bitrate * (uint64_t)den; return (uint32_t)(rate_den / num); } static uint32_t radv_vcn_per_frame_frac(uint32_t bitrate, uint32_t den, uint32_t num) { uint64_t rate_den = (uint64_t)bitrate * (uint64_t)den; uint64_t remainder = rate_den % num; return (uint32_t)((remainder << 32) / num); } static void radv_enc_set_emulation_prevention(struct radv_cmd_buffer *cmd_buffer, bool set) { struct radv_enc_state *enc = &cmd_buffer->video.enc; if (set != enc->emulation_prevention) { enc->emulation_prevention = set; enc->num_zeros = 0; } } static uint32_t radv_enc_value_bits(uint32_t value) { uint32_t i = 1; while (value > 1) { i++; value >>= 1; } return i; } static const unsigned index_to_shifts[4] = {24, 16, 8, 0}; static void radv_enc_output_one_byte(struct radv_cmd_buffer *cmd_buffer, unsigned char byte) { struct radeon_cmdbuf *cs = cmd_buffer->cs; struct radv_enc_state *enc = &cmd_buffer->video.enc; if (enc->byte_index == 0) cs->buf[cs->cdw] = 0; cs->buf[cs->cdw] |= ((unsigned int)(byte) << index_to_shifts[enc->byte_index]); enc->byte_index++; if (enc->byte_index >= 4) { enc->byte_index = 0; cs->cdw++; } } static void radv_enc_emulation_prevention(struct radv_cmd_buffer *cmd_buffer, unsigned char byte) { struct radv_enc_state *enc = &cmd_buffer->video.enc; if (enc->emulation_prevention) { if ((enc->num_zeros >= 2) && ((byte == 0x00) || (byte == 0x01) || (byte == 0x02) || (byte == 0x03))) { radv_enc_output_one_byte(cmd_buffer, 0x03); enc->bits_output += 8; enc->num_zeros = 0; } enc->num_zeros = (byte == 0 ? (enc->num_zeros + 1) : 0); } } static void radv_enc_code_fixed_bits(struct radv_cmd_buffer *cmd_buffer, unsigned int value, unsigned int num_bits) { struct radv_enc_state *enc = &cmd_buffer->video.enc; unsigned int bits_to_pack = 0; enc->bits_size += num_bits; while (num_bits > 0) { unsigned int value_to_pack = value & (0xffffffff >> (32 - num_bits)); bits_to_pack = num_bits > (32 - enc->bits_in_shifter) ? (32 - enc->bits_in_shifter) : num_bits; if (bits_to_pack < num_bits) value_to_pack = value_to_pack >> (num_bits - bits_to_pack); enc->shifter |= value_to_pack << (32 - enc->bits_in_shifter - bits_to_pack); num_bits -= bits_to_pack; enc->bits_in_shifter += bits_to_pack; while (enc->bits_in_shifter >= 8) { unsigned char output_byte = (unsigned char)(enc->shifter >> 24); enc->shifter <<= 8; radv_enc_emulation_prevention(cmd_buffer, output_byte); radv_enc_output_one_byte(cmd_buffer, output_byte); enc->bits_in_shifter -= 8; enc->bits_output += 8; } } } static void radv_enc_reset(struct radv_cmd_buffer *cmd_buffer) { struct radv_enc_state *enc = &cmd_buffer->video.enc; enc->emulation_prevention = false; enc->shifter = 0; enc->bits_in_shifter = 0; enc->bits_output = 0; enc->num_zeros = 0; enc->byte_index = 0; enc->bits_size = 0; } static void radv_enc_byte_align(struct radv_cmd_buffer *cmd_buffer) { struct radv_enc_state *enc = &cmd_buffer->video.enc; unsigned int num_padding_zeros = (32 - enc->bits_in_shifter) % 8; if (num_padding_zeros > 0) radv_enc_code_fixed_bits(cmd_buffer, 0, num_padding_zeros); } static void radv_enc_flush_headers(struct radv_cmd_buffer *cmd_buffer) { struct radv_enc_state *enc = &cmd_buffer->video.enc; struct radeon_cmdbuf *cs = cmd_buffer->cs; if (enc->bits_in_shifter != 0) { unsigned char output_byte = (unsigned char)(enc->shifter >> 24); radv_enc_emulation_prevention(cmd_buffer, output_byte); radv_enc_output_one_byte(cmd_buffer, output_byte); enc->bits_output += enc->bits_in_shifter; enc->shifter = 0; enc->bits_in_shifter = 0; enc->num_zeros = 0; } if (enc->byte_index > 0) { cs->cdw++; enc->byte_index = 0; } } static void radv_enc_code_ue(struct radv_cmd_buffer *cmd_buffer, unsigned int value) { unsigned int x = 0; unsigned int ue_code = value + 1; value += 1; while (value) { value = (value >> 1); x += 1; } if (x > 1) radv_enc_code_fixed_bits(cmd_buffer, 0, x - 1); radv_enc_code_fixed_bits(cmd_buffer, ue_code, x); } static void radv_enc_code_se(struct radv_cmd_buffer *cmd_buffer, int value) { unsigned int v = 0; if (value != 0) v = (value < 0 ? ((unsigned int)(0 - value) << 1) : (((unsigned int)(value) << 1) - 1)); radv_enc_code_ue(cmd_buffer, v); } #define ENC_BEGIN \ { \ uint32_t begin = cs->cdw++; #define ENC_END \ radeon_emit_direct(cs, begin, (cs->cdw - begin) * 4); \ cmd_buffer->video.enc.total_task_size += cs->buf[begin]; \ } static void radv_enc_session_info(struct radv_cmd_buffer *cmd_buffer) { 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; ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.session_info); radeon_emit(cs, pdev->encoder_interface_version); radv_cs_add_buffer(device->ws, cs, cmd_buffer->video.vid->sessionctx.mem->bo); uint64_t va = radv_buffer_get_va(cmd_buffer->video.vid->sessionctx.mem->bo); va += cmd_buffer->video.vid->sessionctx.offset; radeon_emit(cs, va >> 32); radeon_emit(cs, va & 0xffffffff); radeon_emit(cs, RENCODE_ENGINE_TYPE_ENCODE); ENC_END; } static void radv_enc_task_info(struct radv_cmd_buffer *cmd_buffer, bool feedback) { 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; struct radv_enc_state *enc = &cmd_buffer->video.enc; enc->task_id++; ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.task_info); enc->task_size_offset = cs->cdw++; radeon_emit(cs, enc->task_id); radeon_emit(cs, feedback ? 1 : 0); ENC_END; } static void radv_enc_session_init(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 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; uint32_t aligned_picture_width = align(w, alignment); uint32_t aligned_picture_height = align(h, alignment); uint32_t padding_width = aligned_picture_width - w; uint32_t padding_height = aligned_picture_height - h; ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.session_init); radeon_emit(cs, vid->enc_session.encode_standard); radeon_emit(cs, aligned_picture_width); radeon_emit(cs, aligned_picture_height); radeon_emit(cs, padding_width); radeon_emit(cs, padding_height); radeon_emit(cs, vid->enc_session.pre_encode_mode); radeon_emit(cs, vid->enc_session.pre_encode_chroma_enabled); if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_3) { radeon_emit(cs, 0); // slice output enabled. } radeon_emit(cs, vid->enc_session.display_remote); ENC_END; } static void radv_enc_layer_control(struct radv_cmd_buffer *cmd_buffer, const rvcn_enc_layer_control_t *rc_layer_control) { 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; ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.layer_control); radeon_emit(cs, rc_layer_control->max_num_temporal_layers); // max num temporal layesr radeon_emit(cs, rc_layer_control->num_temporal_layers); // num temporal layers ENC_END; } static void radv_enc_layer_select(struct radv_cmd_buffer *cmd_buffer, int tl_idx) { 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; ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.layer_select); radeon_emit(cs, tl_idx); // temporal layer index ENC_END; } static void radv_enc_slice_control(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; uint32_t num_mbs_in_slice; uint32_t width_in_mbs = enc_info->srcPictureResource.codedExtent.width / 16; uint32_t height_in_mbs = enc_info->srcPictureResource.codedExtent.height / 16; num_mbs_in_slice = width_in_mbs * height_in_mbs; ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.slice_control_h264); radeon_emit(cs, RENCODE_H264_SLICE_CONTROL_MODE_FIXED_MBS); // slice control mode radeon_emit(cs, num_mbs_in_slice); // num mbs per slice ENC_END; } static void radv_enc_spec_misc_h264(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 VkVideoEncodeH264PictureInfoKHR *h264_picture_info = vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H264_PICTURE_INFO_KHR); const StdVideoEncodeH264PictureInfo *pic = h264_picture_info->pStdPictureInfo; const StdVideoH264SequenceParameterSet *sps = vk_video_find_h264_enc_std_sps(&cmd_buffer->video.params->vk, pic->seq_parameter_set_id); const StdVideoH264PictureParameterSet *pps = vk_video_find_h264_enc_std_pps(&cmd_buffer->video.params->vk, pic->pic_parameter_set_id); ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.spec_misc_h264); radeon_emit(cs, pps->flags.constrained_intra_pred_flag); // constrained_intra_pred_flag radeon_emit(cs, pps->flags.entropy_coding_mode_flag); // cabac enable radeon_emit(cs, 0); // cabac init idc radeon_emit(cs, 1); // half pel enabled radeon_emit(cs, 1); // quarter pel enabled radeon_emit(cs, cmd_buffer->video.vid->vk.h264.profile_idc); // profile_idc radeon_emit(cs, vk_video_get_h264_level(sps->level_idc)); if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_3) { radeon_emit(cs, 0); // v3 b_picture_enabled radeon_emit(cs, pps->weighted_bipred_idc); // v3 weighted bipred idc } 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) { 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; struct radv_video_session *vid = cmd_buffer->video.vid; ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.rc_session_init); radeon_emit(cs, vid->enc_rate_control_method); // rate_control_method); radeon_emit(cs, vid->enc_vbv_buffer_level); // vbv_buffer_level); ENC_END; } static void radv_enc_rc_layer_init(struct radv_cmd_buffer *cmd_buffer, rvcn_enc_rate_ctl_layer_init_t *layer_init) { 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; ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.rc_layer_init); radeon_emit(cs, layer_init->target_bit_rate); // target bit rate radeon_emit(cs, layer_init->peak_bit_rate); // peak bit rate radeon_emit(cs, layer_init->frame_rate_num); // frame rate num radeon_emit(cs, layer_init->frame_rate_den); // frame rate dem radeon_emit(cs, layer_init->vbv_buffer_size); // vbv buffer size radeon_emit(cs, layer_init->avg_target_bits_per_picture); // avg target bits per picture radeon_emit(cs, layer_init->peak_bits_per_picture_integer); // peak bit per picture int radeon_emit(cs, layer_init->peak_bits_per_picture_fractional); // peak bit per picture fract ENC_END; } static void radv_enc_deblocking_filter_h264(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 VkVideoEncodeH264PictureInfoKHR *h264_picture_info = vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H264_PICTURE_INFO_KHR); const VkVideoEncodeH264NaluSliceInfoKHR *h264_slice = &h264_picture_info->pNaluSliceEntries[0]; const StdVideoEncodeH264SliceHeader *slice = h264_slice->pStdSliceHeader; ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.deblocking_filter_h264); radeon_emit(cs, slice->disable_deblocking_filter_idc); radeon_emit(cs, slice->slice_alpha_c0_offset_div2); radeon_emit(cs, slice->slice_beta_offset_div2); radeon_emit(cs, 0); // cb qp offset radeon_emit(cs, 0); // cr qp offset 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) { 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; ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.quality_params); radeon_emit(cs, 0); radeon_emit(cs, 0); radeon_emit(cs, 0); radeon_emit(cs, 0); if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_2) radeon_emit(cs, 0); ENC_END; } static void radv_enc_slice_header(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 VkVideoEncodeH264PictureInfoKHR *h264_picture_info = vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H264_PICTURE_INFO_KHR); int slice_count = h264_picture_info->naluSliceEntryCount; const StdVideoEncodeH264PictureInfo *pic = h264_picture_info->pStdPictureInfo; const StdVideoH264SequenceParameterSet *sps = vk_video_find_h264_enc_std_sps(&cmd_buffer->video.params->vk, pic->seq_parameter_set_id); const StdVideoH264PictureParameterSet *pps = vk_video_find_h264_enc_std_pps(&cmd_buffer->video.params->vk, pic->pic_parameter_set_id); const VkVideoEncodeH264NaluSliceInfoKHR *slice_info = &h264_picture_info->pNaluSliceEntries[0]; unsigned int inst_index = 0; unsigned int cdw_start = 0; unsigned int cdw_filled = 0; unsigned int bits_copied = 0; assert(slice_count <= 1); 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; 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; if (pic->flags.IdrPicFlag) radv_enc_code_fixed_bits(cmd_buffer, 0x65, 8); else if (!pic->flags.is_reference) radv_enc_code_fixed_bits(cmd_buffer, 0x01, 8); else radv_enc_code_fixed_bits(cmd_buffer, 0x41, 8); 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_H264_HEADER_INSTRUCTION_FIRST_MB; inst_index++; switch (pic->primary_pic_type) { case STD_VIDEO_H264_PICTURE_TYPE_I: case STD_VIDEO_H264_PICTURE_TYPE_IDR: default: radv_enc_code_ue(cmd_buffer, 7); break; case STD_VIDEO_H264_PICTURE_TYPE_P: radv_enc_code_ue(cmd_buffer, 5); break; case STD_VIDEO_H264_PICTURE_TYPE_B: radv_enc_code_ue(cmd_buffer, 6); break; } radv_enc_code_ue(cmd_buffer, 0x0); unsigned int max_frame_num_bits = sps->log2_max_frame_num_minus4 + 4; radv_enc_code_fixed_bits(cmd_buffer, pic->frame_num % (1 << max_frame_num_bits), max_frame_num_bits); #if 0 if (enc->enc_pic.h264_enc_params.input_picture_structure != RENCODE_H264_PICTURE_STRUCTURE_FRAME) { radv_enc_code_fixed_bits(cmd_buffer, 0x1, 1); radv_enc_code_fixed_bits(cmd_buffer, enc->enc_pic.h264_enc_params.input_picture_structure == RENCODE_H264_PICTURE_STRUCTURE_BOTTOM_FIELD ? 1 : 0, 1); } #endif if (pic->flags.IdrPicFlag) radv_enc_code_ue(cmd_buffer, pic->idr_pic_id); if (sps->pic_order_cnt_type == STD_VIDEO_H264_POC_TYPE_0) { unsigned int max_poc_bits = sps->log2_max_pic_order_cnt_lsb_minus4 + 4; radv_enc_code_fixed_bits(cmd_buffer, pic->PicOrderCnt % (1 << max_poc_bits), max_poc_bits); } if (pps->flags.redundant_pic_cnt_present_flag) radv_enc_code_ue(cmd_buffer, 0); if (pic->primary_pic_type == STD_VIDEO_H264_PICTURE_TYPE_B) { radv_enc_code_fixed_bits(cmd_buffer, slice_info->pStdSliceHeader->flags.direct_spatial_mv_pred_flag, 1); } const StdVideoEncodeH264ReferenceListsInfo *ref_lists = pic->pRefLists; /* ref_pic_list_modification() */ if (pic->primary_pic_type != STD_VIDEO_H264_PICTURE_TYPE_IDR && pic->primary_pic_type != STD_VIDEO_H264_PICTURE_TYPE_I) { /* num ref idx active override flag */ radv_enc_code_fixed_bits(cmd_buffer, slice_info->pStdSliceHeader->flags.num_ref_idx_active_override_flag, 1); if (slice_info->pStdSliceHeader->flags.num_ref_idx_active_override_flag) { radv_enc_code_ue(cmd_buffer, ref_lists->num_ref_idx_l0_active_minus1); if (pic->primary_pic_type == STD_VIDEO_H264_PICTURE_TYPE_B) radv_enc_code_ue(cmd_buffer, ref_lists->num_ref_idx_l1_active_minus1); } radv_enc_code_fixed_bits(cmd_buffer, ref_lists->flags.ref_pic_list_modification_flag_l0, 1); if (ref_lists->flags.ref_pic_list_modification_flag_l0) { for (unsigned op = 0; op < ref_lists->refList0ModOpCount; op++) { const StdVideoEncodeH264RefListModEntry *entry = &ref_lists->pRefList0ModOperations[op]; radv_enc_code_ue(cmd_buffer, entry->modification_of_pic_nums_idc); if (entry->modification_of_pic_nums_idc == STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_SHORT_TERM_SUBTRACT || entry->modification_of_pic_nums_idc == STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_SHORT_TERM_ADD) radv_enc_code_ue(cmd_buffer, entry->abs_diff_pic_num_minus1); else if (entry->modification_of_pic_nums_idc == STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_LONG_TERM) radv_enc_code_ue(cmd_buffer, entry->long_term_pic_num); } } if (pic->primary_pic_type == STD_VIDEO_H264_PICTURE_TYPE_B) { radv_enc_code_fixed_bits(cmd_buffer, ref_lists->flags.ref_pic_list_modification_flag_l1, 1); if (ref_lists->flags.ref_pic_list_modification_flag_l1) { for (unsigned op = 0; op < ref_lists->refList1ModOpCount; op++) { const StdVideoEncodeH264RefListModEntry *entry = &ref_lists->pRefList1ModOperations[op]; radv_enc_code_ue(cmd_buffer, entry->modification_of_pic_nums_idc); if (entry->modification_of_pic_nums_idc == STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_SHORT_TERM_SUBTRACT || entry->modification_of_pic_nums_idc == STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_SHORT_TERM_ADD) radv_enc_code_ue(cmd_buffer, entry->abs_diff_pic_num_minus1); else if (entry->modification_of_pic_nums_idc == STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_LONG_TERM) radv_enc_code_ue(cmd_buffer, entry->long_term_pic_num); } } } } if (pic->flags.IdrPicFlag) { radv_enc_code_fixed_bits(cmd_buffer, 0x0, 1); radv_enc_code_fixed_bits(cmd_buffer, pic->flags.long_term_reference_flag, 1); /* long_term_reference_flag */ } else if (pic->flags.is_reference) { radv_enc_code_fixed_bits(cmd_buffer, ref_lists->refPicMarkingOpCount > 0 ? 1 : 0, 1); for (unsigned op = 0; op < ref_lists->refPicMarkingOpCount; op++) { const StdVideoEncodeH264RefPicMarkingEntry *entry = &ref_lists->pRefPicMarkingOperations[op]; radv_enc_code_ue(cmd_buffer, entry->memory_management_control_operation); if (entry->memory_management_control_operation == STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_UNMARK_SHORT_TERM || entry->memory_management_control_operation == STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_MARK_LONG_TERM) radv_enc_code_ue(cmd_buffer, entry->difference_of_pic_nums_minus1); if (entry->memory_management_control_operation == STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_UNMARK_LONG_TERM) radv_enc_code_ue(cmd_buffer, entry->long_term_pic_num); if (entry->memory_management_control_operation == STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_MARK_LONG_TERM || entry->memory_management_control_operation == STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_MARK_CURRENT_AS_LONG_TERM) radv_enc_code_ue(cmd_buffer, entry->long_term_frame_idx); if (entry->memory_management_control_operation == STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_SET_MAX_LONG_TERM_INDEX) radv_enc_code_ue(cmd_buffer, entry->max_long_term_frame_idx_plus1); if (entry->memory_management_control_operation == STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_END) break; } } if (pic->primary_pic_type != STD_VIDEO_H264_PICTURE_TYPE_IDR && pic->primary_pic_type != STD_VIDEO_H264_PICTURE_TYPE_I && pps->flags.entropy_coding_mode_flag) radv_enc_code_ue(cmd_buffer, slice_info->pStdSliceHeader->cabac_init_idc); 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_H264_HEADER_INSTRUCTION_SLICE_QP_DELTA; inst_index++; if (pps->flags.deblocking_filter_control_present_flag) { radv_enc_code_ue(cmd_buffer, slice_info->pStdSliceHeader->disable_deblocking_filter_idc); if (!slice_info->pStdSliceHeader->disable_deblocking_filter_idc) { radv_enc_code_se(cmd_buffer, slice_info->pStdSliceHeader->slice_alpha_c0_offset_div2); radv_enc_code_se(cmd_buffer, slice_info->pStdSliceHeader->slice_beta_offset_div2); } } 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_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); 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 */ unsigned int max_poc_bits = sps->log2_max_pic_order_cnt_lsb_minus4 + 4; radv_enc_code_fixed_bits(cmd_buffer, pic->PicOrderCntVal % (1 << max_poc_bits), max_poc_bits); 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) { 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; struct radv_image_view *dpb_iv = NULL; struct radv_image *dpb = NULL; struct radv_image_plane *dpb_luma = NULL; struct radv_image_plane *dpb_chroma = NULL; uint64_t va = 0; uint32_t luma_pitch = 0; int max_ref_slot_idx = 0; if (info->pSetupReferenceSlot) { dpb_iv = radv_image_view_from_handle(info->pSetupReferenceSlot->pPictureResource->imageViewBinding); if (info->pSetupReferenceSlot->slotIndex > max_ref_slot_idx) max_ref_slot_idx = info->pSetupReferenceSlot->slotIndex; } if (info->referenceSlotCount > 0) { dpb_iv = radv_image_view_from_handle(info->pReferenceSlots[0].pPictureResource->imageViewBinding); for (unsigned i = 0; i < info->referenceSlotCount; i++) { if (info->pReferenceSlots[i].slotIndex > max_ref_slot_idx) max_ref_slot_idx = info->pReferenceSlots[i].slotIndex; } } if (dpb_iv) { dpb = dpb_iv->image; dpb_luma = &dpb->planes[0]; dpb_chroma = &dpb->planes[1]; radv_cs_add_buffer(device->ws, cs, dpb->bindings[0].bo); va = radv_buffer_get_va(dpb->bindings[0].bo) + dpb->bindings[0].offset; // TODO DPB resource luma_pitch = dpb_luma->surface.u.gfx9.surf_pitch * dpb_luma->surface.blk_w; // rec_luma_pitch } uint32_t swizzle_mode = 0; if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_4) swizzle_mode = RENCODE_REC_SWIZZLE_MODE_256B_D; else if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_2) swizzle_mode = RENCODE_REC_SWIZZLE_MODE_256B_S; ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.ctx); radeon_emit(cs, va >> 32); radeon_emit(cs, va & 0xffffffff); radeon_emit(cs, swizzle_mode); radeon_emit(cs, luma_pitch); // rec_luma_pitch radeon_emit(cs, luma_pitch); // rec_luma_pitch0); //rec_chromma_pitch radeon_emit(cs, max_ref_slot_idx + 1); // num_reconstructed_pictures int i; for (i = 0; i < max_ref_slot_idx + 1; i++) { radeon_emit(cs, dpb_luma ? dpb_luma->surface.u.gfx9.surf_offset + i * dpb_luma->surface.u.gfx9.surf_slice_size : 0); // luma offset radeon_emit(cs, dpb_chroma ? dpb_chroma->surface.u.gfx9.surf_offset + i * dpb_chroma->surface.u.gfx9.surf_slice_size : 0); // chroma offset if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_4) { radeon_emit(cs, 0); /* unused offset 1 */ radeon_emit(cs, 0); /* unused offset 2 */ } } for (; i < RENCODE_MAX_NUM_RECONSTRUCTED_PICTURES; i++) { radeon_emit(cs, 0); radeon_emit(cs, 0); if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_4) { radeon_emit(cs, 0); /* unused offset 1 */ radeon_emit(cs, 0); /* unused offset 2 */ } } if (pdev->enc_hw_ver == RADV_VIDEO_ENC_HW_3) { radeon_emit(cs, 0); // colloc buffer offset } radeon_emit(cs, 0); // enc pic pre encode luma pitch radeon_emit(cs, 0); // enc pic pre encode chroma pitch for (i = 0; i < RENCODE_MAX_NUM_RECONSTRUCTED_PICTURES; i++) { radeon_emit(cs, 0); // pre encode luma offset radeon_emit(cs, 0); // pre encode chroma offset if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_4) { radeon_emit(cs, 0); /* unused offset 1 */ radeon_emit(cs, 0); /* unused offset 2 */ } } if (pdev->enc_hw_ver == RADV_VIDEO_ENC_HW_2) { radeon_emit(cs, 0); // enc pic yuv luma offset radeon_emit(cs, 0); // enc pic yuv chroma offset radeon_emit(cs, 0); // two pass search center map offset // rgboffsets radeon_emit(cs, 0); // red radeon_emit(cs, 0); // green radeon_emit(cs, 0); // blue } else if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_3) { radeon_emit(cs, 0); // red radeon_emit(cs, 0); // green radeon_emit(cs, 0); // blue radeon_emit(cs, 0); // v3 two pass search center map offset radeon_emit(cs, 0); if (pdev->enc_hw_ver == RADV_VIDEO_ENC_HW_3) { radeon_emit(cs, 0); } } ENC_END; } static void radv_enc_bitstream(struct radv_cmd_buffer *cmd_buffer, struct radv_buffer *buffer, VkDeviceSize offset) { 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; uint64_t va = radv_buffer_get_va(buffer->bo) + buffer->offset; radv_cs_add_buffer(device->ws, cs, buffer->bo); ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.bitstream); radeon_emit(cs, RENCODE_REC_SWIZZLE_MODE_LINEAR); radeon_emit(cs, va >> 32); radeon_emit(cs, va & 0xffffffff); radeon_emit(cs, buffer->vk.size); radeon_emit(cs, offset); ENC_END; } static void radv_enc_feedback(struct radv_cmd_buffer *cmd_buffer, uint64_t feedback_query_va) { 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; ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.feedback); radeon_emit(cs, RENCODE_FEEDBACK_BUFFER_MODE_LINEAR); radeon_emit(cs, feedback_query_va >> 32); radeon_emit(cs, feedback_query_va & 0xffffffff); radeon_emit(cs, 16); // buffer_size radeon_emit(cs, 40); // data_size ENC_END; } static void radv_enc_intra_refresh(struct radv_cmd_buffer *cmd_buffer) { 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; ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.intra_refresh); radeon_emit(cs, 0); // intra refresh mode radeon_emit(cs, 0); // intra ref offset radeon_emit(cs, 0); // intra region size ENC_END; } static void radv_enc_rc_per_pic(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info, rvcn_enc_rate_ctl_per_picture_t *per_pic) { struct radv_video_session *vid = cmd_buffer->video.vid; 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 qp = per_pic->qp_i; if (vid->enc_rate_control_method == RENCODE_RATE_CONTROL_METHOD_NONE && !vid->enc_rate_control_default) { switch (vid->vk.op) { case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR: { const struct VkVideoEncodeH264PictureInfoKHR *h264_picture_info = vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_H264_PICTURE_INFO_KHR); const VkVideoEncodeH264NaluSliceInfoKHR *h264_slice = &h264_picture_info->pNaluSliceEntries[0]; 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]; qp = h265_slice->constantQp; break; } default: break; } } ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.rc_per_pic); radeon_emit(cs, qp); // qp_i radeon_emit(cs, qp); // qp_p radeon_emit(cs, qp); // qp_b radeon_emit(cs, per_pic->min_qp_i); radeon_emit(cs, per_pic->max_qp_i); radeon_emit(cs, per_pic->min_qp_p); radeon_emit(cs, per_pic->max_qp_p); radeon_emit(cs, per_pic->min_qp_b); radeon_emit(cs, per_pic->max_qp_b); radeon_emit(cs, per_pic->max_au_size_i); radeon_emit(cs, per_pic->max_au_size_p); radeon_emit(cs, per_pic->max_au_size_b); radeon_emit(cs, per_pic->enabled_filler_data); radeon_emit(cs, per_pic->skip_frame_enable); radeon_emit(cs, per_pic->enforce_hrd); radeon_emit(cs, 0xFFFFFFFF); // reserved_0xff ENC_END; } static void radv_enc_params(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info) { 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); const struct radv_physical_device *pdev = radv_device_physical(device); struct radeon_cmdbuf *cs = cmd_buffer->cs; uint64_t va = radv_buffer_get_va(src_img->bindings[0].bo) + src_img->bindings[0].offset; uint64_t luma_va = va + src_img->planes[0].surface.u.gfx9.surf_offset; uint64_t chroma_va = va + src_img->planes[1].surface.u.gfx9.surf_offset; uint32_t pic_type; unsigned int slot_idx = 0xffffffff; radv_cs_add_buffer(device->ws, cs, src_img->bindings[0].bo); if (h264_pic) { switch (h264_pic->primary_pic_type) { case STD_VIDEO_H264_PICTURE_TYPE_P: slot_idx = enc_info->pReferenceSlots[0].slotIndex; pic_type = RENCODE_PICTURE_TYPE_P; break; case STD_VIDEO_H264_PICTURE_TYPE_B: slot_idx = enc_info->pReferenceSlots[0].slotIndex; pic_type = RENCODE_PICTURE_TYPE_B; break; case STD_VIDEO_H264_PICTURE_TYPE_I: case STD_VIDEO_H264_PICTURE_TYPE_IDR: default: pic_type = RENCODE_PICTURE_TYPE_I; break; } radv_enc_layer_select(cmd_buffer, h264_pic->temporal_id); } 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; } radv_enc_layer_select(cmd_buffer, h265_pic->TemporalId); } else { assert(0); return; } ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.enc_params); radeon_emit(cs, pic_type); // pic type radeon_emit(cs, enc_info->dstBufferRange); // allowed max bitstream size radeon_emit(cs, luma_va >> 32); radeon_emit(cs, luma_va & 0xffffffff); radeon_emit(cs, chroma_va >> 32); radeon_emit(cs, chroma_va & 0xffffffff); radeon_emit(cs, src_img->planes[0].surface.u.gfx9.surf_pitch); // luma pitch radeon_emit(cs, src_img->planes[1].surface.u.gfx9.surf_pitch); // chroma pitch radeon_emit(cs, src_img->planes[0].surface.u.gfx9.swizzle_mode); // swizzle mode radeon_emit(cs, slot_idx); // ref0_idx if (enc_info->pSetupReferenceSlot) radeon_emit(cs, enc_info->pSetupReferenceSlot->slotIndex); // reconstructed picture index else radeon_emit(cs, 0); ENC_END; } static void radv_enc_params_h264(struct radv_cmd_buffer *cmd_buffer) { 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; ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.enc_params_h264); if (pdev->enc_hw_ver < RADV_VIDEO_ENC_HW_3) { radeon_emit(cs, RENCODE_H264_PICTURE_STRUCTURE_FRAME); radeon_emit(cs, RENCODE_H264_INTERLACING_MODE_PROGRESSIVE); radeon_emit(cs, RENCODE_H264_PICTURE_STRUCTURE_FRAME); radeon_emit(cs, 0xffffffff); // reference_picture1_index } else { // V3 radeon_emit(cs, RENCODE_H264_PICTURE_STRUCTURE_FRAME); radeon_emit(cs, 0); // input pic order cnt radeon_emit(cs, RENCODE_H264_INTERLACING_MODE_PROGRESSIVE); radeon_emit(cs, 0); // l0 ref pic0 pic_type radeon_emit(cs, 0); // l0 ref pic0 is long term radeon_emit(cs, 0); // l0 ref pic0 picture structure radeon_emit(cs, 0); // l0 ref pic0 pic order cnt radeon_emit(cs, 0xffffffff); // l0 ref pic1 index radeon_emit(cs, 0); // l0 ref pic1 pic_type radeon_emit(cs, 0); // l0 ref pic1 is long term radeon_emit(cs, 0); // l0 ref pic1 picture structure radeon_emit(cs, 0); // l0 ref pic1 pic order cnt radeon_emit(cs, 0xffffffff); // l1 ref pic0 index radeon_emit(cs, 0); // l1 ref pic0 pic_type radeon_emit(cs, 0); // l1 ref pic0 is long term radeon_emit(cs, 0); // l1 ref pic0 picture structure radeon_emit(cs, 0); // l1 ref pic0 pic order cnt } ENC_END; } static void radv_enc_op_init(struct radv_cmd_buffer *cmd_buffer) { struct radeon_cmdbuf *cs = cmd_buffer->cs; ENC_BEGIN; radeon_emit(cs, RENCODE_IB_OP_INITIALIZE); ENC_END; } static void radv_enc_op_enc(struct radv_cmd_buffer *cmd_buffer) { struct radeon_cmdbuf *cs = cmd_buffer->cs; ENC_BEGIN; radeon_emit(cs, RENCODE_IB_OP_ENCODE); ENC_END; } static void radv_enc_op_init_rc(struct radv_cmd_buffer *cmd_buffer) { struct radeon_cmdbuf *cs = cmd_buffer->cs; ENC_BEGIN; radeon_emit(cs, RENCODE_IB_OP_INIT_RC); ENC_END; } static void radv_enc_op_init_rc_vbv(struct radv_cmd_buffer *cmd_buffer) { struct radeon_cmdbuf *cs = cmd_buffer->cs; ENC_BEGIN; radeon_emit(cs, RENCODE_IB_OP_INIT_RC_VBV_BUFFER_LEVEL); ENC_END; } static void radv_enc_op_preset(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info) { struct radeon_cmdbuf *cs = cmd_buffer->cs; 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) preset_mode = RENCODE_IB_OP_SET_BALANCE_ENCODING_MODE; else preset_mode = RENCODE_IB_OP_SET_SPEED_ENCODING_MODE; ENC_BEGIN; radeon_emit(cs, preset_mode); ENC_END; } static void radv_enc_input_format(struct radv_cmd_buffer *cmd_buffer) { 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; struct radv_video_session *vid = cmd_buffer->video.vid; uint32_t color_bit_depth; uint32_t color_packing_format; switch (vid->vk.picture_format) { case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: color_bit_depth = RENCODE_COLOR_BIT_DEPTH_8_BIT; color_packing_format = RENCODE_COLOR_PACKING_FORMAT_NV12; break; case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: color_bit_depth = RENCODE_COLOR_BIT_DEPTH_10_BIT; color_packing_format = RENCODE_COLOR_PACKING_FORMAT_P010; break; default: assert(0); return; } ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.input_format); radeon_emit(cs, 0); // input color volume radeon_emit(cs, 0); // input color space radeon_emit(cs, RENCODE_COLOR_RANGE_STUDIO); // input color range radeon_emit(cs, 0); // input chroma subsampling radeon_emit(cs, 0); // input chroma location radeon_emit(cs, color_bit_depth); // input color bit depth radeon_emit(cs, color_packing_format); // input color packing format ENC_END; } static void radv_enc_output_format(struct radv_cmd_buffer *cmd_buffer) { 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; struct radv_video_session *vid = cmd_buffer->video.vid; uint32_t color_bit_depth; switch (vid->vk.op) { case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR: color_bit_depth = RENCODE_COLOR_BIT_DEPTH_8_BIT; break; case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR: if (vid->vk.h265.profile_idc == STD_VIDEO_H265_PROFILE_IDC_MAIN_10) color_bit_depth = RENCODE_COLOR_BIT_DEPTH_10_BIT; else color_bit_depth = RENCODE_COLOR_BIT_DEPTH_8_BIT; break; default: assert(0); return; } ENC_BEGIN; radeon_emit(cs, pdev->vcn_enc_cmds.output_format); radeon_emit(cs, 0); // output color volume radeon_emit(cs, RENCODE_COLOR_RANGE_STUDIO); // output color range radeon_emit(cs, 0); // output chroma location radeon_emit(cs, color_bit_depth); // output color bit depth ENC_END; } static void radv_enc_headers_h264(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info) { radv_enc_slice_header(cmd_buffer, enc_info); radv_enc_params(cmd_buffer, enc_info); 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) { struct radv_video_session *vid = cmd_buffer->video.vid; radv_enc_op_init(cmd_buffer); radv_enc_session_init(cmd_buffer, enc_info); if (vid->vk.op == VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR) { 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); radv_enc_quality_params(cmd_buffer); // temporal layers init unsigned i = 0; do { radv_enc_layer_select(cmd_buffer, i); radv_enc_rc_layer_init(cmd_buffer, &vid->rc_layer_init[i]); radv_enc_layer_select(cmd_buffer, i); radv_enc_rc_per_pic(cmd_buffer, enc_info, &vid->rc_per_pic[i]); } while (++i < vid->rc_layer_control.num_temporal_layers); radv_enc_op_init_rc(cmd_buffer); radv_enc_op_init_rc_vbv(cmd_buffer); } static void radv_vcn_encode_video(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR *enc_info) { VK_FROM_HANDLE(radv_buffer, dst_buffer, enc_info->dstBuffer); struct radv_video_session *vid = cmd_buffer->video.vid; struct radv_device *device = radv_cmd_buffer_device(cmd_buffer); const struct radv_physical_device *pdev = radv_device_physical(device); struct radv_enc_state *enc = &cmd_buffer->video.enc; uint64_t feedback_query_va; 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); return; } const struct VkVideoInlineQueryInfoKHR *inline_queries = NULL; if (vid->vk.flags & VK_VIDEO_SESSION_CREATE_INLINE_QUERIES_BIT_KHR) { inline_queries = vk_find_struct_const(enc_info->pNext, VIDEO_INLINE_QUERY_INFO_KHR); if (inline_queries) { VK_FROM_HANDLE(radv_query_pool, pool, inline_queries->queryPool); feedback_query_va = radv_buffer_get_va(pool->bo); feedback_query_va += pool->stride * inline_queries->firstQuery; } } if (!inline_queries) feedback_query_va = cmd_buffer->video.feedback_query_va; // before encode // session info radv_enc_session_info(cmd_buffer); cmd_buffer->video.enc.total_task_size = 0; // task info radv_enc_task_info(cmd_buffer, true); if (vid->enc_need_begin) { begin(cmd_buffer, enc_info); vid->enc_need_begin = false; } else { // temporal layers init unsigned i = 0; do { if (vid->enc_need_rate_control) { radv_enc_layer_select(cmd_buffer, i); radv_enc_rc_layer_init(cmd_buffer, &vid->rc_layer_init[i]); vid->enc_need_rate_control = false; } radv_enc_layer_select(cmd_buffer, i); radv_enc_rc_per_pic(cmd_buffer, enc_info, &vid->rc_per_pic[i]); } while (++i < vid->rc_layer_control.num_temporal_layers); } // encode headers // ctx 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); // feedback radv_enc_feedback(cmd_buffer, feedback_query_va); // v2 encode statistics if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_2) { } // intra_refresh radv_enc_intra_refresh(cmd_buffer); // v2 input format if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_2) { radv_enc_input_format(cmd_buffer); radv_enc_output_format(cmd_buffer); } // v2 output format // op_preset radv_enc_op_preset(cmd_buffer, enc_info); // op_enc radv_enc_op_enc(cmd_buffer); radeon_emit_direct(cmd_buffer->cs, enc->task_size_offset, enc->total_task_size); } static void set_rate_control_defaults(struct radv_video_session *vid) { uint32_t frame_rate_den = 1, frame_rate_num = 30; vid->enc_rate_control_method = RENCODE_RATE_CONTROL_METHOD_NONE; vid->enc_vbv_buffer_level = 64; vid->rc_layer_control.num_temporal_layers = 1; vid->rc_layer_control.max_num_temporal_layers = 1; vid->rc_per_pic[0].qp_i = 26; vid->rc_per_pic[0].qp_p = 26; vid->rc_per_pic[0].qp_b = 26; vid->rc_per_pic[0].min_qp_i = 0; vid->rc_per_pic[0].max_qp_i = 51; vid->rc_per_pic[0].min_qp_p = 0; vid->rc_per_pic[0].max_qp_p = 51; vid->rc_per_pic[0].min_qp_b = 0; vid->rc_per_pic[0].max_qp_b = 51; vid->rc_per_pic[0].max_au_size_i = 0; vid->rc_per_pic[0].max_au_size_p = 0; vid->rc_per_pic[0].max_au_size_b = 0; vid->rc_per_pic[0].enabled_filler_data = 1; vid->rc_per_pic[0].skip_frame_enable = 0; vid->rc_per_pic[0].enforce_hrd = 1; vid->rc_layer_init[0].frame_rate_den = frame_rate_den; vid->rc_layer_init[0].frame_rate_num = frame_rate_num; vid->rc_layer_init[0].vbv_buffer_size = 20000000; // rate_control->virtualBufferSizeInMs; vid->rc_layer_init[0].target_bit_rate = 16000; vid->rc_layer_init[0].peak_bit_rate = 32000; vid->rc_layer_init[0].avg_target_bits_per_picture = radv_vcn_per_frame_integer(16000, frame_rate_den, frame_rate_num); vid->rc_layer_init[0].peak_bits_per_picture_integer = radv_vcn_per_frame_integer(32000, frame_rate_den, frame_rate_num); vid->rc_layer_init[0].peak_bits_per_picture_fractional = radv_vcn_per_frame_frac(32000, frame_rate_den, frame_rate_num); return; } void radv_video_enc_control_video_coding(struct radv_cmd_buffer *cmd_buffer, const VkVideoCodingControlInfoKHR *control_info) { struct radv_video_session *vid = cmd_buffer->video.vid; 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"); } if (control_info->flags & VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR) { set_rate_control_defaults(vid); vid->enc_need_begin = true; } if (control_info->flags & VK_VIDEO_CODING_CONTROL_ENCODE_RATE_CONTROL_BIT_KHR) { const VkVideoEncodeRateControlInfoKHR *rate_control = (VkVideoEncodeRateControlInfoKHR *)vk_find_struct_const( control_info->pNext, VIDEO_ENCODE_RATE_CONTROL_INFO_KHR); assert(rate_control); 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); uint32_t rate_control_method = RENCODE_RATE_CONTROL_METHOD_NONE; vid->enc_rate_control_default = false; if (rate_control->rateControlMode == VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DEFAULT_KHR) { vid->enc_rate_control_default = true; set_rate_control_defaults(vid); } else if (rate_control->rateControlMode == VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR) rate_control_method = RENCODE_RATE_CONTROL_METHOD_CBR; else if (rate_control->rateControlMode == VK_VIDEO_ENCODE_RATE_CONTROL_MODE_VBR_BIT_KHR) rate_control_method = RENCODE_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR; vid->enc_need_rate_control = true; if (vid->enc_rate_control_method != rate_control_method) vid->enc_need_begin = true; vid->enc_rate_control_method = rate_control_method; if (rate_control->rateControlMode == VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DEFAULT_KHR) return; 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 = h265_rate_control->subLayerCount; vid->rc_layer_control.num_temporal_layers = h265_rate_control->subLayerCount; } 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; frame_rate_den = layer->frameRateDenominator; frame_rate_num = layer->frameRateNumerator; radv_vcn_enc_invalid_frame_rate(&frame_rate_den, &frame_rate_num); vid->rc_layer_init[l].frame_rate_den = frame_rate_den; vid->rc_layer_init[l].frame_rate_num = frame_rate_num; vid->rc_layer_init[l].vbv_buffer_size = (rate_control->virtualBufferSizeInMs / 1000.) * layer->averageBitrate; vid->rc_layer_init[l].avg_target_bits_per_picture = radv_vcn_per_frame_integer(layer->averageBitrate, frame_rate_den, frame_rate_num); vid->rc_layer_init[l].peak_bits_per_picture_integer = radv_vcn_per_frame_integer(layer->maxBitrate, frame_rate_den, frame_rate_num); vid->rc_layer_init[l].peak_bits_per_picture_fractional = radv_vcn_per_frame_frac(layer->maxBitrate, frame_rate_den, frame_rate_num); if (h264_layer) { vid->rc_per_pic[l].min_qp_i = h264_layer->useMinQp ? h264_layer->minQp.qpI : 0; vid->rc_per_pic[l].min_qp_p = h264_layer->useMinQp ? h264_layer->minQp.qpP : 0; vid->rc_per_pic[l].min_qp_b = h264_layer->useMinQp ? h264_layer->minQp.qpB : 0; vid->rc_per_pic[l].max_qp_i = h264_layer->useMaxQp ? h264_layer->maxQp.qpI : 51; vid->rc_per_pic[l].max_qp_p = h264_layer->useMaxQp ? h264_layer->maxQp.qpP : 51; vid->rc_per_pic[l].max_qp_b = h264_layer->useMaxQp ? h264_layer->maxQp.qpB : 51; vid->rc_per_pic[l].max_au_size_i = h264_layer->useMaxFrameSize ? h264_layer->maxFrameSize.frameISize : 0; vid->rc_per_pic[l].max_au_size_p = h264_layer->useMaxFrameSize ? h264_layer->maxFrameSize.framePSize : 0; vid->rc_per_pic[l].max_au_size_b = h264_layer->useMaxFrameSize ? h264_layer->maxFrameSize.frameBSize : 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].min_qp_p = h265_layer->useMinQp ? h265_layer->minQp.qpP : 0; vid->rc_per_pic[l].min_qp_b = h265_layer->useMinQp ? h265_layer->minQp.qpB : 0; vid->rc_per_pic[l].max_qp_i = h265_layer->useMaxQp ? h265_layer->maxQp.qpI : 51; vid->rc_per_pic[l].max_qp_p = h265_layer->useMaxQp ? h265_layer->maxQp.qpP : 51; vid->rc_per_pic[l].max_qp_b = h265_layer->useMaxQp ? h265_layer->maxQp.qpB : 51; vid->rc_per_pic[l].max_au_size_i = h265_layer->useMaxFrameSize ? h265_layer->maxFrameSize.frameISize : 0; vid->rc_per_pic[l].max_au_size_p = h265_layer->useMaxFrameSize ? h265_layer->maxFrameSize.framePSize : 0; vid->rc_per_pic[l].max_au_size_b = h265_layer->useMaxFrameSize ? h265_layer->maxFrameSize.frameBSize : 0; } vid->rc_per_pic[l].enabled_filler_data = 1; vid->rc_per_pic[l].skip_frame_enable = 0; vid->rc_per_pic[l].enforce_hrd = 1; } if (rate_control->virtualBufferSizeInMs > 0) vid->enc_vbv_buffer_level = lroundf((float)rate_control->initialVirtualBufferSizeInMs / rate_control->virtualBufferSizeInMs * 64); } } VKAPI_ATTR void VKAPI_CALL radv_CmdEncodeVideoKHR(VkCommandBuffer commandBuffer, const VkVideoEncodeInfoKHR *pEncodeInfo) { VK_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer); radv_vcn_encode_video(cmd_buffer, pEncodeInfo); } VKAPI_ATTR VkResult VKAPI_CALL radv_GetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR( VkPhysicalDevice physicalDevice, const VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR *pQualityLevelInfo, VkVideoEncodeQualityLevelPropertiesKHR *pQualityLevelProperties) { return VK_SUCCESS; } void radv_video_patch_encode_session_parameters(struct vk_video_session_parameters *params) { 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; } } VKAPI_ATTR VkResult VKAPI_CALL radv_GetEncodedVideoSessionParametersKHR(VkDevice device, const VkVideoEncodeSessionParametersGetInfoKHR *pVideoSessionParametersInfo, VkVideoEncodeSessionParametersFeedbackInfoKHR *pFeedbackInfo, size_t *pDataSize, void *pData) { VK_FROM_HANDLE(radv_video_session_params, templ, pVideoSessionParametersInfo->videoSessionParameters); size_t total_size = 0; size_t size_limit = 0; if (pData) size_limit = *pDataSize; switch (templ->vk.op) { case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR: { const struct VkVideoEncodeH264SessionParametersGetInfoKHR *h264_get_info = vk_find_struct_const(pVideoSessionParametersInfo->pNext, VIDEO_ENCODE_H264_SESSION_PARAMETERS_GET_INFO_KHR); size_t sps_size = 0, pps_size = 0; if (h264_get_info->writeStdSPS) { const StdVideoH264SequenceParameterSet *sps = vk_video_find_h264_enc_std_sps(&templ->vk, h264_get_info->stdSPSId); assert(sps); vk_video_encode_h264_sps(sps, size_limit, &sps_size, pData); } if (h264_get_info->writeStdPPS) { const StdVideoH264PictureParameterSet *pps = vk_video_find_h264_enc_std_pps(&templ->vk, h264_get_info->stdPPSId); assert(pps); char *data_ptr = pData ? (char *)pData + sps_size : NULL; vk_video_encode_h264_pps(pps, templ->vk.h264_enc.profile_idc == STD_VIDEO_H264_PROFILE_IDC_HIGH, size_limit, &pps_size, data_ptr); } total_size = sps_size + pps_size; 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); size_t sps_size = 0, pps_size = 0, vps_size = 0; 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, &vps_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); char *data_ptr = pData ? (char *)pData + vps_size : NULL; vk_video_encode_h265_sps(sps, size_limit, &sps_size, data_ptr); } if (h265_get_info->writeStdPPS) { const StdVideoH265PictureParameterSet *pps = vk_video_find_h265_enc_std_pps(&templ->vk, h265_get_info->stdPPSId); assert(pps); char *data_ptr = pData ? (char *)pData + vps_size + sps_size : NULL; vk_video_encode_h265_pps(pps, size_limit, &pps_size, data_ptr); if (pFeedbackInfo) { struct VkVideoEncodeH265SessionParametersFeedbackInfoKHR *h265_feedback_info = vk_find_struct(pFeedbackInfo->pNext, VIDEO_ENCODE_H265_SESSION_PARAMETERS_FEEDBACK_INFO_KHR); pFeedbackInfo->hasOverrides = VK_TRUE; h265_feedback_info->hasStdPPSOverrides = VK_TRUE; } } total_size = sps_size + pps_size + vps_size; break; } default: break; } *pDataSize = total_size; return VK_SUCCESS; } void radv_video_enc_begin_coding(struct radv_cmd_buffer *cmd_buffer) { struct radv_device *device = radv_cmd_buffer_device(cmd_buffer); const struct radv_physical_device *pdev = radv_device_physical(device); radeon_check_space(device->ws, cmd_buffer->cs, 1024); if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_4) radv_vcn_sq_header(cmd_buffer->cs, &cmd_buffer->video.sq, RADEON_VCN_ENGINE_TYPE_ENCODE); } void radv_video_enc_end_coding(struct radv_cmd_buffer *cmd_buffer) { struct radv_device *device = radv_cmd_buffer_device(cmd_buffer); const struct radv_physical_device *pdev = radv_device_physical(device); if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_4) radv_vcn_sq_tail(cmd_buffer->cs, &cmd_buffer->video.sq); } #define VCN_ENC_SESSION_SIZE 128 * 1024 VkResult radv_video_get_encode_session_memory_requirements(struct radv_device *device, struct radv_video_session *vid, uint32_t *pMemoryRequirementsCount, VkVideoSessionMemoryRequirementsKHR *pMemoryRequirements) { struct radv_physical_device *pdev = radv_device_physical(device); uint32_t memory_type_bits = (1u << pdev->memory_properties.memoryTypeCount) - 1; VK_OUTARRAY_MAKE_TYPED(VkVideoSessionMemoryRequirementsKHR, out, pMemoryRequirements, pMemoryRequirementsCount); vk_outarray_append_typed(VkVideoSessionMemoryRequirementsKHR, &out, m) { m->memoryBindIndex = 0; m->memoryRequirements.size = VCN_ENC_SESSION_SIZE; m->memoryRequirements.alignment = 0; m->memoryRequirements.memoryTypeBits = memory_type_bits; } return vk_outarray_status(&out); }