From 72f161739b270b01807f97cd853030440f0fd430 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 19 Nov 2010 12:38:36 +0100 Subject: Fix possible corrupted text when gl glyph cache becomes full When the OpenGL glyph cache filled up (the max texture size on the hardware was exceeded) the characters would be drawn as black blocks instead. As a work-around for this, the cache will now be cleared and repopulated whenever this happens, meaning that once in a while (when a lot of different glyphs have been drawn in a font) there will be a performance hit. A more complete solution is described in QTBUG-13784, but this requires so much refactoring that it was deemed too risky for a patch release. This patch fixes the problem with a small penalty and low risk. Task-number: QT-3971 Reviewed-by: Samuel --- src/gui/painting/qtextureglyphcache.cpp | 13 ++++++++++--- src/gui/painting/qtextureglyphcache_p.h | 2 +- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 9 +++++++-- src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp | 19 ++++++++++++++++++- src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h | 2 ++ 5 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index b609f7b..2cd7780 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -65,7 +65,7 @@ static inline int qt_next_power_of_two(int v) return v; } -void QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs, +bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs, const QFixedPoint *) { #ifdef CACHE_DEBUG @@ -119,7 +119,7 @@ void QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const rowHeight = qMax(rowHeight, glyph_height); } if (listItemCoordinates.isEmpty()) - return; + return true; rowHeight += margin * 2 + paddingDoubled; if (isNull()) @@ -150,6 +150,13 @@ void QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const int new_height = m_h*2; while (new_height < m_cy + c.h) new_height *= 2; + + if (new_height > maxTextureHeight()) { + // We can't make a new texture of the required size, so + // bail out + return false; + } + // if no room in the current texture - realloc a larger texture resizeTextureData(m_w, new_height); m_h = new_height; @@ -165,7 +172,7 @@ void QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const ++iter; } - + return true; } QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g) const diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h index e6d2b22..f84d1e6 100644 --- a/src/gui/painting/qtextureglyphcache_p.h +++ b/src/gui/painting/qtextureglyphcache_p.h @@ -96,7 +96,7 @@ public: int baseLineY; }; - void populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs, + bool populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions); virtual void createTextureData(int width, int height) = 0; diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 37552ac..3ddc15a 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1499,8 +1499,13 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp // cache so this text is performed before we test if the cache size has changed. if (recreateVertexArrays) { cache->setPaintEnginePrivate(this); - cache->populate(staticTextItem->fontEngine(), staticTextItem->numGlyphs, - staticTextItem->glyphs, staticTextItem->glyphPositions); + if (!cache->populate(staticTextItem->fontEngine(), staticTextItem->numGlyphs, + staticTextItem->glyphs, staticTextItem->glyphPositions)) { + // No space in cache. We need to clear the cache and try again + cache->clear(); + cache->populate(staticTextItem->fontEngine(), staticTextItem->numGlyphs, + staticTextItem->glyphs, staticTextItem->glyphPositions); + } } if (cache->width() == 0 || cache->height() == 0) diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp index 28e8c40..705ad09 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp @@ -78,7 +78,7 @@ void QGLTextureGlyphCache::setContext(QGLContext *context) SLOT(contextDestroyed(const QGLContext*))); } -QGLTextureGlyphCache::~QGLTextureGlyphCache() +void QGLTextureGlyphCache::clear() { if (ctx) { QGLShareContextScope scope(ctx); @@ -88,7 +88,24 @@ QGLTextureGlyphCache::~QGLTextureGlyphCache() if (m_width || m_height) glDeleteTextures(1, &m_texture); + + m_fbo = 0; + m_texture = 0; + m_width = 0; + m_height = 0; + m_w = 0; + m_h = 0; + m_cx = 0; + m_cy = 0; + m_currentRowHeight = 0; + coords.clear(); } + +} + +QGLTextureGlyphCache::~QGLTextureGlyphCache() +{ + clear(); } void QGLTextureGlyphCache::createTextureData(int width, int height) diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h index fa2b091..aaef350 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h @@ -124,6 +124,8 @@ public Q_SLOTS: } } + void clear(); + private: QGLContext *ctx; -- cgit v0.12