Don't crash if re.InitContext() fails before creating context

One problem was that GL3_Shutdown() called several functions that use
that gl* function pointers - not a good idea if InitContext() failed
and the function pointers are all NULL. So check for that.
Similarly in GL3/R_ShutdownWindow() calling glClear() etc.

Another problem was that R_SetMode() would, if R_SetMode_impl() failed,
try again with a "safe" resolution (640x480 unless  we had another
working resolution before) - which is bad if we're already using that
"safe" resolution because then GLimp_InitGraphics() would check mode
and fullscreen and decide it hasn't changed and do nothing and return
true, which would make SetMode() believe everything is fine and
afterwards all hell breaks loose.
This commit is contained in:
Daniel Gibson 2017-04-02 04:04:00 +02:00
parent 3503f91234
commit bd5b8d0aea
5 changed files with 50 additions and 21 deletions

View file

@ -141,6 +141,7 @@ typedef struct
// called by GLimp_InitGraphics() *after* creating window,
// passing the SDL_Window* (void* so we don't spill SDL.h here)
// (or SDL_Surface* for SDL1.2, another reason to use void*)
// returns true (1) on success
int (EXPORT *InitContext)(void* sdl_window);

View file

@ -1343,9 +1343,15 @@ R_SetMode(void)
}
else if (err == rserr_invalid_mode)
{
R_Printf(PRINT_ALL, "ref_gl::R_SetMode() - invalid mode\n");
if(gl_mode->value == gl_state.prev_mode)
{
// trying again would result in a crash anyway, give up already
// (this would happen if your initing fails at all and your resolution already was 640x480)
return false;
}
ri.Cvar_SetValue("gl_mode", gl_state.prev_mode);
gl_mode->modified = false;
R_Printf(PRINT_ALL, "ref_gl::R_SetMode() - invalid mode\n");
}
/* try setting it back to something safe */

View file

@ -474,19 +474,24 @@ RI_ShutdownWindow(qboolean contextOnly)
current. This may help some broken
video drivers like the AMD Catalyst
to avoid artifacts in unused screen
areas. */
areas.
Only do this if we have a context, though. */
if (window)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
RI_EndFrame();
#if SDL_VERSION_ATLEAST(2, 0, 0)
if(context)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
RI_EndFrame();
SDL_GL_DeleteContext(context);
context = NULL;
}
#else // SDL 1.2
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
RI_EndFrame();
#endif
}

View file

@ -388,7 +388,7 @@ GL3_SetMode(void)
{
ri.Cvar_SetValue("vid_fullscreen", 0);
vid_fullscreen->modified = false;
R_Printf(PRINT_ALL, "ref_gl::R_SetMode() - fullscreen unavailable in this mode\n");
R_Printf(PRINT_ALL, "ref_gl3::GL3_SetMode() - fullscreen unavailable in this mode\n");
if ((err = SetMode_impl(&vid.width, &vid.height, gl_mode->value, false)) == rserr_ok)
{
@ -397,15 +397,23 @@ GL3_SetMode(void)
}
else if (err == rserr_invalid_mode)
{
R_Printf(PRINT_ALL, "ref_gl3::GL3_SetMode() - invalid mode\n");
if(gl_mode->value == gl3state.prev_mode)
{
// trying again would result in a crash anyway, give up already
// (this would happen if your initing fails at all and your resolution already was 640x480)
return false;
}
ri.Cvar_SetValue("gl_mode", gl3state.prev_mode);
gl_mode->modified = false;
R_Printf(PRINT_ALL, "ref_gl::R_SetMode() - invalid mode\n");
}
/* try setting it back to something safe */
if ((err = SetMode_impl(&vid.width, &vid.height, gl3state.prev_mode, false)) != rserr_ok)
{
R_Printf(PRINT_ALL, "ref_gl::R_SetMode() - could not revert to safe mode\n");
R_Printf(PRINT_ALL, "ref_gl3::GL3_SetMode() - could not revert to safe mode\n");
return false;
}
}
@ -455,7 +463,6 @@ GL3_Init(void)
/* create the window and set up the context */
if (!GL3_SetMode())
{
//QGL_Shutdown();
R_Printf(PRINT_ALL, "ref_gl3::R_Init() - could not R_SetMode()\n");
return false;
}
@ -557,12 +564,17 @@ GL3_Shutdown(void)
ri.Cmd_RemoveCommand("imagelist");
ri.Cmd_RemoveCommand("gl_strings");
GL3_Mod_FreeAll();
GL3_ShutdownMeshes();
GL3_ShutdownImages();
GL3_SurfShutdown();
GL3_Draw_ShutdownLocal();
GL3_ShutdownShaders();
// only call all these if we have an OpenGL context and the gl function pointers
// randomly chose one function that should always be there to test..
if(glDeleteBuffers != NULL)
{
GL3_Mod_FreeAll();
GL3_ShutdownMeshes();
GL3_ShutdownImages();
GL3_SurfShutdown();
GL3_Draw_ShutdownLocal();
GL3_ShutdownShaders();
}
/* shutdown OS specific OpenGL stuff like contexts, etc. */
GL3_ShutdownWindow(false);

View file

@ -292,19 +292,24 @@ void GL3_ShutdownWindow(qboolean contextOnly)
current. This may help some broken
video drivers like the AMD Catalyst
to avoid artifacts in unused screen
areas. */
areas.
Only do this if we have a context, though. */
if (window)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GL3_EndFrame();
#if SDL_VERSION_ATLEAST(2, 0, 0)
if(context)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GL3_EndFrame();
SDL_GL_DeleteContext(context);
context = NULL;
}
#else // SDL1.2
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GL3_EndFrame();
#endif
}