aboutsummaryrefslogtreecommitdiff
path: root/src/library_gl.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/library_gl.js')
-rw-r--r--src/library_gl.js426
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;