• 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!

Performace issue with blur shader

streng

Member
Hi I’m facing a huge performance drop when I use blur shader on the layer.

If using shader only for text in standard draw event, then working fine, but when I using it on layer respectively 9 different layers a massive slowdown occur. The frame drop is from 60 to 10 FPS. Real FPS don’t drop it runs around 4000 – meaning that a shader is the issue, because real FPS counting only CPU steps.

Here is my code:

Shader vertex:
Code:
attribute vec3 in_Position;                  // (x,y,z)
//attribute vec3 in_Normal;                  // (x,y,z)     unused in this shader.   
attribute vec4 in_Colour;                    // (r,g,b,a)
attribute vec2 in_TextureCoord;              // (u,v)

varying vec2 v_vTexcoord;
varying vec4 v_vColour;

void main()
{
    vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0);
    gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;
    
    v_vColour = in_Colour;
    v_vTexcoord = in_TextureCoord;
}
Shader fragment:
Code:
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform vec3 size;//width,height,radius

const int Quality = 8;
const int Directions = 16;
const float Pi = 6.28318530718;//pi * 2

void main()
{
    vec2 radius = size.z/size.xy;
    vec4 Color = texture2D( gm_BaseTexture, v_vTexcoord);
    for( float d=0.0;d<Pi;d+=Pi/float(Directions) )
    {
        for( float i=1.0/float(Quality);i<=1.0;i+=1.0/float(Quality) )
        {
                Color += texture2D( gm_BaseTexture, v_vTexcoord+vec2(cos(d),sin(d))*radius*i);
        }
    }
    Color /= float(Quality)*float(Directions)+1.0;
    gl_FragColor =  Color *  v_vColour;
}
Then in my control object using shader activation on layer like this:
Code:
//initialise pause blur shader
layer_script_begin("Backgrounds", scr_BlurPause_Start);
layer_script_end("Backgrounds", scr_Blur_End);
layer_script_begin("Backgrounds_1", scr_BlurPause_Start);
layer_script_end("Backgrounds_1", scr_Blur_End);
layer_script_begin("Backgrounds_2", scr_BlurPause_Start);
layer_script_end("Backgrounds_2", scr_Blur_End);
layer_script_begin("Backgrounds_3", scr_BlurPause_Start);
layer_script_end("Backgrounds_3", scr_Blur_End);
layer_script_begin("Backgrounds_4", scr_BlurPause_Start);
layer_script_end("Backgrounds_4", scr_Blur_End);
layer_script_begin("Backgrounds_5", scr_BlurPause_Start);
layer_script_end("Backgrounds_5", scr_Blur_End);
layer_script_begin("Backgrounds_6", scr_BlurPause_Start);
layer_script_end("Backgrounds_6", scr_Blur_End);
layer_script_begin("Backgrounds_7", scr_BlurPause_Start);
layer_script_end("Backgrounds_7", scr_Blur_End);
layer_script_begin("Instances", scr_BlurPause_Start);
layer_script_end("Instances", scr_Blur_End);
And the scripts which handle shader activation/deactivation
scr_BlurPause_Start
Code:
if event_type == ev_draw
   {

        if instance_exists(obj_controller_pause)
            {
                if (obj_controller_pause.pause == true)
                    {
    
                        usize = shader_get_uniform(shd_gausian,"size");//uniform for width, height, radius
                        shader_set(shd_gausian)
                        shader_set_uniform_f(usize,1920,1080,1.75)//width,height,radius
                    }
            }   
        else if instance_exists(o_control)
            {   
                
                if (o_control.victory != -1)
            
                    {
                        usize = shader_get_uniform(shd_gausian,"size");//uniform for width, height, radius
                        shader_set(shd_gausian)
                        shader_set_uniform_f(usize,1920,1080,stage_finish.backround_alpha*4)//width,height,radius
                    
                    }   
            }
    }
scr_Blur_End
Code:
if event_type == ev_draw
   {
shader_reset()
}
Is there any way how to optimize it?
Is it a bad way to use shader on such many layers?


I just want to achieve, if player pause button, i want to blur all objects and backgrounds except the pause object, which work but at the cost of performance, so is there any other way how to do it better?


Thank you for your answers
 
You're doing 129 texture samples, and 256 trig functions per fragment. There are two main things you can do to improve this situation. 1) Draw to a downscaled surface to reduce the number of fragments that run this shader. 2) Consider breaking up the blur into two phases, horizontal, and vertical. With the same level of quality you can thus reduce the number of samples from 129 per fragment to something more like 34.
 
Do you really absolutely need to draw each background blurred or could you draw all backgrounds onto a surface and then draw that blurred? That could also be a performance boost.
But the main two general improvements on blur performance are what flyingsaucerinvasion already mentioned.

If you want to learn more about blurring with shaders I made a video tutorial series on shaders and video 15a to 15e are about getting from a horribly slow to a very performant blur shader. But still if you draw every background separately by the blur shader you'll still have performance issues - especially on odler machines or mobiles:
https://www.youtube.com/playlist?list=PL0kTSdIvQNCNE-BDKOlYu628AalMmXy_P
 

streng

Member
The reason, why I’m trying to draw blur shader on 9 different layers is that, many of the layers are background tiled layer which are responsible for parallax effect. If I draw these sprites not on the background layer, but in the standard draw event with correct order, I will be facing issues with tiling, but it can be probably fixed in code.

I also tried draw background as surface but without success. Maybe I just don’t know how to properly using surface. Can you point me to right direction using surfaces on background?

Also, thanks for attached link, I will watch the video.
 
Top