Vulkan/OpenXR: Support VK_KHR_external_memory_win32
This PR add support to use a win32 handle to perform share render result with the OpenXR vulkan instance. This is only possible when the GPU matches. Otherwise a CPU roundtrip will be performed. Pull Request: https://projects.blender.org/blender/blender/pulls/137093
This commit is contained in:
@@ -780,6 +780,14 @@ typedef enum {
|
||||
* will import the memory and copy the image to the swapchain.
|
||||
*/
|
||||
GHOST_kVulkanXRModeFD,
|
||||
|
||||
/**
|
||||
* Use Win32 handle to transfer the render result to the XR swapchain.
|
||||
*
|
||||
* Application renders a view, export the memory in an win32 handle.
|
||||
* GHOST_XrGraphicsBindingVulkan will import the memory and copy the image to the swapchain.
|
||||
*/
|
||||
GHOST_kVulkanXRModeWin32,
|
||||
} GHOST_TVulkanXRModes;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -1070,7 +1070,7 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext()
|
||||
/* External memory extensions. */
|
||||
required_device_extensions.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME);
|
||||
#ifdef _WIN32
|
||||
/* Placeholder to add VK_KHR_external_memory_win32 */
|
||||
optional_device_extensions.push_back(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME);
|
||||
#elif not defined(__APPLE__)
|
||||
optional_device_extensions.push_back(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
|
||||
#endif
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
#include "GHOST_XrGraphicsBindingVulkan.hh"
|
||||
#include "GHOST_Xr_intern.hh"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <vulkan/vulkan_win32.h>
|
||||
#endif
|
||||
|
||||
/** OpenXR/Vulkan specific function pointers. */
|
||||
PFN_xrGetVulkanGraphicsRequirements2KHR
|
||||
GHOST_XrGraphicsBindingVulkan::s_xrGetVulkanGraphicsRequirements2KHR_fn = nullptr;
|
||||
@@ -311,6 +315,11 @@ GHOST_TVulkanXRModes GHOST_XrGraphicsBindingVulkan::choseDataTransferMode()
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
bool has_vk_khr_external_memory_win32_extension = has_extension(
|
||||
VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME);
|
||||
if (has_vk_khr_external_memory_win32_extension) {
|
||||
return GHOST_kVulkanXRModeWin32;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
#else /* UNIX/Linux */
|
||||
bool has_vk_khr_external_memory_fd_extension = has_extension(
|
||||
@@ -408,16 +417,13 @@ void GHOST_XrGraphicsBindingVulkan::submitToSwapchainImage(
|
||||
|
||||
switch (m_data_transfer_mode) {
|
||||
case GHOST_kVulkanXRModeFD:
|
||||
case GHOST_kVulkanXRModeWin32:
|
||||
submitToSwapchainImageGpu(vulkan_image, draw_info);
|
||||
break;
|
||||
|
||||
case GHOST_kVulkanXRModeCPU:
|
||||
submitToSwapchainImageCpu(vulkan_image, draw_info);
|
||||
break;
|
||||
|
||||
default:
|
||||
// assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -553,9 +559,18 @@ void GHOST_XrGraphicsBindingVulkan::submitToSwapchainImageGpu(
|
||||
|
||||
/* Create an image handle */
|
||||
VkExternalMemoryImageCreateInfo vk_external_memory_image_info = {
|
||||
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
|
||||
nullptr,
|
||||
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT};
|
||||
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, nullptr, 0};
|
||||
|
||||
switch (m_data_transfer_mode) {
|
||||
case GHOST_kVulkanXRModeFD:
|
||||
vk_external_memory_image_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
|
||||
break;
|
||||
case GHOST_kVulkanXRModeWin32:
|
||||
vk_external_memory_image_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
|
||||
break;
|
||||
case GHOST_kVulkanXRModeCPU:
|
||||
break;
|
||||
}
|
||||
|
||||
VkImageCreateInfo vk_image_info = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
&vk_external_memory_image_info,
|
||||
@@ -581,16 +596,40 @@ void GHOST_XrGraphicsBindingVulkan::submitToSwapchainImageGpu(
|
||||
vkGetImageMemoryRequirements(m_vk_device, vk_image, &vk_memory_requirements);
|
||||
|
||||
/* Import the memory */
|
||||
VkDeviceMemory device_memory = VK_NULL_HANDLE;
|
||||
VkMemoryDedicatedAllocateInfo vk_memory_dedicated_allocation_info = {
|
||||
VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, nullptr, vk_image, VK_NULL_HANDLE};
|
||||
VkImportMemoryFdInfoKHR import_memory_info = {VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
|
||||
&vk_memory_dedicated_allocation_info,
|
||||
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
|
||||
int(openxr_data.gpu.image_handle)};
|
||||
VkMemoryAllocateInfo allocate_info = {
|
||||
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, &import_memory_info, vk_memory_requirements.size};
|
||||
VkDeviceMemory device_memory;
|
||||
vkAllocateMemory(m_vk_device, &allocate_info, nullptr, &device_memory);
|
||||
switch (m_data_transfer_mode) {
|
||||
case GHOST_kVulkanXRModeFD: {
|
||||
VkImportMemoryFdInfoKHR import_memory_info = {VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
|
||||
&vk_memory_dedicated_allocation_info,
|
||||
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
|
||||
int(openxr_data.gpu.image_handle)};
|
||||
VkMemoryAllocateInfo allocate_info = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
&import_memory_info,
|
||||
vk_memory_requirements.size};
|
||||
vkAllocateMemory(m_vk_device, &allocate_info, nullptr, &device_memory);
|
||||
break;
|
||||
}
|
||||
|
||||
case GHOST_kVulkanXRModeWin32: {
|
||||
#ifdef _WIN32
|
||||
VkImportMemoryWin32HandleInfoKHR import_memory_info = {
|
||||
VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR,
|
||||
&vk_memory_dedicated_allocation_info,
|
||||
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT,
|
||||
HANDLE(openxr_data.gpu.image_handle)};
|
||||
VkMemoryAllocateInfo allocate_info = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
&import_memory_info,
|
||||
vk_memory_requirements.size};
|
||||
vkAllocateMemory(m_vk_device, &allocate_info, nullptr, &device_memory);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case GHOST_kVulkanXRModeCPU:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Bind the imported memory to the image. */
|
||||
vkBindImageMemory(m_vk_device, vk_image, device_memory, openxr_data.gpu.memory_offset);
|
||||
|
||||
@@ -451,6 +451,19 @@ void VKContext::openxr_acquire_framebuffer_image_handler(GHOST_VulkanOpenXRData
|
||||
openxr_data.gpu.memory_offset = exported_memory.memory_offset;
|
||||
break;
|
||||
}
|
||||
|
||||
case GHOST_kVulkanXRModeWin32: {
|
||||
flush_render_graph(RenderGraphFlushFlags::SUBMIT |
|
||||
RenderGraphFlushFlags::WAIT_FOR_COMPLETION |
|
||||
RenderGraphFlushFlags::RENEW_RENDER_GRAPH);
|
||||
VKMemoryExport exported_memory = color_attachment->export_memory(
|
||||
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT);
|
||||
openxr_data.gpu.image_handle = exported_memory.handle;
|
||||
openxr_data.gpu.image_format = to_vk_format(color_attachment->device_format_get());
|
||||
openxr_data.gpu.memory_size = exported_memory.memory_size;
|
||||
openxr_data.gpu.memory_offset = exported_memory.memory_offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,6 +481,14 @@ void VKContext::openxr_release_framebuffer_image_handler(GHOST_VulkanOpenXRData
|
||||
* https://registry.khronos.org/vulkan/specs/latest/man/html/VK_KHR_external_memory_fd.html#_issues
|
||||
*/
|
||||
break;
|
||||
|
||||
case GHOST_kVulkanXRModeWin32:
|
||||
#ifdef _WIN32
|
||||
/* Exported handle isn't consumed during import and should be freed after use. */
|
||||
CloseHandle(HANDLE(openxr_data.gpu.image_handle));
|
||||
openxr_data.gpu.image_handle = 0;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -138,6 +138,11 @@ void VKDevice::init_functions()
|
||||
/* VK_KHR_external_memory_fd */
|
||||
functions.vkGetMemoryFd = LOAD_FUNCTION(vkGetMemoryFdKHR);
|
||||
|
||||
#ifdef _WIN32
|
||||
/* VK_KHR_external_memory_win32 */
|
||||
functions.vkGetMemoryWin32Handle = LOAD_FUNCTION(vkGetMemoryWin32HandleKHR);
|
||||
#endif
|
||||
|
||||
#undef LOAD_FUNCTION
|
||||
}
|
||||
|
||||
@@ -217,10 +222,16 @@ void VKDevice::init_memory_allocator()
|
||||
/* External memory pool */
|
||||
/* Initialize a dummy image create info to find the memory type index that will be used for
|
||||
* allocating. */
|
||||
VkExternalMemoryHandleTypeFlags vk_external_memory_handle_type = 0;
|
||||
#ifdef _WIN32
|
||||
vk_external_memory_handle_type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
|
||||
#else
|
||||
vk_external_memory_handle_type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
|
||||
#endif
|
||||
VkExternalMemoryImageCreateInfo external_image_create_info = {
|
||||
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
|
||||
nullptr,
|
||||
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT};
|
||||
vk_external_memory_handle_type};
|
||||
VkImageCreateInfo image_create_info = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
&external_image_create_info,
|
||||
0,
|
||||
@@ -244,7 +255,7 @@ void VKDevice::init_memory_allocator()
|
||||
vmaFindMemoryTypeIndexForImageInfo(
|
||||
mem_allocator_, &image_create_info, &allocation_create_info, &memory_type_index);
|
||||
|
||||
vma_pools.external_memory_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
|
||||
vma_pools.external_memory_info.handleTypes = vk_external_memory_handle_type;
|
||||
VmaPoolCreateInfo pool_create_info = {};
|
||||
pool_create_info.memoryTypeIndex = memory_type_index;
|
||||
pool_create_info.pMemoryAllocateNext = &vma_pools.external_memory_info;
|
||||
|
||||
@@ -235,6 +235,11 @@ class VKDevice : public NonCopyable {
|
||||
|
||||
/* Extension: VK_KHR_external_memory_fd */
|
||||
PFN_vkGetMemoryFdKHR vkGetMemoryFd = nullptr;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Extension: VK_KHR_external_memory_win32 */
|
||||
PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32Handle = nullptr;
|
||||
#endif
|
||||
} functions;
|
||||
|
||||
struct {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
|
||||
#include "GPU_capabilities.hh"
|
||||
|
||||
/* vk_common needs to be included first to ensure win32 vulkan API is fully initialized, before
|
||||
* working with it. */
|
||||
#include "vk_common.hh"
|
||||
|
||||
#include "vk_texture.hh"
|
||||
|
||||
#include "vk_buffer.hh"
|
||||
@@ -401,14 +405,31 @@ VKMemoryExport VKTexture::export_memory(VkExternalMemoryHandleTypeFlagBits handl
|
||||
BLI_assert_msg(allocation_ != nullptr,
|
||||
"Cannot export memory when the texture is not backed by any device memory.");
|
||||
const VKDevice &device = VKBackend::get().device;
|
||||
VkMemoryGetFdInfoKHR vk_memory_get_fd_info = {VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
|
||||
nullptr,
|
||||
allocation_info_.deviceMemory,
|
||||
handle_type};
|
||||
if (handle_type == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) {
|
||||
VkMemoryGetFdInfoKHR vk_memory_get_fd_info = {VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
|
||||
nullptr,
|
||||
allocation_info_.deviceMemory,
|
||||
handle_type};
|
||||
int fd_handle = 0;
|
||||
device.functions.vkGetMemoryFd(device.vk_handle(), &vk_memory_get_fd_info, &fd_handle);
|
||||
return {uint64_t(fd_handle), allocation_info_.size, allocation_info_.offset};
|
||||
}
|
||||
|
||||
int fd_handle = 0;
|
||||
device.functions.vkGetMemoryFd(device.vk_handle(), &vk_memory_get_fd_info, &fd_handle);
|
||||
return {uint64_t(fd_handle), allocation_info_.size, allocation_info_.offset};
|
||||
#ifdef _WIN32
|
||||
if (handle_type == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) {
|
||||
VkMemoryGetWin32HandleInfoKHR vk_memory_get_win32_handle_info = {
|
||||
VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR,
|
||||
nullptr,
|
||||
allocation_info_.deviceMemory,
|
||||
handle_type};
|
||||
HANDLE win32_handle = nullptr;
|
||||
device.functions.vkGetMemoryWin32Handle(
|
||||
device.vk_handle(), &vk_memory_get_win32_handle_info, &win32_handle);
|
||||
return {uint64_t(win32_handle), allocation_info_.size, allocation_info_.offset};
|
||||
}
|
||||
#endif
|
||||
BLI_assert_unreachable();
|
||||
return {};
|
||||
}
|
||||
|
||||
bool VKTexture::init_internal()
|
||||
@@ -585,9 +606,7 @@ bool VKTexture::allocate()
|
||||
}
|
||||
|
||||
VkExternalMemoryImageCreateInfo external_memory_create_info = {
|
||||
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
|
||||
nullptr,
|
||||
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT};
|
||||
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, nullptr, 0};
|
||||
|
||||
VmaAllocationCreateInfo allocCreateInfo = {};
|
||||
allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
|
||||
@@ -595,6 +614,11 @@ bool VKTexture::allocate()
|
||||
|
||||
if (bool(texture_usage & GPU_TEXTURE_USAGE_MEMORY_EXPORT)) {
|
||||
image_info.pNext = &external_memory_create_info;
|
||||
#ifdef _WIN32
|
||||
external_memory_create_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
|
||||
#else
|
||||
external_memory_create_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
|
||||
#endif
|
||||
allocCreateInfo.pool = device.vma_pools.external_memory;
|
||||
}
|
||||
result = vmaCreateImage(device.mem_allocator_get(),
|
||||
|
||||
Reference in New Issue
Block a user