1// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qframegraphnode.h"
5#include "qframegraphnode_p.h"
6#include <Qt3DRender/qfilterkey.h>
7#include <Qt3DRender/qtechniquefilter.h>
8#include <Qt3DRender/qrenderpassfilter.h>
9
10#include <Qt3DCore/QNode>
11#include <QList>
12#include <QQueue>
13
14
15QT_BEGIN_NAMESPACE
16
17namespace {
18
19QString dumpNode(const Qt3DRender::QFrameGraphNode *n) {
20 QString res = QLatin1String(n->metaObject()->className());
21 if (!n->objectName().isEmpty())
22 res += QString(QLatin1String(" (%1)")).arg(a: n->objectName());
23 if (!n->isEnabled())
24 res += QLatin1String(" [D]");
25 return res;
26}
27
28QString dumpNodeFilters(const Qt3DRender::QFrameGraphNode *n, const QList<Qt3DRender::QFilterKey *> &filters) {
29 QString res = QLatin1String(n->metaObject()->className());
30 if (!n->objectName().isEmpty())
31 res += QString(QLatin1String(" (%1)")).arg(a: n->objectName());
32
33 QStringList kv;
34 for (auto filter: filters)
35 kv.push_back(t: QString(QLatin1String("%1: %2")).arg(args: filter->name(), args: filter->value().toString()));
36 if (!kv.empty())
37 res += QString(QLatin1String(" <%1>")).arg(a: kv.join(sep: QLatin1String(", ")));
38
39 return res;
40}
41
42QStringList dumpFG(const Qt3DCore::QNode *n, int level = 0)
43{
44 QStringList reply;
45
46 const Qt3DRender::QFrameGraphNode *fgNode = qobject_cast<const Qt3DRender::QFrameGraphNode *>(object: n);
47 if (fgNode) {
48 QString res = dumpNode(n: fgNode);
49 reply += res.rightJustified(width: res.size() + level * 2, fill: QLatin1Char(' '));
50 }
51
52 const auto children = n->childNodes();
53 const int inc = fgNode ? 1 : 0;
54 for (auto *child: children) {
55 auto *childFGNode = qobject_cast<Qt3DCore::QNode *>(object: child);
56 if (childFGNode != nullptr)
57 reply += dumpFG(n: childFGNode, level: level + inc);
58 }
59
60 return reply;
61}
62
63struct HierarchyFGNode
64{
65 const Qt3DRender::QFrameGraphNode *root;
66 QList<QSharedPointer<HierarchyFGNode>> children;
67};
68using HierarchyFGNodePtr = QSharedPointer<HierarchyFGNode>;
69
70HierarchyFGNodePtr buildFGHierarchy(const Qt3DCore::QNode *n, HierarchyFGNodePtr lastFGParent = HierarchyFGNodePtr())
71{
72 const Qt3DRender::QFrameGraphNode *fgNode = qobject_cast<const Qt3DRender::QFrameGraphNode *>(object: n);
73
74 // Only happens for the root case
75 if (!lastFGParent) {
76 lastFGParent = HierarchyFGNodePtr::create();
77 lastFGParent->root = fgNode;
78 } else {
79 if (fgNode != nullptr) {
80 HierarchyFGNodePtr hN = HierarchyFGNodePtr::create();
81 hN->root = fgNode;
82 if (lastFGParent)
83 lastFGParent->children.push_back(t: hN);
84 lastFGParent = hN;
85 }
86 }
87
88 const auto children = n->childNodes();
89 for (auto *child: children)
90 buildFGHierarchy(n: child, lastFGParent);
91
92 return lastFGParent;
93}
94
95void findFGLeaves(const HierarchyFGNodePtr root, QList<const Qt3DRender::QFrameGraphNode *> &fgLeaves)
96{
97 const auto children = root->children;
98 for (const auto &child : children)
99 findFGLeaves(root: child, fgLeaves);
100
101 if (children.empty())
102 fgLeaves.push_back(t: root->root);
103}
104
105void dumpFGPaths(const Qt3DRender::QFrameGraphNode *n, QStringList &result)
106{
107 // Build FG node hierarchy
108 const HierarchyFGNodePtr rootHFg = buildFGHierarchy(n);
109
110 // Gather FG leaves
111 QList<const Qt3DRender::QFrameGraphNode *> fgLeaves;
112 findFGLeaves(root: rootHFg, fgLeaves);
113
114 // Traverse back to root
115 int rv = 1;
116 for (const Qt3DRender::QFrameGraphNode *fgNode : fgLeaves) {
117 QStringList parents;
118 while (fgNode != nullptr) {
119 parents.prepend(t: dumpNode(n: fgNode));
120 fgNode = fgNode->parentFrameGraphNode();
121 }
122 if (!parents.empty()) {
123 result << QString(QLatin1String("%1 [ %2 ]")).arg(args: QString::number(rv), args: parents.join(sep: QLatin1String(", ")));
124 ++rv;
125 }
126 }
127}
128
129void dumpFGFilterState(const Qt3DRender::QFrameGraphNode *n, QStringList &result)
130{
131 // Build FG node hierarchy
132 const HierarchyFGNodePtr rootHFg = buildFGHierarchy(n);
133
134 // Gather FG leaves
135 QList<const Qt3DRender::QFrameGraphNode *> fgLeaves;
136 findFGLeaves(root: rootHFg, fgLeaves);
137
138 // Traverse back to root
139 int rv = 1;
140 for (const Qt3DRender::QFrameGraphNode *fgNode : fgLeaves) {
141 int parents = 0;
142 QStringList filters;
143 while (fgNode != nullptr) {
144 ++parents;
145 if (fgNode->isEnabled()) {
146 auto techniqueFilter = qobject_cast<const Qt3DRender::QTechniqueFilter *>(object: fgNode);
147 if (techniqueFilter && techniqueFilter->matchAll().size())
148 filters.prepend(t: dumpNodeFilters(n: techniqueFilter, filters: techniqueFilter->matchAll()));
149 auto renderPassFilter = qobject_cast<const Qt3DRender::QRenderPassFilter *>(object: fgNode);
150 if (renderPassFilter)
151 filters.prepend(t: dumpNodeFilters(n: renderPassFilter, filters: renderPassFilter->matchAny()));
152 }
153 fgNode = fgNode->parentFrameGraphNode();
154 }
155 if (parents) {
156 if (!filters.empty())
157 result << QString(QLatin1String("%1 [ %2 ]")).arg(args: QString::number(rv), args: filters.join(sep: QLatin1String(", ")));
158 else
159 result << QString(QObject::tr(s: "%1 [ No Filters ]")).arg(a: rv);
160 ++rv;
161 }
162 }
163}
164
165}
166
167namespace Qt3DRender {
168
169QFrameGraphNodePrivate::QFrameGraphNodePrivate()
170 : QNodePrivate()
171{
172}
173
174/*!
175 \class Qt3DRender::QFrameGraphNode
176 \inmodule Qt3DRender
177 \since 5.5
178
179 \brief Base class of all FrameGraph configuration nodes.
180
181 This class is rarely instanced directly since it doesn't provide
182 any frame graph specific behavior, although it can be convenient
183 to use for grouping other nodes together in dynamic frame graphs.
184 The actual behavior comes from the subclasses.
185
186 The subclasses are:
187 \table
188 \header
189 \li class
190 \li description
191 \row
192 \li Qt3DRender::QCameraSelector
193 \li Select camera from all available cameras in the scene
194 \row
195 \li Qt3DRender::QClearBuffers
196 \li Specify which buffers to clear and to what values
197 \row
198 \li Qt3DRender::QDispatchCompute
199 \li Specify Compute operation kernels
200 \row
201 \li Qt3DRender::QFrustumCulling
202 \li Enable frustum culling
203 \row
204 \li Qt3DRender::QLayerFilter
205 \li Select which layers to draw
206 \row
207 \li Qt3DRender::QNoDraw
208 \li Disable drawing
209 \row
210 \li Qt3DRender::QRenderPassFilter
211 \li Select which render passes to draw
212 \row
213 \li Qt3DRender::QRenderStateSet
214 \li Set render states
215 \row
216 \li Qt3DRender::QRenderSurfaceSelector
217 \li Select which surface to draw to
218 \row
219 \li Qt3DRender::QRenderTargetSelector
220 \li Select which QRenderTarget to draw to
221 \row
222 \li Qt3DRender::QSortPolicy
223 \li Specify how entities are sorted to determine draw order
224 \row
225 \li Qt3DRender::QTechniqueFilter
226 \li Select which techniques to draw
227 \row
228 \li Qt3DRender::QViewport
229 \li Specify viewport
230 \row
231 \li Qt3DRender::QMemoryBarrier
232 \li Places a memory barrier
233 \endtable
234
235 */
236
237/*!
238 \qmltype FrameGraphNode
239 \inqmlmodule Qt3D.Render
240 \nativetype Qt3DRender::QFrameGraphNode
241 \inherits Node
242 \since 5.5
243 \brief Base class of all FrameGraph configuration nodes.
244
245 This class is rarely instanced directly since it doesn't provide
246 any frame graph specific behavior, although it can be convenient
247 to use for grouping other nodes together in dynamic frame graphs.
248 The actual behavior comes from the subclasses.
249
250 The subclasses are:
251 \table
252 \header
253 \li class
254 \li description
255 \row
256 \li CameraSelector
257 \li Select camera from all available cameras in the scene
258 \row
259 \li ClearBuffers
260 \li Specify which buffers to clear and to what values
261 \row
262 \li DispatchCompute
263 \li Specify compute operation kernels
264 \row
265 \li FrustumCulling
266 \li Enable frustum culling
267 \row
268 \li LayerFilter
269 \li Select which layers to draw
270 \row
271 \li NoDraw
272 \li Disable drawing
273 \row
274 \li RenderPassFilter
275 \li Select which render passes to draw
276 \row
277 \li RenderStateSet
278 \li Set render states
279 \row
280 \li RenderSurfaceSelector
281 \li Select which surface to draw to
282 \row
283 \li RenderTargetSelector
284 \li Select which RenderTarget to draw to
285 \row
286 \li SortPolicy
287 \li Specify how entities are sorted to determine draw order
288 \row
289 \li TechniqueFilter
290 \li Select which techniques to draw
291 \row
292 \li Viewport
293 \li Specify viewport
294 \row
295 \li MemoryBarrier
296 \li Places a memory barrier
297 \endtable
298*/
299
300/*!
301 The constructor creates an instance with the specified \a parent.
302 */
303QFrameGraphNode::QFrameGraphNode(QNode *parent)
304 : QNode(*new QFrameGraphNodePrivate, parent)
305{
306}
307
308/*! \internal */
309QFrameGraphNode::~QFrameGraphNode()
310{
311}
312
313/*!
314 Returns a pointer to the parent frame graph node.
315
316 If the parent of this node is not a frame graph node,
317 this method will recursively look for a parent node that is a frame graph node.
318 */
319QFrameGraphNode *QFrameGraphNode::parentFrameGraphNode() const
320{
321 QFrameGraphNode *parentFGNode = nullptr;
322 QNode *parentN = parentNode();
323
324 while (parentN) {
325 if ((parentFGNode = qobject_cast<QFrameGraphNode *>(object: parentN)) != nullptr)
326 break;
327 parentN = parentN->parentNode();
328 }
329 return parentFGNode;
330}
331
332/*!
333 \internal
334 * Returns a list of the children that are frame graph nodes.
335 * If this function encounters a child node that is not a frame graph node,
336 * it will go through the children of the child node and look for frame graph nodes.
337 * If any of these are not frame graph nodes, they will be further searched as
338 * if they were direct children of this node.
339 */
340QList<QFrameGraphNode *> QFrameGraphNodePrivate::childFrameGraphNodes() const
341{
342 using namespace Qt3DCore;
343
344 Q_Q(const QFrameGraphNode);
345 QList<QFrameGraphNode *> result;
346 QQueue<QNode *> queue;
347 const auto childNodes = q->childNodes();
348 for (auto c: childNodes)
349 queue.append(t: c);
350 result.reserve(size: queue.size());
351 while (!queue.isEmpty()) {
352 auto *child = queue.dequeue();
353 auto *childFGNode = qobject_cast<QFrameGraphNode *>(object: child);
354 if (childFGNode != nullptr)
355 result.push_back(t: childFGNode);
356 else {
357 const auto childNodes = child->childNodes();
358 for (auto c: childNodes)
359 queue.append(t: c);
360 }
361 }
362 return result;
363}
364
365QString QFrameGraphNodePrivate::dumpFrameGraph() const
366{
367 Q_Q(const QFrameGraphNode);
368 return dumpFG(n: q).join(sep: QLatin1Char('\n'));
369}
370
371QStringList QFrameGraphNodePrivate::dumpFrameGraphPaths() const
372{
373 Q_Q(const QFrameGraphNode);
374 QStringList result;
375 dumpFGPaths(n: q, result);
376 return result;
377}
378
379QStringList QFrameGraphNodePrivate::dumpFrameGraphFilterState() const
380{
381 Q_Q(const QFrameGraphNode);
382 QStringList result;
383 dumpFGFilterState(n: q, result);
384 return result;
385}
386
387/*! \internal */
388QFrameGraphNode::QFrameGraphNode(QFrameGraphNodePrivate &dd, QNode *parent)
389 : QNode(dd, parent)
390{
391}
392
393void QFrameGraphNode::onParentChanged(QObject *)
394{
395 // Direct sync update request
396 Q_D(QFrameGraphNode);
397 d->update();
398}
399
400} // namespace Qt3DRender
401
402QT_END_NAMESPACE
403
404#include "moc_qframegraphnode.cpp"
405

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qt3d/src/render/framegraph/qframegraphnode.cpp