Changeset 561 for trunk/src/opengl/gl2paintengineex
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 5 deleted
- 7 edited
- 7 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtOpenGL module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 44 44 #include <private/qbezier_p.h> 45 45 46 QT_BEGIN_NAMESPACE 47 46 48 void QGL2PEXVertexArray::clear() 47 49 { 48 50 vertexArray.reset(); 49 vertexArrayStops. clear();51 vertexArrayStops.reset(); 50 52 boundingRectDirty = true; 51 53 } … … 60 62 } 61 63 62 void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseScale) 64 void QGL2PEXVertexArray::addRect(const QRectF &rect) 65 { 66 vertexArray << rect.topLeft() << rect.topRight() << rect.bottomRight() 67 << rect.bottomRight() << rect.bottomLeft() << rect.topLeft(); 68 } 69 70 void QGL2PEXVertexArray::addClosingLine(int index) 71 { 72 if (QPointF(vertexArray.at(index)) != QPointF(vertexArray.last())) 73 vertexArray.add(vertexArray.at(index)); 74 } 75 76 void QGL2PEXVertexArray::addCentroid(const QVectorPath &path, int subPathIndex) 77 { 78 const QPointF *const points = reinterpret_cast<const QPointF *>(path.points()); 79 const QPainterPath::ElementType *const elements = path.elements(); 80 81 QPointF sum = points[subPathIndex]; 82 int count = 1; 83 84 for (int i = subPathIndex + 1; i < path.elementCount() && (!elements || elements[i] != QPainterPath::MoveToElement); ++i) { 85 sum += points[i]; 86 ++count; 87 } 88 89 const QPointF centroid = sum / qreal(count); 90 vertexArray.add(centroid); 91 } 92 93 void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline) 63 94 { 64 95 const QPointF* const points = reinterpret_cast<const QPointF*>(path.points()); … … 71 102 } 72 103 104 if (!outline && !path.isConvex()) 105 addCentroid(path, 0); 106 107 int lastMoveTo = vertexArray.size(); 73 108 vertexArray.add(points[0]); // The first element is always a moveTo 74 109 … … 86 121 87 122 for (int i=1; i<path.elementCount(); ++i) { 88 const QPainterPath::ElementType elementType = elements[i]; 89 switch (elementType) { 123 switch (elements[i]) { 90 124 case QPainterPath::MoveToElement: 125 if (!outline) 126 addClosingLine(lastMoveTo); 91 127 // qDebug("element[%d] is a MoveToElement", i); 92 vertexArrayStops.append(vertexArray.size()); 93 vertexArray.add(points[i]); // Add the moveTo as a new vertex 128 vertexArrayStops.add(vertexArray.size()); 129 if (!outline) { 130 if (!path.isConvex()) addCentroid(path, i); 131 lastMoveTo = vertexArray.size(); 132 } 133 lineToArray(points[i].x(), points[i].y()); // Add the moveTo as a new vertex 94 134 break; 95 135 case QPainterPath::LineToElement: … … 97 137 lineToArray(points[i].x(), points[i].y()); 98 138 break; 99 case QPainterPath::CurveToElement: 100 // qDebug("element[%d] is a CurveToElement", i); 101 curveToArray(points[i], points[i+1], points[i+2], curveInverseScale); 102 i+=2; 103 break; 139 case QPainterPath::CurveToElement: { 140 QBezier b = QBezier::fromPoints(*(((const QPointF *) points) + i - 1), 141 points[i], 142 points[i+1], 143 points[i+2]); 144 QRectF bounds = b.bounds(); 145 // threshold based on same algorithm as in qtriangulatingstroker.cpp 146 int threshold = qMin<float>(64, qMax(bounds.width(), bounds.height()) * 3.14f / (curveInverseScale * 6)); 147 if (threshold < 3) threshold = 3; 148 qreal one_over_threshold_minus_1 = 1.f / (threshold - 1); 149 for (int t=0; t<threshold; ++t) { 150 QPointF pt = b.pointAt(t * one_over_threshold_minus_1); 151 lineToArray(pt.x(), pt.y()); 152 } 153 i += 2; 154 break; } 104 155 default: 105 156 break; … … 108 159 } while (0); 109 160 110 vertexArrayStops.append(vertexArray.size()); 161 if (!outline) 162 addClosingLine(lastMoveTo); 163 vertexArrayStops.add(vertexArray.size()); 111 164 } 112 165 … … 125 178 } 126 179 127 void QGL2PEXVertexArray::curveToArray(const QGLPoint &cp1, const QGLPoint &cp2, const QGLPoint &ep, GLfloat inverseScale) 128 { 129 qreal inverseScaleHalf = inverseScale / 2; 130 131 QBezier beziers[32]; 132 beziers[0] = QBezier::fromPoints(vertexArray.last(), cp1, cp2, ep); 133 QBezier *b = beziers; 134 while (b >= beziers) { 135 // check if we can pop the top bezier curve from the stack 136 qreal l = qAbs(b->x4 - b->x1) + qAbs(b->y4 - b->y1); 137 qreal d; 138 if (l > inverseScale) { 139 d = qAbs( (b->x4 - b->x1)*(b->y1 - b->y2) - (b->y4 - b->y1)*(b->x1 - b->x2) ) 140 + qAbs( (b->x4 - b->x1)*(b->y1 - b->y3) - (b->y4 - b->y1)*(b->x1 - b->x3) ); 141 d /= l; 142 } else { 143 d = qAbs(b->x1 - b->x2) + qAbs(b->y1 - b->y2) + 144 qAbs(b->x1 - b->x3) + qAbs(b->y1 - b->y3); 145 } 146 if (d < inverseScaleHalf || b == beziers + 31) { 147 // good enough, we pop it off and add the endpoint 148 lineToArray(b->x4, b->y4); 149 --b; 150 } else { 151 // split, second half of the polygon goes lower into the stack 152 b->split(b+1, b); 153 ++b; 154 } 155 } 156 } 180 QT_END_NAMESPACE -
trunk/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtOpenGL module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 51 51 // 52 52 53 #ifndef QGL2PEXVERTEXARRAY_P_H 54 #define QGL2PEXVERTEXARRAY_P_H 55 53 56 #include <QRectF> 54 57 … … 56 59 #include <private/qvectorpath_p.h> 57 60 #include <private/qgl_p.h> 61 62 QT_BEGIN_NAMESPACE 58 63 59 64 class QGLPoint … … 63 68 x(new_x), y(new_y) {}; 64 69 65 QGLPoint( QPointFp) :70 QGLPoint(const QPointF &p) : 66 71 x(p.x()), y(p.y()) {}; 67 72 … … 78 83 struct QGLRect 79 84 { 80 QGLRect( QRectFr)85 QGLRect(const QRectF &r) 81 86 : left(r.left()), top(r.top()), right(r.right()), bottom(r.bottom()) {} 82 87 … … 99 104 boundingRectDirty(true) {} 100 105 101 void addPath(const QVectorPath &path, GLfloat curveInverseScale); 106 void addRect(const QRectF &rect); 107 void addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline = true); 102 108 void clear(); 103 109 104 110 QGLPoint* data() {return vertexArray.data();} 105 QVector<int>& stops() {return vertexArrayStops;} 111 int *stops() const { return vertexArrayStops.data(); } 112 int stopCount() const { return vertexArrayStops.size(); } 106 113 QGLRect boundingRect() const; 114 115 int vertexCount() const { return vertexArray.size(); } 107 116 108 117 void lineToArray(const GLfloat x, const GLfloat y); … … 110 119 private: 111 120 QDataBuffer<QGLPoint> vertexArray; 112 Q Vector<int>vertexArrayStops;121 QDataBuffer<int> vertexArrayStops; 113 122 114 123 GLfloat maxX; … … 117 126 GLfloat minY; 118 127 bool boundingRectDirty; 128 void addClosingLine(int index); 129 void addCentroid(const QVectorPath &path, int subPathIndex); 130 }; 119 131 120 inline void curveToArray(const QGLPoint &cp1, const QGLPoint &cp2, const QGLPoint &ep, GLfloat inverseScale); 121 }; 132 QT_END_NAMESPACE 133 134 #endif -
trunk/src/opengl/gl2paintengineex/qglgradientcache.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtOpenGL module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 45 45 #include "qglgradientcache_p.h" 46 46 47 void QGLGradientCache::cleanCache() { 47 QT_BEGIN_NAMESPACE 48 49 static void QGL2GradientCache_free(void *ptr) 50 { 51 delete reinterpret_cast<QGL2GradientCache *>(ptr); 52 } 53 54 Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_gradient_caches, (QGL2GradientCache_free)) 55 56 QGL2GradientCache *QGL2GradientCache::cacheForContext(const QGLContext *context) 57 { 58 QGL2GradientCache *p = reinterpret_cast<QGL2GradientCache *>(qt_gradient_caches()->value(context)); 59 if (!p) { 60 QGLShareContextScope scope(context); 61 p = new QGL2GradientCache; 62 qt_gradient_caches()->insert(context, p); 63 } 64 return p; 65 } 66 67 void QGL2GradientCache::cleanCache() { 48 68 QGLGradientColorTableHash::const_iterator it = cache.constBegin(); 49 69 for (; it != cache.constEnd(); ++it) { … … 54 74 } 55 75 56 GLuint QGL GradientCache::getBuffer(const QGradient &gradient, qreal opacity, const QGLContext *ctx)76 GLuint QGL2GradientCache::getBuffer(const QGradient &gradient, qreal opacity) 57 77 { 58 if (buffer_ctx && !qgl_share_reg()->checkSharing(buffer_ctx, ctx))59 cleanCache();60 61 buffer_ctx = ctx;62 63 78 quint64 hash_val = 0; 64 79 … … 85 100 86 101 87 GLuint QGL GradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity)102 GLuint QGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity) 88 103 { 89 104 if (cache.size() == maxCacheSize()) { … … 110 125 111 126 112 // GL's expects pixels in RGBA , bin-endian (ABGR on x86).113 // Qt stores in ARGB using whateverbyte-order the mancine uses.127 // GL's expects pixels in RGBA (when using GL_RGBA), bin-endian (ABGR on x86). 128 // Qt always stores in ARGB reguardless of the byte-order the mancine uses. 114 129 static inline uint qtToGlColor(uint c) 115 130 { 116 131 uint o; 117 132 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN 118 o = c & 0xFF00FF00; // alpha & green already in the right place 119 o |= (c >> 16) & 0x000000FF; // red 120 o |= (c << 16) & 0x00FF0000; // blue 121 133 o = (c & 0xff00ff00) // alpha & green already in the right place 134 | ((c >> 16) & 0x000000ff) // red 135 | ((c << 16) & 0x00ff0000); // blue 122 136 #else //Q_BIG_ENDIAN 123 o = c & 0x00FF00FF; // alpha & green already in the right place 124 o |= (c << 16) & 0xFF000000; // red 125 o |= (c >> 16) & 0x0000FF00; // blue 126 #error big endian not tested with QGLGraphicsContext 137 o = (c << 8) 138 | ((c >> 24) & 0x000000ff); 127 139 #endif // Q_BYTE_ORDER 128 140 return o; … … 130 142 131 143 //TODO: Let GL generate the texture using an FBO 132 void QGL GradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const144 void QGL2GradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const 133 145 { 134 146 int pos = 0; … … 137 149 138 150 for (int i = 0; i < s.size(); ++i) 139 colors[i] = s[i].second.rgba(); // Qt LIES! It returns ARGB 151 colors[i] = s[i].second.rgba(); // Qt LIES! It returns ARGB (on little-endian AND on big-endian) 140 152 141 153 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation); … … 184 196 colorTable[size-1] = last_color; 185 197 } 198 199 QT_END_NAMESPACE -
trunk/src/opengl/gl2paintengineex/qglgradientcache_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtOpenGL module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 53 53 #include <QMultiHash> 54 54 #include <QObject> 55 #include <QtOpenGL> 55 #include <QtOpenGL/QtOpenGL> 56 #include <private/qgl_p.h> 56 57 57 class QGLGradientCache : public QObject 58 QT_BEGIN_NAMESPACE 59 60 class QGL2GradientCache 58 61 { 59 Q_OBJECT60 62 struct CacheInfo 61 63 { … … 72 74 73 75 public: 74 QGLGradientCache() : QObject(), buffer_ctx(0) 75 { 76 /* 77 connect(QGLSignalProxy::instance(), 78 SIGNAL(aboutToDestroyContext(const QGLContext *)), 79 SLOT(cleanupGLContextRefs(const QGLContext *))); 80 */ 81 } 76 static QGL2GradientCache *cacheForContext(const QGLContext *context); 82 77 83 GLuint getBuffer(const QGradient &gradient, qreal opacity, const QGLContext *ctx); 78 QGL2GradientCache() { } 79 ~QGL2GradientCache() {cleanCache();} 80 81 GLuint getBuffer(const QGradient &gradient, qreal opacity); 84 82 inline int paletteSize() const { return 1024; } 85 83 … … 94 92 95 93 QGLGradientColorTableHash cache; 96 const QGLContext *buffer_ctx;97 98 public slots:99 void cleanupGLContextRefs(const QGLContext *context) {100 if (context == buffer_ctx) {101 cleanCache();102 buffer_ctx = 0;103 }104 }105 94 }; 106 95 96 QT_END_NAMESPACE 107 97 108 -
trunk/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtOpenGL module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 63 63 */ 64 64 65 // #define QT_OPENGL_CACHE_AS_VBOS 65 66 66 67 #include "qpaintengineex_opengl2_p.h" … … 76 77 #include <private/qfontengine_p.h> 77 78 #include <private/qtextureglyphcache_p.h> 79 #include <private/qpixmapdata_gl_p.h> 80 #include <private/qdatabuffer_p.h> 78 81 79 82 #include "qglgradientcache_p.h" 80 #include "qgl pexshadermanager_p.h"83 #include "qglengineshadermanager_p.h" 81 84 #include "qgl2pexvertexarray_p.h" 82 85 83 84 extern QImage qt_imageForBrush(int brushStyle, bool invert); //in qbrush.cpp 85 86 #include "qtriangulatingstroker_p.h" 86 87 87 88 #include <QDebug> 88 89 89 90 static const GLuint QT_VERTEX_COORDS_ATTR = 0; 91 static const GLuint QT_TEXTURE_COORDS_ATTR = 1; 92 static const GLuint QT_BRUSH_TEXTURE_UNIT = 0; 93 94 class QGL2PaintEngineExPrivate : public QPaintEngineExPrivate 95 { 96 Q_DECLARE_PUBLIC(QGL2PaintEngineEx) 90 QT_BEGIN_NAMESPACE 91 92 //#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 97 107 public: 98 QGL2PaintEngineExPrivate(QGL2PaintEngineEx *q_ptr) : 99 q(q_ptr), 100 width(0), height(0), 101 ctx(0), 102 currentBrush( &(q->state()->brush) ), 103 inverseScale(1), 104 shaderManager(0) 105 { } 106 107 ~QGL2PaintEngineExPrivate(); 108 109 void updateBrushTexture(); 110 void updateBrushUniforms(); 111 void updateMatrix(); 112 void updateCompositionMode(); 113 void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform); 114 115 void setBrush(const QBrush* brush); 116 117 void drawTexture(const QGLRect& dest, const QGLRect& src, int txtWidth, int txtHeight); 118 119 void fill(const QVectorPath &path); 120 void drawOutline(const QVectorPath& path); 121 122 void drawVertexArrays(QGL2PEXVertexArray& vertexArray, GLenum primitive); 123 // ^ draws whatever is in the vertex array 124 void composite(const QGLRect& boundingRect); 125 // ^ Composites the bounding rect onto dest buffer 126 void fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill); 127 // ^ Calls drawVertexArrays to render into stencil buffer 128 void cleanStencilBuffer(const QGLRect& area); 129 130 void prepareForDraw(); 131 132 inline void useSimpleShader(); 133 inline QColor premultiplyColor(QColor c, GLfloat opacity); 134 135 QGL2PaintEngineEx* q; 136 137 //### Move into QGLDrawable 138 int width, height; 139 QGLContext* ctx; 140 141 // Dirty flags 142 bool matrixDirty; // Implies matrix uniforms are also dirty 143 bool compositionModeDirty; 144 bool brushTextureDirty; 145 bool brushUniformsDirty; 146 bool simpleShaderMatrixUniformDirty; 147 bool brushShaderMatrixUniformDirty; 148 bool imageShaderMatrixUniformDirty; 149 bool textShaderMatrixUniformDirty; 150 bool stencilBuferDirty; 151 152 const QBrush* currentBrush; // May not be the state's brush! 153 154 GLfloat inverseScale; 155 156 QGL2PEXVertexArray pathVertexArray; 157 158 GLfloat pmvMatrix[4][4]; 159 160 QGLPEXShaderManager* shaderManager; 161 162 // Clipping & state stuff stolen from QOpenGLPaintEngine: 163 void updateDepthClip(); 164 uint use_system_clip : 1; 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; 165 154 }; 166 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 glDisable(GL_STENCIL_TEST); 231 glDisable(GL_DEPTH_TEST); 232 glDisable(GL_SCISSOR_TEST); 233 glDisable(GL_BLEND); 234 235 glViewport(0, 0, oldWidth, oldHeight); 236 237 float vertexCoordinateArray[] = { -1, -1, 1, -1, 1, 1, -1, 1 }; 238 float textureCoordinateArray[] = { 0, 0, 1, 0, 1, 1, 0, 1 }; 239 240 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 241 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); 242 243 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray); 244 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray); 245 246 pex->shaderManager->blitProgram()->bind(); 247 pex->shaderManager->blitProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT); 248 pex->shaderManager->setDirty(); 249 250 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 251 252 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 253 glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); 254 255 glBindTexture(GL_TEXTURE_2D, m_texture); 256 257 #ifdef QT_OPENGL_ES_2 258 QDataBuffer<uchar> buffer(4*oldWidth*oldHeight); 259 buffer.resize(4*oldWidth*oldHeight); 260 glReadPixels(0, 0, oldWidth, oldHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data()); 261 262 // do an in-place conversion from GL_RGBA to GL_ALPHA 263 for (int i=0; i<oldWidth*oldHeight; ++i) 264 buffer.data()[i] = buffer.at(4*i + 3); 265 266 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, 267 GL_ALPHA, GL_UNSIGNED_BYTE, buffer.data()); 268 #else 269 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight); 270 #endif 271 272 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 273 GL_RENDERBUFFER_EXT, 0); 274 glDeleteTextures(1, &tmp_texture); 275 glDeleteTextures(1, &oldTexture); 276 277 glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); 278 279 glViewport(0, 0, pex->width, pex->height); 280 pex->updateClipScissorTest(); 281 } 282 283 void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph) 284 { 285 QImage mask = textureMapForGlyph(glyph); 286 const int maskWidth = mask.width(); 287 const int maskHeight = mask.height(); 288 289 if (mask.format() == QImage::Format_Mono) { 290 mask = mask.convertToFormat(QImage::Format_Indexed8); 291 for (int y = 0; y < maskHeight; ++y) { 292 uchar *src = (uchar *) mask.scanLine(y); 293 for (int x = 0; x < maskWidth; ++x) 294 src[x] = -src[x]; // convert 0 and 1 into 0 and 255 295 } 296 } 297 298 299 glBindTexture(GL_TEXTURE_2D, m_texture); 300 if (mask.format() == QImage::Format_RGB32) { 301 glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits()); 302 } else { 303 #ifdef QT_OPENGL_ES2 304 glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_ALPHA, GL_UNSIGNED_BYTE, mask.bits()); 305 #else 306 // glTexSubImage2D() might cause some garbage to appear in the texture if the mask width is 307 // not a multiple of four bytes. The bug appeared on a computer with 32-bit Windows Vista 308 // and nVidia GeForce 8500GT. GL_UNPACK_ALIGNMENT is set to four bytes, 'mask' has a 309 // multiple of four bytes per line, and most of the glyph shows up correctly in the 310 // texture, which makes me think that this is a driver bug. 311 // One workaround is to make sure the mask width is a multiple of four bytes, for instance 312 // by converting it to a format with four bytes per pixel. Another is to copy one line at a 313 // time. 314 315 for (int i = 0; i < maskHeight; ++i) 316 glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, maskWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, mask.scanLine(i)); 317 #endif 318 } 319 } 320 321 int QGLTextureGlyphCache::glyphMargin() const 322 { 323 #if defined(Q_WS_MAC) 324 return 2; 325 #elif defined (Q_WS_X11) 326 return 0; 327 #else 328 return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0; 329 #endif 330 } 331 332 extern QImage qt_imageForBrush(int brushStyle, bool invert); 167 333 168 334 ////////////////////////////////// Private Methods ////////////////////////////////////////// … … 170 336 QGL2PaintEngineExPrivate::~QGL2PaintEngineExPrivate() 171 337 { 172 if (shaderManager) { 173 delete shaderManager; 174 shaderManager = 0; 175 } 176 } 177 178 void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform) 179 { 180 glActiveTexture(QT_BRUSH_TEXTURE_UNIT); 338 delete shaderManager; 339 340 while (pathCaches.size()) { 341 QVectorPath::CacheEntry *e = *(pathCaches.constBegin()); 342 e->cleanup(e->engine, e->data); 343 e->data = 0; 344 e->engine = 0; 345 } 346 } 347 348 void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id) 349 { 350 // glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); //### Is it always this texture unit? 351 if (id != GLuint(-1) && id == lastTextureUsed) 352 return; 353 354 lastTextureUsed = id; 181 355 182 356 if (smoothPixmapTransform) { … … 192 366 193 367 194 QColor QGL2PaintEngineExPrivate::premultiplyColor(QColor c, GLfloat opacity) 195 { 196 uint alpha = qRound(c.alpha() * opacity); 197 return QColor ( ((c.red() * alpha + 128) >> 8), 198 ((c.green() * alpha + 128) >> 8), 199 ((c.blue() * alpha + 128) >> 8), 200 alpha); 201 } 202 203 204 void QGL2PaintEngineExPrivate::setBrush(const QBrush* brush) 205 { 368 inline QColor qt_premultiplyColor(QColor c, GLfloat opacity) 369 { 370 qreal alpha = c.alphaF() * opacity; 371 c.setAlphaF(alpha); 372 c.setRedF(c.redF() * alpha); 373 c.setGreenF(c.greenF() * alpha); 374 c.setBlueF(c.blueF() * alpha); 375 return c; 376 } 377 378 379 void QGL2PaintEngineExPrivate::setBrush(const QBrush& brush) 380 { 381 if (qbrush_fast_equals(currentBrush, brush)) 382 return; 383 384 const Qt::BrushStyle newStyle = qbrush_style(brush); 385 Q_ASSERT(newStyle != Qt::NoBrush); 386 206 387 currentBrush = brush; 207 brushTextureDirty = true; 208 brushUniformsDirty = true; 209 shaderManager->setBrushStyle(currentBrush->style()); 210 shaderManager->setAffineOnlyBrushTransform(currentBrush->transform().isAffine()); 211 } 212 213 214 // Unless this gets used elsewhere, it's probably best to merge it into fillStencilWithVertexArray 388 brushUniformsDirty = true; // All brushes have at least one uniform 389 390 if (newStyle > Qt::SolidPattern) 391 brushTextureDirty = true; 392 393 if (currentBrush.style() == Qt::TexturePattern 394 && qHasPixmapTexture(brush) && brush.texture().isQBitmap()) 395 { 396 shaderManager->setSrcPixelType(QGLEngineShaderManager::TextureSrcWithPattern); 397 } else { 398 shaderManager->setSrcPixelType(newStyle); 399 } 400 shaderManager->optimiseForBrushTransform(currentBrush.transform().type()); 401 } 402 403 215 404 void QGL2PaintEngineExPrivate::useSimpleShader() 216 405 { 217 shaderManager->simpleShader()->use(); 406 shaderManager->simpleProgram()->bind(); 407 shaderManager->setDirty(); 218 408 219 409 if (matrixDirty) … … 221 411 222 412 if (simpleShaderMatrixUniformDirty) { 223 shaderManager->simpleShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix; 413 const GLuint location = shaderManager->simpleProgram()->uniformLocation("pmvMatrix"); 414 glUniformMatrix3fv(location, 1, GL_FALSE, (GLfloat*)pmvMatrix); 224 415 simpleShaderMatrixUniformDirty = false; 225 416 } 226 417 } 227 418 228 229 Q_GLOBAL_STATIC(QGLGradientCache, qt_opengl_gradient_cache)230 231 419 void QGL2PaintEngineExPrivate::updateBrushTexture() 232 420 { 421 Q_Q(QGL2PaintEngineEx); 233 422 // qDebug("QGL2PaintEngineExPrivate::updateBrushTexture()"); 234 Qt::BrushStyle style = currentBrush ->style();423 Qt::BrushStyle style = currentBrush.style(); 235 424 236 425 if ( (style >= Qt::Dense1Pattern) && (style <= Qt::DiagCrossPattern) ) { 237 426 // Get the image data for the pattern 238 QImage texImage = qt_imageForBrush(style, true);239 240 glActiveTexture( QT_BRUSH_TEXTURE_UNIT);241 ctx->d_func()->bindTexture(texImage, GL_TEXTURE_2D, GL_RGBA, true );242 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true);427 QImage texImage = qt_imageForBrush(style, false); 428 429 glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); 430 ctx->d_func()->bindTexture(texImage, GL_TEXTURE_2D, GL_RGBA, true, QGLContext::InternalBindOption); 431 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); 243 432 } 244 433 else if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) { 245 434 // Gradiant brush: All the gradiants use the same texture 246 435 247 const QGradient* g = currentBrush ->gradient();436 const QGradient* g = currentBrush.gradient(); 248 437 249 438 // We apply global opacity in the fragment shaders, so we always pass 1.0 250 439 // for opacity to the cache. 251 GLuint texId = qt_opengl_gradient_cache()->getBuffer(*g, 1.0, ctx); 440 GLuint texId = QGL2GradientCache::cacheForContext(ctx)->getBuffer(*g, 1.0); 441 442 glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); 443 glBindTexture(GL_TEXTURE_2D, texId); 252 444 253 445 if (g->spread() == QGradient::RepeatSpread || g->type() == QGradient::ConicalGradient) 254 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true);446 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); 255 447 else if (g->spread() == QGradient::ReflectSpread) 256 updateTextureFilter(GL_TEXTURE_2D, GL_MIRRORED_REPEAT_IBM, true);448 updateTextureFilter(GL_TEXTURE_2D, GL_MIRRORED_REPEAT_IBM, q->state()->renderHints & QPainter::SmoothPixmapTransform); 257 449 else 258 updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, true); 259 260 glBindTexture(GL_TEXTURE_2D, texId); 450 updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, q->state()->renderHints & QPainter::SmoothPixmapTransform); 261 451 } 262 452 else if (style == Qt::TexturePattern) { 263 const QPixmap& texPixmap = currentBrush->texture(); 264 265 glActiveTexture(QT_BRUSH_TEXTURE_UNIT); 266 ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, true); 267 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true); 453 const QPixmap& texPixmap = currentBrush.texture(); 454 455 glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); 456 QGLTexture *tex = ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption); 457 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); 458 textureInvertedY = tex->options & QGLContext::InvertedYBindOption ? -1 : 1; 268 459 } 269 460 brushTextureDirty = false; … … 274 465 { 275 466 // qDebug("QGL2PaintEngineExPrivate::updateBrushUniforms()"); 276 Qt::BrushStyle style = currentBrush ->style();467 Qt::BrushStyle style = currentBrush.style(); 277 468 278 469 if (style == Qt::NoBrush) 279 470 return; 280 471 281 GLfloat opacity = 1.0; 282 if (q->state()->opacity < 0.99f) 283 opacity = (GLfloat)q->state()->opacity; 284 bool setOpacity = true; 285 286 QTransform brushQTransform = currentBrush->transform(); 472 QTransform brushQTransform = currentBrush.transform(); 287 473 288 474 if (style == Qt::SolidPattern) { 289 QColor col = premultiplyColor(currentBrush->color(), opacity); 290 shaderManager->brushShader()->uniforms()[QLatin1String("fragmentColor")] = col; 291 setOpacity = false; 475 QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity); 476 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::FragmentColor), col); 292 477 } 293 478 else { … … 296 481 297 482 if (style <= Qt::DiagCrossPattern) { 298 translationPoint = q->state()->brushOrigin; 299 300 QColor col = premultiplyColor(currentBrush->color(), opacity); 301 302 shaderManager->brushShader()->uniforms()[QLatin1String("patternColor")] = col; 303 setOpacity = false; //So code below doesn't try to set the opacity uniform 304 305 QGLVec2 halfViewportSize = { width*0.5, height*0.5 }; 306 shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize; 483 QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity); 484 485 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col); 486 487 QVector2D halfViewportSize(width*0.5, height*0.5); 488 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); 307 489 } 308 490 else if (style == Qt::LinearGradientPattern) { 309 const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush ->gradient());491 const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush.gradient()); 310 492 311 493 QPointF realStart = g->start(); … … 315 497 QPointF l = realFinal - realStart; 316 498 317 // ### 318 QGLVec3 linearData = { 499 QVector3D linearData( 319 500 l.x(), 320 501 l.y(), 321 502 1.0f / (l.x() * l.x() + l.y() * l.y()) 322 };323 324 shaderManager-> brushShader()->uniforms()[QLatin1String("linearData")] = linearData;325 326 Q GLVec2 halfViewportSize = { width*0.5, height*0.5 };327 shaderManager-> brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize;503 ); 504 505 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::LinearData), linearData); 506 507 QVector2D halfViewportSize(width*0.5, height*0.5); 508 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); 328 509 } 329 510 else if (style == Qt::ConicalGradientPattern) { 330 const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrush ->gradient());511 const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrush.gradient()); 331 512 translationPoint = g->center(); 332 513 333 514 GLfloat angle = -(g->angle() * 2 * Q_PI) / 360.0; 334 515 335 shaderManager-> brushShader()->uniforms()[QLatin1String("angle")] = angle;336 337 Q GLVec2 halfViewportSize = { width*0.5, height*0.5 };338 shaderManager-> brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize;516 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Angle), angle); 517 518 QVector2D halfViewportSize(width*0.5, height*0.5); 519 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); 339 520 } 340 521 else if (style == Qt::RadialGradientPattern) { 341 const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush ->gradient());522 const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush.gradient()); 342 523 QPointF realCenter = g->center(); 343 524 QPointF realFocal = g->focalPoint(); … … 346 527 347 528 QPointF fmp = realCenter - realFocal; 348 shaderManager-> brushShader()->uniforms()[QLatin1String("fmp")] = fmp;529 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Fmp), fmp); 349 530 350 531 GLfloat fmp2_m_radius2 = -fmp.x() * fmp.x() - fmp.y() * fmp.y() + realRadius*realRadius; 351 shaderManager->brushShader()->uniforms()[QLatin1String("fmp2_m_radius2")] = fmp2_m_radius2; 352 353 shaderManager->brushShader()->uniforms()[QLatin1String("inverse_2_fmp2_m_radius2")] = 354 GLfloat(1.0 / (2.0*fmp2_m_radius2)); 355 356 QGLVec2 halfViewportSize = { width*0.5, height*0.5 }; 357 shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize; 532 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Fmp2MRadius2), fmp2_m_radius2); 533 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Inverse2Fmp2MRadius2), 534 GLfloat(1.0 / (2.0*fmp2_m_radius2))); 535 536 QVector2D halfViewportSize(width*0.5, height*0.5); 537 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); 358 538 } 359 539 else if (style == Qt::TexturePattern) { 360 translationPoint = q->state()->brushOrigin; 361 362 const QPixmap& texPixmap = currentBrush->texture(); 363 364 QSizeF invertedTextureSize( 1.0 / texPixmap.width(), 1.0 / texPixmap.height() ); 365 shaderManager->brushShader()->uniforms()[QLatin1String("invertedTextureSize")] = invertedTextureSize; 366 367 QGLVec2 halfViewportSize = { width*0.5, height*0.5 }; 368 shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize; 540 const QPixmap& texPixmap = currentBrush.texture(); 541 542 if (qHasPixmapTexture(currentBrush) && currentBrush.texture().isQBitmap()) { 543 QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity); 544 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col); 545 } 546 547 QSizeF invertedTextureSize(1.0 / texPixmap.width(), 1.0 / texPixmap.height()); 548 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::InvertedTextureSize), invertedTextureSize); 549 550 QVector2D halfViewportSize(width*0.5, height*0.5); 551 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); 369 552 } 370 553 else 371 554 qWarning("QGL2PaintEngineEx: Unimplemented fill style"); 372 555 556 const QPointF &brushOrigin = q->state()->brushOrigin; 557 QTransform matrix = q->state()->matrix; 558 matrix.translate(brushOrigin.x(), brushOrigin.y()); 559 373 560 QTransform translate(1, 0, 0, 1, -translationPoint.x(), -translationPoint.y()); 374 561 QTransform gl_to_qt(1, 0, 0, -1, 0, height); 375 QTransform inv_matrix = gl_to_qt * (brushQTransform * q->state()->matrix).inverted() * translate; 376 377 shaderManager->brushShader()->uniforms()[QLatin1String("brushTransform")] = inv_matrix; 378 shaderManager->brushShader()->uniforms()[QLatin1String("brushTexture")] = QT_BRUSH_TEXTURE_UNIT; 379 380 if (setOpacity) 381 shaderManager->brushShader()->uniforms()[QLatin1String("opacity")] = opacity; 562 QTransform inv_matrix; 563 if (style == Qt::TexturePattern && textureInvertedY == -1) 564 inv_matrix = gl_to_qt * (QTransform(1, 0, 0, -1, 0, currentBrush.texture().height()) * brushQTransform * matrix).inverted() * translate; 565 else 566 inv_matrix = gl_to_qt * (brushQTransform * matrix).inverted() * translate; 567 568 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BrushTransform), inv_matrix); 569 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BrushTexture), QT_BRUSH_TEXTURE_UNIT); 382 570 } 383 571 brushUniformsDirty = false; … … 390 578 // qDebug("QGL2PaintEngineExPrivate::updateMatrix()"); 391 579 392 // We setup the Projection matrix to be the equivilant of glOrtho(0, w, h, 0, -1, 1):393 GLfloat P[4][4] = {394 {2.0/width, 0.0, 0.0, -1.0},395 {0.0, -2.0/height, 0.0, 1.0},396 {0.0, 0.0, -1.0, 0.0},397 {0.0, 0.0, 0.0, 1.0}398 };399 400 // Use the (3x3) transform for the Model~View matrix:401 580 const QTransform& transform = q->state()->matrix; 402 GLfloat MV[4][4] = { 403 {transform.m11(), transform.m21(), 0.0, transform.dx() + 0.5}, 404 {transform.m12(), transform.m22(), 0.0, transform.dy() + 0.5}, 405 {0.0, 0.0, 1.0, 0.0}, 406 {transform.m13(), transform.m23(), 0.0, transform.m33()} 407 }; 408 409 // NOTE: OpenGL ES works with column-major matrices, so when we multiply the matrices, 410 // we also transpose them ready for GL. 411 for (int row = 0; row < 4; ++row) { 412 for (int col = 0; col < 4; ++col) { 413 pmvMatrix[col][row] = 0.0; 414 for (int n = 0; n < 4; ++n) 415 pmvMatrix[col][row] += P[row][n] * MV[n][col]; 416 } 417 } 581 582 // The projection matrix converts from Qt's coordinate system to GL's coordinate system 583 // * GL's viewport is 2x2, Qt's is width x height 584 // * GL has +y -> -y going from bottom -> top, Qt is the other way round 585 // * GL has [0,0] in the center, Qt has it in the top-left 586 // 587 // This results in the Projection matrix below, which is multiplied by the painter's 588 // transformation matrix, as shown below: 589 // 590 // Projection Matrix Painter Transform 591 // ------------------------------------------------ ------------------------ 592 // | 2.0 / width | 0.0 | -1.0 | | m11 | m21 | dx | 593 // | 0.0 | -2.0 / height | 1.0 | * | m12 | m22 | dy | 594 // | 0.0 | 0.0 | 1.0 | | m13 | m23 | m33 | 595 // ------------------------------------------------ ------------------------ 596 // 597 // NOTE: The resultant matrix is also transposed, as GL expects column-major matracies 598 599 const GLfloat wfactor = 2.0f / width; 600 const GLfloat hfactor = -2.0f / height; 601 GLfloat dx = transform.dx(); 602 GLfloat dy = transform.dy(); 603 604 // Non-integer translates can have strange effects for some rendering operations such as 605 // anti-aliased text rendering. In such cases, we snap the translate to the pixel grid. 606 if (snapToPixelGrid && transform.type() == QTransform::TxTranslate) { 607 // 0.50 needs to rounded down to 0.0 for consistency with raster engine: 608 dx = ceilf(dx - 0.5f); 609 dy = ceilf(dy - 0.5f); 610 } 611 612 if (addOffset) { 613 dx += 0.49f; 614 dy += 0.49f; 615 } 616 617 pmvMatrix[0][0] = (wfactor * transform.m11()) - transform.m13(); 618 pmvMatrix[1][0] = (wfactor * transform.m21()) - transform.m23(); 619 pmvMatrix[2][0] = (wfactor * dx) - transform.m33(); 620 pmvMatrix[0][1] = (hfactor * transform.m12()) + transform.m13(); 621 pmvMatrix[1][1] = (hfactor * transform.m22()) + transform.m23(); 622 pmvMatrix[2][1] = (hfactor * dy) + transform.m33(); 623 pmvMatrix[0][2] = transform.m13(); 624 pmvMatrix[1][2] = transform.m23(); 625 pmvMatrix[2][2] = transform.m33(); 418 626 419 627 // 1/10000 == 0.0001, so we have good enough res to cover curves … … 427 635 // The actual data has been updated so both shader program's uniforms need updating 428 636 simpleShaderMatrixUniformDirty = true; 429 brushShaderMatrixUniformDirty = true; 430 imageShaderMatrixUniformDirty = true; 431 textShaderMatrixUniformDirty = true; 637 shaderMatrixUniformDirty = true; 638 639 dasher.setInvScale(inverseScale); 640 stroker.setInvScale(inverseScale); 432 641 } 433 642 … … 486 695 } 487 696 488 489 void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& src, int txtWidth, int txtHeight) 490 { 491 // qDebug("QGL2PaintEngineExPrivate::drawImage()"); 492 493 // We have a shader specifically for drawPixmap/drawImage... 494 shaderManager->imageShader()->use(); 495 496 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); 497 498 if (compositionModeDirty) 499 updateCompositionMode(); 500 697 static inline void setCoords(GLfloat *coords, const QGLRect &rect) 698 { 699 coords[0] = rect.left; 700 coords[1] = rect.top; 701 coords[2] = rect.right; 702 coords[3] = rect.top; 703 coords[4] = rect.right; 704 coords[5] = rect.bottom; 705 coords[6] = rect.left; 706 coords[7] = rect.bottom; 707 } 708 709 void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern) 710 { 711 // Setup for texture drawing 712 currentBrush = noBrush; 713 shaderManager->setSrcPixelType(pattern ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc); 714 715 if (addOffset) { 716 addOffset = false; 717 matrixDirty = true; 718 } 719 720 if (snapToPixelGrid) { 721 snapToPixelGrid = false; 722 matrixDirty = true; 723 } 724 725 if (prepareForDraw(opaque)) 726 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT); 727 728 if (pattern) { 729 QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity); 730 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col); 731 } 732 733 GLfloat dx = 1.0 / textureSize.width(); 734 GLfloat dy = 1.0 / textureSize.height(); 735 736 QGLRect srcTextureRect(src.left*dx, src.top*dy, src.right*dx, src.bottom*dy); 737 738 setCoords(staticVertexCoordinateArray, dest); 739 setCoords(staticTextureCoordinateArray, srcTextureRect); 740 741 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 742 } 743 744 void QGL2PaintEngineEx::beginNativePainting() 745 { 746 Q_D(QGL2PaintEngineEx); 747 ensureActive(); 748 d->transferMode(BrushDrawingMode); 749 750 QGLContext *ctx = d->ctx; 751 glUseProgram(0); 752 753 #ifndef QT_OPENGL_ES_2 754 // be nice to people who mix OpenGL 1.x code with QPainter commands 755 // by setting modelview and projection matrices to mirror the GL 1 756 // paint engine 757 const QTransform& mtx = state()->matrix; 758 759 float mv_matrix[4][4] = 760 { 761 { mtx.m11(), mtx.m12(), 0, mtx.m13() }, 762 { mtx.m21(), mtx.m22(), 0, mtx.m23() }, 763 { 0, 0, 1, 0 }, 764 { mtx.dx(), mtx.dy(), 0, mtx.m33() } 765 }; 766 767 const QSize sz = d->device->size(); 768 769 glMatrixMode(GL_PROJECTION); 770 glLoadIdentity(); 771 glOrtho(0, sz.width(), sz.height(), 0, -999999, 999999); 772 773 glMatrixMode(GL_MODELVIEW); 774 glLoadMatrixf(&mv_matrix[0][0]); 775 #else 776 Q_UNUSED(ctx); 777 #endif 778 779 d->lastTextureUsed = GLuint(-1); 780 d->dirtyStencilRegion = QRect(0, 0, d->width, d->height); 781 d->resetGLState(); 782 783 d->shaderManager->setDirty(); 784 785 d->needsSync = true; 786 } 787 788 void QGL2PaintEngineExPrivate::resetGLState() 789 { 790 glDisable(GL_BLEND); 791 glActiveTexture(GL_TEXTURE0); 792 glDisable(GL_STENCIL_TEST); 793 glDisable(GL_DEPTH_TEST); 794 glDisable(GL_SCISSOR_TEST); 795 glDepthMask(true); 796 glDepthFunc(GL_LESS); 797 glClearDepth(1); 798 } 799 800 void QGL2PaintEngineEx::endNativePainting() 801 { 802 Q_D(QGL2PaintEngineEx); 803 d->needsSync = true; 804 } 805 806 void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode) 807 { 808 if (newMode == mode) 809 return; 810 811 if (mode == TextDrawingMode || mode == ImageDrawingMode || mode == ImageArrayDrawingMode) { 812 glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); 813 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 814 glDisableVertexAttribArray(QT_OPACITY_ATTR); 815 816 lastTextureUsed = GLuint(-1); 817 } 818 819 if (newMode == TextDrawingMode) { 820 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 821 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); 822 823 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data()); 824 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data()); 825 } 826 827 if (newMode == ImageDrawingMode) { 828 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 829 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); 830 831 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticVertexCoordinateArray); 832 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticTextureCoordinateArray); 833 } 834 835 if (newMode == ImageArrayDrawingMode) { 836 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 837 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); 838 glEnableVertexAttribArray(QT_OPACITY_ATTR); 839 840 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data()); 841 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data()); 842 glVertexAttribPointer(QT_OPACITY_ATTR, 1, GL_FLOAT, GL_FALSE, 0, opacityArray.data()); 843 } 844 845 // This needs to change when we implement high-quality anti-aliasing... 846 if (newMode != TextDrawingMode) 847 shaderManager->setMaskType(QGLEngineShaderManager::NoMask); 848 849 mode = newMode; 850 } 851 852 struct QGL2PEVectorPathCache 853 { 854 #ifdef QT_OPENGL_CACHE_AS_VBOS 855 GLuint vbo; 856 #else 857 float *vertices; 858 #endif 859 int vertexCount; 860 GLenum primitiveType; 861 qreal iscale; 862 }; 863 864 void QGL2PaintEngineExPrivate::cleanupVectorPath(QPaintEngineEx *engine, void *data) 865 { 866 QGL2PEVectorPathCache *c = (QGL2PEVectorPathCache *) data; 867 #ifdef QT_OPENGL_CACHE_AS_VBOS 868 Q_ASSERT(engine->type() == QPaintEngine::OpenGL2); 869 static_cast<QGL2PaintEngineEx *>(engine)->d_func()->unusedVBOSToClean << c->vbo; 870 #else 871 Q_UNUSED(engine); 872 qFree(c->vertices); 873 #endif 874 delete c; 875 } 876 877 // Assumes everything is configured for the brush you want to use 878 void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) 879 { 880 transferMode(BrushDrawingMode); 881 882 const QOpenGL2PaintEngineState *s = q->state(); 883 const bool newAddOffset = !(s->renderHints & QPainter::Antialiasing) && 884 (qbrush_style(currentBrush) == Qt::SolidPattern) && 885 !multisamplingAlwaysEnabled; 886 887 if (addOffset != newAddOffset) { 888 addOffset = newAddOffset; 889 matrixDirty = true; 890 } 891 892 if (snapToPixelGrid) { 893 snapToPixelGrid = false; 894 matrixDirty = true; 895 } 896 897 // Might need to call updateMatrix to re-calculate inverseScale 501 898 if (matrixDirty) 502 899 updateMatrix(); 503 900 504 if (imageShaderMatrixUniformDirty) {505 shaderManager->imageShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix;506 imageShaderMatrixUniformDirty = false;507 }508 509 shaderManager->imageShader()->uniforms()[QLatin1String("textureSampler")] = QT_BRUSH_TEXTURE_UNIT;510 511 // if (q->state()->opacity < 0.99f)512 shaderManager->imageShader()->uniforms()[QLatin1String("opacity")] = (GLfloat)q->state()->opacity;513 514 GLfloat vertexCoords[] = {515 dest.left, dest.top,516 dest.left, dest.bottom,517 dest.right, dest.bottom,518 dest.right, dest.top519 };520 521 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);522 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords);523 524 GLfloat dx = 1.0 / txtWidth;525 GLfloat dy = 1.0 / txtHeight;526 527 QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy);528 529 GLfloat textureCoords[] = {530 srcTextureRect.left, srcTextureRect.top,531 srcTextureRect.left, srcTextureRect.bottom,532 srcTextureRect.right, srcTextureRect.bottom,533 srcTextureRect.right, srcTextureRect.top534 };535 536 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);537 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoords);538 539 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);540 541 glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);542 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);543 }544 545 546 void QGL2PaintEngineExPrivate::drawOutline(const QVectorPath& path)547 {548 // qDebug("QGL2PaintEngineExPrivate::drawOutline()");549 if (matrixDirty)550 updateMatrix();551 552 pathVertexArray.clear();553 pathVertexArray.addPath(path, inverseScale);554 555 if (path.hasImplicitClose()) {556 // Close the path's outline557 pathVertexArray.lineToArray(path.points()[0], path.points()[1]);558 pathVertexArray.stops().last() += 1;559 }560 561 prepareForDraw();562 drawVertexArrays(pathVertexArray, GL_LINE_STRIP);563 }564 565 566 // Assumes everything is configured for the brush you want to use567 void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)568 {569 if (matrixDirty)570 updateMatrix();571 572 901 const QPointF* const points = reinterpret_cast<const QPointF*>(path.points()); 573 574 902 575 903 // Check to see if there's any hints 576 904 if (path.shape() == QVectorPath::RectangleHint) { 577 905 QGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y()); 578 prepareForDraw( );906 prepareForDraw(currentBrush.isOpaque()); 579 907 composite(rect); 580 } 581 else if (path.shape() == QVectorPath::EllipseHint) { 582 pathVertexArray.clear(); 583 pathVertexArray.addPath(path, inverseScale); 584 prepareForDraw(); 585 drawVertexArrays(pathVertexArray, GL_TRIANGLE_FAN); 586 } 587 else { 908 } else if (path.isConvex()) { 909 910 if (path.isCacheable()) { 911 QVectorPath::CacheEntry *data = path.lookupCacheData(q); 912 QGL2PEVectorPathCache *cache; 913 914 if (data) { 915 cache = (QGL2PEVectorPathCache *) data->data; 916 // Check if scale factor is exceeded for curved paths and generate curves if so... 917 if (path.isCurved()) { 918 qreal scaleFactor = cache->iscale / inverseScale; 919 if (scaleFactor < 0.5 || scaleFactor > 2.0) { 920 #ifdef QT_OPENGL_CACHE_AS_VBOS 921 glDeleteBuffers(1, &cache->vbo); 922 cache->vbo = 0; 923 #else 924 qFree(cache->vertices); 925 #endif 926 cache->vertexCount = 0; 927 } 928 } 929 } else { 930 cache = new QGL2PEVectorPathCache; 931 cache->vertexCount = 0; 932 data = const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath); 933 } 934 935 // Flatten the path at the current scale factor and fill it into the cache struct. 936 if (!cache->vertexCount) { 937 vertexCoordinateArray.clear(); 938 vertexCoordinateArray.addPath(path, inverseScale, false); 939 int vertexCount = vertexCoordinateArray.vertexCount(); 940 int floatSizeInBytes = vertexCount * 2 * sizeof(float); 941 cache->vertexCount = vertexCount; 942 cache->primitiveType = GL_TRIANGLE_FAN; 943 cache->iscale = inverseScale; 944 #ifdef QT_OPENGL_CACHE_AS_VBOS 945 glGenBuffers(1, &cache->vbo); 946 glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); 947 glBufferData(GL_ARRAY_BUFFER, floatSizeInBytes, vertexCoordinateArray.data(), GL_STATIC_DRAW); 948 #else 949 cache->vertices = (float *) qMalloc(floatSizeInBytes); 950 memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes); 951 #endif 952 } 953 954 prepareForDraw(currentBrush.isOpaque()); 955 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 956 #ifdef QT_OPENGL_CACHE_AS_VBOS 957 glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); 958 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, 0); 959 #else 960 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, cache->vertices); 961 #endif 962 glDrawArrays(cache->primitiveType, 0, cache->vertexCount); 963 964 } else { 965 // printf(" - Marking path as cachable...\n"); 966 // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable 967 // ### Remove before release... 968 static bool do_vectorpath_cache = qgetenv("QT_OPENGL_NO_PATH_CACHE").isEmpty(); 969 if (do_vectorpath_cache) 970 path.makeCacheable(); 971 vertexCoordinateArray.clear(); 972 vertexCoordinateArray.addPath(path, inverseScale, false); 973 prepareForDraw(currentBrush.isOpaque()); 974 drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN); 975 } 976 977 } else { 588 978 // The path is too complicated & needs the stencil technique 589 pathVertexArray.clear(); 590 pathVertexArray.addPath(path, inverseScale); 591 592 fillStencilWithVertexArray(pathVertexArray, path.hasWindingFill()); 979 vertexCoordinateArray.clear(); 980 vertexCoordinateArray.addPath(path, inverseScale, false); 981 982 fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill()); 983 984 glStencilMask(0xff); 985 glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); 986 987 if (q->state()->clipTestEnabled) { 988 // Pass when high bit is set, replace stencil value with current clip 989 glStencilFunc(GL_NOTEQUAL, q->state()->currentClip, GL_STENCIL_HIGH_BIT); 990 } else if (path.hasWindingFill()) { 991 // Pass when any bit is set, replace stencil value with 0 992 glStencilFunc(GL_NOTEQUAL, 0, 0xff); 993 } else { 994 // Pass when high bit is set, replace stencil value with 0 995 glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); 996 } 997 prepareForDraw(currentBrush.isOpaque()); 593 998 594 999 // Stencil the brush onto the dest buffer 595 glStencilFunc(GL_NOTEQUAL, 0, 0xFFFF); // Pass if stencil buff value != 0 596 glEnable(GL_STENCIL_TEST); 597 prepareForDraw(); 598 composite(pathVertexArray.boundingRect()); 599 glDisable(GL_STENCIL_TEST); 600 601 cleanStencilBuffer(pathVertexArray.boundingRect()); 602 } 603 } 604 605 606 void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill) 607 { 1000 composite(vertexCoordinateArray.boundingRect()); 1001 glStencilMask(0); 1002 updateClipScissorTest(); 1003 } 1004 } 1005 1006 1007 void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data, 1008 int count, 1009 int *stops, 1010 int stopCount, 1011 const QGLRect &bounds, 1012 StencilFillMode mode) 1013 { 1014 Q_ASSERT(count || stops); 1015 608 1016 // qDebug("QGL2PaintEngineExPrivate::fillStencilWithVertexArray()"); 609 if (stencilBuferDirty) {610 // Clear the stencil buffer to zeros 611 glDisable(GL_STENCIL_TEST);612 glStencilMask(0xFFFF); // Enable writing to stencil buffer, otherwise glClear wont do anything.1017 glStencilMask(0xff); // Enable stencil writes 1018 1019 if (dirtyStencilRegion.intersects(currentScissorBounds)) { 1020 QVector<QRect> clearRegion = dirtyStencilRegion.intersected(currentScissorBounds).rects(); 613 1021 glClearStencil(0); // Clear to zero 614 glClear(GL_STENCIL_BUFFER_BIT); 615 stencilBuferDirty = false; 1022 for (int i = 0; i < clearRegion.size(); ++i) { 1023 #ifndef QT_GL_NO_SCISSOR_TEST 1024 setScissor(clearRegion.at(i)); 1025 #endif 1026 glClear(GL_STENCIL_BUFFER_BIT); 1027 } 1028 1029 dirtyStencilRegion -= currentScissorBounds; 1030 1031 #ifndef QT_GL_NO_SCISSOR_TEST 1032 updateClipScissorTest(); 1033 #endif 616 1034 } 617 1035 618 1036 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes 619 glStencilMask(0xFFFF); // Enable stencil writes 620 glStencilFunc(GL_ALWAYS, 0, 0xFFFF); // Always pass the stencil test 621 622 // Setup the stencil op: 623 if (useWindingFill) { 624 glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); // Inc. for front-facing triangle 625 glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); //Dec. for back-facing "holes" 626 } else 1037 useSimpleShader(); 1038 glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d 1039 1040 if (mode == WindingFillMode) { 1041 Q_ASSERT(stops && !count); 1042 if (q->state()->clipTestEnabled) { 1043 // Flatten clip values higher than current clip, and set high bit to match current clip 1044 glStencilFunc(GL_LEQUAL, GL_STENCIL_HIGH_BIT | q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); 1045 glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); 1046 composite(bounds); 1047 1048 glStencilFunc(GL_EQUAL, GL_STENCIL_HIGH_BIT, GL_STENCIL_HIGH_BIT); 1049 } else if (!stencilClean) { 1050 // Clear stencil buffer within bounding rect 1051 glStencilFunc(GL_ALWAYS, 0, 0xff); 1052 glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); 1053 composite(bounds); 1054 } 1055 1056 // Inc. for front-facing triangle 1057 glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP); 1058 // Dec. for back-facing "holes" 1059 glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_DECR_WRAP); 1060 glStencilMask(~GL_STENCIL_HIGH_BIT); 1061 drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN); 1062 1063 if (q->state()->clipTestEnabled) { 1064 // Clear high bit of stencil outside of path 1065 glStencilFunc(GL_EQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); 1066 glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); 1067 glStencilMask(GL_STENCIL_HIGH_BIT); 1068 composite(bounds); 1069 } 1070 } else if (mode == OddEvenFillMode) { 1071 glStencilMask(GL_STENCIL_HIGH_BIT); 627 1072 glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit 628 629 // No point in using a fancy gradiant shader for writing into the stencil buffer! 630 useSimpleShader(); 631 632 glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d 633 glDisable(GL_BLEND); 634 635 // Draw the vertecies into the stencil buffer: 636 drawVertexArrays(vertexArray, GL_TRIANGLE_FAN); 1073 drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN); 1074 1075 } else { // TriStripStrokeFillMode 1076 Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops 1077 glStencilMask(GL_STENCIL_HIGH_BIT); 1078 #if 0 1079 glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit 1080 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 1081 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data); 1082 glDrawArrays(GL_TRIANGLE_STRIP, 0, count); 1083 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 1084 #else 1085 1086 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); 1087 if (q->state()->clipTestEnabled) { 1088 glStencilFunc(GL_LEQUAL, q->state()->currentClip | GL_STENCIL_HIGH_BIT, 1089 ~GL_STENCIL_HIGH_BIT); 1090 } else { 1091 glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff); 1092 } 1093 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 1094 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data); 1095 glDrawArrays(GL_TRIANGLE_STRIP, 0, count); 1096 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 1097 #endif 1098 } 637 1099 638 1100 // Enable color writes & disable stencil writes 639 1101 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 640 glStencilMask(0); 641 } 642 643 void QGL2PaintEngineExPrivate::cleanStencilBuffer(const QGLRect& area) 644 { 645 // qDebug("QGL2PaintEngineExPrivate::cleanStencilBuffer()"); 1102 } 1103 1104 /* 1105 If the maximum value in the stencil buffer is GL_STENCIL_HIGH_BIT - 1, 1106 restore the stencil buffer to a pristine state. The current clip region 1107 is set to 1, and the rest to 0. 1108 */ 1109 void QGL2PaintEngineExPrivate::resetClipIfNeeded() 1110 { 1111 if (maxClip != (GL_STENCIL_HIGH_BIT - 1)) 1112 return; 1113 1114 Q_Q(QGL2PaintEngineEx); 1115 646 1116 useSimpleShader(); 647 648 GLfloat rectVerts[] = {649 area.left, area.top,650 area.left, area.bottom,651 area.right, area.bottom,652 area.right, area.top653 };654 655 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);656 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, rectVerts);657 658 1117 glEnable(GL_STENCIL_TEST); 659 glStencilFunc(GL_ALWAYS, 0, 0xFFFF); // Always pass the stencil test 660 661 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes 662 glStencilMask(0xFFFF); // Enable writing to stencil buffer 663 glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); // Write 0's to stencil buffer 664 665 glDisable(GL_BLEND); 666 667 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 668 669 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 670 671 // Enable color writes & disable stencil writes 1118 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); 1119 1120 QRectF bounds = q->state()->matrix.inverted().mapRect(QRectF(0, 0, width, height)); 1121 QGLRect rect(bounds.left(), bounds.top(), bounds.right(), bounds.bottom()); 1122 1123 // Set high bit on clip region 1124 glStencilFunc(GL_LEQUAL, q->state()->currentClip, 0xff); 1125 glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT); 1126 glStencilMask(GL_STENCIL_HIGH_BIT); 1127 composite(rect); 1128 1129 // Reset clipping to 1 and everything else to zero 1130 glStencilFunc(GL_NOTEQUAL, 0x01, GL_STENCIL_HIGH_BIT); 1131 glStencilOp(GL_ZERO, GL_REPLACE, GL_REPLACE); 1132 glStencilMask(0xff); 1133 composite(rect); 1134 1135 q->state()->currentClip = 1; 1136 q->state()->canRestoreClip = false; 1137 1138 maxClip = 1; 1139 1140 glStencilMask(0x0); 672 1141 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 673 glStencilMask(0); 674 glDisable(GL_STENCIL_TEST); 675 } 676 677 void QGL2PaintEngineExPrivate::prepareForDraw() 678 { 679 if (brushTextureDirty) 1142 } 1143 1144 bool QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque) 1145 { 1146 if (brushTextureDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode) 680 1147 updateBrushTexture(); 681 1148 … … 683 1150 updateCompositionMode(); 684 1151 685 if (shaderManager->useCorrectShaderProg()) { 1152 if (matrixDirty) 1153 updateMatrix(); 1154 1155 const bool stateHasOpacity = q->state()->opacity < 0.99f; 1156 if (q->state()->composition_mode == QPainter::CompositionMode_Source 1157 || (q->state()->composition_mode == QPainter::CompositionMode_SourceOver 1158 && srcPixelsAreOpaque && !stateHasOpacity)) 1159 { 1160 glDisable(GL_BLEND); 1161 } else { 1162 glEnable(GL_BLEND); 1163 } 1164 1165 QGLEngineShaderManager::OpacityMode opacityMode; 1166 if (mode == ImageArrayDrawingMode) { 1167 opacityMode = QGLEngineShaderManager::AttributeOpacity; 1168 } else { 1169 opacityMode = stateHasOpacity ? QGLEngineShaderManager::UniformOpacity 1170 : QGLEngineShaderManager::NoOpacity; 1171 if (stateHasOpacity && (mode != ImageDrawingMode)) { 1172 // Using a brush 1173 bool brushIsPattern = (currentBrush.style() >= Qt::Dense1Pattern) && 1174 (currentBrush.style() <= Qt::DiagCrossPattern); 1175 1176 if ((currentBrush.style() == Qt::SolidPattern) || brushIsPattern) 1177 opacityMode = QGLEngineShaderManager::NoOpacity; // Global opacity handled by srcPixel shader 1178 } 1179 } 1180 shaderManager->setOpacityMode(opacityMode); 1181 1182 bool changed = shaderManager->useCorrectShaderProg(); 1183 // If the shader program needs changing, we change it and mark all uniforms as dirty 1184 if (changed) { 686 1185 // The shader program has changed so mark all uniforms as dirty: 687 1186 brushUniformsDirty = true; 688 brushShaderMatrixUniformDirty = true; 689 } 690 691 if (brushUniformsDirty) 1187 shaderMatrixUniformDirty = true; 1188 opacityUniformDirty = true; 1189 } 1190 1191 if (brushUniformsDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode) 692 1192 updateBrushUniforms(); 693 1193 694 if (brushShaderMatrixUniformDirty) { 695 shaderManager->brushShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix; 696 brushShaderMatrixUniformDirty = false; 697 } 698 699 if ((q->state()->opacity < 0.99f) || !currentBrush->isOpaque()) 700 glEnable(GL_BLEND); 701 else 702 glDisable(GL_BLEND); 1194 if (shaderMatrixUniformDirty) { 1195 glUniformMatrix3fv(location(QGLEngineShaderManager::PmvMatrix), 1, GL_FALSE, (GLfloat*)pmvMatrix); 1196 shaderMatrixUniformDirty = false; 1197 } 1198 1199 if (opacityMode == QGLEngineShaderManager::UniformOpacity && opacityUniformDirty) { 1200 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::GlobalOpacity), (GLfloat)q->state()->opacity); 1201 opacityUniformDirty = false; 1202 } 1203 1204 return changed; 703 1205 } 704 1206 … … 722 1224 723 1225 // Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans. 724 void QGL2PaintEngineExPrivate::drawVertexArrays(QGL2PEXVertexArray& vertexArray, GLenum primitive) 1226 void QGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stops, int stopCount, 1227 GLenum primitive) 725 1228 { 726 1229 // Now setup the pointer to the vertex array: 727 1230 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 728 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexArray.data());1231 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data); 729 1232 730 1233 int previousStop = 0; 731 foreach(int stop, vertexArray.stops()) { 1234 for (int i=0; i<stopCount; ++i) { 1235 int stop = stops[i]; 732 1236 /* 733 1237 qDebug("Drawing triangle fan for vertecies %d -> %d:", previousStop, stop-1); … … 741 1245 } 742 1246 743 744 745 746 747 1247 /////////////////////////////////// Public Methods ////////////////////////////////////////// 748 1248 … … 750 1250 : QPaintEngineEx(*(new QGL2PaintEngineExPrivate(this))) 751 1251 { 752 qDebug("QGL2PaintEngineEx::QGL2PaintEngineEx()");753 754 1252 } 755 1253 … … 762 1260 Q_D(QGL2PaintEngineEx); 763 1261 764 QTime startTime = QTime::currentTime(); 765 766 d->setBrush(&brush); 1262 if (qbrush_style(brush) == Qt::NoBrush) 1263 return; 1264 ensureActive(); 1265 d->setBrush(brush); 767 1266 d->fill(path); 768 d->setBrush(&(state()->brush)); // reset back to the state's brush 769 } 1267 } 1268 1269 extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp 1270 770 1271 771 1272 void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) … … 773 1274 Q_D(QGL2PaintEngineEx); 774 1275 775 if (pen.style() == Qt::NoPen) 1276 const QBrush &penBrush = qpen_brush(pen); 1277 if (qpen_style(pen) == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush) 776 1278 return; 777 1279 778 if ( (pen.isCosmetic() && (pen.style() == Qt::SolidLine)) && (pen.widthF() < 2.5f) ) 779 { 780 // We only handle solid, cosmetic pens with a width of 1 pixel 781 const QBrush& brush = pen.brush(); 782 d->setBrush(&brush); 783 784 if (pen.widthF() < 0.01f) 785 glLineWidth(1.0); 786 else 787 glLineWidth(pen.widthF()); 788 789 d->drawOutline(path); 790 d->setBrush(&(state()->brush)); 791 } else 792 return QPaintEngineEx::stroke(path, pen); 793 794 } 795 796 void QGL2PaintEngineEx::penChanged() 797 { 798 // qDebug("QGL2PaintEngineEx::penChanged() not implemented!"); 799 } 800 801 802 void QGL2PaintEngineEx::brushChanged() 803 { 804 // qDebug("QGL2PaintEngineEx::brushChanged()"); 805 Q_D(QGL2PaintEngineEx); 806 d->setBrush(&(state()->brush)); 807 } 808 809 void QGL2PaintEngineEx::brushOriginChanged() 810 { 811 // qDebug("QGL2PaintEngineEx::brushOriginChanged()"); 812 Q_D(QGL2PaintEngineEx); 813 d->brushUniformsDirty = true; 814 } 1280 QOpenGL2PaintEngineState *s = state(); 1281 if (pen.isCosmetic() && !qt_scaleForTransform(s->transform(), 0)) { 1282 // QTriangulatingStroker class is not meant to support cosmetically sheared strokes. 1283 QPaintEngineEx::stroke(path, pen); 1284 return; 1285 } 1286 1287 ensureActive(); 1288 d->setBrush(penBrush); 1289 d->stroke(path, pen); 1290 } 1291 1292 void QGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &pen) 1293 { 1294 const QOpenGL2PaintEngineState *s = q->state(); 1295 const bool newAddOffset = !(s->renderHints & QPainter::Antialiasing) && !multisamplingAlwaysEnabled; 1296 if (addOffset != newAddOffset) { 1297 addOffset = newAddOffset; 1298 matrixDirty = true; 1299 } 1300 1301 if (snapToPixelGrid) { 1302 snapToPixelGrid = false; 1303 matrixDirty = true; 1304 } 1305 1306 const Qt::PenStyle penStyle = qpen_style(pen); 1307 const QBrush &penBrush = qpen_brush(pen); 1308 const bool opaque = penBrush.isOpaque() && s->opacity > 0.99; 1309 1310 transferMode(BrushDrawingMode); 1311 1312 // updateMatrix() is responsible for setting the inverse scale on 1313 // the strokers, so we need to call it here and not wait for 1314 // prepareForDraw() down below. 1315 updateMatrix(); 1316 1317 if (penStyle == Qt::SolidLine) { 1318 stroker.process(path, pen); 1319 1320 } else { // Some sort of dash 1321 dasher.process(path, pen); 1322 1323 QVectorPath dashStroke(dasher.points(), 1324 dasher.elementCount(), 1325 dasher.elementTypes()); 1326 stroker.process(dashStroke, pen); 1327 } 1328 1329 if (opaque) { 1330 prepareForDraw(opaque); 1331 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 1332 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, stroker.vertices()); 1333 glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2); 1334 1335 // QBrush b(Qt::green); 1336 // d->setBrush(&b); 1337 // d->prepareForDraw(true); 1338 // glDrawArrays(GL_LINE_STRIP, 0, d->stroker.vertexCount() / 2); 1339 1340 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 1341 1342 } else { 1343 qreal width = qpen_widthf(pen) / 2; 1344 if (width == 0) 1345 width = 0.5; 1346 qreal extra = pen.joinStyle() == Qt::MiterJoin 1347 ? qMax(pen.miterLimit() * width, width) 1348 : width; 1349 1350 if (pen.isCosmetic()) 1351 extra = extra * inverseScale; 1352 1353 QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra); 1354 1355 fillStencilWithVertexArray(stroker.vertices(), stroker.vertexCount() / 2, 1356 0, 0, bounds, QGL2PaintEngineExPrivate::TriStripStrokeFillMode); 1357 1358 glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); 1359 1360 // Pass when any bit is set, replace stencil value with 0 1361 glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); 1362 prepareForDraw(false); 1363 1364 // Stencil the brush onto the dest buffer 1365 composite(bounds); 1366 1367 glStencilMask(0); 1368 1369 updateClipScissorTest(); 1370 } 1371 } 1372 1373 void QGL2PaintEngineEx::penChanged() { } 1374 void QGL2PaintEngineEx::brushChanged() { } 1375 void QGL2PaintEngineEx::brushOriginChanged() { } 815 1376 816 1377 void QGL2PaintEngineEx::opacityChanged() … … 818 1379 // qDebug("QGL2PaintEngineEx::opacityChanged()"); 819 1380 Q_D(QGL2PaintEngineEx); 1381 state()->opacityChanged = true; 820 1382 821 1383 Q_ASSERT(d->shaderManager); 822 d->shaderManager->setUseGlobalOpacity(state()->opacity > 0.999);823 1384 d->brushUniformsDirty = true; 1385 d->opacityUniformDirty = true; 824 1386 } 825 1387 … … 828 1390 // qDebug("QGL2PaintEngineEx::compositionModeChanged()"); 829 1391 Q_D(QGL2PaintEngineEx); 1392 state()->compositionModeChanged = true; 830 1393 d->compositionModeDirty = true; 831 1394 } … … 833 1396 void QGL2PaintEngineEx::renderHintsChanged() 834 1397 { 1398 state()->renderHintsChanged = true; 1399 1400 #if !defined(QT_OPENGL_ES_2) 1401 if ((state()->renderHints & QPainter::Antialiasing) 1402 || (state()->renderHints & QPainter::HighQualityAntialiasing)) 1403 glEnable(GL_MULTISAMPLE); 1404 else 1405 glDisable(GL_MULTISAMPLE); 1406 #endif 1407 1408 Q_D(QGL2PaintEngineEx); 1409 d->lastTextureUsed = GLuint(-1); 1410 d->brushTextureDirty = true; 835 1411 // qDebug("QGL2PaintEngineEx::renderHintsChanged() not implemented!"); 836 1412 } … … 840 1416 Q_D(QGL2PaintEngineEx); 841 1417 d->matrixDirty = true; 1418 state()->matrixChanged = true; 842 1419 } 843 1420 … … 846 1423 { 847 1424 Q_D(QGL2PaintEngineEx); 848 glActiveTexture(QT_BRUSH_TEXTURE_UNIT); 849 850 d->ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, true); 851 852 //FIXME: we should use hasAlpha() instead, but that's SLOW at the moment 853 if ((state()->opacity < 0.99f) || pixmap.hasAlphaChannel()) 854 glEnable(GL_BLEND); 855 else 856 glDisable(GL_BLEND); 857 858 d->drawTexture(dest, src, pixmap.width(), pixmap.height()); 1425 ensureActive(); 1426 d->transferMode(ImageDrawingMode); 1427 1428 QGLContext *ctx = d->ctx; 1429 glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); 1430 QGLTexture *texture = 1431 ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, 1432 QGLContext::InternalBindOption 1433 | QGLContext::CanFlipNativePixmapBindOption); 1434 1435 GLfloat top = texture->options & QGLContext::InvertedYBindOption ? (pixmap.height() - src.top()) : src.top(); 1436 GLfloat bottom = texture->options & QGLContext::InvertedYBindOption ? (pixmap.height() - src.bottom()) : src.bottom(); 1437 QGLRect srcRect(src.left(), top, src.right(), bottom); 1438 1439 bool isBitmap = pixmap.isQBitmap(); 1440 bool isOpaque = !isBitmap && !pixmap.hasAlphaChannel(); 1441 1442 d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, 1443 state()->renderHints & QPainter::SmoothPixmapTransform, texture->id); 1444 d->drawTexture(dest, srcRect, pixmap.size(), isOpaque, isBitmap); 859 1445 } 860 1446 … … 863 1449 { 864 1450 Q_D(QGL2PaintEngineEx); 865 glActiveTexture(QT_BRUSH_TEXTURE_UNIT); 866 d->ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true); 867 868 if ((state()->opacity < 0.99f) || image.hasAlphaChannel()) 869 glEnable(GL_BLEND); 870 else 871 glDisable(GL_BLEND); 872 873 d->drawTexture(dest, src, image.width(), image.height()); 1451 ensureActive(); 1452 d->transferMode(ImageDrawingMode); 1453 1454 QGLContext *ctx = d->ctx; 1455 glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); 1456 QGLTexture *texture = ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption); 1457 GLuint id = texture->id; 1458 1459 d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, 1460 state()->renderHints & QPainter::SmoothPixmapTransform, id); 1461 d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel()); 1462 } 1463 1464 void QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src) 1465 { 1466 Q_D(QGL2PaintEngineEx); 1467 ensureActive(); 1468 d->transferMode(ImageDrawingMode); 1469 1470 #ifndef QT_OPENGL_ES_2 1471 QGLContext *ctx = d->ctx; 1472 #endif 1473 glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); 1474 glBindTexture(GL_TEXTURE_2D, textureId); 1475 1476 QGLRect srcRect(src.left(), src.bottom(), src.right(), src.top()); 1477 1478 d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, 1479 state()->renderHints & QPainter::SmoothPixmapTransform, textureId); 1480 d->drawTexture(dest, srcRect, size, false); 874 1481 } 875 1482 876 1483 void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem) 877 1484 { 878 QOpenGLPaintEngineState *s = state(); 1485 Q_D(QGL2PaintEngineEx); 1486 1487 ensureActive(); 1488 QOpenGL2PaintEngineState *s = state(); 879 1489 880 1490 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); 881 1491 882 bool drawCached = true; 883 884 if (state()->pen.brush().style() != Qt::SolidPattern) 1492 QTransform::TransformationType txtype = s->matrix.type(); 1493 1494 float det = s->matrix.determinant(); 1495 bool drawCached = txtype < QTransform::TxProject; 1496 1497 // don't try to cache huge fonts or vastly transformed fonts 1498 const qreal pixelSize = ti.fontEngine->fontDef.pixelSize; 1499 if (pixelSize * pixelSize * qAbs(det) >= 64 * 64 || det < 0.25f || det > 4.f) 885 1500 drawCached = false; 886 1501 887 if (s->matrix.type() > QTransform::TxTranslate) 1502 QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 1503 ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat) 1504 : d->glyphCacheType; 1505 1506 if (txtype > QTransform::TxTranslate) 1507 glyphType = QFontEngineGlyphCache::Raster_A8; 1508 1509 if (glyphType == QFontEngineGlyphCache::Raster_RGBMask 1510 && state()->composition_mode != QPainter::CompositionMode_Source 1511 && state()->composition_mode != QPainter::CompositionMode_SourceOver) 1512 { 888 1513 drawCached = false; 889 890 // don't try to cache huge fonts 891 if (ti.fontEngine->fontDef.pixelSize * qSqrt(s->matrix.determinant()) >= 64) 892 drawCached = false; 1514 } 893 1515 894 1516 if (drawCached) { 895 d rawCachedGlyphs(p, ti);1517 d->drawCachedGlyphs(p, glyphType, ti); 896 1518 return; 897 1519 } … … 900 1522 } 901 1523 902 void QGL2PaintEngineEx ::drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti)903 { 904 Q_D(QGL2PaintEngineEx); 905 Q OpenGLPaintEngineState *s = state();1524 void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType, 1525 const QTextItemInt &ti) 1526 { 1527 Q_Q(QGL2PaintEngineEx); 906 1528 907 1529 QVarLengthArray<QFixedPoint> positions; 908 1530 QVarLengthArray<glyph_t> glyphs; 909 QTransform matrix; 910 matrix.translate(p.x(), p.y()); 1531 QTransform matrix = QTransform::fromTranslate(p.x(), p.y()); 911 1532 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); 912 1533 913 QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 914 ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat) 915 : QFontEngineGlyphCache::Raster_A8; 916 917 QImageTextureGlyphCache *cache = 918 (QImageTextureGlyphCache *) ti.fontEngine->glyphCache(glyphType, s->matrix); 919 if (!cache) { 920 cache = new QImageTextureGlyphCache(glyphType, s->matrix); 921 ti.fontEngine->setGlyphCache(glyphType, cache); 922 } 923 1534 QGLTextureGlyphCache *cache = 1535 (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, glyphType, QTransform()); 1536 1537 if (!cache || cache->cacheType() != glyphType) { 1538 cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform()); 1539 ti.fontEngine->setGlyphCache(ctx, cache); 1540 } 1541 1542 cache->setPaintEnginePrivate(this); 924 1543 cache->populate(ti, glyphs, positions); 925 1544 926 const QImage &image = cache->image(); 1545 if (cache->width() == 0 || cache->height() == 0) 1546 return; 1547 1548 transferMode(TextDrawingMode); 1549 927 1550 int margin = cache->glyphMargin(); 928 1551 929 glActiveTexture(QT_BRUSH_TEXTURE_UNIT); 930 d->ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true); 931 932 glEnable(GL_BLEND); 933 934 d->shaderManager->textShader()->use(); 935 d->updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); 936 937 if (d->compositionModeDirty) 938 d->updateCompositionMode(); 939 940 if (d->matrixDirty) 941 d->updateMatrix(); 942 943 if (d->textShaderMatrixUniformDirty) { 944 d->shaderManager->textShader()->uniforms()[QLatin1String("pmvMatrix")] = d->pmvMatrix; 945 d->textShaderMatrixUniformDirty = false; 946 } 947 948 d->shaderManager->textShader()->uniforms()[QLatin1String("textureSampler")] = QT_BRUSH_TEXTURE_UNIT; 949 QColor col = d->premultiplyColor(state()->pen.color(), (GLfloat)state()->opacity); 950 d->shaderManager->textShader()->uniforms()[QLatin1String("fragmentColor")] = col; 951 952 GLfloat dx = 1.0 / image.width(); 953 GLfloat dy = 1.0 / image.height(); 954 955 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 956 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); 1552 GLfloat dx = 1.0 / cache->width(); 1553 GLfloat dy = 1.0 / cache->height(); 1554 1555 QGLPoint *oldVertexCoordinateDataPtr = vertexCoordinateArray.data(); 1556 QGLPoint *oldTextureCoordinateDataPtr = textureCoordinateArray.data(); 1557 1558 vertexCoordinateArray.clear(); 1559 textureCoordinateArray.clear(); 1560 957 1561 for (int i=0; i<glyphs.size(); ++i) { 958 1562 const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]); … … 960 1564 int y = positions[i].y.toInt() - c.baseLineY - margin; 961 1565 962 QGLRect dest = QRectF(x, y, c.w, c.h); 963 QGLRect src = QRectF(c.x, c.y, c.w, c.h); 964 965 GLfloat vertexCoords[] = { 966 dest.left, dest.top, 967 dest.left, dest.bottom, 968 dest.right, dest.bottom, 969 dest.right, dest.top 970 }; 971 972 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords); 973 974 QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy); 975 976 GLfloat textureCoords[] = { 977 srcTextureRect.left, srcTextureRect.top, 978 srcTextureRect.left, srcTextureRect.bottom, 979 srcTextureRect.right, srcTextureRect.bottom, 980 srcTextureRect.right, srcTextureRect.top 981 }; 982 983 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoords); 984 985 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 986 } 987 glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); 988 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 1566 vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h)); 1567 textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); 1568 } 1569 1570 if (vertexCoordinateArray.data() != oldVertexCoordinateDataPtr) 1571 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data()); 1572 if (textureCoordinateArray.data() != oldTextureCoordinateDataPtr) 1573 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data()); 1574 1575 if (addOffset) { 1576 addOffset = false; 1577 matrixDirty = true; 1578 } 1579 if (!snapToPixelGrid) { 1580 snapToPixelGrid = true; 1581 matrixDirty = true; 1582 } 1583 1584 QBrush pensBrush = q->state()->pen.brush(); 1585 setBrush(pensBrush); 1586 1587 if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) { 1588 1589 // Subpixel antialiasing without gamma correction 1590 1591 QPainter::CompositionMode compMode = q->state()->composition_mode; 1592 Q_ASSERT(compMode == QPainter::CompositionMode_Source 1593 || compMode == QPainter::CompositionMode_SourceOver); 1594 1595 shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMaskPass1); 1596 1597 if (pensBrush.style() == Qt::SolidPattern) { 1598 // Solid patterns can get away with only one pass. 1599 QColor c = pensBrush.color(); 1600 qreal oldOpacity = q->state()->opacity; 1601 if (compMode == QPainter::CompositionMode_Source) { 1602 c = qt_premultiplyColor(c, q->state()->opacity); 1603 q->state()->opacity = 1; 1604 opacityUniformDirty = true; 1605 } 1606 1607 compositionModeDirty = false; // I can handle this myself, thank you very much 1608 prepareForDraw(false); // Text always causes src pixels to be transparent 1609 1610 // prepareForDraw() have set the opacity on the current shader, so the opacity state can now be reset. 1611 if (compMode == QPainter::CompositionMode_Source) { 1612 q->state()->opacity = oldOpacity; 1613 opacityUniformDirty = true; 1614 } 1615 1616 glEnable(GL_BLEND); 1617 glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR); 1618 glBlendColor(c.redF(), c.greenF(), c.blueF(), c.alphaF()); 1619 } else { 1620 // Other brush styles need two passes. 1621 1622 qreal oldOpacity = q->state()->opacity; 1623 if (compMode == QPainter::CompositionMode_Source) { 1624 q->state()->opacity = 1; 1625 opacityUniformDirty = true; 1626 pensBrush = Qt::white; 1627 setBrush(pensBrush); 1628 } 1629 1630 compositionModeDirty = false; // I can handle this myself, thank you very much 1631 prepareForDraw(false); // Text always causes src pixels to be transparent 1632 glEnable(GL_BLEND); 1633 glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); 1634 1635 glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT); 1636 glBindTexture(GL_TEXTURE_2D, cache->texture()); 1637 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); 1638 1639 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT); 1640 glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size()); 1641 1642 shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMaskPass2); 1643 1644 if (compMode == QPainter::CompositionMode_Source) { 1645 q->state()->opacity = oldOpacity; 1646 opacityUniformDirty = true; 1647 pensBrush = q->state()->pen.brush(); 1648 setBrush(pensBrush); 1649 } 1650 1651 compositionModeDirty = false; 1652 prepareForDraw(false); // Text always causes src pixels to be transparent 1653 glEnable(GL_BLEND); 1654 glBlendFunc(GL_ONE, GL_ONE); 1655 } 1656 compositionModeDirty = true; 1657 } else { 1658 // Greyscale/mono glyphs 1659 1660 shaderManager->setMaskType(QGLEngineShaderManager::PixelMask); 1661 prepareForDraw(false); // Text always causes src pixels to be transparent 1662 } 1663 //### TODO: Gamma correction 1664 1665 glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT); 1666 glBindTexture(GL_TEXTURE_2D, cache->texture()); 1667 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); 1668 1669 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT); 1670 glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size()); 1671 } 1672 1673 void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints) 1674 { 1675 Q_D(QGL2PaintEngineEx); 1676 // Use fallback for extended composition modes. 1677 if (state()->composition_mode > QPainter::CompositionMode_Plus) { 1678 QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints); 1679 return; 1680 } 1681 1682 ensureActive(); 1683 d->drawPixmaps(drawingData, dataCount, pixmap, hints); 1684 } 1685 1686 1687 void QGL2PaintEngineExPrivate::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints) 1688 { 1689 GLfloat dx = 1.0f / pixmap.size().width(); 1690 GLfloat dy = 1.0f / pixmap.size().height(); 1691 1692 vertexCoordinateArray.clear(); 1693 textureCoordinateArray.clear(); 1694 opacityArray.reset(); 1695 1696 if (addOffset) { 1697 addOffset = false; 1698 matrixDirty = true; 1699 } 1700 1701 if (snapToPixelGrid) { 1702 snapToPixelGrid = false; 1703 matrixDirty = true; 1704 } 1705 1706 bool allOpaque = true; 1707 1708 for (int i = 0; i < dataCount; ++i) { 1709 qreal s = 0; 1710 qreal c = 1; 1711 if (drawingData[i].rotation != 0) { 1712 s = qFastSin(drawingData[i].rotation * Q_PI / 180); 1713 c = qFastCos(drawingData[i].rotation * Q_PI / 180); 1714 } 1715 1716 qreal right = 0.5 * drawingData[i].scaleX * drawingData[i].source.width(); 1717 qreal bottom = 0.5 * drawingData[i].scaleY * drawingData[i].source.height(); 1718 QGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c); 1719 QGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c); 1720 1721 vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y()); 1722 vertexCoordinateArray.lineToArray(-bottomLeft.x + drawingData[i].point.x(), -bottomLeft.y + drawingData[i].point.y()); 1723 vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y()); 1724 vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y()); 1725 vertexCoordinateArray.lineToArray(bottomLeft.x + drawingData[i].point.x(), bottomLeft.y + drawingData[i].point.y()); 1726 vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y()); 1727 1728 QGLRect src(drawingData[i].source.left() * dx, drawingData[i].source.top() * dy, 1729 drawingData[i].source.right() * dx, drawingData[i].source.bottom() * dy); 1730 1731 textureCoordinateArray.lineToArray(src.right, src.bottom); 1732 textureCoordinateArray.lineToArray(src.right, src.top); 1733 textureCoordinateArray.lineToArray(src.left, src.top); 1734 textureCoordinateArray.lineToArray(src.left, src.top); 1735 textureCoordinateArray.lineToArray(src.left, src.bottom); 1736 textureCoordinateArray.lineToArray(src.right, src.bottom); 1737 1738 qreal opacity = drawingData[i].opacity * q->state()->opacity; 1739 opacityArray << opacity << opacity << opacity << opacity << opacity << opacity; 1740 allOpaque &= (opacity >= 0.99f); 1741 } 1742 1743 glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); 1744 QGLTexture *texture = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, 1745 QGLContext::InternalBindOption 1746 | QGLContext::CanFlipNativePixmapBindOption); 1747 1748 if (texture->options & QGLContext::InvertedYBindOption) { 1749 // Flip texture y-coordinate. 1750 QGLPoint *data = textureCoordinateArray.data(); 1751 for (int i = 0; i < 6 * dataCount; ++i) 1752 data[i].y = 1 - data[i].y; 1753 } 1754 1755 transferMode(ImageArrayDrawingMode); 1756 1757 bool isBitmap = pixmap.isQBitmap(); 1758 bool isOpaque = !isBitmap && (!pixmap.hasAlphaChannel() || (hints & QDrawPixmaps::OpaqueHint)) && allOpaque; 1759 1760 updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, 1761 q->state()->renderHints & QPainter::SmoothPixmapTransform, texture->id); 1762 1763 // Setup for texture drawing 1764 currentBrush = noBrush; 1765 shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc); 1766 if (prepareForDraw(isOpaque)) 1767 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT); 1768 1769 if (isBitmap) { 1770 QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity); 1771 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col); 1772 } 1773 1774 glDrawArrays(GL_TRIANGLES, 0, 6 * dataCount); 989 1775 } 990 1776 … … 994 1780 995 1781 // qDebug("QGL2PaintEngineEx::begin()"); 996 997 QGLWidget* widget = static_cast<QGLWidget*>(pdev); 998 d->ctx = const_cast<QGLContext*>(widget->context()); 999 d->ctx->makeCurrent(); 1000 d->width = widget->width(); 1001 d->height = widget->height(); 1002 1003 if (!d->shaderManager) 1004 d->shaderManager = new QGLPEXShaderManager(d->ctx); 1005 1006 glViewport(0, 0, d->width, d->height); 1007 1008 // glClearColor(0.0, 1.0, 0.0, 1.0); 1009 // glClear(GL_COLOR_BUFFER_BIT); 1010 // d->ctx->swapBuffers(); 1011 // qDebug("You should see green now"); 1012 // sleep(5); 1013 1782 if (pdev->devType() == QInternal::OpenGL) 1783 d->device = static_cast<QGLPaintDevice*>(pdev); 1784 else 1785 d->device = QGLPaintDevice::getDevice(pdev); 1786 1787 if (!d->device) 1788 return false; 1789 1790 d->ctx = d->device->context(); 1791 d->ctx->d_ptr->active_engine = this; 1792 1793 const QSize sz = d->device->size(); 1794 d->width = sz.width(); 1795 d->height = sz.height(); 1796 d->mode = BrushDrawingMode; 1014 1797 d->brushTextureDirty = true; 1015 1798 d->brushUniformsDirty = true; 1016 1799 d->matrixDirty = true; 1017 1800 d->compositionModeDirty = true; 1018 d->stencilBuferDirty = true; 1019 1020 d->use_system_clip = !systemClip().isEmpty(); 1021 1801 d->opacityUniformDirty = true; 1802 d->needsSync = true; 1803 d->useSystemClip = !systemClip().isEmpty(); 1804 d->currentBrush = QBrush(); 1805 1806 d->dirtyStencilRegion = QRect(0, 0, d->width, d->height); 1807 d->stencilClean = true; 1808 1809 // Calling begin paint should make the correct context current. So, any 1810 // code which calls into GL or otherwise needs a current context *must* 1811 // go after beginPaint: 1812 d->device->beginPaint(); 1813 1814 #if !defined(QT_OPENGL_ES_2) 1815 bool success = qt_resolve_version_2_0_functions(d->ctx) 1816 && qt_resolve_buffer_extensions(d->ctx); 1817 Q_ASSERT(success); 1818 Q_UNUSED(success); 1819 #endif 1820 1821 d->shaderManager = new QGLEngineShaderManager(d->ctx); 1822 1823 glDisable(GL_STENCIL_TEST); 1022 1824 glDisable(GL_DEPTH_TEST); 1825 glDisable(GL_SCISSOR_TEST); 1826 1827 #if !defined(QT_OPENGL_ES_2) 1828 glDisable(GL_MULTISAMPLE); 1829 #endif 1830 1831 d->glyphCacheType = QFontEngineGlyphCache::Raster_A8; 1832 1833 #if !defined(QT_OPENGL_ES_2) 1834 #if defined(Q_WS_WIN) 1835 if (qt_cleartype_enabled) 1836 #endif 1837 d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask; 1838 #endif 1839 1840 #if defined(QT_OPENGL_ES_2) 1841 // OpenGL ES can't switch MSAA off, so if the gl paint device is 1842 // multisampled, it's always multisampled. 1843 d->multisamplingAlwaysEnabled = d->device->format().sampleBuffers(); 1844 #else 1845 d->multisamplingAlwaysEnabled = false; 1846 #endif 1023 1847 1024 1848 return true; … … 1028 1852 { 1029 1853 Q_D(QGL2PaintEngineEx); 1030 d->ctx->swapBuffers(); 1854 QGLContext *ctx = d->ctx; 1855 1856 glUseProgram(0); 1857 d->transferMode(BrushDrawingMode); 1858 d->device->endPaint(); 1859 1860 #if defined(Q_WS_X11) 1861 // On some (probably all) drivers, deleting an X pixmap which has been bound to a texture 1862 // before calling glFinish/swapBuffers renders garbage. Presumably this is because X deletes 1863 // the pixmap behind the driver's back before it's had a chance to use it. To fix this, we 1864 // reference all QPixmaps which have been bound to stop them being deleted and only deref 1865 // them here, after swapBuffers, where they can be safely deleted. 1866 ctx->d_func()->boundPixmaps.clear(); 1867 #endif 1868 d->ctx->d_ptr->active_engine = 0; 1869 1870 d->resetGLState(); 1871 1872 delete d->shaderManager; 1873 d->shaderManager = 0; 1874 1875 #ifdef QT_OPENGL_CACHE_AS_VBOS 1876 if (!d->unusedVBOSToClean.isEmpty()) { 1877 glDeleteBuffers(d->unusedVBOSToClean.size(), d->unusedVBOSToClean.constData()); 1878 d->unusedVBOSToClean.clear(); 1879 } 1880 #endif 1881 1031 1882 return false; 1032 1883 } 1033 1884 1034 1035 /////////////////////////////////// State/Clipping stolen from QOpenGLPaintEngine ////////////////////////////////////////// 1885 void QGL2PaintEngineEx::ensureActive() 1886 { 1887 Q_D(QGL2PaintEngineEx); 1888 QGLContext *ctx = d->ctx; 1889 1890 if (isActive() && ctx->d_ptr->active_engine != this) { 1891 ctx->d_ptr->active_engine = this; 1892 d->needsSync = true; 1893 } 1894 1895 d->device->ensureActiveTarget(); 1896 1897 if (d->needsSync) { 1898 d->transferMode(BrushDrawingMode); 1899 glViewport(0, 0, d->width, d->height); 1900 d->needsSync = false; 1901 d->shaderManager->setDirty(); 1902 setState(state()); 1903 } 1904 } 1905 1906 void QGL2PaintEngineExPrivate::updateClipScissorTest() 1907 { 1908 Q_Q(QGL2PaintEngineEx); 1909 if (q->state()->clipTestEnabled) { 1910 glEnable(GL_STENCIL_TEST); 1911 glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); 1912 } else { 1913 glDisable(GL_STENCIL_TEST); 1914 glStencilFunc(GL_ALWAYS, 0, 0xff); 1915 } 1916 1917 #ifdef QT_GL_NO_SCISSOR_TEST 1918 currentScissorBounds = QRect(0, 0, width, height); 1919 #else 1920 QRect bounds = q->state()->rectangleClip; 1921 if (!q->state()->clipEnabled) { 1922 if (useSystemClip) 1923 bounds = systemClip.boundingRect(); 1924 else 1925 bounds = QRect(0, 0, width, height); 1926 } else { 1927 if (useSystemClip) 1928 bounds = bounds.intersected(systemClip.boundingRect()); 1929 else 1930 bounds = bounds.intersected(QRect(0, 0, width, height)); 1931 } 1932 1933 currentScissorBounds = bounds; 1934 1935 if (bounds == QRect(0, 0, width, height)) { 1936 glDisable(GL_SCISSOR_TEST); 1937 } else { 1938 glEnable(GL_SCISSOR_TEST); 1939 setScissor(bounds); 1940 } 1941 #endif 1942 } 1943 1944 void QGL2PaintEngineExPrivate::setScissor(const QRect &rect) 1945 { 1946 const int left = rect.left(); 1947 const int width = rect.width(); 1948 const int bottom = height - (rect.top() + rect.height()); 1949 const int height = rect.height(); 1950 1951 glScissor(left, bottom, width, height); 1952 } 1036 1953 1037 1954 void QGL2PaintEngineEx::clipEnabledChanged() … … 1039 1956 Q_D(QGL2PaintEngineEx); 1040 1957 1041 d->updateDepthClip(); 1958 state()->clipChanged = true; 1959 1960 if (painter()->hasClipping()) 1961 d->regenerateClip(); 1962 else 1963 d->systemStateChanged(); 1964 } 1965 1966 void QGL2PaintEngineExPrivate::clearClip(uint value) 1967 { 1968 dirtyStencilRegion -= currentScissorBounds; 1969 1970 glStencilMask(0xff); 1971 glClearStencil(value); 1972 glClear(GL_STENCIL_BUFFER_BIT); 1973 glStencilMask(0x0); 1974 1975 q->state()->needsClipBufferClear = false; 1976 } 1977 1978 void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint value) 1979 { 1980 transferMode(BrushDrawingMode); 1981 1982 if (addOffset) { 1983 addOffset = false; 1984 matrixDirty = true; 1985 } 1986 if (snapToPixelGrid) { 1987 snapToPixelGrid = false; 1988 matrixDirty = true; 1989 } 1990 1991 if (matrixDirty) 1992 updateMatrix(); 1993 1994 stencilClean = false; 1995 1996 const bool singlePass = !path.hasWindingFill() 1997 && (((q->state()->currentClip == maxClip - 1) && q->state()->clipTestEnabled) 1998 || q->state()->needsClipBufferClear); 1999 const uint referenceClipValue = q->state()->needsClipBufferClear ? 1 : q->state()->currentClip; 2000 2001 if (q->state()->needsClipBufferClear) 2002 clearClip(1); 2003 2004 if (path.isEmpty()) { 2005 glEnable(GL_STENCIL_TEST); 2006 glStencilFunc(GL_LEQUAL, value, ~GL_STENCIL_HIGH_BIT); 2007 return; 2008 } 2009 2010 if (q->state()->clipTestEnabled) 2011 glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); 2012 else 2013 glStencilFunc(GL_ALWAYS, 0, 0xff); 2014 2015 vertexCoordinateArray.clear(); 2016 vertexCoordinateArray.addPath(path, inverseScale, false); 2017 2018 if (!singlePass) 2019 fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill()); 2020 2021 glColorMask(false, false, false, false); 2022 glEnable(GL_STENCIL_TEST); 2023 useSimpleShader(); 2024 2025 if (singlePass) { 2026 // Under these conditions we can set the new stencil value in a single 2027 // pass, by using the current value and the "new value" as the toggles 2028 2029 glStencilFunc(GL_LEQUAL, referenceClipValue, ~GL_STENCIL_HIGH_BIT); 2030 glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT); 2031 glStencilMask(value ^ referenceClipValue); 2032 2033 drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN); 2034 } else { 2035 glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); 2036 glStencilMask(0xff); 2037 2038 if (!q->state()->clipTestEnabled && path.hasWindingFill()) { 2039 // Pass when any clip bit is set, set high bit 2040 glStencilFunc(GL_NOTEQUAL, GL_STENCIL_HIGH_BIT, ~GL_STENCIL_HIGH_BIT); 2041 composite(vertexCoordinateArray.boundingRect()); 2042 } 2043 2044 // Pass when high bit is set, replace stencil value with new clip value 2045 glStencilFunc(GL_NOTEQUAL, value, GL_STENCIL_HIGH_BIT); 2046 2047 composite(vertexCoordinateArray.boundingRect()); 2048 } 2049 2050 glStencilFunc(GL_LEQUAL, value, ~GL_STENCIL_HIGH_BIT); 2051 glStencilMask(0); 2052 2053 glColorMask(true, true, true, true); 1042 2054 } 1043 2055 … … 1045 2057 { 1046 2058 // qDebug("QGL2PaintEngineEx::clip()"); 1047 const qreal *points = path.points();1048 const QPainterPath::ElementType *types = path.elements();1049 if (!types && path.shape() == QVectorPath::RectangleHint) {1050 QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);1051 updateClipRegion(QRegion(r.toRect()), op);1052 return;1053 }1054 1055 QPainterPath p;1056 if (types) {1057 int id = 0;1058 for (int i=0; i<path.elementCount(); ++i) {1059 switch(types[i]) {1060 case QPainterPath::MoveToElement:1061 p.moveTo(QPointF(points[id], points[id+1]));1062 id+=2;1063 break;1064 case QPainterPath::LineToElement:1065 p.lineTo(QPointF(points[id], points[id+1]));1066 id+=2;1067 break;1068 case QPainterPath::CurveToElement: {1069 QPointF p1(points[id], points[id+1]);1070 QPointF p2(points[id+2], points[id+3]);1071 QPointF p3(points[id+4], points[id+5]);1072 p.cubicTo(p1, p2, p3);1073 id+=6;1074 break;1075 }1076 case QPainterPath::CurveToDataElement:1077 ;1078 break;1079 }1080 }1081 } else if (!path.isEmpty()) {1082 p.moveTo(QPointF(points[0], points[1]));1083 int id = 2;1084 for (int i=1; i<path.elementCount(); ++i) {1085 p.lineTo(QPointF(points[id], points[id+1]));1086 id+=2;1087 }1088 }1089 if (path.hints() & QVectorPath::WindingFill)1090 p.setFillRule(Qt::WindingFill);1091 1092 updateClipRegion(QRegion(p.toFillPolygon().toPolygon(), p.fillRule()), op);1093 return;1094 }1095 1096 void QGL2PaintEngineEx::updateClipRegion(const QRegion &clipRegion, Qt::ClipOperation op)1097 {1098 // qDebug("QGL2PaintEngineEx::updateClipRegion()");1099 2059 Q_D(QGL2PaintEngineEx); 1100 2060 1101 QRegion sysClip = systemClip();1102 if (op == Qt::NoClip && !d->use_system_clip) { 1103 state()->hasClipping = false;1104 state()->clipRegion = QRegion(); 1105 d->updateDepthClip();1106 return;1107 }1108 1109 bool isScreenClip = false;1110 if (!d->use_system_clip) {1111 QVector<QRect> untransformedRects = clipRegion.rects();1112 1113 if (untransformedRects.size() == 1) { 1114 QPainterPath path;1115 path.addRect(untransformedRects[0]);1116 //path = d->matrix.map(path);1117 path = state()->matrix.map(path); 1118 1119 // if (path.contains(QRectF(QPointF(), d->drawable.size()))) 1120 // isScreenClip = true;1121 if (path.contains(QRectF(0.0, 0.0, d->width, d->height)))1122 isScreenClip = true;1123 1124 } 1125 1126 // QRegion region = isScreenClip ? QRegion() : clipRegion * d->matrix;1127 QRegion region = isScreenClip ? QRegion() : clipRegion * state()->matrix; 2061 state()->clipChanged = true; 2062 2063 ensureActive(); 2064 2065 if (op == Qt::ReplaceClip) { 2066 op = Qt::IntersectClip; 2067 if (d->hasClipOperations()) { 2068 d->systemStateChanged(); 2069 state()->canRestoreClip = false; 2070 } 2071 } 2072 2073 #ifndef QT_GL_NO_SCISSOR_TEST 2074 if (!path.isEmpty() && op == Qt::IntersectClip && (path.shape() == QVectorPath::RectangleHint)) { 2075 const QPointF* const points = reinterpret_cast<const QPointF*>(path.points()); 2076 QRectF rect(points[0], points[2]); 2077 2078 if (state()->matrix.type() <= QTransform::TxScale) { 2079 state()->rectangleClip = state()->rectangleClip.intersected(state()->matrix.mapRect(rect).toRect()); 2080 d->updateClipScissorTest(); 2081 return; 2082 } 2083 } 2084 #endif 2085 2086 const QRect pathRect = state()->matrix.mapRect(path.controlPointRect()).toAlignedRect(); 2087 1128 2088 switch (op) { 1129 2089 case Qt::NoClip: 1130 if (!d->use_system_clip) 1131 break; 1132 state()->clipRegion = sysClip; 2090 if (d->useSystemClip) { 2091 state()->clipTestEnabled = true; 2092 state()->currentClip = 1; 2093 } else { 2094 state()->clipTestEnabled = false; 2095 } 2096 state()->rectangleClip = QRect(0, 0, d->width, d->height); 2097 state()->canRestoreClip = false; 2098 d->updateClipScissorTest(); 1133 2099 break; 1134 2100 case Qt::IntersectClip: 1135 if (isScreenClip) 1136 return; 1137 if (state()->hasClipping) { 1138 state()->clipRegion &= region; 1139 break; 1140 } 1141 // fall through 1142 case Qt::ReplaceClip: 1143 if (d->use_system_clip && !sysClip.isEmpty()) 1144 state()->clipRegion = region & sysClip; 1145 else 1146 state()->clipRegion = region; 2101 state()->rectangleClip = state()->rectangleClip.intersected(pathRect); 2102 d->updateClipScissorTest(); 2103 d->resetClipIfNeeded(); 2104 ++d->maxClip; 2105 d->writeClip(path, d->maxClip); 2106 state()->currentClip = d->maxClip; 2107 state()->clipTestEnabled = true; 1147 2108 break; 1148 case Qt::UniteClip: 1149 state()->clipRegion |= region; 1150 if (d->use_system_clip && !sysClip.isEmpty()) 1151 state()->clipRegion &= sysClip; 2109 case Qt::UniteClip: { 2110 d->resetClipIfNeeded(); 2111 ++d->maxClip; 2112 if (state()->rectangleClip.isValid()) { 2113 QPainterPath path; 2114 path.addRect(state()->rectangleClip); 2115 2116 // flush the existing clip rectangle to the depth buffer 2117 d->writeClip(qtVectorPathForPath(state()->matrix.inverted().map(path)), d->maxClip); 2118 } 2119 2120 state()->clipTestEnabled = false; 2121 #ifndef QT_GL_NO_SCISSOR_TEST 2122 QRect oldRectangleClip = state()->rectangleClip; 2123 2124 state()->rectangleClip = state()->rectangleClip.united(pathRect); 2125 d->updateClipScissorTest(); 2126 2127 QRegion extendRegion = QRegion(state()->rectangleClip) - oldRectangleClip; 2128 2129 if (!extendRegion.isEmpty()) { 2130 QPainterPath extendPath; 2131 extendPath.addRegion(extendRegion); 2132 2133 // first clear the depth buffer in the extended region 2134 d->writeClip(qtVectorPathForPath(state()->matrix.inverted().map(extendPath)), 0); 2135 } 2136 #endif 2137 // now write the clip path 2138 d->writeClip(path, d->maxClip); 2139 state()->canRestoreClip = false; 2140 state()->currentClip = d->maxClip; 2141 state()->clipTestEnabled = true; 1152 2142 break; 2143 } 1153 2144 default: 1154 2145 break; 1155 2146 } 1156 1157 if (isScreenClip) { 1158 state()->hasClipping = false; 1159 state()->clipRegion = QRegion(); 2147 } 2148 2149 void QGL2PaintEngineExPrivate::regenerateClip() 2150 { 2151 systemStateChanged(); 2152 replayClipOperations(); 2153 } 2154 2155 void QGL2PaintEngineExPrivate::systemStateChanged() 2156 { 2157 Q_Q(QGL2PaintEngineEx); 2158 2159 q->state()->clipChanged = true; 2160 2161 if (systemClip.isEmpty()) { 2162 useSystemClip = false; 1160 2163 } else { 1161 state()->hasClipping = op != Qt::NoClip || d->use_system_clip; 1162 } 1163 1164 if (state()->hasClipping && state()->clipRegion.rects().size() == 1) 1165 state()->fastClip = state()->clipRegion.rects().at(0); 2164 if (q->paintDevice()->devType() == QInternal::Widget && currentClipWidget) { 2165 QWidgetPrivate *widgetPrivate = qt_widget_private(currentClipWidget->window()); 2166 useSystemClip = widgetPrivate->extra && widgetPrivate->extra->inRenderWithPainter; 2167 } else { 2168 useSystemClip = true; 2169 } 2170 } 2171 2172 q->state()->clipTestEnabled = false; 2173 q->state()->needsClipBufferClear = true; 2174 2175 q->state()->currentClip = 1; 2176 maxClip = 1; 2177 2178 q->state()->rectangleClip = useSystemClip ? systemClip.boundingRect() : QRect(0, 0, width, height); 2179 updateClipScissorTest(); 2180 2181 if (systemClip.rectCount() == 1) { 2182 if (systemClip.boundingRect() == QRect(0, 0, width, height)) 2183 useSystemClip = false; 2184 #ifndef QT_GL_NO_SCISSOR_TEST 2185 // scissoring takes care of the system clip 2186 return; 2187 #endif 2188 } 2189 2190 if (useSystemClip) { 2191 clearClip(0); 2192 2193 QPainterPath path; 2194 path.addRegion(systemClip); 2195 2196 q->state()->currentClip = 0; 2197 writeClip(qtVectorPathForPath(q->state()->matrix.inverted().map(path)), 1); 2198 q->state()->currentClip = 1; 2199 q->state()->clipTestEnabled = true; 2200 } 2201 } 2202 2203 void QGL2PaintEngineEx::setState(QPainterState *new_state) 2204 { 2205 // qDebug("QGL2PaintEngineEx::setState()"); 2206 2207 Q_D(QGL2PaintEngineEx); 2208 2209 QOpenGL2PaintEngineState *s = static_cast<QOpenGL2PaintEngineState *>(new_state); 2210 QOpenGL2PaintEngineState *old_state = state(); 2211 2212 QPaintEngineEx::setState(s); 2213 2214 if (s->isNew) { 2215 // Newly created state object. The call to setState() 2216 // will either be followed by a call to begin(), or we are 2217 // setting the state as part of a save(). 2218 s->isNew = false; 2219 return; 2220 } 2221 2222 // Setting the state as part of a restore(). 2223 2224 if (old_state == s || old_state->renderHintsChanged) 2225 renderHintsChanged(); 2226 2227 if (old_state == s || old_state->matrixChanged) { 2228 d->matrixDirty = true; 2229 d->simpleShaderMatrixUniformDirty = true; 2230 d->shaderMatrixUniformDirty = true; 2231 } 2232 2233 if (old_state == s || old_state->compositionModeChanged) 2234 d->compositionModeDirty = true; 2235 2236 if (old_state == s || old_state->opacityChanged) 2237 d->opacityUniformDirty = true; 2238 2239 if (old_state == s || old_state->clipChanged) { 2240 if (old_state && old_state != s && old_state->canRestoreClip) { 2241 d->updateClipScissorTest(); 2242 glDepthFunc(GL_LEQUAL); 2243 } else { 2244 d->regenerateClip(); 2245 } 2246 } 2247 } 2248 2249 QPainterState *QGL2PaintEngineEx::createState(QPainterState *orig) const 2250 { 2251 if (orig) 2252 const_cast<QGL2PaintEngineEx *>(this)->ensureActive(); 2253 2254 QOpenGL2PaintEngineState *s; 2255 if (!orig) 2256 s = new QOpenGL2PaintEngineState(); 1166 2257 else 1167 state()->fastClip = QRect(); 1168 1169 d->updateDepthClip(); 1170 } 1171 1172 1173 void QGL2PaintEngineExPrivate::updateDepthClip() 1174 { 1175 // qDebug("QGL2PaintEngineExPrivate::updateDepthClip()"); 1176 1177 Q_Q(QGL2PaintEngineEx); 1178 1179 glDisable(GL_DEPTH_TEST); 1180 glDisable(GL_SCISSOR_TEST); 1181 1182 if (!q->state()->hasClipping) 1183 return; 1184 1185 QRect fastClip; 1186 if (q->state()->clipEnabled) { 1187 fastClip = q->state()->fastClip; 1188 } else if (use_system_clip && q->systemClip().rects().count() == 1) { 1189 fastClip = q->systemClip().rects().at(0); 1190 } 1191 1192 if (!fastClip.isEmpty()) { 1193 glEnable(GL_SCISSOR_TEST); 1194 1195 const int left = fastClip.left(); 1196 const int width = fastClip.width(); 1197 const int bottom = height - (fastClip.bottom() + 1); 1198 const int height = fastClip.height(); 1199 1200 glScissor(left, bottom, width, height); 1201 return; 1202 } 1203 1204 glClearDepthf(0x0); 1205 glDepthMask(true); 1206 glClear(GL_DEPTH_BUFFER_BIT); 1207 glClearDepthf(0x1); 1208 1209 const QVector<QRect> rects = q->state()->clipEnabled ? q->state()->clipRegion.rects() : q->systemClip().rects(); 1210 glEnable(GL_SCISSOR_TEST); 1211 for (int i = 0; i < rects.size(); ++i) { 1212 QRect rect = rects.at(i); 1213 1214 const int left = rect.left(); 1215 const int width = rect.width(); 1216 const int bottom = height - (rect.bottom() + 1); 1217 const int height = rect.height(); 1218 1219 glScissor(left, bottom, width, height); 1220 1221 glClear(GL_DEPTH_BUFFER_BIT); 1222 } 1223 glDisable(GL_SCISSOR_TEST); 1224 1225 glDepthMask(false); 1226 glDepthFunc(GL_LEQUAL); 1227 glEnable(GL_DEPTH_TEST); 1228 } 1229 1230 1231 1232 void QGL2PaintEngineEx::setState(QPainterState *s) 1233 { 1234 // qDebug("QGL2PaintEngineEx::setState()"); 1235 1236 Q_D(QGL2PaintEngineEx); 1237 QPaintEngineEx::setState(s); 1238 1239 d->updateDepthClip(); 1240 1241 d->matrixDirty = true; 1242 d->compositionModeDirty = true; 1243 d->brushTextureDirty = true; 1244 d->brushUniformsDirty = true; 1245 d->simpleShaderMatrixUniformDirty = true; 1246 d->brushShaderMatrixUniformDirty = true; 1247 d->imageShaderMatrixUniformDirty = true; 1248 d->textShaderMatrixUniformDirty = true; 1249 } 1250 1251 QPainterState *QGL2PaintEngineEx::createState(QPainterState *orig) const 1252 { 1253 QOpenGLPaintEngineState *s; 1254 if (!orig) 1255 s = new QOpenGLPaintEngineState(); 1256 else 1257 s = new QOpenGLPaintEngineState(*static_cast<QOpenGLPaintEngineState *>(orig)); 2258 s = new QOpenGL2PaintEngineState(*static_cast<QOpenGL2PaintEngineState *>(orig)); 2259 2260 s->matrixChanged = false; 2261 s->compositionModeChanged = false; 2262 s->opacityChanged = false; 2263 s->renderHintsChanged = false; 2264 s->clipChanged = false; 1258 2265 1259 2266 return s; 1260 2267 } 1261 2268 1262 QOpenGL PaintEngineState::QOpenGLPaintEngineState(QOpenGLPaintEngineState &other)2269 QOpenGL2PaintEngineState::QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other) 1263 2270 : QPainterState(other) 1264 2271 { 1265 clipRegion = other.clipRegion; 1266 hasClipping = other.hasClipping; 1267 fastClip = other.fastClip; 1268 } 1269 1270 QOpenGLPaintEngineState::QOpenGLPaintEngineState() 1271 { 1272 hasClipping = false; 1273 } 1274 1275 QOpenGLPaintEngineState::~QOpenGLPaintEngineState() 1276 { 1277 } 1278 2272 isNew = true; 2273 needsClipBufferClear = other.needsClipBufferClear; 2274 clipTestEnabled = other.clipTestEnabled; 2275 currentClip = other.currentClip; 2276 canRestoreClip = other.canRestoreClip; 2277 rectangleClip = other.rectangleClip; 2278 } 2279 2280 QOpenGL2PaintEngineState::QOpenGL2PaintEngineState() 2281 { 2282 isNew = true; 2283 needsClipBufferClear = true; 2284 clipTestEnabled = false; 2285 canRestoreClip = true; 2286 } 2287 2288 QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState() 2289 { 2290 } 2291 2292 QT_END_NAMESPACE 2293 2294 #include "qpaintengineex_opengl2.moc" -
trunk/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtOpenGL module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 54 54 // 55 55 56 #include <QDebug> 57 56 58 #include <private/qpaintengineex_p.h> 59 #include <private/qglengineshadermanager_p.h> 60 #include <private/qgl2pexvertexarray_p.h> 61 #include <private/qglpaintdevice_p.h> 62 #include <private/qglpixmapfilter_p.h> 63 #include <private/qfontengine_p.h> 64 #include <private/qdatabuffer_p.h> 65 #include <private/qtriangulatingstroker_p.h> 66 67 enum EngineMode { 68 ImageDrawingMode, 69 TextDrawingMode, 70 BrushDrawingMode, 71 ImageArrayDrawingMode 72 }; 73 74 QT_BEGIN_NAMESPACE 57 75 58 76 class QGL2PaintEngineExPrivate; 59 77 60 78 61 class QOpenGL PaintEngineState : public QPainterState79 class QOpenGL2PaintEngineState : public QPainterState 62 80 { 63 81 public: 64 QOpenGLPaintEngineState(QOpenGLPaintEngineState &other); 65 QOpenGLPaintEngineState(); 66 ~QOpenGLPaintEngineState(); 67 68 QRegion clipRegion; 69 bool hasClipping; 70 QRect fastClip; 71 }; 72 73 74 class QGL2PaintEngineEx : public QPaintEngineEx 82 QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other); 83 QOpenGL2PaintEngineState(); 84 ~QOpenGL2PaintEngineState(); 85 86 uint isNew : 1; 87 uint needsClipBufferClear : 1; 88 uint clipTestEnabled : 1; 89 uint canRestoreClip : 1; 90 uint matrixChanged : 1; 91 uint compositionModeChanged : 1; 92 uint opacityChanged : 1; 93 uint renderHintsChanged : 1; 94 uint clipChanged : 1; 95 uint currentClip : 8; 96 97 QRect rectangleClip; 98 }; 99 100 class Q_OPENGL_EXPORT QGL2PaintEngineEx : public QPaintEngineEx 75 101 { 76 102 Q_DECLARE_PRIVATE(QGL2PaintEngineEx) … … 80 106 81 107 bool begin(QPaintDevice *device); 108 void ensureActive(); 82 109 bool end(); 83 84 virtual void fill(const QVectorPath &path, const QBrush &brush);85 virtual void stroke(const QVectorPath &path, const QPen &pen);86 virtual void clip(const QVectorPath &path, Qt::ClipOperation op);87 110 88 111 virtual void clipEnabledChanged(); … … 95 118 virtual void transformChanged(); 96 119 97 120 virtual void drawTexture(const QRectF &r, GLuint textureId, const QSize &size, const QRectF &sr); 98 121 virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr); 99 122 virtual void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints); 100 123 virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, 101 124 Qt::ImageConversionFlags flags = Qt::AutoColor); 102 125 virtual void drawTextItem(const QPointF &p, const QTextItem &textItem); 103 void drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti); 104 105 Type type() const { return OpenGL; } 106 107 108 // State stuff is just for clipping and ripped off from QGLPaintEngine 109 void setState(QPainterState *s); 110 QPainterState *createState(QPainterState *orig) const; 111 inline QOpenGLPaintEngineState *state() { 112 return static_cast<QOpenGLPaintEngineState *>(QPaintEngineEx::state()); 113 } 114 inline const QOpenGLPaintEngineState *state() const { 115 return static_cast<const QOpenGLPaintEngineState *>(QPaintEngineEx::state()); 116 } 117 void updateClipRegion(const QRegion &clipRegion, Qt::ClipOperation op); 126 virtual void fill(const QVectorPath &path, const QBrush &brush); 127 virtual void stroke(const QVectorPath &path, const QPen &pen); 128 virtual void clip(const QVectorPath &path, Qt::ClipOperation op); 129 130 131 Type type() const { return OpenGL2; } 132 133 virtual void setState(QPainterState *s); 134 virtual QPainterState *createState(QPainterState *orig) const; 135 inline QOpenGL2PaintEngineState *state() { 136 return static_cast<QOpenGL2PaintEngineState *>(QPaintEngineEx::state()); 137 } 138 inline const QOpenGL2PaintEngineState *state() const { 139 return static_cast<const QOpenGL2PaintEngineState *>(QPaintEngineEx::state()); 140 } 141 142 void beginNativePainting(); 143 void endNativePainting(); 144 145 QPixmapFilter *pixmapFilter(int type, const QPixmapFilter *prototype); 146 147 void setRenderTextActive(bool); 118 148 119 149 private: … … 122 152 123 153 154 class QGL2PaintEngineExPrivate : public QPaintEngineExPrivate 155 { 156 Q_DECLARE_PUBLIC(QGL2PaintEngineEx) 157 public: 158 enum StencilFillMode { 159 OddEvenFillMode, 160 WindingFillMode, 161 TriStripStrokeFillMode 162 }; 163 164 QGL2PaintEngineExPrivate(QGL2PaintEngineEx *q_ptr) : 165 q(q_ptr), 166 shaderManager(0), 167 width(0), height(0), 168 ctx(0), 169 useSystemClip(true), 170 snapToPixelGrid(false), 171 addOffset(false), 172 inverseScale(1) 173 { } 174 175 ~QGL2PaintEngineExPrivate(); 176 177 void updateBrushTexture(); 178 void updateBrushUniforms(); 179 void updateMatrix(); 180 void updateCompositionMode(); 181 void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id = -1); 182 183 void resetGLState(); 184 185 // fill, stroke, drawTexture, drawPixmaps & drawCachedGlyphs are the main rendering entry-points, 186 // however writeClip can also be thought of as en entry point as it does similar things. 187 void fill(const QVectorPath &path); 188 void stroke(const QVectorPath &path, const QPen &pen); 189 void drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern = false); 190 void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints); 191 void drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType, const QTextItemInt &ti); 192 193 // draws whatever is in the vertex array: 194 void drawVertexArrays(const float *data, int *stops, int stopCount, GLenum primitive); 195 void drawVertexArrays(QGL2PEXVertexArray &vertexArray, GLenum primitive) { 196 drawVertexArrays((const float *) vertexArray.data(), vertexArray.stops(), vertexArray.stopCount(), primitive); 197 } 198 199 // Composites the bounding rect onto dest buffer: 200 void composite(const QGLRect& boundingRect); 201 202 // Calls drawVertexArrays to render into stencil buffer: 203 void fillStencilWithVertexArray(const float *data, int count, int *stops, int stopCount, const QGLRect &bounds, StencilFillMode mode); 204 void fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill) { 205 fillStencilWithVertexArray((const float *) vertexArray.data(), 0, vertexArray.stops(), vertexArray.stopCount(), 206 vertexArray.boundingRect(), 207 useWindingFill ? WindingFillMode : OddEvenFillMode); 208 } 209 210 void setBrush(const QBrush& brush); 211 void transferMode(EngineMode newMode); 212 bool prepareForDraw(bool srcPixelsAreOpaque); // returns true if the program has changed 213 inline void useSimpleShader(); 214 inline GLuint location(const QGLEngineShaderManager::Uniform uniform) { 215 return shaderManager->getUniformLocation(uniform); 216 } 217 218 void clearClip(uint value); 219 void writeClip(const QVectorPath &path, uint value); 220 void resetClipIfNeeded(); 221 222 void updateClipScissorTest(); 223 void setScissor(const QRect &rect); 224 void regenerateClip(); 225 void systemStateChanged(); 226 227 static QGLEngineShaderManager* shaderManagerForEngine(QGL2PaintEngineEx *engine) { return engine->d_func()->shaderManager; } 228 static QGL2PaintEngineExPrivate *getData(QGL2PaintEngineEx *engine) { return engine->d_func(); } 229 static void cleanupVectorPath(QPaintEngineEx *engine, void *data); 230 231 232 QGL2PaintEngineEx* q; 233 QGLEngineShaderManager* shaderManager; 234 QGLPaintDevice* device; 235 int width, height; 236 QGLContext *ctx; 237 EngineMode mode; 238 QFontEngineGlyphCache::Type glyphCacheType; 239 240 // Dirty flags 241 bool matrixDirty; // Implies matrix uniforms are also dirty 242 bool compositionModeDirty; 243 bool brushTextureDirty; 244 bool brushUniformsDirty; 245 bool simpleShaderMatrixUniformDirty; 246 bool shaderMatrixUniformDirty; 247 bool opacityUniformDirty; 248 249 bool stencilClean; // Has the stencil not been used for clipping so far? 250 bool useSystemClip; 251 QRegion dirtyStencilRegion; 252 QRect currentScissorBounds; 253 uint maxClip; 254 255 QBrush currentBrush; // May not be the state's brush! 256 const QBrush noBrush; 257 258 QGL2PEXVertexArray vertexCoordinateArray; 259 QGL2PEXVertexArray textureCoordinateArray; 260 QDataBuffer<GLfloat> opacityArray; 261 GLfloat staticVertexCoordinateArray[8]; 262 GLfloat staticTextureCoordinateArray[8]; 263 264 bool snapToPixelGrid; 265 bool addOffset; // When enabled, adds a 0.49,0.49 offset to matrix in updateMatrix 266 GLfloat pmvMatrix[3][3]; 267 GLfloat inverseScale; 268 269 GLuint lastTextureUsed; 270 271 bool needsSync; 272 bool multisamplingAlwaysEnabled; 273 274 GLfloat depthRange[2]; 275 276 float textureInvertedY; 277 278 QTriangulatingStroker stroker; 279 QDashedStrokeProcessor dasher; 280 281 QScopedPointer<QPixmapFilter> convolutionFilter; 282 QScopedPointer<QPixmapFilter> colorizeFilter; 283 QScopedPointer<QPixmapFilter> blurFilter; 284 QScopedPointer<QPixmapFilter> dropShadowFilter; 285 286 QSet<QVectorPath::CacheEntry *> pathCaches; 287 QVector<GLuint> unusedVBOSToClean; 288 }; 289 290 QT_END_NAMESPACE 124 291 125 292 #endif
Note:
See TracChangeset
for help on using the changeset viewer.