zink: Query external memory handle type compatibility

Zink sets multiple external memory handle types(like Opaque FD,DMA-BUF)
without confirming if the Vulkan driver actually supports them. This may lead
to failures when attempting to allocate external memory with vkAllocateMemory.

This patch introduces query_external_memory_compatibility() to verify
handle type support via VkPhysicalDeviceImageFormatProperties2.
Combine handle types only if they are compatible; otherwise, use a single
supported type as a fallback.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40212>
This commit is contained in:
Lakshman Chandu Kondreddy 2026-05-22 13:41:39 +05:30 committed by Marge Bot
parent cafa22142b
commit 9ff0cd7b4d

View file

@ -1328,6 +1328,118 @@ create_buffer(struct zink_screen *screen, struct zink_resource_object *obj,
return roc_success;
}
/* Query external memory support with the exact VkImageCreateInfo which will be
* used for vkCreateImage. This has to happen after eval_ici(), since tiling,
* usage, flags, and the selected DRM modifier may change while Zink searches
* for a supported image configuration.
*/
static bool
get_external_image_handle_type_props(struct zink_screen *screen,
const VkImageCreateInfo *ici,
uint64_t modifier,
VkExternalMemoryHandleTypeFlagBits handle_type,
VkExternalMemoryProperties *external_props)
{
if (!VKSCR(GetPhysicalDeviceImageFormatProperties2))
return false;
VkPhysicalDeviceExternalImageFormatInfo external_info = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
.pNext = ici->pNext,
.handleType = handle_type,
};
VkPhysicalDeviceImageFormatInfo2 format_info = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
.pNext = &external_info,
.format = ici->format,
.type = ici->imageType,
.tiling = ici->tiling,
.usage = ici->usage,
.flags = ici->flags,
};
VkPhysicalDeviceImageDrmFormatModifierInfoEXT modifier_info;
if (modifier != DRM_FORMAT_MOD_INVALID) {
modifier_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT;
modifier_info.pNext = format_info.pNext;
modifier_info.drmFormatModifier = modifier;
modifier_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
modifier_info.queueFamilyIndexCount = 0;
modifier_info.pQueueFamilyIndices = NULL;
format_info.pNext = &modifier_info;
}
VkExternalImageFormatProperties external_format_props = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES,
};
VkImageFormatProperties2 format_props = {
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
.pNext = &external_format_props,
};
VkResult result = VKSCR(GetPhysicalDeviceImageFormatProperties2)(screen->pdev,
&format_info,
&format_props);
if (result != VK_SUCCESS)
return false;
*external_props = external_format_props.externalMemoryProperties;
return true;
}
/* Only keep combined OPAQUE_FD|DMA_BUF image exports when the Vulkan driver
* reports that the two handle types are compatible for this final image
* configuration. The filtered export_types are later used by vkAllocateMemory.
*/
static void
filter_external_image_export_types(struct zink_screen *screen,
const VkImageCreateInfo *ici,
uint64_t modifier,
struct mem_alloc_info *alloc_info)
{
const VkExternalMemoryHandleTypeFlags opaque =
ZINK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_BIT;
const VkExternalMemoryHandleTypeFlags dmabuf =
VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
if ((alloc_info->export_types & (opaque | dmabuf)) != (opaque | dmabuf))
return;
VkExternalMemoryProperties dmabuf_props = {0};
bool dmabuf_supported = get_external_image_handle_type_props(screen, ici,
modifier,
dmabuf,
&dmabuf_props) &&
(dmabuf_props.externalMemoryFeatures &
VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT);
bool compatible = dmabuf_supported &&
(dmabuf_props.compatibleHandleTypes & opaque);
/* If this image imports external memory, external is the handle type used
* for the import while export_types may also request extra export handles.
* Check that memory imported with external can be re-exported with those
* extra handle types before keeping the combined export_types mask.
*/
if (compatible && alloc_info->external) {
VkExternalMemoryProperties import_props = {0};
compatible = get_external_image_handle_type_props(screen, ici, modifier,
alloc_info->external,
&import_props) &&
(import_props.exportFromImportedHandleTypes &
(alloc_info->export_types & ~alloc_info->external));
}
if (compatible)
return;
/* Imported memory must keep its original handle type. Replacing an opaque-fd
* import with dma-buf would make vkAllocateMemory import the fd incorrectly.
*/
if (alloc_info->external)
alloc_info->export_types &= alloc_info->external;
else
alloc_info->export_types &= dmabuf_supported ? dmabuf : opaque;
}
struct image_pnext_state {
VkExternalMemoryImageCreateInfo emici;
VkImageDrmFormatModifierExplicitCreateInfoEXT idfmeci;
@ -1356,6 +1468,8 @@ setup_image_pnext(struct zink_screen *screen, const struct pipe_resource *templ,
alloc_info->export_types &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
}
filter_external_image_export_types(screen, ici, mod, alloc_info);
if (alloc_info->shared || alloc_info->external) {
s->emici.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
s->emici.pNext = ici->pNext;