Vulkan:vkQueuePresentKHR 做了啥?
Posted
技术标签:
【中文标题】Vulkan:vkQueuePresentKHR 做了啥?【英文标题】:Vulkan: What did vkQueuePresentKHR do?Vulkan:vkQueuePresentKHR 做了什么? 【发布时间】:2019-10-30 16:37:40 【问题描述】:void drawFrame()
vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, std::numeric_limits<uint64_t>::max());
...
VkSemaphore signalSemaphores[] = renderFinishedSemaphores[currentFrame];
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores;
vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame])
...
VkSwapchainKHR swapChains[] = swapChain;
VkPresentInfoKHR presentInfo = ;
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = signalSemaphores;
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = swapChains;
presentInfo.pImageIndices = &imageIndex;
vkQueuePresentKHR(presentQueue, &presentInfo); // <- vkQueuePresentKHR
...
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
第一帧vkQueueSubmit提交后调用vkQueuePresentKHR进行presont,第二帧调用vkWaitForFences等待上一帧的vkQueueSubmit结束再调用vkQueueSubmit提交,但此时第一帧的vkQueuePresentKHR 可能在渲染中,它占用了第一帧的Framebuffer。那么第二帧的vkQueueSubmit会和第一帧的vkQueuePresentKHR冲突吗?
我认为可能有两种情况:
1:第一帧和第二帧不占用同一个Framebuffer,当第一帧vkQueueSubmit结束时,数据已经复制到了新的内存中。 vkQueuePresentKHR 将数据呈现在新内存中,因此将第二帧渲染到 Framebuffer 不会影响第一帧的内容。
2:第一帧和第二帧占用同一个Framebuffer,当第一帧的vkQueuePresentKHR和第二帧的vkQueueSubmit同时使用Framebuffer时,会出现画面撕裂(我猜的)。
我认为第二种可能性会更高。
我想将结果渲染到我自己的记忆中,而不是在屏幕上显示。我想弄清楚 vkQueuePresentKHR 是做什么的。
这里是渲染到自己内存的例子:https://github.com/SaschaWillems/Vulkan/blob/master/examples/renderheadless/renderheadless.cpp
在本例中,渲染的 Framebuffer 数据被传输到新的内存中。
在我设计的程序中,有一个辅助线程负责等待Fence完成。一旦传输完成,就会使用此内存。类似于下面的例子:
主线程:
void drawFrame()
vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, std::numeric_limits<uint64_t>::max());
...
VkSemaphore signalSemaphores[] = renderFinishedSemaphores[currentFrame];
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores;
// VkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame]) cannot be executed before the execution of
// vkQueueSubmit(graphicsQueue, 1, &transferSubmitInfo, transferCompleteFences[currentFrame]) in the previous frame. Otherwise,
// they will occupy the same FrameBuffer. I think it is not possible.
transferCompleteMutexs[currentFrame].lock(); // <- lock transferCompleteMutexs
vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame])
...
VkSubmitInfo transferSubmitInfo = ;
transferSubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
transferSubmitInfo.commandBufferCount = 1;
transferSubmitInfo.pCommandBuffers = &commandBuffer;
transferSubmitInfo.waitSemaphoreCount = 1;
transferSubmitInfo.pWaitSemaphores = signalSemaphores;
vkQueueSubmit(graphicsQueue, 1, &transferSubmitInfo, transferCompleteFences[currentFrame]) // Signal <- transferCompleteFences
...
次要线程:
while(true)
// Waiting for transfer to complete
vkWaitForFences(logicalDevice_->vkLogicalDevice(),
1,
&transferCompleteFences[currentFrame], // Wait <- transferCompleteFences
VK_TRUE,
std::numeric_limits<uint64_t>::max());
// using transfer completed data
...
// Secondary thread knows that the current frame is transmitted. The next Primary thread can be submitted.
transferCompleteMutexs[currentFrame].unlock(); // <- unlock transferCompleteMutexs
上面的代码使用transferCompleteMutexs来保护FrameBuffer,我认为这是必要的。但显然 vkQueuePresentKHR 并没有这样做。我是否有更好的方法来模拟 vkQueuePresentKHR 以将数据呈现到我自己的内存中,或者我现在这样做是否正确?
【问题讨论】:
"那么第二帧的 vkQueueSubmit 会和第一帧的 vkQueuePresentKHR 冲突吗?" 这完全取决于你提交的内容。既然你不说,这个问题就没法回答了。 【参考方案1】:第二帧的vkQueueSubmit
不能与第一帧的vkQueuePresent
“冲突”。
在第二帧中,您还可以执行vkAcquireNextImage
,它会给出一个信号量。如果信号量已发出信号,则表示引擎不再使用该图像(无论它是否与前一帧的图像相同)。
vkQueueSubmit
可能与之前的vkQueueSubmit
以及使用的各种资源发生冲突。
vkQueuePresent
所做的是在返回之前提交您的信号量等待执行。在信号量发出信号之前,它不会访问图像。它将从 Vulkan 队列中异步呈现 Image 中的图片。其他任何内容都未指定。图像可以被复制、即时复制或直接使用,或任何其他符合上述 API 合同的内容。
【讨论】:
谢谢,我明白了,那么vulkan可以产生OpenGL垂直同步画面撕裂吗? VkPresentModeKHR以上是关于Vulkan:vkQueuePresentKHR 做了啥?的主要内容,如果未能解决你的问题,请参考以下文章
Vulkan Tutorial 02 编写Vulkan应用程序框架原型
Vulkan Tutorial 02 编写Vulkan应用程序框架原型
如果设备不支持vulkan,就用swiftshader,否则就加载系统的vulkan的正确姿势(让程序能够智能的在vulkan-1.dll和libvk_swiftshader.dll之间切换)