![](/img/trans.png)
[英]In Vulkan, is it beneficial for the graphics queue family to be separate from the present queue family?
[英]What is actually a Queue family in Vulkan?
我目前正在学习vulkan,现在我正在拆开每个命令并检查结构以试图理解它们的含义。
现在我正在分析QueueFamilies,我有以下代码:
vector<vk::QueueFamilyProperties> queue_families = device.getQueueFamilyProperties();
for(auto &q_family : queue_families)
{
cout << "Queue number: " + to_string(q_family.queueCount) << endl;
cout << "Queue flags: " + to_string(q_family.queueFlags) << endl;
}
这会产生以下输出:
Queue number: 16
Queue flags: {Graphics | Compute | Transfer | SparseBinding}
Queue number: 1
Queue flags: {Transfer}
Queue number: 8
Queue flags: {Compute}
所以,天真地我这样理解:
有3个Queue系列,一个队列系列有16个队列,都可以进行图形,计算,传输和稀疏绑定操作(不知道后两个是什么)
另一个有1个队列,只能传输(无论是什么)
最后一个有8个队列,可以进行计算操作。
每个队列系列是什么? 我理解这是我们发送执行命令的地方,比如绘制和交换缓冲区,但这是一个有点广泛的解释,我想要更详细的知识答案。
2个额外标志是什么? 转移和SparseBidning?
最后,为什么我们需要/需要多个命令队列?
要了解队列系列,首先必须了解队列。
队列是您向命令缓冲区提交的,并且提交到队列的命令缓冲区按顺序[* 1]相对于彼此执行。 提交到不同队列的命令缓冲区相对于彼此是无序的,除非您明确地将它们与VkSemaphore
同步。 您只能一次从一个线程向队列提交工作,但不同的线程可以同时向不同的队列提交工作。
每个队列只能执行某些类型的操作。 图形队列可以运行由vkCmdDraw*
命令启动的图形管道。 计算队列可以运行由vkCmdDispatch*
启动的计算管道。 传输队列可以从vkCmdCopy*
执行传输(复制)操作。 稀疏绑定队列可以使用vkQueueBindSparse
更改稀疏资源与内存的vkQueueBindSparse
(请注意,这是直接提交给队列的操作,而不是命令缓冲区中的命令)。 某些队列可以执行多种操作。 在规范中,每个可以提交到队列的命令都有一个“命令属性”表,列出了可以执行命令的队列类型。
队列系列只描述了一组具有相同属性的队列。 因此,在您的示例中,设备支持三种队列:
一种可以执行图形,计算,传输和稀疏绑定操作,并且您最多可以创建该类型的16个队列。
另一种只能进行传输操作,你只能创建一个这种队列。 通常这是用于在离散GPU上的主机和设备存储器之间异步DMA数据,因此可以与独立的图形/计算操作同时进行传输。
最后,您最多可以创建8个只能进行计算操作的队列。
某些队列可能只对应于主机端调度程序中的单独队列,其他队列可能对应于硬件中的实际独立队列。 例如,许多GPU只有一个硬件图形队列,因此即使您从具有图形功能的队列系列创建两个VkQueue,提交给这些队列的命令缓冲区也将独立地通过内核驱动程序的命令缓冲区调度程序,但将以某些序列执行在GPU上订购。 但是一些GPU具有多个仅计算硬件队列,因此仅用于计算的队列系列的两个VkQueue实际上可以在GPU中一直独立并同时进行。 Vulkan不公开这个。
最重要的是,根据您拥有的并发数量,确定可以有效使用的队列数。 对于许多应用程序,只需要一个“通用”队列。 更高级的可能有一个图形+计算队列,一个用于异步计算工作的单独的仅计算队列,以及用于异步DMA的传输队列。 然后将你想要的东西映射到可用的东西上; 您可能需要进行自己的多路复用,例如,在没有仅计算队列系列的设备上,您可以创建多个图形+计算队列,或者自己将异步计算作业序列化到单个图形+计算队列中。
[* 1]过度简化了一下。 它们按顺序启动 ,但允许在此之后独立进行并完成故障。 但是不保证不同队列的独立进度。 对于这个问题我会留下它。
队列是接受包含给定类型的操作的命令缓冲区(由系列标志给出)的东西。 提交给队列的命令具有提交顺序,因此它们受管道障碍,子通道依赖关系和事件的同步(跨队列时必须使用信号量或beter)。
有一个技巧: COMPUTE
和GRAPHICS
总是可以隐式接受TRANSFER
工作负载(即使QueueFamilyProperties
没有列出它。请参阅下面的注释VkQueueFlagBits规范 )。
传输用于复制和Blit命令。 稀疏就像分页; 它允许将多个Memory句柄绑定到单个Image,并且它允许稍后重新绑定不同的内存。
在规范中,下面给出了vkCmd*
命令,它总是说哪些是“支持的队列类型”。
队列族是一组与自己有特殊关系的队列。 有些东西仅限于单个队列系列,例如图像(它们必须在队列系列之间转移)或命令池(仅为给定的队列系列而不是其他队列系列创建命令缓冲区)。 理论上,在一些奇特的设备上,可能会有更多具有相同标志的队列系列。
这几乎是Vulkan规范保证的一切。 请参阅KhronosGroup / Vulkan-Docs#569上的问题
提供了一些供应商特定的材料,例如:
GPU具有异步图形引擎,计算引擎和复制\\ DMA引擎。 图形和计算当然会与GPU的相同计算单元竞争。
它们通常只有一个图形前端。 这是图形操作的瓶颈,因此这意味着使用多个图形队列毫无意义。
Compute有两种操作模式:Synchronous Compute(公开为GRAPHICS|COMPUTE
系列)和Async Compute(公开为COMPUTE
-only系列)。 首先是一个安全的选择。 第二个可以给你大约10%的性能,但更棘手,需要更多的努力。 AMD文章建议始终将第一个作为基线。
理论上可以有与GPU上的计算单元一样多的计算队列。 但AMD认为,对两个以上的异步计算队列没有任何好处,并且暴露了许多。 NVIDIA似乎全力以赴。
Copy \\ DMA Engines(作为TRANSFER
-only系列公开)主要用于CPU⇄GPU传输。 它们通常无法实现内部GPU副本的完全吞吐量。 因此,除非有一些驱动程序魔法,否则异步传输系列应该用于CPU⇄GPU传输(以获取Async属性,能够无阻碍地在其旁边执行图形)。 对于内部GPU副本,大多数情况下使用GRAPHICS|TRANSFER
系列应该更好。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.