返回

如何在 Vulkan 中从 DMA-buf 导入外部内存?

Linux

从 DMA-buf 导入 Vulkan 中

导入 DMA-buf 到 Vulkan

DMA-buf(直接内存访问缓冲区)是一种跨平台协议,用于在应用程序和内核驱动程序之间共享内存缓冲区。在 Vulkan 中,我们可以利用这种协议,通过将 DMA-buf 导入到 Vulkan 中,实现对外部内存的访问和使用。

步骤

1. 创建外部内存缓冲区信息结构**

VkExternalMemoryBufferCreateInfo extMemBufInfo;
extMemBufInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
extMemBufInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
extMemBufInfo.pNext = NULL;

2. 设置缓冲区创建信息**

VkBufferCreateInfo bufferInfo;
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = size; // DMA-buf 的大小
bufferInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
bufferInfo.flags = 0;
bufferInfo.pNext = &extMemBufInfo;

3. 创建缓冲区**

if (vkCreateBuffer(device, &bufferInfo, nullptr, &fdBuffer) != VK_SUCCESS) {
  qDebug("failed to create buffer!");
}

4. 获取缓冲区内存需求**

VkMemoryRequirements memRequirements;
vkGetBufferMemoryRequirements(device, fdBuffer, &memRequirements);

5. 设置专用内存分配信息**

VkMemoryDedicatedAllocateInfo memDedAllocInfo;
memset(&memDedAllocInfo, 0, sizeof(memDedAllocInfo));
memDedAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
memDedAllocInfo.buffer = fdBuffer;

6. 设置导入内存 FD 信息**

VkImportMemoryFdInfoKHR importInfo;
memset(&importInfo, 0, sizeof(importInfo));
importInfo.fd = dmafd;
importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
importInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
importInfo.pNext = &memDedAllocInfo;

7. 设置内存分配信息**

VkMemoryAllocateInfo allocInfo;
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
allocInfo.pNext = &importInfo;

8. 分配内存**

if (vkAllocateMemory(device, &allocInfo, nullptr, &fdBufferMemory) != VK_SUCCESS) {
  qDebug("failed to allocate image memory!");
}

9. 绑定缓冲区内存**

if (vkBindBufferMemory(device, fdBuffer, fdBufferMemory, 0) != VK_SUCCESS) {
  qDebug() << "vkBindBufferMemory failed: " << strerror(errno);
}

其他提示

  • 确保 DMA-buf 是在 /cma-uncached 内存中。
  • DMA-buf 的文件符已附加到 VkDeviceMemory。
  • 验证层未报告任何问题。
  • 使用 vkMapMemory 检查 VkBuffer 是否包含 DMA-buf 中的数据。

常见问题解答

1. 为什么使用 DMA-buf 导入 Vulkan?
DMA-buf 允许在不同 API 和应用程序之间共享内存,从而提高性能并减少数据复制。

2. DMA-buf 导入 Vulkan 的局限性是什么?
DMA-buf 导入到 Vulkan 仅适用于特定类型的内存类型,并且可能需要特定的驱动程序支持。

3. 如何确定 DMA-buf 是否适用于我的场景?
如果你的应用程序需要跨不同应用程序或 API 共享数据,并且性能至关重要,那么 DMA-buf 导入可能是合适的。

4. DMA-buf 导入 Vulkan 的替代方案是什么?
替代方案包括使用 VK_KHR_external_memory 扩展或使用自有实现的跨进程共享内存机制。

5. 如何调试 DMA-buf 导入 Vulkan 的问题?
检查验证层错误消息,使用 vkMapMemory 检查缓冲区内容,并确保满足所有先决条件,例如 DMA-buf 在 /cma-uncached 内存中。