aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rwxr-xr-xemcc25
-rwxr-xr-xemscripten.py2
-rw-r--r--src/analyzer.js6
-rw-r--r--src/experimental/allow_loopvars_from_memsetcpy_inasm.diff97
-rw-r--r--src/library.js121
-rw-r--r--src/library_browser.js80
-rw-r--r--src/library_gl.js219
-rw-r--r--src/library_sdl.js34
-rw-r--r--src/long.js11
-rw-r--r--src/parseTools.js24
-rw-r--r--src/shell.html9
-rw-r--r--system/include/err.h95
-rw-r--r--system/lib/libc.symbols25
-rw-r--r--system/lib/libc/gen/err.c49
-rw-r--r--system/lib/libc/gen/errx.c49
-rw-r--r--system/lib/libc/gen/verr.c58
-rw-r--r--system/lib/libc/gen/verrx.c51
-rw-r--r--system/lib/libc/gen/vwarn.c55
-rw-r--r--system/lib/libc/gen/vwarnx.c48
-rw-r--r--system/lib/libc/gen/warn.c49
-rw-r--r--system/lib/libc/gen/warnx.c49
-rw-r--r--system/lib/libc/stdlib/getopt_long.c511
-rw-r--r--system/lib/libc/stdlib/strtod.c305
-rw-r--r--tests/cases/emptystruct.ll2
-rw-r--r--tests/cases/gepoverflow.ll2
-rw-r--r--tests/cases/storestruct.ll8
-rwxr-xr-xtests/fuzz/csmith_driver.py6
-rw-r--r--tests/hello_world_gles_full.c742
-rwxr-xr-xtests/runner.py183
-rw-r--r--tools/cache.py5
-rw-r--r--tools/shared.py4
32 files changed, 2669 insertions, 256 deletions
diff --git a/AUTHORS b/AUTHORS
index 296d4150..0741022f 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -52,4 +52,5 @@ a license to everyone to use it as detailed in LICENSE.)
* Roger Braun <roger@rogerbraun.net>
* Vladimir Vukicevic <vladimir@pobox.com> (copyright owned by Mozilla Foundation)
* Lorant Pinter <lorant.pinter@prezi.com>
+* Tobias Doerffel <tobias.doerffel@gmail.com>
diff --git a/emcc b/emcc
index d773dd85..fa62acb1 100755
--- a/emcc
+++ b/emcc
@@ -75,7 +75,7 @@ emcc can be influenced by a few environment variables:
EMMAKEN_COMPILER - The compiler to be used, if you don't want the default clang.
'''
-import os, sys, shutil, tempfile, subprocess, shlex, time
+import os, sys, shutil, tempfile, subprocess, shlex, time, re
from subprocess import PIPE, STDOUT
from tools import shared
from tools.shared import Compression, execute, suffix, unsuffixed, unsuffixed_basename
@@ -1069,7 +1069,22 @@ try:
def create_libc():
if DEBUG: print >> sys.stderr, 'emcc: building libc for cache'
o_s = []
- for src in ['dlmalloc.c', os.path.join('libcxx', 'new.cpp')]:
+ libc_files = [
+ 'dlmalloc.c',
+ os.path.join('libcxx', 'new.cpp'),
+ os.path.join('libc', 'stdlib', 'getopt_long.c'),
+ os.path.join('libc', 'gen', 'err.c'),
+ os.path.join('libc', 'gen', 'errx.c'),
+ os.path.join('libc', 'gen', 'warn.c'),
+ os.path.join('libc', 'gen', 'warnx.c'),
+ os.path.join('libc', 'gen', 'verr.c'),
+ os.path.join('libc', 'gen', 'verrx.c'),
+ os.path.join('libc', 'gen', 'vwarn.c'),
+ os.path.join('libc', 'gen', 'vwarnx.c'),
+ os.path.join('libc', 'stdlib', 'strtod.c'),
+ ];
+
+ for src in libc_files:
o = in_temp(os.path.basename(src) + '.o')
execute([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o], stdout=stdout, stderr=stderr)
o_s.append(o)
@@ -1347,6 +1362,12 @@ try:
flush_js_optimizer_queue()
+ if not minify_whitespace:
+ # Remove some trivial whitespace
+ src = open(final).read()
+ src = re.sub(r'\n+[ \n]*\n+', '\n', src)
+ open(final, 'w').write(src)
+
# If we were asked to also generate HTML, do that
if final_suffix == 'html':
if DEBUG: print >> sys.stderr, 'emcc: generating HTML'
diff --git a/emscripten.py b/emscripten.py
index 08ae85c5..b698654b 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -238,7 +238,7 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None,
outputs = [output.split('//FORWARDED_DATA:') for output in outputs]
for output in outputs:
- assert len(output) == 2, 'Did not receive forwarded data in an output - process failed? We only got: ' + output[0][-300:]
+ assert len(output) == 2, 'Did not receive forwarded data in an output - process failed? We only got: ' + output[0][-3000:]
if DEBUG: print >> sys.stderr, ' emscript: phase 2 took %s seconds' % (time.time() - t)
if DEBUG: t = time.time()
diff --git a/src/analyzer.js b/src/analyzer.js
index dbbb267d..209e3140 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -290,7 +290,7 @@ function analyzer(data, sidePass) {
var elements = getLegalParams([item.value], bits)[0];
var j = 0;
elements.forEach(function(element) {
- var tempVar = '$st$' + i + '$' + j;
+ var tempVar = '$st$' + (tempId++) + '$' + j;
toAdd.push({
intertype: 'getelementptr',
assignTo: tempVar,
@@ -401,7 +401,7 @@ function analyzer(data, sidePass) {
var j = 0;
var toAdd = [];
elements.forEach(function(element) {
- var tempVar = '$st$' + i + '$' + j;
+ var tempVar = '$ld$' + (tempId++) + '$' + j;
toAdd.push({
intertype: 'getelementptr',
assignTo: tempVar,
@@ -952,6 +952,7 @@ function analyzer(data, sidePass) {
// Function parameters
func.params.forEach(function(param) {
if (param.intertype !== 'varargs') {
+ if (func.variables[param.ident]) warn('cannot have duplicate variable names: ' + param.ident); // toNiceIdent collisions?
func.variables[param.ident] = {
ident: param.ident,
type: param.type,
@@ -965,6 +966,7 @@ function analyzer(data, sidePass) {
// Normal variables
func.lines.forEach(function(item, i) {
if (item.assignTo) {
+ if (func.variables[item.assignTo]) warn('cannot have duplicate variable names: ' + item.assignTo); // toNiceIdent collisions?
var variable = func.variables[item.assignTo] = {
ident: item.assignTo,
type: item.type,
diff --git a/src/experimental/allow_loopvars_from_memsetcpy_inasm.diff b/src/experimental/allow_loopvars_from_memsetcpy_inasm.diff
new file mode 100644
index 00000000..a2dde7da
--- /dev/null
+++ b/src/experimental/allow_loopvars_from_memsetcpy_inasm.diff
@@ -0,0 +1,97 @@
+commit a61ef3dbbaf7333ad67fca29c0aad5bcc99b653a
+Author: Alon Zakai <alonzakai@gmail.com>
+Date: Wed Mar 6 18:18:03 2013 -0800
+
+ handle new vars in asm code, such as the loop vars from memset/memcpy loops
+
+diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
+index f2dc516..65059e8 100644
+--- a/tools/js-optimizer.js
++++ b/tools/js-optimizer.js
+@@ -1321,7 +1321,7 @@ function normalizeAsm(func) {
+ var name = v[0];
+ var value = v[1];
+ if (!(name in data.vars)) {
+- assert(value[0] == 'num' || (value[0] == 'unary-prefix' && value[2][0] == 'num')); // must be valid coercion no-op
++ if (!(value[0] == 'num' || (value[0] == 'unary-prefix' && value[2][0] == 'num'))) break outer; // must be valid coercion no-op
+ data.vars[name] = detectAsmCoercion(value);
+ v.length = 1; // make an un-assigning var
+ } else {
+@@ -1331,6 +1331,7 @@ function normalizeAsm(func) {
+ i++;
+ }
+ // finally, look for other var definitions and collect them
++ var extra = [];
+ while (i < stats.length) {
+ traverse(stats[i], function(node, type) {
+ if (type == 'var') {
+@@ -1340,6 +1341,7 @@ function normalizeAsm(func) {
+ var value = v[1];
+ if (!(name in data.vars)) {
+ data.vars[name] = detectAsmCoercion(value);
++ extra.push(['var', [[name]]]); // add a 'var' for normal JS
+ }
+ }
+ unVarify(node[1], node);
+@@ -1353,6 +1355,7 @@ function normalizeAsm(func) {
+ });
+ i++;
+ }
++ if (extra.length > 0) stats.splice.apply(stats, [0, 0].concat(extra));
+ //printErr('normalized \n\n' + astToSrc(func) + '\n\nwith: ' + JSON.stringify(data));
+ return data;
+ }
+diff --git a/tools/test-js-optimizer-asm-regs-output.js b/tools/test-js-optimizer-asm-regs-output.js
+index 99bccd2..f84b8d5 100644
+--- a/tools/test-js-optimizer-asm-regs-output.js
++++ b/tools/test-js-optimizer-asm-regs-output.js
+@@ -9,6 +9,18 @@ function asm(d1, i2) {
+ d4 = d1 * 5;
+ return d4;
+ }
++function asm2(d1, i2) {
++ d1 = +d1;
++ i2 = i2 | 0;
++ var i3 = 0, d4 = +0;
++ i3 = i2;
++ i2 = d1 + i3 | 0;
++ d1 = d(Math_max(10, Math_min(5, f())));
++ i3 = i2 + 2 | 0;
++ print(i3);
++ d4 = d1 * 5;
++ return d4;
++}
+ function _doit(i1, i2, i3) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+diff --git a/tools/test-js-optimizer-asm-regs.js b/tools/test-js-optimizer-asm-regs.js
+index 0afced2..fbaa7c4 100644
+--- a/tools/test-js-optimizer-asm-regs.js
++++ b/tools/test-js-optimizer-asm-regs.js
+@@ -10,6 +10,19 @@ function asm(x, y) {
+ double2 = double1*5;
+ return double2;
+ }
++function asm2(x, y) {
++ x = +x;
++ y = y | 0;
++ var int1 = 0, int2 = 0; // do not mix the types!
++ var double1 = +0, double2 = +0;
++ var tempy = y;
++ int1 = (x+tempy)|0;
++ double1 = d(Math.max(10, Math_min(5, f())));
++ int2 = (int1+2)|0;
++ print(int2);
++ double2 = double1*5;
++ return double2;
++}
+ function _doit($x, $y$0, $y$1) {
+ $x = $x | 0;
+ $y$0 = $y$0 | 0;
+@@ -41,5 +54,5 @@ function retf() {
+ }
+ // missing final return, need it as a float
+ }
+-// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "_doit", "rett", "ret2t", "retf"]
++// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "asm2", "_doit", "rett", "ret2t", "retf"]
+
diff --git a/src/library.js b/src/library.js
index a5166c72..d787e30c 100644
--- a/src/library.js
+++ b/src/library.js
@@ -3670,6 +3670,17 @@ LibraryManager.library = {
abs: 'Math.abs',
labs: 'Math.abs',
+#if USE_TYPED_ARRAYS == 2
+ llabs__deps: [function() { Types.preciseI64MathUsed = 1 }],
+ llabs: function(lo, hi) {
+ i64Math.abs(lo, hi);
+ {{{ makeStructuralReturn([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32')]) }}};
+ },
+#else
+ llabs: function(lo, hi) {
+ throw 'unsupported llabs';
+ },
+#endif
exit__deps: ['_exit'],
exit: function(status) {
@@ -3727,93 +3738,6 @@ LibraryManager.library = {
return ret;
},
- strtod__deps: ['isspace', 'isdigit'],
- strtod: function(str, endptr) {
- var origin = str;
-
- // Skip space.
- while (_isspace({{{ makeGetValue('str', 0, 'i8') }}})) str++;
-
- // Check for a plus/minus sign.
- var multiplier = 1;
- if ({{{ makeGetValue('str', 0, 'i8') }}} == '-'.charCodeAt(0)) {
- multiplier = -1;
- str++;
- } else if ({{{ makeGetValue('str', 0, 'i8') }}} == '+'.charCodeAt(0)) {
- str++;
- }
-
- var chr;
- var ret = 0;
-
- // Get whole part.
- var whole = false;
- while(1) {
- chr = {{{ makeGetValue('str', 0, 'i8') }}};
- if (!_isdigit(chr)) break;
- whole = true;
- ret = ret*10 + chr - '0'.charCodeAt(0);
- str++;
- }
-
- // Get fractional part.
- var fraction = false;
- if ({{{ makeGetValue('str', 0, 'i8') }}} == '.'.charCodeAt(0)) {
- str++;
- var mul = 1/10;
- while(1) {
- chr = {{{ makeGetValue('str', 0, 'i8') }}};
- if (!_isdigit(chr)) break;
- fraction = true;
- ret += mul*(chr - '0'.charCodeAt(0));
- mul /= 10;
- str++;
- }
- }
-
- if (!whole && !fraction) {
- if (endptr) {
- {{{ makeSetValue('endptr', 0, 'origin', '*') }}}
- }
- return 0;
- }
-
- // Get exponent part.
- chr = {{{ makeGetValue('str', 0, 'i8') }}};
- if (chr == 'e'.charCodeAt(0) || chr == 'E'.charCodeAt(0)) {
- str++;
- var exponent = 0;
- var expNegative = false;
- chr = {{{ makeGetValue('str', 0, 'i8') }}};
- if (chr == '-'.charCodeAt(0)) {
- expNegative = true;
- str++;
- } else if (chr == '+'.charCodeAt(0)) {
- str++;
- }
- chr = {{{ makeGetValue('str', 0, 'i8') }}};
- while(1) {
- if (!_isdigit(chr)) break;
- exponent = exponent*10 + chr - '0'.charCodeAt(0);
- str++;
- chr = {{{ makeGetValue('str', 0, 'i8') }}};
- }
- if (expNegative) exponent = -exponent;
- ret *= Math.pow(10, exponent);
- }
-
- // Set end pointer.
- if (endptr) {
- {{{ makeSetValue('endptr', 0, 'str', '*') }}}
- }
-
- return ret * multiplier;
- },
- strtod_l: 'strtod', // no locale support yet
- strtold: 'strtod', // XXX add real support for long double
- strtold_l: 'strtold', // no locale support yet
- strtof: 'strtod', // use stdtod to handle strtof
-
_parseInt__deps: ['isspace', '__setErrNo', '$ERRNO_CODES'],
_parseInt: function(str, endptr, base, min, max, bits, unsign) {
// Skip space.
@@ -3972,11 +3896,6 @@ LibraryManager.library = {
},
strtoull_l: 'strtoull', // no locale support yet
- atof__deps: ['strtod'],
- atof: function(ptr) {
- return _strtod(ptr, null);
- },
-
atoi__deps: ['strtol'],
atoi: function(ptr) {
return _strtol(ptr, null, 10);
@@ -4315,7 +4234,7 @@ LibraryManager.library = {
ptr = ptr|0; value = value|0; num = num|0;
var stop = 0, value4 = 0, stop4 = 0, unaligned = 0;
stop = (ptr + num)|0;
- if ((num|0) >= {{{ SEEK_OPTIMAL_ALIGN_MIN }}}) {
+ if ((num|0) >= {{{ Math.round(2.5*UNROLL_LOOP_MAX) }}}) {
// This is unaligned, but quite large, so work hard to get to aligned settings
value = value & 0xff;
unaligned = ptr & 3;
@@ -4977,6 +4896,20 @@ LibraryManager.library = {
#endif
},
+ llvm_ctpop_i32: function(x) {
+ var ret = 0;
+ while (x) {
+ if (x&1) ret++;
+ x >>= 1;
+ }
+ return ret;
+ },
+
+ llvm_ctpop_i64__deps: ['llvm_ctpop_i32'],
+ llvm_ctpop_i64: function(l, h) {
+ return _llvm_ctpop_i32(l) + _llvm_ctpop_i32(h);
+ },
+
llvm_trap: function() {
throw 'trap! ' + new Error().stack;
},
@@ -6188,7 +6121,7 @@ LibraryManager.library = {
setjmp__inline: function(env) {
// Save the label
- return '(tempInt = setjmpId++, mySetjmpIds[tempInt] = 1, setjmpLabels[tempInt] = label,' + makeSetValue(env, '0', 'tempInt', 'i32') + ', 0)';
+ return '(tempInt = setjmpId++, mySetjmpIds[tempInt] = 1, setjmpLabels[tempInt] = label,' + makeSetValue(env, '0', 'tempInt', 'i32', undefined, undefined, undefined, undefined, ',') + ', 0)';
},
longjmp: function(env, value) {
diff --git a/src/library_browser.js b/src/library_browser.js
index 5b19a360..bdd94bac 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -3,7 +3,7 @@
// Utilities for browser environments
mergeInto(LibraryManager.library, {
- $Browser__postset: 'Module["requestFullScreen"] = function() { Browser.requestFullScreen() };\n' + // exports
+ $Browser__postset: 'Module["requestFullScreen"] = function(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };\n' + // exports
'Module["requestAnimationFrame"] = function(func) { Browser.requestAnimationFrame(func) };\n' +
'Module["pauseMainLoop"] = function() { Browser.mainLoop.pause() };\n' +
'Module["resumeMainLoop"] = function() { Browser.mainLoop.resume() };\n',
@@ -40,6 +40,7 @@ mergeInto(LibraryManager.library, {
}
}
},
+ isFullScreen: false,
pointerLock: false,
moduleContextCreatedCallbacks: [],
workers: [],
@@ -205,10 +206,10 @@ mergeInto(LibraryManager.library, {
try {
if (useWebGL) {
ctx = canvas.getContext('experimental-webgl', {
- alpha: false,
#if GL_TESTING
- preserveDrawingBuffer: true
+ preserveDrawingBuffer: true,
#endif
+ alpha: false
});
} else {
ctx = canvas.getContext('2d');
@@ -273,36 +274,60 @@ mergeInto(LibraryManager.library, {
}
return ctx;
},
+
destroyContext: function(canvas, useWebGL, setInModule) {},
- requestFullScreen: function() {
+
+ fullScreenHandlersInstalled: false,
+ lockPointer: undefined,
+ resizeCanvas: undefined,
+ requestFullScreen: function(lockPointer, resizeCanvas) {
+ this.lockPointer = lockPointer;
+ this.resizeCanvas = resizeCanvas;
+ if (typeof this.lockPointer === 'undefined') this.lockPointer = true;
+ if (typeof this.resizeCanvas === 'undefined') this.resizeCanvas = false;
+
var canvas = Module['canvas'];
function fullScreenChange() {
- var isFullScreen = false;
+ Browser.isFullScreen = false;
if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
document['fullScreenElement'] || document['fullscreenElement']) === canvas) {
canvas.requestPointerLock = canvas['requestPointerLock'] ||
canvas['mozRequestPointerLock'] ||
canvas['webkitRequestPointerLock'];
- canvas.requestPointerLock();
- isFullScreen = true;
+ canvas.exitPointerLock = document['exitPointerLock'] ||
+ document['mozExitPointerLock'] ||
+ document['webkitExitPointerLock'];
+ canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
+ canvas.cancelFullScreen = document['cancelFullScreen'] ||
+ document['mozCancelFullScreen'] ||
+ document['webkitCancelFullScreen'];
+ canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+ if (Browser.lockPointer) canvas.requestPointerLock();
+ Browser.isFullScreen = true;
+ if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+ } else if (Browser.resizeCanvas){
+ Browser.setWindowedCanvasSize();
}
- if (Module['onFullScreen']) Module['onFullScreen'](isFullScreen);
+ if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
}
- document.addEventListener('fullscreenchange', fullScreenChange, false);
- document.addEventListener('mozfullscreenchange', fullScreenChange, false);
- document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
-
function pointerLockChange() {
Browser.pointerLock = document['pointerLockElement'] === canvas ||
document['mozPointerLockElement'] === canvas ||
document['webkitPointerLockElement'] === canvas;
}
- document.addEventListener('pointerlockchange', pointerLockChange, false);
- document.addEventListener('mozpointerlockchange', pointerLockChange, false);
- document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+ if (!this.fullScreenHandlersInstalled) {
+ this.fullScreenHandlersInstalled = true;
+ document.addEventListener('fullscreenchange', fullScreenChange, false);
+ document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+ document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+
+ document.addEventListener('pointerlockchange', pointerLockChange, false);
+ document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+ document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+ }
canvas.requestFullScreen = canvas['requestFullScreen'] ||
canvas['mozRequestFullScreen'] ||
@@ -380,7 +405,32 @@ mergeInto(LibraryManager.library, {
canvas.width = width;
canvas.height = height;
if (!noUpdates) Browser.updateResizeListeners();
+ },
+
+ windowedWidth: 0,
+ windowedHeight: 0,
+ setFullScreenCanvasSize: function() {
+ var canvas = Module['canvas'];
+ this.windowedWidth = canvas.width;
+ this.windowedHeight = canvas.height;
+ canvas.width = screen.width;
+ canvas.height = screen.height;
+ var flags = {{{ makeGetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'i32', 0, 1) }}};
+ flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+ {{{ makeSetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'flags', 'i32') }}}
+ Browser.updateResizeListeners();
+ },
+
+ setWindowedCanvasSize: function() {
+ var canvas = Module['canvas'];
+ canvas.width = this.windowedWidth;
+ canvas.height = this.windowedHeight;
+ var flags = {{{ makeGetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'i32', 0, 1) }}};
+ flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+ {{{ makeSetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'flags', 'i32') }}}
+ Browser.updateResizeListeners();
}
+
},
emscripten_async_wget: function(url, file, onload, onerror) {
diff --git a/src/library_gl.js b/src/library_gl.js
index 4977d2e9..c6007809 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -21,7 +21,6 @@ var LibraryGL = {
#if FULL_ES2
clientBuffers: [],
- enabledClientBuffers: [],
#endif
currArrayBuffer: 0,
currElementArrayBuffer: 0,
@@ -59,6 +58,65 @@ var LibraryGL = {
return ret;
},
+ // Temporary buffers
+ MAX_TEMP_BUFFER_SIZE: {{{ GL_MAX_TEMP_BUFFER_SIZE }}},
+ tempBufferIndexLookup: null,
+ tempVertexBuffers: null,
+ tempIndexBuffers: null,
+ tempQuadIndexBuffer: null,
+
+ generateTempBuffers: function(quads) {
+ this.tempBufferIndexLookup = new Uint8Array(this.MAX_TEMP_BUFFER_SIZE+1);
+ this.tempVertexBuffers = [];
+ this.tempIndexBuffers = [];
+ var last = -1, curr = -1;
+ var size = 1;
+ for (var i = 0; i <= this.MAX_TEMP_BUFFER_SIZE; i++) {
+ if (i > size) {
+ size <<= 1;
+ }
+ if (size != last) {
+ curr++;
+ this.tempVertexBuffers[curr] = Module.ctx.createBuffer();
+ Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, this.tempVertexBuffers[curr]);
+ Module.ctx.bufferData(Module.ctx.ARRAY_BUFFER, size, Module.ctx.DYNAMIC_DRAW);
+ Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, null);
+ this.tempIndexBuffers[curr] = Module.ctx.createBuffer();
+ Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, this.tempIndexBuffers[curr]);
+ Module.ctx.bufferData(Module.ctx.ELEMENT_ARRAY_BUFFER, size, Module.ctx.DYNAMIC_DRAW);
+ Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, null);
+ last = size;
+ }
+ this.tempBufferIndexLookup[i] = curr;
+ }
+
+ if (quads) {
+ // GL_QUAD indexes can be precalculated
+ this.tempQuadIndexBuffer = Module.ctx.createBuffer();
+ Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, this.tempQuadIndexBuffer);
+ var numIndexes = this.MAX_TEMP_BUFFER_SIZE >> 1;
+ var quadIndexes = new Uint16Array(numIndexes);
+ var i = 0, v = 0;
+ while (1) {
+ quadIndexes[i++] = v;
+ if (i >= numIndexes) break;
+ quadIndexes[i++] = v+1;
+ if (i >= numIndexes) break;
+ quadIndexes[i++] = v+2;
+ if (i >= numIndexes) break;
+ quadIndexes[i++] = v;
+ if (i >= numIndexes) break;
+ quadIndexes[i++] = v+2;
+ if (i >= numIndexes) break;
+ quadIndexes[i++] = v+3;
+ if (i >= numIndexes) break;
+ v += 4;
+ }
+ Module.ctx.bufferData(Module.ctx.ELEMENT_ARRAY_BUFFER, quadIndexes, Module.ctx.STATIC_DRAW);
+ Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, null);
+ }
+ },
+
// Linear lookup in one of the tables (buffers, programs, etc.). TODO: consider using a weakmap to make this faster, if it matters
scan: function(table, object) {
for (var item in table) {
@@ -207,19 +265,34 @@ var LibraryGL = {
return size * typeSize * count;
},
+ usedTempBuffers: [],
+
preDrawHandleClientVertexAttribBindings: function(count) {
GL.resetBufferBinding = false;
+
+ var used = GL.usedTempBuffers;
+ used.length = 0;
+
+ // TODO: initial pass to detect ranges we need to upload, might not need an upload per attrib
for (var i = 0; i < GL.maxVertexAttribs; ++i) {
- if (!GL.enabledClientBuffers[i] || !GL.clientBuffers[i]) continue;
-
- GL.resetBufferBinding = true;
-
var cb = GL.clientBuffers[i];
-
- var buf = Module.ctx.createBuffer();
+ if (!cb.enabled) continue;
+
+ GL.resetBufferBinding = true;
+
+ var size = GL.calcBufLength(cb.size, cb.type, cb.stride, count);
+ var index = GL.tempBufferIndexLookup[size];
+ var buf;
+ do {
+#if ASSERTIONS
+ assert(index < GL.tempVertexBuffers.length);
+#endif
+ buf = GL.tempVertexBuffers[index++];
+ } while (used.indexOf(buf) >= 0);
+ used.push(buf);
Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, buf);
Module.ctx.bufferData(Module.ctx.ARRAY_BUFFER,
- HEAPU8.subarray(cb.ptr, cb.ptr + GL.calcBufLength(cb.size, cb.type, cb.stride, count)),
+ HEAPU8.subarray(cb.ptr, cb.ptr + size),
Module.ctx.DYNAMIC_DRAW);
Module.ctx.vertexAttribPointer(i, cb.size, cb.type, cb.normalized, cb.stride, 0);
}
@@ -239,6 +312,13 @@ var LibraryGL = {
if (!Module.useWebGL) return; // an app might link both gl and 2d backends
GL.maxVertexAttribs = Module.ctx.getParameter(Module.ctx.MAX_VERTEX_ATTRIBS);
+#if FULL_ES2
+ for (var i = 0; i < GL.maxVertexAttribs; i++) {
+ GL.clientBuffers[i] = { enabled: false, size: 0, type: 0, normalized: 0, stride: 0, ptr: 0 };
+ }
+
+ GL.generateTempBuffers();
+#endif
GL.compressionExt = Module.ctx.getExtension('WEBGL_compressed_texture_s3tc') ||
Module.ctx.getExtension('MOZ_WEBGL_compressed_texture_s3tc') ||
@@ -612,7 +692,7 @@ var LibraryGL = {
glGetVertexAttribfv: function(index, pname, params) {
#if FULL_ES2
- if (GL.clientBuffers[index]) {
+ if (GL.clientBuffers[index].enabled) {
Module.printErr("glGetVertexAttribfv on client-side array: not supported, bad data returned");
}
#endif
@@ -628,7 +708,7 @@ var LibraryGL = {
glGetVertexAttribiv: function(index, pname, params) {
#if FULL_ES2
- if (GL.clientBuffers[index]) {
+ if (GL.clientBuffers[index].enabled) {
Module.printErr("glGetVertexAttribiv on client-side array: not supported, bad data returned");
}
#endif
@@ -644,7 +724,7 @@ var LibraryGL = {
glGetVertexAttribPointerv: function(index, pname, pointer) {
#if FULL_ES2
- if (GL.clientBuffers[index]) {
+ if (GL.clientBuffers[index].enabled) {
Module.printErr("glGetVertexAttribPointer on client-side array: not supported, bad data returned");
}
#endif
@@ -1693,62 +1773,6 @@ var LibraryGL = {
this.modifiedClientAttributes = true;
},
- // Temporary buffers
- MAX_TEMP_BUFFER_SIZE: {{{ GL_MAX_TEMP_BUFFER_SIZE }}},
- tempBufferIndexLookup: null,
- tempVertexBuffers: null,
- tempIndexBuffers: null,
- tempQuadIndexBuffer: null,
-
- generateTempBuffers: function() {
- this.tempBufferIndexLookup = new Uint8Array(this.MAX_TEMP_BUFFER_SIZE+1);
- this.tempVertexBuffers = [];
- this.tempIndexBuffers = [];
- var last = -1, curr = -1;
- var size = 1;
- for (var i = 0; i <= this.MAX_TEMP_BUFFER_SIZE; i++) {
- if (i > size) {
- size <<= 1;
- }
- if (size != last) {
- curr++;
- this.tempVertexBuffers[curr] = Module.ctx.createBuffer();
- Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, this.tempVertexBuffers[curr]);
- Module.ctx.bufferData(Module.ctx.ARRAY_BUFFER, size, Module.ctx.DYNAMIC_DRAW);
- Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, null);
- this.tempIndexBuffers[curr] = Module.ctx.createBuffer();
- Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, this.tempIndexBuffers[curr]);
- Module.ctx.bufferData(Module.ctx.ELEMENT_ARRAY_BUFFER, size, Module.ctx.DYNAMIC_DRAW);
- Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, null);
- last = size;
- }
- this.tempBufferIndexLookup[i] = curr;
- }
- // GL_QUAD indexes can be precalculated
- this.tempQuadIndexBuffer = Module.ctx.createBuffer();
- Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, this.tempQuadIndexBuffer);
- var numIndexes = this.MAX_TEMP_BUFFER_SIZE >> 1;
- var quadIndexes = new Uint16Array(numIndexes);
- var i = 0, v = 0;
- while (1) {
- quadIndexes[i++] = v;
- if (i >= numIndexes) break;
- quadIndexes[i++] = v+1;
- if (i >= numIndexes) break;
- quadIndexes[i++] = v+2;
- if (i >= numIndexes) break;