Ibrahim Ozdemir
Ibrahim Ozdemir

Reputation: 651

(Vulkan) vkAcquireNextImageKHR takes so long when VK_PRESENT_MODE_FIFO_KHR choosen for present mode

i follow the tutorial on https://vulkan-tutorial.com/ for trying to draw a simple triangle with Vulkan, but i get about 70 fps. (With a similar scene like drawing triangle with directx11 i am getting 10000 fps, and opengl:9000fps)

i've done some profiling and i find out that vkAcquireNextImageKHR takes so long.

the reason propably is that my graphics card doesnt support VK_PRESENT_MODE_MAILBOX_KHR, and according to tutorial i am choosing VK_PRESENT_MODE_FIFO_KHR

( my graphics card supports only 2 modes for PresentMode: VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR )

yes only thing i can think of this tutorial designed for VK_PRESENT_MODE_MAILBOX_KHR but i am using VK_PRESENT_MODE_FIFO_KHR mode.

also if i switch to VK_PRESENT_MODE_IMMEDIATE_KHR mode, i get 4000 fps (still direct3D11 and opengl faster than vulkan)

i copy-paste almost everything from vulkan-tutorial.com, and the code is: https://vulkan-tutorial.com/code/16_swap_chain_recreation.cpp

only different part i am doing is, in the tutorial, he uses glfw library for window creation and i create my own.. these are the differen parts (i didnt copy-paste the rest of the code since everything is same with the link above, the problem vkAcquireNextImageKHR call is in the drawFrame method, please check it from the link above)

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;
}

there is another person also having this issue, but couldnt get any answer on that page https://community.khronos.org/t/tearing-with-present-mode-fifo-enabled-vulkan-tutorial/106298

EDIT: i thought would help if i share values below after 64bit release test:

64bit release mode:

Vulkan 74fps (with VK_PRESENT_MODE_FIFO_KHR) Vulkan 9930fps (with VK_PRESENT_MODE_IMMEDIATE_KHR) Direct3D11 13100fps OpenGL 9600fps

Upvotes: 1

Views: 1220

Answers (1)

Nicol Bolas
Nicol Bolas

Reputation: 473447

Everything that you have described is essentially what is supposed to happen.

If you outrun the display engine (ie: render stuff faster than it can be displayed), there are two options. You can either slow down your rendering or you can force the display engine to show an image in the middle of showing a different one (typically causing tearing).

In Vulkan, these two options are spelled PRESENT_MODE_FIFO and PRESENT_MODE_IMMEDIATE. So the fact that FIFO causes your code to synchronize itself to the display engine, and IMMEDIATE does not, is entirely normal. This is in fact what you asked for.

Upvotes: 1

Related Questions