summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Harmer <sean.harmer@kdab.com>2020-09-28 13:16:56 +0100
committerSean Harmer <sean.harmer@kdab.com>2020-10-01 10:44:33 +0100
commit5b354f93fb74cbbaaed49bc1e4d3d1c4c2e2ffe5 (patch)
tree918ade5025a78c2fb8a896dc840f50b26f86ba82
parentf256e171b4455bfdd8357623ac63c9820a35a0f3 (diff)
Ensure Scene3D re-renders when a backend node is updated
There are two ways in which backend nodes can receive changes from the frontend: 1) By syncing the state directly from the frontend nodes 2) By changs delivered by the change arbiter Scene3D is already equipped to deal with changes going via the first mechanism. However, it is possible for changes going via the second mechanism to not trigger a re-render of a Scene3D item using the OnDemand render mode. This is even true in the case of using a Scene3D inside of a QQuickWidget even though this disables the threaded Qt Quick 2 rendering. The way this manifests is that: * A change is made via mechanism 2) such as creating some new nodes. * The frontend changes trigger a re-render of the Scene3D item via the existing notification mechanism (connection to the change arbiter's receivedChange() signal. * The QQuickWidget uses a timerEvent() to trigger a possible update * This notices the Scene3D is dirty and causes it to render and mark its state as clean. This does not yet pick up the newly created frontend nodes though as they need to go through the deferred post creation init dance. * The change arbiter then processes the deferred node creation events and creates the backend nodes. * At the next timerEvent from the QQuickWidget it still sees that the Scene3D is clean and does not bother to re-render it. This change fixes this by adding a new signal to the change arbiter, syncedChanges() that gets emitted only when the arbiter has actually finished distributing the changes going via mechanism 2) to the backend nodes. This syncedChhanges() signal is emitted on the aspect thread and so Scene3DItem connects to this using a queued connection. This then ensures that once the new backend nodes are actually present and up to date that the Scene3D in OnDemand mode will then re-render the scene with the complete scene graph. Change-Id: I3246f34a3cfe15392a390eb6d97b4e90346288a6 Reviewed-by: Mike Krus <mike.krus@kdab.com>
-rw-r--r--src/core/qchangearbiter.cpp15
-rw-r--r--src/core/qchangearbiter_p.h1
-rw-r--r--src/quick3d/imports/scene3d/scene3ditem.cpp7
3 files changed, 20 insertions, 3 deletions
diff --git a/src/core/qchangearbiter.cpp b/src/core/qchangearbiter.cpp
index e5745b017..3672777de 100644
--- a/src/core/qchangearbiter.cpp
+++ b/src/core/qchangearbiter.cpp
@@ -171,12 +171,21 @@ void QChangeArbiter::removeLockingChangeQueue(QChangeArbiter::QChangeQueue *queu
void QChangeArbiter::syncChanges()
{
- const std::lock_guard<QRecursiveMutex> locker(m_mutex);;
- for (QChangeArbiter::QChangeQueue *changeQueue : qAsConst(m_changeQueues))
+ const std::lock_guard<QRecursiveMutex> locker(m_mutex);
+
+ bool hasChanges = false;
+ for (QChangeArbiter::QChangeQueue *changeQueue : qAsConst(m_changeQueues)) {
+ hasChanges |= !changeQueue->empty();
distributeQueueChanges(changeQueue);
+ }
- for (QChangeQueue *changeQueue : qAsConst(m_lockingChangeQueues))
+ for (QChangeQueue *changeQueue : qAsConst(m_lockingChangeQueues)) {
+ hasChanges |= !changeQueue->empty();
distributeQueueChanges(changeQueue);
+ }
+
+ if (hasChanges)
+ emit syncedChanges();
}
void QChangeArbiter::setScene(QScene *scene)
diff --git a/src/core/qchangearbiter_p.h b/src/core/qchangearbiter_p.h
index 483b46575..e32fe7da4 100644
--- a/src/core/qchangearbiter_p.h
+++ b/src/core/qchangearbiter_p.h
@@ -138,6 +138,7 @@ public:
Q_SIGNALS:
void receivedChange();
+ void syncedChanges();
protected:
typedef std::vector<QSceneChangePtr> QChangeQueue;
diff --git a/src/quick3d/imports/scene3d/scene3ditem.cpp b/src/quick3d/imports/scene3d/scene3ditem.cpp
index 586de9938..a720b8aa0 100644
--- a/src/quick3d/imports/scene3d/scene3ditem.cpp
+++ b/src/quick3d/imports/scene3d/scene3ditem.cpp
@@ -886,8 +886,15 @@ QSGNode *Scene3DItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNode
updateWindowSurface();
managerNode->init();
// Note: ChangeArbiter is only set after aspect was registered
+
+ // This allows Scene3DItem to know when it needs to re-render as a result of frontend nodes receiving a change.
QObject::connect(renderAspectPriv->m_aspectManager->changeArbiter(), &Qt3DCore::QChangeArbiter::receivedChange,
this, [this] { m_dirty = true; }, Qt::DirectConnection);
+
+ // This allows Scene3DItem to know when it needs to re-render as a result of backend nodes receiving a change.
+ // For e.g. nodes being created/destroyed.
+ QObject::connect(renderAspectPriv->m_aspectManager->changeArbiter(), &Qt3DCore::QChangeArbiter::syncedChanges,
+ this, [this] { m_dirty = true; }, Qt::QueuedConnection);
}
const bool usesFBO = m_compositingMode == FBO;