automagically select best shadowmapping filter mode depending on hardware
authoreihrul <eihrul@d7cf8633-e32d-0410-b094-e92efae38249>
Thu, 1 Oct 2009 05:43:23 +0000 (05:43 +0000)
committereihrul <eihrul@d7cf8633-e32d-0410-b094-e92efae38249>
Thu, 1 Oct 2009 05:43:23 +0000 (05:43 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@9269 d7cf8633-e32d-0410-b094-e92efae38249

gl_rmain.c
gl_textures.c
glquake.h
r_shadow.c
vid_shared.c

index 8375090..a9e5b78 100644 (file)
@@ -447,6 +447,9 @@ static void R_BuildFogTexture(void)
 static const char *builtinshaderstring =
 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
 "// written by Forest 'LordHavoc' Hale\n"
+"\n"
+"// enable various extensions depending on permutation:\n"
+"\n" 
 "#ifdef USESHADOWMAPRECT\n"
 "# extension GL_ARB_texture_rectangle : enable\n"
 "#endif\n"
@@ -471,6 +474,10 @@ static const char *builtinshaderstring =
 "# extension GL_EXT_gpu_shader4 : enable\n"
 "#endif\n"
 "\n"
+"#ifdef USESHADOWSAMPLER\n"
+"# extension GL_ARB_shadow : enable\n"
+"#endif\n"
+"\n"
 "// common definitions between vertex shader and fragment shader:\n"
 "\n"
 "//#ifdef __GLSL_CG_DATA_TYPES\n"
@@ -1995,8 +2002,9 @@ extern qboolean r_shadow_usingshadowmapcube;
 extern qboolean r_shadow_usingshadowmap2d;
 extern float r_shadow_shadowmap_texturescale[4];
 extern float r_shadow_shadowmap_parameters[4];
-extern int r_shadow_shadowmapvsdct;
-extern int r_shadow_shadowmapfilter;
+extern qboolean r_shadow_shadowmapvsdct;
+extern qboolean r_shadow_shadowmapsampler;
+extern int r_shadow_shadowmappcf;
 void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass)
 {
        // select a permutation of the lighting shader appropriate to this
@@ -2047,21 +2055,12 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                        else if(r_shadow_shadowmapvsdct)
                                permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
 
-                       switch (r_shadow_shadowmapfilter)
-                       {
-                       case 1:
+                       if (r_shadow_shadowmapsampler)
                                permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
-                               break;
-                       case 2:
-                               permutation |= SHADERPERMUTATION_SHADOWSAMPLER | SHADERPERMUTATION_SHADOWMAPPCF;
-                               break;
-                       case 3:
-                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
-                               break;
-                       case 4:
+                       if (r_shadow_shadowmappcf > 1)
                                permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
-                               break;
-                       } 
+                       else if (r_shadow_shadowmappcf)
+                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
                }
        }
        else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
index 0a3f2cb..c3cbcf3 100644 (file)
@@ -785,15 +785,18 @@ static void GL_SetupTextureParameters(int flags, textype_t textype, int texturet
 
        if (textype == TEXTYPE_SHADOWMAP)
        {
-               if (flags & TEXF_COMPARE)
+               if (gl_support_arb_shadow)
                {
-                       qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
-               }
-               else
-               {
-                       qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
+                       if (flags & TEXF_COMPARE)
+                       {
+                               qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
+                       }
+                       else
+                       {
+                               qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
+                       }
+                       qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
                }
-               qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
                qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
        }
 
index fb7a833..301b466 100644 (file)
--- a/glquake.h
+++ b/glquake.h
@@ -135,11 +135,6 @@ typedef ptrdiff_t GLsizeiptrARB;
 #define GL_LINE                                        0x1B01
 #define GL_FILL                                        0x1B02
 
-extern int gl_support_anisotropy;
-extern int gl_max_anisotropy;
-#define GL_TEXTURE_MAX_ANISOTROPY_EXT          0x84FE
-#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT      0x84FF
-
 #define GL_ADD                                 0x0104
 #define GL_DECAL                               0x2101
 #define GL_MODULATE                            0x2100
@@ -268,8 +263,16 @@ extern int gl_max_anisotropy;
 
 #endif
 
+//GL_EXT_texture_filter_anisotropic
+extern int gl_support_anisotropy;
+extern int gl_max_anisotropy;
+#ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT       0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT   0x84FF
+#endif
+
 // GL_ARB_depth_texture
-#ifndef GL_DEPTH_COMPOENNT32_ARB
+#ifndef GL_DEPTH_COMPONENT32_ARB
 #define GL_DEPTH_COMPONENT16_ARB          0x81A5
 #define GL_DEPTH_COMPONENT24_ARB          0x81A6
 #define GL_DEPTH_COMPONENT32_ARB          0x81A7
@@ -278,6 +281,7 @@ extern int gl_max_anisotropy;
 #endif
 
 // GL_ARB_shadow
+extern int gl_support_arb_shadow;
 #ifndef GL_TEXTURE_COMPARE_MODE_ARB
 #define GL_TEXTURE_COMPARE_MODE_ARB       0x884C
 #define GL_TEXTURE_COMPARE_FUNC_ARB       0x884D
@@ -953,6 +957,12 @@ extern void (GLAPIENTRY *qglGetQueryObjectuivARB)(GLuint qid, GLenum pname, GLui
 #define GL_LUMINANCE_ALPHA                0x190A
 #define GL_LUMINANCE16_ALPHA16            0x8048
 
+//GL_AMD_texture_texture4
+extern int gl_support_amd_texture_texture4;
+
+//GL_ARB_texture_gather
+extern int gl_support_arb_texture_gather;
+
 #define DEBUGGL
 
 #ifdef DEBUGGL
index fd8830c..27eeaa4 100644 (file)
@@ -179,9 +179,12 @@ GLuint r_shadow_fborectangle;
 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS][6];
 GLuint r_shadow_fbo2d;
 int r_shadow_shadowmode;
-int r_shadow_shadowmapvsdct;
+int r_shadow_shadowmapfilterquality;
+int r_shadow_shadowmaptexturetype;
 int r_shadow_shadowmapmaxsize;
-int r_shadow_shadowmapfilter;
+qboolean r_shadow_shadowmapvsdct;
+qboolean r_shadow_shadowmapsampler;
+int r_shadow_shadowmappcf;
 int r_shadow_shadowmapborder;
 int r_shadow_lightscissor[4];
 
@@ -263,7 +266,8 @@ cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compi
 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
-cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "0", "shadowmap filter modes: 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
+cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "0", "shadowmap texture types: 0 = auto-select, 1 = 2D, 2 = rectangle, 3 = cubemap"};
+cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
@@ -338,18 +342,71 @@ cachepic_t *r_editlights_sprcubemaplight;
 cachepic_t *r_editlights_sprcubemapnoshadowlight;
 cachepic_t *r_editlights_sprselection;
 
-void R_Shadow_FreeShadowMaps(void)
+void R_Shadow_SetShadowMode(void)
 {
-       int i;
-
        r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
-       r_shadow_shadowmode = r_shadow_shadowmapping.integer;
-       r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer;
-       r_shadow_shadowmapfilter = r_shadow_shadowmapping_filterquality.integer;
+       r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
+       r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
+       r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
        r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
        r_shadow_shadowmaplod = -1;
+       r_shadow_shadowmapsampler = false;
+       r_shadow_shadowmappcf = 0;
+       r_shadow_shadowmode = 0;
+       if(r_shadow_shadowmapping.integer)
+       {
+               if(r_shadow_shadowmapfilterquality < 0)
+               {
+                       if(strstr(gl_vendor, "NVIDIA")) 
+                       {
+                               r_shadow_shadowmapsampler = gl_support_arb_shadow;
+                               r_shadow_shadowmappcf = 1;
+                       }
+                       else if(gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) 
+                               r_shadow_shadowmappcf = 1;
+                       else if(strstr(gl_vendor, "ATI")) 
+                               r_shadow_shadowmappcf = 1;
+                       else 
+                               r_shadow_shadowmapsampler = gl_support_arb_shadow;
+               }
+               else 
+               {
+                       switch (r_shadow_shadowmapfilterquality)
+                       {
+                       case 1:
+                               r_shadow_shadowmapsampler = gl_support_arb_shadow;
+                               break;
+                       case 2:
+                               r_shadow_shadowmapsampler = gl_support_arb_shadow;
+                               r_shadow_shadowmappcf = 1;
+                               break;
+                       case 3:
+                               r_shadow_shadowmappcf = 1;
+                               break;
+                       case 4:
+                               r_shadow_shadowmappcf = 2;
+                               break;
+                       }
+               }
+        r_shadow_shadowmode = r_shadow_shadowmaptexturetype;
+               if(r_shadow_shadowmode <= 0)
+               {
+                       if(!gl_texturerectangle || gl_support_arb_texture_non_power_of_two) 
+                               r_shadow_shadowmode = 1;
+                       else if((gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
+                               r_shadow_shadowmode = 1;
+                       else 
+                               r_shadow_shadowmode = 2;
+               }
+       }
+}
+
+void R_Shadow_FreeShadowMaps(void)
+{
+       int i;
+
+       R_Shadow_SetShadowMode();
 
-       CHECKGLERROR
        if (r_shadow_fborectangle)
                qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
        r_shadow_fborectangle = 0;
@@ -401,8 +458,11 @@ void r_shadow_start(void)
        r_shadow_shadowmapmaxsize = 0;
        r_shadow_shadowmapsize = 0;
        r_shadow_shadowmaplod = 0;
-       r_shadow_shadowmapvsdct = 0;
-       r_shadow_shadowmapfilter = 0;
+       r_shadow_shadowmapfilterquality = 0;
+       r_shadow_shadowmaptexturetype = 0;
+       r_shadow_shadowmapvsdct = false;
+       r_shadow_shadowmapsampler = false;
+       r_shadow_shadowmappcf = 0;
        r_shadow_fborectangle = 0;
        r_shadow_fbo2d = 0;
        memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
@@ -575,6 +635,7 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_scissor);
        Cvar_RegisterVariable(&r_shadow_shadowmapping);
        Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
+       Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
        Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
        Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
        Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
@@ -1497,7 +1558,8 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
                if (!r_shadow_shadowmap2dtexture)
                {
 #if 1
-                       r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*4, r_shadow_shadowmapfilter == 1 || r_shadow_shadowmapfilter == 2);
+                       int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
+                       r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapsampler);
                        qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
                        qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
                        qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
@@ -1527,8 +1589,8 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
                R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapping_bordersize.integer, nearclip, farclip, NULL);
                r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
                r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
-               r_shadow_shadowmap_parameters[0] = r_shadow_shadowmapvsdct ? size / (float)maxsize : 0.5f * (size - r_shadow_shadowmapborder);
-               r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 0.75f * size / (float)maxsize : size;
+               r_shadow_shadowmap_parameters[0] = r_shadow_shadowmapvsdct ? 2*size * r_shadow_shadowmap_texturescale[0] : 0.5f * (size - r_shadow_shadowmapborder);
+               r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 3*size * r_shadow_shadowmap_texturescale[1] : size;
                r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
        }
        else if (r_shadow_shadowmode == 2)
@@ -1539,7 +1601,7 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
                if (!r_shadow_shadowmaprectangletexture)
                {
 #if 1
-                       r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapfilter == 1 || r_shadow_shadowmapfilter == 2);
+                       r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapsampler);
                        qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
                        qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
                        qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
@@ -1579,7 +1641,7 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
                if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
                {
  #if 1
-                       r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", bound(1, maxsize >> r_shadow_shadowmaplod, 2048), r_shadow_shadowmapfilter == 1 || r_shadow_shadowmapfilter == 2);
+                       r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", bound(1, maxsize >> r_shadow_shadowmaplod, 2048), r_shadow_shadowmapsampler);
                        qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
                        for (i = 0;i < 6;i++)
                        {
@@ -3821,7 +3883,12 @@ void R_ShadowVolumeLighting(qboolean visible)
        dlight_t *light;
        size_t range;
 
-       if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) || r_shadow_shadowmode != r_shadow_shadowmapping.integer || r_shadow_shadowmapvsdct != r_shadow_shadowmapping_vsdct.integer || r_shadow_shadowmapfilter != r_shadow_shadowmapping_filterquality.integer || r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
+       if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) || 
+               (r_shadow_shadowmode != 0) != (r_shadow_shadowmapping.integer != 0) || 
+               r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) || 
+               r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
+               r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer || 
+               r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
                R_Shadow_FreeShadowMaps();
 
        if (r_editlights.integer)
index 68428f3..978a6d3 100644 (file)
@@ -43,6 +43,8 @@ int gl_support_arb_texture_non_power_of_two = false;
 int gl_dot3arb = false;
 // GL_ARB_depth_texture
 int gl_depthtexture = false;
+// GL_ARB_shadow
+int gl_support_arb_shadow = false;
 // GL_SGIS_texture_edge_clamp
 int gl_support_clamptoedge = false;
 // GL_EXT_texture_filter_anisotropic
@@ -72,6 +74,10 @@ int gl_support_ext_framebuffer_object = false;
 int gl_support_texture_compression = false;
 //GL_ARB_occlusion_query
 int gl_support_arb_occlusion_query = false;
+//GL_AMD_texture_texture4
+int gl_support_amd_texture_texture4 = false;
+//GL_ARB_texture_gather
+int gl_support_arb_texture_gather = false;
 
 // LordHavoc: if window is hidden, don't update screen
 qboolean vid_hidden = true;
@@ -832,6 +838,7 @@ void VID_CheckExtensions(void)
        gl_support_arb_texture_non_power_of_two = false;
        gl_dot3arb = false;
        gl_depthtexture = false;
+       gl_support_arb_shadow = false;
        gl_support_clamptoedge = false;
        gl_support_anisotropy = false;
        gl_max_anisotropy = 1;
@@ -847,6 +854,8 @@ void VID_CheckExtensions(void)
        gl_support_ext_framebuffer_object = false;
        gl_support_texture_compression = false;
        gl_support_arb_occlusion_query = false;
+       gl_support_amd_texture_texture4 = false;
+       gl_support_arb_texture_gather = false;
 
        if (!GL_CheckExtension("1.1", opengl110funcs, NULL, false))
                Sys_Error("OpenGL 1.1.0 functions not found");
@@ -887,7 +896,11 @@ void VID_CheckExtensions(void)
 // COMMANDLINEOPTION: GL: -norectangle disables GL_ARB_texture_rectangle (required for bumpmapping)
        if ((gl_texturerectangle = GL_CheckExtension("GL_ARB_texture_rectangle", NULL, "-norectangle", false)))
                qglGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &gl_max_rectangle_texture_size);
+// COMMANDLINEOPTION: GL: -nodepthtexture disables use of GL_ARB_depth_texture (required for shadowmapping)
        gl_depthtexture = GL_CheckExtension("GL_ARB_depth_texture", NULL, "-nodepthtexture", false);
+// COMMANDLINEOPTION: GL: -noshadow disables use of GL_ARB_shadow (required for hardware shadowmap filtering)
+       gl_support_arb_shadow = GL_CheckExtension("GL_ARB_shadow", NULL, "-noshadow", false);
+
 // COMMANDLINEOPTION: GL: -notexturecompression disables GL_ARB_texture_compression (which saves video memory if it is supported, but can also degrade image quality, see gl_texturecompression cvar documentation for more information)
        gl_support_texture_compression = GL_CheckExtension("GL_ARB_texture_compression", texturecompressionfuncs, "-notexturecompression", false);
 // COMMANDLINEOPTION: GL: -nocva disables GL_EXT_compiled_vertex_array (renders faster)
@@ -942,6 +955,11 @@ void VID_CheckExtensions(void)
 
 // COMMANDLINEOPTION: GL: -noocclusionquery disables GL_ARB_occlusion_query (which allows coronas to fade according to visibility, and potentially used for rendering optimizations)
        gl_support_arb_occlusion_query = GL_CheckExtension("GL_ARB_occlusion_query", occlusionqueryfuncs, "-noocclusionquery", false);
+
+// COMMANDLINEOPTION: GL: -notexture4 disables GL_AMD_texture_texture4 (which provides fetch4 sampling)
+    gl_support_amd_texture_texture4 = GL_CheckExtension("GL_AMD_texture_texture4", NULL, "-notexture4", false);
+// COMMANDLINEOPTION: GL: -notexturegather disables GL_ARB_texture_gather (which provides fetch4 sampling)
+    gl_support_arb_texture_gather = GL_CheckExtension("GL_ARB_texture_gather", NULL, "-notexturegather", false);
 }
 
 void Force_CenterView_f (void)