diff options
Diffstat (limited to 'src/opengl')
-rw-r--r-- | src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp | 6 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h | 30 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 200 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h | 11 | ||||
-rw-r--r-- | src/opengl/qgl.cpp | 29 | ||||
-rw-r--r-- | src/opengl/qgl_p.h | 42 | ||||
-rw-r--r-- | src/opengl/qgl_win.cpp | 3 | ||||
-rw-r--r-- | src/opengl/qglextensions_p.h | 8 | ||||
-rw-r--r-- | src/opengl/qpaintengine_opengl.cpp | 94 | ||||
-rw-r--r-- | src/opengl/qpaintengine_opengl_p.h | 1 |
10 files changed, 335 insertions, 89 deletions
diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp b/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp index 03b1bf0..559a6fd 100644 --- a/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp +++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp @@ -61,12 +61,6 @@ QGLRect QGL2PEXVertexArray::boundingRect() const return QGLRect(minX, minY, maxX, maxY); } -void QGL2PEXVertexArray::addRect(const QRectF &rect) -{ - vertexArray << rect.topLeft() << rect.topRight() << rect.bottomRight() - << rect.bottomRight() << rect.bottomLeft() << rect.topLeft(); -} - void QGL2PEXVertexArray::addClosingLine(int index) { if (QPointF(vertexArray.at(index)) != QPointF(vertexArray.last())) diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h index e0497b1..d1e7615 100644 --- a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h +++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h @@ -102,8 +102,36 @@ public: QGL2PEXVertexArray() : maxX(-2e10), maxY(-2e10), minX(2e10), minY(2e10), boundingRectDirty(true) {} + + inline void addRect(const QRectF &rect) + { + qreal top = rect.top(); + qreal left = rect.left(); + qreal bottom = rect.bottom(); + qreal right = rect.right(); + + vertexArray << QGLPoint(left, top) + << QGLPoint(right, top) + << QGLPoint(right, bottom) + << QGLPoint(right, bottom) + << QGLPoint(left, bottom) + << QGLPoint(left, top); + } + + inline void addQuad(const QRectF &rect) + { + qreal top = rect.top(); + qreal left = rect.left(); + qreal bottom = rect.bottom(); + qreal right = rect.right(); + + vertexArray << QGLPoint(left, top) + << QGLPoint(right, top) + << QGLPoint(left, bottom) + << QGLPoint(right, bottom); + + } - void addRect(const QRectF &rect); void addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline = true); void clear(); diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index e39d385..c34cf89 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.h> #include <private/qtriangulator_p.h> #include "qglgradientcache_p.h" @@ -108,6 +109,11 @@ QGL2PaintEngineExPrivate::~QGL2PaintEngineExPrivate() e->data = 0; e->engine = 0; } + + if (elementIndicesVBOId != 0) { + glDeleteBuffers(1, &elementIndicesVBOId); + elementIndicesVBOId = 0; + } } void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id) @@ -1293,6 +1299,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); @@ -1346,33 +1366,72 @@ 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) +namespace { + + class QOpenGLStaticTextUserData: public QStaticTextUserData + { + public: + QOpenGLStaticTextUserData() + : QStaticTextUserData(OpenGLUserData) + { + } + + ~QOpenGLStaticTextUserData() + { + } + + QGL2PEXVertexArray vertexCoordinateArray; + QGL2PEXVertexArray textureCoordinateArray; + }; + +} + +// #define QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO + +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; @@ -1384,20 +1443,83 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly GLfloat dx = 1.0 / cache->width(); GLfloat dy = 1.0 / cache->height(); - vertexCoordinateArray.clear(); - textureCoordinateArray.clear(); + bool recreateVertexArrays = false; + if (staticTextItem->userDataNeedsUpdate) + recreateVertexArrays = true; + else if (staticTextItem->userData == 0) + recreateVertexArrays = true; + else if (staticTextItem->userData->type != QStaticTextUserData::OpenGLUserData) + recreateVertexArrays = true; + + // Use global arrays by default + QGL2PEXVertexArray *vertexCoordinates = &vertexCoordinateArray; + QGL2PEXVertexArray *textureCoordinates = &textureCoordinateArray; - 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 (staticTextItem->useBackendOptimizations) { + QOpenGLStaticTextUserData *userData = 0; - 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->userData == 0 + || staticTextItem->userData->type != QStaticTextUserData::OpenGLUserData) { + + userData = new QOpenGLStaticTextUserData(); + staticTextItem->setUserData(userData); + + } else { + userData = static_cast<QOpenGLStaticTextUserData*>(staticTextItem->userData); + } + + // Use cache if backend optimizations is turned on + vertexCoordinates = &userData->vertexCoordinateArray; + textureCoordinates = &userData->textureCoordinateArray; + } + + + if (recreateVertexArrays) { + vertexCoordinates->clear(); + textureCoordinates->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; + + vertexCoordinates->addQuad(QRectF(x, y, c.w, c.h)); + textureCoordinates->addQuad(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); + } + + staticTextItem->userDataNeedsUpdate = false; } - setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data()); - setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data()); + if (elementIndices.size() < staticTextItem->numGlyphs*6) { + Q_ASSERT(elementIndices.size() % 6 == 0); + int j = elementIndices.size() / 6 * 4; + while (j < staticTextItem->numGlyphs*4) { + elementIndices.append(j + 0); + elementIndices.append(j + 0); + elementIndices.append(j + 1); + elementIndices.append(j + 2); + elementIndices.append(j + 3); + elementIndices.append(j + 3); + + j += 4; + } + +#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) + if (elementIndicesVBOId == 0) + glGenBuffers(1, &elementIndicesVBOId); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementIndices.size() * sizeof(GLushort), + elementIndices.constData(), GL_STATIC_DRAW); +#endif + } else { +#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId); +#endif + } + + setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data()); + setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data()); if (addOffset) { addOffset = false; @@ -1411,6 +1533,13 @@ 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 @@ -1464,7 +1593,11 @@ 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(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) + glDrawElements(GL_TRIANGLE_STRIP, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_SHORT, 0); +#else + glDrawElements(GL_TRIANGLE_STRIP, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data()); +#endif shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMaskPass2); @@ -1490,11 +1623,23 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly //### TODO: Gamma correction glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT); - glBindTexture(GL_TEXTURE_2D, cache->texture()); + if (lastMaskTextureUsed != cache->texture()) { + glBindTexture(GL_TEXTURE_2D, cache->texture()); + lastMaskTextureUsed = cache->texture(); + } 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(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) + glDrawElements(GL_TRIANGLE_STRIP, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_SHORT, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +#else + glDrawElements(GL_TRIANGLE_STRIP, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data()); +#endif + + if (includeMatrixInCache) + s->matrix = old; } void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints) @@ -1640,7 +1785,11 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) case QInternal::FramebufferObject: { GLenum f = static_cast<QGLFramebufferObject *>(pdev)->format().internalTextureFormat(); +#ifndef QT_OPENGL_ES d->deviceHasAlpha = (f != GL_RGB && f != GL_RGB5 && f != GL_RGB8); +#else + d->deviceHasAlpha = (f == GL_RGBA); +#endif } break; default: @@ -1746,6 +1895,7 @@ void QGL2PaintEngineEx::ensureActive() d->transferMode(BrushDrawingMode); glViewport(0, 0, d->width, d->height); d->needsSync = false; + d->lastMaskTextureUsed = 0; d->shaderManager->setDirty(); d->ctx->d_func()->syncGlState(); for (int i = 0; i < 3; ++i) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index e816e17..d4932be 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -133,6 +133,7 @@ public: virtual void stroke(const QVectorPath &path, const QPen &pen); virtual void clip(const QVectorPath &path, Qt::ClipOperation op); + virtual void drawStaticTextItem(QStaticTextItem *textItem); Type type() const { return OpenGL2; } @@ -173,9 +174,11 @@ public: width(0), height(0), ctx(0), useSystemClip(true), + elementIndicesVBOId(0), snapToPixelGrid(false), addOffset(false), - inverseScale(1) + inverseScale(1), + lastMaskTextureUsed(0) { } ~QGL2PaintEngineExPrivate(); @@ -194,7 +197,8 @@ public: void stroke(const QVectorPath &path, const QPen &pen); void drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern = false); void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints); - void drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType, const QTextItemInt &ti); + void drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, QStaticTextItem *staticTextItem, + bool includeMatrixInCache); // Calls glVertexAttributePointer if the pointer has changed inline void setVertexAttributePointer(unsigned int arrayIndex, const GLfloat *pointer); @@ -265,6 +269,8 @@ public: QGL2PEXVertexArray vertexCoordinateArray; QGL2PEXVertexArray textureCoordinateArray; + QVector<GLushort> elementIndices; + GLuint elementIndicesVBOId; QDataBuffer<GLfloat> opacityArray; GLfloat staticVertexCoordinateArray[8]; GLfloat staticTextureCoordinateArray[8]; @@ -275,6 +281,7 @@ public: GLfloat inverseScale; GLuint lastTextureUsed; + GLuint lastMaskTextureUsed; bool needsSync; bool multisamplingAlwaysEnabled; diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index cfcbbf8..f3c66f2 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -1708,6 +1708,7 @@ QGLTextureCache::~QGLTextureCache() void QGLTextureCache::insert(QGLContext* ctx, qint64 key, QGLTexture* texture, int cost) { + QWriteLocker locker(&m_lock); if (m_cache.totalCost() + cost > m_cache.maxCost()) { // the cache is full - make an attempt to remove something const QList<qint64> keys = m_cache.keys(); @@ -1725,6 +1726,7 @@ void QGLTextureCache::insert(QGLContext* ctx, qint64 key, QGLTexture* texture, i bool QGLTextureCache::remove(QGLContext* ctx, GLuint textureId) { + QWriteLocker locker(&m_lock); QList<qint64> keys = m_cache.keys(); for (int i = 0; i < keys.size(); ++i) { QGLTexture *tex = m_cache.object(keys.at(i)); @@ -1739,6 +1741,7 @@ bool QGLTextureCache::remove(QGLContext* ctx, GLuint textureId) void QGLTextureCache::removeContextTextures(QGLContext* ctx) { + QWriteLocker locker(&m_lock); QList<qint64> keys = m_cache.keys(); for (int i = 0; i < keys.size(); ++i) { const qint64 &key = keys.at(i); @@ -1761,9 +1764,6 @@ QGLTextureCache* QGLTextureCache::instance() */ void QGLTextureCache::imageCleanupHook(qint64 cacheKey) { - // ### remove when the GL texture cache becomes thread-safe - if (qApp->thread() != QThread::currentThread()) - return; QGLTexture *texture = instance()->getTexture(cacheKey); if (texture && texture->options & QGLContext::MemoryManagedBindOption) instance()->remove(cacheKey); @@ -1772,13 +1772,10 @@ void QGLTextureCache::imageCleanupHook(qint64 cacheKey) void QGLTextureCache::cleanupTextures(QPixmapData* pmd) { - // ### remove when the GL texture cache becomes thread-safe - if (qApp->thread() == QThread::currentThread()) { - const qint64 cacheKey = pmd->cacheKey(); - QGLTexture *texture = instance()->getTexture(cacheKey); - if (texture && texture->options & QGLContext::MemoryManagedBindOption) - instance()->remove(cacheKey); - } + const qint64 cacheKey = pmd->cacheKey(); + QGLTexture *texture = instance()->getTexture(cacheKey); + if (texture && texture->options & QGLContext::MemoryManagedBindOption) + instance()->remove(cacheKey); } void QGLTextureCache::cleanupBeforePixmapDestruction(QPixmapData* pmd) @@ -2393,7 +2390,7 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G #ifndef QT_NO_DEBUG GLenum error = glGetError(); if (error != GL_NO_ERROR) { - qWarning(" - texture upload failed, error code 0x%x\n", error); + qWarning(" - texture upload failed, error code 0x%x, enum: %d (%x)\n", error, target, target); } #endif @@ -3292,6 +3289,7 @@ void QGLContextPrivate::setCurrentContext(QGLContext *context) */ + /***************************************************************************** QGLWidget implementation *****************************************************************************/ @@ -3412,6 +3410,15 @@ void QGLContextPrivate::setCurrentContext(QGLContext *context) One approach to doing this is shown in the \l{Overpainting Example}{Overpainting} example. + \section1 Threading + + It is possible to render into a QGLWidget from another thread, but it + requires that all access to the GL context is safe guarded. The Qt GUI + thread will try to use the context in resizeEvent and paintEvent, so in + order for threaded rendering using a GL widget to work, these functions + need to be intercepted in the GUI thread and handled accordingly in the + application. + \e{OpenGL is a trademark of Silicon Graphics, Inc. in the United States and other countries.} diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index efd2090..5c4638e 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -528,14 +528,14 @@ public: ~QGLTextureCache(); void insert(QGLContext *ctx, qint64 key, QGLTexture *texture, int cost); - void remove(quint64 key) { m_cache.remove(key); } + inline void remove(quint64 key); + inline int size(); + inline void setMaxCost(int newMax); + inline int maxCost(); + inline QGLTexture* getTexture(quint64 key); + bool remove(QGLContext *ctx, GLuint textureId); void removeContextTextures(QGLContext *ctx); - int size() { return m_cache.size(); } - void setMaxCost(int newMax) { m_cache.setMaxCost(newMax); } - int maxCost() {return m_cache.maxCost(); } - QGLTexture* getTexture(quint64 key) { return m_cache.object(key); } - static QGLTextureCache *instance(); static void deleteIfEmpty(); static void imageCleanupHook(qint64 cacheKey); @@ -544,8 +544,38 @@ public: private: QCache<qint64, QGLTexture> m_cache; + QReadWriteLock m_lock; }; +int QGLTextureCache::size() { + QReadLocker locker(&m_lock); + return m_cache.size(); +} + +void QGLTextureCache::setMaxCost(int newMax) +{ + QWriteLocker locker(&m_lock); + m_cache.setMaxCost(newMax); +} + +int QGLTextureCache::maxCost() +{ + QReadLocker locker(&m_lock); + return m_cache.maxCost(); +} + +QGLTexture* QGLTextureCache::getTexture(quint64 key) +{ + QReadLocker locker(&m_lock); + return m_cache.object(key); +} + +void QGLTextureCache::remove(quint64 key) +{ + QWriteLocker locker(&m_lock); + m_cache.remove(key); +} + extern Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine(); diff --git a/src/opengl/qgl_win.cpp b/src/opengl/qgl_win.cpp index b5f952e..5ab944a 100644 --- a/src/opengl/qgl_win.cpp +++ b/src/opengl/qgl_win.cpp @@ -1280,8 +1280,9 @@ void QGLContext::reset() void QGLContext::makeCurrent() { Q_D(QGLContext); - if (d->rc == wglGetCurrentContext() || !d->valid) // already current + if (d->rc == wglGetCurrentContext() || !d->valid) // already current return; + if (d->win) { d->dc = GetDC(d->win); if (!d->dc) { diff --git a/src/opengl/qglextensions_p.h b/src/opengl/qglextensions_p.h index 4edd5f7..f6926f3 100644 --- a/src/opengl/qglextensions_p.h +++ b/src/opengl/qglextensions_p.h @@ -452,6 +452,14 @@ struct QGLExtensionFuncs // OpenGL constants +#ifndef GL_ARRAY_BUFFER +#define GL_ARRAY_BUFFER 0x8892 +#endif + +#ifndef GL_STATIC_DRAW +#define GL_STATIC_DRAW 0x88E4 +#endif + /* NV_texture_rectangle */ #ifndef GL_NV_texture_rectangle #define GL_TEXTURE_RECTANGLE_NV 0x84F5 diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp index 3845e43..c8307a0 100644 --- a/src/opengl/qpaintengine_opengl.cpp +++ b/src/opengl/qpaintengine_opengl.cpp @@ -60,6 +60,7 @@ #include <private/qglpixelbuffer_p.h> #include <private/qbezier_p.h> #include <qglframebufferobject.h> +#include <private/qstatictext_p.h> #include "private/qtessellator_p.h" @@ -4548,7 +4549,7 @@ public: QGLGlyphCache() : QObject(0) { current_cache = 0; } ~QGLGlyphCache(); QGLGlyphCoord *lookup(QFontEngine *, glyph_t); - void cacheGlyphs(QGLContext *, const QTextItemInt &, const QVarLengthArray<glyph_t> &); + void cacheGlyphs(QGLContext *, QFontEngine *, glyph_t *glyphs, int numGlyphs); void cleanCache(); void allocTexture(int width, int height, GLuint texture); @@ -4700,8 +4701,8 @@ static QImage getCurrentTexture(const QColor &color, QGLFontTexture *font_tex) } #endif -void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti, - const QVarLengthArray<glyph_t> &glyphs) +void QGLGlyphCache::cacheGlyphs(QGLContext *context, QFontEngine *fontEngine, + glyph_t *glyphs, int numGlyphs) { QGLContextHash::const_iterator dev_it = qt_context_cache.constFind(context); QGLFontGlyphHash *font_cache = 0; @@ -4737,25 +4738,25 @@ void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti, } Q_ASSERT(font_cache != 0); - QGLFontGlyphHash::const_iterator cache_it = font_cache->constFind(ti.fontEngine); + QGLFontGlyphHash::const_iterator cache_it = font_cache->constFind(fontEngine); QGLGlyphHash *cache = 0; if (cache_it == font_cache->constEnd()) { cache = new QGLGlyphHash; - font_cache->insert(ti.fontEngine, cache); - connect(ti.fontEngine, SIGNAL(destroyed(QObject*)), SLOT(fontEngineDestroyed(QObject*))); + font_cache->insert(fontEngine, cache); + connect(fontEngine, SIGNAL(destroyed(QObject*)), SLOT(fontEngineDestroyed(QObject*))); } else { cache = cache_it.value(); } current_cache = cache; quint64 font_key = (reinterpret_cast<quint64>(context_key ? context_key : context) << 32) - | reinterpret_cast<quint64>(ti.fontEngine); + | reinterpret_cast<quint64>(fontEngine); QGLFontTexHash::const_iterator it = qt_font_textures.constFind(font_key); QGLFontTexture *font_tex; if (it == qt_font_textures.constEnd()) { GLuint font_texture; glGenTextures(1, &font_texture); - GLint tex_height = qt_next_power_of_two(qRound(ti.ascent.toReal() + ti.descent.toReal())+2); + GLint tex_height = qt_next_power_of_two(qRound(fontEngine->ascent().toReal() + fontEngine->descent().toReal())+2); GLint tex_width = qt_next_power_of_two(tex_height*30); // ### GLint max_tex_size; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size); @@ -4777,16 +4778,16 @@ void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti, glBindTexture(GL_TEXTURE_2D, font_tex->texture); } - for (int i=0; i< glyphs.size(); ++i) { + for (int i=0; i< numGlyphs; ++i) { QGLGlyphHash::const_iterator it = cache->constFind(glyphs[i]); if (it == cache->constEnd()) { // render new glyph and put it in the cache - glyph_metrics_t metrics = ti.fontEngine->boundingBox(glyphs[i]); + glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]); int glyph_width = qRound(metrics.width.toReal())+2; - int glyph_height = qRound(ti.ascent.toReal() + ti.descent.toReal())+2; + int glyph_height = qRound(fontEngine->ascent().toReal() + fontEngine->descent().toReal())+2; if (font_tex->x_offset + glyph_width + x_margin > font_tex->width) { - int strip_height = qt_next_power_of_two(qRound(ti.ascent.toReal() + ti.descent.toReal())+2); + int strip_height = qt_next_power_of_two(qRound(fontEngine->ascent().toReal() + fontEngine->descent().toReal())+2); font_tex->x_offset = x_margin; font_tex->y_offset += strip_height; if (font_tex->y_offset >= font_tex->height) { @@ -4819,7 +4820,7 @@ void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti, } } - QImage glyph_im(ti.fontEngine->alphaMapForGlyph(glyphs[i])); + QImage glyph_im(fontEngine->alphaMapForGlyph(glyphs[i])); glyph_im = glyph_im.convertToFormat(QImage::Format_Indexed8); glyph_width = glyph_im.width(); Q_ASSERT(glyph_width >= 0); @@ -4899,30 +4900,15 @@ void qgl_cleanup_glyph_cache(QGLContext *ctx) qt_glyph_cache()->cleanupContext(ctx); } -void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) +void QOpenGLPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) { Q_D(QOpenGLPaintEngine); - const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); - - // fall back to drawing a polygon if the scale factor is large, or - // we use a gradient pen - if ((d->matrix.det() > 1) || (d->pen_brush_style >= Qt::LinearGradientPattern - && d->pen_brush_style <= Qt::ConicalGradientPattern)) { - QPaintEngine::drawTextItem(p, textItem); - return; - } - d->flushDrawQueue(); - // add the glyphs used to the glyph texture cache - QVarLengthArray<QFixedPoint> positions; - QVarLengthArray<glyph_t> glyphs; - QTransform matrix = QTransform::fromTranslate(qRound(p.x()), qRound(p.y())); - ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); - // make sure the glyphs we want to draw are in the cache - qt_glyph_cache()->cacheGlyphs(d->device->context(), ti, glyphs); + qt_glyph_cache()->cacheGlyphs(d->device->context(), textItem->fontEngine, textItem->glyphs, + textItem->numGlyphs); d->setGradientOps(Qt::SolidPattern, QRectF()); // turns off gradient ops qt_glColor4ubv(d->pen_color); @@ -4944,13 +4930,13 @@ void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - bool antialias = !(ti.fontEngine->fontDef.styleStrategy & QFont::NoAntialias) - && (d->matrix.type() > QTransform::TxTranslate); + bool antialias = !(textItem->fontEngine->fontDef.styleStrategy & QFont::NoAntialias) + && (d->matrix.type() > QTransform::TxTranslate); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, antialias ? GL_LINEAR : GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, antialias ? GL_LINEAR : GL_NEAREST); - for (int i=0; i< glyphs.size(); ++i) { - QGLGlyphCoord *g = qt_glyph_cache()->lookup(ti.fontEngine, glyphs[i]); + for (int i=0; i< textItem->numGlyphs; ++i) { + QGLGlyphCoord *g = qt_glyph_cache()->lookup(textItem->fontEngine, textItem->glyphs[i]); // we don't cache glyphs with no width/height if (!g) @@ -4962,8 +4948,8 @@ void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte x2 = x1 + g->width; y2 = y1 + g->height; - QPointF logical_pos((positions[i].x - g->x_offset).toReal(), - (positions[i].y + g->y_offset).toReal()); + QPointF logical_pos((textItem->glyphPositions[i].x - g->x_offset).toReal(), + (textItem->glyphPositions[i].y + g->y_offset).toReal()); qt_add_rect_to_array(QRectF(logical_pos, QSizeF(g->log_width, g->log_height)), vertexArray); qt_add_texcoords_to_array(x1, y1, x2, y2, texCoordArray); @@ -4980,6 +4966,40 @@ void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte // XXX: This may not be needed as this behavior does seem to be caused by driver bug glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); #endif + +} + +void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) +{ + Q_D(QOpenGLPaintEngine); + + const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); + + // fall back to drawing a polygon if the scale factor is large, or + // we use a gradient pen + if ((d->matrix.det() > 1) || (d->pen_brush_style >= Qt::LinearGradientPattern + && d->pen_brush_style <= Qt::ConicalGradientPattern)) { + QPaintEngine::drawTextItem(p, textItem); + return; + } + + // add the glyphs used to the glyph texture cache + QVarLengthArray<QFixedPoint> positions; + QVarLengthArray<glyph_t> glyphs; + QTransform matrix = QTransform::fromTranslate(qRound(p.x()), qRound(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(); + drawStaticTextItem(&staticTextItem); + } + } diff --git a/src/opengl/qpaintengine_opengl_p.h b/src/opengl/qpaintengine_opengl_p.h index de0086a..55f7792 100644 --- a/src/opengl/qpaintengine_opengl_p.h +++ b/src/opengl/qpaintengine_opengl_p.h @@ -133,6 +133,7 @@ public: void drawImage(const QRectF &r, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags conversionFlags); void drawTextItem(const QPointF &p, const QTextItem &ti); + void drawStaticTextItem(QStaticTextItem *staticTextItem); void drawEllipse(const QRectF &rect); |