Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
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
// Qt-Security score:significant reason:default
4
5
#
include
<
QtQuick
/
private
/
qsgcontext_p
.
h
>
6
#
include
<
QtQuick
/
private
/
qsgtexture_p
.
h
>
7
#
include
<
QtQuick
/
private
/
qsgrenderer_p
.
h
>
8
#
include
<
QtQuick
/
private
/
qquickpixmap_p
.
h
>
9
#
include
<
QtQuick
/
private
/
qsgadaptationlayer_p
.
h
>
10
#
include
<
QtQuick
/
private
/
qsginternaltextnode_p
.
h
>
11
12
#
include
<
QGuiApplication
>
13
#
include
<
QScreen
>
14
#
include
<
QQuickWindow
>
15
16
#
include
<
private
/
qqmlglobal_p
.
h
>
17
18
#
include
<
QtQuick
/
private
/
qsgtexture_p
.
h
>
19
#
include
<
QtGui
/
private
/
qguiapplication_p
.
h
>
20
#
include
<
QtCore
/
private
/
qabstractanimation_p
.
h
>
21
22
#
include
<
private
/
qobject_p
.
h
>
23
#
include
<
qmutex
.
h
>
24
25
/*
26
Comments about this class from Gunnar:
27
28
The QSGContext class is right now two things.. The first is the
29
adaptation layer and central storage ground for all the things
30
in the scene graph, like textures and materials. This part really
31
belongs inside the scene graph coreapi.
32
33
The other part is the QML adaptation classes, like how to implement
34
rectangle nodes. This is not part of the scene graph core API, but
35
more part of the QML adaptation of scene graph.
36
37
If we ever move the scene graph core API into its own thing, this class
38
needs to be split in two. Right now its one because we're lazy when it comes
39
to defining plugin interfaces..
40
*/
41
42
QT_BEGIN_NAMESPACE
43
44
// Used for very high-level info about the renderering and gl context
45
// Includes GL_VERSION, type of render loop, atlas size, etc.
46
Q_LOGGING_CATEGORY(QSG_LOG_INFO,
"qt.scenegraph.general"
)
47
48
// Used to debug the renderloop logic. Primarily useful for platform integrators
49
// and when investigating the render loop logic.
50
Q_LOGGING_CATEGORY(QSG_LOG_RENDERLOOP,
"qt.scenegraph.renderloop"
)
51
52
53
// GLSL shader compilation
54
Q_LOGGING_CATEGORY(QSG_LOG_TIME_COMPILATION,
"qt.scenegraph.time.compilation"
)
55
56
// polish, animations, sync, render and swap in the render loop
57
Q_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERLOOP,
"qt.scenegraph.time.renderloop"
)
58
59
// Texture uploads and swizzling
60
Q_LOGGING_CATEGORY(QSG_LOG_TIME_TEXTURE,
"qt.scenegraph.time.texture"
)
61
62
// Glyph preparation (only for distance fields atm)
63
Q_LOGGING_CATEGORY(QSG_LOG_TIME_GLYPH,
"qt.scenegraph.time.glyph"
)
64
65
// Timing inside the renderer base class
66
Q_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERER,
"qt.scenegraph.time.renderer"
)
67
68
// Leak checks
69
Q_LOGGING_CATEGORY(lcQsgLeak,
"qt.scenegraph.leaks"
)
70
71
// Applicable for render loops that install their own animation driver, such as
72
// the 'threaded' loop. This env.var. is documented in the scenegraph docs.
73
DEFINE_BOOL_CONFIG_OPTION(useElapsedTimerBasedAnimationDriver, QSG_USE_SIMPLE_ANIMATION_DRIVER);
74
75
bool
qsg_useConsistentTiming
()
76
{
77
static
int
use = -1;
78
if
(use < 0) {
79
use = !qEnvironmentVariableIsEmpty(
"QSG_FIXED_ANIMATION_STEP"
) && qgetenv(
"QSG_FIXED_ANIMATION_STEP"
) !=
"no"
80
? 1 : 0;
81
qCDebug(QSG_LOG_INFO,
"Using %s"
,
bool
(use) ?
"fixed animation steps"
:
"sg animation driver"
);
82
}
83
return
bool
(use);
84
}
85
86
class
QSGAnimationDriver
:
public
QAnimationDriver
87
{
88
public
:
89
QSGAnimationDriver
(QObject *parent)
90
:
QAnimationDriver
(
parent
)
91
{
92
QScreen *screen = QGuiApplication::primaryScreen();
93
if
(screen) {
94
qreal refreshRate = screen->refreshRate();
95
// To work around that some platforms wrongfully return 0 or something
96
// bogus for the refresh rate.
97
if
(refreshRate < 1)
98
refreshRate = 60;
99
m_vsync
= 1000.0f /
float
(refreshRate);
100
}
else
{
101
m_vsync
= 16.67f;
102
}
103
}
104
105
float
vsyncInterval
()
const
{
return
m_vsync
; }
106
107
virtual
bool
isVSyncDependent
()
const
= 0;
108
109
protected
:
110
float
m_vsync
= 0;
111
};
112
113
// default as in default for the threaded render loop
114
class
QSGDefaultAnimationDriver
:
public
QSGAnimationDriver
115
{
116
Q_OBJECT
117
public
:
118
enum
Mode
{
119
VSyncMode
,
120
TimerMode
121
};
122
123
QSGDefaultAnimationDriver
(QObject *parent)
124
:
QSGAnimationDriver
(parent)
125
,
m_time
(0)
126
,
m_mode
(
VSyncMode
)
127
,
m_lag
(0)
128
,
m_bad
(0)
129
,
m_good
(0)
130
{
131
QScreen *screen = QGuiApplication::primaryScreen();
132
if
(screen && !
qsg_useConsistentTiming
(
)
) {
133
if
(m_vsync <= 0)
134
m_mode = TimerMode;
135
}
else
{
136
m_mode = TimerMode;
137
if
(qsg_useConsistentTiming())
138
QUnifiedTimer::instance(
true
)->setConsistentTiming(
true
);
139
}
140
if
(m_mode == VSyncMode)
141
qCDebug(QSG_LOG_INFO,
"Animation Driver: using vsync: %.2f ms"
, m_vsync);
142
else
143
qCDebug(QSG_LOG_INFO,
"Animation Driver: using walltime"
);
144
}
145
146
void
start
()
override
147
{
148
m_time
= 0;
149
m_timer.start();
150
m_wallTime.start();
151
QAnimationDriver::start();
152
}
153
154
qint64
elapsed
()
const
override
155
{
156
return
m_mode == VSyncMode
157
? qint64(m_time)
158
: qint64(m_time) + m_wallTime.elapsed();
159
}
160
161
void
advance
()
override
162
{
163
qint64 delta = m_timer.restart();
164
165
if
(m_mode == VSyncMode) {
166
// If a frame is skipped, either because rendering was slow or because
167
// the QML was slow, we accept it and continue advancing with a single
168
// vsync tick. The reason for this is that by the time we notice this
169
// on the GUI thread, the temporal distortion has already gone to screen
170
// and by catching up, we will introduce a second distortion which will
171
// worse. We accept that the animation time falls behind wall time because
172
// it comes out looking better.
173
// Only when multiple bad frames are hit in a row, do we consider
174
// switching. A few really bad frames and we switch right away. For frames
175
// just above the vsync delta, we tolerate a bit more since a buffered
176
// driver can have vsync deltas on the form: 4, 21, 21, 2, 23, 16, and
177
// still manage to put the frames to screen at 16 ms intervals. In addition
178
// to that, we tolerate a 25% margin of error on the value of m_vsync
179
// reported from the system as this value is often not precise.
180
181
m_time
+= m_vsync;
182
183
if
(delta > m_vsync * 1.25f) {
184
m_lag
+= (delta / m_vsync);
185
m_bad
++;
186
// We tolerate one bad frame without resorting to timer based. This is
187
// done to cope with a slow loader frame followed by smooth animation.
188
// However, on the second frame with massive lag, we switch.
189
if
(
m_lag
> 10 &&
m_bad
> 2) {
190
m_mode = TimerMode;
191
qCDebug(QSG_LOG_INFO,
"animation driver switched to timer mode"
);
192
m_wallTime.start();
193
}
194
}
else
{
195
m_lag
= 0;
196
m_bad
= 0;
197
}
198
199
}
else
{
200
if
(delta < 1.25f * m_vsync) {
201
++
m_good
;
202
}
else
{
203
m_good
= 0;
204
}
205
206
// We've been solid for a while, switch back to vsync mode. Tolerance
207
// for switching back is lower than switching to timer mode, as we
208
// want to stay in vsync mode as much as possible.
209
if
(
m_good
> 10 && !
qsg_useConsistentTiming
(
)
) {
210
m_time
= elapsed();
211
m_mode = VSyncMode;
212
m_bad
= 0;
213
m_lag
= 0;
214
qCDebug(QSG_LOG_INFO,
"animation driver switched to vsync mode"
);
215
}
216
}
217
218
advanceAnimation();
219
}
220
221
bool
isVSyncDependent
()
const
override
222
{
223
return
true
;
224
}
225
226
double
m_time
;
227
Mode
m_mode
;
228
QElapsedTimer
m_timer
;
229
QElapsedTimer
m_wallTime
;
230
float
m_lag
;
231
int
m_bad
;
232
int
m_good
;
233
};
234
235
// Advance based on QElapsedTimer. (so like the TimerMode of QSGDefaultAnimationDriver)
236
// Does not depend on vsync-based throttling.
237
//
238
// NB this is not the same as not installing a QAnimationDriver: the built-in
239
// approach in QtCore is to rely on 16 ms timer events which are potentially a
240
// lot less accurate.
241
//
242
// This has the benefits of:
243
// - not needing any of the infrastructure for falling back to a
244
// QTimer when there are multiple windows,
245
// - needing no heuristics trying determine if vsync-based throttling
246
// is missing or broken,
247
// - being compatible with any kind of temporal drifts in vsync throttling
248
// which is reportedly happening in various environments and platforms
249
// still,
250
// - not being tied to the primary screen's refresh rate, i.e. this is
251
// correct even if the window is on some secondary screen with a
252
// different refresh rate,
253
// - not having to worry about the potential effects of variable refresh
254
// rate solutions,
255
// - render thread animators work correctly regardless of vsync.
256
//
257
// On the downside, some animations might appear less smooth (compared to the
258
// ideal single window case of QSGDefaultAnimationDriver).
259
//
260
class
QSGElapsedTimerAnimationDriver
:
public
QSGAnimationDriver
261
{
262
public
:
263
QSGElapsedTimerAnimationDriver
(QObject *parent)
264
:
QSGAnimationDriver
(parent)
265
{
266
qCDebug(QSG_LOG_INFO,
"Animation Driver: using QElapsedTimer, thread %p %s"
,
267
QThread::currentThread(),
268
QThread::currentThread() == qGuiApp->thread() ?
"(gui/main thread)"
:
"(render thread)"
);
269
}
270
271
void
start
()
override
272
{
273
m_wallTime.start();
274
QAnimationDriver::start();
275
}
276
277
qint64
elapsed
()
const
override
278
{
279
return
m_wallTime.elapsed();
280
}
281
282
void
advance
()
override
283
{
284
advanceAnimation();
285
}
286
287
bool
isVSyncDependent
()
const
override
288
{
289
return
false
;
290
}
291
292
private
:
293
QElapsedTimer m_wallTime;
294
};
295
296
QSGRenderContext::FontKey::FontKey(
const
QRawFont &font,
int
quality)
297
{
298
QFontEngine *fe = QRawFontPrivate::get(font)->fontEngine;
299
if
(fe !=
nullptr
)
300
faceId = fe->faceId();
301
style = font.style();
302
weight = font.weight();
303
renderTypeQuality = quality;
304
if
(faceId.filename.isEmpty()) {
305
familyName = font.familyName();
306
styleName = font.styleName();
307
}
308
}
309
310
/*!
311
\class QSGContext
312
313
\brief The QSGContext holds the scene graph entry points for one QML engine.
314
315
The context is not ready for use until it has a QRhi. Once that happens,
316
the scene graph population can start.
317
318
\internal
319
*/
320
321
QSGContext::QSGContext(QObject *parent) :
322
QObject(parent)
323
{
324
}
325
326
QSGContext::~QSGContext()
327
{
328
}
329
330
void
QSGContext::renderContextInitialized(QSGRenderContext *)
331
{
332
}
333
334
void
QSGContext::renderContextInvalidated(QSGRenderContext *)
335
{
336
}
337
338
339
/*!
340
Convenience factory function for creating a colored rectangle with the given geometry.
341
*/
342
QSGInternalRectangleNode *QSGContext::createInternalRectangleNode(
const
QRectF &rect,
const
QColor &c)
343
{
344
QSGInternalRectangleNode *node = createInternalRectangleNode();
345
node->setRect(rect);
346
node->setColor(c);
347
node->update();
348
return
node;
349
}
350
351
QSGInternalTextNode *QSGContext::createInternalTextNode(QSGRenderContext *renderContext)
352
{
353
return
new
QSGInternalTextNode(renderContext);
354
}
355
356
QSGTextNode *QSGContext::createTextNode(QSGRenderContext *renderContext)
357
{
358
return
createInternalTextNode(renderContext);
359
}
360
361
/*!
362
Creates a new shader effect helper instance. This function is called on the
363
GUI thread, unlike the others. This is necessary in order to provide
364
adaptable, backend-specific shader effect functionality to the GUI thread too.
365
*/
366
QSGGuiThreadShaderEffectManager *QSGContext::createGuiThreadShaderEffectManager()
367
{
368
return
nullptr
;
369
}
370
371
/*!
372
Creates a new shader effect node. The default of returning nullptr is
373
valid as long as the backend does not claim SupportsShaderEffectNode or
374
ignoring ShaderEffect elements is acceptable.
375
*/
376
QSGShaderEffectNode *QSGContext::createShaderEffectNode(QSGRenderContext *)
377
{
378
return
nullptr
;
379
}
380
381
/*!
382
Creates a new animation driver.
383
*/
384
QAnimationDriver *QSGContext::createAnimationDriver(QObject *parent)
385
{
386
if
(useElapsedTimerBasedAnimationDriver())
387
return
new
QSGElapsedTimerAnimationDriver(parent);
388
389
return
new
QSGDefaultAnimationDriver(parent);
390
}
391
392
/*!
393
\return the vsync rate (such as, 16.68 ms or similar), if applicable, for
394
the \a driver that was created by createAnimationDriver().
395
*/
396
float
QSGContext::vsyncIntervalForAnimationDriver(QAnimationDriver *driver)
397
{
398
return
static_cast
<QSGAnimationDriver *>(driver)->vsyncInterval();
399
}
400
401
/*!
402
\return true if \a driver relies on vsync-based throttling in some form.
403
*/
404
bool
QSGContext::isVSyncDependent(QAnimationDriver *driver)
405
{
406
return
static_cast
<QSGAnimationDriver *>(driver)->isVSyncDependent();
407
}
408
409
QSize QSGContext::minimumFBOSize()
const
410
{
411
return
QSize(1, 1);
412
}
413
414
/*!
415
Returns a pointer to the (presumably) global renderer interface.
416
417
\note This function may be called on the GUI thread in order to get access
418
to QSGRendererInterface::graphicsApi() and other getters.
419
420
\note it is expected that the simple queries (graphicsApi, shaderType,
421
etc.) are available regardless of the render context validity (i.e.
422
scenegraph status). This does not apply to engine-specific getters like
423
getResource(). In the end this means that this function must always return
424
a valid object in subclasses, even when renderContext->isValid() is false.
425
The typical pattern is to implement the QSGRendererInterface in the
426
QSGContext or QSGRenderContext subclass itself, whichever is more suitable.
427
*/
428
QSGRendererInterface *QSGContext::rendererInterface(QSGRenderContext *renderContext)
429
{
430
Q_UNUSED(renderContext);
431
qWarning(
"QSGRendererInterface not implemented"
);
432
return
nullptr
;
433
}
434
435
/*!
436
\class QSGRenderContext
437
\inmodule QtQuick
438
\internal
439
*/
440
QSGRenderContext::QSGRenderContext(QSGContext *context)
441
: m_sg(context)
442
{
443
}
444
445
QSGRenderContext::~QSGRenderContext()
446
{
447
}
448
449
void
QSGRenderContext::initialize(
const
InitParams *params)
450
{
451
Q_UNUSED(params);
452
}
453
454
void
QSGRenderContext::invalidate()
455
{
456
}
457
458
void
QSGRenderContext::prepareSync(qreal devicePixelRatio,
459
QRhiCommandBuffer *cb,
460
const
QQuickGraphicsConfiguration &config)
461
{
462
Q_UNUSED(devicePixelRatio);
463
Q_UNUSED(cb);
464
Q_UNUSED(config);
465
}
466
467
void
QSGRenderContext::beginNextFrame(QSGRenderer *renderer,
const
QSGRenderTarget &renderTarget,
468
RenderPassCallback mainPassRecordingStart,
469
RenderPassCallback mainPassRecordingEnd,
470
void
*callbackUserData)
471
{
472
renderer->setRenderTarget(renderTarget);
473
Q_UNUSED(mainPassRecordingStart);
474
Q_UNUSED(mainPassRecordingEnd);
475
Q_UNUSED(callbackUserData);
476
}
477
478
void
QSGRenderContext::endNextFrame(QSGRenderer *renderer)
479
{
480
Q_UNUSED(renderer);
481
}
482
483
void
QSGRenderContext::endSync()
484
{
485
qDeleteAll(m_texturesToDelete);
486
m_texturesToDelete.clear();
487
}
488
489
/*!
490
Do necessary preprocessing before the frame
491
*/
492
void
QSGRenderContext::preprocess()
493
{
494
}
495
496
/*!
497
Factory function for curve atlases that can be used to provide geometry for the curve
498
renderer for a given font.
499
*/
500
QSGCurveGlyphAtlas *QSGRenderContext::curveGlyphAtlas(
const
QRawFont &font)
501
{
502
Q_UNUSED(font);
503
return
nullptr
;
504
}
505
506
/*!
507
Factory function for scene graph backends of the distance-field glyph cache.
508
*/
509
QSGDistanceFieldGlyphCache *QSGRenderContext::distanceFieldGlyphCache(
const
QRawFont &,
int
)
510
{
511
return
nullptr
;
512
}
513
514
void
QSGRenderContext::invalidateGlyphCaches()
515
{
516
517
}
518
519
void
QSGRenderContext::flushGlyphCaches()
520
{
521
522
}
523
524
void
QSGRenderContext::registerFontengineForCleanup(QFontEngine *engine)
525
{
526
engine->ref.ref();
527
m_fontEnginesToClean[engine]++;
528
}
529
530
void
QSGRenderContext::unregisterFontengineForCleanup(QFontEngine *engine)
531
{
532
m_fontEnginesToClean[engine]--;
533
Q_ASSERT(m_fontEnginesToClean.value(engine) >= 0);
534
}
535
536
QRhi *QSGRenderContext::rhi()
const
537
{
538
return
nullptr
;
539
}
540
541
/*!
542
Factory function for the scene graph renderers.
543
544
The renderers are used for the toplevel renderer and once for every
545
QQuickShaderEffectSource used in the QML scene.
546
*/
547
548
QSGTexture *QSGRenderContext::textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window)
549
{
550
if
(!factory)
551
return
nullptr
;
552
553
m_mutex.lock();
554
QSGTexture *texture = m_textures.value(factory);
555
m_mutex.unlock();
556
557
if
(!texture) {
558
texture = factory->createTexture(window);
559
if
(!texture)
560
return
nullptr
;
561
562
m_mutex.lock();
563
m_textures.insert(factory, texture);
564
m_mutex.unlock();
565
566
connect(factory, SIGNAL(destroyed(QObject*)),
this
, SLOT(textureFactoryDestroyed(QObject*)), Qt::DirectConnection);
567
}
568
return
texture;
569
}
570
571
void
QSGRenderContext::textureFactoryDestroyed(QObject *o)
572
{
573
m_mutex.lock();
574
m_texturesToDelete << m_textures.take(o);
575
m_mutex.unlock();
576
}
577
578
/*!
579
Return the texture corresponding to a texture factory.
580
581
This may optionally manipulate the texture in some way; for example by returning
582
an atlased texture.
583
584
This function is not a replacement for textureForFactory; both should be used
585
for a single texture (this might atlas, while the other might cache).
586
*/
587
QSGTexture *QSGRenderContext::compressedTextureForFactory(
const
QSGCompressedTextureFactory *)
const
588
{
589
return
nullptr
;
590
}
591
592
QT_END_NAMESPACE
593
594
#
include
"qsgcontext.moc"
595
#
include
"moc_qsgcontext_p.cpp"
QSGAnimationDriver
Definition
qsgcontext.cpp:87
QSGAnimationDriver::QSGAnimationDriver
QSGAnimationDriver(QObject *parent)
Definition
qsgcontext.cpp:89
QSGAnimationDriver::vsyncInterval
float vsyncInterval() const
Definition
qsgcontext.cpp:105
QSGAnimationDriver::isVSyncDependent
virtual bool isVSyncDependent() const =0
QSGAnimationDriver::m_vsync
float m_vsync
Definition
qsgcontext.cpp:110
QSGDefaultAnimationDriver
Definition
qsgcontext.cpp:115
QSGDefaultAnimationDriver::m_timer
QElapsedTimer m_timer
Definition
qsgcontext.cpp:228
QSGDefaultAnimationDriver::elapsed
qint64 elapsed() const override
Returns the number of milliseconds since the animations was started.
Definition
qsgcontext.cpp:154
QSGDefaultAnimationDriver::m_wallTime
QElapsedTimer m_wallTime
Definition
qsgcontext.cpp:229
QSGDefaultAnimationDriver::advance
void advance() override
Advances the animation.
Definition
qsgcontext.cpp:161
QSGDefaultAnimationDriver::m_bad
int m_bad
Definition
qsgcontext.cpp:231
QSGDefaultAnimationDriver::m_lag
float m_lag
Definition
qsgcontext.cpp:230
QSGDefaultAnimationDriver::m_good
int m_good
Definition
qsgcontext.cpp:232
QSGDefaultAnimationDriver::QSGDefaultAnimationDriver
QSGDefaultAnimationDriver(QObject *parent)
Definition
qsgcontext.cpp:123
QSGDefaultAnimationDriver::start
void start() override
Definition
qsgcontext.cpp:146
QSGDefaultAnimationDriver::isVSyncDependent
bool isVSyncDependent() const override
Definition
qsgcontext.cpp:221
QSGDefaultAnimationDriver::m_mode
Mode m_mode
Definition
qsgcontext.cpp:227
QSGDefaultAnimationDriver::m_time
double m_time
Definition
qsgcontext.cpp:226
QSGElapsedTimerAnimationDriver
Definition
qsgcontext.cpp:261
QSGElapsedTimerAnimationDriver::QSGElapsedTimerAnimationDriver
QSGElapsedTimerAnimationDriver(QObject *parent)
Definition
qsgcontext.cpp:263
QSGElapsedTimerAnimationDriver::isVSyncDependent
bool isVSyncDependent() const override
Definition
qsgcontext.cpp:287
QSGElapsedTimerAnimationDriver::start
void start() override
Definition
qsgcontext.cpp:271
QSGElapsedTimerAnimationDriver::elapsed
qint64 elapsed() const override
Returns the number of milliseconds since the animations was started.
Definition
qsgcontext.cpp:277
QSGElapsedTimerAnimationDriver::advance
void advance() override
Advances the animation.
Definition
qsgcontext.cpp:282
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
qsg_useConsistentTiming
bool qsg_useConsistentTiming()
Definition
qsgcontext.cpp:75
qtdeclarative
src
quick
scenegraph
qsgcontext.cpp
Generated on
for Qt by
1.18.0