From 2705d8bd8bb0cd049b4e91ac4e15ccc798abeda1 Mon Sep 17 00:00:00 2001 From: Autumn Ashton Date: Wed, 3 Sep 2025 22:29:58 +0100 Subject: [PATCH] radv/video: Implement VK_VALVE_video_encode_rgb_conversion This is used by Steam Link VR (driver_vrlink) to avoid doing YUV conversion itself. Signed-off-by: Autumn Ashton Reviewed-by: David Rosca Part-of: --- docs/features.txt | 2 +- docs/relnotes/new_features.txt | 1 + src/amd/vulkan/radv_physical_device.c | 5 ++ src/amd/vulkan/radv_video.c | 109 ++++++++++++++++---------- src/amd/vulkan/radv_video_enc.c | 106 ++++++++++++++++++++++--- src/vulkan/runtime/vk_video.c | 12 +++ src/vulkan/runtime/vk_video.h | 8 ++ 7 files changed, 191 insertions(+), 52 deletions(-) diff --git a/docs/features.txt b/docs/features.txt index 08763314c91..9c5c1226762 100644 --- a/docs/features.txt +++ b/docs/features.txt @@ -716,7 +716,7 @@ Khronos extensions that are not part of any Vulkan version: VK_MESA_image_alignment_control DONE (anv, nvk, radv) VK_EXT_legacy_dithering DONE (anv, tu, vn) VK_QCOM_fragment_density_map_offset DONE (tu) - + VK_VALVE_video_encode_rgb_conversion DONE (radv) Rusticl OpenCL 1.0 -- all DONE: Image support DONE diff --git a/docs/relnotes/new_features.txt b/docs/relnotes/new_features.txt index 0e1d7aaab6f..33178781c6e 100644 --- a/docs/relnotes/new_features.txt +++ b/docs/relnotes/new_features.txt @@ -9,3 +9,4 @@ VK_KHR_present_wait2 on HoneyKrisp VK_KHR_maintenance10 on ANV, NVK, RADV VK_EXT_shader_uniform_buffer_unsized_array on NVK, RADV VK_EXT_device_memory_report on panvk +VK_VALVE_video_encode_rgb_conversion on radv diff --git a/src/amd/vulkan/radv_physical_device.c b/src/amd/vulkan/radv_physical_device.c index bed03974903..fe57e0622c0 100644 --- a/src/amd/vulkan/radv_physical_device.c +++ b/src/amd/vulkan/radv_physical_device.c @@ -814,6 +814,8 @@ radv_physical_device_get_supported_extensions(const struct radv_physical_device .NV_compute_shader_derivatives = true, .NV_cooperative_matrix2 = radv_cooperative_matrix2_nv_enabled(pdev), .VALVE_mutable_descriptor_type = true, + .VALVE_video_encode_rgb_conversion = + pdev->video_encode_enabled && pdev->info.vcn_ip_version >= VCN_2_0_0 && pdev->info.vcn_ip_version != VCN_2_2_0, }; *out_ext = ext; } @@ -1428,6 +1430,9 @@ radv_physical_device_get_features(const struct radv_physical_device *pdev, struc /* VK_KHR_maintenance10 */ .maintenance10 = true, + + /* VK_VALVE_video_encode_rgb_conversion */ + .videoEncodeRgbConversion = true, }; } diff --git a/src/amd/vulkan/radv_video.c b/src/amd/vulkan/radv_video.c index 22d9ed28006..b2fdc14ce5d 100644 --- a/src/amd/vulkan/radv_video.c +++ b/src/amd/vulkan/radv_video.c @@ -928,6 +928,8 @@ radv_GetPhysicalDeviceVideoCapabilitiesKHR(VkPhysicalDevice physicalDevice, cons vk_find_struct(pCapabilities->pNext, VIDEO_ENCODE_INTRA_REFRESH_CAPABILITIES_KHR); struct VkVideoEncodeQuantizationMapCapabilitiesKHR *qp_map_caps = vk_find_struct(pCapabilities->pNext, VIDEO_ENCODE_QUANTIZATION_MAP_CAPABILITIES_KHR); + struct VkVideoEncodeRgbConversionCapabilitiesVALVE *rgb_caps = + vk_find_struct(pCapabilities->pNext, VIDEO_ENCODE_RGB_CONVERSION_CAPABILITIES_VALVE); if (enc_caps) { enc_caps->flags = 0; @@ -958,6 +960,15 @@ radv_GetPhysicalDeviceVideoCapabilitiesKHR(VkPhysicalDevice physicalDevice, cons qp_map_caps->maxQuantizationMapExtent.width = pCapabilities->maxCodedExtent.width / qp_map_texel_size; qp_map_caps->maxQuantizationMapExtent.height = pCapabilities->maxCodedExtent.height / qp_map_texel_size; } + if (rgb_caps) { + rgb_caps->rgbModels = VK_VIDEO_ENCODE_RGB_MODEL_CONVERSION_YCBCR_709_BIT_VALVE | + VK_VIDEO_ENCODE_RGB_MODEL_CONVERSION_YCBCR_2020_BIT_VALVE; + rgb_caps->rgbRanges = VK_VIDEO_ENCODE_RGB_RANGE_COMPRESSION_FULL_RANGE_BIT_VALVE | + VK_VIDEO_ENCODE_RGB_RANGE_COMPRESSION_NARROW_RANGE_BIT_VALVE; + rgb_caps->xChromaOffsets = VK_VIDEO_ENCODE_RGB_CHROMA_OFFSET_COSITED_EVEN_BIT_VALVE; + rgb_caps->yChromaOffsets = VK_VIDEO_ENCODE_RGB_CHROMA_OFFSET_MIDPOINT_BIT_VALVE | + VK_VIDEO_ENCODE_RGB_CHROMA_OFFSET_COSITED_EVEN_BIT_VALVE; + } pCapabilities->minBitstreamBufferOffsetAlignment = 256; pCapabilities->minBitstreamBufferSizeAlignment = 8; if (pdev->info.vcn_ip_version >= VCN_5_0_0) @@ -1241,13 +1252,17 @@ radv_GetPhysicalDeviceVideoFormatPropertiesKHR(VkPhysicalDevice physicalDevice, (VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR | VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR)) return VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR; - VkFormat format = VK_FORMAT_UNDEFINED; + VkFormat formats[2] = {VK_FORMAT_UNDEFINED, VK_FORMAT_UNDEFINED}; uint32_t qp_map_texel_size = 0; const struct VkVideoProfileListInfoKHR *prof_list = (struct VkVideoProfileListInfoKHR *)vk_find_struct_const(pVideoFormatInfo->pNext, VIDEO_PROFILE_LIST_INFO_KHR); if (prof_list) { for (unsigned i = 0; i < prof_list->profileCount; i++) { const VkVideoProfileInfoKHR *profile = &prof_list->pProfiles[i]; + const VkVideoEncodeProfileRgbConversionInfoVALVE *rgbProfile = + vk_find_struct_const(profile, VIDEO_ENCODE_PROFILE_RGB_CONVERSION_INFO_VALVE); + bool rgb = rgbProfile && rgbProfile->performEncodeRgbConversion && + (pVideoFormatInfo->imageUsage & VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR); /* "If any of the video profiles specified via VkVideoProfileListInfoKHR::pProfiles are not * supported, then this command returns one of the video-profile-specific error codes." @@ -1256,8 +1271,7 @@ radv_GetPhysicalDeviceVideoFormatPropertiesKHR(VkPhysicalDevice physicalDevice, if (res != VK_SUCCESS) return res; - VkFormat profile_format = VK_FORMAT_UNDEFINED; - + VkFormat profile_formats[2] = {VK_FORMAT_UNDEFINED, VK_FORMAT_UNDEFINED}; if (pVideoFormatInfo->imageUsage & VK_IMAGE_USAGE_VIDEO_ENCODE_QUANTIZATION_DELTA_MAP_BIT_KHR) { const uint32_t profile_qp_map_texel_size = radv_video_get_qp_map_texel_size(profile->videoCodecOperation); @@ -1267,31 +1281,41 @@ radv_GetPhysicalDeviceVideoFormatPropertiesKHR(VkPhysicalDevice physicalDevice, qp_map_texel_size = profile_qp_map_texel_size; - profile_format = pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_5 ? VK_FORMAT_R16_SINT : VK_FORMAT_R32_SINT; + profile_formats[0] = pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_5 ? VK_FORMAT_R16_SINT : VK_FORMAT_R32_SINT; + } else if (rgb) { + if (profile->lumaBitDepth == VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR) { + profile_formats[0] = VK_FORMAT_B8G8R8A8_UNORM; + profile_formats[1] = VK_FORMAT_R8G8B8A8_UNORM; + } else if (profile->lumaBitDepth == VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR) { + profile_formats[0] = VK_FORMAT_A2B10G10R10_UNORM_PACK32; + profile_formats[1] = VK_FORMAT_A2R10G10B10_UNORM_PACK32; + } } else { if (profile->lumaBitDepth == VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR) - profile_format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; + profile_formats[0] = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; else if (profile->lumaBitDepth == VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR) - profile_format = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16; + profile_formats[0] = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16; else if (profile->lumaBitDepth == VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR) - profile_format = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16; + profile_formats[0] = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16; } - /* All profiles must share the same format. */ - if (format != VK_FORMAT_UNDEFINED && format != profile_format) - return VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR; + for (int j = 0; j < 2; j++) { + /* All profiles must share the same format. */ + if (formats[j] != VK_FORMAT_UNDEFINED && formats[j] != profile_formats[j]) + return VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR; - format = profile_format; + formats[j] = profile_formats[j]; + } } } else { /* On AMD, we need a codec specified for qp map as the extents differ. */ if (pVideoFormatInfo->imageUsage & VK_IMAGE_USAGE_VIDEO_ENCODE_QUANTIZATION_DELTA_MAP_BIT_KHR) return VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR; - format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; + formats[0] = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; } - if (format == VK_FORMAT_UNDEFINED) + if (formats[0] == VK_FORMAT_UNDEFINED) return VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR; const bool qp_map = pVideoFormatInfo->imageUsage & VK_IMAGE_USAGE_VIDEO_ENCODE_QUANTIZATION_DELTA_MAP_BIT_KHR; @@ -1320,35 +1344,40 @@ radv_GetPhysicalDeviceVideoFormatPropertiesKHR(VkPhysicalDevice physicalDevice, VK_OUTARRAY_MAKE_TYPED(VkVideoFormatPropertiesKHR, out, pVideoFormatProperties, pVideoFormatPropertyCount); - for (uint32_t i = 0; i < num_tiling; i++) { - vk_outarray_append_typed(VkVideoFormatPropertiesKHR, &out, p) - { - p->format = format; - p->componentMapping.r = VK_COMPONENT_SWIZZLE_IDENTITY; - p->componentMapping.g = VK_COMPONENT_SWIZZLE_IDENTITY; - p->componentMapping.b = VK_COMPONENT_SWIZZLE_IDENTITY; - p->componentMapping.a = VK_COMPONENT_SWIZZLE_IDENTITY; - p->imageCreateFlags = 0; - if (src_dst || qp_map) - p->imageCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT; - p->imageType = VK_IMAGE_TYPE_2D; - p->imageTiling = tiling[i]; - p->imageUsageFlags = usage_flags; + for (uint32_t i = 0; i < 2; i++) { + VkFormat format = formats[i]; + if (format == VK_FORMAT_UNDEFINED) + break; + for (uint32_t j = 0; j < num_tiling; j++) { + vk_outarray_append_typed(VkVideoFormatPropertiesKHR, &out, p) + { + p->format = format; + p->componentMapping.r = VK_COMPONENT_SWIZZLE_IDENTITY; + p->componentMapping.g = VK_COMPONENT_SWIZZLE_IDENTITY; + p->componentMapping.b = VK_COMPONENT_SWIZZLE_IDENTITY; + p->componentMapping.a = VK_COMPONENT_SWIZZLE_IDENTITY; + p->imageCreateFlags = 0; + if (src_dst || qp_map) + p->imageCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT; + p->imageType = VK_IMAGE_TYPE_2D; + p->imageTiling = tiling[j]; + p->imageUsageFlags = usage_flags; - if (qp_map) { - struct VkVideoFormatQuantizationMapPropertiesKHR *qp_map_props = - vk_find_struct(p->pNext, VIDEO_FORMAT_QUANTIZATION_MAP_PROPERTIES_KHR); - struct VkVideoFormatH265QuantizationMapPropertiesKHR *qp_map_h265_props = - vk_find_struct(p->pNext, VIDEO_FORMAT_H265_QUANTIZATION_MAP_PROPERTIES_KHR); - struct VkVideoFormatAV1QuantizationMapPropertiesKHR *qp_map_av1_props = - vk_find_struct(p->pNext, VIDEO_FORMAT_AV1_QUANTIZATION_MAP_PROPERTIES_KHR); + if (qp_map) { + struct VkVideoFormatQuantizationMapPropertiesKHR *qp_map_props = + vk_find_struct(p->pNext, VIDEO_FORMAT_QUANTIZATION_MAP_PROPERTIES_KHR); + struct VkVideoFormatH265QuantizationMapPropertiesKHR *qp_map_h265_props = + vk_find_struct(p->pNext, VIDEO_FORMAT_H265_QUANTIZATION_MAP_PROPERTIES_KHR); + struct VkVideoFormatAV1QuantizationMapPropertiesKHR *qp_map_av1_props = + vk_find_struct(p->pNext, VIDEO_FORMAT_AV1_QUANTIZATION_MAP_PROPERTIES_KHR); - if (qp_map_props) - qp_map_props->quantizationMapTexelSize = (VkExtent2D){qp_map_texel_size, qp_map_texel_size}; - if (qp_map_h265_props) - qp_map_h265_props->compatibleCtbSizes = VK_VIDEO_ENCODE_H265_CTB_SIZE_64_BIT_KHR; - if (qp_map_av1_props) - qp_map_av1_props->compatibleSuperblockSizes = VK_VIDEO_ENCODE_AV1_SUPERBLOCK_SIZE_64_BIT_KHR; + if (qp_map_props) + qp_map_props->quantizationMapTexelSize = (VkExtent2D){qp_map_texel_size, qp_map_texel_size}; + if (qp_map_h265_props) + qp_map_h265_props->compatibleCtbSizes = VK_VIDEO_ENCODE_H265_CTB_SIZE_64_BIT_KHR; + if (qp_map_av1_props) + qp_map_av1_props->compatibleSuperblockSizes = VK_VIDEO_ENCODE_AV1_SUPERBLOCK_SIZE_64_BIT_KHR; + } } } } diff --git a/src/amd/vulkan/radv_video_enc.c b/src/amd/vulkan/radv_video_enc.c index bb4088939d4..f2616622321 100644 --- a/src/amd/vulkan/radv_video_enc.c +++ b/src/amd/vulkan/radv_video_enc.c @@ -1845,8 +1845,9 @@ radv_enc_params(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR * uint64_t va = src_img->bindings[0].addr; uint64_t luma_va = va + src_img->planes[0].surface.u.gfx9.surf_offset + array_idx * src_img->planes[0].surface.u.gfx9.surf_slice_size; - uint64_t chroma_va = va + src_img->planes[1].surface.u.gfx9.surf_offset + - array_idx * src_img->planes[1].surface.u.gfx9.surf_slice_size; + uint64_t chroma_va = src_img->plane_count > 1 ? (va + src_img->planes[1].surface.u.gfx9.surf_offset + + array_idx * src_img->planes[1].surface.u.gfx9.surf_slice_size) + : 0; uint32_t pic_type; unsigned int slot_idx = 0xffffffff; unsigned int max_layers = cmd_buffer->video.vid->rc_layer_control.max_num_temporal_layers; @@ -1903,7 +1904,7 @@ radv_enc_params(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKHR * RADEON_ENC_CS(chroma_va >> 32); RADEON_ENC_CS(chroma_va & 0xffffffff); RADEON_ENC_CS(src_img->planes[0].surface.u.gfx9.surf_pitch); // luma pitch - RADEON_ENC_CS(src_img->planes[1].surface.u.gfx9.surf_pitch); // chroma pitch + RADEON_ENC_CS(src_img->plane_count > 1 ? src_img->planes[1].surface.u.gfx9.surf_pitch : 0); // chroma pitch RADEON_ENC_CS(src_img->planes[0].surface.u.gfx9.swizzle_mode); // swizzle mode if (pdev->enc_hw_ver < RADV_VIDEO_ENC_HW_5) @@ -2103,35 +2104,109 @@ radv_enc_op_preset(struct radv_cmd_buffer *cmd_buffer, const VkVideoEncodeInfoKH RADEON_ENC_END(); } +static uint32_t +radv_get_encode_color_volume(VkVideoEncodeRgbModelConversionFlagBitsVALVE model) +{ + switch (model) { + case VK_VIDEO_ENCODE_RGB_MODEL_CONVERSION_YCBCR_709_BIT_VALVE: + return RENCODE_COLOR_VOLUME_G22_BT709; + case VK_VIDEO_ENCODE_RGB_MODEL_CONVERSION_YCBCR_2020_BIT_VALVE: + return RENCODE_COLOR_VOLUME_G2084_BT2020; + default: + UNREACHABLE("Unsupported rgb model conversion."); + } +} + +static uint32_t +radv_get_encode_color_range(VkVideoEncodeRgbRangeCompressionFlagBitsVALVE range) +{ + switch (range) { + case VK_VIDEO_ENCODE_RGB_RANGE_COMPRESSION_FULL_RANGE_BIT_VALVE: + return RENCODE_COLOR_RANGE_FULL; + case VK_VIDEO_ENCODE_RGB_RANGE_COMPRESSION_NARROW_RANGE_BIT_VALVE: + return RENCODE_COLOR_RANGE_STUDIO; + default: + UNREACHABLE("Unsupported rgb range compression."); + } +} + +static uint32_t +radv_get_encode_chroma_location(VkVideoEncodeRgbChromaOffsetFlagBitsVALVE location) +{ + switch (location) { + case VK_VIDEO_ENCODE_RGB_CHROMA_OFFSET_COSITED_EVEN_BIT_VALVE: + return RENCODE_CHROMA_LOCATION_CO_SITE; + case VK_VIDEO_ENCODE_RGB_CHROMA_OFFSET_MIDPOINT_BIT_VALVE: + return RENCODE_CHROMA_LOCATION_INTERSTITIAL; + default: + UNREACHABLE("Unsupported chroma offset."); + } +} + 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 radv_video_session *vid = cmd_buffer->video.vid; + uint32_t color_space; uint32_t color_bit_depth; uint32_t color_packing_format; + uint32_t chroma_subsampling; switch (vid->vk.picture_format) { + case VK_FORMAT_B8G8R8A8_UNORM: + color_bit_depth = RENCODE_COLOR_BIT_DEPTH_8_BIT; + color_packing_format = RENCODE_COLOR_PACKING_FORMAT_A8R8G8B8; + chroma_subsampling = RENCODE_CHROMA_SUBSAMPLING_4_4_4; + color_space = RENCODE_COLOR_SPACE_RGB; + break; + case VK_FORMAT_R8G8B8A8_UNORM: + color_bit_depth = RENCODE_COLOR_BIT_DEPTH_8_BIT; + color_packing_format = RENCODE_COLOR_PACKING_FORMAT_A8B8G8R8; + chroma_subsampling = RENCODE_CHROMA_SUBSAMPLING_4_4_4; + color_space = RENCODE_COLOR_SPACE_RGB; + break; + case VK_FORMAT_A2B10G10R10_UNORM_PACK32: + color_bit_depth = RENCODE_COLOR_BIT_DEPTH_10_BIT; + color_packing_format = RENCODE_COLOR_PACKING_FORMAT_A2B10G10R10; + chroma_subsampling = RENCODE_CHROMA_SUBSAMPLING_4_4_4; + color_space = RENCODE_COLOR_SPACE_RGB; + break; + case VK_FORMAT_A2R10G10B10_UNORM_PACK32: + color_bit_depth = RENCODE_COLOR_BIT_DEPTH_10_BIT; + color_packing_format = RENCODE_COLOR_PACKING_FORMAT_A2R10G10B10; + chroma_subsampling = RENCODE_CHROMA_SUBSAMPLING_4_4_4; + color_space = RENCODE_COLOR_SPACE_RGB; + break; 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; + chroma_subsampling = RENCODE_CHROMA_SUBSAMPLING_4_2_0; + color_space = RENCODE_COLOR_SPACE_YUV; 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; + chroma_subsampling = RENCODE_CHROMA_SUBSAMPLING_4_2_0; + color_space = RENCODE_COLOR_SPACE_YUV; break; default: assert(0); return; } + // Color volume should match between input and output + uint32_t color_volume = RENCODE_COLOR_VOLUME_G22_BT709; + if (vid->vk.perform_rgb_conversion) + color_volume = radv_get_encode_color_volume(vid->vk.rgb_conv.rgb_model); + RADEON_ENC_BEGIN(pdev->vcn_enc_cmds.input_format); - RADEON_ENC_CS(0); // input color volume - RADEON_ENC_CS(0); // input color space - RADEON_ENC_CS(RENCODE_COLOR_RANGE_STUDIO); // input color range - RADEON_ENC_CS(0); // input chroma subsampling - RADEON_ENC_CS(0); // input chroma location + RADEON_ENC_CS(color_volume); // input color volume + RADEON_ENC_CS(color_space); // input color space + RADEON_ENC_CS(0); // input color range (ignored) + RADEON_ENC_CS(chroma_subsampling); // input chroma subsampling + RADEON_ENC_CS(0); // input chroma location (ignored for RGB) RADEON_ENC_CS(color_bit_depth); // input color bit depth RADEON_ENC_CS(color_packing_format); // input color packing format RADEON_ENC_END(); @@ -2166,12 +2241,21 @@ radv_enc_output_format(struct radv_cmd_buffer *cmd_buffer) return; } + uint32_t color_volume = 0; + uint32_t color_range = RENCODE_COLOR_RANGE_STUDIO; + uint32_t chroma_location = 0; + if (vid->vk.perform_rgb_conversion) { + color_volume = radv_get_encode_color_volume(vid->vk.rgb_conv.rgb_model); + color_range = radv_get_encode_color_range(vid->vk.rgb_conv.rgb_range); + chroma_location = radv_get_encode_chroma_location(vid->vk.rgb_conv.y_chroma_offset); + } + RADEON_ENC_BEGIN(pdev->vcn_enc_cmds.output_format); - RADEON_ENC_CS(0); // output color volume - RADEON_ENC_CS(RENCODE_COLOR_RANGE_STUDIO); // output color range + RADEON_ENC_CS(color_volume); // output color volume + RADEON_ENC_CS(color_range); // output color range if (pdev->enc_hw_ver >= RADV_VIDEO_ENC_HW_5) RADEON_ENC_CS(0); // output chroma subsampling - RADEON_ENC_CS(0); // output chroma location + RADEON_ENC_CS(chroma_location); // output chroma location RADEON_ENC_CS(color_bit_depth); // output color bit depth RADEON_ENC_END(); } diff --git a/src/vulkan/runtime/vk_video.c b/src/vulkan/runtime/vk_video.c index 02dcf81dde5..638e10793a6 100644 --- a/src/vulkan/runtime/vk_video.c +++ b/src/vulkan/runtime/vk_video.c @@ -108,6 +108,8 @@ vk_video_session_init(struct vk_device *device, vk_find_struct_const(create_info->pVideoProfile->pNext, VIDEO_ENCODE_USAGE_INFO_KHR); const struct VkVideoEncodeSessionIntraRefreshCreateInfoKHR *intra_refresh = vk_find_struct_const(create_info->pNext, VIDEO_ENCODE_SESSION_INTRA_REFRESH_CREATE_INFO_KHR); + const struct VkVideoEncodeProfileRgbConversionInfoVALVE *rgb_profile_info = + vk_find_struct_const(create_info->pVideoProfile->pNext, VIDEO_ENCODE_PROFILE_RGB_CONVERSION_INFO_VALVE); if (encode_usage_profile) { vid->enc_usage.video_usage_hints = encode_usage_profile->videoUsageHints; vid->enc_usage.video_content_hints = encode_usage_profile->videoContentHints; @@ -119,6 +121,16 @@ vk_video_session_init(struct vk_device *device, } if (intra_refresh) vid->intra_refresh_mode = intra_refresh->intraRefreshMode; + if (rgb_profile_info && rgb_profile_info->performEncodeRgbConversion) { + const struct VkVideoEncodeSessionRgbConversionCreateInfoVALVE *rgb_info = + vk_find_struct_const(create_info->pNext, VIDEO_ENCODE_SESSION_RGB_CONVERSION_CREATE_INFO_VALVE); + + vid->perform_rgb_conversion = true; + vid->rgb_conv.rgb_model = rgb_info->rgbModel; + vid->rgb_conv.rgb_range = rgb_info->rgbRange; + vid->rgb_conv.x_chroma_offset = rgb_info->xChromaOffset; + vid->rgb_conv.y_chroma_offset = rgb_info->yChromaOffset; + } } return VK_SUCCESS; diff --git a/src/vulkan/runtime/vk_video.h b/src/vulkan/runtime/vk_video.h index 41c8c9bb22e..e9308ff0cdd 100644 --- a/src/vulkan/runtime/vk_video.h +++ b/src/vulkan/runtime/vk_video.h @@ -91,6 +91,14 @@ struct vk_video_session { uint32_t max_active_ref_pics; VkVideoEncodeIntraRefreshModeFlagBitsKHR intra_refresh_mode; + bool perform_rgb_conversion; + struct { + VkVideoEncodeRgbModelConversionFlagBitsVALVE rgb_model; + VkVideoEncodeRgbRangeCompressionFlagBitsVALVE rgb_range; + VkVideoEncodeRgbChromaOffsetFlagBitsVALVE x_chroma_offset; + VkVideoEncodeRgbChromaOffsetFlagBitsVALVE y_chroma_offset; + } rgb_conv; + struct { VkVideoEncodeUsageFlagsKHR video_usage_hints; VkVideoEncodeContentFlagsKHR video_content_hints;