我正在使用交换链的3个图像和每个交换链图像一个VkCommandBuffer
(CB)。 GPU同步由两个信号量完成,一个用于presentation_finished
,另一个用于rendering_finished
。目前的模式是VK_PRESENT_MODE_MAILBOX_KHR
(quick overview)。
现在,当我在不等待任何CB围栏的情况下运行我的示例时,验证层会在第二次使用任何交换链图像时立即报告此错误:
乍一看,这对我来说似乎是合理的,因为处理来自CB的命令可能还没有完成。但我想的越多,我就越能得出结论,这根本不会发生。在活动CB完成之前调用
vkBeginCommandBuffer()
。您必须在此次通话前检查CB围栏。
我目前的理解是当vkAcquireImageKHR
返回特定图像索引时,它意味着返回的图像必须通过渲染完成。
这是因为我正在将rendering_finished
信号量传递给vkQueueSubmit
以在渲染结束时发出信号,并vkQueuePresentKHR
等待它在呈现图像之前发出信号。
VkQueuePresentInfoKHR
的规范说:
pWaitSemaphores
,如果不是VK_NULL_HANDLE,则是VkSemaphore
个带waitSemaphoreCount
个条目的对象数组,并指定在发出当前请求之前要等待的信号量
含义:我永远不会出现任何没有渲染渲染的图像,因此一旦图像出现,相关的CB就不能再使用了。
第二个信号量presentation_finished
由vkAqcuireImageKHR
发出信号并传递给相同的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之前等待它时插入栅栏显然可以解决问题,但是 - 正如所解释的那样 - 似乎是多余的。
答案 0 :(得分:19)
vkAcquireNextImageKHR
返回仍然是正在进行的异步操作的目标和/或源的映像。这意味着您无法保证在重用时命令缓冲区可用。只要这些命令配置为在presentation_finished
信号量上等待,将正确地排队其他不同的命令缓冲区以写入所获取的图像。但要安全地重用该命令缓冲区,您必须等待传递给vkQueueSubmit
的栅栏。
使用KHR扩展程序查看Vulkan规范中的section 29.6. WSI Swapchain:
的这些说明应用程序可以使用vkAcquireNextImageKHR获取可呈现图像的使用。获取可呈现的图像并在修改之前,应用程序必须使用同步原语来确保表示引擎已完成从图像中读取。应用程序可以将图像的布局,队列渲染命令转换为最后,应用程序使用vkQueuePresentKHR显示图像,该图像释放图像的采集。
成功时,vkAcquireNextImageKHR获取应用程序可以使用的可呈现图像,并将pImageIndex设置为该图像的索引。演示引擎在获取图像时可能尚未完成读取,因此应用程序必须使用信号量和/或栅栏以确保图像布局和内容不会被修改直到演示引擎读取已完成。
[...]
如上所述,呈现引擎可以与应用程序和/或逻辑设备异步。 vkAcquireNextImageKHR可以在识别出将要获取的图像后立即返回,并且可以保证信号量和围栏将由演示引擎发出信号;并且可能不会很快成功返回。应用程序使用超时来指定vkAcquireNextImageKHR等待获取图像的时间。
这表明vkAcquireNextImageKHR
不需要阻止表示操作,并且传统上不需要阻止表示操作本身等待的图形命令。