Reputation:
I have run into the following conundrum trying to use Vulkan Hpp unique handles to store a buffer and its allocated memory. I declare the handles
vk::UniqueBuffer vertex_buffer;
vk::UniqueDeviceMemory vertex_buffer_memory;
and populate them using vk::Device::createBufferUnique
and vk::Device::allocateMemoryUnique
. These need to be called in this order since the latter depends on the memory requirements of the former (obtained via vk::Device::getBufferMemoryRequirements
). However, this results in vertex_memory_buffer
being destroyed before vertex_buffer
and triggers the following warning from validation layers:
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[].
Indeed, all C API examples that I looked up destroy the buffer first and then free the memory. I can of course use some sort of workaround to ensure that the same happens here (e.g., default initializing vertex_buffer_memory
and assigning to it after creating vertex_buffer
), but that really defeats the purpose of unique handles (which is exactly to make the resource management automatic). Unless I'm misunderstanding something, there seems to be an incompatibility between the design of Vulkan API and RAII. What is the correct way of solving this issue?
Upvotes: 4
Views: 937
Reputation: 473302
These need to be called in this order since the latter depends on the memory requirements of the former
No, they do not. You do need to get the memory requirements appropriate to that buffer, but you do not need to use that specific VkBuffer
object to do that.
It's best to compute the requirements once at the start of the application by creating VkBuffer
s that represent your specific use cases. That is, create some number of VkBuffer
instances that represent all of the kinds of buffers you will ever use.
The memory requirements for a buffer are not specific to that VkBuffer
object; there are a bunch of rules in the Vulkan specification defining the circumstances under which the requirements of two VkBuffer
s will be the same. So if you create a VkBuffer
that's like the one you'll actually use, you can get the requirements for that and know that the memory allocated for those requirements will work for the one you plan to use.
Just stick to those rules and you won't need to reverse the initialization order of these objects.
Also, it's pretty much always a bad idea to allocate memory for just one buffer or image. Vulkan is not OpenGL, and you should not treat vkAllocateMemory
and vkCreateBuffer
like glBufferStorage
. Allocate large blocks of memory, then subdivide it into buffers (and images) as you see fit. You can also use a memory manager like VulkanMemoryAllocator to handle memory management for you.
Upvotes: 3