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();
|
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, (), {
|
EM_JS(void, qt_asyncify_suspend_js, (), {
|
||||||
if (Module.qtSuspendId === undefined)
|
if (Module.qtSuspendId === undefined)
|
||||||
Module.qtSuspendId = 0;
|
Module.qtSuspendId = 0;
|
||||||
@ -105,15 +146,15 @@ bool qt_asyncify_suspend()
|
|||||||
|
|
||||||
// Wakes any currently suspended main thread. Returns true if the main
|
// Wakes any currently suspended main thread. Returns true if the main
|
||||||
// thread was suspended, in which case it will now be asynchronously woken.
|
// 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)
|
if (!g_is_asyncify_suspended)
|
||||||
return false;
|
return;
|
||||||
g_is_asyncify_suspended = false;
|
g_is_asyncify_suspended = false;
|
||||||
qt_asyncify_resume_js();
|
qt_asyncify_resume_js();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Q_CONSTINIT QEventDispatcherWasm *QEventDispatcherWasm::g_mainThreadEventDispatcher = nullptr;
|
Q_CONSTINIT QEventDispatcherWasm *QEventDispatcherWasm::g_mainThreadEventDispatcher = nullptr;
|
||||||
#if QT_CONFIG(thread)
|
#if QT_CONFIG(thread)
|
||||||
Q_CONSTINIT QVector<QEventDispatcherWasm *> QEventDispatcherWasm::g_secondaryThreadEventDispatchers;
|
Q_CONSTINIT QVector<QEventDispatcherWasm *> QEventDispatcherWasm::g_secondaryThreadEventDispatchers;
|
||||||
@ -431,11 +472,15 @@ bool QEventDispatcherWasm::wait(int timeout)
|
|||||||
if (timeout > 0)
|
if (timeout > 0)
|
||||||
qWarning() << "QEventDispatcherWasm asyncify wait with timeout is not supported; timeout will be ignored"; // FIXME
|
qWarning() << "QEventDispatcherWasm asyncify wait with timeout is not supported; timeout will be ignored"; // FIXME
|
||||||
|
|
||||||
|
if (useJspi()) {
|
||||||
|
qt_jspi_suspend_js();
|
||||||
|
} else {
|
||||||
bool didSuspend = qt_asyncify_suspend();
|
bool didSuspend = qt_asyncify_suspend();
|
||||||
if (!didSuspend) {
|
if (!didSuspend) {
|
||||||
qWarning("QEventDispatcherWasm: current thread is already suspended; could not asyncify wait for events");
|
qWarning("QEventDispatcherWasm: current thread is already suspended; could not asyncify wait for events");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
qWarning("QEventLoop::WaitForMoreEvents is not supported on the main thread without asyncify");
|
qWarning("QEventLoop::WaitForMoreEvents is not supported on the main thread without asyncify");
|
||||||
@ -458,6 +503,12 @@ bool QEventDispatcherWasm::wakeEventDispatcherThread()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
Q_ASSERT(isMainThreadEventDispatcher());
|
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) {
|
if (g_is_asyncify_suspended) {
|
||||||
runOnMainThread([]{ qt_asyncify_resume(); });
|
runOnMainThread([]{ qt_asyncify_resume(); });
|
||||||
return true;
|
return true;
|
||||||
|
@ -30,7 +30,7 @@ static void usePotentialyUnusedSymbols()
|
|||||||
// called at runtime.
|
// called at runtime.
|
||||||
volatile bool doIt = false;
|
volatile bool doIt = false;
|
||||||
if (doIt)
|
if (doIt)
|
||||||
emscripten_set_wheel_callback(NULL, 0, 0, NULL);
|
emscripten_set_wheel_callback("", 0, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_CONSTRUCTOR_FUNCTION(usePotentialyUnusedSymbols)
|
Q_CONSTRUCTOR_FUNCTION(usePotentialyUnusedSymbols)
|
||||||
@ -363,10 +363,13 @@ void WebPromiseManager::adoptPromise(emscripten::val target, PromiseCallbacks ca
|
|||||||
#if defined(QT_STATIC)
|
#if defined(QT_STATIC)
|
||||||
|
|
||||||
EM_JS(bool, jsHaveAsyncify, (), { return typeof Asyncify !== "undefined"; });
|
EM_JS(bool, jsHaveAsyncify, (), { return typeof Asyncify !== "undefined"; });
|
||||||
|
EM_JS(bool, jsHaveJspi, (),
|
||||||
|
{ return !!Asyncify && !!Asyncify.makeAsyncFunction && !!WebAssembly.Function; });
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
bool jsHaveAsyncify() { return false; }
|
bool jsHaveAsyncify() { return false; }
|
||||||
|
bool jsHaveJspi() { return false; }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -855,6 +858,12 @@ bool haveAsyncify()
|
|||||||
return HaveAsyncify;
|
return HaveAsyncify;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool haveJspi()
|
||||||
|
{
|
||||||
|
static bool HaveJspi = jsHaveJspi();
|
||||||
|
return HaveJspi;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<CancellationFlag>
|
std::shared_ptr<CancellationFlag>
|
||||||
readDataTransfer(emscripten::val webDataTransfer, std::function<QVariant(QByteArray)> imageReader,
|
readDataTransfer(emscripten::val webDataTransfer, std::function<QVariant(QByteArray)> imageReader,
|
||||||
std::function<void(std::unique_ptr<QMimeData>)> onDone)
|
std::function<void(std::unique_ptr<QMimeData>)> onDone)
|
||||||
|
@ -203,6 +203,7 @@ namespace qstdweb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool haveAsyncify();
|
bool haveAsyncify();
|
||||||
|
bool haveJspi();
|
||||||
|
|
||||||
struct CancellationFlag
|
struct CancellationFlag
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user