5

A recommended approach for memory management in Vulkan is sub-allocation of buffers, for instance see the image below.

I'm trying to implement "the good" approach. I have a system in place that can tell me where within a Memory Allocation is available, so I can bind a sub area of a single large buffer. However, I can't find the mechanism to do this, or am just misunderstanding what is happening, as the bind functions take a buffer as input, and an offset. I can't see how to specify the size of the binding other than through the existing buffer.

So I have a few questions I guess:

  • are the dotted rectangles in the image below just bindings, or are they additional buffers?
  • if they are bindings, how do I tell Vulkan (ideally using VMA) to use that subsection of the buffer?
  • if they are additional buffers, how do I create them?
  • if neither, what are they?

I have read up on a few custom allocators, but they seem to follow the "bad" approach, returning offsets into large allocations for binding, so still plenty of buffers but lower allocation counts. To be clear, I am not using custom allocator callbacks other than through VMA; the "system" to which I refer above sits on top of the VMA calls.

Any pointers much appreciated!

here

mike
  • 1,192
  • 9
  • 32

1 Answers1

7

are the dotted rectangles in the image below just bindings, or are they additional buffers?

They represent the actual data. So the "Index" block is the range of storage that contains vertex indices.

if they are bindings, how do I tell Vulkan (ideally using VMA) to use that subsection of the buffer?

That depends on the particular nature of how you're using that VkBuffer as a resource. Generally speaking, every function that uses a VkBuffer as a resource takes a byte offset that represents where to start reading from. Many such functions also take a size which coupled with the offset represents the full quantity of data that can be read through that particular resource.

For example, vkCmdBindVertexBuffers takes an array of VkBuffers, and for each VkBuffer it also takes a byte offset that represents the starting point for that vertex buffer. VkDescriptorBufferInfo, the structure that represents a buffer used by a descriptor, takes a VkBuffer, a byte offset, and a size.

The vertex buffer (and index buffer) bindings don't have a size, but they don't need one. Their effective size is defined by the rendering command used with them (and the index data being read by it). If you render using 100 32-bit indices, then the expectation is that the index buffer's size, minus the starting offset, should be at least 400 bytes. And if it isn't, UB results.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Right, that makes sense. So `vkBindBufferMemory` will be over the whole buffer, and I'll use my offsets for `vkCmdBindVertexBuffers`, and `vkCmdCopyBuffer` etc. – mike Nov 26 '20 at 18:57
  • 2
    It should also be noted that NVIDIA's recommendations are for *NVIDIA's* hardware. While it's not good to have bunches of buffers for no reason, the assumption they're making is that a particular piece of hardware will provide memory that allows for both vertex and uniform storage. So you must temper the suggestion with the knowledge that you may *need* to separate these things because hardware just doesn't allow it. Or because you might need to stream vertex data, and it might be faster to read directly from CPU memory than to do transfer operations. – Nicol Bolas Nov 26 '20 at 18:59