diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 2 | ||||
-rw-r--r-- | src/intertyper.js | 24 | ||||
-rw-r--r-- | src/jsifier.js | 24 | ||||
-rw-r--r-- | src/library.js | 24 | ||||
-rw-r--r-- | src/library_egl.js | 14 | ||||
-rw-r--r-- | src/library_fs.js | 172 | ||||
-rw-r--r-- | src/library_gl.js | 66 | ||||
-rw-r--r-- | src/library_glfw.js | 4 | ||||
-rw-r--r-- | src/library_glut.js | 4 | ||||
-rw-r--r-- | src/library_idbfs.js | 2 | ||||
-rw-r--r-- | src/library_memfs.js | 100 | ||||
-rw-r--r-- | src/library_nodefs.js | 12 | ||||
-rw-r--r-- | src/library_path.js | 22 | ||||
-rw-r--r-- | src/library_sdl.js | 56 | ||||
-rw-r--r-- | src/parseTools.js | 96 | ||||
-rw-r--r-- | src/preamble.js | 10 | ||||
-rw-r--r-- | src/runtime.js | 15 | ||||
-rw-r--r-- | src/shell.html | 7 |
18 files changed, 392 insertions, 262 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 96db6966..fceeb38d 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -672,15 +672,17 @@ function intertyper(lines, sidePass, baseLineNums) { assert((item.tokens[5].text.match(/=/g) || []).length <= 1, 'we only support at most 1 exported variable from inline js: ' + item.ident); var i = 0; var params = [], args = []; - splitTokenList(tokensLeft[3].tokens).map(function(element) { - var ident = toNiceIdent(element[1].text); - var type = element[0].text; - params.push('$' + (i++)); - args.push(ident); - }); + if (tokensLeft[3].tokens) { + splitTokenList(tokensLeft[3].tokens).map(function(element) { + var ident = toNiceIdent(element[1].text); + var type = element[0].text; + params.push('$' + (i++)); + args.push(ident); + }); + } 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() @@ -703,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) { @@ -719,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 b36e11ed..0da48a8c 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -948,11 +948,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: @@ -1323,11 +1324,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) { @@ -1489,7 +1491,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..76501111 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') }}}; } }, @@ -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) { @@ -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 ASSERTIONS assert(GL.immediate.firstVertex % 4 == 0); +#endif ptr = GL.immediate.firstVertex*3; var numQuads = numVertexes / 4; numIndexes = numQuads * 6; // 0 1 2, 0 2 3 pattern +#if ASSERTIONS assert(ptr + (numIndexes << 1) <= GL.MAX_TEMP_BUFFER_SIZE, 'too many immediate mode indexes (b)'); +#endif Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, GL.tempQuadIndexBuffer); emulatedElementArrayBuffer = true; } diff --git a/src/library_glfw.js b/src/library_glfw.js index b0519e39..647d4bb6 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -355,7 +355,9 @@ var LibraryGLFW = { } var contextAttributes = { - antialias: (GLFW.params[0x00020 |