diff options
39 files changed, 833 insertions, 327 deletions
diff --git a/emscripten.py b/emscripten.py index 1b1284c7..a156ca73 100755 --- a/emscripten.py +++ b/emscripten.py @@ -190,6 +190,11 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, open(forwarded_file, 'w').write(forwarded_data) if DEBUG: print >> sys.stderr, ' emscript: phase 1 took %s seconds' % (time.time() - t) + indexed_functions = set() + forwarded_json = json.loads(forwarded_data) + for key in forwarded_json['Functions']['indexedFunctions'].iterkeys(): + indexed_functions.add(key) + # Phase 2 - func cores = int(os.environ.get('EMCC_CORES') or multiprocessing.cpu_count()) @@ -203,8 +208,6 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, chunk_size = MAX_CHUNK_SIZE # if 1 core, just use the max chunk size if DEBUG: t = time.time() - forwarded_json = json.loads(forwarded_data) - indexed_functions = set() if settings.get('ASM_JS'): settings['EXPORTED_FUNCTIONS'] = forwarded_json['EXPORTED_FUNCTIONS'] save_settings() diff --git a/src/compiler.js b/src/compiler.js index 365ff32f..2390f4c9 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -203,6 +203,8 @@ if (phase == 'pre') { } } +if (VERBOSE) printErr('VERBOSE is on, this generates a lot of output and can slow down compilation'); + // Load compiler code load('framework.js'); diff --git a/src/jsifier.js b/src/jsifier.js index c92526d2..8ed19194 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -16,6 +16,8 @@ var SETJMP_LABEL = -1; var INDENTATION = ' '; +var functionStubSigs = {}; + // JSifier function JSify(data, functionsOnly, givenFunctions) { var mainPass = !functionsOnly; @@ -407,6 +409,11 @@ function JSify(data, functionsOnly, givenFunctions) { // functionStub substrate.addActor('FunctionStub', { processItem: function(item) { + // note the signature + if (item.returnType && item.params) { + functionStubSigs[item.ident] = Functions.getSignature(item.returnType.text, item.params.map(function(arg) { return arg.type }), false); + } + function addFromLibrary(ident) { if (ident in addedLibraryItems) return ''; addedLibraryItems[ident] = true; @@ -1537,7 +1544,7 @@ function JSify(data, functionsOnly, givenFunctions) { // This is a call through an invoke_*, either a forced one, or a setjmp-required one // note: no need to update argsTypes at this point if (byPointerForced) Functions.unimplementedFunctions[callIdent] = sig; - args.unshift(byPointerForced ? Functions.getIndex(callIdent, undefined, sig) : asmCoercion(callIdent, 'i32')); + args.unshift(byPointerForced ? Functions.getIndex(callIdent, sig) : asmCoercion(callIdent, 'i32')); callIdent = 'invoke_' + sig; } } else if (SAFE_DYNCALLS) { diff --git a/src/library.js b/src/library.js index ee49ae1f..9e78db13 100644 --- a/src/library.js +++ b/src/library.js @@ -7235,7 +7235,7 @@ LibraryManager.library = { socket__deps: ['$FS', '$Sockets'], socket: function(family, type, protocol) { var INCOMING_QUEUE_LENGTH = 64; - var stream = FS.createStream({ + var info = FS.createStream({ addr: null, port: null, inQueue: new CircularBuffer(INCOMING_QUEUE_LENGTH), @@ -7244,7 +7244,7 @@ LibraryManager.library = { socket: true, stream_ops: {} }); - assert(stream.fd < 64); // select() assumes socket fd values are in 0..63 + assert(info.fd < 64); // select() assumes socket fd values are in 0..63 var stream = type == {{{ cDefine('SOCK_STREAM') }}}; if (protocol) { assert(stream == (protocol == {{{ cDefine('IPPROTO_TCP') }}})); // if stream, must be tcp @@ -7357,8 +7357,7 @@ LibraryManager.library = { } }; }; - - return stream.fd; + return info.fd; }, mkport__deps: ['$Sockets'], @@ -7452,6 +7451,7 @@ LibraryManager.library = { buffer.set(data, info.header.byteLength); connection.send('unreliable', buffer.buffer); + return ret; }, recvmsg__deps: ['$FS', '$Sockets', 'bind', '__setErrNo', '$ERRNO_CODES', 'htons'], diff --git a/src/library_browser.js b/src/library_browser.js index f65791e4..511e158e 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -6,6 +6,7 @@ mergeInto(LibraryManager.library, { $Browser__deps: ['$PATH'], $Browser__postset: 'Module["requestFullScreen"] = function(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };\n' + // exports 'Module["requestAnimationFrame"] = function(func) { Browser.requestAnimationFrame(func) };\n' + + 'Module["setCanvasSize"] = function(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };\n' + 'Module["pauseMainLoop"] = function() { Browser.mainLoop.pause() };\n' + 'Module["resumeMainLoop"] = function() { Browser.mainLoop.resume() };\n' + 'Module["getUserMedia"] = function() { Browser.getUserMedia() }', diff --git a/src/library_egl.js b/src/library_egl.js index 0e96e92f..ff912ed2 100644 --- a/src/library_egl.js +++ b/src/library_egl.js @@ -489,6 +489,11 @@ var LibraryEGL = { eglSwapBuffers: function() { EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); }, + + eglGetProcAddress__deps: ['emscripten_GetProcAddress'], + eglGetProcAddress: function(name_) { + return _emscripten_GetProcAddress(Pointer_stringify(name_)); + }, }; autoAddDeps(LibraryEGL, '$EGL'); diff --git a/src/library_fs.js b/src/library_fs.js index 8ea6b06f..9d1f0cfd 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -18,7 +18,7 @@ mergeInto(LibraryManager.library, { devices: [null], streams: [null], nextInode: 1, - name_table: new Array(4096), + name_table: null, currentPath: '/', initialized: false, // Whether we are currently ignoring permissions. Useful when preparing the @@ -27,16 +27,21 @@ mergeInto(LibraryManager.library, { // to modify the filesystem freely before run() is called. ignorePermissions: true, - ErrnoError: function(errno) { - this.errno = errno; - for (var key in ERRNO_CODES) { - if (ERRNO_CODES[key] === errno) { - this.code = key; - break; + ErrnoError: (function() { + function ErrnoError(errno) { + this.errno = errno; + for (var key in ERRNO_CODES) { + if (ERRNO_CODES[key] === errno) { + this.code = key; + break; + } } - } - this.message = ERRNO_MESSAGES[errno] + ' : ' + new Error().stack; - }, + this.message = ERRNO_MESSAGES[errno]; + }; + ErrnoError.prototype = new Error(); + ErrnoError.prototype.constructor = ErrnoError; + return ErrnoError; + }()), handleFSError: function(e) { if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + new Error().stack; @@ -863,6 +868,8 @@ mergeInto(LibraryManager.library, { assert(stderr.fd === 3, 'invalid handle for stderr (' + stderr.fd + ')'); }, staticInit: function() { + FS.name_table = new Array(4096); + FS.root = FS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0); FS.mount(MEMFS, {}, '/'); diff --git a/src/library_gl.js b/src/library_gl.js index 8c724245..c134ad97 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -1285,10 +1285,11 @@ var LibraryGL = { return Module.ctx.isFramebuffer(fb); }, -#if DISABLE_GL_EMULATION == 0 +#if LEGACY_GL_EMULATION // GL emulation: provides misc. functionality not present in OpenGL ES 2.0 or WebGL + $GLEmulation__deps: ['$GLImmediateSetup', 'glEnable', 'glDisable', 'glIsEnabled', 'glGetBooleanv', 'glGetIntegerv', 'glGetString', 'glCreateShader', 'glShaderSource', 'glCompileShader', 'glAttachShader', 'glDetachShader', 'glUseProgram', 'glDeleteProgram', 'glBindAttribLocation', 'glLinkProgram', 'glBindBuffer', 'glGetFloatv', 'glHint', 'glEnableVertexAttribArray', 'glDisableVertexAttribArray', 'glVertexAttribPointer', 'glActiveTexture'], $GLEmulation__postset: 'GLEmulation.init();', $GLEmulation: { // Fog support. Partial, we assume shaders are used that implement fog. We just pass them uniforms @@ -1323,7 +1324,7 @@ var LibraryGL = { GLEmulation.fogColor = new Float32Array(4); // Add some emulation workarounds - Module.printErr('WARNING: using emscripten GL emulation. This is a collection of limited workarounds, do not expect it to work. (If you do not want this, build with -s DISABLE_GL_EMULATION=1)'); + Module.printErr('WARNING: using emscripten GL emulation. This is a collection of limited workarounds, do not expect it to work.'); #if GL_UNSAFE_OPTS == 0 Module.printErr('WARNING: using emscripten GL emulation unsafe opts. If weirdness happens, try -s GL_UNSAFE_OPTS=0'); #endif @@ -1618,17 +1619,15 @@ var LibraryGL = { var glCompileShader = _glCompileShader; _glCompileShader = function(shader) { Module.ctx.compileShader(GL.shaders[shader]); +#if GL_DEBUG if (!Module.ctx.getShaderParameter(GL.shaders[shader], Module.ctx.COMPILE_STATUS)) { Module.printErr('Failed to compile shader: ' + Module.ctx.getShaderInfoLog(GL.shaders[shader])); Module.printErr('Info: ' + JSON.stringify(GL.shaderInfos[shader])); -#if GL_DEBUG Module.printErr('Original source: ' + GL.shaderOriginalSources[shader]); Module.printErr('Source: ' + GL.shaderSources[shader]); throw 'Shader compilation halt'; -#else - Module.printErr('Enable GL_DEBUG to see shader source'); -#endif } +#endif }; GL.programShaders = {}; @@ -1775,170 +1774,6 @@ var LibraryGL = { } return attrib; }, - - getProcAddress: function(name) { - name = name.replace('EXT', '').replace('ARB', ''); - // Do the translation carefully because of closure - var ret = 0; - switch (name) { - case 'glCreateShaderObject': case 'glCreateShader': ret = {{{ Functions.getIndex('_glCreateShader', true) }}}; break; - case 'glCreateProgramObject': case 'glCreateProgram': ret = {{{ Functions.getIndex('_glCreateProgram', true) }}}; break; - case 'glAttachObject': case 'glAttachShader': ret = {{{ Functions.getIndex('_glAttachShader', true) }}}; break; - case 'glUseProgramObject': case 'glUseProgram': ret = {{{ Functions.getIndex('_glUseProgram', true) }}}; break; - case 'glDetachObject': case 'glDetachShader': ret = {{{ Functions.getIndex('_glDetachShader', true) }}}; break; - case 'glDeleteObject': ret = {{{ Functions.getIndex('_glDeleteObject', true) }}}; break; - case 'glGetObjectParameteriv': ret = {{{ Functions.getIndex('_glGetObjectParameteriv', true) }}}; break; - case 'glGetInfoLog': ret = {{{ Functions.getIndex('_glGetInfoLog', true) }}}; break; - case 'glBindProgram': ret = {{{ Functions.getIndex('_glBindProgram', true) }}}; break; - case 'glDrawRangeElements': ret = {{{ Functions.getIndex('_glDrawRangeElements', true) }}}; break; - case 'glShaderSource': ret = {{{ Functions.getIndex('_glShaderSource', true) }}}; break; - case 'glCompileShader': ret = {{{ Functions.getIndex('_glCompileShader', true) }}}; break; - case 'glLinkProgram': ret = {{{ Functions.getIndex('_glLinkProgram', true) }}}; break; - case 'glGetUniformLocation': ret = {{{ Functions.getIndex('_glGetUniformLocation', true) }}}; break; - case 'glUniform1f': ret = {{{ Functions.getIndex('_glUniform1f', true) }}}; break; - case 'glUniform2f': ret = {{{ Functions.getIndex('_glUniform2f', true) }}}; break; - case 'glUniform3f': ret = {{{ Functions.getIndex('_glUniform3f', true) }}}; break; - case 'glUniform4f': ret = {{{ Functions.getIndex('_glUniform4f', true) }}}; break; - case 'glUniform1fv': ret = {{{ Functions.getIndex('_glUniform1fv', true) }}}; break; - case 'glUniform2fv': ret = {{{ Functions.getIndex('_glUniform2fv', true) }}}; break; - case 'glUniform3fv': ret = {{{ Functions.getIndex('_glUniform3fv', true) }}}; break; - case 'glUniform4fv': ret = {{{ Functions.getIndex('_glUniform4fv', true) }}}; break; - case 'glUniform1i': ret = {{{ Functions.getIndex('_glUniform1i', true) }}}; break; - case 'glUniform2i': ret = {{{ Functions.getIndex('_glUniform2i', true) }}}; break; - case 'glUniform3i': ret = {{{ Functions.getIndex('_glUniform3i', true) }}}; break; - case 'glUniform4i': ret = {{{ Functions.getIndex('_glUniform4i', true) }}}; break; - case 'glUniform1iv': ret = {{{ Functions.getIndex('_glUniform1iv', true) }}}; break; - case 'glUniform2iv': ret = {{{ Functions.getIndex('_glUniform2iv', true) }}}; break; - case 'glUniform3iv': ret = {{{ Functions.getIndex('_glUniform3iv', true) }}}; break; - case 'glUniform4iv': ret = {{{ Functions.getIndex('_glUniform4iv', true) }}}; break; - case 'glBindAttribLocation': ret = {{{ Functions.getIndex('_glBindAttribLocation', true) }}}; break; - case 'glGetActiveUniform': ret = {{{ Functions.getIndex('_glGetActiveUniform', true) }}}; break; - case 'glGenBuffers': ret = {{{ Functions.getIndex('_glGenBuffers', true) }}}; break; - case 'glBindBuffer': ret = {{{ Functions.getIndex('_glBindBuffer', true) }}}; break; - case 'glBufferData': ret = {{{ Functions.getIndex('_glBufferData', true) }}}; break; - case 'glBufferSubData': ret = {{{ Functions.getIndex('_glBufferSubData', true) }}}; break; - case 'glDeleteBuffers': ret = {{{ Functions.getIndex('_glDeleteBuffers', true) }}}; break; - case 'glActiveTexture': ret = {{{ Functions.getIndex('_glActiveTexture', true) }}}; break; - case 'glClientActiveTexture': ret = {{{ Functions.getIndex('_glClientActiveTexture', true) }}}; break; - case 'glGetProgramiv': ret = {{{ Functions.getIndex('_glGetProgramiv', true) }}}; break; - case 'glEnableVertexAttribArray': ret = {{{ Functions.getIndex('_glEnableVertexAttribArray', true) }}}; break; - case 'glDisableVertexAttribArray': ret = {{{ Functions.getIndex('_glDisableVertexAttribArray', true) }}}; break; - case 'glVertexAttribPointer': ret = {{{ Functions.getIndex('_glVertexAttribPointer', true) }}}; break; - case 'glVertexAttrib1f': ret = {{{ Functions.getIndex('_glVertexAttrib1f', true) }}}; break; - case 'glVertexAttrib2f': ret = {{{ Functions.getIndex('_glVertexAttrib2f', true) }}}; break; - case 'glVertexAttrib3f': ret = {{{ Functions.getIndex('_glVertexAttrib3f', true) }}}; break; - case 'glVertexAttrib4f': ret = {{{ Functions.getIndex('_glVertexAttrib4f', true) }}}; break; - case 'glVertexAttrib1fv': ret = {{{ Functions.getIndex('_glVertexAttrib1fv', true) }}}; break; - case 'glVertexAttrib2fv': ret = {{{ Functions.getIndex('_glVertexAttrib2fv', true) }}}; break; - case 'glVertexAttrib3fv': ret = {{{ Functions.getIndex('_glVertexAttrib3fv', true) }}}; break; - case 'glVertexAttrib4fv': ret = {{{ Functions.getIndex('_glVertexAttrib4fv', true) }}}; break; - case 'glGetVertexAttribfv': ret = {{{ Functions.getIndex('_glGetVertexAttribfv', true) }}}; break; - case 'glGetVertexAttribiv': ret = {{{ Functions.getIndex('_glGetVertexAttribiv', true) }}}; break; - case 'glGetVertexAttribPointerv': ret = {{{ Functions.getIndex('_glGetVertexAttribPointerv', true) }}}; break; - case 'glGetAttribLocation': ret = {{{ Functions.getIndex('_glGetAttribLocation', true) }}}; break; - case 'glGetActiveAttrib': ret = {{{ Functions.getIndex('_glGetActiveAttrib', true) }}}; break; - case 'glBindRenderbuffer': ret = {{{ Functions.getIndex('_glBindRenderbuffer', true) }}}; break; - case 'glDeleteRenderbuffers': ret = {{{ Functions.getIndex('_glDeleteRenderbuffers', true) }}}; break; - case 'glGenRenderbuffers': ret = {{{ Functions.getIndex('_glGenRenderbuffers', true) }}}; break; - case 'glCompressedTexImage2D': ret = {{{ Functions.getIndex('_glCompressedTexImage2D', true) }}}; break; - case 'glCompressedTexSubImage2D': ret = {{{ Functions.getIndex('_glCompressedTexSubImage2D', true) }}}; break; - case 'glBindFramebuffer': ret = {{{ Functions.getIndex('_glBindFramebuffer', true) }}}; break; - case 'glGenFramebuffers': ret = {{{ Functions.getIndex('_glGenFramebuffers', true) }}}; break; - case 'glDeleteFramebuffers': ret = {{{ Functions.getIndex('_glDeleteFramebuffers', true) }}}; break; - case 'glFramebufferRenderbuffer': ret = {{{ Functions.getIndex('_glFramebufferRenderbuffer', true) }}}; break; - case 'glFramebufferTexture2D': ret = {{{ Functions.getIndex('_glFramebufferTexture2D', true) }}}; break; - case 'glGetFramebufferAttachmentParameteriv': ret = {{{ Functions.getIndex('_glGetFramebufferAttachmentParameteriv', true) }}}; break; - case 'glIsFramebuffer': ret = {{{ Functions.getIndex('_glIsFramebuffer', true) }}}; break; - case 'glCheckFramebufferStatus': ret = {{{ Functions.getIndex('_glCheckFramebufferStatus', true) }}}; break; - case 'glRenderbufferStorage': ret = {{{ Functions.getIndex('_glRenderbufferStorage', true) }}}; break; - case 'glGenVertexArrays': ret = {{{ Functions.getIndex('_glGenVertexArrays', true) }}}; break; - case 'glDeleteVertexArrays': ret = {{{ Functions.getIndex('_glDeleteVertexArrays', true) }}}; break; - case 'glBindVertexArray': ret = {{{ Functions.getIndex('_glBindVertexArray', true) }}}; break; - case 'glGetString': ret = {{{ Functions.getIndex('_glGetString', true) }}}; break; - case 'glBindTexture': ret = {{{ Functions.getIndex('_glBindTexture', true) }}}; break; - case 'glGetBufferParameteriv': ret = {{{ Functions.getIndex('_glGetBufferParameteriv', true) }}}; break; - case 'glIsBuffer': ret = {{{ Functions.getIndex('_glIsBuffer', true) }}}; break; - case 'glDeleteShader': ret = {{{ Functions.getIndex('_glDeleteShader', true) }}}; break; - case 'glUniformMatrix2fv': ret = {{{ Functions.getIndex('_glUniformMatrix2fv', true) }}}; break; - case 'glUniformMatrix3fv': ret = {{{ Functions.getIndex('_glUniformMatrix3fv', true) }}}; break; - case 'glUniformMatrix4fv': ret = {{{ Functions.getIndex('_glUniformMatrix4fv', true) }}}; break; - case 'glIsRenderbuffer': ret = {{{ Functions.getIndex('_glIsRenderbuffer', true) }}}; break; - case 'glBlendEquation': ret = {{{ Functions.getIndex('_glBlendEquation', true) }}}; break; - case 'glBlendFunc': ret = {{{ Functions.getIndex('_glBlendFunc', true) }}}; break; - case 'glBlendFuncSeparate': ret = {{{ Functions.getIndex('_glBlendFuncSeparate', true) }}}; break; - case 'glBlendEquationSeparate': ret = {{{ Functions.getIndex('_glBlendEquationSeparate', true) }}}; break; - case 'glDepthRangef': ret = {{{ Functions.getIndex('_glDepthRangef', true) }}}; break; - case 'glClear': ret = {{{ Functions.getIndex('_glClear', true) }}}; break; - case 'glGenerateMipmap': ret = {{{ Functions.getIndex('_glGenerateMipmap', true) }}}; break; - case 'glBlendColor': ret = {{{ Functions.getIndex('_glBlendColor', true) }}}; break; - case 'glClearDepthf': ret = {{{ Functions.getIndex('_glClearDepthf', true) }}}; break; - case 'glDeleteProgram': ret = {{{ Functions.getIndex('_glDeleteProgram', true) }}}; break; - case 'glUniformMatrix3fv': ret = {{{ Functions.getIndex('_glUniformMatrix3fv', true) }}}; break; - case 'glClearColor': ret = {{{ Functions.getIndex('_glClearColor', true) }}}; break; - case 'glGetRenderbufferParameteriv': ret = {{{ Functions.getIndex('_glGetRenderbufferParameteriv', true) }}}; break; - case 'glGetShaderInfoLog': ret = {{{ Functions.getIndex('_glGetShaderInfoLog', true) }}}; break; - case 'glUniformMatrix4fv': ret = {{{ Functions.getIndex('_glUniformMatrix4fv', true) }}}; break; - case 'glClearStencil': ret = {{{ Functions.getIndex('_glClearStencil', true) }}}; break; - case 'glGetProgramInfoLog': ret = {{{ Functions.getIndex('_glGetProgramInfoLog', true) }}}; break; - case 'glGetUniformfv': ret = {{{ Functions.getIndex('_glGetUniformfv', true) }}}; break; - case 'glStencilFuncSeparate': ret = {{{ Functions.getIndex('_glStencilFuncSeparate', true) }}}; break; - case 'glSampleCoverage': ret = {{{ Functions.getIndex('_glSampleCoverage', true) }}}; break; - case 'glColorMask': ret = {{{ Functions.getIndex('_glColorMask', true) }}}; break; - case 'glGetShaderiv': ret = {{{ Functions.getIndex('_glGetShaderiv', true) }}}; break; - case 'glGetUniformiv': ret = {{{ Functions.getIndex('_glGetUniformiv', true) }}}; break; - case 'glCopyTexSubImage2D': ret = {{{ Functions.getIndex('_glCopyTexSubImage2D', true) }}}; break; - case 'glDetachShader': ret = {{{ Functions.getIndex('_glDetachShader', true) }}}; break; - case 'glGetShaderSource': ret = {{{ Functions.getIndex('_glGetShaderSource', true) }}}; break; - case 'glDeleteTextures': ret = {{{ Functions.getIndex('_glDeleteTextures', true) }}}; break; - case 'glGetAttachedShaders': ret = {{{ Functions.getIndex('_glGetAttachedShaders', true) }}}; break; - case 'glValidateProgram': ret = {{{ Functions.getIndex('_glValidateProgram', true) }}}; break; - case 'glDepthFunc': ret = {{{ Functions.getIndex('_glDepthFunc', true) }}}; break; - case 'glIsShader': ret = {{{ Functions.getIndex('_glIsShader', true) }}}; break; - case 'glDepthMask': ret = {{{ Functions.getIndex('_glDepthMask', true) }}}; break; - case 'glStencilMaskSeparate': ret = {{{ Functions.getIndex('_glStencilMaskSeparate', true) }}}; break; - case 'glIsProgram': ret = {{{ Functions.getIndex('_glIsProgram', true) }}}; break; - case 'glDisable': ret = {{{ Functions.getIndex('_glDisable', true) }}}; break; - case 'glStencilOpSeparate': ret = {{{ Functions.getIndex('_glStencilOpSeparate', true) }}}; break; - case 'glDrawArrays': ret = {{{ Functions.getIndex('_glDrawArrays', true) }}}; break; - case 'glDrawElements': ret = {{{ Functions.getIndex('_glDrawElements', true) }}}; break; - case 'glEnable': ret = {{{ Functions.getIndex('_glEnable', true) }}}; break; - case 'glFinish': ret = {{{ Functions.getIndex('_glFinish', true) }}}; break; - case 'glFlush': ret = {{{ Functions.getIndex('_glFlush', true) }}}; break; - case 'glFrontFace': ret = {{{ Functions.getIndex('_glFrontFace', true) }}}; break; - case 'glCullFace': ret = {{{ Functions.getIndex('_glCullFace', true) }}}; break; - case 'glGenTextures': ret = {{{ Functions.getIndex('_glGenTextures', true) }}}; break; - case 'glGetError': ret = {{{ Functions.getIndex('_glGetError', true) }}}; break; - case 'glGetIntegerv': ret = {{{ Functions.getIndex('_glGetIntegerv', true) }}}; break; - case 'glGetBooleanv': ret = {{{ Functions.getIndex('_glGetBooleanv', true) }}}; break; - case 'glGetFloatv': ret = {{{ Functions.getIndex('_glGetFloatv', true) }}}; break; - case 'glHint': ret = {{{ Functions.getIndex('_glHint', true) }}}; break; - case 'glIsTexture': ret = {{{ Functions.getIndex('_glIsTexture', true) }}}; break; - case 'glPixelStorei': ret = {{{ Functions.getIndex('_glPixelStorei', true) }}}; break; - case 'glReadPixels': ret = {{{ Functions.getIndex('_glReadPixels', true) }}}; break; - case 'glScissor': ret = {{{ Functions.getIndex('_glScissor', true) }}}; break; - case 'glStencilFunc': ret = {{{ Functions.getIndex('_glStencilFunc', true) }}}; break; - case 'glStencilMask': ret = {{{ Functions.getIndex('_glStencilMask', true) }}}; break; - case 'glStencilOp': ret = {{{ Functions.getIndex('_glStencilOp', true) }}}; break; - case 'glTexImage2D': ret = {{{ Functions.getIndex('_glTexImage2D', true) }}}; break; - case 'glTexParameterf': ret = {{{ Functions.getIndex('_glTexParameterf', true) }}}; break; - case 'glTexParameterfv': ret = {{{ Functions.getIndex('_glTexParameterfv', true) }}}; break; - case 'glTexParameteri': ret = {{{ Functions.getIndex('_glTexParameteri', true) }}}; break; - case 'glTexParameteriv': ret = {{{ Functions.getIndex('_glTexParameteriv', true) }}}; break; - case 'glGetTexParameterfv': ret = {{{ Functions.getIndex('_glGetTexParameterfv', true) }}}; break; - case 'glGetTexParameteriv': ret = {{{ Functions.getIndex('_glGetTexParameteriv', true) }}}; break; - case 'glTexSubImage2D': ret = {{{ Functions.getIndex('_glTexSubImage2D', true) }}}; break; - case 'glCopyTexImage2D': ret = {{{ Functions.getIndex('_glCopyTexImage2D', true) }}}; break; - case 'glViewport': ret = {{{ Functions.getIndex('_glViewport', true) }}}; break; - case 'glIsEnabled': ret = {{{ Functions.getIndex('_glIsEnabled', true) }}}; break; - case 'glLineWidth': ret = {{{ Functions.getIndex('_glLineWidth', true) }}}; break; - case 'glPolygonOffset': ret = {{{ Functions.getIndex('_glPolygonOffset', true) }}}; break; - case 'glReleaseShaderCompiler': ret = {{{ Functions.getIndex('_glReleaseShaderCompiler', true) }}}; break; - case 'glGetShaderPrecisionFormat': ret = {{{ Functions.getIndex('_glGetShaderPrecisionFormat', true) }}}; break; - case 'glShaderBinary': ret = {{{ Functions.getIndex('_glShaderBinary', true) }}}; break; - } - if (!ret) Module.printErr('WARNING: getProcAddress failed for ' + name); - return ret; - } }, glGetShaderPrecisionFormat__sig: 'v', @@ -4202,7 +4037,43 @@ var LibraryGL = { glBindVertexArrayOES: 'glBindVertexArray', glFramebufferTexture2DOES: 'glFramebufferTexture2D', -#endif // DISABLE_GL_EMULATION == 0 +#else // LEGACY_GL_EMULATION + + // Warn if code tries to use various emulation stuff, when emulation is disabled + // (do not warn if INCLUDE_FULL_LIBRARY is one, because then likely the gl code will + // not be called anyhow, leave only the runtime aborts) + glVertexPointer__deps: [function() { +#if INCLUDE_FULL_LIBRARY == 0 + warn('Legacy GL function (glVertexPointer) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'); +#endif + }], + glVertexPointer: function(){ throw 'Legacy GL function (glVertexPointer) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; }, + glGenVertexArrays__deps: [function() { +#if INCLUDE_FULL_LIBRARY == 0 + warn('Legacy GL function (glGenVertexArrays) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'); +#endif + }], + glGenVertexArrays: function(){ throw 'Legacy GL function (glGenVertexArrays) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; }, + glMatrixMode__deps: [function() { +#if INCLUDE_FULL_LIBRARY == 0 + warn('Legacy GL function (glMatrixMode) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'); +#endif + }], + glMatrixMode: function(){ throw 'Legacy GL function (glMatrixMode) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; }, + glBegin__deps: [function() { +#if INCLUDE_FULL_LIBRARY == 0 + warn('Legacy GL function (glBegin) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'); +#endif + }], + glBegin: function(){ throw 'Legacy GL function (glBegin) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; }, + glLoadIdentity__deps: [function() { +#if INCLUDE_FULL_LIBRARY == 0 + warn('Legacy GL function (glLoadIdentity) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'); +#endif + }], + glLoadIdentity: function(){ throw 'Legacy GL function (glLoadIdentity) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; }, + +#endif // LEGACY_GL_EMULATION // GLU @@ -4438,28 +4309,60 @@ var LibraryGL = { autoAddDeps(LibraryGL, '$GL'); -if (!DISABLE_GL_EMULATION) { - // Emulation requires everything else, potentially - LibraryGL.$GLEmulation__deps = LibraryGL.$GLEmulation__deps.slice(0); // the __deps object is shared - var glFuncs = []; - for (var item in LibraryGL) { - if (item != '$GLEmulation' && item.substr(-6) != '__deps' && item.substr(-9) != '__postset' && item.substr(-5) != '__sig' && item.substr(0, 2) == 'gl') { - glFuncs.push(item); +// Legacy GL emulation +if (LEGACY_GL_EMULATION) { + DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.push('$GLEmulation'); +} + +// GL proc address retrieval +LibraryGL.emscripten_GetProcAddress__deps = [function() { + // ProcAddress is used, so include everything in GL. This runs before we go to the $ProcAddressTable object, + // and we fill its deps just in time, and create the lookup table + var table = {}; + LibraryManager.library.emscripten_procAddressTable__deps = keys(LibraryGL).map(function(x) { + if (x.substr(-6) == '__deps' || x.substr(-9) == '__postset' || x.substr(-5) == '__sig' || x.substr(-5) == '__asm' || x.substr(0, 2) != 'gl') return null; + var original = x; + if (('_' + x) in Functions.implementedFunctions) { + // a user-implemented function aliases this one, but we still want it to be accessible by name, so rename it + var y = x + '__procTable'; + LibraryManager.library[y] = LibraryManager.library[x]; + LibraryManager.library[y + '__deps'] = LibraryManager.library[x + '__deps']; + LibraryManager.library[y + '__postset'] = LibraryManager.library[x + '__postset']; + LibraryManager.library[y + '__sig'] = LibraryManager.library[x + '__sig'];//|| Functions.implementedFunctions['_' + x]; + LibraryManager.library[y + '__asm'] = LibraryManager.library[x + '__asm']; + x = y; + assert(!(y in Functions.implementedFunctions) && !Functions.unimplementedFunctions['_' + y]); } - } - LibraryGL.$GLEmulation__deps = LibraryGL.$GLEmulation__deps.concat(glFuncs); - LibraryGL.$GLEmulation__deps.push(function() { - for (var func in Functions.getIndex.tentative) { - Functions.getIndex(func); - Functions.unimplementedFunctions[func] = LibraryGL[func.substr(1) + '__sig']; + var longX = '_' + x; + var sig = LibraryManager.library[x + '__sig'] || functionStubSigs[longX]; + if (sig) { + table[original] = Functions.getIndex(longX, sig); + if (!(longX in Functions.implementedFunctions)) Functions.unimplementedFunctions[longX] = sig; } - }); - - if (FORCE_GL_EMULATION) { - LibraryGL.glDrawElements__deps = LibraryGL.glDrawElements__deps.concat('$GLEmulation'); - LibraryGL.glDrawArrays__deps = LibraryGL.glDrawArrays__deps.concat('$GLEmulation'); + return x; + }).filter(function(x) { return x !== null }); + // convert table into function with switch, to not confuse closure compiler + var tableImpl = 'switch(name) {\n'; + for (var x in table) tableImpl += 'case "' + x + '": return ' + table[x] + '; break;\n'; + tableImpl += '}\nreturn 0;'; + LibraryManager.library.emscripten_procAddressTable = new Function('name', tableImpl); +}, 'emscripten_procAddressTable']; +LibraryGL.emscripten_GetProcAddress = function(name) { + name = name.replace('EXT', '').replace('ARB', ''); + switch(name) { // misc renamings + case 'glCreateProgramObject': name = 'glCreateProgram'; break; + case 'glUseProgramObject': name = 'glUseProgram'; break; + case 'glCreateShaderObject': name = 'glCreateShader'; break; + case 'glAttachObject': name = 'glAttachShader'; break; + case 'glDetachObject': name = 'glDetachShader'; break; } + var ret = _emscripten_procAddressTable(name); + if (!ret) Module.printErr('WARNING: getProcAddress failed for ' + name); + return ret; } +// Final merge mergeInto(LibraryManager.library, LibraryGL); +assert(!(FULL_ES2 && LEGACY_GL_EMULATION), 'cannot emulate both ES2 and legacy GL'); + diff --git a/src/library_sdl.js b/src/library_sdl.js index 6cc337e8..236ab1bf 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -2067,9 +2067,9 @@ var LibrarySDL = { console.log('TODO: SDL_GL_SetAttribute'); }, - SDL_GL_GetProcAddress__deps: ['$GLEmulation'], + SDL_GL_GetProcAddress__deps: ['emscripten_GetProcAddress'], SDL_GL_GetProcAddress: function(name_) { - return GLEmulation.getProcAddress(Pointer_stringify(name_)); + return _emscripten_GetProcAddress(Pointer_stringify(name_)); }, SDL_GL_SwapBuffers: function() {}, diff --git a/src/modules.js b/src/modules.js index 13561777..fa6c0983 100644 --- a/src/modules.js +++ b/src/modules.js @@ -275,20 +275,15 @@ var Functions = { }, // Mark a function as needing indexing. Python will coordinate them all - getIndex: function(ident, doNotCreate, sig) { - if (doNotCreate && !(ident in this.indexedFunctions)) { - if (!Functions.getIndex.tentative) Functions.getIndex.tentative = {}; // only used by GL emulation; TODO: generalize when needed - Functions.getIndex.tentative[ident] = 0; - } + getIndex: function(ident, sig) { var ret; if (phase != 'post' && singlePhase) { - if (!doNotCreate) this.indexedFunctions[ident] = 0; // tell python we need this indexized ret = "'{{ FI_" + toNiceIdent(ident) + " }}'"; // something python will replace later + this.indexedFunctions[ident] = 0; } else { if (!singlePhase) return 'NO_INDEX'; // Should not index functions in post ret = this.indexedFunctions[ident]; if (!ret) { - if (doNotCreate) return '0'; ret = this.nextIndex; this.nextIndex += 2; // Need to have indexes be even numbers, see |polymorph| test this.indexedFunctions[ident] = ret; @@ -326,7 +321,7 @@ var Functions = { tables[sig][index] = ident; } var generated = false; - var wrapped = {}; + var wrapped = {}; // whether we wrapped a lib func var maxTable = 0; for (var t in tables) { if (t == 'pre') continue; @@ -349,10 +344,11 @@ var Functions = { if (ASM_JS) { var curr = table[i]; if (curr && curr != '0' && !Functions.implementedFunctions[curr]) { - curr = toNiceIdent(curr); // fix Math.* to Math_* + var short = toNiceIdent(curr); // fix Math.* to Math_* + curr = t + '_' + short; // libfuncs can alias with different sigs, wrap each separately // This is a library function, we can't just put it in the function table, need a wrapper if (!wrapped[curr]) { - var args = '', arg_coercions = '', call = curr + '(', retPre = '', retPost = ''; + var args = '', arg_coercions = '', call = short + '(', retPre = '', retPost = ''; if (t[0] != 'v') { if (t[0] == 'i') { retPre = 'return '; @@ -367,7 +363,7 @@ var Functions = { call += (j > 1 ? ',' : '') + asmCoercion('a' + j, t[j] != 'i' ? 'float' : 'i32'); } call += ')'; - if (curr == '_setjmp') printErr('WARNING: setjmp used via a function pointer. If this is for libc setjmp (not something of your own with the same name), it will break things'); + if (short == '_setjmp') printErr('WARNING: setjmp used via a function pointer. If this is for libc setjmp (not something of your own with the same name), it will break things'); tables.pre += 'function ' + curr + '__wrapper(' + args + ') { ' + arg_coercions + ' ; ' + retPre + call + retPost + ' }\n'; wrapped[curr] = 1; } diff --git a/src/parseTools.js b/src/parseTools.js index f11c867a..65e96264 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1244,7 +1244,7 @@ function indexizeFunctions(value, type) { if (!sig) { sig = Functions.unimplementedFunctions[value] = Functions.getSignature(out.returnType, out.segments ? out.segments.map(function(segment) { return segment[0].text }) : [], isVarArgsFunctionType(type)); } - return Functions.getIndex(value, undefined, sig); + return Functions.getIndex(value, sig); } return value; } diff --git a/src/postamble.js b/src/postamble.js index c4ca3aae..08c3a9d8 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -127,6 +127,7 @@ Module['exit'] = Module.exit = exit; function abort(text) { if (text) { Module.print(text); + Module.printErr(text); } ABORT = true; diff --git a/src/settings.js b/src/settings.js index 3ecac040..8757f7b9 100644 --- a/src/settings.js +++ b/src/settings.js @@ -191,9 +191,8 @@ var GL_TESTING = 0; // When enabled, sets preserveDrawingBuffer in the context, var GL_MAX_TEMP_BUFFER_SIZE = 2097152; // How large GL emulation temp buffers are var GL_UNSAFE_OPTS = 1; // Enables some potentially-unsafe optimizations in GL emulation code var FULL_ES2 = 0; // Forces support for all GLES2 features, not just the WebGL-friendly subset. -var FORCE_GL_EMULATION = 0; // Forces inclusion of full GL emulation code. -var DISABLE_GL_EMULATION = 0; // Disable inclusion of full GL emulation code. Useful when you don't want emulation - // but do need INCLUDE_FULL_LIBRARY or MAIN_MODULE. +var LEGACY_GL_EMULATION = 0; // Includes code to emulate various desktop GL features. Incomplete but useful + // in some cases, see https://github.com/kripken/emscripten/wiki/OpenGL-support var STB_IMAGE = 0; // Enables building of stb-image, a tiny public-domain library for decoding images, allowing // decoding of images without using the browser's built-in decoders. The benefit is that this diff --git a/system/include/compat/math.h b/system/include/compat/math.h new file mode 100644 index 00000000..089cf66b --- /dev/null +++ b/system/include/compat/math.h @@ -0,0 +1,14 @@ +#ifndef _COMPAT_MATH_H_ +#define _COMPAT_MATH_H_ + +#ifndef isinff + #define isinff isinf +#endif + +#ifndef isnanf + #define isnanf isnan +#endif + +#include_next <math.h> + +#endif /* _COMPAT_MATH_H_ */ diff --git a/system/include/compat/stdlib.h b/system/include/compat/stdlib.h new file mode 100644 index 00000000..dc01947d --- /dev/null +++ b/system/include/compat/stdlib.h @@ -0,0 +1,16 @@ +#ifndef _COMPAT_STDLIB_H +#define _COMPAT_STDLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +int getloadavg(double loadavg[], int nelem); + +#ifdef __cplusplus +} +#endif + +#include_next <stdlib.h> + +#endif diff --git a/system/include/compat/string.h b/system/include/compat/string.h new file mode 100644 index 00000000..880089cc --- /dev/null +++ b/system/include/compat/string.h @@ -0,0 +1,17 @@ +#ifndef _COMPAT_STRING_H +#define _COMPAT_STRING_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern char* strlwr(char *); +extern char* strupr(char *); + +#ifdef __cplusplus +} +#endif + +#include_next <string.h> + +#endif diff --git a/system/include/compat/sys/stat.h b/system/include/compat/sys/stat.h new file mode 100644 index 00000000..731502ea --- /dev/null +++ b/system/include/compat/sys/stat.h @@ -0,0 +1,20 @@ +#ifndef _COMPAT_STAT_H +#define _COMPAT_STAT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include_next <sys/stat.h> + +#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO) +#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO) +#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH) +#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH) +#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/system/include/libc/sys/timeb.h b/system/include/compat/sys/timeb.h index 0a2c3de8..0a2c3de8 100644 --- a/system/include/libc/sys/timeb.h +++ b/system/include/compat/sys/timeb.h diff --git a/system/include/compat/unistd.h b/system/include/compat/unistd.h new file mode 100644 index 00000000..07c3afde --- /dev/null +++ b/system/include/compat/unistd.h @@ -0,0 +1,16 @@ +#ifndef _COMPAT_UNISTD_H +#define _COMPAT_UNISTD_H + +#ifdef __cplusplus +extern "C" { +#endif + +char * getwd(char *__buf ); + +#ifdef __cplusplus +} +#endif + +#include_next <unistd.h> + +#endif diff --git a/system/include/compat/xlocale.h b/system/include/compat/xlocale.h new file mode 100644 index 00000000..4bafa27d --- /dev/null +++ b/system/include/compat/xlocale.h @@ -0,0 +1,21 @@ +#ifndef _COMPAT_XLOCALE_H_ +#define _COMPAT_XLOCALE_H_ + +#include <locale.h> + +#ifdef __cplusplus +extern "C" { +#endif + +long long strtoll_l(const char *start, char **end, int base, locale_t loc); +unsigned long long strtoull_l(const char *start, char **end, int base, locale_t loc); +double strtold_l(const char *start, char **end, locale_t loc); + +#ifdef __cplusplus +} +#endif + +#include_next <xlocale.h> + +#endif /* _COMPAT_XLOCALE_H_ */ + diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h index 28e6063c..f0df8dca 100644 --- a/system/include/emscripten/emscripten.h +++ b/system/include/emscripten/emscripten.h @@ -20,14 +20,13 @@ extern "C" { /* * Forces LLVM to not dead-code-eliminate a function. Note that - * closure may still eliminate it at the JS level, for which you - * should use EXPORTED_FUNCTIONS (see settings.js). - * - * **DEPRECATED**: Use EXPORTED_FUNCTIONS instead, which will work - * with closure, asm.js, etc. For example - * -s EXPORTED_FUNCTIONS=["_main", "myfunc"] + * you still need to use EXPORTED_FUNCTIONS so it stays alive + * in JS, e.g. + * emcc -s EXPORTED_FUNCTIONS=["_main", "_myfunc"] + * and in the source file + * void EMSCRIPTEN_KEEPALIVE myfunc() {..} */ -/* #define EMSCRIPTEN_KEEPALIVE __attribute__((used)) */ +#define EMSCRIPTEN_KEEPALIVE __attribute__((used)) /* * Interface to the underlying JS engine. This function will diff --git a/system/include/libc/stdlib.h b/system/include/libc/stdlib.h index 888b6041..6fdef40b 100644 --- a/system/include/libc/stdlib.h +++ b/system/include/libc/stdlib.h @@ -223,8 +223,6 @@ extern long double strtold (const char *, char **); extern long double wcstold (const wchar_t *, wchar_t **); #endif /* _LDBL_EQ_DBL */ -int getloadavg(double loadavg[], int nelem); /* XXX Emscripten */ - _END_STD_C #endif /* _STDLIB_H_ */ diff --git a/system/include/libc/string.h b/system/include/libc/string.h index 515c71a7..8fd9ea43 100644 --- a/system/include/libc/string.h +++ b/system/include/libc/string.h @@ -72,8 +72,6 @@ size_t _EXFUN(strlcpy,(char *, const char *, size_t)); int _EXFUN(strncasecmp,(const char *, const char *, size_t)); size_t _EXFUN(strnlen,(const char *, size_t)); char *_EXFUN(strsep,(char **, const char *)); -char *_EXFUN(strlwr,(char *)); -char *_EXFUN(strupr,(char *)); #if defined(__CYGWIN__) || defined(EMSCRIPTEN) #ifndef DEFS_H /* Kludge to work around problem compiling in gdb */ char *_EXFUN(strsignal, (int __signo)); diff --git a/system/include/libc/sys/unistd.h b/system/include/libc/sys/unistd.h index 1a414b3c..a4219d4d 100644 --- a/system/include/libc/sys/unistd.h +++ b/system/include/libc/sys/unistd.h @@ -102,7 +102,6 @@ uid_t _EXFUN(getuid, (void )); #endif #if defined(EMSCRIPTEN) || defined(__CYGWIN__) char * _EXFUN(getusershell, (void)); -char * _EXFUN(getwd, (char *__buf )); int _EXFUN(iruserok, (unsigned long raddr, int superuser, const char *ruser, const char *luser)); #endif int _EXFUN(isatty, (int __fildes )); diff --git a/system/include/xlocale.h b/system/include/xlocale.h index bb3b50e5..6867d25f 100644 --- a/system/include/xlocale.h +++ b/system/include/xlocale.h @@ -1,4 +1,3 @@ - #ifndef _XLOCALE_H_ #define _XLOCALE_H_ @@ -9,10 +8,6 @@ extern "C" { #endif -long long strtoll_l(const char *start, char **end, int base, locale_t loc); -unsigned long long strtoull_l(const char *start, char **end, int base, locale_t loc); -double strtold_l(const char *start, char **end, locale_t loc); - int strcoll_l(const char *s1, const char *s2, locale_t locale); int wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t locale); @@ -43,5 +38,5 @@ size_t strftime_l(char *s, size_t maxsize, const char *format, const struct tm * } #endif -#endif /* _LOCALE_H_ */ +#endif /* _XLOCALE_H_ */ diff --git a/tests/aniso.c b/tests/aniso.c index 1126265e..f210e5a5 100644 --- a/tests/aniso.c +++ b/tests/aniso.c @@ -161,7 +161,7 @@ int main(int argc, char *argv[]) for (int x = 0; x < n; x++) { int start = x*w*2; glBegin( GL_TRIANGLES ); - glTexCoord2i( 1, 0 ); glVertex3f( start , 0, 0 ); + glTexCoord2i( 1, 0 ); glVertex2i( start , 0 ); glTexCoord2i( 0, 0 ); glVertex3f( start+w, 300, 0 ); glTexCoord2i( 1, 1 ); glVertex3f( start-w, 300, 0 ); glEnd(); @@ -209,5 +209,11 @@ int main(int argc, char *argv[]) SDL_Quit(); - return 0; + // check for asm compilation bug with aliased functions with different sigs + void (*f)(int, int) = glVertex2i; + if ((int)f % 16 == 4) f(5, 7); + void (*g)(int, int) = glVertex3f; + if ((int)g % 16 == 4) g(5, 7); + return (int)f + (int)g; } + diff --git a/tests/runner.py b/tests/runner.py index 2f508dfc..318946e6 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -275,6 +275,18 @@ process(sys.argv[1]) print "Output: " + output[0] return output[0] + # Tests that the given two paths are identical, modulo path delimiters. E.g. "C:/foo" is equal to "C:\foo". + def assertPathsIdentical(self, path1, path2): + path1 = path1.replace('\\', '/') + path2 = path2.replace('\\', '/') + return self.assertIdentical(path1, path2) + + # Tests that the given two multiline text content are identical, modulo line ending differences (\r\n on Windows, \n on Unix). + def assertTextDataIdentical(self, text1, text2): + text1 = text1.replace('\r\n', '\n') + text2 = text2.replace('\r\n', '\n') + return self.assertIdentical(text1, text2) + def assertIdentical(self, values, y): if type(values) not in [list, tuple]: values = [values] for x in values: @@ -480,7 +492,7 @@ def server_func(dir, q): if 'report_' in s.path: q.put(s.path) else: - filename = s.path[1:] + filename = s.path.split('?')[0][1:] if os.path.exists(filename): s.send_response(200) s.send_header("Content-type", "text/html") @@ -649,6 +661,7 @@ class BrowserCore(RunnerCore): self.reftest(path_from_root('tests', reference)) args = args + ['--pre-js', 'reftest.js', '-s', 'GL_TESTING=1'] Popen([PYTHON, EMCC, temp_filepath, '-o', outfile] + args).communicate() + assert os.path.exists(outfile) if type(expected) is str: expected = [expected] self.run_browser(outfile, message, ['/report_result?' + e for e in expected]) @@ -765,10 +778,17 @@ an individual test with except: pass + numFailures = 0 # Keep count of the total number of failing tests. + # Run the discovered tests if not len(suites): print >> sys.stderr, 'No tests found for %s' % str(sys.argv[1:]) + numFailures = 1 else: testRunner = unittest.TextTestRunner(verbosity=2) for suite in suites: - testRunner.run(suite) + results = testRunner.run(suite) + numFailures += len(results.errors) + len(results.failures) + + # Return the number of failures as the process exit code for automating success/failure reporting. + exit(numFailures) diff --git a/tests/sdl_ogl_proc_alias.c b/tests/sdl_ogl_proc_alias.c new file mode 100644 index 00000000..c96da81b --- /dev/null +++ b/tests/sdl_ogl_proc_alias.c @@ -0,0 +1,180 @@ +/******************************************************************* + * * + * Using SDL With OpenGL * + * * + * Tutorial by Kyle Foley (sdw) * + * * + * http://gpwiki.org/index.php/SDL:Tutorials:Using_SDL_with_OpenGL * + * * + *******************************************************************/ + +/* +THIS WORK, INCLUDING THE SOURCE CODE, DOCUMENTATION +AND RELATED MEDIA AND DATA, IS PLACED INTO THE PUBLIC DOMAIN. + +THE ORIGINAL AUTHOR IS KYLE FOLEY. + +THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY +OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF +MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE, +ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE +RESULTING FROM THE USE, MODIFICATION, OR +REDISTRIBUTION OF THIS SOFTWARE. +*/ + +#include "SDL/SDL.h" +#include "SDL/SDL_image.h" +#include "SDL/SDL_opengl.h" + +#include <stdio.h> +#include <string.h> + +void (*true_glGenTextures)(GLsizei, GLuint*) = NULL; + +void glGenTextures(GLsizei n, GLuint *textures) { + printf("num? %d\n", n); + true_glGenTextures(n + 1, textures); // correct the error, ensures we are gone through +} + +int main(int argc, char *argv[]) +{ + SDL_Surface *screen; + + // Slightly different SDL initialization + if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) { + printf("Unable to initialize SDL: %s\n", SDL_GetError()); + return 1; + } + + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // *new* + + screen = SDL_SetVideoMode( 640, 480, 16, SDL_OPENGL ); // *changed* + if ( !screen ) { + printf("Unable to set video mode: %s\n", SDL_GetError()); + return 1; + } + + // Set the OpenGL state after creating the context with SDL_SetVideoMode + + glClearColor( 0, 0, 0, 0 ); + + glEnable( GL_TEXTURE_2D ); // Needed when we're using the fixed-function pipeline. + + glViewport( 0, 0, 640, 480 ); + + glMatrixMode( GL_PROJECTION ); + glPushMatrix(); // just for testing + glLoadIdentity(); + + glOrtho( 0, 640, 480, 0, -1, 1 ); + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + // Load the OpenGL texture + + GLuint texture; // Texture object handle + SDL_Surface *surface; // Gives us the information to make the texture + + if ( (surface = IMG_Load("screenshot.png")) ) { + + // Check that the image's width is a power of 2 + if ( (surface->w & (surface->w - 1)) != 0 ) { + printf("warning: image.bmp's width is not a power of 2\n"); + } + + // Also check if the height is a power of 2 + if ( (surface->h & (surface->h - 1)) != 0 ) { + printf("warning: image.bmp's height is not a power of 2\n"); + } + + true_glGenTextures = SDL_GL_GetProcAddress("glGenTextures"); + + // Have OpenGL generate a texture object handle for us + glGenTextures( 0, &texture ); + + // Bind the texture object + glBindTexture( GL_TEXTURE_2D, texture ); + + // Set the texture's stretching properties + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + //SDL_LockSurface(surface); + + // Add some greyness + memset(surface->pixels, 0x66, surface->w*surface->h); + + // Edit the texture object's image data using the information SDL_Surface gives us + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0, + GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels ); + + //SDL_UnlockSurface(surface); + } + else { + printf("SDL could not load image.bmp: %s\n", SDL_GetError()); + SDL_Quit(); + return 1; + } + + // Free the SDL_Surface only if it was successfully created + if ( surface ) { + SDL_FreeSurface( surface ); + } + + // Clear the screen before drawing + glClear( GL_COLOR_BUFFER_BIT ); + + // Bind the texture to which subsequent calls refer to + glBindTexture( GL_TEXTURE_2D, texture ); + + glBegin( GL_QUADS ); + glTexCoord2i( 0, 0 ); glVertex3f( 10, 10, 0 ); + glTexCoord2i( 1, 0 ); glVertex3f( 300, 10, 0 ); + glTexCoord2i( 1, 1 ); glVertex3f( 300, 128, 0 ); + glTexCoord2i( 0, 1 ); glVertex3f( 10, 128, 0 ); + + glTexCoord2f( 0, 0.5 ); glVertex3f( 410, 10, 0 ); + glTexCoord2f( 1, 0.5 ); glVertex3f( 600, 10, 0 ); + glTexCoord2f( 1, 1 ); glVertex3f( 630, 200, 0 ); + glTexCoord2f( 0.5, 1 ); glVertex3f( 310, 250, 0 ); + glEnd(); + + glBegin( GL_TRIANGLE_STRIP ); + glTexCoord2i( 0, 0 ); glVertex3f( 100, 300, 0 ); + glTexCoord2i( 1, 0 ); glVertex3f( 300, 300, 0 ); + glTexCoord2i( 1, 1 ); glVertex3f( 300, 400, 0 ); + glTexCoord2i( 0, 1 ); glVertex3f( 500, 410, 0 ); + glEnd(); + + glDisable(GL_TEXTURE_2D); + + glColor3ub(90, 255, 255); + glBegin( GL_QUADS ); + glVertex3f( 10, 410, 0 ); + glVertex3f( 300, 410, 0 ); + glVertex3f( 300, 480, 0 ); + glVertex3f( 10, 470, 0 ); + glEnd(); + + glBegin( GL_QUADS ); + glColor3f(1.0, 0, 1.0); glVertex3f( 410, 410, 0 ); + glColor3f(0, 1.0, 0); glVertex3f( 600, 410, 0 ); + glColor3f(0, 0, 1.0); glVertex3f( 600, 480, 0 ); + glColor3f(1.0, 1.0, 1.0); glVertex3f( 410, 470, 0 ); + glEnd(); + + SDL_GL_SwapBuffers(); + +#if !EMSCRIPTEN + // Wait for 3 seconds to give us a chance to see the image + SDL_Delay(3000); +#endif + + // Now we can delete the OpenGL texture and close down SDL + glDeleteTextures( 1, &texture ); + + SDL_Quit(); + + return 0; +} diff --git a/tests/sockets/test_sockets_echo_server.c b/tests/sockets/test_sockets_echo_server.c index 8a48b878..38e27cac 100644 --- a/tests/sockets/test_sockets_echo_server.c +++ b/tests/sockets/test_sockets_echo_server.c @@ -37,6 +37,11 @@ typedef struct { server_t server; client_t client; +void cleanup() { + if (server.fd) close(server.fd); + if (client.fd) close(client.fd); +} + void main_loop(void *arg) { int res; fd_set fdr; @@ -105,6 +110,9 @@ int main() { struct sockaddr_in addr; int res; + atexit(cleanup); + signal(SIGTERM, cleanup); + memset(&server, 0, sizeof(server_t)); memset(&client, 0, sizeof(client_t)); diff --git a/tests/sockets/test_sockets_partial_server.c b/tests/sockets/test_sockets_partial_server.c index 57fae84b..dfe0e249 100644 --- a/tests/sockets/test_sockets_partial_server.c +++ b/tests/sockets/test_sockets_partial_server.c @@ -14,18 +14,13 @@ #include <emscripten.h> #endif -int serverfd = -1; -int clientfd = -1; - -// csock.send("\x09\x01\x02\x03\x04\x05\x06\x07\x08\x09") -// csock.send("\x08\x01\x02\x03\x04\x05\x06\x07\x08") -// csock.send("\x07\x01\x02\x03\x04\x05\x06\x07") -// csock.send("\x06\x01\x02\x03\x04\x05\x06") -// csock.send("\x05\x01\x02\x03\x04\x05") -// csock.send("\x04\x01\x02\x03\x04") -// csock.send("\x03\x01\x02\x03") -// csock.send("\x02\x01\x02") -// csock.send("\x01\x01") +int serverfd = 0; +int clientfd = 0; + +void cleanup() { + if (serverfd) close(serverfd); + if (clientfd) close(clientfd); +} void do_send(int sockfd) { static char* buffers[] = { @@ -69,7 +64,7 @@ void iter(void *arg) { FD_ZERO(&fdr); FD_ZERO(&fdw); FD_SET(serverfd, &fdr); - if (clientfd != -1) FD_SET(clientfd, &fdw); + if (clientfd) FD_SET(clientfd, &fdw); res = select(64, &fdr, &fdw, NULL, NULL); if (res == -1) { perror("select failed"); @@ -91,6 +86,9 @@ int main() { struct sockaddr_in addr; int res; + atexit(cleanup); + signal(SIGTERM, cleanup); + // create the socket serverfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (serverfd == -1) { diff --git a/tests/sockets/webrtc_host.c b/tests/sockets/webrtc_host.c new file mode 100644 index 00000000..770e59e0 --- /dev/null +++ b/tests/sockets/webrtc_host.c @@ -0,0 +1,89 @@ +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <assert.h> +#if EMSCRIPTEN +#include <emscripten.h> +#endif + +#define EXPECTED_BYTES 5 +#define BUFLEN 16 + +int result = 0; +int sock; +char buf[BUFLEN]; +char expected[] = "emscripten"; +struct sockaddr_in si_host, + si_peer; +struct iovec iov[1]; +struct msghdr hdr; +int done = 0; + +void iter(void* arg) { + int n; + n = recvmsg(sock, &hdr, 0); + + if(0 < n) { + done = 1; + fprintf(stderr, "received %d bytes: %s", n, (char*)hdr.msg_iov[0].iov_base); + + shutdown(sock, SHUT_RDWR); + close(sock); + +#if EMSCRIPTEN + int result = 1; + REPORT_RESULT(); + exit(EXIT_SUCCESS); + emscripten_cancel_main_loop(); +#endif + } else if(EWOULDBLOCK != errno) { + perror("recvmsg failed"); + exit(EXIT_FAILURE); + emscripten_cancel_main_loop(); + } +} + +int main(void) +{ + memset(&si_host, 0, sizeof(struct sockaddr_in)); + memset(&si_peer, 0, sizeof(struct sockaddr_in)); + + si_host.sin_family = AF_INET; + si_host.sin_port = htons(8991); + si_host.sin_addr.s_addr = htonl(INADDR_ANY); + + if(-1 == (sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP))) { + perror("cannot create host socket"); + exit(EXIT_FAILURE); + } + + if(-1 == bind(sock, (struct sockaddr*)&si_host, sizeof(struct sockaddr))) { + perror("cannot bind host socket"); + exit(EXIT_FAILURE); + } + + iov[0].iov_base = buf; + iov[0].iov_len = sizeof(buf); + + memset (&hdr, 0, sizeof (struct msghdr)); + + hdr.msg_name = &si_peer; + hdr.msg_namelen = sizeof(struct sockaddr_in); + hdr.msg_iov = iov; + hdr.msg_iovlen = 1; + +#if EMSCRIPTEN + emscripten_set_main_loop(iter, 0, 0); +#else + while (!done) iter(NULL); +#endif + + return EXIT_SUCCESS; +}
\ No newline at end of file diff --git a/tests/sockets/webrtc_peer.c b/tests/sockets/webrtc_peer.c new file mode 100644 index 00000000..d24979e7 --- /dev/null +++ b/tests/sockets/webrtc_peer.c @@ -0,0 +1,81 @@ +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <assert.h> +#if EMSCRIPTEN +#include <emscripten.h> +#endif + +#define EXPECTED_BYTES 5 +#define BUFLEN 16 +#define HOST_ADDR "10.0.0.1" + +int result = 0; +int sock; +char buf[16] = "emscripten"; +struct sockaddr_in si_host; +struct iovec iov[1]; +struct msghdr hdr; +int done = 0; + +void iter(void* arg) { + int n; + n = sendmsg(sock, &hdr, 0); + + if(0 < n) { + done = 1; + fprintf(stderr, "sent %d bytes: %s", n, (char*)hdr.msg_iov[0].iov_base); + + shutdown(sock, SHUT_RDWR); + close(sock); + + exit(EXIT_SUCCESS); + emscripten_cancel_main_loop(); + } else if(EWOULDBLOCK != errno) { + perror("sendmsg failed"); + exit(EXIT_FAILURE); + emscripten_cancel_main_loop(); + } +} + +int main(void) +{ + memset(&si_host, 0, sizeof(struct sockaddr_in)); + + si_host.sin_family = AF_INET; + si_host.sin_port = htons(8991); + if(0 == inet_pton(AF_INET, HOST_ADDR, &si_host.sin_addr)) { + perror("inet_aton failed"); + exit(EXIT_FAILURE); + } + + if(-1 == (sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP))) { + perror("cannot create socket"); + exit(EXIT_FAILURE); + } + + iov[0].iov_base = buf; + iov[0].iov_len = sizeof(buf); + + memset (&hdr, 0, sizeof (struct msghdr)); + + hdr.msg_name = &si_host; + hdr.msg_namelen = sizeof(struct sockaddr_in); + hdr.msg_iov = iov; + hdr.msg_iovlen = 1; + +#if EMSCRIPTEN + emscripten_set_main_loop(iter, 0, 0); +#else + while (!done) iter(NULL); +#endif + + return EXIT_SUCCESS; +}
\ No newline at end of file diff --git a/tests/test_browser.py b/tests/test_browser.py index be2c388b..69fb6f7e 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -620,7 +620,7 @@ Press any key to continue.''' def test_sdl_canvas(self): open(os.path.join(self.get_dir(), 'sdl_canvas.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_canvas.c')).read())) - Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_canvas.c'), '-o', 'page.html']).communicate() + Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_canvas.c'), '-o', 'page.html', '-s', 'LEGACY_GL_EMULATION=1']).communicate() self.run_browser('page.html', '', '/report_result?1') def test_sdl_key(self): @@ -843,50 +843,55 @@ Press any key to continue.''' def test_sdl_ogl(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_ogl.c', reference='screenshot-gray-purple.png', reference_slack=1, - args=['-O2', '--minify', '0', '--preload-file', 'screenshot.png'], + args=['-O2', '--minify', '0', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], message='You should see an image with gray at the top.') def test_sdl_ogl_defaultmatrixmode(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_ogl_defaultMatrixMode.c', reference='screenshot-gray-purple.png', reference_slack=1, - args=['--minify', '0', '--preload-file', 'screenshot.png'], + args=['--minify', '0', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], message='You should see an image with gray at the top.') def test_sdl_ogl_p(self): # Immediate mode with pointers shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_ogl_p.c', reference='screenshot-gray.png', reference_slack=1, - args=['--preload-file', 'screenshot.png'], + args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], message='You should see an image with gray at the top.') + def test_sdl_ogl_proc_alias(self): + shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) + self.btest('sdl_ogl_proc_alias.c', reference='screenshot-gray-purple.png', reference_slack=1, + args=['-O2', '-g2', '-s', 'INLINING_LIMIT=1', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '-s', 'VERBOSE=1']) + def test_sdl_fog_simple(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_fog_simple.c', reference='screenshot-fog-simple.png', - args=['-O2', '--minify', '0', '--preload-file', 'screenshot.png'], + args=['-O2', '--minify', '0', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], message='You should see an image with fog.') def test_sdl_fog_negative(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_fog_negative.c', reference='screenshot-fog-negative.png', - args=['--preload-file', 'screenshot.png'], + args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], message='You should see an image with fog.') def test_sdl_fog_density(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_fog_density.c', reference='screenshot-fog-density.png', - args=['--preload-file', 'screenshot.png'], + args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], message='You should see an image with fog.') def test_sdl_fog_exp2(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_fog_exp2.c', reference='screenshot-fog-exp2.png', - args=['--preload-file', 'screenshot.png'], + args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], message='You should see an image with fog.') def test_sdl_fog_linear(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_fog_linear.c', reference='screenshot-fog-linear.png', reference_slack=1, - args=['--preload-file', 'screenshot.png'], + args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], message='You should see an image with fog.') def test_openal_playback(self): @@ -903,7 +908,7 @@ Press any key to continue.''' def test_glfw(self): open(os.path.join(self.get_dir(), 'glfw.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'glfw.c')).read())) - Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'glfw.c'), '-o', 'page.html']).communicate() + Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'glfw.c'), '-o', 'page.html', '-s', 'LEGACY_GL_EMULATION=1']).communicate() self.run_browser('page.html', '', '/report_result?1') def test_egl_width_height(self): @@ -1063,17 +1068,13 @@ Press any key to continue.''' def test_glgears_animation(self): es2_suffix = ['', '_full', '_full_944'] for full_es2 in [0, 1, 2]: - for emulation in [0, 1]: - if full_es2 and emulation: continue - print full_es2, emulation - Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_gles%s.c' % es2_suffix[full_es2]), '-o', 'something.html', - '-DHAVE_BUILTIN_SINCOS', '-s', 'GL_TESTING=1', - '--shell-file', path_from_root('tests', 'hello_world_gles_shell.html')] + - (['-s', 'FORCE_GL_EMULATION=1'] if emulation else []) + - (['-s', 'FULL_ES2=1'] if full_es2 else []), - ).communicate() - self.run_browser('something.html', 'You should see animating gears.', '/report_gl_result?true') - assert ('var GLEmulation' in open(self.in_dir('something.html')).read()) == emulation, "emulation code should be added when asked for" + print full_es2 + Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_gles%s.c' % es2_suffix[full_es2]), '-o', 'something.html', + '-DHAVE_BUILTIN_SINCOS', '-s', 'GL_TESTING=1', + '--shell-file', path_from_root('tests', 'hello_world_gles_shell.html')] + + (['-s', 'FULL_ES2=1'] if full_es2 else []), + ).communicate() + self.run_browser('something.html', 'You should see animating gears.', '/report_gl_result?true') def test_fulles2_sdlproc(self): self.btest('full_es2_sdlproc.c', '1', args=['-s', 'GL_TESTING=1', '-DHAVE_BUILTIN_SINCOS', '-s', 'FULL_ES2=1']) @@ -1163,90 +1164,90 @@ Press any key to continue.''' self.btest('glgetattachedshaders.c', '1') def test_sdlglshader(self): - self.btest('sdlglshader.c', reference='sdlglshader.png', args=['-O2', '--closure', '1']) + self.btest('sdlglshader.c', reference='sdlglshader.png', args=['-O2', '--closure', '1', '-s', 'LEGACY_GL_EMULATION=1']) def test_gl_ps(self): # pointers and a shader shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) - self.btest('gl_ps.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png'], reference_slack=1) + self.btest('gl_ps.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], reference_slack=1) def test_gl_ps_packed(self): # packed data that needs to be strided shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) - self.btest('gl_ps_packed.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png'], reference_slack=1) + self.btest('gl_ps_packed.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], reference_slack=1) def test_gl_ps_strides(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) - self.btest('gl_ps_strides.c', reference='gl_ps_strides.png', args=['--preload-file', 'screenshot.png']) + self.btest('gl_ps_strides.c', reference='gl_ps_strides.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1']) def test_gl_renderers(self): - self.btest('gl_renderers.c', reference='gl_renderers.png', args=['-s', 'GL_UNSAFE_OPTS=0']) + self.btest('gl_renderers.c', reference='gl_renderers.png', args=['-s', 'GL_UNSAFE_OPTS=0', '-s', 'LEGACY_GL_EMULATION=1']) def test_gl_stride(self): - self.btest('gl_stride.c', reference='gl_stride.png', args=['-s', 'GL_UNSAFE_OPTS=0']) + self.btest('gl_stride.c', reference='gl_stride.png', args=['-s', 'GL_UNSAFE_OPTS=0', '-s', 'LEGACY_GL_EMULATION=1']) def test_matrix_identity(self): - self.btest('gl_matrix_identity.c', expected=['-1882984448', '460451840']) + self.btest('gl_matrix_identity.c', expected=['-1882984448', '460451840'], args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_pre(self): - self.btest('cubegeom_pre.c', reference='cubegeom_pre.png') + self.btest('cubegeom_pre.c', reference='cubegeom_pre.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_pre2(self): - self.btest('cubegeom_pre2.c', reference='cubegeom_pre2.png', args=['-s', 'GL_DEBUG=1']) # some coverage for GL_DEBUG not breaking the build + self.btest('cubegeom_pre2.c', reference='cubegeom_pre2.png', args=['-s', 'GL_DEBUG=1', '-s', 'LEGACY_GL_EMULATION=1']) # some coverage for GL_DEBUG not breaking the build def test_cubegeom_pre3(self): - self.btest('cubegeom_pre3.c', reference='cubegeom_pre2.png') + self.btest('cubegeom_pre3.c', reference='cubegeom_pre2.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom(self): - self.btest('cubegeom.c', args=['-O2', '-g'], reference='cubegeom.png') + self.btest('cubegeom.c', reference='cubegeom.png', args=['-O2', '-g', '-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_glew(self): - self.btest('cubegeom_glew.c', args=['-O2', '--closure', '1'], reference='cubegeom.png') + self.btest('cubegeom_glew.c', reference='cubegeom.png', args=['-O2', '--closure', '1', '-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_color(self): - self.btest('cubegeom_color.c', reference='cubegeom_color.png') + self.btest('cubegeom_color.c', reference='cubegeom_color.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_normal(self): - self.btest('cubegeom_normal.c', reference='cubegeom_normal.png') + self.btest('cubegeom_normal.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_normal_dap(self): # draw is given a direct pointer to clientside memory, no element array buffer - self.btest('cubegeom_normal_dap.c', reference='cubegeom_normal.png') + self.btest('cubegeom_normal_dap.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_normal_dap_far(self): # indices do nto start from 0 - self.btest('cubegeom_normal_dap_far.c', reference='cubegeom_normal.png') + self.btest('cubegeom_normal_dap_far.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_normal_dap_far_range(self): # glDrawRangeElements - self.btest('cubegeom_normal_dap_far_range.c', reference='cubegeom_normal.png') + self.btest('cubegeom_normal_dap_far_range.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_normal_dap_far_glda(self): # use glDrawArrays - self.btest('cubegeom_normal_dap_far_glda.c', reference='cubegeom_normal_dap_far_glda.png') + self.btest('cubegeom_normal_dap_far_glda.c', reference='cubegeom_normal_dap_far_glda.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_normal_dap_far_glda_quad(self): # with quad - self.btest('cubegeom_normal_dap_far_glda_quad.c', reference='cubegeom_normal_dap_far_glda_quad.png') + self.btest('cubegeom_normal_dap_far_glda_quad.c', reference='cubegeom_normal_dap_far_glda_quad.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_mt(self): - self.btest('cubegeom_mt.c', reference='cubegeom_mt.png') # multitexture + self.btest('cubegeom_mt.c', reference='cubegeom_mt.png', args=['-s', 'LEGACY_GL_EMULATION=1']) # multitexture def test_cubegeom_color2(self): - self.btest('cubegeom_color2.c', reference='cubegeom_color2.png') + self.btest('cubegeom_color2.c', reference='cubegeom_color2.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_texturematrix(self): - self.btest('cubegeom_texturematrix.c', reference='cubegeom_texturematrix.png') + self.btest('cubegeom_texturematrix.c', reference='cubegeom_texturematrix.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_fog(self): - self.btest('cubegeom_fog.c', reference='cubegeom_fog.png') + self.btest('cubegeom_fog.c', reference='cubegeom_fog.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_pre_vao(self): - self.btest('cubegeom_pre_vao.c', reference='cubegeom_pre_vao.png') + self.btest('cubegeom_pre_vao.c', reference='cubegeom_pre_vao.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_pre2_vao(self): - self.btest('cubegeom_pre2_vao.c', reference='cubegeom_pre_vao.png') + self.btest('cubegeom_pre2_vao.c', reference='cubegeom_pre_vao.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_pre2_vao2(self): - self.btest('cubegeom_pre2_vao2.c', reference='cubegeom_pre2_vao2.png') + self.btest('cubegeom_pre2_vao2.c', reference='cubegeom_pre2_vao2.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cube_explosion(self): - self.btest('cube_explosion.c', reference='cube_explosion.png') + self.btest('cube_explosion.c', reference='cube_explosion.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_sdl_canvas_blank(self): self.btest('sdl_canvas_blank.c', reference='sdl_canvas_blank.png') @@ -1298,11 +1299,11 @@ Press any key to continue.''' def test_glbegin_points(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) - self.btest('glbegin_points.c', reference='glbegin_points.png', args=['--preload-file', 'screenshot.png']) + self.btest('glbegin_points.c', reference='glbegin_points.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1']) def test_s3tc(self): shutil.copyfile(path_from_root('tests', 'screenshot.dds'), os.path.join(self.get_dir(), 'screenshot.dds')) - self.btest('s3tc.c', reference='s3tc.png', args=['--preload-file', 'screenshot.dds']) + self.btest('s3tc.c', reference='s3tc.png', args=['--preload-file', 'screenshot.dds', '-s', 'LEGACY_GL_EMULATION=1']) def test_s3tc_crunch(self): shutil.copyfile(path_from_root('tests', 'ship.dds'), 'ship.dds') @@ -1313,7 +1314,7 @@ Press any key to continue.''' shutil.move('ship.dds', 'ship.donotfindme.dds') # make sure we load from the compressed shutil.move('bloom.dds', 'bloom.donotfindme.dds') # make sure we load from the compressed shutil.move('water.dds', 'water.donotfindme.dds') # make sure we load from the compressed - self.btest('s3tc_crunch.c', reference='s3tc_crunch.png', reference_slack=11, args=['--pre-js', 'pre.js']) + self.btest('s3tc_crunch.c', reference='s3tc_crunch.png', reference_slack=11, args=['--pre-js', 'pre.js', '-s', 'LEGACY_GL_EMULATION=1']) def test_s3tc_crunch_split(self): # load several datafiles/outputs of file packager shutil.copyfile(path_from_root('tests', 'ship.dds'), 'ship.dds') @@ -1324,14 +1325,20 @@ Press any key to continue.''' shutil.move('ship.dds', 'ship.donotfindme.dds') # make sure we load from the compressed shutil.move('bloom.dds', 'bloom.donotfindme.dds') # make sure we load from the compressed shutil.move('water.dds', 'water.donotfindme.dds') # make sure we load from the compressed - self.btest('s3tc_crunch.c', reference='s3tc_crunch.png', reference_slack=11, args=['--pre-js', 'asset_a.js', '--pre-js', 'asset_b.js']) + self.btest('s3tc_crunch.c', reference='s3tc_crunch.png', reference_slack=11, args=['--pre-js', 'asset_a.js', '--pre-js', 'asset_b.js', '-s', 'LEGACY_GL_EMULATION=1']) def test_aniso(self): + if SPIDERMONKEY_ENGINE in JS_ENGINES: + # asm.js-ification check + Popen([PYTHON, EMCC, path_from_root('tests', 'aniso.c'), '-O2', '-g2', '-s', 'LEGACY_GL_EMULATION=1']).communicate() + Settings.ASM_JS = 1 + self.run_generated_code(SPIDERMONKEY_ENGINE, 'a.out.js') + shutil.copyfile(path_from_root('tests', 'water.dds'), 'water.dds') - self.btest('aniso.c', reference='aniso.png', reference_slack=2, args=['--preload-file', 'water.dds']) + self.btest('aniso.c', reference='aniso.png', reference_slack=2, args=['--preload-file', 'water.dds', '-s', 'LEGACY_GL_EMULATION=1']) def test_tex_nonbyte(self): - self.btest('tex_nonbyte.c', reference='tex_nonbyte.png') + self.btest('tex_nonbyte.c', reference='tex_nonbyte.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_float_tex(self): self.btest('float_tex.cpp', reference='float_tex.png') @@ -1340,7 +1347,7 @@ Press any key to continue.''' self.btest('gl_subdata.cpp', reference='float_tex.png') def test_perspective(self): - self.btest('perspective.c', reference='perspective.png') + self.btest('perspective.c', reference='perspective.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_runtimelink(self): return self.skip('shared libs are deprecated') diff --git a/tests/test_core.py b/tests/test_core.py index 31db6ca5..88f6674a 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -9582,15 +9582,15 @@ def process(filename): self.assertIdentical(clean(no_maps_file), clean(out_file)) map_filename = out_filename + '.map' data = json.load(open(map_filename, 'r')) - self.assertIdentical(out_filename, data['file']) - self.assertIdentical(src_filename, data['sources'][0]) - self.assertIdentical(src, data['sourcesContent'][0]) + self.assertPathsIdentical(out_filename, data['file']) + self.assertPathsIdentical(src_filename, data['sources'][0]) + self.assertTextDataIdentical(src, data['sourcesContent'][0]) mappings = json.loads(jsrun.run_js( path_from_root('tools', 'source-maps', 'sourcemap2json.js'), tools.shared.NODE_JS, [map_filename])) seen_lines = set() for m in mappings: - self.assertIdentical(src_filename, m['source']) + self.assertPathsIdentical(src_filename, m['source']) seen_lines.add(m['originalLine']) # ensure that all the 'meaningful' lines in the original code get mapped assert seen_lines.issuperset([6, 7, 11, 12]) diff --git a/tests/test_sockets.py b/tests/test_sockets.py index 03593674..4f6ee2a9 100644 --- a/tests/test_sockets.py +++ b/tests/test_sockets.py @@ -198,3 +198,71 @@ class sockets(BrowserCore): # ]: # with harness: # self.btest(os.path.join('sockets', 'test_enet_client.c'), expected='0', args=['-DSOCKK=9011'] + enet) + + def test_webrtc(self): + host_src = 'webrtc_host.c' + peer_src = 'webrtc_peer.c' + + host_outfile = 'host.html' + peer_outfile = 'peer.html' + + host_filepath = path_from_root('tests', 'sockets', host_src) + temp_host_filepath = os.path.join(self.get_dir(), os.path.basename(host_src)) + with open(host_filepath) as f: host_src = f.read() + with open(temp_host_filepath, 'w') as f: f.write(self.with_report_result(host_src)) + + peer_filepath = path_from_root('tests', 'sockets', peer_src) + temp_peer_filepath = os.path.join(self.get_dir(), os.path.basename(peer_src)) + with open(peer_filepath) as f: peer_src = f.read() + with open(temp_peer_filepath, 'w') as f: f.write(self.with_report_result(peer_src)) + + open(os.path.join(self.get_dir(), 'host_pre.js'), 'w').write(''' + var Module = { + webrtc: { + broker: 'https://mdsw.ch:8080', + session: undefined, + onpeer: function(peer, route) { + window.open('http://localhost:8888/peer.html?' + route); + // iframe = document.createElement("IFRAME"); + // iframe.setAttribute("src", "http://localhost:8888/peer.html?" + route); + // iframe.style.display = "none"; + // document.body.appendChild(iframe); + peer.listen(); + }, + onconnect: function(peer) { + }, + ondisconnect: function(peer) { + }, + onerror: function(error) { + console.error(error); + } + }, + }; + ''') + + open(os.path.join(self.get_dir(), 'peer_pre.js'), 'w').write(''' + var Module = { + webrtc: { + broker: 'https://mdsw.ch:8080', + session: window.location.toString().split('?')[1], + onpeer: function(peer, route) { + peer.connect(Module['webrtc']['session']); + }, + onconnect: function(peer) { + }, + ondisconnect: function(peer) { + // Calling window.close() from this handler hangs my browser, so run it in the next turn + setTimeout(window.close, 0); + }, + onerror: function(error) { + console.error(error); + } + } + }; + ''') + + Popen([PYTHON, EMCC, temp_host_filepath, '-o', host_outfile] + ['-s', 'GL_TESTING=1', '--pre-js', 'host_pre.js', '-s', 'SOCKET_WEBRTC=1', '-s', 'SOCKET_DEBUG=1']).communicate() + Popen([PYTHON, EMCC, temp_peer_filepath, '-o', peer_outfile] + ['-s', 'GL_TESTING=1', '--pre-js', 'peer_pre.js', '-s', 'SOCKET_WEBRTC=1', '-s', 'SOCKET_DEBUG=1']).communicate() + + expected = '1' + self.run_browser(host_outfile, '.', ['/report_result?' + e for e in expected])
\ No newline at end of file diff --git a/tools/find_bigfuncs.py b/tools/find_bigfuncs.py index 6fdec3a9..79136343 100644 --- a/tools/find_bigfuncs.py +++ b/tools/find_bigfuncs.py @@ -1,5 +1,5 @@ ''' -Simple tool to find big functions in an .ll file. +Simple tool to find big functions in a js or ll file ''' import os, sys, re @@ -11,7 +11,7 @@ curr = None data = [] for line in open(filename): i += 1 - if line.startswith('function '): + if line.startswith(('function ', 'define ')): start = i curr = line elif line.startswith('}') and curr: diff --git a/tools/response_file.py b/tools/response_file.py index 312cda73..f19cf8af 100644 --- a/tools/response_file.py +++ b/tools/response_file.py @@ -6,8 +6,8 @@ def create_response_file(args, directory): (response_fd, response_filename) = tempfile.mkstemp(prefix='emscripten_', suffix='.rsp', dir=directory, text=True) response_fd = os.fdopen(response_fd, "w") #print >> sys.stderr, "Creating response file '%s'" % response_filename - args = map(lambda p: p.replace(' ', '').replace('\\', '\\\\').replace('"', '\\"'), args) - response_fd.write(' '.join(args)) + args = map(lambda p: p.replace('\\', '\\\\').replace('"', '\\"'), args) + response_fd.write('"' + '" "'.join(args) + '"') response_fd.close() return response_filename diff --git a/tools/shared.py b/tools/shared.py index 917f548e..0d0f20d4 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -550,6 +550,7 @@ if USE_EMSDK: # allows projects to override them) EMSDK_OPTS = ['-nostdinc', '-Xclang', '-nobuiltininc', '-Xclang', '-nostdsysteminc', '-Xclang', '-isystem' + path_from_root('system', 'local', 'include'), + '-Xclang', '-isystem' + path_from_root('system', 'include', 'compat'), '-Xclang', '-isystem' + path_from_root('system', 'include', 'libcxx'), '-Xclang', '-isystem' + path_from_root('system', 'include'), '-Xclang', '-isystem' + path_from_root('system', 'include', 'emscripten'), diff --git a/tools/source-maps/sourcemapper.js b/tools/source-maps/sourcemapper.js index fa908900..06c9a227 100755 --- a/tools/source-maps/sourcemapper.js +++ b/tools/source-maps/sourcemapper.js @@ -16,6 +16,38 @@ function countLines(s) { return count; } +// For a minor optimization, only do win32->unix normalization if we are actually on Windows, +// which avoids redundantly scanning files if not needed. +var isWindows = (process.platform === 'win32'); + +var unixPathRe = new RegExp('\\\\', 'g'); +// Returns the given (possibly Windows) path p normalized to unix path separators '/'. +function toUnixPath(p) { + if (isWindows) { + return p.replace(unixPathRe, '/'); + } else { + return p; + } +} + +var unixLineEndRe = new RegExp('\r\n', 'g'); +// Returns the given (possibly Windows) text data t normalized to unix line endings '\n'. +function toUnixLineEnding(t) { + if (isWindows) { + return t.replace(unixLineEndRe, '\n'); + } else { + return t; + } +} + +// If path "p2" is a relative path, joins paths p1 and p2 to form "p1/p2". If p2 is an absolute path, "p2" is returned. +function joinPath(p1, p2) { + if (p2[0] == '/' || (p2.length >= 3 && p2[1] == ':' && (p2[2] == '/' || p2[2] == '\\'))) // Is p2 an absolute path? + return p2; + else + return toUnixPath(path.join(p1, p2)); +} + /* * Extracts the line (not block) comments from the generated function code and * invokes commentHandler with (comment content, line number of comment). This @@ -105,8 +137,7 @@ function generateMap(mappings, sourceRoot, mapFileBaseName, generatedLineOffset) // avoid doing it unnecessarily if (!(originalFileName in seenFiles)) { seenFiles[originalFileName] = true; - var rootedPath = originalFileName[0] === path.sep ? - originalFileName : path.join(sourceRoot, originalFileName); + var rootedPath = joinPath(sourceRoot, originalFileName); try { generator.setSourceContent(originalFileName, fs.readFileSync(rootedPath, 'utf-8')); } catch (e) { @@ -144,15 +175,15 @@ if (require.main === module) { } else { var opts = parseArgs(process.argv.slice(2)); var fileName = opts._[0]; - var sourceRoot = opts.sourceRoot ? opts.sourceRoot : "."; - var mapFileBaseName = opts.mapFileBaseName ? opts.mapFileBaseName : fileName; + var sourceRoot = opts.sourceRoot ? toUnixPath(opts.sourceRoot) : "."; + var mapFileBaseName = toUnixPath(opts.mapFileBaseName ? opts.mapFileBaseName : fileName); var generatedLineOffset = opts.offset ? parseInt(opts.offset, 10) : 0; - var generatedSource = fs.readFileSync(fileName, 'utf-8'); + var generatedSource = toUnixLineEnding(fs.readFileSync(fileName, 'utf-8')); var source = generatedSource; var mappings = getMappings(generatedSource); for (var i = 1, l = opts._.length; i < l; i ++) { - var optimizedSource = fs.readFileSync(opts._[i], 'utf-8') + var optimizedSource = toUnixLineEnding(fs.readFileSync(opts._[i], 'utf-8')) var optimizedMappings = getMappings(optimizedSource); var newMappings = {}; // uglify processes the code between EMSCRIPTEN_START_FUNCS and |