# Why there are calculation differences in WebGL and OpenGL

I am currently implementing the Mandelbrot fractal on the GPU. I wrote two programs: the first in OpenGL (desktop C++ application) and the second in WebGL (static webpage). The two programs use almost the same fragment shader for generating the fractal, but picture on WebGL looks less detailed than the OpenGL one. I cannot understand the reason behind that.

WebGL version:

OpenGL version:

I place here the fragment shader code:

precision highp float;
float xShift = 200.0;
float yShift = 50.0;

struct ComplexNumber
{
float Real;
float Imagine;
};

ComplexNumber Product(in ComplexNumber first, in ComplexNumber second)
{
ComplexNumber result;
result.Real = first.Real * second.Real - first.Imagine * second.Imagine;
result.Imagine = first.Real * second.Imagine + first.Imagine * second.Real;
return result;
}

ComplexNumber Add(in ComplexNumber first, in ComplexNumber second)
{
ComplexNumber result;
result.Real = first.Real + second.Real;
result.Imagine = first.Imagine + second.Imagine;
return result;
}

float length2(in ComplexNumber number)
{
return number.Real * number.Real + number.Imagine * number.Imagine;
}

vec4 linearExtrapolation(const vec4 first, const vec4 last, int min, int max, int x)
{
float xDiff = float(max - min);
return first + float(x - min) * (last - first) / xDiff;
}

int getOutOfBoundsIdx()
{
const int nMax = 1000;

ComplexNumber z;
z.Real = 0.;
z.Imagine = 0.;

ComplexNumber c;
c.Real = float((gl_FragCoord.x - xShift ) * fade);
c.Imagine = float((gl_FragCoord.y - yShift) * fade);

for (int i = 0; i < nMax; i++)
{
if (length2(z) > 4.)
{
return i;
}
}

return nMax;
}

void main()
{

const vec4 blue = vec4(166, 202, 240, 255) / 255.;
const vec4 biruz = vec4(123, 228, 209, 255) / 255.;
const vec4 red = vec4(255, 0, 0, 255) / 255.;
const vec4 green = vec4(0, 255, 0, 255) / 255.;
const vec4 black = vec4(0, 0, 0, 255) / 255.;

const int kThreshold0 = 0;
const int kThreshold1 = 100;
const int kThreshold2 = 150;
const int kThreshold3 = 250;
const int kThreshold4 = 390;

int k = getOutOfBoundsIdx();

vec4 color;
if (k < kThreshold1)
{
color = linearExtrapolation(biruz, blue, kThreshold0, kThreshold1, k);
}
else if (k < kThreshold2)
{
color = linearExtrapolation(red, green, kThreshold1, kThreshold2, k);
}
else if (k < kThreshold3)
{
color = linearExtrapolation(biruz, blue, kThreshold2, kThreshold3, k);
}
else if (k < kThreshold4)
{
color = linearExtrapolation(biruz, green, kThreshold3, kThreshold4, k);
}

else
{
color = black;
}

gl_FragColor = color;
}


What can be a reason of such weird difference? I have a feeling that the float operations on WebGL are less precise than in OpenGL.

• It looks like the top image is rendered to a lower resolution render target (or texture). Dec 7, 2019 at 12:26
• @PaulH It was the first which I was suspecting. For testing I’ve generated the gradient coloring in Webgl and the result was perfect. I suspect that the reason behind the problem is that by the ES GLSL 2.0 standard (which is used in WebGL). float should contain at least 16 bit. They give a freedom in the standard to implement more precise floats, but don’t require that. At the same time the float in OpenGL is 32 bit Dec 7, 2019 at 12:56
• @David - you are correct about that. highp in GLES is 16bit where as in normal opengl floats are 32 bit. I think that's where the problem may lie. You can try to use 16 bit floats in normal OpenGL and see if it produces the same result as WebGL one Dec 8, 2019 at 7:53
• @PaulHK You were completely right. I used css styles to setup the width and height of the canvas up to 100%. And it was just stretching the canvas, but the actual size was of viewports was 300x300 pixels Dec 16, 2019 at 10:56