diff options
Diffstat (limited to 'src/library_gl.js')
-rw-r--r-- | src/library_gl.js | 1549 |
1 files changed, 844 insertions, 705 deletions
diff --git a/src/library_gl.js b/src/library_gl.js index 075d7cb5..61ca8957 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -4,7 +4,7 @@ */ var LibraryGL = { - $GL__postset: 'GL.init()', + $GL__postset: 'var GLctx; GL.init()', $GL: { #if GL_DEBUG debug: true, @@ -22,9 +22,13 @@ var LibraryGL = { #if FULL_ES2 clientBuffers: [], + currArrayBuffer: 0, + currElementArrayBuffer: 0, #endif +#if LEGACY_GL_EMULATION currArrayBuffer: 0, currElementArrayBuffer: 0, +#endif byteSizeByTypeRoot: 0x1400, // GL_BYTE byteSizeByType: [ @@ -53,6 +57,7 @@ var LibraryGL = { unpackAlignment: 4, // default alignment is 4 bytes init: function() { + GL.createLog2ceilLookup(GL.MAX_TEMP_BUFFER_SIZE); Browser.moduleContextCreatedCallbacks.push(GL.initExtensions); }, @@ -77,42 +82,64 @@ var LibraryGL = { miniTempBuffer: null, miniTempBufferViews: [0], // index i has the view of size i+1 - // Large temporary buffers + // When user GL code wants to render from client-side memory, we need to upload the vertex data to a temp VBO + // for rendering. Maintain a set of temp VBOs that are created-on-demand to appropriate sizes, and never destroyed. + // Also, for best performance the VBOs are double-buffered, i.e. every second frame we switch the set of VBOs we + // upload to, so that rendering from the previous frame is not disturbed by uploading from new data to it, which + // could cause a GPU-CPU pipeline stall. + // Note that index buffers are not double-buffered (at the moment) in this manner. MAX_TEMP_BUFFER_SIZE: {{{ GL_MAX_TEMP_BUFFER_SIZE }}}, - tempBufferIndexLookup: null, - tempVertexBuffers: null, - tempIndexBuffers: null, + tempVertexBuffers1: [], + tempVertexBufferCounters1: [], + tempVertexBuffers2: [], + tempVertexBufferCounters2: [], + // Maximum number of temp VBOs of one size to maintain, after that we start reusing old ones, which is safe but can give + // a performance impact. If CPU-GPU stalls are a problem, increasing this might help. + numTempVertexBuffersPerSize: 64, // (const) + tempIndexBuffers: [], tempQuadIndexBuffer: null, - generateTempBuffers: function(quads) { - GL.tempBufferIndexLookup = new Uint8Array(GL.MAX_TEMP_BUFFER_SIZE+1); - GL.tempVertexBuffers = []; - GL.tempIndexBuffers = []; - var last = -1, curr = -1; - var size = 1; - for (var i = 0; i <= GL.MAX_TEMP_BUFFER_SIZE; i++) { - if (i > size) { - size <<= 1; + // Precompute a lookup table for the function ceil(log2(x)), i.e. how many bits are needed to represent x, or, + // if x was rounded up to next pow2, which index is the single '1' bit at? + // Then log2ceilLookup[x] returns ceil(log2(x)). + log2ceilLookup: null, + createLog2ceilLookup: function(maxValue) { + GL.log2ceilLookup = new Uint8Array(maxValue+1); + var log2 = 0; + var pow2 = 1; + GL.log2ceilLookup[0] = 0; + for(var i = 1; i <= maxValue; ++i) { + if (i > pow2) { + pow2 <<= 1; + ++log2; } - if (size != last) { - curr++; - GL.tempVertexBuffers[curr] = Module.ctx.createBuffer(); - Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, GL.tempVertexBuffers[curr]); - Module.ctx.bufferData(Module.ctx.ARRAY_BUFFER, size, Module.ctx.DYNAMIC_DRAW); - Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, null); - GL.tempIndexBuffers[curr] = Module.ctx.createBuffer(); - Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, GL.tempIndexBuffers[curr]); - Module.ctx.bufferData(Module.ctx.ELEMENT_ARRAY_BUFFER, size, Module.ctx.DYNAMIC_DRAW); - Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, null); - last = size; + GL.log2ceilLookup[i] = log2; + } + }, + + generateTempBuffers: function(quads) { + var largestIndex = GL.log2ceilLookup[GL.MAX_TEMP_BUFFER_SIZE]; + GL.tempVertexBufferCounters1.length = GL.tempVertexBufferCounters2.length = largestIndex+1; + GL.tempVertexBuffers1.length = GL.tempVertexBuffers2.length = largestIndex+1; + GL.tempIndexBuffers.length = largestIndex+1; + for(var i = 0; i <= largestIndex; ++i) { + GL.tempIndexBuffers[i] = null; // Created on-demand + GL.tempVertexBufferCounters1[i] = GL.tempVertexBufferCounters2[i] = 0; + var ringbufferLength = GL.numTempVertexBuffersPerSize; + GL.tempVertexBuffers1[i] = []; + GL.tempVertexBuffers2[i] = []; + var ringbuffer1 = GL.tempVertexBuffers1[i]; + var ringbuffer2 = GL.tempVertexBuffers2[i]; + ringbuffer1.length = ringbuffer2.length = ringbufferLength; + for(var j = 0; j < ringbufferLength; ++j) { + ringbuffer1[j] = ringbuffer2[j] = null; // Created on-demand } - GL.tempBufferIndexLookup[i] = curr; } if (quads) { // GL_QUAD indexes can be precalculated - GL.tempQuadIndexBuffer = Module.ctx.createBuffer(); - Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, GL.tempQuadIndexBuffer); + GL.tempQuadIndexBuffer = GLctx.createBuffer(); + GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, GL.tempQuadIndexBuffer); var numIndexes = GL.MAX_TEMP_BUFFER_SIZE >> 1; var quadIndexes = new Uint16Array(numIndexes); var i = 0, v = 0; @@ -131,8 +158,55 @@ var LibraryGL = { if (i >= numIndexes) break; v += 4; } - Module.ctx.bufferData(Module.ctx.ELEMENT_ARRAY_BUFFER, quadIndexes, Module.ctx.STATIC_DRAW); - Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, null); + GLctx.bufferData(GLctx.ELEMENT_ARRAY_BUFFER, quadIndexes, GLctx.STATIC_DRAW); + GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, null); + } + }, + + getTempVertexBuffer: function getTempVertexBuffer(sizeBytes) { + var idx = GL.log2ceilLookup[sizeBytes]; + var ringbuffer = GL.tempVertexBuffers1[idx]; + var nextFreeBufferIndex = GL.tempVertexBufferCounters1[idx]; + GL.tempVertexBufferCounters1[idx] = (GL.tempVertexBufferCounters1[idx]+1) & (GL.numTempVertexBuffersPerSize-1); + var vbo = ringbuffer[nextFreeBufferIndex]; + if (vbo) { + return vbo; + } + var prevVBO = GLctx.getParameter(GLctx.ARRAY_BUFFER_BINDING); + ringbuffer[nextFreeBufferIndex] = GLctx.createBuffer(); + GLctx.bindBuffer(GLctx.ARRAY_BUFFER, ringbuffer[nextFreeBufferIndex]); + GLctx.bufferData(GLctx.ARRAY_BUFFER, 1 << idx, GLctx.DYNAMIC_DRAW); + GLctx.bindBuffer(GLctx.ARRAY_BUFFER, prevVBO); + return ringbuffer[nextFreeBufferIndex]; + }, + + getTempIndexBuffer: function getTempIndexBuffer(sizeBytes) { + var idx = GL.log2ceilLookup[sizeBytes]; + var ibo = GL.tempIndexBuffers[idx]; + if (ibo) { + return ibo; + } + var prevIBO = GLctx.getParameter(GLctx.ELEMENT_ARRAY_BUFFER_BINDING); + GL.tempIndexBuffers[idx] = GLctx.createBuffer(); + GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, GL.tempIndexBuffers[idx]); + GLctx.bufferData(GLctx.ELEMENT_ARRAY_BUFFER, 1 << idx, GLctx.DYNAMIC_DRAW); + GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, prevIBO); + return GL.tempIndexBuffers[idx]; + }, + + // Called at start of each new WebGL rendering frame. This swaps the doublebuffered temp VB memory pointers, + // so that every second frame utilizes different set of temp buffers. The aim is to keep the set of buffers + // being rendered, and the set of buffers being updated disjoint. + newRenderingFrameStarted: function newRenderingFrameStarted() { + var vb = GL.tempVertexBuffers1; + GL.tempVertexBuffers1 = GL.tempVertexBuffers2; + GL.tempVertexBuffers2 = vb; + vb = GL.tempVertexBufferCounters1; + GL.tempVertexBufferCounters1 = GL.tempVertexBufferCounters2; + GL.tempVertexBufferCounters2 = vb; + var largestIndex = GL.log2ceilLookup[GL.MAX_TEMP_BUFFER_SIZE]; + for(var i = 0; i <= largestIndex; ++i) { + GL.tempVertexBufferCounters1[i] = 0; } }, @@ -182,13 +256,13 @@ var LibraryGL = { source += frag; } // Let's see if we need to enable the standard derivatives extension - type = Module.ctx.getShaderParameter(GL.shaders[shader], 0x8B4F /* GL_SHADER_TYPE */); + type = GLctx.getShaderParameter(GL.shaders[shader], 0x8B4F /* GL_SHADER_TYPE */); if (type == 0x8B30 /* GL_FRAGMENT_SHADER */) { if (GL.findToken(source, "dFdx") || GL.findToken(source, "dFdy") || GL.findToken(source, "fwidth")) { source = "#extension GL_OES_standard_derivatives : enable\n" + source; - var extension = Module.ctx.getExtension("OES_standard_derivatives"); + var extension = GLctx.getExtension("OES_standard_derivatives"); #if GL_DEBUG if (!extension) { Module.printErr("Shader attempts to use the standard derivatives extension which is not available."); @@ -240,7 +314,7 @@ var LibraryGL = { case 0x86A2: // GL_NUM_COMPRESSED_TEXTURE_FORMATS // WebGL doesn't have GL_NUM_COMPRESSED_TEXTURE_FORMATS (it's obsolete since GL_COMPRESSED_TEXTURE_FORMATS returns a JS array that can be queried for length), // so implement it ourselves to allow C++ GLES2 code get the length. - var formats = Module.ctx.getParameter(0x86A3 /*GL_COMPRESSED_TEXTURE_FORMATS*/); + var formats = GLctx.getParameter(0x86A3 /*GL_COMPRESSED_TEXTURE_FORMATS*/); ret = formats.length; break; case 0x8B9A: // GL_IMPLEMENTATION_COLOR_READ_TYPE @@ -252,7 +326,7 @@ var LibraryGL = { } if (ret === undefined) { - var result = Module.ctx.getParameter(name_); + var result = GLctx.getParameter(name_); switch (typeof(result)) { case "number": ret = result; @@ -391,7 +465,7 @@ var LibraryGL = { default: throw 'Invalid format (' + format + ')'; } - internalFormat = Module.ctx.RGBA; + internalFormat = GLctx.RGBA; break; default: throw 'Invalid type (' + type + ')'; @@ -417,13 +491,13 @@ var LibraryGL = { enableVertexAttribArray: function enableVertexAttribArray(index) { if (!GL.enabledClientAttribIndices[index]) { GL.enabledClientAttribIndices[index] = true; - Module.ctx.enableVertexAttribArray(index); + GLctx.enableVertexAttribArray(index); } }, disableVertexAttribArray: function disableVertexAttribArray(index) { if (GL.enabledClientAttribIndices[index]) { GL.enabledClientAttribIndices[index] = false; - Module.ctx.disableVertexAttribArray(index); + GLctx.disableVertexAttribArray(index); } }, #endif @@ -442,9 +516,6 @@ var LibraryGL = { preDrawHandleClientVertexAttribBindings: function preDrawHandleClientVertexAttribBindings(count) { GL.resetBufferBinding = false; - var used = GL.usedTempBuffers; - used.length = 0; - // TODO: initial pass to detect ranges we need to upload, might not need an upload per attrib for (var i = 0; i < GL.maxVertexAttribs; ++i) { var cb = GL.clientBuffers[i]; @@ -453,29 +524,21 @@ var LibraryGL = { GL.resetBufferBinding = true; var size = GL.calcBufLength(cb.size, cb.type, cb.stride, count); - var index = GL.tempBufferIndexLookup[size]; - var buf; - do { -#if ASSERTIONS - assert(index < GL.tempVertexBuffers.length); -#endif - buf = GL.tempVertexBuffers[index++]; - } while (used.indexOf(buf) >= 0); - used.push(buf); - Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, buf); - Module.ctx.bufferSubData(Module.ctx.ARRAY_BUFFER, + var buf = GL.getTempVertexBuffer(size); + GLctx.bindBuffer(GLctx.ARRAY_BUFFER, buf); + GLctx.bufferSubData(GLctx.ARRAY_BUFFER, 0, HEAPU8.subarray(cb.ptr, cb.ptr + size)); #if GL_ASSERTIONS GL.validateVertexAttribPointer(cb.size, cb.type, cb.stride, 0); #endif - Module.ctx.vertexAttribPointer(i, cb.size, cb.type, cb.normalized, cb.stride, 0); + GLctx.vertexAttribPointer(i, cb.size, cb.type, cb.normalized, cb.stride, 0); } }, postDrawHandleClientVertexAttribBindings: function postDrawHandleClientVertexAttribBindings() { if (GL.resetBufferBinding) { - Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, GL.buffers[GL.currArrayBuffer]); + GLctx.bindBuffer(GLctx.ARRAY_BUFFER, GL.buffers[GL.currArrayBuffer]); } }, #endif @@ -544,7 +607,7 @@ var LibraryGL = { GL.miniTempBufferViews[i] = GL.miniTempBuffer.subarray(0, i+1); } - GL.maxVertexAttribs = Module.ctx.getParameter(Module.ctx.MAX_VERTEX_ATTRIBS); + GL.maxVertexAttribs = GLctx.getParameter(GLctx.MAX_VERTEX_ATTRIBS); #if FULL_ES2 for (var i = 0; i < GL.maxVertexAttribs; i++) { GL.clientBuffers[i] = { enabled: false, clientside: false, size: 0, type: 0, normalized: 0, stride: 0, ptr: 0 }; @@ -554,18 +617,18 @@ var LibraryGL = { #endif // Detect the presence of a few extensions manually, this GL interop layer itself will need to know if they exist. - GL.compressionExt = Module.ctx.getExtension('WEBGL_compressed_texture_s3tc') || - Module.ctx.getExtension('MOZ_WEBGL_compressed_texture_s3tc') || - Module.ctx.getExtension('WEBKIT_WEBGL_compressed_texture_s3tc'); + GL.compressionExt = GLctx.getExtension('WEBGL_compressed_texture_s3tc') || + GLctx.getExtension('MOZ_WEBGL_compressed_texture_s3tc') || + GLctx.getExtension('WEBKIT_WEBGL_compressed_texture_s3tc'); - GL.anisotropicExt = Module.ctx.getExtension('EXT_texture_filter_anisotropic') || - Module.ctx.getExtension('MOZ_EXT_texture_filter_anisotropic') || - Module.ctx.getExtension('WEBKIT_EXT_texture_filter_anisotropic'); + GL.anisotropicExt = GLctx.getExtension('EXT_texture_filter_anisotropic') || + GLctx.getExtension('MOZ_EXT_texture_filter_anisotropic') || + GLctx.getExtension('WEBKIT_EXT_texture_filter_anisotropic'); - GL.floatExt = Module.ctx.getExtension('OES_texture_float'); + GL.floatExt = GLctx.getExtension('OES_texture_float'); // Extension available from Firefox 26 and Google Chrome 30 - GL.instancedArraysExt = Module.ctx.getExtension('ANGLE_instanced_arrays'); + GL.instancedArraysExt = GLctx.getExtension('ANGLE_instanced_arrays'); // These are the 'safe' feature-enabling extensions that don't add any performance impact related to e.g. debugging, and // should be enabled by default so that client GLES2/GL code will not need to go through extra hoops to get its stuff working. @@ -589,11 +652,11 @@ var LibraryGL = { return false; } - var extensions = Module.ctx.getSupportedExtensions(); + var extensions = GLctx.getSupportedExtensions(); for(var e in extensions) { var ext = extensions[e].replace('MOZ_', '').replace('WEBKIT_', ''); if (automaticallyEnabledExtensions.indexOf(ext) != -1) { - Module.ctx.getExtension(ext); // Calling .getExtension enables that extension permanently, no need to store the return value to be enabled. + GLctx.getExtension(ext); // Calling .getExtension enables that extension permanently, no need to store the return value to be enabled. } } }, @@ -620,9 +683,9 @@ var LibraryGL = { 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. - var numUniforms = Module.ctx.getProgramParameter(p, Module.ctx.ACTIVE_UNIFORMS); + var numUniforms = GLctx.getProgramParameter(p, GLctx.ACTIVE_UNIFORMS); for (var i = 0; i < numUniforms; ++i) { - var u = Module.ctx.getActiveUniform(p, i); + var u = GLctx.getActiveUniform(p, i); var name = u.name; ptable.maxUniformLength = Math.max(ptable.maxUniformLength, name.length+1); @@ -636,14 +699,14 @@ var LibraryGL = { // Optimize memory usage slightly: If we have an array of uniforms, e.g. 'vec3 colors[3];', then // 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 = Module.ctx.getUniformLocation(p, name); + var loc = GLctx.getUniformLocation(p, name); var id = GL.getNewId(GL.uniforms); utable[name] = [u.size, id]; GL.uniforms[id] = loc; for (var j = 1; j < u.size; ++j) { var n = name + '['+j+']'; - loc = Module.ctx.getUniformLocation(p, n); + loc = GLctx.getUniformLocation(p, n); id = GL.getNewId(GL.uniforms); GL.uniforms[id] = loc; @@ -659,7 +722,7 @@ var LibraryGL = { } else if (pname == 0x0cf5 /* GL_UNPACK_ALIGNMENT */) { GL.unpackAlignment = param; } - Module.ctx.pixelStorei(pname, param); + GLctx.pixelStorei(pname, param); }, glGetString__sig: 'ii', @@ -670,10 +733,10 @@ var LibraryGL = { case 0x1F00 /* GL_VENDOR */: case 0x1F01 /* GL_RENDERER */: case 0x1F02 /* GL_VERSION */: - ret = allocate(intArrayFromString(Module.ctx.getParameter(name_)), 'i8', ALLOC_NORMAL); + ret = allocate(intArrayFromString(GLctx.getParameter(name_)), 'i8', ALLOC_NORMAL); break; case 0x1F03 /* GL_EXTENSIONS */: - var exts = Module.ctx.getSupportedExtensions(); + var exts = GLctx.getSupportedExtensions(); var gl_exts = []; for (i in exts) { gl_exts.push(exts[i]); @@ -714,7 +777,7 @@ var LibraryGL = { glGenTextures: function(n, textures) { for (var i = 0; i < n; i++) { var id = GL.getNewId(GL.textures); - var texture = Module.ctx.createTexture(); + var texture = GLctx.createTexture(); texture.name = id; GL.textures[id] = texture; {{{ makeSetValue('textures', 'i*4', 'id', 'i32') }}}; @@ -726,7 +789,7 @@ var LibraryGL = { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('textures', 'i*4', 'i32') }}}; var texture = GL.textures[id]; - Module.ctx.deleteTexture(texture); + GLctx.deleteTexture(texture); texture.name = 0; GL.textures[id] = null; } @@ -742,7 +805,8 @@ var LibraryGL = { } else { data = null; } - Module.ctx['compressedTexImage2D'](target, level, internalFormat, width, height, border, data); + // N.b. using array notation explicitly to not confuse Closure minification. + GLctx['compressedTexImage2D'](target, level, internalFormat, width, height, border, data); }, glCompressedTexSubImage2D__sig: 'viiiiiiiii', @@ -755,7 +819,7 @@ var LibraryGL = { } else { data = null; } - Module.ctx['compressedTexSubImage2D'](target, level, xoffset, yoffset, width, height, data); + CLctx['compressedTexSubImage2D'](target, level, xoffset, yoffset, width, height, data); }, glTexImage2D__sig: 'viiiiiiiii', @@ -767,7 +831,7 @@ var LibraryGL = { } else { pixels = null; } - Module.ctx.texImage2D(target, level, internalFormat, width, height, border, format, type, pixels); + GLctx.texImage2D(target, level, internalFormat, width, height, border, format, type, pixels); }, glTexSubImage2D__sig: 'viiiiiiiii', @@ -778,7 +842,7 @@ var LibraryGL = { } else { pixels = null; } - Module.ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); + GLctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); }, glReadPixels__sig: 'viiiiiii', @@ -802,7 +866,7 @@ var LibraryGL = { return; } var totalSize = width*height*sizePerPixel; - Module.ctx.readPixels(x, y, width, height, format, type, HEAPU8.subarray(pixels, pixels + totalSize)); + GLctx.readPixels(x, y, width, height, format, type, HEAPU8.subarray(pixels, pixels + totalSize)); }, glBindTexture__sig: 'vii', @@ -810,7 +874,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.textures, texture, 'glBindTexture', 'texture'); #endif - Module.ctx.bindTexture(target, texture ? GL.textures[texture] : null); + GLctx.bindTexture(target, texture ? GL.textures[texture] : null); }, glGetTexParameterfv__sig: 'viii', @@ -826,27 +890,27 @@ var LibraryGL = { glTexParameterfv__sig: 'viii', glTexParameterfv: function(target, pname, params) { var param = {{{ makeGetValue('params', '0', 'float') }}}; - Module.ctx.texParameterf(target, pname, param); + GLctx.texParameterf(target, pname, param); }, glTexParameteriv__sig: 'viii', glTexParameteriv: function(target, pname, params) { var param = {{{ makeGetValue('params', '0', 'i32') }}}; - Module.ctx.texParameteri(target, pname, param); + GLctx.texParameteri(target, pname, param); }, glIsTexture__sig: 'ii', glIsTexture: function(texture) { var texture = GL.textures[texture]; if (!texture) return 0; - return Module.ctx.isTexture(texture); + return GLctx.isTexture(texture); }, glGenBuffers__sig: 'vii', glGenBuffers: function(n, buffers) { for (var i = 0; i < n; i++) { var id = GL.getNewId(GL.buffers); - var buffer = Module.ctx.createBuffer(); + var buffer = GLctx.createBuffer(); buffer.name = id; GL.buffers[id] = buffer; {{{ makeSetValue('buffers', 'i*4', 'id', 'i32') }}}; @@ -863,7 +927,7 @@ var LibraryGL = { // correspond to existing buffer objects." if (!buffer) continue; - Module.ctx.deleteBuffer(buffer); + GLctx.deleteBuffer(buffer); buffer.name = 0; GL.buffers[id] = null; @@ -874,7 +938,7 @@ var LibraryGL = { glGetBufferParameteriv__sig: 'viii', glGetBufferParameteriv: function(target, value, data) { - {{{ makeSetValue('data', '0', 'Module.ctx.getBufferParameter(target, value)', 'i32') }}}; + {{{ makeSetValue('data', '0', 'GLctx.getBufferParameter(target, value)', 'i32') }}}; }, glBufferData__sig: 'viiii', @@ -893,26 +957,26 @@ var LibraryGL = { usage = 0x88E8; // GL_DYNAMIC_DRAW break; } - Module.ctx.bufferData(target, HEAPU8.subarray(data, data+size), usage); + GLctx.bufferData(target, HEAPU8.subarray(data, data+size), usage); }, glBufferSubData__sig: 'viiii', glBufferSubData: function(target, offset, size, data) { - Module.ctx.bufferSubData(target, offset, HEAPU8.subarray(data, data+size)); + GLctx.bufferSubData(target, offset, HEAPU8.subarray(data, data+size)); }, glIsBuffer__sig: 'ii', glIsBuffer: function(buffer) { var b = GL.buffers[buffer]; if (!b) return 0; - return Module.ctx.isBuffer(b); + return GLctx.isBuffer(b); }, glGenRenderbuffers__sig: 'vii', glGenRenderbuffers: function(n, renderbuffers) { for (var i = 0; i < n; i++) { var id = GL.getNewId(GL.renderbuffers); - var renderbuffer = Module.ctx.createRenderbuffer(); + var renderbuffer = GLctx.createRenderbuffer(); renderbuffer.name = id; GL.renderbuffers[id] = renderbuffer; {{{ makeSetValue('renderbuffers', 'i*4', 'id', 'i32') }}}; @@ -924,7 +988,7 @@ var LibraryGL = { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('renderbuffers', 'i*4', 'i32') }}}; var renderbuffer = GL.renderbuffers[id]; - Module.ctx.deleteRenderbuffer(renderbuffer); + GLctx.deleteRenderbuffer(renderbuffer); renderbuffer.name = 0; GL.renderbuffers[id] = null; } @@ -935,19 +999,19 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.renderbuffers, renderbuffer, 'glBindRenderbuffer', 'renderbuffer'); #endif - Module.ctx.bindRenderbuffer(target, renderbuffer ? GL.renderbuffers[renderbuffer] : null); + GLctx.bindRenderbuffer(target, renderbuffer ? GL.renderbuffers[renderbuffer] : null); }, glGetRenderbufferParameteriv__sig: 'viii', glGetRenderbufferParameteriv: function(target, pname, params) { - {{{ makeSetValue('params', '0', 'Module.ctx.getRenderbufferParameter(target, pname)', 'i32') }}}; + {{{ makeSetValue('params', '0', 'GLctx.getRenderbufferParameter(target, pname)', 'i32') }}}; }, glIsRenderbuffer__sig: 'ii', glIsRenderbuffer: function(renderbuffer) { var rb = GL.renderbuffers[renderbuffer]; if (!rb) return 0; - return Module.ctx.isRenderbuffer(rb); + return GLctx.isRenderbuffer(rb); }, glGetUniformfv__sig: 'viii', @@ -956,7 +1020,7 @@ var LibraryGL = { GL.validateGLObjectID(GL.programs, program, 'glGetUniformfv', 'program'); GL.validateGLObjectID(GL.uniforms, location, 'glGetUniformfv', 'location'); #endif - var data = Module.ctx.getUniform(GL.programs[program], GL.uniforms[location]); + var data = GLctx.getUniform(GL.programs[program], GL.uniforms[location]); if (typeof data == 'number') { {{{ makeSetValue('params', '0', 'data', 'float') }}}; } else { @@ -972,7 +1036,7 @@ var LibraryGL = { GL.validateGLObjectID(GL.programs, program, 'glGetUniformiv', 'program'); GL.validateGLObjectID(GL.uniforms, location, 'glGetUniformiv', 'location'); #endif - var data = Module.ctx.getUniform(GL.programs[program], GL.uniforms[location]); + var data = GLctx.getUniform(GL.programs[program], GL.uniforms[location]); if (typeof data == 'number' || typeof data == 'boolean') { {{{ makeSetValue('params', '0', 'data', 'i32') }}}; } else { @@ -1023,7 +1087,7 @@ var LibraryGL = { Module.printErr("glGetVertexAttribfv on client-side array: not supported, bad data returned"); } #endif - var data = Module.ctx.getVertexAttrib(index, pname); + var data = GLctx.getVertexAttrib(index, pname); if (typeof data == 'number') { {{{ makeSetValue('params', '0', 'data', 'float') }}}; } else { @@ -1040,7 +1104,7 @@ var LibraryGL = { Module.printErr("glGetVertexAttribiv on client-side array: not supported, bad data returned"); } #endif - var data = Module.ctx.getVertexAttrib(index, pname); + var data = GLctx.getVertexAttrib(index, pname); if (typeof data == 'number' || typeof data == 'boolean') { {{{ makeSetValue('params', '0', 'data', 'i32') }}}; } else { @@ -1057,7 +1121,7 @@ var LibraryGL = { Module.printErr("glGetVertexAttribPointer on client-side array: not supported, bad data returned"); } #endif - {{{ makeSetValue('pointer', '0', 'Module.ctx.getVertexAttribOffset(index, pname)', 'i32') }}}; + {{{ makeSetValue('pointer', '0', 'GLctx.getVertexAttribOffset(index, pname)', 'i32') }}}; }, glGetActiveUniform__sig: 'viiiiiii', @@ -1066,7 +1130,7 @@ var LibraryGL = { GL.validateGLObjectID(GL.programs, program, 'glGetActiveUniform', 'program'); #endif program = GL.programs[program]; - var info = Module.ctx.getActiveUniform(program, index); + var info = GLctx.getActiveUniform(program, index); var infoname = info.name.slice(0, Math.max(0, bufSize - 1)); writeStringToMemory(infoname, name); @@ -1088,7 +1152,7 @@ var LibraryGL = { GL.validateGLObjectID(GL.uniforms, location, 'glUniform1f', 'location'); #endif location = GL.uniforms[location]; - Module.ctx.uniform1f(location, v0); + GLctx.uniform1f(location, v0); }, glUniform2f__sig: 'viff', @@ -1097,7 +1161,7 @@ var LibraryGL = { GL.validateGLObjectID(GL.uniforms, location, 'glUniform2f', 'location'); #endif location = GL.uniforms[location]; - Module.ctx.uniform2f(location, v0, v1); + GLctx.uniform2f(location, v0, v1); }, glUniform3f__sig: 'vifff', @@ -1106,7 +1170,7 @@ var LibraryGL = { GL.validateGLObjectID(GL.uniforms, location, 'glUniform3f', 'location'); #endif location = GL.uniforms[location]; - Module.ctx.uniform3f(location, v0, v1, v2); + GLctx.uniform3f(location, v0, v1, v2); }, glUniform4f__sig: 'viffff', @@ -1115,7 +1179,7 @@ var LibraryGL = { GL.validateGLObjectID(GL.uniforms, location, 'glUniform4f', 'location'); #endif location = GL.uniforms[location]; - Module.ctx.uniform4f(location, v0, v1, v2, v3); + GLctx.uniform4f(location, v0, v1, v2, v3); }, glUniform1i__sig: 'vii', @@ -1124,7 +1188,7 @@ var LibraryGL = { GL.validateGLObjectID(GL.uniforms, location, 'glUniform1i', 'location'); #endif location = GL.uniforms[location]; - Module.ctx.uniform1i(location, v0); + GLctx.uniform1i(location, v0); }, glUniform2i__sig: 'viii', @@ -1133,7 +1197,7 @@ var LibraryGL = { GL.validateGLObjectID(GL.uniforms, location, 'glUniform2i', 'location'); #endif location = GL.uniforms[location]; - Module.ctx.uniform2i(location, v0, v1); + GLctx.uniform2i(location, v0, v1); }, glUniform3i__sig: 'viiii', @@ -1142,7 +1206,7 @@ var LibraryGL = { GL.validateGLObjectID(GL.uniforms, location, 'glUniform3i', 'location'); #endif location = GL.uniforms[location]; - Module.ctx.uniform3i(location, v0, v1, v2); + GLctx.uniform3i(location, v0, v1, v2); }, glUniform4i__sig: 'viiiii', @@ -1151,7 +1215,7 @@ var LibraryGL = { GL.validateGLObjectID(GL.uniforms, location, 'glUniform4i', 'location'); #endif location = GL.uniforms[location]; - Module.ctx.uniform4i(location, v0, v1, v2, v3); + GLctx.uniform4i(location, v0, v1, v2, v3); }, glUniform1iv__sig: 'viii', @@ -1161,7 +1225,7 @@ var LibraryGL = { #endif location = GL.uniforms[location]; value = {{{ makeHEAPView('32', 'value', 'value+count*4') }}}; - Module.ctx.uniform1iv(location, value); + GLctx.uniform1iv(location, value); }, glUniform2iv__sig: 'viii', @@ -1172,7 +1236,7 @@ var LibraryGL = { location = GL.uniforms[location]; count *= 2; value = {{{ makeHEAPView('32', 'value', 'value+count*4') }}}; - Module.ctx.uniform2iv(location, value); + GLctx.uniform2iv(location, value); }, glUniform3iv__sig: 'viii', @@ -1183,7 +1247,7 @@ var LibraryGL = { location = GL.uniforms[location]; count *= 3; value = {{{ makeHEAPView('32', 'value', 'value+count*4') }}}; - Module.ctx.uniform3iv(location, value); + GLctx.uniform3iv(location, value); }, glUniform4iv__sig: 'viii', @@ -1194,7 +1258,7 @@ var LibraryGL = { location = GL.uniforms[location]; count *= 4; value = {{{ makeHEAPView('32', 'value', 'value+count*4') }}}; - Module.ctx.uniform4iv(location, value); + GLctx.uniform4iv(location, value); }, glUniform1fv__sig: 'viii', @@ -1211,7 +1275,7 @@ var LibraryGL = { } else { view = {{{ makeHEAPView('F32', 'value', 'value+count*4') }}}; } - Module.ctx.uniform1fv(location, view); + GLctx.uniform1fv(location, view); }, glUniform2fv__sig: 'viii', @@ -1229,7 +1293,7 @@ var LibraryGL = { } else { view = {{{ makeHEAPView('F32', 'value', 'value+count*8') }}}; } - Module.ctx.uniform2fv(location, view); + GLctx.uniform2fv(location, view); }, glUniform3fv__sig: 'viii', @@ -1248,7 +1312,7 @@ var LibraryGL = { } else { view = {{{ makeHEAPView('F32', 'value', 'value+count*12') }}}; } - Module.ctx.uniform3fv(location, view); + GLctx.uniform3fv(location, view); }, glUniform4fv__sig: 'viii', @@ -1268,7 +1332,7 @@ var LibraryGL = { } else { view = {{{ makeHEAPView('F32', 'value', 'value+count*16') }}}; } - Module.ctx.uniform4fv(location, view); + GLctx.uniform4fv(location, view); }, glUniformMatrix2fv__sig: 'viiii', @@ -1287,7 +1351,7 @@ var LibraryGL = { } else { view = {{{ makeHEAPView('F32', 'value', 'value+count*16') }}}; } - Module.ctx.uniformMatrix2fv(location, transpose, view); + GLctx.uniformMatrix2fv(location, transpose, view); }, glUniformMatrix3fv__sig: 'viiii', @@ -1306,7 +1370,7 @@ var LibraryGL = { } else { view = {{{ makeHEAPView('F32', 'value', 'value+count*36') }}}; } - Module.ctx.uniformMatrix3fv(location, transpose, view); + GLctx.uniformMatrix3fv(location, transpose, view); }, glUniformMatrix4fv__sig: 'viiii', @@ -1325,7 +1389,7 @@ var LibraryGL = { } else { view = {{{ makeHEAPView('F32', 'value', 'value+count*64') }}}; } - Module.ctx.uniformMatrix4fv(location, transpose, view); + GLctx.uniformMatrix4fv(location, transpose, view); }, glBindBuffer__sig: 'vii', @@ -1335,44 +1399,53 @@ var LibraryGL = { #endif var bufferObj = buffer ? GL.buffers[buffer] : null; - if (target == Module.ctx.ARRAY_BUFFER) { +#if FULL_ES2 + if (target == GLctx.ARRAY_BUFFER) { GL.currArrayBuffer = buffer; - } else if (target == Module.ctx.ELEMENT_ARRAY_BUFFER) { + } else if (target == GLctx.ELEMENT_ARRAY_BUFFER) { + GL.currElementArrayBuffer = buffer; + } +#endif +#if LEGACY_GL_EMULATION + if (target == GLctx.ARRAY_BUFFER) { + GLImmediate.lastArrayBuffer = GL.currArrayBuffer = buffer; + } else if (target == GLctx.ELEMENT_ARRAY_BUFFER) { GL.currElementArrayBuffer = buffer; } +#endif - Module.ctx.bindBuffer(target, bufferObj); + GLctx.bindBuffer(target, bufferObj); }, glVertexAttrib1fv__sig: 'vii', glVertexAttrib1fv: function(index, v) { v = {{{ makeHEAPView('F32', 'v', 'v+' + (1*4)) }}}; - Module.ctx.vertexAttrib1fv(index, v); + GLctx.vertexAttrib1fv(index, v); }, glVertexAttrib2fv__sig: 'vii', glVertexAttrib2fv: function(index, v) { v = {{{ makeHEAPView('F32', 'v', 'v+' + (2*4)) }}}; - Module.ctx.vertexAttrib2fv(index, v); + GLctx.vertexAttrib2fv(index, v); }, glVertexAttrib3fv__sig: 'vii', glVertexAttrib3fv: function(index, v) { v = {{{ makeHEAPView('F32', 'v', 'v+' + (3*4)) }}}; - Module.ctx.vertexAttrib3fv(index, v); + GLctx.vertexAttrib3fv(index, v); }, glVertexAttrib4fv__sig: 'vii', glVertexAttrib4fv: function(index, v) { v = {{{ makeHEAPView('F32', 'v', 'v+' + (4*4)) }}}; - Module.ctx.vertexAttrib4fv(index, v); + GLctx.vertexAttrib4fv(index, v); }, glGetAttribLocation__sig: 'vii', glGetAttribLocation: function(program, name) { program = GL.programs[program]; name = Pointer_stringify(name); - return Module.ctx.getAttribLocation(program, name); + return GLctx.getAttribLocation(program, name); }, glGetActiveAttrib__sig: 'viiiiiii', @@ -1381,7 +1454,7 @@ var LibraryGL = { GL.validateGLObjectID(GL.programs, program, 'glGetActiveAttrib', 'program'); #endif program = GL.programs[program]; - var info = Module.ctx.getActiveAttrib(program, index); + var info = GLctx.getActiveAttrib(program, index); var infoname = info.name.slice(0, Math.max(0, bufSize - 1)); writeStringToMemory(infoname, name); @@ -1400,13 +1473,13 @@ var LibraryGL = { glCreateShader__sig: 'ii', glCreateShader: function(shaderType) { var id = GL.getNewId(GL.shaders); - GL.shaders[id] = Module.ctx.createShader(shaderType); + GL.shaders[id] = GLctx.createShader(shaderType); return id; }, glDeleteShader__sig: 'vi', glDeleteShader: function(shader) { - Module.ctx.deleteShader(GL.shaders[shader]); + GLctx.deleteShader(GL.shaders[shader]); GL.shaders[shader] = null; }, @@ -1415,7 +1488,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetAttachedShaders', 'program'); #endif - var result = Module.ctx.getAttachedShaders(GL.programs[program]); + var result = GLctx.getAttachedShaders(GL.programs[program]); var len = result.length; if (len > maxCount) { len = maxCount; @@ -1436,7 +1509,7 @@ var LibraryGL = { GL.validateGLObjectID(GL.shaders, shader, 'glShaderSource', 'shader'); #endif var source = GL.getSource(shader, count, string, length); - Module.ctx.shaderSource(GL.shaders[shader], source); + GLctx.shaderSource(GL.shaders[shader], source); }, glGetShaderSource__sig: 'viiii', @@ -1444,7 +1517,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.shaders, shader, 'glGetShaderSource', 'shader'); #endif - var result = Module.ctx.getShaderSource(GL.shaders[shader]); + var result = GLctx.getShaderSource(GL.shaders[shader]); result = result.slice(0, Math.max(0, bufSize - 1)); writeStringToMemory(result, source); if (length) { @@ -1457,7 +1530,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.shaders, shader, 'glCompileShader', 'shader'); #endif - Module.ctx.compileShader(GL.shaders[shader]); + GLctx.compileShader(GL.shaders[shader]); }, glGetShaderInfoLog__sig: 'viiii', @@ -1465,7 +1538,7 @@ var LibraryGL = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.shaders, shader, 'glGetShaderInfoLog', 'shader'); #endif - var log = Module.ctx.getShaderInfoLog(GL.shaders[shader]); + var log = GLctx.getShaderInfoLog(GL.shaders[shader]); // Work around a bug in Chromium which causes getShaderInfoLog to return null if (!log) { log = ""; @@ -1483,9 +1556,9 @@ var LibraryGL = { GL.validateGLObjectID(GL.shaders, shader, 'glGetShaderiv', 'shader'); #endif if (pname == 0x8B84) { // GL_INFO_LOG_LENGTH - {{{ makeSetValue('p', '0', 'Module.ctx.getShaderInfoLog(GL.shaders[shader]).length + 1', 'i32') }}}; + {{{ makeSetValue('p', '0', 'GLctx.getShaderInfoLog(GL.shaders[shader]).length + 1', 'i32') }}}; } else { - {{{ makeSetValue('p', '0', 'Module.ctx.getShaderParameter(GL.shaders[shader], pname)', 'i32') }}}; + {{{ makeSetValue('p', '0', 'GLctx.getShaderParameter(GL.shaders[shader], pname)', 'i32') }}}; } }, @@ -1495,7 +1568,7 @@ var LibraryGL = { GL.validateGLObjectID(GL.programs, program, 'glGetProgramiv', 'program'); #endif if (pname == 0x8B84) { // GL_INFO_LOG_LENGTH - {{{ makeSetValue('p', '0', 'Module.ctx.getProgramInfoLog(GL.programs[program]).length + 1', 'i32') }}}; + {{{ makeSetValue('p', '0', 'GLctx.getProgramInfoLog(GL.programs[program]).length + 1', 'i32') }}}; } else if (pname == 0x8B87 /* GL_ACTIVE_UNIFORM_MAX_LENGTH */) { var ptable = GL.programInfos[program]; if (ptable) { @@ -1517,10 + |