Vulkan-1个统一缓冲区,N个网格-动态VkDeviceMemory

时间:2018-11-01 16:09:25

标签: buffer vulkan memory-reallocation

假设我要在随机位置绘制简单的多维数据集。

应用程序中有3个作为多维数据集的起始数目,该应用程序获取VkBuffer句柄并将其绑定到VkDeviceMemory,以便在其中连续存储所有多维数据集的模型矩阵,并且稍后由着色器通过描述符集访问。 VkDeviceMemory的内存足以容纳这3个多维数据集。

我想做的是,每当用户按下一个键时,一个新的多维数据集应该在某处弹出。我的问题是,我应该如何调整内存大小?您能否概述我应该执行的步骤?

我意识到我可以为每个多维数据集分别使用VkBuffer / VkDeviceMemory,但我不想这样做。我读过的所有地方都说那是一种反模式。

我应该只丢弃VkDeviceMemory,分配一个大小合适的新对象,然后称其为一天吗?描述符集怎么样,它们需要任何特殊处理吗?

在我读过的某些地方,您可以分配非常大的数据块,因此在处理越来越多的多维数据集时,我处于安全的立场,直到我猜想您将停止允许更多的多维数据集由于已达到限制而弹出。有没有办法解决这个自我施加的限制?

编辑:我也意识到一次分配一个小块是一个坏主意。我感兴趣的是重新分配本身及其所需要的内容。

3 个答案:

答案 0 :(得分:1)

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

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

这是您需要的物品清单:

  1. 缓冲区本身:VkBufferVkDeviceMemory。如果您在当前的VkDeviceMemory中分配了额外的空间,因此对于新旧的VkBuffer来说都足够大,那么您就不需要新的VkDeviceMemory对象。无论哪种方式,都需要创建一个所需大小的新VkBuffer,并将其绑定到VkDeviceMemory对象的未使用部分。

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

  3. 最后,在要使用新缓冲区的框架上构建命令缓冲区时,请将新的描述符集传递给vkCmdBindDescriptorSets而不是旧的描述符。

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

答案 1 :(得分:0)

同意Jherico所说的话,但是还有一个附加选择,就是不要将自己局限于一个VkBuffer

通常,您要考虑存储页面的倍数(4 KiB)中的VkDeviceMemory,甚至某些设备甚至要考虑64 KiB的倍数。即使分配的内存少于该值,由于OS内核无法为您提供较小的内存块,因此很有可能会用完这么多的内存。

因此,如果每个变换都需要64 B,那么您可能只打算分配1k变换的块。分配一对64 KiB VkBuffer / VkDeviceMemory,并在填充时分配第二对,填充时分配第三对,依此类推。

绘制时,每个块都需要一个单独的绘制调用,中间需要重新绑定缓冲区。如果发现在实践中最终绘制了大量的多维数据集,并且绘制调用和状态更改的数量限制了性能,请使用更大的块大小-无论如何都要使用内存,因此请以较小的增量进行分配没有任何帮助。

如果执行此操作,则每次分配新块时,都需要为其设置新的描述符。同时创建一个,然后在两次绘制之间仅绑定到要使用的缓冲区的描述符集。

如果改为重新分配缓冲区,则需要等待之前的渲染完成并更新具有的描述符集,然后才能使用重新分配的缓冲区进行绘制,或者可以创建一个新的描述符集并立即进行绘制,然后再回收当您知道使用它的图形已完成时,将使用旧的描述符集。

答案 2 :(得分:-1)

  

VkDeviceMemory的内存足以容纳这3个多维数据集。

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

  

我应该只丢弃VkDeviceMemory,分配一个大小合适的新存储器,然后每天调用它吗?

对于数量可变的结构,您应该为当前需求以及未来可能的需求进行分配。同时,您也不想过度分配。对于诸如变换这样的事情,相对于现代GPU上通常可用的内存量而言,它很小,因此可以通过分配1024个唯一的变换开始而不是不合理的。如果是简单的mat4转换,则仅消耗512个字节,因此其中的1k仅占一半的内存。与纹理或复杂网格的典型内存负载相比,这是微不足道的。

如果您实际上最终消耗了所有能量,则可以重新分配更多能量。根据您可能的使用模式,您可以以固定的块大小(例如1024)重新分配,也可以以指数方式增加分配,例如始终分配当前边的两倍。您可以在vector reallocation上搜索Google,以获得有关可能超出其当前范围的连续内存处理策略的更多信息。 Here's关于该主题的文章