Search code examples
iphoneglslwebglmobile-safari

WebGL Shader rendering green box on iPhone


I wrote a fragment shader that generates a plot of a fractal using some maths which aren't particularly relevant to this question.

On my MacBook Pro, the plot works fine (Chrome and Safari). On my iPhone, it shows only a bright green (#00FF00) rectangle. In iPhone simulator (on my MacBook Pro), it works 100% fine.

I suspect there is something in my fragment shader that is not compatible with the graphics hardware on the phone. I can't figure what. I have enabled debugging but don't see anything that indicates a problem.

f-shader.glsl

precision mediump float;

varying vec2 v_coord;

void color_wheel(in float hue, out vec3 rgb) {
  float x;
  if (0.0 <= hue && hue < 60.0) {
    x = 1.0 - hue/60.0;
    rgb = vec3(1.0, x, 0.0);
  } else if (hue < 120.0) {
    x = (hue - 60.0)/60.0;
    rgb = vec3(x, 1.0, 0.0);
  } else if (hue < 180.0) {
    x = 1.0 - (hue - 120.0)/60.0;
    rgb = vec3(0.0, 1.0, x);
  } else if (hue < 240.0) {
    x = (hue - 180.0)/60.0;
    rgb = vec3(0.0, x, 1.0);
  } else if (hue < 300.0) {
    x = 1.0 - (hue - 240.0)/60.0;
    rgb = vec3(x, 0.0, 1.0);
  } else if (hue < 360.0) {
    x = (hue - 300.0)/60.0;
    rgb = vec3(1.0, 0.0, x);
  } else {
    rgb = vec3(0.0, 0.0, 0.0);
  }
}

void color_step_ratio(in int steps, in int max_steps, out vec3 rgb) {
  if (steps == max_steps) {
    rgb = vec3(0.0, 0.0, 0.0);
  } else {
    float ratio = float(steps)/float(max_steps);
    color_wheel(60.0*(1.0 - ratio), rgb);
  } 
}

void main() {
  float w = v_coord.x;
  float a = v_coord.y;

  float b = 0.05;
  float h = 0.001;
  float h2 = h/2.0;
  float t = 0.0;
  const int max_steps = 60000;

  vec2 k0 = vec2(0.0, 0.0);
  vec2 k1, k1P, k2, k2P, k3, k3P, k4;
  int steps = 0;
  for (int i = 0; i < max_steps; i++) {
    k1 = vec2( k0.y,  -b*k0.y  - k0.x +   k0.x*k0.x + a*sin(w*t));
    k1P = k0 + h2*k1;
    k2 = vec2(k1P.y, -b*k1P.y - k1P.x + k1P.x*k1P.x + a*sin(w*(t + h2)));
    k2P = k0 + h2*k2;
    k3 = vec2(k2P.y, -b*k2P.y - k2P.x + k2P.x*k2P.x + a*sin(w*(t + h2)));
    k3P = k0 + h*k3;
    k4 = vec2(k3P.y, -b*k3P.y - k3P.x + k3P.x*k3P.x + a*sin(w*(t + h)));

    t += h;
    k0 += (h/6.0)*(k1 + 2.0*(k2 + k3) + k4);

    steps++;
    if (k0.x >= 1.0) break;
  }

  vec3 rgb;
  color_step_ratio(steps, max_steps, rgb);
  gl_FragColor = vec4(rgb, 1);
}

I don't know where to go from here. Any suggestions?

You can check out a live demo here and the full source code here.

What I expect: plot on my laptop (MacBook Pro - Retina, 13-inch, Late 2013 - OS X 10.10.5):

Ship stability plot on laptop

What actually happens: on my iPhone (iPhone 6 - iOS 9.2 - Mobile Safari):

enter image description here


Solution

  • This is the problem:

    const int max_steps = 60000;
    
    ...
    
    for (int i = 0; i < max_steps; i++) { ... }
    

    I suspect that the for loop is being "unrolled" by the graphics driver. It works fine when I reduce max_steps to 60, 600, and 6000. 60000 is just too much.