diff options
Diffstat (limited to 'src/library_gl.js')
-rw-r--r-- | src/library_gl.js | 426 |
1 files changed, 318 insertions, 108 deletions
diff --git a/src/library_gl.js b/src/library_gl.js index 1ea8efc2..afd36197 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -11,6 +11,7 @@ var LibraryGL = { #endif counter: 1, // 0 is reserved as 'null' in gl + lastError: 0, buffers: [], programs: [], framebuffers: [], @@ -40,7 +41,13 @@ var LibraryGL = { 8 // GL_DOUBLE ], - uniformTable: {}, // name => uniform ID. the uID must be identical until relinking, cannot create a new uID each call to glGetUniformLocation + programInfos: {}, // Stores additional information needed for each shader program. Each entry is of form: + /* { uniforms: {}, // Maps ints back to the opaque WebGLUniformLocation objects. + maxUniformLength: int, // Cached in order to implement glGetProgramiv(GL_ACTIVE_UNIFORM_MAX_LENGTH) + maxAttributeLength: int // Cached in order to implement glGetProgramiv(GL_ACTIVE_ATTRIBUTE_MAX_LENGTH) + } */ + + stringCache: {}, packAlignment: 4, // default alignment is 4 bytes unpackAlignment: 4, // default alignment is 4 bytes @@ -49,6 +56,13 @@ var LibraryGL = { Browser.moduleContextCreatedCallbacks.push(GL.initExtensions); }, + // Records a GL error condition that occurred, stored until user calls glGetError() to fetch it. As per GLES2 spec, only the first error + // is remembered, and subsequent errors are discarded until the user has cleared the stored error by a call to glGetError(). + recordError: function recordError(errorCode) { + if (!GL.lastError) { + GL.lastError = errorCode; + } + }, // Get a new ID for a texture/buffer/etc., while keeping the table dense and fast. Creation is farely rare so it is worth optimizing lookups later. getNewId: function(table) { var ret = GL.counter++; @@ -240,7 +254,9 @@ var LibraryGL = { sizePerPixel = 2; break; case 0x1406 /* GL_FLOAT */: +#if ASSERTIONS assert(GL.floatExt, 'Must have OES_texture_float to use float textures'); +#endif switch (format) { case 0x1907 /* GL_RGB */: sizePerPixel = 3*4; @@ -273,7 +289,7 @@ var LibraryGL = { }, #if FULL_ES2 - calcBufLength: function(size, type, stride, count) { + calcBufLength: function calcBufLength(size, type, stride, count) { if (stride > 0) { return count * stride; // XXXvlad this is not exactly correct I don't think } @@ -283,7 +299,7 @@ var LibraryGL = { usedTempBuffers: [], - preDrawHandleClientVertexAttribBindings: function(count) { + preDrawHandleClientVertexAttribBindings: function preDrawHandleClientVertexAttribBindings(count) { GL.resetBufferBinding = false; var used = GL.usedTempBuffers; @@ -317,7 +333,7 @@ var LibraryGL = { } }, - postDrawHandleClientVertexAttribBindings: function() { + postDrawHandleClientVertexAttribBindings: function postDrawHandleClientVertexAttribBindings() { if (GL.resetBufferBinding) { Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, GL.buffers[GL.currArrayBuffer]); } @@ -451,15 +467,23 @@ var LibraryGL = { GL.validateGLObjectID(GL.programs, program, 'populateUniformTable', 'program'); #endif var p = GL.programs[program]; - GL.uniformTable[program] = {}; - var ptable = GL.uniformTable[program]; - // A program's uniformTable maps the string name of an uniform to an integer location of that uniform. + 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. + }; + + 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. var numUniforms = Module.ctx.getProgramParameter(p, Module.ctx.ACTIVE_UNIFORMS); for (var i = 0; i < numUniforms; ++i) { var u = Module.ctx.getActiveUniform(p, i); var name = u.name; + 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('['); @@ -467,11 +491,11 @@ 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 ptable, and 'colors[0]', 'colors[1]' and 'colors[2]' will be parsed as 'colors'+i. + // 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 id = GL.getNewId(GL.uniforms); - ptable[name] = [u.size, id]; + utable[name] = [u.size, id]; GL.uniforms[id] = loc; for (var j = 1; j < u.size; ++j) { @@ -497,11 +521,14 @@ var LibraryGL = { glGetString__sig: 'ii', glGetString: function(name_) { + if (GL.stringCache[name_]) return GL.stringCache[name_]; + var ret; switch(name_) { case 0x1F00 /* GL_VENDOR */: case 0x1F01 /* GL_RENDERER */: case 0x1F02 /* GL_VERSION */: - return allocate(intArrayFromString(Module.ctx.getParameter(name_)), 'i8', ALLOC_NORMAL); + ret = allocate(intArrayFromString(Module.ctx.getParameter(name_)), 'i8', ALLOC_NORMAL); + break; case 0x1F03 /* GL_EXTENSIONS */: var exts = Module.ctx.getSupportedExtensions(); var gl_exts = []; @@ -509,12 +536,20 @@ var LibraryGL = { gl_exts.push(exts[i]); gl_exts.push("GL_" + exts[i]); } - return allocate(intArrayFromString(gl_exts.join(' ')), 'i8', ALLOC_NORMAL); // XXX this leaks! TODO: Cache all results like this in library_gl.js to be clean and nice and avoid leaking. + ret = allocate(intArrayFromString(gl_exts.join(' ')), 'i8', ALLOC_NORMAL); + break; case 0x8B8C /* GL_SHADING_LANGUAGE_VERSION */: - return allocate(intArrayFromString('OpenGL ES GLSL 1.00 (WebGL)'), 'i8', ALLOC_NORMAL); + ret = allocate(intArrayFromString('OpenGL ES GLSL 1.00 (WebGL)'), 'i8', ALLOC_NORMAL); + break; default: - throw 'Failure: Invalid glGetString value: ' + name_; + GL.recordError(0x0500/*GL_INVALID_ENUM*/); +#if GL_ASSERTIONS + Module.printErr('GL_INVALID_ENUM in glGetString: Unknown parameter ' + name_ + '!'); +#endif + return 0; } + GL.stringCache[name_] = ret; + return ret; }, glGetIntegerv__sig: 'vii', @@ -523,6 +558,7 @@ var LibraryGL = { case 0x8DFA: // GL_SHADER_COMPILER {{{ makeSetValue('p', '0', '1', 'i32') }}}; return; + case 0x8DF8: // GL_SHADER_BINARY_FORMATS case 0x8DF9: // GL_NUM_SHADER_BINARY_FORMATS {{{ makeSetValue('p', '0', '0', 'i32') }}}; return; @@ -542,7 +578,11 @@ var LibraryGL = { {{{ makeSetValue('p', '0', 'result ? 1 : 0', 'i8') }}}; break; case "string": - throw 'Native code calling glGetIntegerv(' + name_ + ') on a name which returns a string!'; + GL.recordError(0x0500/*GL_INVALID_ENUM*/); +#if GL_ASSERTIONS + Module.printErr('GL_INVALID_ENUM in glGetIntegerv: Native code calling glGetIntegerv(' + name_ + ') on a name which returns a string!'); +#endif + return; case "object": if (result === null) { {{{ makeSetValue('p', '0', '0', 'i32') }}}; @@ -564,18 +604,45 @@ var LibraryGL = { } else if (result instanceof WebGLTexture) { {{{ makeSetValue('p', '0', 'result.name | 0', 'i32') }}}; } else { - throw 'Unknown object returned from WebGL getParameter'; + GL.recordError(0x0500/*GL_INVALID_ENUM*/); +#if GL_ASSERTIONS + Module.printErr('GL_INVALID_ENUM in glGetIntegerv: Unknown object returned from WebGL getParameter(' + name_ + ')!'); +#endif + return; } break; - case "undefined": - throw 'Native code calling glGetIntegerv(' + name_ + ') and it returns undefined'; default: - throw 'Why did we hit the default case?'; + GL.recordError(0x0500/*GL_INVALID_ENUM*/); +#if GL_ASSERTIONS + Module.printErr('GL_INVALID_ENUM in glGetIntegerv: Native code calling glGetIntegerv(' + name_ + ') and it returns ' + result + ' of type ' + typeof(result) + '!'); +#endif + return; } }, glGetFloatv__sig: 'vii', glGetFloatv: function(name_, p) { + switch(name_) { + case 0x8DFA: // GL_SHADER_COMPILER + {{{ makeSetValue('p', '0', '1', 'float') }}}; + return; + case 0x8DF8: // GL_SHADER_BINARY_FORMATS + GL.recordError(0x0500/*GL_INVALID_ENUM*/); +#if GL_ASSERTIONS + Module.printErr('GL_INVALID_ENUM in glGetFloatv(GL_SHADER_BINARY_FORMATS): Invalid parameter type!'); +#endif + return; + case 0x8DF9: // GL_NUM_SHADER_BINARY_FORMATS + {{{ makeSetValue('p', '0', '0', 'float') }}}; + return; + 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*/); + {{{ makeSetValue('p', '0', 'formats.length', 'float') }}}; + return; + } + var result = Module.ctx.getParameter(name_); switch (typeof(result)) { case "number": @@ -588,7 +655,11 @@ var LibraryGL = { {{{ makeSetValue('p', '0', '0', 'float') }}}; case "object": if (result === null) { - throw 'Native code calling glGetFloatv(' + name_ + ') and it returns null'; + GL.recordError(0x0500/*GL_INVALID_ENUM*/); +#if GL_ASSERTIONS + Module.printErr('GL_INVALID_ENUM in glGetFloatv: Native code calling glGetFloatv(' + name_ + ') and it returns null!'); +#endif + return; } else if (result instanceof Float32Array || result instanceof Uint32Array || result instanceof Int32Array || @@ -607,18 +678,45 @@ var LibraryGL = { } else if (result instanceof WebGLTexture) { {{{ makeSetValue('p', '0', 'result.name | 0', 'float') }}}; } else { - throw 'Unknown object returned from WebGL getParameter'; + GL.recordError(0x0500/*GL_INVALID_ENUM*/); +#if GL_ASSERTIONS + Module.printErr('GL_INVALID_ENUM in glGetFloatv: Native code calling glGetFloatv(' + name_ + ') and it returns ' + result + ' of type ' + typeof(result) + '!'); +#endif + return; } break; - case "undefined": - throw 'Native code calling glGetFloatv(' + name_ + ') and it returns undefined'; default: - throw 'Why did we hit the default case?'; + GL.recordError(0x0500/*GL_INVALID_ENUM*/); +#if GL_ASSERTIONS + Module.printErr('GL_INVALID_ENUM in glGetFloatv: Native code calling glGetFloatv(' + name_ + ') and it returns ' + result + ' of type ' + typeof(result) + '!'); +#endif + return; } }, glGetBooleanv__sig: 'vii', glGetBooleanv: function(name_, p) { + switch(name_) { + case 0x8DFA: // GL_SHADER_COMPILER + {{{ makeSetValue('p', '0', '1', 'i8') }}}; + return; + case 0x8DF8: // GL_SHADER_BINARY_FORMATS + GL.recordError(0x0500/*GL_INVALID_ENUM*/); +#if GL_ASSERTIONS + Module.printErr('GL_INVALID_ENUM in glGetBooleanv(GL_SHADER_BINARY_FORMATS): Invalid parameter type!'); +#endif + return; + case 0x8DF9: // GL_NUM_SHADER_BINARY_FORMATS + {{{ makeSetValue('p', '0', '0', 'i8') }}}; + return; + 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 hasCompressedFormats = Module.ctx.getParameter(0x86A3 /*GL_COMPRESSED_TEXTURE_FORMATS*/).length > 0 ? 1 : 0; + {{{ makeSetValue('p', '0', 'hasCompressedFormats', 'i8') }}}; + return; + } + var result = Module.ctx.getParameter(name_); switch (typeof(result)) { case "number": @@ -628,7 +726,11 @@ var LibraryGL = { {{{ makeSetValue('p', '0', 'result != 0', 'i8') }}}; break; case "string": - throw 'Native code calling glGetBooleanv(' + name_ + ') on a name which returns a string!'; + GL.recordError(0x0500/*GL_INVALID_ENUM*/); +#if GL_ASSERTIONS + Module.printErr('GL_INVALID_ENUM in glGetBooleanv: Native code calling glGetBooleanv(' + name_ + ') on a name which returns a string!'); +#endif + return; case "object": if (result === null) { {{{ makeSetValue('p', '0', '0', 'i8') }}}; @@ -646,13 +748,19 @@ var LibraryGL = { result instanceof WebGLTexture) { {{{ makeSetValue('p', '0', '1', 'i8') }}}; // non-zero ID is always 1! } else { - throw 'Unknown object returned from WebGL getParameter'; + GL.recordError(0x0500/*GL_INVALID_ENUM*/); +#if GL_ASSERTIONS + Module.printErr('GL_INVALID_ENUM in glGetBooleanv: Unknown object returned from WebGL getParameter(' + name_ + ')!'); +#endif + return; } break; - case "undefined": - throw 'Unknown object returned from WebGL getParameter'; default: - throw 'Why did we hit the default case?'; + GL.recordError(0x0500/*GL_INVALID_ENUM*/); +#if GL_ASSERTIONS + Module.printErr('GL_INVALID_ENUM in glGetBooleanv: Native code calling glGetBooleanv(' + name_ + ') and it returns ' + result + ' of type ' + typeof(result) + '!'); +#endif + return; } }, @@ -680,7 +788,9 @@ var LibraryGL = { glCompressedTexImage2D__sig: 'viiiiiiii', glCompressedTexImage2D: function(target, level, internalFormat, width, height, border, imageSize, data) { +#if ASSERTIONS assert(GL.compressionExt); +#endif if (data) { data = {{{ makeHEAPView('U8', 'data', 'data+imageSize') }}}; } else { @@ -691,7 +801,9 @@ var LibraryGL = { glCompressedTexSubImage2D__sig: 'viiiiiiiii', glCompressedTexSubImage2D: function(target, level, xoffset, yoffset, width, height, format, imageSize, data) { +#if ASSERTIONS assert(GL.compressionExt); +#endif if (data) { data = {{{ makeHEAPView('U8', 'data', 'data+imageSize') }}}; } else { @@ -725,7 +837,9 @@ var LibraryGL = { glReadPixels__sig: 'viiiiiii', glReadPixels: function(x, y, width, height, format, type, pixels) { +#if ASSERTIONS assert(type == 0x1401 /* GL_UNSIGNED_BYTE */); +#endif var sizePerPixel; switch (format) { case 0x1907 /* GL_RGB */: @@ -734,7 +848,12 @@ var LibraryGL = { case 0x1908 /* GL_RGBA */: sizePerPixel = 4; break; - default: throw 'unsupported glReadPixels format'; + default: + GL.recordError(0x0500/*GL_INVALID_ENUM*/); +#if GL_ASSERTIONS + Module.printErr('GL_INVALID_ENUM in glReadPixels: Unsupported format ' + format + '!'); +#endif + return; } var totalSize = width*height*sizePerPixel; Module.ctx.readPixels(x, y, width, height, format, type, HEAPU8.subarray(pixels, pixels + totalSize)); @@ -938,11 +1057,12 @@ var LibraryGL = { name = name.slice(0, ls); } - var ptable = GL.uniformTable[program]; + var ptable = GL.programInfos[program]; if (!ptable) { return -1; } - var uniformInfo = ptable[name]; // returns pair [ dimension_of_uniform_array, uniform_location ] + 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; } else { @@ -1357,7 +1477,9 @@ var LibraryGL = { {{{ makeSetValue('count', '0', 'len', 'i32') }}}; for (var i = 0; i < len; ++i) { var id = GL.shaders.indexOf(result[i]); +#if ASSERTIONS assert(id !== -1, 'shader not bound to local id'); +#endif {{{ makeSetValue('shaders', 'i*4', 'id', 'i32') }}}; } }, @@ -1428,6 +1550,47 @@ var LibraryGL = { #endif if (pname == 0x8B84) { // GL_INFO_LOG_LENGTH {{{ makeSetValue('p', '0', 'Module.ctx.getProgramInfoLog(GL.programs[program]).length + 1', 'i32') }}}; + } else if (pname == 0x8B87 /* GL_ACTIVE_UNIFORM_MAX_LENGTH */) { + var ptable = GL.programInfos[program]; + if (ptable) { + {{{ makeSetValue('p', '0', 'ptable.maxUniformLength', 'i32') }}}; + return; + } else if (program < GL.counter) { +#if GL_ASSERTIONS + Module.printErr("A GL object " + program + " that is not a program object was passed to glGetProgramiv!"); +#endif + GL.recordError(0x0502 /* GL_INVALID_OPERATION */); + } else { +#if GL_ASSERTIONS + Module.printErr("A GL object " + program + " that did not come from GL was passed to glGetProgramiv!"); +#endif + GL.recordError(0x0501 /* GL_INVALID_VALUE */); + } + } else if (pname == 0x8B8A /* GL_ACTIVE_ATTRIBUTE_MAX_LENGTH */) { + var ptable = GL.programInfos[program]; + if (ptable) { + if (ptable.maxAttributeLength == -1) { + var program = GL.programs[program]; + var numAttribs = Module.ctx.getProgramParameter(program, Module.ctx.ACTIVE_ATTRIBUTES); + ptable.maxAttributeLength = 0; // Spec says if there are no active attribs, 0 must be returned. + for(var i = 0; i < numAttribs; ++i) { + var activeAttrib = Module.ctx.getActiveAttrib(program, i); + ptable.maxAttributeLength = Math.max(ptable.maxAttributeLength, activeAttrib.name.length+1); + } + } + {{{ makeSetValue('p', '0', 'ptable.maxAttributeLength', 'i32') }}}; + return; + } else if (program < GL.counter) { +#if GL_ASSERTIONS + Module.printErr("A GL object " + program + " that is not a program object was passed to glGetProgramiv!"); +#endif + GL.recordError(0x0502 /* GL_INVALID_OPERATION */); + } else { +#if GL_ASSERTIONS + Module.printErr("A GL object " + program + " that did not come from GL was passed to glGetProgramiv!"); +#endif + GL.recordError(0x0501 /* GL_INVALID_VALUE */); + } } else { {{{ makeSetValue('p', '0', 'Module.ctx.getProgramParameter(GL.programs[program], pname)', 'i32') }}}; } @@ -1455,7 +1618,7 @@ var LibraryGL = { Module.ctx.deleteProgram(program); program.name = 0; GL.programs[program] = null; - GL.uniformTable[program] = null; + GL.programInfos[program] = null; }, glAttachShader__sig: 'vii', @@ -1491,7 +1654,7 @@ var LibraryGL = { GL.validateGLObjectID(GL.programs, program, 'glLinkProgram', 'program'); #endif Module.ctx.linkProgram(GL.programs[program]); - GL.uniformTable[program] = {}; // uniforms no longer keep the same names after linking + GL.programInfos[program] = null; // uniforms no longer keep the same names after linking GL.populateUniformTable(program); }, @@ -1663,7 +1826,7 @@ var LibraryGL = { }; var glEnable = _glEnable; - _glEnable = function(cap) { + _glEnable = function _glEnable(cap) { // Clean up the renderer on any change to the rendering state. The optimization of // skipping renderer setup is aimed at the case of multiple glDraw* right after each other if (GL.immediate.lastRenderer) GL.immediate.lastRenderer.cleanup(); @@ -1685,7 +1848,7 @@ var LibraryGL = { }; var glDisable = _glDisable; - _glDisable = function(cap) { + _glDisable = function _glDisable(cap) { if (GL.immediate.lastRenderer) GL.immediate.lastRenderer.cleanup(); if (cap == 0x0B60 /* GL_FOG */) { GLEmulation.fogEnabled = false; @@ -1703,7 +1866,7 @@ var LibraryGL = { } glDisable(cap); }; - _glIsEnabled = function(cap) { + _glIsEnabled = function _glIsEnabled(cap) { if (cap == 0x0B60 /* GL_FOG */) { return GLEmulation.fogEnabled ? 1 : 0; } else if (!(cap in validCapabilities)) { @@ -1713,7 +1876,7 @@ var LibraryGL = { }; var glGetBooleanv = _glGetBooleanv; - _glGetBooleanv = function(pname, p) { + _glGetBooleanv = function _glGetBooleanv(pname, p) { var attrib = GLEmulation.getAttributeFromCapability(pname); if (attrib !== null) { var result = GL.immediate.enabledClientAttributes[attrib]; @@ -1724,7 +1887,7 @@ var LibraryGL = { }; var glGetIntegerv = _glGetIntegerv; - _glGetIntegerv = function(pname, params) { + _glGetIntegerv = function _glGetIntegerv(pname, params) { switch (pname) { case 0x84E2: pname = Module.ctx.MAX_TEXTURE_IMAGE_UNITS /* fake it */; break; // GL_MAX_TEXTURE_UNITS case 0x8B4A: { // GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB @@ -1774,17 +1937,17 @@ var LibraryGL = { return; } case 0x8088: { // GL_TEXTURE_COORD_ARRAY_SIZE - var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0]; + var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0 + GLImmediate.clientActiveTexture]; {{{ makeSetValue('params', '0', 'attribute ? attribute.size : 0', 'i32') }}}; return; } case 0x8089: { // GL_TEXTURE_COORD_ARRAY_TYPE - var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0]; + var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0 + GLImmediate.clientActiveTexture]; {{{ makeSetValue('params', '0', 'attribute ? attribute.type : 0', 'i32') }}}; return; } case 0x808A: { // GL_TEXTURE_COORD_ARRAY_STRIDE - var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0]; + var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0 + GLImmediate.clientActiveTexture]; {{{ makeSetValue('params', '0', 'attribute ? attribute.stride : 0', 'i32') }}}; return; } @@ -1793,14 +1956,17 @@ var LibraryGL = { }; var glGetString = _glGetString; - _glGetString = function(name_) { + _glGetString = function _glGetString(name_) { + if (GL.stringCache[name_]) return GL.stringCache[name_]; switch(name_) { case 0x1F03 /* GL_EXTENSIONS */: // Add various extensions that we can support - return allocate(intArrayFromString(Module.ctx.getSupportedExtensions().join(' ') + + var ret = allocate(intArrayFromString(Module.ctx.getSupportedExtensions().join(' ') + ' GL_EXT_texture_env_combine GL_ARB_texture_env_crossbar GL_ATI_texture_env_combine3 GL_NV_texture_env_combine4 GL_EXT_texture_env_dot3 GL_ARB_multitexture GL_ARB_vertex_buffer_object GL_EXT_framebuffer_object GL_ARB_vertex_program GL_ARB_fragment_program GL_ARB_shading_language_100 GL_ARB_shader_objects GL_ARB_vertex_shader GL_ARB_fragment_shader GL_ARB_texture_cube_map GL_EXT_draw_range_elements' + (GL.compressionExt ? ' GL_ARB_texture_compression GL_EXT_texture_compression_s3tc' : '') + (GL.anisotropicExt ? ' GL_EXT_texture_filter_anisotropic' : '') ), 'i8', ALLOC_NORMAL); + GL.stringCache[name_] = ret; + return ret; } return glGetString(name_); }; @@ -1814,7 +1980,7 @@ var LibraryGL = { GL.shaderOriginalSources = {}; #endif var glCreateShader = _glCreateShader; - _glCreateShader = function(shaderType) { + _glCreateShader = function _glCreateShader(shaderType) { var id = glCreateShader(shaderType); GL.shaderInfos[id] = { type: shaderType, @@ -1824,7 +1990,7 @@ var LibraryGL = { }; var glShaderSource = _glShaderSource; - _glShaderSource = function(shader, count, string, length) { + _glShaderSource = function _glShaderSource(shader, count, string, length) { var source = GL.getSource(shader, count, string, length); #if GL_DEBUG console.log("glShaderSource: Input: \n" + source); @@ -1937,7 +2103,7 @@ var LibraryGL = { }; var glCompileShader = _glCompileShader; - _glCompileShader = function(shader) { + _glCompileShader = function _glCompileShader(shader) { Module.ctx.compileShader(GL.shaders[shader]); #if GL_DEBUG if (!Module.ctx.getShaderParameter(GL.shaders[shader], Module.ctx.COMPILE_STATUS)) { @@ -1952,14 +2118,14 @@ var LibraryGL = { GL.programShaders = {}; var glAttachShader = _glAttachShader; - _glAttachShader = function(program, shader) { + _glAttachShader = function _glAttachShader(program, shader) { if (!GL.programShaders[program]) GL.programShaders[program] = []; GL.programShaders[program].push(shader); glAttachShader(program, shader); }; var glDetachShader = _glDetachShader; - _glDetachShader = function(program, shader) { + _glDetachShader = function _glDetachShader(program, shader) { var programShader = GL.programShaders[program]; if (!programShader) { Module.printErr('WARNING: _glDetachShader received invalid program: ' + program); @@ -1971,7 +2137,7 @@ var LibraryGL = { }; var glUseProgram = _glUseProgram; - _glUseProgram = function(program) { + _glUseProgram = function _glUseProgram(program) { #if GL_DEBUG if (GL.debug) { Module.printErr('[using program with shaders]'); @@ -1988,7 +2154,7 @@ var LibraryGL = { } var glDeleteProgram = _glDeleteProgram; - _glDeleteProgram = function(program) { + _glDeleteProgram = function _glDeleteProgram(program) { glDeleteProgram(program); if (program == GL.currProgram) GL.currProgram = 0; }; @@ -1996,12 +2162,12 @@ var LibraryGL = { // If attribute 0 was not bound, bind it to 0 for WebGL performance reasons. Track if 0 is free for that. var zeroUsedPrograms = {}; var glBindAttribLocation = _glBindAttribLocation; - _glBindAttribLocation = function(program, index, name) { + _glBindAttribLocation = function _glBindAttribLocation(program, index, name) { if (index == 0) zeroUsedPrograms[program] = true; glBindAttribLocation(program, index, name); }; var glLinkProgram = _glLinkProgram; - _glLinkProgram = function(program) { + _glLinkProgram = function _glLinkProgram(program) { if (!(program in zeroUsedPrograms)) { Module.ctx.bindAttribLocation(GL.programs[program], 0, 'a_position'); } @@ -2009,11 +2175,13 @@ var LibraryGL = { }; var glBindBuffer = _glBindBuffer; - _glBindBuffer = function(target, buffer) { + _glBindBuffer = function _glBindBuffer(target, buffer) { glBindBuffer(target, buffer); if (target == Module.ctx.ARRAY_BUFFER) { if (GLEmulation.currentVao) { +#if ASSERTIONS assert(GLEmulation.currentVao.arrayBuffer == buffer || GLEmulation.currentVao.arrayBuffer == 0 || buffer == 0, 'TODO: support for multiple array buffers in vao'); +#endif GLEmulation.currentVao.arrayBuffer = buffer; } } else if (target == Module.ctx.ELEMENT_ARRAY_BUFFER) { @@ -2022,7 +2190,7 @@ var LibraryGL = { }; var glGetFloatv = _glGetFloatv; - _glGetFloatv = function(pname, params) { + _glGetFloatv = function _glGetFloatv(pname, params) { if (pname == 0x0BA6) { // GL_MODELVIEW_MATRIX HEAPF32.set(GL.immediate.matrix['m'], params >> 2); } else if (pname == 0x0BA7) { // GL_PROJECTION_MATRIX @@ -2045,7 +2213,7 @@ var LibraryGL = { }; var glHint = _glHint; - _glHint = function(target, mode) { + _glHint = function _glHint(target, mode) { if (target == 0x84EF) { // GL_TEXTURE_COMPRESSION_HINT return; } @@ -2053,21 +2221,21 @@ var LibraryGL = { }; var glEnableVertexAttribArray = _glEnableVertexAttribArray; - _glEnableVertexAttribArray = function(index) { + _glEnableVertexAttribArray = function _glEnableVertexAttribArray(index) { glEnableVertexAttribArray(index); GLEmulation.enabledVertexAttribArrays[index] = 1; if (GLEmulation.currentVao) GLEmulation.currentVao.enabledVertexAttribArrays[index] = 1; }; var glDisableVertexAttribArray = _glDisableVertexAttribArray; - _glDisableVertexAttribArray = function(index) { + _glDisableVertexAttribArray = function _glDisableVertexAttribArray(index) { glDisableVertexAttribArray(index); delete GLEmulation.enabledVertexAttribArrays[index]; if (GLEmulation.currentVao) delete GLEmulation.currentVao.enabledVertexAttribArrays[index]; }; var glVertexAttribPointer = _glVertexAttribPointer; - _glVertexAttribPointer = function(index, size, type, normalized, stride, pointer) { + _glVertexAttribPointer = function _glVertexAttribPointer(index, size, type, normalized, stride, pointer) { glVertexAttribPointer(index, size, type, normalized, stride, pointer); if (GLEmulation.currentVao) { // TODO: avoid object creation here? likely not hot though GLEmulation.currentVao.vertexAttribPointers[index] = [index, size, type, normalized, stride, pointer]; @@ -2099,9 +2267,6 @@ var LibraryGL = { glGetShaderPrecisionFormat__sig: 'v', glGetShaderPrecisionFormat: function() { throw 'glGetShaderPrecisionFormat: TODO' }, - glShaderBinary__sig: 'v', - glShaderBinary: function() { throw 'glShaderBinary: TODO' }, - glDeleteObject__sig: 'vi', glDeleteObject: function(id) { if (GL.programs[id]) { @@ -2113,11 +2278,6 @@ var LibraryGL = { } }, - glReleaseShaderCompiler__sig: 'v', - glReleaseShaderCompiler: function() { - // NOP (as allowed by GLES 2.0 spec) - }, - glGetObjectParameteriv__sig: 'viii', glGetObjectParameteriv: function(id, type, result) { if (GL.programs[id]) { @@ -2153,7 +2313,9 @@ var LibraryGL = { glBindProgram__sig: 'vii', glBindProgram: function(type, id) { +#if ASSERTIONS assert(id == 0); +#endif }, glGetPointerv: function(name, p) { @@ -2164,8 +2326,13 @@ var LibraryGL = { case 0x8090: // GL_COLOR_ARRAY_POINTER attribute = GLImmediate.clientAttributes[GLImmediate.COLOR]; break; case 0x8092: // GL_TEXTURE_COORD_ARRAY_POINTER - attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0]; break; - default: throw 'TODO: glGetPointerv for ' + name; + attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0 + GLImmediate.clientActiveTexture]; break; + default: + GL.recordError(0x0500/*GL_INVALID_ENUM*/); +#if GL_ASSERTIONS + Module.printErr('GL_INVALID_ENUM in glGetPointerv: Unsupported name ' + name + '!'); +#endif + return; } {{{ makeSetValue('p', '0', 'attribute ? attribute.pointer : 0', 'i32') }}}; }, @@ -2186,14 +2353,14 @@ var LibraryGL = { function CNaiveListMap() { var list = []; - this.insert = function(key, val) { + this.insert = function CNaiveListMap_insert(key, val) { if (this.contains(key|0)) return false; list.push([key, val]); return true; }; var __contains_i; - this.contains = function(key) { + this.contains = function CNaiveListMap_contains(key) { for (__contains_i = 0; __contains_i < list.length; ++__contains_i) { if (list[__contains_i][0] === key) return true; } @@ -2201,7 +2368,7 @@ var LibraryGL = { }; var __get_i; - this.get = function(key) { + this.get = function CNaiveListMap_get(key) { for (__get_i = 0; __get_i < list.length; ++__get_i) { if (list[__get_i][0] === key) return list[__get_i][1]; } @@ -2235,7 +2402,7 @@ var LibraryGL = { function CNLNode() { var map = new CNaiveListMap(); - this.child = function(keyFrag) { + this.child = function CNLNode_child(keyFrag) { if (!map.contains(keyFrag|0)) { map.insert(keyFrag|0, new CNLNode()); } @@ -2243,11 +2410,11 @@ var LibraryGL = { }; this.value = undefined; - this.get = function() { + this.get = function CNLNode_get() { return this.value; }; - this.set = function(val) { + this.set = function CNLNode_set(val) { this.value = val; }; } @@ -2255,22 +2422,22 @@ var LibraryGL = { function CKeyView(root) { var cur; - this.reset = function() { + this.reset = function CKeyView_reset() { cur = root; return this; }; this.reset(); - this.next = function(keyFrag) { + this.next = function CKeyView_next(keyFrag) { cur = cur.child(keyFrag); return this; }; - this.get = function() { + this.get = function CKeyView_get() { return cur.get(); }; - this.set = function(val) { + this.set = function CKeyView_set(val) { cur.set(val); }; }; @@ -2278,17 +2445,17 @@ var LibraryGL = { var root; var staticKeyView; - this.createKeyView = function() { + this.createKeyView = function CNLNode_createKeyView() { return new CKeyView(root); } - this.clear = function() { + this.clear = function CNLNode_clear() { root = new CNLNode(); staticKeyView = this.createKeyView(); }; this.clear(); - this.getStaticKeyView = function() { + this.getStaticKeyView = function CNLNode_getStaticKeyView() { staticKeyView.reset(); return staticKeyView; }; @@ -2522,7 +2689,7 @@ var LibraryGL = { GL_SRC_ALPHA ]; - this.traverseState = function(keyView) { + this.traverseState = function CTexEnv_traverseState(keyView) { keyView.next(this.mode); keyView.next(this.colorCombiner); keyView.next(this.alphaCombiner); @@ -2558,7 +2725,7 @@ var LibraryGL = { this.enabled_tex3D = false; this.enabled_texCube = false; - this.traverseState = function(keyView) { + this.traverseState = function CTexUnit_traverseState(keyView) { var texUnitType = this.getTexType(); keyView.next(texUnitType); if (!texUnitType) return; @@ -2567,11 +2734,11 @@ var LibraryGL = { }; // Class impls: - CTexUnit.prototype.enabled = function() { + CTexUnit.prototype.enabled = function CTexUnit_enabled() { return this.getTexType() != 0; } - CTexUnit.prototype.genPassLines = function(passOutputVar, passInputVar, texUnitID) { + CTexUnit.prototype.genPassLines = function CTexUnit_genPassLines(passOutputVar, passInputVar, texUnitID) { if (!this.enabled()) { return ["vec4 " + passOutputVar + " = " + passInputVar + ";"]; } @@ -2579,7 +2746,7 @@ var LibraryGL = { return this.env.genPassLines(passOutputVar, passInputVar, texUnitID); } - CTexUnit.prototype.getTexType = function() { + CTexUnit.prototype.getTexType = function CTexUnit_getTexType() { if (this.enabled_texCube) { return GL_TEXTURE_CUBE_MAP; } else if (this.enabled_tex3D) { @@ -2592,7 +2759,7 @@ var LibraryGL = { return 0; } - CTexEnv.prototype.genPassLines = function(passOutputVar, passInputVar, texUnitID) { + CTexEnv.prototype.genPassLines = function CTexEnv_genPassLines(passOutputVar, passInputVar, texUnitID) { switch (this.mode) { case GL_REPLACE: { /* RGB: @@ -2714,9 +2881,9 @@ var LibraryGL = { return Abort_NoSupport("Unsupported TexEnv mode: 0x" + this.mode.toString(16)); } - CTexEnv.prototype.genCombinerLines = function(isColor, outputVar, - passInputVar, texUnitID, - combiner, srcArr, opArr) + CTexEnv.prototype.genCombinerLines = function CTexEnv_getCombinerLines(isColor, outputVar, + passInputVar, texUnitID, + combiner, srcArr, opArr) { var argsNeeded = null; switch (combiner) { @@ -2832,9 +2999,9 @@ var LibraryGL = { } else if (gl) { maxTexUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS); } - +#if ASSERTIONS assert(maxTexUnits > 0); - +#endif s_texUnits = []; for (var i = 0; i < maxTexUnits; i++) { s_texUnits.push(new CTexUnit()); @@ -2893,9 +3060,10 @@ var LibraryGL = { }, getTexUnitType: function(texUnitID) { +#if ASSERTIONS assert(texUnitID >= 0 && texUnitID < s_texUnits.length); - +#endif return s_texUnits[texUnitID].getTexType(); }, @@ -3198,9 +3366,13 @@ var LibraryGL = { if (!GL.immediate.enabledClientAttributes[texAttribName]) continue; +#if ASSERTIONS if (!useCurrProgram) { - assert(GL.immediate.TexEnvJIT.getTexUnitType(i) != 0, "GL_TEXTURE" + i + " coords are supplied, but that texture unit is disabled in the fixed-function pipeline."); + if (GL.immediate.TexEnvJIT.getTexUnitType(i) == 0) { + Runtime.warnOnce("GL_TEXTURE" + i + " coords are supplied, but that texture unit is disabled in the fixed-function pipeline."); + } } +#endif textureSizes[i] = GL.immediate.clientAttributes[texAttribName].size; textureTypes[i] = GL.immediate.clientAttributes[texAttribName].type; |