modules/emscripten/src/library_gl.js in webruby-0.1.2 vs modules/emscripten/src/library_gl.js in webruby-0.2.1
- old
+ new
@@ -215,10 +215,27 @@
break;
default:
throw 'Invalid format (' + format + ')';
}
break;
+ case 0x1403 /* GL_UNSIGNED_SHORT */:
+ if (format == 0x1902 /* GL_DEPTH_COMPONENT */) {
+ sizePerPixel = 2;
+ } else {
+ throw 'Invalid format (' + format + ')';
+ }
+ break;
+ case 0x1405 /* GL_UNSIGNED_INT */:
+ if (format == 0x1902 /* GL_DEPTH_COMPONENT */) {
+ sizePerPixel = 4;
+ } else {
+ throw 'Invalid format (' + format + ')';
+ }
+ break;
+ case 0x84FA /* UNSIGNED_INT_24_8_WEBGL */:
+ sizePerPixel = 4;
+ break;
case 0x8363 /* GL_UNSIGNED_SHORT_5_6_5 */:
case 0x8033 /* GL_UNSIGNED_SHORT_4_4_4_4 */:
case 0x8034 /* GL_UNSIGNED_SHORT_5_5_5_1 */:
sizePerPixel = 2;
break;
@@ -242,10 +259,12 @@
var bytes = GL.computeImageSize(width, height, sizePerPixel, GL.unpackAlignment);
if (type == 0x1401 /* GL_UNSIGNED_BYTE */) {
pixels = {{{ makeHEAPView('U8', 'pixels', 'pixels+bytes') }}};
} else if (type == 0x1406 /* GL_FLOAT */) {
pixels = {{{ makeHEAPView('F32', 'pixels', 'pixels+bytes') }}};
+ } else if (type == 0x1405 /* GL_UNSIGNED_INT */ || type == 0x84FA /* UNSIGNED_INT_24_8_WEBGL */) {
+ pixels = {{{ makeHEAPView('U32', 'pixels', 'pixels+bytes') }}};
} else {
pixels = {{{ makeHEAPView('U16', 'pixels', 'pixels+bytes') }}};
}
return {
pixels: pixels,
@@ -289,10 +308,13 @@
used.push(buf);
Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, buf);
Module.ctx.bufferSubData(Module.ctx.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);
}
},
postDrawHandleClientVertexAttribBindings: function() {
@@ -300,10 +322,63 @@
Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, GL.buffers[GL.currArrayBuffer]);
}
},
#endif
+#if GL_ASSERTIONS
+ validateGLObjectID: function(objectHandleArray, objectID, callerFunctionName, objectReadableType) {
+ if (objectID != 0) {
+ if (objectHandleArray[objectID] === null) {
+ console.error(callerFunctionName + ' called with an already deleted ' + objectReadableType + ' ID ' + objectID + '!');
+ } else if (!objectHandleArray[objectID]) {
+ console.error(callerFunctionName + ' called with an invalid ' + objectReadableType + ' ID ' + objectID + '!');
+ }
+ }
+ },
+ // Validates that user obeys GL spec #6.4: http://www.khronos.org/registry/webgl/specs/latest/1.0/#6.4
+ validateVertexAttribPointer: function(dimension, dataType, stride, offset) {
+ var sizeBytes = 1;
+ switch(dataType) {
+ case 0x1400 /* GL_BYTE */:
+ case 0x1401 /* GL_UNSIGNED_BYTE */:
+ sizeBytes = 1;
+ break;
+ case 0x1402 /* GL_SHORT */:
+ case 0x1403 /* GL_UNSIGNED_SHORT */:
+ sizeBytes = 2;
+ break;
+ case 0x1404 /* GL_INT */:
+ case 0x1405 /* GL_UNSIGNED_INT */:
+ case 0x1406 /* GL_FLOAT */:
+ sizeBytes = 4;
+ break;
+ case 0x140A /* GL_DOUBLE */:
+ sizeBytes = 8;
+ break;
+ default:
+ console.error('Invalid vertex attribute data type GLenum ' + dataType + ' passed to GL function!');
+ }
+ if (dimension == 0x80E1 /* GL_BGRA */) {
+ console.error('WebGL does not support size=GL_BGRA in a call to glVertexAttribPointer! Please use size=4 and type=GL_UNSIGNED_BYTE instead!');
+ } else if (dimension < 1 || dimension > 4) {
+ console.error('Invalid dimension='+dimension+' in call to glVertexAttribPointer, must be 1,2,3 or 4.');
+ }
+ if (stride < 0 || stride > 255) {
+ console.error('Invalid stride='+stride+' in call to glVertexAttribPointer. Note that maximum supported stride in WebGL is 255!');
+ }
+ if (offset % sizeBytes != 0) {
+ console.error('GL spec section 6.4 error: vertex attribute data offset of ' + offset + ' bytes should have been a multiple of the data type size that was used: GLenum ' + dataType + ' has size of ' + sizeBytes + ' bytes!');
+ }
+ if (stride % sizeBytes != 0) {
+ console.error('GL spec section 6.4 error: vertex attribute data stride of ' + stride + ' bytes should have been a multiple of the data type size that was used: GLenum ' + dataType + ' has size of ' + sizeBytes + ' bytes!');
+ }
+ },
+#endif
+
+ // In WebGL, extensions must be explicitly enabled to be active, see http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.14
+ // In GLES2, all extensions are enabled by default without additional operations. Init all extensions we need to give to GLES2 user
+ // code here, so that GLES2 code can operate without changing behavior.
initExtensions: function() {
if (GL.initExtensions.done) return;
GL.initExtensions.done = true;
if (!Module.useWebGL) return; // an app might link both gl and 2d backends
@@ -320,22 +395,95 @@
}
GL.generateTempBuffers();
#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.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.floatExt = Module.ctx.getExtension('OES_texture_float');
- GL.elementIndexUintExt = Module.ctx.getExtension('OES_element_index_uint');
- GL.standardDerivativesExt = Module.ctx.getExtension('OES_standard_derivatives');
+ // 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.
+ // As new extensions are ratified at http://www.khronos.org/registry/webgl/extensions/ , feel free to add your new extensions
+ // here, as long as they don't produce a performance impact for users that might not be using those extensions.
+ // E.g. debugging-related extensions should probably be off by default.
+ var automaticallyEnabledExtensions = [ "OES_texture_float", "OES_texture_half_float", "OES_standard_derivatives",
+ "OES_vertex_array_object", "WEBGL_compressed_texture_s3tc", "WEBGL_depth_texture",
+ "OES_element_index_uint", "EXT_texture_filter_anisotropic", "ANGLE_instanced_arrays",
+ "OES_texture_float_linear", "OES_texture_half_float_linear", "WEBGL_compressed_texture_atc",
+ "WEBGL_compressed_texture_pvrtc", "EXT_color_buffer_half_float", "WEBGL_color_buffer_float",
+ "EXT_frag_depth", "EXT_sRGB", "WEBGL_draw_buffers", "WEBGL_shared_resources" ];
+
+ function shouldEnableAutomatically(extension) {
+ for(var i in automaticallyEnabledExtensions) {
+ var include = automaticallyEnabledExtensions[i];
+ if (ext.indexOf(include) != -1) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ var extensions = Module.ctx.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.
+ }
+ }
+ },
+
+ // In WebGL, uniforms in a shader program are accessed through an opaque object type 'WebGLUniformLocation'.
+ // In GLES2, uniforms are accessed via indices. Therefore we must generate a mapping of indices -> WebGLUniformLocations
+ // to provide the client code the API that uses indices.
+ // This function takes a linked GL program and generates a mapping table for the program.
+ // NOTE: Populating the uniform table is performed eagerly at glLinkProgram time, so glLinkProgram should be considered
+ // to be a slow/costly function call. Calling glGetUniformLocation is relatively fast, since it is always a read-only
+ // lookup to the table populated in this function call.
+ populateUniformTable: function(program) {
+#if GL_ASSERTIONS
+ 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.
+ // 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;
+ // Strip off any trailing array specifier we might have got, e.g. "[0]".
+ if (name.indexOf(']', name.length-1) !== -1) {
+ var ls = name.lastIndexOf('[');
+ name = name.slice(0, ls);
+ }
+
+ // 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.
+ // 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];
+ GL.uniforms[id] = loc;
+
+ for (var j = 1; j < u.size; ++j) {
+ var n = name + '['+j+']';
+ loc = Module.ctx.getUniformLocation(p, n);
+ id = GL.getNewId(GL.uniforms);
+
+ GL.uniforms[id] = loc;
+ }
+ }
}
},
glPixelStorei__sig: 'vii',
glPixelStorei: function(pname, param) {
@@ -353,11 +501,17 @@
case 0x1F00 /* GL_VENDOR */:
case 0x1F01 /* GL_RENDERER */:
case 0x1F02 /* GL_VERSION */:
return allocate(intArrayFromString(Module.ctx.getParameter(name_)), 'i8', ALLOC_NORMAL);
case 0x1F03 /* GL_EXTENSIONS */:
- return allocate(intArrayFromString(Module.ctx.getSupportedExtensions().join(' ')), 'i8', ALLOC_NORMAL);
+ var exts = Module.ctx.getSupportedExtensions();
+ var gl_exts = [];
+ for (i in exts) {
+ 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.
case 0x8B8C /* GL_SHADING_LANGUAGE_VERSION */:
return allocate(intArrayFromString('OpenGL ES GLSL 1.00 (WebGL)'), 'i8', ALLOC_NORMAL);
default:
throw 'Failure: Invalid glGetString value: ' + name_;
}
@@ -586,10 +740,13 @@
Module.ctx.readPixels(x, y, width, height, format, type, HEAPU8.subarray(pixels, pixels + totalSize));
},
glBindTexture__sig: 'vii',
glBindTexture: function(target, texture) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.textures, texture, 'glBindTexture', 'texture');
+#endif
Module.ctx.bindTexture(target, texture ? GL.textures[texture] : null);
},
glGetTexParameterfv__sig: 'viii',
glGetTexParameterfv: function(target, pname, params) {
@@ -655,10 +812,24 @@
{{{ makeSetValue('data', '0', 'Module.ctx.getBufferParameter(target, value)', 'i32') }}};
},
glBufferData__sig: 'viiii',
glBufferData: function(target, size, data, usage) {
+ switch (usage) { // fix usages, WebGL only has *_DRAW
+ case 0x88E1: // GL_STREAM_READ
+ case 0x88E2: // GL_STREAM_COPY
+ usage = 0x88E0; // GL_STREAM_DRAW
+ break;
+ case 0x88E5: // GL_STATIC_READ
+ case 0x88E6: // GL_STATIC_COPY
+ usage = 0x88E4; // GL_STATIC_DRAW
+ break;
+ case 0x88E9: // GL_DYNAMIC_READ
+ case 0x88EA: // GL_DYNAMIC_COPY
+ usage = 0x88E8; // GL_DYNAMIC_DRAW
+ break;
+ }
Module.ctx.bufferData(target, HEAPU8.subarray(data, data+size), usage);
},
glBufferSubData__sig: 'viiii',
glBufferSubData: function(target, offset, size, data) {
@@ -694,10 +865,13 @@
}
},
glBindRenderbuffer__sig: 'vii',
glBindRenderbuffer: function(target, renderbuffer) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.renderbuffers, renderbuffer, 'glBindRenderbuffer', 'renderbuffer');
+#endif
Module.ctx.bindRenderbuffer(target, renderbuffer ? GL.renderbuffers[renderbuffer] : null);
},
glGetRenderbufferParameteriv__sig: 'viii',
glGetRenderbufferParameteriv: function(target, pname, params) {
@@ -711,10 +885,14 @@
return Module.ctx.isRenderbuffer(rb);
},
glGetUniformfv__sig: 'viii',
glGetUniformfv: function(program, location, params) {
+#if GL_ASSERTIONS
+ 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]);
if (typeof data == 'number') {
{{{ makeSetValue('params', '0', 'data', 'float') }}};
} else {
for (var i = 0; i < data.length; i++) {
@@ -723,10 +901,14 @@
}
},
glGetUniformiv__sig: 'viii',
glGetUniformiv: function(program, location, params) {
+#if GL_ASSERTIONS
+ 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]);
if (typeof data == 'number' || typeof data == 'boolean') {
{{{ makeSetValue('params', '0', 'data', 'i32') }}};
} else {
for (var i = 0; i < data.length; i++) {
@@ -735,21 +917,39 @@
}
},
glGetUniformLocation__sig: 'iii',
glGetUniformLocation: function(program, name) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glGetUniformLocation', 'program');
+#endif
name = Pointer_stringify(name);
+
+ var arrayOffset = 0;
+ // If user passed an array accessor "[index]", parse the array index off the accessor.
+ if (name.indexOf(']', name.length-1) !== -1) {
+ var ls = name.lastIndexOf('[');
+ var arrayIndex = name.slice(ls+1, -1);
+ if (arrayIndex.length > 0) {
+ arrayOffset = parseInt(arrayIndex);
+ if (arrayOffset < 0) {
+ return -1;
+ }
+ }
+ name = name.slice(0, ls);
+ }
+
var ptable = GL.uniformTable[program];
- if (!ptable) ptable = GL.uniformTable[program] = {};
- var id = ptable[name];
- if (id) return id;
- var loc = Module.ctx.getUniformLocation(GL.programs[program], name);
- if (!loc) return -1;
- id = GL.getNewId(GL.uniforms);
- GL.uniforms[id] = loc;
- ptable[name] = id;
- return id;
+ if (!ptable) {
+ return -1;
+ }
+ var uniformInfo = ptable[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 {
+ return -1;
+ }
},
glGetVertexAttribfv__sig: 'viii',
glGetVertexAttribfv: function(index, pname, params) {
#if FULL_ES2
@@ -794,10 +994,13 @@
{{{ makeSetValue('pointer', '0', 'Module.ctx.getVertexAttribOffset(index, pname)', 'i32') }}};
},
glGetActiveUniform__sig: 'viiiiiii',
glGetActiveUniform: function(program, index, bufSize, length, size, type, name) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glGetActiveUniform', 'program');
+#endif
program = GL.programs[program];
var info = Module.ctx.getActiveUniform(program, index);
var infoname = info.name.slice(0, Math.max(0, bufSize - 1));
writeStringToMemory(infoname, name);
@@ -813,89 +1016,128 @@
}
},
glUniform1f__sig: 'vif',
glUniform1f: function(location, v0) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.uniforms, location, 'glUniform1f', 'location');
+#endif
location = GL.uniforms[location];
Module.ctx.uniform1f(location, v0);
},
glUniform2f__sig: 'viff',
glUniform2f: function(location, v0, v1) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.uniforms, location, 'glUniform2f', 'location');
+#endif
location = GL.uniforms[location];
Module.ctx.uniform2f(location, v0, v1);
},
glUniform3f__sig: 'vifff',
glUniform3f: function(location, v0, v1, v2) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.uniforms, location, 'glUniform3f', 'location');
+#endif
location = GL.uniforms[location];
Module.ctx.uniform3f(location, v0, v1, v2);
},
glUniform4f__sig: 'viffff',
glUniform4f: function(location, v0, v1, v2, v3) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.uniforms, location, 'glUniform4f', 'location');
+#endif
location = GL.uniforms[location];
Module.ctx.uniform4f(location, v0, v1, v2, v3);
},
glUniform1i__sig: 'vii',
glUniform1i: function(location, v0) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.uniforms, location, 'glUniform1i', 'location');
+#endif
location = GL.uniforms[location];
Module.ctx.uniform1i(location, v0);
},
glUniform2i__sig: 'viii',
glUniform2i: function(location, v0, v1) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.uniforms, location, 'glUniform2i', 'location');
+#endif
location = GL.uniforms[location];
Module.ctx.uniform2i(location, v0, v1);
},
glUniform3i__sig: 'viiii',
glUniform3i: function(location, v0, v1, v2) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.uniforms, location, 'glUniform3i', 'location');
+#endif
location = GL.uniforms[location];
Module.ctx.uniform3i(location, v0, v1, v2);
},
glUniform4i__sig: 'viiiii',
glUniform4i: function(location, v0, v1, v2, v3) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.uniforms, location, 'glUniform4i', 'location');
+#endif
location = GL.uniforms[location];
Module.ctx.uniform4i(location, v0, v1, v2, v3);
},
glUniform1iv__sig: 'viii',
glUniform1iv: function(location, count, value) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.uniforms, location, 'glUniform1iv', 'location');
+#endif
location = GL.uniforms[location];
value = {{{ makeHEAPView('32', 'value', 'value+count*4') }}};
Module.ctx.uniform1iv(location, value);
},
glUniform2iv__sig: 'viii',
glUniform2iv: function(location, count, value) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.uniforms, location, 'glUniform2iv', 'location');
+#endif
location = GL.uniforms[location];
count *= 2;
value = {{{ makeHEAPView('32', 'value', 'value+count*4') }}};
Module.ctx.uniform2iv(location, value);
},
glUniform3iv__sig: 'viii',
glUniform3iv: function(location, count, value) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.uniforms, location, 'glUniform3iv', 'location');
+#endif
location = GL.uniforms[location];
count *= 3;
value = {{{ makeHEAPView('32', 'value', 'value+count*4') }}};
Module.ctx.uniform3iv(location, value);
},
glUniform4iv__sig: 'viii',
glUniform4iv: function(location, count, value) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.uniforms, location, 'glUniform4iv', 'location');
+#endif
location = GL.uniforms[location];
count *= 4;
value = {{{ makeHEAPView('32', 'value', 'value+count*4') }}};
Module.ctx.uniform4iv(location, value);
},
glUniform1fv__sig: 'viii',
glUniform1fv: function(location, count, value) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.uniforms, location, 'glUniform1fv', 'location');
+#endif
location = GL.uniforms[location];
var view;
if (count == 1) {
// avoid allocation for the common case of uploading one uniform
view = GL.miniTempBufferViews[0];
@@ -906,10 +1148,13 @@
Module.ctx.uniform1fv(location, view);
},
glUniform2fv__sig: 'viii',
glUniform2fv: function(location, count, value) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.uniforms, location, 'glUniform2fv', 'location');
+#endif
location = GL.uniforms[location];
var view;
if (count == 1) {
// avoid allocation for the common case of uploading one uniform
view = GL.miniTempBufferViews[1];
@@ -921,10 +1166,13 @@
Module.ctx.uniform2fv(location, view);
},
glUniform3fv__sig: 'viii',
glUniform3fv: function(location, count, value) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.uniforms, location, 'glUniform3fv', 'location');
+#endif
location = GL.uniforms[location];
var view;
if (count == 1) {
// avoid allocation for the common case of uploading one uniform
view = GL.miniTempBufferViews[2];
@@ -937,10 +1185,13 @@
Module.ctx.uniform3fv(location, view);
},
glUniform4fv__sig: 'viii',
glUniform4fv: function(location, count, value) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.uniforms, location, 'glUniform4fv', 'location');
+#endif
location = GL.uniforms[location];
var view;
if (count == 1) {
// avoid allocation for the common case of uploading one uniform
view = GL.miniTempBufferViews[3];
@@ -954,10 +1205,13 @@
Module.ctx.uniform4fv(location, view);
},
glUniformMatrix2fv__sig: 'viiii',
glUniformMatrix2fv: function(location, count, transpose, value) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.uniforms, location, 'glUniformMatrix2fv', 'location');
+#endif
location = GL.uniforms[location];
var view;
if (count == 1) {
// avoid allocation for the common case of uploading one uniform matrix
view = GL.miniTempBufferViews[3];
@@ -970,10 +1224,13 @@
Module.ctx.uniformMatrix2fv(location, transpose, view);
},
glUniformMatrix3fv__sig: 'viiii',
glUniformMatrix3fv: function(location, count, transpose, value) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.uniforms, location, 'glUniformMatrix3fv', 'location');
+#endif
location = GL.uniforms[location];
var view;
if (count == 1) {
// avoid allocation for the common case of uploading one uniform matrix
view = GL.miniTempBufferViews[8];
@@ -986,10 +1243,13 @@
Module.ctx.uniformMatrix3fv(location, transpose, view);
},
glUniformMatrix4fv__sig: 'viiii',
glUniformMatrix4fv: function(location, count, transpose, value) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.uniforms, location, 'glUniformMatrix4fv', 'location');
+#endif
location = GL.uniforms[location];
var view;
if (count == 1) {
// avoid allocation for the common case of uploading one uniform matrix
view = GL.miniTempBufferViews[15];
@@ -1002,10 +1262,13 @@
Module.ctx.uniformMatrix4fv(location, transpose, view);
},
glBindBuffer__sig: 'vii',
glBindBuffer: function(target, buffer) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.buffers, buffer, 'glBindBuffer', 'buffer');
+#endif
var bufferObj = buffer ? GL.buffers[buffer] : null;
if (target == Module.ctx.ARRAY_BUFFER) {
GL.currArrayBuffer = buffer;
} else if (target == Module.ctx.ELEMENT_ARRAY_BUFFER) {
@@ -1046,10 +1309,13 @@
return Module.ctx.getAttribLocation(program, name);
},
glGetActiveAttrib__sig: 'viiiiiii',
glGetActiveAttrib: function(program, index, bufSize, length, size, type, name) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glGetActiveAttrib', 'program');
+#endif
program = GL.programs[program];
var info = Module.ctx.getActiveAttrib(program, index);
var infoname = info.name.slice(0, Math.max(0, bufSize - 1));
writeStringToMemory(infoname, name);
@@ -1078,10 +1344,13 @@
GL.shaders[shader] = null;
},
glGetAttachedShaders__sig: 'viiii',
glGetAttachedShaders: function(program, maxCount, count, shaders) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glGetAttachedShaders', 'program');
+#endif
var result = Module.ctx.getAttachedShaders(GL.programs[program]);
var len = result.length;
if (len > maxCount) {
len = maxCount;
}
@@ -1093,31 +1362,43 @@
}
},
glShaderSource__sig: 'viiii',
glShaderSource: function(shader, count, string, length) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.shaders, shader, 'glShaderSource', 'shader');
+#endif
var source = GL.getSource(shader, count, string, length);
Module.ctx.shaderSource(GL.shaders[shader], source);
},
glGetShaderSource__sig: 'viiii',
glGetShaderSource: function(shader, bufSize, length, source) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.shaders, shader, 'glGetShaderSource', 'shader');
+#endif
var result = Module.ctx.getShaderSource(GL.shaders[shader]);
result = result.slice(0, Math.max(0, bufSize - 1));
writeStringToMemory(result, source);
if (length) {
{{{ makeSetValue('length', '0', 'result.length', 'i32') }}};
}
},
glCompileShader__sig: 'vi',
glCompileShader: function(shader) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.shaders, shader, 'glCompileShader', 'shader');
+#endif
Module.ctx.compileShader(GL.shaders[shader]);
},
glGetShaderInfoLog__sig: 'viiii',
glGetShaderInfoLog: function(shader, maxLength, length, infoLog) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.shaders, shader, 'glGetShaderInfoLog', 'shader');
+#endif
var log = Module.ctx.getShaderInfoLog(GL.shaders[shader]);
// Work around a bug in Chromium which causes getShaderInfoLog to return null
if (!log) {
log = "";
}
@@ -1128,19 +1409,25 @@
}
},
glGetShaderiv__sig: 'viii',
glGetShaderiv : function(shader, pname, p) {
+#if GL_ASSERTIONS
+ 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') }}};
} else {
{{{ makeSetValue('p', '0', 'Module.ctx.getShaderParameter(GL.shaders[shader], pname)', 'i32') }}};
}
},
glGetProgramiv__sig: 'viii',
glGetProgramiv : function(program, pname, p) {
+#if GL_ASSERTIONS
+ 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') }}};
} else {
{{{ makeSetValue('p', '0', 'Module.ctx.getProgramParameter(GL.programs[program], pname)', 'i32') }}};
}
@@ -1171,16 +1458,24 @@
GL.uniformTable[program] = null;
},
glAttachShader__sig: 'vii',
glAttachShader: function(program, shader) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glAttachShader', 'program');
+ GL.validateGLObjectID(GL.shaders, shader, 'glAttachShader', 'shader');
+#endif
Module.ctx.attachShader(GL.programs[program],
GL.shaders[shader]);
},
glDetachShader__sig: 'vii',
glDetachShader: function(program, shader) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glDetachShader', 'program');
+ GL.validateGLObjectID(GL.shaders, shader, 'glDetachShader', 'shader');
+#endif
Module.ctx.detachShader(GL.programs[program],
GL.shaders[shader]);
},
glGetShaderPrecisionFormat: function(shaderType, precisionType, range, precision) {
@@ -1190,16 +1485,23 @@
{{{ makeSetValue('precision', '0', 'result.precision', 'i32') }}};
},
glLinkProgram__sig: 'vi',
glLinkProgram: function(program) {
+#if GL_ASSERTIONS
+ 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.populateUniformTable(program);
},
glGetProgramInfoLog__sig: 'viiii',
glGetProgramInfoLog: function(program, maxLength, length, infoLog) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glGetProgramInfoLog', 'program');
+#endif
var log = Module.ctx.getProgramInfoLog(GL.programs[program]);
// Work around a bug in Chromium which causes getProgramInfoLog to return null
if (!log) {
log = "";
}
@@ -1210,15 +1512,21 @@
}
},
glUseProgram__sig: 'vi',
glUseProgram: function(program) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glUseProgram', 'program');
+#endif
Module.ctx.useProgram(program ? GL.programs[program] : null);
},
glValidateProgram__sig: 'vi',
glValidateProgram: function(program) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glValidateProgram', 'program');
+#endif
Module.ctx.validateProgram(GL.programs[program]);
},
glIsProgram__sig: 'ii',
glIsProgram: function(program) {
@@ -1227,16 +1535,22 @@
return Module.ctx.isProgram(program);
},
glBindAttribLocation__sig: 'viii',
glBindAttribLocation: function(program, index, name) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glBindAttribLocation', 'program');
+#endif
name = Pointer_stringify(name);
Module.ctx.bindAttribLocation(GL.programs[program], index, name);
},
glBindFramebuffer__sig: 'vii',
glBindFramebuffer: function(target, framebuffer) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.framebuffers, framebuffer, 'glBindFramebuffer', 'framebuffer');
+#endif
Module.ctx.bindFramebuffer(target, framebuffer ? GL.framebuffers[framebuffer] : null);
},
glGenFramebuffers__sig: 'vii',
glGenFramebuffers: function(n, ids) {
@@ -1260,16 +1574,22 @@
}
},
glFramebufferRenderbuffer__sig: 'viiii',
glFramebufferRenderbuffer: function(target, attachment, renderbuffertarget, renderbuffer) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.renderbuffers, renderbuffer, 'glFramebufferRenderbuffer', 'renderbuffer');
+#endif
Module.ctx.framebufferRenderbuffer(target, attachment, renderbuffertarget,
GL.renderbuffers[renderbuffer]);
},
glFramebufferTexture2D__sig: 'viiiii',
glFramebufferTexture2D: function(target, attachment, textarget, texture, level) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.textures, texture, 'glFramebufferTexture2D', 'texture');
+#endif
Module.ctx.framebufferTexture2D(target, attachment, textarget,
GL.textures[texture], level);
},
glGetFramebufferAttachmentParameteriv__sig: 'viiii',
@@ -1283,14 +1603,15 @@
var fb = GL.framebuffers[framebuffer];
if (!fb) return 0;
return Module.ctx.isFramebuffer(fb);
},
-#if DISABLE_GL_EMULATION == 0
+#if LEGACY_GL_EMULATION
// GL emulation: provides misc. functionality not present in OpenGL ES 2.0 or WebGL
+ $GLEmulation__deps: ['$GLImmediateSetup', 'glEnable', 'glDisable', 'glIsEnabled', 'glGetBooleanv', 'glGetIntegerv', 'glGetString', 'glCreateShader', 'glShaderSource', 'glCompileShader', 'glAttachShader', 'glDetachShader', 'glUseProgram', 'glDeleteProgram', 'glBindAttribLocation', 'glLinkProgram', 'glBindBuffer', 'glGetFloatv', 'glHint', 'glEnableVertexAttribArray', 'glDisableVertexAttribArray', 'glVertexAttribPointer', 'glActiveTexture'],
$GLEmulation__postset: 'GLEmulation.init();',
$GLEmulation: {
// Fog support. Partial, we assume shaders are used that implement fog. We just pass them uniforms
fogStart: 0,
fogEnd: 1,
@@ -1321,11 +1642,11 @@
GLEmulation.hasRunInit = true;
GLEmulation.fogColor = new Float32Array(4);
// Add some emulation workarounds
- Module.printErr('WARNING: using emscripten GL emulation. This is a collection of limited workarounds, do not expect it to work. (If you do not want this, build with -s DISABLE_GL_EMULATION=1)');
+ Module.printErr('WARNING: using emscripten GL emulation. This is a collection of limited workarounds, do not expect it to work.');
#if GL_UNSAFE_OPTS == 0
Module.printErr('WARNING: using emscripten GL emulation unsafe opts. If weirdness happens, try -s GL_UNSAFE_OPTS=0');
#endif
// XXX some of the capabilities we don't support may lead to incorrect rendering, if we do not emulate them in shaders
@@ -1616,21 +1937,19 @@
};
var glCompileShader = _glCompileShader;
_glCompileShader = function(shader) {
Module.ctx.compileShader(GL.shaders[shader]);
+#if GL_DEBUG
if (!Module.ctx.getShaderParameter(GL.shaders[shader], Module.ctx.COMPILE_STATUS)) {
Module.printErr('Failed to compile shader: ' + Module.ctx.getShaderInfoLog(GL.shaders[shader]));
Module.printErr('Info: ' + JSON.stringify(GL.shaderInfos[shader]));
-#if GL_DEBUG
Module.printErr('Original source: ' + GL.shaderOriginalSources[shader]);
Module.printErr('Source: ' + GL.shaderSources[shader]);
throw 'Shader compilation halt';
-#else
- Module.printErr('Enable GL_DEBUG to see shader source');
-#endif
}
+#endif
};
GL.programShaders = {};
var glAttachShader = _glAttachShader;
_glAttachShader = function(program, shader) {
@@ -1773,174 +2092,10 @@
case 0x8076: // GL_COLOR_ARRAY
attrib = GL.immediate.COLOR; break;
}
return attrib;
},
-
- getProcAddress: function(name) {
- name = name.replace('EXT', '').replace('ARB', '');
- // Do the translation carefully because of closure
- var ret = 0;
- switch (name) {
- case 'glCreateShaderObject': case 'glCreateShader': ret = {{{ Functions.getIndex('_glCreateShader', true) }}}; break;
- case 'glCreateProgramObject': case 'glCreateProgram': ret = {{{ Functions.getIndex('_glCreateProgram', true) }}}; break;
- case 'glAttachObject': case 'glAttachShader': ret = {{{ Functions.getIndex('_glAttachShader', true) }}}; break;
- case 'glUseProgramObject': case 'glUseProgram': ret = {{{ Functions.getIndex('_glUseProgram', true) }}}; break;
- case 'glDetachObject': case 'glDetachShader': ret = {{{ Functions.getIndex('_glDetachShader', true) }}}; break;
- case 'glDeleteObject': ret = {{{ Functions.getIndex('_glDeleteObject', true) }}}; break;
- case 'glGetObjectParameteriv': ret = {{{ Functions.getIndex('_glGetObjectParameteriv', true) }}}; break;
- case 'glGetInfoLog': ret = {{{ Functions.getIndex('_glGetInfoLog', true) }}}; break;
- case 'glBindProgram': ret = {{{ Functions.getIndex('_glBindProgram', true) }}}; break;
- case 'glDrawRangeElements': ret = {{{ Functions.getIndex('_glDrawRangeElements', true) }}}; break;
- case 'glShaderSource': ret = {{{ Functions.getIndex('_glShaderSource', true) }}}; break;
- case 'glCompileShader': ret = {{{ Functions.getIndex('_glCompileShader', true) }}}; break;
- case 'glLinkProgram': ret = {{{ Functions.getIndex('_glLinkProgram', true) }}}; break;
- case 'glGetUniformLocation': ret = {{{ Functions.getIndex('_glGetUniformLocation', true) }}}; break;
- case 'glUniform1f': ret = {{{ Functions.getIndex('_glUniform1f', true) }}}; break;
- case 'glUniform2f': ret = {{{ Functions.getIndex('_glUniform2f', true) }}}; break;
- case 'glUniform3f': ret = {{{ Functions.getIndex('_glUniform3f', true) }}}; break;
- case 'glUniform4f': ret = {{{ Functions.getIndex('_glUniform4f', true) }}}; break;
- case 'glUniform1fv': ret = {{{ Functions.getIndex('_glUniform1fv', true) }}}; break;
- case 'glUniform2fv': ret = {{{ Functions.getIndex('_glUniform2fv', true) }}}; break;
- case 'glUniform3fv': ret = {{{ Functions.getIndex('_glUniform3fv', true) }}}; break;
- case 'glUniform4fv': ret = {{{ Functions.getIndex('_glUniform4fv', true) }}}; break;
- case 'glUniform1i': ret = {{{ Functions.getIndex('_glUniform1i', true) }}}; break;
- case 'glUniform2i': ret = {{{ Functions.getIndex('_glUniform2i', true) }}}; break;
- case 'glUniform3i': ret = {{{ Functions.getIndex('_glUniform3i', true) }}}; break;
- case 'glUniform4i': ret = {{{ Functions.getIndex('_glUniform4i', true) }}}; break;
- case 'glUniform1iv': ret = {{{ Functions.getIndex('_glUniform1iv', true) }}}; break;
- case 'glUniform2iv': ret = {{{ Functions.getIndex('_glUniform2iv', true) }}}; break;
- case 'glUniform3iv': ret = {{{ Functions.getIndex('_glUniform3iv', true) }}}; break;
- case 'glUniform4iv': ret = {{{ Functions.getIndex('_glUniform4iv', true) }}}; break;
- case 'glBindAttribLocation': ret = {{{ Functions.getIndex('_glBindAttribLocation', true) }}}; break;
- case 'glGetActiveUniform': ret = {{{ Functions.getIndex('_glGetActiveUniform', true) }}}; break;
- case 'glGenBuffers': ret = {{{ Functions.getIndex('_glGenBuffers', true) }}}; break;
- case 'glBindBuffer': ret = {{{ Functions.getIndex('_glBindBuffer', true) }}}; break;
- case 'glBufferData': ret = {{{ Functions.getIndex('_glBufferData', true) }}}; break;
- case 'glBufferSubData': ret = {{{ Functions.getIndex('_glBufferSubData', true) }}}; break;
- case 'glDeleteBuffers': ret = {{{ Functions.getIndex('_glDeleteBuffers', true) }}}; break;
- case 'glActiveTexture': ret = {{{ Functions.getIndex('_glActiveTexture', true) }}}; break;
- case 'glClientActiveTexture': ret = {{{ Functions.getIndex('_glClientActiveTexture', true) }}}; break;
- case 'glGetProgramiv': ret = {{{ Functions.getIndex('_glGetProgramiv', true) }}}; break;
- case 'glEnableVertexAttribArray': ret = {{{ Functions.getIndex('_glEnableVertexAttribArray', true) }}}; break;
- case 'glDisableVertexAttribArray': ret = {{{ Functions.getIndex('_glDisableVertexAttribArray', true) }}}; break;
- case 'glVertexAttribPointer': ret = {{{ Functions.getIndex('_glVertexAttribPointer', true) }}}; break;
- case 'glVertexAttrib1f': ret = {{{ Functions.getIndex('_glVertexAttrib1f', true) }}}; break;
- case 'glVertexAttrib2f': ret = {{{ Functions.getIndex('_glVertexAttrib2f', true) }}}; break;
- case 'glVertexAttrib3f': ret = {{{ Functions.getIndex('_glVertexAttrib3f', true) }}}; break;
- case 'glVertexAttrib4f': ret = {{{ Functions.getIndex('_glVertexAttrib4f', true) }}}; break;
- case 'glVertexAttrib1fv': ret = {{{ Functions.getIndex('_glVertexAttrib1fv', true) }}}; break;
- case 'glVertexAttrib2fv': ret = {{{ Functions.getIndex('_glVertexAttrib2fv', true) }}}; break;
- case 'glVertexAttrib3fv': ret = {{{ Functions.getIndex('_glVertexAttrib3fv', true) }}}; break;
- case 'glVertexAttrib4fv': ret = {{{ Functions.getIndex('_glVertexAttrib4fv', true) }}}; break;
- case 'glGetVertexAttribfv': ret = {{{ Functions.getIndex('_glGetVertexAttribfv', true) }}}; break;
- case 'glGetVertexAttribiv': ret = {{{ Functions.getIndex('_glGetVertexAttribiv', true) }}}; break;
- case 'glGetVertexAttribPointerv': ret = {{{ Functions.getIndex('_glGetVertexAttribPointerv', true) }}}; break;
- case 'glGetAttribLocation': ret = {{{ Functions.getIndex('_glGetAttribLocation', true) }}}; break;
- case 'glGetActiveAttrib': ret = {{{ Functions.getIndex('_glGetActiveAttrib', true) }}}; break;
- case 'glBindRenderbuffer': ret = {{{ Functions.getIndex('_glBindRenderbuffer', true) }}}; break;
- case 'glDeleteRenderbuffers': ret = {{{ Functions.getIndex('_glDeleteRenderbuffers', true) }}}; break;
- case 'glGenRenderbuffers': ret = {{{ Functions.getIndex('_glGenRenderbuffers', true) }}}; break;
- case 'glCompressedTexImage2D': ret = {{{ Functions.getIndex('_glCompressedTexImage2D', true) }}}; break;
- case 'glCompressedTexSubImage2D': ret = {{{ Functions.getIndex('_glCompressedTexSubImage2D', true) }}}; break;
- case 'glBindFramebuffer': ret = {{{ Functions.getIndex('_glBindFramebuffer', true) }}}; break;
- case 'glGenFramebuffers': ret = {{{ Functions.getIndex('_glGenFramebuffers', true) }}}; break;
- case 'glDeleteFramebuffers': ret = {{{ Functions.getIndex('_glDeleteFramebuffers', true) }}}; break;
- case 'glFramebufferRenderbuffer': ret = {{{ Functions.getIndex('_glFramebufferRenderbuffer', true) }}}; break;
- case 'glFramebufferTexture2D': ret = {{{ Functions.getIndex('_glFramebufferTexture2D', true) }}}; break;
- case 'glGetFramebufferAttachmentParameteriv': ret = {{{ Functions.getIndex('_glGetFramebufferAttachmentParameteriv', true) }}}; break;
- case 'glIsFramebuffer': ret = {{{ Functions.getIndex('_glIsFramebuffer', true) }}}; break;
- case 'glCheckFramebufferStatus': ret = {{{ Functions.getIndex('_glCheckFramebufferStatus', true) }}}; break;
- case 'glRenderbufferStorage': ret = {{{ Functions.getIndex('_glRenderbufferStorage', true) }}}; break;
- case 'glGenVertexArrays': ret = {{{ Functions.getIndex('_glGenVertexArrays', true) }}}; break;
- case 'glDeleteVertexArrays': ret = {{{ Functions.getIndex('_glDeleteVertexArrays', true) }}}; break;
- case 'glBindVertexArray': ret = {{{ Functions.getIndex('_glBindVertexArray', true) }}}; break;
- case 'glGetString': ret = {{{ Functions.getIndex('_glGetString', true) }}}; break;
- case 'glBindTexture': ret = {{{ Functions.getIndex('_glBindTexture', true) }}}; break;
- case 'glGetBufferParameteriv': ret = {{{ Functions.getIndex('_glGetBufferParameteriv', true) }}}; break;
- case 'glIsBuffer': ret = {{{ Functions.getIndex('_glIsBuffer', true) }}}; break;
- case 'glDeleteShader': ret = {{{ Functions.getIndex('_glDeleteShader', true) }}}; break;
- case 'glUniformMatrix2fv': ret = {{{ Functions.getIndex('_glUniformMatrix2fv', true) }}}; break;
- case 'glUniformMatrix3fv': ret = {{{ Functions.getIndex('_glUniformMatrix3fv', true) }}}; break;
- case 'glUniformMatrix4fv': ret = {{{ Functions.getIndex('_glUniformMatrix4fv', true) }}}; break;
- case 'glIsRenderbuffer': ret = {{{ Functions.getIndex('_glIsRenderbuffer', true) }}}; break;
- case 'glBlendEquation': ret = {{{ Functions.getIndex('_glBlendEquation', true) }}}; break;
- case 'glBlendFunc': ret = {{{ Functions.getIndex('_glBlendFunc', true) }}}; break;
- case 'glBlendFuncSeparate': ret = {{{ Functions.getIndex('_glBlendFuncSeparate', true) }}}; break;
- case 'glBlendEquationSeparate': ret = {{{ Functions.getIndex('_glBlendEquationSeparate', true) }}}; break;
- case 'glDepthRangef': ret = {{{ Functions.getIndex('_glDepthRangef', true) }}}; break;
- case 'glClear': ret = {{{ Functions.getIndex('_glClear', true) }}}; break;
- case 'glGenerateMipmap': ret = {{{ Functions.getIndex('_glGenerateMipmap', true) }}}; break;
- case 'glBlendColor': ret = {{{ Functions.getIndex('_glBlendColor', true) }}}; break;
- case 'glClearDepthf': ret = {{{ Functions.getIndex('_glClearDepthf', true) }}}; break;
- case 'glDeleteProgram': ret = {{{ Functions.getIndex('_glDeleteProgram', true) }}}; break;
- case 'glUniformMatrix3fv': ret = {{{ Functions.getIndex('_glUniformMatrix3fv', true) }}}; break;
- case 'glClearColor': ret = {{{ Functions.getIndex('_glClearColor', true) }}}; break;
- case 'glGetRenderbufferParameteriv': ret = {{{ Functions.getIndex('_glGetRenderbufferParameteriv', true) }}}; break;
- case 'glGetShaderInfoLog': ret = {{{ Functions.getIndex('_glGetShaderInfoLog', true) }}}; break;
- case 'glUniformMatrix4fv': ret = {{{ Functions.getIndex('_glUniformMatrix4fv', true) }}}; break;
- case 'glClearStencil': ret = {{{ Functions.getIndex('_glClearStencil', true) }}}; break;
- case 'glGetProgramInfoLog': ret = {{{ Functions.getIndex('_glGetProgramInfoLog', true) }}}; break;
- case 'glGetUniformfv': ret = {{{ Functions.getIndex('_glGetUniformfv', true) }}}; break;
- case 'glStencilFuncSeparate': ret = {{{ Functions.getIndex('_glStencilFuncSeparate', true) }}}; break;
- case 'glSampleCoverage': ret = {{{ Functions.getIndex('_glSampleCoverage', true) }}}; break;
- case 'glColorMask': ret = {{{ Functions.getIndex('_glColorMask', true) }}}; break;
- case 'glGetShaderiv': ret = {{{ Functions.getIndex('_glGetShaderiv', true) }}}; break;
- case 'glGetUniformiv': ret = {{{ Functions.getIndex('_glGetUniformiv', true) }}}; break;
- case 'glCopyTexSubImage2D': ret = {{{ Functions.getIndex('_glCopyTexSubImage2D', true) }}}; break;
- case 'glDetachShader': ret = {{{ Functions.getIndex('_glDetachShader', true) }}}; break;
- case 'glGetShaderSource': ret = {{{ Functions.getIndex('_glGetShaderSource', true) }}}; break;
- case 'glDeleteTextures': ret = {{{ Functions.getIndex('_glDeleteTextures', true) }}}; break;
- case 'glGetAttachedShaders': ret = {{{ Functions.getIndex('_glGetAttachedShaders', true) }}}; break;
- case 'glValidateProgram': ret = {{{ Functions.getIndex('_glValidateProgram', true) }}}; break;
- case 'glDepthFunc': ret = {{{ Functions.getIndex('_glDepthFunc', true) }}}; break;
- case 'glIsShader': ret = {{{ Functions.getIndex('_glIsShader', true) }}}; break;
- case 'glDepthMask': ret = {{{ Functions.getIndex('_glDepthMask', true) }}}; break;
- case 'glStencilMaskSeparate': ret = {{{ Functions.getIndex('_glStencilMaskSeparate', true) }}}; break;
- case 'glIsProgram': ret = {{{ Functions.getIndex('_glIsProgram', true) }}}; break;
- case 'glDisable': ret = {{{ Functions.getIndex('_glDisable', true) }}}; break;
- case 'glStencilOpSeparate': ret = {{{ Functions.getIndex('_glStencilOpSeparate', true) }}}; break;
- case 'glDrawArrays': ret = {{{ Functions.getIndex('_glDrawArrays', true) }}}; break;
- case 'glDrawElements': ret = {{{ Functions.getIndex('_glDrawElements', true) }}}; break;
- case 'glEnable': ret = {{{ Functions.getIndex('_glEnable', true) }}}; break;
- case 'glFinish': ret = {{{ Functions.getIndex('_glFinish', true) }}}; break;
- case 'glFlush': ret = {{{ Functions.getIndex('_glFlush', true) }}}; break;
- case 'glFrontFace': ret = {{{ Functions.getIndex('_glFrontFace', true) }}}; break;
- case 'glCullFace': ret = {{{ Functions.getIndex('_glCullFace', true) }}}; break;
- case 'glGenTextures': ret = {{{ Functions.getIndex('_glGenTextures', true) }}}; break;
- case 'glGetError': ret = {{{ Functions.getIndex('_glGetError', true) }}}; break;
- case 'glGetIntegerv': ret = {{{ Functions.getIndex('_glGetIntegerv', true) }}}; break;
- case 'glGetBooleanv': ret = {{{ Functions.getIndex('_glGetBooleanv', true) }}}; break;
- case 'glGetFloatv': ret = {{{ Functions.getIndex('_glGetFloatv', true) }}}; break;
- case 'glHint': ret = {{{ Functions.getIndex('_glHint', true) }}}; break;
- case 'glIsTexture': ret = {{{ Functions.getIndex('_glIsTexture', true) }}}; break;
- case 'glPixelStorei': ret = {{{ Functions.getIndex('_glPixelStorei', true) }}}; break;
- case 'glReadPixels': ret = {{{ Functions.getIndex('_glReadPixels', true) }}}; break;
- case 'glScissor': ret = {{{ Functions.getIndex('_glScissor', true) }}}; break;
- case 'glStencilFunc': ret = {{{ Functions.getIndex('_glStencilFunc', true) }}}; break;
- case 'glStencilMask': ret = {{{ Functions.getIndex('_glStencilMask', true) }}}; break;
- case 'glStencilOp': ret = {{{ Functions.getIndex('_glStencilOp', true) }}}; break;
- case 'glTexImage2D': ret = {{{ Functions.getIndex('_glTexImage2D', true) }}}; break;
- case 'glTexParameterf': ret = {{{ Functions.getIndex('_glTexParameterf', true) }}}; break;
- case 'glTexParameterfv': ret = {{{ Functions.getIndex('_glTexParameterfv', true) }}}; break;
- case 'glTexParameteri': ret = {{{ Functions.getIndex('_glTexParameteri', true) }}}; break;
- case 'glTexParameteriv': ret = {{{ Functions.getIndex('_glTexParameteriv', true) }}}; break;
- case 'glGetTexParameterfv': ret = {{{ Functions.getIndex('_glGetTexParameterfv', true) }}}; break;
- case 'glGetTexParameteriv': ret = {{{ Functions.getIndex('_glGetTexParameteriv', true) }}}; break;
- case 'glTexSubImage2D': ret = {{{ Functions.getIndex('_glTexSubImage2D', true) }}}; break;
- case 'glCopyTexImage2D': ret = {{{ Functions.getIndex('_glCopyTexImage2D', true) }}}; break;
- case 'glViewport': ret = {{{ Functions.getIndex('_glViewport', true) }}}; break;
- case 'glIsEnabled': ret = {{{ Functions.getIndex('_glIsEnabled', true) }}}; break;
- case 'glLineWidth': ret = {{{ Functions.getIndex('_glLineWidth', true) }}}; break;
- case 'glPolygonOffset': ret = {{{ Functions.getIndex('_glPolygonOffset', true) }}}; break;
- case 'glReleaseShaderCompiler': ret = {{{ Functions.getIndex('_glReleaseShaderCompiler', true) }}}; break;
- case 'glGetShaderPrecisionFormat': ret = {{{ Functions.getIndex('_glGetShaderPrecisionFormat', true) }}}; break;
- case 'glShaderBinary': ret = {{{ Functions.getIndex('_glShaderBinary', true) }}}; break;
- }
- if (!ret) Module.printErr('WARNING: getProcAddress failed for ' + name);
- return ret;
- }
},
glGetShaderPrecisionFormat__sig: 'v',
glGetShaderPrecisionFormat: function() { throw 'glGetShaderPrecisionFormat: TODO' },
@@ -3310,10 +3465,13 @@
if (this.modelViewLocation) Module.ctx.uniformMatrix4fv(this.modelViewLocation, false, GL.immediate.matrix['m']);
if (this.projectionLocation) Module.ctx.uniformMatrix4fv(this.projectionLocation, false, GL.immediate.matrix['p']);
var clientAttributes = GL.immediate.clientAttributes;
+#if GL_ASSERTIONS
+ GL.validateVertexAttribPointer(positionSize, positionType, GL.immediate.stride, clientAttributes[GL.immediate.VERTEX].offset);
+#endif
Module.ctx.vertexAttribPointer(this.positionLocation, positionSize, positionType, false,
GL.immediate.stride, clientAttributes[GL.immediate.VERTEX].offset);
Module.ctx.enableVertexAttribArray(this.positionLocation);
if (this.hasTextures) {
//for (var i = 0; i < this.usedTexUnitList.length; i++) {
@@ -3322,10 +3480,13 @@
var texUnitID = i;
var attribLoc = this.texCoordLocations[texUnitID];
if (attribLoc === undefined || attribLoc < 0) continue;
if (texUnitID < textureSizes.length && textureSizes[texUnitID]) {
+#if GL_ASSERTIONS
+ GL.validateVertexAttribPointer(textureSizes[texUnitID], textureTypes[texUnitID], GL.immediate.stride, GL.immediate.clientAttributes[GL.immediate.TEXTURE0 + texUnitID].offset);
+#endif
Module.ctx.vertexAttribPointer(attribLoc, textureSizes[texUnitID], textureTypes[texUnitID], false,
GL.immediate.stride, GL.immediate.clientAttributes[GL.immediate.TEXTURE0 + texUnitID].offset);
Module.ctx.enableVertexAttribArray(attribLoc);
} else {
// These two might be dangerous, but let's try them.
@@ -3338,18 +3499,24 @@
Module.ctx.uniformMatrix4fv(this.textureMatrixLocations[i], false, GL.immediate.matrix['t' + i]);
}
}
}
if (colorSize) {
+#if GL_ASSERTIONS
+ GL.validateVertexAttribPointer(colorSize, colorType, GL.immediate.stride, clientAttributes[GL.immediate.COLOR].offset);
+#endif
Module.ctx.vertexAttribPointer(this.colorLocation, colorSize, colorType, true,
GL.immediate.stride, clientAttributes[GL.immediate.COLOR].offset);
Module.ctx.enableVertexAttribArray(this.colorLocation);
} else if (this.hasColor) {
Module.ctx.disableVertexAttribArray(this.colorLocation);
Module.ctx.vertexAttrib4fv(this.colorLocation, GL.immediate.clientColor);
}
if (this.hasNormal) {
+#if GL_ASSERTIONS
+ GL.validateVertexAttribPointer(normalSize, normalType, GL.immediate.stride, clientAttributes[GL.immediate.NORMAL].offset);
+#endif
Module.ctx.vertexAttribPointer(this.normalLocation, normalSize, normalType, true,
GL.immediate.stride, clientAttributes[GL.immediate.NORMAL].offset);
Module.ctx.enableVertexAttribArray(this.normalLocation);
}
if (this.hasFog) {
@@ -3561,10 +3728,11 @@
prepareClientAttributes: function(count, beginEnd) {
// If no client attributes were modified since we were last called, do nothing. Note that this
// does not work for glBegin/End, where we generate renderer components dynamically and then
// disable them ourselves, but it does help with glDrawElements/Arrays.
if (!this.modifiedClientAttributes) {
+ GL.immediate.vertexCounter = (GL.immediate.stride * count) / 4; // XXX assuming float
return;
}
this.modifiedClientAttributes = false;
var stride = 0, start;
@@ -3877,11 +4045,14 @@
glColor4fv__deps: ['glColor4f'],
glColor4fv: function(p) {
_glColor4f({{{ makeGetValue('p', '0', 'float') }}}, {{{ makeGetValue('p', '4', 'float') }}}, {{{ makeGetValue('p', '8', 'float') }}}, {{{ makeGetValue('p', '12', 'float') }}});
},
- glColor4ubv: function() { throw 'glColor4ubv not implemented' },
+ glColor4ubv__deps: ['glColor4ub'],
+ glColor4ubv: function(p) {
+ _glColor4ub({{{ makeGetValue('p', '0', 'i8') }}}, {{{ makeGetValue('p', '1', 'i8') }}}, {{{ makeGetValue('p', '2', 'i8') }}}, {{{ makeGetValue('p', '3', 'i8') }}});
+ },
glFogf: function(pname, param) { // partial support, TODO
switch(pname) {
case 0x0B63: // GL_FOG_START
GLEmulation.fogStart = param; break;
@@ -4200,12 +4371,48 @@
glGenVertexArraysOES: 'glGenVertexArrays',
glDeleteVertexArraysOES: 'glDeleteVertexArrays',
glBindVertexArrayOES: 'glBindVertexArray',
glFramebufferTexture2DOES: 'glFramebufferTexture2D',
-#endif // DISABLE_GL_EMULATION == 0
+#else // LEGACY_GL_EMULATION
+ // Warn if code tries to use various emulation stuff, when emulation is disabled
+ // (do not warn if INCLUDE_FULL_LIBRARY is one, because then likely the gl code will
+ // not be called anyhow, leave only the runtime aborts)
+ glVertexPointer__deps: [function() {
+#if INCLUDE_FULL_LIBRARY == 0
+ warn('Legacy GL function (glVertexPointer) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.');
+#endif
+ }],
+ glVertexPointer: function(){ throw 'Legacy GL function (glVertexPointer) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; },
+ glGenVertexArrays__deps: [function() {
+#if INCLUDE_FULL_LIBRARY == 0
+ warn('Legacy GL function (glGenVertexArrays) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.');
+#endif
+ }],
+ glGenVertexArrays: function(){ throw 'Legacy GL function (glGenVertexArrays) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; },
+ glMatrixMode__deps: [function() {
+#if INCLUDE_FULL_LIBRARY == 0
+ warn('Legacy GL function (glMatrixMode) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.');
+#endif
+ }],
+ glMatrixMode: function(){ throw 'Legacy GL function (glMatrixMode) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; },
+ glBegin__deps: [function() {
+#if INCLUDE_FULL_LIBRARY == 0
+ warn('Legacy GL function (glBegin) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.');
+#endif
+ }],
+ glBegin: function(){ throw 'Legacy GL function (glBegin) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; },
+ glLoadIdentity__deps: [function() {
+#if INCLUDE_FULL_LIBRARY == 0
+ warn('Legacy GL function (glLoadIdentity) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.');
+#endif
+ }],
+ glLoadIdentity: function(){ throw 'Legacy GL function (glLoadIdentity) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; },
+
+#endif // LEGACY_GL_EMULATION
+
// GLU
gluPerspective: function(fov, aspect, near, far) {
GL.immediate.matricesModified = true;
GL.immediate.matrix[GL.immediate.currentMatrix] =
@@ -4264,10 +4471,11 @@
{{{ makeSetValue('objZ', '0', 'result[2]', 'double') }}};
return 1 /* GL_TRUE */;
},
+ gluOrtho2D__deps: ['glOrtho'],
gluOrtho2D: function(left, right, bottom, top) {
_glOrtho(left, right, bottom, top, -1, 1);
},
// GLES2 emulation
@@ -4288,10 +4496,13 @@
cb.clientside = true;
return;
}
cb.clientside = false;
#endif
+#if GL_ASSERTIONS
+ GL.validateVertexAttribPointer(size, type, stride, ptr);
+#endif
Module.ctx.vertexAttribPointer(index, size, type, normalized, stride, ptr);
},
glEnableVertexAttribArray__sig: 'vi',
glEnableVertexAttribArray: function(index) {
@@ -4436,30 +4647,62 @@
});
});
autoAddDeps(LibraryGL, '$GL');
-if (!DISABLE_GL_EMULATION) {
- // Emulation requires everything else, potentially
- LibraryGL.$GLEmulation__deps = LibraryGL.$GLEmulation__deps.slice(0); // the __deps object is shared
- var glFuncs = [];
- for (var item in LibraryGL) {
- if (item != '$GLEmulation' && item.substr(-6) != '__deps' && item.substr(-9) != '__postset' && item.substr(-5) != '__sig' && item.substr(0, 2) == 'gl') {
- glFuncs.push(item);
+// Legacy GL emulation
+if (LEGACY_GL_EMULATION) {
+ DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.push('$GLEmulation');
+}
+
+// GL proc address retrieval
+LibraryGL.emscripten_GetProcAddress__deps = [function() {
+ // ProcAddress is used, so include everything in GL. This runs before we go to the $ProcAddressTable object,
+ // and we fill its deps just in time, and create the lookup table
+ var table = {};
+ LibraryManager.library.emscripten_procAddressTable__deps = keys(LibraryGL).map(function(x) {
+ if (x.substr(-6) == '__deps' || x.substr(-9) == '__postset' || x.substr(-5) == '__sig' || x.substr(-5) == '__asm' || x.substr(0, 2) != 'gl') return null;
+ var original = x;
+ if (('_' + x) in Functions.implementedFunctions) {
+ // a user-implemented function aliases this one, but we still want it to be accessible by name, so rename it
+ var y = x + '__procTable';
+ LibraryManager.library[y] = LibraryManager.library[x];
+ LibraryManager.library[y + '__deps'] = LibraryManager.library[x + '__deps'];
+ LibraryManager.library[y + '__postset'] = LibraryManager.library[x + '__postset'];
+ LibraryManager.library[y + '__sig'] = LibraryManager.library[x + '__sig'];//|| Functions.implementedFunctions['_' + x];
+ LibraryManager.library[y + '__asm'] = LibraryManager.library[x + '__asm'];
+ x = y;
+ assert(!(y in Functions.implementedFunctions) && !Functions.unimplementedFunctions['_' + y]);
}
- }
- LibraryGL.$GLEmulation__deps = LibraryGL.$GLEmulation__deps.concat(glFuncs);
- LibraryGL.$GLEmulation__deps.push(function() {
- for (var func in Functions.getIndex.tentative) {
- Functions.getIndex(func);
- Functions.unimplementedFunctions[func] = LibraryGL[func.substr(1) + '__sig'];
+ var longX = '_' + x;
+ var sig = LibraryManager.library[x + '__sig'] || functionStubSigs[longX];
+ if (sig) {
+ table[original] = Functions.getIndex(longX, sig);
+ if (!(longX in Functions.implementedFunctions)) Functions.unimplementedFunctions[longX] = sig;
}
- });
-
- if (FORCE_GL_EMULATION) {
- LibraryGL.glDrawElements__deps = LibraryGL.glDrawElements__deps.concat('$GLEmulation');
- LibraryGL.glDrawArrays__deps = LibraryGL.glDrawArrays__deps.concat('$GLEmulation');
+ return x;
+ }).filter(function(x) { return x !== null });
+ // convert table into function with switch, to not confuse closure compiler
+ var tableImpl = 'switch(name) {\n';
+ for (var x in table) tableImpl += 'case "' + x + '": return ' + table[x] + '; break;\n';
+ tableImpl += '}\nreturn 0;';
+ LibraryManager.library.emscripten_procAddressTable = new Function('name', tableImpl);
+}, 'emscripten_procAddressTable'];
+LibraryGL.emscripten_GetProcAddress = function(name) {
+ name = name.replace('EXT', '').replace('ARB', '');
+ switch(name) { // misc renamings
+ case 'glCreateProgramObject': name = 'glCreateProgram'; break;
+ case 'glUseProgramObject': name = 'glUseProgram'; break;
+ case 'glCreateShaderObject': name = 'glCreateShader'; break;
+ case 'glAttachObject': name = 'glAttachShader'; break;
+ case 'glDetachObject': name = 'glDetachShader'; break;
}
+ var ret = _emscripten_procAddressTable(name);
+ if (!ret) Module.printErr('WARNING: getProcAddress failed for ' + name);
+ return ret;
}
+// Final merge
mergeInto(LibraryManager.library, LibraryGL);
+
+assert(!(FULL_ES2 && LEGACY_GL_EMULATION), 'cannot emulate both ES2 and legacy GL');