I have a very simple shader and added linear fog via mix like this:
finalColor = mix(finalColor, vec3(0.5, 0.8, 0.95), vUVoutAndViewZ.z);
Note that the view Z distance is in the variable that also contains the UV coordinates, so the fog didn't even add a new interpolator.
Still, this one innocuous line brought the framerate on the OG Droid with the Power SGX chipset from 33fps to 22fps. Even the HTC Evo with the Adreno 200 GPU stays under 30fps. (The Adreno 205 is at a constant 60fps, but that thing is a beast).
The fragment shader itself is primitive (all values are hard-coded since it's a test shader):
precision mediump float;
varying mediump vec3 vUVoutAndViewZ;
varying lowp vec3 vNormalOut;
uniform lowp sampler2D diffuse;
void main() {
lowp vec3 normal = vNormalOut;
// Lighting
lowp vec3 lightDir = vec3(0.5, 0.3, 0.5);
lowp vec3 light = vec3(dot(normal, lightDir));
lowp vec3 diffuse = texture2D(diffuse, vUVoutAndViewZ.xy).rgb;
lowp vec3 finalColor = diffuse * light;
// Fog
finalColor = mix(finalColor, vec3(0.5, 0.8, 0.95), vUVoutAndViewZ.z);
gl_FragColor = vec4(finalColor.xyz, 1.0);
}
I added the lowp/mediump declarations later (which added about 2fps), it works just as bad without them.
I refuse to believe that the PowerVR chipset is so weak that it can't handle a simple shader like this. There must be something stupid in this shader (like something implicitly swizzling a lowp register) that just completely messes up the unit.
ANSWER and EDIT:
Ellis has some fantastic information in the answer and the subsequent comments. In this particular case, it seems that mix() is flat-out broken. It brought the shader to 12 cycles (from 4) and 4 GPRs (from 2). I got back to 29fps by using this code instead:
lowp vec3 fogDiff = vec3(0.5, 0.8, 0.95) - finalColor;
fogDiff *= vUVoutAndViewZ.z;
finalColor += fogDiff;
mix()killed the framerate, I wasn't too inclined to throw in apowto finish it off. – EboMike Apr 20 '11 at 15:34