diff options
author | Mike Krus <mike.krus@kdab.com> | 2019-08-06 15:30:01 +0100 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2019-08-28 06:30:29 +0200 |
commit | f3268fcb2a4e73d99dbd66aa5e262a118b5a5480 (patch) | |
tree | 374bd9ace2fccaa33534f338950185368ab5598b /src/core | |
parent | 91dc1e1a61651a82a0ee5ce6ad3b24e82f526be6 (diff) |
Do direct notification of backend nodeswip/refactor
Since aspect manager is now on main thread, we can directly update
backend nodes safely. Track nodes which have changed properties and
notify the backend nodes as part of the frame loop.
This avoid allocating and delivering many change messages.
To follow:
- implement on all nodes
- look at backend to frontend syncing
- figure out what to do with non property messages (components
added/removed, commands, ...)
Change-Id: Ia0c442b0528e728c4324d168200bae021bc29266
Reviewed-by: Mike Krus <mike.krus@kdab.com>
Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/aspects/qabstractaspect.cpp | 102 | ||||
-rw-r--r-- | src/core/aspects/qabstractaspect.h | 13 | ||||
-rw-r--r-- | src/core/aspects/qabstractaspect_p.h | 10 | ||||
-rw-r--r-- | src/core/aspects/qaspectengine.cpp | 11 | ||||
-rw-r--r-- | src/core/aspects/qaspectengine_p.h | 3 | ||||
-rw-r--r-- | src/core/aspects/qaspectmanager.cpp | 6 | ||||
-rw-r--r-- | src/core/nodes/qbackendnode.cpp | 16 | ||||
-rw-r--r-- | src/core/nodes/qcomponent.cpp | 4 | ||||
-rw-r--r-- | src/core/nodes/qentity.cpp | 4 | ||||
-rw-r--r-- | src/core/nodes/qnode.cpp | 72 | ||||
-rw-r--r-- | src/core/nodes/qnode_p.h | 2 | ||||
-rw-r--r-- | src/core/qchangearbiter.cpp | 16 | ||||
-rw-r--r-- | src/core/qchangearbiter_p.h | 10 | ||||
-rw-r--r-- | src/core/qscene.cpp | 6 | ||||
-rw-r--r-- | src/core/qscene_p.h | 5 |
15 files changed, 199 insertions, 81 deletions
diff --git a/src/core/aspects/qabstractaspect.cpp b/src/core/aspects/qabstractaspect.cpp index 7b08dec81..7636fd666 100644 --- a/src/core/aspects/qabstractaspect.cpp +++ b/src/core/aspects/qabstractaspect.cpp @@ -40,6 +40,9 @@ #include "qabstractaspect.h" #include "qabstractaspect_p.h" +#include <QMetaObject> +#include <QMetaProperty> + #include <Qt3DCore/qentity.h> #include <Qt3DCore/qpropertyupdatedchange.h> @@ -48,6 +51,7 @@ #include <Qt3DCore/private/qaspectmanager_p.h> #include <Qt3DCore/private/qchangearbiter_p.h> #include <Qt3DCore/private/qnodevisitor_p.h> +#include <Qt3DCore/private/qnode_p.h> #include <Qt3DCore/private/qscene_p.h> QT_BEGIN_NAMESPACE @@ -170,7 +174,14 @@ QNodeId QAbstractAspect::rootEntityId() const Q_DECL_NOEXCEPT void QAbstractAspect::registerBackendType(const QMetaObject &obj, const QBackendNodeMapperPtr &functor) { Q_D(QAbstractAspect); - d->m_backendCreatorFunctors.insert(&obj, functor); + d->m_backendCreatorFunctors.insert(&obj, {functor, QAbstractAspectPrivate::DefaultMapper}); +} + +void QAbstractAspect::registerBackendType(const QMetaObject &obj, const QBackendNodeMapperPtr &functor, bool supportsSyncing) +{ + Q_D(QAbstractAspect); + const auto f = supportsSyncing ? QAbstractAspectPrivate::SupportsSyncing : QAbstractAspectPrivate::DefaultMapper; + d->m_backendCreatorFunctors.insert(&obj, {functor, f}); } void QAbstractAspect::unregisterBackendType(const QMetaObject &obj) @@ -203,12 +214,96 @@ QVector<QAspectJobPtr> QAbstractAspect::jobsToExecute(qint64 time) return QVector<QAspectJobPtr>(); } +void QAbstractAspect::syncDirtyFrontEndNodes(const QVector<QNode *> &nodes) +{ + Q_D(QAbstractAspect); + d->syncDirtyFrontEndNodes(nodes); +} + +void QAbstractAspectPrivate::syncDirtyFrontEndNodes(const QVector<QNode *> &nodes) +{ + for (auto node: qAsConst(nodes)) { + const QMetaObject *metaObj = node->metaObject(); + QBackendNodeMapperPtr backendNodeMapper; + bool supportsSyncing = false; + while (metaObj != nullptr && backendNodeMapper.isNull()) { + auto v = m_backendCreatorFunctors.value(metaObj); + backendNodeMapper = v.first; + supportsSyncing = v.second & SupportsSyncing; + metaObj = metaObj->superClass(); + } + + if (!backendNodeMapper) + continue; + + QBackendNode *backend = backendNodeMapper->get(node->id()); + if (!backend) + continue; + if (supportsSyncing) + syncDirtyFrontEndNode(node, backend, false); + else + sendPropertyMessages(node, backend); + } +} + +void QAbstractAspectPrivate::syncDirtyFrontEndNode(QNode *node, QBackendNode *backend, bool firstTime) const +{ + Q_UNUSED(firstTime); + Q_ASSERT(false); // overload in derived class + sendPropertyMessages(node, backend); +} + +void QAbstractAspectPrivate::sendPropertyMessages(QNode *node, QBackendNode *backend) const +{ + const int offset = QNode::staticMetaObject.propertyOffset(); + const auto metaObj = node->metaObject(); + const int count = metaObj->propertyCount(); + + const auto toBackendValue = [](const QVariant &data) -> QVariant + { + if (data.canConvert<QNode*>()) { + QNode *node = data.value<QNode*>(); + + // Ensure the node and all ancestors have issued their node creation changes. + // We can end up here if a newly created node with a parent is immediately set + // as a property on another node. In this case the deferred call to + // _q_postConstructorInit() will not have happened yet as the event + // loop will still be blocked. We need to do this for all ancestors, + // since the subtree of this node otherwise can end up on the backend + // with a reference to a non-existent parent. + if (node) + QNodePrivate::get(node)->_q_ensureBackendNodeCreated(); + + const QNodeId id = node ? node->id() : QNodeId(); + return QVariant::fromValue(id); + } + + return data; + }; + + QPropertyUpdatedChange change(node->id()); + QPropertyUpdatedChangePtr pchange(&change, [](QPropertyUpdatedChange *) { }); + for (int index = offset; index < count; index++) { + const QMetaProperty pro = metaObj->property(index); + change.setPropertyName(pro.name()); + change.setValue(toBackendValue(pro.read(node))); + backend->sceneChangeEvent(pchange); + } + + auto const dynamicProperties = node->dynamicPropertyNames(); + for (const QByteArray &name: dynamicProperties) { + change.setPropertyName(name.data()); + change.setValue(toBackendValue(node->property(name.data()))); + backend->sceneChangeEvent(pchange); + } +} + QBackendNode *QAbstractAspectPrivate::createBackendNode(const QNodeCreatedChangeBasePtr &change) const { const QMetaObject *metaObj = change->metaObject(); QBackendNodeMapperPtr backendNodeMapper; while (metaObj != nullptr && backendNodeMapper.isNull()) { - backendNodeMapper = m_backendCreatorFunctors.value(metaObj); + backendNodeMapper = m_backendCreatorFunctors.value(metaObj).first; metaObj = metaObj->superClass(); } @@ -248,6 +343,7 @@ QBackendNode *QAbstractAspectPrivate::createBackendNode(const QNodeCreatedChange return backend; } + void QAbstractAspectPrivate::clearBackendNode(const QNodeDestroyedChangePtr &change) const { // Each QNodeDestroyedChange may contain info about a whole sub-tree of nodes that @@ -259,7 +355,7 @@ void QAbstractAspectPrivate::clearBackendNode(const QNodeDestroyedChangePtr &cha // Find backend node mapper for this type while (metaObj != nullptr && backendNodeMapper.isNull()) { - backendNodeMapper = m_backendCreatorFunctors.value(metaObj); + backendNodeMapper = m_backendCreatorFunctors.value(metaObj).first; metaObj = metaObj->superClass(); } diff --git a/src/core/aspects/qabstractaspect.h b/src/core/aspects/qabstractaspect.h index 1ae85e4e6..a9f4f03fc 100644 --- a/src/core/aspects/qabstractaspect.h +++ b/src/core/aspects/qabstractaspect.h @@ -77,12 +77,17 @@ protected: template<class Frontend> void registerBackendType(const QBackendNodeMapperPtr &functor); - void registerBackendType(const QMetaObject &, const QBackendNodeMapperPtr &functor); + template<class Frontend, bool supportsSyncing> + void registerBackendType(const QBackendNodeMapperPtr &functor); + void registerBackendType(const QMetaObject &obj, const QBackendNodeMapperPtr &functor); template<class Frontend> void unregisterBackendType(); void unregisterBackendType(const QMetaObject &); private: + void syncDirtyFrontEndNodes(const QVector<QNode *> &nodes); + void registerBackendType(const QMetaObject &obj, const QBackendNodeMapperPtr &functor, bool supportsSyncing); + virtual QVariant executeCommand(const QStringList &args); virtual QVector<QAspectJobPtr> jobsToExecute(qint64 time); @@ -104,6 +109,12 @@ void QAbstractAspect::registerBackendType(const QBackendNodeMapperPtr &functor) registerBackendType(Frontend::staticMetaObject, functor); } +template<class Frontend, bool supportsSyncing> +void QAbstractAspect::registerBackendType(const QBackendNodeMapperPtr &functor) +{ + registerBackendType(Frontend::staticMetaObject, functor, supportsSyncing); +} + template<class Frontend> void QAbstractAspect::unregisterBackendType() { diff --git a/src/core/aspects/qabstractaspect_p.h b/src/core/aspects/qabstractaspect_p.h index e743dc63a..668b9670c 100644 --- a/src/core/aspects/qabstractaspect_p.h +++ b/src/core/aspects/qabstractaspect_p.h @@ -121,6 +121,9 @@ public: QBackendNode *createBackendNode(const QNodeCreatedChangeBasePtr &change) const override; void clearBackendNode(const QNodeDestroyedChangePtr &change) const; + void syncDirtyFrontEndNodes(const QVector<QNode *> &nodes); + virtual void syncDirtyFrontEndNode(QNode *node, QBackendNode *backend, bool firstTime) const; + void sendPropertyMessages(QNode *node, QBackendNode *backend) const; void sceneNodeAdded(Qt3DCore::QSceneChangePtr &e) override; void sceneNodeRemoved(Qt3DCore::QSceneChangePtr &e) override; @@ -134,12 +137,17 @@ public: Q_DECLARE_PUBLIC(QAbstractAspect) + enum NodeMapperInfo { + DefaultMapper = 0, + SupportsSyncing = 1 << 0 + }; + QEntity *m_root; QNodeId m_rootId; QAspectManager *m_aspectManager; QAbstractAspectJobManager *m_jobManager; QChangeArbiter *m_arbiter; - QHash<const QMetaObject*, QBackendNodeMapperPtr> m_backendCreatorFunctors; + QHash<const QMetaObject*, QPair<QBackendNodeMapperPtr, NodeMapperInfo>> m_backendCreatorFunctors; QMutex m_singleShotMutex; QVector<QAspectJobPtr> m_singleShotJobs; diff --git a/src/core/aspects/qaspectengine.cpp b/src/core/aspects/qaspectengine.cpp index 9c98e9613..c5e4b2b26 100644 --- a/src/core/aspects/qaspectengine.cpp +++ b/src/core/aspects/qaspectengine.cpp @@ -120,12 +120,6 @@ void QAspectEnginePrivate::initEntity(QEntity *entity) } } -void QAspectEnginePrivate::generateCreationChanges(QNode *root) -{ - const QNodeCreatedChangeGenerator generator(root); - m_creationChanges = generator.creationChanges(); -} - /*! * \class Qt3DCore::QAspectEngine * \inheaderfile Qt3DCore/QAspectEngine @@ -444,7 +438,8 @@ void QAspectEngine::setRootEntity(QEntityPtr root) d->initNodeTree(root.data()); // Traverse tree to generate a vector of creation changes - d->generateCreationChanges(root.data()); + const QNodeCreatedChangeGenerator generator(root.data()); + auto creationChanges = generator.creationChanges(); // Specify if the AspectManager should be driving the simulation loop or not d->m_aspectManager->setRunMode(d->m_runMode); @@ -456,7 +451,7 @@ void QAspectEngine::setRootEntity(QEntityPtr root) // TODO: Pass the creation changes via the arbiter rather than relying upon // an invokeMethod call. qCDebug(Aspects) << "Begin setting scene root on aspect manager"; - d->m_aspectManager->setRootEntity(root.data(), d->m_creationChanges); + d->m_aspectManager->setRootEntity(root.data(), creationChanges); qCDebug(Aspects) << "Done setting scene root on aspect manager"; d->m_aspectManager->enterSimulationLoop(); } diff --git a/src/core/aspects/qaspectengine_p.h b/src/core/aspects/qaspectengine_p.h index e1aaa9de9..7dad2a352 100644 --- a/src/core/aspects/qaspectengine_p.h +++ b/src/core/aspects/qaspectengine_p.h @@ -106,9 +106,6 @@ public: void initNode(QNode *node); void initEntity(QEntity *entity); - void generateCreationChanges(QNode *rootNode); - QVector<QNodeCreatedChangeBasePtr> m_creationChanges; - static QAspectEnginePrivate *get(QAspectEngine *engine); }; diff --git a/src/core/aspects/qaspectmanager.cpp b/src/core/aspects/qaspectmanager.cpp index 6502590d8..0c16de882 100644 --- a/src/core/aspects/qaspectmanager.cpp +++ b/src/core/aspects/qaspectmanager.cpp @@ -370,6 +370,10 @@ void QAspectManager::processFrame() changeArbiterStats.threadId = reinterpret_cast<quint64>(QThread::currentThreadId()); changeArbiterStats.startTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed(); #endif + const auto dirtyFrontEndNodes = m_changeArbiter->takeDirtyFrontEndNodes(); + if (dirtyFrontEndNodes.size()) + for (QAbstractAspect *aspect : qAsConst(m_aspects)) + aspect->syncDirtyFrontEndNodes(dirtyFrontEndNodes); // TO DO: Having this done in the main thread actually means aspects could just // as simply read info out of the Frontend classes without risk of introducing // races. This could therefore be removed for Qt 6. @@ -390,6 +394,8 @@ void QAspectManager::processFrame() #if defined(QT3D_CORE_JOB_TIMING) qDebug() << "Jobs took" << timer.nsecsElapsed() / 1.0e6; #endif + + // TODO sync backend changes to frontend } } // namespace Qt3DCore diff --git a/src/core/nodes/qbackendnode.cpp b/src/core/nodes/qbackendnode.cpp index f10bf5769..3eb1cd9f7 100644 --- a/src/core/nodes/qbackendnode.cpp +++ b/src/core/nodes/qbackendnode.cpp @@ -256,16 +256,16 @@ void QBackendNode::setEnabled(bool enabled) Q_DECL_NOTHROW void QBackendNode::sceneChangeEvent(const QSceneChangePtr &e) { Q_D(QBackendNode); - auto propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e); switch (e->type()) { - case PropertyUpdated: { - if (propertyChange->propertyName() == QByteArrayLiteral("enabled")) - d->m_enabled = propertyChange->value().toBool(); - break; - } - default: - break; + case PropertyUpdated: { + auto propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e); + if (propertyChange->propertyName() == QByteArrayLiteral("enabled")) + d->m_enabled = propertyChange->value().toBool(); + break; + } + default: + break; } } diff --git a/src/core/nodes/qcomponent.cpp b/src/core/nodes/qcomponent.cpp index f67989b1e..2fe3c8094 100644 --- a/src/core/nodes/qcomponent.cpp +++ b/src/core/nodes/qcomponent.cpp @@ -73,7 +73,7 @@ void QComponentPrivate::addEntity(QEntity *entity) m_scene->addEntityForComponent(m_id, entity->id()); } - const auto componentAddedChange = QComponentAddedChangePtr::create(q, entity); + const auto componentAddedChange = QComponentAddedChangePtr::create(q, entity); // TODOSYNC notify backend directly notifyObservers(componentAddedChange); Q_EMIT q->addedToEntity(entity); } @@ -86,7 +86,7 @@ void QComponentPrivate::removeEntity(QEntity *entity) m_entities.removeAll(entity); - const auto componentRemovedChange = QComponentRemovedChangePtr::create(q, entity); + const auto componentRemovedChange = QComponentRemovedChangePtr::create(q, entity); // TODOSYNC notify backend directly notifyObservers(componentRemovedChange); Q_EMIT q->removedFromEntity(entity); } diff --git a/src/core/nodes/qentity.cpp b/src/core/nodes/qentity.cpp index 1d16e828e..a1f7d2859 100644 --- a/src/core/nodes/qentity.cpp +++ b/src/core/nodes/qentity.cpp @@ -105,7 +105,7 @@ void QEntityPrivate::removeDestroyedComponent(QComponent *comp) Q_Q(QEntity); if (m_changeArbiter) { - const auto componentRemovedChange = QComponentRemovedChangePtr::create(q, comp); + const auto componentRemovedChange = QComponentRemovedChangePtr::create(q, comp); // TODOSYNC notify backend directly notifyObservers(componentRemovedChange); } @@ -187,7 +187,7 @@ void QEntity::addComponent(QComponent *comp) d->registerPrivateDestructionHelper(comp, &QEntityPrivate::removeDestroyedComponent); if (d->m_changeArbiter) { - const auto componentAddedChange = QComponentAddedChangePtr::create(this, comp); + const auto componentAddedChange = QComponentAddedChangePtr::create(this, comp); // TODOSYNC notify backend directly d->notifyObservers(componentAddedChange); } static_cast<QComponentPrivate *>(QComponentPrivate::get(comp))->addEntity(this); diff --git a/src/core/nodes/qnode.cpp b/src/core/nodes/qnode.cpp index 900c3f8ce..45d58bd8c 100644 --- a/src/core/nodes/qnode.cpp +++ b/src/core/nodes/qnode.cpp @@ -385,48 +385,13 @@ void QNodePrivate::unregisterNotifiedProperties() void QNodePrivate::propertyChanged(int propertyIndex) { + Q_UNUSED(propertyIndex); + // Bail out early if we can to avoid the cost below if (m_blockNotifications) return; - const auto toBackendValue = [](const QVariant &data) -> QVariant - { - if (data.canConvert<QNode*>()) { - QNode *node = data.value<QNode*>(); - - // Ensure the node and all ancestors have issued their node creation changes. - // We can end up here if a newly created node with a parent is immediately set - // as a property on another node. In this case the deferred call to - // _q_postConstructorInit() will not have happened yet as the event - // loop will still be blocked. We need to do this for all ancestors, - // since the subtree of this node otherwise can end up on the backend - // with a reference to a non-existent parent. - if (node) - QNodePrivate::get(node)->_q_ensureBackendNodeCreated(); - - const QNodeId id = node ? node->id() : QNodeId(); - return QVariant::fromValue(id); - } - - return data; - }; - - Q_Q(QNode); - - const QMetaProperty property = q->metaObject()->property(propertyIndex); - - const QVariant data = property.read(q); - - if (data.type() == QVariant::List) { - QSequentialIterable iterable = data.value<QSequentialIterable>(); - QVariantList variants; - variants.reserve(iterable.size()); - for (const auto &v : iterable) - variants.append(toBackendValue(v)); - notifyPropertyChange(property.name(), variants); - } else { - notifyPropertyChange(property.name(), toBackendValue(data)); - } + update(); } /*! @@ -498,8 +463,13 @@ void QNodePrivate::addEntityComponentToScene(QNode *root) // Called in the main thread by QScene -> following QEvent::childAdded / addChild void QNodePrivate::setArbiter(QLockableObserverInterface *arbiter) { - if (m_changeArbiter && m_changeArbiter != arbiter) + if (m_changeArbiter && m_changeArbiter != arbiter) { unregisterNotifiedProperties(); + + // Remove node from dirtyFrontendNodeList on old arbiter + Q_Q(QNode); + m_changeArbiter->removeDirtyFrontEndNode(q); + } m_changeArbiter = static_cast<QAbstractArbiter *>(arbiter); if (m_changeArbiter) registerNotifiedProperties(); @@ -626,26 +596,26 @@ QScene *QNodePrivate::scene() const */ void QNodePrivate::notifyPropertyChange(const char *name, const QVariant &value) { + Q_UNUSED(name); + Q_UNUSED(value); + // Bail out early if we can to avoid operator new if (m_blockNotifications) return; - auto e = QPropertyUpdatedChangePtr::create(m_id); - e->setPropertyName(name); - e->setValue(value); - notifyObservers(e); + update(); } void QNodePrivate::notifyDynamicPropertyChange(const QByteArray &name, const QVariant &value) { + Q_UNUSED(name); + Q_UNUSED(value); + // Bail out early if we can to avoid operator new if (m_blockNotifications) return; - auto e = QDynamicPropertyUpdatedChangePtr::create(m_id); - e->setPropertyName(name); - e->setValue(value); - notifyObservers(e); + update(); } /*! @@ -704,6 +674,14 @@ void QNodePrivate::updatePropertyTrackMode() } } +void QNodePrivate::update() +{ + if (m_changeArbiter) { + Q_Q(QNode); + m_changeArbiter->addDirtyFrontEndNode(q); + } +} + /*! \internal */ diff --git a/src/core/nodes/qnode_p.h b/src/core/nodes/qnode_p.h index 511a0e562..990c2caeb 100644 --- a/src/core/nodes/qnode_p.h +++ b/src/core/nodes/qnode_p.h @@ -89,6 +89,8 @@ public: void insertTree(QNode *treeRoot, int depth = 0); void updatePropertyTrackMode(); + void update(); + Q_DECLARE_PUBLIC(QNode) // For now this just protects access to the m_changeArbiter. diff --git a/src/core/qchangearbiter.cpp b/src/core/qchangearbiter.cpp index 8cfc4b066..6ad72c895 100644 --- a/src/core/qchangearbiter.cpp +++ b/src/core/qchangearbiter.cpp @@ -266,6 +266,22 @@ void QChangeArbiter::sceneChangeEventWithLock(const QSceneChangeList &e) emit receivedChange(); } +void QChangeArbiter::addDirtyFrontEndNode(QNode *node) +{ + if (!m_dirtyFrontEndNodes.contains(node)) + m_dirtyFrontEndNodes += node; +} + +void QChangeArbiter::removeDirtyFrontEndNode(QNode *node) +{ + m_dirtyFrontEndNodes.removeOne(node); +} + +QVector<QNode *> QChangeArbiter::takeDirtyFrontEndNodes() +{ + return std::move(m_dirtyFrontEndNodes); +} + // Either we have the postman or we could make the QChangeArbiter agnostic to the postman // but that would require adding it to every QObserverList in m_aspectObservations. void QChangeArbiter::setPostman(QAbstractPostman *postman) diff --git a/src/core/qchangearbiter_p.h b/src/core/qchangearbiter_p.h index c7d96b593..48fc4ca8c 100644 --- a/src/core/qchangearbiter_p.h +++ b/src/core/qchangearbiter_p.h @@ -81,6 +81,8 @@ class Q_3DCORE_PRIVATE_EXPORT QAbstractArbiter : public QLockableObserverInterfa { public: virtual QAbstractPostman *postman() const = 0; + virtual void addDirtyFrontEndNode(QNode *node) = 0; + virtual void removeDirtyFrontEndNode(QNode *node) = 0; }; class Q_3DCORE_PRIVATE_EXPORT QChangeArbiter final @@ -89,7 +91,7 @@ class Q_3DCORE_PRIVATE_EXPORT QChangeArbiter final { Q_OBJECT public: - explicit QChangeArbiter(QObject *parent = 0); + explicit QChangeArbiter(QObject *parent = nullptr); ~QChangeArbiter(); void initialize(Qt3DCore::QAbstractAspectJobManager *jobManager); @@ -109,6 +111,10 @@ public: void sceneChangeEventWithLock(const QSceneChangePtr &e) override; // QLockableObserverInterface impl void sceneChangeEventWithLock(const QSceneChangeList &e) override; // QLockableObserverInterface impl + void addDirtyFrontEndNode(QNode *node) override; + void removeDirtyFrontEndNode(QNode *node) override; + QVector<QNode *> takeDirtyFrontEndNodes(); + void setPostman(Qt3DCore::QAbstractPostman *postman); void setScene(Qt3DCore::QScene *scene); @@ -155,6 +161,8 @@ private: QList<QChangeQueue *> m_lockingChangeQueues; QAbstractPostman *m_postman; QScene *m_scene; + + QVector<QNode *> m_dirtyFrontEndNodes; }; } // namespace Qt3DCore diff --git a/src/core/qscene.cpp b/src/core/qscene.cpp index c94272e90..1b8996e8d 100644 --- a/src/core/qscene.cpp +++ b/src/core/qscene.cpp @@ -68,7 +68,7 @@ public: QMultiHash<QNodeId, QObservableInterface *> m_observablesLookupTable; QHash<QObservableInterface *, QNodeId> m_observableToUuid; QHash<QNodeId, QScene::NodePropertyTrackData> m_nodePropertyTrackModeLookupTable; - QLockableObserverInterface *m_arbiter; + QAbstractArbiter *m_arbiter; QScopedPointer<NodePostConstructorInit> m_postConstructorInit; mutable QReadWriteLock m_lock; mutable QReadWriteLock m_nodePropertyTrackModeLock; @@ -183,13 +183,13 @@ QNode *QScene::rootNode() const return d->m_rootNode; } -void QScene::setArbiter(QLockableObserverInterface *arbiter) +void QScene::setArbiter(QAbstractArbiter *arbiter) { Q_D(QScene); d->m_arbiter = arbiter; } -QLockableObserverInterface *QScene::arbiter() const +QAbstractArbiter *QScene::arbiter() const { Q_D(const QScene); return d->m_arbiter; diff --git a/src/core/qscene_p.h b/src/core/qscene_p.h index afcfb9b40..cdb85ebe6 100644 --- a/src/core/qscene_p.h +++ b/src/core/qscene_p.h @@ -65,6 +65,7 @@ namespace Qt3DCore { class QScenePrivate; class QAspectEngine; class NodePostConstructorInit; +class QAbstractArbiter; typedef QList<QObservableInterface *> QObservableList; @@ -88,8 +89,8 @@ public: QNode *rootNode() const; - void setArbiter(Qt3DCore::QLockableObserverInterface *arbiter); - Qt3DCore::QLockableObserverInterface *arbiter() const; + void setArbiter(QAbstractArbiter *arbiter); + QAbstractArbiter *arbiter() const; // Component -> Entities QVector<QNodeId> entitiesForComponent(QNodeId id) const; |