summaryrefslogtreecommitdiffstats
path: root/src/opengl
diff options
context:
space:
mode:
Diffstat (limited to 'src/opengl')
-rw-r--r--src/opengl/gl2paintengineex/glgc_shader_source.h289
-rw-r--r--src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp6
-rw-r--r--src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h5
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager.cpp465
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager_p.h385
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadersource_p.h383
-rw-r--r--src/opengl/gl2paintengineex/qglpexshadermanager.cpp450
-rw-r--r--src/opengl/gl2paintengineex/qglpexshadermanager_p.h156
-rw-r--r--src/opengl/gl2paintengineex/qglshader.cpp17
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp612
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h5
-rw-r--r--src/opengl/opengl.pro23
-rw-r--r--src/opengl/qgl.cpp241
-rw-r--r--src/opengl/qgl.h2
-rw-r--r--src/opengl/qgl_p.h46
-rw-r--r--src/opengl/qglextensions.cpp10
-rw-r--r--src/opengl/qglextensions_p.h119
-rw-r--r--src/opengl/qglframebufferobject.cpp480
-rw-r--r--src/opengl/qglframebufferobject.h49
-rw-r--r--src/opengl/qglpixelbuffer.cpp10
-rw-r--r--src/opengl/qglpixmapfilter.cpp13
-rw-r--r--src/opengl/qpaintengine_opengl.cpp176
-rw-r--r--src/opengl/qpixmapdata_gl.cpp272
-rw-r--r--src/opengl/qpixmapdata_gl_p.h25
-rw-r--r--src/opengl/qwindowsurface_gl.cpp133
-rw-r--r--src/opengl/qwindowsurface_gl_p.h1
26 files changed, 2866 insertions, 1507 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..f237847 100644
--- a/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp
+++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp
@@ -59,6 +59,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());
diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h
index c205022..a83f13e 100644
--- a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h
+++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h
@@ -62,7 +62,7 @@ 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 +77,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 +98,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();
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
new file mode 100644
index 0000000..3d8d34b
--- /dev/null
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
@@ -0,0 +1,465 @@
+/****************************************************************************
+**
+** 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
+
+
+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),
+ 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[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[NonPremultipliedImageSrcFragmentShader] = qglslNonPremultipliedImageSrcFragmentShader;
+ code[SolidBrushSrcFragmentShader] = qglslSolidBrushSrcFragmentShader;
+ code[TextureBrushSrcFragmentShader] = qglslTextureBrushSrcFragmentShader;
+ 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->link();
+ if (!simpleShaderProg->isValid()) {
+ qCritical() << "Errors linking simple shader:"
+ << simpleShaderProg->errors();
+ }
+}
+
+QGLEngineShaderManager::~QGLEngineShaderManager()
+{
+ //###
+}
+
+
+
+
+
+void QGLEngineShaderManager::optimiseForBrushTransform(const QTransform &transform)
+{
+ Q_UNUSED(transform); // Currently ignored
+}
+
+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;
+}
+
+
+
+
+// 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::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("inputVertex", QT_VERTEX_COORDS_ATTR);
+ if (useTextureCoords)
+ requiredProgram.program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
+
+ requiredProgram.program->link();
+ if (!requiredProgram.program->isValid()) {
+ 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->errors();
+ 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->setSourceCode(qglEngineShaderSourceCode[name]);
+ // newShader->compile(); ### does not exist?
+
+#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;
+}
+
+
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
new file mode 100644
index 0000000..b8b2745
--- /dev/null
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
@@ -0,0 +1,385 @@
+/****************************************************************************
+**
+** 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
+ qglslNonPremultipliedImageSrcFragShader
+ qglslSolidBrushSrcFragShader
+ qglslTextureBrushSrcFragShader
+ 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
+ };
+
+ // 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);
+
+ 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
+
+ enum ShaderName {
+ MainVertexShader,
+ MainWithTexCoordsVertexShader,
+
+ 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,
+ NonPremultipliedImageSrcFragmentShader,
+ SolidBrushSrcFragmentShader,
+ TextureBrushSrcFragmentShader,
+ 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* 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..bf896b1
--- /dev/null
+++ b/src/opengl/gl2paintengineex/qglengineshadersource_p.h
@@ -0,0 +1,383 @@
+/****************************************************************************
+**
+** 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;\
+ void setPosition(void)\
+ {\
+ gl_Position = pmvMatrix * vertexCoordsArray;\
+ }";
+
+
+// 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; \
+ void setPosition(void) { \
+ gl_Position = pmvMatrix * vertexCoordsArray;\
+ 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; \
+ 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 * 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 ; \
+ void setPosition() { \
+ gl_Position = pmvMatrix * vertexCoordsArray;\
+ 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* 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; \
+ void setPosition(void)\
+ {\
+ gl_Position = pmvMatrix * vertexCoordsArray;\
+ 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* 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; \
+ void setPosition(void) \
+ {\
+ gl_Position = pmvMatrix * vertexCoordsArray;\
+ 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 * 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; \
+ void setPosition(void) { \
+ gl_Position = pmvMatrix * vertexCoordsArray;\
+ 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; \
+ 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); \
+ }";
+
+
+// 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 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 lowp 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.r; \
+ }";
+
+/*
+ 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/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
index 634be84..ea4cae9 100644
--- a/src/opengl/gl2paintengineex/qglshader.cpp
+++ b/src/opengl/gl2paintengineex/qglshader.cpp
@@ -49,7 +49,12 @@
return false; \
ctx->makeCurrent(); \
-
+#if !defined(QT_OPENGL_ES_2)
+static const char *qglslDefines = "#define lowp\n#define mediump\n#define highp\n";
+#include "private/qgl_p.h"
+#else
+static const char *qglslDefines = "";
+#endif
class QGLShaderPrivate
@@ -131,9 +136,13 @@ bool QGLShader::compile()
return false;
const QByteArray src_ba = d->source.toAscii();
- const char* src = src_ba.constData();
+ const char* src[2];
+ src[0] = qglslDefines;
+ src[1] = src_ba.constData();
+
- glShaderSource(d->shaderId, 1, &src, 0);
+ QGLContext *ctx = d->ctx;
+ glShaderSource(d->shaderId, 2, src, 0);
glCompileShader(d->shaderId);
@@ -160,6 +169,7 @@ QString QGLShader::log()
GLint logSize;
GLint logLength;
+ QGLContext *ctx = d->ctx;
glGetShaderiv(d->shaderId, GL_INFO_LOG_LENGTH, &logSize);
if (!logSize)
@@ -377,6 +387,7 @@ void QGLShaderProgram::use()
if (!d->valid)
return;
+ QGLContext *ctx = d->ctx;
glUseProgram(d->programId);
}
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index a74f044..7dbdc32 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -77,7 +77,7 @@
#include <private/qtextureglyphcache_p.h>
#include "qglgradientcache_p.h"
-#include "qglpexshadermanager_p.h"
+#include "qglengineshadermanager_p.h"
#include "qgl2pexvertexarray_p.h"
@@ -86,10 +86,16 @@ extern QImage qt_imageForBrush(int brushStyle, bool invert); //in qbrush.cpp
#include <QDebug>
+enum EngineMode {
+ ImageDrawingMode,
+ TextDrawingMode,
+ BrushDrawingMode
+};
-static const GLuint QT_VERTEX_COORDS_ATTR = 0;
-static const GLuint QT_TEXTURE_COORDS_ATTR = 1;
-static const GLuint QT_BRUSH_TEXTURE_UNIT = 0;
+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;
class QGL2PaintEngineExPrivate : public QPaintEngineExPrivate
{
@@ -114,10 +120,13 @@ public:
void setBrush(const QBrush* brush);
- void drawTexture(const QGLRect& dest, const QGLRect& src, int txtWidth, int txtHeight);
+ 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);
+ void drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti);
void drawVertexArrays(QGL2PEXVertexArray& vertexArray, GLenum primitive);
// ^ draws whatever is in the vertex array
@@ -127,16 +136,17 @@ public:
// ^ Calls drawVertexArrays to render into stencil buffer
void cleanStencilBuffer(const QGLRect& area);
- void prepareForDraw();
+ void prepareForDraw(bool srcPixelsAreOpaque);
inline void useSimpleShader();
inline QColor premultiplyColor(QColor c, GLfloat opacity);
QGL2PaintEngineEx* q;
-
- //### Move into QGLDrawable
+ QGLDrawable drawable;
int width, height;
- QGLContext* ctx;
+ QGLContext *ctx;
+
+ EngineMode mode;
// Dirty flags
bool matrixDirty; // Implies matrix uniforms are also dirty
@@ -144,24 +154,28 @@ public:
bool brushTextureDirty;
bool brushUniformsDirty;
bool simpleShaderMatrixUniformDirty;
- bool brushShaderMatrixUniformDirty;
- bool imageShaderMatrixUniformDirty;
- bool textShaderMatrixUniformDirty;
+ bool shaderMatrixUniformDirty;
bool stencilBuferDirty;
const QBrush* currentBrush; // May not be the state's brush!
GLfloat inverseScale;
- QGL2PEXVertexArray pathVertexArray;
+ QGL2PEXVertexArray vertexCoordinateArray;
+ QGL2PEXVertexArray textureCoordinateArray;
+
+ GLfloat staticVertexCoordinateArray[8];
+ GLfloat staticTextureCoordinateArray[8];
GLfloat pmvMatrix[4][4];
- QGLPEXShaderManager* shaderManager;
+ QGLEngineShaderManager* shaderManager;
// Clipping & state stuff stolen from QOpenGLPaintEngine:
void updateDepthClip();
uint use_system_clip : 1;
+
+ QPaintEngine *last_engine;
};
@@ -177,7 +191,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);
@@ -206,21 +220,21 @@ void QGL2PaintEngineExPrivate::setBrush(const QBrush* brush)
currentBrush = brush;
brushTextureDirty = true;
brushUniformsDirty = true;
- shaderManager->setBrushStyle(currentBrush->style());
- shaderManager->setAffineOnlyBrushTransform(currentBrush->transform().isAffine());
+ 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();
if (matrixDirty)
updateMatrix();
if (simpleShaderMatrixUniformDirty) {
- shaderManager->simpleShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix;
+ shaderManager->simpleProgram()->setUniformValue("pmvMatrix", pmvMatrix);
simpleShaderMatrixUniformDirty = false;
}
}
@@ -237,7 +251,7 @@ void QGL2PaintEngineExPrivate::updateBrushTexture()
// Get the image data for the pattern
QImage texImage = qt_imageForBrush(style, true);
- 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 +271,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 +293,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 +306,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 +322,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 +339,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,16 +352,15 @@ 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;
@@ -362,10 +368,10 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms()
const QPixmap& texPixmap = currentBrush->texture();
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 +380,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 +400,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 +501,140 @@ 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)
{
-// 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(QGLEngineShaderManager::ImageSrc);
+ shaderManager->setTextureCoordsEnabled(true);
+ prepareForDraw(false); // ###
- if (compositionModeDirty)
- updateCompositionMode();
+ shaderManager->currentProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT);
- if (matrixDirty)
- updateMatrix();
+ GLfloat dx = 1.0 / textureSize.width();
+ GLfloat dy = 1.0 / textureSize.height();
- if (imageShaderMatrixUniformDirty) {
- shaderManager->imageShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix;
- imageShaderMatrixUniformDirty = false;
- }
+ QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy);
- shaderManager->imageShader()->uniforms()[QLatin1String("textureSampler")] = QT_BRUSH_TEXTURE_UNIT;
+ setCoords(staticVertexCoordinateArray, dest);
+ setCoords(staticTextureCoordinateArray, srcTextureRect);
-// if (q->state()->opacity < 0.99f)
- shaderManager->imageShader()->uniforms()[QLatin1String("opacity")] = (GLfloat)q->state()->opacity;
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+}
- GLfloat vertexCoords[] = {
- dest.left, dest.top,
- dest.left, dest.bottom,
- dest.right, dest.bottom,
- dest.right, dest.top
- };
+void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
+{
+ if (newMode == mode)
+ return;
- glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
- glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords);
+ if (mode == TextDrawingMode || mode == ImageDrawingMode) {
+ glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
+ glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ }
- GLfloat dx = 1.0 / txtWidth;
- GLfloat dy = 1.0 / txtHeight;
+ if (mode == TextDrawingMode)
+ matrixDirty = true;
- QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy);
+ if (newMode == TextDrawingMode) {
+ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
- GLfloat textureCoords[] = {
- srcTextureRect.left, srcTextureRect.top,
- srcTextureRect.left, srcTextureRect.bottom,
- srcTextureRect.right, srcTextureRect.bottom,
- srcTextureRect.right, srcTextureRect.top
- };
+ 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());
- glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
- glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoords);
+ matrixDirty = true;
+ }
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ if (newMode == ImageDrawingMode) {
+ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
- glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
- glDisableVertexAttribArray(QT_VERTEX_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
glEnable(GL_STENCIL_TEST);
- prepareForDraw();
- composite(pathVertexArray.boundingRect());
+ prepareForDraw(currentBrush->isOpaque());
+ composite(vertexCoordinateArray.boundingRect());
glDisable(GL_STENCIL_TEST);
- cleanStencilBuffer(pathVertexArray.boundingRect());
+ cleanStencilBuffer(vertexCoordinateArray.boundingRect());
}
}
@@ -674,32 +710,53 @@ void QGL2PaintEngineExPrivate::cleanStencilBuffer(const QGLRect& area)
glDisable(GL_STENCIL_TEST);
}
-void QGL2PaintEngineExPrivate::prepareForDraw()
+void QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
{
- if (brushTextureDirty)
+ if (brushTextureDirty && mode != ImageDrawingMode)
updateBrushTexture();
if (compositionModeDirty)
updateCompositionMode();
+ if (matrixDirty)
+ updateMatrix();
+
+ const bool stateHasOpacity = q->state()->opacity < 0.99f;
+ if ( (!srcPixelsAreOpaque || stateHasOpacity) &&
+ q->state()->compositionMode() != QPainter::CompositionMode_Source)
+ glEnable(GL_BLEND);
+ else
+ glDisable(GL_BLEND);
+
+ bool useGlobalOpacityUniform = stateHasOpacity;
+ if (stateHasOpacity && (mode != ImageDrawingMode)) {
+ // Using a brush
+ bool brushIsPattern = (currentBrush->style() >= Qt::Dense1Pattern) &&
+ (currentBrush->style() <= Qt::DiagCrossPattern);
+
+ if ((currentBrush->style() == Qt::SolidPattern) || brushIsPattern)
+ useGlobalOpacityUniform = false; // Global opacity handled by srcPixel shader
+ }
+ shaderManager->setUseGlobalOpacity(useGlobalOpacityUniform);
+
+
+ // 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;
}
- 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 (useGlobalOpacityUniform)
+ shaderManager->currentProgram()->setUniformValue("globalOpacity", (GLfloat)q->state()->opacity);
}
void QGL2PaintEngineExPrivate::composite(const QGLRect& boundingRect)
@@ -749,8 +806,6 @@ void QGL2PaintEngineExPrivate::drawVertexArrays(QGL2PEXVertexArray& vertexArray,
QGL2PaintEngineEx::QGL2PaintEngineEx()
: QPaintEngineEx(*(new QGL2PaintEngineExPrivate(this)))
{
- qDebug("QGL2PaintEngineEx::QGL2PaintEngineEx()");
-
}
QGL2PaintEngineEx::~QGL2PaintEngineEx()
@@ -761,8 +816,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
@@ -772,6 +829,7 @@ void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
{
Q_D(QGL2PaintEngineEx);
+ ensureActive();
if (pen.style() == Qt::NoPen)
return;
@@ -790,7 +848,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 +876,6 @@ void QGL2PaintEngineEx::opacityChanged()
Q_D(QGL2PaintEngineEx);
Q_ASSERT(d->shaderManager);
- d->shaderManager->setUseGlobalOpacity(state()->opacity > 0.999);
d->brushUniformsDirty = true;
}
@@ -845,9 +901,12 @@ 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())
@@ -855,35 +914,39 @@ void QGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, c
else
glDisable(GL_BLEND);
- d->drawTexture(dest, src, pixmap.width(), pixmap.height());
+ d->drawTexture(dest, src, pixmap.size());
}
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);
+
+ QGLContext *ctx = d->ctx;
+ glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
+ ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true);
if ((state()->opacity < 0.99f) || image.hasAlphaChannel())
glEnable(GL_BLEND);
else
glDisable(GL_BLEND);
- d->drawTexture(dest, src, image.width(), image.height());
+ d->drawTexture(dest, src, image.size());
}
void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem)
{
+ Q_D(QGL2PaintEngineEx);
+
+ ensureActive();
QOpenGLPaintEngineState *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 +955,19 @@ 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();
+ transferMode(TextDrawingMode);
+
+ Q_Q(QGL2PaintEngineEx);
+ QOpenGLPaintEngineState *s = q->state();
QVarLengthArray<QFixedPoint> positions;
QVarLengthArray<glyph_t> glyphs;
@@ -910,10 +975,22 @@ void QGL2PaintEngineEx::drawCachedGlyphs(const QPointF &p, const QTextItemInt &t
matrix.translate(p.x(), p.y());
ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
+
QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0
? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat)
: QFontEngineGlyphCache::Raster_A8;
+ GLenum maskFormat = GL_RGBA;
+ if (glyphType == QFontEngineGlyphCache::Raster_A8) {
+ shaderManager->setMaskType(QGLEngineShaderManager::PixelMask);
+// maskFormat = GL_ALPHA;
+ }
+ else if (glyphType == QFontEngineGlyphCache::Raster_RGBMask)
+ shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMask);
+ //### TODO: Gamma correction
+ shaderManager->setTextureCoordsEnabled(true);
+
+
QImageTextureGlyphCache *cache =
(QImageTextureGlyphCache *) ti.fontEngine->glyphCache(glyphType, s->matrix);
if (!cache) {
@@ -926,66 +1003,46 @@ void QGL2PaintEngineEx::drawCachedGlyphs(const QPointF &p, const QTextItemInt &t
const QImage &image = cache->image();
int margin = cache->glyphMargin();
- glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
- d->ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true);
-
- glEnable(GL_BLEND);
-
- d->shaderManager->textShader()->use();
- d->updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
-
- if (d->compositionModeDirty)
- d->updateCompositionMode();
-
- if (d->matrixDirty)
- d->updateMatrix();
-
- if (d->textShaderMatrixUniformDirty) {
- d->shaderManager->textShader()->uniforms()[QLatin1String("pmvMatrix")] = d->pmvMatrix;
- d->textShaderMatrixUniformDirty = false;
- }
-
- 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;
+ if (image.isNull())
+ return;
GLfloat dx = 1.0 / image.width();
GLfloat dy = 1.0 / image.height();
- glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
- glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
+ QGLPoint *oldVertexCoordinateDataPtr = vertexCoordinateArray.data();
+ QGLPoint *oldTextureCoordinateDataPtr = textureCoordinateArray.data();
+
+ vertexCoordinateArray.clear();
+ textureCoordinateArray.clear();
+
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, 1 - c.y*dy, c.w * dx, -c.h * dy));
+ }
- GLfloat vertexCoords[] = {
- dest.left, dest.top,
- dest.left, dest.bottom,
- dest.right, dest.bottom,
- dest.right, dest.top
- };
+ glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
+ ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true);
+ updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
- glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords);
+ QBrush pensBrush = q->state()->pen.brush();
+ setBrush(&pensBrush);
- QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy);
+ prepareForDraw(false); // Text always causes src pixels to be transparent
- GLfloat textureCoords[] = {
- srcTextureRect.left, srcTextureRect.top,
- srcTextureRect.left, srcTextureRect.bottom,
- srcTextureRect.right, srcTextureRect.bottom,
- srcTextureRect.right, srcTextureRect.top
- };
+ shaderManager->currentProgram()->setUniformValue("maskTexture", QT_MASK_TEXTURE_UNIT);
- glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoords);
+ 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());
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- }
- glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
- glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size());
+
+ setBrush(&(q->state()->brush)); //###
}
bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
@@ -994,14 +1051,27 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
// qDebug("QGL2PaintEngineEx::begin()");
- 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.setDevice(pdev);
+ d->drawable.makeCurrent();
+ d->ctx = d->drawable.context();
+ QSize sz = d->drawable.size();
+ d->width = sz.width();
+ d->height = sz.height();
+ d->mode = BrushDrawingMode;
+
+ qt_resolve_version_1_3_functions(d->ctx);
+ qt_resolve_glsl_extensions(d->ctx);
+
+ d->last_engine = d->ctx->d_ptr->active_engine;
+ d->ctx->d_ptr->active_engine = this;
+
+ if (d->last_engine) {
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(d->last_engine);
+ static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr)->transferMode(BrushDrawingMode);
+ }
if (!d->shaderManager)
- d->shaderManager = new QGLPEXShaderManager(d->ctx);
+ d->shaderManager = new QGLEngineShaderManager(d->ctx);
glViewport(0, 0, d->width, d->height);
@@ -1020,17 +1090,84 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
d->use_system_clip = !systemClip().isEmpty();
glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+
+ QGLPixmapData *source = d->drawable.copyOnBegin();
+ if (source) {
+ d->transferMode(ImageDrawingMode);
+ source->bind(false);
+
+ glDisable(GL_BLEND);
+
+ QRect rect(0, 0, source->width(), source->height());
+ d->drawTexture(QRectF(rect), QRectF(rect), rect.size());
+ }
+
+ updateClipRegion(QRegion(), Qt::NoClip);
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 *>(d->last_engine);
+ if (engine) {
+ 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 = d->last_engine;
+
+ if (d->last_engine) {
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(d->last_engine);
+ QGL2PaintEngineExPrivate *p = static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr);
+
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+
+ glViewport(0, 0, p->width, p->height);
+ engine->setState(engine->state());
+ p->updateDepthClip();
+ }
+
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) {
+ 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);
+ glDisable(GL_SCISSOR_TEST);
+
+ glViewport(0, 0, d->width, d->height);
+ setState(state());
+ d->updateDepthClip();
+ }
+}
+
/////////////////////////////////// State/Clipping stolen from QOpenGLPaintEngine //////////////////////////////////////////
@@ -1161,11 +1298,6 @@ void QGL2PaintEngineEx::updateClipRegion(const QRegion &clipRegion, Qt::ClipOper
state()->hasClipping = op != Qt::NoClip || d->use_system_clip;
}
- if (state()->hasClipping && state()->clipRegion.rects().size() == 1)
- state()->fastClip = state()->clipRegion.rects().at(0);
- else
- state()->fastClip = QRect();
-
d->updateDepthClip();
}
@@ -1176,20 +1308,17 @@ void QGL2PaintEngineExPrivate::updateDepthClip()
Q_Q(QGL2PaintEngineEx);
+ q->ensureActive();
glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
if (!q->state()->hasClipping)
return;
- 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);
- }
+ const QVector<QRect> rects = q->state()->clipEnabled ? q->state()->clipRegion.rects() : q->systemClip().rects();
+ if (rects.size() == 1) {
+ QRect fastClip = rects.at(0);
- if (!fastClip.isEmpty()) {
glEnable(GL_SCISSOR_TEST);
const int left = fastClip.left();
@@ -1206,7 +1335,6 @@ void QGL2PaintEngineExPrivate::updateDepthClip()
glClear(GL_DEPTH_BUFFER_BIT);
glClearDepthf(0x1);
- 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);
@@ -1229,23 +1357,30 @@ void QGL2PaintEngineExPrivate::updateDepthClip()
-void QGL2PaintEngineEx::setState(QPainterState *s)
+void QGL2PaintEngineEx::setState(QPainterState *new_state)
{
// qDebug("QGL2PaintEngineEx::setState()");
Q_D(QGL2PaintEngineEx);
+
+ QOpenGLPaintEngineState *s = static_cast<QOpenGLPaintEngineState *>(new_state);
+
+ QOpenGLPaintEngineState *old_state = state();
+ const bool needsDepthClipUpdate = !old_state
+ || s->clipEnabled != old_state->clipEnabled
+ || (s->clipEnabled && s->clipRegion != old_state->clipRegion);
+
QPaintEngineEx::setState(s);
- d->updateDepthClip();
+ if (needsDepthClipUpdate)
+ d->updateDepthClip();
d->matrixDirty = true;
d->compositionModeDirty = true;
d->brushTextureDirty = true;
d->brushUniformsDirty = true;
d->simpleShaderMatrixUniformDirty = true;
- d->brushShaderMatrixUniformDirty = true;
- d->imageShaderMatrixUniformDirty = true;
- d->textShaderMatrixUniformDirty = true;
+ d->shaderMatrixUniformDirty = true;
}
QPainterState *QGL2PaintEngineEx::createState(QPainterState *orig) const
@@ -1264,7 +1399,6 @@ QOpenGLPaintEngineState::QOpenGLPaintEngineState(QOpenGLPaintEngineState &other)
{
clipRegion = other.clipRegion;
hasClipping = other.hasClipping;
- fastClip = other.fastClip;
}
QOpenGLPaintEngineState::QOpenGLPaintEngineState()
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
index ce66e4b..b31f685 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
@@ -67,7 +67,6 @@ public:
QRegion clipRegion;
bool hasClipping;
- QRect fastClip;
};
@@ -81,6 +80,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,11 +101,9 @@ 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;
diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro
index cdf31cc..88af516 100644
--- a/src/opengl/opengl.pro
+++ b/src/opengl/opengl.pro
@@ -25,6 +25,7 @@ HEADERS += qgl.h \
qglcolormap.h \
qglpixelbuffer.h \
qglframebufferobject.h \
+ qglpixmapfilter_p.h \
qglshaderprogram.h
SOURCES += qgl.cpp \
@@ -32,26 +33,26 @@ SOURCES += qgl.cpp \
qglpixelbuffer.cpp \
qglframebufferobject.cpp \
qglextensions.cpp \
+ qglpixmapfilter.cpp \
qglshaderprogram.cpp
-!contains(QT_CONFIG, opengles2) {
- HEADERS += qpaintengine_opengl_p.h qglpixmapfilter_p.h
- SOURCES += qpaintengine_opengl.cpp qglpixmapfilter.cpp
-}
+#!contains(QT_CONFIG, opengles2) {
+# HEADERS += qpaintengine_opengl_p.h
+# SOURCES += qpaintengine_opengl.cpp
+#}
-contains(QT_CONFIG, opengles2) {
+#contains(QT_CONFIG, opengles2) {
SOURCES += gl2paintengineex/qglgradientcache.cpp \
- gl2paintengineex/qglpexshadermanager.cpp \
- gl2paintengineex/qglshader.cpp \
+ gl2paintengineex/qglengineshadermanager.cpp \
gl2paintengineex/qgl2pexvertexarray.cpp \
gl2paintengineex/qpaintengineex_opengl2.cpp
HEADERS += gl2paintengineex/qglgradientcache_p.h \
- gl2paintengineex/qglpexshadermanager_p.h \
- gl2paintengineex/qglshader_p.h \
+ gl2paintengineex/qglengineshadermanager_p.h \
gl2paintengineex/qgl2pexvertexarray_p.h \
- gl2paintengineex/qpaintengineex_opengl2_p.h
-}
+ gl2paintengineex/qpaintengineex_opengl2_p.h \
+ gl2paintengineex/qglengineshadersource_p.h
+#}
x11 {
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index 2d58084..d74ed95 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -65,15 +65,20 @@
#include "qimage.h"
#include "qgl_p.h"
-#if defined(QT_OPENGL_ES_2)
+#if 1 || defined(QT_OPENGL_ES_2)
#include "gl2paintengineex/qpaintengineex_opengl2_p.h"
#else
#include <private/qpaintengine_opengl_p.h>
#endif
+#include <qglpixelbuffer.h>
+#include <qglframebufferobject.h>
+
#include <private/qimage_p.h>
#include <private/qpixmapdata_p.h>
#include <private/qpixmapdata_gl_p.h>
+#include <private/qglpixelbuffer_p.h>
+#include <private/qwindowsurface_gl_p.h>
#include "qcolormap.h"
#include "qcache.h"
#include "qfile.h"
@@ -1290,6 +1295,7 @@ void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format)
eglContext = 0;
#endif
pbo = 0;
+ fbo = 0;
crWin = false;
initDone = false;
sharing = false;
@@ -1298,6 +1304,7 @@ void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format)
version_flags_cached = false;
version_flags = QGLFormat::OpenGL_Version_None;
current_fbo = 0;
+ active_engine = 0;
}
QGLContext* QGLContext::currentCtx = 0;
@@ -1308,12 +1315,8 @@ QGLContext* QGLContext::currentCtx = 0;
QGLFramebufferObject::toImage()
*/
-QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha)
+static void convertFromGLImage(QImage &img, int w, int h, bool alpha_format, bool include_alpha)
{
- QImage img(size, alpha_format ? QImage::Format_ARGB32 : QImage::Format_RGB32);
- int w = size.width();
- int h = size.height();
- glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
// OpenGL gives RGBA; Qt wants ARGB
uint *p = (uint*)img.bits();
@@ -1344,7 +1347,27 @@ QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include
}
}
- return img.mirrored();
+ img = img.mirrored();
+}
+
+QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha)
+{
+ QImage img(size, alpha_format ? QImage::Format_ARGB32 : QImage::Format_RGB32);
+ int w = size.width();
+ int h = size.height();
+ glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
+ convertFromGLImage(img, w, h, alpha_format, include_alpha);
+ return img;
+}
+
+QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha)
+{
+ QImage img(size, alpha_format ? QImage::Format_ARGB32 : QImage::Format_RGB32);
+ int w = size.width();
+ int h = size.height();
+ glGetTexImage(qt_gl_preferredTextureTarget(), 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
+ convertFromGLImage(img, w, h, alpha_format, include_alpha);
+ return img;
}
// returns the highest number closest to v, which is a power of 2
@@ -1944,14 +1967,14 @@ GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint
/*! \internal */
GLuint QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean)
{
-#if !defined(QT_OPENGL_ES_2)
- if (target == qt_gl_preferredTextureTarget() && pixmap.pixmapData()->classId() == QPixmapData::OpenGLClass) {
- const QGLPixmapData *data = static_cast<const QGLPixmapData *>(pixmap.pixmapData());
+ Q_Q(QGLContext);
+ QPixmapData *pd = pixmap.pixmapData();
+ if (target == qt_gl_preferredTextureTarget() && pd->classId() == QPixmapData::OpenGLClass) {
+ const QGLPixmapData *data = static_cast<const QGLPixmapData *>(pd);
- if (data->isValidContext(QGLContext::currentContext()))
+ if (data->isValidContext(q))
return data->bind();
}
-#endif
const qint64 key = pixmap.cacheKey();
GLuint id;
@@ -2102,7 +2125,24 @@ void QGLContext::deleteTexture(QMacCompatGLuint id)
// qpaintengine_opengl.cpp
#if !defined(QT_OPENGL_ES_2)
-extern void qt_add_rect_to_array(const QRectF &r, q_vertexType *array);
+//extern void qt_add_rect_to_array(const QRectF &r, q_vertexType *array);
+void qt_add_rect_to_array(const QRectF &r, q_vertexType *array)
+{
+ qreal left = r.left();
+ qreal right = r.right();
+ qreal top = r.top();
+ qreal bottom = r.bottom();
+
+ array[0] = f2vt(left);
+ array[1] = f2vt(top);
+ array[2] = f2vt(right);
+ array[3] = f2vt(top);
+ array[4] = f2vt(right);
+ array[5] = f2vt(bottom);
+ array[6] = f2vt(left);
+ array[7] = f2vt(bottom);
+}
+
#else
void qt_add_rect_to_array(const QRectF &r, q_vertexType *array) {};
#endif
@@ -4112,14 +4152,14 @@ void QGLWidget::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QM
}
#endif
-#if defined(QT_OPENGL_ES_2)
+#if 1 || defined(QT_OPENGL_ES_2)
Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_engine)
#else
Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_engine)
#endif
#ifdef Q_WS_QWS
-Q_OPENGL_EXPORT QOpenGLPaintEngine* qt_qgl_paint_engine()
+Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine()
{
#if !defined(QT_OPENGL_ES_2)
return qt_gl_engine();
@@ -4226,6 +4266,8 @@ void QGLExtensions::init_extensions()
glExtensions |= FramebufferObject;
glExtensions |= GenerateMipmap;
#endif
+ if (extensions.contains(QLatin1String("EXT_framebuffer_blit")))
+ glExtensions |= FramebufferBlit;
QGLContext cx(QGLFormat::defaultFormat());
if (glExtensions & TextureCompression) {
@@ -4275,4 +4317,173 @@ Q_OPENGL_EXPORT const QString qt_gl_library_name()
}
#endif
+void QGLDrawable::setDevice(QPaintDevice *pdev)
+{
+ wasBound = false;
+ widget = 0;
+ buffer = 0;
+ fbo = 0;
+#ifdef Q_WS_QWS
+ wsurf = 0;
+#endif
+
+ if (pdev->devType() == QInternal::Pixmap) {
+ QPixmapData *data = static_cast<QPixmap *>(pdev)->pixmapData();
+ Q_ASSERT(data->classId() == QPixmapData::OpenGLClass);
+ pixmapData = static_cast<QGLPixmapData *>(data);
+
+ fbo = pixmapData->fbo();
+ }
+
+ if (pdev->devType() == QInternal::Widget)
+ widget = static_cast<QGLWidget *>(pdev);
+ else if (pdev->devType() == QInternal::Pbuffer)
+ buffer = static_cast<QGLPixelBuffer *>(pdev);
+ else if (pdev->devType() == QInternal::FramebufferObject)
+ fbo = static_cast<QGLFramebufferObject *>(pdev);
+ else if (pdev->devType() == QInternal::UnknownDevice)
+#ifdef Q_WS_QWS
+ wsurf = static_cast<QWSGLPaintDevice*>(pdev)->windowSurface();
+#else
+ wsurf = static_cast<QGLWindowSurface *>(pdev);
+#endif
+}
+
+void QGLDrawable::swapBuffers()
+{
+ if (widget) {
+ if (widget->autoBufferSwap())
+ widget->swapBuffers();
+ } else if (pixmapData) {
+ pixmapData->swapBuffers();
+ } else {
+ glFlush();
+ }
+}
+
+void QGLDrawable::makeCurrent()
+{
+ if (pixmapData)
+ pixmapData->makeCurrent();
+ else if (widget)
+ widget->makeCurrent();
+ else if (buffer)
+ buffer->makeCurrent();
+ else if (wsurf)
+ wsurf->context()->makeCurrent();
+ else if (fbo) {
+ wasBound = fbo->isBound();
+ if (!wasBound)
+ fbo->bind();
+ }
+}
+
+QGLPixmapData *QGLDrawable::copyOnBegin() const
+{
+ if (!pixmapData || pixmapData->isUninitialized())
+ return 0;
+ return pixmapData;
+}
+
+void QGLDrawable::doneCurrent()
+{
+ if (pixmapData)
+ pixmapData->doneCurrent();
+ else if (fbo && !wasBound)
+ fbo->release();
+}
+
+QSize QGLDrawable::size() const
+{
+ if (widget) {
+ return QSize(widget->d_func()->glcx->device()->width(),
+ widget->d_func()->glcx->device()->height());
+ } else if (pixmapData) {
+ return pixmapData->size();
+ } else if (buffer) {
+ return buffer->size();
+ } else if (fbo) {
+ return fbo->size();
+ } else if (wsurf) {
+#ifdef Q_WS_QWS
+ return wsurf->window()->frameSize();
+#else
+ return QSize(wsurf->width(), wsurf->height());
+#endif
+ }
+ return QSize();
+}
+
+QGLFormat QGLDrawable::format() const
+{
+ if (widget)
+ return widget->format();
+ else if (buffer)
+ return buffer->format();
+ else if (wsurf)
+ return wsurf->context()->format();
+ else if (fbo && QGLContext::currentContext()) {
+ QGLFormat fmt = QGLContext::currentContext()->format();
+ fmt.setStencil(fbo->attachment() == QGLFramebufferObject::CombinedDepthStencil);
+ fmt.setDepth(fbo->attachment() != QGLFramebufferObject::NoAttachment);
+ return fmt;
+ }
+
+ return QGLFormat();
+}
+
+GLuint QGLDrawable::bindTexture(const QImage &image, GLenum target, GLint format)
+{
+ if (widget)
+ return widget->d_func()->glcx->d_func()->bindTexture(image, target, format, true);
+ else if (buffer)
+ return buffer->d_func()->qctx->d_func()->bindTexture(image, target, format, true);
+ else if (fbo && QGLContext::currentContext())
+ return const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(image, target, format, true);
+ else if (wsurf)
+ return wsurf->context()->d_func()->bindTexture(image, target, format, true);
+ return 0;
+}
+
+GLuint QGLDrawable::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
+{
+ if (widget)
+ return widget->d_func()->glcx->d_func()->bindTexture(pixmap, target, format, true);
+ else if (buffer)
+ return buffer->d_func()->qctx->d_func()->bindTexture(pixmap, target, format, true);
+ else if (fbo && QGLContext::currentContext())
+ return const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(pixmap, target, format, true);
+ else if (wsurf)
+ return wsurf->context()->d_func()->bindTexture(pixmap, target, format, true);
+ return 0;
+}
+
+QColor QGLDrawable::backgroundColor() const
+{
+ if (widget)
+ return widget->palette().brush(widget->backgroundRole()).color();
+ return QApplication::palette().brush(QPalette::Background).color();
+}
+
+QGLContext *QGLDrawable::context() const
+{
+ if (widget)
+ return widget->d_func()->glcx;
+ else if (buffer)
+ return buffer->d_func()->qctx;
+ else if (fbo)
+ return const_cast<QGLContext *>(QGLContext::currentContext());
+ else if (wsurf)
+ return wsurf->context();
+ return 0;
+}
+
+bool QGLDrawable::autoFillBackground() const
+{
+ if (widget)
+ return widget->autoFillBackground();
+ else
+ return false;
+}
+
QT_END_NAMESPACE
diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h
index 32fbce2..19d779a 100644
--- a/src/opengl/qgl.h
+++ b/src/opengl/qgl.h
@@ -372,8 +372,8 @@ private:
friend QGLContextPrivate *qt_phonon_get_dptr(const QGLContext *);
#endif
friend class QGLFramebufferObject;
-#ifdef Q_WS_WIN
friend class QGLFramebufferObjectPrivate;
+#ifdef Q_WS_WIN
friend bool qt_resolve_GLSL_functions(QGLContext *ctx);
friend bool qt_createGLSLProgram(QGLContext *ctx, GLuint &program, const char *shader_src, GLuint &shader);
#endif
diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h
index 1214f20..f7b9392 100644
--- a/src/opengl/qgl_p.h
+++ b/src/opengl/qgl_p.h
@@ -60,6 +60,7 @@
#include "QtCore/qthreadstorage.h"
#include "QtCore/qhash.h"
#include "private/qwidget_p.h"
+#include "private/qpixmapdata_gl_p.h"
#ifndef QT_OPENGL_ES_1_CL
#define q_vertexType float
@@ -239,6 +240,7 @@ public:
QGLFormat glFormat;
QGLFormat reqFormat;
GLuint pbo;
+ GLuint fbo;
uint valid : 1;
uint sharing : 1;
@@ -256,6 +258,7 @@ public:
GLint max_texture_size;
GLuint current_fbo;
+ QPaintEngine *active_engine;
#ifdef Q_WS_WIN
static inline QGLExtensionFuncs& qt_get_extension_funcs(const QGLContext *ctx) { return ctx->d_ptr->extensionFuncs; }
@@ -283,6 +286,42 @@ Q_SIGNALS:
void aboutToDestroyContext(const QGLContext *context);
};
+class QGLPixelBuffer;
+class QGLFramebufferObject;
+class QWSGLWindowSurface;
+class QGLWindowSurface;
+class QGLDrawable {
+public:
+ QGLDrawable() : widget(0), buffer(0), fbo(0)
+ , wsurf(0), pixmapData(0)
+ {}
+ void setDevice(QPaintDevice *pdev);
+ void swapBuffers();
+ void makeCurrent();
+ void doneCurrent();
+ QSize size() const;
+ QGLFormat format() const;
+ GLuint bindTexture(const QImage &image, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA);
+ GLuint bindTexture(const QPixmap &pixmap, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA);
+ QColor backgroundColor() const;
+ QGLContext *context() const;
+ bool autoFillBackground() const;
+
+ QGLPixmapData *copyOnBegin() const;
+
+private:
+ bool wasBound;
+ QGLWidget *widget;
+ QGLPixelBuffer *buffer;
+ QGLFramebufferObject *fbo;
+#ifdef Q_WS_QWS
+ QWSGLWindowSurface *wsurf;
+#else
+ QGLWindowSurface *wsurf;
+#endif
+ QGLPixmapData *pixmapData;
+};
+
// GL extension definitions
class QGLExtensions {
public:
@@ -298,7 +337,8 @@ public:
StencilWrap = 0x00000100,
PackedDepthStencil = 0x00000200,
NVFloatBuffer = 0x00000400,
- PixelBufferObject = 0x00000800
+ PixelBufferObject = 0x00000800,
+ FramebufferBlit = 0x00001000
};
Q_DECLARE_FLAGS(Extensions, Extension)
@@ -386,9 +426,13 @@ inline GLenum qt_gl_preferredTextureFormat()
inline GLenum qt_gl_preferredTextureTarget()
{
+#if 1 || defined(QT_OPENGL_ES_2)
+ return GL_TEXTURE_2D;
+#else
return (QGLExtensions::glExtensions & QGLExtensions::TextureRectangle)
? GL_TEXTURE_RECTANGLE_NV
: GL_TEXTURE_2D;
+#endif
}
diff --git a/src/opengl/qglextensions.cpp b/src/opengl/qglextensions.cpp
index 5ba669b..9ec76cb 100644
--- a/src/opengl/qglextensions.cpp
+++ b/src/opengl/qglextensions.cpp
@@ -74,6 +74,9 @@ bool qt_resolve_framebufferobject_extensions(QGLContext *ctx)
glGetFramebufferAttachmentParameterivEXT =
(_glGetFramebufferAttachmentParameterivEXT) ctx->getProcAddress(QLatin1String("glGetFramebufferAttachmentParameterivEXT"));
glGenerateMipmapEXT = (_glGenerateMipmapEXT) ctx->getProcAddress(QLatin1String("glGenerateMipmapEXT"));
+ glBlitFramebufferEXT = (_glBlitFramebufferEXT) ctx->getProcAddress(QLatin1String("glBlitFramebufferEXT"));
+ glRenderbufferStorageMultisampleEXT =
+ (_glRenderbufferStorageMultisampleEXT) ctx->getProcAddress(QLatin1String("glRenderbufferStorageMultisampleEXT"));
return glIsRenderbufferEXT;
#else
Q_UNUSED(ctx);
@@ -211,6 +214,8 @@ bool qt_resolve_glsl_extensions(QGLContext *ctx)
glVertexAttribPointer = (_glVertexAttribPointer) ctx->getProcAddress(QLatin1String("glVertexAttribPointer"));
glDisableVertexAttribArray = (_glDisableVertexAttribArray) ctx->getProcAddress(QLatin1String("glDisableVertexAttribArray"));
glEnableVertexAttribArray = (_glEnableVertexAttribArray) ctx->getProcAddress(QLatin1String("glEnableVertexAttribArray"));
+
+ glStencilOpSeparate = (_glStencilOpSeparate) ctx->getProcAddress(QLatin1String("glStencilOpSeparate")); //### Not really a glsl extension, but needed for gl2
} else {
// We may not have the standard shader functions, but we might
// have the older ARB functions instead.
@@ -261,6 +266,8 @@ bool qt_resolve_glsl_extensions(QGLContext *ctx)
glVertexAttribPointer = (_glVertexAttribPointer) ctx->getProcAddress(QLatin1String("glVertexAttribPointerARB"));
glDisableVertexAttribArray = (_glDisableVertexAttribArray) ctx->getProcAddress(QLatin1String("glDisableVertexAttribArrayARB"));
glEnableVertexAttribArray = (_glEnableVertexAttribArray) ctx->getProcAddress(QLatin1String("glEnableVertexAttribArrayARB"));
+
+ glStencilOpSeparate = 0; //### Was never an ARB extension but went strait into OpenGL 2.0
}
// Note: glShaderBinary(), glIsShader(), glIsProgram(), and
@@ -300,7 +307,8 @@ bool qt_resolve_glsl_extensions(QGLContext *ctx)
glVertexAttrib4fv &&
glVertexAttribPointer &&
glDisableVertexAttribArray &&
- glEnableVertexAttribArray;
+ glEnableVertexAttribArray &&
+ glStencilOpSeparate;
#endif
}
diff --git a/src/opengl/qglextensions_p.h b/src/opengl/qglextensions_p.h
index f71ae9d..793400a 100644
--- a/src/opengl/qglextensions_p.h
+++ b/src/opengl/qglextensions_p.h
@@ -74,6 +74,10 @@
typedef ptrdiff_t GLsizeiptrARB;
#endif
+#ifndef GL_VERSION_2_0
+typedef char GLchar;
+#endif
+
// ARB_pixel_buffer_object
typedef void (APIENTRY *_glBindBufferARB) (GLenum, GLuint);
typedef void (APIENTRY *_glDeleteBuffersARB) (GLsizei, const GLuint *);
@@ -146,6 +150,22 @@ typedef void (APIENTRY *_glActiveStencilFaceEXT) (GLenum );
typedef void (APIENTRY *_glMultiTexCoord4f) (GLenum, GLfloat, GLfloat, GLfloat, GLfloat);
typedef void (APIENTRY *_glActiveTexture) (GLenum);
+typedef void (APIENTRY *_glGetActiveAttrib) (GLuint program, GLuint index, GLsizei maxLength, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+typedef GLint (APIENTRY *_glGetAttribLocation) (GLuint program, const GLchar* name);
+typedef void (APIENTRY *_glGetActiveUniform) (GLuint program, GLuint index, GLsizei maxLength, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+typedef void (APIENTRY *_glGetProgramInfoLog) (GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
+typedef void (APIENTRY *_glUniform1f) (GLint location, GLfloat v0);
+typedef void (APIENTRY *_glUniform2f) (GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRY *_glUniform4f) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRY *_glUniformMatrix2fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+typedef void (APIENTRY *_glUniformMatrix3fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+typedef void (APIENTRY *_glUniformMatrix4fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+typedef void (APIENTRY *_glEnableVertexAttribArray) (GLuint);
+typedef void (APIENTRY *_glDisableVertexAttribArray) (GLuint);
+typedef void (APIENTRY *_glVertexAttribPointer) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* pointer);
+typedef void (APIENTRY *_glStencilOpSeparate) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+
+
// EXT_GL_framebuffer_object
typedef GLboolean (APIENTRY *_glIsRenderbufferEXT) (GLuint renderbuffer);
typedef void (APIENTRY *_glBindRenderbufferEXT) (GLenum target, GLuint renderbuffer);
@@ -170,6 +190,15 @@ typedef void (APIENTRY *_glGetFramebufferAttachmentParameterivEXT) (GLenum targe
GLint *params);
typedef void (APIENTRY *_glGenerateMipmapEXT) (GLenum target);
+// EXT_GL_framebuffer_blit
+typedef void (APIENTRY *_glBlitFramebufferEXT) (int srcX0, int srcY0, int srcX1, int srcY1,
+ int dstX0, int dstY0, int dstX1, int dstY1,
+ GLbitfield mask, GLenum filter);
+
+// EXT_GL_framebuffer_multisample
+typedef void (APIENTRY *_glRenderbufferStorageMultisampleEXT) (GLenum target, GLsizei samples,
+ GLenum internalformat, GLsizei width, GLsizei height);
+
QT_BEGIN_NAMESPACE
struct QGLExtensionFuncs
@@ -260,6 +289,8 @@ struct QGLExtensionFuncs
qt_glGetFramebufferAttachmentParameterivEXT = 0;
qt_glGenerateMipmapEXT = 0;
#endif
+ qt_glBlitFramebufferEXT = 0;
+ qt_glRenderbufferStorageMultisampleEXT = 0;
qt_glBindBufferARB = 0;
qt_glDeleteBuffersARB = 0;
@@ -267,6 +298,21 @@ struct QGLExtensionFuncs
qt_glBufferDataARB = 0;
qt_glMapBufferARB = 0;
qt_glUnmapBufferARB = 0;
+
+ qt_glGetActiveAttrib = 0;
+ qt_glGetAttribLocation = 0;
+ qt_glGetActiveUniform = 0;
+ qt_glGetProgramInfoLog = 0;
+ qt_glUniform1f = 0;
+ qt_glUniform2f = 0;
+ qt_glUniform4f = 0;
+ qt_glUniformMatrix2fv = 0;
+ qt_glUniformMatrix3fv = 0;
+ qt_glUniformMatrix4fv = 0;
+ qt_glEnableVertexAttribArray = 0;
+ qt_glDisableVertexAttribArray = 0;
+ qt_glVertexAttribPointer = 0;
+ qt_glStencilOpSeparate = 0;
}
_glProgramStringARB qt_glProgramStringARB;
@@ -355,6 +401,8 @@ struct QGLExtensionFuncs
_glGetFramebufferAttachmentParameterivEXT qt_glGetFramebufferAttachmentParameterivEXT;
_glGenerateMipmapEXT qt_glGenerateMipmapEXT;
#endif
+ _glBlitFramebufferEXT qt_glBlitFramebufferEXT;
+ _glRenderbufferStorageMultisampleEXT qt_glRenderbufferStorageMultisampleEXT;
_glBindBufferARB qt_glBindBufferARB;
_glDeleteBuffersARB qt_glDeleteBuffersARB;
@@ -362,6 +410,13 @@ struct QGLExtensionFuncs
_glBufferDataARB qt_glBufferDataARB;
_glMapBufferARB qt_glMapBufferARB;
_glUnmapBufferARB qt_glUnmapBufferARB;
+
+ _glGetActiveAttrib qt_glGetActiveAttrib;
+ _glGetActiveUniform qt_glGetActiveUniform;
+ _glUniform1f qt_glUniform1f;
+ _glUniform2f qt_glUniform2f;
+ _glUniform4f qt_glUniform4f;
+ _glStencilOpSeparate qt_glStencilOpSeparate;
};
@@ -489,6 +544,28 @@ struct QGLExtensionFuncs
#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55
#endif
+// GL_EXT_framebuffer_blit
+#ifndef GL_READ_FRAMEBUFFER_EXT
+#define GL_READ_FRAMEBUFFER_EXT 0x8CA8
+#endif
+
+// GL_EXT_framebuffer_multisample
+#ifndef GL_RENDERBUFFER_SAMPLES_EXT
+#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB
+#endif
+
+#ifndef GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56
+#endif
+
+#ifndef GL_MAX_SAMPLES_EXT
+#define GL_MAX_SAMPLES_EXT 0x8D5
+#endif
+
+#ifndef GL_DRAW_FRAMEBUFFER_EXT
+#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9
+#endif
+
#ifndef GL_EXT_packed_depth_stencil
#define GL_DEPTH_STENCIL_EXT 0x84F9
#define GL_UNSIGNED_INT_24_8_EXT 0x84FA
@@ -508,6 +585,40 @@ struct QGLExtensionFuncs
#define GL_UNPACK_IMAGE_HEIGHT 0x806E
#endif
+#ifndef GL_VERSION_1_4
+#define GL_INCR_WRAP 0x8507
+#define GL_DECR_WRAP 0x8508
+#endif
+
+#ifndef GL_VERSION_2_0
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_FLOAT_VEC2 0x8B50
+#define GL_FLOAT_VEC3 0x8B51
+#define GL_FLOAT_VEC4 0x8B52
+#define GL_INT_VEC2 0x8B53
+#define GL_INT_VEC3 0x8B54
+#define GL_INT_VEC4 0x8B55
+#define GL_BOOL 0x8B56
+#define GL_BOOL_VEC2 0x8B57
+#define GL_BOOL_VEC3 0x8B58
+#define GL_BOOL_VEC4 0x8B59
+#define GL_FLOAT_MAT2 0x8B5A
+#define GL_FLOAT_MAT3 0x8B5B
+#define GL_FLOAT_MAT4 0x8B5C
+#define GL_SAMPLER_1D 0x8B5D
+#define GL_SAMPLER_2D 0x8B5E
+#define GL_SAMPLER_3D 0x8B5F
+#define GL_SAMPLER_CUBE 0x8B60
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_LINK_STATUS 0x8B82
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#endif
+
#define glProgramStringARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glProgramStringARB
#define glBindProgramARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBindProgramARB
#define glDeleteProgramsARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteProgramsARB
@@ -541,6 +652,8 @@ struct QGLExtensionFuncs
#define glFramebufferRenderbufferEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glFramebufferRenderbufferEXT
#define glGetFramebufferAttachmentParameterivEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetFramebufferAttachmentParameterivEXT
#define glGenerateMipmapEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGenerateMipmapEXT
+#define glBlitFramebufferEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBlitFramebufferEXT
+#define glRenderbufferStorageMultisampleEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glRenderbufferStorageMultisampleEXT
#else // QT_OPENGL_ES_2
@@ -628,6 +741,12 @@ struct QGLExtensionFuncs
#endif // QT_OPENGL_ES_2
+#define glStencilOpSeparate QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glStencilOpSeparate
+
+#if !defined(QT_OPENGL_ES_2)
+#define glClearDepthf(x) glClearDepth(GLdouble(x))
+#endif
+
extern bool qt_resolve_framebufferobject_extensions(QGLContext *ctx);
bool qt_resolve_buffer_extensions(QGLContext *ctx);
diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp
index 4ba9213..b210285 100644
--- a/src/opengl/qglframebufferobject.cpp
+++ b/src/opengl/qglframebufferobject.cpp
@@ -43,7 +43,11 @@
#include <qdebug.h>
#include <private/qgl_p.h>
+#if 1 || defined(QT_OPENGL_ES_2)
+#include <private/qpaintengineex_opengl2_p.h>
+#else
#include <private/qpaintengine_opengl_p.h>
+#endif
#include <qglframebufferobject.h>
#include <qlibrary.h>
#include <qimage.h>
@@ -67,6 +71,216 @@ extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
} \
}
+class QGLFramebufferObjectFormatPrivate
+{
+public:
+ int samples;
+ QGLFramebufferObject::Attachment attachment;
+ GLenum target;
+ GLenum internal_format;
+};
+
+/*!
+ \class QGLFramebufferObjectFormat
+ \brief The QGLFramebufferObjectFormat class specifies the format of an OpenGL
+ framebuffer object.
+
+ \since 4.6
+
+ \ingroup multimedia
+
+ A framebuffer object has several characteristics:
+ \list
+ \i \link setSamples() Number of samples per pixels.\endlink
+ \i \link setAttachment() Depth and/or stencil attachments.\endlink
+ \i \link setTextureTarget() Texture target.\endlink
+ \i \link setInternalFormat() Internal format.\endlink
+ \endlist
+
+ Note that the desired attachments or number of samples per pixels might not
+ be supported by the hardware driver. Call QGLFramebufferObject::format()
+ after creating a QGLFramebufferObject to find the exact format that was
+ used to create the frame buffer object.
+
+ \sa QGLFramebufferObject
+*/
+
+/*!
+ \since 4.6
+
+ Creates a QGLFramebufferObjectFormat object with properties specifying
+ the format of an OpenGL framebuffer object.
+
+ A multisample framebuffer object is specified by setting \a samples
+ to a value different from zero. If the desired amount of samples per pixel is
+ not supported by the hardware then the maximum number of samples per pixel
+ will be used. Note that multisample framebuffer objects can not be bound as
+ textures. Also, the \c{GL_EXT_framebuffer_multisample} extension is required
+ to create a framebuffer with more than one sample per pixel.
+
+ For multisample framebuffer objects a color render buffer is created,
+ otherwise a texture with the texture target \a target is created.
+ The color render buffer or texture will have the internal format
+ \a internalFormat, and will be bound to the \c GL_COLOR_ATTACHMENT0
+ attachment in the framebuffer object.
+
+ The \a attachment parameter describes the depth/stencil buffer
+ configuration.
+
+ \sa samples(), attachment(), target(), internalFormat()
+*/
+
+QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(int samples,
+ QGLFramebufferObject::Attachment attachment,
+ GLenum target,
+ GLenum internalFormat)
+{
+ d = new QGLFramebufferObjectFormatPrivate;
+ d->samples = samples;
+ d->attachment = attachment;
+ d->target = target;
+ d->internal_format = internalFormat;
+}
+
+/*!
+ \since 4.6
+
+ Constructs a copy of \a other.
+*/
+
+QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(const QGLFramebufferObjectFormat &other)
+{
+ d = new QGLFramebufferObjectFormatPrivate;
+ *d = *other.d;
+}
+
+/*!
+ \since 4.6
+
+ Assigns \a other to this object.
+*/
+
+QGLFramebufferObjectFormat::QGLFramebufferObjectFormat &
+QGLFramebufferObjectFormat::operator=(const QGLFramebufferObjectFormat &other)
+{
+ *d = *other.d;
+ return *this;
+}
+
+/*!
+ \since 4.6
+
+ Destroys the QGLFramebufferObjectFormat.
+*/
+QGLFramebufferObjectFormat::~QGLFramebufferObjectFormat()
+{
+ delete d;
+}
+
+/*!
+ \since 4.6
+
+ Sets the number of samples per pixel for a multisample framebuffer object
+ to \a samples.
+ A sample count of 0 represents a regular non-multisample framebuffer object.
+
+ \sa samples()
+*/
+void QGLFramebufferObjectFormat::setSamples(int samples)
+{
+ d->samples = samples;
+}
+
+/*!
+ \since 4.6
+
+ Returns the number of samples per pixel if a framebuffer object
+ is a multisample framebuffer object. Otherwise, returns 0.
+
+ \sa setSamples()
+*/
+int QGLFramebufferObjectFormat::samples() const
+{
+ return d->samples;
+}
+
+/*!
+ \since 4.6
+
+ Sets the attachments a framebuffer object should have to \a attachment.
+
+ \sa attachment()
+*/
+void QGLFramebufferObjectFormat::setAttachment(QGLFramebufferObject::Attachment attachment)
+{
+ d->attachment = attachment;
+}
+
+/*!
+ \since 4.6
+
+ Returns the status of the depth and stencil buffers attached to
+ a framebuffer object.
+
+ \sa setAttachment()
+*/
+QGLFramebufferObject::Attachment QGLFramebufferObjectFormat::attachment() const
+{
+ return d->attachment;
+}
+
+/*!
+ \since 4.6
+
+ Sets the texture target of the texture attached to a framebuffer object to
+ \a target. Ignored for multisample framebuffer objects.
+
+ \sa textureTarget(), samples()
+*/
+void QGLFramebufferObjectFormat::setTextureTarget(GLenum target)
+{
+ d->target = target;
+}
+
+/*!
+ \since 4.6
+
+ Returns the texture target of the texture attached to a framebuffer object.
+ Ignored for multisample framebuffer objects.
+
+ \sa setTextureTarget(), samples()
+*/
+GLenum QGLFramebufferObjectFormat::textureTarget() const
+{
+ return d->target;
+}
+
+/*!
+ \since 4.6
+
+ Sets the internal format of a framebuffer object's texture or multisample
+ framebuffer object's color buffer to \a internalFormat.
+
+ \sa internalFormat()
+*/
+void QGLFramebufferObjectFormat::setInternalFormat(GLenum internalFormat)
+{
+ d->internal_format = internalFormat;
+}
+
+/*!
+ \since 4.6
+
+ Returns the internal format of a framebuffer object's texture or
+ multisample framebuffer object's color buffer.
+
+ \sa setInternalFormat()
+*/
+GLenum QGLFramebufferObjectFormat::internalFormat() const
+{
+ return d->internal_format;
+}
+
class QGLFramebufferObjectPrivate
{
public:
@@ -74,13 +288,16 @@ public:
~QGLFramebufferObjectPrivate() {}
void init(const QSize& sz, QGLFramebufferObject::Attachment attachment,
- GLenum internal_format, GLenum texture_target);
+ GLenum internal_format, GLenum texture_target, int samples = 0);
bool checkFramebufferStatus() const;
GLuint texture;
GLuint fbo;
GLuint depth_stencil_buffer;
+ GLuint color_buffer;
GLenum target;
QSize size;
+ QGLFramebufferObjectFormat format;
+ int samples;
uint valid : 1;
uint bound : 1;
QGLFramebufferObject::Attachment fbo_attachment;
@@ -122,6 +339,9 @@ bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
qDebug("QGLFramebufferObject: Framebuffer incomplete, missing read buffer.");
break;
+ case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
+ qDebug("QGLFramebufferObject: Framebuffer incomplete, attachments must have same number of samples per pixel.");
+ break;
default:
qDebug() <<"QGLFramebufferObject: An undefined error has occurred: "<< status;
break;
@@ -130,7 +350,7 @@ bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
}
void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::Attachment attachment,
- GLenum texture_target, GLenum internal_format)
+ GLenum texture_target, GLenum internal_format, int samples)
{
ctx = const_cast<QGLContext *>(QGLContext::currentContext());
bool ext_detected = (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject);
@@ -147,26 +367,56 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
QT_CHECK_GLERROR();
// init texture
- glGenTextures(1, &texture);
- glBindTexture(target, texture);
- glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ if (samples == 0) {
+ glGenTextures(1, &texture);
+ glBindTexture(target, texture);
+ glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
#ifndef QT_OPENGL_ES
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#else
- glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#endif
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
- target, texture, 0);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ target, texture, 0);
- QT_CHECK_GLERROR();
- valid = checkFramebufferStatus();
+ QT_CHECK_GLERROR();
+ valid = checkFramebufferStatus();
+
+ color_buffer = 0;
+ samples = 0;
+ } else {
+ GLint maxSamples;
+ glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples);
+
+ samples = qBound(1, samples, int(maxSamples));
+
+ glGenRenderbuffersEXT(1, &color_buffer);
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, color_buffer);
+ if (glRenderbufferStorageMultisampleEXT) {
+ glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
+ internal_format, size.width(), size.height());
+ } else {
+ samples = 0;
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, internal_format,
+ size.width(), size.height());
+ }
+
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT, color_buffer);
+
+ QT_CHECK_GLERROR();
+ valid = checkFramebufferStatus();
+
+ if (valid)
+ glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_SAMPLES_EXT, &samples);
+ }
if (attachment == QGLFramebufferObject::CombinedDepthStencil
&& (QGLExtensions::glExtensions & QGLExtensions::PackedDepthStencil)) {
@@ -175,7 +425,13 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
Q_ASSERT(!glIsRenderbufferEXT(depth_stencil_buffer));
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
Q_ASSERT(glIsRenderbufferEXT(depth_stencil_buffer));
- glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, size.width(), size.height());
+ if (samples != 0 && glRenderbufferStorageMultisampleEXT)
+ glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
+ GL_DEPTH24_STENCIL8_EXT, size.width(), size.height());
+ else
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
+ GL_DEPTH24_STENCIL8_EXT, size.width(), size.height());
+
GLint i = 0;
glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
@@ -183,6 +439,7 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, depth_stencil_buffer);
fbo_attachment = QGLFramebufferObject::CombinedDepthStencil;
+
valid = checkFramebufferStatus();
if (!valid)
glDeleteRenderbuffersEXT(1, &depth_stencil_buffer);
@@ -193,12 +450,23 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
Q_ASSERT(!glIsRenderbufferEXT(depth_stencil_buffer));
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
Q_ASSERT(glIsRenderbufferEXT(depth_stencil_buffer));
+ if (samples != 0 && glRenderbufferStorageMultisampleEXT) {
+#ifdef QT_OPENGL_ES
+#define GL_DEPTH_COMPONENT16 0x81A5
+ glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
+ GL_DEPTH_COMPONENT16, size.width(), size.height());
+#else
+ glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
+ GL_DEPTH_COMPONENT, size.width(), size.height());
+#endif
+ } else {
#ifdef QT_OPENGL_ES
#define GL_DEPTH_COMPONENT16 0x81A5
- glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, size.width(), size.height());
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, size.width(), size.height());
#else
- glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, size.width(), size.height());
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, size.width(), size.height());
#endif
+ }
GLint i = 0;
glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
@@ -211,12 +479,20 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
fbo_attachment = QGLFramebufferObject::NoAttachment;
}
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
if (!valid) {
- glDeleteTextures(1, &texture);
+ if (color_buffer)
+ glDeleteRenderbuffersEXT(1, &color_buffer);
+ else
+ glDeleteTextures(1, &texture);
glDeleteFramebuffersEXT(1, &fbo);
}
QT_CHECK_GLERROR();
+
+ format.setTextureTarget(target);
+ format.setSamples(samples);
+ format.setAttachment(fbo_attachment);
+ format.setInternalFormat(internal_format);
}
/*!
@@ -264,13 +540,18 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
framebuffer objects more portable.
\endlist
- Note that primitives drawn to a QGLFramebufferObject with QPainter
- will only be antialiased if the QPainter::HighQualityAntialiasing
- render hint is set. This is because there is currently no support
- for the \c{GL_EXT_framebuffer_multisample} extension, which is
- required to do multisample based antialiasing. Also note that the
- QPainter::HighQualityAntialiasing render hint requires the
- \c{GL_ARB_fragment_program} extension to work in OpenGL.
+ Note that you need to create a QGLFramebufferObject with more than one
+ sample per pixel for primitives to be antialiased when drawing using a
+ QPainter, unless if the QPainter::HighQualityAntialiasing render hint is
+ set. The QPainter::HighQualityAntialiasing render hint will enable
+ antialiasing as long as the \c{GL_ARB_fragment_program} extension is
+ present. To create a multisample framebuffer object you should use one of
+ the constructors that take a QGLFramebufferObject parameter, and set the
+ QGLFramebufferObject::samples() property to a non-zero value.
+
+ If you want to use a framebuffer object with multisampling enabled
+ as a texture, you first need to copy from it to a regular framebuffer
+ object using QGLContext::blitFramebuffer().
\sa {Framebuffer Object Example}
*/
@@ -358,6 +639,32 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, GLenum target)
d->init(QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
}
+/*! \overload
+
+ Constructs an OpenGL framebuffer object of the given \a size based on the
+ supplied \a format.
+*/
+
+QGLFramebufferObject::QGLFramebufferObject(const QSize &size, const QGLFramebufferObjectFormat &format)
+ : d_ptr(new QGLFramebufferObjectPrivate)
+{
+ Q_D(QGLFramebufferObject);
+ d->init(size, format.attachment(), format.textureTarget(), format.internalFormat(), format.samples());
+}
+
+/*! \overload
+
+ Constructs an OpenGL framebuffer object of the given \a width and \a height
+ based on the supplied \a format.
+*/
+
+QGLFramebufferObject::QGLFramebufferObject(int width, int height, const QGLFramebufferObjectFormat &format)
+ : d_ptr(new QGLFramebufferObjectPrivate)
+{
+ Q_D(QGLFramebufferObject);
+ d->init(QSize(width, height), format.attachment(), format.textureTarget(), format.internalFormat(), format.samples());
+}
+
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
/*! \internal */
QGLFramebufferObject::QGLFramebufferObject(int width, int height, QMacCompatGLenum target)
@@ -445,6 +752,8 @@ QGLFramebufferObject::~QGLFramebufferObject()
|| qgl_share_reg()->checkSharing(d->ctx, QGLContext::currentContext())))
{
glDeleteTextures(1, &d->texture);
+ if (d->color_buffer)
+ glDeleteRenderbuffersEXT(1, &d->color_buffer);
if (d->depth_stencil_buffer)
glDeleteRenderbuffersEXT(1, &d->depth_stencil_buffer);
glDeleteFramebuffersEXT(1, &d->fbo);
@@ -520,18 +829,17 @@ bool QGLFramebufferObject::release()
return false;
Q_D(QGLFramebufferObject);
QGL_FUNC_CONTEXT;
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
- d->valid = d->checkFramebufferStatus();
d->bound = false;
+
const QGLContext *context = QGLContext::currentContext();
- if (d->valid && context) {
+ if (context) {
// Restore the previous setting for stacked framebuffer objects.
context->d_ptr->current_fbo = d->previous_fbo;
- if (d->previous_fbo)
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, d->previous_fbo);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, d->previous_fbo);
d->previous_fbo = 0;
}
- return d->valid;
+
+ return true;
}
/*!
@@ -540,6 +848,9 @@ bool QGLFramebufferObject::release()
Returns the texture id for the texture attached as the default
rendering target in this framebuffer object. This texture id can
be bound as a normal texture in your own GL code.
+
+ If a multisample framebuffer object is used then the value returned
+ from this function will be invalid.
*/
GLuint QGLFramebufferObject::texture() const
{
@@ -560,6 +871,15 @@ QSize QGLFramebufferObject::size() const
}
/*!
+ Returns the format of this framebuffer object.
+*/
+const QGLFramebufferObjectFormat &QGLFramebufferObject::format() const
+{
+ Q_D(const QGLFramebufferObject);
+ return d->format;
+}
+
+/*!
\fn QImage QGLFramebufferObject::toImage() const
Returns the contents of this framebuffer object as a QImage.
@@ -577,7 +897,9 @@ QImage QGLFramebufferObject::toImage() const
return image;
}
-#if !defined(QT_OPENGL_ES_2)
+#if 1 || defined(QT_OPENGL_ES_2)
+Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_buffer_paintengine)
+#else
Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_paintengine)
#endif
@@ -599,7 +921,8 @@ QPaintEngine *QGLFramebufferObject::paintEngine() const
*/
bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
{
- QGLWidget dmy; // needed to detect and init the QGLExtensions object
+ if (!QGLContext::currentContext())
+ QGLWidget dmy; // needed to detect and init the QGLExtensions object
return (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject);
}
@@ -750,4 +1073,85 @@ bool QGLFramebufferObject::isBound() const
return d->bound;
}
+/*!
+ \fn bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
+
+ \since 4.6
+
+ Returns true if the OpenGL \c{GL_EXT_framebuffer_blit} extension
+ is present on this system; otherwise returns false.
+*/
+bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
+{
+ if (!QGLContext::currentContext())
+ QGLWidget dmy; // needed to detect and init the QGLExtensions object
+ return (QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit);
+}
+
+/*!
+ \since 4.6
+
+ Blits from the \a sourceRect rectangle in the \a source framebuffer
+ object to the \a targetRect rectangle in the \a target framebuffer object.
+
+ If \a source or \a target is 0, the default framebuffer will be used
+ instead of a framebuffer object as source or target respectively.
+
+ The \a buffers parameter should be a mask consisting of any combination of
+ COLOR_BUFFER_BIT, DEPTH_BUFFER_BIT, and STENCIL_BUFFER_BIT. Any buffer type
+ that is not present both in the source and target buffers is ignored.
+
+ The \a sourceRect and \a targetRect rectangles may have different sizes;
+ in this case \a buffers should not contain DEPTH_BUFFER_BIT or
+ STENCIL_BUFFER_BIT. The \a filter parameter should be set to GL_LINEAR or
+ GL_NEAREST, and specifies whether linear or nearest interpolation should
+ be used when scaling is performed.
+
+ If \a source equals \a target a copy is performed within the same buffer.
+ Results are undefined if the source and target rectangles overlap and
+ have different sizes. The sizes must also be the same if any of the
+ framebuffer objects are multisample framebuffers.
+
+ Note that the scissor test will restrict the blit area if enabled.
+
+ This function will have no effect unless hasOpenGLFramebufferBlit() returns
+ true.
+*/
+void QGLFramebufferObject::blitFramebuffer(QGLFramebufferObject *target, const QRect &targetRect,
+ QGLFramebufferObject *source, const QRect &sourceRect,
+ GLbitfield buffers,
+ GLenum filter)
+{
+ if (!(QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit))
+ return;
+
+ const QGLContext *ctx = QGLContext::currentContext();
+ if (!ctx)
+ return;
+
+ const int height = ctx->device()->height();
+
+ const int sh = source ? source->height() : height;
+ const int th = target ? target->height() : height;
+
+ const int sx0 = sourceRect.left();
+ const int sx1 = sourceRect.left() + sourceRect.width();
+ const int sy0 = sh - (sourceRect.top() + sourceRect.height());
+ const int sy1 = sh - sourceRect.top();
+
+ const int tx0 = targetRect.left();
+ const int tx1 = targetRect.left() + targetRect.width();
+ const int ty0 = th - (targetRect.top() + targetRect.height());
+ const int ty1 = th - targetRect.top();
+
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, source ? source->handle() : 0);
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, target ? target->handle() : 0);
+
+ glBlitFramebufferEXT(sx0, sy0, sx1, sy1,
+ tx0, ty0, tx1, ty1,
+ buffers, filter);
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
+}
+
QT_END_NAMESPACE
diff --git a/src/opengl/qglframebufferobject.h b/src/opengl/qglframebufferobject.h
index a9e1b2f..0a2a9d2 100644
--- a/src/opengl/qglframebufferobject.h
+++ b/src/opengl/qglframebufferobject.h
@@ -52,6 +52,7 @@ QT_BEGIN_NAMESPACE
QT_MODULE(OpenGL)
class QGLFramebufferObjectPrivate;
+class QGLFramebufferObjectFormat;
class Q_OPENGL_EXPORT QGLFramebufferObject : public QPaintDevice
{
@@ -77,6 +78,9 @@ public:
GLenum target = GL_TEXTURE_2D, GLenum internal_format = GL_RGBA);
#endif
+ QGLFramebufferObject(const QSize &size, const QGLFramebufferObjectFormat &format);
+ QGLFramebufferObject(int width, int height, const QGLFramebufferObjectFormat &format);
+
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
QGLFramebufferObject(const QSize &size, QMacCompatGLenum target = GL_TEXTURE_2D);
QGLFramebufferObject(int width, int height, QMacCompatGLenum target = GL_TEXTURE_2D);
@@ -89,10 +93,13 @@ public:
virtual ~QGLFramebufferObject();
+ const QGLFramebufferObjectFormat &format() const;
+
bool isValid() const;
bool isBound() const;
bool bind();
bool release();
+
GLuint texture() const;
QSize size() const;
QImage toImage() const;
@@ -110,6 +117,12 @@ public:
void drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget = GL_TEXTURE_2D);
#endif
+ static bool hasOpenGLFramebufferBlit();
+ static void blitFramebuffer(QGLFramebufferObject *target, const QRect &targetRect,
+ QGLFramebufferObject *source, const QRect &sourceRect,
+ GLbitfield buffers = GL_COLOR_BUFFER_BIT,
+ GLenum filter = GL_NEAREST);
+
protected:
int metric(PaintDeviceMetric metric) const;
int devType() const { return QInternal::FramebufferObject; }
@@ -120,6 +133,42 @@ private:
friend class QGLDrawable;
};
+class QGLFramebufferObjectFormatPrivate;
+class Q_OPENGL_EXPORT QGLFramebufferObjectFormat
+{
+public:
+#if !defined(QT_OPENGL_ES) || defined(Q_QDOC)
+ QGLFramebufferObjectFormat(int samples = 0,
+ QGLFramebufferObject::Attachment attachment = QGLFramebufferObject::NoAttachment,
+ GLenum target = GL_TEXTURE_2D,
+ GLenum internalFormat = GL_RGBA8);
+#else
+ QGLFramebufferObjectFormat(int samples = 0,
+ QGLFramebufferObject::Attachment attachment = QGLFramebufferObject::NoAttachment,
+ GLenum target = GL_TEXTURE_2D,
+ GLenum internalFormat = GL_RGBA);
+#endif
+
+ QGLFramebufferObjectFormat(const QGLFramebufferObjectFormat &other);
+ QGLFramebufferObjectFormat &operator=(const QGLFramebufferObjectFormat &other);
+ ~QGLFramebufferObjectFormat();
+
+ void setSamples(int samples);
+ int samples() const;
+
+ void setAttachment(QGLFramebufferObject::Attachment attachment);
+ QGLFramebufferObject::Attachment attachment() const;
+
+ void setTextureTarget(GLenum target);
+ GLenum textureTarget() const;
+
+ void setInternalFormat(GLenum internalFormat);
+ GLenum internalFormat() const;
+
+private:
+ QGLFramebufferObjectFormatPrivate *d;
+};
+
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp
index 5f74f26..6a207c8 100644
--- a/src/opengl/qglpixelbuffer.cpp
+++ b/src/opengl/qglpixelbuffer.cpp
@@ -81,13 +81,15 @@
#include <private/qglpixelbuffer_p.h>
#include <qimage.h>
-#if !defined(QT_OPENGL_ES_2)
+#if 1 || defined(QT_OPENGL_ES_2)
+#include <private/qpaintengineex_opengl2_p.h>
+#else
#include <private/qpaintengine_opengl_p.h>
#endif
QT_BEGIN_NAMESPACE
-#if !defined(QT_OPENGL_ES_2)
+#if 0 && !defined(QT_OPENGL_ES_2)
extern void qgl_cleanup_glyph_cache(QGLContext *);
#else
void qgl_cleanup_glyph_cache(QGLContext *) {}
@@ -363,7 +365,9 @@ bool QGLPixelBuffer::isValid() const
return !d->invalid;
}
-#if !defined(QT_OPENGL_ES_2)
+#if 1 || defined(QT_OPENGL_ES_2)
+Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_buffer_paintengine)
+#else
Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_paintengine)
#endif
diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp
index 4b811e5..87abf60 100644
--- a/src/opengl/qglpixmapfilter.cpp
+++ b/src/opengl/qglpixmapfilter.cpp
@@ -118,7 +118,18 @@ QPixmapFilter *QGLContextPrivate::createPixmapFilter(int type) const
#if !defined(QT_OPENGL_ES_2)
extern void qt_add_rect_to_array(const QRectF &r, q_vertexType *array);
-extern void qt_add_texcoords_to_array(qreal x1, qreal y1, qreal x2, qreal y2, q_vertexType *array);
+//extern void qt_add_texcoords_to_array(qreal x1, qreal y1, qreal x2, qreal y2, q_vertexType *array);
+void qt_add_texcoords_to_array(qreal x1, qreal y1, qreal x2, qreal y2, q_vertexType *array)
+{
+ array[0] = f2vt(x1);
+ array[1] = f2vt(y1);
+ array[2] = f2vt(x2);
+ array[3] = f2vt(y1);
+ array[4] = f2vt(x2);
+ array[5] = f2vt(y2);
+ array[6] = f2vt(x1);
+ array[7] = f2vt(y2);
+}
#endif
static void qgl_drawTexture(const QRectF &rect, int tx_width, int tx_height, const QRectF & src)
diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp
index 77ff9fb..612168e 100644
--- a/src/opengl/qpaintengine_opengl.cpp
+++ b/src/opengl/qpaintengine_opengl.cpp
@@ -57,13 +57,11 @@
#include "qpen.h"
#include "qvarlengtharray.h"
#include <private/qpainter_p.h>
-#include <qglpixelbuffer.h>
#include <private/qglpixelbuffer_p.h>
#include <private/qbezier_p.h>
#include <qglframebufferobject.h>
#include "private/qtessellator_p.h"
-#include "private/qwindowsurface_gl_p.h"
#include "util/fragmentprograms_p.h"
@@ -190,180 +188,6 @@ const QGLTrapezoid QGLTrapezoid::translated(const QPointF &delta) const
return trap;
}
-class QGLDrawable {
-public:
- QGLDrawable() : widget(0), buffer(0), fbo(0)
- , wsurf(0)
- {}
- inline void setDevice(QPaintDevice *pdev);
- inline void swapBuffers();
- inline void makeCurrent();
- inline void doneCurrent();
- inline QSize size() const;
- inline QGLFormat format() const;
- inline GLuint bindTexture(const QImage &image, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA);
- inline GLuint bindTexture(const QPixmap &pixmap, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA);
- inline QColor backgroundColor() const;
- inline QGLContext *context() const;
- inline bool autoFillBackground() const;
-
-private:
- bool wasBound;
- QGLWidget *widget;
- QGLPixelBuffer *buffer;
- QGLFramebufferObject *fbo;
-#ifdef Q_WS_QWS
- QWSGLWindowSurface *wsurf;
-#else
- QGLWindowSurface *wsurf;
-#endif
-};
-
-void QGLDrawable::setDevice(QPaintDevice *pdev)
-{
- wasBound = false;
- widget = 0;
- buffer = 0;
- fbo = 0;
-#ifdef Q_WS_QWS
- wsurf = 0;
-#endif
- if (pdev->devType() == QInternal::Widget)
- widget = static_cast<QGLWidget *>(pdev);
- else if (pdev->devType() == QInternal::Pbuffer)
- buffer = static_cast<QGLPixelBuffer *>(pdev);
- else if (pdev->devType() == QInternal::FramebufferObject)
- fbo = static_cast<QGLFramebufferObject *>(pdev);
- else if (pdev->devType() == QInternal::UnknownDevice)
-#ifdef Q_WS_QWS
- wsurf = static_cast<QWSGLPaintDevice*>(pdev)->windowSurface();
-#else
- wsurf = static_cast<QGLWindowSurface *>(pdev);
-#endif
-}
-
-inline void QGLDrawable::swapBuffers()
-{
- if (widget) {
- if (widget->autoBufferSwap())
- widget->swapBuffers();
- } else {
- glFlush();
- }
-}
-
-inline void QGLDrawable::makeCurrent()
-{
- if (widget)
- widget->makeCurrent();
- else if (buffer)
- buffer->makeCurrent();
- else if (wsurf)
- wsurf->context()->makeCurrent();
- else if (fbo) {
- wasBound = fbo->isBound();
- if (!wasBound)
- fbo->bind();
- }
-}
-
-inline void QGLDrawable::doneCurrent()
-{
- if (fbo && !wasBound)
- fbo->release();
-}
-
-inline QSize QGLDrawable::size() const
-{
- if (widget) {
- return QSize(widget->d_func()->glcx->device()->width(),
- widget->d_func()->glcx->device()->height());
- } else if (buffer) {
- return buffer->size();
- } else if (fbo) {
- return fbo->size();
- } else if (wsurf) {
-#ifdef Q_WS_QWS
- return wsurf->window()->frameSize();
-#else
- return QSize(wsurf->width(), wsurf->height());
-#endif
- }
- return QSize();
-}
-
-inline QGLFormat QGLDrawable::format() const
-{
- if (widget)
- return widget->format();
- else if (buffer)
- return buffer->format();
- else if (wsurf)
- return wsurf->context()->format();
- else if (fbo && QGLContext::currentContext()) {
- QGLFormat fmt = QGLContext::currentContext()->format();
- fmt.setStencil(fbo->attachment() == QGLFramebufferObject::CombinedDepthStencil);
- fmt.setDepth(fbo->attachment() != QGLFramebufferObject::NoAttachment);
- return fmt;
- }
-
- return QGLFormat();
-}
-
-inline GLuint QGLDrawable::bindTexture(const QImage &image, GLenum target, GLint format)
-{
- if (widget)
- return widget->d_func()->glcx->d_func()->bindTexture(image, target, format, true);
- else if (buffer)
- return buffer->d_func()->qctx->d_func()->bindTexture(image, target, format, true);
- else if (fbo && QGLContext::currentContext())
- return const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(image, target, format, true);
- else if (wsurf)
- return wsurf->context()->d_func()->bindTexture(image, target, format, true);
- return 0;
-}
-
-inline GLuint QGLDrawable::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
-{
- if (widget)
- return widget->d_func()->glcx->d_func()->bindTexture(pixmap, target, format, true);
- else if (buffer)
- return buffer->d_func()->qctx->d_func()->bindTexture(pixmap, target, format, true);
- else if (fbo && QGLContext::currentContext())
- return const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(pixmap, target, format, true);
- else if (wsurf)
- return wsurf->context()->d_func()->bindTexture(pixmap, target, format, true);
- return 0;
-}
-
-inline QColor QGLDrawable::backgroundColor() const
-{
- if (widget)
- return widget->palette().brush(widget->backgroundRole()).color();
- return QApplication::palette().brush(QPalette::Background).color();
-}
-
-inline QGLContext *QGLDrawable::context() const
-{
- if (widget)
- return widget->d_func()->glcx;
- else if (buffer)
- return buffer->d_func()->qctx;
- else if (fbo)
- return const_cast<QGLContext *>(QGLContext::currentContext());
- else if (wsurf)
- return wsurf->context();
- return 0;
-}
-
-inline bool QGLDrawable::autoFillBackground() const
-{
- if (widget)
- return widget->autoFillBackground();
- else
- return false;
-}
-
class QOpenGLImmediateModeTessellator;
class QGLMaskGenerator;
diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp
index b079557..1fa5b47 100644
--- a/src/opengl/qpixmapdata_gl.cpp
+++ b/src/opengl/qpixmapdata_gl.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qpixmap.h"
+#include "qglframebufferobject.h"
#include <private/qpaintengine_raster_p.h>
@@ -48,6 +49,12 @@
#include <private/qgl_p.h>
#include <private/qdrawhelper_p.h>
+#if 1 || defined(QT_OPENGL_ES_2)
+#include <private/qpaintengineex_opengl2_p.h>
+#else
+#include <private/qpaintengine_opengl_p.h>
+#endif
+
QT_BEGIN_NAMESPACE
extern QGLWidget* qt_gl_share_widget();
@@ -57,12 +64,14 @@ class QGLShareContextScope
public:
QGLShareContextScope(const QGLContext *ctx)
: m_oldContext(0)
- , m_ctx(const_cast<QGLContext *>(ctx))
{
- const QGLContext *currentContext = QGLContext::currentContext();
+ QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
if (currentContext != ctx && !qgl_share_reg()->checkSharing(ctx, currentContext)) {
- m_oldContext = const_cast<QGLContext *>(currentContext);
+ m_oldContext = currentContext;
+ m_ctx = const_cast<QGLContext *>(ctx);
m_ctx->makeCurrent();
+ } else {
+ m_ctx = currentContext;
}
}
@@ -87,47 +96,16 @@ private:
QGLContext *m_ctx;
};
-void qt_gl_convertFromGLImage(QImage *img)
-{
- const int w = img->width();
- const int h = img->height();
-
- if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
- uint *p = (uint*)img->bits();
- uint *end = p + w*h;
-
- while (p < end) {
- uint a = *p << 24;
- *p = (*p >> 8) | a;
- p++;
- }
-
- *img = img->mirrored();
- } else {
- // mirror image
- uint *data = (uint *)img->bits();
-
- const int mid = h/2;
-
- for (int y = 0; y < mid; ++y) {
- uint *p = data + y * w;
- uint *end = p + w;
- uint *q = data + (h - y - 1) * w;
-
- while (p < end)
- qSwap(*p++, *q++);
- }
- }
-}
-
-
static int qt_gl_pixmap_serial = 0;
QGLPixmapData::QGLPixmapData(PixelType type)
: QPixmapData(type, OpenGLClass)
, m_width(0)
, m_height(0)
- , m_texture(0)
+ , m_renderFbo(0)
+ , m_textureId(0)
+ , m_engine(0)
+ , m_ctx(0)
, m_dirty(false)
{
setSerialNumber(++qt_gl_pixmap_serial);
@@ -135,10 +113,11 @@ QGLPixmapData::QGLPixmapData(PixelType type)
QGLPixmapData::~QGLPixmapData()
{
- if (m_texture && qt_gl_share_widget()) {
- QGLShareContextScope ctx(qt_gl_share_widget()->context());
- glDeleteTextures(1, &m_texture);
- }
+ QGLWidget *shareWidget = qt_gl_share_widget();
+ if (!shareWidget)
+ return;
+ QGLShareContextScope ctx(shareWidget->context());
+ glDeleteTextures(1, &m_textureId);
}
bool QGLPixmapData::isValid() const
@@ -148,6 +127,9 @@ bool QGLPixmapData::isValid() const
bool QGLPixmapData::isValidContext(const QGLContext *ctx) const
{
+ if (ctx == m_ctx)
+ return true;
+
const QGLContext *share_ctx = qt_gl_share_widget()->context();
return ctx == share_ctx || qgl_share_reg()->checkSharing(ctx, share_ctx);
}
@@ -160,6 +142,12 @@ void QGLPixmapData::resize(int width, int height)
m_width = width;
m_height = height;
+ if (m_textureId) {
+ QGLShareContextScope ctx(qt_gl_share_widget()->context());
+ glDeleteTextures(1, &m_textureId);
+ m_textureId = 0;
+ }
+
m_source = QImage();
m_dirty = isValid();
setSerialNumber(++qt_gl_pixmap_serial);
@@ -173,28 +161,35 @@ void QGLPixmapData::ensureCreated() const
m_dirty = false;
QGLShareContextScope ctx(qt_gl_share_widget()->context());
+ m_ctx = ctx;
const GLenum format = qt_gl_preferredTextureFormat();
const GLenum target = qt_gl_preferredTextureTarget();
- if (!m_texture)
- glGenTextures(1, &m_texture);
-
- glBindTexture(target, m_texture);
+ if (!m_textureId) {
+ glGenTextures(1, &m_textureId);
+ glBindTexture(target, m_textureId);
+ glTexImage2D(target, 0, GL_RGBA, m_width, m_height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, 0);
+ }
- if (m_source.isNull()) {
- glTexImage2D(target, 0, GL_RGBA, m_width, m_height, 0, format, GL_UNSIGNED_BYTE, 0);
- } else {
+ if (!m_source.isNull()) {
const QImage tx = ctx->d_func()->convertToGLFormat(m_source, true, format);
- glBindTexture(target, m_texture);
- glTexImage2D(target, 0, GL_RGBA, m_width, m_height, 0, format,
- GL_UNSIGNED_BYTE, tx.bits());
+ glBindTexture(target, m_textureId);
+ glTexSubImage2D(target, 0, 0, 0, m_width, m_height, format,
+ GL_UNSIGNED_BYTE, tx.bits());
- m_source = QImage();
+ if (useFramebufferObjects())
+ m_source = QImage();
}
}
+QGLFramebufferObject *QGLPixmapData::fbo() const
+{
+ return m_renderFbo;
+}
+
void QGLPixmapData::fromImage(const QImage &image,
Qt::ImageConversionFlags)
{
@@ -213,6 +208,17 @@ bool QGLPixmapData::scroll(int dx, int dy, const QRect &rect)
return false;
}
+void QGLPixmapData::copy(const QPixmapData *data, const QRect &rect)
+{
+ if (data->classId() != QPixmapData::OpenGLClass) {
+ QPixmapData::copy(data, rect);
+ return;
+ }
+
+ // can be optimized to do a framebuffer blit or similar ...
+ QPixmapData::copy(data, rect);
+}
+
void QGLPixmapData::fill(const QColor &color)
{
if (!isValid())
@@ -239,29 +245,108 @@ QImage QGLPixmapData::toImage() const
if (!isValid())
return QImage();
- if (!m_source.isNull())
+ if (m_renderFbo)
+ copyBackFromRenderFbo(true);
+ else if (!m_source.isNull())
return m_source;
else if (m_dirty)
return QImage(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
+ else
+ ensureCreated();
+
+ QGLShareContextScope ctx(qt_gl_share_widget()->context());
+ extern QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha);
+ glBindTexture(qt_gl_preferredTextureTarget(), m_textureId);
+ return qt_gl_read_texture(QSize(m_width, m_height), true, true);
+}
+
+struct TextureBuffer
+{
+ QGLFramebufferObject *fbo;
+ QGL2PaintEngineEx *engine;
+};
+
+static QVector<TextureBuffer> textureBufferStack;
+static int currentTextureBuffer = 0;
+
+void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const
+{
+ if (!isValid())
+ return;
+
+ const QGLContext *share_ctx = qt_gl_share_widget()->context();
+ QGLShareContextScope ctx(share_ctx);
ensureCreated();
- QGLShareContextScope ctx(qt_gl_share_widget()->context());
- QImage img(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
+ if (!ctx->d_ptr->fbo)
+ glGenFramebuffersEXT(1, &ctx->d_ptr->fbo);
- GLenum format = qt_gl_preferredTextureFormat();
- GLenum target = qt_gl_preferredTextureTarget();
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->d_ptr->fbo);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ qt_gl_preferredTextureTarget(), m_textureId, 0);
- glBindTexture(target, m_texture);
-#ifndef QT_OPENGL_ES
- glGetTexImage(target, 0, format, GL_UNSIGNED_BYTE, img.bits());
-#else
- // XXX - cannot download textures this way on OpenGL/ES.
-#endif
+ const int x0 = 0;
+ const int x1 = m_width;
+ const int y0 = 0;
+ const int y1 = m_height;
+
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_renderFbo->handle());
- qt_gl_convertFromGLImage(&img);
+ glDisable(GL_SCISSOR_TEST);
- return img;
+ glBlitFramebufferEXT(x0, y0, x1, y1,
+ x0, y0, x1, y1,
+ GL_COLOR_BUFFER_BIT,
+ GL_NEAREST);
+
+ if (keepCurrentFboBound)
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
+}
+
+void QGLPixmapData::swapBuffers()
+{
+ if (!isValid())
+ return;
+
+ copyBackFromRenderFbo(false);
+ m_renderFbo->release();
+
+ --currentTextureBuffer;
+
+ m_renderFbo = 0;
+ m_engine = 0;
+}
+
+void QGLPixmapData::makeCurrent()
+{
+ if (isValid() && m_renderFbo)
+ m_renderFbo->bind();
+}
+
+void QGLPixmapData::doneCurrent()
+{
+ if (isValid() && m_renderFbo)
+ m_renderFbo->release();
+}
+
+static TextureBuffer createTextureBuffer(const QSize &size, QGL2PaintEngineEx *engine = 0)
+{
+ TextureBuffer buffer;
+ QGLFramebufferObjectFormat fmt;
+ fmt.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ fmt.setSamples(4);
+
+ buffer.fbo = new QGLFramebufferObject(size, fmt);
+ buffer.engine = engine ? engine : new QGL2PaintEngineEx;
+
+ return buffer;
+}
+
+bool QGLPixmapData::useFramebufferObjects()
+{
+ return QGLFramebufferObject::hasOpenGLFramebufferObjects()
+ && QGLFramebufferObject::hasOpenGLFramebufferBlit();
}
QPaintEngine* QGLPixmapData::paintEngine() const
@@ -269,23 +354,62 @@ QPaintEngine* QGLPixmapData::paintEngine() const
if (!isValid())
return 0;
- m_source = toImage();
- m_dirty = true;
+ if (m_engine)
+ return m_engine;
+ else if (!useFramebufferObjects()) {
+ m_dirty = true;
+
+ if (m_source.size() != size())
+ m_source = QImage(size(), QImage::Format_ARGB32_Premultiplied);
+ return m_source.paintEngine();
+ }
+
+ extern QGLWidget* qt_gl_share_widget();
+
+ if (!QGLContext::currentContext())
+ qt_gl_share_widget()->makeCurrent();
+ QGLShareContextScope ctx(qt_gl_share_widget()->context());
- return m_source.paintEngine();
+ if (textureBufferStack.size() <= currentTextureBuffer) {
+ textureBufferStack << createTextureBuffer(size());
+ } else {
+ QSize sz = textureBufferStack.at(currentTextureBuffer).fbo->size();
+ if (sz.width() < m_width || sz.height() < m_height) {
+ if (sz.width() < m_width)
+ sz.setWidth(qMax(m_width, qRound(sz.width() * 1.5)));
+ if (sz.height() < m_height)
+ sz.setHeight(qMax(m_height, qRound(sz.height() * 1.5)));
+ delete textureBufferStack.at(currentTextureBuffer).fbo;
+ textureBufferStack[currentTextureBuffer] =
+ createTextureBuffer(sz, textureBufferStack.at(currentTextureBuffer).engine);
+ qDebug() << "Creating new pixmap texture buffer:" << sz;
+ }
+ }
+
+ m_renderFbo = textureBufferStack.at(currentTextureBuffer).fbo;
+ m_engine = textureBufferStack.at(currentTextureBuffer).engine;
+
+ ++currentTextureBuffer;
+
+ return m_engine;
}
-GLuint QGLPixmapData::bind() const
+GLuint QGLPixmapData::bind(bool copyBack) const
{
- ensureCreated();
- glBindTexture(qt_gl_preferredTextureTarget(), m_texture);
- return m_texture;
+ if (m_renderFbo && copyBack)
+ copyBackFromRenderFbo(true);
+ else
+ ensureCreated();
+
+ GLuint id = m_textureId;
+ glBindTexture(qt_gl_preferredTextureTarget(), id);
+ return id;
}
GLuint QGLPixmapData::textureId() const
{
ensureCreated();
- return m_texture;
+ return m_textureId;
}
extern int qt_defaultDpiX();
diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h
index e450f01..536f33d 100644
--- a/src/opengl/qpixmapdata_gl_p.h
+++ b/src/opengl/qpixmapdata_gl_p.h
@@ -60,6 +60,7 @@
QT_BEGIN_NAMESPACE
class QPaintEngine;
+class QGLFramebufferObject;
class QGLPixmapData : public QPixmapData
{
@@ -72,6 +73,7 @@ public:
void resize(int width, int height);
void fromImage(const QImage &image,
Qt::ImageConversionFlags flags);
+ void copy(const QPixmapData *data, const QRect &rect);
bool scroll(int dx, int dy, const QRect &rect);
@@ -80,13 +82,25 @@ public:
QImage toImage() const;
QPaintEngine* paintEngine() const;
- GLuint bind() const;
+ GLuint bind(bool copyBack = true) const;
GLuint textureId() const;
bool isValidContext(const QGLContext *ctx) const;
void ensureCreated() const;
+ bool isUninitialized() const { return m_dirty && m_source.isNull(); }
+
+ QSize size() const { return QSize(m_width, m_height); }
+ int width() const { return m_width; }
+ int height() const { return m_height; }
+
+ QGLFramebufferObject *fbo() const;
+
+ void makeCurrent();
+ void doneCurrent();
+ void swapBuffers();
+
protected:
int metric(QPaintDevice::PaintDeviceMetric metric) const;
@@ -94,10 +108,17 @@ private:
QGLPixmapData(const QGLPixmapData &other);
QGLPixmapData &operator=(const QGLPixmapData &other);
+ void copyBackFromRenderFbo(bool keepCurrentFboBound) const;
+
+ static bool useFramebufferObjects();
+
int m_width;
int m_height;
- mutable GLuint m_texture;
+ mutable QGLFramebufferObject *m_renderFbo;
+ mutable uint m_textureId;
+ mutable QPaintEngine *m_engine;
+ mutable QGLContext *m_ctx;
mutable bool m_dirty;
mutable QImage m_source;
};
diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp
index b41adf9..d92241d 100644
--- a/src/opengl/qwindowsurface_gl.cpp
+++ b/src/opengl/qwindowsurface_gl.cpp
@@ -69,7 +69,11 @@
#include <private/qglpixelbuffer_p.h>
#include <private/qgraphicssystem_gl_p.h>
+#if 1 || defined(QT_OPENGL_ES_2)
+#include <private/qpaintengineex_opengl2_p.h>
+#else
#include <private/qpaintengine_opengl_p.h>
+#endif
#ifndef GLX_ARB_multisample
#define GLX_SAMPLE_BUFFERS_ARB 100000
@@ -100,8 +104,8 @@ QGLGraphicsSystem::QGLGraphicsSystem()
int i = 0;
int spec[16];
spec[i++] = GLX_RGBA;
-#if 0
spec[i++] = GLX_DOUBLEBUFFER;
+#if 0
spec[i++] = GLX_DEPTH_SIZE;
spec[i++] = 8;
spec[i++] = GLX_STENCIL_SIZE;
@@ -187,9 +191,10 @@ public:
}
void cleanup() {
- delete widget;
- widget = 0;
+ QGLWidget *w = widget;
cleanedUp = true;
+ widget = 0;
+ delete w;
}
static bool cleanedUp;
@@ -287,7 +292,9 @@ void QGLWindowSurface::hijackWindow(QWidget *widget)
qDebug() << "hijackWindow() context created for" << widget << d_ptr->contexts.size();
}
-#if !defined(QT_OPENGL_ES_2)
+#if 1 || defined(QT_OPENGL_ES_2)
+Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_window_surface_paintengine)
+#else
Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_window_surface_paintengine)
#endif
@@ -313,6 +320,8 @@ QGLContext *QGLWindowSurface::context() const
QPaintDevice *QGLWindowSurface::paintDevice()
{
+ updateGeometry();
+
if (d_ptr->pb)
return d_ptr->pb;
@@ -328,6 +337,7 @@ static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize,
void QGLWindowSurface::beginPaint(const QRegion &)
{
+ updateGeometry();
}
void QGLWindowSurface::endPaint(const QRegion &rgn)
@@ -427,40 +437,64 @@ void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &
size = parent->size();
}
- ctx->makeCurrent();
+ glDisable(GL_SCISSOR_TEST);
+
+ if (d_ptr->fbo && QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit) {
+ const int h = d_ptr->fbo->height();
+
+ const int x0 = rect.left();
+ const int x1 = rect.left() + rect.width();
+ const int y0 = h - (rect.top() + rect.height());
+ const int y1 = h - rect.top();
+
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
+
+ glBlitFramebufferEXT(x0, y0, x1, y1,
+ x0, y0, x1, y1,
+ GL_COLOR_BUFFER_BIT,
+ GL_NEAREST);
+
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, d_ptr->fbo->handle());
+ } else {
+ glDisable(GL_DEPTH_TEST);
+
+ if (d_ptr->fbo) {
+ d_ptr->fbo->release();
+ } else {
+ ctx->makeCurrent();
#ifdef Q_WS_MAC
- ctx->updatePaintDevice();
+ ctx->updatePaintDevice();
#endif
- if (d_ptr->fbo)
- d_ptr->fbo->release();
+ }
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
#ifndef QT_OPENGL_ES
- glOrtho(0, size.width(), size.height(), 0, -999999, 999999);
+ glOrtho(0, size.width(), size.height(), 0, -999999, 999999);
#else
- glOrthof(0, size.width(), size.height(), 0, -999999, 999999);
+ glOrthof(0, size.width(), size.height(), 0, -999999, 999999);
#endif
- glViewport(0, 0, size.width(), size.height());
+ glViewport(0, 0, size.width(), size.height());
- glColor4f(1, 1, 1, 1);
- drawTexture(rect, texture, window()->size(), br);
+ glColor4f(1, 1, 1, 1);
+ drawTexture(rect, texture, window()->size(), br);
+
+ if (d_ptr->fbo)
+ d_ptr->fbo->bind();
+ }
if (ctx->format().doubleBuffer())
ctx->swapBuffers();
else
glFlush();
-
- if (d_ptr->fbo)
- d_ptr->fbo->bind();
}
-void QGLWindowSurface::setGeometry(const QRect &rect)
+void QGLWindowSurface::updateGeometry()
{
- QWindowSurface::setGeometry(rect);
+ QRect rect = QWindowSurface::geometry();
const GLenum target = qt_gl_preferredTextureTarget();
@@ -479,6 +513,35 @@ void QGLWindowSurface::setGeometry(const QRect &rect)
return;
}
+ if ((QGLExtensions::glExtensions & QGLExtensions::FramebufferObject) && (d_ptr->fbo || !d_ptr->tried_fbo)) {
+ d_ptr->tried_fbo = true;
+ hijackWindow(window());
+ QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
+ ctx->d_ptr->internal_context = true;
+ ctx->makeCurrent();
+ delete d_ptr->fbo;
+
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ format.setInternalFormat(GL_RGBA);
+ format.setTextureTarget(target);
+
+ if (QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit)
+ format.setSamples(8);
+
+ d_ptr->fbo = new QGLFramebufferObject(rect.size(), format);
+ d_ptr->fbo->bind();
+ if (d_ptr->fbo->isValid()) {
+ qDebug() << "Created Window Surface FBO" << rect.size()
+ << "with samples" << d_ptr->fbo->format().samples();
+ return;
+ } else {
+ qDebug() << "QGLWindowSurface: Failed to create valid FBO, falling back";
+ delete d_ptr->fbo;
+ d_ptr->fbo = 0;
+ }
+ }
+
if (d_ptr->pb || !d_ptr->tried_pb) {
d_ptr->tried_pb = true;
@@ -494,7 +557,7 @@ void QGLWindowSurface::setGeometry(const QRect &rect)
qt_gl_share_widget());
if (d_ptr->pb->isValid()) {
- qDebug() << "PB Sample buffers:" << d_ptr->pb->format().sampleBuffers();
+ qDebug() << "Created Window Surface Pixelbuffer, Sample buffers:" << d_ptr->pb->format().sampleBuffers();
d_ptr->pb->makeCurrent();
glGenTextures(1, &d_ptr->pb_tex_id);
@@ -522,25 +585,6 @@ void QGLWindowSurface::setGeometry(const QRect &rect)
}
}
- if ((QGLExtensions::glExtensions & QGLExtensions::FramebufferObject) && (d_ptr->fbo || !d_ptr->tried_fbo)) {
- d_ptr->tried_fbo = true;
- hijackWindow(window());
- QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
- ctx->d_ptr->internal_context = true;
- ctx->makeCurrent();
- delete d_ptr->fbo;
- d_ptr->fbo = new QGLFramebufferObject(rect.size(), QGLFramebufferObject::CombinedDepthStencil,
- GLenum(target), GLenum(GL_RGBA));
-
- d_ptr->fbo->bind();
- if (d_ptr->fbo->isValid()) {
- return;
- } else {
- qDebug() << "QGLWindowSurface: Failed to create valid FBO, falling back";
- delete d_ptr->fbo;
- d_ptr->fbo = 0;
- }
- }
hijackWindow(window());
QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
@@ -559,6 +603,11 @@ void QGLWindowSurface::setGeometry(const QRect &rect)
d_ptr->ctx->d_ptr->internal_context = true;
}
+void QGLWindowSurface::setGeometry(const QRect &rect)
+{
+ QWindowSurface::setGeometry(rect);
+}
+
bool QGLWindowSurface::scroll(const QRegion &area, int dx, int dy)
{
// this code randomly fails currently for unknown reasons
diff --git a/src/opengl/qwindowsurface_gl_p.h b/src/opengl/qwindowsurface_gl_p.h
index 0194378..d47e3e3 100644
--- a/src/opengl/qwindowsurface_gl_p.h
+++ b/src/opengl/qwindowsurface_gl_p.h
@@ -74,6 +74,7 @@ public:
QPaintDevice *paintDevice();
void flush(QWidget *widget, const QRegion &region, const QPoint &offset);
void setGeometry(const QRect &rect);
+ void updateGeometry();
bool scroll(const QRegion &area, int dx, int dy);
void beginPaint(const QRegion &region);