]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
Implement OpenGL version checking, use it for occlusion queries
authorbones_was_here <bones_was_here@xonotic.au>
Tue, 3 Oct 2023 02:36:16 +0000 (12:36 +1000)
committerbones_was_here <bones_was_here@xonotic.au>
Sat, 28 Oct 2023 08:20:50 +0000 (18:20 +1000)
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 <bones_was_here@xonotic.au>
glquake.h
r_shadow.c
vid.h
vid_sdl.c
vid_shared.c

index e3f8f6d0eee4a40e35865228f932683369869952..46efbf0721fe6ac23334c0a201fe1f9502d918b4 100644 (file)
--- 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
 
 
index c80f0d7da57133924a66b73f634a035e7b59577e..fed00a8f26a1e4c2d49fcfcf479e9130bc7a38e2 100644 (file)
@@ -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 8ddf76c4ff6bff88c87b5ec46dd56d243f2455e2..8f1977bc9ef7fd66c9a1460460d07293fad90f25 100644 (file)
--- 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);
index 11cc4ac298702aa51f5bbcc2b9afabd8c9d7eba3..6f71d29b5104a0da1d869ad6ee44b4f7ff49c665 100644 (file)
--- 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);
 
index 27e01c7023519083814bacf6e3314967d99f374e..2a9b84ba8b21ab4db7fa0cc5b7a9f8a3e2fcf9d8 100644 (file)
@@ -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