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
qsgcontext.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 <QtQuick/private/qsgcontext_p.h>
5#include <QtQuick/private/qsgtexture_p.h>
6#include <QtQuick/private/qsgrenderer_p.h>
7#include <QtQuick/private/qquickpixmap_p.h>
8#include <QtQuick/private/qsgadaptationlayer_p.h>
9#include <QtQuick/private/qsginternaltextnode_p.h>
10
11#include <QGuiApplication>
12#include <QScreen>
13#include <QQuickWindow>
14
15#include <private/qqmlglobal_p.h>
16
17#include <QtQuick/private/qsgtexture_p.h>
18#include <QtGui/private/qguiapplication_p.h>
19#include <QtCore/private/qabstractanimation_p.h>
20
21#include <private/qobject_p.h>
22#include <qmutex.h>
23
24/*
25 Comments about this class from Gunnar:
26
27 The QSGContext class is right now two things.. The first is the
28 adaptation layer and central storage ground for all the things
29 in the scene graph, like textures and materials. This part really
30 belongs inside the scene graph coreapi.
31
32 The other part is the QML adaptation classes, like how to implement
33 rectangle nodes. This is not part of the scene graph core API, but
34 more part of the QML adaptation of scene graph.
35
36 If we ever move the scene graph core API into its own thing, this class
37 needs to be split in two. Right now its one because we're lazy when it comes
38 to defining plugin interfaces..
39*/
40
42
43// Used for very high-level info about the renderering and gl context
44// Includes GL_VERSION, type of render loop, atlas size, etc.
45Q_LOGGING_CATEGORY(QSG_LOG_INFO, "qt.scenegraph.general")
46
47// Used to debug the renderloop logic. Primarily useful for platform integrators
48// and when investigating the render loop logic.
49Q_LOGGING_CATEGORY(QSG_LOG_RENDERLOOP, "qt.scenegraph.renderloop")
50
51
52// GLSL shader compilation
53Q_LOGGING_CATEGORY(QSG_LOG_TIME_COMPILATION, "qt.scenegraph.time.compilation")
54
55// polish, animations, sync, render and swap in the render loop
56Q_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERLOOP, "qt.scenegraph.time.renderloop")
57
58// Texture uploads and swizzling
59Q_LOGGING_CATEGORY(QSG_LOG_TIME_TEXTURE, "qt.scenegraph.time.texture")
60
61// Glyph preparation (only for distance fields atm)
62Q_LOGGING_CATEGORY(QSG_LOG_TIME_GLYPH, "qt.scenegraph.time.glyph")
63
64// Timing inside the renderer base class
65Q_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERER, "qt.scenegraph.time.renderer")
66
67// Leak checks
68Q_LOGGING_CATEGORY(lcQsgLeak, "qt.scenegraph.leaks")
69
70// Applicable for render loops that install their own animation driver, such as
71// the 'threaded' loop. This env.var. is documented in the scenegraph docs.
72DEFINE_BOOL_CONFIG_OPTION(useElapsedTimerBasedAnimationDriver, QSG_USE_SIMPLE_ANIMATION_DRIVER);
73
75{
76 int use = -1;
77 if (use < 0) {
78 use = !qEnvironmentVariableIsEmpty("QSG_FIXED_ANIMATION_STEP") && qgetenv("QSG_FIXED_ANIMATION_STEP") != "no"
79 ? 1 : 0;
80 qCDebug(QSG_LOG_INFO, "Using %s", bool(use) ? "fixed animation steps" : "sg animation driver");
81 }
82 return bool(use);
83}
84
86{
87public:
90 {
92 if (screen) {
93 qreal refreshRate = screen->refreshRate();
94 // To work around that some platforms wrongfully return 0 or something
95 // bogus for the refresh rate.
96 if (refreshRate < 1)
97 refreshRate = 60;
98 m_vsync = 1000.0f / float(refreshRate);
99 } else {
100 m_vsync = 16.67f;
101 }
102 }
103
104 float vsyncInterval() const { return m_vsync; }
105
106 virtual bool isVSyncDependent() const = 0;
107
108protected:
109 float m_vsync = 0;
110};
111
112// default as in default for the threaded render loop
114{
116public:
121
124 , m_time(0)
126 , m_lag(0)
127 , m_bad(0)
128 , m_good(0)
129 {
132 if (m_vsync <= 0)
134 } else {
137 QUnifiedTimer::instance(true)->setConsistentTiming(true);
138 }
139 if (m_mode == VSyncMode)
140 qCDebug(QSG_LOG_INFO, "Animation Driver: using vsync: %.2f ms", m_vsync);
141 else
142 qCDebug(QSG_LOG_INFO, "Animation Driver: using walltime");
143 }
144
145 void start() override
146 {
147 m_time = 0;
148 m_timer.start();
151 }
152
153 qint64 elapsed() const override
154 {
155 return m_mode == VSyncMode
156 ? qint64(m_time)
158 }
159
160 void advance() override
161 {
162 qint64 delta = m_timer.restart();
163
164 if (m_mode == VSyncMode) {
165 // If a frame is skipped, either because rendering was slow or because
166 // the QML was slow, we accept it and continue advancing with a single
167 // vsync tick. The reason for this is that by the time we notice this
168 // on the GUI thread, the temporal distortion has already gone to screen
169 // and by catching up, we will introduce a second distortion which will
170 // worse. We accept that the animation time falls behind wall time because
171 // it comes out looking better.
172 // Only when multiple bad frames are hit in a row, do we consider
173 // switching. A few really bad frames and we switch right away. For frames
174 // just above the vsync delta, we tolerate a bit more since a buffered
175 // driver can have vsync deltas on the form: 4, 21, 21, 2, 23, 16, and
176 // still manage to put the frames to screen at 16 ms intervals. In addition
177 // to that, we tolerate a 25% margin of error on the value of m_vsync
178 // reported from the system as this value is often not precise.
179
180 m_time += m_vsync;
181
182 if (delta > m_vsync * 1.25f) {
183 m_lag += (delta / m_vsync);
184 m_bad++;
185 // We tolerate one bad frame without resorting to timer based. This is
186 // done to cope with a slow loader frame followed by smooth animation.
187 // However, on the second frame with massive lag, we switch.
188 if (m_lag > 10 && m_bad > 2) {
190 qCDebug(QSG_LOG_INFO, "animation driver switched to timer mode");
192 }
193 } else {
194 m_lag = 0;
195 m_bad = 0;
196 }
197
198 } else {
199 if (delta < 1.25f * m_vsync) {
200 ++m_good;
201 } else {
202 m_good = 0;
203 }
204
205 // We've been solid for a while, switch back to vsync mode. Tolerance
206 // for switching back is lower than switching to timer mode, as we
207 // want to stay in vsync mode as much as possible.
208 if (m_good > 10 && !qsg_useConsistentTiming()) {
209 m_time = elapsed();
211 m_bad = 0;
212 m_lag = 0;
213 qCDebug(QSG_LOG_INFO, "animation driver switched to vsync mode");
214 }
215 }
216
218 }
219
220 bool isVSyncDependent() const override
221 {
222 return true;
223 }
224
225 double m_time;
229 float m_lag;
230 int m_bad;
232};
233
234// Advance based on QElapsedTimer. (so like the TimerMode of QSGDefaultAnimationDriver)
235// Does not depend on vsync-based throttling.
236//
237// NB this is not the same as not installing a QAnimationDriver: the built-in
238// approach in QtCore is to rely on 16 ms timer events which are potentially a
239// lot less accurate.
240//
241// This has the benefits of:
242// - not needing any of the infrastructure for falling back to a
243// QTimer when there are multiple windows,
244// - needing no heuristics trying determine if vsync-based throttling
245// is missing or broken,
246// - being compatible with any kind of temporal drifts in vsync throttling
247// which is reportedly happening in various environments and platforms
248// still,
249// - not being tied to the primary screen's refresh rate, i.e. this is
250// correct even if the window is on some secondary screen with a
251// different refresh rate,
252// - not having to worry about the potential effects of variable refresh
253// rate solutions,
254// - render thread animators work correctly regardless of vsync.
255//
256// On the downside, some animations might appear less smooth (compared to the
257// ideal single window case of QSGDefaultAnimationDriver).
258//
260{
261public:
264 {
265 qCDebug(QSG_LOG_INFO, "Animation Driver: using QElapsedTimer, thread %p %s",
267 QThread::currentThread() == qGuiApp->thread() ? "(gui/main thread)" : "(render thread)");
268 }
269
270 void start() override
271 {
272 m_wallTime.restart();
274 }
275
276 qint64 elapsed() const override
277 {
278 return m_wallTime.elapsed();
279 }
280
281 void advance() override
282 {
284 }
285
286 bool isVSyncDependent() const override
287 {
288 return false;
289 }
290
291private:
292 QElapsedTimer m_wallTime;
293};
294
296{
297 QFontEngine *fe = QRawFontPrivate::get(font)->fontEngine;
298 if (fe != nullptr)
299 faceId = fe->faceId();
300 style = font.style();
301 weight = font.weight();
302 renderTypeQuality = quality;
303 if (faceId.filename.isEmpty()) {
304 familyName = font.familyName();
306 }
307}
308
324
328
332
336
337
342{
344 node->setRect(rect);
345 node->setColor(c);
346 node->update();
347 return node;
348}
349
351{
352 return new QSGInternalTextNode(renderContext);
353}
354
356{
357 return createInternalTextNode(renderContext);
358}
359
369
379
384{
385 if (useElapsedTimerBasedAnimationDriver())
387
389}
390
396{
397 return static_cast<QSGAnimationDriver *>(driver)->vsyncInterval();
398}
399
404{
405 return static_cast<QSGAnimationDriver *>(driver)->isVSyncDependent();
406}
407
409{
410 return QSize(1, 1);
411}
412
428{
429 Q_UNUSED(renderContext);
430 qWarning("QSGRendererInterface not implemented");
431 return nullptr;
432}
433
438
442
447
451
455{
456 Q_UNUSED(devicePixelRatio);
457 Q_UNUSED(cb);
459}
460
462 RenderPassCallback mainPassRecordingStart,
463 RenderPassCallback mainPassRecordingEnd,
464 void *callbackUserData)
465{
466 renderer->setRenderTarget(renderTarget);
467 Q_UNUSED(mainPassRecordingStart);
468 Q_UNUSED(mainPassRecordingEnd);
469 Q_UNUSED(callbackUserData);
470}
471
476
482
489
499
507
512
518
524
526{
527 return nullptr;
528}
529
557
564
578
580
581#include "qsgcontext.moc"
582#include "moc_qsgcontext_p.cpp"
\inmodule QtCore
void advanceAnimation()
Advances the animation.
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:107
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
\inmodule QtCore
qint64 elapsed() const noexcept
Returns the number of milliseconds since this QElapsedTimer was last started.
qint64 restart() noexcept
Restarts the timer and returns the number of milliseconds elapsed since the previous start.
void start() noexcept
\typealias QElapsedTimer::Duration Synonym for std::chrono::nanoseconds.
QString styleName() const
Definition qfont.cpp:849
Weight weight() const
Returns the weight of the font, using the same scale as the \l{QFont::Weight} enumeration.
Definition qfont.cpp:1133
Style style() const
Returns the style of the font.
Definition qfont.cpp:1105
QScreen * primaryScreen
the primary (or default) screen of the application.
T take(const Key &key)
Removes the item with the key from the hash and returns the value associated with it.
Definition qhash.h:985
T value(const Key &key) const noexcept
Definition qhash.h:1054
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
void unlock() noexcept
Unlocks the mutex.
Definition qmutex.h:289
void lock() noexcept
Locks the mutex.
Definition qmutex.h:286
\inmodule QtCore
Definition qobject.h:103
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
QQuickGraphicsConfiguration controls lower level graphics settings for the QQuickWindow.
The QQuickTextureFactory class provides an interface for loading custom textures from QML....
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
static QRawFontPrivate * get(const QRawFont &font)
Definition qrawfont_p.h:104
The QRawFont class provides access to a single physical instance of a font.
Definition qrawfont.h:24
\inmodule QtCore\reentrant
Definition qrect.h:484
\inmodule QtGui
Definition qrhi.h:1651
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:1804
QSGAnimationDriver(QObject *parent)
float vsyncInterval() const
virtual bool isVSyncDependent() const =0
The QSGContext holds the scene graph entry points for one QML engine.
virtual void renderContextInitialized(QSGRenderContext *renderContext)
virtual QSGInternalTextNode * createInternalTextNode(QSGRenderContext *renderContext)
virtual float vsyncIntervalForAnimationDriver(QAnimationDriver *driver)
virtual QSGShaderEffectNode * createShaderEffectNode(QSGRenderContext *renderContext)
Creates a new shader effect node.
virtual bool isVSyncDependent(QAnimationDriver *driver)
~QSGContext() override
virtual QSGRendererInterface * rendererInterface(QSGRenderContext *renderContext)
Returns a pointer to the (presumably) global renderer interface.
virtual QSGInternalRectangleNode * createInternalRectangleNode()=0
virtual QAnimationDriver * createAnimationDriver(QObject *parent)
Creates a new animation driver.
virtual QSGTextNode * createTextNode(QSGRenderContext *renderContext)
QSGContext(QObject *parent=nullptr)
virtual QSGGuiThreadShaderEffectManager * createGuiThreadShaderEffectManager()
Creates a new shader effect helper instance.
virtual QSize minimumFBOSize() const
virtual void renderContextInvalidated(QSGRenderContext *renderContext)
qint64 elapsed() const override
Returns the number of milliseconds since the animations was started.
void advance() override
Advances the animation.
QSGDefaultAnimationDriver(QObject *parent)
bool isVSyncDependent() const override
QSGElapsedTimerAnimationDriver(QObject *parent)
bool isVSyncDependent() const override
qint64 elapsed() const override
Returns the number of milliseconds since the animations was started.
void advance() override
Advances the animation.
virtual void setRect(const QRectF &rect)=0
virtual void update()=0
virtual void setColor(const QColor &color)=0
void registerFontengineForCleanup(QFontEngine *engine)
QSGRenderContext(QSGContext *context)
QHash< QObject *, QSGTexture * > m_textures
virtual void endNextFrame(QSGRenderer *renderer)
QHash< QFontEngine *, int > m_fontEnginesToClean
virtual void initialize(const InitParams *params)
virtual void beginNextFrame(QSGRenderer *renderer, const QSGRenderTarget &renderTarget, RenderPassCallback mainPassRecordingStart, RenderPassCallback mainPassRecordingEnd, void *callbackUserData)
void textureFactoryDestroyed(QObject *o)
virtual void invalidateGlyphCaches()
virtual QSGDistanceFieldGlyphCache * distanceFieldGlyphCache(const QRawFont &font, int renderTypeQuality)
Factory function for scene graph backends of the distance-field glyph cache.
virtual void invalidate()
virtual void endSync()
void(*)(void *) RenderPassCallback
virtual QSGCurveGlyphAtlas * curveGlyphAtlas(const QRawFont &font)
Factory function for curve atlases that can be used to provide geometry for the curve renderer for a ...
virtual void preprocess()
Do necessary preprocessing before the frame.
virtual QRhi * rhi() const
void unregisterFontengineForCleanup(QFontEngine *engine)
virtual void prepareSync(qreal devicePixelRatio, QRhiCommandBuffer *cb, const QQuickGraphicsConfiguration &config)
QSGTexture * textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window)
Factory function for the scene graph renderers.
~QSGRenderContext() override
virtual QSGTexture * compressedTextureForFactory(const QSGCompressedTextureFactory *) const
Return the texture corresponding to a texture factory.
QSet< QSGTexture * > m_texturesToDelete
An interface providing access to some of the graphics API specific internals of the scenegraph.
The renderer class is the abstract baseclass used for rendering the QML scene graph.
The QSGTextNode class is a class for drawing text layouts and text documents in the Qt Quick scene gr...
Definition qsgtextnode.h:14
\inmodule QtQuick
Definition qsgtexture.h:20
The QScreen class is used to query screen properties. \inmodule QtGui.
Definition qscreen.h:32
qreal refreshRate
the approximate vertical refresh rate of the screen in Hz
Definition qscreen.h:64
void clear()
Definition qset.h:61
\inmodule QtCore
Definition qsize.h:25
static QThread * currentThread()
Definition qthread.cpp:1039
static QUnifiedTimer * instance()
qDeleteAll(list.begin(), list.end())
rect
[4]
Combined button and popup list for selecting options.
@ DirectConnection
static void * context
EGLConfig config
#define qGuiApp
#define qWarning
Definition qlogging.h:166
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLuint GLuint GLfloat weight
GLenum GLuint texture
void ** params
const GLubyte * c
#define DEFINE_BOOL_CONFIG_OPTION(name, var)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
bool qsg_useConsistentTiming()
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
QScreen * screen
[1]
Definition main.cpp:29
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CORE_EXPORT bool qEnvironmentVariableIsEmpty(const char *varName) noexcept
#define Q_OBJECT
#define Q_UNUSED(x)
long long qint64
Definition qtypes.h:60
double qreal
Definition qtypes.h:187
QItemEditorFactory * factory
aWidget window() -> setWindowTitle("New Window Title")
[2]
QJSEngine engine
[0]
QSvgRenderer * renderer
[0]
FontKey(const QRawFont &font, int renderTypeQuality)
QFontEngine::FaceId faceId