Most of the code is from here, I just loaded webgl2
instead of webgl
, changed the fragment shader to include a while loop, and logged a few things,
source/script.js:
const canvas = document.getElementById('screen');
const gl = canvas.getContext('webgl2');
if (!gl) {
throw new Error('WebGL not supported');
}
console.log(gl instanceof WebGL2RenderingContext);
// vertexData = [...]
// create buffer
// load vertexData into buffer
// create vertex shader
// create fragment shader
// create program
// attach shaders to program
// enable vertex attributes
// draw
const vertexData = [
0, 1, 0,
1, -1, 0,
-1, -1, 0,
];
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, `
attribute vec3 position;
void main() {
gl_Position = vec4(position, 1);
}
`);
gl.compileShader(vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, `
void main() {
int i = 0;
while (i < 2) {
i++;
}
gl_FragColor = vec4(1, 0, 0, 1);
}
`);
gl.compileShader(fragmentShader);
var compiled = gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS);
console.log('Shader compiled successfully: ' + compiled);
var compilationLog = gl.getShaderInfoLog(fragmentShader);
console.log('Shader compiler log: ' + compilationLog);
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
const positionLocation = gl.getAttribLocation(program, `position`);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
gl.useProgram(program);
gl.drawArrays(gl.TRIANGLES, 0, 3);
the console output is:
true
script.js:56 Shader compiled successfully: false
script.js:58 Shader compiler log: ERROR: 0:4: 'while' : This type of loop is not allowed
I am hosting this using python -m http.server 8000
if that is of any help.
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>WebGL2 Test</title>
<link href="style.css" rel="stylesheet" type="text/css">
</head>
<body>
<canvas id="screen"></canvas>
<script type="module" src="./source/script.js"></script>
</body>
</html>
style.css:
body{
margin: 0;
width: 100vw;
height: 100vh;
}
canvas {
display: block;
width: 100%;
height: 100%;
}
I really have no clue as to what this could be. I hope someone can figure it out.
while
loops are not guaranteed to be supported. Try using a for
loop instead.
From the link below:
The while and do-while loops are optional. The only loop construct you are guaranteed to have is the for loop. In addition, there are many restrictions on the looping constructs. In general “control flow is limited to loops where the maximum number of iterations can easily be determined at compile time.”
The link also explains some limitations on loops.
Try this instead.
void main() {
for (int i = 0; i < 2; i++) {
// do something
}
gl_FragColor = vec4(1, 0, 0, 1);
}
Another approach is to use a high enough hard limit for your loop and then break when your condition is met. This allows the compiler to know the max iterations at compile time (required) and you can break the loop when your condition is met. Do not set the loop limit higher than you need as it affects compilation time and higher limits may not work on all devices (see additional notes below.)
void main() {
for (int i = 0; i < 1000; i++) {
// do something
if (myCondition) break;
}
gl_FragColor = vec4(1, 0, 0, 1);
}
One of my favorite tools for testing the validity of, and understanding shaders is GPU ShaderAnalyzer by AMD. You can paste in your shader and select compile and it shows you the generated assembly.
For example:
void main() {
for (int i = 0; i < 10; i++) {
// do something
}
gl_FragColor = vec4(1, 0, 0, 1);
}
Is compiled to:
il_ps_2_0
dcl_output_generic o0
dcl_literal l0, 0x3F800000, 0x00000000, 0x00000000, 0x3F800000
dcl_literal l1, 0x00000001, 0x00000000, 0x00000000, 0x00000000
mov r1.x___, l0.y
mov r2.x___, r1.x
iadd r1.x___, r1.x, l1.x
mov r3.x___, r1.x
iadd r1.x___, r1.x, l1.x
mov r4.x___, r1.x
iadd r1.x___, r1.x, l1.x
mov r5.x___, r1.x
iadd r1.x___, r1.x, l1.x
mov r6.x___, r1.x
iadd r1.x___, r1.x, l1.x
mov r7.x___, r1.x
iadd r1.x___, r1.x, l1.x
mov r8.x___, r1.x
iadd r1.x___, r1.x, l1.x
mov r9.x___, r1.x
iadd r1.x___, r1.x, l1.x
mov r10.x___, r1.x
iadd r1.x___, r1.x, l1.x
mov r11.x___, r1.x
iadd r1.x___, r1.x, l1.x
mov r12, l0
mov o0, r12
endmain
See how it doesn't create an assembly loop and instead creates instructions for each iteration? It helps give a better idea of what is going on under the hood.