src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
branchGCC_SURGE
changeset 31 5daf16870df6
parent 30 5dc02b23752f
child 33 3e2da88830cd
equal deleted inserted replaced
27:93b982ccede2 31:5daf16870df6
    62     and use the correct program when we really need it.
    62     and use the correct program when we really need it.
    63 */
    63 */
    64 
    64 
    65 // #define QT_OPENGL_CACHE_AS_VBOS
    65 // #define QT_OPENGL_CACHE_AS_VBOS
    66 
    66 
       
    67 #include "qglgradientcache_p.h"
    67 #include "qpaintengineex_opengl2_p.h"
    68 #include "qpaintengineex_opengl2_p.h"
    68 
    69 
    69 #include <string.h> //for memcpy
    70 #include <string.h> //for memcpy
    70 #include <qmath.h>
    71 #include <qmath.h>
    71 
    72 
    75 #include <QPaintEngine>
    76 #include <QPaintEngine>
    76 #include <private/qpainter_p.h>
    77 #include <private/qpainter_p.h>
    77 #include <private/qfontengine_p.h>
    78 #include <private/qfontengine_p.h>
    78 #include <private/qpixmapdata_gl_p.h>
    79 #include <private/qpixmapdata_gl_p.h>
    79 #include <private/qdatabuffer_p.h>
    80 #include <private/qdatabuffer_p.h>
    80 
    81 #include <private/qstatictext_p.h>
    81 #include "qglgradientcache_p.h"
    82 #include <private/qtriangulator_p.h>
       
    83 
    82 #include "qglengineshadermanager_p.h"
    84 #include "qglengineshadermanager_p.h"
    83 #include "qgl2pexvertexarray_p.h"
    85 #include "qgl2pexvertexarray_p.h"
    84 #include "qtriangulatingstroker_p.h"
    86 #include "qtriangulatingstroker_p.h"
    85 #include "qtextureglyphcache_gl_p.h"
    87 #include "qtextureglyphcache_gl_p.h"
    86 
    88 
   104     while (pathCaches.size()) {
   106     while (pathCaches.size()) {
   105         QVectorPath::CacheEntry *e = *(pathCaches.constBegin());
   107         QVectorPath::CacheEntry *e = *(pathCaches.constBegin());
   106         e->cleanup(e->engine, e->data);
   108         e->cleanup(e->engine, e->data);
   107         e->data = 0;
   109         e->data = 0;
   108         e->engine = 0;
   110         e->engine = 0;
       
   111     }
       
   112 
       
   113     if (elementIndicesVBOId != 0) {
       
   114         glDeleteBuffers(1, &elementIndicesVBOId);
       
   115         elementIndicesVBOId = 0;
   109     }
   116     }
   110 }
   117 }
   111 
   118 
   112 void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id)
   119 void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id)
   113 {
   120 {
   208     }
   215     }
   209     else if (style == Qt::TexturePattern) {
   216     else if (style == Qt::TexturePattern) {
   210         const QPixmap& texPixmap = currentBrush.texture();
   217         const QPixmap& texPixmap = currentBrush.texture();
   211 
   218 
   212         glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT);
   219         glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT);
   213         QGLTexture *tex = ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption);
   220         QGLTexture *tex = ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA,
       
   221                                                      QGLContext::InternalBindOption |
       
   222                                                      QGLContext::CanFlipNativePixmapBindOption);
   214         updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform);
   223         updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform);
   215         textureInvertedY = tex->options & QGLContext::InvertedYBindOption ? -1 : 1;
   224         textureInvertedY = tex->options & QGLContext::InvertedYBindOption ? -1 : 1;
   216     }
   225     }
   217     brushTextureDirty = false;
   226     brushTextureDirty = false;
   218 }
   227 }
   386     inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())),
   395     inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())),
   387                                   qMax(qAbs(transform.m12()), qAbs(transform.m21())) ),
   396                                   qMax(qAbs(transform.m12()), qAbs(transform.m21())) ),
   388                         qreal(0.0001));
   397                         qreal(0.0001));
   389 
   398 
   390     matrixDirty = false;
   399     matrixDirty = false;
       
   400     matrixUniformDirty = true;
   391 
   401 
   392     // Set the PMV matrix attribute. As we use an attributes rather than uniforms, we only
   402     // Set the PMV matrix attribute. As we use an attributes rather than uniforms, we only
   393     // need to do this once for every matrix change and persists across all shader programs.
   403     // need to do this once for every matrix change and persists across all shader programs.
   394     glVertexAttrib3fv(QT_PMV_MATRIX_1_ATTR, pmvMatrix[0]);
   404     glVertexAttrib3fv(QT_PMV_MATRIX_1_ATTR, pmvMatrix[0]);
   395     glVertexAttrib3fv(QT_PMV_MATRIX_2_ATTR, pmvMatrix[1]);
   405     glVertexAttrib3fv(QT_PMV_MATRIX_2_ATTR, pmvMatrix[1]);
   504 {
   514 {
   505     Q_D(QGL2PaintEngineEx);
   515     Q_D(QGL2PaintEngineEx);
   506     ensureActive();
   516     ensureActive();
   507     d->transferMode(BrushDrawingMode);
   517     d->transferMode(BrushDrawingMode);
   508 
   518 
       
   519     d->nativePaintingActive = true;
       
   520 
   509     QGLContext *ctx = d->ctx;
   521     QGLContext *ctx = d->ctx;
   510     glUseProgram(0);
   522     glUseProgram(0);
   511 
   523 
   512     // Disable all the vertex attribute arrays:
   524     // Disable all the vertex attribute arrays:
   513     for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i)
   525     for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i)
   519     // paint engine
   531     // paint engine
   520     const QTransform& mtx = state()->matrix;
   532     const QTransform& mtx = state()->matrix;
   521 
   533 
   522     float mv_matrix[4][4] =
   534     float mv_matrix[4][4] =
   523     {
   535     {
   524         { mtx.m11(), mtx.m12(),     0, mtx.m13() },
   536         { float(mtx.m11()), float(mtx.m12()),     0, float(mtx.m13()) },
   525         { mtx.m21(), mtx.m22(),     0, mtx.m23() },
   537         { float(mtx.m21()), float(mtx.m22()),     0, float(mtx.m23()) },
   526         {         0,         0,     1,         0 },
   538         {                0,                0,     1,                0 },
   527         {  mtx.dx(),  mtx.dy(),     0, mtx.m33() }
   539         {  float(mtx.dx()),  float(mtx.dy()),     0, float(mtx.m33()) }
   528     };
   540     };
   529 
   541 
   530     const QSize sz = d->device->size();
   542     const QSize sz = d->device->size();
   531 
   543 
   532     glMatrixMode(GL_PROJECTION);
   544     glMatrixMode(GL_PROJECTION);
   559     glDepthFunc(GL_LESS);
   571     glDepthFunc(GL_LESS);
   560     glClearDepth(1);
   572     glClearDepth(1);
   561     glStencilMask(0xff);
   573     glStencilMask(0xff);
   562     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
   574     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
   563     glStencilFunc(GL_ALWAYS, 0, 0xff);
   575     glStencilFunc(GL_ALWAYS, 0, 0xff);
   564     glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
   576     ctx->d_func()->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, false);
   565     glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
   577     ctx->d_func()->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, false);
   566     glDisableVertexAttribArray(QT_OPACITY_ATTR);
   578     ctx->d_func()->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false);
   567 #ifndef QT_OPENGL_ES_2
   579 #ifndef QT_OPENGL_ES_2
   568     glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // color may have been changed by glVertexAttrib()
   580     glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // color may have been changed by glVertexAttrib()
   569 #endif
   581 #endif
   570 }
   582 }
   571 
   583 
   572 void QGL2PaintEngineEx::endNativePainting()
   584 void QGL2PaintEngineEx::endNativePainting()
   573 {
   585 {
   574     Q_D(QGL2PaintEngineEx);
   586     Q_D(QGL2PaintEngineEx);
   575     d->needsSync = true;
   587     d->needsSync = true;
       
   588     d->nativePaintingActive = false;
       
   589 }
       
   590 
       
   591 bool QGL2PaintEngineEx::isNativePaintingActive() const {
       
   592     Q_D(const QGL2PaintEngineEx);
       
   593     return d->nativePaintingActive;
   576 }
   594 }
   577 
   595 
   578 void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
   596 void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
   579 {
   597 {
   580     if (newMode == mode)
   598     if (newMode == mode)
   585     }
   603     }
   586 
   604 
   587     if (newMode == TextDrawingMode) {
   605     if (newMode == TextDrawingMode) {
   588         setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data());
   606         setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data());
   589         setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data());
   607         setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data());
       
   608         shaderManager->setHasComplexGeometry(true);
       
   609     } else {
       
   610         shaderManager->setHasComplexGeometry(false);
   590     }
   611     }
   591 
   612 
   592     if (newMode == ImageDrawingMode) {
   613     if (newMode == ImageDrawingMode) {
   593         setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray);
   614         setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray);
   594         setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, staticTextureCoordinateArray);
   615         setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, staticTextureCoordinateArray);
   609 
   630 
   610 struct QGL2PEVectorPathCache
   631 struct QGL2PEVectorPathCache
   611 {
   632 {
   612 #ifdef QT_OPENGL_CACHE_AS_VBOS
   633 #ifdef QT_OPENGL_CACHE_AS_VBOS
   613     GLuint vbo;
   634     GLuint vbo;
       
   635     GLuint ibo;
   614 #else
   636 #else
   615     float *vertices;
   637     float *vertices;
       
   638     quint32 *indices;
   616 #endif
   639 #endif
   617     int vertexCount;
   640     int vertexCount;
       
   641     int indexCount;
   618     GLenum primitiveType;
   642     GLenum primitiveType;
   619     qreal iscale;
   643     qreal iscale;
   620 };
   644 };
   621 
   645 
   622 void QGL2PaintEngineExPrivate::cleanupVectorPath(QPaintEngineEx *engine, void *data)
   646 void QGL2PaintEngineExPrivate::cleanupVectorPath(QPaintEngineEx *engine, void *data)
   623 {
   647 {
   624     QGL2PEVectorPathCache *c = (QGL2PEVectorPathCache *) data;
   648     QGL2PEVectorPathCache *c = (QGL2PEVectorPathCache *) data;
   625 #ifdef QT_OPENGL_CACHE_AS_VBOS
   649 #ifdef QT_OPENGL_CACHE_AS_VBOS
   626     Q_ASSERT(engine->type() == QPaintEngine::OpenGL2);
   650     Q_ASSERT(engine->type() == QPaintEngine::OpenGL2);
   627     static_cast<QGL2PaintEngineEx *>(engine)->d_func()->unusedVBOSToClean << c->vbo;
   651     static_cast<QGL2PaintEngineEx *>(engine)->d_func()->unusedVBOSToClean << c->vbo;
       
   652     if (c->ibo)
       
   653         d->unusedIBOSToClean << c->ibo;
   628 #else
   654 #else
   629     Q_UNUSED(engine);
   655     Q_UNUSED(engine);
   630     qFree(c->vertices);
   656     qFree(c->vertices);
       
   657     qFree(c->indices);
   631 #endif
   658 #endif
   632     delete c;
   659     delete c;
   633 }
   660 }
   634 
   661 
   635 // Assumes everything is configured for the brush you want to use
   662 // Assumes everything is configured for the brush you want to use
   655     // Might need to call updateMatrix to re-calculate inverseScale
   682     // Might need to call updateMatrix to re-calculate inverseScale
   656     if (matrixDirty)
   683     if (matrixDirty)
   657         updateMatrix();
   684         updateMatrix();
   658 
   685 
   659     const QPointF* const points = reinterpret_cast<const QPointF*>(path.points());
   686     const QPointF* const points = reinterpret_cast<const QPointF*>(path.points());
       
   687 
       
   688     // ### Remove before release...
       
   689     static bool do_vectorpath_cache = qgetenv("QT_OPENGL_NO_PATH_CACHE").isEmpty();
   660 
   690 
   661     // Check to see if there's any hints
   691     // Check to see if there's any hints
   662     if (path.shape() == QVectorPath::RectangleHint) {
   692     if (path.shape() == QVectorPath::RectangleHint) {
   663         QGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y());
   693         QGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y());
   664         prepareForDraw(currentBrush.isOpaque());
   694         prepareForDraw(currentBrush.isOpaque());
   666     } else if (path.isConvex()) {
   696     } else if (path.isConvex()) {
   667 
   697 
   668         if (path.isCacheable()) {
   698         if (path.isCacheable()) {
   669             QVectorPath::CacheEntry *data = path.lookupCacheData(q);
   699             QVectorPath::CacheEntry *data = path.lookupCacheData(q);
   670             QGL2PEVectorPathCache *cache;
   700             QGL2PEVectorPathCache *cache;
       
   701 
       
   702             bool updateCache = false;
   671 
   703 
   672             if (data) {
   704             if (data) {
   673                 cache = (QGL2PEVectorPathCache *) data->data;
   705                 cache = (QGL2PEVectorPathCache *) data->data;
   674                 // Check if scale factor is exceeded for curved paths and generate curves if so...
   706                 // Check if scale factor is exceeded for curved paths and generate curves if so...
   675                 if (path.isCurved()) {
   707                 if (path.isCurved()) {
   676                     qreal scaleFactor = cache->iscale / inverseScale;
   708                     qreal scaleFactor = cache->iscale / inverseScale;
   677                     if (scaleFactor < 0.5 || scaleFactor > 2.0) {
   709                     if (scaleFactor < 0.5 || scaleFactor > 2.0) {
   678 #ifdef QT_OPENGL_CACHE_AS_VBOS
   710 #ifdef QT_OPENGL_CACHE_AS_VBOS
   679                         glDeleteBuffers(1, &cache->vbo);
   711                         glDeleteBuffers(1, &cache->vbo);
   680                         cache->vbo = 0;
   712                         cache->vbo = 0;
       
   713                         Q_ASSERT(cache->ibo == 0);
   681 #else
   714 #else
   682                         qFree(cache->vertices);
   715                         qFree(cache->vertices);
   683 #endif
   716                         Q_ASSERT(cache->indices == 0);
   684                         cache->vertexCount = 0;
   717 #endif
       
   718                         updateCache = true;
   685                     }
   719                     }
   686                 }
   720                 }
   687             } else {
   721             } else {
   688                 cache = new QGL2PEVectorPathCache;
   722                 cache = new QGL2PEVectorPathCache;
   689                 cache->vertexCount = 0;
       
   690                 data = const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath);
   723                 data = const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath);
       
   724                 updateCache = true;
   691             }
   725             }
   692 
   726 
   693             // Flatten the path at the current scale factor and fill it into the cache struct.
   727             // Flatten the path at the current scale factor and fill it into the cache struct.
   694             if (!cache->vertexCount) {
   728             if (updateCache) {
   695                 vertexCoordinateArray.clear();
   729                 vertexCoordinateArray.clear();
   696                 vertexCoordinateArray.addPath(path, inverseScale, false);
   730                 vertexCoordinateArray.addPath(path, inverseScale, false);
   697                 int vertexCount = vertexCoordinateArray.vertexCount();
   731                 int vertexCount = vertexCoordinateArray.vertexCount();
   698                 int floatSizeInBytes = vertexCount * 2 * sizeof(float);
   732                 int floatSizeInBytes = vertexCount * 2 * sizeof(float);
   699                 cache->vertexCount = vertexCount;
   733                 cache->vertexCount = vertexCount;
       
   734                 cache->indexCount = 0;
   700                 cache->primitiveType = GL_TRIANGLE_FAN;
   735                 cache->primitiveType = GL_TRIANGLE_FAN;
   701                 cache->iscale = inverseScale;
   736                 cache->iscale = inverseScale;
   702 #ifdef QT_OPENGL_CACHE_AS_VBOS
   737 #ifdef QT_OPENGL_CACHE_AS_VBOS
   703                 glGenBuffers(1, &cache->vbo);
   738                 glGenBuffers(1, &cache->vbo);
   704                 glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
   739                 glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
   705                 glBufferData(GL_ARRAY_BUFFER, floatSizeInBytes, vertexCoordinateArray.data(), GL_STATIC_DRAW);
   740                 glBufferData(GL_ARRAY_BUFFER, floatSizeInBytes, vertexCoordinateArray.data(), GL_STATIC_DRAW);
       
   741                 cache->ibo = 0;
   706 #else
   742 #else
   707                 cache->vertices = (float *) qMalloc(floatSizeInBytes);
   743                 cache->vertices = (float *) qMalloc(floatSizeInBytes);
   708                 memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes);
   744                 memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes);
       
   745                 cache->indices = 0;
   709 #endif
   746 #endif
   710             }
   747             }
   711 
   748 
   712             prepareForDraw(currentBrush.isOpaque());
   749             prepareForDraw(currentBrush.isOpaque());
   713 #ifdef QT_OPENGL_CACHE_AS_VBOS
   750 #ifdef QT_OPENGL_CACHE_AS_VBOS
   719             glDrawArrays(cache->primitiveType, 0, cache->vertexCount);
   756             glDrawArrays(cache->primitiveType, 0, cache->vertexCount);
   720 
   757 
   721         } else {
   758         } else {
   722       //        printf(" - Marking path as cachable...\n");
   759       //        printf(" - Marking path as cachable...\n");
   723             // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable
   760             // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable
   724             // ### Remove before release...
       
   725             static bool do_vectorpath_cache = qgetenv("QT_OPENGL_NO_PATH_CACHE").isEmpty();
       
   726             if (do_vectorpath_cache)
   761             if (do_vectorpath_cache)
   727                 path.makeCacheable();
   762                 path.makeCacheable();
   728             vertexCoordinateArray.clear();
   763             vertexCoordinateArray.clear();
   729             vertexCoordinateArray.addPath(path, inverseScale, false);
   764             vertexCoordinateArray.addPath(path, inverseScale, false);
   730             prepareForDraw(currentBrush.isOpaque());
   765             prepareForDraw(currentBrush.isOpaque());
   731             drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN);
   766             drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN);
   732         }
   767         }
   733 
   768 
   734     } else {
   769     } else {
   735         // The path is too complicated & needs the stencil technique
   770         bool useCache = path.isCacheable();
   736         vertexCoordinateArray.clear();
   771         if (useCache) {
   737         vertexCoordinateArray.addPath(path, inverseScale, false);
   772             QRectF bbox = path.controlPointRect();
   738 
   773             // If the path doesn't fit within these limits, it is possible that the triangulation will fail.
   739         fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill());
   774             useCache &= (bbox.left() > -0x8000 * inverseScale)
   740 
   775                      && (bbox.right() < 0x8000 * inverseScale)
   741         glStencilMask(0xff);
   776                      && (bbox.top() > -0x8000 * inverseScale)
   742         glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
   777                      && (bbox.bottom() < 0x8000 * inverseScale);
   743 
   778         }
   744         if (q->state()->clipTestEnabled) {
   779 
   745             // Pass when high bit is set, replace stencil value with current clip
   780         if (useCache) {
   746             glStencilFunc(GL_NOTEQUAL, q->state()->currentClip, GL_STENCIL_HIGH_BIT);
   781             QVectorPath::CacheEntry *data = path.lookupCacheData(q);
   747         } else if (path.hasWindingFill()) {
   782             QGL2PEVectorPathCache *cache;
   748             // Pass when any bit is set, replace stencil value with 0
   783 
   749             glStencilFunc(GL_NOTEQUAL, 0, 0xff);
   784             bool updateCache = false;
       
   785 
       
   786             if (data) {
       
   787                 cache = (QGL2PEVectorPathCache *) data->data;
       
   788                 // Check if scale factor is exceeded for curved paths and generate curves if so...
       
   789                 if (path.isCurved()) {
       
   790                     qreal scaleFactor = cache->iscale / inverseScale;
       
   791                     if (scaleFactor < 0.5 || scaleFactor > 2.0) {
       
   792 #ifdef QT_OPENGL_CACHE_AS_VBOS
       
   793                         glDeleteBuffers(1, &cache->vbo);
       
   794                         glDeleteBuffers(1, &cache->ibo);
       
   795 #else
       
   796                         qFree(cache->vertices);
       
   797                         qFree(cache->indices);
       
   798 #endif
       
   799                         updateCache = true;
       
   800                     }
       
   801                 }
       
   802             } else {
       
   803                 cache = new QGL2PEVectorPathCache;
       
   804                 data = const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath);
       
   805                 updateCache = true;
       
   806             }
       
   807 
       
   808             // Flatten the path at the current scale factor and fill it into the cache struct.
       
   809             if (updateCache) {
       
   810                 QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale));
       
   811                 cache->vertexCount = polys.vertices.size() / 2;
       
   812                 cache->indexCount = polys.indices.size();
       
   813                 cache->primitiveType = GL_TRIANGLES;
       
   814                 cache->iscale = inverseScale;
       
   815 
       
   816 #ifdef QT_OPENGL_CACHE_AS_VBOS
       
   817                 glGenBuffers(1, &cache->vbo);
       
   818                 glGenBuffers(1, &cache->ibo);
       
   819                 glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
       
   820                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache->ibo);
       
   821                 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quint32) * polys.indices.size(), polys.indices.data(), GL_STATIC_DRAW);
       
   822 
       
   823                 QVarLengthArray<float> vertices(polys.vertices.size());
       
   824                 for (int i = 0; i < polys.vertices.size(); ++i)
       
   825                     vertices[i] = float(inverseScale * polys.vertices.at(i));
       
   826                 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(), vertices.data(), GL_STATIC_DRAW);
       
   827 #else
       
   828                 cache->vertices = (float *) qMalloc(sizeof(float) * polys.vertices.size());
       
   829                 cache->indices = (quint32 *) qMalloc(sizeof(quint32) * polys.indices.size());
       
   830                 memcpy(cache->indices, polys.indices.data(), sizeof(quint32) * polys.indices.size());
       
   831                 for (int i = 0; i < polys.vertices.size(); ++i)
       
   832                     cache->vertices[i] = float(inverseScale * polys.vertices.at(i));
       
   833 #endif
       
   834             }
       
   835 
       
   836             prepareForDraw(currentBrush.isOpaque());
       
   837 #ifdef QT_OPENGL_CACHE_AS_VBOS
       
   838             glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
       
   839             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache->ibo);
       
   840             setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0);
       
   841             glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, 0);
       
   842             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
       
   843             glBindBuffer(GL_ARRAY_BUFFER, 0);
       
   844 #else
       
   845             setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, cache->vertices);
       
   846             glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, cache->indices);
       
   847 #endif
       
   848 
   750         } else {
   849         } else {
   751             // Pass when high bit is set, replace stencil value with 0
   850       //        printf(" - Marking path as cachable...\n");
   752             glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
   851             // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable
   753         }
   852             if (do_vectorpath_cache)
   754         prepareForDraw(currentBrush.isOpaque());
   853                 path.makeCacheable();
   755 
   854 
   756         // Stencil the brush onto the dest buffer
   855             // The path is too complicated & needs the stencil technique
   757         composite(vertexCoordinateArray.boundingRect());
   856             vertexCoordinateArray.clear();
   758         glStencilMask(0);
   857             vertexCoordinateArray.addPath(path, inverseScale, false);
   759         updateClipScissorTest();
   858 
       
   859             fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill());
       
   860 
       
   861             glStencilMask(0xff);
       
   862             glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
       
   863 
       
   864             if (q->state()->clipTestEnabled) {
       
   865                 // Pass when high bit is set, replace stencil value with current clip
       
   866                 glStencilFunc(GL_NOTEQUAL, q->state()->currentClip, GL_STENCIL_HIGH_BIT);
       
   867             } else if (path.hasWindingFill()) {
       
   868                 // Pass when any bit is set, replace stencil value with 0
       
   869                 glStencilFunc(GL_NOTEQUAL, 0, 0xff);
       
   870             } else {
       
   871                 // Pass when high bit is set, replace stencil value with 0
       
   872                 glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
       
   873             }
       
   874             prepareForDraw(currentBrush.isOpaque());
       
   875 
       
   876             // Stencil the brush onto the dest buffer
       
   877             composite(vertexCoordinateArray.boundingRect());
       
   878             glStencilMask(0);
       
   879             updateClipScissorTest();
       
   880         }
   760     }
   881     }
   761 }
   882 }
   762 
   883 
   763 
   884 
   764 void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data,
   885 void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data,
   936     // If the shader program needs changing, we change it and mark all uniforms as dirty
  1057     // If the shader program needs changing, we change it and mark all uniforms as dirty
   937     if (changed) {
  1058     if (changed) {
   938         // The shader program has changed so mark all uniforms as dirty:
  1059         // The shader program has changed so mark all uniforms as dirty:
   939         brushUniformsDirty = true;
  1060         brushUniformsDirty = true;
   940         opacityUniformDirty = true;
  1061         opacityUniformDirty = true;
       
  1062         matrixUniformDirty = true;
   941     }
  1063     }
   942 
  1064 
   943     if (brushUniformsDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode)
  1065     if (brushUniformsDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode)
   944         updateBrushUniforms();
  1066         updateBrushUniforms();
   945 
  1067 
   946     if (opacityMode == QGLEngineShaderManager::UniformOpacity && opacityUniformDirty) {
  1068     if (opacityMode == QGLEngineShaderManager::UniformOpacity && opacityUniformDirty) {
   947         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::GlobalOpacity), (GLfloat)q->state()->opacity);
  1069         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::GlobalOpacity), (GLfloat)q->state()->opacity);
   948         opacityUniformDirty = false;
  1070         opacityUniformDirty = false;
       
  1071     }
       
  1072 
       
  1073     if (matrixUniformDirty && shaderManager->hasComplexGeometry()) {
       
  1074         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Matrix),
       
  1075                                                          pmvMatrix);
       
  1076         matrixUniformDirty = false;
   949     }
  1077     }
   950 
  1078 
   951     return changed;
  1079     return changed;
   952 }
  1080 }
   953 
  1081 
  1046     // updateMatrix() is responsible for setting the inverse scale on
  1174     // updateMatrix() is responsible for setting the inverse scale on
  1047     // the strokers, so we need to call it here and not wait for
  1175     // the strokers, so we need to call it here and not wait for
  1048     // prepareForDraw() down below.
  1176     // prepareForDraw() down below.
  1049     updateMatrix();
  1177     updateMatrix();
  1050 
  1178 
       
  1179     QRectF clip = q->state()->matrix.inverted().mapRect(q->state()->clipEnabled
       
  1180                                                         ? q->state()->rectangleClip
       
  1181                                                         : QRectF(0, 0, width, height));
       
  1182 
  1051     if (penStyle == Qt::SolidLine) {
  1183     if (penStyle == Qt::SolidLine) {
  1052         stroker.process(path, pen);
  1184         stroker.process(path, pen, clip);
  1053 
  1185 
  1054     } else { // Some sort of dash
  1186     } else { // Some sort of dash
  1055         dasher.process(path, pen);
  1187         dasher.process(path, pen, clip);
  1056 
  1188 
  1057         QVectorPath dashStroke(dasher.points(),
  1189         QVectorPath dashStroke(dasher.points(),
  1058                                dasher.elementCount(),
  1190                                dasher.elementCount(),
  1059                                dasher.elementTypes());
  1191                                dasher.elementTypes());
  1060         stroker.process(dashStroke, pen);
  1192         stroker.process(dashStroke, pen, clip);
  1061     }
  1193     }
  1062 
  1194 
  1063     if (opaque) {
  1195     if (opaque) {
  1064         prepareForDraw(opaque);
  1196         prepareForDraw(opaque);
  1065         setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, stroker.vertices());
  1197         setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, stroker.vertices());
  1190     d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
  1322     d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
  1191                            state()->renderHints & QPainter::SmoothPixmapTransform, id);
  1323                            state()->renderHints & QPainter::SmoothPixmapTransform, id);
  1192     d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel());
  1324     d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel());
  1193 }
  1325 }
  1194 
  1326 
  1195 void QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src)
  1327 void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem)
  1196 {
  1328 {
  1197     Q_D(QGL2PaintEngineEx);
  1329     Q_D(QGL2PaintEngineEx);
       
  1330 
       
  1331     ensureActive();
       
  1332 
       
  1333     QFontEngineGlyphCache::Type glyphType = textItem->fontEngine->glyphFormat >= 0
       
  1334                                             ? QFontEngineGlyphCache::Type(textItem->fontEngine->glyphFormat)
       
  1335                                             : d->glyphCacheType;
       
  1336 
       
  1337     d->drawCachedGlyphs(glyphType, textItem, true);
       
  1338 }
       
  1339 
       
  1340 bool QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src)
       
  1341 {
       
  1342     Q_D(QGL2PaintEngineEx);
       
  1343     if (!d->shaderManager)
       
  1344         return false;
       
  1345 
  1198     ensureActive();
  1346     ensureActive();
  1199     d->transferMode(ImageDrawingMode);
  1347     d->transferMode(ImageDrawingMode);
  1200 
  1348 
  1201 #ifndef QT_OPENGL_ES_2
  1349 #ifndef QT_OPENGL_ES_2
  1202     QGLContext *ctx = d->ctx;
  1350     QGLContext *ctx = d->ctx;
  1207     QGLRect srcRect(src.left(), src.bottom(), src.right(), src.top());
  1355     QGLRect srcRect(src.left(), src.bottom(), src.right(), src.top());
  1208 
  1356 
  1209     d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
  1357     d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
  1210                            state()->renderHints & QPainter::SmoothPixmapTransform, textureId);
  1358                            state()->renderHints & QPainter::SmoothPixmapTransform, textureId);
  1211     d->drawTexture(dest, srcRect, size, false);
  1359     d->drawTexture(dest, srcRect, size, false);
       
  1360     return true;
  1212 }
  1361 }
  1213 
  1362 
  1214 void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem)
  1363 void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem)
  1215 {
  1364 {
  1216     Q_D(QGL2PaintEngineEx);
  1365     Q_D(QGL2PaintEngineEx);
  1243             glyphType = QFontEngineGlyphCache::Raster_A8;
  1392             glyphType = QFontEngineGlyphCache::Raster_A8;
  1244         }
  1393         }
  1245     }
  1394     }
  1246 
  1395 
  1247     if (drawCached) {
  1396     if (drawCached) {
  1248         d->drawCachedGlyphs(p, glyphType, ti);
  1397         QVarLengthArray<QFixedPoint> positions;
       
  1398         QVarLengthArray<glyph_t> glyphs;
       
  1399         QTransform matrix = QTransform::fromTranslate(p.x(), p.y());
       
  1400         ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
       
  1401 
       
  1402         {
       
  1403             QStaticTextItem staticTextItem;
       
  1404             staticTextItem.chars = ti.chars;
       
  1405             staticTextItem.fontEngine = ti.fontEngine;
       
  1406             staticTextItem.glyphs = glyphs.data();
       
  1407             staticTextItem.numChars = ti.num_chars;
       
  1408             staticTextItem.numGlyphs = glyphs.size();
       
  1409             staticTextItem.glyphPositions = positions.data();
       
  1410 
       
  1411             d->drawCachedGlyphs(glyphType, &staticTextItem, false);
       
  1412         }
  1249         return;
  1413         return;
  1250     }
  1414     }
  1251 
  1415 
  1252     QPaintEngineEx::drawTextItem(p, ti);
  1416     QPaintEngineEx::drawTextItem(p, ti);
  1253 }
  1417 }
  1254 
  1418 
  1255 void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType,
  1419 namespace {
  1256                                                 const QTextItemInt &ti)
  1420 
       
  1421     class QOpenGLStaticTextUserData: public QStaticTextUserData
       
  1422     {
       
  1423     public:
       
  1424         QOpenGLStaticTextUserData()
       
  1425             : QStaticTextUserData(OpenGLUserData)
       
  1426         {
       
  1427         }
       
  1428 
       
  1429         ~QOpenGLStaticTextUserData()
       
  1430         {
       
  1431         }
       
  1432 
       
  1433         QGL2PEXVertexArray vertexCoordinateArray;
       
  1434         QGL2PEXVertexArray textureCoordinateArray;
       
  1435     };
       
  1436 
       
  1437 }
       
  1438 
       
  1439 // #define QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO
       
  1440 
       
  1441 void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType,
       
  1442                                                 QStaticTextItem *staticTextItem,
       
  1443                                                 bool includeMatrixInCache)
  1257 {
  1444 {
  1258     Q_Q(QGL2PaintEngineEx);
  1445     Q_Q(QGL2PaintEngineEx);
  1259 
  1446 
  1260     QVarLengthArray<QFixedPoint> positions;
  1447     QOpenGL2PaintEngineState *s = q->state();
  1261     QVarLengthArray<glyph_t> glyphs;
       
  1262     QTransform matrix = QTransform::fromTranslate(p.x(), p.y());
       
  1263     ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
       
  1264 
  1448 
  1265     QGLTextureGlyphCache *cache =
  1449     QGLTextureGlyphCache *cache =
  1266             (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, glyphType, QTransform());
  1450         (QGLTextureGlyphCache *) staticTextItem->fontEngine->glyphCache(ctx, glyphType,
  1267 
  1451                                                                         includeMatrixInCache
       
  1452                                                                           ? s->matrix
       
  1453                                                                           : QTransform());
  1268     if (!cache || cache->cacheType() != glyphType) {
  1454     if (!cache || cache->cacheType() != glyphType) {
  1269         cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform());
  1455         cache = new QGLTextureGlyphCache(ctx, glyphType,
  1270         ti.fontEngine->setGlyphCache(ctx, cache);
  1456                                          includeMatrixInCache ? s->matrix : QTransform());
       
  1457         staticTextItem->fontEngine->setGlyphCache(ctx, cache);
  1271     }
  1458     }
  1272 
  1459 
  1273     cache->setPaintEnginePrivate(this);
  1460     cache->setPaintEnginePrivate(this);
  1274     cache->populate(ti, glyphs, positions);
  1461     cache->populate(staticTextItem->fontEngine, staticTextItem->numGlyphs, staticTextItem->glyphs,
       
  1462                     staticTextItem->glyphPositions);
  1275 
  1463 
  1276     if (cache->width() == 0 || cache->height() == 0)
  1464     if (cache->width() == 0 || cache->height() == 0)
  1277         return;
  1465         return;
  1278 
  1466 
  1279     transferMode(TextDrawingMode);
  1467     transferMode(TextDrawingMode);
  1281     int margin = cache->glyphMargin();
  1469     int margin = cache->glyphMargin();
  1282 
  1470 
  1283     GLfloat dx = 1.0 / cache->width();
  1471     GLfloat dx = 1.0 / cache->width();
  1284     GLfloat dy = 1.0 / cache->height();
  1472     GLfloat dy = 1.0 / cache->height();
  1285 
  1473 
  1286     vertexCoordinateArray.clear();
  1474     bool recreateVertexArrays = false;
  1287     textureCoordinateArray.clear();
  1475     if (staticTextItem->userDataNeedsUpdate)
  1288 
  1476         recreateVertexArrays = true;
  1289     for (int i=0; i<glyphs.size(); ++i) {
  1477     else if (staticTextItem->userData == 0)
  1290         const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]);
  1478         recreateVertexArrays = true;
  1291         int x = positions[i].x.toInt() + c.baseLineX - margin;
  1479     else if (staticTextItem->userData->type != QStaticTextUserData::OpenGLUserData)
  1292         int y = positions[i].y.toInt() - c.baseLineY - margin;
  1480         recreateVertexArrays = true;
  1293 
  1481 
  1294         vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h));
  1482     // Use global arrays by default
  1295         textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy));
  1483     QGL2PEXVertexArray *vertexCoordinates = &vertexCoordinateArray;
  1296     }
  1484     QGL2PEXVertexArray *textureCoordinates = &textureCoordinateArray;
  1297 
  1485 
  1298     setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data());
  1486     if (staticTextItem->useBackendOptimizations) {
  1299     setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data());
  1487         QOpenGLStaticTextUserData *userData = 0;
       
  1488 
       
  1489         if (staticTextItem->userData == 0
       
  1490             || staticTextItem->userData->type != QStaticTextUserData::OpenGLUserData) {
       
  1491 
       
  1492             userData = new QOpenGLStaticTextUserData();
       
  1493             staticTextItem->setUserData(userData);
       
  1494 
       
  1495         } else {
       
  1496             userData = static_cast<QOpenGLStaticTextUserData*>(staticTextItem->userData);
       
  1497         }
       
  1498 
       
  1499         // Use cache if backend optimizations is turned on
       
  1500         vertexCoordinates = &userData->vertexCoordinateArray;
       
  1501         textureCoordinates = &userData->textureCoordinateArray;
       
  1502     }
       
  1503 
       
  1504 
       
  1505     if (recreateVertexArrays) {
       
  1506         vertexCoordinates->clear();
       
  1507         textureCoordinates->clear();
       
  1508 
       
  1509         for (int i=0; i<staticTextItem->numGlyphs; ++i) {
       
  1510             const QTextureGlyphCache::Coord &c = cache->coords.value(staticTextItem->glyphs[i]);
       
  1511             int x = staticTextItem->glyphPositions[i].x.toInt() + c.baseLineX - margin;
       
  1512             int y = staticTextItem->glyphPositions[i].y.toInt() - c.baseLineY - margin;
       
  1513 
       
  1514             vertexCoordinates->addQuad(QRectF(x, y, c.w, c.h));
       
  1515             textureCoordinates->addQuad(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy));
       
  1516         }
       
  1517 
       
  1518         staticTextItem->userDataNeedsUpdate = false;
       
  1519     }
       
  1520 
       
  1521     if (elementIndices.size() < staticTextItem->numGlyphs*6) {
       
  1522         Q_ASSERT(elementIndices.size() % 6 == 0);
       
  1523         int j = elementIndices.size() / 6 * 4;
       
  1524         while (j < staticTextItem->numGlyphs*4) {
       
  1525             elementIndices.append(j + 0);
       
  1526             elementIndices.append(j + 0);
       
  1527             elementIndices.append(j + 1);
       
  1528             elementIndices.append(j + 2);
       
  1529             elementIndices.append(j + 3);
       
  1530             elementIndices.append(j + 3);
       
  1531 
       
  1532             j += 4;
       
  1533         }
       
  1534 
       
  1535 #if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
       
  1536         if (elementIndicesVBOId == 0)
       
  1537             glGenBuffers(1, &elementIndicesVBOId);
       
  1538 
       
  1539         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId);
       
  1540         glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementIndices.size() * sizeof(GLushort),
       
  1541                      elementIndices.constData(), GL_STATIC_DRAW);
       
  1542 #endif
       
  1543     } else {
       
  1544 #if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
       
  1545         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId);
       
  1546 #endif
       
  1547     }
       
  1548 
       
  1549     setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data());
       
  1550     setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data());
  1300 
  1551 
  1301     if (addOffset) {
  1552     if (addOffset) {
  1302         addOffset = false;
  1553         addOffset = false;
  1303         matrixDirty = true;
  1554         matrixDirty = true;
  1304     }
  1555     }
  1307         matrixDirty = true;
  1558         matrixDirty = true;
  1308     }
  1559     }
  1309 
  1560 
  1310     QBrush pensBrush = q->state()->pen.brush();
  1561     QBrush pensBrush = q->state()->pen.brush();
  1311     setBrush(pensBrush);
  1562     setBrush(pensBrush);
       
  1563 
       
  1564     // When painting a QStaticTextItem, the glyph positions are already in device coordinates,
       
  1565     // therefore we temporarily set an identity matrix on the painter for the draw call to
       
  1566     // avoid transforming the positions twice.
       
  1567     QTransform old = s->matrix;
       
  1568     if (includeMatrixInCache)
       
  1569         s->matrix = QTransform();
  1312 
  1570 
  1313     if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
  1571     if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
  1314 
  1572 
  1315         // Subpixel antialiasing without gamma correction
  1573         // Subpixel antialiasing without gamma correction
  1316 
  1574 
  1361             glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
  1619             glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
  1362             glBindTexture(GL_TEXTURE_2D, cache->texture());
  1620             glBindTexture(GL_TEXTURE_2D, cache->texture());
  1363             updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
  1621             updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
  1364 
  1622 
  1365             shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
  1623             shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
  1366             glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size());
  1624 #if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
       
  1625             glDrawElements(GL_TRIANGLE_STRIP, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_SHORT, 0);
       
  1626 #else
       
  1627             glDrawElements(GL_TRIANGLE_STRIP, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data());
       
  1628 #endif
  1367 
  1629 
  1368             shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMaskPass2);
  1630             shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMaskPass2);
  1369 
  1631 
  1370             if (compMode == QPainter::CompositionMode_Source) {
  1632             if (compMode == QPainter::CompositionMode_Source) {
  1371                 q->state()->opacity = oldOpacity;
  1633                 q->state()->opacity = oldOpacity;
  1387         prepareForDraw(false); // Text always causes src pixels to be transparent
  1649         prepareForDraw(false); // Text always causes src pixels to be transparent
  1388     }
  1650     }
  1389     //### TODO: Gamma correction
  1651     //### TODO: Gamma correction
  1390 
  1652 
  1391     glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
  1653     glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
  1392     glBindTexture(GL_TEXTURE_2D, cache->texture());
  1654     if (lastMaskTextureUsed != cache->texture()) {
  1393     updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
  1655         glBindTexture(GL_TEXTURE_2D, cache->texture());
  1394 
  1656         lastMaskTextureUsed = cache->texture();
       
  1657     }
       
  1658     updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, s->matrix.type() > QTransform::TxTranslate);
  1395     shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
  1659     shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
  1396     glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size());
  1660 
  1397 }
  1661 #if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
  1398 
  1662     glDrawElements(GL_TRIANGLE_STRIP, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_SHORT, 0);
  1399 void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints)
  1663     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
       
  1664 #else
       
  1665     glDrawElements(GL_TRIANGLE_STRIP, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data());
       
  1666 #endif
       
  1667 
       
  1668     if (includeMatrixInCache)
       
  1669         s->matrix = old;
       
  1670 }
       
  1671 
       
  1672 void QGL2PaintEngineEx::drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap,
       
  1673                                             QPainter::PixmapFragmentHints hints)
  1400 {
  1674 {
  1401     Q_D(QGL2PaintEngineEx);
  1675     Q_D(QGL2PaintEngineEx);
  1402     // Use fallback for extended composition modes.
  1676     // Use fallback for extended composition modes.
  1403     if (state()->composition_mode > QPainter::CompositionMode_Plus) {
  1677     if (state()->composition_mode > QPainter::CompositionMode_Plus) {
  1404         QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints);
  1678         QPaintEngineEx::drawPixmapFragments(fragments, fragmentCount, pixmap, hints);
  1405         return;
  1679         return;
  1406     }
  1680     }
  1407 
  1681 
  1408     ensureActive();
  1682     ensureActive();
  1409     d->drawPixmaps(drawingData, dataCount, pixmap, hints);
  1683     d->drawPixmapFragments(fragments, fragmentCount, pixmap, hints);
  1410 }
  1684 }
  1411 
  1685 
  1412 
  1686 
  1413 void QGL2PaintEngineExPrivate::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints)
  1687 void QGL2PaintEngineExPrivate::drawPixmapFragments(const QPainter::PixmapFragment *fragments,
       
  1688                                                    int fragmentCount, const QPixmap &pixmap,
       
  1689                                                    QPainter::PixmapFragmentHints hints)
  1414 {
  1690 {
  1415     GLfloat dx = 1.0f / pixmap.size().width();
  1691     GLfloat dx = 1.0f / pixmap.size().width();
  1416     GLfloat dy = 1.0f / pixmap.size().height();
  1692     GLfloat dy = 1.0f / pixmap.size().height();
  1417 
  1693 
  1418     vertexCoordinateArray.clear();
  1694     vertexCoordinateArray.clear();
  1429         matrixDirty = true;
  1705         matrixDirty = true;
  1430     }
  1706     }
  1431 
  1707 
  1432     bool allOpaque = true;
  1708     bool allOpaque = true;
  1433 
  1709 
  1434     for (int i = 0; i < dataCount; ++i) {
  1710     for (int i = 0; i < fragmentCount; ++i) {
  1435         qreal s = 0;
  1711         qreal s = 0;
  1436         qreal c = 1;
  1712         qreal c = 1;
  1437         if (drawingData[i].rotation != 0) {
  1713         if (fragments[i].rotation != 0) {
  1438             s = qFastSin(drawingData[i].rotation * Q_PI / 180);
  1714             s = qFastSin(fragments[i].rotation * Q_PI / 180);
  1439             c = qFastCos(drawingData[i].rotation * Q_PI / 180);
  1715             c = qFastCos(fragments[i].rotation * Q_PI / 180);
  1440         }
  1716         }
  1441 
  1717 
  1442         qreal right = 0.5 * drawingData[i].scaleX * drawingData[i].source.width();
  1718         qreal right = 0.5 * fragments[i].scaleX * fragments[i].width;
  1443         qreal bottom = 0.5 * drawingData[i].scaleY * drawingData[i].source.height();
  1719         qreal bottom = 0.5 * fragments[i].scaleY * fragments[i].height;
  1444         QGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c);
  1720         QGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c);
  1445         QGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c);
  1721         QGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c);
  1446 
  1722 
  1447         vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y());
  1723         vertexCoordinateArray.addVertex(bottomRight.x + fragments[i].x, bottomRight.y + fragments[i].y);
  1448         vertexCoordinateArray.lineToArray(-bottomLeft.x + drawingData[i].point.x(), -bottomLeft.y + drawingData[i].point.y());
  1724         vertexCoordinateArray.addVertex(-bottomLeft.x + fragments[i].x, -bottomLeft.y + fragments[i].y);
  1449         vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y());
  1725         vertexCoordinateArray.addVertex(-bottomRight.x + fragments[i].x, -bottomRight.y + fragments[i].y);
  1450         vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y());
  1726         vertexCoordinateArray.addVertex(-bottomRight.x + fragments[i].x, -bottomRight.y + fragments[i].y);
  1451         vertexCoordinateArray.lineToArray(bottomLeft.x + drawingData[i].point.x(), bottomLeft.y + drawingData[i].point.y());
  1727         vertexCoordinateArray.addVertex(bottomLeft.x + fragments[i].x, bottomLeft.y + fragments[i].y);
  1452         vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y());
  1728         vertexCoordinateArray.addVertex(bottomRight.x + fragments[i].x, bottomRight.y + fragments[i].y);
  1453 
  1729 
  1454         QGLRect src(drawingData[i].source.left() * dx, drawingData[i].source.top() * dy,
  1730         QGLRect src(fragments[i].sourceLeft * dx, fragments[i].sourceTop * dy,
  1455                     drawingData[i].source.right() * dx, drawingData[i].source.bottom() * dy);
  1731                     (fragments[i].sourceLeft + fragments[i].width) * dx,
  1456 
  1732                     (fragments[i].sourceTop + fragments[i].height) * dy);
  1457         textureCoordinateArray.lineToArray(src.right, src.bottom);
  1733 
  1458         textureCoordinateArray.lineToArray(src.right, src.top);
  1734         textureCoordinateArray.addVertex(src.right, src.bottom);
  1459         textureCoordinateArray.lineToArray(src.left, src.top);
  1735         textureCoordinateArray.addVertex(src.right, src.top);
  1460         textureCoordinateArray.lineToArray(src.left, src.top);
  1736         textureCoordinateArray.addVertex(src.left, src.top);
  1461         textureCoordinateArray.lineToArray(src.left, src.bottom);
  1737         textureCoordinateArray.addVertex(src.left, src.top);
  1462         textureCoordinateArray.lineToArray(src.right, src.bottom);
  1738         textureCoordinateArray.addVertex(src.left, src.bottom);
  1463 
  1739         textureCoordinateArray.addVertex(src.right, src.bottom);
  1464         qreal opacity = drawingData[i].opacity * q->state()->opacity;
  1740 
       
  1741         qreal opacity = fragments[i].opacity * q->state()->opacity;
  1465         opacityArray << opacity << opacity << opacity << opacity << opacity << opacity;
  1742         opacityArray << opacity << opacity << opacity << opacity << opacity << opacity;
  1466         allOpaque &= (opacity >= 0.99f);
  1743         allOpaque &= (opacity >= 0.99f);
  1467     }
  1744     }
  1468 
  1745 
  1469     glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
  1746     glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
  1472                                                      | QGLContext::CanFlipNativePixmapBindOption);
  1749                                                      | QGLContext::CanFlipNativePixmapBindOption);
  1473 
  1750 
  1474     if (texture->options & QGLContext::InvertedYBindOption) {
  1751     if (texture->options & QGLContext::InvertedYBindOption) {
  1475         // Flip texture y-coordinate.
  1752         // Flip texture y-coordinate.
  1476         QGLPoint *data = textureCoordinateArray.data();
  1753         QGLPoint *data = textureCoordinateArray.data();
  1477         for (int i = 0; i < 6 * dataCount; ++i)
  1754         for (int i = 0; i < 6 * fragmentCount; ++i)
  1478             data[i].y = 1 - data[i].y;
  1755             data[i].y = 1 - data[i].y;
  1479     }
  1756     }
  1480 
  1757 
  1481     transferMode(ImageArrayDrawingMode);
  1758     transferMode(ImageArrayDrawingMode);
  1482 
  1759 
  1483     bool isBitmap = pixmap.isQBitmap();
  1760     bool isBitmap = pixmap.isQBitmap();
  1484     bool isOpaque = !isBitmap && (!pixmap.hasAlphaChannel() || (hints & QDrawPixmaps::OpaqueHint)) && allOpaque;
  1761     bool isOpaque = !isBitmap && (!pixmap.hasAlphaChannel() || (hints & QPainter::OpaqueHint)) && allOpaque;
  1485 
  1762 
  1486     updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
  1763     updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
  1487                            q->state()->renderHints & QPainter::SmoothPixmapTransform, texture->id);
  1764                            q->state()->renderHints & QPainter::SmoothPixmapTransform, texture->id);
  1488 
  1765 
  1489     // Setup for texture drawing
  1766     // Setup for texture drawing
  1490     currentBrush = noBrush;
  1767     currentBrush = noBrush;
  1491     shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc);
  1768     shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc
       
  1769                                             : QGLEngineShaderManager::ImageSrc);
  1492     if (prepareForDraw(isOpaque))
  1770     if (prepareForDraw(isOpaque))
  1493         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
  1771         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
  1494 
  1772 
  1495     if (isBitmap) {
  1773     if (isBitmap) {
  1496         QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity);
  1774         QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity);
  1497         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
  1775         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
  1498     }
  1776     }
  1499 
  1777 
  1500     glDrawArrays(GL_TRIANGLES, 0, 6 * dataCount);
  1778     glDrawArrays(GL_TRIANGLES, 0, 6 * fragmentCount);
  1501 }
  1779 }
  1502 
  1780 
  1503 bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
  1781 bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
  1504 {
  1782 {
  1505     Q_D(QGL2PaintEngineEx);
  1783     Q_D(QGL2PaintEngineEx);
  1520     d->width = sz.width();
  1798     d->width = sz.width();
  1521     d->height = sz.height();
  1799     d->height = sz.height();
  1522     d->mode = BrushDrawingMode;
  1800     d->mode = BrushDrawingMode;
  1523     d->brushTextureDirty = true;
  1801     d->brushTextureDirty = true;
  1524     d->brushUniformsDirty = true;
  1802     d->brushUniformsDirty = true;
       
  1803     d->matrixUniformDirty = true;
  1525     d->matrixDirty = true;
  1804     d->matrixDirty = true;
  1526     d->compositionModeDirty = true;
  1805     d->compositionModeDirty = true;
  1527     d->opacityUniformDirty = true;
  1806     d->opacityUniformDirty = true;
  1528     d->needsSync = true;
  1807     d->needsSync = true;
  1529     d->useSystemClip = !systemClip().isEmpty();
  1808     d->useSystemClip = !systemClip().isEmpty();
  1602 #ifdef QT_OPENGL_CACHE_AS_VBOS
  1881 #ifdef QT_OPENGL_CACHE_AS_VBOS
  1603     if (!d->unusedVBOSToClean.isEmpty()) {
  1882     if (!d->unusedVBOSToClean.isEmpty()) {
  1604         glDeleteBuffers(d->unusedVBOSToClean.size(), d->unusedVBOSToClean.constData());
  1883         glDeleteBuffers(d->unusedVBOSToClean.size(), d->unusedVBOSToClean.constData());
  1605         d->unusedVBOSToClean.clear();
  1884         d->unusedVBOSToClean.clear();
  1606     }
  1885     }
       
  1886     if (!d->unusedIBOSToClean.isEmpty()) {
       
  1887         glDeleteBuffers(d->unusedIBOSToClean.size(), d->unusedIBOSToClean.constData());
       
  1888         d->unusedIBOSToClean.clear();
       
  1889     }
  1607 #endif
  1890 #endif
  1608 
  1891 
  1609     return false;
  1892     return false;
  1610 }
  1893 }
  1611 
  1894 
  1623 
  1906 
  1624     if (d->needsSync) {
  1907     if (d->needsSync) {
  1625         d->transferMode(BrushDrawingMode);
  1908         d->transferMode(BrushDrawingMode);
  1626         glViewport(0, 0, d->width, d->height);
  1909         glViewport(0, 0, d->width, d->height);
  1627         d->needsSync = false;
  1910         d->needsSync = false;
       
  1911         d->lastMaskTextureUsed = 0;
  1628         d->shaderManager->setDirty();
  1912         d->shaderManager->setDirty();
  1629         d->ctx->d_func()->syncGlState();
  1913         d->ctx->d_func()->syncGlState();
  1630         for (int i = 0; i < 3; ++i)
  1914         for (int i = 0; i < 3; ++i)
  1631             d->vertexAttribPointers[i] = (GLfloat*)-1; // Assume the pointers are clobbered
  1915             d->vertexAttribPointers[i] = (GLfloat*)-1; // Assume the pointers are clobbered
  1632         setState(state());
  1916         setState(state());