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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtdeclarative/src/quick/scenegraph/qsgadaptationlayer.cpp