1 /****************************************************************************
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
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.
65 The QSGNode class can be used as a child container. Children are added with
66 the appendChildNode(), prependChildNode(), insertChildNodeBefore() and
67 insertChildNodeAfter(). Ordering of nodes is important as geometry nodes
68 will be rendered in the order they are added to the scene graph.
69 Actually, the scene may reorder nodes freely, but the resulting visual
70 order is still guaranteed.
72 If nodes change every frame, the preprocess() function can be used to
73 apply changes to a node for every frame its rendered. The use of preprocess()
74 must be explicitly enabled by setting the QSGNode::UsePreprocess flag
77 The virtual isSubtreeBlocked() function can be used to disable a subtree all
78 together. Nodes in a blocked subtree will not be preprocessed() and not
81 Anything related to QSGNode should happen on the scene graph rendering thread.
86 , m_type(BasicNodeType)
90 , m_previousSibling(0)
91 , m_subtreeGeometryCount(0)
92 , m_nodeFlags(OwnedByParent)
98 QSGNode::QSGNode(NodeType type)
104 , m_previousSibling(0)
105 , m_subtreeGeometryCount(type == GeometryNodeType ? 1 : 0)
106 , m_nodeFlags(OwnedByParent)
116 static bool atexit_registered = false;
117 if (!atexit_registered) {
118 atexit(qt_print_node_count);
119 atexit_registered = true;
128 if (qt_node_count < 0)
129 qDebug("Node destroyed after qt_print_node_count() was called.");
136 \fn void QSGNode::preprocess()
138 Override this function to do processing on the node before it is rendered.
140 Preprocessing needs to be explicitly enabled by setting the flag
141 QSGNode::UsePreprocess. The flag needs to be set before the node is added
142 to the scene graph and will cause the preprocess() function to be called
143 for every frame the node is rendered.
145 The preprocess function is called before the update pass that propegates
146 opacity and transformations through the scene graph. That means that
147 functions like QSGOpacityNode::combinedOpacity() and
148 QSGTransformNode::combinedMatrix() will not contain up-to-date values.
149 If such values are changed during the preprocess, these changes will be
150 propegated through the scene graph before it is rendered.
152 \warning Beware of deleting nodes while they are being preprocessed. It is
153 possible, with a small performance hit, to delete a single node during its
154 own preprocess call. Deleting a subtree which has nodes that also use
155 preprocessing may result in a segmentation fault. This is done for
163 Returns whether this node and its subtree is available for use.
165 Blocked subtrees will not get their dirty states updated and they
166 will not be rendered.
168 The QSGOpacityNode will return a blocked subtree when accumulated opacity
172 bool QSGNode::isSubtreeBlocked() const
174 return m_subtreeGeometryCount == 0;
179 Detaches the node from the scene graph and deletes any children it owns.
181 This function is called from QSGNode's and QSGRootNode's destructor. It
182 should not be called explicitly in user code. QSGRootNode needs to call
183 destroy() because destroy() calls removeChildNode() which in turn calls
184 markDirty() which type-casts the node to QSGRootNode. This type-cast is not
185 valid at the time QSGNode's destructor is called because the node will
186 already be partially destroyed at that point.
189 void QSGNode::destroy()
192 m_parent->removeChildNode(this);
193 Q_ASSERT(m_parent == 0);
195 while (m_firstChild) {
196 QSGNode *child = m_firstChild;
197 removeChildNode(child);
198 Q_ASSERT(child->m_parent == 0);
199 if (child->flags() & OwnedByParent)
203 Q_ASSERT(m_firstChild == 0 && m_lastChild == 0);
208 Prepends \a node to this node's the list of children.
210 Ordering of nodes is important as geometry nodes will be rendered in the
211 order they are added to the scene graph.
214 void QSGNode::prependChildNode(QSGNode *node)
216 //Q_ASSERT_X(!m_children.contains(node), "QSGNode::prependChildNode", "QSGNode is already a child!");
217 Q_ASSERT_X(!node->m_parent, "QSGNode::prependChildNode", "QSGNode already has a parent");
220 if (node->type() == QSGNode::GeometryNodeType) {
221 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
222 Q_ASSERT_X(g->material(), "QSGNode::prependChildNode", "QSGGeometryNode is missing material");
223 Q_ASSERT_X(g->geometry(), "QSGNode::prependChildNode", "QSGGeometryNode is missing geometry");
228 m_firstChild->m_previousSibling = node;
231 node->m_nextSibling = m_firstChild;
233 node->m_parent = this;
235 node->markDirty(DirtyNodeAdded);
239 Appends \a node to this node's list of children.
241 Ordering of nodes is important as geometry nodes will be rendered in the
242 order they are added to the scene graph.
245 void QSGNode::appendChildNode(QSGNode *node)
247 //Q_ASSERT_X(!m_children.contains(node), "QSGNode::appendChildNode", "QSGNode is already a child!");
248 Q_ASSERT_X(!node->m_parent, "QSGNode::appendChildNode", "QSGNode already has a parent");
251 if (node->type() == QSGNode::GeometryNodeType) {
252 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
253 Q_ASSERT_X(g->material(), "QSGNode::appendChildNode", "QSGGeometryNode is missing material");
254 Q_ASSERT_X(g->geometry(), "QSGNode::appendChildNode", "QSGGeometryNode is missing geometry");
259 m_lastChild->m_nextSibling = node;
262 node->m_previousSibling = m_lastChild;
264 node->m_parent = this;
266 node->markDirty(DirtyNodeAdded);
272 Inserts \a node to this node's list of children before the node specified with \a before.
274 Ordering of nodes is important as geometry nodes will be rendered in the
275 order they are added to the scene graph.
278 void QSGNode::insertChildNodeBefore(QSGNode *node, QSGNode *before)
280 //Q_ASSERT_X(!m_children.contains(node), "QSGNode::insertChildNodeBefore", "QSGNode is already a child!");
281 Q_ASSERT_X(!node->m_parent, "QSGNode::insertChildNodeBefore", "QSGNode already has a parent");
282 Q_ASSERT_X(before && before->m_parent == this, "QSGNode::insertChildNodeBefore", "The parent of \'before\' is wrong");
285 if (node->type() == QSGNode::GeometryNodeType) {
286 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
287 Q_ASSERT_X(g->material(), "QSGNode::insertChildNodeBefore", "QSGGeometryNode is missing material");
288 Q_ASSERT_X(g->geometry(), "QSGNode::insertChildNodeBefore", "QSGGeometryNode is missing geometry");
292 QSGNode *previous = before->m_previousSibling;
294 previous->m_nextSibling = node;
297 node->m_previousSibling = previous;
298 node->m_nextSibling = before;
299 before->m_previousSibling = node;
300 node->m_parent = this;
302 node->markDirty(DirtyNodeAdded);
308 Inserts \a node to this node's list of children after the node specified with \a after.
310 Ordering of nodes is important as geometry nodes will be rendered in the
311 order they are added to the scene graph.
314 void QSGNode::insertChildNodeAfter(QSGNode *node, QSGNode *after)
316 //Q_ASSERT_X(!m_children.contains(node), "QSGNode::insertChildNodeAfter", "QSGNode is already a child!");
317 Q_ASSERT_X(!node->m_parent, "QSGNode::insertChildNodeAfter", "QSGNode already has a parent");
318 Q_ASSERT_X(after && after->m_parent == this, "QSGNode::insertChildNodeBefore", "The parent of \'before\' is wrong");
321 if (node->type() == QSGNode::GeometryNodeType) {
322 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
323 Q_ASSERT_X(g->material(), "QSGNode::insertChildNodeAfter", "QSGGeometryNode is missing material");
324 Q_ASSERT_X(g->geometry(), "QSGNode::insertChildNodeAfter", "QSGGeometryNode is missing geometry");
328 QSGNode *next = after->m_nextSibling;
330 next->m_previousSibling = node;
333 node->m_nextSibling = next;
334 node->m_previousSibling = after;
335 after->m_nextSibling = node;
336 node->m_parent = this;
338 node->markDirty(DirtyNodeAdded);
344 Removes \a node from this node's list of children.
347 void QSGNode::removeChildNode(QSGNode *node)
349 //Q_ASSERT(m_children.contains(node));
350 Q_ASSERT(node->parent() == this);
352 QSGNode *previous = node->m_previousSibling;
353 QSGNode *next = node->m_nextSibling;
355 previous->m_nextSibling = next;
359 next->m_previousSibling = previous;
361 m_lastChild = previous;
362 node->m_previousSibling = 0;
363 node->m_nextSibling = 0;
365 node->markDirty(DirtyNodeRemoved);
371 Removes all child nodes from this node's list of children.
374 void QSGNode::removeAllChildNodes()
376 while (m_firstChild) {
377 QSGNode *node = m_firstChild;
378 m_firstChild = node->m_nextSibling;
379 node->m_nextSibling = 0;
381 m_firstChild->m_previousSibling = 0;
384 node->markDirty(DirtyNodeRemoved);
390 int QSGNode::childCount() const
393 QSGNode *n = m_firstChild;
396 n = n->m_nextSibling;
402 QSGNode *QSGNode::childAtIndex(int i) const
404 QSGNode *n = m_firstChild;
407 n = n->m_nextSibling;
414 Sets the flag \a f on this node if \a enabled is true;
415 otherwise clears the flag.
420 void QSGNode::setFlag(Flag f, bool enabled)
430 Sets the flags \a f on this node if \a enabled is true;
431 otherwise clears the flags.
436 void QSGNode::setFlags(Flags f, bool enabled)
447 Marks this node with the states in \a flags as dirty.
449 When a node is marked dirty, it recursively mark the parent chain
450 as dirty and notify all connected renderers that the has dirty states.
453 void QSGNode::markDirty(DirtyFlags flags)
455 m_flags |= (flags & DirtyPropagationMask);
457 DirtyFlags subtreeFlags = DirtyFlags((flags & DirtyPropagationMask) << 16);
459 int geometryCountDiff = 0;
460 if (flags & DirtyNodeAdded)
461 geometryCountDiff += m_subtreeGeometryCount;
462 if (flags & DirtyNodeRemoved)
463 geometryCountDiff -= m_subtreeGeometryCount;
465 QSGNode *p = m_parent;
467 p->m_flags |= subtreeFlags;
468 p->m_subtreeGeometryCount += geometryCountDiff;
469 if (p->type() == RootNodeType)
470 static_cast<QSGRootNode *>(p)->notifyNodeChange(this, flags);
478 \class QSGBasicGeometryNode
479 \brief The QSGBasicGeometryNode serves as a baseclass for geometry based nodes
481 The QSGBasicGeometryNode class should not be used by itself. It is only encapsulates
482 shared functionality between the QSGGeometryNode and QSGClipNode classes.
487 Creates a new basic geometry node.
489 QSGBasicGeometryNode::QSGBasicGeometryNode(NodeType type)
499 Deletes this QSGBasicGeometryNode.
501 If the node has the flag QSGNode::OwnsGeometry set, it will also delete the
502 geometry object it is pointing to. This flag is not set by default.
505 QSGBasicGeometryNode::~QSGBasicGeometryNode()
507 if (flags() & OwnsGeometry)
513 \fn QSGGeometry *QSGBasicGeometryNode::geometry() const
515 Returns this node's geometry.
517 The geometry is null by default.
522 Sets the geometry of this node to \a geometry.
524 If the node has the flag QSGNode::OwnsGeometry set, it will also delete the
525 geometry object it is pointing to. This flag is not set by default.
528 void QSGBasicGeometryNode::setGeometry(QSGGeometry *geometry)
530 if (flags() & OwnsGeometry)
532 m_geometry = geometry;
533 markDirty(DirtyGeometry);
539 \class QSGGeometryNode
540 \brief The QSGGeometryNode class is used for all rendered content in the scene graph.
542 The QSGGeometryNode consists of geometry and material. The geometry defines the mesh,
543 the vertices and their structure, to be drawn. The Material defines how the shape is
546 A geometry node must have both geometry and a normal material before it is added to
549 The geometry node supports two types of materials, the opaqueMaterial and the normal
550 material. The opaqueMaterial is used when the accumulated scene graph opacity at the
551 time of rendering is 1. The primary usecase is to special case opaque rendering
552 to avoid an extra operation in the fragment shader can have significant performance
553 impact on embedded graphics chips. The opaque material is optional.
559 Creates a new geometry node without geometry and material.
562 QSGGeometryNode::QSGGeometryNode()
563 : QSGBasicGeometryNode(GeometryNodeType)
566 , m_opaque_material(0)
573 Deletes this geometry node.
575 The flags QSGNode::OwnsMaterial, QSGNode::OwnsOpaqueMaterial and
576 QSGNode::OwnsGeometry decides weither the geometry node should also
577 delete the materials and geometry. By default, these flags are disabled.
580 QSGGeometryNode::~QSGGeometryNode()
582 if (flags() & OwnsMaterial)
584 if (flags() & OwnsOpaqueMaterial)
585 delete m_opaque_material;
591 \fn int QSGGeometryNode::renderOrder() const
593 Returns the render order of this geometry node.
600 Sets the render order of this node to be \a order.
602 GeometryNodes are rendered in an order that visually looks like
603 low order nodes are rendered prior to high order nodes. For opaque
604 geometry there is little difference as z-testing will handle
605 the discard, but for translucent objects, the rendering should
606 normally be specified in the order of back-to-front.
608 The default render order is 0.
612 void QSGGeometryNode::setRenderOrder(int order)
614 m_render_order = order;
620 Sets the material of this geometry node to \a material.
622 Geometry nodes must have a material before they can be added to the
625 void QSGGeometryNode::setMaterial(QSGMaterial *material)
627 if (flags() & OwnsMaterial)
629 m_material = material;
631 if (m_material != 0 && m_opaque_material == m_material)
632 qWarning("QSGGeometryNode: using same material for both opaque and translucent");
634 markDirty(DirtyMaterial);
640 Sets the opaque material of this geometry to \a material.
642 The opaque material will be preferred by the renderer over the
643 default material, as returned by the material() function, if
644 it is not null and the geometry item has an inherited opacity of
647 The opaqueness refers to scene graph opacity, the material is still
648 allowed to set QSGMaterial::Blending to true and draw transparent
651 void QSGGeometryNode::setOpaqueMaterial(QSGMaterial *material)
653 if (flags() & OwnsOpaqueMaterial)
654 delete m_opaque_material;
655 m_opaque_material = material;
657 if (m_opaque_material != 0 && m_opaque_material == m_material)
658 qWarning("QSGGeometryNode: using same material for both opaque and translucent");
661 markDirty(DirtyMaterial);
667 Returns the material which should currently be used for geometry node.
669 If the inherited opacity of the node is 1 and there is an opaque material
670 set on this node, it will be returned; otherwise, the default material
673 \warning This function requires the scene graph above this item to be
674 completely free of dirty states, so it can only be called during rendering
678 \sa setMaterial, setOpaqueMaterial
680 QSGMaterial *QSGGeometryNode::activeMaterial() const
682 Q_ASSERT_X(dirtyFlags() == 0, "QSGGeometryNode::activeMaterial()", "function assumes that all dirty states are cleaned up");
683 if (m_opaque_material && m_opacity > 0.999)
684 return m_opaque_material;
690 Sets the inherited opacity of this geometry to \a opacity.
692 This function is meant to be called by the node preprocessing
693 prior to rendering the tree, so it will not mark the tree as
698 void QSGGeometryNode::setInheritedOpacity(qreal opacity)
700 Q_ASSERT(opacity >= 0 && opacity <= 1);
707 \brief The QSGClipNode implements the clipping functionality in the scene graph.
709 Clipping applies to the node's subtree and can be nested. Multiple clip nodes will be
710 accumulated by intersecting all their geometries. The accumulation happens
711 as part of the rendering.
713 Clip nodes must have a geometry before they can be added to the scene graph.
715 Clipping is usually implemented by using the stencil buffer.
721 Creates a new QSGClipNode without a geometry.
723 The clip node must have a geometry before it can be added to the
727 QSGClipNode::QSGClipNode()
728 : QSGBasicGeometryNode(ClipNodeType)
735 Deletes this QSGClipNode.
737 If the flag QSGNode::OwnsGeometry is set, the geometry will also be
741 QSGClipNode::~QSGClipNode()
748 \fn bool QSGClipNode::isRectangular() const
750 Returns if this clip node has a rectangular clip.
756 Sets whether this clip node has a rectangular clip to \a rectHint.
758 This is an optimization hint which means that the renderer can
759 use scissoring instead of stencil, which is significnatly faster.
761 When this hint is and it is applicable, the clip region will be
762 generated from clipRect() rather than geometry().
765 void QSGClipNode::setIsRectangular(bool rectHint)
767 m_is_rectangular = rectHint;
773 \fn void QSGClipNode::clipRect() const
775 Returns the clip rect of this node.
780 Sets the clip rect of this clip node to \a rect.
782 When a rectangular clip is set in combination with setIsRectangular
783 the renderer may in some cases use a more optimal clip method.
785 void QSGClipNode::setClipRect(const QRectF &rect)
792 \class QSGTransformNode
793 \brief The QSGTransformNode implements transformations in the scene graph
795 Transformations apply the node's subtree and can be nested. Multiple transform nodes
796 will be accumulated by intersecting all their matrices. The accumulation happens
797 as part of the rendering.
799 The transform nodes implement a 4x4 matrix which in theory supports full 3D
800 transformations. However, because the renderer optimizes for 2D use-cases rather
801 than 3D use-cases, rendering a scene with full 3D transformations needs to
802 be done with some care.
805 QSGTransformNode::QSGTransformNode()
806 : QSGNode(TransformNodeType)
813 Deletes this transform node.
816 QSGTransformNode::~QSGTransformNode()
823 \fn QMatrix4x4 QSGTransformNode::matrix() const
825 Returns this transform node's matrix.
831 Sets this transform node's matrix to \a matrix.
834 void QSGTransformNode::setMatrix(const QMatrix4x4 &matrix)
837 markDirty(DirtyMatrix);
842 Sets the combined matrix of this matrix to \a transform.
844 This function is meant to be called by the node preprocessing
845 prior to rendering the tree, so it will not mark the tree as
850 void QSGTransformNode::setCombinedMatrix(const QMatrix4x4 &matrix)
852 m_combined_matrix = matrix;
859 \brief The QSGRootNode is the toplevel root of any scene graph.
861 The root node is used to attach a scene graph to a renderer.
869 \fn QSGRootNode::QSGRootNode()
871 Creates a new root node.
874 QSGRootNode::QSGRootNode()
875 : QSGNode(RootNodeType)
881 Deletes the root node.
883 When a root node is deleted it removes itself from all of renderers
884 that are referencing it.
887 QSGRootNode::~QSGRootNode()
889 while (!m_renderers.isEmpty())
890 m_renderers.last()->setRootNode(0);
891 destroy(); // Must call destroy() here because markDirty() casts this to QSGRootNode.
897 Called to notify all renderers that \a node has been marked as dirty
901 void QSGRootNode::notifyNodeChange(QSGNode *node, DirtyFlags flags)
903 for (int i=0; i<m_renderers.size(); ++i) {
904 m_renderers.at(i)->nodeChanged(node, flags);
911 \class QSGOpacityNode
912 \brief The QSGOpacityNode is used
914 Opacity apply to its subtree and can be nested. Multiple opacity nodes
915 will be accumulated by multiplying their opacity. The accumulation happens
916 as part of the rendering.
918 When nested opacity gets below a certain threshold, the subtree might
919 be marked as blocked, causing isSubtreeBlocked() to return true. This
920 is done for performance reasons.
927 Constructs an opacity node with a default opacity of 1.
929 Opacity accumulate downwards in the scene graph so a node with two
930 QSGOpacityNode instances above it, both with opacity of 0.5, will have
931 effective opacity of 0.25.
933 The default opacity of nodes is 1.
935 QSGOpacityNode::QSGOpacityNode()
936 : QSGNode(OpacityNodeType)
938 , m_combined_opacity(1)
945 Deletes the opacity node.
948 QSGOpacityNode::~QSGOpacityNode()
955 \fn qreal QSGOpacityNode::opacity() const
957 Returns this opacity node's opacity.
963 Sets the opacity of this node to \a opacity.
965 Before rendering the graph, the renderer will do an update pass
966 over the subtree to propegate the opacity to its children.
968 The value will be bounded to the range 0 to 1.
971 void QSGOpacityNode::setOpacity(qreal opacity)
973 opacity = qBound<qreal>(0, opacity, 1);
974 if (m_opacity == opacity)
977 markDirty(DirtyOpacity);
983 \fn qreal QSGOpacityNode::combinedOpacity() const
985 Returns this node's accumulated opacity.
987 This vaule is calculated during rendering and only stored
988 in the opacity node temporarily.
996 Sets the combined opacity of this node to \a opacity.
998 This function is meant to be called by the node preprocessing
999 prior to rendering the tree, so it will not mark the tree as
1005 void QSGOpacityNode::setCombinedOpacity(qreal opacity)
1007 m_combined_opacity = opacity;
1013 For performance reasons, we block the subtree when the opacity
1014 is below a certain threshold.
1019 bool QSGOpacityNode::isSubtreeBlocked() const
1021 return QSGNode::isSubtreeBlocked() || m_opacity < 0.001;
1026 \class QSGNodeVisitor
1027 \brief The QSGNodeVisitor class is a helper class for traversing the scene graph.
1032 QSGNodeVisitor::~QSGNodeVisitor()
1038 void QSGNodeVisitor::visitNode(QSGNode *n)
1040 switch (n->type()) {
1041 case QSGNode::TransformNodeType: {
1042 QSGTransformNode *t = static_cast<QSGTransformNode *>(n);
1043 enterTransformNode(t);
1045 leaveTransformNode(t);
1047 case QSGNode::GeometryNodeType: {
1048 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(n);
1049 enterGeometryNode(g);
1051 leaveGeometryNode(g);
1053 case QSGNode::ClipNodeType: {
1054 QSGClipNode *c = static_cast<QSGClipNode *>(n);
1059 case QSGNode::OpacityNodeType: {
1060 QSGOpacityNode *o = static_cast<QSGOpacityNode *>(n);
1061 enterOpacityNode(o);
1063 leaveOpacityNode(o);
1071 void QSGNodeVisitor::visitChildren(QSGNode *n)
1073 for (QSGNode *c = n->firstChild(); c; c = c->nextSibling())
1079 #ifndef QT_NO_DEBUG_STREAM
1080 QDebug operator<<(QDebug d, const QSGGeometryNode *n)
1083 d << "QSGGeometryNode(null)";
1086 d << "QSGGeometryNode(" << hex << (void *) n << dec;
1088 const QSGGeometry *g = n->geometry();
1094 switch (g->drawingMode()) {
1095 case GL_TRIANGLE_STRIP: d << "strip"; break;
1096 case GL_TRIANGLE_FAN: d << "fan"; break;
1097 case GL_TRIANGLES: d << "triangles"; break;
1101 d << g->vertexCount();
1103 if (g->attributeCount() > 0 && g->attributes()->type == GL_FLOAT) {
1104 float x1 = 1e10, x2 = -1e10, y1=1e10, y2=-1e10;
1105 int stride = g->sizeOfVertex();
1106 for (int i = 0; i < g->vertexCount(); ++i) {
1107 float x = ((float *)((char *)const_cast<QSGGeometry *>(g)->vertexData() + i * stride))[0];
1108 float y = ((float *)((char *)const_cast<QSGGeometry *>(g)->vertexData() + i * stride))[1];
1116 d << "x1=" << x1 << "y1=" << y1 << "x2=" << x2 << "y2=" << y2;
1120 d << "order=" << n->renderOrder();
1122 d << "effect=" << n->material() << "type=" << n->material()->type();
1126 #ifdef QML_RUNTIME_TESTING
1127 d << n->description;
1129 d << "dirty=" << hex << (int) n->dirtyFlags() << dec;
1133 QDebug operator<<(QDebug d, const QSGClipNode *n)
1136 d << "QSGClipNode(null)";
1139 d << "QSGClipNode(" << hex << (void *) n << dec;
1141 if (n->childCount())
1142 d << "children=" << n->childCount();
1144 d << "is rect?" << (n->isRectangular() ? "yes" : "no");
1147 #ifdef QML_RUNTIME_TESTING
1148 d << n->description;
1150 d << "dirty=" << hex << (int) n->dirtyFlags() << dec << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1154 QDebug operator<<(QDebug d, const QSGTransformNode *n)
1157 d << "QSGTransformNode(null)";
1160 const QMatrix4x4 m = n->matrix();
1161 d << "QSGTransformNode(";
1162 d << hex << (void *) n << dec;
1165 else if (m.determinant() == 1 && m(0, 0) == 1 && m(1, 1) == 1 && m(2, 2) == 1)
1166 d << "translate" << m(0, 3) << m(1, 3) << m(2, 3);
1168 d << "det=" << n->matrix().determinant();
1169 #ifdef QML_RUNTIME_TESTING
1170 d << n->description;
1172 d << "dirty=" << hex << (int) n->dirtyFlags() << dec << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1177 QDebug operator<<(QDebug d, const QSGOpacityNode *n)
1180 d << "QSGOpacityNode(null)";
1183 d << "QSGOpacityNode(";
1184 d << hex << (void *) n << dec;
1185 d << "opacity=" << n->opacity()
1186 << "combined=" << n->combinedOpacity()
1187 << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1188 #ifdef QML_RUNTIME_TESTING
1189 d << n->description;
1191 d << "dirty=" << hex << (int) n->dirtyFlags() << dec;
1197 QDebug operator<<(QDebug d, const QSGRootNode *n)
1200 d << "QSGRootNode(null)";
1203 d << "QSGRootNode" << hex << (void *) n << "dirty=" << (int) n->dirtyFlags() << dec
1204 << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1205 #ifdef QML_RUNTIME_TESTING
1206 d << n->description;
1214 QDebug operator<<(QDebug d, const QSGNode *n)
1217 d << "QSGNode(null)";
1220 switch (n->type()) {
1221 case QSGNode::GeometryNodeType:
1222 d << static_cast<const QSGGeometryNode *>(n);
1224 case QSGNode::TransformNodeType:
1225 d << static_cast<const QSGTransformNode *>(n);
1227 case QSGNode::ClipNodeType:
1228 d << static_cast<const QSGClipNode *>(n);
1230 case QSGNode::RootNodeType:
1231 d << static_cast<const QSGRootNode *>(n);
1233 case QSGNode::OpacityNodeType:
1234 d << static_cast<const QSGOpacityNode *>(n);
1237 d << "QSGNode(" << hex << (void *) n << dec
1238 << "dirty=" << hex << (int) n->dirtyFlags()
1239 << "flags=" << (int) n->flags() << dec
1240 << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1241 #ifdef QML_RUNTIME_TESTING
1242 d << n->description;