summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/api/studio3d/q3dssurfaceviewer.cpp4
-rw-r--r--src/api/studio3dqml/q3dsrenderer.cpp112
-rw-r--r--src/api/studio3dqml/q3dsrenderer_p.h11
-rw-r--r--src/api/studio3dqml/q3dsruntimeInitializerthread.cpp73
-rw-r--r--src/api/studio3dqml/q3dsruntimeInitializerthread_p.h94
-rw-r--r--src/api/studio3dqml/q3dsstudio3d.cpp33
-rw-r--r--src/api/studio3dqml/q3dsstudio3d_p.h5
-rw-r--r--src/api/studio3dqml/studio3dqml.pro6
-rw-r--r--src/engine/Qt3DSRuntimeView.cpp29
-rw-r--r--src/engine/Qt3DSRuntimeView.h5
-rw-r--r--src/runtime/Qt3DSApplication.cpp20
-rw-r--r--src/runtime/Qt3DSApplication.h3
-rw-r--r--src/runtime/Qt3DSIScriptBridge.h2
-rw-r--r--src/runtime/Qt3DSPresentation.cpp8
-rw-r--r--src/runtime/Qt3DSPresentation.h2
-rw-r--r--src/runtime/Qt3DSQmlEngine.cpp57
-rw-r--r--src/runtime/Qt3DSQmlEngine.h2
-rw-r--r--src/uipparser/Qt3DSUIPParser.h3
-rw-r--r--src/uipparser/Qt3DSUIPParserImpl.cpp17
-rw-r--r--src/uipparser/Qt3DSUIPParserImpl.h9
-rw-r--r--src/viewer/Qt3DSViewerApp.cpp65
-rw-r--r--src/viewer/Qt3DSViewerApp.h4
-rw-r--r--tools/viewer/viewer.pro2
23 files changed, 455 insertions, 111 deletions
diff --git a/src/api/studio3d/q3dssurfaceviewer.cpp b/src/api/studio3d/q3dssurfaceviewer.cpp
index 899d771..d8a9756 100644
--- a/src/api/studio3d/q3dssurfaceviewer.cpp
+++ b/src/api/studio3d/q3dssurfaceviewer.cpp
@@ -650,9 +650,9 @@ bool Q3DSSurfaceViewerPrivate::initializeRuntime()
if (!m_viewerApp->InitializeApp(int(m_size.width() * m_pixelRatio),
int(m_size.height() * m_pixelRatio),
- m_context->format(), m_fboId, localSource,
+ m_context->format(), int(m_fboId), localSource,
m_presentation->variantList(),
- m_presentation->delayedLoading(),
+ m_presentation->delayedLoading(), true,
m_presentation->d_ptr->streamProxy())) {
setError(m_viewerApp->error());
releaseRuntime();
diff --git a/src/api/studio3dqml/q3dsrenderer.cpp b/src/api/studio3dqml/q3dsrenderer.cpp
index 12f2e4d..172ec69 100644
--- a/src/api/studio3dqml/q3dsrenderer.cpp
+++ b/src/api/studio3dqml/q3dsrenderer.cpp
@@ -32,6 +32,7 @@
#include "Qt3DSViewerApp.h"
#include "Qt3DSAudioPlayerImpl.h"
#include "q3dspresentationitem_p.h"
+#include "q3dsruntimeInitializerthread_p.h"
#include <QtStudio3D/private/q3dscommandqueue_p.h>
#include <QtStudio3D/private/q3dsviewersettings_p.h>
@@ -41,6 +42,7 @@
#include <QtCore/qdebug.h>
#include <QtCore/qrunnable.h>
+#include <QtCore/qthread.h>
#include <QtGui/qwindow.h>
#include <QtGui/qopenglcontext.h>
#include <QtQuick/qquickwindow.h>
@@ -50,10 +52,10 @@ using namespace Q3DSViewer;
QT_BEGIN_NAMESPACE
Q3DSRenderer::Q3DSRenderer(bool visibleFlag, qt3ds::Qt3DSAssetVisitor *assetVisitor,
- QElapsedTimer *startupTimer)
+ QElapsedTimer *startupTimer, bool asyncInit)
: m_visibleFlag(visibleFlag)
, m_initElements(false)
- , m_runtime(0)
+ , m_runtime(nullptr)
, m_window(nullptr)
, m_initialized(false)
, m_initializationFailure(false)
@@ -61,6 +63,7 @@ Q3DSRenderer::Q3DSRenderer(bool visibleFlag, qt3ds::Qt3DSAssetVisitor *assetVisi
, m_settings(new Q3DSViewerSettings(this))
, m_presentation(new Q3DSPresentation(this))
, m_startupTimer(startupTimer)
+ , m_asyncInit(asyncInit)
{
}
@@ -77,7 +80,7 @@ QOpenGLFramebufferObject *Q3DSRenderer::createFramebufferObject(const QSize &siz
QOpenGLFramebufferObject *frameBuffer =
new QOpenGLFramebufferObject(size, theFormat);
if (m_runtime && m_runtime->IsInitialised())
- m_runtime->setOffscreenId(frameBuffer->handle());
+ m_runtime->setOffscreenId(int(frameBuffer->handle()));
return frameBuffer;
}
@@ -123,11 +126,27 @@ void Q3DSRenderer::releaseRuntime()
m_presentation->d_ptr->setViewerApp(nullptr);
if (m_runtime) {
+ if (m_asyncInit && m_runtimeInitializerThread) {
+ m_runtimeInitializerThread->quit();
+ m_runtimeInitializerThread->wait();
+ delete m_runtimeInitializerThread;
+ m_runtimeInitializerThread = nullptr;
+ }
m_runtime->Release();
m_runtime = nullptr;
}
}
+void Q3DSRenderer::registerCallbacks()
+{
+ m_runtime->RegisterScriptCallback(Q3DSViewer::ViewerCallbackType::Enum::CALLBACK_ON_INIT,
+ reinterpret_cast<qml_Function>(Q3DSRenderer::onInitHandler),
+ this);
+ m_runtime->RegisterScriptCallback(Q3DSViewer::ViewerCallbackType::Enum::CALLBACK_ON_UPDATE,
+ reinterpret_cast<qml_Function>(Q3DSRenderer::onUpdateHandler),
+ this);
+}
+
class RuntimeInitializer : public QRunnable
{
public:
@@ -149,7 +168,6 @@ private:
Q3DSRenderer *m_renderer;
};
-
/** Invoked by the QML scene graph indicating that it's time to render.
* Calls `draw()` if the plugin is visible, or `processCommands()` otherwise.
*
@@ -163,9 +181,14 @@ void Q3DSRenderer::render()
// We may start in a non visible state but we still need
// to init the runtime otherwise the commands are never processed
if (!m_initialized && !m_initializationFailure) {
- auto *ri = new RuntimeInitializer(this);
- // Initialize runtime after the first frame has been drawn
- m_window->scheduleRenderJob(ri, QQuickWindow::AfterSwapStage);
+ if (m_asyncInit) {
+ if (!m_runtimeInitializerThread)
+ initializeRuntime(framebufferObject());
+ } else {
+ auto *ri = new RuntimeInitializer(this);
+ // Initialize runtime after the first frame has been drawn
+ m_window->scheduleRenderJob(ri, QQuickWindow::AfterSwapStage);
+ }
}
// Don't render if the plugin is hidden; however, if hidden, but sure
@@ -210,28 +233,37 @@ bool Q3DSRenderer::initializeRuntime(QOpenGLFramebufferObject *inFbo)
const QString localSource = Q3DSUtils::urlToLocalFileOrQrc(m_presentation->source());
- if (!m_runtime->InitializeApp(theWidth, theHeight,
- QOpenGLContext::currentContext()->format(),
- inFbo->handle(), localSource,
- m_presentation->variantList(),
- m_presentation->delayedLoading(),
- m_visitor)) {
- m_error = m_runtime->error();
- releaseRuntime();
- return false;
+ if (m_asyncInit) {
+ auto currentContext = QOpenGLContext::currentContext();
+ auto context = new QOpenGLContext();
+ context->setFormat(currentContext->format());
+ context->setShareContext(currentContext);
+ context->create();
+ m_runtimeInitializerThread = new Q3DSRuntimeInitializerThread(
+ m_runtime, theWidth, theHeight, QOpenGLContext::currentContext()->format(),
+ int(inFbo->handle()), localSource, m_presentation->variantList(),
+ m_presentation->delayedLoading(), m_visitor, context,
+ currentContext->surface());
+ connect(m_runtimeInitializerThread, &Q3DSRuntimeInitializerThread::initDone,
+ this, &Q3DSRenderer::handleRuntimeInitializedAsync, Qt::QueuedConnection);
+ context->moveToThread(m_runtimeInitializerThread);
+ m_runtimeInitializerThread->start();
+ } else {
+ if (!m_runtime->InitializeApp(theWidth, theHeight,
+ QOpenGLContext::currentContext()->format(),
+ int(inFbo->handle()), localSource,
+ m_presentation->variantList(),
+ m_presentation->delayedLoading(), true,
+ m_visitor)) {
+ m_error = m_runtime->error();
+ releaseRuntime();
+ return false;
+ }
+ m_settings->d_ptr->setViewerApp(m_runtime);
+ m_presentation->d_ptr->setViewerApp(m_runtime, false);
+ registerCallbacks();
}
- m_runtime->RegisterScriptCallback(Q3DSViewer::ViewerCallbackType::Enum::CALLBACK_ON_INIT,
- reinterpret_cast<qml_Function>(Q3DSRenderer::onInitHandler),
- this);
- m_runtime->RegisterScriptCallback(Q3DSViewer::ViewerCallbackType::Enum::CALLBACK_ON_UPDATE,
- reinterpret_cast<qml_Function>(Q3DSRenderer::onUpdateHandler),
- this);
-
- m_settings->d_ptr->setViewerApp(m_runtime);
- m_presentation->d_ptr->setViewerApp(m_runtime, false);
-
- // Connect signals
connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigSlideEntered,
this, &Q3DSRenderer::enterSlide);
connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigSlideExited,
@@ -332,7 +364,7 @@ void Q3DSRenderer::processCommands()
m_presentation->goToTime(cmd.m_elementPath, cmd.m_floatValue);
break;
case CommandType_GoToSlide:
- m_presentation->goToSlide(cmd.m_elementPath, cmd.m_intValues[0]);
+ m_presentation->goToSlide(cmd.m_elementPath, quint32(cmd.m_intValues[0]));
break;
case CommandType_GoToSlideByName:
m_presentation->goToSlide(cmd.m_elementPath, cmd.m_stringValue);
@@ -496,4 +528,28 @@ void Q3DSRenderer::processCommands()
m_commands.clear(false);
}
+void Q3DSRenderer::handleRuntimeInitializedAsync()
+{
+ m_initialized = m_runtimeInitializerThread->wasSuccess();
+ m_initializationFailure = !m_initialized;
+
+ if (m_initializationFailure) {
+ m_commands.clear(true);
+ m_error = m_runtime->error();
+ releaseRuntime();
+ } else {
+ m_runtime->finishAsyncInit();
+ registerCallbacks();
+ m_settings->d_ptr->setViewerApp(m_runtime);
+ m_presentation->d_ptr->setViewerApp(m_runtime, false);
+ m_window->setClearBeforeRendering(false);
+
+ connect(m_runtimeInitializerThread, &QThread::finished, [this]() {
+ m_runtimeInitializerThread->deleteLater();
+ m_runtimeInitializerThread = nullptr;
+ });
+ m_runtimeInitializerThread->quit();
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/api/studio3dqml/q3dsrenderer_p.h b/src/api/studio3dqml/q3dsrenderer_p.h
index 61e8770..f0b6cfe 100644
--- a/src/api/studio3dqml/q3dsrenderer_p.h
+++ b/src/api/studio3dqml/q3dsrenderer_p.h
@@ -52,6 +52,7 @@ QT_BEGIN_NAMESPACE
class Q3DSViewerSettings;
class Q3DSPresentation;
+class Q3DSRuntimeInitializerThread;
class Q3DSRenderer : public QObject,
public QQuickFramebufferObject::Renderer
@@ -60,8 +61,8 @@ class Q3DSRenderer : public QObject,
public:
Q3DSRenderer(bool visibleFlag, qt3ds::Qt3DSAssetVisitor *assetVisitor,
- QElapsedTimer *startupTimer);
- ~Q3DSRenderer();
+ QElapsedTimer *startupTimer, bool asyncInit);
+ ~Q3DSRenderer() override;
QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override;
@@ -80,6 +81,9 @@ Q_SIGNALS:
void meshesCreated(const QStringList &meshNames, const QString &error);
void dataOutputValueUpdated(const QString &name, const QVariant &newValue);
+protected Q_SLOTS:
+ void handleRuntimeInitializedAsync();
+
protected:
static void onInitHandler(void *userData);
static void onUpdateHandler(void *userData);
@@ -88,6 +92,7 @@ protected:
void render() override;
void synchronize(QQuickFramebufferObject *inView) override;
void releaseRuntime();
+ void registerCallbacks();
protected:
bool m_visibleFlag; // Is the plugin visible? Prevents rendering hidden content.
@@ -104,6 +109,8 @@ protected:
Q3DSPresentation *m_presentation;
QString m_error;
QElapsedTimer *m_startupTimer;
+ Q3DSRuntimeInitializerThread *m_runtimeInitializerThread = nullptr;
+ bool m_asyncInit = false;
friend class RuntimeInitializer;
};
diff --git a/src/api/studio3dqml/q3dsruntimeInitializerthread.cpp b/src/api/studio3dqml/q3dsruntimeInitializerthread.cpp
new file mode 100644
index 0000000..677b61a
--- /dev/null
+++ b/src/api/studio3dqml/q3dsruntimeInitializerthread.cpp
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3dsruntimeInitializerthread_p.h"
+#include "Qt3DSViewerApp.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qthread.h>
+
+QT_BEGIN_NAMESPACE
+
+Q3DSRuntimeInitializerThread::Q3DSRuntimeInitializerThread(
+ Q3DSViewer::Q3DSViewerApp *runtime,
+ int width, int height, const QSurfaceFormat &format, int offscreenID, const QString &source,
+ const QStringList &variantList, bool delayedLoading, qt3ds::Qt3DSAssetVisitor *assetVisitor,
+ QOpenGLContext *context, QSurface *surface)
+ : m_runtime(runtime)
+ , m_width(width)
+ , m_height(height)
+ , m_format(format)
+ , m_offscreenId(offscreenID)
+ , m_source(source)
+ , m_variantList(variantList)
+ , m_delayedLoading(delayedLoading)
+ , m_assetVisitor(assetVisitor)
+ , m_context(context)
+ , m_surface(surface)
+{
+
+}
+
+void Q3DSRuntimeInitializerThread::run()
+{
+ m_context->makeCurrent(m_surface);
+ m_success = m_runtime->InitializeApp(m_width, m_height, m_format, m_offscreenId,
+ m_source, m_variantList, m_delayedLoading, false,
+ m_assetVisitor);
+ m_context->doneCurrent();
+ delete m_context;
+
+ Q_EMIT initDone();
+
+ // Enter event loop to ensure thread is alive for long enough for initDone to be delivered
+ exec();
+}
+
+QT_END_NAMESPACE
diff --git a/src/api/studio3dqml/q3dsruntimeInitializerthread_p.h b/src/api/studio3dqml/q3dsruntimeInitializerthread_p.h
new file mode 100644
index 0000000..42dcf67
--- /dev/null
+++ b/src/api/studio3dqml/q3dsruntimeInitializerthread_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3DS_RUNTIME_INITIALIZER_THEAD_H
+#define Q3DS_RUNTIME_INITIALIZER_THEAD_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtStudio3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "Qt3DSViewerApp.h"
+#include "q3dsstudio3d_p.h"
+
+#include <QtCore/qthread.h>
+#include <QtGui/qopenglframebufferobject.h>
+#include <QtGui/qsurfaceformat.h>
+#include <QtGui/qopenglcontext.h>
+#include <QtGui/qsurface.h>
+#include <QtQuick/qquickframebufferobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSRenderer;
+
+class Q3DSRuntimeInitializerThread : public QThread
+{
+ Q_OBJECT
+public:
+ Q3DSRuntimeInitializerThread(Q3DSViewer::Q3DSViewerApp *runtime,
+ int width, int height, const QSurfaceFormat &format,
+ int offscreenID, const QString &source,
+ const QStringList &variantList, bool delayedLoading,
+ qt3ds::Qt3DSAssetVisitor *assetVisitor, QOpenGLContext *context,
+ QSurface *surface);
+
+ void run() override;
+
+ bool wasSuccess() const { return m_success; }
+
+Q_SIGNALS:
+ void initDone();
+
+private:
+ Q3DSViewer::Q3DSViewerApp *m_runtime = nullptr;
+ Q3DSRenderer *m_renderer = nullptr;
+ int m_width = 0;
+ int m_height = 0;
+ QSurfaceFormat m_format;
+ int m_offscreenId = 0;
+ QString m_source;
+ QStringList m_variantList;
+ bool m_delayedLoading = false;
+ qt3ds::Qt3DSAssetVisitor *m_assetVisitor;
+ QOpenGLContext *m_context;
+ QSurface *m_surface;
+ bool m_success = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DS_RUNTIME_INITIALIZER_THEAD_H
diff --git a/src/api/studio3dqml/q3dsstudio3d.cpp b/src/api/studio3dqml/q3dsstudio3d.cpp
index 8183d7b..736846e 100644
--- a/src/api/studio3dqml/q3dsstudio3d.cpp
+++ b/src/api/studio3dqml/q3dsstudio3d.cpp
@@ -211,6 +211,31 @@ void Q3DSStudio3D::setError(const QString &error)
}
/*!
+ \qmlproperty bool Studio3D::asyncInit
+
+ If set to \c{true}, indicates that renderer initialization should be done asynchronously
+ in a helper thread. This improves UI responsiveness while initialization is happening,
+ but can lead to slower initialization. Asynchronous initialization may not work properly
+ on all platforms.
+
+ Defaults to \c{false}.
+
+ Changing this property after renderer is created doesn't do anything.
+*/
+bool Q3DSStudio3D::asyncInit() const
+{
+ return m_asyncInit;
+}
+
+void Q3DSStudio3D::setAsyncInit(bool enabled)
+{
+ if (enabled != m_asyncInit) {
+ m_asyncInit = enabled;
+ Q_EMIT asyncInitChanged(m_asyncInit);
+ }
+}
+
+/*!
\qmlproperty EventIgnoreFlags Studio3D::ignoredEvents
This property can be used to ignore mouse/wheel/keyboard events.
@@ -295,7 +320,10 @@ void Q3DSStudio3D::handleWindowChanged(QQuickWindow *window)
if (!window)
return;
- window->setClearBeforeRendering(false);
+ // We need to enable clearing until the presentation starts rendering and takes care of that.
+ // Note that having this flag as false assumes presentation is always full screen.
+ window->setClearBeforeRendering(m_asyncInit);
+
m_pixelRatio = window->devicePixelRatio();
// Call tick every frame of the GUI thread to notify QML about new frame via frameUpdate signal
@@ -380,8 +408,7 @@ QQuickFramebufferObject::Renderer *Q3DSStudio3D::createRenderer() const
// and the plugin, and vice-versa. The only valid time the two
// may communicate is during Q3DSRenderer::synchronize().
Q3DSRenderer *renderer = new Q3DSRenderer(isVisible(), m_presentation->d_ptr->streamProxy(),
- m_startupTimer.get());
-
+ m_startupTimer.get(), m_asyncInit);
connect(renderer, &Q3DSRenderer::enterSlide,
m_presentation->d_ptr, &Q3DSPresentationPrivate::handleSlideEntered);
connect(renderer, &Q3DSRenderer::dataOutputValueUpdated,
diff --git a/src/api/studio3dqml/q3dsstudio3d_p.h b/src/api/studio3dqml/q3dsstudio3d_p.h
index 0fa91d6..45d0695 100644
--- a/src/api/studio3dqml/q3dsstudio3d_p.h
+++ b/src/api/studio3dqml/q3dsstudio3d_p.h
@@ -61,6 +61,7 @@ class Q3DSStudio3D : public QQuickFramebufferObject
Q_PROPERTY(Q3DSViewerSettings *viewerSettings READ viewerSettings CONSTANT)
Q_PROPERTY(QString error READ error NOTIFY errorChanged)
Q_PROPERTY(EventIgnoreFlags ignoredEvents READ ignoredEvents WRITE setIgnoredEvents NOTIFY ignoredEventsChanged)
+ Q_PROPERTY(bool asyncInit READ asyncInit WRITE setAsyncInit NOTIFY asyncInitChanged)
public:
enum EventIgnoreFlag {
@@ -83,6 +84,8 @@ public:
Q3DSViewerSettings *viewerSettings() const;
QString error() const;
void setError(const QString &error);
+ bool asyncInit() const;
+ void setAsyncInit(bool enabled);
void getCommands(bool emitInitialize, CommandQueue &renderQueue);
@@ -105,6 +108,7 @@ Q_SIGNALS:
void ignoredEventsChanged();
void presentationReady();
void presentationLoaded();
+ void asyncInitChanged(bool enabled);
public Q_SLOTS:
void reset();
@@ -130,6 +134,7 @@ protected:
qreal m_pixelRatio;
QString m_error;
QScopedPointer<QElapsedTimer> m_startupTimer;
+ bool m_asyncInit = false;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(Q3DSStudio3D::EventIgnoreFlags)
diff --git a/src/api/studio3dqml/studio3dqml.pro b/src/api/studio3dqml/studio3dqml.pro
index b62a342..df685fc 100644
--- a/src/api/studio3dqml/studio3dqml.pro
+++ b/src/api/studio3dqml/studio3dqml.pro
@@ -16,13 +16,15 @@ SOURCES += \
q3dsplugin.cpp \
q3dsstudio3d.cpp \
q3dsrenderer.cpp \
- q3dspresentationitem.cpp
+ q3dspresentationitem.cpp \
+ q3dsruntimeinitializerthread.cpp
HEADERS += \
q3dsplugin.h \
q3dsrenderer_p.h \
q3dsstudio3d_p.h \
- q3dspresentationitem_p.h
+ q3dspresentationitem_p.h \
+ q3dsruntimeinitializerthread_p.h
LIBS += \
-lqt3dsopengl$$qtPlatformTargetSuffix() \
diff --git a/src/engine/Qt3DSRuntimeView.cpp b/src/engine/Qt3DSRuntimeView.cpp
index 90a2562..f9a4768 100644
--- a/src/engine/Qt3DSRuntimeView.cpp
+++ b/src/engine/Qt3DSRuntimeView.cpp
@@ -170,7 +170,10 @@ public:
bool BeginLoad(const QString &sourcePath, const QStringList &variantList) override;
bool HasOfflineLoadingCompleted() override;
- bool InitializeGraphics(const QSurfaceFormat &format, bool delayedLoading) override;
+ bool InitializeGraphics(const QSurfaceFormat &format, bool delayedLoading,
+ bool initInRenderThread) override;
+ void connectSignals() override;
+ void finishAsyncInit() override;
void Cleanup() override;
@@ -251,6 +254,8 @@ CRuntimeView::CRuntimeView(ITimeProvider &inTimeProvider, IWindowSystem &inWindo
, m_startupTimer(startupTimer)
, m_startupTime(-1)
{
+ // Signal proxy thread affinity is set later when signals are connected to ensure it is correct
+ signalProxy()->moveToThread(nullptr);
}
CRuntimeView::~CRuntimeView()
@@ -292,7 +297,8 @@ bool CRuntimeView::HasOfflineLoadingCompleted()
return true;
}
-bool CRuntimeView::InitializeGraphics(const QSurfaceFormat &format, bool delayedLoading)
+bool CRuntimeView::InitializeGraphics(const QSurfaceFormat &format, bool delayedLoading,
+ bool initInRenderThread)
{
m_ApplicationCore->EndLoad();
// Next call will initialize the render portion of the scenes. This *must* have a loaded
@@ -300,7 +306,7 @@ bool CRuntimeView::InitializeGraphics(const QSurfaceFormat &format, bool delayed
m_RuntimeFactory = m_RuntimeFactoryCore->CreateRenderFactory(format, delayedLoading);
m_Application
= m_ApplicationCore->CreateApplication(*m_InputEngine, m_AudioPlayer,
- *m_RuntimeFactory);
+ *m_RuntimeFactory, initInRenderThread);
if (!m_Application->createSuccessful())
return false;
@@ -308,6 +314,15 @@ bool CRuntimeView::InitializeGraphics(const QSurfaceFormat &format, bool delayed
m_RenderEngine = &m_RuntimeFactory->CreateRenderEngine();
m_Presentation = m_Application->GetPrimaryPresentation();
+ m_TimeProvider.Reset();
+ return true;
+}
+
+void CRuntimeView::connectSignals()
+{
+ m_Presentation->signalProxy()->moveToThread(QThread::currentThread());
+ signalProxy()->moveToThread(QThread::currentThread());
+
QObject::connect(m_Presentation->signalProxy(), &QPresentationSignalProxy::SigSlideEntered,
signalProxy(), &QRuntimeViewSignalProxy::SigSlideEntered);
QObject::connect(m_Presentation->signalProxy(), &QPresentationSignalProxy::SigSlideExited,
@@ -325,9 +340,13 @@ bool CRuntimeView::InitializeGraphics(const QSurfaceFormat &format, bool delayed
&QPresentationSignalProxy::SigDataOutputValueUpdated,
signalProxy(),
&QRuntimeViewSignalProxy::SigDataOutputValueUpdated);
+}
- m_TimeProvider.Reset();
- return true;
+void CRuntimeView::finishAsyncInit()
+{
+ Q3DStudio::CQmlEngine &bridgeEngine
+ = static_cast<Q3DStudio::CQmlEngine &>(m_RuntimeFactoryCore->GetScriptEngineQml());
+ bridgeEngine.loadDeferredScripts();
}
void CRuntimeView::Cleanup()
diff --git a/src/engine/Qt3DSRuntimeView.h b/src/engine/Qt3DSRuntimeView.h
index 7d86022..bfcb31b 100644
--- a/src/engine/Qt3DSRuntimeView.h
+++ b/src/engine/Qt3DSRuntimeView.h
@@ -161,7 +161,10 @@ public:
public: // loading
virtual bool BeginLoad(const QString &sourcePath, const QStringList &variantList) = 0;
virtual bool HasOfflineLoadingCompleted() = 0;
- virtual bool InitializeGraphics(const QSurfaceFormat &format, bool delayedLoading) = 0;
+ virtual bool InitializeGraphics(const QSurfaceFormat &format, bool delayedLoading,
+ bool initInRenderThread) = 0;
+ virtual void connectSignals() = 0;
+ virtual void finishAsyncInit() = 0;
virtual void Cleanup() = 0;
diff --git a/src/runtime/Qt3DSApplication.cpp b/src/runtime/Qt3DSApplication.cpp
index c885371..60e5b56 100644
--- a/src/runtime/Qt3DSApplication.cpp
+++ b/src/runtime/Qt3DSApplication.cpp
@@ -405,7 +405,7 @@ class IAppLoadContext : public NVRefCounted
{
public:
virtual void EndLoad() = 0;
- virtual bool OnGraphicsInitialized(IRuntimeFactory &inFactory) = 0;
+ virtual bool OnGraphicsInitialized(IRuntimeFactory &inFactory, bool initInRenderThread) = 0;
virtual bool HasCompletedLoading() = 0;
static IAppLoadContext &CreateXMLLoadContext(
SApp &inApp, const char8_t *inScaleMode);
@@ -1218,7 +1218,8 @@ struct SApp : public IApplication
}
bool LoadUIP(SPresentationAsset &inAsset,
- NVConstDataRef<SElementAttributeReference> inExternalReferences)
+ NVConstDataRef<SElementAttributeReference> inExternalReferences,
+ bool initInRenderThread)
{
GetMetaData();
eastl::string theFile;
@@ -1243,7 +1244,7 @@ struct SApp : public IApplication
m_CoreFactory->GetStringTable()));
Q3DStudio::IScene *newScene = NULL;
m_PresentationBuffer.clear();
- if (theUIPParser->Load(*thePresentation, inExternalReferences)) {
+ if (theUIPParser->Load(*thePresentation, inExternalReferences, initInRenderThread)) {
// Load the scene graph portion of the scene.
newScene = m_RuntimeFactory->GetSceneManager().LoadScene(
thePresentation, theUIPParser.mPtr,
@@ -1691,7 +1692,8 @@ struct SApp : public IApplication
// of resources that need to be uploaded to opengl. Maintains reference to runtime factory
IApplication &CreateApplication(Q3DStudio::CInputEngine &inInputEngine,
Q3DStudio::IAudioPlayer *inAudioPlayer,
- Q3DStudio::IRuntimeFactory &inFactory) override
+ Q3DStudio::IRuntimeFactory &inFactory,
+ bool initInRenderThread) override
{
{
SStackPerfTimer __loadTimer(m_CoreFactory->GetPerfTimer(),
@@ -1708,7 +1710,8 @@ struct SApp : public IApplication
SStackPerfTimer __timer(m_CoreFactory->GetPerfTimer(),
"Application: Load Context Graphics Initialized");
if (m_AppLoadContext)
- m_createSuccessful = m_AppLoadContext->OnGraphicsInitialized(inFactory);
+ m_createSuccessful = m_AppLoadContext->OnGraphicsInitialized(
+ inFactory, initInRenderThread);
// Guarantees the end of the multithreaded access to the various components
m_AppLoadContext = NULL;
if (!m_createSuccessful)
@@ -1957,7 +1960,7 @@ struct SXMLLoader : public IAppLoadContext
bool HasCompletedLoading() override { return true; }
- bool OnGraphicsInitialized(IRuntimeFactory &inFactory) override
+ bool OnGraphicsInitialized(IRuntimeFactory &inFactory, bool initInRenderThread) override
{
eastl::vector<SElementAttributeReference> theUIPReferences;
eastl::string tempString;
@@ -1978,7 +1981,8 @@ struct SXMLLoader : public IAppLoadContext
if (!m_App.LoadUIP(thePresentationAsset,
toConstDataRef(theUIPReferences.data(),
- (QT3DSU32)theUIPReferences.size()))) {
+ (QT3DSU32)theUIPReferences.size()),
+ initInRenderThread)) {
qCCritical(INVALID_OPERATION, "Unable to load presentation %s",
thePathStr.c_str());
}
@@ -2061,7 +2065,7 @@ CAppStr &CAppStr::operator=(const CAppStr &inOther)
}
IApplication &IApplication::CreateApplicationCore(Q3DStudio::IRuntimeFactoryCore &inFactory,
- const char8_t *inApplicationDirectory)
+ const char8_t *inApplicationDirectory)
{
return *QT3DS_NEW(inFactory.GetFoundation().getAllocator(), SApp)(inFactory,
inApplicationDirectory);
diff --git a/src/runtime/Qt3DSApplication.h b/src/runtime/Qt3DSApplication.h
index 510845e..7624a39 100644
--- a/src/runtime/Qt3DSApplication.h
+++ b/src/runtime/Qt3DSApplication.h
@@ -249,7 +249,8 @@ public:
// of resources that need to be uploaded to opengl. Maintains reference to runtime factory
virtual IApplication &CreateApplication(Q3DStudio::CInputEngine &inInputEngine,
Q3DStudio::IAudioPlayer *inAudioPlayer,
- Q3DStudio::IRuntimeFactory &inFactory) = 0;
+ Q3DStudio::IRuntimeFactory &inFactory,
+ bool initInRenderThread) = 0;
// maintains reference to runtime factory core. AppDir is where the executable is located;
// the system will expect res directory
diff --git a/src/runtime/Qt3DSIScriptBridge.h b/src/runtime/Qt3DSIScriptBridge.h
index 889968d..16bf299 100644
--- a/src/runtime/Qt3DSIScriptBridge.h
+++ b/src/runtime/Qt3DSIScriptBridge.h
@@ -139,7 +139,7 @@ public: // Scripts
// LoadScript goes further by registering scriptIndex->inPresentation, and inOwner->m_ScriptID=
// scriptIndex
virtual void LoadScript(IPresentation *inPresentation, TElement *inOwner,
- const CHAR *inName) = 0;
+ const CHAR *inName, bool initInRenderThread) = 0;
virtual Q3DStudio::INT32 InitializeApplicationBehavior(const char *inProjectRelativePath) = 0;
public: // Script functions and Callbacks
diff --git a/src/runtime/Qt3DSPresentation.cpp b/src/runtime/Qt3DSPresentation.cpp
index 0792119..504e7b6 100644
--- a/src/runtime/Qt3DSPresentation.cpp
+++ b/src/runtime/Qt3DSPresentation.cpp
@@ -94,6 +94,9 @@ CPresentation::CPresentation(const QString &inName, const QString &projectPath,
ILogicSystem::CreateLogicSystem(inApplication->GetRuntimeFactoryCore().GetFoundation());
m_ParametersSystem = IParametersSystem::CreateParametersSystem(
inApplication->GetRuntimeFactoryCore().GetFoundation());
+
+ // Signal proxy thread affinity is set later when signals are connected to ensure it is correct
+ m_SignalProxy.moveToThread(nullptr);
}
#ifdef _WIN32
#pragma warning(pop)
@@ -833,9 +836,4 @@ void CPresentation::SetSize(const SPresentationSize &inSize)
m_Size = inSize;
}
-QPresentationSignalProxy *CPresentation::signalProxy()
-{
- return &m_SignalProxy;
-}
-
} // namespace Q3DStudio
diff --git a/src/runtime/Qt3DSPresentation.h b/src/runtime/Qt3DSPresentation.h
index 76b0a6e..5917d7b 100644
--- a/src/runtime/Qt3DSPresentation.h
+++ b/src/runtime/Qt3DSPresentation.h
@@ -161,7 +161,7 @@ public: // Commands and Events
void FlushEventCommandQueue(void) override;
void ProcessEvent(SEventCommand &inEvent) override;
- QPresentationSignalProxy *signalProxy();
+ QPresentationSignalProxy *signalProxy() { return &m_SignalProxy; }
public: // Data Output
void AddToDataOutputMap(const QHash<qt3ds::foundation::CRegisteredString,
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);
diff --git a/src/runtime/Qt3DSQmlEngine.h b/src/runtime/Qt3DSQmlEngine.h
index a5ad382..c515df1 100644
--- a/src/runtime/Qt3DSQmlEngine.h
+++ b/src/runtime/Qt3DSQmlEngine.h
@@ -209,6 +209,8 @@ public: // Public functions but not functions on the script bridge
virtual void Initialize() = 0;
+ virtual void loadDeferredScripts() = 0;
+
public:
/**
* @brief Create QML engine
diff --git a/src/uipparser/Qt3DSUIPParser.h b/src/uipparser/Qt3DSUIPParser.h
index 6657139..7b4fc3f 100644
--- a/src/uipparser/Qt3DSUIPParser.h
+++ b/src/uipparser/Qt3DSUIPParser.h
@@ -131,7 +131,8 @@ protected:
virtual ~IUIPParser() {}
public: // Parse UIP file
virtual BOOL Load(IPresentation &inPresentation,
- NVConstDataRef<SElementAttributeReference> inStateReferences) = 0;
+ NVConstDataRef<SElementAttributeReference> inStateReferences,
+ bool initInRenderThread) = 0;
virtual qt3dsdm::IDOMReader &GetDOMReader() = 0;
virtual IRuntimeMetaData &GetMetaData() = 0;
// Mapping back from file id to element id, needed to hook elements up to their respective
diff --git a/src/uipparser/Qt3DSUIPParserImpl.cpp b/src/uipparser/Qt3DSUIPParserImpl.cpp
index a2f3c7c..b899248 100644
--- a/src/uipparser/Qt3DSUIPParserImpl.cpp
+++ b/src/uipparser/Qt3DSUIPParserImpl.cpp
@@ -514,7 +514,8 @@ CUIPParserImpl::~CUIPParserImpl()
* @return a flag indicating whether or not we successfully loaded the file
*/
BOOL CUIPParserImpl::Load(IPresentation &inPresentation,
- NVConstDataRef<SElementAttributeReference> inStateReferences)
+ NVConstDataRef<SElementAttributeReference> inStateReferences,
+ bool initInRenderThread)
{
m_CurrentPresentation = &inPresentation;
if (!m_DOMReader) {
@@ -582,7 +583,7 @@ BOOL CUIPParserImpl::Load(IPresentation &inPresentation,
// Now we are ready to load the scene graph
if (theLoadResult)
- theLoadResult &= LoadGraph(inPresentation, *m_DOMReader);
+ theLoadResult &= LoadGraph(inPresentation, *m_DOMReader, initInRenderThread);
if (theLoadResult)
theLoadResult &= LoadLogic(inPresentation, *m_DOMReader);
@@ -673,7 +674,8 @@ BOOL CUIPParserImpl::LoadClasses(IPresentation & /*inPresentation*/, IDOMReader
return true;
}
-BOOL CUIPParserImpl::LoadGraph(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader)
+BOOL CUIPParserImpl::LoadGraph(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader,
+ bool initInRenderThread)
{
IDOMReader::Scope __childScope(inReader);
@@ -683,7 +685,7 @@ BOOL CUIPParserImpl::LoadGraph(IPresentation &inPresentation, qt3dsdm::IDOMReade
bool theLoadResult = inReader.MoveToFirstChild("Graph");
if (theLoadResult) {
- theLoadResult &= LoadSceneGraph(inPresentation, inReader);
+ theLoadResult &= LoadSceneGraph(inPresentation, inReader, nullptr, initInRenderThread);
if (theLoadResult)
PatchSceneElementRef();
}
@@ -1009,7 +1011,8 @@ EElementType GetElementType(const char *inType)
* @return a flag indicating whether or not we successfully loaded the file
*/
BOOL CUIPParserImpl::LoadSceneGraph(IPresentation &inPresentation, IDOMReader &inReader,
- qt3ds::runtime::element::SElement *inNewStyleParent)
+ qt3ds::runtime::element::SElement *inNewStyleParent,
+ bool initInRenderThread)
{
IDOMReader::Scope __childScope(inReader);
IScriptBridge *theScriptBridgeQml = inPresentation.GetScriptBridgeQml();
@@ -1141,10 +1144,10 @@ BOOL CUIPParserImpl::LoadSceneGraph(IPresentation &inPresentation, IDOMReader &i
if (isBehavior) {
if (theFileString.find(".qml") != eastl::string::npos) {
theScriptBridgeQml->LoadScript(&inPresentation, &theNewElem,
- theFileString.c_str());
+ theFileString.c_str(), initInRenderThread);
}
}
- LoadSceneGraph(inPresentation, inReader, &theNewElem);
+ LoadSceneGraph(inPresentation, inReader, &theNewElem, initInRenderThread);
}
return true;
diff --git a/src/uipparser/Qt3DSUIPParserImpl.h b/src/uipparser/Qt3DSUIPParserImpl.h
index bca984b..3c44e21 100644
--- a/src/uipparser/Qt3DSUIPParserImpl.h
+++ b/src/uipparser/Qt3DSUIPParserImpl.h
@@ -527,7 +527,8 @@ public: // Construction
public: // Parse UIP file
BOOL Load(IPresentation &inPresentation,
- NVConstDataRef<SElementAttributeReference> inStateReferences) override;
+ NVConstDataRef<SElementAttributeReference> inStateReferences,
+ bool initInRenderThread) override;
qt3dsdm::IDOMReader &GetDOMReader() override;
IRuntimeMetaData &GetMetaData() override;
SElementAndType GetElementForID(const char *inStringId) override;
@@ -549,9 +550,11 @@ public: // Parse UIP file
protected: // Operation
BOOL LoadProjectSettings(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader);
BOOL LoadClasses(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader);
- BOOL LoadGraph(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader);
+ BOOL LoadGraph(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader,
+ bool initInRenderThread);
BOOL LoadSceneGraph(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader,
- qt3ds::runtime::element::SElement *inNewStyleParent = NULL);
+ qt3ds::runtime::element::SElement *inNewStyleParent,
+ bool initInRenderThread);
BOOL LoadLogic(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader);
BOOL LoadStateGraph(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader);
diff --git a/src/viewer/Qt3DSViewerApp.cpp b/src/viewer/Qt3DSViewerApp.cpp
index 1402ef0..e7b153c 100644
--- a/src/viewer/Qt3DSViewerApp.cpp
+++ b/src/viewer/Qt3DSViewerApp.cpp
@@ -390,7 +390,7 @@ void Q3DSViewerApp::setOffscreenId(int offscreenID)
bool Q3DSViewerApp::InitializeApp(int winWidth, int winHeight, const QSurfaceFormat &format,
int offscreenID, const QString &source,
const QStringList &variantList,
- bool delayedLoading,
+ bool delayedLoading, bool initInRenderThread,
qt3ds::Qt3DSAssetVisitor *assetVisitor)
{
bool hasValidPresentationFile = !source.isEmpty();
@@ -427,7 +427,8 @@ bool Q3DSViewerApp::InitializeApp(int winWidth, int winHeight, const QSurfaceFor
return false;
}
- bool success = m_Impl.m_view->InitializeGraphics(format, delayedLoading);
+ bool success = m_Impl.m_view->InitializeGraphics(format, delayedLoading,
+ initInRenderThread);
if (!success) {
m_Impl.m_error = QObject::tr("Viewer launch failure! Failed to load: '%1'").arg(source);
m_Impl.m_error.append("\n");
@@ -435,28 +436,8 @@ bool Q3DSViewerApp::InitializeApp(int winWidth, int winHeight, const QSurfaceFor
return false;
}
- // Connect signals
- connect(m_Impl.m_view->signalProxy(),
- &QRuntimeViewSignalProxy::SigSlideEntered, this, &Q3DSViewerApp::SigSlideEntered);
- connect(m_Impl.m_view->signalProxy(),
- &QRuntimeViewSignalProxy::SigSlideExited, this, &Q3DSViewerApp::SigSlideExited);
- connect(m_Impl.m_view->signalProxy(),
- &QRuntimeViewSignalProxy::SigCustomSignal, this, &Q3DSViewerApp::SigCustomSignal);
- connect(m_Impl.m_view->signalProxy(), &QRuntimeViewSignalProxy::SigDataOutputValueUpdated,
- this, &Q3DSViewerApp::SigDataOutputValueUpdated);
- QMetaObject::Connection *presReadyconn = new QMetaObject::Connection();
- *presReadyconn = connect(m_Impl.m_view->signalProxy(),
- &QRuntimeViewSignalProxy::SigPresentationReady, [&, presReadyconn]{
- // We receive presentation ready signal from runtime when animations and properties
- // have been updated.
- Q_EMIT SigPresentationReady();
- disconnect(*presReadyconn);
- delete presReadyconn;
- });
- connect(m_Impl.m_view->signalProxy(), &QRuntimeViewSignalProxy::SigElementsCreated, this,
- &Q3DSViewerApp::SigElementsCreated);
- connect(m_Impl.m_view->signalProxy(), &QRuntimeViewSignalProxy::SigMaterialsCreated, this,
- &Q3DSViewerApp::SigMaterialsCreated);
+ if (initInRenderThread)
+ this->connectSignals();
Resize(winWidth, winHeight);
@@ -465,6 +446,42 @@ bool Q3DSViewerApp::InitializeApp(int winWidth, int winHeight, const QSurfaceFor
return true;
}
+void Q3DSViewerApp::connectSignals()
+{
+ if (!m_Impl.m_view)
+ return;
+
+ m_Impl.m_view->connectSignals();
+
+ connect(m_Impl.m_view->signalProxy(),
+ &QRuntimeViewSignalProxy::SigSlideEntered, this, &Q3DSViewerApp::SigSlideEntered);
+ connect(m_Impl.m_view->signalProxy(),
+ &QRuntimeViewSignalProxy::SigSlideExited, this, &Q3DSViewerApp::SigSlideExited);
+ connect(m_Impl.m_view->signalProxy(),
+ &QRuntimeViewSignalProxy::SigCustomSignal, this, &Q3DSViewerApp::SigCustomSignal);
+ connect(m_Impl.m_view->signalProxy(), &QRuntimeViewSignalProxy::SigDataOutputValueUpdated,
+ this, &Q3DSViewerApp::SigDataOutputValueUpdated);
+ QMetaObject::Connection *presReadyconn = new QMetaObject::Connection();
+ *presReadyconn = connect(m_Impl.m_view->signalProxy(),
+ &QRuntimeViewSignalProxy::SigPresentationReady, [&, presReadyconn]{
+ // We receive presentation ready signal from runtime when animations and properties
+ // have been updated.
+ Q_EMIT SigPresentationReady();
+ disconnect(*presReadyconn);
+ delete presReadyconn;
+ });
+ connect(m_Impl.m_view->signalProxy(), &QRuntimeViewSignalProxy::SigElementsCreated, this,
+ &Q3DSViewerApp::SigElementsCreated);
+ connect(m_Impl.m_view->signalProxy(), &QRuntimeViewSignalProxy::SigMaterialsCreated, this,
+ &Q3DSViewerApp::SigMaterialsCreated);
+}
+
+void Q3DSViewerApp::finishAsyncInit()
+{
+ connectSignals();
+ m_Impl.m_view->finishAsyncInit();
+}
+
bool Q3DSViewerApp::IsInitialised(void)
{
return m_Impl.m_view != nullptr && m_Impl.m_appInitSuccessful;
diff --git a/src/viewer/Qt3DSViewerApp.h b/src/viewer/Qt3DSViewerApp.h
index 3086d55..153f9d7 100644
--- a/src/viewer/Qt3DSViewerApp.h
+++ b/src/viewer/Qt3DSViewerApp.h
@@ -219,9 +219,11 @@ public:
bool InitializeApp(int winWidth, int winHeight, const QSurfaceFormat& format,
int offscreenID, const QString &source,
const QStringList &variantList,
- bool delayedLoading,
+ bool delayedLoading, bool initInRenderThread,
qt3ds::Qt3DSAssetVisitor *assetVisitor = nullptr);
+ void connectSignals();
+ void finishAsyncInit();
bool IsInitialised(void);
void setOffscreenId(int offscreenID);
diff --git a/tools/viewer/viewer.pro b/tools/viewer/viewer.pro
index 927100f..fc750b7 100644
--- a/tools/viewer/viewer.pro
+++ b/tools/viewer/viewer.pro
@@ -21,6 +21,7 @@ SOURCES += \
$$PWD/../../src/api/studio3dqml/q3dsstudio3d.cpp \
$$PWD/../../src/api/studio3dqml/q3dsrenderer.cpp \
$$PWD/../../src/api/studio3dqml/q3dspresentationitem.cpp \
+ $$PWD/../../src/api/studio3dqml/q3dsruntimeinitializerthread.cpp \
main.cpp \
viewer.cpp \
remotedeploymentreceiver.cpp
@@ -29,6 +30,7 @@ HEADERS += \
$$PWD/../../src/api/studio3dqml/q3dsstudio3d_p.h \
$$PWD/../../src/api/studio3dqml/q3dsrenderer_p.h \
$$PWD/../../src/api/studio3dqml/q3dspresentationitem_p.h \
+ $$PWD/../../src/api/studio3dqml/q3dsruntimeinitializerthread_p.h \
viewer.h \
remotedeploymentreceiver.h