summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntti Määttä <antti.maatta@qt.io>2019-02-15 14:56:54 +0200
committerAntti Määttä <antti.maatta@qt.io>2019-03-12 07:02:04 +0000
commit63ec9f17ed1cf4da27015244f97bb161e51949ce (patch)
tree7bc84ea4f0e85786a678ce0f14d0f4cbf9f662d5
parent7bc264b20fe1e707ab5b1ce248463a6365db0d06 (diff)
Load subpresentations asynchronously
Task-numer: QT3DS-2664 Change-Id: I612d81f08681eec1a396c1f48b75ca02cc12e8bf Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io> Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io>
-rw-r--r--src/runtime/q3dscustommaterialgenerator.cpp13
-rw-r--r--src/runtime/q3dscustommaterialgenerator_p.h4
-rw-r--r--src/runtime/q3dsdefaultmaterialgenerator.cpp9
-rw-r--r--src/runtime/q3dsdefaultmaterialgenerator_p.h4
-rw-r--r--src/runtime/q3dsengine.cpp136
-rw-r--r--src/runtime/q3dsengine_p.h71
-rw-r--r--src/runtime/q3dsimagemanager.cpp41
-rw-r--r--src/runtime/q3dsimagemanager_p.h3
-rw-r--r--src/runtime/q3dsscenemanager.cpp112
-rw-r--r--src/runtime/q3dsscenemanager_p.h9
10 files changed, 337 insertions, 65 deletions
diff --git a/src/runtime/q3dscustommaterialgenerator.cpp b/src/runtime/q3dscustommaterialgenerator.cpp
index 23da459..e85eaff 100644
--- a/src/runtime/q3dscustommaterialgenerator.cpp
+++ b/src/runtime/q3dscustommaterialgenerator.cpp
@@ -29,6 +29,7 @@
#include "q3dscustommaterialgenerator_p.h"
#include "q3dsdefaultmaterialgenerator_p.h"
+#include "q3dsengine_p.h"
#include <Qt3DCore/QEntity>
#include <Qt3DRender/QMaterial>
@@ -48,7 +49,11 @@
QT_BEGIN_NAMESPACE
-Qt3DRender::QMaterial *Q3DSCustomMaterialGenerator::generateMaterial(Q3DSCustomMaterialInstance *customMaterial, Q3DSReferencedMaterial *referencedMaterial, const QVector<Qt3DRender::QParameter *> &params, const QVector<Q3DSLightNode *> &lights, Q3DSLayerNode *layer3DS, const Q3DSMaterial::Pass &pass)
+Qt3DRender::QMaterial *Q3DSCustomMaterialGenerator::generateMaterial(
+ ParentChildPairs *pairs, Q3DSCustomMaterialInstance *customMaterial,
+ Q3DSReferencedMaterial *referencedMaterial, const QVector<Qt3DRender::QParameter *> &params,
+ const QVector<Q3DSLightNode *> &lights, Q3DSLayerNode *layer3DS,
+ const Q3DSMaterial::Pass &pass)
{
Qt3DRender::QMaterial *material = new Qt3DRender::QMaterial;
Qt3DRender::QEffect *effect = new Qt3DRender::QEffect;
@@ -70,7 +75,11 @@ Qt3DRender::QMaterial *Q3DSCustomMaterialGenerator::generateMaterial(Q3DSCustomM
// The returned program may be a cached instance, ensure it is not parented
// to the QMaterial by parenting it to something else now.
- shaderProgram->setParent(layerData->entity);
+ if (pairs)
+ pairs->addPair(layerData->entity, shaderProgram);
+ else
+ shaderProgram->setParent(layerData->entity);
+
// ### TODO This is does not take into consideration anything specified by the custom material pass
for (Qt3DRender::QRenderPass *pass : Q3DSSceneManager::standardRenderPasses(shaderProgram,
layer3DS,
diff --git a/src/runtime/q3dscustommaterialgenerator_p.h b/src/runtime/q3dscustommaterialgenerator_p.h
index 9acc732..78bc106 100644
--- a/src/runtime/q3dscustommaterialgenerator_p.h
+++ b/src/runtime/q3dscustommaterialgenerator_p.h
@@ -50,11 +50,13 @@ namespace Qt3DRender {
class QParameter;
class QMaterial;
}
+struct ParentChildPairs;
class Q3DSCustomMaterialGenerator
{
public:
- Qt3DRender::QMaterial *generateMaterial(Q3DSCustomMaterialInstance *customMaterial,
+ Qt3DRender::QMaterial *generateMaterial(ParentChildPairs *pairs,
+ Q3DSCustomMaterialInstance *customMaterial,
Q3DSReferencedMaterial *referencedMaterial,
const QVector<Qt3DRender::QParameter *> &params,
const QVector<Q3DSLightNode *> &lights,
diff --git a/src/runtime/q3dsdefaultmaterialgenerator.cpp b/src/runtime/q3dsdefaultmaterialgenerator.cpp
index 9a2fef9..6056492 100644
--- a/src/runtime/q3dsdefaultmaterialgenerator.cpp
+++ b/src/runtime/q3dsdefaultmaterialgenerator.cpp
@@ -42,6 +42,7 @@
#include "q3dsutils_p.h"
#include "q3dslogging_p.h"
#include "q3dsgraphicslimits_p.h"
+#include "q3dsengine_p.h"
#include "shadergenerator/q3dsshadermanager_p.h"
@@ -87,7 +88,8 @@ QT_BEGIN_NAMESPACE
// vec2 attr_uv0
// Caller takes ownership everything generated in the method
-Qt3DRender::QMaterial *Q3DSDefaultMaterialGenerator::generateMaterial(Q3DSDefaultMaterial *defaultMaterial,
+Qt3DRender::QMaterial *Q3DSDefaultMaterialGenerator::generateMaterial(ParentChildPairs *pairs,
+ Q3DSDefaultMaterial *defaultMaterial,
Q3DSReferencedMaterial *referencedMaterial,
const QVector<Qt3DRender::QParameter *> &params,
const QVector<Q3DSLightNode*> &lights,
@@ -112,7 +114,10 @@ Qt3DRender::QMaterial *Q3DSDefaultMaterialGenerator::generateMaterial(Q3DSDefaul
// The returned program may be a cached instance, ensure it is not parented
// to the QMaterial by parenting it to something else now.
- shaderProgram->setParent(layerData->entity);
+ if (pairs)
+ pairs->addPair(layerData->entity, shaderProgram);
+ else
+ shaderProgram->setParent(layerData->entity);
for (Qt3DRender::QRenderPass *pass : Q3DSSceneManager::standardRenderPasses(shaderProgram,
layer3DS,
diff --git a/src/runtime/q3dsdefaultmaterialgenerator_p.h b/src/runtime/q3dsdefaultmaterialgenerator_p.h
index e384d18..3355acc 100644
--- a/src/runtime/q3dsdefaultmaterialgenerator_p.h
+++ b/src/runtime/q3dsdefaultmaterialgenerator_p.h
@@ -51,11 +51,13 @@ class QParameter;
class QMaterial;
class QTechnique;
}
+struct ParentChildPairs;
class Q3DSDefaultMaterialGenerator
{
public:
- Qt3DRender::QMaterial *generateMaterial(Q3DSDefaultMaterial *defaultMaterial,
+ Qt3DRender::QMaterial *generateMaterial(ParentChildPairs *pairs,
+ Q3DSDefaultMaterial *defaultMaterial,
Q3DSReferencedMaterial *referencedMaterial,
const QVector<Qt3DRender::QParameter *> &params,
const QVector<Q3DSLightNode *> &lights,
diff --git a/src/runtime/q3dsengine.cpp b/src/runtime/q3dsengine.cpp
index 6c7be72..005ad7e 100644
--- a/src/runtime/q3dsengine.cpp
+++ b/src/runtime/q3dsengine.cpp
@@ -49,6 +49,7 @@
#include <QOpenGLFunctions>
#include <QOpenGLTexture>
#include <QOffscreenSurface>
+#include <QtConcurrent>
#include <Qt3DCore/QEntity>
#include <Qt3DRender/QRenderAspect>
@@ -717,6 +718,8 @@ void Q3DSEngine::finalizePresentations()
m_uipPresentations[0].q3dscene.renderSettings->setRenderPolicy(m_onDemandRendering ?
Qt3DRender::QRenderSettings::OnDemand : Qt3DRender::QRenderSettings::Always);
+ finishAsyncLoad(false);
+
for (const UipPresentation &pres : m_uipPresentations) {
if (pres.sceneManager)
pres.sceneManager->prepareAnimators();
@@ -834,6 +837,89 @@ Q3DSSubPresentation Q3DSEngine::loadSubUipPresentation(const QString &subPresId)
return sp;
}
+void Q3DSEngine::SceneLoaderAsync::reparentChildren()
+{
+ for (auto pair : qAsConst(m_parentChildPairs)) {
+ Qt3DCore::QNode *parent = static_cast<Qt3DCore::QNode *>(pair.first);
+ Qt3DCore::QNode *child = static_cast<Qt3DCore::QNode *>(pair.second);
+ if (parent && child)
+ child->setParent(parent);
+ else
+ pair.second->setParent(pair.first);
+ }
+}
+
+void Q3DSEngine::beginAsyncLoad(Q3DSSubPresentation &sp, SceneLoaderAsync *loader)
+{
+ loader->sp = sp;
+ loader->targetThread = QThread::currentThread();
+ loader->future = QtConcurrent::run([this, loader] {
+ QElapsedTimer timer;
+ timer.start();
+ qCDebug(lcScene, "Begin loading subpresentation: %s", qPrintable(loader->pres->subPres.id));
+ if (!parseUipDocument(loader->pres)) {
+ Q3DSUtils::showMessage(QObject::tr("Failed to parse subpresentation"));
+ return;
+ }
+ buildSubUipPresentationScene(loader->pres, loader);
+ for (auto obj : qAsConst(loader->m_parentChildPairs)) {
+ if (obj.second->thread() != loader->targetThread) {
+ if (obj.second->parent()
+ && obj.second->parent()->thread() != loader->targetThread) {
+ QObject *parent = obj.second->parent();
+ while (parent->parent())
+ parent = parent->parent();
+ parent->moveToThread(loader->targetThread);
+ } else {
+ obj.second->moveToThread(loader->targetThread);
+ }
+ }
+ }
+ loader->sp = loader->pres->subPres;
+ qCDebug(lcScene, "Subpresentation %s loaded in %lld ms",
+ qPrintable(loader->pres->subPres.id), timer.elapsed());
+ });
+ m_asyncSceneLoaders.push_back(loader);
+}
+
+void Q3DSEngine::finishAsyncLoadForSubpresentation(const QString &name)
+{
+ for (auto &item : qAsConst(m_asyncSceneLoaders)) {
+ if (item->done == false && item->pres->subPres.id == name) {
+ item->future.waitForFinished();
+ item->done = true;
+ item->function();
+ return;
+ }
+ }
+}
+
+void Q3DSEngine::finishAsyncLoad(bool wait)
+{
+ if (wait) {
+ QElapsedTimer timer;
+ timer.start();
+ {
+ QFutureSynchronizer<void> sync;
+ for (auto &item : qAsConst(m_asyncSceneLoaders)) {
+ if (item->done == false)
+ sync.addFuture(item->future);
+ }
+ }
+ for (auto &item : qAsConst(m_asyncSceneLoaders)) {
+ item->done = true;
+ item->function();
+ }
+ } else {
+ for (auto &item : qAsConst(m_asyncSceneLoaders)) {
+ if (!item->done && item->future.isFinished()) {
+ item->done = true;
+ item->function();
+ }
+ }
+ }
+}
+
bool Q3DSEngine::loadSubUipPresentation(UipPresentation *pres)
{
Q_ASSERT(pres);
@@ -845,7 +931,7 @@ bool Q3DSEngine::loadSubUipPresentation(UipPresentation *pres)
return buildSubUipPresentationScene(pres);
}
-bool Q3DSEngine::buildSubUipPresentationScene(UipPresentation *pres)
+bool Q3DSEngine::buildSubUipPresentationScene(UipPresentation *pres, SceneLoaderAsync *loader)
{
Qt3DRender::QFrameGraphNode *fgParent = m_uipPresentations[0].q3dscene.subPresFrameGraphRoot;
Qt3DCore::QNode *entityParent = m_uipPresentations[0].q3dscene.rootEntity;
@@ -860,12 +946,24 @@ bool Q3DSEngine::buildSubUipPresentationScene(UipPresentation *pres)
params.outputDpr = 1;
params.engine = this;
- Qt3DRender::QRenderTargetSelector *rtSel = new Qt3DRender::QRenderTargetSelector(fgParent);
+ Qt3DRender::QRenderTargetSelector *rtSel;
+ if (loader) {
+ rtSel = new Qt3DRender::QRenderTargetSelector;
+ loader->addPair(fgParent, rtSel);
+ } else {
+ rtSel = new Qt3DRender::QRenderTargetSelector(fgParent);
+ }
+
Qt3DRender::QRenderTarget *rt = new Qt3DRender::QRenderTarget;
Qt3DRender::QRenderTargetOutput *color = new Qt3DRender::QRenderTargetOutput;
color->setAttachmentPoint(Qt3DRender::QRenderTargetOutput::Color0);
- pres->subPres.colorTex = new Qt3DRender::QTexture2D(entityParent);
+ if (!loader) {
+ pres->subPres.colorTex = new Qt3DRender::QTexture2D(entityParent);
+ } else {
+ pres->subPres.colorTex = new Qt3DRender::QTexture2D;
+ loader->addPair(entityParent, pres->subPres.colorTex);
+ }
pres->subPres.colorTex->setFormat(Qt3DRender::QAbstractTexture::RGBA8_UNorm);
pres->subPres.colorTex->setWidth(pres3DS->presentationWidth());
pres->subPres.colorTex->setHeight(pres3DS->presentationHeight());
@@ -877,7 +975,12 @@ bool Q3DSEngine::buildSubUipPresentationScene(UipPresentation *pres)
if (gfxLimits.packedDepthStencilBufferSupported) {
Qt3DRender::QRenderTargetOutput *ds = new Qt3DRender::QRenderTargetOutput;
ds->setAttachmentPoint(Qt3DRender::QRenderTargetOutput::DepthStencil);
- pres->subPres.depthOrDepthStencilTex = new Qt3DRender::QTexture2D(entityParent);
+ if (loader) {
+ pres->subPres.depthOrDepthStencilTex = new Qt3DRender::QTexture2D();
+ loader->addPair(entityParent, pres->subPres.depthOrDepthStencilTex);
+ } else {
+ pres->subPres.depthOrDepthStencilTex = new Qt3DRender::QTexture2D(entityParent);
+ }
pres->subPres.depthOrDepthStencilTex->setFormat(Qt3DRender::QAbstractTexture::D24S8);
pres->subPres.depthOrDepthStencilTex->setWidth(pres3DS->presentationWidth());
pres->subPres.depthOrDepthStencilTex->setHeight(pres3DS->presentationHeight());
@@ -888,7 +991,12 @@ bool Q3DSEngine::buildSubUipPresentationScene(UipPresentation *pres)
} else {
Qt3DRender::QRenderTargetOutput *depth = new Qt3DRender::QRenderTargetOutput;
depth->setAttachmentPoint(Qt3DRender::QRenderTargetOutput::Depth);
- pres->subPres.depthOrDepthStencilTex = new Qt3DRender::QTexture2D(entityParent);
+ if (loader) {
+ pres->subPres.depthOrDepthStencilTex = new Qt3DRender::QTexture2D();
+ loader->addPair(entityParent, pres->subPres.depthOrDepthStencilTex);
+ } else {
+ pres->subPres.depthOrDepthStencilTex = new Qt3DRender::QTexture2D(entityParent);
+ }
pres->subPres.depthOrDepthStencilTex->setFormat(Qt3DRender::QAbstractTexture::D16);
pres->subPres.depthOrDepthStencilTex->setWidth(pres3DS->presentationWidth());
pres->subPres.depthOrDepthStencilTex->setHeight(pres3DS->presentationHeight());
@@ -898,7 +1006,12 @@ bool Q3DSEngine::buildSubUipPresentationScene(UipPresentation *pres)
rt->addOutput(depth);
Qt3DRender::QRenderTargetOutput *stencil = new Qt3DRender::QRenderTargetOutput;
stencil->setAttachmentPoint(Qt3DRender::QRenderTargetOutput::Stencil);
- pres->subPres.stencilTex = new Qt3DRender::QTexture2D(entityParent);
+ if (loader) {
+ pres->subPres.stencilTex = new Qt3DRender::QTexture2D();
+ loader->addPair(entityParent, pres->subPres.stencilTex);
+ } else {
+ pres->subPres.stencilTex = new Qt3DRender::QTexture2D(entityParent);
+ }
pres->subPres.stencilTex->setFormat(Qt3DRender::QAbstractTexture::TextureFormat(0x1901)); // GL_STENCIL_INDEX
pres->subPres.stencilTex->setWidth(pres3DS->presentationWidth());
pres->subPres.stencilTex->setHeight(pres3DS->presentationHeight());
@@ -910,8 +1023,7 @@ bool Q3DSEngine::buildSubUipPresentationScene(UipPresentation *pres)
rtSel->setTarget(rt);
params.frameGraphRoot = rtSel;
-
- QScopedPointer<Q3DSSceneManager> sceneManager(new Q3DSSceneManager);
+ QScopedPointer<Q3DSSceneManager> sceneManager(new Q3DSSceneManager(loader));
pres->q3dscene = sceneManager->buildScene(pres->presentation, params);
if (!pres->q3dscene.rootEntity) {
Q3DSUtils::showMessage(QObject::tr("Failed to build Qt3D scene for subpresentation"));
@@ -920,7 +1032,10 @@ bool Q3DSEngine::buildSubUipPresentationScene(UipPresentation *pres)
pres->sceneManager = sceneManager.take();
pres->subPres.sceneManager = pres->sceneManager;
- pres->q3dscene.rootEntity->setParent(entityParent);
+ if (!loader)
+ pres->q3dscene.rootEntity->setParent(entityParent);
+ else
+ loader->addPair(entityParent, pres->q3dscene.rootEntity);
return true;
}
@@ -2008,7 +2123,7 @@ QRect Q3DSEngine::calculateViewport(const QSize &surfaceSize, const QSize &prese
Q3DSGraphObject *Q3DSEngine::findObjectByHashIdOrNameOrPath(Q3DSGraphObject *thisObject,
Q3DSUipPresentation *defaultPresentation,
const QString &idOrNameOrPath,
- Q3DSUipPresentation **actualPresentation) const
+ Q3DSUipPresentation **actualPresentation)
{
Q3DSUipPresentation *pres = defaultPresentation;
QString attr = idOrNameOrPath;
@@ -2016,6 +2131,7 @@ Q3DSGraphObject *Q3DSEngine::findObjectByHashIdOrNameOrPath(Q3DSGraphObject *thi
const QStringList presentationPathPair = attr.split(QLatin1Char(':'), QString::SkipEmptyParts);
if (presentationPathPair.count() < 2)
return nullptr;
+ finishAsyncLoadForSubpresentation(presentationPathPair[0]);
pres = presentationByName(presentationPathPair[0]);
attr = presentationPathPair[1];
}
diff --git a/src/runtime/q3dsengine_p.h b/src/runtime/q3dsengine_p.h
index 386f95c..ab85fc2 100644
--- a/src/runtime/q3dsengine_p.h
+++ b/src/runtime/q3dsengine_p.h
@@ -92,6 +92,16 @@ struct Q3DSV_PRIVATE_EXPORT Q3DSRenderLoopStats
float quickDeltaMs = 0;
};
+struct ParentChildPairs
+{
+ QVector<QPair<QObject *, QObject *>> m_parentChildPairs;
+
+ void addPair(QObject *parent, QObject *child)
+ {
+ m_parentChildPairs.push_back(QPair<QObject *, QObject *>(parent, child));
+ }
+};
+
class Q3DSV_PRIVATE_EXPORT Q3DSEngine : public QObject
{
Q_OBJECT
@@ -222,7 +232,7 @@ public:
Q3DSGraphObject *findObjectByHashIdOrNameOrPath(Q3DSGraphObject *thisObject,
Q3DSUipPresentation *defaultPresentation,
const QString &idOrNameOrPath,
- Q3DSUipPresentation **actualPresentation = nullptr) const;
+ Q3DSUipPresentation **actualPresentation = nullptr);
QString makePath(Q3DSGraphObject *obj) const;
Qt3DCore::QNodeId layerTextureNodeId(Q3DSLayerNode *layer3DS) const;
@@ -232,6 +242,35 @@ public:
Q3DSSubPresentation loadSubUipPresentation(const QString &subPresId);
+ template <typename FinalizeFunc, typename... Params>
+ Q3DSSubPresentation loadSubUipPresentation(const QString &subPresId, FinalizeFunc finalize, Params... params)
+ {
+ Q3DSSubPresentation sp;
+ SceneLoaderAsync *loader = nullptr;
+ UipPresentation *uip = nullptr;
+
+ for (int i = 0; i < m_uipPresentations.count(); ++i) {
+ if (m_uipPresentations[i].subPres.id == subPresId) {
+ uip = &m_uipPresentations[i];
+ break;
+ }
+ }
+ if (!uip)
+ return sp;
+
+ loader = new SceneLoaderAsync;
+ loader->function = [loader, finalize, params...]() {
+ loader->reparentChildren();
+ finalize(&loader->sp, params...);
+ };
+
+ loader->pres = uip;
+ beginAsyncLoad(sp, loader);
+ return sp;
+ }
+
+ void finishAsyncLoad(bool wait = true);
+
void createAspectEngine();
public Q_SLOTS:
@@ -270,12 +309,38 @@ private:
Qt3DRender::Quick::QScene2D *scene2d = nullptr;
};
+ struct SceneLoaderAsync : public ParentChildPairs
+ {
+ QThread *targetThread;
+ QFuture<void> future;
+ UipPresentation *pres;
+ std::function<void()> function;
+ Q3DSSubPresentation sp;
+ bool done;
+
+ SceneLoaderAsync()
+ : targetThread(nullptr), pres(nullptr), done(false)
+ {}
+
+ SceneLoaderAsync(const SceneLoaderAsync &loader)
+ : ParentChildPairs(loader), targetThread(loader.targetThread),
+ future(loader.future), pres(loader.pres), function(loader.function),
+ sp(loader.sp), done(loader.done)
+ {}
+
+ void reparentChildren();
+ };
+
+ void beginAsyncLoad(Q3DSSubPresentation &sp, SceneLoaderAsync *loader);
+ void finishAsyncLoadForSubpresentation(const QString &name);
+ void reparentScene(SceneLoaderAsync *loader);
+
bool loadPresentations();
void finalizePresentations();
bool loadUipPresentation(UipPresentation *pres);
bool buildUipPresentationScene(UipPresentation *pres);
bool loadSubUipPresentation(UipPresentation *pres);
- bool buildSubUipPresentationScene(UipPresentation *pres);
+ bool buildSubUipPresentationScene(UipPresentation *pres, SceneLoaderAsync *loader = nullptr);
bool loadSubQmlPresentation(QmlPresentation *pres);
bool parseUipDocument(UipPresentation *pres);
@@ -338,6 +403,8 @@ private:
QMutex m_renderLoopStatsMutex;
float m_quickDeltaSum = 0;
int m_quickDeltaCount = 0;
+
+ QVector<SceneLoaderAsync *> m_asyncSceneLoaders;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(Q3DSEngine::Flags)
diff --git a/src/runtime/q3dsimagemanager.cpp b/src/runtime/q3dsimagemanager.cpp
index 4788ac9..f0eba05 100644
--- a/src/runtime/q3dsimagemanager.cpp
+++ b/src/runtime/q3dsimagemanager.cpp
@@ -47,7 +47,7 @@ QMutex Q3DSImageManager::s_loadMutex;
Q3DSImageManager::Q3DSImageManager()
{
- m_threadPool.setMaxThreadCount(qMax(1, QThread::idealThreadCount() - 2));
+ m_threadPool.setMaxThreadCount(qMax(2, QThread::idealThreadCount() - 2));
}
Q3DSImageManager &Q3DSImageManager::instance()
@@ -258,22 +258,37 @@ QVector<Qt3DRender::QTextureImageDataPtr> Q3DSImageManager::load(const QUrl &sou
return result;
}
-void Q3DSImageManager::finishAsyncLoad()
+void Q3DSImageManager::finishAsyncLoad(bool wait)
{
if (m_setSourceAsync.isEmpty())
return;
- QElapsedTimer t;
- t.start();
- {
- QFutureSynchronizer<void> sync;
- for (auto &item : qAsConst(m_setSourceAsync))
- sync.addFuture(item.future);
+
+ if (wait) {
+ QElapsedTimer t;
+ t.start();
+ {
+ QFutureSynchronizer<void> sync;
+ for (auto &item : qAsConst(m_setSourceAsync))
+ sync.addFuture(item.future);
+ }
+ qCDebug(lcPerf, "Finish async image loading took %lld ms", t.elapsed());
+ }
+ bool allDone = true;
+ for (int i = 0; i < m_setSourceAsync.size(); ++i) {
+ auto &item = m_setSourceAsync[i];
+ if (!item.done) {
+ if (item.future.isFinished() && item.tex->thread() == QThread::currentThread()) {
+ item.done = true;
+ setSource(item.tex, item.source, item.preferKtx, false);
+ } else {
+ allDone = false;
+ }
+ }
+ }
+ if (allDone) {
+ m_setSourceAsync.clear();
+ m_loadImageAsync.clear();
}
- qCDebug(lcPerf, "Finish async image loading took %lld ms", t.elapsed());
- for (auto &item : qAsConst(m_setSourceAsync))
- setSource(item.tex, item.source, item.preferKtx, false);
- m_setSourceAsync.clear();
- m_loadImageAsync.clear();
}
static bool isAsyncImageLoadingEnabled()
diff --git a/src/runtime/q3dsimagemanager_p.h b/src/runtime/q3dsimagemanager_p.h
index ac768bc..765e01e 100644
--- a/src/runtime/q3dsimagemanager_p.h
+++ b/src/runtime/q3dsimagemanager_p.h
@@ -88,7 +88,7 @@ public:
qint64 ioTimeMsecs() const { return m_ioTime; }
qint64 iblTimeMsecs() const { return m_iblTime; }
- void finishAsyncLoad();
+ void finishAsyncLoad(bool wait = true);
private:
QVector<Qt3DRender::QTextureImageDataPtr> load(const QUrl &source, ImageFlags flags, bool *wasCached);
@@ -111,6 +111,7 @@ private:
Qt3DRender::QAbstractTexture *tex = nullptr;
QUrl source;
bool preferKtx = false;
+ bool done = false;
};
QHash<Qt3DRender::QAbstractTexture *, TextureInfo> m_metadata;
diff --git a/src/runtime/q3dsscenemanager.cpp b/src/runtime/q3dsscenemanager.cpp
index 6c40962..060b43c 100644
--- a/src/runtime/q3dsscenemanager.cpp
+++ b/src/runtime/q3dsscenemanager.cpp
@@ -447,7 +447,7 @@ static const int LAYER_CACHING_THRESHOLD = 4;
*/
-Q3DSSceneManager::Q3DSSceneManager()
+Q3DSSceneManager::Q3DSSceneManager(ParentChildPairs *pairs)
: m_gfxLimits(Q3DS::graphicsLimits()),
m_matGen(new Q3DSDefaultMaterialGenerator),
m_customMaterialGen(new Q3DSCustomMaterialGenerator),
@@ -459,7 +459,8 @@ Q3DSSceneManager::Q3DSSceneManager()
m_glyphCacheManager(nullptr),
#endif
m_profiler(new Q3DSProfiler),
- m_inputManager(new Q3DSInputManager(this))
+ m_inputManager(new Q3DSInputManager(this)),
+ m_pairs(pairs)
{
if (Q3DSSlideUtils::useDragonWings())
m_slidePlayer = new Q3DSSlidePlayerNg(this);
@@ -813,6 +814,10 @@ Q3DSSceneManager::Scene Q3DSSceneManager::buildScene(Q3DSUipPresentation *presen
Qt3DLogic::QFrameAction *nodeUpdater = new Qt3DLogic::QFrameAction;
m_frameUpdater = new Q3DSFrameUpdater(this);
QObject::connect(nodeUpdater, &Qt3DLogic::QFrameAction::triggered, m_frameUpdater, &Q3DSFrameUpdater::frameAction);
+ if (m_pairs) {
+ m_pairs->addPair(m_rootEntity, nodeUpdater);
+ m_pairs->addPair(m_rootEntity, m_frameUpdater);
+ }
m_rootEntity->addComponent(nodeUpdater);
Qt3DRender::QRenderSettings *frameGraphComponent;
@@ -981,13 +986,15 @@ void Q3DSSceneManager::finalizeMainScene()
#endif
}
-void Q3DSSceneManager::loadSubUipPresentation(Q3DSSubPresentation *sp)
+void Q3DSSceneManager::finalizeSubpresentationLoading(Q3DSSubPresentation *sp)
{
- const QString id = sp->id;
- Q_ASSERT(!id.isEmpty());
- *sp = m_engine->loadSubUipPresentation(sp->id);
- sp->id = id;
if (sp->colorTex && sp->sceneManager) {
+ for (int i = 0; i < m_subPresentations.size(); ++i) {
+ if (m_subPresentations[i].id == sp->id) {
+ m_subPresentations[i] = *sp;
+ break;
+ }
+ }
sp->sceneManager->setSubPresentations(m_subPresentations);
if (!m_inSetSubPresentations) {
sp->sceneManager->prepareAnimators();
@@ -1004,6 +1011,12 @@ void Q3DSSceneManager::loadSubUipPresentation(Q3DSSubPresentation *sp)
}
}
+static bool isAsyncSubpresentationLoadingEnabled()
+{
+ static bool enabled = (qEnvironmentVariableIntValue("Q3DS_ASYNC_LOADING") & 8) > 0;
+ return enabled;
+}
+
void Q3DSSceneManager::updateSubPresentationHosts()
{
for (Q3DSLayerNode *layer3DS : m_pendingSubPresLayers) {
@@ -1012,25 +1025,39 @@ void Q3DSSceneManager::updateSubPresentationHosts()
auto it = std::find_if(m_subPresentations.begin(), m_subPresentations.end(),
[subPresId](const Q3DSSubPresentation &sp) { return sp.id == subPresId; });
if (it != m_subPresentations.end()) {
- if (!it->colorTex)
- loadSubUipPresentation(it);
- if (it->colorTex) {
- qCDebug(lcScene, "Directing subpresentation %s to layer %s", qPrintable(it->id), layer3DS->id().constData());
- Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
- layerData->eyeMono->layerTexture = it->colorTex;
+
+ auto setSubpresentationTolayer = [this](Q3DSLayerNode *layer, Q3DSSubPresentation *sp){
+ qCDebug(lcScene, "Directing subpresentation %s to layer %s", qPrintable(sp->id), layer->id().constData());
+ Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(layer->attached());
+ layerData->eyeMono->layerTexture = sp->colorTex;
layerData->eyeMono->compositorSourceParam->setValue(QVariant::fromValue(layerData->eyeMono->layerTexture));
- layerData->eyeLeft->layerTexture = it->colorTex;
- layerData->eyeRight->layerTexture = it->colorTex;
+ layerData->eyeLeft->layerTexture = sp->colorTex;
+ layerData->eyeRight->layerTexture = sp->colorTex;
layerData->eyeLeft->compositorSourceParam->setValue(QVariant::fromValue(layerData->eyeLeft->layerTexture));
layerData->eyeRight->compositorSourceParam->setValue(QVariant::fromValue(layerData->eyeRight->layerTexture));
layerData->updateSubPresentationSize();
+ };
+
+ if (!it->colorTex) {
+ if (isAsyncSubpresentationLoadingEnabled()) {
+ m_engine->loadSubUipPresentation(subPresId, [this, setSubpresentationTolayer](
+ Q3DSSubPresentation *sp, Q3DSLayerNode *layer) {
+ finalizeSubpresentationLoading(sp);
+ setSubpresentationTolayer(layer, sp);
+ }, layer3DS);
+ } else {
+ *it = m_engine->loadSubUipPresentation(subPresId);
+ finalizeSubpresentationLoading(it);
+ setSubpresentationTolayer(layer3DS, it);
+ }
+ } else {
+ setSubpresentationTolayer(layer3DS, it);
}
} else {
qCDebug(lcScene, "Subpresentation %s for layer %s not found",
qPrintable(subPresId), layer3DS->id().constData());
}
}
-
for (auto p : m_pendingSubPresImages)
setImageTextureFromSubPresentation(p.first, p.second);
@@ -1563,7 +1590,9 @@ void Q3DSSceneManager::buildLayer(Q3DSLayerNode *layer3DS,
// Generate Qt3D material components.
Q3DSUipPresentation::forAllModels(layer3DS->firstChild(),
- [this](Q3DSModelNode *model3DS) { buildModelMaterial(model3DS); },
+ [this](Q3DSModelNode *model3DS) {
+ buildModelMaterial(model3DS);
+ },
true); // include hidden ones too
// Set up effects.
@@ -5867,7 +5896,7 @@ void Q3DSSceneManager::buildModelMaterial(Q3DSModelNode *model3DS)
param->setParent(layerData->entity);
}
- sm.materialComponent = m_matGen->generateMaterial(defaultMaterial, sm.referencingMaterial, params, lightNodes, modelData->layer3DS);
+ sm.materialComponent = m_matGen->generateMaterial(m_pairs, defaultMaterial, sm.referencingMaterial, params, lightNodes, modelData->layer3DS);
sm.entity->addComponent(sm.materialComponent);
} else if (sm.resolvedMaterial->type() == Q3DSGraphObject::CustomMaterial) {
Q3DSCustomMaterialInstance *customMaterial = static_cast<Q3DSCustomMaterialInstance *>(sm.resolvedMaterial);
@@ -5948,7 +5977,7 @@ void Q3DSSceneManager::buildModelMaterial(Q3DSModelNode *model3DS)
if (!passes.isEmpty()) {
// ### TODO support more than one pass
auto pass = passes.first();
- sm.materialComponent = m_customMaterialGen->generateMaterial(customMaterial, sm.referencingMaterial, params, lightNodes, modelData->layer3DS, pass);
+ sm.materialComponent = m_customMaterialGen->generateMaterial(m_pairs, customMaterial, sm.referencingMaterial, params, lightNodes, modelData->layer3DS, pass);
} else {
qCDebug(lcScene, "Custom material %s has no passes. Using dummy material. Object %s will not show.",
customMaterial->id().constData(), model3DS->id().constData());
@@ -5972,6 +6001,7 @@ void Q3DSSceneManager::rebuildModelMaterial(Q3DSModelNode *model3DS)
for (Q3DSModelAttached::SubMesh &sm : modelData->subMeshes) {
if (sm.resolvedMaterial && sm.materialComponent) {
qCDebug(lcPerf, "Rebuilding material for %s (entity %p)", model3DS->id().constData(), sm.entity);
+
delete sm.materialComponent;
sm.materialComponent = nullptr;
}
@@ -6143,17 +6173,36 @@ void Q3DSSceneManager::setImageTextureFromSubPresentation(Qt3DRender::QParameter
auto it = std::find_if(m_subPresentations.begin(), m_subPresentations.end(),
[image](const Q3DSSubPresentation &sp) { return sp.id == image->subPresentation(); });
if (it != m_subPresentations.cend()) {
- if (!it->colorTex)
- loadSubUipPresentation(it);
- qCDebug(lcScene, "Directing subpresentation %s to image %s",
- qPrintable(image->subPresentation()), image->id().constData());
- sampler->setValue(QVariant::fromValue(it->colorTex));
- qCDebug(lcPerf, "Using a subpresentation as texture map (not as layer) makes layer caching in main presentation less efficient");
- // QML subpresentations will not have a scenemanager
- if (it->sceneManager)
- m_layerCacheDeps.insert(it->sceneManager);
- else
- m_hasQmlSubPresAsTextureMap = true;
+ auto handleSubpresentation = [this](
+ Q3DSSubPresentation *sp, Qt3DRender::QParameter *sampler, Q3DSImage *image) {
+ qCDebug(lcScene, "Directing subpresentation %s to image %s",
+ qPrintable(image->subPresentation()), image->id().constData());
+ sampler->setValue(QVariant::fromValue(sp->colorTex));
+ qCDebug(lcPerf, "Using a subpresentation as texture map (not as layer) makes layer caching in main presentation less efficient");
+ // QML subpresentations will not have a scenemanager
+ if (sp->sceneManager)
+ m_layerCacheDeps.insert(sp->sceneManager);
+ else
+ m_hasQmlSubPresAsTextureMap = true;
+ };
+ if (!it->colorTex) {
+ if (isAsyncSubpresentationLoadingEnabled()) {
+ m_engine->loadSubUipPresentation(image->subPresentation(),
+ [this, handleSubpresentation]
+ (Q3DSSubPresentation *sp,
+ Qt3DRender::QParameter *sampler,
+ Q3DSImage *image) {
+ finalizeSubpresentationLoading(sp);
+ handleSubpresentation(sp, sampler, image);
+ }, sampler, image);
+ } else {
+ *it = m_engine->loadSubUipPresentation(image->subPresentation());
+ finalizeSubpresentationLoading(it);
+ handleSubpresentation(it, sampler, image);
+ }
+ } else {
+ handleSubpresentation(it, sampler, image);
+ }
} else {
qCDebug(lcScene, "Subpresentation %s for image %s not found",
qPrintable(image->subPresentation()), image->id().constData());
@@ -8397,7 +8446,8 @@ void Q3DSSceneManager::syncScene()
for (Q3DSModelNode *model3DS : needsRebuild)
rebuildModelMaterial(model3DS);
- Q3DSImageManager::instance().finishAsyncLoad();
+ m_engine->finishAsyncLoad(false);
+ Q3DSImageManager::instance().finishAsyncLoad(false);
}
void Q3DSSceneManager::setPendingVisibilities()
diff --git a/src/runtime/q3dsscenemanager_p.h b/src/runtime/q3dsscenemanager_p.h
index ce189e5..4a0b2c0 100644
--- a/src/runtime/q3dsscenemanager_p.h
+++ b/src/runtime/q3dsscenemanager_p.h
@@ -51,6 +51,7 @@
#include <QQueue>
#include <QElapsedTimer>
#include <QMutex>
+#include <QFuture>
QT_BEGIN_NAMESPACE
@@ -74,6 +75,7 @@ class Q3DSConsoleCommands;
class Q3DSScenePicker;
struct Q3DSAnimator;
class Q3DSDataInput;
+struct ParentChildPairs;
namespace Qt3DCore {
class QEntity;
@@ -734,7 +736,7 @@ public:
Qt3DRender::QViewport *viewportRight = nullptr;
};
- Q3DSSceneManager();
+ Q3DSSceneManager(ParentChildPairs *pairs = nullptr);
~Q3DSSceneManager();
Scene buildScene(Q3DSUipPresentation *presentation, const SceneBuilderParams &params);
@@ -804,6 +806,7 @@ public:
Q3DSInputManager *inputManager() { return m_inputManager; }
Q3DSTextRenderer *textRenderer() const { return m_textRenderer; }
+ Q3DSEngine *engine() const { return m_engine; }
void setEyeDepthTextureEnabled(Q3DSLayerNode *layer3DS, Q3DSEyeData *eyeData, bool enabled);
void setDepthTextureEnabled(Q3DSLayerNode *layer3DS, bool enabled);
@@ -828,8 +831,9 @@ public:
private:
Q_DISABLE_COPY(Q3DSSceneManager)
+
void updateSubPresentationHosts();
- void loadSubUipPresentation(Q3DSSubPresentation *sp);
+ void finalizeSubpresentationLoading(Q3DSSubPresentation *sp);
void initSubTree(Q3DSGraphObject *subTreeRoot);
void updateStereoRenderTree(Q3DSLayerAttached *layerData);
Q3DSEyeData *buildEye(Q3DSLayerNode *layer3DS, Qt3DRender::QViewport *viewport);
@@ -1029,6 +1033,7 @@ private:
QVector<Qt3DCore::QEntity *> m_compositorEntities;
bool m_compositorEnabled = true;
QVector<ViewportSet> m_viewports;
+ ParentChildPairs *m_pairs = nullptr;
friend class Q3DSFrameUpdater;
friend class Q3DSProfiler;
friend class Q3DSSlidePlayerNg;