diff options
author | Antti Määttä <antti.maatta@qt.io> | 2019-02-15 14:56:54 +0200 |
---|---|---|
committer | Antti Määttä <antti.maatta@qt.io> | 2019-03-12 07:02:04 +0000 |
commit | 63ec9f17ed1cf4da27015244f97bb161e51949ce (patch) | |
tree | 7bc84ea4f0e85786a678ce0f14d0f4cbf9f662d5 | |
parent | 7bc264b20fe1e707ab5b1ce248463a6365db0d06 (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.cpp | 13 | ||||
-rw-r--r-- | src/runtime/q3dscustommaterialgenerator_p.h | 4 | ||||
-rw-r--r-- | src/runtime/q3dsdefaultmaterialgenerator.cpp | 9 | ||||
-rw-r--r-- | src/runtime/q3dsdefaultmaterialgenerator_p.h | 4 | ||||
-rw-r--r-- | src/runtime/q3dsengine.cpp | 136 | ||||
-rw-r--r-- | src/runtime/q3dsengine_p.h | 71 | ||||
-rw-r--r-- | src/runtime/q3dsimagemanager.cpp | 41 | ||||
-rw-r--r-- | src/runtime/q3dsimagemanager_p.h | 3 | ||||
-rw-r--r-- | src/runtime/q3dsscenemanager.cpp | 112 | ||||
-rw-r--r-- | src/runtime/q3dsscenemanager_p.h | 9 |
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 *> ¶ms, const QVector<Q3DSLightNode *> &lights, Q3DSLayerNode *layer3DS, const Q3DSMaterial::Pass &pass) +Qt3DRender::QMaterial *Q3DSCustomMaterialGenerator::generateMaterial( + ParentChildPairs *pairs, Q3DSCustomMaterialInstance *customMaterial, + Q3DSReferencedMaterial *referencedMaterial, const QVector<Qt3DRender::QParameter *> ¶ms, + 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 *> ¶ms, 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 *> ¶ms, 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 *> ¶ms, 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 ¶ms); @@ -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; |