aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js2
-rw-r--r--src/intertyper.js10
-rw-r--r--src/jsifier.js24
-rw-r--r--src/library.js24
-rw-r--r--src/library_egl.js14
-rw-r--r--src/library_fs.js172
-rw-r--r--src/library_gl.js74
-rw-r--r--src/library_glfw.js4
-rw-r--r--src/library_glut.js4
-rw-r--r--src/library_idbfs.js2
-rw-r--r--src/library_memfs.js106
-rw-r--r--src/library_nodefs.js12
-rw-r--r--src/library_path.js22
-rw-r--r--src/library_sdl.js48
-rw-r--r--src/parseTools.js102
-rw-r--r--src/preamble.js10
-rw-r--r--src/runtime.js4
-rw-r--r--src/shell.html5
18 files changed, 376 insertions, 263 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index 2b74a83f..253c5505 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -418,7 +418,7 @@ function analyzer(data, sidePass) {
toAdd.push({
intertype: 'value',
assignTo: element.ident,
- type: element.bits,
+ type: 'i' + element.bits,
ident: 'tempRet' + (j - 1)
});
assert(j<10); // TODO: dynamically create more than 10 tempRet-s
diff --git a/src/intertyper.js b/src/intertyper.js
index d3640889..fceeb38d 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -682,7 +682,7 @@ function intertyper(lines, sidePass, baseLineNums) {
}
if (item.assignTo) item.ident = 'return ' + item.ident;
item.ident = '(function(' + params + ') { ' + item.ident + ' })(' + args + ');';
- return { forward: null, ret: item, item: item };
+ return { ret: item, item: item };
}
if (item.ident.substr(-2) == '()') {
// See comment in isStructType()
@@ -705,13 +705,12 @@ function intertyper(lines, sidePass, baseLineNums) {
if (item.indent == 2) {
// standalone call - not in assign
item.standalone = true;
- return { forward: null, ret: item, item: item };
+ return { ret: item, item: item };
}
- return { forward: item, ret: null, item: item };
+ return { ret: null, item: item };
}
function callHandler(item) {
var result = makeCall.call(this, item, 'call');
- if (result.forward) this.forwardItem(result.forward, 'Reintegrator');
return result.ret;
}
function invokeHandler(item) {
@@ -721,10 +720,9 @@ function intertyper(lines, sidePass, baseLineNums) {
finalResults.push({
intertype: 'branch',
label: result.item.toLabel,
- lineNum: (result.forward ? item.parentLineNum : item.lineNum) + 0.5
+ lineNum: item.lineNum + 0.5
});
}
- if (result.forward) this.forwardItem(result.forward, 'Reintegrator');
return result.ret;
}
function atomicHandler(item) {
diff --git a/src/jsifier.js b/src/jsifier.js
index 669cec73..d5b87a77 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -937,11 +937,12 @@ function JSify(data, functionsOnly, givenFunctions) {
}
if (item.valueType[item.valueType.length-1] === '>') {
// vector store TODO: move to makeSetValue?
- var base = getVectorBaseType(item.valueType);
- return '(' + makeSetValue(item.ident, 0, value + '.x', base, 0, 0, item.align) + ',' +
- makeSetValue(item.ident, 4, value + '.y', base, 0, 0, item.align) + ',' +
- makeSetValue(item.ident, 8, value + '.z', base, 0, 0, item.align) + ',' +
- makeSetValue(item.ident, 12, value + '.w', base, 0, 0, item.align) + ')';
+ var native = getVectorNativeType(item.valueType);
+ var base = getSIMDName(native);
+ return '(' + makeSetValue(item.ident, 0, value + '.x', native, 0, 0, item.align) + ',' +
+ makeSetValue(item.ident, 4, value + '.y', native, 0, 0, item.align) + ',' +
+ makeSetValue(item.ident, 8, value + '.z', native, 0, 0, item.align) + ',' +
+ makeSetValue(item.ident, 12, value + '.w', native, 0, 0, item.align) + ');';
}
switch (impl) {
case VAR_NATIVIZED:
@@ -1312,11 +1313,12 @@ function JSify(data, functionsOnly, givenFunctions) {
var value = finalizeLLVMParameter(item.pointer);
if (item.valueType[item.valueType.length-1] === '>') {
// vector load
- var base = getVectorBaseType(item.valueType);
- return base + '32x4(' + makeGetValue(value, 0, base, 0, item.unsigned, 0, item.align) + ',' +
- makeGetValue(value, 4, base, 0, item.unsigned, 0, item.align) + ',' +
- makeGetValue(value, 8, base, 0, item.unsigned, 0, item.align) + ',' +
- makeGetValue(value, 12, base, 0, item.unsigned, 0, item.align) + ')';
+ var native = getVectorNativeType(item.valueType);
+ var base = getSIMDName(native);
+ return base + '32x4(' + makeGetValue(value, 0, native, 0, item.unsigned, 0, item.align) + ',' +
+ makeGetValue(value, 4, native, 0, item.unsigned, 0, item.align) + ',' +
+ makeGetValue(value, 8, native, 0, item.unsigned, 0, item.align) + ',' +
+ makeGetValue(value, 12, native, 0, item.unsigned, 0, item.align) + ');';
}
var impl = item.ident ? getVarImpl(item.funcData, item.ident) : VAR_EMULATED;
switch (impl) {
@@ -1478,7 +1480,7 @@ function JSify(data, functionsOnly, givenFunctions) {
}
params.forEach(function(param, i) {
- var val = finalizeParam(param);
+ var val = finalizeLLVMParameter(param);
if (!hasVarArgs || useJSArgs || i < normalArgs) {
args.push(val);
argsTypes.push(param.type);
diff --git a/src/library.js b/src/library.js
index 875d8bab..e3cdc7c3 100644
--- a/src/library.js
+++ b/src/library.js
@@ -1579,12 +1579,12 @@ LibraryManager.library = {
// stdio.h
// ==========================================================================
- _isFloat: function(text) {
- return !!(/^[+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?$/.exec(text));
+ _getFloat: function(text) {
+ return /^[+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?/.exec(text);
},
// TODO: Document.
- _scanString__deps: ['_isFloat'],
+ _scanString__deps: ['_getFloat'],
_scanString: function(format, get, unget, varargs) {
if (!__scanString.whiteSpace) {
__scanString.whiteSpace = {};
@@ -1743,15 +1743,13 @@ LibraryManager.library = {
// Read characters according to the format. floats are trickier, they may be in an unfloat state in the middle, then be a valid float later
if (type == 'f' || type == 'e' || type == 'g' ||
type == 'F' || type == 'E' || type == 'G') {
- var last = 0;
next = get();
- while (next > 0) {
+ while (next > 0 && (!(next in __scanString.whiteSpace))) {
buffer.push(String.fromCharCode(next));
- if (__isFloat(buffer.join(''))) {
- last = buffer.length;
- }
next = get();
}
+ var m = __getFloat(buffer.join(''));
+ var last = m ? m[0].length : 0;
for (var i = 0; i < buffer.length - last + 1; i++) {
unget();
}
@@ -8580,7 +8578,7 @@ LibraryManager.library = {
},
emscripten_run_script_string: function(ptr) {
- var s = eval(Pointer_stringify(ptr));
+ var s = eval(Pointer_stringify(ptr)) + '';
var me = _emscripten_run_script_string;
if (!me.bufferSize || me.bufferSize < s.length+1) {
if (me.bufferSize) _free(me.buffer);
@@ -8623,6 +8621,14 @@ LibraryManager.library = {
},
//============================
+ // emscripten vector ops
+ //============================
+
+ emscripten_float32x4_signmask__inline: function(x) {
+ return x + '.signMask()';
+ },
+
+ //============================
// i64 math
//============================
diff --git a/src/library_egl.js b/src/library_egl.js
index c25dc8ef..cc702fec 100644
--- a/src/library_egl.js
+++ b/src/library_egl.js
@@ -10,6 +10,8 @@ var LibraryEGL = {
$EGL: {
// This variable tracks the success status of the most recently invoked EGL function call.
eglErrorCode: 0x3000 /* EGL_SUCCESS */,
+
+ stringCache: {},
setErrorCode: function(code) {
EGL.eglErrorCode = code;
@@ -416,15 +418,19 @@ var LibraryEGL = {
}
//\todo An EGL_NOT_INITIALIZED error is generated if EGL is not initialized for dpy.
EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
+ if (EGL.stringCache[name]) return EGL.stringCache[name];
+ var ret;
switch(name) {
- case 0x3053 /* EGL_VENDOR */: return allocate(intArrayFromString("Emscripten"), 'i8', ALLOC_NORMAL);
- case 0x3054 /* EGL_VERSION */: return allocate(intArrayFromString("1.4 Emscripten EGL"), 'i8', ALLOC_NORMAL);
- case 0x3055 /* EGL_EXTENSIONS */: return allocate(intArrayFromString(""), 'i8', ALLOC_NORMAL); // Currently not supporting any EGL extensions.
- case 0x308D /* EGL_CLIENT_APIS */: return allocate(intArrayFromString("OpenGL_ES"), 'i8', ALLOC_NORMAL);
+ case 0x3053 /* EGL_VENDOR */: ret = allocate(intArrayFromString("Emscripten"), 'i8', ALLOC_NORMAL); break;
+ case 0x3054 /* EGL_VERSION */: ret = allocate(intArrayFromString("1.4 Emscripten EGL"), 'i8', ALLOC_NORMAL); break;
+ case 0x3055 /* EGL_EXTENSIONS */: ret = allocate(intArrayFromString(""), 'i8', ALLOC_NORMAL); break; // Currently not supporting any EGL extensions.
+ case 0x308D /* EGL_CLIENT_APIS */: ret = allocate(intArrayFromString("OpenGL_ES"), 'i8', ALLOC_NORMAL); break;
default:
EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */);
return 0;
}
+ EGL.stringCache[name] = ret;
+ return ret;
},
// EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api);
diff --git a/src/library_fs.js b/src/library_fs.js
index bd1522a8..aece2664 100644
--- a/src/library_fs.js
+++ b/src/library_fs.js
@@ -28,6 +28,7 @@ mergeInto(LibraryManager.library, {
ignorePermissions: true,
ErrnoError: null, // set during init
+ genericErrors: {},
handleFSError: function(e) {
if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
@@ -62,7 +63,7 @@ mergeInto(LibraryManager.library, {
}
current = FS.lookupNode(current, parts[i]);
- current_path = PATH.join(current_path, parts[i]);
+ current_path = PATH.join2(current_path, parts[i]);
// jump to the mount's root node if this is a mountpoint
if (FS.isMountpoint(current)) {
@@ -94,9 +95,11 @@ mergeInto(LibraryManager.library, {
var path;
while (true) {
if (FS.isRoot(node)) {
- return path ? PATH.join(node.mount.mountpoint, path) : node.mount.mountpoint;
+ var mount = node.mount.mountpoint;
+ if (!path) return mount;
+ return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
}
- path = path ? PATH.join(node.name, path) : node.name;
+ path = path ? node.name + '/' + path : node.name;
node = node.parent;
}
},
@@ -158,44 +161,50 @@ mergeInto(LibraryManager.library, {
return FS.lookup(parent, name);
},
createNode: function(parent, name, mode, rdev) {
- var node = {
- id: FS.nextInode++,
- name: name,
- mode: mode,
- node_ops: {},
- stream_ops: {},
- rdev: rdev,
- parent: null,
- mount: null
- };
- if (!parent) {
- parent = node; // root node sets parent to itself
- }
- node.parent = parent;
- node.mount = parent.mount;
- // compatibility
- var readMode = {{{ cDefine('S_IRUGO') }}} | {{{ cDefine('S_IXUGO') }}};
- var writeMode = {{{ cDefine('S_IWUGO') }}};
- // NOTE we must use Object.defineProperties instead of individual calls to
- // Object.defineProperty in order to make closure compiler happy
- Object.defineProperties(node, {
- read: {
- get: function() { return (node.mode & readMode) === readMode; },
- set: function(val) { val ? node.mode |= readMode : node.mode &= ~readMode; }
- },
- write: {
- get: function() { return (node.mode & writeMode) === writeMode; },
- set: function(val) { val ? node.mode |= writeMode : node.mode &= ~writeMode; }
- },
- isFolder: {
- get: function() { return FS.isDir(node.mode); },
- },
- isDevice: {
- get: function() { return FS.isChrdev(node.mode); },
- },
- });
- FS.hashAddNode(node);
- return node;
+ if (!FS.FSNode) {
+ FS.FSNode = function(parent, name, mode, rdev) {
+ this.id = FS.nextInode++;
+ this.name = name;
+ this.mode = mode;
+ this.node_ops = {};
+ this.stream_ops = {};
+ this.rdev = rdev;
+ this.parent = null;
+ this.mount = null;
+ if (!parent) {
+ parent = this; // root node sets parent to itself
+ }
+ this.parent = parent;
+ this.mount = parent.mount;
+ FS.hashAddNode(this);
+ };
+
+ // compatibility
+ var readMode = {{{ cDefine('S_IRUGO') }}} | {{{ cDefine('S_IXUGO') }}};
+ var writeMode = {{{ cDefine('S_IWUGO') }}};
+
+ FS.FSNode.prototype = {};
+
+ // NOTE we must use Object.defineProperties instead of individual calls to
+ // Object.defineProperty in order to make closure compiler happy
+ Object.defineProperties(FS.FSNode.prototype, {
+ read: {
+ get: function() { return (this.mode & readMode) === readMode; },
+ set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+ },
+ write: {
+ get: function() { return (this.mode & writeMode) === writeMode; },
+ set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+ },
+ isFolder: {
+ get: function() { return FS.isDir(this.mode); },
+ },
+ isDevice: {
+ get: function() { return FS.isChrdev(this.mode); },
+ },
+ });
+ }
+ return new FS.FSNode(parent, name, mode, rdev);
},
destroyNode: function(node) {
FS.hashRemoveNode(node);
@@ -351,24 +360,28 @@ mergeInto(LibraryManager.library, {
// object isn't directly passed in. not possible until
// SOCKFS is completed.
createStream: function(stream, fd_start, fd_end) {
+ if (!FS.FSStream) {
+ FS.FSStream = {};
+ // compatibility
+ Object.defineProperties(FS.FSStream, {
+ object: {
+ get: function() { return this.node; },
+ set: function(val) { this.node = val; }
+ },
+ isRead: {
+ get: function() { return (this.flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_WRONLY') }}}; }
+ },
+ isWrite: {
+ get: function() { return (this.flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_RDONLY') }}}; }
+ },
+ isAppend: {
+ get: function() { return (this.flags & {{{ cDefine('O_APPEND') }}}); }
+ }
+ });
+ }
+ stream.prototype = FS.FSStream;
var fd = FS.nextfd(fd_start, fd_end);
stream.fd = fd;
- // compatibility
- Object.defineProperties(stream, {
- object: {
- get: function() { return stream.node; },
- set: function(val) { stream.node = val; }
- },
- isRead: {
- get: function() { return (stream.flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_WRONLY') }}}; }
- },
- isWrite: {
- get: function() { return (stream.flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_RDONLY') }}}; }
- },
- isAppend: {
- get: function() { return (stream.flags & {{{ cDefine('O_APPEND') }}}); }
- }
- });
FS.streams[fd] = stream;
return stream;
},
@@ -771,7 +784,6 @@ mergeInto(LibraryManager.library, {
});
},
open: function(path, flags, mode, fd_start, fd_end) {
- path = PATH.normalize(path);
flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
mode = typeof mode === 'undefined' ? 0666 : mode;
if ((flags & {{{ cDefine('O_CREAT') }}})) {
@@ -780,13 +792,18 @@ mergeInto(LibraryManager.library, {
mode = 0;
}
var node;
- try {
- var lookup = FS.lookupPath(path, {
- follow: !(flags & {{{ cDefine('O_NOFOLLOW') }}})
- });
- node = lookup.node;
- } catch (e) {
- // ignore
+ if (typeof path === 'object') {
+ node = path;
+ } else {
+ path = PATH.normalize(path);
+ try {
+ var lookup = FS.lookupPath(path, {
+ follow: !(flags & {{{ cDefine('O_NOFOLLOW') }}})
+ });
+ node = lookup.node;
+ } catch (e) {
+ // ignore
+ }
}
// perhaps we need to create the node
if ((flags & {{{ cDefine('O_CREAT') }}})) {
@@ -1079,6 +1096,11 @@ mergeInto(LibraryManager.library, {
};
FS.ErrnoError.prototype = new Error();
FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+ // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+ [ERRNO_CODES.ENOENT].forEach(function(code) {
+ FS.genericErrors[code] = new FS.ErrnoError(code);
+ FS.genericErrors[code].stack = '<generic error, no stack>';
+ });
},
staticInit: function() {
FS.ensureErrnoError();
@@ -1173,7 +1195,7 @@ mergeInto(LibraryManager.library, {
return ret;
},
createFolder: function(parent, name, canRead, canWrite) {
- var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+ var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
var mode = FS.getMode(canRead, canWrite);
return FS.mkdir(path, mode);
},
@@ -1183,7 +1205,7 @@ mergeInto(LibraryManager.library, {
while (parts.length) {
var part = parts.pop();
if (!part) continue;
- var current = PATH.join(parent, part);
+ var current = PATH.join2(parent, part);
try {
FS.mkdir(current);
} catch (e) {
@@ -1194,12 +1216,12 @@ mergeInto(LibraryManager.library, {
return current;
},
createFile: function(parent, name, properties, canRead, canWrite) {
- var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+ var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
var mode = FS.getMode(canRead, canWrite);
return FS.create(path, mode);
},
createDataFile: function(parent, name, data, canRead, canWrite, canOwn) {
- var path = name ? PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+ var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
var mode = FS.getMode(canRead, canWrite);
var node = FS.create(path, mode);
if (data) {
@@ -1209,16 +1231,16 @@ mergeInto(LibraryManager.library, {
data = arr;
}
// make sure we can write to the file
- FS.chmod(path, mode | {{{ cDefine('S_IWUGO') }}});
- var stream = FS.open(path, 'w');
+ FS.chmod(node, mode | {{{ cDefine('S_IWUGO') }}});
+ var stream = FS.open(node, 'w');
FS.write(stream, data, 0, data.length, 0, canOwn);
FS.close(stream);
- FS.chmod(path, mode);
+ FS.chmod(node, mode);
}
return node;
},
createDevice: function(parent, name, input, output) {
- var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+ var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
var mode = FS.getMode(!!input, !!output);
if (!FS.createDevice.major) FS.createDevice.major = 64;
var dev = FS.makedev(FS.createDevice.major++, 0);
@@ -1272,7 +1294,7 @@ mergeInto(LibraryManager.library, {
return FS.mkdev(path, mode, dev);
},
createLink: function(parent, name, target, canRead, canWrite) {
- var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+ var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
return FS.symlink(target, path);
},
// Makes sure a file's contents are loaded. Returns whether the file has
@@ -1462,7 +1484,7 @@ mergeInto(LibraryManager.library, {
Browser.init();
// TODO we should allow people to just pass in a complete filename instead
// of parent and name being that we just join them anyways
- var fullname = name ? PATH.resolve(PATH.join(parent, name)) : parent;
+ var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
function processData(byteArray) {
function finish(byteArray) {
if (!dontCreateFile) {
diff --git a/src/library_gl.js b/src/library_gl.js
index 1ea8efc2..6ae20185 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -42,6 +42,8 @@ var LibraryGL = {
uniformTable: {}, // name => uniform ID. the uID must be identical until relinking, cannot create a new uID each call to glGetUniformLocation
+ stringCache: {},
+
packAlignment: 4, // default alignment is 4 bytes
unpackAlignment: 4, // default alignment is 4 bytes
@@ -240,7 +242,9 @@ var LibraryGL = {
sizePerPixel = 2;
break;
case 0x1406 /* GL_FLOAT */:
+#if ASSERTIONS
assert(GL.floatExt, 'Must have OES_texture_float to use float textures');
+#endif
switch (format) {
case 0x1907 /* GL_RGB */:
sizePerPixel = 3*4;
@@ -497,11 +501,14 @@ var LibraryGL = {
glGetString__sig: 'ii',
glGetString: function(name_) {
+ if (GL.stringCache[name_]) return GL.stringCache[name_];
+ var ret;
switch(name_) {
case 0x1F00 /* GL_VENDOR */:
case 0x1F01 /* GL_RENDERER */:
case 0x1F02 /* GL_VERSION */:
- return allocate(intArrayFromString(Module.ctx.getParameter(name_)), 'i8', ALLOC_NORMAL);
+ ret = allocate(intArrayFromString(Module.ctx.getParameter(name_)), 'i8', ALLOC_NORMAL);
+ break;
case 0x1F03 /* GL_EXTENSIONS */:
var exts = Module.ctx.getSupportedExtensions();
var gl_exts = [];
@@ -509,12 +516,16 @@ var LibraryGL = {
gl_exts.push(exts[i]);
gl_exts.push("GL_" + exts[i]);
}
- return allocate(intArrayFromString(gl_exts.join(' ')), 'i8', ALLOC_NORMAL); // XXX this leaks! TODO: Cache all results like this in library_gl.js to be clean and nice and avoid leaking.
+ ret = allocate(intArrayFromString(gl_exts.join(' ')), 'i8', ALLOC_NORMAL);
+ break;
case 0x8B8C /* GL_SHADING_LANGUAGE_VERSION */:
- return allocate(intArrayFromString('OpenGL ES GLSL 1.00 (WebGL)'), 'i8', ALLOC_NORMAL);
+ ret = allocate(intArrayFromString('OpenGL ES GLSL 1.00 (WebGL)'), 'i8', ALLOC_NORMAL);
+ break;
default:
throw 'Failure: Invalid glGetString value: ' + name_;
}
+ GL.stringCache[name_] = ret;
+ return ret;
},
glGetIntegerv__sig: 'vii',
@@ -680,7 +691,9 @@ var LibraryGL = {
glCompressedTexImage2D__sig: 'viiiiiiii',
glCompressedTexImage2D: function(target, level, internalFormat, width, height, border, imageSize, data) {
+#if ASSERTIONS
assert(GL.compressionExt);
+#endif
if (data) {
data = {{{ makeHEAPView('U8', 'data', 'data+imageSize') }}};
} else {
@@ -691,7 +704,9 @@ var LibraryGL = {
glCompressedTexSubImage2D__sig: 'viiiiiiiii',
glCompressedTexSubImage2D: function(target, level, xoffset, yoffset, width, height, format, imageSize, data) {
+#if ASSERTIONS
assert(GL.compressionExt);
+#endif
if (data) {
data = {{{ makeHEAPView('U8', 'data', 'data+imageSize') }}};
} else {
@@ -725,7 +740,9 @@ var LibraryGL = {
glReadPixels__sig: 'viiiiiii',
glReadPixels: function(x, y, width, height, format, type, pixels) {
+#if ASSERTIONS
assert(type == 0x1401 /* GL_UNSIGNED_BYTE */);
+#endif
var sizePerPixel;
switch (format) {
case 0x1907 /* GL_RGB */:
@@ -1357,7 +1374,9 @@ var LibraryGL = {
{{{ makeSetValue('count', '0', 'len', 'i32') }}};
for (var i = 0; i < len; ++i) {
var id = GL.shaders.indexOf(result[i]);
+#if ASSERTIONS
assert(id !== -1, 'shader not bound to local id');
+#endif
{{{ makeSetValue('shaders', 'i*4', 'id', 'i32') }}};
}
},
@@ -1774,17 +1793,17 @@ var LibraryGL = {
return;
}
case 0x8088: { // GL_TEXTURE_COORD_ARRAY_SIZE
- var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0];
+ var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0 + GLImmediate.clientActiveTexture];
{{{ makeSetValue('params', '0', 'attribute ? attribute.size : 0', 'i32') }}};
return;
}
case 0x8089: { // GL_TEXTURE_COORD_ARRAY_TYPE
- var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0];
+ var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0 + GLImmediate.clientActiveTexture];
{{{ makeSetValue('params', '0', 'attribute ? attribute.type : 0', 'i32') }}};
return;
}
case 0x808A: { // GL_TEXTURE_COORD_ARRAY_STRIDE
- var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0];
+ var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0 + GLImmediate.clientActiveTexture];
{{{ makeSetValue('params', '0', 'attribute ? attribute.stride : 0', 'i32') }}};
return;
}
@@ -1794,13 +1813,16 @@ var LibraryGL = {
var glGetString = _glGetString;
_glGetString = function(name_) {
+ if (GL.stringCache[name_]) return GL.stringCache[name_];
switch(name_) {
case 0x1F03 /* GL_EXTENSIONS */: // Add various extensions that we can support
- return allocate(intArrayFromString(Module.ctx.getSupportedExtensions().join(' ') +
+ var ret = allocate(intArrayFromString(Module.ctx.getSupportedExtensions().join(' ') +
' GL_EXT_texture_env_combine GL_ARB_texture_env_crossbar GL_ATI_texture_env_combine3 GL_NV_texture_env_combine4 GL_EXT_texture_env_dot3 GL_ARB_multitexture GL_ARB_vertex_buffer_object GL_EXT_framebuffer_object GL_ARB_vertex_program GL_ARB_fragment_program GL_ARB_shading_language_100 GL_ARB_shader_objects GL_ARB_vertex_shader GL_ARB_fragment_shader GL_ARB_texture_cube_map GL_EXT_draw_range_elements' +
(GL.compressionExt ? ' GL_ARB_texture_compression GL_EXT_texture_compression_s3tc' : '') +
(GL.anisotropicExt ? ' GL_EXT_texture_filter_anisotropic' : '')
), 'i8', ALLOC_NORMAL);
+ GL.stringCache[name_] = ret;
+ return ret;
}
return glGetString(name_);
};
@@ -2013,7 +2035,9 @@ var LibraryGL = {
glBindBuffer(target, buffer);
if (target == Module.ctx.ARRAY_BUFFER) {
if (GLEmulation.currentVao) {
+#if ASSERTIONS
assert(GLEmulation.currentVao.arrayBuffer == buffer || GLEmulation.currentVao.arrayBuffer == 0 || buffer == 0, 'TODO: support for multiple array buffers in vao');
+#endif
GLEmulation.currentVao.arrayBuffer = buffer;
}
} else if (target == Module.ctx.ELEMENT_ARRAY_BUFFER) {
@@ -2153,7 +2177,9 @@ var LibraryGL = {
glBindProgram__sig: 'vii',
glBindProgram: function(type, id) {
+#if ASSERTIONS
assert(id == 0);
+#endif
},
glGetPointerv: function(name, p) {
@@ -2164,7 +2190,7 @@ var LibraryGL = {
case 0x8090: // GL_COLOR_ARRAY_POINTER
attribute = GLImmediate.clientAttributes[GLImmediate.COLOR]; break;
case 0x8092: // GL_TEXTURE_COORD_ARRAY_POINTER
- attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0]; break;
+ attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0 + GLImmediate.clientActiveTexture]; break;
default: throw 'TODO: glGetPointerv for ' + name;
}
{{{ makeSetValue('p', '0', 'attribute ? attribute.pointer : 0', 'i32') }}};
@@ -2832,9 +2858,9 @@ var LibraryGL = {
} else if (gl) {
maxTexUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
}
-
+#if ASSERTIONS
assert(maxTexUnits > 0);
-
+#endif
s_texUnits = [];
for (var i = 0; i < maxTexUnits; i++) {
s_texUnits.push(new CTexUnit());
@@ -2893,9 +2919,10 @@ var LibraryGL = {
},
getTexUnitType: function(texUnitID) {
+#if ASSERTIONS
assert(texUnitID >= 0 &&
texUnitID < s_texUnits.length);
-
+#endif
return s_texUnits[texUnitID].getTexType();
},
@@ -3198,9 +3225,13 @@ var LibraryGL = {
if (!GL.immediate.enabledClientAttributes[texAttribName])
continue;
+#if ASSERTIONS
if (!useCurrProgram) {
- assert(GL.immediate.TexEnvJIT.getTexUnitType(i) != 0, "GL_TEXTURE" + i + " coords are supplied, but that texture unit is disabled in the fixed-function pipeline.");
+ if (GL.immediate.TexEnvJIT.getTexUnitType(i) == 0) {
+ Runtime.warnOnce("GL_TEXTURE" + i + " coords are supplied, but that texture unit is disabled in the fixed-function pipeline.");
+ }
}
+#endif
textureSizes[i] = GL.immediate.clientAttributes[texAttribName].size;
textureTypes[i] = GL.immediate.clientAttributes[texAttribName].type;
@@ -3417,7 +3448,9 @@ var LibraryGL = {
if (!GL.currArrayBuffer) {
var start = GL.immediate.firstVertex*GL.immediate.stride;
var end = GL.immediate.lastVertex*GL.immediate.stride;
+#if ASSERTIONS
assert(end <= GL.MAX_TEMP_BUFFER_SIZE, 'too much vertex data');
+#endif
arrayBuffer = GL.tempVertexBuffers[GL.tempBufferIndexLookup[end]];
// TODO: consider using the last buffer we bound, if it was larger. downside is larger buffer, but we might avoid rebinding and preparing
} else {
@@ -3586,10 +3619,10 @@ var LibraryGL = {
Module.ctx.drawElements(mode, count, type, indices);
return;
}
+#if ASSERTIONS
if (!GL.currElementArrayBuffer) {
assert(type == Module.ctx.UNSIGNED_SHORT); // We can only emulate buffers of this kind, for now
}
-#if ASSERTIONS
console.log("DrawElements doesn't actually prepareClientAttributes properly.");
#endif
GL.immediate.prepareClientAttributes(count, false);
@@ -3797,13 +3830,17 @@ var LibraryGL = {
if (!attribute) break;
attribute.offset = attribute.pointer - start;
if (attribute.offset > bytes) { // ensure we start where we should
+#if ASSERTIONS
assert((attribute.offset - bytes)%4 == 0); // XXX assuming 4-alignment
+#endif
bytes += attribute.offset - bytes;
}
bytes += attribute.size * GL.byteSizeByType[attribute.type - GL.byteSizeByTypeRoot];
if (bytes % 4 != 0) bytes += 4 - (bytes % 4); // XXX assuming 4-alignment
}
+#if ASSERTIONS
assert(beginEnd || bytes <= stride); // if not begin-end, explicit stride should make sense with total byte size
+#endif
if (bytes < stride) { // ensure the size is that of the stride
bytes = stride;
}
@@ -3830,18 +3867,21 @@ var LibraryGL = {
// Generate index data in a format suitable for GLES 2.0/WebGL
var numVertexes = 4 * this.vertexCounter / GL.immediate.stride;
+#if ASSERTIONS
assert(numVertexes % 1 == 0, "`numVertexes` must be an integer.");
-
+#endif
var emulatedElementArrayBuffer = false;
var numIndexes = 0;
if (numProvidedIndexes) {
numIndexes = numProvidedIndexes;
if (!GL.currArrayBuffer && GL.immediate.firstVertex > GL.immediate.lastVertex) {
// Figure out the first and last vertex from the index data
+#if ASSERTIONS
assert(!GL.currElementArrayBuffer); // If we are going to upload array buffer data, we need to find which range to
// upload based on the indices. If they are in a buffer on the GPU, that is very
// inconvenient! So if you do not have an array buffer, you should also not have
// an element array buffer. But best is to use both buffers!
+#endif
for (var i = 0; i < numProvidedIndexes; i++) {
var currIndex = {{{ makeGetValue('ptr', 'i*2', 'i16', null, 1) }}};
GL.immediate.firstVertex = Math.min(GL.immediate.firstVertex, currIndex);
@@ -3850,7 +3890,9 @@ var LibraryGL = {
}
if (!GL.currElementArrayBuffer) {
// If no element array buffer is bound, then indices is a literal pointer to clientside data
+#if ASSERTIONS
assert(numProvidedIndexes << 1 <= GL.MAX_TEMP_BUFFER_SIZE, 'too many immediate mode indexes (a)');
+#endif
var indexBuffer = GL.tempIndexBuffers[GL.tempBufferIndexLookup[numProvidedIndexes << 1]];
Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, indexBuffer);
Module.ctx.bufferSubData(Module.ctx.ELEMENT_ARRAY_BUFFER, 0, {{{ makeHEAPView('U16', 'ptr', 'ptr + (numProvidedIndexes << 1)') }}});
@@ -3862,11 +3904,15 @@ var LibraryGL = {
// GL.immediate.firstVertex is the first vertex we want. Quad indexes are in the pattern
// 0 1 2, 0 2 3, 4 5 6, 4 6 7, so we need to look at index firstVertex * 1.5 to see it.
// Then since indexes are 2 bytes each, that means 3
+#if ASSER