Vulkan:为什么每个池有多个命令缓冲区?

Joh*_*hke 2 c multithreading vulkan

我正在使用 Vulkan 1.0 进行开发,通过一步步学习和实现功能来构建渲染系统。我了解了命令记录和提交的要点,但还不足以理解我希望每个池有多个命令缓冲区的用例。正是幻灯片 14 中演示引发了一些问题。

我的理解和目前的设计如下:

  • 最佳情况下,每个线程每帧应该有一个命令池,这样命令缓冲区就不会在运行时在同一内存上进行记录。如果我有 3 个帧,并且每个帧最多可以有 4 个记录线程,则至少有 12 个命令池。
  • 命令缓冲区在创建时与命令池相关联,并将在下一帧重置。为了获得更好的性能,将重置整个池而不是单个缓冲区。
  • 单个命令池可用于创建多个命令缓冲区。这组命令缓冲区将全部在同一帧和线程中使用。
  • 根据“命令重叠”下的这篇文章,命令的重新排序可能发生在命令缓冲区和vkQueueSubmit调用之间。因此,如果我在同一帧和线程中有一组命令缓冲区,我需要的不仅仅是提交顺序来保证我想要的结果。也许我会为每次提交使用独特的信号量?
  • 如果我正在为框架/线程编码,我认为从头到尾提交几次命令与最后一次提交所有内容相比没有任何优势。这是在相同的时间跨度内完成相同的工作量。vkQueueSubmit由于规范中提到的开销,多次提交甚至可能是有害的。

根据上述假设,在什么情况下,每个命令池拥有多个命令缓冲区而不是拥有一个记录给定帧和线程从开始到结束的所有内容的命令缓冲区是必要或有利的?

Nic*_*las 5

是否有一个命令缓冲区来记录给定帧和线程从头到尾的所有内容?

那么,如果线程需要按照不同于提交顺序的顺序记录事物,会发生什么情况呢?这就是 CB 的意义所在,不是吗?能够以方便的顺序构建命令,然后以适合 GPU 的方式提交它们。

例如,假设您有一个正在渲染一组特定对象的线程。为此,您需要将它们的矩阵和其他每个对象的属性写入统一的缓冲区。假设,无论出于何种原因,这个特定的 Vulkan 实现不允许您直接将可映射内存用于统一缓冲区。因此,您必须写入可映射内存并通过内存传输操作将数据复制到统一缓冲区。

因此,为这些网格创建命令的线程需要做两件事。他们需要构建命令来渲染网格,并且需要构建命令来将统一数据传输到渲染命令所需的缓冲区。

然而,您的方法要求按照您希望执行的顺序将命令放入 CB 中。因此,您必须循环遍历整个对象列表来构建传输命令,然后再次循环它来构建渲染命令。但是每次循环中您都会读取相同的对象。在第一个循环期间,您可以访问发出渲染命令所需的 100% 数据。

第二次循环时,所有数据都不再位于缓存中。因此,第二次的缓存未命中次数(以及实际内存访问次数)与第一次大致相同。

那很糟。

此外,渲染命令需要放置在渲染通道实例中。传输命令不能位于渲染通道实例中。但是,如果您将传输命令放入与渲染命令相同的 CB 中...该 CB 必须开始和结束渲染通道实例。

那么...其他线程如何为该渲染通道实例发出命令?

如果您想要并行性(并且确实如此),那么您需要这些线程为其渲染命令创建辅助 CB。稍后的任务会将它们整理到主 CB 中,并且该 CB 将具有渲染通道实例。但是为渲染通道构建的辅助 CB不能包含传输命令。

因此,如果您想要并行性,那么必须与渲染命令一起生成的任何传输命令都必须进入不同的 CB。将在辅助 CB 之前提交(或者甚至完全提交到不同的队列)。