Shader compilation problem on PowerVR only

Hi all,

I’m getting error reports that the following pixel shader does not compile on Android-driven PowerVR SGX 540 and 530 chipsets. Specifically on the following devices, while it compiles and runs fine on Tegra2, Adreno and all others I have tested it on:

MB525    2.3.7  PowerVR SGX 530  Motorola Defy
SGH-T959   2.2  PowerVR SGX 540  Samsung Vibrant Galaxy S
GT-I9000   2.2  PowerVR SGX 540  Samsung Galaxy S
SGH-T959V   2.2.1  PowerVR SGX 540  Samsung Galaxy S 4G
GT-P1000   2.2  PowerVR SGX 540  Samsung Galaxy Tab P1000
LG-P920   2.2.2  PowerVR SGX 540  LG Optimus 3D
YP-G70    2.2.2  PowerVR SGX 540  Samsung Galaxy S Wifi 5.0
SAMSUNG-SGH-I897  2.2  PowerVR SGX 540  Samsung Captivate

Since I don’t have any of these devices at my disposal, I was hoping someone in these forums could help me out.

Here’s the vertex shader, which compiles fine:

// position and normal of the vertices
attribute vec4 aPosition;

// texture variables
attribute vec2 textureCoord;
varying vec2 tCoord;

uniform float UVscaleX;
uniform float UVscaleY;

void main() 
tCoord = textureCoord;
gl_Position = aPosition; 

Here's the pixel shader, which does not compile fine, apparently:

precision mediump float;

varying vec2 tCoord;

uniform vec3 tCoordOffset;
uniform float coordScale;
uniform vec3 octMult;
uniform vec3 colorMult;
uniform sampler2D permTexture;

vec4 permute(vec4 x)
  return mod(((x*34.0)+1.0)*x, 289.0);

vec4 taylorInvSqrt(vec4 r)
  return 1.79284291400159 - 0.85373472095314 * r;

vec3 fade(vec3 t) 
  return t*t*t*(t*(t*6.0-15.0)+10.0);

// Classic Perlin noise
float cnoise(vec3 P)
  vec3 Pi0 = floor(P); // Integer part for indexing
  vec3 Pi1 = Pi0 + vec3(1.0); // Integer part + 1
  Pi0 = mod(Pi0, 289.0);
  Pi1 = mod(Pi1, 289.0);
  vec3 Pf0 = fract(P); // Fractional part for interpolation
  vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0
  vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
  vec4 iy = vec4(Pi0.yy, Pi1.yy);
  vec4 iz0 = Pi0.zzzz;
  vec4 iz1 = Pi1.zzzz;

  vec4 ixy = permute(permute(ix) + iy);
  vec4 ixy0 = permute(ixy + iz0);
  vec4 ixy1 = permute(ixy + iz1);

  vec4 gx0 = ixy0 / 7.0;
  vec4 gy0 = fract(floor(gx0) / 7.0) - 0.5;
  gx0 = fract(gx0);
  vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0);
  vec4 sz0 = step(gz0, vec4(0.0));
  gx0 -= sz0 * (step(0.0, gx0) - 0.5);
  gy0 -= sz0 * (step(0.0, gy0) - 0.5);

  vec4 gx1 = ixy1 / 7.0;
  vec4 gy1 = fract(floor(gx1) / 7.0) - 0.5;
  gx1 = fract(gx1);
  vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1);
  vec4 sz1 = step(gz1, vec4(0.0));
  gx1 -= sz1 * (step(0.0, gx1) - 0.5);
  gy1 -= sz1 * (step(0.0, gy1) - 0.5);

  vec3 g000 = vec3(gx0.x,gy0.x,gz0.x);
  vec3 g100 = vec3(gx0.y,gy0.y,gz0.y);
  vec3 g010 = vec3(gx0.z,gy0.z,gz0.z);
  vec3 g110 = vec3(gx0.w,gy0.w,gz0.w);
  vec3 g001 = vec3(gx1.x,gy1.x,gz1.x);
  vec3 g101 = vec3(gx1.y,gy1.y,gz1.y);
  vec3 g011 = vec3(gx1.z,gy1.z,gz1.z);
  vec3 g111 = vec3(gx1.w,gy1.w,gz1.w);

  vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));
  g000 *= norm0.x;
  g010 *= norm0.y;
  g100 *= norm0.z;
  g110 *= norm0.w;
  vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));
  g001 *= norm1.x;
  g011 *= norm1.y;
  g101 *= norm1.z;
  g111 *= norm1.w;

  float n000 = dot(g000, Pf0);
  float n100 = dot(g100, vec3(Pf1.x, Pf0.yz));
  float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z));
  float n110 = dot(g110, vec3(Pf1.xy, Pf0.z));
  float n001 = dot(g001, vec3(Pf0.xy, Pf1.z));
  float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z));
  float n011 = dot(g011, vec3(Pf0.x, Pf1.yz));
  float n111 = dot(g111, Pf1);

  vec3 fade_xyz = fade(Pf0);
  vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z);
  vec2 n_yz = mix(n_z.xy,, fade_xyz.y);
  float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); 
  return 2.2 * n_xyz;

void main( void )
  vec3 finaltCoord = (vec3( tCoord, 0.0 ) + tCoordOffset) * coordScale;

  float n = abs( cnoise( finaltCoord ) ) * octMult.x + (abs(cnoise( finaltCoord * 2.0 )) / 2.0) * octMult.y + (abs(cnoise( finaltCoord * 4.0 )) / 4.0) * octMult.z;

  gl_FragColor = vec4( vec3( n * colorMult.x, n * colorMult.y, n * colorMult.z ), 1.0);

Hope someone can shed some light on this...


Hi Nils,

I’ve been able to successfully compile and link the shaders on the following devices:

* Galaxy S 2.3.3. [SGX driver]
* Kindle Fire [SGX driver]

I’ll try to compile the shaders on a few more devices and will get back to you.


Hi Joe,

Thanks for picking this up! I haven’t gotten any further yet with it myself. Although today, I got word from a colleague whose wife has a Galaxy S (Android 2.2) that has the same shader compilation problem. I hope to get debug access to this phone tomorrow.

Another thing that’s very frustrating, is that I can’t seem to get a descriptive error as to WHY a shader does not compile. This is not just on PowerVR by the way, it’s a problem I’ve been having on every Android device, with any shader I compile. For some reason, I cannot get glGetShaderInfoLog to give me anything but an empty string. As I typed this, I did some searching on this issue (again), and found the following post:
so I'll be trying that workaround tomorrow as well, hoping it helps me narrow down the reason for the compilation failure...


Hi Nils,

I’ve just tried a Nexus S I have and again the shaders you’ve given have compiled and linked sucessfully.
* Nexus S 2.3.1 [SGX driver]

glGetShaderInfoLog() should, in most cases, return the compiler’s output. If the returned string is empty then the compiler may have suffered an internal error and crashed, which in turn means it is unable to fill the log. If I was able to reproduce the crash, I’d be happy to help you look into this. My first approach to this kind of shader compilation problem is to simplify the shader and re-introduce functionality until the crash occurs to gain understanding of where the problem may be.

Do you have access to any PowerVR devices where the crash occurs? Can you use “cat /proc/pvr/version” in the Android shell to query the GPU driver version string and share this with us for any devices that have crashed?


Hi Joe,

I use glGetShaderInfoLog from Java, and the default wrapper has a bug that makes glGetShaderInfoLog always return null. So I worked around the bug, as per the link in my previous mail, and I still get an empty string back (the workaround works on my other devices, so it’s REALLY returning an empty string, even the C version apparently).

I have access to a device where it happens for exactly one hour now :slight_smile:
After that, no more direct testing until I find a different test device, which sucks.

Here’s the cat /proc/pvr/version output:

Version (release,Sep  1 2010 21:34:13) smdkc110_android
System Version String: SGX540 S5PC110

This is on a Galaxy S2 (GT-I9000), running android 2.2

Since I now have 30 minutes left with this phone, I’ll do some more testing with the shader to see at which point it breaks…

Nils Desle

Hi Joe,

My time with this phone is up. I’ve narrowed it down to the cnoise function. It’s not the permute or taylorInvSqrt that’s causing it. Just putting return 0 progressively in the flow of the cnoise function works right up to the end. Returning meaningful values, that use the intermediate results of what’s been calculated so far, works until I call the fade() function. Then the compiler apparently chokes without telling me why…

I really hope you can help me figure this out, as I no longer have debugging capabilities as of now :frowning:


HI Nils,

As I haven’t found a device that reproduces the problem, I won’t be able to help you investigate this issue at this point in time.

From what you’ve told me so far, it sounds like the problem may be specific to 1.5 SGX drivers. You can also query the driver version on most devices with glGetString(GL_VERSION). This should make it easier for you to collect the driver version information from devices that you do not have direct access to.


Hi Joe,

Fair enough. I’m detecting the compilation fail now, and falling back to a different shader in these cases.