From: bones_was_here Date: Tue, 3 Oct 2023 02:36:16 +0000 (+1000) Subject: Implement OpenGL version checking, use it for occlusion queries X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=e6815ebce187ac7ddcddcdddc5a939df7c778c07;p=xonotic%2Fdarkplaces.git Implement OpenGL version checking, use it for occlusion queries This allows DP to use core features added after 3.2 without crashing, in this case query buffer objects. In div0-stable GL_ARB_query_buffer_object was checked but that extension was written against 4.3 and became part of core in 4.4 so we can just check for 4.4. Fixes https://gitlab.com/xonotic/darkplaces/-/issues/176 Moves GL function pointer initialisation to its own function to support a workaround for NVIDIA's opinion about GL profiles. Signed-off-by: bones_was_here --- diff --git a/glquake.h b/glquake.h index e3f8f6d0..46efbf07 100644 --- a/glquake.h +++ b/glquake.h @@ -1034,6 +1034,8 @@ extern void (GLAPIENTRY *qglViewport)(GLint x, GLint y, GLsizei width, GLsizei h #define GL_TEXTURE_3D 0x806F #define GL_HALF_FLOAT 0x140B +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C #define GL_NUM_EXTENSIONS 0x821D diff --git a/r_shadow.c b/r_shadow.c index c80f0d7d..fed00a8f 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -232,7 +232,7 @@ cvar_t r_shadow_bouncegrid_subsamples = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bounc cvar_t r_shadow_bouncegrid_threaded = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_threaded", "1", "enables use of taskqueue_maxthreads to perform the traces and slice rendering of bouncegrid"}; cvar_t r_coronas = {CF_CLIENT | CF_ARCHIVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"}; cvar_t r_coronas_occlusionsizescale = {CF_CLIENT | CF_ARCHIVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksum the proportion of hidden pixels controls corona intensity"}; -cvar_t r_coronas_occlusionquery = {CF_CLIENT | CF_ARCHIVE, "r_coronas_occlusionquery", "0", "fades coronas according to visibility"}; +cvar_t r_coronas_occlusionquery = {CF_CLIENT | CF_ARCHIVE, "r_coronas_occlusionquery", "0", "fades coronas according to visibility, requires OpenGL 4.4"}; cvar_t gl_flashblend = {CF_CLIENT | CF_ARCHIVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"}; cvar_t r_editlights = {CF_CLIENT, "r_editlights", "0", "enables .rtlights file editing mode"}; cvar_t r_editlights_cursordistance = {CF_CLIENT, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"}; @@ -4561,7 +4561,8 @@ void R_Shadow_DrawCoronas(void) { case RENDERPATH_GL32: case RENDERPATH_GLES2: - usequery = r_coronas_occlusionquery.integer; + // buffer binding target GL_QUERY_BUFFER: Core since version 4.4 + usequery = r_coronas_occlusionquery.integer && vid.support.glversion >= 44; #ifndef USE_GLES2 if (usequery) { diff --git a/vid.h b/vid.h index 8ddf76c4..8f1977bc 100644 --- a/vid.h +++ b/vid.h @@ -41,6 +41,7 @@ renderpath_t; typedef struct viddef_support_s { + int glversion; // this is at least 32 int glshaderversion; // this is at least 150 (GL 3.2) qbool amd_texture_texture4; qbool arb_texture_gather; @@ -199,6 +200,7 @@ qbool GL_ExtensionSupported(const char *name); void VID_Shared_Init(void); +void GL_InitFunctions(void); void GL_Setup(void); void VID_ClearExtensions(void); diff --git a/vid_sdl.c b/vid_sdl.c index 11cc4ac2..6f71d29b 100644 --- a/vid_sdl.c +++ b/vid_sdl.c @@ -1570,6 +1570,9 @@ static qbool VID_InitModeGL(viddef_mode_t *mode) 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); + /* Requesting a Core profile and 3.2 minimum is mandatory on macOS and older Mesa drivers. + * It works fine on other drivers too except NVIDIA, see HACK below. + */ #endif SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, (gl_debug.integer > 0 ? SDL_GL_CONTEXT_DEBUG_FLAG : 0)); @@ -1592,6 +1595,27 @@ static qbool VID_InitModeGL(viddef_mode_t *mode) return false; } + GL_InitFunctions(); + +#if !defined(USE_GLES2) && !defined(MACOSX) + // NVIDIA hates the Core profile and limits the version to the minimum we specified. + // HACK: to detect NVIDIA we first need a context, fortunately replacing it takes a few milliseconds + gl_vendor = (const char *)qglGetString(GL_VENDOR); + if (strncmp(gl_vendor, "NVIDIA", 6) == 0) + { + Con_DPrint("The Way It's Meant To Be Played: replacing OpenGL Core profile with Compatibility profile...\n"); + SDL_GL_DeleteContext(context); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); + context = SDL_GL_CreateContext(window); + if (context == NULL) + { + Con_Printf(CON_ERROR "Failed to initialize OpenGL context: %s\n", SDL_GetError()); + VID_Shutdown(); + return false; + } + } +#endif + SDL_GL_SetSwapInterval(bound(-1, vid_vsync.integer, 1)); vid_usingvsync = (vid_vsync.integer != 0); diff --git a/vid_shared.c b/vid_shared.c index 27e01c70..2a9b84ba 100644 --- a/vid_shared.c +++ b/vid_shared.c @@ -680,20 +680,40 @@ void VID_ClearExtensions(void) memset(&vid.support, 0, sizeof(vid.support)); } -void GL_Setup(void) +void GL_InitFunctions(void) { - char *s; - int j; - GLint numextensions = 0; +#ifndef USE_GLES2 const glfunction_t *func; qbool missingrequiredfuncs = false; static char missingfuncs[16384]; -#ifndef USE_GLES2 // first fetch the function pointers for everything - after this we can begin making GL calls. for (func = openglfuncs; func->name != NULL; func++) *func->funcvariable = (void *)GL_GetProcAddress(func->name); + + missingfuncs[0] = 0; + for (func = openglfuncs; func && func->name != NULL; func++) + { + if (!*func->funcvariable && !strcmp(func->extension, "core")) + { + Con_DPrintf("GL context is missing required function \"%s\"!\n", func->name); + missingrequiredfuncs = true; + strlcat(missingfuncs, " ", sizeof(missingfuncs)); + strlcat(missingfuncs, func->name, sizeof(missingfuncs)); + } + } + + if (missingrequiredfuncs) + Sys_Error("OpenGL driver/hardware lacks required features:\n%s", missingfuncs); #endif +} + +void GL_Setup(void) +{ + char *s; + int j; + GLint numextensions = 0; + int majorv, minorv; gl_renderer = (const char *)qglGetString(GL_RENDERER); gl_vendor = (const char *)qglGetString(GL_VENDOR); @@ -704,6 +724,13 @@ void GL_Setup(void) Con_Printf("GL_VERSION: %s\n", gl_version); #ifndef USE_GLES2 + qglGetIntegerv(GL_MAJOR_VERSION, &majorv); + qglGetIntegerv(GL_MINOR_VERSION, &minorv); + vid.support.glversion = 10 * majorv + minorv; + if (vid.support.glversion < 32) + // fallback, should never get here: GL context creation should have failed + Sys_Error("OpenGL driver/hardware supports version %i.%i but 3.2 is the minimum\n", majorv, minorv); + qglGetIntegerv(GL_NUM_EXTENSIONS, &numextensions); Con_DPrint("GL_EXTENSIONS:\n"); for (j = 0; j < numextensions; j++) @@ -716,23 +743,6 @@ void GL_Setup(void) Con_DPrint("\n"); #endif //USE_GLES2 -#ifndef USE_GLES2 - missingfuncs[0] = 0; - for (func = openglfuncs; func && func->name != NULL; func++) - { - if (!*func->funcvariable && !strcmp(func->extension, "core")) - { - Con_DPrintf("GL context is missing required function \"%s\"!\n", func->name); - missingrequiredfuncs = true; - strlcat(missingfuncs, " ", sizeof(missingfuncs)); - strlcat(missingfuncs, func->name, sizeof(missingfuncs)); - } - } - - if (missingrequiredfuncs) - Sys_Error("OpenGL driver/hardware lacks required features:\n%s", missingfuncs); -#endif - Con_DPrint("Checking OpenGL extensions...\n"); // detect what GLSL version is available, to enable features like higher quality reliefmapping