From 5e5e6240c2dcb7d228fc68075c263f668a9ee963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20S=C3=B8rvig?= Date: Fri, 26 Jan 2024 11:46:26 +0100 Subject: [PATCH] wasm: fix onLoaded delay functionality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit onLoaded and the initial expose/paint should be sequenced such that onLoaded is fired first, followed by the expose. This makes sure that we don't spend any time on painting frames before Qt is completely initialized. Add a "requestUpdateHold" mode to QWasmCompositor (initially on) which disables requestUpdate calls, as well as releaseRequestUpdateHold() which enables requestUpdate calls again. This is a one-way transition; the mode can't be enabled again. This amends commit f2e22774 which implemented the concept of startup tasks, where onLoaded can be delayed until for instance font loading has been completed. After this commit the expose event and initial commit will be delayed as well. Change-Id: Icc784306726174fbabe8785d54485860e968745a Reviewed-by: Lorn Potter Reviewed-by: Piotr WierciƄski --- src/corelib/kernel/qeventdispatcher_wasm.cpp | 27 ++++++++++++------- src/corelib/kernel/qeventdispatcher_wasm_p.h | 3 ++- .../platforms/wasm/qwasmcompositor.cpp | 16 +++++++++++ src/plugins/platforms/wasm/qwasmcompositor.h | 3 ++- .../platforms/wasm/qwasmeventdispatcher.cpp | 17 ++++++++++++ .../platforms/wasm/qwasmeventdispatcher.h | 1 + .../platforms/wasm/qwasmintegration.cpp | 7 +++++ src/plugins/platforms/wasm/qwasmintegration.h | 1 + 8 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/corelib/kernel/qeventdispatcher_wasm.cpp b/src/corelib/kernel/qeventdispatcher_wasm.cpp index 5f4c46c07f2..f5061f35d74 100644 --- a/src/corelib/kernel/qeventdispatcher_wasm.cpp +++ b/src/corelib/kernel/qeventdispatcher_wasm.cpp @@ -218,9 +218,12 @@ QEventDispatcherWasm::QEventDispatcherWasm() #if QT_CONFIG(thread) g_mainThread = pthread_self(); #endif + // Call the "onLoaded" JavaScript callback, unless startup tasks - // have been registered which should complete first. - checkCallQtLoaded(); + // have been registered which should complete first. Run async + // to make sure event dispatcher construction (in particular any + // subclass construction) has completed first. + runAsync(callOnLoadedIfRequired); } else { #if QT_CONFIG(thread) std::lock_guard lock(g_staticDataMutex); @@ -916,10 +919,10 @@ void QEventDispatcherWasm::registerStartupTask() void QEventDispatcherWasm::completeStarupTask() { --g_startupTasks; - checkCallQtLoaded(); + callOnLoadedIfRequired(); } -void QEventDispatcherWasm::checkCallQtLoaded() +void QEventDispatcherWasm::callOnLoadedIfRequired() { if (g_startupTasks > 0) return; @@ -929,12 +932,16 @@ void QEventDispatcherWasm::checkCallQtLoaded() return; qtLoadedCalled = true; - QTimer::singleShot(0, [](){ - emscripten::val qt = emscripten::val::module_property("qt"); - if (qt.isUndefined()) - return; - qt.call("onLoaded"); - }); + Q_ASSERT(g_mainThreadEventDispatcher); + g_mainThreadEventDispatcher->onLoaded(); +} + +void QEventDispatcherWasm::onLoaded() +{ + emscripten::val qt = emscripten::val::module_property("qt"); + if (qt.isUndefined()) + return; + qt.call("onLoaded"); } namespace { diff --git a/src/corelib/kernel/qeventdispatcher_wasm_p.h b/src/corelib/kernel/qeventdispatcher_wasm_p.h index afffc8a813b..0d94c48a25d 100644 --- a/src/corelib/kernel/qeventdispatcher_wasm_p.h +++ b/src/corelib/kernel/qeventdispatcher_wasm_p.h @@ -59,7 +59,8 @@ public: static void registerStartupTask(); static void completeStarupTask(); - static void checkCallQtLoaded(); + static void callOnLoadedIfRequired(); + virtual void onLoaded(); protected: virtual bool processPostedEvents(); diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp index 66eaea62faa..48445d5db95 100644 --- a/src/plugins/platforms/wasm/qwasmcompositor.cpp +++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp @@ -4,6 +4,8 @@ #include "qwasmcompositor.h" #include "qwasmwindow.h" +#include + #include #include @@ -41,6 +43,17 @@ void QWasmCompositor::setEnabled(bool enabled) m_isEnabled = enabled; } +// requestUpdate delivery is initially disabled at startup, while Qt completes +// startup tasks such as font loading. This function enables requestUpdate delivery +// again. +void QWasmCompositor::releaseRequesetUpdateHold() +{ + if (!m_requestUpdateHoldEnabled) + return; + m_requestUpdateHoldEnabled = false; + requestUpdate(); +} + void QWasmCompositor::requestUpdateWindow(QWasmWindow *window, UpdateRequestDeliveryType updateType) { auto it = m_requestUpdateWindows.find(window); @@ -62,6 +75,9 @@ void QWasmCompositor::requestUpdate() if (m_requestAnimationFrameId != -1) return; + if (m_requestUpdateHoldEnabled) + return; + static auto frame = [](double frameTime, void *context) -> int { Q_UNUSED(frameTime); diff --git a/src/plugins/platforms/wasm/qwasmcompositor.h b/src/plugins/platforms/wasm/qwasmcompositor.h index 182ea2b1678..5de401844c3 100644 --- a/src/plugins/platforms/wasm/qwasmcompositor.h +++ b/src/plugins/platforms/wasm/qwasmcompositor.h @@ -31,8 +31,8 @@ public: QWasmScreen *screen(); void setEnabled(bool enabled); + void releaseRequesetUpdateHold(); enum UpdateRequestDeliveryType { ExposeEventDelivery, UpdateRequestDelivery }; - void requestUpdateWindow(QWasmWindow *window, UpdateRequestDeliveryType updateType = ExposeEventDelivery); void handleBackingStoreFlush(QWindow *window); @@ -50,6 +50,7 @@ private: bool m_isEnabled = true; QMap m_requestUpdateWindows; int m_requestAnimationFrameId = -1; + bool m_requestUpdateHoldEnabled = true; bool m_inDeliverUpdateRequest = false; }; diff --git a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp index cd2cefc14d9..1f2d3095d65 100644 --- a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp +++ b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "qwasmeventdispatcher.h" +#include "qwasmintegration.h" #include @@ -15,4 +16,20 @@ bool QWasmEventDispatcher::processPostedEvents() return QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::AllEvents); } +void QWasmEventDispatcher::onLoaded() +{ + // This function is called when the application is ready to paint + // the first frame. Send the qtlaoder onLoaded event first (via + // the base class implementation), and then enable/call requestUpdate + // to deliver a frame. + QEventDispatcherWasm::onLoaded(); + + // Make sure all screens have a defined size; and pick + // up size changes due to onLoaded event handling. + QWasmIntegration *wasmIntegration = QWasmIntegration::get(); + wasmIntegration->resizeAllScreens(); + + wasmIntegration->releaseRequesetUpdateHold(); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmeventdispatcher.h b/src/plugins/platforms/wasm/qwasmeventdispatcher.h index 33d672a57fb..cbf10482e3f 100644 --- a/src/plugins/platforms/wasm/qwasmeventdispatcher.h +++ b/src/plugins/platforms/wasm/qwasmeventdispatcher.h @@ -12,6 +12,7 @@ class QWasmEventDispatcher : public QEventDispatcherWasm { protected: bool processPostedEvents() override; + void onLoaded() override; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp index c665251d0d2..d2e7c8716cc 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.cpp +++ b/src/plugins/platforms/wasm/qwasmintegration.cpp @@ -206,6 +206,13 @@ void QWasmIntegration::removeBackingStore(QWindow* window) m_backingStores.remove(window); } +void QWasmIntegration::releaseRequesetUpdateHold() +{ + for (const auto &elementAndScreen : m_screens) { + elementAndScreen.wasmScreen->compositor()->releaseRequesetUpdateHold(); + } +} + #ifndef QT_NO_OPENGL QPlatformOpenGLContext *QWasmIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h index eeb68109a0d..870bd0d16b4 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.h +++ b/src/plugins/platforms/wasm/qwasmintegration.h @@ -78,6 +78,7 @@ public: void resizeAllScreens(); void loadLocalFontFamilies(emscripten::val families); void removeBackingStore(QWindow* window); + void releaseRequesetUpdateHold(); static quint64 getTimestamp(); int touchPoints;