summaryrefslogtreecommitdiffstats
path: root/src/runtime/Qt3DSQmlEngine.cpp
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2019-08-07 16:52:00 +0300
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2019-08-13 11:52:25 +0300
commit7ea21a4315b1c6df104d80a700680dd1f9d204dc (patch)
tree8b5dca8ca23a2acdab6f8ad1f911faad1fdb1ddc /src/runtime/Qt3DSQmlEngine.cpp
parentd2a1092b93e9669288dc1d5825bfec849bec9f95 (diff)
Make runtime initialization optionally not block QML
Runtime initialization made non-blocking by offloading it to a worker thread. This causes various object thread affinities in runtime to be incorrect. This is relevant at least for the singaling, where having affinity to non-existing initialization thread would cause signals to not be delivered. To work around this issue, signal proxy thread affinitions and signal connections are set after initialization has completed. Similarly, behavior script QML engine initialization is deferred so that it can be done in correct thread. Task-number: QT3DS-3805 Change-Id: Ie8b64f4ecd93e4c422e369e625080652d67bde27 Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io>
Diffstat (limited to 'src/runtime/Qt3DSQmlEngine.cpp')
-rw-r--r--src/runtime/Qt3DSQmlEngine.cpp57
1 files changed, 41 insertions, 16 deletions
diff --git a/src/runtime/Qt3DSQmlEngine.cpp b/src/runtime/Qt3DSQmlEngine.cpp
index b9b2067..a945f14 100644
--- a/src/runtime/Qt3DSQmlEngine.cpp
+++ b/src/runtime/Qt3DSQmlEngine.cpp
@@ -385,12 +385,13 @@ private:
CScriptCallbacks m_ScriptCallbacks;
- QQmlEngine m_engine;
+ QScopedPointer<QQmlEngine> m_engine;
QMap<QString, QQmlComponent *> m_components;
QVector<Q3DSQmlScript *> m_scripts;
QSet<int> m_availableIds;
QHash<TElement *, int> m_elementIdMap;
+ QVector<QPair<TElement *, QString>> m_deferredScriptLoads;
public:
CQmlEngineImpl(NVFoundationBase &fnd, ITimeProvider &inTimeProvider);
@@ -406,7 +407,10 @@ public:
qt3ds::runtime::IApplication *GetApplication() override;
void Initialize() override;
- void LoadScript(IPresentation *presentation, TElement *element, const CHAR *path) override;
+ void loadScript(TElement *element, const QString &sourcePath);
+ void LoadScript(IPresentation *presentation, TElement *element, const CHAR *path,
+ bool initInRenderThread) override;
+ void loadDeferredScripts() override;
Q3DStudio::INT32 InitializeApplicationBehavior(const char *) override
{
return -1;
@@ -667,20 +671,15 @@ bool CQmlEngineImpl::GetAttribute(const char *element, const char *attName, char
return false;
}
-void CQmlEngineImpl::LoadScript(IPresentation *presentation, TElement *element, const CHAR *path)
+void CQmlEngineImpl::loadScript(TElement *element, const QString &sourcePath)
{
- QString presPath = QFileInfo(presentation->GetFilePath()).absolutePath();
-
- QString sourcePath(presPath + QLatin1Char('/') + path);
- sourcePath.replace(QLatin1Char('\\'), QLatin1Char('/'));
-
- TElement *parent = element->GetParent();
- if (!parent)
- return;
+ if (m_engine.isNull())
+ m_engine.reset(new QQmlEngine);
if (!m_components.contains(sourcePath)) {
- m_components[sourcePath] = new QQmlComponent(&m_engine, QUrl::fromLocalFile(sourcePath),
- &m_engine);
+ m_components[sourcePath] = new QQmlComponent(m_engine.data(),
+ QUrl::fromLocalFile(sourcePath),
+ m_engine.data());
}
QQmlComponent *component = m_components[sourcePath];
@@ -705,6 +704,32 @@ void CQmlEngineImpl::LoadScript(IPresentation *presentation, TElement *element,
}
}
+void CQmlEngineImpl::LoadScript(IPresentation *presentation, TElement *element, const CHAR *path,
+ bool initInRenderThread)
+{
+ QString presPath = QFileInfo(presentation->GetFilePath()).absolutePath();
+
+ QString sourcePath(presPath + QLatin1Char('/') + path);
+ sourcePath.replace(QLatin1Char('\\'), QLatin1Char('/'));
+
+ TElement *parent = element->GetParent();
+ if (!parent)
+ return;
+
+ // Defer engine initialization until we are in render thread
+ if (initInRenderThread)
+ loadScript(element, sourcePath);
+ else
+ m_deferredScriptLoads.append({element, sourcePath});
+}
+
+void CQmlEngineImpl::loadDeferredScripts()
+{
+ for (const auto &data : qAsConst(m_deferredScriptLoads))
+ loadScript(data.first, data.second);
+ m_deferredScriptLoads.clear();
+}
+
void CQmlEngineImpl::FireEvent(const char *element, const char *evtName)
{
TElement *theElement = getTarget(element);
@@ -2001,7 +2026,7 @@ void CQmlEngineImpl::createComponent(QQmlComponent *component, TElement *element
if (!parent)
return;
- QQmlContext *context = new QQmlContext(&m_engine, &m_engine);
+ QQmlContext *context = new QQmlContext(m_engine.data(), m_engine.data());
QObject *obj = component->beginCreate(context);
if (!obj) {
context->deleteLater();
@@ -2439,7 +2464,7 @@ bool CQmlEngineImpl::getAttributeVector2(QVector<QByteArray> &outAttVec,
QJSValue CQmlEngineImpl::buildJSFunc(const QString &userFunc)
{
- auto res = this->m_engine.evaluate(userFunc);
+ auto res = this->m_engine->evaluate(userFunc);
if (res.isError()) {
qWarning() << __FUNCTION__
<< "Uncaught exception during datainput evaluation. Evaluator function" << userFunc;
@@ -2457,7 +2482,7 @@ QVariant CQmlEngineImpl::callJSFunc(const QString &controllerName,
// get the most recent set values for datainput sources (arguments) in the expression
for (auto diVal : sourceDIs)
- args << this->m_engine.toScriptValue(diMap[diVal].value);
+ args << this->m_engine->toScriptValue(diMap[diVal].value);
if (diDef.evalFunc.isCallable()) {
QJSValue res = diDef.evalFunc.call(args);