# mask shader performance

**URL:** <https://forums.imgtec.com/t/mask-shader-performance/1037>\
**Category:** PowerVR Insider\
**Created:** [March 22, 2011, 4:00pm UTC](https://forums.imgtec.com/t/mask-shader-performance/1037 "2011-03-22T16:00:15Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![wogz](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.imgtec.com/wogz/32/104_2.png) [@wogz](https://forums.imgtec.com/u/wogz)\
**Post date:** [March 22, 2011, 4:00pm UTC](https://forums.imgtec.com/t/mask-shader-performance/1037/1 "2011-03-22T16:00:15Z")

</div>

Hello,  
  
I’m implementing the renderer for my game in OpenGL ES 2 and targeting Android mobile devices, like Galaxy S.  
  
I have a fragment shader which does some tricky texture masking to a screen aligned quad (ortho projection).   
  
Thing is it’s currently running with 17 fps. I have tried many things to optimize it, like:  
&nbsp;  
+ removed all branching code (ifs) and float comparison (3 fps increase)  
+ tried to put lowp to everything (1 fps increase on average)  
  
For instance if I use comment out line in main() as the color output… performance goes up to 40-50 fps.  
  
Any ideas why this runs so slow?

Code:

  
#ifdef GL\_FRAGMENT\_PRECISION\_HIGH  
&nbsp;&nbsp; // Default precision  
&nbsp;&nbsp; precision highp float;  
#else  
&nbsp;&nbsp; precision mediump float;  
#endif  
  
uniform sampler2D ScreenSampler;  
uniform sampler2D BGSampler;  
uniform sampler2D RockSampler;  
uniform sampler2D HomeSampler;  
uniform sampler2D GrassSampler;  
uniform sampler2D GoldenSampler;  
  
uniform vec2 Texel;  
uniform vec2 Aspect;  
uniform float Wave;  
  
varying vec2 vTextureCoord;  
  
vec4 PixelShaderFn()  
{  
&nbsp;&nbsp; vec4&nbsp;&nbsp; bg =&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; texture2D(BGSampler, vTextureCoord \* Aspect);&nbsp;&nbsp;   
&nbsp;&nbsp; vec4&nbsp;&nbsp; wave1 =&nbsp;&nbsp; texture2D(BGSampler, vec2(vTextureCoord.x - Wave \* 0.03, vTextureCoord.y - Wave \* 0.01));  
&nbsp;&nbsp; vec4&nbsp;&nbsp; wave2 =&nbsp;&nbsp; texture2D(BGSampler, vec2(vTextureCoord.x + Wave \* 0.02, vTextureCoord.y + Wave \* 0.02));  
&nbsp;&nbsp; vec4&nbsp;&nbsp; rock =&nbsp;&nbsp;&nbsp; texture2D(RockSampler, vTextureCoord \* Aspect);  
&nbsp;&nbsp; vec4&nbsp;&nbsp; home =&nbsp;&nbsp;&nbsp; texture2D(HomeSampler, vTextureCoord \* Aspect);  
&nbsp;&nbsp; vec4&nbsp;&nbsp; grass =&nbsp;&nbsp; texture2D(GrassSampler, vTextureCoord \* Aspect);  
&nbsp;&nbsp; vec4&nbsp;&nbsp; golden =&nbsp; texture2D(GoldenSampler, vTextureCoord \* Aspect \* 4.0);  
&nbsp;&nbsp;   
&nbsp;&nbsp; vec4&nbsp;&nbsp; color =&nbsp;&nbsp; texture2D(ScreenSampler, vTextureCoord);  
&nbsp;&nbsp; float&nbsp; top =&nbsp;&nbsp;&nbsp;&nbsp; texture2D(ScreenSampler, vec2(vTextureCoord.x, vTextureCoord.y - Texel.y \* 4.0)).r;  
&nbsp;&nbsp; float&nbsp; top2 =&nbsp;&nbsp;&nbsp; texture2D(ScreenSampler, vec2(vTextureCoord.x, vTextureCoord.y - Texel.y \* 9.0)).r;  
&nbsp;&nbsp; float&nbsp; top3 =&nbsp;&nbsp;&nbsp; texture2D(ScreenSampler, vec2(vTextureCoord.x, vTextureCoord.y - Texel.y \* 22.0)).r;  
&nbsp;&nbsp; float&nbsp; bottom =&nbsp; texture2D(ScreenSampler, vec2(vTextureCoord.x, vTextureCoord.y + Texel.y \* 2.0)).r;  
&nbsp;&nbsp; float&nbsp; bottom2 = texture2D(ScreenSampler, vec2(vTextureCoord.x, vTextureCoord.y + Texel.y \* 4.0)).r;  
&nbsp;&nbsp; float&nbsp; bottom3 = texture2D(ScreenSampler, vec2(vTextureCoord.x, vTextureCoord.y + Texel.y \* 7.0)).r;  
&nbsp;&nbsp;   
&nbsp;&nbsp; float&nbsp; groundX = step(0.5, color.g);  
&nbsp;&nbsp; vec4&nbsp;&nbsp; ground =&nbsp; grass \* (1.0 - groundX) + home \* groundX;  
&nbsp;&nbsp; float&nbsp; goldX =&nbsp;&nbsp; color.b \* color.r;  
&nbsp;&nbsp; float&nbsp; lavaX =&nbsp;&nbsp; color.b - color.r;  
  
&nbsp;&nbsp; vec4&nbsp; lava =&nbsp;&nbsp;&nbsp; vec4(1.0, wave1.g + wave2.g, wave1.ba);  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bg =&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bg \* (1.0 - lavaX) + lava \* lavaX;  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; top =&nbsp;&nbsp;&nbsp;&nbsp; (top \* 0.05 + top2 \* 0.09 + top3 \* 0.15) \* (1.0 - color.r);  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bottom =&nbsp; (bottom \* 0.2 + bottom2 \* 0.6 + bottom3) \* (1.0 - color.r);  
&nbsp;&nbsp;   
&nbsp;&nbsp; vec4&nbsp; base =&nbsp;&nbsp; bg \* (1.0 - color.r) + rock \* color.r;  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; base =&nbsp;&nbsp; base \* (1.0 - bottom) + ground \* (bottom - top);  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; base =&nbsp;&nbsp; base \* (1.0 - goldX) + golden \* goldX;  
  
&nbsp;&nbsp; return base;  
}  
  
void main(void)  
{  
&nbsp;&nbsp;&nbsp; //gl\_FragColor = texture2D( ScreenSampler, vTextureCoord );  
&nbsp;&nbsp;&nbsp; gl\_FragColor = PixelShaderFn();  
}

---

<div class="post-metadata">

**Author:** ![JoeDavis](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.imgtec.com/joedavis/32/71_2.png) [@JoeDavis](https://forums.imgtec.com/u/JoeDavis)\
**Post date:** [March 22, 2011, 4:36pm UTC](https://forums.imgtec.com/t/mask-shader-performance/1037/2 "2011-03-22T16:36:52Z")

</div>

Hi,  
  
  
  
  
  
The main reason your performance is suffering is because of the large number of dependent texture reads you are performing. Every time you use a texture coordinate that has been calculated in the fragment shader as a parameter to texture2D(), the thread processing that fragment will have to stall until the texture data is retrieved. POWERVR hardware is capable of hiding the latency of a few dependent texture reads as the hardware will schedule in other threads until the data is retrieved. When a large number of dependent texture reads are performed, the hardware will reach a point where all queued threads are waiting for texture data.  
  
  
  
  
  
You should perform independent texture reads where possible instead of dependent reads. Independent texture reads are performed by the hardware when the texture coordinate is already known for the fragment before it is processed, which means the hardware can pre-fetch texture data (e.g. the texture coordinate is a varying or a constant value). For example, if you calculate vTextureCoord \* Aspect in the vertex shader and pass it to the fragment shader as a varying, 5 of your texture2D() calls will be independents and faster.  
  
  
  
  
  
Ideally, you’ll want to reduce the number of texture samples you have here as much as possible. If you can, you should pack textures so instead of only retrieving the data in the .r channel, you could be retrieving data in all .rgba channels.  
  
  
  
  
  
If you can either post a picture of your rendered effect here, or send it to [devtech@imgtec.com](mailto:devtech@imgtec.com) I can advice further. If I can understand the end effect you are going for, I think I’ll be able to suggest further optimisations 🙂

---

<div class="post-metadata">

**Author:** ![wogz](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.imgtec.com/wogz/32/104_2.png) [@wogz](https://forums.imgtec.com/u/wogz)\
**Post date:** [March 22, 2011, 5:03pm UTC](https://forums.imgtec.com/t/mask-shader-performance/1037/3 "2011-03-22T17:03:48Z")

</div>

Thanks for the tips and fast reply. Pics below.  
  
Some more details…  
Top and bottom variables are used to give a sense of depth to the scene according to what is below and above current pixel.  
  
texColor \* (1.0 - variable.channel) … or texColor \* variable.channel is doing the masking according to the color and picks the correct texture. This avoids using ifs and color comparison.  
  
Any more tips would be appreciated, I will try then out and let you know =P  
  
Mask (ScreenSampler)  
 ![](http://dl.dropbox.com/u/13532547/devicemask.png)  
  
Final render  
 ![](http://dl.dropbox.com/u/13532547/devicerender.png)

---

<div class="post-metadata">

**Author:** ![wogz](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.imgtec.com/wogz/32/104_2.png) [@wogz](https://forums.imgtec.com/u/wogz)\
**Post date:** [March 24, 2011, 11:33am UTC](https://forums.imgtec.com/t/mask-shader-performance/1037/4 "2011-03-24T11:33:45Z")

</div>

Once more I have run into a weird problem.  
  
After modifying the VS and FS to the ones below, when trying to add the depth color component (bt) the shader compilation fails, that’s it no other error messages. Tried several things but I wasn’t able go around the problem.  
  
But for instance outputting bt as the final color, it looks correct. check the pics below.  
  
Good thing is that the performance increased 10 fps.  
  
Any ideas?  
  
VS

Code:

  
uniform mat4 uMVPMatrix;  
attribute vec4 aPosition;  
attribute vec2 aTextureCoord;  
varying vec2 vTextureCoord;  
varying vec2 vTextureCoordAspect;  
varying vec2 vTextureCoordAspect4;  
  
uniform vec2 Aspect;  
  
void main() {  
gl\_Position = uMVPMatrix \* aPosition;  
vTextureCoord = aTextureCoord;  
vTextureCoordAspect = vTextureCoord \* Aspect;  
vTextureCoordAspect4 = vTextureCoordAspect \* 4.0;  
}  

  
  
FS  

Code:

  
#ifdef GL\_FRAGMENT\_PRECISION\_HIGH  
&nbsp;&nbsp; // Default precision  
&nbsp;&nbsp; precision highp float;  
#else  
&nbsp;&nbsp; precision mediump float;  
#endif  
  
uniform sampler2D ScreenSampler;  
uniform sampler2D BGSampler;  
uniform sampler2D RockSampler;  
uniform sampler2D HomeSampler;  
uniform sampler2D GrassSampler;  
uniform sampler2D GoldenSampler;  
  
uniform vec2 Texel;  
uniform vec2 Aspect;  
uniform float Wave;  
  
varying vec2 vTextureCoord;  
varying vec2 vTextureCoordAspect;  
varying vec2 vTextureCoordAspect4;  
  
vec4 PixelShaderFn()  
{  
&nbsp;&nbsp; vec4&nbsp;&nbsp; bg =&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; texture2D(BGSampler, vTextureCoordAspect );&nbsp;&nbsp;   
&nbsp;&nbsp; vec4&nbsp;&nbsp; wave1 =&nbsp;&nbsp; texture2D(BGSampler, vec2(vTextureCoord.x - Wave \* 0.03, vTextureCoord.y - Wave \* 0.01));  
&nbsp;&nbsp; vec4&nbsp;&nbsp; wave2 =&nbsp;&nbsp; texture2D(BGSampler, vec2(vTextureCoord.x + Wave \* 0.02, vTextureCoord.y + Wave \* 0.02));  
&nbsp;&nbsp; vec4&nbsp;&nbsp; rock =&nbsp;&nbsp;&nbsp; texture2D(RockSampler, vTextureCoordAspect );  
&nbsp;&nbsp; vec4&nbsp;&nbsp; home =&nbsp;&nbsp;&nbsp; texture2D(HomeSampler, vTextureCoordAspect );  
&nbsp;&nbsp; vec4&nbsp;&nbsp; grass =&nbsp;&nbsp; texture2D(GrassSampler, vTextureCoordAspect );  
&nbsp;&nbsp; vec4&nbsp;&nbsp; golden =&nbsp; texture2D(GoldenSampler, vTextureCoordAspect4 );  
&nbsp;&nbsp;   
&nbsp;&nbsp; vec4&nbsp;&nbsp; color =&nbsp;&nbsp; texture2D(ScreenSampler, vTextureCoord);  
&nbsp;&nbsp; float&nbsp; top =&nbsp;&nbsp;&nbsp;&nbsp; texture2D(ScreenSampler, vec2(vTextureCoord.x, vTextureCoord.y - Texel.y \* 4.0)).r;  
&nbsp;&nbsp; float&nbsp; top2 =&nbsp;&nbsp;&nbsp; texture2D(ScreenSampler, vec2(vTextureCoord.x, vTextureCoord.y - Texel.y \* 9.0)).r;  
&nbsp;&nbsp; float&nbsp; top3 =&nbsp;&nbsp;&nbsp; texture2D(ScreenSampler, vec2(vTextureCoord.x, vTextureCoord.y - Texel.y \* 22.0)).r;  
&nbsp;&nbsp; float&nbsp; bottom =&nbsp; texture2D(ScreenSampler, vec2(vTextureCoord.x, vTextureCoord.y + Texel.y \* 2.0)).r;  
&nbsp;&nbsp; float&nbsp; bottom2 = texture2D(ScreenSampler, vec2(vTextureCoord.x, vTextureCoord.y + Texel.y \* 4.0)).r;  
&nbsp;&nbsp; float&nbsp; bottom3 = texture2D(ScreenSampler, vec2(vTextureCoord.x, vTextureCoord.y + Texel.y \* 7.0)).r;&nbsp;&nbsp;   
&nbsp;&nbsp;   
&nbsp;&nbsp; float&nbsp; groundX = step(0.5, color.g);  
&nbsp;&nbsp; vec4&nbsp;&nbsp; ground =&nbsp; grass \* (1.0 - groundX) + home \* groundX;  
&nbsp;&nbsp; float&nbsp; goldX =&nbsp;&nbsp; color.b \* color.r;  
&nbsp;&nbsp; float&nbsp; lavaX =&nbsp;&nbsp; color.b - color.r;  
  
&nbsp;&nbsp; vec4&nbsp; lava =&nbsp;&nbsp;&nbsp; vec4(1.0, wave1.g + wave2.g, wave1.ba);  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bg =&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bg \* (1.0 - lavaX) + lava \* lavaX;  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; top =&nbsp;&nbsp;&nbsp;&nbsp; (top \* 0.05 + top2 \* 0.09 + top3 \* 0.15) \* (1.0 - color.r);  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bottom =&nbsp; (bottom \* 0.2 + bottom2 \* 0.6 + bottom3) \* (1.0 - color.r);  
  
&nbsp;&nbsp; vec4&nbsp; bt = ground \* (bottom - top);  
&nbsp;&nbsp;   
&nbsp;&nbsp; vec4&nbsp; base =&nbsp;&nbsp; bg \* (1.0 - color.r) + rock \* color.r;  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; base \*= (1.0 - bottom);&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;  
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//base +=&nbsp; bt;  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; base =&nbsp;&nbsp; base \* (1.0 - goldX) + golden \* goldX;  
  
&nbsp;&nbsp; return base;  
&nbsp;&nbsp; //return bt;  
}  
  
void main(void)  
{  
&nbsp;&nbsp;&nbsp; //gl\_FragColor = texture2D( ScreenSampler, vTextureCoord );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   
&nbsp;&nbsp;&nbsp; gl\_FragColor = PixelShaderFn();  
}  

  
  
base without bt  
 ![](http://dl.dropbox.com/u/13532547/devicenobt.png)  
  
bt  
 ![](http://dl.dropbox.com/u/13532547/devicebt.png)
