推导`VkMemoryRequirements`

时间:2019-03-31 21:33:21

标签: c++ vulkan

  1. 是否有一种方法可以为VkMemoryRequirements结构获取正确的值,而不必先分配缓冲区也无需使用vkGetBufferMemoryRequirements
  2. 是否受支持/兼容?

动机-简短版

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

    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规范指出:

  

必须使用允许的一种内存类型分配内存   在VkMemoryRequirements结构的memoryTypeBits成员中   调用带有缓冲区的vkGetBufferMemoryRequirements返回的

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

我觉得在某些情况下,在实际需要之前预先分配一块内存会很有用;在大多数OpenGL风格中,我都无法做到这一点,但是Vulkan不应受此限制的影响,对吗?

  1. 在创建第一个缓冲区之前,是否有一种(或多或少的自动)方式来获取内存需求?
  2. 受支持/兼容吗?

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

1 个答案:

答案 0 :(得分:2)

该问题已经认识到答案为“否”;您似乎只是想对已经知道的内容做一个最终的尝试。你不能做到的。

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

但是,由于“答案”是特定于实现的,因此它会根据硬件而变化。安装新的驱动程序时,它可能会更改。实际上,即使您在创建VkDevice时激活了哪些扩展或Vulkan功能,它也可能会改变。

话虽如此:

  

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

不正确。它要求您有答案,并且已选择适合该答案的内存和字节偏移。但是Vulkan对于“答案”的实际含义是松散的

Vulkan具有specific guarantees in place,可让您知道特定缓冲区/图像的答案,而不必询问那个 specific VkBuffer/Image对象。细节有些复杂,但是对于缓冲区来说,它们却很松懈。

基本思想是,您可以创建测试VkBuffer/Image并询问其内存属性。然后,您可以使用该答案来了解您打算使用的与该缓冲区“相似”的属性。至少,Vulkan保证两个相同的缓冲区/图像(格式,使用标志,大小等)将始终产生相同的内存属性。

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

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

对于大小,您只能获得最基本的保证:等效的缓冲区/图像将产生等效的大小。

对于对齐,图像与尺寸一样严格:仅保证等效的图像产生等效的对齐。但是对于缓冲区来说,事情就更加松懈了。如果测试缓冲区仅在使用情况标志方面有所不同,并且最终缓冲区使用了使用情况标志的子集,则最终缓冲区的对齐方式不会比测试缓冲区更具限制性。因此,您可以使用测试缓冲区中的对齐方式。

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

  • 平铺
  • 某些内存标志(稀疏/拆分实例绑定)
  • 图像格式是彩色还是深度/模板
    • 如果图像格式为深度/模板,则格式必须匹配
  • 外部存储器
  • 瞬时分配用法

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

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

噢,线性图像和缓冲区必须始终能够至少在一种可映射的,相干的存储器类型中使用。当然,这要求您使用这些用法和标志字段创建了一个有效的VkDevice/Image,因此,如果设备不允许(例如)将线性图像用作纹理,则在询问之前将其停下来关于内存属性。