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 QVector<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 if ((
int) glyphIndex >= glyphCount() && glyphCount() > 0) {
105 qWarning(
"Warning: distance-field glyph is not available with index %d", glyphIndex);
109 GlyphData &gd = glyphData(glyphIndex);
111 referencedGlyphs.insert(glyphIndex);
113 if (gd.texCoord.isValid() || m_populatingGlyphs.contains(glyphIndex))
116 m_populatingGlyphs.insert(glyphIndex);
118 if (gd.boundingRect.isEmpty()) {
119 gd.texCoord.width = 0;
120 gd.texCoord.height = 0;
122 newGlyphs.insert(glyphIndex);
126 referenceGlyphs(referencedGlyphs);
127 if (!newGlyphs.isEmpty())
128 requestGlyphs(newGlyphs);
131void QSGDistanceFieldGlyphCache::release(
const QVector<glyph_t> &glyphs)
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(glyphIndex);
139 unusedGlyphs.insert(glyphIndex);
141 releaseGlyphs(unusedGlyphs);
149void QSGDistanceFieldGlyphCache::update()
151 m_populatingGlyphs.clear();
153 if (m_pendingGlyphs.isEmpty())
156 Q_TRACE_SCOPE(QSGDistanceFieldGlyphCache_update, m_pendingGlyphs.size());
158 bool profileFrames = QSG_LOG_TIME_GLYPH().isDebugEnabled();
160 qsg_render_timer.start();
161 Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphAdaptationLayerFrame);
162 Q_TRACE(QSGDistanceFieldGlyphCache_glyphRender_entry);
164 QList<QDistanceField> distanceFields;
165 const int pendingGlyphsSize = m_pendingGlyphs.size();
166 distanceFields.reserve(pendingGlyphsSize);
167 for (
int i = 0; i < pendingGlyphsSize; ++i) {
168 GlyphData &gd = glyphData(m_pendingGlyphs.at(i));
170 QSize size = QSize(qCeil(gd.texCoord.width + gd.texCoord.xMargin * 2),
171 qCeil(gd.texCoord.height + gd.texCoord.yMargin * 2));
173 distanceFields.append(QDistanceField(size,
175 m_pendingGlyphs.at(i),
176 m_doubleGlyphResolution));
177 gd.path = QPainterPath();
180 qint64 renderTime = 0;
181 int count = m_pendingGlyphs.size();
183 renderTime = qsg_render_timer.nsecsElapsed();
185 Q_TRACE(QSGDistanceFieldGlyphCache_glyphRender_exit);
186 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphAdaptationLayerFrame,
187 QQuickProfiler::SceneGraphAdaptationLayerGlyphRender);
188 Q_TRACE(QSGDistanceFieldGlyphCache_glyphStore_entry);
190 m_pendingGlyphs.reset();
192 storeGlyphs(distanceFields);
194#if defined(QSG_DISTANCEFIELD_CACHE_DEBUG)
195 for (Texture texture : std::as_const(m_textures))
196 saveTexture(texture.texture, m_referenceFont.familyName());
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",
205 int(renderTime / 1000000),
206 int((now - (renderTime / 1000000))));
208 Q_TRACE(QSGDistanceFieldGlyphCache_glyphStore_exit);
209 Q_QUICK_SG_PROFILE_END_WITH_PAYLOAD(QQuickProfiler::SceneGraphAdaptationLayerFrame,
210 QQuickProfiler::SceneGraphAdaptationLayerGlyphStore,
214void QSGDistanceFieldGlyphCache::setGlyphsPosition(
const QList<GlyphPosition> &glyphs)
216 QVector<quint32> invalidatedGlyphs;
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);
223 if (!gd.texCoord.isNull())
224 invalidatedGlyphs.append(glyph.glyph);
226 gd.texCoord.xMargin = QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution));
227 gd.texCoord.yMargin = QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(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();
234 if (!invalidatedGlyphs.isEmpty()) {
235 for (QSGDistanceFieldGlyphConsumerList::iterator iter = m_registeredNodes.begin(); iter != m_registeredNodes.end(); ++iter) {
236 iter->invalidateGlyphs(invalidatedGlyphs);
246void QSGDistanceFieldGlyphCache::setGlyphsTexture(
const QVector<glyph_t> &glyphs,
const Texture &tex)
248 int i = m_textures.indexOf(tex);
250 m_textures.append(tex);
251 i = m_textures.size() - 1;
253 m_textures[i].size = tex.size;
255 Texture *texture = &(m_textures[i]);
257 QVector<quint32> invalidatedGlyphs;
259 int count = glyphs.size();
260 for (
int j = 0; j < count; ++j) {
261 glyph_t glyphIndex = glyphs.at(j);
262 GlyphData &gd = glyphData(glyphIndex);
263 if (gd.texture != &s_emptyTexture)
264 invalidatedGlyphs.append(glyphIndex);
265 gd.texture = texture;
268 if (!invalidatedGlyphs.isEmpty()) {
269 for (QSGDistanceFieldGlyphConsumerList::iterator iter = m_registeredNodes.begin(); iter != m_registeredNodes.end(); ++iter) {
270 iter->invalidateGlyphs(invalidatedGlyphs);
282void QSGDistanceFieldGlyphCache::updateRhiTexture(QRhiTexture *oldTex, QRhiTexture *newTex,
const QSize &newTexSize)
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;
298void QSGNodeVisitorEx::visitChildren(QSGNode *node)
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);
309 case QSGNode::TransformNodeType: {
310 QSGTransformNode *c =
static_cast<QSGTransformNode*>(child);
316 case QSGNode::OpacityNodeType: {
317 QSGOpacityNode *c =
static_cast<QSGOpacityNode*>(child);
323 case QSGNode::GeometryNodeType: {
324 if (child->flags() & QSGNode::IsVisitableNode) {
325 QSGVisitableNode *v =
static_cast<QSGVisitableNode*>(child);
328 QSGGeometryNode *c =
static_cast<QSGGeometryNode*>(child);
335 case QSGNode::RootNodeType: {
336 QSGRootNode *root =
static_cast<QSGRootNode*>(child);
342 case QSGNode::BasicNodeType: {
343 visitChildren(child);
346 case QSGNode::RenderNodeType: {
347 QSGRenderNode *r =
static_cast<QSGRenderNode*>(child);
373QDebug operator<<(QDebug debug,
const QSGGuiThreadShaderEffectManager::ShaderInfo::Variable &v)
375 QDebugStateSaver saver(debug);
379 case QSGGuiThreadShaderEffectManager::ShaderInfo::Constant:
380 debug <<
"cvar" <<
"offset" << v.offset <<
"size" << v.size;
382 case QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler:
383 debug <<
"sampler" <<
"bindpoint" << v.bindPoint;
385 case QSGGuiThreadShaderEffectManager::ShaderInfo::Texture:
386 debug <<
"texture" <<
"bindpoint" << v.bindPoint;