diff options
author | Svenn-Arne Dragly <s@dragly.com> | 2019-02-19 20:14:41 +0100 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2019-03-21 12:58:31 +0000 |
commit | 3c4591088f00e154281d5c6ce041ffe7da8f557b (patch) | |
tree | 8c074517278c7fc19f330108fbafa6ec2fc76e36 | |
parent | 4b0237eb7891dacf5105e1e4ce4a5b29fc762509 (diff) |
Dragon: Introduce NodeTree
NodeTree is a separate class that holds the hierarchy of all the nodes.
This is then used to create the frame graph hierarhcy and the entity
hierarchy.
Change-Id: Idfc0b069d24b4e0ac2c108bf63f963403c8aefef
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
-rw-r--r-- | src/runtime/dragon/dragon.pri | 3 | ||||
-rw-r--r-- | src/runtime/dragon/dragonentity.cpp | 21 | ||||
-rw-r--r-- | src/runtime/dragon/dragonentity_p.h | 4 | ||||
-rw-r--r-- | src/runtime/dragon/dragonmapper_p.h | 30 | ||||
-rw-r--r-- | src/runtime/dragon/dragonnodetree_p.h | 124 | ||||
-rw-r--r-- | src/runtime/dragon/dragonrendersettings.cpp | 16 | ||||
-rw-r--r-- | src/runtime/dragon/dragonrendersettings_p.h | 8 | ||||
-rw-r--r-- | src/runtime/dragon/dragontask_p.h | 1 | ||||
-rw-r--r-- | src/runtime/dragon/framegraph/dragonframegraphnode.cpp | 44 | ||||
-rw-r--r-- | src/runtime/dragon/framegraph/dragonframegraphnode_p.h | 6 | ||||
-rw-r--r-- | src/runtime/dragon/jobs/dragontransformjobs.cpp | 35 | ||||
-rw-r--r-- | src/runtime/dragon/jobs/dragontransformjobs_p.h | 2 | ||||
-rw-r--r-- | src/runtime/dragon/jobs/dragontreejobs.cpp | 87 | ||||
-rw-r--r-- | src/runtime/dragon/jobs/dragontreejobs_p.h | 86 | ||||
-rw-r--r-- | src/runtime/dragon/qdragonrenderaspect.cpp | 46 | ||||
-rw-r--r-- | src/runtime/dragon/qdragonrenderaspect_p.h | 54 |
16 files changed, 355 insertions, 212 deletions
diff --git a/src/runtime/dragon/dragon.pri b/src/runtime/dragon/dragon.pri index a32fbec..2b09cbe 100644 --- a/src/runtime/dragon/dragon.pri +++ b/src/runtime/dragon/dragon.pri @@ -46,7 +46,8 @@ HEADERS += \ $$PWD/dragonmutable_p.h \ $$PWD/dragoncomparegenerators_p.h \ $$PWD/dragontextureproperties_p.h \ - $$PWD/dragonscene2d_p.h + $$PWD/dragonscene2d_p.h \ + $$PWD/dragonnodetree_p.h SOURCES += \ $$PWD/dragonattachment.cpp \ diff --git a/src/runtime/dragon/dragonentity.cpp b/src/runtime/dragon/dragonentity.cpp index 125e66c..a4e838c 100644 --- a/src/runtime/dragon/dragonentity.cpp +++ b/src/runtime/dragon/dragonentity.cpp @@ -67,7 +67,6 @@ void Entity::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &chang // Note this is *not* the parentId as that is the ID of the parent QNode, which is not // necessarily the same as the parent QEntity (which may be further up the tree). m_parentEntityId = data.parentEntityId; - m_childEntityIds = data.childEntityIds; for (const auto &idAndType : qAsConst(data.componentIdsAndTypes)) addComponent(idAndType); } @@ -93,26 +92,6 @@ void Entity::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) markDirty(); break; } - - case PropertyValueAdded: { - QPropertyNodeAddedChangePtr change = qSharedPointerCast<QPropertyNodeAddedChange>(e); - if (change->metaObject()->inherits(&QEntity::staticMetaObject)) { - if (!m_childEntityIds.contains(change->addedNodeId())) { - m_childEntityIds.push_back(change->addedNodeId()); - markDirty(Change::DirtyInfo::Tree); - } - } - break; - } - - case PropertyValueRemoved: { - QPropertyNodeRemovedChangePtr change = qSharedPointerCast<QPropertyNodeRemovedChange>(e); - if (change->metaObject()->inherits(&QEntity::staticMetaObject)) { - m_childEntityIds.removeAll(change->removedNodeId()); - markDirty(Change::DirtyInfo::Tree); - } - break; - } default: break; } diff --git a/src/runtime/dragon/dragonentity_p.h b/src/runtime/dragon/dragonentity_p.h index 2b15fdb..73143ea 100644 --- a/src/runtime/dragon/dragonentity_p.h +++ b/src/runtime/dragon/dragonentity_p.h @@ -68,10 +68,6 @@ public: Qt3DCore::QNodeId parentId() const; Qt3DCore::QNodeId cameraLensComponent() const; - // TODO not so happy about this, only needed for tree building - Qt3DCore::QNodeIdVector treeChildren() const { return m_childEntityIds; } - - QVector<Qt3DCore::QNodeId> m_childEntityIds; Qt3DCore::QNodeId m_materialComponent; QVector<Qt3DCore::QNodeId> m_layerComponents; Qt3DCore::QNodeId m_transformComponent; diff --git a/src/runtime/dragon/dragonmapper_p.h b/src/runtime/dragon/dragonmapper_p.h index 4399764..a688249 100644 --- a/src/runtime/dragon/dragonmapper_p.h +++ b/src/runtime/dragon/dragonmapper_p.h @@ -44,6 +44,11 @@ #include <private/dragonbackendnode_p.h> #include <private/dragonvaluecontainer_p.h> +#include <private/dragonnodetree_p.h> + +#include <Qt3DCore/qpropertynodeaddedchange.h> +#include <Qt3DCore/qpropertynoderemovedchange.h> +#include <Qt3DCore/qpropertyupdatedchange.h> #include <Qt3DCore/qpropertyupdatedchange.h> @@ -65,13 +70,15 @@ template <class Backend, class BackendTarget=Backend> class NodeFunctor : public Qt3DCore::QBackendNodeMapper { public: - NodeFunctor() + NodeFunctor(NodeTree *nodeTree) : m_localNodes(new ValueContainer<Backend>()) , m_nodes(m_localNodes.get()) + , m_nodeTree(nodeTree) {} - NodeFunctor(ValueContainer<Backend> *nodes) + NodeFunctor(NodeTree *nodeTree, ValueContainer<Backend> *nodes) : m_nodes(nodes) + , m_nodeTree(nodeTree) {} // TODO constructors, one takes nothing, creates nodes - other takes existing list @@ -84,6 +91,8 @@ public: void destroy(Qt3DCore::QNodeId id) const final { + m_nodeTree->removeNode(id); + auto &nodes = *m_nodes; // TODO consider use modified to show there's a copy nodes.remove(id); @@ -92,6 +101,8 @@ public: void initializeFromPeer(Qt3DCore::QNodeId id, const Qt3DCore::QNodeCreatedChangeBasePtr &change) const { + m_nodeTree->setParent(id, change->parentId()); + auto &nodes = *m_nodes; // Using a std::move here because we are assigning to the same node. @@ -103,6 +114,18 @@ public: void sceneChangeEvent(Qt3DCore::QNodeId id, const Qt3DCore::QSceneChangePtr &e) const { + switch (e->type()) { + case Qt3DCore::PropertyUpdated: { + Qt3DCore::QPropertyUpdatedChangePtr change = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e); + if (change->propertyName() == QByteArrayLiteral("parent")) { + m_nodeTree->setParent(id, change->value().value<Qt3DCore::QNodeId>()); + } + break; + } + default: + break; + } + auto &nodes = *m_nodes; // Using a std::move here because we are assigning to the same node. @@ -149,6 +172,7 @@ private: // TODO consider storing ValueContainer<BackendNode> (need to verify polymorphism) mutable QScopedPointer<ValueContainer<Backend>> m_localNodes; mutable ValueContainer<Backend> *m_nodes; + mutable NodeTree *m_nodeTree = nullptr; }; template <typename T, typename U> @@ -180,6 +204,8 @@ private: template<class Backend, class BackendTarget> Qt3DCore::QBackendNode *NodeFunctor<Backend, BackendTarget>::create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const { + m_nodeTree->addNode(change->subjectId()); + auto peerId = change->subjectId(); auto *wrapper = new MapperWrapper<Backend, BackendTarget>(this); m_wrappers[peerId] = wrapper; diff --git a/src/runtime/dragon/dragonnodetree_p.h b/src/runtime/dragon/dragonnodetree_p.h new file mode 100644 index 0000000..94cd72a --- /dev/null +++ b/src/runtime/dragon/dragonnodetree_p.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB). +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) 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.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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DRAGONNODETREE_P_H +#define DRAGONNODETREE_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. +// + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Dragon { + +/*! + * Qt3D passes very limited information to the backend about the child/parent hierarchy. + * Only parent information is passed on creation and only child information is passed in updates. + * The nodeTree tries its best to use information from the different + * NodeFunctors (a.k.a. QBackendNodeMappers) to construct a usable tree. + * + * TODO: Make Qt3D pass the parent id to the backend when parent changes and/or + * children on node creation. + */ +class NodeTree +{ +public: + struct NodeInfo + { + Qt3DCore::QNodeId parentId; + QVector<Qt3DCore::QNodeId> childIds; + }; + using Nodes = QHash<Qt3DCore::QNodeId, NodeInfo>; + + void addNode(Qt3DCore::QNodeId id) + { + // node might already exist if setParent or addChild was called first + if (!m_nodes.contains(id)) + m_nodes.insert(id, NodeInfo()); + } + + void removeNode(Qt3DCore::QNodeId id) + { + // this is mostly to clear the data in case the node appears again + NodeInfo node = m_nodes.take(id); + if (!node.parentId.isNull()) + m_nodes[node.parentId].childIds.removeOne(id); + } + + void setParent(Qt3DCore::QNodeId childId, Qt3DCore::QNodeId parentId) + { + // remove child from old parent + if (m_nodes.contains(childId)) { + Qt3DCore::QNodeId oldParentId = m_nodes[childId].parentId; + if (m_nodes.contains(oldParentId)) { + m_nodes[oldParentId].childIds.removeOne(childId); + } + } + // using operator[] here on purpose - we want to set it even if addNode has not been called + m_nodes[childId].parentId = parentId; + if (!parentId.isNull() && !m_nodes[parentId].childIds.contains(childId)) + m_nodes[parentId].childIds.push_back(childId); + } + + const QHash<Qt3DCore::QNodeId, NodeInfo> &nodes() + { + return m_nodes; + } + + // Task interface + QHash<Qt3DCore::QNodeId, NodeInfo> result() + { + return m_nodes; + } + + bool isFinished() + { + return true; + } + +private: + QHash<Qt3DCore::QNodeId, NodeInfo> m_nodes; +}; + +} // namespace Dragon +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // DRAGONNODETREE_P_H diff --git a/src/runtime/dragon/dragonrendersettings.cpp b/src/runtime/dragon/dragonrendersettings.cpp index 6bf33f0..dd24064 100644 --- a/src/runtime/dragon/dragonrendersettings.cpp +++ b/src/runtime/dragon/dragonrendersettings.cpp @@ -44,7 +44,7 @@ using namespace Qt3DCore; namespace Qt3DRender { namespace Dragon { -RenderSettings::RenderSettings() +RenderSettings::RenderSettings(NodeTree *nodeTree) : Qt3DCore::QBackendNode() , m_renderPolicy(QRenderSettings::OnDemand) , m_pickMethod(QPickingSettings::BoundingVolumePicking) @@ -52,11 +52,17 @@ RenderSettings::RenderSettings() , m_faceOrientationPickingMode(QPickingSettings::FrontFace) , m_pickWorldSpaceTolerance(.1f) , m_activeFrameGraph() + , m_nodeTree(nodeTree) { } +// TODO see if maybe all that was needed was for this to have a parent? + void RenderSettings::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) { + m_nodeTree->addNode(peerId()); + m_nodeTree->setParent(peerId(), change->parentId()); + const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QRenderSettingsData>>(change); const auto &data = typedChange->data; m_activeFrameGraph = data.activeFrameGraphId; @@ -84,14 +90,18 @@ void RenderSettings::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) m_activeFrameGraph = propertyChange->value().value<QNodeId>(); else if (propertyChange->propertyName() == QByteArrayLiteral("renderPolicy")) m_renderPolicy = propertyChange->value().value<QRenderSettings::RenderPolicy>(); + else if (propertyChange->propertyName() == QByteArrayLiteral("parent")) { + m_nodeTree->setParent(peerId(), propertyChange->value().value<QNodeId>()); + } // markDirty(AbstractRenderer::AllDirty); } QBackendNode::sceneChangeEvent(e); } -RenderSettingsFunctor::RenderSettingsFunctor(QDragonRenderAspect *renderer) +RenderSettingsFunctor::RenderSettingsFunctor(QDragonRenderAspect *renderer, NodeTree *nodeTree) : m_renderer(renderer) + , m_nodeTree(nodeTree) { } @@ -103,7 +113,7 @@ Qt3DCore::QBackendNode *RenderSettingsFunctor::create(const Qt3DCore::QNodeCreat return nullptr; } - RenderSettings *settings = new RenderSettings; + RenderSettings *settings = new RenderSettings(m_nodeTree); m_renderer->m_renderSettings = settings; return settings; } diff --git a/src/runtime/dragon/dragonrendersettings_p.h b/src/runtime/dragon/dragonrendersettings_p.h index d3dcf34..bda7fda 100644 --- a/src/runtime/dragon/dragonrendersettings_p.h +++ b/src/runtime/dragon/dragonrendersettings_p.h @@ -43,6 +43,8 @@ // #include <private/dragonbackendnode_p.h> +#include <private/dragonmapper_p.h> + #include <Qt3DRender/qrendersettings.h> #include <Qt3DRender/qpickingsettings.h> @@ -56,7 +58,7 @@ class QDragonRenderAspect; class Q_AUTOTEST_EXPORT RenderSettings : public Qt3DCore::QBackendNode { public: - RenderSettings(); + RenderSettings(NodeTree *nodeTree); void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override; @@ -79,18 +81,20 @@ private: QPickingSettings::FaceOrientationPickingMode m_faceOrientationPickingMode; float m_pickWorldSpaceTolerance; Qt3DCore::QNodeId m_activeFrameGraph; + NodeTree *m_nodeTree = nullptr; }; class RenderSettingsFunctor : public Qt3DCore::QBackendNodeMapper { public: - explicit RenderSettingsFunctor(QDragonRenderAspect *renderer); + explicit RenderSettingsFunctor(QDragonRenderAspect *renderer, NodeTree *nodeTree); Qt3DCore::QBackendNode *create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const override; Qt3DCore::QBackendNode *get(Qt3DCore::QNodeId id) const override; void destroy(Qt3DCore::QNodeId id) const override; private: QDragonRenderAspect *m_renderer = nullptr; + NodeTree *m_nodeTree = nullptr; }; } // namespace Render diff --git a/src/runtime/dragon/dragontask_p.h b/src/runtime/dragon/dragontask_p.h index 4d3150c..3fe2ed9 100644 --- a/src/runtime/dragon/dragontask_p.h +++ b/src/runtime/dragon/dragontask_p.h @@ -175,6 +175,7 @@ struct Task : public Qt3DCore::QAspectJob template <typename OtherTask, typename... Tasks> void assertTaskFinished(OtherTask task, Tasks... tasks) { + Q_UNUSED(task); Q_ASSERT(task != nullptr); Q_ASSERT(task->isFinished()); assertTaskFinished(tasks...); diff --git a/src/runtime/dragon/framegraph/dragonframegraphnode.cpp b/src/runtime/dragon/framegraph/dragonframegraphnode.cpp index 932c127..5b058bf 100644 --- a/src/runtime/dragon/framegraph/dragonframegraphnode.cpp +++ b/src/runtime/dragon/framegraph/dragonframegraphnode.cpp @@ -70,52 +70,8 @@ FrameGraphNode::~FrameGraphNode() { } -void FrameGraphNode::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) -{ - // Set up the parent child relationship and enabled state - const auto creationChange = qSharedPointerCast<QFrameGraphNodeCreatedChangeBase>(change); - m_childFrameGraphNodeIds = QFrameGraphNodeCreatedChangeBasePrivate::get(creationChange.get())->m_childFrameGraphNodeIds; -} - -QVector<Qt3DCore::QNodeId> FrameGraphNode::childrenIds() const -{ - return m_childFrameGraphNodeIds; -} - void FrameGraphNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) { - switch (e->type()) { - - case Qt3DCore::PropertyUpdated: { - Qt3DCore::QPropertyUpdatedChangePtr change = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e); - break; - } - - case Qt3DCore::PropertyValueAdded: { - Qt3DCore::QPropertyNodeAddedChangePtr change = qSharedPointerCast<Qt3DCore::QPropertyNodeAddedChange>(e); - if (change->metaObject()->inherits(&QFrameGraphNode::staticMetaObject)) { - if (!m_childFrameGraphNodeIds.contains(change->addedNodeId())) { - markDirty(Change::DirtyInfo::Tree); - m_childFrameGraphNodeIds.append(change->addedNodeId()); - } - } - break; - } - - case Qt3DCore::PropertyValueRemoved: { - Qt3DCore::QPropertyNodeRemovedChangePtr change = qSharedPointerCast<Qt3DCore::QPropertyNodeRemovedChange>(e); - if (change->metaObject()->inherits(&QFrameGraphNode::staticMetaObject)) { - m_childFrameGraphNodeIds.removeAll(change->removedNodeId()); - markDirty(Change::DirtyInfo::Tree); - } - break; - } - default: - break; - } - // TODO what if the parent changes? - - markDirty(); BackendNode::sceneChangeEvent(e); } diff --git a/src/runtime/dragon/framegraph/dragonframegraphnode_p.h b/src/runtime/dragon/framegraph/dragonframegraphnode_p.h index 680f834..44ba9e5 100644 --- a/src/runtime/dragon/framegraph/dragonframegraphnode_p.h +++ b/src/runtime/dragon/framegraph/dragonframegraphnode_p.h @@ -91,18 +91,12 @@ public: }; FrameGraphNodeType nodeType() const { return m_nodeType; } - QVector<Qt3DCore::QNodeId> childrenIds() const; - void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override; FrameGraphNode(FrameGraphNodeType nodeType, Qt3DCore::QBackendNode::Mode mode = Qt3DCore::QBackendNode::ReadOnly); - void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) override; - - Qt3DCore::QNodeIdVector treeChildren() const { return m_childFrameGraphNodeIds; } private: FrameGraphNodeType m_nodeType; - QVector<Qt3DCore::QNodeId> m_childFrameGraphNodeIds; friend class FrameGraphVisitor; }; diff --git a/src/runtime/dragon/jobs/dragontransformjobs.cpp b/src/runtime/dragon/jobs/dragontransformjobs.cpp index 921baae..2b84adc 100644 --- a/src/runtime/dragon/jobs/dragontransformjobs.cpp +++ b/src/runtime/dragon/jobs/dragontransformjobs.cpp @@ -46,20 +46,25 @@ namespace Qt3DRender { namespace Dragon { ValueContainer<Matrix4x4> calculateWorldTransforms(ValueContainer<Matrix4x4> worldTransforms, + const QHash<QNodeId, NodeTree::NodeInfo> hierarchy, const ValueContainer<Entity> &entities, const ValueContainer<Transform> &transforms, QNodeId rootEntityId) { worldTransforms.reset(); - if (!entities.anythingDirty() && !transforms.anythingDirty()) + // TODO remove false + if (!entities.anythingDirty() && !transforms.anythingDirty() && false) return worldTransforms; + worldTransforms = ValueContainer<Matrix4x4>(); + struct Data { Data() { } - Data(QNodeId entityId_, bool dirty_) : entityId(entityId_), dirty(dirty_) { } + Data(QNodeId entityId_, bool dirty_, int level_) : entityId(entityId_), dirty(dirty_), level(level_) { } QNodeId entityId; bool dirty = false; + int level = 0; }; // If entities are dirty, a transform component may have changed and we set the entire tree to @@ -78,23 +83,33 @@ ValueContainer<Matrix4x4> calculateWorldTransforms(ValueContainer<Matrix4x4> wor QStack<Data> stack; stack.reserve(10); - stack.push({ rootEntityId, rootDirty }); + stack.push({ rootEntityId, rootDirty, 0 }); while (!stack.isEmpty()) { auto currentItem = stack.pop(); QNodeId currentId = currentItem.entityId; - bool currentDirty = currentItem.dirty; + int level = currentItem.level; +// bool currentDirty = currentItem.dirty; + bool currentDirty = true; if (currentDirty) worldTransforms.markDirty(currentId); const auto ¤tWorldTransform = *worldTransforms[currentId]; - const auto &children = entities[currentId]->treeChildren(); + Q_ASSERT(hierarchy.contains(currentId)); + + const auto &children = hierarchy[currentId].childIds; // Iterate the children in reverse order (because the stack is last-in-first-out) // TODO use std::reverse_iterator once we have C++17 for (auto it = children.rbegin(); it != children.rend(); ++it) { const auto &childId = *it; + if (!entities.contains(childId)) { + // Skip past non-QEntity nodes + worldTransforms[childId] = currentWorldTransform; + stack.push({childId, currentDirty, level + 1}); + continue; + } const auto &childEntity = entities[childId]; bool childDirty = currentDirty || entities.hasDirtyOrCreated(childId); if (!childEntity->m_transformComponent.isNull()) { @@ -106,10 +121,18 @@ ValueContainer<Matrix4x4> calculateWorldTransforms(ValueContainer<Matrix4x4> wor if (childDirty) worldTransforms[childId] = currentWorldTransform; } - stack.push({ childId, childDirty }); + stack.push({ childId, childDirty, level + 1 }); } } +#ifdef QT_DEBUG + // Verify that all exist in debug mode only + for (const auto &key : entities.keys()) { + Q_ASSERT_X(worldTransforms.contains(key), "calculateWorldTransforms", + QStringLiteral("ERROR: Key %1 missing").arg(key.id()).toStdString().c_str()); + } +#endif + return worldTransforms; }; diff --git a/src/runtime/dragon/jobs/dragontransformjobs_p.h b/src/runtime/dragon/jobs/dragontransformjobs_p.h index 91269f6..991f2d0 100644 --- a/src/runtime/dragon/jobs/dragontransformjobs_p.h +++ b/src/runtime/dragon/jobs/dragontransformjobs_p.h @@ -49,6 +49,7 @@ #include <private/dragontreejobs_p.h> #include <private/dragonsphere_p.h> +#include <private/dragonmapper_p.h> QT_BEGIN_NAMESPACE @@ -61,6 +62,7 @@ class Geometry; class Buffer; ValueContainer<Matrix4x4> calculateWorldTransforms(ValueContainer<Matrix4x4> worldTransforms, + const QHash<Qt3DCore::QNodeId, NodeTree::NodeInfo> hierarchy, const ValueContainer<Entity> &entities, const ValueContainer<Transform> &transforms, Qt3DCore::QNodeId rootEntityId); diff --git a/src/runtime/dragon/jobs/dragontreejobs.cpp b/src/runtime/dragon/jobs/dragontreejobs.cpp index e60dc60..c3b01fc 100644 --- a/src/runtime/dragon/jobs/dragontreejobs.cpp +++ b/src/runtime/dragon/jobs/dragontreejobs.cpp @@ -33,6 +33,93 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { namespace Dragon { + +TreeInfo generateInheritanceTable(TreeInfo inheritanceTable, + const NodeTree::Nodes hierarchy, + const ValueContainer<FrameGraphNode> nodes, + Qt3DCore::QNodeId rootEntityId) +{ + inheritanceTable.nodes.reset(); + + if (!nodes.anythingDirty()) + return inheritanceTable; + + const auto &changes = nodes.changes(); + bool dirtyTree = false; + for (const auto &change : changes) { + if (change.action != Change::Action::Modified || change.info == Change::DirtyInfo::Tree) { + dirtyTree = true; + break; + } + } + if (!dirtyTree) + return inheritanceTable; + + // Clear old data + inheritanceTable.leafNodes.clear(); + inheritanceTable.nodes = synchronizeKeys(std::move(inheritanceTable.nodes), nodes); + inheritanceTable.rootNode = rootEntityId; + + // Clear old data, set parent and find all children of all nodes + for (const auto &id : nodes.keys()) { + auto tableNode = *(inheritanceTable.nodes[id]); + inheritanceTable.nodes.markDirty(id); + inheritanceTable.nodes[id] = tableNode; + } + + + { + // Traverse the tree from top to bottom to add ancestor and descendant information + // using a depth-first search. + QStack<Qt3DCore::QNodeId> stack; + stack.push(rootEntityId); + while (!stack.isEmpty()) { + auto currentId = stack.pop(); + QVector<Qt3DCore::QNodeId> currentAncestors = inheritanceTable.nodes[currentId]->ancestors + + QVector<Qt3DCore::QNodeId>{{currentId}}; + + // NOTE: A copy is necessary, because we might insert into the map below + const QVector<Qt3DCore::QNodeId> children = hierarchy[currentId].childIds; + QVector<Qt3DCore::QNodeId> nodeChildren; + for (const auto &childId : children) { + if (nodes.contains(childId)) { + nodeChildren.push_back(childId); + } + } + + if (nodeChildren.isEmpty()) { + inheritanceTable.leafNodes.push_back(currentId); + continue; + } + + // Iterate the children in reverse order (because the stack is last-in-first-out) + // TODO use std::reverse_iterator once we have C++17 + for (auto it = nodeChildren.rbegin(); it != nodeChildren.rend(); ++it) { + const auto &childId = *it; + auto child = *inheritanceTable.nodes[childId]; + child.ancestors = currentAncestors; + inheritanceTable.nodes[childId] = child; + // Go through all ancestors and add us as a child + for (const auto &ancestorId : qAsConst(currentAncestors)) { + auto ancestor = *inheritanceTable.nodes[ancestorId]; + ancestor.descendants.push_back(childId); + inheritanceTable.nodes[ancestorId] = ancestor; + } + // Only add if not added as one of the dirty nodes + stack.push(childId); + } + } + // Reverse all the ancestor lists + for (const auto &id : inheritanceTable.nodes.keys()) { + auto node = *inheritanceTable.nodes[id]; + std::reverse(node.ancestors.begin(), node.ancestors.end()); + inheritanceTable.nodes[id] = node; + } + } + + return inheritanceTable; +} + } // namespace Dragon } // namespace Qt3DRender QT_END_NAMESPACE diff --git a/src/runtime/dragon/jobs/dragontreejobs_p.h b/src/runtime/dragon/jobs/dragontreejobs_p.h index bcc6246..33cafbb 100644 --- a/src/runtime/dragon/jobs/dragontreejobs_p.h +++ b/src/runtime/dragon/jobs/dragontreejobs_p.h @@ -45,6 +45,8 @@ #include <private/dragonjobs_common_p.h> #include <private/dragontextureimage_p.h> #include <private/dragonvaluecontainer_p.h> +#include <private/dragonnodetree_p.h> +#include <private/dragonframegraphnode_p.h> #include <Qt3DCore/QNodeId> @@ -64,13 +66,11 @@ struct InheritanceInfo // TODO consider adding an ancestor list that includes ourselves (useful to build render views) QVector<Key> ancestors; QVector<Key> descendants; - QVector<Key> children; void clear() { ancestors.clear(); descendants.clear(); - children.clear(); } }; @@ -82,84 +82,10 @@ struct TreeInfo Key rootNode; }; -template<typename T> -TreeInfo generateInheritanceTable(TreeInfo inheritanceTable, T nodes, Qt3DCore::QNodeId rootEntityId) -{ - inheritanceTable.nodes.reset(); - - if (!nodes.anythingDirty()) - return inheritanceTable; - - const auto &changes = nodes.changes(); - bool dirtyTree = false; - for (const auto &change : changes) { - if (change.action != Change::Action::Modified || change.info == Change::DirtyInfo::Tree) { - dirtyTree = true; - break; - } - } - if (!dirtyTree) - return inheritanceTable; - - // Clear old data - inheritanceTable.leafNodes.clear(); - inheritanceTable.nodes = synchronizeKeys(std::move(inheritanceTable.nodes), nodes); - inheritanceTable.rootNode = rootEntityId; - - // Clear old data, set parent and find all children of all nodes - for (const auto &id : nodes.keys()) { - const auto &node = nodes[id]; - auto tableNode = *(inheritanceTable.nodes[id]); - inheritanceTable.nodes.markDirty(id); - tableNode.children = node->treeChildren(); - inheritanceTable.nodes[id] = tableNode; - } - - { - // Traverse the tree from top to bottom to add ancestor and descendant information - // using a depth-first search. - QStack<Qt3DCore::QNodeId> stack; - stack.push(rootEntityId); - while (!stack.isEmpty()) { - auto currentId = stack.pop(); - QVector<Qt3DCore::QNodeId> currentAncestors = inheritanceTable.nodes[currentId]->ancestors - + QVector<Qt3DCore::QNodeId>{{currentId}}; - - // NOTE: A copy is necessary, because we might insert into the map below - const auto children = inheritanceTable.nodes[currentId]->children; - - if (children.isEmpty()) { - inheritanceTable.leafNodes.push_back(currentId); - continue; - } - - // Iterate the children in reverse order (because the stack is last-in-first-out) - // TODO use std::reverse_iterator once we have C++17 - for (auto it = children.rbegin(); it != children.rend(); ++it) { - const auto &childId = *it; - auto child = *inheritanceTable.nodes[childId]; - child.ancestors = currentAncestors; - inheritanceTable.nodes[childId] = child; - // Go through all ancestors and add us as a child - for (const auto &ancestorId : qAsConst(currentAncestors)) { - auto ancestor = *inheritanceTable.nodes[ancestorId]; - ancestor.descendants.push_back(childId); - inheritanceTable.nodes[ancestorId] = ancestor; - } - // Only add if not added as one of the dirty nodes - stack.push(childId); - } - } - // Reverse all the ancestor lists - for (const auto &id : inheritanceTable.nodes.keys()) { - auto node = *inheritanceTable.nodes[id]; - std::reverse(node.ancestors.begin(), node.ancestors.end()); - inheritanceTable.nodes[id] = node; - } - } - - return inheritanceTable; -} +TreeInfo generateInheritanceTable(TreeInfo inheritanceTable, + const NodeTree::Nodes hierarchy, + const ValueContainer<FrameGraphNode> nodes, + Qt3DCore::QNodeId rootEntityId); } // namespace Dragon } // namespace Qt3DRender diff --git a/src/runtime/dragon/qdragonrenderaspect.cpp b/src/runtime/dragon/qdragonrenderaspect.cpp index bad00f3..2f53d16 100644 --- a/src/runtime/dragon/qdragonrenderaspect.cpp +++ b/src/runtime/dragon/qdragonrenderaspect.cpp @@ -216,56 +216,59 @@ QDragonRenderAspect::QDragonRenderAspect(Renderer::RenderType renderType) registerBackendType<Quick::QScene2D>(m_scene2ds); // Custom functors - registerBackendType<QRenderSettings>(QSharedPointer<RenderSettingsFunctor>::create(this)); + registerBackendType<QRenderSettings>(QSharedPointer<RenderSettingsFunctor>::create(this, &m_nodeTree)); // Framegraph registerBackendType<QFrameGraphNode>( - NodeFunctorPtr<FrameGraphNode, FrameGraphNode>::create(&m_frameGraphNodesContainer)); + NodeFunctorPtr<FrameGraphNode, FrameGraphNode>::create(&m_nodeTree, &m_frameGraphNodesContainer)); registerBackendType<QCameraSelector>( - NodeFunctorPtr<FrameGraphNode, CameraSelector>::create(&m_frameGraphNodesContainer)); + NodeFunctorPtr<FrameGraphNode, CameraSelector>::create(&m_nodeTree, &m_frameGraphNodesContainer)); registerBackendType<QClearBuffers>( - NodeFunctorPtr<FrameGraphNode, ClearBuffers>::create(&m_frameGraphNodesContainer)); + NodeFunctorPtr<FrameGraphNode, ClearBuffers>::create(&m_nodeTree, &m_frameGraphNodesContainer)); registerBackendType<QDispatchCompute>( - NodeFunctorPtr<FrameGraphNode, DispatchCompute>::create(&m_frameGraphNodesContainer)); + NodeFunctorPtr<FrameGraphNode, DispatchCompute>::create(&m_nodeTree, &m_frameGraphNodesContainer)); registerBackendType<QFrustumCulling>( - NodeFunctorPtr<FrameGraphNode, FrustumCulling>::create(&m_frameGraphNodesContainer)); + NodeFunctorPtr<FrameGraphNode, FrustumCulling>::create(&m_nodeTree, &m_frameGraphNodesContainer)); registerBackendType<QLayerFilter>( - NodeFunctorPtr<FrameGraphNode, LayerFilterNode>::create(&m_frameGraphNodesContainer)); + NodeFunctorPtr<FrameGraphNode, LayerFilterNode>::create(&m_nodeTree, &m_frameGraphNodesContainer)); registerBackendType<QNoDraw>( - NodeFunctorPtr<FrameGraphNode, NoDraw>::create(&m_frameGraphNodesContainer)); + NodeFunctorPtr<FrameGraphNode, NoDraw>::create(&m_nodeTree, &m_frameGraphNodesContainer)); registerBackendType<QRenderPassFilter>( - NodeFunctorPtr<FrameGraphNode, RenderPassFilter>::create(&m_frameGraphNodesContainer)); + NodeFunctorPtr<FrameGraphNode, RenderPassFilter>::create(&m_nodeTree, &m_frameGraphNodesContainer)); registerBackendType<QRenderStateSet>( - NodeFunctorPtr<FrameGraphNode, StateSetNode>::create(&m_frameGraphNodesContainer)); + NodeFunctorPtr<FrameGraphNode, StateSetNode>::create(&m_nodeTree, &m_frameGraphNodesContainer)); registerBackendType<QRenderSurfaceSelector>( - NodeFunctorPtr<FrameGraphNode, RenderSurfaceSelector>::create(&m_frameGraphNodesContainer)); + NodeFunctorPtr<FrameGraphNode, RenderSurfaceSelector>::create(&m_nodeTree, &m_frameGraphNodesContainer)); registerBackendType<QRenderTargetSelector>( - NodeFunctorPtr<FrameGraphNode, RenderTargetSelector>::create(&m_frameGraphNodesContainer)); + NodeFunctorPtr<FrameGraphNode, RenderTargetSelector>::create(&m_nodeTree, &m_frameGraphNodesContainer)); registerBackendType<QSortPolicy>( - NodeFunctorPtr<FrameGraphNode, SortPolicy>::create(&m_frameGraphNodesContainer)); + NodeFunctorPtr<FrameGraphNode, SortPolicy>::create(&m_nodeTree, &m_frameGraphNodesContainer)); registerBackendType<QTechniqueFilter>( - NodeFunctorPtr<FrameGraphNode, TechniqueFilter>::create(&m_frameGraphNodesContainer)); + NodeFunctorPtr<FrameGraphNode, TechniqueFilter>::create(&m_nodeTree, &m_frameGraphNodesContainer)); registerBackendType<QViewport>( - NodeFunctorPtr<FrameGraphNode, ViewportNode>::create(&m_frameGraphNodesContainer)); + NodeFunctorPtr<FrameGraphNode, ViewportNode>::create(&m_nodeTree, &m_frameGraphNodesContainer)); registerBackendType<QRenderCapture>( - NodeFunctorPtr<FrameGraphNode, RenderCapture>::create(&m_frameGraphNodesContainer)); + NodeFunctorPtr<FrameGraphNode, RenderCapture>::create(&m_nodeTree, &m_frameGraphNodesContainer)); registerBackendType<QBufferCapture>( - NodeFunctorPtr<FrameGraphNode, BufferCapture>::create(&m_frameGraphNodesContainer)); + NodeFunctorPtr<FrameGraphNode, BufferCapture>::create(&m_nodeTree, &m_frameGraphNodesContainer)); // TODO add this back when MemoryBarrier is expanded correctly on MinGW... // registerBackendType<QMemoryBarrier>( // NodeFunctorPtr<FrameGraphNode, MemoryBarrier>::create(&m_frameGraphNodesContainer)); registerBackendType<QProximityFilter>( - NodeFunctorPtr<FrameGraphNode, ProximityFilter>::create(&m_frameGraphNodesContainer)); + NodeFunctorPtr<FrameGraphNode, ProximityFilter>::create(&m_nodeTree, &m_frameGraphNodesContainer)); registerBackendType<QBlitFramebuffer>( - NodeFunctorPtr<FrameGraphNode, BlitFramebuffer>::create(&m_frameGraphNodesContainer)); + NodeFunctorPtr<FrameGraphNode, BlitFramebuffer>::create(&m_nodeTree, &m_frameGraphNodesContainer)); + + // Catch-all for other nodes. Necessary to gather information about the hierarchy. + registerBackendType<Qt3DCore::QNode>(m_otherNodes); // TODO could be done in header or initializer // TODO syntax could be improved, consider adding a createEdge/setInput function m_calculateWorldTransforms = TaskPtr<ValueContainer<Matrix4x4>>::create( - calculateWorldTransforms, Self, m_entities, m_transforms, m_rootEntitySource); + calculateWorldTransforms, Self, &m_nodeTree, m_entities, m_transforms, m_rootEntitySource); m_loadBuffers = TaskPtr<LoadedBuffers>::create(loadBuffers, Self, m_buffers); @@ -298,8 +301,9 @@ QDragonRenderAspect::QDragonRenderAspect(Renderer::RenderType renderType) // m_loadShaders = TaskPtr<ValueContainer<GLShader>>::create(uploadShaders, Self, m_shaders); - m_generateFrameGraph = TaskPtr<TreeInfo>::create(generateInheritanceTable<ValueContainer<FrameGraphNode>>, + m_generateFrameGraph = TaskPtr<TreeInfo>::create(generateInheritanceTable, Self, + &m_nodeTree, m_frameGraphNodes, m_rootFrameGraphNodeSource); diff --git a/src/runtime/dragon/qdragonrenderaspect_p.h b/src/runtime/dragon/qdragonrenderaspect_p.h index e788243..dedecac 100644 --- a/src/runtime/dragon/qdragonrenderaspect_p.h +++ b/src/runtime/dragon/qdragonrenderaspect_p.h @@ -109,6 +109,10 @@ using CacheValueContainer = CacheContainer<Immutable<T>, U>; template<typename T> using BasicContainer = TrackingChangesContainer<T>; +class DummyNode : public BackendNode +{ +}; + // aspect.h class Q3DSV_EXPORT QDragonRenderAspect : public Qt3DCore::QAbstractAspect { @@ -125,34 +129,40 @@ private: QVector<Qt3DCore::QAspectJobPtr> m_jobs; + // Hierarchy manager, necessary because Qt 3D passes limited hierarchy information to the backend + NodeTree m_nodeTree; + // Backend nodes - NodeFunctorPtr<Entity> m_entities = NodeFunctorPtr<Entity>::create(); - NodeFunctorPtr<Transform> m_transforms = NodeFunctorPtr<Transform>::create(); - NodeFunctorPtr<Texture> m_textures = NodeFunctorPtr<Texture>::create(); - NodeFunctorPtr<TextureImage> m_textureImages = NodeFunctorPtr<TextureImage>::create(); - NodeFunctorPtr<Buffer> m_buffers = NodeFunctorPtr<Buffer>::create(); - NodeFunctorPtr<Parameter> m_parameters = NodeFunctorPtr<Parameter>::create(); - NodeFunctorPtr<Material> m_materials = NodeFunctorPtr<Material>::create(); - NodeFunctorPtr<Effect> m_effects = NodeFunctorPtr<Effect>::create(); - NodeFunctorPtr<Technique> m_techniques = NodeFunctorPtr<Technique>::create(); - NodeFunctorPtr<FilterKey> m_filterKeys = NodeFunctorPtr<FilterKey>::create(); - NodeFunctorPtr<Geometry> m_geometries = NodeFunctorPtr<Geometry>::create(); - NodeFunctorPtr<GeometryRenderer> m_geometryRenderers = NodeFunctorPtr<GeometryRenderer>::create(); - NodeFunctorPtr<Attribute> m_attributes = NodeFunctorPtr<Attribute>::create(); - NodeFunctorPtr<CameraLens> m_cameraLenses = NodeFunctorPtr<CameraLens>::create(); - NodeFunctorPtr<RenderTarget> m_renderTargets = NodeFunctorPtr<RenderTarget>::create(); - NodeFunctorPtr<RenderPass> m_renderPasses = NodeFunctorPtr<RenderPass>::create(); + NodeFunctorPtr<Entity> m_entities = NodeFunctorPtr<Entity>::create(&m_nodeTree); + NodeFunctorPtr<Transform> m_transforms = NodeFunctorPtr<Transform>::create(&m_nodeTree); + NodeFunctorPtr<Texture> m_textures = NodeFunctorPtr<Texture>::create(&m_nodeTree); + NodeFunctorPtr<TextureImage> m_textureImages = NodeFunctorPtr<TextureImage>::create(&m_nodeTree); + NodeFunctorPtr<Buffer> m_buffers = NodeFunctorPtr<Buffer>::create(&m_nodeTree); + NodeFunctorPtr<Parameter> m_parameters = NodeFunctorPtr<Parameter>::create(&m_nodeTree); + NodeFunctorPtr<Material> m_materials = NodeFunctorPtr<Material>::create(&m_nodeTree); + NodeFunctorPtr<Effect> m_effects = NodeFunctorPtr<Effect>::create(&m_nodeTree); + NodeFunctorPtr<Technique> m_techniques = NodeFunctorPtr<Technique>::create(&m_nodeTree); + NodeFunctorPtr<FilterKey> m_filterKeys = NodeFunctorPtr<FilterKey>::create(&m_nodeTree); + NodeFunctorPtr<Geometry> m_geometries = NodeFunctorPtr<Geometry>::create(&m_nodeTree); + NodeFunctorPtr<GeometryRenderer> m_geometryRenderers = NodeFunctorPtr<GeometryRenderer>::create(&m_nodeTree); + NodeFunctorPtr<Attribute> m_attributes = NodeFunctorPtr<Attribute>::create(&m_nodeTree); + NodeFunctorPtr<CameraLens> m_cameraLenses = NodeFunctorPtr<CameraLens>::create(&m_nodeTree); + NodeFunctorPtr<RenderTarget> m_renderTargets = NodeFunctorPtr<RenderTarget>::create(&m_nodeTree); + NodeFunctorPtr<RenderPass> m_renderPasses = NodeFunctorPtr<RenderPass>::create(&m_nodeTree); NodeFunctorPtr<RenderTargetOutput> m_renderTargetOutputs - = NodeFunctorPtr<RenderTargetOutput>::create(); - NodeFunctorPtr<Shader> m_shaders = NodeFunctorPtr<Shader>::create(); - NodeFunctorPtr<ShaderData> m_shaderDatas = NodeFunctorPtr<ShaderData>::create(); - NodeFunctorPtr<RenderStateNode> m_renderStates = NodeFunctorPtr<RenderStateNode>::create(); - NodeFunctorPtr<Scene2D> m_scene2ds = NodeFunctorPtr<Scene2D>::create(); + = NodeFunctorPtr<RenderTargetOutput>::create(&m_nodeTree); + NodeFunctorPtr<Shader> m_shaders = NodeFunctorPtr<Shader>::create(&m_nodeTree); + NodeFunctorPtr<ShaderData> m_shaderDatas = NodeFunctorPtr<ShaderData>::create(&m_nodeTree); + NodeFunctorPtr<RenderStateNode> m_renderStates = NodeFunctorPtr<RenderStateNode>::create(&m_nodeTree); + NodeFunctorPtr<Scene2D> m_scene2ds = NodeFunctorPtr<Scene2D>::create(&m_nodeTree); // Frame graph ValueContainer<FrameGraphNode> m_frameGraphNodesContainer; NodeFunctorPtr<FrameGraphNode> m_frameGraphNodes = NodeFunctorPtr<FrameGraphNode>::create( - &m_frameGraphNodesContainer); + &m_nodeTree, &m_frameGraphNodesContainer); + + // Catch-all fallback for unknown nodes. Necessary for hierarchy information. + NodeFunctorPtr<DummyNode> m_otherNodes = NodeFunctorPtr<DummyNode>::create(&m_nodeTree); RenderSettings *m_renderSettings = nullptr; |