如何解决(Vulkan) 当 VK_PRESENT_MODE_FIFO_KHR 选择当前模式时,vkAcquireNextImageKHR 需要很长时间
我按照 https://vulkan-tutorial.com/ 上的教程尝试使用 Vulkan 绘制一个简单的三角形,但我得到了大约 70 fps。 (类似的场景,比如用 directx11 绘制三角形,我得到 10000 fps,和 opengl:9000fps)
我做了一些分析,我发现 vkAcquireNextimageKHR 需要很长时间。
原因可能是我的显卡不支持 VK_PRESENT_MODE_MAILBox_KHR,根据教程我选择了 VK_PRESENT_MODE_FIFO_KHR
( 我的显卡仅支持 2 种 PresentMode 模式: VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR )
是的,我只能想到为 VK_PRESENT_MODE_MAILBox_KHR 设计的本教程,但我使用的是 VK_PRESENT_MODE_FIFO_KHR 模式。
此外,如果我切换到 VK_PRESENT_MODE_IMMEDIATE_KHR 模式,我将获得 4000 fps(仍然比 vulkan 更快的 direct3D11 和 opengl)
我从 vulkan-tutorial.com 复制粘贴了几乎所有内容,代码是: https://vulkan-tutorial.com/code/16_swap_chain_recreation.cpp
我所做的唯一不同的部分是,在教程中,他使用 glfw 库来创建窗口,而我创建了自己的..这些是不同的部分(我没有复制粘贴其余代码,因为一切都与上面的链接,问题 vkAcquireNextimageKHR 调用是在 drawFrame 方法中,请从上面的链接中检查)
void Graphics_Vulkan::recreateSwapChain()
{
uint w = 0,h = 0;
while (!MainWindow->GetClientSize(w,h) || w == 0 || h == 0)
ProcessMessageForAllWindows();
vkDeviceWaitIdle(device);
cleanupSwapChain();
createSwapChain();
createImageViews();
createRenderPass();
createGraphicsPipeline();
createFramebuffers();
createCommandBuffers();
imagesInFlight.resize(swapChainImages.size(),VK_NULL_HANDLE);
}
void Graphics_Vulkan::createSurface()
{
VkWin32SurfaceCreateInfoKHR createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
createInfo.hwnd = MainWindow->hwnd;
createInfo.hinstance = hInstance;
if (vkCreateWin32SurfaceKHR(instance,&createInfo,nullptr,&surface) != VK_SUCCESS)
throw std::runtime_error("Failed to create window surface!");
}
VkExtent2D Graphics_Vulkan::chooseSwapExtent(const VkSurfaceCapabilitiesKHR & capabilities)
{
if (capabilities.currentExtent.width != UINT32_MAX) {
return capabilities.currentExtent;
}
else {
uint width = 0,height = 0;
MainWindow->GetClientSize(width,height);
VkExtent2D actualExtent = {
static_cast<uint32_t>(width),static_cast<uint32_t>(height)
};
actualExtent.width = max(capabilities.minImageExtent.width,min(capabilities.maxImageExtent.width,actualExtent.width));
actualExtent.height = max(capabilities.minImageExtent.height,min(capabilities.maxImageExtent.height,actualExtent.height));
return actualExtent;
}
}
std::vector<const char*> Graphics_Vulkan::getrequiredExtensions()
{
std::vector<const char*> enabledExtensions = { VK_KHR_SURFACE_EXTENSION_NAME };
#if defined(OSWINDOWS)
enabledExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#elif defined(__ANDROID__)
enabledExtensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
#elif defined(__linux__)
enabledExtensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
#endif
enabledExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
/*on my pc,there were 2 more extensions. i wasnt sure to add those to in the list:
VK_KHR_get_physical_device_properties2
VK_EXT_debug_report
*/
return enabledExtensions;
}
还有一个人也有这个问题,但在那个页面上找不到任何答案 https://community.khronos.org/t/tearing-with-present-mode-fifo-enabled-vulkan-tutorial/106298
编辑: 我认为如果我在 64 位发布测试后共享以下值会有所帮助:
64 位发布模式:
Vulkan 74fps(使用 VK_PRESENT_MODE_FIFO_KHR) Vulkan 9930fps(使用 VK_PRESENT_MODE_IMMEDIATE_KHR) Direct3D11 13100fps OpenGL 9600fps
解决方法
您所描述的一切本质上都是应该发生的事情。
如果您跑得比显示引擎快(即:渲染内容比显示速度快),有两种选择。您可以减慢渲染速度,也可以强制显示引擎在显示不同图像的中间显示图像(通常会导致撕裂)。
在 Vulkan 中,这两个选项拼写为 PRESENT_MODE_FIFO
和 PRESENT_MODE_IMMEDIATE
。因此,FIFO 导致您的代码将自身同步到显示引擎而 IMMEDIATE 不会,这一事实是完全正常的。这实际上是您要求的。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。