外部内存和同步

有时,应用程序与 GPU 相关的所有操作并非都在 Vulkan 中完成。在各种情况下,内存是在 Vulkan 范围之外写入或读取的。为了支持这些用例,创建了一组外部内存和同步函数

扩展分解

虽然看起来有很多 VK_KHR_external_* 扩展,但实际上,它们只是很好地将逻辑分离开来。

内存 vs 同步

external_extensions_2.png

有一组扩展用于处理仅内存本身的导入/导出。另一组扩展用于控制内部 Vulkan 命令的同步原语 (VkFenceVkSemaphore)。通常的做法是,对于每个导入/导出的内存片段,还有一个匹配的栅栏/信号量来管理内存访问。

句柄类型

external_extensions_1.png

根据平台的不同,将使用特定的句柄在 Vulkan 和外部平台之间进行通信。例如,POSIX fd 用于大多数非 Windows 平台。

功能

VK_KHR_external_fence_capabilitiesVK_KHR_external_semaphore_capabilitiesVK_KHR_external_memory_capabilities 仅仅是查询有关实现提供的外部支持的信息的方法。

外部内存

VK_KHR_external_memory 扩展主要提供 VkExternalMemoryHandleTypeFlagBits 枚举,该枚举描述了外部使用的内存类型。

目前支持 3 种导入/导出内存的方式

  • VK_KHR_external_memory_fd 用于 POSIX 文件描述符中的内存

  • VK_KHR_external_memory_win32 用于 Windows 句柄中的内存

  • VK_ANDROID_external_memory_android_hardware_buffer 用于 AHardwareBuffer 中的内存

这些方法中的每一种都有关于限制、要求、所有权等的详细描述。

导入内存

要导入内存,给定外部内存扩展会提供一个 VkImport*Info 结构。将其传递给 vkAllocateMemory,Vulkan 现在将具有映射到导入内存的 VkDeviceMemory 句柄。

// some external memory types require dedicated allocation
VkMemoryDedicatedAllocateInfo dedicated_info;
dedicated_info.buffer = buffer;

VkImportMemoryFdInfoKHR import_info;
import_info.pNext = &dedicated_info;
import_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
import_info.fd = fd;

VkMemoryAllocateInfo allocate_info;
allocate_info.pNext = &import_info

VkDeviceMemory device_memory;
vkAllocateMemory(device, &allocate_info, nullptr, device_memory);

导出内存

要导出内存,给定外部内存扩展会提供一个 VkGetMemory* 函数。此函数将接收一个 VkDeviceMemory 句柄,然后将其映射到扩展公开的对象。

VkExportMemoryAllocateInfo export_info;
export_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;

VkMemoryAllocateInfo allocate_info;
allocate_info.pNext = &export_info

VkDeviceMemory device_memory;
vkAllocateMemory(device, &allocate_info, nullptr, device_memory);

VkMemoryGetFdInfoKHR get_handle_info;
get_handle_info.memory = device_memory;
get_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;

int fd;
vkGetMemoryFdKHR(device, &get_handle_info, &fd);

同步

外部同步可以在 Vulkan 中用于 VkFenceVkSemaphores。两者在如何用于导入和导出方面几乎没有区别。

VK_KHR_external_fenceVK_KHR_external_semaphore 扩展都公开了 Vk*ImportFlagBits 枚举和 VkExport*CreateInfo 结构,以描述正在导入/导出的同步类型。

目前支持 2 种导入/导出同步的方式

  • VK_KHR_external_fence_fd / VK_KHR_external_semaphore_fd

  • VK_KHR_external_fence_win32 / VK_KHR_external_semaphore_win32

每个扩展都解释了它如何管理同步原语的所有权。

导入和导出同步原语

有一个用于导入的 VkImport* 函数和一个用于导出的 VkGet* 函数。这两个函数都接收传入的 VkFence/VkSemaphores 句柄以及扩展定义外部同步对象的方法。

示例工作流程

这是一个简单的图表,显示了 Vulkan 和与 GPU 对话的某些其他 API 之间事件的时间线。这用于表示这些外部内存和同步扩展的常见用例。

external_example.png