summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2020-10-28 11:28:32 +0100
committerPaul Lemire <paul.lemire@kdab.com>2020-11-05 08:10:28 +0100
commit46f6e8f9521fa8a3e94b000be16862ace30b65b9 (patch)
tree4865a2eb274361c23fe271f33ab9bf1c9b489cdd
parentdb1a22f00c85aa2d2dde3a19a3611f98e2f0da5f (diff)
Scene3DItem: release frontend/backend tree on destruction
We fully release the AspectEngine when the last of the threads between main/sg thread is destroyed. We do it that way as the destruction order of the threads is non deterministic and we can only destroy the AspectEngine after it has been shut down from the SGThread. However, that can lead to the Entity tree to never be properly released/cleaned up in the case where the main thread is destroyed before the render thread. To account for that, we now release the root entity when the AspectEngineDestroyer allowRelease is called in the context of the main thread. That way, even if the AspectEngine is fully destroyed later once SG thread exits(), the scene tree is still cleaned up while we have an event loop. Special handling is done for that behavior not to happen in the case Scene3D is rendered from with a QQuickRenderControl. This should fix asserts or crash observed when using Scene2D within a Scene3D scene. Change-Id: I77edff567d60e53a61023f88b551fc475885e5eb Reviewed-by: Mike Krus <mike.krus@kdab.com>
-rw-r--r--src/quick3d/imports/scene3d/scene3ditem.cpp31
1 files changed, 28 insertions, 3 deletions
diff --git a/src/quick3d/imports/scene3d/scene3ditem.cpp b/src/quick3d/imports/scene3d/scene3ditem.cpp
index a720b8aa0..377569f6a 100644
--- a/src/quick3d/imports/scene3d/scene3ditem.cpp
+++ b/src/quick3d/imports/scene3d/scene3ditem.cpp
@@ -100,13 +100,31 @@ public:
m_targetAllowed = targetCount;
}
+ Qt3DCore::QAspectEngine *aspectEngine() const
+ {
+ if (children().empty())
+ return nullptr;
+ return qobject_cast<Qt3DCore::QAspectEngine *>(children().first());
+ }
+
+ bool releaseRootEntity() const { return m_releaseRootEntity; }
+ void setReleaseRootEntity(bool release) { m_releaseRootEntity = release; }
+
void allowRelease()
{
++m_allowed;
- if (m_allowed == m_targetAllowed) {
- if (QThread::currentThread() == thread())
+ const bool shouldSelfDestruct = m_allowed == m_targetAllowed;
+ if (QThread::currentThread() == thread()) {
+ // Force Backend Tree to be cleaned up
+ Qt3DCore::QAspectEngine *engine = aspectEngine();
+ // If used in the regular Scene3D, take this opportunity to release the root
+ // Entity which will release the backend entities of Qt3D
+ if (m_releaseRootEntity && engine && engine->rootEntity())
+ engine->setRootEntity(Qt3DCore::QEntityPtr());
+ if (shouldSelfDestruct)
delete this;
- else
+ } else {
+ if (shouldSelfDestruct)
deleteLater();
}
}
@@ -118,6 +136,7 @@ private:
int m_allowed = 0;
int m_targetAllowed = 0;
bool m_sgNodeAlive = false;
+ bool m_releaseRootEntity = true;
};
/*!
@@ -881,6 +900,12 @@ QSGNode *Scene3DItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNode
// If the render aspect wasn't created yet, do so now
if (!managerNode->isInitialized()) {
auto *rw = QQuickRenderControl::renderWindowFor(window());
+
+ // When using a RenderControl, the AspectEngineDestroyer shouldn't release the root entity
+ // as it could be reused if render control was moved to another window
+ if (rw)
+ m_aspectEngineDestroyer->setReleaseRootEntity(false);
+
auto renderAspectPriv = static_cast<QRenderAspectPrivate*>(QRenderAspectPrivate::get(renderAspect));
renderAspectPriv->m_screen = (rw ? rw->screen() : window()->screen());
updateWindowSurface();