You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
WebGL/WebGL2: any integer-valued number ≥ 1e21 emits invalid GLSL (1e+30.0) #864
On the WebGL and WebGL2 backends, an integer-valued number of 1e21 or larger produces a fragment shader that fails to compile:
Error compiling fragment shader: ERROR: 0:518: '.0' : syntax error
The generated GLSL contains 1e+30.0, which is not a valid float literal.
1e30 is a natural thing to write — it is the usual "infinitely far away" sentinel in a ray marcher or path tracer, which is where I hit it.
Reproduction
Verified on gpu.js 2.21.0, Chrome 150, Apple M1 Max (apple metal-3), via dist/gpu-browser.js.
// FAILS — literal in the kernel bodynewGPU({mode: 'webgl2'}).createKernel(function(){return1e30;}).setOutput([1])();// FAILS — value passed through setConstantsnewGPU({mode: 'webgl2'}).createKernel(function(){returnthis.constants.big*1;}).setConstants({big: 1e30}).setOutput([1])();// OK — runtime argument, uploaded as a uniform rather than emitted into sourcenewGPU({mode: 'webgl2'}).createKernel(function(v){returnv*1;}).setOutput([1])(1e30);
Affected backends
backend
1e30
1e21
1e20
123456
webgl2
FAIL
FAIL
ok
ok
webgl
FAIL
FAIL
ok
ok
webgpu
ok
ok
ok
ok
Cause
The threshold is exactly 1e21, which is where Number.prototype.toString() switches to exponential notation:
Number.isInteger(1e30) is true, so the .0 is appended to a string that is already in exponential form.
Suggested fix
Only append .0 when the rendered string does not already make the literal a float. GLSL accepts 1e30 as a float literal, so the exponential form can pass through unchanged:
consts=`${ast.value}`;retArr.push(/[.eE]/.test(s) ? s : `${s}.0`);
The same ${value}.0 pattern appears in src/backend/function-node.js and src/backend/web-gpu/function-node.js; I only observed the failure on the two WebGL backends, so I have not checked whether the others are reachable with the same input.
Workaround
Keep sentinels below 1e21 — 1e20 renders as digits and works, and for most scenes something like 1e9 is plenty.
Activity
bench: fix the two failing rows, cut four
fix(gl): expression for-inits, assigned loop counters, and huge float…