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.
This commit is contained in:
Ricardo Garcia 2021-03-21 00:26:25 +01:00
parent 11bcb785d0
commit e362e0280e
4 changed files with 29 additions and 18 deletions

View File

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

View File

@ -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)
{

View File

@ -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,20 +1410,9 @@ 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();
}
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;
}
}
/*

View File

@ -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