From: eihrul <eihrul@d7cf8633-e32d-0410-b094-e92efae38249>
Date: Thu, 1 Oct 2009 05:43:23 +0000 (+0000)
Subject: automagically select best shadowmapping filter mode depending on hardware
X-Git-Tag: xonotic-v0.1.0preview~1364
X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=b6ee99c1ec92872b535c07cef78cf38a31584021;p=xonotic%2Fdarkplaces.git

automagically select best shadowmapping filter mode depending on hardware


git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@9269 d7cf8633-e32d-0410-b094-e92efae38249
---

diff --git a/gl_rmain.c b/gl_rmain.c
index 8375090e..a9e5b783 100644
--- a/gl_rmain.c
+++ b/gl_rmain.c
@@ -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)
diff --git a/gl_textures.c b/gl_textures.c
index 0a3f2cb1..c3cbcf3d 100644
--- a/gl_textures.c
+++ b/gl_textures.c
@@ -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
 	}
 
diff --git a/glquake.h b/glquake.h
index fb7a8335..301b4660 100644
--- 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
diff --git a/r_shadow.c b/r_shadow.c
index fd8830c2..27eeaa41 100644
--- a/r_shadow.c
+++ b/r_shadow.c
@@ -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)
diff --git a/vid_shared.c b/vid_shared.c
index 68428f3e..978a6d3d 100644
--- a/vid_shared.c
+++ b/vid_shared.c
@@ -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)