c – Vulkan中的Queue系列实际上是什么?

我目前正在学习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更改稀疏资源与内存的绑定(请注意,这是直接提交给队列的操作,而不是命令缓冲区中的命令).某些队列可以执行多种操作.在规范中,每个可以提交到队列的命令都有一个“命令属性”表,列出了可以执行命令的队列类型.

队列系列只描述了一组具有相同属性的队列.因此,在您的示例中,设备支持三种队列:

>一种可以执行图形,计算,传输和稀疏绑定操作,并且您最多可以创建16个该类型的队列.
>另一种只能进行传输操作,而您只能创建一个这种队列.通常这是用于在离散GPU上的主机和设备存储器之间异步DMA数据,因此可以与独立的图形/计算操作同时进行传输.
>最后,您最多可以创建8个只能进行计算操作的队列.

某些队列可能只对应于主机端调度程序中的单独队列,其他队列可能对应于硬件中的实际独立队列.例如,许多GPU只有一个硬件图形队列,因此即使您从具有图形功能的队列系列创建两个VkQueue,提交给这些队列的命令缓冲区也将独立地通过内核驱动程序的命令缓冲区调度程序,但将以某些序列执行在GPU上订购.但是一些GPU具有多个仅计算硬件队列,因此仅用于计算的队列系列的两个VkQueue实际上可以在GPU中一直独立并同时进行. Vulkan不公开这个.

最重要的是,根据您拥有的并发数量,确定可以有效使用的队列数.对于许多应用程序,只需要一个“通用”队列.更高级的可能有一个图形计算队列,一个用于异步计算工作的单独的仅计算队列,以及用于异步DMA的传输队列.然后将你想要的东西映射到可用的东西上;您可能需要进行自己的多路复用,例如在没有仅计算队列系列的设备上,您可以改为创建多个图形计算队列,或者自己将异步计算作业序列化到单个图形计算队列中.

[* 1]过度简化了一下.它们按顺序启动,但允许在此之后独立进行并完成故障.但是不保证不同队列的独立进度.对于这个问题我会留下它.

上一篇:JPBC库实现基于身份的签名*


下一篇:[译]Vulkan教程(01)入门