为什么在使用信号量时每个swapchain命令缓冲区都需要VkFence?

时间:2016-09-20 16:45:53

标签: c++ vulkan

我正在使用交换链的3个图像和每个交换链图像一个VkCommandBuffer(CB)。 GPU同步由两个信号量完成,一个用于presentation_finished,另一个用于rendering_finished。目前的模式是VK_PRESENT_MODE_MAILBOX_KHRquick overview)。

现在,当我在不等待任何CB围栏的情况下运行我的示例时,验证层会在第二次使用任何交换链图像时立即报告此错误:

  

在活动CB完成之前调用vkBeginCommandBuffer()。您必须在此次通话前检查CB围栏。

乍一看,这对我来说似乎是合理的,因为处理来自CB的命令可能还没有完成。但我想的越多,我就越能得出结论,这根本不会发生。

我目前的理解是当vkAcquireImageKHR返回特定图像索引时,它意味着返回的图像必须通过渲染完成。

这是因为我正在将rendering_finished信号量传递给vkQueueSubmit以在渲染结束时发出信号,并vkQueuePresentKHR等待它在呈现图像之前发出信号。

VkQueuePresentInfoKHR的规范说:

  

pWaitSemaphores,如果不是VK_NULL_HANDLE,则是VkSemaphore个带waitSemaphoreCount个条目的对象数组,并指定在发出当前请求之前要等待的信号量

含义:我永远不会出现任何没有渲染渲染的图像,因此一旦图像出现,相关的CB就不能再使用了。

第二个信号量presentation_finishedvkAqcuireImageKHR发出信号并传递给相同的vkQueueSubmit(开始渲染)。这意味着任何图像的渲染都不会早于演示引擎允许的开始。

总结:来自vkQueuePresentKHR的当前请求不会在图像渲染完成之前发出,vkAcquireImageKHR会阻塞,直到图像可用,并且永远不会返回当前获取的图像。

我错过了什么使围栏变​​得必要?

我已经包含了一个最小的代码示例,其中仅包含概念上重要的部分来说明问题。

VkImage[] swapchain_images;
VkCommandBuffer[] command_buffers;

VkSemaphore rendering_finished;
VkSemaphore presentation_finished;

void RenderLoop()
{
    /* Acquire an image from the swapchain. Block until one is available.
       Signal presentation_finished when we are allowed to render into the image */
    int index;
    vkAcquireImageKHR(device, swapchain, UINT64_MAX, presentation_finished, nullptr, &index);

    /* (...) Frambuffer creation, etc. */

    /* Begin CB: The command pool is flagged to reset the command buffer on reuse */
    VkCommandBuffer cb = command_buffers[index];
    vkBeginCommandBuffer(cb, ...);

    /* (...) Trivial rendering of a single color image */

    /* End CB */
    vkEndCommandBuffer(cb);


    /* Queue the rendering and wait for presentation_finished.
       When rendering is finished, signal rendering_finished.

       The VkSubmitInfo will have these important members set among others:
       .pWaitSemaphores = &presentation_finished;
       .pSignalSemaphores = &rendering_finished;
    */
    vkQueueSubmit(render_queue, &submit_info);

    /* Submit the presentation request as soon as the rendering_finished
       semaphore gets signalled

       The VkPresentInfoKHR will have these important members set among others:
       .pWaitSemaphores = &rendering_finished;
    */
    vkQueuePresentKHR(present_queue, &present_info);
}

在将CB提交到渲染队列并在再次使用该CB之前等待它时插入栅栏显然可以解决问题,但是 - 正如所解释的那样 - 似乎是多余的。

1 个答案:

答案 0 :(得分:19)

允许

vkAcquireNextImageKHR返回仍然是正在进行的异步操作的目标和/或源的映像。这意味着您无法保证在重用时命令缓冲区可用。只要这些命令配置为在presentation_finished信号量上等待,正确地排队其他不同的命令缓冲区以写入所获取的图像。但要安全地重用该命令缓冲区,您必须等待传递给vkQueueSubmit的栅栏。

使用KHR扩展程序查看Vulkan规范中的section 29.6. WSI Swapchain

  

应用程序可以使用vkAcquireNextImageKHR获取可呈现图像的使用。获取可呈现的图像并在修改之前,应用程序必须使用同步原语来确保表示引擎已完成从图像中读取。应用程序可以将图像的布局,队列渲染命令转换为最后,应用程序使用vkQueuePresentKHR显示图像,该图像释放图像的采集。

另请参阅vkAcquireNextImageKHR

的这些说明
  

成功时,vkAcquireNextImageKHR获取应用程序可以使用的可呈现图像,并将pImageIndex设置为该图像的索引。演示引擎在获取图像时可能尚未完成读取,因此应用程序必须使用信号量和/或栅栏以确保图像布局和内容不会被修改直到演示引擎读取已完成

     

[...]

     

如上所述,呈现引擎可以与应用程序和/或逻辑设备异步。 vkAcquireNextImageKHR可以在识别出将要获取的图像后立即返回,并且可以保证信号量和围栏将由演示引擎发出信号;并且可能不会很快成功返回。应用程序使用超时来指定vkAcquireNextImageKHR等待获取图像的时间。

这表明vkAcquireNextImageKHR不需要阻止表示操作,并且传统上不需要阻止表示操作本身等待的图形命令。