From f869bffe971de35fa1c26156121f2fd8e143ff1e Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Thu, 6 Jun 2024 17:05:04 -0500 Subject: [PATCH] OpenGL2: Fallback to OpenGL ES if OpenGL fails --- README.md | 7 +- code/sdl/sdl_glimp.c | 192 +++++++++++++++++++++---------------------- opengl2-readme.md | 8 +- 3 files changed, 104 insertions(+), 103 deletions(-) diff --git a/README.md b/README.md index f2031c730e..a5c5337980 100644 --- a/README.md +++ b/README.md @@ -168,11 +168,12 @@ embedded System-on-a-Chip and mobile platforms. The opengl1 renderer does not have OpenGL ES support. -The `r_useOpenGLES` cvar controls whether to use OpenGL or OpenGL ES API. -Set to -1 for auto (default), 0 for OpenGL, and 1 for OpenGL ES. It should be +The opengl2 renderer will try both OpenGL and OpenGL ES APIs to find one that +works. The `r_preferOpenGLES` cvar controls which API to try first. +Set it to -1 for auto (default), 0 for OpenGL, and 1 for OpenGL ES. It should be set using command line arguments: - ioquake3 +set cl_renderer opengl2 +set r_useOpenGLES 1 + ioquake3 +set cl_renderer opengl2 +set r_preferOpenGLES 1 # Console diff --git a/code/sdl/sdl_glimp.c b/code/sdl/sdl_glimp.c index b24759b5a5..a3c5bb82bf 100644 --- a/code/sdl/sdl_glimp.c +++ b/code/sdl/sdl_glimp.c @@ -52,7 +52,7 @@ cvar_t *r_allowSoftwareGL; // Don't abort out if a hardware visual can't be obta cvar_t *r_allowResize; // make window resizable cvar_t *r_centerWindow; cvar_t *r_sdlDriver; -cvar_t *r_useOpenGLES; +cvar_t *r_preferOpenGLES; int qglMajorVersion, qglMinorVersion; int qglesMajorVersion, qglesMinorVersion; @@ -394,6 +394,12 @@ GLimp_SetMode */ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder, qboolean fixedFunction) { + struct GLimp_ContextType { + int profileMask; + int majorVersion; + int minorVersion; + } contexts[3]; + int numContexts, type; const char *glstring; int perChannelColorBits; int colorBits, depthBits, stencilBits; @@ -524,6 +530,48 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder, qbool stencilBits = r_stencilbits->value; samples = r_ext_multisample->value; + numContexts = 0; + + if ( !fixedFunction ) { + int profileMask; + qboolean preferOpenGLES; + + SDL_GL_ResetAttributes(); + SDL_GL_GetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, &profileMask ); + + preferOpenGLES = ( r_preferOpenGLES->integer == 1 || + ( r_preferOpenGLES->integer == -1 && profileMask == SDL_GL_CONTEXT_PROFILE_ES ) ); + + if ( preferOpenGLES ) { + contexts[numContexts].profileMask = SDL_GL_CONTEXT_PROFILE_ES; + contexts[numContexts].majorVersion = 2; + contexts[numContexts].minorVersion = 0; + numContexts++; + } + + contexts[numContexts].profileMask = SDL_GL_CONTEXT_PROFILE_CORE; + contexts[numContexts].majorVersion = 3; + contexts[numContexts].minorVersion = 2; + numContexts++; + + contexts[numContexts].profileMask = 0; + contexts[numContexts].majorVersion = 2; + contexts[numContexts].minorVersion = 0; + numContexts++; + + if ( !preferOpenGLES ) { + contexts[numContexts].profileMask = SDL_GL_CONTEXT_PROFILE_ES; + contexts[numContexts].majorVersion = 2; + contexts[numContexts].minorVersion = 0; + numContexts++; + } + } else { + contexts[numContexts].profileMask = 0; + contexts[numContexts].majorVersion = 1; + contexts[numContexts].minorVersion = 1; + numContexts++; + } + for (i = 0; i < 16; i++) { int testColorBits, testDepthBits, testStencilBits; @@ -656,116 +704,68 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder, qbool SDL_SetWindowIcon( SDL_window, icon ); - if (!fixedFunction) - { - int profileMask; - - SDL_GL_GetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, &profileMask ); - - if ( r_useOpenGLES->integer == 1 || ( r_useOpenGLES->integer == -1 && profileMask == SDL_GL_CONTEXT_PROFILE_ES ) ) - { - ri.Printf( PRINT_ALL, "Trying to get an OpenGL ES 2.0 context\n" ); - SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES ); - SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 2 ); - SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 0 ); + for ( type = 0; type < numContexts; type++ ) { + char contextName[32]; - SDL_glContext = SDL_GL_CreateContext( SDL_window ); - if ( !SDL_glContext ) - { - ri.Printf( PRINT_ALL, "SDL_GL_CreateContext failed: %s\n", SDL_GetError() ); - } - else - { - ri.Printf( PRINT_ALL, "SDL_GL_CreateContext succeeded.\n" ); - - if ( !GLimp_GetProcAddresses( fixedFunction ) ) - { - ri.Printf( PRINT_ALL, "GLimp_GetProcAddresses() failed for OpenGL ES 2.0 context\n" ); - GLimp_ClearProcAddresses(); - SDL_GL_DeleteContext( SDL_glContext ); - SDL_glContext = NULL; - } - } + switch ( contexts[type].profileMask ) { + default: + case 0: + Com_sprintf( contextName, sizeof( contextName ), "OpenGL %d.%d", + contexts[type].majorVersion, contexts[type].minorVersion ); + break; + case SDL_GL_CONTEXT_PROFILE_CORE: + Com_sprintf( contextName, sizeof( contextName ), "OpenGL %d.%d Core", + contexts[type].majorVersion, contexts[type].minorVersion ); + break; + case SDL_GL_CONTEXT_PROFILE_ES: + Com_sprintf( contextName, sizeof( contextName ), "OpenGL ES %d.%d", + contexts[type].majorVersion, contexts[type].minorVersion ); + break; } - if ( !SDL_glContext ) - { - ri.Printf( PRINT_ALL, "Trying to get an OpenGL 3.2 core context\n" ); - SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE ); - SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 ); - SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 2 ); - - SDL_glContext = SDL_GL_CreateContext( SDL_window ); - if ( !SDL_glContext ) - { - ri.Printf( PRINT_ALL, "SDL_GL_CreateContext failed: %s\n", SDL_GetError() ); - } - else - { - const char *renderer; - - ri.Printf( PRINT_ALL, "SDL_GL_CreateContext succeeded.\n" ); - - if ( GLimp_GetProcAddresses( fixedFunction ) ) - { - renderer = (const char *)qglGetString( GL_RENDERER ); - } - else - { - ri.Printf( PRINT_ALL, "GLimp_GetProcAddresses() failed for OpenGL 3.2 core context\n" ); - renderer = NULL; - } - - if ( !renderer || strstr( renderer, "Software Renderer" ) || strstr( renderer, "Software Rasterizer" ) ) - { - if ( renderer ) - ri.Printf(PRINT_ALL, "GL_RENDERER is %s, rejecting context\n", renderer); - - GLimp_ClearProcAddresses(); - SDL_GL_DeleteContext( SDL_glContext ); - SDL_glContext = NULL; - } - } - } + SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, contexts[type].profileMask ); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, contexts[type].majorVersion ); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, contexts[type].minorVersion ); + SDL_glContext = SDL_GL_CreateContext( SDL_window ); if ( !SDL_glContext ) { - ri.Printf( PRINT_ALL, "Trying to get an OpenGL 2.0 context\n" ); - - SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, 0 ); - SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 2 ); - SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 0 ); - } - } - else - { - SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, 0 ); - SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 1 ); - SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 1 ); - - SDL_glContext = NULL; - } - - if ( !SDL_glContext ) - { - if( ( SDL_glContext = SDL_GL_CreateContext( SDL_window ) ) == NULL ) - { - ri.Printf( PRINT_DEVELOPER, "SDL_GL_CreateContext failed: %s\n", SDL_GetError( ) ); - SDL_DestroyWindow( SDL_window ); - SDL_window = NULL; + ri.Printf( PRINT_ALL, "SDL_GL_CreateContext() for %s context failed: %s\n", contextName, SDL_GetError() ); continue; } if ( !GLimp_GetProcAddresses( fixedFunction ) ) { - ri.Printf( PRINT_ALL, "GLimp_GetProcAddresses() failed\n" ); + ri.Printf( PRINT_ALL, "GLimp_GetProcAddresses() for %s context failed\n", contextName ); GLimp_ClearProcAddresses(); SDL_GL_DeleteContext( SDL_glContext ); SDL_glContext = NULL; - SDL_DestroyWindow( SDL_window ); - SDL_window = NULL; continue; } + + if ( contexts[type].profileMask == SDL_GL_CONTEXT_PROFILE_CORE ) { + const char *renderer; + + renderer = (const char *)qglGetString( GL_RENDERER ); + + if ( !renderer || strstr( renderer, "Software Renderer" ) || strstr( renderer, "Software Rasterizer" ) ) + { + ri.Printf( PRINT_ALL, "GL_RENDERER is %s, rejecting %s context\n", renderer, contextName ); + + GLimp_ClearProcAddresses(); + SDL_GL_DeleteContext( SDL_glContext ); + SDL_glContext = NULL; + continue; + } + } + + break; + } + + if ( !SDL_glContext ) { + SDL_DestroyWindow( SDL_window ); + SDL_window = NULL; + continue; } qglClearColor( 0, 0, 0, 1 ); @@ -1055,7 +1055,7 @@ void GLimp_Init( qboolean fixedFunction ) r_sdlDriver = ri.Cvar_Get( "r_sdlDriver", "", CVAR_ROM ); r_allowResize = ri.Cvar_Get( "r_allowResize", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_centerWindow = ri.Cvar_Get( "r_centerWindow", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_useOpenGLES = ri.Cvar_Get( "r_useOpenGLES", "-1", CVAR_ARCHIVE | CVAR_LATCH ); + r_preferOpenGLES = ri.Cvar_Get( "r_preferOpenGLES", "-1", CVAR_ARCHIVE | CVAR_LATCH ); if( ri.Cvar_VariableIntegerValue( "com_abnormalExit" ) ) { diff --git a/opengl2-readme.md b/opengl2-readme.md index 2e076cfaa6..c798d89c6f 100644 --- a/opengl2-readme.md +++ b/opengl2-readme.md @@ -65,10 +65,10 @@ For Win32: Cvars for API: -* `r_useOpenGLES` - This enables using OpenGL ES 2+. - Many features are not supported such as sun shadows and HDR. - 1 - Use OpenGL ES. - 0 - Use desktop OpenGL. +* `r_preferOpenGLES` - This sets the preference for using OpenGL or OpenGL ES 2. + Many features are not supported when using OpenGL ES such as sun shadows and HDR. + 1 - Prefer OpenGL ES 2+. + 0 - Prefer desktop OpenGL. -1 - Automatically pick (default). Cvars for simple rendering features: