微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

(Vulkan) 当 VK_PRESENT_MODE_FIFO_KHR 选择当前模式时,vkAcquireNextImageKHR 需要很长时间

如何解决(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_FIFOPRESENT_MODE_IMMEDIATE。因此,FIFO 导致您的代码将自身同步到显示引擎而 IMMEDIATE 不会,这一事实是完全正常的。这实际上是您要求的。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。