Link

cmake

Vulkan 命令执行

与 OpenGL 或 DirectX pre-11 不同,在 Vulkan 中,所有 GPU 命令都必须通过命令缓冲区,并通过队列执行。

执行命令的一般流程是

  • 您从 VkCommandPool 分配一个 VkCommandBuffer
  • 您使用 VkCmdXXXXX 函数将命令记录到命令缓冲区中。
  • 您将命令缓冲区提交到 VkQueue 中,这将开始执行命令。

可以多次提交相同的命令缓冲区。在教程和示例中,通常的做法是记录一次命令,然后在渲染循环中每帧提交它们。在本教程中,我们将每帧记录命令,因为它更贴近实际渲染引擎的工作方式。

在 Vulkan 中记录命令相对便宜。通常,开销大的操作是 VkQueueSubmit 调用,驱动程序会在其中验证命令缓冲区并在 GPU 上执行它。

命令缓冲区非常重要的一部分是它们可以并行记录。您可以从不同的线程安全地记录不同的命令缓冲区。为此,您需要每个线程(至少) 1 个 VkCommandPool 和 1 个 VkCommandBuffer,并确保每个线程仅使用其自己的命令缓冲区和池。完成此操作后,可以在其中一个线程中提交命令缓冲区。vkQueueSubmit 不是线程安全的,一次只有一个线程可以在给定的队列上推送命令。在大型引擎中,通常从后台线程完成提交,这样主渲染循环线程可以继续执行。

VkQueue

Vulkan 中的队列是 GPU 的“执行端口”。每个 GPU 都有多个可用的队列,您甚至可以同时使用它们来执行不同的命令流。提交到不同队列的命令可能会同时执行。如果您正在执行与主帧循环不太相关的后台工作,这将非常有用。您可以专门为所述后台工作创建一个 VkQueue,并使其与正常渲染分离。

Vulkan 中的所有队列都来自队列族。队列族是队列的“类型”,以及它支持的命令类型。

不同的 GPU 支持不同的队列族。一个例子是来自 Vulkan Hardware Info 的这个 NVidia GT 750ti 链接。它有 2 个队列族,一个最多支持 16 个具有所有功能的队列,另一个族可以支持 1 个仅用于传输的队列。 这里 您有一个高端 AMD 显卡的示例,有 5 个队列族,每种类型最多 2 个队列。它有 1 个支持所有功能的队列,最多 2 个支持计算和传输的队列,2 个专用传输队列,以及 2 个仅用于 Present 的其他队列。如您所见,每个 GPU 支持的队列可能差异很大。

常见的引擎使用 3 个队列族。一个用于绘制帧,另一个用于异步计算,另一个用于数据传输。在本教程中,为了简单起见,我们使用一个队列来运行所有命令。

VkCommandPool

VkCommandPool 是从 VkDevice 创建的,您需要此命令池将从中创建命令的队列族的索引。

VkCommandPool 视为 VkCommandBuffer 的分配器。您可以从给定的池中分配任意数量的 VkCommandBuffer,但一次只能从一个线程记录命令。如果您想要多线程命令记录,则需要更多 VkCommandPool 对象。因此,我们将命令缓冲区与其命令分配器配对。

VkCommandBuffer

GPU 的所有命令都记录在 VkCommandBuffer 中。所有将执行 GPU 工作的函数在命令缓冲区通过 VkQueueSubmit 调用提交到 GPU 之前都不会执行任何操作。

命令缓冲区以就绪状态启动。在就绪状态下,您可以调用 vkBeginCommandBuffer() 使其进入记录状态。现在,您可以使用 vkCmdXXXXX 函数开始向其中输入命令。完成后,调用 vkEndCommandBuffer() 以完成记录命令并将其置于可执行状态,在该状态下可以将其提交到 GPU。

要提交命令缓冲区,请调用 vkQueueSubmit(),同时使用命令和要提交到的队列。vkQueueSubmit 也接受一起提交多个命令缓冲区。任何提交的命令缓冲区都将置于挂起状态。

提交命令缓冲区后,它仍然“存活”,并被 GPU 消耗,此时重置命令缓冲区尚不安全。您需要确保 GPU 已完成执行该命令缓冲区中的所有命令,然后才能重置并重复使用它

要重置命令缓冲区,请使用 vkResetCommandBuffer()

由于我们希望在执行命令缓冲区时继续绘制下一帧,因此我们将对命令进行双缓冲。这样,当 GPU 忙于渲染和处理一个缓冲区时,我们可以写入另一个缓冲区。

有关命令缓冲区生命周期的更多详细信息,请参阅 Vulkan 规范中关于它们的章节 https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/chap6.html#commandbuffers-lifecycle

下一步: 设置 Vulkan 命令