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

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