src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
branchRCL_3
changeset 4 3b1da2848fc7
parent 3 41300fa6a67c
child 5 d3bac044e0f0
equal deleted inserted replaced
3:41300fa6a67c 4:3b1da2848fc7
     1 /****************************************************************************
     1 /****************************************************************************
     2 **
     2 **
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     4 ** All rights reserved.
     4 ** All rights reserved.
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     6 **
     6 **
     7 ** This file is part of the QtOpenGL module of the Qt Toolkit.
     7 ** This file is part of the QtOpenGL module of the Qt Toolkit.
     8 **
     8 **
    73 #include <private/qmath_p.h>
    73 #include <private/qmath_p.h>
    74 #include <private/qpaintengineex_p.h>
    74 #include <private/qpaintengineex_p.h>
    75 #include <QPaintEngine>
    75 #include <QPaintEngine>
    76 #include <private/qpainter_p.h>
    76 #include <private/qpainter_p.h>
    77 #include <private/qfontengine_p.h>
    77 #include <private/qfontengine_p.h>
    78 #include <private/qtextureglyphcache_p.h>
       
    79 #include <private/qpixmapdata_gl_p.h>
    78 #include <private/qpixmapdata_gl_p.h>
    80 #include <private/qdatabuffer_p.h>
    79 #include <private/qdatabuffer_p.h>
    81 
    80 
    82 #include "qglgradientcache_p.h"
    81 #include "qglgradientcache_p.h"
    83 #include "qglengineshadermanager_p.h"
    82 #include "qglengineshadermanager_p.h"
    84 #include "qgl2pexvertexarray_p.h"
    83 #include "qgl2pexvertexarray_p.h"
    85 
       
    86 #include "qtriangulatingstroker_p.h"
    84 #include "qtriangulatingstroker_p.h"
       
    85 #include "qtextureglyphcache_gl_p.h"
    87 
    86 
    88 #include <QDebug>
    87 #include <QDebug>
    89 
    88 
    90 QT_BEGIN_NAMESPACE
    89 QT_BEGIN_NAMESPACE
    91 
    90 
    92 //#define QT_GL_NO_SCISSOR_TEST
    91 //#define QT_GL_NO_SCISSOR_TEST
    93 
       
    94 static const GLuint GL_STENCIL_HIGH_BIT         = 0x80;
       
    95 static const GLuint QT_BRUSH_TEXTURE_UNIT       = 0;
       
    96 static const GLuint QT_IMAGE_TEXTURE_UNIT       = 0; //Can be the same as brush texture unit
       
    97 static const GLuint QT_MASK_TEXTURE_UNIT        = 1;
       
    98 static const GLuint QT_BACKGROUND_TEXTURE_UNIT  = 2;
       
    99 
       
   100 #ifdef Q_WS_WIN
       
   101 extern Q_GUI_EXPORT bool qt_cleartype_enabled;
       
   102 #endif
       
   103 
       
   104 class QGLTextureGlyphCache : public QObject, public QTextureGlyphCache
       
   105 {
       
   106     Q_OBJECT
       
   107 public:
       
   108     QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix);
       
   109     ~QGLTextureGlyphCache();
       
   110 
       
   111     virtual void createTextureData(int width, int height);
       
   112     virtual void resizeTextureData(int width, int height);
       
   113     virtual void fillTexture(const Coord &c, glyph_t glyph);
       
   114     virtual int glyphMargin() const;
       
   115 
       
   116     inline GLuint texture() const { return m_texture; }
       
   117 
       
   118     inline int width() const { return m_width; }
       
   119     inline int height() const { return m_height; }
       
   120 
       
   121     inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; }
       
   122 
       
   123 
       
   124 public Q_SLOTS:
       
   125     void contextDestroyed(const QGLContext *context) {
       
   126         if (context == ctx) {
       
   127             QList<const QGLContext *> shares = qgl_share_reg()->shares(ctx);
       
   128             if (shares.isEmpty()) {
       
   129                 glDeleteFramebuffers(1, &m_fbo);
       
   130                 if (m_width || m_height)
       
   131                     glDeleteTextures(1, &m_texture);
       
   132                 ctx = 0;
       
   133             } else {
       
   134                 // since the context holding the texture is shared, and
       
   135                 // about to be destroyed, we have to transfer ownership
       
   136                 // of the texture to one of the share contexts
       
   137                 ctx = const_cast<QGLContext *>((ctx == shares.at(0)) ? shares.at(1) : shares.at(0));
       
   138             }
       
   139         }
       
   140     }
       
   141 
       
   142 private:
       
   143     QGLContext *ctx;
       
   144 
       
   145     QGL2PaintEngineExPrivate *pex;
       
   146 
       
   147     GLuint m_texture;
       
   148     GLuint m_fbo;
       
   149 
       
   150     int m_width;
       
   151     int m_height;
       
   152 
       
   153     QGLShaderProgram *m_program;
       
   154 };
       
   155 
       
   156 QGLTextureGlyphCache::QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix)
       
   157     : QTextureGlyphCache(type, matrix)
       
   158     , ctx(context)
       
   159     , m_width(0)
       
   160     , m_height(0)
       
   161 {
       
   162     glGenFramebuffers(1, &m_fbo);
       
   163     connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)),
       
   164             SLOT(contextDestroyed(const QGLContext*)));
       
   165 }
       
   166 
       
   167 QGLTextureGlyphCache::~QGLTextureGlyphCache()
       
   168 {
       
   169     if (ctx) {
       
   170         QGLShareContextScope scope(ctx);
       
   171         glDeleteFramebuffers(1, &m_fbo);
       
   172 
       
   173         if (m_width || m_height)
       
   174             glDeleteTextures(1, &m_texture);
       
   175     }
       
   176 }
       
   177 
       
   178 void QGLTextureGlyphCache::createTextureData(int width, int height)
       
   179 {
       
   180     glGenTextures(1, &m_texture);
       
   181     glBindTexture(GL_TEXTURE_2D, m_texture);
       
   182 
       
   183     m_width = width;
       
   184     m_height = height;
       
   185 
       
   186     QVarLengthArray<uchar> data(width * height);
       
   187     for (int i = 0; i < data.size(); ++i)
       
   188         data[i] = 0;
       
   189 
       
   190     if (m_type == QFontEngineGlyphCache::Raster_RGBMask)
       
   191         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
       
   192     else
       
   193         glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
       
   194 
       
   195     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
       
   196     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
       
   197 }
       
   198 
       
   199 void QGLTextureGlyphCache::resizeTextureData(int width, int height)
       
   200 {
       
   201     // ### the QTextureGlyphCache API needs to be reworked to allow
       
   202     // ### resizeTextureData to fail
       
   203 
       
   204     int oldWidth = m_width;
       
   205     int oldHeight = m_height;
       
   206 
       
   207     GLuint oldTexture = m_texture;
       
   208     createTextureData(width, height);
       
   209 
       
   210     glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo);
       
   211 
       
   212     GLuint tmp_texture;
       
   213     glGenTextures(1, &tmp_texture);
       
   214     glBindTexture(GL_TEXTURE_2D, tmp_texture);
       
   215     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
       
   216                  GL_RGBA, GL_UNSIGNED_BYTE, NULL);
       
   217     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
       
   218     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
       
   219     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
       
   220     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
       
   221     glBindTexture(GL_TEXTURE_2D, 0);
       
   222     glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
       
   223                            GL_TEXTURE_2D, tmp_texture, 0);
       
   224 
       
   225     glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
       
   226     glBindTexture(GL_TEXTURE_2D, oldTexture);
       
   227 
       
   228     pex->transferMode(BrushDrawingMode);
       
   229 
       
   230 #ifndef QT_OPENGL_ES_2
       
   231     if (pex->inRenderText)
       
   232         glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT | GL_SCISSOR_BIT);
       
   233 #endif
       
   234 
       
   235     glDisable(GL_STENCIL_TEST);
       
   236     glDisable(GL_DEPTH_TEST);
       
   237     glDisable(GL_SCISSOR_TEST);
       
   238     glDisable(GL_BLEND);
       
   239 
       
   240     glViewport(0, 0, oldWidth, oldHeight);
       
   241 
       
   242     float vertexCoordinateArray[] = { -1, -1, 1, -1, 1, 1, -1, 1 };
       
   243     float textureCoordinateArray[] = { 0, 0, 1, 0, 1, 1, 0, 1 };
       
   244 
       
   245     glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
       
   246     glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
       
   247 
       
   248     glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray);
       
   249     glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray);
       
   250 
       
   251     pex->shaderManager->blitProgram()->bind();
       
   252     pex->shaderManager->blitProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT);
       
   253     pex->shaderManager->setDirty();
       
   254 
       
   255     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
       
   256 
       
   257     glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
       
   258     glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
       
   259 
       
   260     glBindTexture(GL_TEXTURE_2D, m_texture);
       
   261 
       
   262 #ifdef QT_OPENGL_ES_2
       
   263     QDataBuffer<uchar> buffer(4*oldWidth*oldHeight);
       
   264     buffer.resize(4*oldWidth*oldHeight);
       
   265     glReadPixels(0, 0, oldWidth, oldHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
       
   266 
       
   267     // do an in-place conversion from GL_RGBA to GL_ALPHA
       
   268     for (int i=0; i<oldWidth*oldHeight; ++i)
       
   269         buffer.data()[i] = buffer.at(4*i + 3);
       
   270 
       
   271     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight,
       
   272                     GL_ALPHA, GL_UNSIGNED_BYTE, buffer.data());
       
   273 #else
       
   274     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
       
   275 #endif
       
   276 
       
   277     glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
       
   278                               GL_RENDERBUFFER_EXT, 0);
       
   279     glDeleteTextures(1, &tmp_texture);
       
   280     glDeleteTextures(1, &oldTexture);
       
   281 
       
   282     glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
       
   283 
       
   284     glViewport(0, 0, pex->width, pex->height);
       
   285     pex->updateClipScissorTest();
       
   286 
       
   287 #ifndef QT_OPENGL_ES_2
       
   288     if (pex->inRenderText)
       
   289         glPopAttrib();
       
   290 #endif
       
   291 }
       
   292 
       
   293 void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph)
       
   294 {
       
   295     QImage mask = textureMapForGlyph(glyph);
       
   296     const int maskWidth = mask.width();
       
   297     const int maskHeight = mask.height();
       
   298 
       
   299     if (mask.format() == QImage::Format_Mono) {
       
   300         mask = mask.convertToFormat(QImage::Format_Indexed8);
       
   301         for (int y = 0; y < maskHeight; ++y) {
       
   302             uchar *src = (uchar *) mask.scanLine(y);
       
   303             for (int x = 0; x < maskWidth; ++x)
       
   304                 src[x] = -src[x]; // convert 0 and 1 into 0 and 255
       
   305         }
       
   306      }
       
   307 
       
   308 
       
   309     glBindTexture(GL_TEXTURE_2D, m_texture);
       
   310     if (mask.format() == QImage::Format_RGB32) {
       
   311         glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits());
       
   312     } else {
       
   313 #ifdef QT_OPENGL_ES2
       
   314         glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_ALPHA, GL_UNSIGNED_BYTE, mask.bits());
       
   315 #else
       
   316         // glTexSubImage2D() might cause some garbage to appear in the texture if the mask width is
       
   317         // not a multiple of four bytes. The bug appeared on a computer with 32-bit Windows Vista
       
   318         // and nVidia GeForce 8500GT. GL_UNPACK_ALIGNMENT is set to four bytes, 'mask' has a
       
   319         // multiple of four bytes per line, and most of the glyph shows up correctly in the
       
   320         // texture, which makes me think that this is a driver bug.
       
   321         // One workaround is to make sure the mask width is a multiple of four bytes, for instance
       
   322         // by converting it to a format with four bytes per pixel. Another is to copy one line at a
       
   323         // time.
       
   324 
       
   325         for (int i = 0; i < maskHeight; ++i)
       
   326             glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, maskWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, mask.scanLine(i));
       
   327 #endif
       
   328     }
       
   329 }
       
   330 
       
   331 int QGLTextureGlyphCache::glyphMargin() const
       
   332 {
       
   333 #if defined(Q_WS_MAC)
       
   334     return 2;
       
   335 #elif defined (Q_WS_X11)
       
   336     return 0;
       
   337 #else
       
   338     return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0;
       
   339 #endif
       
   340 }
       
   341 
    92 
   342 extern QImage qt_imageForBrush(int brushStyle, bool invert);
    93 extern QImage qt_imageForBrush(int brushStyle, bool invert);
   343 
    94 
   344 ////////////////////////////////// Private Methods //////////////////////////////////////////
    95 ////////////////////////////////// Private Methods //////////////////////////////////////////
   345 
    96 
   356 }
   107 }
   357 
   108 
   358 void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id)
   109 void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id)
   359 {
   110 {
   360 //    glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); //### Is it always this texture unit?
   111 //    glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); //### Is it always this texture unit?
   361     if (id != GLuint(-1) && id == lastTexture)
   112     if (id != GLuint(-1) && id == lastTextureUsed)
   362         return;
   113         return;
   363 
   114 
   364     lastTexture = id;
   115     lastTextureUsed = id;
   365 
   116 
   366     if (smoothPixmapTransform) {
   117     if (smoothPixmapTransform) {
   367         glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   118         glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   368         glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   119         glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   369     } else {
   120     } else {
   386 }
   137 }
   387 
   138 
   388 
   139 
   389 void QGL2PaintEngineExPrivate::setBrush(const QBrush& brush)
   140 void QGL2PaintEngineExPrivate::setBrush(const QBrush& brush)
   390 {
   141 {
   391     Q_ASSERT(brush.style() != Qt::NoBrush);
       
   392 
       
   393     if (qbrush_fast_equals(currentBrush, brush))
   142     if (qbrush_fast_equals(currentBrush, brush))
   394         return;
   143         return;
   395 
   144 
       
   145     const Qt::BrushStyle newStyle = qbrush_style(brush);
       
   146     Q_ASSERT(newStyle != Qt::NoBrush);
       
   147 
   396     currentBrush = brush;
   148     currentBrush = brush;
   397 
   149     brushUniformsDirty = true; // All brushes have at least one uniform
   398     brushTextureDirty = true;
   150 
   399     brushUniformsDirty = true;
   151     if (newStyle > Qt::SolidPattern)
       
   152         brushTextureDirty = true;
       
   153 
   400     if (currentBrush.style() == Qt::TexturePattern
   154     if (currentBrush.style() == Qt::TexturePattern
   401         && qHasPixmapTexture(brush) && brush.texture().isQBitmap())
   155         && qHasPixmapTexture(brush) && brush.texture().isQBitmap())
   402     {
   156     {
   403         shaderManager->setSrcPixelType(QGLEngineShaderManager::TextureSrcWithPattern);
   157         shaderManager->setSrcPixelType(QGLEngineShaderManager::TextureSrcWithPattern);
   404     } else {
   158     } else {
   405         shaderManager->setSrcPixelType(currentBrush.style());
   159         shaderManager->setSrcPixelType(newStyle);
   406     }
   160     }
   407     shaderManager->optimiseForBrushTransform(currentBrush.transform());
   161     shaderManager->optimiseForBrushTransform(currentBrush.transform().type());
   408 }
   162 }
   409 
   163 
   410 
   164 
   411 void QGL2PaintEngineExPrivate::useSimpleShader()
   165 void QGL2PaintEngineExPrivate::useSimpleShader()
   412 {
   166 {
   413     shaderManager->simpleProgram()->bind();
   167     shaderManager->useSimpleProgram();
   414     shaderManager->setDirty();
       
   415 
   168 
   416     if (matrixDirty)
   169     if (matrixDirty)
   417         updateMatrix();
   170         updateMatrix();
   418 
   171 
   419     if (simpleShaderMatrixUniformDirty) {
   172     if (simpleShaderMatrixUniformDirty) {
   420         shaderManager->simpleProgram()->setUniformValue("pmvMatrix", pmvMatrix);
   173         const GLuint location = shaderManager->simpleProgram()->uniformLocation("pmvMatrix");
       
   174         glUniformMatrix3fv(location, 1, GL_FALSE, (GLfloat*)pmvMatrix);
   421         simpleShaderMatrixUniformDirty = false;
   175         simpleShaderMatrixUniformDirty = false;
   422     }
   176     }
   423 }
   177 }
   424 
   178 
   425 void QGL2PaintEngineExPrivate::updateBrushTexture()
   179 void QGL2PaintEngineExPrivate::updateBrushTexture()
   581 // This assumes the shader manager has already setup the correct shader program
   335 // This assumes the shader manager has already setup the correct shader program
   582 void QGL2PaintEngineExPrivate::updateMatrix()
   336 void QGL2PaintEngineExPrivate::updateMatrix()
   583 {
   337 {
   584 //     qDebug("QGL2PaintEngineExPrivate::updateMatrix()");
   338 //     qDebug("QGL2PaintEngineExPrivate::updateMatrix()");
   585 
   339 
   586     // We set up the 4x4 transformation matrix on the vertex shaders to
   340     const QTransform& transform = q->state()->matrix;
   587     // be the equivalent of glOrtho(0, w, h, 0, -1, 1) * transform:
   341 
       
   342     // The projection matrix converts from Qt's coordinate system to GL's coordinate system
       
   343     //    * GL's viewport is 2x2, Qt's is width x height
       
   344     //    * GL has +y -> -y going from bottom -> top, Qt is the other way round
       
   345     //    * GL has [0,0] in the center, Qt has it in the top-left
   588     //
   346     //
   589     // | 2/width     0     0 -1 |   | m11  m21  0   dx |
   347     // This results in the Projection matrix below, which is multiplied by the painter's
   590     // |   0    -2/height  0  1 |   | m12  m22  0   dy |
   348     // transformation matrix, as shown below:
   591     // |   0         0    -1  0 | * |  0    0   1   0  |
       
   592     // |   0         0     0  1 |   | m13  m23  0  m33 |
       
   593     //
   349     //
   594     // We expand out the multiplication to save the cost of a full 4x4
   350     //                Projection Matrix                      Painter Transform
   595     // matrix multiplication as most of the components are trivial.
   351     // ------------------------------------------------   ------------------------
   596     const QTransform& transform = q->state()->matrix;
   352     // | 2.0 / width  |      0.0      |     -1.0      |   |  m11  |  m21  |  dx  |
   597 
   353     // |     0.0      | -2.0 / height |      1.0      | * |  m12  |  m22  |  dy  |
   598     qreal wfactor = 2.0 / width;
   354     // |     0.0      |      0.0      |      1.0      |   |  m13  |  m23  |  m33 |
   599     qreal hfactor = -2.0 / height;
   355     // ------------------------------------------------   ------------------------
   600 
   356     //
   601     pmvMatrix[0][0] = wfactor * transform.m11() - transform.m13();
   357     // NOTE: The resultant matrix is also transposed, as GL expects column-major matracies
   602     pmvMatrix[0][1] = hfactor * transform.m12() + transform.m13();
   358 
   603     pmvMatrix[0][2] = 0.0;
   359     const GLfloat wfactor = 2.0f / width;
   604     pmvMatrix[0][3] = transform.m13();
   360     const GLfloat hfactor = -2.0f / height;
   605     pmvMatrix[1][0] = wfactor * transform.m21() - transform.m23();
   361     GLfloat dx = transform.dx();
   606     pmvMatrix[1][1] = hfactor * transform.m22() + transform.m23();
   362     GLfloat dy = transform.dy();
   607     pmvMatrix[1][2] = 0.0;
   363 
   608     pmvMatrix[1][3] = transform.m23();
   364     // Non-integer translates can have strange effects for some rendering operations such as
   609     pmvMatrix[2][0] = 0.0;
   365     // anti-aliased text rendering. In such cases, we snap the translate to the pixel grid.
   610     pmvMatrix[2][1] = 0.0;
   366     if (snapToPixelGrid && transform.type() == QTransform::TxTranslate) {
   611     pmvMatrix[2][2] = -1.0;
   367         // 0.50 needs to rounded down to 0.0 for consistency with raster engine:
   612     pmvMatrix[2][3] = 0.0;
   368         dx = ceilf(dx - 0.5f);
   613     pmvMatrix[3][0] = wfactor * transform.dx() - transform.m33();
   369         dy = ceilf(dy - 0.5f);
   614     pmvMatrix[3][1] = hfactor * transform.dy() + transform.m33();
   370     }
   615     pmvMatrix[3][2] = 0.0;
   371 
   616     pmvMatrix[3][3] = transform.m33();
   372     if (addOffset) {
       
   373         dx += 0.49f;
       
   374         dy += 0.49f;
       
   375     }
       
   376 
       
   377     pmvMatrix[0][0] = (wfactor * transform.m11())  - transform.m13();
       
   378     pmvMatrix[1][0] = (wfactor * transform.m21())  - transform.m23();
       
   379     pmvMatrix[2][0] = (wfactor * dx) - transform.m33();
       
   380     pmvMatrix[0][1] = (hfactor * transform.m12())  + transform.m13();
       
   381     pmvMatrix[1][1] = (hfactor * transform.m22())  + transform.m23();
       
   382     pmvMatrix[2][1] = (hfactor * dy) + transform.m33();
       
   383     pmvMatrix[0][2] = transform.m13();
       
   384     pmvMatrix[1][2] = transform.m23();
       
   385     pmvMatrix[2][2] = transform.m33();
   617 
   386 
   618     // 1/10000 == 0.0001, so we have good enough res to cover curves
   387     // 1/10000 == 0.0001, so we have good enough res to cover curves
   619     // that span the entire widget...
   388     // that span the entire widget...
   620     inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())),
   389     inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())),
   621                                   qMax(qAbs(transform.m12()), qAbs(transform.m21())) ),
   390                                   qMax(qAbs(transform.m12()), qAbs(transform.m21())) ),
   698 }
   467 }
   699 
   468 
   700 void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern)
   469 void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern)
   701 {
   470 {
   702     // Setup for texture drawing
   471     // Setup for texture drawing
       
   472     currentBrush = noBrush;
   703     shaderManager->setSrcPixelType(pattern ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc);
   473     shaderManager->setSrcPixelType(pattern ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc);
       
   474 
       
   475     if (addOffset) {
       
   476         addOffset = false;
       
   477         matrixDirty = true;
       
   478     }
       
   479 
       
   480     if (snapToPixelGrid) {
       
   481         snapToPixelGrid = false;
       
   482         matrixDirty = true;
       
   483     }
       
   484 
   704     if (prepareForDraw(opaque))
   485     if (prepareForDraw(opaque))
   705         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
   486         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
   706 
   487 
   707     if (pattern) {
   488     if (pattern) {
   708         QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity);
   489         QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity);
   726     ensureActive();
   507     ensureActive();
   727     d->transferMode(BrushDrawingMode);
   508     d->transferMode(BrushDrawingMode);
   728 
   509 
   729     QGLContext *ctx = d->ctx;
   510     QGLContext *ctx = d->ctx;
   730     glUseProgram(0);
   511     glUseProgram(0);
       
   512 
       
   513     // Disable all the vertex attribute arrays:
       
   514     for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i)
       
   515         glDisableVertexAttribArray(i);
   731 
   516 
   732 #ifndef QT_OPENGL_ES_2
   517 #ifndef QT_OPENGL_ES_2
   733     // be nice to people who mix OpenGL 1.x code with QPainter commands
   518     // be nice to people who mix OpenGL 1.x code with QPainter commands
   734     // by setting modelview and projection matrices to mirror the GL 1
   519     // by setting modelview and projection matrices to mirror the GL 1
   735     // paint engine
   520     // paint engine
   753     glLoadMatrixf(&mv_matrix[0][0]);
   538     glLoadMatrixf(&mv_matrix[0][0]);
   754 #else
   539 #else
   755     Q_UNUSED(ctx);
   540     Q_UNUSED(ctx);
   756 #endif
   541 #endif
   757 
   542 
   758     d->lastTexture = GLuint(-1);
   543     d->lastTextureUsed = GLuint(-1);
   759     d->dirtyStencilRegion = QRect(0, 0, d->width, d->height);
   544     d->dirtyStencilRegion = QRect(0, 0, d->width, d->height);
   760     d->resetGLState();
   545     d->resetGLState();
   761 
   546 
   762     d->shaderManager->setDirty();
   547     d->shaderManager->setDirty();
   763 
   548 
   772     glDisable(GL_DEPTH_TEST);
   557     glDisable(GL_DEPTH_TEST);
   773     glDisable(GL_SCISSOR_TEST);
   558     glDisable(GL_SCISSOR_TEST);
   774     glDepthMask(true);
   559     glDepthMask(true);
   775     glDepthFunc(GL_LESS);
   560     glDepthFunc(GL_LESS);
   776     glClearDepth(1);
   561     glClearDepth(1);
       
   562     glStencilMask(0xff);
       
   563     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
       
   564     glStencilFunc(GL_ALWAYS, 0, 0xff);
   777 }
   565 }
   778 
   566 
   779 void QGL2PaintEngineEx::endNativePainting()
   567 void QGL2PaintEngineEx::endNativePainting()
   780 {
   568 {
   781     Q_D(QGL2PaintEngineEx);
   569     Q_D(QGL2PaintEngineEx);
   782     d->needsSync = true;
   570     d->needsSync = true;
   783 }
   571 }
   784 
   572 
   785 const QGLContext *QGL2PaintEngineEx::context()
       
   786 {
       
   787     Q_D(QGL2PaintEngineEx);
       
   788     return d->ctx;
       
   789 }
       
   790 
       
   791 void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
   573 void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
   792 {
   574 {
   793     if (newMode == mode)
   575     if (newMode == mode)
   794         return;
   576         return;
   795 
   577 
   796     if (mode == TextDrawingMode || mode == ImageDrawingMode || mode == ImageArrayDrawingMode) {
   578     if (mode == TextDrawingMode || mode == ImageDrawingMode || mode == ImageArrayDrawingMode) {
   797         glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
   579         lastTextureUsed = GLuint(-1);
   798         glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
       
   799         glDisableVertexAttribArray(QT_OPACITY_ATTR);
       
   800 
       
   801         lastTexture = GLuint(-1);
       
   802     }
   580     }
   803 
   581 
   804     if (newMode == TextDrawingMode) {
   582     if (newMode == TextDrawingMode) {
   805         glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
   583         setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data());
   806         glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
   584         setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data());
   807 
       
   808         glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data());
       
   809         glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data());
       
   810     }
   585     }
   811 
   586 
   812     if (newMode == ImageDrawingMode) {
   587     if (newMode == ImageDrawingMode) {
   813         glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
   588         setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray);
   814         glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
   589         setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, staticTextureCoordinateArray);
   815 
       
   816         glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticVertexCoordinateArray);
       
   817         glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticTextureCoordinateArray);
       
   818     }
   590     }
   819 
   591 
   820     if (newMode == ImageArrayDrawingMode) {
   592     if (newMode == ImageArrayDrawingMode) {
   821         glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
   593         setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data());
   822         glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
   594         setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data());
   823         glEnableVertexAttribArray(QT_OPACITY_ATTR);
   595         setVertexAttributePointer(QT_OPACITY_ATTR, (GLfloat*)opacityArray.data());
   824 
       
   825         glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data());
       
   826         glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data());
       
   827         glVertexAttribPointer(QT_OPACITY_ATTR, 1, GL_FLOAT, GL_FALSE, 0, opacityArray.data());
       
   828     }
   596     }
   829 
   597 
   830     // This needs to change when we implement high-quality anti-aliasing...
   598     // This needs to change when we implement high-quality anti-aliasing...
   831     if (newMode != TextDrawingMode)
   599     if (newMode != TextDrawingMode)
   832         shaderManager->setMaskType(QGLEngineShaderManager::NoMask);
   600         shaderManager->setMaskType(QGLEngineShaderManager::NoMask);
   844     int vertexCount;
   612     int vertexCount;
   845     GLenum primitiveType;
   613     GLenum primitiveType;
   846     qreal iscale;
   614     qreal iscale;
   847 };
   615 };
   848 
   616 
   849 void qopengl2paintengine_cleanup_vectorpath(QPaintEngineEx *engine, void *data)
   617 void QGL2PaintEngineExPrivate::cleanupVectorPath(QPaintEngineEx *engine, void *data)
   850 {
   618 {
   851     QGL2PEVectorPathCache *c = (QGL2PEVectorPathCache *) data;
   619     QGL2PEVectorPathCache *c = (QGL2PEVectorPathCache *) data;
   852 #ifdef QT_OPENGL_CACHE_AS_VBOS
   620 #ifdef QT_OPENGL_CACHE_AS_VBOS
   853     QGL2PaintEngineExPrivate *d = QGL2PaintEngineExPrivate::getData((QGL2PaintEngineEx *) engine);
   621     Q_ASSERT(engine->type() == QPaintEngine::OpenGL2);
   854     d->unusedVBOSToClean << c->vbo;
   622     static_cast<QGL2PaintEngineEx *>(engine)->d_func()->unusedVBOSToClean << c->vbo;
   855 #else
   623 #else
       
   624     Q_UNUSED(engine);
   856     qFree(c->vertices);
   625     qFree(c->vertices);
   857 #endif
   626 #endif
   858     delete c;
   627     delete c;
   859 }
   628 }
   860 
   629 
   861 // Assumes everything is configured for the brush you want to use
   630 // Assumes everything is configured for the brush you want to use
   862 void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)
   631 void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)
   863 {
   632 {
   864     transferMode(BrushDrawingMode);
   633     transferMode(BrushDrawingMode);
       
   634 
       
   635     const QOpenGL2PaintEngineState *s = q->state();
       
   636     const bool newAddOffset = !(s->renderHints & QPainter::Antialiasing) &&
       
   637                               (qbrush_style(currentBrush) == Qt::SolidPattern) &&
       
   638                               !multisamplingAlwaysEnabled;
       
   639 
       
   640     if (addOffset != newAddOffset) {
       
   641         addOffset = newAddOffset;
       
   642         matrixDirty = true;
       
   643     }
       
   644 
       
   645     if (snapToPixelGrid) {
       
   646         snapToPixelGrid = false;
       
   647         matrixDirty = true;
       
   648     }
   865 
   649 
   866     // Might need to call updateMatrix to re-calculate inverseScale
   650     // Might need to call updateMatrix to re-calculate inverseScale
   867     if (matrixDirty)
   651     if (matrixDirty)
   868         updateMatrix();
   652         updateMatrix();
   869 
   653 
   896                     }
   680                     }
   897                 }
   681                 }
   898             } else {
   682             } else {
   899                 cache = new QGL2PEVectorPathCache;
   683                 cache = new QGL2PEVectorPathCache;
   900                 cache->vertexCount = 0;
   684                 cache->vertexCount = 0;
   901                 data = const_cast<QVectorPath &>(path).addCacheData(q, cache, qopengl2paintengine_cleanup_vectorpath);
   685                 data = const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath);
   902             }
   686             }
   903 
   687 
   904             // Flatten the path at the current scale factor and fill it into the cache struct.
   688             // Flatten the path at the current scale factor and fill it into the cache struct.
   905             if (!cache->vertexCount) {
   689             if (!cache->vertexCount) {
   906                 vertexCoordinateArray.clear();
   690                 vertexCoordinateArray.clear();
   919                 memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes);
   703                 memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes);
   920 #endif
   704 #endif
   921             }
   705             }
   922 
   706 
   923             prepareForDraw(currentBrush.isOpaque());
   707             prepareForDraw(currentBrush.isOpaque());
   924             glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
       
   925 #ifdef QT_OPENGL_CACHE_AS_VBOS
   708 #ifdef QT_OPENGL_CACHE_AS_VBOS
   926             glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
   709             glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
   927             glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, 0);
   710             setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0);
   928 #else
   711 #else
   929             glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, cache->vertices);
   712             setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, cache->vertices);
   930 #endif
   713 #endif
   931             glDrawArrays(cache->primitiveType, 0, cache->vertexCount);
   714             glDrawArrays(cache->primitiveType, 0, cache->vertexCount);
   932 
   715 
   933         } else {
   716         } else {
   934       //        printf(" - Marking path as cachable...\n");
   717       //        printf(" - Marking path as cachable...\n");
   961             glStencilFunc(GL_NOTEQUAL, 0, 0xff);
   744             glStencilFunc(GL_NOTEQUAL, 0, 0xff);
   962         } else {
   745         } else {
   963             // Pass when high bit is set, replace stencil value with 0
   746             // Pass when high bit is set, replace stencil value with 0
   964             glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
   747             glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
   965         }
   748         }
   966 
       
   967         prepareForDraw(currentBrush.isOpaque());
   749         prepareForDraw(currentBrush.isOpaque());
   968 
       
   969         if (inRenderText)
       
   970             prepareDepthRangeForRenderText();
       
   971 
   750 
   972         // Stencil the brush onto the dest buffer
   751         // Stencil the brush onto the dest buffer
   973         composite(vertexCoordinateArray.boundingRect());
   752         composite(vertexCoordinateArray.boundingRect());
   974 
       
   975         if (inRenderText)
       
   976             restoreDepthRangeForRenderText();
       
   977 
       
   978         glStencilMask(0);
   753         glStencilMask(0);
   979 
       
   980         updateClipScissorTest();
   754         updateClipScissorTest();
   981     }
   755     }
   982 }
   756 }
   983 
   757 
   984 
   758 
  1012     }
   786     }
  1013 
   787 
  1014     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes
   788     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes
  1015     useSimpleShader();
   789     useSimpleShader();
  1016     glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d
   790     glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d
  1017 
       
  1018 #ifndef QT_OPENGL_ES_2
       
  1019     if (inRenderText) {
       
  1020         glPushAttrib(GL_ENABLE_BIT);
       
  1021         glDisable(GL_DEPTH_TEST);
       
  1022     }
       
  1023 #endif
       
  1024 
   791 
  1025     if (mode == WindingFillMode) {
   792     if (mode == WindingFillMode) {
  1026         Q_ASSERT(stops && !count);
   793         Q_ASSERT(stops && !count);
  1027         if (q->state()->clipTestEnabled) {
   794         if (q->state()->clipTestEnabled) {
  1028             // Flatten clip values higher than current clip, and set high bit to match current clip
   795             // Flatten clip values higher than current clip, and set high bit to match current clip
  1060     } else { // TriStripStrokeFillMode
   827     } else { // TriStripStrokeFillMode
  1061         Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops
   828         Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops
  1062         glStencilMask(GL_STENCIL_HIGH_BIT);
   829         glStencilMask(GL_STENCIL_HIGH_BIT);
  1063 #if 0
   830 #if 0
  1064         glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit
   831         glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit
  1065         glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
   832         setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data);
  1066         glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data);
       
  1067         glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
   833         glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
  1068         glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
       
  1069 #else
   834 #else
  1070 
   835 
  1071         glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
   836         glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  1072         if (q->state()->clipTestEnabled) {
   837         if (q->state()->clipTestEnabled) {
  1073             glStencilFunc(GL_LEQUAL, q->state()->currentClip | GL_STENCIL_HIGH_BIT,
   838             glStencilFunc(GL_LEQUAL, q->state()->currentClip | GL_STENCIL_HIGH_BIT,
  1074                           ~GL_STENCIL_HIGH_BIT);
   839                           ~GL_STENCIL_HIGH_BIT);
  1075         } else {
   840         } else {
  1076             glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff);
   841             glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff);
  1077         }
   842         }
  1078         glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
   843         setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data);
  1079         glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data);
       
  1080         glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
   844         glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
  1081         glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
       
  1082 #endif
   845 #endif
  1083     }
   846     }
  1084 
   847 
  1085     // Enable color writes & disable stencil writes
   848     // Enable color writes & disable stencil writes
  1086     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
   849     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  1087 
       
  1088 #ifndef QT_OPENGL_ES_2
       
  1089     if (inRenderText)
       
  1090         glPopAttrib();
       
  1091 #endif
       
  1092 
       
  1093 }
   850 }
  1094 
   851 
  1095 /*
   852 /*
  1096     If the maximum value in the stencil buffer is GL_STENCIL_HIGH_BIT - 1,
   853     If the maximum value in the stencil buffer is GL_STENCIL_HIGH_BIT - 1,
  1097     restore the stencil buffer to a pristine state.  The current clip region
   854     restore the stencil buffer to a pristine state.  The current clip region
  1181 
   938 
  1182     if (brushUniformsDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode)
   939     if (brushUniformsDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode)
  1183         updateBrushUniforms();
   940         updateBrushUniforms();
  1184 
   941 
  1185     if (shaderMatrixUniformDirty) {
   942     if (shaderMatrixUniformDirty) {
  1186         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PmvMatrix), pmvMatrix);
   943         glUniformMatrix3fv(location(QGLEngineShaderManager::PmvMatrix), 1, GL_FALSE, (GLfloat*)pmvMatrix);
  1187         shaderMatrixUniformDirty = false;
   944         shaderMatrixUniformDirty = false;
  1188     }
   945     }
  1189 
   946 
  1190     if (opacityMode == QGLEngineShaderManager::UniformOpacity && opacityUniformDirty) {
   947     if (opacityMode == QGLEngineShaderManager::UniformOpacity && opacityUniformDirty) {
  1191         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::GlobalOpacity), (GLfloat)q->state()->opacity);
   948         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::GlobalOpacity), (GLfloat)q->state()->opacity);
  1195     return changed;
   952     return changed;
  1196 }
   953 }
  1197 
   954 
  1198 void QGL2PaintEngineExPrivate::composite(const QGLRect& boundingRect)
   955 void QGL2PaintEngineExPrivate::composite(const QGLRect& boundingRect)
  1199 {
   956 {
  1200     // Setup a vertex array for the bounding rect:
   957     setCoords(staticVertexCoordinateArray, boundingRect);
  1201     GLfloat rectVerts[] = {
   958     setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray);
  1202         boundingRect.left, boundingRect.top,
       
  1203         boundingRect.left, boundingRect.bottom,
       
  1204         boundingRect.right, boundingRect.bottom,
       
  1205         boundingRect.right, boundingRect.top
       
  1206     };
       
  1207 
       
  1208     glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
       
  1209     glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, rectVerts);
       
  1210 
       
  1211     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
   959     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
  1212 
       
  1213     glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
       
  1214 }
   960 }
  1215 
   961 
  1216 // Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans.
   962 // Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans.
  1217 void QGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stops, int stopCount,
   963 void QGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stops, int stopCount,
  1218                                                 GLenum primitive)
   964                                                 GLenum primitive)
  1219 {
   965 {
  1220     // Now setup the pointer to the vertex array:
   966     // Now setup the pointer to the vertex array:
  1221     glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
   967     setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)data);
  1222     glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data);
       
  1223 
   968 
  1224     int previousStop = 0;
   969     int previousStop = 0;
  1225     for (int i=0; i<stopCount; ++i) {
   970     for (int i=0; i<stopCount; ++i) {
  1226         int stop = stops[i];
   971         int stop = stops[i];
  1227 /*
   972 /*
  1230             qDebug("   %02d: [%.2f, %.2f]", i, vertexArray.data()[i].x, vertexArray.data()[i].y);
   975             qDebug("   %02d: [%.2f, %.2f]", i, vertexArray.data()[i].x, vertexArray.data()[i].y);
  1231 */
   976 */
  1232         glDrawArrays(primitive, previousStop, stop - previousStop);
   977         glDrawArrays(primitive, previousStop, stop - previousStop);
  1233         previousStop = stop;
   978         previousStop = stop;
  1234     }
   979     }
  1235     glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
       
  1236 }
       
  1237 
       
  1238 void QGL2PaintEngineExPrivate::prepareDepthRangeForRenderText()
       
  1239 {
       
  1240 #ifndef QT_OPENGL_ES_2
       
  1241     // Get the z translation value from the model view matrix and
       
  1242     // transform it using the ortogonal projection with z-near = 0,
       
  1243     // and z-far = 1, which is used in QGLWidget::renderText()
       
  1244     GLdouble model[4][4];
       
  1245     glGetDoublev(GL_MODELVIEW_MATRIX, &model[0][0]);
       
  1246     float deviceZ = -2 * model[3][2] - 1;
       
  1247 
       
  1248     glGetFloatv(GL_DEPTH_RANGE, depthRange);
       
  1249     float windowZ = depthRange[0] + (deviceZ + 1) * 0.5 * (depthRange[1] - depthRange[0]);
       
  1250 
       
  1251     glDepthRange(windowZ, windowZ);
       
  1252 #endif
       
  1253 }
       
  1254 
       
  1255 void QGL2PaintEngineExPrivate::restoreDepthRangeForRenderText()
       
  1256 {
       
  1257 #ifndef QT_OPENGL_ES_2
       
  1258     glDepthRange(depthRange[0], depthRange[1]);
       
  1259 #endif
       
  1260 }
   980 }
  1261 
   981 
  1262 /////////////////////////////////// Public Methods //////////////////////////////////////////
   982 /////////////////////////////////// Public Methods //////////////////////////////////////////
  1263 
   983 
  1264 QGL2PaintEngineEx::QGL2PaintEngineEx()
   984 QGL2PaintEngineEx::QGL2PaintEngineEx()
  1272 
   992 
  1273 void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush)
   993 void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush)
  1274 {
   994 {
  1275     Q_D(QGL2PaintEngineEx);
   995     Q_D(QGL2PaintEngineEx);
  1276 
   996 
  1277     Qt::BrushStyle style = qbrush_style(brush);
   997     if (qbrush_style(brush) == Qt::NoBrush)
  1278     if (style == Qt::NoBrush)
       
  1279         return;
   998         return;
  1280     if (!d->inRenderText)
   999     ensureActive();
  1281         ensureActive();
       
  1282 
       
  1283     QOpenGL2PaintEngineState *s = state();
       
  1284     bool doOffset = !(s->renderHints & QPainter::Antialiasing) &&
       
  1285                     (style == Qt::SolidPattern) &&
       
  1286                     !d->multisamplingAlwaysEnabled;
       
  1287 
       
  1288     if (doOffset) {
       
  1289         d->temporaryTransform = s->matrix;
       
  1290         QTransform tx = QTransform::fromTranslate(.49, .49);
       
  1291         s->matrix = s->matrix * tx;
       
  1292         d->matrixDirty = true;
       
  1293     }
       
  1294 
       
  1295     d->setBrush(brush);
  1000     d->setBrush(brush);
  1296     d->fill(path);
  1001     d->fill(path);
  1297 
       
  1298     if (doOffset) {
       
  1299         s->matrix = d->temporaryTransform;
       
  1300         d->matrixDirty = true;
       
  1301     }
       
  1302 }
  1002 }
  1303 
  1003 
  1304 extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
  1004 extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
  1305 
  1005 
  1306 
  1006 
  1307 void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
  1007 void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
  1308 {
  1008 {
  1309     Q_D(QGL2PaintEngineEx);
  1009     Q_D(QGL2PaintEngineEx);
  1310 
  1010 
  1311     Qt::PenStyle penStyle = qpen_style(pen);
       
  1312     const QBrush &penBrush = qpen_brush(pen);
  1011     const QBrush &penBrush = qpen_brush(pen);
  1313     if (penStyle == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush)
  1012     if (qpen_style(pen) == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush)
  1314         return;
  1013         return;
  1315 
  1014 
  1316     QOpenGL2PaintEngineState *s = state();
  1015     QOpenGL2PaintEngineState *s = state();
  1317     if (pen.isCosmetic() && !qt_scaleForTransform(s->transform(), 0)) {
  1016     if (pen.isCosmetic() && !qt_scaleForTransform(s->transform(), 0)) {
  1318         // QTriangulatingStroker class is not meant to support cosmetically sheared strokes.
  1017         // QTriangulatingStroker class is not meant to support cosmetically sheared strokes.
  1319         QPaintEngineEx::stroke(path, pen);
  1018         QPaintEngineEx::stroke(path, pen);
  1320         return;
  1019         return;
  1321     }
  1020     }
  1322 
  1021 
  1323     ensureActive();
  1022     ensureActive();
  1324 
       
  1325     bool doOffset = !(s->renderHints & QPainter::Antialiasing) && !d->multisamplingAlwaysEnabled;
       
  1326     if (doOffset) {
       
  1327         d->temporaryTransform = s->matrix;
       
  1328         QTransform tx = QTransform::fromTranslate(0.49, .49);
       
  1329         s->matrix = s->matrix * tx;
       
  1330         d->matrixDirty = true;
       
  1331     }
       
  1332 
       
  1333     bool opaque = penBrush.isOpaque() && s->opacity > 0.99;
       
  1334     d->setBrush(penBrush);
  1023     d->setBrush(penBrush);
  1335     d->transferMode(BrushDrawingMode);
  1024     d->stroke(path, pen);
       
  1025 }
       
  1026 
       
  1027 void QGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &pen)
       
  1028 {
       
  1029     const QOpenGL2PaintEngineState *s = q->state();
       
  1030     const bool newAddOffset = !(s->renderHints & QPainter::Antialiasing) && !multisamplingAlwaysEnabled;
       
  1031     if (addOffset != newAddOffset) {
       
  1032         addOffset = newAddOffset;
       
  1033         matrixDirty = true;
       
  1034     }
       
  1035 
       
  1036     if (snapToPixelGrid) {
       
  1037         snapToPixelGrid = false;
       
  1038         matrixDirty = true;
       
  1039     }
       
  1040 
       
  1041     const Qt::PenStyle penStyle = qpen_style(pen);
       
  1042     const QBrush &penBrush = qpen_brush(pen);
       
  1043     const bool opaque = penBrush.isOpaque() && s->opacity > 0.99;
       
  1044 
       
  1045     transferMode(BrushDrawingMode);
  1336 
  1046 
  1337     // updateMatrix() is responsible for setting the inverse scale on
  1047     // updateMatrix() is responsible for setting the inverse scale on
  1338     // the strokers, so we need to call it here and not wait for
  1048     // the strokers, so we need to call it here and not wait for
  1339     // prepareForDraw() down below.
  1049     // prepareForDraw() down below.
  1340     d->updateMatrix();
  1050     updateMatrix();
  1341 
  1051 
  1342     if (penStyle == Qt::SolidLine) {
  1052     if (penStyle == Qt::SolidLine) {
  1343         d->stroker.process(path, pen);
  1053         stroker.process(path, pen);
  1344 
  1054 
  1345     } else { // Some sort of dash
  1055     } else { // Some sort of dash
  1346         d->dasher.process(path, pen);
  1056         dasher.process(path, pen);
  1347 
  1057 
  1348         QVectorPath dashStroke(d->dasher.points(),
  1058         QVectorPath dashStroke(dasher.points(),
  1349                                d->dasher.elementCount(),
  1059                                dasher.elementCount(),
  1350                                d->dasher.elementTypes());
  1060                                dasher.elementTypes());
  1351         d->stroker.process(dashStroke, pen);
  1061         stroker.process(dashStroke, pen);
  1352     }
  1062     }
  1353 
       
  1354 
       
  1355     QGLContext *ctx = d->ctx;
       
  1356     Q_UNUSED(ctx);
       
  1357 
  1063 
  1358     if (opaque) {
  1064     if (opaque) {
  1359         d->prepareForDraw(opaque);
  1065         prepareForDraw(opaque);
  1360         glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
  1066         setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, stroker.vertices());
  1361         glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, d->stroker.vertices());
  1067         glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2);
  1362         glDrawArrays(GL_TRIANGLE_STRIP, 0, d->stroker.vertexCount() / 2);
       
  1363 
  1068 
  1364 //         QBrush b(Qt::green);
  1069 //         QBrush b(Qt::green);
  1365 //         d->setBrush(&b);
  1070 //         d->setBrush(&b);
  1366 //         d->prepareForDraw(true);
  1071 //         d->prepareForDraw(true);
  1367 //         glDrawArrays(GL_LINE_STRIP, 0, d->stroker.vertexCount() / 2);
  1072 //         glDrawArrays(GL_LINE_STRIP, 0, d->stroker.vertexCount() / 2);
  1368 
       
  1369         glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
       
  1370 
  1073 
  1371     } else {
  1074     } else {
  1372         qreal width = qpen_widthf(pen) / 2;
  1075         qreal width = qpen_widthf(pen) / 2;
  1373         if (width == 0)
  1076         if (width == 0)
  1374             width = 0.5;
  1077             width = 0.5;
  1375         qreal extra = pen.joinStyle() == Qt::MiterJoin
  1078         qreal extra = pen.joinStyle() == Qt::MiterJoin
  1376                       ? qMax(pen.miterLimit() * width, width)
  1079                       ? qMax(pen.miterLimit() * width, width)
  1377                       : width;
  1080                       : width;
  1378 
  1081 
  1379         if (pen.isCosmetic())
  1082         if (pen.isCosmetic())
  1380             extra = extra * d->inverseScale;
  1083             extra = extra * inverseScale;
  1381 
  1084 
  1382         QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra);
  1085         QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra);
  1383 
  1086 
  1384         d->fillStencilWithVertexArray(d->stroker.vertices(), d->stroker.vertexCount() / 2,
  1087         fillStencilWithVertexArray(stroker.vertices(), stroker.vertexCount() / 2,
  1385                                       0, 0, bounds, QGL2PaintEngineExPrivate::TriStripStrokeFillMode);
  1088                                       0, 0, bounds, QGL2PaintEngineExPrivate::TriStripStrokeFillMode);
  1386 
  1089 
  1387         glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
  1090         glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
  1388 
  1091 
  1389         // Pass when any bit is set, replace stencil value with 0
  1092         // Pass when any bit is set, replace stencil value with 0
  1390         glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
  1093         glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
  1391         d->prepareForDraw(false);
  1094         prepareForDraw(false);
  1392 
  1095 
  1393         // Stencil the brush onto the dest buffer
  1096         // Stencil the brush onto the dest buffer
  1394         d->composite(bounds);
  1097         composite(bounds);
  1395 
  1098 
  1396         glStencilMask(0);
  1099         glStencilMask(0);
  1397 
  1100 
  1398         d->updateClipScissorTest();
  1101         updateClipScissorTest();
  1399     }
       
  1400 
       
  1401     if (doOffset) {
       
  1402         s->matrix = d->temporaryTransform;
       
  1403         d->matrixDirty = true;
       
  1404     }
  1102     }
  1405 }
  1103 }
  1406 
  1104 
  1407 void QGL2PaintEngineEx::penChanged() { }
  1105 void QGL2PaintEngineEx::penChanged() { }
  1408 void QGL2PaintEngineEx::brushChanged() { }
  1106 void QGL2PaintEngineEx::brushChanged() { }
  1438     else
  1136     else
  1439         glDisable(GL_MULTISAMPLE);
  1137         glDisable(GL_MULTISAMPLE);
  1440 #endif
  1138 #endif
  1441 
  1139 
  1442     Q_D(QGL2PaintEngineEx);
  1140     Q_D(QGL2PaintEngineEx);
  1443     d->lastTexture = GLuint(-1);
  1141     d->lastTextureUsed = GLuint(-1);
  1444     d->brushTextureDirty = true;
  1142     d->brushTextureDirty = true;
  1445 //    qDebug("QGL2PaintEngineEx::renderHintsChanged() not implemented!");
  1143 //    qDebug("QGL2PaintEngineEx::renderHintsChanged() not implemented!");
  1446 }
  1144 }
  1447 
  1145 
  1448 void QGL2PaintEngineEx::transformChanged()
  1146 void QGL2PaintEngineEx::transformChanged()
  1516 
  1214 
  1517 void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem)
  1215 void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem)
  1518 {
  1216 {
  1519     Q_D(QGL2PaintEngineEx);
  1217     Q_D(QGL2PaintEngineEx);
  1520 
  1218 
  1521     if (!d->inRenderText)
  1219     ensureActive();
  1522         ensureActive();
       
  1523     QOpenGL2PaintEngineState *s = state();
  1220     QOpenGL2PaintEngineState *s = state();
  1524 
  1221 
  1525     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
  1222     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
  1526 
  1223 
  1527     QTransform::TransformationType txtype = s->matrix.type();
  1224     QTransform::TransformationType txtype = s->matrix.type();
  1536 
  1233 
  1537     QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0
  1234     QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0
  1538                                             ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat)
  1235                                             ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat)
  1539                                             : d->glyphCacheType;
  1236                                             : d->glyphCacheType;
  1540 
  1237 
  1541     if (d->inRenderText || txtype > QTransform::TxTranslate)
  1238     if (txtype > QTransform::TxTranslate)
  1542         glyphType = QFontEngineGlyphCache::Raster_A8;
  1239         glyphType = QFontEngineGlyphCache::Raster_A8;
  1543 
  1240 
  1544     if (glyphType == QFontEngineGlyphCache::Raster_RGBMask
  1241     if (glyphType == QFontEngineGlyphCache::Raster_RGBMask
  1545         && state()->composition_mode != QPainter::CompositionMode_Source
  1242         && state()->composition_mode != QPainter::CompositionMode_Source
  1546         && state()->composition_mode != QPainter::CompositionMode_SourceOver)
  1243         && state()->composition_mode != QPainter::CompositionMode_SourceOver)
  1578     cache->populate(ti, glyphs, positions);
  1275     cache->populate(ti, glyphs, positions);
  1579 
  1276 
  1580     if (cache->width() == 0 || cache->height() == 0)
  1277     if (cache->width() == 0 || cache->height() == 0)
  1581         return;
  1278         return;
  1582 
  1279 
  1583     if (inRenderText)
       
  1584         transferMode(BrushDrawingMode);
       
  1585     transferMode(TextDrawingMode);
  1280     transferMode(TextDrawingMode);
  1586 
  1281 
  1587     int margin = cache->glyphMargin();
  1282     int margin = cache->glyphMargin();
  1588 
  1283 
  1589     GLfloat dx = 1.0 / cache->width();
  1284     GLfloat dx = 1.0 / cache->width();
  1590     GLfloat dy = 1.0 / cache->height();
  1285     GLfloat dy = 1.0 / cache->height();
  1591 
       
  1592     QGLPoint *oldVertexCoordinateDataPtr = vertexCoordinateArray.data();
       
  1593     QGLPoint *oldTextureCoordinateDataPtr = textureCoordinateArray.data();
       
  1594 
  1286 
  1595     vertexCoordinateArray.clear();
  1287     vertexCoordinateArray.clear();
  1596     textureCoordinateArray.clear();
  1288     textureCoordinateArray.clear();
  1597 
  1289 
  1598     for (int i=0; i<glyphs.size(); ++i) {
  1290     for (int i=0; i<glyphs.size(); ++i) {
  1602 
  1294 
  1603         vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h));
  1295         vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h));
  1604         textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy));
  1296         textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy));
  1605     }
  1297     }
  1606 
  1298 
  1607     if (vertexCoordinateArray.data() != oldVertexCoordinateDataPtr)
  1299     setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data());
  1608         glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data());
  1300     setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data());
  1609     if (textureCoordinateArray.data() != oldTextureCoordinateDataPtr)
  1301 
  1610         glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data());
  1302     if (addOffset) {
       
  1303         addOffset = false;
       
  1304         matrixDirty = true;
       
  1305     }
       
  1306     if (!snapToPixelGrid) {
       
  1307         snapToPixelGrid = true;
       
  1308         matrixDirty = true;
       
  1309     }
  1611 
  1310 
  1612     QBrush pensBrush = q->state()->pen.brush();
  1311     QBrush pensBrush = q->state()->pen.brush();
  1613     setBrush(pensBrush);
  1312     setBrush(pensBrush);
  1614 
       
  1615     if (inRenderText)
       
  1616         prepareDepthRangeForRenderText();
       
  1617 
  1313 
  1618     if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
  1314     if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
  1619 
  1315 
  1620         // Subpixel antialiasing without gamma correction
  1316         // Subpixel antialiasing without gamma correction
  1621 
  1317 
  1697     glBindTexture(GL_TEXTURE_2D, cache->texture());
  1393     glBindTexture(GL_TEXTURE_2D, cache->texture());
  1698     updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
  1394     updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
  1699 
  1395 
  1700     shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
  1396     shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
  1701     glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size());
  1397     glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size());
  1702 
       
  1703     if (inRenderText)
       
  1704         restoreDepthRangeForRenderText();
       
  1705 }
  1398 }
  1706 
  1399 
  1707 void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints)
  1400 void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints)
  1708 {
  1401 {
       
  1402     Q_D(QGL2PaintEngineEx);
  1709     // Use fallback for extended composition modes.
  1403     // Use fallback for extended composition modes.
  1710     if (state()->composition_mode > QPainter::CompositionMode_Plus) {
  1404     if (state()->composition_mode > QPainter::CompositionMode_Plus) {
  1711         QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints);
  1405         QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints);
  1712         return;
  1406         return;
  1713     }
  1407     }
  1714 
  1408 
  1715     Q_D(QGL2PaintEngineEx);
  1409     ensureActive();
  1716 
  1410     d->drawPixmaps(drawingData, dataCount, pixmap, hints);
       
  1411 }
       
  1412 
       
  1413 
       
  1414 void QGL2PaintEngineExPrivate::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints)
       
  1415 {
  1717     GLfloat dx = 1.0f / pixmap.size().width();
  1416     GLfloat dx = 1.0f / pixmap.size().width();
  1718     GLfloat dy = 1.0f / pixmap.size().height();
  1417     GLfloat dy = 1.0f / pixmap.size().height();
  1719 
  1418 
  1720     d->vertexCoordinateArray.clear();
  1419     vertexCoordinateArray.clear();
  1721     d->textureCoordinateArray.clear();
  1420     textureCoordinateArray.clear();
  1722     d->opacityArray.reset();
  1421     opacityArray.reset();
       
  1422 
       
  1423     if (addOffset) {
       
  1424         addOffset = false;
       
  1425         matrixDirty = true;
       
  1426     }
       
  1427 
       
  1428     if (snapToPixelGrid) {
       
  1429         snapToPixelGrid = false;
       
  1430         matrixDirty = true;
       
  1431     }
  1723 
  1432 
  1724     bool allOpaque = true;
  1433     bool allOpaque = true;
  1725 
  1434 
  1726     for (int i = 0; i < dataCount; ++i) {
  1435     for (int i = 0; i < dataCount; ++i) {
  1727         qreal s = 0;
  1436         qreal s = 0;
  1734         qreal right = 0.5 * drawingData[i].scaleX * drawingData[i].source.width();
  1443         qreal right = 0.5 * drawingData[i].scaleX * drawingData[i].source.width();
  1735         qreal bottom = 0.5 * drawingData[i].scaleY * drawingData[i].source.height();
  1444         qreal bottom = 0.5 * drawingData[i].scaleY * drawingData[i].source.height();
  1736         QGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c);
  1445         QGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c);
  1737         QGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c);
  1446         QGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c);
  1738 
  1447 
  1739         d->vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y());
  1448         vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y());
  1740         d->vertexCoordinateArray.lineToArray(-bottomLeft.x + drawingData[i].point.x(), -bottomLeft.y + drawingData[i].point.y());
  1449         vertexCoordinateArray.lineToArray(-bottomLeft.x + drawingData[i].point.x(), -bottomLeft.y + drawingData[i].point.y());
  1741         d->vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y());
  1450         vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y());
  1742         d->vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y());
  1451         vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y());
  1743         d->vertexCoordinateArray.lineToArray(bottomLeft.x + drawingData[i].point.x(), bottomLeft.y + drawingData[i].point.y());
  1452         vertexCoordinateArray.lineToArray(bottomLeft.x + drawingData[i].point.x(), bottomLeft.y + drawingData[i].point.y());
  1744         d->vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y());
  1453         vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y());
  1745 
  1454 
  1746         QGLRect src(drawingData[i].source.left() * dx, drawingData[i].source.top() * dy,
  1455         QGLRect src(drawingData[i].source.left() * dx, drawingData[i].source.top() * dy,
  1747                     drawingData[i].source.right() * dx, drawingData[i].source.bottom() * dy);
  1456                     drawingData[i].source.right() * dx, drawingData[i].source.bottom() * dy);
  1748 
  1457 
  1749         d->textureCoordinateArray.lineToArray(src.right, src.bottom);
  1458         textureCoordinateArray.lineToArray(src.right, src.bottom);
  1750         d->textureCoordinateArray.lineToArray(src.right, src.top);
  1459         textureCoordinateArray.lineToArray(src.right, src.top);
  1751         d->textureCoordinateArray.lineToArray(src.left, src.top);
  1460         textureCoordinateArray.lineToArray(src.left, src.top);
  1752         d->textureCoordinateArray.lineToArray(src.left, src.top);
  1461         textureCoordinateArray.lineToArray(src.left, src.top);
  1753         d->textureCoordinateArray.lineToArray(src.left, src.bottom);
  1462         textureCoordinateArray.lineToArray(src.left, src.bottom);
  1754         d->textureCoordinateArray.lineToArray(src.right, src.bottom);
  1463         textureCoordinateArray.lineToArray(src.right, src.bottom);
  1755 
  1464 
  1756         qreal opacity = drawingData[i].opacity * state()->opacity;
  1465         qreal opacity = drawingData[i].opacity * q->state()->opacity;
  1757         d->opacityArray << opacity << opacity << opacity << opacity << opacity << opacity;
  1466         opacityArray << opacity << opacity << opacity << opacity << opacity << opacity;
  1758         allOpaque &= (opacity >= 0.99f);
  1467         allOpaque &= (opacity >= 0.99f);
  1759     }
  1468     }
  1760 
  1469 
  1761     ensureActive();
       
  1762 
       
  1763     QGLContext *ctx = d->ctx;
       
  1764     glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
  1470     glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
  1765     QGLTexture *texture = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA,
  1471     QGLTexture *texture = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA,
  1766                                                      QGLContext::InternalBindOption
  1472                                                      QGLContext::InternalBindOption
  1767                                                      | QGLContext::CanFlipNativePixmapBindOption);
  1473                                                      | QGLContext::CanFlipNativePixmapBindOption);
  1768 
  1474 
  1769     if (texture->options & QGLContext::InvertedYBindOption) {
  1475     if (texture->options & QGLContext::InvertedYBindOption) {
  1770         // Flip texture y-coordinate.
  1476         // Flip texture y-coordinate.
  1771         QGLPoint *data = d->textureCoordinateArray.data();
  1477         QGLPoint *data = textureCoordinateArray.data();
  1772         for (int i = 0; i < 6 * dataCount; ++i)
  1478         for (int i = 0; i < 6 * dataCount; ++i)
  1773             data[i].y = 1 - data[i].y;
  1479             data[i].y = 1 - data[i].y;
  1774     }
  1480     }
  1775 
  1481 
  1776     d->transferMode(ImageArrayDrawingMode);
  1482     transferMode(ImageArrayDrawingMode);
  1777 
  1483 
  1778     bool isBitmap = pixmap.isQBitmap();
  1484     bool isBitmap = pixmap.isQBitmap();
  1779     bool isOpaque = !isBitmap && (!pixmap.hasAlphaChannel() || (hints & QDrawPixmaps::OpaqueHint)) && allOpaque;
  1485     bool isOpaque = !isBitmap && (!pixmap.hasAlphaChannel() || (hints & QDrawPixmaps::OpaqueHint)) && allOpaque;
  1780 
  1486 
  1781     d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
  1487     updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
  1782                            state()->renderHints & QPainter::SmoothPixmapTransform, texture->id);
  1488                            q->state()->renderHints & QPainter::SmoothPixmapTransform, texture->id);
  1783 
  1489 
  1784     // Setup for texture drawing
  1490     // Setup for texture drawing
  1785     d->shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc);
  1491     currentBrush = noBrush;
  1786     if (d->prepareForDraw(isOpaque))
  1492     shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc);
  1787         d->shaderManager->currentProgram()->setUniformValue(d->location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
  1493     if (prepareForDraw(isOpaque))
       
  1494         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
  1788 
  1495 
  1789     if (isBitmap) {
  1496     if (isBitmap) {
  1790         QColor col = qt_premultiplyColor(state()->pen.color(), (GLfloat)state()->opacity);
  1497         QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity);
  1791         d->shaderManager->currentProgram()->setUniformValue(d->location(QGLEngineShaderManager::PatternColor), col);
  1498         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
  1792     }
  1499     }
  1793 
  1500 
  1794     glDrawArrays(GL_TRIANGLES, 0, 6 * dataCount);
  1501     glDrawArrays(GL_TRIANGLES, 0, 6 * dataCount);
  1795 }
  1502 }
  1796 
  1503 
  1818     d->brushUniformsDirty = true;
  1525     d->brushUniformsDirty = true;
  1819     d->matrixDirty = true;
  1526     d->matrixDirty = true;
  1820     d->compositionModeDirty = true;
  1527     d->compositionModeDirty = true;
  1821     d->opacityUniformDirty = true;
  1528     d->opacityUniformDirty = true;
  1822     d->needsSync = true;
  1529     d->needsSync = true;
  1823     d->use_system_clip = !systemClip().isEmpty();
  1530     d->useSystemClip = !systemClip().isEmpty();
  1824     d->currentBrush = QBrush();
  1531     d->currentBrush = QBrush();
  1825 
  1532 
  1826     d->dirtyStencilRegion = QRect(0, 0, d->width, d->height);
  1533     d->dirtyStencilRegion = QRect(0, 0, d->width, d->height);
  1827     d->stencilClean = true;
  1534     d->stencilClean = true;
  1828 
  1535 
  1838     Q_UNUSED(success);
  1545     Q_UNUSED(success);
  1839 #endif
  1546 #endif
  1840 
  1547 
  1841     d->shaderManager = new QGLEngineShaderManager(d->ctx);
  1548     d->shaderManager = new QGLEngineShaderManager(d->ctx);
  1842 
  1549 
  1843     if (!d->inRenderText) {
  1550     glDisable(GL_STENCIL_TEST);
  1844         glDisable(GL_STENCIL_TEST);
  1551     glDisable(GL_DEPTH_TEST);
  1845         glDisable(GL_DEPTH_TEST);
  1552     glDisable(GL_SCISSOR_TEST);
  1846         glDisable(GL_SCISSOR_TEST);
       
  1847     }
       
  1848 
  1553 
  1849 #if !defined(QT_OPENGL_ES_2)
  1554 #if !defined(QT_OPENGL_ES_2)
  1850     glDisable(GL_MULTISAMPLE);
  1555     glDisable(GL_MULTISAMPLE);
  1851 #endif
  1556 #endif
  1852 
  1557 
  1853     d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
  1558     d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
  1854 
  1559 
  1855 #if !defined(QT_OPENGL_ES_2)
  1560 #if !defined(QT_OPENGL_ES_2)
  1856 #if defined(Q_WS_WIN)
  1561 #if defined(Q_WS_WIN)
       
  1562     extern Q_GUI_EXPORT bool qt_cleartype_enabled;
  1857     if (qt_cleartype_enabled)
  1563     if (qt_cleartype_enabled)
  1858 #endif
  1564 #endif
  1859         d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask;
  1565         d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask;
  1860 #endif
  1566 #endif
  1861 
  1567 
  1919     if (d->needsSync) {
  1625     if (d->needsSync) {
  1920         d->transferMode(BrushDrawingMode);
  1626         d->transferMode(BrushDrawingMode);
  1921         glViewport(0, 0, d->width, d->height);
  1627         glViewport(0, 0, d->width, d->height);
  1922         d->needsSync = false;
  1628         d->needsSync = false;
  1923         d->shaderManager->setDirty();
  1629         d->shaderManager->setDirty();
       
  1630         d->ctx->d_func()->syncGlState();
       
  1631         for (int i = 0; i < 3; ++i)
       
  1632             d->vertexAttribPointers[i] = (GLfloat*)-1; // Assume the pointers are clobbered
  1924         setState(state());
  1633         setState(state());
  1925     }
  1634     }
  1926 }
  1635 }
  1927 
  1636 
  1928 void QGL2PaintEngineExPrivate::updateClipScissorTest()
  1637 void QGL2PaintEngineExPrivate::updateClipScissorTest()
  1939 #ifdef QT_GL_NO_SCISSOR_TEST
  1648 #ifdef QT_GL_NO_SCISSOR_TEST
  1940     currentScissorBounds = QRect(0, 0, width, height);
  1649     currentScissorBounds = QRect(0, 0, width, height);
  1941 #else
  1650 #else
  1942     QRect bounds = q->state()->rectangleClip;
  1651     QRect bounds = q->state()->rectangleClip;
  1943     if (!q->state()->clipEnabled) {
  1652     if (!q->state()->clipEnabled) {
  1944         if (use_system_clip)
  1653         if (useSystemClip)
  1945             bounds = systemClip.boundingRect();
  1654             bounds = systemClip.boundingRect();
  1946         else
  1655         else
  1947             bounds = QRect(0, 0, width, height);
  1656             bounds = QRect(0, 0, width, height);
  1948     } else {
  1657     } else {
  1949         if (use_system_clip)
  1658         if (useSystemClip)
  1950             bounds = bounds.intersected(systemClip.boundingRect());
  1659             bounds = bounds.intersected(systemClip.boundingRect());
  1951         else
  1660         else
  1952             bounds = bounds.intersected(QRect(0, 0, width, height));
  1661             bounds = bounds.intersected(QRect(0, 0, width, height));
  1953     }
  1662     }
  1954 
  1663 
  1999 
  1708 
  2000 void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint value)
  1709 void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint value)
  2001 {
  1710 {
  2002     transferMode(BrushDrawingMode);
  1711     transferMode(BrushDrawingMode);
  2003 
  1712 
       
  1713     if (addOffset) {
       
  1714         addOffset = false;
       
  1715         matrixDirty = true;
       
  1716     }
       
  1717     if (snapToPixelGrid) {
       
  1718         snapToPixelGrid = false;
       
  1719         matrixDirty = true;
       
  1720     }
       
  1721 
  2004     if (matrixDirty)
  1722     if (matrixDirty)
  2005         updateMatrix();
  1723         updateMatrix();
  2006 
  1724 
  2007     stencilClean = false;
  1725     stencilClean = false;
  2008 
  1726 
  2098 
  1816 
  2099     const QRect pathRect = state()->matrix.mapRect(path.controlPointRect()).toAlignedRect();
  1817     const QRect pathRect = state()->matrix.mapRect(path.controlPointRect()).toAlignedRect();
  2100 
  1818 
  2101     switch (op) {
  1819     switch (op) {
  2102     case Qt::NoClip:
  1820     case Qt::NoClip:
  2103         if (d->use_system_clip) {
  1821         if (d->useSystemClip) {
  2104             state()->clipTestEnabled = true;
  1822             state()->clipTestEnabled = true;
  2105             state()->currentClip = 1;
  1823             state()->currentClip = 1;
  2106         } else {
  1824         } else {
  2107             state()->clipTestEnabled = false;
  1825             state()->clipTestEnabled = false;
  2108         }
  1826         }
  2170     Q_Q(QGL2PaintEngineEx);
  1888     Q_Q(QGL2PaintEngineEx);
  2171 
  1889 
  2172     q->state()->clipChanged = true;
  1890     q->state()->clipChanged = true;
  2173 
  1891 
  2174     if (systemClip.isEmpty()) {
  1892     if (systemClip.isEmpty()) {
  2175         use_system_clip = false;
  1893         useSystemClip = false;
  2176     } else {
  1894     } else {
  2177         if (q->paintDevice()->devType() == QInternal::Widget && currentClipWidget) {
  1895         if (q->paintDevice()->devType() == QInternal::Widget && currentClipWidget) {
  2178             QWidgetPrivate *widgetPrivate = qt_widget_private(currentClipWidget->window());
  1896             QWidgetPrivate *widgetPrivate = qt_widget_private(currentClipWidget->window());
  2179             use_system_clip = widgetPrivate->extra && widgetPrivate->extra->inRenderWithPainter;
  1897             useSystemClip = widgetPrivate->extra && widgetPrivate->extra->inRenderWithPainter;
  2180         } else {
  1898         } else {
  2181             use_system_clip = true;
  1899             useSystemClip = true;
  2182         }
  1900         }
  2183     }
  1901     }
  2184 
  1902 
  2185     q->state()->clipTestEnabled = false;
  1903     q->state()->clipTestEnabled = false;
  2186     q->state()->needsClipBufferClear = true;
  1904     q->state()->needsClipBufferClear = true;
  2187 
  1905 
  2188     q->state()->currentClip = 1;
  1906     q->state()->currentClip = 1;
  2189     maxClip = 1;
  1907     maxClip = 1;
  2190 
  1908 
  2191     q->state()->rectangleClip = use_system_clip ? systemClip.boundingRect() : QRect(0, 0, width, height);
  1909     q->state()->rectangleClip = useSystemClip ? systemClip.boundingRect() : QRect(0, 0, width, height);
  2192     updateClipScissorTest();
  1910     updateClipScissorTest();
  2193 
  1911 
  2194     if (systemClip.rectCount() == 1) {
  1912     if (systemClip.rectCount() == 1) {
  2195         if (systemClip.boundingRect() == QRect(0, 0, width, height))
  1913         if (systemClip.boundingRect() == QRect(0, 0, width, height))
  2196             use_system_clip = false;
  1914             useSystemClip = false;
  2197 #ifndef QT_GL_NO_SCISSOR_TEST
  1915 #ifndef QT_GL_NO_SCISSOR_TEST
  2198         // scissoring takes care of the system clip
  1916         // scissoring takes care of the system clip
  2199         return;
  1917         return;
  2200 #endif
  1918 #endif
  2201     }
  1919     }
  2202 
  1920 
  2203     if (use_system_clip) {
  1921     if (useSystemClip) {
  2204         clearClip(0);
  1922         clearClip(0);
  2205 
  1923 
  2206         QPainterPath path;
  1924         QPainterPath path;
  2207         path.addRegion(systemClip);
  1925         path.addRegion(systemClip);
  2208 
  1926 
  2277     s->clipChanged = false;
  1995     s->clipChanged = false;
  2278 
  1996 
  2279     return s;
  1997     return s;
  2280 }
  1998 }
  2281 
  1999 
  2282 void QGL2PaintEngineEx::setRenderTextActive(bool active)
       
  2283 {
       
  2284     Q_D(QGL2PaintEngineEx);
       
  2285     d->inRenderText = active;
       
  2286 }
       
  2287 
       
  2288 QOpenGL2PaintEngineState::QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other)
  2000 QOpenGL2PaintEngineState::QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other)
  2289     : QPainterState(other)
  2001     : QPainterState(other)
  2290 {
  2002 {
  2291     isNew = true;
  2003     isNew = true;
  2292     needsClipBufferClear = other.needsClipBufferClear;
  2004     needsClipBufferClear = other.needsClipBufferClear;
  2307 QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState()
  2019 QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState()
  2308 {
  2020 {
  2309 }
  2021 }
  2310 
  2022 
  2311 QT_END_NAMESPACE
  2023 QT_END_NAMESPACE
  2312 
       
  2313 #include "qpaintengineex_opengl2.moc"