• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Shaders [SOLVED] Shader function causes slowdown

Q

Quackertree

Guest
Hi there!

For my current project, I'm using a shadow shader (code below). The shadow shader has two features; "soft" and "smooth", which are two functions which can run seperately without any issues. However, when trying to combine the two, I run into massive performance issues, even though there should be no need for it.

Shader code (fragment only - vertex is pretty straight-forward):
Code:
varying vec2 v_vTexcoord;
varying vec3 v_vView;
varying vec3 v_vNormal;
varying vec4 v_vScoord;
varying vec4 v_vColour;
varying vec3 v_vPosition;
varying float d_new;

uniform sampler2D shadowMap;

uniform vec2 size;
uniform vec3 cam;

uniform float worldSize_new;
uniform sampler2D colourSurf_new;
uniform float isWorld_new;
uniform vec4 colour_new;

uniform float shadowBlur_new;

const vec3 lightDir_new = vec3(0.1, -0.4, 1.0);

const float pi = 3.1415;
const float n = 4.0;

float vtof(vec3 v)
{
    return v.x*65025.0+v.y*255.0+v.z;
}

float soft(vec2 scoord,vec2 size)
{
    vec2 smooth_ = smoothstep(0.0,1.0,fract(scoord * size+0.5));
    float depth = vtof(texture2D(shadowMap,scoord).rgb);
   
    float depth1 = vtof(texture2D(shadowMap,scoord+vec2(-0.5,-0.5)/size).rgb);
    float light1 = clamp((depth1+(depth1-depth) - v_vScoord.z*65025.0)+8.0,0.0,1.0);
   
    float depth2 = vtof(texture2D(shadowMap,scoord+vec2(0.5,-0.5)/size).rgb);
    float light2 = clamp((depth2+(depth2-depth) - v_vScoord.z*65025.0)+8.0,0.0,1.0);
   
    float depth3 = vtof(texture2D(shadowMap,scoord+vec2(-0.5,0.5)/size).rgb);
    float light3 = clamp((depth3+(depth3-depth) - v_vScoord.z*65025.0)+8.0,0.0,1.0);
   
    float depth4 = vtof(texture2D(shadowMap,scoord+vec2(0.5,0.5)/size).rgb);
    float light4 = clamp((depth4+(depth4-depth) - v_vScoord.z*65025.0)+8.0,0.0,1.0);
    return  mix(mix(light1,light2,smooth_.x),mix(light3,light4,smooth_.x),smooth_.y);
}

float smooth(vec2 scoord,vec2 size)
{
    float total = 0.0;
    for(float i = 0.0;i<2.0;i+=2.0/n)
    {
        vec2 p = vec2(cos((i)*pi),sin((i)*pi))/size;
        total += soft(scoord+p,size);
        p = vec2(cos((i+0.5)*pi),sin((i+0.5)*pi))/size;
        total += soft(scoord+p*2.0,size);
    }
    total /= n*2.0;
    return total;
}

void main()
{   
    vec2 scoord = v_vScoord.xy/v_vScoord.w * vec2(0.5,-0.5) + 0.5;
    float light;
    if(shadowBlur_new == 1.0){light = smooth(scoord,size);}else{light = soft(scoord, size);}
   
    float D = dot(v_vNormal, normalize(lightDir_new));
    float d_ffuse = 0.25 + max(0.0, D);
   
    vec3 texel = vec3(1.0);
    if(isWorld_new == 1.0){texel = (texture2D(colourSurf_new, vec2(v_vPosition.x / worldSize_new, v_vPosition.y / worldSize_new))).rgb;}
   
    gl_FragColor = v_vColour * texture2D(gm_BaseTexture, v_vTexcoord) * vec4(vec3((light*0.5)+0.5) * ((d_new*0.75) + 0.25) * d_ffuse * texel, 1.0) * colour_new;
}
I've been trying to let the user toggle between "soft" and "smooth" by adding a uniform called shadowBlur_new, however, the performance doesn't change when using this function!

When applying the function directly, i.e.: "float light = soft(...)" or "float light = smooth(...)", everything works fine, and soft() runs two times as fast as smooth() (as it should). However, in the current code setup, no matter whether shadowBlur_new is 0 or 1, the performance remains the exact same. The shadows DO change, however, and the toggle between soft and smooth is clearly visible in-game.

I'm starting to feel like this is some kind of GM:S bug, but I wanted to ask here first.

Below is some more code; It's the line of code which submits the "shadowBlur_new":

Code:
if(SHADOW_BLUR){shader_set_uniform_f(SH_SHADOW_BLUR, true);}
else{shader_set_uniform_f(SH_SHADOW_BLUR, false);}
Little sidenote: Trying to do "shader_set_uniform_f(SH_SHADOW_BLUR, SHADOW_BLUR)" will result in a crash saying "invalid argument" whenever SHADOW_BLUR becomes false (aka 0). The way I set up and toggle SHADOW_BLUR is as follows:

Code:
globalvar SHADOW_BLUR;
SHADOW_BLUR = true;

--LATER ON

if(...){SHADOW_BLUR = !SHADOW_BLUR;}
I hope someone around here knows what's going on and can help me solve the issue!

Thanks in advance,

Gavin.
 
Why not make the smooth and soft different shaders?

This is just a hunch so take it with a big grain of salt, but I remember reading somewhere that flow control (if, else) in some way massively slows down shaders. I think the language was something along the lines of... each fragment needs to know that it is executing exactly the same instructions, and the if statement makes that impossible to predict. I would imagine that wouldn't apply when the condition is a uniform, because it will evaluate the same way for every fragment, but then again, I'm obviously pretty unsure about the whole thing.
 
I

icuurd12b42

Guest
1) You cant pass anything but float
1b) if SHADOW_BLUR is a float in the shader you should probably pass 1 and not true for logic's and type's sakes
2) instead of passing what shader type you want why dont you make 2 shaders and decide which one to activate in gml
3) float light; may skip being initialised because the if may fluke out and
4) the else may never trigger

//if(someFloatUniform <0.0) would fluke out in my code
//and so would == 0.0 if I remember, neither if nor else would run
try
if(shadowBlur_new >0.0)
{
light = smooth(scoord,size);
}
else
{
light = soft(scoord, size);
}

and try to refrain using single liners like your if else does
 
I

icuurd12b42

Guest
[EDIT] WTH, I ended up in an entirely different topic quoting an entirely different post. ignore
 
Q

Quackertree

Guest
Why not make the smooth and soft different shaders?

This is just a hunch so take it with a big grain of salt, but I remember reading somewhere that flow control (if, else) in some way massively slows down shaders. I think the language was something along the lines of... each fragment needs to know that it is executing exactly the same instructions, and the if statement makes that impossible to predict. I would imagine that wouldn't apply when the condition is a uniform, because it will evaluate the same way for every fragment, but then again, I'm obviously pretty unsure about the whole thing.
1) You cant pass anything but float
1b) if SHADOW_BLUR is a float in the shader you should probably pass 1 and not true for logic's and type's sakes
2) instead of passing what shader type you want why dont you make 2 shaders and decide which one to activate in gml
3) float light; may skip being initialised because the if may fluke out and
4) the else may never trigger

//if(someFloatUniform <0.0) would fluke out in my code
//and so would == 0.0 if I remember, neither if nor else would run
try
if(shadowBlur_new >0.0)
{
light = smooth(scoord,size);
}
else
{
light = soft(scoord, size);
}

and try to refrain using single liners like your if else does
I somehow never got alerted of these responses... :/

The problem wasn't that the shadows didn't switch; They did just fine. However, the performane didn't seem to change. I seperated the shaders and the issue seemed to persist.

I switched over from GLSL to HLSL and all of a sudden everything was fixed. I still don't get why, but it's fixed now. :)
 
Top