summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>2010-01-29 15:53:39 (GMT)
committerEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>2010-01-29 15:53:39 (GMT)
commitda388773f581e251054abd037dc410ae52cfa69c (patch)
tree5801db3f2793ff9b9d418b25814db50880427550
parent951922772c0c5f8b8833c2793064f8c6ebeecd9c (diff)
downloadQt-da388773f581e251054abd037dc410ae52cfa69c.zip
Qt-da388773f581e251054abd037dc410ae52cfa69c.tar.gz
Qt-da388773f581e251054abd037dc410ae52cfa69c.tar.bz2
Improve performance of QStaticText on OpenGL by caching data on GPU
There's a big improvement to be seen in the OpenGL engine by caching the vertex data for the QStaticText in VBOs. In order to have the buffers properly disposed, I've implemented a userdata concept for QStaticTextItem. By default, the optimizations will be turned off, and can be turned on by using the useBackendOptimizations flag.
-rw-r--r--src/gui/painting/qpainter.cpp1
-rw-r--r--src/gui/text/qstatictext.cpp43
-rw-r--r--src/gui/text/qstatictext.h3
-rw-r--r--src/gui/text/qstatictext_p.h59
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp92
5 files changed, 173 insertions, 25 deletions
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 54eed03..521072f 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -5800,6 +5800,7 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static
textItem->glyphPositions[i].x += fx - oldX;
textItem->glyphPositions[i].y += fy - oldY;
}
+ textItem->userDataNeedsUpdate = true;
}
staticText_d->position = transformedPosition;
diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp
index 6c960bb..7be89cb 100644
--- a/src/gui/text/qstatictext.cpp
+++ b/src/gui/text/qstatictext.cpp
@@ -236,6 +236,43 @@ QString QStaticText::text() const
}
/*!
+ Sets whether the QStaticText object should use optimizations specific to the paint engine
+ backend if they are available. If \a on is set to true, backend optimizations will be turned
+ on, otherwise they will be turned off. The default value is false.
+
+ If backend optimizations are on, the paint engine used to draw the static text is allowed to
+ store data in the object which will assist it in future calls to drawStaticText. In particular,
+ when using the opengl graphics system, or when painting on a QGLWidget, turning this flag on will
+ improve performance, but increase the memory footprint of the QStaticText object.
+
+ The default value is false.
+
+ \note This function will cause the layout of the text to be recalculated.
+
+ \sa useBackendOptimizations()
+*/
+void QStaticText::setUseBackendOptimizations(bool on)
+{
+ if (on == d_ptr->useBackendOptimizations)
+ return;
+
+ detach();
+ d_ptr->useBackendOptimizations = on;
+ d_ptr->init();
+}
+
+/*!
+ Returns whether the QStaticText object should use optimizations specific to the paint engine
+ backend when possible. By default this setting is false.
+
+ \sa setUseBackendOptimizations()
+*/
+bool QStaticText::useBackendOptimizations() const
+{
+ return d_ptr->useBackendOptimizations;
+}
+
+/*!
Sets the maximum size of the QStaticText to \a maximumSize.
\note This function will cause the layout of the text to be recalculated.
@@ -470,6 +507,12 @@ void QStaticTextPrivate::init()
itemCount = counterDevice.itemCount();
items = new QStaticTextItem[itemCount];
+ if (useBackendOptimizations) {
+ for (int i=0; i<itemCount; ++i)
+ items[i].useBackendOptimizations = true;
+ }
+
+
int glyphCount = counterDevice.glyphCount();
glyphPool = new glyph_t[glyphCount];
positionPool = new QFixedPoint[glyphCount];
diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h
index de2fdb3..d79d887 100644
--- a/src/gui/text/qstatictext.h
+++ b/src/gui/text/qstatictext.h
@@ -73,6 +73,9 @@ public:
void prepare(const QTransform &matrix, const QFont &font);
+ void setUseBackendOptimizations(bool on);
+ bool useBackendOptimizations() const;
+
QStaticText &operator=(const QStaticText &);
bool operator==(const QStaticText &) const;
bool operator!=(const QStaticText &) const;
diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h
index 78f7896..bca59e0 100644
--- a/src/gui/text/qstatictext_p.h
+++ b/src/gui/text/qstatictext_p.h
@@ -57,10 +57,35 @@
QT_BEGIN_NAMESPACE
+class QStaticTextUserData
+{
+public:
+ enum Type {
+ NoUserData,
+ OpenGLUserData
+ };
+
+ QStaticTextUserData(Type t) : type(t) {}
+ virtual ~QStaticTextUserData() {}
+
+ Type type;
+};
+
class Q_GUI_EXPORT QStaticTextItem
{
public:
- QStaticTextItem() : chars(0), numChars(0), fontEngine(0) {}
+ QStaticTextItem() : chars(0), numChars(0), fontEngine(0), userData(0),
+ useBackendOptimizations(false), userDataNeedsUpdate(0) {}
+ ~QStaticTextItem() { delete userData; }
+
+ void setUserData(QStaticTextUserData *newUserData)
+ {
+ if (userData == newUserData)
+ return;
+
+ delete userData;
+ userData = newUserData;
+ }
QFixedPoint *glyphPositions; // 8 bytes per glyph
glyph_t *glyphs; // 4 bytes per glyph
@@ -73,8 +98,11 @@ public:
int numChars; // 4 bytes per item
QFontEngine *fontEngine; // 4 bytes per item
QFont font; // 8 bytes per item
+ QStaticTextUserData *userData; // 8 bytes per item
+ char useBackendOptimizations : 1; // 1 byte per item
+ char userDataNeedsUpdate : 1; //
// ================
- // 32 bytes per item
+ // 41 bytes per item
};
class QStaticText;
@@ -86,22 +114,23 @@ public:
void init();
- QAtomicInt ref; // 4 bytes per text
+ QAtomicInt ref; // 4 bytes per text
- QString text; // 4 bytes per text
- QFont font; // 8 bytes per text
- QSizeF size; // 16 bytes per text
- QPointF position; // 16 bytes per text
+ QString text; // 4 bytes per text
+ QFont font; // 8 bytes per text
+ QSizeF size; // 16 bytes per text
+ QPointF position; // 16 bytes per text
- QTransform matrix; // 80 bytes per text
- QStaticTextItem *items; // 4 bytes per text
- int itemCount; // 4 bytes per text
- glyph_t *glyphPool; // 4 bytes per text
- QFixedPoint *positionPool; // 4 bytes per text
+ QTransform matrix; // 80 bytes per text
+ QStaticTextItem *items; // 4 bytes per text
+ int itemCount; // 4 bytes per text
+ glyph_t *glyphPool; // 4 bytes per text
+ QFixedPoint *positionPool; // 4 bytes per text
- char needsClipRect : 1; // 1 byte per text
- // ================
- // 145 bytes per text
+ char needsClipRect : 1; // 1 byte per text
+ char useBackendOptimizations : 1;
+ // ================
+ // 145 bytes per text
static QStaticTextPrivate *get(const QStaticText *q);
};
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index 4c3b343..f6ef827 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -1284,6 +1284,29 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem
QPaintEngineEx::drawTextItem(p, ti);
}
+namespace {
+
+ class QOpenGLStaticTextUserData: public QStaticTextUserData
+ {
+ public:
+ QOpenGLStaticTextUserData(QGLContext *glContext)
+ : QStaticTextUserData(OpenGLUserData),
+ vertexCoordVBOId(0), textureCoordVBOId(0), ctx(glContext) {}
+ ~QOpenGLStaticTextUserData()
+ {
+ if (vertexCoordVBOId != 0)
+ glDeleteBuffers(1, &vertexCoordVBOId);
+
+ if (textureCoordVBOId != 0)
+ glDeleteBuffers(1, &textureCoordVBOId);
+ }
+
+ QGLContext *ctx;
+ GLuint vertexCoordVBOId;
+ GLuint textureCoordVBOId;
+ };
+}
+
void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, QStaticTextItem *staticTextItem)
{
Q_Q(QGL2PaintEngineEx);
@@ -1309,20 +1332,66 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp
GLfloat dx = 1.0 / cache->width();
GLfloat dy = 1.0 / cache->height();
- vertexCoordinateArray.clear();
- textureCoordinateArray.clear();
+ if (staticTextItem->userData == 0
+ || staticTextItem->userData->type != QStaticTextUserData::OpenGLUserData
+ || staticTextItem->userDataNeedsUpdate) {
+ vertexCoordinateArray.clear();
+ textureCoordinateArray.clear();
+
+ 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 (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_ARB, userData->vertexCoordVBOId);
+ glBufferData(GL_ARRAY_BUFFER_ARB, vertexCoordinateArraySize,
+ vertexCoordinateArray.data(), GL_STATIC_DRAW_ARB);
+
+ glBindBuffer(GL_ARRAY_BUFFER_ARB, userData->textureCoordVBOId);
+ glBufferData(GL_ARRAY_BUFFER_ARB, textureCoordinateArraySize,
+ textureCoordinateArray.data(), GL_STATIC_DRAW_ARB);
- 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;
+ // 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());
+ }
}
- 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);
+
+ QOpenGLStaticTextUserData *userData = static_cast<QOpenGLStaticTextUserData *>(staticTextItem->userData);
+
+ glBindBuffer(GL_ARRAY_BUFFER_ARB, userData->vertexCoordVBOId);
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, 0);
+
+ glBindBuffer(GL_ARRAY_BUFFER_ARB, userData->textureCoordVBOId);
+ glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, 0);
+ }
if (addOffset) {
addOffset = false;
@@ -1420,6 +1489,9 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
glDrawArrays(GL_TRIANGLES, 0, 6 * staticTextItem->numGlyphs);
+
+ // Reset bindings
+ glBindBuffer(GL_ARRAY_BUFFER_ARB, 0);
}
void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints)