summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSvenn-Arne Dragly <s@dragly.com>2019-02-19 20:14:41 +0100
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2019-03-21 12:58:31 +0000
commit3c4591088f00e154281d5c6ce041ffe7da8f557b (patch)
tree8c074517278c7fc19f330108fbafa6ec2fc76e36
parent4b0237eb7891dacf5105e1e4ce4a5b29fc762509 (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.pri3
-rw-r--r--src/runtime/dragon/dragonentity.cpp21
-rw-r--r--src/runtime/dragon/dragonentity_p.h4
-rw-r--r--src/runtime/dragon/dragonmapper_p.h30
-rw-r--r--src/runtime/dragon/dragonnodetree_p.h124
-rw-r--r--src/runtime/dragon/dragonrendersettings.cpp16
-rw-r--r--src/runtime/dragon/dragonrendersettings_p.h8
-rw-r--r--src/runtime/dragon/dragontask_p.h1
-rw-r--r--src/runtime/dragon/framegraph/dragonframegraphnode.cpp44
-rw-r--r--src/runtime/dragon/framegraph/dragonframegraphnode_p.h6
-rw-r--r--src/runtime/dragon/jobs/dragontransformjobs.cpp35
-rw-r--r--src/runtime/dragon/jobs/dragontransformjobs_p.h2
-rw-r--r--src/runtime/dragon/jobs/dragontreejobs.cpp87
-rw-r--r--src/runtime/dragon/jobs/dragontreejobs_p.h86
-rw-r--r--src/runtime/dragon/qdragonrenderaspect.cpp46
-rw-r--r--src/runtime/dragon/qdragonrenderaspect_p.h54
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 &currentWorldTransform = *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;