记录命令
命令是通过使用Vulkan命令函数记录到命令缓冲区的,这些函数都接受一个命令缓冲区的handle作为第一个参数。对命令缓冲区的访问必须是同步的,意味着应用程序需负责保证没有两个线程同时记录命令到同一个命令缓冲区中。然而,下面的情形是可以接受的:
l 一个线程可以通过调用命令缓冲区函数,依次的记录命令进入到多个命令缓冲区中。
l 两个或多个线程可以参加建立一个命令缓冲区的过程,只要应用程序可以保证它们不同时执行命令缓冲区建立的函数。
Vulkan的一个关键的设计原则是让程序可以多线程的工作。为此,要保证应用程序的多个线程不会互相堵塞,比如,不会因对共享资源加锁而导致堵塞其他线程。因此,最好是一个线程有一个或者多个命令缓冲区,而不是共享一个。因命令缓冲区是从pool中分配而来,你可以进一步的为每一个线程创建命令池,允许多个命令缓冲区都是从自己线程的命令池中获取的,这样就不会有任何冲突了。
在你往一个命令缓冲区录入命令之前,你需要启动命令缓冲区,这将导致它处于初始状态,这需要调用vkBeginCommandBuffer(),原型如下:
VkResult vkBeginCommandBuffer (
VkCommandBuffer commandBuffer,
const VkCommandBufferBeginInfo* pBeginInfo);
需要开始记录命令的命令缓冲区是通过commandBuffer参数传递的,记录命令需要用的参数是通过一个VkCommandBufferBeginInfo类型的变量pBeginInfo,通过指针传递的。VkCommandBufferBeginInfo的定义如下:
typedef struct VkCommandBufferBeginInfo {
VkStructureType sType;
const void* pNext;
VkCommandBufferUsageFlags flags;
const VkCommandBufferInheritanceInfo* pInheritanceInfo;
} VkCommandBufferBeginInfo;
sType域应当被设置为VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,pNext应被设置为nullptr。flags域是用来告诉Vulkan命令缓冲区将会被如何使用。它的值是VkCommandBufferUsageFlagBits枚举变量某几个值的组合得到的,枚举类型有以下选项:
l VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT意味着命令缓冲区就会被记录,只会被执行一次,然后被销毁、回收。
l VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT意味着这个命令缓冲区就会被用在renderpass内部,此类型只对次级命令缓冲区有效。如果用于主命令缓冲区,那么它会被无视。Renderpass和次级命令缓冲区将在第十三章“”讲解。
l VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT 意味着命令缓冲区有可能被多次执行或者暂停
把flags设置为0是安全的,意味着我们可能多次执行命令缓冲区,但不同时访问也不需要次级命令缓冲区。
pInheritanceInfo成员是用来开启次级命令缓冲区所需要的,来定义被继承的主命令缓冲区的状态。对于主命令缓冲区,这个指针参数被忽略。我们将在第十三章讲解次级命令缓冲区时介绍VkCommandBufferInheritanceInfo类型的结构
现在,我们需要创建首个命令来。在第二章中,已经学到了缓冲,图像,内存。vkCmdCopyBuffer()命令是用来在两个buffer对象之间拷贝数据的,原型如下:
void vkCmdCopyBuffer (
VkCommandBuffer commandBuffer,
VkBuffer srcBuffer,
VkBuffer dstBuffer,
uint32_t regionCount,
const VkBufferCopy* pRegions);
这是一个常见形式的Vulkan命令。第一个参数commandBuffer,指定了命令需要追加到的哪个命令缓冲区。srcBuffer和dstBuffer指定了源地址和目的地址。最后,一个regions的数组是通过pRegions指定的。每一个region代表着一个VkBufferCopy类型的数据,定义如下:
typedef struct VkBufferCopy {
VkDeviceSize srcOffset;
VkDeviceSize dstOffset;
VkDeviceSize size;
} VkBufferCopy;这个数组的每一个元素都仅包含源和目标的偏移值,和每个region从srcOffset到dstOffset需要拷贝的大小。当命令被执行时,在pRegions中的每一个region,size 大小的数据将会从srcBuffer的srcOffset拷贝到dstBuffer的dstOffset。这些偏移值都是以byte为单位的。
关于Vulkan操作的很基础的事实是命令在被调用时并不是被立即执行的。他们仅仅是被添加到命令缓冲区中了。如果你正在从或者到一个CPU可访问的内存区域拷贝数据,那么,你需要确认以下几件事:
l 保证在命令被设备执行前,数据一直都在源区域
l 保证在命令在设备上执行后,源区域的数据是有效的
l 保证直到命令在设备上执行命令后,