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