Skip to content

Latest commit

 

History

History
78 lines (45 loc) · 7.27 KB

05 - 指令缓冲.md

File metadata and controls

78 lines (45 loc) · 7.27 KB

05 - 指令缓冲

命令缓冲区是用于记录命令的对象,这些命令随后可提交到设备队列执行。命令缓冲区分为两级——一级命令缓冲区和二级命令缓冲区,前者可以执行二级命令缓冲区,并提交给队列;后者可以由一级命令缓冲区执行,但不直接提交给队列。

命令缓冲区由 VkCommandBuffer 句柄表示:

// Provided by VK_VERSION_1_0
VK_DEFINE_HANDLE(VkCommandBuffer)

记录的命令包括将管线和描述符集绑定到命令缓冲区的命令、修改动态状态的命令、绘制命令(用于图形渲染器)、调度命令(用于计算)、执行二级命令缓冲区的命令(仅适用于一级命令缓冲区)、复制缓冲区和图像的命令以及其他命令。

每个命令缓冲区都独立于其他命令缓冲区管理状态。主命令缓冲区和辅助(secondary)命令缓冲区之间或辅助(secondary)命令缓冲区之间的状态都不会继承。当一个命令缓冲区开始录制时,该命令缓冲区中的所有状态都是未定义的。当记录辅助(secondary)命令缓冲区以在主命令缓冲区上执行时,辅助命令缓冲区不会从主命令缓冲区继承任何状态,并且在记录执行辅助命令缓冲区命令后,主命令缓冲区的所有状态都未定义。 这条规则有一个例外——如果主命令缓冲区位于渲染器通道实例内部,那么渲染器通道和子通道状态不会受到执行二级命令缓冲区的干扰。对于依赖于状态的命令(如绘制和派发),这些命令消耗的任何状态都不能是未定义的。

VkCommandBufferInheritanceViewportScissorInfoNV 定义了一个例外,允许有限地继承动态视口和剪刀(scissor,窗口裁切)状态。

除非另有规定,在没有显式同步的情况下,通过命令缓冲区提交到队列的各种命令可以任意顺序相对执行,和/或同时执行。此外,如果没有明确的内存依赖关系,其他命令可能无法直接看到这些命令的内存副作用。在一个命令缓冲区内如此,在提交给特定队列的命令缓冲区之间也是如此。有关命令间隐式和显式同步的信息,请参阅同步章节。

指令缓冲生命周期

每个命令缓冲区始终处于以下状态之一:

初始状态 分配命令缓冲区时,缓冲区处于初始状态。某些命令可以将一个命令缓冲区(或一组命令缓冲区)从可执行状态、记录状态或无效状态重置回初始状态。处于初始状态的命令缓冲区只能移动到记录状态或释放。

记录 vkBeginCommandBuffer 会将命令缓冲区的状态从初始状态更改为记录状态。一旦命令缓冲区进入记录状态,就可以使用 vkCmd.... 命令记录命令缓冲区。

可执行 vkEndCommandBuffer 结束命令缓冲区的记录,并将其从记录状态移至可执行状态。可执行的命令缓冲区可以提交、重置或记录到另一个命令缓冲区。

待处理(pending,未决状态) 队列提交命令缓冲区会将命令缓冲区的状态从可执行状态变为待处理状态。在待处理状态下,应用程序不得试图以任何方式修改命令缓冲区,因为设备可能正在处理记录到该缓冲区的命令。一旦命令缓冲区执行完毕,命令缓冲区要么恢复到可执行状态,要么(如果使用 VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT 记录)转入无效状态。应使用同步命令来检测何时出现这种情况。

无效 某些操作(如修改或删除记录到命令缓冲区的命令中使用的资源)会将该命令缓冲区的状态转换为无效状态。处于无效状态的命令缓冲区只能被重置或释放。

对命令缓冲区进行操作的任何给定命令对命令缓冲区必须处于何种状态都有自己的要求,这些要求详见该命令的有效使用限制。

重置命令缓冲区是一种丢弃先前记录的任何命令并将命令缓冲区置于初始状态的操作。重置是 vkResetCommandBuffer 或 vkResetCommandPool 的结果,或者是 vkBeginCommandBuffer 的一部分(它会额外将命令缓冲区置于记录状态)。

二级命令缓冲区可通过 vkCmdExecuteCommands 记录到一级命令缓冲区。这在一定程度上将两个命令缓冲区的生命周期联系在一起——如果主命令缓冲区被提交到队列中,主命令缓冲区和记录到主命令缓冲区的次命令缓冲区都会进入待执行状态。一旦主命令执行完毕,其中记录的任何辅助命令也会执行完毕。每个命令缓冲区的所有执行完成后,它们都会移动到相应的完成状态(如上所述,要么是可执行状态,要么是无效状态)。

如果二级缓存移动到无效状态或初始状态,则所有记录二级缓冲的一级缓冲都会移动到无效状态。主缓冲区移动到任何其他状态都不会影响记录在其中的次缓冲区的状态。

Note

重置或释放主命令缓冲区会删除与记录在其中的所有辅助命令缓冲区的生命周期关联。

指令池

命令池是一种不透明对象,命令缓冲区内存就是从命令池中分配的,这样就可以在多个命令缓冲区中分摊创建资源的成本。命令池是外部同步的,这意味着命令池不得在多个线程中同时使用。这包括通过记录命令使用从命令池分配的任何命令缓冲区,以及分配、释放和重置命令缓冲区或命令池本身的操作。

指令缓冲的分配与管理

命令缓冲区记录

命令缓冲区提交

队列转发进度(Queue Forward Progress)

在使用二进制 semaphore 时,应用程序必须确保命令缓冲区的提交能够在没有应用程序对任何队列进行任何后续操作的情况下完成。在任何对 vkQueueSubmit(或其他队列操作)的调用之后,对于使用 VkSemaphoreType 为 VK_SEMAPHORE_TYPE_BINARY 的 semaphore 创建的每个队列等待,该 semaphore 必须有一个不会被该 semaphore 上的其他等待占用的前置信号。

在使用时间线 semaphores 时,"先等待后信号 "的行为定义明确,应用程序可以在提交相应的 semaphore 信号操作之前,通过 vkQueueSubmit 提交工作,定义时间线 semaphore 等待操作。对于调用 vkQueueSubmit 所定义的每个时间线信号等待操作,应用程序必须确保在向前推进之前执行了相应的信号操作。

如果命令缓冲区提交等待任何事件信号,应用程序必须确保命令缓冲区提交能够在没有应用程序任何后续操作的情况下完成。主机发出信号的事件必须在命令缓冲区等待这些事件之前发出信号。

Note

命令等待主机设置事件的功能最初是为了实现主机和设备之间资源的低延迟更新。但是,为了确保服务质量,实现过程中必须检测到执行过程中的长时间停滞,并在短时间后超时。由于 Vulkan 规范中没有定义这个时间段,因此无法正确验证任何应用程序的等待时间。由于该功能的最初用户非常有限,而且是针对特定平台的,因此现在该功能已被视为失效,不应再使用。

二级命令缓冲区执行

嵌套命令缓冲区

命令缓冲区设备掩码