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.js242
1 files changed, 223 insertions, 19 deletions
diff --git a/src/library_gl.js b/src/library_gl.js
index 9ee379d0..995f2358 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -993,6 +993,11 @@ var LibraryGL = {
fogMode: 0x0800, // GL_EXP
fogEnabled: false,
+ // VAO support
+ vaos: [],
+ currentVao: null,
+ enabledVertexAttribArrays: {}, // helps with vao cleanups
+
init: function() {
GLEmulation.fogColor = new Float32Array(4);
@@ -1011,6 +1016,7 @@ var LibraryGL = {
0x809E: 1, // GL_SAMPLE_ALPHA_TO_COVERAGE
0x80A0: 1 // GL_SAMPLE_COVERAGE
};
+
_glEnable = function(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
@@ -1022,6 +1028,7 @@ var LibraryGL = {
// XXX not according to spec, and not in desktop GL, but works in some GLES1.x apparently, so support
// it by forwarding to glEnableClientState
_glEnableClientState(cap);
+ return;
} else if (!(cap in validCapabilities)) {
return;
}
@@ -1036,6 +1043,7 @@ var LibraryGL = {
// XXX not according to spec, and not in desktop GL, but works in some GLES1.x apparently, so support
// it by forwarding to glDisableClientState
_glDisableClientState(cap);
+ return;
} else if (!(cap in validCapabilities)) {
return;
}
@@ -1050,6 +1058,17 @@ var LibraryGL = {
return Module.ctx.isEnabled(cap);
};
+ var glGetBooleanv = _glGetBooleanv;
+ _glGetBooleanv = function(pname, p) {
+ var attrib = GLEmulation.getAttributeFromCapability(pname);
+ if (attrib !== null) {
+ var result = GL.immediate.enabledClientAttributes[attrib];
+ {{{ makeSetValue('p', '0', 'result === true ? 1 : 0', 'i8') }}};
+ return;
+ }
+ glGetBooleanv(pname, p);
+ };
+
var glGetIntegerv = _glGetIntegerv;
_glGetIntegerv = function(pname, params) {
switch (pname) {
@@ -1070,6 +1089,51 @@ var LibraryGL = {
return;
}
case 0x8871: pname = Module.ctx.MAX_COMBINED_TEXTURE_IMAGE_UNITS /* close enough */; break; // GL_MAX_TEXTURE_COORDS
+ case 0x807A: { // GL_VERTEX_ARRAY_SIZE
+ var attribute = GLImmediate.clientAttributes[GLImmediate.VERTEX];
+ {{{ makeSetValue('params', '0', 'attribute ? attribute.size : 0', 'i32') }}};
+ return;
+ }
+ case 0x807B: { // GL_VERTEX_ARRAY_TYPE
+ var attribute = GLImmediate.clientAttributes[GLImmediate.VERTEX];
+ {{{ makeSetValue('params', '0', 'attribute ? attribute.type : 0', 'i32') }}};
+ return;
+ }
+ case 0x807C: { // GL_VERTEX_ARRAY_STRIDE
+ var attribute = GLImmediate.clientAttributes[GLImmediate.VERTEX];
+ {{{ makeSetValue('params', '0', 'attribute ? attribute.stride : 0', 'i32') }}};
+ return;
+ }
+ case 0x8081: { // GL_COLOR_ARRAY_SIZE
+ var attribute = GLImmediate.clientAttributes[GLImmediate.COLOR];
+ {{{ makeSetValue('params', '0', 'attribute ? attribute.size : 0', 'i32') }}};
+ return;
+ }
+ case 0x8082: { // GL_COLOR_ARRAY_TYPE
+ var attribute = GLImmediate.clientAttributes[GLImmediate.COLOR];
+ {{{ makeSetValue('params', '0', 'attribute ? attribute.type : 0', 'i32') }}};
+ return;
+ }
+ case 0x8083: { // GL_COLOR_ARRAY_STRIDE
+ var attribute = GLImmediate.clientAttributes[GLImmediate.COLOR];
+ {{{ makeSetValue('params', '0', 'attribute ? attribute.stride : 0', 'i32') }}};
+ return;
+ }
+ case 0x8088: { // GL_TEXTURE_COORD_ARRAY_SIZE
+ var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0];
+ {{{ makeSetValue('params', '0', 'attribute ? attribute.size : 0', 'i32') }}};
+ return;
+ }
+ case 0x8089: { // GL_TEXTURE_COORD_ARRAY_TYPE
+ var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0];
+ {{{ makeSetValue('params', '0', 'attribute ? attribute.type : 0', 'i32') }}};
+ return;
+ }
+ case 0x808A: { // GL_TEXTURE_COORD_ARRAY_STRIDE
+ var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0];
+ {{{ makeSetValue('params', '0', 'attribute ? attribute.stride : 0', 'i32') }}};
+ return;
+ }
}
glGetIntegerv(pname, params);
};
@@ -1285,8 +1349,13 @@ var LibraryGL = {
glBindBuffer(target, buffer);
if (target == Module.ctx.ARRAY_BUFFER) {
GL.currArrayBuffer = buffer;
+ if (GLEmulation.currentVao) {
+ assert(GLEmulation.currentVao.arrayBuffer == buffer || GLEmulation.currentVao.arrayBuffer == 0 || buffer == 0, 'TODO: support for multiple array buffers in vao');
+ GLEmulation.currentVao.arrayBuffer = buffer;
+ }
} else if (target == Module.ctx.ELEMENT_ARRAY_BUFFER) {
GL.currElementArrayBuffer = buffer;
+ if (GLEmulation.currentVao) GLEmulation.currentVao.elementArrayBuffer = buffer;
}
};
@@ -1330,6 +1399,44 @@ var LibraryGL = {
}
glHint(target, mode);
};
+
+ var glEnableVertexAttribArray = _glEnableVertexAttribArray;
+ _glEnableVertexAttribArray = function(index) {
+ glEnableVertexAttribArray(index);
+ GLEmulation.enabledVertexAttribArrays[index] = 1;
+ if (GLEmulation.currentVao) GLEmulation.currentVao.enabledVertexAttribArrays[index] = 1;
+ };
+
+ var glDisableVertexAttribArray = _glDisableVertexAttribArray;
+ _glDisableVertexAttribArray = function(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(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];
+ }
+ };
+ },
+
+ getAttributeFromCapability: function(cap) {
+ var attrib = null;
+ switch (cap) {
+ case 0x8078: // GL_TEXTURE_COORD_ARRAY
+ case 0x0de1: // GL_TEXTURE_2D - XXX not according to spec, and not in desktop GL, but works in some GLES1.x apparently, so support it
+ attrib = GL.immediate.TEXTURE0 + GL.immediate.clientActiveTexture; break;
+ case 0x8074: // GL_VERTEX_ARRAY
+ attrib = GL.immediate.VERTEX; break;
+ case 0x8075: // GL_NORMAL_ARRAY
+ attrib = GL.immediate.NORMAL; break;
+ case 0x8076: // GL_COLOR_ARRAY
+ attrib = GL.immediate.COLOR; break;
+ }
+ return attrib;
},
getProcAddress: function(name) {
@@ -1393,6 +1500,9 @@ var LibraryGL = {
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;
}
if (!ret) Module.printErr('WARNING: getProcAddress failed for ' + name);
return ret;
@@ -1445,6 +1555,20 @@ var LibraryGL = {
assert(id == 0);
},
+ glGetPointerv: function(name, p) {
+ var attribute;
+ switch(name) {
+ case 0x808E: // GL_VERTEX_ARRAY_POINTER
+ attribute = GLImmediate.clientAttributes[GLImmediate.VERTEX]; break;
+ 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;
+ }
+ {{{ makeSetValue('p', '0', 'attribute ? attribute.pointer : 0', 'i32') }}};
+ },
+
// GL Immediate mode
$GLImmediate__postset: 'GL.immediate.setupFuncs(); Browser.moduleContextCreatedCallbacks.push(function() { GL.immediate.init() });',
@@ -1802,27 +1926,35 @@ var LibraryGL = {
}
// If the array buffer is unchanged and the renderer as well, then we can avoid all the work here
- // XXX We use some heuristics here, and this may not work in all cases. Try disabling this if you
- // have odd glitches (by setting canSkip always to 0, or even cleaning up the renderer right
- // after rendering)
+ // XXX We use some heuristics here, and this may not work in all cases. Try disabling GL_UNSAFE_OPTS if you
+ // have odd glitches
+#if GL_UNSAFE_OPTS
var lastRenderer = GL.immediate.lastRenderer;
var canSkip = this == lastRenderer &&
arrayBuffer == GL.immediate.lastArrayBuffer &&
(GL.currProgram || this.program) == GL.immediate.lastProgram &&
!GL.immediate.matricesModified;
if (!canSkip && lastRenderer) lastRenderer.cleanup();
+#endif
if (!GL.currArrayBuffer) {
// Bind the array buffer and upload data after cleaning up the previous renderer
+#if GL_UNSAFE_OPTS
+ // Potentially unsafe, since lastArrayBuffer might not reflect the true array buffer in code that mixes immediate/non-immediate
if (arrayBuffer != GL.immediate.lastArrayBuffer) {
+#endif
Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, arrayBuffer);
+#if GL_UNSAFE_OPTS
}
+#endif
Module.ctx.bufferSubData(Module.ctx.ARRAY_BUFFER, start, GL.immediate.vertexData.subarray(start >> 2, end >> 2));
}
+#if GL_UNSAFE_OPTS
if (canSkip) return;
GL.immediate.lastRenderer = this;
GL.immediate.lastArrayBuffer = arrayBuffer;
GL.immediate.lastProgram = GL.currProgram || this.program;
GL.immediate.matricesModified = false;
+#endif
if (!GL.currProgram) {
Module.ctx.useProgram(this.program);
@@ -1898,9 +2030,11 @@ var LibraryGL = {
Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, null);
}
+#if GL_UNSAFE_OPTS
GL.immediate.lastRenderer = null;
GL.immediate.lastArrayBuffer = null;
GL.immediate.lastProgram = null;
+#endif
GL.immediate.matricesModified = true;
}
};
@@ -2145,6 +2279,10 @@ var LibraryGL = {
if (emulatedElementArrayBuffer) {
Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, GL.buffers[GL.currElementArrayBuffer] || null);
}
+
+#if GL_UNSAFE_OPTS == 0
+ renderer.cleanup();
+#endif
}
},
@@ -2359,29 +2497,21 @@ var LibraryGL = {
// ClientState/gl*Pointer
glEnableClientState: function(cap, disable) {
- var attrib;
- switch(cap) {
- case 0x8078: // GL_TEXTURE_COORD_ARRAY
- case 0x0de1: // GL_TEXTURE_2D - XXX not according to spec, and not in desktop GL, but works in some GLES1.x apparently, so support it
- attrib = GL.immediate.TEXTURE0 + GL.immediate.clientActiveTexture; break;
- case 0x8074: // GL_VERTEX_ARRAY
- attrib = GL.immediate.VERTEX; break;
- case 0x8075: // GL_NORMAL_ARRAY
- attrib = GL.immediate.NORMAL; break;
- case 0x8076: // GL_COLOR_ARRAY
- attrib = GL.immediate.COLOR; break;
- default:
+ var attrib = GLEmulation.getAttributeFromCapability(cap);
+ if (attrib === null) {
#if ASSERTIONS
- Module.printErr('WARNING: unhandled clientstate: ' + cap);
+ Module.printErr('WARNING: unhandled clientstate: ' + cap);
#endif
- return;
+ return;
}
if (disable && GL.immediate.enabledClientAttributes[attrib]) {
GL.immediate.enabledClientAttributes[attrib] = false;
GL.immediate.totalEnabledClientAttributes--;
+ if (GLEmulation.currentVao) delete GLEmulation.currentVao.enabledClientStates[cap];
} else if (!disable && !GL.immediate.enabledClientAttributes[attrib]) {
GL.immediate.enabledClientAttributes[attrib] = true;
GL.immediate.totalEnabledClientAttributes++;
+ if (GLEmulation.currentVao) GLEmulation.currentVao.enabledClientStates[cap] = 1;
}
GL.immediate.modifiedClientAttributes = true;
},
@@ -2408,6 +2538,63 @@ var LibraryGL = {
GL.immediate.clientActiveTexture = texture - 0x84C0; // GL_TEXTURE0
},
+ // Vertex array object (VAO) support. TODO: when the WebGL extension is popular, use that and remove this code and GL.vaos
+ glGenVertexArrays__deps: ['$GLEMulation'],
+ glGenVertexArrays__sig: ['vii'],
+ glGenVertexArrays: function(n, vaos) {
+ for (var i = 0; i < n; i++) {
+ var id = GL.getNewId(GLEmulation.vaos);
+ GLEmulation.vaos[id] = {
+ id: id,
+ arrayBuffer: 0,
+ elementArrayBuffer: 0,
+ enabledVertexAttribArrays: {},
+ vertexAttribPointers: {},
+ enabledClientStates: {},
+ };
+ {{{ makeSetValue('vaos', 'i*4', 'id', 'i32') }}};
+ }
+ },
+ glDeleteVertexArrays__sig: ['vii'],
+ glDeleteVertexArrays: function(n, vaos) {
+ for (var i = 0; i < n; i++) {
+ var id = {{{ makeGetValue('vaos', 'i*4', 'i32') }}};
+ GLEmulation.vaos[id] = null;
+ if (GLEmulation.currentVao && GLEmulation.currentVao.id == id) GLEmulation.currentVao = null;
+ }
+ },
+ glBindVertexArray__sig: ['vi'],
+ glBindVertexArray: function(vao) {
+ // undo vao-related things, wipe the slate clean, both for vao of 0 or an actual vao
+ GLEmulation.currentVao = null; // make sure the commands we run here are not recorded
+ if (GL.immediate.lastRenderer) GL.immediate.lastRenderer.cleanup();
+ _glBindBuffer(Module.ctx.ARRAY_BUFFER, 0); // XXX if one was there before we were bound?
+ _glBindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, 0);
+ for (var vaa in GLEmulation.enabledVertexAttribArrays) {
+ Module.ctx.disableVertexAttribArray(vaa);
+ }
+ GLEmulation.enabledVertexAttribArrays = {};
+ GL.immediate.enabledClientAttributes = [0, 0];
+ GL.immediate.totalEnabledClientAttributes = 0;
+ GL.immediate.modifiedClientAttributes = true;
+ if (vao) {
+ // replay vao
+ var info = GLEmulation.vaos[vao];
+ _glBindBuffer(Module.ctx.ARRAY_BUFFER, info.arrayBuffer); // XXX overwrite current binding?
+ _glBindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, info.elementArrayBuffer);
+ for (var vaa in info.enabledVertexAttribArrays) {
+ _glEnableVertexAttribArray(vaa);
+ }
+ for (var vaa in info.vertexAttribPointers) {
+ _glVertexAttribPointer.apply(null, info.vertexAttribPointers[vaa]);
+ }
+ for (var attrib in info.enabledClientStates) {
+ _glEnableClientState(attrib|0);
+ }
+ GLEmulation.currentVao = info; // set currentVao last, so the commands we ran here were not recorded
+ }
+ },
+
// OpenGL Immediate Mode matrix routines.
// Note that in the future we might make these available only in certain modes.
glMatrixMode__deps: ['$GL', '$GLImmediateSetup', '$GLEmulation'], // emulation is not strictly needed, this is a workaround
@@ -2498,6 +2685,7 @@ var LibraryGL = {
GL.immediate.matrix.lib.mat4.multiply(GL.immediate.matrix[GL.immediate.currentMatrix],
GL.immediate.matrix.lib.mat4.frustum(left, right, bottom, top_, nearVal, farVal));
},
+ glFrustumf: 'glFrustum',
glOrtho: function(left, right, bottom, top_, nearVal, farVal) {
GL.immediate.matricesModified = true;
@@ -2599,8 +2787,8 @@ var LibraryGL = {
glTexGeni: function() { throw 'glTexGeni: TODO' },
glTexGenfv: function() { throw 'glTexGenfv: TODO' },
- glTexEnvi: function() { throw 'glTexEnvi: TODO' },
- glTexEnvfv: function() { throw 'glTexEnvfv: TODO' },
+ glTexEnvi: function() { Runtime.warnOnce('glTexEnvi: TODO') },
+ glTexEnvfv: function() { Runtime.warnOnce('glTexEnvfv: TODO') },
glTexImage1D: function() { throw 'glTexImage1D: TODO' },
glTexCoord3f: function() { throw 'glTexCoord3f: TODO' },
@@ -2613,6 +2801,22 @@ var LibraryGL = {
glVertexAttribPointer__sig: 'viiiiii',
glCheckFramebufferStatus__sig: 'ii',
glRenderbufferStorage__sig: 'viiii',
+
+ // Open GLES1.1 compatibility
+ glGenFramebuffersOES : 'glGenFramebuffers',
+ glGenRenderbuffersOES : 'glGenRenderbuffers',
+ glBindFramebufferOES : 'glBindFramebuffer',
+ glBindRenderbufferOES : 'glBindRenderbuffer',
+ glGetRenderbufferParameterivOES : 'glGetRenderbufferParameteriv',
+ glFramebufferRenderbufferOES : 'glFramebufferRenderbuffer',
+ glRenderbufferStorageOES : 'glRenderbufferStorage',
+ glCheckFramebufferStatusOES : 'glCheckFramebufferStatus',
+ glDeleteFramebuffersOES : 'glDeleteFramebuffers',
+ glDeleteRenderbuffersOES : 'glDeleteRenderbuffers',
+ glGenVertexArraysOES: 'glGenVertexArrays',
+ glDeleteVertexArraysOES: 'glDeleteVertexArrays',
+ glBindVertexArrayOES: 'glBindVertexArray',
+ glFramebufferTexture2DOES: 'glFramebufferTexture2D'
};
// Simple pass-through functions. Starred ones have return values. [X] ones have X in the C name but not in the JS name