mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2024-11-10 07:12:07 +00:00
Merge pull request #676 from rg3/vk_restart_fixes
Avoid restarting the whole video on VK_ERROR_OUT_OF_DATE_KHR
This commit is contained in:
commit
51caf5b85e
3 changed files with 77 additions and 40 deletions
|
@ -260,6 +260,8 @@ extern qvktexture_t vk_colorbuffer;
|
||||||
extern qvktexture_t vk_colorbufferWarp;
|
extern qvktexture_t vk_colorbufferWarp;
|
||||||
// indicator if the frame is currently being rendered
|
// indicator if the frame is currently being rendered
|
||||||
extern qboolean vk_frameStarted;
|
extern qboolean vk_frameStarted;
|
||||||
|
// Indicates if the renderer needs to be restarted.
|
||||||
|
extern qboolean vk_restartNeeded;
|
||||||
|
|
||||||
// function pointers
|
// function pointers
|
||||||
extern PFN_vkCreateDebugUtilsMessengerEXT qvkCreateDebugUtilsMessengerEXT;
|
extern PFN_vkCreateDebugUtilsMessengerEXT qvkCreateDebugUtilsMessengerEXT;
|
||||||
|
@ -271,8 +273,12 @@ extern PFN_vkCmdEndDebugUtilsLabelEXT qvkCmdEndDebugUtilsLabelEXT;
|
||||||
extern PFN_vkCmdInsertDebugUtilsLabelEXT qvkInsertDebugUtilsLabelEXT;
|
extern PFN_vkCmdInsertDebugUtilsLabelEXT qvkInsertDebugUtilsLabelEXT;
|
||||||
|
|
||||||
// The Interface Functions (tm)
|
// The Interface Functions (tm)
|
||||||
qboolean QVk_Init(SDL_Window *window);
|
void QVk_SetWindow(SDL_Window*);
|
||||||
|
qboolean QVk_Init(void);
|
||||||
|
void QVk_PostInit(void);
|
||||||
|
void QVk_WaitAndShutdownAll(void);
|
||||||
void QVk_Shutdown(void);
|
void QVk_Shutdown(void);
|
||||||
|
void QVk_Restart(void);
|
||||||
void QVk_CreateValidationLayers(void);
|
void QVk_CreateValidationLayers(void);
|
||||||
void QVk_DestroyValidationLayers(void);
|
void QVk_DestroyValidationLayers(void);
|
||||||
qboolean QVk_CreateDevice(int preferredDeviceIdx);
|
qboolean QVk_CreateDevice(int preferredDeviceIdx);
|
||||||
|
|
|
@ -31,6 +31,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
#include "header/local.h"
|
#include "header/local.h"
|
||||||
|
|
||||||
|
static SDL_Window *vk_window;
|
||||||
|
|
||||||
// Vulkan instance, surface and memory allocator
|
// Vulkan instance, surface and memory allocator
|
||||||
VkInstance vk_instance = VK_NULL_HANDLE;
|
VkInstance vk_instance = VK_NULL_HANDLE;
|
||||||
VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
|
VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
|
||||||
|
@ -121,6 +123,8 @@ static uint32_t vk_imageIndex = 0;
|
||||||
static int vk_activeStagingBuffer = 0;
|
static int vk_activeStagingBuffer = 0;
|
||||||
// started rendering frame?
|
// started rendering frame?
|
||||||
qboolean vk_frameStarted = false;
|
qboolean vk_frameStarted = false;
|
||||||
|
// the renderer needs to be restarted.
|
||||||
|
qboolean vk_restartNeeded = false;
|
||||||
|
|
||||||
// render pipelines
|
// render pipelines
|
||||||
qvkpipeline_t vk_drawTexQuadPipeline[RP_COUNT] = {
|
qvkpipeline_t vk_drawTexQuadPipeline[RP_COUNT] = {
|
||||||
|
@ -1637,13 +1641,46 @@ void QVk_Shutdown( void )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QVk_SetWindow(SDL_Window *window)
|
||||||
|
{
|
||||||
|
vk_window = window;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QVk_WaitAndShutdownAll (void)
|
||||||
|
{
|
||||||
|
if (vk_device.logical != VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
vkDeviceWaitIdle(vk_device.logical);
|
||||||
|
}
|
||||||
|
|
||||||
|
Mod_FreeAll();
|
||||||
|
Vk_ShutdownImages();
|
||||||
|
QVk_Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QVk_Restart(void)
|
||||||
|
{
|
||||||
|
QVk_WaitAndShutdownAll();
|
||||||
|
if (!QVk_Init())
|
||||||
|
ri.Sys_Error(ERR_FATAL, "Unable to restart Vulkan renderer");
|
||||||
|
QVk_PostInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QVk_PostInit(void)
|
||||||
|
{
|
||||||
|
Vk_InitImages();
|
||||||
|
Mod_Init();
|
||||||
|
RE_InitParticleTexture();
|
||||||
|
Draw_InitLocal();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** QVk_Init
|
** QVk_Init
|
||||||
**
|
**
|
||||||
** This is responsible for initializing Vulkan.
|
** This is responsible for initializing Vulkan.
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
qboolean QVk_Init(SDL_Window *window)
|
qboolean QVk_Init(void)
|
||||||
{
|
{
|
||||||
PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion");
|
PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion");
|
||||||
uint32_t instanceVersion = VK_API_VERSION_1_0;
|
uint32_t instanceVersion = VK_API_VERSION_1_0;
|
||||||
|
@ -1682,7 +1719,7 @@ qboolean QVk_Init(SDL_Window *window)
|
||||||
vk_config.triangle_fan_index_max_usage = 0;
|
vk_config.triangle_fan_index_max_usage = 0;
|
||||||
vk_config.triangle_fan_index_count = TRIANGLE_FAN_INDEX_CNT;
|
vk_config.triangle_fan_index_count = TRIANGLE_FAN_INDEX_CNT;
|
||||||
|
|
||||||
if (!SDL_Vulkan_GetInstanceExtensions(window, &extCount, NULL))
|
if (!SDL_Vulkan_GetInstanceExtensions(vk_window, &extCount, NULL))
|
||||||
{
|
{
|
||||||
R_Printf(PRINT_ALL, "%s() SDL_Vulkan_GetInstanceExtensions failed: %s",
|
R_Printf(PRINT_ALL, "%s() SDL_Vulkan_GetInstanceExtensions failed: %s",
|
||||||
__func__, SDL_GetError());
|
__func__, SDL_GetError());
|
||||||
|
@ -1694,7 +1731,7 @@ qboolean QVk_Init(SDL_Window *window)
|
||||||
extCount++;
|
extCount++;
|
||||||
|
|
||||||
wantedExtensions = malloc(extCount * sizeof(const char *));
|
wantedExtensions = malloc(extCount * sizeof(const char *));
|
||||||
if (!SDL_Vulkan_GetInstanceExtensions(window, &extCount, wantedExtensions))
|
if (!SDL_Vulkan_GetInstanceExtensions(vk_window, &extCount, wantedExtensions))
|
||||||
{
|
{
|
||||||
R_Printf(PRINT_ALL, "%s() SDL_Vulkan_GetInstanceExtensions failed: %s",
|
R_Printf(PRINT_ALL, "%s() SDL_Vulkan_GetInstanceExtensions failed: %s",
|
||||||
__func__, SDL_GetError());
|
__func__, SDL_GetError());
|
||||||
|
@ -1798,7 +1835,7 @@ qboolean QVk_Init(SDL_Window *window)
|
||||||
if (vk_validation->value)
|
if (vk_validation->value)
|
||||||
QVk_CreateValidationLayers();
|
QVk_CreateValidationLayers();
|
||||||
|
|
||||||
if (!Vkimp_CreateSurface(window))
|
if (!Vkimp_CreateSurface(vk_window))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2009,6 +2046,17 @@ VkResult QVk_BeginFrame(const VkViewport* viewport, const VkRect2D* scissor)
|
||||||
ReleaseSwapBuffers();
|
ReleaseSwapBuffers();
|
||||||
|
|
||||||
VkResult result = vkAcquireNextImageKHR(vk_device.logical, vk_swapchain.sc, UINT32_MAX, vk_imageAvailableSemaphores[vk_activeBufferIdx], VK_NULL_HANDLE, &vk_imageIndex);
|
VkResult result = vkAcquireNextImageKHR(vk_device.logical, vk_swapchain.sc, UINT32_MAX, vk_imageAvailableSemaphores[vk_activeBufferIdx], VK_NULL_HANDLE, &vk_imageIndex);
|
||||||
|
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || result == VK_ERROR_SURFACE_LOST_KHR)
|
||||||
|
{
|
||||||
|
// 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 Vulkan.
|
||||||
|
R_Printf(PRINT_ALL, "%s(): received %s after vkAcquireNextImageKHR - restarting video!\n", __func__, QVk_GetError(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else if (result != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
Sys_Error("%s(): unexpected error after vkAcquireNextImageKHR: %s", __func__, QVk_GetError(result));
|
||||||
|
}
|
||||||
|
|
||||||
vk_activeCmdbuffer = vk_commandbuffers[vk_activeBufferIdx];
|
vk_activeCmdbuffer = vk_commandbuffers[vk_activeBufferIdx];
|
||||||
|
|
||||||
// swap dynamic buffers
|
// swap dynamic buffers
|
||||||
|
@ -2021,17 +2069,6 @@ VkResult QVk_BeginFrame(const VkViewport* viewport, const VkRect2D* scissor)
|
||||||
VK_VERIFY(buffer_invalidate(&vk_dynVertexBuffers[vk_activeDynBufferIdx].resource));
|
VK_VERIFY(buffer_invalidate(&vk_dynVertexBuffers[vk_activeDynBufferIdx].resource));
|
||||||
VK_VERIFY(buffer_invalidate(&vk_dynIndexBuffers[vk_activeDynBufferIdx].resource));
|
VK_VERIFY(buffer_invalidate(&vk_dynIndexBuffers[vk_activeDynBufferIdx].resource));
|
||||||
|
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
R_Printf(PRINT_ALL, "%s(): received %s after vkAcquireNextImageKHR - restarting video!\n", __func__, QVk_GetError(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
else if (result != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
Sys_Error("%s(): unexpected error after vkAcquireNextImageKHR: %s", __func__, QVk_GetError(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
VK_VERIFY(vkWaitForFences(vk_device.logical, 1, &vk_fences[vk_activeBufferIdx], VK_TRUE, UINT32_MAX));
|
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]));
|
VK_VERIFY(vkResetFences(vk_device.logical, 1, &vk_fences[vk_activeBufferIdx]));
|
||||||
|
|
||||||
|
@ -2109,8 +2146,8 @@ VkResult QVk_EndFrame(qboolean force)
|
||||||
// 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
|
// 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 (renderResult == VK_ERROR_OUT_OF_DATE_KHR || renderResult == VK_SUBOPTIMAL_KHR || renderResult == VK_ERROR_SURFACE_LOST_KHR)
|
if (renderResult == VK_ERROR_OUT_OF_DATE_KHR || renderResult == VK_SUBOPTIMAL_KHR || renderResult == VK_ERROR_SURFACE_LOST_KHR)
|
||||||
{
|
{
|
||||||
R_Printf(PRINT_ALL, "%s(): received %s after vkQueuePresentKHR - restarting video!\n", __func__, QVk_GetError(renderResult));
|
R_Printf(PRINT_ALL, "%s(): received %s after vkQueuePresentKHR - will restart video!\n", __func__, QVk_GetError(renderResult));
|
||||||
vid_fullscreen->modified = true;
|
vk_restartNeeded = true;
|
||||||
}
|
}
|
||||||
else if (renderResult != VK_SUCCESS)
|
else if (renderResult != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1328,10 +1328,7 @@ static qboolean RE_Init( void )
|
||||||
// print device information during startup
|
// print device information during startup
|
||||||
Vk_Strings_f();
|
Vk_Strings_f();
|
||||||
|
|
||||||
Vk_InitImages();
|
QVk_PostInit();
|
||||||
Mod_Init();
|
|
||||||
RE_InitParticleTexture();
|
|
||||||
Draw_InitLocal();
|
|
||||||
|
|
||||||
R_Printf(PRINT_ALL, "Successfully initialized Vulkan!\n");
|
R_Printf(PRINT_ALL, "Successfully initialized Vulkan!\n");
|
||||||
|
|
||||||
|
@ -1347,7 +1344,6 @@ static qboolean RE_Init( void )
|
||||||
*/
|
*/
|
||||||
static void RE_ShutdownContext( void )
|
static void RE_ShutdownContext( void )
|
||||||
{
|
{
|
||||||
|
|
||||||
// Shutdown Vulkan subsystem
|
// Shutdown Vulkan subsystem
|
||||||
QVk_Shutdown();
|
QVk_Shutdown();
|
||||||
}
|
}
|
||||||
|
@ -1365,14 +1361,7 @@ void RE_Shutdown (void)
|
||||||
ri.Cmd_RemoveCommand("screenshot");
|
ri.Cmd_RemoveCommand("screenshot");
|
||||||
ri.Cmd_RemoveCommand( "modellist" );
|
ri.Cmd_RemoveCommand( "modellist" );
|
||||||
|
|
||||||
if (vk_device.logical != VK_NULL_HANDLE)
|
QVk_WaitAndShutdownAll();
|
||||||
{
|
|
||||||
vkDeviceWaitIdle(vk_device.logical);
|
|
||||||
}
|
|
||||||
|
|
||||||
Mod_FreeAll();
|
|
||||||
Vk_ShutdownImages();
|
|
||||||
RE_ShutdownContext();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1388,6 +1377,7 @@ RE_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
|
// 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);
|
QVk_EndFrame(true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** change modes if necessary
|
** change modes if necessary
|
||||||
*/
|
*/
|
||||||
|
@ -1417,18 +1407,21 @@ RE_BeginFrame( float camera_separation )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkResult swapChainValid = QVk_BeginFrame(&vk_viewport, &vk_scissor);
|
if (vk_restartNeeded)
|
||||||
// if the swapchain is invalid, just recreate the video system and revert to safe windowed mode
|
|
||||||
if (swapChainValid != VK_SUCCESS)
|
|
||||||
{
|
{
|
||||||
vid_fullscreen->value = false;
|
QVk_Restart();
|
||||||
vid_fullscreen->modified = true;
|
vk_restartNeeded = false;
|
||||||
ri.Cvar_SetValue("vid_fullscreen", 0);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
for (;;)
|
||||||
{
|
{
|
||||||
QVk_BeginRenderpass(RP_WORLD);
|
VkResult swapChainValid = QVk_BeginFrame(&vk_viewport, &vk_scissor);
|
||||||
|
if (swapChainValid == VK_SUCCESS)
|
||||||
|
break;
|
||||||
|
QVk_Restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVk_BeginRenderpass(RP_WORLD);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1590,7 +1583,8 @@ RE_InitContext(void *win)
|
||||||
SDL_SetWindowTitle(window, title);
|
SDL_SetWindowTitle(window, title);
|
||||||
|
|
||||||
// window is ready, initialize Vulkan now
|
// window is ready, initialize Vulkan now
|
||||||
if (!QVk_Init(window))
|
QVk_SetWindow(window);
|
||||||
|
if (!QVk_Init())
|
||||||
{
|
{
|
||||||
R_Printf(PRINT_ALL, "%s() - could not initialize Vulkan!\n", __func__);
|
R_Printf(PRINT_ALL, "%s() - could not initialize Vulkan!\n", __func__);
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in a new issue