SDL Vulkan window crashes on resize (before event handling).

So I was following this tutorial to creating a SDL window with Vulkan. However when enabling window resize: SDL_SetWindowResizable(mWindow, SDL_TRUE); however it crashes before getting back to the event handling loop to address adjusting the swap chain. What am I missing?

Platform:
Linux Mint 19 Cinnamon
4.18.7-041807-generic
Intel© Core™ i7-8086K CPU @ 4.00GHz × 6
GeForce GTX 1070 Ti

Crash msg:
Detected Vulkan error: -1000001004
444
Aborted (core dumped)

Also just double checked to see if ImGUI had anything to do with it; commented out all the ImGUI code and the issue is still there.

Maybe this helps track it down:

// Provided by VK_KHR_swapchain
    VK_ERROR_OUT_OF_DATE_KHR = -1000001004,
`VK_ERROR_OUT_OF_DATE_KHR`: The swap chain has become incompatible with the surface and can no longer be used for rendering. Usually happens after a window resize.

I don’t know enough about SDL’s vulkan backend to know if this is a genuine bug, but it could be that it’s not handling this soft-error condition correctly.

Thanks for pointing out where that error code comes from. Here’s what I’m seeing…
code:

            else if(e.type == SDL_WINDOWEVENT)
            {
                std::cout << "window event..." << std::endl;
                switch (e.window.event)
                {
                case SDL_WINDOWEVENT_SIZE_CHANGED:
                case SDL_WINDOWEVENT_RESIZED:
                    std::cout << "refreshing..." << std::endl;
                    mMainDeletionQueue.refresh("swap_chain");
                    std::cout << "done..." << std::endl;
                    break;
                }
            }

Std out:

window event...
window event...
window event...
window event...
window event...
window event...
window event...
window event...
window event...
Detected Vulkan error: -1000001004
444
Aborted (core dumped)

Just as a side note, the “window event…” are likely window focus event prior to the resize.

Even handling at SDL_AddEventWatch(), it crashes before ever reaching the call back.

I haven’t looked it up, but it’s possible that the callbacks from SDL_AddEventWatch() are only called once SDL_PumpEvents() runs (because that’s when SDL_Events are added to the internal queue).

No idea if your problem is solvable (or if resizable SDL windows with Vulkan just don’t work); but someone should know? You can’t be the first running into this problem…
Maybe @icculus (this problem also seems relevant to the new 3D API that wraps Vulkan)?

VK_ERROR_OUT_OF_DATE_KHR is a perfectly normal thing to happen, and is expected behavior when the window resizes. When it does, you should recreate your VkSwapchainKHR. It doesn’t matter what SDL events are sent, it only matters when you get this error, and that you handle it properly.

If you are running a normal game loop style thing that reads SDL events first, then draws, then you will definitely know the current size of the resized window and be able to act upon it appropriately when you get an VK_ERROR_OUT_OF_DATE_KHR.

I do not know where this is crashing (or even which code in the tutorial you are using), so I can’t say why it crashes, but I would definitely get the callstack before going any further, because that’ll tell you more than we can from where we are sitting.

Yeah, you need to recreate the swapchain if the window is resized.

Set a flag when a resize event is detected, then before any rendering check the flag and recreate the swapchain. As @icculus pointed out, you should also set your “recreate swapchain” flag whenever VK_ERROR_OUT_OF_DATE_KHR occurs. Which in this case coincides with the window being resized, but may happen at other times.

Is there a reason you’re using SDL_SetWindowResizable() instead of just passing SDL_WINDOW_RESIZABLE as one of the flags when creating the window? It may very well be causing the swapchain to be invalidated when you do this, even if you don’t actually resize the window.

1 Like

The X11 target calls XResizeWindow() during your SDL_SetWindowResizable() call, for various reasons, which at least makes it possible it’ll invalidate your swapchain.

But again, this shouldn’t crash the program.

It crashes at resize. If I don’t reize, it continues with the render loop just fine. The issue is I was try to rebuild the swap chain at the point of the resize event, but it crashes before either event handler is reached.

@icculus From what I understand, you’re saying I shouldn’t rely on the event handler, but check for size difference at the point of pushing the next frame to the swap chain? As for the code, here’s the github source of that tutorial: vk_engine.cpp . The swap chain code is at the bottom of ::draw().

But where does it crash specifically?

I’m saying you should rebuild the swap chain when you get an out-of-date error. Don’t do it in the resize event handling code.

I assume this is where you’re getting Detected Vulkan error: -1000001004

VK_CHECK(vkAcquireNextImageKHR(_device, _swapchain, 1000000000, get_current_frame()._presentSemaphore, nullptr, &swapchainImageIndex));

When that happens, rebuild the swap chain and then acquire the next image again, and carry on drawing.

180: VK_CHECK(vkQueuePresentKHR(_graphicsQueue, &presentInfo));

How do I do that? Is it just a try catch block? Is it some kind of C based error handler?

It’s not unexpected that the program would explode if you present with an out of date swap chain.

Instead of using VK_CHECK, which just logs the error value, you should check for the error value and rebuild the swapchain.

VkResult result = vkAcquireNextImageKHR(_device, _swapchain, 1000000000, get_current_frame()._presentSemaphore, nullptr, &swapchainImageIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
   rebuild_swap_chain();
}

Rebuilding the swap chain is well-documented, and more than I could type here. It’s vulkan! It’s verbose!! :slight_smile:

@icculus Sorry if I’m beating a dead horse here, but something doesn’t add up with what I’m seeing. VK_CHECK() never printed out any messages before crashing. I just rebuilt with it deliberately set to hang when that case is reached, but it just goes on without issue.

    VkResult result = vkAcquireNextImageKHR(mDevice, mSwapchain, 1000000000, getCurrentFrame().mPresentSemaphore, nullptr, &swapchainImageIndex);
    if (result != VK_SUCCESS)
    {
       std::cout << __LINE__ << " - " <<__FILE__ << "\n" << "\n" << "\n" << "\n" << "\n" << "\n" << "\n";
       while(1) {}
    }
    else
    {
        std::cout << "everything is just fine" << std::endl;
    }

Output:

everything is just fine
451 - /home/adminz/projects/vulcanPrac/vulkanTest/src/vkEngine.cpp
453 - /home/adminz/projects/vulcanPrac/vulkanTest/src/vkEngine.cpp
455 - /home/adminz/projects/vulcanPrac/vulkanTest/src/vkEngine.cpp
everything is just fine
451 - /home/adminz/projects/vulcanPrac/vulkanTest/src/vkEngine.cpp
453 - /home/adminz/projects/vulcanPrac/vulkanTest/src/vkEngine.cpp
Detected Vulkan error: -1000001004
454
Aborted (core dumped)

Edit:
Slight disclaimer, technically there is one VK_CHECK() that outputs text but that’s 454: VK_CHECK(vkQueuePresentKHR(mGraphicsQueue, &presentInfo)) and by then we’re already off the rails.

Are you setting the window to resizable sometime during draw()?

Same behavior either way, changed it to just the flag. In either case I am not getting VK_ERROR_OUT_OF_DATE_KHR; vkAcquireNextImageKHR() is still returning VK_SUCCESS when the window resizes.

You shouldn’t be calling SDL_SetWindowResizable() during draw. If you are, that’s why vkAcquireNextImageKHR() isn’t returning an error: everything’s fine at that point, and then you call SDL_SetWindowResizable() which invalidates the backing surface, and the swapchain is invalid by the time you try to present the frame, at which point it blows up.

If you call SDL_SetWindowResizable() you also need to set your flag that the swapchain should be rebuilt.

Right now this is what I have SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_VULKAN|SDL_WINDOW_RESIZABLE); and I’m still stuck with the above behavior.

EDIT:
Also made sure those function calls are removed.

EDIT #2:
Just in case this is relevant; sdl version according to synaptic package manager 2.0.8

Honestly, I’m not sure then. It’s been a while since I’ve used Vulkan.

Reading back up on it, there are two things I’d forgotten about:

  1. Not all Vulkan drivers on all platforms will let you know when the swapchain needs to be recreated by returning VK_ERROR_OUT_OF_DATE_KHR, so you need to make sure to keep track of when the window is resized
  2. It’s perfectly valid for vkQueuePresentKHR() (not just vkAcquireNextImageKHR()) to return VK_ERROR_OUT_OF_DATE_KHR, and it also just means you need to recreate the swapchain

Do something like (C++ pseudocode):

// *** in event handling ***
case SDL_WINDOW_RESIZED:
    windowSize = getWindowSize();
    needSwapchainRebuilt = true;
    break;

// *** in draw function, before trying to acquire the next swapchain image ***
vkWaitForFences(blah blah blah)
// DO NOT DO vkResetFences() HERE!

if(needSwapchainRebuilt) {
    needSwapchainRebuilt = false;
    rebuildSwapchain();
}

VkResult result = vkAcquireNextImageKHR(etc etc etc);
if(result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
    rebuildSwapchain();
    // skip this frame
    return;
} else if(result != VK_SUCCESS) {
    // handle error
}

// *Now* we can call this without possibly introducing a deadlock
vkResetFences(whatever);

// draw some stuff

// *** at the bottom of draw ***
VkResult presentResult = vkQueuePresentKHR(etc etc etc);
if(presentResult == VK_ERROR_OUT_OF_DATE_KHR || presentResult == VK_SUBOPTIMAL_KHR) {
    rebuildSwapchain();
    // the frame gets thrown out instead of drawn, but that's OK
} else if(presentResult != VK_SUCCESS) {
    // handle error
}

Be aware that vkAcquireNextImageKHR() and vkQueuePresentKHR() can also return VK_SUBOPTIMAL_KHR, which isn’t an error but rather a warning that the pixel format or whatever of the swapchain has become sub-optimal and you should rebuilt it.

Finally, your program isn’t really crashing. The VK_CHECK() macro is just calling abort() if it sees any result other than VK_SUCCESS

edit: updated code sample to avoid deadlock if the swapchain needs to be recreated

I’d also check out Vulkan Tutorial’s section on handling window resizing and swapchain recreation but be advised they use GLFW instead of SDL

I kind of wonder if it’s vendor/version related, going to see what happens with my laptop…

UPDATE:
This is becoming comical; so I still don’t get VK_ERROR_OUT_OF_DATE_KHR, but now it just keeps on chugging along with no crash. Instead the rendered image keeps its original geometry while showing blank when expanding and clipping in when shrinking. So where my desktop has a GeForce GTX 1070 Ti, the laptop is using integrated graphics (FYI it’s the Framework laptop)