My application is written in C++ using OpenGL API, and I build it for desktop OS, as well as for web, using Emscripten. Not so long ago a strange bug emerged: everything works okay on desktop (with any optimizations, valgrind-clean), but crashes in WebGL with the following error:
exception thrown: TypeError: Argument 2 of WebGLRenderingContext.uniform4fv could not be converted to any of: Float32Array, UnrestrictedFloatSequence.
I built it with -g4
(generate readable JS code with debug info) and figured out that sometimes glUniform4fv
gets zero as it's count
argument. OpenGL call wrapper generated by Emscripten is the following:
function _glUniform4fv(location, count, value) {
var view;
if (4*count <= GL.MINI_TEMP_BUFFER_SIZE) {
// avoid allocation when uploading few enough uniforms
view = GL.miniTempBufferViews[4*count-1];
for (var i = 0; i < 4*count; i += 4) {
view[i] = HEAPF32[(((value)+(4*i))>>2)];
view[i+1] = HEAPF32[(((value)+(4*i+4))>>2)];
view[i+2] = HEAPF32[(((value)+(4*i+8))>>2)];
view[i+3] = HEAPF32[(((value)+(4*i+12))>>2)];
}
} else {
view = HEAPF32.subarray((value)>>2,(value+count*16)>>2);
}
GLctx.uniform4fv(GL.uniforms[location], view);
}
So when this wrapper gets zero count
and enters first branch, it executes view = GL.miniTempBufferViews[-1];
, which is undefined
. This value goes to GLctx.uniform4fv
, yielding the above error.
Ok, let's take a look at OpenGL documentation, ES 2.0 version, which is base for WebGL1:
count
Specifies the number of elements that are to be modified. This should be 1 if the targeted uniform variable is not an array, and 1 or more if it is an array.
...
Errors
...
GL_INVALID_VALUE is generated if count is less than 0.
So I can't see anything about what OpenGL should do when count
is zero. I assumed, that it's a correct value, when we have nothing to pass to a shader. At least, it shouldn't crash.
So I have the following questions:
Is it undefined or implementation-defined behavior from the respect of GLES 2.0 specification?
What should be Emscripten's correct reaction? It's definitely not allowed to set error state as there is no such error in specs. But maybe it would be more correct to pass zero-sized
Float32Array
toGLctx.uniform4fv
, letting browser's Webgl implementation to deal with it? Should I report an issue to Emscripten developers?
Circling back to this old issue, I believe the this was fixed in emscripten in https://github.com/emscripten-core/emscripten/pull/16837