From e362e0280e61a1b383d677b76ab6fa700dd3020e Mon Sep 17 00:00:00 2001 From: Ricardo Garcia Date: Sun, 21 Mar 2021 00:26:25 +0100 Subject: [PATCH] Restart Vulkan renderer at EndFrame instead of BeginFrame This brings yquake2 closer to vkQuake2 regarding renderer restarts when the swapchain is out of date, among other situations that trigger a Vulkan renderer restart. Basically, the current behavior has the problem that when the renderer is restarted at the beginning of the frame, the models are lost and we end up with "ERROR: Mod_PointInLeaf: bad model" when attempting to render anything after that restart. To solve this, we move the restart logic to EndFrame and add a twist to it: we use a vid_refresh variable to signal the server that the client needs re-registration before starting the next frame cleanly, which will trigger the registration logic to prepare the models again. --- src/client/refresh/vk/header/local.h | 1 + src/client/refresh/vk/vk_common.c | 4 +++- src/client/refresh/vk/vk_rmain.c | 34 ++++++++++++++-------------- src/client/vid/vid.c | 8 +++++++ 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/client/refresh/vk/header/local.h b/src/client/refresh/vk/header/local.h index b1ffc7d9..b2760ddc 100644 --- a/src/client/refresh/vk/header/local.h +++ b/src/client/refresh/vk/header/local.h @@ -152,6 +152,7 @@ extern cvar_t *vk_pixel_size; extern cvar_t *r_fixsurfsky; extern cvar_t *vid_fullscreen; +extern cvar_t *vid_refresh; extern cvar_t *vid_gamma; extern int c_visible_lightmaps; diff --git a/src/client/refresh/vk/vk_common.c b/src/client/refresh/vk/vk_common.c index 08ffb225..81535598 100644 --- a/src/client/refresh/vk/vk_common.c +++ b/src/client/refresh/vk/vk_common.c @@ -1664,6 +1664,7 @@ void QVk_Restart(void) if (!QVk_Init()) ri.Sys_Error(ERR_FATAL, "Unable to restart Vulkan renderer"); QVk_PostInit(); + vid_refresh->modified = true; } void QVk_PostInit(void) @@ -2097,7 +2098,8 @@ VkResult QVk_EndFrame(qboolean force) { // continue only if QVk_BeginFrame() had been previously issued if (!vk_frameStarted) - return VK_NOT_READY; + return VK_SUCCESS; + // this may happen if Sys_Error is issued mid-frame, so we need to properly advance the draw pipeline if (force) { diff --git a/src/client/refresh/vk/vk_rmain.c b/src/client/refresh/vk/vk_rmain.c index 80abeb80..41322e39 100644 --- a/src/client/refresh/vk/vk_rmain.c +++ b/src/client/refresh/vk/vk_rmain.c @@ -130,6 +130,7 @@ cvar_t *vk_nolerp_list; cvar_t *r_fixsurfsky; cvar_t *vid_fullscreen; +cvar_t *vid_refresh; cvar_t *vid_gamma; static cvar_t *viewsize; @@ -1194,6 +1195,7 @@ R_Register( void ) ri.Cvar_Set("r_msaa_samples", "0"); vid_fullscreen = ri.Cvar_Get("vid_fullscreen", "0", CVAR_ARCHIVE); + vid_refresh = ri.Cvar_Get("vid_refresh", "0", CVAR_NOSET); vid_gamma = ri.Cvar_Get("vid_gamma", "1.0", CVAR_ARCHIVE); viewsize = ri.Cvar_Get("viewsize", "100", CVAR_ARCHIVE); @@ -1376,7 +1378,8 @@ RE_BeginFrame( float camera_separation ) world_rendered = false; // 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 - QVk_EndFrame(true); + if (QVk_EndFrame(true) != VK_SUCCESS) + vk_restartNeeded = true; /* ** change modes if necessary @@ -1407,21 +1410,10 @@ RE_BeginFrame( float camera_separation ) } } - if (vk_restartNeeded) - { - QVk_Restart(); - vk_restartNeeded = false; - } - - for (;;) - { - VkResult swapChainValid = QVk_BeginFrame(&vk_viewport, &vk_scissor); - if (swapChainValid == VK_SUCCESS) - break; - QVk_Restart(); - } - - QVk_BeginRenderpass(RP_WORLD); + if (QVk_BeginFrame(&vk_viewport, &vk_scissor) != VK_SUCCESS) + vk_restartNeeded = true; + else + QVk_BeginRenderpass(RP_WORLD); } /* @@ -1432,9 +1424,17 @@ RE_EndFrame static void RE_EndFrame( void ) { - QVk_EndFrame(false); + if (QVk_EndFrame(false) != VK_SUCCESS) + vk_restartNeeded = true; + // world has not rendered yet world_rendered = false; + + if (vk_restartNeeded) + { + QVk_Restart(); + vk_restartNeeded = false; + } } /* diff --git a/src/client/vid/vid.c b/src/client/vid/vid.c index 0857e573..c2c6f61f 100644 --- a/src/client/vid/vid.c +++ b/src/client/vid/vid.c @@ -286,6 +286,7 @@ VID_GetModeInfo(int *width, int *height, int mode) // Global console variables. cvar_t *vid_gamma; cvar_t *vid_fullscreen; +cvar_t *vid_refresh; cvar_t *vid_renderer; // Global video state, used throughout the client. @@ -489,6 +490,12 @@ VID_CheckChanges(void) // Unblock the client. cls.disable_screen = false; } + + if (vid_refresh->modified) + { + vid_refresh->modified = false; + cl.refresh_prepped = false; + } } /* @@ -500,6 +507,7 @@ VID_Init(void) // Console variables vid_gamma = Cvar_Get("vid_gamma", "1.0", CVAR_ARCHIVE); vid_fullscreen = Cvar_Get("vid_fullscreen", "0", CVAR_ARCHIVE); + vid_refresh = Cvar_Get("vid_refresh", "0", CVAR_NOSET); vid_renderer = Cvar_Get("vid_renderer", "gl1", CVAR_ARCHIVE); // Commands