diff options
author | Paul Lemire <paul.lemire@kdab.com> | 2017-01-24 10:43:32 +0100 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2017-01-25 14:56:43 +0000 |
commit | 393ab950be4a622dc2616c061eeb4f2194991093 (patch) | |
tree | a8e83bb510c9cc58c1461eb2345f122925e09c34 /src | |
parent | 4f6bf6d53c50221977d3f6e2c04ced70d815e6ac (diff) |
Allow to filter change events based on a track property
* QNode now has a PropertyTrackMode property
* QScene contains a table of PropertyTrakcMode data
* QPostman checks if a QNode is supposed to receive a change based on the
information available in the QScene property track mode table
* Unit tests updated and added for QPostman
Change-Id: I3b88037a949020a917c81817f1451ef532065982
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/core/changes/qpropertyupdatedchangebase.cpp | 6 | ||||
-rw-r--r-- | src/core/changes/qpropertyupdatedchangebase_p.h | 3 | ||||
-rw-r--r-- | src/core/core.pri | 3 | ||||
-rw-r--r-- | src/core/nodes/qnode.cpp | 73 | ||||
-rw-r--r-- | src/core/nodes/qnode.h | 16 | ||||
-rw-r--r-- | src/core/nodes/qnode_p.h | 3 | ||||
-rw-r--r-- | src/core/qchangearbiter.cpp | 6 | ||||
-rw-r--r-- | src/core/qchangearbiter_p.h | 8 | ||||
-rw-r--r-- | src/core/qpostman.cpp | 44 | ||||
-rw-r--r-- | src/core/qpostman_p.h | 4 | ||||
-rw-r--r-- | src/core/qpostman_p_p.h | 85 | ||||
-rw-r--r-- | src/core/qscene.cpp | 23 | ||||
-rw-r--r-- | src/core/qscene_p.h | 12 | ||||
-rw-r--r-- | src/render/geometry/buffer.cpp | 2 | ||||
-rw-r--r-- | src/render/io/scene.cpp | 3 |
15 files changed, 264 insertions, 27 deletions
diff --git a/src/core/changes/qpropertyupdatedchangebase.cpp b/src/core/changes/qpropertyupdatedchangebase.cpp index 18f2039fc..d33c737e5 100644 --- a/src/core/changes/qpropertyupdatedchangebase.cpp +++ b/src/core/changes/qpropertyupdatedchangebase.cpp @@ -46,6 +46,7 @@ namespace Qt3DCore { QPropertyUpdatedChangeBasePrivate::QPropertyUpdatedChangeBasePrivate() : QSceneChangePrivate() + , m_isFinal(false) { } @@ -53,6 +54,11 @@ QPropertyUpdatedChangeBasePrivate::~QPropertyUpdatedChangeBasePrivate() { } +QPropertyUpdatedChangeBasePrivate *QPropertyUpdatedChangeBasePrivate::get(QPropertyUpdatedChangeBase *q) +{ + return q->d_func(); +} + /*! * \class Qt3DCore::QPropertyUpdatedChangeBase * \inheaderfile Qt3DCore/QPropertyUpdatedChangeBase diff --git a/src/core/changes/qpropertyupdatedchangebase_p.h b/src/core/changes/qpropertyupdatedchangebase_p.h index 314b1ea15..3c32b2237 100644 --- a/src/core/changes/qpropertyupdatedchangebase_p.h +++ b/src/core/changes/qpropertyupdatedchangebase_p.h @@ -66,7 +66,10 @@ public: QPropertyUpdatedChangeBasePrivate(); virtual ~QPropertyUpdatedChangeBasePrivate(); + static QPropertyUpdatedChangeBasePrivate *get(QPropertyUpdatedChangeBase *q); + Q_DECLARE_PUBLIC(QPropertyUpdatedChangeBase) + bool m_isFinal; }; } // namespace Qt3DCore diff --git a/src/core/core.pri b/src/core/core.pri index becdbb282..458a0328d 100644 --- a/src/core/core.pri +++ b/src/core/core.pri @@ -13,7 +13,8 @@ HEADERS += \ $$PWD/qchangearbiter_p.h \ $$PWD/qbackendnodefactory_p.h \ $$PWD/qt3dcore_global_p.h \ - $$PWD/qscene_p.h + $$PWD/qscene_p.h \ + $$PWD/qpostman_p_p.h SOURCES += \ $$PWD/qtickclock.cpp \ diff --git a/src/core/nodes/qnode.cpp b/src/core/nodes/qnode.cpp index e4bb5d4a3..77d7c0a6b 100644 --- a/src/core/nodes/qnode.cpp +++ b/src/core/nodes/qnode.cpp @@ -73,6 +73,7 @@ QNodePrivate::QNodePrivate() , m_blockNotifications(false) , m_hasBackendNode(false) , m_enabled(true) + , m_propertyTrackMode(QNode::DefaultTrackMode) , m_propertyChangesSetup(false) , m_signals(this) { @@ -402,7 +403,6 @@ void QNodePrivate::unsetSceneHelper(QNode *root) m_scene->removeEntityForComponent(c->id(), entity->id()); } } - if (m_scene != nullptr) m_scene->removeObservable(root); root->d_func()->setScene(nullptr); @@ -495,8 +495,13 @@ void QNode::sceneChangeEvent(const QSceneChangePtr &change) */ void QNodePrivate::setScene(QScene *scene) { - if (m_scene != scene) + if (m_scene != scene) { + if (m_scene != nullptr) + m_scene->removePropertyTrackDataForNode(m_id); m_scene = scene; + // set PropertyTrackData in the scene + updatePropertyTrackMode(); + } } /*! @@ -580,6 +585,16 @@ void QNodePrivate::insertTree(QNode *treeRoot, int depth) treeRoot->setParent(q_func()); } +void QNodePrivate::updatePropertyTrackMode() +{ + if (m_scene != nullptr) { + QScene::NodePropertyTrackData trackData; + trackData.updateMode = m_propertyTrackMode; + trackData.namedProperties = m_trackedProperties; + m_scene->setPropertyTrackDataForNode(m_id,trackData); + } +} + /*! \internal */ @@ -769,6 +784,34 @@ void QNode::setEnabled(bool isEnabled) emit enabledChanged(isEnabled); } +void QNode::setPropertyTrackMode(QNode::PropertyTrackMode mode) +{ + Q_D(QNode); + if (d->m_propertyTrackMode == mode) + return; + + d->m_propertyTrackMode = mode; + // The backend doesn't care about such notification + const bool blocked = blockNotifications(true); + emit propertyUpdateModeChanged(mode); + blockNotifications(blocked); + d->updatePropertyTrackMode(); +} + +void QNode::setTrackedProperties(const QStringList &trackedProperties) +{ + Q_D(QNode); + if (d->m_trackedProperties == trackedProperties) + return; + + d->m_trackedProperties = trackedProperties; + // The backend doesn't care about such notification + const bool blocked = blockNotifications(true); + emit trackedPropertiesChanged(trackedProperties); + blockNotifications(blocked); + d->updatePropertyTrackMode(); +} + /*! \property Qt3DCore::QNode::enabled @@ -785,6 +828,32 @@ bool QNode::isEnabled() const return d->m_enabled; } +/*! + \property Qt3DCore::QNode::propertyTrackMode + + Holds the property track mode which determines whether a QNode should + be listening for property updates + + By default it is set to QNode::DontTrackProperties +*/ +QNode::PropertyTrackMode QNode::propertyTrackMode() const +{ + Q_D(const QNode); + return d->m_propertyTrackMode; +} + +/*! + \property Qt3DCore::QNode::trackedProperties + + Holds the names of the properties to be tracked when propertyTrackMode is + set to TrackNamedProperties. +*/ +QStringList QNode::trackedProperties() const +{ + Q_D(const QNode); + return d->m_trackedProperties; +} + QNodeCreatedChangeBasePtr QNode::createNodeCreationChange() const { // Uncomment this when implementing new frontend and backend types. diff --git a/src/core/nodes/qnode.h b/src/core/nodes/qnode.h index cadcc7d5c..75ea61cc7 100644 --- a/src/core/nodes/qnode.h +++ b/src/core/nodes/qnode.h @@ -69,7 +69,17 @@ class QT3DCORESHARED_EXPORT QNode : public QObject Q_OBJECT Q_PROPERTY(Qt3DCore::QNode *parent READ parentNode WRITE setParent NOTIFY parentChanged) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged) + Q_PROPERTY(PropertyTrackMode propertyTrackMode READ propertyTrackMode WRITE setPropertyTrackMode NOTIFY propertyUpdateModeChanged) + Q_PROPERTY(QStringList trackedProperties READ trackedProperties WRITE setTrackedProperties NOTIFY trackedPropertiesChanged) public: + + enum PropertyTrackMode { + DefaultTrackMode, + TrackNamedPropertiesMode, + TrackAllPropertiesMode + }; + Q_ENUM(PropertyTrackMode) + explicit QNode(QNode *parent = nullptr); virtual ~QNode(); @@ -82,14 +92,20 @@ public: QNodeVector childNodes() const; bool isEnabled() const; + PropertyTrackMode propertyTrackMode() const; + QStringList trackedProperties() const; public Q_SLOTS: void setParent(QNode *parent); void setEnabled(bool isEnabled); + void setPropertyTrackMode(PropertyTrackMode mode); + void setTrackedProperties(const QStringList &trackedProperties); Q_SIGNALS: void parentChanged(QObject *parent); void enabledChanged(bool enabled); + void propertyUpdateModeChanged(PropertyTrackMode mode); + void trackedPropertiesChanged(const QStringList &trackedProperties); void nodeDestroyed(); protected: diff --git a/src/core/nodes/qnode_p.h b/src/core/nodes/qnode_p.h index a90011128..5d6329e62 100644 --- a/src/core/nodes/qnode_p.h +++ b/src/core/nodes/qnode_p.h @@ -84,6 +84,7 @@ public: void notifyObservers(const QSceneChangePtr &change) Q_DECL_OVERRIDE; void insertTree(QNode *treeRoot, int depth = 0); + void updatePropertyTrackMode(); Q_DECLARE_PUBLIC(QNode) @@ -97,6 +98,8 @@ public: bool m_blockNotifications; bool m_hasBackendNode; bool m_enabled; + QNode::PropertyTrackMode m_propertyTrackMode; + QStringList m_trackedProperties; static QNodePrivate *get(QNode *q); static void nodePtrDeleter(QNode *q); diff --git a/src/core/qchangearbiter.cpp b/src/core/qchangearbiter.cpp index 3bd3f69e8..a7ca3ed40 100644 --- a/src/core/qchangearbiter.cpp +++ b/src/core/qchangearbiter.cpp @@ -132,9 +132,11 @@ void QChangeArbiter::distributeQueueChanges(QChangeQueue *changeQueue) (change->deliveryFlags() & QSceneChange::BackendNodes)) observer.second->sceneChangeEvent(change); } + // Also send change to the postman if (change->deliveryFlags() & QSceneChange::Nodes) { - // Also send change to the postman - m_postman->sceneChangeEvent(change); + // Check if QNode actually cares about the change + if (m_postman->shouldNotifyFrontend(change)) + m_postman->sceneChangeEvent(change); } } } diff --git a/src/core/qchangearbiter_p.h b/src/core/qchangearbiter_p.h index e3fdcad9b..e381abc65 100644 --- a/src/core/qchangearbiter_p.h +++ b/src/core/qchangearbiter_p.h @@ -136,14 +136,8 @@ private: QMutex m_mutex; QAbstractAspectJobManager *m_jobManager; - // The lists of observers indexed by observable. We maintain two - // distinct hashes: - // - // m_aspectObservations is for observables owned by aspects + // The lists of observers indexed by observable (QNodeId). // m_nodeObservations is for observables in the main thread's object tree - // - // We keep these distinct because we do not manage the main thread which means - // the mechanisms for working with objects there is different. QHash<QNodeId, QObserverList> m_nodeObservations; QList<QSceneObserverInterface *> m_sceneObservers; diff --git a/src/core/qpostman.cpp b/src/core/qpostman.cpp index ac78450c6..2b8e6c3a8 100644 --- a/src/core/qpostman.cpp +++ b/src/core/qpostman.cpp @@ -38,30 +38,22 @@ ****************************************************************************/ #include "qpostman_p.h" -#include <private/qobject_p.h> +#include "qpostman_p_p.h" #include <Qt3DCore/qpropertyupdatedchange.h> #include <Qt3DCore/private/qscene_p.h> #include <Qt3DCore/private/qlockableobserverinterface_p.h> #include <Qt3DCore/qnode.h> #include <Qt3DCore/private/qnode_p.h> +#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h> QT_BEGIN_NAMESPACE namespace Qt3DCore { -class QPostmanPrivate : public QObjectPrivate +QPostmanPrivate *QPostmanPrivate::get(QPostman *q) { -public: - QPostmanPrivate() - : QObjectPrivate() - , m_scene(nullptr) - { - } - - Q_DECLARE_PUBLIC(QPostman) - QScene *m_scene; - std::vector<QSceneChangePtr> m_batch; -}; + return q->d_func(); +} QPostman::QPostman(QObject *parent) : QObject(*new QPostmanPrivate, parent) @@ -118,6 +110,32 @@ void QPostman::notifyBackend(const QSceneChangePtr &change) d->m_batch.push_back(change); } +// AspectThread +bool QPostman::shouldNotifyFrontend(const QSceneChangePtr &e) +{ + Q_D(QPostman); + const QPropertyUpdatedChangePtr propertyChange = qSharedPointerDynamicCast<QPropertyUpdatedChange>(e); + if (Q_LIKELY(d->m_scene != nullptr) && !propertyChange.isNull()) { + const bool isFinal = QPropertyUpdatedChangeBasePrivate::get(propertyChange.data())->m_isFinal; + if (isFinal) + return true; + const QScene::NodePropertyTrackData propertyTrackData = d->m_scene->lookupNodePropertyTrackData(e->subjectId()); + switch (propertyTrackData.updateMode) { + case QNode::TrackAllPropertiesMode: + return true; + case QNode::TrackNamedPropertiesMode: + return propertyTrackData.namedProperties.contains(QLatin1String(propertyChange->propertyName())); + case QNode::DefaultTrackMode: + return false; + default: + Q_UNREACHABLE(); + return false; + } + } + return true; +} + +// Main Thread void QPostman::notifyFrontendNode(const QSceneChangePtr &e) { Q_D(QPostman); diff --git a/src/core/qpostman_p.h b/src/core/qpostman_p.h index 4fe788960..cbc4048ce 100644 --- a/src/core/qpostman_p.h +++ b/src/core/qpostman_p.h @@ -66,9 +66,10 @@ class QT3DCORE_PRIVATE_EXPORT QAbstractPostman : public QObserverInterface public: virtual void setScene(QScene *sceneLookup) = 0; virtual void notifyBackend(const QSceneChangePtr &change) = 0; + virtual bool shouldNotifyFrontend(const QSceneChangePtr &change) = 0; }; -class QPostman Q_DECL_FINAL +class Q_AUTOTEST_EXPORT QPostman Q_DECL_FINAL : public QObject , public QAbstractPostman { @@ -80,6 +81,7 @@ public: void setScene(QScene *sceneLookup) Q_DECL_FINAL; void sceneChangeEvent(const QSceneChangePtr &e) Q_DECL_FINAL; void notifyBackend(const QSceneChangePtr &change) Q_DECL_FINAL; + bool shouldNotifyFrontend(const QSceneChangePtr &e) Q_DECL_FINAL; public Q_SLOTS: void submitChangeBatch(); diff --git a/src/core/qpostman_p_p.h b/src/core/qpostman_p_p.h new file mode 100644 index 000000000..1b5cca3c9 --- /dev/null +++ b/src/core/qpostman_p_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DCORE_QPOSTMAN_P_P_H +#define QT3DCORE_QPOSTMAN_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <Qt3DCore/qscenechange.h> +#include <private/qobject_p.h> +#include <Qt3DCore/private/qt3dcore_global_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DCore { + +class QScene; +class QPostman; + +class QT3DCORE_PRIVATE_EXPORT QPostmanPrivate : public QObjectPrivate +{ +public: + QPostmanPrivate() + : QObjectPrivate() + , m_scene(nullptr) + { + } + + static QPostmanPrivate *get(QPostman *q); + + Q_DECLARE_PUBLIC(QPostman) + QScene *m_scene; + std::vector<QSceneChangePtr> m_batch; +}; + +} // Qt3DCore + +QT_END_NAMESPACE + +#endif // QT3DCORE_QPOSTMAN_P_P_H diff --git a/src/core/qscene.cpp b/src/core/qscene.cpp index 42c3a2bc8..972659131 100644 --- a/src/core/qscene.cpp +++ b/src/core/qscene.cpp @@ -63,8 +63,10 @@ public: QMultiHash<QNodeId, QNodeId> m_componentToEntities; QMultiHash<QNodeId, QObservableInterface *> m_observablesLookupTable; QHash<QObservableInterface *, QNodeId> m_observableToUuid; + QHash<QNodeId, QScene::NodePropertyTrackData> m_nodePropertyTrackModeLookupTable; QLockableObserverInterface *m_arbiter; mutable QReadWriteLock m_lock; + mutable QReadWriteLock m_nodePropertyTrackModeLock; }; @@ -213,6 +215,27 @@ bool QScene::hasEntityForComponent(QNodeId componentUuid, QNodeId entityUuid) return d->m_componentToEntities.values(componentUuid).contains(entityUuid); } +QScene::NodePropertyTrackData QScene::lookupNodePropertyTrackData(QNodeId id) const +{ + Q_D(const QScene); + QReadLocker lock(&d->m_nodePropertyTrackModeLock); + return d->m_nodePropertyTrackModeLookupTable.value(id); +} + +void QScene::setPropertyTrackDataForNode(QNodeId nodeId, const QScene::NodePropertyTrackData &data) +{ + Q_D(QScene); + QWriteLocker lock(&d->m_nodePropertyTrackModeLock); + d->m_nodePropertyTrackModeLookupTable.insert(nodeId, data); +} + +void QScene::removePropertyTrackDataForNode(QNodeId nodeId) +{ + Q_D(QScene); + QWriteLocker lock(&d->m_nodePropertyTrackModeLock); + d->m_nodePropertyTrackModeLookupTable.remove(nodeId); +} + } // Qt3D QT_END_NAMESPACE diff --git a/src/core/qscene_p.h b/src/core/qscene_p.h index 6b4009538..1a313c249 100644 --- a/src/core/qscene_p.h +++ b/src/core/qscene_p.h @@ -53,13 +53,13 @@ #include <Qt3DCore/private/qt3dcore_global_p.h> #include <Qt3DCore/private/qobservableinterface_p.h> +#include <Qt3DCore/qnode.h> #include <QScopedPointer> QT_BEGIN_NAMESPACE namespace Qt3DCore { -class QNode; class QScenePrivate; class QAspectEngine; @@ -92,6 +92,16 @@ public: void removeEntityForComponent(QNodeId componentUuid, QNodeId entityUuid); bool hasEntityForComponent(QNodeId componentUuid, QNodeId entityUuid); + // Node -> Property Update Data + struct NodePropertyTrackData + { + QNode::PropertyTrackMode updateMode = QNode::DefaultTrackMode; + QStringList namedProperties; + }; + NodePropertyTrackData lookupNodePropertyTrackData(QNodeId id) const; + void setPropertyTrackDataForNode(QNodeId id, const NodePropertyTrackData &data); + void removePropertyTrackDataForNode(QNodeId id); + private: Q_DECLARE_PRIVATE(QScene) QScopedPointer<QScenePrivate> d_ptr; diff --git a/src/render/geometry/buffer.cpp b/src/render/geometry/buffer.cpp index aaae9825f..df0bc3c92 100644 --- a/src/render/geometry/buffer.cpp +++ b/src/render/geometry/buffer.cpp @@ -41,6 +41,7 @@ #include <Qt3DCore/qpropertyupdatedchange.h> #include <Qt3DRender/private/buffermanager_p.h> #include <Qt3DRender/private/qbuffer_p.h> +#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h> QT_BEGIN_NAMESPACE @@ -92,6 +93,7 @@ void Buffer::executeFunctor() e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("data"); e->setValue(QVariant::fromValue(m_data)); + Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } } diff --git a/src/render/io/scene.cpp b/src/render/io/scene.cpp index cf1ca4736..2057ffd3d 100644 --- a/src/render/io/scene.cpp +++ b/src/render/io/scene.cpp @@ -46,6 +46,7 @@ #include <Qt3DRender/private/qsceneloader_p.h> #include <Qt3DRender/private/scenemanager_p.h> #include <QtCore/qcoreapplication.h> +#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h> QT_BEGIN_NAMESPACE @@ -72,6 +73,7 @@ void Scene::setStatus(QSceneLoader::Status status) e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("status"); e->setValue(QVariant::fromValue(status)); + Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } @@ -114,6 +116,7 @@ void Scene::setSceneSubtree(Qt3DCore::QEntity *subTree) e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); e->setPropertyName("scene"); e->setValue(QVariant::fromValue(subTree)); + Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true; notifyObservers(e); } |