From e5d437d6899904de2596b0ece4914274cff37561 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 17 Jun 2010 14:28:15 +0200 Subject: Refactor QTextureGlyphCache Separate getting the glyph coordinates from actually making and populating the cache. Calling populate() and fillInPendingGlyphs() immediately after should be equivalent to the old code, except it might have fewer reallocations of the texture since you will only create it one per set of glyphs. This mainly enables populating the GL glyph cache outside a GL context and then actually drawing into it later, when the context has actually been established. Reviewed-by: Kim --- src/gui/painting/qpaintengine_raster.cpp | 1 + src/gui/painting/qtextureglyphcache.cpp | 47 ++++++++++++---- src/gui/painting/qtextureglyphcache_p.h | 12 ++++- src/gui/text/qfont_p.h | 5 ++ .../gl2paintengineex/qpaintengineex_opengl2.cpp | 1 + .../gl2paintengineex/qtextureglyphcache_gl.cpp | 62 +++++++++++++++++----- .../gl2paintengineex/qtextureglyphcache_gl_p.h | 13 ++++- 7 files changed, 114 insertions(+), 27 deletions(-) diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 48974e8..06effd4 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -3009,6 +3009,7 @@ void QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, } cache->populate(fontEngine, numGlyphs, glyphs, positions); + cache->fillInPendingGlyphs(); const QImage &image = cache->image(); int bpl = image.bytesPerLine(); diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index 631a9cf..29cd82b 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -126,8 +126,9 @@ void QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const return; rowHeight += margin * 2 + paddingDoubled; - if (isNull()) - createCache(QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH, qt_next_power_of_two(rowHeight)); + + if (m_w == 0) + m_w = QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH; // now actually use the coords and paint the wanted glyps into cache. QHash::iterator iter = listItemCoordinates.begin(); @@ -142,26 +143,50 @@ void QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const m_cy += m_currentRowHeight + paddingDoubled; m_currentRowHeight = 0; // New row } - if (m_cy + c.h > m_h) { - int new_height = m_h*2; - while (new_height < m_cy + c.h) - new_height *= 2; - // if no room in the current texture - realloc a larger texture - resizeTextureData(m_w, new_height); - m_h = new_height; - } c.x = m_cx; c.y = m_cy; - fillTexture(c, iter.key()); coords.insert(iter.key(), c); + m_pendingGlyphs.insert(iter.key(), c); m_cx += c.w + paddingDoubled; ++iter; } +} + +void QTextureGlyphCache::fillInPendingGlyphs() +{ + if (m_pendingGlyphs.isEmpty()) + return; + + int requiredHeight = 0; + { + QHash::iterator iter = m_pendingGlyphs.begin(); + while (iter != m_pendingGlyphs.end()) { + Coord c = iter.value(); + requiredHeight = qMax(requiredHeight, c.y + c.h); + ++iter; + } + } + + if (requiredHeight > m_h) { + if (isNull()) + createCache(m_w, qt_next_power_of_two(requiredHeight)); + else + resizeCache(m_w, qt_next_power_of_two(requiredHeight)); + } + { + QHash::iterator iter = m_pendingGlyphs.begin(); + while (iter != m_pendingGlyphs.end()) { + fillTexture(iter.value(), iter.key()); + + ++iter; + } + } + m_pendingGlyphs.clear(); } QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g) const diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h index a818978..0770ed4 100644 --- a/src/gui/painting/qtextureglyphcache_p.h +++ b/src/gui/painting/qtextureglyphcache_p.h @@ -94,6 +94,7 @@ public: void populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions); + void fillInPendingGlyphs(); virtual void createTextureData(int width, int height) = 0; virtual void resizeTextureData(int width, int height) = 0; @@ -108,7 +109,14 @@ public: createTextureData(width, height); } - inline bool isNull() const { return m_w <= 0 || m_h <= 0; } + inline void resizeCache(int width, int height) + { + resizeTextureData(width, height); + m_w = width; + m_h = height; + } + + inline bool isNull() const { return m_h == 0; } QHash coords; @@ -117,6 +125,8 @@ public: protected: QFontEngine *m_current_fontengine; + QHash m_pendingGlyphs; + int m_w; // image width int m_h; // image height int m_cx; // current x diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h index 470c109..646a8b8 100644 --- a/src/gui/text/qfont_p.h +++ b/src/gui/text/qfont_p.h @@ -192,6 +192,11 @@ public: QFont smallCapsFont() const { return QFont(smallCapsFontPrivate()); } QFontPrivate *smallCapsFontPrivate() const; + static QFontPrivate *get(const QFont &font) + { + return font.d.data(); + } + void resolve(uint mask, const QFontPrivate *other); private: QFontPrivate &operator=(const QFontPrivate &) { return *this; } diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index ee49a3d..634b315 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1463,6 +1463,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp cache->setPaintEnginePrivate(this); cache->populate(staticTextItem->fontEngine, staticTextItem->numGlyphs, staticTextItem->glyphs, staticTextItem->glyphPositions); + cache->fillInPendingGlyphs(); if (cache->width() == 0 || cache->height() == 0) return; diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp index 5371c5e..e2ec8a1 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp @@ -52,39 +52,65 @@ QT_BEGIN_NAMESPACE extern Q_GUI_EXPORT bool qt_cleartype_enabled; #endif -QGLTextureGlyphCache::QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix) +QGLTextureGlyphCache::QGLTextureGlyphCache(const QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix) : QImageTextureGlyphCache(type, matrix) - , ctx(context) + , ctx(0) , m_width(0) , m_height(0) { - // broken FBO readback is a bug in the SGX 1.3 and 1.4 drivers for the N900 where - // copying between FBO's is broken if the texture is either GL_ALPHA or POT. The - // workaround is to use a system-memory copy of the glyph cache for this device. - // Switching to NPOT and GL_RGBA would both cost a lot more graphics memory and - // be slower, so that is not desireable. - if (!ctx->d_ptr->workaround_brokenFBOReadBack) - glGenFramebuffers(1, &m_fbo); - - connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)), - SLOT(contextDestroyed(const QGLContext*))); + if (context != 0) + setContext(context); } QGLTextureGlyphCache::~QGLTextureGlyphCache() { + cleanUpContext(); +} + +void QGLTextureGlyphCache::cleanUpContext() +{ if (ctx) { QGLShareContextScope scope(ctx); if (!ctx->d_ptr->workaround_brokenFBOReadBack) glDeleteFramebuffers(1, &m_fbo); - if (m_width || m_height) + if (m_width || m_height) { glDeleteTextures(1, &m_texture); + m_width = 0; + m_height = 0; + m_h = 0; + } + + ctx = 0; } } +void QGLTextureGlyphCache::setContext(const QGLContext *context) +{ + cleanUpContext(); + + ctx = context; + + // broken FBO readback is a bug in the SGX 1.3 and 1.4 drivers for the N900 where + // copying between FBO's is broken if the texture is either GL_ALPHA or POT. The + // workaround is to use a system-memory copy of the glyph cache for this device. + // Switching to NPOT and GL_RGBA would both cost a lot more graphics memory and + // be slower, so that is not desireable. + if (!ctx->d_ptr->workaround_brokenFBOReadBack) + glGenFramebuffers(1, &m_fbo); + + connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)), + SLOT(contextDestroyed(const QGLContext*))); +} + void QGLTextureGlyphCache::createTextureData(int width, int height) { + if (ctx == 0) { + qWarning("QGLTextureGlyphCache::createTextureData: Called with no context"); + return; + } + // create in QImageTextureGlyphCache baseclass is meant to be called // only to create the initial image and does not preserve the content, // so we don't call when this function is called from resize. @@ -118,6 +144,11 @@ void QGLTextureGlyphCache::createTextureData(int width, int height) void QGLTextureGlyphCache::resizeTextureData(int width, int height) { + if (ctx == 0) { + qWarning("QGLTextureGlyphCache::resizeTextureData: Called with no context"); + return; + } + int oldWidth = m_width; int oldHeight = m_height; @@ -213,6 +244,11 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height) void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph) { + if (ctx == 0) { + qWarning("QGLTextureGlyphCache::fillTexture: Called with no context"); + return; + } + if (ctx->d_ptr->workaround_brokenFBOReadBack) { QImageTextureGlyphCache::fillTexture(c, glyph); diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h index 84e9021..d291ac3 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h @@ -66,7 +66,7 @@ class Q_OPENGL_EXPORT QGLTextureGlyphCache : public QObject, public QImageTextur { Q_OBJECT public: - QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix); + QGLTextureGlyphCache(const QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix); ~QGLTextureGlyphCache(); virtual void createTextureData(int width, int height); @@ -82,6 +82,13 @@ public: inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; } + void setContext(const QGLContext *context); + inline const QGLContext *context() const + { + return ctx; + } + + public Q_SLOTS: void contextDestroyed(const QGLContext *context) { @@ -105,7 +112,9 @@ public Q_SLOTS: } private: - QGLContext *ctx; + void cleanUpContext(); + + const QGLContext *ctx; QGL2PaintEngineExPrivate *pex; -- cgit v0.12