如何确保正确销毁 vk::UniqueBuffer 和 vk::UniqueDeviceMemory

How to ensure correct destruction of vk::UniqueBuffer and vk::UniqueDeviceMemory

我 运行 遇到以下难题,试图使用 Vulkan Hpp 唯一句柄来存储缓冲区及其分配的内存。我声明句柄

vk::UniqueBuffer vertex_buffer;
vk::UniqueDeviceMemory vertex_buffer_memory;

并使用 vk::Device::createBufferUniquevk::Device::allocateMemoryUnique 填充它们。这些需要按此顺序调用,因为后者取决于前者的内存要求(通过 vk::Device::getBufferMemoryRequirements 获得)。但是,这会导致 vertex_memory_buffervertex_buffer 之前被销毁并触发来自验证层的以下警告:

Validation Warning: [ CHASSIS ] Object 0: handle = 0x558599c91fc0, type = VK_OBJECT_TYPE_DEVICE; Object 1: handle = 0x1b000000001b, type = VK_OBJECT_TYPE_BUFFER; Object 2: handle = 0x1c000000001c, type = VK_OBJECT_TYPE_DEVICE_MEMORY; | MessageID = 0x7366b7dd | 
VK Object VkBuffer 0x1b000000001b[] still has a reference to mem obj VkDeviceMemory 0x1c000000001c[].

确实,我查找的所有 C API 示例都是先销毁缓冲区,然后再释放内存。我当然可以使用某种解决方法来确保这里发生同样的情况(例如,默认初始化 vertex_buffer_memory 并在创建 vertex_buffer 后分配给它),但这确实违背了唯一句柄的目的(这就是让资源管理自动化)。除非我误解了什么,否则 Vulkan API 和 RAII 的设计之间似乎存在不兼容性。解决这个问题的正确方法是什么?

These need to be called in this order since the latter depends on the memory requirements of the former

不,他们没有。您确实需要获得适合该缓冲区的内存要求,但您不需要使用那个 specific VkBuffer 对象来做到这一点。

最好在应用程序开始时通过创建代表您的特定用例的 VkBuffer 来计算一次需求。也就是说,创建一些 VkBuffer 个实例,代表您将使用的所有 缓冲区。

缓冲区的内存要求并不特定于那个 VkBuffer 对象;有一个 bunch of rules in the Vulkan specification 定义了两个 VkBuffer 的要求相同的情况。因此,如果您创建一个类似于您实际使用的 VkBuffer,您可以获得它的要求,并且知道为这些要求分配的内存将适用于您计划使用的内存。

只需遵守这些规则,您就不需要颠倒这些对象的初始化顺序。

此外,为一个缓冲区或图像分配内存几乎总是一个坏主意。 Vulkan 不是 OpenGL,您不应该像对待 glBufferStorage 那样对待 vkAllocateMemoryvkCreateBuffer。分配大块内存,然后将其细分为您认为合适的缓冲区(和图像)。您还可以使用像 VulkanMemoryAllocator 这样的内存管理器来为您处理内存管理。