毕竟,能够并行构建命令缓冲区是Vulkan的卖点之一。
规范(5.1命令池)(强调我的):
命令池是应用程序同步的,这意味着不能在多个线程中同时使用命令池。 包括通过记录命令在从池分配的任何命令缓冲区上使用,以及分配,释放和重置命令缓冲区或池本身的操作。
当涉及到并行录制时,这种方式不会扼杀命令池的全部目的吗?如果你打算并行录制,那么你最好为每个帖子设一个单独的池,不是吗?
如果您预先记录从同一个池(在一个线程中)分配的命令缓冲区,然后并行执行它们,我会理解它。这具有摊销资源创建成本以及并行执行的优势。但是,并行录制和命令池似乎并不匹配。
我个人不知道你为什么不预先录制一切。那么为什么需要并行构建命令缓冲区呢?那么你是否真的必须为每个线程使用一个池?
答案 0 :(得分:7)
如果您打算并行录制,那么最好为每个帖子设置一个单独的池,不是吗?
我不知道每个线程是否有一个单独的池"在并行记录时会杀死命令池的全部目的"。实际上,它有很大帮助,因为每个线程都可以按照自己的意愿管理自己的命令池。
考虑描述符池和命令池之间的结构差异。使用描述符池,您基本上可以准确地告诉它将从中分配什么。 VkDescriptorPoolCreateInfo
提供详细信息,允许实现预先分配您将为每个池使用多少内存。并且你不能从描述符池中分配更多。
相比之下,VkCommandPoolCreateInfo
包含......没有。哦,你告诉它命令缓冲区是主要的还是辅助的。你说是命令缓冲区是经常重置还是持久化。还有其他一些事情。但除此之外,你对命令缓冲区的内容一无所知。你甚至不会给它提供你将分配多少缓冲区的信息。
描述符池应该是固定的:根据需要分配,但最多可以在施工时设置。命令缓冲区非常动态:根据您的特定用例需要进行分配。
将其视为每个池都有自己的malloc / free。由于用户被迫同步对池及其缓冲区的访问,这意味着在分配内存时,不需要每个vkCmd*
函数。这使得命令构建更快。 帮助线程化。当线程决定重置其命令池时,它不必锁定任何互斥锁或任何其他此类东西来执行此操作。
每个线程有一个命令池在概念上没有任何错误。实际上,每个线程有两个(双缓冲)更有意义。
我个人不知道为什么你不会预先录制所有内容。
因为您没有制作静态技术演示。
我想这来自缺乏经验,但我想象并行记录看起来像"线程2-N记录辅助命令缓冲区,线程1在一个主命令缓冲区中调用所有这些",在这种情况下,每个线程只有一个命令缓冲区。这就是为什么我说它杀死了命令池的目的,因为你只为每个池进行一次分配。
这当然是并行记录命令缓冲区的可行方式。但是有两件事你错过了。
虽然这肯定是平行录音的一种形式,但它不是唯一的一种。如果您正在进行延迟渲染,那么为光照通道构建CB的线程将比其中一个负责(部分)几何传递的线程更快地完成其工作。因此,设计良好的多线程系统必须根据需要将工作分配给线程,而不是基于某些固定的东西排列。因此,单个线程通常最终会构建多个命令缓冲区。
即使不是这样,你也会忘记缓冲。当需要为下一帧构建CB时,您不能只覆盖现有的CB。毕竟,他们可能还在排队做工作。所以每个线程至少需要两个 CB;当前正在执行的那个以及当前正在构建的那个。
即使不是这种情况,命令池也会分配与CB关联的所有内存。这就是我将它们类比为malloc/free
的原因。即使您只使用具有特定池的单个CB,这个CB的分配(可能由于任何vkCmd*
函数而发生)永远不必与另一个线程同步这一事实是一件好事。< / p>
所以不,这绝不会抑制使用多个线程来构建CB的能力。
答案 1 :(得分:1)
如果您打算并行录制,那么最好为每个线程设置一个单独的池,不是吗?
这是完全正确的。这就是你的规范引用所暗示的。
如果您预先记录从同一个池(在一个线程中)分配的命令缓冲区,然后并行执行它们,我会理解它。
Vulkan做得更好。您可以预先记录命令缓冲区(从每个线程池分配)并行和,然后并行执行它们(如果您的工作量有助于此)。
我个人不知道为什么你不会只是预先录制一切。那么为什么需要并行构建命令缓冲区呢?
因为它很难(特别是随着你的应用程序的复杂性增加)。在某些时候甚至是反作用的(当你将CmB扭曲为可预先记录时 - 例如用空的占位符绑定填充它,其中80%将不会被使用)。
它不一定是“需要的”,Vulkan只是让你选择你认为最适合你的应用程序(或其中的一部分)。