如何确保正确销毁 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::createBufferUnique
和 vk::Device::allocateMemoryUnique
填充它们。这些需要按此顺序调用,因为后者取决于前者的内存要求(通过 vk::Device::getBufferMemoryRequirements
获得)。但是,这会导致 vertex_memory_buffer
在 vertex_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
那样对待 vkAllocateMemory
和 vkCreateBuffer
。分配大块内存,然后将其细分为您认为合适的缓冲区(和图像)。您还可以使用像 VulkanMemoryAllocator 这样的内存管理器来为您处理内存管理。
我 运行 遇到以下难题,试图使用 Vulkan Hpp 唯一句柄来存储缓冲区及其分配的内存。我声明句柄
vk::UniqueBuffer vertex_buffer;
vk::UniqueDeviceMemory vertex_buffer_memory;
并使用 vk::Device::createBufferUnique
和 vk::Device::allocateMemoryUnique
填充它们。这些需要按此顺序调用,因为后者取决于前者的内存要求(通过 vk::Device::getBufferMemoryRequirements
获得)。但是,这会导致 vertex_memory_buffer
在 vertex_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
那样对待 vkAllocateMemory
和 vkCreateBuffer
。分配大块内存,然后将其细分为您认为合适的缓冲区(和图像)。您还可以使用像 VulkanMemoryAllocator 这样的内存管理器来为您处理内存管理。