src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
changeset 3 41300fa6a67c
parent 0 1918ee327afb
child 4 3b1da2848fc7
child 7 f7bc934e204c
child 18 2f34d5167611
equal deleted inserted replaced
2:56cd8111b7f7 3:41300fa6a67c
    60     The shader manager should only switch when we tell it to. E.g. if we set a new
    60     The shader manager should only switch when we tell it to. E.g. if we set a new
    61     brush style and then switch to transparent painter, we only want it to compile
    61     brush style and then switch to transparent painter, we only want it to compile
    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
       
    66 
    65 #include "qpaintengineex_opengl2_p.h"
    67 #include "qpaintengineex_opengl2_p.h"
    66 
    68 
    67 #include <string.h> //for memcpy
    69 #include <string.h> //for memcpy
    68 #include <qmath.h>
    70 #include <qmath.h>
    69 
    71 
   156     , ctx(context)
   158     , ctx(context)
   157     , m_width(0)
   159     , m_width(0)
   158     , m_height(0)
   160     , m_height(0)
   159 {
   161 {
   160     glGenFramebuffers(1, &m_fbo);
   162     glGenFramebuffers(1, &m_fbo);
   161     connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext *)),
   163     connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)),
   162             SLOT(contextDestroyed(const QGLContext *)));
   164             SLOT(contextDestroyed(const QGLContext*)));
   163 }
   165 }
   164 
   166 
   165 QGLTextureGlyphCache::~QGLTextureGlyphCache()
   167 QGLTextureGlyphCache::~QGLTextureGlyphCache()
   166 {
   168 {
   167     if (ctx) {
   169     if (ctx) {
   244     glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
   246     glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
   245 
   247 
   246     glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray);
   248     glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray);
   247     glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray);
   249     glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray);
   248 
   250 
   249     pex->shaderManager->blitProgram()->enable();
   251     pex->shaderManager->blitProgram()->bind();
   250     pex->shaderManager->blitProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT);
   252     pex->shaderManager->blitProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT);
   251     pex->shaderManager->setDirty();
   253     pex->shaderManager->setDirty();
   252 
   254 
   253     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
   255     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
   254 
   256 
   342 ////////////////////////////////// Private Methods //////////////////////////////////////////
   344 ////////////////////////////////// Private Methods //////////////////////////////////////////
   343 
   345 
   344 QGL2PaintEngineExPrivate::~QGL2PaintEngineExPrivate()
   346 QGL2PaintEngineExPrivate::~QGL2PaintEngineExPrivate()
   345 {
   347 {
   346     delete shaderManager;
   348     delete shaderManager;
       
   349 
       
   350     while (pathCaches.size()) {
       
   351         QVectorPath::CacheEntry *e = *(pathCaches.constBegin());
       
   352         e->cleanup(e->engine, e->data);
       
   353         e->data = 0;
       
   354         e->engine = 0;
       
   355     }
   347 }
   356 }
   348 
   357 
   349 void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id)
   358 void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id)
   350 {
   359 {
   351 //    glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); //### Is it always this texture unit?
   360 //    glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); //### Is it always this texture unit?
   375     c.setBlueF(c.blueF() * alpha);
   384     c.setBlueF(c.blueF() * alpha);
   376     return c;
   385     return c;
   377 }
   386 }
   378 
   387 
   379 
   388 
   380 void QGL2PaintEngineExPrivate::setBrush(const QBrush* brush)
   389 void QGL2PaintEngineExPrivate::setBrush(const QBrush& brush)
   381 {
   390 {
       
   391     Q_ASSERT(brush.style() != Qt::NoBrush);
       
   392 
       
   393     if (qbrush_fast_equals(currentBrush, brush))
       
   394         return;
       
   395 
   382     currentBrush = brush;
   396     currentBrush = brush;
       
   397 
   383     brushTextureDirty = true;
   398     brushTextureDirty = true;
   384     brushUniformsDirty = true;
   399     brushUniformsDirty = true;
   385     if (currentBrush->style() == Qt::TexturePattern
   400     if (currentBrush.style() == Qt::TexturePattern
   386         && qHasPixmapTexture(*brush) && brush->texture().isQBitmap())
   401         && qHasPixmapTexture(brush) && brush.texture().isQBitmap())
   387     {
   402     {
   388         shaderManager->setSrcPixelType(QGLEngineShaderManager::TextureSrcWithPattern);
   403         shaderManager->setSrcPixelType(QGLEngineShaderManager::TextureSrcWithPattern);
   389     } else {
   404     } else {
   390         shaderManager->setSrcPixelType(currentBrush->style());
   405         shaderManager->setSrcPixelType(currentBrush.style());
   391     }
   406     }
   392     shaderManager->optimiseForBrushTransform(currentBrush->transform());
   407     shaderManager->optimiseForBrushTransform(currentBrush.transform());
   393 }
   408 }
   394 
   409 
   395 
   410 
   396 void QGL2PaintEngineExPrivate::useSimpleShader()
   411 void QGL2PaintEngineExPrivate::useSimpleShader()
   397 {
   412 {
   398     shaderManager->simpleProgram()->enable();
   413     shaderManager->simpleProgram()->bind();
   399     shaderManager->setDirty();
   414     shaderManager->setDirty();
   400 
   415 
   401     if (matrixDirty)
   416     if (matrixDirty)
   402         updateMatrix();
   417         updateMatrix();
   403 
   418 
   409 
   424 
   410 void QGL2PaintEngineExPrivate::updateBrushTexture()
   425 void QGL2PaintEngineExPrivate::updateBrushTexture()
   411 {
   426 {
   412     Q_Q(QGL2PaintEngineEx);
   427     Q_Q(QGL2PaintEngineEx);
   413 //     qDebug("QGL2PaintEngineExPrivate::updateBrushTexture()");
   428 //     qDebug("QGL2PaintEngineExPrivate::updateBrushTexture()");
   414     Qt::BrushStyle style = currentBrush->style();
   429     Qt::BrushStyle style = currentBrush.style();
   415 
   430 
   416     if ( (style >= Qt::Dense1Pattern) && (style <= Qt::DiagCrossPattern) ) {
   431     if ( (style >= Qt::Dense1Pattern) && (style <= Qt::DiagCrossPattern) ) {
   417         // Get the image data for the pattern
   432         // Get the image data for the pattern
   418         QImage texImage = qt_imageForBrush(style, false);
   433         QImage texImage = qt_imageForBrush(style, false);
   419 
   434 
   422         updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform);
   437         updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform);
   423     }
   438     }
   424     else if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) {
   439     else if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) {
   425         // Gradiant brush: All the gradiants use the same texture
   440         // Gradiant brush: All the gradiants use the same texture
   426 
   441 
   427         const QGradient* g = currentBrush->gradient();
   442         const QGradient* g = currentBrush.gradient();
   428 
   443 
   429         // We apply global opacity in the fragment shaders, so we always pass 1.0
   444         // We apply global opacity in the fragment shaders, so we always pass 1.0
   430         // for opacity to the cache.
   445         // for opacity to the cache.
   431         GLuint texId = QGL2GradientCache::cacheForContext(ctx)->getBuffer(*g, 1.0);
   446         GLuint texId = QGL2GradientCache::cacheForContext(ctx)->getBuffer(*g, 1.0);
   432 
   447 
   439             updateTextureFilter(GL_TEXTURE_2D, GL_MIRRORED_REPEAT_IBM, q->state()->renderHints & QPainter::SmoothPixmapTransform);
   454             updateTextureFilter(GL_TEXTURE_2D, GL_MIRRORED_REPEAT_IBM, q->state()->renderHints & QPainter::SmoothPixmapTransform);
   440         else
   455         else
   441             updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, q->state()->renderHints & QPainter::SmoothPixmapTransform);
   456             updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, q->state()->renderHints & QPainter::SmoothPixmapTransform);
   442     }
   457     }
   443     else if (style == Qt::TexturePattern) {
   458     else if (style == Qt::TexturePattern) {
   444         const QPixmap& texPixmap = currentBrush->texture();
   459         const QPixmap& texPixmap = currentBrush.texture();
   445 
   460 
   446         glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT);
   461         glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT);
   447         QGLTexture *tex = ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption);
   462         QGLTexture *tex = ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption);
   448         updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform);
   463         updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform);
   449         textureInvertedY = tex->options & QGLContext::InvertedYBindOption ? -1 : 1;
   464         textureInvertedY = tex->options & QGLContext::InvertedYBindOption ? -1 : 1;
   453 
   468 
   454 
   469 
   455 void QGL2PaintEngineExPrivate::updateBrushUniforms()
   470 void QGL2PaintEngineExPrivate::updateBrushUniforms()
   456 {
   471 {
   457 //     qDebug("QGL2PaintEngineExPrivate::updateBrushUniforms()");
   472 //     qDebug("QGL2PaintEngineExPrivate::updateBrushUniforms()");
   458     Qt::BrushStyle style = currentBrush->style();
   473     Qt::BrushStyle style = currentBrush.style();
   459 
   474 
   460     if (style == Qt::NoBrush)
   475     if (style == Qt::NoBrush)
   461         return;
   476         return;
   462 
   477 
   463     QTransform brushQTransform = currentBrush->transform();
   478     QTransform brushQTransform = currentBrush.transform();
   464 
   479 
   465     if (style == Qt::SolidPattern) {
   480     if (style == Qt::SolidPattern) {
   466         QColor col = qt_premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity);
   481         QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity);
   467         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::FragmentColor), col);
   482         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::FragmentColor), col);
   468     }
   483     }
   469     else {
   484     else {
   470         // All other brushes have a transform and thus need the translation point:
   485         // All other brushes have a transform and thus need the translation point:
   471         QPointF translationPoint;
   486         QPointF translationPoint;
   472 
   487 
   473         if (style <= Qt::DiagCrossPattern) {
   488         if (style <= Qt::DiagCrossPattern) {
   474             QColor col = qt_premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity);
   489             QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity);
   475 
   490 
   476             shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
   491             shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
   477 
   492 
   478             QVector2D halfViewportSize(width*0.5, height*0.5);
   493             QVector2D halfViewportSize(width*0.5, height*0.5);
   479             shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
   494             shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
   480         }
   495         }
   481         else if (style == Qt::LinearGradientPattern) {
   496         else if (style == Qt::LinearGradientPattern) {
   482             const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush->gradient());
   497             const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush.gradient());
   483 
   498 
   484             QPointF realStart = g->start();
   499             QPointF realStart = g->start();
   485             QPointF realFinal = g->finalStop();
   500             QPointF realFinal = g->finalStop();
   486             translationPoint = realStart;
   501             translationPoint = realStart;
   487 
   502 
   497 
   512 
   498             QVector2D halfViewportSize(width*0.5, height*0.5);
   513             QVector2D halfViewportSize(width*0.5, height*0.5);
   499             shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
   514             shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
   500         }
   515         }
   501         else if (style == Qt::ConicalGradientPattern) {
   516         else if (style == Qt::ConicalGradientPattern) {
   502             const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrush->gradient());
   517             const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrush.gradient());
   503             translationPoint   = g->center();
   518             translationPoint   = g->center();
   504 
   519 
   505             GLfloat angle = -(g->angle() * 2 * Q_PI) / 360.0;
   520             GLfloat angle = -(g->angle() * 2 * Q_PI) / 360.0;
   506 
   521 
   507             shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Angle), angle);
   522             shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Angle), angle);
   508 
   523 
   509             QVector2D halfViewportSize(width*0.5, height*0.5);
   524             QVector2D halfViewportSize(width*0.5, height*0.5);
   510             shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
   525             shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
   511         }
   526         }
   512         else if (style == Qt::RadialGradientPattern) {
   527         else if (style == Qt::RadialGradientPattern) {
   513             const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush->gradient());
   528             const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush.gradient());
   514             QPointF realCenter = g->center();
   529             QPointF realCenter = g->center();
   515             QPointF realFocal  = g->focalPoint();
   530             QPointF realFocal  = g->focalPoint();
   516             qreal   realRadius = g->radius();
   531             qreal   realRadius = g->radius();
   517             translationPoint   = realFocal;
   532             translationPoint   = realFocal;
   518 
   533 
   526 
   541 
   527             QVector2D halfViewportSize(width*0.5, height*0.5);
   542             QVector2D halfViewportSize(width*0.5, height*0.5);
   528             shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
   543             shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
   529         }
   544         }
   530         else if (style == Qt::TexturePattern) {
   545         else if (style == Qt::TexturePattern) {
   531             const QPixmap& texPixmap = currentBrush->texture();
   546             const QPixmap& texPixmap = currentBrush.texture();
   532 
   547 
   533             if (qHasPixmapTexture(*currentBrush) && currentBrush->texture().isQBitmap()) {
   548             if (qHasPixmapTexture(currentBrush) && currentBrush.texture().isQBitmap()) {
   534                 QColor col = qt_premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity);
   549                 QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity);
   535                 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
   550                 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
   536             }
   551             }
   537 
   552 
   538             QSizeF invertedTextureSize(1.0 / texPixmap.width(), 1.0 * textureInvertedY / texPixmap.height());
   553             QSizeF invertedTextureSize(1.0 / texPixmap.width(), 1.0 / texPixmap.height());
   539             shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::InvertedTextureSize), invertedTextureSize);
   554             shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::InvertedTextureSize), invertedTextureSize);
   540 
   555 
   541             QVector2D halfViewportSize(width*0.5, height*0.5);
   556             QVector2D halfViewportSize(width*0.5, height*0.5);
   542             shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
   557             shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
   543         }
   558         }
   548         QTransform matrix = q->state()->matrix;
   563         QTransform matrix = q->state()->matrix;
   549         matrix.translate(brushOrigin.x(), brushOrigin.y());
   564         matrix.translate(brushOrigin.x(), brushOrigin.y());
   550 
   565 
   551         QTransform translate(1, 0, 0, 1, -translationPoint.x(), -translationPoint.y());
   566         QTransform translate(1, 0, 0, 1, -translationPoint.x(), -translationPoint.y());
   552         QTransform gl_to_qt(1, 0, 0, -1, 0, height);
   567         QTransform gl_to_qt(1, 0, 0, -1, 0, height);
   553         QTransform inv_matrix = gl_to_qt * (brushQTransform * matrix).inverted() * translate;
   568         QTransform inv_matrix;
       
   569         if (style == Qt::TexturePattern && textureInvertedY == -1)
       
   570             inv_matrix = gl_to_qt * (QTransform(1, 0, 0, -1, 0, currentBrush.texture().height()) * brushQTransform * matrix).inverted() * translate;
       
   571         else
       
   572             inv_matrix = gl_to_qt * (brushQTransform * matrix).inverted() * translate;
   554 
   573 
   555         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BrushTransform), inv_matrix);
   574         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BrushTransform), inv_matrix);
   556         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BrushTexture), QT_BRUSH_TEXTURE_UNIT);
   575         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BrushTexture), QT_BRUSH_TEXTURE_UNIT);
   557     }
   576     }
   558     brushUniformsDirty = false;
   577     brushUniformsDirty = false;
   574     //
   593     //
   575     // We expand out the multiplication to save the cost of a full 4x4
   594     // We expand out the multiplication to save the cost of a full 4x4
   576     // matrix multiplication as most of the components are trivial.
   595     // matrix multiplication as most of the components are trivial.
   577     const QTransform& transform = q->state()->matrix;
   596     const QTransform& transform = q->state()->matrix;
   578 
   597 
   579     if (mode == TextDrawingMode) {
   598     qreal wfactor = 2.0 / width;
   580         // Text drawing mode is only used for non-scaling transforms
   599     qreal hfactor = -2.0 / height;
   581         pmvMatrix[0][0] = 2.0 / width;
   600 
   582         pmvMatrix[0][1] = 0.0;
   601     pmvMatrix[0][0] = wfactor * transform.m11() - transform.m13();
   583         pmvMatrix[0][2] = 0.0;
   602     pmvMatrix[0][1] = hfactor * transform.m12() + transform.m13();
   584         pmvMatrix[0][3] = 0.0;
   603     pmvMatrix[0][2] = 0.0;
   585         pmvMatrix[1][0] = 0.0;
   604     pmvMatrix[0][3] = transform.m13();
   586         pmvMatrix[1][1] = -2.0 / height;
   605     pmvMatrix[1][0] = wfactor * transform.m21() - transform.m23();
   587         pmvMatrix[1][2] = 0.0;
   606     pmvMatrix[1][1] = hfactor * transform.m22() + transform.m23();
   588         pmvMatrix[1][3] = 0.0;
   607     pmvMatrix[1][2] = 0.0;
   589         pmvMatrix[2][0] = 0.0;
   608     pmvMatrix[1][3] = transform.m23();
   590         pmvMatrix[2][1] = 0.0;
   609     pmvMatrix[2][0] = 0.0;
   591         pmvMatrix[2][2] = -1.0;
   610     pmvMatrix[2][1] = 0.0;
   592         pmvMatrix[2][3] = 0.0;
   611     pmvMatrix[2][2] = -1.0;
   593         pmvMatrix[3][0] = pmvMatrix[0][0] * qRound(transform.dx()) - 1.0;
   612     pmvMatrix[2][3] = 0.0;
   594         pmvMatrix[3][1] = pmvMatrix[1][1] * qRound(transform.dy()) + 1.0;
   613     pmvMatrix[3][0] = wfactor * transform.dx() - transform.m33();
   595         pmvMatrix[3][2] = 0.0;
   614     pmvMatrix[3][1] = hfactor * transform.dy() + transform.m33();
   596         pmvMatrix[3][3] = 1.0;
   615     pmvMatrix[3][2] = 0.0;
   597 
   616     pmvMatrix[3][3] = transform.m33();
   598         inverseScale = 1;
   617 
   599     } else {
   618     // 1/10000 == 0.0001, so we have good enough res to cover curves
   600         qreal wfactor = 2.0 / width;
   619     // that span the entire widget...
   601         qreal hfactor = -2.0 / height;
   620     inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())),
   602 
   621                                   qMax(qAbs(transform.m12()), qAbs(transform.m21())) ),
   603         pmvMatrix[0][0] = wfactor * transform.m11() - transform.m13();
   622                         qreal(0.0001));
   604         pmvMatrix[0][1] = hfactor * transform.m12() + transform.m13();
       
   605         pmvMatrix[0][2] = 0.0;
       
   606         pmvMatrix[0][3] = transform.m13();
       
   607         pmvMatrix[1][0] = wfactor * transform.m21() - transform.m23();
       
   608         pmvMatrix[1][1] = hfactor * transform.m22() + transform.m23();
       
   609         pmvMatrix[1][2] = 0.0;
       
   610         pmvMatrix[1][3] = transform.m23();
       
   611         pmvMatrix[2][0] = 0.0;
       
   612         pmvMatrix[2][1] = 0.0;
       
   613         pmvMatrix[2][2] = -1.0;
       
   614         pmvMatrix[2][3] = 0.0;
       
   615         pmvMatrix[3][0] = wfactor * transform.dx() - transform.m33();
       
   616         pmvMatrix[3][1] = hfactor * transform.dy() + transform.m33();
       
   617         pmvMatrix[3][2] = 0.0;
       
   618         pmvMatrix[3][3] = transform.m33();
       
   619 
       
   620         // 1/10000 == 0.0001, so we have good enough res to cover curves
       
   621         // that span the entire widget...
       
   622         inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())),
       
   623                     qMax(qAbs(transform.m12()), qAbs(transform.m21())) ),
       
   624                 qreal(0.0001));
       
   625     }
       
   626 
   623 
   627     matrixDirty = false;
   624     matrixDirty = false;
   628 
   625 
   629     // The actual data has been updated so both shader program's uniforms need updating
   626     // The actual data has been updated so both shader program's uniforms need updating
   630     simpleShaderMatrixUniformDirty = true;
   627     simpleShaderMatrixUniformDirty = true;
   802         glDisableVertexAttribArray(QT_OPACITY_ATTR);
   799         glDisableVertexAttribArray(QT_OPACITY_ATTR);
   803 
   800 
   804         lastTexture = GLuint(-1);
   801         lastTexture = GLuint(-1);
   805     }
   802     }
   806 
   803 
   807     if (mode == TextDrawingMode)
       
   808         matrixDirty = true;
       
   809 
       
   810     if (newMode == TextDrawingMode) {
   804     if (newMode == TextDrawingMode) {
   811         glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
   805         glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
   812         glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
   806         glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
   813 
   807 
   814         glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data());
   808         glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data());
   815         glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data());
   809         glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data());
   816 
       
   817         matrixDirty = true;
       
   818     }
   810     }
   819 
   811 
   820     if (newMode == ImageDrawingMode) {
   812     if (newMode == ImageDrawingMode) {
   821         glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
   813         glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
   822         glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
   814         glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
   840         shaderManager->setMaskType(QGLEngineShaderManager::NoMask);
   832         shaderManager->setMaskType(QGLEngineShaderManager::NoMask);
   841 
   833 
   842     mode = newMode;
   834     mode = newMode;
   843 }
   835 }
   844 
   836 
       
   837 struct QGL2PEVectorPathCache
       
   838 {
       
   839 #ifdef QT_OPENGL_CACHE_AS_VBOS
       
   840     GLuint vbo;
       
   841 #else
       
   842     float *vertices;
       
   843 #endif
       
   844     int vertexCount;
       
   845     GLenum primitiveType;
       
   846     qreal iscale;
       
   847 };
       
   848 
       
   849 void qopengl2paintengine_cleanup_vectorpath(QPaintEngineEx *engine, void *data)
       
   850 {
       
   851     QGL2PEVectorPathCache *c = (QGL2PEVectorPathCache *) data;
       
   852 #ifdef QT_OPENGL_CACHE_AS_VBOS
       
   853     QGL2PaintEngineExPrivate *d = QGL2PaintEngineExPrivate::getData((QGL2PaintEngineEx *) engine);
       
   854     d->unusedVBOSToClean << c->vbo;
       
   855 #else
       
   856     qFree(c->vertices);
       
   857 #endif
       
   858     delete c;
       
   859 }
       
   860 
   845 // Assumes everything is configured for the brush you want to use
   861 // Assumes everything is configured for the brush you want to use
   846 void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)
   862 void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)
   847 {
   863 {
   848     transferMode(BrushDrawingMode);
   864     transferMode(BrushDrawingMode);
   849 
   865 
   854     const QPointF* const points = reinterpret_cast<const QPointF*>(path.points());
   870     const QPointF* const points = reinterpret_cast<const QPointF*>(path.points());
   855 
   871 
   856     // Check to see if there's any hints
   872     // Check to see if there's any hints
   857     if (path.shape() == QVectorPath::RectangleHint) {
   873     if (path.shape() == QVectorPath::RectangleHint) {
   858         QGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y());
   874         QGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y());
   859         prepareForDraw(currentBrush->isOpaque());
   875         prepareForDraw(currentBrush.isOpaque());
   860         composite(rect);
   876         composite(rect);
   861     } else if (path.shape() == QVectorPath::EllipseHint
   877     } else if (path.isConvex()) {
   862              || path.shape() == QVectorPath::ConvexPolygonHint)
   878 
   863     {
   879         if (path.isCacheable()) {
   864         vertexCoordinateArray.clear();
   880             QVectorPath::CacheEntry *data = path.lookupCacheData(q);
   865         vertexCoordinateArray.addPath(path, inverseScale, false);
   881             QGL2PEVectorPathCache *cache;
   866         prepareForDraw(currentBrush->isOpaque());
   882 
   867         drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN);
   883             if (data) {
       
   884                 cache = (QGL2PEVectorPathCache *) data->data;
       
   885                 // Check if scale factor is exceeded for curved paths and generate curves if so...
       
   886                 if (path.isCurved()) {
       
   887                     qreal scaleFactor = cache->iscale / inverseScale;
       
   888                     if (scaleFactor < 0.5 || scaleFactor > 2.0) {
       
   889 #ifdef QT_OPENGL_CACHE_AS_VBOS
       
   890                         glDeleteBuffers(1, &cache->vbo);
       
   891                         cache->vbo = 0;
       
   892 #else
       
   893                         qFree(cache->vertices);
       
   894 #endif
       
   895                         cache->vertexCount = 0;
       
   896                     }
       
   897                 }
       
   898             } else {
       
   899                 cache = new QGL2PEVectorPathCache;
       
   900                 cache->vertexCount = 0;
       
   901                 data = const_cast<QVectorPath &>(path).addCacheData(q, cache, qopengl2paintengine_cleanup_vectorpath);
       
   902             }
       
   903 
       
   904             // Flatten the path at the current scale factor and fill it into the cache struct.
       
   905             if (!cache->vertexCount) {
       
   906                 vertexCoordinateArray.clear();
       
   907                 vertexCoordinateArray.addPath(path, inverseScale, false);
       
   908                 int vertexCount = vertexCoordinateArray.vertexCount();
       
   909                 int floatSizeInBytes = vertexCount * 2 * sizeof(float);
       
   910                 cache->vertexCount = vertexCount;
       
   911                 cache->primitiveType = GL_TRIANGLE_FAN;
       
   912                 cache->iscale = inverseScale;
       
   913 #ifdef QT_OPENGL_CACHE_AS_VBOS
       
   914                 glGenBuffers(1, &cache->vbo);
       
   915                 glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
       
   916                 glBufferData(GL_ARRAY_BUFFER, floatSizeInBytes, vertexCoordinateArray.data(), GL_STATIC_DRAW);
       
   917 #else
       
   918                 cache->vertices = (float *) qMalloc(floatSizeInBytes);
       
   919                 memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes);
       
   920 #endif
       
   921             }
       
   922 
       
   923             prepareForDraw(currentBrush.isOpaque());
       
   924             glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
       
   925 #ifdef QT_OPENGL_CACHE_AS_VBOS
       
   926             glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
       
   927             glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, 0);
       
   928 #else
       
   929             glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, cache->vertices);
       
   930 #endif
       
   931             glDrawArrays(cache->primitiveType, 0, cache->vertexCount);
       
   932 
       
   933         } else {
       
   934       //        printf(" - Marking path as cachable...\n");
       
   935             // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable
       
   936             // ### Remove before release...
       
   937             static bool do_vectorpath_cache = qgetenv("QT_OPENGL_NO_PATH_CACHE").isEmpty();
       
   938             if (do_vectorpath_cache)
       
   939                 path.makeCacheable();
       
   940             vertexCoordinateArray.clear();
       
   941             vertexCoordinateArray.addPath(path, inverseScale, false);
       
   942             prepareForDraw(currentBrush.isOpaque());
       
   943             drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN);
       
   944         }
       
   945 
   868     } else {
   946     } else {
   869         // The path is too complicated & needs the stencil technique
   947         // The path is too complicated & needs the stencil technique
   870         vertexCoordinateArray.clear();
   948         vertexCoordinateArray.clear();
   871         vertexCoordinateArray.addPath(path, inverseScale, false);
   949         vertexCoordinateArray.addPath(path, inverseScale, false);
   872 
   950 
   884         } else {
   962         } else {
   885             // Pass when high bit is set, replace stencil value with 0
   963             // Pass when high bit is set, replace stencil value with 0
   886             glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
   964             glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
   887         }
   965         }
   888 
   966 
   889         prepareForDraw(currentBrush->isOpaque());
   967         prepareForDraw(currentBrush.isOpaque());
   890 
   968 
   891         if (inRenderText)
   969         if (inRenderText)
   892             prepareDepthRangeForRenderText();
   970             prepareDepthRangeForRenderText();
   893 
   971 
   894         // Stencil the brush onto the dest buffer
   972         // Stencil the brush onto the dest buffer
   904 }
   982 }
   905 
   983 
   906 
   984 
   907 void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data,
   985 void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data,
   908                                                           int count,
   986                                                           int count,
   909                                                           const QVector<int> *stops,
   987                                                           int *stops,
       
   988                                                           int stopCount,
   910                                                           const QGLRect &bounds,
   989                                                           const QGLRect &bounds,
   911                                                           StencilFillMode mode)
   990                                                           StencilFillMode mode)
   912 {
   991 {
   913     Q_ASSERT(count || stops);
   992     Q_ASSERT(count || stops);
   914 
   993 
   962         // Inc. for front-facing triangle
  1041         // Inc. for front-facing triangle
   963         glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP);
  1042         glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP);
   964         // Dec. for back-facing "holes"
  1043         // Dec. for back-facing "holes"
   965         glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_DECR_WRAP);
  1044         glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_DECR_WRAP);
   966         glStencilMask(~GL_STENCIL_HIGH_BIT);
  1045         glStencilMask(~GL_STENCIL_HIGH_BIT);
   967         drawVertexArrays(data, stops, GL_TRIANGLE_FAN);
  1046         drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN);
   968 
  1047 
   969         if (q->state()->clipTestEnabled) {
  1048         if (q->state()->clipTestEnabled) {
   970             // Clear high bit of stencil outside of path
  1049             // Clear high bit of stencil outside of path
   971             glStencilFunc(GL_EQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT);
  1050             glStencilFunc(GL_EQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT);
   972             glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
  1051             glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
   974             composite(bounds);
  1053             composite(bounds);
   975         }
  1054         }
   976     } else if (mode == OddEvenFillMode) {
  1055     } else if (mode == OddEvenFillMode) {
   977         glStencilMask(GL_STENCIL_HIGH_BIT);
  1056         glStencilMask(GL_STENCIL_HIGH_BIT);
   978         glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit
  1057         glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit
   979         drawVertexArrays(data, stops, GL_TRIANGLE_FAN);
  1058         drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN);
   980 
  1059 
   981     } else { // TriStripStrokeFillMode
  1060     } else { // TriStripStrokeFillMode
   982         Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops
  1061         Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops
   983         glStencilMask(GL_STENCIL_HIGH_BIT);
  1062         glStencilMask(GL_STENCIL_HIGH_BIT);
   984 #if 0
  1063 #if 0
  1080     } else {
  1159     } else {
  1081         opacityMode = stateHasOpacity ? QGLEngineShaderManager::UniformOpacity
  1160         opacityMode = stateHasOpacity ? QGLEngineShaderManager::UniformOpacity
  1082                                       : QGLEngineShaderManager::NoOpacity;
  1161                                       : QGLEngineShaderManager::NoOpacity;
  1083         if (stateHasOpacity && (mode != ImageDrawingMode)) {
  1162         if (stateHasOpacity && (mode != ImageDrawingMode)) {
  1084             // Using a brush
  1163             // Using a brush
  1085             bool brushIsPattern = (currentBrush->style() >= Qt::Dense1Pattern) &&
  1164             bool brushIsPattern = (currentBrush.style() >= Qt::Dense1Pattern) &&
  1086                                   (currentBrush->style() <= Qt::DiagCrossPattern);
  1165                                   (currentBrush.style() <= Qt::DiagCrossPattern);
  1087 
  1166 
  1088             if ((currentBrush->style() == Qt::SolidPattern) || brushIsPattern)
  1167             if ((currentBrush.style() == Qt::SolidPattern) || brushIsPattern)
  1089                 opacityMode = QGLEngineShaderManager::NoOpacity; // Global opacity handled by srcPixel shader
  1168                 opacityMode = QGLEngineShaderManager::NoOpacity; // Global opacity handled by srcPixel shader
  1090         }
  1169         }
  1091     }
  1170     }
  1092     shaderManager->setOpacityMode(opacityMode);
  1171     shaderManager->setOpacityMode(opacityMode);
  1093 
  1172 
  1133 
  1212 
  1134     glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
  1213     glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
  1135 }
  1214 }
  1136 
  1215 
  1137 // Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans.
  1216 // Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans.
  1138 void QGL2PaintEngineExPrivate::drawVertexArrays(const float *data, const QVector<int> *stops,
  1217 void QGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stops, int stopCount,
  1139                                                 GLenum primitive)
  1218                                                 GLenum primitive)
  1140 {
  1219 {
  1141     // Now setup the pointer to the vertex array:
  1220     // Now setup the pointer to the vertex array:
  1142     glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
  1221     glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
  1143     glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data);
  1222     glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data);
  1144 
  1223 
  1145     int previousStop = 0;
  1224     int previousStop = 0;
  1146     foreach(int stop, *stops) {
  1225     for (int i=0; i<stopCount; ++i) {
       
  1226         int stop = stops[i];
  1147 /*
  1227 /*
  1148         qDebug("Drawing triangle fan for vertecies %d -> %d:", previousStop, stop-1);
  1228         qDebug("Drawing triangle fan for vertecies %d -> %d:", previousStop, stop-1);
  1149         for (int i=previousStop; i<stop; ++i)
  1229         for (int i=previousStop; i<stop; ++i)
  1150             qDebug("   %02d: [%.2f, %.2f]", i, vertexArray.data()[i].x, vertexArray.data()[i].y);
  1230             qDebug("   %02d: [%.2f, %.2f]", i, vertexArray.data()[i].x, vertexArray.data()[i].y);
  1151 */
  1231 */
  1199         return;
  1279         return;
  1200     if (!d->inRenderText)
  1280     if (!d->inRenderText)
  1201         ensureActive();
  1281         ensureActive();
  1202 
  1282 
  1203     QOpenGL2PaintEngineState *s = state();
  1283     QOpenGL2PaintEngineState *s = state();
  1204     bool doOffset = !(s->renderHints & QPainter::Antialiasing) && style == Qt::SolidPattern;
  1284     bool doOffset = !(s->renderHints & QPainter::Antialiasing) &&
       
  1285                     (style == Qt::SolidPattern) &&
       
  1286                     !d->multisamplingAlwaysEnabled;
  1205 
  1287 
  1206     if (doOffset) {
  1288     if (doOffset) {
  1207         d->temporaryTransform = s->matrix;
  1289         d->temporaryTransform = s->matrix;
  1208         QTransform tx = QTransform::fromTranslate(.49, .49);
  1290         QTransform tx = QTransform::fromTranslate(.49, .49);
  1209         s->matrix = s->matrix * tx;
  1291         s->matrix = s->matrix * tx;
  1210         d->matrixDirty = true;
  1292         d->matrixDirty = true;
  1211     }
  1293     }
  1212 
  1294 
  1213     d->setBrush(&brush);
  1295     d->setBrush(brush);
  1214     d->fill(path);
  1296     d->fill(path);
  1215 
  1297 
  1216     if (doOffset) {
  1298     if (doOffset) {
  1217         s->matrix = d->temporaryTransform;
  1299         s->matrix = d->temporaryTransform;
  1218         d->matrixDirty = true;
  1300         d->matrixDirty = true;
  1219     }
  1301     }
  1220 }
  1302 }
       
  1303 
       
  1304 extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
       
  1305 
  1221 
  1306 
  1222 void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
  1307 void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
  1223 {
  1308 {
  1224     Q_D(QGL2PaintEngineEx);
  1309     Q_D(QGL2PaintEngineEx);
  1225 
  1310 
  1227     const QBrush &penBrush = qpen_brush(pen);
  1312     const QBrush &penBrush = qpen_brush(pen);
  1228     if (penStyle == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush)
  1313     if (penStyle == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush)
  1229         return;
  1314         return;
  1230 
  1315 
  1231     QOpenGL2PaintEngineState *s = state();
  1316     QOpenGL2PaintEngineState *s = state();
       
  1317     if (pen.isCosmetic() && !qt_scaleForTransform(s->transform(), 0)) {
       
  1318         // QTriangulatingStroker class is not meant to support cosmetically sheared strokes.
       
  1319         QPaintEngineEx::stroke(path, pen);
       
  1320         return;
       
  1321     }
  1232 
  1322 
  1233     ensureActive();
  1323     ensureActive();
  1234 
  1324 
  1235     bool doOffset = !(s->renderHints & QPainter::Antialiasing);
  1325     bool doOffset = !(s->renderHints & QPainter::Antialiasing) && !d->multisamplingAlwaysEnabled;
  1236     if (doOffset) {
  1326     if (doOffset) {
  1237         d->temporaryTransform = s->matrix;
  1327         d->temporaryTransform = s->matrix;
  1238         QTransform tx = QTransform::fromTranslate(0.49, .49);
  1328         QTransform tx = QTransform::fromTranslate(0.49, .49);
  1239         s->matrix = s->matrix * tx;
  1329         s->matrix = s->matrix * tx;
  1240         d->matrixDirty = true;
  1330         d->matrixDirty = true;
  1241     }
  1331     }
  1242 
  1332 
  1243     bool opaque = penBrush.isOpaque() && s->opacity > 0.99;
  1333     bool opaque = penBrush.isOpaque() && s->opacity > 0.99;
  1244     d->setBrush(&penBrush);
  1334     d->setBrush(penBrush);
  1245     d->transferMode(BrushDrawingMode);
  1335     d->transferMode(BrushDrawingMode);
  1246 
  1336 
  1247     // updateMatrix() is responsible for setting the inverse scale on
  1337     // updateMatrix() is responsible for setting the inverse scale on
  1248     // the strokers, so we need to call it here and not wait for
  1338     // the strokers, so we need to call it here and not wait for
  1249     // prepareForDraw() down below.
  1339     // prepareForDraw() down below.
  1261         d->stroker.process(dashStroke, pen);
  1351         d->stroker.process(dashStroke, pen);
  1262     }
  1352     }
  1263 
  1353 
  1264 
  1354 
  1265     QGLContext *ctx = d->ctx;
  1355     QGLContext *ctx = d->ctx;
       
  1356     Q_UNUSED(ctx);
  1266 
  1357 
  1267     if (opaque) {
  1358     if (opaque) {
  1268         d->prepareForDraw(opaque);
  1359         d->prepareForDraw(opaque);
  1269         glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
  1360         glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
  1270         glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, d->stroker.vertices());
  1361         glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, d->stroker.vertices());
  1289             extra = extra * d->inverseScale;
  1380             extra = extra * d->inverseScale;
  1290 
  1381 
  1291         QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra);
  1382         QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra);
  1292 
  1383 
  1293         d->fillStencilWithVertexArray(d->stroker.vertices(), d->stroker.vertexCount() / 2,
  1384         d->fillStencilWithVertexArray(d->stroker.vertices(), d->stroker.vertexCount() / 2,
  1294                                       0, bounds, QGL2PaintEngineExPrivate::TriStripStrokeFillMode);
  1385                                       0, 0, bounds, QGL2PaintEngineExPrivate::TriStripStrokeFillMode);
  1295 
  1386 
  1296         glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
  1387         glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
  1297 
  1388 
  1298         // Pass when any bit is set, replace stencil value with 0
  1389         // Pass when any bit is set, replace stencil value with 0
  1299         glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
  1390         glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
  1431         ensureActive();
  1522         ensureActive();
  1432     QOpenGL2PaintEngineState *s = state();
  1523     QOpenGL2PaintEngineState *s = state();
  1433 
  1524 
  1434     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
  1525     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
  1435 
  1526 
  1436     bool drawCached = true;
  1527     QTransform::TransformationType txtype = s->matrix.type();
  1437 
  1528 
  1438     if (s->matrix.type() > QTransform::TxTranslate)
  1529     float det = s->matrix.determinant();
  1439         drawCached = false;
  1530     bool drawCached = txtype < QTransform::TxProject;
  1440 
  1531 
  1441     // don't try to cache huge fonts
  1532     // don't try to cache huge fonts or vastly transformed fonts
  1442     if (ti.fontEngine->fontDef.pixelSize * qSqrt(s->matrix.determinant()) >= 64)
  1533     const qreal pixelSize = ti.fontEngine->fontDef.pixelSize;
       
  1534     if (pixelSize * pixelSize * qAbs(det) >= 64 * 64 || det < 0.25f || det > 4.f)
  1443         drawCached = false;
  1535         drawCached = false;
  1444 
  1536 
  1445     QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0
  1537     QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0
  1446                                             ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat)
  1538                                             ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat)
  1447                                             : d->glyphCacheType;
  1539                                             : d->glyphCacheType;
  1448 
  1540 
  1449     if (d->inRenderText)
  1541     if (d->inRenderText || txtype > QTransform::TxTranslate)
  1450         glyphType = QFontEngineGlyphCache::Raster_A8;
  1542         glyphType = QFontEngineGlyphCache::Raster_A8;
  1451 
  1543 
  1452     if (glyphType == QFontEngineGlyphCache::Raster_RGBMask
  1544     if (glyphType == QFontEngineGlyphCache::Raster_RGBMask
  1453         && state()->composition_mode != QPainter::CompositionMode_Source
  1545         && state()->composition_mode != QPainter::CompositionMode_Source
  1454         && state()->composition_mode != QPainter::CompositionMode_SourceOver)
  1546         && state()->composition_mode != QPainter::CompositionMode_SourceOver)
  1466 
  1558 
  1467 void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType,
  1559 void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType,
  1468                                                 const QTextItemInt &ti)
  1560                                                 const QTextItemInt &ti)
  1469 {
  1561 {
  1470     Q_Q(QGL2PaintEngineEx);
  1562     Q_Q(QGL2PaintEngineEx);
  1471     QOpenGL2PaintEngineState *s = q->state();
       
  1472 
  1563 
  1473     QVarLengthArray<QFixedPoint> positions;
  1564     QVarLengthArray<QFixedPoint> positions;
  1474     QVarLengthArray<glyph_t> glyphs;
  1565     QVarLengthArray<glyph_t> glyphs;
  1475     QTransform matrix = QTransform::fromTranslate(p.x(), p.y());
  1566     QTransform matrix = QTransform::fromTranslate(p.x(), p.y());
  1476     ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
  1567     ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
  1477 
  1568 
  1478     QGLTextureGlyphCache *cache =
  1569     QGLTextureGlyphCache *cache =
  1479         (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, s->matrix);
  1570             (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, glyphType, QTransform());
  1480 
  1571 
  1481     if (!cache || cache->cacheType() != glyphType) {
  1572     if (!cache || cache->cacheType() != glyphType) {
  1482         cache = new QGLTextureGlyphCache(ctx, glyphType, s->matrix);
  1573         cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform());
  1483         ti.fontEngine->setGlyphCache(ctx, cache);
  1574         ti.fontEngine->setGlyphCache(ctx, cache);
  1484     }
  1575     }
  1485 
  1576 
  1486     cache->setPaintEnginePrivate(this);
  1577     cache->setPaintEnginePrivate(this);
  1487     cache->populate(ti, glyphs, positions);
  1578     cache->populate(ti, glyphs, positions);
  1517         glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data());
  1608         glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data());
  1518     if (textureCoordinateArray.data() != oldTextureCoordinateDataPtr)
  1609     if (textureCoordinateArray.data() != oldTextureCoordinateDataPtr)
  1519         glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data());
  1610         glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data());
  1520 
  1611 
  1521     QBrush pensBrush = q->state()->pen.brush();
  1612     QBrush pensBrush = q->state()->pen.brush();
  1522     setBrush(&pensBrush);
  1613     setBrush(pensBrush);
  1523 
  1614 
  1524     if (inRenderText)
  1615     if (inRenderText)
  1525         prepareDepthRangeForRenderText();
  1616         prepareDepthRangeForRenderText();
  1526 
  1617 
  1527     if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
  1618     if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
  1562             qreal oldOpacity = q->state()->opacity;
  1653             qreal oldOpacity = q->state()->opacity;
  1563             if (compMode == QPainter::CompositionMode_Source) {
  1654             if (compMode == QPainter::CompositionMode_Source) {
  1564                 q->state()->opacity = 1;
  1655                 q->state()->opacity = 1;
  1565                 opacityUniformDirty = true;
  1656                 opacityUniformDirty = true;
  1566                 pensBrush = Qt::white;
  1657                 pensBrush = Qt::white;
  1567                 setBrush(&pensBrush);
  1658                 setBrush(pensBrush);
  1568             }
  1659             }
  1569 
  1660 
  1570             compositionModeDirty = false; // I can handle this myself, thank you very much
  1661             compositionModeDirty = false; // I can handle this myself, thank you very much
  1571             prepareForDraw(false); // Text always causes src pixels to be transparent
  1662             prepareForDraw(false); // Text always causes src pixels to be transparent
  1572             glEnable(GL_BLEND);
  1663             glEnable(GL_BLEND);
  1583 
  1674 
  1584             if (compMode == QPainter::CompositionMode_Source) {
  1675             if (compMode == QPainter::CompositionMode_Source) {
  1585                 q->state()->opacity = oldOpacity;
  1676                 q->state()->opacity = oldOpacity;
  1586                 opacityUniformDirty = true;
  1677                 opacityUniformDirty = true;
  1587                 pensBrush = q->state()->pen.brush();
  1678                 pensBrush = q->state()->pen.brush();
  1588                 setBrush(&pensBrush);
  1679                 setBrush(pensBrush);
  1589             }
  1680             }
  1590 
  1681 
  1591             compositionModeDirty = false;
  1682             compositionModeDirty = false;
  1592             prepareForDraw(false); // Text always causes src pixels to be transparent
  1683             prepareForDraw(false); // Text always causes src pixels to be transparent
  1593             glEnable(GL_BLEND);
  1684             glEnable(GL_BLEND);
  1728     d->matrixDirty = true;
  1819     d->matrixDirty = true;
  1729     d->compositionModeDirty = true;
  1820     d->compositionModeDirty = true;
  1730     d->opacityUniformDirty = true;
  1821     d->opacityUniformDirty = true;
  1731     d->needsSync = true;
  1822     d->needsSync = true;
  1732     d->use_system_clip = !systemClip().isEmpty();
  1823     d->use_system_clip = !systemClip().isEmpty();
       
  1824     d->currentBrush = QBrush();
  1733 
  1825 
  1734     d->dirtyStencilRegion = QRect(0, 0, d->width, d->height);
  1826     d->dirtyStencilRegion = QRect(0, 0, d->width, d->height);
  1735     d->stencilClean = true;
  1827     d->stencilClean = true;
  1736 
  1828 
  1737     // Calling begin paint should make the correct context current. So, any
  1829     // Calling begin paint should make the correct context current. So, any
  1738     // code which calls into GL or otherwise needs a current context *must*
  1830     // code which calls into GL or otherwise needs a current context *must*
  1739     // go after beginPaint:
  1831     // go after beginPaint:
  1740     d->device->beginPaint();
  1832     d->device->beginPaint();
  1741 
  1833 
  1742 #if !defined(QT_OPENGL_ES_2)
  1834 #if !defined(QT_OPENGL_ES_2)
  1743     bool success = qt_resolve_version_2_0_functions(d->ctx);
  1835     bool success = qt_resolve_version_2_0_functions(d->ctx)
       
  1836                    && qt_resolve_buffer_extensions(d->ctx);
  1744     Q_ASSERT(success);
  1837     Q_ASSERT(success);
  1745     Q_UNUSED(success);
  1838     Q_UNUSED(success);
  1746 #endif
  1839 #endif
  1747 
  1840 
  1748     d->shaderManager = new QGLEngineShaderManager(d->ctx);
  1841     d->shaderManager = new QGLEngineShaderManager(d->ctx);
  1758 #endif
  1851 #endif
  1759 
  1852 
  1760     d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
  1853     d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
  1761 
  1854 
  1762 #if !defined(QT_OPENGL_ES_2)
  1855 #if !defined(QT_OPENGL_ES_2)
  1763     if (!d->device->format().alpha()
       
  1764 #if defined(Q_WS_WIN)
  1856 #if defined(Q_WS_WIN)
  1765         && qt_cleartype_enabled
  1857     if (qt_cleartype_enabled)
  1766 #endif
  1858 #endif
  1767        ) {
       
  1768         d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask;
  1859         d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask;
  1769     }
  1860 #endif
       
  1861 
       
  1862 #if defined(QT_OPENGL_ES_2)
       
  1863     // OpenGL ES can't switch MSAA off, so if the gl paint device is
       
  1864     // multisampled, it's always multisampled.
       
  1865     d->multisamplingAlwaysEnabled = d->device->format().sampleBuffers();
       
  1866 #else
       
  1867     d->multisamplingAlwaysEnabled = false;
  1770 #endif
  1868 #endif
  1771 
  1869 
  1772     return true;
  1870     return true;
  1773 }
  1871 }
  1774 
  1872 
  1793 
  1891 
  1794     d->resetGLState();
  1892     d->resetGLState();
  1795 
  1893 
  1796     delete d->shaderManager;
  1894     delete d->shaderManager;
  1797     d->shaderManager = 0;
  1895     d->shaderManager = 0;
       
  1896 
       
  1897 #ifdef QT_OPENGL_CACHE_AS_VBOS
       
  1898     if (!d->unusedVBOSToClean.isEmpty()) {
       
  1899         glDeleteBuffers(d->unusedVBOSToClean.size(), d->unusedVBOSToClean.constData());
       
  1900         d->unusedVBOSToClean.clear();
       
  1901     }
       
  1902 #endif
  1798 
  1903 
  1799     return false;
  1904     return false;
  1800 }
  1905 }
  1801 
  1906 
  1802 void QGL2PaintEngineEx::ensureActive()
  1907 void QGL2PaintEngineEx::ensureActive()
  2084     maxClip = 1;
  2189     maxClip = 1;
  2085 
  2190 
  2086     q->state()->rectangleClip = use_system_clip ? systemClip.boundingRect() : QRect(0, 0, width, height);
  2191     q->state()->rectangleClip = use_system_clip ? systemClip.boundingRect() : QRect(0, 0, width, height);
  2087     updateClipScissorTest();
  2192     updateClipScissorTest();
  2088 
  2193 
  2089     if (systemClip.numRects() == 1) {
  2194     if (systemClip.rectCount() == 1) {
  2090         if (systemClip.boundingRect() == QRect(0, 0, width, height))
  2195         if (systemClip.boundingRect() == QRect(0, 0, width, height))
  2091             use_system_clip = false;
  2196             use_system_clip = false;
  2092 #ifndef QT_GL_NO_SCISSOR_TEST
  2197 #ifndef QT_GL_NO_SCISSOR_TEST
  2093         // scissoring takes care of the system clip
  2198         // scissoring takes care of the system clip
  2094         return;
  2199         return;