1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
43 #include "qsgrenderer_p.h"
44 #include "qsgnodeupdater_p.h"
45 #include "qsgmaterial.h"
52 static int qt_node_count = 0;
54 static void qt_print_node_count()
56 qDebug("Number of leaked nodes: %i", qt_node_count);
63 \brief The QSGNode class is the base class for all nodes in the scene graph.
67 The QSGNode class can be used as a child container. Children are added with
68 the appendChildNode(), prependChildNode(), insertChildNodeBefore() and
69 insertChildNodeAfter(). Ordering of nodes is important as geometry nodes
70 will be rendered in the order they are added to the scene graph.
71 Actually, the scene may reorder nodes freely, but the resulting visual
72 order is still guaranteed.
74 If nodes change every frame, the preprocess() function can be used to
75 apply changes to a node for every frame its rendered. The use of preprocess()
76 must be explicitly enabled by setting the QSGNode::UsePreprocess flag
79 The virtual isSubtreeBlocked() function can be used to disable a subtree all
80 together. Nodes in a blocked subtree will not be preprocessed() and not
83 Anything related to QSGNode should happen on the scene graph rendering thread.
88 , m_type(BasicNodeType)
92 , m_previousSibling(0)
93 , m_subtreeGeometryCount(0)
94 , m_nodeFlags(OwnedByParent)
100 QSGNode::QSGNode(NodeType type)
106 , m_previousSibling(0)
107 , m_subtreeGeometryCount(type == GeometryNodeType ? 1 : 0)
108 , m_nodeFlags(OwnedByParent)
118 static bool atexit_registered = false;
119 if (!atexit_registered) {
120 atexit(qt_print_node_count);
121 atexit_registered = true;
130 if (qt_node_count < 0)
131 qDebug("Node destroyed after qt_print_node_count() was called.");
138 \fn void QSGNode::preprocess()
140 Override this function to do processing on the node before it is rendered.
142 Preprocessing needs to be explicitly enabled by setting the flag
143 QSGNode::UsePreprocess. The flag needs to be set before the node is added
144 to the scene graph and will cause the preprocess() function to be called
145 for every frame the node is rendered.
147 The preprocess function is called before the update pass that propegates
148 opacity and transformations through the scene graph. That means that
149 functions like QSGOpacityNode::combinedOpacity() and
150 QSGTransformNode::combinedMatrix() will not contain up-to-date values.
151 If such values are changed during the preprocess, these changes will be
152 propegated through the scene graph before it is rendered.
154 \warning Beware of deleting nodes while they are being preprocessed. It is
155 possible, with a small performance hit, to delete a single node during its
156 own preprocess call. Deleting a subtree which has nodes that also use
157 preprocessing may result in a segmentation fault. This is done for
165 Returns whether this node and its subtree is available for use.
167 Blocked subtrees will not get their dirty states updated and they
168 will not be rendered.
170 The QSGOpacityNode will return a blocked subtree when accumulated opacity
174 bool QSGNode::isSubtreeBlocked() const
176 return m_subtreeGeometryCount == 0;
181 Detaches the node from the scene graph and deletes any children it owns.
183 This function is called from QSGNode's and QSGRootNode's destructor. It
184 should not be called explicitly in user code. QSGRootNode needs to call
185 destroy() because destroy() calls removeChildNode() which in turn calls
186 markDirty() which type-casts the node to QSGRootNode. This type-cast is not
187 valid at the time QSGNode's destructor is called because the node will
188 already be partially destroyed at that point.
191 void QSGNode::destroy()
194 m_parent->removeChildNode(this);
195 Q_ASSERT(m_parent == 0);
197 while (m_firstChild) {
198 QSGNode *child = m_firstChild;
199 removeChildNode(child);
200 Q_ASSERT(child->m_parent == 0);
201 if (child->flags() & OwnedByParent)
205 Q_ASSERT(m_firstChild == 0 && m_lastChild == 0);
210 Prepends \a node to this node's the list of children.
212 Ordering of nodes is important as geometry nodes will be rendered in the
213 order they are added to the scene graph.
216 void QSGNode::prependChildNode(QSGNode *node)
218 //Q_ASSERT_X(!m_children.contains(node), "QSGNode::prependChildNode", "QSGNode is already a child!");
219 Q_ASSERT_X(!node->m_parent, "QSGNode::prependChildNode", "QSGNode already has a parent");
222 if (node->type() == QSGNode::GeometryNodeType) {
223 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
224 Q_ASSERT_X(g->material(), "QSGNode::prependChildNode", "QSGGeometryNode is missing material");
225 Q_ASSERT_X(g->geometry(), "QSGNode::prependChildNode", "QSGGeometryNode is missing geometry");
230 m_firstChild->m_previousSibling = node;
233 node->m_nextSibling = m_firstChild;
235 node->m_parent = this;
237 node->markDirty(DirtyNodeAdded);
241 Appends \a node to this node's list of children.
243 Ordering of nodes is important as geometry nodes will be rendered in the
244 order they are added to the scene graph.
247 void QSGNode::appendChildNode(QSGNode *node)
249 //Q_ASSERT_X(!m_children.contains(node), "QSGNode::appendChildNode", "QSGNode is already a child!");
250 Q_ASSERT_X(!node->m_parent, "QSGNode::appendChildNode", "QSGNode already has a parent");
253 if (node->type() == QSGNode::GeometryNodeType) {
254 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
255 Q_ASSERT_X(g->material(), "QSGNode::appendChildNode", "QSGGeometryNode is missing material");
256 Q_ASSERT_X(g->geometry(), "QSGNode::appendChildNode", "QSGGeometryNode is missing geometry");
261 m_lastChild->m_nextSibling = node;
264 node->m_previousSibling = m_lastChild;
266 node->m_parent = this;
268 node->markDirty(DirtyNodeAdded);
274 Inserts \a node to this node's list of children before the node specified with \a before.
276 Ordering of nodes is important as geometry nodes will be rendered in the
277 order they are added to the scene graph.
280 void QSGNode::insertChildNodeBefore(QSGNode *node, QSGNode *before)
282 //Q_ASSERT_X(!m_children.contains(node), "QSGNode::insertChildNodeBefore", "QSGNode is already a child!");
283 Q_ASSERT_X(!node->m_parent, "QSGNode::insertChildNodeBefore", "QSGNode already has a parent");
284 Q_ASSERT_X(before && before->m_parent == this, "QSGNode::insertChildNodeBefore", "The parent of \'before\' is wrong");
287 if (node->type() == QSGNode::GeometryNodeType) {
288 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
289 Q_ASSERT_X(g->material(), "QSGNode::insertChildNodeBefore", "QSGGeometryNode is missing material");
290 Q_ASSERT_X(g->geometry(), "QSGNode::insertChildNodeBefore", "QSGGeometryNode is missing geometry");
294 QSGNode *previous = before->m_previousSibling;
296 previous->m_nextSibling = node;
299 node->m_previousSibling = previous;
300 node->m_nextSibling = before;
301 before->m_previousSibling = node;
302 node->m_parent = this;
304 node->markDirty(DirtyNodeAdded);
310 Inserts \a node to this node's list of children after the node specified with \a after.
312 Ordering of nodes is important as geometry nodes will be rendered in the
313 order they are added to the scene graph.
316 void QSGNode::insertChildNodeAfter(QSGNode *node, QSGNode *after)
318 //Q_ASSERT_X(!m_children.contains(node), "QSGNode::insertChildNodeAfter", "QSGNode is already a child!");
319 Q_ASSERT_X(!node->m_parent, "QSGNode::insertChildNodeAfter", "QSGNode already has a parent");
320 Q_ASSERT_X(after && after->m_parent == this, "QSGNode::insertChildNodeBefore", "The parent of \'before\' is wrong");
323 if (node->type() == QSGNode::GeometryNodeType) {
324 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
325 Q_ASSERT_X(g->material(), "QSGNode::insertChildNodeAfter", "QSGGeometryNode is missing material");
326 Q_ASSERT_X(g->geometry(), "QSGNode::insertChildNodeAfter", "QSGGeometryNode is missing geometry");
330 QSGNode *next = after->m_nextSibling;
332 next->m_previousSibling = node;
335 node->m_nextSibling = next;
336 node->m_previousSibling = after;
337 after->m_nextSibling = node;
338 node->m_parent = this;
340 node->markDirty(DirtyNodeAdded);
346 Removes \a node from this node's list of children.
349 void QSGNode::removeChildNode(QSGNode *node)
351 //Q_ASSERT(m_children.contains(node));
352 Q_ASSERT(node->parent() == this);
354 QSGNode *previous = node->m_previousSibling;
355 QSGNode *next = node->m_nextSibling;
357 previous->m_nextSibling = next;
361 next->m_previousSibling = previous;
363 m_lastChild = previous;
364 node->m_previousSibling = 0;
365 node->m_nextSibling = 0;
367 node->markDirty(DirtyNodeRemoved);
373 Removes all child nodes from this node's list of children.
376 void QSGNode::removeAllChildNodes()
378 while (m_firstChild) {
379 QSGNode *node = m_firstChild;
380 m_firstChild = node->m_nextSibling;
381 node->m_nextSibling = 0;
383 m_firstChild->m_previousSibling = 0;
386 node->markDirty(DirtyNodeRemoved);
392 int QSGNode::childCount() const
395 QSGNode *n = m_firstChild;
398 n = n->m_nextSibling;
404 QSGNode *QSGNode::childAtIndex(int i) const
406 QSGNode *n = m_firstChild;
409 n = n->m_nextSibling;
416 Sets the flag \a f on this node if \a enabled is true;
417 otherwise clears the flag.
422 void QSGNode::setFlag(Flag f, bool enabled)
424 if (bool(m_nodeFlags & f) == enabled)
427 Q_ASSERT(int(UsePreprocess) == int(DirtyUsePreprocess));
428 Q_ASSERT(int(ChildrenDoNotOverlap) == int(DirtyChildrenDoNotOverlap));
429 Q_ASSERT(int(StaticSubtreeGeometry) == int(DirtyStaticSubtreeGeometry));
430 int changedFlag = f & (UsePreprocess | ChildrenDoNotOverlap | StaticSubtreeGeometry);
432 markDirty(DirtyState(changedFlag));
437 Sets the flags \a f on this node if \a enabled is true;
438 otherwise clears the flags.
443 void QSGNode::setFlags(Flags f, bool enabled)
445 Flags oldFlags = m_nodeFlags;
450 Q_ASSERT(int(UsePreprocess) == int(DirtyUsePreprocess));
451 Q_ASSERT(int(ChildrenDoNotOverlap) == int(DirtyChildrenDoNotOverlap));
452 Q_ASSERT(int(StaticSubtreeGeometry) == int(DirtyStaticSubtreeGeometry));
453 int changedFlags = (oldFlags ^ m_nodeFlags)
454 & (UsePreprocess | ChildrenDoNotOverlap | StaticSubtreeGeometry);
456 markDirty(DirtyState(changedFlags));
462 Marks this node with the states in \a flags as dirty.
464 When a node is marked dirty, it recursively mark the parent chain
465 as dirty and notify all connected renderers that the has dirty states.
468 void QSGNode::markDirty(DirtyState bits)
470 m_dirtyState |= (bits & DirtyPropagationMask);
472 DirtyState subtreeBits = DirtyState((bits & DirtyPropagationMask) << 16);
474 int geometryCountDiff = 0;
475 if (bits & DirtyNodeAdded)
476 geometryCountDiff += m_subtreeGeometryCount;
477 if (bits & DirtyNodeRemoved)
478 geometryCountDiff -= m_subtreeGeometryCount;
480 QSGNode *p = m_parent;
482 p->m_dirtyState |= subtreeBits;
483 p->m_subtreeGeometryCount += geometryCountDiff;
484 if (p->type() == RootNodeType)
485 static_cast<QSGRootNode *>(p)->notifyNodeChange(this, bits);
493 \class QSGBasicGeometryNode
494 \brief The QSGBasicGeometryNode class serves as a baseclass for geometry based nodes
498 The QSGBasicGeometryNode class should not be used by itself. It is only encapsulates
499 shared functionality between the QSGGeometryNode and QSGClipNode classes.
504 Creates a new basic geometry node.
506 QSGBasicGeometryNode::QSGBasicGeometryNode(NodeType type)
516 Deletes this QSGBasicGeometryNode.
518 If the node has the flag QSGNode::OwnsGeometry set, it will also delete the
519 geometry object it is pointing to. This flag is not set by default.
522 QSGBasicGeometryNode::~QSGBasicGeometryNode()
524 if (flags() & OwnsGeometry)
530 \fn QSGGeometry *QSGBasicGeometryNode::geometry() const
532 Returns this node's geometry.
534 The geometry is null by default.
539 Sets the geometry of this node to \a geometry.
541 If the node has the flag QSGNode::OwnsGeometry set, it will also delete the
542 geometry object it is pointing to. This flag is not set by default.
545 void QSGBasicGeometryNode::setGeometry(QSGGeometry *geometry)
547 if (flags() & OwnsGeometry)
549 m_geometry = geometry;
550 markDirty(DirtyGeometry);
556 \class QSGGeometryNode
557 \brief The QSGGeometryNode class is used for all rendered content in the scene graph.
561 The QSGGeometryNode consists of geometry and material. The geometry defines the mesh,
562 the vertices and their structure, to be drawn. The Material defines how the shape is
565 A geometry node must have both geometry and a normal material before it is added to
568 The geometry node supports two types of materials, the opaqueMaterial and the normal
569 material. The opaqueMaterial is used when the accumulated scene graph opacity at the
570 time of rendering is 1. The primary usecase is to special case opaque rendering
571 to avoid an extra operation in the fragment shader can have significant performance
572 impact on embedded graphics chips. The opaque material is optional.
578 Creates a new geometry node without geometry and material.
581 QSGGeometryNode::QSGGeometryNode()
582 : QSGBasicGeometryNode(GeometryNodeType)
585 , m_opaque_material(0)
592 Deletes this geometry node.
594 The flags QSGNode::OwnsMaterial, QSGNode::OwnsOpaqueMaterial and
595 QSGNode::OwnsGeometry decides weither the geometry node should also
596 delete the materials and geometry. By default, these flags are disabled.
599 QSGGeometryNode::~QSGGeometryNode()
601 if (flags() & OwnsMaterial)
603 if (flags() & OwnsOpaqueMaterial)
604 delete m_opaque_material;
610 \fn int QSGGeometryNode::renderOrder() const
612 Returns the render order of this geometry node.
619 Sets the render order of this node to be \a order.
621 GeometryNodes are rendered in an order that visually looks like
622 low order nodes are rendered prior to high order nodes. For opaque
623 geometry there is little difference as z-testing will handle
624 the discard, but for translucent objects, the rendering should
625 normally be specified in the order of back-to-front.
627 The default render order is 0.
631 void QSGGeometryNode::setRenderOrder(int order)
633 m_render_order = order;
639 Sets the material of this geometry node to \a material.
641 Geometry nodes must have a material before they can be added to the
644 void QSGGeometryNode::setMaterial(QSGMaterial *material)
646 if (flags() & OwnsMaterial)
648 m_material = material;
650 if (m_material != 0 && m_opaque_material == m_material)
651 qWarning("QSGGeometryNode: using same material for both opaque and translucent");
653 markDirty(DirtyMaterial);
659 Sets the opaque material of this geometry to \a material.
661 The opaque material will be preferred by the renderer over the
662 default material, as returned by the material() function, if
663 it is not null and the geometry item has an inherited opacity of
666 The opaqueness refers to scene graph opacity, the material is still
667 allowed to set QSGMaterial::Blending to true and draw transparent
670 void QSGGeometryNode::setOpaqueMaterial(QSGMaterial *material)
672 if (flags() & OwnsOpaqueMaterial)
673 delete m_opaque_material;
674 m_opaque_material = material;
676 if (m_opaque_material != 0 && m_opaque_material == m_material)
677 qWarning("QSGGeometryNode: using same material for both opaque and translucent");
680 markDirty(DirtyMaterial);
686 Returns the material which should currently be used for geometry node.
688 If the inherited opacity of the node is 1 and there is an opaque material
689 set on this node, it will be returned; otherwise, the default material
692 \warning This function requires the scene graph above this item to be
693 completely free of dirty states, so it can only be called during rendering
697 \sa setMaterial, setOpaqueMaterial
699 QSGMaterial *QSGGeometryNode::activeMaterial() const
701 Q_ASSERT_X(dirtyState() == 0, "QSGGeometryNode::activeMaterial()", "function assumes that all dirty states are cleaned up");
702 if (m_opaque_material && m_opacity > 0.999)
703 return m_opaque_material;
709 Sets the inherited opacity of this geometry to \a opacity.
711 This function is meant to be called by the node preprocessing
712 prior to rendering the tree, so it will not mark the tree as
717 void QSGGeometryNode::setInheritedOpacity(qreal opacity)
719 Q_ASSERT(opacity >= 0 && opacity <= 1);
726 \brief The QSGClipNode class implements the clipping functionality in the scene graph.
730 Clipping applies to the node's subtree and can be nested. Multiple clip nodes will be
731 accumulated by intersecting all their geometries. The accumulation happens
732 as part of the rendering.
734 Clip nodes must have a geometry before they can be added to the scene graph.
736 Clipping is usually implemented by using the stencil buffer.
742 Creates a new QSGClipNode without a geometry.
744 The clip node must have a geometry before it can be added to the
748 QSGClipNode::QSGClipNode()
749 : QSGBasicGeometryNode(ClipNodeType)
756 Deletes this QSGClipNode.
758 If the flag QSGNode::OwnsGeometry is set, the geometry will also be
762 QSGClipNode::~QSGClipNode()
769 \fn bool QSGClipNode::isRectangular() const
771 Returns if this clip node has a rectangular clip.
777 Sets whether this clip node has a rectangular clip to \a rectHint.
779 This is an optimization hint which means that the renderer can
780 use scissoring instead of stencil, which is significnatly faster.
782 When this hint is and it is applicable, the clip region will be
783 generated from clipRect() rather than geometry().
786 void QSGClipNode::setIsRectangular(bool rectHint)
788 m_is_rectangular = rectHint;
794 \fn void QSGClipNode::clipRect() const
796 Returns the clip rect of this node.
801 Sets the clip rect of this clip node to \a rect.
803 When a rectangular clip is set in combination with setIsRectangular
804 the renderer may in some cases use a more optimal clip method.
806 void QSGClipNode::setClipRect(const QRectF &rect)
813 \class QSGTransformNode
814 \brief The QSGTransformNode class implements transformations in the scene graph
818 Transformations apply the node's subtree and can be nested. Multiple transform nodes
819 will be accumulated by intersecting all their matrices. The accumulation happens
820 as part of the rendering.
822 The transform nodes implement a 4x4 matrix which in theory supports full 3D
823 transformations. However, because the renderer optimizes for 2D use-cases rather
824 than 3D use-cases, rendering a scene with full 3D transformations needs to
825 be done with some care.
828 QSGTransformNode::QSGTransformNode()
829 : QSGNode(TransformNodeType)
836 Deletes this transform node.
839 QSGTransformNode::~QSGTransformNode()
846 \fn QMatrix4x4 QSGTransformNode::matrix() const
848 Returns this transform node's matrix.
854 Sets this transform node's matrix to \a matrix.
857 void QSGTransformNode::setMatrix(const QMatrix4x4 &matrix)
860 markDirty(DirtyMatrix);
865 Sets the combined matrix of this matrix to \a transform.
867 This function is meant to be called by the node preprocessing
868 prior to rendering the tree, so it will not mark the tree as
873 void QSGTransformNode::setCombinedMatrix(const QMatrix4x4 &matrix)
875 m_combined_matrix = matrix;
882 \brief The QSGRootNode is the toplevel root of any scene graph.
884 The root node is used to attach a scene graph to a renderer.
892 \fn QSGRootNode::QSGRootNode()
894 Creates a new root node.
897 QSGRootNode::QSGRootNode()
898 : QSGNode(RootNodeType)
904 Deletes the root node.
906 When a root node is deleted it removes itself from all of renderers
907 that are referencing it.
910 QSGRootNode::~QSGRootNode()
912 while (!m_renderers.isEmpty())
913 m_renderers.last()->setRootNode(0);
914 destroy(); // Must call destroy() here because markDirty() casts this to QSGRootNode.
920 Called to notify all renderers that \a node has been marked as dirty
924 void QSGRootNode::notifyNodeChange(QSGNode *node, DirtyState state)
926 for (int i=0; i<m_renderers.size(); ++i) {
927 m_renderers.at(i)->nodeChanged(node, state);
934 \class QSGOpacityNode
935 \brief The QSGOpacityNode class is used to change opacity of nodes.
939 Opacity applies to its subtree and can be nested. Multiple opacity nodes
940 will be accumulated by multiplying their opacity. The accumulation happens
941 as part of the rendering.
943 When nested opacity gets below a certain threshold, the subtree might
944 be marked as blocked, causing isSubtreeBlocked() to return true. This
945 is done for performance reasons.
952 Constructs an opacity node with a default opacity of 1.
954 Opacity accumulates downwards in the scene graph so a node with two
955 QSGOpacityNode instances above it, both with opacity of 0.5, will have
956 effective opacity of 0.25.
958 The default opacity of nodes is 1.
960 QSGOpacityNode::QSGOpacityNode()
961 : QSGNode(OpacityNodeType)
963 , m_combined_opacity(1)
970 Deletes the opacity node.
973 QSGOpacityNode::~QSGOpacityNode()
980 \fn qreal QSGOpacityNode::opacity() const
982 Returns this opacity node's opacity.
988 Sets the opacity of this node to \a opacity.
990 Before rendering the graph, the renderer will do an update pass
991 over the subtree to propegate the opacity to its children.
993 The value will be bounded to the range 0 to 1.
996 void QSGOpacityNode::setOpacity(qreal opacity)
998 opacity = qBound<qreal>(0, opacity, 1);
999 if (m_opacity == opacity)
1001 m_opacity = opacity;
1002 markDirty(DirtyOpacity);
1008 \fn qreal QSGOpacityNode::combinedOpacity() const
1010 Returns this node's accumulated opacity.
1012 This vaule is calculated during rendering and only stored
1013 in the opacity node temporarily.
1021 Sets the combined opacity of this node to \a opacity.
1023 This function is meant to be called by the node preprocessing
1024 prior to rendering the tree, so it will not mark the tree as
1030 void QSGOpacityNode::setCombinedOpacity(qreal opacity)
1032 m_combined_opacity = opacity;
1038 For performance reasons, we block the subtree when the opacity
1039 is below a certain threshold.
1044 bool QSGOpacityNode::isSubtreeBlocked() const
1046 return QSGNode::isSubtreeBlocked() || m_opacity < 0.001;
1051 \class QSGNodeVisitor
1052 \brief The QSGNodeVisitor class is a helper class for traversing the scene graph.
1057 QSGNodeVisitor::~QSGNodeVisitor()
1063 void QSGNodeVisitor::visitNode(QSGNode *n)
1065 switch (n->type()) {
1066 case QSGNode::TransformNodeType: {
1067 QSGTransformNode *t = static_cast<QSGTransformNode *>(n);
1068 enterTransformNode(t);
1070 leaveTransformNode(t);
1072 case QSGNode::GeometryNodeType: {
1073 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(n);
1074 enterGeometryNode(g);
1076 leaveGeometryNode(g);
1078 case QSGNode::ClipNodeType: {
1079 QSGClipNode *c = static_cast<QSGClipNode *>(n);
1084 case QSGNode::OpacityNodeType: {
1085 QSGOpacityNode *o = static_cast<QSGOpacityNode *>(n);
1086 enterOpacityNode(o);
1088 leaveOpacityNode(o);
1096 void QSGNodeVisitor::visitChildren(QSGNode *n)
1098 for (QSGNode *c = n->firstChild(); c; c = c->nextSibling())
1104 #ifndef QT_NO_DEBUG_STREAM
1105 QDebug operator<<(QDebug d, const QSGGeometryNode *n)
1108 d << "QSGGeometryNode(null)";
1111 d << "QSGGeometryNode(" << hex << (void *) n << dec;
1113 const QSGGeometry *g = n->geometry();
1119 switch (g->drawingMode()) {
1120 case GL_TRIANGLE_STRIP: d << "strip"; break;
1121 case GL_TRIANGLE_FAN: d << "fan"; break;
1122 case GL_TRIANGLES: d << "triangles"; break;
1126 d << g->vertexCount();
1128 if (g->attributeCount() > 0 && g->attributes()->type == GL_FLOAT) {
1129 float x1 = 1e10, x2 = -1e10, y1=1e10, y2=-1e10;
1130 int stride = g->sizeOfVertex();
1131 for (int i = 0; i < g->vertexCount(); ++i) {
1132 float x = ((float *)((char *)const_cast<QSGGeometry *>(g)->vertexData() + i * stride))[0];
1133 float y = ((float *)((char *)const_cast<QSGGeometry *>(g)->vertexData() + i * stride))[1];
1141 d << "x1=" << x1 << "y1=" << y1 << "x2=" << x2 << "y2=" << y2;
1145 d << "order=" << n->renderOrder();
1147 d << "effect=" << n->material() << "type=" << n->material()->type();
1151 #ifdef QML_RUNTIME_TESTING
1152 d << n->description;
1154 d << "dirty=" << hex << (int) n->dirtyState() << dec;
1158 QDebug operator<<(QDebug d, const QSGClipNode *n)
1161 d << "QSGClipNode(null)";
1164 d << "QSGClipNode(" << hex << (void *) n << dec;
1166 if (n->childCount())
1167 d << "children=" << n->childCount();
1169 d << "is rect?" << (n->isRectangular() ? "yes" : "no");
1172 #ifdef QML_RUNTIME_TESTING
1173 d << n->description;
1175 d << "dirty=" << hex << (int) n->dirtyState() << dec << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1179 QDebug operator<<(QDebug d, const QSGTransformNode *n)
1182 d << "QSGTransformNode(null)";
1185 const QMatrix4x4 m = n->matrix();
1186 d << "QSGTransformNode(";
1187 d << hex << (void *) n << dec;
1190 else if (m.determinant() == 1 && m(0, 0) == 1 && m(1, 1) == 1 && m(2, 2) == 1)
1191 d << "translate" << m(0, 3) << m(1, 3) << m(2, 3);
1193 d << "det=" << n->matrix().determinant();
1194 #ifdef QML_RUNTIME_TESTING
1195 d << n->description;
1197 d << "dirty=" << hex << (int) n->dirtyState() << dec << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1202 QDebug operator<<(QDebug d, const QSGOpacityNode *n)
1205 d << "QSGOpacityNode(null)";
1208 d << "QSGOpacityNode(";
1209 d << hex << (void *) n << dec;
1210 d << "opacity=" << n->opacity()
1211 << "combined=" << n->combinedOpacity()
1212 << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1213 #ifdef QML_RUNTIME_TESTING
1214 d << n->description;
1216 d << "dirty=" << hex << (int) n->dirtyState() << dec;
1222 QDebug operator<<(QDebug d, const QSGRootNode *n)
1225 d << "QSGRootNode(null)";
1228 d << "QSGRootNode" << hex << (void *) n << "dirty=" << (int) n->dirtyState() << dec
1229 << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1230 #ifdef QML_RUNTIME_TESTING
1231 d << n->description;
1239 QDebug operator<<(QDebug d, const QSGNode *n)
1242 d << "QSGNode(null)";
1245 switch (n->type()) {
1246 case QSGNode::GeometryNodeType:
1247 d << static_cast<const QSGGeometryNode *>(n);
1249 case QSGNode::TransformNodeType:
1250 d << static_cast<const QSGTransformNode *>(n);
1252 case QSGNode::ClipNodeType:
1253 d << static_cast<const QSGClipNode *>(n);
1255 case QSGNode::RootNodeType:
1256 d << static_cast<const QSGRootNode *>(n);
1258 case QSGNode::OpacityNodeType:
1259 d << static_cast<const QSGOpacityNode *>(n);
1262 d << "QSGNode(" << hex << (void *) n << dec
1263 << "dirty=" << hex << (int) n->dirtyState()
1264 << "flags=" << (int) n->flags() << dec
1265 << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1266 #ifdef QML_RUNTIME_TESTING
1267 d << n->description;