Vulkan Cookbook 第三章 11 将命令缓冲区提交到队列

将命令缓冲区提交到队列

译者注:示例代码点击此处

我们记录了命令缓冲区,希望利用图形硬件的能力来处理准备好的操作。接下来做什么?我们需要将准备好的工作提交到选定的列队。

做好准备

在本文中,我们将使用自定义WaitSemaphoreInfo类型的变量。它的定义如下:


struct WaitSemaphoreInfo { 
  VkSemaphore           Semaphore; 
  VkPipelineStageFlags  WaitingStage; 
};

通过它,我们提供一个信号量的句柄,硬件在处理给定的命令缓冲区之前应该等待,并且我们还指定应该在哪个管道阶段进行等待。

怎么做...

1.获取应该提交工作的队列的句柄。使用句柄初始化名为queue的VkQueue类型变量。
2.创建一个名为wait_semaphore_handles的std::vector类型变量。如果提交的命令应等待其他命令结束,在变量中存储给定队列应该等待的所有信号量的句柄。
3.创建一个名为wait_semaphore_stages的std::vector类型变量。如果提交的命令应等待其他命令结束,则使用管道阶段初始化向量,在该阶段,队列应等待来自wait_semaphore_handles变量的相应信号量以发出信号。
4.准备名为command_buffers的std::vector类型变量。存储应提交到所选队列的所有记录命令缓冲区的句柄。确保设备当前没有处理这些缓冲区,或者使用VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT标志记录这些命令缓冲区。
5.创建一个名为signal_semaphores的std::vector 6.创建一个名为fence的VkFence类型变量。如果在完成command_buffers变量中提交的所有命令缓冲区的处理时应发送围栏信号,请将此围栏的句柄储存在fence变量中。否则使用VK_NULL_HANDLE值初始化此变量。
7.创建名为submit_info的VkSubmitInfo类型的变量。使用一下值初始化其成员:
  ·sType为VK_STRUCTURE_TYPE_SUBMIT_INFO
  ·pNext为nullptr
  ·waitSemaphoreCount为wait_semaphore_handles向量中的元素数量
  ·pWaitSemaphores为指向wait_semaphore_handles向量的第一个元素的指针如果向量是空则为nullptr值。
  ·pWaitDstStageMask为指向wait_semaphore_stages向量的第一个元素的指针如果向量是空则为nullptr值。
  ·commandBufferCount提交的命令缓冲区数量(command_buffers向量中的元素数量)。
  ·pCommandBuffers为指向command_buffers向量的第一个元素的指针如果向量是空则为nullptr值。
  ·signalSemaphoreCount为signal_semaphores向量中的元素数量。
  ·pSignalSemaphores为指向signal_semaphores向量的第一个元素的指针如果向量是空则为nullptr值。
8.调用vkQueueSubmit( queue, 1, &submit_info, fence )并且提供提交工作的队列句柄、1值、指向submit_info变量的指针和fence变量。
9.通过检查返回值是否是VK_SUCCESS值,确保调用成功。

这个怎么运作...

当我们将命令缓冲区提交给设备的队列时,一旦提交到同一队列的之前命令处理完成,它们就会被执行。从应用程序的角度来看,我们不知道命令何时将被执行。它可能会立即开始或稍后开始。

当我们想要推迟处理提交的命令时,需要通过提供一个信号量列表来同步它们,给定队列应该在执行提交的命令缓冲区之前等待。

当我们提交命令缓冲区并提供信号量列表时,每个信号量都与一个通道阶段相关联。执行命令直到它们到达指定的管道阶段,它们暂停并等待信号量发出信号。

在提交期间,信号量和管道阶段位于单独的数组中。因此我们需要将自定义类型WaitSemaphoreInfo的元素向量拆分为两个独立的向量:

std::vector          wait_semaphore_handles; 
std::vector wait_semaphore_stages; 

for( auto & wait_semaphore_info : wait_semaphore_infos ) { 
  wait_semaphore_handles.emplace_back( wait_semaphore_info.Semaphore ); 
  wait_semaphore_stages.emplace_back( wait_semaphore_info.WaitingStage ); 
};

现在,我们已准备好接受提交。对于提交,命令缓冲区应该等待信号量、执行等待的管道阶段、命令缓冲区和用信号通知的另一个信号量列队,都是通过VkSubmitInfo类型变量指定的:

VkSubmitInfo submit_info = {
  VK_STRUCTURE_TYPE_SUBMIT_INFO,
  nullptr,
  static_cast(wait_semaphore_infos.size()),   
  wait_semaphore_handles.size() > 0 ? &wait_semaphore_handles[0] : nullptr, 
  wait_semaphore_stages.size() > 0 ? &wait_semaphore_stages[0] : nullptr,   
  static_cast(command_buffers.size()),
  command_buffers.size() > 0 ? &command_buffers[0] : nullptr,   
  static_cast(signal_semaphores.size()), 
  signal_semaphores.size() > 0 ? &signal_semaphores[0] : nullptr
};

然后像这样提交这批数据:

VkResult result = vkQueueSubmit( queue, 1, &submit_info, fence ); 
if( VK_SUCCESS != result ) {
  std::cout << "Error occurred during command buffer submission." << std::endl;
  return false; 
}
return true;

当我们提交命令缓冲区时,设备将执行记录的命令并产生所需的结果,例如它将在屏幕上绘制3D场景。这里我们只提交一批命令缓冲区,但可以提交多个批次。

提示:出于性能原因,我们应尽可能少调用函数而每次调用尽可能多的提交批次。

如果已经提交了命令缓冲区并且它们的执行尚未结束,我们就不应该再提交它们,只有在使用VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT标志记录命令缓冲区时才能执行此操作,但出于性能原因,应该避免使用此标志。

你可能感兴趣的:(Vulkan,Cookbook)