damix911
damix911

Reputation: 4453

Deriving the `VkMemoryRequirements`

  1. Is there a way to get the right values for a VkMemoryRequirements structure without having to allocate a buffer first and without using vkGetBufferMemoryRequirements?
  2. Is it supported/compliant?

Motivation - Short version

I have an application that does the following, and everything works as expected.

    VkMemoryRequirements memReq;
    vkGetBufferMemoryRequirements(application.shell->device, uniformBuffer, &memReq);
    int memType = application.shell->findMemoryType(memReq.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);

Internally, findMemoryType loops over the memory types and checks that they have the required property flags.

If I replace the call to vkGetMemoryRequirements with hardcoded values (which are not portable, specific to my system and obtained through debugging), everything still works and I don't get any validation errors.

    VkMemoryRequirements memReq = { 768, 256, 1665 };
    int memType = application.shell->findMemoryType(memReq.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);

The above code is IMHO neat because enables to pre-allocate memory before you actually need it.

Motivation - Long version

In Vulkan you create buffers which initially are not backed by device memory and at a later stage you allocate the memory and bind it to the buffer using vkBindBufferMemory:

VkResult vkBindBufferMemory(
    VkDevice                                    device,
    VkBuffer                                    buffer,
    VkDeviceMemory                              memory,
    VkDeviceSize                                memoryOffset);

Its Vulkan spec states that:

memory must have been allocated using one of the memory types allowed in the memoryTypeBits member of the VkMemoryRequirements structure returned from a call to vkGetBufferMemoryRequirements with buffer

Which implies that before allocating the memory for a buffer, you should have already created the buffer.

I have a feeling that in some circumstances it would be useful to pre-allocate a chunk of memory before you actually need it; in most of the OpenGL flavors I have experience with this was not possible, but Vulkan should not suffer from this limitation, right?

  1. Is there a (more or less automatic) way to get the memory requirements before creating the first buffer?
  2. Is it supported/compliant?

Obviously, when you do allocate the memory for the first buffer you can allocate a little more so that when you need a second buffer you can bind it to another range in the same chunk. But my understanding is that, to comply with the spec, you would still need to call vkGetBufferMemoryRequirements on the second buffer, even if it is exactly the same type and the same size as the first one.

Upvotes: 2

Views: 1900

Answers (1)

Nicol Bolas
Nicol Bolas

Reputation: 474386

This question already recognizes that the answer is "no"; you just seem to want to do an end-run around what you already know. Which you can't.

The code you showed with the hard-coded values works because you already know the answer. It's not that Vulkan requires you to ask the question; Vulkan requires you to provide buffers that use the answer.

However, since "the answer" is implementation-specific, it changes depending on the hardware. It could change when you install a new driver. Indeed, it could change even depending on which extensions or Vulkan features you activate when creating the VkDevice.

That having been said:

Which implies that before allocating the memory for a buffer, you should have already created the buffer.

Incorrect. It requires that you have the answer and have selected memory and byte offsets appropriate to that answer. But Vulkan is specifically loose about what "the answer" actually means.

Vulkan has specific guarantees in place which allow you to know the answer for a particular buffer/image without necessarily having asked about that specific VkBuffer/Image object. The details are kind of complicated, but for buffers they are pretty lax.

The basic idea is that you can create a test VkBuffer/Image and ask about its memory properties. You can then use that answer to know what the properties of the buffers you intend to use which are "similar" to that. At the very least, Vulkan guarantees that two identical buffer/images (formats, usage flags, sizes, etc) will always produce identical memory properties.

But Vulkan also offers a few other guarantees. There are basically 3 things that the memory properties tell you:

  • The memory types that this object can be bound to.
  • The alignment requirement for the offset for the memory object.
  • The byte size the object will take up in memory.

For the size, you get only the most basic guarantee: equivalent buffer/images will produce equivalent sizes.

For the alignment, images are as strict as sizes: only equivalent images are guaranteed to produce equivalent alignment. But for buffers, things are more lax. If the test buffer differs only in usage flags, and the final buffer uses a subset of the usage flags, then the alignment for the final buffer will not be more restrictive than the test buffer. So you can use the alignment from the test buffer.

For the memory types, things are even more loose. For images, the only things that matter are:

  • Tiling
  • Certain memory flags (sparse/split-instance binding)
  • Whether the image format is color or depth/stencil
    • If the image format is depth/stencil, then the formats must match
  • External memory
  • Transient allocation usage

If all of these are the same for two VkImage objects, then the standard guarantees that all such images will support the same set of memory types.

For buffers, things are even more lax. For non-sparse buffers, if your test buffer differs from the final buffer only by usage flags, then if the final one has a subset of the usage flags of the test buffer, then the set of memory types it supports must include all of the ones from the test buffer. The final buffer could support more, but it must support at least those of such a test buffer.

Oh, and linear images and buffers must always be able to be used in at least one mappable, coherent memory type. Of course, this requires that you have created a valid VkDevice/Image with those usage and flags fields, so if the device doesn't allow (for example) linear images to be used as textures, then that gets stopped well before asking about memory properties.

Upvotes: 3

Related Questions