From: havoc Date: Fri, 3 Mar 2006 15:02:56 +0000 (+0000) Subject: now only compiles GLSL shaders on demand, this improves startup times (but causes... X-Git-Tag: xonotic-v0.1.0preview~4263 X-Git-Url: https://git.xonotic.org/?a=commitdiff_plain;h=6f04e228bdc53d529c4255d54690769130247c47;p=xonotic%2Fdarkplaces.git now only compiles GLSL shaders on demand, this improves startup times (but causes some pausing when new combinations occur - which usually only happens on new levels) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6051 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/r_shadow.c b/r_shadow.c index f4b0524a..d6b8a8b1 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -263,6 +263,9 @@ static cubemapinfo_t cubemaps[MAX_CUBEMAPS]; #define SHADERPERMUTATION_GEFORCEFX (1<<6) #define SHADERPERMUTATION_COUNT (1<<7) +// indicates if we have tried compiling this shader permutation yet +qboolean r_shadow_program_compiledlight[SHADERPERMUTATION_COUNT]; +// GLSL program object number, or 0 if compile failed GLhandleARB r_shadow_program_light[SHADERPERMUTATION_COUNT]; void R_Shadow_UncompileWorldLights(void); @@ -454,6 +457,97 @@ const char *builtinshader_light_frag = "}\n" ; +int R_Shadow_CompileShaderPermutation(int permutation) +{ + if (r_shadow_program_compiledlight[permutation]) + return r_shadow_program_light[permutation]; + r_shadow_program_compiledlight[permutation] = true; + char *vertstring, *fragstring; + int vertstrings_count; + int fragstrings_count; + const char *vertstrings_list[SHADERPERMUTATION_COUNT+1]; + const char *fragstrings_list[SHADERPERMUTATION_COUNT+1]; + char permutationname[256]; + vertstring = (char *)FS_LoadFile("glsl/light.vert", tempmempool, false, NULL); + fragstring = (char *)FS_LoadFile("glsl/light.frag", tempmempool, false, NULL); + vertstrings_count = 0; + fragstrings_count = 0; + permutationname[0] = 0; + if (permutation & SHADERPERMUTATION_COLORMAPPING) + { + vertstrings_list[vertstrings_count++] = "#define USECOLORMAPPING\n"; + fragstrings_list[fragstrings_count++] = "#define USECOLORMAPPING\n"; + strlcat(permutationname, " colormapping", sizeof(permutationname)); + } + if (permutation & SHADERPERMUTATION_SPECULAR) + { + vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n"; + fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n"; + strlcat(permutationname, " specular", sizeof(permutationname)); + } + if (permutation & SHADERPERMUTATION_FOG) + { + vertstrings_list[vertstrings_count++] = "#define USEFOG\n"; + fragstrings_list[fragstrings_count++] = "#define USEFOG\n"; + strlcat(permutationname, " fog", sizeof(permutationname)); + } + if (permutation & SHADERPERMUTATION_CUBEFILTER) + { + vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n"; + fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n"; + strlcat(permutationname, " cubefilter", sizeof(permutationname)); + } + if (permutation & SHADERPERMUTATION_OFFSETMAPPING) + { + vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n"; + fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n"; + strlcat(permutationname, " offsetmapping", sizeof(permutationname)); + } + if (permutation & SHADERPERMUTATION_SURFACENORMALIZE) + { + vertstrings_list[vertstrings_count++] = "#define SURFACENORMALIZE\n"; + fragstrings_list[fragstrings_count++] = "#define SURFACENORMALIZE\n"; + strlcat(permutationname, " surfacenormalize", sizeof(permutationname)); + } + if (permutation & SHADERPERMUTATION_GEFORCEFX) + { + vertstrings_list[vertstrings_count++] = "#define GEFORCEFX\n"; + fragstrings_list[fragstrings_count++] = "#define GEFORCEFX\n"; + strlcat(permutationname, " halffloat", sizeof(permutationname)); + } + vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert; + fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag; + r_shadow_program_light[permutation] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list); + if (r_shadow_program_light[permutation]) + { + qglUseProgramObjectARB(r_shadow_program_light[permutation]); + qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_Normal"), 0);CHECKGLERROR + qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_Color"), 1);CHECKGLERROR + if (permutation & SHADERPERMUTATION_SPECULAR) + { + qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_Gloss"), 2);CHECKGLERROR + } + if (permutation & SHADERPERMUTATION_CUBEFILTER) + { + qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_Cube"), 3);CHECKGLERROR + } + if (permutation & SHADERPERMUTATION_FOG) + { + qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_FogMask"), 4);CHECKGLERROR + } + qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_Pants"), 5);CHECKGLERROR + qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[permutation], "Texture_Shirt"), 6);CHECKGLERROR + qglUseProgramObjectARB(0); + } + else + Con_Printf("permutation%s failed for shader %s, some features may not work properly!\n", permutationname, "glsl/light"); + if (fragstring) + Mem_Free(fragstring); + if (vertstring) + Mem_Free(vertstring); + return r_shadow_program_light[permutation]; +} + void r_shadow_start(void) { int i; @@ -486,98 +580,9 @@ void r_shadow_start(void) r_shadow_buffer_surfacepvs = NULL; r_shadow_buffer_surfacelist = NULL; for (i = 0;i < SHADERPERMUTATION_COUNT;i++) + { + r_shadow_program_compiledlight[i] = false; r_shadow_program_light[i] = 0; - if (gl_support_fragment_shader) - { - char *vertstring, *fragstring; - int vertstrings_count; - int fragstrings_count; - const char *vertstrings_list[SHADERPERMUTATION_COUNT+1]; - const char *fragstrings_list[SHADERPERMUTATION_COUNT+1]; - vertstring = (char *)FS_LoadFile("glsl/light.vert", tempmempool, false, NULL); - fragstring = (char *)FS_LoadFile("glsl/light.frag", tempmempool, false, NULL); - for (i = 0;i < SHADERPERMUTATION_COUNT;i++) - { - char permutationname[256]; - vertstrings_count = 0; - fragstrings_count = 0; - permutationname[0] = 0; - if (i & SHADERPERMUTATION_COLORMAPPING) - { - vertstrings_list[vertstrings_count++] = "#define USECOLORMAPPING\n"; - fragstrings_list[fragstrings_count++] = "#define USECOLORMAPPING\n"; - strlcat(permutationname, " colormapping", sizeof(permutationname)); - } - if (i & SHADERPERMUTATION_SPECULAR) - { - vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n"; - fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n"; - strlcat(permutationname, " specular", sizeof(permutationname)); - } - if (i & SHADERPERMUTATION_FOG) - { - vertstrings_list[vertstrings_count++] = "#define USEFOG\n"; - fragstrings_list[fragstrings_count++] = "#define USEFOG\n"; - strlcat(permutationname, " fog", sizeof(permutationname)); - } - if (i & SHADERPERMUTATION_CUBEFILTER) - { - vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n"; - fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n"; - strlcat(permutationname, " cubefilter", sizeof(permutationname)); - } - if (i & SHADERPERMUTATION_OFFSETMAPPING) - { - vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n"; - fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n"; - strlcat(permutationname, " offsetmapping", sizeof(permutationname)); - } - if (i & SHADERPERMUTATION_SURFACENORMALIZE) - { - vertstrings_list[vertstrings_count++] = "#define SURFACENORMALIZE\n"; - fragstrings_list[fragstrings_count++] = "#define SURFACENORMALIZE\n"; - strlcat(permutationname, " surfacenormalize", sizeof(permutationname)); - } - if (i & SHADERPERMUTATION_GEFORCEFX) - { - // if the extension does not exist, don't try to compile it - if (!gl_support_half_float) - continue; - vertstrings_list[vertstrings_count++] = "#define GEFORCEFX\n"; - fragstrings_list[fragstrings_count++] = "#define GEFORCEFX\n"; - strlcat(permutationname, " halffloat", sizeof(permutationname)); - } - vertstrings_list[vertstrings_count++] = vertstring ? vertstring : builtinshader_light_vert; - fragstrings_list[fragstrings_count++] = fragstring ? fragstring : builtinshader_light_frag; - r_shadow_program_light[i] = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list); - if (!r_shadow_program_light[i]) - { - Con_Printf("permutation%s failed for shader %s, some features may not work properly!\n", permutationname, "glsl/light"); - continue; - } - qglUseProgramObjectARB(r_shadow_program_light[i]); - qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Normal"), 0);CHECKGLERROR - qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Color"), 1);CHECKGLERROR - if (i & SHADERPERMUTATION_SPECULAR) - { - qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Gloss"), 2);CHECKGLERROR - } - if (i & SHADERPERMUTATION_CUBEFILTER) - { - qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Cube"), 3);CHECKGLERROR - } - if (i & SHADERPERMUTATION_FOG) - { - qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_FogMask"), 4);CHECKGLERROR - } - qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Pants"), 5);CHECKGLERROR - qglUniform1iARB(qglGetUniformLocationARB(r_shadow_program_light[i], "Texture_Shirt"), 6);CHECKGLERROR - } - qglUseProgramObjectARB(0); - if (fragstring) - Mem_Free(fragstring); - if (vertstring) - Mem_Free(vertstring); } } @@ -1143,7 +1148,7 @@ void R_Shadow_RenderMode_Begin(void) else r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL; - if (r_shadow_glsl.integer && r_shadow_program_light[0]) + if (r_shadow_glsl.integer && gl_support_fragment_shader) r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL; else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil) r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3; @@ -1617,24 +1622,45 @@ static void R_Shadow_RenderSurfacesLighting_Light_GLSL(const entity_render_t *en // minimum features necessary to avoid wasting rendering time in the // fragment shader on features that are not being used r_shadow_lightpermutation = 0; - // only add a feature to the permutation if that permutation exists - // (otherwise it might end up not using a shader at all, which looks - // worse than using less features) - if (fogenabled && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_FOG]) + if (fogenabled) r_shadow_lightpermutation |= SHADERPERMUTATION_FOG; - if ((dopants || doshirt) && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_COLORMAPPING]) + if ((dopants || doshirt)) r_shadow_lightpermutation |= SHADERPERMUTATION_COLORMAPPING; - if (specularscale > 0 && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SPECULAR]) + if (specularscale > 0) r_shadow_lightpermutation |= SHADERPERMUTATION_SPECULAR; - if (r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_CUBEFILTER]) + if (r_shadow_rtlight->currentcubemap != r_texture_whitecube) r_shadow_lightpermutation |= SHADERPERMUTATION_CUBEFILTER; - if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_OFFSETMAPPING]) + if (r_shadow_glsl_offsetmapping.integer) r_shadow_lightpermutation |= SHADERPERMUTATION_OFFSETMAPPING; - if (r_shadow_glsl_surfacenormalize.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_SURFACENORMALIZE]) + if (r_shadow_glsl_surfacenormalize.integer) r_shadow_lightpermutation |= SHADERPERMUTATION_SURFACENORMALIZE; - if (r_shadow_glsl_usehalffloat.integer && r_shadow_program_light[r_shadow_lightpermutation | SHADERPERMUTATION_GEFORCEFX]) + if (r_shadow_glsl_usehalffloat.integer) r_shadow_lightpermutation |= SHADERPERMUTATION_GEFORCEFX; r_shadow_lightprog = r_shadow_program_light[r_shadow_lightpermutation]; + if (!r_shadow_lightprog) + { + if (!r_shadow_program_compiledlight[r_shadow_lightpermutation]) + r_shadow_lightprog = R_Shadow_CompileShaderPermutation(r_shadow_lightpermutation); + if (!r_shadow_lightprog) + { + // remove features until we find a valid permutation + int i; + for (i = SHADERPERMUTATION_COUNT-1;;i>>=1) + { + // reduce i more quickly whenever it would not remove any bits + if (r_shadow_lightpermutation < i) + continue; + r_shadow_lightpermutation &= i; + if (!r_shadow_program_compiledlight[r_shadow_lightpermutation]) + R_Shadow_CompileShaderPermutation(r_shadow_lightpermutation); + r_shadow_lightprog = r_shadow_program_light[r_shadow_lightpermutation]; + if (r_shadow_lightprog) + break; + if (!i) + return; // utterly failed + } + } + } qglUseProgramObjectARB(r_shadow_lightprog);CHECKGLERROR R_Mesh_TexMatrix(0, &texture->currenttexmatrix); R_Mesh_TexMatrix(3, &r_shadow_entitytolight);