Spellcaster Studios

Make it happen…

Preprocessor

Today I worked on building a preprocessor for GLSL…

Well, I didn’t exactly built a preprocessor, GLSL has one (contrary to what I understood previously), but it doesn’t work like the Direct3D one. On the D3D one, when I ask him to compile a shader, I give him a series of preprocessor macros and he uses that set. On OpenGL, I have to actually include in the text of the shader the macros so he’ll expand them.

So, basically, what I’ve built is a system to handle this (without screwing up line numbers in case of errors), and to deal with including other files (again, considering the line numbers and such).

screen338

This is the result of compiling conditionally on a #define… The above is with texturing enabled (“#define texture0_enabled true”), below is with that define set to false:

screen339

Now, on the shader I have something like:

in     vec4 fragmentColor;
in    vec2 fragmentUV;

out vec4 color;

void main()
{
    if (texture0_enabled)
    {
        color.rgba=texture(texture0,fragmentUV).rgba*fragmentColor.rgba;
    }
    else
    {
        color.rgba=fragmentColor.rgba;
    }
}

When expanded, it becomes internally something like:

in     vec4 fragmentColor;
in    vec2 fragmentUV;

out vec4 color;

void main()
{
    if (false)
    {
        color.rgba=texture(texture0,fragmentUV).rgba*fragmentColor.rgba;
    }
    else
    {
        color.rgba=fragmentColor.rgba;
    }
}

We know the system will never go into the first branch of the if, but the compiler doesn’t necessarily remove that piece of code, which means that there is a possibility (especially on mobile devices) that it will put in both branches in the compile shader and use some math to shift between one and the other (although it will always select the second one), which is inefficient. This is another place where D3D does a superb job…

Anyway, I have three different solutions to this issue. One is not use an actual if, but use something like:

in     vec4 fragmentColor;
in    vec2 fragmentUV;

out vec4 color;

void main()
{
#if (texture0_enabled)
    color.rgba=texture(texture0,fragmentUV).rgba*fragmentColor.rgba;
#else
    color.rgba=fragmentColor.rgba;
#endif
}

Which is ugly as hell and is harder to work with in normal cases. But after macro expansion, this should behave as expected.

Second, I could build a simple GLSL parser that can detect these cases and remove them… Shouldn’t be that hard, but I have solution 3, which is to use GLSL Optimizer, which is actually part of Unity 3.0+.

Hopefully, that will do all that I require (with some additional bonuses)…

Now listening to “Balls to Picasso” by “Bruce Dickinson”

Link of the Day: I have very fond memories of the ZX Spectrum (well, more accurately, the Timex 2048, but it’s of the same ilk), so this project looks awesome… So remember, Christmas is coming! Smile

Comment