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());
68QSGDistanceFieldGlyphCache::GlyphData &QSGDistanceFieldGlyphCache::glyphData(glyph_t glyph)
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);
75 qreal scaleFactor = qreal(1) / QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution);
77 scaleDown.scale(scaleFactor, scaleFactor);
78 gd.boundingRect = scaleDown.mapRect(gd.path.boundingRect());
84QSGDistanceFieldGlyphCache::Metrics QSGDistanceFieldGlyphCache::glyphMetrics(glyph_t glyph, qreal pixelSize)
86 GlyphData &gd = glyphData(glyph);
87 qreal scale = fontScale(pixelSize);
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;
98void QSGDistanceFieldGlyphCache::populate(
const QList<glyph_t> &glyphs)
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;
108 qWarning(
"Warning: distance-field glyph is not available with index %d (glyph count: %d, font: %s)",
111 qPrintable(m_referenceFont.familyName()));
114 GlyphData &gd = isValid ? glyphData(glyphIndex) : emptyData(glyphIndex);
116 referencedGlyphs.insert(glyphIndex);
118 if (gd.texCoord.isValid() || m_populatingGlyphs.contains(glyphIndex))
121 m_populatingGlyphs.insert(glyphIndex);
123 if (gd.boundingRect.isEmpty()) {
124 gd.texCoord.width = 0;
125 gd.texCoord.height = 0;
127 newGlyphs.insert(glyphIndex);
131 referenceGlyphs(referencedGlyphs);
132 if (!newGlyphs.isEmpty())
133 requestGlyphs(newGlyphs);
136void QSGDistanceFieldGlyphCache::release(
const QList<glyph_t> &glyphs)
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();
143 unusedGlyphs.insert(glyphIndex);
146 releaseGlyphs(unusedGlyphs);
154void QSGDistanceFieldGlyphCache::update()
156 m_populatingGlyphs.clear();
158 if (m_pendingGlyphs.isEmpty())
161 Q_TRACE_SCOPE(QSGDistanceFieldGlyphCache_update, m_pendingGlyphs.size());
163 bool profileFrames = QSG_LOG_TIME_GLYPH().isDebugEnabled();
165 qsg_render_timer.start();
166 Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphAdaptationLayerFrame);
167 Q_TRACE(QSGDistanceFieldGlyphCache_glyphRender_entry);
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));
175 QSize size = QSize(qCeil(gd.texCoord.width + gd.texCoord.xMargin * 2),
176 qCeil(gd.texCoord.height + gd.texCoord.yMargin * 2));
178 distanceFields.append(QDistanceField(size,
180 m_pendingGlyphs.at(i),
181 m_doubleGlyphResolution));
182 gd.path = QPainterPath();
185 qint64 renderTime = 0;
186 int count = m_pendingGlyphs.size();
188 renderTime = qsg_render_timer.nsecsElapsed();
190 Q_TRACE(QSGDistanceFieldGlyphCache_glyphRender_exit);
191 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphAdaptationLayerFrame,
192 QQuickProfiler::SceneGraphAdaptationLayerGlyphRender);
193 Q_TRACE(QSGDistanceFieldGlyphCache_glyphStore_entry);
195 m_pendingGlyphs.reset();
197 storeGlyphs(distanceFields);
199#if defined(QSG_DISTANCEFIELD_CACHE_DEBUG)
200 for (Texture texture : std::as_const(m_textures))
201 saveTexture(texture.texture, m_referenceFont.familyName());
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",
210 int(renderTime / 1000000),
211 int((now - (renderTime / 1000000))));
213 Q_TRACE(QSGDistanceFieldGlyphCache_glyphStore_exit);
214 Q_QUICK_SG_PROFILE_END_WITH_PAYLOAD(QQuickProfiler::SceneGraphAdaptationLayerFrame,
215 QQuickProfiler::SceneGraphAdaptationLayerGlyphStore,
219void QSGDistanceFieldGlyphCache::setGlyphsPosition(
const QList<GlyphPosition> &glyphs)
221 QList<quint32> invalidatedGlyphs;
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);
228 if (!gd.texCoord.isNull())
229 invalidatedGlyphs.append(glyph.glyph);
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();
239 if (!invalidatedGlyphs.isEmpty()) {
240 for (QSGDistanceFieldGlyphConsumerList::iterator iter = m_registeredNodes.begin(); iter != m_registeredNodes.end(); ++iter) {
241 iter->invalidateGlyphs(invalidatedGlyphs);
251void QSGDistanceFieldGlyphCache::setGlyphsTexture(
const QList<glyph_t> &glyphs,
const Texture &tex)
253 int i = m_textures.indexOf(tex);
255 m_textures.append(tex);
256 i = m_textures.size() - 1;
258 m_textures[i].size = tex.size;
260 Texture *texture = &(m_textures[i]);
262 QList<quint32> invalidatedGlyphs;
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;
273 if (!invalidatedGlyphs.isEmpty()) {
274 for (QSGDistanceFieldGlyphConsumerList::iterator iter = m_registeredNodes.begin(); iter != m_registeredNodes.end(); ++iter) {
275 iter->invalidateGlyphs(invalidatedGlyphs);
287void QSGDistanceFieldGlyphCache::updateRhiTexture(QRhiTexture *oldTex, QRhiTexture *newTex,
const QSize &newTexSize)
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;
303void QSGNodeVisitorEx::visitChildren(QSGNode *node)
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);
314 case QSGNode::TransformNodeType: {
315 QSGTransformNode *c =
static_cast<QSGTransformNode*>(child);
321 case QSGNode::OpacityNodeType: {
322 QSGOpacityNode *c =
static_cast<QSGOpacityNode*>(child);
328 case QSGNode::GeometryNodeType: {
329 if (child->flags() & QSGNode::IsVisitableNode) {
330 QSGVisitableNode *v =
static_cast<QSGVisitableNode*>(child);
333 QSGGeometryNode *c =
static_cast<QSGGeometryNode*>(child);
340 case QSGNode::RootNodeType: {
341 QSGRootNode *root =
static_cast<QSGRootNode*>(child);
347 case QSGNode::BasicNodeType: {
348 visitChildren(child);
351 case QSGNode::RenderNodeType: {
352 QSGRenderNode *r =
static_cast<QSGRenderNode*>(child);
378QDebug operator<<(QDebug debug,
const QSGGuiThreadShaderEffectManager::ShaderInfo::Variable &v)
380 QDebugStateSaver saver(debug);
384 case QSGGuiThreadShaderEffectManager::ShaderInfo::Constant:
385 debug <<
"cvar" <<
"offset" << v.offset <<
"size" << v.size;
387 case QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler:
388 debug <<
"sampler" <<
"bindpoint" << v.bindPoint;
390 case QSGGuiThreadShaderEffectManager::ShaderInfo::Texture:
391 debug <<
"texture" <<
"bindpoint" << v.bindPoint;