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