I have the situation that a shader produces a completely different output on my Apple (M1) iMac (and also iPhone) than on my Intel (i5-4300U / Haswell-ULT Integrated Graphics Controller) Thinkpad 440 (more info in the comments). Yet there seems to be no difference between browsers, Chrome and Safari resp. Chrome and GNOME Web produce the same image on the iMac resp. laptop. My Intel Thinkpad 13 Chromebook also displays the Intel version (couldn't test other browsers than Chrome there obviously). What could be the reason for this?
[EDIT] Most people (friends and folks who commented below) seem to get the Apple version, so only me and my two laptops apparently get the Intel version?
This is the shader:
const gl = document.querySelector("canvas").getContext("webgl");
gl.canvas.width = gl.canvas.height = 512
gl.viewport(0, 0, 512, 512);
const programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
a_Position: {
numComponents: 2,
data: [-1, -1, -1, 3, 3, -1]
},
});
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.drawBufferInfo(gl, bufferInfo);
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<script id="vs" type="x-shader/x-vertex">
attribute vec4 a_Position;
varying vec2 v_Position;
varying vec2 v_TexCoord;
void main() {
v_Position = a_Position.xy;
v_TexCoord = a_Position.xy / 2.0 + 0.5;
gl_Position = a_Position;
}
</script>
<script id="fs" type="x-shader/x-vertex">
precision highp float;
varying vec2 v_Position;
varying vec2 v_TexCoord;
vec2 compMult(vec2 u, vec2 v) {
return vec2(u.x * v.x - u.y * v.y, u.x * v.y + u.y * v.x);
}
vec2 G(vec3 x) {
float lenx = length(x);
float ang = 350.0 * lenx;
return vec2(cos(ang), sin(ang)) / lenx;
}
void main() {
gl_FragColor.a = 1.0;
vec3 x0 = vec3(v_TexCoord, 1);
vec2 amplitude;
for(int i = 0; i < 10; i++) {
for(int j = 0; j < 10; j++) {
vec2 pos = 0.05 + vec2(i, j) / 10.0;
vec3 x = vec3(0.4 + 0.2 * pos, 0);
float disx0x = distance(x0, x);
amplitude += compMult(
G(x - vec3(-0.4765625, -0.671875, 300)),
compMult(
vec2(-1.0 / disx0x, 350.0),
G(x - x0) / disx0x
)
);
}
}
gl_FragColor.r = length(amplitude) / 10.0;
}
</script>
<canvas></canvas>
And here are the different outputs:
(Apple)
(Intel)
[EDIT] I think I'm pretty close, look at the following snippet:
const gl = document.querySelector("canvas").getContext("webgl");
gl.canvas.width = gl.canvas.height = 512
gl.viewport(0, 0, 512, 512);
const programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
a_Position: {
numComponents: 2,
data: [-1, -1, -1, 3, 3, -1]
},
});
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.drawBufferInfo(gl, bufferInfo);
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<script id="vs" type="x-shader/x-vertex">
attribute vec4 a_Position;
varying vec2 v_Position;
varying vec2 v_TexCoord;
void main() {
v_Position = a_Position.xy;
v_TexCoord = a_Position.xy / 2.0 + 0.5;
gl_Position = a_Position;
}
</script>
<script id="fs" type="x-shader/x-vertex">
precision highp float;
varying vec2 v_Position;
varying vec2 v_TexCoord;
vec2 compMult(vec2 u, vec2 v) {
return vec2(u.x * v.x - u.y * v.y, u.x * v.y + u.y * v.x);
}
vec2 G(vec3 x) {
float lenx = length(x);
float ang = 350.0 * lenx;
return vec2(cos(ang), sin(ang)) / lenx;
}
void main() {
gl_FragColor.a = 1.0;
vec3 x0 = vec3(v_TexCoord, 1);
vec2 pos = floor(8.0 * v_TexCoord) / 8.0;
vec3 x = vec3(0.375 + 0.25 * pos, 0);
float disx0x = distance(x0, x);
vec2 amplitude = compMult(
G(x - vec3(-0.46875, -0.5, 300.0)),
compMult(
vec2(-1.0 / disx0x, 350.0),
G(x - x0)
)
);
gl_FragColor.rgb = vec3(0.5 + amplitude, 0.5);
}
</script>
<canvas></canvas>
This is what it looks like on my Intel machines:
I think, from looking at the algorithm (there is not even a loop anymore), it's pretty clear that the gray areas should not be gray but similar to the other tiles. Also note that I never divide by small numbers, x
resp. x0
have z-coordinates of 0
resp. 1
, so distance(x, x0)
and distance(x, vec3(-0.46875, -0.5, 300))
are never small, which are the only values I use as dividers. Also I changed some constants so that now all numbers have exact binary representations.
chrome://gpu
on my Thinkpad 440 and this is the one on my Chromebook (Thinkpad 13), hope it helps! – Enterovirusfloat ang = 350.0 * lenx;
tofloat ang = 300.0 * lenx;
to see what I mean. – Darwindarwinian