问题描述
毕竟,能够并行构建命令缓冲区是 Vulkan 的卖点之一.
规范(5.1 命令池)(强调我的):
Specs (5.1 Command Pools) (emphasis mine):
命令池是应用程序同步的,这意味着命令池不能在多个线程中同时使用.这包括通过在从池分配的任何命令缓冲区上记录命令使用,以及分配、释放和重置命令缓冲区或池本身的操作.
当涉及到并行记录时,这种类型不会扼杀命令池的全部目的吗?如果您打算并行录制,那么您最好为每个线程设置一个单独的池,不是吗?
Doesn't this kind of kill the whole purpose of command pools when it comes to recording in parallel? If you intend to record in parallel, then you would better be off having a separate pool for each thread, isn't that right?
如果您预先记录从同一个池(在一个线程中)分配的所有命令缓冲区,然后并行执行它们,我会理解.这具有摊销资源创建成本以及并行执行的优势.但是,并行记录和命令池似乎不太匹配.
I would understand it if if you pre-record command buffers allocated all from the same pool (in one thread) and then execute them in parallel. That has the advantage of amortized resource creation costs as well as parallel execution. However, parallel recording and command pools don't seem to match very well.
我个人不知道您为什么不预先录制所有内容.那么为什么需要并行构建命令缓冲区呢?那么您真的必须为每个线程使用一个池吗?
I don't personally know why you wouldn't just pre-record everything. So why is building command buffers in parallel so needed? And would you then really have to use one pool per thread?
推荐答案
我不明白每个线程有一个单独的池如何在并行记录时杀死命令池的全部目的".事实上,它有很大帮助,因为每个线程都可以按照它认为合适的方式管理自己的命令池.
I don't see how having a separate pool per thread "kills the whole purpose of command pools when it comes to recording in parallel". Indeed, it helps it quite a bit, since each thread can manage its own command pool as it sees fit.
考虑描述符池和命令池之间的结构差异.使用描述符池,您基本上可以准确地告诉它您将从它分配什么.VkDescriptorPoolCreateInfo
提供了详细信息,允许实现预先准确分配您将为每个池使用多少内存.并且您不能从描述符池中分配更多.
Consider the structural difference between, say, a descriptor pool and a command pool. With a descriptor pool, you basically tell it exactly what you will allocate from it. VkDescriptorPoolCreateInfo
provides detailed information which allows implementations to allocate up-front exactly how much memory you'll use for each pool. And you cannot allocate more than this from a descriptor pool.
相比之下,VkCommandPoolCreateInfo
包含……什么都没有.哦,你告诉它命令缓冲区可以是主要的还是次要的.您说命令缓冲区是频繁重置还是持久化.还有其他一些事情.但除此之外,您对命令缓冲区的内容一无所知.您甚至没有提供有关将分配多少缓冲区的信息.
By contrast, VkCommandPoolCreateInfo
contains... nothing. Oh, you tell it if the command buffers can be primary or secondary. You say whether the command buffers will be frequently reset or persistent. And a couple of other things. But other than that, you say nothing about the contents of the command buffers. You don't even give it information on how many buffers you'll allocate.
描述符池是固定的:根据需要分配,但最多不超过构建时设置的数量.命令缓冲区旨在非常动态:根据您的特定用例的需要进行分配.
Descriptor pools are intended to be fixed: allocated as needed, but up to a quantity set at construction time. Command buffers are intended to be very dynamic: allocated from as needed for your particular use cases.
把它想象成每个池都有自己的 malloc/free.由于用户被迫同步对池及其缓冲区的访问,这意味着每个 vkCmd*
函数在分配内存时都不需要这样做.这使得命令构建速度更快.这帮助线程.当一个线程决定重置它的命令池时,它不需要锁定任何互斥锁或任何其他类似的东西来做到这一点.
Think of it as each pool having its own malloc/free. Since the user is forced to synchronize access to pools and their buffers, that means that every vkCmd*
function is not required to do so when they allocate memory. That makes command building faster. That helps threading. When a thread decides to reset its command pool, it doesn't have to lock any mutexes or any other such stuff to do that.
每个线程有一个命令池在概念上没有任何问题.事实上,每个线程有两个(双缓冲)更有意义.
There's nothing conceptually wrong with having one command pool per thread. Indeed, having two per thread (double-buffering) makes even more sense.
我个人不明白你为什么不预先录制所有内容.
因为您不是在制作静态技术演示.
Because you're not making a static tech demo.
我猜这是由于缺乏经验,但我想象并行记录看起来像线程 2-N 记录辅助命令缓冲区,线程 1 在一个主命令缓冲区中调用所有这些",在这种情况下有每个线程只有一个命令缓冲区.这就是为什么我说它扼杀了命令池的目的,因为您只为每个池进行了一次分配.
这当然是一种可行的并行记录命令缓冲区的形式.但是有两件事你错过了.
That's certainly a viable form of recording command buffers in parallel. But there are two things you've missed.
虽然这当然是并行录制的一种形式,但它不是唯一的一种.如果您正在执行延迟渲染,则为照明通道构建 CB 的线程将比负责(部分)几何通道的线程之一更快地完成其工作.因此,设计良好的多线程系统必须根据需要将工作分配给线程,而不是基于某些固定的内容安排.因此,单个线程通常最终会构建多个命令缓冲区.
While that is certainly one form of parallel recording, it is not the only one. If you're doing deferred rendering, the thread that builds the CB for the lighting passes will be finished with its work much sooner than one of the threads that's responsible for (part of) the geometry pass. So a well-designed multithreaded system will have to apportion out work to threads based on need, not based on some fixed arrangement of stuff. So an individual thread will often end up building multiple command buffers.
即使情况并非如此,您也忘记了缓冲.当需要为下一帧构建 CB 时,您不能只是覆盖现有的.毕竟,他们可能仍在队列中工作.所以每个线程至少需要两个 CB;当前正在执行的一个和正在构建的一个.
And even if that were not the case, you forget about buffering. When it comes time to build the CBs for the next frame, you can't just overwrite the existing ones. After all, they're probably still in the queue doing work. So each thread will need at least two CBs; the one that's currently being executed and the one that's currently being built.
即使情况并非如此,命令池也会分配与 CB 关联的所有内存.我将它们类比为 malloc/free
是有原因的.即使您只将单个 CB 与特定池一起使用,这个 CB 的分配(可能由于任何 vkCmd*
函数而发生)永远不必与另一个线程同步这一事实是一件好事.
And even if that were not the case, command pools allocate all memory associated with a CB. There's a reason why I analogized them to malloc/free
. Even if you only use a single CB with a particular pool, the fact that this CB's allocations (which can happen due to any vkCmd*
function) never have to synchronize with another thread is a good thing.
所以不,这不会以任何方式抑制使用多线程构建 CB 的能力.
So no, this does not in any way inhibit the ability to use multiple threads to build CBs.
这篇关于多线程渲染与命令池的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!