diff --git a/src/library_gl.js b/src/library_gl.js index 3d88e27172129..884e31f7e0dd1 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -251,8 +251,8 @@ var LibraryGL = { getSource: function(shader, count, string, length) { var source = ''; for (var i = 0; i < count; ++i) { - var len = length ? {{{ makeGetValue('length', 'i*4', 'i32') }}} : undefined; - source += UTF8ToString({{{ makeGetValue('string', 'i*4', 'i32') }}}, len >= 0 ? len : undefined); + var len = length ? {{{ makeGetValue('length', 'i*4', 'i32') }}} : -1; + source += UTF8ToString({{{ makeGetValue('string', 'i*4', 'i32') }}}, len < 0 ? undefined : len); } #if LEGACY_GL_EMULATION // Let's see if we need to enable the standard derivatives extension @@ -752,7 +752,7 @@ var LibraryGL = { registerContext: function(ctx, webGLContextAttributes) { var handle = _malloc(8); // Make space on the heap to store GL context attributes that need to be accessible as shared between threads. -#if ASSERTIONS +#if GL_ASSERTIONS assert(handle, 'malloc() failed in GL.registerContext!'); #endif #if GL_SUPPORT_EXPLICIT_SWAP_CONTROL @@ -833,25 +833,19 @@ var LibraryGL = { }, makeContextCurrent: function(contextHandle) { - // Deactivating current context? - if (!contextHandle) { - GLctx = Module.ctx = GL.currentContext = null; - return true; - } - var context = GL.contexts[contextHandle]; - if (!context) { #if GL_DEBUG + if (contextHandle && !GL.contexts[contextHandle]) { #if USE_PTHREADS console.error('GL.makeContextCurrent() failed! WebGL context ' + contextHandle + ' does not exist, or was created on another thread!'); #else console.error('GL.makeContextCurrent() failed! WebGL context ' + contextHandle + ' does not exist!'); #endif -#endif - return false; } - GLctx = Module.ctx = context.GLctx; // Active WebGL context object. - GL.currentContext = context; // Active Emscripten GL layer context object. - return true; +#endif + + GL.currentContext = GL.contexts[contextHandle]; // Active Emscripten GL layer context object. + Module.ctx = GLctx = GL.currentContext && GL.currentContext.GLctx; // Active WebGL context object. + return !(contextHandle && !GLctx); }, getContext: function(contextHandle) { @@ -959,14 +953,13 @@ var LibraryGL = { GL.validateGLObjectID(GL.programs, program, 'populateUniformTable', 'program'); #endif var p = GL.programs[program]; - GL.programInfos[program] = { + var ptable = GL.programInfos[program] = { uniforms: {}, maxUniformLength: 0, // This is eagerly computed below, since we already enumerate all uniforms anyway. maxAttributeLength: -1, // This is lazily computed and cached, computed when/if first asked, "-1" meaning not computed yet. maxUniformBlockNameLength: -1 // Lazily computed as well }; - var ptable = GL.programInfos[program]; var utable = ptable.uniforms; // A program's uniform table maps the string name of an uniform to an integer location of that uniform. // The global GL.uniforms map maps integer locations to WebGLUniformLocations. @@ -978,8 +971,8 @@ var LibraryGL = { ptable.maxUniformLength = Math.max(ptable.maxUniformLength, name.length+1); // Strip off any trailing array specifier we might have got, e.g. "[0]". - if (name.indexOf(']', name.length-1) !== -1) { - var ls = name.lastIndexOf('['); + var ls = name.lastIndexOf('['); + if (ls > 0) { name = name.slice(0, ls); } @@ -987,8 +980,7 @@ var LibraryGL = { // only store the string 'colors' in utable, and 'colors[0]', 'colors[1]' and 'colors[2]' will be parsed as 'colors'+i. // Note that for the GL.uniforms table, we still need to fetch the all WebGLUniformLocations for all the indices. var loc = GLctx.getUniformLocation(p, name); - if (loc != null) - { + if (loc) { var id = GL.getNewId(GL.uniforms); utable[name] = [u.size, id]; GL.uniforms[id] = loc; @@ -1416,7 +1408,10 @@ var LibraryGL = { _computeUnpackAlignedImageSize: function(width, height, sizePerPixel, alignment) { function roundedToNextMultipleOf(x, y) { - return Math.ceil(x/y)*y; +#if GL_ASSERTIONS + assert((y & (y-1)) === 0, 'Unpack alignment must be a power of 2! (Allowed values per WebGL spec are 1, 2, 4 or 8)'); +#endif + return (x + y - 1) & -y; } var plainRowSize = width * sizePerPixel; var alignedRowSize = roundedToNextMultipleOf(plainRowSize, alignment); @@ -1620,10 +1615,7 @@ var LibraryGL = { return; } #endif - - var pixelData = null; - if (pixels) pixelData = emscriptenWebGLGetTexPixelData(type, format, width, height, pixels, internalFormat); - GLctx.texImage2D(target, level, internalFormat, width, height, border, format, type, pixelData); + GLctx.texImage2D(target, level, internalFormat, width, height, border, format, type, pixels ? emscriptenWebGLGetTexPixelData(type, format, width, height, pixels, internalFormat) : null); }, glTexSubImage2D__sig: 'viiiiiiiii', @@ -1692,7 +1684,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.textures, texture, 'glBindTexture', 'texture'); #endif - GLctx.bindTexture(target, texture ? GL.textures[texture] : null); + GLctx.bindTexture(target, GL.textures[texture]); }, glGetTexParameterfv__sig: 'viii', @@ -1754,17 +1746,16 @@ var LibraryGL = { ) { for (var i = 0; i < n; i++) { var buffer = GLctx[createFunction](); - if (!buffer) { + var id = buffer && GL.getNewId(objectTable); + if (buffer) { + buffer.name = id; + objectTable[id] = buffer; + } else { GL.recordError(0x0502 /* GL_INVALID_OPERATION */); #if GL_ASSERTIONS err('GL_INVALID_OPERATION in ' + functionName + ': GLctx.' + createFunction + ' returned null - most likely GL context is lost!'); #endif - while(i < n) {{{ makeSetValue('buffers', 'i++*4', 0, 'i32') }}}; - return; } - var id = GL.getNewId(objectTable); - buffer.name = id; - objectTable[id] = buffer; {{{ makeSetValue('buffers', 'i*4', 'id', 'i32') }}}; } }, @@ -1860,17 +1851,21 @@ var LibraryGL = { break; } #endif - if (!data) { - GLctx.bufferData(target, size, usage); - } else { #if USE_WEBGL2 - if (GL.currentContext.supportsWebGL2EntryPoints) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. + if (GL.currentContext.supportsWebGL2EntryPoints) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. + if (data) { GLctx.bufferData(target, HEAPU8, usage, data, size); - return; + } else { + GLctx.bufferData(target, size, usage); } + } else { #endif - GLctx.bufferData(target, HEAPU8.subarray(data, data+size), usage); + // N.b. here first form specifies a heap subarray, second form an integer size, so the ?: code here is polymorphic. It is advised to avoid + // randomly mixing both uses in calling code, to avoid any potential JS engine JIT issues. + GLctx.bufferData(target, data ? HEAPU8.subarray(data, data+size) : size, usage); +#if USE_WEBGL2 } +#endif }, glBufferSubData__sig: 'viiii', @@ -1927,7 +1922,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.timerQueriesEXT, id, 'glBeginQueryEXT', 'id'); #endif - GLctx.disjointTimerQueryExt['beginQueryEXT'](target, id ? GL.timerQueriesEXT[id] : null); + GLctx.disjointTimerQueryExt['beginQueryEXT'](target, GL.timerQueriesEXT[id]); }, glEndQueryEXT__sig: 'vi', @@ -1940,7 +1935,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.timerQueriesEXT, id, 'glQueryCounterEXT', 'id'); #endif - GLctx.disjointTimerQueryExt['queryCounterEXT'](id ? GL.timerQueriesEXT[id] : null, target); + GLctx.disjointTimerQueryExt['queryCounterEXT'](GL.timerQueriesEXT[id], target); }, glGetQueryivEXT__sig: 'viii', @@ -2235,7 +2230,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.queries, id, 'glBeginQuery', 'id'); #endif - GLctx['beginQuery'](target, id ? GL.queries[id] : null); + GLctx['beginQuery'](target, GL.queries[id]); }, glGetQueryiv__sig: 'viii', @@ -2312,7 +2307,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); #endif - GLctx['bindSampler'](unit, sampler ? GL.samplers[sampler] : null); + GLctx['bindSampler'](unit, GL.samplers[sampler]); }, glSamplerParameterf__sig: 'viif', @@ -2320,7 +2315,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); #endif - GLctx['samplerParameterf'](sampler ? GL.samplers[sampler] : null, pname, param); + GLctx['samplerParameterf'](GL.samplers[sampler], pname, param); }, glSamplerParameteri__sig: 'viii', @@ -2328,7 +2323,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); #endif - GLctx['samplerParameteri'](sampler ? GL.samplers[sampler] : null, pname, param); + GLctx['samplerParameteri'](GL.samplers[sampler], pname, param); }, glSamplerParameterfv__sig: 'viii', @@ -2337,7 +2332,7 @@ var LibraryGL = { GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); #endif var param = {{{ makeGetValue('params', '0', 'float') }}}; - GLctx['samplerParameterf'](sampler ? GL.samplers[sampler] : null, pname, param); + GLctx['samplerParameterf'](GL.samplers[sampler], pname, param); }, glSamplerParameteriv__sig: 'viii', @@ -2346,7 +2341,7 @@ var LibraryGL = { GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); #endif var param = {{{ makeGetValue('params', '0', 'i32') }}}; - GLctx['samplerParameteri'](sampler ? GL.samplers[sampler] : null, pname, param); + GLctx['samplerParameteri'](GL.samplers[sampler], pname, param); }, glGetSamplerParameterfv__sig: 'viii', @@ -2403,10 +2398,8 @@ var LibraryGL = { }, glIsTransformFeedback__sig: 'ii', - glIsTransformFeedback: function(transformFeedback) { - var transformFeedback = GL.transformFeedbacks[transformFeedback]; - if (!transformFeedback) return 0; - return GLctx['isTransformFeedback'](transformFeedback); + glIsTransformFeedback: function(id) { + return GLctx['isTransformFeedback'](GL.transformFeedbacks[id]); }, glBindTransformFeedback__sig: 'vii', @@ -2414,12 +2407,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.transformFeedbacks, id, 'glBindTransformFeedback', 'id'); #endif - var transformFeedback = id ? GL.transformFeedbacks[id] : null; - if (id && !transformFeedback) { // Passing an nonexisting or an already deleted id is an error. - GL.recordError(0x0502 /* GL_INVALID_OPERATION */); - return; - } - GLctx['bindTransformFeedback'](target, transformFeedback); + GLctx['bindTransformFeedback'](target, GL.transformFeedbacks[id]); }, glTransformFeedbackVaryings__sig: 'viiii', @@ -2534,8 +2522,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.buffers, buffer, 'glBindBufferBase', 'buffer'); #endif - var bufferObj = buffer ? GL.buffers[buffer] : null; - GLctx['bindBufferBase'](target, index, bufferObj); + GLctx['bindBufferBase'](target, index, GL.buffers[buffer]); }, glBindBufferRange__sig: 'viiiii', @@ -2543,8 +2530,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.buffers, buffer, 'glBindBufferRange', 'buffer'); #endif - var bufferObj = buffer ? GL.buffers[buffer] : null; - GLctx['bindBufferRange'](target, index, bufferObj, offset, ptrsize); + GLctx['bindBufferRange'](target, index, GL.buffers[buffer], offset, ptrsize); }, glGetUniformIndices__sig: 'viiii', @@ -2617,9 +2603,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetUniformBlockIndex', 'program'); #endif - program = GL.programs[program]; - uniformBlockName = UTF8ToString(uniformBlockName); - return GLctx['getUniformBlockIndex'](program, uniformBlockName); + return GLctx['getUniformBlockIndex'](GL.programs[program], UTF8ToString(uniformBlockName)); }, glGetActiveUniformBlockiv__sig: 'viiii', @@ -2851,7 +2835,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.renderbuffers, renderbuffer, 'glBindRenderbuffer', 'renderbuffer'); #endif - GLctx.bindRenderbuffer(target, renderbuffer ? GL.renderbuffers[renderbuffer] : null); + GLctx.bindRenderbuffer(target, GL.renderbuffers[renderbuffer]); }, glGetRenderbufferParameteriv__sig: 'viii', @@ -2932,28 +2916,17 @@ var LibraryGL = { #endif name = UTF8ToString(name); - var arrayOffset = 0; + var arrayIndex = 0; // If user passed an array accessor "[index]", parse the array index off the accessor. - if (name.indexOf(']', name.length-1) !== -1) { - var ls = name.lastIndexOf('['); - var arrayIndex = name.slice(ls+1, -1); - if (arrayIndex.length > 0) { - arrayOffset = parseInt(arrayIndex); - if (arrayOffset < 0) { - return -1; - } - } - name = name.slice(0, ls); + if (name[name.length - 1] == ']') { + var leftBrace = name.lastIndexOf('['); + arrayIndex = name[leftBrace+1] != ']' ? parseInt(name.slice(leftBrace + 1)) : 0; // "index]", parseInt will ignore the ']' at the end; but treat "foo[]" as "foo[0]" + name = name.slice(0, leftBrace); } - var ptable = GL.programInfos[program]; - if (!ptable) { - return -1; - } - var utable = ptable.uniforms; - var uniformInfo = utable[name]; // returns pair [ dimension_of_uniform_array, uniform_location ] - if (uniformInfo && arrayOffset < uniformInfo[0]) { // Check if user asked for an out-of-bounds element, i.e. for 'vec4 colors[3];' user could ask for 'colors[10]' which should return -1. - return uniformInfo[1]+arrayOffset; + var uniformInfo = GL.programInfos[program] && GL.programInfos[program].uniforms[name]; // returns pair [ dimension_of_uniform_array, uniform_location ] + if (uniformInfo && arrayIndex >= 0 && arrayIndex < uniformInfo[0]) { // Check if user asked for an out-of-bounds element, i.e. for 'vec4 colors[3];' user could ask for 'colors[10]' which should return -1. + return uniformInfo[1] + arrayIndex; } else { return -1; } @@ -3636,8 +3609,6 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.buffers, buffer, 'glBindBuffer', 'buffer'); #endif - var bufferObj = buffer ? GL.buffers[buffer] : null; - #if FULL_ES2 || LEGACY_GL_EMULATION if (target == GLctx.ARRAY_BUFFER) { GL.currArrayBuffer = buffer; @@ -3664,7 +3635,7 @@ var LibraryGL = { GLctx.currentPixelUnpackBufferBinding = buffer; } #endif - GLctx.bindBuffer(target, bufferObj); + GLctx.bindBuffer(target, GL.buffers[buffer]); }, glVertexAttrib1fv__sig: 'vii', @@ -3784,7 +3755,7 @@ var LibraryGL = { {{{ makeSetValue('count', '0', 'len', 'i32') }}}; for (var i = 0; i < len; ++i) { var id = GL.shaders.indexOf(result[i]); -#if ASSERTIONS +#if GL_ASSERTIONS assert(id !== -1, 'shader not bound to local id'); #endif {{{ makeSetValue('shaders', 'i*4', 'id', 'i32') }}}; @@ -4045,7 +4016,6 @@ var LibraryGL = { var log = (GLctx.getProgramInfoLog(GL.programs[program]) || '').trim(); if (log) console.error('glLinkProgram: ' + log); #endif - GL.programInfos[program] = null; // uniforms no longer keep the same names after linking GL.populateUniformTable(program); }, @@ -4070,7 +4040,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glUseProgram', 'program'); #endif - GLctx.useProgram(program ? GL.programs[program] : null); + GLctx.useProgram(GL.programs[program]); }, glValidateProgram__sig: 'vi', @@ -4119,8 +4089,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glBindAttribLocation', 'program'); #endif - name = UTF8ToString(name); - GLctx.bindAttribLocation(GL.programs[program], index, name); + GLctx.bindAttribLocation(GL.programs[program], index, UTF8ToString(name)); }, glBindFramebuffer__sig: 'vii', @@ -4135,7 +4104,7 @@ var LibraryGL = { // is being used, but that is ultimately decided at context creation time. GLctx.bindFramebuffer(target, framebuffer ? GL.framebuffers[framebuffer] : GL.currentContext.defaultFbo); #else - GLctx.bindFramebuffer(target, framebuffer ? GL.framebuffers[framebuffer] : null); + GLctx.bindFramebuffer(target, GL.framebuffers[framebuffer]); #endif }, @@ -4375,7 +4344,7 @@ var LibraryGL = { glVertexAttribPointer: function(index, size, type, normalized, stride, ptr) { #if FULL_ES2 var cb = GL.currentContext.clientBuffers[index]; -#if ASSERTIONS +#if GL_ASSERTIONS assert(cb, index); #endif if (!GL.currArrayBuffer) { @@ -4403,7 +4372,7 @@ var LibraryGL = { glVertexAttribIPointer: function(index, size, type, stride, ptr) { #if FULL_ES3 var cb = GL.currentContext.clientBuffers[index]; -#if ASSERTIONS +#if GL_ASSERTIONS assert(cb, index); #endif if (!GL.currArrayBuffer) { @@ -4432,7 +4401,7 @@ var LibraryGL = { glEnableVertexAttribArray: function(index) { #if FULL_ES2 var cb = GL.currentContext.clientBuffers[index]; -#if ASSERTIONS +#if GL_ASSERTIONS assert(cb, index); #endif cb.enabled = true; @@ -4444,7 +4413,7 @@ var LibraryGL = { glDisableVertexAttribArray: function(index) { #if FULL_ES2 var cb = GL.currentContext.clientBuffers[index]; -#if ASSERTIONS +#if GL_ASSERTIONS assert(cb, index); #endif cb.enabled = false; diff --git a/tests/test_other.py b/tests/test_other.py index 098e3f7b00984..93906cfe5c167 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -8890,8 +8890,8 @@ def test_minimal_runtime_code_size(self): test_cases = [ (asmjs + opts, hello_world_sources, {'a.html': 665, 'a.js': 518, 'a.asm.js': 741, 'a.mem': 6}), (opts, hello_world_sources, {'a.html': 623, 'a.js': 624, 'a.wasm': 86}), - (asmjs + opts, hello_webgl_sources, {'a.html': 665, 'a.js': 5605, 'a.asm.js': 11361, 'a.mem': 321}), - (opts, hello_webgl_sources, {'a.html': 623, 'a.js': 5568, 'a.wasm': 8978}) + (asmjs + opts, hello_webgl_sources, {'a.html': 665, 'a.js': 5403, 'a.asm.js': 11361, 'a.mem': 321}), + (opts, hello_webgl_sources, {'a.html': 623, 'a.js': 5380, 'a.wasm': 8978}) ] success = True