Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qsgrenderer.cpp
Go to the documentation of this file.
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 "qsgrenderer_p.h"
5#include "qsgnodeupdater_p.h"
6#include <private/qquickprofiler_p.h>
7#include <qtquick_tracepoints_p.h>
8
9#include <QtCore/QElapsedTimer>
10
12
16
17Q_TRACE_POINT(qtquick, QSG_preprocess_entry)
18Q_TRACE_POINT(qtquick, QSG_preprocess_exit)
19Q_TRACE_POINT(qtquick, QSG_update_entry)
20Q_TRACE_POINT(qtquick, QSG_update_exit)
21Q_TRACE_POINT(qtquick, QSG_renderScene_entry)
22Q_TRACE_POINT(qtquick, QSG_renderScene_exit)
23
24#ifndef QT_NO_DEBUG
26#endif
27
28int qt_sg_envInt(const char *name, int defaultValue)
29{
31 return defaultValue;
32 bool ok = false;
34 return ok ? value : defaultValue;
35}
36
66 : m_current_opacity(1)
67 , m_current_determinant(1)
68 , m_device_pixel_ratio(1)
69 , m_context(context)
70 , m_current_uniform_data(nullptr)
71 , m_current_resource_update_batch(nullptr)
72 , m_rhi(nullptr)
73 , m_node_updater(nullptr)
74 , m_changed_emitted(false)
75 , m_is_rendering(false)
76 , m_is_preprocessing(false)
77{
78}
79
80
82{
83 setRootNode(nullptr);
84 delete m_node_updater;
85}
86
95{
96 if (!m_node_updater)
97 const_cast<QSGRenderer *>(this)->m_node_updater = new QSGNodeUpdater();
98 return m_node_updater;
99}
100
101
109{
110 if (m_node_updater)
111 delete m_node_updater;
112 m_node_updater = updater;
113}
114
116{
118 // Mirrored relative to the usual Qt coordinate system with origin in the top left corner.
119 return matrix(0, 0) * matrix(1, 1) - matrix(0, 1) * matrix(1, 0) > 0;
120}
121
123{
124 if (!rootNode())
125 return;
126
127 Q_TRACE_SCOPE(QSG_renderScene);
128 m_is_rendering = true;
129
130 bool profileFrames = QSG_LOG_TIME_RENDERER().isDebugEnabled();
131 if (profileFrames)
133 Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphRendererFrame);
134
135 // The QML Profiler architecture is extremely fragile: we have to record a
136 // hardcoded number of data points for each event, otherwise the view will
137 // show weird things in Creator. So record a dummy Binding data point, even
138 // though it is meaningless for our purposes.
139 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRendererFrame,
140 QQuickProfiler::SceneGraphRendererBinding);
141
142 qint64 renderTime = 0;
143
144 preprocess();
145
146 Q_TRACE(QSG_render_entry);
147 render();
148 if (profileFrames)
149 renderTime = frameTimer.nsecsElapsed();
150 Q_TRACE(QSG_render_exit);
151 Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRendererFrame,
152 QQuickProfiler::SceneGraphRendererRender);
153
154 m_is_rendering = false;
155 m_changed_emitted = false;
156
157 qCDebug(QSG_LOG_TIME_RENDERER,
158 "time in renderer: total=%dms, preprocess=%d, updates=%d, rendering=%d",
159 int(renderTime / 1000000),
160 int(preprocessTime / 1000000),
161 int((updatePassTime - preprocessTime) / 1000000),
162 int((renderTime - updatePassTime) / 1000000));
163}
164
166{
167 if (!rootNode())
168 return;
169
170 Q_ASSERT(!m_is_rendering);
171 m_is_rendering = true;
172
173 preprocess();
174
176}
177
179{
180 Q_ASSERT(m_is_rendering);
181
182 renderInline();
183
184 m_is_rendering = false;
185 m_changed_emitted = false;
186}
187
196void QSGRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state)
197{
203 if (node->flags() & QSGNode::UsePreprocess)
204 m_nodes_to_preprocess.insert(node);
205 else
206 m_nodes_to_preprocess.remove(node);
207 }
208
209 if (!m_changed_emitted && !m_is_rendering) {
210 // Premature overoptimization to avoid excessive signal emissions
211 m_changed_emitted = true;
213 }
214}
215
217{
218 Q_TRACE(QSG_preprocess_entry);
219
220 m_is_preprocessing = true;
221
222 QSGRootNode *root = rootNode();
223 Q_ASSERT(root);
224
225 // We need to take a copy here, in case any of the preprocess calls deletes a node that
226 // is in the preprocess list and thus, changes the m_nodes_to_preprocess behind our backs
227 // For the default case, when this does not happen, the cost is negligible.
228 QSet<QSGNode *> items = m_nodes_to_preprocess;
229
231
233 it != items.constEnd(); ++it) {
234 QSGNode *n = *it;
235
236 // If we are currently preprocessing, check this node hasn't been
237 // deleted or something. we don't want a use-after-free!
238 if (m_nodes_dont_preprocess.contains(n)) // skip
239 continue;
240 if (!nodeUpdater()->isNodeBlocked(n, root)) {
241 n->preprocess();
242 }
243 }
244
245 bool profileFrames = QSG_LOG_TIME_RENDERER().isDebugEnabled();
246 if (profileFrames)
248 Q_TRACE(QSG_preprocess_exit);
249 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRendererFrame,
250 QQuickProfiler::SceneGraphRendererPreprocess);
251 Q_TRACE(QSG_update_entry);
252
253 nodeUpdater()->updateStates(root);
254
255 if (profileFrames)
257 Q_TRACE(QSG_update_exit);
258 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRendererFrame,
259 QQuickProfiler::SceneGraphRendererUpdate);
260
261 m_is_preprocessing = false;
262 m_nodes_dont_preprocess.clear();
263}
264
265
266
268{
269 for (QSGNode *c = node->firstChild(); c; c = c->nextSibling())
271 if (node->flags() & QSGNode::UsePreprocess)
272 m_nodes_to_preprocess.insert(node);
273}
274
276{
277 for (QSGNode *c = node->firstChild(); c; c = c->nextSibling())
279 if (node->flags() & QSGNode::UsePreprocess) {
280 m_nodes_to_preprocess.remove(node);
281
282 // If preprocessing *now*, mark the node as gone.
283 if (m_is_preprocessing)
284 m_nodes_dont_preprocess.insert(node);
285 }
286}
287
289{
290}
291
293{
294}
295
296
307{
309 dump.visitNode(n);
310}
311
313{
314 qDebug() << QByteArray(m_indent * 2, ' ').constData() << n;
316}
317
319{
320 ++m_indent;
322 --m_indent;
323}
324
325
\inmodule QtCore
Definition qbytearray.h:57
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
\inmodule QtCore
void start() noexcept
Starts this timer.
qint64 nsecsElapsed() const noexcept
const_iterator constBegin() const noexcept
Definition qlist.h:615
const_iterator constEnd() const noexcept
Definition qlist.h:616
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
QMatrix4x4 projectionMatrix() const
Returns the projection matrix.
QSGRootNode * rootNode() const
Returns the root of the QSGNode scene.
void sceneGraphChanged()
This signal is emitted on the first modification of a node in the tree after the last scene render.
void setRootNode(QSGRootNode *node)
Sets the node as the root of the QSGNode scene that you want to render.
The QSGNodeDumper class provides a way of dumping a scene grahp to the console.
void visitNode(QSGNode *n) override
static void dump(QSGNode *n)
void visitChildren(QSGNode *n) override
virtual bool isNodeBlocked(QSGNode *n, QSGNode *root) const
Returns true if node is has something that blocks it in the chain from node to root doing a full stat...
virtual void updateStates(QSGNode *n)
virtual void visitChildren(QSGNode *n)
Definition qsgnode.cpp:1416
virtual void visitNode(QSGNode *n)
Definition qsgnode.cpp:1383
\group qtquick-scenegraph-nodes \title Qt Quick Scene Graph Node classes
Definition qsgnode.h:37
Flags flags() const
Returns the set of flags for this node.
Definition qsgnode.h:118
@ DirtyNodeAdded
Definition qsgnode.h:72
@ DirtyNodeRemoved
Definition qsgnode.h:73
@ DirtyUsePreprocess
Definition qsgnode.h:80
@ UsePreprocess
Definition qsgnode.h:52
QSGNode * firstChild() const
Returns the first child of this node.
Definition qsgnode.h:105
virtual void preprocess()
Do necessary preprocessing before the frame.
The renderer class is the abstract baseclass used for rendering the QML scene graph.
virtual void render()=0
virtual void preprocess()
void renderSceneInline() override
void removeNodesToPreprocess(QSGNode *node)
virtual ~QSGRenderer()
QSGRenderer(QSGRenderContext *context)
void setNodeUpdater(QSGNodeUpdater *updater)
Sets the node updater that this renderer uses to update states in the scene graph.
void nodeChanged(QSGNode *node, QSGNode::DirtyState state) override
Updates internal data structures and emits the sceneGraphChanged() signal.
virtual void renderInline()
void addNodesToPreprocess(QSGNode *node)
QSGRenderContext * m_context
bool isMirrored() const
void renderScene() override
Renders the scene.
void prepareSceneInline() override
virtual void prepareInline()
QSGNodeUpdater * nodeUpdater() const
Returns the node updater that this renderer uses to update states in the scene graph.
The QSGRootNode is the toplevel root of any scene graph.
Definition qsgnode.h:262
Definition qset.h:18
bool remove(const T &value)
Definition qset.h:63
void clear()
Definition qset.h:61
bool contains(const T &value) const
Definition qset.h:71
iterator insert(const T &value)
Definition qset.h:155
QSet< QString >::iterator it
else opt state
[0]
Combined button and popup list for selecting options.
static void * context
#define Q_LIKELY(x)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qDebug
[1]
Definition qlogging.h:160
#define qCDebug(category,...)
GLuint name
GLfloat n
const GLubyte * c
GLuint GLenum matrix
#define Q_QUICK_SG_PROFILE_END(Type, position)
#define Q_QUICK_SG_PROFILE_RECORD(Type, position)
#define Q_QUICK_SG_PROFILE_START(Type)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
int qt_sg_envInt(const char *name, int defaultValue)
bool _q_sg_leak_check
static QT_BEGIN_NAMESPACE QElapsedTimer frameTimer
static qint64 preprocessTime
static qint64 updatePassTime
Q_CORE_EXPORT bool qEnvironmentVariableIsEmpty(const char *varName) noexcept
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
#define emit
#define Q_TRACE_SCOPE(x,...)
Definition qtrace_p.h:146
#define Q_TRACE(x,...)
Definition qtrace_p.h:144
#define Q_TRACE_POINT(provider, tracepoint,...)
Definition qtrace_p.h:232
long long qint64
Definition qtypes.h:55
QObject::connect nullptr
QList< QTreeWidgetItem * > items