译者注:示例代码点击此处
我们记录了命令缓冲区,希望利用图形硬件的能力来处理准备好的操作。接下来做什么?我们需要将准备好的工作提交到选定的列队。
在本文中,我们将使用自定义WaitSemaphoreInfo类型的变量。它的定义如下:
struct WaitSemaphoreInfo {
VkSemaphore Semaphore;
VkPipelineStageFlags WaitingStage;
};
通过它,我们提供一个信号量的句柄,硬件在处理给定的命令缓冲区之前应该等待,并且我们还指定应该在哪个管道阶段进行等待。
1.获取应该提交工作的队列的句柄。使用句柄初始化名为queue的VkQueue类型变量。
2.创建一个名为wait_semaphore_handles的std::vector
3.创建一个名为wait_semaphore_stages的std::vector
4.准备名为command_buffers的std::vector
5.创建一个名为signal_semaphores的std::vector
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标志记录命令缓冲区时才能执行此操作,但出于性能原因,应该避免使用此标志。