Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have been struggling to implement a simple linear motion blur effect on mobile (Android, OpenGLES 2.0) but it just seems to destroy my framerate.

I'm rendering to texture (FBO) then applying a fragment shader with a blur function that looks like this (with just some hard coded values for testing):

vec4 motionBlur(sampler2D color, vec2 uv, float intensity)
{
    vec2 speed = vec2(0.05, 0.0);
    vec2 offset = intensity * speed;
    vec3 c = vec3(0.);
    float inc = 0.1;
    float weight = 0.;
    for (float i = 0.; i <= 1.; i += inc)
    {
        c += texture2D(color, uv + i * offset).rgb;
        weight += 1.;
    }
    c /= weight;
    return vec4(c, 1.);
}

Called with (for example):

gl_FragColor = motionBlur(u_Texture, v_TexCoordinate.xy, 0.2);

This sends my frame rate from 60fps to 5fps.

Is this even plausible on a mobile device? I have a 2012 Galaxy Nexus (PowerVR SGX540 GPU).

I'm wondering if it's just too much for a little mobile, or whether I'm doing something stupidly wrong in the shader.

Any ideas? Anyone successfully implemented a motion blur on mobile?

share|improve this question
    
Motion blur generally tends to be an intensive task for desktop GPUs so I'd assume its just a little much for mobile GPUs. I think thtat doesn't mean its impossible you just might have to adjust your methods. –  Digital Architect Mar 24 '13 at 7:45
1  
That is 10 texture lookups, with a loop, per pixel, and I suggest you try variants of that to profile where the slowdown is coming from. Loop only 5, is it twice as fast? Unroll the loop, see what changes. Maybe source texture size isn't optimal, change that. Etc... –  Patrick Hughes Mar 24 '13 at 15:58
    
@PatrickHughes Yeah I tried that, somehow even looping only once or twice the best I get is 10fps... Almost like it's hitting some sort of hard limit. –  Jason Mar 25 '13 at 8:09
    
@DigitalArchitect A comparable shader running on a desktop GPU (for much higher resolution) yields a frame cost of <0.5 ms. Although the GPU on mobile is obviously a lot less powerful, the resolution is also a lot less. But perhaps it's still too much for the little GPU to deal with. –  Jason Mar 25 '13 at 8:29
add comment

2 Answers 2

So it looks like the cause of this is simply a limitation in the PowerVR GPU used by this, (and many other) devices.

From the "POWERVR Post Processing Effects Development Recommendations"

It is important that the texture coordinates, which are required for the texture lookups in the pixel shader, have to be calculated in the vertex shader or have to be passed as uniform shader variables in order to avoid dependant texture reads. Although these are supported, they incur a substantial performance hit. Doing no dependent texture reads means that the texture sampling hardware can fetch the texels sooner and hide the latency of accessing memory.

So it looks like the texture coordinates for the blur need to be pre-calculated in the vertex shader and passed to the fragment shader. Not sure exactly how to do this, but I'll give it a go.

share|improve this answer
    
So quick update. Even this solution is not enough unfortunately. Following the example here: xissburg.com/faster-gaussian-blur-in-glsl I still get only around 20fps. Reducing the samples to around 4 (from 14) I get 30fps which is better but still a big drop from 60. Looks like 2013 is not the year for post processing shader effects on mobile. Check back in 2 years. –  Jason Mar 26 '13 at 6:14
    
My guess is that the tile based deferred rendering architecture of the mobile GPUs has a lot to do with why it's such a performance hit. –  Tetrad Mar 26 '13 at 7:42
    
@Tetrad You might be right. Tinkering with the frame buffer might be invalidating the cache. On that basis it may actually be faster to perform multiple draw operations (to simulate blur). It seems counter intuitive but multiple draw calls should take full advantage of deferred rendering even though they'll be a performance hit for the actual draw call. Of course this is likely to look pretty terrible. –  Jason Mar 26 '13 at 16:01
add comment

That shader you have is pretty simple so I would be surprised if the framerate tanked that hard, maybe its the use of a FBO that is problematic. What happens to your FPS when you let this motion blur shader just output the input color?

A good tip to speed up your motion blur is to use the GPU to generate a mipmap chain of the texture to sample from a lower resolution version of the texture (aka FBO). This gives your really inexpensive blurring. You can keep some high level details by blending this with the original value of that texel before motion blur.

share|improve this answer
    
FYI Various tinkering with the texel lookup (i.e. not looking up at all) and reducing the number of samples got the framerate up to around 17fps, but still way too far off acceptable speeds. With no loops involved, that is just a single texture2D call I get 60fps so I don't think it's the FBO per se. –  Jason Mar 25 '13 at 8:23
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.