Skip to content

Commit

Permalink
Don't rebuild entire window if Vulkan fails (fixes #95).
Browse files Browse the repository at this point in the history
  • Loading branch information
kondrak committed May 4, 2020
1 parent a4f8c3c commit 134c82a
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 22 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ The following commands are available when using the Vulkan renderer:
| `vk_aniso` | Toggle anisotropic filtering. (default: `1`) |
| `vk_vsync` | Toggle vertical sync. (default: `0`) |
| `vk_postprocess` | Toggle additional color/gamma correction. (default: `1`) |
| `vk_restart` | Recreate entire Vulkan subsystem. |
| `vk_mip_nearfilter` | Use nearest-neighbor filtering for mipmaps. (default: `0`) |
| `vk_texturemode` | Change current texture filtering mode:<br>`VK_NEAREST` - nearest-neighbor interpolation, no mipmaps<br>`VK_LINEAR` - linear interpolation, no mipmaps<br>`VK_MIPMAP_NEAREST` - nearest-neighbor interpolation with mipmaps<br>`VK_MIPMAP_LINEAR` - linear interpolation with mipmaps (default) |
| `vk_lmaptexturemode` | Same as `vk_texturemode` but applied to lightmap textures. |
Expand Down
7 changes: 7 additions & 0 deletions linux/vid_so.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ cvar_t *vid_ref; // Name of Refresh DLL loaded
cvar_t *vid_xpos; // X coordinate of window position
cvar_t *vid_ypos; // Y coordinate of window position
cvar_t *vid_fullscreen;
cvar_t *vid_refresh;
cvar_t *vid_hudscale;
cvar_t *r_customwidth;
cvar_t *r_customheight;
Expand Down Expand Up @@ -429,6 +430,11 @@ Com_Printf("Trying mode 0\n");
cls.disable_screen = false;
}

if ( vid_refresh->modified )
{
vid_refresh->modified = false;
cl.refresh_prepped = false;
}
}

/*
Expand All @@ -442,6 +448,7 @@ void VID_Init (void)
vid_xpos = Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE);
vid_ypos = Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE);
vid_fullscreen = Cvar_Get ("vid_fullscreen", "0", CVAR_ARCHIVE);
vid_refresh = Cvar_Get ("vid_refresh", "0", CVAR_NOSET);
vid_gamma = Cvar_Get( "vid_gamma", "1", CVAR_ARCHIVE );
r_customwidth = Cvar_Get( "r_customwidth", "1024", CVAR_ARCHIVE );
r_customheight = Cvar_Get( "r_customheight", "768", CVAR_ARCHIVE );
Expand Down
7 changes: 7 additions & 0 deletions macos/vid_dsym.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ cvar_t *vid_ref; // Name of Refresh DLL loaded
cvar_t *vid_xpos; // X coordinate of window position
cvar_t *vid_ypos; // Y coordinate of window position
cvar_t *vid_fullscreen;
cvar_t *vid_refresh;
cvar_t *vid_hudscale;
cvar_t *r_customwidth;
cvar_t *r_customheight;
Expand Down Expand Up @@ -403,6 +404,11 @@ void VID_CheckChanges (void)
cls.disable_screen = false;
}

if ( vid_refresh->modified )
{
vid_refresh->modified = false;
cl.refresh_prepped = false;
}
}

/*
Expand All @@ -416,6 +422,7 @@ void VID_Init (void)
vid_xpos = Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE);
vid_ypos = Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE);
vid_fullscreen = Cvar_Get ("vid_fullscreen", "0", CVAR_ARCHIVE);
vid_refresh = Cvar_Get ("vid_refresh", "0", CVAR_NOSET);
vid_gamma = Cvar_Get( "vid_gamma", "1", CVAR_ARCHIVE );
r_customwidth = Cvar_Get( "r_customwidth", "1024", CVAR_ARCHIVE );
r_customheight = Cvar_Get( "r_customheight", "768", CVAR_ARCHIVE );
Expand Down
2 changes: 2 additions & 0 deletions ref_vk/qvk.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,8 @@ extern qvktexture_t vk_colorbuffer;
extern qvktexture_t vk_colorbufferWarp;
// indicator if the frame is currently being rendered
extern qboolean vk_frameStarted;
// indicator if the renderer needs to restart next frame
extern qboolean vk_restart;

// function pointers
extern PFN_vkCreateDebugUtilsMessengerEXT qvkCreateDebugUtilsMessengerEXT;
Expand Down
28 changes: 15 additions & 13 deletions ref_vk/vk_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ uint32_t vk_imageIndex = 0;
int vk_activeStagingBuffer = 0;
// started rendering frame?
qboolean vk_frameStarted = false;
// renderer needs to restart next frame?
qboolean vk_restart = false;

// render pipelines
qvkpipeline_t vk_drawTexQuadPipeline = QVKPIPELINE_INIT;
Expand Down Expand Up @@ -1848,6 +1850,17 @@ VkResult QVk_BeginFrame()
ReleaseSwapBuffers();

VkResult result = vkAcquireNextImageKHR(vk_device.logical, vk_swapchain.sc, UINT32_MAX, vk_imageAvailableSemaphores[vk_activeBufferIdx], VK_NULL_HANDLE, &vk_imageIndex);
// for VK_OUT_OF_DATE_KHR and VK_SUBOPTIMAL_KHR it'd be fine to just rebuild the swapchain but let's take the easy way out and restart video system
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || result == VK_ERROR_SURFACE_LOST_KHR)
{
ri.Con_Printf(PRINT_ALL, "QVk_BeginFrame(): received %s after vkAcquireNextImageKHR - restarting video!\n", QVk_GetError(result));
return result;
}
else if (result != VK_SUCCESS)
{
Sys_Error("QVk_BeginFrame(): unexpected error after vkAcquireNextImageKHR: %s", QVk_GetError(result));
}

vk_activeCmdbuffer = vk_commandbuffers[vk_activeBufferIdx];

// swap dynamic buffers
Expand All @@ -1860,17 +1873,6 @@ VkResult QVk_BeginFrame()
vmaInvalidateAllocation(vk_malloc, vk_dynVertexBuffers[vk_activeDynBufferIdx].allocation, 0, VK_WHOLE_SIZE);
vmaInvalidateAllocation(vk_malloc, vk_dynIndexBuffers[vk_activeDynBufferIdx].allocation, 0, VK_WHOLE_SIZE);

// for VK_OUT_OF_DATE_KHR and VK_SUBOPTIMAL_KHR it'd be fine to just rebuild the swapchain but let's take the easy way out and restart video system
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || result == VK_ERROR_SURFACE_LOST_KHR)
{
ri.Con_Printf(PRINT_ALL, "QVk_BeginFrame(): received %s after vkAcquireNextImageKHR - restarting video!\n", QVk_GetError(result));
return result;
}
else if (result != VK_SUCCESS)
{
Sys_Error("QVk_BeginFrame(): unexpected error after vkAcquireNextImageKHR: %s", QVk_GetError(result));
}

VK_VERIFY(vkWaitForFences(vk_device.logical, 1, &vk_fences[vk_activeBufferIdx], VK_TRUE, UINT32_MAX));
VK_VERIFY(vkResetFences(vk_device.logical, 1, &vk_fences[vk_activeBufferIdx]));

Expand All @@ -1895,7 +1897,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)
{
Expand Down Expand Up @@ -1944,7 +1947,6 @@ VkResult QVk_EndFrame(qboolean force)
if (renderResult == VK_ERROR_OUT_OF_DATE_KHR || renderResult == VK_SUBOPTIMAL_KHR || renderResult == VK_ERROR_SURFACE_LOST_KHR)
{
ri.Con_Printf(PRINT_ALL, "QVk_EndFrame(): received %s after vkQueuePresentKHR - restarting video!\n", QVk_GetError(renderResult));
vid_ref->modified = true;
}
else if (renderResult != VK_SUCCESS)
{
Expand Down
3 changes: 3 additions & 0 deletions ref_vk/vk_draw.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,9 @@ void Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data
int row;
float t;

if (!vk_frameStarted)
return;

if (rows <= 256)
{
hscale = 1;
Expand Down
2 changes: 1 addition & 1 deletion ref_vk/vk_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "qvk.h"

#define REF_VERSION "Vulkan (vkQuake2 v"VKQUAKE2_VERSION")"
#define VKQUAKE2_VERSION "1.4.4"
#define VKQUAKE2_VERSION "1.4.5"

// verify if VkResult is VK_SUCCESS
#ifdef _DEBUG
Expand Down
69 changes: 61 additions & 8 deletions ref_vk/vk_rmain.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ int c_brush_polys, c_alias_polys;
float v_blend[4]; // final blending color

void Vk_Strings_f(void);
void Vk_PollRestart_f(void);
void Vk_Mem_f(void);

//
Expand Down Expand Up @@ -124,6 +125,7 @@ cvar_t *vk_device_idx;
cvar_t *vid_fullscreen;
cvar_t *vid_gamma;
cvar_t *vid_ref;
cvar_t *vid_refresh;
cvar_t *viewsize;

/*
Expand Down Expand Up @@ -1075,9 +1077,11 @@ void R_Register( void )
vid_fullscreen = ri.Cvar_Get("vid_fullscreen", "0", CVAR_ARCHIVE);
vid_gamma = ri.Cvar_Get("vid_gamma", "1.0", CVAR_ARCHIVE);
vid_ref = ri.Cvar_Get("vid_ref", "soft", CVAR_ARCHIVE);
vid_refresh = ri.Cvar_Get("vid_refresh", "0", CVAR_NOSET);
viewsize = ri.Cvar_Get("viewsize", "100", CVAR_ARCHIVE);

ri.Cmd_AddCommand("vk_strings", Vk_Strings_f);
ri.Cmd_AddCommand("vk_restart", Vk_PollRestart_f);
ri.Cmd_AddCommand("vk_mem", Vk_Mem_f);
ri.Cmd_AddCommand("imagelist", Vk_ImageList_f);
ri.Cmd_AddCommand("screenshot", Vk_ScreenShot_f);
Expand Down Expand Up @@ -1196,6 +1200,7 @@ void R_Shutdown (void)
{
ri.Cmd_RemoveCommand("vk_strings");
ri.Cmd_RemoveCommand("vk_mem");
ri.Cmd_RemoveCommand("vk_restart");
ri.Cmd_RemoveCommand("imagelist");
ri.Cmd_RemoveCommand("screenshot");

Expand All @@ -1220,13 +1225,16 @@ R_BeginFrame
void R_BeginFrame( float camera_separation )
{
// 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_PollRestart_f();
return;
}
/*
** change modes if necessary
*/
if (vk_mode->modified || vid_fullscreen->modified || vk_msaa->modified || vk_clear->modified || vk_picmip->modified ||
vk_validation->modified || vk_texturemode->modified || vk_lmaptexturemode->modified || vk_aniso->modified || vid_gamma->modified ||
vk_mip_nearfilter->modified || vk_sampleshading->modified || vk_vsync->modified || vk_device_idx->modified)
if (vk_mode->modified || vid_fullscreen->modified || vk_texturemode->modified ||
vk_lmaptexturemode->modified || vk_aniso->modified || vk_device_idx->modified)
{
if (vk_texturemode->modified || vk_lmaptexturemode->modified || vk_aniso->modified)
{
Expand Down Expand Up @@ -1267,24 +1275,69 @@ void R_BeginFrame( float camera_separation )
// if the swapchain is invalid, just recreate the video system and revert to safe windowed mode
if (swapChainValid != VK_SUCCESS)
{
vid_ref->modified = true;
vid_fullscreen->value = false;
ri.Cvar_SetValue("vid_fullscreen", 0);
Vk_PollRestart_f();
}
else
{
QVk_BeginRenderpass(RP_WORLD);
}
}

static qboolean R_ShouldRestart()
{
return vk_restart || vk_validation->modified || vk_msaa->modified || vk_clear->modified ||
vk_picmip->modified || vid_gamma->modified || vk_mip_nearfilter->modified ||
vk_sampleshading->modified || vk_vsync->modified;
}

/*
@@@@@@@@@@@@@@@@@@@@@
R_EndFrame
@@@@@@@@@@@@@@@@@@@@@
*/
void R_EndFrame( void )
{
QVk_EndFrame(false);
if (QVk_EndFrame(false) != VK_SUCCESS)
Vk_PollRestart_f();

// restart Vulkan renderer without rebuilding the entire window
if (R_ShouldRestart())
{
vk_restart = false;
vk_validation->modified = false;
vk_msaa->modified = false;
vk_clear->modified = false;
vk_picmip->modified = false;
vid_gamma->modified = false;
vk_mip_nearfilter->modified = false;
vk_sampleshading->modified = false;
vk_vsync->modified = false;

// shutdown
vkDeviceWaitIdle(vk_device.logical);
Mod_FreeAll();
Vk_ShutdownImages();
QVk_Shutdown();
numvktextures = 0;

// initialize
if (!QVk_Init())
{
ri.Sys_Error(ERR_FATAL, "R_EndFrame(): could not re-initialize Vulkan!");
}

ri.Con_Printf(PRINT_ALL, "Successfully restarted Vulkan!\n");

Vk_Strings_f();

Vk_InitImages();
Mod_Init();
R_InitParticleTexture();
Draw_InitLocal();

extern cvar_t *vid_refresh;
vid_refresh->modified = true;
}
}

/*
Expand Down
9 changes: 9 additions & 0 deletions ref_vk/vk_rmisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,15 @@ void Vk_Strings_f(void)
ri.Con_Printf(PRINT_ALL, "\n");
}

/*
** Vk_PollRestart_f
*/

void Vk_PollRestart_f(void)
{
vk_restart = true;
}

/*
** Vk_Mem_f
*/
Expand Down
8 changes: 8 additions & 0 deletions win32/vid_dll.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ cvar_t *vid_ref; // Name of Refresh DLL loaded
cvar_t *vid_xpos; // X coordinate of window position
cvar_t *vid_ypos; // Y coordinate of window position
cvar_t *vid_fullscreen;
cvar_t *vid_refresh;
cvar_t *vid_hudscale;
cvar_t *r_customwidth;
cvar_t *r_customheight;
Expand Down Expand Up @@ -735,6 +736,12 @@ void VID_CheckChanges (void)
vid_xpos->modified = false;
vid_ypos->modified = false;
}

if ( vid_refresh->modified )
{
vid_refresh->modified = false;
cl.refresh_prepped = false;
}
}

/*
Expand All @@ -749,6 +756,7 @@ void VID_Init (void)
vid_xpos = Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE);
vid_ypos = Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE);
vid_fullscreen = Cvar_Get ("vid_fullscreen", "0", CVAR_ARCHIVE);
vid_refresh = Cvar_Get ("vid_refresh", "0", CVAR_NOSET);
vid_gamma = Cvar_Get( "vid_gamma", "1", CVAR_ARCHIVE );
win_noalttab = Cvar_Get( "win_noalttab", "0", CVAR_ARCHIVE );
r_customwidth = Cvar_Get( "r_customwidth", "1024", CVAR_ARCHIVE );
Expand Down

0 comments on commit 134c82a

Please sign in to comment.