diff --git a/src/amd/vulkan/radv_formats.c b/src/amd/vulkan/radv_formats.c index 006ea8fb833..bda15796194 100644 --- a/src/amd/vulkan/radv_formats.c +++ b/src/amd/vulkan/radv_formats.c @@ -492,8 +492,12 @@ radv_physical_device_get_format_properties(struct radv_physical_device *pdev, Vk tiled |= VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT; } - if (pdev->video_encode_enabled && format == VK_FORMAT_R32_SINT) { - linear |= VK_FORMAT_FEATURE_2_VIDEO_ENCODE_QUANTIZATION_DELTA_MAP_BIT_KHR; + if (pdev->video_encode_enabled) { + const VkFormat map_format = pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_5 ? VK_FORMAT_R16_SINT : VK_FORMAT_R32_SINT; + if (format == map_format) { + linear |= VK_FORMAT_FEATURE_2_VIDEO_ENCODE_QUANTIZATION_DELTA_MAP_BIT_KHR; + tiled |= VK_FORMAT_FEATURE_2_VIDEO_ENCODE_QUANTIZATION_DELTA_MAP_BIT_KHR; + } } out_properties->linearTilingFeatures = linear; diff --git a/src/amd/vulkan/radv_physical_device.c b/src/amd/vulkan/radv_physical_device.c index 346c809bd14..e1e1f2e6cbd 100644 --- a/src/amd/vulkan/radv_physical_device.c +++ b/src/amd/vulkan/radv_physical_device.c @@ -649,7 +649,7 @@ radv_physical_device_get_supported_extensions(const struct radv_physical_device .KHR_video_encode_av1 = (radv_video_encode_av1_supported(pdev) && VIDEO_CODEC_AV1ENC && pdev->video_encode_enabled), .KHR_video_encode_intra_refresh = pdev->video_encode_enabled, - .KHR_video_encode_quantization_map = pdev->video_encode_enabled && pdev->info.vcn_ip_version < VCN_5_0_0, + .KHR_video_encode_quantization_map = pdev->video_encode_enabled && radv_video_encode_qp_map_supported(pdev), .KHR_video_encode_queue = pdev->video_encode_enabled, .KHR_vulkan_memory_model = true, .KHR_workgroup_memory_explicit_layout = true, diff --git a/src/amd/vulkan/radv_video.c b/src/amd/vulkan/radv_video.c index 68d6569455c..fd5cc7cde6b 100644 --- a/src/amd/vulkan/radv_video.c +++ b/src/amd/vulkan/radv_video.c @@ -40,7 +40,7 @@ static void set_reg(struct radv_cmd_buffer *cmd_buffer, unsigned reg, uint32_t val); -static inline bool +bool radv_check_vcn_fw_version(const struct radv_physical_device *pdev, uint32_t dec, uint32_t enc, uint32_t rev) { return pdev->info.vcn_dec_version > dec || pdev->info.vcn_enc_minor_version > enc || @@ -804,7 +804,7 @@ radv_video_is_profile_supported(struct radv_physical_device *pdev, const VkVideo return VK_SUCCESS; } -static uint32_t +uint32_t radv_video_get_qp_map_texel_size(VkVideoCodecOperationFlagBitsKHR codec) { switch (codec) { @@ -902,7 +902,7 @@ radv_GetPhysicalDeviceVideoCapabilitiesKHR(VkPhysicalDevice physicalDevice, cons enc_caps->supportedEncodeFeedbackFlags = VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_BUFFER_OFFSET_BIT_KHR | VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_BYTES_WRITTEN_BIT_KHR; - if (pdev->info.vcn_ip_version < VCN_5_0_0) + if (radv_video_encode_qp_map_supported(pdev)) enc_caps->flags |= VK_VIDEO_ENCODE_CAPABILITY_QUANTIZATION_DELTA_MAP_BIT_KHR; } if (intra_refresh_caps) { @@ -1254,7 +1254,7 @@ radv_GetPhysicalDeviceVideoFormatPropertiesKHR(VkPhysicalDevice physicalDevice, qp_map_texel_size = profile_qp_map_texel_size; - profile_format = VK_FORMAT_R32_SINT; + profile_format = pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_5 ? VK_FORMAT_R16_SINT : VK_FORMAT_R32_SINT; } else { if (profile->lumaBitDepth == VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR) profile_format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; @@ -1468,6 +1468,9 @@ radv_BindVideoSessionMemoryKHR(VkDevice _device, VkVideoSessionKHR videoSession, case RADV_BIND_INTRA_ONLY: copy_bind(&vid->intra_only_dpb, &pBindSessionMemoryInfos[i]); break; + case RADV_BIND_ENCODE_QP_MAP: + copy_bind(&vid->qp_map, &pBindSessionMemoryInfos[i]); + break; default: assert(0); break; diff --git a/src/amd/vulkan/radv_video.h b/src/amd/vulkan/radv_video.h index e259615f3cd..56309fc57ce 100644 --- a/src/amd/vulkan/radv_video.h +++ b/src/amd/vulkan/radv_video.h @@ -30,6 +30,7 @@ struct radv_cmd_stream; #define RADV_BIND_SESSION_CTX 0 #define RADV_BIND_DECODER_CTX 1 #define RADV_BIND_INTRA_ONLY 2 +#define RADV_BIND_ENCODE_QP_MAP 3 #define RADV_BIND_ENCODE_AV1_CDF_STORE RADV_BIND_DECODER_CTX struct radv_vid_mem { @@ -51,6 +52,7 @@ struct radv_video_session { struct radv_vid_mem ctx; struct radv_vid_mem intra_only_dpb; + struct radv_vid_mem qp_map; unsigned dbg_frame_cnt; rvcn_enc_session_init_t enc_session; @@ -93,5 +95,8 @@ void radv_video_get_enc_dpb_image(struct radv_device *device, const struct VkVid struct radv_image *image, struct radv_image_create_info *create_info); bool radv_video_decode_vp9_supported(const struct radv_physical_device *pdev); bool radv_video_encode_av1_supported(const struct radv_physical_device *pdev); +bool radv_video_encode_qp_map_supported(const struct radv_physical_device *pdev); +uint32_t radv_video_get_qp_map_texel_size(VkVideoCodecOperationFlagBitsKHR codec); +bool radv_check_vcn_fw_version(const struct radv_physical_device *pdev, uint32_t dec, uint32_t enc, uint32_t rev); #endif /* RADV_VIDEO_H */ diff --git a/src/amd/vulkan/radv_video_enc.c b/src/amd/vulkan/radv_video_enc.c index 6c3eb7d7757..0e684be5c19 100644 --- a/src/amd/vulkan/radv_video_enc.c +++ b/src/amd/vulkan/radv_video_enc.c @@ -1707,6 +1707,52 @@ radv_enc_intra_refresh(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeIn RADEON_ENC_END(); } +static void +radv_enc_qp_map_input(struct radv_cmd_buffer *cmd_buffer, const struct VkVideoEncodeInfoKHR *enc_info) +{ + struct radv_device *device = radv_cmd_buffer_device(cmd_buffer); + const struct VkVideoEncodeQuantizationMapInfoKHR *quantization_map_info = + vk_find_struct_const(enc_info->pNext, VIDEO_ENCODE_QUANTIZATION_MAP_INFO_KHR); + const struct radv_image_view *qp_map_view = + quantization_map_info ? radv_image_view_from_handle(quantization_map_info->quantizationMap) : NULL; + const struct radv_image *qp_map = qp_map_view ? qp_map_view->image : NULL; + struct radv_cmd_stream *cs = cmd_buffer->cs; + + if (!(enc_info->flags & VK_VIDEO_ENCODE_WITH_QUANTIZATION_DELTA_MAP_BIT_KHR) || !qp_map) + return; + + const uint64_t va_in = qp_map->bindings[0].addr; + radv_cs_add_buffer(device->ws, cs->b, qp_map->bindings[0].bo); + + const uint64_t va_out = + radv_buffer_get_va(cmd_buffer->video.vid->qp_map.mem->bo) + cmd_buffer->video.vid->qp_map.offset; + radv_cs_add_buffer(device->ws, cmd_buffer->cs->b, cmd_buffer->video.vid->qp_map.mem->bo); + + radv_vcn_sq_header(cs, &cmd_buffer->video.sq, RADEON_VCN_ENGINE_TYPE_COMMON, false); + + struct rvcn_cmn_engine_ib_package *ib_header = (struct rvcn_cmn_engine_ib_package *)&(cs->b->buf[cs->b->cdw]); + ib_header->package_size = + sizeof(struct rvcn_cmn_engine_ib_package) + sizeof(struct rvcn_cmn_engine_op_resolveinputparamlayout); + cs->b->cdw++; + ib_header->package_type = RADEON_VCN_IB_COMMON_OP_RESOLVEINPUTPARAMLAYOUT; + cs->b->cdw++; + + struct rvcn_cmn_engine_op_resolveinputparamlayout *resolve_input = + (struct rvcn_cmn_engine_op_resolveinputparamlayout *)&(cs->b->buf[cs->b->cdw]); + resolve_input->map_type = RADEON_VCN_RESOLVE_INPUT_PARAM_LAYOUT_TYPE_QPMAP_INT16; + resolve_input->map_width = qp_map->vk.extent.width; + resolve_input->map_height = qp_map->vk.extent.height; + resolve_input->input_buffer_address_lo = va_in & 0xffffffff; + resolve_input->input_buffer_address_hi = va_in >> 32; + resolve_input->input_buffer_pitch = qp_map->planes[0].surface.u.gfx9.surf_pitch; + resolve_input->input_buffer_swizzle_mode = qp_map->planes[0].surface.u.gfx9.swizzle_mode; + resolve_input->output_buffer_address_lo = va_out & 0xffffffff; + resolve_input->output_buffer_address_hi = va_out >> 32; + + cs->b->cdw += sizeof(*resolve_input) / 4; + radv_vcn_sq_tail(cs, &cmd_buffer->video.sq); +} + static void radv_enc_qp_map(struct radv_cmd_buffer *cmd_buffer, const struct VkVideoEncodeInfoKHR *enc_info) { @@ -1720,18 +1766,24 @@ radv_enc_qp_map(struct radv_cmd_buffer *cmd_buffer, const struct VkVideoEncodeIn RADEON_ENC_BEGIN(pdev->vcn_enc_cmds.enc_qp_map); if (enc_info->flags & VK_VIDEO_ENCODE_WITH_QUANTIZATION_DELTA_MAP_BIT_KHR && qp_map) { - /* VCN < 5 uses a 32-bit signed integer for QP maps. */ - assert(qp_map->vk.format == VK_FORMAT_R32_SINT); - - const uint32_t qp_map_type = cmd_buffer->video.vid->enc_rate_control_method == RENCODE_RATE_CONTROL_METHOD_NONE - ? RENCODE_QP_MAP_TYPE_DELTA - : RENCODE_QP_MAP_TYPE_MAP_PA; - radv_cs_add_buffer(device->ws, cmd_buffer->cs->b, qp_map->bindings[0].bo); - const uint64_t va = qp_map->bindings[0].addr; - RADEON_ENC_CS(qp_map_type); - RADEON_ENC_CS(va >> 32); - RADEON_ENC_CS(va & 0xffffffff); - RADEON_ENC_CS(qp_map->planes[0].surface.u.gfx9.surf_pitch); + if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_5) { + uint64_t va = radv_buffer_get_va(cmd_buffer->video.vid->qp_map.mem->bo); + va += cmd_buffer->video.vid->qp_map.offset; + RADEON_ENC_CS(RENCODE_QP_MAP_TYPE_DELTA); + RADEON_ENC_CS(va >> 32); + RADEON_ENC_CS(va & 0xffffffff); + RADEON_ENC_CS(0); + } else { + const uint32_t qp_map_type = cmd_buffer->video.vid->enc_rate_control_method == RENCODE_RATE_CONTROL_METHOD_NONE + ? RENCODE_QP_MAP_TYPE_DELTA + : RENCODE_QP_MAP_TYPE_MAP_PA; + radv_cs_add_buffer(device->ws, cmd_buffer->cs->b, qp_map->bindings[0].bo); + const uint64_t va = qp_map->bindings[0].addr; + RADEON_ENC_CS(qp_map_type); + RADEON_ENC_CS(va >> 32); + RADEON_ENC_CS(va & 0xffffffff); + RADEON_ENC_CS(qp_map->planes[0].surface.u.gfx9.surf_pitch); + } } else { RADEON_ENC_CS(RENCODE_QP_MAP_TYPE_NONE); RADEON_ENC_CS(0); @@ -2732,6 +2784,9 @@ radv_vcn_encode_video(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInf radeon_check_space(device->ws, cs->b, 1600); + if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_5) + radv_enc_qp_map_input(cmd_buffer, enc_info); + if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_4) radv_vcn_sq_header(cs, &cmd_buffer->video.sq, RADEON_VCN_ENGINE_TYPE_ENCODE, false); @@ -3304,6 +3359,22 @@ radv_video_get_encode_session_memory_requirements(struct radv_device *device, st m->memoryRequirements.memoryTypeBits |= (1 << i); } } + + if (vid->vk.flags & VK_VIDEO_SESSION_CREATE_ALLOW_ENCODE_QUANTIZATION_DELTA_MAP_BIT_KHR && + pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_5) { + const uint32_t texel_size = radv_video_get_qp_map_texel_size(vid->vk.op); + const uint32_t map_width = DIV_ROUND_UP(vid->vk.max_coded.width, texel_size); + const uint32_t map_height = DIV_ROUND_UP(vid->vk.max_coded.height, texel_size); + + vk_outarray_append_typed(VkVideoSessionMemoryRequirementsKHR, &out, m) + { + m->memoryBindIndex = RADV_BIND_ENCODE_QP_MAP; + m->memoryRequirements.size = map_width * map_height * sizeof(int16_t); + m->memoryRequirements.alignment = 0; + m->memoryRequirements.memoryTypeBits = memory_type_bits; + } + } + return vk_outarray_status(&out); } @@ -3365,3 +3436,11 @@ radv_video_encode_av1_supported(const struct radv_physical_device *pdev) return false; } } + +bool +radv_video_encode_qp_map_supported(const struct radv_physical_device *pdev) +{ + if (pdev->info.vcn_ip_version >= VCN_5_0_0) + return radv_check_vcn_fw_version(pdev, 9, 9, 28); + return true; +}