wasm: enable event dispatcher asyncify support

Misc. fixes, including:

Fix a couple of typos in the JavaScript code. Also, macros-
within-macros don’t work, (without resorting to preprocessor
token pasting), so remove the debug output for now.

Limit the exec() “simulateInfiniteLoop” workaround to
top-level application exec() only. This way, asyncify
can be used for nested QEventLoop::exec() calls. (Emscripten
supports one level of suspend only, so we don’t want
to use that for the top-level exec(), but instead use it
for dialogs and such).

Use the new QEventLoop::ProcessEventsFlag::ApplicationExec
enum value to detect the exec() call type.

Change-Id: Ic702bfc31faf2e9f84ac5d3ccf43d067c5c61bf0
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
This commit is contained in:
Morten Johan Sørvig 2021-09-17 11:40:14 +02:00
parent 63feecfc11
commit 6d039a5e76
3 changed files with 10 additions and 24 deletions

View File

@ -104,7 +104,7 @@ function (qt_internal_setup_wasm_target_properties wasmTarget)
set(QT_CFLAGS_OPTIMIZE_DEBUG "-Os" CACHE STRING INTERNAL FORCE)
set(QT_FEATURE_optimize_debug ON CACHE BOOL INTERNAL FORCE)
target_link_options("${wasmTarget}" INTERFACE "SHELL:-s ASYNCIFY" "-Os")
target_link_options("${wasmTarget}" INTERFACE "SHELL:-s ASYNCIFY" "-Os" "-s" "ASYNCIFY_IMPORTS=[qt_asyncify_suspend_js, qt_asyncify_resume_js]")
target_compile_definitions("${wasmTarget}" INTERFACE QT_HAVE_EMSCRIPTEN_ASYNCIFY)
endif()
endfunction()

View File

@ -56,13 +56,6 @@ Q_LOGGING_CATEGORY(lcEventDispatcherTimers, "qt.eventdispatcher.timers");
#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY
// Enable/disable JavaScript-side debugging
#if 0
#define QT_ASYNCIFY_DEBUG(X) out(X)
#else
#define QT_ASYNCIFY_DEBUG(X)
#endif
// Emscripten asyncify currently supports one level of suspend -
// recursion is not permitted. We track the suspend state here
// on order to fail (more) gracefully, but we can of course only
@ -70,28 +63,21 @@ Q_LOGGING_CATEGORY(lcEventDispatcherTimers, "qt.eventdispatcher.timers");
static bool g_is_asyncify_suspended = false;
EM_JS(void, qt_asyncify_suspend_js, (), {
QT_ASYNCIFY_DEBUG("qt_asyncify_suspend_js");
let sleepFn = (wakeUp) = >
{
QT_ASYNCIFY_DEBUG("setting Module.qtAsyncifyWakeUp")
Module.qtAsyncifyWakeUp = wakeUp; // ### not "Module" any more
let sleepFn = (wakeUp) => {
Module.qtAsyncifyWakeUp = wakeUp;
};
return Asyncify.handleSleep(sleepFn);
});
EM_JS(void, qt_asyncify_resume_js, (), {
QT_ASYNCIFY_DEBUG("qt_asyncify_resume_js");
let wakeUp = Module.qtAsyncifyWakeUp;
if (wakeUp == = undefined) {
QT_ASYNCIFY_DEBUG("qt_asyncify_resume_js no wakeup fn set - did not wake");
if (wakeUp == undefined)
return;
}
Module.qtAsyncifyWakeUp = undefined;
// Delayed wakeup with zero-timer. Workaround/fix for
// https://github.com/emscripten-core/emscripten/issues/10515
setTimeout(wakeUp);
QT_ASYNCIFY_DEBUG("qt_asyncify_resume_js done");
});
// Suspends the main thread until qt_asyncify_resume() is called. Returns
@ -209,8 +195,8 @@ bool QEventDispatcherWasm::processEvents(QEventLoop::ProcessEventsFlags flags)
if (isMainThreadEventDispatcher()) {
if (flags & QEventLoop::DialogExec)
handleDialogExec();
else if (flags & QEventLoop::EventLoopExec)
handleEventLoopExec();
else if (flags & QEventLoop::ApplicationExec)
handleApplicationExec();
}
if (!(flags & QEventLoop::ExcludeUserInputEvents))
@ -368,7 +354,7 @@ void QEventDispatcherWasm::wakeUp()
emscripten_async_call(&QEventDispatcherWasm::callProcessEvents, this, 0);
}
void QEventDispatcherWasm::handleEventLoopExec()
void QEventDispatcherWasm::handleApplicationExec()
{
// Start the main loop, and then stop it on the first callback. This
// is done for the "simulateInfiniteLoop" functionality where
@ -386,7 +372,7 @@ void QEventDispatcherWasm::handleEventLoopExec()
void QEventDispatcherWasm::handleDialogExec()
{
#if !QT_HAVE_EMSCRIPTEN_ASYNCIFY
#ifndef QT_HAVE_EMSCRIPTEN_ASYNCIFY
qWarning() << "Warning: dialog exec() is not supported on Qt for WebAssembly in this"
<< "configuration. Please use show() instead, or enable experimental support"
<< "for asyncify.\n"
@ -432,7 +418,7 @@ bool QEventDispatcherWasm::waitForForEvents()
Q_ASSERT(emscripten_is_main_runtime_thread());
#if QT_HAVE_EMSCRIPTEN_ASYNCIFY
#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY
// We can block on the main thread using asyncify:
bool didSuspend = qt_asyncify_suspend();
if (!didSuspend)

View File

@ -90,7 +90,7 @@ private:
bool isMainThreadEventDispatcher();
bool isSecondaryThreadEventDispatcher();
void handleEventLoopExec();
void handleApplicationExec();
void handleDialogExec();
void pollForNativeEvents();
bool waitForForEvents();