Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
24int qt_sg_envInt(const char *name, int defaultValue)
25{
27 return defaultValue;
28 bool ok = false;
30 return ok ? value : defaultValue;
31}
32
62 : m_current_opacity(1)
63 , m_current_determinant(1)
64 , m_device_pixel_ratio(1)
65 , m_context(context)
66 , m_current_uniform_data(nullptr)
67 , m_current_resource_update_batch(nullptr)
68 , m_rhi(nullptr)
69 , m_node_updater(nullptr)
70 , m_changed_emitted(false)
71 , m_is_rendering(false)
72 , m_is_preprocessing(false)
73{
76}
77
78
80{
81 setRootNode(nullptr);
82 delete m_node_updater;
83}
84
93{
94 if (!m_node_updater)
95 const_cast<QSGRenderer *>(this)->m_node_updater = new QSGNodeUpdater();
96 return m_node_updater;
97}
98
99
107{
108 if (m_node_updater)
109 delete m_node_updater;
110 m_node_updater = updater;
111}
112
114{
116 // Mirrored relative to the usual Qt coordinate system with origin in the top left corner.
117 return matrix(0, 0) * matrix(1, 1) - matrix(0, 1) * matrix(1, 0) > 0;
118}
119
121{
122 if (!rootNode())
123 return;
124
125 Q_TRACE_SCOPE(QSG_renderScene);
126 m_is_rendering = true;
127
128 bool profileFrames = QSG_LOG_TIME_RENDERER().isDebugEnabled();
129 if (profileFrames)
130 frameTimer.start();
131 Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphRendererFrame);
132
133 // The QML Profiler architecture is extremely fragile: we have to record a
134 // hardcoded number of data points for each event, otherwise the view will
135 // show weird things in Creator. So record a dummy Binding data point, even
136 // though it is meaningless for our purposes.
137 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRendererFrame,
138 QQuickProfiler::SceneGraphRendererBinding);
139
140 qint64 renderTime = 0;
141
142 preprocess();
143
144 Q_TRACE(QSG_render_entry);
145 render();
146 if (profileFrames)
147 renderTime = frameTimer.nsecsElapsed();
148 Q_TRACE(QSG_render_exit);
149 Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRendererFrame,
150 QQuickProfiler::SceneGraphRendererRender);
151
152 m_is_rendering = false;
153 m_changed_emitted = false;
154
155 qCDebug(QSG_LOG_TIME_RENDERER,
156 "time in renderer: total=%dms, preprocess=%d, updates=%d, rendering=%d",
157 int(renderTime / 1000000),
158 int(preprocessTime / 1000000),
159 int((updatePassTime - preprocessTime) / 1000000),
160 int((renderTime - updatePassTime) / 1000000));
161}
162
164{
165 if (!rootNode())
166 return;
167
168 Q_ASSERT(!m_is_rendering);
169 m_is_rendering = true;
170
171 preprocess();
172
174}
175
177{
178 Q_ASSERT(m_is_rendering);
179
180 renderInline();
181
182 m_is_rendering = false;
183 m_changed_emitted = false;
184}
185
194void QSGRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state)
195{
201 if (node->flags() & QSGNode::UsePreprocess)
202 m_nodes_to_preprocess.insert(node);
203 else
204 m_nodes_to_preprocess.remove(node);
205 }
206
207 if (!m_changed_emitted && !m_is_rendering) {
208 // Premature overoptimization to avoid excessive signal emissions
209 m_changed_emitted = true;
211 }
212}
213
215{
216 Q_TRACE(QSG_preprocess_entry);
217
218 m_is_preprocessing = true;
219
220 QSGRootNode *root = rootNode();
221 Q_ASSERT(root);
222
223 // We need to take a copy here, in case any of the preprocess calls deletes a node that
224 // is in the preprocess list and thus, changes the m_nodes_to_preprocess behind our backs
225 // For the default case, when this does not happen, the cost is negligible.
226 QSet<QSGNode *> items = m_nodes_to_preprocess;
227
229
231 it != items.constEnd(); ++it) {
232 QSGNode *n = *it;
233
234 // If we are currently preprocessing, check this node hasn't been
235 // deleted or something. we don't want a use-after-free!
236 if (m_nodes_dont_preprocess.contains(n)) // skip
237 continue;
238 if (!nodeUpdater()->isNodeBlocked(n, root)) {
239 n->preprocess();
240 }
241 }
242
243 bool profileFrames = QSG_LOG_TIME_RENDERER().isDebugEnabled();
244 if (profileFrames)
245 preprocessTime = frameTimer.nsecsElapsed();
246 Q_TRACE(QSG_preprocess_exit);
247 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRendererFrame,
248 QQuickProfiler::SceneGraphRendererPreprocess);
249 Q_TRACE(QSG_update_entry);
250
251 nodeUpdater()->updateStates(root);
252
253 if (profileFrames)
254 updatePassTime = frameTimer.nsecsElapsed();
255 Q_TRACE(QSG_update_exit);
256 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRendererFrame,
257 QQuickProfiler::SceneGraphRendererUpdate);
258
259 m_is_preprocessing = false;
260 m_nodes_dont_preprocess.clear();
261}
262
263
264
266{
267 for (QSGNode *c = node->firstChild(); c; c = c->nextSibling())
269 if (node->flags() & QSGNode::UsePreprocess)
270 m_nodes_to_preprocess.insert(node);
271}
272
274{
275 for (QSGNode *c = node->firstChild(); c; c = c->nextSibling())
277 if (node->flags() & QSGNode::UsePreprocess) {
278 m_nodes_to_preprocess.remove(node);
279
280 // If preprocessing *now*, mark the node as gone.
281 if (m_is_preprocessing)
282 m_nodes_dont_preprocess.insert(node);
283 }
284}
285
289
293
294
305{
307 dump.visitNode(n);
308}
309
311{
312 qDebug() << QByteArray(m_indent * 2, ' ').constData() << n;
314}
315
317{
318 ++m_indent;
320 --m_indent;
321}
322
323
\inmodule QtCore
const_iterator constBegin() const noexcept
Definition qlist.h:632
const_iterator constEnd() const noexcept
Definition qlist.h:633
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
QSGRootNode * rootNode() const
Returns the root of the QSGNode scene.
QMatrix4x4 projectionMatrix(int index) const
Returns the projection matrix.
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:1418
virtual void visitNode(QSGNode *n)
Definition qsgnode.cpp:1385
\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.
QVarLengthArray< QMatrix4x4, 1 > m_current_projection_matrix_native_ndc
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
QVarLengthArray< QMatrix4x4, 1 > m_current_projection_matrix
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:259
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
void resize(qsizetype sz)
QSet< QString >::iterator it
else opt state
[0]
Combined button and popup list for selecting options.
static void * context
#define Q_LIKELY(x)
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qDebug
[1]
Definition qlogging.h:164
#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)
static QT_BEGIN_NAMESPACE QElapsedTimer frameTimer
static qint64 preprocessTime
static qint64 updatePassTime
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:60
QObject::connect nullptr
QList< QTreeWidgetItem * > items