aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>2022-03-18 12:57:01 +0100
committerEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>2022-04-08 07:48:57 +0200
commit2fb43a35dfa08bb0746913e3363f1fcf21815e72 (patch)
treef21107060994df759deb2ba8cfebb55113e4f5dc /src/quick/scenegraph
parent54a71e8c83de9b0312c920bc52378efcf20d537b (diff)
Invalidate text when application fonts are added or removed
We had multiple related issues due to application fonts being added or removed during the application lifetime. 1. If a text had font family "foo" set, and this font did not exist at the time, then loading "foo" at a later stage would not update the text to use the correct font, since the result of the previous request had been cached. 2. A variation of #1 was if the font "foo" was loaded by a FontLoader in the scene and referred to by name in the text component. In this case, there was a race condition, where the font lookup would sometimes yield different results on the main thread and on the render thread, and text would be garbled. 3. When a font was removed from the font database, then references to it would remain in the caches (glyph cache + font cache) in the render thread. With certain backends (DirectWrite, CoreText) this caused errors or even crashes, as the cached font engines would be referring to data that had been removed. The work-around for #1 and #2 was merely to avoid hardcoding names for fonts, but instead getting them from the FontLoader. This way, you can avoid requesting the font family before it is available (and thus avoid caching the wrong result). However, for #3 there is no known work-around. This patch fixes all three (together with a smaller patch for qtbase) by invalidating all text and related caches in Qt Quick when fonts are either added or removed from the font database. This does add some overhead if font loading happens during runtime, but the alternative is broken behavior and dangling pointers. This is done during the synchronization step. Before synchronization, the font cache is flushed and all text components are marked for update, so that fonts are re-requested against the new font database. After synchronization, we delete all distance field glyph caches which are not currently in use, to avoid having references to stale application font data in the list. [ChangeLog][Text] Fix multiple issues with usage of application fonts when they are added or removed during the lifetime of the application. Task-number: QTBUG-100697 Task-number: QDS-1142 Change-Id: Ib309e54e0ee97b6be6d2a7211964043fd51c9ec5 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Diffstat (limited to 'src/quick/scenegraph')
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer.cpp5
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h1
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp4
-rw-r--r--src/quick/scenegraph/qsgcontext_p.h1
-rw-r--r--src/quick/scenegraph/qsgdefaultrendercontext.cpp13
-rw-r--r--src/quick/scenegraph/qsgdefaultrendercontext_p.h1
-rw-r--r--src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp5
-rw-r--r--src/quick/scenegraph/qsgrhidistancefieldglyphcache_p.h1
8 files changed, 31 insertions, 0 deletions
diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp
index 9d18868c58..a35c1dc5a6 100644
--- a/src/quick/scenegraph/qsgadaptationlayer.cpp
+++ b/src/quick/scenegraph/qsgadaptationlayer.cpp
@@ -170,6 +170,11 @@ void QSGDistanceFieldGlyphCache::release(const QVector<glyph_t> &glyphs)
releaseGlyphs(unusedGlyphs);
}
+bool QSGDistanceFieldGlyphCache::isActive() const
+{
+ return true;
+}
+
void QSGDistanceFieldGlyphCache::update()
{
m_populatingGlyphs.clear();
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index 03b3889322..d7c5bebbf7 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -495,6 +495,7 @@ public:
virtual bool eightBitFormatIsAlphaSwizzled() const = 0;
virtual bool screenSpaceDerivativesSupported() const = 0;
+ virtual bool isActive() const;
protected:
struct GlyphPosition {
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index 695af6b127..a5e0e5e035 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -432,6 +432,10 @@ QSGDistanceFieldGlyphCache *QSGRenderContext::distanceFieldGlyphCache(const QRaw
return nullptr;
}
+void QSGRenderContext::invalidateGlyphCaches()
+{
+
+}
void QSGRenderContext::registerFontengineForCleanup(QFontEngine *engine)
{
diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h
index 1c6b5c3205..39a3051fe2 100644
--- a/src/quick/scenegraph/qsgcontext_p.h
+++ b/src/quick/scenegraph/qsgcontext_p.h
@@ -198,6 +198,7 @@ public:
virtual void endSync();
virtual void preprocess();
+ virtual void invalidateGlyphCaches();
virtual QSGDistanceFieldGlyphCache *distanceFieldGlyphCache(const QRawFont &font, int renderTypeQuality);
QSGTexture *textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window);
diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
index a4337a58ca..508870fbd5 100644
--- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp
+++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
@@ -94,6 +94,19 @@ void QSGDefaultRenderContext::initialize(const QSGRenderContext::InitParams *par
emit initialized();
}
+void QSGDefaultRenderContext::invalidateGlyphCaches()
+{
+ auto it = m_glyphCaches.begin();
+ while (it != m_glyphCaches.end()) {
+ if (!(*it)->isActive()) {
+ delete *it;
+ it = m_glyphCaches.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
void QSGDefaultRenderContext::invalidate()
{
if (!m_rhi)
diff --git a/src/quick/scenegraph/qsgdefaultrendercontext_p.h b/src/quick/scenegraph/qsgdefaultrendercontext_p.h
index a97347eaf0..e233c4c3bd 100644
--- a/src/quick/scenegraph/qsgdefaultrendercontext_p.h
+++ b/src/quick/scenegraph/qsgdefaultrendercontext_p.h
@@ -111,6 +111,7 @@ public:
void endNextRhiFrame(QSGRenderer *renderer) override;
void preprocess() override;
+ void invalidateGlyphCaches() override;
QSGDistanceFieldGlyphCache *distanceFieldGlyphCache(const QRawFont &font, int renderTypeQuality) override;
QSGTexture *createTexture(const QImage &image, uint flags) const override;
diff --git a/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp
index b139c3428a..50a3091c55 100644
--- a/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp
@@ -147,6 +147,11 @@ void QSGRhiDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs)
markGlyphsToRender(glyphsToRender);
}
+bool QSGRhiDistanceFieldGlyphCache::isActive() const
+{
+ return m_unusedGlyphs.size() != m_glyphsTexture.size();
+}
+
void QSGRhiDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField> &glyphs)
{
typedef QHash<TextureInfo *, QVector<glyph_t> > GlyphTextureHash;
diff --git a/src/quick/scenegraph/qsgrhidistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgrhidistancefieldglyphcache_p.h
index 965b496e48..47bf59e3d7 100644
--- a/src/quick/scenegraph/qsgrhidistancefieldglyphcache_p.h
+++ b/src/quick/scenegraph/qsgrhidistancefieldglyphcache_p.h
@@ -72,6 +72,7 @@ public:
bool useTextureResizeWorkaround() const;
bool createFullSizeTextures() const;
+ bool isActive() const override;
int maxTextureSize() const;
void setMaxTextureCount(int max) { m_maxTextureCount = max; }