33QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(
const QRawFont &font,
int renderTypeQuality)
34 : m_renderTypeQuality(renderTypeQuality)
37 Q_ASSERT(font.isValid());
39 QRawFontPrivate *fontD = QRawFontPrivate::get(font);
40 m_glyphCount = fontD->fontEngine->glyphCount();
42 m_doubleGlyphResolution = qt_fontHasNarrowOutlines(font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT();
44 m_referenceFont = font;
47 m_referenceFont.setPixelSize(baseFontSize() * QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution));
48 Q_ASSERT(m_referenceFont.isValid());
69QSGDistanceFieldGlyphCache::GlyphData &QSGDistanceFieldGlyphCache::glyphData(glyph_t glyph)
71 QHash<glyph_t, GlyphData>::iterator data = m_glyphsData.find(glyph);
72 if (data == m_glyphsData.end()) {
73 GlyphData &gd = emptyData(glyph);
74 gd.path = m_referenceFont.pathForGlyph(glyph);
76 qreal scaleFactor = qreal(1) / QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution);
78 scaleDown.scale(scaleFactor, scaleFactor);
79 gd.boundingRect = scaleDown.mapRect(gd.path.boundingRect());
83 const qreal pixelSize = baseFontSize();
84 if (QFontEngine::glyphBoundingBoxExceedsLimit(gd.boundingRect.width(),
85 gd.boundingRect.height(),
86 pixelSize * pixelSize)) {
87 gd.boundingRect = QRectF();
88 gd.path = QPainterPath();
96QSGDistanceFieldGlyphCache::Metrics QSGDistanceFieldGlyphCache::glyphMetrics(glyph_t glyph, qreal pixelSize)
98 GlyphData &gd = glyphData(glyph);
99 qreal scale = fontScale(pixelSize);
102 m.width = gd.boundingRect.width() * scale;
103 m.height = gd.boundingRect.height() * scale;
104 m.baselineX = gd.boundingRect.x() * scale;
105 m.baselineY = -gd.boundingRect.y() * scale;
110void QSGDistanceFieldGlyphCache::populate(
const QList<glyph_t> &glyphs)
112 QSet<glyph_t> referencedGlyphs;
113 QSet<glyph_t> newGlyphs;
114 int count = glyphs.size();
115 for (
int i = 0; i < count; ++i) {
116 glyph_t glyphIndex = glyphs.at(i);
117 const bool isValid =
int(glyphIndex) < glyphCount() || glyphCount() <= 0;
120 qWarning(
"Warning: distance-field glyph is not available with index %d (glyph count: %d, font: %s)",
123 qPrintable(m_referenceFont.familyName()));
126 GlyphData &gd = isValid ? glyphData(glyphIndex) : emptyData(glyphIndex);
128 referencedGlyphs.insert(glyphIndex);
130 if (gd.texCoord.isValid() || m_populatingGlyphs.contains(glyphIndex))
133 m_populatingGlyphs.insert(glyphIndex);
135 if (gd.boundingRect.isEmpty()) {
136 gd.texCoord.width = 0;
137 gd.texCoord.height = 0;
139 newGlyphs.insert(glyphIndex);
143 referenceGlyphs(referencedGlyphs);
144 if (!newGlyphs.isEmpty())
145 requestGlyphs(newGlyphs);
148void QSGDistanceFieldGlyphCache::release(
const QList<glyph_t> &glyphs)
150 QSet<glyph_t> unusedGlyphs;
151 for (glyph_t glyphIndex : glyphs) {
152 if (
auto it = m_glyphsData.find(glyphIndex); it != m_glyphsData.end()) {
153 GlyphData &gd = it.value();
155 unusedGlyphs.insert(glyphIndex);
158 releaseGlyphs(unusedGlyphs);
166void QSGDistanceFieldGlyphCache::update()
168 m_populatingGlyphs.clear();
170 if (m_pendingGlyphs.isEmpty())
173 Q_TRACE_SCOPE(QSGDistanceFieldGlyphCache_update, m_pendingGlyphs.size());
175 bool profileFrames = QSG_LOG_TIME_GLYPH().isDebugEnabled();
177 qsg_render_timer.start();
178 Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphAdaptationLayerFrame);
179 Q_TRACE(QSGDistanceFieldGlyphCache_glyphRender_entry);
181 QList<QDistanceField> distanceFields;
182 const int pendingGlyphsSize = m_pendingGlyphs.size();
183 distanceFields.reserve(pendingGlyphsSize);
184 for (
int i = 0; i < pendingGlyphsSize; ++i) {
185 GlyphData &gd = glyphData(m_pendingGlyphs.at(i));
187 QSize size = QSize(qCeil(gd.texCoord.width + gd.texCoord.xMargin * 2),
188 qCeil(gd.texCoord.height + gd.texCoord.yMargin * 2));
190 distanceFields.append(QDistanceField(size,
192 m_pendingGlyphs.at(i),
193 m_doubleGlyphResolution));
194 gd.path = QPainterPath();
197 qint64 renderTime = 0;
198 int count = m_pendingGlyphs.size();
200 renderTime = qsg_render_timer.nsecsElapsed();
202 Q_TRACE(QSGDistanceFieldGlyphCache_glyphRender_exit);
203 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphAdaptationLayerFrame,
204 QQuickProfiler::SceneGraphAdaptationLayerGlyphRender);
205 Q_TRACE(QSGDistanceFieldGlyphCache_glyphStore_entry);
207 m_pendingGlyphs.reset();
209 storeGlyphs(distanceFields);
211#if defined(QSG_DISTANCEFIELD_CACHE_DEBUG)
212 for (
const Texture *texture : std::as_const(m_textures))
213 saveTexture(texture->texture, m_referenceFont.familyName());
216 if (QSG_LOG_TIME_GLYPH().isDebugEnabled()) {
217 quint64 now = qsg_render_timer.elapsed();
218 qCDebug(QSG_LOG_TIME_GLYPH,
219 "distancefield: %d glyphs prepared in %dms, rendering=%d, upload=%d",
222 int(renderTime / 1000000),
223 int((now - (renderTime / 1000000))));
225 Q_TRACE(QSGDistanceFieldGlyphCache_glyphStore_exit);
226 Q_QUICK_SG_PROFILE_END_WITH_PAYLOAD(QQuickProfiler::SceneGraphAdaptationLayerFrame,
227 QQuickProfiler::SceneGraphAdaptationLayerGlyphStore,
231void QSGDistanceFieldGlyphCache::setGlyphsPosition(
const QList<GlyphPosition> &glyphs)
233 QList<quint32> invalidatedGlyphs;
235 int count = glyphs.size();
236 for (
int i = 0; i < count; ++i) {
237 GlyphPosition glyph = glyphs.at(i);
238 GlyphData &gd = glyphData(glyph.glyph);
240 if (!gd.texCoord.isNull())
241 invalidatedGlyphs.append(glyph.glyph);
243 gd.texCoord.xMargin = QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution));
244 gd.texCoord.yMargin = QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution));
245 gd.texCoord.x = glyph.position.x();
246 gd.texCoord.y = glyph.position.y();
247 gd.texCoord.width = gd.boundingRect.width();
248 gd.texCoord.height = gd.boundingRect.height();
251 if (!invalidatedGlyphs.isEmpty()) {
252 for (QSGDistanceFieldGlyphConsumerList::iterator iter = m_registeredNodes.begin(); iter != m_registeredNodes.end(); ++iter) {
253 iter->invalidateGlyphs(invalidatedGlyphs);
263void QSGDistanceFieldGlyphCache::setGlyphsTexture(
const QList<glyph_t> &glyphs,
const Texture &tex)
265 Texture *texture =
nullptr;
266 for (Texture *t : std::as_const(m_textures)) {
269 texture->size = tex.size;
273 if (texture ==
nullptr) {
274 texture =
new Texture(tex);
275 m_textures.append(texture);
278 QList<quint32> invalidatedGlyphs;
280 int count = glyphs.size();
281 for (
int j = 0; j < count; ++j) {
282 glyph_t glyphIndex = glyphs.at(j);
283 GlyphData &gd = glyphData(glyphIndex);
284 if (gd.texture != &s_emptyTexture)
285 invalidatedGlyphs.append(glyphIndex);
286 gd.texture = texture;
289 if (!invalidatedGlyphs.isEmpty()) {
290 for (QSGDistanceFieldGlyphConsumerList::iterator iter = m_registeredNodes.begin(); iter != m_registeredNodes.end(); ++iter) {
291 iter->invalidateGlyphs(invalidatedGlyphs);
317void QSGNodeVisitorEx::visitChildren(QSGNode *node)
319 for (QSGNode *child = node->firstChild(); child; child = child->nextSibling()) {
320 switch (child->type()) {
321 case QSGNode::ClipNodeType: {
322 QSGClipNode *c =
static_cast<QSGClipNode*>(child);
328 case QSGNode::TransformNodeType: {
329 QSGTransformNode *c =
static_cast<QSGTransformNode*>(child);
335 case QSGNode::OpacityNodeType: {
336 QSGOpacityNode *c =
static_cast<QSGOpacityNode*>(child);
342 case QSGNode::GeometryNodeType: {
343 if (child->flags() & QSGNode::IsVisitableNode) {
344 QSGVisitableNode *v =
static_cast<QSGVisitableNode*>(child);
347 QSGGeometryNode *c =
static_cast<QSGGeometryNode*>(child);
354 case QSGNode::RootNodeType: {
355 QSGRootNode *root =
static_cast<QSGRootNode*>(child);
361 case QSGNode::BasicNodeType: {
362 visitChildren(child);
365 case QSGNode::RenderNodeType: {
366 QSGRenderNode *r =
static_cast<QSGRenderNode*>(child);
392QDebug operator<<(QDebug debug,
const QSGGuiThreadShaderEffectManager::ShaderInfo::Variable &v)
394 QDebugStateSaver saver(debug);
398 case QSGGuiThreadShaderEffectManager::ShaderInfo::Constant:
399 debug <<
"cvar" <<
"offset" << v.offset <<
"size" << v.size;
401 case QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler:
402 debug <<
"sampler" <<
"bindpoint" << v.bindPoint;
404 case QSGGuiThreadShaderEffectManager::ShaderInfo::Texture:
405 debug <<
"texture" <<
"bindpoint" << v.bindPoint;