Vulkan编程指南翻译 第三章 队列和命令 第2节 创建命令缓冲区

2017-02-20

第三章 队列和命令 第3节 创建命令缓冲区

 

 

创建命令缓冲区

队列的意义就是应用程序内处理任务。任务通过一串的命令表示的,命令被记录到命令缓冲区(command buffer)中。你的应用将会创建包含任务的命令缓冲区进而提交到队列来执行记录任何命令之前,你需要创建命令缓冲区。命令缓冲区并不被直接创建,需要从pool中分配。你可以调用vkCreateCommandPool() 函数来创建pool,其原型如下:

VkResult vkCreateCommandPool (

VkDevice  device,

const VkCommandPoolCreateInfo*  pCreateInfo,

const VkAllocationCallbacks*  pAllocator,

VkCommandPool*  pCommandPool);

Vulkan中绝大多数对象创建一样,它的第一个参数device,就是拥有该pool的设备对该pool的描述信息是通过一个指向某个数据结构的指针pCreateInfo传递的。这个数据结构就是VkCommandPoolCreateInfo,定义如下:

typedef struct VkCommandPoolCreateInfo {

VkStructureType  sType;

const void*  pNext;

VkCommandPoolCreateFlags  flags;

uint32_t  queueFamilyIndex;

} VkCommandPoolCreateInfo;

大多数Vulkan数据结构类似,前两个是sType  pNext前一包含了数据结构的类型,后一个是一指向包含更多关于pool创建信息的数据。这里我们设置sTypeK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO我们不需要传递任何其他信息,pNext需被设置为nullptr。

flags域包含标志,它控制了pool和从pool分配得倒的命令缓冲区的行为其值为VkCommandPoolCreateFlagBits枚举类型。这个枚举现在有两个值被定义了:

VK_COMMAND_POOL_CREATE_TRANSIENT_BIT 表示命令缓冲区使用周期短,使用完后马上退回给pool。设置这个枚举值,就意味着告诉Vulkan,你将长时间的持有这个命令缓冲区。

VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT表示允许单独的命令缓冲区可通过重置重启而被重用如果没有这个bit标志那么只有pool本身能够被重置,这隐式的回收所有由它分配出的命令缓冲区。

每一个bit标志位都会增加一些开销,因为Vulkan实现需要跟踪资源或者改变其自身分配策略。例如设置VK_COMMAND_POOL_CREATE_TRANSIENT_BIT这个标志位导致Vulkan实现跟踪每一个命令缓冲区的重置状态而不是简单的只是在pool内跟踪。在这种情形下我们实际上需要两个标志位都设置上。这将给我们极大的灵活性,可能在一些性能损失条件下,我们可以批量的管理命令缓冲区。

最后,VkCommandPoolCreateInfo queueFamilyIndex域指定这个pool分配的命令缓冲区需要提交的队列的所属的集合这是必需的,因为一个设备上拥有相同性能并具有相同命令的两个队列,发送相同命令到他们,表现也会各异。

pAllocator参数应用程序用来管理主机内存的,这部分在第二章有讲解。假设一个命令池被成功的创建,它的handle被赋值给pCommandPoolvkCreateCommandPool()就会返回VK_SUCCESS

一旦我们有了一个可以分配命令缓冲区的pool,我们可以通过调用vkAllocateCommandBuffers()得到新的命令缓冲区其原型如下:

VkResult vkAllocateCommandBuffers (

VkDevice  device,

const VkCommandBufferAllocateInfo*  pAllocateInfo,

VkCommandBuffer*  pCommandBuffers);

分配额命令缓冲区的设备通过device参数传递,剩余的参数描述了命令缓冲区,是通过一个VkCommandBufferAllocateInfo类型数据传递的缓冲区的地址是通过pCommandBuffers参数传递的VkCommandBufferAllocateInfo原型如下:

typedef struct VkCommandBufferAllocateInfo {

VkStructureType  sType;

const void*  pNext;

VkCommandPool  commandPool;

VkCommandBufferLevel  level;

uint32_t  commandBufferCount;

} VkCommandBufferAllocateInfo; sType应当赋值为VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO当我们仅仅使用核心功能集的时候,需要设置pNextnullptr。我在之前创建的命令池被放入了commandPool参数
level参数表示我们需要分配的命令缓冲区的级别。它可以被赋值为VK_COMMAND_BUFFER_LEVEL_PRIMARY或者VK_COMMAND_BUFFER_LEVEL_SECONDARY.Vulkan允许主命令缓冲区来调用次命令缓冲区。在我们最初的几个例子中,我们将使用主级别的命令缓冲区。将在本书的后面讲到次级命令缓冲区。

最后,commandBufferCount指定我们想要从pool中分配的命令缓冲区的数量注意,我们并没有告诉Vulkan任何关于我们需要的命令缓冲区的大小和个数。表示设备命令的内部内部数据将自由的变动以适应任意尺寸大小command。Vulkan替你管理好命令缓冲区的内存。

如果vkAllocateCommandBuffers()运行成功,会返回VK_SUCCESS并且把分配好的多个命令缓冲区handle放到pCommandBuffers这个数组。这个数组应当足够的大以容纳这些handle当然,如果你想仅仅分配一个命令缓冲区,可以只声明一个普通的VkCommandBuffer类型的变量即可。

需要使用vkFreeCommandBuffers()释放命令缓冲区,其声明如下:

 

void vkFreeCommandBuffers (

VkDevice  device,

VkCommandPool  commandPool,

uint32_t  commandBufferCount,

const VkCommandBuffer*  pCommandBuffers);

device参数是进行命令缓冲区分配所在的设备commandPoolpool的handle,commandBufferCount需要释放的命令缓冲区的个数,pCommandBuffers需要被释放的命令缓冲区的handle组成的数组。注意,释放一个命令缓冲区并不意味着需要释放与它相关的资源,只是把它们放回了他们被创建所在的pool。

为了释放一个命令池所用所有资源它创建的所有命令缓冲区,需要调用vkDestroyCommandPool(),原型如下:

void vkDestroyCommandPool (

VkDevice  device,

VkCommandPool  commandPool,

const VkAllocationCallbacks* pAllocator);

拥有命令池设备是通过device参数传入的,需要销毁的命令池通过commandPool参数传递pAllocator参数应当和pool创建时所用的该参数保持一致。如果vkCreateCommandPool()pAllocator参数是nullptr,这个函数中的pAllocator参数也应该为nullptr。

pool销毁之前,没有必要显式的释放所有从它分配出来的命令缓冲区pool被销毁时,分配出来命令缓冲区,作为pool的组成部分,会自动的被释放,每个缓冲区相关的资源同样会被释放。然而这里需要注意需要保证当vkDestroyCommandPool()调用时,从pool分配出来的命令缓冲区正在执行。

 

 

如果有任何意见,欢迎留言讨论。


[ 主页 ]
COMMENTS
POST A COMMENT

(optional)



(optional)