32QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(
const QRawFont &font,
int renderTypeQuality)
33 : m_renderTypeQuality(renderTypeQuality)
36 Q_ASSERT(font.isValid());
38 QRawFontPrivate *fontD = QRawFontPrivate::get(font);
39 m_glyphCount = fontD->fontEngine->glyphCount();
41 m_doubleGlyphResolution = qt_fontHasNarrowOutlines(font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT();
43 m_referenceFont = font;
46 m_referenceFont.setPixelSize(baseFontSize() * QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution));
47 Q_ASSERT(m_referenceFont.isValid());
67QSGDistanceFieldGlyphCache::GlyphData &QSGDistanceFieldGlyphCache::glyphData(glyph_t glyph)
69 QHash<glyph_t, GlyphData>::iterator data = m_glyphsData.find(glyph);
70 if (data == m_glyphsData.end()) {
71 GlyphData &gd = emptyData(glyph);
72 gd.path = m_referenceFont.pathForGlyph(glyph);
74 qreal scaleFactor = qreal(1) / QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution);
76 scaleDown.scale(scaleFactor, scaleFactor);
77 gd.boundingRect = scaleDown.mapRect(gd.path.boundingRect());
83QSGDistanceFieldGlyphCache::Metrics QSGDistanceFieldGlyphCache::glyphMetrics(glyph_t glyph, qreal pixelSize)
85 GlyphData &gd = glyphData(glyph);
86 qreal scale = fontScale(pixelSize);
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;
97void QSGDistanceFieldGlyphCache::populate(
const QList<glyph_t> &glyphs)
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 const bool isValid =
int(glyphIndex) < glyphCount() || glyphCount() <= 0;
107 qWarning(
"Warning: distance-field glyph is not available with index %d (glyph count: %d, font: %s)",
110 qPrintable(m_referenceFont.familyName()));
113 GlyphData &gd = isValid ? glyphData(glyphIndex) : emptyData(glyphIndex);
115 referencedGlyphs.insert(glyphIndex);
117 if (gd.texCoord.isValid() || m_populatingGlyphs.contains(glyphIndex))
120 m_populatingGlyphs.insert(glyphIndex);
122 if (gd.boundingRect.isEmpty()) {
123 gd.texCoord.width = 0;
124 gd.texCoord.height = 0;
126 newGlyphs.insert(glyphIndex);
130 referenceGlyphs(referencedGlyphs);
131 if (!newGlyphs.isEmpty())
132 requestGlyphs(newGlyphs);
135void QSGDistanceFieldGlyphCache::release(
const QList<glyph_t> &glyphs)
137 QSet<glyph_t> unusedGlyphs;
138 for (glyph_t glyphIndex : glyphs) {
139 if (
auto it = m_glyphsData.find(glyphIndex); it != m_glyphsData.end()) {
140 GlyphData &gd = it.value();
142 unusedGlyphs.insert(glyphIndex);
145 releaseGlyphs(unusedGlyphs);
153void QSGDistanceFieldGlyphCache::update()
155 m_populatingGlyphs.clear();
157 if (m_pendingGlyphs.isEmpty())
160 Q_TRACE_SCOPE(QSGDistanceFieldGlyphCache_update, m_pendingGlyphs.size());
162 bool profileFrames = QSG_LOG_TIME_GLYPH().isDebugEnabled();
164 qsg_render_timer.start();
165 Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphAdaptationLayerFrame);
166 Q_TRACE(QSGDistanceFieldGlyphCache_glyphRender_entry);
168 QList<QDistanceField> distanceFields;
169 const int pendingGlyphsSize = m_pendingGlyphs.size();
170 distanceFields.reserve(pendingGlyphsSize);
171 for (
int i = 0; i < pendingGlyphsSize; ++i) {
172 GlyphData &gd = glyphData(m_pendingGlyphs.at(i));
174 QSize size = QSize(qCeil(gd.texCoord.width + gd.texCoord.xMargin * 2),
175 qCeil(gd.texCoord.height + gd.texCoord.yMargin * 2));
177 distanceFields.append(QDistanceField(size,
179 m_pendingGlyphs.at(i),
180 m_doubleGlyphResolution));
181 gd.path = QPainterPath();
184 qint64 renderTime = 0;
185 int count = m_pendingGlyphs.size();
187 renderTime = qsg_render_timer.nsecsElapsed();
189 Q_TRACE(QSGDistanceFieldGlyphCache_glyphRender_exit);
190 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphAdaptationLayerFrame,
191 QQuickProfiler::SceneGraphAdaptationLayerGlyphRender);
192 Q_TRACE(QSGDistanceFieldGlyphCache_glyphStore_entry);
194 m_pendingGlyphs.reset();
196 storeGlyphs(distanceFields);
198#if defined(QSG_DISTANCEFIELD_CACHE_DEBUG)
199 for (Texture texture : std::as_const(m_textures))
200 saveTexture(texture.texture, m_referenceFont.familyName());
203 if (QSG_LOG_TIME_GLYPH().isDebugEnabled()) {
204 quint64 now = qsg_render_timer.elapsed();
205 qCDebug(QSG_LOG_TIME_GLYPH,
206 "distancefield: %d glyphs prepared in %dms, rendering=%d, upload=%d",
209 int(renderTime / 1000000),
210 int((now - (renderTime / 1000000))));
212 Q_TRACE(QSGDistanceFieldGlyphCache_glyphStore_exit);
213 Q_QUICK_SG_PROFILE_END_WITH_PAYLOAD(QQuickProfiler::SceneGraphAdaptationLayerFrame,
214 QQuickProfiler::SceneGraphAdaptationLayerGlyphStore,
218void QSGDistanceFieldGlyphCache::setGlyphsPosition(
const QList<GlyphPosition> &glyphs)
220 QList<quint32> invalidatedGlyphs;
222 int count = glyphs.size();
223 for (
int i = 0; i < count; ++i) {
224 GlyphPosition glyph = glyphs.at(i);
225 GlyphData &gd = glyphData(glyph.glyph);
227 if (!gd.texCoord.isNull())
228 invalidatedGlyphs.append(glyph.glyph);
230 gd.texCoord.xMargin = QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution));
231 gd.texCoord.yMargin = QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution));
232 gd.texCoord.x = glyph.position.x();
233 gd.texCoord.y = glyph.position.y();
234 gd.texCoord.width = gd.boundingRect.width();
235 gd.texCoord.height = gd.boundingRect.height();
238 if (!invalidatedGlyphs.isEmpty()) {
239 for (QSGDistanceFieldGlyphConsumerList::iterator iter = m_registeredNodes.begin(); iter != m_registeredNodes.end(); ++iter) {
240 iter->invalidateGlyphs(invalidatedGlyphs);
250void QSGDistanceFieldGlyphCache::setGlyphsTexture(
const QList<glyph_t> &glyphs,
const Texture &tex)
252 int i = m_textures.indexOf(tex);
254 m_textures.append(tex);
255 i = m_textures.size() - 1;
257 m_textures[i].size = tex.size;
259 Texture *texture = &(m_textures[i]);
261 QList<quint32> invalidatedGlyphs;
263 int count = glyphs.size();
264 for (
int j = 0; j < count; ++j) {
265 glyph_t glyphIndex = glyphs.at(j);
266 GlyphData &gd = glyphData(glyphIndex);
267 if (gd.texture != &s_emptyTexture)
268 invalidatedGlyphs.append(glyphIndex);
269 gd.texture = texture;
272 if (!invalidatedGlyphs.isEmpty()) {
273 for (QSGDistanceFieldGlyphConsumerList::iterator iter = m_registeredNodes.begin(); iter != m_registeredNodes.end(); ++iter) {
274 iter->invalidateGlyphs(invalidatedGlyphs);
286void QSGDistanceFieldGlyphCache::updateRhiTexture(QRhiTexture *oldTex, QRhiTexture *newTex,
const QSize &newTexSize)
288 int count = m_textures.size();
289 for (
int i = 0; i < count; ++i) {
290 Texture &tex = m_textures[i];
291 if (tex.texture == oldTex) {
292 tex.texture = newTex;
293 tex.size = newTexSize;
302void QSGNodeVisitorEx::visitChildren(QSGNode *node)
304 for (QSGNode *child = node->firstChild(); child; child = child->nextSibling()) {
305 switch (child->type()) {
306 case QSGNode::ClipNodeType: {
307 QSGClipNode *c =
static_cast<QSGClipNode*>(child);
313 case QSGNode::TransformNodeType: {
314 QSGTransformNode *c =
static_cast<QSGTransformNode*>(child);
320 case QSGNode::OpacityNodeType: {
321 QSGOpacityNode *c =
static_cast<QSGOpacityNode*>(child);
327 case QSGNode::GeometryNodeType: {
328 if (child->flags() & QSGNode::IsVisitableNode) {
329 QSGVisitableNode *v =
static_cast<QSGVisitableNode*>(child);
332 QSGGeometryNode *c =
static_cast<QSGGeometryNode*>(child);
339 case QSGNode::RootNodeType: {
340 QSGRootNode *root =
static_cast<QSGRootNode*>(child);
346 case QSGNode::BasicNodeType: {
347 visitChildren(child);
350 case QSGNode::RenderNodeType: {
351 QSGRenderNode *r =
static_cast<QSGRenderNode*>(child);
377QDebug operator<<(QDebug debug,
const QSGGuiThreadShaderEffectManager::ShaderInfo::Variable &v)
379 QDebugStateSaver saver(debug);
383 case QSGGuiThreadShaderEffectManager::ShaderInfo::Constant:
384 debug <<
"cvar" <<
"offset" << v.offset <<
"size" << v.size;
386 case QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler:
387 debug <<
"sampler" <<
"bindpoint" << v.bindPoint;
389 case QSGGuiThreadShaderEffectManager::ShaderInfo::Texture:
390 debug <<
"texture" <<
"bindpoint" << v.bindPoint;