Reputation: 1
I am trying to make VK_KHR_EXTERNAL_MEMORY_EXTENSION work.
Similar to this
https://stackoverflow.com/questions/50020878/how-to-correctly-share-vkdevicememory-what-is-vkexternalmemorybuffercreateinfok/
It is working well when the import and the export are done in the same process.
But I am not sure if what I try has been already done, I cannot find any example and I don't think that the test code is testing that too. I want one process that creates a VkBuffer, populate it and export it / share the FD. After, IN ANOTHER PROCESS, I try to import that VkBuffer.
I have different trouble, depending on whether it is tested under Windows or Linux. Under Linux, I got VK_OUT_OF_MEMORY at vkAllocateMemory call. On Windows, I sometimes have no error but only '0' or noise as payload, sometime error about a mismatch in the size of the memory (but a size that exists somewhere else in the producer app) so look like if the FD (HANDLE) was referring to another 'random' resource. I also tried to call DuplicatHandle on 'consumer / import side' but in that case, I receive an error about "invalid Handle" from DuplicatHandle.
Here the config structure used on export side: VkBufferCreateInfo, VkExternalMemoryBufferCreateInfo, VkMemoryDedicatedRequirementsKHR, VkMemoryDedicatedAllocateInfo, VkExportMemoryAllocateInfoKHR, VkGetMemoryWin32HandleKHR / VkGetMemoryFdKHR, VkMemoryAllocateInfo
Here the config structire used on import side: VkExternalMemoryBufferCreateInfo, VkBufferCreateInfo, VkMemoryDedicatedAllocateInfo, VkImportMemoryWin32HandleInfoKHR / VkImportMemoryFdInfoKHR, VkMemoryAllocateInfo, VkMemoryDedicatedRequirementsKHR
I tried with and without MemoryDedicated.
Anyway, vkGetBufferMemoryRequirements2 repport that prefersDedicatedAllocation and requiresDedicatedAllocation to false.
I expect to acces to the payload as it was on producer side. Thanks
Here some code:
int64_t createBuffer(VkPhysicalDevice& p_vkPhysicalDevice, VkDevice& p_vkDevice, VkDeviceSize size,
VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& p_refVkBuffer, VkDeviceMemory& bufferMemory,
VkSharingMode p_VkSharingMode, uint32_t* p_pVkQueueFamliyIndices)
{
//PRINTLN("createBuffer size: %d", size);
if (size == 0)
{
ERROR_PRINTLN("createBuffer with size 0 is illegal.");
return -1;
}
VkBufferCreateInfo bufferInfo = {};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = size;
bufferInfo.usage = usage;
bufferInfo.sharingMode = p_VkSharingMode; //VK_SHARING_MODE_EXCLUSIVE;
if (p_pVkQueueFamliyIndices)
{
bufferInfo.queueFamilyIndexCount = 2;
bufferInfo.pQueueFamilyIndices = p_pVkQueueFamliyIndices;
}
#if SUPPORT_EXTERNAL_MEMORY
VkExternalMemoryBufferCreateInfo externalMemBufferCreateInfo = {};
externalMemBufferCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
externalMemBufferCreateInfo.handleTypes = GetFdType();
bufferInfo.pNext = &externalMemBufferCreateInfo;
#endif
VK_CHECK_RESULT(vkCreateBuffer(p_vkDevice, &bufferInfo, nullptr, &p_refVkBuffer));
VkMemoryDedicatedRequirementsKHR dedicatedRequirements = {};
dedicatedRequirements.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR;
dedicatedRequirements.requiresDedicatedAllocation = VK_TRUE;
VkMemoryRequirements2 memoryRequirements =
{
.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
.pNext = &dedicatedRequirements,
};
const VkBufferMemoryRequirementsInfo2 bufferRequirementsInfo =
{
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,
.pNext = NULL,
.buffer = p_refVkBuffer
};
vkGetBufferMemoryRequirements2(p_vkDevice, &bufferRequirementsInfo, &memoryRequirements);
PRINTLN("prefersDedicatedAllocation: %d requiresDedicatedAllocation: %d",
dedicatedRequirements.prefersDedicatedAllocation, dedicatedRequirements.requiresDedicatedAllocation);
#if SUPPORT_EXTERNAL_MEMORY
VkMemoryDedicatedAllocateInfo dedicated_alloc_info = {};
dedicated_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR;
dedicated_alloc_info.pNext = NULL;
dedicated_alloc_info.image = VK_NULL_HANDLE;
dedicated_alloc_info.buffer = p_refVkBuffer;
VkExportMemoryAllocateInfoKHR export_memory_allocate_info = {};
export_memory_allocate_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
export_memory_allocate_info.handleTypes = GetFdType();
export_memory_allocate_info.pNext = &dedicated_alloc_info;
#ifdef _WIN32
WinSecurityAttributes win_security_attributes;
VkExportMemoryWin32HandleInfoKHR export_memory_win32_handle_info = {};
export_memory_win32_handle_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR;
export_memory_win32_handle_info.pAttributes = &win_security_attributes;
export_memory_win32_handle_info.dwAccess = DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE;
//export_memory_win32_handle_info.dwAccess = GENERIC_ALL;
export_memory_win32_handle_info.pNext = &export_memory_allocate_info;
#endif
#endif
VkMemoryAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memoryRequirements.memoryRequirements.size;
allocInfo.memoryTypeIndex = findMemoryType(p_vkPhysicalDevice, memoryRequirements.memoryRequirements.memoryTypeBits, properties);
#if SUPPORT_EXTERNAL_MEMORY
#if _WIN32
allocInfo.pNext = &export_memory_win32_handle_info;
#else
allocInfo.pNext = &export_memory_allocate_info;
#endif
#endif
VK_CHECK_RESULT(vkAllocateMemory(p_vkDevice, &allocInfo, nullptr, &bufferMemory)); // Allocate with CUDA (aka EXTERNAL_MEMORY)
PRINTF("********************* vkAllocateMemory ( %d ) Will Do the initial Bind of the memory (srv side)\r\n", allocInfo.allocationSize);
if(bufferMemory)
{
VK_CHECK_RESULT(vkBindBufferMemory(p_vkDevice, p_refVkBuffer, bufferMemory, 0));
} // No need to re-print error, VK_CHECK_RESULT already done it
return 0;
}
#ifdef _WIN32
HANDLE get_vulkan_memory_handle(VkDevice& p_vkDevice, VkDeviceMemory memory)
{
HANDLE handle;
VkMemoryGetWin32HandleInfoKHR win32_handle_info = {};
win32_handle_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR;
win32_handle_info.handleType = GetFdType();
win32_handle_info.memory = memory;
PFN_vkGetMemoryWin32HandleKHR fct_vkGetMemoryWin32Handle = (PFN_vkGetMemoryWin32HandleKHR)PFN_vkGetMemoryWin32HandleKHR(vkGetDeviceProcAddr(p_vkDevice, "vkGetMemoryWin32HandleKHR"));
fct_vkGetMemoryWin32Handle(p_vkDevice, &win32_handle_info, &handle);
PRINTLN("get_vulkan_memory_handle return: 0x%p", handle);
DWORD info;
bool ret = GetHandleInformation(handle, &info);
PRINTLN("GetHandleInformation ret: %d Info: 0x%X", ret, info);
return handle;
}
HANDLE get_vulkan_semaphore_handle(VkDevice& p_vkDevice, VkSemaphore& sempahore)
{
HANDLE handle;
VkSemaphoreGetWin32HandleInfoKHR win32_handle_info{};
win32_handle_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR;
win32_handle_info.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT;
win32_handle_info.semaphore = sempahore;
//vkGetSemaphoreWin32HandleKHR(p_vkDevice, &win32_handle_info, &handle);
typedef VkResult(*fct_vkGetSemaphoreWin32HandleKHR_t)(VkDevice, const VkSemaphoreGetWin32HandleInfoKHR*, HANDLE*);
fct_vkGetSemaphoreWin32HandleKHR_t fct_vkGetSemaphoreWin32HandleKHR = (fct_vkGetSemaphoreWin32HandleKHR_t)PFN_vkGetSemaphoreWin32HandleKHR(vkGetDeviceProcAddr(p_vkDevice, "vkGetSemaphoreWin32HandleKHR"));
fct_vkGetSemaphoreWin32HandleKHR(p_vkDevice, &win32_handle_info, &handle);
return handle;
}
#else
int get_vulkan_memory_handle(VkDevice& p_vkDevice, VkDeviceMemory memory)
{
int fd;
VkMemoryGetFdInfoKHR fd_info{};
fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR;
fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
fd_info.memory = memory;
//vkGetMemoryFdKHR(p_vkDevice, &fd_info, &fd);
typedef VkResult(*fct_vkGetMemoryFdKHR_t)(VkDevice, const VkMemoryGetFdInfoKHR*, int*);
fct_vkGetMemoryFdKHR_t fct_vkGetMemoryFdKHR = (fct_vkGetMemoryFdKHR_t)PFN_vkGetMemoryFdKHR(vkGetDeviceProcAddr(p_vkDevice, "vkGetMemoryFdKHR"));
fct_vkGetMemoryFdKHR(p_vkDevice, &fd_info, &fd);
PRINTLN("get_vulkan_memory_handle return: 0x%X", fd);
return fd;
}
int get_vulkan_semaphore_handle(VkDevice& p_vkDevice, VkSemaphore& sempahore)
{
int fd;
VkSemaphoreGetFdInfoKHR fd_info{};
fd_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
fd_info.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
fd_info.semaphore = sempahore;
//vkGetSemaphoreFdKHR(p_vkDevice, &fd_info, &fd);
typedef VkResult(*fct_vkGetSemaphoreFdKHR_t)(VkDevice, const VkSemaphoreGetFdInfoKHR*, int*);
fct_vkGetSemaphoreFdKHR_t fct_vkGetSemaphoreFdKHR = (fct_vkGetSemaphoreFdKHR_t)PFN_vkGetSemaphoreFdKHR(vkGetDeviceProcAddr(p_vkDevice, "vkGetSemaphoreFdKHR"));
fct_vkGetSemaphoreFdKHR(p_vkDevice, &fd_info, &fd);
return fd;
}
#endif
VkExternalMemoryHandleTypeFlagBits GetFdType()
{
#if _WIN32
return IsWindows8OrGreater() ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT;
#else
return VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
#endif
}
On the other process, let say consumer / import side, here the related code:
#ifdef _WIN32
unsigned char* GetBufferExtFdMapped(const VkDevice* p_pDev, const VkPhysicalDevice* p_pPhyDev, HANDLE p_fd, size_t p_size)
#else
unsigned char* GetBufferExtFdMapped(const VkDevice* p_pDev, const VkPhysicalDevice* p_pPhyDev, int p_fd, size_t p_size)
#endif
{
VkExternalMemoryBufferCreateInfo stVkExtMemBufCreateInfo = {};
stVkExtMemBufCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
stVkExtMemBufCreateInfo.handleTypes = GetFdType();
// Example: Creating a buffer using the imported memory
VkBufferCreateInfo bufferCreateInfo = {};
bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferCreateInfo.size = p_size; // Size of the buffer
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
bufferCreateInfo.pNext = &stVkExtMemBufCreateInfo;
VK_CHECK_RESULT(vkCreateBuffer(*p_pDev, &bufferCreateInfo, nullptr, &m_ExtFdBuffer));
VkMemoryDedicatedAllocateInfo dedicated_info = {};
dedicated_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR;
dedicated_info.buffer = m_ExtFdBuffer;
#if _WIN32
VkImportMemoryWin32HandleInfoKHR importMemoryOSSpecificHandleInfo = {};
importMemoryOSSpecificHandleInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR;
importMemoryOSSpecificHandleInfo.handle = p_fd;
#else
VkImportMemoryFdInfoKHR importMemoryOSSpecificHandleInfo = {};
importMemoryOSSpecificHandleInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
importMemoryOSSpecificHandleInfo.fd = p_fd; // The file descriptor representing the memory
#endif
importMemoryOSSpecificHandleInfo.handleType = GetFdType();
importMemoryOSSpecificHandleInfo.pNext = &dedicated_info;
VkMemoryAllocateInfo memoryAllocateInfo = {};
memoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
VkMemoryDedicatedRequirementsKHR dedicatedRequirements = {};
dedicatedRequirements.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR;
dedicatedRequirements.requiresDedicatedAllocation = VK_TRUE;
VkMemoryRequirements2 memoryRequirements =
{
.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
.pNext = &dedicatedRequirements,
};
const VkBufferMemoryRequirementsInfo2 bufferRequirementsInfo =
{
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,
.pNext = NULL,
.buffer = m_ExtFdBuffer
};
vkGetBufferMemoryRequirements2(*p_pDev, &bufferRequirementsInfo, &memoryRequirements);
memoryAllocateInfo.pNext = &importMemoryOSSpecificHandleInfo;
////////////////////memoryAllocateInfo.allocationSize = p_size; // Set to the p_size of the memory you want to import
memoryAllocateInfo.allocationSize = memoryRequirements.memoryRequirements.size;
memoryAllocateInfo.memoryTypeIndex = findMemoryType(*p_pPhyDev, memoryRequirements.memoryRequirements.memoryTypeBits,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
m_ExtFdDeviceMemory = NULL;
VK_CHECK_RESULT(vkAllocateMemory(*p_pDev, &memoryAllocateInfo, nullptr, &m_ExtFdDeviceMemory));
if (m_ExtFdDeviceMemory)
{
// Bind the imported memory to the buffer
VK_CHECK_RESULT(vkBindBufferMemory(*p_pDev, m_ExtFdBuffer, m_ExtFdDeviceMemory, 0));
unsigned char* pMappedBuffer = NULL;
VK_CHECK_RESULT_FATAL(vkMapMemory(*p_pDev,
m_ExtFdDeviceMemory,
0, VK_WHOLE_SIZE, 0,
(void**)&pMappedBuffer));
return pMappedBuffer;
}
else
{
vkDestroyBuffer(*p_pDev, m_ExtFdBuffer, nullptr);
return NULL;
}
}
Upvotes: 0
Views: 65