summaryrefslogtreecommitdiffstats
path: root/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp')
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp227
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"