src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
changeset 18 2f34d5167611
parent 3 41300fa6a67c
child 19 fcece45ef507
equal deleted inserted replaced
3:41300fa6a67c 18:2f34d5167611
     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 
    92 #if defined(Q_WS_WIN)
    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;
    93 extern Q_GUI_EXPORT bool qt_cleartype_enabled;
   102 #endif
    94 #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 
    95 
   342 extern QImage qt_imageForBrush(int brushStyle, bool invert);
    96 extern QImage qt_imageForBrush(int brushStyle, bool invert);
   343 
    97 
   344 ////////////////////////////////// Private Methods //////////////////////////////////////////
    98 ////////////////////////////////// Private Methods //////////////////////////////////////////
   345 
    99 
   356 }
   110 }
   357 
   111 
   358 void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id)
   112 void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id)
   359 {
   113 {
   360 //    glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); //### Is it always this texture unit?
   114 //    glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); //### Is it always this texture unit?
   361     if (id != GLuint(-1) && id == lastTexture)
   115     if (id != GLuint(-1) && id == lastTextureUsed)
   362         return;
   116         return;
   363 
   117 
   364     lastTexture = id;
   118     lastTextureUsed = id;
   365 
   119 
   366     if (smoothPixmapTransform) {
   120     if (smoothPixmapTransform) {
   367         glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   121         glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   368         glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   122         glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   369     } else {
   123     } else {
   386 }
   140 }
   387 
   141 
   388 
   142 
   389 void QGL2PaintEngineExPrivate::setBrush(const QBrush& brush)
   143 void QGL2PaintEngineExPrivate::setBrush(const QBrush& brush)
   390 {
   144 {
   391     Q_ASSERT(brush.style() != Qt::NoBrush);
       
   392 
       
   393     if (qbrush_fast_equals(currentBrush, brush))
   145     if (qbrush_fast_equals(currentBrush, brush))
   394         return;
   146         return;
   395 
   147 
       
   148     const Qt::BrushStyle newStyle = qbrush_style(brush);
       
   149     Q_ASSERT(newStyle != Qt::NoBrush);
       
   150 
   396     currentBrush = brush;
   151     currentBrush = brush;
   397 
   152     brushUniformsDirty = true; // All brushes have at least one uniform
   398     brushTextureDirty = true;
   153 
   399     brushUniformsDirty = true;
   154     if (newStyle > Qt::SolidPattern)
       
   155         brushTextureDirty = true;
       
   156 
   400     if (currentBrush.style() == Qt::TexturePattern
   157     if (currentBrush.style() == Qt::TexturePattern
   401         && qHasPixmapTexture(brush) && brush.texture().isQBitmap())
   158         && qHasPixmapTexture(brush) && brush.texture().isQBitmap())
   402     {
   159     {
   403         shaderManager->setSrcPixelType(QGLEngineShaderManager::TextureSrcWithPattern);
   160         shaderManager->setSrcPixelType(QGLEngineShaderManager::TextureSrcWithPattern);
   404     } else {
   161     } else {
   405         shaderManager->setSrcPixelType(currentBrush.style());
   162         shaderManager->setSrcPixelType(newStyle);
   406     }
   163     }
   407     shaderManager->optimiseForBrushTransform(currentBrush.transform());
   164     shaderManager->optimiseForBrushTransform(currentBrush.transform().type());
   408 }
   165 }
   409 
   166 
   410 
   167 
   411 void QGL2PaintEngineExPrivate::useSimpleShader()
   168 void QGL2PaintEngineExPrivate::useSimpleShader()
   412 {
   169 {
   413     shaderManager->simpleProgram()->bind();
   170     shaderManager->useSimpleProgram();
   414     shaderManager->setDirty();
       
   415 
   171 
   416     if (matrixDirty)
   172     if (matrixDirty)
   417         updateMatrix();
   173         updateMatrix();
   418 
       
   419     if (simpleShaderMatrixUniformDirty) {
       
   420         shaderManager->simpleProgram()->setUniformValue("pmvMatrix", pmvMatrix);
       
   421         simpleShaderMatrixUniformDirty = false;
       
   422     }
       
   423 }
   174 }
   424 
   175 
   425 void QGL2PaintEngineExPrivate::updateBrushTexture()
   176 void QGL2PaintEngineExPrivate::updateBrushTexture()
   426 {
   177 {
   427     Q_Q(QGL2PaintEngineEx);
   178     Q_Q(QGL2PaintEngineEx);
   581 // This assumes the shader manager has already setup the correct shader program
   332 // This assumes the shader manager has already setup the correct shader program
   582 void QGL2PaintEngineExPrivate::updateMatrix()
   333 void QGL2PaintEngineExPrivate::updateMatrix()
   583 {
   334 {
   584 //     qDebug("QGL2PaintEngineExPrivate::updateMatrix()");
   335 //     qDebug("QGL2PaintEngineExPrivate::updateMatrix()");
   585 
   336 
   586     // We set up the 4x4 transformation matrix on the vertex shaders to
   337     const QTransform& transform = q->state()->matrix;
   587     // be the equivalent of glOrtho(0, w, h, 0, -1, 1) * transform:
   338 
       
   339     // The projection matrix converts from Qt's coordinate system to GL's coordinate system
       
   340     //    * GL's viewport is 2x2, Qt's is width x height
       
   341     //    * GL has +y -> -y going from bottom -> top, Qt is the other way round
       
   342     //    * GL has [0,0] in the center, Qt has it in the top-left
   588     //
   343     //
   589     // | 2/width     0     0 -1 |   | m11  m21  0   dx |
   344     // This results in the Projection matrix below, which is multiplied by the painter's
   590     // |   0    -2/height  0  1 |   | m12  m22  0   dy |
   345     // transformation matrix, as shown below:
   591     // |   0         0    -1  0 | * |  0    0   1   0  |
       
   592     // |   0         0     0  1 |   | m13  m23  0  m33 |
       
   593     //
   346     //
   594     // We expand out the multiplication to save the cost of a full 4x4
   347     //                Projection Matrix                      Painter Transform
   595     // matrix multiplication as most of the components are trivial.
   348     // ------------------------------------------------   ------------------------
   596     const QTransform& transform = q->state()->matrix;
   349     // | 2.0 / width  |      0.0      |     -1.0      |   |  m11  |  m21  |  dx  |
   597 
   350     // |     0.0      | -2.0 / height |      1.0      | * |  m12  |  m22  |  dy  |
   598     qreal wfactor = 2.0 / width;
   351     // |     0.0      |      0.0      |      1.0      |   |  m13  |  m23  |  m33 |
   599     qreal hfactor = -2.0 / height;
   352     // ------------------------------------------------   ------------------------
   600 
   353     //
   601     pmvMatrix[0][0] = wfactor * transform.m11() - transform.m13();
   354     // NOTE: The resultant matrix is also transposed, as GL expects column-major matracies
   602     pmvMatrix[0][1] = hfactor * transform.m12() + transform.m13();
   355 
   603     pmvMatrix[0][2] = 0.0;
   356     const GLfloat wfactor = 2.0f / width;
   604     pmvMatrix[0][3] = transform.m13();
   357     const GLfloat hfactor = -2.0f / height;
   605     pmvMatrix[1][0] = wfactor * transform.m21() - transform.m23();
   358     GLfloat dx = transform.dx();
   606     pmvMatrix[1][1] = hfactor * transform.m22() + transform.m23();
   359     GLfloat dy = transform.dy();
   607     pmvMatrix[1][2] = 0.0;
   360 
   608     pmvMatrix[1][3] = transform.m23();
   361     // Non-integer translates can have strange effects for some rendering operations such as
   609     pmvMatrix[2][0] = 0.0;
   362     // anti-aliased text rendering. In such cases, we snap the translate to the pixel grid.
   610     pmvMatrix[2][1] = 0.0;
   363     if (snapToPixelGrid && transform.type() == QTransform::TxTranslate) {
   611     pmvMatrix[2][2] = -1.0;
   364         // 0.50 needs to rounded down to 0.0 for consistency with raster engine:
   612     pmvMatrix[2][3] = 0.0;
   365         dx = ceilf(dx - 0.5f);
   613     pmvMatrix[3][0] = wfactor * transform.dx() - transform.m33();
   366         dy = ceilf(dy - 0.5f);
   614     pmvMatrix[3][1] = hfactor * transform.dy() + transform.m33();
   367     }
   615     pmvMatrix[3][2] = 0.0;
   368 
   616     pmvMatrix[3][3] = transform.m33();
   369     if (addOffset) {
       
   370         dx += 0.49f;
       
   371         dy += 0.49f;
       
   372     }
       
   373 
       
   374     pmvMatrix[0][0] = (wfactor * transform.m11())  - transform.m13();
       
   375     pmvMatrix[1][0] = (wfactor * transform.m21())  - transform.m23();
       
   376     pmvMatrix[2][0] = (wfactor * dx) - transform.m33();
       
   377     pmvMatrix[0][1] = (hfactor * transform.m12())  + transform.m13();
       
   378     pmvMatrix[1][1] = (hfactor * transform.m22())  + transform.m23();
       
   379     pmvMatrix[2][1] = (hfactor * dy) + transform.m33();
       
   380     pmvMatrix[0][2] = transform.m13();
       
   381     pmvMatrix[1][2] = transform.m23();
       
   382     pmvMatrix[2][2] = transform.m33();
   617 
   383 
   618     // 1/10000 == 0.0001, so we have good enough res to cover curves
   384     // 1/10000 == 0.0001, so we have good enough res to cover curves
   619     // that span the entire widget...
   385     // that span the entire widget...
   620     inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())),
   386     inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())),
   621                                   qMax(qAbs(transform.m12()), qAbs(transform.m21())) ),
   387                                   qMax(qAbs(transform.m12()), qAbs(transform.m21())) ),
   622                         qreal(0.0001));
   388                         qreal(0.0001));
   623 
   389 
   624     matrixDirty = false;
   390     matrixDirty = false;
   625 
   391 
   626     // The actual data has been updated so both shader program's uniforms need updating
   392     // Set the PMV matrix attribute. As we use an attributes rather than uniforms, we only
   627     simpleShaderMatrixUniformDirty = true;
   393     // need to do this once for every matrix change and persists across all shader programs.
   628     shaderMatrixUniformDirty = true;
   394     glVertexAttrib3fv(QT_PMV_MATRIX_1_ATTR, pmvMatrix[0]);
       
   395     glVertexAttrib3fv(QT_PMV_MATRIX_2_ATTR, pmvMatrix[1]);
       
   396     glVertexAttrib3fv(QT_PMV_MATRIX_3_ATTR, pmvMatrix[2]);
   629 
   397 
   630     dasher.setInvScale(inverseScale);
   398     dasher.setInvScale(inverseScale);
   631     stroker.setInvScale(inverseScale);
   399     stroker.setInvScale(inverseScale);
   632 }
   400 }
   633 
   401 
   698 }
   466 }
   699 
   467 
   700 void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern)
   468 void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern)
   701 {
   469 {
   702     // Setup for texture drawing
   470     // Setup for texture drawing
       
   471     currentBrush = noBrush;
   703     shaderManager->setSrcPixelType(pattern ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc);
   472     shaderManager->setSrcPixelType(pattern ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc);
       
   473 
       
   474     if (addOffset) {
       
   475         addOffset = false;
       
   476         matrixDirty = true;
       
   477     }
       
   478 
       
   479     if (snapToPixelGrid) {
       
   480         snapToPixelGrid = false;
       
   481         matrixDirty = true;
       
   482     }
       
   483 
   704     if (prepareForDraw(opaque))
   484     if (prepareForDraw(opaque))
   705         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
   485         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
   706 
   486 
   707     if (pattern) {
   487     if (pattern) {
   708         QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity);
   488         QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity);
   726     ensureActive();
   506     ensureActive();
   727     d->transferMode(BrushDrawingMode);
   507     d->transferMode(BrushDrawingMode);
   728 
   508 
   729     QGLContext *ctx = d->ctx;
   509     QGLContext *ctx = d->ctx;
   730     glUseProgram(0);
   510     glUseProgram(0);
       
   511 
       
   512     // Disable all the vertex attribute arrays:
       
   513     for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i)
       
   514         glDisableVertexAttribArray(i);
   731 
   515 
   732 #ifndef QT_OPENGL_ES_2
   516 #ifndef QT_OPENGL_ES_2
   733     // be nice to people who mix OpenGL 1.x code with QPainter commands
   517     // 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
   518     // by setting modelview and projection matrices to mirror the GL 1
   735     // paint engine
   519     // paint engine
   753     glLoadMatrixf(&mv_matrix[0][0]);
   537     glLoadMatrixf(&mv_matrix[0][0]);
   754 #else
   538 #else
   755     Q_UNUSED(ctx);
   539     Q_UNUSED(ctx);
   756 #endif
   540 #endif
   757 
   541 
   758     d->lastTexture = GLuint(-1);
   542     d->lastTextureUsed = GLuint(-1);
   759     d->dirtyStencilRegion = QRect(0, 0, d->width, d->height);
   543     d->dirtyStencilRegion = QRect(0, 0, d->width, d->height);
   760     d->resetGLState();
   544     d->resetGLState();
   761 
   545 
   762     d->shaderManager->setDirty();
   546     d->shaderManager->setDirty();
   763 
   547 
   772     glDisable(GL_DEPTH_TEST);
   556     glDisable(GL_DEPTH_TEST);
   773     glDisable(GL_SCISSOR_TEST);
   557     glDisable(GL_SCISSOR_TEST);
   774     glDepthMask(true);
   558     glDepthMask(true);
   775     glDepthFunc(GL_LESS);
   559     glDepthFunc(GL_LESS);
   776     glClearDepth(1);
   560     glClearDepth(1);
       
   561     glStencilMask(0xff);
       
   562     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
       
   563     glStencilFunc(GL_ALWAYS, 0, 0xff);
       
   564     glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
       
   565     glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
       
   566     glDisableVertexAttribArray(QT_OPACITY_ATTR);
       
   567 #ifndef QT_OPENGL_ES_2
       
   568     glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // color may have been changed by glVertexAttrib()
       
   569 #endif
   777 }
   570 }
   778 
   571 
   779 void QGL2PaintEngineEx::endNativePainting()
   572 void QGL2PaintEngineEx::endNativePainting()
   780 {
   573 {
   781     Q_D(QGL2PaintEngineEx);
   574     Q_D(QGL2PaintEngineEx);
   782     d->needsSync = true;
   575     d->needsSync = true;
   783 }
   576 }
   784 
   577 
   785 const QGLContext *QGL2PaintEngineEx::context()
       
   786 {
       
   787     Q_D(QGL2PaintEngineEx);
       
   788     return d->ctx;
       
   789 }
       
   790 
       
   791 void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
   578 void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
   792 {
   579 {
   793     if (newMode == mode)
   580     if (newMode == mode)
   794         return;
   581         return;
   795 
   582 
   796     if (mode == TextDrawingMode || mode == ImageDrawingMode || mode == ImageArrayDrawingMode) {
   583     if (mode == TextDrawingMode || mode == ImageDrawingMode || mode == ImageArrayDrawingMode) {
   797         glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
   584         lastTextureUsed = GLuint(-1);
   798         glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
       
   799         glDisableVertexAttribArray(QT_OPACITY_ATTR);
       
   800 
       
   801         lastTexture = GLuint(-1);
       
   802     }
   585     }
   803 
   586 
   804     if (newMode == TextDrawingMode) {
   587     if (newMode == TextDrawingMode) {
   805         glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
   588         setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data());
   806         glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
   589         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     }
   590     }
   811 
   591 
   812     if (newMode == ImageDrawingMode) {
   592     if (newMode == ImageDrawingMode) {
   813         glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
   593         setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray);
   814         glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
   594         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     }
   595     }
   819 
   596 
   820     if (newMode == ImageArrayDrawingMode) {
   597     if (newMode == ImageArrayDrawingMode) {
   821         glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
   598         setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data());
   822         glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
   599         setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data());
   823         glEnableVertexAttribArray(QT_OPACITY_ATTR);
   600         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     }
   601     }
   829 
   602 
   830     // This needs to change when we implement high-quality anti-aliasing...
   603     // This needs to change when we implement high-quality anti-aliasing...
   831     if (newMode != TextDrawingMode)
   604     if (newMode != TextDrawingMode)
   832         shaderManager->setMaskType(QGLEngineShaderManager::NoMask);
   605         shaderManager->setMaskType(QGLEngineShaderManager::NoMask);
   844     int vertexCount;
   617     int vertexCount;
   845     GLenum primitiveType;
   618     GLenum primitiveType;
   846     qreal iscale;
   619     qreal iscale;
   847 };
   620 };
   848 
   621 
   849 void qopengl2paintengine_cleanup_vectorpath(QPaintEngineEx *engine, void *data)
   622 void QGL2PaintEngineExPrivate::cleanupVectorPath(QPaintEngineEx *engine, void *data)
   850 {
   623 {
   851     QGL2PEVectorPathCache *c = (QGL2PEVectorPathCache *) data;
   624     QGL2PEVectorPathCache *c = (QGL2PEVectorPathCache *) data;
   852 #ifdef QT_OPENGL_CACHE_AS_VBOS
   625 #ifdef QT_OPENGL_CACHE_AS_VBOS
   853     QGL2PaintEngineExPrivate *d = QGL2PaintEngineExPrivate::getData((QGL2PaintEngineEx *) engine);
   626     Q_ASSERT(engine->type() == QPaintEngine::OpenGL2);
   854     d->unusedVBOSToClean << c->vbo;
   627     static_cast<QGL2PaintEngineEx *>(engine)->d_func()->unusedVBOSToClean << c->vbo;
   855 #else
   628 #else
       
   629     Q_UNUSED(engine);
   856     qFree(c->vertices);
   630     qFree(c->vertices);
   857 #endif
   631 #endif
   858     delete c;
   632     delete c;
   859 }
   633 }
   860 
   634 
   861 // Assumes everything is configured for the brush you want to use
   635 // Assumes everything is configured for the brush you want to use
   862 void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)
   636 void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)
   863 {
   637 {
   864     transferMode(BrushDrawingMode);
   638     transferMode(BrushDrawingMode);
       
   639 
       
   640     const QOpenGL2PaintEngineState *s = q->state();
       
   641     const bool newAddOffset = !(s->renderHints & QPainter::Antialiasing) &&
       
   642                               (qbrush_style(currentBrush) == Qt::SolidPattern) &&
       
   643                               !multisamplingAlwaysEnabled;
       
   644 
       
   645     if (addOffset != newAddOffset) {
       
   646         addOffset = newAddOffset;
       
   647         matrixDirty = true;
       
   648     }
       
   649 
       
   650     if (snapToPixelGrid) {
       
   651         snapToPixelGrid = false;
       
   652         matrixDirty = true;
       
   653     }
   865 
   654 
   866     // Might need to call updateMatrix to re-calculate inverseScale
   655     // Might need to call updateMatrix to re-calculate inverseScale
   867     if (matrixDirty)
   656     if (matrixDirty)
   868         updateMatrix();
   657         updateMatrix();
   869 
   658 
   896                     }
   685                     }
   897                 }
   686                 }
   898             } else {
   687             } else {
   899                 cache = new QGL2PEVectorPathCache;
   688                 cache = new QGL2PEVectorPathCache;
   900                 cache->vertexCount = 0;
   689                 cache->vertexCount = 0;
   901                 data = const_cast<QVectorPath &>(path).addCacheData(q, cache, qopengl2paintengine_cleanup_vectorpath);
   690                 data = const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath);
   902             }
   691             }
   903 
   692 
   904             // Flatten the path at the current scale factor and fill it into the cache struct.
   693             // Flatten the path at the current scale factor and fill it into the cache struct.
   905             if (!cache->vertexCount) {
   694             if (!cache->vertexCount) {
   906                 vertexCoordinateArray.clear();
   695                 vertexCoordinateArray.clear();
   919                 memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes);
   708                 memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes);
   920 #endif
   709 #endif
   921             }
   710             }
   922 
   711 
   923             prepareForDraw(currentBrush.isOpaque());
   712             prepareForDraw(currentBrush.isOpaque());
   924             glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
       
   925 #ifdef QT_OPENGL_CACHE_AS_VBOS
   713 #ifdef QT_OPENGL_CACHE_AS_VBOS
   926             glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
   714             glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
   927             glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, 0);
   715             setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0);
   928 #else
   716 #else
   929             glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, cache->vertices);
   717             setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, cache->vertices);
   930 #endif
   718 #endif
   931             glDrawArrays(cache->primitiveType, 0, cache->vertexCount);
   719             glDrawArrays(cache->primitiveType, 0, cache->vertexCount);
   932 
   720 
   933         } else {
   721         } else {
   934       //        printf(" - Marking path as cachable...\n");
   722       //        printf(" - Marking path as cachable...\n");
   961             glStencilFunc(GL_NOTEQUAL, 0, 0xff);
   749             glStencilFunc(GL_NOTEQUAL, 0, 0xff);
   962         } else {
   750         } else {
   963             // Pass when high bit is set, replace stencil value with 0
   751             // Pass when high bit is set, replace stencil value with 0
   964             glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
   752             glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
   965         }
   753         }
   966 
       
   967         prepareForDraw(currentBrush.isOpaque());
   754         prepareForDraw(currentBrush.isOpaque());
   968 
       
   969         if (inRenderText)
       
   970             prepareDepthRangeForRenderText();
       
   971 
   755 
   972         // Stencil the brush onto the dest buffer
   756         // Stencil the brush onto the dest buffer
   973         composite(vertexCoordinateArray.boundingRect());
   757         composite(vertexCoordinateArray.boundingRect());
   974 
       
   975         if (inRenderText)
       
   976             restoreDepthRangeForRenderText();
       
   977 
       
   978         glStencilMask(0);
   758         glStencilMask(0);
   979 
       
   980         updateClipScissorTest();
   759         updateClipScissorTest();
   981     }
   760     }
   982 }
   761 }
   983 
   762 
   984 
   763 
  1012     }
   791     }
  1013 
   792 
  1014     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes
   793     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes
  1015     useSimpleShader();
   794     useSimpleShader();
  1016     glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d
   795     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 
   796 
  1025     if (mode == WindingFillMode) {
   797     if (mode == WindingFillMode) {
  1026         Q_ASSERT(stops && !count);
   798         Q_ASSERT(stops && !count);
  1027         if (q->state()->clipTestEnabled) {
   799         if (q->state()->clipTestEnabled) {
  1028             // Flatten clip values higher than current clip, and set high bit to match current clip
   800             // Flatten clip values higher than current clip, and set high bit to match current clip
  1060     } else { // TriStripStrokeFillMode
   832     } else { // TriStripStrokeFillMode
  1061         Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops
   833         Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops
  1062         glStencilMask(GL_STENCIL_HIGH_BIT);
   834         glStencilMask(GL_STENCIL_HIGH_BIT);
  1063 #if 0
   835 #if 0
  1064         glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit
   836         glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit
  1065         glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
   837         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);
   838         glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
  1068         glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
       
  1069 #else
   839 #else
  1070 
   840 
  1071         glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
   841         glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  1072         if (q->state()->clipTestEnabled) {
   842         if (q->state()->clipTestEnabled) {
  1073             glStencilFunc(GL_LEQUAL, q->state()->currentClip | GL_STENCIL_HIGH_BIT,
   843             glStencilFunc(GL_LEQUAL, q->state()->currentClip | GL_STENCIL_HIGH_BIT,
  1074                           ~GL_STENCIL_HIGH_BIT);
   844                           ~GL_STENCIL_HIGH_BIT);
  1075         } else {
   845         } else {
  1076             glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff);
   846             glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff);
  1077         }
   847         }
  1078         glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
   848         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);
   849         glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
  1081         glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
       
  1082 #endif
   850 #endif
  1083     }
   851     }
  1084 
   852 
  1085     // Enable color writes & disable stencil writes
   853     // Enable color writes & disable stencil writes
  1086     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
   854     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 }
   855 }
  1094 
   856 
  1095 /*
   857 /*
  1096     If the maximum value in the stencil buffer is GL_STENCIL_HIGH_BIT - 1,
   858     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
   859     restore the stencil buffer to a pristine state.  The current clip region
  1173     bool changed = shaderManager->useCorrectShaderProg();
   935     bool changed = shaderManager->useCorrectShaderProg();
  1174     // If the shader program needs changing, we change it and mark all uniforms as dirty
   936     // If the shader program needs changing, we change it and mark all uniforms as dirty
  1175     if (changed) {
   937     if (changed) {
  1176         // The shader program has changed so mark all uniforms as dirty:
   938         // The shader program has changed so mark all uniforms as dirty:
  1177         brushUniformsDirty = true;
   939         brushUniformsDirty = true;
  1178         shaderMatrixUniformDirty = true;
       
  1179         opacityUniformDirty = true;
   940         opacityUniformDirty = true;
  1180     }
   941     }
  1181 
   942 
  1182     if (brushUniformsDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode)
   943     if (brushUniformsDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode)
  1183         updateBrushUniforms();
   944         updateBrushUniforms();
  1184 
       
  1185     if (shaderMatrixUniformDirty) {
       
  1186         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PmvMatrix), pmvMatrix);
       
  1187         shaderMatrixUniformDirty = false;
       
  1188     }
       
  1189 
   945 
  1190     if (opacityMode == QGLEngineShaderManager::UniformOpacity && opacityUniformDirty) {
   946     if (opacityMode == QGLEngineShaderManager::UniformOpacity && opacityUniformDirty) {
  1191         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::GlobalOpacity), (GLfloat)q->state()->opacity);
   947         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::GlobalOpacity), (GLfloat)q->state()->opacity);
  1192         opacityUniformDirty = false;
   948         opacityUniformDirty = false;
  1193     }
   949     }
  1195     return changed;
   951     return changed;
  1196 }
   952 }
  1197 
   953 
  1198 void QGL2PaintEngineExPrivate::composite(const QGLRect& boundingRect)
   954 void QGL2PaintEngineExPrivate::composite(const QGLRect& boundingRect)
  1199 {
   955 {
  1200     // Setup a vertex array for the bounding rect:
   956     setCoords(staticVertexCoordinateArray, boundingRect);
  1201     GLfloat rectVerts[] = {
   957     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);
   958     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
  1212 
       
  1213     glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
       
  1214 }
   959 }
  1215 
   960 
  1216 // Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans.
   961 // Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans.
  1217 void QGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stops, int stopCount,
   962 void QGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stops, int stopCount,
  1218                                                 GLenum primitive)
   963                                                 GLenum primitive)
  1219 {
   964 {
  1220     // Now setup the pointer to the vertex array:
   965     // Now setup the pointer to the vertex array:
  1221     glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
   966     setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)data);
  1222     glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data);
       
  1223 
   967 
  1224     int previousStop = 0;
   968     int previousStop = 0;
  1225     for (int i=0; i<stopCount; ++i) {
   969     for (int i=0; i<stopCount; ++i) {
  1226         int stop = stops[i];
   970         int stop = stops[i];
  1227 /*
   971 /*
  1230             qDebug("   %02d: [%.2f, %.2f]", i, vertexArray.data()[i].x, vertexArray.data()[i].y);
   974             qDebug("   %02d: [%.2f, %.2f]", i, vertexArray.data()[i].x, vertexArray.data()[i].y);
  1231 */
   975 */
  1232         glDrawArrays(primitive, previousStop, stop - previousStop);
   976         glDrawArrays(primitive, previousStop, stop - previousStop);
  1233         previousStop = stop;
   977         previousStop = stop;
  1234     }
   978     }
  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 }
   979 }
  1261 
   980 
  1262 /////////////////////////////////// Public Methods //////////////////////////////////////////
   981 /////////////////////////////////// Public Methods //////////////////////////////////////////
  1263 
   982 
  1264 QGL2PaintEngineEx::QGL2PaintEngineEx()
   983 QGL2PaintEngineEx::QGL2PaintEngineEx()
  1272 
   991 
  1273 void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush)
   992 void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush)
  1274 {
   993 {
  1275     Q_D(QGL2PaintEngineEx);
   994     Q_D(QGL2PaintEngineEx);
  1276 
   995 
  1277     Qt::BrushStyle style = qbrush_style(brush);
   996     if (qbrush_style(brush) == Qt::NoBrush)
  1278     if (style == Qt::NoBrush)
       
  1279         return;
   997         return;
  1280     if (!d->inRenderText)
   998     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);
   999     d->setBrush(brush);
  1296     d->fill(path);
  1000     d->fill(path);
  1297 
       
  1298     if (doOffset) {
       
  1299         s->matrix = d->temporaryTransform;
       
  1300         d->matrixDirty = true;
       
  1301     }
       
  1302 }
  1001 }
  1303 
  1002 
  1304 extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
  1003 extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
  1305 
  1004 
  1306 
  1005 
  1307 void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
  1006 void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
  1308 {
  1007 {
  1309     Q_D(QGL2PaintEngineEx);
  1008     Q_D(QGL2PaintEngineEx);
  1310 
  1009 
  1311     Qt::PenStyle penStyle = qpen_style(pen);
       
  1312     const QBrush &penBrush = qpen_brush(pen);
  1010     const QBrush &penBrush = qpen_brush(pen);
  1313     if (penStyle == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush)
  1011     if (qpen_style(pen) == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush)
  1314         return;
  1012         return;
  1315 
  1013 
  1316     QOpenGL2PaintEngineState *s = state();
  1014     QOpenGL2PaintEngineState *s = state();
  1317     if (pen.isCosmetic() && !qt_scaleForTransform(s->transform(), 0)) {
  1015     if (pen.isCosmetic() && !qt_scaleForTransform(s->transform(), 0)) {
  1318         // QTriangulatingStroker class is not meant to support cosmetically sheared strokes.
  1016         // QTriangulatingStroker class is not meant to support cosmetically sheared strokes.
  1319         QPaintEngineEx::stroke(path, pen);
  1017         QPaintEngineEx::stroke(path, pen);
  1320         return;
  1018         return;
  1321     }
  1019     }
  1322 
  1020 
  1323     ensureActive();
  1021     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);
  1022     d->setBrush(penBrush);
  1335     d->transferMode(BrushDrawingMode);
  1023     d->stroke(path, pen);
       
  1024 }
       
  1025 
       
  1026 void QGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &pen)
       
  1027 {
       
  1028     const QOpenGL2PaintEngineState *s = q->state();
       
  1029     const bool newAddOffset = !(s->renderHints & QPainter::Antialiasing) && !multisamplingAlwaysEnabled;
       
  1030     if (addOffset != newAddOffset) {
       
  1031         addOffset = newAddOffset;
       
  1032         matrixDirty = true;
       
  1033     }
       
  1034 
       
  1035     if (snapToPixelGrid) {
       
  1036         snapToPixelGrid = false;
       
  1037         matrixDirty = true;
       
  1038     }
       
  1039 
       
  1040     const Qt::PenStyle penStyle = qpen_style(pen);
       
  1041     const QBrush &penBrush = qpen_brush(pen);
       
  1042     const bool opaque = penBrush.isOpaque() && s->opacity > 0.99;
       
  1043 
       
  1044     transferMode(BrushDrawingMode);
  1336 
  1045 
  1337     // updateMatrix() is responsible for setting the inverse scale on
  1046     // updateMatrix() is responsible for setting the inverse scale on
  1338     // the strokers, so we need to call it here and not wait for
  1047     // the strokers, so we need to call it here and not wait for
  1339     // prepareForDraw() down below.
  1048     // prepareForDraw() down below.
  1340     d->updateMatrix();
  1049     updateMatrix();
  1341 
  1050 
  1342     if (penStyle == Qt::SolidLine) {
  1051     if (penStyle == Qt::SolidLine) {
  1343         d->stroker.process(path, pen);
  1052         stroker.process(path, pen);
  1344 
  1053 
  1345     } else { // Some sort of dash
  1054     } else { // Some sort of dash
  1346         d->dasher.process(path, pen);
  1055         dasher.process(path, pen);
  1347 
  1056 
  1348         QVectorPath dashStroke(d->dasher.points(),
  1057         QVectorPath dashStroke(dasher.points(),
  1349                                d->dasher.elementCount(),
  1058                                dasher.elementCount(),
  1350                                d->dasher.elementTypes());
  1059                                dasher.elementTypes());
  1351         d->stroker.process(dashStroke, pen);
  1060         stroker.process(dashStroke, pen);
  1352     }
  1061     }
  1353 
       
  1354 
       
  1355     QGLContext *ctx = d->ctx;
       
  1356     Q_UNUSED(ctx);
       
  1357 
  1062 
  1358     if (opaque) {
  1063     if (opaque) {
  1359         d->prepareForDraw(opaque);
  1064         prepareForDraw(opaque);
  1360         glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
  1065         setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, stroker.vertices());
  1361         glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, d->stroker.vertices());
  1066         glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2);
  1362         glDrawArrays(GL_TRIANGLE_STRIP, 0, d->stroker.vertexCount() / 2);
       
  1363 
  1067 
  1364 //         QBrush b(Qt::green);
  1068 //         QBrush b(Qt::green);
  1365 //         d->setBrush(&b);
  1069 //         d->setBrush(&b);
  1366 //         d->prepareForDraw(true);
  1070 //         d->prepareForDraw(true);
  1367 //         glDrawArrays(GL_LINE_STRIP, 0, d->stroker.vertexCount() / 2);
  1071 //         glDrawArrays(GL_LINE_STRIP, 0, d->stroker.vertexCount() / 2);
  1368 
       
  1369         glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
       
  1370 
  1072 
  1371     } else {
  1073     } else {
  1372         qreal width = qpen_widthf(pen) / 2;
  1074         qreal width = qpen_widthf(pen) / 2;
  1373         if (width == 0)
  1075         if (width == 0)
  1374             width = 0.5;
  1076             width = 0.5;
  1375         qreal extra = pen.joinStyle() == Qt::MiterJoin
  1077         qreal extra = pen.joinStyle() == Qt::MiterJoin
  1376                       ? qMax(pen.miterLimit() * width, width)
  1078                       ? qMax(pen.miterLimit() * width, width)
  1377                       : width;
  1079                       : width;
  1378 
  1080 
  1379         if (pen.isCosmetic())
  1081         if (pen.isCosmetic())
  1380             extra = extra * d->inverseScale;
  1082             extra = extra * inverseScale;
  1381 
  1083 
  1382         QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra);
  1084         QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra);
  1383 
  1085 
  1384         d->fillStencilWithVertexArray(d->stroker.vertices(), d->stroker.vertexCount() / 2,
  1086         fillStencilWithVertexArray(stroker.vertices(), stroker.vertexCount() / 2,
  1385                                       0, 0, bounds, QGL2PaintEngineExPrivate::TriStripStrokeFillMode);
  1087                                       0, 0, bounds, QGL2PaintEngineExPrivate::TriStripStrokeFillMode);
  1386 
  1088 
  1387         glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
  1089         glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
  1388 
  1090 
  1389         // Pass when any bit is set, replace stencil value with 0
  1091         // Pass when any bit is set, replace stencil value with 0
  1390         glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
  1092         glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
  1391         d->prepareForDraw(false);
  1093         prepareForDraw(false);
  1392 
  1094 
  1393         // Stencil the brush onto the dest buffer
  1095         // Stencil the brush onto the dest buffer
  1394         d->composite(bounds);
  1096         composite(bounds);
  1395 
  1097 
  1396         glStencilMask(0);
  1098         glStencilMask(0);
  1397 
  1099 
  1398         d->updateClipScissorTest();
  1100         updateClipScissorTest();
  1399     }
       
  1400 
       
  1401     if (doOffset) {
       
  1402         s->matrix = d->temporaryTransform;
       
  1403         d->matrixDirty = true;
       
  1404     }
  1101     }
  1405 }
  1102 }
  1406 
  1103 
  1407 void QGL2PaintEngineEx::penChanged() { }
  1104 void QGL2PaintEngineEx::penChanged() { }
  1408 void QGL2PaintEngineEx::brushChanged() { }
  1105 void QGL2PaintEngineEx::brushChanged() { }
  1438     else
  1135     else
  1439         glDisable(GL_MULTISAMPLE);
  1136         glDisable(GL_MULTISAMPLE);
  1440 #endif
  1137 #endif
  1441 
  1138 
  1442     Q_D(QGL2PaintEngineEx);
  1139     Q_D(QGL2PaintEngineEx);
  1443     d->lastTexture = GLuint(-1);
  1140     d->lastTextureUsed = GLuint(-1);
  1444     d->brushTextureDirty = true;
  1141     d->brushTextureDirty = true;
  1445 //    qDebug("QGL2PaintEngineEx::renderHintsChanged() not implemented!");
  1142 //    qDebug("QGL2PaintEngineEx::renderHintsChanged() not implemented!");
  1446 }
  1143 }
  1447 
  1144 
  1448 void QGL2PaintEngineEx::transformChanged()
  1145 void QGL2PaintEngineEx::transformChanged()
  1516 
  1213 
  1517 void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem)
  1214 void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem)
  1518 {
  1215 {
  1519     Q_D(QGL2PaintEngineEx);
  1216     Q_D(QGL2PaintEngineEx);
  1520 
  1217 
  1521     if (!d->inRenderText)
  1218     ensureActive();
  1522         ensureActive();
       
  1523     QOpenGL2PaintEngineState *s = state();
  1219     QOpenGL2PaintEngineState *s = state();
  1524 
  1220 
  1525     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
  1221     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
  1526 
  1222 
  1527     QTransform::TransformationType txtype = s->matrix.type();
  1223     QTransform::TransformationType txtype = s->matrix.type();
  1536 
  1232 
  1537     QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0
  1233     QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0
  1538                                             ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat)
  1234                                             ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat)
  1539                                             : d->glyphCacheType;
  1235                                             : d->glyphCacheType;
  1540 
  1236 
  1541     if (d->inRenderText || txtype > QTransform::TxTranslate)
  1237 
  1542         glyphType = QFontEngineGlyphCache::Raster_A8;
  1238     if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
  1543 
  1239         if (d->device->alphaRequested() || txtype > QTransform::TxTranslate
  1544     if (glyphType == QFontEngineGlyphCache::Raster_RGBMask
  1240             || (state()->composition_mode != QPainter::CompositionMode_Source
  1545         && state()->composition_mode != QPainter::CompositionMode_Source
  1241             && state()->composition_mode != QPainter::CompositionMode_SourceOver))
  1546         && state()->composition_mode != QPainter::CompositionMode_SourceOver)
  1242         {
  1547     {
  1243             glyphType = QFontEngineGlyphCache::Raster_A8;
  1548         drawCached = false;
  1244         }
  1549     }
  1245     }
  1550 
  1246 
  1551     if (drawCached) {
  1247     if (drawCached) {
  1552         d->drawCachedGlyphs(p, glyphType, ti);
  1248         d->drawCachedGlyphs(p, glyphType, ti);
  1553         return;
  1249         return;
  1578     cache->populate(ti, glyphs, positions);
  1274     cache->populate(ti, glyphs, positions);
  1579 
  1275 
  1580     if (cache->width() == 0 || cache->height() == 0)
  1276     if (cache->width() == 0 || cache->height() == 0)
  1581         return;
  1277         return;
  1582 
  1278 
  1583     if (inRenderText)
       
  1584         transferMode(BrushDrawingMode);
       
  1585     transferMode(TextDrawingMode);
  1279     transferMode(TextDrawingMode);
  1586 
  1280 
  1587     int margin = cache->glyphMargin();
  1281     int margin = cache->glyphMargin();
  1588 
  1282 
  1589     GLfloat dx = 1.0 / cache->width();
  1283     GLfloat dx = 1.0 / cache->width();
  1590     GLfloat dy = 1.0 / cache->height();
  1284     GLfloat dy = 1.0 / cache->height();
  1591 
       
  1592     QGLPoint *oldVertexCoordinateDataPtr = vertexCoordinateArray.data();
       
  1593     QGLPoint *oldTextureCoordinateDataPtr = textureCoordinateArray.data();
       
  1594 
  1285 
  1595     vertexCoordinateArray.clear();
  1286     vertexCoordinateArray.clear();
  1596     textureCoordinateArray.clear();
  1287     textureCoordinateArray.clear();
  1597 
  1288 
  1598     for (int i=0; i<glyphs.size(); ++i) {
  1289     for (int i=0; i<glyphs.size(); ++i) {
  1602 
  1293 
  1603         vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h));
  1294         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));
  1295         textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy));
  1605     }
  1296     }
  1606 
  1297 
  1607     if (vertexCoordinateArray.data() != oldVertexCoordinateDataPtr)
  1298     setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data());
  1608         glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data());
  1299     setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data());
  1609     if (textureCoordinateArray.data() != oldTextureCoordinateDataPtr)
  1300 
  1610         glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data());
  1301     if (addOffset) {
       
  1302         addOffset = false;
       
  1303         matrixDirty = true;
       
  1304     }
       
  1305     if (!snapToPixelGrid) {
       
  1306         snapToPixelGrid = true;
       
  1307         matrixDirty = true;
       
  1308     }
  1611 
  1309 
  1612     QBrush pensBrush = q->state()->pen.brush();
  1310     QBrush pensBrush = q->state()->pen.brush();
  1613     setBrush(pensBrush);
  1311     setBrush(pensBrush);
  1614 
       
  1615     if (inRenderText)
       
  1616         prepareDepthRangeForRenderText();
       
  1617 
  1312 
  1618     if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
  1313     if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
  1619 
  1314 
  1620         // Subpixel antialiasing without gamma correction
  1315         // Subpixel antialiasing without gamma correction
  1621 
  1316 
  1697     glBindTexture(GL_TEXTURE_2D, cache->texture());
  1392     glBindTexture(GL_TEXTURE_2D, cache->texture());
  1698     updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
  1393     updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
  1699 
  1394 
  1700     shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
  1395     shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
  1701     glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size());
  1396     glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size());
  1702 
       
  1703     if (inRenderText)
       
  1704         restoreDepthRangeForRenderText();
       
  1705 }
  1397 }
  1706 
  1398 
  1707 void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints)
  1399 void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints)
  1708 {
  1400 {
       
  1401     Q_D(QGL2PaintEngineEx);
  1709     // Use fallback for extended composition modes.
  1402     // Use fallback for extended composition modes.
  1710     if (state()->composition_mode > QPainter::CompositionMode_Plus) {
  1403     if (state()->composition_mode > QPainter::CompositionMode_Plus) {
  1711         QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints);
  1404         QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints);
  1712         return;
  1405         return;
  1713     }
  1406     }
  1714 
  1407 
  1715     Q_D(QGL2PaintEngineEx);
  1408     ensureActive();
  1716 
  1409     d->drawPixmaps(drawingData, dataCount, pixmap, hints);
       
  1410 }
       
  1411 
       
  1412 
       
  1413 void QGL2PaintEngineExPrivate::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints)
       
  1414 {
  1717     GLfloat dx = 1.0f / pixmap.size().width();
  1415     GLfloat dx = 1.0f / pixmap.size().width();
  1718     GLfloat dy = 1.0f / pixmap.size().height();
  1416     GLfloat dy = 1.0f / pixmap.size().height();
  1719 
  1417 
  1720     d->vertexCoordinateArray.clear();
  1418     vertexCoordinateArray.clear();
  1721     d->textureCoordinateArray.clear();
  1419     textureCoordinateArray.clear();
  1722     d->opacityArray.reset();
  1420     opacityArray.reset();
       
  1421 
       
  1422     if (addOffset) {
       
  1423         addOffset = false;
       
  1424         matrixDirty = true;
       
  1425     }
       
  1426 
       
  1427     if (snapToPixelGrid) {
       
  1428         snapToPixelGrid = false;
       
  1429         matrixDirty = true;
       
  1430     }
  1723 
  1431 
  1724     bool allOpaque = true;
  1432     bool allOpaque = true;
  1725 
  1433 
  1726     for (int i = 0; i < dataCount; ++i) {
  1434     for (int i = 0; i < dataCount; ++i) {
  1727         qreal s = 0;
  1435         qreal s = 0;
  1734         qreal right = 0.5 * drawingData[i].scaleX * drawingData[i].source.width();
  1442         qreal right = 0.5 * drawingData[i].scaleX * drawingData[i].source.width();
  1735         qreal bottom = 0.5 * drawingData[i].scaleY * drawingData[i].source.height();
  1443         qreal bottom = 0.5 * drawingData[i].scaleY * drawingData[i].source.height();
  1736         QGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c);
  1444         QGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c);
  1737         QGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c);
  1445         QGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c);
  1738 
  1446 
  1739         d->vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y());
  1447         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());
  1448         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());
  1449         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());
  1450         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());
  1451         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());
  1452         vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y());
  1745 
  1453 
  1746         QGLRect src(drawingData[i].source.left() * dx, drawingData[i].source.top() * dy,
  1454         QGLRect src(drawingData[i].source.left() * dx, drawingData[i].source.top() * dy,
  1747                     drawingData[i].source.right() * dx, drawingData[i].source.bottom() * dy);
  1455                     drawingData[i].source.right() * dx, drawingData[i].source.bottom() * dy);
  1748 
  1456 
  1749         d->textureCoordinateArray.lineToArray(src.right, src.bottom);
  1457         textureCoordinateArray.lineToArray(src.right, src.bottom);
  1750         d->textureCoordinateArray.lineToArray(src.right, src.top);
  1458         textureCoordinateArray.lineToArray(src.right, src.top);
  1751         d->textureCoordinateArray.lineToArray(src.left, src.top);
  1459         textureCoordinateArray.lineToArray(src.left, src.top);
  1752         d->textureCoordinateArray.lineToArray(src.left, src.top);
  1460         textureCoordinateArray.lineToArray(src.left, src.top);
  1753         d->textureCoordinateArray.lineToArray(src.left, src.bottom);
  1461         textureCoordinateArray.lineToArray(src.left, src.bottom);
  1754         d->textureCoordinateArray.lineToArray(src.right, src.bottom);
  1462         textureCoordinateArray.lineToArray(src.right, src.bottom);
  1755 
  1463 
  1756         qreal opacity = drawingData[i].opacity * state()->opacity;
  1464         qreal opacity = drawingData[i].opacity * q->state()->opacity;
  1757         d->opacityArray << opacity << opacity << opacity << opacity << opacity << opacity;
  1465         opacityArray << opacity << opacity << opacity << opacity << opacity << opacity;
  1758         allOpaque &= (opacity >= 0.99f);
  1466         allOpaque &= (opacity >= 0.99f);
  1759     }
  1467     }
  1760 
  1468 
  1761     ensureActive();
       
  1762 
       
  1763     QGLContext *ctx = d->ctx;
       
  1764     glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
  1469     glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
  1765     QGLTexture *texture = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA,
  1470     QGLTexture *texture = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA,
  1766                                                      QGLContext::InternalBindOption
  1471                                                      QGLContext::InternalBindOption
  1767                                                      | QGLContext::CanFlipNativePixmapBindOption);
  1472                                                      | QGLContext::CanFlipNativePixmapBindOption);
  1768 
  1473 
  1769     if (texture->options & QGLContext::InvertedYBindOption) {
  1474     if (texture->options & QGLContext::InvertedYBindOption) {
  1770         // Flip texture y-coordinate.
  1475         // Flip texture y-coordinate.
  1771         QGLPoint *data = d->textureCoordinateArray.data();
  1476         QGLPoint *data = textureCoordinateArray.data();
  1772         for (int i = 0; i < 6 * dataCount; ++i)
  1477         for (int i = 0; i < 6 * dataCount; ++i)
  1773             data[i].y = 1 - data[i].y;
  1478             data[i].y = 1 - data[i].y;
  1774     }
  1479     }
  1775 
  1480 
  1776     d->transferMode(ImageArrayDrawingMode);
  1481     transferMode(ImageArrayDrawingMode);
  1777 
  1482 
  1778     bool isBitmap = pixmap.isQBitmap();
  1483     bool isBitmap = pixmap.isQBitmap();
  1779     bool isOpaque = !isBitmap && (!pixmap.hasAlphaChannel() || (hints & QDrawPixmaps::OpaqueHint)) && allOpaque;
  1484     bool isOpaque = !isBitmap && (!pixmap.hasAlphaChannel() || (hints & QDrawPixmaps::OpaqueHint)) && allOpaque;
  1780 
  1485 
  1781     d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
  1486     updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
  1782                            state()->renderHints & QPainter::SmoothPixmapTransform, texture->id);
  1487                            q->state()->renderHints & QPainter::SmoothPixmapTransform, texture->id);
  1783 
  1488 
  1784     // Setup for texture drawing
  1489     // Setup for texture drawing
  1785     d->shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc);
  1490     currentBrush = noBrush;
  1786     if (d->prepareForDraw(isOpaque))
  1491     shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc);
  1787         d->shaderManager->currentProgram()->setUniformValue(d->location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
  1492     if (prepareForDraw(isOpaque))
       
  1493         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
  1788 
  1494 
  1789     if (isBitmap) {
  1495     if (isBitmap) {
  1790         QColor col = qt_premultiplyColor(state()->pen.color(), (GLfloat)state()->opacity);
  1496         QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity);
  1791         d->shaderManager->currentProgram()->setUniformValue(d->location(QGLEngineShaderManager::PatternColor), col);
  1497         shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
  1792     }
  1498     }
  1793 
  1499 
  1794     glDrawArrays(GL_TRIANGLES, 0, 6 * dataCount);
  1500     glDrawArrays(GL_TRIANGLES, 0, 6 * dataCount);
  1795 }
  1501 }
  1796 
  1502 
  1818     d->brushUniformsDirty = true;
  1524     d->brushUniformsDirty = true;
  1819     d->matrixDirty = true;
  1525     d->matrixDirty = true;
  1820     d->compositionModeDirty = true;
  1526     d->compositionModeDirty = true;
  1821     d->opacityUniformDirty = true;
  1527     d->opacityUniformDirty = true;
  1822     d->needsSync = true;
  1528     d->needsSync = true;
  1823     d->use_system_clip = !systemClip().isEmpty();
  1529     d->useSystemClip = !systemClip().isEmpty();
  1824     d->currentBrush = QBrush();
  1530     d->currentBrush = QBrush();
  1825 
  1531 
  1826     d->dirtyStencilRegion = QRect(0, 0, d->width, d->height);
  1532     d->dirtyStencilRegion = QRect(0, 0, d->width, d->height);
  1827     d->stencilClean = true;
  1533     d->stencilClean = true;
  1828 
  1534 
  1838     Q_UNUSED(success);
  1544     Q_UNUSED(success);
  1839 #endif
  1545 #endif
  1840 
  1546 
  1841     d->shaderManager = new QGLEngineShaderManager(d->ctx);
  1547     d->shaderManager = new QGLEngineShaderManager(d->ctx);
  1842 
  1548 
  1843     if (!d->inRenderText) {
  1549     glDisable(GL_STENCIL_TEST);
  1844         glDisable(GL_STENCIL_TEST);
  1550     glDisable(GL_DEPTH_TEST);
  1845         glDisable(GL_DEPTH_TEST);
  1551     glDisable(GL_SCISSOR_TEST);
  1846         glDisable(GL_SCISSOR_TEST);
       
  1847     }
       
  1848 
  1552 
  1849 #if !defined(QT_OPENGL_ES_2)
  1553 #if !defined(QT_OPENGL_ES_2)
  1850     glDisable(GL_MULTISAMPLE);
  1554     glDisable(GL_MULTISAMPLE);
  1851 #endif
  1555 #endif
  1852 
  1556 
  1919     if (d->needsSync) {
  1623     if (d->needsSync) {
  1920         d->transferMode(BrushDrawingMode);
  1624         d->transferMode(BrushDrawingMode);
  1921         glViewport(0, 0, d->width, d->height);
  1625         glViewport(0, 0, d->width, d->height);
  1922         d->needsSync = false;
  1626         d->needsSync = false;
  1923         d->shaderManager->setDirty();
  1627         d->shaderManager->setDirty();
       
  1628         d->ctx->d_func()->syncGlState();
       
  1629         for (int i = 0; i < 3; ++i)
       
  1630             d->vertexAttribPointers[i] = (GLfloat*)-1; // Assume the pointers are clobbered
  1924         setState(state());
  1631         setState(state());
  1925     }
  1632     }
  1926 }
  1633 }
  1927 
  1634 
  1928 void QGL2PaintEngineExPrivate::updateClipScissorTest()
  1635 void QGL2PaintEngineExPrivate::updateClipScissorTest()
  1939 #ifdef QT_GL_NO_SCISSOR_TEST
  1646 #ifdef QT_GL_NO_SCISSOR_TEST
  1940     currentScissorBounds = QRect(0, 0, width, height);
  1647     currentScissorBounds = QRect(0, 0, width, height);
  1941 #else
  1648 #else
  1942     QRect bounds = q->state()->rectangleClip;
  1649     QRect bounds = q->state()->rectangleClip;
  1943     if (!q->state()->clipEnabled) {
  1650     if (!q->state()->clipEnabled) {
  1944         if (use_system_clip)
  1651         if (useSystemClip)
  1945             bounds = systemClip.boundingRect();
  1652             bounds = systemClip.boundingRect();
  1946         else
  1653         else
  1947             bounds = QRect(0, 0, width, height);
  1654             bounds = QRect(0, 0, width, height);
  1948     } else {
  1655     } else {
  1949         if (use_system_clip)
  1656         if (useSystemClip)
  1950             bounds = bounds.intersected(systemClip.boundingRect());
  1657             bounds = bounds.intersected(systemClip.boundingRect());
  1951         else
  1658         else
  1952             bounds = bounds.intersected(QRect(0, 0, width, height));
  1659             bounds = bounds.intersected(QRect(0, 0, width, height));
  1953     }
  1660     }
  1954 
  1661 
  1999 
  1706 
  2000 void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint value)
  1707 void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint value)
  2001 {
  1708 {
  2002     transferMode(BrushDrawingMode);
  1709     transferMode(BrushDrawingMode);
  2003 
  1710 
       
  1711     if (addOffset) {
       
  1712         addOffset = false;
       
  1713         matrixDirty = true;
       
  1714     }
       
  1715     if (snapToPixelGrid) {
       
  1716         snapToPixelGrid = false;
       
  1717         matrixDirty = true;
       
  1718     }
       
  1719 
  2004     if (matrixDirty)
  1720     if (matrixDirty)
  2005         updateMatrix();
  1721         updateMatrix();
  2006 
  1722 
  2007     stencilClean = false;
  1723     stencilClean = false;
  2008 
  1724 
  2098 
  1814 
  2099     const QRect pathRect = state()->matrix.mapRect(path.controlPointRect()).toAlignedRect();
  1815     const QRect pathRect = state()->matrix.mapRect(path.controlPointRect()).toAlignedRect();
  2100 
  1816 
  2101     switch (op) {
  1817     switch (op) {
  2102     case Qt::NoClip:
  1818     case Qt::NoClip:
  2103         if (d->use_system_clip) {
  1819         if (d->useSystemClip) {
  2104             state()->clipTestEnabled = true;
  1820             state()->clipTestEnabled = true;
  2105             state()->currentClip = 1;
  1821             state()->currentClip = 1;
  2106         } else {
  1822         } else {
  2107             state()->clipTestEnabled = false;
  1823             state()->clipTestEnabled = false;
  2108         }
  1824         }
  2170     Q_Q(QGL2PaintEngineEx);
  1886     Q_Q(QGL2PaintEngineEx);
  2171 
  1887 
  2172     q->state()->clipChanged = true;
  1888     q->state()->clipChanged = true;
  2173 
  1889 
  2174     if (systemClip.isEmpty()) {
  1890     if (systemClip.isEmpty()) {
  2175         use_system_clip = false;
  1891         useSystemClip = false;
  2176     } else {
  1892     } else {
  2177         if (q->paintDevice()->devType() == QInternal::Widget && currentClipWidget) {
  1893         if (q->paintDevice()->devType() == QInternal::Widget && currentClipWidget) {
  2178             QWidgetPrivate *widgetPrivate = qt_widget_private(currentClipWidget->window());
  1894             QWidgetPrivate *widgetPrivate = qt_widget_private(currentClipWidget->window());
  2179             use_system_clip = widgetPrivate->extra && widgetPrivate->extra->inRenderWithPainter;
  1895             useSystemClip = widgetPrivate->extra && widgetPrivate->extra->inRenderWithPainter;
  2180         } else {
  1896         } else {
  2181             use_system_clip = true;
  1897             useSystemClip = true;
  2182         }
  1898         }
  2183     }
  1899     }
  2184 
  1900 
  2185     q->state()->clipTestEnabled = false;
  1901     q->state()->clipTestEnabled = false;
  2186     q->state()->needsClipBufferClear = true;
  1902     q->state()->needsClipBufferClear = true;
  2187 
  1903 
  2188     q->state()->currentClip = 1;
  1904     q->state()->currentClip = 1;
  2189     maxClip = 1;
  1905     maxClip = 1;
  2190 
  1906 
  2191     q->state()->rectangleClip = use_system_clip ? systemClip.boundingRect() : QRect(0, 0, width, height);
  1907     q->state()->rectangleClip = useSystemClip ? systemClip.boundingRect() : QRect(0, 0, width, height);
  2192     updateClipScissorTest();
  1908     updateClipScissorTest();
  2193 
  1909 
  2194     if (systemClip.rectCount() == 1) {
  1910     if (systemClip.rectCount() == 1) {
  2195         if (systemClip.boundingRect() == QRect(0, 0, width, height))
  1911         if (systemClip.boundingRect() == QRect(0, 0, width, height))
  2196             use_system_clip = false;
  1912             useSystemClip = false;
  2197 #ifndef QT_GL_NO_SCISSOR_TEST
  1913 #ifndef QT_GL_NO_SCISSOR_TEST
  2198         // scissoring takes care of the system clip
  1914         // scissoring takes care of the system clip
  2199         return;
  1915         return;
  2200 #endif
  1916 #endif
  2201     }
  1917     }
  2202 
  1918 
  2203     if (use_system_clip) {
  1919     if (useSystemClip) {
  2204         clearClip(0);
  1920         clearClip(0);
  2205 
  1921 
  2206         QPainterPath path;
  1922         QPainterPath path;
  2207         path.addRegion(systemClip);
  1923         path.addRegion(systemClip);
  2208 
  1924 
  2235     // Setting the state as part of a restore().
  1951     // Setting the state as part of a restore().
  2236 
  1952 
  2237     if (old_state == s || old_state->renderHintsChanged)
  1953     if (old_state == s || old_state->renderHintsChanged)
  2238         renderHintsChanged();
  1954         renderHintsChanged();
  2239 
  1955 
  2240     if (old_state == s || old_state->matrixChanged) {
  1956     if (old_state == s || old_state->matrixChanged)
  2241         d->matrixDirty = true;
  1957         d->matrixDirty = true;
  2242         d->simpleShaderMatrixUniformDirty = true;
       
  2243         d->shaderMatrixUniformDirty = true;
       
  2244     }
       
  2245 
  1958 
  2246     if (old_state == s || old_state->compositionModeChanged)
  1959     if (old_state == s || old_state->compositionModeChanged)
  2247         d->compositionModeDirty = true;
  1960         d->compositionModeDirty = true;
  2248 
  1961 
  2249     if (old_state == s || old_state->opacityChanged)
  1962     if (old_state == s || old_state->opacityChanged)
  2277     s->clipChanged = false;
  1990     s->clipChanged = false;
  2278 
  1991 
  2279     return s;
  1992     return s;
  2280 }
  1993 }
  2281 
  1994 
  2282 void QGL2PaintEngineEx::setRenderTextActive(bool active)
       
  2283 {
       
  2284     Q_D(QGL2PaintEngineEx);
       
  2285     d->inRenderText = active;
       
  2286 }
       
  2287 
       
  2288 QOpenGL2PaintEngineState::QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other)
  1995 QOpenGL2PaintEngineState::QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other)
  2289     : QPainterState(other)
  1996     : QPainterState(other)
  2290 {
  1997 {
  2291     isNew = true;
  1998     isNew = true;
  2292     needsClipBufferClear = other.needsClipBufferClear;
  1999     needsClipBufferClear = other.needsClipBufferClear;
  2307 QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState()
  2014 QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState()
  2308 {
  2015 {
  2309 }
  2016 }
  2310 
  2017 
  2311 QT_END_NAMESPACE
  2018 QT_END_NAMESPACE
  2312 
       
  2313 #include "qpaintengineex_opengl2.moc"