From 6c83e3ea98b7e2c8972e9897c5971f78c69a7138 Mon Sep 17 00:00:00 2001 From: Bas Nieuwenhuizen Date: Mon, 16 Nov 2020 04:00:29 +0100 Subject: [PATCH] radv: Add format modifier format queries. Reviewed-By: Chad Versace Part-of: --- src/amd/vulkan/radv_formats.c | 217 ++++++++++++++++++++++++++++++++-- 1 file changed, 208 insertions(+), 9 deletions(-) diff --git a/src/amd/vulkan/radv_formats.c b/src/amd/vulkan/radv_formats.c index 25d147adfe3..450846f76dd 100644 --- a/src/amd/vulkan/radv_formats.c +++ b/src/amd/vulkan/radv_formats.c @@ -23,16 +23,19 @@ */ #include "radv_private.h" +#include "radv_debug.h" #include "vk_format.h" #include "sid.h" #include "vk_util.h" +#include "drm-uapi/drm_fourcc.h" #include "util/half_float.h" #include "util/format_srgb.h" #include "util/format_r11g11b10f.h" #include "util/format_rgb9e5.h" +#include "vulkan/util/vk_format.h" uint32_t radv_translate_buffer_dataformat(const struct vk_format_description *desc, int first_non_void) @@ -1119,6 +1122,167 @@ void radv_GetPhysicalDeviceFormatProperties( pFormatProperties); } +static const struct ac_modifier_options radv_modifier_options = { + .dcc = false, + .dcc_retile = false, +}; + +static VkFormatFeatureFlags +radv_get_modifier_flags(struct radv_physical_device *dev, + VkFormat format, uint64_t modifier, + const VkFormatProperties *props) +{ + VkFormatFeatureFlags features; + + if (vk_format_is_compressed(format) || vk_format_is_depth_or_stencil(format)) + return 0; + + if (modifier == DRM_FORMAT_MOD_LINEAR) + features = props->linearTilingFeatures; + else + features = props->optimalTilingFeatures; + + if (modifier != DRM_FORMAT_MOD_LINEAR && vk_format_get_plane_count(format) > 1) + return 0; + + if (ac_modifier_has_dcc(modifier)) { + features &= ~VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; + + if (dev->instance->debug_flags & RADV_DEBUG_NO_DCC) + return 0; + } + + return features; +} + +static void radv_list_drm_format_modifiers(struct radv_physical_device *dev, + VkFormat format, + VkFormatProperties2 *pFormatProperties) +{ + VkDrmFormatModifierPropertiesListEXT *mod_list = + vk_find_struct(pFormatProperties, DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT); + unsigned mod_count; + + if (!mod_list) + return; + + if (vk_format_is_compressed(format) || vk_format_is_depth_or_stencil(format)) { + mod_list->drmFormatModifierCount = 0; + return; + } + + ac_get_supported_modifiers(&dev->rad_info, &radv_modifier_options, + vk_format_to_pipe_format(format), &mod_count, NULL); + if (!mod_list->pDrmFormatModifierProperties) { + mod_list->drmFormatModifierCount = mod_count; + return; + } + + mod_count = MIN2(mod_count, mod_list->drmFormatModifierCount); + + uint64_t *mods = malloc(mod_count * sizeof(uint64_t)); + if (!mods) { + /* We can't return an error here ... */ + mod_list->drmFormatModifierCount = 0; + return; + } + ac_get_supported_modifiers(&dev->rad_info, &radv_modifier_options, + vk_format_to_pipe_format(format), &mod_count, mods); + + mod_list->drmFormatModifierCount = 0; + for (unsigned i = 0; i < mod_count; ++i) { + VkFormatFeatureFlags features = + radv_get_modifier_flags(dev, format, mods[i], &pFormatProperties->formatProperties); + unsigned planes = vk_format_get_plane_count(format); + if (planes == 1) { + if (ac_modifier_has_dcc_retile(mods[i])) + planes = 3; + else if (ac_modifier_has_dcc(mods[i])) + planes = 2; + } + + if (!features) + continue; + + mod_list->pDrmFormatModifierProperties[mod_list->drmFormatModifierCount].drmFormatModifier = mods[i]; + mod_list->pDrmFormatModifierProperties[mod_list->drmFormatModifierCount].drmFormatModifierPlaneCount = planes; + mod_list->pDrmFormatModifierProperties[mod_list->drmFormatModifierCount].drmFormatModifierTilingFeatures = features; + + ++mod_list->drmFormatModifierCount; + } + + free(mods); +} + + +static VkResult radv_check_modifier_support(struct radv_physical_device *dev, + const VkPhysicalDeviceImageFormatInfo2 *info, + VkImageFormatProperties *props, + VkFormat format, + uint64_t modifier) +{ + if (info->type != VK_IMAGE_TYPE_2D) + return VK_ERROR_FORMAT_NOT_SUPPORTED; + + /* We did not add modifiers for sparse textures. */ + if (info->flags & (VK_IMAGE_CREATE_SPARSE_BINDING_BIT | + VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | + VK_IMAGE_CREATE_SPARSE_ALIASED_BIT)) + return VK_ERROR_FORMAT_NOT_SUPPORTED; + + /* + * Need to check the modifier is supported in general: + * "If the drmFormatModifier is incompatible with the parameters specified + * in VkPhysicalDeviceImageFormatInfo2 and its pNext chain, then + * vkGetPhysicalDeviceImageFormatProperties2 returns VK_ERROR_FORMAT_NOT_SUPPORTED. + * The implementation must support the query of any drmFormatModifier, + * including unknown and invalid modifier values." + */ + VkDrmFormatModifierPropertiesListEXT mod_list = { + .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT, + }; + + VkFormatProperties2 format_props2 = { + .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, + .pNext = &mod_list + }; + + radv_GetPhysicalDeviceFormatProperties2(radv_physical_device_to_handle(dev), format, &format_props2); + + if (!mod_list.drmFormatModifierCount) + return VK_ERROR_FORMAT_NOT_SUPPORTED; + + mod_list.pDrmFormatModifierProperties = calloc(mod_list.drmFormatModifierCount, sizeof(*mod_list.pDrmFormatModifierProperties)); + if (!mod_list.pDrmFormatModifierProperties) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + radv_GetPhysicalDeviceFormatProperties2(radv_physical_device_to_handle(dev), format, &format_props2); + + bool found = false; + for (uint32_t i = 0; i < mod_list.drmFormatModifierCount && !found; ++i) + if (mod_list.pDrmFormatModifierProperties[i].drmFormatModifier == modifier) + found = true; + + free(mod_list.pDrmFormatModifierProperties); + + if (!found) + return VK_ERROR_FORMAT_NOT_SUPPORTED; + + if (ac_modifier_has_dcc(modifier) && + !radv_are_formats_dcc_compatible(dev, info->pNext, format, info->flags)) + return VK_ERROR_FORMAT_NOT_SUPPORTED; + + /* We can expand this as needed and implemented but there is not much demand + * for more. */ + if (ac_modifier_has_dcc(modifier)) { + props->maxMipLevels = 1; + props->maxArrayLayers = 1; + } + /* We don't support MSAA for modifiers */ + props->sampleCounts &= VK_SAMPLE_COUNT_1_BIT; + return VK_SUCCESS; +} + void radv_GetPhysicalDeviceFormatProperties2( VkPhysicalDevice physicalDevice, VkFormat format, @@ -1129,6 +1293,8 @@ void radv_GetPhysicalDeviceFormatProperties2( radv_physical_device_get_format_properties(physical_device, format, &pFormatProperties->formatProperties); + + radv_list_drm_format_modifiers(physical_device, format, pFormatProperties); } static VkResult radv_get_image_format_properties(struct radv_physical_device *physical_device, @@ -1145,13 +1311,26 @@ static VkResult radv_get_image_format_properties(struct radv_physical_device *ph VkSampleCountFlags sampleCounts = VK_SAMPLE_COUNT_1_BIT; const struct vk_format_description *desc = vk_format_description(format); enum chip_class chip_class = physical_device->rad_info.chip_class; + VkImageTiling tiling = info->tiling; + const VkPhysicalDeviceImageDrmFormatModifierInfoEXT *mod_info = + vk_find_struct_const(info->pNext, PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT); + VkResult result = VK_ERROR_FORMAT_NOT_SUPPORTED; + + if (mod_info) { + tiling = mod_info->drmFormatModifier == DRM_FORMAT_MOD_LINEAR ? + VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL; + } radv_physical_device_get_format_properties(physical_device, format, &format_props); - if (info->tiling == VK_IMAGE_TILING_LINEAR) { + if (tiling == VK_IMAGE_TILING_LINEAR) { format_feature_flags = format_props.linearTilingFeatures; - } else if (info->tiling == VK_IMAGE_TILING_OPTIMAL) { + } else if (tiling == VK_IMAGE_TILING_OPTIMAL) { format_feature_flags = format_props.optimalTilingFeatures; + } else if (tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) { + format_feature_flags = radv_get_modifier_flags(physical_device, format, + mod_info->drmFormatModifier, + &format_props); } else { unreachable("bad VkImageTiling"); } @@ -1200,7 +1379,7 @@ static VkResult radv_get_image_format_properties(struct radv_physical_device *ph maxArraySize = 1; } - if (info->tiling == VK_IMAGE_TILING_OPTIMAL && + if (tiling == VK_IMAGE_TILING_OPTIMAL && info->type == VK_IMAGE_TYPE_2D && (format_feature_flags & (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) && @@ -1208,7 +1387,7 @@ static VkResult radv_get_image_format_properties(struct radv_physical_device *ph sampleCounts |= VK_SAMPLE_COUNT_2_BIT | VK_SAMPLE_COUNT_4_BIT | VK_SAMPLE_COUNT_8_BIT; } - if (info->tiling == VK_IMAGE_TILING_LINEAR && + if (tiling == VK_IMAGE_TILING_LINEAR && (format == VK_FORMAT_R32G32B32_SFLOAT || format == VK_FORMAT_R32G32B32_SINT || format == VK_FORMAT_R32G32B32_UINT)) { @@ -1306,6 +1485,14 @@ static VkResult radv_get_image_format_properties(struct radv_physical_device *ph .maxResourceSize = UINT32_MAX, }; + if (mod_info) { + result = radv_check_modifier_support(physical_device, info, + pImageFormatProperties, + format, mod_info->drmFormatModifier); + if (result != VK_SUCCESS) + goto unsupported; + } + return VK_SUCCESS; unsupported: *pImageFormatProperties = (VkImageFormatProperties) { @@ -1316,7 +1503,7 @@ unsupported: .maxResourceSize = 0, }; - return VK_ERROR_FORMAT_NOT_SUPPORTED; + return result; } VkResult radv_GetPhysicalDeviceImageFormatProperties( @@ -1359,16 +1546,28 @@ get_external_image_format_properties(struct radv_physical_device *physical_devic return; switch (handleType) { - case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT: case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT: + if (pImageFormatInfo->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) + break; + switch (pImageFormatInfo->type) { case VK_IMAGE_TYPE_2D: - flags = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT|VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; + flags = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT |VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; + + compat_flags = export_flags = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + break; + default: + break; + } + break; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT: + switch (pImageFormatInfo->type) { + case VK_IMAGE_TYPE_2D: + flags = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT |VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; if (pImageFormatInfo->tiling != VK_IMAGE_TILING_LINEAR) flags |= VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT; - compat_flags = export_flags = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT | - VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; + compat_flags = export_flags = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; break; default: break;