aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2012-10-22 15:18:13 -0700
committerAlon Zakai <alonzakai@gmail.com>2012-10-22 15:18:13 -0700
commitdafd2a3f15a530e1fd79fa9bf432947ab78a8501 (patch)
tree3dab09e9217bb57ad0c054b68543de77e90448c7
parente2575e4a5c49f8c644e7055074775db3fa91358a (diff)
parent11a4926fc6c2bfe43fef3c66ad30e4b2df612616 (diff)
Merge branch 'incoming'
-rwxr-xr-xemcc12
-rw-r--r--src/jsifier.js20
-rw-r--r--src/library.js102
-rw-r--r--src/library_browser.js36
-rw-r--r--src/library_egl.js421
-rw-r--r--src/library_gl.js11
-rw-r--r--src/library_glut.js31
-rw-r--r--src/library_sdl.js36
-rw-r--r--src/parseTools.js8
-rw-r--r--src/preamble.js10
-rw-r--r--src/runtime.js2
-rw-r--r--src/settings.js12
-rw-r--r--src/shell.js26
-rw-r--r--system/include/emscripten/emscripten.h16
-rw-r--r--tests/checksummer.c71
-rw-r--r--tests/cubegeom.c8
-rwxr-xr-xtests/runner.py333
-rw-r--r--tests/sdl_image_prepare_data.c69
-rw-r--r--tests/sdl_resize.c45
-rw-r--r--tests/websockets_bi_bigdata.c137
-rw-r--r--tests/websockets_bi_side_bigdata.c69
-rw-r--r--tests/websockets_bigdata.h20
-rw-r--r--tools/file_packager.py4
-rw-r--r--tools/js-optimizer.js17
-rw-r--r--tools/shared.py84
25 files changed, 1494 insertions, 106 deletions
diff --git a/emcc b/emcc
index 68f5cc35..fa00bb52 100755
--- a/emcc
+++ b/emcc
@@ -74,7 +74,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
+import os, sys, shutil, tempfile, subprocess, shlex, time
from subprocess import PIPE, STDOUT
from tools import shared
from tools.shared import Compression, execute, suffix, unsuffixed, unsuffixed_basename
@@ -815,7 +815,8 @@ try:
extra_files_to_link = []
- if not LEAVE_INPUTS_RAW and not AUTODEBUG:
+ if not LEAVE_INPUTS_RAW and not AUTODEBUG and \
+ not shared.Settings.BUILD_AS_SHARED_LIB == 2: # shared lib 2 use the library in the parent
# Check if we need to include some libraries that we compile. (We implement libc ourselves in js, but
# compile a malloc implementation and stdlibc++.)
# Note that we assume a single symbol is enough to know if we have/do not have dlmalloc etc. If you
@@ -921,10 +922,15 @@ try:
print >> sys.stderr, 'emcc: saving intermediate processing steps to %s' % shared.EMSCRIPTEN_TEMP_DIR
intermediate_counter = 0
+ intermediate_time = None
def save_intermediate(name=None, suffix='js'):
- global intermediate_counter
+ global intermediate_counter, intermediate_time
shutil.copyfile(final, os.path.join(shared.EMSCRIPTEN_TEMP_DIR, 'emcc-%d%s.%s' % (intermediate_counter, '' if name is None else '-' + name, suffix)))
intermediate_counter += 1
+ now = time.time()
+ if intermediate_time:
+ print >> sys.stderr, 'emcc: step took %.2f seconds' % (now - intermediate_time)
+ intermediate_time = now
if not LEAVE_INPUTS_RAW: save_intermediate('basebc', 'bc')
diff --git a/src/jsifier.js b/src/jsifier.js
index b76579cc..2aa65980 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -358,11 +358,21 @@ function JSify(data, functionsOnly, givenFunctions) {
item.JS = 'var ' + item.ident + ';';
// Set the actual value in a postset, since it may be a global variable. We also order by dependencies there
var value = Variables.globals[item.ident].resolvedAlias = finalizeLLVMParameter(item.value);
+ var fix = '';
+ if (BUILD_AS_SHARED_LIB == 2 && !item.private_) {
+ var target = item.ident;
+ if (isFunctionType(item.type)) {
+ target = item.value.ident; // the other side does not know this is an alias/function table index. So make it the alias target.
+ var varData = Variables.globals[target];
+ assert(!varData, 'multi-level aliasing does not work yet in shared lib 2 exports');
+ }
+ fix = '\nif (globalScope) { assert(!globalScope["' + item.ident + '"]); globalScope["' + item.ident + '"] = ' + target + ' }'
+ }
ret.push({
intertype: 'GlobalVariablePostSet',
ident: item.ident,
dependencies: set([value]),
- JS: item.ident + ' = ' + value + ';'
+ JS: item.ident + ' = ' + value + ';' + fix
});
return ret;
}
@@ -1166,7 +1176,13 @@ function JSify(data, functionsOnly, givenFunctions) {
return makeFunctionCall(item.ident, item.params, item.funcData, item.type) + (item.standalone ? ';' : '');
});
- makeFuncLineActor('unreachable', function(item) { return 'throw "Reached an unreachable!"' }); // Original .ll line: ' + item.lineNum + '";' });
+ makeFuncLineActor('unreachable', function(item) {
+ if (ASSERTIONS) {
+ return 'throw "Reached an unreachable!"';
+ } else {
+ return ';';
+ }
+ });
// Final combiner
diff --git a/src/library.js b/src/library.js
index 1bb58833..2855c33d 100644
--- a/src/library.js
+++ b/src/library.js
@@ -289,7 +289,83 @@ LibraryManager.library = {
// XHR, which is not possible in browsers except in a web worker! Use preloading,
// either --preload-file in emcc or FS.createPreloadedFile
createLazyFile: function(parent, name, url, canRead, canWrite) {
- var properties = {isDevice: false, url: url};
+
+ if (typeof XMLHttpRequest !== 'undefined') {
+ if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+ // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+ var LazyUint8Array = function(chunkSize, length) {
+ this.length = length;
+ this.chunkSize = chunkSize;
+ this.chunks = []; // Loaded chunks. Index is the chunk number
+ }
+ LazyUint8Array.prototype.get = function(idx) {
+ if (idx > this.length-1 || idx < 0) {
+ return undefined;
+ }
+ var chunkOffset = idx % chunkSize;
+ var chunkNum = Math.floor(idx / chunkSize);
+ return this.getter(chunkNum)[chunkOffset];
+ }
+ LazyUint8Array.prototype.setDataGetter = function(getter) {
+ this.getter = getter;
+ }
+
+ // Find length
+ var xhr = new XMLHttpRequest();
+ xhr.open('HEAD', url, false);
+ xhr.send(null);
+ if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+ var datalength = Number(xhr.getResponseHeader("Content-length"));
+ var header;
+ var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+#if SMALL_XHR_CHUNKS
+ var chunkSize = 1024; // Chunk size in bytes
+#else
+ var chunkSize = 1024*1024; // Chunk size in bytes
+#endif
+ if (!hasByteServing) chunkSize = datalength;
+
+ // Function to get a range from the remote URL.
+ var doXHR = (function(from, to) {
+ if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+ if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+ // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', url, false);
+ if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+ // Some hints to the browser that we want binary data.
+ if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+ if (xhr.overrideMimeType) {
+ xhr.overrideMimeType('text/plain; charset=x-user-defined');
+ }
+
+ xhr.send(null);
+ if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+ if (xhr.response !== undefined) {
+ return new Uint8Array(xhr.response || []);
+ } else {
+ return intArrayFromString(xhr.responseText || '', true);
+ }
+ });
+
+ var lazyArray = new LazyUint8Array(chunkSize, datalength);
+ lazyArray.setDataGetter(function(chunkNum) {
+ var start = chunkNum * lazyArray.chunkSize;
+ var end = (chunkNum+1) * lazyArray.chunkSize - 1; // including this byte
+ end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+ if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+ lazyArray.chunks[chunkNum] = doXHR(start, end);
+ }
+ if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+ return lazyArray.chunks[chunkNum];
+ });
+ var properties = { isDevice: false, contents: lazyArray };
+ } else {
+ var properties = { isDevice: false, url: url };
+ }
+
return FS.createFile(parent, name, properties, canRead, canWrite);
},
// Preloads a file asynchronously. You can call this before run, for example in
@@ -360,8 +436,7 @@ LibraryManager.library = {
if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
var success = true;
if (typeof XMLHttpRequest !== 'undefined') {
- // Browser.
- throw 'Cannot do synchronous binary XHRs in modern browsers. Use --embed-file or --preload-file in emcc';
+ throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
} else if (Module['read']) {
// Command-line.
try {
@@ -1631,8 +1706,14 @@ LibraryManager.library = {
}
var contents = stream.object.contents;
var size = Math.min(contents.length - offset, nbyte);
- for (var i = 0; i < size; i++) {
- {{{ makeSetValue('buf', 'i', 'contents[offset + i]', 'i8') }}}
+ if (contents.subarray || contents.slice) { // typed array or normal array
+ for (var i = 0; i < size; i++) {
+ {{{ makeSetValue('buf', 'i', 'contents[offset + i]', 'i8') }}}
+ }
+ } else {
+ for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+ {{{ makeSetValue('buf', 'i', 'contents.get(offset + i)', 'i8') }}}
+ }
}
bytesRead += size;
return bytesRead;
@@ -2417,8 +2498,8 @@ LibraryManager.library = {
while ((curr < max_ || isNaN(max_)) && next > 0) {
if (!(next in __scanString.whiteSpace) && // stop on whitespace
(type == 's' ||
- ((type === 'd' || type == 'u') && ((next >= '0'.charCodeAt(0) && next <= '9'.charCodeAt(0)) ||
- (first && next == '-'.charCodeAt(0)))) ||
+ ((type === 'd' || type == 'u' || type == 'i') && ((next >= '0'.charCodeAt(0) && next <= '9'.charCodeAt(0)) ||
+ (first && next == '-'.charCodeAt(0)))) ||
(type === 'x' && (next >= '0'.charCodeAt(0) && next <= '9'.charCodeAt(0) ||
next >= 'a'.charCodeAt(0) && next <= 'f'.charCodeAt(0) ||
next >= 'A'.charCodeAt(0) && next <= 'F'.charCodeAt(0)))) &&
@@ -2437,7 +2518,7 @@ LibraryManager.library = {
var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
argIndex += Runtime.getNativeFieldSize('void*');
switch (type) {
- case 'd': case 'u':
+ case 'd': case 'u': case 'i':
if (half) {
{{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i16') }}};
} else {
@@ -4352,6 +4433,9 @@ LibraryManager.library = {
__strtok_state: 0,
strtok__deps: ['__strtok_state', 'strtok_r'],
strtok: function(s, delim) {
+ if (!___strtok_state) {
+ ___strtok_state = _malloc(4);
+ }
return _strtok_r(s, delim, ___strtok_state);
},
@@ -6452,7 +6536,7 @@ LibraryManager.library = {
assert(info.host, 'problem translating fake ip ' + parts);
}
console.log('opening ws://' + info.host + ':' + info.port);
- info.socket = new WebSocket('ws://' + info.host + ':' + info.port, ['arraybuffer']);
+ info.socket = new WebSocket('ws://' + info.host + ':' + info.port, ['base64']);
info.socket.binaryType = 'arraybuffer';
info.buffer = new Uint8Array(Sockets.BUFFER_SIZE);
info.bufferWrite = info.bufferRead = 0;
diff --git a/src/library_browser.js b/src/library_browser.js
index fc8cb84c..99106fc3 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -347,11 +347,21 @@ mergeInto(LibraryManager.library, {
});
addRunDependency('al ' + url);
},
-
- setCanvasSize: function(width, height) {
+
+ resizeListeners: [],
+
+ updateResizeListeners: function() {
+ var canvas = Module['canvas'];
+ Browser.resizeListeners.forEach(function(listener) {
+ listener(canvas.width, canvas.height);
+ });
+ },
+
+ setCanvasSize: function(width, height, noUpdates) {
var canvas = Module['canvas'];
canvas.width = width;
canvas.height = height;
+ if (!noUpdates) Browser.updateResizeListeners();
}
},
@@ -392,6 +402,28 @@ mergeInto(LibraryManager.library, {
return 0;
},
+ emscripten_async_prepare_data: function(data, size, suffix, arg, onload, onerror) {
+ var _suffix = Pointer_stringify(suffix);
+ if (!Browser.asyncPrepareDataCounter) Browser.asyncPrepareDataCounter = 0;
+ var name = 'prepare_data_' + (Browser.asyncPrepareDataCounter++) + '.' + _suffix;
+ var cname = _malloc(name.length+1);
+ writeStringToMemory(name, cname);
+ FS.createPreloadedFile(
+ '',
+ name,
+ {{{ makeHEAPView('U8', 'data', 'data + size') }}},
+ true, true,
+ function() {
+ if (onload) FUNCTION_TABLE[onload](arg, cname);
+ },
+ function() {
+ if (onerror) FUNCTION_TABLE[onerror](arg);
+ },
+ true // don'tCreateFile - it's already there
+ );
+ return 0;
+ },
+
emscripten_async_run_script__deps: ['emscripten_run_script'],
emscripten_async_run_script: function(script, millis) {
Module['noExitRuntime'] = true;
diff --git a/src/library_egl.js b/src/library_egl.js
index 635e00a7..1c35ddf4 100644
--- a/src/library_egl.js
+++ b/src/library_egl.js
@@ -1,26 +1,423 @@
-
+/*
+ The EGL implementation supports only one EGLNativeDisplayType, the EGL_DEFAULT_DISPLAY.
+ This native display type returns the only supported EGLDisplay handle with the magic value 62000.
+ There is only a single EGLConfig configuration supported, that has the magic value 62002.
+ The implementation only allows a single EGLContext to be created, that has the magic value of 62004. (multiple creations silently return this same context)
+ The implementation only creates a single EGLSurface, a handle with the magic value of 62006. (multiple creations silently return the same surface)
+*/
+
var LibraryEGL = {
- eglGetDisplay: function(x_display) { return 3 },
- eglInitialize: function(display, majorVersion, minorVersion) { return 1 },
- eglGetConfigs: function(display, hmm1, hmm2, numConfigs) { return 1 },
- eglChooseConfig: function(display, attribList, config, hmm, numConfigs) { return 1 },
- eglCreateWindowSurface: function(display, config, hWnd, hmm) { return 4 },
+ $EGL: {
+ // This variable tracks the success status of the most recently invoked EGL function call.
+ eglErrorCode: 0x3000 /* EGL_SUCCESS */,
+
+ setErrorCode: function(code) {
+ EGL.eglErrorCode = code;
+ },
+
+ chooseConfig: function(display, attribList, config, config_size, numConfigs) {
+ if (display != 62000 /* Magic ID for Emscripten 'default display' */) {
+ EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */);
+ return 0;
+ }
+ // TODO: read attribList.
+ if ((!config || !config_size) && !numConfigs) {
+ EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */);
+ return 0;
+ }
+ if (numConfigs) {
+ {{{ makeSetValue('numConfigs', '0', '1', 'i32') }}}; // Total number of supported configs: 1.
+ }
+ if (config && config_size > 0) {
+ {{{ makeSetValue('config', '0', '62002' /* Magic ID for the only EGLConfig supported by Emscripten */, 'i32') }}};
+ }
+
+ EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
+ return 1;
+ },
+ },
+
+ // EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id);
+ eglGetDisplay: function(nativeDisplayType) {
+ EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
+ // Note: As a 'conformant' implementation of EGL, we would prefer to init here only if the user
+ // calls this function with EGL_DEFAULT_DISPLAY. Other display IDs would be preferred to be unsupported
+ // and EGL_NO_DISPLAY returned. Uncomment the following code lines to do this.
+ // Instead, an alternative route has been preferred, namely that the Emscripten EGL implementation
+ // "emulates" X11, and eglGetDisplay is expected to accept/receive a pointer to an X11 Display object.
+ // Therefore, be lax and allow anything to be passed in, and return the magic handle to our default EGLDisplay object.
+
+// if (nativeDisplayType == 0 /* EGL_DEFAULT_DISPLAY */) {
+ return 62000; // Magic ID for Emscripten 'default display'
+// }
+// else
+// return 0; // EGL_NO_DISPLAY
+ },
+
+ // EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor);
+ eglInitialize: function(display, majorVersion, minorVersion) {
+ if (display == 62000 /* Magic ID for Emscripten 'default display' */) {
+ if (majorVersion) {
+ {{{ makeSetValue('majorVersion', '0', '1', 'i32') }}}; // Advertise EGL Major version: '1'
+ }
+ if (minorVersion) {
+ {{{ makeSetValue('minorVersion', '0', '4', 'i32') }}}; // Advertise EGL Minor version: '4'
+ }
+ EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
+ return 1;
+ }
+ else {
+ EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */);
+ return 0;
+ }
+ },
+
+ // EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+ eglGetConfigs: function(display, configs, config_size, numConfigs) {
+ return EGL.chooseConfig(display, 0, configs, config_size, numConfigs);
+ },
+
+ // EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+ eglChooseConfig: function(display, attrib_list, configs, config_size, numConfigs) {
+ return EGL.chooseConfig(display, attrib_list, configs, config_size, numConfigs);
+ },
+
+ // EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
+ eglGetConfigAttrib: function(display, config, attribute, value) {
+ if (display != 62000 /* Magic ID for Emscripten 'default display' */) {
+ EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */);
+ return 0;
+ }
+ if (config != 62002 /* Magic ID for the only EGLConfig supported by Emscripten */) {
+ EGL.setErrorCode(0x3005 /* EGL_BAD_CONFIG */);
+ return 0;
+ }
+ if (!value) {
+ EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */);
+ return 0;
+ }
+ EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
+ switch(attribute) {
+ case 0x3020: // EGL_BUFFER_SIZE
+ {{{ makeSetValue('value', '0', '32' /* 8 bits for each A,R,G,B. */, 'i32') }}};
+ return 1;
+ case 0x3021: // EGL_ALPHA_SIZE
+ {{{ makeSetValue('value', '0', '8' /* 8 bits for alpha channel. */, 'i32') }}};
+ return 1;
+ case 0x3022: // EGL_BLUE_SIZE
+ {{{ makeSetValue('value', '0', '8' /* 8 bits for blue channel. */, 'i32') }}};
+ return 1;
+ case 0x3023: // EGL_GREEN_SIZE
+ {{{ makeSetValue('value', '0', '8' /* 8 bits for green channel. */, 'i32') }}};
+ return 1;
+ case 0x3024: // EGL_RED_SIZE
+ {{{ makeSetValue('value', '0', '8' /* 8 bits for red channel. */, 'i32') }}};
+ return 1;
+ case 0x3025: // EGL_DEPTH_SIZE
+ {{{ makeSetValue('value', '0', '24' /* 24 bits for depth buffer. TODO: This is hardcoded, add support for this! */, 'i32') }}};
+ return 1;
+ case 0x3026: // EGL_STENCIL_SIZE
+ {{{ makeSetValue('value', '0', '8' /* 8 bits for stencil buffer. TODO: This is hardcoded, add support for this! */, 'i32') }}};
+ return 1;
+ case 0x3027: // EGL_CONFIG_CAVEAT
+ // We can return here one of EGL_NONE (0x3038), EGL_SLOW_CONFIG (0x3050) or EGL_NON_CONFORMANT_CONFIG (0x3051).
+ {{{ makeSetValue('value', '0', '0x3038' /* EGL_NONE */, 'i32') }}};
+ return 1;
+ case 0x3028: // EGL_CONFIG_ID
+ {{{ makeSetValue('value', '0', '62002' /* Magic ID for the only EGLConfig supported by Emscripten */, 'i32') }}};
+ return 1;
+ case 0x3029: // EGL_LEVEL
+ {{{ makeSetValue('value', '0', '0' /* Z order/depth layer for this level. Not applicable for Emscripten. */, 'i32') }}};
+ return 1;
+ case 0x302A: // EGL_MAX_PBUFFER_HEIGHT
+ {{{ makeSetValue('value', '0', '4096', 'i32') }}};
+ return 1;
+ case 0x302B: // EGL_MAX_PBUFFER_PIXELS
+ {{{ makeSetValue('value', '0', '16777216' /* 4096 * 4096 */, 'i32') }}};
+ return 1;
+ case 0x302C: // EGL_MAX_PBUFFER_WIDTH
+ {{{ makeSetValue('value', '0', '4096', 'i32') }}};
+ return 1;
+ case 0x302D: // EGL_NATIVE_RENDERABLE
+ {{{ makeSetValue('value', '0', '0' /* This config does not allow co-rendering with other 'native' rendering APIs. */, 'i32') }}};
+ return 1;
+ case 0x302E: // EGL_NATIVE_VISUAL_ID
+ {{{ makeSetValue('value', '0', '0' /* N/A for Emscripten. */, 'i32') }}};
+ return 1;
+ case 0x302F: // EGL_NATIVE_VISUAL_TYPE
+ {{{ makeSetValue('value', '0', '0x3038' /* EGL_NONE */, 'i32') }}};
+ return 1;
+ case 0x3031: // EGL_SAMPLES
+ {{{ makeSetValue('value', '0', '0' /* No multisampling. */, 'i32') }}};
+ return 1;
+ case 0x3032: // EGL_SAMPLE_BUFFERS
+ {{{ makeSetValue('value', '0', '0' /* No multisampling. */, 'i32') }}};
+ return 1;
+ case 0x3033: // EGL_SURFACE_TYPE
+ {{{ makeSetValue('value', '0', '0x0004' /* EGL_WINDOW_BIT */, 'i32') }}};
+ return 1;
+ case 0x3034: // EGL_TRANSPARENT_TYPE
+ // If this returns EGL_TRANSPARENT_RGB (0x3052), transparency is used through color-keying. No such thing applies to Emscripten canvas.
+ {{{ makeSetValue('value', '0', '0x3038' /* EGL_NONE */, 'i32') }}};
+ return 1;
+ case 0x3035: // EGL_TRANSPARENT_BLUE_VALUE
+ case 0x3036: // EGL_TRANSPARENT_GREEN_VALUE
+ case 0x3037: // EGL_TRANSPARENT_RED_VALUE
+ // "If EGL_TRANSPARENT_TYPE is EGL_NONE, then the values for EGL_TRANSPARENT_RED_VALUE, EGL_TRANSPARENT_GREEN_VALUE, and EGL_TRANSPARENT_BLUE_VALUE are undefined."
+ {{{ makeSetValue('value', '0', '-1' /* Report a "does not apply" value. */, 'i32') }}};
+ return 1;
+ case 0x3039: // EGL_BIND_TO_TEXTURE_RGB
+ case 0x303A: // EGL_BIND_TO_TEXTURE_RGBA
+ {{{ makeSetValue('value', '0', '0' /* Only pbuffers would be bindable, but these are not supported. */, 'i32') }}};
+ return 1;
+ case 0x303B: // EGL_MIN_SWAP_INTERVAL
+ case 0x303C: // EGL_MAX_SWAP_INTERVAL
+ {{{ makeSetValue('value', '0', '1' /* TODO: Currently this is not strictly true, since user can specify custom presentation interval in JS requestAnimationFrame/emscripten_set_main_loop. */, 'i32') }}};
+ return 1;
+ case 0x303D: // EGL_LUMINANCE_SIZE
+ case 0x303E: // EGL_ALPHA_MASK_SIZE
+ {{{ makeSetValue('value', '0', '0' /* N/A in this config. */, 'i32') }}};
+ return 1;
+ case 0x303F: // EGL_COLOR_BUFFER_TYPE
+ // EGL has two types of buffers: EGL_RGB_BUFFER and EGL_LUMINANCE_BUFFER.
+ {{{ makeSetValue('value', '0', '0x308E' /* EGL_RGB_BUFFER */, 'i32') }}};
+ return 1;
+ case 0x3040: // EGL_RENDERABLE_TYPE
+ // A bit combination of EGL_OPENGL_ES_BIT,EGL_OPENVG_BIT,EGL_OPENGL_ES2_BIT and EGL_OPENGL_BIT.
+ {{{ makeSetValue('value', '0', '0x0004' /* EGL_OPENGL_ES2_BIT */, 'i32') }}};
+ return 1;
+ case 0x3042: // EGL_CONFORMANT
+ // "EGL_CONFORMANT is a mask indicating if a client API context created with respect to the corresponding EGLConfig will pass the required conformance tests for that API."
+ {{{ makeSetValue('value', '0', '0' /* EGL_OPENGL_ES2_BIT */, 'i32') }}};
+ return 1;
+ default:
+ EGL.setErrorCode(0x3004 /* EGL_BAD_ATTRIBUTE */);
+ return 0;
+ }
+ },
+
+ // EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
+ eglCreateWindowSurface: function(display, config, win, attrib_list) {
+ if (display != 62000 /* Magic ID for Emscripten 'default display' */) {
+ EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */);
+ return 0;
+ }
+ if (config != 62002 /* Magic ID for the only EGLConfig supported by Emscripten */) {
+ EGL.setErrorCode(0x3005 /* EGL_BAD_CONFIG */);
+ return 0;
+ }
+ // TODO: Examine attrib_list! Parameters that can be present there are:
+ // - EGL_RENDER_BUFFER (must be EGL_BACK_BUFFER)
+ // - EGL_VG_COLORSPACE (can't be set)
+ // - EGL_VG_ALPHA_FORMAT (can't be set)
+ EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
+ return 62006; /* Magic ID for Emscripten 'default surface' */
+ },
eglCreateContext__deps: ['glutCreateWindow', '$GL'],
+
+ // EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
eglCreateContext: function(display, config, hmm, contextAttribs) {
+ if (display != 62000 /* Magic ID for Emscripten 'default display' */) {
+ EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */);
+ return 0;
+ }
+
_glutCreateWindow();
- return 1;
+ EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
+ return 62004; // Magic ID for Emscripten EGLContext
},
// EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);
- eglQuerySurface: function(display, surface, attribute, value) { return 0 },
+ eglQuerySurface: function(display, surface, attribute, value) {
+ if (display != 62000 /* Magic ID for Emscripten 'default display' */) {
+ EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */);
+ return 0;
+ }
+ if (surface != 62006 /* Magic ID for Emscripten 'default surface' */) {
+ EGL.setErrorCode(0x300D /* EGL_BAD_SURFACE */);
+ return 0;
+ }
+ if (!value) {
+ EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */);
+ return 0;
+ }
+ EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
+ switch(attribute) {
+ case 0x3028: // EGL_CONFIG_ID
+ {{{ makeSetValue('value', '0', '62002' /* A magic value for the only EGLConfig configuration ID supported by Emscripten. */, 'i32') }}};
+ return 1;
+ case 0x3058: // EGL_LARGEST_PBUFFER
+ // Odd EGL API: If surface is not a pbuffer surface, 'value' should not be written to. It's not specified as an error, so true should(?) be returned.
+ // Existing Android implementation seems to do so at least.
+ return 1;
+ case 0x3057: // EGL_WIDTH
+ // TODO
+ return 1;
+ case 0x3056: // EGL_HEIGHT
+ // TODO
+ return 1;
+ case 0x3090: // EGL_HORIZONTAL_RESOLUTION
+ {{{ makeSetValue('value', '0', '-1' /* EGL_UNKNOWN */, 'i32') }}};
+ return 1;
+ case 0x3091: // EGL_VERTICAL_RESOLUTION
+ {{{ makeSetValue('value', '0', '-1' /* EGL_UNKNOWN */, 'i32') }}};
+ return 1;
+ case 0x3092: // EGL_PIXEL_ASPECT_RATIO
+ {{{ makeSetValue('value', '0', '-1' /* EGL_UNKNOWN */, 'i32') }}};
+ return 1;
+ case 0x3086: // EGL_RENDER_BUFFER
+ // The main surface is bound to the visible canvas window - it's always backbuffered.
+ // Alternative to EGL_BACK_BUFFER would be EGL_SINGLE_BUFFER.
+ {{{ makeSetValue('value', '0', '0x3084' /* EGL_BACK_BUFFER */, 'i32') }}};
+ return 1;
+ case 0x3099: // EGL_MULTISAMPLE_RESOLVE
+ {{{ makeSetValue('value', '0', '0x309A' /* EGL_MULTISAMPLE_RESOLVE_DEFAULT */, 'i32') }}};
+ return 1;
+ case 0x3093: // EGL_SWAP_BEHAVIOR
+ // The two possibilities are EGL_BUFFER_PRESERVED and EGL_BUFFER_DESTROYED. Slightly unsure which is the
+ // case for browser environment, but advertise the 'weaker' behavior to be sure.
+ {{{ makeSetValue('value', '0', '0x3095' /* EGL_BUFFER_DESTROYED */, 'i32') }}};
+ return 1;
+ case 0x3080: // EGL_TEXTURE_FORMAT
+ case 0x3081: // EGL_TEXTURE_TARGET
+ case 0x3082: // EGL_MIPMAP_TEXTURE
+ case 0x3083: // EGL_MIPMAP_LEVEL
+ // This is a window surface, not a pbuffer surface. Spec:
+ // "Querying EGL_TEXTURE_FORMAT, EGL_TEXTURE_TARGET, EGL_MIPMAP_TEXTURE, or EGL_MIPMAP_LEVEL for a non-pbuffer surface is not an error, but value is not modified."
+ // So pass-through.
+ return 1;
+ default:
+ EGL.setErrorCode(0x3004 /* EGL_BAD_ATTRIBUTE */);
+ return 0;
+ }
+ },
+ // EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value);
+ eglQueryContext: function(display, context, attribute, value) {
+ if (display != 62000 /* Magic ID for Emscripten 'default display' */) {
+ EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */);
+ return 0;
+ }
+ //\todo An EGL_NOT_INITIALIZED error is generated if EGL is not initialized for dpy.
+ if (context != 62004 /* Magic ID for Emscripten EGLContext */) {
+ EGL.setErrorCode(0x3006 /* EGL_BAD_CONTEXT */);
+ return 0;
+ }
+ if (!value) {
+ EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */);
+ return 0;
+ }
+
+ EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
+ switch(attribute) {
+ case 0x3028: // EGL_CONFIG_ID
+ {{{ makeSetValue('value', '0', '62002' /* A magic value for the only EGLConfig configuration ID supported by Emscripten. */, 'i32') }}};
+ return 1;
+ case 0x3097: // EGL_CONTEXT_CLIENT_TYPE
+ {{{ makeSetValue('value', '0', '0x30A0' /* EGL_OPENGL_ES_API */, 'i32') }}};
+ return 1;
+ case 0x3098: // EGL_CONTEXT_CLIENT_VERSION
+ {{{ makeSetValue('value', '0', '2' /* GLES2 context */, 'i32') }}}; // We always report the context to be a GLES2 context (and not a GLES1 context)
+ return 1;
+ case 0x3086: // EGL_RENDER_BUFFER
+ // The context is bound to the visible canvas window - it's always backbuffered.
+ // Alternative to EGL_BACK_BUFFER would be EGL_SINGLE_BUFFER.
+ {{{ makeSetValue('value', '0', '0x3084' /* EGL_BACK_BUFFER */, 'i32') }}};
+ return 1;
+ default:
+ EGL.setErrorCode(0x3004 /* EGL_BAD_ATTRIBUTE */);
+ return 0;
+ }
+ },
+
// EGLAPI EGLint EGLAPIENTRY eglGetError(void);
- eglGetError: function() { return 0x3000 /* EGL_SUCCESS */ },
+ eglGetError: function() {
+ return EGL.eglErrorCode;
+ },
- eglMakeCurrent: function(display, surface, surface_, context) { return 1 },
- eglSwapBuffers: function() {},
+ eglQueryString: function(display, name) {
+ if (display != 62000 /* Magic ID for Emscripten 'default display' */) {
+ EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */);
+ return 0;
+ }
+ //\todo An EGL_NOT_INITIALIZED error is generated if EGL is not initialized for dpy.
+ EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
+ 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);
+ default:
+ EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */);
+ return 0;
+ }
+ },
+
+ // EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api);
+ eglBindAPI: function(api) {
+ if (api == 0x30A0 /* EGL_OPENGL_ES_API */) {
+ EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
+ return 1;
+ } else { // if (api == 0x30A1 /* EGL_OPENVG_API */ || api == 0x30A2 /* EGL_OPENGL_API */) {
+ EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */);
+ return 0;
+ }
+ },
+
+ // EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void);
+ eglQueryAPI: function() {
+ EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
+ return 0x30A0; // EGL_OPENGL_ES_API
+ },
+
+ // EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void);
+ eglWaitClient: function() {
+ EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
+ return 1;
+ },
+
+ // EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine);
+ eglWaitNative: function(nativeEngineId) {
+ EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
+ return 1;
+ },
+
+ // EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval);
+ eglSwapInterval: function(display, interval) {
+ if (display != 62000 /* Magic ID for Emscripten 'default display' */) {
+ EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */);