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

source code of qtdeclarative/src/quick/scenegraph/coreapi/qsgnode.cpp