Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qsgnode.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include "qsgnode.h"
6#include "qsgnode_p.h"
9#include "qsgmaterial.h"
10
11#include <algorithm>
12
13#include "limits.h"
14
16
17#ifndef QT_NO_DEBUG
18static int qt_node_count = 0;
19
21{
22 qCDebug(lcQsgLeak, "Number of leaked nodes: %i", qt_node_count);
23 qt_node_count = -1;
24}
25#endif
26
27/*!
28 \group qtquick-scenegraph-nodes
29 \title Qt Quick Scene Graph Node classes
30 \brief Nodes that can be used as part of the scene graph.
31
32 This page lists the nodes in \l {Qt Quick}'s \l {Qt Quick Scene Graph}{scene graph}.
33 */
34
35/*!
36 \class QSGNode
37 \brief The QSGNode class is the base class for all nodes in the scene graph.
38
39 \inmodule QtQuick
40 \ingroup qtquick-scenegraph-nodes
41
42 The QSGNode class can be used as a child container. Children are added with
43 the appendChildNode(), prependChildNode(), insertChildNodeBefore() and
44 insertChildNodeAfter(). The order of nodes is important as geometry nodes
45 are rendered according to their ordering in the scene graph.
46
47 The scene graph nodes contain a mechanism that describes which
48 parts of the scene have changed. This includes the combined matrices,
49 accumulated opacity, changes to the node hierarchy, and so on. This
50 information can be used for optimizations inside the scene graph renderer.
51 For the renderer to properly render the nodes, it is important that users
52 call QSGNode::markDirty() with the correct flags when nodes are changed.
53 Most of the functions on the node classes will implicitly call markDirty().
54 For example, QSGNode::appendChildNode() will call markDirty() passing in
55 QSGNode::DirtyNodeAdded.
56
57 If nodes change every frame, the preprocess() function can be used to
58 apply changes to a node for every frame it is rendered. The use of
59 preprocess() must be explicitly enabled by setting the
60 QSGNode::UsePreprocess flag on the node.
61
62 The virtual isSubtreeBlocked() function can be used to disable a subtree all
63 together. Nodes in a blocked subtree will not be preprocessed() and not
64 rendered.
65
66 \note All classes with QSG prefix should be used solely on the scene graph's
67 rendering thread. See \l {Scene Graph and Rendering} for more information.
68 */
69
70/*!
71 \enum QSGNode::DirtyStateBit
72
73 Used in QSGNode::markDirty() to indicate how the scene graph has changed.
74
75 \value DirtyMatrix The matrix in a QSGTransformNode has changed.
76 \value DirtyNodeAdded A node was added.
77 \value DirtyNodeRemoved A node was removed.
78 \value DirtyGeometry The geometry of a QSGGeometryNode has changed.
79 \value DirtyMaterial The material of a QSGGeometryNode has changed.
80 \value DirtyOpacity The opacity of a QSGOpacityNode has changed.
81 \value DirtySubtreeBlocked The subtree has been blocked.
82
83 \omitvalue DirtyForceUpdate
84 \omitvalue DirtyUsePreprocess
85 \omitvalue DirtyPropagationMask
86
87 \sa QSGNode::markDirty()
88 */
89
90/*!
91 \enum QSGNode::Flag
92
93 The QSGNode::Flag enum describes flags on the QSGNode
94
95 \value OwnedByParent The node is owned by its parent and will be deleted
96 when the parent is deleted.
97 \value UsePreprocess The node's virtual preprocess() function will be called
98 before rendering starts.
99 \value OwnsGeometry Only valid for QSGGeometryNode and QSGClipNode.
100 The node has ownership over the QSGGeometry instance and will
101 delete it when the node is destroyed or a geometry is assigned.
102 \value OwnsMaterial Only valid for QSGGeometryNode. The node has ownership
103 over the material and will delete it when the node is destroyed or a material is assigned.
104 \value OwnsOpaqueMaterial Only valid for QSGGeometryNode. The node has
105 ownership over the opaque material and will delete it when the node is
106 destroyed or a material is assigned.
107 \value InternalReserved Reserved for internal use.
108
109 \omitvalue IsVisitableNode
110 \omitvalue IsNodeBlocked
111 */
112
113/*!
114 \enum QSGNode::NodeType
115
116 Can be used to figure out the type of node.
117
118 \value BasicNodeType The type of QSGNode
119 \value GeometryNodeType The type of QSGGeometryNode
120 \value TransformNodeType The type of QSGTransformNode
121 \value ClipNodeType The type of QSGClipNode
122 \value OpacityNodeType The type of QSGOpacityNode
123 \value RenderNodeType The type of QSGRenderNode
124
125 \omitvalue RootNodeType
126
127 \sa type()
128 */
129
130/*!
131 \fn QSGNode *QSGNode::childAtIndex(int i) const
132
133 Returns the child at index \a i.
134
135 Children are stored internally as a linked list, so iterating
136 over the children via the index is suboptimal.
137 */
138
139/*!
140 \fn int QSGNode::childCount() const
141
142 Returns the number of child nodes.
143 */
144
145/*!
146 \fn void QSGNode::clearDirty()
147
148 \internal
149 */
150
151/*!
152 \fn QSGNode *QSGNode::firstChild() const
153
154 Returns the first child of this node.
155
156 The children are stored in a linked list.
157 */
158
159/*!
160 \fn QSGNode *QSGNode::lastChild() const
161
162 Returns the last child of this node.
163
164 The children are stored as a linked list.
165 */
166
167/*!
168 \fn QSGNode::Flags QSGNode::flags() const
169
170 Returns the set of flags for this node.
171 */
172
173/*!
174 \fn QSGNode *QSGNode::nextSibling() const
175
176 Returns the node after this in the parent's list of children.
177
178 The children are stored as a linked list.
179 */
180
181/*!
182 \fn QSGNode *QSGNode::previousSibling() const
183
184 Returns the node before this in the parent's list of children.
185
186 The children are stored as a linked list.
187 */
188
189/*!
190 \fn QSGNode::Type QSGNode::type() const
191
192 Returns the type of this node. The node type must be one of the
193 predefined types defined in QSGNode::NodeType and can safely be
194 used to cast to the corresponding class.
195 */
196
197/*!
198 \fn QSGNode::DirtyState QSGNode::dirtyState() const
199
200 \internal
201 */
202
203/*!
204 \fn QSGNode *QSGNode::parent() const
205
206 Returns the parent node of this node.
207 */
208
209
210/*!
211 * Constructs a new node
212 */
213QSGNode::QSGNode()
214 : m_nodeFlags(OwnedByParent)
215{
216 init();
217}
218
219/*!
220 * Constructs a new node with the given node type.
221 *
222 * \internal
223 */
224QSGNode::QSGNode(NodeType type)
225 : m_parent(nullptr)
226 , m_type(type)
227 , m_firstChild(nullptr)
228 , m_lastChild(nullptr)
229 , m_nextSibling(nullptr)
230 , m_previousSibling(nullptr)
231 , m_subtreeRenderableCount(type == GeometryNodeType || type == RenderNodeType ? 1 : 0)
232 , m_nodeFlags(OwnedByParent)
233{
234 init();
235}
236
237/*!
238 * Constructs a new node with the given node type.
239 *
240 * \internal
241 */
242QSGNode::QSGNode(QSGNodePrivate &dd, NodeType type)
243 : m_parent(nullptr)
244 , m_type(type)
245 , m_firstChild(nullptr)
246 , m_lastChild(nullptr)
247 , m_nextSibling(nullptr)
248 , m_previousSibling(nullptr)
249 , m_subtreeRenderableCount(type == GeometryNodeType || type == RenderNodeType ? 1 : 0)
250 , m_nodeFlags(OwnedByParent)
251 , d_ptr(&dd)
252{
253 init();
254}
255
256/*!
257 * \internal
258 */
259void QSGNode::init()
260{
261#ifndef QT_NO_DEBUG
262 if (lcQsgLeak().isDebugEnabled()) {
263 ++qt_node_count;
264 static bool atexit_registered = false;
265 if (!atexit_registered) {
266 atexit(qt_print_node_count);
267 atexit_registered = true;
268 }
269 }
270#endif
271
273 if (d_ptr.isNull())
274 d_ptr.reset(new QSGNodePrivate());
275#endif
276}
277
278/*!
279 * Destroys the node.
280 *
281 * Every child of this node that has the flag QSGNode::OwnedByParent set,
282 * will also be deleted.
283 */
284QSGNode::~QSGNode()
285{
286#ifndef QT_NO_DEBUG
287 if (lcQsgLeak().isDebugEnabled()) {
288 --qt_node_count;
289 if (qt_node_count < 0)
290 qCDebug(lcQsgLeak, "Node destroyed after qt_print_node_count() was called.");
291 }
292#endif
293 destroy();
294}
295
296
297/*!
298 \fn void QSGNode::preprocess()
299
300 Override this function to do processing on the node before it is rendered.
301
302 Preprocessing needs to be explicitly enabled by setting the flag
303 QSGNode::UsePreprocess. The flag needs to be set before the node is added
304 to the scene graph and will cause the preprocess() function to be called
305 for every frame the node is rendered.
306
307 \warning Beware of deleting nodes while they are being preprocessed. It is
308 possible, with a small performance hit, to delete a single node during its
309 own preprocess call. Deleting a subtree which has nodes that also use
310 preprocessing may result in a segmentation fault. This is done for
311 performance reasons.
312 */
313
314
315
316
317/*!
318 Returns whether this node and its subtree is available for use.
319
320 Blocked subtrees will not get their dirty states updated and they
321 will not be rendered.
322
323 The QSGOpacityNode will return a blocked subtree when accumulated opacity
324 is 0, for instance.
325 */
326
327bool QSGNode::isSubtreeBlocked() const
328{
329 return flags().testFlag(IsNodeBlocked);
330}
331
332/*!
333 \internal
334 Detaches the node from the scene graph and deletes any children it owns.
335
336 This function is called from QSGNode's and QSGRootNode's destructor. It
337 should not be called explicitly in user code. QSGRootNode needs to call
338 destroy() because destroy() calls removeChildNode() which in turn calls
339 markDirty() which type-casts the node to QSGRootNode. This type-cast is not
340 valid at the time QSGNode's destructor is called because the node will
341 already be partially destroyed at that point.
342*/
343
344void QSGNode::destroy()
345{
346 if (m_parent) {
347 m_parent->removeChildNode(this);
348 Q_ASSERT(m_parent == nullptr);
349 }
350 while (m_firstChild) {
351 QSGNode *child = m_firstChild;
352 removeChildNode(child);
353 Q_ASSERT(child->m_parent == nullptr);
354 if (child->flags() & OwnedByParent)
355 delete child;
356 }
357
358 Q_ASSERT(m_firstChild == nullptr && m_lastChild == nullptr);
359}
360
361quint8 QSGNodePrivate::mutabilityGroup(const QSGNode *node)
362{
363 return !node->d_ptr.isNull()
364 ? node->d_ptr->m_mutabilityGroup
365 : 0;
366}
367
368/*!
369 \internal
370
371 Sets the mutability group of this node. Recurses to children.
372 */
373void QSGNodePrivate::setMutabilityGroupOfSubtree(QSGNode *node, quint8 group)
374{
375 Q_ASSERT((group & 0xf) == group);
376
377 const quint8 currentMutabilityGroup = mutabilityGroup(node);
378 if (currentMutabilityGroup != group) {
379 if (node->d_ptr.isNull())
380 node->d_ptr.reset(new QSGNodePrivate());
381 node->d_ptr->m_mutabilityGroup = group;
382 node->markDirty(QSGNode::DirtyGeometry);
383 }
384
385 for (int i = 0; i < node->childCount(); ++i)
386 QSGNodePrivate::setMutabilityGroupOfSubtree(node->childAtIndex(i), group);
387}
388
389/*!
390 Prepends \a node to this node's the list of children.
391
392 Ordering of nodes is important as geometry nodes will be rendered in the
393 order they are added to the scene graph.
394 */
395
396void QSGNode::prependChildNode(QSGNode *node)
397{
398 //Q_ASSERT_X(!m_children.contains(node), "QSGNode::prependChildNode", "QSGNode is already a child!");
399 Q_ASSERT_X(!node->m_parent, "QSGNode::prependChildNode", "QSGNode already has a parent");
400
401#ifndef QT_NO_DEBUG
402 if (node->type() == QSGNode::GeometryNodeType) {
403 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
404 Q_ASSERT_X(g->material(), "QSGNode::prependChildNode", "QSGGeometryNode is missing material");
405 Q_ASSERT_X(g->geometry(), "QSGNode::prependChildNode", "QSGGeometryNode is missing geometry");
406 }
407#endif
408
409 if (m_firstChild)
410 m_firstChild->m_previousSibling = node;
411 else
412 m_lastChild = node;
413 node->m_nextSibling = m_firstChild;
414 m_firstChild = node;
415 node->m_parent = this;
416
417 node->markDirty(DirtyNodeAdded);
418}
419
420/*!
421 Appends \a node to this node's list of children.
422
423 Ordering of nodes is important as geometry nodes will be rendered in the
424 order they are added to the scene graph.
425 */
426
427void QSGNode::appendChildNode(QSGNode *node)
428{
429 //Q_ASSERT_X(!m_children.contains(node), "QSGNode::appendChildNode", "QSGNode is already a child!");
430 Q_ASSERT_X(!node->m_parent, "QSGNode::appendChildNode", "QSGNode already has a parent");
431
432#ifndef QT_NO_DEBUG
433 if (node->type() == QSGNode::GeometryNodeType) {
434 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
435 Q_ASSERT_X(g->material(), "QSGNode::appendChildNode", "QSGGeometryNode is missing material");
436 Q_ASSERT_X(g->geometry(), "QSGNode::appendChildNode", "QSGGeometryNode is missing geometry");
437 }
438#endif
439
440 if (m_lastChild)
441 m_lastChild->m_nextSibling = node;
442 else
443 m_firstChild = node;
444 node->m_previousSibling = m_lastChild;
445 m_lastChild = node;
446 node->m_parent = this;
447
448 node->markDirty(DirtyNodeAdded);
449}
450
451
452
453/*!
454 Inserts \a node to this node's list of children before the node specified with \a before.
455
456 Ordering of nodes is important as geometry nodes will be rendered in the
457 order they are added to the scene graph.
458 */
459
460void QSGNode::insertChildNodeBefore(QSGNode *node, QSGNode *before)
461{
462 //Q_ASSERT_X(!m_children.contains(node), "QSGNode::insertChildNodeBefore", "QSGNode is already a child!");
463 Q_ASSERT_X(!node->m_parent, "QSGNode::insertChildNodeBefore", "QSGNode already has a parent");
464 Q_ASSERT_X(before && before->m_parent == this, "QSGNode::insertChildNodeBefore", "The parent of \'before\' is wrong");
465
466#ifndef QT_NO_DEBUG
467 if (node->type() == QSGNode::GeometryNodeType) {
468 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
469 Q_ASSERT_X(g->material(), "QSGNode::insertChildNodeBefore", "QSGGeometryNode is missing material");
470 Q_ASSERT_X(g->geometry(), "QSGNode::insertChildNodeBefore", "QSGGeometryNode is missing geometry");
471 }
472#endif
473
474 QSGNode *previous = before->m_previousSibling;
475 if (previous)
476 previous->m_nextSibling = node;
477 else
478 m_firstChild = node;
479 node->m_previousSibling = previous;
480 node->m_nextSibling = before;
481 before->m_previousSibling = node;
482 node->m_parent = this;
483
484 node->markDirty(DirtyNodeAdded);
485}
486
487
488
489/*!
490 Inserts \a node to this node's list of children after the node specified with \a after.
491
492 Ordering of nodes is important as geometry nodes will be rendered in the
493 order they are added to the scene graph.
494 */
495
496void QSGNode::insertChildNodeAfter(QSGNode *node, QSGNode *after)
497{
498 //Q_ASSERT_X(!m_children.contains(node), "QSGNode::insertChildNodeAfter", "QSGNode is already a child!");
499 Q_ASSERT_X(!node->m_parent, "QSGNode::insertChildNodeAfter", "QSGNode already has a parent");
500 Q_ASSERT_X(after && after->m_parent == this, "QSGNode::insertChildNodeAfter", "The parent of \'after\' is wrong");
501
502#ifndef QT_NO_DEBUG
503 if (node->type() == QSGNode::GeometryNodeType) {
504 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
505 Q_ASSERT_X(g->material(), "QSGNode::insertChildNodeAfter", "QSGGeometryNode is missing material");
506 Q_ASSERT_X(g->geometry(), "QSGNode::insertChildNodeAfter", "QSGGeometryNode is missing geometry");
507 }
508#endif
509
510 QSGNode *next = after->m_nextSibling;
511 if (next)
512 next->m_previousSibling = node;
513 else
514 m_lastChild = node;
515 node->m_nextSibling = next;
516 node->m_previousSibling = after;
517 after->m_nextSibling = node;
518 node->m_parent = this;
519
520 node->markDirty(DirtyNodeAdded);
521}
522
523
524
525/*!
526 Removes \a node from this node's list of children.
527 */
528
529void QSGNode::removeChildNode(QSGNode *node)
530{
531 //Q_ASSERT(m_children.contains(node));
532 Q_ASSERT(node->parent() == this);
533
534 QSGNode *previous = node->m_previousSibling;
535 QSGNode *next = node->m_nextSibling;
536 if (previous)
537 previous->m_nextSibling = next;
538 else
539 m_firstChild = next;
540 if (next)
541 next->m_previousSibling = previous;
542 else
543 m_lastChild = previous;
544 node->m_previousSibling = nullptr;
545 node->m_nextSibling = nullptr;
546
547 node->markDirty(DirtyNodeRemoved);
548 node->m_parent = nullptr;
549}
550
551
552/*!
553 Removes all child nodes from this node's list of children.
554 */
555
556void QSGNode::removeAllChildNodes()
557{
558 while (m_firstChild) {
559 QSGNode *node = m_firstChild;
560 m_firstChild = node->m_nextSibling;
561 node->m_nextSibling = nullptr;
562 if (m_firstChild)
563 m_firstChild->m_previousSibling = nullptr;
564 else
565 m_lastChild = nullptr;
566 node->markDirty(DirtyNodeRemoved);
567 node->m_parent = nullptr;
568 }
569}
570
571/*!
572 * \internal
573 *
574 * Reparents all nodes of this node to \a newParent.
575 */
576void QSGNode::reparentChildNodesTo(QSGNode *newParent)
577{
578 for (QSGNode *c = firstChild(); c; c = firstChild()) {
579 removeChildNode(c);
580 newParent->appendChildNode(c);
581 }
582}
583
584
585int QSGNode::childCount() const
586{
587 int count = 0;
588 QSGNode *n = m_firstChild;
589 while (n) {
590 ++count;
591 n = n->m_nextSibling;
592 }
593 return count;
594}
595
596
597QSGNode *QSGNode::childAtIndex(int i) const
598{
599 QSGNode *n = m_firstChild;
600 while (i && n) {
601 --i;
602 n = n->m_nextSibling;
603 }
604 return n;
605}
606
607
608/*!
609 Sets the flag \a f on this node if \a enabled is true;
610 otherwise clears the flag.
611
612 \sa flags()
613*/
614
615void QSGNode::setFlag(Flag f, bool enabled)
616{
617 if (bool(m_nodeFlags & f) == enabled)
618 return;
619 m_nodeFlags ^= f;
620 Q_ASSERT(int(UsePreprocess) == int(DirtyUsePreprocess));
621 int changedFlag = f & UsePreprocess;
622 if (changedFlag)
623 markDirty(DirtyState(changedFlag));
624}
625
626
627/*!
628 Sets the flags \a f on this node if \a enabled is true;
629 otherwise clears the flags.
630
631 \sa flags()
632*/
633
634void QSGNode::setFlags(Flags f, bool enabled)
635{
636 Flags oldFlags = m_nodeFlags;
637 if (enabled)
638 m_nodeFlags |= f;
639 else
640 m_nodeFlags &= ~f;
641 Q_ASSERT(int(UsePreprocess) == int(DirtyUsePreprocess));
642 int changedFlags = (oldFlags ^ m_nodeFlags) & UsePreprocess;
643 if (changedFlags)
644 markDirty(DirtyState(changedFlags));
645}
646
647
648
649/*!
650 Notifies all connected renderers that the node has dirty \a bits.
651 */
652
653void QSGNode::markDirty(DirtyState bits)
654{
655 int renderableCountDiff = 0;
656 if (bits & DirtyNodeAdded)
657 renderableCountDiff += m_subtreeRenderableCount;
658 if (bits & DirtyNodeRemoved)
659 renderableCountDiff -= m_subtreeRenderableCount;
660
661 QSGNode *p = m_parent;
662 while (p) {
663 p->m_subtreeRenderableCount += renderableCountDiff;
664 if (p->type() == RootNodeType)
665 static_cast<QSGRootNode *>(p)->notifyNodeChange(this, bits);
666 p = p->m_parent;
667 }
668}
669
670void qsgnode_set_description(QSGNode *node, const QString &description)
671{
673 QSGNodePrivate::setDescription(node, description);
674#else
675 Q_UNUSED(node);
676 Q_UNUSED(description);
677#endif
678}
679
680/*!
681 \class QSGBasicGeometryNode
682 \brief The QSGBasicGeometryNode class serves as a baseclass for geometry based nodes.
683
684 \inmodule QtQuick
685
686 The QSGBasicGeometryNode class should not be used by itself. It is only encapsulates
687 shared functionality between the QSGGeometryNode and QSGClipNode classes.
688
689 \note All classes with QSG prefix should be used solely on the scene graph's
690 rendering thread. See \l {Scene Graph and Rendering} for more information.
691 */
692
693
694/*!
695 Creates a new basic geometry node of type \a type
696
697 \internal
698 */
699QSGBasicGeometryNode::QSGBasicGeometryNode(NodeType type)
700 : QSGNode(type)
701 , m_geometry(nullptr)
702 , m_matrix(nullptr)
703 , m_clip_list(nullptr)
704{
705}
706
707
708/*!
709 \internal
710 */
711QSGBasicGeometryNode::QSGBasicGeometryNode(QSGBasicGeometryNodePrivate &dd, NodeType type)
712 : QSGNode(dd, type)
713 , m_geometry(nullptr)
714 , m_matrix(nullptr)
715 , m_clip_list(nullptr)
716{
717}
718
719
720/*!
721 Deletes this QSGBasicGeometryNode.
722
723 If the node has the flag QSGNode::OwnsGeometry set, it will also delete the
724 geometry object it is pointing to. This flag is not set by default.
725 */
726
727QSGBasicGeometryNode::~QSGBasicGeometryNode()
728{
729 if (flags() & OwnsGeometry)
730 delete m_geometry;
731}
732
733
734/*!
735 \fn QSGGeometry *QSGBasicGeometryNode::geometry()
736
737 Returns this node's geometry.
738
739 The geometry is null by default.
740 */
741
742/*!
743 \fn const QSGGeometry *QSGBasicGeometryNode::geometry() const
744
745 Returns this node's geometry.
746
747 The geometry is null by default.
748 */
749
750/*!
751 \fn QMatrix4x4 *QSGBasicGeometryNode::matrix() const
752
753 Will be set during rendering to contain transformation of the geometry
754 for that rendering pass.
755
756 \internal
757 */
758
759/*!
760 \fn QSGClipNode *QSGBasicGeometryNode::clipList() const
761
762 Will be set during rendering to contain the clip of the geometry
763 for that rendering pass.
764
765 \internal
766 */
767
768/*!
769 \fn void QSGBasicGeometryNode::setRendererMatrix(const QMatrix4x4 *m)
770
771 \internal
772 */
773
774/*!
775 \fn void QSGBasicGeometryNode::setRendererClipList(const QSGClipNode *c)
776
777 \internal
778 */
779
780
781/*!
782 Sets the geometry of this node to \a geometry.
783
784 If the node has the flag QSGNode::OwnsGeometry set, it will also delete the
785 geometry object it is pointing to. This flag is not set by default.
786
787 If the geometry is changed without calling setGeometry() again, the user
788 must also mark the geometry as dirty using QSGNode::markDirty().
789
790 \sa markDirty()
791 */
792
793void QSGBasicGeometryNode::setGeometry(QSGGeometry *geometry)
794{
795 if ((flags() & OwnsGeometry) != 0 && m_geometry != geometry)
796 delete m_geometry;
797 m_geometry = geometry;
798 markDirty(DirtyGeometry);
799}
800
801
802
803/*!
804 \class QSGGeometryNode
805 \brief The QSGGeometryNode class is used for all rendered content in the scene graph.
806
807 \inmodule QtQuick
808 \ingroup qtquick-scenegraph-nodes
809
810 The QSGGeometryNode consists of geometry and material. The geometry defines the mesh,
811 the vertices and their structure, to be drawn. The Material defines how the shape is
812 filled.
813
814 The following is a code snippet illustrating how to create a red
815 line using a QSGGeometryNode:
816 \code
817 QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 2);
818 geometry->setDrawingMode(QSGGeometry::DrawLines);
819 geometry->setLineWidth(3);
820 geometry->vertexDataAsPoint2D()[0].set(0, 0);
821 geometry->vertexDataAsPoint2D()[1].set(width(), height());
822
823 QSGFlatColorMaterial *material = new QSGFlatColorMaterial;
824 material->setColor(QColor(255, 0, 0));
825
826 QSGGeometryNode *node = new QSGGeometryNode;
827 node->setGeometry(geometry);
828 node->setFlag(QSGNode::OwnsGeometry);
829 node->setMaterial(material);
830 node->setFlag(QSGNode::OwnsMaterial);
831 \endcode
832
833 A geometry node must have both geometry and a normal material before it is added to
834 the scene graph. When the geometry and materials are changed after the node has
835 been added to the scene graph, the user should also mark them as dirty using
836 QSGNode::markDirty().
837
838 The geometry node supports two types of materials, the opaqueMaterial and the normal
839 material. The opaqueMaterial is used when the accumulated scene graph opacity at the
840 time of rendering is 1. The primary use case is to special case opaque rendering
841 to avoid an extra operation in the fragment shader can have significant performance
842 impact on embedded graphics chips. The opaque material is optional.
843
844 \note All classes with QSG prefix should be used solely on the scene graph's
845 rendering thread. See \l {Scene Graph and Rendering} for more information.
846
847 \sa QSGGeometry, QSGMaterial
848 */
849
850
851/*!
852 Creates a new geometry node without geometry and material.
853 */
854
855QSGGeometryNode::QSGGeometryNode()
856 : QSGBasicGeometryNode(GeometryNodeType)
857{
858}
859
860
861/*!
862 \internal
863 */
864QSGGeometryNode::QSGGeometryNode(QSGGeometryNodePrivate &dd)
865 : QSGBasicGeometryNode(dd, GeometryNodeType)
866 , m_render_order(0)
867 , m_material(nullptr)
868 , m_opaque_material(nullptr)
869 , m_opacity(1)
870{
871}
872
873
874/*!
875 Deletes this geometry node.
876
877 The flags QSGNode::OwnsMaterial, QSGNode::OwnsOpaqueMaterial and
878 QSGNode::OwnsGeometry decides whether the geometry node should also
879 delete the materials and geometry. By default, these flags are disabled.
880 */
881
882QSGGeometryNode::~QSGGeometryNode()
883{
884 if (flags() & OwnsMaterial)
885 delete m_material;
886 if (flags() & OwnsOpaqueMaterial)
887 delete m_opaque_material;
888}
889
890
891
892/*!
893 \fn int QSGGeometryNode::renderOrder() const
894
895 Returns the render order of this geometry node.
896
897 \internal
898 */
899
900/*!
901 \fn QSGMaterial *QSGGeometryNode::material() const
902
903 Returns the material of the QSGGeometryNode.
904
905 \sa setMaterial()
906 */
907
908/*!
909 \fn QSGMaterial *QSGGeometryNode::opaqueMaterial() const
910
911 Returns the opaque material of the QSGGeometryNode.
912
913 \sa setOpaqueMaterial()
914 */
915
916/*!
917 \fn qreal QSGGeometryNode::inheritedOpacity() const
918
919 Set during rendering to specify the inherited opacity for that
920 rendering pass.
921
922 \internal
923 */
924
925
926/*!
927 Sets the render order of this node to be \a order.
928
929 Geometry nodes are rendered in an order that visually looks like
930 low order nodes are rendered prior to high order nodes. For opaque
931 geometry there is little difference as z-testing will handle
932 the discard, but for translucent objects, the rendering should
933 normally be specified in the order of back-to-front.
934
935 The default render order is \c 0.
936
937 \internal
938 */
939void QSGGeometryNode::setRenderOrder(int order)
940{
941 m_render_order = order;
942}
943
944
945
946/*!
947 Sets the material of this geometry node to \a material.
948
949 Geometry nodes must have a material before they can be added to the
950 scene graph.
951
952 If the material is changed without calling setMaterial() again, the user
953 must also mark the material as dirty using QSGNode::markDirty().
954
955 */
956void QSGGeometryNode::setMaterial(QSGMaterial *material)
957{
958 if ((flags() & OwnsMaterial) != 0 && m_material != material)
959 delete m_material;
960 m_material = material;
961#ifndef QT_NO_DEBUG
962 if (m_material != nullptr && m_opaque_material == m_material)
963 qWarning("QSGGeometryNode: using same material for both opaque and translucent");
964#endif
965 markDirty(DirtyMaterial);
966}
967
968
969
970/*!
971 Sets the opaque material of this geometry to \a material.
972
973 The opaque material will be preferred by the renderer over the
974 default material, as returned by the material() function, if
975 it is not null and the geometry item has an inherited opacity of
976 1.
977
978 The opaqueness refers to scene graph opacity, the material is still
979 allowed to set QSGMaterial::Blending to true and draw transparent
980 pixels.
981
982 If the material is changed without calling setOpaqueMaterial()
983 again, the user must also mark the opaque material as dirty using
984 QSGNode::markDirty().
985
986 */
987void QSGGeometryNode::setOpaqueMaterial(QSGMaterial *material)
988{
989 if ((flags() & OwnsOpaqueMaterial) != 0 && m_opaque_material != m_material)
990 delete m_opaque_material;
991 m_opaque_material = material;
992#ifndef QT_NO_DEBUG
993 if (m_opaque_material != nullptr && m_opaque_material == m_material)
994 qWarning("QSGGeometryNode: using same material for both opaque and translucent");
995#endif
996
997 markDirty(DirtyMaterial);
998}
999
1000
1001
1002/*!
1003 Returns the material which should currently be used for geometry node.
1004
1005 If the inherited opacity of the node is 1 and there is an opaque material
1006 set on this node, it will be returned; otherwise, the default material
1007 will be returned.
1008
1009 \warning This function requires the scene graph above this item to be
1010 completely free of dirty states, so it can only be called during rendering
1011
1012 \internal
1013
1014 \sa setMaterial, setOpaqueMaterial
1015 */
1016QSGMaterial *QSGGeometryNode::activeMaterial() const
1017{
1018 if (m_opaque_material && m_opacity > 0.999)
1019 return m_opaque_material;
1020 return m_material;
1021}
1022
1023
1024/*!
1025 Sets the inherited opacity of this geometry to \a opacity.
1026
1027 This function is meant to be called by the node preprocessing
1028 prior to rendering the tree, so it will not mark the tree as
1029 dirty.
1030
1031 \internal
1032 */
1033void QSGGeometryNode::setInheritedOpacity(qreal opacity)
1034{
1035 Q_ASSERT(opacity >= 0 && opacity <= 1);
1036 m_opacity = opacity;
1037}
1038
1039
1040/*!
1041 \class QSGClipNode
1042 \brief The QSGClipNode class implements the clipping functionality in the scene graph.
1043
1044 \inmodule QtQuick
1045 \ingroup qtquick-scenegraph-nodes
1046
1047 Clipping applies to the node's subtree and can be nested. Multiple clip nodes will be
1048 accumulated by intersecting all their geometries. The accumulation happens
1049 as part of the rendering.
1050
1051 Clip nodes must have a geometry before they can be added to the scene graph.
1052
1053 Clipping is usually implemented by using the stencil buffer.
1054
1055 \note All classes with QSG prefix should be used solely on the scene graph's
1056 rendering thread. See \l {Scene Graph and Rendering} for more information.
1057 */
1058
1059
1060
1061/*!
1062 Creates a new QSGClipNode without a geometry.
1063
1064 The clip node must have a geometry before it can be added to the
1065 scene graph.
1066 */
1067
1068QSGClipNode::QSGClipNode()
1069 : QSGBasicGeometryNode(ClipNodeType)
1070 , m_is_rectangular(false)
1071{
1072 Q_UNUSED(m_reserved);
1073}
1074
1075
1076
1077/*!
1078 Deletes this QSGClipNode.
1079
1080 If the flag QSGNode::OwnsGeometry is set, the geometry will also be
1081 deleted.
1082 */
1083
1084QSGClipNode::~QSGClipNode()
1085{
1086}
1087
1088
1089
1090/*!
1091 \fn bool QSGClipNode::isRectangular() const
1092
1093 Returns if this clip node has a rectangular clip.
1094 */
1095
1096
1097
1098/*!
1099 Sets whether this clip node has a rectangular clip to \a rectHint.
1100
1101 This is an optimization hint which means that the renderer can
1102 use scissoring instead of stencil, which is significantly faster.
1103
1104 When this hint is set and it is applicable, the clip region will be
1105 generated from clipRect() rather than geometry().
1106
1107 By default this property is \c false.
1108 */
1109
1110void QSGClipNode::setIsRectangular(bool rectHint)
1111{
1112 m_is_rectangular = rectHint;
1113}
1114
1115
1116
1117/*!
1118 \fn QRectF QSGClipNode::clipRect() const
1119
1120 Returns the clip rect of this node.
1121 */
1122
1123
1124/*!
1125 Sets the clip rect of this clip node to \a rect.
1126
1127 When a rectangular clip is set in combination with setIsRectangular
1128 the renderer may in some cases use a more optimal clip method.
1129 */
1130void QSGClipNode::setClipRect(const QRectF &rect)
1131{
1132 m_clip_rect = rect;
1133}
1134
1135
1136/*!
1137 \class QSGTransformNode
1138 \brief The QSGTransformNode class implements transformations in the scene graph.
1139
1140 \inmodule QtQuick
1141 \ingroup qtquick-scenegraph-nodes
1142
1143 Transformations apply the node's subtree and can be nested. Multiple transform nodes
1144 will be accumulated by intersecting all their matrices. The accumulation happens
1145 as part of the rendering.
1146
1147 The transform nodes implement a 4x4 matrix which in theory supports full 3D
1148 transformations. However, because the renderer optimizes for 2D use-cases rather
1149 than 3D use-cases, rendering a scene with full 3D transformations needs to
1150 be done with some care.
1151
1152 \note All classes with QSG prefix should be used solely on the scene graph's
1153 rendering thread. See \l {Scene Graph and Rendering} for more information.
1154
1155 */
1156
1157
1158/*!
1159 Create a new QSGTransformNode with its matrix set to the identity matrix.
1160 */
1161
1162QSGTransformNode::QSGTransformNode()
1163 : QSGNode(TransformNodeType)
1164{
1165}
1166
1167
1168
1169/*!
1170 Deletes this transform node.
1171 */
1172
1173QSGTransformNode::~QSGTransformNode()
1174{
1175}
1176
1177
1178
1179/*!
1180 \fn QMatrix4x4 QSGTransformNode::matrix() const
1181
1182 Returns this transform node's matrix.
1183 */
1184
1185
1186
1187/*!
1188 Sets this transform node's matrix to \a matrix.
1189 */
1190
1191void QSGTransformNode::setMatrix(const QMatrix4x4 &matrix)
1192{
1193 m_matrix = matrix;
1194 markDirty(DirtyMatrix);
1195}
1196
1197/*!
1198 \fn const QMatrix4x4 &QSGTransformNode::combinedMatrix() const
1199
1200 Set during rendering to the combination of all parent matrices for
1201 that rendering pass.
1202
1203 \internal
1204 */
1205
1206
1207
1208/*!
1209 Sets the combined matrix of this matrix to \a transform.
1210
1211 This function is meant to be called by the node preprocessing
1212 prior to rendering the tree, so it will not mark the tree as
1213 dirty.
1214
1215 \internal
1216 */
1217void QSGTransformNode::setCombinedMatrix(const QMatrix4x4 &matrix)
1218{
1219 m_combined_matrix = matrix;
1220}
1221
1222
1223
1224/*!
1225 \class QSGRootNode
1226 \brief The QSGRootNode is the toplevel root of any scene graph.
1227
1228 The root node is used to attach a scene graph to a renderer.
1229
1230 \internal
1231 */
1232
1233
1234
1235/*!
1236 \fn QSGRootNode::QSGRootNode()
1237
1238 Creates a new root node.
1239 */
1240
1241QSGRootNode::QSGRootNode()
1242 : QSGNode(RootNodeType)
1243{
1244}
1245
1246
1247/*!
1248 Deletes the root node.
1249
1250 When a root node is deleted it removes itself from all of renderers
1251 that are referencing it.
1252 */
1253
1254QSGRootNode::~QSGRootNode()
1255{
1256 while (!m_renderers.isEmpty())
1257 m_renderers.constLast()->setRootNode(nullptr);
1258 destroy(); // Must call destroy() here because markDirty() casts this to QSGRootNode.
1259}
1260
1261
1262
1263/*!
1264 Called to notify all renderers that \a node has been marked as dirty
1265 with \a flags.
1266 */
1267
1268void QSGRootNode::notifyNodeChange(QSGNode *node, DirtyState state)
1269{
1270 for (int i=0; i<m_renderers.size(); ++i) {
1271 m_renderers.at(i)->nodeChanged(node, state);
1272 }
1273}
1274
1275
1276
1277/*!
1278 \class QSGOpacityNode
1279 \brief The QSGOpacityNode class is used to change opacity of nodes.
1280
1281 \inmodule QtQuick
1282 \ingroup qtquick-scenegraph-nodes
1283
1284 Opacity applies to its subtree and can be nested. Multiple opacity nodes
1285 will be accumulated by multiplying their opacity. The accumulation happens
1286 as part of the rendering.
1287
1288 When nested opacity gets below a certain threshold, the subtree might
1289 be marked as blocked, causing isSubtreeBlocked() to return true. This
1290 is done for performance reasons.
1291
1292 \note All classes with QSG prefix should be used solely on the scene graph's
1293 rendering thread. See \l {Scene Graph and Rendering} for more information.
1294 */
1295
1296
1297
1298/*!
1299 Constructs an opacity node with a default opacity of 1.
1300
1301 Opacity accumulates downwards in the scene graph so a node with two
1302 QSGOpacityNode instances above it, both with opacity of 0.5, will have
1303 effective opacity of 0.25.
1304
1305 The default opacity of nodes is 1.
1306 */
1307QSGOpacityNode::QSGOpacityNode()
1308 : QSGNode(OpacityNodeType)
1309{
1310}
1311
1312
1313
1314/*!
1315 Deletes the opacity node.
1316 */
1317
1318QSGOpacityNode::~QSGOpacityNode()
1319{
1320}
1321
1322
1323
1324/*!
1325 \fn qreal QSGOpacityNode::opacity() const
1326
1327 Returns this opacity node's opacity.
1328 */
1329
1331
1332/*!
1333 Sets the opacity of this node to \a opacity.
1334
1335 Before rendering the graph, the renderer will do an update pass
1336 over the subtree to propagate the opacity to its children.
1337
1338 The value will be bounded to the range 0 to 1.
1339 */
1340
1341void QSGOpacityNode::setOpacity(qreal opacity)
1342{
1343 opacity = std::clamp(opacity, qreal(0.0), qreal(1.0));
1344 if (m_opacity == opacity)
1345 return;
1346 DirtyState dirtyState = DirtyOpacity;
1347
1348 if ((m_opacity < OPACITY_THRESHOLD && opacity >= OPACITY_THRESHOLD) // blocked to unblocked
1349 || (m_opacity >= OPACITY_THRESHOLD && opacity < OPACITY_THRESHOLD)) // unblocked to blocked
1350 dirtyState |= DirtySubtreeBlocked;
1351
1352 m_opacity = opacity;
1353 markDirty(dirtyState);
1354}
1355
1356
1357
1358/*!
1359 \fn qreal QSGOpacityNode::combinedOpacity() const
1360
1361 Returns this node's accumulated opacity.
1362
1363 This value is calculated during rendering and only stored
1364 in the opacity node temporarily.
1365
1366 \internal
1367 */
1368
1369
1370
1371/*!
1372 Sets the combined opacity of this node to \a opacity.
1373
1374 This function is meant to be called by the node preprocessing
1375 prior to rendering the tree, so it will not mark the tree as
1376 dirty.
1377
1378 \internal
1379 */
1380
1381void QSGOpacityNode::setCombinedOpacity(qreal opacity)
1382{
1383 m_combined_opacity = opacity;
1384}
1385
1386
1387
1388/*!
1389 For performance reasons, we block the subtree when the opacity
1390 is below a certain threshold.
1391
1392 \internal
1393 */
1394
1395bool QSGOpacityNode::isSubtreeBlocked() const
1396{
1397 // IsNodeBlocked is deliberately not checked: it is only ever set on the
1398 // transform nodes of items.
1399 return m_opacity < OPACITY_THRESHOLD;
1400}
1401
1402
1403/*!
1404 \class QSGNodeVisitor
1405 \brief The QSGNodeVisitor class is a helper class for traversing the scene graph.
1406
1407 \internal
1408 */
1409
1410QSGNodeVisitor::~QSGNodeVisitor()
1411{
1412
1413}
1414
1415
1416void QSGNodeVisitor::visitNode(QSGNode *n)
1417{
1418 switch (n->type()) {
1419 case QSGNode::TransformNodeType: {
1420 QSGTransformNode *t = static_cast<QSGTransformNode *>(n);
1421 enterTransformNode(t);
1422 visitChildren(t);
1423 leaveTransformNode(t);
1424 break; }
1425 case QSGNode::GeometryNodeType: {
1426 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(n);
1427 enterGeometryNode(g);
1428 visitChildren(g);
1429 leaveGeometryNode(g);
1430 break; }
1431 case QSGNode::ClipNodeType: {
1432 QSGClipNode *c = static_cast<QSGClipNode *>(n);
1433 enterClipNode(c);
1434 visitChildren(c);
1435 leaveClipNode(c);
1436 break; }
1437 case QSGNode::OpacityNodeType: {
1438 QSGOpacityNode *o = static_cast<QSGOpacityNode *>(n);
1439 enterOpacityNode(o);
1440 visitChildren(o);
1441 leaveOpacityNode(o);
1442 break; }
1443 default:
1444 visitChildren(n);
1445 break;
1446 }
1447}
1448
1449void QSGNodeVisitor::visitChildren(QSGNode *n)
1450{
1451 for (QSGNode *c = n->firstChild(); c; c = c->nextSibling())
1452 visitNode(c);
1453}
1454
1455#ifndef QT_NO_DEBUG_STREAM
1456QDebug operator<<(QDebug d, const QSGGeometryNode *n)
1457{
1458 if (!n) {
1459 d << "Geometry(null)";
1460 return d;
1461 }
1462 d << "GeometryNode(" << Qt::hex << (const void *) n << Qt::dec;
1463
1464 const QSGGeometry *g = n->geometry();
1465
1466 if (!g) {
1467 d << "no geometry";
1468 } else {
1469
1470 switch (g->drawingMode()) {
1471 case QSGGeometry::DrawTriangleStrip: d << "strip"; break;
1472 case QSGGeometry::DrawTriangleFan: d << "fan"; break;
1473 case QSGGeometry::DrawTriangles: d << "triangles"; break;
1474 default: break;
1475 }
1476
1477 d << "#V:" << g->vertexCount() << "#I:" << g->indexCount();
1478
1479 if (g->attributeCount() > 0 && g->attributes()->type == QSGGeometry::FloatType) {
1480 float x1 = 1e10, x2 = -1e10, y1=1e10, y2=-1e10;
1481 int stride = g->sizeOfVertex();
1482 for (int i = 0; i < g->vertexCount(); ++i) {
1483 float x = ((float *)((char *)const_cast<QSGGeometry *>(g)->vertexData() + i * stride))[0];
1484 float y = ((float *)((char *)const_cast<QSGGeometry *>(g)->vertexData() + i * stride))[1];
1485
1486 x1 = qMin(x1, x);
1487 x2 = qMax(x2, x);
1488 y1 = qMin(y1, y);
1489 y2 = qMax(y2, y);
1490 }
1491
1492 d << "x1=" << x1 << "y1=" << y1 << "x2=" << x2 << "y2=" << y2;
1493 }
1494 }
1495
1496 if (n->material())
1497 d << "materialtype=" << n->material()->type();
1498
1499
1500 d << ')';
1502 d << QSGNodePrivate::description(n);
1503#endif
1504 return d;
1505}
1506
1507QDebug operator<<(QDebug d, const QSGClipNode *n)
1508{
1509 if (!n) {
1510 d << "ClipNode(null)";
1511 return d;
1512 }
1513 d << "ClipNode(" << Qt::hex << (const void *) n << Qt::dec;
1514
1515 if (n->childCount())
1516 d << "children=" << n->childCount();
1517
1518 d << "is rect?" << (n->isRectangular() ? "yes" : "no");
1519
1520 d << ')';
1522 d << QSGNodePrivate::description(n);
1523#endif
1524 d << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1525 return d;
1526}
1527
1528QDebug operator<<(QDebug d, const QSGTransformNode *n)
1529{
1530 if (!n) {
1531 d << "TransformNode(null)";
1532 return d;
1533 }
1534 const QMatrix4x4 m = n->matrix();
1535 d << "TransformNode(";
1536 d << Qt::hex << (const void *) n << Qt::dec;
1537 if (m.isIdentity())
1538 d << "identity";
1539 else if (m.determinant() == 1 && m(0, 0) == 1 && m(1, 1) == 1 && m(2, 2) == 1)
1540 d << "translate" << m(0, 3) << m(1, 3) << m(2, 3);
1541 else
1542 d << "det=" << n->matrix().determinant();
1544 d << QSGNodePrivate::description(n);
1545#endif
1546 d << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1547 d << ')';
1548 return d;
1549}
1550
1551QDebug operator<<(QDebug d, const QSGOpacityNode *n)
1552{
1553 if (!n) {
1554 d << "OpacityNode(null)";
1555 return d;
1556 }
1557 d << "OpacityNode(";
1558 d << Qt::hex << (const void *) n << Qt::dec;
1559 d << "opacity=" << n->opacity()
1560 << "combined=" << n->combinedOpacity()
1561 << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1563 d << QSGNodePrivate::description(n);
1564#endif
1565 d << ')';
1566 return d;
1567}
1568
1569
1570QDebug operator<<(QDebug d, const QSGRootNode *n)
1571{
1572 if (!n) {
1573 d << "RootNode(null)";
1574 return d;
1575 }
1576 QDebugStateSaver saver(d);
1577 d << "RootNode" << Qt::hex << (const void *) n << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1579 d << QSGNodePrivate::description(n);
1580#endif
1581 d << ')';
1582 return d;
1583}
1584
1585
1586
1587QDebug operator<<(QDebug d, const QSGNode *n)
1588{
1589 if (!n) {
1590 d << "Node(null)";
1591 return d;
1592 }
1593 switch (n->type()) {
1594 case QSGNode::GeometryNodeType:
1595 d << static_cast<const QSGGeometryNode *>(n);
1596 break;
1597 case QSGNode::TransformNodeType:
1598 d << static_cast<const QSGTransformNode *>(n);
1599 break;
1600 case QSGNode::ClipNodeType:
1601 d << static_cast<const QSGClipNode *>(n);
1602 break;
1603 case QSGNode::RootNodeType:
1604 d << static_cast<const QSGRootNode *>(n);
1605 break;
1606 case QSGNode::OpacityNodeType:
1607 d << static_cast<const QSGOpacityNode *>(n);
1608 break;
1609 case QSGNode::RenderNodeType:
1610 d << "RenderNode(" << Qt::hex << (const void *) n << Qt::dec
1611 << "flags=" << (int) n->flags() << Qt::dec
1612 << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1614 d << QSGNodePrivate::description(n);
1615#endif
1616 d << ')';
1617 break;
1618 default:
1619 d << "Node(" << Qt::hex << (const void *) n << Qt::dec
1620 << "flags=" << (int) n->flags() << Qt::dec
1621 << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1623 d << QSGNodePrivate::description(n);
1624#endif
1625 d << ')';
1626 break;
1627 }
1628 return d;
1629}
1630
1631#endif
1632
1633QT_END_NAMESPACE
QDebug operator<<(QDebug d, const QSGRootNode *n)
Definition qsgnode.cpp:1570
QDebug operator<<(QDebug d, const QSGClipNode *n)
Definition qsgnode.cpp:1507
QDebug operator<<(QDebug d, const QSGNode *n)
Definition qsgnode.cpp:1587
QDebug operator<<(QDebug d, const QSGTransformNode *n)
Definition qsgnode.cpp:1528
void qsgnode_set_description(QSGNode *node, const QString &description)
Definition qsgnode.cpp:670
QDebug operator<<(QDebug d, const QSGOpacityNode *n)
Definition qsgnode.cpp:1551
static void qt_print_node_count()
Definition qsgnode.cpp:20
static QT_BEGIN_NAMESPACE int qt_node_count
Definition qsgnode.cpp:18
QDebug operator<<(QDebug d, const QSGGeometryNode *n)
Definition qsgnode.cpp:1456
const qreal OPACITY_THRESHOLD
Definition qsgnode.cpp:1330
#define QSG_RUNTIME_DESCRIPTION
Definition qsgnode.h:17