08/09/2020
文章目录
渲染和呈现三步骤
- 从交换链获取一张图像
- 使用该图像作为帧缓冲区中的附件执行命令缓冲区,进行绘制工作
- 将绘制完的图像返回给交换链并呈现出来
以上3个步骤可以异步执行,但是需要保证执行结果,所以需要同步机制
同步
由于Vulkan大多数操作都是多线程,如果某些步骤需要同步,即按照顺序执行,我们需要启动同步机制。
栅栏和信号量(fences and Semaphores)
- 栅栏和信号量机制实现时间的同福,fences主要用于客户程序和Vulkan之间的同步,信号量完全交给Vulkan自己使用,用户不需要管理这个信号量
它们都是对象,它们可以通过发出一个操作信号来进行协调操作,而另一个操作则等待栅栏或信号灯从无信号状态变为发信号状态。区别在于可以使用vkWaitForFences之类的调用从程序中访问fence状态,而信号量则不能。栅栏主要用于将应用程序本身与呈现操作同步,而信号量用于在命令队列之内或之间同步操作。我们要同步绘制命令和表示的队列操作,这使信号量最合适。
创建Semaphores 信号量
信号量用于在命令队列内或者跨命令队列同步操作,我们需要同步绘制与呈现的队列操作。
两个信号量,一个表示准备进行渲染,另一个表示渲染结束,准备呈现
VkSemaphore imageAvailableSemaphore;
VkSemaphore renderFinishedSemaphore;
void createSemaphores()
{
VkSemaphoreCreateInfo semaphoreInfo{
};
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphore) != VK_SUCCESS ||
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphore) != VK_SUCCESS)
{
throw std::runtime_error("failed to create semaphores!");
}
}
第一步:从交换链获取下一帧的图像
//acquire an image from the swap chain
uint32_t imageIndex;
vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphore,
VK_NULL_HANDLE, &imageIndex);
首先因为交换链是一个扩展,我们需要使用vkXXXKHR来使用扩展函数。
- 第三参数:指定图像可用的超时时间(以纳秒为单位)。使用64位无符号整数的最大值可禁用超时
- 接下来的两个参数指定使用的同步对象,当presentation引擎完成了图像的呈现后会使用该对象发起信号。这就是开始绘制的时间点。它可以指定一个信号量semaphore或者栅栏或者两者。出于目的性,我们会使用imageAvailableSemaphore。
- 最后一个参数:最后一个参数指定一个变量,以输出已可用的交换链图像的索引。索引引用了我们swapChainImages数组中的VkImage。我们将使用该索引来选择正确的命令缓冲区
第二步:执行命令缓冲区开始绘图
基本逻辑:
- 绘图之前,需要等待图像准备完成的信号,但只需要在图形管道的COLOR_ATTACHMENT_OUTPUT等待
- 一旦绘图完成,发射渲染完成信号
//submit the command buffer
VkSubmitInfo submitInfo{
};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
//参数指定在执行开始之前要等待的哪个信号量及要等待的通道的哪个阶段
VkSemaphore waitSemaphores[] = {
imageAvailableSemaphore };
VkPipelineStageFlags waitStages[] = {
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; //等待图像状态变为available
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages;
//应该提交命令缓冲区,它将我们刚获取的交换链图像做为颜色附件进行绑定。
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffers[imageIndex]; //提交命令缓冲区
//当命令缓冲区执行结束向哪些信号量发出信号
VkSemaphore signalSemaphores[] =