Adapt WASM event dispatcher to use JSPI, if available
Detect if JSPI is available and suspend the execution of the program if so, instead of using 'bare' asyncify. For now: 1) This works only with emscripten 3.1.36 with mboc-qt patches from emscripten repo 2) Apps have to specify the following linker options: -sDYNCALLS=1 -sASYNCIFY=2 -sASYNCIFY_EXPORTS=dynCall_* Fixes: QTBUG-113570 Change-Id: Ide7c51e36990df7e20c6c9b5a218366cb0db100e Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
This commit is contained in:
parent
97f68cd306
commit
05c3342b43
@ -42,6 +42,47 @@ static bool useAsyncify()
|
||||
return qstdweb::haveAsyncify();
|
||||
}
|
||||
|
||||
static bool useJspi()
|
||||
{
|
||||
return qstdweb::haveJspi();
|
||||
}
|
||||
|
||||
EM_ASYNC_JS(void, qt_jspi_suspend_js, (), {
|
||||
++Module.qtJspiSuspensionCounter;
|
||||
|
||||
await new Promise(resolve => {
|
||||
Module.qtAsyncifyWakeUp.push(resolve);
|
||||
});
|
||||
});
|
||||
|
||||
EM_JS(bool, qt_jspi_resume_js, (), {
|
||||
if (!Module.qtJspiSuspensionCounter)
|
||||
return false;
|
||||
|
||||
--Module.qtJspiSuspensionCounter;
|
||||
|
||||
setTimeout(() => {
|
||||
const wakeUp = (Module.qtAsyncifyWakeUp ?? []).pop();
|
||||
if (wakeUp) wakeUp();
|
||||
});
|
||||
return true;
|
||||
});
|
||||
|
||||
EM_JS(bool, qt_jspi_can_resume_js, (), {
|
||||
return Module.qtJspiSuspensionCounter > 0;
|
||||
});
|
||||
|
||||
EM_JS(void, init_jspi_support_js, (), {
|
||||
Module.qtAsyncifyWakeUp = [];
|
||||
Module.qtJspiSuspensionCounter = 0;
|
||||
});
|
||||
|
||||
void initJspiSupport() {
|
||||
init_jspi_support_js();
|
||||
}
|
||||
|
||||
Q_CONSTRUCTOR_FUNCTION(initJspiSupport);
|
||||
|
||||
EM_JS(void, qt_asyncify_suspend_js, (), {
|
||||
if (Module.qtSuspendId === undefined)
|
||||
Module.qtSuspendId = 0;
|
||||
@ -105,15 +146,15 @@ bool qt_asyncify_suspend()
|
||||
|
||||
// Wakes any currently suspended main thread. Returns true if the main
|
||||
// thread was suspended, in which case it will now be asynchronously woken.
|
||||
bool qt_asyncify_resume()
|
||||
void qt_asyncify_resume()
|
||||
{
|
||||
if (!g_is_asyncify_suspended)
|
||||
return false;
|
||||
return;
|
||||
g_is_asyncify_suspended = false;
|
||||
qt_asyncify_resume_js();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Q_CONSTINIT QEventDispatcherWasm *QEventDispatcherWasm::g_mainThreadEventDispatcher = nullptr;
|
||||
#if QT_CONFIG(thread)
|
||||
Q_CONSTINIT QVector<QEventDispatcherWasm *> QEventDispatcherWasm::g_secondaryThreadEventDispatchers;
|
||||
@ -431,10 +472,14 @@ bool QEventDispatcherWasm::wait(int timeout)
|
||||
if (timeout > 0)
|
||||
qWarning() << "QEventDispatcherWasm asyncify wait with timeout is not supported; timeout will be ignored"; // FIXME
|
||||
|
||||
bool didSuspend = qt_asyncify_suspend();
|
||||
if (!didSuspend) {
|
||||
qWarning("QEventDispatcherWasm: current thread is already suspended; could not asyncify wait for events");
|
||||
return false;
|
||||
if (useJspi()) {
|
||||
qt_jspi_suspend_js();
|
||||
} else {
|
||||
bool didSuspend = qt_asyncify_suspend();
|
||||
if (!didSuspend) {
|
||||
qWarning("QEventDispatcherWasm: current thread is already suspended; could not asyncify wait for events");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
@ -458,6 +503,12 @@ bool QEventDispatcherWasm::wakeEventDispatcherThread()
|
||||
}
|
||||
#endif
|
||||
Q_ASSERT(isMainThreadEventDispatcher());
|
||||
if (useJspi()) {
|
||||
if (!qt_jspi_can_resume_js())
|
||||
return false;
|
||||
runOnMainThread([]{ qt_jspi_resume_js(); });
|
||||
return true;
|
||||
}
|
||||
if (g_is_asyncify_suspended) {
|
||||
runOnMainThread([]{ qt_asyncify_resume(); });
|
||||
return true;
|
||||
|
@ -30,7 +30,7 @@ static void usePotentialyUnusedSymbols()
|
||||
// called at runtime.
|
||||
volatile bool doIt = false;
|
||||
if (doIt)
|
||||
emscripten_set_wheel_callback(NULL, 0, 0, NULL);
|
||||
emscripten_set_wheel_callback("", 0, 0, NULL);
|
||||
}
|
||||
|
||||
Q_CONSTRUCTOR_FUNCTION(usePotentialyUnusedSymbols)
|
||||
@ -363,10 +363,13 @@ void WebPromiseManager::adoptPromise(emscripten::val target, PromiseCallbacks ca
|
||||
#if defined(QT_STATIC)
|
||||
|
||||
EM_JS(bool, jsHaveAsyncify, (), { return typeof Asyncify !== "undefined"; });
|
||||
EM_JS(bool, jsHaveJspi, (),
|
||||
{ return !!Asyncify && !!Asyncify.makeAsyncFunction && !!WebAssembly.Function; });
|
||||
|
||||
#else
|
||||
|
||||
bool jsHaveAsyncify() { return false; }
|
||||
bool jsHaveJspi() { return false; }
|
||||
|
||||
#endif
|
||||
|
||||
@ -855,6 +858,12 @@ bool haveAsyncify()
|
||||
return HaveAsyncify;
|
||||
}
|
||||
|
||||
bool haveJspi()
|
||||
{
|
||||
static bool HaveJspi = jsHaveJspi();
|
||||
return HaveJspi;
|
||||
}
|
||||
|
||||
std::shared_ptr<CancellationFlag>
|
||||
readDataTransfer(emscripten::val webDataTransfer, std::function<QVariant(QByteArray)> imageReader,
|
||||
std::function<void(std::unique_ptr<QMimeData>)> onDone)
|
||||
|
@ -203,6 +203,7 @@ namespace qstdweb {
|
||||
}
|
||||
|
||||
bool haveAsyncify();
|
||||
bool haveJspi();
|
||||
|
||||
struct CancellationFlag
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user