From c543d3cc05df1da0028fac42441d731965a69f1a Mon Sep 17 00:00:00 2001 From: Yamagi Date: Fri, 23 Apr 2021 15:00:20 +0200 Subject: [PATCH] Work around maximal extent size of 0x0 when the game is minimized. Some GPU drivers set a maximal extent size of 0x0 when the window gets minimized. One example is Intel on Windows. A swapchain with extent size of 0x0 is invalid, so we cannot reinitialize the renderer... Work around that by postponing the restart as long as the maxmimal extent size stays 0x0. This could should be done in the client (don't call into th renderer when the window is minimized), but it would need a lot of changes to the client <-> renderer interactions. So take the easy route. --- src/client/refresh/vk/vk_rmain.c | 46 ++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/client/refresh/vk/vk_rmain.c b/src/client/refresh/vk/vk_rmain.c index 0279c468..046b5273 100644 --- a/src/client/refresh/vk/vk_rmain.c +++ b/src/client/refresh/vk/vk_rmain.c @@ -1383,6 +1383,42 @@ RE_BeginFrame( float camera_separation ) return; } + /* Some GPU drivers set a maximum extent size of 0x0 when + the window is minimized. But a swapchain with an extent + size of 0x0 is invalid. This leads to the following + problem: + + 1. The window is minimized, the extent size changes and + the Vulkan state get's corrupted. QVk_EndFrame() + above or QVk_BeginFrame() below detect the Vulkan + state as corrupted, set vk_frameStated to false and + request a restart by setting vk_restartNeeded to + true. + 2. RE_EndFrame() triggers the restart. QVk_Shutdown() + is successfull, but QVk_Init() can't create a valid + swapchains and errors out. An incomplete internal + renderer state is left behind. The only way out is + to trigger a full render restart. + 3. The full renderer restart would lead to a restart + loop: Restart -> QVk_Init() fails -> restart -> ... + The only alternative is not to restart. Instead the + renderer could error out, that would print an error + message and quit the client. + + Work around this by not starting the frame or restarting + the renderer, as long as the maximum extent size is 0x0. + This is part 1 (the state corruption war detect in the + last frame), part 2 (the state corruption was detected in + the current frame) is in RE_EndFrame(). */ + if (vk_restartNeeded) + { + if (!QVk_CheckExtent()) + { + vk_frameStarted = false; + return; + } + } + // if ri.Sys_Error() had been issued mid-frame, we might end up here without properly submitting the image, so call QVk_EndFrame to be safe if (QVk_EndFrame(true) != VK_SUCCESS) vk_restartNeeded = true; @@ -1432,10 +1468,16 @@ RE_EndFrame( void ) // world has not rendered yet world_rendered = false; + /* Part two of the 'maximum extent size may be 0x0' + * work around. See the explanation in RE_BeginFrame() + * for details. */ if (vk_restartNeeded) { - QVk_Restart(); - vk_restartNeeded = false; + if (QVk_CheckExtent()) + { + QVk_Restart(); + vk_restartNeeded = false; + } } }