派生`VkMemoryRequirements`

Deriving the `VkMemoryRequirements`

  1. 有没有一种方法可以为 VkMemoryRequirements 结构获取正确的值,而无需先分配缓冲区且无需使用 vkGetBufferMemoryRequirements
  2. 是supported/compliant吗

动机 - 简短版

我有一个应用程序执行以下操作,并且一切正常。

    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);

在内部,findMemoryType 遍历内存类型并检查它们是否具有所需的 属性 标志。

如果我用硬编码值(不可移植,特定于我的系统并通过调试获得)替换对 vkGetMemoryRequirements 的调用,一切仍然有效,我没有收到任何验证错误。

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

上面的代码是恕我直言,因为可以在您实际需要之前预分配内存。

动机 - 长版

在 Vulkan 中,您创建的缓冲区最初不受设备内存支持,在稍后阶段您分配内存并将其绑定到缓冲区,使用 vkBindBufferMemory:

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

其 Vulkan 规范指出:

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

这意味着在为缓冲区分配内存之前,您应该已经创建了缓冲区。

我感觉在某些情况下,在您实际需要之前预分配一块内存会很有用;在我体验过的大多数 OpenGL 风格中,这是不可能的,但是 Vulkan 不应该受到这个限制,对吧?

  1. 在创建第一个缓冲区之前是否有一种(或多或少是自动的)方法来获取内存需求?
  2. 是supported/compliant吗?

显然,当您 do 为第一个缓冲区分配内存时,您可以分配更多的内存,这样当您需要第二个缓冲区时,您可以将它绑定到相同的块。但我的理解是,为了符合规范,您仍然需要在第二个缓冲区上调用 vkGetBufferMemoryRequirements,即使它与第一个缓冲区的类型和大小完全相同。

本题已经识别答案为"no";你似乎只是想围绕你已经知道的事情做一个结束-运行。你不能。

您使用硬编码值显示的代码有效,因为您已经知道答案。并不是 Vulkan 要求您提出问题;而是Vulkan 要求您提供使用答案的缓冲区。

但是,由于 "the answer" 是特定于实现的,因此它会根据硬件而变化。当您安装新的驱动程序时,它可能会发生变化。事实上,它甚至可以根据您在创建 VkDevice.

时激活的 扩展 或 Vulkan 功能而改变。

话虽如此:

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

不正确。它要求您有答案并选择适合该答案的内存和字节偏移量。但是 Vulkan 对 "the answer" 的实际含义特别 松散

Vulkan 有 specific guarantees in place 可以让您知道特定 buffer/image 的答案,而不必询问 specific VkBuffer/Image 对象.细节有点复杂,但是对于缓冲区来说,它们是相当松散的。

基本思路是您可以创建一个测试VkBuffer/Image并询问其内存属性。然后,您可以使用该答案来了解您打算使用的缓冲区的哪些属性 "similar" 。至少,Vulkan 保证两个相同的 buffer/image(格式、使用标志、大小等)将始终产生相同的内存属性。

但 Vulkan 还提供了一些其他保证。内存属性基本上告诉您 3 件事:

  • 此对象可以绑定到的内存类型。
  • 内存对象偏移量的对齐要求。
  • 对象在内存中占用的字节大小。

对于尺寸,您只能得到最基本的保证:等效的 buffer/image 将产生等效的尺寸。

对于对齐,图像与大小一样严格:只有等效图像才能保证产生等效对齐。但是对于缓冲区来说,事情就更宽松了。如果测试缓冲区仅在使用标志上有所不同,而最终缓冲区使用使用标志的子集,则最终缓冲区的对齐不会比测试缓冲区更严格。所以你可以使用测试缓冲区的比对。

对于内存类型,事情就更加松散了。对于图像,唯一重要的是:

  • 平铺
  • 某些内存标志(sparse/split-instance 绑定)
  • 图片格式是彩色还是depth/stencil
    • 如果图像格式为depth/stencil,则格式必须匹配
  • 外部存储器
  • 瞬态分配用法

如果两个 VkImage 对象的所有这些都相同,则标准保证所有这些图像将支持同一组内存类型。

对于缓冲区,事情更加宽松。对于非稀疏缓冲区,如果您的测试缓冲区仅在使用标志方面与最终缓冲区不同,那么如果最终缓冲区具有测试缓冲区的使用标志的子集,则它支持的内存类型集必须包括所有来自测试缓冲区的。最终缓冲区可以支持更多,但它必须至少支持这样的测试缓冲区。

哦,线性图像和缓冲区必须始终能够在至少一种可映射的、连贯的内存类型中使用。当然,这要求您已经使用这些用法和标志字段创建了一个有效的 VkDevice/Image,因此如果设备不允许(例如)将线性图像用作纹理,那么在询问之前它会停止关于内存属性。