diff options
Diffstat (limited to 'src/opengl/gl2paintengineex')
-rw-r--r-- | src/opengl/gl2paintengineex/glgc_shader_source.h | 289 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp | 10 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h | 14 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qglengineshadermanager.cpp | 507 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qglengineshadermanager_p.h | 395 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qglengineshadersource_p.h | 417 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qglgradientcache.cpp | 31 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qglgradientcache_p.h | 10 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qglpexshadermanager.cpp | 450 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qglpexshadermanager_p.h | 156 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qglshader.cpp | 605 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qglshader_p.h | 260 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 1237 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h | 130 |
14 files changed, 2229 insertions, 2282 deletions
diff --git a/src/opengl/gl2paintengineex/glgc_shader_source.h b/src/opengl/gl2paintengineex/glgc_shader_source.h deleted file mode 100644 index 5b9d28b..0000000 --- a/src/opengl/gl2paintengineex/glgc_shader_source.h +++ /dev/null @@ -1,289 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef GLGC_SHADER_SOURCE_H -#define GLGC_SHADER_SOURCE_H - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(OpenGL) - -static const char* qglslImageVertexShader = "\ - attribute highp vec4 inputVertex; \ - attribute lowp vec2 textureCoord; \ - uniform highp mat4 pmvMatrix; \ - varying lowp vec2 fragTextureCoord; \ - void main(void) \ - {\ - gl_Position = pmvMatrix * inputVertex;\ - fragTextureCoord = textureCoord; \ - }"; - -static const char* qglslImageFragmentShader = "\ - varying lowp vec2 fragTextureCoord;\ - uniform sampler2D textureSampler;\ - uniform lowp float opacity; \ - void main(void) \ - {\ - gl_FragColor = texture2D(textureSampler, fragTextureCoord) * opacity; \ - }"; - -static const char* qglslTextFragmentShader = "\ - varying lowp vec2 fragTextureCoord;\ - uniform mediump vec4 fragmentColor;\ - uniform sampler2D textureSampler;\ - void main(void) \ - {\ - highp vec4 tex = texture2D(textureSampler, fragTextureCoord); \ - tex = fragmentColor * tex.r; \ - gl_FragColor = tex; \ - }"; - -static const char* qglslDefaultVertexShader = "\ - attribute highp vec4 inputVertex;\ - uniform highp mat4 pmvMatrix;\ - void main(void)\ - {\ - gl_Position = pmvMatrix * inputVertex;\ - }"; - -static const char* qglslSimpleFragmentShader = "\ - void main (void)\ - {\ - gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\ - }"; - - -/**** FRAGMENT SHADER MAIN FUNCTIONS ****/ -// NOTE: Currently, the engine assumes brushes return colors already in pre-multiplied -// format. However, this may change if we add support for non-premultiplied - -static const char* qglslNoOpacityFragmentShaderMain = "\n\ - mediump vec4 brush();\ - void main (void)\ - {\ - gl_FragColor = brush();\ - }\n"; - -static const char* qglslFragmentShaderMain = "\n\ - mediump vec4 brush();\ - uniform lowp float opacity; \ - void main (void)\ - {\ - gl_FragColor = brush() * opacity;\ - }\n"; - - - -/**** BRUSH SHADERS ****/ - -// This should never actually be used -static const char* qglslNoBrushFragmentShader = "\n\ - mediump vec4 brush() { \ - discard; \ - return vec4(1.0, 0.8, 0.8, 1.0);\ - }\n"; - -// Solid Fill Brush -static const char* qglslSolidBrushFragmentShader = "\n\ - uniform mediump vec4 fragmentColor; \ - mediump vec4 brush() { \ - return fragmentColor;\ - }\n"; - -// Texture Brush -static const char* qglslTextureBrushVertexShader = "\ - attribute highp vec4 inputVertex; \ - uniform highp mat4 pmvMatrix; \ - uniform mediump vec2 halfViewportSize; \ - uniform mediump vec2 invertedTextureSize; \ - uniform mediump mat3 brushTransform; \ - varying mediump vec2 texCoords; \ - void main(void) { \ - gl_Position = pmvMatrix * inputVertex;\ - gl_Position.xy = gl_Position.xy / gl_Position.w; \ - mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ - mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ - mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ - gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ - gl_Position.w = invertedHTexCoordsZ; \ - texCoords.xy = (hTexCoords.xy * invertedTextureSize) * gl_Position.w; \ - texCoords.y = -texCoords.y; \ - }"; - -static const char* qglslTextureBrushFragmentShader = "\n\ - varying mediump vec2 texCoords;\ - uniform sampler2D brushTexture;\ - mediump vec4 brush() { \ - return texture2D(brushTexture, texCoords); \ - }\n"; - - -// Pattern Brush - This assumes the texture size is 8x8 and thus, the inverted size is 0.125 -static const char* qglslPatternBrushVertexShader = "\ - attribute highp vec4 inputVertex; \ - uniform highp mat4 pmvMatrix; \ - uniform mediump vec2 halfViewportSize; \ - uniform mediump vec2 invertedTextureSize; \ - uniform mediump mat3 brushTransform; \ - varying mediump vec2 texCoords; \ - void main(void) { \ - gl_Position = pmvMatrix * inputVertex;\ - gl_Position.xy = gl_Position.xy / gl_Position.w; \ - mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ - mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ - mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ - gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ - gl_Position.w = invertedHTexCoordsZ; \ - texCoords.xy = (hTexCoords.xy * 0.125) * invertedHTexCoordsZ; \ - texCoords.y = -texCoords.y; \ - }"; - -static const char* qglslPatternBrushFragmentShader = "\n\ - uniform sampler2D brushTexture;\ - uniform lowp vec4 patternColor; \ - varying mediump vec2 texCoords;\ - mediump vec4 brush() { \ - return patternColor * texture2D(brushTexture, texCoords).r; \ - }\n"; - - -// Linear Gradient Brush -static const char* qglslLinearGradientBrushVertexShader = "\ - attribute highp vec4 inputVertex; \ - uniform highp mat4 pmvMatrix; \ - uniform mediump vec2 halfViewportSize; \ - uniform highp vec3 linearData; \ - uniform mediump mat3 brushTransform; \ - varying mediump float index ; \ - void main() { \ - gl_Position = pmvMatrix * inputVertex;\ - gl_Position.xy = gl_Position.xy / gl_Position.w; \ - mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ - mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ - mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ - gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ - gl_Position.w = invertedHTexCoordsZ; \ - index = (dot(linearData.xy, hTexCoords.xy) * linearData.z) * invertedHTexCoordsZ; \ - }"; - -static const char* qglslLinearGradientBrushFragmentShader = "\n\ - uniform sampler2D brushTexture; \ - varying mediump float index; \ - mediump vec4 brush() { \ - mediump vec2 val = vec2(index, 0.5); \ - return texture2D(brushTexture, val); \ - }\n"; - - -static const char* qglslRadialGradientBrushVertexShader = "\ - attribute highp vec4 inputVertex;\ - uniform highp mat4 pmvMatrix;\ - uniform mediump vec2 halfViewportSize; \ - uniform highp mat3 brushTransform; \ - uniform highp vec2 fmp; \ - varying highp float b; \ - varying highp vec2 A; \ - void main(void) \ - {\ - gl_Position = pmvMatrix * inputVertex;\ - gl_Position.xy = gl_Position.xy / gl_Position.w; \ - mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ - mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ - mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ - gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ - gl_Position.w = invertedHTexCoordsZ; \ - A = hTexCoords.xy * invertedHTexCoordsZ; \ - b = 2.0 * fmp * (A.x + A.y); \ -\ - }"; - -static const char* qglslRadialGradientBrushFragmentShader = "\n\ - uniform sampler2D brushTexture; \ - uniform highp float fmp2_m_radius2; \ - uniform highp float inverse_2_fmp2_m_radius2; \ - varying highp float b; \ - varying highp vec2 A; \ -\ - mediump vec4 brush() { \ - highp float c = -dot(A, A); \ - highp vec2 val = vec2((-b + sqrt(b*b - 4.0*fmp2_m_radius2*c)) * inverse_2_fmp2_m_radius2, 0.5); \ - return texture2D(brushTexture, val); \ - }\n"; - -static const char* qglslConicalGradientBrushVertexShader = "\ - attribute highp vec4 inputVertex;\ - uniform highp mat4 pmvMatrix;\ - uniform mediump vec2 halfViewportSize; \ - uniform highp mat3 brushTransform; \ - varying highp vec2 A; \ - void main(void)\ - {\ - gl_Position = pmvMatrix * inputVertex;\ - gl_Position.xy = gl_Position.xy / gl_Position.w; \ - mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ - mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ - mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ - gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ - gl_Position.w = invertedHTexCoordsZ; \ - A = hTexCoords.xy * invertedHTexCoordsZ; \ - }"; - -static const char* qglslConicalGradientBrushFragmentShader = "\n\ - #define INVERSE_2PI 0.1591549430918953358 \n\ - uniform sampler2D brushTexture; \ - uniform mediump float angle; \ - varying highp vec2 A; \ - mediump vec4 brush() { \ - if (abs(A.y) == abs(A.x)) \ - A.y += 0.002; \ - highp float t = (atan2(-A.y, A.x) + angle) * INVERSE_2PI; \ - return texture2D(brushTexture, vec2(t - floor(t), 0.5)); \ - }\n"; - - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // GLGC_SHADER_SOURCE_H diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp b/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp index 0352d39..560ad3a 100644 --- a/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp +++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp @@ -43,6 +43,8 @@ #include <private/qbezier_p.h> +QT_BEGIN_NAMESPACE + void QGL2PEXVertexArray::clear() { vertexArray.reset(); @@ -59,6 +61,12 @@ QGLRect QGL2PEXVertexArray::boundingRect() const return QGLRect(minX, minY, maxX, maxY); } +void QGL2PEXVertexArray::addRect(const QRectF &rect) +{ + vertexArray << rect.topLeft() << rect.topRight() << rect.bottomRight() + << rect.bottomRight() << rect.bottomLeft() << rect.topLeft(); +} + void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseScale) { const QPointF* const points = reinterpret_cast<const QPointF*>(path.points()); @@ -154,3 +162,5 @@ void QGL2PEXVertexArray::curveToArray(const QGLPoint &cp1, const QGLPoint &cp2, } } } + +QT_END_NAMESPACE diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h index c205022..d7a9f73 100644 --- a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h +++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h @@ -50,19 +50,24 @@ // We mean it. // +#ifndef QGL2PEXVERTEXARRAY_P_H +#define QGL2PEXVERTEXARRAY_P_H + #include <QRectF> #include <private/qdatabuffer_p.h> #include <private/qvectorpath_p.h> #include <private/qgl_p.h> +QT_BEGIN_NAMESPACE + class QGLPoint { public: QGLPoint(GLfloat new_x, GLfloat new_y) : x(new_x), y(new_y) {}; - QGLPoint(QPointF p) : + QGLPoint(const QPointF &p) : x(p.x()), y(p.y()) {}; QGLPoint(const QPointF* p) : @@ -77,7 +82,7 @@ public: struct QGLRect { - QGLRect(QRectF r) + QGLRect(const QRectF &r) : left(r.left()), top(r.top()), right(r.right()), bottom(r.bottom()) {} QGLRect(GLfloat l, GLfloat t, GLfloat r, GLfloat b) @@ -98,6 +103,7 @@ public: maxX(-2e10), maxY(-2e10), minX(2e10), minY(2e10), boundingRectDirty(true) {} + void addRect(const QRectF &rect); void addPath(const QVectorPath &path, GLfloat curveInverseScale); void clear(); @@ -119,3 +125,7 @@ private: inline void curveToArray(const QGLPoint &cp1, const QGLPoint &cp2, const QGLPoint &ep, GLfloat inverseScale); }; + +QT_END_NAMESPACE + +#endif diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp new file mode 100644 index 0000000..b71c4c1 --- /dev/null +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -0,0 +1,507 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qglengineshadermanager_p.h" +#include "qglengineshadersource_p.h" + +#if defined(QT_DEBUG) +#include <QMetaEnum> +#endif + + +QT_BEGIN_NAMESPACE + +const char* QGLEngineShaderManager::qglEngineShaderSourceCode[] = { + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0 +}; + +QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context) + : ctx(context), + shaderProgNeedsChanging(true), + srcPixelType(Qt::NoBrush), + useGlobalOpacity(false), + maskType(NoMask), + useTextureCoords(false), + compositionMode(QPainter::CompositionMode_SourceOver), + blitShaderProg(0), + simpleShaderProg(0), + currentShaderProg(0) +{ + memset(compiledShaders, 0, sizeof(compiledShaders)); + +/* + Rather than having the shader source array statically initialised, it is initialised + here instead. This is to allow new shader names to be inserted or existing names moved + around without having to change the order of the glsl strings. It is hoped this will + make future hard-to-find runtime bugs more obvious and generally give more solid code. +*/ + static bool qglEngineShaderSourceCodePopulated = false; + if (!qglEngineShaderSourceCodePopulated) { + + const char** code = qglEngineShaderSourceCode; // shortcut + + code[MainVertexShader] = qglslMainVertexShader; + code[MainWithTexCoordsVertexShader] = qglslMainWithTexCoordsVertexShader; + + code[UntransformedPositionVertexShader] = qglslUntransformedPositionVertexShader; + code[PositionOnlyVertexShader] = qglslPositionOnlyVertexShader; + code[PositionWithPatternBrushVertexShader] = qglslPositionWithPatternBrushVertexShader; + code[PositionWithLinearGradientBrushVertexShader] = qglslPositionWithLinearGradientBrushVertexShader; + code[PositionWithConicalGradientBrushVertexShader] = qglslPositionWithConicalGradientBrushVertexShader; + code[PositionWithRadialGradientBrushVertexShader] = qglslPositionWithRadialGradientBrushVertexShader; + code[PositionWithTextureBrushVertexShader] = qglslPositionWithTextureBrushVertexShader; + code[AffinePositionWithPatternBrushVertexShader] = qglslAffinePositionWithPatternBrushVertexShader; + code[AffinePositionWithLinearGradientBrushVertexShader] = qglslAffinePositionWithLinearGradientBrushVertexShader; + code[AffinePositionWithConicalGradientBrushVertexShader] = qglslAffinePositionWithConicalGradientBrushVertexShader; + code[AffinePositionWithRadialGradientBrushVertexShader] = qglslAffinePositionWithRadialGradientBrushVertexShader; + code[AffinePositionWithTextureBrushVertexShader] = qglslAffinePositionWithTextureBrushVertexShader; + + code[MainFragmentShader_CMO] = qglslMainFragmentShader_CMO; + code[MainFragmentShader_CM] = qglslMainFragmentShader_CM; + code[MainFragmentShader_MO] = qglslMainFragmentShader_MO; + code[MainFragmentShader_M] = qglslMainFragmentShader_M; + code[MainFragmentShader_CO] = qglslMainFragmentShader_CO; + code[MainFragmentShader_C] = qglslMainFragmentShader_C; + code[MainFragmentShader_O] = qglslMainFragmentShader_O; + code[MainFragmentShader] = qglslMainFragmentShader; + + code[ImageSrcFragmentShader] = qglslImageSrcFragmentShader; + code[ImageSrcWithPatternFragmentShader] = qglslImageSrcWithPatternFragmentShader; + code[NonPremultipliedImageSrcFragmentShader] = qglslNonPremultipliedImageSrcFragmentShader; + code[SolidBrushSrcFragmentShader] = qglslSolidBrushSrcFragmentShader; + code[TextureBrushSrcFragmentShader] = qglslTextureBrushSrcFragmentShader; + code[TextureBrushSrcWithPatternFragmentShader] = qglslTextureBrushSrcWithPatternFragmentShader; + code[PatternBrushSrcFragmentShader] = qglslPatternBrushSrcFragmentShader; + code[LinearGradientBrushSrcFragmentShader] = qglslLinearGradientBrushSrcFragmentShader; + code[RadialGradientBrushSrcFragmentShader] = qglslRadialGradientBrushSrcFragmentShader; + code[ConicalGradientBrushSrcFragmentShader] = qglslConicalGradientBrushSrcFragmentShader; + code[ShockingPinkSrcFragmentShader] = qglslShockingPinkSrcFragmentShader; + + code[MaskFragmentShader] = qglslMaskFragmentShader; + code[RgbMaskFragmentShader] = ""; //### + code[RgbMaskWithGammaFragmentShader] = ""; //### + + code[MultiplyCompositionModeFragmentShader] = ""; //### + code[ScreenCompositionModeFragmentShader] = ""; //### + code[OverlayCompositionModeFragmentShader] = ""; //### + code[DarkenCompositionModeFragmentShader] = ""; //### + code[LightenCompositionModeFragmentShader] = ""; //### + code[ColorDodgeCompositionModeFragmentShader] = ""; //### + code[ColorBurnCompositionModeFragmentShader] = ""; //### + code[HardLightCompositionModeFragmentShader] = ""; //### + code[SoftLightCompositionModeFragmentShader] = ""; //### + code[DifferenceCompositionModeFragmentShader] = ""; //### + code[ExclusionCompositionModeFragmentShader] = ""; //### + +#if defined(QT_DEBUG) + // Check that all the elements have been filled: + for (int i = 0; i < TotalShaderCount; ++i) { + if (qglEngineShaderSourceCode[i] == 0) { + int enumIndex = staticMetaObject.indexOfEnumerator("ShaderName"); + QMetaEnum m = staticMetaObject.enumerator(enumIndex); + + qCritical() << "qglEngineShaderSourceCode: Source for" << m.valueToKey(i) + << "(shader" << i << ") missing!"; + } + } +#endif + qglEngineShaderSourceCodePopulated = true; + } + + // Compile up the simple shader: + simpleShaderProg = new QGLShaderProgram(ctx, this); + compileNamedShader(MainVertexShader, QGLShader::PartialVertexShader); + compileNamedShader(PositionOnlyVertexShader, QGLShader::PartialVertexShader); + compileNamedShader(MainFragmentShader, QGLShader::PartialFragmentShader); + compileNamedShader(ShockingPinkSrcFragmentShader, QGLShader::PartialFragmentShader); + simpleShaderProg->addShader(compiledShaders[MainVertexShader]); + simpleShaderProg->addShader(compiledShaders[PositionOnlyVertexShader]); + simpleShaderProg->addShader(compiledShaders[MainFragmentShader]); + simpleShaderProg->addShader(compiledShaders[ShockingPinkSrcFragmentShader]); + simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); + simpleShaderProg->link(); + if (!simpleShaderProg->isLinked()) { + qCritical() << "Errors linking simple shader:" + << simpleShaderProg->log(); + } + + // Compile the blit shader: + blitShaderProg = new QGLShaderProgram(ctx, this); + compileNamedShader(MainWithTexCoordsVertexShader, QGLShader::PartialVertexShader); + compileNamedShader(UntransformedPositionVertexShader, QGLShader::PartialVertexShader); + compileNamedShader(MainFragmentShader, QGLShader::PartialFragmentShader); + compileNamedShader(ImageSrcFragmentShader, QGLShader::PartialFragmentShader); + blitShaderProg->addShader(compiledShaders[MainWithTexCoordsVertexShader]); + blitShaderProg->addShader(compiledShaders[UntransformedPositionVertexShader]); + blitShaderProg->addShader(compiledShaders[MainFragmentShader]); + blitShaderProg->addShader(compiledShaders[ImageSrcFragmentShader]); + blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); + blitShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); + blitShaderProg->link(); + if (!blitShaderProg->isLinked()) { + qCritical() << "Errors linking blit shader:" + << blitShaderProg->log(); + } +} + +QGLEngineShaderManager::~QGLEngineShaderManager() +{ + //### +} + + + + + +void QGLEngineShaderManager::optimiseForBrushTransform(const QTransform &transform) +{ + Q_UNUSED(transform); // Currently ignored +} + +void QGLEngineShaderManager::setDirty() +{ + shaderProgNeedsChanging = true; +} + +void QGLEngineShaderManager::setSrcPixelType(Qt::BrushStyle style) +{ + srcPixelType = style; + shaderProgNeedsChanging = true; //### +} + +void QGLEngineShaderManager::setSrcPixelType(PixelSrcType type) +{ + srcPixelType = type; + shaderProgNeedsChanging = true; //### +} + +void QGLEngineShaderManager::setTextureCoordsEnabled(bool enabled) +{ + useTextureCoords = enabled; + shaderProgNeedsChanging = true; //### +} + +void QGLEngineShaderManager::setUseGlobalOpacity(bool useOpacity) +{ + useGlobalOpacity = useOpacity; + shaderProgNeedsChanging = true; //### +} + +void QGLEngineShaderManager::setMaskType(MaskType type) +{ + maskType = type; + shaderProgNeedsChanging = true; //### +} + +void QGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mode) +{ + compositionMode = mode; + shaderProgNeedsChanging = true; //### +} + +QGLShaderProgram* QGLEngineShaderManager::currentProgram() +{ + return currentShaderProg; +} + +QGLShaderProgram* QGLEngineShaderManager::simpleProgram() +{ + return simpleShaderProg; +} + +QGLShaderProgram* QGLEngineShaderManager::blitProgram() +{ + return blitShaderProg; +} + + + +// Select & use the correct shader program using the current state. +// Returns true if program needed changing. +bool QGLEngineShaderManager::useCorrectShaderProg() +{ + if (!shaderProgNeedsChanging) + return false; + + QGLEngineShaderProg requiredProgram; + requiredProgram.program = 0; + + // Choose vertex shader main function + QGLEngineShaderManager::ShaderName mainVertexShaderName = InvalidShaderName; + if (useTextureCoords) + mainVertexShaderName = MainWithTexCoordsVertexShader; + else + mainVertexShaderName = MainVertexShader; + compileNamedShader(mainVertexShaderName, QGLShader::PartialVertexShader); + requiredProgram.mainVertexShader = compiledShaders[mainVertexShaderName]; + + // Choose vertex shader shader position function (which typically also sets + // varyings) and the source pixel (srcPixel) fragment shader function: + QGLEngineShaderManager::ShaderName positionVertexShaderName = InvalidShaderName; + QGLEngineShaderManager::ShaderName srcPixelFragShaderName = InvalidShaderName; + bool isAffine = brushTransform.isAffine(); + if ( (srcPixelType >= Qt::Dense1Pattern) && (srcPixelType <= Qt::DiagCrossPattern) ) { + if (isAffine) + positionVertexShaderName = AffinePositionWithPatternBrushVertexShader; + else + positionVertexShaderName = PositionWithPatternBrushVertexShader; + + srcPixelFragShaderName = PatternBrushSrcFragmentShader; + } + else switch (srcPixelType) { + default: + case Qt::NoBrush: + qCritical("QGLEngineShaderManager::useCorrectShaderProg() - I'm scared, Qt::NoBrush style is set"); + break; + case QGLEngineShaderManager::ImageSrc: + srcPixelFragShaderName = ImageSrcFragmentShader; + positionVertexShaderName = PositionOnlyVertexShader; + break; + case QGLEngineShaderManager::PatternSrc: + srcPixelFragShaderName = ImageSrcWithPatternFragmentShader; + positionVertexShaderName = PositionOnlyVertexShader; + break; + case QGLEngineShaderManager::TextureSrcWithPattern: + srcPixelFragShaderName = TextureBrushSrcWithPatternFragmentShader; + positionVertexShaderName = isAffine ? AffinePositionWithTextureBrushVertexShader + : PositionWithTextureBrushVertexShader; + break; + case QGLEngineShaderManager::NonPremultipliedImageSrc: + srcPixelFragShaderName = NonPremultipliedImageSrcFragmentShader; + positionVertexShaderName = PositionOnlyVertexShader; + break; + case Qt::SolidPattern: + srcPixelFragShaderName = SolidBrushSrcFragmentShader; + positionVertexShaderName = PositionOnlyVertexShader; + break; + case Qt::LinearGradientPattern: + srcPixelFragShaderName = LinearGradientBrushSrcFragmentShader; + positionVertexShaderName = isAffine ? AffinePositionWithLinearGradientBrushVertexShader + : PositionWithLinearGradientBrushVertexShader; + break; + case Qt::ConicalGradientPattern: + srcPixelFragShaderName = ConicalGradientBrushSrcFragmentShader; + positionVertexShaderName = isAffine ? AffinePositionWithConicalGradientBrushVertexShader + : PositionWithConicalGradientBrushVertexShader; + break; + case Qt::RadialGradientPattern: + srcPixelFragShaderName = RadialGradientBrushSrcFragmentShader; + positionVertexShaderName = isAffine ? AffinePositionWithRadialGradientBrushVertexShader + : PositionWithRadialGradientBrushVertexShader; + break; + case Qt::TexturePattern: + srcPixelFragShaderName = TextureBrushSrcFragmentShader; + positionVertexShaderName = isAffine ? AffinePositionWithTextureBrushVertexShader + : PositionWithTextureBrushVertexShader; + break; + }; + compileNamedShader(positionVertexShaderName, QGLShader::PartialVertexShader); + compileNamedShader(srcPixelFragShaderName, QGLShader::PartialFragmentShader); + requiredProgram.positionVertexShader = compiledShaders[positionVertexShaderName]; + requiredProgram.srcPixelFragShader = compiledShaders[srcPixelFragShaderName]; + + + const bool hasCompose = compositionMode > QPainter::CompositionMode_Plus; + const bool hasMask = maskType != QGLEngineShaderManager::NoMask; + + // Choose fragment shader main function: + QGLEngineShaderManager::ShaderName mainFragShaderName; + + if (hasCompose && hasMask && useGlobalOpacity) + mainFragShaderName = MainFragmentShader_CMO; + if (hasCompose && hasMask && !useGlobalOpacity) + mainFragShaderName = MainFragmentShader_CM; + if (!hasCompose && hasMask && useGlobalOpacity) + mainFragShaderName = MainFragmentShader_MO; + if (!hasCompose && hasMask && !useGlobalOpacity) + mainFragShaderName = MainFragmentShader_M; + if (hasCompose && !hasMask && useGlobalOpacity) + mainFragShaderName = MainFragmentShader_CO; + if (hasCompose && !hasMask && !useGlobalOpacity) + mainFragShaderName = MainFragmentShader_C; + if (!hasCompose && !hasMask && useGlobalOpacity) + mainFragShaderName = MainFragmentShader_O; + if (!hasCompose && !hasMask && !useGlobalOpacity) + mainFragShaderName = MainFragmentShader; + + compileNamedShader(mainFragShaderName, QGLShader::PartialFragmentShader); + requiredProgram.mainFragShader = compiledShaders[mainFragShaderName]; + + if (hasMask) { + QGLEngineShaderManager::ShaderName maskShaderName = QGLEngineShaderManager::InvalidShaderName; + if (maskType == PixelMask) + maskShaderName = MaskFragmentShader; + else if (maskType == SubPixelMask) + maskShaderName = RgbMaskFragmentShader; + else if (maskType == SubPixelWithGammaMask) + maskShaderName = RgbMaskWithGammaFragmentShader; + else + qCritical("QGLEngineShaderManager::useCorrectShaderProg() - Unknown mask type"); + + compileNamedShader(maskShaderName, QGLShader::PartialFragmentShader); + requiredProgram.maskFragShader = compiledShaders[maskShaderName]; + } + else + requiredProgram.maskFragShader = 0; + + if (hasCompose) { + QGLEngineShaderManager::ShaderName compositionShaderName = QGLEngineShaderManager::InvalidShaderName; + switch (compositionMode) { + case QPainter::CompositionMode_Multiply: + compositionShaderName = MultiplyCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Screen: + compositionShaderName = ScreenCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Overlay: + compositionShaderName = OverlayCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Darken: + compositionShaderName = DarkenCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Lighten: + compositionShaderName = LightenCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_ColorDodge: + compositionShaderName = ColorDodgeCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_ColorBurn: + compositionShaderName = ColorBurnCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_HardLight: + compositionShaderName = HardLightCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_SoftLight: + compositionShaderName = SoftLightCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Difference: + compositionShaderName = DifferenceCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Exclusion: + compositionShaderName = ExclusionCompositionModeFragmentShader; + break; + default: + qWarning("QGLEngineShaderManager::useCorrectShaderProg() - Unsupported composition mode"); + } + compileNamedShader(compositionShaderName, QGLShader::PartialFragmentShader); + requiredProgram.compositionFragShader = compiledShaders[compositionShaderName]; + } + else + requiredProgram.compositionFragShader = 0; + + + // At this point, requiredProgram is fully populated so try to find the program in the cache + foreach (const QGLEngineShaderProg &prog, cachedPrograms) { + if ( (prog.mainVertexShader == requiredProgram.mainVertexShader) + && (prog.positionVertexShader == requiredProgram.positionVertexShader) + && (prog.mainFragShader == requiredProgram.mainFragShader) + && (prog.srcPixelFragShader == requiredProgram.srcPixelFragShader) + && (prog.compositionFragShader == requiredProgram.compositionFragShader) ) + { + currentShaderProg = prog.program; + currentShaderProg->enable(); + shaderProgNeedsChanging = false; + return true; + } + } + + // Shader program not found in cache, create it now. + requiredProgram.program = new QGLShaderProgram(ctx, this); + requiredProgram.program->addShader(requiredProgram.mainVertexShader); + requiredProgram.program->addShader(requiredProgram.positionVertexShader); + requiredProgram.program->addShader(requiredProgram.mainFragShader); + requiredProgram.program->addShader(requiredProgram.srcPixelFragShader); + requiredProgram.program->addShader(requiredProgram.maskFragShader); + requiredProgram.program->addShader(requiredProgram.compositionFragShader); + + // We have to bind the vertex attribute names before the program is linked: + requiredProgram.program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); + if (useTextureCoords) + requiredProgram.program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); + + requiredProgram.program->link(); + if (!requiredProgram.program->isLinked()) { + QString error; + qWarning() << "Shader program failed to link," +#if defined(QT_DEBUG) + << '\n' + << " Shaders Used:" << '\n' + << " mainVertexShader = " << requiredProgram.mainVertexShader->objectName() << '\n' + << " positionVertexShader = " << requiredProgram.positionVertexShader->objectName() << '\n' + << " mainFragShader = " << requiredProgram.mainFragShader->objectName() << '\n' + << " srcPixelFragShader = " << requiredProgram.srcPixelFragShader->objectName() << '\n' + << " maskFragShader = " << requiredProgram.maskFragShader->objectName() << '\n' + << " compositionFragShader = "<< requiredProgram.compositionFragShader->objectName() << '\n' +#endif + << " Error Log:" << '\n' + << " " << requiredProgram.program->log(); + qWarning() << error; + } + else { + cachedPrograms.append(requiredProgram); + currentShaderProg = requiredProgram.program; + currentShaderProg->enable(); + } + shaderProgNeedsChanging = false; + return true; +} + +void QGLEngineShaderManager::compileNamedShader(QGLEngineShaderManager::ShaderName name, QGLShader::ShaderType type) +{ + if (compiledShaders[name]) + return; + + QGLShader *newShader = new QGLShader(type, ctx, this); + newShader->compile(qglEngineShaderSourceCode[name]); + +#if defined(QT_DEBUG) + // Name the shader for easier debugging + QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("ShaderName")); + newShader->setObjectName(QLatin1String(m.valueToKey(name))); +#endif + + compiledShaders[name] = newShader; +} + +QT_END_NAMESPACE diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h new file mode 100644 index 0000000..4a55eca --- /dev/null +++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h @@ -0,0 +1,395 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +/* + VERTEX SHADERS + ============== + + Vertex shaders are specified as multiple (partial) shaders. On desktop, + this works fine. On ES, QGLShader & QGLShaderProgram will make partial + shaders work by concatenating the source in each QGLShader and compiling + it as a single shader. This is abstracted nicely by QGLShaderProgram and + the GL2 engine doesn't need to worry about it. + + Generally, there's two vertex shader objects. The position shaders are + the ones which set gl_Position. There's also two "main" vertex shaders, + one which just calls the position shader and another which also passes + through some texture coordinates from a vertex attribute array to a + varying. These texture coordinates are used for mask position in text + rendering and for the source coordinates in drawImage/drawPixmap. There's + also a "Simple" vertex shader for rendering a solid colour (used to render + into the stencil buffer where the actual colour value is discarded). + + The position shaders for brushes look scary. This is because many of the + calculations which logically belong in the fragment shader have been moved + into the vertex shader to improve performance. This is why the position + calculation is in a seperate shader. Not only does it calculate the + position, but it also calculates some data to be passed to the fragment + shader as a varying. It is optimal to move as much of the calculation as + possible into the vertex shader as this is executed less often. + + The varyings passed to the fragment shaders are interpolated (which is + cheap). Unfortunately, GL will apply perspective correction to the + interpolation calusing errors. To get around this, the vertex shader must + apply perspective correction itself and set the w-value of gl_Position to + zero. That way, GL will be tricked into thinking it doesn't need to apply a + perspective correction and use linear interpolation instead (which is what + we want). Of course, if the brush transform is affeine, no perspective + correction is needed and a simpler vertex shader can be used instead. + + So there are the following "main" vertex shaders: + qglslMainVertexShader + qglslMainWithTexCoordsVertexShader + + And the the following position vertex shaders: + qglslPositionOnlyVertexShader + qglslPositionWithTextureBrushVertexShader + qglslPositionWithPatternBrushVertexShader + qglslPositionWithLinearGradientBrushVertexShader + qglslPositionWithRadialGradientBrushVertexShader + qglslPositionWithConicalGradientBrushVertexShader + qglslAffinePositionWithTextureBrushVertexShader + qglslAffinePositionWithPatternBrushVertexShader + qglslAffinePositionWithLinearGradientBrushVertexShader + qglslAffinePositionWithRadialGradientBrushVertexShader + qglslAffinePositionWithConicalGradientBrushVertexShader + + Leading to 23 possible vertex shaders + + + FRAGMENT SHADERS + ================ + + Fragment shaders are also specified as multiple (partial) shaders. The + different fragment shaders represent the different stages in Qt's fragment + pipeline. There are 1-3 stages in this pipeline: First stage is to get the + fragment's colour value. The next stage is to get the fragment's mask value + (coverage value for anti-aliasing) and the final stage is to blend the + incoming fragment with the background (for composition modes not supported + by GL). + + Of these, the first stage will always be present. If Qt doesn't need to + apply anti-aliasing (because it's off or handled by multisampling) then + the coverage value doesn't need to be applied. (Note: There are two types + of mask, one for regular anti-aliasing and one for sub-pixel anti- + aliasing.) If the composition mode is one which GL supports natively then + the blending stage doesn't need to be applied. + + As eash stage can have multiple implementations, they are abstracted as + GLSL function calls with the following signatures: + + Brushes & image drawing are implementations of "qcolorp vec4 srcPixel()": + qglslImageSrcFragShader + qglslImageSrcWithPatternFragShader + qglslNonPremultipliedImageSrcFragShader + qglslSolidBrushSrcFragShader + qglslTextureBrushSrcFragShader + qglslTextureBrushWithPatternFragShader + qglslPatternBrushSrcFragShader + qglslLinearGradientBrushSrcFragShader + qglslRadialGradientBrushSrcFragShader + qglslConicalGradientBrushSrcFragShader + NOTE: It is assumed the colour returned by srcPixel() is pre-multiplied + + Masks are implementations of "qcolorp vec4 applyMask(qcolorp vec4 src)": + qglslMaskFragmentShader + qglslRgbMaskFragmentShader + qglslRgbMaskWithGammaFragmentShader + + Composition modes are "qcolorp vec4 compose(qcolorp vec4 src)": + qglslColorBurnCompositionModeFragmentShader + qglslColorDodgeCompositionModeFragmentShader + qglslDarkenCompositionModeFragmentShader + qglslDifferenceCompositionModeFragmentShader + qglslExclusionCompositionModeFragmentShader + qglslHardLightCompositionModeFragmentShader + qglslLightenCompositionModeFragmentShader + qglslMultiplyCompositionModeFragmentShader + qglslOverlayCompositionModeFragmentShader + qglslScreenCompositionModeFragmentShader + qglslSoftLightCompositionModeFragmentShader + + + Note: In the future, some GLSL compilers will support an extension allowing + a new 'color' precision specifier. To support this, qcolorp is used for + all color components so it can be defined to colorp or lowp depending upon + the implementation. + + So there are differnt frament shader main functions, depending on the + number & type of pipelines the fragment needs to go through. + + The choice of which main() fragment shader string to use depends on: + - Use of global opacity + - Brush style (some brushes apply opacity themselves) + - Use & type of mask (TODO: Need to support high quality anti-aliasing & text) + - Use of non-GL Composition mode + + Leading to the following fragment shader main functions: + gl_FragColor = compose(applyMask(srcPixel()*globalOpacity)); + gl_FragColor = compose(applyMask(srcPixel())); + gl_FragColor = applyMask(srcPixel()*globalOpacity); + gl_FragColor = applyMask(srcPixel()); + gl_FragColor = compose(srcPixel()*globalOpacity); + gl_FragColor = compose(srcPixel()); + gl_FragColor = srcPixel()*globalOpacity; + gl_FragColor = srcPixel(); + + Called: + qglslMainFragmentShader_CMO + qglslMainFragmentShader_CM + qglslMainFragmentShader_MO + qglslMainFragmentShader_M + qglslMainFragmentShader_CO + qglslMainFragmentShader_C + qglslMainFragmentShader_O + qglslMainFragmentShader + + Where: + M = Mask + C = Composition + O = Global Opacity + + + CUSTOM SHADER CODE (idea, depricated) + ================== + + The use of custom shader code is supported by the engine for drawImage and + drawPixmap calls. This is implemented via hooks in the fragment pipeline. + The custom shader is passed to the engine as a partial fragment shader + (QGLCustomizedShader). The shader will implement a pre-defined method name + which Qt's fragment pipeline will call. There are two different hooks which + can be implemented as custom shader code: + + mediump vec4 customShader(sampler2d src, vec2 srcCoords) + mediump vec4 customShaderWithDest(sampler2d dest, sampler2d src, vec2 srcCoords) + +*/ + +#ifndef QGLENGINE_SHADER_MANAGER_H +#define QGLENGINE_SHADER_MANAGER_H + +#include <QGLShader> +#include <QGLShaderProgram> +#include <QPainter> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(OpenGL) + + +struct QGLEngineShaderProg +{ + QGLShader* mainVertexShader; + QGLShader* positionVertexShader; + QGLShader* mainFragShader; + QGLShader* srcPixelFragShader; + QGLShader* maskFragShader; // Can be null for no mask + QGLShader* compositionFragShader; // Can be null for GL-handled mode + QGLShaderProgram* program; +}; + +/* +struct QGLEngineCachedShaderProg +{ + QGLEngineCachedShaderProg(QGLEngineShaderManager::ShaderName vertexMain, + QGLEngineShaderManager::ShaderName vertexPosition, + QGLEngineShaderManager::ShaderName fragMain, + QGLEngineShaderManager::ShaderName pixelSrc, + QGLEngineShaderManager::ShaderName mask, + QGLEngineShaderManager::ShaderName composition); + + int cacheKey; + QGLShaderProgram* program; +} +*/ + +static const GLuint QT_VERTEX_COORDS_ATTR = 0; +static const GLuint QT_TEXTURE_COORDS_ATTR = 1; + +class QGLEngineShaderManager : public QObject +{ + Q_OBJECT +public: + QGLEngineShaderManager(QGLContext* context); + ~QGLEngineShaderManager(); + + enum MaskType {NoMask, PixelMask, SubPixelMask, SubPixelWithGammaMask}; + enum PixelSrcType { + ImageSrc = Qt::TexturePattern+1, + NonPremultipliedImageSrc = Qt::TexturePattern+2, + PatternSrc = Qt::TexturePattern+3, + TextureSrcWithPattern = Qt::TexturePattern+4 + }; + + // There are optimisations we can do, depending on the brush transform: + // 1) May not have to apply perspective-correction + // 2) Can use lower precision for matrix + void optimiseForBrushTransform(const QTransform &transform); + void setSrcPixelType(Qt::BrushStyle); + void setSrcPixelType(PixelSrcType); // For non-brush sources, like pixmaps & images + void setTextureCoordsEnabled(bool); // For images & text glyphs + void setUseGlobalOpacity(bool); + void setMaskType(MaskType); + void setCompositionMode(QPainter::CompositionMode); + + void setDirty(); // someone has manually changed the current shader program + bool useCorrectShaderProg(); // returns true if the shader program needed to be changed + + QGLShaderProgram* currentProgram(); // Returns pointer to the shader the manager has chosen + QGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers + QGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer + + enum ShaderName { + MainVertexShader, + MainWithTexCoordsVertexShader, + + UntransformedPositionVertexShader, + PositionOnlyVertexShader, + PositionWithPatternBrushVertexShader, + PositionWithLinearGradientBrushVertexShader, + PositionWithConicalGradientBrushVertexShader, + PositionWithRadialGradientBrushVertexShader, + PositionWithTextureBrushVertexShader, + AffinePositionWithPatternBrushVertexShader, + AffinePositionWithLinearGradientBrushVertexShader, + AffinePositionWithConicalGradientBrushVertexShader, + AffinePositionWithRadialGradientBrushVertexShader, + AffinePositionWithTextureBrushVertexShader, + + MainFragmentShader_CMO, + MainFragmentShader_CM, + MainFragmentShader_MO, + MainFragmentShader_M, + MainFragmentShader_CO, + MainFragmentShader_C, + MainFragmentShader_O, + MainFragmentShader, + + ImageSrcFragmentShader, + ImageSrcWithPatternFragmentShader, + NonPremultipliedImageSrcFragmentShader, + SolidBrushSrcFragmentShader, + TextureBrushSrcFragmentShader, + TextureBrushSrcWithPatternFragmentShader, + PatternBrushSrcFragmentShader, + LinearGradientBrushSrcFragmentShader, + RadialGradientBrushSrcFragmentShader, + ConicalGradientBrushSrcFragmentShader, + ShockingPinkSrcFragmentShader, + + MaskFragmentShader, + RgbMaskFragmentShader, + RgbMaskWithGammaFragmentShader, + + MultiplyCompositionModeFragmentShader, + ScreenCompositionModeFragmentShader, + OverlayCompositionModeFragmentShader, + DarkenCompositionModeFragmentShader, + LightenCompositionModeFragmentShader, + ColorDodgeCompositionModeFragmentShader, + ColorBurnCompositionModeFragmentShader, + HardLightCompositionModeFragmentShader, + SoftLightCompositionModeFragmentShader, + DifferenceCompositionModeFragmentShader, + ExclusionCompositionModeFragmentShader, + + TotalShaderCount, InvalidShaderName + }; + +/* + // These allow the ShaderName enum to be used as a cache key + const int mainVertexOffset = 0; + const int positionVertexOffset = (1<<2) - PositionOnlyVertexShader; + const int mainFragOffset = (1<<6) - MainFragmentShader_CMO; + const int srcPixelOffset = (1<<10) - ImageSrcFragmentShader; + const int maskOffset = (1<<14) - NoMaskShader; + const int compositionOffset = (1 << 16) - MultiplyCompositionModeFragmentShader; +*/ + +#if defined (QT_DEBUG) + Q_ENUMS(ShaderName) +#endif + + +private: + QGLContext* ctx; + bool shaderProgNeedsChanging; + + // Current state variables which influence the choice of shader: + QTransform brushTransform; + int srcPixelType; + bool useGlobalOpacity; + MaskType maskType; + bool useTextureCoords; + QPainter::CompositionMode compositionMode; + + QGLShaderProgram* blitShaderProg; + QGLShaderProgram* simpleShaderProg; + QGLShaderProgram* currentShaderProg; + + // TODO: Possibly convert to a LUT + QList<QGLEngineShaderProg> cachedPrograms; + + QGLShader* compiledShaders[TotalShaderCount]; + + void compileNamedShader(QGLEngineShaderManager::ShaderName name, QGLShader::ShaderType type); + + static const char* qglEngineShaderSourceCode[TotalShaderCount]; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif //QGLENGINE_SHADER_MANAGER_H diff --git a/src/opengl/gl2paintengineex/qglengineshadersource_p.h b/src/opengl/gl2paintengineex/qglengineshadersource_p.h new file mode 100644 index 0000000..61cc63e --- /dev/null +++ b/src/opengl/gl2paintengineex/qglengineshadersource_p.h @@ -0,0 +1,417 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QGL_ENGINE_SHADER_SOURCE_H +#define QGL_ENGINE_SHADER_SOURCE_H + +#include "qglengineshadermanager_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(OpenGL) + + +static const char* const qglslMainVertexShader = "\ + void setPosition();\ + void main(void)\ + {\ + setPosition();\ + }"; + +static const char* const qglslMainWithTexCoordsVertexShader = "\ + attribute lowp vec2 textureCoordArray; \ + varying lowp vec2 textureCoords; \ + void setPosition();\ + void main(void) \ + {\ + setPosition();\ + textureCoords = textureCoordArray; \ + }"; + + +static const char* const qglslPositionOnlyVertexShader = "\ + attribute highp vec4 vertexCoordsArray;\ + uniform highp mat4 pmvMatrix;\ + uniform highp float depth;\ + void setPosition(void)\ + {\ + gl_Position = pmvMatrix * vertexCoordsArray;\ + gl_Position.z = depth;\ + }"; + +static const char* const qglslUntransformedPositionVertexShader = "\ + attribute highp vec4 vertexCoordsArray;\ + uniform highp float depth;\ + void setPosition(void)\ + {\ + gl_Position = vertexCoordsArray;\ + gl_Position.z = depth;\ + }"; + +// Pattern Brush - This assumes the texture size is 8x8 and thus, the inverted size is 0.125 +static const char* const qglslPositionWithPatternBrushVertexShader = "\ + attribute highp vec4 vertexCoordsArray; \ + uniform highp mat4 pmvMatrix; \ + uniform mediump vec2 halfViewportSize; \ + uniform mediump vec2 invertedTextureSize; \ + uniform mediump mat3 brushTransform; \ + varying mediump vec2 patternTexCoords; \ + uniform highp float depth;\ + void setPosition(void) { \ + gl_Position = pmvMatrix * vertexCoordsArray;\ + gl_Position.xy = gl_Position.xy / gl_Position.w; \ + gl_Position.z = depth;\ + mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ + mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ + mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ + gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ + gl_Position.w = invertedHTexCoordsZ; \ + patternTexCoords.xy = (hTexCoords.xy * 0.125) * invertedHTexCoordsZ; \ + patternTexCoords.y = -patternTexCoords.y; \ + }"; + +static const char* const qglslAffinePositionWithPatternBrushVertexShader + = qglslPositionWithPatternBrushVertexShader; + +static const char* const qglslPatternBrushSrcFragmentShader = "\ + uniform sampler2D brushTexture;\ + uniform lowp vec4 patternColor; \ + varying mediump vec2 patternTexCoords;\ + lowp vec4 srcPixel() { \ + return patternColor * (1.0 - texture2D(brushTexture, patternTexCoords).r); \ + }\n"; + + +// Linear Gradient Brush +static const char* const qglslPositionWithLinearGradientBrushVertexShader = "\ + attribute highp vec4 vertexCoordsArray; \ + uniform highp mat4 pmvMatrix; \ + uniform mediump vec2 halfViewportSize; \ + uniform highp vec3 linearData; \ + uniform highp mat3 brushTransform; \ + varying mediump float index ; \ + uniform highp float depth;\ + void setPosition() { \ + gl_Position = pmvMatrix * vertexCoordsArray;\ + gl_Position.xy = gl_Position.xy / gl_Position.w; \ + gl_Position.z = depth;\ + mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ + mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ + mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ + gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ + gl_Position.w = invertedHTexCoordsZ; \ + index = (dot(linearData.xy, hTexCoords.xy) * linearData.z) * invertedHTexCoordsZ; \ + }"; + +static const char* const qglslAffinePositionWithLinearGradientBrushVertexShader + = qglslPositionWithLinearGradientBrushVertexShader; + +static const char* const qglslLinearGradientBrushSrcFragmentShader = "\ + uniform sampler2D brushTexture; \ + varying mediump float index; \ + lowp vec4 srcPixel() { \ + mediump vec2 val = vec2(index, 0.5); \ + return texture2D(brushTexture, val); \ + }\n"; + + +// Conical Gradient Brush +static const char* const qglslPositionWithConicalGradientBrushVertexShader = "\ + attribute highp vec4 vertexCoordsArray;\ + uniform highp mat4 pmvMatrix;\ + uniform mediump vec2 halfViewportSize; \ + uniform highp mat3 brushTransform; \ + varying highp vec2 A; \ + uniform highp float depth;\ + void setPosition(void)\ + {\ + gl_Position = pmvMatrix * vertexCoordsArray;\ + gl_Position.xy = gl_Position.xy / gl_Position.w; \ + gl_Position.z = depth; \ + mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ + mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ + mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ + gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ + gl_Position.w = invertedHTexCoordsZ; \ + A = hTexCoords.xy * invertedHTexCoordsZ; \ + }"; + +static const char* const qglslAffinePositionWithConicalGradientBrushVertexShader + = qglslPositionWithConicalGradientBrushVertexShader; + +static const char* const qglslConicalGradientBrushSrcFragmentShader = "\n\ + #define INVERSE_2PI 0.1591549430918953358 \n\ + uniform sampler2D brushTexture; \n\ + uniform mediump float angle; \ + varying highp vec2 A; \ + lowp vec4 srcPixel() { \ + highp float t; \ + if (abs(A.y) == abs(A.x)) \ + t = (atan(-A.y + 0.002, A.x) + angle) * INVERSE_2PI; \ + else \ + t = (atan(-A.y, A.x) + angle) * INVERSE_2PI; \ + return texture2D(brushTexture, vec2(t - floor(t), 0.5)); \ + }"; + + +// Radial Gradient Brush +static const char* const qglslPositionWithRadialGradientBrushVertexShader = "\ + attribute highp vec4 vertexCoordsArray;\ + uniform highp mat4 pmvMatrix;\ + uniform mediump vec2 halfViewportSize; \ + uniform highp mat3 brushTransform; \ + uniform highp vec2 fmp; \ + varying highp float b; \ + varying highp vec2 A; \ + uniform highp float depth;\ + void setPosition(void) \ + {\ + gl_Position = pmvMatrix * vertexCoordsArray;\ + gl_Position.xy = gl_Position.xy / gl_Position.w; \ + gl_Position.z = depth; \ + mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ + mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ + mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ + gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ + gl_Position.w = invertedHTexCoordsZ; \ + A = hTexCoords.xy * invertedHTexCoordsZ; \ + b = 2.0 * dot(A, fmp); \ + }"; + +static const char* const qglslAffinePositionWithRadialGradientBrushVertexShader + = qglslPositionWithRadialGradientBrushVertexShader; + +static const char* const qglslRadialGradientBrushSrcFragmentShader = "\ + uniform sampler2D brushTexture; \ + uniform highp float fmp2_m_radius2; \ + uniform highp float inverse_2_fmp2_m_radius2; \ + varying highp float b; \ + varying highp vec2 A; \ + lowp vec4 srcPixel() { \ + highp float c = -dot(A, A); \ + highp vec2 val = vec2((-b + sqrt(b*b - 4.0*fmp2_m_radius2*c)) * inverse_2_fmp2_m_radius2, 0.5); \ + return texture2D(brushTexture, val); \ + }"; + + +// Texture Brush +static const char* const qglslPositionWithTextureBrushVertexShader = "\ + attribute highp vec4 vertexCoordsArray; \ + uniform highp mat4 pmvMatrix; \ + uniform mediump vec2 halfViewportSize; \ + uniform mediump vec2 invertedTextureSize; \ + uniform mediump mat3 brushTransform; \ + varying mediump vec2 brushTextureCoords; \ + uniform highp float depth;\ + void setPosition(void) { \ + gl_Position = pmvMatrix * vertexCoordsArray;\ + gl_Position.xy = gl_Position.xy / gl_Position.w; \ + gl_Position.z = depth; \ + mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ + mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ + mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ + gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ + gl_Position.w = invertedHTexCoordsZ; \ + brushTextureCoords.xy = (hTexCoords.xy * invertedTextureSize) * gl_Position.w; \ + brushTextureCoords.y = -brushTextureCoords.y; \ + }"; + +static const char* const qglslAffinePositionWithTextureBrushVertexShader + = qglslPositionWithTextureBrushVertexShader; + +static const char* const qglslTextureBrushSrcFragmentShader = "\ + varying mediump vec2 brushTextureCoords; \ + uniform sampler2D brushTexture; \ + lowp vec4 srcPixel() { \ + return texture2D(brushTexture, brushTextureCoords); \ + }"; + +static const char* const qglslTextureBrushSrcWithPatternFragmentShader = "\ + varying mediump vec2 brushTextureCoords; \ + uniform lowp vec4 patternColor; \ + uniform sampler2D brushTexture; \ + lowp vec4 srcPixel() { \ + return patternColor * (1.0 - texture2D(brushTexture, brushTextureCoords).r); \ + }"; + +// Solid Fill Brush +static const char* const qglslSolidBrushSrcFragmentShader = "\ + uniform lowp vec4 fragmentColor; \ + lowp vec4 srcPixel() { \ + return fragmentColor; \ + }"; + +static const char* const qglslImageSrcFragmentShader = "\ + varying highp vec2 textureCoords; \ + uniform sampler2D imageTexture; \ + lowp vec4 srcPixel() { \ + return texture2D(imageTexture, textureCoords); \ + }"; + +static const char* const qglslImageSrcWithPatternFragmentShader = "\ + varying highp vec2 textureCoords; \ + uniform lowp vec4 patternColor; \ + uniform sampler2D imageTexture; \ + lowp vec4 srcPixel() { \ + return patternColor * (1.0 - texture2D(imageTexture, textureCoords).r); \ + }\n"; + +static const char* const qglslNonPremultipliedImageSrcFragmentShader = "\ + varying highp vec2 textureCoords; \ + uniform sampler2D imageTexture; \ + lowp vec4 srcPixel() { \ + lowp vec4 sample = texture2D(imageTexture, textureCoords); \ + sample.rgb = sample.rgb * sample.a; \ + return sample; \ + }"; + +static const char* const qglslShockingPinkSrcFragmentShader = "\ + lowp vec4 srcPixel() { \ + return vec4(0.98, 0.06, 0.75, 1.0); \ + }"; + + +static const char* const qglslMainFragmentShader_CMO = "\ + uniform lowp float globalOpacity; \ + lowp vec4 srcPixel(); \ + lowp vec4 applyMask(lowp vec4); \ + lowp vec4 compose(lowp vec4); \ + void main() { \ + gl_FragColor = applyMask(compose(srcPixel()*globalOpacity))); \ + }"; + +static const char* const qglslMainFragmentShader_CM = "\ + lowp vec4 srcPixel(); \ + lowp vec4 applyMask(lowp vec4); \ + lowp vec4 compose(lowp vec4); \ + void main() { \ + gl_FragColor = applyMask(compose(srcPixel())); \ + }"; + +static const char* const qglslMainFragmentShader_MO = "\ + uniform lowp float globalOpacity; \ + lowp vec4 srcPixel(); \ + lowp vec4 applyMask(lowp vec4); \ + void main() { \ + gl_FragColor = applyMask(srcPixel()*globalOpacity); \ + }"; + +static const char* const qglslMainFragmentShader_M = "\ + lowp vec4 srcPixel(); \ + lowp vec4 applyMask(lowp vec4); \ + void main() { \ + gl_FragColor = applyMask(srcPixel()); \ + }"; + +static const char* const qglslMainFragmentShader_CO = "\ + uniform lowp float globalOpacity; \ + lowp vec4 srcPixel(); \ + lowp vec4 compose(lowp vec4); \ + void main() { \ + gl_FragColor = compose(srcPixel()*globalOpacity); \ + }"; + +static const char* const qglslMainFragmentShader_C = "\ + lowp vec4 srcPixel(); \ + lowp vec4 compose(lowp vec4); \ + void main() { \ + gl_FragColor = compose(srcPixel()); \ + }"; + +static const char* const qglslMainFragmentShader_O = "\ + uniform lowp float globalOpacity; \ + lowp vec4 srcPixel(); \ + void main() { \ + gl_FragColor = srcPixel()*globalOpacity; \ + }"; + +static const char* const qglslMainFragmentShader = "\ + lowp vec4 srcPixel(); \ + void main() { \ + gl_FragColor = srcPixel(); \ + }"; + +static const char* const qglslMaskFragmentShader = "\ + varying highp vec2 textureCoords;\ + uniform sampler2D maskTexture;\ + lowp vec4 applyMask(lowp vec4 src) \ + {\ + lowp vec4 mask = texture2D(maskTexture, textureCoords); \ + return src * mask.a; \ + }"; + +/* + Left to implement: + RgbMaskFragmentShader, + RgbMaskWithGammaFragmentShader, + + MultiplyCompositionModeFragmentShader, + ScreenCompositionModeFragmentShader, + OverlayCompositionModeFragmentShader, + DarkenCompositionModeFragmentShader, + LightenCompositionModeFragmentShader, + ColorDodgeCompositionModeFragmentShader, + ColorBurnCompositionModeFragmentShader, + HardLightCompositionModeFragmentShader, + SoftLightCompositionModeFragmentShader, + DifferenceCompositionModeFragmentShader, + ExclusionCompositionModeFragmentShader, +*/ + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // GLGC_SHADER_SOURCE_H diff --git a/src/opengl/gl2paintengineex/qglgradientcache.cpp b/src/opengl/gl2paintengineex/qglgradientcache.cpp index b4591b2..f1a8850 100644 --- a/src/opengl/gl2paintengineex/qglgradientcache.cpp +++ b/src/opengl/gl2paintengineex/qglgradientcache.cpp @@ -44,7 +44,9 @@ #include "qglgradientcache_p.h" -void QGLGradientCache::cleanCache() { +QT_BEGIN_NAMESPACE + +void QGL2GradientCache::cleanCache() { QGLGradientColorTableHash::const_iterator it = cache.constBegin(); for (; it != cache.constEnd(); ++it) { const CacheInfo &cache_info = it.value(); @@ -53,7 +55,7 @@ void QGLGradientCache::cleanCache() { cache.clear(); } -GLuint QGLGradientCache::getBuffer(const QGradient &gradient, qreal opacity, const QGLContext *ctx) +GLuint QGL2GradientCache::getBuffer(const QGradient &gradient, qreal opacity, const QGLContext *ctx) { if (buffer_ctx && !qgl_share_reg()->checkSharing(buffer_ctx, ctx)) cleanCache(); @@ -84,7 +86,7 @@ GLuint QGLGradientCache::getBuffer(const QGradient &gradient, qreal opacity, con } -GLuint QGLGradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity) +GLuint QGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity) { if (cache.size() == maxCacheSize()) { int elem_to_remove = qrand() % maxCacheSize(); @@ -109,34 +111,31 @@ GLuint QGLGradientCache::addCacheElement(quint64 hash_val, const QGradient &grad } -// GL's expects pixels in RGBA, bin-endian (ABGR on x86). -// Qt stores in ARGB using whatever byte-order the mancine uses. +// GL's expects pixels in RGBA (when using GL_RGBA), bin-endian (ABGR on x86). +// Qt always stores in ARGB reguardless of the byte-order the mancine uses. static inline uint qtToGlColor(uint c) { uint o; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - o = c & 0xFF00FF00; // alpha & green already in the right place - o |= (c >> 16) & 0x000000FF; // red - o |= (c << 16) & 0x00FF0000; // blue - + o = (c & 0xff00ff00) // alpha & green already in the right place + | ((c >> 16) & 0x000000ff) // red + | ((c << 16) & 0x00ff0000); // blue #else //Q_BIG_ENDIAN - o = c & 0x00FF00FF; // alpha & green already in the right place - o |= (c << 16) & 0xFF000000; // red - o |= (c >> 16) & 0x0000FF00; // blue -#error big endian not tested with QGLGraphicsContext + o = (c << 8) + | ((c >> 24) & 0x000000ff); #endif // Q_BYTE_ORDER return o; } //TODO: Let GL generate the texture using an FBO -void QGLGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const +void QGL2GradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const { int pos = 0; QGradientStops s = gradient.stops(); QVector<uint> colors(s.size()); for (int i = 0; i < s.size(); ++i) - colors[i] = s[i].second.rgba(); // Qt LIES! It returns ARGB + colors[i] = s[i].second.rgba(); // Qt LIES! It returns ARGB (on little-endian AND on big-endian) bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation); @@ -183,3 +182,5 @@ void QGLGradientCache::generateGradientColorTable(const QGradient& gradient, uin // Make sure the last color stop is represented at the end of the table colorTable[size-1] = last_color; } + +QT_END_NAMESPACE diff --git a/src/opengl/gl2paintengineex/qglgradientcache_p.h b/src/opengl/gl2paintengineex/qglgradientcache_p.h index 346ea13..f088359 100644 --- a/src/opengl/gl2paintengineex/qglgradientcache_p.h +++ b/src/opengl/gl2paintengineex/qglgradientcache_p.h @@ -52,9 +52,11 @@ #include <QMultiHash> #include <QObject> -#include <QtOpenGL> +#include <QtOpenGL/QtOpenGL> -class QGLGradientCache : public QObject +QT_BEGIN_NAMESPACE + +class QGL2GradientCache : public QObject { Q_OBJECT struct CacheInfo @@ -71,7 +73,7 @@ class QGLGradientCache : public QObject typedef QMultiHash<quint64, CacheInfo> QGLGradientColorTableHash; public: - QGLGradientCache() : QObject(), buffer_ctx(0) + QGL2GradientCache() : QObject(), buffer_ctx(0) { /* connect(QGLSignalProxy::instance(), @@ -104,5 +106,5 @@ public slots: } }; - +QT_END_NAMESPACE diff --git a/src/opengl/gl2paintengineex/qglpexshadermanager.cpp b/src/opengl/gl2paintengineex/qglpexshadermanager.cpp deleted file mode 100644 index e460e08..0000000 --- a/src/opengl/gl2paintengineex/qglpexshadermanager.cpp +++ /dev/null @@ -1,450 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qglpexshadermanager_p.h" - -#include "glgc_shader_source.h" - -QGLPEXShaderManager::QGLPEXShaderManager(const QGLContext* context) -{ - ctx = const_cast<QGLContext*>(context); - - defaultVertexShader= new QGLShader(QGLShader::VertexShader, context); - defaultVertexShader->addSource(QLatin1String(qglslDefaultVertexShader)); - if (!defaultVertexShader->compile()) - qWarning() << "Default vertex shader failed to compile: " << defaultVertexShader->log(); - - noBrushShader = new QGLShader(QGLShader::FragmentShader, context); - noBrushShader->addSource(QLatin1String(qglslFragmentShaderMain)); - noBrushShader->addSource(QLatin1String(qglslNoBrushFragmentShader)); - if (!noBrushShader->compile()) - qWarning() << "No brush shader failed to compile:" << noBrushShader->log(); - - - // Create a program for noBrush: - QGLShaderProgram* noBrushProg = new QGLShaderProgram(ctx); - noBrushProg->addShader(defaultVertexShader); - noBrushProg->addShader(noBrushShader); - if (!noBrushProg->link()) - qWarning() << "NoBrush shader program failed to link:" << noBrushProg->log(); - - // Add noBrush Program to cache: - QGLCachedShaderProg cachedProg; - cachedProg.vertexShader = defaultVertexShader; - cachedProg.brushShader = noBrushShader; - cachedProg.compositionShader = 0; - cachedProg.shader = noBrushProg; - cachedPrograms.append(cachedProg); - - - // Set state - useGlobalOpacity = true; - currentBrushStyle = Qt::NoBrush; - currentTransformType = FullTransform; - shaderProgNeedsChanging = false; - activeProgram = noBrushProg; - - solidBrushShader = 0; - - conicalBrushVertexShader = 0; - conicalBrushFragmentShader = 0; - - radialBrushVertexShader = 0; - radialBrushFragmentShader = 0; - - linearBrushVertexShader = 0; - linearBrushFragmentShader = 0; - - patternBrushVertexShader = 0; - patternBrushFragmentShader = 0; - - textureBrushFragmentShader = 0; - textureBrushVertexShader = 0; - - simpleFragmentShader = 0; - simpleShaderProgram = 0; - - imageVertexShader = 0; - imageFragmentShader = 0; - imageShaderProgram = 0; - - textVertexShader = 0; - textFragmentShader = 0; - textShaderProgram = 0; -} - -QGLPEXShaderManager::~QGLPEXShaderManager() -{ - delete defaultVertexShader; - delete imageVertexShader; - delete imageFragmentShader; - delete imageShaderProgram; - delete textVertexShader; - delete textFragmentShader; - delete textShaderProgram; - delete noBrushShader; - delete solidBrushShader; - - delete conicalBrushVertexShader; - delete conicalBrushFragmentShader; - - delete radialBrushVertexShader; - delete radialBrushFragmentShader; - - delete linearBrushFragmentShader; - delete linearBrushVertexShader; - - delete patternBrushFragmentShader; - delete patternBrushVertexShader; - - delete textureBrushFragmentShader; - delete textureBrushVertexShader; - - delete simpleFragmentShader; - delete simpleShaderProgram; -} - -void QGLPEXShaderManager::setUseGlobalOpacity(bool value) -{ - if (value != useGlobalOpacity) - shaderProgNeedsChanging = true; - - useGlobalOpacity = value; -} - -void QGLPEXShaderManager::setBrushStyle(Qt::BrushStyle style) -{ - if (currentBrushStyle != style) - shaderProgNeedsChanging = true; - - currentBrushStyle = style; -} - -void QGLPEXShaderManager::setAffineOnlyBrushTransform(bool value) -{ - Q_UNUSED(value); - // TODO -} - -bool QGLPEXShaderManager::useCorrectShaderProg() -{ - if (!shaderProgNeedsChanging) { - activeProgram->use(); - return false; - } - - const char* fragmentShaderMainSrc = qglslFragmentShaderMain; - QGLShader* vertexShader = defaultVertexShader; - QGLShader* fragmentShader = noBrushShader; - - // Make sure we compile up the correct brush shader - switch (currentBrushStyle) { - case Qt::NoBrush: - break; - case Qt::SolidPattern: - if (!solidBrushShader) { - qDebug("Compiling qglslSolidBrushFragmentShader"); - solidBrushShader = new QGLShader(QGLShader::FragmentShader, ctx); - solidBrushShader->addSource(QLatin1String(qglslNoOpacityFragmentShaderMain)); - solidBrushShader->addSource(QLatin1String(qglslSolidBrushFragmentShader)); - if (!solidBrushShader->compile()) - qWarning() << "qglslSolidBrush failed to compile:" << solidBrushShader->log(); - } - fragmentShader = solidBrushShader; - break; - case Qt::TexturePattern: - if (!textureBrushVertexShader) { - qDebug("Compiling qglslTextureBrushVertexShader"); - textureBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); - textureBrushVertexShader->addSource(QLatin1String(qglslTextureBrushVertexShader)); - if (!textureBrushVertexShader->compile()) { - qWarning() << "qglslTextureBrushVertexShader failed to compile: " - << textureBrushVertexShader->log(); - } - } - vertexShader = textureBrushVertexShader; - - if (!textureBrushFragmentShader) { - qDebug("Compiling qglslTextureBrushFragmentShader"); - textureBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); - textureBrushFragmentShader->addSource(QLatin1String(fragmentShaderMainSrc)); - textureBrushFragmentShader->addSource(QLatin1String(qglslTextureBrushFragmentShader)); - if (!textureBrushFragmentShader->compile()) { - qWarning() << "qglslTextureBrushFragmentShader failed to compile:" - << textureBrushFragmentShader->log(); - } - } - fragmentShader = textureBrushFragmentShader; - break; - case Qt::LinearGradientPattern: - if (!linearBrushVertexShader) { - qDebug("Compiling qglslLinearGradientBrushVertexShader"); - linearBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); - linearBrushVertexShader->addSource(QLatin1String(qglslLinearGradientBrushVertexShader)); - if (!linearBrushVertexShader->compile()) { - qWarning() << "qglslLinearGradientBrushVertexShader failed to compile: " - << linearBrushVertexShader->log(); - } - } - vertexShader = linearBrushVertexShader; - - if (!linearBrushFragmentShader) { - qDebug("Compiling qglslLinearGradientBrushFragmentShader"); - linearBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); - linearBrushFragmentShader->addSource(QLatin1String(fragmentShaderMainSrc)); - linearBrushFragmentShader->addSource(QLatin1String(qglslLinearGradientBrushFragmentShader)); - if (!linearBrushFragmentShader->compile()) { - qWarning() << "qglslLinearGradientBrushFragmentShader failed to compile:" - << linearBrushFragmentShader->log(); - } - } - fragmentShader = linearBrushFragmentShader; - break; - case Qt::RadialGradientPattern: - if (!radialBrushVertexShader) { - qDebug("Compiling qglslRadialGradientBrushVertexShader"); - radialBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); - radialBrushVertexShader->addSource(QLatin1String(qglslRadialGradientBrushVertexShader)); - if (!radialBrushVertexShader->compile()) { - qWarning() << "qglslRadialGradientBrushVertexShader failed to compile: " - << radialBrushVertexShader->log(); - } - } - vertexShader = radialBrushVertexShader; - - if (!radialBrushFragmentShader) { - qDebug("Compiling qglslRadialGradientBrushFragmentShader"); - radialBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); - radialBrushFragmentShader->addSource(QLatin1String(fragmentShaderMainSrc)); - radialBrushFragmentShader->addSource(QLatin1String(qglslRadialGradientBrushFragmentShader)); - if (!radialBrushFragmentShader->compile()) { - qWarning() << "qglslRadialGradientBrushFragmentShader failed to compile:" - << radialBrushFragmentShader->log(); - } - } - fragmentShader = radialBrushFragmentShader; - break; - case Qt::ConicalGradientPattern: - // FIXME: We currently use the same vertex shader as radial brush - if (!conicalBrushVertexShader) { - qDebug("Compiling qglslConicalGradientBrushVertexShader"); - conicalBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); - conicalBrushVertexShader->addSource(QLatin1String(qglslConicalGradientBrushVertexShader)); - if (!conicalBrushVertexShader->compile()) { - qWarning() << "qglslConicalGradientBrushVertexShader failed to compile: " - << conicalBrushVertexShader->log(); - } - } - vertexShader = conicalBrushVertexShader; - - if (!conicalBrushFragmentShader) { - qDebug("Compiling qglslConicalGradientBrushFragmentShader"); - conicalBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); - conicalBrushFragmentShader->addSource(QLatin1String(fragmentShaderMainSrc)); - conicalBrushFragmentShader->addSource(QLatin1String(qglslConicalGradientBrushFragmentShader)); - if (!conicalBrushFragmentShader->compile()) { - qWarning() << "qglslConicalGradientBrushFragmentShader failed to compile:" - << conicalBrushFragmentShader->log(); - } - } - fragmentShader = conicalBrushFragmentShader; - break; - case Qt::Dense1Pattern: - case Qt::Dense2Pattern: - case Qt::Dense3Pattern: - case Qt::Dense4Pattern: - case Qt::Dense5Pattern: - case Qt::Dense6Pattern: - case Qt::Dense7Pattern: - case Qt::HorPattern: - case Qt::VerPattern: - case Qt::CrossPattern: - case Qt::BDiagPattern: - case Qt::FDiagPattern: - case Qt::DiagCrossPattern: - if (!patternBrushVertexShader) { - qDebug("Compiling qglslPatternBrushVertexShader"); - patternBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); - patternBrushVertexShader->addSource(QLatin1String(qglslPatternBrushVertexShader)); - if (!patternBrushVertexShader->compile()) { - qWarning() << "qglslPatternBrushVertexShader failed to compile: " - << patternBrushVertexShader->log(); - } - } - vertexShader = patternBrushVertexShader; - - if (!patternBrushFragmentShader) { - qDebug("Compiling qglslPatternBrushFragmentShader"); - patternBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); - patternBrushFragmentShader->addSource(QLatin1String(qglslNoOpacityFragmentShaderMain)); - patternBrushFragmentShader->addSource(QLatin1String(qglslPatternBrushFragmentShader)); - if (!patternBrushFragmentShader->compile()) { - qWarning() << "qglslPatternBrushFragmentShader failed to compile:" - << patternBrushFragmentShader->log(); - } - } - fragmentShader = patternBrushFragmentShader; - break; - default: - qWarning("Unimplemented brush style (%d)", currentBrushStyle); - } - - // Now newBrushShader is set correctly, check to see if we already have the program - // already linked and ready to go in the cache: - bool foundProgram = false; - foreach (QGLCachedShaderProg cachedProg, cachedPrograms) { - if ((cachedProg.vertexShader == vertexShader) && - (cachedProg.brushShader == fragmentShader) && - (cachedProg.compositionShader == 0) ) { - - activeProgram = cachedProg.shader; - foundProgram = true; - break; - } - } - - if (!foundProgram) { - qDebug() << "Linking shader program for " << currentBrushStyle; - // Required program not found - create it. - QGLShaderProgram* newProg = new QGLShaderProgram(ctx); - - newProg->addShader(vertexShader); - newProg->addShader(fragmentShader); - - if (!newProg->link()) - qWarning() << "Shader program for " << currentBrushStyle << "failed to link:" << newProg->log(); - - QGLCachedShaderProg cachedProg; - cachedProg.vertexShader = vertexShader; - cachedProg.brushShader = fragmentShader; - cachedProg.compositionShader = 0; - cachedProg.shader = newProg; - - cachedPrograms.append(cachedProg); - activeProgram = newProg; - } - - activeProgram->use(); - shaderProgNeedsChanging = false; - return true; -} - -QGLShaderProgram* QGLPEXShaderManager::brushShader() -{ - return activeProgram; -} - -// The only uniform the simple shader has is the PMV matrix -QGLShaderProgram* QGLPEXShaderManager::simpleShader() -{ - if (!simpleShaderProgram) { - simpleShaderProgram = new QGLShaderProgram(ctx); - - if (!simpleFragmentShader) { - simpleFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); - simpleFragmentShader->addSource(QLatin1String(qglslSimpleFragmentShader)); - if (!simpleFragmentShader->compile()) - qWarning() << "qglslSimpleFragmentShader failed to compile:" << simpleFragmentShader->log(); - } - - simpleShaderProgram->addShader(defaultVertexShader); - simpleShaderProgram->addShader(simpleFragmentShader); - if (!simpleShaderProgram->link()) - qWarning() << "Simple shader program failed to link:" << simpleShaderProgram->log(); - } - - return simpleShaderProgram; -} - -QGLShaderProgram* QGLPEXShaderManager::imageShader() -{ - if (!imageShaderProgram) { - if (!imageVertexShader) { - imageVertexShader = new QGLShader(QGLShader::VertexShader, ctx); - imageVertexShader->addSource(QLatin1String(qglslImageVertexShader)); - if (!imageVertexShader->compile()) - qWarning() << "Image/Pixmap vertex shader failed to compile:" << imageVertexShader->log(); - } - - if (!imageFragmentShader) { - imageFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); - imageFragmentShader->addSource(QLatin1String(qglslImageFragmentShader)); - if (!imageFragmentShader->compile()) - qWarning() << "Image/Pixmap fragment shader failed to compile:" << imageFragmentShader->log(); - } - - imageShaderProgram = new QGLShaderProgram(ctx); - imageShaderProgram->addShader(imageVertexShader); - imageShaderProgram->addShader(imageFragmentShader); - if (!imageShaderProgram->link()) - qWarning() << "Image/Pixmap shader program failed to link:" << imageShaderProgram->log(); - } - - return imageShaderProgram; -} - -QGLShaderProgram* QGLPEXShaderManager::textShader() -{ - if (!textShaderProgram) { - if (!textVertexShader) { - textVertexShader = new QGLShader(QGLShader::VertexShader, ctx); - textVertexShader->addSource(QLatin1String(qglslImageVertexShader)); - if (!textVertexShader->compile()) - qWarning() << "Text vertex shader failed to compile:" << textVertexShader->log(); - } - - if (!textFragmentShader) { - textFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); - textFragmentShader->addSource(QLatin1String(qglslTextFragmentShader)); - if (!textFragmentShader->compile()) - qWarning() << "Text fragment shader failed to compile:" << textFragmentShader->log(); - } - - textShaderProgram = new QGLShaderProgram(ctx); - textShaderProgram->addShader(textVertexShader); - textShaderProgram->addShader(textFragmentShader); - if (!textShaderProgram->link()) - qWarning() << "Text shader program failed to link:" << textShaderProgram->log(); - } - - return textShaderProgram; -} - diff --git a/src/opengl/gl2paintengineex/qglpexshadermanager_p.h b/src/opengl/gl2paintengineex/qglpexshadermanager_p.h deleted file mode 100644 index c8f47b2..0000000 --- a/src/opengl/gl2paintengineex/qglpexshadermanager_p.h +++ /dev/null @@ -1,156 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qglshader_p.h" - - -// Worstcase combo: Brush->Mask->Composition - -/* - Vertex shader source is specified with a single string. This string - contains the main function and sets the gl_Position. The choice of - which vertex shader to use depends on: - - Brush style - - Brush transform->isAffine() - - Fragment shaders are specified as multiple strings, one for the main - function, one for the brush calculation and optionally one for the - extended composition mode. Brushes are implementations of - "mediump vec4 brush()" - Composition modes are implemented as a - "mediump vec4 compose(mediump vec4 color)" - NOTE: Precision may change in future. - - The choice of which main() fragment shader string to use depends on: - - Global opacity - - Brush style (some brushes apply opacity themselves) - - Use of mask (TODO: Need to support high quality anti-aliasing & text) - - Composition mode - - The choice of which brush() fragment shader to use depends on: - - Brush style - -*/ - - -struct QGLCachedShaderProg -{ - QGLShader* vertexShader; - QGLShader* brushShader; - QGLShader* compositionShader; - QGLShaderProgram* shader; -}; - -class QGLPEXShaderManager -{ -public: - QGLPEXShaderManager(const QGLContext* context); - ~QGLPEXShaderManager(); - - enum TransformType {IdentityTransform, ScaleTransform, TranslateTransform, FullTransform}; - - void optimiseForBrushTransform(const QTransform& transform); - void setBrushStyle(Qt::BrushStyle style); - void setUseGlobalOpacity(bool value); - void setAffineOnlyBrushTransform(bool value); // I.e. Do we need to apply perspective-correction? - // Not doing so saves some vertex shader calculations. - - bool useCorrectShaderProg(); // returns true if the shader program has changed - - QGLShaderProgram* brushShader(); - QGLShaderProgram* simpleShader(); // Used to draw into e.g. stencil buffers - QGLShaderProgram* imageShader(); - QGLShaderProgram* textShader(); - -private: - QGLShader* defaultVertexShader; - - QGLShader* imageVertexShader; - QGLShader* imageFragmentShader; - QGLShaderProgram* imageShaderProgram; - - QGLShader* textVertexShader; - QGLShader* textFragmentShader; - QGLShaderProgram* textShaderProgram; - - QGLShader* noBrushShader; - QGLShader* solidBrushShader; - - QGLShader* conicalBrushVertexShader; - QGLShader* conicalBrushFragmentShader; - - QGLShader* radialBrushVertexShader; - QGLShader* radialBrushFragmentShader; - - QGLShader* linearBrushVertexShader; - QGLShader* linearBrushFragmentShader; - - QGLShader* patternBrushVertexShader; - QGLShader* patternBrushFragmentShader; - - QGLShader* textureBrushFragmentShader; - QGLShader* textureBrushVertexShader; - - QGLShader* simpleFragmentShader; - QGLShaderProgram* simpleShaderProgram; - - QGLShaderProgram* activeProgram; - - Qt::BrushStyle currentBrushStyle; - bool useGlobalOpacity; - TransformType currentTransformType; - bool shaderProgNeedsChanging; - - QList<QGLCachedShaderProg> cachedPrograms; - - QGLContext* ctx; -}; diff --git a/src/opengl/gl2paintengineex/qglshader.cpp b/src/opengl/gl2paintengineex/qglshader.cpp deleted file mode 100644 index 634be84..0000000 --- a/src/opengl/gl2paintengineex/qglshader.cpp +++ /dev/null @@ -1,605 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qglshader_p.h" - - -// Windows needs to resolve OpenGL 2.0 function pointers for each context. The -// QGL OpenGL 2.0 functions are actually macros, which take a "ctx" parameter. -#define Q_CTX QGLContext* ctx = d->ctx; \ - if (!ctx) \ - return false; \ - ctx->makeCurrent(); \ - - - - -class QGLShaderPrivate -{ -public: - QGLShaderPrivate() : shaderId(0), valid(false), ctx(0) {} - - GLuint shaderId; - QString source; - bool valid; - QGLShader::ShaderType type; - QGLContext* ctx; -}; - - -QGLShader::QGLShader(QGLShader::ShaderType type, const QGLContext* ctx) - : d_ptr(new QGLShaderPrivate) -{ - Q_D(QGLShader); - - if (!ctx) - ctx = QGLContext::currentContext(); - - if (!ctx) { - qWarning("QGLShader being created without a context"); - return; - } - - d->ctx = const_cast<QGLContext*>(ctx); - d->ctx->makeCurrent(); - - if (type == QGLShader::FragmentShader) - d->shaderId = glCreateShader(GL_FRAGMENT_SHADER); - else - d->shaderId = glCreateShader(GL_VERTEX_SHADER); - - if (d->shaderId == 0) { - qWarning("Error creating shader object"); - return; - } - - d->type = type; -} - -GLuint QGLShader::id() -{ - Q_D(QGLShader); - return d->shaderId; -} - -const QGLContext* QGLShader::context() -{ - Q_D(QGLShader); - return d->ctx; -} - -void QGLShader::clearSource() -{ - Q_D(QGLShader); - d->source.clear(); - d->valid = false; -} - -void QGLShader::addSource(const QLatin1String& newSource) -{ - Q_D(QGLShader); - d->source += newSource; - d->valid = false; -} - - -bool QGLShader::compile() -{ - Q_D(QGLShader); - - d->valid = false; - - if (d->source.size() == 0) - return false; - - const QByteArray src_ba = d->source.toAscii(); - const char* src = src_ba.constData(); - - glShaderSource(d->shaderId, 1, &src, 0); - - glCompileShader(d->shaderId); - - GLint shaderCompiled; - glGetShaderiv(d->shaderId, GL_COMPILE_STATUS, &shaderCompiled); - if (!shaderCompiled) - return false; - - d->valid = true; - return true; -} - -bool QGLShader::isValid() -{ - Q_D(QGLShader); - return d->valid; -} - -QString QGLShader::log() -{ - Q_D(QGLShader); - - char* logData; - GLint logSize; - GLint logLength; - - glGetShaderiv(d->shaderId, GL_INFO_LOG_LENGTH, &logSize); - - if (!logSize) - return QString(); - - logData = new char[logSize]; - glGetShaderInfoLog(d->shaderId, logSize, &logLength, logData); - QString result = QString::fromAscii(logData); - delete [] logData; - - return result; -} - - - - - - - - - - - - -class QGLShaderProgramPrivate -{ -public: - QGLShaderProgramPrivate() : valid(false), programId(0), ctx(0) {} - void populateVariableLists(); - - QVector<QGLShader*> shaders; - QGLUniformList uniforms; - QGLVertexAttributeList attributeArrays; - bool valid; - GLuint programId; - QGLContext* ctx; -}; - - - -void QGLShaderProgramPrivate::populateVariableLists() -{ - attributeArrays.clear(); - uniforms.clear(); - - int count; - int sizeOfNameBuff; - char* name; - GLint nameLength; - GLenum type; - GLint size; - GLint location; - - glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTES, &count); - glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &sizeOfNameBuff); - name = new char[sizeOfNameBuff]; - - for (int i = 0; i < count; ++i) { - nameLength = -1; - glGetActiveAttrib(programId, i, sizeOfNameBuff, &nameLength, &size, &type, name); - if (nameLength == -1) - continue; - - location = glGetAttribLocation(programId, name); - attributeArrays.insert(QString::fromAscii(name), QGLVertexAttribute(type, location, ctx)); - } - - delete [] name; - - - glGetProgramiv(programId, GL_ACTIVE_UNIFORMS, &count); - glGetProgramiv(programId, GL_ACTIVE_UNIFORM_MAX_LENGTH, &sizeOfNameBuff); - - name = new char[sizeOfNameBuff]; - - for (int i = 0; i < count; ++i) { - nameLength = -1; - glGetActiveUniform(programId, i, sizeOfNameBuff, &nameLength, &size, &type, name); - if (nameLength == -1) - continue; - - location = glGetUniformLocation(programId, name); - uniforms.insert(QString::fromAscii(name), QGLUniform(type, location, ctx)); - } -} - - -QGLShaderProgram::QGLShaderProgram(const QGLContext* ctx) - : d_ptr(new QGLShaderProgramPrivate) -{ - Q_D(QGLShaderProgram); - if (!ctx) - ctx = QGLContext::currentContext(); - - if (!ctx) { - qWarning("QGLShaderProgram being created without a context"); - return; - } - - d->ctx = const_cast<QGLContext*>(ctx); - d->ctx->makeCurrent(); - - d->programId = glCreateProgram(); - - d->valid = false; -} - - -const QGLUniformList & QGLShaderProgram::uniforms() -{ - Q_D(QGLShaderProgram); - return const_cast<const QGLUniformList&>(d->uniforms); -} - - -const QGLVertexAttributeList& QGLShaderProgram::vertexAttributes() -{ - Q_D(QGLShaderProgram); - return const_cast<const QGLVertexAttributeList&>(d->attributeArrays); -} - - -bool QGLShaderProgram::addShader(QGLShader* newShader) -{ - Q_D(QGLShaderProgram); - if (!newShader || !d->ctx) - return false; - - if (newShader->context() != d->ctx) { - qWarning("Shader object's context does not match program's context"); - return false; - } - - if (!newShader->isValid()) - return false; - - QGLContext* ctx = d->ctx; - if (!ctx) - return false; - ctx->makeCurrent(); - - glAttachShader(d->programId, newShader->id()); - - d->shaders.append(newShader); - return true; -} - - -bool QGLShaderProgram::removeShader(QGLShader* oldShader) -{ - Q_D(QGLShaderProgram); - - int idx = d->shaders.indexOf(oldShader); - - if (idx == -1) - return false; - - d->shaders.remove(idx); - - QGLContext* ctx = d->ctx; - if (!ctx) - return false; - ctx->makeCurrent(); - - glDetachShader(d->programId, oldShader->id()); - return true; -} - - -bool QGLShaderProgram::removeAllShaders() -{ - Q_D(QGLShaderProgram); - - QGLContext* ctx = d->ctx; - if (!ctx) - return false; - ctx->makeCurrent(); - - foreach (QGLShader* shader, d->shaders) - glDetachShader(d->programId, shader->id()); - - d->shaders.clear(); - return true; -} - -#include <stdio.h> - -bool QGLShaderProgram::link() -{ - Q_D(QGLShaderProgram); - - QGLContext* ctx = d->ctx; - if (!ctx) - return false; - ctx->makeCurrent(); - - glLinkProgram(d->programId); - - - GLint linked; - glGetProgramiv(d->programId, GL_LINK_STATUS, &linked); - - if (!linked) - return false; - - d->populateVariableLists(); - - d->valid = true; - return true; -} - -void QGLShaderProgram::use() -{ - Q_D(QGLShaderProgram); - if (!d->valid) - return; - - glUseProgram(d->programId); -} - - -QString QGLShaderProgram::log() -{ - Q_D(QGLShaderProgram); - - QGLContext* ctx = d->ctx; - if (!ctx) - return QString(); - ctx->makeCurrent(); - - GLint logSize = -666; - glGetProgramiv(d->programId, GL_INFO_LOG_LENGTH, &logSize); - - char* logData = new char[logSize]; - GLint logLength; - - glGetProgramInfoLog(d->programId, logSize, &logLength, logData); - - QString result = QString::fromAscii(logData); - delete [] logData; - - return result; -} - -GLuint QGLShaderProgram::id() -{ - Q_D(QGLShaderProgram); - return d->programId; -} - -///////////////////////////////////////////////////////////////////////// - - - - -QGLUniform::QGLUniform() - : m_id(0), m_type(QGLInvalidType), ctx(0) -{ - qWarning("Unknown uniform! Either the uniform doesn't exist or it was removed at shader link"); -} - -const QGLUniform& QGLUniform::operator=(const GLfloat& rhs) const -{ - if (m_type != QGLFloatType) - return *this; - - glUniform1f(m_id, rhs); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const QGLVec2& rhs) const -{ - if (m_type != QGLVec2Type) - return *this; - - glUniform2fv(m_id, 1, (const GLfloat*)&rhs); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const QSizeF& rhs) const -{ - if (m_type != QGLVec2Type) - return *this; - - glUniform2f(m_id, rhs.width(), rhs.height()); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const QPointF& rhs) const -{ - if (m_type != QGLVec2Type) - return *this; - - glUniform2f(m_id, rhs.x(), rhs.y()); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const QGLVec3& rhs) const -{ - if (m_type != QGLVec3Type) - return *this; - - glUniform3fv(m_id, 1, (const GLfloat*)&rhs); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const QGLVec4& rhs) const -{ - if (m_type != QGLVec4Type) - return *this; - - glUniform4fv(m_id, 1, (const GLfloat*)&rhs); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const QColor& rhs) const -{ - if (m_type != QGLVec4Type) - return *this; - - glUniform4f(m_id, rhs.redF(), rhs.greenF(), rhs.blueF(), rhs.alphaF()); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const GLfloat rhs[2][2]) const -{ - if (m_type != QGLMat2Type) - return *this; - - glUniformMatrix2fv(m_id, 1, GL_FALSE, (GLfloat*)rhs); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const GLfloat rhs[3][3]) const -{ - if (m_type != QGLMat3Type) - return *this; - - glUniformMatrix3fv(m_id, 1, GL_FALSE, (GLfloat*)rhs); - - return *this; -} - -// Transposes ready for GL -const QGLUniform& QGLUniform::operator=(const QTransform& rhs) const -{ - if (m_type != QGLMat3Type) - return *this; - - GLfloat mat3[3][3] = { - {rhs.m11(), rhs.m12(), rhs.m13()}, - {rhs.m21(), rhs.m22(), rhs.m23()}, - {rhs.m31(), rhs.m32(), rhs.m33()} - }; - - glUniformMatrix3fv(m_id, 1, GL_FALSE, (GLfloat*)mat3); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const GLfloat rhs[4][4]) const -{ - if (m_type != QGLMat4Type) - return *this; - - glUniformMatrix4fv(m_id, 1, GL_FALSE, (GLfloat*)rhs); - - return *this; -} - -const QGLUniform& QGLUniform::operator=(const GLuint& rhs) const -{ - if ((m_type != QGLSampler2DType) || (m_type != QGLSamplerCubeType)) - return *this; - - glUniform1i(m_id, rhs); - - return *this; -} - - - - -///////////////////////////////////////////////////////////////////////// - -QGLVertexAttribute::QGLVertexAttribute() - : m_id(0), m_type(QGLInvalidType), ctx(0) -{ - qWarning("Unknown vertex attribute!"); -} - -void QGLVertexAttribute::enable() const -{ - glEnableVertexAttribArray(m_id); -} - -void QGLVertexAttribute::disable() const -{ - glDisableVertexAttribArray(m_id); -} - -// NOTE: Under PC emulation, QGLVec4Type is _always_ returned as the type, so this -// method isn't very useful. I.e. The datatypes are needed to distinguish the different -// sizes for the function signatures. -const QGLVertexAttribute& QGLVertexAttribute::operator=(const GLfloat* rhs) const -{ - int size = -1; - if (m_type == QGLFloatType) - size = 1; - else if (m_type == QGLVec2Type) - size = 2; - else if (m_type == QGLVec3Type) - size = 3; - else if (m_type == QGLVec4Type) - size = 4; - else if (m_type == QGLMat2Type) //### Not sure if this is right for matrix attributes... - size = 4; - else if (m_type == QGLMat3Type) //### Not sure if this is right for matrix attributes... - size = 9; - else if (m_type == QGLMat4Type) //### Not sure if this is right for matrix attributes... - size = 16; - else - return *this; - - glVertexAttribPointer(m_id, size, GL_FLOAT, GL_FALSE, 0, rhs); - - return *this; -} - -const QGLVertexAttribute& QGLVertexAttribute::operator=(const QGLVec3* rhs) const -{ - glVertexAttribPointer(m_id, 3, GL_FLOAT, GL_FALSE, 0, (GLfloat*)rhs); - - return *this; -} diff --git a/src/opengl/gl2paintengineex/qglshader_p.h b/src/opengl/gl2paintengineex/qglshader_p.h deleted file mode 100644 index 1625b84..0000000 --- a/src/opengl/gl2paintengineex/qglshader_p.h +++ /dev/null @@ -1,260 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -/* -Uniform Types in OpenGL ES 2.0 -============================== -GL_FLOAT GLfloat GLfloat -GL_FLOAT_VEC2 QGLVec2 GLfloat[2] -GL_FLOAT_VEC3 QGLVec3 GLfloat[3] -GL_FLOAT_VEC4 QGLVec4 GLfloat[4] -GL_INT GLint GLint -GL_INT_VEC2 QGLIVec2 GLint[2] -GL_INT_VEC3 QGLIVec3 GLint[3] -GL_INT_VEC4 QGLIVec4 GLint[4] -GL_BOOL GLbool GLbool -GL_BOOL_VEC2 QGLBVec2 GLbool[2] -GL_BOOL_VEC3 QGLBVec3 GLbool[3] -GL_BOOL_VEC4 QGLBVec4 GLbool[4] -GL_FLOAT_MAT2 QGLMat2 GLfloat[2][2] -GL_FLOAT_MAT3 QGLMat3 GLfloat[3][3] -GL_FLOAT_MAT4 QGLMat4 GLfloat[4][4] -GL_SAMPLER_2D QGLSampler2D GLuint -GL_SAMPLER_CUBE QGLSamplerCube GLuint - -Additional Types in Desktop OpenGL 2.0 -====================================== -SAMPLER_1D, -SAMPLER_3D, -SAMPLER_1D_SHADOW, -SAMPLER_2D_SHADOW. -*/ - -#include <QtOpenGL> - - -typedef struct { - GLfloat a; - GLfloat b; -} QGLVec2; - -typedef struct { - GLfloat a; - GLfloat b; - GLfloat c; -} QGLVec3; - -typedef struct { - GLfloat a; - GLfloat b; - GLfloat c; - GLfloat d; -} QGLVec4; - - -class QGLShaderProgram; - -class QGLShaderPrivate; - -class QGLShader : QObject -{ - Q_OBJECT -public: - enum ShaderType {VertexShader, FragmentShader}; - - QGLShader(ShaderType type, const QGLContext* ctx = 0); - - GLuint id(); - void clearSource(); - void addSource(const QLatin1String& newSource); - bool compile(); - bool isValid(); - QString log(); - const QGLContext* context(); //maybe make private with prog a friend? - -private: - QGLShaderPrivate* d_ptr; - Q_DECLARE_PRIVATE(QGLShader); - -/* -public slots: - void cleanupGLContextRefs(const QGLContext *context); -*/ -}; - - -enum QGLType { - QGLInvalidType = 0, - QGLFloatType = GL_FLOAT, - QGLVec2Type = GL_FLOAT_VEC2, - QGLVec3Type = GL_FLOAT_VEC3, - QGLVec4Type = GL_FLOAT_VEC4, - QGLIntType = GL_INT, - QGLIVec2Type = GL_INT_VEC2, - QGLIVec3Type = GL_INT_VEC3, - QGLIVec4Type = GL_INT_VEC4, - QGLBoolType = GL_BOOL, - QGLBVec2Type = GL_BOOL_VEC2, - QGLBVec3Type = GL_BOOL_VEC3, - QGLBVec4Type = GL_BOOL_VEC4, - QGLMat2Type = GL_FLOAT_MAT2, - QGLMat3Type = GL_FLOAT_MAT3, - QGLMat4Type = GL_FLOAT_MAT4, - QGLSampler2DType = GL_SAMPLER_2D, - QGLSamplerCubeType = GL_SAMPLER_CUBE -}; - -class QGLUniform -{ -public: - - QGLUniform(GLenum glType, GLint location, QGLContext* context) - : m_id(location), m_type(QGLType(glType)), ctx(context) {} - - QGLUniform(); // Called by QMap when there's no match on the name - - QGLType type() const {return m_type;} - GLuint id() const {return m_id;} - - // Seems odd to be const, but it doesn't actually modify any of the - // class members, only the GL state! - const QGLUniform& operator=(const GLfloat&) const; - - const QGLUniform& operator=(const QGLVec2&) const; - const QGLUniform& operator=(const QSizeF&) const; - const QGLUniform& operator=(const QPointF&) const; - - const QGLUniform& operator=(const QGLVec3&) const; - - const QGLUniform& operator=(const QGLVec4&) const; - const QGLUniform& operator=(const QColor&) const; - - const QGLUniform& operator=(const GLfloat[2][2]) const; - - const QGLUniform& operator=(const GLfloat[3][3]) const; - const QGLUniform& operator=(const QTransform&) const; - - const QGLUniform& operator=(const GLfloat[4][4]) const; - - const QGLUniform& operator=(const GLuint&) const; // sampler2d, specifying a texture unit - - -protected: - GLuint m_id; - QGLType m_type; - QGLContext* ctx; -}; - -typedef QMap<QString, QGLUniform> QGLUniformList; -typedef QMapIterator<QString, QGLUniform> QGLUniformListIterator; - - -class QGLVertexAttribute -{ -public: - QGLVertexAttribute(GLenum glType, GLuint location, QGLContext* context) - : m_id(location), m_type(QGLType(glType)), ctx(context) {} - - QGLVertexAttribute(); // Called by QMap when there's no match on the name - - QGLType type() const {return m_type;} - GLuint id() const {return m_id;} - void enable() const; - void disable() const; - - const QGLVertexAttribute& operator=(const GLfloat* rhs) const; - const QGLVertexAttribute& operator=(const QGLVec3* rhs) const; - -protected: - GLuint m_id; - QGLType m_type; - QGLContext* ctx; -}; - -//TODO: Convert into setter overloads on QGLShaderProgram -typedef QMap<QString, QGLVertexAttribute> QGLVertexAttributeList; -typedef QMapIterator<QString, QGLVertexAttribute> QGLVertexAttributeListIterator; - - - -class QGLShaderProgramPrivate; - -class QGLShaderProgram : QObject -{ - Q_OBJECT -public: - QGLShaderProgram(const QGLContext* ctx = 0); - - const QGLUniformList & uniforms(); - const QGLVertexAttributeList& vertexAttributes(); - - bool addShader(QGLShader* newShader); - bool removeShader(QGLShader* oldShader); - bool removeAllShaders(); - - bool link(); - QString log(); - bool isValid(); - void use(); - - GLuint id(); - -private: - QGLShaderProgramPrivate* d_ptr; - Q_DECLARE_PRIVATE(QGLShaderProgram); - -/* -public slots: - void cleanupGLContextRefs(const QGLContext *context); -*/ -}; - diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index beb4da6..19cb02a 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -62,7 +62,6 @@ and use the correct program when we really need it. */ - #include "qpaintengineex_opengl2_p.h" #include <string.h> //for memcpy @@ -77,93 +76,167 @@ #include <private/qtextureglyphcache_p.h> #include "qglgradientcache_p.h" -#include "qglpexshadermanager_p.h" +#include "qglengineshadermanager_p.h" #include "qgl2pexvertexarray_p.h" +#include <QDebug> -extern QImage qt_imageForBrush(int brushStyle, bool invert); //in qbrush.cpp +QT_BEGIN_NAMESPACE +static const GLuint QT_BRUSH_TEXTURE_UNIT = 0; +static const GLuint QT_IMAGE_TEXTURE_UNIT = 0; //Can be the same as brush texture unit +static const GLuint QT_MASK_TEXTURE_UNIT = 1; +static const GLuint QT_BACKGROUND_TEXTURE_UNIT = 2; -#include <QDebug> +class QGLTextureGlyphCache : public QTextureGlyphCache +{ +public: + QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix); + ~QGLTextureGlyphCache(); + + virtual void createTextureData(int width, int height); + virtual void resizeTextureData(int width, int height); + virtual void fillTexture(const Coord &c, glyph_t glyph); + + inline GLuint texture() const { return m_texture; } + + inline int width() const { return m_width; } + inline int height() const { return m_height; } + + inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; } + +private: + QGLContext *ctx; + QGL2PaintEngineExPrivate *pex; -static const GLuint QT_VERTEX_COORDS_ATTR = 0; -static const GLuint QT_TEXTURE_COORDS_ATTR = 1; -static const GLuint QT_BRUSH_TEXTURE_UNIT = 0; + GLuint m_texture; + GLuint m_fbo; -class QGL2PaintEngineExPrivate : public QPaintEngineExPrivate + int m_width; + int m_height; + + QGLShaderProgram *m_program; +}; + +QGLTextureGlyphCache::QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix) + : QTextureGlyphCache(type, matrix) + , ctx(context) + , m_width(0) + , m_height(0) { - Q_DECLARE_PUBLIC(QGL2PaintEngineEx) -public: - QGL2PaintEngineExPrivate(QGL2PaintEngineEx *q_ptr) : - q(q_ptr), - width(0), height(0), - ctx(0), - currentBrush( &(q->state()->brush) ), - inverseScale(1), - shaderManager(0) - { } + glGenFramebuffers(1, &m_fbo); +} + +QGLTextureGlyphCache::~QGLTextureGlyphCache() +{ + glDeleteFramebuffers(1, &m_fbo); + + if (m_width || m_height) + glDeleteTextures(1, &m_texture); +} - ~QGL2PaintEngineExPrivate(); +void QGLTextureGlyphCache::createTextureData(int width, int height) +{ + glGenTextures(1, &m_texture); + glBindTexture(GL_TEXTURE_2D, m_texture); - void updateBrushTexture(); - void updateBrushUniforms(); - void updateMatrix(); - void updateCompositionMode(); - void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform); + m_width = width; + m_height = height; - void setBrush(const QBrush* brush); + QVarLengthArray<uchar> data(width * height); + for (int i = 0; i < width * height; ++i) + data[i] = 0; - void drawTexture(const QGLRect& dest, const QGLRect& src, int txtWidth, int txtHeight); + if (m_type == QFontEngineGlyphCache::Raster_RGBMask) + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]); + else + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]); - void fill(const QVectorPath &path); - void drawOutline(const QVectorPath& path); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +} + +void QGLTextureGlyphCache::resizeTextureData(int width, int height) +{ + // ### the QTextureGlyphCache API needs to be reworked to allow + // ### resizeTextureData to fail - void drawVertexArrays(QGL2PEXVertexArray& vertexArray, GLenum primitive); - // ^ draws whatever is in the vertex array - void composite(const QGLRect& boundingRect); - // ^ Composites the bounding rect onto dest buffer - void fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill); - // ^ Calls drawVertexArrays to render into stencil buffer - void cleanStencilBuffer(const QGLRect& area); + int oldWidth = m_width; + int oldHeight = m_height; - void prepareForDraw(); + GLuint oldTexture = m_texture; + createTextureData(width, height); - inline void useSimpleShader(); - inline QColor premultiplyColor(QColor c, GLfloat opacity); + glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo); - QGL2PaintEngineEx* q; + GLuint colorBuffer; + glGenRenderbuffers(1, &colorBuffer); + glBindRenderbuffer(GL_RENDERBUFFER_EXT, colorBuffer); + glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_RGBA, oldWidth, oldHeight); + glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_RENDERBUFFER_EXT, colorBuffer); + glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0); - //### Move into QGLDrawable - int width, height; - QGLContext* ctx; + glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); + glBindTexture(GL_TEXTURE_2D, oldTexture); - // Dirty flags - bool matrixDirty; // Implies matrix uniforms are also dirty - bool compositionModeDirty; - bool brushTextureDirty; - bool brushUniformsDirty; - bool simpleShaderMatrixUniformDirty; - bool brushShaderMatrixUniformDirty; - bool imageShaderMatrixUniformDirty; - bool textShaderMatrixUniformDirty; - bool stencilBuferDirty; + pex->transferMode(BrushDrawingMode); - const QBrush* currentBrush; // May not be the state's brush! + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); - GLfloat inverseScale; + glViewport(0, 0, oldWidth, oldHeight); - QGL2PEXVertexArray pathVertexArray; + float vertexCoordinateArray[] = { -1, -1, 1, -1, 1, 1, -1, 1 }; + float textureCoordinateArray[] = { 0, 0, 1, 0, 1, 1, 0, 1 }; - GLfloat pmvMatrix[4][4]; + glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); + glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); - QGLPEXShaderManager* shaderManager; + glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray); + glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray); - // Clipping & state stuff stolen from QOpenGLPaintEngine: - void updateDepthClip(); - uint use_system_clip : 1; -}; + pex->shaderManager->blitProgram()->enable(); + pex->shaderManager->blitProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT); + pex->shaderManager->setDirty(); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); + glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); + + glBindTexture(GL_TEXTURE_2D, m_texture); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_RENDERBUFFER_EXT, 0); + glDeleteRenderbuffers(1, &colorBuffer); + glDeleteTextures(1, &oldTexture); + + glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); + + glViewport(0, 0, pex->width, pex->height); + pex->updateDepthScissorTest(); +} + +void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph) +{ + QImage mask = textureMapForGlyph(glyph); + + const uint maskWidth = mask.width(); + const uint maskHeight = mask.height(); + + glBindTexture(GL_TEXTURE_2D, m_texture); + if (mask.format() == QImage::Format_RGB32) { + glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, m_height - c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits()); + } else { + mask = mask.convertToFormat(QImage::Format_Indexed8); + glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_ALPHA, GL_UNSIGNED_BYTE, mask.bits()); + } +} + +extern QImage qt_imageForBrush(int brushStyle, bool invert); ////////////////////////////////// Private Methods ////////////////////////////////////////// @@ -177,7 +250,7 @@ QGL2PaintEngineExPrivate::~QGL2PaintEngineExPrivate() void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform) { - glActiveTexture(QT_BRUSH_TEXTURE_UNIT); +// glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); //### Is it always this texture unit? if (smoothPixmapTransform) { glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -193,11 +266,11 @@ void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMod QColor QGL2PaintEngineExPrivate::premultiplyColor(QColor c, GLfloat opacity) { - uint alpha = qRound(c.alpha() * opacity); - return QColor ( ((c.red() * alpha + 128) >> 8), - ((c.green() * alpha + 128) >> 8), - ((c.blue() * alpha + 128) >> 8), - alpha); + qreal alpha = c.alphaF() * opacity; + c.setRedF(c.redF() * alpha); + c.setGreenF(c.greenF() * alpha); + c.setBlueF(c.blueF() * alpha); + return c; } @@ -206,27 +279,39 @@ void QGL2PaintEngineExPrivate::setBrush(const QBrush* brush) currentBrush = brush; brushTextureDirty = true; brushUniformsDirty = true; - shaderManager->setBrushStyle(currentBrush->style()); - shaderManager->setAffineOnlyBrushTransform(currentBrush->transform().isAffine()); + if (currentBrush->style() == Qt::TexturePattern + && qHasPixmapTexture(*brush) && brush->texture().isQBitmap()) + { + shaderManager->setSrcPixelType(QGLEngineShaderManager::TextureSrcWithPattern); + } else { + shaderManager->setSrcPixelType(currentBrush->style()); + } + shaderManager->optimiseForBrushTransform(currentBrush->transform()); } // Unless this gets used elsewhere, it's probably best to merge it into fillStencilWithVertexArray void QGL2PaintEngineExPrivate::useSimpleShader() { - shaderManager->simpleShader()->use(); + shaderManager->simpleProgram()->enable(); + shaderManager->setDirty(); if (matrixDirty) updateMatrix(); if (simpleShaderMatrixUniformDirty) { - shaderManager->simpleShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix; + shaderManager->simpleProgram()->setUniformValue("pmvMatrix", pmvMatrix); simpleShaderMatrixUniformDirty = false; } + + if (simpleShaderDepthUniformDirty) { + shaderManager->simpleProgram()->setUniformValue("depth", (GLfloat)q->state()->currentDepth); + simpleShaderDepthUniformDirty = false; + } } -Q_GLOBAL_STATIC(QGLGradientCache, qt_opengl_gradient_cache) +Q_GLOBAL_STATIC(QGL2GradientCache, qt_opengl_gradient_cache) void QGL2PaintEngineExPrivate::updateBrushTexture() { @@ -235,9 +320,9 @@ void QGL2PaintEngineExPrivate::updateBrushTexture() if ( (style >= Qt::Dense1Pattern) && (style <= Qt::DiagCrossPattern) ) { // Get the image data for the pattern - QImage texImage = qt_imageForBrush(style, true); + QImage texImage = qt_imageForBrush(style, false); - glActiveTexture(QT_BRUSH_TEXTURE_UNIT); + glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); ctx->d_func()->bindTexture(texImage, GL_TEXTURE_2D, GL_RGBA, true); updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true); } @@ -257,12 +342,13 @@ void QGL2PaintEngineExPrivate::updateBrushTexture() else updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, true); + glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); glBindTexture(GL_TEXTURE_2D, texId); } else if (style == Qt::TexturePattern) { const QPixmap& texPixmap = currentBrush->texture(); - glActiveTexture(QT_BRUSH_TEXTURE_UNIT); + glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, true); updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true); } @@ -278,17 +364,11 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() if (style == Qt::NoBrush) return; - GLfloat opacity = 1.0; - if (q->state()->opacity < 0.99f) - opacity = (GLfloat)q->state()->opacity; - bool setOpacity = true; - QTransform brushQTransform = currentBrush->transform(); if (style == Qt::SolidPattern) { - QColor col = premultiplyColor(currentBrush->color(), opacity); - shaderManager->brushShader()->uniforms()[QLatin1String("fragmentColor")] = col; - setOpacity = false; + QColor col = premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity); + shaderManager->currentProgram()->setUniformValue("fragmentColor", col); } else { // All other brushes have a transform and thus need the translation point: @@ -297,13 +377,12 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() if (style <= Qt::DiagCrossPattern) { translationPoint = q->state()->brushOrigin; - QColor col = premultiplyColor(currentBrush->color(), opacity); + QColor col = premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity); - shaderManager->brushShader()->uniforms()[QLatin1String("patternColor")] = col; - setOpacity = false; //So code below doesn't try to set the opacity uniform + shaderManager->currentProgram()->setUniformValue("patternColor", col); - QGLVec2 halfViewportSize = { width*0.5, height*0.5 }; - shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize; + QVector2D halfViewportSize(width*0.5, height*0.5); + shaderManager->currentProgram()->setUniformValue("halfViewportSize", halfViewportSize); } else if (style == Qt::LinearGradientPattern) { const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush->gradient()); @@ -314,17 +393,16 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() QPointF l = realFinal - realStart; - // ### - QGLVec3 linearData = { + QVector3D linearData( l.x(), l.y(), 1.0f / (l.x() * l.x() + l.y() * l.y()) - }; + ); - shaderManager->brushShader()->uniforms()[QLatin1String("linearData")] = linearData; + shaderManager->currentProgram()->setUniformValue("linearData", linearData); - QGLVec2 halfViewportSize = { width*0.5, height*0.5 }; - shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize; + QVector2D halfViewportSize(width*0.5, height*0.5); + shaderManager->currentProgram()->setUniformValue("halfViewportSize", halfViewportSize); } else if (style == Qt::ConicalGradientPattern) { const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrush->gradient()); @@ -332,10 +410,10 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() GLfloat angle = -(g->angle() * 2 * Q_PI) / 360.0; - shaderManager->brushShader()->uniforms()[QLatin1String("angle")] = angle; + shaderManager->currentProgram()->setUniformValue("angle", angle); - QGLVec2 halfViewportSize = { width*0.5, height*0.5 }; - shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize; + QVector2D halfViewportSize(width*0.5, height*0.5); + shaderManager->currentProgram()->setUniformValue("halfViewportSize", halfViewportSize); } else if (style == Qt::RadialGradientPattern) { const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush->gradient()); @@ -345,27 +423,31 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() translationPoint = realFocal; QPointF fmp = realCenter - realFocal; - shaderManager->brushShader()->uniforms()[QLatin1String("fmp")] = fmp; + shaderManager->currentProgram()->setUniformValue("fmp", fmp); GLfloat fmp2_m_radius2 = -fmp.x() * fmp.x() - fmp.y() * fmp.y() + realRadius*realRadius; - shaderManager->brushShader()->uniforms()[QLatin1String("fmp2_m_radius2")] = fmp2_m_radius2; - - shaderManager->brushShader()->uniforms()[QLatin1String("inverse_2_fmp2_m_radius2")] = - GLfloat(1.0 / (2.0*fmp2_m_radius2)); + shaderManager->currentProgram()->setUniformValue("fmp2_m_radius2", fmp2_m_radius2); + shaderManager->currentProgram()->setUniformValue("inverse_2_fmp2_m_radius2", + GLfloat(1.0 / (2.0*fmp2_m_radius2))); - QGLVec2 halfViewportSize = { width*0.5, height*0.5 }; - shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize; + QVector2D halfViewportSize(width*0.5, height*0.5); + shaderManager->currentProgram()->setUniformValue("halfViewportSize", halfViewportSize); } else if (style == Qt::TexturePattern) { translationPoint = q->state()->brushOrigin; const QPixmap& texPixmap = currentBrush->texture(); + if (qHasPixmapTexture(*currentBrush) && currentBrush->texture().isQBitmap()) { + QColor col = premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity); + shaderManager->currentProgram()->setUniformValue("patternColor", col); + } + QSizeF invertedTextureSize( 1.0 / texPixmap.width(), 1.0 / texPixmap.height() ); - shaderManager->brushShader()->uniforms()[QLatin1String("invertedTextureSize")] = invertedTextureSize; + shaderManager->currentProgram()->setUniformValue("invertedTextureSize", invertedTextureSize); - QGLVec2 halfViewportSize = { width*0.5, height*0.5 }; - shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize; + QVector2D halfViewportSize(width*0.5, height*0.5); + shaderManager->currentProgram()->setUniformValue("halfViewportSize", halfViewportSize); } else qWarning("QGL2PaintEngineEx: Unimplemented fill style"); @@ -374,11 +456,8 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() QTransform gl_to_qt(1, 0, 0, -1, 0, height); QTransform inv_matrix = gl_to_qt * (brushQTransform * q->state()->matrix).inverted() * translate; - shaderManager->brushShader()->uniforms()[QLatin1String("brushTransform")] = inv_matrix; - shaderManager->brushShader()->uniforms()[QLatin1String("brushTexture")] = QT_BRUSH_TEXTURE_UNIT; - - if (setOpacity) - shaderManager->brushShader()->uniforms()[QLatin1String("opacity")] = opacity; + shaderManager->currentProgram()->setUniformValue("brushTransform", inv_matrix); + shaderManager->currentProgram()->setUniformValue("brushTexture", QT_BRUSH_TEXTURE_UNIT); } brushUniformsDirty = false; } @@ -397,38 +476,51 @@ void QGL2PaintEngineExPrivate::updateMatrix() {0.0, 0.0, 0.0, 1.0} }; - // Use the (3x3) transform for the Model~View matrix: const QTransform& transform = q->state()->matrix; - GLfloat MV[4][4] = { - {transform.m11(), transform.m21(), 0.0, transform.dx() + 0.5}, - {transform.m12(), transform.m22(), 0.0, transform.dy() + 0.5}, - {0.0, 0.0, 1.0, 0.0}, - {transform.m13(), transform.m23(), 0.0, transform.m33()} - }; - // NOTE: OpenGL ES works with column-major matrices, so when we multiply the matrices, - // we also transpose them ready for GL. - for (int row = 0; row < 4; ++row) { - for (int col = 0; col < 4; ++col) { - pmvMatrix[col][row] = 0.0; - for (int n = 0; n < 4; ++n) - pmvMatrix[col][row] += P[row][n] * MV[n][col]; + if (mode == TextDrawingMode) { + // Text drawing mode is only used for non-scaling transforms + for (int row = 0; row < 4; ++row) + for (int col = 0; col < 4; ++col) + pmvMatrix[col][row] = P[row][col]; + + pmvMatrix[3][0] += P[0][0] * qRound(transform.dx()); + pmvMatrix[3][1] += P[1][1] * qRound(transform.dy()); + + inverseScale = 1; + } else { + // Use the (3x3) transform for the Model~View matrix: + GLfloat MV[4][4] = { + {transform.m11(), transform.m21(), 0.0, transform.dx()}, + {transform.m12(), transform.m22(), 0.0, transform.dy()}, + {0.0, 0.0, 1.0, 0.0}, + {transform.m13(), transform.m23(), 0.0, transform.m33()} + }; + + // NOTE: OpenGL ES works with column-major matrices, so when we multiply the matrices, + // we also transpose them ready for GL. + for (int row = 0; row < 4; ++row) { + for (int col = 0; col < 4; ++col) { + pmvMatrix[col][row] = 0.0; + + // P[row][n] is 0.0 for n < row + for (int n = row; n < 4; ++n) + pmvMatrix[col][row] += P[row][n] * MV[n][col]; + } } - } - // 1/10000 == 0.0001, so we have good enough res to cover curves - // that span the entire widget... - inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())), - qMax(qAbs(transform.m12()), qAbs(transform.m21())) ), - qreal(0.0001)); + // 1/10000 == 0.0001, so we have good enough res to cover curves + // that span the entire widget... + inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())), + qMax(qAbs(transform.m12()), qAbs(transform.m21())) ), + qreal(0.0001)); + } matrixDirty = false; // The actual data has been updated so both shader program's uniforms need updating simpleShaderMatrixUniformDirty = true; - brushShaderMatrixUniformDirty = true; - imageShaderMatrixUniformDirty = true; - textShaderMatrixUniformDirty = true; + shaderMatrixUniformDirty = true; } @@ -485,120 +577,185 @@ void QGL2PaintEngineExPrivate::updateCompositionMode() compositionModeDirty = false; } +static inline void setCoords(GLfloat *coords, const QGLRect &rect) +{ + coords[0] = rect.left; + coords[1] = rect.top; + coords[2] = rect.right; + coords[3] = rect.top; + coords[4] = rect.right; + coords[5] = rect.bottom; + coords[6] = rect.left; + coords[7] = rect.bottom; +} -void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& src, int txtWidth, int txtHeight) +void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern) { -// qDebug("QGL2PaintEngineExPrivate::drawImage()"); + transferMode(ImageDrawingMode); - // We have a shader specifically for drawPixmap/drawImage... - shaderManager->imageShader()->use(); + updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); - updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); + // Setup for texture drawing + shaderManager->setSrcPixelType(pattern ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc); + shaderManager->setTextureCoordsEnabled(true); + prepareForDraw(opaque); - if (compositionModeDirty) - updateCompositionMode(); + if (pattern) { + QColor col = premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity); + shaderManager->currentProgram()->setUniformValue("patternColor", col); + } - if (matrixDirty) - updateMatrix(); + shaderManager->currentProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT); - if (imageShaderMatrixUniformDirty) { - shaderManager->imageShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix; - imageShaderMatrixUniformDirty = false; - } + GLfloat dx = 1.0 / textureSize.width(); + GLfloat dy = 1.0 / textureSize.height(); - shaderManager->imageShader()->uniforms()[QLatin1String("textureSampler")] = QT_BRUSH_TEXTURE_UNIT; + QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy); -// if (q->state()->opacity < 0.99f) - shaderManager->imageShader()->uniforms()[QLatin1String("opacity")] = (GLfloat)q->state()->opacity; + setCoords(staticVertexCoordinateArray, dest); + setCoords(staticTextureCoordinateArray, srcTextureRect); - GLfloat vertexCoords[] = { - dest.left, dest.top, - dest.left, dest.bottom, - dest.right, dest.bottom, - dest.right, dest.top - }; + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); +} - glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords); +void QGL2PaintEngineEx::sync() +{ + Q_D(QGL2PaintEngineEx); + ensureActive(); + d->transferMode(BrushDrawingMode); - GLfloat dx = 1.0 / txtWidth; - GLfloat dy = 1.0 / txtHeight; + QGLContext *ctx = d->ctx; + glUseProgram(0); - QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy); +#ifndef QT_OPENGL_ES_2 + // be nice to people who mix OpenGL 1.x code with QPainter commands + // by setting modelview and projection matrices to mirror the GL 1 + // paint engine + const QTransform& mtx = state()->matrix; - GLfloat textureCoords[] = { - srcTextureRect.left, srcTextureRect.top, - srcTextureRect.left, srcTextureRect.bottom, - srcTextureRect.right, srcTextureRect.bottom, - srcTextureRect.right, srcTextureRect.top + float mv_matrix[4][4] = + { + { mtx.m11(), mtx.m12(), 0, mtx.m13() }, + { mtx.m21(), mtx.m22(), 0, mtx.m23() }, + { 0, 0, 1, 0 }, + { mtx.dx(), mtx.dy(), 0, mtx.m33() } }; - glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); - glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoords); + const QSize sz = d->drawable.size(); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, sz.width(), sz.height(), 0, -999999, 999999); - glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); - glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(&mv_matrix[0][0]); +#endif + + glDisable(GL_BLEND); + glActiveTexture(GL_TEXTURE0); } +void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode) +{ + if (newMode == mode) + return; + + if (mode == TextDrawingMode || mode == ImageDrawingMode) { + glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); + glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); + } + + if (mode == TextDrawingMode) + matrixDirty = true; + + if (newMode == TextDrawingMode) { + glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); + glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); + + glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data()); + glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data()); + + matrixDirty = true; + } + + if (newMode == ImageDrawingMode) { + glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); + glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); + + glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticVertexCoordinateArray); + glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticTextureCoordinateArray); + } + + // This needs to change when we implement high-quality anti-aliasing... + if (newMode != TextDrawingMode) + shaderManager->setMaskType(QGLEngineShaderManager::NoMask); + + mode = newMode; +} void QGL2PaintEngineExPrivate::drawOutline(const QVectorPath& path) { -// qDebug("QGL2PaintEngineExPrivate::drawOutline()"); + transferMode(BrushDrawingMode); + + // Might need to call updateMatrix to re-calculate inverseScale if (matrixDirty) updateMatrix(); - pathVertexArray.clear(); - pathVertexArray.addPath(path, inverseScale); + vertexCoordinateArray.clear(); + vertexCoordinateArray.addPath(path, inverseScale); if (path.hasImplicitClose()) { // Close the path's outline - pathVertexArray.lineToArray(path.points()[0], path.points()[1]); - pathVertexArray.stops().last() += 1; + vertexCoordinateArray.lineToArray(path.points()[0], path.points()[1]); + vertexCoordinateArray.stops().last() += 1; } - prepareForDraw(); - drawVertexArrays(pathVertexArray, GL_LINE_STRIP); + prepareForDraw(currentBrush->isOpaque()); + drawVertexArrays(vertexCoordinateArray, GL_LINE_STRIP); } // Assumes everything is configured for the brush you want to use void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) { + transferMode(BrushDrawingMode); + + // Might need to call updateMatrix to re-calculate inverseScale if (matrixDirty) updateMatrix(); const QPointF* const points = reinterpret_cast<const QPointF*>(path.points()); - // Check to see if there's any hints if (path.shape() == QVectorPath::RectangleHint) { QGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y()); - prepareForDraw(); + prepareForDraw(currentBrush->isOpaque()); + composite(rect); } else if (path.shape() == QVectorPath::EllipseHint) { - pathVertexArray.clear(); - pathVertexArray.addPath(path, inverseScale); - prepareForDraw(); - drawVertexArrays(pathVertexArray, GL_TRIANGLE_FAN); + vertexCoordinateArray.clear(); + vertexCoordinateArray.addPath(path, inverseScale); + prepareForDraw(currentBrush->isOpaque()); + drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN); } else { // The path is too complicated & needs the stencil technique - pathVertexArray.clear(); - pathVertexArray.addPath(path, inverseScale); + vertexCoordinateArray.clear(); + vertexCoordinateArray.addPath(path, inverseScale); - fillStencilWithVertexArray(pathVertexArray, path.hasWindingFill()); + fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill()); // Stencil the brush onto the dest buffer glStencilFunc(GL_NOTEQUAL, 0, 0xFFFF); // Pass if stencil buff value != 0 + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); + glEnable(GL_STENCIL_TEST); - prepareForDraw(); - composite(pathVertexArray.boundingRect()); + prepareForDraw(currentBrush->isOpaque()); + composite(vertexCoordinateArray.boundingRect()); glDisable(GL_STENCIL_TEST); - cleanStencilBuffer(pathVertexArray.boundingRect()); + glStencilMask(0); } } @@ -606,17 +763,17 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill) { // qDebug("QGL2PaintEngineExPrivate::fillStencilWithVertexArray()"); - if (stencilBuferDirty) { + glStencilMask(0xFFFF); // Enable stencil writes + + if (stencilBufferDirty) { // Clear the stencil buffer to zeros glDisable(GL_STENCIL_TEST); - glStencilMask(0xFFFF); // Enable writing to stencil buffer, otherwise glClear wont do anything. glClearStencil(0); // Clear to zero glClear(GL_STENCIL_BUFFER_BIT); - stencilBuferDirty = false; + stencilBufferDirty = false; } glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes - glStencilMask(0xFFFF); // Enable stencil writes glStencilFunc(GL_ALWAYS, 0, 0xFFFF); // Always pass the stencil test // Setup the stencil op: @@ -626,7 +783,7 @@ void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& ve } else glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit - // No point in using a fancy gradiant shader for writing into the stencil buffer! + // No point in using a fancy gradient shader for writing into the stencil buffer! useSimpleShader(); glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d @@ -637,69 +794,62 @@ void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& ve // Enable color writes & disable stencil writes glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glStencilMask(0); } -void QGL2PaintEngineExPrivate::cleanStencilBuffer(const QGLRect& area) +void QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque) { -// qDebug("QGL2PaintEngineExPrivate::cleanStencilBuffer()"); - useSimpleShader(); - - GLfloat rectVerts[] = { - area.left, area.top, - area.left, area.bottom, - area.right, area.bottom, - area.right, area.top - }; - - glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, rectVerts); - - glEnable(GL_STENCIL_TEST); - glStencilFunc(GL_ALWAYS, 0, 0xFFFF); // Always pass the stencil test - - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes - glStencilMask(0xFFFF); // Enable writing to stencil buffer - glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); // Write 0's to stencil buffer + if (brushTextureDirty && mode != ImageDrawingMode) + updateBrushTexture(); - glDisable(GL_BLEND); + if (compositionModeDirty) + updateCompositionMode(); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + if (matrixDirty) + updateMatrix(); - glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); + const bool stateHasOpacity = q->state()->opacity < 0.99f; + if (q->state()->compositionMode() == QPainter::CompositionMode_Source + || (q->state()->compositionMode() == QPainter::CompositionMode_SourceOver + && srcPixelsAreOpaque && !stateHasOpacity)) + glDisable(GL_BLEND); + else + glEnable(GL_BLEND); - // Enable color writes & disable stencil writes - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glStencilMask(0); - glDisable(GL_STENCIL_TEST); -} + bool useGlobalOpacityUniform = stateHasOpacity; + if (stateHasOpacity && (mode != ImageDrawingMode)) { + // Using a brush + bool brushIsPattern = (currentBrush->style() >= Qt::Dense1Pattern) && + (currentBrush->style() <= Qt::DiagCrossPattern); -void QGL2PaintEngineExPrivate::prepareForDraw() -{ - if (brushTextureDirty) - updateBrushTexture(); + if ((currentBrush->style() == Qt::SolidPattern) || brushIsPattern) + useGlobalOpacityUniform = false; // Global opacity handled by srcPixel shader + } + shaderManager->setUseGlobalOpacity(useGlobalOpacityUniform); - if (compositionModeDirty) - updateCompositionMode(); + // If the shader program needs changing, we change it and mark all uniforms as dirty if (shaderManager->useCorrectShaderProg()) { // The shader program has changed so mark all uniforms as dirty: brushUniformsDirty = true; - brushShaderMatrixUniformDirty = true; + shaderMatrixUniformDirty = true; + depthUniformDirty = true; } - if (brushUniformsDirty) + if (brushUniformsDirty && mode != ImageDrawingMode) updateBrushUniforms(); - if (brushShaderMatrixUniformDirty) { - shaderManager->brushShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix; - brushShaderMatrixUniformDirty = false; + if (shaderMatrixUniformDirty) { + shaderManager->currentProgram()->setUniformValue("pmvMatrix", pmvMatrix); + shaderMatrixUniformDirty = false; } - if ((q->state()->opacity < 0.99f) || !currentBrush->isOpaque()) - glEnable(GL_BLEND); - else - glDisable(GL_BLEND); + if (depthUniformDirty) { + shaderManager->currentProgram()->setUniformValue("depth", (GLfloat)q->state()->currentDepth); + depthUniformDirty = false; + } + + if (useGlobalOpacityUniform) + shaderManager->currentProgram()->setUniformValue("globalOpacity", (GLfloat)q->state()->opacity); } void QGL2PaintEngineExPrivate::composite(const QGLRect& boundingRect) @@ -749,8 +899,6 @@ void QGL2PaintEngineExPrivate::drawVertexArrays(QGL2PEXVertexArray& vertexArray, QGL2PaintEngineEx::QGL2PaintEngineEx() : QPaintEngineEx(*(new QGL2PaintEngineExPrivate(this))) { - qDebug("QGL2PaintEngineEx::QGL2PaintEngineEx()"); - } QGL2PaintEngineEx::~QGL2PaintEngineEx() @@ -761,8 +909,10 @@ void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush) { Q_D(QGL2PaintEngineEx); - QTime startTime = QTime::currentTime(); + if (brush.style() == Qt::NoBrush) + return; + ensureActive(); d->setBrush(&brush); d->fill(path); d->setBrush(&(state()->brush)); // reset back to the state's brush @@ -775,6 +925,8 @@ void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) if (pen.style() == Qt::NoPen) return; + ensureActive(); + if ( (pen.isCosmetic() && (pen.style() == Qt::SolidLine)) && (pen.widthF() < 2.5f) ) { // We only handle solid, cosmetic pens with a width of 1 pixel @@ -790,7 +942,6 @@ void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) d->setBrush(&(state()->brush)); } else return QPaintEngineEx::stroke(path, pen); - } void QGL2PaintEngineEx::penChanged() @@ -819,7 +970,6 @@ void QGL2PaintEngineEx::opacityChanged() Q_D(QGL2PaintEngineEx); Q_ASSERT(d->shaderManager); - d->shaderManager->setUseGlobalOpacity(state()->opacity > 0.999); d->brushUniformsDirty = true; } @@ -845,45 +995,44 @@ void QGL2PaintEngineEx::transformChanged() void QGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, const QRectF & src) { Q_D(QGL2PaintEngineEx); - glActiveTexture(QT_BRUSH_TEXTURE_UNIT); + ensureActive(); + d->transferMode(ImageDrawingMode); - d->ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, true); + QGLContext *ctx = d->ctx; + glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); + ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, true); - //FIXME: we should use hasAlpha() instead, but that's SLOW at the moment - if ((state()->opacity < 0.99f) || pixmap.hasAlphaChannel()) - glEnable(GL_BLEND); - else - glDisable(GL_BLEND); + bool isBitmap = pixmap.isQBitmap(); + bool isOpaque = !isBitmap && !pixmap.hasAlphaChannel(); - d->drawTexture(dest, src, pixmap.width(), pixmap.height()); + d->drawTexture(dest, src, pixmap.size(), isOpaque, isBitmap); } void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const QRectF& src, Qt::ImageConversionFlags) { Q_D(QGL2PaintEngineEx); - glActiveTexture(QT_BRUSH_TEXTURE_UNIT); - d->ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true); + ensureActive(); + d->transferMode(ImageDrawingMode); - if ((state()->opacity < 0.99f) || image.hasAlphaChannel()) - glEnable(GL_BLEND); - else - glDisable(GL_BLEND); + QGLContext *ctx = d->ctx; + glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); + ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true); - d->drawTexture(dest, src, image.width(), image.height()); + d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel()); } void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem) { - QOpenGLPaintEngineState *s = state(); + Q_D(QGL2PaintEngineEx); + + ensureActive(); + QOpenGL2PaintEngineState *s = state(); const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); bool drawCached = true; - if (state()->pen.brush().style() != Qt::SolidPattern) - drawCached = false; - if (s->matrix.type() > QTransform::TxTranslate) drawCached = false; @@ -892,17 +1041,17 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem drawCached = false; if (drawCached) { - drawCachedGlyphs(p, ti); + d->drawCachedGlyphs(p, ti); return; } QPaintEngineEx::drawTextItem(p, ti); } -void QGL2PaintEngineEx::drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti) +void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti) { - Q_D(QGL2PaintEngineEx); - QOpenGLPaintEngineState *s = state(); + Q_Q(QGL2PaintEngineEx); + QOpenGL2PaintEngineState *s = q->state(); QVarLengthArray<QFixedPoint> positions; QVarLengthArray<glyph_t> glyphs; @@ -914,81 +1063,67 @@ void QGL2PaintEngineEx::drawCachedGlyphs(const QPointF &p, const QTextItemInt &t ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat) : QFontEngineGlyphCache::Raster_A8; - QImageTextureGlyphCache *cache = - (QImageTextureGlyphCache *) ti.fontEngine->glyphCache(glyphType, s->matrix); + QGLTextureGlyphCache *cache = + (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, s->matrix); if (!cache) { - cache = new QImageTextureGlyphCache(glyphType, s->matrix); - ti.fontEngine->setGlyphCache(glyphType, cache); + cache = new QGLTextureGlyphCache(ctx, glyphType, s->matrix); + ti.fontEngine->setGlyphCache(ctx, cache); } + cache->setPaintEnginePrivate(this); cache->populate(ti, glyphs, positions); - const QImage &image = cache->image(); - int margin = cache->glyphMargin(); - - if (image.isNull()) + if (cache->width() == 0 || cache->height() == 0) return; - glActiveTexture(QT_BRUSH_TEXTURE_UNIT); - d->ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true); - - glEnable(GL_BLEND); + transferMode(TextDrawingMode); - d->shaderManager->textShader()->use(); - d->updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); + if (glyphType == QFontEngineGlyphCache::Raster_A8) + shaderManager->setMaskType(QGLEngineShaderManager::PixelMask); + else if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) + shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMask); + //### TODO: Gamma correction + shaderManager->setTextureCoordsEnabled(true); - if (d->compositionModeDirty) - d->updateCompositionMode(); + int margin = cache->glyphMargin(); - if (d->matrixDirty) - d->updateMatrix(); + GLfloat dx = 1.0 / cache->width(); + GLfloat dy = 1.0 / cache->height(); - if (d->textShaderMatrixUniformDirty) { - d->shaderManager->textShader()->uniforms()[QLatin1String("pmvMatrix")] = d->pmvMatrix; - d->textShaderMatrixUniformDirty = false; - } + QGLPoint *oldVertexCoordinateDataPtr = vertexCoordinateArray.data(); + QGLPoint *oldTextureCoordinateDataPtr = textureCoordinateArray.data(); - d->shaderManager->textShader()->uniforms()[QLatin1String("textureSampler")] = QT_BRUSH_TEXTURE_UNIT; - QColor col = d->premultiplyColor(state()->pen.color(), (GLfloat)state()->opacity); - d->shaderManager->textShader()->uniforms()[QLatin1String("fragmentColor")] = col; + vertexCoordinateArray.clear(); + textureCoordinateArray.clear(); - GLfloat dx = 1.0 / image.width(); - GLfloat dy = 1.0 / image.height(); - - glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); for (int i=0; i<glyphs.size(); ++i) { const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]); int x = positions[i].x.toInt() + c.baseLineX - margin; int y = positions[i].y.toInt() - c.baseLineY - margin; - QGLRect dest = QRectF(x, y, c.w, c.h); - QGLRect src = QRectF(c.x, c.y, c.w, c.h); + vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h)); + textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); + } + + glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT); + glBindTexture(GL_TEXTURE_2D, cache->texture()); + updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); - GLfloat vertexCoords[] = { - dest.left, dest.top, - dest.left, dest.bottom, - dest.right, dest.bottom, - dest.right, dest.top - }; + QBrush pensBrush = q->state()->pen.brush(); + setBrush(&pensBrush); - glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords); + prepareForDraw(false); // Text always causes src pixels to be transparent - QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy); + shaderManager->currentProgram()->setUniformValue("maskTexture", QT_MASK_TEXTURE_UNIT); - GLfloat textureCoords[] = { - srcTextureRect.left, srcTextureRect.top, - srcTextureRect.left, srcTextureRect.bottom, - srcTextureRect.right, srcTextureRect.bottom, - srcTextureRect.right, srcTextureRect.top - }; + if (vertexCoordinateArray.data() != oldVertexCoordinateDataPtr) + glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data()); + if (textureCoordinateArray.data() != oldTextureCoordinateDataPtr) + glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data()); - glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoords); + glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size()); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - } - glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); - glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); + setBrush(&(q->state()->brush)); //### } bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) @@ -996,15 +1131,31 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) Q_D(QGL2PaintEngineEx); // qDebug("QGL2PaintEngineEx::begin()"); + d->drawable.setDevice(pdev); + d->ctx = d->drawable.context(); + + if (d->ctx->d_ptr->active_engine) { + QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(d->ctx->d_ptr->active_engine); + QGL2PaintEngineExPrivate *p = static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr); + p->transferMode(BrushDrawingMode); + p->drawable.doneCurrent(); + } + + d->ctx->d_ptr->active_engine = this; + d->last_created_state = 0; - QGLWidget* widget = static_cast<QGLWidget*>(pdev); - d->ctx = const_cast<QGLContext*>(widget->context()); - d->ctx->makeCurrent(); - d->width = widget->width(); - d->height = widget->height(); + d->drawable.makeCurrent(); + QSize sz = d->drawable.size(); + d->width = sz.width(); + d->height = sz.height(); + d->mode = BrushDrawingMode; + +#if !defined(QT_OPENGL_ES_2) + qt_resolve_version_2_0_functions(d->ctx); +#endif if (!d->shaderManager) - d->shaderManager = new QGLPEXShaderManager(d->ctx); + d->shaderManager = new QGLEngineShaderManager(d->ctx); glViewport(0, 0, d->width, d->height); @@ -1018,264 +1169,378 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) d->brushUniformsDirty = true; d->matrixDirty = true; d->compositionModeDirty = true; - d->stencilBuferDirty = true; + d->stencilBufferDirty = true; + d->simpleShaderDepthUniformDirty = true; + d->depthUniformDirty = true; d->use_system_clip = !systemClip().isEmpty(); glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + glDepthFunc(GL_LEQUAL); + glDepthMask(false); + + QGLPixmapData *source = d->drawable.copyOnBegin(); + if (d->drawable.context()->d_func()->clear_on_painter_begin && d->drawable.autoFillBackground()) { + if (d->drawable.hasTransparentBackground()) + glClearColor(0.0, 0.0, 0.0, 0.0); + else { + const QColor &c = d->drawable.backgroundColor(); + float alpha = c.alphaF(); + glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha); + } + glClear(GL_COLOR_BUFFER_BIT); + } else if (source) { + QGLContext *ctx = d->ctx; + + d->transferMode(ImageDrawingMode); + + glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); + source->bind(false); + + QRect rect(0, 0, source->width(), source->height()); + d->drawTexture(QRectF(rect), QRectF(rect), rect.size(), true); + } + d->systemStateChanged(); return true; } bool QGL2PaintEngineEx::end() { Q_D(QGL2PaintEngineEx); - d->ctx->swapBuffers(); + QGLContext *ctx = d->ctx; + if (ctx->d_ptr->active_engine != this) { + QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(ctx->d_ptr->active_engine); + if (engine && engine->isActive()) { + QGL2PaintEngineExPrivate *p = static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr); + p->transferMode(BrushDrawingMode); + p->drawable.doneCurrent(); + } + d->drawable.makeCurrent(); + } + + glUseProgram(0); + d->transferMode(BrushDrawingMode); + d->drawable.swapBuffers(); + d->drawable.doneCurrent(); + d->ctx->d_ptr->active_engine = 0; + return false; } +void QGL2PaintEngineEx::ensureActive() +{ + Q_D(QGL2PaintEngineEx); + QGLContext *ctx = d->ctx; + + if (isActive() && ctx->d_ptr->active_engine != this) { + QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(ctx->d_ptr->active_engine); + if (engine && engine->isActive()) { + QGL2PaintEngineExPrivate *p = static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr); + p->transferMode(BrushDrawingMode); + p->drawable.doneCurrent(); + } + d->drawable.makeCurrent(); + + ctx->d_ptr->active_engine = this; + + glDisable(GL_DEPTH_TEST); -/////////////////////////////////// State/Clipping stolen from QOpenGLPaintEngine ////////////////////////////////////////// + glViewport(0, 0, d->width, d->height); + + setState(state()); + } +} + +void QGL2PaintEngineExPrivate::updateDepthScissorTest() +{ + Q_Q(QGL2PaintEngineEx); + if (q->state()->depthTestEnabled) + glEnable(GL_DEPTH_TEST); + else + glDisable(GL_DEPTH_TEST); + + if (q->state()->scissorTestEnabled) + glEnable(GL_SCISSOR_TEST); + else + glDisable(GL_SCISSOR_TEST); +} void QGL2PaintEngineEx::clipEnabledChanged() { Q_D(QGL2PaintEngineEx); - d->updateDepthClip(); + d->simpleShaderDepthUniformDirty = true; + d->depthUniformDirty = true; + + if (painter()->hasClipping()) { + d->regenerateDepthClip(); + } else { + if (d->use_system_clip) { + state()->currentDepth = -0.5f; + } else { + glDisable(GL_DEPTH_TEST); + state()->depthTestEnabled = false; + } + } } -void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op) +void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, float depth) { -// qDebug("QGL2PaintEngineEx::clip()"); - const qreal *points = path.points(); - const QPainterPath::ElementType *types = path.elements(); - if (!types && path.shape() == QVectorPath::RectangleHint) { - QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]); - updateClipRegion(QRegion(r.toRect()), op); - return; - } + transferMode(BrushDrawingMode); - QPainterPath p; - if (types) { - int id = 0; - for (int i=0; i<path.elementCount(); ++i) { - switch(types[i]) { - case QPainterPath::MoveToElement: - p.moveTo(QPointF(points[id], points[id+1])); - id+=2; - break; - case QPainterPath::LineToElement: - p.lineTo(QPointF(points[id], points[id+1])); - id+=2; - break; - case QPainterPath::CurveToElement: { - QPointF p1(points[id], points[id+1]); - QPointF p2(points[id+2], points[id+3]); - QPointF p3(points[id+4], points[id+5]); - p.cubicTo(p1, p2, p3); - id+=6; - break; - } - case QPainterPath::CurveToDataElement: - ; - break; - } - } - } else if (!path.isEmpty()) { - p.moveTo(QPointF(points[0], points[1])); - int id = 2; - for (int i=1; i<path.elementCount(); ++i) { - p.lineTo(QPointF(points[id], points[id+1])); - id+=2; - } + if (matrixDirty) + updateMatrix(); + + if (q->state()->needsDepthBufferClear) { + glDepthMask(true); + glClearDepth(0.5); + glClear(GL_DEPTH_BUFFER_BIT); + q->state()->needsDepthBufferClear = false; + glDepthMask(false); } - if (path.hints() & QVectorPath::WindingFill) - p.setFillRule(Qt::WindingFill); - updateClipRegion(QRegion(p.toFillPolygon().toPolygon(), p.fillRule()), op); - return; + if (path.isEmpty()) + return; + + glDisable(GL_BLEND); + glDepthMask(false); + + vertexCoordinateArray.clear(); + vertexCoordinateArray.addPath(path, inverseScale); + + glDepthMask(GL_FALSE); + fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill()); + + // Stencil the clip onto the clip buffer + glColorMask(false, false, false, false); + glDepthMask(true); + + shaderManager->simpleProgram()->setUniformValue("depth", depth); + simpleShaderDepthUniformDirty = true; + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); + + glStencilFunc(GL_NOTEQUAL, 0, 0xFFFF); // Pass if stencil buff value != 0 + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); + + glEnable(GL_STENCIL_TEST); + composite(vertexCoordinateArray.boundingRect()); + glDisable(GL_STENCIL_TEST); + + glStencilMask(0); + + glColorMask(true, true, true, true); + glDepthMask(false); } -void QGL2PaintEngineEx::updateClipRegion(const QRegion &clipRegion, Qt::ClipOperation op) +void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op) { -// qDebug("QGL2PaintEngineEx::updateClipRegion()"); +// qDebug("QGL2PaintEngineEx::clip()"); Q_D(QGL2PaintEngineEx); - QRegion sysClip = systemClip(); - if (op == Qt::NoClip && !d->use_system_clip) { - state()->hasClipping = false; - state()->clipRegion = QRegion(); - d->updateDepthClip(); - return; - } + if (op == Qt::ReplaceClip && !d->hasClipOperations()) + op = Qt::IntersectClip; - bool isScreenClip = false; - if (!d->use_system_clip) { - QVector<QRect> untransformedRects = clipRegion.rects(); + if (!path.isEmpty() && op == Qt::IntersectClip && (path.hints() & QVectorPath::RectangleHint)) { + const QPointF* const points = reinterpret_cast<const QPointF*>(path.points()); + QRectF rect(points[0], points[2]); - if (untransformedRects.size() == 1) { - QPainterPath path; - path.addRect(untransformedRects[0]); - //path = d->matrix.map(path); - path = state()->matrix.map(path); - -// if (path.contains(QRectF(QPointF(), d->drawable.size()))) -// isScreenClip = true; - if (path.contains(QRectF(0.0, 0.0, d->width, d->height))) - isScreenClip = true; + if (state()->matrix.type() <= QTransform::TxScale) { + rect = state()->matrix.mapRect(rect); + + if (d->use_system_clip && rect.contains(d->systemClip.boundingRect()) + || rect.contains(QRect(0, 0, d->width, d->height))) + return; } } -// QRegion region = isScreenClip ? QRegion() : clipRegion * d->matrix; - QRegion region = isScreenClip ? QRegion() : clipRegion * state()->matrix; switch (op) { case Qt::NoClip: - if (!d->use_system_clip) - break; - state()->clipRegion = sysClip; + if (d->use_system_clip) { + glEnable(GL_DEPTH_TEST); + state()->depthTestEnabled = true; + state()->currentDepth = -0.5; + } else { + glDisable(GL_DEPTH_TEST); + state()->depthTestEnabled = false; + } + state()->canRestoreClip = false; break; case Qt::IntersectClip: - if (isScreenClip) - return; - if (state()->hasClipping) { - state()->clipRegion &= region; - break; - } - // fall through + state()->maxDepth = (1.0f + state()->maxDepth) * 0.5; + d->writeClip(path, state()->maxDepth); + state()->currentDepth = 1.5 * state()->maxDepth - 0.5f; + state()->depthTestEnabled = true; + break; case Qt::ReplaceClip: - if (d->use_system_clip && !sysClip.isEmpty()) - state()->clipRegion = region & sysClip; - else - state()->clipRegion = region; + d->systemStateChanged(); + state()->maxDepth = 0.5f; + glDepthFunc(GL_ALWAYS); + d->writeClip(path, state()->maxDepth); + state()->currentDepth = 0.25f; + state()->canRestoreClip = false; + state()->depthTestEnabled = true; break; case Qt::UniteClip: - state()->clipRegion |= region; - if (d->use_system_clip && !sysClip.isEmpty()) - state()->clipRegion &= sysClip; - break; - default: + glDepthFunc(GL_ALWAYS); + d->writeClip(path, state()->maxDepth); + state()->canRestoreClip = false; + state()->depthTestEnabled = true; break; } - if (isScreenClip) { - state()->hasClipping = false; - state()->clipRegion = QRegion(); - } else { - state()->hasClipping = op != Qt::NoClip || d->use_system_clip; + glDepthFunc(GL_LEQUAL); + if (state()->depthTestEnabled) { + glEnable(GL_DEPTH_TEST); + d->simpleShaderDepthUniformDirty = true; + d->depthUniformDirty = true; } - - if (state()->hasClipping && state()->clipRegion.rects().size() == 1) - state()->fastClip = state()->clipRegion.rects().at(0); - else - state()->fastClip = QRect(); - - d->updateDepthClip(); } - -void QGL2PaintEngineExPrivate::updateDepthClip() +void QGL2PaintEngineExPrivate::regenerateDepthClip() { -// qDebug("QGL2PaintEngineExPrivate::updateDepthClip()"); + systemStateChanged(); + replayClipOperations(); +} +void QGL2PaintEngineExPrivate::systemStateChanged() +{ Q_Q(QGL2PaintEngineEx); + use_system_clip = !systemClip.isEmpty(); glDisable(GL_DEPTH_TEST); + q->state()->depthTestEnabled = false; + q->state()->scissorTestEnabled = false; + q->state()->needsDepthBufferClear = true; + glDisable(GL_SCISSOR_TEST); - if (!q->state()->hasClipping) - return; + q->state()->currentDepth = -0.5f; + q->state()->maxDepth = 0.5f; - QRect fastClip; - if (q->state()->clipEnabled) { - fastClip = q->state()->fastClip; - } else if (use_system_clip && q->systemClip().rects().count() == 1) { - fastClip = q->systemClip().rects().at(0); - } + if (use_system_clip) { + QRect bounds = systemClip.boundingRect(); + if (systemClip.numRects() == 1 + && bounds == QRect(0, 0, width, height)) + { + q->state()->needsDepthBufferClear = true; + } else { + glEnable(GL_SCISSOR_TEST); - if (!fastClip.isEmpty()) { - glEnable(GL_SCISSOR_TEST); + const int left = bounds.left(); + const int width = bounds.width(); + const int bottom = height - (bounds.top() + bounds.height()); + const int height = bounds.height(); - const int left = fastClip.left(); - const int width = fastClip.width(); - const int bottom = height - (fastClip.bottom() + 1); - const int height = fastClip.height(); + glScissor(left, bottom, width, height); - glScissor(left, bottom, width, height); - return; - } + QTransform transform = q->state()->matrix; + q->state()->matrix = QTransform(); + q->transformChanged(); - glClearDepthf(0x0); - glDepthMask(true); - glClear(GL_DEPTH_BUFFER_BIT); - glClearDepthf(0x1); + q->state()->needsDepthBufferClear = false; - const QVector<QRect> rects = q->state()->clipEnabled ? q->state()->clipRegion.rects() : q->systemClip().rects(); - glEnable(GL_SCISSOR_TEST); - for (int i = 0; i < rects.size(); ++i) { - QRect rect = rects.at(i); + glDepthMask(true); - const int left = rect.left(); - const int width = rect.width(); - const int bottom = height - (rect.bottom() + 1); - const int height = rect.height(); + glClearDepth(0); + glClear(GL_DEPTH_BUFFER_BIT); - glScissor(left, bottom, width, height); + QPainterPath path; + path.addRegion(systemClip); - glClear(GL_DEPTH_BUFFER_BIT); - } - glDisable(GL_SCISSOR_TEST); + glDepthFunc(GL_ALWAYS); + writeClip(qtVectorPathForPath(path), 0.0f); + glDepthFunc(GL_LEQUAL); - glDepthMask(false); - glDepthFunc(GL_LEQUAL); - glEnable(GL_DEPTH_TEST); -} + glEnable(GL_DEPTH_TEST); + q->state()->depthTestEnabled = true; + q->state()->scissorTestEnabled = true; + q->state()->matrix = transform; + q->transformChanged(); + } + q->state()->currentDepth = -0.5f; + simpleShaderDepthUniformDirty = true; + depthUniformDirty = true; + } +} -void QGL2PaintEngineEx::setState(QPainterState *s) +void QGL2PaintEngineEx::setState(QPainterState *new_state) { -// qDebug("QGL2PaintEngineEx::setState()"); + // qDebug("QGL2PaintEngineEx::setState()"); Q_D(QGL2PaintEngineEx); + + QOpenGL2PaintEngineState *s = static_cast<QOpenGL2PaintEngineState *>(new_state); + QOpenGL2PaintEngineState *old_state = state(); + QPaintEngineEx::setState(s); - d->updateDepthClip(); + if (s == d->last_created_state) { + d->last_created_state = 0; + return; + } d->matrixDirty = true; d->compositionModeDirty = true; d->brushTextureDirty = true; d->brushUniformsDirty = true; + d->simpleShaderDepthUniformDirty = true; + d->depthUniformDirty = true; d->simpleShaderMatrixUniformDirty = true; - d->brushShaderMatrixUniformDirty = true; - d->imageShaderMatrixUniformDirty = true; - d->textShaderMatrixUniformDirty = true; + d->shaderMatrixUniformDirty = true; + + if (old_state && old_state != s && old_state->canRestoreClip) { + d->updateDepthScissorTest(); + glDepthMask(false); + glDepthFunc(GL_LEQUAL); + s->maxDepth = old_state->maxDepth; + } else { + d->regenerateDepthClip(); + } } QPainterState *QGL2PaintEngineEx::createState(QPainterState *orig) const { - QOpenGLPaintEngineState *s; + Q_D(const QGL2PaintEngineEx); + + QOpenGL2PaintEngineState *s; if (!orig) - s = new QOpenGLPaintEngineState(); + s = new QOpenGL2PaintEngineState(); else - s = new QOpenGLPaintEngineState(*static_cast<QOpenGLPaintEngineState *>(orig)); + s = new QOpenGL2PaintEngineState(*static_cast<QOpenGL2PaintEngineState *>(orig)); + d->last_created_state = s; return s; } -QOpenGLPaintEngineState::QOpenGLPaintEngineState(QOpenGLPaintEngineState &other) +QOpenGL2PaintEngineState::QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other) : QPainterState(other) { - clipRegion = other.clipRegion; - hasClipping = other.hasClipping; - fastClip = other.fastClip; + needsDepthBufferClear = other.needsDepthBufferClear; + depthTestEnabled = other.depthTestEnabled; + scissorTestEnabled = other.scissorTestEnabled; + currentDepth = other.currentDepth; + maxDepth = other.maxDepth; + canRestoreClip = other.canRestoreClip; } -QOpenGLPaintEngineState::QOpenGLPaintEngineState() +QOpenGL2PaintEngineState::QOpenGL2PaintEngineState() { - hasClipping = false; + needsDepthBufferClear = true; + depthTestEnabled = false; + scissorTestEnabled = false; + currentDepth = -0.5f; + maxDepth = 0.5f; + canRestoreClip = true; } -QOpenGLPaintEngineState::~QOpenGLPaintEngineState() +QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState() { } +QT_END_NAMESPACE diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index ce66e4b..8a50096 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -53,21 +53,39 @@ // We mean it. // +#include <QDebug> + #include <private/qpaintengineex_p.h> +#include <private/qglengineshadermanager_p.h> +#include <private/qgl2pexvertexarray_p.h> + +enum EngineMode { + ImageDrawingMode, + TextDrawingMode, + BrushDrawingMode +}; + +QT_BEGIN_NAMESPACE class QGL2PaintEngineExPrivate; -class QOpenGLPaintEngineState : public QPainterState +class QOpenGL2PaintEngineState : public QPainterState { public: - QOpenGLPaintEngineState(QOpenGLPaintEngineState &other); - QOpenGLPaintEngineState(); - ~QOpenGLPaintEngineState(); + QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other); + QOpenGL2PaintEngineState(); + ~QOpenGL2PaintEngineState(); - QRegion clipRegion; - bool hasClipping; - QRect fastClip; + bool needsDepthBufferClear; + qreal depthBufferClearValue; + + bool depthTestEnabled; + bool scissorTestEnabled; + qreal currentDepth; + qreal maxDepth; + + bool canRestoreClip; }; @@ -81,6 +99,8 @@ public: bool begin(QPaintDevice *device); bool end(); + void ensureActive(); + virtual void fill(const QVectorPath &path, const QBrush &brush); virtual void stroke(const QVectorPath &path, const QPen &pen); virtual void clip(const QVectorPath &path, Qt::ClipOperation op); @@ -100,26 +120,106 @@ public: virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags = Qt::AutoColor); virtual void drawTextItem(const QPointF &p, const QTextItem &textItem); - void drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti); Type type() const { return OpenGL; } - - // State stuff is just for clipping and ripped off from QGLPaintEngine void setState(QPainterState *s); QPainterState *createState(QPainterState *orig) const; - inline QOpenGLPaintEngineState *state() { - return static_cast<QOpenGLPaintEngineState *>(QPaintEngineEx::state()); + inline QOpenGL2PaintEngineState *state() { + return static_cast<QOpenGL2PaintEngineState *>(QPaintEngineEx::state()); } - inline const QOpenGLPaintEngineState *state() const { - return static_cast<const QOpenGLPaintEngineState *>(QPaintEngineEx::state()); + inline const QOpenGL2PaintEngineState *state() const { + return static_cast<const QOpenGL2PaintEngineState *>(QPaintEngineEx::state()); } - void updateClipRegion(const QRegion &clipRegion, Qt::ClipOperation op); + virtual void sync(); private: Q_DISABLE_COPY(QGL2PaintEngineEx) }; +class QGL2PaintEngineExPrivate : public QPaintEngineExPrivate +{ + Q_DECLARE_PUBLIC(QGL2PaintEngineEx) +public: + QGL2PaintEngineExPrivate(QGL2PaintEngineEx *q_ptr) : + q(q_ptr), + width(0), height(0), + ctx(0), + currentBrush( &(q->state()->brush) ), + inverseScale(1), + shaderManager(0) + { } + + ~QGL2PaintEngineExPrivate(); + + void updateBrushTexture(); + void updateBrushUniforms(); + void updateMatrix(); + void updateCompositionMode(); + void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform); + + void setBrush(const QBrush* brush); + + void transferMode(EngineMode newMode); + + // fill, drawOutline, drawTexture & drawCachedGlyphs are the rendering entry points: + void fill(const QVectorPath &path); + void drawOutline(const QVectorPath& path); + void drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern = false); + void drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti); + + void drawVertexArrays(QGL2PEXVertexArray& vertexArray, GLenum primitive); + // ^ draws whatever is in the vertex array + void composite(const QGLRect& boundingRect); + // ^ Composites the bounding rect onto dest buffer + void fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill); + // ^ Calls drawVertexArrays to render into stencil buffer + + void prepareForDraw(bool srcPixelsAreOpaque); + + inline void useSimpleShader(); + inline QColor premultiplyColor(QColor c, GLfloat opacity); + + QGL2PaintEngineEx* q; + QGLDrawable drawable; + int width, height; + QGLContext *ctx; + EngineMode mode; + + mutable QOpenGL2PaintEngineState *last_created_state; + + // Dirty flags + bool matrixDirty; // Implies matrix uniforms are also dirty + bool compositionModeDirty; + bool brushTextureDirty; + bool brushUniformsDirty; + bool simpleShaderMatrixUniformDirty; + bool shaderMatrixUniformDirty; + bool stencilBufferDirty; + bool depthUniformDirty; + bool simpleShaderDepthUniformDirty; + + const QBrush* currentBrush; // May not be the state's brush! + + GLfloat inverseScale; + + QGL2PEXVertexArray vertexCoordinateArray; + QGL2PEXVertexArray textureCoordinateArray; + + GLfloat staticVertexCoordinateArray[8]; + GLfloat staticTextureCoordinateArray[8]; + + GLfloat pmvMatrix[4][4]; + + QGLEngineShaderManager* shaderManager; + + void writeClip(const QVectorPath &path, float depth); + void updateDepthScissorTest(); + void regenerateDepthClip(); + void systemStateChanged(); + uint use_system_clip : 1; +}; +QT_END_NAMESPACE #endif |