Commit f635a7a9 authored by Mehdi Sabwat's avatar Mehdi Sabwat
Browse files

update vlc patches.

parent a4c7a653
......@@ -72,8 +72,9 @@ diagnostic "Patching"
cd vlc
# patching vlc
if [ -d ../patch_vlc ] && [ "$(ls -A ../patch_vlc)" ]; then
git am -3 ../patch_vlc/*
if [ -d ../vlc_patches ] && [ "$(ls -A ../vlc_patches)" ]; then
git am -3 ../vlc_patches/00*
git am -3 ../vlc_patches/openal/*
fi
# BOOTSTRAP
......
From cdb3730114d038e4d2ba09e6812413474410da11 Mon Sep 17 00:00:00 2001
From: Etienne Brateau <etienne.brateau@gmail.com>
Date: Fri, 25 Aug 2017 10:24:40 +0200
Subject: [PATCH] Set _CLOCK_POSIX_SELECTION to 0 because clock_nanosleep is
not defined.
---
system/include/libc/unistd.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/system/include/libc/unistd.h b/system/include/libc/unistd.h
index c7cafaafb..2571fd594 100644
--- a/system/include/libc/unistd.h
+++ b/system/include/libc/unistd.h
@@ -239,7 +239,7 @@ int eaccess(const char *, int);
#define _POSIX_TIMEOUTS _POSIX_VERSION
#define _POSIX_MONOTONIC_CLOCK _POSIX_VERSION
#define _POSIX_CPUTIME _POSIX_VERSION
-#define _POSIX_CLOCK_SELECTION _POSIX_VERSION
+#define _POSIX_CLOCK_SELECTION 0
#define _POSIX_BARRIERS _POSIX_VERSION
#define _POSIX_SPIN_LOCKS _POSIX_VERSION
#define _POSIX_READER_WRITER_LOCKS _POSIX_VERSION
--
2.14.1
From 46b90cec6ca808fc074c1b79555029f473982b72 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= <jujjyl@gmail.com>
Date: Sat, 26 Aug 2017 15:13:56 +0300
Subject: [PATCH 02/23] Implement a model for synchronously or asynchronously
proxying JS function calls to main browser thread.
---
src/jsifier.js | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 109 insertions(+), 2 deletions(-)
diff --git a/src/jsifier.js b/src/jsifier.js
index 1e4f1191e..40d42e30f 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -16,6 +16,15 @@ var INDENTATION = ' ';
var functionStubSigs = {};
+// Some JS-implemented library functions are proxied to be called on the main browser thread, if the Emscripten runtime is executing in a Web Worker.
+// Each such proxied function is identified via an ordinal number (this is not the same namespace as function pointers in general).
+var proxiedFunctionTable = ["null" /* Reserve index 0 for an undefined function*/];
+
+// proxiedFunctionInvokers contains bodies of the functions that will perform the proxying. These
+// are generated in a map to keep track which ones have already been emitted, to avoid outputting duplicates.
+// map: pair(sig, syncOrAsync) -> function body
+var proxiedFunctionInvokers = {};
+
// JSifier
function JSify(data, functionsOnly) {
//B.start('jsifier');
@@ -100,6 +109,68 @@ function JSify(data, functionsOnly) {
return snippet;
}
+ // Generates a function that invokes a proxied function call from the calling thread to the main browser thread.
+ function generateProxiedCallInvoker(sig, sync /*async if false*/) {
+ if (sig.length == 0) throw 'Function signature cannot be empty!';
+ function argsList(num) { // ", p0, p1, p2, p3, p4"
+ var s = '';
+ for(var i = 0; i < num; ++i) s += ', p' + i;
+ return s;
+ }
+
+ var func = "function _emscripten_" + (sync ? '' : 'a') + 'sync_run_in_browser_thread_' + sig + '(func' + argsList(sig.length-1) + ') {\n';
+ if (sync) func += ' var waitAddress = Runtime.stackSave();\n';
+
+ function sizeofType(t) {
+ switch(t) {
+ case 'd':
+// case 'I': // int64 // TODO: For wasm, we'll have to have something like this
+// return 8;
+ case 'i':
+ case 'f':
+ return 4;
+ case 'v':
+ return 0;
+ // TODO: Smaller sizes?
+ default:
+ throw 'unsupported type in signature: ' + t;
+ }
+ }
+
+ var sizeofReturn = sizeofType(sig[0]);
+ if (sync) {
+ if (sizeofReturn == 4) func += ' var returnValue = waitAddress + 4;\n';
+ else if (sizeofReturn == 8) func += ' var returnValue = waitAddress + 8;\n'; // Retain alignment of each type
+ }
+
+ if (sync) func += ' Atomics.store(HEAP32, waitAddress >> 2, 0);\n';
+
+ function argsDict(num) { // ", p0: p0, p1: p1, p2: p2, p3: p3, p4: p4"
+ var s = '';
+ for(var i = 0; i < num; ++i) s += ', p' + i + ': p' + i;
+ return s;
+ }
+
+ // This is ad-hoc numbering scheme to map signatures to IDs, and must agree with call handler in src/library_pthread.js.
+ // Once proxied function calls no longer go through postMessage()s but instead in the heap, this will need to change, since int vs float will matter.
+ var functionCallOrdinal = sig.length + (sizeofReturn == 8 ? 20 : 0);
+
+ // next line generates a form: "postMessage({ proxiedCall: 9, func: func, waitAddress: waitAddress, returnValue: returnValue, p0: p0, p1: p1, p2: p2, p3: p3, p4: p4, p5: p5, p6: p6, p7: p7 });"
+ func += ' postMessage({ proxiedCall: ' + functionCallOrdinal + ', func: func' + (sync ? ', waitAddress: waitAddress' : '') + (sync && sizeofReturn > 0 ? ', returnValue: returnValue' : '') + argsDict(sig.length-1) + ' });\n';
+ if (sync) {
+ func += ' Atomics.wait(HEAP32, waitAddress >> 2, 0);\n';
+ switch(sig[0]) {
+ case 'i': func += ' return HEAP32[returnValue >> 2];\n'; break;
+ case 'f': func += ' return HEAPF32[returnValue >> 2];\n'; break;
+ case 'd': func += ' return HEAPF64[returnValue >> 3];\n'; break;
+ //case 'I': func += ' return HEAP64[returnValue >> 3];\n'; // TODO: For wasm
+ // TODO: Smaller sizes?
+ }
+ }
+ func += '}';
+ return func;
+ }
+
// functionStub
function functionStubHandler(item) {
// special logic
@@ -122,6 +193,11 @@ function JSify(data, functionsOnly) {
// dependencies can be JS functions, which we just run
if (typeof ident == 'function') return ident();
+ // don't process any special identifiers. These are looked up when processing the base name of the identifier.
+ if (ident.endsWith('__sig') || ident.endsWith('__proxy') || ident.endsWith('__asm') || ident.endsWith('__inline') || ident.endsWith('__deps') || ident.endsWith('__postset')) {
+ return '';
+ }
+
// $ident's are special, we do not prefix them with a '_'.
if (ident[0] === '$') {
var finalName = ident.substr(1);
@@ -225,7 +301,33 @@ function JSify(data, functionsOnly) {
var depsText = (deps ? '\n' + deps.map(addFromLibrary).filter(function(x) { return x != '' }).join('\n') : '');
var contentText;
if (isFunction) {
- contentText = snippet;
+ // Emit the body of a JS library function.
+ var proxyingMode = LibraryManager.library[ident + '__proxy'];
+ if (proxyingMode && proxyingMode !== 'main' && proxyingMode !== 'main_gl' && proxyingMode !== 'async' && proxyingMode !== 'async_gl') {
+ throw 'Invalid proxyingMode ' + ident + '__proxy: \'' + proxyingMode + '\' specified!';
+ }
+
+ if (USE_PTHREADS && proxyingMode) {
+ var sig = LibraryManager.library[ident + '__sig'];
+ if (!sig) throw 'Missing function signature field "' + ident + '__sig"! (Using proxying mode requires specifying the signature of the function)';
+ sig = sig.replace(/f/g, 'i'); // TODO: Implement float signatures.
+ var synchronousCall = (proxyingMode === 'main' || proxyingMode === 'main_gl');
+ var invokerKey = sig + (synchronousCall ? '_sync' : '_async');
+ if (!proxiedFunctionInvokers[invokerKey]) proxiedFunctionInvokers[invokerKey] = generateProxiedCallInvoker(sig, synchronousCall);
+ var proxyingCondition = (proxyingMode === 'main_gl' || proxyingMode === 'async_gl') ? 'GLctxIsOnParentThread' : 'ENVIRONMENT_IS_PTHREAD';
+ var proxyingFunc = synchronousCall ? '_emscripten_sync_run_in_browser_thread_' : '_emscripten_async_run_in_browser_thread_';
+ if (sig.length > 1) {
+ // If the function takes parameters, forward those to the proxied function call
+ snippet = snippet.replace(/function\s+(.*)?\s*\((.*?)\)\s*{/, 'function $1($2) {\nif (' + proxyingCondition + ') return ' + proxyingFunc + sig + '(' + proxiedFunctionTable.length + ', $2);');
+ } else {
+ // No parameters to the function
+ snippet = snippet.replace(/function (.*)? {/, 'function $1 {\nif (' + proxyingCondition + ') return ' + proxyingFunc + sig + '(' + proxiedFunctionTable.length + ');');
+ }
+ contentText = snippet;
+ proxiedFunctionTable.push(finalName);
+ } else {
+ contentText = snippet; // Regular JS function that will be executed in the context of the calling thread.
+ }
} else if (typeof snippet === 'string' && snippet.indexOf(';') == 0) {
contentText = 'var ' + finalName + snippet;
if (snippet[snippet.length-1] != ';' && snippet[snippet.length-1] != '}') contentText += ';';
@@ -402,7 +504,12 @@ function JSify(data, functionsOnly) {
legalizedI64s = legalizedI64sDefault;
if (!BUILD_AS_SHARED_LIB && !SIDE_MODULE) {
- if (USE_PTHREADS) print('if (!ENVIRONMENT_IS_PTHREAD) {\n // Only main thread initializes these, pthreads copy them over at thread worker init time (in pthread-main.js)');
+ if (USE_PTHREADS) {
+ print('\n // proxiedFunctionTable specifies the list of functions that can be called either synchronously or asynchronously from other threads in postMessage()d or internally queued events. This way a pthread in a Worker can synchronously access e.g. the DOM on the main thread.')
+ print('\nvar proxiedFunctionTable = [' + proxiedFunctionTable.join() + '];\n');
+ for(i in proxiedFunctionInvokers) print(proxiedFunctionInvokers[i]+'\n');
+ print('if (!ENVIRONMENT_IS_PTHREAD) {\n // Only main thread initializes these, pthreads copy them over at thread worker init time (in pthread-main.js)');
+ }
print('DYNAMICTOP_PTR = allocate(1, "i32", ALLOC_STATIC);\n');
print('STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);\n');
if (STACK_START > 0) print('if (STACKTOP < ' + STACK_START + ') STACK_BASE = STACKTOP = Runtime.alignMemory(' + STACK_START + ');\n');
--
2.14.1
From 5697581451fecb98b1ce965da77187a80b0c7b04 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= <jujjyl@gmail.com>
Date: Sat, 26 Aug 2017 20:42:00 +0300
Subject: [PATCH 03/23] Add test for synchronously proxying a call to main
thread and getting a value back.
---
src/library_pthread.js | 36 +++++++++++++++++++++++++++++++
tests/pthread/call_sync_on_main_thread.c | 30 ++++++++++++++++++++++++++
tests/pthread/call_sync_on_main_thread.js | 28 ++++++++++++++++++++++++
tests/test_browser.py | 8 ++++++-
4 files changed, 101 insertions(+), 1 deletion(-)
create mode 100644 tests/pthread/call_sync_on_main_thread.c
create mode 100644 tests/pthread/call_sync_on_main_thread.js
diff --git a/src/library_pthread.js b/src/library_pthread.js
index f438799b7..309717623 100644
--- a/src/library_pthread.js
+++ b/src/library_pthread.js
@@ -262,6 +262,42 @@ var LibraryPThread = {
var worker = new Worker(pthreadMainJs);
worker.onmessage = function(e) {
+ // TODO: Move the proxied call mechanism into a queue inside heap.
+ if (e.data.proxiedCall) {
+ var returnValue;
+ var funcTable = (e.data.func >= 0) ? proxiedFunctionTable : ASM_CONSTS;
+ var funcIdx = (e.data.func >= 0) ? e.data.func : (-1 - e.data.func);
+ PThread.currentProxiedOperationCallerThread = worker.pthread.threadInfoStruct; // Sometimes we need to backproxy events to the calling thread (e.g. HTML5 DOM events handlers such as emscripten_set_mousemove_callback()), so keep track in a globally accessible variable about the thread that initiated the proxying.
+ switch(e.data.proxiedCall) {
+ case 1: case 21: returnValue = funcTable[funcIdx](); break;
+ case 2: returnValue = funcTable[funcIdx](e.data.p0); break;
+ case 3: returnValue = funcTable[funcIdx](e.data.p0, e.data.p1); break;
+ case 4: returnValue = funcTable[funcIdx](e.data.p0, e.data.p1, e.data.p2); break;
+ case 5: returnValue = funcTable[funcIdx](e.data.p0, e.data.p1, e.data.p2, e.data.p3); break;
+ case 6: returnValue = funcTable[funcIdx](e.data.p0, e.data.p1, e.data.p2, e.data.p3, e.data.p4); break;
+ case 7: returnValue = funcTable[funcIdx](e.data.p0, e.data.p1, e.data.p2, e.data.p3, e.data.p4, e.data.p5); break;
+ case 8: returnValue = funcTable[funcIdx](e.data.p0, e.data.p1, e.data.p2, e.data.p3, e.data.p4, e.data.p5, e.data.p6); break;
+ case 9: returnValue = funcTable[funcIdx](e.data.p0, e.data.p1, e.data.p2, e.data.p3, e.data.p4, e.data.p5, e.data.p6, e.data.p7); break;
+ case 10: returnValue = funcTable[funcIdx](e.data.p0, e.data.p1, e.data.p2, e.data.p3, e.data.p4, e.data.p5, e.data.p6, e.data.p7, e.data.p8); break;
+ default:
+ if (e.data.proxiedCall) {
+ Module['printErr']("worker sent an unknown proxied call idx " + e.data.proxiedCall);
+ console.error(e.data);
+ }
+ break;
+ }
+ if (e.data.returnValue) {
+ if (e.data.proxiedCall != 21) HEAP32[e.data.returnValue >> 2] = returnValue;
+ else HEAPF64[e.data.returnValue >> 3] = returnValue;
+ }
+ var waitAddress = e.data.waitAddress;
+ if (waitAddress) {
+ Atomics.store(HEAP32, waitAddress >> 2, 1);
+ Atomics.wake(HEAP32, waitAddress >> 2, 1);
+ }
+ return;
+ }
+
// If this message is intended to a recipient that is not the main thread, forward it to the target thread.
if (e.data.targetThread && e.data.targetThread != _pthread_self()) {
var thread = PThread.pthreads[e.data.targetThread];
diff --git a/tests/pthread/call_sync_on_main_thread.c b/tests/pthread/call_sync_on_main_thread.c
new file mode 100644
index 000000000..2f4ca38aa
--- /dev/null
+++ b/tests/pthread/call_sync_on_main_thread.c
@@ -0,0 +1,30 @@
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+extern void getDomElementInnerHTML(const char *domElement, char *dst, int size);
+extern int isThisInWorker(void);
+extern int isThisInWorkerOnMainThread(void);
+extern int receivesAndReturnsAnInteger(int i);
+
+// Define this if compiling via -s PROXY_TO_PTHREAD=1
+// #define PROXY_TO_PTHREAD 1
+
+int main()
+{
+ char dst[256];
+ char name[7] = "resize";
+ getDomElementInnerHTML(name, dst, sizeof(dst));
+ memset(name, 0, sizeof(name)); // Try to uncover if there might be a race condition and above line was not synchronously processed, and we could take name string away.
+ int inWorker1 = isThisInWorker(); // Build this application with -s USE_PTHREADS=1 -s PROXY_TO_PTHREAD=1 for this to return 1, otherwise returns 0.
+ int inWorker2 = isThisInWorkerOnMainThread(); // This should always return 0
+ int returnedInt = receivesAndReturnsAnInteger(4);
+ printf("text: \"%s\". inWorker1: %d, inWorker2: %d, returnedInt: %d\n", dst, inWorker1, inWorker2, returnedInt);
+ assert(!strstr(dst, "Resize canvas"));
+ assert(inWorker1 == PROXY_TO_PTHREAD);
+ assert(inWorker2 == 0);
+ assert(returnedInt == 42 + 4);
+#ifdef REPORT_RESULT
+ REPORT_RESULT(1);
+#endif
+}
diff --git a/tests/pthread/call_sync_on_main_thread.js b/tests/pthread/call_sync_on_main_thread.js
new file mode 100644
index 000000000..3a9e57b44
--- /dev/null
+++ b/tests/pthread/call_sync_on_main_thread.js
@@ -0,0 +1,28 @@
+mergeInto(LibraryManager.library, {
+ // Test accessing a DOM element on the main thread.
+ // This function returns the inner text of the div by ID "status"
+ // Because it accesses the DOM, it must be called on the main thread.
+ getDomElementInnerHTML__proxy: 'main',
+ getDomElementInnerHTML__sig: 'viii',
+ getDomElementInnerHTML: function(domElementId, dst, size) {
+ var id = UTF8ToString(domElementId);
+ var text = document.getElementById(id).innerHTML;
+ stringToUTF8(text, dst, size);
+ },
+
+ receivesAndReturnsAnInteger__proxy: 'main',
+ receivesAndReturnsAnInteger__sig: 'ii',
+ receivesAndReturnsAnInteger: function(i) {
+ return i + 42;
+ },
+
+ isThisInWorker: function() {
+ return ENVIRONMENT_IS_WORKER;
+ },
+
+ isThisInWorkerOnMainThread__proxy: 'main',
+ isThisInWorkerOnMainThread__sig: 'i',
+ isThisInWorkerOnMainThread: function() {
+ return ENVIRONMENT_IS_WORKER;
+ }
+});
diff --git a/tests/test_browser.py b/tests/test_browser.py
index 033248405..0f21e7e64 100644
--- a/tests/test_browser.py
+++ b/tests/test_browser.py
@@ -3318,6 +3318,12 @@ window.close = function() {
def test_pthread_run_on_main_thread_flood(self):
self.btest(path_from_root('tests', 'pthread', 'test_pthread_run_on_main_thread_flood.cpp'), expected='0', args=['-O3', '-s', 'USE_PTHREADS=2', '-s', 'PTHREAD_POOL_SIZE=1', '--separate-asm'], timeout=30)
+ # Test that it is possible to synchronously call a JavaScript function on the main thread and get a return value back.
+ def test_pthread_call_sync_on_main_thread(self):
+ self.btest(path_from_root('tests', 'pthread', 'call_sync_on_main_thread.c'), expected='1', args=['-O3', '-s', 'USE_PTHREADS=1', '-s', 'PROXY_TO_PTHREAD=1', '-DPROXY_TO_PTHREAD=1', '--js-library', path_from_root('tests', 'pthread', 'call_sync_on_main_thread.js')])
+ self.btest(path_from_root('tests', 'pthread', 'call_sync_on_main_thread.c'), expected='1', args=['-O3', '-s', 'USE_PTHREADS=1', '-DPROXY_TO_PTHREAD=0', '--js-library', path_from_root('tests', 'pthread', 'call_sync_on_main_thread.js')])
+ self.btest(path_from_root('tests', 'pthread', 'call_sync_on_main_thread.c'), expected='1', args=['-Oz', '-DPROXY_TO_PTHREAD=0', '--js-library', path_from_root('tests', 'pthread', 'call_sync_on_main_thread.js')])
+
# test atomicrmw i64
def test_atomicrmw_i64(self):
Popen([PYTHON, EMCC, path_from_root('tests', 'atomicrmw_i64.ll'), '-s', 'USE_PTHREADS=1', '-s', 'IN_TEST_HARNESS=1', '-o', 'test.html']).communicate()
@@ -3623,4 +3629,4 @@ window.close = function() {
# Tests the Emscripten HTML5 API emscripten_set_canvas_element_size() and emscripten_get_canvas_element_size() functionality in singlethreaded programs.
def test_emscripten_set_canvas_element_size(self):
- self.btest('emscripten_set_canvas_element_size.c', expected='1')
\ No newline at end of file
+ self.btest('emscripten_set_canvas_element_size.c', expected='1')
--
2.14.1
From c90c09ce45d2dc4b1b0a6a714372a2d4731cd2f0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= <jujjyl@gmail.com>
Date: Sat, 26 Aug 2017 21:15:56 +0300
Subject: [PATCH 04/23] Add a test for asynchronously proxying calls from a
pthread to the main thread.
---
tests/pthread/call_async_on_main_thread.c | 10 ++++++++++
tests/pthread/call_async_on_main_thread.js | 12 ++++++++++++
tests/runner.py | 2 +-
tests/test_browser.py | 6 ++++++
4 files changed, 29 insertions(+), 1 deletion(-)
create mode 100644 tests/pthread/call_async_on_main_thread.c
create mode 100644 tests/pthread/call_async_on_main_thread.js
diff --git a/tests/pthread/call_async_on_main_thread.c b/tests/pthread/call_async_on_main_thread.c
new file mode 100644
index 000000000..b46f5f83c
--- /dev/null
+++ b/tests/pthread/call_async_on_main_thread.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+extern void report_result(int param1, int param2, int param3);
+
+int main()
+{
+ report_result(1, 2, 3);
+}
diff --git a/tests/pthread/call_async_on_main_thread.js b/tests/pthread/call_async_on_main_thread.js
new file mode 100644
index 000000000..f70198dc5
--- /dev/null
+++ b/tests/pthread/call_async_on_main_thread.js
@@ -0,0 +1,12 @@
+mergeInto(LibraryManager.library, {
+ // Test asynchronously calling a function on the main thread.
+ report_result__proxy: 'async',
+ report_result__sig: 'viii',
+ report_result: function(param1, param2, param3) {
+ if (ENVIRONMENT_IS_WORKER) {
+ console.error('This function should be getting called on the main thread!');
+ }
+ console.log('got ' + param1 + ' ' + param2 + ' ' + param3);
+ __ReportResult(param1 + param2 * param3, 0);
+ }
+});
diff --git a/tests/runner.py b/tests/runner.py
index 3054e5de2..05da71883 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -819,7 +819,7 @@ class BrowserCore(RunnerCore):
#define __REPORT_RESULT_DEFINED__
#include <emscripten.h>
- static void _ReportResult(int result, int sync)
+ static void EMSCRIPTEN_KEEPALIVE _ReportResult(int result, int sync)
{
EM_ASM({
var xhr = new XMLHttpRequest();
diff --git a/tests/test_browser.py b/tests/test_browser.py
index 0f21e7e64..b487e5480 100644
--- a/tests/test_browser.py
+++ b/tests/test_browser.py
@@ -3324,6 +3324,12 @@ window.close = function() {
self.btest(path_from_root('tests', 'pthread', 'call_sync_on_main_thread.c'), expected='1', args=['-O3', '-s', 'USE_PTHREADS=1', '-DPROXY_TO_PTHREAD=0', '--js-library', path_from_root('tests', 'pthread', 'call_sync_on_main_thread.js')])
self.btest(path_from_root('tests', 'pthread', 'call_sync_on_main_thread.c'), expected='1', args=['-Oz', '-DPROXY_TO_PTHREAD=0', '--js-library', path_from_root('tests', 'pthread', 'call_sync_on_main_thread.js')])
+ # Test that it is possible to asynchronously call a JavaScript function on the main thread.
+ def test_pthread_call_async_on_main_thread(self):
+ self.btest(path_from_root('tests', 'pthread', 'call_async_on_main_thread.c'), expected='7', args=['-O3', '-s', 'USE_PTHREADS=1', '-s', 'PROXY_TO_PTHREAD=1', '-DPROXY_TO_PTHREAD=1', '--js-library', path_from_root('tests', 'pthread', 'call_async_on_main_thread.js')])
+ self.btest(path_from_root('tests', 'pthread', 'call_async_on_main_thread.c'), expected='7', args=['-O3', '-s', 'USE_PTHREADS=1', '-DPROXY_TO_PTHREAD=0', '--js-library', path_from_root('tests', 'pthread', 'call_async_on_main_thread.js')])
+ self.btest(path_from_root('tests', 'pthread', 'call_async_on_main_thread.c'), expected='7', args=['-Oz', '-DPROXY_TO_PTHREAD=0', '--js-library', path_from_root('tests', 'pthread', 'call_async_on_main_thread.js')])
+
# test atomicrmw i64
def test_atomicrmw_i64(self):
Popen([PYTHON, EMCC, path_from_root('tests', 'atomicrmw_i64.ll'), '-s', 'USE_PTHREADS=1', '-s', 'IN_TEST_HARNESS=1', '-o', 'test.html']).communicate()
--
2.14.1
From 5581631cc23d5e91035e269a1514598c2235f29a Mon Sep 17 00:00:00 2001
From: Jameson Ernst <jameson@jpernst.com>
Date: Fri, 7 Jul 2017 11:21:55 -0700
Subject: [PATCH 06/23] Add -Os flag to al.c
---
tools/system_libs.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/system_libs.py b/tools/system_libs.py
index 65ff8f8d0..99bbbbdbd 100755
--- a/tools/system_libs.py
+++ b/tools/system_libs.py
@@ -257,7 +257,7 @@ def calculate(temp_files, in_temp, stdout_, stderr_, forced=[]):
# al
def create_al(libname): # libname is ignored, this is just one .o file
o = in_temp('al.o')
- check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'al.c'), '-o', o])
+ check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'al.c'), '-o', o, '-Os'])
return o
def create_html5(libname):
--
2.14.1
From 5b6004917512f7de3548702e02c4753fb5a638f2 Mon Sep 17 00:00:00 2001
From: Jameson Ernst <jameson@jpernst.com>
Date: Fri, 7 Jul 2017 11:49:02 -0700
Subject: [PATCH 07/23] Minor fix to AL panner initialization when source has
leading zero-buffers
---
src/library_openal.js | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/library_openal.js b/src/library_openal.js
index c6e326fcc..7f65f6d67 100644
--- a/src/library_openal.js
+++ b/src/library_openal.js
@@ -376,8 +376,16 @@ var LibraryOpenAL = {
return;
}
+ // Find the first non-zero buffer in the queue to determine the proper format
+ var templateBuf = AL.buffers[0];
+ for (var i = 0; i < src.bufQueue.length; i++) {
+ if (src.bufQueue[i].id !== 0) {
+ templateBuf = src.bufQueue[i];
+ break;
+ }
+ }
// Create a panner if AL_SOURCE_SPATIALIZE_SOFT is set to true, or alternatively if it's set to auto and the source is mono
- if (src.spatialize === 1 /* AL_TRUE */ || (src.spatialize === 2 /* AL_AUTO_SOFT */ && src.bufQueue[0].channels === 1)) {
+ if (src.spatialize === 1 /* AL_TRUE */ || (src.spatialize === 2 /* AL_AUTO_SOFT */ && templateBuf.channels === 1)) {
if (src.panner) {
return;
}
--
2.14.1
From 45b70ef08c5a7ea75cc0c7e1869aa6aae3b09c15 Mon Sep 17 00:00:00 2001
From: yoanlcq <yoanlecoq.io@gmail.com>
Date: Mon, 10 Jul 2017 19:45:26 +0200
Subject: [PATCH 08/23] Change docs w.r.t juj's review
---
site/source/docs/porting/Audio.rst | 46 ++++++++++++--------------------------
1 file changed, 14 insertions(+), 32 deletions(-)
diff --git a/site/source/docs/porting/Audio.rst b/site/source/docs/porting/Audio.rst
index 43b55b8d7..241559efb 100644
--- a/site/source/docs/porting/Audio.rst
+++ b/site/source/docs/porting/Audio.rst
@@ -4,10 +4,13 @@
Audio
=====
-Emscripten supports OpenAL 1.1 "out of the box", with no additional compilation flag required. The implementation uses the Web Audio API.
+Emscripten ships with its own implementation of the OpenAL 1.1 API, using the Web Audio API as a backend.
-You can reasonably expect ported OpenAL applications to "just work" with no additional effort.
-However, there are some implementation-specific aspects which are worth considering - these are documented here.
+You can reasonably expect ported OpenAL applications to "just work" with no additional effort. Just link with the ``-lopenal`` linker flag.
+
+There are some implementation-specific aspects which are worth considering and are documented here.
+
+.. warning:: There used to be no additional flag to pass to the compiler in order to use OpenAL. However, specifying ``-lopenal`` as mentioned above should be considered mandatory (at some point in the future, it **will** be)!
.. _Audio-openal-extensions-g:
@@ -33,32 +36,21 @@ The following extensions are supported by Emscripten's OpenAL implementation.
Guidelines for Audio on Emscripten
==================================
-First: Do not loop on OpenAL calls.
+Know that your application needs to yield to the Javascript main loop for audio processing to take place (See :ref:`Browser main loop <emscripten-runtime-environment-main-loop>`).
-Put simply, avoid completely this kind of code :
+Put simply, this kind of code will block indefinitely :
.. code-block:: c
while(nframes < THE_NUMBER_OF_FRAMES_WE_WANT)
alcGetIntegerv(device, ALC_CAPTURE_SAMPLES, 1, &nframes);
+The above snippet usually works in native applications because most OpenAL implementations own and manage one or more separate threads. This is **not** the case in Emscripten.
-The reason for this is simple: Your application needs to yield to the Javascript main loop for audio processing to take place (See :ref:`Browser main loop <emscripten-runtime-environment-main-loop>`).
-
-The above snippet usually works because most OpenAL implementations own and manage one or more separate threads. This is not the case in Emscripten.
What you must do instead is perform each such query only once per "main loop iteration" (i.e the callback you provide via :c:func:`emscripten_set_main_loop` or :c:func:`emscripten_set_main_loop_arg`).
-Second: Avoid creating and destroying resources relentlessly.
-
-On some browsers (except, apparently, Firefox), garbage collection does not occur as much as it should. Knowing this, your app should ideally at most use one ``ALCcontext`` for playback and one ``ALCdevice`` for capture.
-
-Even if you're planning to suspend audio capture or playback for extended periods of time, it is probably better to keep contexts in memory (unlike in native apps where you should rather destroy them) to avoid risking memory leaks caused by poorly garbage-collected Javascript implementations.
-
-Of course, the current OpenAL implementation strives to be memory-efficient, but it has no control over lower-level mechanisms involved.
-
-
.. _Audio-openal-capture-behavior-g:
Emscripten-specific capture behavior
@@ -66,11 +58,8 @@ Emscripten-specific capture behavior
Attempting to open an input stream to the user's audio capture device
results in the asynchronous appearance of a small browser-specific dialog
-asking for the user's permission.
+asking for the user's permission, and on some browsers, the capture device to choose.
-.. note::
- On Firefox, the user is also given the opportunity to pick from a list of devices at that moment.
- On other browsers, this is normally a simple "Allow/Deny" button pair on a toast.
With this in mind, when ``alcCaptureOpenDevice()`` is called with valid and
supported parameters, a "proxy" device is returned, which successfully
@@ -81,7 +70,7 @@ That means, when calling ``alcGetIntegerv(device, ALC_CAPTURE_SAMPLES, 1, &nfram
If the user clicks "Deny", the device is invalidated (because this is somewhat