Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qsgadaptationlayer.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 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
6
7#include <qmath.h>
8#include <QtQuick/private/qsgdistancefieldglyphnode_p.h>
9#include <QtQuick/private/qsgcontext_p.h>
10#include <private/qrawfont_p.h>
11#include <QtGui/qguiapplication.h>
12#include <qdir.h>
13#include <qsgrendernode.h>
14
15#include <private/qquickprofiler_p.h>
16#include <QElapsedTimer>
17
18#include <qtquick_tracepoints_p.h>
19
20QT_BEGIN_NAMESPACE
21
22Q_TRACE_POINT(qtquick, QSGDistanceFieldGlyphCache_update_entry, int count)
23Q_TRACE_POINT(qtquick, QSGDistanceFieldGlyphCache_update_exit)
24Q_TRACE_POINT(qtquick, QSGDistanceFieldGlyphCache_glyphRender_entry)
25Q_TRACE_POINT(qtquick, QSGDistanceFieldGlyphCache_glyphRender_exit)
26Q_TRACE_POINT(qtquick, QSGDistanceFieldGlyphCache_glyphStore_entry)
27Q_TRACE_POINT(qtquick, QSGDistanceFieldGlyphCache_glyphStore_exit)
28
29static QElapsedTimer qsg_render_timer;
30
31QSGDistanceFieldGlyphCache::Texture QSGDistanceFieldGlyphCache::s_emptyTexture;
32
33QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(const QRawFont &font, int renderTypeQuality)
34 : m_renderTypeQuality(renderTypeQuality)
35 , m_pendingGlyphs(64)
36{
37 Q_ASSERT(font.isValid());
38
39 QRawFontPrivate *fontD = QRawFontPrivate::get(font);
40 m_glyphCount = fontD->fontEngine->glyphCount();
41
42 m_doubleGlyphResolution = qt_fontHasNarrowOutlines(font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT();
43
44 m_referenceFont = font;
45 // we set the same pixel size as used by the distance field internally.
46 // this allows us to call pathForGlyph once and reuse the result.
47 m_referenceFont.setPixelSize(baseFontSize() * QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution));
48 Q_ASSERT(m_referenceFont.isValid());
49}
50
51QSGDistanceFieldGlyphCache::~QSGDistanceFieldGlyphCache()
52{
53}
54
55int QSGDistanceFieldGlyphCache::baseFontSize() const
56{
57 return m_renderTypeQuality > 0 ? m_renderTypeQuality : QT_DISTANCEFIELD_BASEFONTSIZE(m_doubleGlyphResolution);
58}
59
60QSGDistanceFieldGlyphCache::GlyphData &QSGDistanceFieldGlyphCache::emptyData(glyph_t glyph)
61{
62 GlyphData gd;
63 gd.texture = &s_emptyTexture;
64 QHash<glyph_t, GlyphData>::iterator it = m_glyphsData.insert(glyph, gd);
65 return it.value();
66}
67
68QSGDistanceFieldGlyphCache::GlyphData &QSGDistanceFieldGlyphCache::glyphData(glyph_t glyph)
69{
70 QHash<glyph_t, GlyphData>::iterator data = m_glyphsData.find(glyph);
71 if (data == m_glyphsData.end()) {
72 GlyphData &gd = emptyData(glyph);
73 gd.path = m_referenceFont.pathForGlyph(glyph);
74 // need bounding rect in base font size scale
75 qreal scaleFactor = qreal(1) / QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution);
76 QTransform scaleDown;
77 scaleDown.scale(scaleFactor, scaleFactor);
78 gd.boundingRect = scaleDown.mapRect(gd.path.boundingRect());
79 return gd;
80 }
81 return data.value();
82}
83
84QSGDistanceFieldGlyphCache::Metrics QSGDistanceFieldGlyphCache::glyphMetrics(glyph_t glyph, qreal pixelSize)
85{
86 GlyphData &gd = glyphData(glyph);
87 qreal scale = fontScale(pixelSize);
88
89 Metrics m;
90 m.width = gd.boundingRect.width() * scale;
91 m.height = gd.boundingRect.height() * scale;
92 m.baselineX = gd.boundingRect.x() * scale;
93 m.baselineY = -gd.boundingRect.y() * scale;
94
95 return m;
96}
97
98void QSGDistanceFieldGlyphCache::populate(const QList<glyph_t> &glyphs)
99{
100 QSet<glyph_t> referencedGlyphs;
101 QSet<glyph_t> newGlyphs;
102 int count = glyphs.size();
103 for (int i = 0; i < count; ++i) {
104 glyph_t glyphIndex = glyphs.at(i);
105 const bool isValid = int(glyphIndex) < glyphCount() || glyphCount() <= 0;
106
107 if (!isValid) {
108 qWarning("Warning: distance-field glyph is not available with index %d (glyph count: %d, font: %s)",
109 glyphIndex,
110 glyphCount(),
111 qPrintable(m_referenceFont.familyName()));
112 }
113
114 GlyphData &gd = isValid ? glyphData(glyphIndex) : emptyData(glyphIndex);
115 ++gd.ref;
116 referencedGlyphs.insert(glyphIndex);
117
118 if (gd.texCoord.isValid() || m_populatingGlyphs.contains(glyphIndex))
119 continue;
120
121 m_populatingGlyphs.insert(glyphIndex);
122
123 if (gd.boundingRect.isEmpty()) {
124 gd.texCoord.width = 0;
125 gd.texCoord.height = 0;
126 } else {
127 newGlyphs.insert(glyphIndex);
128 }
129 }
130
131 referenceGlyphs(referencedGlyphs);
132 if (!newGlyphs.isEmpty())
133 requestGlyphs(newGlyphs);
134}
135
136void QSGDistanceFieldGlyphCache::release(const QList<glyph_t> &glyphs)
137{
138 QSet<glyph_t> unusedGlyphs;
139 for (glyph_t glyphIndex : glyphs) {
140 if (auto it = m_glyphsData.find(glyphIndex); it != m_glyphsData.end()) {
141 GlyphData &gd = it.value();
142 if (--gd.ref == 0)
143 unusedGlyphs.insert(glyphIndex);
144 }
145 }
146 releaseGlyphs(unusedGlyphs);
147}
148
149bool QSGDistanceFieldGlyphCache::isActive() const
150{
151 return true;
152}
153
154void QSGDistanceFieldGlyphCache::update()
155{
156 m_populatingGlyphs.clear();
157
158 if (m_pendingGlyphs.isEmpty())
159 return;
160
161 Q_TRACE_SCOPE(QSGDistanceFieldGlyphCache_update, m_pendingGlyphs.size());
162
163 bool profileFrames = QSG_LOG_TIME_GLYPH().isDebugEnabled();
164 if (profileFrames)
165 qsg_render_timer.start();
166 Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphAdaptationLayerFrame);
167 Q_TRACE(QSGDistanceFieldGlyphCache_glyphRender_entry);
168
169 QList<QDistanceField> distanceFields;
170 const int pendingGlyphsSize = m_pendingGlyphs.size();
171 distanceFields.reserve(pendingGlyphsSize);
172 for (int i = 0; i < pendingGlyphsSize; ++i) {
173 GlyphData &gd = glyphData(m_pendingGlyphs.at(i));
174
175 QSize size = QSize(qCeil(gd.texCoord.width + gd.texCoord.xMargin * 2),
176 qCeil(gd.texCoord.height + gd.texCoord.yMargin * 2));
177
178 distanceFields.append(QDistanceField(size,
179 gd.path,
180 m_pendingGlyphs.at(i),
181 m_doubleGlyphResolution));
182 gd.path = QPainterPath(); // no longer needed, so release memory used by the painter path
183 }
184
185 qint64 renderTime = 0;
186 int count = m_pendingGlyphs.size();
187 if (profileFrames)
188 renderTime = qsg_render_timer.nsecsElapsed();
189
190 Q_TRACE(QSGDistanceFieldGlyphCache_glyphRender_exit);
191 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphAdaptationLayerFrame,
192 QQuickProfiler::SceneGraphAdaptationLayerGlyphRender);
193 Q_TRACE(QSGDistanceFieldGlyphCache_glyphStore_entry);
194
195 m_pendingGlyphs.reset();
196
197 storeGlyphs(distanceFields);
198
199#if defined(QSG_DISTANCEFIELD_CACHE_DEBUG)
200 for (Texture texture : std::as_const(m_textures))
201 saveTexture(texture.texture, m_referenceFont.familyName());
202#endif
203
204 if (QSG_LOG_TIME_GLYPH().isDebugEnabled()) {
205 quint64 now = qsg_render_timer.elapsed();
206 qCDebug(QSG_LOG_TIME_GLYPH,
207 "distancefield: %d glyphs prepared in %dms, rendering=%d, upload=%d",
208 count,
209 (int) now,
210 int(renderTime / 1000000),
211 int((now - (renderTime / 1000000))));
212 }
213 Q_TRACE(QSGDistanceFieldGlyphCache_glyphStore_exit);
214 Q_QUICK_SG_PROFILE_END_WITH_PAYLOAD(QQuickProfiler::SceneGraphAdaptationLayerFrame,
215 QQuickProfiler::SceneGraphAdaptationLayerGlyphStore,
216 (qint64)count);
217}
218
219void QSGDistanceFieldGlyphCache::setGlyphsPosition(const QList<GlyphPosition> &glyphs)
220{
221 QList<quint32> invalidatedGlyphs;
222
223 int count = glyphs.size();
224 for (int i = 0; i < count; ++i) {
225 GlyphPosition glyph = glyphs.at(i);
226 GlyphData &gd = glyphData(glyph.glyph);
227
228 if (!gd.texCoord.isNull())
229 invalidatedGlyphs.append(glyph.glyph);
230
231 gd.texCoord.xMargin = QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution));
232 gd.texCoord.yMargin = QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution));
233 gd.texCoord.x = glyph.position.x();
234 gd.texCoord.y = glyph.position.y();
235 gd.texCoord.width = gd.boundingRect.width();
236 gd.texCoord.height = gd.boundingRect.height();
237 }
238
239 if (!invalidatedGlyphs.isEmpty()) {
240 for (QSGDistanceFieldGlyphConsumerList::iterator iter = m_registeredNodes.begin(); iter != m_registeredNodes.end(); ++iter) {
241 iter->invalidateGlyphs(invalidatedGlyphs);
242 }
243 }
244}
245
246void QSGDistanceFieldGlyphCache::processPendingGlyphs()
247{
248 /* Intentionally empty */
249}
250
251void QSGDistanceFieldGlyphCache::setGlyphsTexture(const QList<glyph_t> &glyphs, const Texture &tex)
252{
253 int i = m_textures.indexOf(tex);
254 if (i == -1) {
255 m_textures.append(tex);
256 i = m_textures.size() - 1;
257 } else {
258 m_textures[i].size = tex.size;
259 }
260 Texture *texture = &(m_textures[i]);
261
262 QList<quint32> invalidatedGlyphs;
263
264 int count = glyphs.size();
265 for (int j = 0; j < count; ++j) {
266 glyph_t glyphIndex = glyphs.at(j);
267 GlyphData &gd = glyphData(glyphIndex);
268 if (gd.texture != &s_emptyTexture)
269 invalidatedGlyphs.append(glyphIndex);
270 gd.texture = texture;
271 }
272
273 if (!invalidatedGlyphs.isEmpty()) {
274 for (QSGDistanceFieldGlyphConsumerList::iterator iter = m_registeredNodes.begin(); iter != m_registeredNodes.end(); ++iter) {
275 iter->invalidateGlyphs(invalidatedGlyphs);
276 }
277 }
278}
279
280void QSGDistanceFieldGlyphCache::markGlyphsToRender(const QList<glyph_t> &glyphs)
281{
282 int count = glyphs.size();
283 for (int i = 0; i < count; ++i)
284 m_pendingGlyphs.add(glyphs.at(i));
285}
286
287void QSGDistanceFieldGlyphCache::updateRhiTexture(QRhiTexture *oldTex, QRhiTexture *newTex, const QSize &newTexSize)
288{
289 int count = m_textures.size();
290 for (int i = 0; i < count; ++i) {
291 Texture &tex = m_textures[i];
292 if (tex.texture == oldTex) {
293 tex.texture = newTex;
294 tex.size = newTexSize;
295 return;
296 }
297 }
298}
299
300QSGNodeVisitorEx::~QSGNodeVisitorEx()
301 = default;
302
303void QSGNodeVisitorEx::visitChildren(QSGNode *node)
304{
305 for (QSGNode *child = node->firstChild(); child; child = child->nextSibling()) {
306 switch (child->type()) {
307 case QSGNode::ClipNodeType: {
308 QSGClipNode *c = static_cast<QSGClipNode*>(child);
309 if (visit(c))
310 visitChildren(c);
311 endVisit(c);
312 break;
313 }
314 case QSGNode::TransformNodeType: {
315 QSGTransformNode *c = static_cast<QSGTransformNode*>(child);
316 if (visit(c))
317 visitChildren(c);
318 endVisit(c);
319 break;
320 }
321 case QSGNode::OpacityNodeType: {
322 QSGOpacityNode *c = static_cast<QSGOpacityNode*>(child);
323 if (visit(c))
324 visitChildren(c);
325 endVisit(c);
326 break;
327 }
328 case QSGNode::GeometryNodeType: {
329 if (child->flags() & QSGNode::IsVisitableNode) {
330 QSGVisitableNode *v = static_cast<QSGVisitableNode*>(child);
331 v->accept(this);
332 } else {
333 QSGGeometryNode *c = static_cast<QSGGeometryNode*>(child);
334 if (visit(c))
335 visitChildren(c);
336 endVisit(c);
337 }
338 break;
339 }
340 case QSGNode::RootNodeType: {
341 QSGRootNode *root = static_cast<QSGRootNode*>(child);
342 if (visit(root))
343 visitChildren(root);
344 endVisit(root);
345 break;
346 }
347 case QSGNode::BasicNodeType: {
348 visitChildren(child);
349 break;
350 }
351 case QSGNode::RenderNodeType: {
352 QSGRenderNode *r = static_cast<QSGRenderNode*>(child);
353 if (visit(r))
354 visitChildren(r);
355 endVisit(r);
356 break;
357 }
358 default:
359 Q_UNREACHABLE();
360 break;
361 }
362 }
363}
364
365QSGVisitableNode::~QSGVisitableNode()
366 = default;
367
368QSGInternalRectangleNode::~QSGInternalRectangleNode()
369 = default;
370
371QSGInternalImageNode::~QSGInternalImageNode()
372 = default;
373
374QSGPainterNode::~QSGPainterNode()
375 = default;
376
377#ifndef QT_NO_DEBUG_STREAM
378QDebug operator<<(QDebug debug, const QSGGuiThreadShaderEffectManager::ShaderInfo::Variable &v)
379{
380 QDebugStateSaver saver(debug);
381 debug.space();
382 debug << v.name;
383 switch (v.type) {
384 case QSGGuiThreadShaderEffectManager::ShaderInfo::Constant:
385 debug << "cvar" << "offset" << v.offset << "size" << v.size;
386 break;
387 case QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler:
388 debug << "sampler" << "bindpoint" << v.bindPoint;
389 break;
390 case QSGGuiThreadShaderEffectManager::ShaderInfo::Texture:
391 debug << "texture" << "bindpoint" << v.bindPoint;
392 break;
393 default:
394 break;
395 }
396 return debug;
397}
398
399QDebug operator<<(QDebug debug, const QSGShaderEffectNode::VariableData &vd)
400{
401 QDebugStateSaver saver(debug);
402 debug.space();
403 debug << vd.specialType;
404 return debug;
405}
406#endif
407
408/*!
409 \internal
410 */
411QSGLayer::QSGLayer(QSGTexturePrivate &dd)
412 : QSGDynamicTexture(dd)
413{
414}
415
416QSGLayer::~QSGLayer()
417 = default;
418
419#if QT_CONFIG(quick_sprite)
420
421QSGSpriteNode::~QSGSpriteNode()
422 = default;
423
424#endif
425
426QSGGuiThreadShaderEffectManager::~QSGGuiThreadShaderEffectManager()
427 = default;
428
429QSGShaderEffectNode::~QSGShaderEffectNode()
430 = default;
431
432QSGGlyphNode::~QSGGlyphNode()
433 = default;
434
435QSGDistanceFieldGlyphConsumer::~QSGDistanceFieldGlyphConsumer()
436 = default;
437
438QT_END_NAMESPACE
439
440#include "moc_qsgadaptationlayer_p.cpp"
QDebug operator<<(QDebug dbg, const QFileInfo &fi)