diff options
Diffstat (limited to 'src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp')
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 227 |
1 files changed, 203 insertions, 24 deletions
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 07f3159..c66472c 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -77,6 +77,7 @@ #include <private/qfontengine_p.h> #include <private/qpixmapdata_gl_p.h> #include <private/qdatabuffer_p.h> +#include <private/qstatictext_p_p.h> #include "qglgradientcache_p.h" #include "qglengineshadermanager_p.h" @@ -1189,6 +1190,20 @@ void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel()); } +void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem) +{ + Q_D(QGL2PaintEngineEx); + + ensureActive(); + + QFontEngineGlyphCache::Type glyphType = textItem->fontEngine->glyphFormat >= 0 + ? QFontEngineGlyphCache::Type(textItem->fontEngine->glyphFormat) + : d->glyphCacheType; + + // ### What about huge fonts? These are not passed through cache in drawTextItem(). + d->drawCachedGlyphs(glyphType, textItem, true); +} + void QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src) { Q_D(QGL2PaintEngineEx); @@ -1242,33 +1257,95 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem } if (drawCached) { - d->drawCachedGlyphs(p, glyphType, ti); + QVarLengthArray<QFixedPoint> positions; + QVarLengthArray<glyph_t> glyphs; + QTransform matrix = QTransform::fromTranslate(p.x(), p.y()); + ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); + + { + QStaticTextItem staticTextItem; + staticTextItem.chars = ti.chars; + staticTextItem.fontEngine = ti.fontEngine; + staticTextItem.glyphs = glyphs.data(); + staticTextItem.numChars = ti.num_chars; + staticTextItem.numGlyphs = glyphs.size(); + staticTextItem.glyphPositions = positions.data(); + + d->drawCachedGlyphs(glyphType, &staticTextItem, false); + } return; } QPaintEngineEx::drawTextItem(p, ti); } -void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType, - const QTextItemInt &ti) +#define QSTATICTEXT_USE_INDEXARRAY + +class QOpenGLStaticTextUserData: public QObject, public QStaticTextUserData +{ + Q_OBJECT +public: + QOpenGLStaticTextUserData(QGLContext *glContext) + : QStaticTextUserData(OpenGLUserData), + vertexCoordVBOId(0), textureCoordVBOId(0), ctx(glContext) + { + connect(QGLSignalProxy::instance(), + SIGNAL(aboutToDestroyContext(const QGLContext*)), + SLOT(cleanupGLContextRefs(const QGLContext*))); + } + + ~QOpenGLStaticTextUserData() + { + if (ctx != 0) + cleanupGLContextRefs(ctx); + } + + QGLContext *ctx; + GLuint vertexCoordVBOId; + GLuint textureCoordVBOId; + +#if defined(QSTATICTEXT_USE_INDEXARRAY) + QVector<GLuint> indices; +#endif + +public Q_SLOTS: + void cleanupGLContextRefs(const QGLContext *context) + { + if (context == ctx) { + if (vertexCoordVBOId != 0) + glDeleteBuffers(1, &vertexCoordVBOId); + + if (textureCoordVBOId != 0) + glDeleteBuffers(1, &textureCoordVBOId); + + vertexCoordVBOId = 0; + textureCoordVBOId = 0; + } + } +}; + +void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, + QStaticTextItem *staticTextItem, + bool includeMatrixInCache) { Q_Q(QGL2PaintEngineEx); - QVarLengthArray<QFixedPoint> positions; - QVarLengthArray<glyph_t> glyphs; - QTransform matrix = QTransform::fromTranslate(p.x(), p.y()); - ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); + QOpenGL2PaintEngineState *s = q->state(); QGLTextureGlyphCache *cache = - (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, glyphType, QTransform()); - + (QGLTextureGlyphCache *) staticTextItem->fontEngine->glyphCache(ctx, glyphType, + includeMatrixInCache + ? s->matrix + : QTransform()); if (!cache || cache->cacheType() != glyphType) { - cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform()); - ti.fontEngine->setGlyphCache(ctx, cache); + cache = new QGLTextureGlyphCache(ctx, glyphType, + includeMatrixInCache ? s->matrix : QTransform()); + staticTextItem->fontEngine->setGlyphCache(ctx, cache); } cache->setPaintEnginePrivate(this); - cache->populate(ti, glyphs, positions); + cache->populate(staticTextItem->fontEngine, staticTextItem->numGlyphs, staticTextItem->glyphs, + staticTextItem->glyphPositions); if (cache->width() == 0 || cache->height() == 0) return; @@ -1280,20 +1357,103 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly GLfloat dx = 1.0 / cache->width(); GLfloat dy = 1.0 / cache->height(); - vertexCoordinateArray.clear(); - textureCoordinateArray.clear(); +#if defined(QSTATICTEXT_USE_INDEXARRAY) + QVector<GLuint> indices; +#endif + + bool recreateVertexArrays = false; + if (staticTextItem->userDataNeedsUpdate) + recreateVertexArrays = true; + else if (staticTextItem->userData == 0) + recreateVertexArrays = true; + else if (staticTextItem->userData->type != QStaticTextUserData::OpenGLUserData) + recreateVertexArrays = true; + else if (static_cast<QOpenGLStaticTextUserData *>(staticTextItem->userData)->ctx != ctx) + recreateVertexArrays = true; + + if (recreateVertexArrays) { + vertexCoordinateArray.clear(); + textureCoordinateArray.clear(); + +#if defined(QSTATICTEXT_USE_INDEXARRAY) + QStaticTextUserData *uData = staticTextItem->userData; + QOpenGLStaticTextUserData *openGlUserData = uData != 0 + && uData->type == QStaticTextUserData::OpenGLUserData + ? static_cast<QOpenGLStaticTextUserData *>(uData) + : 0; + bool updateIndices = openGlUserData == 0 + || openGlUserData->indices.size() < staticTextItem->numGlyphs; + int j=0; +#endif + + for (int i=0; i<staticTextItem->numGlyphs; ++i) { + const QTextureGlyphCache::Coord &c = cache->coords.value(staticTextItem->glyphs[i]); + int x = staticTextItem->glyphPositions[i].x.toInt() + c.baseLineX - margin; + int y = staticTextItem->glyphPositions[i].y.toInt() - c.baseLineY - margin; + + vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h)); + textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); + +#if defined(QSTATICTEXT_USE_INDEXARRAY) + if (updateIndices) { + for (int k=0; k<6; ++k) + indices.append(j++); + } +#endif + } + + if (staticTextItem->useBackendOptimizations) { + QOpenGLStaticTextUserData *userData = + staticTextItem->userData != 0 && staticTextItem->userData->type == QStaticTextUserData::OpenGLUserData + ? static_cast<QOpenGLStaticTextUserData *>(staticTextItem->userData) + : new QOpenGLStaticTextUserData(ctx); + + int vertexCoordinateArraySize = vertexCoordinateArray.vertexCount() * sizeof(QGLPoint); + if (userData->vertexCoordVBOId == 0) + glGenBuffers(1, &userData->vertexCoordVBOId); + + int textureCoordinateArraySize = textureCoordinateArray.vertexCount() * sizeof(QGLPoint); + if (userData->textureCoordVBOId == 0) + glGenBuffers(1, &userData->textureCoordVBOId); + + glBindBuffer(GL_ARRAY_BUFFER, userData->vertexCoordVBOId); + glBufferData(GL_ARRAY_BUFFER, vertexCoordinateArraySize, + vertexCoordinateArray.data(), GL_STATIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, userData->textureCoordVBOId); + glBufferData(GL_ARRAY_BUFFER, textureCoordinateArraySize, + textureCoordinateArray.data(), GL_STATIC_DRAW); - for (int i=0; i<glyphs.size(); ++i) { - const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]); - int x = positions[i].x.toInt() + c.baseLineX - margin; - int y = positions[i].y.toInt() - c.baseLineY - margin; +#if defined(QSTATICTEXT_USE_INDEXARRAY) + if (updateIndices) + userData->indices = indices; +#endif + + // If a new user data has been created, make sure we delete the old + staticTextItem->setUserData(userData); + staticTextItem->userDataNeedsUpdate = false; - vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h)); - textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); + } else { + setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data()); + setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data()); + } } + if (staticTextItem->useBackendOptimizations) { + Q_ASSERT(staticTextItem->userData != 0); + Q_ASSERT(staticTextItem->userData->type == QStaticTextUserData::OpenGLUserData); - setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data()); - setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data()); + QOpenGLStaticTextUserData *userData = static_cast<QOpenGLStaticTextUserData *>(staticTextItem->userData); + + glBindBuffer(GL_ARRAY_BUFFER, userData->vertexCoordVBOId); + glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, 0); + + glBindBuffer(GL_ARRAY_BUFFER, userData->textureCoordVBOId); + glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, 0); + +#if defined(QSTATICTEXT_USE_INDEXARRAY) + indices = userData->indices; +#endif + } if (addOffset) { addOffset = false; @@ -1307,6 +1467,12 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly QBrush pensBrush = q->state()->pen.brush(); setBrush(pensBrush); + // When painting a QStaticTextItem, the glyph positions are already in device coordinates, + // therefore we temporarily set an identity matrix on the painter for the draw call to + // avoid transforming the positions twice. + QTransform old = s->matrix; + if (includeMatrixInCache) + s->matrix = QTransform(); if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) { // Subpixel antialiasing without gamma correction @@ -1360,7 +1526,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT); - glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size()); + glDrawArrays(GL_TRIANGLES, 0, 6 * staticTextItem->numGlyphs); shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMaskPass2); @@ -1390,7 +1556,18 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT); - glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size()); + +#if defined(QSTATICTEXT_USE_INDEXARRAY) + glDrawElements(GL_TRIANGLES, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_INT, indices.constData()); +#else + glDrawArrays(GL_TRIANGLES, 0, 6 * staticTextItem->numGlyphs); +#endif + + // Reset bindings + glBindBuffer(GL_ARRAY_BUFFER, 0); + + if (includeMatrixInCache) + s->matrix = old; } void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints) @@ -2014,3 +2191,5 @@ QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState() } QT_END_NAMESPACE + +#include "qpaintengineex_opengl2.moc" |