Hi,
I’m currently trying to understand the usage of the VK_KHR_external_memory
(and _win32
) extension in the context of sharing a Vulkan created texture (image) with a Direct3D 11.1 device (created using the same GPU as the Vulkan device, LUIDs do match).
I have a hard time finding documentation or examples about this. The main problem I have is that exceptions are triggered when trying to open the handle I get with D3D11Device1::OpenSharedResource1(). Even with DirectX debug layers on, I only get a rather unhelpful long at memory location
error in the log.
I am at the point where I have a VkImage created, and the underlying VkDeviceMemory allocated with the relevant structure passed for exporting a win32 handle.
format is R8G8B8A8_UNORM and handleType
is set to VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHR
:
VkExternalMemoryImageCreateInfoKHR externalMemoryImageCreateInfo
{
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR,
nullptr,
handleType
};
VkImageCreateInfo imageCreateInfo{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, &externalMemoryImageCreateInfo };
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.extent.width = texture.getWidth();
imageCreateInfo.extent.height = texture.getHeight();
imageCreateInfo.extent.depth = 1;
imageCreateInfo.mipLevels = 1;
imageCreateInfo.arrayLayers = 1;
imageCreateInfo.format = imageFormat;
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.flags = 0;
vkCreateImage(device, &imageCreateInfo, nullptr, &textureImage);
VkMemoryRequirements imageMemoryRequirement{};
vkGetImageMemoryRequirements(device, textureImage, &imageMemoryRequirement);
VkExportMemoryWin32HandleInfoKHR exportMemoryWin32HandleInfo
{ VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR,
nullptr,
nullptr,
DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE ,
nullptr
};
VkExportMemoryAllocateInfo exportMemoryAllocateInfo
{
VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
&exportMemoryWin32HandleInfo,
handleType
};
VkMemoryAllocateInfo imageAllocateInfo
{
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
&exportMemoryAllocateInfo,
imageMemoryRequirement.size,
deviceLocalMemoryIndex.front() //1st in this array is dedicated GPU memory
};
vkAllocateMemory(device, &imageAllocateInfo, nullptr, &imageDeviceMemory);
vkBindImageMemory(device, textureImage, imageDeviceMemory, 0);
transitionImageLayout(textureImage, imageFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
copyBufferToImage(textureDataBufferUpload, textureImage, static_cast<uint32_t>(texture.getWidth()), static_cast<uint32_t>(texture.getHeight()));
I can obtain a HANDLE
that way:
VkMemoryGetWin32HandleInfoKHR getWin32HandleInfo{ VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR, nullptr };
getWin32HandleInfo.memory = imageDeviceMemory;
getWin32HandleInfo.handleType = handleType;
HANDLE output = INVALID_HANDLE_VALUE;
vkGetMemoryWin32HandleKHR(device, &getWin32HandleInfo, &output);
After this, the image is in “transfer optimal layout”, and I do not know if this is important for the resource sharing between the 2 APIs. I attempted to transition the image in the general layout, with the memory read/write access mask, and to the “all commands” pipeline stage, but I have the same problem.
This passes all Vulkan validations. I am clueless about what I am doing wrong. The texture is being created properly on the Vulkan side (I think), as it is readable in a GPU debugger like Nsight and displays the expected content.
Edit: Code that attempt to open handle, and fails:
ID3D11Texture2D* textureFromVulkanResource = nullptr;
const auto openShareResult = D3D11Device1->OpenSharedResource1(shareHandle, __uuidof(ID3D11Texture2D), (void**)&textureFromVulkanResource);