diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index 6bb8503f7f..9c397ec4fc 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -546,6 +546,11 @@ static std::string GenEngineConstants() { AddDefine( str, "r_ShowParallelShadowSplits", 1 ); } + if ( r_dynamicLight->integer ) + { + AddDefine( str, "r_dynamicLight", r_dynamicLight->integer ); + } + if ( r_precomputedLighting->integer ) AddDefine( str, "r_precomputedLighting", 1 ); @@ -774,6 +779,11 @@ bool GLShaderManager::buildPermutation( GLShader *shader, int macroIndex, int de if( !baseShader->VS || !baseShader->FS ) CompileGPUShaders( shader, baseShader, compileMacros ); + if ( baseShader->unusedPermutation ) + { + return true; + } + glAttachShader( shaderProgram->program, baseShader->VS ); glAttachShader( shaderProgram->program, _deformShaders[ deformIndex ] ); glAttachShader( shaderProgram->program, baseShader->FS ); @@ -806,6 +816,42 @@ void GLShaderManager::buildAll() while ( !_shaderBuildQueue.empty() ) { GLShader& shader = *_shaderBuildQueue.front(); + + std::string shaderName = shader.GetMainShaderName(); + + /* NOTE: motionblur is enabled by cg_motionblur which is a client cvar + so we have to build it in all cases. */ + if ( shaderName == "forwardLighting" && r_dynamicLight->integer != 1 ) + { + _shaderBuildQueue.pop(); + continue; + } + else if ( shaderName == "reflection_CB" && r_reflectionMapping->integer == 0 ) + { + _shaderBuildQueue.pop(); + continue; + } + else if ( shaderName == "liquid" && r_liquidMapping->integer == 0 ) + { + _shaderBuildQueue.pop(); + continue; + } + else if ( shaderName == "heatHaze" && r_heatHaze->integer == 0 ) + { + _shaderBuildQueue.pop(); + continue; + } + else if ( shaderName == "fxaa" && r_FXAA->integer == 0 ) + { + _shaderBuildQueue.pop(); + continue; + } + else if ( shaderName == "bloom" && r_bloom->integer != 1 ) + { + _shaderBuildQueue.pop(); + continue; + } + size_t numPermutations = static_cast(1) << shader.GetNumOfCompiledMacros(); size_t i; @@ -990,6 +1036,7 @@ void GLShaderManager::CompileGPUShaders( GLShader *shader, shaderProgram_t *prog const char **compileMacrosP = &compileMacros_; char *token; + // Do not build shader macro permutations that will never be used. while ( true ) { token = COM_ParseExt2( compileMacrosP, false ); @@ -999,10 +1046,54 @@ void GLShaderManager::CompileGPUShaders( GLShader *shader, shaderProgram_t *prog break; } + /* FIXME: add this test: ( strcmp( token, "USE_TCGEN_LIGHTMAP" ) == 0 && r_lightMapping->integer == 0 ) + when lightmaps are never used when lightmapping is disabled + see https://github.com/DaemonEngine/Daemon/issues/296 is fixed */ + if ( strcmp( token, "USE_LIGHT_MAPPING" ) == 0 && r_vertexLighting->integer != 0 ) + { + program->unusedPermutation = true; + return; + } + else if ( strcmp( token, "USE_NORMAL_MAPPING" ) == 0 && r_normalMapping->integer == 0 ) + { + program->unusedPermutation = true; + return; + } + else if ( strcmp( token, "USE_DELUXE_MAPPING" ) == 0 && r_deluxeMapping->integer == 0 ) + { + program->unusedPermutation = true; + return; + } + else if ( strcmp( token, "USE_PHYSICAL_MAPPING" ) == 0 && r_physicalMapping->integer == 0 ) + { + program->unusedPermutation = true; + return; + } + /* FIXME: add to the following test: && r_physicalMapping->integer == 0 + when reflective specular is implemented for physical mapping too + see https://github.com/DaemonEngine/Daemon/issues/355 */ + else if ( strcmp( token, "USE_REFLECTIVE_SPECULAR" ) == 0 && r_specularMapping->integer == 0 ) + { + program->unusedPermutation = true; + return; + } + else if ( strcmp( token, "USE_RELIEF_MAPPING" ) == 0 && r_reliefMapping->integer == 0 ) + { + program->unusedPermutation = true; + return; + } + else if ( strcmp( token, "USE_HEIGHTMAP_IN_NORMALMAP" ) == 0 && r_reliefMapping->integer == 0 && r_normalMapping->integer == 0 ) + { + program->unusedPermutation = true; + return; + } + macrosString += Str::Format( "#ifndef %s\n#define %s 1\n#endif\n", token, token ); } } + program->unusedPermutation = false; + Log::Debug( "building %s shader permutation with macro: %s", shader->GetMainShaderName(), compileMacros.empty() ? "none" : compileMacros ); @@ -1031,6 +1122,11 @@ void GLShaderManager::CompileAndLinkGPUShaderProgram( GLShader *shader, shaderPr { GLShaderManager::CompileGPUShaders( shader, program, compileMacros ); + if ( program->unusedPermutation ) + { + return; + } + glAttachShader( program->program, program->VS ); glAttachShader( program->program, _deformShaders[ deformIndex ] ); glAttachShader( program->program, program->FS ); @@ -1205,7 +1301,7 @@ bool GLCompileMacro_USE_REFLECTIVE_SPECULAR::HasConflictingMacros( size_t permut { for (const GLCompileMacro* macro : macros) { - if ( ( permutation & macro->GetBit() ) != 0 && (macro->GetType() == USE_PHYSICAL_SHADING || macro->GetType() == USE_VERTEX_SPRITE) ) + if ( ( permutation & macro->GetBit() ) != 0 && (macro->GetType() == USE_PHYSICAL_MAPPING || macro->GetType() == USE_VERTEX_SPRITE) ) { //Log::Notice("conflicting macro! canceling '%s' vs. '%s'", GetName(), macro->GetName()); return true; @@ -1490,7 +1586,7 @@ GLShader_lightMapping::GLShader_lightMapping( GLShaderManager *manager ) : GLCompileMacro_USE_HEIGHTMAP_IN_NORMALMAP( this ), GLCompileMacro_USE_RELIEF_MAPPING( this ), GLCompileMacro_USE_REFLECTIVE_SPECULAR( this ), - GLCompileMacro_USE_PHYSICAL_SHADING( this ) + GLCompileMacro_USE_PHYSICAL_MAPPING( this ) { } diff --git a/src/engine/renderer/gl_shader.h b/src/engine/renderer/gl_shader.h index ea2e6c1b41..bb90ae6624 100644 --- a/src/engine/renderer/gl_shader.h +++ b/src/engine/renderer/gl_shader.h @@ -792,7 +792,7 @@ class GLCompileMacro USE_SHADOWING, LIGHT_DIRECTIONAL, USE_DEPTH_FADE, - USE_PHYSICAL_SHADING, + USE_PHYSICAL_MAPPING, USE_ALPHA_TESTING }; @@ -1215,23 +1215,23 @@ class GLCompileMacro_USE_DEPTH_FADE : } }; -class GLCompileMacro_USE_PHYSICAL_SHADING : +class GLCompileMacro_USE_PHYSICAL_MAPPING : GLCompileMacro { public: - GLCompileMacro_USE_PHYSICAL_SHADING( GLShader *shader ) : + GLCompileMacro_USE_PHYSICAL_MAPPING( GLShader *shader ) : GLCompileMacro( shader ) { } const char *GetName() const { - return "USE_PHYSICAL_SHADING"; + return "USE_PHYSICAL_MAPPING"; } EGLCompileMacro GetType() const { - return USE_PHYSICAL_SHADING; + return USE_PHYSICAL_MAPPING; } void SetPhysicalShading( bool enable ) @@ -2247,7 +2247,7 @@ class GLShader_lightMapping : public GLCompileMacro_USE_HEIGHTMAP_IN_NORMALMAP, public GLCompileMacro_USE_RELIEF_MAPPING, public GLCompileMacro_USE_REFLECTIVE_SPECULAR, - public GLCompileMacro_USE_PHYSICAL_SHADING + public GLCompileMacro_USE_PHYSICAL_MAPPING { public: GLShader_lightMapping( GLShaderManager *manager ); diff --git a/src/engine/renderer/glsl_source/computeLight_fp.glsl b/src/engine/renderer/glsl_source/computeLight_fp.glsl index 7843001f06..a338055dd5 100644 --- a/src/engine/renderer/glsl_source/computeLight_fp.glsl +++ b/src/engine/renderer/glsl_source/computeLight_fp.glsl @@ -27,13 +27,13 @@ uniform samplerCube u_EnvironmentMap1; uniform float u_EnvironmentInterpolation; #endif // USE_REFLECTIVE_SPECULAR +#ifdef HAVE_ARB_uniform_buffer_object struct light { vec4 center_radius; vec4 color_type; vec4 direction_angle; }; -#ifdef HAVE_ARB_uniform_buffer_object layout(std140) uniform u_Lights { light lights[ MAX_REF_LIGHTS ]; }; @@ -67,9 +67,12 @@ void computeLight( vec3 lightDir, vec3 normal, vec3 viewDir, vec3 lightColor, vec4 diffuseColor, vec4 materialColor, inout vec4 color ) { vec3 H = normalize( lightDir + viewDir ); + +#if defined(USE_PHYSICAL_MAPPING) || defined(r_specularMapping) float NdotH = clamp( dot( normal, H ), 0.0, 1.0 ); +#endif // USE_PHYSICAL_MAPPING || r_specularMapping -#if defined(r_physicalMapping) && defined(USE_PHYSICAL_SHADING) +#if defined(USE_PHYSICAL_MAPPING) // Daemon PBR packing defaults to ORM like glTF 2.0 defines // https://www.khronos.org/blog/art-pipeline-for-gltf // > ORM texture for Occlusion, Roughness, and Metallic @@ -103,7 +106,7 @@ void computeLight( vec3 lightDir, vec3 normal, vec3 viewDir, vec3 lightColor, color.rgb += lightColor.rgb * (1.0 - metalness) * NdotL * diffuseColor.rgb; color.rgb += lightColor.rgb * vec3((D * F * G) / (4.0 * NdotV)); color.a = mix(diffuseColor.a, 1.0, FexpNV); -#else // !r_physicalMapping || !USE_PHYSICAL_SHADING +#else // !USE_PHYSICAL_MAPPING float NdotL = dot( normal, lightDir ); #if defined(r_HalfLambertLighting) // http://developer.valvesoftware.com/wiki/Half_Lambert @@ -124,10 +127,10 @@ void computeLight( vec3 lightDir, vec3 normal, vec3 viewDir, vec3 lightColor, #endif // USE_REFLECTIVE_SPECULAR color.rgb += diffuseColor.rgb * lightColor.rgb * NdotL; -#if defined(r_specularMapping) && !defined(USE_PHYSICAL_SHADING) +#if defined(r_specularMapping) color.rgb += materialColor.rgb * lightColor.rgb * pow( NdotH, u_SpecularExponent.x * materialColor.a + u_SpecularExponent.y) * r_SpecularScale; -#endif // r_specularMapping && !USE_PHYSICAL_SHADING& -#endif // !r_physicalMapping || !USE_PHYSICAL_SHADING +#endif // r_specularMapping +#endif // !USE_PHYSICAL_MAPPING } #if defined(TEXTURE_INTEGER) @@ -159,6 +162,7 @@ int nextIdx( inout idxs_t idxs ) { const int numLayers = MAX_REF_LIGHTS / 256; +#if defined(r_dynamicLight) void computeDLight( int idx, vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, vec4 material, inout vec4 color ) { vec4 center_radius = GetLight( idx, center_radius ); @@ -231,3 +235,4 @@ void computeDLights( vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, vec4 mater } #endif } +#endif diff --git a/src/engine/renderer/glsl_source/forwardLighting_fp.glsl b/src/engine/renderer/glsl_source/forwardLighting_fp.glsl index 3e5a635c4d..a5219e9c81 100644 --- a/src/engine/renderer/glsl_source/forwardLighting_fp.glsl +++ b/src/engine/renderer/glsl_source/forwardLighting_fp.glsl @@ -975,13 +975,13 @@ void main() } diffuse.rgb *= u_LightColor * NL; -#if !defined(USE_PHYSICAL_SHADING) +#if !defined(USE_PHYSICAL_MAPPING) #if defined(r_specularMapping) // compute the specular term vec4 spec = texture2D(u_MaterialMap, texCoords).rgba; vec3 specular = spec.rgb * u_LightColor * pow(clamp(dot(normal, H), 0.0, 1.0), u_SpecularExponent.x * spec.a + u_SpecularExponent.y) * r_SpecularScale; #endif // r_specularMapping -#endif // !USE_PHYSICAL_SHADING +#endif // !USE_PHYSICAL_MAPPING // compute light attenuation #if defined(LIGHT_PROJ) @@ -1000,11 +1000,11 @@ void main() // compute final color vec4 color = diffuse; -#if !defined(USE_PHYSICAL_SHADING) +#if !defined(USE_PHYSICAL_MAPPING) #if defined(r_specularMapping) color.rgb += specular; #endif // r_specularMapping -#endif // !USE_PHYSICAL_SHADING +#endif // !USE_PHYSICAL_MAPPING #if !defined(LIGHT_DIRECTIONAL) color.rgb *= attenuationXY; diff --git a/src/engine/renderer/glsl_source/lightMapping_fp.glsl b/src/engine/renderer/glsl_source/lightMapping_fp.glsl index 651d0777a6..72ca1755f1 100644 --- a/src/engine/renderer/glsl_source/lightMapping_fp.glsl +++ b/src/engine/renderer/glsl_source/lightMapping_fp.glsl @@ -181,8 +181,10 @@ void main() computeLight(lightDir, normal, viewDir, lightColor, diffuse, material, color); #endif - // Blend dynamic lights. - computeDLights(var_Position, normal, viewDir, diffuse, material, color); + #if defined(r_dynamicLight) + // Blend dynamic lights. + computeDLights(var_Position, normal, viewDir, diffuse, material, color); + #endif // Add Rim Lighting to highlight the edges on model entities. #if defined(r_RimLighting) && !defined(USE_BSP_SURFACE) && !defined(USE_LIGHT_MAPPING) diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index 9c880a2521..497d75fe21 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -1073,7 +1073,7 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p r_precomputedLighting = ri.Cvar_Get( "r_precomputedLighting", "1", CVAR_LATCH ); r_vertexLighting = ri.Cvar_Get( "r_vertexLighting", "0", CVAR_LATCH | CVAR_ARCHIVE ); r_exportTextures = ri.Cvar_Get( "r_exportTextures", "0", 0 ); - r_heatHaze = ri.Cvar_Get( "r_heatHaze", "1", 0 ); + r_heatHaze = ri.Cvar_Get( "r_heatHaze", "1", CVAR_LATCH | CVAR_ARCHIVE ); r_noMarksOnTrisurfs = ri.Cvar_Get( "r_noMarksOnTrisurfs", "1", CVAR_CHEAT ); r_lazyShaders = ri.Cvar_Get( "r_lazyShaders", "0", 0 ); @@ -1131,11 +1131,11 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p r_printShaders = ri.Cvar_Get( "r_printShaders", "0", 0 ); - r_bloom = ri.Cvar_Get( "r_bloom", "0", CVAR_ARCHIVE ); + r_bloom = ri.Cvar_Get( "r_bloom", "0", CVAR_LATCH | CVAR_ARCHIVE ); r_bloomBlur = ri.Cvar_Get( "r_bloomBlur", "1.0", CVAR_CHEAT ); r_bloomPasses = ri.Cvar_Get( "r_bloomPasses", "2", CVAR_CHEAT ); - r_FXAA = ri.Cvar_Get( "r_FXAA", "0", 0 ); - r_ssao = ri.Cvar_Get( "r_ssao", "0", CVAR_LATCH ); + r_FXAA = ri.Cvar_Get( "r_FXAA", "0", CVAR_LATCH | CVAR_ARCHIVE ); + r_ssao = ri.Cvar_Get( "r_ssao", "0", CVAR_LATCH | CVAR_ARCHIVE ); // temporary variables that can change at any time r_showImages = ri.Cvar_Get( "r_showImages", "0", CVAR_TEMP ); @@ -1148,7 +1148,7 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p r_noLightVisCull = ri.Cvar_Get( "r_noLightVisCull", "0", CVAR_CHEAT ); r_noInteractionSort = ri.Cvar_Get( "r_noInteractionSort", "0", CVAR_CHEAT ); - r_dynamicLight = ri.Cvar_Get( "r_dynamicLight", "2", CVAR_ARCHIVE ); + r_dynamicLight = ri.Cvar_Get( "r_dynamicLight", "2", CVAR_LATCH | CVAR_ARCHIVE ); r_staticLight = ri.Cvar_Get( "r_staticLight", "2", CVAR_ARCHIVE ); r_drawworld = ri.Cvar_Get( "r_drawworld", "1", CVAR_CHEAT ); r_portalOnly = ri.Cvar_Get( "r_portalOnly", "0", CVAR_CHEAT ); @@ -1187,14 +1187,14 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p r_normalScale = ri.Cvar_Get( "r_normalScale", "1.0", CVAR_ARCHIVE ); r_normalMapping = ri.Cvar_Get( "r_normalMapping", "1", CVAR_LATCH | CVAR_ARCHIVE ); r_highQualityNormalMapping = ri.Cvar_Get( "r_highQualityNormalMapping", "0", CVAR_LATCH ); - r_liquidMapping = ri.Cvar_Get( "r_liquidMapping", "0", CVAR_LATCH ); + r_liquidMapping = ri.Cvar_Get( "r_liquidMapping", "0", CVAR_LATCH | CVAR_ARCHIVE ); r_reliefDepthScale = ri.Cvar_Get( "r_reliefDepthScale", "0.03", CVAR_CHEAT ); r_reliefMapping = ri.Cvar_Get( "r_reliefMapping", "0", CVAR_LATCH | CVAR_ARCHIVE ); r_glowMapping = ri.Cvar_Get( "r_glowMapping", "1", CVAR_LATCH ); - r_reflectionMapping = ri.Cvar_Get( "r_reflectionMapping", "0", CVAR_CHEAT ); + r_reflectionMapping = ri.Cvar_Get( "r_reflectionMapping", "0", CVAR_LATCH | CVAR_ARCHIVE ); r_wrapAroundLighting = ri.Cvar_Get( "r_wrapAroundLighting", "0.7", CVAR_CHEAT | CVAR_LATCH ); - r_halfLambertLighting = ri.Cvar_Get( "r_halfLambertLighting", "1", CVAR_CHEAT | CVAR_LATCH ); + r_halfLambertLighting = ri.Cvar_Get( "r_halfLambertLighting", "1", CVAR_LATCH | CVAR_ARCHIVE ); r_rimLighting = ri.Cvar_Get( "r_rimLighting", "0", CVAR_LATCH | CVAR_ARCHIVE ); r_rimExponent = ri.Cvar_Get( "r_rimExponent", "3", CVAR_CHEAT | CVAR_LATCH ); AssertCvarRange( r_rimExponent, 0.5, 8.0, false ); diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 4fef98ec13..873f9e3626 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -1372,6 +1372,11 @@ static inline void halfToFloat( const f16vec4_t in, vec4_t out ) // GLSL vertex and one GLSL fragment shader struct shaderProgram_t { + /* If this shader program permutation implements a disabled feature, + it will not be built. This boolean makes possible to ignore such + programs at link time. */ + bool unusedPermutation; + GLuint program; GLuint VS, FS; uint32_t attribs; // vertex array attributes