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
qsgdefaultrendercontext.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
"qsgdefaultrendercontext_p.h"
6
#
include
"qsgcurveglyphatlas_p.h"
7
8
#
include
<
QtGui
/
QGuiApplication
>
9
10
#
include
<
QtQuick
/
private
/
qsgbatchrenderer_p
.
h
>
11
#
include
<
QtQuick
/
private
/
qsgrenderer_p
.
h
>
12
#
include
<
QtQuick
/
private
/
qsgrhiatlastexture_p
.
h
>
13
#
include
<
QtQuick
/
private
/
qsgrhidistancefieldglyphcache_p
.
h
>
14
#
include
<
QtQuick
/
private
/
qsgmaterialshader_p
.
h
>
15
#
include
<
QtQuick
/
private
/
qsgrhisupport_p
.
h
>
16
17
#
include
<
QtQuick
/
private
/
qsgcompressedtexture_p
.
h
>
18
19
#
include
<
QtQuick
/
qsgrendererinterface
.
h
>
20
#
include
<
QtQuick
/
qquickgraphicsconfiguration
.
h
>
21
22
QT_BEGIN_NAMESPACE
23
24
Q_STATIC_LOGGING_CATEGORY(lcGlyphCaches,
"qt.scenegraph.text.glyphcache"
)
25
26
/*!
27
\class QSGDefaultRenderContext
28
\inmodule QtQuick
29
\internal
30
*/
31
QSGDefaultRenderContext::QSGDefaultRenderContext(QSGContext *context)
32
: QSGRenderContext(context)
33
, m_rhi(
nullptr
)
34
, m_maxTextureSize(0)
35
, m_rhiAtlasManager(
nullptr
)
36
, m_currentFrameCommandBuffer(
nullptr
)
37
, m_currentFrameRenderPass(
nullptr
)
38
, m_useDepthBufferFor2D(
true
)
39
, m_glyphCacheResourceUpdates(
nullptr
)
40
{
41
}
42
43
/*!
44
Initializes the scene graph render context with the GL context \a context. This also
45
emits the ready() signal so that the QML graph can start building scene graph nodes.
46
*/
47
void
QSGDefaultRenderContext::initialize(
const
QSGRenderContext::InitParams *params)
48
{
49
if
(!m_sg)
50
return
;
51
52
const
InitParams *initParams =
static_cast
<
const
InitParams *>(params);
53
if
(initParams->sType != INIT_PARAMS_MAGIC)
54
qFatal(
"QSGDefaultRenderContext: Invalid parameters passed to initialize()"
);
55
56
m_initParams = *initParams;
57
58
m_rhi = m_initParams.rhi;
59
m_maxTextureSize = m_rhi->resourceLimit(QRhi::TextureSizeMax);
60
if
(!m_rhiAtlasManager)
61
m_rhiAtlasManager =
new
QSGRhiAtlasTexture::Manager(
this
, m_initParams.initialSurfacePixelSize, m_initParams.maybeSurface);
62
63
m_glyphCacheResourceUpdates =
nullptr
;
64
65
m_sg->renderContextInitialized(
this
);
66
67
emit initialized();
68
}
69
70
static
QFontEngine
*
fontEngineOfRawFont
(
const
QRawFont &font)
71
{
72
QRawFontPrivate *d = QRawFontPrivate::get(font);
73
if
(d !=
nullptr
)
74
return
d->fontEngine;
75
else
76
return
nullptr
;
77
}
78
79
void
QSGDefaultRenderContext::flushGlyphCaches()
80
{
81
auto
it = m_staleGlyphCaches.begin();
82
while
(it != m_staleGlyphCaches.end()) {
83
if
(!(*it)->isActive()) {
84
qCDebug(lcGlyphCaches()) <<
"Deleting stale glyph cache:"
85
<< (*it)
86
<<
"fontEngine:"
<< fontEngineOfRawFont((*it)->referenceFont())
87
<< (*it)->referenceFont().familyName();
88
delete
*it;
89
it = m_staleGlyphCaches.erase(it);
90
}
else
{
91
++it;
92
}
93
}
94
95
{
96
auto
it = m_fontEnginesToClean.begin();
97
while
(it != m_fontEnginesToClean.end()) {
98
if
(it.value() == 0) {
99
it.key()->clearGlyphCache(
this
);
100
if
(!it.key()->ref.deref())
101
delete
it.key();
102
it = m_fontEnginesToClean.erase(it);
103
}
else
{
104
++it;
105
}
106
}
107
}
108
}
109
110
void
QSGDefaultRenderContext::invalidateGlyphCaches()
111
{
112
{
113
auto
it = m_glyphCaches.begin();
114
while
(it != m_glyphCaches.end()) {
115
if
(!(*it)->isActive()) {
116
qCDebug(lcGlyphCaches()) <<
"Direct delete glyph cache:"
117
<< it.value()
118
<<
"fontEngine:"
<< fontEngineOfRawFont(it.value()->referenceFont())
119
<< it.value()->referenceFont().familyName()
120
<< it.value()->referenceFont().styleName()
121
<<
", key:"
122
<< it.key().familyName
123
<< it.key().styleName
124
<< it.key().faceId.filename;
125
delete
*it;
126
}
else
{
127
qCDebug(lcGlyphCaches()) <<
"Stale glyph cache:"
128
<< it.value()
129
<<
"fontEngine:"
<< fontEngineOfRawFont(it.value()->referenceFont())
130
<< it.value()->referenceFont().familyName()
131
<< it.value()->referenceFont().styleName()
132
<<
", key:"
133
<< it.key().familyName
134
<< it.key().styleName
135
<< it.key().faceId.filename;
136
137
m_staleGlyphCaches.append(*it);
138
}
139
140
it = m_glyphCaches.erase(it);
141
}
142
}
143
144
qDeleteAll(m_curveGlyphAtlases);
145
m_curveGlyphAtlases.clear();
146
}
147
148
void
QSGDefaultRenderContext::invalidate()
149
{
150
if
(!m_rhi)
151
return
;
152
153
qDeleteAll(m_texturesToDelete);
154
m_texturesToDelete.clear();
155
156
qDeleteAll(m_textures);
157
m_textures.clear();
158
159
for
(
auto
it = m_depthStencilBuffers.cbegin(), end = m_depthStencilBuffers.cend(); it != end; ++it) {
160
QSharedPointer<QSGDepthStencilBuffer> buf = it.value().toStrongRef();
161
delete
buf->ds;
162
buf->ds =
nullptr
;
163
buf->rc =
nullptr
;
164
}
165
m_depthStencilBuffers.clear();
166
167
/* The cleanup of the atlas textures is a bit intriguing.
168
As part of the cleanup in the threaded render loop, we
169
do:
170
1. call this function
171
2. call QCoreApp::sendPostedEvents() to immediately process
172
any pending deferred deletes.
173
3. delete the GL context.
174
175
As textures need the atlas manager while cleaning up, the
176
manager needs to be cleaned up after the textures, so
177
we post a deleteLater here at the very bottom so it gets
178
deferred deleted last.
179
180
Another alternative would be to use a QPointer in
181
QSGOpenGLAtlasTexture::Texture, but this seemed simpler.
182
*/
183
if
(m_rhiAtlasManager) {
184
m_rhiAtlasManager->invalidate();
185
m_rhiAtlasManager->deleteLater();
186
m_rhiAtlasManager =
nullptr
;
187
}
188
189
// The following piece of code will read/write to the font engine's caches,
190
// potentially from different threads. However, this is safe because this
191
// code is only called from QQuickWindow's shutdown which is called
192
// only when the GUI is blocked, and multiple threads will call it in
193
// sequence. (see qsgdefaultglyphnode_p.cpp's init())
194
for
(
auto
it = m_fontEnginesToClean.constBegin(); it != m_fontEnginesToClean.constEnd(); ++it) {
195
it.key()->clearGlyphCache(
this
);
196
if
(!it.key()->ref.deref())
197
delete
it.key();
198
}
199
m_fontEnginesToClean.clear();
200
201
qDeleteAll(m_curveGlyphAtlases);
202
m_curveGlyphAtlases.clear();
203
204
qCDebug(lcGlyphCaches()) <<
"Deleting"
<< m_glyphCaches.size() <<
"live glyph caches"
;
205
206
qDeleteAll(m_glyphCaches);
207
m_glyphCaches.clear();
208
209
qCDebug(lcGlyphCaches()) <<
"Deleting"
<< m_staleGlyphCaches.size() <<
"stale glyph caches"
;
210
211
qDeleteAll(m_staleGlyphCaches);
212
m_staleGlyphCaches.clear();
213
214
resetGlyphCacheResources();
215
216
m_rhi =
nullptr
;
217
218
if
(m_sg)
219
m_sg->renderContextInvalidated(
this
);
220
221
emit invalidated();
222
}
223
224
void
QSGDefaultRenderContext::prepareSync(qreal devicePixelRatio,
225
QRhiCommandBuffer *cb,
226
const
QQuickGraphicsConfiguration &config)
227
{
228
m_currentDevicePixelRatio = devicePixelRatio;
229
m_useDepthBufferFor2D = config.isDepthBufferEnabledFor2D();
230
231
// we store the command buffer already here, in case there is something in
232
// an updatePaintNode() implementation that leads to needing it (for
233
// example, an updateTexture() call on a QSGRhiLayer)
234
m_currentFrameCommandBuffer = cb;
235
}
236
237
void
QSGDefaultRenderContext::beginNextFrame(QSGRenderer *renderer,
const
QSGRenderTarget &renderTarget,
238
RenderPassCallback mainPassRecordingStart,
239
RenderPassCallback mainPassRecordingEnd,
240
void
*callbackUserData)
241
{
242
renderer->setRenderTarget(renderTarget);
243
renderer->setRenderPassRecordingCallbacks(mainPassRecordingStart, mainPassRecordingEnd, callbackUserData);
244
245
m_currentFrameCommandBuffer = renderTarget.cb;
// usually the same as what was passed to prepareSync() but cannot count on that having been called
246
m_currentFrameRenderPass = renderTarget.rpDesc;
247
}
248
249
void
QSGDefaultRenderContext::renderNextFrame(QSGRenderer *renderer)
250
{
251
renderer->renderScene();
252
}
253
254
void
QSGDefaultRenderContext::endNextFrame(QSGRenderer *renderer)
255
{
256
Q_UNUSED(renderer);
257
258
// In case glyphs were generated in this frame but no glyph node was
259
// rendered because all Text items in the scene were invisible.
260
if
(m_glyphCacheResourceUpdates) {
261
if
(m_currentFrameCommandBuffer)
262
m_currentFrameCommandBuffer->resourceUpdate(m_glyphCacheResourceUpdates);
263
else
264
m_glyphCacheResourceUpdates->release();
265
m_glyphCacheResourceUpdates =
nullptr
;
266
}
267
268
m_currentFrameCommandBuffer =
nullptr
;
269
m_currentFrameRenderPass =
nullptr
;
270
}
271
272
QSGTexture *QSGDefaultRenderContext::createTexture(
const
QImage &image, uint flags)
const
273
{
274
bool
atlas = flags & CreateTexture_Atlas;
275
bool
mipmap = flags & CreateTexture_Mipmap;
276
bool
alpha = flags & CreateTexture_Alpha;
277
278
// The atlas implementation is only supported from the render thread and
279
// does not support mipmaps.
280
if
(m_rhi) {
281
if
(!mipmap && atlas && QThread::currentThread() == m_rhi->thread()) {
282
QSGTexture *t = m_rhiAtlasManager->create(image, alpha);
283
if
(t)
284
return
t;
285
}
286
}
287
288
QSGPlainTexture *texture =
new
QSGPlainTexture;
289
texture->setImage(image);
290
if
(texture->hasAlphaChannel() && !alpha)
291
texture->setHasAlphaChannel(
false
);
292
293
return
texture;
294
}
295
296
QSGRenderer *QSGDefaultRenderContext::createRenderer(QSGRendererInterface::RenderMode renderMode)
297
{
298
return
new
QSGBatchRenderer::Renderer(
this
, renderMode);
299
}
300
301
QSGTexture *QSGDefaultRenderContext::compressedTextureForFactory(
const
QSGCompressedTextureFactory *factory)
const
302
{
303
// This is only used for atlasing compressed textures. Returning null implies no atlas.
304
305
if
(m_rhi && QThread::currentThread() == m_rhi->thread())
306
return
m_rhiAtlasManager->create(factory);
307
308
return
nullptr
;
309
}
310
311
void
QSGDefaultRenderContext::initializeRhiShader(QSGMaterialShader *shader, QShader::Variant shaderVariant)
312
{
313
QSGMaterialShaderPrivate::get(shader)->prepare(shaderVariant);
314
}
315
316
void
QSGDefaultRenderContext::preprocess()
317
{
318
for
(
auto
it = m_glyphCaches.begin(); it != m_glyphCaches.end(); ++it) {
319
it.value()->processPendingGlyphs();
320
it.value()->update();
321
}
322
323
for
(
auto
it = m_staleGlyphCaches.begin(); it != m_staleGlyphCaches.end(); ++it) {
324
(*it)->processPendingGlyphs();
325
(*it)->update();
326
}
327
}
328
329
QSGCurveGlyphAtlas *QSGDefaultRenderContext::curveGlyphAtlas(
const
QRawFont &font)
330
{
331
FontKey key = FontKey(font, 0);
332
QSGCurveGlyphAtlas *atlas = m_curveGlyphAtlases.value(key,
nullptr
);
333
if
(atlas ==
nullptr
) {
334
atlas =
new
QSGCurveGlyphAtlas(font);
335
m_curveGlyphAtlases.insert(key, atlas);
336
}
337
338
return
atlas;
339
}
340
341
QSGDistanceFieldGlyphCache *QSGDefaultRenderContext::distanceFieldGlyphCache(
const
QRawFont &font,
int
renderTypeQuality)
342
{
343
FontKey key(font, renderTypeQuality);
344
QSGDistanceFieldGlyphCache *cache = m_glyphCaches.value(key, 0);
345
if
(!cache && font.isValid()) {
346
cache =
new
QSGRhiDistanceFieldGlyphCache(
this
, font, renderTypeQuality);
347
m_glyphCaches.insert(key, cache);
348
349
qCDebug(lcGlyphCaches()) <<
"Creating new glyph cache:"
350
<< cache
351
<<
"fontEngine:"
<< fontEngineOfRawFont(cache->referenceFont())
352
<< cache->referenceFont().familyName()
353
<< cache->referenceFont().styleName()
354
<<
", key:"
355
<< key.familyName
356
<< key.styleName
357
<< key.faceId.filename;
358
}
else
{
359
qCDebug(lcGlyphCaches()) <<
"Found existing glyph cache:"
360
<< cache
361
<<
"fontEngine:"
<< fontEngineOfRawFont(cache->referenceFont())
362
<< cache->referenceFont().familyName()
363
<< cache->referenceFont().styleName()
364
<<
", key:"
365
<< key.familyName
366
<< key.styleName
367
<< key.faceId.filename;
368
}
369
370
return
cache;
371
}
372
373
QRhiResourceUpdateBatch *QSGDefaultRenderContext::maybeGlyphCacheResourceUpdates()
374
{
375
return
m_glyphCacheResourceUpdates;
376
}
377
378
QRhiResourceUpdateBatch *QSGDefaultRenderContext::glyphCacheResourceUpdates()
379
{
380
if
(!m_glyphCacheResourceUpdates)
381
m_glyphCacheResourceUpdates = m_rhi->nextResourceUpdateBatch();
382
383
return
m_glyphCacheResourceUpdates;
384
}
385
386
void
QSGDefaultRenderContext::deferredReleaseGlyphCacheTexture(QRhiTexture *texture)
387
{
388
if
(texture)
389
m_pendingGlyphCacheTextures.insert(texture);
390
}
391
392
void
QSGDefaultRenderContext::resetGlyphCacheResources()
393
{
394
if
(m_glyphCacheResourceUpdates) {
395
m_glyphCacheResourceUpdates->release();
396
m_glyphCacheResourceUpdates =
nullptr
;
397
}
398
399
for
(QRhiTexture *t : std::as_const(m_pendingGlyphCacheTextures))
400
t->deleteLater();
// the QRhiTexture object stays valid for the current frame
401
402
m_pendingGlyphCacheTextures.clear();
403
}
404
405
QSGDepthStencilBuffer
::~
QSGDepthStencilBuffer
()
406
{
407
if
(
rc
&&
ds
) {
408
const
auto
key =
std
::pair(
ds
->pixelSize(),
ds
->sampleCount());
409
rc
->m_depthStencilBuffers.remove(key);
410
}
411
delete
ds
;
412
}
413
414
QSharedPointer<QSGDepthStencilBuffer> QSGDefaultRenderContext::getDepthStencilBuffer(
const
QSize &size,
int
sampleCount)
415
{
416
const
auto
key = std::pair(size, sampleCount);
417
auto
it = m_depthStencilBuffers.constFind(key);
418
if
(it != m_depthStencilBuffers.cend()) {
419
if
(it.value())
420
return
it.value().toStrongRef();
421
}
422
423
QRhiRenderBuffer *ds = m_rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, size, sampleCount,
424
QSGRhiSupport::depthStencilBufferFlags());
425
if
(!ds->create()) {
426
qWarning(
"Failed to build depth-stencil buffer for layer"
);
427
delete
ds;
428
return
{};
429
}
430
QSharedPointer<QSGDepthStencilBuffer> buf(
new
QSGDepthStencilBuffer(ds));
431
addDepthStencilBuffer(buf);
432
return
buf;
433
}
434
435
void
QSGDefaultRenderContext::addDepthStencilBuffer(
const
QSharedPointer<QSGDepthStencilBuffer> &ds)
436
{
437
if
(ds) {
438
const
auto
key = std::pair(ds->ds->pixelSize(), ds->ds->sampleCount());
439
ds->rc =
this
;
440
m_depthStencilBuffers.insert(key, ds.toWeakRef());
441
}
442
}
443
444
QT_END_NAMESPACE
445
446
#
include
"moc_qsgdefaultrendercontext_p.cpp"
QSGDepthStencilBuffer
Definition
qsgdefaultrendercontext_p.h:39
QSGDepthStencilBuffer::ds
QRhiRenderBuffer * ds
Definition
qsgdefaultrendercontext_p.h:44
QSGDepthStencilBuffer::~QSGDepthStencilBuffer
~QSGDepthStencilBuffer()
Definition
qsgdefaultrendercontext.cpp:405
QSGDepthStencilBuffer::rc
QSGDefaultRenderContext * rc
Definition
qsgdefaultrendercontext_p.h:45
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
std
[33]
Definition
src_corelib_tools_qhash.cpp:421
fontEngineOfRawFont
static QFontEngine * fontEngineOfRawFont(const QRawFont &font)
Definition
qsgdefaultrendercontext.cpp:70
qtdeclarative
src
quick
scenegraph
qsgdefaultrendercontext.cpp
Generated on
for Qt by
1.18.0