2

假设我在随机位置渲染简单的立方体。

将其中 3 个作为立方体的起始数量,应用程序获取一个VkBuffer句柄并将其绑定到 a VkDeviceMemory,以便将所有立方体的模型矩阵连续存储在其中,然后着色器通过描述符集访问该句柄。VkDeviceMemory对这 3 个立方体有足够的内存。

我想要做的是,每次用户按下一个键时,一个新的立方体应该在某个地方弹出。我的问题是,我应该如何调整该内存的大小?你能概述一下我应该经历的步骤吗?

我意识到我可以为每个立方体使用单独的VkBuffer/VkDeviceMemory但我不想这样做。我读到的所有地方都说这是一种反模式。

我是否应该丢弃VkDeviceMemory,分配一个大小合适的新的,然后收工?描述符集呢,它们需要任何特殊处理吗?

在我读过的某些地方,您可以分配非常大的数据块,因此在处理越来越多的多维数据集时,您是安全的因为已经达到了极限。有没有办法绕过这个自我施加的限制?

编辑:我也意识到一次分配一小块是一个坏主意。我感兴趣的是重新分配本身,以及它需要什么。

4

3 回答 3

2

要回答“我如何重新分配并开始使用新内存”的问题,请忽略有关分配策略的问题:重新分配与分配新事物没有什么不同,用您想要的数据填充它,然后开始使用它。因此,您基本上需要与初始分配相同的所有步骤。

需要注意的是,在命令缓冲区完成执行之前,无法安全地修改命令缓冲区中引用的大多数对象。通常,当帧 N 的命令仍在执行时,您将记录帧 N+1 的命令。因此,您要避免更新可变对象(如描述符集)以开始使用新分配;相反,您需要一个新的描述符集。

所以这里是你需要的东西的清单:

  1. 缓冲区本身: aVkBuffer和 a VkDeviceMemory。如果您在 current 中分配了额外的空间,VkDeviceMemory那么它对于 old 和 new 都足够大VkBuffer,那么您不需要新VkDeviceMemory对象。无论哪种方式,创建一个VkBuffer所需大小的新对象,并将其绑定到VkDeviceMemory对象的未使用部分。

  2. 一种将缓冲区绑定到管道的方法VkDescriptorSet:您将使用与以前相同的描述符集布局,这不会改变。因此,从您的描述符池中分配一个新的描述符集,并用于vkUpdateDescriptorSet将缓冲区描述符设置为指向您的新缓冲区(如果不需要更改,您也可以从以前的描述符集中复制其他描述符)。

  3. 最后,在为要使用新缓冲区的帧构建命令缓冲区时,传递新的描述符集,vkCmdBindDescriptorSets而不是旧的。

  4. 最后,在所有使用旧缓冲区和描述符集的命令缓冲区都完成后,您可以释放缓冲区和描述符集。对于描述符集,您可能只是将其返回到池中,或者保留它并在下次需要重新分配缓冲区时重用它。然后可以释放旧缓冲区使用的设备内存,或者您可以保留它以供以后重用。

于 2018-11-14T04:19:51.097 回答
0

同意 Jherico 所说的,但还有一个额外的选择,那就是不要将自己限制在一个VkBuffer.

通常你想考虑VkDeviceMemory内存页的倍数(4 KiB),有些设备甚至像 64 KiB 的倍数。即使您分配的内存小于这个值,您也很可能会用完那么多内存,因为操作系统内核无法为您提供更小块的内存。

因此,如果每个转换需要 64 B,那么您可能只计划分配 1k 转换块。分配一个 64 KiB VkBuffer/ VkDeviceMemorypair,当它填满时分配第二对,当它填满时分配第三对,等等。

当您进行绘图时,您需要为每个块进行单独的绘图调用,并在两者之间进行缓冲区重新绑定。如果您发现在实践中最终绘制了大量的立方体,并且绘制调用和状态更改的数量限制了性能,请使用更大的块大小 - 无论如何您都会使用内存,因此以小增量分配它没有任何帮助。

如果这样做,那么每次分配新块时,都需要为其设置一个新的描述符。同时创建它,然后在两次绘制之间绑定到您将要使用的缓冲区的描述符集。

相反,如果您重新分配缓冲区,那么您需要等待先前的渲染完成并在使用重新分配的缓冲区进行绘制之前更新您拥有的描述符集,或者您可以创建一个新的描述符集并立即绘制,然后再回收旧的描述符当您知道使用它的绘图完成时设置。

于 2018-11-02T03:26:17.957 回答
-1

VkDeviceMemory 为这 3 个多维数据集提供了足够的内存。

为什么?如果您想支持任意数量的多维数据集,那么您应该管理您的内存,以便您可以以最少的重新分配次数来处理诸如转换之类的事物数量的变化。

我是否应该丢弃 VkDeviceMemory,分配一个大小合适的新内存,然后收工?

对于数量可变的结构,您应该根据当前需求和未来可能的需求进行分配。同时,您不希望过度分配。对于像转换这样的东西,与现代 GPU 上通常可用的内存量相比非常小,从分配 1024 个独特的转换开始并不是不合理的。如果它是一个简单的mat4转换,它只消耗 512 个字节,所以其中 1k 只需要半兆字节的内存。与纹理甚至复杂网格的典型内存负载相比,这是微不足道的。

如果你真的把它们都吃光了,你可以重新分配更多。根据您可能的使用模式,您可以使用固定的块大小(如 1024)重新分配,或者进行指数增加的分配,例如始终分配两倍的当前侧。您可以 googlevector reallocation以获取有关处理可能超出当前范围的连续内存的策略的更多信息。 这是有关该主题的文章

于 2018-11-01T18:01:55.997 回答