aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/intertyper.js25
-rw-r--r--src/jsifier.js28
-rw-r--r--src/library.js101
-rw-r--r--src/library_browser.js4
-rw-r--r--src/library_gl.js837
-rw-r--r--src/library_sdl.js27
-rw-r--r--src/library_sockfs.js2
-rw-r--r--src/modules.js11
-rw-r--r--src/parseTools.js34
-rw-r--r--src/runtime.js5
-rw-r--r--src/settings.js4
-rw-r--r--src/shell.html2
-rw-r--r--src/simd.js1034
-rw-r--r--src/utility.js8
14 files changed, 1299 insertions, 823 deletions
diff --git a/src/intertyper.js b/src/intertyper.js
index 940c677f..b34d0c08 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -524,6 +524,27 @@ function intertyper(lines, sidePass, baseLineNums) {
}
});
}
+ } else if (ident == '_llvm_used') {
+ var chunk = item.tokens[1].tokens;
+ var funcs = [];
+ var part = [];
+
+ for (var i = 0; i < chunk.length; i++) {
+ if (chunk[i].text == ',') {
+ var call = parseLLVMFunctionCall(part);
+ EXPORTED_FUNCTIONS[call.ident] = 0;
+ part = [];
+ } else {
+ part.push(chunk[i]);
+ }
+ }
+ if (part.length > 0) {
+ var call = parseLLVMFunctionCall(part);
+ EXPORTED_FUNCTIONS[call.ident] = 0;
+ }
+
+ ret.type = 'i32';
+ ret.value = { intertype: 'value', ident: '0', value: '0', type: ret.type };
} else if (!external) {
if (item.tokens[1] && item.tokens[1].text != ';') {
if (item.tokens[1].text == 'c') {
@@ -538,6 +559,7 @@ function intertyper(lines, sidePass, baseLineNums) {
ret.value = { intertype: 'value', ident: '0', value: '0', type: ret.type };
}
}
+
return ret;
}
}
@@ -616,7 +638,8 @@ function intertyper(lines, sidePass, baseLineNums) {
// 'bitcast'
function bitcastHandler(item) {
item.intertype = 'bitcast';
- item.type = item.tokens[4].text; // The final type
+ var last = getTokenIndexByText(item.tokens, ';');
+ item.type = item.tokens[Math.min(last, item.tokens.length-1)].text; // The final type
Types.needAnalysis[item.type] = 0;
var to = getTokenIndexByText(item.tokens, 'to');
item.params = [parseLLVMSegment(item.tokens.slice(1, to))];
diff --git a/src/jsifier.js b/src/jsifier.js
index cb753e57..b5502741 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -1373,8 +1373,9 @@ function JSify(data, functionsOnly, givenFunctions) {
function insertelementHandler(item) {
var base = getVectorBaseType(item.type);
var ident = ensureVector(item.ident, base);
+ var laneOp = ((base == 'float') ? 'SIMD.float32x4.with' : 'SIMD.int32x4.with');
//return ident + '.with' + SIMDLane[finalizeLLVMParameter(item.index)] + '(' + finalizeLLVMParameter(item.value) + ')';
- return 'SIMD.with' + SIMDLane[finalizeLLVMParameter(item.index)] + '(' + ident + ',' + finalizeLLVMParameter(item.value) + ')';
+ return laneOp + SIMDLane[finalizeLLVMParameter(item.index)] + '(' + ident + ',' + finalizeLLVMParameter(item.value) + ')';
}
function extractelementHandler(item) {
var base = getVectorBaseType(item.type);
@@ -1603,6 +1604,15 @@ function JSify(data, functionsOnly, givenFunctions) {
}
}
+ // we alias llvm memset and such to normal memset. The target has a return value, while the original
+ // does not, so we need to fix that for the actual call target
+ if (ASM_JS) {
+ var sig = LibraryManager.library[simpleIdent + '__sig'];
+ if (sig && sig[0] !== 'v') {
+ returnType = Functions.getSignatureType(sig[0]);
+ }
+ }
+
if (byPointer) {
var sig = Functions.getSignature(returnType, argsTypes, hasVarArgs);
if (ASM_JS) {
@@ -1746,11 +1756,13 @@ function JSify(data, functionsOnly, givenFunctions) {
print('/* no memory initializer */'); // test purposes
}
- // Define postsets. These will be run in ATINIT, right before global initializers (which might need the postsets). We cannot
- // run them now because the memory initializer might not have been applied yet.
- print('function runPostSets() {\n');
- print(itemsDict.GlobalVariablePostSet.map(function(item) { return item.JS }).join('\n'));
- print('}\n');
+ if (phase !== 'glue') {
+ // Define postsets. These will be run in ATINIT, right before global initializers (which might need the postsets). We cannot
+ // run them now because the memory initializer might not have been applied yet.
+ print('function runPostSets() {\n');
+ print(itemsDict.GlobalVariablePostSet.map(function(item) { return item.JS }).join('\n'));
+ print('}\n');
+ }
if (USE_TYPED_ARRAYS == 2) {
if (!BUILD_AS_SHARED_LIB && !SIDE_MODULE) {
@@ -1847,10 +1859,10 @@ function JSify(data, functionsOnly, givenFunctions) {
// first row are utilities called from generated code, second are needed from fastLong
['i64Add', 'i64Subtract', 'bitshift64Shl', 'bitshift64Lshr', 'bitshift64Ashr',
'llvm_ctlz_i32', 'llvm_cttz_i32'].forEach(function(func) {
- if (!Functions.libraryFunctions[func]) {
+ if (!Functions.libraryFunctions[func] || (phase == 'glue' && func[0] === 'l')) { // TODO: one-by-one in fastcomp glue mode
print(processLibraryFunction(LibraryManager.library[func], func)); // must be first to be close to generated code
Functions.implementedFunctions['_' + func] = LibraryManager.library[func + '__sig'];
- Functions.libraryFunctions[func] = 1;
+ Functions.libraryFunctions[func] = phase == 'glue' ? 2 : 1; // XXX
// limited dependency handling
var deps = LibraryManager.library[func + '__deps'];
if (deps) {
diff --git a/src/library.js b/src/library.js
index 4b5fc9ae..bdc0a39e 100644
--- a/src/library.js
+++ b/src/library.js
@@ -23,6 +23,7 @@ LibraryManager.library = {
stdout: 'allocate(1, "i32*", ALLOC_STATIC)',
stderr: 'allocate(1, "i32*", ALLOC_STATIC)',
_impure_ptr: 'allocate(1, "i32*", ALLOC_STATIC)',
+ __dso_handle: 'allocate(1, "i32*", ALLOC_STATIC)',
// ==========================================================================
// dirent.h
@@ -471,6 +472,11 @@ LibraryManager.library = {
mkstemp: function(template) {
return _creat(_mktemp(template), 0600);
},
+ mkdtemp__deps: ['mktemp', 'mkdir'],
+ mkdtemp: function(template) {
+ template = _mktemp(template);
+ return (_mkdir(template, 0700) === 0) ? template : 0;
+ },
fcntl__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
fcntl: function(fildes, cmd, varargs, dup2) {
// int fcntl(int fildes, int cmd, ...);
@@ -535,7 +541,7 @@ LibraryManager.library = {
// Advise as much as you wish. We don't care.
return 0;
},
- posix_madvise: 'posix_fadvise',
+ posix_madvise: function(){ return 0 }, // ditto as fadvise
posix_fallocate__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
posix_fallocate: function(fd, offset, len) {
// int posix_fallocate(int fd, off_t offset, off_t len);
@@ -1862,14 +1868,13 @@ LibraryManager.library = {
#endif
#if USE_TYPED_ARRAYS == 2
} else if (type == 'i64') {
-
-#if TARGET_LE32
+#if TARGET_LE32 == 1
ret = [{{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true) }}},
{{{ makeGetValue('varargs', 'argIndex+8', 'i32', undefined, undefined, true) }}}];
argIndex += {{{ STACK_ALIGN }}}; // each 32-bit chunk is in a 64-bit block
#else
- ret = [{{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true) }}},
- {{{ makeGetValue('varargs', 'argIndex+4', 'i32', undefined, undefined, true) }}}];
+ ret = [{{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true, 4) }}},
+ {{{ makeGetValue('varargs', 'argIndex+4', 'i32', undefined, undefined, true, 4) }}}];
#endif
#else
@@ -2513,6 +2518,10 @@ LibraryManager.library = {
}
var bytesRead = 0;
var streamObj = FS.getStream(stream);
+ if (!streamObj) {
+ ___setErrNo(ERRNO_CODES.EBADF);
+ return 0;
+ }
while (streamObj.ungotten.length && bytesToRead > 0) {
{{{ makeSetValue('ptr++', '0', 'streamObj.ungotten.pop()', 'i8') }}}
bytesToRead--;
@@ -3530,13 +3539,15 @@ LibraryManager.library = {
llvm_memcpy_p0i8_p0i8_i32: 'memcpy',
llvm_memcpy_p0i8_p0i8_i64: 'memcpy',
- memmove__sig: 'viii',
+ memmove__sig: 'iiii',
memmove__asm: true,
memmove__deps: ['memcpy'],
memmove: function(dest, src, num) {
dest = dest|0; src = src|0; num = num|0;
+ var ret = 0;
if (((src|0) < (dest|0)) & ((dest|0) < ((src + num)|0))) {
// Unlikely case: Copy backwards in a safe manner
+ ret = dest;
src = (src + num)|0;
dest = (dest + num)|0;
while ((num|0) > 0) {
@@ -3545,9 +3556,11 @@ LibraryManager.library = {
num = (num - 1)|0;
{{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i8'), 'i8') }}};
}
+ dest = ret;
} else {
_memcpy(dest, src, num) | 0;
}
+ return dest | 0;
},
llvm_memmove_i32: 'memmove',
llvm_memmove_i64: 'memmove',
@@ -3564,7 +3577,7 @@ LibraryManager.library = {
memset__inline: function(ptr, value, num, align) {
return makeSetValues(ptr, 0, value, 'null', num, align);
},
- memset__sig: 'viii',
+ memset__sig: 'iiii',
memset__asm: true,
memset: function(ptr, value, num) {
#if USE_TYPED_ARRAYS == 2
@@ -3593,8 +3606,10 @@ LibraryManager.library = {
{{{ makeSetValueAsm('ptr', 0, 'value', 'i8') }}};
ptr = (ptr+1)|0;
}
+ return (ptr-num)|0;
#else
{{{ makeSetValues('ptr', '0', 'value', 'null', 'num') }}};
+ return ptr;
#endif
},
llvm_memset_i32: 'memset',
@@ -4665,6 +4680,10 @@ LibraryManager.library = {
llvm_dbg_declare__inline: function() { throw 'llvm_debug_declare' }, // avoid warning
+ // llvm-nacl
+
+ llvm_nacl_atomic_store_i32__inline: true,
+
// ==========================================================================
// llvm-mono integration
// ==========================================================================
@@ -8820,8 +8839,72 @@ LibraryManager.library = {
// emscripten vector ops
//============================
- emscripten_float32x4_signmask__inline: function(x) {
- return x + '.signMask()';
+ emscripten_float32x4_signmask__inline: function(a) {
+ return 'SIMD.float32x4.bitsToInt32x4(' + a + ').signMask';
+ },
+
+ emscripten_float32x4_min__inline: function(a, b) {
+ return 'SIMD.float32x4.min(' + a + ', ' + b + ')';
+ },
+
+ emscripten_float32x4_max__inline: function(a, b) {
+ return 'SIMD.float32x4.max(' + a + ', ' + b + ')';
+ },
+
+ emscripten_float32x4_sqrt__inline: function(a) {
+ return 'SIMD.float32x4.sqrt(' + a + ')';
+ },
+
+ emscripten_float32x4_lessThan__inline: function(a, b) {
+ return 'SIMD.int32x4.bitsToFloat32x4(SIMD.float32x4.lessThan(' + a + ', ' + b + '))';
+ },
+
+ emscripten_float32x4_lessThanOrEqual__inline: function(a, b) {
+ return 'SIMD.int32x4.bitsToFloat32x4(SIMD.float32x4.lessThanOrEqual(' + a + ', ' + b + '))';
+ },
+
+ emscripten_float32x4_equal__inline: function(a, b) {
+ return 'SIMD.int32x4.bitsToFloat32x4(SIMD.float32x4.equal(' + a + ', ' + b + '))';
+ },
+
+ emscripten_float32x4_greaterThanOrEqual__inline: function(a, b) {
+ return 'SIMD.int32x4.bitsToFloat32x4(SIMD.float32x4.greaterThanOrEqual(' + a + ', ' + b + '))';
+ },
+
+ emscripten_float32x4_greaterThan__inline: function(a, b) {
+ return 'SIMD.int32x4.bitsToFloat32x4(SIMD.float32x4.greaterThan(' + a + ', ' + b + '))';
+ },
+
+ emscripten_float32x4_and__inline: function(a, b) {
+ return 'SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.and(SIMD.float32x4.bitsToInt32x4(' + a + '), SIMD.float32x4.bitsToInt32x4(' + b + ')))';
+ },
+
+ emscripten_float32x4_andNot__inline: function(a, b) {
+ return 'SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.and(SIMD.int32x4.not(SIMD.float32x4.bitsToInt32x4(' + a + ')), SIMD.float32x4.bitsToInt32x4(' + b + ')))';
+ },
+
+ emscripten_float32x4_or__inline: function(a, b) {
+ return 'SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.or(SIMD.float32x4.bitsToInt32x4(' + a + '), SIMD.float32x4.bitsToInt32x4(' + b + ')))';
+ },
+
+ emscripten_float32x4_xor__inline: function(a, b) {
+ return 'SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.xor(SIMD.float32x4.bitsToInt32x4(' + a + '), SIMD.float32x4.bitsToInt32x4(' + b + ')))';
+ },
+
+ emscripten_int32x4_bitsToFloat32x4__inline: function(a) {
+ return 'SIMD.int32x4.bitsToFloat32x4(' + a + ')';
+ },
+
+ emscripten_int32x4_toFloat32x4__inline: function(a) {
+ return 'SIMD.int32x4.toFloat32x4(' + a + ')';
+ },
+
+ emscripten_float32x4_bitsToInt32x4__inline: function(a) {
+ return 'SIMD.float32x4.bitsToInt32x4(' + a + ')';
+ },
+
+ emscripten_float32x4_toInt32x4__inline: function(a) {
+ return 'SIMD.float32x4.toInt32x4(' + a + ')';
},
//============================
diff --git a/src/library_browser.js b/src/library_browser.js
index fbc609d7..b368c6ac 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -252,7 +252,7 @@ mergeInto(LibraryManager.library, {
var errorInfo = '?';
function onContextCreationError(event) {
- errorInfo = e.statusMessage || errorInfo;
+ errorInfo = event.statusMessage || errorInfo;
}
canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
try {
@@ -863,7 +863,7 @@ mergeInto(LibraryManager.library, {
var styleSheet = document.styleSheets[0];
var rules = styleSheet.cssRules;
for (var i = 0; i < rules.length; i++) {
- if (rules[i].cssText.substr(0, 5) == 'canvas') {
+ if (rules[i].cssText.substr(0, 6) == 'canvas') {
styleSheet.deleteRule(i);
i--;
}
diff --git a/src/library_gl.js b/src/library_gl.js
index afd36197..cc39b048 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -209,6 +209,105 @@ var LibraryGL = {
((height - 1) * alignedRowSize + plainRowSize);
},
+ get: function(name_, p, type) {
+ var ret = undefined;
+ switch(name_) { // Handle a few trivial GLES values
+ case 0x8DFA: // GL_SHADER_COMPILER
+ ret = 1;
+ break;
+ case 0x8DF8: // GL_SHADER_BINARY_FORMATS
+ if (type === 'Integer') {
+ // fall through, see gles2_conformance.cpp
+ } else {
+ GL.recordError(0x0500); // GL_INVALID_ENUM
+#if GL_ASSERTIONS
+ Module.printErr('GL_INVALID_ENUM in glGet' + type + 'v(GL_SHADER_BINARY_FORMATS): Invalid parameter type!');
+#endif
+ return;
+ }
+ case 0x8DF9: // GL_NUM_SHADER_BINARY_FORMATS
+ ret = 0;
+ break;
+ 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*/);
+ ret = formats.length;
+ break;
+ case 0x8B9A: // GL_IMPLEMENTATION_COLOR_READ_TYPE
+ ret = 0x1401; // GL_UNSIGNED_BYTE
+ break;
+ case 0x8B9B: // GL_IMPLEMENTATION_COLOR_READ_FORMAT
+ ret = 0x1908; // GL_RGBA
+ break;
+ }
+
+ if (ret === undefined) {
+ var result = Module.ctx.getParameter(name_);
+ switch (typeof(result)) {
+ case "number":
+ ret = result;
+ break;
+ case "boolean":
+ ret = result ? 1 : 0;
+ break;
+ case "string":
+ GL.recordError(0x0500); // GL_INVALID_ENUM
+#if GL_ASSERTIONS
+ Module.printErr('GL_INVALID_ENUM in glGet' + type + 'v(' + name_ + ') on a name which returns a string!');
+#endif
+ return;
+ case "object":
+ if (result === null) {
+ GL.recordError(0x0500); // GL_INVALID_ENUM
+#if GL_ASSERTIONS
+ Module.printErr('GL_INVALID_ENUM in glGet' + type + 'v(' + name_ + ') and it returns null!');
+#endif
+ return;
+ } else if (result instanceof Float32Array ||
+ result instanceof Uint32Array ||
+ result instanceof Int32Array ||
+ result instanceof Array) {
+ for (var i = 0; i < result.length; ++i) {
+ switch (type) {
+ case 'Integer': {{{ makeSetValue('p', 'i*4', 'result[i]', 'i32') }}}; break;
+ case 'Float': {{{ makeSetValue('p', 'i*4', 'result[i]', 'float') }}}; break;
+ case 'Boolean': {{{ makeSetValue('p', 'i', 'result[i] ? 1 : 0', 'i8') }}}; break;
+ default: throw 'internal glGet error, bad type: ' + type;
+ }
+ }
+ return;
+ } else if (result instanceof WebGLBuffer ||
+ result instanceof WebGLProgram ||
+ result instanceof WebGLFramebuffer ||
+ result instanceof WebGLRenderbuffer ||
+ result instanceof WebGLTexture) {
+ ret = result.name | 0;
+ } else {
+ GL.recordError(0x0500); // GL_INVALID_ENUM
+#if GL_ASSERTIONS
+ Module.printErr('GL_INVALID_ENUM in glGet' + type + 'v: Unknown object returned from WebGL getParameter(' + name_ + ')!');
+#endif
+ return;
+ }
+ break;
+ default:
+ GL.recordError(0x0500); // GL_INVALID_ENUM
+#if GL_ASSERTIONS
+ Module.printErr('GL_INVALID_ENUM in glGetIntegerv: Native code calling glGet' + type + 'v(' + name_ + ') and it returns ' + result + ' of type ' + typeof(result) + '!');
+#endif
+ return;
+ }
+ }
+
+ switch (type) {
+ case 'Integer': {{{ makeSetValue('p', '0', 'ret', 'i32') }}}; break;
+ case 'Float': {{{ makeSetValue('p', '0', 'ret', 'float') }}}; break;
+ case 'Boolean': {{{ makeSetValue('p', '0', 'ret ? 1 : 0', 'i8') }}}; break;
+ default: throw 'internal glGet error, bad type: ' + type;
+ }
+ },
+
getTexPixelData: function(type, format, width, height, pixels, internalFormat) {
var sizePerPixel;
switch (type) {
@@ -288,6 +387,22 @@ var LibraryGL = {
}
},
+#if GL_FFP_ONLY
+ enabledClientAttribIndices: [],
+ enableVertexAttribArray: function enableVertexAttribArray(index) {
+ if (!GL.enabledClientAttribIndices[index]) {
+ GL.enabledClientAttribIndices[index] = true;
+ Module.ctx.enableVertexAttribArray(index);
+ }
+ },
+ disableVertexAttribArray: function disableVertexAttribArray(index) {
+ if (GL.enabledClientAttribIndices[index]) {
+ GL.enabledClientAttribIndices[index] = false;
+ Module.ctx.disableVertexAttribArray(index);
+ }
+ },
+#endif
+
#if FULL_ES2
calcBufLength: function calcBufLength(size, type, stride, count) {
if (stride > 0) {
@@ -554,214 +669,17 @@ var LibraryGL = {
glGetIntegerv__sig: 'vii',
glGetIntegerv: function(name_, p) {
- switch(name_) { // Handle a few trivial GLES values
- 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;
- 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', 'i32') }}};
- return;
- }
- var result = Module.ctx.getParameter(name_);
- switch (typeof(result)) {
- case "number":
- {{{ makeSetValue('p', '0', 'result', 'i32') }}};
- break;
- case "boolean":
- {{{ makeSetValue('p', '0', 'result ? 1 : 0', 'i8') }}};
- break;
- case "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') }}};
- } else if (result instanceof Float32Array ||
- result instanceof Uint32Array ||
- result instanceof Int32Array ||
- result instanceof Array) {
- for (var i = 0; i < result.length; ++i) {
- {{{ makeSetValue('p', 'i*4', 'result[i]', 'i32') }}};
- }
- } else if (result instanceof WebGLBuffer) {
- {{{ makeSetValue('p', '0', 'result.name | 0', 'i32') }}};
- } else if (result instanceof WebGLProgram) {
- {{{ makeSetValue('p', '0', 'result.name | 0', 'i32') }}};
- } else if (result instanceof WebGLFramebuffer) {
- {{{ makeSetValue('p', '0', 'result.name | 0', 'i32') }}};
- } else if (result instanceof WebGLRenderbuffer) {
- {{{ makeSetValue('p', '0', 'result.name | 0', 'i32') }}};
- } else if (result instanceof WebGLTexture) {
- {{{ makeSetValue('p', '0', 'result.name | 0', 'i32') }}};
- } else {
- 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;
- default:
- 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;
- }
+ return GL.get(name_, p, 'Integer');
},
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":
- {{{ makeSetValue('p', '0', 'result', 'float') }}};
- break;
- case "boolean":
- {{{ makeSetValue('p', '0', 'result ? 1.0 : 0.0', 'float') }}};
- break;
- case "string":
- {{{ makeSetValue('p', '0', '0', 'float') }}};
- case "object":
- if (result === 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 ||
- result instanceof Array) {
- for (var i = 0; i < result.length; ++i) {
- {{{ makeSetValue('p', 'i*4', 'result[i]', 'float') }}};
- }
- } else if (result instanceof WebGLBuffer) {
- {{{ makeSetValue('p', '0', 'result.name | 0', 'float') }}};
- } else if (result instanceof WebGLProgram) {
- {{{ makeSetValue('p', '0', 'result.name | 0', 'float') }}};
- } else if (result instanceof WebGLFramebuffer) {
- {{{ makeSetValue('p', '0', 'result.name | 0', 'float') }}};
- } else if (result instanceof WebGLRenderbuffer) {
- {{{ makeSetValue('p', '0', 'result.name | 0', 'float') }}};
- } else if (result instanceof WebGLTexture) {
- {{{ makeSetValue('p', '0', 'result.name | 0', 'float') }}};
- } else {
- 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;
- default:
- 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;
- }
+ return GL.get(name_, p, 'Float');
},
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":
- {{{ makeSetValue('p', '0', 'result != 0', 'i8') }}};
- break;
- case "boolean":
- {{{ makeSetValue('p', '0', 'result != 0', 'i8') }}};
- break;
- case "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') }}};
- } else if (result instanceof Float32Array ||
- result instanceof Uint32Array ||
- result instanceof Int32Array ||
- result instanceof Array) {
- for (var i = 0; i < result.length; ++i) {
- {{{ makeSetValue('p', 'i', 'result[i] != 0', 'i8') }}};
- }
- } else if (result instanceof WebGLBuffer ||
- result instanceof WebGLProgram ||
- result instanceof WebGLFramebuffer ||
- result instanceof WebGLRenderbuffer ||
- result instanceof WebGLTexture) {
- {{{ makeSetValue('p', '0', '1', 'i8') }}}; // non-zero ID is always 1!
- } else {
- 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;
- default:
- 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;
- }
+ return GL.get(name_, p, 'Boolean');
},
glGenTextures__sig: 'vii',
@@ -1808,7 +1726,7 @@ var LibraryGL = {
// 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 GL_UNSAFE_OPTS == 0
+#if GL_UNSAFE_OPTS == 1
Module.printErr('WARNING: using emscripten GL emulation unsafe opts. If weirdness happens, try -s GL_UNSAFE_OPTS=0');
#endif
@@ -2149,7 +2067,10 @@ var LibraryGL = {
}
}
#endif
- GL.currProgram = program;
+ if (GL.currProgram != program) {
+ GL.currentRenderer = null; // This changes the FFP emulation shader program, need to recompute that.
+ GL.currProgram = program;
+ }
glUseProgram(program);
}
@@ -2689,32 +2610,85 @@ var LibraryGL = {
GL_SRC_ALPHA
];
- this.traverseState = function CTexEnv_traverseState(keyView) {
- keyView.next(this.mode);
- keyView.next(this.colorCombiner);
- keyView.next(this.alphaCombiner);
- keyView.next(this.colorCombiner);
- keyView.next(this.alphaScale);
- keyView.next(this.envColor[0]);
- keyView.next(this.envColor[1]);
- keyView.next(this.envColor[2]);
- keyView.next(this.envColor[3]);
-
- keyView.next(this.colorSrc[0]);
- keyView.next(this.colorSrc[1]);
- keyView.next(this.colorSrc[2]);
-
- keyView.next(this.alphaSrc[0]);
- keyView.next(this.alphaSrc[1]);
- keyView.next(this.alphaSrc[2]);
-
- keyView.next(this.colorOp[0]);
- keyView.next(this.colorOp[1]);
- keyView.next(this.colorOp[2]);
-
- keyView.next(this.alphaOp[0]);
- keyView.next(this.alphaOp[1]);
- keyView.next(this.alphaOp[2]);
+ // Map GLenums to small values to efficiently pack the enums to bits for tighter access.
+ this.traverseKey = {
+ // mode
+ 0x1E01 /* GL_REPLACE */: 0,
+ 0x2100 /* GL_MODULATE */: 1,
+ 0x0104 /* GL_ADD */: 2,
+ 0x0BE2 /* GL_BLEND */: 3,
+ 0x2101 /* GL_DECAL */: 4,
+ 0x8570 /* GL_COMBINE */: 5,
+
+ // additional color and alpha combiners
+ 0x84E7 /* GL_SUBTRACT */: 3,
+ 0x8575 /* GL_INTERPOLATE */: 4,
+
+ // color and alpha src
+ 0x1702 /* GL_TEXTURE */: 0,
+ 0x8576 /* GL_CONSTANT */: 1,
+ 0x8577 /* GL_PRIMARY_COLOR */: 2,
+ 0x8578 /* GL_PREVIOUS */: 3,
+
+ // color and alpha op
+ 0x0300 /* GL_SRC_COLOR */: 0,
+ 0x0301 /* GL_ONE_MINUS_SRC_COLOR */: 1,
+ 0x0302 /* GL_SRC_ALPHA */: 2,
+ 0x0300 /* GL_ONE_MINUS_SRC_ALPHA */: 3
+ };
+
+ // The tuple (key0,key1,key2) uniquely identifies the state of the variables in CTexEnv.
+ // -1 on key0 denotes 'the whole cached key is dirty'
+ this.key0 = -1;
+ this.key1 = 0;
+ this.key2 = 0;
+
+ this.computeKey0 = function() {
+ var k = this.traverseKey;
+ var key = k[this.mode] * 1638400; // 6 distinct values.
+ key += k[this.colorCombiner] * 327680; // 5 distinct values.
+ key += k[this.alphaCombiner] * 65536; // 5 distinct values.
+ // The above three fields have 6*5*5=150 distinct values -> 8 bits.
+ key += (this.colorScale-1) * 16384; // 10 bits used.
+ key += (this.alphaScale-1) * 4096; // 12 bits used.
+ key += k[this.colorSrc[0]] * 1024; // 14
+ key += k[this.colorSrc[1]] * 256; // 16
+ key += k[this.colorSrc[2]] * 64; // 18
+ key += k[this.alphaSrc[0]] * 16; // 20
+ key += k[this.alphaSrc[1]] * 4; // 22
+ key += k[this.alphaSrc[2]]; // 24 bits used total.
+ return key;
+ }
+ this.computeKey1 = function() {
+ var k = this.traverseKey;
+ key = k[this.colorOp[0]] * 4096;
+ key += k[this.colorOp[1]] * 1024;
+ key += k[this.colorOp[2]] * 256;
+ key += k[this.alphaOp[0]] * 16;
+ key += k[this.alphaOp[1]] * 4;
+ key += k[this.alphaOp[2]];
+ return key;
+ }
+ // TODO: remove this. The color should not be part of the key!
+ this.computeKey2 = function() {
+ return this.envColor[0] * 16777216 + this.envColor[1] * 65536 + this.envColor[2] * 256 + 1 + this.envColor[3];
+ }
+ this.recomputeKey = function() {
+ this.key0 = this.computeKey0();
+ this.key1 = this.computeKey1();
+ this.key2 = this.computeKey2();
+ }
+ this.invalidateKey = function() {
+ this.key0 = -1; // The key of this texture unit must be recomputed when rendering the next time.
+ GL.immediate.currentRenderer = null; // The currently used renderer must be re-evaluated at next render.
+ }
+ this.traverseState = function(keyView) {
+ if (this.key0 == -1) {
+ this.recomputeKey();
+ }
+ keyView.next(this.key0);
+ keyView.next(this.key1);
+ keyView.next(this.key2);
};
}
@@ -3076,16 +3050,28 @@ var LibraryGL = {
var cur = getCurTexUnit();
switch (cap) {
case GL_TEXTURE_1D:
- cur.enabled_tex1D = true;
+ if (!cur.enabled_tex1D) {
+ GL.immediate.currentRenderer = null; // Renderer state changed, and must be recreated or looked up again.
+ cur.enabled_tex1D = true;
+ }
break;
case GL_TEXTURE_2D:
- cur.enabled_tex2D = true;
+ if (!cur.enabled_tex2D) {
+ GL.immediate.currentRenderer = null;
+ cur.enabled_tex2D = true;
+ }
break;
case GL_TEXTURE_3D:
- cur.enabled_tex3D = true;
+ if (!cur.enabled_tex3D)