微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

是否可以通过覆盖 PFN_vkAllocationFunction 并将回调传递给 Vulkan 函数来分配主机内存

如何解决是否可以通过覆盖 PFN_vkAllocationFunction 并将回调传递给 Vulkan 函数来分配主机内存

我已经实现了一个自定义分配器来跟踪由 vkAllocateMemory 分配的内存。 我还研究了有关此主题的官方 Khronos 文档,但找不到以下问题的答案:

  1. 究竟什么是 size 参数 PFN_vkAllocationFunction?我发现这显然不是我们要为其分配内存的实际缓冲区的大小。我怀疑这是 Vulkan 结构或任何其他 Vulkan 内部缓冲区的大小。无论我想分配多大的内存块,它的大小总是设置为 200 (它是机器/GPU/驱动程序相关的值,但它是一个常数值)。 出于测试目的,我使用了来自 https://github.com/SaschaWillems/Vulkan 的三角形和来自类似问题的分配器:Vulkan's VkAllocationCallbacks implemented with malloc/free()
triangle before vkAllocateMemory: memAlloc.allocationSize: 7864320 sizeof(memAlloc): 32
triangle after vkAllocateMemory: memAlloc.allocationSize: 7864320
pAllocator's allocationFunction: <Memory>,size: 200,alignment: 8,allocationScope: 1,return ptr* : 0x0x5564ac917b20

我还发现,对于其他调用,这个 size 对于不同的 vulkan 调用是不同的,例如 vkCreateRenderPassvkCreateImageView

pAllocator's allocationFunction: <ImageView>,size: 160,return ptr* : 0x0x5564acdf8390 
pAllocator's allocationFunction: <ImageView>,size: 824,return ptr* : 0x0x5564acdf8440 
pAllocator's allocationFunction: <RenderPass>,return ptr* : 0x0x5564ac950ee0 
pAllocator's allocationFunction: <RenderPass>,size: 88,return ptr* : 0x0x5564acdf8780 
pAllocator's allocationFunction: <RenderPass>,size: 56,return ptr* : 0x0x5564acdf7a00 
pAllocator's allocationFunction: <RenderPass>,size: 344,return ptr* : 0x0x5564ac6a07c0 
pAllocator's allocationFunction: <RenderPass>,size: 8,return ptr* : 0x0x5564acdf87e0 
  1. 是否可以使用这些回调分配主机可见内存?我想模拟 VK_EXT_external_memory_hostVK_KHR_external_memory_fdVK_EXT_external_memory_dma_buf 的行为,但我不知道这种方法(即实现自己的分配器)是否对其有用。

解决方法

要了解发生了什么,您需要了解 VkAllocationCallbacks 的用途。那么让我们深入了解。

例如,当您调用 vkCreateDevice 时,Vulkan 实现需要返回 VkDevice 句柄。这无疑是一个指向对象的指针。那么……它的记忆是从哪里来的?必须有一些内部的、实现定义的数据结构在起作用。这可能需要堆分配。

然而,对于低级系统,在使用该系统的应用程序不知情或不同意的情况下,随意分配堆内存通常被认为是不礼貌的。出于各种原因,较大的应用程序可能希望预先分配一堆内存,专门供 Vulkan 实现使用。

要做到这一点,需要能够替换 Vulkan 实现的堆分配函数与您自己的。这就是 VkAllocationCallbacks 的用途:允许您的程序为 Vulkan 实现提供堆分配服务,Vulkan 实现会将它们用于自己的内部数据结构。最后一部分很重要:这些分配供内部使用。

vkAllocateMemory 是一个用于分配设备可访问内存的函数。现在是的,根据使用的内存类型,它可能从与 CPU 可访问内存相同的内存池中分配。但是分配的内存 vkAllocateMemory 不是供 Vulkan 实现使用的;它供您的应用使用,通过 Vulkan API 进行中介。

现在,上面我说的是“在某些情况下”。当您使用 VkAllocationCallbacks 创建设备时,回调将用于为使用该设备的任何 Vulkan 函数分配实现内存。这就是这些回调的上下文。其他函数有它们自己的上下文。例如,当你调用 vkCreateDescriptorPool 时,你也给它回调。这些回调(如果指定)将用于用于描述符池的任何分配。

现在,如上所述,vkAllocateMemory 分配设备可访问的内存。但是,它还会创建一个表示此存储的 VkDeviceMemory 对象。该对象存在于 CPU 空间中,因此它必须是从 CPU 存储中分配的。

这就是您看到的 200 字节所代表的内容:不是设备内存分配本身,而是用于管理该设备内存的 CPU 存储分配。您可以说 VkDeviceMemory 表示的内部实现对象占用了 200 个字节。

总体而言,您无法通过旨在让您访问 Vulkan 分配了多少 CPU 可访问内存的系统来跟踪设备可访问的分配。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。