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 "qsgnodeupdater_p.h"
5#include "qsgnode.h"
6#include "qsgrendernode_p.h"
7
8QT_BEGIN_NAMESPACE
9
10// #define QSG_UPDATER_DEBUG
11
12QSGNodeUpdater::QSGNodeUpdater()
13 : m_combined_matrix_stack(64)
14 , m_opacity_stack(64)
15 , m_current_clip(nullptr)
16 , m_force_update(0)
17{
18 m_opacity_stack.add(t: 1);
19}
20
21QSGNodeUpdater::~QSGNodeUpdater()
22{
23}
24
25void QSGNodeUpdater::updateStates(QSGNode *n)
26{
27 m_current_clip = nullptr;
28 m_force_update = 0;
29
30 Q_ASSERT(m_opacity_stack.size() == 1); // The one we added in the constructr...
31 Q_ASSERT(m_combined_matrix_stack.isEmpty());
32
33 visitNode(n);
34}
35
36
37/*!
38 Returns true if \a node is has something that blocks it in the chain from
39 \a node to \a root doing a full state update pass.
40
41 This function does not process dirty states, simply does a simple traversion
42 up to the top.
43
44 The function assumes that \a root exists in the parent chain of \a node.
45 */
46
47bool QSGNodeUpdater::isNodeBlocked(QSGNode *node, QSGNode *root) const
48{
49 while (node != root && node != nullptr) {
50 if (node->isSubtreeBlocked())
51 return true;
52 node = node->parent();
53 }
54 return false;
55}
56
57
58void QSGNodeUpdater::enterTransformNode(QSGTransformNode *t)
59{
60#ifdef QSG_UPDATER_DEBUG
61 qDebug() << "enter transform:" << t << "force=" << m_force_update;
62#endif
63
64 if (!t->matrix().isIdentity()) {
65 if (!m_combined_matrix_stack.isEmpty()) {
66 t->setCombinedMatrix(*m_combined_matrix_stack.last() * t->matrix());
67 } else {
68 t->setCombinedMatrix(t->matrix());
69 }
70 m_combined_matrix_stack.add(t: &t->combinedMatrix());
71 } else {
72 if (!m_combined_matrix_stack.isEmpty()) {
73 t->setCombinedMatrix(*m_combined_matrix_stack.last());
74 } else {
75 t->setCombinedMatrix(QMatrix4x4());
76 }
77 }
78}
79
80
81void QSGNodeUpdater::leaveTransformNode(QSGTransformNode *t)
82{
83#ifdef QSG_UPDATER_DEBUG
84 qDebug() << "leave transform:" << t;
85#endif
86
87 if (!t->matrix().isIdentity()) {
88 m_combined_matrix_stack.pop_back();
89 }
90
91}
92
93
94void QSGNodeUpdater::enterClipNode(QSGClipNode *c)
95{
96#ifdef QSG_UPDATER_DEBUG
97 qDebug() << "enter clip:" << c;
98#endif
99
100 c->m_matrix = m_combined_matrix_stack.isEmpty() ? 0 : m_combined_matrix_stack.last();
101 c->m_clip_list = m_current_clip;
102 m_current_clip = c;
103}
104
105
106void QSGNodeUpdater::leaveClipNode(QSGClipNode *c)
107{
108#ifdef QSG_UPDATER_DEBUG
109 qDebug() << "leave clip:" << c;
110#endif
111
112 m_current_clip = c->m_clip_list;
113}
114
115
116void QSGNodeUpdater::enterGeometryNode(QSGGeometryNode *g)
117{
118#ifdef QSG_UPDATER_DEBUG
119 qDebug() << "enter geometry:" << g;
120#endif
121
122 g->m_matrix = m_combined_matrix_stack.isEmpty() ? 0 : m_combined_matrix_stack.last();
123 g->m_clip_list = m_current_clip;
124 g->setInheritedOpacity(m_opacity_stack.last());
125}
126
127void QSGNodeUpdater::leaveGeometryNode(QSGGeometryNode *g)
128{
129#ifdef QSG_UPDATER_DEBUG
130 qDebug() << "leave geometry" << g;
131#else
132 Q_UNUSED(g);
133#endif
134}
135
136void QSGNodeUpdater::enterRenderNode(QSGRenderNode *r)
137{
138#ifdef QSG_UPDATER_DEBUG
139 qDebug() << "enter render:" << r;
140#endif
141
142 QSGRenderNodePrivate *rd = QSGRenderNodePrivate::get(node: r);
143 rd->m_matrix = m_combined_matrix_stack.isEmpty() ? 0 : m_combined_matrix_stack.last();
144 rd->m_clip_list = m_current_clip;
145 rd->m_opacity = m_opacity_stack.last();
146}
147
148void QSGNodeUpdater::leaveRenderNode(QSGRenderNode *r)
149{
150#ifdef QSG_UPDATER_DEBUG
151 qDebug() << "leave render" << r;
152#else
153 Q_UNUSED(r);
154#endif
155}
156
157void QSGNodeUpdater::enterOpacityNode(QSGOpacityNode *o)
158{
159 qreal opacity = m_opacity_stack.last() * o->opacity();
160 o->setCombinedOpacity(opacity);
161 m_opacity_stack.add(t: opacity);
162
163#ifdef QSG_UPDATER_DEBUG
164 qDebug() << "enter opacity" << o;
165#endif
166}
167
168void QSGNodeUpdater::leaveOpacityNode(QSGOpacityNode *o)
169{
170#ifdef QSG_UPDATER_DEBUG
171 qDebug() << "leave opacity" << o;
172#endif
173 if (o->flags() & QSGNode::DirtyOpacity)
174 --m_force_update;
175
176 m_opacity_stack.pop_back();
177}
178
179void QSGNodeUpdater::visitChildren(QSGNode *n)
180{
181 for (QSGNode *c = n->firstChild(); c; c = c->nextSibling())
182 visitNode(n: c);
183}
184
185void QSGNodeUpdater::visitNode(QSGNode *n)
186{
187#ifdef QSG_UPDATER_DEBUG
188 qDebug() << "enter:" << n;
189#endif
190
191 if (!m_force_update)
192 return;
193 if (n->isSubtreeBlocked())
194 return;
195
196 switch (n->type()) {
197 case QSGNode::TransformNodeType: {
198 QSGTransformNode *t = static_cast<QSGTransformNode *>(n);
199 enterTransformNode(t);
200 visitChildren(n: t);
201 leaveTransformNode(t);
202 break; }
203 case QSGNode::GeometryNodeType: {
204 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(n);
205 enterGeometryNode(g);
206 visitChildren(n: g);
207 leaveGeometryNode(g);
208 break; }
209 case QSGNode::RenderNodeType: {
210 QSGRenderNode *r = static_cast<QSGRenderNode *>(n);
211 enterRenderNode(r);
212 visitChildren(n: r);
213 leaveRenderNode(r);
214 break; }
215 case QSGNode::ClipNodeType: {
216 QSGClipNode *c = static_cast<QSGClipNode *>(n);
217 enterClipNode(c);
218 visitChildren(n: c);
219 leaveClipNode(c);
220 break; }
221 case QSGNode::OpacityNodeType: {
222 QSGOpacityNode *o = static_cast<QSGOpacityNode *>(n);
223 enterOpacityNode(o);
224 visitChildren(n: o);
225 leaveOpacityNode(o);
226 break; }
227 default:
228 visitChildren(n);
229 break;
230 }
231}
232
233QT_END_NAMESPACE
234

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