Import dmabuf from OpenGL into Vulkan
Andreas Streichardt
andreas at mop.koeln
Mon May 27 07:49:55 UTC 2024
Hi,
I am trying to import a texture from OpenGL into Vulkan. I am using https://gitlab.com/blaztinn/dma-buf-texture-sharing for the OpenGL side. When I start the server and its client as it is it works as expected. Now I want to reproduce the same using a vuikan client (while using the OpenGL side for the server part). My base code for this experiment is this: https://vulkan-tutorial.com/code/26_texture_mapping.cpp. I replaced the texture loading with this code:
VkSubresourceLayout layout = {};
layout.offset = texture_storage_metadata.offset;
layout.rowPitch = texture_storage_metadata.stride;
VkImageDrmFormatModifierExplicitCreateInfoEXT modifier_explicit_info = {};
modifier_explicit_info.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT;
// linear => 0
modifier_explicit_info.drmFormatModifier = 0;
modifier_explicit_info.drmFormatModifierPlaneCount = 1;
modifier_explicit_info.pPlaneLayouts = &layout;
VkExternalMemoryImageCreateInfo external_memory_image_create_info = {};
external_memory_image_create_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
external_memory_image_create_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
VkImageCreateInfo image_info = {};
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image_info.imageType = VK_IMAGE_TYPE_2D;
image_info.format = DMABUF_FORMAT;
image_info.extent.width = 256;
image_info.extent.height = 256;
image_info.extent.depth = 1;
image_info.mipLevels = 1;
image_info.arrayLayers = 1;
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
image_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
modifier_explicit_info.pNext = &external_memory_image_create_info;
image_info.pNext = &modifier_explicit_info;
if (vkCreateImage(device, &image_info, nullptr, &textureImage) != VK_SUCCESS)
{
throw std::runtime_error("failed to create image!");
}
VkMemoryFdPropertiesKHR memory_fd_properties = {};
memory_fd_properties.sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR;
auto vkGetMemoryFdPropertiesKHR = (PFN_vkGetMemoryFdPropertiesKHR)vkGetInstanceProcAddr(instance, "vkGetMemoryFdPropertiesKHR");
VkResult result;
result = vkGetMemoryFdPropertiesKHR(device, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, texture_dmabuf_fd, &memory_fd_properties);
if (result != VK_SUCCESS)
{
std::stringstream ss;
ss << "failed to get memory fd properties! " << result;
throw std::runtime_error(ss.str());
}
VkMemoryRequirements memRequirements;
vkGetImageMemoryRequirements(device, textureImage, &memRequirements);
VkImportMemoryFdInfoKHR import_memory_fd_info = {};
import_memory_fd_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
import_memory_fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
import_memory_fd_info.fd = texture_dmabuf_fd;
VkMemoryDedicatedAllocateInfo dedicated_allocate_info = {};
dedicated_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
dedicated_allocate_info.image = textureImage;
VkMemoryAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits & memory_fd_properties.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
import_memory_fd_info.pNext = &dedicated_allocate_info;
allocInfo.pNext = &import_memory_fd_info;
VkDeviceMemory imageMemory;
if (vkAllocateMemory(device, &allocInfo, nullptr, &imageMemory) != VK_SUCCESS)
{
throw std::runtime_error("failed to allocate image memory!");
}
// close(texture_dmabuf_fd);
if (vkBindImageMemory(device, textureImage, imageMemory, 0) != VK_SUCCESS)
{
throw std::runtime_error("failed to bind image memory!");
}
transitionImageLayout(textureImage, DMABUF_FORMAT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
and added the required extensions. I am not getting any validation errors. As you can see I completely ignore the drm modifier right now and just hardcode it to 0. The reason for that is that when I start the server using my GPU I am getting DRM_MOD_INVALID. I am not sure how to work with this case? The resulting image is distorted :( I am assuming that the tiling is wrong. I can see that the colors are changing but large parts of the image are just memory garbage.
When I start the client using
MESA_LOADER_DRIVER_OVERRIDE=zink ./dmabufshare server
the opengl side is reporting a modifier of 0 (linear) and the vulkan side works properly. I am not sure how to handle this using the real GPU. I am wondering why the OpenGL side is working fine when I use the client in OpenGL. It seems that something in the driver is properly handling DRM_MOD_INVALID.
When I try to pass in the DRM_MOD_INVALID modifier in the vulkan code I get a properly rendered image but I am also getting validation errors because the modifier is not listed in the supported drm modifiers for my device.
I am a bit lost right now. How can I make this work properly?
Mesa: 24.1
GPU: Vega 8 (AMD 4900HS)
Best regards,
Andreas Streichardt
More information about the mesa-users
mailing list