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.cpp108
-rw-r--r--src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h27
-rw-r--r--src/opengl/gl2paintengineex/qglcustomshaderstage.cpp138
-rw-r--r--src/opengl/gl2paintengineex/qglcustomshaderstage_p.h (renamed from src/opengl/qglpaintdevice_qws.cpp)83
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager.cpp723
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager_p.h499
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadersource_p.h476
-rw-r--r--src/opengl/gl2paintengineex/qglgradientcache.cpp54
-rw-r--r--src/opengl/gl2paintengineex/qglgradientcache_p.h33
-rw-r--r--src/opengl/gl2paintengineex/qglpexshadermanager.cpp450
-rw-r--r--src/opengl/gl2paintengineex/qglpexshadermanager_p.h156
-rw-r--r--src/opengl/gl2paintengineex/qglshader.cpp605
-rw-r--r--src/opengl/gl2paintengineex/qglshader_p.h260
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp2240
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h212
-rw-r--r--src/opengl/gl2paintengineex/qtriangulatingstroker.cpp555
-rw-r--r--src/opengl/gl2paintengineex/qtriangulatingstroker_p.h156
-rw-r--r--src/opengl/opengl.pro105
-rw-r--r--src/opengl/qegl.cpp787
-rw-r--r--src/opengl/qegl_p.h188
-rw-r--r--src/opengl/qegl_qws.cpp126
-rw-r--r--src/opengl/qegl_wince.cpp105
-rw-r--r--src/opengl/qegl_x11egl.cpp130
-rw-r--r--src/opengl/qgl.cpp2132
-rw-r--r--src/opengl/qgl.h65
-rw-r--r--src/opengl/qgl_egl.cpp118
-rw-r--r--src/opengl/qgl_egl_p.h2
-rw-r--r--src/opengl/qgl_mac.mm11
-rw-r--r--src/opengl/qgl_p.h400
-rw-r--r--src/opengl/qgl_qws.cpp183
-rw-r--r--src/opengl/qgl_win.cpp32
-rw-r--r--src/opengl/qgl_wince.cpp123
-rw-r--r--src/opengl/qgl_x11.cpp428
-rw-r--r--src/opengl/qgl_x11egl.cpp644
-rw-r--r--src/opengl/qglcolormap.cpp32
-rw-r--r--src/opengl/qglextensions.cpp355
-rw-r--r--src/opengl/qglextensions_p.h544
-rw-r--r--src/opengl/qglframebufferobject.cpp805
-rw-r--r--src/opengl/qglframebufferobject.h53
-rw-r--r--src/opengl/qglframebufferobject_p.h153
-rw-r--r--src/opengl/qglpaintdevice.cpp224
-rw-r--r--src/opengl/qglpaintdevice_p.h112
-rw-r--r--src/opengl/qglpixelbuffer.cpp68
-rw-r--r--src/opengl/qglpixelbuffer.h4
-rw-r--r--src/opengl/qglpixelbuffer_egl.cpp76
-rw-r--r--src/opengl/qglpixelbuffer_p.h15
-rw-r--r--src/opengl/qglpixelbuffer_x11.cpp31
-rw-r--r--src/opengl/qglpixmapfilter.cpp717
-rw-r--r--src/opengl/qglpixmapfilter_p.h29
-rw-r--r--src/opengl/qglshaderprogram.cpp2983
-rw-r--r--src/opengl/qglshaderprogram.h302
-rw-r--r--src/opengl/qglwindowsurface_qws.cpp1
-rw-r--r--src/opengl/qgraphicsshadereffect.cpp314
-rw-r--r--src/opengl/qgraphicsshadereffect_p.h94
-rw-r--r--src/opengl/qgraphicssystem_gl.cpp16
-rw-r--r--src/opengl/qpaintengine_opengl.cpp553
-rw-r--r--src/opengl/qpaintengine_opengl_p.h7
-rw-r--r--src/opengl/qpixmapdata_gl.cpp660
-rw-r--r--src/opengl/qpixmapdata_gl_p.h97
-rw-r--r--src/opengl/qpixmapdata_x11gl_egl.cpp252
-rw-r--r--src/opengl/qpixmapdata_x11gl_p.h86
-rw-r--r--src/opengl/qwindowsurface_gl.cpp510
-rw-r--r--src/opengl/qwindowsurface_gl_p.h22
-rw-r--r--src/opengl/qwindowsurface_x11gl.cpp147
-rw-r--r--src/opengl/qwindowsurface_x11gl_p.h (renamed from src/opengl/qglpaintdevice_qws_p.h)40
-rw-r--r--src/opengl/util/composition_mode_colorburn.glsl4
-rw-r--r--src/opengl/util/composition_mode_colordodge.glsl4
-rw-r--r--src/opengl/util/composition_mode_darken.glsl2
-rw-r--r--src/opengl/util/composition_mode_difference.glsl2
-rw-r--r--src/opengl/util/composition_mode_exclusion.glsl2
-rw-r--r--src/opengl/util/composition_mode_hardlight.glsl6
-rw-r--r--src/opengl/util/composition_mode_lighten.glsl2
-rw-r--r--src/opengl/util/composition_mode_multiply.glsl2
-rw-r--r--src/opengl/util/composition_mode_overlay.glsl6
-rw-r--r--src/opengl/util/composition_mode_softlight.glsl24
-rw-r--r--src/opengl/util/conical_brush.glsl2
-rw-r--r--src/opengl/util/ellipse.glsl6
-rw-r--r--src/opengl/util/ellipse_aa.glsl56
-rw-r--r--src/opengl/util/ellipse_aa_copy.glsl11
-rw-r--r--src/opengl/util/ellipse_aa_radial.glsl24
-rw-r--r--src/opengl/util/ellipse_functions.glsl63
-rw-r--r--src/opengl/util/fragmentprograms_p.h7331
-rw-r--r--src/opengl/util/generator.cpp56
-rw-r--r--src/opengl/util/generator.pro2
-rw-r--r--src/opengl/util/masks.conf1
-rw-r--r--src/opengl/util/pattern_brush.glsl4
-rw-r--r--src/opengl/util/simple_porter_duff.glsl6
-rw-r--r--src/opengl/util/texture_brush.glsl2
-rw-r--r--src/opengl/util/trap_exact_aa.glsl12
90 files changed, 19415 insertions, 10160 deletions
diff --git a/src/opengl/gl2paintengineex/glgc_shader_source.h b/src/opengl/gl2paintengineex/glgc_shader_source.h
deleted file mode 100644
index 2bf37fd..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).
-** All rights reserved.
-** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
-** this package.
-**
-** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@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 e1757d3..ee1a797 100644
--- a/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp
+++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp
@@ -43,10 +43,12 @@
#include <private/qbezier_p.h>
+QT_BEGIN_NAMESPACE
+
void QGL2PEXVertexArray::clear()
{
vertexArray.reset();
- vertexArrayStops.clear();
+ vertexArrayStops.reset();
boundingRectDirty = true;
}
@@ -59,7 +61,36 @@ QGLRect QGL2PEXVertexArray::boundingRect() const
return QGLRect(minX, minY, maxX, maxY);
}
-void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseScale)
+void QGL2PEXVertexArray::addRect(const QRectF &rect)
+{
+ vertexArray << rect.topLeft() << rect.topRight() << rect.bottomRight()
+ << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
+}
+
+void QGL2PEXVertexArray::addClosingLine(int index)
+{
+ if (QPointF(vertexArray.at(index)) != QPointF(vertexArray.last()))
+ vertexArray.add(vertexArray.at(index));
+}
+
+void QGL2PEXVertexArray::addCentroid(const QVectorPath &path, int subPathIndex)
+{
+ const QPointF *const points = reinterpret_cast<const QPointF *>(path.points());
+ const QPainterPath::ElementType *const elements = path.elements();
+
+ QPointF sum = points[subPathIndex];
+ int count = 1;
+
+ for (int i = subPathIndex + 1; i < path.elementCount() && (!elements || elements[i] != QPainterPath::MoveToElement); ++i) {
+ sum += points[i];
+ ++count;
+ }
+
+ const QPointF centroid = sum / qreal(count);
+ vertexArray.add(centroid);
+}
+
+void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline)
{
const QPointF* const points = reinterpret_cast<const QPointF*>(path.points());
const QPainterPath::ElementType* const elements = path.elements();
@@ -70,6 +101,10 @@ void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseSc
boundingRectDirty = false;
}
+ if (!outline && !path.isConvex())
+ addCentroid(path, 0);
+
+ int lastMoveTo = vertexArray.size();
vertexArray.add(points[0]); // The first element is always a moveTo
do {
@@ -85,29 +120,47 @@ void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseSc
// qDebug("QVectorPath has element types");
for (int i=1; i<path.elementCount(); ++i) {
- const QPainterPath::ElementType elementType = elements[i];
- switch (elementType) {
+ switch (elements[i]) {
case QPainterPath::MoveToElement:
+ if (!outline)
+ addClosingLine(lastMoveTo);
// qDebug("element[%d] is a MoveToElement", i);
- vertexArrayStops.append(vertexArray.size());
- vertexArray.add(points[i]); // Add the moveTo as a new vertex
+ vertexArrayStops.add(vertexArray.size());
+ if (!outline) {
+ if (!path.isConvex()) addCentroid(path, i);
+ lastMoveTo = vertexArray.size();
+ }
+ lineToArray(points[i].x(), points[i].y()); // Add the moveTo as a new vertex
break;
case QPainterPath::LineToElement:
// qDebug("element[%d] is a LineToElement", i);
lineToArray(points[i].x(), points[i].y());
break;
- case QPainterPath::CurveToElement:
-// qDebug("element[%d] is a CurveToElement", i);
- curveToArray(points[i], points[i+1], points[i+2], curveInverseScale);
- i+=2;
- break;
+ case QPainterPath::CurveToElement: {
+ QBezier b = QBezier::fromPoints(*(((const QPointF *) points) + i - 1),
+ points[i],
+ points[i+1],
+ points[i+2]);
+ QRectF bounds = b.bounds();
+ // threshold based on same algorithm as in qtriangulatingstroker.cpp
+ int threshold = qMin<float>(64, qMax(bounds.width(), bounds.height()) * 3.14f / (curveInverseScale * 6));
+ if (threshold < 3) threshold = 3;
+ qreal one_over_threshold_minus_1 = 1.f / (threshold - 1);
+ for (int t=0; t<threshold; ++t) {
+ QPointF pt = b.pointAt(t * one_over_threshold_minus_1);
+ lineToArray(pt.x(), pt.y());
+ }
+ i += 2;
+ break; }
default:
break;
}
}
} while (0);
- vertexArrayStops.append(vertexArray.size());
+ if (!outline)
+ addClosingLine(lastMoveTo);
+ vertexArrayStops.add(vertexArray.size());
}
void QGL2PEXVertexArray::lineToArray(const GLfloat x, const GLfloat y)
@@ -124,33 +177,4 @@ void QGL2PEXVertexArray::lineToArray(const GLfloat x, const GLfloat y)
minY = y;
}
-void QGL2PEXVertexArray::curveToArray(const QGLPoint &cp1, const QGLPoint &cp2, const QGLPoint &ep, GLfloat inverseScale)
-{
- qreal inverseScaleHalf = inverseScale / 2;
-
- QBezier beziers[32];
- beziers[0] = QBezier::fromPoints(vertexArray.last(), cp1, cp2, ep);
- QBezier *b = beziers;
- while (b >= beziers) {
- // check if we can pop the top bezier curve from the stack
- qreal l = qAbs(b->x4 - b->x1) + qAbs(b->y4 - b->y1);
- qreal d;
- if (l > inverseScale) {
- d = qAbs( (b->x4 - b->x1)*(b->y1 - b->y2) - (b->y4 - b->y1)*(b->x1 - b->x2) )
- + qAbs( (b->x4 - b->x1)*(b->y1 - b->y3) - (b->y4 - b->y1)*(b->x1 - b->x3) );
- d /= l;
- } else {
- d = qAbs(b->x1 - b->x2) + qAbs(b->y1 - b->y2) +
- qAbs(b->x1 - b->x3) + qAbs(b->y1 - b->y3);
- }
- if (d < inverseScaleHalf || b == beziers + 31) {
- // good enough, we pop it off and add the endpoint
- lineToArray(b->x4, b->y4);
- --b;
- } else {
- // split, second half of the polygon goes lower into the stack
- b->split(b+1, b);
- ++b;
- }
- }
-}
+QT_END_NAMESPACE
diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h
index 9160780..98eaa91 100644
--- a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h
+++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h
@@ -50,19 +50,24 @@
// We mean it.
//
+#ifndef QGL2PEXVERTEXARRAY_P_H
+#define QGL2PEXVERTEXARRAY_P_H
+
#include <QRectF>
#include <private/qdatabuffer_p.h>
#include <private/qvectorpath_p.h>
#include <private/qgl_p.h>
+QT_BEGIN_NAMESPACE
+
class QGLPoint
{
public:
QGLPoint(GLfloat new_x, GLfloat new_y) :
x(new_x), y(new_y) {};
- QGLPoint(QPointF p) :
+ QGLPoint(const QPointF &p) :
x(p.x()), y(p.y()) {};
QGLPoint(const QPointF* p) :
@@ -77,7 +82,7 @@ public:
struct QGLRect
{
- QGLRect(QRectF r)
+ QGLRect(const QRectF &r)
: left(r.left()), top(r.top()), right(r.right()), bottom(r.bottom()) {}
QGLRect(GLfloat l, GLfloat t, GLfloat r, GLfloat b)
@@ -98,24 +103,32 @@ public:
maxX(-2e10), maxY(-2e10), minX(2e10), minY(2e10),
boundingRectDirty(true) {}
- void addPath(const QVectorPath &path, GLfloat curveInverseScale);
+ void addRect(const QRectF &rect);
+ void addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline = true);
void clear();
QGLPoint* data() {return vertexArray.data();}
- QVector<int>& stops() {return vertexArrayStops;}
+ int *stops() const { return vertexArrayStops.data(); }
+ int stopCount() const { return vertexArrayStops.size(); }
QGLRect boundingRect() const;
+ int vertexCount() const { return vertexArray.size(); }
+
void lineToArray(const GLfloat x, const GLfloat y);
private:
QDataBuffer<QGLPoint> vertexArray;
- QVector<int> vertexArrayStops;
+ QDataBuffer<int> vertexArrayStops;
GLfloat maxX;
GLfloat maxY;
GLfloat minX;
GLfloat minY;
bool boundingRectDirty;
-
- inline void curveToArray(const QGLPoint &cp1, const QGLPoint &cp2, const QGLPoint &ep, GLfloat inverseScale);
+ void addClosingLine(int index);
+ void addCentroid(const QVectorPath &path, int subPathIndex);
};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp b/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp
new file mode 100644
index 0000000..b71a7b7
--- /dev/null
+++ b/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglcustomshaderstage_p.h"
+#include "qglengineshadermanager_p.h"
+#include "qpaintengineex_opengl2_p.h"
+#include <private/qpainter_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGLCustomShaderStagePrivate
+{
+public:
+ QGLCustomShaderStagePrivate() :
+ m_manager(0) {}
+
+ QPointer<QGLEngineShaderManager> m_manager;
+ QByteArray m_source;
+};
+
+
+
+
+QGLCustomShaderStage::QGLCustomShaderStage()
+ : d_ptr(new QGLCustomShaderStagePrivate)
+{
+}
+
+QGLCustomShaderStage::~QGLCustomShaderStage()
+{
+ Q_D(QGLCustomShaderStage);
+ if (d->m_manager) {
+ d->m_manager->removeCustomStage();
+ d->m_manager->sharedShaders->cleanupCustomStage(this);
+ }
+}
+
+void QGLCustomShaderStage::setUniformsDirty()
+{
+ Q_D(QGLCustomShaderStage);
+ if (d->m_manager)
+ d->m_manager->setDirty(); // ### Probably a bit overkill!
+}
+
+bool QGLCustomShaderStage::setOnPainter(QPainter* p)
+{
+ Q_D(QGLCustomShaderStage);
+ if (p->paintEngine()->type() != QPaintEngine::OpenGL2) {
+ qWarning("QGLCustomShaderStage::setOnPainter() - paint engine not OpenGL2");
+ return false;
+ }
+ if (d->m_manager)
+ qWarning("Custom shader is already set on a painter");
+
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx*>(p->paintEngine());
+ d->m_manager = QGL2PaintEngineExPrivate::shaderManagerForEngine(engine);
+ Q_ASSERT(d->m_manager);
+
+ d->m_manager->setCustomStage(this);
+ return true;
+}
+
+void QGLCustomShaderStage::removeFromPainter(QPainter* p)
+{
+ Q_D(QGLCustomShaderStage);
+ if (p->paintEngine()->type() != QPaintEngine::OpenGL2)
+ return;
+
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx*>(p->paintEngine());
+ d->m_manager = QGL2PaintEngineExPrivate::shaderManagerForEngine(engine);
+ Q_ASSERT(d->m_manager);
+
+ // Just set the stage to null, don't call removeCustomStage().
+ // This should leave the program in a compiled/linked state
+ // if the next custom shader stage is this one again.
+ d->m_manager->setCustomStage(0);
+ d->m_manager = 0;
+}
+
+QByteArray QGLCustomShaderStage::source() const
+{
+ Q_D(const QGLCustomShaderStage);
+ return d->m_source;
+}
+
+// Called by the shader manager if another custom shader is attached or
+// the manager is deleted
+void QGLCustomShaderStage::setInactive()
+{
+ Q_D(QGLCustomShaderStage);
+ d->m_manager = 0;
+}
+
+void QGLCustomShaderStage::setSource(const QByteArray& s)
+{
+ Q_D(QGLCustomShaderStage);
+ d->m_source = s;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opengl/qglpaintdevice_qws.cpp b/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h
index 8bb889b..e0033be 100644
--- a/src/opengl/qglpaintdevice_qws.cpp
+++ b/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h
@@ -39,60 +39,55 @@
**
****************************************************************************/
-#include <private/qglpaintdevice_qws_p.h>
-#include <private/qgl_p.h>
-#include <private/qpaintengine_opengl_p.h>
-#include <private/qglwindowsurface_qws_p.h>
+#ifndef QGL_CUSTOM_SHADER_STAGE_H
+#define QGL_CUSTOM_SHADER_STAGE_H
+
+//
+// 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 <QGLShaderProgram>
+
+QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
-class QWSGLPaintDevicePrivate
+QT_MODULE(OpenGL)
+
+class QGLCustomShaderStagePrivate;
+class Q_OPENGL_EXPORT QGLCustomShaderStage
{
+ Q_DECLARE_PRIVATE(QGLCustomShaderStage)
public:
- QWidget *widget;
-};
+ QGLCustomShaderStage();
+ virtual ~QGLCustomShaderStage();
+ virtual void setUniforms(QGLShaderProgram*) {}
-class QMetricAccessor : public QWidget {
-public:
- int metric(PaintDeviceMetric m) {
- return QWidget::metric(m);
- }
-};
+ void setUniformsDirty();
-QWSGLPaintDevice::QWSGLPaintDevice(QWidget *widget) :
- d_ptr(new QWSGLPaintDevicePrivate)
-{
- Q_D(QWSGLPaintDevice);
- d->widget = widget;
-}
+ bool setOnPainter(QPainter*);
+ void removeFromPainter(QPainter*);
+ QByteArray source() const;
-QWSGLPaintDevice::~QWSGLPaintDevice()
-{
- Q_D(QWSGLPaintDevice);
- delete d;
-}
+ void setInactive();
+protected:
+ void setSource(const QByteArray&);
-QPaintEngine* QWSGLPaintDevice::paintEngine() const
-{
-#if !defined(QT_OPENGL_ES_2)
- return qt_qgl_paint_engine();
-#else
- return 0; // XXX
-#endif
-}
+private:
+ QGLCustomShaderStagePrivate* d_ptr;
+};
-int QWSGLPaintDevice::metric(PaintDeviceMetric m) const
-{
- Q_D(const QWSGLPaintDevice);
- Q_ASSERT(d->widget);
- return ((QMetricAccessor *) d->widget)->metric(m);
-}
+QT_END_NAMESPACE
-QWSGLWindowSurface* QWSGLPaintDevice::windowSurface() const
-{
- Q_D(const QWSGLPaintDevice);
- return static_cast<QWSGLWindowSurface*>(d->widget->windowSurface());
-}
+QT_END_HEADER
-QT_END_NAMESPACE
+
+#endif
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
new file mode 100644
index 0000000..9d545b9
--- /dev/null
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
@@ -0,0 +1,723 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglengineshadermanager_p.h"
+#include "qglengineshadersource_p.h"
+
+#if defined(QT_DEBUG)
+#include <QMetaEnum>
+#endif
+
+
+QT_BEGIN_NAMESPACE
+
+static void qt_shared_shaders_free(void *data)
+{
+ delete reinterpret_cast<QGLEngineSharedShaders *>(data);
+}
+
+Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_shared_shaders, (qt_shared_shaders_free))
+
+QGLEngineSharedShaders *QGLEngineSharedShaders::shadersForContext(const QGLContext *context)
+{
+ QGLEngineSharedShaders *p = reinterpret_cast<QGLEngineSharedShaders *>(qt_shared_shaders()->value(context));
+ if (!p) {
+ QGLShareContextScope scope(context);
+ qt_shared_shaders()->insert(context, p = new QGLEngineSharedShaders(context));
+ }
+ return p;
+}
+
+const char* QGLEngineSharedShaders::qShaderSnippets[] = {
+ 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
+};
+
+QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
+ : ctxGuard(context)
+ , blitShaderProg(0)
+ , simpleShaderProg(0)
+{
+
+/*
+ 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 snippetsPopulated = false;
+ if (!snippetsPopulated) {
+
+ const char** code = qShaderSnippets; // shortcut
+
+ code[MainVertexShader] = qglslMainVertexShader;
+ code[MainWithTexCoordsVertexShader] = qglslMainWithTexCoordsVertexShader;
+ code[MainWithTexCoordsAndOpacityVertexShader] = qglslMainWithTexCoordsAndOpacityVertexShader;
+
+ code[UntransformedPositionVertexShader] = qglslUntransformedPositionVertexShader;
+ code[PositionOnlyVertexShader] = qglslPositionOnlyVertexShader;
+ code[PositionWithPatternBrushVertexShader] = qglslPositionWithPatternBrushVertexShader;
+ code[PositionWithLinearGradientBrushVertexShader] = qglslPositionWithLinearGradientBrushVertexShader;
+ code[PositionWithConicalGradientBrushVertexShader] = qglslPositionWithConicalGradientBrushVertexShader;
+ code[PositionWithRadialGradientBrushVertexShader] = qglslPositionWithRadialGradientBrushVertexShader;
+ code[PositionWithTextureBrushVertexShader] = qglslPositionWithTextureBrushVertexShader;
+ code[AffinePositionWithPatternBrushVertexShader] = qglslAffinePositionWithPatternBrushVertexShader;
+ code[AffinePositionWithLinearGradientBrushVertexShader] = qglslAffinePositionWithLinearGradientBrushVertexShader;
+ code[AffinePositionWithConicalGradientBrushVertexShader] = qglslAffinePositionWithConicalGradientBrushVertexShader;
+ code[AffinePositionWithRadialGradientBrushVertexShader] = qglslAffinePositionWithRadialGradientBrushVertexShader;
+ code[AffinePositionWithTextureBrushVertexShader] = qglslAffinePositionWithTextureBrushVertexShader;
+
+ code[MainFragmentShader_CMO] = qglslMainFragmentShader_CMO;
+ code[MainFragmentShader_CM] = qglslMainFragmentShader_CM;
+ code[MainFragmentShader_MO] = qglslMainFragmentShader_MO;
+ code[MainFragmentShader_M] = qglslMainFragmentShader_M;
+ code[MainFragmentShader_CO] = qglslMainFragmentShader_CO;
+ code[MainFragmentShader_C] = qglslMainFragmentShader_C;
+ code[MainFragmentShader_O] = qglslMainFragmentShader_O;
+ code[MainFragmentShader] = qglslMainFragmentShader;
+ code[MainFragmentShader_ImageArrays] = qglslMainFragmentShader_ImageArrays;
+
+ code[ImageSrcFragmentShader] = qglslImageSrcFragmentShader;
+ code[ImageSrcWithPatternFragmentShader] = qglslImageSrcWithPatternFragmentShader;
+ code[NonPremultipliedImageSrcFragmentShader] = qglslNonPremultipliedImageSrcFragmentShader;
+ code[CustomImageSrcFragmentShader] = qglslCustomSrcFragmentShader; // Calls "customShader", which must be appended
+ code[SolidBrushSrcFragmentShader] = qglslSolidBrushSrcFragmentShader;
+ code[TextureBrushSrcFragmentShader] = qglslTextureBrushSrcFragmentShader;
+ code[TextureBrushSrcWithPatternFragmentShader] = qglslTextureBrushSrcWithPatternFragmentShader;
+ code[PatternBrushSrcFragmentShader] = qglslPatternBrushSrcFragmentShader;
+ code[LinearGradientBrushSrcFragmentShader] = qglslLinearGradientBrushSrcFragmentShader;
+ code[RadialGradientBrushSrcFragmentShader] = qglslRadialGradientBrushSrcFragmentShader;
+ code[ConicalGradientBrushSrcFragmentShader] = qglslConicalGradientBrushSrcFragmentShader;
+ code[ShockingPinkSrcFragmentShader] = qglslShockingPinkSrcFragmentShader;
+
+ code[NoMaskFragmentShader] = "";
+ code[MaskFragmentShader] = qglslMaskFragmentShader;
+ code[RgbMaskFragmentShaderPass1] = qglslRgbMaskFragmentShaderPass1;
+ code[RgbMaskFragmentShaderPass2] = qglslRgbMaskFragmentShaderPass2;
+ code[RgbMaskWithGammaFragmentShader] = ""; //###
+
+ code[NoCompositionModeFragmentShader] = "";
+ 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 < TotalSnippetCount; ++i) {
+ if (qShaderSnippets[i] == 0) {
+ qFatal("Shader snippet for %s (#%d) is missing!",
+ snippetNameStr(SnippetName(i)).constData(), i);
+ }
+ }
+#endif
+ snippetsPopulated = true;
+ }
+
+ QGLShader* fragShader;
+ QGLShader* vertexShader;
+ QByteArray source;
+
+ // Compile up the simple shader:
+ source.clear();
+ source.append(qShaderSnippets[MainVertexShader]);
+ source.append(qShaderSnippets[PositionOnlyVertexShader]);
+ vertexShader = new QGLShader(QGLShader::Vertex, context, this);
+ if (!vertexShader->compileSourceCode(source))
+ qWarning("Vertex shader for simpleShaderProg (MainVertexShader & PositionOnlyVertexShader) failed to compile");
+
+ source.clear();
+ source.append(qShaderSnippets[MainFragmentShader]);
+ source.append(qShaderSnippets[ShockingPinkSrcFragmentShader]);
+ fragShader = new QGLShader(QGLShader::Fragment, context, this);
+ if (!fragShader->compileSourceCode(source))
+ qWarning("Fragment shader for simpleShaderProg (MainFragmentShader & ShockingPinkSrcFragmentShader) failed to compile");
+
+ simpleShaderProg = new QGLShaderProgram(context, this);
+ simpleShaderProg->addShader(vertexShader);
+ simpleShaderProg->addShader(fragShader);
+ simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
+ simpleShaderProg->link();
+ if (!simpleShaderProg->isLinked()) {
+ qCritical() << "Errors linking simple shader:"
+ << simpleShaderProg->log();
+ }
+
+ // Compile the blit shader:
+ source.clear();
+ source.append(qShaderSnippets[MainWithTexCoordsVertexShader]);
+ source.append(qShaderSnippets[UntransformedPositionVertexShader]);
+ vertexShader = new QGLShader(QGLShader::Vertex, context, this);
+ if (!vertexShader->compileSourceCode(source))
+ qWarning("Vertex shader for blitShaderProg (MainWithTexCoordsVertexShader & UntransformedPositionVertexShader) failed to compile");
+
+ source.clear();
+ source.append(qShaderSnippets[MainFragmentShader]);
+ source.append(qShaderSnippets[ImageSrcFragmentShader]);
+ fragShader = new QGLShader(QGLShader::Fragment, context, this);
+ if (!fragShader->compileSourceCode(source))
+ qWarning("Fragment shader for blitShaderProg (MainFragmentShader & ImageSrcFragmentShader) failed to compile");
+
+ blitShaderProg = new QGLShaderProgram(context, this);
+ blitShaderProg->addShader(vertexShader);
+ blitShaderProg->addShader(fragShader);
+ blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
+ blitShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
+ blitShaderProg->link();
+ if (!blitShaderProg->isLinked()) {
+ qCritical() << "Errors linking blit shader:"
+ << simpleShaderProg->log();
+ }
+
+}
+
+#if defined (QT_DEBUG)
+QByteArray QGLEngineSharedShaders::snippetNameStr(SnippetName name)
+{
+ QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("SnippetName"));
+ return QByteArray(m.valueToKey(name));
+}
+#endif
+
+// The address returned here will only be valid until next time this function is called.
+QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineShaderProg &prog)
+{
+ for (int i = 0; i < cachedPrograms.size(); ++i) {
+ QGLEngineShaderProg *cachedProg = cachedPrograms[i];
+ if (*cachedProg == prog) {
+ // Move the program to the top of the list as a poor-man's cache algo
+ cachedPrograms.move(i, 0);
+ return cachedProg;
+ }
+ }
+
+ QGLShader *vertexShader = 0;
+ QGLShader *fragShader = 0;
+ QGLEngineShaderProg *newProg = 0;
+ bool success = false;
+
+ do {
+ QByteArray source;
+ source.append(qShaderSnippets[prog.mainFragShader]);
+ source.append(qShaderSnippets[prog.srcPixelFragShader]);
+ if (prog.srcPixelFragShader == CustomImageSrcFragmentShader)
+ source.append(prog.customStageSource);
+ if (prog.compositionFragShader)
+ source.append(qShaderSnippets[prog.compositionFragShader]);
+ if (prog.maskFragShader)
+ source.append(qShaderSnippets[prog.maskFragShader]);
+ fragShader = new QGLShader(QGLShader::Fragment, ctxGuard.context(), this);
+ QByteArray description;
+#if defined(QT_DEBUG)
+ // Name the shader for easier debugging
+ description.append("Fragment shader: main=");
+ description.append(snippetNameStr(prog.mainFragShader));
+ description.append(", srcPixel=");
+ description.append(snippetNameStr(prog.srcPixelFragShader));
+ if (prog.compositionFragShader) {
+ description.append(", composition=");
+ description.append(snippetNameStr(prog.compositionFragShader));
+ }
+ if (prog.maskFragShader) {
+ description.append(", mask=");
+ description.append(snippetNameStr(prog.maskFragShader));
+ }
+ fragShader->setObjectName(QString::fromLatin1(description));
+#endif
+ if (!fragShader->compileSourceCode(source)) {
+ qWarning() << "Warning:" << description << "failed to compile!";
+ break;
+ }
+
+ source.clear();
+ source.append(qShaderSnippets[prog.mainVertexShader]);
+ source.append(qShaderSnippets[prog.positionVertexShader]);
+ vertexShader = new QGLShader(QGLShader::Vertex, ctxGuard.context(), this);
+#if defined(QT_DEBUG)
+ // Name the shader for easier debugging
+ description.clear();
+ description.append("Vertex shader: main=");
+ description.append(snippetNameStr(prog.mainVertexShader));
+ description.append(", position=");
+ description.append(snippetNameStr(prog.positionVertexShader));
+ vertexShader->setObjectName(QString::fromLatin1(description));
+#endif
+ if (!vertexShader->compileSourceCode(source)) {
+ qWarning() << "Warning:" << description << "failed to compile!";
+ break;
+ }
+
+ newProg = new QGLEngineShaderProg(prog);
+
+ // If the shader program's not found in the cache, create it now.
+ newProg->program = new QGLShaderProgram(ctxGuard.context(), this);
+ newProg->program->addShader(vertexShader);
+ newProg->program->addShader(fragShader);
+
+ // We have to bind the vertex attribute names before the program is linked:
+ newProg->program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
+ if (newProg->useTextureCoords)
+ newProg->program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
+ if (newProg->useOpacityAttribute)
+ newProg->program->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR);
+
+ newProg->program->link();
+ if (!newProg->program->isLinked()) {
+ QLatin1String none("none");
+ QLatin1String br("\n");
+ QString error;
+ error = QLatin1String("Shader program failed to link,")
+#if defined(QT_DEBUG)
+ + br
+ + QLatin1String(" Shaders Used:") + br
+ + QLatin1String(" ") + vertexShader->objectName() + QLatin1String(": ") + br
+ + QLatin1String(vertexShader->sourceCode()) + br
+ + QLatin1String(" ") + fragShader->objectName() + QLatin1String(": ") + br
+ + QLatin1String(fragShader->sourceCode()) + br
+#endif
+ + QLatin1String(" Error Log:\n")
+ + QLatin1String(" ") + newProg->program->log();
+ qWarning() << error;
+ break;
+ }
+ if (cachedPrograms.count() > 30) {
+ // The cache is full, so delete the last 5 programs in the list.
+ // These programs will be least used, as a program us bumped to
+ // the top of the list when it's used.
+ for (int i = 0; i < 5; ++i) {
+ delete cachedPrograms.last();
+ cachedPrograms.removeLast();
+ }
+ }
+
+ cachedPrograms.insert(0, newProg);
+
+ success = true;
+ } while (false);
+
+ // Clean up everything if we weren't successful
+ if (!success) {
+ if (newProg) {
+ delete newProg; // Also deletes the QGLShaderProgram which in turn deletes the QGLShaders
+ newProg = 0;
+ }
+ else {
+ if (vertexShader)
+ delete vertexShader;
+ if (fragShader)
+ delete fragShader;
+ }
+ }
+
+ return newProg;
+}
+
+void QGLEngineSharedShaders::cleanupCustomStage(QGLCustomShaderStage* stage)
+{
+ // Remove any shader programs which has this as the custom shader src:
+ for (int i = 0; i < cachedPrograms.size(); ++i) {
+ QGLEngineShaderProg *cachedProg = cachedPrograms[i];
+ if (cachedProg->customStageSource == stage->source()) {
+ delete cachedProg;
+ cachedPrograms.removeAt(i);
+ i--;
+ }
+ }
+}
+
+
+QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
+ : ctx(context),
+ shaderProgNeedsChanging(true),
+ srcPixelType(Qt::NoBrush),
+ opacityMode(NoOpacity),
+ maskType(NoMask),
+ compositionMode(QPainter::CompositionMode_SourceOver),
+ customSrcStage(0),
+ currentShaderProg(0)
+{
+ sharedShaders = QGLEngineSharedShaders::shadersForContext(context);
+ connect(sharedShaders, SIGNAL(shaderProgNeedsChanging()), this, SLOT(shaderProgNeedsChangingSlot()));
+}
+
+QGLEngineShaderManager::~QGLEngineShaderManager()
+{
+ //###
+ removeCustomStage();
+}
+
+uint QGLEngineShaderManager::getUniformLocation(Uniform id)
+{
+ if (!currentShaderProg)
+ return 0;
+
+ QVector<uint> &uniformLocations = currentShaderProg->uniformLocations;
+ if (uniformLocations.isEmpty())
+ uniformLocations.fill(GLuint(-1), NumUniforms);
+
+ static const char *uniformNames[] = {
+ "imageTexture",
+ "patternColor",
+ "globalOpacity",
+ "depth",
+ "pmvMatrix",
+ "maskTexture",
+ "fragmentColor",
+ "linearData",
+ "angle",
+ "halfViewportSize",
+ "fmp",
+ "fmp2_m_radius2",
+ "inverse_2_fmp2_m_radius2",
+ "invertedTextureSize",
+ "brushTransform",
+ "brushTexture"
+ };
+
+ if (uniformLocations.at(id) == GLuint(-1))
+ uniformLocations[id] = currentShaderProg->program->uniformLocation(uniformNames[id]);
+
+ return uniformLocations.at(id);
+}
+
+
+void QGLEngineShaderManager::optimiseForBrushTransform(const QTransform &transform)
+{
+ Q_UNUSED(transform); // Currently ignored
+}
+
+void QGLEngineShaderManager::setDirty()
+{
+ shaderProgNeedsChanging = true;
+}
+
+void QGLEngineShaderManager::setSrcPixelType(Qt::BrushStyle style)
+{
+ Q_ASSERT(style != Qt::NoBrush);
+ if (srcPixelType == PixelSrcType(style))
+ return;
+
+ srcPixelType = style;
+ shaderProgNeedsChanging = true; //###
+}
+
+void QGLEngineShaderManager::setSrcPixelType(PixelSrcType type)
+{
+ if (srcPixelType == type)
+ return;
+
+ srcPixelType = type;
+ shaderProgNeedsChanging = true; //###
+}
+
+void QGLEngineShaderManager::setOpacityMode(OpacityMode mode)
+{
+ if (opacityMode == mode)
+ return;
+
+ opacityMode = mode;
+ shaderProgNeedsChanging = true; //###
+}
+
+void QGLEngineShaderManager::setMaskType(MaskType type)
+{
+ if (maskType == type)
+ return;
+
+ maskType = type;
+ shaderProgNeedsChanging = true; //###
+}
+
+void QGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mode)
+{
+ if (compositionMode == mode)
+ return;
+
+ compositionMode = mode;
+ shaderProgNeedsChanging = true; //###
+}
+
+void QGLEngineShaderManager::setCustomStage(QGLCustomShaderStage* stage)
+{
+ if (customSrcStage)
+ removeCustomStage();
+ customSrcStage = stage;
+ shaderProgNeedsChanging = true;
+}
+
+void QGLEngineShaderManager::removeCustomStage()
+{
+ if (customSrcStage)
+ customSrcStage->setInactive();
+ customSrcStage = 0;
+ shaderProgNeedsChanging = true;
+}
+
+QGLShaderProgram* QGLEngineShaderManager::currentProgram()
+{
+ if (currentShaderProg)
+ return currentShaderProg->program;
+ else
+ return simpleProgram();
+}
+
+QGLShaderProgram* QGLEngineShaderManager::simpleProgram()
+{
+ return sharedShaders->simpleProgram();
+}
+
+QGLShaderProgram* QGLEngineShaderManager::blitProgram()
+{
+ return sharedShaders->blitProgram();
+}
+
+
+
+// Select & use the correct shader program using the current state.
+// Returns true if program needed changing.
+bool QGLEngineShaderManager::useCorrectShaderProg()
+{
+ if (!shaderProgNeedsChanging)
+ return false;
+
+ bool useCustomSrc = customSrcStage != 0;
+ if (useCustomSrc && srcPixelType != QGLEngineShaderManager::ImageSrc && srcPixelType != Qt::TexturePattern) {
+ useCustomSrc = false;
+ qWarning("QGLEngineShaderManager - Ignoring custom shader stage for non image src");
+ }
+
+ QGLEngineShaderProg requiredProgram;
+
+ bool texCoords = false;
+
+ // Choose vertex shader shader position function (which typically also sets
+ // varyings) and the source pixel (srcPixel) fragment shader function:
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::InvalidSnippetName;
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::InvalidSnippetName;
+ bool isAffine = brushTransform.isAffine();
+ if ( (srcPixelType >= Qt::Dense1Pattern) && (srcPixelType <= Qt::DiagCrossPattern) ) {
+ if (isAffine)
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::AffinePositionWithPatternBrushVertexShader;
+ else
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionWithPatternBrushVertexShader;
+
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::PatternBrushSrcFragmentShader;
+ }
+ else switch (srcPixelType) {
+ default:
+ case Qt::NoBrush:
+ qFatal("QGLEngineShaderManager::useCorrectShaderProg() - Qt::NoBrush style is set");
+ break;
+ case QGLEngineShaderManager::ImageSrc:
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::ImageSrcFragmentShader;
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
+ texCoords = true;
+ break;
+ case QGLEngineShaderManager::NonPremultipliedImageSrc:
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::NonPremultipliedImageSrcFragmentShader;
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
+ texCoords = true;
+ break;
+ case QGLEngineShaderManager::PatternSrc:
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::ImageSrcWithPatternFragmentShader;
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
+ texCoords = true;
+ break;
+ case QGLEngineShaderManager::TextureSrcWithPattern:
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::TextureBrushSrcWithPatternFragmentShader;
+ requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader
+ : QGLEngineSharedShaders::PositionWithTextureBrushVertexShader;
+ break;
+ case Qt::SolidPattern:
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::SolidBrushSrcFragmentShader;
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
+ break;
+ case Qt::LinearGradientPattern:
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::LinearGradientBrushSrcFragmentShader;
+ requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithLinearGradientBrushVertexShader
+ : QGLEngineSharedShaders::PositionWithLinearGradientBrushVertexShader;
+ break;
+ case Qt::ConicalGradientPattern:
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::ConicalGradientBrushSrcFragmentShader;
+ requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithConicalGradientBrushVertexShader
+ : QGLEngineSharedShaders::PositionWithConicalGradientBrushVertexShader;
+ break;
+ case Qt::RadialGradientPattern:
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::RadialGradientBrushSrcFragmentShader;
+ requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithRadialGradientBrushVertexShader
+ : QGLEngineSharedShaders::PositionWithRadialGradientBrushVertexShader;
+ break;
+ case Qt::TexturePattern:
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::TextureBrushSrcFragmentShader;
+ requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader
+ : QGLEngineSharedShaders::PositionWithTextureBrushVertexShader;
+ break;
+ };
+
+ if (useCustomSrc) {
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::CustomImageSrcFragmentShader;
+ requiredProgram.customStageSource = customSrcStage->source();
+ }
+
+ const bool hasCompose = compositionMode > QPainter::CompositionMode_Plus;
+ const bool hasMask = maskType != QGLEngineShaderManager::NoMask;
+
+ // Choose fragment shader main function:
+ if (opacityMode == AttributeOpacity) {
+ Q_ASSERT(!hasCompose && !hasMask);
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_ImageArrays;
+ } else {
+ bool useGlobalOpacity = (opacityMode == UniformOpacity);
+ if (hasCompose && hasMask && useGlobalOpacity)
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_CMO;
+ if (hasCompose && hasMask && !useGlobalOpacity)
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_CM;
+ if (!hasCompose && hasMask && useGlobalOpacity)
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_MO;
+ if (!hasCompose && hasMask && !useGlobalOpacity)
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_M;
+ if (hasCompose && !hasMask && useGlobalOpacity)
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_CO;
+ if (hasCompose && !hasMask && !useGlobalOpacity)
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_C;
+ if (!hasCompose && !hasMask && useGlobalOpacity)
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_O;
+ if (!hasCompose && !hasMask && !useGlobalOpacity)
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader;
+ }
+
+ if (hasMask) {
+ if (maskType == PixelMask) {
+ requiredProgram.maskFragShader = QGLEngineSharedShaders::MaskFragmentShader;
+ texCoords = true;
+ } else if (maskType == SubPixelMaskPass1) {
+ requiredProgram.maskFragShader = QGLEngineSharedShaders::RgbMaskFragmentShaderPass1;
+ texCoords = true;
+ } else if (maskType == SubPixelMaskPass2) {
+ requiredProgram.maskFragShader = QGLEngineSharedShaders::RgbMaskFragmentShaderPass2;
+ texCoords = true;
+ } else if (maskType == SubPixelWithGammaMask) {
+ requiredProgram.maskFragShader = QGLEngineSharedShaders::RgbMaskWithGammaFragmentShader;
+ texCoords = true;
+ } else {
+ qCritical("QGLEngineShaderManager::useCorrectShaderProg() - Unknown mask type");
+ }
+ } else {
+ requiredProgram.maskFragShader = QGLEngineSharedShaders::NoMaskFragmentShader;
+ }
+
+ if (hasCompose) {
+ switch (compositionMode) {
+ case QPainter::CompositionMode_Multiply:
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::MultiplyCompositionModeFragmentShader;
+ break;
+ case QPainter::CompositionMode_Screen:
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::ScreenCompositionModeFragmentShader;
+ break;
+ case QPainter::CompositionMode_Overlay:
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::OverlayCompositionModeFragmentShader;
+ break;
+ case QPainter::CompositionMode_Darken:
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::DarkenCompositionModeFragmentShader;
+ break;
+ case QPainter::CompositionMode_Lighten:
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::LightenCompositionModeFragmentShader;
+ break;
+ case QPainter::CompositionMode_ColorDodge:
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::ColorDodgeCompositionModeFragmentShader;
+ break;
+ case QPainter::CompositionMode_ColorBurn:
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::ColorBurnCompositionModeFragmentShader;
+ break;
+ case QPainter::CompositionMode_HardLight:
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::HardLightCompositionModeFragmentShader;
+ break;
+ case QPainter::CompositionMode_SoftLight:
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::SoftLightCompositionModeFragmentShader;
+ break;
+ case QPainter::CompositionMode_Difference:
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::DifferenceCompositionModeFragmentShader;
+ break;
+ case QPainter::CompositionMode_Exclusion:
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::ExclusionCompositionModeFragmentShader;
+ break;
+ default:
+ qWarning("QGLEngineShaderManager::useCorrectShaderProg() - Unsupported composition mode");
+ }
+ } else {
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::NoCompositionModeFragmentShader;
+ }
+
+ // Choose vertex shader main function
+ if (opacityMode == AttributeOpacity) {
+ Q_ASSERT(texCoords);
+ requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainWithTexCoordsAndOpacityVertexShader;
+ } else if (texCoords) {
+ requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainWithTexCoordsVertexShader;
+ } else {
+ requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainVertexShader;
+ }
+ requiredProgram.useTextureCoords = texCoords;
+ requiredProgram.useOpacityAttribute = (opacityMode == AttributeOpacity);
+
+ // At this point, requiredProgram is fully populated so try to find the program in the cache
+ currentShaderProg = sharedShaders->findProgramInCache(requiredProgram);
+
+ if (currentShaderProg) {
+ currentShaderProg->program->bind();
+ if (useCustomSrc)
+ customSrcStage->setUniforms(currentShaderProg->program);
+ }
+
+ shaderProgNeedsChanging = false;
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
new file mode 100644
index 0000000..50c1432
--- /dev/null
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
@@ -0,0 +1,499 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+/*
+ VERTEX SHADERS
+ ==============
+
+ Vertex shaders are specified as multiple (partial) shaders. On desktop,
+ this works fine. On ES, QGLShader & QGLShaderProgram will make partial
+ shaders work by concatenating the source in each QGLShader and compiling
+ it as a single shader. This is abstracted nicely by QGLShaderProgram and
+ the GL2 engine doesn't need to worry about it.
+
+ Generally, there's two vertex shader objects. The position shaders are
+ the ones which set gl_Position. There's also two "main" vertex shaders,
+ one which just calls the position shader and another which also passes
+ through some texture coordinates from a vertex attribute array to a
+ varying. These texture coordinates are used for mask position in text
+ rendering and for the source coordinates in drawImage/drawPixmap. There's
+ also a "Simple" vertex shader for rendering a solid colour (used to render
+ into the stencil buffer where the actual colour value is discarded).
+
+ The position shaders for brushes look scary. This is because many of the
+ calculations which logically belong in the fragment shader have been moved
+ into the vertex shader to improve performance. This is why the position
+ calculation is in a seperate shader. Not only does it calculate the
+ position, but it also calculates some data to be passed to the fragment
+ shader as a varying. It is optimal to move as much of the calculation as
+ possible into the vertex shader as this is executed less often.
+
+ The varyings passed to the fragment shaders are interpolated (which is
+ cheap). Unfortunately, GL will apply perspective correction to the
+ interpolation calusing errors. To get around this, the vertex shader must
+ apply perspective correction itself and set the w-value of gl_Position to
+ zero. That way, GL will be tricked into thinking it doesn't need to apply a
+ perspective correction and use linear interpolation instead (which is what
+ we want). Of course, if the brush transform is affeine, no perspective
+ correction is needed and a simpler vertex shader can be used instead.
+
+ So there are the following "main" vertex shaders:
+ qglslMainVertexShader
+ qglslMainWithTexCoordsVertexShader
+
+ And the the following position vertex shaders:
+ qglslPositionOnlyVertexShader
+ qglslPositionWithTextureBrushVertexShader
+ qglslPositionWithPatternBrushVertexShader
+ qglslPositionWithLinearGradientBrushVertexShader
+ qglslPositionWithRadialGradientBrushVertexShader
+ qglslPositionWithConicalGradientBrushVertexShader
+ qglslAffinePositionWithTextureBrushVertexShader
+ qglslAffinePositionWithPatternBrushVertexShader
+ qglslAffinePositionWithLinearGradientBrushVertexShader
+ qglslAffinePositionWithRadialGradientBrushVertexShader
+ qglslAffinePositionWithConicalGradientBrushVertexShader
+
+ Leading to 23 possible vertex shaders
+
+
+ FRAGMENT SHADERS
+ ================
+
+ Fragment shaders are also specified as multiple (partial) shaders. The
+ different fragment shaders represent the different stages in Qt's fragment
+ pipeline. There are 1-3 stages in this pipeline: First stage is to get the
+ fragment's colour value. The next stage is to get the fragment's mask value
+ (coverage value for anti-aliasing) and the final stage is to blend the
+ incoming fragment with the background (for composition modes not supported
+ by GL).
+
+ Of these, the first stage will always be present. If Qt doesn't need to
+ apply anti-aliasing (because it's off or handled by multisampling) then
+ the coverage value doesn't need to be applied. (Note: There are two types
+ of mask, one for regular anti-aliasing and one for sub-pixel anti-
+ aliasing.) If the composition mode is one which GL supports natively then
+ the blending stage doesn't need to be applied.
+
+ As eash stage can have multiple implementations, they are abstracted as
+ GLSL function calls with the following signatures:
+
+ Brushes & image drawing are implementations of "qcolorp vec4 srcPixel()":
+ qglslImageSrcFragShader
+ qglslImageSrcWithPatternFragShader
+ qglslNonPremultipliedImageSrcFragShader
+ qglslSolidBrushSrcFragShader
+ qglslTextureBrushSrcFragShader
+ qglslTextureBrushWithPatternFragShader
+ qglslPatternBrushSrcFragShader
+ qglslLinearGradientBrushSrcFragShader
+ qglslRadialGradientBrushSrcFragShader
+ qglslConicalGradientBrushSrcFragShader
+ NOTE: It is assumed the colour returned by srcPixel() is pre-multiplied
+
+ Masks are implementations of "qcolorp vec4 applyMask(qcolorp vec4 src)":
+ qglslMaskFragmentShader
+ qglslRgbMaskFragmentShaderPass1
+ qglslRgbMaskFragmentShaderPass2
+ 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
+ ==================
+
+ 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
+ (QGLCustomShaderStage). The shader will implement a pre-defined method name
+ which Qt's fragment pipeline will call:
+
+ lowp vec4 customShader(lowp sampler2d imageTexture, highp vec2 textureCoords)
+
+ The provided src and srcCoords parameters can be used to sample from the
+ source image.
+
+ Transformations, clipping, opacity, and composition modes set using QPainter
+ will be respected when using the custom shader hook.
+*/
+
+#ifndef QGLENGINE_SHADER_MANAGER_H
+#define QGLENGINE_SHADER_MANAGER_H
+
+#include <QGLShader>
+#include <QGLShaderProgram>
+#include <QPainter>
+#include <private/qgl_p.h>
+#include <private/qglcustomshaderstage_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(OpenGL)
+
+
+/*
+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;
+static const GLuint QT_OPACITY_ATTR = 2;
+
+class QGLEngineShaderProg;
+
+class QGLEngineSharedShaders : public QObject
+{
+ Q_OBJECT
+public:
+
+ enum SnippetName {
+ MainVertexShader,
+ MainWithTexCoordsVertexShader,
+ MainWithTexCoordsAndOpacityVertexShader,
+
+ // UntransformedPositionVertexShader must be first in the list:
+ UntransformedPositionVertexShader,
+ PositionOnlyVertexShader,
+ PositionWithPatternBrushVertexShader,
+ PositionWithLinearGradientBrushVertexShader,
+ PositionWithConicalGradientBrushVertexShader,
+ PositionWithRadialGradientBrushVertexShader,
+ PositionWithTextureBrushVertexShader,
+ AffinePositionWithPatternBrushVertexShader,
+ AffinePositionWithLinearGradientBrushVertexShader,
+ AffinePositionWithConicalGradientBrushVertexShader,
+ AffinePositionWithRadialGradientBrushVertexShader,
+ AffinePositionWithTextureBrushVertexShader,
+
+ // MainFragmentShader_CMO must be first in the list:
+ MainFragmentShader_CMO,
+ MainFragmentShader_CM,
+ MainFragmentShader_MO,
+ MainFragmentShader_M,
+ MainFragmentShader_CO,
+ MainFragmentShader_C,
+ MainFragmentShader_O,
+ MainFragmentShader,
+ MainFragmentShader_ImageArrays,
+
+ // ImageSrcFragmentShader must be first in the list::
+ ImageSrcFragmentShader,
+ ImageSrcWithPatternFragmentShader,
+ NonPremultipliedImageSrcFragmentShader,
+ CustomImageSrcFragmentShader,
+ SolidBrushSrcFragmentShader,
+ TextureBrushSrcFragmentShader,
+ TextureBrushSrcWithPatternFragmentShader,
+ PatternBrushSrcFragmentShader,
+ LinearGradientBrushSrcFragmentShader,
+ RadialGradientBrushSrcFragmentShader,
+ ConicalGradientBrushSrcFragmentShader,
+ ShockingPinkSrcFragmentShader,
+
+ // NoMaskFragmentShader must be first in the list:
+ NoMaskFragmentShader,
+ MaskFragmentShader,
+ RgbMaskFragmentShaderPass1,
+ RgbMaskFragmentShaderPass2,
+ RgbMaskWithGammaFragmentShader,
+
+ // NoCompositionModeFragmentShader must be first in the list:
+ NoCompositionModeFragmentShader,
+ MultiplyCompositionModeFragmentShader,
+ ScreenCompositionModeFragmentShader,
+ OverlayCompositionModeFragmentShader,
+ DarkenCompositionModeFragmentShader,
+ LightenCompositionModeFragmentShader,
+ ColorDodgeCompositionModeFragmentShader,
+ ColorBurnCompositionModeFragmentShader,
+ HardLightCompositionModeFragmentShader,
+ SoftLightCompositionModeFragmentShader,
+ DifferenceCompositionModeFragmentShader,
+ ExclusionCompositionModeFragmentShader,
+
+ TotalSnippetCount, InvalidSnippetName
+ };
+#if defined (QT_DEBUG)
+ Q_ENUMS(SnippetName)
+ static QByteArray snippetNameStr(SnippetName snippetName);
+#endif
+
+/*
+ // 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;
+*/
+
+ QGLEngineSharedShaders(const QGLContext *context);
+
+ QGLShaderProgram *simpleProgram() { return simpleShaderProg; }
+ QGLShaderProgram *blitProgram() { return blitShaderProg; }
+ // Compile the program if it's not already in the cache, return the item in the cache.
+ QGLEngineShaderProg *findProgramInCache(const QGLEngineShaderProg &prog);
+ // Compile the custom shader if it's not already in the cache, return the item in the cache.
+
+ static QGLEngineSharedShaders *shadersForContext(const QGLContext *context);
+
+ // Ideally, this would be static and cleanup all programs in all contexts which
+ // contain the custom code. Currently it is just a hint and we rely on deleted
+ // custom shaders being cleaned up by being kicked out of the cache when it's
+ // full.
+ void cleanupCustomStage(QGLCustomShaderStage* stage);
+
+signals:
+ void shaderProgNeedsChanging();
+
+private:
+ QGLSharedResourceGuard ctxGuard;
+ QGLShaderProgram *blitShaderProg;
+ QGLShaderProgram *simpleShaderProg;
+ QList<QGLEngineShaderProg*> cachedPrograms;
+
+ static const char* qShaderSnippets[TotalSnippetCount];
+};
+
+
+class QGLEngineShaderProg
+{
+public:
+ QGLEngineShaderProg() : program(0) {}
+
+ ~QGLEngineShaderProg() {
+ if (program)
+ delete program;
+ }
+
+ QGLEngineSharedShaders::SnippetName mainVertexShader;
+ QGLEngineSharedShaders::SnippetName positionVertexShader;
+ QGLEngineSharedShaders::SnippetName mainFragShader;
+ QGLEngineSharedShaders::SnippetName srcPixelFragShader;
+ QGLEngineSharedShaders::SnippetName maskFragShader;
+ QGLEngineSharedShaders::SnippetName compositionFragShader;
+
+ QByteArray customStageSource; //TODO: Decent cache key for custom stages
+ QGLShaderProgram* program;
+
+ QVector<uint> uniformLocations;
+
+ bool useTextureCoords;
+ bool useOpacityAttribute;
+
+ bool operator==(const QGLEngineShaderProg& other) {
+ // We don't care about the program
+ return ( mainVertexShader == other.mainVertexShader &&
+ positionVertexShader == other.positionVertexShader &&
+ mainFragShader == other.mainFragShader &&
+ srcPixelFragShader == other.srcPixelFragShader &&
+ maskFragShader == other.maskFragShader &&
+ compositionFragShader == other.compositionFragShader &&
+ customStageSource == other.customStageSource
+ );
+ }
+};
+
+class Q_OPENGL_EXPORT QGLEngineShaderManager : public QObject
+{
+ Q_OBJECT
+public:
+ QGLEngineShaderManager(QGLContext* context);
+ ~QGLEngineShaderManager();
+
+ enum MaskType {NoMask, PixelMask, SubPixelMaskPass1, SubPixelMaskPass2, SubPixelWithGammaMask};
+ enum PixelSrcType {
+ ImageSrc = Qt::TexturePattern+1,
+ NonPremultipliedImageSrc = Qt::TexturePattern+2,
+ PatternSrc = Qt::TexturePattern+3,
+ TextureSrcWithPattern = Qt::TexturePattern+4
+ };
+
+ enum Uniform {
+ ImageTexture,
+ PatternColor,
+ GlobalOpacity,
+ Depth,
+ PmvMatrix,
+ MaskTexture,
+ FragmentColor,
+ LinearData,
+ Angle,
+ HalfViewportSize,
+ Fmp,
+ Fmp2MRadius2,
+ Inverse2Fmp2MRadius2,
+ InvertedTextureSize,
+ BrushTransform,
+ BrushTexture,
+ NumUniforms
+ };
+
+ enum OpacityMode {
+ NoOpacity,
+ UniformOpacity,
+ AttributeOpacity
+ };
+
+ // 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 setOpacityMode(OpacityMode);
+ void setMaskType(MaskType);
+ void setCompositionMode(QPainter::CompositionMode);
+ void setCustomStage(QGLCustomShaderStage* stage);
+ void removeCustomStage();
+
+ uint getUniformLocation(Uniform id);
+
+ void setDirty(); // someone has manually changed the current shader program
+ bool useCorrectShaderProg(); // returns true if the shader program needed to be changed
+
+ QGLShaderProgram* currentProgram(); // Returns pointer to the shader the manager has chosen
+ QGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers
+ QGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer
+
+ QGLEngineSharedShaders* sharedShaders;
+
+private slots:
+ void shaderProgNeedsChangingSlot() { shaderProgNeedsChanging = true; }
+
+private:
+ QGLContext* ctx;
+ bool shaderProgNeedsChanging;
+
+ // Current state variables which influence the choice of shader:
+ QTransform brushTransform;
+ int srcPixelType;
+ OpacityMode opacityMode;
+ MaskType maskType;
+ QPainter::CompositionMode compositionMode;
+ QGLCustomShaderStage* customSrcStage;
+
+ QGLEngineShaderProg* currentShaderProg;
+};
+
+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..46de124
--- /dev/null
+++ b/src/opengl/gl2paintengineex/qglengineshadersource_p.h
@@ -0,0 +1,476 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@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 = "\
+ uniform highp float depth;\
+ void setPosition();\
+ void main(void)\
+ {\
+ setPosition();\
+ gl_Position.z = depth * gl_Position.w;\
+ }";
+
+static const char* const qglslMainWithTexCoordsVertexShader = "\
+ attribute highp vec2 textureCoordArray; \
+ varying highp vec2 textureCoords; \
+ uniform highp float depth;\
+ void setPosition();\
+ void main(void) \
+ {\
+ setPosition();\
+ gl_Position.z = depth * gl_Position.w;\
+ textureCoords = textureCoordArray; \
+ }";
+
+static const char* const qglslMainWithTexCoordsAndOpacityVertexShader = "\
+ attribute highp vec2 textureCoordArray; \
+ attribute lowp float opacityArray; \
+ varying highp vec2 textureCoords; \
+ varying lowp float opacity; \
+ uniform highp float depth; \
+ void setPosition(); \
+ void main(void) \
+ { \
+ setPosition(); \
+ gl_Position.z = depth * gl_Position.w; \
+ textureCoords = textureCoordArray; \
+ opacity = opacityArray; \
+ }";
+
+// NOTE: We let GL do the perspective correction so texture lookups in the fragment
+// shader are also perspective corrected.
+static const char* const qglslPositionOnlyVertexShader = "\
+ attribute highp vec2 vertexCoordsArray;\
+ uniform highp mat3 pmvMatrix;\
+ void setPosition(void)\
+ {\
+ vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \
+ gl_Position = vec4(transformedPos.xy, 0.0, transformedPos.z); \
+ }";
+
+static const char* const qglslUntransformedPositionVertexShader = "\
+ attribute highp vec4 vertexCoordsArray;\
+ void setPosition(void)\
+ {\
+ gl_Position = 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 vec2 vertexCoordsArray; \
+ uniform highp mat3 pmvMatrix; \
+ uniform mediump vec2 halfViewportSize; \
+ uniform highp vec2 invertedTextureSize; \
+ uniform highp mat3 brushTransform; \
+ varying highp vec2 patternTexCoords; \
+ void setPosition(void) { \
+ vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \
+ gl_Position.xy = transformedPos.xy / transformedPos.z; \
+ mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \
+ mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1.0); \
+ mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \
+ gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \
+ patternTexCoords.xy = (hTexCoords.xy * 0.125) * invertedHTexCoordsZ; \
+ }";
+
+static const char* const qglslAffinePositionWithPatternBrushVertexShader
+ = qglslPositionWithPatternBrushVertexShader;
+
+static const char* const qglslPatternBrushSrcFragmentShader = "\
+ uniform lowp sampler2D brushTexture;\
+ uniform lowp vec4 patternColor; \
+ varying highp vec2 patternTexCoords;\
+ lowp vec4 srcPixel() { \
+ return patternColor * (1.0 - texture2D(brushTexture, patternTexCoords).r); \
+ }\n";
+
+
+// Linear Gradient Brush
+static const char* const qglslPositionWithLinearGradientBrushVertexShader = "\
+ attribute highp vec2 vertexCoordsArray; \
+ uniform highp mat3 pmvMatrix; \
+ uniform mediump vec2 halfViewportSize; \
+ uniform highp vec3 linearData; \
+ uniform highp mat3 brushTransform; \
+ varying mediump float index; \
+ void setPosition() { \
+ vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \
+ gl_Position.xy = transformedPos.xy / transformedPos.z; \
+ 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 = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \
+ index = (dot(linearData.xy, hTexCoords.xy) * linearData.z) * invertedHTexCoordsZ; \
+ }";
+
+static const char* const qglslAffinePositionWithLinearGradientBrushVertexShader
+ = qglslPositionWithLinearGradientBrushVertexShader;
+
+static const char* const qglslLinearGradientBrushSrcFragmentShader = "\
+ uniform lowp 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 vec2 vertexCoordsArray;\
+ uniform highp mat3 pmvMatrix;\
+ uniform mediump vec2 halfViewportSize; \
+ uniform highp mat3 brushTransform; \
+ varying highp vec2 A; \
+ void setPosition(void)\
+ {\
+ vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \
+ gl_Position.xy = transformedPos.xy / transformedPos.z; \
+ 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 = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \
+ A = hTexCoords.xy * invertedHTexCoordsZ; \
+ }";
+
+static const char* const qglslAffinePositionWithConicalGradientBrushVertexShader
+ = qglslPositionWithConicalGradientBrushVertexShader;
+
+static const char* const qglslConicalGradientBrushSrcFragmentShader = "\n\
+ #define INVERSE_2PI 0.1591549430918953358 \n\
+ uniform lowp 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 vec2 vertexCoordsArray;\
+ uniform highp mat3 pmvMatrix;\
+ uniform mediump vec2 halfViewportSize; \
+ uniform highp mat3 brushTransform; \
+ uniform highp vec2 fmp; \
+ varying highp float b; \
+ varying highp vec2 A; \
+ void setPosition(void) \
+ {\
+ vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \
+ gl_Position.xy = transformedPos.xy / transformedPos.z; \
+ 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 = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \
+ A = hTexCoords.xy * invertedHTexCoordsZ; \
+ b = 2.0 * dot(A, fmp); \
+ }";
+
+static const char* const qglslAffinePositionWithRadialGradientBrushVertexShader
+ = qglslPositionWithRadialGradientBrushVertexShader;
+
+static const char* const qglslRadialGradientBrushSrcFragmentShader = "\
+ uniform lowp 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 vec2 vertexCoordsArray; \
+ uniform highp mat3 pmvMatrix; \
+ uniform mediump vec2 halfViewportSize; \
+ uniform highp vec2 invertedTextureSize; \
+ uniform highp mat3 brushTransform; \
+ varying highp vec2 textureCoords; \
+ void setPosition(void) { \
+ vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \
+ gl_Position.xy = transformedPos.xy / transformedPos.z; \
+ 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 = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \
+ textureCoords.xy = (hTexCoords.xy * invertedTextureSize) * gl_Position.w; \
+ }";
+
+static const char* const qglslAffinePositionWithTextureBrushVertexShader
+ = qglslPositionWithTextureBrushVertexShader;
+
+#if defined(QT_OPENGL_ES_2)
+// OpenGL ES does not support GL_REPEAT wrap modes for NPOT textures. So instead,
+// we emulate GL_REPEAT by only taking the fractional part of the texture coords.
+// TODO: Special case POT textures which don't need this emulation
+static const char* const qglslTextureBrushSrcFragmentShader = "\
+ varying highp vec2 textureCoords; \
+ uniform lowp sampler2D brushTexture; \
+ lowp vec4 srcPixel() { \
+ return texture2D(brushTexture, fract(textureCoords)); \
+ }";
+#else
+static const char* const qglslTextureBrushSrcFragmentShader = "\
+ varying highp vec2 textureCoords; \
+ uniform lowp sampler2D brushTexture; \
+ lowp vec4 srcPixel() { \
+ return texture2D(brushTexture, textureCoords); \
+ }";
+#endif
+
+static const char* const qglslTextureBrushSrcWithPatternFragmentShader = "\
+ varying highp vec2 textureCoords; \
+ uniform lowp vec4 patternColor; \
+ uniform lowp sampler2D brushTexture; \
+ lowp vec4 srcPixel() { \
+ return patternColor * (1.0 - texture2D(brushTexture, textureCoords).r); \
+ }";
+
+// Solid Fill Brush
+static const char* const qglslSolidBrushSrcFragmentShader = "\
+ uniform lowp vec4 fragmentColor; \
+ lowp vec4 srcPixel() { \
+ return fragmentColor; \
+ }";
+
+static const char* const qglslImageSrcFragmentShader = "\
+ varying highp vec2 textureCoords; \
+ uniform lowp sampler2D imageTexture; \
+ lowp vec4 srcPixel() { \
+ return texture2D(imageTexture, textureCoords); \
+ }";
+
+static const char* const qglslCustomSrcFragmentShader = "\
+ varying highp vec2 textureCoords; \
+ uniform lowp sampler2D imageTexture; \
+ lowp vec4 customShader(lowp sampler2D texture, highp vec2 coords); \
+ lowp vec4 srcPixel() { \
+ return customShader(imageTexture, textureCoords); \
+ }";
+
+static const char* const qglslImageSrcWithPatternFragmentShader = "\
+ varying highp vec2 textureCoords; \
+ uniform lowp vec4 patternColor; \
+ uniform lowp sampler2D imageTexture; \
+ lowp vec4 srcPixel() { \
+ return patternColor * (1.0 - texture2D(imageTexture, textureCoords).r); \
+ }\n";
+
+static const char* const qglslNonPremultipliedImageSrcFragmentShader = "\
+ varying highp vec2 textureCoords; \
+ uniform lowp sampler2D imageTexture; \
+ lowp vec4 srcPixel() { \
+ lowp vec4 sample = texture2D(imageTexture, textureCoords); \
+ sample.rgb = sample.rgb * sample.a; \
+ return sample; \
+ }";
+
+static const char* const qglslShockingPinkSrcFragmentShader = "\
+ lowp vec4 srcPixel() { \
+ return vec4(0.98, 0.06, 0.75, 1.0); \
+ }";
+
+static const char* const qglslMainFragmentShader_ImageArrays = "\
+ varying lowp float opacity; \
+ lowp vec4 srcPixel(); \
+ void main() { \
+ gl_FragColor = srcPixel() * opacity; \
+ }";
+
+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 lowp sampler2D maskTexture;\
+ lowp vec4 applyMask(lowp vec4 src) \
+ {\
+ lowp vec4 mask = texture2D(maskTexture, textureCoords); \
+ return src * mask.a; \
+ }";
+
+// For source over with subpixel antialiasing, the final color is calculated per component as follows
+// (.a is alpha component, .c is red, green or blue component):
+// alpha = src.a * mask.c * opacity
+// dest.c = dest.c * (1 - alpha) + src.c * alpha
+//
+// In the first pass, calculate: dest.c = dest.c * (1 - alpha) with blend funcs: zero, 1 - source color
+// In the second pass, calculate: dest.c = dest.c + src.c * alpha with blend funcs: one, one
+//
+// If source is a solid color (src is constant), only the first pass is needed, with blend funcs: constant, 1 - source color
+
+// For source composition with subpixel antialiasing, the final color is calculated per component as follows:
+// alpha = src.a * mask.c * opacity
+// dest.c = dest.c * (1 - mask.c) + src.c * alpha
+//
+
+static const char* const qglslRgbMaskFragmentShaderPass1 = "\
+ varying highp vec2 textureCoords;\
+ uniform lowp sampler2D maskTexture;\
+ lowp vec4 applyMask(lowp vec4 src) \
+ {\
+ lowp vec4 mask = texture2D(maskTexture, textureCoords); \
+ return src.a * mask; \
+ }";
+
+static const char* const qglslRgbMaskFragmentShaderPass2 = "\
+ varying highp vec2 textureCoords;\
+ uniform lowp sampler2D maskTexture;\
+ lowp vec4 applyMask(lowp vec4 src) \
+ {\
+ lowp vec4 mask = texture2D(maskTexture, textureCoords); \
+ return src * mask; \
+ }";
+
+/*
+ Left to implement:
+ RgbMaskFragmentShader,
+ RgbMaskWithGammaFragmentShader,
+
+ MultiplyCompositionModeFragmentShader,
+ ScreenCompositionModeFragmentShader,
+ OverlayCompositionModeFragmentShader,
+ DarkenCompositionModeFragmentShader,
+ LightenCompositionModeFragmentShader,
+ ColorDodgeCompositionModeFragmentShader,
+ ColorBurnCompositionModeFragmentShader,
+ HardLightCompositionModeFragmentShader,
+ SoftLightCompositionModeFragmentShader,
+ DifferenceCompositionModeFragmentShader,
+ ExclusionCompositionModeFragmentShader,
+*/
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // GLGC_SHADER_SOURCE_H
diff --git a/src/opengl/gl2paintengineex/qglgradientcache.cpp b/src/opengl/gl2paintengineex/qglgradientcache.cpp
index 59bc437..e06f15d 100644
--- a/src/opengl/gl2paintengineex/qglgradientcache.cpp
+++ b/src/opengl/gl2paintengineex/qglgradientcache.cpp
@@ -44,7 +44,27 @@
#include "qglgradientcache_p.h"
-void QGLGradientCache::cleanCache() {
+QT_BEGIN_NAMESPACE
+
+static void QGL2GradientCache_free(void *ptr)
+{
+ delete reinterpret_cast<QGL2GradientCache *>(ptr);
+}
+
+Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_gradient_caches, (QGL2GradientCache_free))
+
+QGL2GradientCache *QGL2GradientCache::cacheForContext(const QGLContext *context)
+{
+ QGL2GradientCache *p = reinterpret_cast<QGL2GradientCache *>(qt_gradient_caches()->value(context));
+ if (!p) {
+ QGLShareContextScope scope(context);
+ p = new QGL2GradientCache;
+ qt_gradient_caches()->insert(context, p);
+ }
+ return p;
+}
+
+void QGL2GradientCache::cleanCache() {
QGLGradientColorTableHash::const_iterator it = cache.constBegin();
for (; it != cache.constEnd(); ++it) {
const CacheInfo &cache_info = it.value();
@@ -53,13 +73,8 @@ void QGLGradientCache::cleanCache() {
cache.clear();
}
-GLuint QGLGradientCache::getBuffer(const QGradient &gradient, qreal opacity, const QGLContext *ctx)
+GLuint QGL2GradientCache::getBuffer(const QGradient &gradient, qreal opacity)
{
- if (buffer_ctx && !qgl_share_reg()->checkSharing(buffer_ctx, ctx))
- cleanCache();
-
- buffer_ctx = ctx;
-
quint64 hash_val = 0;
QGradientStops stops = gradient.stops();
@@ -84,7 +99,7 @@ GLuint QGLGradientCache::getBuffer(const QGradient &gradient, qreal opacity, con
}
-GLuint QGLGradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity)
+GLuint QGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity)
{
if (cache.size() == maxCacheSize()) {
int elem_to_remove = qrand() % maxCacheSize();
@@ -109,34 +124,31 @@ GLuint QGLGradientCache::addCacheElement(quint64 hash_val, const QGradient &grad
}
-// GL's expects pixels in RGBA, bin-endian (ABGR on x86).
-// Qt stores in ARGB using whatever byte-order the mancine uses.
+// GL's expects pixels in RGBA (when using GL_RGBA), bin-endian (ABGR on x86).
+// Qt always stores in ARGB reguardless of the byte-order the mancine uses.
static inline uint qtToGlColor(uint c)
{
uint o;
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- o = c & 0xFF00FF00; // alpha & green already in the right place
- o |= (c >> 16) & 0x000000FF; // red
- o |= (c << 16) & 0x00FF0000; // blue
-
+ o = (c & 0xff00ff00) // alpha & green already in the right place
+ | ((c >> 16) & 0x000000ff) // red
+ | ((c << 16) & 0x00ff0000); // blue
#else //Q_BIG_ENDIAN
- o = c & 0x00FF00FF; // alpha & green already in the right place
- o |= (c << 16) & 0xFF000000; // red
- o |= (c >> 16) & 0x0000FF00; // blue
-#error big endian not tested with QGLGraphicsContext
+ o = (c << 8)
+ | ((c >> 24) & 0x000000ff);
#endif // Q_BYTE_ORDER
return o;
}
//TODO: Let GL generate the texture using an FBO
-void QGLGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const
+void QGL2GradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const
{
int pos = 0;
QGradientStops s = gradient.stops();
QVector<uint> colors(s.size());
for (int i = 0; i < s.size(); ++i)
- colors[i] = s[i].second.rgba(); // Qt LIES! It returns ARGB
+ colors[i] = s[i].second.rgba(); // Qt LIES! It returns ARGB (on little-endian AND on big-endian)
bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
@@ -183,3 +195,5 @@ void QGLGradientCache::generateGradientColorTable(const QGradient& gradient, uin
// Make sure the last color stop is represented at the end of the table
colorTable[size-1] = last_color;
}
+
+QT_END_NAMESPACE
diff --git a/src/opengl/gl2paintengineex/qglgradientcache_p.h b/src/opengl/gl2paintengineex/qglgradientcache_p.h
index 8d1a43f..3813f39 100644
--- a/src/opengl/gl2paintengineex/qglgradientcache_p.h
+++ b/src/opengl/gl2paintengineex/qglgradientcache_p.h
@@ -52,11 +52,13 @@
#include <QMultiHash>
#include <QObject>
-#include <QtOpenGL>
+#include <QtOpenGL/QtOpenGL>
+#include <private/qgl_p.h>
-class QGLGradientCache : public QObject
+QT_BEGIN_NAMESPACE
+
+class QGL2GradientCache
{
- Q_OBJECT
struct CacheInfo
{
inline CacheInfo(QGradientStops s, qreal op, QGradient::InterpolationMode mode) :
@@ -71,16 +73,12 @@ class QGLGradientCache : public QObject
typedef QMultiHash<quint64, CacheInfo> QGLGradientColorTableHash;
public:
- QGLGradientCache() : QObject(), buffer_ctx(0)
- {
-/*
- connect(QGLSignalProxy::instance(),
- SIGNAL(aboutToDestroyContext(const QGLContext *)),
- SLOT(cleanupGLContextRefs(const QGLContext *)));
-*/
- }
+ static QGL2GradientCache *cacheForContext(const QGLContext *context);
+
+ QGL2GradientCache() { }
+ ~QGL2GradientCache() {cleanCache();}
- GLuint getBuffer(const QGradient &gradient, qreal opacity, const QGLContext *ctx);
+ GLuint getBuffer(const QGradient &gradient, qreal opacity);
inline int paletteSize() const { return 1024; }
protected:
@@ -93,16 +91,7 @@ protected:
void cleanCache();
QGLGradientColorTableHash cache;
- const QGLContext *buffer_ctx;
-
-public slots:
- void cleanupGLContextRefs(const QGLContext *context) {
- if (context == buffer_ctx) {
- cleanCache();
- buffer_ctx = 0;
- }
- }
};
-
+QT_END_NAMESPACE
diff --git a/src/opengl/gl2paintengineex/qglpexshadermanager.cpp b/src/opengl/gl2paintengineex/qglpexshadermanager.cpp
deleted file mode 100644
index 4fb5417..0000000
--- a/src/opengl/gl2paintengineex/qglpexshadermanager.cpp
+++ /dev/null
@@ -1,450 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
-** this package.
-**
-** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@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 cc66c12..0000000
--- a/src/opengl/gl2paintengineex/qglpexshadermanager_p.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
-** this package.
-**
-** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qglshader_p.h"
-
-
-// Worstcase combo: Brush->Mask->Composition
-
-/*
- Vertex shader source is specified with a single string. This string
- contains the main function and sets the gl_Position. The choice of
- which vertex shader to use depends on:
- - Brush style
- - Brush transform->isAffine()
-
- Fragment shaders are specified as multiple strings, one for the main
- function, one for the brush calculation and optionally one for the
- extended composition mode. Brushes are implementations of
- "mediump vec4 brush()"
- Composition modes are implemented as a
- "mediump vec4 compose(mediump vec4 color)"
- NOTE: Precision may change in future.
-
- The choice of which main() fragment shader string to use depends on:
- - Global opacity
- - Brush style (some brushes apply opacity themselves)
- - Use of mask (TODO: Need to support high quality anti-aliasing & text)
- - Composition mode
-
- The choice of which brush() fragment shader to use depends on:
- - Brush style
-
-*/
-
-
-struct QGLCachedShaderProg
-{
- QGLShader* vertexShader;
- QGLShader* brushShader;
- QGLShader* compositionShader;
- QGLShaderProgram* shader;
-};
-
-class QGLPEXShaderManager
-{
-public:
- QGLPEXShaderManager(const QGLContext* context);
- ~QGLPEXShaderManager();
-
- enum TransformType {IdentityTransform, ScaleTransform, TranslateTransform, FullTransform};
-
- void optimiseForBrushTransform(const QTransform& transform);
- void setBrushStyle(Qt::BrushStyle style);
- void setUseGlobalOpacity(bool value);
- void setAffineOnlyBrushTransform(bool value); // I.e. Do we need to apply perspective-correction?
- // Not doing so saves some vertex shader calculations.
-
- bool useCorrectShaderProg(); // returns true if the shader program has changed
-
- QGLShaderProgram* brushShader();
- QGLShaderProgram* simpleShader(); // Used to draw into e.g. stencil buffers
- QGLShaderProgram* imageShader();
- QGLShaderProgram* textShader();
-
-private:
- QGLShader* defaultVertexShader;
-
- QGLShader* imageVertexShader;
- QGLShader* imageFragmentShader;
- QGLShaderProgram* imageShaderProgram;
-
- QGLShader* textVertexShader;
- QGLShader* textFragmentShader;
- QGLShaderProgram* textShaderProgram;
-
- QGLShader* noBrushShader;
- QGLShader* solidBrushShader;
-
- QGLShader* conicalBrushVertexShader;
- QGLShader* conicalBrushFragmentShader;
-
- QGLShader* radialBrushVertexShader;
- QGLShader* radialBrushFragmentShader;
-
- QGLShader* linearBrushVertexShader;
- QGLShader* linearBrushFragmentShader;
-
- QGLShader* patternBrushVertexShader;
- QGLShader* patternBrushFragmentShader;
-
- QGLShader* textureBrushFragmentShader;
- QGLShader* textureBrushVertexShader;
-
- QGLShader* simpleFragmentShader;
- QGLShaderProgram* simpleShaderProgram;
-
- QGLShaderProgram* activeProgram;
-
- Qt::BrushStyle currentBrushStyle;
- bool useGlobalOpacity;
- TransformType currentTransformType;
- bool shaderProgNeedsChanging;
-
- QList<QGLCachedShaderProg> cachedPrograms;
-
- QGLContext* ctx;
-};
diff --git a/src/opengl/gl2paintengineex/qglshader.cpp b/src/opengl/gl2paintengineex/qglshader.cpp
deleted file mode 100644
index a8384f2..0000000
--- a/src/opengl/gl2paintengineex/qglshader.cpp
+++ /dev/null
@@ -1,605 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
-** this package.
-**
-** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qglshader_p.h"
-
-
-// Windows needs to resolve OpenGL 2.0 function pointers for each context. The
-// QGL OpenGL 2.0 functions are actually macros, which take a "ctx" parameter.
-#define Q_CTX QGLContext* ctx = d->ctx; \
- if (!ctx) \
- return false; \
- ctx->makeCurrent(); \
-
-
-
-
-class QGLShaderPrivate
-{
-public:
- QGLShaderPrivate() : shaderId(0), valid(false), ctx(0) {}
-
- GLuint shaderId;
- QString source;
- bool valid;
- QGLShader::ShaderType type;
- QGLContext* ctx;
-};
-
-
-QGLShader::QGLShader(QGLShader::ShaderType type, const QGLContext* ctx)
- : d_ptr(new QGLShaderPrivate)
-{
- Q_D(QGLShader);
-
- if (!ctx)
- ctx = QGLContext::currentContext();
-
- if (!ctx) {
- qWarning("QGLShader being created without a context");
- return;
- }
-
- d->ctx = const_cast<QGLContext*>(ctx);
- d->ctx->makeCurrent();
-
- if (type == QGLShader::FragmentShader)
- d->shaderId = glCreateShader(GL_FRAGMENT_SHADER);
- else
- d->shaderId = glCreateShader(GL_VERTEX_SHADER);
-
- if (d->shaderId == 0) {
- qWarning("Error creating shader object");
- return;
- }
-
- d->type = type;
-}
-
-GLuint QGLShader::id()
-{
- Q_D(QGLShader);
- return d->shaderId;
-}
-
-const QGLContext* QGLShader::context()
-{
- Q_D(QGLShader);
- return d->ctx;
-}
-
-void QGLShader::clearSource()
-{
- Q_D(QGLShader);
- d->source.clear();
- d->valid = false;
-}
-
-void QGLShader::addSource(const QLatin1String& newSource)
-{
- Q_D(QGLShader);
- d->source += newSource;
- d->valid = false;
-}
-
-
-bool QGLShader::compile()
-{
- Q_D(QGLShader);
-
- d->valid = false;
-
- if (d->source.size() == 0)
- return false;
-
- const QByteArray src_ba = d->source.toAscii();
- const char* src = src_ba.constData();
-
- glShaderSource(d->shaderId, 1, &src, 0);
-
- glCompileShader(d->shaderId);
-
- GLint shaderCompiled;
- glGetShaderiv(d->shaderId, GL_COMPILE_STATUS, &shaderCompiled);
- if (!shaderCompiled)
- return false;
-
- d->valid = true;
- return true;
-}
-
-bool QGLShader::isValid()
-{
- Q_D(QGLShader);
- return d->valid;
-}
-
-QString QGLShader::log()
-{
- Q_D(QGLShader);
-
- char* logData;
- GLint logSize;
- GLint logLength;
-
- glGetShaderiv(d->shaderId, GL_INFO_LOG_LENGTH, &logSize);
-
- if (!logSize)
- return QString();
-
- logData = new char[logSize];
- glGetShaderInfoLog(d->shaderId, logSize, &logLength, logData);
- QString result = QString::fromAscii(logData);
- delete [] logData;
-
- return result;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-class QGLShaderProgramPrivate
-{
-public:
- QGLShaderProgramPrivate() : valid(false), programId(0), ctx(0) {}
- void populateVariableLists();
-
- QVector<QGLShader*> shaders;
- QGLUniformList uniforms;
- QGLVertexAttributeList attributeArrays;
- bool valid;
- GLuint programId;
- QGLContext* ctx;
-};
-
-
-
-void QGLShaderProgramPrivate::populateVariableLists()
-{
- attributeArrays.clear();
- uniforms.clear();
-
- int count;
- int sizeOfNameBuff;
- char* name;
- GLint nameLength;
- GLenum type;
- GLint size;
- GLint location;
-
- glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTES, &count);
- glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &sizeOfNameBuff);
- name = new char[sizeOfNameBuff];
-
- for (int i = 0; i < count; ++i) {
- nameLength = -1;
- glGetActiveAttrib(programId, i, sizeOfNameBuff, &nameLength, &size, &type, name);
- if (nameLength == -1)
- continue;
-
- location = glGetAttribLocation(programId, name);
- attributeArrays.insert(QString::fromAscii(name), QGLVertexAttribute(type, location, ctx));
- }
-
- delete [] name;
-
-
- glGetProgramiv(programId, GL_ACTIVE_UNIFORMS, &count);
- glGetProgramiv(programId, GL_ACTIVE_UNIFORM_MAX_LENGTH, &sizeOfNameBuff);
-
- name = new char[sizeOfNameBuff];
-
- for (int i = 0; i < count; ++i) {
- nameLength = -1;
- glGetActiveUniform(programId, i, sizeOfNameBuff, &nameLength, &size, &type, name);
- if (nameLength == -1)
- continue;
-
- location = glGetUniformLocation(programId, name);
- uniforms.insert(QString::fromAscii(name), QGLUniform(type, location, ctx));
- }
-}
-
-
-QGLShaderProgram::QGLShaderProgram(const QGLContext* ctx)
- : d_ptr(new QGLShaderProgramPrivate)
-{
- Q_D(QGLShaderProgram);
- if (!ctx)
- ctx = QGLContext::currentContext();
-
- if (!ctx) {
- qWarning("QGLShaderProgram being created without a context");
- return;
- }
-
- d->ctx = const_cast<QGLContext*>(ctx);
- d->ctx->makeCurrent();
-
- d->programId = glCreateProgram();
-
- d->valid = false;
-}
-
-
-const QGLUniformList & QGLShaderProgram::uniforms()
-{
- Q_D(QGLShaderProgram);
- return const_cast<const QGLUniformList&>(d->uniforms);
-}
-
-
-const QGLVertexAttributeList& QGLShaderProgram::vertexAttributes()
-{
- Q_D(QGLShaderProgram);
- return const_cast<const QGLVertexAttributeList&>(d->attributeArrays);
-}
-
-
-bool QGLShaderProgram::addShader(QGLShader* newShader)
-{
- Q_D(QGLShaderProgram);
- if (!newShader || !d->ctx)
- return false;
-
- if (newShader->context() != d->ctx) {
- qWarning("Shader object's context does not match program's context");
- return false;
- }
-
- if (!newShader->isValid())
- return false;
-
- QGLContext* ctx = d->ctx;
- if (!ctx)
- return false;
- ctx->makeCurrent();
-
- glAttachShader(d->programId, newShader->id());
-
- d->shaders.append(newShader);
- return true;
-}
-
-
-bool QGLShaderProgram::removeShader(QGLShader* oldShader)
-{
- Q_D(QGLShaderProgram);
-
- int idx = d->shaders.indexOf(oldShader);
-
- if (idx == -1)
- return false;
-
- d->shaders.remove(idx);
-
- QGLContext* ctx = d->ctx;
- if (!ctx)
- return false;
- ctx->makeCurrent();
-
- glDetachShader(d->programId, oldShader->id());
- return true;
-}
-
-
-bool QGLShaderProgram::removeAllShaders()
-{
- Q_D(QGLShaderProgram);
-
- QGLContext* ctx = d->ctx;
- if (!ctx)
- return false;
- ctx->makeCurrent();
-
- foreach (QGLShader* shader, d->shaders)
- glDetachShader(d->programId, shader->id());
-
- d->shaders.clear();
- return true;
-}
-
-#include <stdio.h>
-
-bool QGLShaderProgram::link()
-{
- Q_D(QGLShaderProgram);
-
- QGLContext* ctx = d->ctx;
- if (!ctx)
- return false;
- ctx->makeCurrent();
-
- glLinkProgram(d->programId);
-
-
- GLint linked;
- glGetProgramiv(d->programId, GL_LINK_STATUS, &linked);
-
- if (!linked)
- return false;
-
- d->populateVariableLists();
-
- d->valid = true;
- return true;
-}
-
-void QGLShaderProgram::use()
-{
- Q_D(QGLShaderProgram);
- if (!d->valid)
- return;
-
- glUseProgram(d->programId);
-}
-
-
-QString QGLShaderProgram::log()
-{
- Q_D(QGLShaderProgram);
-
- QGLContext* ctx = d->ctx;
- if (!ctx)
- return QString();
- ctx->makeCurrent();
-
- GLint logSize = -666;
- glGetProgramiv(d->programId, GL_INFO_LOG_LENGTH, &logSize);
-
- char* logData = new char[logSize];
- GLint logLength;
-
- glGetProgramInfoLog(d->programId, logSize, &logLength, logData);
-
- QString result = QString::fromAscii(logData);
- delete [] logData;
-
- return result;
-}
-
-GLuint QGLShaderProgram::id()
-{
- Q_D(QGLShaderProgram);
- return d->programId;
-}
-
-/////////////////////////////////////////////////////////////////////////
-
-
-
-
-QGLUniform::QGLUniform()
- : m_id(0), m_type(QGLInvalidType), ctx(0)
-{
- qWarning("Unknown uniform! Either the uniform doesn't exist or it was removed at shader link");
-}
-
-const QGLUniform& QGLUniform::operator=(const GLfloat& rhs) const
-{
- if (m_type != QGLFloatType)
- return *this;
-
- glUniform1f(m_id, rhs);
-
- return *this;
-}
-
-const QGLUniform& QGLUniform::operator=(const QGLVec2& rhs) const
-{
- if (m_type != QGLVec2Type)
- return *this;
-
- glUniform2fv(m_id, 1, (const GLfloat*)&rhs);
-
- return *this;
-}
-
-const QGLUniform& QGLUniform::operator=(const QSizeF& rhs) const
-{
- if (m_type != QGLVec2Type)
- return *this;
-
- glUniform2f(m_id, rhs.width(), rhs.height());
-
- return *this;
-}
-
-const QGLUniform& QGLUniform::operator=(const QPointF& rhs) const
-{
- if (m_type != QGLVec2Type)
- return *this;
-
- glUniform2f(m_id, rhs.x(), rhs.y());
-
- return *this;
-}
-
-const QGLUniform& QGLUniform::operator=(const QGLVec3& rhs) const
-{
- if (m_type != QGLVec3Type)
- return *this;
-
- glUniform3fv(m_id, 1, (const GLfloat*)&rhs);
-
- return *this;
-}
-
-const QGLUniform& QGLUniform::operator=(const QGLVec4& rhs) const
-{
- if (m_type != QGLVec4Type)
- return *this;
-
- glUniform4fv(m_id, 1, (const GLfloat*)&rhs);
-
- return *this;
-}
-
-const QGLUniform& QGLUniform::operator=(const QColor& rhs) const
-{
- if (m_type != QGLVec4Type)
- return *this;
-
- glUniform4f(m_id, rhs.redF(), rhs.greenF(), rhs.blueF(), rhs.alphaF());
-
- return *this;
-}
-
-const QGLUniform& QGLUniform::operator=(const GLfloat rhs[2][2]) const
-{
- if (m_type != QGLMat2Type)
- return *this;
-
- glUniformMatrix2fv(m_id, 1, GL_FALSE, (GLfloat*)rhs);
-
- return *this;
-}
-
-const QGLUniform& QGLUniform::operator=(const GLfloat rhs[3][3]) const
-{
- if (m_type != QGLMat3Type)
- return *this;
-
- glUniformMatrix3fv(m_id, 1, GL_FALSE, (GLfloat*)rhs);
-
- return *this;
-}
-
-// Transposes ready for GL
-const QGLUniform& QGLUniform::operator=(const QTransform& rhs) const
-{
- if (m_type != QGLMat3Type)
- return *this;
-
- GLfloat mat3[3][3] = {
- {rhs.m11(), rhs.m12(), rhs.m13()},
- {rhs.m21(), rhs.m22(), rhs.m23()},
- {rhs.m31(), rhs.m32(), rhs.m33()}
- };
-
- glUniformMatrix3fv(m_id, 1, GL_FALSE, (GLfloat*)mat3);
-
- return *this;
-}
-
-const QGLUniform& QGLUniform::operator=(const GLfloat rhs[4][4]) const
-{
- if (m_type != QGLMat4Type)
- return *this;
-
- glUniformMatrix4fv(m_id, 1, GL_FALSE, (GLfloat*)rhs);
-
- return *this;
-}
-
-const QGLUniform& QGLUniform::operator=(const GLuint& rhs) const
-{
- if ((m_type != QGLSampler2DType) || (m_type != QGLSamplerCubeType))
- return *this;
-
- glUniform1i(m_id, rhs);
-
- return *this;
-}
-
-
-
-
-/////////////////////////////////////////////////////////////////////////
-
-QGLVertexAttribute::QGLVertexAttribute()
- : m_id(0), m_type(QGLInvalidType), ctx(0)
-{
- qWarning("Unknown vertex attribute!");
-}
-
-void QGLVertexAttribute::enable() const
-{
- glEnableVertexAttribArray(m_id);
-}
-
-void QGLVertexAttribute::disable() const
-{
- glDisableVertexAttribArray(m_id);
-}
-
-// NOTE: Under PC emulation, QGLVec4Type is _always_ returned as the type, so this
-// method isn't very useful. I.e. The datatypes are needed to distinguish the different
-// sizes for the function signatures.
-const QGLVertexAttribute& QGLVertexAttribute::operator=(const GLfloat* rhs) const
-{
- int size = -1;
- if (m_type == QGLFloatType)
- size = 1;
- else if (m_type == QGLVec2Type)
- size = 2;
- else if (m_type == QGLVec3Type)
- size = 3;
- else if (m_type == QGLVec4Type)
- size = 4;
- else if (m_type == QGLMat2Type) //### Not sure if this is right for matrix attributes...
- size = 4;
- else if (m_type == QGLMat3Type) //### Not sure if this is right for matrix attributes...
- size = 9;
- else if (m_type == QGLMat4Type) //### Not sure if this is right for matrix attributes...
- size = 16;
- else
- return *this;
-
- glVertexAttribPointer(m_id, size, GL_FLOAT, GL_FALSE, 0, rhs);
-
- return *this;
-}
-
-const QGLVertexAttribute& QGLVertexAttribute::operator=(const QGLVec3* rhs) const
-{
- glVertexAttribPointer(m_id, 3, GL_FLOAT, GL_FALSE, 0, (GLfloat*)rhs);
-
- return *this;
-}
diff --git a/src/opengl/gl2paintengineex/qglshader_p.h b/src/opengl/gl2paintengineex/qglshader_p.h
deleted file mode 100644
index 016a400..0000000
--- a/src/opengl/gl2paintengineex/qglshader_p.h
+++ /dev/null
@@ -1,260 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
-** this package.
-**
-** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-/*
-Uniform Types in OpenGL ES 2.0
-==============================
-GL_FLOAT GLfloat GLfloat
-GL_FLOAT_VEC2 QGLVec2 GLfloat[2]
-GL_FLOAT_VEC3 QGLVec3 GLfloat[3]
-GL_FLOAT_VEC4 QGLVec4 GLfloat[4]
-GL_INT GLint GLint
-GL_INT_VEC2 QGLIVec2 GLint[2]
-GL_INT_VEC3 QGLIVec3 GLint[3]
-GL_INT_VEC4 QGLIVec4 GLint[4]
-GL_BOOL GLbool GLbool
-GL_BOOL_VEC2 QGLBVec2 GLbool[2]
-GL_BOOL_VEC3 QGLBVec3 GLbool[3]
-GL_BOOL_VEC4 QGLBVec4 GLbool[4]
-GL_FLOAT_MAT2 QGLMat2 GLfloat[2][2]
-GL_FLOAT_MAT3 QGLMat3 GLfloat[3][3]
-GL_FLOAT_MAT4 QGLMat4 GLfloat[4][4]
-GL_SAMPLER_2D QGLSampler2D GLuint
-GL_SAMPLER_CUBE QGLSamplerCube GLuint
-
-Additional Types in Desktop OpenGL 2.0
-======================================
-SAMPLER_1D,
-SAMPLER_3D,
-SAMPLER_1D_SHADOW,
-SAMPLER_2D_SHADOW.
-*/
-
-#include <QtOpenGL>
-
-
-typedef struct {
- GLfloat a;
- GLfloat b;
-} QGLVec2;
-
-typedef struct {
- GLfloat a;
- GLfloat b;
- GLfloat c;
-} QGLVec3;
-
-typedef struct {
- GLfloat a;
- GLfloat b;
- GLfloat c;
- GLfloat d;
-} QGLVec4;
-
-
-class QGLShaderProgram;
-
-class QGLShaderPrivate;
-
-class QGLShader : QObject
-{
- Q_OBJECT
-public:
- enum ShaderType {VertexShader, FragmentShader};
-
- QGLShader(ShaderType type, const QGLContext* ctx = 0);
-
- GLuint id();
- void clearSource();
- void addSource(const QLatin1String& newSource);
- bool compile();
- bool isValid();
- QString log();
- const QGLContext* context(); //maybe make private with prog a friend?
-
-private:
- QGLShaderPrivate* d_ptr;
- Q_DECLARE_PRIVATE(QGLShader);
-
-/*
-public slots:
- void cleanupGLContextRefs(const QGLContext *context);
-*/
-};
-
-
-enum QGLType {
- QGLInvalidType = 0,
- QGLFloatType = GL_FLOAT,
- QGLVec2Type = GL_FLOAT_VEC2,
- QGLVec3Type = GL_FLOAT_VEC3,
- QGLVec4Type = GL_FLOAT_VEC4,
- QGLIntType = GL_INT,
- QGLIVec2Type = GL_INT_VEC2,
- QGLIVec3Type = GL_INT_VEC3,
- QGLIVec4Type = GL_INT_VEC4,
- QGLBoolType = GL_BOOL,
- QGLBVec2Type = GL_BOOL_VEC2,
- QGLBVec3Type = GL_BOOL_VEC3,
- QGLBVec4Type = GL_BOOL_VEC4,
- QGLMat2Type = GL_FLOAT_MAT2,
- QGLMat3Type = GL_FLOAT_MAT3,
- QGLMat4Type = GL_FLOAT_MAT4,
- QGLSampler2DType = GL_SAMPLER_2D,
- QGLSamplerCubeType = GL_SAMPLER_CUBE
-};
-
-class QGLUniform
-{
-public:
-
- QGLUniform(GLenum glType, GLint location, QGLContext* context)
- : m_id(location), m_type(QGLType(glType)), ctx(context) {}
-
- QGLUniform(); // Called by QMap when there's no match on the name
-
- QGLType type() const {return m_type;}
- GLuint id() const {return m_id;}
-
- // Seems odd to be const, but it doesn't actually modify any of the
- // class members, only the GL state!
- const QGLUniform& operator=(const GLfloat&) const;
-
- const QGLUniform& operator=(const QGLVec2&) const;
- const QGLUniform& operator=(const QSizeF&) const;
- const QGLUniform& operator=(const QPointF&) const;
-
- const QGLUniform& operator=(const QGLVec3&) const;
-
- const QGLUniform& operator=(const QGLVec4&) const;
- const QGLUniform& operator=(const QColor&) const;
-
- const QGLUniform& operator=(const GLfloat[2][2]) const;
-
- const QGLUniform& operator=(const GLfloat[3][3]) const;
- const QGLUniform& operator=(const QTransform&) const;
-
- const QGLUniform& operator=(const GLfloat[4][4]) const;
-
- const QGLUniform& operator=(const GLuint&) const; // sampler2d, specifying a texture unit
-
-
-protected:
- GLuint m_id;
- QGLType m_type;
- QGLContext* ctx;
-};
-
-typedef QMap<QString, QGLUniform> QGLUniformList;
-typedef QMapIterator<QString, QGLUniform> QGLUniformListIterator;
-
-
-class QGLVertexAttribute
-{
-public:
- QGLVertexAttribute(GLenum glType, GLuint location, QGLContext* context)
- : m_id(location), m_type(QGLType(glType)), ctx(context) {}
-
- QGLVertexAttribute(); // Called by QMap when there's no match on the name
-
- QGLType type() const {return m_type;}
- GLuint id() const {return m_id;}
- void enable() const;
- void disable() const;
-
- const QGLVertexAttribute& operator=(const GLfloat* rhs) const;
- const QGLVertexAttribute& operator=(const QGLVec3* rhs) const;
-
-protected:
- GLuint m_id;
- QGLType m_type;
- QGLContext* ctx;
-};
-
-//TODO: Convert into setter overloads on QGLShaderProgram
-typedef QMap<QString, QGLVertexAttribute> QGLVertexAttributeList;
-typedef QMapIterator<QString, QGLVertexAttribute> QGLVertexAttributeListIterator;
-
-
-
-class QGLShaderProgramPrivate;
-
-class QGLShaderProgram : QObject
-{
- Q_OBJECT
-public:
- QGLShaderProgram(const QGLContext* ctx = 0);
-
- const QGLUniformList & uniforms();
- const QGLVertexAttributeList& vertexAttributes();
-
- bool addShader(QGLShader* newShader);
- bool removeShader(QGLShader* oldShader);
- bool removeAllShaders();
-
- bool link();
- QString log();
- bool isValid();
- void use();
-
- GLuint id();
-
-private:
- QGLShaderProgramPrivate* d_ptr;
- Q_DECLARE_PRIVATE(QGLShaderProgram);
-
-/*
-public slots:
- void cleanupGLContextRefs(const QGLContext *context);
-*/
-};
-
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index 9258477..f52ed92 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -62,6 +62,7 @@
and use the correct program when we really need it.
*/
+// #define QT_OPENGL_CACHE_AS_VBOS
#include "qpaintengineex_opengl2_p.h"
@@ -75,109 +76,292 @@
#include <private/qpainter_p.h>
#include <private/qfontengine_p.h>
#include <private/qtextureglyphcache_p.h>
+#include <private/qpixmapdata_gl_p.h>
+#include <private/qdatabuffer_p.h>
#include "qglgradientcache_p.h"
-#include "qglpexshadermanager_p.h"
+#include "qglengineshadermanager_p.h"
#include "qgl2pexvertexarray_p.h"
+#include "qtriangulatingstroker_p.h"
-extern QImage qt_imageForBrush(int brushStyle, bool invert); //in qbrush.cpp
+#include <QDebug>
+QT_BEGIN_NAMESPACE
-#include <QDebug>
+//#define QT_GL_NO_SCISSOR_TEST
+static const GLuint GL_STENCIL_HIGH_BIT = 0x80;
+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;
-static const GLuint QT_VERTEX_COORDS_ATTR = 0;
-static const GLuint QT_TEXTURE_COORDS_ATTR = 1;
-static const GLuint QT_BRUSH_TEXTURE_UNIT = 0;
+#ifdef Q_WS_WIN
+extern Q_GUI_EXPORT bool qt_cleartype_enabled;
+#endif
-class QGL2PaintEngineExPrivate : public QPaintEngineExPrivate
+class QGLTextureGlyphCache : public QObject, public QTextureGlyphCache
{
- Q_DECLARE_PUBLIC(QGL2PaintEngineEx)
+ Q_OBJECT
public:
- QGL2PaintEngineExPrivate(QGL2PaintEngineEx *q_ptr) :
- q(q_ptr),
- width(0), height(0),
- ctx(0),
- currentBrush( &(q->state()->brush) ),
- inverseScale(1),
- shaderManager(0)
- { }
+ QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix);
+ ~QGLTextureGlyphCache();
+
+ virtual void createTextureData(int width, int height);
+ virtual void resizeTextureData(int width, int height);
+ virtual void fillTexture(const Coord &c, glyph_t glyph);
+ virtual int glyphMargin() const;
+
+ inline GLuint texture() const { return m_texture; }
+
+ inline int width() const { return m_width; }
+ inline int height() const { return m_height; }
+
+ inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; }
+
+
+public Q_SLOTS:
+ void contextDestroyed(const QGLContext *context) {
+ if (context == ctx) {
+ QList<const QGLContext *> shares = qgl_share_reg()->shares(ctx);
+ if (shares.isEmpty()) {
+ glDeleteFramebuffers(1, &m_fbo);
+ if (m_width || m_height)
+ glDeleteTextures(1, &m_texture);
+ ctx = 0;
+ } else {
+ // since the context holding the texture is shared, and
+ // about to be destroyed, we have to transfer ownership
+ // of the texture to one of the share contexts
+ ctx = const_cast<QGLContext *>((ctx == shares.at(0)) ? shares.at(1) : shares.at(0));
+ }
+ }
+ }
- ~QGL2PaintEngineExPrivate();
+private:
+ QGLContext *ctx;
- void updateBrushTexture();
- void updateBrushUniforms();
- void updateMatrix();
- void updateCompositionMode();
- void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform);
+ QGL2PaintEngineExPrivate *pex;
- void setBrush(const QBrush* brush);
+ GLuint m_texture;
+ GLuint m_fbo;
- void drawTexture(const QGLRect& dest, const QGLRect& src, int txtWidth, int txtHeight);
+ int m_width;
+ int m_height;
- void fill(const QVectorPath &path);
- void drawOutline(const QVectorPath& path);
+ QGLShaderProgram *m_program;
+};
- void drawVertexArrays(QGL2PEXVertexArray& vertexArray, GLenum primitive);
- // ^ draws whatever is in the vertex array
- void composite(const QGLRect& boundingRect);
- // ^ Composites the bounding rect onto dest buffer
- void fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill);
- // ^ Calls drawVertexArrays to render into stencil buffer
- void cleanStencilBuffer(const QGLRect& area);
+QGLTextureGlyphCache::QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix)
+ : QTextureGlyphCache(type, matrix)
+ , ctx(context)
+ , m_width(0)
+ , m_height(0)
+{
+ glGenFramebuffers(1, &m_fbo);
+ connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)),
+ SLOT(contextDestroyed(const QGLContext*)));
+}
- void prepareForDraw();
+QGLTextureGlyphCache::~QGLTextureGlyphCache()
+{
+ if (ctx) {
+ QGLShareContextScope scope(ctx);
+ glDeleteFramebuffers(1, &m_fbo);
- inline void useSimpleShader();
- inline QColor premultiplyColor(QColor c, GLfloat opacity);
+ if (m_width || m_height)
+ glDeleteTextures(1, &m_texture);
+ }
+}
- QGL2PaintEngineEx* q;
+void QGLTextureGlyphCache::createTextureData(int width, int height)
+{
+ glGenTextures(1, &m_texture);
+ glBindTexture(GL_TEXTURE_2D, m_texture);
- //### Move into QGLDrawable
- int width, height;
- QGLContext* ctx;
+ m_width = width;
+ m_height = height;
- // Dirty flags
- bool matrixDirty; // Implies matrix uniforms are also dirty
- bool compositionModeDirty;
- bool brushTextureDirty;
- bool brushUniformsDirty;
- bool simpleShaderMatrixUniformDirty;
- bool brushShaderMatrixUniformDirty;
- bool imageShaderMatrixUniformDirty;
- bool textShaderMatrixUniformDirty;
- bool stencilBuferDirty;
+ QVarLengthArray<uchar> data(width * height);
+ for (int i = 0; i < data.size(); ++i)
+ data[i] = 0;
- const QBrush* currentBrush; // May not be the state's brush!
+ if (m_type == QFontEngineGlyphCache::Raster_RGBMask)
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
+ else
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
- GLfloat inverseScale;
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+}
- QGL2PEXVertexArray pathVertexArray;
+void QGLTextureGlyphCache::resizeTextureData(int width, int height)
+{
+ // ### the QTextureGlyphCache API needs to be reworked to allow
+ // ### resizeTextureData to fail
- GLfloat pmvMatrix[4][4];
+ int oldWidth = m_width;
+ int oldHeight = m_height;
- QGLPEXShaderManager* shaderManager;
+ GLuint oldTexture = m_texture;
+ createTextureData(width, height);
- // Clipping & state stuff stolen from QOpenGLPaintEngine:
- void updateDepthClip();
- uint use_system_clip : 1;
-};
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo);
+ GLuint tmp_texture;
+ glGenTextures(1, &tmp_texture);
+ glBindTexture(GL_TEXTURE_2D, tmp_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, tmp_texture, 0);
+
+ glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
+ glBindTexture(GL_TEXTURE_2D, oldTexture);
+
+ pex->transferMode(BrushDrawingMode);
+
+#ifndef QT_OPENGL_ES_2
+ if (pex->inRenderText)
+ glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT | GL_SCISSOR_BIT);
+#endif
+
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_BLEND);
+
+ glViewport(0, 0, oldWidth, oldHeight);
+
+ float vertexCoordinateArray[] = { -1, -1, 1, -1, 1, 1, -1, 1 };
+ float textureCoordinateArray[] = { 0, 0, 1, 0, 1, 1, 0, 1 };
+
+ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
+
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray);
+ glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray);
+
+ pex->shaderManager->blitProgram()->bind();
+ pex->shaderManager->blitProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT);
+ pex->shaderManager->setDirty();
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
+
+ glBindTexture(GL_TEXTURE_2D, m_texture);
+
+#ifdef QT_OPENGL_ES_2
+ QDataBuffer<uchar> buffer(4*oldWidth*oldHeight);
+ buffer.resize(4*oldWidth*oldHeight);
+ glReadPixels(0, 0, oldWidth, oldHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
+
+ // do an in-place conversion from GL_RGBA to GL_ALPHA
+ for (int i=0; i<oldWidth*oldHeight; ++i)
+ buffer.data()[i] = buffer.at(4*i + 3);
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight,
+ GL_ALPHA, GL_UNSIGNED_BYTE, buffer.data());
+#else
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
+#endif
+
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT, 0);
+ glDeleteTextures(1, &tmp_texture);
+ glDeleteTextures(1, &oldTexture);
+
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
+
+ glViewport(0, 0, pex->width, pex->height);
+ pex->updateClipScissorTest();
+
+#ifndef QT_OPENGL_ES_2
+ if (pex->inRenderText)
+ glPopAttrib();
+#endif
+}
+
+void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph)
+{
+ QImage mask = textureMapForGlyph(glyph);
+ const int maskWidth = mask.width();
+ const int maskHeight = mask.height();
+
+ if (mask.format() == QImage::Format_Mono) {
+ mask = mask.convertToFormat(QImage::Format_Indexed8);
+ for (int y = 0; y < maskHeight; ++y) {
+ uchar *src = (uchar *) mask.scanLine(y);
+ for (int x = 0; x < maskWidth; ++x)
+ src[x] = -src[x]; // convert 0 and 1 into 0 and 255
+ }
+ }
+
+
+ glBindTexture(GL_TEXTURE_2D, m_texture);
+ if (mask.format() == QImage::Format_RGB32) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits());
+ } else {
+#ifdef QT_OPENGL_ES2
+ glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_ALPHA, GL_UNSIGNED_BYTE, mask.bits());
+#else
+ // glTexSubImage2D() might cause some garbage to appear in the texture if the mask width is
+ // not a multiple of four bytes. The bug appeared on a computer with 32-bit Windows Vista
+ // and nVidia GeForce 8500GT. GL_UNPACK_ALIGNMENT is set to four bytes, 'mask' has a
+ // multiple of four bytes per line, and most of the glyph shows up correctly in the
+ // texture, which makes me think that this is a driver bug.
+ // One workaround is to make sure the mask width is a multiple of four bytes, for instance
+ // by converting it to a format with four bytes per pixel. Another is to copy one line at a
+ // time.
+
+ for (int i = 0; i < maskHeight; ++i)
+ glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, maskWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, mask.scanLine(i));
+#endif
+ }
+}
+
+int QGLTextureGlyphCache::glyphMargin() const
+{
+#if defined(Q_WS_MAC)
+ return 2;
+#elif defined (Q_WS_X11)
+ return 0;
+#else
+ return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0;
+#endif
+}
+
+extern QImage qt_imageForBrush(int brushStyle, bool invert);
////////////////////////////////// Private Methods //////////////////////////////////////////
QGL2PaintEngineExPrivate::~QGL2PaintEngineExPrivate()
{
- if (shaderManager) {
- delete shaderManager;
- shaderManager = 0;
+ delete shaderManager;
+
+ while (pathCaches.size()) {
+ QVectorPath::CacheEntry *e = *(pathCaches.constBegin());
+ e->cleanup(e->engine, e->data);
+ e->data = 0;
+ e->engine = 0;
}
}
-void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform)
+void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id)
{
- glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
+// glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); //### Is it always this texture unit?
+ if (id != GLuint(-1) && id == lastTexture)
+ return;
+
+ lastTexture = id;
if (smoothPixmapTransform) {
glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -191,80 +375,93 @@ void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMod
}
-QColor QGL2PaintEngineExPrivate::premultiplyColor(QColor c, GLfloat opacity)
+inline QColor qt_premultiplyColor(QColor c, GLfloat opacity)
{
- uint alpha = qRound(c.alpha() * opacity);
- return QColor ( ((c.red() * alpha + 128) >> 8),
- ((c.green() * alpha + 128) >> 8),
- ((c.blue() * alpha + 128) >> 8),
- alpha);
+ qreal alpha = c.alphaF() * opacity;
+ c.setAlphaF(alpha);
+ c.setRedF(c.redF() * alpha);
+ c.setGreenF(c.greenF() * alpha);
+ c.setBlueF(c.blueF() * alpha);
+ return c;
}
-void QGL2PaintEngineExPrivate::setBrush(const QBrush* brush)
+void QGL2PaintEngineExPrivate::setBrush(const QBrush& brush)
{
+ Q_ASSERT(brush.style() != Qt::NoBrush);
+
+ if (qbrush_fast_equals(currentBrush, brush))
+ return;
+
currentBrush = brush;
+
brushTextureDirty = true;
brushUniformsDirty = true;
- shaderManager->setBrushStyle(currentBrush->style());
- shaderManager->setAffineOnlyBrushTransform(currentBrush->transform().isAffine());
+ if (currentBrush.style() == Qt::TexturePattern
+ && qHasPixmapTexture(brush) && brush.texture().isQBitmap())
+ {
+ shaderManager->setSrcPixelType(QGLEngineShaderManager::TextureSrcWithPattern);
+ } else {
+ shaderManager->setSrcPixelType(currentBrush.style());
+ }
+ shaderManager->optimiseForBrushTransform(currentBrush.transform());
}
-// Unless this gets used elsewhere, it's probably best to merge it into fillStencilWithVertexArray
void QGL2PaintEngineExPrivate::useSimpleShader()
{
- shaderManager->simpleShader()->use();
+ shaderManager->simpleProgram()->bind();
+ shaderManager->setDirty();
if (matrixDirty)
updateMatrix();
if (simpleShaderMatrixUniformDirty) {
- shaderManager->simpleShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix;
+ shaderManager->simpleProgram()->setUniformValue("pmvMatrix", pmvMatrix);
simpleShaderMatrixUniformDirty = false;
}
}
-
-Q_GLOBAL_STATIC(QGLGradientCache, qt_opengl_gradient_cache)
-
void QGL2PaintEngineExPrivate::updateBrushTexture()
{
+ Q_Q(QGL2PaintEngineEx);
// qDebug("QGL2PaintEngineExPrivate::updateBrushTexture()");
- Qt::BrushStyle style = currentBrush->style();
+ Qt::BrushStyle style = currentBrush.style();
if ( (style >= Qt::Dense1Pattern) && (style <= Qt::DiagCrossPattern) ) {
// Get the image data for the pattern
- QImage texImage = qt_imageForBrush(style, true);
+ QImage texImage = qt_imageForBrush(style, false);
- glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
- ctx->d_func()->bindTexture(texImage, GL_TEXTURE_2D, GL_RGBA, true);
- updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true);
+ glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT);
+ ctx->d_func()->bindTexture(texImage, GL_TEXTURE_2D, GL_RGBA, true, QGLContext::InternalBindOption);
+ updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform);
}
else if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) {
// Gradiant brush: All the gradiants use the same texture
- const QGradient* g = currentBrush->gradient();
+ const QGradient* g = currentBrush.gradient();
// We apply global opacity in the fragment shaders, so we always pass 1.0
// for opacity to the cache.
- GLuint texId = qt_opengl_gradient_cache()->getBuffer(*g, 1.0, ctx);
+ GLuint texId = QGL2GradientCache::cacheForContext(ctx)->getBuffer(*g, 1.0);
+
+ glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT);
+ glBindTexture(GL_TEXTURE_2D, texId);
if (g->spread() == QGradient::RepeatSpread || g->type() == QGradient::ConicalGradient)
- updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true);
+ updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform);
else if (g->spread() == QGradient::ReflectSpread)
- updateTextureFilter(GL_TEXTURE_2D, GL_MIRRORED_REPEAT_IBM, true);
+ updateTextureFilter(GL_TEXTURE_2D, GL_MIRRORED_REPEAT_IBM, q->state()->renderHints & QPainter::SmoothPixmapTransform);
else
- updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, true);
-
- glBindTexture(GL_TEXTURE_2D, texId);
+ updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, q->state()->renderHints & QPainter::SmoothPixmapTransform);
}
else if (style == Qt::TexturePattern) {
- const QPixmap& texPixmap = currentBrush->texture();
+ const QPixmap& texPixmap = currentBrush.texture();
- glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
- ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, true);
- updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true);
+ glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT);
+ QGLTexture *tex = ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption);
+ updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform);
+ textureInvertedY = tex->options & QGLContext::InvertedYBindOption ? -1 : 1;
}
brushTextureDirty = false;
}
@@ -273,40 +470,31 @@ void QGL2PaintEngineExPrivate::updateBrushTexture()
void QGL2PaintEngineExPrivate::updateBrushUniforms()
{
// qDebug("QGL2PaintEngineExPrivate::updateBrushUniforms()");
- Qt::BrushStyle style = currentBrush->style();
+ Qt::BrushStyle style = currentBrush.style();
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();
+ QTransform brushQTransform = currentBrush.transform();
if (style == Qt::SolidPattern) {
- QColor col = premultiplyColor(currentBrush->color(), opacity);
- shaderManager->brushShader()->uniforms()[QLatin1String("fragmentColor")] = col;
- setOpacity = false;
+ QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::FragmentColor), col);
}
else {
// All other brushes have a transform and thus need the translation point:
QPointF translationPoint;
if (style <= Qt::DiagCrossPattern) {
- translationPoint = q->state()->brushOrigin;
+ QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity);
- QColor col = premultiplyColor(currentBrush->color(), opacity);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
- shaderManager->brushShader()->uniforms()[QLatin1String("patternColor")] = col;
- setOpacity = false; //So code below doesn't try to set the opacity uniform
-
- 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(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
}
else if (style == Qt::LinearGradientPattern) {
- const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush->gradient());
+ const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush.gradient());
QPointF realStart = g->start();
QPointF realFinal = g->finalStop();
@@ -314,71 +502,77 @@ 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(location(QGLEngineShaderManager::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(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
}
else if (style == Qt::ConicalGradientPattern) {
- const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrush->gradient());
+ const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrush.gradient());
translationPoint = g->center();
GLfloat angle = -(g->angle() * 2 * Q_PI) / 360.0;
- shaderManager->brushShader()->uniforms()[QLatin1String("angle")] = angle;
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::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(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
}
else if (style == Qt::RadialGradientPattern) {
- const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush->gradient());
+ const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush.gradient());
QPointF realCenter = g->center();
QPointF realFocal = g->focalPoint();
qreal realRadius = g->radius();
translationPoint = realFocal;
QPointF fmp = realCenter - realFocal;
- shaderManager->brushShader()->uniforms()[QLatin1String("fmp")] = fmp;
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::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(location(QGLEngineShaderManager::Fmp2MRadius2), fmp2_m_radius2);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Inverse2Fmp2MRadius2),
+ 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(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
}
else if (style == Qt::TexturePattern) {
- translationPoint = q->state()->brushOrigin;
+ const QPixmap& texPixmap = currentBrush.texture();
- const QPixmap& texPixmap = currentBrush->texture();
+ if (qHasPixmapTexture(currentBrush) && currentBrush.texture().isQBitmap()) {
+ QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
+ }
- QSizeF invertedTextureSize( 1.0 / texPixmap.width(), 1.0 / texPixmap.height() );
- shaderManager->brushShader()->uniforms()[QLatin1String("invertedTextureSize")] = invertedTextureSize;
+ QSizeF invertedTextureSize(1.0 / texPixmap.width(), 1.0 / texPixmap.height());
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::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(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
}
else
qWarning("QGL2PaintEngineEx: Unimplemented fill style");
+ const QPointF &brushOrigin = q->state()->brushOrigin;
+ QTransform matrix = q->state()->matrix;
+ matrix.translate(brushOrigin.x(), brushOrigin.y());
+
QTransform translate(1, 0, 0, 1, -translationPoint.x(), -translationPoint.y());
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;
+ QTransform inv_matrix;
+ if (style == Qt::TexturePattern && textureInvertedY == -1)
+ inv_matrix = gl_to_qt * (QTransform(1, 0, 0, -1, 0, currentBrush.texture().height()) * brushQTransform * matrix).inverted() * translate;
+ else
+ inv_matrix = gl_to_qt * (brushQTransform * matrix).inverted() * translate;
- if (setOpacity)
- shaderManager->brushShader()->uniforms()[QLatin1String("opacity")] = opacity;
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BrushTransform), inv_matrix);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BrushTexture), QT_BRUSH_TEXTURE_UNIT);
}
brushUniformsDirty = false;
}
@@ -389,32 +583,37 @@ void QGL2PaintEngineExPrivate::updateMatrix()
{
// qDebug("QGL2PaintEngineExPrivate::updateMatrix()");
- // We setup the Projection matrix to be the equivilant of glOrtho(0, w, h, 0, -1, 1):
- GLfloat P[4][4] = {
- {2.0/width, 0.0, 0.0, -1.0},
- {0.0, -2.0/height, 0.0, 1.0},
- {0.0, 0.0, -1.0, 0.0},
- {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];
- }
- }
+ // The projection matrix converts from Qt's coordinate system to GL's coordinate system
+ // * GL's viewport is 2x2, Qt's is width x height
+ // * GL has +y -> -y going from bottom -> top, Qt is the other way round
+ // * GL has [0,0] in the center, Qt has it in the top-left
+ //
+ // This results in the Projection matrix below, which is multiplied by the painter's
+ // transformation matrix, as shown below:
+ //
+ // Projection Matrix Painter Transform
+ // ------------------------------------------------ ------------------------
+ // | 2.0 / width | 0.0 | -1.0 | | m11 | m21 | dx |
+ // | 0.0 | -2.0 / height | 1.0 | * | m12 | m22 | dy |
+ // | 0.0 | 0.0 | 1.0 | | m13 | m23 | m33 |
+ // ------------------------------------------------ ------------------------
+ //
+ // NOTE: The resultant matrix is also transposed, as GL expects column-major matracies
+
+ const GLfloat wfactor = 2.0f / width;
+ const GLfloat hfactor = -2.0f / height;
+
+ pmvMatrix[0][0] = (wfactor * transform.m11()) - transform.m13();
+ pmvMatrix[1][0] = (wfactor * transform.m21()) - transform.m23();
+ pmvMatrix[2][0] = (wfactor * transform.dx() ) - transform.m33();
+ pmvMatrix[0][1] = (hfactor * transform.m12()) + transform.m13();
+ pmvMatrix[1][1] = (hfactor * transform.m22()) + transform.m23();
+ pmvMatrix[2][1] = (hfactor * transform.dy() ) + transform.m33();
+ pmvMatrix[0][2] = transform.m13();
+ pmvMatrix[1][2] = transform.m23();
+ pmvMatrix[2][2] = transform.m33();
// 1/10000 == 0.0001, so we have good enough res to cover curves
// that span the entire widget...
@@ -426,9 +625,10 @@ void QGL2PaintEngineExPrivate::updateMatrix()
// The actual data has been updated so both shader program's uniforms need updating
simpleShaderMatrixUniformDirty = true;
- brushShaderMatrixUniformDirty = true;
- imageShaderMatrixUniformDirty = true;
- textShaderMatrixUniformDirty = true;
+ shaderMatrixUniformDirty = true;
+
+ dasher.setInvScale(inverseScale);
+ stroker.setInvScale(inverseScale);
}
@@ -485,221 +685,514 @@ void QGL2PaintEngineExPrivate::updateCompositionMode()
compositionModeDirty = false;
}
+static inline void setCoords(GLfloat *coords, const QGLRect &rect)
+{
+ coords[0] = rect.left;
+ coords[1] = rect.top;
+ coords[2] = rect.right;
+ coords[3] = rect.top;
+ coords[4] = rect.right;
+ coords[5] = rect.bottom;
+ coords[6] = rect.left;
+ coords[7] = rect.bottom;
+}
-void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& src, int txtWidth, int txtHeight)
+void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern)
{
-// qDebug("QGL2PaintEngineExPrivate::drawImage()");
+ // Setup for texture drawing
+ shaderManager->setSrcPixelType(pattern ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc);
+ if (prepareForDraw(opaque))
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
+
+ if (pattern) {
+ QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
+ }
- // We have a shader specifically for drawPixmap/drawImage...
- shaderManager->imageShader()->use();
+ GLfloat dx = 1.0 / textureSize.width();
+ GLfloat dy = 1.0 / textureSize.height();
- updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
+ QGLRect srcTextureRect(src.left*dx, src.top*dy, src.right*dx, src.bottom*dy);
- if (compositionModeDirty)
- updateCompositionMode();
+ setCoords(staticVertexCoordinateArray, dest);
+ setCoords(staticTextureCoordinateArray, srcTextureRect);
- if (matrixDirty)
- updateMatrix();
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+}
- if (imageShaderMatrixUniformDirty) {
- shaderManager->imageShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix;
- imageShaderMatrixUniformDirty = false;
- }
+void QGL2PaintEngineEx::beginNativePainting()
+{
+ Q_D(QGL2PaintEngineEx);
+ ensureActive();
+ d->transferMode(BrushDrawingMode);
- shaderManager->imageShader()->uniforms()[QLatin1String("textureSampler")] = QT_BRUSH_TEXTURE_UNIT;
+ QGLContext *ctx = d->ctx;
+ glUseProgram(0);
-// if (q->state()->opacity < 0.99f)
- shaderManager->imageShader()->uniforms()[QLatin1String("opacity")] = (GLfloat)q->state()->opacity;
+#ifndef QT_OPENGL_ES_2
+ // be nice to people who mix OpenGL 1.x code with QPainter commands
+ // by setting modelview and projection matrices to mirror the GL 1
+ // paint engine
+ const QTransform& mtx = state()->matrix;
- GLfloat vertexCoords[] = {
- dest.left, dest.top,
- dest.left, dest.bottom,
- dest.right, dest.bottom,
- dest.right, dest.top
+ float mv_matrix[4][4] =
+ {
+ { mtx.m11(), mtx.m12(), 0, mtx.m13() },
+ { mtx.m21(), mtx.m22(), 0, mtx.m23() },
+ { 0, 0, 1, 0 },
+ { mtx.dx(), mtx.dy(), 0, mtx.m33() }
};
- glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
- glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords);
+ const QSize sz = d->device->size();
- GLfloat dx = 1.0 / txtWidth;
- GLfloat dy = 1.0 / txtHeight;
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, sz.width(), sz.height(), 0, -999999, 999999);
- QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadMatrixf(&mv_matrix[0][0]);
+#else
+ Q_UNUSED(ctx);
+#endif
- GLfloat textureCoords[] = {
- srcTextureRect.left, srcTextureRect.top,
- srcTextureRect.left, srcTextureRect.bottom,
- srcTextureRect.right, srcTextureRect.bottom,
- srcTextureRect.right, srcTextureRect.top
- };
+ d->lastTexture = GLuint(-1);
+ d->dirtyStencilRegion = QRect(0, 0, d->width, d->height);
+ d->resetGLState();
- glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
- glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoords);
+ d->shaderManager->setDirty();
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ d->needsSync = true;
+}
- glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
- glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+void QGL2PaintEngineExPrivate::resetGLState()
+{
+ glDisable(GL_BLEND);
+ glActiveTexture(GL_TEXTURE0);
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glDepthMask(true);
+ glDepthFunc(GL_LESS);
+ glClearDepth(1);
}
+void QGL2PaintEngineEx::endNativePainting()
+{
+ Q_D(QGL2PaintEngineEx);
+ d->needsSync = true;
+}
-void QGL2PaintEngineExPrivate::drawOutline(const QVectorPath& path)
+const QGLContext *QGL2PaintEngineEx::context()
{
-// qDebug("QGL2PaintEngineExPrivate::drawOutline()");
- if (matrixDirty)
- updateMatrix();
+ Q_D(QGL2PaintEngineEx);
+ return d->ctx;
+}
- pathVertexArray.clear();
- pathVertexArray.addPath(path, inverseScale);
+void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
+{
+ if (newMode == mode)
+ return;
- if (path.hasImplicitClose()) {
- // Close the path's outline
- pathVertexArray.lineToArray(path.points()[0], path.points()[1]);
- pathVertexArray.stops().last() += 1;
+ if (mode == TextDrawingMode || mode == ImageDrawingMode || mode == ImageArrayDrawingMode) {
+ glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
+ glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glDisableVertexAttribArray(QT_OPACITY_ATTR);
+
+ lastTexture = GLuint(-1);
}
- prepareForDraw();
- drawVertexArrays(pathVertexArray, GL_LINE_STRIP);
+ if (newMode == TextDrawingMode) {
+ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
+
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data());
+ glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data());
+ }
+
+ if (newMode == ImageDrawingMode) {
+ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
+
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticVertexCoordinateArray);
+ glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticTextureCoordinateArray);
+ }
+
+ if (newMode == ImageArrayDrawingMode) {
+ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
+ glEnableVertexAttribArray(QT_OPACITY_ATTR);
+
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data());
+ glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data());
+ glVertexAttribPointer(QT_OPACITY_ATTR, 1, GL_FLOAT, GL_FALSE, 0, opacityArray.data());
+ }
+
+ // This needs to change when we implement high-quality anti-aliasing...
+ if (newMode != TextDrawingMode)
+ shaderManager->setMaskType(QGLEngineShaderManager::NoMask);
+
+ mode = newMode;
}
+struct QGL2PEVectorPathCache
+{
+#ifdef QT_OPENGL_CACHE_AS_VBOS
+ GLuint vbo;
+#else
+ float *vertices;
+#endif
+ int vertexCount;
+ GLenum primitiveType;
+ qreal iscale;
+};
+
+void qopengl2paintengine_cleanup_vectorpath(QPaintEngineEx *engine, void *data)
+{
+ QGL2PEVectorPathCache *c = (QGL2PEVectorPathCache *) data;
+#ifdef QT_OPENGL_CACHE_AS_VBOS
+ QGL2PaintEngineExPrivate *d = QGL2PaintEngineExPrivate::getData((QGL2PaintEngineEx *) engine);
+ d->unusedVBOSToClean << c->vbo;
+#else
+ qFree(c->vertices);
+#endif
+ delete c;
+}
// 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);
- }
- else {
+ } else if (path.isConvex()) {
+
+ if (path.isCacheable()) {
+ QVectorPath::CacheEntry *data = path.lookupCacheData(q);
+ QGL2PEVectorPathCache *cache;
+
+ if (data) {
+ cache = (QGL2PEVectorPathCache *) data->data;
+ // Check if scale factor is exceeded for curved paths and generate curves if so...
+ if (path.isCurved()) {
+ qreal scaleFactor = cache->iscale / inverseScale;
+ if (scaleFactor < 0.5 || scaleFactor > 2.0) {
+#ifdef QT_OPENGL_CACHE_AS_VBOS
+ glDeleteBuffers(1, &cache->vbo);
+ cache->vbo = 0;
+#else
+ qFree(cache->vertices);
+#endif
+ cache->vertexCount = 0;
+ }
+ }
+ } else {
+ cache = new QGL2PEVectorPathCache;
+ cache->vertexCount = 0;
+ data = const_cast<QVectorPath &>(path).addCacheData(q, cache, qopengl2paintengine_cleanup_vectorpath);
+ }
+
+ // Flatten the path at the current scale factor and fill it into the cache struct.
+ if (!cache->vertexCount) {
+ vertexCoordinateArray.clear();
+ vertexCoordinateArray.addPath(path, inverseScale, false);
+ int vertexCount = vertexCoordinateArray.vertexCount();
+ int floatSizeInBytes = vertexCount * 2 * sizeof(float);
+ cache->vertexCount = vertexCount;
+ cache->primitiveType = GL_TRIANGLE_FAN;
+ cache->iscale = inverseScale;
+#ifdef QT_OPENGL_CACHE_AS_VBOS
+ glGenBuffers(1, &cache->vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
+ glBufferData(GL_ARRAY_BUFFER, floatSizeInBytes, vertexCoordinateArray.data(), GL_STATIC_DRAW);
+#else
+ cache->vertices = (float *) qMalloc(floatSizeInBytes);
+ memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes);
+#endif
+ }
+
+ prepareForDraw(currentBrush.isOpaque());
+ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+#ifdef QT_OPENGL_CACHE_AS_VBOS
+ glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, 0);
+#else
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, cache->vertices);
+#endif
+ glDrawArrays(cache->primitiveType, 0, cache->vertexCount);
+
+ } else {
+ // printf(" - Marking path as cachable...\n");
+ // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable
+ // ### Remove before release...
+ static bool do_vectorpath_cache = qgetenv("QT_OPENGL_NO_PATH_CACHE").isEmpty();
+ if (do_vectorpath_cache)
+ path.makeCacheable();
+ vertexCoordinateArray.clear();
+ vertexCoordinateArray.addPath(path, inverseScale, false);
+ 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, false);
+
+ fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill());
+
+ glStencilMask(0xff);
+ glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
+
+ if (q->state()->clipTestEnabled) {
+ // Pass when high bit is set, replace stencil value with current clip
+ glStencilFunc(GL_NOTEQUAL, q->state()->currentClip, GL_STENCIL_HIGH_BIT);
+ } else if (path.hasWindingFill()) {
+ // Pass when any bit is set, replace stencil value with 0
+ glStencilFunc(GL_NOTEQUAL, 0, 0xff);
+ } else {
+ // Pass when high bit is set, replace stencil value with 0
+ glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
+ }
- fillStencilWithVertexArray(pathVertexArray, path.hasWindingFill());
+ prepareForDraw(currentBrush.isOpaque());
+
+ if (inRenderText)
+ prepareDepthRangeForRenderText();
// 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());
- glDisable(GL_STENCIL_TEST);
+ composite(vertexCoordinateArray.boundingRect());
+
+ if (inRenderText)
+ restoreDepthRangeForRenderText();
- cleanStencilBuffer(pathVertexArray.boundingRect());
+ glStencilMask(0);
+
+ updateClipScissorTest();
}
}
-void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill)
+void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data,
+ int count,
+ int *stops,
+ int stopCount,
+ const QGLRect &bounds,
+ StencilFillMode mode)
{
+ Q_ASSERT(count || stops);
+
// qDebug("QGL2PaintEngineExPrivate::fillStencilWithVertexArray()");
- if (stencilBuferDirty) {
- // Clear the stencil buffer to zeros
- glDisable(GL_STENCIL_TEST);
- glStencilMask(0xFFFF); // Enable writing to stencil buffer, otherwise glClear wont do anything.
+ glStencilMask(0xff); // Enable stencil writes
+
+ if (dirtyStencilRegion.intersects(currentScissorBounds)) {
+ QVector<QRect> clearRegion = dirtyStencilRegion.intersected(currentScissorBounds).rects();
glClearStencil(0); // Clear to zero
- glClear(GL_STENCIL_BUFFER_BIT);
- stencilBuferDirty = false;
+ for (int i = 0; i < clearRegion.size(); ++i) {
+#ifndef QT_GL_NO_SCISSOR_TEST
+ setScissor(clearRegion.at(i));
+#endif
+ glClear(GL_STENCIL_BUFFER_BIT);
+ }
+
+ dirtyStencilRegion -= currentScissorBounds;
+
+#ifndef QT_GL_NO_SCISSOR_TEST
+ updateClipScissorTest();
+#endif
}
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes
- glStencilMask(0xFFFF); // Enable stencil writes
- glStencilFunc(GL_ALWAYS, 0, 0xFFFF); // Always pass the stencil test
-
- // Setup the stencil op:
- if (useWindingFill) {
- glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); // Inc. for front-facing triangle
- glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); //Dec. for back-facing "holes"
- } else
- glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit
-
- // No point in using a fancy gradiant shader for writing into the stencil buffer!
useSimpleShader();
-
glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d
- glDisable(GL_BLEND);
- // Draw the vertecies into the stencil buffer:
- drawVertexArrays(vertexArray, GL_TRIANGLE_FAN);
+#ifndef QT_OPENGL_ES_2
+ if (inRenderText) {
+ glPushAttrib(GL_ENABLE_BIT);
+ glDisable(GL_DEPTH_TEST);
+ }
+#endif
+
+ if (mode == WindingFillMode) {
+ Q_ASSERT(stops && !count);
+ if (q->state()->clipTestEnabled) {
+ // Flatten clip values higher than current clip, and set high bit to match current clip
+ glStencilFunc(GL_LEQUAL, GL_STENCIL_HIGH_BIT | q->state()->currentClip, ~GL_STENCIL_HIGH_BIT);
+ glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
+ composite(bounds);
+
+ glStencilFunc(GL_EQUAL, GL_STENCIL_HIGH_BIT, GL_STENCIL_HIGH_BIT);
+ } else if (!stencilClean) {
+ // Clear stencil buffer within bounding rect
+ glStencilFunc(GL_ALWAYS, 0, 0xff);
+ glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
+ composite(bounds);
+ }
+
+ // Inc. for front-facing triangle
+ glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP);
+ // Dec. for back-facing "holes"
+ glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_DECR_WRAP);
+ glStencilMask(~GL_STENCIL_HIGH_BIT);
+ drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN);
+
+ if (q->state()->clipTestEnabled) {
+ // Clear high bit of stencil outside of path
+ glStencilFunc(GL_EQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT);
+ glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
+ glStencilMask(GL_STENCIL_HIGH_BIT);
+ composite(bounds);
+ }
+ } else if (mode == OddEvenFillMode) {
+ glStencilMask(GL_STENCIL_HIGH_BIT);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit
+ drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN);
+
+ } else { // TriStripStrokeFillMode
+ Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops
+ glStencilMask(GL_STENCIL_HIGH_BIT);
+#if 0
+ glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit
+ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
+ glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+#else
+
+ glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+ if (q->state()->clipTestEnabled) {
+ glStencilFunc(GL_LEQUAL, q->state()->currentClip | GL_STENCIL_HIGH_BIT,
+ ~GL_STENCIL_HIGH_BIT);
+ } else {
+ glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff);
+ }
+ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
+ glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+#endif
+ }
// Enable color writes & disable stencil writes
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- glStencilMask(0);
+
+#ifndef QT_OPENGL_ES_2
+ if (inRenderText)
+ glPopAttrib();
+#endif
+
}
-void QGL2PaintEngineExPrivate::cleanStencilBuffer(const QGLRect& area)
+/*
+ If the maximum value in the stencil buffer is GL_STENCIL_HIGH_BIT - 1,
+ restore the stencil buffer to a pristine state. The current clip region
+ is set to 1, and the rest to 0.
+*/
+void QGL2PaintEngineExPrivate::resetClipIfNeeded()
{
-// qDebug("QGL2PaintEngineExPrivate::cleanStencilBuffer()");
- useSimpleShader();
-
- GLfloat rectVerts[] = {
- area.left, area.top,
- area.left, area.bottom,
- area.right, area.bottom,
- area.right, area.top
- };
+ if (maxClip != (GL_STENCIL_HIGH_BIT - 1))
+ return;
- glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
- glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, rectVerts);
+ Q_Q(QGL2PaintEngineEx);
+ useSimpleShader();
glEnable(GL_STENCIL_TEST);
- glStencilFunc(GL_ALWAYS, 0, 0xFFFF); // Always pass the stencil test
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
- glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes
- glStencilMask(0xFFFF); // Enable writing to stencil buffer
- glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); // Write 0's to stencil buffer
+ QRectF bounds = q->state()->matrix.inverted().mapRect(QRectF(0, 0, width, height));
+ QGLRect rect(bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
- glDisable(GL_BLEND);
+ // Set high bit on clip region
+ glStencilFunc(GL_LEQUAL, q->state()->currentClip, 0xff);
+ glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT);
+ glStencilMask(GL_STENCIL_HIGH_BIT);
+ composite(rect);
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ // Reset clipping to 1 and everything else to zero
+ glStencilFunc(GL_NOTEQUAL, 0x01, GL_STENCIL_HIGH_BIT);
+ glStencilOp(GL_ZERO, GL_REPLACE, GL_REPLACE);
+ glStencilMask(0xff);
+ composite(rect);
- glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ q->state()->currentClip = 1;
+ q->state()->canRestoreClip = false;
- // Enable color writes & disable stencil writes
+ maxClip = 1;
+
+ glStencilMask(0x0);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- glStencilMask(0);
- glDisable(GL_STENCIL_TEST);
}
-void QGL2PaintEngineExPrivate::prepareForDraw()
+bool QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
{
- if (brushTextureDirty)
+ if (brushTextureDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode)
updateBrushTexture();
if (compositionModeDirty)
updateCompositionMode();
- if (shaderManager->useCorrectShaderProg()) {
+ if (matrixDirty)
+ updateMatrix();
+
+ const bool stateHasOpacity = q->state()->opacity < 0.99f;
+ if (q->state()->composition_mode == QPainter::CompositionMode_Source
+ || (q->state()->composition_mode == QPainter::CompositionMode_SourceOver
+ && srcPixelsAreOpaque && !stateHasOpacity))
+ {
+ glDisable(GL_BLEND);
+ } else {
+ glEnable(GL_BLEND);
+ }
+
+ QGLEngineShaderManager::OpacityMode opacityMode;
+ if (mode == ImageArrayDrawingMode) {
+ opacityMode = QGLEngineShaderManager::AttributeOpacity;
+ } else {
+ opacityMode = stateHasOpacity ? QGLEngineShaderManager::UniformOpacity
+ : QGLEngineShaderManager::NoOpacity;
+ if (stateHasOpacity && (mode != ImageDrawingMode)) {
+ // Using a brush
+ bool brushIsPattern = (currentBrush.style() >= Qt::Dense1Pattern) &&
+ (currentBrush.style() <= Qt::DiagCrossPattern);
+
+ if ((currentBrush.style() == Qt::SolidPattern) || brushIsPattern)
+ opacityMode = QGLEngineShaderManager::NoOpacity; // Global opacity handled by srcPixel shader
+ }
+ }
+ shaderManager->setOpacityMode(opacityMode);
+
+ bool changed = shaderManager->useCorrectShaderProg();
+ // If the shader program needs changing, we change it and mark all uniforms as dirty
+ if (changed) {
// The shader program has changed so mark all uniforms as dirty:
brushUniformsDirty = true;
- brushShaderMatrixUniformDirty = true;
+ shaderMatrixUniformDirty = true;
+ opacityUniformDirty = true;
}
- if (brushUniformsDirty)
+ if (brushUniformsDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode)
updateBrushUniforms();
- if (brushShaderMatrixUniformDirty) {
- shaderManager->brushShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix;
- brushShaderMatrixUniformDirty = false;
+ if (shaderMatrixUniformDirty) {
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PmvMatrix), pmvMatrix);
+ shaderMatrixUniformDirty = false;
}
- if ((q->state()->opacity < 0.99f) || !currentBrush->isOpaque())
- glEnable(GL_BLEND);
- else
- glDisable(GL_BLEND);
+ if (opacityMode == QGLEngineShaderManager::UniformOpacity && opacityUniformDirty) {
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::GlobalOpacity), (GLfloat)q->state()->opacity);
+ opacityUniformDirty = false;
+ }
+
+ return changed;
}
void QGL2PaintEngineExPrivate::composite(const QGLRect& boundingRect)
@@ -721,14 +1214,16 @@ void QGL2PaintEngineExPrivate::composite(const QGLRect& boundingRect)
}
// Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans.
-void QGL2PaintEngineExPrivate::drawVertexArrays(QGL2PEXVertexArray& vertexArray, GLenum primitive)
+void QGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stops, int stopCount,
+ GLenum primitive)
{
// Now setup the pointer to the vertex array:
glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
- glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexArray.data());
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data);
int previousStop = 0;
- foreach(int stop, vertexArray.stops()) {
+ for (int i=0; i<stopCount; ++i) {
+ int stop = stops[i];
/*
qDebug("Drawing triangle fan for vertecies %d -> %d:", previousStop, stop-1);
for (int i=previousStop; i<stop; ++i)
@@ -740,17 +1235,35 @@ void QGL2PaintEngineExPrivate::drawVertexArrays(QGL2PEXVertexArray& vertexArray,
glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
}
+void QGL2PaintEngineExPrivate::prepareDepthRangeForRenderText()
+{
+#ifndef QT_OPENGL_ES_2
+ // Get the z translation value from the model view matrix and
+ // transform it using the ortogonal projection with z-near = 0,
+ // and z-far = 1, which is used in QGLWidget::renderText()
+ GLdouble model[4][4];
+ glGetDoublev(GL_MODELVIEW_MATRIX, &model[0][0]);
+ float deviceZ = -2 * model[3][2] - 1;
+
+ glGetFloatv(GL_DEPTH_RANGE, depthRange);
+ float windowZ = depthRange[0] + (deviceZ + 1) * 0.5 * (depthRange[1] - depthRange[0]);
+
+ glDepthRange(windowZ, windowZ);
+#endif
+}
-
-
+void QGL2PaintEngineExPrivate::restoreDepthRangeForRenderText()
+{
+#ifndef QT_OPENGL_ES_2
+ glDepthRange(depthRange[0], depthRange[1]);
+#endif
+}
/////////////////////////////////// Public Methods //////////////////////////////////////////
QGL2PaintEngineEx::QGL2PaintEngineEx()
: QPaintEngineEx(*(new QGL2PaintEngineExPrivate(this)))
{
- qDebug("QGL2PaintEngineEx::QGL2PaintEngineEx()");
-
}
QGL2PaintEngineEx::~QGL2PaintEngineEx()
@@ -761,77 +1274,174 @@ void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush)
{
Q_D(QGL2PaintEngineEx);
- QTime startTime = QTime::currentTime();
+ Qt::BrushStyle style = qbrush_style(brush);
+ if (style == Qt::NoBrush)
+ return;
+ if (!d->inRenderText)
+ ensureActive();
+
+ QOpenGL2PaintEngineState *s = state();
+ bool doOffset = !(s->renderHints & QPainter::Antialiasing) &&
+ (style == Qt::SolidPattern) &&
+ !d->multisamplingAlwaysEnabled;
+
+ if (doOffset) {
+ d->temporaryTransform = s->matrix;
+ QTransform tx = QTransform::fromTranslate(.49, .49);
+ s->matrix = s->matrix * tx;
+ d->matrixDirty = true;
+ }
- d->setBrush(&brush);
+ d->setBrush(brush);
d->fill(path);
- d->setBrush(&(state()->brush)); // reset back to the state's brush
+
+ if (doOffset) {
+ s->matrix = d->temporaryTransform;
+ d->matrixDirty = true;
+ }
}
+extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
+
+
void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
{
Q_D(QGL2PaintEngineEx);
- if (pen.style() == Qt::NoPen)
+ Qt::PenStyle penStyle = qpen_style(pen);
+ const QBrush &penBrush = qpen_brush(pen);
+ if (penStyle == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush)
return;
- if ( (pen.isCosmetic() && (pen.style() == Qt::SolidLine)) && (pen.widthF() < 2.5f) )
- {
- // We only handle solid, cosmetic pens with a width of 1 pixel
- const QBrush& brush = pen.brush();
- d->setBrush(&brush);
+ QOpenGL2PaintEngineState *s = state();
+ if (pen.isCosmetic() && !qt_scaleForTransform(s->transform(), 0)) {
+ // QTriangulatingStroker class is not meant to support cosmetically sheared strokes.
+ QPaintEngineEx::stroke(path, pen);
+ return;
+ }
- if (pen.widthF() < 0.01f)
- glLineWidth(1.0);
- else
- glLineWidth(pen.widthF());
+ ensureActive();
- d->drawOutline(path);
- d->setBrush(&(state()->brush));
- } else
- return QPaintEngineEx::stroke(path, pen);
+ bool doOffset = !(s->renderHints & QPainter::Antialiasing) && !d->multisamplingAlwaysEnabled;
+ if (doOffset) {
+ d->temporaryTransform = s->matrix;
+ QTransform tx = QTransform::fromTranslate(0.49, .49);
+ s->matrix = s->matrix * tx;
+ d->matrixDirty = true;
+ }
-}
+ bool opaque = penBrush.isOpaque() && s->opacity > 0.99;
+ d->setBrush(penBrush);
+ d->transferMode(BrushDrawingMode);
-void QGL2PaintEngineEx::penChanged()
-{
-// qDebug("QGL2PaintEngineEx::penChanged() not implemented!");
-}
+ // updateMatrix() is responsible for setting the inverse scale on
+ // the strokers, so we need to call it here and not wait for
+ // prepareForDraw() down below.
+ d->updateMatrix();
+ if (penStyle == Qt::SolidLine) {
+ d->stroker.process(path, pen);
-void QGL2PaintEngineEx::brushChanged()
-{
-// qDebug("QGL2PaintEngineEx::brushChanged()");
- Q_D(QGL2PaintEngineEx);
- d->setBrush(&(state()->brush));
-}
+ } else { // Some sort of dash
+ d->dasher.process(path, pen);
-void QGL2PaintEngineEx::brushOriginChanged()
-{
-// qDebug("QGL2PaintEngineEx::brushOriginChanged()");
- Q_D(QGL2PaintEngineEx);
- d->brushUniformsDirty = true;
+ QVectorPath dashStroke(d->dasher.points(),
+ d->dasher.elementCount(),
+ d->dasher.elementTypes());
+ d->stroker.process(dashStroke, pen);
+ }
+
+
+ QGLContext *ctx = d->ctx;
+ Q_UNUSED(ctx);
+
+ if (opaque) {
+ d->prepareForDraw(opaque);
+ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, d->stroker.vertices());
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, d->stroker.vertexCount() / 2);
+
+// QBrush b(Qt::green);
+// d->setBrush(&b);
+// d->prepareForDraw(true);
+// glDrawArrays(GL_LINE_STRIP, 0, d->stroker.vertexCount() / 2);
+
+ glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+
+ } else {
+ qreal width = qpen_widthf(pen) / 2;
+ if (width == 0)
+ width = 0.5;
+ qreal extra = pen.joinStyle() == Qt::MiterJoin
+ ? qMax(pen.miterLimit() * width, width)
+ : width;
+
+ if (pen.isCosmetic())
+ extra = extra * d->inverseScale;
+
+ QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra);
+
+ d->fillStencilWithVertexArray(d->stroker.vertices(), d->stroker.vertexCount() / 2,
+ 0, 0, bounds, QGL2PaintEngineExPrivate::TriStripStrokeFillMode);
+
+ glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
+
+ // Pass when any bit is set, replace stencil value with 0
+ glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
+ d->prepareForDraw(false);
+
+ // Stencil the brush onto the dest buffer
+ d->composite(bounds);
+
+ glStencilMask(0);
+
+ d->updateClipScissorTest();
+ }
+
+ if (doOffset) {
+ s->matrix = d->temporaryTransform;
+ d->matrixDirty = true;
+ }
}
+void QGL2PaintEngineEx::penChanged() { }
+void QGL2PaintEngineEx::brushChanged() { }
+void QGL2PaintEngineEx::brushOriginChanged() { }
+
void QGL2PaintEngineEx::opacityChanged()
{
// qDebug("QGL2PaintEngineEx::opacityChanged()");
Q_D(QGL2PaintEngineEx);
+ state()->opacityChanged = true;
Q_ASSERT(d->shaderManager);
- d->shaderManager->setUseGlobalOpacity(state()->opacity > 0.999);
d->brushUniformsDirty = true;
+ d->opacityUniformDirty = true;
}
void QGL2PaintEngineEx::compositionModeChanged()
{
// qDebug("QGL2PaintEngineEx::compositionModeChanged()");
Q_D(QGL2PaintEngineEx);
+ state()->compositionModeChanged = true;
d->compositionModeDirty = true;
}
void QGL2PaintEngineEx::renderHintsChanged()
{
+ state()->renderHintsChanged = true;
+
+#if !defined(QT_OPENGL_ES_2)
+ if ((state()->renderHints & QPainter::Antialiasing)
+ || (state()->renderHints & QPainter::HighQualityAntialiasing))
+ glEnable(GL_MULTISAMPLE);
+ else
+ glDisable(GL_MULTISAMPLE);
+#endif
+
+ Q_D(QGL2PaintEngineEx);
+ d->lastTexture = GLuint(-1);
+ d->brushTextureDirty = true;
// qDebug("QGL2PaintEngineEx::renderHintsChanged() not implemented!");
}
@@ -839,156 +1449,349 @@ void QGL2PaintEngineEx::transformChanged()
{
Q_D(QGL2PaintEngineEx);
d->matrixDirty = true;
+ state()->matrixChanged = true;
}
void QGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, const QRectF & src)
{
Q_D(QGL2PaintEngineEx);
- glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
+ ensureActive();
+ d->transferMode(ImageDrawingMode);
+
+ QGLContext *ctx = d->ctx;
+ glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
+ QGLTexture *texture =
+ ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA,
+ QGLContext::InternalBindOption
+ | QGLContext::CanFlipNativePixmapBindOption);
+
+ GLfloat top = texture->options & QGLContext::InvertedYBindOption ? (pixmap.height() - src.top()) : src.top();
+ GLfloat bottom = texture->options & QGLContext::InvertedYBindOption ? (pixmap.height() - src.bottom()) : src.bottom();
+ QGLRect srcRect(src.left(), top, src.right(), bottom);
+
+ bool isBitmap = pixmap.isQBitmap();
+ bool isOpaque = !isBitmap && !pixmap.hasAlphaChannel();
+
+ d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
+ state()->renderHints & QPainter::SmoothPixmapTransform, texture->id);
+ d->drawTexture(dest, srcRect, pixmap.size(), isOpaque, isBitmap);
+}
- d->ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, true);
+void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const QRectF& src,
+ Qt::ImageConversionFlags)
+{
+ Q_D(QGL2PaintEngineEx);
+ ensureActive();
+ d->transferMode(ImageDrawingMode);
- //FIXME: we should use hasAlpha() instead, but that's SLOW at the moment
- if ((state()->opacity < 0.99f) || pixmap.hasAlphaChannel())
- glEnable(GL_BLEND);
- else
- glDisable(GL_BLEND);
+ QGLContext *ctx = d->ctx;
+ glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
+ QGLTexture *texture = ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption);
+ GLuint id = texture->id;
- d->drawTexture(dest, src, pixmap.width(), pixmap.height());
+ d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
+ state()->renderHints & QPainter::SmoothPixmapTransform, id);
+ d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel());
}
-void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const QRectF& src,
- Qt::ImageConversionFlags)
+void QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src)
{
Q_D(QGL2PaintEngineEx);
- glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
- d->ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true);
+ ensureActive();
+ d->transferMode(ImageDrawingMode);
- if ((state()->opacity < 0.99f) || image.hasAlphaChannel())
- glEnable(GL_BLEND);
- else
- glDisable(GL_BLEND);
+#ifndef QT_OPENGL_ES_2
+ QGLContext *ctx = d->ctx;
+#endif
+ glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
+ glBindTexture(GL_TEXTURE_2D, textureId);
- d->drawTexture(dest, src, image.width(), image.height());
+ QGLRect srcRect(src.left(), src.bottom(), src.right(), src.top());
+
+ d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
+ state()->renderHints & QPainter::SmoothPixmapTransform, textureId);
+ d->drawTexture(dest, srcRect, size, false);
}
void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem)
{
- QOpenGLPaintEngineState *s = state();
+ Q_D(QGL2PaintEngineEx);
+
+ if (!d->inRenderText)
+ ensureActive();
+ QOpenGL2PaintEngineState *s = state();
const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
- bool drawCached = true;
+ QTransform::TransformationType txtype = s->matrix.type();
- if (state()->pen.brush().style() != Qt::SolidPattern)
- drawCached = false;
+ float det = s->matrix.determinant();
+ bool drawCached = txtype < QTransform::TxProject;
- if (s->matrix.type() > QTransform::TxTranslate)
+ // don't try to cache huge fonts or vastly transformed fonts
+ const qreal pixelSize = ti.fontEngine->fontDef.pixelSize;
+ if (pixelSize * pixelSize * qAbs(det) >= 64 * 64 || det < 0.25f || det > 4.f)
drawCached = false;
- // don't try to cache huge fonts
- if (ti.fontEngine->fontDef.pixelSize * qSqrt(s->matrix.determinant()) >= 64)
+ QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0
+ ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat)
+ : d->glyphCacheType;
+
+ if (d->inRenderText || txtype > QTransform::TxTranslate)
+ glyphType = QFontEngineGlyphCache::Raster_A8;
+
+ if (glyphType == QFontEngineGlyphCache::Raster_RGBMask
+ && state()->composition_mode != QPainter::CompositionMode_Source
+ && state()->composition_mode != QPainter::CompositionMode_SourceOver)
+ {
drawCached = false;
+ }
if (drawCached) {
- drawCachedGlyphs(p, ti);
+ d->drawCachedGlyphs(p, glyphType, ti);
return;
}
QPaintEngineEx::drawTextItem(p, ti);
}
-void QGL2PaintEngineEx::drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti)
+void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType,
+ const QTextItemInt &ti)
{
- Q_D(QGL2PaintEngineEx);
- QOpenGLPaintEngineState *s = state();
+ Q_Q(QGL2PaintEngineEx);
QVarLengthArray<QFixedPoint> positions;
QVarLengthArray<glyph_t> glyphs;
- QTransform matrix;
- matrix.translate(p.x(), p.y());
+ QTransform matrix = QTransform::fromTranslate(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;
-
- QImageTextureGlyphCache *cache =
- (QImageTextureGlyphCache *) ti.fontEngine->glyphCache(glyphType, s->matrix);
- if (!cache) {
- cache = new QImageTextureGlyphCache(glyphType, s->matrix);
- ti.fontEngine->setGlyphCache(glyphType, cache);
+ QGLTextureGlyphCache *cache =
+ (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, glyphType, QTransform());
+
+ if (!cache || cache->cacheType() != glyphType) {
+ cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform());
+ ti.fontEngine->setGlyphCache(ctx, cache);
}
+ cache->setPaintEnginePrivate(this);
cache->populate(ti, glyphs, positions);
- const QImage &image = cache->image();
+ if (cache->width() == 0 || cache->height() == 0)
+ return;
+
+ if (inRenderText)
+ transferMode(BrushDrawingMode);
+ transferMode(TextDrawingMode);
+
int margin = cache->glyphMargin();
- if (image.isNull())
- return;
+ GLfloat dx = 1.0 / cache->width();
+ GLfloat dy = 1.0 / cache->height();
+
+ 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;
+
+ vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h));
+ textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy));
+ }
+
+ 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());
+
+ QBrush pensBrush = q->state()->pen.brush();
+ setBrush(pensBrush);
+
+ if (inRenderText)
+ prepareDepthRangeForRenderText();
+
+ if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
+
+ // Subpixel antialiasing without gamma correction
- glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
- d->ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true);
+ QPainter::CompositionMode compMode = q->state()->composition_mode;
+ Q_ASSERT(compMode == QPainter::CompositionMode_Source
+ || compMode == QPainter::CompositionMode_SourceOver);
- glEnable(GL_BLEND);
+ shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMaskPass1);
- d->shaderManager->textShader()->use();
- d->updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
+ if (pensBrush.style() == Qt::SolidPattern) {
+ // Solid patterns can get away with only one pass.
+ QColor c = pensBrush.color();
+ qreal oldOpacity = q->state()->opacity;
+ if (compMode == QPainter::CompositionMode_Source) {
+ c = qt_premultiplyColor(c, q->state()->opacity);
+ q->state()->opacity = 1;
+ opacityUniformDirty = true;
+ }
+
+ compositionModeDirty = false; // I can handle this myself, thank you very much
+ prepareForDraw(false); // Text always causes src pixels to be transparent
+
+ // prepareForDraw() have set the opacity on the current shader, so the opacity state can now be reset.
+ if (compMode == QPainter::CompositionMode_Source) {
+ q->state()->opacity = oldOpacity;
+ opacityUniformDirty = true;
+ }
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR);
+ glBlendColor(c.redF(), c.greenF(), c.blueF(), c.alphaF());
+ } else {
+ // Other brush styles need two passes.
+
+ qreal oldOpacity = q->state()->opacity;
+ if (compMode == QPainter::CompositionMode_Source) {
+ q->state()->opacity = 1;
+ opacityUniformDirty = true;
+ pensBrush = Qt::white;
+ setBrush(pensBrush);
+ }
+
+ compositionModeDirty = false; // I can handle this myself, thank you very much
+ prepareForDraw(false); // Text always causes src pixels to be transparent
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
+
+ glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
+ glBindTexture(GL_TEXTURE_2D, cache->texture());
+ updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
- if (d->compositionModeDirty)
- d->updateCompositionMode();
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
+ glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size());
- if (d->matrixDirty)
- d->updateMatrix();
+ shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMaskPass2);
- if (d->textShaderMatrixUniformDirty) {
- d->shaderManager->textShader()->uniforms()[QLatin1String("pmvMatrix")] = d->pmvMatrix;
- d->textShaderMatrixUniformDirty = false;
+ if (compMode == QPainter::CompositionMode_Source) {
+ q->state()->opacity = oldOpacity;
+ opacityUniformDirty = true;
+ pensBrush = q->state()->pen.brush();
+ setBrush(pensBrush);
+ }
+
+ compositionModeDirty = false;
+ prepareForDraw(false); // Text always causes src pixels to be transparent
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE);
+ }
+ compositionModeDirty = true;
+ } else {
+ // Greyscale/mono glyphs
+
+ shaderManager->setMaskType(QGLEngineShaderManager::PixelMask);
+ prepareForDraw(false); // Text always causes src pixels to be transparent
}
+ //### TODO: Gamma correction
- 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;
+ glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
+ glBindTexture(GL_TEXTURE_2D, cache->texture());
+ updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
- GLfloat dx = 1.0 / image.width();
- GLfloat dy = 1.0 / image.height();
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
+ glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size());
- glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
- glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
- for (int i=0; i<glyphs.size(); ++i) {
- const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]);
- int x = positions[i].x.toInt() + c.baseLineX - margin;
- int y = positions[i].y.toInt() - c.baseLineY - margin;
+ if (inRenderText)
+ restoreDepthRangeForRenderText();
+}
+
+void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints)
+{
+ // Use fallback for extended composition modes.
+ if (state()->composition_mode > QPainter::CompositionMode_Plus) {
+ QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints);
+ return;
+ }
+
+ Q_D(QGL2PaintEngineEx);
+
+ GLfloat dx = 1.0f / pixmap.size().width();
+ GLfloat dy = 1.0f / pixmap.size().height();
- QGLRect dest = QRectF(x, y, c.w, c.h);
- QGLRect src = QRectF(c.x, c.y, c.w, c.h);
+ d->vertexCoordinateArray.clear();
+ d->textureCoordinateArray.clear();
+ d->opacityArray.reset();
- GLfloat vertexCoords[] = {
- dest.left, dest.top,
- dest.left, dest.bottom,
- dest.right, dest.bottom,
- dest.right, dest.top
- };
+ bool allOpaque = true;
- glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords);
+ for (int i = 0; i < dataCount; ++i) {
+ qreal s = 0;
+ qreal c = 1;
+ if (drawingData[i].rotation != 0) {
+ s = qFastSin(drawingData[i].rotation * Q_PI / 180);
+ c = qFastCos(drawingData[i].rotation * Q_PI / 180);
+ }
- QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy);
+ qreal right = 0.5 * drawingData[i].scaleX * drawingData[i].source.width();
+ qreal bottom = 0.5 * drawingData[i].scaleY * drawingData[i].source.height();
+ QGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c);
+ QGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c);
+
+ d->vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y());
+ d->vertexCoordinateArray.lineToArray(-bottomLeft.x + drawingData[i].point.x(), -bottomLeft.y + drawingData[i].point.y());
+ d->vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y());
+ d->vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y());
+ d->vertexCoordinateArray.lineToArray(bottomLeft.x + drawingData[i].point.x(), bottomLeft.y + drawingData[i].point.y());
+ d->vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y());
+
+ QGLRect src(drawingData[i].source.left() * dx, drawingData[i].source.top() * dy,
+ drawingData[i].source.right() * dx, drawingData[i].source.bottom() * dy);
+
+ d->textureCoordinateArray.lineToArray(src.right, src.bottom);
+ d->textureCoordinateArray.lineToArray(src.right, src.top);
+ d->textureCoordinateArray.lineToArray(src.left, src.top);
+ d->textureCoordinateArray.lineToArray(src.left, src.top);
+ d->textureCoordinateArray.lineToArray(src.left, src.bottom);
+ d->textureCoordinateArray.lineToArray(src.right, src.bottom);
+
+ qreal opacity = drawingData[i].opacity * state()->opacity;
+ d->opacityArray << opacity << opacity << opacity << opacity << opacity << opacity;
+ allOpaque &= (opacity >= 0.99f);
+ }
- GLfloat textureCoords[] = {
- srcTextureRect.left, srcTextureRect.top,
- srcTextureRect.left, srcTextureRect.bottom,
- srcTextureRect.right, srcTextureRect.bottom,
- srcTextureRect.right, srcTextureRect.top
- };
+ ensureActive();
- glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoords);
+ QGLContext *ctx = d->ctx;
+ glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
+ QGLTexture *texture = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA,
+ QGLContext::InternalBindOption
+ | QGLContext::CanFlipNativePixmapBindOption);
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ if (texture->options & QGLContext::InvertedYBindOption) {
+ // Flip texture y-coordinate.
+ QGLPoint *data = d->textureCoordinateArray.data();
+ for (int i = 0; i < 6 * dataCount; ++i)
+ data[i].y = 1 - data[i].y;
}
- glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
- glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+
+ d->transferMode(ImageArrayDrawingMode);
+
+ bool isBitmap = pixmap.isQBitmap();
+ bool isOpaque = !isBitmap && (!pixmap.hasAlphaChannel() || (hints & QDrawPixmaps::OpaqueHint)) && allOpaque;
+
+ d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
+ state()->renderHints & QPainter::SmoothPixmapTransform, texture->id);
+
+ // Setup for texture drawing
+ d->shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc);
+ if (d->prepareForDraw(isOpaque))
+ d->shaderManager->currentProgram()->setUniformValue(d->location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
+
+ if (isBitmap) {
+ QColor col = qt_premultiplyColor(state()->pen.color(), (GLfloat)state()->opacity);
+ d->shaderManager->currentProgram()->setUniformValue(d->location(QGLEngineShaderManager::PatternColor), col);
+ }
+
+ glDrawArrays(GL_TRIANGLES, 0, 6 * dataCount);
}
bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
@@ -996,33 +1799,73 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
Q_D(QGL2PaintEngineEx);
// qDebug("QGL2PaintEngineEx::begin()");
+ if (pdev->devType() == QInternal::OpenGL)
+ d->device = static_cast<QGLPaintDevice*>(pdev);
+ else
+ d->device = QGLPaintDevice::getDevice(pdev);
- QGLWidget* widget = static_cast<QGLWidget*>(pdev);
- d->ctx = const_cast<QGLContext*>(widget->context());
- d->ctx->makeCurrent();
- d->width = widget->width();
- d->height = widget->height();
-
- if (!d->shaderManager)
- d->shaderManager = new QGLPEXShaderManager(d->ctx);
-
- glViewport(0, 0, d->width, d->height);
+ if (!d->device)
+ return false;
-// glClearColor(0.0, 1.0, 0.0, 1.0);
-// glClear(GL_COLOR_BUFFER_BIT);
-// d->ctx->swapBuffers();
-// qDebug("You should see green now");
-// sleep(5);
+ d->ctx = d->device->context();
+ d->ctx->d_ptr->active_engine = this;
+ const QSize sz = d->device->size();
+ d->width = sz.width();
+ d->height = sz.height();
+ d->mode = BrushDrawingMode;
d->brushTextureDirty = true;
d->brushUniformsDirty = true;
d->matrixDirty = true;
d->compositionModeDirty = true;
- d->stencilBuferDirty = true;
-
+ d->opacityUniformDirty = true;
+ d->needsSync = true;
d->use_system_clip = !systemClip().isEmpty();
+ d->currentBrush = QBrush();
- glDisable(GL_DEPTH_TEST);
+ d->dirtyStencilRegion = QRect(0, 0, d->width, d->height);
+ d->stencilClean = true;
+
+ // Calling begin paint should make the correct context current. So, any
+ // code which calls into GL or otherwise needs a current context *must*
+ // go after beginPaint:
+ d->device->beginPaint();
+
+#if !defined(QT_OPENGL_ES_2)
+ bool success = qt_resolve_version_2_0_functions(d->ctx)
+ && qt_resolve_buffer_extensions(d->ctx);
+ Q_ASSERT(success);
+ Q_UNUSED(success);
+#endif
+
+ d->shaderManager = new QGLEngineShaderManager(d->ctx);
+
+ if (!d->inRenderText) {
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ }
+
+#if !defined(QT_OPENGL_ES_2)
+ glDisable(GL_MULTISAMPLE);
+#endif
+
+ d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
+
+#if !defined(QT_OPENGL_ES_2)
+#if defined(Q_WS_WIN)
+ if (qt_cleartype_enabled)
+#endif
+ d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask;
+#endif
+
+#if defined(QT_OPENGL_ES_2)
+ // OpenGL ES can't switch MSAA off, so if the gl paint device is
+ // multisampled, it's always multisampled.
+ d->multisamplingAlwaysEnabled = d->device->format().sampleBuffers();
+#else
+ d->multisamplingAlwaysEnabled = false;
+#endif
return true;
}
@@ -1030,252 +1873,441 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
bool QGL2PaintEngineEx::end()
{
Q_D(QGL2PaintEngineEx);
- d->ctx->swapBuffers();
+ QGLContext *ctx = d->ctx;
+
+ glUseProgram(0);
+ d->transferMode(BrushDrawingMode);
+ d->device->endPaint();
+
+#if defined(Q_WS_X11)
+ // On some (probably all) drivers, deleting an X pixmap which has been bound to a texture
+ // before calling glFinish/swapBuffers renders garbage. Presumably this is because X deletes
+ // the pixmap behind the driver's back before it's had a chance to use it. To fix this, we
+ // reference all QPixmaps which have been bound to stop them being deleted and only deref
+ // them here, after swapBuffers, where they can be safely deleted.
+ ctx->d_func()->boundPixmaps.clear();
+#endif
+ d->ctx->d_ptr->active_engine = 0;
+
+ d->resetGLState();
+
+ delete d->shaderManager;
+ d->shaderManager = 0;
+
+#ifdef QT_OPENGL_CACHE_AS_VBOS
+ if (!d->unusedVBOSToClean.isEmpty()) {
+ glDeleteBuffers(d->unusedVBOSToClean.size(), d->unusedVBOSToClean.constData());
+ d->unusedVBOSToClean.clear();
+ }
+#endif
+
return false;
}
+void QGL2PaintEngineEx::ensureActive()
+{
+ Q_D(QGL2PaintEngineEx);
+ QGLContext *ctx = d->ctx;
+
+ if (isActive() && ctx->d_ptr->active_engine != this) {
+ ctx->d_ptr->active_engine = this;
+ d->needsSync = true;
+ }
-/////////////////////////////////// State/Clipping stolen from QOpenGLPaintEngine //////////////////////////////////////////
+ d->device->ensureActiveTarget();
+
+ if (d->needsSync) {
+ d->transferMode(BrushDrawingMode);
+ glViewport(0, 0, d->width, d->height);
+ d->needsSync = false;
+ d->shaderManager->setDirty();
+ setState(state());
+ }
+}
+
+void QGL2PaintEngineExPrivate::updateClipScissorTest()
+{
+ Q_Q(QGL2PaintEngineEx);
+ if (q->state()->clipTestEnabled) {
+ glEnable(GL_STENCIL_TEST);
+ glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT);
+ } else {
+ glDisable(GL_STENCIL_TEST);
+ glStencilFunc(GL_ALWAYS, 0, 0xff);
+ }
+
+#ifdef QT_GL_NO_SCISSOR_TEST
+ currentScissorBounds = QRect(0, 0, width, height);
+#else
+ QRect bounds = q->state()->rectangleClip;
+ if (!q->state()->clipEnabled) {
+ if (use_system_clip)
+ bounds = systemClip.boundingRect();
+ else
+ bounds = QRect(0, 0, width, height);
+ } else {
+ if (use_system_clip)
+ bounds = bounds.intersected(systemClip.boundingRect());
+ else
+ bounds = bounds.intersected(QRect(0, 0, width, height));
+ }
+
+ currentScissorBounds = bounds;
+
+ if (bounds == QRect(0, 0, width, height)) {
+ glDisable(GL_SCISSOR_TEST);
+ } else {
+ glEnable(GL_SCISSOR_TEST);
+ setScissor(bounds);
+ }
+#endif
+}
+
+void QGL2PaintEngineExPrivate::setScissor(const QRect &rect)
+{
+ const int left = rect.left();
+ const int width = rect.width();
+ const int bottom = height - (rect.top() + rect.height());
+ const int height = rect.height();
+
+ glScissor(left, bottom, width, height);
+}
void QGL2PaintEngineEx::clipEnabledChanged()
{
Q_D(QGL2PaintEngineEx);
- d->updateDepthClip();
+ state()->clipChanged = true;
+
+ if (painter()->hasClipping())
+ d->regenerateClip();
+ else
+ d->systemStateChanged();
+}
+
+void QGL2PaintEngineExPrivate::clearClip(uint value)
+{
+ dirtyStencilRegion -= currentScissorBounds;
+
+ glStencilMask(0xff);
+ glClearStencil(value);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ glStencilMask(0x0);
+
+ q->state()->needsClipBufferClear = false;
}
-void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op)
+void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint value)
{
-// qDebug("QGL2PaintEngineEx::clip()");
- const qreal *points = path.points();
- const QPainterPath::ElementType *types = path.elements();
- if (!types && path.shape() == QVectorPath::RectangleHint) {
- QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
- updateClipRegion(QRegion(r.toRect()), op);
+ transferMode(BrushDrawingMode);
+
+ if (matrixDirty)
+ updateMatrix();
+
+ stencilClean = false;
+
+ const bool singlePass = !path.hasWindingFill()
+ && (((q->state()->currentClip == maxClip - 1) && q->state()->clipTestEnabled)
+ || q->state()->needsClipBufferClear);
+ const uint referenceClipValue = q->state()->needsClipBufferClear ? 1 : q->state()->currentClip;
+
+ if (q->state()->needsClipBufferClear)
+ clearClip(1);
+
+ if (path.isEmpty()) {
+ glEnable(GL_STENCIL_TEST);
+ glStencilFunc(GL_LEQUAL, value, ~GL_STENCIL_HIGH_BIT);
return;
}
- QPainterPath p;
- if (types) {
- int id = 0;
- for (int i=0; i<path.elementCount(); ++i) {
- switch(types[i]) {
- case QPainterPath::MoveToElement:
- p.moveTo(QPointF(points[id], points[id+1]));
- id+=2;
- break;
- case QPainterPath::LineToElement:
- p.lineTo(QPointF(points[id], points[id+1]));
- id+=2;
- break;
- case QPainterPath::CurveToElement: {
- QPointF p1(points[id], points[id+1]);
- QPointF p2(points[id+2], points[id+3]);
- QPointF p3(points[id+4], points[id+5]);
- p.cubicTo(p1, p2, p3);
- id+=6;
- break;
- }
- case QPainterPath::CurveToDataElement:
- ;
- break;
- }
- }
- } else if (!path.isEmpty()) {
- p.moveTo(QPointF(points[0], points[1]));
- int id = 2;
- for (int i=1; i<path.elementCount(); ++i) {
- p.lineTo(QPointF(points[id], points[id+1]));
- id+=2;
+ if (q->state()->clipTestEnabled)
+ glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT);
+ else
+ glStencilFunc(GL_ALWAYS, 0, 0xff);
+
+ vertexCoordinateArray.clear();
+ vertexCoordinateArray.addPath(path, inverseScale, false);
+
+ if (!singlePass)
+ fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill());
+
+ glColorMask(false, false, false, false);
+ glEnable(GL_STENCIL_TEST);
+ useSimpleShader();
+
+ if (singlePass) {
+ // Under these conditions we can set the new stencil value in a single
+ // pass, by using the current value and the "new value" as the toggles
+
+ glStencilFunc(GL_LEQUAL, referenceClipValue, ~GL_STENCIL_HIGH_BIT);
+ glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT);
+ glStencilMask(value ^ referenceClipValue);
+
+ drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN);
+ } else {
+ glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
+ glStencilMask(0xff);
+
+ if (!q->state()->clipTestEnabled && path.hasWindingFill()) {
+ // Pass when any clip bit is set, set high bit
+ glStencilFunc(GL_NOTEQUAL, GL_STENCIL_HIGH_BIT, ~GL_STENCIL_HIGH_BIT);
+ composite(vertexCoordinateArray.boundingRect());
}
+
+ // Pass when high bit is set, replace stencil value with new clip value
+ glStencilFunc(GL_NOTEQUAL, value, GL_STENCIL_HIGH_BIT);
+
+ composite(vertexCoordinateArray.boundingRect());
}
- if (path.hints() & QVectorPath::WindingFill)
- p.setFillRule(Qt::WindingFill);
- updateClipRegion(QRegion(p.toFillPolygon().toPolygon(), p.fillRule()), op);
- return;
+ glStencilFunc(GL_LEQUAL, value, ~GL_STENCIL_HIGH_BIT);
+ glStencilMask(0);
+
+ glColorMask(true, true, true, true);
}
-void QGL2PaintEngineEx::updateClipRegion(const QRegion &clipRegion, Qt::ClipOperation op)
+void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op)
{
-// qDebug("QGL2PaintEngineEx::updateClipRegion()");
+// qDebug("QGL2PaintEngineEx::clip()");
Q_D(QGL2PaintEngineEx);
- QRegion sysClip = systemClip();
- if (op == Qt::NoClip && !d->use_system_clip) {
- state()->hasClipping = false;
- state()->clipRegion = QRegion();
- d->updateDepthClip();
- return;
+ state()->clipChanged = true;
+
+ ensureActive();
+
+ if (op == Qt::ReplaceClip) {
+ op = Qt::IntersectClip;
+ if (d->hasClipOperations()) {
+ d->systemStateChanged();
+ state()->canRestoreClip = false;
+ }
}
- bool isScreenClip = false;
- if (!d->use_system_clip) {
- QVector<QRect> untransformedRects = clipRegion.rects();
+#ifndef QT_GL_NO_SCISSOR_TEST
+ if (!path.isEmpty() && op == Qt::IntersectClip && (path.shape() == QVectorPath::RectangleHint)) {
+ const QPointF* const points = reinterpret_cast<const QPointF*>(path.points());
+ QRectF rect(points[0], points[2]);
- if (untransformedRects.size() == 1) {
- QPainterPath path;
- path.addRect(untransformedRects[0]);
- //path = d->matrix.map(path);
- path = state()->matrix.map(path);
-
-// if (path.contains(QRectF(QPointF(), d->drawable.size())))
-// isScreenClip = true;
- if (path.contains(QRectF(0.0, 0.0, d->width, d->height)))
- isScreenClip = true;
+ if (state()->matrix.type() <= QTransform::TxScale) {
+ state()->rectangleClip = state()->rectangleClip.intersected(state()->matrix.mapRect(rect).toRect());
+ d->updateClipScissorTest();
+ return;
}
}
+#endif
+
+ const QRect pathRect = state()->matrix.mapRect(path.controlPointRect()).toAlignedRect();
-// QRegion region = isScreenClip ? QRegion() : clipRegion * d->matrix;
- QRegion region = isScreenClip ? QRegion() : clipRegion * state()->matrix;
switch (op) {
case Qt::NoClip:
- if (!d->use_system_clip)
- break;
- state()->clipRegion = sysClip;
+ if (d->use_system_clip) {
+ state()->clipTestEnabled = true;
+ state()->currentClip = 1;
+ } else {
+ state()->clipTestEnabled = false;
+ }
+ state()->rectangleClip = QRect(0, 0, d->width, d->height);
+ state()->canRestoreClip = false;
+ d->updateClipScissorTest();
break;
case Qt::IntersectClip:
- if (isScreenClip)
- return;
- if (state()->hasClipping) {
- state()->clipRegion &= region;
- break;
- }
- // fall through
- case Qt::ReplaceClip:
- if (d->use_system_clip && !sysClip.isEmpty())
- state()->clipRegion = region & sysClip;
- else
- state()->clipRegion = region;
+ state()->rectangleClip = state()->rectangleClip.intersected(pathRect);
+ d->updateClipScissorTest();
+ d->resetClipIfNeeded();
+ ++d->maxClip;
+ d->writeClip(path, d->maxClip);
+ state()->currentClip = d->maxClip;
+ state()->clipTestEnabled = true;
break;
- case Qt::UniteClip:
- state()->clipRegion |= region;
- if (d->use_system_clip && !sysClip.isEmpty())
- state()->clipRegion &= sysClip;
+ case Qt::UniteClip: {
+ d->resetClipIfNeeded();
+ ++d->maxClip;
+ if (state()->rectangleClip.isValid()) {
+ QPainterPath path;
+ path.addRect(state()->rectangleClip);
+
+ // flush the existing clip rectangle to the depth buffer
+ d->writeClip(qtVectorPathForPath(state()->matrix.inverted().map(path)), d->maxClip);
+ }
+
+ state()->clipTestEnabled = false;
+#ifndef QT_GL_NO_SCISSOR_TEST
+ QRect oldRectangleClip = state()->rectangleClip;
+
+ state()->rectangleClip = state()->rectangleClip.united(pathRect);
+ d->updateClipScissorTest();
+
+ QRegion extendRegion = QRegion(state()->rectangleClip) - oldRectangleClip;
+
+ if (!extendRegion.isEmpty()) {
+ QPainterPath extendPath;
+ extendPath.addRegion(extendRegion);
+
+ // first clear the depth buffer in the extended region
+ d->writeClip(qtVectorPathForPath(state()->matrix.inverted().map(extendPath)), 0);
+ }
+#endif
+ // now write the clip path
+ d->writeClip(path, d->maxClip);
+ state()->canRestoreClip = false;
+ state()->currentClip = d->maxClip;
+ state()->clipTestEnabled = true;
break;
+ }
default:
break;
}
+}
- if (isScreenClip) {
- state()->hasClipping = false;
- state()->clipRegion = QRegion();
- } else {
- state()->hasClipping = op != Qt::NoClip || d->use_system_clip;
- }
+void QGL2PaintEngineExPrivate::regenerateClip()
+{
+ systemStateChanged();
+ replayClipOperations();
+}
- if (state()->hasClipping && state()->clipRegion.rects().size() == 1)
- state()->fastClip = state()->clipRegion.rects().at(0);
- else
- state()->fastClip = QRect();
+void QGL2PaintEngineExPrivate::systemStateChanged()
+{
+ Q_Q(QGL2PaintEngineEx);
- d->updateDepthClip();
-}
+ q->state()->clipChanged = true;
+ if (systemClip.isEmpty()) {
+ use_system_clip = false;
+ } else {
+ if (q->paintDevice()->devType() == QInternal::Widget && currentClipWidget) {
+ QWidgetPrivate *widgetPrivate = qt_widget_private(currentClipWidget->window());
+ use_system_clip = widgetPrivate->extra && widgetPrivate->extra->inRenderWithPainter;
+ } else {
+ use_system_clip = true;
+ }
+ }
-void QGL2PaintEngineExPrivate::updateDepthClip()
-{
-// qDebug("QGL2PaintEngineExPrivate::updateDepthClip()");
+ q->state()->clipTestEnabled = false;
+ q->state()->needsClipBufferClear = true;
- Q_Q(QGL2PaintEngineEx);
+ q->state()->currentClip = 1;
+ maxClip = 1;
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_SCISSOR_TEST);
+ q->state()->rectangleClip = use_system_clip ? systemClip.boundingRect() : QRect(0, 0, width, height);
+ updateClipScissorTest();
- if (!q->state()->hasClipping)
+ if (systemClip.rectCount() == 1) {
+ if (systemClip.boundingRect() == QRect(0, 0, width, height))
+ use_system_clip = false;
+#ifndef QT_GL_NO_SCISSOR_TEST
+ // scissoring takes care of the system clip
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);
+#endif
}
- if (!fastClip.isEmpty()) {
- glEnable(GL_SCISSOR_TEST);
+ if (use_system_clip) {
+ clearClip(0);
- const int left = fastClip.left();
- const int width = fastClip.width();
- const int bottom = height - (fastClip.bottom() + 1);
- const int height = fastClip.height();
+ QPainterPath path;
+ path.addRegion(systemClip);
- glScissor(left, bottom, width, height);
- return;
+ q->state()->currentClip = 0;
+ writeClip(qtVectorPathForPath(q->state()->matrix.inverted().map(path)), 1);
+ q->state()->currentClip = 1;
+ q->state()->clipTestEnabled = true;
}
+}
- glClearDepthf(0x0);
- glDepthMask(true);
- glClear(GL_DEPTH_BUFFER_BIT);
- glClearDepthf(0x1);
+void QGL2PaintEngineEx::setState(QPainterState *new_state)
+{
+ // qDebug("QGL2PaintEngineEx::setState()");
- 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);
+ Q_D(QGL2PaintEngineEx);
- const int left = rect.left();
- const int width = rect.width();
- const int bottom = height - (rect.bottom() + 1);
- const int height = rect.height();
+ QOpenGL2PaintEngineState *s = static_cast<QOpenGL2PaintEngineState *>(new_state);
+ QOpenGL2PaintEngineState *old_state = state();
- glScissor(left, bottom, width, height);
+ QPaintEngineEx::setState(s);
- glClear(GL_DEPTH_BUFFER_BIT);
+ if (s->isNew) {
+ // Newly created state object. The call to setState()
+ // will either be followed by a call to begin(), or we are
+ // setting the state as part of a save().
+ s->isNew = false;
+ return;
}
- glDisable(GL_SCISSOR_TEST);
- glDepthMask(false);
- glDepthFunc(GL_LEQUAL);
- glEnable(GL_DEPTH_TEST);
-}
+ // Setting the state as part of a restore().
+ if (old_state == s || old_state->renderHintsChanged)
+ renderHintsChanged();
+ if (old_state == s || old_state->matrixChanged) {
+ d->matrixDirty = true;
+ d->simpleShaderMatrixUniformDirty = true;
+ d->shaderMatrixUniformDirty = true;
+ }
-void QGL2PaintEngineEx::setState(QPainterState *s)
-{
-// qDebug("QGL2PaintEngineEx::setState()");
+ if (old_state == s || old_state->compositionModeChanged)
+ d->compositionModeDirty = true;
- Q_D(QGL2PaintEngineEx);
- QPaintEngineEx::setState(s);
-
- d->updateDepthClip();
+ if (old_state == s || old_state->opacityChanged)
+ d->opacityUniformDirty = true;
- d->matrixDirty = true;
- d->compositionModeDirty = true;
- d->brushTextureDirty = true;
- d->brushUniformsDirty = true;
- d->simpleShaderMatrixUniformDirty = true;
- d->brushShaderMatrixUniformDirty = true;
- d->imageShaderMatrixUniformDirty = true;
- d->textShaderMatrixUniformDirty = true;
+ if (old_state == s || old_state->clipChanged) {
+ if (old_state && old_state != s && old_state->canRestoreClip) {
+ d->updateClipScissorTest();
+ glDepthFunc(GL_LEQUAL);
+ } else {
+ d->regenerateClip();
+ }
+ }
}
QPainterState *QGL2PaintEngineEx::createState(QPainterState *orig) const
{
- QOpenGLPaintEngineState *s;
+ if (orig)
+ const_cast<QGL2PaintEngineEx *>(this)->ensureActive();
+
+ QOpenGL2PaintEngineState *s;
if (!orig)
- s = new QOpenGLPaintEngineState();
+ s = new QOpenGL2PaintEngineState();
else
- s = new QOpenGLPaintEngineState(*static_cast<QOpenGLPaintEngineState *>(orig));
+ s = new QOpenGL2PaintEngineState(*static_cast<QOpenGL2PaintEngineState *>(orig));
+
+ s->matrixChanged = false;
+ s->compositionModeChanged = false;
+ s->opacityChanged = false;
+ s->renderHintsChanged = false;
+ s->clipChanged = false;
return s;
}
-QOpenGLPaintEngineState::QOpenGLPaintEngineState(QOpenGLPaintEngineState &other)
+void QGL2PaintEngineEx::setRenderTextActive(bool active)
+{
+ Q_D(QGL2PaintEngineEx);
+ d->inRenderText = active;
+}
+
+QOpenGL2PaintEngineState::QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other)
: QPainterState(other)
{
- clipRegion = other.clipRegion;
- hasClipping = other.hasClipping;
- fastClip = other.fastClip;
+ isNew = true;
+ needsClipBufferClear = other.needsClipBufferClear;
+ clipTestEnabled = other.clipTestEnabled;
+ currentClip = other.currentClip;
+ canRestoreClip = other.canRestoreClip;
+ rectangleClip = other.rectangleClip;
}
-QOpenGLPaintEngineState::QOpenGLPaintEngineState()
+QOpenGL2PaintEngineState::QOpenGL2PaintEngineState()
{
- hasClipping = false;
+ isNew = true;
+ needsClipBufferClear = true;
+ clipTestEnabled = false;
+ canRestoreClip = true;
}
-QOpenGLPaintEngineState::~QOpenGLPaintEngineState()
+QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState()
{
}
+QT_END_NAMESPACE
+
+#include "qpaintengineex_opengl2.moc"
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
index dea2304..f1ec6e6 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
@@ -53,25 +53,51 @@
// We mean it.
//
+#include <QDebug>
+
#include <private/qpaintengineex_p.h>
+#include <private/qglengineshadermanager_p.h>
+#include <private/qgl2pexvertexarray_p.h>
+#include <private/qglpaintdevice_p.h>
+#include <private/qglpixmapfilter_p.h>
+#include <private/qfontengine_p.h>
+#include <private/qdatabuffer_p.h>
+#include <private/qtriangulatingstroker_p.h>
+
+enum EngineMode {
+ ImageDrawingMode,
+ TextDrawingMode,
+ BrushDrawingMode,
+ ImageArrayDrawingMode
+};
+
+QT_BEGIN_NAMESPACE
class QGL2PaintEngineExPrivate;
-class QOpenGLPaintEngineState : public QPainterState
+class QOpenGL2PaintEngineState : public QPainterState
{
public:
- QOpenGLPaintEngineState(QOpenGLPaintEngineState &other);
- QOpenGLPaintEngineState();
- ~QOpenGLPaintEngineState();
+ QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other);
+ QOpenGL2PaintEngineState();
+ ~QOpenGL2PaintEngineState();
- QRegion clipRegion;
- bool hasClipping;
- QRect fastClip;
-};
+ uint isNew : 1;
+ uint needsClipBufferClear : 1;
+ uint clipTestEnabled : 1;
+ uint canRestoreClip : 1;
+ uint matrixChanged : 1;
+ uint compositionModeChanged : 1;
+ uint opacityChanged : 1;
+ uint renderHintsChanged : 1;
+ uint clipChanged : 1;
+ uint currentClip : 8;
+ QRect rectangleClip;
+};
-class QGL2PaintEngineEx : public QPaintEngineEx
+class Q_OPENGL_EXPORT QGL2PaintEngineEx : public QPaintEngineEx
{
Q_DECLARE_PRIVATE(QGL2PaintEngineEx)
public:
@@ -81,6 +107,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);
@@ -96,30 +124,178 @@ public:
virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr);
-
virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr,
Qt::ImageConversionFlags flags = Qt::AutoColor);
+ virtual void drawTexture(const QRectF &r, GLuint textureId, const QSize &size, const QRectF &sr);
+
virtual void drawTextItem(const QPointF &p, const QTextItem &textItem);
- void drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti);
- Type type() const { return OpenGL; }
+ virtual void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints);
+ Type type() const { return OpenGL2; }
- // State stuff is just for clipping and ripped off from QGLPaintEngine
void setState(QPainterState *s);
QPainterState *createState(QPainterState *orig) const;
- inline QOpenGLPaintEngineState *state() {
- return static_cast<QOpenGLPaintEngineState *>(QPaintEngineEx::state());
+ inline QOpenGL2PaintEngineState *state() {
+ return static_cast<QOpenGL2PaintEngineState *>(QPaintEngineEx::state());
}
- inline const QOpenGLPaintEngineState *state() const {
- return static_cast<const QOpenGLPaintEngineState *>(QPaintEngineEx::state());
+ inline const QOpenGL2PaintEngineState *state() const {
+ return static_cast<const QOpenGL2PaintEngineState *>(QPaintEngineEx::state());
}
- void updateClipRegion(const QRegion &clipRegion, Qt::ClipOperation op);
+
+ void beginNativePainting();
+ void endNativePainting();
+
+ const QGLContext* context();
+
+ QPixmapFilter *pixmapFilter(int type, const QPixmapFilter *prototype);
+
+ void setRenderTextActive(bool);
private:
Q_DISABLE_COPY(QGL2PaintEngineEx)
};
+class QGL2PaintEngineExPrivate : public QPaintEngineExPrivate
+{
+ Q_DECLARE_PUBLIC(QGL2PaintEngineEx)
+public:
+ enum StencilFillMode {
+ OddEvenFillMode,
+ WindingFillMode,
+ TriStripStrokeFillMode
+ };
+
+ QGL2PaintEngineExPrivate(QGL2PaintEngineEx *q_ptr) :
+ q(q_ptr),
+ width(0), height(0),
+ ctx(0),
+ inverseScale(1),
+ shaderManager(0),
+ inRenderText(false)
+ { }
+
+ ~QGL2PaintEngineExPrivate();
+
+ void updateBrushTexture();
+ void updateBrushUniforms();
+ void updateMatrix();
+ void updateCompositionMode();
+ void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id = -1);
+
+ void setBrush(const QBrush& brush);
+
+ void transferMode(EngineMode newMode);
+ void resetGLState();
+
+ // fill, drawOutline, drawTexture & drawCachedGlyphs are the rendering entry points:
+ void fill(const QVectorPath &path);
+ void drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern = false);
+ void drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType, const QTextItemInt &ti);
+
+ void drawVertexArrays(const float *data, int *stops, int stopCount, GLenum primitive);
+ void drawVertexArrays(QGL2PEXVertexArray &vertexArray, GLenum primitive) {
+ drawVertexArrays((const float *) vertexArray.data(), vertexArray.stops(), vertexArray.stopCount(), primitive);
+ }
+
+ // ^ draws whatever is in the vertex array
+ void composite(const QGLRect& boundingRect);
+ // ^ Composites the bounding rect onto dest buffer
+
+ void fillStencilWithVertexArray(const float *data, int count, int *stops, int stopCount, const QGLRect &bounds, StencilFillMode mode);
+ void fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill) {
+ fillStencilWithVertexArray((const float *) vertexArray.data(), 0, vertexArray.stops(), vertexArray.stopCount(),
+ vertexArray.boundingRect(),
+ useWindingFill ? WindingFillMode : OddEvenFillMode);
+ }
+ // ^ Calls drawVertexArrays to render into stencil buffer
+
+ bool prepareForDraw(bool srcPixelsAreOpaque);
+ // ^ returns whether the current program changed or not
+
+ inline void useSimpleShader();
+
+ void prepareDepthRangeForRenderText();
+ void restoreDepthRangeForRenderText();
+
+ static QGLEngineShaderManager* shaderManagerForEngine(QGL2PaintEngineEx *engine) { return engine->d_func()->shaderManager; }
+ static QGL2PaintEngineExPrivate *getData(QGL2PaintEngineEx *engine) { return engine->d_func(); }
+
+ QGL2PaintEngineEx* q;
+ QGLPaintDevice* device;
+ int width, height;
+ QGLContext *ctx;
+ EngineMode mode;
+ QFontEngineGlyphCache::Type glyphCacheType;
+
+ // Dirty flags
+ bool matrixDirty; // Implies matrix uniforms are also dirty
+ bool compositionModeDirty;
+ bool brushTextureDirty;
+ bool brushUniformsDirty;
+ bool simpleShaderMatrixUniformDirty;
+ bool shaderMatrixUniformDirty;
+ bool opacityUniformDirty;
+
+ bool stencilClean; // Has the stencil not been used for clipping so far?
+ QRegion dirtyStencilRegion;
+ QRect currentScissorBounds;
+ uint maxClip;
+
+ QBrush currentBrush; // May not be the state's brush!
+
+ GLfloat inverseScale;
+
+ QGL2PEXVertexArray vertexCoordinateArray;
+ QGL2PEXVertexArray textureCoordinateArray;
+ QDataBuffer<GLfloat> opacityArray;
+
+ GLfloat staticVertexCoordinateArray[8];
+ GLfloat staticTextureCoordinateArray[8];
+
+ GLfloat pmvMatrix[3][3];
+
+ QGLEngineShaderManager* shaderManager;
+
+ void clearClip(uint value);
+ void writeClip(const QVectorPath &path, uint value);
+ void resetClipIfNeeded();
+
+ void updateClipScissorTest();
+ void setScissor(const QRect &rect);
+ void regenerateClip();
+ void systemStateChanged();
+ uint use_system_clip : 1;
+
+ uint location(QGLEngineShaderManager::Uniform uniform)
+ {
+ return shaderManager->getUniformLocation(uniform);
+ }
+
+ GLuint lastTexture;
+
+ bool needsSync;
+ bool inRenderText;
+ bool multisamplingAlwaysEnabled;
+
+ GLfloat depthRange[2];
+
+ float textureInvertedY;
+
+ QTriangulatingStroker stroker;
+ QDashedStrokeProcessor dasher;
+ QTransform temporaryTransform;
+
+ QScopedPointer<QPixmapFilter> convolutionFilter;
+ QScopedPointer<QPixmapFilter> colorizeFilter;
+ QScopedPointer<QPixmapFilter> blurFilter;
+ QScopedPointer<QPixmapFilter> dropShadowFilter;
+
+ QSet<QVectorPath::CacheEntry *> pathCaches;
+ QVector<GLuint> unusedVBOSToClean;
+};
+
+QT_END_NAMESPACE
#endif
diff --git a/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp b/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp
new file mode 100644
index 0000000..395b8a3
--- /dev/null
+++ b/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp
@@ -0,0 +1,555 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtriangulatingstroker_p.h"
+#include <qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+#define CURVE_FLATNESS Q_PI / 8
+
+
+
+
+void QTriangulatingStroker::endCapOrJoinClosed(const qreal *start, const qreal *cur,
+ bool implicitClose, bool endsAtStart)
+{
+ if (endsAtStart) {
+ join(start + 2);
+ } else if (implicitClose) {
+ join(start);
+ lineTo(start);
+ join(start+2);
+ } else {
+ endCap(cur);
+ }
+ int count = m_vertices.size();
+
+ // Copy the (x, y) values because QDataBuffer::add(const float& t)
+ // may resize the buffer, which will leave t pointing at the
+ // previous buffer's memory region if we don't copy first.
+ float x = m_vertices.at(count-2);
+ float y = m_vertices.at(count-1);
+ m_vertices.add(x);
+ m_vertices.add(y);
+}
+
+
+void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen)
+{
+ const qreal *pts = path.points();
+ const QPainterPath::ElementType *types = path.elements();
+ int count = path.elementCount();
+ if (count < 2)
+ return;
+
+ float realWidth = qpen_widthf(pen);
+ if (realWidth == 0)
+ realWidth = 1;
+
+ m_width = realWidth / 2;
+
+ bool cosmetic = pen.isCosmetic();
+ if (cosmetic) {
+ m_width = m_width * m_inv_scale;
+ }
+
+ m_join_style = qpen_joinStyle(pen);
+ m_cap_style = qpen_capStyle(pen);
+ m_vertices.reset();
+ m_miter_limit = pen.miterLimit() * qpen_widthf(pen);
+
+ // The curvyness is based on the notion that I originally wanted
+ // roughly one line segment pr 4 pixels. This may seem little, but
+ // because we sample at constantly incrementing B(t) E [0<t<1], we
+ // will get longer segments where the curvature is small and smaller
+ // segments when the curvature is high.
+ //
+ // To get a rough idea of the length of each curve, I pretend that
+ // the curve is a 90 degree arc, whose radius is
+ // qMax(curveBounds.width, curveBounds.height). Based on this
+ // logic we can estimate the length of the outline edges based on
+ // the radius + a pen width and adjusting for scale factors
+ // depending on if the pen is cosmetic or not.
+ //
+ // The curvyness value of PI/14 was based on,
+ // arcLength=2*PI*r/4=PI/2 and splitting length into somewhere
+ // between 3 and 8 where 5 seemed to be give pretty good results
+ // hence: Q_PI/14. Lower divisors will give more detail at the
+ // direct cost of performance.
+
+ // simplfy pens that are thin in device size (2px wide or less)
+ if (realWidth < 2.5 && (cosmetic || m_inv_scale == 1)) {
+ if (m_cap_style == Qt::RoundCap)
+ m_cap_style = Qt::SquareCap;
+ if (m_join_style == Qt::RoundJoin)
+ m_join_style = Qt::MiterJoin;
+ m_curvyness_add = 0.5;
+ m_curvyness_mul = CURVE_FLATNESS / m_inv_scale;
+ m_roundness = 1;
+ } else if (cosmetic) {
+ m_curvyness_add = realWidth / 2;
+ m_curvyness_mul = CURVE_FLATNESS;
+ m_roundness = qMax<int>(4, realWidth * CURVE_FLATNESS);
+ } else {
+ m_curvyness_add = m_width;
+ m_curvyness_mul = CURVE_FLATNESS / m_inv_scale;
+ m_roundness = qMax<int>(4, realWidth * m_curvyness_mul);
+ }
+
+ // Over this level of segmentation, there doesn't seem to be any
+ // benefit, even for huge penWidth
+ if (m_roundness > 24)
+ m_roundness = 24;
+
+ m_sin_theta = qFastSin(Q_PI / m_roundness);
+ m_cos_theta = qFastCos(Q_PI / m_roundness);
+
+ const qreal *endPts = pts + (count<<1);
+ const qreal *startPts;
+
+ Qt::PenCapStyle cap = m_cap_style;
+
+ if (!types) {
+ startPts = pts;
+
+ bool endsAtStart = startPts[0] == *(endPts-2) && startPts[1] == *(endPts-1);
+
+ if (endsAtStart || path.hasImplicitClose())
+ m_cap_style = Qt::FlatCap;
+ moveTo(pts);
+ m_cap_style = cap;
+ pts += 2;
+ lineTo(pts);
+ pts += 2;
+ while (pts < endPts) {
+ join(pts);
+ lineTo(pts);
+ pts += 2;
+ }
+
+ endCapOrJoinClosed(startPts, pts-2, path.hasImplicitClose(), endsAtStart);
+
+ } else {
+ bool endsAtStart;
+ while (pts < endPts) {
+ switch (*types) {
+ case QPainterPath::MoveToElement: {
+ if (pts != path.points())
+ endCapOrJoinClosed(startPts, pts-2, path.hasImplicitClose(), endsAtStart);
+
+ startPts = pts;
+ int end = (endPts - pts) / 2;
+ int i = 2; // Start looking to ahead since we never have two moveto's in a row
+ while (i<end && types[i] != QPainterPath::MoveToElement) {
+ ++i;
+ }
+ endsAtStart = startPts[0] == pts[i*2 - 2] && startPts[1] == pts[i*2 - 1];
+ if (endsAtStart || path.hasImplicitClose())
+ m_cap_style = Qt::FlatCap;
+
+ moveTo(pts);
+ m_cap_style = cap;
+ pts+=2;
+ ++types;
+ break; }
+ case QPainterPath::LineToElement:
+ if (*(types - 1) != QPainterPath::MoveToElement)
+ join(pts);
+ lineTo(pts);
+ pts+=2;
+ ++types;
+ break;
+ case QPainterPath::CurveToElement:
+ if (*(types - 1) != QPainterPath::MoveToElement)
+ join(pts);
+ cubicTo(pts);
+ pts+=6;
+ types+=3;
+ break;
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+ }
+
+ endCapOrJoinClosed(startPts, pts-2, path.hasImplicitClose(), endsAtStart);
+ }
+}
+
+void QTriangulatingStroker::moveTo(const qreal *pts)
+{
+ m_cx = pts[0];
+ m_cy = pts[1];
+
+ float x2 = pts[2];
+ float y2 = pts[3];
+ normalVector(m_cx, m_cy, x2, y2, &m_nvx, &m_nvy);
+
+
+ // To acheive jumps we insert zero-area tringles. This is done by
+ // adding two identical points in both the end of previous strip
+ // and beginning of next strip
+ bool invisibleJump = m_vertices.size();
+
+ switch (m_cap_style) {
+ case Qt::FlatCap:
+ if (invisibleJump) {
+ m_vertices.add(m_cx + m_nvx);
+ m_vertices.add(m_cy + m_nvy);
+ }
+ break;
+ case Qt::SquareCap: {
+ float sx = m_cx - m_nvy;
+ float sy = m_cy + m_nvx;
+ if (invisibleJump) {
+ m_vertices.add(sx + m_nvx);
+ m_vertices.add(sy + m_nvy);
+ }
+ emitLineSegment(sx, sy, m_nvx, m_nvy);
+ break; }
+ case Qt::RoundCap: {
+ QVarLengthArray<float> points;
+ arcPoints(m_cx, m_cy, m_cx + m_nvx, m_cy + m_nvy, m_cx - m_nvx, m_cy - m_nvy, points);
+ m_vertices.resize(m_vertices.size() + points.size() + 2 * int(invisibleJump));
+ int count = m_vertices.size();
+ int front = 0;
+ int end = points.size() / 2;
+ while (front != end) {
+ m_vertices.at(--count) = points[2 * end - 1];
+ m_vertices.at(--count) = points[2 * end - 2];
+ --end;
+ if (front == end)
+ break;
+ m_vertices.at(--count) = points[2 * front + 1];
+ m_vertices.at(--count) = points[2 * front + 0];
+ ++front;
+ }
+
+ if (invisibleJump) {
+ m_vertices.at(count - 1) = m_vertices.at(count + 1);
+ m_vertices.at(count - 2) = m_vertices.at(count + 0);
+ }
+ break; }
+ default: break; // ssssh gcc...
+ }
+ emitLineSegment(m_cx, m_cy, m_nvx, m_nvy);
+}
+
+void QTriangulatingStroker::cubicTo(const qreal *pts)
+{
+ const QPointF *p = (const QPointF *) pts;
+ QBezier bezier = QBezier::fromPoints(*(p - 1), p[0], p[1], p[2]);
+
+ QRectF bounds = bezier.bounds();
+ float rad = qMax(bounds.width(), bounds.height());
+ int threshold = qMin<float>(64, (rad + m_curvyness_add) * m_curvyness_mul);
+ if (threshold < 4)
+ threshold = 4;
+ qreal threshold_minus_1 = threshold - 1;
+ float vx, vy;
+
+ float cx = m_cx, cy = m_cy;
+ float x, y;
+
+ for (int i=1; i<threshold; ++i) {
+ qreal t = qreal(i) / threshold_minus_1;
+ QPointF p = bezier.pointAt(t);
+ x = p.x();
+ y = p.y();
+
+ normalVector(cx, cy, x, y, &vx, &vy);
+
+ emitLineSegment(x, y, vx, vy);
+
+ cx = x;
+ cy = y;
+ }
+
+ m_cx = cx;
+ m_cy = cy;
+
+ m_nvx = vx;
+ m_nvy = vy;
+}
+
+void QTriangulatingStroker::join(const qreal *pts)
+{
+ // Creates a join to the next segment (m_cx, m_cy) -> (pts[0], pts[1])
+ normalVector(m_cx, m_cy, pts[0], pts[1], &m_nvx, &m_nvy);
+
+ switch (m_join_style) {
+ case Qt::BevelJoin:
+ break;
+ case Qt::SvgMiterJoin:
+ case Qt::MiterJoin: {
+ // Find out on which side the join should be.
+ int count = m_vertices.size();
+ float prevNvx = m_vertices.at(count - 2) - m_cx;
+ float prevNvy = m_vertices.at(count - 1) - m_cy;
+ float xprod = prevNvx * m_nvy - prevNvy * m_nvx;
+ float px, py, qx, qy;
+
+ // If the segments are parallel, use bevel join.
+ if (qFuzzyIsNull(xprod))
+ break;
+
+ // Find the corners of the previous and next segment to join.
+ if (xprod < 0) {
+ px = m_vertices.at(count - 2);
+ py = m_vertices.at(count - 1);
+ qx = m_cx - m_nvx;
+ qy = m_cy - m_nvy;
+ } else {
+ px = m_vertices.at(count - 4);
+ py = m_vertices.at(count - 3);
+ qx = m_cx + m_nvx;
+ qy = m_cy + m_nvy;
+ }
+
+ // Find intersection point.
+ float pu = px * prevNvx + py * prevNvy;
+ float qv = qx * m_nvx + qy * m_nvy;
+ float ix = (m_nvy * pu - prevNvy * qv) / xprod;
+ float iy = (prevNvx * qv - m_nvx * pu) / xprod;
+
+ // Check that the distance to the intersection point is less than the miter limit.
+ if ((ix - px) * (ix - px) + (iy - py) * (iy - py) <= m_miter_limit * m_miter_limit) {
+ m_vertices.add(ix);
+ m_vertices.add(iy);
+ m_vertices.add(ix);
+ m_vertices.add(iy);
+ }
+ // else
+ // Do a plain bevel join if the miter limit is exceeded or if
+ // the lines are parallel. This is not what the raster
+ // engine's stroker does, but it is both faster and similar to
+ // what some other graphics API's do.
+
+ break; }
+ case Qt::RoundJoin: {
+ QVarLengthArray<float> points;
+ int count = m_vertices.size();
+ float prevNvx = m_vertices.at(count - 2) - m_cx;
+ float prevNvy = m_vertices.at(count - 1) - m_cy;
+ if (m_nvx * prevNvy - m_nvy * prevNvx < 0) {
+ arcPoints(0, 0, m_nvx, m_nvy, -prevNvx, -prevNvy, points);
+ for (int i = points.size() / 2; i > 0; --i)
+ emitLineSegment(m_cx, m_cy, points[2 * i - 2], points[2 * i - 1]);
+ } else {
+ arcPoints(0, 0, -prevNvx, -prevNvy, m_nvx, m_nvy, points);
+ for (int i = 0; i < points.size() / 2; ++i)
+ emitLineSegment(m_cx, m_cy, points[2 * i + 0], points[2 * i + 1]);
+ }
+ break; }
+ default: break; // gcc warn--
+ }
+
+ emitLineSegment(m_cx, m_cy, m_nvx, m_nvy);
+}
+
+void QTriangulatingStroker::endCap(const qreal *)
+{
+ switch (m_cap_style) {
+ case Qt::FlatCap:
+ break;
+ case Qt::SquareCap:
+ emitLineSegment(m_cx + m_nvy, m_cy - m_nvx, m_nvx, m_nvy);
+ break;
+ case Qt::RoundCap: {
+ QVarLengthArray<float> points;
+ int count = m_vertices.size();
+ arcPoints(m_cx, m_cy, m_vertices.at(count - 2), m_vertices.at(count - 1), m_vertices.at(count - 4), m_vertices.at(count - 3), points);
+ int front = 0;
+ int end = points.size() / 2;
+ while (front != end) {
+ m_vertices.add(points[2 * end - 2]);
+ m_vertices.add(points[2 * end - 1]);
+ --end;
+ if (front == end)
+ break;
+ m_vertices.add(points[2 * front + 0]);
+ m_vertices.add(points[2 * front + 1]);
+ ++front;
+ }
+ break; }
+ default: break; // to shut gcc up...
+ }
+}
+
+void QTriangulatingStroker::arcPoints(float cx, float cy, float fromX, float fromY, float toX, float toY, QVarLengthArray<float> &points)
+{
+ float dx1 = fromX - cx;
+ float dy1 = fromY - cy;
+ float dx2 = toX - cx;
+ float dy2 = toY - cy;
+
+ // while more than 180 degrees left:
+ while (dx1 * dy2 - dx2 * dy1 < 0) {
+ float tmpx = dx1 * m_cos_theta - dy1 * m_sin_theta;
+ float tmpy = dx1 * m_sin_theta + dy1 * m_cos_theta;
+ dx1 = tmpx;
+ dy1 = tmpy;
+ points.append(cx + dx1);
+ points.append(cy + dy1);
+ }
+
+ // while more than 90 degrees left:
+ while (dx1 * dx2 + dy1 * dy2 < 0) {
+ float tmpx = dx1 * m_cos_theta - dy1 * m_sin_theta;
+ float tmpy = dx1 * m_sin_theta + dy1 * m_cos_theta;
+ dx1 = tmpx;
+ dy1 = tmpy;
+ points.append(cx + dx1);
+ points.append(cy + dy1);
+ }
+
+ // while more than 0 degrees left:
+ while (dx1 * dy2 - dx2 * dy1 > 0) {
+ float tmpx = dx1 * m_cos_theta - dy1 * m_sin_theta;
+ float tmpy = dx1 * m_sin_theta + dy1 * m_cos_theta;
+ dx1 = tmpx;
+ dy1 = tmpy;
+ points.append(cx + dx1);
+ points.append(cy + dy1);
+ }
+
+ // remove last point which was rotated beyond [toX, toY].
+ if (!points.isEmpty())
+ points.resize(points.size() - 2);
+}
+
+static void qdashprocessor_moveTo(qreal x, qreal y, void *data)
+{
+ ((QDashedStrokeProcessor *) data)->addElement(QPainterPath::MoveToElement, x, y);
+}
+
+static void qdashprocessor_lineTo(qreal x, qreal y, void *data)
+{
+ ((QDashedStrokeProcessor *) data)->addElement(QPainterPath::LineToElement, x, y);
+}
+
+static void qdashprocessor_cubicTo(qreal, qreal, qreal, qreal, qreal, qreal, void *)
+{
+ Q_ASSERT(0); // The dasher should not produce curves...
+}
+
+QDashedStrokeProcessor::QDashedStrokeProcessor()
+ : m_dash_stroker(0), m_inv_scale(1)
+{
+ m_dash_stroker.setMoveToHook(qdashprocessor_moveTo);
+ m_dash_stroker.setLineToHook(qdashprocessor_lineTo);
+ m_dash_stroker.setCubicToHook(qdashprocessor_cubicTo);
+}
+
+void QDashedStrokeProcessor::process(const QVectorPath &path, const QPen &pen)
+{
+
+ const qreal *pts = path.points();
+ const QPainterPath::ElementType *types = path.elements();
+ int count = path.elementCount();
+
+ m_points.reset();
+ m_types.reset();
+
+ qreal width = qpen_widthf(pen);
+ if (width == 0)
+ width = 1;
+
+ m_dash_stroker.setDashPattern(pen.dashPattern());
+ m_dash_stroker.setStrokeWidth(pen.isCosmetic() ? width * m_inv_scale : width);
+ m_dash_stroker.setMiterLimit(pen.miterLimit());
+ qreal curvyness = sqrt(width) * m_inv_scale / 8;
+
+ if (count < 2)
+ return;
+
+ const qreal *endPts = pts + (count<<1);
+
+ m_dash_stroker.begin(this);
+
+ if (!types) {
+ m_dash_stroker.moveTo(pts[0], pts[1]);
+ pts += 2;
+ while (pts < endPts) {
+ m_dash_stroker.lineTo(pts[0], pts[1]);
+ pts += 2;
+ }
+ } else {
+ while (pts < endPts) {
+ switch (*types) {
+ case QPainterPath::MoveToElement:
+ m_dash_stroker.moveTo(pts[0], pts[1]);
+ pts += 2;
+ ++types;
+ break;
+ case QPainterPath::LineToElement:
+ m_dash_stroker.lineTo(pts[0], pts[1]);
+ pts += 2;
+ ++types;
+ break;
+ case QPainterPath::CurveToElement: {
+ QBezier b = QBezier::fromPoints(*(((const QPointF *) pts) - 1),
+ *(((const QPointF *) pts)),
+ *(((const QPointF *) pts) + 1),
+ *(((const QPointF *) pts) + 2));
+ QRectF bounds = b.bounds();
+ int threshold = qMin<float>(64, qMax(bounds.width(), bounds.height()) * curvyness);
+ if (threshold < 4)
+ threshold = 4;
+ qreal threshold_minus_1 = threshold - 1;
+ for (int i=0; i<threshold; ++i) {
+ QPointF pt = b.pointAt(i / threshold_minus_1);
+ m_dash_stroker.lineTo(pt.x(), pt.y());
+ }
+ pts += 6;
+ types += 3;
+ break; }
+ default: break;
+ }
+ }
+ }
+
+ m_dash_stroker.end();
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/opengl/gl2paintengineex/qtriangulatingstroker_p.h b/src/opengl/gl2paintengineex/qtriangulatingstroker_p.h
new file mode 100644
index 0000000..2dba0ce
--- /dev/null
+++ b/src/opengl/gl2paintengineex/qtriangulatingstroker_p.h
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTRIANGULATINGSTROKER_P_H
+#define QTRIANGULATINGSTROKER_P_H
+
+#include <private/qdatabuffer_p.h>
+#include <qvarlengtharray.h>
+#include <private/qvectorpath_p.h>
+#include <private/qbezier_p.h>
+#include <private/qnumeric_p.h>
+#include <private/qmath_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTriangulatingStroker
+{
+public:
+ void process(const QVectorPath &path, const QPen &pen);
+
+ inline int vertexCount() const { return m_vertices.size(); }
+ inline const float *vertices() const { return m_vertices.data(); }
+
+ inline void setInvScale(qreal invScale) { m_inv_scale = invScale; }
+
+private:
+ inline void emitLineSegment(float x, float y, float nx, float ny);
+ void moveTo(const qreal *pts);
+ inline void lineTo(const qreal *pts);
+ void cubicTo(const qreal *pts);
+ void join(const qreal *pts);
+ inline void normalVector(float x1, float y1, float x2, float y2, float *nx, float *ny);
+ void endCap(const qreal *pts);
+ void arcPoints(float cx, float cy, float fromX, float fromY, float toX, float toY, QVarLengthArray<float> &points);
+ void endCapOrJoinClosed(const qreal *start, const qreal *cur, bool implicitClose, bool endsAtStart);
+
+
+ QDataBuffer<float> m_vertices;
+
+ float m_cx, m_cy; // current points
+ float m_nvx, m_nvy; // normal vector...
+ float m_width;
+ qreal m_miter_limit;
+
+ int m_roundness; // Number of line segments in a round join
+ qreal m_sin_theta; // sin(m_roundness / 360);
+ qreal m_cos_theta; // cos(m_roundness / 360);
+ qreal m_inv_scale;
+ float m_curvyness_mul;
+ float m_curvyness_add;
+
+ Qt::PenJoinStyle m_join_style;
+ Qt::PenCapStyle m_cap_style;
+};
+
+class QDashedStrokeProcessor
+{
+public:
+ QDashedStrokeProcessor();
+
+ void process(const QVectorPath &path, const QPen &pen);
+
+ inline void addElement(QPainterPath::ElementType type, qreal x, qreal y) {
+ m_points.add(x);
+ m_points.add(y);
+ m_types.add(type);
+ }
+
+ inline int elementCount() const { return m_types.size(); }
+ inline qreal *points() const { return m_points.data(); }
+ inline QPainterPath::ElementType *elementTypes() const { return m_types.data(); }
+
+ inline void setInvScale(qreal invScale) { m_inv_scale = invScale; }
+
+private:
+ QDataBuffer<qreal> m_points;
+ QDataBuffer<QPainterPath::ElementType> m_types;
+ QDashStroker m_dash_stroker;
+ qreal m_inv_scale;
+};
+
+inline void QTriangulatingStroker::normalVector(float x1, float y1, float x2, float y2,
+ float *nx, float *ny)
+{
+ float dx = x2 - x1;
+ float dy = y2 - y1;
+
+ float pw;
+
+ if (dx == 0)
+ pw = m_width / qAbs(dy);
+ else if (dy == 0)
+ pw = m_width / qAbs(dx);
+ else
+ pw = m_width / sqrt(dx*dx + dy*dy);
+
+ *nx = -dy * pw;
+ *ny = dx * pw;
+}
+
+inline void QTriangulatingStroker::emitLineSegment(float x, float y, float vx, float vy)
+{
+ m_vertices.add(x + vx);
+ m_vertices.add(y + vy);
+ m_vertices.add(x - vx);
+ m_vertices.add(y - vy);
+}
+
+void QTriangulatingStroker::lineTo(const qreal *pts)
+{
+ emitLineSegment(pts[0], pts[1], m_nvx, m_nvy);
+ m_cx = pts[0];
+ m_cy = pts[1];
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro
index 78aaddb..b2474ed 100644
--- a/src/opengl/opengl.pro
+++ b/src/opengl/opengl.pro
@@ -13,55 +13,75 @@ include(../qbase.pri)
!win32:!embedded:!mac:CONFIG += x11
contains(QT_CONFIG, opengl):CONFIG += opengl
contains(QT_CONFIG, opengles1):CONFIG += opengles1
+contains(QT_CONFIG, opengles1cl):CONFIG += opengles1cl
contains(QT_CONFIG, opengles2):CONFIG += opengles2
-
-!contains(QT_CONFIG, opengles2) {
- HEADERS += qgraphicssystem_gl_p.h qwindowsurface_gl_p.h qpixmapdata_gl_p.h
- SOURCES += qgraphicssystem_gl.cpp qwindowsurface_gl.cpp qpixmapdata_gl.cpp
-}
+contains(QT_CONFIG, egl):CONFIG += egl
HEADERS += qgl.h \
qgl_p.h \
qglcolormap.h \
qglpixelbuffer.h \
+ qglpixelbuffer_p.h \
qglframebufferobject.h \
+ qglframebufferobject_p.h \
+ qglextensions_p.h \
+ qglpaintdevice_p.h \
+
SOURCES += qgl.cpp \
qglcolormap.cpp \
qglpixelbuffer.cpp \
qglframebufferobject.cpp \
qglextensions.cpp \
+ qglpaintdevice.cpp \
+
!contains(QT_CONFIG, opengles2) {
- HEADERS += qpaintengine_opengl_p.h qglpixmapfilter_p.h
- SOURCES += qpaintengine_opengl.cpp qglpixmapfilter.cpp
+ HEADERS += qpaintengine_opengl_p.h
+ SOURCES += qpaintengine_opengl.cpp
}
-contains(QT_CONFIG, opengles2) {
- SOURCES += gl2paintengineex/qglgradientcache.cpp \
- gl2paintengineex/qglpexshadermanager.cpp \
- gl2paintengineex/qglshader.cpp \
+!contains(QT_CONFIG, opengles1):!contains(QT_CONFIG, opengles1cl) {
+ HEADERS += qglshaderprogram.h \
+ qglpixmapfilter_p.h \
+ qgraphicsshadereffect_p.h \
+ qgraphicssystem_gl_p.h \
+ qwindowsurface_gl_p.h \
+ qpixmapdata_gl_p.h \
+ gl2paintengineex/qglgradientcache_p.h \
+ gl2paintengineex/qglengineshadermanager_p.h \
+ gl2paintengineex/qgl2pexvertexarray_p.h \
+ gl2paintengineex/qpaintengineex_opengl2_p.h \
+ gl2paintengineex/qglengineshadersource_p.h \
+ gl2paintengineex/qglcustomshaderstage_p.h \
+ gl2paintengineex/qtriangulatingstroker_p.h
+
+ SOURCES += qglshaderprogram.cpp \
+ qglpixmapfilter.cpp \
+ qgraphicsshadereffect.cpp \
+ qgraphicssystem_gl.cpp \
+ qwindowsurface_gl.cpp \
+ qpixmapdata_gl.cpp \
+ gl2paintengineex/qglgradientcache.cpp \
+ gl2paintengineex/qglengineshadermanager.cpp \
gl2paintengineex/qgl2pexvertexarray.cpp \
- gl2paintengineex/qpaintengineex_opengl2.cpp
+ gl2paintengineex/qpaintengineex_opengl2.cpp \
+ gl2paintengineex/qglcustomshaderstage.cpp \
+ gl2paintengineex/qtriangulatingstroker.cpp
- HEADERS += gl2paintengineex/qglgradientcache_p.h \
- gl2paintengineex/qglpexshadermanager_p.h \
- gl2paintengineex/qglshader_p.h \
- gl2paintengineex/qgl2pexvertexarray_p.h \
- gl2paintengineex/qpaintengineex_opengl2_p.h
}
-
x11 {
contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles1cl)|contains(QT_CONFIG, opengles2) {
SOURCES += qgl_x11egl.cpp \
qglpixelbuffer_egl.cpp \
qgl_egl.cpp \
- qegl.cpp \
- qegl_x11egl.cpp
+ qpixmapdata_x11gl_egl.cpp \
+ qwindowsurface_x11gl.cpp
- HEADERS += qegl_p.h \
- qgl_egl_p.h
+ HEADERS += qgl_egl_p.h \
+ qpixmapdata_x11gl_p.h \
+ qwindowsurface_x11gl_p.h
} else {
SOURCES += qgl_x11.cpp \
@@ -69,16 +89,26 @@ x11 {
}
contains(QT_CONFIG, fontconfig) {
+ contains(QT_CONFIG, system-freetype) {
+ embedded:CONFIG += opentype
+ # pull in the proper freetype2 include directory
include($$QT_SOURCE_TREE/config.tests/unix/freetype/freetype.pri)
+ LIBS_PRIVATE += -lfreetype
+ } else {
+ ### Note: how does this compile with a non-system freetype?
+ # This probably does not compile
+ }
} else {
DEFINES *= QT_NO_FREETYPE
}
+
+ LIBS_PRIVATE += $$QMAKE_LIBS_DYNLOAD
}
mac {
OBJECTIVE_SOURCES += qgl_mac.mm \
qglpixelbuffer_mac.mm
- LIBS += -framework AppKit
+ LIBS_PRIVATE += -framework AppKit -framework Carbon
}
win32:!wince*: {
SOURCES += qgl_win.cpp \
@@ -87,30 +117,22 @@ win32:!wince*: {
wince*: {
SOURCES += qgl_wince.cpp \
qglpixelbuffer_egl.cpp \
- qgl_egl.cpp \
- qegl.cpp \
- qegl_wince.cpp
+ qgl_egl.cpp
HEADERS += qgl_cl_p.h \
qgl_egl_p.h \
- qegl_p.h
}
embedded {
SOURCES += qgl_qws.cpp \
- qglpaintdevice_qws.cpp \
qglpixelbuffer_egl.cpp \
qglscreen_qws.cpp \
qglwindowsurface_qws.cpp \
- qegl.cpp \
- qegl_qws.cpp \
qgl_egl.cpp
- HEADERS += qglpaintdevice_qws_p.h \
- qglscreen_qws.h \
+ HEADERS += qglscreen_qws.h \
qglwindowsurface_qws_p.h \
- qgl_egl_p.h \
- qegl_p.h
+ qgl_egl_p.h
contains(QT_CONFIG, fontconfig) {
include($$QT_SOURCE_TREE/config.tests/unix/freetype/freetype.pri)
@@ -120,18 +142,3 @@ embedded {
}
INCLUDEPATH += ../3rdparty/harfbuzz/src
-
-wince*: {
- contains(QT_CONFIG,opengles1) {
- QMAKE_LIBS += "libGLES_CM.lib"
- }
- contains(QT_CONFIG,opengles1cl) {
- QMAKE_LIBS += "libGLES_CL.lib"
- }
- contains(QT_CONFIG,opengles2) {
- QMAKE_LIBS += "libGLESv2.lib"
- }
-
-} else {
- QMAKE_LIBS += $$QMAKE_LIBS_OPENGL
-}
diff --git a/src/opengl/qegl.cpp b/src/opengl/qegl.cpp
deleted file mode 100644
index a1c3e02..0000000
--- a/src/opengl/qegl.cpp
+++ /dev/null
@@ -1,787 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
-** this package.
-**
-** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtGui/qpaintdevice.h>
-#include <QtGui/qpixmap.h>
-#include <QtGui/qwidget.h>
-#include <QtCore/qdebug.h>
-#include "qegl_p.h"
-
-#if defined(QT_OPENGL_ES) || defined(QT_OPENVG)
-
-QT_BEGIN_NAMESPACE
-
-QEglContext::QEglContext()
-{
- apiType = OpenGL;
- dpy = EGL_NO_DISPLAY;
- ctx = EGL_NO_CONTEXT;
- surf = EGL_NO_SURFACE;
- cfg = 0;
- share = false;
- reserved = 0;
-}
-
-QEglContext::~QEglContext()
-{
- destroy();
-}
-
-bool QEglContext::isValid() const
-{
- return (ctx != EGL_NO_CONTEXT);
-}
-
-bool QEglContext::isSharing() const
-{
- return share;
-}
-
-// Open the EGL display associated with "device".
-bool QEglContext::openDisplay(QPaintDevice *device)
-{
- if (dpy == EGL_NO_DISPLAY)
- dpy = defaultDisplay(device);
- return (dpy != EGL_NO_DISPLAY);
-}
-
-// Choose a configuration that matches "properties".
-bool QEglContext::chooseConfig
- (const QEglProperties& properties, PixelFormatMatch match)
-{
- QEglProperties props(properties);
- EGLConfig *configs;
- EGLint matching, size;
- do {
- // Get the number of matching configurations for this set of properties.
- matching = 0;
- if (!eglChooseConfig(dpy, props.properties(), 0, 256, &matching) || !matching)
- continue;
-
- // If we want the best pixel format, then return the first
- // matching configuration.
- if (match == BestPixelFormat) {
- eglChooseConfig(dpy, props.properties(), &cfg, 1, &matching);
- if (matching < 1)
- continue;
- return true;
- }
-
- // Fetch all of the matching configurations and find the
- // first that matches the pixel format we wanted.
- size = matching;
- configs = new EGLConfig [size];
- eglChooseConfig(dpy, props.properties(), configs, size, &matching);
- for (EGLint index = 0; index < size; ++index) {
- EGLint red, green, blue, alpha;
- eglGetConfigAttrib(dpy, configs[index], EGL_RED_SIZE, &red);
- eglGetConfigAttrib(dpy, configs[index], EGL_GREEN_SIZE, &green);
- eglGetConfigAttrib(dpy, configs[index], EGL_BLUE_SIZE, &blue);
- eglGetConfigAttrib(dpy, configs[index], EGL_ALPHA_SIZE, &alpha);
- if (red == props.value(EGL_RED_SIZE) &&
- green == props.value(EGL_GREEN_SIZE) &&
- blue == props.value(EGL_BLUE_SIZE) &&
- (props.value(EGL_ALPHA_SIZE) == EGL_DONT_CARE ||
- alpha == props.value(EGL_ALPHA_SIZE))) {
- cfg = configs[index];
- delete [] configs;
- return true;
- }
- }
- delete [] configs;
- } while (props.reduceConfiguration());
-
-#ifdef EGL_BIND_TO_TEXTURE_RGBA
- // Don't report an error just yet if we failed to get a pbuffer
- // configuration with texture rendering. Only report failure if
- // we cannot get any pbuffer configurations at all.
- if (props.value(EGL_BIND_TO_TEXTURE_RGBA) == EGL_DONT_CARE &&
- props.value(EGL_BIND_TO_TEXTURE_RGB) == EGL_DONT_CARE)
-#endif
- {
- qWarning() << "QEglContext::chooseConfig(): Could not find a suitable EGL configuration";
- qWarning() << "Requested:" << props.toString();
- qWarning() << "Available:";
- dumpAllConfigs();
- }
- return false;
-}
-
-// Create the EGLContext.
-bool QEglContext::createContext(QEglContext *shareContext)
-{
- // We need to select the correct API before calling eglCreateContext().
-#ifdef EGL_OPENGL_ES_API
- if (apiType == OpenGL)
- eglBindAPI(EGL_OPENGL_ES_API);
-#endif
-#ifdef EGL_OPENVG_API
- if (apiType == OpenVG)
- eglBindAPI(EGL_OPENVG_API);
-#endif
-
- // Create a new context for the configuration.
- QEglProperties contextProps;
-#if defined(QT_OPENGL_ES_2)
- if (apiType == OpenGL)
- contextProps.setValue(EGL_CONTEXT_CLIENT_VERSION, 2);
-#endif
- if (shareContext && shareContext->ctx == EGL_NO_CONTEXT)
- shareContext = 0;
- if (shareContext) {
- ctx = eglCreateContext(dpy, cfg, shareContext->ctx, contextProps.properties());
- if (ctx == EGL_NO_CONTEXT) {
- qWarning() << "QEglContext::createContext(): Could not share context:" << errorString(eglGetError());
- shareContext = 0;
- }
- }
- if (ctx == EGL_NO_CONTEXT) {
- ctx = eglCreateContext(dpy, cfg, 0, contextProps.properties());
- if (ctx == EGL_NO_CONTEXT) {
- qWarning() << "QEglContext::createContext(): Unable to create EGL context:" << errorString(eglGetError());
- return false;
- }
- }
- share = (shareContext != 0);
- return true;
-}
-
-// Recreate the surface for a paint device because the native id has changed.
-bool QEglContext::recreateSurface(QPaintDevice *device)
-{
- // Bail out if the surface has not been created for the first time yet.
- if (surf == EGL_NO_SURFACE)
- return true;
-
- // Destroy the old surface.
- eglDestroySurface(dpy, surf);
-
- // Create a new one.
- return createSurface(device);
-}
-
-void QEglContext::destroy()
-{
- if (ctx != EGL_NO_CONTEXT)
- eglDestroyContext(dpy, ctx);
- dpy = EGL_NO_DISPLAY;
- ctx = EGL_NO_CONTEXT;
- surf = EGL_NO_SURFACE;
- cfg = 0;
- share = false;
-}
-
-bool QEglContext::makeCurrent()
-{
- if(ctx == EGL_NO_CONTEXT) {
- qWarning() << "QEglContext::makeCurrent(): Cannot make invalid context current";
- return false;
- }
-
- bool ok = eglMakeCurrent(dpy, surf, surf, ctx);
- if (!ok) {
- EGLint err = eglGetError();
- qWarning() << "QEglContext::makeCurrent():" << errorString(err);
- }
- return ok;
-}
-
-bool QEglContext::doneCurrent()
-{
- // If the context is invalid, we assume that an error was reported
- // when makeCurrent() was called.
- if (ctx == EGL_NO_CONTEXT)
- return false;
-
- // We need to select the correct API before calling eglMakeCurrent()
- // with EGL_NO_CONTEXT because threads can have both OpenGL and OpenVG
- // contexts active at the same time.
-#ifdef EGL_OPENGL_ES_API
- if (apiType == OpenGL)
- eglBindAPI(EGL_OPENGL_ES_API);
-#endif
-#ifdef EGL_OPENVG_API
- if (apiType == OpenVG)
- eglBindAPI(EGL_OPENVG_API);
-#endif
-
- bool ok = eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- if (!ok) {
- EGLint err = eglGetError();
- qWarning() << "QEglContext::doneCurrent():" << errorString(err);
- }
- return ok;
-}
-
-bool QEglContext::swapBuffers()
-{
- if(ctx == EGL_NO_CONTEXT)
- return false;
-
- bool ok = eglSwapBuffers(dpy, surf);
- if (!ok) {
- EGLint err = eglGetError();
- qWarning() << "QEglContext::swapBuffers():" << errorString(err);
- }
- return ok;
-}
-
-// Wait for native rendering operations to complete before starting
-// to use OpenGL/OpenVG operations.
-void QEglContext::waitNative()
-{
-#ifdef EGL_CORE_NATIVE_ENGINE
- eglWaitNative(EGL_CORE_NATIVE_ENGINE);
-#endif
-}
-
-// Wait for client OpenGL/OpenVG operations to complete before
-// using native rendering operations.
-void QEglContext::waitClient()
-{
-#ifdef EGL_OPENGL_ES_API
- if (apiType == OpenGL) {
- eglBindAPI(EGL_OPENGL_ES_API);
- eglWaitClient();
- }
-#else
- if (apiType == OpenGL)
- eglWaitGL();
-#endif
-#ifdef EGL_OPENVG_API
- if (apiType == OpenVG) {
- eglBindAPI(EGL_OPENVG_API);
- eglWaitClient();
- }
-#endif
-}
-
-// Query the actual size of the EGL surface.
-QSize QEglContext::surfaceSize() const
-{
- int w, h;
- eglQuerySurface(dpy, surf, EGL_WIDTH, &w);
- eglQuerySurface(dpy, surf, EGL_HEIGHT, &h);
- return QSize(w, h);
-}
-
-// Query the value of a configuration attribute.
-bool QEglContext::configAttrib(int name, EGLint *value) const
-{
- return eglGetConfigAttrib(dpy, cfg, name, value);
-}
-
-// Retrieve all of the properties on "cfg". If zero, return
-// the context's configuration.
-QEglProperties QEglContext::configProperties(EGLConfig cfg) const
-{
- if (!cfg)
- cfg = config();
- QEglProperties props;
- for (int name = 0x3020; name <= 0x304F; ++name) {
- EGLint value;
- if (name != EGL_NONE && eglGetConfigAttrib(dpy, cfg, name, &value))
- props.setValue(name, value);
- }
- eglGetError(); // Clear the error state.
- return props;
-}
-
-// Initialize and return the default display.
-EGLDisplay QEglContext::defaultDisplay(QPaintDevice *device)
-{
- static EGLDisplay dpy = EGL_NO_DISPLAY;
- if (dpy == EGL_NO_DISPLAY) {
- dpy = getDisplay(device);
- if (dpy == EGL_NO_DISPLAY) {
- qWarning() << "QEglContext::defaultDisplay(): Cannot open EGL display";
- return EGL_NO_DISPLAY;
- }
- if (!eglInitialize(dpy, NULL, NULL)) {
- EGLint err = eglGetError();
- qWarning() << "QEglContext::defaultDisplay(): Cannot initialize EGL display:" << errorString(err);
- return EGL_NO_DISPLAY;
- }
-#ifdef EGL_OPENGL_ES_API
- eglBindAPI(EGL_OPENGL_ES_API);
-#endif
- }
- return dpy;
-}
-
-// Return the error string associated with a specific code.
-QString QEglContext::errorString(int code)
-{
- static const char * const errors[] = {
- "Success (0x3000)", // No tr
- "Not initialized (0x3001)", // No tr
- "Bad access (0x3002)", // No tr
- "Bad alloc (0x3003)", // No tr
- "Bad attribute (0x3004)", // No tr
- "Bad config (0x3005)", // No tr
- "Bad context (0x3006)", // No tr
- "Bad current surface (0x3007)", // No tr
- "Bad display (0x3008)", // No tr
- "Bad match (0x3009)", // No tr
- "Bad native pixmap (0x300A)", // No tr
- "Bad native window (0x300B)", // No tr
- "Bad parameter (0x300C)", // No tr
- "Bad surface (0x300D)", // No tr
- "Context lost (0x300E)" // No tr
- };
- if (code >= 0x3000 && code <= 0x300E) {
- return QString::fromLatin1(errors[code - 0x3000]);
- } else {
- return QLatin1String("0x") + QString::number(code, 16);
- }
-}
-
-// Dump all of the EGL configurations supported by the system.
-void QEglContext::dumpAllConfigs()
-{
- QEglProperties props;
- EGLint count = 0;
- if (!eglGetConfigs(dpy, 0, 0, &count))
- return;
- if (count < 1)
- return;
- EGLConfig *configs = new EGLConfig [count];
- eglGetConfigs(dpy, configs, count, &count);
- for (EGLint index = 0; index < count; ++index) {
- props = configProperties(configs[index]);
- qWarning() << props.toString();
- }
- delete [] configs;
-}
-
-// Initialize a property block.
-QEglProperties::QEglProperties()
-{
- props.append(EGL_NONE);
-}
-
-// Fetch the current value associated with a property.
-int QEglProperties::value(int name) const
-{
- for (int index = 0; index < (props.size() - 1); index += 2) {
- if (props[index] == name)
- return props[index + 1];
- }
- return EGL_DONT_CARE;
-}
-
-// Set the value associated with a property, replacing an existing
-// value if there is one.
-void QEglProperties::setValue(int name, int value)
-{
- for (int index = 0; index < (props.size() - 1); index += 2) {
- if (props[index] == name) {
- props[index + 1] = value;
- return;
- }
- }
- props[props.size() - 1] = name;
- props.append(value);
- props.append(EGL_NONE);
-}
-
-// Remove a property value. Returns false if the property is not present.
-bool QEglProperties::removeValue(int name)
-{
- for (int index = 0; index < (props.size() - 1); index += 2) {
- if (props[index] == name) {
- while ((index + 2) < props.size()) {
- props[index] = props[index + 2];
- ++index;
- }
- props.resize(props.size() - 2);
- return true;
- }
- }
- return false;
-}
-
-// Sets the red, green, blue, and alpha sizes based on a pixel format.
-// Normally used to match a configuration request to the screen format.
-void QEglProperties::setPixelFormat(QImage::Format pixelFormat)
-{
- int red, green, blue, alpha;
- switch (pixelFormat) {
- case QImage::Format_RGB32:
- case QImage::Format_RGB888:
- red = green = blue = 8; alpha = 0; break;
- case QImage::Format_ARGB32:
- case QImage::Format_ARGB32_Premultiplied:
- red = green = blue = alpha = 8; break;
- case QImage::Format_RGB16:
- red = 5; green = 6; blue = 5; alpha = 0; break;
- case QImage::Format_ARGB8565_Premultiplied:
- red = 5; green = 6; blue = 5; alpha = 8; break;
- case QImage::Format_RGB666:
- red = green = blue = 6; alpha = 0; break;
- case QImage::Format_ARGB6666_Premultiplied:
- red = green = blue = alpha = 6; break;
- case QImage::Format_RGB555:
- red = green = blue = 5; alpha = 0; break;
- case QImage::Format_ARGB8555_Premultiplied:
- red = green = blue = 5; alpha = 8; break;
- case QImage::Format_RGB444:
- red = green = blue = 4; alpha = 0; break;
- case QImage::Format_ARGB4444_Premultiplied:
- red = green = blue = alpha = 4; break;
- default:
- qWarning() << "QEglProperties::setPixelFormat(): Unsupported pixel format";
- red = green = blue = alpha = 1; break;
- }
- setValue(EGL_RED_SIZE, red);
- setValue(EGL_GREEN_SIZE, green);
- setValue(EGL_BLUE_SIZE, blue);
- setValue(EGL_ALPHA_SIZE, alpha);
-}
-
-void QEglProperties::setRenderableType(int api)
-{
-#if defined(EGL_RENDERABLE_TYPE)
-#if defined(QT_OPENGL_ES_2)
- if (api == QEglContext::OpenGL)
- setValue(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT);
-#elif defined(QT_OPENGL_ES)
- if (api == QEglContext::OpenGL)
- setValue(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT);
-#endif
-#if defined(EGL_OPENVG_BIT)
- if (api == QEglContext::OpenVG)
- setValue(EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT);
-#endif
-#else
- Q_UNUSED(api);
-#endif
-}
-
-// Reduce the complexity of a configuration request to ask for less
-// because the previous request did not result in success. Returns
-// true if the complexity was reduced, or false if no further
-// reductions in complexity are possible.
-bool QEglProperties::reduceConfiguration()
-{
- if (removeValue(EGL_SAMPLE_BUFFERS)) {
- removeValue(EGL_SAMPLES);
- return true;
- }
- if (removeValue(EGL_ALPHA_SIZE))
- return true;
- if (removeValue(EGL_STENCIL_SIZE))
- return true;
- if (removeValue(EGL_DEPTH_SIZE))
- return true;
- return false;
-}
-
-static void addTag(QString& str, const QString& tag)
-{
- int lastnl = str.lastIndexOf(QLatin1String("\n"));
- if (lastnl == -1)
- lastnl = 0;
- if ((str.length() - lastnl) >= 50)
- str += QLatin1String("\n ");
- str += tag;
-}
-
-// Convert a property list to a string suitable for debug output.
-QString QEglProperties::toString() const
-{
- QString str;
- int val;
-
- val = value(EGL_CONFIG_ID);
- if (val != EGL_DONT_CARE) {
- str += QLatin1String("id=");
- str += QString::number(val);
- str += QLatin1String(" ");
- }
-
-#ifdef EGL_RENDERABLE_TYPE
- val = value(EGL_RENDERABLE_TYPE);
- if (val != EGL_DONT_CARE) {
- str += QLatin1String("type=");
- QStringList types;
- if ((val & EGL_OPENGL_ES_BIT) != 0)
- types += QLatin1String("es1");
-#ifdef EGL_OPENGL_ES2_BIT
- if ((val & EGL_OPENGL_ES2_BIT) != 0)
- types += QLatin1String("es2");
-#endif
- if ((val & EGL_OPENVG_BIT) != 0)
- types += QLatin1String("vg");
- if ((val & ~7) != 0)
- types += QString::number(val);
- str += types.join(QLatin1String(","));
- } else {
- str += QLatin1String("type=any");
- }
-#else
- str += QLatin1String("type=es1");
-#endif
-
- int red = value(EGL_RED_SIZE);
- int green = value(EGL_GREEN_SIZE);
- int blue = value(EGL_BLUE_SIZE);
- int alpha = value(EGL_ALPHA_SIZE);
- int bufferSize = value(EGL_BUFFER_SIZE);
- if (bufferSize == (red + green + blue + alpha))
- bufferSize = EGL_DONT_CARE;
- str += QLatin1String(" rgba=");
- str += QString::number(red);
- str += QLatin1String(",");
- str += QString::number(green);
- str += QLatin1String(",");
- str += QString::number(blue);
- str += QLatin1String(",");
- str += QString::number(alpha);
- if (bufferSize != EGL_DONT_CARE) {
- // Only report buffer size if different than r+g+b+a.
- str += QLatin1String(" buffer-size=");
- str += QString::number(bufferSize);
- }
-
-#ifdef EGL_COLOR_BUFFER_TYPE
- val = value(EGL_COLOR_BUFFER_TYPE);
- if (val == EGL_LUMINANCE_BUFFER) {
- addTag(str, QLatin1String(" color-buffer-type=luminance"));
- } else if (val != EGL_DONT_CARE && val != EGL_RGB_BUFFER) {
- addTag(str, QLatin1String(" color-buffer-type="));
- str += QString::number(val, 16);
- }
-#endif
-
- val = value(EGL_DEPTH_SIZE);
- if (val != EGL_DONT_CARE) {
- addTag(str, QLatin1String(" depth="));
- str += QString::number(val);
- }
-
- val = value(EGL_STENCIL_SIZE);
- if (val != EGL_DONT_CARE) {
- addTag(str, QLatin1String(" stencil="));
- str += QString::number(val);
- }
-
- val = value(EGL_SURFACE_TYPE);
- if (val != EGL_DONT_CARE) {
- addTag(str, QLatin1String(" surface-type="));
- QStringList types;
- if ((val & EGL_WINDOW_BIT) != 0)
- types += QLatin1String("window");
- if ((val & EGL_PIXMAP_BIT) != 0)
- types += QLatin1String("pixmap");
- if ((val & EGL_PBUFFER_BIT) != 0)
- types += QLatin1String("pbuffer");
-#ifdef EGL_VG_COLORSPACE_LINEAR_BIT
- if ((val & EGL_VG_COLORSPACE_LINEAR_BIT) != 0)
- types += QLatin1String("vg-colorspace-linear");
-#endif
-#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT
- if ((val & EGL_VG_ALPHA_FORMAT_PRE_BIT) != 0)
- types += QLatin1String("vg-alpha-format-pre");
-#endif
- if ((val & ~(EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT
-#ifdef EGL_VG_COLORSPACE_LINEAR_BIT
- | EGL_VG_COLORSPACE_LINEAR_BIT
-#endif
-#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT
- | EGL_VG_ALPHA_FORMAT_PRE_BIT
-#endif
- )) != 0) {
- types += QString::number(val);
- }
- str += types.join(QLatin1String(","));
- }
-
- val = value(EGL_CONFIG_CAVEAT);
- if (val != EGL_DONT_CARE) {
- addTag(str, QLatin1String(" caveat="));
- if (val == EGL_NONE)
- str += QLatin1String("none");
- else if (val == EGL_SLOW_CONFIG)
- str += QLatin1String("slow");
- else if (val == EGL_NON_CONFORMANT_CONFIG)
- str += QLatin1String("non-conformant");
- else
- str += QString::number(val, 16);
- }
-
- val = value(EGL_LEVEL);
- if (val != EGL_DONT_CARE) {
- addTag(str, QLatin1String(" level="));
- str += QString::number(val);
- }
-
- int width, height, pixels;
- width = value(EGL_MAX_PBUFFER_WIDTH);
- height = value(EGL_MAX_PBUFFER_HEIGHT);
- pixels = value(EGL_MAX_PBUFFER_PIXELS);
- if (height != EGL_DONT_CARE || width != EGL_DONT_CARE) {
- addTag(str, QLatin1String(" max-pbuffer-size="));
- str += QString::number(width);
- str += QLatin1String("x");
- str += QString::number(height);
- if (pixels != (width * height)) {
- addTag(str, QLatin1String(" max-pbuffer-pixels="));
- str += QString::number(pixels);
- }
- }
-
- val = value(EGL_NATIVE_RENDERABLE);
- if (val != EGL_DONT_CARE) {
- if (val)
- addTag(str, QLatin1String(" native-renderable=true"));
- else
- addTag(str, QLatin1String(" native-renderable=false"));
- }
-
- val = value(EGL_NATIVE_VISUAL_ID);
- if (val != EGL_DONT_CARE) {
- addTag(str, QLatin1String(" visual-id="));
- str += QString::number(val);
- }
-
- val = value(EGL_NATIVE_VISUAL_TYPE);
- if (val != EGL_DONT_CARE) {
- addTag(str, QLatin1String(" visual-type="));
- str += QString::number(val);
- }
-
-#ifdef EGL_PRESERVED_RESOURCES
- val = value(EGL_PRESERVED_RESOURCES);
- if (val != EGL_DONT_CARE) {
- if (val)
- addTag(str, QLatin1String(" preserved-resources=true"));
- else
- addTag(str, QLatin1String(" preserved-resources=false"));
- }
-#endif
-
- val = value(EGL_SAMPLES);
- if (val != EGL_DONT_CARE) {
- addTag(str, QLatin1String(" samples="));
- str += QString::number(val);
- }
-
- val = value(EGL_SAMPLE_BUFFERS);
- if (val != EGL_DONT_CARE) {
- addTag(str, QLatin1String(" sample-buffers="));
- str += QString::number(val);
- }
-
- val = value(EGL_TRANSPARENT_TYPE);
- if (val == EGL_TRANSPARENT_RGB) {
- addTag(str, QLatin1String(" transparent-rgb="));
- str += QString::number(value(EGL_TRANSPARENT_RED_VALUE));
- str += QLatin1String(",");
- str += QString::number(value(EGL_TRANSPARENT_GREEN_VALUE));
- str += QLatin1String(",");
- str += QString::number(value(EGL_TRANSPARENT_BLUE_VALUE));
- }
-
-#if defined(EGL_BIND_TO_TEXTURE_RGB) && defined(EGL_BIND_TO_TEXTURE_RGBA)
- val = value(EGL_BIND_TO_TEXTURE_RGB);
- int val2 = value(EGL_BIND_TO_TEXTURE_RGBA);
- if (val != EGL_DONT_CARE || val2 != EGL_DONT_CARE) {
- addTag(str, QLatin1String(" bind-texture="));
- if (val == EGL_TRUE)
- str += QLatin1String("rgb");
- else
- str += QLatin1String("no-rgb");
- if (val2 == EGL_TRUE)
- str += QLatin1String(",rgba");
- else
- str += QLatin1String(",no-rgba");
- }
-#endif
-
-#ifdef EGL_MIN_SWAP_INTERVAL
- val = value(EGL_MIN_SWAP_INTERVAL);
- if (val != EGL_DONT_CARE) {
- addTag(str, QLatin1String(" min-swap-interval="));
- str += QString::number(val);
- }
-#endif
-
-#ifdef EGL_MIN_SWAP_INTERVAL
- val = value(EGL_MAX_SWAP_INTERVAL);
- if (val != EGL_DONT_CARE) {
- addTag(str, QLatin1String(" max-swap-interval="));
- str += QString::number(val);
- }
-#endif
-
-#ifdef EGL_LUMINANCE_SIZE
- val = value(EGL_LUMINANCE_SIZE);
- if (val != EGL_DONT_CARE) {
- addTag(str, QLatin1String(" luminance="));
- str += QString::number(val);
- }
-#endif
-
-#ifdef EGL_ALPHA_MASK_SIZE
- val = value(EGL_ALPHA_MASK_SIZE);
- if (val != EGL_DONT_CARE) {
- addTag(str, QLatin1String(" alpha-mask="));
- str += QString::number(val);
- }
-#endif
-
-#ifdef EGL_CONFORMANT
- val = value(EGL_CONFORMANT);
- if (val != EGL_DONT_CARE) {
- if (val)
- addTag(str, QLatin1String(" conformant=true"));
- else
- addTag(str, QLatin1String(" conformant=false"));
- }
-#endif
-
- return str;
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_OPENGL_ES || QT_OPENVG
diff --git a/src/opengl/qegl_p.h b/src/opengl/qegl_p.h
deleted file mode 100644
index a57e522..0000000
--- a/src/opengl/qegl_p.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
-** this package.
-**
-** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QEGL_P_H
-#define QEGL_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of the QGLWidget class. This header file may change from
-// version to version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "QtCore/qvarlengtharray.h"
-#include "QtCore/qsize.h"
-#include "QtGui/qimage.h"
-
-#if defined(QT_OPENGL_ES) || defined(QT_OPENVG)
-
-QT_BEGIN_INCLUDE_NAMESPACE
-#if defined(QT_OPENGL_ES_2) || defined(QT_OPENVG)
-#include <EGL/egl.h>
-#else
-#include <GLES/egl.h>
-#endif
-#if !defined(EGL_VERSION_1_3) && !defined(QEGL_NATIVE_TYPES_DEFINED)
-#undef EGLNativeWindowType
-#undef EGLNativePixmapType
-#undef EGLNativeDisplayType
-typedef NativeWindowType EGLNativeWindowType;
-typedef NativePixmapType EGLNativePixmapType;
-typedef NativeDisplayType EGLNativeDisplayType;
-#define QEGL_NATIVE_TYPES_DEFINED 1
-#endif
-QT_END_INCLUDE_NAMESPACE
-
-class QX11Info;
-class QPaintDevice;
-class QImage;
-class QPixmap;
-class QWidget;
-
-QT_BEGIN_NAMESPACE
-
-class Q_OPENGL_EXPORT QEglProperties
-{
-public:
- QEglProperties();
- QEglProperties(const QEglProperties& other) : props(other.props) {}
- ~QEglProperties() {}
-
- int value(int name) const;
- void setValue(int name, int value);
- bool removeValue(int name);
-
- const int *properties() const { return props.constData(); }
-
- void setPixelFormat(QImage::Format pixelFormat);
-#ifdef Q_WS_X11
- void setVisualFormat(const QX11Info *xinfo);
-#endif
- void setRenderableType(int api);
-
- bool reduceConfiguration();
-
- QString toString() const;
-
-private:
- QVarLengthArray<int> props;
-};
-
-class Q_OPENGL_EXPORT QEglContext
-{
-public:
- QEglContext();
- ~QEglContext();
-
- enum API
- {
- OpenGL,
- OpenVG
- };
-
- enum PixelFormatMatch
- {
- ExactPixelFormat,
- BestPixelFormat
- };
-
- bool isValid() const;
- bool isSharing() const;
-
- void setApi(QEglContext::API api) { apiType = api; }
- bool openDisplay(QPaintDevice *device);
- bool chooseConfig(const QEglProperties& properties, PixelFormatMatch match = ExactPixelFormat);
- bool createContext(QEglContext *shareContext = 0);
- bool createSurface(QPaintDevice *device);
- bool recreateSurface(QPaintDevice *device);
- void setSurface(EGLSurface surface) { surf = surface; }
-
- void destroy();
-
- bool makeCurrent();
- bool doneCurrent();
- bool swapBuffers();
-
- void waitNative();
- void waitClient();
-
- QSize surfaceSize() const;
-
- bool configAttrib(int name, EGLint *value) const;
-
- void clearError() const { eglGetError(); }
-
- QEglContext::API api() const { return apiType; }
-
- EGLDisplay display() const { return dpy; }
- EGLContext context() const { return ctx; }
- EGLSurface surface() const { return surf; }
- EGLConfig config() const { return cfg; }
-
- QEglProperties configProperties(EGLConfig cfg = 0) const;
-
- static EGLDisplay defaultDisplay(QPaintDevice *device);
- static QString errorString(int code);
-
- void dumpAllConfigs();
-
-private:
- QEglContext::API apiType;
- EGLDisplay dpy;
- EGLContext ctx;
- EGLSurface surf;
- EGLConfig cfg;
- bool share;
- void *reserved; // For extension data in future versions.
-
- static EGLDisplay getDisplay(QPaintDevice *device);
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_OPENGL_ES || QT_OPENVG
-
-#endif // QEGL_P_H
diff --git a/src/opengl/qegl_qws.cpp b/src/opengl/qegl_qws.cpp
deleted file mode 100644
index f0433bb..0000000
--- a/src/opengl/qegl_qws.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
-** this package.
-**
-** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtGui/qpaintdevice.h>
-#include <QtGui/qpixmap.h>
-#include <QtGui/qwidget.h>
-#include "qegl_p.h"
-
-#if defined(QT_OPENGL_ES) || defined(QT_OPENVG)
-
-#include <qglscreen_qws.h>
-#include <qscreenproxy_qws.h>
-#include <private/qglwindowsurface_qws_p.h>
-#include <qapplication.h>
-#include <qdesktopwidget.h>
-
-QT_BEGIN_NAMESPACE
-
-static QGLScreen *glScreenForDevice(QPaintDevice *device)
-{
- QScreen *screen = qt_screen;
- if (screen->classId() == QScreen::MultiClass) {
- int screenNumber;
- if (device && device->devType() == QInternal::Widget)
- screenNumber = qApp->desktop()->screenNumber(static_cast<QWidget *>(device));
- else
- screenNumber = 0;
- screen = screen->subScreens()[screenNumber];
- }
- while (screen->classId() == QScreen::ProxyClass ||
- screen->classId() == QScreen::TransformedClass) {
- screen = static_cast<QProxyScreen *>(screen)->screen();
- }
- if (screen->classId() == QScreen::GLClass)
- return static_cast<QGLScreen *>(screen);
- else
- return 0;
-}
-
-// Create the surface for a QPixmap, QImage, or QWidget.
-bool QEglContext::createSurface(QPaintDevice *device)
-{
- // Get the screen surface functions, which are used to create native ids.
- QGLScreen *glScreen = glScreenForDevice(device);
- if (!glScreen)
- return false;
- QGLScreenSurfaceFunctions *funcs = glScreen->surfaceFunctions();
- if (!funcs)
- return false;
-
- // Create the native drawable for the paint device.
- int devType = device->devType();
- EGLNativePixmapType pixmapDrawable = 0;
- EGLNativeWindowType windowDrawable = 0;
- bool ok;
- if (devType == QInternal::Pixmap) {
- ok = funcs->createNativePixmap(static_cast<QPixmap *>(device), &pixmapDrawable);
- } else if (devType == QInternal::Image) {
- ok = funcs->createNativeImage(static_cast<QImage *>(device), &pixmapDrawable);
- } else {
- ok = funcs->createNativeWindow(static_cast<QWidget *>(device), &windowDrawable);
- }
- if (!ok) {
- qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable");
- return false;
- }
-
- // Create the EGL surface to draw into, based on the native drawable.
- if (devType == QInternal::Widget)
- surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, 0);
- else
- surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, 0);
- if (surf == EGL_NO_SURFACE) {
- qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError());
- return false;
- }
- return true;
-}
-
-EGLDisplay QEglContext::getDisplay(QPaintDevice *device)
-{
- Q_UNUSED(device);
- return eglGetDisplay(EGLNativeDisplayType(EGL_DEFAULT_DISPLAY));
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_OPENGL_ES || QT_OPENVG
diff --git a/src/opengl/qegl_wince.cpp b/src/opengl/qegl_wince.cpp
deleted file mode 100644
index ea65793..0000000
--- a/src/opengl/qegl_wince.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
-** this package.
-**
-** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtGui/qpaintdevice.h>
-#include <QtGui/qpixmap.h>
-#include <QtGui/qwidget.h>
-#include "qegl_p.h"
-
-#if defined(QT_OPENGL_ES) || defined(QT_OPENVG)
-
-#include <windows.h>
-
-
-QT_BEGIN_NAMESPACE
-
-bool QEglContext::createSurface(QPaintDevice *device)
-{
- // Create the native drawable for the paint device.
- int devType = device->devType();
- EGLNativePixmapType pixmapDrawable = 0;
- EGLNativeWindowType windowDrawable = 0;
- bool ok;
- if (devType == QInternal::Pixmap) {
- pixmapDrawable = 0;
- ok = (pixmapDrawable != 0);
- } else if (devType == QInternal::Widget) {
- windowDrawable = (EGLNativeWindowType)(static_cast<QWidget *>(device))->winId();
- ok = (windowDrawable != 0);
- } else {
- ok = false;
- }
- if (!ok) {
- qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable");
- return false;
- }
-
- // Create the EGL surface to draw into, based on the native drawable.
- if (devType == QInternal::Widget)
- surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, 0);
- else
- surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, 0);
- if (surf == EGL_NO_SURFACE) {
- qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError());
- return false;
- }
- return true;
-}
-
-EGLDisplay QEglContext::getDisplay(QPaintDevice *device)
-{
- EGLDisplay dpy = 0;
- HWND win = ((QWidget*)device)->winId();
- HDC myDc = GetDC(win);
- if (!myDc) {
- qWarning("QEglContext::defaultDisplay(): WinCE display is not open");
- }
- dpy = eglGetDisplay(EGLNativeDisplayType(myDc));
- if (dpy == EGL_NO_DISPLAY) {
- qWarning("QEglContext::defaultDisplay(): Falling back to EGL_DEFAULT_DISPLAY");
- dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- }
- return dpy;
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_OPENGL_ES || QT_OPENVG
diff --git a/src/opengl/qegl_x11egl.cpp b/src/opengl/qegl_x11egl.cpp
deleted file mode 100644
index 71e1928..0000000
--- a/src/opengl/qegl_x11egl.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
-** this package.
-**
-** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtGui/qpaintdevice.h>
-#include <QtGui/qpixmap.h>
-#include <QtGui/qwidget.h>
-#include "qegl_p.h"
-
-#if defined(QT_OPENGL_ES) || defined(QT_OPENVG)
-
-#if defined(Q_WS_X11)
-#include <QtGui/qx11info_x11.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-bool QEglContext::createSurface(QPaintDevice *device)
-{
- // Create the native drawable for the paint device.
- int devType = device->devType();
- EGLNativePixmapType pixmapDrawable = 0;
- EGLNativeWindowType windowDrawable = 0;
- bool ok;
- if (devType == QInternal::Pixmap) {
- pixmapDrawable = (EGLNativePixmapType)(static_cast<QPixmap *>(device))->handle();
- ok = (pixmapDrawable != 0);
- } else if (devType == QInternal::Widget) {
- windowDrawable = (EGLNativeWindowType)(static_cast<QWidget *>(device))->winId();
- ok = (windowDrawable != 0);
- } else {
- ok = false;
- }
- if (!ok) {
- qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable");
- return false;
- }
-
- // Create the EGL surface to draw into, based on the native drawable.
- if (devType == QInternal::Widget)
- surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, 0);
- else
- surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, 0);
- if (surf == EGL_NO_SURFACE) {
- qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError());
- return false;
- }
- return true;
-}
-
-EGLDisplay QEglContext::getDisplay(QPaintDevice *device)
-{
- Q_UNUSED(device);
- Display *xdpy = QX11Info::display();
- if (!xdpy) {
- qWarning("QEglContext::getDisplay(): X11 display is not open");
- return EGL_NO_DISPLAY;
- }
- return eglGetDisplay(EGLNativeDisplayType(xdpy));
-}
-
-static int countBits(unsigned long mask)
-{
- int count = 0;
- while (mask != 0) {
- if (mask & 1)
- ++count;
- mask >>= 1;
- }
- return count;
-}
-
-// Set the pixel format parameters from the visual in "xinfo".
-void QEglProperties::setVisualFormat(const QX11Info *xinfo)
-{
- if (!xinfo)
- return;
- Visual *visual = (Visual*)xinfo->visual();
- if (!visual)
- return;
- if (visual->c_class != TrueColor && visual->c_class != DirectColor)
- return;
- setValue(EGL_RED_SIZE, countBits(visual->red_mask));
- setValue(EGL_GREEN_SIZE, countBits(visual->green_mask));
- setValue(EGL_BLUE_SIZE, countBits(visual->blue_mask));
- setValue(EGL_ALPHA_SIZE, 0); // XXX
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_OPENGL_ES || QT_OPENVG
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index b011637..466e851 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -59,23 +59,36 @@
# include <private/qt_mac_p.h>
#endif
+#include <qdatetime.h>
+
#include <stdlib.h> // malloc
#include "qpixmap.h"
#include "qimage.h"
#include "qgl_p.h"
-#if defined(QT_OPENGL_ES_2)
+#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
#include "gl2paintengineex/qpaintengineex_opengl2_p.h"
-#else
+#endif
+
+#ifndef QT_OPENGL_ES_2
#include <private/qpaintengine_opengl_p.h>
#endif
+#ifdef Q_WS_QWS
+#include <private/qglwindowsurface_qws_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 <private/qimagepixmapcleanuphooks_p.h>
#include "qcolormap.h"
-#include "qcache.h"
#include "qfile.h"
#include "qlibrary.h"
@@ -91,7 +104,11 @@ QT_BEGIN_NAMESPACE
QGLExtensionFuncs QGLContextPrivate::qt_extensionFuncs;
#endif
-QThreadStorage<QGLThreadContext *> qgl_context_storage;
+struct QGLThreadContext {
+ QGLContext *context;
+};
+
+static QThreadStorage<QGLThreadContext *> qgl_context_storage;
Q_GLOBAL_STATIC(QGLFormat, qgl_default_format)
@@ -110,31 +127,88 @@ Q_GLOBAL_STATIC(QGLDefaultOverlayFormat, defaultOverlayFormatInstance)
QGLExtensions::Extensions QGLExtensions::glExtensions = 0;
bool QGLExtensions::nvidiaFboNeedsFinish = false;
-#ifndef APIENTRY
-# define APIENTRY
-#endif
-typedef void (APIENTRY *pfn_glCompressedTexImage2DARB) (GLenum, GLint, GLenum, GLsizei,
- GLsizei, GLint, GLsizei, const GLvoid *);
-static pfn_glCompressedTexImage2DARB qt_glCompressedTexImage2DARB = 0;
+Q_GLOBAL_STATIC(QGLSignalProxy, theSignalProxy)
+QGLSignalProxy *QGLSignalProxy::instance()
+{
+ return theSignalProxy();
+}
-#ifndef APIENTRY
-#define APIENTRY
+class QGLEngineSelector
+{
+public:
+ QGLEngineSelector() : engineType(QPaintEngine::MaxUser)
+ {
+ }
+
+ void setPreferredPaintEngine(QPaintEngine::Type type) {
+ if (type == QPaintEngine::OpenGL || type == QPaintEngine::OpenGL2)
+ engineType = type;
+ }
+
+ QPaintEngine::Type preferredPaintEngine() {
+#ifdef Q_WS_MAC
+ // The ATI X1600 driver for Mac OS X does not support return
+ // values from functions in GLSL. Since working around this in
+ // the GL2 engine would require a big, ugly rewrite, we're
+ // falling back to the GL 1 engine..
+ static bool mac_x1600_check_done = false;
+ if (!mac_x1600_check_done) {
+ QGLWidget *tmp = 0;
+ if (!QGLContext::currentContext()) {
+ tmp = new QGLWidget();
+ tmp->makeCurrent();
+ }
+ if (strstr((char *) glGetString(GL_RENDERER), "X1600"))
+ engineType = QPaintEngine::OpenGL;
+ if (tmp)
+ delete tmp;
+ mac_x1600_check_done = true;
+ }
#endif
+ if (engineType == QPaintEngine::MaxUser) {
+ // No user-set engine - use the defaults
+#if defined(QT_OPENGL_ES_2)
+ engineType = QPaintEngine::OpenGL2;
+#else
+ // We can't do this in the constructor for this object because it
+ // needs to be called *before* the QApplication constructor.
+ // Also check for the FragmentShader extension in conjunction with
+ // the 2.0 version flag, to cover the case where we export the display
+ // from an old GL 1.1 server to a GL 2.x client. In that case we can't
+ // use GL 2.0.
+ if ((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0)
+ && (QGLExtensions::glExtensions & QGLExtensions::FragmentShader)
+ && qgetenv("QT_GL_USE_OPENGL1ENGINE").isEmpty())
+ engineType = QPaintEngine::OpenGL2;
+ else
+ engineType = QPaintEngine::OpenGL;
+#endif
+ }
+ return engineType;
+ }
-Q_GLOBAL_STATIC(QGLSignalProxy, theSignalProxy)
-QGLSignalProxy *QGLSignalProxy::instance()
+private:
+ QPaintEngine::Type engineType;
+};
+
+Q_GLOBAL_STATIC(QGLEngineSelector, qgl_engine_selector)
+
+
+bool qt_gl_preferGL2Engine()
{
- return theSignalProxy();
+ return qgl_engine_selector()->preferredPaintEngine() == QPaintEngine::OpenGL2;
}
+
/*!
\namespace QGL
+ \inmodule QtOpenGL
\brief The QGL namespace specifies miscellaneous identifiers used
in the Qt OpenGL module.
- \ingroup multimedia
+ \ingroup painting-3D
*/
/*!
@@ -167,6 +241,32 @@ QGLSignalProxy *QGLSignalProxy::instance()
\sa {Sample Buffers Example}
*/
+/*!
+ \fn void QGL::setPreferredPaintEngine(QPaintEngine::Type engineType)
+
+ \since 4.6
+
+ Sets the preferred OpenGL paint engine that is used to draw onto
+ QGLWidget, QGLPixelBuffer and QGLFramebufferObject targets with QPainter
+ in Qt.
+
+ The \a engineType parameter specifies which of the GL engines to
+ use. Only \c QPaintEngine::OpenGL and \c QPaintEngine::OpenGL2 are
+ valid parameters to this function. All other values are ignored.
+
+ By default, the \c QPaintEngine::OpenGL2 engine is used if GL/GLES
+ version 2.0 is available, otherwise \c QPaintEngine::OpenGL is
+ used.
+
+ \warning This function must be called before the QApplication
+ constructor is called.
+*/
+void QGL::setPreferredPaintEngine(QPaintEngine::Type engineType)
+{
+ qgl_engine_selector()->setPreferredPaintEngine(engineType);
+}
+
+
/*****************************************************************************
QGLFormat implementation
*****************************************************************************/
@@ -177,7 +277,7 @@ QGLSignalProxy *QGLSignalProxy::instance()
\brief The QGLFormat class specifies the display format of an OpenGL
rendering context.
- \ingroup multimedia
+ \ingroup painting-3D
A display format has several characteristics:
\list
@@ -190,13 +290,14 @@ QGLSignalProxy *QGLSignalProxy::instance()
\i \link setStereo() Stereo buffers.\endlink
\i \link setDirectRendering() Direct rendering.\endlink
\i \link setOverlay() Presence of an overlay.\endlink
- \i \link setPlane() The plane of an overlay format.\endlink
+ \i \link setPlane() Plane of an overlay.\endlink
\i \link setSampleBuffers() Multisample buffers.\endlink
\endlist
- You can also specify preferred bit depths for the depth buffer,
- alpha buffer, accumulation buffer and the stencil buffer with the
- functions: setDepthBufferSize(), setAlphaBufferSize(),
+ You can also specify preferred bit depths for the color buffer,
+ depth buffer, alpha buffer, accumulation buffer and the stencil
+ buffer with the functions: setRedBufferSize(), setGreenBufferSize(),
+ setBlueBufferSize(), setDepthBufferSize(), setAlphaBufferSize(),
setAccumBufferSize() and setStencilBufferSize().
Note that even if you specify that you prefer a 32 bit depth
@@ -237,6 +338,8 @@ QGLSignalProxy *QGLSignalProxy::instance()
\sa QGLContext, QGLWidget
*/
+#ifndef QT_OPENGL_ES
+
static inline void transform_point(GLdouble out[4], const GLdouble m[16], const GLdouble in[4])
{
#define M(row,col) m[col*4+row]
@@ -279,15 +382,17 @@ static inline GLint qgluProject(GLdouble objx, GLdouble objy, GLdouble objz,
return GL_TRUE;
}
+#endif // !QT_OPENGL_ES
+
/*!
- Constructs a QGLFormat object with the factory default settings:
+ Constructs a QGLFormat object with the following default settings:
\list
\i \link setDoubleBuffer() Double buffer:\endlink Enabled.
\i \link setDepth() Depth buffer:\endlink Enabled.
\i \link setRgba() RGBA:\endlink Enabled (i.e., color index disabled).
\i \link setAlpha() Alpha channel:\endlink Disabled.
\i \link setAccum() Accumulator buffer:\endlink Disabled.
- \i \link setStencil() Stencil buffer:\endlink Disabled.
+ \i \link setStencil() Stencil buffer:\endlink Enabled.
\i \link setStereo() Stereo:\endlink Disabled.
\i \link setDirectRendering() Direct rendering:\endlink Enabled.
\i \link setOverlay() Overlay:\endlink Disabled.
@@ -303,26 +408,26 @@ QGLFormat::QGLFormat()
/*!
- Creates a QGLFormat object that is a copy of the current \link
- defaultFormat() application default format\endlink.
+ Creates a QGLFormat object that is a copy of the current
+ defaultFormat().
- If \a options is not 0, this copy is modified by these format
- options. The \a options parameter should be \c FormatOption values
- OR'ed together.
+ If \a options is not 0, the default format is modified by the
+ specified format options. The \a options parameter should be
+ QGL::FormatOption values OR'ed together.
This constructor makes it easy to specify a certain desired format
in classes derived from QGLWidget, for example:
\snippet doc/src/snippets/code/src_opengl_qgl.cpp 3
- Note that there are \c FormatOption values to turn format settings
- both on and off, e.g. \c DepthBuffer and \c NoDepthBuffer,
- \c DirectRendering and \c IndirectRendering, etc.
+ Note that there are QGL::FormatOption values to turn format settings
+ both on and off, e.g. QGL::DepthBuffer and QGL::NoDepthBuffer,
+ QGL::DirectRendering and QGL::IndirectRendering, etc.
The \a plane parameter defaults to 0 and is the plane which this
format should be associated with. Not all OpenGL implementations
supports overlay/underlay rendering planes.
- \sa defaultFormat(), setOption()
+ \sa defaultFormat(), setOption(), setPlane()
*/
QGLFormat::QGLFormat(QGL::FormatOptions options, int plane)
@@ -336,13 +441,26 @@ QGLFormat::QGLFormat(QGL::FormatOptions options, int plane)
}
/*!
+ \internal
+*/
+void QGLFormat::detach()
+{
+ if (d->ref != 1) {
+ QGLFormatPrivate *newd = new QGLFormatPrivate(d);
+ if (!d->ref.deref())
+ delete d;
+ d = newd;
+ }
+}
+
+/*!
Constructs a copy of \a other.
*/
QGLFormat::QGLFormat(const QGLFormat &other)
{
- d = new QGLFormatPrivate;
- *d = *other.d;
+ d = other.d;
+ d->ref.ref();
}
/*!
@@ -351,7 +469,12 @@ QGLFormat::QGLFormat(const QGLFormat &other)
QGLFormat &QGLFormat::operator=(const QGLFormat &other)
{
- *d = *other.d;
+ if (d != other.d) {
+ other.d->ref.ref();
+ if (!d->ref.deref())
+ delete d;
+ d = other.d;
+ }
return *this;
}
@@ -360,7 +483,8 @@ QGLFormat &QGLFormat::operator=(const QGLFormat &other)
*/
QGLFormat::~QGLFormat()
{
- delete d;
+ if (!d->ref.deref())
+ delete d;
}
/*!
@@ -514,7 +638,7 @@ void QGLFormat::setAccum(bool enable)
\fn bool QGLFormat::stencil() const
Returns true if the stencil buffer is enabled; otherwise returns
- false. The stencil buffer is disabled by default.
+ false. The stencil buffer is enabled by default.
\sa setStencil(), setStencilBufferSize()
*/
@@ -523,7 +647,7 @@ void QGLFormat::setAccum(bool enable)
If \a enable is true enables the stencil buffer; otherwise
disables the stencil buffer.
- The stencil buffer is disabled by default.
+ The stencil buffer is enabled by default.
The stencil buffer masks certain parts of the drawing area so that
masked parts are not drawn on.
@@ -636,6 +760,7 @@ int QGLFormat::samples() const
*/
void QGLFormat::setSamples(int numSamples)
{
+ detach();
if (numSamples < 0) {
qWarning("QGLFormat::setSamples: Cannot have negative number of samples per pixel %d", numSamples);
return;
@@ -663,6 +788,7 @@ void QGLFormat::setSamples(int numSamples)
*/
void QGLFormat::setSwapInterval(int interval)
{
+ detach();
d->swapInterval = interval;
}
@@ -708,7 +834,7 @@ void QGLFormat::setOverlay(bool enable)
is 0, which means the normal plane. The default for overlay
formats is 1, which is the first overlay plane.
- \sa setPlane()
+ \sa setPlane(), defaultOverlayFormat()
*/
int QGLFormat::plane() const
{
@@ -730,6 +856,7 @@ int QGLFormat::plane() const
*/
void QGLFormat::setPlane(int plane)
{
+ detach();
d->pln = plane;
}
@@ -741,6 +868,7 @@ void QGLFormat::setPlane(int plane)
void QGLFormat::setOption(QGL::FormatOptions opt)
{
+ detach();
if (opt & 0xffff)
d->opts |= opt;
else
@@ -770,6 +898,7 @@ bool QGLFormat::testOption(QGL::FormatOptions opt) const
*/
void QGLFormat::setDepthBufferSize(int size)
{
+ detach();
if (size < 0) {
qWarning("QGLFormat::setDepthBufferSize: Cannot set negative depth buffer size %d", size);
return;
@@ -796,6 +925,7 @@ int QGLFormat::depthBufferSize() const
*/
void QGLFormat::setRedBufferSize(int size)
{
+ detach();
if (size < 0) {
qWarning("QGLFormat::setRedBufferSize: Cannot set negative red buffer size %d", size);
return;
@@ -824,6 +954,7 @@ int QGLFormat::redBufferSize() const
*/
void QGLFormat::setGreenBufferSize(int size)
{
+ detach();
if (size < 0) {
qWarning("QGLFormat::setGreenBufferSize: Cannot set negative green buffer size %d", size);
return;
@@ -852,6 +983,7 @@ int QGLFormat::greenBufferSize() const
*/
void QGLFormat::setBlueBufferSize(int size)
{
+ detach();
if (size < 0) {
qWarning("QGLFormat::setBlueBufferSize: Cannot set negative blue buffer size %d", size);
return;
@@ -879,6 +1011,7 @@ int QGLFormat::blueBufferSize() const
*/
void QGLFormat::setAlphaBufferSize(int size)
{
+ detach();
if (size < 0) {
qWarning("QGLFormat::setAlphaBufferSize: Cannot set negative alpha buffer size %d", size);
return;
@@ -905,6 +1038,7 @@ int QGLFormat::alphaBufferSize() const
*/
void QGLFormat::setAccumBufferSize(int size)
{
+ detach();
if (size < 0) {
qWarning("QGLFormat::setAccumBufferSize: Cannot set negative accumulate buffer size %d", size);
return;
@@ -929,6 +1063,7 @@ int QGLFormat::accumBufferSize() const
*/
void QGLFormat::setStencilBufferSize(int size)
{
+ detach();
if (size < 0) {
qWarning("QGLFormat::setStencilBufferSize: Cannot set negative stencil buffer size %d", size);
return;
@@ -1124,11 +1259,11 @@ QGLFormat::OpenGLVersionFlags QGLFormat::openGLVersionFlags()
if (cachedDefault) {
return defaultVersionFlags;
} else {
- cachedDefault = true;
if (!hasOpenGL())
return defaultVersionFlags;
dummy = new QGLWidget;
dummy->makeCurrent(); // glGetString() needs a current context
+ cachedDefault = true;
}
}
@@ -1148,8 +1283,8 @@ QGLFormat::OpenGLVersionFlags QGLFormat::openGLVersionFlags()
/*!
- Returns the default QGLFormat for the application. All QGLWidgets
- that are created use this format unless another format is
+ Returns the default QGLFormat for the application. All QGLWidget
+ objects that are created use this format unless another format is
specified, e.g. when they are constructed.
If no special default format has been set using
@@ -1182,7 +1317,7 @@ void QGLFormat::setDefaultFormat(const QGLFormat &f)
/*!
Returns the default QGLFormat for overlay contexts.
- The factory default overlay format is:
+ The default overlay format is:
\list
\i \link setDoubleBuffer() Double buffer:\endlink Disabled.
\i \link setDepth() Depth buffer:\endlink Disabled.
@@ -1193,6 +1328,7 @@ void QGLFormat::setDefaultFormat(const QGLFormat &f)
\i \link setStereo() Stereo:\endlink Disabled.
\i \link setDirectRendering() Direct rendering:\endlink Enabled.
\i \link setOverlay() Overlay:\endlink Disabled.
+ \i \link setSampleBuffers() Multisample buffers:\endlink Disabled.
\i \link setPlane() Plane:\endlink 1 (i.e., first overlay plane).
\endlist
@@ -1235,21 +1371,30 @@ void QGLFormat::setDefaultOverlayFormat(const QGLFormat &f)
/*!
- Returns true if all the options of the two QGLFormats are equal;
- otherwise returns false.
+ Returns true if all the options of the two QGLFormat objects
+ \a a and \a b are equal; otherwise returns false.
+
+ \relates QGLFormat
*/
bool operator==(const QGLFormat& a, const QGLFormat& b)
{
return (int) a.d->opts == (int) b.d->opts && a.d->pln == b.d->pln && a.d->alphaSize == b.d->alphaSize
&& a.d->accumSize == b.d->accumSize && a.d->stencilSize == b.d->stencilSize
- && a.d->depthSize == b.d->depthSize;
+ && a.d->depthSize == b.d->depthSize
+ && a.d->redSize == b.d->redSize
+ && a.d->greenSize == b.d->greenSize
+ && a.d->blueSize == b.d->blueSize
+ && a.d->numSamples == b.d->numSamples
+ && a.d->swapInterval == b.d->swapInterval;
}
/*!
- Returns false if all the options of the two QGLFormats are equal;
- otherwise returns true.
+ Returns false if all the options of the two QGLFormat objects
+ \a a and \a b are equal; otherwise returns true.
+
+ \relates QGLFormat
*/
bool operator!=(const QGLFormat& a, const QGLFormat& b)
@@ -1260,6 +1405,45 @@ bool operator!=(const QGLFormat& a, const QGLFormat& b)
/*****************************************************************************
QGLContext implementation
*****************************************************************************/
+
+QGLContextGroup::~QGLContextGroup()
+{
+ // Clear any remaining QGLSharedResourceGuard objects on the group.
+ QGLSharedResourceGuard *guard = m_guards;
+ while (guard != 0) {
+ guard->m_group = 0;
+ guard->m_id = 0;
+ guard = guard->m_next;
+ }
+}
+
+void QGLContextGroup::addGuard(QGLSharedResourceGuard *guard)
+{
+ if (m_guards)
+ m_guards->m_prev = guard;
+ guard->m_next = m_guards;
+ guard->m_prev = 0;
+ m_guards = guard;
+}
+
+void QGLContextGroup::removeGuard(QGLSharedResourceGuard *guard)
+{
+ if (guard->m_next)
+ guard->m_next->m_prev = guard->m_prev;
+ if (guard->m_prev)
+ guard->m_prev->m_next = guard->m_next;
+ else
+ m_guards = guard->m_next;
+}
+
+QGLContextPrivate::~QGLContextPrivate()
+{
+ if (!group->m_refs.deref()) {
+ Q_ASSERT(group->context() == q_ptr);
+ delete group;
+ }
+}
+
void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format)
{
Q_Q(QGLContext);
@@ -1288,15 +1472,18 @@ void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format)
#endif
#if defined(QT_OPENGL_ES)
eglContext = 0;
+ eglSurface = EGL_NO_SURFACE;
#endif
- pbo = 0;
+ fbo = 0;
crWin = false;
initDone = false;
sharing = false;
- clear_on_painter_begin = true;
max_texture_size = -1;
version_flags_cached = false;
version_flags = QGLFormat::OpenGL_Version_None;
+ current_fbo = 0;
+ default_fbo = 0;
+ active_engine = 0;
}
QGLContext* QGLContext::currentCtx = 0;
@@ -1307,12 +1494,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();
@@ -1343,7 +1526,30 @@ 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();
+#if !defined(QT_OPENGL_ES_2) && !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
+ //### glGetTexImage not in GL ES 2.0, need to do something else here!
+ glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
+#endif
+ convertFromGLImage(img, w, h, alpha_format, include_alpha);
+ return img;
}
// returns the highest number closest to v, which is a power of 2
@@ -1360,39 +1566,133 @@ int qt_next_power_of_two(int v)
return v;
}
-class QGLTexture {
-public:
- QGLTexture(const QGLContext *ctx, GLuint tx_id, GLenum tx_target, bool _clean = false)
- : context(ctx), id(tx_id), target(tx_target), clean(_clean) {}
- ~QGLTexture() {
- if (clean) {
- QGLContext *current = const_cast<QGLContext *>(QGLContext::currentContext());
- QGLContext *ctx = const_cast<QGLContext *>(context);
- bool switch_context = current && current != ctx && !qgl_share_reg()->checkSharing(current, ctx);
- if (switch_context)
- ctx->makeCurrent();
- glDeleteTextures(1, &id);
- if (switch_context)
- current->makeCurrent();
- }
- }
-
- const QGLContext *context;
- GLuint id;
- GLenum target;
- bool clean;
-};
-
-typedef QCache<qint64, QGLTexture> QGLTextureCache;
-static int qt_tex_cache_limit = 64*1024; // cache ~64 MB worth of textures - this is not accurate though
-static QGLTextureCache *qt_tex_cache = 0;
-
typedef void (*_qt_pixmap_cleanup_hook_64)(qint64);
typedef void (*_qt_image_cleanup_hook_64)(qint64);
extern Q_GUI_EXPORT _qt_pixmap_cleanup_hook_64 qt_pixmap_cleanup_hook_64;
extern Q_GUI_EXPORT _qt_image_cleanup_hook_64 qt_image_cleanup_hook_64;
+static QGLTextureCache *qt_gl_texture_cache = 0;
+
+QGLTextureCache::QGLTextureCache()
+ : m_cache(64*1024) // cache ~64 MB worth of textures - this is not accurate though
+{
+ Q_ASSERT(qt_gl_texture_cache == 0);
+ qt_gl_texture_cache = this;
+
+ QImagePixmapCleanupHooks::instance()->addPixmapModificationHook(cleanupTextures);
+#ifdef Q_WS_X11
+ QImagePixmapCleanupHooks::instance()->addPixmapDestructionHook(cleanupPixmapSurfaces);
+#endif
+ QImagePixmapCleanupHooks::instance()->addImageHook(imageCleanupHook);
+}
+
+QGLTextureCache::~QGLTextureCache()
+{
+ qt_gl_texture_cache = 0;
+
+ QImagePixmapCleanupHooks::instance()->removePixmapModificationHook(cleanupTextures);
+#ifdef Q_WS_X11
+ QImagePixmapCleanupHooks::instance()->removePixmapDestructionHook(cleanupPixmapSurfaces);
+#endif
+ QImagePixmapCleanupHooks::instance()->removeImageHook(imageCleanupHook);
+}
+
+void QGLTextureCache::insert(QGLContext* ctx, qint64 key, QGLTexture* texture, int cost)
+{
+ if (m_cache.totalCost() + cost > m_cache.maxCost()) {
+ // the cache is full - make an attempt to remove something
+ const QList<qint64> keys = m_cache.keys();
+ int i = 0;
+ while (i < m_cache.count()
+ && (m_cache.totalCost() + cost > m_cache.maxCost())) {
+ QGLTexture *tex = m_cache.object(keys.at(i));
+ if (tex->context == ctx)
+ m_cache.remove(keys.at(i));
+ ++i;
+ }
+ }
+ m_cache.insert(key, texture, cost);
+}
+
+bool QGLTextureCache::remove(QGLContext* ctx, GLuint textureId)
+{
+ QList<qint64> keys = m_cache.keys();
+ for (int i = 0; i < keys.size(); ++i) {
+ QGLTexture *tex = m_cache.object(keys.at(i));
+ if (tex->id == textureId && tex->context == ctx) {
+ tex->options |= QGLContext::MemoryManagedBindOption; // forces a glDeleteTextures() call
+ m_cache.remove(keys.at(i));
+ return true;
+ }
+ }
+ return false;
+}
+
+void QGLTextureCache::removeContextTextures(QGLContext* ctx)
+{
+ QList<qint64> keys = m_cache.keys();
+ for (int i = 0; i < keys.size(); ++i) {
+ const qint64 &key = keys.at(i);
+ if (m_cache.object(key)->context == ctx)
+ m_cache.remove(key);
+ }
+}
+
+QGLTextureCache* QGLTextureCache::instance()
+{
+ if (!qt_gl_texture_cache)
+ qt_gl_texture_cache = new QGLTextureCache;
+
+ return qt_gl_texture_cache;
+}
+
+/*
+ a hook that removes textures from the cache when a pixmap/image
+ is deref'ed
+*/
+void QGLTextureCache::imageCleanupHook(qint64 cacheKey)
+{
+ // ### remove when the GL texture cache becomes thread-safe
+ if (qApp->thread() != QThread::currentThread())
+ return;
+ QGLTexture *texture = instance()->getTexture(cacheKey);
+ if (texture && texture->options & QGLContext::MemoryManagedBindOption)
+ instance()->remove(cacheKey);
+}
+
+
+void QGLTextureCache::cleanupTextures(QPixmap* pixmap)
+{
+ // ### remove when the GL texture cache becomes thread-safe
+ if (qApp->thread() == QThread::currentThread()) {
+ const qint64 cacheKey = pixmap->cacheKey();
+ QGLTexture *texture = instance()->getTexture(cacheKey);
+ if (texture && texture->options & QGLContext::MemoryManagedBindOption)
+ instance()->remove(cacheKey);
+ }
+}
+
+#if defined(Q_WS_X11)
+void QGLTextureCache::cleanupPixmapSurfaces(QPixmap* pixmap)
+{
+ // Remove any bound textures first:
+ cleanupTextures(pixmap);
+
+ QPixmapData *pd = pixmap->data_ptr().data();
+ if (pd->classId() == QPixmapData::X11Class) {
+ Q_ASSERT(pd->ref == 1); // Make sure reference counting isn't broken
+ QGLContextPrivate::destroyGlSurfaceForPixmap(pd);
+ }
+}
+#endif
+
+void QGLTextureCache::deleteIfEmpty()
+{
+ if (instance()->size() == 0)
+ delete instance();
+}
+
// DDS format structure
struct DDSFormat {
quint32 dwSize;
@@ -1429,7 +1729,7 @@ struct DDSFormat {
#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192
#endif
-Q_GLOBAL_STATIC(QGLShareRegister, _qgl_share_reg);
+Q_GLOBAL_STATIC(QGLShareRegister, _qgl_share_reg)
Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg()
{
return _qgl_share_reg();
@@ -1439,7 +1739,7 @@ Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg()
\class QGLContext
\brief The QGLContext class encapsulates an OpenGL rendering context.
- \ingroup multimedia
+ \ingroup painting-3D
An OpenGL rendering context is a complete set of OpenGL state
variables. The rendering context's \l {QGL::FormatOption} {format}
@@ -1464,6 +1764,47 @@ Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg()
Please note that QGLContext is not thread safe.
*/
+/*!
+ \enum QGLContext::BindOption
+ \since 4.6
+
+ A set of options to decide how to bind a texture using bindTexture().
+
+ \value NoBindOption Don't do anything, pass the texture straight
+ through.
+
+ \value InvertedYBindOption Specifies that the texture should be flipped
+ over the X axis so that the texture coordinate 0,0 corresponds to
+ the top left corner. Inverting the texture implies a deep copy
+ prior to upload.
+
+ \value MipmapBindOption Specifies that bindTexture() should try
+ to generate mipmaps. If the GL implementation supports the \c
+ GL_SGIS_generate_mipmap extension, mipmaps will be automatically
+ generated for the texture. Mipmap generation is only supported for
+ the \c GL_TEXTURE_2D target.
+
+ \value PremultipliedAlphaBindOption Specifies that the image should be
+ uploaded with premultiplied alpha and does a conversion accordingly.
+
+ \value LinearFilteringBindOption Specifies that the texture filtering
+ should be set to GL_LINEAR. Default is GL_NEAREST. If mipmap is
+ also enabled, filtering will be set to GL_LINEAR_MIPMAP_LINEAR.
+
+ \value DefaultBindOption In Qt 4.5 and earlier, bindTexture()
+ would mirror the image and automatically generate mipmaps. This
+ option helps preserve this default behavior.
+
+ \omitvalue CanFlipNativePixmapBindOption Used by x11 from pixmap to choose
+ wether or not it can bind the pixmap upside down or not.
+
+ \omitvalue MemoryManagedBindOption Used by paint engines to
+ indicate that the pixmap should be memory managed along side with
+ the pixmap/image that it stems from, e.g. installing destruction
+ hooks in them.
+
+ \omitvalue InternalBindOption
+*/
/*!
\obsolete
@@ -1484,8 +1825,8 @@ Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg()
*/
QGLContext::QGLContext(const QGLFormat &format, QPaintDevice *device)
+ : d_ptr(new QGLContextPrivate(this))
{
- d_ptr = new QGLContextPrivate(this);
Q_D(QGLContext);
d->init(device, format);
}
@@ -1507,8 +1848,8 @@ QGLContext::QGLContext(const QGLFormat &format, QPaintDevice *device)
\sa format(), isValid()
*/
QGLContext::QGLContext(const QGLFormat &format)
+ : d_ptr(new QGLContextPrivate(this))
{
- d_ptr = new QGLContextPrivate(this);
Q_D(QGLContext);
d->init(0, format);
}
@@ -1519,223 +1860,168 @@ QGLContext::QGLContext(const QGLFormat &format)
QGLContext::~QGLContext()
{
- Q_D(QGLContext);
// remove any textures cached in this context
- if (qt_tex_cache) {
- QList<qint64> keys = qt_tex_cache->keys();
- for (int i = 0; i < keys.size(); ++i) {
- const qint64 &key = keys.at(i);
- if (qt_tex_cache->object(key)->context == this)
- qt_tex_cache->remove(key);
- }
- // ### thread safety
- if (qt_tex_cache->size() == 0) {
- qt_pixmap_cleanup_hook_64 = 0;
- qt_image_cleanup_hook_64 = 0;
- delete qt_tex_cache;
- qt_tex_cache = 0;
- }
- }
+ QGLTextureCache::instance()->removeContextTextures(this);
+ QGLTextureCache::deleteIfEmpty(); // ### thread safety
+
+ d_ptr->group->cleanupResources(this);
QGLSignalProxy::instance()->emitAboutToDestroyContext(this);
reset();
- delete d;
}
void QGLContextPrivate::cleanup()
{
- Q_Q(QGLContext);
- if (pbo) {
- QGLContext *ctx = q;
- glDeleteBuffersARB(1, &pbo);
- pbo = 0;
- }
}
-typedef QHash<QString, GLuint> QGLDDSCache;
-Q_GLOBAL_STATIC(QGLDDSCache, qgl_dds_cache)
-
/*!
\overload
- Reads the DirectDrawSurface (DDS) compressed file \a fileName and
- generates a 2D GL texture from it.
+ Reads the compressed texture file \a fileName and generates a 2D GL
+ texture from it.
- Only the DXT1, DXT3 and DXT5 DDS formats are supported.
+ This function can load DirectDrawSurface (DDS) textures in the
+ DXT1, DXT3 and DXT5 DDS formats if the \c GL_ARB_texture_compression
+ and \c GL_EXT_texture_compression_s3tc extensions are supported.
- Note that this will only work if the implementation supports the
- \c GL_ARB_texture_compression and \c GL_EXT_texture_compression_s3tc
- extensions.
+ Since 4.6.1, textures in the ETC1 format can be loaded if the
+ \c GL_OES_compressed_ETC1_RGB8_texture extension is supported
+ and the ETC1 texture has been encapsulated in the PVR container format.
+ Also, textures in the PVRTC2 and PVRTC4 formats can be loaded
+ if the \c GL_IMG_texture_compression_pvrtc extension is supported.
\sa deleteTexture()
*/
GLuint QGLContext::bindTexture(const QString &fileName)
{
- if (!qt_glCompressedTexImage2DARB) {
- qWarning("QGLContext::bindTexture(): The GL implementation does not support texture"
- "compression extensions.");
- return 0;
- }
-
- QGLDDSCache::const_iterator it = qgl_dds_cache()->constFind(fileName);
- if (it != qgl_dds_cache()->constEnd()) {
+ Q_D(QGLContext);
+ QGLDDSCache *dds_cache = &(d->group->m_dds_cache);
+ QGLDDSCache::const_iterator it = dds_cache->constFind(fileName);
+ if (it != dds_cache->constEnd()) {
glBindTexture(GL_TEXTURE_2D, it.value());
return it.value();
}
- QFile f(fileName);
- f.open(QIODevice::ReadOnly);
-
- char tag[4];
- f.read(&tag[0], 4);
- if (strncmp(tag,"DDS ", 4) != 0) {
- qWarning("QGLContext::bindTexture(): not a DDS image file.");
+ QGLTexture texture(this);
+ QSize size = texture.bindCompressedTexture(fileName);
+ if (!size.isValid())
return 0;
- }
-
- DDSFormat ddsHeader;
- f.read((char *) &ddsHeader, sizeof(DDSFormat));
- if (!ddsHeader.dwLinearSize) {
- qWarning("QGLContext::bindTexture() DDS image size is not valid.");
- return 0;
- }
-
- int factor = 4;
- int bufferSize = 0;
- int blockSize = 16;
- GLenum format;
-
- switch(ddsHeader.ddsPixelFormat.dwFourCC) {
- case FOURCC_DXT1:
- format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
- factor = 2;
- blockSize = 8;
- break;
- case FOURCC_DXT3:
- format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
- break;
- case FOURCC_DXT5:
- format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
- break;
- default:
- qWarning("QGLContext::bindTexture() DDS image format not supported.");
- return 0;
- }
-
- if (ddsHeader.dwMipMapCount > 1)
- bufferSize = ddsHeader.dwLinearSize * factor;
- else
- bufferSize = ddsHeader.dwLinearSize;
-
- GLubyte *pixels = (GLubyte *) malloc(bufferSize*sizeof(GLubyte));
- f.seek(ddsHeader.dwSize + 4);
- f.read((char *) pixels, bufferSize);
- f.close();
-
- GLuint tx_id;
- glGenTextures(1, &tx_id);
- glBindTexture(GL_TEXTURE_2D, tx_id);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-
- int size;
- int offset = 0;
- int w = ddsHeader.dwWidth;
- int h = ddsHeader.dwHeight;
-
- // load mip-maps
- for(int i = 0; i < (int) ddsHeader.dwMipMapCount; ++i) {
- if (w == 0) w = 1;
- if (h == 0) h = 1;
-
- size = ((w+3)/4) * ((h+3)/4) * blockSize;
- qt_glCompressedTexImage2DARB(GL_TEXTURE_2D, i, format, w, h, 0,
- size, pixels + offset);
- offset += size;
+ dds_cache->insert(fileName, texture.id);
+ return texture.id;
+}
- // half size for each mip-map level
- w = w/2;
- h = h/2;
+static inline QRgb qt_gl_convertToGLFormatHelper(QRgb src_pixel, GLenum texture_format)
+{
+ if (texture_format == GL_BGRA) {
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ return ((src_pixel << 24) & 0xff000000)
+ | ((src_pixel >> 24) & 0x000000ff)
+ | ((src_pixel << 8) & 0x00ff0000)
+ | ((src_pixel >> 8) & 0x0000ff00);
+ } else {
+ return src_pixel;
+ }
+ } else { // GL_RGBA
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ return (src_pixel << 8) | ((src_pixel >> 24) & 0xff);
+ } else {
+ return ((src_pixel << 16) & 0xff0000)
+ | ((src_pixel >> 16) & 0xff)
+ | (src_pixel & 0xff00ff00);
+ }
}
-
- free(pixels);
-
- qgl_dds_cache()->insert(fileName, tx_id);
- return tx_id;
}
-/*
- a hook that removes textures from the cache when a pixmap/image
- is deref'ed
-*/
-static void qt_gl_clean_cache(qint64 cacheKey)
+QRgb qt_gl_convertToGLFormat(QRgb src_pixel, GLenum texture_format)
{
- // ### remove when the GL texture cache becomes thread-safe
- if (qApp->thread() != QThread::currentThread())
- return;
- if (qt_tex_cache) {
- QGLTexture *texture = qt_tex_cache->object(cacheKey);
- if (texture && texture->clean)
- qt_tex_cache->remove(cacheKey);
- }
+ return qt_gl_convertToGLFormatHelper(src_pixel, texture_format);
}
static void convertToGLFormatHelper(QImage &dst, const QImage &img, GLenum texture_format)
{
- Q_ASSERT(dst.size() == img.size());
Q_ASSERT(dst.depth() == 32);
Q_ASSERT(img.depth() == 32);
- const int width = img.width();
- const int height = img.height();
- const uint *p = (const uint*) img.scanLine(img.height() - 1);
- uint *q = (uint*) dst.scanLine(0);
-
- if (texture_format == GL_BGRA) {
- if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
- // mirror + swizzle
- for (int i=0; i < height; ++i) {
- const uint *end = p + width;
- while (p < end) {
- *q = ((*p << 24) & 0xff000000)
- | ((*p >> 24) & 0x000000ff)
- | ((*p << 8) & 0x00ff0000)
- | ((*p >> 8) & 0x0000ff00);
- p++;
- q++;
- }
- p -= 2 * width;
- }
- } else {
- const uint bytesPerLine = img.bytesPerLine();
- for (int i=0; i < height; ++i) {
- memcpy(q, p, bytesPerLine);
- q += width;
- p -= width;
+ if (dst.size() != img.size()) {
+ int target_width = dst.width();
+ int target_height = dst.height();
+ qreal sx = target_width / qreal(img.width());
+ qreal sy = target_height / qreal(img.height());
+
+ quint32 *dest = (quint32 *) dst.scanLine(0); // NB! avoid detach here
+ uchar *srcPixels = (uchar *) img.scanLine(img.height() - 1);
+ int sbpl = img.bytesPerLine();
+ int dbpl = dst.bytesPerLine();
+
+ int ix = int(0x00010000 / sx);
+ int iy = int(0x00010000 / sy);
+
+ quint32 basex = int(0.5 * ix);
+ quint32 srcy = int(0.5 * iy);
+
+ // scale, swizzle and mirror in one loop
+ while (target_height--) {
+ const uint *src = (const quint32 *) (srcPixels - (srcy >> 16) * sbpl);
+ int srcx = basex;
+ for (int x=0; x<target_width; ++x) {
+ dest[x] = qt_gl_convertToGLFormatHelper(src[srcx >> 16], texture_format);
+ srcx += ix;
}
+ dest = (quint32 *)(((uchar *) dest) + dbpl);
+ srcy += iy;
}
} else {
- if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
- for (int i=0; i < height; ++i) {
- const uint *end = p + width;
- while (p < end) {
- *q = (*p << 8) | ((*p >> 24) & 0xFF);
- p++;
- q++;
+ const int width = img.width();
+ const int height = img.height();
+ const uint *p = (const uint*) img.scanLine(img.height() - 1);
+ uint *q = (uint*) dst.scanLine(0);
+
+ if (texture_format == GL_BGRA) {
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ // mirror + swizzle
+ for (int i=0; i < height; ++i) {
+ const uint *end = p + width;
+ while (p < end) {
+ *q = ((*p << 24) & 0xff000000)
+ | ((*p >> 24) & 0x000000ff)
+ | ((*p << 8) & 0x00ff0000)
+ | ((*p >> 8) & 0x0000ff00);
+ p++;
+ q++;
+ }
+ p -= 2 * width;
+ }
+ } else {
+ const uint bytesPerLine = img.bytesPerLine();
+ for (int i=0; i < height; ++i) {
+ memcpy(q, p, bytesPerLine);
+ q += width;
+ p -= width;
}
- p -= 2 * width;
}
} else {
- for (int i=0; i < height; ++i) {
- const uint *end = p + width;
- while (p < end) {
- *q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00);
- p++;
- q++;
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ for (int i=0; i < height; ++i) {
+ const uint *end = p + width;
+ while (p < end) {
+ *q = (*p << 8) | ((*p >> 24) & 0xff);
+ p++;
+ q++;
+ }
+ p -= 2 * width;
+ }
+ } else {
+ for (int i=0; i < height; ++i) {
+ const uint *end = p + width;
+ while (p < end) {
+ *q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00);
+ p++;
+ q++;
+ }
+ p -= 2 * width;
}
- p -= 2 * width;
}
}
}
@@ -1753,161 +2039,308 @@ QImage QGLContextPrivate::convertToGLFormat(const QImage &image, bool force_prem
return result;
}
-GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format,
- const qint64 key, bool clean)
+/*! \internal */
+QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format,
+ QGLContext::BindOptions options)
{
- Q_Q(QGLContext);
+ const qint64 key = image.cacheKey();
+ QGLTexture *texture = textureCacheLookup(key, target);
+ if (texture) {
+ glBindTexture(target, texture->id);
+ return texture;
+ }
- QGLContext *ctx = q;
+ if (!texture)
+ texture = bindTexture(image, target, format, key, options);
+ // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null
+ Q_ASSERT(texture);
- bool use_pbo = false;
- if (QGLExtensions::glExtensions & QGLExtensions::PixelBufferObject) {
+ if (texture->id > 0)
+ QImagePixmapCleanupHooks::enableCleanupHooks(image);
- use_pbo = qt_resolve_buffer_extensions(ctx);
- if (use_pbo && pbo == 0)
- glGenBuffersARB(1, &pbo);
- }
+ return texture;
+}
+
+// #define QGL_BIND_TEXTURE_DEBUG
- // the GL_BGRA format is only present in GL version >= 1.2
- GLenum texture_format = (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_2)
- ? GL_BGRA : GL_RGBA;
- if (!qt_tex_cache) {
- qt_tex_cache = new QGLTextureCache(qt_tex_cache_limit);
- qt_pixmap_cleanup_hook_64 = qt_gl_clean_cache;
- qt_image_cleanup_hook_64 = qt_gl_clean_cache;
+// map from Qt's ARGB endianness-dependent format to GL's big-endian RGBA layout
+static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type)
+{
+ const int width = img.width();
+ const int height = img.height();
+
+ if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV
+ || (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian))
+ {
+ for (int i = 0; i < height; ++i) {
+ uint *p = (uint *) img.scanLine(i);
+ for (int x = 0; x < width; ++x)
+ p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
+ }
+ } else {
+ for (int i = 0; i < height; ++i) {
+ uint *p = (uint *) img.scanLine(i);
+ for (int x = 0; x < width; ++x)
+ p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff);
+ }
}
+}
+
+QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint internalFormat,
+ const qint64 key, QGLContext::BindOptions options)
+{
+ Q_Q(QGLContext);
+
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf("QGLContextPrivate::bindTexture(), imageSize=(%d,%d), internalFormat =0x%x, options=%x\n",
+ image.width(), image.height(), internalFormat, int(options));
+ QTime time;
+ time.start();
+#endif
+
+#ifndef QT_NO_DEBUG
+ // Reset the gl error stack...git
+ while (glGetError() != GL_NO_ERROR) ;
+#endif
// Scale the pixmap if needed. GL textures needs to have the
- // dimensions 2^n+2(border) x 2^m+2(border).
+ // dimensions 2^n+2(border) x 2^m+2(border), unless we're using GL
+ // 2.0 or use the GL_TEXTURE_RECTANGLE texture target
int tx_w = qt_next_power_of_two(image.width());
int tx_h = qt_next_power_of_two(image.height());
- // Note: the clean param is only true when a texture is bound
- // from the QOpenGLPaintEngine - in that case we have to force
- // a premultiplied texture format
QImage img = image;
- if (( !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) &&
- !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0) )
+ if (!(QGLExtensions::glExtensions & QGLExtensions::NPOTTextures)
+ && !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0)
&& (target == GL_TEXTURE_2D && (tx_w != image.width() || tx_h != image.height())))
{
- img = image.scaled(tx_w, tx_h);
+ img = img.scaled(tx_w, tx_h);
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - upscaled to %dx%d (%d ms)\n", tx_w, tx_h, time.elapsed());
+
+#endif
}
+ GLuint filtering = options & QGLContext::LinearFilteringBindOption ? GL_LINEAR : GL_NEAREST;
+
GLuint tx_id;
glGenTextures(1, &tx_id);
glBindTexture(target, tx_id);
- glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(target, GL_TEXTURE_MAG_FILTER, filtering);
+
+#if defined(QT_OPENGL_ES_2)
+ bool genMipmap = false;
+#endif
if (glFormat.directRendering()
- && QGLExtensions::glExtensions & QGLExtensions::GenerateMipmap
- && target == GL_TEXTURE_2D && !clean)
+ && (QGLExtensions::glExtensions & QGLExtensions::GenerateMipmap)
+ && target == GL_TEXTURE_2D
+ && (options & QGLContext::MipmapBindOption))
{
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - generating mipmaps (%d ms)\n", time.elapsed());
+#endif
+#if !defined(QT_OPENGL_ES_2)
glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
#ifndef QT_OPENGL_ES
glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
#else
glTexParameterf(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
#endif
- glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+#else
+ glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
+ genMipmap = true;
+#endif
+ glTexParameterf(target, GL_TEXTURE_MIN_FILTER, options & QGLContext::LinearFilteringBindOption
+ ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST);
+ } else {
+ glTexParameterf(target, GL_TEXTURE_MIN_FILTER, filtering);
+ }
- // Mipmap generation causes huge slowdown with PBO's for some reason
- use_pbo = false;
+ QImage::Format target_format = img.format();
+ bool premul = options & QGLContext::PremultipliedAlphaBindOption;
+ GLenum externalFormat;
+ GLuint pixel_type;
+ if (QGLExtensions::glExtensions & QGLExtensions::BGRATextureFormat) {
+ externalFormat = GL_BGRA;
+ pixel_type = GL_UNSIGNED_INT_8_8_8_8_REV;
} else {
- glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ externalFormat = GL_RGBA;
+ pixel_type = GL_UNSIGNED_BYTE;
}
- uchar *ptr = 0;
- if (use_pbo) {
- glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
- glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, img.width() * img.height() * 4, 0, GL_STREAM_DRAW_ARB);
- ptr = reinterpret_cast<uchar *>(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB));
+ switch (target_format) {
+ case QImage::Format_ARGB32:
+ if (premul) {
+ img = img.convertToFormat(target_format = QImage::Format_ARGB32_Premultiplied);
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - converting ARGB32 -> ARGB32_Premultiplied (%d ms) \n", time.elapsed());
+#endif
+ }
+ break;
+ case QImage::Format_ARGB32_Premultiplied:
+ if (!premul) {
+ img = img.convertToFormat(target_format = QImage::Format_ARGB32);
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - converting ARGB32_Premultiplied -> ARGB32 (%d ms)\n", time.elapsed());
+#endif
+ }
+ break;
+ case QImage::Format_RGB16:
+ pixel_type = GL_UNSIGNED_SHORT_5_6_5;
+ externalFormat = GL_RGB;
+ internalFormat = GL_RGB;
+ break;
+ case QImage::Format_RGB32:
+ break;
+ default:
+ if (img.hasAlphaChannel()) {
+ img = img.convertToFormat(premul
+ ? QImage::Format_ARGB32_Premultiplied
+ : QImage::Format_ARGB32);
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - converting to 32-bit alpha format (%d ms)\n", time.elapsed());
+#endif
+ } else {
+ img = img.convertToFormat(QImage::Format_RGB32);
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - converting to 32-bit (%d ms)\n", time.elapsed());
+#endif
+ }
}
- if (ptr) {
- QImage::Format target_format = img.format();
- if (clean || img.format() != QImage::Format_ARGB32)
- target_format = QImage::Format_ARGB32_Premultiplied;
+ if (options & QGLContext::InvertedYBindOption) {
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - flipping bits over y (%d ms)\n", time.elapsed());
+#endif
+ if (img.isDetached()) {
+ int ipl = img.bytesPerLine() / 4;
+ int h = img.height();
+ for (int y=0; y<h/2; ++y) {
+ int *a = (int *) img.scanLine(y);
+ int *b = (int *) img.scanLine(h - y - 1);
+ for (int x=0; x<ipl; ++x)
+ qSwap(a[x], b[x]);
+ }
+ } else {
+ // Create a new image and copy across. If we use the
+ // above in-place code then a full copy of the image is
+ // made before the lines are swapped, which processes the
+ // data twice. This version should only do it once.
+ img = img.mirrored();
+ }
+ }
- QImage buffer(ptr, img.width(), img.height(), target_format);
- convertToGLFormatHelper(buffer, img.convertToFormat(target_format), texture_format);
- glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
- glTexImage2D(target, 0, format, img.width(), img.height(), 0, texture_format, GL_UNSIGNED_BYTE, 0);
- } else {
- QImage tx = convertToGLFormat(img, clean, texture_format);
- glTexImage2D(target, 0, format, tx.width(), tx.height(), 0, texture_format,
- GL_UNSIGNED_BYTE, tx.bits());
+ if (externalFormat == GL_RGBA) {
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - doing byte swapping (%d ms)\n", time.elapsed());
+#endif
+ // The only case where we end up with a depth different from
+ // 32 in the switch above is for the RGB16 case, where we set
+ // the format to GL_RGB
+ Q_ASSERT(img.depth() == 32);
+ qgl_byteSwapImage(img, pixel_type);
}
+#ifdef QT_OPENGL_ES
+ // OpenGL/ES requires that the internal and external formats be identical.
+ // This is typically used to convert GL_RGBA into GL_BGRA.
+ // Also, we need to use GL_UNSIGNED_BYTE when the format is GL_BGRA.
+ internalFormat = externalFormat;
+ if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV)
+ pixel_type = GL_UNSIGNED_BYTE;
+#endif
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - uploading, image.format=%d, externalFormat=0x%x, internalFormat=0x%x, pixel_type=0x%x\n",
+ img.format(), externalFormat, internalFormat, pixel_type);
+#endif
+
+ const QImage &constRef = img; // to avoid detach in bits()...
+ glTexImage2D(target, 0, internalFormat, img.width(), img.height(), 0, externalFormat,
+ pixel_type, constRef.bits());
+#if defined(QT_OPENGL_ES_2)
+ if (genMipmap)
+ glGenerateMipmap(target);
+#endif
+#ifndef QT_NO_DEBUG
+ GLenum error = glGetError();
+ if (error != GL_NO_ERROR) {
+ qWarning(" - texture upload failed, error code 0x%x\n", error);
+ }
+#endif
+
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ static int totalUploadTime = 0;
+ totalUploadTime += time.elapsed();
+ printf(" - upload done in (%d ms) time=%d\n", time.elapsed(), totalUploadTime);
+#endif
- if (use_pbo)
- glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
// this assumes the size of a texture is always smaller than the max cache size
int cost = img.width()*img.height()*4/1024;
- if (qt_tex_cache->totalCost() + cost > qt_tex_cache->maxCost()) {
- // the cache is full - make an attempt to remove something
- const QList<qint64> keys = qt_tex_cache->keys();
- int i = 0;
- while (i < qt_tex_cache->count()
- && (qt_tex_cache->totalCost() + cost > qt_tex_cache->maxCost())) {
- QGLTexture *tex = qt_tex_cache->object(keys.at(i));
- if (tex->context == q)
- qt_tex_cache->remove(keys.at(i));
- ++i;
- }
- }
- qt_tex_cache->insert(key, new QGLTexture(q, tx_id, target, clean), cost);
- return tx_id;
+ QGLTexture *texture = new QGLTexture(q, tx_id, target, options);
+ QGLTextureCache::instance()->insert(q, key, texture, cost);
+ return texture;
}
-bool QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum target, GLuint *id)
+QGLTexture *QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum target)
{
Q_Q(QGLContext);
- if (qt_tex_cache) {
- QGLTexture *texture = qt_tex_cache->object(key);
- if (texture && texture->target == target
- && (texture->context == q || qgl_share_reg()->checkSharing(q, texture->context)))
- {
- *id = texture->id;
- return true;
- }
+ QGLTexture *texture = QGLTextureCache::instance()->getTexture(key);
+ if (texture && texture->target == target
+ && (texture->context == q || QGLContext::areSharing(q, texture->context)))
+ {
+ return texture;
}
- return false;
+ return 0;
}
-/*! \internal */
-GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format, bool clean)
-{
- const qint64 key = image.cacheKey();
- GLuint id;
- if (textureCacheLookup(key, target, &id)) {
- glBindTexture(target, id);
- return id;
- }
- GLuint cached = bindTexture(image, target, format, key, clean);
- const_cast<QImage &>(image).data_ptr()->is_cached = (cached > 0);
- return cached;
-}
/*! \internal */
-GLuint QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean)
+QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, QGLContext::BindOptions options)
{
-#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());
-
- if (data->isValidContext(QGLContext::currentContext()))
- return data->bind();
+ Q_Q(QGLContext);
+ QPixmapData *pd = pixmap.pixmapData();
+#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
+ if (target == GL_TEXTURE_2D && pd->classId() == QPixmapData::OpenGLClass) {
+ const QGLPixmapData *data = static_cast<const QGLPixmapData *>(pd);
+
+ if (data->isValidContext(q)) {
+ data->bind();
+ return data->texture();
+ }
}
+#else
+ Q_UNUSED(pd);
+ Q_UNUSED(q);
#endif
const qint64 key = pixmap.cacheKey();
- GLuint id;
- if (textureCacheLookup(key, target, &id)) {
- glBindTexture(target, id);
- return id;
+ QGLTexture *texture = textureCacheLookup(key, target);
+ if (texture) {
+ glBindTexture(target, texture->id);
+ return texture;
}
- GLuint cached = bindTexture(pixmap.toImage(), target, format, key, clean);
- const_cast<QPixmap &>(pixmap).data_ptr()->is_cached = (cached > 0);
- return cached;
+
+#if defined(Q_WS_X11)
+ // Try to use texture_from_pixmap
+ if (pd->classId() == QPixmapData::X11Class && pd->pixelType() == QPixmapData::PixmapType) {
+ texture = bindTextureFromNativePixmap(pd, key, options);
+ if (texture) {
+ texture->options |= QGLContext::MemoryManagedBindOption;
+ texture->boundPixmap = pd;
+ boundPixmaps.insert(pd, QPixmap(pixmap));
+ }
+ }
+#endif
+
+ if (!texture)
+ texture = bindTexture(pixmap.toImage(), target, format, key, options);
+ // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null
+ Q_ASSERT(texture);
+
+ if (texture->id > 0)
+ QImagePixmapCleanupHooks::enableCleanupHooks(pixmap);
+
+ return texture;
}
/*! \internal */
@@ -1946,6 +2379,25 @@ int QGLContextPrivate::maxTextureSize()
}
/*!
+ Generates and binds a 2D GL texture to the current context, based
+ on \a image. The generated texture id is returned and can be used in
+ later \c glBindTexture() calls.
+
+ \overload
+*/
+GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format)
+{
+ if (image.isNull())
+ return 0;
+
+ Q_D(QGLContext);
+ QGLTexture *texture = d->bindTexture(image, target, format, false, DefaultBindOption);
+ return texture->id;
+}
+
+/*!
+ \since 4.6
+
Generates and binds a 2D GL texture to the current context, based
on \a image. The generated texture id is returned and can be used
in later \c glBindTexture() calls.
@@ -1954,12 +2406,10 @@ int QGLContextPrivate::maxTextureSize()
target is \c GL_TEXTURE_2D.
The \a format parameter sets the internal format for the
- texture. The default format is \c GL_RGBA8.
+ texture. The default format is \c GL_RGBA.
- If the GL implementation supports the \c GL_SGIS_generate_mipmap
- extension, mipmaps will be automatically generated for the
- texture. Mipmap generation is only supported for the \c
- GL_TEXTURE_2D target.
+ The binding \a options are a set of options used to decide how to
+ bind the texture to the context.
The texture that is generated is cached, so multiple calls to
bindTexture() with the same QImage will return the same texture
@@ -1970,18 +2420,38 @@ int QGLContextPrivate::maxTextureSize()
\sa deleteTexture()
*/
-GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format)
+GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format, BindOptions options)
{
+ if (image.isNull())
+ return 0;
+
Q_D(QGLContext);
- return d->bindTexture(image, target, format, false);
+ QGLTexture *texture = d->bindTexture(image, target, format, false, options);
+ return texture->id;
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
/*! \internal */
GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format)
{
+ if (image.isNull())
+ return 0;
+
Q_D(QGLContext);
- return d->bindTexture(image, GLenum(target), GLint(format), false);
+ QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, DefaultBindOption);
+ return texture->id;
+}
+
+/*! \internal */
+GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format,
+ BindOptions options)
+{
+ if (image.isNull())
+ return 0;
+
+ Q_D(QGLContext);
+ QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, options);
+ return texture->id;
}
#endif
@@ -1991,16 +2461,52 @@ GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMa
*/
GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
{
+ if (pixmap.isNull())
+ return 0;
+
+ Q_D(QGLContext);
+ QGLTexture *texture = d->bindTexture(pixmap, target, format, DefaultBindOption);
+ return texture->id;
+}
+
+/*!
+ \overload
+ \since 4.6
+
+ Generates and binds a 2D GL texture to the current context, based
+ on \a pixmap.
+*/
+GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, BindOptions options)
+{
+ if (pixmap.isNull())
+ return 0;
+
Q_D(QGLContext);
- return d->bindTexture(pixmap, target, format, false);
+ QGLTexture *texture = d->bindTexture(pixmap, target, format, options);
+ return texture->id;
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
/*! \internal */
GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format)
{
+ if (pixmap.isNull())
+ return 0;
+
Q_D(QGLContext);
- return d->bindTexture(pixmap, GLenum(target), GLint(format), false);
+ QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), DefaultBindOption);
+ return texture->id;
+}
+/*! \internal */
+GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format,
+ BindOptions options)
+{
+ if (pixmap.isNull())
+ return 0;
+
+ Q_D(QGLContext);
+ QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), options);
+ return texture->id;
}
#endif
@@ -2013,26 +2519,20 @@ GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, Q
*/
void QGLContext::deleteTexture(GLuint id)
{
- if (qt_tex_cache) {
- QList<qint64> keys = qt_tex_cache->keys();
- for (int i = 0; i < keys.size(); ++i) {
- QGLTexture *tex = qt_tex_cache->object(keys.at(i));
- if (tex->id == id && tex->context == this) {
- tex->clean = true; // forces a glDeleteTextures() call
- qt_tex_cache->remove(keys.at(i));
- return;
- }
- }
- }
+ Q_D(QGLContext);
+
+ if (QGLTextureCache::instance()->remove(this, id))
+ return;
// check the DDS cache if the texture wasn't found in the pixmap/image
// cache
- QList<QString> ddsKeys = qgl_dds_cache()->keys();
+ QGLDDSCache *dds_cache = &(d->group->m_dds_cache);
+ QList<QString> ddsKeys = dds_cache->keys();
for (int i = 0; i < ddsKeys.size(); ++i) {
- GLuint texture = qgl_dds_cache()->value(ddsKeys.at(i));
+ GLuint texture = dds_cache->value(ddsKeys.at(i));
if (id == texture) {
glDeleteTextures(1, &texture);
- qgl_dds_cache()->remove(ddsKeys.at(i));
+ dds_cache->remove(ddsKeys.at(i));
return;
}
}
@@ -2046,12 +2546,36 @@ void QGLContext::deleteTexture(QMacCompatGLuint id)
}
#endif
-// qpaintengine_opengl.cpp
+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);
+}
+
+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);
+}
+
#if !defined(QT_OPENGL_ES_2)
-extern void qt_add_rect_to_array(const QRectF &r, q_vertexType *array);
-#else
-void qt_add_rect_to_array(const QRectF &r, q_vertexType *array) {};
-#endif
static void qDrawTextureRect(const QRectF &target, GLint textureWidth, GLint textureHeight, GLenum textureTarget)
{
@@ -2081,7 +2605,6 @@ static void qDrawTextureRect(const QRectF &target, GLint textureWidth, GLint tex
q_vertexType vertexArray[4*2];
qt_add_rect_to_array(target, vertexArray);
-#if !defined(QT_OPENGL_ES_2)
glVertexPointer(2, q_vertexTypeEnum, 0, vertexArray);
glTexCoordPointer(2, q_vertexTypeEnum, 0, texCoordArray);
@@ -2091,9 +2614,10 @@ static void qDrawTextureRect(const QRectF &target, GLint textureWidth, GLint tex
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-#endif
}
+#endif // !QT_OPENGL_ES_2
+
/*!
\since 4.4
@@ -2101,10 +2625,11 @@ static void qDrawTextureRect(const QRectF &target, GLint textureWidth, GLint tex
\a target, in OpenGL model space. The \a textureTarget should be a 2D
texture target.
- Equivalent to the corresponding QGLContext::drawTexture().
+ \note This function is not supported under OpenGL/ES 2.0.
*/
void QGLContext::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
{
+#ifndef QT_OPENGL_ES_2
#ifdef QT_OPENGL_ES
if (textureTarget != GL_TEXTURE_2D) {
qWarning("QGLContext::drawTexture(): texture target must be GL_TEXTURE_2D on OpenGL ES");
@@ -2128,6 +2653,12 @@ void QGLContext::drawTexture(const QRectF &target, GLuint textureId, GLenum text
glDisable(textureTarget);
glBindTexture(textureTarget, oldTexture);
#endif
+#else
+ Q_UNUSED(target);
+ Q_UNUSED(textureId);
+ Q_UNUSED(textureTarget);
+ qWarning("drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget) not supported with OpenGL ES/2.0");
+#endif
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
@@ -2144,7 +2675,7 @@ void QGLContext::drawTexture(const QRectF &target, QMacCompatGLuint textureId, Q
Draws the given texture at the given \a point in OpenGL model
space. The \a textureTarget should be a 2D texture target.
- Equivalent to the corresponding QGLContext::drawTexture().
+ \note This function is not supported under OpenGL/ES.
*/
void QGLContext::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
{
@@ -2195,9 +2726,7 @@ void QGLContext::drawTexture(const QPointF &point, QMacCompatGLuint textureId, Q
*/
void QGLContext::setTextureCacheLimit(int size)
{
- qt_tex_cache_limit = size;
- if (qt_tex_cache)
- qt_tex_cache->setMaxCost(qt_tex_cache_limit);
+ QGLTextureCache::instance()->setMaxCost(size);
}
/*!
@@ -2207,7 +2736,7 @@ void QGLContext::setTextureCacheLimit(int size)
*/
int QGLContext::textureCacheLimit()
{
- return qt_tex_cache_limit;
+ return QGLTextureCache::instance()->maxCost();
}
@@ -2288,6 +2817,20 @@ void QGLContext::setDevice(QPaintDevice *pDev)
*/
/*!
+ Returns true if \a context1 and \a context2 are sharing their
+ GL resources such as textures, shader programs, etc;
+ otherwise returns false.
+
+ \since 4.6
+*/
+bool QGLContext::areSharing(const QGLContext *context1, const QGLContext *context2)
+{
+ if (!context1 || !context2)
+ return false;
+ return context1->d_ptr->group == context2->d_ptr->group;
+}
+
+/*!
\fn bool QGLContext::deviceIsPixmap() const
Returns true if the paint device of this context is a pixmap;
@@ -2430,7 +2973,7 @@ void QGLContext::setValid(bool valid)
bool QGLContext::isSharing() const
{
Q_D(const QGLContext);
- return d->sharing;
+ return d->group->isSharing();
}
QGLFormat QGLContext::format() const
@@ -2485,11 +3028,28 @@ void QGLContext::setInitialized(bool on)
const QGLContext* QGLContext::currentContext()
{
- if (qgl_context_storage.hasLocalData())
- return qgl_context_storage.localData()->context;
+ QGLThreadContext *threadContext = qgl_context_storage.localData();
+ if (threadContext)
+ return threadContext->context;
return 0;
}
+void QGLContextPrivate::setCurrentContext(QGLContext *context)
+{
+ QGLThreadContext *threadContext = qgl_context_storage.localData();
+ if (!threadContext) {
+ if (!QThread::currentThread()) {
+ // We don't have a current QThread, so just set the static.
+ QGLContext::currentCtx = context;
+ return;
+ }
+ threadContext = new QGLThreadContext;
+ qgl_context_storage.setLocalData(threadContext);
+ }
+ threadContext->context = context;
+ QGLContext::currentCtx = context; // XXX: backwards-compat, not thread-safe
+}
+
/*!
\fn bool QGLContext::chooseContext(const QGLContext* shareContext = 0)
@@ -2505,7 +3065,7 @@ const QGLContext* QGLContext::currentContext()
*/
/*! \fn int QGLContext::choosePixelFormat(void* dummyPfd, HDC pdc)
-
+
\bold{Win32 only:} This virtual function chooses a pixel format
that matches the OpenGL \link setFormat() format\endlink.
Reimplement this function in a subclass if you need a custom
@@ -2519,7 +3079,7 @@ const QGLContext* QGLContext::currentContext()
*/
/*! \fn void *QGLContext::chooseVisual()
-
+
\bold{X11 only:} This virtual function tries to find a visual that
matches the format, reducing the demands if the original request
cannot be met.
@@ -2608,8 +3168,8 @@ const QGLContext* QGLContext::currentContext()
\class QGLWidget
\brief The QGLWidget class is a widget for rendering OpenGL graphics.
- \ingroup multimedia
- \mainclass
+ \ingroup painting-3D
+
QGLWidget provides functionality for displaying OpenGL graphics
integrated into a Qt application. It is very simple to use. You
@@ -2650,7 +3210,7 @@ const QGLContext* QGLContext::currentContext()
QGLFormat format\endlink and you can also create widgets with
customized rendering \link QGLContext contexts\endlink.
- You can also share OpenGL display lists between QGLWidgets (see
+ You can also share OpenGL display lists between QGLWidget objects (see
the documentation of the QGLWidget constructors for details).
Note that under Windows, the QGLContext belonging to a QGLWidget
@@ -2932,7 +3492,7 @@ bool QGLWidget::isValid() const
Returns true if this widget's GL context is shared with another GL
context, otherwise false is returned. Context sharing might not be
- possible if the QGLWidgets use different formats.
+ possible if the widgets use different formats.
\sa format()
*/
@@ -3030,7 +3590,7 @@ void QGLWidget::swapBuffers()
resizeGL() or paintGL().
This method will try to keep display list and texture object sharing
- in effect with other QGLWidgets, but changing the format might make
+ in effect with other QGLWidget objects, but changing the format might make
sharing impossible. Use isSharing() to see if sharing is still in
effect.
@@ -3238,21 +3798,34 @@ bool QGLWidget::event(QEvent *e)
glFinish();
doneCurrent();
} else if (e->type() == QEvent::ParentChange) {
- if (d->glcx->d_func()->screen != d->xinfo.screen()) {
+ // if we've reparented a window that has the current context
+ // bound, we need to rebind that context to the new window id
+ if (d->glcx == QGLContext::currentContext())
+ makeCurrent();
+
+ if (d->glcx->d_func()->screen != d->xinfo.screen() || testAttribute(Qt::WA_TranslucentBackground)) {
setContext(new QGLContext(d->glcx->requestedFormat(), this));
// ### recreating the overlay isn't supported atm
}
+ }
+
#if defined(QT_OPENGL_ES)
- // The window may have been re-created during re-parent - if so, the EGL
+ // A re-parent is likely to destroy the X11 window and re-create it. It is important
+ // that we free the EGL surface _before_ the winID changes - otherwise we can leak.
+ if (e->type() == QEvent::ParentAboutToChange)
+ d->glcx->d_func()->destroyEglSurfaceForDevice();
+
+ if ((e->type() == QEvent::ParentChange) || (e->type() == QEvent::WindowStateChange)) {
+ // The window may have been re-created during re-parent or state change - if so, the EGL
// surface will need to be re-created.
d->recreateEglSurface(false);
-#endif
}
+#endif
#elif defined(Q_WS_WIN)
if (e->type() == QEvent::ParentChange) {
QGLContext *newContext = new QGLContext(d->glcx->requestedFormat(), this);
- qgl_share_reg()->replaceShare(d->glcx, newContext);
- setContext(newContext);
+ setContext(newContext, d->glcx);
+
// the overlay needs to be recreated as well
delete d->olcx;
if (isValid() && context()->format().hasOverlay()) {
@@ -3331,7 +3904,7 @@ void QGLWidget::paintEvent(QPaintEvent *)
/*!
Renders the current scene on a pixmap and returns the pixmap.
- You can use this method on both visible and invisible QGLWidgets.
+ You can use this method on both visible and invisible QGLWidget objects.
This method will create a pixmap and a temporary QGLContext to
render on the pixmap. It will then call initializeGL(),
@@ -3453,7 +4026,7 @@ QImage QGLWidget::grabFrameBuffer(bool withAlpha)
glReadPixels(0, 0, w, h, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, res.bits());
const QVector<QColor> pal = QColormap::instance().colormap();
if (pal.size()) {
- res.setNumColors(pal.size());
+ res.setColorCount(pal.size());
for (int i = 0; i < pal.size(); i++)
res.setColor(i, pal.at(i).rgb());
}
@@ -3517,6 +4090,8 @@ void QGLWidget::glDraw()
Calls glColor4 (in RGBA mode) or glIndex (in color-index mode)
with the color \a c. Applies to this widgets GL context.
+ \note This function is not supported on OpenGL/ES 2.0 systems.
+
\sa qglClearColor(), QGLContext::currentContext(), QColor
*/
@@ -3524,7 +4099,7 @@ void QGLWidget::qglColor(const QColor& c) const
{
#if !defined(QT_OPENGL_ES_2)
#ifdef QT_OPENGL_ES
- glColor4f(c.red()/255.0, c.green()/255.0, c.blue()/255.0, c.alpha()/255.0);
+ glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF());
#else
Q_D(const QGLWidget);
const QGLContext *ctx = QGLContext::currentContext();
@@ -3540,6 +4115,8 @@ void QGLWidget::qglColor(const QColor& c) const
glIndexi(ctx->colorIndex(c));
}
#endif //QT_OPENGL_ES
+#else
+ Q_UNUSED(c);
#endif //QT_OPENGL_ES_2
}
@@ -3554,15 +4131,13 @@ void QGLWidget::qglColor(const QColor& c) const
void QGLWidget::qglClearColor(const QColor& c) const
{
#ifdef QT_OPENGL_ES
- glClearColor((GLfloat)c.red() / 255.0, (GLfloat)c.green() / 255.0,
- (GLfloat)c.blue() / 255.0, (GLfloat) c.alpha() / 255.0);
+ glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF());
#else
Q_D(const QGLWidget);
const QGLContext *ctx = QGLContext::currentContext();
if (ctx) {
if (ctx->format().rgba())
- glClearColor((GLfloat)c.red() / 255.0, (GLfloat)c.green() / 255.0,
- (GLfloat)c.blue() / 255.0, (GLfloat) c.alpha() / 255.0);
+ glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF());
else if (!d->cmap.isEmpty()) { // QGLColormap in use?
int i = d->cmap.find(c.rgb());
if (i < 0)
@@ -3633,10 +4208,10 @@ QImage QGLWidget::convertToGLFormat(const QImage& img)
colormaps installed. Asking for the colormap of a child widget
will return the colormap for the child's top-level widget.
- If no colormap has been set for this widget, the QColormap
+ If no colormap has been set for this widget, the QGLColormap
returned will be empty.
- \sa setColormap()
+ \sa setColormap(), QGLColormap::isEmpty()
*/
/*!
@@ -3656,9 +4231,12 @@ QImage QGLWidget::convertToGLFormat(const QImage& img)
the characters in the given \a font. \a listBase indicates the base
value used when generating the display lists for the font. The
default value is 2000.
+
+ \note This function is not supported on OpenGL/ES systems.
*/
int QGLWidget::fontDisplayListBase(const QFont & font, int listBase)
{
+#ifndef QT_OPENGL_ES
Q_D(QGLWidget);
int base;
@@ -3676,9 +4254,7 @@ int QGLWidget::fontDisplayListBase(const QFont & font, int listBase)
QString color_key;
if (font.styleStrategy() != QFont::NoAntialias) {
GLfloat color[4];
-#ifndef QT_OPENGL_ES
glGetFloatv(GL_CURRENT_COLOR, color);
-#endif
color_key.sprintf("%f_%f_%f",color[0], color[1], color[2]);
}
QString key = font.key() + color_key + QString::number((int) regenerate);
@@ -3701,15 +4277,19 @@ int QGLWidget::fontDisplayListBase(const QFont & font, int listBase)
base = maxBase;
}
return base;
+#else // QT_OPENGL_ES
+ Q_UNUSED(font);
+ Q_UNUSED(listBase);
+ return 0;
+#endif
}
+#ifndef QT_OPENGL_ES
+
static void qt_save_gl_state()
{
-#ifndef QT_OPENGL_ES
glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
glPushAttrib(GL_ALL_ATTRIB_BITS);
-#endif
-#if !defined(QT_OPENGL_ES_2)
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glLoadIdentity();
@@ -3722,34 +4302,28 @@ static void qt_save_gl_state()
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);
glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-#endif // !defined(QT_OPENGL_ES_2)
}
static void qt_restore_gl_state()
{
-#if !defined(QT_OPENGL_ES_2)
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
-#endif // !defined(QT_OPENGL_ES_2)
-#ifndef QT_OPENGL_ES
glPopAttrib();
glPopClientAttrib();
-#endif
}
static void qt_gl_draw_text(QPainter *p, int x, int y, const QString &str,
const QFont &font)
{
GLfloat color[4];
-#ifndef QT_OPENGL_ES
glGetFloatv(GL_CURRENT_COLOR, &color[0]);
-#endif
QColor col;
col.setRgbF(color[0], color[1], color[2],color[3]);
@@ -3764,6 +4338,8 @@ static void qt_gl_draw_text(QPainter *p, int x, int y, const QString &str,
p->setFont(old_font);
}
+#endif // !QT_OPENGL_ES
+
/*!
Renders the string \a str into the GL context of this widget.
@@ -3778,27 +4354,33 @@ static void qt_gl_draw_text(QPainter *p, int x, int y, const QString &str,
future version of Qt.
\note This function clears the stencil buffer.
+
+ \note This function is not supported on OpenGL/ES systems.
+
+ \note This function temporarily disables depth-testing when the
+ text is drawn.
+
+ \l{Overpainting Example}{Overpaint} with QPainter::drawText() instead.
*/
void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font, int)
{
+#ifndef QT_OPENGL_ES
Q_D(QGLWidget);
if (str.isEmpty() || !isValid())
return;
GLint view[4];
-#ifndef QT_OPENGL_ES
bool use_scissor_testing = glIsEnabled(GL_SCISSOR_TEST);
if (!use_scissor_testing)
glGetIntegerv(GL_VIEWPORT, &view[0]);
-#else
- bool use_scissor_testing = false;
-#endif
int width = d->glcx->device()->width();
int height = d->glcx->device()->height();
bool auto_swap = autoBufferSwap();
QPaintEngine *engine = paintEngine();
+ if (engine->type() == QPaintEngine::OpenGL2)
+ static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(true);
QPainter *p;
bool reuse_painter = false;
if (engine->isActive()) {
@@ -3806,24 +4388,23 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font,
p = engine->painter();
qt_save_gl_state();
-#if !defined(QT_OPENGL_ES_2)
glDisable(GL_DEPTH_TEST);
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
-#ifndef QT_OPENGL_ES
glOrtho(0, width, height, 0, 0, 1);
-#else
- glOrthof(0, width, height, 0, 0, 1);
-#endif
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
-#endif // !defined(QT_OPENGL_ES_2)
} else {
setAutoBufferSwap(false);
// disable glClear() as a result of QPainter::begin()
- d->glcx->d_func()->clear_on_painter_begin = false;
+ d->disable_clear_on_painter_begin = true;
+ if (engine->type() == QPaintEngine::OpenGL2) {
+ qt_save_gl_state();
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ }
p = new QPainter(this);
}
@@ -3846,8 +4427,19 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font,
p->end();
delete p;
setAutoBufferSwap(auto_swap);
- d->glcx->d_func()->clear_on_painter_begin = true;
+ d->disable_clear_on_painter_begin = false;
+ if (engine->type() == QPaintEngine::OpenGL2)
+ qt_restore_gl_state();
}
+ if (engine->type() == QPaintEngine::OpenGL2)
+ static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(false);
+#else // QT_OPENGL_ES
+ Q_UNUSED(x);
+ Q_UNUSED(y);
+ Q_UNUSED(str);
+ Q_UNUSED(font);
+ qWarning("QGLWidget::renderText is not supported under OpenGL/ES");
+#endif
}
/*! \overload
@@ -3856,9 +4448,20 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font,
relative to the currently set projection and model matrices. This
can be useful if you want to annotate models with text labels and
have the labels move with the model as it is rotated etc.
+
+ \note This function is not supported on OpenGL/ES systems.
+
+ \note If depth testing is enabled before this function is called,
+ then the drawn text will be depth-tested against the models that
+ have already been drawn in the scene. Use \c{glDisable(GL_DEPTH_TEST)}
+ before calling this function to annotate the models without
+ depth-testing the text.
+
+ \l{Overpainting Example}{Overpaint} with QPainter::drawText() instead.
*/
void QGLWidget::renderText(double x, double y, double z, const QString &str, const QFont &font, int)
{
+#ifndef QT_OPENGL_ES
Q_D(QGLWidget);
if (str.isEmpty() || !isValid())
return;
@@ -3869,26 +4472,21 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con
int height = d->glcx->device()->height();
GLdouble model[4][4], proj[4][4];
GLint view[4];
-#ifndef QT_OPENGL_ES
glGetDoublev(GL_MODELVIEW_MATRIX, &model[0][0]);
glGetDoublev(GL_PROJECTION_MATRIX, &proj[0][0]);
glGetIntegerv(GL_VIEWPORT, &view[0]);
-#endif
GLdouble win_x = 0, win_y = 0, win_z = 0;
qgluProject(x, y, z, &model[0][0], &proj[0][0], &view[0],
&win_x, &win_y, &win_z);
win_y = height - win_y; // y is inverted
QPaintEngine *engine = paintEngine();
+ if (engine->type() == QPaintEngine::OpenGL2)
+ static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(true);
QPainter *p;
bool reuse_painter = false;
-#ifndef QT_OPENGL_ES
bool use_depth_testing = glIsEnabled(GL_DEPTH_TEST);
bool use_scissor_testing = glIsEnabled(GL_SCISSOR_TEST);
-#else
- bool use_depth_testing = false;
- bool use_scissor_testing = false;
-#endif
if (engine->isActive()) {
reuse_painter = true;
@@ -3897,7 +4495,9 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con
} else {
setAutoBufferSwap(false);
// disable glClear() as a result of QPainter::begin()
- d->glcx->d_func()->clear_on_painter_begin = false;
+ d->disable_clear_on_painter_begin = true;
+ if (engine->type() == QPaintEngine::OpenGL2)
+ qt_save_gl_state();
p = new QPainter(this);
}
@@ -3908,27 +4508,17 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con
} else if (use_scissor_testing) {
glEnable(GL_SCISSOR_TEST);
}
-#if !defined(QT_OPENGL_ES_2)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, width, height);
-#ifndef QT_OPENGL_ES
glOrtho(0, width, height, 0, 0, 1);
-#else
- glOrthof(0, width, height, 0, 0, 1);
-#endif
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glAlphaFunc(GL_GREATER, 0.0);
glEnable(GL_ALPHA_TEST);
if (use_depth_testing)
glEnable(GL_DEPTH_TEST);
-#ifndef QT_OPENGL_ES
glTranslated(0, 0, -win_z);
-#else
- glTranslatef(0, 0, -win_z);
-#endif
-#endif // !defined(QT_OPENGL_ES_2)
qt_gl_draw_text(p, qRound(win_x), qRound(win_y), str, font);
if (reuse_painter) {
@@ -3936,9 +4526,21 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con
} else {
p->end();
delete p;
+ if (engine->type() == QPaintEngine::OpenGL2)
+ qt_restore_gl_state();
setAutoBufferSwap(auto_swap);
- d->glcx->d_func()->clear_on_painter_begin = true;
+ d->disable_clear_on_painter_begin = false;
}
+ if (engine->type() == QPaintEngine::OpenGL2)
+ static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(false);
+#else // QT_OPENGL_ES
+ Q_UNUSED(x);
+ Q_UNUSED(y);
+ Q_UNUSED(z);
+ Q_UNUSED(str);
+ Q_UNUSED(font);
+ qWarning("QGLWidget::renderText is not supported under OpenGL/ES");
+#endif
}
QGLFormat QGLWidget::format() const
@@ -3979,16 +4581,49 @@ bool QGLWidget::autoBufferSwap() const
*/
GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format)
{
+ if (image.isNull())
+ return 0;
+
+ Q_D(QGLWidget);
+ return d->glcx->bindTexture(image, target, format, QGLContext::DefaultBindOption);
+}
+
+/*!
+ \overload
+ \since 4.6
+
+ The binding \a options are a set of options used to decide how to
+ bind the texture to the context.
+ */
+GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format, QGLContext::BindOptions options)
+{
+ if (image.isNull())
+ return 0;
+
Q_D(QGLWidget);
- return d->glcx->bindTexture(image, target, format);
+ return d->glcx->bindTexture(image, target, format, options);
}
+
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
/*! \internal */
GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format)
{
+ if (image.isNull())
+ return 0;
+
Q_D(QGLWidget);
- return d->glcx->bindTexture(image, GLenum(target), GLint(format));
+ return d->glcx->bindTexture(image, GLenum(target), GLint(format), QGLContext::DefaultBindOption);
+}
+
+GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format,
+ QGLContext::BindOptions options)
+{
+ if (image.isNull())
+ return 0;
+
+ Q_D(QGLWidget);
+ return d->glcx->bindTexture(image, GLenum(target), GLint(format), options);
}
#endif
@@ -4000,8 +4635,28 @@ GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMac
*/
GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
{
+ if (pixmap.isNull())
+ return 0;
+
+ Q_D(QGLWidget);
+ return d->glcx->bindTexture(pixmap, target, format, QGLContext::DefaultBindOption);
+}
+
+/*!
+ \overload
+ \since 4.6
+
+ Generates and binds a 2D GL texture to the current context, based
+ on \a pixmap. The generated texture id is returned and can be used in
+
+ The binding \a options are a set of options used to decide how to
+ bind the texture to the context.
+ */
+GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format,
+ QGLContext::BindOptions options)
+{
Q_D(QGLWidget);
- return d->glcx->bindTexture(pixmap, target, format);
+ return d->glcx->bindTexture(pixmap, target, format, options);
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
@@ -4009,7 +4664,14 @@ GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format
GLuint QGLWidget::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format)
{
Q_D(QGLWidget);
- return d->glcx->bindTexture(pixmap, target, format);
+ return d->glcx->bindTexture(pixmap, target, format, QGLContext::DefaultBindOption);
+}
+
+GLuint QGLWidget::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format,
+ QGLContext::BindOptions options)
+{
+ Q_D(QGLWidget);
+ return d->glcx->bindTexture(pixmap, target, format, options);
}
#endif
@@ -4094,22 +4756,27 @@ void QGLWidget::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QM
}
#endif
-#if defined(QT_OPENGL_ES_2)
-Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_engine)
-#else
+#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
+Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_2_engine)
+#endif
+
+#ifndef QT_OPENGL_ES_2
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)
+#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL)
return qt_gl_engine();
+#elif defined(QT_OPENGL_ES_2)
+ return qt_gl_2_engine();
#else
- return 0; // XXX
+ if (qt_gl_preferGL2Engine())
+ return qt_gl_2_engine();
+ else
+ return qt_gl_engine();
#endif
}
-#endif
/*!
\internal
@@ -4119,7 +4786,7 @@ Q_OPENGL_EXPORT QOpenGLPaintEngine* qt_qgl_paint_engine()
*/
QPaintEngine *QGLWidget::paintEngine() const
{
- return qt_gl_engine();
+ return qt_qgl_paint_engine();
}
#ifdef QT3_SUPPORT
@@ -4179,40 +4846,67 @@ QGLWidget::QGLWidget(QGLContext *context, QWidget *parent,
void QGLExtensions::init_extensions()
{
- QString extensions = QLatin1String(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
- if (extensions.contains(QLatin1String("texture_rectangle")))
+ QGLExtensionMatcher extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
+
+ if (extensions.match("GL_ARB_texture_rectangle"))
glExtensions |= TextureRectangle;
- if (extensions.contains(QLatin1String("multisample")))
+ if (extensions.match("GL_ARB_multisample"))
glExtensions |= SampleBuffers;
- if (extensions.contains(QLatin1String("generate_mipmap")))
+ if (extensions.match("GL_SGIS_generate_mipmap"))
glExtensions |= GenerateMipmap;
- if (extensions.contains(QLatin1String("texture_compression_s3tc")))
+ if (extensions.match("GL_ARB_texture_compression"))
glExtensions |= TextureCompression;
- if (extensions.contains(QLatin1String("ARB_fragment_program")))
+ if (extensions.match("GL_EXT_texture_compression_s3tc"))
+ glExtensions |= DDSTextureCompression;
+ if (extensions.match("GL_OES_compressed_ETC1_RGB8_texture"))
+ glExtensions |= ETC1TextureCompression;
+ if (extensions.match("GL_IMG_texture_compression_pvrtc"))
+ glExtensions |= PVRTCTextureCompression;
+ if (extensions.match("GL_ARB_fragment_program"))
glExtensions |= FragmentProgram;
- if (extensions.contains(QLatin1String("mirrored_repeat")))
+ if (extensions.match("GL_ARB_fragment_shader"))
+ glExtensions |= FragmentShader;
+ if (extensions.match("GL_ARB_texture_mirrored_repeat"))
glExtensions |= MirroredRepeat;
- if (extensions.contains(QLatin1String("EXT_framebuffer_object")))
+ if (extensions.match("GL_EXT_framebuffer_object"))
glExtensions |= FramebufferObject;
- if (extensions.contains(QLatin1String("EXT_stencil_two_side")))
+ if (extensions.match("GL_EXT_stencil_two_side"))
glExtensions |= StencilTwoSide;
- if (extensions.contains(QLatin1String("EXT_stencil_wrap")))
+ if (extensions.match("GL_EXT_stencil_wrap"))
glExtensions |= StencilWrap;
- if (extensions.contains(QLatin1String("EXT_packed_depth_stencil")))
+ if (extensions.match("GL_EXT_packed_depth_stencil"))
glExtensions |= PackedDepthStencil;
- if (extensions.contains(QLatin1String("GL_NV_float_buffer")))
+ if (extensions.match("GL_NV_float_buffer"))
glExtensions |= NVFloatBuffer;
- if (extensions.contains(QLatin1String("ARB_pixel_buffer_object")))
+ if (extensions.match("GL_ARB_pixel_buffer_object"))
glExtensions |= PixelBufferObject;
#if defined(QT_OPENGL_ES_2)
glExtensions |= FramebufferObject;
glExtensions |= GenerateMipmap;
+ glExtensions |= FragmentShader;
#endif
-
- QGLContext cx(QGLFormat::defaultFormat());
- if (glExtensions & TextureCompression) {
- qt_glCompressedTexImage2DARB = (pfn_glCompressedTexImage2DARB) cx.getProcAddress(QLatin1String("glCompressedTexImage2DARB"));
+#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL)
+ if (extensions.match("GL_OES_framebuffer_object"))
+ glExtensions |= FramebufferObject;
+#endif
+#if defined(QT_OPENGL_ES)
+ if (extensions.match("GL_OES_packed_depth_stencil"))
+ glExtensions |= PackedDepthStencil;
+#endif
+ if (extensions.match("GL_ARB_framebuffer_object")) {
+ // ARB_framebuffer_object also includes EXT_framebuffer_blit.
+ glExtensions |= FramebufferObject;
+ glExtensions |= FramebufferBlit;
}
+
+ if (extensions.match("GL_EXT_framebuffer_blit"))
+ glExtensions |= FramebufferBlit;
+
+ if (extensions.match("GL_ARB_texture_non_power_of_two"))
+ glExtensions |= NPOTTextures;
+
+ if (extensions.match("GL_EXT_bgra"))
+ glExtensions |= BGRATextureFormat;
}
/*
@@ -4222,6 +4916,8 @@ void QGLWidgetPrivate::initContext(QGLContext *context, const QGLWidget* shareWi
{
Q_Q(QGLWidget);
+ glDevice.setWidget(q);
+
QGLExtensions::init();
glcx = 0;
autoSwap = true;
@@ -4237,7 +4933,7 @@ void QGLWidgetPrivate::initContext(QGLContext *context, const QGLWidget* shareWi
}
#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
-Q_GLOBAL_STATIC(QString, qt_gl_lib_name);
+Q_GLOBAL_STATIC(QString, qt_gl_lib_name)
Q_OPENGL_EXPORT void qt_set_gl_library_name(const QString& name)
{
@@ -4248,7 +4944,7 @@ Q_OPENGL_EXPORT const QString qt_gl_library_name()
{
if (qt_gl_lib_name()->isNull()) {
#if defined(Q_WS_X11) || defined(Q_WS_QWS)
- return QString(QLatin1String("GL"));
+ return QLatin1String("GL");
#else // Q_WS_MAC
return QLatin1String("/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib");
#endif
@@ -4257,4 +4953,450 @@ Q_OPENGL_EXPORT const QString qt_gl_library_name()
}
#endif
+void QGLShareRegister::addShare(const QGLContext *context, const QGLContext *share) {
+ Q_ASSERT(context && share);
+ if (context->d_ptr->group == share->d_ptr->group)
+ return;
+
+ // Make sure 'context' is not already shared with another group of contexts.
+ Q_ASSERT(context->d_ptr->group->m_refs == 1);
+
+ // Free 'context' group resources and make it use the same resources as 'share'.
+ QGLContextGroup *group = share->d_ptr->group;
+ delete context->d_ptr->group;
+ context->d_ptr->group = group;
+ group->m_refs.ref();
+
+ // Maintain a list of all the contexts in each group of sharing contexts.
+ // The list is empty if the "share" context wasn't sharing already.
+ if (group->m_shares.isEmpty())
+ group->m_shares.append(share);
+ group->m_shares.append(context);
+}
+
+QList<const QGLContext *> QGLShareRegister::shares(const QGLContext *context) {
+ return context->d_ptr->group->m_shares;
+}
+
+void QGLShareRegister::removeShare(const QGLContext *context) {
+ // Remove the context from the group.
+ QGLContextGroup *group = context->d_ptr->group;
+ if (group->m_shares.isEmpty())
+ return;
+ group->m_shares.removeAll(context);
+
+ // Update context group representative.
+ Q_ASSERT(group->m_shares.size() != 0);
+ if (group->m_context == context)
+ group->m_context = group->m_shares[0];
+
+ // If there is only one context left, then make the list empty.
+ if (group->m_shares.size() == 1)
+ group->m_shares.clear();
+}
+
+QGLContextResource::QGLContextResource(FreeFunc f)
+ : free(f), active(0)
+{
+}
+
+QGLContextResource::~QGLContextResource()
+{
+#ifndef QT_NO_DEBUG
+ if (active != 0) {
+ qWarning("QtOpenGL: Resources are still available at program shutdown.\n"
+ " This is possibly caused by a leaked QGLWidget, \n"
+ " QGLFramebufferObject or QGLPixelBuffer.");
+ }
+#endif
+}
+
+void QGLContextResource::insert(const QGLContext *key, void *value)
+{
+ QGLContextGroup *group = QGLContextPrivate::contextGroup(key);
+ Q_ASSERT(!group->m_resources.contains(this));
+ group->m_resources.insert(this, value);
+ active.ref();
+}
+
+void *QGLContextResource::value(const QGLContext *key)
+{
+ QGLContextGroup *group = QGLContextPrivate::contextGroup(key);
+ return group->m_resources.value(this, 0);
+}
+
+void QGLContextResource::cleanup(const QGLContext *ctx, void *value)
+{
+ QGLShareContextScope scope(ctx);
+ free(value);
+ active.deref();
+}
+
+void QGLContextGroup::cleanupResources(const QGLContext *ctx)
+{
+ // If there are still shares, then no cleanup to be done yet.
+ if (m_shares.size() > 1)
+ return;
+
+ // Iterate over all resources and free each in turn.
+ QHash<QGLContextResource *, void *>::ConstIterator it;
+ for (it = m_resources.begin(); it != m_resources.end(); ++it)
+ it.key()->cleanup(ctx, it.value());
+}
+
+QGLSharedResourceGuard::~QGLSharedResourceGuard()
+{
+ if (m_group)
+ m_group->removeGuard(this);
+}
+
+void QGLSharedResourceGuard::setContext(const QGLContext *context)
+{
+ if (m_group)
+ m_group->removeGuard(this);
+ if (context) {
+ m_group = QGLContextPrivate::contextGroup(context);
+ m_group->addGuard(this);
+ } else {
+ m_group = 0;
+ }
+}
+
+QSize QGLTexture::bindCompressedTexture
+ (const QString& fileName, const char *format)
+{
+ QFile file(fileName);
+ if (!file.open(QIODevice::ReadOnly))
+ return QSize();
+ QByteArray contents = file.readAll();
+ file.close();
+ return bindCompressedTexture
+ (contents.constData(), contents.size(), format);
+}
+
+// PVR header format for container files that store textures compressed
+// with the ETC1, PVRTC2, and PVRTC4 encodings. Format information from the
+// PowerVR SDK at http://www.imgtec.com/powervr/insider/powervr-sdk.asp
+// "PVRTexTool Reference Manual, version 1.11f".
+struct PvrHeader
+{
+ quint32 headerSize;
+ quint32 height;
+ quint32 width;
+ quint32 mipMapCount;
+ quint32 flags;
+ quint32 dataSize;
+ quint32 bitsPerPixel;
+ quint32 redMask;
+ quint32 greenMask;
+ quint32 blueMask;
+ quint32 alphaMask;
+ quint32 magic;
+ quint32 surfaceCount;
+};
+
+#define PVR_MAGIC 0x21525650 // "PVR!" in little-endian
+
+#define PVR_FORMAT_MASK 0x000000FF
+#define PVR_FORMAT_PVRTC2 0x00000018
+#define PVR_FORMAT_PVRTC4 0x00000019
+#define PVR_FORMAT_ETC1 0x00000036
+
+#define PVR_HAS_MIPMAPS 0x00000100
+#define PVR_TWIDDLED 0x00000200
+#define PVR_NORMAL_MAP 0x00000400
+#define PVR_BORDER_ADDED 0x00000800
+#define PVR_CUBE_MAP 0x00001000
+#define PVR_FALSE_COLOR_MIPMAPS 0x00002000
+#define PVR_VOLUME_TEXTURE 0x00004000
+#define PVR_ALPHA_IN_TEXTURE 0x00008000
+#define PVR_VERTICAL_FLIP 0x00010000
+
+#ifndef GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG
+#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
+#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
+#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
+#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
+#endif
+
+#ifndef GL_ETC1_RGB8_OES
+#define GL_ETC1_RGB8_OES 0x8D64
+#endif
+
+bool QGLTexture::canBindCompressedTexture
+ (const char *buf, int len, const char *format, bool *hasAlpha)
+{
+ if (QSysInfo::ByteOrder != QSysInfo::LittleEndian) {
+ // Compressed texture loading only supported on little-endian
+ // systems such as x86 and ARM at the moment.
+ return false;
+ }
+ if (!format) {
+ // Auto-detect the format from the header.
+ if (len >= 4 && !qstrncmp(buf, "DDS ", 4)) {
+ *hasAlpha = true;
+ return true;
+ } else if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4)) {
+ const PvrHeader *pvrHeader =
+ reinterpret_cast<const PvrHeader *>(buf);
+ *hasAlpha = (pvrHeader->alphaMask != 0);
+ return true;
+ }
+ } else {
+ // Validate the format against the header.
+ if (!qstricmp(format, "DDS")) {
+ if (len >= 4 && !qstrncmp(buf, "DDS ", 4)) {
+ *hasAlpha = true;
+ return true;
+ }
+ } else if (!qstricmp(format, "PVR") || !qstricmp(format, "ETC1")) {
+ if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4)) {
+ const PvrHeader *pvrHeader =
+ reinterpret_cast<const PvrHeader *>(buf);
+ *hasAlpha = (pvrHeader->alphaMask != 0);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+#define ctx QGLContext::currentContext()
+
+QSize QGLTexture::bindCompressedTexture
+ (const char *buf, int len, const char *format)
+{
+ if (QSysInfo::ByteOrder != QSysInfo::LittleEndian) {
+ // Compressed texture loading only supported on little-endian
+ // systems such as x86 and ARM at the moment.
+ return QSize();
+ }
+#if !defined(QT_OPENGL_ES)
+ if (!glCompressedTexImage2D) {
+ if (!(QGLExtensions::glExtensions & QGLExtensions::TextureCompression)) {
+ qWarning("QGLContext::bindTexture(): The GL implementation does "
+ "not support texture compression extensions.");
+ return QSize();
+ }
+ glCompressedTexImage2D = (_glCompressedTexImage2DARB) ctx->getProcAddress(QLatin1String("glCompressedTexImage2DARB"));
+ if (!glCompressedTexImage2D) {
+ qWarning("QGLContext::bindTexture(): could not resolve "
+ "glCompressedTexImage2DARB.");
+ return QSize();
+ }
+ }
+#endif
+ if (!format) {
+ // Auto-detect the format from the header.
+ if (len >= 4 && !qstrncmp(buf, "DDS ", 4))
+ return bindCompressedTextureDDS(buf, len);
+ else if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4))
+ return bindCompressedTexturePVR(buf, len);
+ } else {
+ // Validate the format against the header.
+ if (!qstricmp(format, "DDS")) {
+ if (len >= 4 && !qstrncmp(buf, "DDS ", 4))
+ return bindCompressedTextureDDS(buf, len);
+ } else if (!qstricmp(format, "PVR") || !qstricmp(format, "ETC1")) {
+ if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4))
+ return bindCompressedTexturePVR(buf, len);
+ }
+ }
+ return QSize();
+}
+
+QSize QGLTexture::bindCompressedTextureDDS(const char *buf, int len)
+{
+ // We only support 2D texture loading at present.
+ if (target != GL_TEXTURE_2D)
+ return QSize();
+
+ // Bail out if the necessary extension is not present.
+ if (!(QGLExtensions::glExtensions & QGLExtensions::DDSTextureCompression)) {
+ qWarning("QGLContext::bindTexture(): DDS texture compression is not supported.");
+ return QSize();
+ }
+
+ const DDSFormat *ddsHeader = reinterpret_cast<const DDSFormat *>(buf + 4);
+ if (!ddsHeader->dwLinearSize) {
+ qWarning("QGLContext::bindTexture(): DDS image size is not valid.");
+ return QSize();
+ }
+
+ int blockSize = 16;
+ GLenum format;
+
+ switch(ddsHeader->ddsPixelFormat.dwFourCC) {
+ case FOURCC_DXT1:
+ format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ blockSize = 8;
+ break;
+ case FOURCC_DXT3:
+ format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+ break;
+ case FOURCC_DXT5:
+ format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ break;
+ default:
+ qWarning("QGLContext::bindTexture(): DDS image format not supported.");
+ return QSize();
+ }
+
+ const GLubyte *pixels =
+ reinterpret_cast<const GLubyte *>(buf + ddsHeader->dwSize + 4);
+
+ glGenTextures(1, &id);
+ glBindTexture(GL_TEXTURE_2D, id);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+ int size;
+ int offset = 0;
+ int available = len - int(ddsHeader->dwSize + 4);
+ int w = ddsHeader->dwWidth;
+ int h = ddsHeader->dwHeight;
+
+ // load mip-maps
+ for(int i = 0; i < (int) ddsHeader->dwMipMapCount; ++i) {
+ if (w == 0) w = 1;
+ if (h == 0) h = 1;
+
+ size = ((w+3)/4) * ((h+3)/4) * blockSize;
+ if (size > available)
+ break;
+ glCompressedTexImage2D(GL_TEXTURE_2D, i, format, w, h, 0,
+ size, pixels + offset);
+ offset += size;
+ available -= size;
+
+ // half size for each mip-map level
+ w = w/2;
+ h = h/2;
+ }
+
+ // DDS images are not inverted.
+ options &= ~QGLContext::InvertedYBindOption;
+
+ return QSize(ddsHeader->dwWidth, ddsHeader->dwHeight);
+}
+
+QSize QGLTexture::bindCompressedTexturePVR(const char *buf, int len)
+{
+ // We only support 2D texture loading at present. Cube maps later.
+ if (target != GL_TEXTURE_2D)
+ return QSize();
+
+ // Determine which texture format we will be loading.
+ const PvrHeader *pvrHeader = reinterpret_cast<const PvrHeader *>(buf);
+ GLenum textureFormat;
+ quint32 minWidth, minHeight;
+ switch (pvrHeader->flags & PVR_FORMAT_MASK) {
+ case PVR_FORMAT_PVRTC2:
+ if (pvrHeader->alphaMask)
+ textureFormat = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
+ else
+ textureFormat = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
+ minWidth = 16;
+ minHeight = 8;
+ break;
+
+ case PVR_FORMAT_PVRTC4:
+ if (pvrHeader->alphaMask)
+ textureFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
+ else
+ textureFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
+ minWidth = 8;
+ minHeight = 8;
+ break;
+
+ case PVR_FORMAT_ETC1:
+ textureFormat = GL_ETC1_RGB8_OES;
+ minWidth = 4;
+ minHeight = 4;
+ break;
+
+ default:
+ qWarning("QGLContext::bindTexture(): PVR image format 0x%x not supported.", int(pvrHeader->flags & PVR_FORMAT_MASK));
+ return QSize();
+ }
+
+ // Bail out if the necessary extension is not present.
+ if (textureFormat == GL_ETC1_RGB8_OES) {
+ if (!(QGLExtensions::glExtensions &
+ QGLExtensions::ETC1TextureCompression)) {
+ qWarning("QGLContext::bindTexture(): ETC1 texture compression is not supported.");
+ return QSize();
+ }
+ } else {
+ if (!(QGLExtensions::glExtensions &
+ QGLExtensions::PVRTCTextureCompression)) {
+ qWarning("QGLContext::bindTexture(): PVRTC texture compression is not supported.");
+ return QSize();
+ }
+ }
+
+ // Boundary check on the buffer size.
+ quint32 bufferSize = pvrHeader->headerSize + pvrHeader->dataSize;
+ if (bufferSize > quint32(len)) {
+ qWarning("QGLContext::bindTexture(): PVR image size is not valid.");
+ return QSize();
+ }
+
+ // Create the texture.
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glGenTextures(1, &id);
+ glBindTexture(GL_TEXTURE_2D, id);
+ if (pvrHeader->mipMapCount) {
+ if ((options & QGLContext::LinearFilteringBindOption) != 0) {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ } else {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+ }
+ } else if ((options & QGLContext::LinearFilteringBindOption) != 0) {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ } else {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
+
+ // Load the compressed mipmap levels.
+ const GLubyte *buffer =
+ reinterpret_cast<const GLubyte *>(buf + pvrHeader->headerSize);
+ bufferSize = pvrHeader->dataSize;
+ quint32 level = 0;
+ quint32 width = pvrHeader->width;
+ quint32 height = pvrHeader->height;
+ while (bufferSize > 0 && level < pvrHeader->mipMapCount) {
+ quint32 size =
+ (qMax(width, minWidth) * qMax(height, minHeight) *
+ pvrHeader->bitsPerPixel) / 8;
+ if (size > bufferSize)
+ break;
+ glCompressedTexImage2D(GL_TEXTURE_2D, GLint(level), textureFormat,
+ GLsizei(width), GLsizei(height), 0,
+ GLsizei(size), buffer);
+ width /= 2;
+ height /= 2;
+ buffer += size;
+ ++level;
+ }
+
+ // Restore the default pixel alignment for later texture uploads.
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+
+ // Set the invert flag for the texture. The "vertical flip"
+ // flag in PVR is the opposite sense to our sense of inversion.
+ if ((pvrHeader->flags & PVR_VERTICAL_FLIP) != 0)
+ options &= ~QGLContext::InvertedYBindOption;
+ else
+ options |= QGLContext::InvertedYBindOption;
+
+ return QSize(pvrHeader->width, pvrHeader->height);
+}
+
+#undef ctx
+
QT_END_NAMESPACE
diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h
index c5ddfe8..2076c46 100644
--- a/src/opengl/qgl.h
+++ b/src/opengl/qgl.h
@@ -43,8 +43,10 @@
#define QGL_H
#include <QtGui/qwidget.h>
+#include <QtGui/qpaintengine.h>
#include <QtOpenGL/qglcolormap.h>
#include <QtCore/qmap.h>
+#include <QtCore/qscopedpointer.h>
QT_BEGIN_HEADER
@@ -129,6 +131,8 @@ class QGLContextPrivate;
// Namespace class:
namespace QGL
{
+ Q_OPENGL_EXPORT void setPreferredPaintEngine(QPaintEngine::Type engineType);
+
enum FormatOption {
DoubleBuffer = 0x0001,
DepthBuffer = 0x0002,
@@ -254,6 +258,8 @@ public:
private:
QGLFormatPrivate *d;
+ void detach();
+
friend Q_OPENGL_EXPORT bool operator==(const QGLFormat&, const QGLFormat&);
friend Q_OPENGL_EXPORT bool operator!=(const QGLFormat&, const QGLFormat&);
};
@@ -276,7 +282,8 @@ public:
bool isSharing() const;
void reset();
- // ### Qt 5: make format() return a const ref instead
+ static bool areSharing(const QGLContext *context1, const QGLContext *context2);
+
QGLFormat format() const;
QGLFormat requestedFormat() const;
void setFormat(const QGLFormat& format);
@@ -287,6 +294,29 @@ public:
virtual void swapBuffers() const;
+ enum BindOption {
+ NoBindOption = 0x0000,
+ InvertedYBindOption = 0x0001,
+ MipmapBindOption = 0x0002,
+ PremultipliedAlphaBindOption = 0x0004,
+ LinearFilteringBindOption = 0x0008,
+
+ MemoryManagedBindOption = 0x0010, // internal flag
+ CanFlipNativePixmapBindOption = 0x0020, // internal flag
+
+ DefaultBindOption = LinearFilteringBindOption
+ | InvertedYBindOption
+ | MipmapBindOption,
+ InternalBindOption = MemoryManagedBindOption
+ | PremultipliedAlphaBindOption
+ };
+ Q_DECLARE_FLAGS(BindOptions, BindOption)
+
+ GLuint bindTexture(const QImage &image, GLenum target, GLint format,
+ BindOptions options);
+ GLuint bindTexture(const QPixmap &pixmap, GLenum target, GLint format,
+ BindOptions options);
+
GLuint bindTexture(const QImage &image, GLenum target = GL_TEXTURE_2D,
GLint format = GL_RGBA);
GLuint bindTexture(const QPixmap &pixmap, GLenum target = GL_TEXTURE_2D,
@@ -303,6 +333,10 @@ public:
QMacCompatGLint format = GL_RGBA);
GLuint bindTexture(const QPixmap &pixmap, QMacCompatGLenum = GL_TEXTURE_2D,
QMacCompatGLint format = GL_RGBA);
+ GLuint bindTexture(const QImage &image, QMacCompatGLenum, QMacCompatGLint format,
+ BindOptions);
+ GLuint bindTexture(const QPixmap &pixmap, QMacCompatGLenum, QMacCompatGLint format,
+ BindOptions);
void deleteTexture(QMacCompatGLuint tx_id);
@@ -348,12 +382,11 @@ protected:
static QGLContext* currentCtx;
private:
- QGLContextPrivate* d_ptr;
+ QScopedPointer<QGLContextPrivate> d_ptr;
friend class QGLPixelBuffer;
friend class QGLPixelBufferPrivate;
friend class QGLWidget;
- friend class QGLDrawable;
friend class QGLWidgetPrivate;
friend class QGLGlyphCache;
friend class QOpenGLPaintEngine;
@@ -363,6 +396,10 @@ private:
friend class QGLWindowSurface;
friend class QGLPixmapData;
friend class QGLPixmapFilterBase;
+ friend class QGLTextureGlyphCache;
+ friend class QGLShareRegister;
+ friend class QGLSharedResourceGuard;
+ friend class QGLPixmapBlurFilter;
friend QGLFormat::OpenGLVersionFlags QGLFormat::openGLVersionFlags();
#ifdef Q_WS_MAC
public:
@@ -371,16 +408,16 @@ private:
friend class QMacGLWindowChangeEvent;
friend QGLContextPrivate *qt_phonon_get_dptr(const QGLContext *);
#endif
-#ifdef Q_WS_WIN
friend class QGLFramebufferObject;
friend class QGLFramebufferObjectPrivate;
- friend bool qt_resolve_GLSL_functions(QGLContext *ctx);
- friend bool qt_createGLSLProgram(QGLContext *ctx, GLuint &program, const char *shader_src, GLuint &shader);
-#endif
+ friend class QGLFBOGLPaintDevice;
+ friend class QGLPaintDevice;
+ friend class QX11GLPixmapData;
private:
Q_DISABLE_COPY(QGLContext)
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QGLContext::BindOptions)
class Q_OPENGL_EXPORT QGLWidget : public QWidget
{
@@ -416,7 +453,6 @@ public:
bool doubleBuffer() const;
void swapBuffers();
- // ### Qt 5: make format() return a const ref instead
QGLFormat format() const;
void setFormat(const QGLFormat& format);
@@ -443,10 +479,16 @@ public:
const QFont & fnt = QFont(), int listBase = 2000);
QPaintEngine *paintEngine() const;
+ GLuint bindTexture(const QImage &image, GLenum target, GLint format,
+ QGLContext::BindOptions options);
+ GLuint bindTexture(const QPixmap &pixmap, GLenum target, GLint format,
+ QGLContext::BindOptions options);
+
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);
+
GLuint bindTexture(const QString &fileName);
void deleteTexture(GLuint tx_id);
@@ -459,6 +501,10 @@ public:
QMacCompatGLint format = GL_RGBA);
GLuint bindTexture(const QPixmap &pixmap, QMacCompatGLenum = GL_TEXTURE_2D,
QMacCompatGLint format = GL_RGBA);
+ GLuint bindTexture(const QImage &image, QMacCompatGLenum, QMacCompatGLint format,
+ QGLContext::BindOptions);
+ GLuint bindTexture(const QPixmap &pixmap, QMacCompatGLenum, QMacCompatGLint format,
+ QGLContext::BindOptions);
void deleteTexture(QMacCompatGLuint tx_id);
@@ -500,8 +546,11 @@ private:
friend class QGLPixelBuffer;
friend class QGLPixelBufferPrivate;
friend class QGLContext;
+ friend class QGLContextPrivate;
friend class QGLOverlayWidget;
friend class QOpenGLPaintEngine;
+ friend class QGLPaintDevice;
+ friend class QGLWidgetGLPaintDevice;
};
diff --git a/src/opengl/qgl_egl.cpp b/src/opengl/qgl_egl.cpp
index 348a677..839e8eb 100644
--- a/src/opengl/qgl_egl.cpp
+++ b/src/opengl/qgl_egl.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include <QtOpenGL/qgl.h>
+#include "qgl_p.h"
#include "qgl_egl_p.h"
QT_BEGIN_NAMESPACE
@@ -57,14 +58,14 @@ void qt_egl_set_format(QEglProperties& props, int deviceType, const QGLFormat& f
// Set the pixel format to that contained in the QGLFormat
// if the system hasn't already chosen a fixed format to
// match the pixmap, widget, etc.
- if (props.value(EGL_RED_SIZE) == EGL_DONT_CARE || f.redBufferSize() != -1)
+ if (props.value(EGL_RED_SIZE) == 0 || f.redBufferSize() != -1)
props.setValue(EGL_RED_SIZE, f.redBufferSize() == -1 ? 1 : f.redBufferSize());
- if (props.value(EGL_GREEN_SIZE) == EGL_DONT_CARE || f.greenBufferSize() != -1)
+ if (props.value(EGL_GREEN_SIZE) == 0 || f.greenBufferSize() != -1)
props.setValue(EGL_GREEN_SIZE, f.greenBufferSize() == -1 ? 1 : f.greenBufferSize());
- if (props.value(EGL_BLUE_SIZE) == EGL_DONT_CARE || f.blueBufferSize() != -1)
+ if (props.value(EGL_BLUE_SIZE) == 0 || f.blueBufferSize() != -1)
props.setValue(EGL_BLUE_SIZE, f.blueBufferSize() == -1 ? 1 : f.blueBufferSize());
if (f.alpha()) {
- if (props.value(EGL_ALPHA_SIZE) == EGL_DONT_CARE || f.alphaBufferSize() != -1)
+ if (props.value(EGL_ALPHA_SIZE) == 0 || f.alphaBufferSize() != -1)
props.setValue(EGL_ALPHA_SIZE, f.alphaBufferSize() == -1 ? 1 : f.alphaBufferSize());
}
@@ -128,4 +129,113 @@ void qt_egl_update_format(const QEglContext& context, QGLFormat& format)
context.clearError();
}
+bool QGLFormat::hasOpenGL()
+{
+ return true;
+}
+
+void QGLContext::reset()
+{
+ Q_D(QGLContext);
+ if (!d->valid)
+ return;
+ d->cleanup();
+ doneCurrent();
+ if (d->eglContext) {
+ d->destroyEglSurfaceForDevice();
+ delete d->eglContext;
+ }
+ d->eglContext = 0;
+ d->eglSurface = EGL_NO_SURFACE;
+ d->crWin = false;
+ d->sharing = false;
+ d->valid = false;
+ d->transpColor = QColor();
+ d->initDone = false;
+ qgl_share_reg()->removeShare(this);
+}
+
+void QGLContext::makeCurrent()
+{
+ Q_D(QGLContext);
+ if (!d->valid || !d->eglContext || d->eglSurface == EGL_NO_SURFACE) {
+ qWarning("QGLContext::makeCurrent(): Cannot make invalid context current");
+ return;
+ }
+
+ if (d->eglContext->makeCurrent(d->eglSurface))
+ QGLContextPrivate::setCurrentContext(this);
+}
+
+void QGLContext::doneCurrent()
+{
+ Q_D(QGLContext);
+ if (d->eglContext)
+ d->eglContext->doneCurrent();
+
+ QGLContextPrivate::setCurrentContext(0);
+}
+
+
+void QGLContext::swapBuffers() const
+{
+ Q_D(const QGLContext);
+ if (!d->valid || !d->eglContext)
+ return;
+
+ d->eglContext->swapBuffers(d->eglSurface);
+}
+
+void QGLContextPrivate::destroyEglSurfaceForDevice()
+{
+ if (eglSurface != EGL_NO_SURFACE) {
+#ifdef Q_WS_X11
+ // Make sure we don't call eglDestroySurface on a surface which
+ // was created for a different winId:
+ if (paintDevice->devType() == QInternal::Widget) {
+ QGLWidget* w = static_cast<QGLWidget*>(paintDevice);
+
+ if (w->d_func()->eglSurfaceWindowId == w->winId())
+ eglDestroySurface(eglContext->display(), eglSurface);
+ else
+ qWarning("WARNING: Potential EGL surface leak!");
+ } else
+#endif
+ eglDestroySurface(eglContext->display(), eglSurface);
+ eglSurface = EGL_NO_SURFACE;
+ }
+}
+
+void QGLWidget::setMouseTracking(bool enable)
+{
+ QWidget::setMouseTracking(enable);
+}
+
+QColor QGLContext::overlayTransparentColor() const
+{
+ return d_func()->transpColor;
+}
+
+uint QGLContext::colorIndex(const QColor &c) const
+{
+ Q_UNUSED(c);
+ return 0;
+}
+
+void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase)
+{
+ Q_UNUSED(fnt);
+ Q_UNUSED(listBase);
+}
+
+void *QGLContext::getProcAddress(const QString &proc) const
+{
+ return (void*)eglGetProcAddress(reinterpret_cast<const char *>(proc.toLatin1().data()));
+}
+
+bool QGLWidgetPrivate::renderCxPm(QPixmap*)
+{
+ return false;
+}
+
QT_END_NAMESPACE
diff --git a/src/opengl/qgl_egl_p.h b/src/opengl/qgl_egl_p.h
index d246ba3..47a4a19 100644
--- a/src/opengl/qgl_egl_p.h
+++ b/src/opengl/qgl_egl_p.h
@@ -53,7 +53,7 @@
// We mean it.
//
-#include "qegl_p.h"
+#include <QtGui/private/qegl_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/opengl/qgl_mac.mm b/src/opengl/qgl_mac.mm
index dd9d9ff..4dd822d 100644
--- a/src/opengl/qgl_mac.mm
+++ b/src/opengl/qgl_mac.mm
@@ -460,6 +460,7 @@ void QGLContext::reset()
if (d->cx)
aglDestroyContext((AGLContext)d->cx);
#else
+ QMacCocoaAutoReleasePool pool;
[static_cast<NSOpenGLContext *>(d->cx) release];
#endif
d->cx = 0;
@@ -493,11 +494,7 @@ void QGLContext::makeCurrent()
#else
[static_cast<NSOpenGLContext *>(d->cx) makeCurrentContext];
#endif
- currentCtx = this;
- if (!qgl_context_storage.hasLocalData() && QThread::currentThread())
- qgl_context_storage.setLocalData(new QGLThreadContext);
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = this;
+ QGLContextPrivate::setCurrentContext(this);
}
#ifndef QT_MAC_USE_COCOA
@@ -656,9 +653,7 @@ void QGLContext::doneCurrent()
)
return;
- currentCtx = 0;
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = 0;
+ QGLContextPrivate::setCurrentContext(0);
#ifndef QT_MAC_USE_COCOA
aglSetCurrentContext(0);
#else
diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h
index 793c4d7..99c0f33 100644
--- a/src/opengl/qgl_p.h
+++ b/src/opengl/qgl_p.h
@@ -59,7 +59,10 @@
#include "QtCore/qthread.h"
#include "QtCore/qthreadstorage.h"
#include "QtCore/qhash.h"
+#include "QtCore/qatomic.h"
#include "private/qwidget_p.h"
+#include "qcache.h"
+#include "qglpaintdevice_p.h"
#ifndef QT_OPENGL_ES_1_CL
#define q_vertexType float
@@ -126,16 +129,31 @@ QT_END_INCLUDE_NAMESPACE
class QGLFormatPrivate
{
public:
- QGLFormatPrivate() {
+ QGLFormatPrivate()
+ : ref(1)
+ {
opts = QGL::DoubleBuffer | QGL::DepthBuffer | QGL::Rgba | QGL::DirectRendering | QGL::StencilBuffer;
-#if defined(QT_OPENGL_ES_2)
- opts |= QGL::SampleBuffers;
-#endif
pln = 0;
depthSize = accumSize = stencilSize = redSize = greenSize = blueSize = alphaSize = -1;
numSamples = -1;
swapInterval = -1;
}
+ QGLFormatPrivate(const QGLFormatPrivate *other)
+ : ref(1),
+ opts(other->opts),
+ pln(other->pln),
+ depthSize(other->depthSize),
+ accumSize(other->accumSize),
+ stencilSize(other->stencilSize),
+ redSize(other->redSize),
+ greenSize(other->greenSize),
+ blueSize(other->blueSize),
+ alphaSize(other->alphaSize),
+ numSamples(other->numSamples),
+ swapInterval(other->swapInterval)
+ {
+ }
+ QAtomicInt ref;
QGL::FormatOptions opts;
int pln;
int depthSize;
@@ -154,6 +172,7 @@ class QGLWidgetPrivate : public QWidgetPrivate
Q_DECLARE_PUBLIC(QGLWidget)
public:
QGLWidgetPrivate() : QWidgetPrivate()
+ , disable_clear_on_painter_begin(false)
#ifdef Q_WS_QWS
, wsurf(0)
#endif
@@ -170,10 +189,15 @@ public:
void cleanupColormaps();
QGLContext *glcx;
+ QGLWidgetGLPaintDevice glDevice;
bool autoSwap;
QGLColormap cmap;
+#ifndef QT_OPENGL_ES
QMap<QString, int> displayListCache;
+#endif
+
+ bool disable_clear_on_painter_begin;
#if defined(Q_WS_WIN)
void updateColormap();
@@ -192,17 +216,60 @@ public:
#endif
};
+class QGLContextResource;
+class QGLSharedResourceGuard;
+
+typedef QHash<QString, GLuint> QGLDDSCache;
+
+// QGLContextPrivate has the responsibility of creating context groups.
+// QGLContextPrivate and QGLShareRegister will both maintain the reference counter and destroy
+// context groups when needed.
+// QGLShareRegister has the responsibility of keeping the context pointer up to date.
+class QGLContextGroup
+{
+public:
+ ~QGLContextGroup();
+
+ QGLExtensionFuncs &extensionFuncs() {return m_extensionFuncs;}
+ const QGLContext *context() const {return m_context;}
+ bool isSharing() const { return m_shares.size() >= 2; }
+
+ void addGuard(QGLSharedResourceGuard *guard);
+ void removeGuard(QGLSharedResourceGuard *guard);
+private:
+ QGLContextGroup(const QGLContext *context) : m_context(context), m_guards(0), m_refs(1) { }
+
+ QGLExtensionFuncs m_extensionFuncs;
+ const QGLContext *m_context; // context group's representative
+ QList<const QGLContext *> m_shares;
+ QHash<QGLContextResource *, void *> m_resources;
+ QGLSharedResourceGuard *m_guards; // double-linked list of active guards.
+ QAtomicInt m_refs;
+ QGLDDSCache m_dds_cache;
+
+ void cleanupResources(const QGLContext *ctx);
+
+ friend class QGLShareRegister;
+ friend class QGLContext;
+ friend class QGLContextPrivate;
+ friend class QGLContextResource;
+};
+
+class QGLTexture;
+
class QGLContextPrivate
{
Q_DECLARE_PUBLIC(QGLContext)
public:
- explicit QGLContextPrivate(QGLContext *context) : internal_context(false), q_ptr(context) {}
- ~QGLContextPrivate() {}
- GLuint bindTexture(const QImage &image, GLenum target, GLint format, const qint64 key,
- bool clean = false);
- GLuint bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean);
- GLuint bindTexture(const QImage &image, GLenum target, GLint format, bool clean);
- bool textureCacheLookup(const qint64 key, GLenum target, GLuint *id);
+ explicit QGLContextPrivate(QGLContext *context) : internal_context(false), q_ptr(context) {group = new QGLContextGroup(context);}
+ ~QGLContextPrivate();
+ QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format,
+ QGLContext::BindOptions options);
+ QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format, const qint64 key,
+ QGLContext::BindOptions options);
+ QGLTexture *bindTexture(const QPixmap &pixmap, GLenum target, GLint format,
+ QGLContext::BindOptions options);
+ QGLTexture *textureCacheLookup(const qint64 key, GLenum target);
void init(QPaintDevice *dev, const QGLFormat &format);
QImage convertToGLFormat(const QImage &image, bool force_premul, GLenum texture_format);
int maxTextureSize();
@@ -220,6 +287,8 @@ public:
#endif
#if defined(QT_OPENGL_ES)
QEglContext *eglContext;
+ EGLSurface eglSurface;
+ void destroyEglSurfaceForDevice();
#elif defined(Q_WS_X11) || defined(Q_WS_MAC)
void* cx;
#endif
@@ -230,6 +299,11 @@ public:
void* pbuf;
quint32 gpm;
int screen;
+ QHash<QPixmapData*, QPixmap> boundPixmaps;
+ QGLTexture *bindTextureFromNativePixmap(QPixmapData*, const qint64 key,
+ QGLContext::BindOptions options);
+ static void destroyGlSurfaceForPixmap(QPixmapData*);
+ static void unbindPixmapFromTexture(QPixmapData*);
#endif
#if defined(Q_WS_MAC)
bool update;
@@ -238,13 +312,12 @@ public:
#endif
QGLFormat glFormat;
QGLFormat reqFormat;
- GLuint pbo;
+ GLuint fbo;
uint valid : 1;
uint sharing : 1;
uint initDone : 1;
uint crWin : 1;
- uint clear_on_painter_begin : 1;
uint internal_context : 1;
uint version_flags_cached : 1;
QPaintDevice *paintDevice;
@@ -252,23 +325,29 @@ public:
QGLContext *q_ptr;
QGLFormat::OpenGLVersionFlags version_flags;
- QGLExtensionFuncs extensionFuncs;
+ QGLContextGroup *group;
GLint max_texture_size;
+ GLuint current_fbo;
+ GLuint default_fbo;
+ QPaintEngine *active_engine;
+
+ static inline QGLContextGroup *contextGroup(const QGLContext *ctx) { return ctx->d_ptr->group; }
+
#ifdef Q_WS_WIN
- static inline QGLExtensionFuncs& qt_get_extension_funcs(const QGLContext *ctx) { return ctx->d_ptr->extensionFuncs; }
+ static inline QGLExtensionFuncs& extensionFuncs(const QGLContext *ctx) { return ctx->d_ptr->group->extensionFuncs(); }
#endif
#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
static QGLExtensionFuncs qt_extensionFuncs;
- static inline QGLExtensionFuncs& qt_get_extension_funcs(const QGLContext *) { return qt_extensionFuncs; }
+ static inline QGLExtensionFuncs& extensionFuncs(const QGLContext *) { return qt_extensionFuncs; }
#endif
- QPixmapFilter *createPixmapFilter(int type) const;
+ static void setCurrentContext(QGLContext *context);
};
// ### make QGLContext a QObject in 5.0 and remove the proxy stuff
-class QGLSignalProxy : public QObject
+class Q_OPENGL_EXPORT QGLSignalProxy : public QObject
{
Q_OBJECT
public:
@@ -296,7 +375,14 @@ public:
StencilWrap = 0x00000100,
PackedDepthStencil = 0x00000200,
NVFloatBuffer = 0x00000400,
- PixelBufferObject = 0x00000800
+ PixelBufferObject = 0x00000800,
+ FramebufferBlit = 0x00001000,
+ NPOTTextures = 0x00002000,
+ BGRATextureFormat = 0x00004000,
+ DDSTextureCompression = 0x00008000,
+ ETC1TextureCompression = 0x00010000,
+ PVRTCTextureCompression = 0x00020000,
+ FragmentShader = 0x00040000
};
Q_DECLARE_FLAGS(Extensions, Extension)
@@ -309,86 +395,264 @@ public:
Q_DECLARE_OPERATORS_FOR_FLAGS(QGLExtensions::Extensions)
-struct QGLThreadContext {
- QGLContext *context;
+class Q_OPENGL_EXPORT QGLShareRegister
+{
+public:
+ QGLShareRegister() {}
+ ~QGLShareRegister() {}
+
+ void addShare(const QGLContext *context, const QGLContext *share);
+ QList<const QGLContext *> shares(const QGLContext *context);
+ void removeShare(const QGLContext *context);
};
-extern QThreadStorage<QGLThreadContext *> qgl_context_storage;
-typedef QMultiHash<const QGLContext *, const QGLContext *> QGLSharingHash;
-class QGLShareRegister
+extern Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg();
+
+// Temporarily make a context current if not already current or
+// shared with the current contex. The previous context is made
+// current when the object goes out of scope.
+class Q_OPENGL_EXPORT QGLShareContextScope
{
public:
- QGLShareRegister() {}
- ~QGLShareRegister() { reg.clear(); }
-
- bool checkSharing(const QGLContext *context1, const QGLContext *context2, const QGLContext * skip=0) {
- if (context1 == context2)
- return true;
- QList<const QGLContext *> shares = reg.values(context1);
- for (int k=0; k<shares.size(); ++k) {
- const QGLContext *ctx = shares.at(k);
- if (ctx == skip) // avoid an indirect circular loop (infinite recursion)
- continue;
- if (ctx == context2)
- return true;
- if (checkSharing(ctx, context2, context1))
- return true;
+ QGLShareContextScope(const QGLContext *ctx)
+ : m_oldContext(0)
+ {
+ QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
+ if (currentContext != ctx && !QGLContext::areSharing(ctx, currentContext)) {
+ m_oldContext = currentContext;
+ m_ctx = const_cast<QGLContext *>(ctx);
+ m_ctx->makeCurrent();
+ } else {
+ m_ctx = currentContext;
}
- return false;
}
- void addShare(const QGLContext *context, const QGLContext *share) {
- reg.insert(context, share); // context sharing works both ways
- reg.insert(share, context);
+ operator QGLContext *()
+ {
+ return m_ctx;
}
- void removeShare(const QGLContext *context) {
- QGLSharingHash::iterator it = reg.begin();
- while (it != reg.end()) {
- if (it.key() == context || it.value() == context)
- it = reg.erase(it);
- else
- ++it;
- }
+ QGLContext *operator->()
+ {
+ return m_ctx;
}
- void replaceShare(const QGLContext *oldContext, const QGLContext *newContext) {
- QGLSharingHash::iterator it = reg.begin();
- while (it != reg.end()) {
- if (it.key() == oldContext)
- reg.insert(newContext, it.value());
- else if (it.value() == oldContext)
- reg.insert(it.key(), newContext);
- ++it;
- }
- removeShare(oldContext);
+ ~QGLShareContextScope()
+ {
+ if (m_oldContext)
+ m_oldContext->makeCurrent();
}
private:
- QGLSharingHash reg;
+ QGLContext *m_oldContext;
+ QGLContext *m_ctx;
};
-extern Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg();
+class QGLTexture {
+public:
+ QGLTexture(QGLContext *ctx = 0, GLuint tx_id = 0, GLenum tx_target = GL_TEXTURE_2D,
+ QGLContext::BindOptions opt = QGLContext::DefaultBindOption)
+ : context(ctx),
+ id(tx_id),
+ target(tx_target),
+ options(opt)
+#if defined(Q_WS_X11)
+ , boundPixmap(0)
+#endif
+ {}
-#ifdef Q_WS_QWS
-class QOpenGLPaintEngine;
-extern QOpenGLPaintEngine* qt_qgl_paint_engine();
+ ~QGLTexture() {
+ if (options & QGLContext::MemoryManagedBindOption) {
+ Q_ASSERT(context);
+ QGLShareContextScope scope(context);
+#if defined(Q_WS_X11)
+ // Although glXReleaseTexImage is a glX call, it must be called while there
+ // is a current context - the context the pixmap was bound to a texture in.
+ // Otherwise the release doesn't do anything and you get BadDrawable errors
+ // when you come to delete the context.
+ if (boundPixmap)
+ QGLContextPrivate::unbindPixmapFromTexture(boundPixmap);
+#endif
+ glDeleteTextures(1, &id);
+ }
+ }
+
+ QGLContext *context;
+ GLuint id;
+ GLenum target;
-extern EGLDisplay qt_qgl_egl_display();
+ QGLContext::BindOptions options;
+
+#if defined(Q_WS_X11)
+ QPixmapData* boundPixmap;
#endif
+ bool canBindCompressedTexture
+ (const char *buf, int len, const char *format, bool *hasAlpha);
+ QSize bindCompressedTexture
+ (const QString& fileName, const char *format = 0);
+ QSize bindCompressedTexture
+ (const char *buf, int len, const char *format = 0);
+ QSize bindCompressedTextureDDS(const char *buf, int len);
+ QSize bindCompressedTexturePVR(const char *buf, int len);
+};
+
+class QGLTextureCache {
+public:
+ QGLTextureCache();
+ ~QGLTextureCache();
+
+ void insert(QGLContext *ctx, qint64 key, QGLTexture *texture, int cost);
+ void remove(quint64 key) { m_cache.remove(key); }
+ bool remove(QGLContext *ctx, GLuint textureId);
+ void removeContextTextures(QGLContext *ctx);
+ int size() { return m_cache.size(); }
+ void setMaxCost(int newMax) { m_cache.setMaxCost(newMax); }
+ int maxCost() {return m_cache.maxCost(); }
+ QGLTexture* getTexture(quint64 key) { return m_cache.object(key); }
+
+ static QGLTextureCache *instance();
+ static void deleteIfEmpty();
+ static void imageCleanupHook(qint64 cacheKey);
+ static void cleanupTextures(QPixmap* pixmap);
+#ifdef Q_WS_X11
+ // X11 needs to catch pixmap data destruction to delete EGL/GLX pixmap surfaces
+ static void cleanupPixmapSurfaces(QPixmap* pixmap);
+#endif
+
+private:
+ QCache<qint64, QGLTexture> m_cache;
+};
+
+
+extern Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine();
+
+bool qt_gl_preferGL2Engine();
+
inline GLenum qt_gl_preferredTextureFormat()
{
- return QSysInfo::ByteOrder == QSysInfo::BigEndian ? GL_RGBA : GL_BGRA;
+ return (QGLExtensions::glExtensions & QGLExtensions::BGRATextureFormat) && QSysInfo::ByteOrder == QSysInfo::LittleEndian
+ ? GL_BGRA : GL_RGBA;
}
inline GLenum qt_gl_preferredTextureTarget()
{
+#if defined(QT_OPENGL_ES_2)
+ return GL_TEXTURE_2D;
+#else
return (QGLExtensions::glExtensions & QGLExtensions::TextureRectangle)
+ && !qt_gl_preferGL2Engine()
? GL_TEXTURE_RECTANGLE_NV
: GL_TEXTURE_2D;
+#endif
}
+// One resource per group of shared contexts.
+class Q_AUTOTEST_EXPORT QGLContextResource
+{
+public:
+ typedef void (*FreeFunc)(void *);
+ QGLContextResource(FreeFunc f);
+ ~QGLContextResource();
+ // Set resource 'value' for 'key' and all its shared contexts.
+ void insert(const QGLContext *key, void *value);
+ // Return resource for 'key' or a shared context.
+ void *value(const QGLContext *key);
+ // Cleanup 'value' in response to a context group being destroyed.
+ void cleanup(const QGLContext *ctx, void *value);
+private:
+ FreeFunc free;
+ QAtomicInt active;
+};
+
+// Put a guard around a GL object identifier and its context.
+// When the context goes away, a shared context will be used
+// in its place. If there are no more shared contexts, then
+// the identifier is returned as zero - it is assumed that the
+// context destruction cleaned up the identifier in this case.
+class Q_OPENGL_EXPORT QGLSharedResourceGuard
+{
+public:
+ QGLSharedResourceGuard(const QGLContext *context)
+ : m_group(0), m_id(0), m_next(0), m_prev(0)
+ {
+ setContext(context);
+ }
+ QGLSharedResourceGuard(const QGLContext *context, GLuint id)
+ : m_group(0), m_id(id), m_next(0), m_prev(0)
+ {
+ setContext(context);
+ }
+ ~QGLSharedResourceGuard();
+
+ const QGLContext *context() const
+ {
+ return m_group ? m_group->context() : 0;
+ }
+
+ void setContext(const QGLContext *context);
+
+ GLuint id() const
+ {
+ return m_id;
+ }
+
+ void setId(GLuint id)
+ {
+ m_id = id;
+ }
+
+private:
+ QGLContextGroup *m_group;
+ GLuint m_id;
+ QGLSharedResourceGuard *m_next;
+ QGLSharedResourceGuard *m_prev;
+
+ friend class QGLContextGroup;
+};
+
+
+// This class can be used to match GL extensions with doing any mallocs. The
+// class assumes that the GL extension string ends with a space character,
+// which it should do on all conformant platforms. Create the object and pass
+// in a pointer to the extension string, then call match() on each extension
+// that should be matched. The match() function takes the extension name
+// *without* the terminating space character as input.
+
+class QGLExtensionMatcher
+{
+public:
+ QGLExtensionMatcher(const char *str)
+ : gl_extensions(str), gl_extensions_length(qstrlen(str))
+ {}
+
+ bool match(const char *str) {
+ int str_length = qstrlen(str);
+ const char *extensions = gl_extensions;
+ int extensions_length = gl_extensions_length;
+
+ while (1) {
+ // the total length that needs to be matched is the str_length +
+ // the space character that terminates the extension name
+ if (extensions_length < str_length + 1)
+ return false;
+ if (qstrncmp(extensions, str, str_length) == 0 && extensions[str_length] == ' ')
+ return true;
+
+ int split_pos = 0;
+ while (split_pos < extensions_length && extensions[split_pos] != ' ')
+ ++split_pos;
+ ++split_pos; // added for the terminating space character
+ extensions += split_pos;
+ extensions_length -= split_pos;
+ }
+ return false;
+ }
+
+private:
+ const char *gl_extensions;
+ int gl_extensions_length;
+};
QT_END_NAMESPACE
diff --git a/src/opengl/qgl_qws.cpp b/src/opengl/qgl_qws.cpp
index dd578b2..a189c20 100644
--- a/src/opengl/qgl_qws.cpp
+++ b/src/opengl/qgl_qws.cpp
@@ -41,6 +41,7 @@
#include "qgl.h"
#include "qgl_egl_p.h"
+#include "qglpixelbuffer.h"
#include <qglscreen_qws.h>
#include <qscreenproxy_qws.h>
@@ -87,12 +88,6 @@ static QGLScreen *glScreenForDevice(QPaintDevice *device)
*****************************************************************************/
//#define DEBUG_OPENGL_REGION_UPDATE
-bool QGLFormat::hasOpenGL()
-{
- return true;
-}
-
-
bool QGLFormat::hasOpenGLOverlays()
{
QGLScreen *glScreen = glScreenForDevice(0);
@@ -117,6 +112,54 @@ void qt_egl_add_platform_config(QEglProperties& props, QPaintDevice *device)
props.setPixelFormat(glScreen->pixelFormat());
}
+static EGLSurface qt_egl_create_surface
+ (QEglContext *context, QPaintDevice *device,
+ const QEglProperties *properties = 0)
+{
+ // Get the screen surface functions, which are used to create native ids.
+ QGLScreen *glScreen = glScreenForDevice(device);
+ if (!glScreen)
+ return EGL_NO_SURFACE;
+ QGLScreenSurfaceFunctions *funcs = glScreen->surfaceFunctions();
+ if (!funcs)
+ return EGL_NO_SURFACE;
+
+ // Create the native drawable for the paint device.
+ int devType = device->devType();
+ EGLNativePixmapType pixmapDrawable = 0;
+ EGLNativeWindowType windowDrawable = 0;
+ bool ok;
+ if (devType == QInternal::Pixmap) {
+ ok = funcs->createNativePixmap(static_cast<QPixmap *>(device), &pixmapDrawable);
+ } else if (devType == QInternal::Image) {
+ ok = funcs->createNativeImage(static_cast<QImage *>(device), &pixmapDrawable);
+ } else {
+ ok = funcs->createNativeWindow(static_cast<QWidget *>(device), &windowDrawable);
+ }
+ if (!ok) {
+ qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable");
+ return EGL_NO_SURFACE;
+ }
+
+ // Create the EGL surface to draw into, based on the native drawable.
+ const int *props;
+ if (properties)
+ props = properties->properties();
+ else
+ props = 0;
+ EGLSurface surf;
+ if (devType == QInternal::Widget) {
+ surf = eglCreateWindowSurface
+ (context->display(), context->config(), windowDrawable, props);
+ } else {
+ surf = eglCreatePixmapSurface
+ (context->display(), context->config(), pixmapDrawable, props);
+ }
+ if (surf == EGL_NO_SURFACE)
+ qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError());
+ return surf;
+}
+
bool QGLContext::chooseContext(const QGLContext* shareContext)
{
Q_D(QGLContext);
@@ -132,7 +175,7 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
// Get the display and initialize it.
d->eglContext = new QEglContext();
- d->eglContext->setApi(QEglContext::OpenGL);
+ d->eglContext->setApi(QEgl::OpenGL);
if (!d->eglContext->openDisplay(device())) {
delete d->eglContext;
d->eglContext = 0;
@@ -143,7 +186,7 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
QEglProperties configProps;
qt_egl_add_platform_config(configProps, device());
qt_egl_set_format(configProps, devType, d->glFormat);
- configProps.setRenderableType(QEglContext::OpenGL);
+ configProps.setRenderableType(QEgl::OpenGL);
// Search for a matching configuration, reducing the complexity
// each time until we get something that matches.
@@ -163,14 +206,20 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
d->eglContext = 0;
return false;
}
+ d->sharing = d->eglContext->isSharing();
+ if (d->sharing && shareContext)
+ const_cast<QGLContext *>(shareContext)->d_func()->sharing = true;
#if defined(EGL_VERSION_1_1)
if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget)
eglSwapInterval(d->eglContext->display(), d->glFormat.swapInterval());
#endif
- // Create the EGL surface to draw into.
- if (!d->eglContext->createSurface(device())) {
+ // Create the EGL surface to draw into. We cannot use
+ // QEglContext::createSurface() because it does not have
+ // access to the QGLScreen.
+ d->eglSurface = qt_egl_create_surface(d->eglContext, device());
+ if (d->eglSurface == EGL_NO_SURFACE) {
delete d->eglContext;
d->eglContext = 0;
return false;
@@ -180,98 +229,11 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
}
-void QGLContext::reset()
-{
- Q_D(QGLContext);
- if (!d->valid)
- return;
- d->cleanup();
- doneCurrent();
- if (d->eglContext) {
- if (d->eglContext->surface() != EGL_NO_SURFACE)
- eglDestroySurface(d->eglContext->display(), d->eglContext->surface());
- delete d->eglContext;
- d->eglContext = 0;
- }
- d->crWin = false;
- d->sharing = false;
- d->valid = false;
- d->transpColor = QColor();
- d->initDone = false;
- qgl_share_reg()->removeShare(this);
-}
-
-void QGLContext::makeCurrent()
-{
- Q_D(QGLContext);
- if(!d->valid || !d->eglContext) {
- qWarning("QGLContext::makeCurrent(): Cannot make invalid context current");
- return;
- }
-
- if (d->eglContext->makeCurrent()) {
- if (!qgl_context_storage.hasLocalData() && QThread::currentThread())
- qgl_context_storage.setLocalData(new QGLThreadContext);
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = this;
- currentCtx = this;
- }
-}
-
-void QGLContext::doneCurrent()
-{
- Q_D(QGLContext);
- if (d->eglContext)
- d->eglContext->doneCurrent();
-
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = 0;
- currentCtx = 0;
-}
-
-
-void QGLContext::swapBuffers() const
-{
- Q_D(const QGLContext);
- if(!d->valid || !d->eglContext)
- return;
-
- d->eglContext->swapBuffers();
-}
-
-QColor QGLContext::overlayTransparentColor() const
-{
- return QColor(0, 0, 0); // Invalid color
-}
-
-uint QGLContext::colorIndex(const QColor &c) const
-{
- //### color index doesn't work on egl
- Q_UNUSED(c);
- return 0;
-}
-
-void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase)
-{
- Q_UNUSED(fnt);
- Q_UNUSED(listBase);
-}
-
-void *QGLContext::getProcAddress(const QString &proc) const
-{
- return (void*)eglGetProcAddress(reinterpret_cast<const char *>(proc.toLatin1().data()));
-}
-
bool QGLWidget::event(QEvent *e)
{
return QWidget::event(e);
}
-void QGLWidget::setMouseTracking(bool enable)
-{
- QWidget::setMouseTracking(enable);
-}
-
void QGLWidget::resizeEvent(QResizeEvent *)
{
@@ -336,11 +298,6 @@ void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget* shareWidget)
}
}
-bool QGLWidgetPrivate::renderCxPm(QPixmap*)
-{
- return false;
-}
-
void QGLWidgetPrivate::cleanupColormaps()
{
}
@@ -361,7 +318,29 @@ void QGLExtensions::init()
if (init_done)
return;
init_done = true;
+
+ // We need a context current to initialize the extensions,
+ // but getting a valid EGLNativeWindowType this early can be
+ // problematic under QWS. So use a pbuffer instead.
+ //
+ // Unfortunately OpenGL/ES 2.0 systems don't normally
+ // support pbuffers, so we have no choice but to try
+ // our luck with a window on those systems.
+#if defined(QT_OPENGL_ES_2)
+ QGLWidget tmpWidget;
+ tmpWidget.makeCurrent();
+
+ init_extensions();
+
+ tmpWidget.doneCurrent();
+#else
+ QGLPixelBuffer pbuffer(16, 16);
+ pbuffer.makeCurrent();
+
init_extensions();
+
+ pbuffer.doneCurrent();
+#endif
}
QT_END_NAMESPACE
diff --git a/src/opengl/qgl_win.cpp b/src/opengl/qgl_win.cpp
index f0e3bba..5b5820a 100644
--- a/src/opengl/qgl_win.cpp
+++ b/src/opengl/qgl_win.cpp
@@ -51,7 +51,7 @@
#include <qdebug.h>
#include <qcolor.h>
-#include <windows.h>
+#include <qt_windows.h>
typedef bool (APIENTRY *PFNWGLGETPIXELFORMATATTRIBIVARB)(HDC hdc,
int iPixelFormat,
@@ -642,14 +642,10 @@ public:
QString windowClassName = qt_getRegisteredWndClass();
if (parent && !parent->internalWinId())
parent = parent->nativeParentWidget();
- QT_WA({
- const TCHAR *cname = (TCHAR*)windowClassName.utf16();
- dmy_id = CreateWindow(cname, 0, 0, 0, 0, 1, 1,
- parent ? parent->winId() : 0, 0, qWinAppInst(), 0);
- } , {
- dmy_id = CreateWindowA(windowClassName.toLatin1(), 0, 0, 0, 0, 1, 1,
- parent ? parent->winId() : 0, 0, qWinAppInst(), 0);
- });
+
+ dmy_id = CreateWindow((const wchar_t *)windowClassName.utf16(),
+ 0, 0, 0, 0, 1, 1,
+ parent ? parent->winId() : 0, 0, qWinAppInst(), 0);
dmy_pdc = GetDC(dmy_id);
PIXELFORMATDESCRIPTOR dmy_pfd;
@@ -664,6 +660,8 @@ public:
int dmy_pf = ChoosePixelFormat(dmy_pdc, &dmy_pfd);
SetPixelFormat(dmy_pdc, dmy_pf, &dmy_pfd);
dmy_rc = wglCreateContext(dmy_pdc);
+ old_dc = wglGetCurrentDC();
+ old_context = wglGetCurrentContext();
wglMakeCurrent(dmy_pdc, dmy_rc);
}
@@ -672,10 +670,14 @@ public:
wglDeleteContext(dmy_rc);
ReleaseDC(dmy_id, dmy_pdc);
DestroyWindow(dmy_id);
+ if (old_dc && old_context)
+ wglMakeCurrent(old_dc, old_context);
}
HDC dmy_pdc;
HGLRC dmy_rc;
+ HDC old_dc;
+ HGLRC old_context;
WId dmy_id;
};
@@ -1177,11 +1179,7 @@ void QGLContext::makeCurrent()
}
if (wglMakeCurrent(d->dc, d->rc)) {
- if (!qgl_context_storage.hasLocalData() && QThread::currentThread())
- qgl_context_storage.setLocalData(new QGLThreadContext);
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = this;
- currentCtx = this;
+ QGLContextPrivate::setCurrentContext(this);
} else {
qwglError("QGLContext::makeCurrent()", "wglMakeCurrent");
}
@@ -1191,10 +1189,8 @@ void QGLContext::makeCurrent()
void QGLContext::doneCurrent()
{
Q_D(QGLContext);
- currentCtx = 0;
wglMakeCurrent(0, 0);
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = 0;
+ QGLContextPrivate::setCurrentContext(0);
if (deviceIsPixmap() && d->hbitmap) {
QPixmap *pm = static_cast<QPixmap *>(d->paintDevice);
*pm = QPixmap::fromWinHBITMAP(d->hbitmap);
@@ -1417,7 +1413,7 @@ void QGLWidget::setContext(QGLContext *context,
}
if (!d->glcx->isValid()) {
- bool wasSharing = shareContext || oldcx && oldcx->isSharing();
+ bool wasSharing = shareContext || (oldcx && oldcx->isSharing());
d->glcx->create(shareContext ? shareContext : oldcx);
// the above is a trick to keep disp lists etc when a
// QGLWidget has been reparented, so remove the sharing
diff --git a/src/opengl/qgl_wince.cpp b/src/opengl/qgl_wince.cpp
index 831cc01..2553110 100644
--- a/src/opengl/qgl_wince.cpp
+++ b/src/opengl/qgl_wince.cpp
@@ -54,9 +54,9 @@
#include <windows.h>
-#include "qegl_p.h"
-#include "qgl_egl_p.h"
-#include "qgl_cl_p.h"
+#include <private/qegl_p.h>
+#include <private/qgl_egl_p.h>
+#include <private/qgl_cl_p.h>
QT_BEGIN_NAMESPACE
@@ -112,11 +112,6 @@ void qt_egl_add_platform_config(QEglProperties& props, QPaintDevice *device)
}
-bool QGLFormat::hasOpenGL()
-{
- return true;
-}
-
static bool opengl32dll = false;
bool QGLFormat::hasOpenGLOverlays()
@@ -140,7 +135,7 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
// Get the display and initialize it.
d->eglContext = new QEglContext();
- d->eglContext->setApi(QEglContext::OpenGL);
+ d->eglContext->setApi(QEgl::OpenGL);
if (!d->eglContext->openDisplay(device())) {
delete d->eglContext;
d->eglContext = 0;
@@ -151,7 +146,7 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
QEglProperties configProps;
qt_egl_add_platform_config(configProps, device());
qt_egl_set_format(configProps, devType, d->glFormat);
- configProps.setRenderableType(QEglContext::OpenGL);
+ configProps.setRenderableType(QEgl::OpenGL);
// Search for a matching configuration, reducing the complexity
// each time until we get something that matches.
@@ -171,6 +166,9 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
d->eglContext = 0;
return false;
}
+ d->sharing = d->eglContext->isSharing();
+ if (d->sharing && shareContext)
+ const_cast<QGLContext *>(shareContext)->d_func()->sharing = true;
#if defined(EGL_VERSION_1_1)
if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget)
@@ -178,7 +176,8 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
#endif
// Create the EGL surface to draw into.
- if (!d->eglContext->createSurface(device())) {
+ d->eglSurface = d->eglContext->createSurface(device());
+ if (d->eglSurface == EGL_NO_SURFACE) {
delete d->eglContext;
d->eglContext = 0;
return false;
@@ -415,90 +414,6 @@ const QRgb* QGLCmap::colors() const
}
-void QGLContext::reset()
-{
- Q_D(QGLContext);
- if (!d->valid)
- return;
- d->cleanup();
- doneCurrent();
- if (d->eglContext) {
- delete d->eglContext;
- d->eglContext = 0;
- }
- d->crWin = false;
- d->sharing = false;
- d->valid = false;
- d->transpColor = QColor();
- d->initDone = false;
- qgl_share_reg()->removeShare(this);
-}
-
-
-//
-// NOTE: In a multi-threaded environment, each thread has a current
-// context. If we want to make this code thread-safe, we probably
-// have to use TLS (thread local storage) for keeping current contexts.
-//
-
-void QGLContext::makeCurrent()
-{
-
- Q_D(QGLContext);
- if(!d->valid || !d->eglContext) {
- qWarning("QGLContext::makeCurrent(): Cannot make invalid context current");
- return;
- }
-
- if (d->eglContext->makeCurrent()) {
- if (!qgl_context_storage.hasLocalData() && QThread::currentThread())
- qgl_context_storage.setLocalData(new QGLThreadContext);
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = this;
- currentCtx = this;
- }
-}
-
-
-void QGLContext::doneCurrent()
-{
-
- Q_D(QGLContext);
- if (d->eglContext)
- d->eglContext->doneCurrent();
-
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = 0;
- currentCtx = 0;
-}
-
-void QGLContext::swapBuffers() const
-{
- Q_D(const QGLContext);
- if(!d->valid || !d->eglContext)
- return;
-
- d->eglContext->swapBuffers();
-}
-
-
-QColor QGLContext::overlayTransparentColor() const
-{
- return d_func()->transpColor;
-}
-
-
-void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase)
-{
- Q_UNUSED(fnt);
- Q_UNUSED(listBase);
-}
-
-void *QGLContext::getProcAddress(const QString &proc) const
-{
- return (void*)eglGetProcAddress(reinterpret_cast<const char *>(proc.toLatin1().data()));
-}
-
/*****************************************************************************
QGLWidget Win32/WGL-specific code
*****************************************************************************/
@@ -577,12 +492,6 @@ bool QGLWidget::event(QEvent *e)
}
-void QGLWidget::setMouseTracking(bool enable)
-{
- QWidget::setMouseTracking(enable);
-}
-
-
void QGLWidget::resizeEvent(QResizeEvent *)
{
Q_D(QGLWidget);
@@ -682,11 +591,6 @@ void QGLWidget::setContext(QGLContext *context,
}
-bool QGLWidgetPrivate::renderCxPm(QPixmap*)
-{
- return false;
-}
-
void QGLWidgetPrivate::cleanupColormaps()
{
Q_Q(QGLWidget);
@@ -730,7 +634,14 @@ void QGLExtensions::init()
if (init_done)
return;
init_done = true;
+
+ // We need a context current to initialize the extensions.
+ QGLWidget tmpWidget;
+ tmpWidget.makeCurrent();
+
init_extensions();
+
+ tmpWidget.doneCurrent();
}
QT_END_NAMESPACE
diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp
index 76a057a..9c3fc79 100644
--- a/src/opengl/qgl_x11.cpp
+++ b/src/opengl/qgl_x11.cpp
@@ -52,19 +52,34 @@
#include "qdebug.h"
#include <private/qfontengine_ft_p.h>
#include <private/qt_x11_p.h>
+#include <private/qpixmap_x11_p.h>
+#include <private/qimagepixmapcleanuphooks_p.h>
#ifdef Q_OS_HPUX
// for GLXPBuffer
#include <private/qglpixelbuffer_p.h>
#endif
+// We always define GLX_EXT_texture_from_pixmap ourselves because
+// we can't trust system headers to do it properly
+#define GLX_EXT_texture_from_pixmap 1
+
#define INT8 dummy_INT8
#define INT32 dummy_INT32
#include <GL/glx.h>
#undef INT8
#undef INT32
+
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
+#ifdef Q_OS_VXWORS
+# ifdef open
+# undef open
+# endif
+# ifdef getpid
+# undef getpid
+# endif
+#endif // Q_OS_VXWORKS
#include <X11/Xatom.h>
#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
@@ -81,6 +96,25 @@ extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
#define GLX_SAMPLES_ARB 100001
#endif
+#ifndef GLX_TEXTURE_2D_BIT_EXT
+#define GLX_TEXTURE_2D_BIT_EXT 0x00000002
+#define GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004
+#define GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0
+#define GLX_BIND_TO_TEXTURE_RGBA_EXT 0x20D1
+#define GLX_BIND_TO_MIPMAP_TEXTURE_EXT 0x20D2
+#define GLX_BIND_TO_TEXTURE_TARGETS_EXT 0x20D3
+#define GLX_Y_INVERTED_EXT 0x20D4
+#define GLX_TEXTURE_FORMAT_EXT 0x20D5
+#define GLX_TEXTURE_TARGET_EXT 0x20D6
+#define GLX_MIPMAP_TEXTURE_EXT 0x20D7
+#define GLX_TEXTURE_FORMAT_NONE_EXT 0x20D8
+#define GLX_TEXTURE_FORMAT_RGB_EXT 0x20D9
+#define GLX_TEXTURE_FORMAT_RGBA_EXT 0x20DA
+#define GLX_TEXTURE_2D_EXT 0x20DC
+#define GLX_TEXTURE_RECTANGLE_EXT 0x20DD
+#define GLX_FRONT_LEFT_EXT 0x20DE
+#endif
+
/*
The qt_gl_choose_cmap function is internal and used by QGLWidget::setContext()
and GLX (not Windows). If the application can't find any sharable
@@ -129,7 +163,7 @@ struct QGLCMapCleanupHandler {
CMapEntryHash *cmap_hash;
GLCMapHash *qglcmap_hash;
};
-Q_GLOBAL_STATIC(QGLCMapCleanupHandler, cmap_handler);
+Q_GLOBAL_STATIC(QGLCMapCleanupHandler, cmap_handler)
static void cleanup_cmaps()
{
@@ -298,6 +332,62 @@ static void find_trans_colors()
QGLFormat UNIX/GLX-specific code
*****************************************************************************/
+void* qglx_getProcAddress(const char* procName)
+{
+ // On systems where the GL driver is pluggable (like Mesa), we have to use
+ // the glXGetProcAddressARB extension to resolve other function pointers as
+ // the symbols wont be in the GL library, but rather in a plugin loaded by
+ // the GL library.
+ typedef void* (*qt_glXGetProcAddressARB)(const char *);
+ static qt_glXGetProcAddressARB glXGetProcAddressARB = 0;
+ static bool triedResolvingGlxGetProcAddress = false;
+ if (!triedResolvingGlxGetProcAddress) {
+ triedResolvingGlxGetProcAddress = true;
+ QGLExtensionMatcher extensions(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS));
+ if (extensions.match("GLX_ARB_get_proc_address")) {
+#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
+ void *handle = dlopen(NULL, RTLD_LAZY);
+ if (handle) {
+ glXGetProcAddressARB = (qt_glXGetProcAddressARB) dlsym(handle, "glXGetProcAddressARB");
+ dlclose(handle);
+ }
+ if (!glXGetProcAddressARB)
+#endif
+ {
+#if !defined(QT_NO_LIBRARY)
+ extern const QString qt_gl_library_name();
+ QLibrary lib(qt_gl_library_name());
+ glXGetProcAddressARB = (qt_glXGetProcAddressARB) lib.resolve("glXGetProcAddressARB");
+#endif
+ }
+ }
+ }
+
+ void *procAddress = 0;
+ if (glXGetProcAddressARB)
+ procAddress = glXGetProcAddressARB(procName);
+
+ // If glXGetProcAddress didn't work, try looking the symbol up in the GL library
+#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
+ if (!procAddress) {
+ void *handle = dlopen(NULL, RTLD_LAZY);
+ if (handle) {
+ procAddress = dlsym(handle, procName);
+ dlclose(handle);
+ }
+ }
+#endif
+#if !defined(QT_NO_LIBRARY)
+ if (!procAddress) {
+ extern const QString qt_gl_library_name();
+ QLibrary lib(qt_gl_library_name());
+ procAddress = lib.resolve(procName);
+ }
+#endif
+
+ return procAddress;
+}
+
bool QGLFormat::hasOpenGL()
{
return glXQueryExtension(X11->display, 0, 0) != 0;
@@ -433,8 +523,8 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
if (!d->gpm)
return false;
}
- QString glxExt = QString(QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)));
- if (glxExt.contains(QLatin1String("GLX_SGI_video_sync"))) {
+ QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen()));
+ if (extensions.match("GLX_SGI_video_sync")) {
if (d->glFormat.swapInterval() == -1)
d->glFormat.setSwapInterval(0);
} else {
@@ -515,18 +605,33 @@ void *QGLContext::chooseVisual()
void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth)
{
Q_D(QGLContext);
- int spec[40];
+ int spec[45];
int i = 0;
spec[i++] = GLX_LEVEL;
spec[i++] = f.plane();
const QX11Info *xinfo = qt_x11Info(d->paintDevice);
+ bool useFBConfig = false;
+
+#if defined(GLX_VERSION_1_3) && !defined(QT_NO_XRENDER) && !defined(Q_OS_HPUX)
+ /*
+ HPUX defines GLX_VERSION_1_3 but does not implement the corresponding functions.
+ Specifically glXChooseFBConfig and glXGetVisualFromFBConfig are not implemented.
+ */
+ QWidget* widget = 0;
+ if (d->paintDevice->devType() == QInternal::Widget)
+ widget = static_cast<QWidget*>(d->paintDevice);
+
+ // Only use glXChooseFBConfig for widgets if we're trying to get an ARGB visual
+ if (widget && widget->testAttribute(Qt::WA_TranslucentBackground) && X11->use_xrender)
+ useFBConfig = true;
+#endif
#if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
static bool useTranspExt = false;
static bool useTranspExtChecked = false;
if (f.plane() && !useTranspExtChecked && d->paintDevice) {
- QByteArray estr(glXQueryExtensionsString(xinfo->display(), xinfo->screen()));
- useTranspExt = estr.contains("GLX_EXT_visual_info");
+ QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen()));
+ useTranspExt = extensions.match("GLX_EXT_visual_info");
//# (A bit simplistic; that could theoretically be a substring)
if (useTranspExt) {
QByteArray cstr(glXGetClientString(xinfo->display(), GLX_VENDOR));
@@ -547,28 +652,41 @@ void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth)
useTranspExtChecked = true;
}
- if (f.plane() && useTranspExt) {
+ if (f.plane() && useTranspExt && !useFBConfig) {
// Required to avoid non-transparent overlay visual(!) on some systems
spec[i++] = GLX_TRANSPARENT_TYPE_EXT;
spec[i++] = f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT;
}
#endif
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+ // GLX_RENDER_TYPE is only in glx >=1.3
+ if (useFBConfig) {
+ spec[i++] = GLX_RENDER_TYPE;
+ spec[i++] = f.rgba() ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT;
+ }
+#endif
+
if (f.doubleBuffer())
spec[i++] = GLX_DOUBLEBUFFER;
+ if (useFBConfig)
+ spec[i++] = True;
if (f.depth()) {
spec[i++] = GLX_DEPTH_SIZE;
spec[i++] = f.depthBufferSize() == -1 ? 1 : f.depthBufferSize();
}
if (f.stereo()) {
spec[i++] = GLX_STEREO;
+ if (useFBConfig)
+ spec[i++] = True;
}
if (f.stencil()) {
spec[i++] = GLX_STENCIL_SIZE;
spec[i++] = f.stencilBufferSize() == -1 ? 1 : f.stencilBufferSize();
}
if (f.rgba()) {
- spec[i++] = GLX_RGBA;
+ if (!useFBConfig)
+ spec[i++] = GLX_RGBA;
spec[i++] = GLX_RED_SIZE;
spec[i++] = f.redBufferSize() == -1 ? 1 : f.redBufferSize();
spec[i++] = GLX_GREEN_SIZE;
@@ -603,8 +721,86 @@ void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth)
spec[i++] = f.samples() == -1 ? 4 : f.samples();
}
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+ if (useFBConfig) {
+ spec[i++] = GLX_DRAWABLE_TYPE;
+ switch(d->paintDevice->devType()) {
+ case QInternal::Pixmap:
+ spec[i++] = GLX_PIXMAP_BIT;
+ break;
+ case QInternal::Pbuffer:
+ spec[i++] = GLX_PBUFFER_BIT;
+ break;
+ default:
+ qWarning("QGLContext: Unknown paint device type %d", d->paintDevice->devType());
+ // Fall-through & assume it's a window
+ case QInternal::Widget:
+ spec[i++] = GLX_WINDOW_BIT;
+ break;
+ };
+ }
+#endif
+
spec[i] = XNone;
- return glXChooseVisual(xinfo->display(), xinfo->screen(), spec);
+
+
+ XVisualInfo* chosenVisualInfo = 0;
+
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+ while (useFBConfig) {
+ GLXFBConfig *configs;
+ int configCount = 0;
+ configs = glXChooseFBConfig(xinfo->display(), xinfo->screen(), spec, &configCount);
+
+ if (!configs)
+ break; // fallback to trying glXChooseVisual
+
+ for (i = 0; i < configCount; ++i) {
+ XVisualInfo* vi;
+ vi = glXGetVisualFromFBConfig(xinfo->display(), configs[i]);
+ if (!vi)
+ continue;
+
+#if !defined(QT_NO_XRENDER)
+ QWidget* w = 0;
+ if (d->paintDevice->devType() == QInternal::Widget)
+ w = static_cast<QWidget*>(d->paintDevice);
+
+ if (w && w->testAttribute(Qt::WA_TranslucentBackground) && f.alpha()) {
+ // Attempt to find a config who's visual has a proper alpha channel
+ XRenderPictFormat *pictFormat;
+ pictFormat = XRenderFindVisualFormat(xinfo->display(), vi->visual);
+
+ if (pictFormat && (pictFormat->type == PictTypeDirect) && pictFormat->direct.alphaMask) {
+ // The pict format for the visual matching the FBConfig indicates ARGB
+ if (chosenVisualInfo)
+ XFree(chosenVisualInfo);
+ chosenVisualInfo = vi;
+ break;
+ }
+ } else
+#endif //QT_NO_XRENDER
+ if (chosenVisualInfo) {
+ // If we've got a visual we can use and we're not trying to find one with a
+ // real alpha channel, we might as well just use the one we've got
+ break;
+ }
+
+ if (!chosenVisualInfo)
+ chosenVisualInfo = vi; // Have something to fall back to
+ else
+ XFree(vi);
+ }
+
+ XFree(configs);
+ break;
+ }
+#endif // defined(GLX_VERSION_1_3)
+
+ if (!chosenVisualInfo)
+ chosenVisualInfo = glXChooseVisual(xinfo->display(), xinfo->screen(), spec);
+
+ return chosenVisualInfo;
}
@@ -652,22 +848,15 @@ void QGLContext::makeCurrent()
if (!ok)
qWarning("QGLContext::makeCurrent(): Failed.");
- if (ok) {
- if (!qgl_context_storage.hasLocalData() && QThread::currentThread())
- qgl_context_storage.setLocalData(new QGLThreadContext);
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = this;
- currentCtx = this;
- }
+ if (ok)
+ QGLContextPrivate::setCurrentContext(this);
}
void QGLContext::doneCurrent()
{
Q_D(QGLContext);
glXMakeCurrent(qt_x11Info(d->paintDevice)->display(), 0, 0);
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = 0;
- currentCtx = 0;
+ QGLContextPrivate::setCurrentContext(0);
}
@@ -685,23 +874,11 @@ void QGLContext::swapBuffers() const
static qt_glXWaitVideoSyncSGI glXWaitVideoSyncSGI = 0;
static bool resolved = false;
if (!resolved) {
- QString glxExt = QString(QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)));
- if (glxExt.contains(QLatin1String("GLX_SGI_video_sync"))) {
-#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
- void *handle = dlopen(NULL, RTLD_LAZY);
- if (handle) {
- glXGetVideoSyncSGI = (qt_glXGetVideoSyncSGI) dlsym(handle, "glXGetVideoSyncSGI");
- glXWaitVideoSyncSGI = (qt_glXWaitVideoSyncSGI) dlsym(handle, "glXWaitVideoSyncSGI");
- dlclose(handle);
- }
- if (!glXGetVideoSyncSGI)
-#endif
- {
- extern const QString qt_gl_library_name();
- QLibrary lib(qt_gl_library_name());
- glXGetVideoSyncSGI = (qt_glXGetVideoSyncSGI) lib.resolve("glXGetVideoSyncSGI");
- glXWaitVideoSyncSGI = (qt_glXWaitVideoSyncSGI) lib.resolve("glXWaitVideoSyncSGI");
- }
+ const QX11Info *xinfo = qt_x11Info(d->paintDevice);
+ QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen()));
+ if (extensions.match("GLX_SGI_video_sync")) {
+ glXGetVideoSyncSGI = (qt_glXGetVideoSyncSGI)qglx_getProcAddress("glXGetVideoSyncSGI");
+ glXWaitVideoSyncSGI = (qt_glXWaitVideoSyncSGI)qglx_getProcAddress("glXWaitVideoSyncSGI");
}
resolved = true;
}
@@ -930,8 +1107,8 @@ void *QGLContext::getProcAddress(const QString &proc) const
if (resolved && !glXGetProcAddressARB)
return 0;
if (!glXGetProcAddressARB) {
- QString glxExt = QString(QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)));
- if (glxExt.contains(QLatin1String("GLX_ARB_get_proc_address"))) {
+ QGLExtensionMatcher extensions(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS));
+ if (extensions.match("GLX_ARB_get_proc_address")) {
#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
void *handle = dlopen(NULL, RTLD_LAZY);
if (handle) {
@@ -941,9 +1118,11 @@ void *QGLContext::getProcAddress(const QString &proc) const
if (!glXGetProcAddressARB)
#endif
{
+#if !defined(QT_NO_LIBRARY)
extern const QString qt_gl_library_name();
QLibrary lib(qt_gl_library_name());
glXGetProcAddressARB = (qt_glXGetProcAddressARB) lib.resolve("glXGetProcAddressARB");
+#endif
}
}
resolved = true;
@@ -1165,7 +1344,6 @@ void QGLWidget::setContext(QGLContext *context,
QGLContext* oldcx = d->glcx;
d->glcx = context;
-
if (parentWidget()) {
// force creation of delay-created widgets
parentWidget()->winId();
@@ -1173,6 +1351,12 @@ void QGLWidget::setContext(QGLContext *context,
d_func()->xinfo = parentWidget()->d_func()->xinfo;
}
+ // If the application has set WA_TranslucentBackground and not explicitly set
+ // the alpha buffer size to zero, modify the format so it have an alpha channel
+ QGLFormat& fmt = d->glcx->d_func()->glFormat;
+ if (testAttribute(Qt::WA_TranslucentBackground) && fmt.alphaBufferSize() == -1)
+ fmt.setAlphaBufferSize(1);
+
bool createFailed = false;
if (!d->glcx->isValid()) {
if (!d->glcx->create(shareContext ? shareContext : oldcx))
@@ -1404,4 +1588,170 @@ void QGLExtensions::init()
}
}
+// Solaris defines glXBindTexImageEXT as part of the GL library
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+typedef void (*qt_glXBindTexImageEXT)(Display*, GLXDrawable, int, const int*);
+typedef void (*qt_glXReleaseTexImageEXT)(Display*, GLXDrawable, int);
+static qt_glXBindTexImageEXT glXBindTexImageEXT = 0;
+static qt_glXReleaseTexImageEXT glXReleaseTexImageEXT = 0;
+
+static bool qt_resolveTextureFromPixmap(QPaintDevice *paintDevice)
+{
+ static bool resolvedTextureFromPixmap = false;
+
+ if (!resolvedTextureFromPixmap) {
+ resolvedTextureFromPixmap = true;
+
+ // Check to see if we have NPOT texture support
+ if ( !(QGLExtensions::glExtensions & QGLExtensions::NPOTTextures) &&
+ !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0))
+ {
+ return false; // Can't use TFP without NPOT
+ }
+ const QX11Info *xinfo = qt_x11Info(paintDevice);
+ QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen()));
+ if (extensions.match("GLX_EXT_texture_from_pixmap")) {
+ glXBindTexImageEXT = (qt_glXBindTexImageEXT) qglx_getProcAddress("glXBindTexImageEXT");
+ glXReleaseTexImageEXT = (qt_glXReleaseTexImageEXT) qglx_getProcAddress("glXReleaseTexImageEXT");
+ }
+ }
+
+ return glXBindTexImageEXT && glXReleaseTexImageEXT;
+}
+#endif //defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+
+
+QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData *pmd, const qint64 key,
+ QGLContext::BindOptions options)
+{
+#if !defined(GLX_VERSION_1_3) || defined(Q_OS_HPUX)
+ return 0;
+#else
+ Q_Q(QGLContext);
+
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
+
+ if (!qt_resolveTextureFromPixmap(paintDevice))
+ return 0;
+
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
+ const QX11Info &x11Info = pixmapData->xinfo;
+
+ // Store the configs (Can be static because configs aren't dependent on current context)
+ static GLXFBConfig glxRGBPixmapConfig = 0;
+ static bool RGBConfigInverted = false;
+ static GLXFBConfig glxRGBAPixmapConfig = 0;
+ static bool RGBAConfigInverted = false;
+
+ bool hasAlpha = pixmapData->hasAlphaChannel();
+
+ // Check to see if we need a config
+ if ( (hasAlpha && !glxRGBAPixmapConfig) || (!hasAlpha && !glxRGBPixmapConfig) ) {
+ GLXFBConfig *configList = 0;
+ int configCount = 0;
+
+ int configAttribs[] = {
+ hasAlpha ? GLX_BIND_TO_TEXTURE_RGBA_EXT : GLX_BIND_TO_TEXTURE_RGB_EXT, True,
+ GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
+ GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
+ // QGLContext::bindTexture() can't return an inverted texture, but QPainter::drawPixmap() can:
+ GLX_Y_INVERTED_EXT, options & QGLContext::CanFlipNativePixmapBindOption ? GLX_DONT_CARE : False,
+ XNone
+ };
+ configList = glXChooseFBConfig(x11Info.display(), x11Info.screen(), configAttribs, &configCount);
+ if (!configList)
+ return 0;
+
+ int yInv;
+ glXGetFBConfigAttrib(x11Info.display(), configList[0], GLX_Y_INVERTED_EXT, &yInv);
+
+ if (hasAlpha) {
+ glxRGBAPixmapConfig = configList[0];
+ RGBAConfigInverted = yInv;
+ }
+ else {
+ glxRGBPixmapConfig = configList[0];
+ RGBConfigInverted = yInv;
+ }
+
+ XFree(configList);
+ }
+
+ // Check to see if the surface is still valid
+ if (pixmapData->gl_surface &&
+ hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
+ {
+ // Surface is invalid!
+ destroyGlSurfaceForPixmap(pixmapData);
+ }
+
+ // Check to see if we need a surface
+ if (!pixmapData->gl_surface) {
+ GLXPixmap glxPixmap;
+ int pixmapAttribs[] = {
+ GLX_TEXTURE_FORMAT_EXT, hasAlpha ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT,
+ GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
+ GLX_MIPMAP_TEXTURE_EXT, False, // Maybe needs to be don't care
+ XNone
+ };
+
+ // Wrap the X Pixmap into a GLXPixmap:
+ glxPixmap = glXCreatePixmap(x11Info.display(),
+ hasAlpha ? glxRGBAPixmapConfig : glxRGBPixmapConfig,
+ pixmapData->handle(), pixmapAttribs);
+
+ if (!glxPixmap)
+ return 0;
+
+ pixmapData->gl_surface = (Qt::HANDLE)glxPixmap;
+
+ // Make sure the cleanup hook gets called so we can delete the glx pixmap
+ QImagePixmapCleanupHooks::enableCleanupHooks(pixmapData);
+ }
+
+ GLuint textureId;
+ glGenTextures(1, &textureId);
+ glBindTexture(GL_TEXTURE_2D, textureId);
+ glXBindTexImageEXT(x11Info.display(), (GLXPixmap)pixmapData->gl_surface, GLX_FRONT_LEFT_EXT, 0);
+
+ glBindTexture(GL_TEXTURE_2D, textureId);
+
+ if (!((hasAlpha && RGBAConfigInverted) || (!hasAlpha && RGBConfigInverted)))
+ options &= ~QGLContext::InvertedYBindOption;
+
+ QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options);
+ if (texture->options & QGLContext::InvertedYBindOption)
+ pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;
+
+ // We assume the cost of bound pixmaps is zero
+ QGLTextureCache::instance()->insert(q, key, texture, 0);
+
+ return texture;
+#endif //!defined(GLX_VERSION_1_3) || defined(Q_OS_HPUX)
+}
+
+
+void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd)
+{
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
+ if (pixmapData->gl_surface) {
+ glXDestroyPixmap(QX11Info::display(), (GLXPixmap)pixmapData->gl_surface);
+ pixmapData->gl_surface = 0;
+ }
+#endif
+}
+
+void QGLContextPrivate::unbindPixmapFromTexture(QPixmapData* pmd)
+{
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
+ Q_ASSERT(QGLContext::currentContext());
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
+ if (pixmapData->gl_surface)
+ glXReleaseTexImageEXT(QX11Info::display(), (GLXPixmap)pixmapData->gl_surface, GLX_FRONT_LEFT_EXT);
+#endif
+}
+
QT_END_NAMESPACE
diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp
index 4de4b6f..19026b3 100644
--- a/src/opengl/qgl_x11egl.cpp
+++ b/src/opengl/qgl_x11egl.cpp
@@ -41,20 +41,17 @@
#include "qgl.h"
#include <private/qt_x11_p.h>
+#include <private/qpixmap_x11_p.h>
+#include <private/qimagepixmapcleanuphooks_p.h>
#include <private/qgl_p.h>
#include <private/qpaintengine_opengl_p.h>
#include "qgl_egl_p.h"
#include "qcolormap.h"
+#include <QDebug>
QT_BEGIN_NAMESPACE
-
-bool QGLFormat::hasOpenGL()
-{
- return true;
-}
-
bool QGLFormat::hasOpenGLOverlays()
{
return false;
@@ -66,6 +63,7 @@ void qt_egl_add_platform_config(QEglProperties& props, QPaintDevice *device)
props.setPixelFormat(static_cast<QImage *>(device)->format());
}
+// Chooses the EGL config and creates the EGL context
bool QGLContext::chooseContext(const QGLContext* shareContext)
{
Q_D(QGLContext);
@@ -76,141 +74,78 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
int devType = device()->devType();
// Get the display and initialize it.
- d->eglContext = new QEglContext();
- d->eglContext->setApi(QEglContext::OpenGL);
- if (!d->eglContext->openDisplay(device())) {
- delete d->eglContext;
- d->eglContext = 0;
- return false;
- }
+ if (d->eglContext == 0) {
+ d->eglContext = new QEglContext();
+ d->eglContext->setApi(QEgl::OpenGL);
+ if (!d->eglContext->openDisplay(device())) {
+ delete d->eglContext;
+ d->eglContext = 0;
+ return false;
+ }
+
+ // Construct the configuration we need for this surface.
+ QEglProperties configProps;
+ qt_egl_set_format(configProps, devType, d->glFormat);
+ qt_egl_add_platform_config(configProps, device());
+ configProps.setRenderableType(QEgl::OpenGL);
+
+#if We_have_an_EGL_library_which_bothers_to_check_EGL_BUFFER_SIZE
+ if (device()->depth() == 16 && configProps.value(EGL_ALPHA_SIZE) <= 0) {
+ qDebug("Setting EGL_BUFFER_SIZE to 16");
+ configProps.setValue(EGL_BUFFER_SIZE, 16);
+ configProps.setValue(EGL_ALPHA_SIZE, 0);
+ }
+
+ if (!d->eglContext->chooseConfig(configProps, QEgl::BestPixelFormat)) {
+ delete d->eglContext;
+ d->eglContext = 0;
+ return false;
+ }
+#else
+ QEgl::PixelFormatMatch matchType = QEgl::BestPixelFormat;
+ if ((device()->depth() == 16) && configProps.value(EGL_ALPHA_SIZE) == 0) {
+ configProps.setValue(EGL_RED_SIZE, 5);
+ configProps.setValue(EGL_GREEN_SIZE, 6);
+ configProps.setValue(EGL_BLUE_SIZE, 5);
+ configProps.setValue(EGL_ALPHA_SIZE, 0);
+ matchType = QEgl::ExactPixelFormat;
+ }
+
+ // Search for a matching configuration, reducing the complexity
+ // each time until we get something that matches.
+ if (!d->eglContext->chooseConfig(configProps, matchType)) {
+ delete d->eglContext;
+ d->eglContext = 0;
+ return false;
+ }
+#endif
- // Construct the configuration we need for this surface.
- QEglProperties configProps;
- qt_egl_set_format(configProps, devType, d->glFormat);
- qt_egl_add_platform_config(configProps, device());
- configProps.setRenderableType(QEglContext::OpenGL);
-
- // Search for a matching configuration, reducing the complexity
- // each time until we get something that matches.
- if (!d->eglContext->chooseConfig(configProps, QEglContext::BestPixelFormat)) {
- delete d->eglContext;
- d->eglContext = 0;
- return false;
- }
+// qDebug("QGLContext::chooseContext() - using EGL config %d:", d->eglContext->config());
+// qDebug() << QEglProperties(d->eglContext->config()).toString();
- // Inform the higher layers about the actual format properties.
- qt_egl_update_format(*(d->eglContext), d->glFormat);
-
- // Create a new context for the configuration.
- if (!d->eglContext->createContext
- (shareContext ? shareContext->d_func()->eglContext : 0)) {
- delete d->eglContext;
- d->eglContext = 0;
- return false;
- }
+ // Create a new context for the configuration.
+ if (!d->eglContext->createContext
+ (shareContext ? shareContext->d_func()->eglContext : 0)) {
+ delete d->eglContext;
+ d->eglContext = 0;
+ return false;
+ }
+ d->sharing = d->eglContext->isSharing();
+ if (d->sharing && shareContext)
+ const_cast<QGLContext *>(shareContext)->d_func()->sharing = true;
#if defined(EGL_VERSION_1_1)
- if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget)
- eglSwapInterval(d->eglContext->display(), d->glFormat.swapInterval());
+ if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget)
+ eglSwapInterval(d->eglContext->display(), d->glFormat.swapInterval());
#endif
-
- // Create the EGL surface to draw into.
- if (!d->eglContext->createSurface(device())) {
- delete d->eglContext;
- d->eglContext = 0;
- return false;
- }
-
- return true;
-}
-
-
-void QGLContext::reset()
-{
- Q_D(QGLContext);
- if (!d->valid)
- return;
- d->cleanup();
- doneCurrent();
- if (d->eglContext) {
- delete d->eglContext;
- d->eglContext = 0;
- }
- d->crWin = false;
- d->sharing = false;
- d->valid = false;
- d->transpColor = QColor();
- d->initDone = false;
- qgl_share_reg()->removeShare(this);
-}
-
-void QGLContext::makeCurrent()
-{
- Q_D(QGLContext);
- if(!d->valid || !d->eglContext) {
- qWarning("QGLContext::makeCurrent(): Cannot make invalid context current");
- return;
}
- if (d->eglContext->makeCurrent()) {
- if (!qgl_context_storage.hasLocalData() && QThread::currentThread())
- qgl_context_storage.setLocalData(new QGLThreadContext);
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = this;
- currentCtx = this;
- }
-}
-
-void QGLContext::doneCurrent()
-{
- Q_D(QGLContext);
- if (d->eglContext)
- d->eglContext->doneCurrent();
-
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = 0;
- currentCtx = 0;
-}
-
-
-void QGLContext::swapBuffers() const
-{
- Q_D(const QGLContext);
- if(!d->valid || !d->eglContext)
- return;
-
- d->eglContext->swapBuffers();
-}
-
-QColor QGLContext::overlayTransparentColor() const
-{
- return QColor(0, 0, 0); // Invalid color
-}
-
-uint QGLContext::colorIndex(const QColor &c) const
-{
- //### color index doesn't work on egl
- Q_UNUSED(c);
- return 0;
-}
-
-void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase)
-{
- Q_UNUSED(fnt);
- Q_UNUSED(listBase);
-}
-
-void *QGLContext::getProcAddress(const QString &proc) const
-{
- return (void*)eglGetProcAddress(reinterpret_cast<const char *>(proc.toLatin1().data()));
-}
+ // Inform the higher layers about the actual format properties.
+ qt_egl_update_format(*(d->eglContext), d->glFormat);
-void QGLWidget::setMouseTracking(bool enable)
-{
- QWidget::setMouseTracking(enable);
+ return true;
}
-
void QGLWidget::resizeEvent(QResizeEvent *)
{
Q_D(QGLWidget);
@@ -238,6 +173,142 @@ void QGLWidget::updateOverlayGL()
//handle overlay
}
+//#define QT_DEBUG_X11_VISUAL_SELECTION 1
+
+bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig config, const QX11Info &x11Info, bool useArgbVisual)
+{
+ bool foundVisualIsArgb = useArgbVisual;
+
+#ifdef QT_DEBUG_X11_VISUAL_SELECTION
+ qDebug("qt_egl_setup_x11_visual() - useArgbVisual=%d", useArgbVisual);
+#endif
+
+ memset(&vi, 0, sizeof(XVisualInfo));
+
+ EGLint eglConfigColorSize;
+ eglGetConfigAttrib(display, config, EGL_BUFFER_SIZE, &eglConfigColorSize);
+
+ // Check to see if EGL is suggesting an appropriate visual id:
+ EGLint nativeVisualId;
+ eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &nativeVisualId);
+ vi.visualid = nativeVisualId;
+
+ if (vi.visualid) {
+ // EGL has suggested a visual id, so get the rest of the visual info for that id:
+ XVisualInfo *chosenVisualInfo;
+ int matchingCount = 0;
+ chosenVisualInfo = XGetVisualInfo(x11Info.display(), VisualIDMask, &vi, &matchingCount);
+ if (chosenVisualInfo) {
+#if !defined(QT_NO_XRENDER)
+ if (useArgbVisual) {
+ // Check to make sure the visual provided by EGL is ARGB
+ XRenderPictFormat *format;
+ format = XRenderFindVisualFormat(x11Info.display(), chosenVisualInfo->visual);
+ if (format->type == PictTypeDirect && format->direct.alphaMask) {
+#ifdef QT_DEBUG_X11_VISUAL_SELECTION
+ qDebug("Using ARGB X Visual ID (%d) provided by EGL", (int)vi.visualid);
+#endif
+ foundVisualIsArgb = true;
+ vi = *chosenVisualInfo;
+ }
+ else {
+ qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this is not ARGB",
+ nativeVisualId, (int)config);
+ vi.visualid = 0;
+ }
+ } else
+#endif
+ {
+ if (eglConfigColorSize == chosenVisualInfo->depth) {
+#ifdef QT_DEBUG_X11_VISUAL_SELECTION
+ qDebug("Using opaque X Visual ID (%d) provided by EGL", (int)vi.visualid);
+#endif
+ vi = *chosenVisualInfo;
+ } else
+ qWarning("Warning: EGL suggested using X visual ID %d (%d bpp) for config %d (%d bpp), but the depths do not match!",
+ nativeVisualId, chosenVisualInfo->depth, (int)config, eglConfigColorSize);
+ }
+ XFree(chosenVisualInfo);
+ }
+ else {
+ qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this seems to be invalid!",
+ nativeVisualId, (int)config);
+ vi.visualid = 0;
+ }
+ }
+
+ // If EGL does not know the visual ID, so try to select an appropriate one ourselves, first
+ // using XRender if we're supposed to have an alpha, then falling back to XGetVisualInfo
+
+#if !defined(QT_NO_XRENDER)
+ if (vi.visualid == 0 && useArgbVisual) {
+ // Try to use XRender to find an ARGB visual we can use
+ vi.screen = x11Info.screen();
+ vi.depth = 32; //### We might at some point (soon) get ARGB4444
+ vi.c_class = TrueColor;
+ XVisualInfo *matchingVisuals;
+ int matchingCount = 0;
+ matchingVisuals = XGetVisualInfo(x11Info.display(),
+ VisualScreenMask|VisualDepthMask|VisualClassMask,
+ &vi, &matchingCount);
+
+ for (int i = 0; i < matchingCount; ++i) {
+ XRenderPictFormat *format;
+ format = XRenderFindVisualFormat(x11Info.display(), matchingVisuals[i].visual);
+ if (format->type == PictTypeDirect && format->direct.alphaMask) {
+ vi = matchingVisuals[i];
+ foundVisualIsArgb = true;
+#ifdef QT_DEBUG_X11_VISUAL_SELECTION
+ qDebug("Using X Visual ID (%d) for ARGB visual as provided by XRender", (int)vi.visualid);
+#endif
+ break;
+ }
+ }
+ XFree(matchingVisuals);
+ }
+#endif
+
+ if (vi.visualid == 0) {
+ EGLint depth;
+ eglGetConfigAttrib(display, config, EGL_BUFFER_SIZE, &depth);
+ int err;
+ err = XMatchVisualInfo(x11Info.display(), x11Info.screen(), depth, TrueColor, &vi);
+ if (err == 0) {
+ qWarning("Warning: Can't find an X visual which matches the EGL config(%d)'s depth (%d)!",
+ (int)config, depth);
+ depth = x11Info.depth();
+ err = XMatchVisualInfo(x11Info.display(), x11Info.screen(), depth, TrueColor, &vi);
+ if (err == 0) {
+ qWarning("Error: Couldn't get any matching X visual!");
+ return false;
+ } else
+ qWarning(" - Falling back to X11 suggested depth (%d)", depth);
+ }
+#ifdef QT_DEBUG_X11_VISUAL_SELECTION
+ else
+ qDebug("Using X Visual ID (%d) for EGL provided depth (%d)", (int)vi.visualid, depth);
+#endif
+
+ // Don't try to use ARGB now unless the visual is 32-bit - even then it might stil fail :-(
+ if (useArgbVisual)
+ foundVisualIsArgb = vi.depth == 32; //### We might at some point (soon) get ARGB4444
+ }
+
+#ifdef QT_DEBUG_X11_VISUAL_SELECTION
+ qDebug("Visual Info:");
+ qDebug(" bits_per_rgb=%d", vi.bits_per_rgb);
+ qDebug(" red_mask=0x%x", vi.red_mask);
+ qDebug(" green_mask=0x%x", vi.green_mask);
+ qDebug(" blue_mask=0x%x", vi.blue_mask);
+ qDebug(" colormap_size=%d", vi.colormap_size);
+ qDebug(" c_class=%d", vi.c_class);
+ qDebug(" depth=%d", vi.depth);
+ qDebug(" screen=%d", vi.screen);
+ qDebug(" visualid=%d", vi.visualid);
+#endif
+ return foundVisualIsArgb;
+}
+
void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext)
{
Q_D(QGLWidget);
@@ -262,21 +333,44 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext,
d_func()->xinfo = parentWidget()->d_func()->xinfo;
}
+ // If the application has set WA_TranslucentBackground and not explicitly set
+ // the alpha buffer size to zero, modify the format so it have an alpha channel
+ QGLFormat& fmt = d->glcx->d_func()->glFormat;
+ const bool tryArgbVisual = testAttribute(Qt::WA_TranslucentBackground) || fmt.alpha();
+ if (tryArgbVisual && fmt.alphaBufferSize() == -1)
+ fmt.setAlphaBufferSize(1);
+
+ bool createFailed = false;
+ if (!d->glcx->isValid()) {
+ // Create the QGLContext here, which in turn chooses the EGL config
+ // and creates the EGL context:
+ if (!d->glcx->create(shareContext ? shareContext : oldcx))
+ createFailed = true;
+ }
+ if (createFailed) {
+ if (deleteOldContext)
+ delete oldcx;
+ return;
+ }
+
+ if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) {
+ if (deleteOldContext)
+ delete oldcx;
+ return;
+ }
+
bool visible = isVisible();
if (visible)
hide();
XVisualInfo vi;
-
- int err = XMatchVisualInfo(x11Info().display(), x11Info().screen(), x11Info().depth(), TrueColor, &vi);
- if (err == 0) {
- qWarning("Error: Couldn't get a matching X visual for format");
- return;
- }
+ QEglContext *eglContext = d->glcx->d_func()->eglContext;
+ bool usingArgbVisual = qt_egl_setup_x11_visual(vi, eglContext->display(), eglContext->config(),
+ x11Info(), tryArgbVisual);
XSetWindowAttributes a;
- Window p = RootWindow(X11->display, vi.screen);
+ Window p = RootWindow(x11Info().display(), x11Info().screen());
if (parentWidget())
p = parentWidget()->winId();
@@ -284,9 +378,14 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext,
a.background_pixel = colmap.pixel(palette().color(backgroundRole()));
a.border_pixel = colmap.pixel(Qt::black);
- Window w = XCreateWindow(X11->display, p, x(), y(), width(), height(),
- 0, vi.depth, InputOutput, vi.visual,
- CWBackPixel|CWBorderPixel, &a);
+ unsigned int valueMask = CWBackPixel|CWBorderPixel;
+ if (usingArgbVisual) {
+ a.colormap = XCreateColormap(x11Info().display(), p, vi.visual, AllocNone);
+ valueMask |= CWColormap;
+ }
+
+ Window w = XCreateWindow(x11Info().display(), p, x(), y(), width(), height(),
+ 0, vi.depth, InputOutput, vi.visual, valueMask, &a);
if (deleteOldContext)
delete oldcx;
@@ -294,28 +393,22 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext,
create(w); // Create with the ID of the window we've just created
- d->eglSurfaceWindowId = w; // Remember the window id we created the surface for
- if (visible)
- show();
-
- bool createFailed = false;
- if (!d->glcx->isValid()) {
- if (!d->glcx->create(shareContext ? shareContext : oldcx))
- createFailed = true;
- }
- if (createFailed) {
- if (deleteOldContext)
- delete oldcx;
+ // Create the EGL surface to draw into.
+ QGLContextPrivate *ctxpriv = d->glcx->d_func();
+ ctxpriv->eglSurface = ctxpriv->eglContext->createSurface(this);
+ if (ctxpriv->eglSurface == EGL_NO_SURFACE) {
+ delete ctxpriv->eglContext;
+ ctxpriv->eglContext = 0;
return;
}
- if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) {
- if (deleteOldContext)
- delete oldcx;
- return;
- }
+ d->eglSurfaceWindowId = w; // Remember the window id we created the surface for
+
+ if (visible)
+ show();
+ XFlush(X11->display);
d->glcx->setWindowCreated(true);
}
@@ -331,11 +424,6 @@ void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget* shareWidget)
}
}
-bool QGLWidgetPrivate::renderCxPm(QPixmap*)
-{
- return false;
-}
-
void QGLWidgetPrivate::cleanupColormaps()
{
}
@@ -356,7 +444,14 @@ void QGLExtensions::init()
if (init_done)
return;
init_done = true;
+
+ // We need a context current to initialize the extensions.
+ QGLWidget tmpWidget;
+ tmpWidget.makeCurrent();
+
init_extensions();
+
+ tmpWidget.doneCurrent();
}
// Re-creates the EGL surface if the window ID has changed or if force is true
@@ -368,11 +463,232 @@ void QGLWidgetPrivate::recreateEglSurface(bool force)
if ( force || (currentId != eglSurfaceWindowId) ) {
// The window id has changed so we need to re-create the EGL surface
- if (!glcx->d_func()->eglContext->recreateSurface(q))
+ QEglContext *ctx = glcx->d_func()->eglContext;
+ EGLSurface surface = glcx->d_func()->eglSurface;
+ if (surface != EGL_NO_SURFACE)
+ ctx->destroySurface(surface); // Will force doneCurrent() if nec.
+ surface = ctx->createSurface(q);
+ if (surface == EGL_NO_SURFACE)
qWarning("Error creating EGL window surface: 0x%x", eglGetError());
+ glcx->d_func()->eglSurface = surface;
eglSurfaceWindowId = currentId;
}
}
+// Selects which configs should be used
+EGLConfig Q_OPENGL_EXPORT qt_chooseEGLConfigForPixmap(bool hasAlpha, bool readOnly)
+{
+ // Cache the configs we select as they wont change:
+ static EGLConfig roPixmapRGBConfig = 0;
+ static EGLConfig roPixmapRGBAConfig = 0;
+ static EGLConfig rwPixmapRGBConfig = 0;
+ static EGLConfig rwPixmapRGBAConfig = 0;
+
+ EGLConfig* targetConfig;
+
+ if (hasAlpha) {
+ if (readOnly)
+ targetConfig = &roPixmapRGBAConfig;
+ else
+ targetConfig = &rwPixmapRGBAConfig;
+ }
+ else {
+ if (readOnly)
+ targetConfig = &roPixmapRGBConfig;
+ else
+ targetConfig = &rwPixmapRGBConfig;
+ }
+
+ if (*targetConfig == 0) {
+ QEglProperties configAttribs;
+ configAttribs.setValue(EGL_SURFACE_TYPE, EGL_PIXMAP_BIT);
+ configAttribs.setRenderableType(QEgl::OpenGL);
+ if (hasAlpha)
+ configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE);
+ else
+ configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE);
+
+ // If this is going to be a render target, it needs to have a depth, stencil & sample buffer
+ if (!readOnly) {
+ configAttribs.setValue(EGL_DEPTH_SIZE, 1);
+ configAttribs.setValue(EGL_STENCIL_SIZE, 1);
+ configAttribs.setValue(EGL_SAMPLE_BUFFERS, 1);
+ }
+
+ EGLint configCount = 0;
+ do {
+ eglChooseConfig(QEglContext::defaultDisplay(0), configAttribs.properties(), targetConfig, 1, &configCount);
+ if (configCount > 0) {
+ // Got one
+ qDebug() << "Found an" << (hasAlpha ? "ARGB" : "RGB") << (readOnly ? "readonly" : "target" )
+ << "config (" << int(*targetConfig) << ") to create a pixmap surface:";
+
+// QEglProperties configProps(*targetConfig);
+// qDebug() << configProps.toString();
+ break;
+ }
+ qWarning("choosePixmapConfig() - No suitible config found, reducing requirements");
+ } while (configAttribs.reduceConfiguration());
+ }
+
+ if (*targetConfig == 0)
+ qWarning("choosePixmapConfig() - Couldn't find a suitable config");
+
+ return *targetConfig;
+}
+
+bool Q_OPENGL_EXPORT qt_createEGLSurfaceForPixmap(QPixmapData* pmd, bool readOnly)
+{
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
+ QX11PixmapData* pixmapData = static_cast<QX11PixmapData*>(pmd);
+
+ bool hasAlpha = pixmapData->hasAlphaChannel();
+
+ EGLConfig pixmapConfig = qt_chooseEGLConfigForPixmap(hasAlpha, readOnly);
+
+ QEglProperties pixmapAttribs;
+
+ // If the pixmap can't be bound to a texture, it's pretty useless
+ pixmapAttribs.setValue(EGL_TEXTURE_TARGET, EGL_TEXTURE_2D);
+ if (hasAlpha)
+ pixmapAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA);
+ else
+ pixmapAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB);
+
+ EGLSurface pixmapSurface;
+ pixmapSurface = eglCreatePixmapSurface(QEglContext::defaultDisplay(0),
+ pixmapConfig,
+ (EGLNativePixmapType) pixmapData->handle(),
+ pixmapAttribs.properties());
+// qDebug("qt_createEGLSurfaceForPixmap() created surface 0x%x for pixmap 0x%x",
+// pixmapSurface, pixmapData->handle());
+ if (pixmapSurface == EGL_NO_SURFACE) {
+ qWarning() << "Failed to create a pixmap surface using config" << (int)pixmapConfig
+ << ":" << QEglContext::errorString(eglGetError());
+ return false;
+ }
+
+ static bool doneOnce = false;
+ if (!doneOnce) {
+ // Make sure QGLTextureCache is instanciated so it can install cleanup hooks
+ // which cleanup the EGL surface.
+ QGLTextureCache::instance();
+ doneOnce = true;
+ }
+
+ Q_ASSERT(sizeof(Qt::HANDLE) >= sizeof(EGLSurface)); // Just to make totally sure!
+ pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface;
+ QImagePixmapCleanupHooks::enableCleanupHooks(pixmapData); // Make sure the cleanup hook gets called
+
+ return true;
+}
+
+
+QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, const qint64 key,
+ QGLContext::BindOptions options)
+{
+ Q_Q(QGLContext);
+
+ // The EGL texture_from_pixmap has no facility to invert the y coordinate
+ if (!(options & QGLContext::CanFlipNativePixmapBindOption))
+ return 0;
+
+ Q_ASSERT(pd->classId() == QPixmapData::X11Class);
+
+ static bool checkedForTFP = false;
+ static bool haveTFP = false;
+
+ if (!checkedForTFP) {
+ // Check for texture_from_pixmap egl extension
+ checkedForTFP = true;
+ if (eglContext->hasExtension("EGL_NOKIA_texture_from_pixmap") ||
+ eglContext->hasExtension("EGL_EXT_texture_from_pixmap"))
+ {
+ qDebug("Found texture_from_pixmap EGL extension!");
+ haveTFP = true;
+ }
+ }
+
+ if (!haveTFP)
+ return 0;
+
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pd);
+
+ bool hasAlpha = pixmapData->hasAlphaChannel();
+
+ // Check to see if the surface is still valid
+ if (pixmapData->gl_surface &&
+ hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
+ {
+ // Surface is invalid!
+ destroyGlSurfaceForPixmap(pixmapData);
+ }
+
+ if (pixmapData->gl_surface == 0) {
+ bool success = qt_createEGLSurfaceForPixmap(pixmapData, true);
+ if (!success) {
+ haveTFP = false;
+ return 0;
+ }
+ }
+
+ Q_ASSERT(pixmapData->gl_surface);
+
+ GLuint textureId;
+ glGenTextures(1, &textureId);
+ glBindTexture(GL_TEXTURE_2D, textureId);
+
+ // bind the egl pixmap surface to a texture
+ EGLBoolean success;
+ success = eglBindTexImage(eglContext->display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER);
+ if (success == EGL_FALSE) {
+ qWarning() << "eglBindTexImage() failed:" << eglContext->errorString(eglGetError());
+ eglDestroySurface(eglContext->display(), (EGLSurface)pixmapData->gl_surface);
+ pixmapData->gl_surface = (Qt::HANDLE)EGL_NO_SURFACE;
+ haveTFP = false;
+ return 0;
+ }
+
+ QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options);
+ pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;
+
+ // We assume the cost of bound pixmaps is zero
+ QGLTextureCache::instance()->insert(q, key, texture, 0);
+
+ glBindTexture(GL_TEXTURE_2D, textureId);
+ return texture;
+}
+
+void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd)
+{
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
+ if (pixmapData->gl_surface) {
+ EGLBoolean success;
+ success = eglDestroySurface(QEglContext::defaultDisplay(0), (EGLSurface)pixmapData->gl_surface);
+ if (success == EGL_FALSE) {
+ qWarning() << "destroyGlSurfaceForPixmap() - Error deleting surface: "
+ << QEglContext::errorString(eglGetError());
+ }
+ pixmapData->gl_surface = 0;
+ }
+}
+
+void QGLContextPrivate::unbindPixmapFromTexture(QPixmapData* pmd)
+{
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
+ if (pixmapData->gl_surface) {
+ EGLBoolean success;
+ success = eglReleaseTexImage(QEglContext::defaultDisplay(0),
+ (EGLSurface)pixmapData->gl_surface,
+ EGL_BACK_BUFFER);
+ if (success == EGL_FALSE) {
+ qWarning() << "unbindPixmapFromTexture() - Unable to release bound texture: "
+ << QEglContext::errorString(eglGetError());
+ }
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/opengl/qglcolormap.cpp b/src/opengl/qglcolormap.cpp
index c86697f..b86f9e0 100644
--- a/src/opengl/qglcolormap.cpp
+++ b/src/opengl/qglcolormap.cpp
@@ -42,14 +42,14 @@
/*!
\class QGLColormap
\brief The QGLColormap class is used for installing custom colormaps into
- QGLWidgets.
+ a QGLWidget.
\module OpenGL
- \ingroup multimedia
+ \ingroup painting-3D
\ingroup shared
QGLColormap provides a platform independent way of specifying and
- installing indexed colormaps into QGLWidgets. QGLColormap is
+ installing indexed colormaps for a QGLWidget. QGLColormap is
especially useful when using the OpenGL color-index mode.
Under X11 you must use an X server that supports either a \c
@@ -61,7 +61,7 @@
least a \c PseudoColor visual. Note that you may experience
colormap flashing if your X server is running in 8 bit mode.
- Under Windows the size of the colormap is always set to 256
+ The size() of the colormap is always set to 256
colors. Note that under Windows you can also install colormaps
in child widgets.
@@ -174,13 +174,14 @@ void QGLColormap::setEntry(int idx, QRgb color)
detach();
if (!d->cells)
d->cells = new QVector<QRgb>(256);
- d->cells->insert(idx, color);
+ d->cells->replace(idx, color);
}
/*!
Set an array of cells in this colormap. \a count is the number of
colors that should be set, \a colors is the array of colors, and
- \a base is the starting index.
+ \a base is the starting index. The first element in \a colors
+ is set at \a base in the colormap.
*/
void QGLColormap::setEntries(int count, const QRgb *colors, int base)
{
@@ -188,10 +189,10 @@ void QGLColormap::setEntries(int count, const QRgb *colors, int base)
if (!d->cells)
d->cells = new QVector<QRgb>(256);
- Q_ASSERT_X(!colors || base >= 0 || base + count < d->cells->size(), "QGLColormap::setEntries",
+ Q_ASSERT_X(colors && base >= 0 && (base + count) <= d->cells->size(), "QGLColormap::setEntries",
"preconditions not met");
- for (int i = base; i < base + count; ++i)
- setEntry(i, colors[i]);
+ for (int i = 0; i < count; ++i)
+ setEntry(base + i, colors[i]);
}
/*!
@@ -227,8 +228,17 @@ QColor QGLColormap::entryColor(int idx) const
}
/*!
- Returns true if the colormap is empty; otherwise returns false. A
- colormap with no color values set is considered to be empty.
+ Returns true if the colormap is empty or it is not in use
+ by a QGLWidget; otherwise returns false.
+
+ A colormap with no color values set is considered to be empty.
+ For historical reasons, a colormap that has color values set
+ but which is not in use by a QGLWidget is also considered empty.
+
+ Compare size() with zero to determine if the colormap is empty
+ regardless of whether it is in use by a QGLWidget or not.
+
+ \sa size()
*/
bool QGLColormap::isEmpty() const
{
diff --git a/src/opengl/qglextensions.cpp b/src/opengl/qglextensions.cpp
index 305b175..c785d8a 100644
--- a/src/opengl/qglextensions.cpp
+++ b/src/opengl/qglextensions.cpp
@@ -43,11 +43,63 @@
QT_BEGIN_NAMESPACE
+static void *qt_gl_getProcAddress_search
+ (QGLContext *ctx, const char *name1, const char *name2,
+ const char *name3, const char *name4)
+{
+ void *addr;
+
+ addr = ctx->getProcAddress(QLatin1String(name1));
+ if (addr)
+ return addr;
+
+ addr = ctx->getProcAddress(QLatin1String(name2));
+ if (addr)
+ return addr;
+
+ addr = ctx->getProcAddress(QLatin1String(name3));
+ if (addr)
+ return addr;
+
+ if (name4)
+ return ctx->getProcAddress(QLatin1String(name4));
+
+ return 0;
+}
+
+// Search for an extension function starting with the most likely
+// function suffix first, and then trying the other variations.
+#if defined(QT_OPENGL_ES)
+#define qt_gl_getProcAddress(ctx,name) \
+ qt_gl_getProcAddress_search((ctx), name, name "OES", name "EXT", name "ARB")
+#define qt_gl_getProcAddressEXT(ctx,name) \
+ qt_gl_getProcAddress_search((ctx), name "OES", name, name "EXT", name "ARB")
+#define qt_gl_getProcAddressARB(ctx,name) \
+ qt_gl_getProcAddress_search((ctx), name "OES", name, name "ARB", name "EXT")
+#define qt_gl_getProcAddressOES(ctx,name) \
+ qt_gl_getProcAddress_search((ctx), name "OES", name, name "EXT", name "ARB")
+#else
+#define qt_gl_getProcAddress(ctx,name) \
+ qt_gl_getProcAddress_search((ctx), name, name "ARB", name "EXT", 0)
+#define qt_gl_getProcAddressEXT(ctx,name) \
+ qt_gl_getProcAddress_search((ctx), name "EXT", name, name "ARB", 0)
+#define qt_gl_getProcAddressARB(ctx,name) \
+ qt_gl_getProcAddress_search((ctx), name "ARB", name, name "EXT", 0)
+#define qt_gl_getProcAddressOES(ctx,name) \
+ qt_gl_getProcAddress_search((ctx), name "OES", name, name "EXT", name "ARB")
+#endif
+
bool qt_resolve_framebufferobject_extensions(QGLContext *ctx)
{
-#if !defined(QT_OPENGL_ES_2)
- if (glIsRenderbufferEXT != 0)
+#if defined(QT_OPENGL_ES_2)
+ static bool have_resolved = false;
+ if (have_resolved)
return true;
+ have_resolved = true;
+#else
+ if (glIsRenderbuffer != 0)
+ return true;
+#endif
if (ctx == 0) {
qWarning("QGLFramebufferObject: Unable to resolve framebuffer object extensions -"
@@ -55,32 +107,39 @@ bool qt_resolve_framebufferobject_extensions(QGLContext *ctx)
return false;
}
- glIsRenderbufferEXT = (_glIsRenderbufferEXT) ctx->getProcAddress(QLatin1String("glIsRenderbufferEXT"));
- glBindRenderbufferEXT = (_glBindRenderbufferEXT) ctx->getProcAddress(QLatin1String("glBindRenderbufferEXT"));
- glDeleteRenderbuffersEXT = (_glDeleteRenderbuffersEXT) ctx->getProcAddress(QLatin1String("glDeleteRenderbuffersEXT"));
- glGenRenderbuffersEXT = (_glGenRenderbuffersEXT) ctx->getProcAddress(QLatin1String("glGenRenderbuffersEXT"));
- glRenderbufferStorageEXT = (_glRenderbufferStorageEXT) ctx->getProcAddress(QLatin1String("glRenderbufferStorageEXT"));
- glGetRenderbufferParameterivEXT =
- (_glGetRenderbufferParameterivEXT) ctx->getProcAddress(QLatin1String("glGetRenderbufferParameterivEXT"));
- glIsFramebufferEXT = (_glIsFramebufferEXT) ctx->getProcAddress(QLatin1String("glIsFramebufferEXT"));
- glBindFramebufferEXT = (_glBindFramebufferEXT) ctx->getProcAddress(QLatin1String("glBindFramebufferEXT"));
- glDeleteFramebuffersEXT = (_glDeleteFramebuffersEXT) ctx->getProcAddress(QLatin1String("glDeleteFramebuffersEXT"));
- glGenFramebuffersEXT = (_glGenFramebuffersEXT) ctx->getProcAddress(QLatin1String("glGenFramebuffersEXT"));
- glCheckFramebufferStatusEXT = (_glCheckFramebufferStatusEXT) ctx->getProcAddress(QLatin1String("glCheckFramebufferStatusEXT"));
- glFramebufferTexture1DEXT = (_glFramebufferTexture1DEXT) ctx->getProcAddress(QLatin1String("glFramebufferTexture1DEXT"));
- glFramebufferTexture2DEXT = (_glFramebufferTexture2DEXT) ctx->getProcAddress(QLatin1String("glFramebufferTexture2DEXT"));
- glFramebufferTexture3DEXT = (_glFramebufferTexture3DEXT) ctx->getProcAddress(QLatin1String("glFramebufferTexture3DEXT"));
- glFramebufferRenderbufferEXT = (_glFramebufferRenderbufferEXT) ctx->getProcAddress(QLatin1String("glFramebufferRenderbufferEXT"));
- glGetFramebufferAttachmentParameterivEXT =
- (_glGetFramebufferAttachmentParameterivEXT) ctx->getProcAddress(QLatin1String("glGetFramebufferAttachmentParameterivEXT"));
- glGenerateMipmapEXT = (_glGenerateMipmapEXT) ctx->getProcAddress(QLatin1String("glGenerateMipmapEXT"));
- return glIsRenderbufferEXT;
+
+ glBlitFramebufferEXT = (_glBlitFramebufferEXT) qt_gl_getProcAddressEXT(ctx, "glBlitFramebuffer");
+ glRenderbufferStorageMultisampleEXT =
+ (_glRenderbufferStorageMultisampleEXT) qt_gl_getProcAddressEXT(ctx, "glRenderbufferStorageMultisample");
+
+#if !defined(QT_OPENGL_ES_2)
+ glIsRenderbuffer = (_glIsRenderbuffer) qt_gl_getProcAddressEXT(ctx, "glIsRenderbuffer");
+ if (!glIsRenderbuffer)
+ return false; // Not much point searching for anything else.
+ glBindRenderbuffer = (_glBindRenderbuffer) qt_gl_getProcAddressEXT(ctx, "glBindRenderbuffer");
+ glDeleteRenderbuffers = (_glDeleteRenderbuffers) qt_gl_getProcAddressEXT(ctx, "glDeleteRenderbuffers");
+ glGenRenderbuffers = (_glGenRenderbuffers) qt_gl_getProcAddressEXT(ctx, "glGenRenderbuffers");
+ glRenderbufferStorage = (_glRenderbufferStorage) qt_gl_getProcAddressEXT(ctx, "glRenderbufferStorage");
+ glGetRenderbufferParameteriv =
+ (_glGetRenderbufferParameteriv) qt_gl_getProcAddressEXT(ctx, "glGetRenderbufferParameteriv");
+ glIsFramebuffer = (_glIsFramebuffer) qt_gl_getProcAddressEXT(ctx, "glIsFramebuffer");
+ glBindFramebuffer = (_glBindFramebuffer) qt_gl_getProcAddressEXT(ctx, "glBindFramebuffer");
+ glDeleteFramebuffers = (_glDeleteFramebuffers) qt_gl_getProcAddressEXT(ctx, "glDeleteFramebuffers");
+ glGenFramebuffers = (_glGenFramebuffers) qt_gl_getProcAddressEXT(ctx, "glGenFramebuffers");
+ glCheckFramebufferStatus = (_glCheckFramebufferStatus) qt_gl_getProcAddressEXT(ctx, "glCheckFramebufferStatus");
+ glFramebufferTexture2D = (_glFramebufferTexture2D) qt_gl_getProcAddressEXT(ctx, "glFramebufferTexture2D");
+ glFramebufferRenderbuffer = (_glFramebufferRenderbuffer) qt_gl_getProcAddressEXT(ctx, "glFramebufferRenderbuffer");
+ glGetFramebufferAttachmentParameteriv =
+ (_glGetFramebufferAttachmentParameteriv) qt_gl_getProcAddressEXT(ctx, "glGetFramebufferAttachmentParameteriv");
+ glGenerateMipmap = (_glGenerateMipmap) qt_gl_getProcAddressEXT(ctx, "glGenerateMipmap");
+
+ return glIsRenderbuffer != 0;
#else
- Q_UNUSED(ctx);
return true;
#endif
}
+#if !defined(QT_OPENGL_ES_2)
bool qt_resolve_version_1_3_functions(QGLContext *ctx)
{
if (glMultiTexCoord4f != 0)
@@ -89,14 +148,12 @@ bool qt_resolve_version_1_3_functions(QGLContext *ctx)
QGLContext cx(QGLFormat::defaultFormat());
glMultiTexCoord4f = (_glMultiTexCoord4f) ctx->getProcAddress(QLatin1String("glMultiTexCoord4f"));
-#if defined(QT_OPENGL_ES_2)
- return glMultiTexCoord4f;
-#else
glActiveTexture = (_glActiveTexture) ctx->getProcAddress(QLatin1String("glActiveTexture"));
return glMultiTexCoord4f && glActiveTexture;
-#endif
}
+#endif
+#if !defined(QT_OPENGL_ES_2)
bool qt_resolve_stencil_face_extension(QGLContext *ctx)
{
if (glActiveStencilFaceEXT != 0)
@@ -107,7 +164,10 @@ bool qt_resolve_stencil_face_extension(QGLContext *ctx)
return glActiveStencilFaceEXT;
}
+#endif
+
+#if !defined(QT_OPENGL_ES_2)
bool qt_resolve_frag_program_extensions(QGLContext *ctx)
{
if (glProgramStringARB != 0)
@@ -126,60 +186,219 @@ bool qt_resolve_frag_program_extensions(QGLContext *ctx)
&& glGenProgramsARB
&& glProgramLocalParameter4fvARB;
}
+#endif
+
bool qt_resolve_buffer_extensions(QGLContext *ctx)
{
- if (glBindBufferARB && glDeleteBuffersARB && glGenBuffersARB && glBufferDataARB
- && glMapBufferARB && glUnmapBufferARB)
+ if (glMapBufferARB && glUnmapBufferARB
+#if !defined(QT_OPENGL_ES_2)
+ && glBindBuffer && glDeleteBuffers && glGenBuffers && glBufferData
+#endif
+ )
return true;
- glBindBufferARB = (_glBindBufferARB) ctx->getProcAddress(QLatin1String("glBindBufferARB"));
- glDeleteBuffersARB = (_glDeleteBuffersARB) ctx->getProcAddress(QLatin1String("glDeleteBuffersARB"));
- glGenBuffersARB = (_glGenBuffersARB) ctx->getProcAddress(QLatin1String("glGenBuffersARB"));
- glBufferDataARB = (_glBufferDataARB) ctx->getProcAddress(QLatin1String("glBufferDataARB"));
- glMapBufferARB = (_glMapBufferARB) ctx->getProcAddress(QLatin1String("glMapBufferARB"));
- glUnmapBufferARB = (_glUnmapBufferARB) ctx->getProcAddress(QLatin1String("glUnmapBufferARB"));
-
- return glBindBufferARB
- && glDeleteBuffersARB
- && glGenBuffersARB
- && glBufferDataARB
- && glMapBufferARB
- && glUnmapBufferARB;
+#if !defined(QT_OPENGL_ES_2)
+ glBindBuffer = (_glBindBuffer) qt_gl_getProcAddressARB(ctx, "glBindBuffer");
+ glDeleteBuffers = (_glDeleteBuffers) qt_gl_getProcAddressARB(ctx, "glDeleteBuffers");
+ glGenBuffers = (_glGenBuffers) qt_gl_getProcAddressARB(ctx, "glGenBuffers");
+ glBufferData = (_glBufferData) qt_gl_getProcAddressARB(ctx, "glBufferData");
+#endif
+ glMapBufferARB = (_glMapBufferARB) qt_gl_getProcAddressARB(ctx, "glMapBuffer");
+ glUnmapBufferARB = (_glUnmapBufferARB) qt_gl_getProcAddressARB(ctx, "glUnmapBuffer");
+
+ return glMapBufferARB
+ && glUnmapBufferARB
+#if !defined(QT_OPENGL_ES_2)
+ && glBindBuffer
+ && glDeleteBuffers
+ && glGenBuffers
+ && glBufferData
+#endif
+ ;
}
bool qt_resolve_glsl_extensions(QGLContext *ctx)
{
+#if defined(QT_OPENGL_ES_2)
+ // The GLSL shader functions are always present in OpenGL/ES 2.0.
+ // The only exceptions are glGetProgramBinaryOES and glProgramBinaryOES.
+ if (!QGLContextPrivate::extensionFuncs(ctx).qt_glslResolved) {
+ glGetProgramBinaryOES = (_glGetProgramBinaryOES) ctx->getProcAddress(QLatin1String("glGetProgramBinaryOES"));
+ glProgramBinaryOES = (_glProgramBinaryOES) ctx->getProcAddress(QLatin1String("glProgramBinaryOES"));
+ QGLContextPrivate::extensionFuncs(ctx).qt_glslResolved = true;
+ }
+ return true;
+#else
if (glCreateShader)
return true;
glCreateShader = (_glCreateShader) ctx->getProcAddress(QLatin1String("glCreateShader"));
- glShaderSource = (_glShaderSource) ctx->getProcAddress(QLatin1String("glShaderSource"));
- glCompileShader = (_glCompileShader) ctx->getProcAddress(QLatin1String("glCompileShader"));
- glDeleteShader = (_glDeleteShader) ctx->getProcAddress(QLatin1String("glDeleteShader"));
-
- glCreateProgram = (_glCreateProgram) ctx->getProcAddress(QLatin1String("glCreateProgram"));
- glAttachShader = (_glAttachShader) ctx->getProcAddress(QLatin1String("glAttachShader"));
- glDetachShader = (_glDetachShader) ctx->getProcAddress(QLatin1String("glDetachShader"));
- glLinkProgram = (_glLinkProgram) ctx->getProcAddress(QLatin1String("glLinkProgram"));
- glUseProgram = (_glUseProgram) ctx->getProcAddress(QLatin1String("glUseProgram"));
- glDeleteProgram = (_glDeleteProgram) ctx->getProcAddress(QLatin1String("glDeleteProgram"));
-
- glGetShaderInfoLog = (_glGetShaderInfoLog) ctx->getProcAddress(QLatin1String("glGetShaderInfoLog"));
- glGetShaderiv = (_glGetShaderiv) ctx->getProcAddress(QLatin1String("glGetShaderiv"));
- glGetProgramiv = (_glGetProgramiv) ctx->getProcAddress(QLatin1String("glGetProgramiv"));
-
- glGetUniformLocation = (_glGetUniformLocation) ctx->getProcAddress(QLatin1String("glGetUniformLocation"));
- glUniform4fv = (_glUniform4fv) ctx->getProcAddress(QLatin1String("glUniform4fv"));
- glUniform3fv = (_glUniform3fv) ctx->getProcAddress(QLatin1String("glUniform3fv"));
- glUniform2fv = (_glUniform2fv) ctx->getProcAddress(QLatin1String("glUniform2fv"));
- glUniform1fv = (_glUniform1fv) ctx->getProcAddress(QLatin1String("glUniform1fv"));
- glUniform1i = (_glUniform1i) ctx->getProcAddress(QLatin1String("glUniform1i"));
-
- return glCreateShader && glShaderSource && glCompileShader && glDeleteProgram &&
- glCreateProgram && glAttachShader && glDetachShader && glLinkProgram && glUseProgram &&
- glDeleteProgram && glGetShaderInfoLog && glGetShaderiv && glGetProgramiv && glGetUniformLocation &&
- glUniform1i && glUniform1fv && glUniform2fv && glUniform3fv && glUniform4fv;
+ if (glCreateShader) {
+ glShaderSource = (_glShaderSource) ctx->getProcAddress(QLatin1String("glShaderSource"));
+ glShaderBinary = (_glShaderBinary) ctx->getProcAddress(QLatin1String("glShaderBinary"));
+ glCompileShader = (_glCompileShader) ctx->getProcAddress(QLatin1String("glCompileShader"));
+ glDeleteShader = (_glDeleteShader) ctx->getProcAddress(QLatin1String("glDeleteShader"));
+ glIsShader = (_glIsShader) ctx->getProcAddress(QLatin1String("glIsShader"));
+
+ glCreateProgram = (_glCreateProgram) ctx->getProcAddress(QLatin1String("glCreateProgram"));
+ glAttachShader = (_glAttachShader) ctx->getProcAddress(QLatin1String("glAttachShader"));
+ glDetachShader = (_glDetachShader) ctx->getProcAddress(QLatin1String("glDetachShader"));
+ glLinkProgram = (_glLinkProgram) ctx->getProcAddress(QLatin1String("glLinkProgram"));
+ glUseProgram = (_glUseProgram) ctx->getProcAddress(QLatin1String("glUseProgram"));
+ glDeleteProgram = (_glDeleteProgram) ctx->getProcAddress(QLatin1String("glDeleteProgram"));
+ glIsProgram = (_glIsProgram) ctx->getProcAddress(QLatin1String("glIsProgram"));
+
+ glGetShaderInfoLog = (_glGetShaderInfoLog) ctx->getProcAddress(QLatin1String("glGetShaderInfoLog"));
+ glGetShaderiv = (_glGetShaderiv) ctx->getProcAddress(QLatin1String("glGetShaderiv"));
+ glGetShaderSource = (_glGetShaderSource) ctx->getProcAddress(QLatin1String("glGetShaderSource"));
+ glGetProgramiv = (_glGetProgramiv) ctx->getProcAddress(QLatin1String("glGetProgramiv"));
+ glGetProgramInfoLog = (_glGetProgramInfoLog) ctx->getProcAddress(QLatin1String("glGetProgramInfoLog"));
+
+ glGetUniformLocation = (_glGetUniformLocation) ctx->getProcAddress(QLatin1String("glGetUniformLocation"));
+ glUniform4fv = (_glUniform4fv) ctx->getProcAddress(QLatin1String("glUniform4fv"));
+ glUniform3fv = (_glUniform3fv) ctx->getProcAddress(QLatin1String("glUniform3fv"));
+ glUniform2fv = (_glUniform2fv) ctx->getProcAddress(QLatin1String("glUniform2fv"));
+ glUniform1fv = (_glUniform1fv) ctx->getProcAddress(QLatin1String("glUniform1fv"));
+ glUniform1i = (_glUniform1i) ctx->getProcAddress(QLatin1String("glUniform1i"));
+ glUniform1iv = (_glUniform1iv) ctx->getProcAddress(QLatin1String("glUniform1iv"));
+ glUniformMatrix2fv = (_glUniformMatrix2fv) ctx->getProcAddress(QLatin1String("glUniformMatrix2fv"));
+ glUniformMatrix3fv = (_glUniformMatrix3fv) ctx->getProcAddress(QLatin1String("glUniformMatrix3fv"));
+ glUniformMatrix4fv = (_glUniformMatrix4fv) ctx->getProcAddress(QLatin1String("glUniformMatrix4fv"));
+ glUniformMatrix2x3fv = (_glUniformMatrix2x3fv) ctx->getProcAddress(QLatin1String("glUniformMatrix2x3fv"));
+ glUniformMatrix2x4fv = (_glUniformMatrix2x4fv) ctx->getProcAddress(QLatin1String("glUniformMatrix2x4fv"));
+ glUniformMatrix3x2fv = (_glUniformMatrix3x2fv) ctx->getProcAddress(QLatin1String("glUniformMatrix3x2fv"));
+ glUniformMatrix3x4fv = (_glUniformMatrix3x4fv) ctx->getProcAddress(QLatin1String("glUniformMatrix3x4fv"));
+ glUniformMatrix4x2fv = (_glUniformMatrix4x2fv) ctx->getProcAddress(QLatin1String("glUniformMatrix4x2fv"));
+ glUniformMatrix4x3fv = (_glUniformMatrix4x3fv) ctx->getProcAddress(QLatin1String("glUniformMatrix4x3fv"));
+
+ glBindAttribLocation = (_glBindAttribLocation) ctx->getProcAddress(QLatin1String("glBindAttribLocation"));
+ glGetAttribLocation = (_glGetAttribLocation) ctx->getProcAddress(QLatin1String("glGetAttribLocation"));
+ glVertexAttrib1fv = (_glVertexAttrib1fv) ctx->getProcAddress(QLatin1String("glVertexAttrib1fv"));
+ glVertexAttrib2fv = (_glVertexAttrib2fv) ctx->getProcAddress(QLatin1String("glVertexAttrib2fv"));
+ glVertexAttrib3fv = (_glVertexAttrib3fv) ctx->getProcAddress(QLatin1String("glVertexAttrib3fv"));
+ glVertexAttrib4fv = (_glVertexAttrib4fv) ctx->getProcAddress(QLatin1String("glVertexAttrib4fv"));
+ glVertexAttribPointer = (_glVertexAttribPointer) ctx->getProcAddress(QLatin1String("glVertexAttribPointer"));
+ glDisableVertexAttribArray = (_glDisableVertexAttribArray) ctx->getProcAddress(QLatin1String("glDisableVertexAttribArray"));
+ glEnableVertexAttribArray = (_glEnableVertexAttribArray) ctx->getProcAddress(QLatin1String("glEnableVertexAttribArray"));
+
+ } else {
+ // We may not have the standard shader functions, but we might
+ // have the older ARB functions instead.
+ glCreateShader = (_glCreateShader) ctx->getProcAddress(QLatin1String("glCreateShaderObjectARB"));
+ glShaderSource = (_glShaderSource) ctx->getProcAddress(QLatin1String("glShaderSourceARB"));
+ glShaderBinary = (_glShaderBinary) ctx->getProcAddress(QLatin1String("glShaderBinaryARB"));
+ glCompileShader = (_glCompileShader) ctx->getProcAddress(QLatin1String("glCompileShaderARB"));
+ glDeleteShader = (_glDeleteShader) ctx->getProcAddress(QLatin1String("glDeleteObjectARB"));
+ glIsShader = 0;
+
+ glCreateProgram = (_glCreateProgram) ctx->getProcAddress(QLatin1String("glCreateProgramObjectARB"));
+ glAttachShader = (_glAttachShader) ctx->getProcAddress(QLatin1String("glAttachObjectARB"));
+ glDetachShader = (_glDetachShader) ctx->getProcAddress(QLatin1String("glDetachObjectARB"));
+ glLinkProgram = (_glLinkProgram) ctx->getProcAddress(QLatin1String("glLinkProgramARB"));
+ glUseProgram = (_glUseProgram) ctx->getProcAddress(QLatin1String("glUseProgramObjectARB"));
+ glDeleteProgram = (_glDeleteProgram) ctx->getProcAddress(QLatin1String("glDeleteObjectARB"));
+ glIsProgram = 0;
+
+ glGetShaderInfoLog = (_glGetShaderInfoLog) ctx->getProcAddress(QLatin1String("glGetInfoLogARB"));
+ glGetShaderiv = (_glGetShaderiv) ctx->getProcAddress(QLatin1String("glGetObjectParameterivARB"));
+ glGetShaderSource = (_glGetShaderSource) ctx->getProcAddress(QLatin1String("glGetShaderSourceARB"));
+ glGetProgramiv = (_glGetProgramiv) ctx->getProcAddress(QLatin1String("glGetObjectParameterivARB"));
+ glGetProgramInfoLog = (_glGetProgramInfoLog) ctx->getProcAddress(QLatin1String("glGetInfoLogARB"));
+
+ glGetUniformLocation = (_glGetUniformLocation) ctx->getProcAddress(QLatin1String("glGetUniformLocationARB"));
+ glUniform4fv = (_glUniform4fv) ctx->getProcAddress(QLatin1String("glUniform4fvARB"));
+ glUniform3fv = (_glUniform3fv) ctx->getProcAddress(QLatin1String("glUniform3fvARB"));
+ glUniform2fv = (_glUniform2fv) ctx->getProcAddress(QLatin1String("glUniform2fvARB"));
+ glUniform1fv = (_glUniform1fv) ctx->getProcAddress(QLatin1String("glUniform1fvARB"));
+ glUniform1i = (_glUniform1i) ctx->getProcAddress(QLatin1String("glUniform1iARB"));
+ glUniform1iv = (_glUniform1iv) ctx->getProcAddress(QLatin1String("glUniform1ivARB"));
+ glUniformMatrix2fv = (_glUniformMatrix2fv) ctx->getProcAddress(QLatin1String("glUniformMatrix2fvARB"));
+ glUniformMatrix3fv = (_glUniformMatrix3fv) ctx->getProcAddress(QLatin1String("glUniformMatrix3fvARB"));
+ glUniformMatrix4fv = (_glUniformMatrix4fv) ctx->getProcAddress(QLatin1String("glUniformMatrix4fvARB"));
+ glUniformMatrix2x3fv = (_glUniformMatrix2x3fv) ctx->getProcAddress(QLatin1String("glUniformMatrix2x3fvARB"));
+ glUniformMatrix2x4fv = (_glUniformMatrix2x4fv) ctx->getProcAddress(QLatin1String("glUniformMatrix2x4fvARB"));
+ glUniformMatrix3x2fv = (_glUniformMatrix3x2fv) ctx->getProcAddress(QLatin1String("glUniformMatrix3x2fvARB"));
+ glUniformMatrix3x4fv = (_glUniformMatrix3x4fv) ctx->getProcAddress(QLatin1String("glUniformMatrix3x4fvARB"));
+ glUniformMatrix4x2fv = (_glUniformMatrix4x2fv) ctx->getProcAddress(QLatin1String("glUniformMatrix4x2fvARB"));
+ glUniformMatrix4x3fv = (_glUniformMatrix4x3fv) ctx->getProcAddress(QLatin1String("glUniformMatrix4x3fvARB"));
+
+ glBindAttribLocation = (_glBindAttribLocation) ctx->getProcAddress(QLatin1String("glBindAttribLocationARB"));
+ glGetAttribLocation = (_glGetAttribLocation) ctx->getProcAddress(QLatin1String("glGetAttribLocationARB"));
+ glVertexAttrib1fv = (_glVertexAttrib1fv) ctx->getProcAddress(QLatin1String("glVertexAttrib1fvARB"));
+ glVertexAttrib2fv = (_glVertexAttrib2fv) ctx->getProcAddress(QLatin1String("glVertexAttrib2fvARB"));
+ glVertexAttrib3fv = (_glVertexAttrib3fv) ctx->getProcAddress(QLatin1String("glVertexAttrib3fvARB"));
+ glVertexAttrib4fv = (_glVertexAttrib4fv) ctx->getProcAddress(QLatin1String("glVertexAttrib4fvARB"));
+ glVertexAttribPointer = (_glVertexAttribPointer) ctx->getProcAddress(QLatin1String("glVertexAttribPointerARB"));
+ glDisableVertexAttribArray = (_glDisableVertexAttribArray) ctx->getProcAddress(QLatin1String("glDisableVertexAttribArrayARB"));
+ glEnableVertexAttribArray = (_glEnableVertexAttribArray) ctx->getProcAddress(QLatin1String("glEnableVertexAttribArrayARB"));
+ }
+
+ // Note: glShaderBinary(), glIsShader(), glIsProgram(), and
+ // glUniformMatrixNxMfv() are optional, but all other functions
+ // are required.
+
+ return glCreateShader &&
+ glShaderSource &&
+ glCompileShader &&
+ glDeleteProgram &&
+ glCreateProgram &&
+ glAttachShader &&
+ glDetachShader &&
+ glLinkProgram &&
+ glUseProgram &&
+ glDeleteProgram &&
+ glGetShaderInfoLog &&
+ glGetShaderiv &&
+ glGetShaderSource &&
+ glGetProgramiv &&
+ glGetProgramInfoLog &&
+ glGetUniformLocation &&
+ glUniform1fv &&
+ glUniform2fv &&
+ glUniform3fv &&
+ glUniform4fv &&
+ glUniform1i &&
+ glUniform1iv &&
+ glUniformMatrix2fv &&
+ glUniformMatrix3fv &&
+ glUniformMatrix4fv &&
+ glBindAttribLocation &&
+ glGetAttribLocation &&
+ glVertexAttrib1fv &&
+ glVertexAttrib2fv &&
+ glVertexAttrib3fv &&
+ glVertexAttrib4fv &&
+ glVertexAttribPointer &&
+ glDisableVertexAttribArray &&
+ glEnableVertexAttribArray;
+#endif
+}
+
+#if !defined(QT_OPENGL_ES_2)
+bool qt_resolve_version_2_0_functions(QGLContext *ctx)
+{
+ bool gl2supported = true;
+ if (!qt_resolve_glsl_extensions(ctx))
+ gl2supported = false;
+
+ if (!qt_resolve_version_1_3_functions(ctx))
+ gl2supported = false;
+
+ if (!qt_resolve_framebufferobject_extensions(ctx))
+ gl2supported = false;
+
+ if (glStencilOpSeparate)
+ return gl2supported;
+
+ glBlendColor = (_glBlendColor) ctx->getProcAddress(QLatin1String("glBlendColor"));
+ glStencilOpSeparate = (_glStencilOpSeparate) ctx->getProcAddress(QLatin1String("glStencilOpSeparate"));
+ if (!glBlendColor || !glStencilOpSeparate)
+ gl2supported = false;
+
+ return gl2supported;
}
+#endif
+
QT_END_NAMESPACE
diff --git a/src/opengl/qglextensions_p.h b/src/opengl/qglextensions_p.h
index 280b525..62e216c 100644
--- a/src/opengl/qglextensions_p.h
+++ b/src/opengl/qglextensions_p.h
@@ -74,11 +74,15 @@
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 *);
-typedef void (APIENTRY *_glGenBuffersARB) (GLsizei, GLuint *);
-typedef void (APIENTRY *_glBufferDataARB) (GLenum, GLsizeiptrARB, const GLvoid *, GLenum);
+typedef void (APIENTRY *_glBindBuffer) (GLenum, GLuint);
+typedef void (APIENTRY *_glDeleteBuffers) (GLsizei, const GLuint *);
+typedef void (APIENTRY *_glGenBuffers) (GLsizei, GLuint *);
+typedef void (APIENTRY *_glBufferData) (GLenum, GLsizeiptrARB, const GLvoid *, GLenum);
typedef GLvoid* (APIENTRY *_glMapBufferARB) (GLenum, GLenum);
typedef GLboolean (APIENTRY *_glUnmapBufferARB) (GLenum);
@@ -92,8 +96,10 @@ typedef void (APIENTRY *_glProgramLocalParameter4fvARB) (GLenum, GLuint, const G
// GLSL
typedef GLuint (APIENTRY *_glCreateShader) (GLenum);
typedef void (APIENTRY *_glShaderSource) (GLuint, GLsizei, const char **, const GLint *);
+typedef void (APIENTRY *_glShaderBinary) (GLint, const GLuint*, GLenum, const void*, GLint);
typedef void (APIENTRY *_glCompileShader) (GLuint);
typedef void (APIENTRY *_glDeleteShader) (GLuint);
+typedef GLboolean (APIENTRY *_glIsShader) (GLuint);
typedef GLuint (APIENTRY *_glCreateProgram) ();
typedef void (APIENTRY *_glAttachShader) (GLuint, GLuint);
@@ -101,62 +107,106 @@ typedef void (APIENTRY *_glDetachShader) (GLuint, GLuint);
typedef void (APIENTRY *_glLinkProgram) (GLuint);
typedef void (APIENTRY *_glUseProgram) (GLuint);
typedef void (APIENTRY *_glDeleteProgram) (GLuint);
+typedef GLboolean (APIENTRY *_glIsProgram) (GLuint);
typedef void (APIENTRY *_glGetShaderInfoLog) (GLuint, GLsizei, GLsizei *, char *);
typedef void (APIENTRY *_glGetShaderiv) (GLuint, GLenum, GLint *);
+typedef void (APIENTRY *_glGetShaderSource) (GLuint, GLsizei, GLsizei *, char *);
typedef void (APIENTRY *_glGetProgramiv) (GLuint, GLenum, GLint *);
+typedef void (APIENTRY *_glGetProgramInfoLog) (GLuint, GLsizei, GLsizei *, char *);
typedef GLuint (APIENTRY *_glGetUniformLocation) (GLuint, const char*);
-typedef void (APIENTRY *_glUniform4fv) (GLint, GLsizei, GLfloat *);
-typedef void (APIENTRY *_glUniform3fv) (GLint, GLsizei, GLfloat *);
-typedef void (APIENTRY *_glUniform2fv) (GLint, GLsizei, GLfloat *);
-typedef void (APIENTRY *_glUniform1fv) (GLint, GLsizei, GLfloat *);
+typedef void (APIENTRY *_glUniform4fv) (GLint, GLsizei, const GLfloat *);
+typedef void (APIENTRY *_glUniform3fv) (GLint, GLsizei, const GLfloat *);
+typedef void (APIENTRY *_glUniform2fv) (GLint, GLsizei, const GLfloat *);
+typedef void (APIENTRY *_glUniform1fv) (GLint, GLsizei, const GLfloat *);
typedef void (APIENTRY *_glUniform1i) (GLint, GLint);
+typedef void (APIENTRY *_glUniform1iv) (GLint, GLsizei, const GLint *);
+typedef void (APIENTRY *_glUniformMatrix2fv) (GLint, GLsizei, GLboolean, const GLfloat *);
+typedef void (APIENTRY *_glUniformMatrix3fv) (GLint, GLsizei, GLboolean, const GLfloat *);
+typedef void (APIENTRY *_glUniformMatrix4fv) (GLint, GLsizei, GLboolean, const GLfloat *);
+typedef void (APIENTRY *_glUniformMatrix2x3fv) (GLint, GLsizei, GLboolean, const GLfloat *);
+typedef void (APIENTRY *_glUniformMatrix2x4fv) (GLint, GLsizei, GLboolean, const GLfloat *);
+typedef void (APIENTRY *_glUniformMatrix3x2fv) (GLint, GLsizei, GLboolean, const GLfloat *);
+typedef void (APIENTRY *_glUniformMatrix3x4fv) (GLint, GLsizei, GLboolean, const GLfloat *);
+typedef void (APIENTRY *_glUniformMatrix4x2fv) (GLint, GLsizei, GLboolean, const GLfloat *);
+typedef void (APIENTRY *_glUniformMatrix4x3fv) (GLint, GLsizei, GLboolean, const GLfloat *);
+
+typedef void (APIENTRY *_glBindAttribLocation) (GLuint, GLuint, const char *);
+typedef GLint (APIENTRY *_glGetAttribLocation) (GLuint, const char *);
+typedef void (APIENTRY *_glVertexAttrib1fv) (GLuint, const GLfloat *);
+typedef void (APIENTRY *_glVertexAttrib2fv) (GLuint, const GLfloat *);
+typedef void (APIENTRY *_glVertexAttrib3fv) (GLuint, const GLfloat *);
+typedef void (APIENTRY *_glVertexAttrib4fv) (GLuint, const GLfloat *);
+typedef void (APIENTRY *_glVertexAttribPointer) (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *);
+typedef void (APIENTRY *_glDisableVertexAttribArray) (GLuint);
+typedef void (APIENTRY *_glEnableVertexAttribArray) (GLuint);
+
+typedef void (APIENTRY *_glGetProgramBinaryOES) (GLuint, GLsizei, GLsizei *, GLenum *, void *);
+typedef void (APIENTRY *_glProgramBinaryOES) (GLuint, GLenum, const void *, GLint);
-typedef void (APIENTRY *_glActiveStencilFaceEXT) (GLenum );
typedef void (APIENTRY *_glMultiTexCoord4f) (GLenum, GLfloat, GLfloat, GLfloat, GLfloat);
+typedef void (APIENTRY *_glActiveStencilFaceEXT) (GLenum );
+
+// Needed for GL2 engine:
+typedef void (APIENTRY *_glStencilOpSeparate) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
typedef void (APIENTRY *_glActiveTexture) (GLenum);
+typedef void (APIENTRY *_glBlendColor) (GLclampf, GLclampf, GLclampf, GLclampf);
+
// EXT_GL_framebuffer_object
-typedef GLboolean (APIENTRY *_glIsRenderbufferEXT) (GLuint renderbuffer);
-typedef void (APIENTRY *_glBindRenderbufferEXT) (GLenum target, GLuint renderbuffer);
-typedef void (APIENTRY *_glDeleteRenderbuffersEXT) (GLsizei n, const GLuint *renderbuffers);
-typedef void (APIENTRY *_glGenRenderbuffersEXT) (GLsizei n, GLuint *renderbuffers);
-typedef void (APIENTRY *_glRenderbufferStorageEXT) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
-typedef void (APIENTRY *_glGetRenderbufferParameterivEXT) (GLenum target, GLenum pname, GLint *params);
-typedef GLboolean (APIENTRY *_glIsFramebufferEXT) (GLuint framebuffer);
-typedef void (APIENTRY *_glBindFramebufferEXT) (GLenum target, GLuint framebuffer);
-typedef void (APIENTRY *_glDeleteFramebuffersEXT) (GLsizei n, const GLuint *framebuffers);
-typedef void (APIENTRY *_glGenFramebuffersEXT) (GLsizei n, GLuint *framebuffers);
-typedef GLenum (APIENTRY *_glCheckFramebufferStatusEXT) (GLenum target);
-typedef void (APIENTRY *_glFramebufferTexture1DEXT) (GLenum target, GLenum attachment, GLenum textarget,
- GLuint texture, GLint level);
-typedef void (APIENTRY *_glFramebufferTexture2DEXT) (GLenum target, GLenum attachment, GLenum textarget,
+typedef GLboolean (APIENTRY *_glIsRenderbuffer) (GLuint renderbuffer);
+typedef void (APIENTRY *_glBindRenderbuffer) (GLenum target, GLuint renderbuffer);
+typedef void (APIENTRY *_glDeleteRenderbuffers) (GLsizei n, const GLuint *renderbuffers);
+typedef void (APIENTRY *_glGenRenderbuffers) (GLsizei n, GLuint *renderbuffers);
+typedef void (APIENTRY *_glRenderbufferStorage) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRY *_glGetRenderbufferParameteriv) (GLenum target, GLenum pname, GLint *params);
+typedef GLboolean (APIENTRY *_glIsFramebuffer) (GLuint framebuffer);
+typedef void (APIENTRY *_glBindFramebuffer) (GLenum target, GLuint framebuffer);
+typedef void (APIENTRY *_glDeleteFramebuffers) (GLsizei n, const GLuint *framebuffers);
+typedef void (APIENTRY *_glGenFramebuffers) (GLsizei n, GLuint *framebuffers);
+typedef GLenum (APIENTRY *_glCheckFramebufferStatus) (GLenum target);
+typedef void (APIENTRY *_glFramebufferTexture2D) (GLenum target, GLenum attachment, GLenum textarget,
GLuint texture, GLint level);
-typedef void (APIENTRY *_glFramebufferTexture3DEXT) (GLenum target, GLenum attachment, GLenum textarget,
- GLuint texture, GLint level, GLint zoffset);
-typedef void (APIENTRY *_glFramebufferRenderbufferEXT) (GLenum target, GLenum attachment, GLenum renderbuffertarget,
+typedef void (APIENTRY *_glFramebufferRenderbuffer) (GLenum target, GLenum attachment, GLenum renderbuffertarget,
GLuint renderbuffer);
-typedef void (APIENTRY *_glGetFramebufferAttachmentParameterivEXT) (GLenum target, GLenum attachment, GLenum pname,
+typedef void (APIENTRY *_glGetFramebufferAttachmentParameteriv) (GLenum target, GLenum attachment, GLenum pname,
GLint *params);
-typedef void (APIENTRY *_glGenerateMipmapEXT) (GLenum target);
+typedef void (APIENTRY *_glGenerateMipmap) (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);
+
+// ARB_texture_compression
+typedef void (APIENTRY *_glCompressedTexImage2DARB) (GLenum, GLint, GLenum, GLsizei,
+ GLsizei, GLint, GLsizei, const GLvoid *);
QT_BEGIN_NAMESPACE
struct QGLExtensionFuncs
{
QGLExtensionFuncs() {
+#if !defined(QT_OPENGL_ES_2)
qt_glProgramStringARB = 0;
qt_glBindProgramARB = 0;
qt_glDeleteProgramsARB = 0;
qt_glGenProgramsARB = 0;
qt_glProgramLocalParameter4fvARB = 0;
+ // GLSL
qt_glCreateShader = 0;
qt_glShaderSource = 0;
+ qt_glShaderBinary = 0;
qt_glCompileShader = 0;
qt_glDeleteShader = 0;
+ qt_glIsShader = 0;
qt_glCreateProgram = 0;
qt_glAttachShader = 0;
@@ -164,10 +214,13 @@ struct QGLExtensionFuncs
qt_glLinkProgram = 0;
qt_glUseProgram = 0;
qt_glDeleteProgram = 0;
+ qt_glIsProgram = 0;
qt_glGetShaderInfoLog = 0;
qt_glGetShaderiv = 0;
+ qt_glGetShaderSource = 0;
qt_glGetProgramiv = 0;
+ qt_glGetProgramInfoLog = 0;
qt_glGetUniformLocation = 0;
qt_glUniform4fv = 0;
@@ -175,40 +228,80 @@ struct QGLExtensionFuncs
qt_glUniform2fv = 0;
qt_glUniform1fv = 0;
qt_glUniform1i = 0;
+ qt_glUniform1iv = 0;
+ qt_glUniformMatrix2fv = 0;
+ qt_glUniformMatrix3fv = 0;
+ qt_glUniformMatrix4fv = 0;
+ qt_glUniformMatrix2x3fv = 0;
+ qt_glUniformMatrix2x4fv = 0;
+ qt_glUniformMatrix3x2fv = 0;
+ qt_glUniformMatrix3x4fv = 0;
+ qt_glUniformMatrix4x2fv = 0;
+ qt_glUniformMatrix4x3fv = 0;
+
+ qt_glBindAttribLocation = 0;
+ qt_glGetAttribLocation = 0;
+ qt_glVertexAttrib1fv = 0;
+ qt_glVertexAttrib2fv = 0;
+ qt_glVertexAttrib3fv = 0;
+ qt_glVertexAttrib4fv = 0;
+ qt_glVertexAttribPointer = 0;
+ qt_glDisableVertexAttribArray = 0;
+ qt_glEnableVertexAttribArray = 0;
+
+ // Extras for GL2 engine:
+ qt_glActiveTexture = 0;
+ qt_glStencilOpSeparate = 0;
+ qt_glBlendColor = 0;
qt_glActiveStencilFaceEXT = 0;
-
qt_glMultiTexCoord4f = 0;
- qt_glActiveTexture = 0;
+#else
+ qt_glslResolved = false;
+
+ qt_glGetProgramBinaryOES = 0;
+ qt_glProgramBinaryOES = 0;
+#endif
+
+ // FBOs
+#if !defined(QT_OPENGL_ES_2)
+ qt_glIsRenderbuffer = 0;
+ qt_glBindRenderbuffer = 0;
+ qt_glDeleteRenderbuffers = 0;
+ qt_glGenRenderbuffers = 0;
+ qt_glRenderbufferStorage = 0;
+ qt_glGetRenderbufferParameteriv = 0;
+ qt_glIsFramebuffer = 0;
+ qt_glBindFramebuffer = 0;
+ qt_glDeleteFramebuffers = 0;
+ qt_glGenFramebuffers = 0;
+ qt_glCheckFramebufferStatus = 0;
+ qt_glFramebufferTexture2D = 0;
+ qt_glFramebufferRenderbuffer = 0;
+ qt_glGetFramebufferAttachmentParameteriv = 0;
+ qt_glGenerateMipmap = 0;
+#endif
+ qt_glBlitFramebufferEXT = 0;
+ qt_glRenderbufferStorageMultisampleEXT = 0;
+ // Buffer objects:
#if !defined(QT_OPENGL_ES_2)
- qt_glIsRenderbufferEXT = 0;
- qt_glBindRenderbufferEXT = 0;
- qt_glDeleteRenderbuffersEXT = 0;
- qt_glGenRenderbuffersEXT = 0;
- qt_glRenderbufferStorageEXT = 0;
- qt_glGetRenderbufferParameterivEXT = 0;
- qt_glIsFramebufferEXT = 0;
- qt_glBindFramebufferEXT = 0;
- qt_glDeleteFramebuffersEXT = 0;
- qt_glGenFramebuffersEXT = 0;
- qt_glCheckFramebufferStatusEXT = 0;
- qt_glFramebufferTexture1DEXT = 0;
- qt_glFramebufferTexture2DEXT = 0;
- qt_glFramebufferTexture3DEXT = 0;
- qt_glFramebufferRenderbufferEXT = 0;
- qt_glGetFramebufferAttachmentParameterivEXT = 0;
- qt_glGenerateMipmapEXT = 0;
-#endif
-
- qt_glBindBufferARB = 0;
- qt_glDeleteBuffersARB = 0;
- qt_glGenBuffersARB = 0;
- qt_glBufferDataARB = 0;
+ qt_glBindBuffer = 0;
+ qt_glDeleteBuffers = 0;
+ qt_glGenBuffers = 0;
+ qt_glBufferData = 0;
+#endif
qt_glMapBufferARB = 0;
qt_glUnmapBufferARB = 0;
+
+#if !defined(QT_OPENGL_ES)
+ // Texture compression
+ qt_glCompressedTexImage2DARB = 0;
+#endif
}
+
+#if !defined(QT_OPENGL_ES_2)
_glProgramStringARB qt_glProgramStringARB;
_glBindProgramARB qt_glBindProgramARB;
_glDeleteProgramsARB qt_glDeleteProgramsARB;
@@ -218,8 +311,10 @@ struct QGLExtensionFuncs
// GLSL definitions
_glCreateShader qt_glCreateShader;
_glShaderSource qt_glShaderSource;
+ _glShaderBinary qt_glShaderBinary;
_glCompileShader qt_glCompileShader;
_glDeleteShader qt_glDeleteShader;
+ _glIsShader qt_glIsShader;
_glCreateProgram qt_glCreateProgram;
_glAttachShader qt_glAttachShader;
@@ -227,10 +322,13 @@ struct QGLExtensionFuncs
_glLinkProgram qt_glLinkProgram;
_glUseProgram qt_glUseProgram;
_glDeleteProgram qt_glDeleteProgram;
+ _glIsProgram qt_glIsProgram;
_glGetShaderInfoLog qt_glGetShaderInfoLog;
_glGetShaderiv qt_glGetShaderiv;
+ _glGetShaderSource qt_glGetShaderSource;
_glGetProgramiv qt_glGetProgramiv;
+ _glGetProgramInfoLog qt_glGetProgramInfoLog;
_glGetUniformLocation qt_glGetUniformLocation;
_glUniform4fv qt_glUniform4fv;
@@ -238,38 +336,80 @@ struct QGLExtensionFuncs
_glUniform2fv qt_glUniform2fv;
_glUniform1fv qt_glUniform1fv;
_glUniform1i qt_glUniform1i;
+ _glUniform1iv qt_glUniform1iv;
+ _glUniformMatrix2fv qt_glUniformMatrix2fv;
+ _glUniformMatrix3fv qt_glUniformMatrix3fv;
+ _glUniformMatrix4fv qt_glUniformMatrix4fv;
+ _glUniformMatrix2x3fv qt_glUniformMatrix2x3fv;
+ _glUniformMatrix2x4fv qt_glUniformMatrix2x4fv;
+ _glUniformMatrix3x2fv qt_glUniformMatrix3x2fv;
+ _glUniformMatrix3x4fv qt_glUniformMatrix3x4fv;
+ _glUniformMatrix4x2fv qt_glUniformMatrix4x2fv;
+ _glUniformMatrix4x3fv qt_glUniformMatrix4x3fv;
+
+ _glBindAttribLocation qt_glBindAttribLocation;
+ _glGetAttribLocation qt_glGetAttribLocation;
+ _glVertexAttrib1fv qt_glVertexAttrib1fv;
+ _glVertexAttrib2fv qt_glVertexAttrib2fv;
+ _glVertexAttrib3fv qt_glVertexAttrib3fv;
+ _glVertexAttrib4fv qt_glVertexAttrib4fv;
+ _glVertexAttribPointer qt_glVertexAttribPointer;
+ _glDisableVertexAttribArray qt_glDisableVertexAttribArray;
+ _glEnableVertexAttribArray qt_glEnableVertexAttribArray;
- _glActiveStencilFaceEXT qt_glActiveStencilFaceEXT;
+#else
+ bool qt_glslResolved;
+ _glGetProgramBinaryOES qt_glGetProgramBinaryOES;
+ _glProgramBinaryOES qt_glProgramBinaryOES;
+#endif
+
+ _glActiveStencilFaceEXT qt_glActiveStencilFaceEXT;
_glMultiTexCoord4f qt_glMultiTexCoord4f;
+
+#if !defined(QT_OPENGL_ES_2)
+ // Extras needed for GL2 engine:
_glActiveTexture qt_glActiveTexture;
+ _glStencilOpSeparate qt_glStencilOpSeparate;
+ _glBlendColor qt_glBlendColor;
+#endif
+
+ // FBOs
#if !defined(QT_OPENGL_ES_2)
- _glIsRenderbufferEXT qt_glIsRenderbufferEXT;
- _glBindRenderbufferEXT qt_glBindRenderbufferEXT;
- _glDeleteRenderbuffersEXT qt_glDeleteRenderbuffersEXT;
- _glGenRenderbuffersEXT qt_glGenRenderbuffersEXT;
- _glRenderbufferStorageEXT qt_glRenderbufferStorageEXT;
- _glGetRenderbufferParameterivEXT qt_glGetRenderbufferParameterivEXT;
- _glIsFramebufferEXT qt_glIsFramebufferEXT;
- _glBindFramebufferEXT qt_glBindFramebufferEXT;
- _glDeleteFramebuffersEXT qt_glDeleteFramebuffersEXT;
- _glGenFramebuffersEXT qt_glGenFramebuffersEXT;
- _glCheckFramebufferStatusEXT qt_glCheckFramebufferStatusEXT;
- _glFramebufferTexture1DEXT qt_glFramebufferTexture1DEXT;
- _glFramebufferTexture2DEXT qt_glFramebufferTexture2DEXT;
- _glFramebufferTexture3DEXT qt_glFramebufferTexture3DEXT;
- _glFramebufferRenderbufferEXT qt_glFramebufferRenderbufferEXT;
- _glGetFramebufferAttachmentParameterivEXT qt_glGetFramebufferAttachmentParameterivEXT;
- _glGenerateMipmapEXT qt_glGenerateMipmapEXT;
-#endif
-
- _glBindBufferARB qt_glBindBufferARB;
- _glDeleteBuffersARB qt_glDeleteBuffersARB;
- _glGenBuffersARB qt_glGenBuffersARB;
- _glBufferDataARB qt_glBufferDataARB;
+ _glIsRenderbuffer qt_glIsRenderbuffer;
+ _glBindRenderbuffer qt_glBindRenderbuffer;
+ _glDeleteRenderbuffers qt_glDeleteRenderbuffers;
+ _glGenRenderbuffers qt_glGenRenderbuffers;
+ _glRenderbufferStorage qt_glRenderbufferStorage;
+ _glGetRenderbufferParameteriv qt_glGetRenderbufferParameteriv;
+ _glIsFramebuffer qt_glIsFramebuffer;
+ _glBindFramebuffer qt_glBindFramebuffer;
+ _glDeleteFramebuffers qt_glDeleteFramebuffers;
+ _glGenFramebuffers qt_glGenFramebuffers;
+ _glCheckFramebufferStatus qt_glCheckFramebufferStatus;
+ _glFramebufferTexture2D qt_glFramebufferTexture2D;
+ _glFramebufferRenderbuffer qt_glFramebufferRenderbuffer;
+ _glGetFramebufferAttachmentParameteriv qt_glGetFramebufferAttachmentParameteriv;
+ _glGenerateMipmap qt_glGenerateMipmap;
+#endif
+ _glBlitFramebufferEXT qt_glBlitFramebufferEXT;
+ _glRenderbufferStorageMultisampleEXT qt_glRenderbufferStorageMultisampleEXT;
+
+ // Buffer objects
+#if !defined(QT_OPENGL_ES_2)
+ _glBindBuffer qt_glBindBuffer;
+ _glDeleteBuffers qt_glDeleteBuffers;
+ _glGenBuffers qt_glGenBuffers;
+ _glBufferData qt_glBufferData;
+#endif
_glMapBufferARB qt_glMapBufferARB;
_glUnmapBufferARB qt_glUnmapBufferARB;
+
+#if !defined(QT_OPENGL_ES)
+ // Texture compression
+ _glCompressedTexImage2DARB qt_glCompressedTexImage2DARB;
+#endif
};
@@ -287,6 +427,18 @@ struct QGLExtensionFuncs
#define GL_BGRA 0x80E1
#endif
+#ifndef GL_RGB16
+#define GL_RGB16 32852
+#endif
+
+#ifndef GL_UNSIGNED_SHORT_5_6_5
+#define GL_UNSIGNED_SHORT_5_6_5 33635
+#endif
+
+#ifndef GL_UNSIGNED_INT_8_8_8_8_REV
+#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
+#endif
+
#ifndef GL_MULTISAMPLE
#define GL_MULTISAMPLE 0x809D
#endif
@@ -397,6 +549,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 0x8D57
+#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
@@ -416,96 +590,170 @@ struct QGLExtensionFuncs
#define GL_UNPACK_IMAGE_HEIGHT 0x806E
#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
-#define glGenProgramsARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGenProgramsARB
-#define glProgramLocalParameter4fvARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glProgramLocalParameter4fvARB
+#ifndef GL_VERSION_1_4
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+#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
+
+
+#if !defined(QT_OPENGL_ES_2)
+#define glProgramStringARB QGLContextPrivate::extensionFuncs(ctx).qt_glProgramStringARB
+#define glBindProgramARB QGLContextPrivate::extensionFuncs(ctx).qt_glBindProgramARB
+#define glDeleteProgramsARB QGLContextPrivate::extensionFuncs(ctx).qt_glDeleteProgramsARB
+#define glGenProgramsARB QGLContextPrivate::extensionFuncs(ctx).qt_glGenProgramsARB
+#define glProgramLocalParameter4fvARB QGLContextPrivate::extensionFuncs(ctx).qt_glProgramLocalParameter4fvARB
+
+#define glActiveStencilFaceEXT QGLContextPrivate::extensionFuncs(ctx).qt_glActiveStencilFaceEXT
-#define glActiveStencilFaceEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glActiveStencilFaceEXT
+#define glMultiTexCoord4f QGLContextPrivate::extensionFuncs(ctx).qt_glMultiTexCoord4f
+
+#define glActiveTexture QGLContextPrivate::extensionFuncs(ctx).qt_glActiveTexture
+#endif // !defined(QT_OPENGL_ES_2)
+
+
+// FBOs
+#if !defined(QT_OPENGL_ES_2)
+#define glIsRenderbuffer QGLContextPrivate::extensionFuncs(ctx).qt_glIsRenderbuffer
+#define glBindRenderbuffer QGLContextPrivate::extensionFuncs(ctx).qt_glBindRenderbuffer
+#define glDeleteRenderbuffers QGLContextPrivate::extensionFuncs(ctx).qt_glDeleteRenderbuffers
+#define glGenRenderbuffers QGLContextPrivate::extensionFuncs(ctx).qt_glGenRenderbuffers
+#define glRenderbufferStorage QGLContextPrivate::extensionFuncs(ctx).qt_glRenderbufferStorage
+#define glGetRenderbufferParameteriv QGLContextPrivate::extensionFuncs(ctx).qt_glGetRenderbufferParameteriv
+#define glIsFramebuffer QGLContextPrivate::extensionFuncs(ctx).qt_glIsFramebuffer
+#define glBindFramebuffer QGLContextPrivate::extensionFuncs(ctx).qt_glBindFramebuffer
+#define glDeleteFramebuffers QGLContextPrivate::extensionFuncs(ctx).qt_glDeleteFramebuffers
+#define glGenFramebuffers QGLContextPrivate::extensionFuncs(ctx).qt_glGenFramebuffers
+#define glCheckFramebufferStatus QGLContextPrivate::extensionFuncs(ctx).qt_glCheckFramebufferStatus
+#define glFramebufferTexture2D QGLContextPrivate::extensionFuncs(ctx).qt_glFramebufferTexture2D
+#define glFramebufferRenderbuffer QGLContextPrivate::extensionFuncs(ctx).qt_glFramebufferRenderbuffer
+#define glGetFramebufferAttachmentParameteriv QGLContextPrivate::extensionFuncs(ctx).qt_glGetFramebufferAttachmentParameteriv
+#define glGenerateMipmap QGLContextPrivate::extensionFuncs(ctx).qt_glGenerateMipmap
+#endif // QT_OPENGL_ES_2
+#define glBlitFramebufferEXT QGLContextPrivate::extensionFuncs(ctx).qt_glBlitFramebufferEXT
+#define glRenderbufferStorageMultisampleEXT QGLContextPrivate::extensionFuncs(ctx).qt_glRenderbufferStorageMultisampleEXT
-#define glMultiTexCoord4f QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glMultiTexCoord4f
+// Buffer objects
#if !defined(QT_OPENGL_ES_2)
-#define glActiveTexture QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glActiveTexture
+#define glBindBuffer QGLContextPrivate::extensionFuncs(ctx).qt_glBindBuffer
+#define glDeleteBuffers QGLContextPrivate::extensionFuncs(ctx).qt_glDeleteBuffers
+#define glGenBuffers QGLContextPrivate::extensionFuncs(ctx).qt_glGenBuffers
+#define glBufferData QGLContextPrivate::extensionFuncs(ctx).qt_glBufferData
#endif
+#define glMapBufferARB QGLContextPrivate::extensionFuncs(ctx).qt_glMapBufferARB
+#define glUnmapBufferARB QGLContextPrivate::extensionFuncs(ctx).qt_glUnmapBufferARB
+
+// GLSL
#if !defined(QT_OPENGL_ES_2)
-#define glIsRenderbufferEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glIsRenderbufferEXT
-#define glBindRenderbufferEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBindRenderbufferEXT
-#define glDeleteRenderbuffersEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteRenderbuffersEXT
-#define glGenRenderbuffersEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGenRenderbuffersEXT
-#define glRenderbufferStorageEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glRenderbufferStorageEXT
-#define glGetRenderbufferParameterivEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetRenderbufferParameterivEXT
-#define glIsFramebufferEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glIsFramebufferEXT
-#define glBindFramebufferEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBindFramebufferEXT
-#define glDeleteFramebuffersEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteFramebuffersEXT
-#define glGenFramebuffersEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGenFramebuffersEXT
-#define glCheckFramebufferStatusEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glCheckFramebufferStatusEXT
-#define glFramebufferTexture1DEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glFramebufferTexture1DEXT
-#define glFramebufferTexture2DEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glFramebufferTexture2DEXT
-#define glFramebufferTexture3DEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glFramebufferTexture3DEXT
-#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 glCreateShader QGLContextPrivate::extensionFuncs(ctx).qt_glCreateShader
+#define glShaderSource QGLContextPrivate::extensionFuncs(ctx).qt_glShaderSource
+#define glShaderBinary QGLContextPrivate::extensionFuncs(ctx).qt_glShaderBinary
+#define glCompileShader QGLContextPrivate::extensionFuncs(ctx).qt_glCompileShader
+#define glDeleteShader QGLContextPrivate::extensionFuncs(ctx).qt_glDeleteShader
+#define glIsShader QGLContextPrivate::extensionFuncs(ctx).qt_glIsShader
+
+#define glCreateProgram QGLContextPrivate::extensionFuncs(ctx).qt_glCreateProgram
+#define glAttachShader QGLContextPrivate::extensionFuncs(ctx).qt_glAttachShader
+#define glDetachShader QGLContextPrivate::extensionFuncs(ctx).qt_glDetachShader
+#define glLinkProgram QGLContextPrivate::extensionFuncs(ctx).qt_glLinkProgram
+#define glUseProgram QGLContextPrivate::extensionFuncs(ctx).qt_glUseProgram
+#define glDeleteProgram QGLContextPrivate::extensionFuncs(ctx).qt_glDeleteProgram
+#define glIsProgram QGLContextPrivate::extensionFuncs(ctx).qt_glIsProgram
+
+#define glGetShaderInfoLog QGLContextPrivate::extensionFuncs(ctx).qt_glGetShaderInfoLog
+#define glGetShaderiv QGLContextPrivate::extensionFuncs(ctx).qt_glGetShaderiv
+#define glGetShaderSource QGLContextPrivate::extensionFuncs(ctx).qt_glGetShaderSource
+#define glGetProgramiv QGLContextPrivate::extensionFuncs(ctx).qt_glGetProgramiv
+#define glGetProgramInfoLog QGLContextPrivate::extensionFuncs(ctx).qt_glGetProgramInfoLog
+
+#define glGetUniformLocation QGLContextPrivate::extensionFuncs(ctx).qt_glGetUniformLocation
+#define glUniform4fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniform4fv
+#define glUniform3fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniform3fv
+#define glUniform2fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniform2fv
+#define glUniform1fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniform1fv
+#define glUniform1i QGLContextPrivate::extensionFuncs(ctx).qt_glUniform1i
+#define glUniform1iv QGLContextPrivate::extensionFuncs(ctx).qt_glUniform1iv
+#define glUniformMatrix2fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniformMatrix2fv
+#define glUniformMatrix3fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniformMatrix3fv
+#define glUniformMatrix4fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniformMatrix4fv
+#define glUniformMatrix2x3fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniformMatrix2x3fv
+#define glUniformMatrix2x4fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniformMatrix2x4fv
+#define glUniformMatrix3x2fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniformMatrix3x2fv
+#define glUniformMatrix3x4fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniformMatrix3x4fv
+#define glUniformMatrix4x2fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniformMatrix4x2fv
+#define glUniformMatrix4x3fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniformMatrix4x3fv
+
+#define glBindAttribLocation QGLContextPrivate::extensionFuncs(ctx).qt_glBindAttribLocation
+#define glGetAttribLocation QGLContextPrivate::extensionFuncs(ctx).qt_glGetAttribLocation
+#define glVertexAttrib1fv QGLContextPrivate::extensionFuncs(ctx).qt_glVertexAttrib1fv
+#define glVertexAttrib2fv QGLContextPrivate::extensionFuncs(ctx).qt_glVertexAttrib2fv
+#define glVertexAttrib3fv QGLContextPrivate::extensionFuncs(ctx).qt_glVertexAttrib3fv
+#define glVertexAttrib4fv QGLContextPrivate::extensionFuncs(ctx).qt_glVertexAttrib4fv
+#define glVertexAttribPointer QGLContextPrivate::extensionFuncs(ctx).qt_glVertexAttribPointer
+#define glDisableVertexAttribArray QGLContextPrivate::extensionFuncs(ctx).qt_glDisableVertexAttribArray
+#define glEnableVertexAttribArray QGLContextPrivate::extensionFuncs(ctx).qt_glEnableVertexAttribArray
#else // QT_OPENGL_ES_2
-#define glIsRenderbufferEXT glIsRenderbuffer
-#define glBindRenderbufferEXT glBindRenderbuffer
-#define glDeleteRenderbuffersEXT glDeleteRenderbuffers
-#define glGenRenderbuffersEXT glGenRenderbuffers
-#define glRenderbufferStorageEXT glRenderbufferStorage
-#define glGetRenderbufferParameterivEXT glGetRenderbufferParameteriv
-#define glIsFramebufferEXT glIsFramebuffer
-#define glBindFramebufferEXT glBindFramebuffer
-#define glDeleteFramebuffersEXT glDeleteFramebuffers
-#define glGenFramebuffersEXT glGenFramebuffers
-#define glCheckFramebufferStatusEXT glCheckFramebufferStatus
-#define glFramebufferTexture1DEXT glFramebufferTexture1D
-#define glFramebufferTexture2DEXT glFramebufferTexture2D
-#define glFramebufferTexture3DEXT glFramebufferTexture3D
-#define glFramebufferRenderbufferEXT glFramebufferRenderbuffer
-#define glGetFramebufferAttachmentParameterivEXT glGetFramebufferAttachmentParameteriv
-#define glGenerateMipmapEXT glGenerateMipmap
+#define glGetProgramBinaryOES QGLContextPrivate::extensionFuncs(ctx).qt_glGetProgramBinaryOES
+#define glProgramBinaryOES QGLContextPrivate::extensionFuncs(ctx).qt_glProgramBinaryOES
#endif // QT_OPENGL_ES_2
-#define glBindBufferARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBindBufferARB
-#define glDeleteBuffersARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteBuffersARB
-#define glGenBuffersARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGenBuffersARB
-#define glBufferDataARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBufferDataARB
-#define glMapBufferARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glMapBufferARB
-#define glUnmapBufferARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUnmapBufferARB
-
-#define glCreateShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glCreateShader
-#define glShaderSource QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glShaderSource
-#define glCompileShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glCompileShader
-#define glDeleteShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteShader
-
-#define glCreateProgram QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glCreateProgram
-#define glAttachShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glAttachShader
-#define glDetachShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDetachShader
-#define glLinkProgram QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glLinkProgram
-#define glUseProgram QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUseProgram
-#define glDeleteProgram QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteProgram
-
-#define glGetShaderInfoLog QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetShaderInfoLog
-#define glGetShaderiv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetShaderiv
-#define glGetProgramiv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetProgramiv
-
-#define glGetUniformLocation QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetUniformLocation
-#define glUniform4fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform4fv
-#define glUniform3fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform3fv
-#define glUniform2fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform2fv
-#define glUniform1fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform1fv
-#define glUniform1i QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform1i
+
+#if !defined(QT_OPENGL_ES_2)
+#define glStencilOpSeparate QGLContextPrivate::extensionFuncs(ctx).qt_glStencilOpSeparate
+#define glBlendColor QGLContextPrivate::extensionFuncs(ctx).qt_glBlendColor
+#endif
+
+#if defined(QT_OPENGL_ES_2)
+#define glClearDepth glClearDepthf
+#endif
+
+#if !defined(QT_OPENGL_ES)
+#define glCompressedTexImage2D QGLContextPrivate::extensionFuncs(ctx).qt_glCompressedTexImage2DARB
+#endif
extern bool qt_resolve_framebufferobject_extensions(QGLContext *ctx);
bool qt_resolve_buffer_extensions(QGLContext *ctx);
bool qt_resolve_version_1_3_functions(QGLContext *ctx);
+bool qt_resolve_version_2_0_functions(QGLContext *ctx);
bool qt_resolve_stencil_face_extension(QGLContext *ctx);
bool qt_resolve_frag_program_extensions(QGLContext *ctx);
diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp
index a0933d1..4b5c30a 100644
--- a/src/opengl/qglframebufferobject.cpp
+++ b/src/opengl/qglframebufferobject.cpp
@@ -40,10 +40,18 @@
****************************************************************************/
#include "qglframebufferobject.h"
+#include "qglframebufferobject_p.h"
#include <qdebug.h>
#include <private/qgl_p.h>
+#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
+#include <private/qpaintengineex_opengl2_p.h>
+#endif
+
+#ifndef QT_OPENGL_ES_2
#include <private/qpaintengine_opengl_p.h>
+#endif
+
#include <qglframebufferobject.h>
#include <qlibrary.h>
#include <qimage.h>
@@ -56,8 +64,14 @@ QT_BEGIN_NAMESPACE
extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
-#define QGL_FUNC_CONTEXT QGLContext *ctx = d_ptr->ctx;
+#define QGL_FUNC_CONTEXT const QGLContext *ctx = d_ptr->fbo_guard.context();
+#define QGL_FUNCP_CONTEXT const QGLContext *ctx = fbo_guard.context();
+#ifndef QT_NO_DEBUG
+#define QT_RESET_GLERROR() \
+{ \
+ while (glGetError() != GL_NO_ERROR) {} \
+}
#define QT_CHECK_GLERROR() \
{ \
GLenum err = glGetError(); \
@@ -66,30 +80,274 @@ extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
__FILE__, __LINE__, (int)err); \
} \
}
+#else
+#define QT_RESET_GLERROR() {}
+#define QT_CHECK_GLERROR() {}
+#endif
+
+/*!
+ \class QGLFramebufferObjectFormat
+ \brief The QGLFramebufferObjectFormat class specifies the format of an OpenGL
+ framebuffer object.
+
+ \since 4.6
+
+ \ingroup painting-3D
+
+ 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 setInternalTextureFormat() Internal texture 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
+*/
+
+/*!
+ \internal
+*/
+void QGLFramebufferObjectFormat::detach()
+{
+ if (d->ref != 1) {
+ QGLFramebufferObjectFormatPrivate *newd
+ = new QGLFramebufferObjectFormatPrivate(d);
+ if (!d->ref.deref())
+ delete d;
+ d = newd;
+ }
+}
+
+/*!
+ Creates a QGLFramebufferObjectFormat object for specifying
+ the format of an OpenGL framebuffer object.
+
+ By default the format specifies a non-multisample framebuffer object with no
+ attachments, texture target \c GL_TEXTURE_2D, and internal format \c GL_RGBA8.
+ On OpenGL/ES systems, the default internal format is \c GL_RGBA.
+
+ \sa samples(), attachment(), target(), internalTextureFormat()
+*/
+
+QGLFramebufferObjectFormat::QGLFramebufferObjectFormat()
+{
+ d = new QGLFramebufferObjectFormatPrivate;
+}
+
+/*!
+ Constructs a copy of \a other.
+*/
+
+QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(const QGLFramebufferObjectFormat &other)
+{
+ d = other.d;
+ d->ref.ref();
+}
+
+/*!
+ Assigns \a other to this object.
+*/
+
+QGLFramebufferObjectFormat &QGLFramebufferObjectFormat::operator=(const QGLFramebufferObjectFormat &other)
+{
+ if (d != other.d) {
+ other.d->ref.ref();
+ if (!d->ref.deref())
+ delete d;
+ d = other.d;
+ }
+ return *this;
+}
+
+/*!
+ Destroys the QGLFramebufferObjectFormat.
+*/
+QGLFramebufferObjectFormat::~QGLFramebufferObjectFormat()
+{
+ if (!d->ref.deref())
+ delete d;
+}
+
+/*!
+ Sets the number of samples per pixel for a multisample framebuffer object
+ to \a samples. The default sample count of 0 represents a regular
+ non-multisample framebuffer object.
+
+ 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.
+
+ \sa samples()
+*/
+void QGLFramebufferObjectFormat::setSamples(int samples)
+{
+ detach();
+ d->samples = samples;
+}
+
+/*!
+ Returns the number of samples per pixel if a framebuffer object
+ is a multisample framebuffer object. Otherwise, returns 0.
+ The default value is 0.
+
+ \sa setSamples()
+*/
+int QGLFramebufferObjectFormat::samples() const
+{
+ return d->samples;
+}
-class QGLFramebufferObjectPrivate
+/*!
+ Sets the attachment configuration of a framebuffer object to \a attachment.
+
+ \sa attachment()
+*/
+void QGLFramebufferObjectFormat::setAttachment(QGLFramebufferObject::Attachment attachment)
+{
+ detach();
+ d->attachment = attachment;
+}
+
+/*!
+ Returns the configuration of the depth and stencil buffers attached to
+ a framebuffer object. The default is QGLFramebufferObject::NoAttachment.
+
+ \sa setAttachment()
+*/
+QGLFramebufferObject::Attachment QGLFramebufferObjectFormat::attachment() const
+{
+ return d->attachment;
+}
+
+/*!
+ 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)
+{
+ detach();
+ d->target = target;
+}
+
+/*!
+ Returns the texture target of the texture attached to a framebuffer object.
+ Ignored for multisample framebuffer objects. The default is
+ \c GL_TEXTURE_2D.
+
+ \sa setTextureTarget(), samples()
+*/
+GLenum QGLFramebufferObjectFormat::textureTarget() const
+{
+ return d->target;
+}
+
+/*!
+ Sets the internal format of a framebuffer object's texture or
+ multisample framebuffer object's color buffer to
+ \a internalTextureFormat.
+
+ \sa internalTextureFormat()
+*/
+void QGLFramebufferObjectFormat::setInternalTextureFormat(GLenum internalTextureFormat)
+{
+ detach();
+ d->internal_format = internalTextureFormat;
+}
+
+/*!
+ Returns the internal format of a framebuffer object's texture or
+ multisample framebuffer object's color buffer. The default is
+ \c GL_RGBA8 on desktop OpenGL systems, and \c GL_RGBA on
+ OpenGL/ES systems.
+
+ \sa setInternalTextureFormat()
+*/
+GLenum QGLFramebufferObjectFormat::internalTextureFormat() const
+{
+ return d->internal_format;
+}
+
+#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
+/*! \internal */
+void QGLFramebufferObjectFormat::setTextureTarget(QMacCompatGLenum target)
{
-public:
- QGLFramebufferObjectPrivate() : depth_stencil_buffer(0), valid(false), bound(false), ctx(0) {}
- ~QGLFramebufferObjectPrivate() {}
+ detach();
+ d->target = target;
+}
- void init(const QSize& sz, QGLFramebufferObject::Attachment attachment,
- GLenum internal_format, GLenum texture_target);
- bool checkFramebufferStatus() const;
- GLuint texture;
- GLuint fbo;
- GLuint depth_stencil_buffer;
- GLenum target;
- QSize size;
- uint valid : 1;
- uint bound : 1;
- QGLFramebufferObject::Attachment fbo_attachment;
- QGLContext *ctx; // for Windows extension ptrs
-};
+/*! \internal */
+void QGLFramebufferObjectFormat::setInternalTextureFormat(QMacCompatGLenum internalTextureFormat)
+{
+ detach();
+ d->internal_format = internalTextureFormat;
+}
+#endif
+
+/*!
+ Returns true if all the options of this framebuffer object format
+ are the same as \a other; otherwise returns false.
+*/
+bool QGLFramebufferObjectFormat::operator==(const QGLFramebufferObjectFormat& other) const
+{
+ if (d == other.d)
+ return true;
+ else
+ return d->equals(other.d);
+}
+
+/*!
+ Returns false if all the options of this framebuffer object format
+ are the same as \a other; otherwise returns true.
+*/
+bool QGLFramebufferObjectFormat::operator!=(const QGLFramebufferObjectFormat& other) const
+{
+ return !(*this == other);
+}
+
+void QGLFBOGLPaintDevice::setFBO(QGLFramebufferObject* f,
+ QGLFramebufferObject::Attachment attachment)
+{
+ fbo = f;
+ m_thisFBO = fbo->d_func()->fbo(); // This shouldn't be needed
+
+ // The context that the fbo was created in may not have depth
+ // and stencil buffers, but the fbo itself might.
+ fboFormat = QGLContext::currentContext()->format();
+ if (attachment == QGLFramebufferObject::CombinedDepthStencil) {
+ fboFormat.setDepth(true);
+ fboFormat.setStencil(true);
+ } else if (attachment == QGLFramebufferObject::Depth) {
+ fboFormat.setDepth(true);
+ }
+}
+
+QGLContext *QGLFBOGLPaintDevice::context() const
+{
+ QGLContext *fboContext = const_cast<QGLContext *>(fbo->d_ptr->fbo_guard.context());
+ QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
+
+ if (QGLContextPrivate::contextGroup(fboContext) == QGLContextPrivate::contextGroup(currentContext))
+ return currentContext;
+ else
+ return fboContext;
+}
bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
{
- GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ QGL_FUNCP_CONTEXT;
+ if (!ctx)
+ return false; // Context no longer exists.
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
switch(status) {
case GL_NO_ERROR:
case GL_FRAMEBUFFER_COMPLETE_EXT:
@@ -121,6 +379,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;
@@ -128,10 +389,13 @@ bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
return false;
}
-void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::Attachment attachment,
- GLenum texture_target, GLenum internal_format)
+void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
+ QGLFramebufferObject::Attachment attachment,
+ GLenum texture_target, GLenum internal_format, GLint samples)
{
- ctx = const_cast<QGLContext *>(QGLContext::currentContext());
+ QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
+ fbo_guard.setContext(ctx);
+
bool ext_detected = (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject);
if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(ctx)))
return;
@@ -140,82 +404,143 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
target = texture_target;
// texture dimensions
- while (glGetError() != GL_NO_ERROR) {} // reset error state
- glGenFramebuffersEXT(1, &fbo);
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
+ QT_RESET_GLERROR(); // reset error state
+ GLuint fbo = 0;
+ glGenFramebuffers(1, &fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo);
+ fbo_guard.setId(fbo);
+
+ glDevice.setFBO(q, attachment);
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);
+ glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ target, texture, 0);
- QT_CHECK_GLERROR();
- valid = checkFramebufferStatus();
+ QT_CHECK_GLERROR();
+ valid = checkFramebufferStatus();
+ glBindTexture(target, 0);
+
+ color_buffer = 0;
+ } else {
+ GLint maxSamples;
+ glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples);
+
+ samples = qBound(1, int(samples), int(maxSamples));
+
+ glGenRenderbuffers(1, &color_buffer);
+ glBindRenderbuffer(GL_RENDERBUFFER_EXT, color_buffer);
+ if (glRenderbufferStorageMultisampleEXT) {
+ glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
+ internal_format, size.width(), size.height());
+ } else {
+ samples = 0;
+ glRenderbufferStorage(GL_RENDERBUFFER_EXT, internal_format,
+ size.width(), size.height());
+ }
+
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT, color_buffer);
+
+ QT_CHECK_GLERROR();
+ valid = checkFramebufferStatus();
+
+ if (valid)
+ glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_SAMPLES_EXT, &samples);
+ }
if (attachment == QGLFramebufferObject::CombinedDepthStencil
&& (QGLExtensions::glExtensions & QGLExtensions::PackedDepthStencil)) {
// depth and stencil buffer needs another extension
- glGenRenderbuffersEXT(1, &depth_stencil_buffer);
- 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());
+ glGenRenderbuffers(1, &depth_stencil_buffer);
+ Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer));
+ glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
+ Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer));
+ if (samples != 0 && glRenderbufferStorageMultisampleEXT)
+ glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
+ GL_DEPTH24_STENCIL8_EXT, size.width(), size.height());
+ else
+ glRenderbufferStorage(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,
+ glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, depth_stencil_buffer);
- glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
+ glFramebufferRenderbuffer(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);
+ glDeleteRenderbuffers(1, &depth_stencil_buffer);
} else if (attachment == QGLFramebufferObject::Depth
|| attachment == QGLFramebufferObject::CombinedDepthStencil)
{
- glGenRenderbuffersEXT(1, &depth_stencil_buffer);
- Q_ASSERT(!glIsRenderbufferEXT(depth_stencil_buffer));
- glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
- Q_ASSERT(glIsRenderbufferEXT(depth_stencil_buffer));
+ glGenRenderbuffers(1, &depth_stencil_buffer);
+ Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer));
+ glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
+ Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer));
+ if (samples != 0 && glRenderbufferStorageMultisampleEXT) {
#ifdef QT_OPENGL_ES
#define GL_DEPTH_COMPONENT16 0x81A5
- glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, size.width(), size.height());
+ glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
+ GL_DEPTH_COMPONENT16, size.width(), size.height());
#else
- glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, size.width(), size.height());
+ glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
+ GL_DEPTH_COMPONENT, size.width(), size.height());
#endif
+ } else {
+#ifdef QT_OPENGL_ES
+#define GL_DEPTH_COMPONENT16 0x81A5
+ glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, size.width(), size.height());
+#else
+ glRenderbufferStorage(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,
+ glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, depth_stencil_buffer);
fbo_attachment = QGLFramebufferObject::Depth;
valid = checkFramebufferStatus();
if (!valid)
- glDeleteRenderbuffersEXT(1, &depth_stencil_buffer);
+ glDeleteRenderbuffers(1, &depth_stencil_buffer);
} else {
fbo_attachment = QGLFramebufferObject::NoAttachment;
}
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
if (!valid) {
- glDeleteTextures(1, &texture);
- glDeleteFramebuffersEXT(1, &fbo);
+ if (color_buffer)
+ glDeleteRenderbuffers(1, &color_buffer);
+ else
+ glDeleteTextures(1, &texture);
+ glDeleteFramebuffers(1, &fbo);
+ fbo_guard.setId(0);
}
QT_CHECK_GLERROR();
+
+ format.setTextureTarget(target);
+ format.setSamples(int(samples));
+ format.setAttachment(fbo_attachment);
+ format.setInternalTextureFormat(internal_format);
}
/*!
@@ -223,7 +548,7 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
\brief The QGLFramebufferObject class encapsulates an OpenGL framebuffer object.
\since 4.2
- \ingroup multimedia
+ \ingroup painting-3D
The QGLFramebufferObject class encapsulates an OpenGL framebuffer
object, defined by the \c{GL_EXT_framebuffer_object} extension. In
@@ -263,13 +588,30 @@ 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.
+ When using a QPainter to paint to a QGLFramebufferObject you should take
+ care that the QGLFramebufferObject is created with the CombinedDepthStencil
+ attachment for QPainter to be able to render correctly.
+ 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. 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.
+
+ When painting to a QGLFramebufferObject using QPainter, the state of
+ the current GL context will be altered by the paint engine to reflect
+ its needs. Applications should not rely upon the GL state being reset
+ to its original conditions, particularly the current shader program,
+ GL viewport, texture units, and drawing modes.
+
+ For multisample framebuffer objects a color render buffer is created,
+ otherwise a texture with the specified texture target is created.
+ The color render buffer or texture will have the specified internal
+ format, and will be bound to the \c GL_COLOR_ATTACHMENT0
+ attachment in the framebuffer object.
+
+ 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}
*/
@@ -311,7 +653,8 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
By default, no depth and stencil buffers are attached. This behavior
can be toggled using one of the overloaded constructors.
- The default internal texture format is \c GL_RGBA8.
+ The default internal texture format is \c GL_RGBA8 for desktop
+ OpenGL, and \c GL_RGBA for OpenGL/ES.
It is important that you have a current GL context set when
creating the QGLFramebufferObject, otherwise the initialization
@@ -320,17 +663,11 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
\sa size(), texture(), attachment()
*/
-#ifndef QT_OPENGL_ES
-#define DEFAULT_FORMAT GL_RGBA8
-#else
-#define DEFAULT_FORMAT GL_RGBA
-#endif
-
QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(size, NoAttachment, target, DEFAULT_FORMAT);
+ d->init(this, size, NoAttachment, target, DEFAULT_FORMAT);
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
@@ -339,7 +676,7 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, QMacCompatGLenum t
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(size, NoAttachment, target, DEFAULT_FORMAT);
+ d->init(this, size, NoAttachment, target, DEFAULT_FORMAT);
}
#endif
@@ -354,7 +691,35 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, GLenum target)
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
+ d->init(this, 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(this, size, format.attachment(), format.textureTarget(), format.internalTextureFormat(),
+ 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(this, QSize(width, height), format.attachment(), format.textureTarget(),
+ format.internalTextureFormat(), format.samples());
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
@@ -363,7 +728,7 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, QMacCompatGLen
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
+ d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
}
#endif
@@ -375,7 +740,8 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, QMacCompatGLen
The \a attachment parameter describes the depth/stencil buffer
configuration, \a target the texture target and \a internal_format
the internal texture format. The default texture target is \c
- GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8.
+ GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8
+ for desktop OpenGL and \c GL_RGBA for OpenGL/ES.
\sa size(), texture(), attachment()
*/
@@ -384,7 +750,7 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment att
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(QSize(width, height), attachment, target, internal_format);
+ d->init(this, QSize(width, height), attachment, target, internal_format);
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
@@ -394,7 +760,7 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment att
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(QSize(width, height), attachment, target, internal_format);
+ d->init(this, QSize(width, height), attachment, target, internal_format);
}
#endif
@@ -406,7 +772,8 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment att
The \a attachment parameter describes the depth/stencil buffer
configuration, \a target the texture target and \a internal_format
the internal texture format. The default texture target is \c
- GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8.
+ GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8
+ for desktop OpenGL and \c GL_RGBA for OpenGL/ES.
\sa size(), texture(), attachment()
*/
@@ -415,7 +782,7 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachm
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(size, attachment, target, internal_format);
+ d->init(this, size, attachment, target, internal_format);
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
@@ -425,7 +792,7 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachm
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(size, attachment, target, internal_format);
+ d->init(this, size, attachment, target, internal_format);
}
#endif
@@ -439,16 +806,19 @@ QGLFramebufferObject::~QGLFramebufferObject()
Q_D(QGLFramebufferObject);
QGL_FUNC_CONTEXT;
- if (isValid()
- && (d->ctx == QGLContext::currentContext()
- || qgl_share_reg()->checkSharing(d->ctx, QGLContext::currentContext())))
- {
- glDeleteTextures(1, &d->texture);
+ delete d->engine;
+
+ if (isValid() && ctx) {
+ QGLShareContextScope scope(ctx);
+ if (d->texture)
+ glDeleteTextures(1, &d->texture);
+ if (d->color_buffer)
+ glDeleteRenderbuffers(1, &d->color_buffer);
if (d->depth_stencil_buffer)
- glDeleteRenderbuffersEXT(1, &d->depth_stencil_buffer);
- glDeleteFramebuffersEXT(1, &d->fbo);
+ glDeleteRenderbuffers(1, &d->depth_stencil_buffer);
+ GLuint fbo = d->fbo();
+ glDeleteFramebuffers(1, &fbo);
}
- delete d_ptr;
}
/*!
@@ -458,13 +828,21 @@ QGLFramebufferObject::~QGLFramebufferObject()
The framebuffer can become invalid if the initialization process
fails, the user attaches an invalid buffer to the framebuffer
- object, or a non-power of 2 width/height is specified as the
+ object, or a non-power of two width/height is specified as the
texture size if the texture target is \c{GL_TEXTURE_2D}.
+ The non-power of two limitation does not apply if the OpenGL version
+ is 2.0 or higher, or if the GL_ARB_texture_non_power_of_two extension
+ is present.
+
+ The framebuffer can also become invalid if the QGLContext that
+ the framebuffer was created within is destroyed and there are
+ no other shared contexts that can take over ownership of the
+ framebuffer.
*/
bool QGLFramebufferObject::isValid() const
{
Q_D(const QGLFramebufferObject);
- return d->valid;
+ return d->valid && d->fbo_guard.context();
}
/*!
@@ -473,6 +851,8 @@ bool QGLFramebufferObject::isValid() const
Switches rendering from the default, windowing system provided
framebuffer to this framebuffer object.
Returns true upon success, false otherwise.
+
+ \sa release()
*/
bool QGLFramebufferObject::bind()
{
@@ -480,8 +860,20 @@ bool QGLFramebufferObject::bind()
return false;
Q_D(QGLFramebufferObject);
QGL_FUNC_CONTEXT;
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, d->fbo);
- d->bound = d->valid = d->checkFramebufferStatus();
+ if (!ctx)
+ return false; // Context no longer exists.
+ const QGLContext *current = QGLContext::currentContext();
+#ifdef QT_DEBUG
+ if (!current ||
+ QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx))
+ {
+ qWarning("QGLFramebufferObject::bind() called from incompatible context");
+ }
+#endif
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, d->fbo());
+ d->valid = d->checkFramebufferStatus();
+ if (d->valid && current)
+ current->d_ptr->current_fbo = d->fbo();
return d->valid;
}
@@ -491,17 +883,33 @@ bool QGLFramebufferObject::bind()
Switches rendering back to the default, windowing system provided
framebuffer.
Returns true upon success, false otherwise.
+
+ \sa bind()
*/
bool QGLFramebufferObject::release()
{
if (!isValid())
return false;
- Q_D(QGLFramebufferObject);
QGL_FUNC_CONTEXT;
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
- d->valid = d->checkFramebufferStatus();
- d->bound = false;
- return d->valid;
+ if (!ctx)
+ return false; // Context no longer exists.
+
+ const QGLContext *current = QGLContext::currentContext();
+
+#ifdef QT_DEBUG
+ if (!current ||
+ QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx))
+ {
+ qWarning("QGLFramebufferObject::release() called from incompatible context");
+ }
+#endif
+
+ if (current) {
+ current->d_ptr->current_fbo = current->d_ptr->default_fbo;
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, current->d_ptr->default_fbo);
+ }
+
+ return true;
}
/*!
@@ -510,6 +918,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
{
@@ -530,6 +941,15 @@ QSize QGLFramebufferObject::size() const
}
/*!
+ Returns the format of this framebuffer object.
+*/
+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.
@@ -540,24 +960,63 @@ QImage QGLFramebufferObject::toImage() const
if (!d->valid)
return QImage();
- const_cast<QGLFramebufferObject *>(this)->bind();
- QImage image = qt_gl_read_framebuffer(d->size, d->ctx->format().alpha(), true);
- const_cast<QGLFramebufferObject *>(this)->release();
+ // qt_gl_read_framebuffer doesn't work on a multisample FBO
+ if (format().samples() != 0) {
+ QGLFramebufferObject temp(size(), QGLFramebufferObjectFormat());
+
+ QRect rect(QPoint(0, 0), size());
+ blitFramebuffer(&temp, rect, const_cast<QGLFramebufferObject *>(this), rect);
+
+ return temp.toImage();
+ }
+
+ bool wasBound = isBound();
+ if (!wasBound)
+ const_cast<QGLFramebufferObject *>(this)->bind();
+ QImage image = qt_gl_read_framebuffer(d->size, format().internalTextureFormat() != GL_RGB, true);
+ if (!wasBound)
+ const_cast<QGLFramebufferObject *>(this)->release();
return image;
}
-#if !defined(QT_OPENGL_ES_2)
-Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_paintengine)
+#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
+Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_buffer_2_engine)
+#endif
+
+#ifndef QT_OPENGL_ES_2
+Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_engine)
#endif
/*! \reimp */
QPaintEngine *QGLFramebufferObject::paintEngine() const
{
+ Q_D(const QGLFramebufferObject);
+ if (d->engine)
+ return d->engine;
+
+#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
+#if !defined (QT_OPENGL_ES_2)
+ if (qt_gl_preferGL2Engine()) {
+#endif
+ QPaintEngine *engine = qt_buffer_2_engine();
+ if (engine->isActive() && engine->paintDevice() != this) {
+ d->engine = new QGL2PaintEngineEx;
+ return d->engine;
+ }
+ return engine;
+#if !defined (QT_OPENGL_ES_2)
+ }
+#endif
+#endif
+
#if !defined(QT_OPENGL_ES_2)
- return qt_buffer_paintengine();
-#else
- return 0;
+ QPaintEngine *engine = qt_buffer_engine();
+ if (engine->isActive() && engine->paintDevice() != this) {
+ d->engine = new QOpenGLPaintEngine;
+ return d->engine;
+ }
+ return engine;
#endif
}
@@ -569,7 +1028,7 @@ QPaintEngine *QGLFramebufferObject::paintEngine() const
*/
bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
{
- QGLWidget dmy; // needed to detect and init the QGLExtensions object
+ QGLExtensions::init();
return (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject);
}
@@ -586,16 +1045,14 @@ bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
*/
void QGLFramebufferObject::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
{
- Q_D(QGLFramebufferObject);
- d->ctx->drawTexture(target, textureId, textureTarget);
+ const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget);
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
/*! \internal */
void QGLFramebufferObject::drawTexture(const QRectF &target, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
{
- Q_D(QGLFramebufferObject);
- d->ctx->drawTexture(target, textureId, textureTarget);
+ const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget);
}
#endif
@@ -611,28 +1068,27 @@ void QGLFramebufferObject::drawTexture(const QRectF &target, QMacCompatGLuint te
*/
void QGLFramebufferObject::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
{
- Q_D(QGLFramebufferObject);
- d->ctx->drawTexture(point, textureId, textureTarget);
+ const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(point, textureId, textureTarget);
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
/*! \internal */
void QGLFramebufferObject::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
{
- Q_D(QGLFramebufferObject);
- d->ctx->drawTexture(point, textureId, textureTarget);
+ const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(point, textureId, textureTarget);
}
#endif
-extern int qt_defaultDpi();
+extern int qt_defaultDpiX();
+extern int qt_defaultDpiY();
/*! \reimp */
int QGLFramebufferObject::metric(PaintDeviceMetric metric) const
{
Q_D(const QGLFramebufferObject);
- float dpmx = qt_defaultDpi()*100./2.54;
- float dpmy = qt_defaultDpi()*100./2.54;
+ float dpmx = qt_defaultDpiX()*100./2.54;
+ float dpmy = qt_defaultDpiY()*100./2.54;
int w = d->size.width();
int h = d->size.height();
switch (metric) {
@@ -655,16 +1111,16 @@ int QGLFramebufferObject::metric(PaintDeviceMetric metric) const
return 32;//d->depth;
case PdmDpiX:
- return (int)(dpmx * 0.0254);
+ return qRound(dpmx * 0.0254);
case PdmDpiY:
- return (int)(dpmy * 0.0254);
+ return qRound(dpmy * 0.0254);
case PdmPhysicalDpiX:
- return (int)(dpmx * 0.0254);
+ return qRound(dpmx * 0.0254);
case PdmPhysicalDpiY:
- return (int)(dpmy * 0.0254);
+ return qRound(dpmy * 0.0254);
default:
qWarning("QGLFramebufferObject::metric(), Unhandled metric type: %d.\n", metric);
@@ -685,12 +1141,11 @@ int QGLFramebufferObject::metric(PaintDeviceMetric metric) const
GLuint QGLFramebufferObject::handle() const
{
Q_D(const QGLFramebufferObject);
- return d->fbo;
+ return d->fbo();
}
/*! \fn int QGLFramebufferObject::devType() const
-
- \reimp
+ \internal
*/
@@ -717,7 +1172,93 @@ QGLFramebufferObject::Attachment QGLFramebufferObject::attachment() const
bool QGLFramebufferObject::isBound() const
{
Q_D(const QGLFramebufferObject);
- return d->bound;
+ const QGLContext *current = QGLContext::currentContext();
+ return current ? current->d_ptr->current_fbo == d->fbo() : false;
+}
+
+/*!
+ \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.
+
+ \sa blitFramebuffer()
+*/
+bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
+{
+ QGLExtensions::init();
+ 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
+ \c GL_COLOR_BUFFER_BIT, \c GL_DEPTH_BUFFER_BIT, and
+ \c GL_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 \c GL_DEPTH_BUFFER_BIT or
+ \c GL_STENCIL_BUFFER_BIT. The \a filter parameter should be set to
+ \c GL_LINEAR or \c 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.
+
+ \sa hasOpenGLFramebufferBlit()
+*/
+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();
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, source ? source->handle() : 0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, target ? target->handle() : 0);
+
+ glBlitFramebufferEXT(sx0, sy0, sx1, sy1,
+ tx0, ty0, tx1, ty1,
+ buffers, filter);
+
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
}
QT_END_NAMESPACE
diff --git a/src/opengl/qglframebufferobject.h b/src/opengl/qglframebufferobject.h
index 89d01b1..6cf5571 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();
+ QGLFramebufferObjectFormat format() const;
+
bool isValid() const;
bool isBound() const;
bool bind();
bool release();
+
GLuint texture() const;
QSize size() const;
QImage toImage() const;
@@ -110,14 +117,56 @@ 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; }
private:
Q_DISABLE_COPY(QGLFramebufferObject)
- QGLFramebufferObjectPrivate *d_ptr;
- friend class QGLDrawable;
+ QScopedPointer<QGLFramebufferObjectPrivate> d_ptr;
+ friend class QGLPaintDevice;
+ friend class QGLFBOGLPaintDevice;
+};
+
+class QGLFramebufferObjectFormatPrivate;
+class Q_OPENGL_EXPORT QGLFramebufferObjectFormat
+{
+public:
+ QGLFramebufferObjectFormat();
+ 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 setInternalTextureFormat(GLenum internalTextureFormat);
+ GLenum internalTextureFormat() const;
+
+#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
+ void setTextureTarget(QMacCompatGLenum target);
+ void setInternalTextureFormat(QMacCompatGLenum internalTextureFormat);
+#endif
+
+ bool operator==(const QGLFramebufferObjectFormat& other) const;
+ bool operator!=(const QGLFramebufferObjectFormat& other) const;
+
+private:
+ QGLFramebufferObjectFormatPrivate *d;
+
+ void detach();
};
QT_END_NAMESPACE
diff --git a/src/opengl/qglframebufferobject_p.h b/src/opengl/qglframebufferobject_p.h
new file mode 100644
index 0000000..800cb68
--- /dev/null
+++ b/src/opengl/qglframebufferobject_p.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLFRAMEBUFFEROBJECT_P_H
+#define QGLFRAMEBUFFEROBJECT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+QT_BEGIN_INCLUDE_NAMESPACE
+
+#include <qglframebufferobject.h>
+#include <private/qglpaintdevice_p.h>
+#include <private/qgl_p.h>
+
+QT_END_INCLUDE_NAMESPACE
+
+#ifndef QT_OPENGL_ES
+#define DEFAULT_FORMAT GL_RGBA8
+#else
+#define DEFAULT_FORMAT GL_RGBA
+#endif
+
+class QGLFramebufferObjectFormatPrivate
+{
+public:
+ QGLFramebufferObjectFormatPrivate()
+ : ref(1),
+ samples(0),
+ attachment(QGLFramebufferObject::NoAttachment),
+ target(GL_TEXTURE_2D),
+ internal_format(DEFAULT_FORMAT)
+ {
+ }
+ QGLFramebufferObjectFormatPrivate
+ (const QGLFramebufferObjectFormatPrivate *other)
+ : ref(1),
+ samples(other->samples),
+ attachment(other->attachment),
+ target(other->target),
+ internal_format(other->internal_format)
+ {
+ }
+ bool equals(const QGLFramebufferObjectFormatPrivate *other)
+ {
+ return samples == other->samples &&
+ attachment == other->attachment &&
+ target == other->target &&
+ internal_format == other->internal_format;
+ }
+
+ QAtomicInt ref;
+ int samples;
+ QGLFramebufferObject::Attachment attachment;
+ GLenum target;
+ GLenum internal_format;
+};
+
+class QGLFBOGLPaintDevice : public QGLPaintDevice
+{
+public:
+ virtual QPaintEngine* paintEngine() const {return fbo->paintEngine();}
+ virtual QSize size() const {return fbo->size();}
+ virtual QGLContext* context() const;
+ virtual QGLFormat format() const {return fboFormat;}
+
+ void setFBO(QGLFramebufferObject* f,
+ QGLFramebufferObject::Attachment attachment);
+
+private:
+ bool wasBound;
+ QGLFramebufferObject* fbo;
+ QGLFormat fboFormat;
+};
+
+class QGLFramebufferObjectPrivate
+{
+public:
+ QGLFramebufferObjectPrivate() : fbo_guard(0), texture(0), depth_stencil_buffer(0)
+ , color_buffer(0), valid(false), engine(0) {}
+ ~QGLFramebufferObjectPrivate() {}
+
+ void init(QGLFramebufferObject *q, const QSize& sz,
+ QGLFramebufferObject::Attachment attachment,
+ GLenum internal_format, GLenum texture_target, GLint samples = 0);
+ bool checkFramebufferStatus() const;
+ QGLSharedResourceGuard fbo_guard;
+ GLuint texture;
+ GLuint depth_stencil_buffer;
+ GLuint color_buffer;
+ GLenum target;
+ QSize size;
+ QGLFramebufferObjectFormat format;
+ uint valid : 1;
+ QGLFramebufferObject::Attachment fbo_attachment;
+ mutable QPaintEngine *engine;
+ QGLFBOGLPaintDevice glDevice;
+
+ inline GLuint fbo() const { return fbo_guard.id(); }
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QGLFRAMEBUFFEROBJECT_P_H
diff --git a/src/opengl/qglpaintdevice.cpp b/src/opengl/qglpaintdevice.cpp
new file mode 100644
index 0000000..bcd90a5
--- /dev/null
+++ b/src/opengl/qglpaintdevice.cpp
@@ -0,0 +1,224 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qglpaintdevice_p.h>
+#include <private/qgl_p.h>
+#include <private/qglpixelbuffer_p.h>
+#include <private/qglframebufferobject_p.h>
+#include <private/qwindowsurface_gl_p.h>
+#ifdef Q_WS_X11
+#include <private/qpixmapdata_x11gl_p.h>
+#endif
+
+#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
+#include <private/qpixmapdata_gl_p.h>
+#endif
+
+#if defined(QT_OPENGL_ES_1_CL)
+#include "qgl_cl_p.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+QGLPaintDevice::QGLPaintDevice()
+ : m_thisFBO(0)
+{
+}
+
+QGLPaintDevice::~QGLPaintDevice()
+{
+}
+
+
+void QGLPaintDevice::beginPaint()
+{
+ // Make sure our context is the current one:
+ QGLContext *ctx = context();
+ if (ctx != QGLContext::currentContext())
+ ctx->makeCurrent();
+
+ // Record the currently bound FBO so we can restore it again
+ // in endPaint() and bind this device's FBO
+ //
+ // Note: m_thisFBO could be zero if the paint device is not
+ // backed by an FBO (e.g. window back buffer). But there could
+ // be a previous FBO bound to the context which we need to
+ // explicitly unbind. Otherwise the painting will go into
+ // the previous FBO instead of to the window.
+ m_previousFBO = ctx->d_func()->current_fbo;
+
+ if (m_previousFBO != m_thisFBO) {
+ ctx->d_ptr->current_fbo = m_thisFBO;
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_thisFBO);
+ }
+
+ // Set the default fbo for the context to m_thisFBO so that
+ // if some raw GL code between beginNativePainting() and
+ // endNativePainting() calls QGLFramebufferObject::release(),
+ // painting will revert to the window surface's fbo.
+ ctx->d_ptr->default_fbo = m_thisFBO;
+}
+
+void QGLPaintDevice::ensureActiveTarget()
+{
+ QGLContext* ctx = context();
+ if (ctx != QGLContext::currentContext())
+ ctx->makeCurrent();
+
+ if (ctx->d_ptr->current_fbo != m_thisFBO) {
+ ctx->d_ptr->current_fbo = m_thisFBO;
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_thisFBO);
+ }
+
+ ctx->d_ptr->default_fbo = m_thisFBO;
+}
+
+void QGLPaintDevice::endPaint()
+{
+ // Make sure the FBO bound at beginPaint is re-bound again here:
+ QGLContext *ctx = context();
+ if (m_previousFBO != ctx->d_func()->current_fbo) {
+ ctx->d_ptr->current_fbo = m_previousFBO;
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_previousFBO);
+ }
+
+ ctx->d_ptr->default_fbo = 0;
+}
+
+QGLFormat QGLPaintDevice::format() const
+{
+ return context()->format();
+}
+
+
+
+
+////////////////// QGLWidgetGLPaintDevice //////////////////
+
+QGLWidgetGLPaintDevice::QGLWidgetGLPaintDevice()
+{
+}
+
+QPaintEngine* QGLWidgetGLPaintDevice::paintEngine() const
+{
+ return glWidget->paintEngine();
+}
+
+void QGLWidgetGLPaintDevice::setWidget(QGLWidget* w)
+{
+ glWidget = w;
+}
+
+void QGLWidgetGLPaintDevice::beginPaint()
+{
+ QGLPaintDevice::beginPaint();
+ if (!glWidget->d_func()->disable_clear_on_painter_begin && glWidget->autoFillBackground()) {
+ if (glWidget->testAttribute(Qt::WA_TranslucentBackground))
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ else {
+ const QColor &c = glWidget->palette().brush(glWidget->backgroundRole()).color();
+ float alpha = c.alphaF();
+ glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha);
+ }
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+}
+
+void QGLWidgetGLPaintDevice::endPaint()
+{
+ if (glWidget->autoBufferSwap())
+ glWidget->swapBuffers();
+ QGLPaintDevice::endPaint();
+}
+
+
+QSize QGLWidgetGLPaintDevice::size() const
+{
+ return glWidget->size();
+}
+
+QGLContext* QGLWidgetGLPaintDevice::context() const
+{
+ return const_cast<QGLContext*>(glWidget->context());
+}
+
+// returns the QGLPaintDevice for the given QPaintDevice
+QGLPaintDevice* QGLPaintDevice::getDevice(QPaintDevice* pd)
+{
+ QGLPaintDevice* glpd = 0;
+
+ switch(pd->devType()) {
+ case QInternal::Widget:
+ // Should not be called on a non-gl widget:
+ Q_ASSERT(qobject_cast<QGLWidget*>(static_cast<QWidget*>(pd)));
+ glpd = &(static_cast<QGLWidget*>(pd)->d_func()->glDevice);
+ break;
+ case QInternal::Pbuffer:
+ glpd = &(static_cast<QGLPixelBuffer*>(pd)->d_func()->glDevice);
+ break;
+ case QInternal::FramebufferObject:
+ glpd = &(static_cast<QGLFramebufferObject*>(pd)->d_func()->glDevice);
+ break;
+ case QInternal::Pixmap: {
+#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
+ QPixmapData* pmd = static_cast<QPixmap*>(pd)->pixmapData();
+ if (pmd->classId() == QPixmapData::OpenGLClass)
+ glpd = static_cast<QGLPixmapData*>(pmd)->glDevice();
+#ifdef Q_WS_X11
+ else if (pmd->classId() == QPixmapData::X11Class)
+ glpd = static_cast<QX11GLPixmapData*>(pmd);
+#endif
+ else
+ qWarning("Pixmap type not supported for GL rendering");
+#else
+ qWarning("Pixmap render targets not supported on OpenGL ES 1.x");
+#endif
+ break;
+ }
+ default:
+ qWarning("QGLPaintDevice::getDevice() - Unknown device type %d", pd->devType());
+ break;
+ }
+
+ return glpd;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opengl/qglpaintdevice_p.h b/src/opengl/qglpaintdevice_p.h
new file mode 100644
index 0000000..63ba5da
--- /dev/null
+++ b/src/opengl/qglpaintdevice_p.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLPAINTDEVICE_P_H
+#define QGLPAINTDEVICE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QtOpenGL module. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#include <qpaintdevice.h>
+#include <qgl.h>
+
+
+QT_BEGIN_NAMESPACE
+
+class Q_OPENGL_EXPORT QGLPaintDevice : public QPaintDevice
+{
+public:
+ QGLPaintDevice();
+ virtual ~QGLPaintDevice();
+
+ int devType() const {return QInternal::OpenGL;}
+
+ virtual void beginPaint();
+ virtual void ensureActiveTarget();
+ virtual void endPaint();
+
+ virtual QGLContext* context() const = 0;
+ virtual QGLFormat format() const;
+ virtual QSize size() const = 0;
+
+ // returns the QGLPaintDevice for the given QPaintDevice
+ static QGLPaintDevice* getDevice(QPaintDevice*);
+
+protected:
+ GLuint m_previousFBO;
+ GLuint m_thisFBO;
+};
+
+
+// Wraps a QGLWidget
+class QGLWidget;
+class QGLWidgetGLPaintDevice : public QGLPaintDevice
+{
+public:
+ QGLWidgetGLPaintDevice();
+
+ virtual QPaintEngine* paintEngine() const;
+
+ // QGLWidgets need to do swapBufers in endPaint:
+ virtual void beginPaint();
+ virtual void endPaint();
+ virtual QSize size() const;
+ virtual QGLContext* context() const;
+
+ void setWidget(QGLWidget*);
+
+private:
+ friend class QGLWidget;
+ QGLWidget *glWidget;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGLPAINTDEVICE_P_H
diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp
index 82b7b1c..7c97ebb 100644
--- a/src/opengl/qglpixelbuffer.cpp
+++ b/src/opengl/qglpixelbuffer.cpp
@@ -44,7 +44,7 @@
\brief The QGLPixelBuffer class encapsulates an OpenGL pbuffer.
\since 4.1
- \ingroup multimedia
+ \ingroup painting-3D
Rendering into a pbuffer is normally done using full hardware
acceleration. This can be significantly faster than rendering
@@ -76,12 +76,17 @@
\sa {opengl/pbuffers}{Pbuffers Example}
*/
+#include <QtCore/qglobal.h>
+
+#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
+#include <private/qpaintengineex_opengl2_p.h>
+#endif
#include <qglpixelbuffer.h>
#include <private/qglpixelbuffer_p.h>
#include <qimage.h>
-#if !defined(QT_OPENGL_ES_2)
+#ifndef QT_OPENGL_ES_2
#include <private/qpaintengine_opengl_p.h>
#endif
@@ -95,6 +100,22 @@ void qgl_cleanup_glyph_cache(QGLContext *) {}
extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
+
+QGLContext* QGLPBufferGLPaintDevice::context() const
+{
+ return pbuf->d_func()->qctx;
+}
+
+void QGLPBufferGLPaintDevice::endPaint() {
+ glFlush();
+ QGLPaintDevice::endPaint();
+}
+
+void QGLPBufferGLPaintDevice::setPBuffer(QGLPixelBuffer* pb)
+{
+ pbuf = pb;
+}
+
void QGLPixelBufferPrivate::common_init(const QSize &size, const QGLFormat &format, QGLWidget *shareWidget)
{
Q_Q(QGLPixelBuffer);
@@ -105,9 +126,12 @@ void QGLPixelBufferPrivate::common_init(const QSize &size, const QGLFormat &form
invalid = false;
qctx = new QGLContext(format);
qctx->d_func()->sharing = (shareWidget != 0);
- if (shareWidget != 0 && shareWidget->d_func()->glcx)
+ if (shareWidget != 0 && shareWidget->d_func()->glcx) {
qgl_share_reg()->addShare(qctx, shareWidget->d_func()->glcx);
+ shareWidget->d_func()->glcx->d_func()->sharing = true;
+ }
+ glDevice.setPBuffer(q);
qctx->d_func()->paintDevice = q;
qctx->d_func()->valid = true;
#if defined(Q_WS_WIN) && !defined(QT_OPENGL_ES)
@@ -122,6 +146,7 @@ void QGLPixelBufferPrivate::common_init(const QSize &size, const QGLFormat &form
qctx->d_func()->vi = 0;
#elif defined(QT_OPENGL_ES)
qctx->d_func()->eglContext = ctx;
+ qctx->d_func()->eglSurface = pbuf;
#endif
}
}
@@ -186,7 +211,6 @@ QGLPixelBuffer::~QGLPixelBuffer()
delete d->qctx;
if (current && current != d->qctx)
current->makeCurrent();
- delete d_ptr;
}
/*! \fn bool QGLPixelBuffer::makeCurrent()
@@ -363,29 +387,39 @@ bool QGLPixelBuffer::isValid() const
return !d->invalid;
}
-#if !defined(QT_OPENGL_ES_2)
-Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_paintengine)
+#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
+Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_buffer_2_engine)
+#endif
+
+#ifndef QT_OPENGL_ES_2
+Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_engine)
#endif
/*! \reimp */
QPaintEngine *QGLPixelBuffer::paintEngine() const
{
-#if !defined(QT_OPENGL_ES_2)
- return qt_buffer_paintengine();
+#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL)
+ return qt_buffer_engine();
+#elif defined(QT_OPENGL_ES_2)
+ return qt_buffer_2_engine();
#else
- return 0;
+ if (qt_gl_preferGL2Engine())
+ return qt_buffer_2_engine();
+ else
+ return qt_buffer_engine();
#endif
}
-extern int qt_defaultDpi();
+extern int qt_defaultDpiX();
+extern int qt_defaultDpiY();
/*! \reimp */
int QGLPixelBuffer::metric(PaintDeviceMetric metric) const
{
Q_D(const QGLPixelBuffer);
- float dpmx = qt_defaultDpi()*100./2.54;
- float dpmy = qt_defaultDpi()*100./2.54;
+ float dpmx = qt_defaultDpiX()*100./2.54;
+ float dpmy = qt_defaultDpiY()*100./2.54;
int w = d->req_size.width();
int h = d->req_size.height();
switch (metric) {
@@ -408,16 +442,16 @@ int QGLPixelBuffer::metric(PaintDeviceMetric metric) const
return 32;//d->depth;
case PdmDpiX:
- return (int)(dpmx * 0.0254);
+ return qRound(dpmx * 0.0254);
case PdmDpiY:
- return (int)(dpmy * 0.0254);
+ return qRound(dpmy * 0.0254);
case PdmPhysicalDpiX:
- return (int)(dpmx * 0.0254);
+ return qRound(dpmx * 0.0254);
case PdmPhysicalDpiY:
- return (int)(dpmy * 0.0254);
+ return qRound(dpmy * 0.0254);
default:
qWarning("QGLPixelBuffer::metric(), Unhandled metric type: %d\n", metric);
@@ -576,7 +610,7 @@ QGLFormat QGLPixelBuffer::format() const
}
/*! \fn int QGLPixelBuffer::devType() const
- \reimp
+ \internal
*/
QT_END_NAMESPACE
diff --git a/src/opengl/qglpixelbuffer.h b/src/opengl/qglpixelbuffer.h
index 971715e..94ecd46 100644
--- a/src/opengl/qglpixelbuffer.h
+++ b/src/opengl/qglpixelbuffer.h
@@ -107,9 +107,11 @@ protected:
private:
Q_DISABLE_COPY(QGLPixelBuffer)
- QGLPixelBufferPrivate *d_ptr;
+ QScopedPointer<QGLPixelBufferPrivate> d_ptr;
friend class QGLDrawable;
friend class QGLWindowSurface;
+ friend class QGLPaintDevice;
+ friend class QGLPBufferGLPaintDevice;
};
QT_END_NAMESPACE
diff --git a/src/opengl/qglpixelbuffer_egl.cpp b/src/opengl/qglpixelbuffer_egl.cpp
index fbe6c36..de08655 100644
--- a/src/opengl/qglpixelbuffer_egl.cpp
+++ b/src/opengl/qglpixelbuffer_egl.cpp
@@ -63,7 +63,7 @@ bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidge
{
// Create the EGL context.
ctx = new QEglContext();
- ctx->setApi(QEglContext::OpenGL);
+ ctx->setApi(QEgl::OpenGL);
// Open the EGL display.
if (!ctx->openDisplay(0)) {
@@ -72,37 +72,53 @@ bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidge
return false;
}
+ // Find the shared context.
+ QEglContext *shareContext = 0;
+ if (shareWidget && shareWidget->d_func()->glcx)
+ shareContext = shareWidget->d_func()->glcx->d_func()->eglContext;
+
// Choose an appropriate configuration. We use the best format
// we can find, even if it is greater than the requested format.
// We try for a pbuffer that is capable of texture rendering if possible.
- QEglProperties configProps;
- qt_egl_set_format(configProps, QInternal::Pbuffer, f);
- configProps.setRenderableType(ctx->api());
- bool ok = false;
+ textureFormat = EGL_NONE;
+ if (shareContext) {
+ // Use the same configuration as the widget we are sharing with.
+ ctx->setConfig(shareContext->config());
+#if QGL_RENDER_TEXTURE
+ EGLint value = EGL_FALSE;
+ if (ctx->configAttrib(EGL_BIND_TO_TEXTURE_RGBA, &value) && value)
+ textureFormat = EGL_TEXTURE_RGBA;
+ else if (ctx->configAttrib(EGL_BIND_TO_TEXTURE_RGB, &value) && value)
+ textureFormat = EGL_TEXTURE_RGB;
+#endif
+ } else {
+ QEglProperties configProps;
+ qt_egl_set_format(configProps, QInternal::Pbuffer, f);
+ configProps.setRenderableType(ctx->api());
+ bool ok = false;
#if QGL_RENDER_TEXTURE
- textureFormat = EGL_TEXTURE_RGBA;
- configProps.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE);
- ok = ctx->chooseConfig(configProps, QEglContext::BestPixelFormat);
- if (!ok) {
- // Try again with RGB texture rendering.
- textureFormat = EGL_TEXTURE_RGB;
- configProps.removeValue(EGL_BIND_TO_TEXTURE_RGBA);
- configProps.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE);
- ok = ctx->chooseConfig(configProps, QEglContext::BestPixelFormat);
+ textureFormat = EGL_TEXTURE_RGBA;
+ configProps.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE);
+ ok = ctx->chooseConfig(configProps, QEgl::BestPixelFormat);
if (!ok) {
- // One last try for a pbuffer with no texture rendering.
- configProps.removeValue(EGL_BIND_TO_TEXTURE_RGB);
- textureFormat = EGL_NONE;
+ // Try again with RGB texture rendering.
+ textureFormat = EGL_TEXTURE_RGB;
+ configProps.removeValue(EGL_BIND_TO_TEXTURE_RGBA);
+ configProps.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE);
+ ok = ctx->chooseConfig(configProps, QEgl::BestPixelFormat);
+ if (!ok) {
+ // One last try for a pbuffer with no texture rendering.
+ configProps.removeValue(EGL_BIND_TO_TEXTURE_RGB);
+ textureFormat = EGL_NONE;
+ }
}
- }
-#else
- textureFormat = EGL_NONE;
#endif
- if (!ok) {
- if (!ctx->chooseConfig(configProps, QEglContext::BestPixelFormat)) {
- delete ctx;
- ctx = 0;
- return false;
+ if (!ok) {
+ if (!ctx->chooseConfig(configProps, QEgl::BestPixelFormat)) {
+ delete ctx;
+ ctx = 0;
+ return false;
+ }
}
}
@@ -135,12 +151,8 @@ bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidge
qWarning() << "QGLPixelBufferPrivate::init(): Unable to create EGL pbuffer surface:" << QEglContext::errorString(eglGetError());
return false;
}
- ctx->setSurface(pbuf);
// Create a new context for the configuration.
- QEglContext *shareContext = 0;
- if (shareWidget && shareWidget->d_func()->glcx)
- shareContext = shareWidget->d_func()->glcx->d_func()->eglContext;
if (!ctx->createContext(shareContext)) {
delete ctx;
ctx = 0;
@@ -163,7 +175,7 @@ bool QGLPixelBuffer::bindToDynamicTexture(GLuint texture_id)
if (d->invalid || d->textureFormat == EGL_NONE || !d->ctx)
return false;
glBindTexture(GL_TEXTURE_2D, texture_id);
- return eglBindTexImage(d->ctx->display(), d->ctx->surface(), EGL_BACK_BUFFER);
+ return eglBindTexImage(d->ctx->display(), d->pbuf, EGL_BACK_BUFFER);
#else
Q_UNUSED(texture_id);
return false;
@@ -176,7 +188,7 @@ void QGLPixelBuffer::releaseFromDynamicTexture()
Q_D(QGLPixelBuffer);
if (d->invalid || d->textureFormat == EGL_NONE || !d->ctx)
return;
- eglReleaseTexImage(d->ctx->display(), d->ctx->surface(), EGL_BACK_BUFFER);
+ eglReleaseTexImage(d->ctx->display(), d->pbuf, EGL_BACK_BUFFER);
#endif
}
@@ -208,7 +220,7 @@ bool QGLPixelBuffer::hasOpenGLPbuffers()
return false;
QEglProperties configProps;
qt_egl_set_format(configProps, QInternal::Pbuffer, QGLFormat::defaultFormat());
- configProps.setRenderableType(QEglContext::OpenGL);
+ configProps.setRenderableType(QEgl::OpenGL);
do {
EGLConfig cfg = 0;
EGLint matching = 0;
diff --git a/src/opengl/qglpixelbuffer_p.h b/src/opengl/qglpixelbuffer_p.h
index d4febb8..7fde802 100644
--- a/src/opengl/qglpixelbuffer_p.h
+++ b/src/opengl/qglpixelbuffer_p.h
@@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE
QT_BEGIN_INCLUDE_NAMESPACE
#include "QtOpenGL/qglpixelbuffer.h"
#include <private/qgl_p.h>
+#include <private/qglpaintdevice_p.h>
#if defined(Q_WS_X11) && !defined(QT_OPENGL_ES)
#include <GL/glx.h>
@@ -135,6 +136,19 @@ QT_END_INCLUDE_NAMESPACE
class QEglContext;
+
+class QGLPBufferGLPaintDevice : public QGLPaintDevice
+{
+public:
+ virtual QPaintEngine* paintEngine() const {return pbuf->paintEngine();}
+ virtual QSize size() const {return pbuf->size();}
+ virtual QGLContext* context() const;
+ virtual void endPaint();
+ void setPBuffer(QGLPixelBuffer* pb);
+private:
+ QGLPixelBuffer* pbuf;
+};
+
class QGLPixelBufferPrivate {
Q_DECLARE_PUBLIC(QGLPixelBuffer)
public:
@@ -154,6 +168,7 @@ public:
QGLPixelBuffer *q_ptr;
bool invalid;
QGLContext *qctx;
+ QGLPBufferGLPaintDevice glDevice;
QGLFormat format;
QGLFormat req_format;
diff --git a/src/opengl/qglpixelbuffer_x11.cpp b/src/opengl/qglpixelbuffer_x11.cpp
index 9900b71..6971133 100644
--- a/src/opengl/qglpixelbuffer_x11.cpp
+++ b/src/opengl/qglpixelbuffer_x11.cpp
@@ -93,6 +93,8 @@ static _glXMakeContextCurrent qt_glXMakeContextCurrent = 0;
#define glXGetFBConfigAttrib qt_glXGetFBConfigAttrib
#define glXMakeContextCurrent qt_glXMakeContextCurrent
+extern void* qglx_getProcAddress(const char* procName); // in qgl_x11.cpp
+
static bool qt_resolve_pbuffer_extensions()
{
static int resolved = false;
@@ -101,29 +103,12 @@ static bool qt_resolve_pbuffer_extensions()
else if (resolved)
return false;
-#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
- void *handle = dlopen(NULL, RTLD_LAZY);
- if (handle) {
- qt_glXChooseFBConfig = (_glXChooseFBConfig) dlsym(handle, "glXChooseFBConfig");
- qt_glXCreateNewContext = (_glXCreateNewContext) dlsym(handle, "glXCreateNewContext");
- qt_glXCreatePbuffer = (_glXCreatePbuffer) dlsym(handle, "glXCreatePbuffer");
- qt_glXDestroyPbuffer = (_glXDestroyPbuffer) dlsym(handle, "glXDestroyPbuffer");
- qt_glXGetFBConfigAttrib = (_glXGetFBConfigAttrib) dlsym(handle, "glXGetFBConfigAttrib");
- qt_glXMakeContextCurrent = (_glXMakeContextCurrent) dlsym(handle, "glXMakeContextCurrent");
- dlclose(handle);
- }
- if (!qt_glXChooseFBConfig)
-#endif
- {
- extern const QString qt_gl_library_name();
- QLibrary gl(qt_gl_library_name());
- qt_glXChooseFBConfig = (_glXChooseFBConfig) gl.resolve("glXChooseFBConfig");
- qt_glXCreateNewContext = (_glXCreateNewContext) gl.resolve("glXCreateNewContext");
- qt_glXCreatePbuffer = (_glXCreatePbuffer) gl.resolve("glXCreatePbuffer");
- qt_glXDestroyPbuffer = (_glXDestroyPbuffer) gl.resolve("glXDestroyPbuffer");
- qt_glXGetFBConfigAttrib = (_glXGetFBConfigAttrib) gl.resolve("glXGetFBConfigAttrib");
- qt_glXMakeContextCurrent = (_glXMakeContextCurrent) gl.resolve("glXMakeContextCurrent");
- }
+ qt_glXChooseFBConfig = (_glXChooseFBConfig) qglx_getProcAddress("glXChooseFBConfig");
+ qt_glXCreateNewContext = (_glXCreateNewContext) qglx_getProcAddress("glXCreateNewContext");
+ qt_glXCreatePbuffer = (_glXCreatePbuffer) qglx_getProcAddress("glXCreatePbuffer");
+ qt_glXDestroyPbuffer = (_glXDestroyPbuffer) qglx_getProcAddress("glXDestroyPbuffer");
+ qt_glXGetFBConfigAttrib = (_glXGetFBConfigAttrib) qglx_getProcAddress("glXGetFBConfigAttrib");
+ qt_glXMakeContextCurrent = (_glXMakeContextCurrent) qglx_getProcAddress("glXMakeContextCurrent");
resolved = qt_glXMakeContextCurrent ? true : false;
return resolved;
diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp
index 6ae791f..d4bcbe9 100644
--- a/src/opengl/qglpixmapfilter.cpp
+++ b/src/opengl/qglpixmapfilter.cpp
@@ -40,38 +40,35 @@
****************************************************************************/
#include "private/qpixmapfilter_p.h"
+#include "private/qpixmapdata_gl_p.h"
+#include "private/qpaintengineex_opengl2_p.h"
+#include "private/qglengineshadermanager_p.h"
+#include "private/qpixmapdata_p.h"
+#include "private/qimagepixmapcleanuphooks_p.h"
#include "qglpixmapfilter_p.h"
#include "qgraphicssystem_gl_p.h"
#include "qpaintengine_opengl_p.h"
+#include "qcache.h"
-#include "qglpixelbuffer.h"
-#include "qglextensions_p.h"
+#include "qglframebufferobject.h"
+#include "qglshaderprogram.h"
#include "qgl_p.h"
#include "private/qapplication_p.h"
-
-
-#ifndef GL_FRAGMENT_SHADER
-#define GL_FRAGMENT_SHADER 0x8B30
-#endif
-
-#ifndef GL_COMPILE_STATUS
-#define GL_COMPILE_STATUS 0x8B81
-#endif
-
-#ifndef GL_LINK_STATUS
-#define GL_LINK_STATUS 0x8B82
-#endif
-
-
-
+#include "private/qdrawhelper_p.h"
+#include "private/qmemrotate_p.h"
+#include "private/qmath_p.h"
+#include "qmath.h"
QT_BEGIN_NAMESPACE
+// qpixmapfilter.cpp
+void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0);
+QImage qt_halfScaled(const QImage &source);
void QGLPixmapFilterBase::bindTexture(const QPixmap &src) const
{
- const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA, true);
+ const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA, QGLContext::BindOptions(QGLContext::DefaultBindOption | QGLContext::MemoryManagedBindOption));
}
void QGLPixmapFilterBase::drawImpl(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF& source) const
@@ -79,331 +76,555 @@ void QGLPixmapFilterBase::drawImpl(QPainter *painter, const QPointF &pos, const
processGL(painter, pos, src, source);
}
-QGLSLProgram::QGLSLProgram(const QString &src)
- : ctx(QGLContext::currentContext())
+class QGLPixmapColorizeFilter: public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapColorizeFilter>
{
- if (!qt_resolve_glsl_extensions(const_cast<QGLContext *>(ctx))) {
- qWarning("Failed to resolve GLSL functions");
- m_valid = false;
- return;
- }
+public:
+ QGLPixmapColorizeFilter();
+
+ void setUniforms(QGLShaderProgram *program);
- m_shader = glCreateShader(GL_FRAGMENT_SHADER);
+protected:
+ bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &pixmap, const QRectF &srcRect) const;
+};
- const QByteArray src_ba = src.toAscii();
- const char *src_cstr = src_ba.constData();
+class QGLPixmapConvolutionFilter: public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapConvolutionFilter>
+{
+public:
+ QGLPixmapConvolutionFilter();
+ ~QGLPixmapConvolutionFilter();
- glShaderSource(m_shader, 1, &src_cstr, 0);
- glCompileShader(m_shader);
- glGetShaderiv(m_shader, GL_COMPILE_STATUS, &m_valid);
- if (!m_valid) {
- char data[4096];
- GLsizei len;
- glGetShaderInfoLog(m_shader, 4096, &len, data);
- qWarning("Failed to compile GLSL shader:\n%s\nCODE:\n%s\n", data, src_cstr);
- return;
- }
+ void setUniforms(QGLShaderProgram *program);
- m_program = glCreateProgram();
- glAttachShader(m_program, m_shader);
- glLinkProgram(m_program);
- glGetProgramiv(m_program, GL_LINK_STATUS, &m_valid);
- if (!m_valid) {
- char data[4096];
- GLsizei len;
- glGetShaderInfoLog(m_shader, 4096, &len, data);
- qWarning("Failed to link GLSL program:\n%s\nCODE:\n%s\n", data, src_cstr);
- return;
- }
-}
+protected:
+ bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const;
-QGLSLProgram::~QGLSLProgram()
+private:
+ QByteArray generateConvolutionShader() const;
+
+ mutable QSize m_srcSize;
+ mutable int m_prevKernelSize;
+};
+
+class QGLPixmapBlurFilter : public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapBlurFilter>
{
- glDeleteProgram(m_program);
- glDeleteShader(m_shader);
-}
+public:
+ QGLPixmapBlurFilter();
+
+protected:
+ bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const;
+};
-bool QGLSLProgram::success() const
+class QGLPixmapDropShadowFilter : public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapDropShadowFilter>
{
- return m_valid;
-}
+public:
+ QGLPixmapDropShadowFilter();
+
+ void setUniforms(QGLShaderProgram *program);
-void QGLSLProgram::enable()
+protected:
+ bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const;
+};
+
+extern QGLWidget *qt_gl_share_widget();
+
+QPixmapFilter *QGL2PaintEngineEx::pixmapFilter(int type, const QPixmapFilter *prototype)
{
- glUseProgram(m_program);
+ Q_D(QGL2PaintEngineEx);
+ switch (type) {
+ case QPixmapFilter::ColorizeFilter:
+ if (!d->colorizeFilter)
+ d->colorizeFilter.reset(new QGLPixmapColorizeFilter);
+ return d->colorizeFilter.data();
+
+ case QPixmapFilter::BlurFilter: {
+ if (!d->blurFilter)
+ d->blurFilter.reset(new QGLPixmapBlurFilter());
+ return d->blurFilter.data();
+ }
+
+ case QPixmapFilter::DropShadowFilter: {
+ if (!d->dropShadowFilter)
+ d->dropShadowFilter.reset(new QGLPixmapDropShadowFilter());
+ return d->dropShadowFilter.data();
+ }
+
+ case QPixmapFilter::ConvolutionFilter:
+ if (!d->convolutionFilter)
+ d->convolutionFilter.reset(new QGLPixmapConvolutionFilter);
+ return d->convolutionFilter.data();
+
+ default: break;
+ }
+ return QPaintEngineEx::pixmapFilter(type, prototype);
}
-void QGLSLProgram::disable()
+static const char *qt_gl_colorize_filter =
+ "uniform lowp vec4 colorizeColor;"
+ "uniform lowp float colorizeStrength;"
+ "lowp vec4 customShader(lowp sampler2D src, highp vec2 srcCoords)"
+ "{"
+ " lowp vec4 srcPixel = texture2D(src, srcCoords);"
+ " lowp float gray = dot(srcPixel.rgb, vec3(0.212671, 0.715160, 0.072169));"
+ " lowp vec3 colorized = 1.0-((1.0-gray)*(1.0-colorizeColor.rgb));"
+ " return vec4(mix(srcPixel.rgb, colorized * srcPixel.a, colorizeStrength), srcPixel.a);"
+ "}";
+
+QGLPixmapColorizeFilter::QGLPixmapColorizeFilter()
{
- glUseProgram(0);
+ setSource(qt_gl_colorize_filter);
}
-typedef GLuint (APIENTRY *_glGetUniformLocation) (GLuint, const char*);
-typedef void (APIENTRY *_glUniform4fv) (GLint, GLsizei, GLfloat *);
-typedef void (APIENTRY *_glUniform3fv) (GLint, GLsizei, GLfloat *);
-typedef void (APIENTRY *_glUniform2fv) (GLint, GLsizei, GLfloat *);
-typedef void (APIENTRY *_glUniform1fv) (GLint, GLsizei, GLfloat *);
-typedef void (APIENTRY *_glUniform1i) (GLint, GLint);
-
-int QGLSLProgram::getUniformLocation(const QString &name)
+bool QGLPixmapColorizeFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &) const
{
- return glGetUniformLocation(m_program, name.toAscii().constData());
+ QGLPixmapColorizeFilter *filter = const_cast<QGLPixmapColorizeFilter *>(this);
+
+ filter->setOnPainter(painter);
+ painter->drawPixmap(pos, src);
+ filter->removeFromPainter(painter);
+
+ return true;
}
-void QGLSLProgram::setUniform(int uniform, int value)
+void QGLPixmapColorizeFilter::setUniforms(QGLShaderProgram *program)
{
- enable();
- glUniform1i(uniform, value);
+ program->setUniformValue("colorizeColor", color());
+ program->setUniformValue("colorizeStrength", float(strength()));
}
-void QGLSLProgram::setUniform(int uniform, qreal value)
+void QGLPixmapConvolutionFilter::setUniforms(QGLShaderProgram *program)
{
- enable();
- GLfloat v[] = { value };
- glUniform1fv(uniform, 1, v);
+ const qreal *kernel = convolutionKernel();
+ int kernelWidth = columns();
+ int kernelHeight = rows();
+ int kernelSize = kernelWidth * kernelHeight;
+
+ QVarLengthArray<GLfloat> matrix(kernelSize);
+ QVarLengthArray<GLfloat> offset(kernelSize * 2);
+
+ for(int i = 0; i < kernelSize; ++i)
+ matrix[i] = kernel[i];
+
+ for(int y = 0; y < kernelHeight; ++y) {
+ for(int x = 0; x < kernelWidth; ++x) {
+ offset[(y * kernelWidth + x) * 2] = x - (kernelWidth / 2);
+ offset[(y * kernelWidth + x) * 2 + 1] = (kernelHeight / 2) - y;
+ }
+ }
+
+ const qreal iw = 1.0 / m_srcSize.width();
+ const qreal ih = 1.0 / m_srcSize.height();
+ program->setUniformValue("inv_texture_size", iw, ih);
+ program->setUniformValueArray("matrix", matrix.constData(), kernelSize, 1);
+ program->setUniformValueArray("offset", offset.constData(), kernelSize, 2);
}
-void QGLSLProgram::setUniform(int uniform, qreal v1, qreal v2)
+// generates convolution filter code for arbitrary sized kernel
+QByteArray QGLPixmapConvolutionFilter::generateConvolutionShader() const {
+ QByteArray code;
+ int kernelWidth = columns();
+ int kernelHeight = rows();
+ int kernelSize = kernelWidth * kernelHeight;
+ code.append("uniform highp vec2 inv_texture_size;\n"
+ "uniform mediump float matrix[");
+ code.append(QByteArray::number(kernelSize));
+ code.append("];\n"
+ "uniform highp vec2 offset[");
+ code.append(QByteArray::number(kernelSize));
+ code.append("];\n");
+ code.append("lowp vec4 customShader(lowp sampler2D src, highp vec2 srcCoords) {\n");
+
+ code.append(" int i = 0;\n"
+ " lowp vec4 sum = vec4(0.0);\n"
+ " for (i = 0; i < ");
+ code.append(QByteArray::number(kernelSize));
+ code.append("; i++) {\n"
+ " sum += matrix[i] * texture2D(src,srcCoords+inv_texture_size*offset[i]);\n"
+ " }\n"
+ " return sum;\n"
+ "}");
+ return code;
+}
+
+QGLPixmapConvolutionFilter::QGLPixmapConvolutionFilter()
+ : m_prevKernelSize(-1)
{
- enable();
- GLfloat v[] = { v1, v2 };
- glUniform2fv(uniform, 1, v);
}
-void QGLSLProgram::setUniform(int uniform, qreal v1, qreal v2, qreal v3)
+QGLPixmapConvolutionFilter::~QGLPixmapConvolutionFilter()
{
- enable();
- GLfloat v[] = { v1, v2, v3 };
- glUniform3fv(uniform, 1, v);
}
-void QGLSLProgram::setUniform(int uniform, qreal v1, qreal v2, qreal v3, qreal v4)
+bool QGLPixmapConvolutionFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const
{
- enable();
- GLfloat v[] = { v1, v2, v3, v4 };
- glUniform4fv(uniform, 1, v);
+ QGLPixmapConvolutionFilter *filter = const_cast<QGLPixmapConvolutionFilter *>(this);
+
+ m_srcSize = src.size();
+
+ int kernelSize = rows() * columns();
+ if (m_prevKernelSize == -1 || m_prevKernelSize != kernelSize) {
+ filter->setSource(generateConvolutionShader());
+ m_prevKernelSize = kernelSize;
+ }
+
+ filter->setOnPainter(painter);
+ painter->drawPixmap(pos, src, srcRect);
+ filter->removeFromPainter(painter);
+
+ return true;
}
-void QGLSLProgram::setUniform(int uniform, int count, float *v)
+QGLPixmapBlurFilter::QGLPixmapBlurFilter()
{
- enable();
- glUniform1fv(uniform, count, v);
}
-class QGLPixmapColorizeFilter: public QGLPixmapFilter<QPixmapColorizeFilter>
+class QGLBlurTextureInfo
{
public:
- QGLPixmapColorizeFilter();
+ QGLBlurTextureInfo(const QImage &image, GLuint tex, qreal r)
+ : m_texture(tex)
+ , m_radius(r)
+ {
+ m_paddedImage << image;
+ }
-protected:
- bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &pixmap, const QRectF &srcRect) const;
+ ~QGLBlurTextureInfo()
+ {
+ glDeleteTextures(1, &m_texture);
+ }
+
+ QImage paddedImage(int scaleLevel = 0) const;
+ GLuint texture() const { return m_texture; }
+ qreal radius() const { return m_radius; }
private:
- mutable QGLSLProgram m_program;
- uint m_colorUniform;
+ mutable QList<QImage> m_paddedImage;
+ GLuint m_texture;
+ qreal m_radius;
};
-class QGLPixmapConvolutionFilter: public QGLPixmapFilter<QPixmapConvolutionFilter>
+QImage QGLBlurTextureInfo::paddedImage(int scaleLevel) const
+{
+ for (int i = m_paddedImage.size() - 1; i <= scaleLevel; ++i)
+ m_paddedImage << qt_halfScaled(m_paddedImage.at(i));
+
+ return m_paddedImage.at(scaleLevel);
+}
+
+class QGLBlurTextureCache : public QObject
{
public:
- QGLPixmapConvolutionFilter();
- ~QGLPixmapConvolutionFilter();
+ static QGLBlurTextureCache *cacheForContext(const QGLContext *context);
-protected:
- bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const;
+ QGLBlurTextureCache();
+ ~QGLBlurTextureCache();
+
+ QGLBlurTextureInfo *takeBlurTextureInfo(const QPixmap &pixmap);
+ bool hasBlurTextureInfo(const QPixmap &pixmap) const;
+ void insertBlurTextureInfo(const QPixmap &pixmap, QGLBlurTextureInfo *info);
+ void clearBlurTextureInfo(const QPixmap &pixmap);
+
+ void timerEvent(QTimerEvent *event);
private:
- QString generateConvolutionShader() const;
+ static void pixmapDestroyed(QPixmap *pixmap);
+
+ QCache<quint64, QGLBlurTextureInfo > cache;
- mutable QGLSLProgram *m_program;
- mutable uint m_scaleUniform;
- mutable uint m_matrixUniform;
+ static QList<QGLBlurTextureCache *> blurTextureCaches;
- mutable int m_kernelWidth;
- mutable int m_kernelHeight;
+ int timerId;
};
-extern QGLWidget *qt_gl_share_widget();
+QList<QGLBlurTextureCache *> QGLBlurTextureCache::blurTextureCaches;
-QPixmapFilter *QGLContextPrivate::createPixmapFilter(int type) const
+static void QGLBlurTextureCache_free(void *ptr)
{
- switch (type) {
- case QPixmapFilter::ColorizeFilter:
- return new QGLPixmapColorizeFilter;
+ delete reinterpret_cast<QGLBlurTextureCache *>(ptr);
+}
+Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_blur_texture_caches, (QGLBlurTextureCache_free))
- case QPixmapFilter::ConvolutionFilter:
- return new QGLPixmapConvolutionFilter;
+QGLBlurTextureCache::QGLBlurTextureCache()
+ : timerId(0)
+{
+ cache.setMaxCost(4 * 1024 * 1024);
+ blurTextureCaches.append(this);
+}
+
+QGLBlurTextureCache::~QGLBlurTextureCache()
+{
+ blurTextureCaches.removeAt(blurTextureCaches.indexOf(this));
+}
+
+void QGLBlurTextureCache::timerEvent(QTimerEvent *)
+{
+ killTimer(timerId);
+ timerId = 0;
- default:
- return 0;
- break;
+ cache.clear();
+}
+
+QGLBlurTextureCache *QGLBlurTextureCache::cacheForContext(const QGLContext *context)
+{
+ QGLBlurTextureCache *p = reinterpret_cast<QGLBlurTextureCache *>(qt_blur_texture_caches()->value(context));
+ if (!p) {
+ p = new QGLBlurTextureCache;
+ qt_blur_texture_caches()->insert(context, p);
}
- return 0;
+ return p;
}
-#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);
-#endif
+QGLBlurTextureInfo *QGLBlurTextureCache::takeBlurTextureInfo(const QPixmap &pixmap)
+{
+ return cache.take(pixmap.cacheKey());
+}
-static void qgl_drawTexture(const QRectF &rect, int tx_width, int tx_height, const QRectF & src)
+void QGLBlurTextureCache::clearBlurTextureInfo(const QPixmap &pixmap)
{
-#ifndef QT_OPENGL_ES_2 // XXX: needs to be ported
-#ifndef QT_OPENGL_ES
- glPushAttrib(GL_CURRENT_BIT);
-#endif
- qreal x1, x2, y1, y2;
+ cache.remove(pixmap.cacheKey());
+}
- x1 = src.x() / tx_width;
- x2 = x1 + src.width() / tx_width;
- y1 = 1.0 - ((src.y() / tx_height) + (src.height() / tx_height));
- y2 = 1.0 - (src.y() / tx_height);
+bool QGLBlurTextureCache::hasBlurTextureInfo(const QPixmap &pixmap) const
+{
+ return cache.contains(pixmap.cacheKey());
+}
- q_vertexType vertexArray[4*2];
- q_vertexType texCoordArray[4*2];
+void QGLBlurTextureCache::insertBlurTextureInfo(const QPixmap &pixmap, QGLBlurTextureInfo *info)
+{
+ static bool hookAdded = false;
+ if (!hookAdded) {
+ QImagePixmapCleanupHooks::instance()->addPixmapDestructionHook(pixmapDestroyed);
+ hookAdded = true;
+ }
- qt_add_rect_to_array(rect, vertexArray);
- qt_add_texcoords_to_array(x1, y2, x2, y1, texCoordArray);
+ QImagePixmapCleanupHooks::enableCleanupHooks(pixmap);
+ cache.insert(pixmap.cacheKey(), info, pixmap.width() * pixmap.height());
- glVertexPointer(2, q_vertexTypeEnum, 0, vertexArray);
- glTexCoordPointer(2, q_vertexTypeEnum, 0, texCoordArray);
+ if (timerId)
+ killTimer(timerId);
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glDisableClientState(GL_VERTEX_ARRAY);
+ timerId = startTimer(8000);
+}
-#ifndef QT_OPENGL_ES
- glPopAttrib();
-#endif
-#endif
+void QGLBlurTextureCache::pixmapDestroyed(QPixmap *pixmap)
+{
+ foreach (QGLBlurTextureCache *cache, blurTextureCaches) {
+ if (cache->hasBlurTextureInfo(*pixmap))
+ cache->clearBlurTextureInfo(*pixmap);
+ }
}
-static const char *qt_gl_colorize_filter =
- "uniform sampler2D texture;"
- "uniform vec3 color;"
- "void main(void)"
- "{"
- " vec2 coords = gl_TexCoord[0].st;"
- " vec4 src = texture2D(texture, coords);"
- " float gray = dot(src.rgb, vec3(0.212671, 0.715160, 0.072169));"
- " vec3 colorizeed = 1.0-((1.0-gray)*(1.0-color));"
- " gl_FragColor = vec4(colorizeed, src.a);"
- "}";
+static const int qAnimatedBlurLevelIncrement = 16;
+static const int qMaxBlurHalfScaleLevel = 1;
-QGLPixmapColorizeFilter::QGLPixmapColorizeFilter()
- : m_program(QLatin1String(qt_gl_colorize_filter))
+static GLuint generateBlurTexture(const QSize &size, GLenum format = GL_RGBA)
{
- m_program.setUniform(m_program.getUniformLocation(QLatin1String("texture")), 0); // GL_TEXTURE_0
- m_colorUniform = m_program.getUniformLocation(QLatin1String("color"));
+ GLuint texture;
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, format, size.width(), size.height(), 0, format,
+ GL_UNSIGNED_BYTE, 0);
+ return texture;
}
-bool QGLPixmapColorizeFilter::processGL(QPainter *, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const
+static inline uint nextMultiple(uint x, uint multiplier)
{
- bindTexture(src);
+ uint mod = x % multiplier;
+ if (mod == 0)
+ return x;
+ return x + multiplier - mod;
+}
- QColor col = color();
- m_program.setUniform(m_colorUniform, col.redF(), col.greenF(), col.blueF());
+void qt_memrotate90_gl(const quint32 *src, int srcWidth, int srcHeight, int srcStride,
+ quint32 *dest, int dstStride);
- QRectF target = (srcRect.isNull() ? QRectF(src.rect()) : srcRect).translated(pos);
- m_program.enable();
- qgl_drawTexture(target, src.width(), src.height(), srcRect);
- m_program.disable();
+bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &) const
+{
+ if (radius() < 1) {
+ painter->drawPixmap(pos, src);
+ return true;
+ }
- return true;
-}
+ qreal actualRadius = radius();
-// generates convolution filter code for arbitrary sized kernel
-QString QGLPixmapConvolutionFilter::generateConvolutionShader() const {
- QByteArray code;
- code.append("uniform sampler2D texture;\n");
- code.append("uniform vec2 inv_texture_size;\n");
- code.append("uniform float matrix[");
- code.append(QByteArray::number(m_kernelWidth * m_kernelHeight));
- code.append("];\n");
- code.append("vec2 offset[");
- code.append(QByteArray::number(m_kernelWidth*m_kernelHeight));
- code.append("];\n");
- code.append("void main(void) {\n");
-
- for(int y = 0; y < m_kernelHeight; y++) {
- for(int x = 0; x < m_kernelWidth; x++) {
- code.append(" offset[");
- code.append(QByteArray::number(y * m_kernelWidth + x));
- code.append("] = vec2(inv_texture_size.x * ");
- code.append(QByteArray::number(x-(int)(m_kernelWidth/2)));
- code.append(".0, inv_texture_size.y * ");
- code.append(QByteArray::number((int)(m_kernelHeight/2)-y));
- code.append(".0)");
- code.append(";\n");
+ QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
+
+ QGLBlurTextureCache *blurTextureCache = QGLBlurTextureCache::cacheForContext(ctx);
+ QGLBlurTextureInfo *info = 0;
+ int padding = nextMultiple(qCeil(actualRadius), qAnimatedBlurLevelIncrement);
+ QRect targetRect = src.rect().adjusted(-padding, -padding, padding, padding);
+
+ // pad so that we'll be able to half-scale qMaxBlurHalfScaleLevel times
+ targetRect.setWidth((targetRect.width() + (qMaxBlurHalfScaleLevel-1)) & ~(qMaxBlurHalfScaleLevel-1));
+ targetRect.setHeight((targetRect.height() + (qMaxBlurHalfScaleLevel-1)) & ~(qMaxBlurHalfScaleLevel-1));
+
+ QSize textureSize;
+
+ info = blurTextureCache->takeBlurTextureInfo(src);
+ if (!info || info->radius() < actualRadius) {
+ QSize paddedSize = targetRect.size() / 2;
+
+ QImage padded(paddedSize.height(), paddedSize.width(), QImage::Format_ARGB32_Premultiplied);
+ padded.fill(0);
+
+ if (info) {
+ int oldPadding = qRound(info->radius());
+
+ QPainter p(&padded);
+ p.setCompositionMode(QPainter::CompositionMode_Source);
+ p.drawImage((padding - oldPadding) / 2, (padding - oldPadding) / 2, info->paddedImage());
+ p.end();
+ } else {
+ // TODO: combine byteswapping and memrotating into one by declaring
+ // custom GL_RGBA pixel type and qt_colorConvert template for it
+ QImage prepadded = qt_halfScaled(src.toImage()).convertToFormat(QImage::Format_ARGB32_Premultiplied);
+
+ // byte-swap and memrotates in one go
+ qt_memrotate90_gl(reinterpret_cast<const quint32*>(prepadded.bits()),
+ prepadded.width(), prepadded.height(), prepadded.bytesPerLine(),
+ reinterpret_cast<quint32*>(padded.scanLine(padding / 2)) + padding / 2,
+ padded.bytesPerLine());
}
+
+ delete info;
+ info = new QGLBlurTextureInfo(padded, generateBlurTexture(paddedSize), padding);
+
+ textureSize = paddedSize;
+ } else {
+ textureSize = QSize(info->paddedImage().height(), info->paddedImage().width());
}
- code.append(" int i = 0;\n");
- code.append(" vec2 coords = gl_TexCoord[0].st;\n");
- code.append(" vec4 sum = vec4(0.0);\n");
- code.append(" for (i = 0; i < ");
- code.append(QByteArray::number(m_kernelWidth * m_kernelHeight));
- code.append("; i++) {\n");
- code.append(" vec4 tmp = texture2D(texture,coords+offset[i]);\n");
- code.append(" sum += matrix[i] * tmp;\n");
- code.append(" }\n");
- code.append(" gl_FragColor = sum;\n");
- code.append("}");
- return QLatin1String(code);
-}
+ actualRadius *= qreal(0.5);
+ int level = 1;
+ for (; level < qMaxBlurHalfScaleLevel; ++level) {
+ if (actualRadius <= 16)
+ break;
+ actualRadius *= qreal(0.5);
+ }
-QGLPixmapConvolutionFilter::QGLPixmapConvolutionFilter()
- : m_program(0)
- , m_scaleUniform(0)
- , m_matrixUniform(0)
- , m_kernelWidth(0)
- , m_kernelHeight(0)
-{
+ const int s = (1 << level);
+
+ int prepadding = qRound(info->radius());
+ padding = qMin(prepadding, qCeil(actualRadius) << level);
+ targetRect = src.rect().adjusted(-padding, -padding, padding, padding);
+
+ targetRect.setWidth(targetRect.width() & ~(s-1));
+ targetRect.setHeight(targetRect.height() & ~(s-1));
+
+ int paddingDelta = (prepadding - padding) >> level;
+
+ QRect subRect(paddingDelta, paddingDelta, targetRect.width() >> level, targetRect.height() >> level);
+ QImage sourceImage = info->paddedImage(level-1);
+
+ QImage subImage(subRect.height(), subRect.width(), QImage::Format_ARGB32_Premultiplied);
+ qt_rectcopy((QRgb *)subImage.bits(), ((QRgb *)sourceImage.scanLine(paddingDelta)) + paddingDelta,
+ 0, 0, subRect.height(), subRect.width(), subImage.bytesPerLine(), sourceImage.bytesPerLine());
+
+ GLuint texture = info->texture();
+
+ qt_blurImage(subImage, actualRadius, blurHints() & QGraphicsBlurEffect::QualityHint, 1);
+
+ // subtract one pixel off the end to prevent the bilinear sampling from sampling uninitialized data
+ QRect textureSubRect = subImage.rect().adjusted(0, 0, -1, -1);
+ QRectF targetRectF = QRectF(targetRect).adjusted(0, 0, -targetRect.width() / qreal(textureSize.width()), -targetRect.height() / qreal(textureSize.height()));
+
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subImage.width(), subImage.height(), GL_RGBA,
+ GL_UNSIGNED_BYTE, const_cast<const QImage &>(subImage).bits());
+
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine());
+ painter->setRenderHint(QPainter::SmoothPixmapTransform);
+
+ // texture is flipped on the y-axis
+ targetRectF = QRectF(targetRectF.x(), targetRectF.bottom(), targetRectF.width(), -targetRectF.height());
+ engine->drawTexture(targetRectF.translated(pos), texture, textureSize, textureSubRect);
+
+ blurTextureCache->insertBlurTextureInfo(src, info);
+
+ return true;
}
-QGLPixmapConvolutionFilter::~QGLPixmapConvolutionFilter()
+static const char *qt_gl_drop_shadow_filter =
+ "uniform lowp vec4 shadowColor;"
+ "lowp vec4 customShader(lowp sampler2D src, highp vec2 srcCoords)"
+ "{"
+ " return shadowColor * texture2D(src, srcCoords.yx).a;"
+ "}";
+
+
+QGLPixmapDropShadowFilter::QGLPixmapDropShadowFilter()
{
- delete m_program;
+ setSource(qt_gl_drop_shadow_filter);
}
-bool QGLPixmapConvolutionFilter::processGL(QPainter *, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const
+bool QGLPixmapDropShadowFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const
{
- QRectF target = (srcRect.isNull() ? QRectF(src.rect()) : srcRect).translated(pos);
+ QGLPixmapDropShadowFilter *filter = const_cast<QGLPixmapDropShadowFilter *>(this);
+
+ qreal r = blurRadius();
+ QRectF targetRectUnaligned = QRectF(src.rect()).translated(pos + offset()).adjusted(-r, -r, r, r);
+ QRect targetRect = targetRectUnaligned.toAlignedRect();
+
+ // ensure even dimensions (going to divide by two)
+ targetRect.setWidth((targetRect.width() + 1) & ~1);
+ targetRect.setHeight((targetRect.height() + 1) & ~1);
- bindTexture(src);
-#ifdef GL_CLAMP
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
-#endif
- if (!m_program || m_kernelWidth != columns() || m_kernelHeight != rows()) {
- delete m_program;
+ QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
+ QGLBlurTextureCache *blurTextureCache = QGLBlurTextureCache::cacheForContext(ctx);
- m_kernelWidth = columns();
- m_kernelHeight = rows();
+ QGLBlurTextureInfo *info = blurTextureCache->takeBlurTextureInfo(src);
+ if (!info || info->radius() != r) {
+ QImage half = qt_halfScaled(src.toImage().alphaChannel());
- QString code = generateConvolutionShader();
- m_program = new QGLSLProgram(code);
- m_scaleUniform = m_program->getUniformLocation(QLatin1String("inv_texture_size"));
- m_matrixUniform = m_program->getUniformLocation(QLatin1String("matrix"));
+ qreal rx = r + targetRect.left() - targetRectUnaligned.left();
+ qreal ry = r + targetRect.top() - targetRectUnaligned.top();
+
+ QImage image = QImage(targetRect.size() / 2, QImage::Format_Indexed8);
+ image.setColorTable(half.colorTable());
+ image.fill(0);
+ int dx = qRound(rx * qreal(0.5));
+ int dy = qRound(ry * qreal(0.5));
+ qt_rectcopy(image.bits(), half.bits(), dx, dy,
+ half.width(), half.height(),
+ image.bytesPerLine(), half.bytesPerLine());
+
+ qt_blurImage(image, r * qreal(0.5), false, 1);
+
+ GLuint texture = generateBlurTexture(image.size(), GL_ALPHA);
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image.width(), image.height(), GL_ALPHA,
+ GL_UNSIGNED_BYTE, image.bits());
+
+ info = new QGLBlurTextureInfo(image, texture, r);
}
- const qreal *kernel = convolutionKernel();
- GLfloat *conv = new GLfloat[m_kernelWidth * m_kernelHeight];
- for(int i = 0; i < m_kernelWidth * m_kernelHeight; ++i)
- conv[i] = kernel[i];
-
- const qreal iw = 1.0 / src.width();
- const qreal ih = 1.0 / src.height();
- m_program->setUniform(m_scaleUniform, iw, ih);
- m_program->setUniform(m_matrixUniform, m_kernelWidth * m_kernelHeight, conv);
-
- m_program->enable();
- qgl_drawTexture(target, src.width(), src.height(), boundingRectFor(srcRect));
- m_program->disable();
+ GLuint texture = info->texture();
+
+ filter->setOnPainter(painter);
+
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine());
+ painter->setRenderHint(QPainter::SmoothPixmapTransform);
+
+ engine->drawTexture(targetRect, texture, info->paddedImage().size(), info->paddedImage().rect());
+
+ filter->removeFromPainter(painter);
+
+ // Now draw the actual pixmap over the top.
+ painter->drawPixmap(pos, src, srcRect);
+
+ blurTextureCache->insertBlurTextureInfo(src, info);
+
return true;
}
+void QGLPixmapDropShadowFilter::setUniforms(QGLShaderProgram *program)
+{
+ QColor col = color();
+ qreal alpha = col.alphaF();
+ program->setUniformValue("shadowColor", col.redF() * alpha,
+ col.greenF() * alpha,
+ col.blueF() * alpha,
+ alpha);
+}
+
QT_END_NAMESPACE
diff --git a/src/opengl/qglpixmapfilter_p.h b/src/opengl/qglpixmapfilter_p.h
index aca4613..0ef3eb5 100644
--- a/src/opengl/qglpixmapfilter_p.h
+++ b/src/opengl/qglpixmapfilter_p.h
@@ -87,35 +87,6 @@ public:
}
};
-class Q_OPENGL_EXPORT QGLSLProgram
-{
-public:
- QGLSLProgram(const QString &src);
- ~QGLSLProgram();
-
- bool success() const;
-
- void enable();
- void disable();
-
- int getUniformLocation(const QString &name);
-
- void setUniform(int uniform, int value);
- void setUniform(int uniform, qreal value);
- void setUniform(int uniform, qreal v1, qreal v2);
- void setUniform(int uniform, qreal v1, qreal v2, qreal v3);
- void setUniform(int uniform, qreal v1, qreal v2, qreal v3, qreal v4);
- void setUniform(int uniform, int count, float *v);
-
-private:
- GLuint m_shader;
- GLuint m_program;
-
- GLint m_valid;
-
- const QGLContext *ctx;
-};
-
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp
new file mode 100644
index 0000000..f9737a56
--- /dev/null
+++ b/src/opengl/qglshaderprogram.cpp
@@ -0,0 +1,2983 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglshaderprogram.h"
+#include "qglextensions_p.h"
+#include "qgl_p.h"
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qvector.h>
+
+QT_BEGIN_NAMESPACE
+
+#if !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1)
+
+/*!
+ \class QGLShaderProgram
+ \brief The QGLShaderProgram class allows OpenGL shader programs to be linked and used.
+ \since 4.6
+ \ingroup painting-3D
+
+ \section1 Introduction
+
+ This class supports shader programs written in the OpenGL Shading
+ Language (GLSL) and in the OpenGL/ES Shading Language (GLSL/ES).
+
+ QGLShader and QGLShaderProgram shelter the programmer from the details of
+ compiling and linking vertex and fragment shaders.
+
+ The following example creates a vertex shader program using the
+ supplied source \c{code}. Once compiled and linked, the shader
+ program is activated in the current QGLContext by calling
+ QGLShaderProgram::bind():
+
+ \snippet doc/src/snippets/code/src_opengl_qglshaderprogram.cpp 0
+
+ \section1 Writing portable shaders
+
+ Shader programs can be difficult to reuse across OpenGL implementations
+ because of varying levels of support for standard vertex attributes and
+ uniform variables. In particular, GLSL/ES lacks all of the
+ standard variables that are present on desktop OpenGL systems:
+ \c{gl_Vertex}, \c{gl_Normal}, \c{gl_Color}, and so on. Desktop OpenGL
+ lacks the variable qualifiers \c{highp}, \c{mediump}, and \c{lowp}.
+
+ The QGLShaderProgram class makes the process of writing portable shaders
+ easier by prefixing all shader programs with the following lines on
+ desktop OpenGL:
+
+ \code
+ #define highp
+ #define mediump
+ #define lowp
+ \endcode
+
+ This makes it possible to run most GLSL/ES shader programs
+ on desktop systems. The programmer should restrict themselves
+ to just features that are present in GLSL/ES, and avoid
+ standard variable names that only work on the desktop.
+
+ \section1 Simple shader example
+
+ \snippet doc/src/snippets/code/src_opengl_qglshaderprogram.cpp 1
+
+ With the above shader program active, we can draw a green triangle
+ as follows:
+
+ \snippet doc/src/snippets/code/src_opengl_qglshaderprogram.cpp 2
+
+ \sa QGLShader
+*/
+
+/*!
+ \class QGLShader
+ \brief The QGLShader class allows OpenGL shaders to be compiled.
+ \since 4.6
+ \ingroup painting-3D
+
+ This class supports shaders written in the OpenGL Shading Language (GLSL)
+ and in the OpenGL/ES Shading Language (GLSL/ES).
+
+ QGLShader and QGLShaderProgram shelter the programmer from the details of
+ compiling and linking vertex and fragment shaders.
+
+ \sa QGLShaderProgram
+*/
+
+/*!
+ \enum QGLShader::ShaderTypeBit
+ This enum specifies the type of QGLShader that is being created.
+
+ \value Vertex Vertex shader written in the OpenGL Shading Language (GLSL).
+ \value Fragment Fragment shader written in the OpenGL Shading Language (GLSL).
+*/
+
+#ifndef GL_FRAGMENT_SHADER
+#define GL_FRAGMENT_SHADER 0x8B30
+#endif
+#ifndef GL_VERTEX_SHADER
+#define GL_VERTEX_SHADER 0x8B31
+#endif
+#ifndef GL_COMPILE_STATUS
+#define GL_COMPILE_STATUS 0x8B81
+#endif
+#ifndef GL_LINK_STATUS
+#define GL_LINK_STATUS 0x8B82
+#endif
+#ifndef GL_INFO_LOG_LENGTH
+#define GL_INFO_LOG_LENGTH 0x8B84
+#endif
+#ifndef GL_ACTIVE_UNIFORMS
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#endif
+#ifndef GL_ACTIVE_UNIFORM_MAX_LENGTH
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#endif
+#ifndef GL_ACTIVE_ATTRIBUTES
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#endif
+#ifndef GL_ACTIVE_ATTRIBUTE_MAX_LENGTH
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#endif
+#ifndef GL_CURRENT_VERTEX_ATTRIB
+#define GL_CURRENT_VERTEX_ATTRIB 0x8626
+#endif
+#ifndef GL_SHADER_SOURCE_LENGTH
+#define GL_SHADER_SOURCE_LENGTH 0x8B88
+#endif
+#ifndef GL_SHADER_BINARY_FORMATS
+#define GL_SHADER_BINARY_FORMATS 0x8DF8
+#endif
+#ifndef GL_NUM_SHADER_BINARY_FORMATS
+#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
+#endif
+
+class QGLShaderPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QGLShader)
+public:
+ QGLShaderPrivate(const QGLContext *context, QGLShader::ShaderType type)
+ : shaderGuard(context)
+ , shaderType(type)
+ , compiled(false)
+ {
+ }
+ ~QGLShaderPrivate();
+
+ QGLSharedResourceGuard shaderGuard;
+ QGLShader::ShaderType shaderType;
+ bool compiled;
+ QString log;
+
+ bool create();
+ bool compile(QGLShader *q);
+ void deleteShader();
+};
+
+#define ctx shaderGuard.context()
+
+QGLShaderPrivate::~QGLShaderPrivate()
+{
+ if (shaderGuard.id()) {
+ QGLShareContextScope scope(shaderGuard.context());
+ glDeleteShader(shaderGuard.id());
+ }
+}
+
+bool QGLShaderPrivate::create()
+{
+ const QGLContext *context = shaderGuard.context();
+ if (!context)
+ return false;
+ if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(context))) {
+ GLuint shader;
+ if (shaderType == QGLShader::Vertex)
+ shader = glCreateShader(GL_VERTEX_SHADER);
+ else
+ shader = glCreateShader(GL_FRAGMENT_SHADER);
+ if (!shader) {
+ qWarning() << "QGLShader: could not create shader";
+ return false;
+ }
+ shaderGuard.setId(shader);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool QGLShaderPrivate::compile(QGLShader *q)
+{
+ GLuint shader = shaderGuard.id();
+ if (!shader)
+ return false;
+ glCompileShader(shader);
+ GLint value = 0;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &value);
+ compiled = (value != 0);
+ value = 0;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &value);
+ if (!compiled && value > 1) {
+ char *logbuf = new char [value];
+ GLint len;
+ glGetShaderInfoLog(shader, value, &len, logbuf);
+ log = QString::fromLatin1(logbuf);
+ QString name = q->objectName();
+ if (name.isEmpty())
+ qWarning() << "QGLShader::compile:" << log;
+ else
+ qWarning() << "QGLShader::compile[" << name << "]:" << log;
+ delete [] logbuf;
+ }
+ return compiled;
+}
+
+void QGLShaderPrivate::deleteShader()
+{
+ if (shaderGuard.id()) {
+ glDeleteShader(shaderGuard.id());
+ shaderGuard.setId(0);
+ }
+}
+
+#undef ctx
+#define ctx d->shaderGuard.context()
+
+/*!
+ Constructs a new QGLShader object of the specified \a type
+ and attaches it to \a parent. If shader programs are not supported,
+ QGLShaderProgram::hasOpenGLShaderPrograms() will return false.
+
+ This constructor is normally followed by a call to compileSourceCode()
+ or compileSourceFile().
+
+ The shader will be associated with the current QGLContext.
+
+ \sa compileSourceCode(), compileSourceFile()
+*/
+QGLShader::QGLShader(QGLShader::ShaderType type, QObject *parent)
+ : QObject(*new QGLShaderPrivate(QGLContext::currentContext(), type), parent)
+{
+ Q_D(QGLShader);
+ d->create();
+}
+
+/*!
+ Constructs a new QGLShader object of the specified \a type
+ and attaches it to \a parent. If shader programs are not supported,
+ then QGLShaderProgram::hasOpenGLShaderPrograms() will return false.
+
+ This constructor is normally followed by a call to compileSourceCode()
+ or compileSourceFile().
+
+ The shader will be associated with \a context.
+
+ \sa compileSourceCode(), compileSourceFile()
+*/
+QGLShader::QGLShader(QGLShader::ShaderType type, const QGLContext *context, QObject *parent)
+ : QObject(*new QGLShaderPrivate(context ? context : QGLContext::currentContext(), type), parent)
+{
+ Q_D(QGLShader);
+#ifndef QT_NO_DEBUG
+ if (context && !QGLContext::areSharing(context, QGLContext::currentContext())) {
+ qWarning("QGLShader::QGLShader: \'context\' must be the current context or sharing with it.");
+ return;
+ }
+#endif
+ d->create();
+}
+
+/*!
+ Deletes this shader. If the shader has been attached to a
+ QGLShaderProgram object, then the actual shader will stay around
+ until the QGLShaderProgram is destroyed.
+*/
+QGLShader::~QGLShader()
+{
+}
+
+/*!
+ Returns the type of this shader.
+*/
+QGLShader::ShaderType QGLShader::shaderType() const
+{
+ Q_D(const QGLShader);
+ return d->shaderType;
+}
+
+// The precision qualifiers are useful on OpenGL/ES systems,
+// but usually not present on desktop systems. Define the
+// keywords to empty strings on desktop systems.
+#ifndef QT_OPENGL_ES
+#define QGL_DEFINE_QUALIFIERS 1
+static const char qualifierDefines[] =
+ "#define lowp\n"
+ "#define mediump\n"
+ "#define highp\n";
+#endif
+
+// The "highp" qualifier doesn't exist in fragment shaders
+// on all ES platforms. When it doesn't exist, use "mediump".
+#ifdef QT_OPENGL_ES
+#define QGL_REDEFINE_HIGHP 1
+static const char redefineHighp[] =
+ "#ifndef GL_FRAGMENT_PRECISION_HIGH\n"
+ "#define highp mediump\n"
+ "#endif\n";
+#endif
+
+/*!
+ Sets the \a source code for this shader and compiles it.
+ Returns true if the source was successfully compiled, false otherwise.
+
+ \sa compileSourceFile()
+*/
+bool QGLShader::compileSourceCode(const char *source)
+{
+ Q_D(QGLShader);
+ if (d->shaderGuard.id()) {
+ QVarLengthArray<const char *, 4> src;
+ QVarLengthArray<GLint, 4> srclen;
+ int headerLen = 0;
+ while (source && source[headerLen] == '#') {
+ // Skip #version and #extension directives at the start of
+ // the shader code. We need to insert the qualifierDefines
+ // and redefineHighp just after them.
+ if (qstrncmp(source + headerLen, "#version", 8) != 0 &&
+ qstrncmp(source + headerLen, "#extension", 10) != 0) {
+ break;
+ }
+ while (source[headerLen] != '\0' && source[headerLen] != '\n')
+ ++headerLen;
+ if (source[headerLen] == '\n')
+ ++headerLen;
+ }
+ if (headerLen > 0) {
+ src.append(source);
+ srclen.append(GLint(headerLen));
+ }
+#ifdef QGL_DEFINE_QUALIFIERS
+ src.append(qualifierDefines);
+ srclen.append(GLint(sizeof(qualifierDefines) - 1));
+#endif
+#ifdef QGL_REDEFINE_HIGHP
+ if (d->shaderType == Fragment) {
+ src.append(redefineHighp);
+ srclen.append(GLint(sizeof(redefineHighp) - 1));
+ }
+#endif
+ src.append(source + headerLen);
+ srclen.append(GLint(qstrlen(source + headerLen)));
+ glShaderSource(d->shaderGuard.id(), src.size(), src.data(), srclen.data());
+ return d->compile(this);
+ } else {
+ return false;
+ }
+}
+
+/*!
+ \overload
+
+ Sets the \a source code for this shader and compiles it.
+ Returns true if the source was successfully compiled, false otherwise.
+
+ \sa compileSourceFile()
+*/
+bool QGLShader::compileSourceCode(const QByteArray& source)
+{
+ return compileSourceCode(source.constData());
+}
+
+/*!
+ \overload
+
+ Sets the \a source code for this shader and compiles it.
+ Returns true if the source was successfully compiled, false otherwise.
+
+ \sa compileSourceFile()
+*/
+bool QGLShader::compileSourceCode(const QString& source)
+{
+ return compileSourceCode(source.toLatin1().constData());
+}
+
+/*!
+ Sets the source code for this shader to the contents of \a fileName
+ and compiles it. Returns true if the file could be opened and the
+ source compiled, false otherwise.
+
+ \sa compileSourceCode()
+*/
+bool QGLShader::compileSourceFile(const QString& fileName)
+{
+ QFile file(fileName);
+ if (!file.open(QFile::ReadOnly)) {
+ qWarning() << "QGLShader: Unable to open file" << fileName;
+ return false;
+ }
+
+ QByteArray contents = file.readAll();
+ return compileSourceCode(contents.constData());
+}
+
+/*!
+ Returns the source code for this shader.
+
+ \sa compileSourceCode()
+*/
+QByteArray QGLShader::sourceCode() const
+{
+ Q_D(const QGLShader);
+ GLuint shader = d->shaderGuard.id();
+ if (!shader)
+ return QByteArray();
+ GLint size = 0;
+ glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &size);
+ if (size <= 0)
+ return QByteArray();
+ GLint len = 0;
+ char *source = new char [size];
+ glGetShaderSource(shader, size, &len, source);
+ QByteArray src(source);
+ delete [] source;
+ return src;
+}
+
+/*!
+ Returns true if this shader has been compiled; false otherwise.
+
+ \sa compileSourceCode(), compileSourceFile()
+*/
+bool QGLShader::isCompiled() const
+{
+ Q_D(const QGLShader);
+ return d->compiled;
+}
+
+/*!
+ Returns the errors and warnings that occurred during the last compile.
+
+ \sa compileSourceCode(), compileSourceFile()
+*/
+QString QGLShader::log() const
+{
+ Q_D(const QGLShader);
+ return d->log;
+}
+
+/*!
+ Returns the OpenGL identifier associated with this shader.
+
+ \sa QGLShaderProgram::programId()
+*/
+GLuint QGLShader::shaderId() const
+{
+ Q_D(const QGLShader);
+ return d->shaderGuard.id();
+}
+
+#undef ctx
+#define ctx programGuard.context()
+
+class QGLShaderProgramPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QGLShaderProgram)
+public:
+ QGLShaderProgramPrivate(const QGLContext *context)
+ : programGuard(context)
+ , linked(false)
+ , inited(false)
+ , removingShaders(false)
+ , vertexShader(0)
+ , fragmentShader(0)
+ {
+ }
+ ~QGLShaderProgramPrivate();
+
+ QGLSharedResourceGuard programGuard;
+ bool linked;
+ bool inited;
+ bool removingShaders;
+ QString log;
+ QList<QGLShader *> shaders;
+ QList<QGLShader *> anonShaders;
+ QGLShader *vertexShader;
+ QGLShader *fragmentShader;
+
+ bool hasShader(QGLShader::ShaderType type) const;
+};
+
+QGLShaderProgramPrivate::~QGLShaderProgramPrivate()
+{
+ if (programGuard.id()) {
+ QGLShareContextScope scope(programGuard.context());
+ glDeleteProgram(programGuard.id());
+ }
+}
+
+bool QGLShaderProgramPrivate::hasShader(QGLShader::ShaderType type) const
+{
+ foreach (QGLShader *shader, shaders) {
+ if (shader->shaderType() == type)
+ return true;
+ }
+ return false;
+}
+
+#undef ctx
+#define ctx d->programGuard.context()
+
+/*!
+ Constructs a new shader program and attaches it to \a parent.
+ The program will be invalid until addShader() is called.
+
+ The shader program will be associated with the current QGLContext.
+
+ \sa addShader()
+*/
+QGLShaderProgram::QGLShaderProgram(QObject *parent)
+ : QObject(*new QGLShaderProgramPrivate(QGLContext::currentContext()), parent)
+{
+}
+
+/*!
+ Constructs a new shader program and attaches it to \a parent.
+ The program will be invalid until addShader() is called.
+
+ The shader program will be associated with \a context.
+
+ \sa addShader()
+*/
+QGLShaderProgram::QGLShaderProgram(const QGLContext *context, QObject *parent)
+ : QObject(*new QGLShaderProgramPrivate(context), parent)
+{
+}
+
+/*!
+ Deletes this shader program.
+*/
+QGLShaderProgram::~QGLShaderProgram()
+{
+}
+
+bool QGLShaderProgram::init()
+{
+ Q_D(QGLShaderProgram);
+ if (d->programGuard.id() || d->inited)
+ return true;
+ d->inited = true;
+ const QGLContext *context = d->programGuard.context();
+ if (!context) {
+ context = QGLContext::currentContext();
+ d->programGuard.setContext(context);
+ }
+ if (!context)
+ return false;
+ if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(context))) {
+ GLuint program = glCreateProgram();
+ if (!program) {
+ qWarning() << "QGLShaderProgram: could not create shader program";
+ return false;
+ }
+ d->programGuard.setId(program);
+ return true;
+ } else {
+ qWarning() << "QGLShaderProgram: shader programs are not supported";
+ return false;
+ }
+}
+
+/*!
+ Adds a compiled \a shader to this shader program. Returns true
+ if the shader could be added, or false otherwise.
+
+ Ownership of the \a shader object remains with the caller.
+ It will not be deleted when this QGLShaderProgram instance
+ is deleted. This allows the caller to add the same shader
+ to multiple shader programs.
+
+ \sa addShaderFromSourceCode(), addShaderFromSourceFile()
+ \sa removeShader(), link(), removeAllShaders()
+*/
+bool QGLShaderProgram::addShader(QGLShader *shader)
+{
+ Q_D(QGLShaderProgram);
+ if (!init())
+ return false;
+ if (d->shaders.contains(shader))
+ return true; // Already added to this shader program.
+ if (d->programGuard.id() && shader) {
+ if (!QGLContext::areSharing(shader->d_func()->shaderGuard.context(),
+ d->programGuard.context())) {
+ qWarning("QGLShaderProgram::addShader: Program and shader are not associated with same context.");
+ return false;
+ }
+ if (!shader->d_func()->compiled)
+ return false;
+ if (!shader->d_func()->shaderGuard.id())
+ return false;
+ glAttachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id());
+ d->linked = false; // Program needs to be relinked.
+ d->shaders.append(shader);
+ connect(shader, SIGNAL(destroyed()), this, SLOT(shaderDestroyed()));
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/*!
+ Compiles \a source as a shader of the specified \a type and
+ adds it to this shader program. Returns true if compilation
+ was successful, false otherwise. The compilation errors
+ and warnings will be made available via log().
+
+ This function is intended to be a short-cut for quickly
+ adding vertex and fragment shaders to a shader program without
+ creating an instance of QGLShader first.
+
+ \sa addShader(), addShaderFromSourceFile()
+ \sa removeShader(), link(), log(), removeAllShaders()
+*/
+bool QGLShaderProgram::addShaderFromSourceCode(QGLShader::ShaderType type, const char *source)
+{
+ Q_D(QGLShaderProgram);
+ if (!init())
+ return false;
+ QGLShader *shader = new QGLShader(type, this);
+ if (!shader->compileSourceCode(source)) {
+ d->log = shader->log();
+ delete shader;
+ return false;
+ }
+ d->anonShaders.append(shader);
+ return addShader(shader);
+}
+
+/*!
+ \overload
+
+ Compiles \a source as a shader of the specified \a type and
+ adds it to this shader program. Returns true if compilation
+ was successful, false otherwise. The compilation errors
+ and warnings will be made available via log().
+
+ This function is intended to be a short-cut for quickly
+ adding vertex and fragment shaders to a shader program without
+ creating an instance of QGLShader first.
+
+ \sa addShader(), addShaderFromSourceFile()
+ \sa removeShader(), link(), log(), removeAllShaders()
+*/
+bool QGLShaderProgram::addShaderFromSourceCode(QGLShader::ShaderType type, const QByteArray& source)
+{
+ return addShaderFromSourceCode(type, source.constData());
+}
+
+/*!
+ \overload
+
+ Compiles \a source as a shader of the specified \a type and
+ adds it to this shader program. Returns true if compilation
+ was successful, false otherwise. The compilation errors
+ and warnings will be made available via log().
+
+ This function is intended to be a short-cut for quickly
+ adding vertex and fragment shaders to a shader program without
+ creating an instance of QGLShader first.
+
+ \sa addShader(), addShaderFromSourceFile()
+ \sa removeShader(), link(), log(), removeAllShaders()
+*/
+bool QGLShaderProgram::addShaderFromSourceCode(QGLShader::ShaderType type, const QString& source)
+{
+ return addShaderFromSourceCode(type, source.toLatin1().constData());
+}
+
+/*!
+ Compiles the contents of \a fileName as a shader of the specified
+ \a type and adds it to this shader program. Returns true if
+ compilation was successful, false otherwise. The compilation errors
+ and warnings will be made available via log().
+
+ This function is intended to be a short-cut for quickly
+ adding vertex and fragment shaders to a shader program without
+ creating an instance of QGLShader first.
+
+ \sa addShader(), addShaderFromSourceCode()
+*/
+bool QGLShaderProgram::addShaderFromSourceFile
+ (QGLShader::ShaderType type, const QString& fileName)
+{
+ Q_D(QGLShaderProgram);
+ if (!init())
+ return false;
+ QGLShader *shader = new QGLShader(type, this);
+ if (!shader->compileSourceFile(fileName)) {
+ d->log = shader->log();
+ delete shader;
+ return false;
+ }
+ d->anonShaders.append(shader);
+ return addShader(shader);
+}
+
+/*!
+ Removes \a shader from this shader program. The object is not deleted.
+
+ \sa addShader(), link(), removeAllShaders()
+*/
+void QGLShaderProgram::removeShader(QGLShader *shader)
+{
+ Q_D(QGLShaderProgram);
+ if (d->programGuard.id() && shader && shader->d_func()->shaderGuard.id()) {
+ QGLShareContextScope scope(d->programGuard.context());
+ glDetachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id());
+ }
+ d->linked = false; // Program needs to be relinked.
+ if (shader) {
+ d->shaders.removeAll(shader);
+ d->anonShaders.removeAll(shader);
+ disconnect(shader, SIGNAL(destroyed()), this, SLOT(shaderDestroyed()));
+ }
+}
+
+/*!
+ Returns a list of all shaders that have been added to this shader
+ program using addShader().
+
+ \sa addShader(), removeShader()
+*/
+QList<QGLShader *> QGLShaderProgram::shaders() const
+{
+ Q_D(const QGLShaderProgram);
+ return d->shaders;
+}
+
+/*!
+ Removes all of the shaders that were added to this program previously.
+ The QGLShader objects for the shaders will not be deleted if they
+ were constructed externally. QGLShader objects that are constructed
+ internally by QGLShaderProgram will be deleted.
+
+ \sa addShader(), removeShader()
+*/
+void QGLShaderProgram::removeAllShaders()
+{
+ Q_D(QGLShaderProgram);
+ d->removingShaders = true;
+ foreach (QGLShader *shader, d->shaders) {
+ if (d->programGuard.id() && shader && shader->d_func()->shaderGuard.id())
+ glDetachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id());
+ }
+ foreach (QGLShader *shader, d->anonShaders) {
+ // Delete shader objects that were created anonymously.
+ delete shader;
+ }
+ d->shaders.clear();
+ d->anonShaders.clear();
+ d->linked = false; // Program needs to be relinked.
+ d->removingShaders = false;
+}
+
+/*!
+ Links together the shaders that were added to this program with
+ addShader(). Returns true if the link was successful or
+ false otherwise. If the link failed, the error messages can
+ be retrieved with log().
+
+ Subclasses can override this function to initialize attributes
+ and uniform variables for use in specific shader programs.
+
+ If the shader program was already linked, calling this
+ function again will force it to be re-linked.
+
+ \sa addShader(), log()
+*/
+bool QGLShaderProgram::link()
+{
+ Q_D(QGLShaderProgram);
+ GLuint program = d->programGuard.id();
+ if (!program)
+ return false;
+ glLinkProgram(program);
+ GLint value = 0;
+ glGetProgramiv(program, GL_LINK_STATUS, &value);
+ d->linked = (value != 0);
+ value = 0;
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &value);
+ d->log = QString();
+ if (value > 1) {
+ char *logbuf = new char [value];
+ GLint len;
+ glGetProgramInfoLog(program, value, &len, logbuf);
+ d->log = QString::fromLatin1(logbuf);
+ QString name = objectName();
+ if (name.isEmpty())
+ qWarning() << "QGLShader::link:" << d->log;
+ else
+ qWarning() << "QGLShader::link[" << name << "]:" << d->log;
+ delete [] logbuf;
+ }
+ return d->linked;
+}
+
+/*!
+ Returns true if this shader program has been linked; false otherwise.
+
+ \sa link()
+*/
+bool QGLShaderProgram::isLinked() const
+{
+ Q_D(const QGLShaderProgram);
+ return d->linked;
+}
+
+/*!
+ Returns the errors and warnings that occurred during the last link()
+ or addShader() with explicitly specified source code.
+
+ \sa link()
+*/
+QString QGLShaderProgram::log() const
+{
+ Q_D(const QGLShaderProgram);
+ return d->log;
+}
+
+/*!
+ Binds this shader program to the active QGLContext and makes
+ it the current shader program. Any previously bound shader program
+ is released. This is equivalent to calling \c{glUseProgram()} on
+ programId(). Returns true if the program was successfully bound;
+ false otherwise. If the shader program has not yet been linked,
+ or it needs to be re-linked, this function will call link().
+
+ \sa link(), release()
+*/
+bool QGLShaderProgram::bind()
+{
+ Q_D(QGLShaderProgram);
+ GLuint program = d->programGuard.id();
+ if (!program)
+ return false;
+ if (!d->linked && !link())
+ return false;
+#ifndef QT_NO_DEBUG
+ if (!QGLContext::areSharing(d->programGuard.context(), QGLContext::currentContext())) {
+ qWarning("QGLShaderProgram::bind: program is not valid in the current context.");
+ return false;
+ }
+#endif
+ glUseProgram(program);
+ return true;
+}
+
+#undef ctx
+#define ctx QGLContext::currentContext()
+
+/*!
+ Releases the active shader program from the current QGLContext.
+ This is equivalent to calling \c{glUseProgram(0)}.
+
+ \sa bind()
+*/
+void QGLShaderProgram::release()
+{
+#ifndef QT_NO_DEBUG
+ Q_D(QGLShaderProgram);
+ if (!QGLContext::areSharing(d->programGuard.context(), QGLContext::currentContext()))
+ qWarning("QGLShaderProgram::release: program is not valid in the current context.");
+#endif
+#if defined(QT_OPENGL_ES_2)
+ glUseProgram(0);
+#else
+ if (glUseProgram)
+ glUseProgram(0);
+#endif
+}
+
+#undef ctx
+#define ctx d->programGuard.context()
+
+/*!
+ Returns the OpenGL identifier associated with this shader program.
+
+ \sa QGLShader::shaderId()
+*/
+GLuint QGLShaderProgram::programId() const
+{
+ Q_D(const QGLShaderProgram);
+ return d->programGuard.id();
+}
+
+/*!
+ Binds the attribute \a name to the specified \a location. This
+ function can be called before or after the program has been linked.
+ Any attributes that have not been explicitly bound when the program
+ is linked will be assigned locations automatically.
+
+ \sa attributeLocation()
+*/
+void QGLShaderProgram::bindAttributeLocation(const char *name, int location)
+{
+ Q_D(QGLShaderProgram);
+ if (!d->linked) {
+ glBindAttribLocation(d->programGuard.id(), location, name);
+ } else {
+ qWarning() << "QGLShaderProgram::bindAttributeLocation(" << name
+ << "): cannot bind after shader program is linked";
+ }
+}
+
+/*!
+ \overload
+
+ Binds the attribute \a name to the specified \a location. This
+ function can be called before or after the program has been linked.
+ Any attributes that have not been explicitly bound when the program
+ is linked will be assigned locations automatically.
+
+ \sa attributeLocation()
+*/
+void QGLShaderProgram::bindAttributeLocation(const QByteArray& name, int location)
+{
+ bindAttributeLocation(name.constData(), location);
+}
+
+/*!
+ \overload
+
+ Binds the attribute \a name to the specified \a location. This
+ function can be called before or after the program has been linked.
+ Any attributes that have not been explicitly bound when the program
+ is linked will be assigned locations automatically.
+
+ \sa attributeLocation()
+*/
+void QGLShaderProgram::bindAttributeLocation(const QString& name, int location)
+{
+ bindAttributeLocation(name.toLatin1().constData(), location);
+}
+
+/*!
+ Returns the location of the attribute \a name within this shader
+ program's parameter list. Returns -1 if \a name is not a valid
+ attribute for this shader program.
+
+ \sa uniformLocation(), bindAttributeLocation()
+*/
+int QGLShaderProgram::attributeLocation(const char *name) const
+{
+ Q_D(const QGLShaderProgram);
+ if (d->linked) {
+ return glGetAttribLocation(d->programGuard.id(), name);
+ } else {
+ qWarning() << "QGLShaderProgram::attributeLocation(" << name
+ << "): shader program is not linked";
+ return -1;
+ }
+}
+
+/*!
+ \overload
+
+ Returns the location of the attribute \a name within this shader
+ program's parameter list. Returns -1 if \a name is not a valid
+ attribute for this shader program.
+
+ \sa uniformLocation(), bindAttributeLocation()
+*/
+int QGLShaderProgram::attributeLocation(const QByteArray& name) const
+{
+ return attributeLocation(name.constData());
+}
+
+/*!
+ \overload
+
+ Returns the location of the attribute \a name within this shader
+ program's parameter list. Returns -1 if \a name is not a valid
+ attribute for this shader program.
+
+ \sa uniformLocation(), bindAttributeLocation()
+*/
+int QGLShaderProgram::attributeLocation(const QString& name) const
+{
+ return attributeLocation(name.toLatin1().constData());
+}
+
+/*!
+ Sets the attribute at \a location in the current context to \a value.
+
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::setAttributeValue(int location, GLfloat value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glVertexAttrib1fv(location, &value);
+}
+
+/*!
+ \overload
+
+ Sets the attribute called \a name in the current context to \a value.
+
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::setAttributeValue(const char *name, GLfloat value)
+{
+ setAttributeValue(attributeLocation(name), value);
+}
+
+/*!
+ Sets the attribute at \a location in the current context to
+ the 2D vector (\a x, \a y).
+
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::setAttributeValue(int location, GLfloat x, GLfloat y)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1) {
+ GLfloat values[2] = {x, y};
+ glVertexAttrib2fv(location, values);
+ }
+}
+
+/*!
+ \overload
+
+ Sets the attribute called \a name in the current context to
+ the 2D vector (\a x, \a y).
+
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::setAttributeValue(const char *name, GLfloat x, GLfloat y)
+{
+ setAttributeValue(attributeLocation(name), x, y);
+}
+
+/*!
+ Sets the attribute at \a location in the current context to
+ the 3D vector (\a x, \a y, \a z).
+
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::setAttributeValue
+ (int location, GLfloat x, GLfloat y, GLfloat z)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1) {
+ GLfloat values[3] = {x, y, z};
+ glVertexAttrib3fv(location, values);
+ }
+}
+
+/*!
+ \overload
+
+ Sets the attribute called \a name in the current context to
+ the 3D vector (\a x, \a y, \a z).
+
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::setAttributeValue
+ (const char *name, GLfloat x, GLfloat y, GLfloat z)
+{
+ setAttributeValue(attributeLocation(name), x, y, z);
+}
+
+/*!
+ Sets the attribute at \a location in the current context to
+ the 4D vector (\a x, \a y, \a z, \a w).
+
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::setAttributeValue
+ (int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1) {
+ GLfloat values[4] = {x, y, z, w};
+ glVertexAttrib4fv(location, values);
+ }
+}
+
+/*!
+ \overload
+
+ Sets the attribute called \a name in the current context to
+ the 4D vector (\a x, \a y, \a z, \a w).
+
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::setAttributeValue
+ (const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ setAttributeValue(attributeLocation(name), x, y, z, w);
+}
+
+/*!
+ Sets the attribute at \a location in the current context to \a value.
+
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::setAttributeValue(int location, const QVector2D& value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glVertexAttrib2fv(location, reinterpret_cast<const GLfloat *>(&value));
+}
+
+/*!
+ \overload
+
+ Sets the attribute called \a name in the current context to \a value.
+
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::setAttributeValue(const char *name, const QVector2D& value)
+{
+ setAttributeValue(attributeLocation(name), value);
+}
+
+/*!
+ Sets the attribute at \a location in the current context to \a value.
+
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::setAttributeValue(int location, const QVector3D& value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glVertexAttrib3fv(location, reinterpret_cast<const GLfloat *>(&value));
+}
+
+/*!
+ \overload
+
+ Sets the attribute called \a name in the current context to \a value.
+
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::setAttributeValue(const char *name, const QVector3D& value)
+{
+ setAttributeValue(attributeLocation(name), value);
+}
+
+/*!
+ Sets the attribute at \a location in the current context to \a value.
+
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::setAttributeValue(int location, const QVector4D& value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glVertexAttrib4fv(location, reinterpret_cast<const GLfloat *>(&value));
+}
+
+/*!
+ \overload
+
+ Sets the attribute called \a name in the current context to \a value.
+
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::setAttributeValue(const char *name, const QVector4D& value)
+{
+ setAttributeValue(attributeLocation(name), value);
+}
+
+/*!
+ Sets the attribute at \a location in the current context to \a value.
+
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::setAttributeValue(int location, const QColor& value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1) {
+ GLfloat values[4] = {value.redF(), value.greenF(), value.blueF(), value.alphaF()};
+ glVertexAttrib4fv(location, values);
+ }
+}
+
+/*!
+ \overload
+
+ Sets the attribute called \a name in the current context to \a value.
+
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::setAttributeValue(const char *name, const QColor& value)
+{
+ setAttributeValue(attributeLocation(name), value);
+}
+
+/*!
+ Sets the attribute at \a location in the current context to the
+ contents of \a values, which contains \a columns elements, each
+ consisting of \a rows elements. The \a rows value should be
+ 1, 2, 3, or 4. This function is typically used to set matrix
+ values and column vectors.
+
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::setAttributeValue
+ (int location, const GLfloat *values, int columns, int rows)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (rows < 1 || rows > 4) {
+ qWarning() << "QGLShaderProgram::setAttributeValue: rows" << rows << "not supported";
+ return;
+ }
+ if (location != -1) {
+ while (columns-- > 0) {
+ if (rows == 1)
+ glVertexAttrib1fv(location, values);
+ else if (rows == 2)
+ glVertexAttrib2fv(location, values);
+ else if (rows == 3)
+ glVertexAttrib3fv(location, values);
+ else
+ glVertexAttrib4fv(location, values);
+ values += rows;
+ ++location;
+ }
+ }
+}
+
+/*!
+ \overload
+
+ Sets the attribute called \a name in the current context to the
+ contents of \a values, which contains \a columns elements, each
+ consisting of \a rows elements. The \a rows value should be
+ 1, 2, 3, or 4. This function is typically used to set matrix
+ values and column vectors.
+
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::setAttributeValue
+ (const char *name, const GLfloat *values, int columns, int rows)
+{
+ setAttributeValue(attributeLocation(name), values, columns, rows);
+}
+
+/*!
+ Sets an array of vertex \a values on the attribute at \a location
+ in this shader program. The \a tupleSize indicates the number of
+ components per vertex (1, 2, 3, or 4), and the \a stride indicates
+ the number of bytes between vertices. A default \a stride value
+ of zero indicates that the vertices are densely packed in \a values.
+
+ The array will become active when enableAttributeArray() is called
+ on the \a location. Otherwise the value specified with
+ setAttributeValue() for \a location will be used.
+
+ \sa setAttributeValue(), setUniformValue(), enableAttributeArray()
+ \sa disableAttributeArray()
+*/
+void QGLShaderProgram::setAttributeArray
+ (int location, const GLfloat *values, int tupleSize, int stride)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1) {
+ glVertexAttribPointer(location, tupleSize, GL_FLOAT, GL_FALSE,
+ stride, values);
+ }
+}
+
+/*!
+ Sets an array of 2D vertex \a values on the attribute at \a location
+ in this shader program. The \a stride indicates the number of bytes
+ between vertices. A default \a stride value of zero indicates that
+ the vertices are densely packed in \a values.
+
+ The array will become active when enableAttributeArray() is called
+ on the \a location. Otherwise the value specified with
+ setAttributeValue() for \a location will be used.
+
+ \sa setAttributeValue(), setUniformValue(), enableAttributeArray()
+ \sa disableAttributeArray()
+*/
+void QGLShaderProgram::setAttributeArray
+ (int location, const QVector2D *values, int stride)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1) {
+ glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE,
+ stride, values);
+ }
+}
+
+/*!
+ Sets an array of 3D vertex \a values on the attribute at \a location
+ in this shader program. The \a stride indicates the number of bytes
+ between vertices. A default \a stride value of zero indicates that
+ the vertices are densely packed in \a values.
+
+ The array will become active when enableAttributeArray() is called
+ on the \a location. Otherwise the value specified with
+ setAttributeValue() for \a location will be used.
+
+ \sa setAttributeValue(), setUniformValue(), enableAttributeArray()
+ \sa disableAttributeArray()
+*/
+void QGLShaderProgram::setAttributeArray
+ (int location, const QVector3D *values, int stride)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1) {
+ glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE,
+ stride, values);
+ }
+}
+
+/*!
+ Sets an array of 4D vertex \a values on the attribute at \a location
+ in this shader program. The \a stride indicates the number of bytes
+ between vertices. A default \a stride value of zero indicates that
+ the vertices are densely packed in \a values.
+
+ The array will become active when enableAttributeArray() is called
+ on the \a location. Otherwise the value specified with
+ setAttributeValue() for \a location will be used.
+
+ \sa setAttributeValue(), setUniformValue(), enableAttributeArray()
+ \sa disableAttributeArray()
+*/
+void QGLShaderProgram::setAttributeArray
+ (int location, const QVector4D *values, int stride)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1) {
+ glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE,
+ stride, values);
+ }
+}
+
+/*!
+ \overload
+
+ Sets an array of vertex \a values on the attribute called \a name
+ in this shader program. The \a tupleSize indicates the number of
+ components per vertex (1, 2, 3, or 4), and the \a stride indicates
+ the number of bytes between vertices. A default \a stride value
+ of zero indicates that the vertices are densely packed in \a values.
+
+ The array will become active when enableAttributeArray() is called
+ on \a name. Otherwise the value specified with setAttributeValue()
+ for \a name will be used.
+
+ \sa setAttributeValue(), setUniformValue(), enableAttributeArray()
+ \sa disableAttributeArray()
+*/
+void QGLShaderProgram::setAttributeArray
+ (const char *name, const GLfloat *values, int tupleSize, int stride)
+{
+ setAttributeArray(attributeLocation(name), values, tupleSize, stride);
+}
+
+/*!
+ \overload
+
+ Sets an array of 2D vertex \a values on the attribute called \a name
+ in this shader program. The \a stride indicates the number of bytes
+ between vertices. A default \a stride value of zero indicates that
+ the vertices are densely packed in \a values.
+
+ The array will become active when enableAttributeArray() is called
+ on \a name. Otherwise the value specified with setAttributeValue()
+ for \a name will be used.
+
+ \sa setAttributeValue(), setUniformValue(), enableAttributeArray()
+ \sa disableAttributeArray()
+*/
+void QGLShaderProgram::setAttributeArray
+ (const char *name, const QVector2D *values, int stride)
+{
+ setAttributeArray(attributeLocation(name), values, stride);
+}
+
+/*!
+ \overload
+
+ Sets an array of 3D vertex \a values on the attribute called \a name
+ in this shader program. The \a stride indicates the number of bytes
+ between vertices. A default \a stride value of zero indicates that
+ the vertices are densely packed in \a values.
+
+ The array will become active when enableAttributeArray() is called
+ on \a name. Otherwise the value specified with setAttributeValue()
+ for \a name will be used.
+
+ \sa setAttributeValue(), setUniformValue(), enableAttributeArray()
+ \sa disableAttributeArray()
+*/
+void QGLShaderProgram::setAttributeArray
+ (const char *name, const QVector3D *values, int stride)
+{
+ setAttributeArray(attributeLocation(name), values, stride);
+}
+
+/*!
+ \overload
+
+ Sets an array of 4D vertex \a values on the attribute called \a name
+ in this shader program. The \a stride indicates the number of bytes
+ between vertices. A default \a stride value of zero indicates that
+ the vertices are densely packed in \a values.
+
+ The array will become active when enableAttributeArray() is called
+ on \a name. Otherwise the value specified with setAttributeValue()
+ for \a name will be used.
+
+ \sa setAttributeValue(), setUniformValue(), enableAttributeArray()
+ \sa disableAttributeArray()
+*/
+void QGLShaderProgram::setAttributeArray
+ (const char *name, const QVector4D *values, int stride)
+{
+ setAttributeArray(attributeLocation(name), values, stride);
+}
+
+/*!
+ Enables the vertex array at \a location in this shader program
+ so that the value set by setAttributeArray() on \a location
+ will be used by the shader program.
+
+ \sa disableAttributeArray(), setAttributeArray(), setAttributeValue()
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::enableAttributeArray(int location)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glEnableVertexAttribArray(location);
+}
+
+/*!
+ \overload
+
+ Enables the vertex array called \a name in this shader program
+ so that the value set by setAttributeArray() on \a name
+ will be used by the shader program.
+
+ \sa disableAttributeArray(), setAttributeArray(), setAttributeValue()
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::enableAttributeArray(const char *name)
+{
+ enableAttributeArray(attributeLocation(name));
+}
+
+/*!
+ Disables the vertex array at \a location in this shader program
+ that was enabled by a previous call to enableAttributeArray().
+
+ \sa enableAttributeArray(), setAttributeArray(), setAttributeValue()
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::disableAttributeArray(int location)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glDisableVertexAttribArray(location);
+}
+
+/*!
+ \overload
+
+ Disables the vertex array called \a name in this shader program
+ that was enabled by a previous call to enableAttributeArray().
+
+ \sa enableAttributeArray(), setAttributeArray(), setAttributeValue()
+ \sa setUniformValue()
+*/
+void QGLShaderProgram::disableAttributeArray(const char *name)
+{
+ disableAttributeArray(attributeLocation(name));
+}
+
+/*!
+ Returns the location of the uniform variable \a name within this shader
+ program's parameter list. Returns -1 if \a name is not a valid
+ uniform variable for this shader program.
+
+ \sa attributeLocation()
+*/
+int QGLShaderProgram::uniformLocation(const char *name) const
+{
+ Q_D(const QGLShaderProgram);
+ Q_UNUSED(d);
+ if (d->linked) {
+ return glGetUniformLocation(d->programGuard.id(), name);
+ } else {
+ qWarning() << "QGLShaderProgram::uniformLocation(" << name
+ << "): shader program is not linked";
+ return -1;
+ }
+}
+
+/*!
+ \overload
+
+ Returns the location of the uniform variable \a name within this shader
+ program's parameter list. Returns -1 if \a name is not a valid
+ uniform variable for this shader program.
+
+ \sa attributeLocation()
+*/
+int QGLShaderProgram::uniformLocation(const QByteArray& name) const
+{
+ return uniformLocation(name.constData());
+}
+
+/*!
+ \overload
+
+ Returns the location of the uniform variable \a name within this shader
+ program's parameter list. Returns -1 if \a name is not a valid
+ uniform variable for this shader program.
+
+ \sa attributeLocation()
+*/
+int QGLShaderProgram::uniformLocation(const QString& name) const
+{
+ return uniformLocation(name.toLatin1().constData());
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context to \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, GLfloat value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glUniform1fv(location, 1, &value);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context
+ to \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, GLfloat value)
+{
+ setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context to \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, GLint value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glUniform1i(location, value);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context
+ to \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, GLint value)
+{
+ setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context to \a value.
+ This function should be used when setting sampler values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, GLuint value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glUniform1i(location, value);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context
+ to \a value. This function should be used when setting sampler values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, GLuint value)
+{
+ setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context to
+ the 2D vector (\a x, \a y).
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, GLfloat x, GLfloat y)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1) {
+ GLfloat values[2] = {x, y};
+ glUniform2fv(location, 1, values);
+ }
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context to
+ the 2D vector (\a x, \a y).
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, GLfloat x, GLfloat y)
+{
+ setUniformValue(uniformLocation(name), x, y);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context to
+ the 3D vector (\a x, \a y, \a z).
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue
+ (int location, GLfloat x, GLfloat y, GLfloat z)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1) {
+ GLfloat values[3] = {x, y, z};
+ glUniform3fv(location, 1, values);
+ }
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context to
+ the 3D vector (\a x, \a y, \a z).
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue
+ (const char *name, GLfloat x, GLfloat y, GLfloat z)
+{
+ setUniformValue(uniformLocation(name), x, y, z);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context to
+ the 4D vector (\a x, \a y, \a z, \a w).
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue
+ (int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1) {
+ GLfloat values[4] = {x, y, z, w};
+ glUniform4fv(location, 1, values);
+ }
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context to
+ the 4D vector (\a x, \a y, \a z, \a w).
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue
+ (const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ setUniformValue(uniformLocation(name), x, y, z, w);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context to \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, const QVector2D& value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glUniform2fv(location, 1, reinterpret_cast<const GLfloat *>(&value));
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context
+ to \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const QVector2D& value)
+{
+ setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context to \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, const QVector3D& value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glUniform3fv(location, 1, reinterpret_cast<const GLfloat *>(&value));
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context
+ to \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const QVector3D& value)
+{
+ setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context to \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, const QVector4D& value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glUniform4fv(location, 1, reinterpret_cast<const GLfloat *>(&value));
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context
+ to \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const QVector4D& value)
+{
+ setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context to
+ the red, green, blue, and alpha components of \a color.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, const QColor& color)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1) {
+ GLfloat values[4] = {color.redF(), color.greenF(), color.blueF(), color.alphaF()};
+ glUniform4fv(location, 1, values);
+ }
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context to
+ the red, green, blue, and alpha components of \a color.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const QColor& color)
+{
+ setUniformValue(uniformLocation(name), color);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context to
+ the x and y coordinates of \a point.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, const QPoint& point)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1) {
+ GLfloat values[4] = {point.x(), point.y()};
+ glUniform2fv(location, 1, values);
+ }
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable associated with \a name in the current
+ context to the x and y coordinates of \a point.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const QPoint& point)
+{
+ setUniformValue(uniformLocation(name), point);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context to
+ the x and y coordinates of \a point.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, const QPointF& point)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1) {
+ GLfloat values[4] = {point.x(), point.y()};
+ glUniform2fv(location, 1, values);
+ }
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable associated with \a name in the current
+ context to the x and y coordinates of \a point.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const QPointF& point)
+{
+ setUniformValue(uniformLocation(name), point);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context to
+ the width and height of the given \a size.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, const QSize& size)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1) {
+ GLfloat values[4] = {size.width(), size.width()};
+ glUniform2fv(location, 1, values);
+ }
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable associated with \a name in the current
+ context to the width and height of the given \a size.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const QSize& size)
+{
+ setUniformValue(uniformLocation(name), size);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context to
+ the width and height of the given \a size.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, const QSizeF& size)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1) {
+ GLfloat values[4] = {size.width(), size.height()};
+ glUniform2fv(location, 1, values);
+ }
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable associated with \a name in the current
+ context to the width and height of the given \a size.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const QSizeF& size)
+{
+ setUniformValue(uniformLocation(name), size);
+}
+
+// We have to repack matrices from qreal to GLfloat.
+#define setUniformMatrix(func,location,value,cols,rows) \
+ if (location == -1) \
+ return; \
+ if (sizeof(qreal) == sizeof(GLfloat)) { \
+ func(location, 1, GL_FALSE, \
+ reinterpret_cast<const GLfloat *>(value.constData())); \
+ } else { \
+ GLfloat mat[cols * rows]; \
+ const qreal *data = value.constData(); \
+ for (int i = 0; i < cols * rows; ++i) \
+ mat[i] = data[i]; \
+ func(location, 1, GL_FALSE, mat); \
+ }
+#if !defined(QT_OPENGL_ES_2)
+#define setUniformGenericMatrix(func,colfunc,location,value,cols,rows) \
+ if (location == -1) \
+ return; \
+ if (sizeof(qreal) == sizeof(GLfloat)) { \
+ const GLfloat *data = reinterpret_cast<const GLfloat *> \
+ (value.constData()); \
+ if (func) \
+ func(location, 1, GL_FALSE, data); \
+ else \
+ colfunc(location, cols, data); \
+ } else { \
+ GLfloat mat[cols * rows]; \
+ const qreal *data = value.constData(); \
+ for (int i = 0; i < cols * rows; ++i) \
+ mat[i] = data[i]; \
+ if (func) \
+ func(location, 1, GL_FALSE, mat); \
+ else \
+ colfunc(location, cols, mat); \
+ }
+#else
+#define setUniformGenericMatrix(func,colfunc,location,value,cols,rows) \
+ if (location == -1) \
+ return; \
+ if (sizeof(qreal) == sizeof(GLfloat)) { \
+ const GLfloat *data = reinterpret_cast<const GLfloat *> \
+ (value.constData()); \
+ colfunc(location, cols, data); \
+ } else { \
+ GLfloat mat[cols * rows]; \
+ const qreal *data = value.constData(); \
+ for (int i = 0; i < cols * rows; ++i) \
+ mat[i] = data[i]; \
+ colfunc(location, cols, mat); \
+ }
+#endif
+
+/*!
+ Sets the uniform variable at \a location in the current context
+ to a 2x2 matrix \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, const QMatrix2x2& value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformMatrix(glUniformMatrix2fv, location, value, 2, 2);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context
+ to a 2x2 matrix \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const QMatrix2x2& value)
+{
+ setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context
+ to a 2x3 matrix \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, const QMatrix2x3& value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformGenericMatrix
+ (glUniformMatrix2x3fv, glUniform3fv, location, value, 2, 3);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context
+ to a 2x3 matrix \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const QMatrix2x3& value)
+{
+ setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context
+ to a 2x4 matrix \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, const QMatrix2x4& value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformGenericMatrix
+ (glUniformMatrix2x4fv, glUniform4fv, location, value, 2, 4);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context
+ to a 2x4 matrix \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const QMatrix2x4& value)
+{
+ setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context
+ to a 3x2 matrix \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, const QMatrix3x2& value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformGenericMatrix
+ (glUniformMatrix3x2fv, glUniform2fv, location, value, 3, 2);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context
+ to a 3x2 matrix \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const QMatrix3x2& value)
+{
+ setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context
+ to a 3x3 matrix \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, const QMatrix3x3& value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformMatrix(glUniformMatrix3fv, location, value, 3, 3);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context
+ to a 3x3 matrix \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const QMatrix3x3& value)
+{
+ setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context
+ to a 3x4 matrix \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, const QMatrix3x4& value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformGenericMatrix
+ (glUniformMatrix3x4fv, glUniform4fv, location, value, 3, 4);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context
+ to a 3x4 matrix \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const QMatrix3x4& value)
+{
+ setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context
+ to a 4x2 matrix \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, const QMatrix4x2& value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformGenericMatrix
+ (glUniformMatrix4x2fv, glUniform2fv, location, value, 4, 2);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context
+ to a 4x2 matrix \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const QMatrix4x2& value)
+{
+ setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context
+ to a 4x3 matrix \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, const QMatrix4x3& value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformGenericMatrix
+ (glUniformMatrix4x3fv, glUniform3fv, location, value, 4, 3);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context
+ to a 4x3 matrix \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const QMatrix4x3& value)
+{
+ setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context
+ to a 4x4 matrix \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, const QMatrix4x4& value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformMatrix(glUniformMatrix4fv, location, value, 4, 4);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context
+ to a 4x4 matrix \a value.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const QMatrix4x4& value)
+{
+ setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable at \a location in the current context
+ to a 2x2 matrix \a value. The matrix elements must be specified
+ in column-major order.
+
+ \sa setAttributeValue()
+ \since 4.6.2
+*/
+void QGLShaderProgram::setUniformValue(int location, const GLfloat value[2][2])
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glUniformMatrix2fv(location, 1, GL_FALSE, value[0]);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable at \a location in the current context
+ to a 3x3 matrix \a value. The matrix elements must be specified
+ in column-major order.
+
+ \sa setAttributeValue()
+ \since 4.6.2
+*/
+void QGLShaderProgram::setUniformValue(int location, const GLfloat value[3][3])
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glUniformMatrix3fv(location, 1, GL_FALSE, value[0]);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable at \a location in the current context
+ to a 4x4 matrix \a value. The matrix elements must be specified
+ in column-major order.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(int location, const GLfloat value[4][4])
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glUniformMatrix4fv(location, 1, GL_FALSE, value[0]);
+}
+
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context
+ to a 2x2 matrix \a value. The matrix elements must be specified
+ in column-major order.
+
+ \sa setAttributeValue()
+ \since 4.6.2
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const GLfloat value[2][2])
+{
+ setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context
+ to a 3x3 matrix \a value. The matrix elements must be specified
+ in column-major order.
+
+ \sa setAttributeValue()
+ \since 4.6.2
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const GLfloat value[3][3])
+{
+ setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context
+ to a 4x4 matrix \a value. The matrix elements must be specified
+ in column-major order.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const GLfloat value[4][4])
+{
+ setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+ Sets the uniform variable at \a location in the current context to a
+ 3x3 transformation matrix \a value that is specified as a QTransform value.
+
+ To set a QTransform value as a 4x4 matrix in a shader, use
+ \c{setUniformValue(location, QMatrix4x4(value))}.
+*/
+void QGLShaderProgram::setUniformValue(int location, const QTransform& value)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1) {
+ GLfloat mat[3][3] = {
+ {value.m11(), value.m12(), value.m13()},
+ {value.m21(), value.m22(), value.m23()},
+ {value.m31(), value.m32(), value.m33()}
+ };
+ glUniformMatrix3fv(location, 1, GL_FALSE, mat[0]);
+ }
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable called \a name in the current context to a
+ 3x3 transformation matrix \a value that is specified as a QTransform value.
+
+ To set a QTransform value as a 4x4 matrix in a shader, use
+ \c{setUniformValue(name, QMatrix4x4(value))}.
+*/
+void QGLShaderProgram::setUniformValue
+ (const char *name, const QTransform& value)
+{
+ setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+ Sets the uniform variable array at \a location in the current
+ context to the \a count elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(int location, const GLint *values, int count)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glUniform1iv(location, count, values);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable array called \a name in the current
+ context to the \a count elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray
+ (const char *name, const GLint *values, int count)
+{
+ setUniformValueArray(uniformLocation(name), values, count);
+}
+
+/*!
+ Sets the uniform variable array at \a location in the current
+ context to the \a count elements of \a values. This overload
+ should be used when setting an array of sampler values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(int location, const GLuint *values, int count)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glUniform1iv(location, count, reinterpret_cast<const GLint *>(values));
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable array called \a name in the current
+ context to the \a count elements of \a values. This overload
+ should be used when setting an array of sampler values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray
+ (const char *name, const GLuint *values, int count)
+{
+ setUniformValueArray(uniformLocation(name), values, count);
+}
+
+/*!
+ Sets the uniform variable array at \a location in the current
+ context to the \a count elements of \a values. Each element
+ has \a tupleSize components. The \a tupleSize must be 1, 2, 3, or 4.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(int location, const GLfloat *values, int count, int tupleSize)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1) {
+ if (tupleSize == 1)
+ glUniform1fv(location, count, values);
+ else if (tupleSize == 2)
+ glUniform2fv(location, count, values);
+ else if (tupleSize == 3)
+ glUniform3fv(location, count, values);
+ else if (tupleSize == 4)
+ glUniform4fv(location, count, values);
+ else
+ qWarning() << "QGLShaderProgram::setUniformValue: size" << tupleSize << "not supported";
+ }
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable array called \a name in the current
+ context to the \a count elements of \a values. Each element
+ has \a tupleSize components. The \a tupleSize must be 1, 2, 3, or 4.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray
+ (const char *name, const GLfloat *values, int count, int tupleSize)
+{
+ setUniformValueArray(uniformLocation(name), values, count, tupleSize);
+}
+
+/*!
+ Sets the uniform variable array at \a location in the current
+ context to the \a count 2D vector elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(int location, const QVector2D *values, int count)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glUniform2fv(location, count, reinterpret_cast<const GLfloat *>(values));
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable array called \a name in the current
+ context to the \a count 2D vector elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(const char *name, const QVector2D *values, int count)
+{
+ setUniformValueArray(uniformLocation(name), values, count);
+}
+
+/*!
+ Sets the uniform variable array at \a location in the current
+ context to the \a count 3D vector elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(int location, const QVector3D *values, int count)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glUniform3fv(location, count, reinterpret_cast<const GLfloat *>(values));
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable array called \a name in the current
+ context to the \a count 3D vector elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(const char *name, const QVector3D *values, int count)
+{
+ setUniformValueArray(uniformLocation(name), values, count);
+}
+
+/*!
+ Sets the uniform variable array at \a location in the current
+ context to the \a count 4D vector elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(int location, const QVector4D *values, int count)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ glUniform4fv(location, count, reinterpret_cast<const GLfloat *>(values));
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable array called \a name in the current
+ context to the \a count 4D vector elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(const char *name, const QVector4D *values, int count)
+{
+ setUniformValueArray(uniformLocation(name), values, count);
+}
+
+// We have to repack matrix arrays from qreal to GLfloat.
+#define setUniformMatrixArray(func,location,values,count,type,cols,rows) \
+ if (location == -1 || count <= 0) \
+ return; \
+ if (sizeof(type) == sizeof(GLfloat) * cols * rows) { \
+ func(location, count, GL_FALSE, \
+ reinterpret_cast<const GLfloat *>(values[0].constData())); \
+ } else { \
+ QVarLengthArray<GLfloat> temp(cols * rows * count); \
+ for (int index = 0; index < count; ++index) { \
+ for (int index2 = 0; index2 < (cols * rows); ++index2) { \
+ temp.data()[cols * rows * index + index2] = \
+ values[index].constData()[index2]; \
+ } \
+ } \
+ func(location, count, GL_FALSE, temp.constData()); \
+ }
+#if !defined(QT_OPENGL_ES_2)
+#define setUniformGenericMatrixArray(func,colfunc,location,values,count,type,cols,rows) \
+ if (location == -1 || count <= 0) \
+ return; \
+ if (sizeof(type) == sizeof(GLfloat) * cols * rows) { \
+ const GLfloat *data = reinterpret_cast<const GLfloat *> \
+ (values[0].constData()); \
+ if (func) \
+ func(location, count, GL_FALSE, data); \
+ else \
+ colfunc(location, count * cols, data); \
+ } else { \
+ QVarLengthArray<GLfloat> temp(cols * rows * count); \
+ for (int index = 0; index < count; ++index) { \
+ for (int index2 = 0; index2 < (cols * rows); ++index2) { \
+ temp.data()[cols * rows * index + index2] = \
+ values[index].constData()[index2]; \
+ } \
+ } \
+ if (func) \
+ func(location, count, GL_FALSE, temp.constData()); \
+ else \
+ colfunc(location, count * cols, temp.constData()); \
+ }
+#else
+#define setUniformGenericMatrixArray(func,colfunc,location,values,count,type,cols,rows) \
+ if (location == -1 || count <= 0) \
+ return; \
+ if (sizeof(type) == sizeof(GLfloat) * cols * rows) { \
+ const GLfloat *data = reinterpret_cast<const GLfloat *> \
+ (values[0].constData()); \
+ colfunc(location, count * cols, data); \
+ } else { \
+ QVarLengthArray<GLfloat> temp(cols * rows * count); \
+ for (int index = 0; index < count; ++index) { \
+ for (int index2 = 0; index2 < (cols * rows); ++index2) { \
+ temp.data()[cols * rows * index + index2] = \
+ values[index].constData()[index2]; \
+ } \
+ } \
+ colfunc(location, count * cols, temp.constData()); \
+ }
+#endif
+
+/*!
+ Sets the uniform variable array at \a location in the current
+ context to the \a count 2x2 matrix elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(int location, const QMatrix2x2 *values, int count)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformMatrixArray
+ (glUniformMatrix2fv, location, values, count, QMatrix2x2, 2, 2);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable array called \a name in the current
+ context to the \a count 2x2 matrix elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x2 *values, int count)
+{
+ setUniformValueArray(uniformLocation(name), values, count);
+}
+
+/*!
+ Sets the uniform variable array at \a location in the current
+ context to the \a count 2x3 matrix elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(int location, const QMatrix2x3 *values, int count)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformGenericMatrixArray
+ (glUniformMatrix2x3fv, glUniform3fv, location, values, count,
+ QMatrix2x3, 2, 3);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable array called \a name in the current
+ context to the \a count 2x3 matrix elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x3 *values, int count)
+{
+ setUniformValueArray(uniformLocation(name), values, count);
+}
+
+/*!
+ Sets the uniform variable array at \a location in the current
+ context to the \a count 2x4 matrix elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(int location, const QMatrix2x4 *values, int count)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformGenericMatrixArray
+ (glUniformMatrix2x4fv, glUniform4fv, location, values, count,
+ QMatrix2x4, 2, 4);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable array called \a name in the current
+ context to the \a count 2x4 matrix elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x4 *values, int count)
+{
+ setUniformValueArray(uniformLocation(name), values, count);
+}
+
+/*!
+ Sets the uniform variable array at \a location in the current
+ context to the \a count 3x2 matrix elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(int location, const QMatrix3x2 *values, int count)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformGenericMatrixArray
+ (glUniformMatrix3x2fv, glUniform2fv, location, values, count,
+ QMatrix3x2, 3, 2);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable array called \a name in the current
+ context to the \a count 3x2 matrix elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x2 *values, int count)
+{
+ setUniformValueArray(uniformLocation(name), values, count);
+}
+
+/*!
+ Sets the uniform variable array at \a location in the current
+ context to the \a count 3x3 matrix elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(int location, const QMatrix3x3 *values, int count)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformMatrixArray
+ (glUniformMatrix3fv, location, values, count, QMatrix3x3, 3, 3);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable array called \a name in the current
+ context to the \a count 3x3 matrix elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x3 *values, int count)
+{
+ setUniformValueArray(uniformLocation(name), values, count);
+}
+
+/*!
+ Sets the uniform variable array at \a location in the current
+ context to the \a count 3x4 matrix elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(int location, const QMatrix3x4 *values, int count)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformGenericMatrixArray
+ (glUniformMatrix3x4fv, glUniform4fv, location, values, count,
+ QMatrix3x4, 3, 4);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable array called \a name in the current
+ context to the \a count 3x4 matrix elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x4 *values, int count)
+{
+ setUniformValueArray(uniformLocation(name), values, count);
+}
+
+/*!
+ Sets the uniform variable array at \a location in the current
+ context to the \a count 4x2 matrix elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(int location, const QMatrix4x2 *values, int count)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformGenericMatrixArray
+ (glUniformMatrix4x2fv, glUniform2fv, location, values, count,
+ QMatrix4x2, 4, 2);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable array called \a name in the current
+ context to the \a count 4x2 matrix elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x2 *values, int count)
+{
+ setUniformValueArray(uniformLocation(name), values, count);
+}
+
+/*!
+ Sets the uniform variable array at \a location in the current
+ context to the \a count 4x3 matrix elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(int location, const QMatrix4x3 *values, int count)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformGenericMatrixArray
+ (glUniformMatrix4x3fv, glUniform3fv, location, values, count,
+ QMatrix4x3, 4, 3);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable array called \a name in the current
+ context to the \a count 4x3 matrix elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x3 *values, int count)
+{
+ setUniformValueArray(uniformLocation(name), values, count);
+}
+
+/*!
+ Sets the uniform variable array at \a location in the current
+ context to the \a count 4x4 matrix elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(int location, const QMatrix4x4 *values, int count)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformMatrixArray
+ (glUniformMatrix4fv, location, values, count, QMatrix4x4, 4, 4);
+}
+
+/*!
+ \overload
+
+ Sets the uniform variable array called \a name in the current
+ context to the \a count 4x4 matrix elements of \a values.
+
+ \sa setAttributeValue()
+*/
+void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x4 *values, int count)
+{
+ setUniformValueArray(uniformLocation(name), values, count);
+}
+
+#undef ctx
+
+/*!
+ Returns true if shader programs written in the OpenGL Shading
+ Language (GLSL) are supported on this system; false otherwise.
+
+ The \a context is used to resolve the GLSL extensions.
+ If \a context is null, then QGLContext::currentContext() is used.
+*/
+bool QGLShaderProgram::hasOpenGLShaderPrograms(const QGLContext *context)
+{
+#if !defined(QT_OPENGL_ES_2)
+ if (!context)
+ context = QGLContext::currentContext();
+ if (!context)
+ return false;
+ return qt_resolve_glsl_extensions(const_cast<QGLContext *>(context));
+#else
+ Q_UNUSED(context);
+ return true;
+#endif
+}
+
+/*!
+ \internal
+*/
+void QGLShaderProgram::shaderDestroyed()
+{
+ Q_D(QGLShaderProgram);
+ QGLShader *shader = qobject_cast<QGLShader *>(sender());
+ if (shader && !d->removingShaders)
+ removeShader(shader);
+}
+
+#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
+/*! \internal */
+void QGLShaderProgram::setUniformValue(int location, QMacCompatGLint value)
+{
+ setUniformValue(location, GLint(value));
+}
+
+/*! \internal */
+void QGLShaderProgram::setUniformValue(int location, QMacCompatGLuint value)
+{
+ setUniformValue(location, GLuint(value));
+}
+
+/*! \internal */
+void QGLShaderProgram::setUniformValue(const char *name, QMacCompatGLint value)
+{
+ setUniformValue(name, GLint(value));
+}
+
+/*! \internal */
+void QGLShaderProgram::setUniformValue(const char *name, QMacCompatGLuint value)
+{
+ setUniformValue(name, GLuint(value));
+}
+
+/*! \internal */
+void QGLShaderProgram::setUniformValueArray(int location, const QMacCompatGLint *values, int count)
+{
+ setUniformValueArray(location, (const GLint *)values, count);
+}
+
+/*! \internal */
+void QGLShaderProgram::setUniformValueArray(int location, const QMacCompatGLuint *values, int count)
+{
+ setUniformValueArray(location, (const GLuint *)values, count);
+}
+
+/*! \internal */
+void QGLShaderProgram::setUniformValueArray(const char *name, const QMacCompatGLint *values, int count)
+{
+ setUniformValueArray(name, (const GLint *)values, count);
+}
+
+/*! \internal */
+void QGLShaderProgram::setUniformValueArray(const char *name, const QMacCompatGLuint *values, int count)
+{
+ setUniformValueArray(name, (const GLuint *)values, count);
+}
+#endif
+
+#endif // !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1)
+
+QT_END_NAMESPACE
diff --git a/src/opengl/qglshaderprogram.h b/src/opengl/qglshaderprogram.h
new file mode 100644
index 0000000..4eb80dd
--- /dev/null
+++ b/src/opengl/qglshaderprogram.h
@@ -0,0 +1,302 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLSHADERPROGRAM_H
+#define QGLSHADERPROGRAM_H
+
+#include <QtOpenGL/qgl.h>
+#include <QtGui/qvector2d.h>
+#include <QtGui/qvector3d.h>
+#include <QtGui/qvector4d.h>
+#include <QtGui/qmatrix4x4.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(OpenGL)
+
+#if !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1)
+
+class QGLShaderProgram;
+class QGLShaderPrivate;
+
+class Q_OPENGL_EXPORT QGLShader : public QObject
+{
+ Q_OBJECT
+public:
+ enum ShaderTypeBit
+ {
+ Vertex = 0x0001,
+ Fragment = 0x0002
+ };
+ Q_DECLARE_FLAGS(ShaderType, ShaderTypeBit)
+
+ explicit QGLShader(QGLShader::ShaderType type, QObject *parent = 0);
+ QGLShader(QGLShader::ShaderType type, const QGLContext *context, QObject *parent = 0);
+ virtual ~QGLShader();
+
+ QGLShader::ShaderType shaderType() const;
+
+ bool compileSourceCode(const char *source);
+ bool compileSourceCode(const QByteArray& source);
+ bool compileSourceCode(const QString& source);
+ bool compileSourceFile(const QString& fileName);
+
+ QByteArray sourceCode() const;
+
+ bool isCompiled() const;
+ QString log() const;
+
+ GLuint shaderId() const;
+
+private:
+ friend class QGLShaderProgram;
+
+ Q_DISABLE_COPY(QGLShader)
+ Q_DECLARE_PRIVATE(QGLShader)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QGLShader::ShaderType)
+
+
+class QGLShaderProgramPrivate;
+
+class Q_OPENGL_EXPORT QGLShaderProgram : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QGLShaderProgram(QObject *parent = 0);
+ explicit QGLShaderProgram(const QGLContext *context, QObject *parent = 0);
+ virtual ~QGLShaderProgram();
+
+ bool addShader(QGLShader *shader);
+ void removeShader(QGLShader *shader);
+ QList<QGLShader *> shaders() const;
+
+ bool addShaderFromSourceCode(QGLShader::ShaderType type, const char *source);
+ bool addShaderFromSourceCode(QGLShader::ShaderType type, const QByteArray& source);
+ bool addShaderFromSourceCode(QGLShader::ShaderType type, const QString& source);
+ bool addShaderFromSourceFile(QGLShader::ShaderType type, const QString& fileName);
+
+ void removeAllShaders();
+
+ virtual bool link();
+ bool isLinked() const;
+ QString log() const;
+
+ bool bind();
+ void release();
+
+ GLuint programId() const;
+
+ void bindAttributeLocation(const char *name, int location);
+ void bindAttributeLocation(const QByteArray& name, int location);
+ void bindAttributeLocation(const QString& name, int location);
+
+ int attributeLocation(const char *name) const;
+ int attributeLocation(const QByteArray& name) const;
+ int attributeLocation(const QString& name) const;
+
+ void setAttributeValue(int location, GLfloat value);
+ void setAttributeValue(int location, GLfloat x, GLfloat y);
+ void setAttributeValue(int location, GLfloat x, GLfloat y, GLfloat z);
+ void setAttributeValue(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+ void setAttributeValue(int location, const QVector2D& value);
+ void setAttributeValue(int location, const QVector3D& value);
+ void setAttributeValue(int location, const QVector4D& value);
+ void setAttributeValue(int location, const QColor& value);
+ void setAttributeValue(int location, const GLfloat *values, int columns, int rows);
+
+ void setAttributeValue(const char *name, GLfloat value);
+ void setAttributeValue(const char *name, GLfloat x, GLfloat y);
+ void setAttributeValue(const char *name, GLfloat x, GLfloat y, GLfloat z);
+ void setAttributeValue(const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+ void setAttributeValue(const char *name, const QVector2D& value);
+ void setAttributeValue(const char *name, const QVector3D& value);
+ void setAttributeValue(const char *name, const QVector4D& value);
+ void setAttributeValue(const char *name, const QColor& value);
+ void setAttributeValue(const char *name, const GLfloat *values, int columns, int rows);
+
+ void setAttributeArray
+ (int location, const GLfloat *values, int tupleSize, int stride = 0);
+ void setAttributeArray
+ (int location, const QVector2D *values, int stride = 0);
+ void setAttributeArray
+ (int location, const QVector3D *values, int stride = 0);
+ void setAttributeArray
+ (int location, const QVector4D *values, int stride = 0);
+ void setAttributeArray
+ (const char *name, const GLfloat *values, int tupleSize, int stride = 0);
+ void setAttributeArray
+ (const char *name, const QVector2D *values, int stride = 0);
+ void setAttributeArray
+ (const char *name, const QVector3D *values, int stride = 0);
+ void setAttributeArray
+ (const char *name, const QVector4D *values, int stride = 0);
+
+ void enableAttributeArray(int location);
+ void enableAttributeArray(const char *name);
+ void disableAttributeArray(int location);
+ void disableAttributeArray(const char *name);
+
+ int uniformLocation(const char *name) const;
+ int uniformLocation(const QByteArray& name) const;
+ int uniformLocation(const QString& name) const;
+
+#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
+ void setUniformValue(int location, QMacCompatGLint value);
+ void setUniformValue(int location, QMacCompatGLuint value);
+ void setUniformValue(const char *name, QMacCompatGLint value);
+ void setUniformValue(const char *name, QMacCompatGLuint value);
+ void setUniformValueArray(int location, const QMacCompatGLint *values, int count);
+ void setUniformValueArray(int location, const QMacCompatGLuint *values, int count);
+ void setUniformValueArray(const char *name, const QMacCompatGLint *values, int count);
+ void setUniformValueArray(const char *name, const QMacCompatGLuint *values, int count);
+#endif
+
+ void setUniformValue(int location, GLfloat value);
+ void setUniformValue(int location, GLint value);
+ void setUniformValue(int location, GLuint value);
+ void setUniformValue(int location, GLfloat x, GLfloat y);
+ void setUniformValue(int location, GLfloat x, GLfloat y, GLfloat z);
+ void setUniformValue(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+ void setUniformValue(int location, const QVector2D& value);
+ void setUniformValue(int location, const QVector3D& value);
+ void setUniformValue(int location, const QVector4D& value);
+ void setUniformValue(int location, const QColor& color);
+ void setUniformValue(int location, const QPoint& point);
+ void setUniformValue(int location, const QPointF& point);
+ void setUniformValue(int location, const QSize& size);
+ void setUniformValue(int location, const QSizeF& size);
+ void setUniformValue(int location, const QMatrix2x2& value);
+ void setUniformValue(int location, const QMatrix2x3& value);
+ void setUniformValue(int location, const QMatrix2x4& value);
+ void setUniformValue(int location, const QMatrix3x2& value);
+ void setUniformValue(int location, const QMatrix3x3& value);
+ void setUniformValue(int location, const QMatrix3x4& value);
+ void setUniformValue(int location, const QMatrix4x2& value);
+ void setUniformValue(int location, const QMatrix4x3& value);
+ void setUniformValue(int location, const QMatrix4x4& value);
+ void setUniformValue(int location, const GLfloat value[2][2]);
+ void setUniformValue(int location, const GLfloat value[3][3]);
+ void setUniformValue(int location, const GLfloat value[4][4]);
+ void setUniformValue(int location, const QTransform& value);
+
+ void setUniformValue(const char *name, GLfloat value);
+ void setUniformValue(const char *name, GLint value);
+ void setUniformValue(const char *name, GLuint value);
+ void setUniformValue(const char *name, GLfloat x, GLfloat y);
+ void setUniformValue(const char *name, GLfloat x, GLfloat y, GLfloat z);
+ void setUniformValue(const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+ void setUniformValue(const char *name, const QVector2D& value);
+ void setUniformValue(const char *name, const QVector3D& value);
+ void setUniformValue(const char *name, const QVector4D& value);
+ void setUniformValue(const char *name, const QColor& color);
+ void setUniformValue(const char *name, const QPoint& point);
+ void setUniformValue(const char *name, const QPointF& point);
+ void setUniformValue(const char *name, const QSize& size);
+ void setUniformValue(const char *name, const QSizeF& size);
+ void setUniformValue(const char *name, const QMatrix2x2& value);
+ void setUniformValue(const char *name, const QMatrix2x3& value);
+ void setUniformValue(const char *name, const QMatrix2x4& value);
+ void setUniformValue(const char *name, const QMatrix3x2& value);
+ void setUniformValue(const char *name, const QMatrix3x3& value);
+ void setUniformValue(const char *name, const QMatrix3x4& value);
+ void setUniformValue(const char *name, const QMatrix4x2& value);
+ void setUniformValue(const char *name, const QMatrix4x3& value);
+ void setUniformValue(const char *name, const QMatrix4x4& value);
+ void setUniformValue(const char *name, const GLfloat value[2][2]);
+ void setUniformValue(const char *name, const GLfloat value[3][3]);
+ void setUniformValue(const char *name, const GLfloat value[4][4]);
+ void setUniformValue(const char *name, const QTransform& value);
+
+ void setUniformValueArray(int location, const GLfloat *values, int count, int tupleSize);
+ void setUniformValueArray(int location, const GLint *values, int count);
+ void setUniformValueArray(int location, const GLuint *values, int count);
+ void setUniformValueArray(int location, const QVector2D *values, int count);
+ void setUniformValueArray(int location, const QVector3D *values, int count);
+ void setUniformValueArray(int location, const QVector4D *values, int count);
+ void setUniformValueArray(int location, const QMatrix2x2 *values, int count);
+ void setUniformValueArray(int location, const QMatrix2x3 *values, int count);
+ void setUniformValueArray(int location, const QMatrix2x4 *values, int count);
+ void setUniformValueArray(int location, const QMatrix3x2 *values, int count);
+ void setUniformValueArray(int location, const QMatrix3x3 *values, int count);
+ void setUniformValueArray(int location, const QMatrix3x4 *values, int count);
+ void setUniformValueArray(int location, const QMatrix4x2 *values, int count);
+ void setUniformValueArray(int location, const QMatrix4x3 *values, int count);
+ void setUniformValueArray(int location, const QMatrix4x4 *values, int count);
+
+ void setUniformValueArray(const char *name, const GLfloat *values, int count, int tupleSize);
+ void setUniformValueArray(const char *name, const GLint *values, int count);
+ void setUniformValueArray(const char *name, const GLuint *values, int count);
+ void setUniformValueArray(const char *name, const QVector2D *values, int count);
+ void setUniformValueArray(const char *name, const QVector3D *values, int count);
+ void setUniformValueArray(const char *name, const QVector4D *values, int count);
+ void setUniformValueArray(const char *name, const QMatrix2x2 *values, int count);
+ void setUniformValueArray(const char *name, const QMatrix2x3 *values, int count);
+ void setUniformValueArray(const char *name, const QMatrix2x4 *values, int count);
+ void setUniformValueArray(const char *name, const QMatrix3x2 *values, int count);
+ void setUniformValueArray(const char *name, const QMatrix3x3 *values, int count);
+ void setUniformValueArray(const char *name, const QMatrix3x4 *values, int count);
+ void setUniformValueArray(const char *name, const QMatrix4x2 *values, int count);
+ void setUniformValueArray(const char *name, const QMatrix4x3 *values, int count);
+ void setUniformValueArray(const char *name, const QMatrix4x4 *values, int count);
+
+ static bool hasOpenGLShaderPrograms(const QGLContext *context = 0);
+
+private Q_SLOTS:
+ void shaderDestroyed();
+
+private:
+ Q_DISABLE_COPY(QGLShaderProgram)
+ Q_DECLARE_PRIVATE(QGLShaderProgram)
+
+ bool init();
+};
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/opengl/qglwindowsurface_qws.cpp b/src/opengl/qglwindowsurface_qws.cpp
index 6bf3257..5041cb9 100644
--- a/src/opengl/qglwindowsurface_qws.cpp
+++ b/src/opengl/qglwindowsurface_qws.cpp
@@ -43,7 +43,6 @@
#include <QtGui/QWidget>
#include <QtOpenGL/QGLWidget>
#include "private/qglwindowsurface_qws_p.h"
-#include "private/qglpaintdevice_qws_p.h"
#include "private/qpaintengine_opengl_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/opengl/qgraphicsshadereffect.cpp b/src/opengl/qgraphicsshadereffect.cpp
new file mode 100644
index 0000000..4d7a69c
--- /dev/null
+++ b/src/opengl/qgraphicsshadereffect.cpp
@@ -0,0 +1,314 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgraphicsshadereffect_p.h"
+#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
+#include "qglshaderprogram.h"
+#include "gl2paintengineex/qglcustomshaderstage_p.h"
+#define QGL_HAVE_CUSTOM_SHADERS 1
+#endif
+#include <QtGui/qpainter.h>
+#include <QtGui/qgraphicsitem.h>
+#include <QtGui/private/qgraphicseffect_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*#
+ \class QGraphicsShaderEffect
+ \brief The QGraphicsShaderEffect class is the base class for creating
+ custom GLSL shader effects in a QGraphicsScene.
+ \since 4.6
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ The specific effect is defined by a fragment of GLSL source code
+ supplied to setPixelShaderFragment(). This source code must define a
+ function with the signature
+ \c{lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords)}
+ that returns the source pixel value
+ to use in the paint engine's shader program. The shader fragment
+ is linked with the regular shader code used by the GL2 paint engine
+ to construct a complete QGLShaderProgram.
+
+ The following example shader converts the incoming pixmap to
+ grayscale and then applies a colorize operation using the
+ \c effectColor value:
+
+ \code
+ static char const colorizeShaderCode[] =
+ "uniform lowp vec4 effectColor;\n"
+ "lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords) {\n"
+ " vec4 src = texture2D(imageTexture, textureCoords);\n"
+ " float gray = dot(src.rgb, vec3(0.212671, 0.715160, 0.072169));\n"
+ " vec4 colorize = 1.0-((1.0-gray)*(1.0-effectColor));\n"
+ " return vec4(colorize.rgb, src.a);\n"
+ "}";
+ \endcode
+
+ To use this shader code, it is necessary to define a subclass
+ of QGraphicsShaderEffect as follows:
+
+ \code
+ class ColorizeEffect : public QGraphicsShaderEffect
+ {
+ Q_OBJECT
+ public:
+ ColorizeEffect(QObject *parent = 0)
+ : QGraphicsShaderEffect(parent), color(Qt::black)
+ {
+ setPixelShaderFragment(colorizeShaderCode);
+ }
+
+ QColor effectColor() const { return color; }
+ void setEffectColor(const QColor& c)
+ {
+ color = c;
+ setUniformsDirty();
+ }
+
+ protected:
+ void setUniforms(QGLShaderProgram *program)
+ {
+ program->setUniformValue("effectColor", color);
+ }
+
+ private:
+ QColor color;
+ };
+ \endcode
+
+ The setUniforms() function is called when the effect is about
+ to be used for drawing to give the subclass the opportunity to
+ set effect-specific uniform variables.
+
+ QGraphicsShaderEffect is only supported when the GL2 paint engine
+ is in use. When any other paint engine is in use (GL1, raster, etc),
+ the drawItem() method will draw its item argument directly with
+ no effect applied.
+
+ \sa QGraphicsEffect
+*/
+
+static const char qglslDefaultImageFragmentShader[] = "\
+ lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords) { \
+ return texture2D(imageTexture, textureCoords); \
+ }\n";
+
+#ifdef QGL_HAVE_CUSTOM_SHADERS
+
+class QGLCustomShaderEffectStage : public QGLCustomShaderStage
+{
+public:
+ QGLCustomShaderEffectStage
+ (QGraphicsShaderEffect *e, const QByteArray& source)
+ : QGLCustomShaderStage(),
+ effect(e)
+ {
+ setSource(source);
+ }
+
+ void setUniforms(QGLShaderProgram *program);
+
+ QGraphicsShaderEffect *effect;
+};
+
+void QGLCustomShaderEffectStage::setUniforms(QGLShaderProgram *program)
+{
+ effect->setUniforms(program);
+}
+
+#endif
+
+class QGraphicsShaderEffectPrivate : public QGraphicsEffectPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsShaderEffect)
+public:
+ QGraphicsShaderEffectPrivate()
+ : pixelShaderFragment(qglslDefaultImageFragmentShader)
+#ifdef QGL_HAVE_CUSTOM_SHADERS
+ , customShaderStage(0)
+#endif
+ {
+ }
+
+ QByteArray pixelShaderFragment;
+#ifdef QGL_HAVE_CUSTOM_SHADERS
+ QGLCustomShaderEffectStage *customShaderStage;
+#endif
+};
+
+/*#
+ Constructs a shader effect and attaches it to \a parent.
+*/
+QGraphicsShaderEffect::QGraphicsShaderEffect(QObject *parent)
+ : QGraphicsEffect(*new QGraphicsShaderEffectPrivate(), parent)
+{
+}
+
+/*#
+ Destroys this shader effect.
+*/
+QGraphicsShaderEffect::~QGraphicsShaderEffect()
+{
+#ifdef QGL_HAVE_CUSTOM_SHADERS
+ Q_D(QGraphicsShaderEffect);
+ delete d->customShaderStage;
+#endif
+}
+
+/*#
+ Returns the source code for the pixel shader fragment for
+ this shader effect. The default is a shader that copies
+ its incoming pixmap directly to the output with no effect
+ applied.
+
+ \sa setPixelShaderFragment()
+*/
+QByteArray QGraphicsShaderEffect::pixelShaderFragment() const
+{
+ Q_D(const QGraphicsShaderEffect);
+ return d->pixelShaderFragment;
+}
+
+/*#
+ Sets the source code for the pixel shader fragment for
+ this shader effect to \a code.
+
+ The \a code must define a GLSL function with the signature
+ \c{lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords)}
+ that returns the source pixel value to use in the paint engine's
+ shader program. The following is the default pixel shader fragment,
+ which draws a pixmap with no effect applied:
+
+ \code
+ lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords) {
+ return texture2D(imageTexture, textureCoords);
+ }
+ \endcode
+
+ \sa pixelShaderFragment(), setUniforms()
+*/
+void QGraphicsShaderEffect::setPixelShaderFragment(const QByteArray& code)
+{
+ Q_D(QGraphicsShaderEffect);
+ if (d->pixelShaderFragment != code) {
+ d->pixelShaderFragment = code;
+#ifdef QGL_HAVE_CUSTOM_SHADERS
+ delete d->customShaderStage;
+ d->customShaderStage = 0;
+#endif
+ }
+}
+
+/*#
+ \reimp
+*/
+void QGraphicsShaderEffect::draw(QPainter *painter)
+{
+ Q_D(QGraphicsShaderEffect);
+
+#ifdef QGL_HAVE_CUSTOM_SHADERS
+ // Set the custom shader on the paint engine. The setOnPainter()
+ // call may fail if the paint engine is not GL2. In that case,
+ // we fall through to drawing the pixmap normally.
+ if (!d->customShaderStage) {
+ d->customShaderStage = new QGLCustomShaderEffectStage
+ (this, d->pixelShaderFragment);
+ }
+ bool usingShader = d->customShaderStage->setOnPainter(painter);
+
+ QPoint offset;
+ if (sourceIsPixmap()) {
+ // No point in drawing in device coordinates (pixmap will be scaled anyways).
+ const QPixmap pixmap = sourcePixmap(Qt::LogicalCoordinates, &offset);
+ painter->drawPixmap(offset, pixmap);
+ } else {
+ // Draw pixmap in device coordinates to avoid pixmap scaling.
+ const QPixmap pixmap = sourcePixmap(Qt::DeviceCoordinates, &offset);
+ QTransform restoreTransform = painter->worldTransform();
+ painter->setWorldTransform(QTransform());
+ painter->drawPixmap(offset, pixmap);
+ painter->setWorldTransform(restoreTransform);
+ }
+
+ // Remove the custom shader to return to normal painting operations.
+ if (usingShader)
+ d->customShaderStage->removeFromPainter(painter);
+#else
+ drawSource(painter);
+#endif
+}
+
+/*#
+ Sets the custom uniform variables on this shader effect to
+ be dirty. The setUniforms() function will be called the next
+ time the shader program corresponding to this effect is used.
+
+ This function is typically called by subclasses when an
+ effect-specific parameter is changed by the application.
+
+ \sa setUniforms()
+*/
+void QGraphicsShaderEffect::setUniformsDirty()
+{
+#ifdef QGL_HAVE_CUSTOM_SHADERS
+ Q_D(QGraphicsShaderEffect);
+ if (d->customShaderStage)
+ d->customShaderStage->setUniformsDirty();
+#endif
+}
+
+/*#
+ Sets custom uniform variables on the current GL context when
+ \a program is about to be used by the paint engine.
+
+ This function should be overridden if the shader set with
+ setPixelShaderFragment() has additional parameters beyond
+ those that the paint engine normally sets itself.
+
+ \sa setUniformsDirty()
+*/
+void QGraphicsShaderEffect::setUniforms(QGLShaderProgram *program)
+{
+ Q_UNUSED(program);
+}
+
+QT_END_NAMESPACE
diff --git a/src/opengl/qgraphicsshadereffect_p.h b/src/opengl/qgraphicsshadereffect_p.h
new file mode 100644
index 0000000..de65ebb
--- /dev/null
+++ b/src/opengl/qgraphicsshadereffect_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSSHADEREFFECT_P_H
+#define QGRAPHICSSHADEREFFECT_P_H
+
+//
+// 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 <QtGui/qgraphicseffect.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(OpenGL)
+
+class QGLShaderProgram;
+class QGLCustomShaderEffectStage;
+class QGraphicsShaderEffectPrivate;
+
+class Q_OPENGL_EXPORT QGraphicsShaderEffect : public QGraphicsEffect
+{
+ Q_OBJECT
+public:
+ QGraphicsShaderEffect(QObject *parent = 0);
+ virtual ~QGraphicsShaderEffect();
+
+ QByteArray pixelShaderFragment() const;
+ void setPixelShaderFragment(const QByteArray& code);
+
+protected:
+ void draw(QPainter *painter);
+ void setUniformsDirty();
+ virtual void setUniforms(QGLShaderProgram *program);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsShaderEffect)
+ Q_DISABLE_COPY(QGraphicsShaderEffect)
+
+ friend class QGLCustomShaderEffectStage;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGRAPHICSSHADEREFFECT_P_H
diff --git a/src/opengl/qgraphicssystem_gl.cpp b/src/opengl/qgraphicssystem_gl.cpp
index 4c65477..c0d9233 100644
--- a/src/opengl/qgraphicssystem_gl.cpp
+++ b/src/opengl/qgraphicssystem_gl.cpp
@@ -44,14 +44,25 @@
#include "private/qpixmap_raster_p.h"
#include "private/qpixmapdata_gl_p.h"
#include "private/qwindowsurface_gl_p.h"
+#include "private/qgl_p.h"
#include <private/qwindowsurface_raster_p.h>
+#if defined(Q_WS_X11) && defined(QT_OPENGL_ES)
+#include "private/qpixmapdata_x11gl_p.h"
+#include "private/qwindowsurface_x11gl_p.h"
+#endif
+
QT_BEGIN_NAMESPACE
extern QGLWidget *qt_gl_getShareWidget();
QPixmapData *QGLGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const
{
+#if defined(Q_WS_X11) && defined(QT_OPENGL_ES)
+ if (type == QPixmapData::PixmapType && QX11GLPixmapData::hasX11GLPixmaps())
+ return new QX11GLPixmapData();
+#endif
+
return new QGLPixmapData(type);
}
@@ -65,6 +76,11 @@ QWindowSurface *QGLGraphicsSystem::createWindowSurface(QWidget *widget) const
return new QRasterWindowSurface(widget);
#endif
+#if defined(Q_WS_X11) && defined(QT_OPENGL_ES)
+ if (QX11GLPixmapData::hasX11GLPixmaps())
+ return new QX11GLWindowSurface(widget);
+#endif
+
return new QGLWindowSurface(widget);
}
diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp
index 9c15d56..8dae02a 100644
--- a/src/opengl/qpaintengine_opengl.cpp
+++ b/src/opengl/qpaintengine_opengl.cpp
@@ -39,7 +39,6 @@
**
****************************************************************************/
-#include <private/qtextengine_p.h>
#include <qdebug.h>
#include <private/qfontengine_p.h>
#include <qmath.h>
@@ -50,6 +49,7 @@
#include "qbrush.h"
#include "qgl.h"
#include <private/qgl_p.h>
+#include <private/qglpaintdevice_p.h>
#include <private/qpainter_p.h>
#include "qmap.h"
#include <private/qpaintengine_opengl_p.h>
@@ -57,18 +57,15 @@
#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"
#ifdef Q_WS_QWS
-#include "private/qglpaintdevice_qws_p.h"
#include "private/qglwindowsurface_qws_p.h"
#include "qwsmanager_qws.h"
#include "private/qwsmanager_p.h"
@@ -78,7 +75,7 @@
#include "qgl_cl_p.h"
#endif
-#define QGL_FUNC_CONTEXT QGLContext *ctx = const_cast<QGLContext *>(drawable.context());
+#define QGL_FUNC_CONTEXT QGLContext *ctx = const_cast<QGLContext *>(device->context());
#include <stdlib.h>
#include "qpaintengine_opengl_p.h"
@@ -121,35 +118,6 @@ struct QT_PointF {
qreal y;
};
-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);
-}
-
-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);
-}
-
struct QGLTrapezoid
{
QGLTrapezoid()
@@ -186,180 +154,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;
@@ -450,8 +244,8 @@ public:
bound(false)
{
connect(QGLSignalProxy::instance(),
- SIGNAL(aboutToDestroyContext(const QGLContext *)),
- SLOT(cleanupGLContextRefs(const QGLContext *)));
+ SIGNAL(aboutToDestroyContext(const QGLContext*)),
+ SLOT(cleanupGLContextRefs(const QGLContext*)));
}
inline void setDevice(QPaintDevice *pdev);
@@ -488,7 +282,7 @@ public Q_SLOTS:
}
private:
- QGLDrawable drawable;
+ QGLPaintDevice* device;
QGLFramebufferObject *offscreen;
QGLContext *ctx;
@@ -507,7 +301,13 @@ private:
inline void QGLOffscreen::setDevice(QPaintDevice *pdev)
{
- drawable.setDevice(pdev);
+ if (pdev->devType() == QInternal::OpenGL)
+ device = static_cast<QGLPaintDevice*>(pdev);
+ else
+ device = QGLPaintDevice::getDevice(pdev);
+
+ if (!device)
+ return;
drawable_fbo = (pdev->devType() == QInternal::FramebufferObject);
}
@@ -531,12 +331,12 @@ void QGLOffscreen::initialize()
activated = true;
initialized = true;
- int dim = qMax(2048, static_cast<int>(qt_next_power_of_two(qMax(drawable.size().width(), drawable.size().height()))));
+ int dim = qMax(2048, static_cast<int>(qt_next_power_of_two(qMax(device->size().width(), device->size().height()))));
- bool shared_context = qgl_share_reg()->checkSharing(drawable.context(), ctx);
+ bool shared_context = QGLContext::areSharing(device->context(), ctx);
bool would_fail = last_failed_size.isValid() &&
- (drawable.size().width() >= last_failed_size.width() ||
- drawable.size().height() >= last_failed_size.height());
+ (device->size().width() >= last_failed_size.width() ||
+ device->size().height() >= last_failed_size.height());
bool needs_refresh = dim > mask_dim || !shared_context;
if (needs_refresh && !would_fail) {
@@ -550,13 +350,13 @@ void QGLOffscreen::initialize()
delete offscreen;
offscreen = 0;
mask_dim = 0;
- last_failed_size = drawable.size();
+ last_failed_size = device->size();
}
}
qt_mask_texture_cache()->setOffscreenSize(offscreenSize());
- qt_mask_texture_cache()->setDrawableSize(drawable.size());
- ctx = drawable.context();
+ qt_mask_texture_cache()->setDrawableSize(device->size());
+ ctx = device->context();
#endif
}
@@ -630,11 +430,11 @@ inline void QGLOffscreen::release()
DEBUG_ONCE_STR("QGLOffscreen: releasing offscreen");
if (drawable_fbo)
- drawable.makeCurrent();
+ device->ensureActiveTarget(); //###
else
offscreen->release();
- QSize sz(drawable.size());
+ QSize sz(device->size());
glViewport(0, 0, sz.width(), sz.height());
glMatrixMode(GL_PROJECTION);
@@ -657,7 +457,7 @@ inline bool QGLOffscreen::isBound() const
inline QSize QGLOffscreen::drawableSize() const
{
- return drawable.size();
+ return device->size();
}
inline QSize QGLOffscreen::offscreenSize() const
@@ -721,8 +521,8 @@ public:
QGLProgramCache() {
// we have to know when a context is deleted so we can free
// any program handles it holds
- connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext *)),
- SLOT(cleanupPrograms(const QGLContext *)));
+ connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)),
+ SLOT(cleanupPrograms(const QGLContext*)));
}
~QGLProgramCache() {
@@ -750,7 +550,7 @@ public:
QList<const QGLContext *> contexts = programs.uniqueKeys();
for (int i=0; i<contexts.size(); ++i) {
const QGLContext *cx = contexts.at(i);
- if (cx != ctx && qgl_share_reg()->checkSharing(cx, ctx)) {
+ if (cx != ctx && QGLContext::areSharing(cx, ctx)) {
QList<GLProgram> progs = programs.values(cx);
for (int k=0; k<progs.size(); ++k) {
const GLProgram &prg = progs.at(k);
@@ -835,8 +635,8 @@ public:
: p(priv)
{
connect(QGLSignalProxy::instance(),
- SIGNAL(aboutToDestroyContext(const QGLContext *)),
- SLOT(cleanupGLContextRefs(const QGLContext *)));
+ SIGNAL(aboutToDestroyContext(const QGLContext*)),
+ SLOT(cleanupGLContextRefs(const QGLContext*)));
}
public Q_SLOTS:
@@ -864,6 +664,7 @@ public:
, txop(QTransform::TxNone)
, inverseScale(1)
, moveToCount(0)
+ , last_created_state(0)
, shader_ctx(0)
, grad_palette(0)
, drawable_texture(0)
@@ -941,7 +742,6 @@ public:
uint has_brush : 1;
uint has_fast_pen : 1;
uint use_stencil_method : 1;
- uint dirty_stencil : 1;
uint dirty_drawable_texture : 1;
uint has_stencil_face_ext : 1;
uint use_fragment_programs : 1;
@@ -952,13 +752,15 @@ public:
uint use_system_clip : 1;
uint use_emulation : 1;
+ QRegion dirty_stencil;
+
void updateUseEmulation();
QTransform matrix;
GLubyte pen_color[4];
GLubyte brush_color[4];
QTransform::TransformationType txop;
- QGLDrawable drawable;
+ QGLPaintDevice* device;
QGLOffscreen offscreen;
qreal inverseScale;
@@ -990,6 +792,8 @@ public:
void updateGLMatrix() const;
+ mutable QPainterState *last_created_state;
+
QGLContext *shader_ctx;
GLuint grad_palette;
@@ -1202,12 +1006,12 @@ public:
QGLGradientCache() : QObject(), buffer_ctx(0)
{
connect(QGLSignalProxy::instance(),
- SIGNAL(aboutToDestroyContext(const QGLContext *)),
- SLOT(cleanupGLContextRefs(const QGLContext *)));
+ SIGNAL(aboutToDestroyContext(const QGLContext*)),
+ SLOT(cleanupGLContextRefs(const QGLContext*)));
}
inline GLuint getBuffer(const QGradient &gradient, qreal opacity, QGLContext *ctx) {
- if (buffer_ctx && !qgl_share_reg()->checkSharing(buffer_ctx, ctx))
+ if (buffer_ctx && !QGLContext::areSharing(buffer_ctx, ctx))
cleanCache();
buffer_ctx = ctx;
@@ -1269,6 +1073,7 @@ protected:
}
void cleanCache() {
+ QGLShareContextScope scope(buffer_ctx);
QGLGradientColorTableHash::const_iterator it = cache.constBegin();
for (; it != cache.constEnd(); ++it) {
const CacheInfo &cache_info = it.value();
@@ -1366,7 +1171,7 @@ void QOpenGLPaintEnginePrivate::createGradientPaletteTexture(const QGradient& g)
#ifdef QT_OPENGL_ES //###
Q_UNUSED(g);
#else
- GLuint texId = qt_opengl_gradient_cache()->getBuffer(g, opacity, drawable.context());
+ GLuint texId = qt_opengl_gradient_cache()->getBuffer(g, opacity, device->context());
glBindTexture(GL_TEXTURE_1D, texId);
grad_palette = texId;
if (g.spread() == QGradient::RepeatSpread || g.type() == QGradient::ConicalGradient)
@@ -1413,7 +1218,7 @@ inline void QOpenGLPaintEnginePrivate::setGradientOps(const QBrush &brush, const
fragment_brush = FRAGMENT_PROGRAM_BRUSH_CONICAL;
else if (current_style == Qt::SolidPattern)
fragment_brush = FRAGMENT_PROGRAM_BRUSH_SOLID;
- else if (current_style == Qt::TexturePattern)
+ else if (current_style == Qt::TexturePattern && !brush.texture().isQBitmap())
fragment_brush = FRAGMENT_PROGRAM_BRUSH_TEXTURE;
else
fragment_brush = FRAGMENT_PROGRAM_BRUSH_PATTERN;
@@ -1435,16 +1240,25 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev)
{
Q_D(QOpenGLPaintEngine);
- d->drawable.setDevice(pdev);
+ if (pdev->devType() == QInternal::OpenGL)
+ d->device = static_cast<QGLPaintDevice*>(pdev);
+ else
+ d->device = QGLPaintDevice::getDevice(pdev);
+
+ if (!d->device)
+ return false;
+
d->offscreen.setDevice(pdev);
d->has_fast_pen = false;
d->inverseScale = 1;
d->opacity = 1;
- d->drawable.makeCurrent();
+ d->device->beginPaint();
d->matrix = QTransform();
d->has_antialiasing = false;
d->high_quality_antialiasing = false;
- d->dirty_stencil = true;
+
+ QSize sz(d->device->size());
+ d->dirty_stencil = QRect(0, 0, sz.width(), sz.height());
d->use_emulation = false;
@@ -1455,7 +1269,7 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev)
bool has_frag_program = (QGLExtensions::glExtensions & QGLExtensions::FragmentProgram)
&& (pdev->devType() != QInternal::Pixmap);
- QGLContext *ctx = const_cast<QGLContext *>(d->drawable.context());
+ QGLContext *ctx = const_cast<QGLContext *>(d->device->context());
if (!ctx) {
qWarning() << "QOpenGLPaintEngine: paint device doesn't have a valid GL context.";
return false;
@@ -1464,9 +1278,9 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev)
if (has_frag_program)
has_frag_program = qt_resolve_frag_program_extensions(ctx) && qt_resolve_version_1_3_functions(ctx);
- d->use_stencil_method = d->drawable.format().stencil()
+ d->use_stencil_method = d->device->format().stencil()
&& (QGLExtensions::glExtensions & QGLExtensions::StencilWrap);
- if (d->drawable.format().directRendering()
+ if (d->device->format().directRendering()
&& (d->use_stencil_method && QGLExtensions::glExtensions & QGLExtensions::StencilTwoSide))
d->has_stencil_face_ext = qt_resolve_stencil_face_extension(ctx);
@@ -1532,17 +1346,6 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev)
d->offscreen.begin();
- const QColor &c = d->drawable.backgroundColor();
- glClearColor(c.redF(), c.greenF(), c.blueF(), 1.0);
- if (d->drawable.context()->d_func()->clear_on_painter_begin && d->drawable.autoFillBackground()) {
- GLbitfield clearBits = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
-#ifndef QT_OPENGL_ES
- clearBits |= GL_ACCUM_BUFFER_BIT;
-#endif
- glClear(clearBits);
- }
-
- QSize sz(d->drawable.size());
glViewport(0, 0, sz.width(), sz.height()); // XXX (Embedded): We need a solution for GLWidgets that draw in a part or a bigger surface...
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
@@ -1559,7 +1362,7 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev)
#ifdef QT_OPENGL_ES
d->max_texture_size = ctx->d_func()->maxTextureSize();
#else
- bool shared_ctx = qgl_share_reg()->checkSharing(d->drawable.context(), d->shader_ctx);
+ bool shared_ctx = QGLContext::areSharing(d->device->context(), d->shader_ctx);
if (shared_ctx) {
d->max_texture_size = d->shader_ctx->d_func()->maxTextureSize();
@@ -1575,7 +1378,7 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev)
glDeleteTextures(1, &d->drawable_texture);
ctx->makeCurrent();
}
- d->shader_ctx = d->drawable.context();
+ d->shader_ctx = d->device->context();
glGenTextures(1, &d->grad_palette);
qt_mask_texture_cache()->clearCache();
@@ -1610,7 +1413,7 @@ bool QOpenGLPaintEngine::end()
Q_D(QOpenGLPaintEngine);
d->flushDrawQueue();
d->offscreen.end();
- QGLContext *ctx = const_cast<QGLContext *>(d->drawable.context());
+ QGLContext *ctx = const_cast<QGLContext *>(d->device->context());
if (!ctx->d_ptr->internal_context) {
glMatrixMode(GL_TEXTURE);
glPopMatrix();
@@ -1627,8 +1430,7 @@ bool QOpenGLPaintEngine::end()
glPopClientAttrib();
}
#endif
- d->drawable.swapBuffers();
- d->drawable.doneCurrent();
+ d->device->endPaint();
qt_mask_texture_cache()->maintainCache();
return true;
@@ -1791,7 +1593,8 @@ void QOpenGLPaintEnginePrivate::updateGradient(const QBrush &brush, const QRectF
qreal realRadius = g->radius();
QTransform translate(1, 0, 0, 1, -realFocal.x(), -realFocal.y());
QTransform gl_to_qt(1, 0, 0, -1, 0, pdev->height());
- QTransform inv_matrix = gl_to_qt * matrix.inverted() * brush.transform().inverted() * translate;
+ QTransform m = QTransform(matrix).translate(brush_origin.x(), brush_origin.y());
+ QTransform inv_matrix = gl_to_qt * (brush.transform() * m).inverted() * translate;
setInvMatrixData(inv_matrix);
@@ -1804,7 +1607,8 @@ void QOpenGLPaintEnginePrivate::updateGradient(const QBrush &brush, const QRectF
QPointF realCenter = g->center();
QTransform translate(1, 0, 0, 1, -realCenter.x(), -realCenter.y());
QTransform gl_to_qt(1, 0, 0, -1, 0, pdev->height());
- QTransform inv_matrix = gl_to_qt * matrix.inverted() * brush.transform().inverted() * translate;
+ QTransform m = QTransform(matrix).translate(brush_origin.x(), brush_origin.y());
+ QTransform inv_matrix = gl_to_qt * (brush.transform() * m).inverted() * translate;
setInvMatrixData(inv_matrix);
@@ -1816,8 +1620,8 @@ void QOpenGLPaintEnginePrivate::updateGradient(const QBrush &brush, const QRectF
QPointF realFinal = g->finalStop();
QTransform translate(1, 0, 0, 1, -realStart.x(), -realStart.y());
QTransform gl_to_qt(1, 0, 0, -1, 0, pdev->height());
-
- QTransform inv_matrix = gl_to_qt * matrix.inverted() * brush.transform().inverted() * translate;
+ QTransform m = QTransform(matrix).translate(brush_origin.x(), brush_origin.y());
+ QTransform inv_matrix = gl_to_qt * (brush.transform() * m).inverted() * translate;
setInvMatrixData(inv_matrix);
@@ -1828,10 +1632,9 @@ void QOpenGLPaintEnginePrivate::updateGradient(const QBrush &brush, const QRectF
linear_data[2] = 1.0f / (l.x() * l.x() + l.y() * l.y());
} else if (style != Qt::SolidPattern) {
- QTransform translate(1, 0, 0, 1, brush_origin.x(), brush_origin.y());
QTransform gl_to_qt(1, 0, 0, -1, 0, pdev->height());
-
- QTransform inv_matrix = gl_to_qt * matrix.inverted() * brush.transform().inverted() * translate;
+ QTransform m = QTransform(matrix).translate(brush_origin.x(), brush_origin.y());
+ QTransform inv_matrix = gl_to_qt * (brush.transform() * m).inverted();
setInvMatrixData(inv_matrix);
}
@@ -1920,15 +1723,15 @@ static void drawTrapezoid(const QGLTrapezoid &trap, const qreal offscreenHeight,
qreal leftB = trap.bottomLeftX + (trap.topLeftX - trap.bottomLeftX) * reciprocal;
qreal rightB = trap.bottomRightX + (trap.topRightX - trap.bottomRightX) * reciprocal;
- const bool topZero = qFuzzyCompare(topDist + 1, 1);
+ const bool topZero = qFuzzyIsNull(topDist);
reciprocal = topZero ? 1.0 / bottomDist : 1.0 / topDist;
qreal leftA = topZero ? (trap.bottomLeftX - leftB) * reciprocal : (trap.topLeftX - leftB) * reciprocal;
qreal rightA = topZero ? (trap.bottomRightX - rightB) * reciprocal : (trap.topRightX - rightB) * reciprocal;
- qreal invLeftA = qFuzzyCompare(leftA + 1, 1) ? 0.0 : 1.0 / leftA;
- qreal invRightA = qFuzzyCompare(rightA + 1, 1) ? 0.0 : 1.0 / rightA;
+ qreal invLeftA = qFuzzyIsNull(leftA) ? 0.0 : 1.0 / leftA;
+ qreal invRightA = qFuzzyIsNull(rightA) ? 0.0 : 1.0 / rightA;
// fragment program needs the negative of invRightA as it mirrors the line
glTexCoord4f(topDist, bottomDist, invLeftA, -invRightA);
@@ -2144,34 +1947,34 @@ void QOpenGLPaintEnginePrivate::fillVertexArray(Qt::FillRule fillRule)
{
Q_Q(QOpenGLPaintEngine);
- if (dirty_stencil) {
- disableClipping();
+ QRect rect = dirty_stencil.boundingRect();
- if (use_system_clip) {
- glEnable(GL_SCISSOR_TEST);
+ if (use_system_clip)
+ rect = q->systemClip().intersected(dirty_stencil).boundingRect();
- QRect rect = q->systemClip().boundingRect();
+ glStencilMask(~0);
- const int left = rect.left();
- const int width = rect.width();
- const int bottom = drawable.size().height() - (rect.bottom() + 1);
- const int height = rect.height();
+ if (!rect.isEmpty()) {
+ disableClipping();
- glScissor(left, bottom, width, height);
- }
+ glEnable(GL_SCISSOR_TEST);
+
+ const int left = rect.left();
+ const int width = rect.width();
+ const int bottom = device->size().height() - (rect.bottom() + 1);
+ const int height = rect.height();
+
+ glScissor(left, bottom, width, height);
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
- dirty_stencil = false;
+ dirty_stencil -= rect;
- if (use_system_clip)
- glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_SCISSOR_TEST);
enableClipping();
}
- glStencilMask(~0);
-
// Enable stencil.
glEnable(GL_STENCIL_TEST);
@@ -2229,7 +2032,7 @@ void QOpenGLPaintEnginePrivate::fillVertexArray(Qt::FillRule fillRule)
// Enable color writes.
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- glStencilMask(0);
+ glStencilMask(stencilMask);
setGradientOps(cbrush, QRectF(QPointF(min_x, min_y), QSizeF(max_x - min_x, max_y - min_y)));
@@ -2241,12 +2044,14 @@ void QOpenGLPaintEnginePrivate::fillVertexArray(Qt::FillRule fillRule)
// Enable stencil func.
glStencilFunc(GL_NOTEQUAL, 0, stencilMask);
+ glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
composite(rect);
} else {
DEBUG_ONCE qDebug() << "QOpenGLPaintEnginePrivate: Drawing polygon using stencil method (no fragment programs)";
// Enable stencil func.
glStencilFunc(GL_NOTEQUAL, 0, stencilMask);
+ glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
#ifndef QT_OPENGL_ES
glBegin(GL_QUADS);
glVertex2f(min_x, min_y);
@@ -2257,24 +2062,6 @@ void QOpenGLPaintEnginePrivate::fillVertexArray(Qt::FillRule fillRule)
#endif
}
- glStencilMask(~0);
- glStencilFunc(GL_ALWAYS, 0, 0);
- glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
-
- // clear all stencil values to 0
- glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
-
-#ifndef QT_OPENGL_ES
- glBegin(GL_QUADS);
- glVertex2f(min_x, min_y);
- glVertex2f(max_x, min_y);
- glVertex2f(max_x, max_y);
- glVertex2f(min_x, max_y);
- glEnd();
-#endif
-
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-
// Disable stencil writes.
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilMask(0);
@@ -2327,7 +2114,7 @@ void QOpenGLPaintEngine::updatePen(const QPen &pen)
Qt::PenStyle pen_style = pen.style();
d->pen_brush_style = pen.brush().style();
d->cpen = pen;
- d->has_pen = (pen_style != Qt::NoPen);
+ d->has_pen = (pen_style != Qt::NoPen) && (d->pen_brush_style != Qt::NoBrush);
d->updateUseEmulation();
if (pen.isCosmetic()) {
@@ -2431,6 +2218,8 @@ void QOpenGLPaintEnginePrivate::updateDepthClip()
{
Q_Q(QOpenGLPaintEngine);
+ ++q->state()->depthClipId;
+
glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
@@ -2449,18 +2238,19 @@ void QOpenGLPaintEnginePrivate::updateDepthClip()
const int left = fastClip.left();
const int width = fastClip.width();
- const int bottom = drawable.size().height() - (fastClip.bottom() + 1);
+ const int bottom = device->size().height() - (fastClip.bottom() + 1);
const int height = fastClip.height();
glScissor(left, bottom, width, height);
return;
}
-#ifndef QT_OPENGL_ES
- glClearDepth(0.0f);
-#else
+#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_ES_1_CL)
glClearDepthf(0.0f);
+#else
+ glClearDepth(0.0f);
#endif
+
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glClear(GL_DEPTH_BUFFER_BIT);
@@ -2519,7 +2309,7 @@ void QOpenGLPaintEnginePrivate::updateDepthClip()
void QOpenGLPaintEnginePrivate::systemStateChanged()
{
Q_Q(QOpenGLPaintEngine);
- if (q->state()->hasClipping)
+ if (q->painter()->hasClipping())
q->updateClipRegion(q->painter()->clipRegion(), Qt::ReplaceClip);
else
q->updateClipRegion(QRegion(), Qt::NoClip);
@@ -2531,7 +2321,7 @@ void QOpenGLPaintEngine::updateClipRegion(const QRegion &clipRegion, Qt::ClipOpe
// clipping is only supported when a stencil or depth buffer is
// available
- if (!d->drawable.format().depth())
+ if (!d->device->format().depth())
return;
d->use_system_clip = false;
@@ -2568,7 +2358,7 @@ void QOpenGLPaintEngine::updateClipRegion(const QRegion &clipRegion, Qt::ClipOpe
path.addRect(untransformedRects[0]);
path = d->matrix.map(path);
- if (path.contains(QRectF(QPointF(), d->drawable.size())))
+ if (path.contains(QRectF(QPointF(), d->device->size())))
isScreenClip = true;
}
}
@@ -3296,6 +3086,9 @@ QGLTrapezoidMaskGenerator::QGLTrapezoidMaskGenerator(const QPainterPath &path, c
{
}
+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);
+
void QGLTrapezoidMaskGenerator::drawMask(const QRect &rect)
{
#ifdef QT_OPENGL_ES
@@ -3441,8 +3234,7 @@ QVector<QGLTrapezoid> QGLRectMaskGenerator::generateTrapezoids()
// manhattan distance (no rotation)
qreal width = qAbs(delta.x()) + qAbs(delta.y());
- Q_ASSERT(qFuzzyCompare(delta.x() + 1, static_cast<qreal>(1))
- || qFuzzyCompare(delta.y() + 1, static_cast<qreal>(1)));
+ Q_ASSERT(qFuzzyIsNull(delta.x()) || qFuzzyIsNull(delta.y()));
tessellator.tessellateRect(first, last, width);
} else {
@@ -3573,7 +3365,7 @@ void QOpenGLPaintEnginePrivate::drawOffscreenPath(const QPainterPath &path)
disableClipping();
- GLuint program = qt_gl_program_cache()->getProgram(drawable.context(),
+ GLuint program = qt_gl_program_cache()->getProgram(device->context(),
FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA, 0, true);
QGLPathMaskGenerator maskGenerator(path, matrix, offscreen, program);
addItem(qt_mask_texture_cache()->getMask(maskGenerator, this));
@@ -3710,7 +3502,7 @@ void QOpenGLPaintEngine::drawRects(const QRectF *rects, int rectCount)
if (d->has_brush) {
d->disableClipping();
- GLuint program = qt_gl_program_cache()->getProgram(d->drawable.context(),
+ GLuint program = qt_gl_program_cache()->getProgram(d->device->context(),
FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA, 0, true);
if (d->matrix.type() >= QTransform::TxProject) {
@@ -3894,10 +3686,10 @@ void QOpenGLPaintEngine::drawLines(const QLineF *lines, int lineCount)
bool useRects = false;
// scale or 90 degree rotation?
if (d->matrix.type() <= QTransform::TxTranslate
- || !d->cpen.isCosmetic()
- && (d->matrix.type() <= QTransform::TxScale
- || (d->matrix.type() == QTransform::TxRotate
- && d->matrix.m11() == 0 && d->matrix.m22() == 0))) {
+ || (!d->cpen.isCosmetic()
+ && (d->matrix.type() <= QTransform::TxScale
+ || (d->matrix.type() == QTransform::TxRotate
+ && d->matrix.m11() == 0 && d->matrix.m22() == 0)))) {
useRects = true;
for (int i = 0; i < lineCount; ++i) {
if (lines[i].p1().x() != lines[i].p2().x()
@@ -4120,7 +3912,7 @@ void QOpenGLPaintEnginePrivate::strokeLines(const QPainterPath &path)
qreal penWidth = cpen.widthF();
- GLuint program = qt_gl_program_cache()->getProgram(drawable.context(),
+ GLuint program = qt_gl_program_cache()->getProgram(device->context(),
FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA, 0, true);
QGLLineMaskGenerator maskGenerator(path, matrix, penWidth == 0 ? 1.0 : penWidth,
offscreen, program);
@@ -4410,8 +4202,7 @@ void QOpenGLPaintEnginePrivate::drawImageAsPath(const QRectF &r, const QImage &i
qreal scaleX = r.width() / sr.width();
qreal scaleY = r.height() / sr.height();
- QTransform brush_matrix;
- brush_matrix.translate(r.left(), r.top());
+ QTransform brush_matrix = QTransform::fromTranslate(r.left(), r.top());
brush_matrix.scale(scaleX, scaleY);
brush_matrix.translate(-sr.left(), -sr.top());
@@ -4433,8 +4224,7 @@ void QOpenGLPaintEnginePrivate::drawTiledImageAsPath(const QRectF &r, const QIma
QBrush old_brush = cbrush;
QPointF old_brush_origin = brush_origin;
- QTransform brush_matrix;
- brush_matrix.translate(r.left(), r.top());
+ QTransform brush_matrix = QTransform::fromTranslate(r.left(), r.top());
brush_matrix.scale(sx, sy);
brush_matrix.translate(-offset.x(), -offset.y());
@@ -4508,14 +4298,26 @@ void QOpenGLPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QR
else {
GLenum target = qt_gl_preferredTextureTarget();
d->flushDrawQueue();
- d->drawable.bindTexture(pm, target);
- drawTextureRect(pm.width(), pm.height(), r, sr, target);
+ QGLTexture *tex =
+ d->device->context()->d_func()->bindTexture(pm, target, GL_RGBA,
+ QGLContext::InternalBindOption);
+ drawTextureRect(pm.width(), pm.height(), r, sr, target, tex);
}
}
void QOpenGLPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &offset)
{
Q_D(QOpenGLPaintEngine);
+ if (pm.depth() == 1) {
+ QPixmap tpx(pm.size());
+ tpx.fill(Qt::transparent);
+ QPainter p(&tpx);
+ p.setPen(d->cpen);
+ p.drawPixmap(0, 0, pm);
+ p.end();
+ drawTiledPixmap(r, tpx, offset);
+ return;
+ }
QImage scaled;
const int sz = d->max_texture_size;
@@ -4541,10 +4343,13 @@ void QOpenGLPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, con
} else {
d->flushDrawQueue();
+ QGLTexture *tex;
if (scaled.isNull())
- d->drawable.bindTexture(pm);
+ tex = d->device->context()->d_func()->bindTexture(pm, GL_TEXTURE_2D, GL_RGBA,
+ QGLContext::InternalBindOption);
else
- d->drawable.bindTexture(scaled);
+ tex = d->device->context()->d_func()->bindTexture(scaled, GL_TEXTURE_2D, GL_RGBA,
+ QGLContext::InternalBindOption);
updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, d->use_smooth_pixmap_transform);
#ifndef QT_OPENGL_ES
@@ -4559,10 +4364,12 @@ void QOpenGLPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, con
// Rotate the texture so that it is aligned correctly and the
// wrapping is done correctly
- glMatrixMode(GL_TEXTURE);
- glPushMatrix();
- glRotatef(180.0, 0.0, 1.0, 0.0);
- glRotatef(180.0, 0.0, 0.0, 1.0);
+ if (tex->options & QGLContext::InvertedYBindOption) {
+ glMatrixMode(GL_TEXTURE);
+ glPushMatrix();
+ glRotatef(180.0, 0.0, 1.0, 0.0);
+ glRotatef(180.0, 0.0, 0.0, 1.0);
+ }
q_vertexType vertexArray[4*2];
q_vertexType texCoordArray[4*2];
@@ -4582,7 +4389,8 @@ void QOpenGLPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, con
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
- glPopMatrix();
+ if (tex->options & QGLContext::InvertedYBindOption)
+ glPopMatrix();
glDisable(GL_TEXTURE_2D);
#ifndef QT_OPENGL_ES
@@ -4618,13 +4426,15 @@ void QOpenGLPaintEngine::drawImage(const QRectF &r, const QImage &image, const Q
else {
GLenum target = qt_gl_preferredTextureTarget();
d->flushDrawQueue();
- d->drawable.bindTexture(image, target);
- drawTextureRect(image.width(), image.height(), r, sr, target);
+ QGLTexture *tex =
+ d->device->context()->d_func()->bindTexture(image, target, GL_RGBA,
+ QGLContext::InternalBindOption);
+ drawTextureRect(image.width(), image.height(), r, sr, target, tex);
}
}
void QOpenGLPaintEngine::drawTextureRect(int tx_width, int tx_height, const QRectF &r,
- const QRectF &sr, GLenum target)
+ const QRectF &sr, GLenum target, QGLTexture *tex)
{
Q_D(QOpenGLPaintEngine);
#ifndef QT_OPENGL_ES
@@ -4639,13 +4449,18 @@ void QOpenGLPaintEngine::drawTextureRect(int tx_width, int tx_height, const QRec
if (target == GL_TEXTURE_2D) {
x1 = sr.x() / tx_width;
x2 = x1 + sr.width() / tx_width;
- y1 = 1.0 - (sr.bottom() / tx_height);
- y2 = 1.0 - (sr.y() / tx_height);
+ if (tex->options & QGLContext::InvertedYBindOption) {
+ y1 = 1 - (sr.bottom() / tx_height);
+ y2 = 1 - (sr.y() / tx_height);
+ } else {
+ y1 = sr.bottom() / tx_height;
+ y2 = sr.y() / tx_height;
+ }
} else {
x1 = sr.x();
x2 = sr.right();
- y1 = tx_height - sr.bottom();
- y2 = tx_height - sr.y();
+ y1 = sr.bottom();
+ y2 = sr.y();
}
q_vertexType vertexArray[4*2];
@@ -4884,7 +4699,7 @@ void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti,
QList<const QGLContext *> contexts = qt_context_cache.keys();
for (int i=0; i<contexts.size(); ++i) {
const QGLContext *ctx = contexts.at(i);
- if (ctx != context && qgl_share_reg()->checkSharing(context, ctx)) {
+ if (ctx != context && QGLContext::areSharing(context, ctx)) {
context_key = ctx;
dev_it = qt_context_cache.constFind(context_key);
break;
@@ -4901,8 +4716,8 @@ void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti,
QWidget *widget = static_cast<QWidget *>(context->device());
connect(widget, SIGNAL(destroyed(QObject*)), SLOT(widgetDestroyed(QObject*)));
connect(QGLSignalProxy::instance(),
- SIGNAL(aboutToDestroyContext(const QGLContext *)),
- SLOT(cleanupContext(const QGLContext *)));
+ SIGNAL(aboutToDestroyContext(const QGLContext*)),
+ SLOT(cleanupContext(const QGLContext*)));
}
} else {
font_cache = dev_it.value();
@@ -4991,7 +4806,8 @@ void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti,
}
}
- QImage glyph_im(ti.fontEngine->alphaMapForGlyph(glyphs[i]).convertToFormat(QImage::Format_Indexed8));
+ QImage glyph_im(ti.fontEngine->alphaMapForGlyph(glyphs[i]));
+ glyph_im = glyph_im.convertToFormat(QImage::Format_Indexed8);
glyph_width = glyph_im.width();
Q_ASSERT(glyph_width >= 0);
// pad the glyph width to an even number
@@ -5089,12 +4905,11 @@ void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
// add the glyphs used to the glyph texture cache
QVarLengthArray<QFixedPoint> positions;
QVarLengthArray<glyph_t> glyphs;
- QTransform matrix;
- matrix.translate(qRound(p.x()), qRound(p.y()));
+ QTransform matrix = QTransform::fromTranslate(qRound(p.x()), qRound(p.y()));
ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
// make sure the glyphs we want to draw are in the cache
- qt_glyph_cache()->cacheGlyphs(d->drawable.context(), ti, glyphs);
+ qt_glyph_cache()->cacheGlyphs(d->device->context(), ti, glyphs);
d->setGradientOps(Qt::SolidPattern, QRectF()); // turns off gradient ops
qt_glColor4ubv(d->pen_color);
@@ -5172,7 +4987,7 @@ void QOpenGLPaintEngine::drawEllipse(const QRectF &rect)
glPushMatrix();
glLoadIdentity();
- GLuint program = qt_gl_program_cache()->getProgram(d->drawable.context(),
+ GLuint program = qt_gl_program_cache()->getProgram(d->device->context(),
FRAGMENT_PROGRAM_MASK_ELLIPSE_AA, 0, true);
QGLEllipseMaskGenerator maskGenerator(rect,
d->matrix,
@@ -5307,10 +5122,10 @@ void QOpenGLPaintEnginePrivate::copyDrawable(const QRectF &rect)
QRectF screen_rect = rect.adjusted(-1, -1, 1, 1);
int left = qMax(0, static_cast<int>(screen_rect.left()));
- int width = qMin(drawable.size().width() - left, static_cast<int>(screen_rect.width()) + 1);
+ int width = qMin(device->size().width() - left, static_cast<int>(screen_rect.width()) + 1);
- int bottom = qMax(0, static_cast<int>(drawable.size().height() - screen_rect.bottom()));
- int height = qMin(drawable.size().height() - bottom, static_cast<int>(screen_rect.height()) + 1);
+ int bottom = qMax(0, static_cast<int>(device->size().height() - screen_rect.bottom()));
+ int height = qMin(device->size().height() - bottom, static_cast<int>(screen_rect.height()) + 1);
glBindTexture(GL_TEXTURE_2D, drawable_texture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, left, bottom, left, bottom, width, height);
@@ -5404,9 +5219,12 @@ void QOpenGLPaintEnginePrivate::composite(GLuint primitive, const q_vertexType *
glActiveTexture(GL_TEXTURE0 + brush_texture_location);
if (current_style == Qt::TexturePattern)
- drawable.bindTexture(cbrush.textureImage());
+ device->context()->d_func()->bindTexture(cbrush.textureImage(), GL_TEXTURE_2D, GL_RGBA,
+ QGLContext::InternalBindOption);
else
- drawable.bindTexture(qt_imageForBrush(current_style, true));
+ device->context()->d_func()->bindTexture(qt_imageForBrush(current_style, false),
+ GL_TEXTURE_2D, GL_RGBA,
+ QGLContext::InternalBindOption);
updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, use_smooth_pixmap_transform);
}
@@ -5414,7 +5232,7 @@ void QOpenGLPaintEnginePrivate::composite(GLuint primitive, const q_vertexType *
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, q_vertexTypeEnum, 0, vertexArray);
glEnable(GL_FRAGMENT_PROGRAM_ARB);
- GLuint program = qt_gl_program_cache()->getProgram(drawable.context(),
+ GLuint program = qt_gl_program_cache()->getProgram(device->context(),
fragment_brush,
fragment_composition_mode, false);
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, program);
@@ -5486,7 +5304,7 @@ void QOpenGLPaintEnginePrivate::drawItem(const QDrawQueueItem &item)
setGradientOps(item.brush, item.location.screen_rect);
composite(item.location.screen_rect, item.location.rect.topLeft() - item.location.screen_rect.topLeft()
- - QPoint(0, offscreen.offscreenSize().height() - drawable.size().height()));
+ - QPoint(0, offscreen.offscreenSize().height() - device->size().height()));
}
void QOpenGLPaintEnginePrivate::flushDrawQueue()
@@ -5635,7 +5453,7 @@ void QOpenGLPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
QPainter *p = painter();
QBrush oldBrush = p->brush();
p->setBrush(brush);
- qt_draw_helper(p->d_ptr, painterPathFromVectorPath(path), QPainterPrivate::FillDraw);
+ qt_draw_helper(p->d_ptr.data(), painterPathFromVectorPath(path), QPainterPrivate::FillDraw);
p->setBrush(oldBrush);
return;
}
@@ -5724,9 +5542,20 @@ void QOpenGLPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
void QOpenGLPaintEngine::setState(QPainterState *s)
{
Q_D(QOpenGLPaintEngine);
+ QOpenGLPaintEngineState *new_state = static_cast<QOpenGLPaintEngineState *>(s);
+ QOpenGLPaintEngineState *old_state = state();
+
QPaintEngineEx::setState(s);
+
+ // are we in a save() ?
+ if (s == d->last_created_state) {
+ d->last_created_state = 0;
+ return;
+ }
+
if (isActive()) {
- d->updateDepthClip();
+ if (old_state->depthClipId != new_state->depthClipId)
+ d->updateDepthClip();
penChanged();
brushChanged();
opacityChanged();
@@ -5738,12 +5567,15 @@ void QOpenGLPaintEngine::setState(QPainterState *s)
QPainterState *QOpenGLPaintEngine::createState(QPainterState *orig) const
{
+ const Q_D(QOpenGLPaintEngine);
+
QOpenGLPaintEngineState *s;
if (!orig)
s = new QOpenGLPaintEngineState();
else
s = new QOpenGLPaintEngineState(*static_cast<QOpenGLPaintEngineState *>(orig));
+ d->last_created_state = s;
return s;
}
@@ -5757,11 +5589,13 @@ QOpenGLPaintEngineState::QOpenGLPaintEngineState(QOpenGLPaintEngineState &other)
clipRegion = other.clipRegion;
hasClipping = other.hasClipping;
fastClip = other.fastClip;
+ depthClipId = other.depthClipId;
}
QOpenGLPaintEngineState::QOpenGLPaintEngineState()
{
hasClipping = false;
+ depthClipId = 0;
}
QOpenGLPaintEngineState::~QOpenGLPaintEngineState()
@@ -5791,15 +5625,6 @@ void QOpenGLPaintEnginePrivate::ensureDrawableTexture()
#endif
}
-QPixmapFilter *QOpenGLPaintEngine::createPixmapFilter(int type) const
-{
- if (QGLContext::currentContext())
- return QGLContext::currentContext()->d_func()->createPixmapFilter(type);
- else
- return 0;
-}
-
-
QT_END_NAMESPACE
#include "qpaintengine_opengl.moc"
diff --git a/src/opengl/qpaintengine_opengl_p.h b/src/opengl/qpaintengine_opengl_p.h
index 41dacd9..4fea638 100644
--- a/src/opengl/qpaintengine_opengl_p.h
+++ b/src/opengl/qpaintengine_opengl_p.h
@@ -58,6 +58,7 @@
QT_BEGIN_NAMESPACE
class QOpenGLPaintEnginePrivate;
+class QGLTexture;
class QOpenGLPaintEngineState : public QPainterState
{
@@ -69,6 +70,7 @@ public:
QRegion clipRegion;
bool hasClipping;
QRect fastClip;
+ uint depthClipId;
};
class QOpenGLPaintEngine : public QPaintEngineEx
@@ -134,8 +136,6 @@ public:
void drawEllipse(const QRectF &rect);
- QPixmapFilter *createPixmapFilter(int type) const;
-
#ifdef Q_WS_WIN
HDC handle() const;
#else
@@ -145,7 +145,8 @@ public:
private:
void drawPolyInternal(const QPolygonF &pa, bool close = true);
- void drawTextureRect(int tx_width, int tx_height, const QRectF &r, const QRectF &sr, GLenum target);
+ void drawTextureRect(int tx_width, int tx_height, const QRectF &r, const QRectF &sr,
+ GLenum target, QGLTexture *tex);
Q_DISABLE_COPY(QOpenGLPaintEngine)
};
diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp
index edf7eb8..92c990b 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>
@@ -47,118 +48,265 @@
#include <private/qgl_p.h>
#include <private/qdrawhelper_p.h>
+#include <private/qimage_p.h>
+
+#include <private/qpaintengineex_opengl2_p.h>
+
+#include <qdesktopwidget.h>
+#include <qfile.h>
+#include <qimagereader.h>
QT_BEGIN_NAMESPACE
extern QGLWidget* qt_gl_share_widget();
-class QGLShareContextScope
-{
-public:
- QGLShareContextScope(const QGLContext *ctx)
- : m_oldContext(0)
- , m_ctx(const_cast<QGLContext *>(ctx))
- {
- const QGLContext *currentContext = QGLContext::currentContext();
- if (currentContext != ctx && !qgl_share_reg()->checkSharing(ctx, currentContext)) {
- m_oldContext = const_cast<QGLContext *>(currentContext);
- m_ctx->makeCurrent();
+/*!
+ \class QGLFramebufferObjectPool
+ \since 4.6
+
+ \brief The QGLFramebufferObject class provides a pool of framebuffer
+ objects for offscreen rendering purposes.
+
+ When requesting an FBO of a given size and format, an FBO of the same
+ format and a size at least as big as the requested size will be returned.
+
+ \internal
+*/
+
+static inline int areaDiff(const QSize &size, const QGLFramebufferObject *fbo)
+{
+ return qAbs(size.width() * size.height() - fbo->width() * fbo->height());
+}
+
+extern int qt_next_power_of_two(int v);
+
+static inline QSize maybeRoundToNextPowerOfTwo(const QSize &sz)
+{
+#ifdef QT_OPENGL_ES_2
+ QSize rounded(qt_next_power_of_two(sz.width()), qt_next_power_of_two(sz.height()));
+ if (rounded.width() * rounded.height() < 1.20 * sz.width() * sz.height())
+ return rounded;
+#endif
+ return sz;
+}
+
+
+QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize, const QGLFramebufferObjectFormat &requestFormat, bool strictSize)
+{
+ QGLFramebufferObject *chosen = 0;
+ QGLFramebufferObject *candidate = 0;
+ for (int i = 0; !chosen && i < m_fbos.size(); ++i) {
+ QGLFramebufferObject *fbo = m_fbos.at(i);
+
+ if (strictSize) {
+ if (fbo->size() == requestSize && fbo->format() == requestFormat) {
+ chosen = fbo;
+ break;
+ } else {
+ continue;
+ }
}
- }
- operator QGLContext *()
- {
- return m_ctx;
+ if (fbo->format() == requestFormat) {
+ // choose the fbo with a matching format and the closest size
+ if (!candidate || areaDiff(requestSize, candidate) > areaDiff(requestSize, fbo))
+ candidate = fbo;
+ }
+
+ if (candidate) {
+ m_fbos.removeOne(candidate);
+
+ const QSize fboSize = candidate->size();
+ QSize sz = fboSize;
+
+ if (sz.width() < requestSize.width())
+ sz.setWidth(qMax(requestSize.width(), qRound(sz.width() * 1.5)));
+ if (sz.height() < requestSize.height())
+ sz.setHeight(qMax(requestSize.height(), qRound(sz.height() * 1.5)));
+
+ // wasting too much space?
+ if (sz.width() * sz.height() > requestSize.width() * requestSize.height() * 4)
+ sz = requestSize;
+
+ if (sz != fboSize) {
+ delete candidate;
+ candidate = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(sz), requestFormat);
+ }
+
+ chosen = candidate;
+ }
}
- QGLContext *operator->()
- {
- return m_ctx;
+ if (!chosen) {
+ if (strictSize)
+ chosen = new QGLFramebufferObject(requestSize, requestFormat);
+ else
+ chosen = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(requestSize), requestFormat);
}
- ~QGLShareContextScope()
- {
- if (m_oldContext)
- m_oldContext->makeCurrent();
+ if (!chosen->isValid()) {
+ delete chosen;
+ chosen = 0;
}
-private:
- QGLContext *m_oldContext;
- QGLContext *m_ctx;
-};
+ return chosen;
+}
-void qt_gl_convertFromGLImage(QImage *img)
+void QGLFramebufferObjectPool::release(QGLFramebufferObject *fbo)
{
- const int w = img->width();
- const int h = img->height();
+ if (fbo)
+ m_fbos << fbo;
+}
- 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++;
- }
+QPaintEngine* QGLPixmapGLPaintDevice::paintEngine() const
+{
+ return data->paintEngine();
+}
- *img = img->mirrored();
- } else {
- // mirror image
- uint *data = (uint *)img->bits();
+void QGLPixmapGLPaintDevice::beginPaint()
+{
+ if (!data->isValid())
+ return;
- const int mid = h/2;
+ // QGLPaintDevice::beginPaint will store the current binding and replace
+ // it with m_thisFBO:
+ m_thisFBO = data->m_renderFbo->handle();
+ QGLPaintDevice::beginPaint();
- for (int y = 0; y < mid; ++y) {
- uint *p = data + y * w;
- uint *end = p + w;
- uint *q = data + (h - y - 1) * w;
+ Q_ASSERT(data->paintEngine()->type() == QPaintEngine::OpenGL2);
- while (p < end)
- qSwap(*p++, *q++);
- }
+ // QPixmap::fill() is deferred until now, where we actually need to do the fill:
+ if (data->needsFill()) {
+ const QColor &c = data->fillColor();
+ float alpha = c.alphaF();
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+ else if (!data->isUninitialized()) {
+ // If the pixmap (GL Texture) has valid content (it has been
+ // uploaded from an image or rendered into before), we need to
+ // copy it from the texture to the render FBO.
+
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_BLEND);
+
+#if !defined(QT_OPENGL_ES_2)
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, data->width(), data->height(), 0, -999999, 999999);
+#endif
+
+ glViewport(0, 0, data->width(), data->height());
+
+ // Pass false to bind so it doesn't copy the FBO into the texture!
+ context()->drawTexture(QRect(0, 0, data->width(), data->height()), data->bind(false));
}
}
+void QGLPixmapGLPaintDevice::endPaint()
+{
+ if (!data->isValid())
+ return;
+
+ data->copyBackFromRenderFbo(false);
+
+ // Base's endPaint will restore the previous FBO binding
+ QGLPaintDevice::endPaint();
+
+ qgl_fbo_pool()->release(data->m_renderFbo);
+ data->m_renderFbo = 0;
+}
+
+QGLContext* QGLPixmapGLPaintDevice::context() const
+{
+ data->ensureCreated();
+ return data->m_ctx;
+}
+
+QSize QGLPixmapGLPaintDevice::size() const
+{
+ return data->size();
+}
+
+void QGLPixmapGLPaintDevice::setPixmapData(QGLPixmapData* d)
+{
+ data = d;
+}
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_engine(0)
+ , m_ctx(0)
, m_dirty(false)
+ , m_hasFillColor(false)
+ , m_hasAlpha(false)
{
setSerialNumber(++qt_gl_pixmap_serial);
+ m_glDevice.setPixmapData(this);
}
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;
+
+ delete m_engine;
+
+ if (m_texture.id) {
+ QGLShareContextScope ctx(shareWidget->context());
+ glDeleteTextures(1, &m_texture.id);
}
}
+QPixmapData *QGLPixmapData::createCompatiblePixmapData() const
+{
+ return new QGLPixmapData(pixelType());
+}
+
bool QGLPixmapData::isValid() const
{
- return m_width > 0 && m_height > 0;
+ return w > 0 && h > 0;
}
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);
+ return ctx == share_ctx || QGLContext::areSharing(ctx, share_ctx);
}
void QGLPixmapData::resize(int width, int height)
{
- if (width == m_width && height == m_height)
+ if (width == w && height == h)
return;
- m_width = width;
- m_height = height;
+ if (width <= 0 || height <= 0) {
+ width = 0;
+ height = 0;
+ }
+
+ w = width;
+ h = height;
+ is_null = (w <= 0 || h <= 0);
+ d = pixelType() == QPixmapData::PixmapType ? 32 : 1;
+
+ if (m_texture.id) {
+ QGLShareContextScope ctx(qt_gl_share_widget()->context());
+ glDeleteTextures(1, &m_texture.id);
+ m_texture.id = 0;
+ }
m_source = QImage();
m_dirty = isValid();
@@ -173,36 +321,157 @@ 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_source.isNull()) {
- glTexImage2D(target, 0, GL_RGBA, m_width, m_height, 0, format, GL_UNSIGNED_BYTE, 0);
- } else {
- const QImage tx = ctx->d_func()->convertToGLFormat(m_source, true, format);
+ const GLenum internal_format = m_hasAlpha ? GL_RGBA : GL_RGB;
+#ifdef QT_OPENGL_ES_2
+ const GLenum external_format = internal_format;
+#else
+ const GLenum external_format = qt_gl_preferredTextureFormat();
+#endif
+ const GLenum target = GL_TEXTURE_2D;
+
+ if (!m_texture.id) {
+ glGenTextures(1, &m_texture.id);
+ glBindTexture(target, m_texture.id);
+ glTexImage2D(target, 0, internal_format, w, h, 0, external_format, GL_UNSIGNED_BYTE, 0);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
- glBindTexture(target, m_texture);
- glTexImage2D(target, 0, GL_RGBA, m_width, m_height, 0, format,
- GL_UNSIGNED_BYTE, tx.bits());
+ if (!m_source.isNull()) {
+ if (external_format == GL_RGB) {
+ const QImage tx = m_source.convertToFormat(QImage::Format_RGB888);
+
+ glBindTexture(target, m_texture.id);
+ glTexSubImage2D(target, 0, 0, 0, w, h, external_format,
+ GL_UNSIGNED_BYTE, tx.bits());
+ } else {
+ const QImage tx = ctx->d_func()->convertToGLFormat(m_source, true, external_format);
+
+ glBindTexture(target, m_texture.id);
+ glTexSubImage2D(target, 0, 0, 0, w, h, external_format,
+ GL_UNSIGNED_BYTE, tx.bits());
+ }
- m_source = QImage();
+ if (useFramebufferObjects())
+ m_source = QImage();
}
+
+ m_texture.options &= ~QGLContext::MemoryManagedBindOption;
}
void QGLPixmapData::fromImage(const QImage &image,
- Qt::ImageConversionFlags)
+ Qt::ImageConversionFlags /*flags*/)
{
- if (image.size() == QSize(m_width, m_height))
+ if (image.size() == QSize(w, h))
setSerialNumber(++qt_gl_pixmap_serial);
resize(image.width(), image.height());
- m_source = image;
+
+ if (pixelType() == BitmapType) {
+ m_source = image.convertToFormat(QImage::Format_MonoLSB);
+
+ } else {
+ QImage::Format format = QImage::Format_RGB32;
+ if (qApp->desktop()->depth() == 16)
+ format = QImage::Format_RGB16;
+
+ if (image.hasAlphaChannel() && const_cast<QImage &>(image).data_ptr()->checkForAlphaPixels())
+ format = QImage::Format_ARGB32_Premultiplied;;
+
+ m_source = image.convertToFormat(format);
+ }
+
m_dirty = true;
+ m_hasFillColor = false;
+
+ m_hasAlpha = m_source.hasAlphaChannel();
+ w = image.width();
+ h = image.height();
+ is_null = (w <= 0 || h <= 0);
+ d = m_source.depth();
+
+ if (m_texture.id) {
+ QGLShareContextScope ctx(qt_gl_share_widget()->context());
+ glDeleteTextures(1, &m_texture.id);
+ m_texture.id = 0;
+ }
+}
+
+bool QGLPixmapData::fromFile(const QString &filename, const char *format,
+ Qt::ImageConversionFlags flags)
+{
+ if (pixelType() == QPixmapData::BitmapType)
+ return QPixmapData::fromFile(filename, format, flags);
+ QFile file(filename);
+ if (!file.open(QIODevice::ReadOnly))
+ return false;
+ QByteArray data = file.peek(64);
+ bool alpha;
+ if (m_texture.canBindCompressedTexture
+ (data.constData(), data.size(), format, &alpha)) {
+ resize(0, 0);
+ data = file.readAll();
+ file.close();
+ QGLShareContextScope ctx(qt_gl_share_widget()->context());
+ QSize size = m_texture.bindCompressedTexture
+ (data.constData(), data.size(), format);
+ if (!size.isEmpty()) {
+ w = size.width();
+ h = size.height();
+ is_null = false;
+ d = 32;
+ m_hasAlpha = alpha;
+ m_source = QImage();
+ m_dirty = isValid();
+ return true;
+ }
+ return false;
+ }
+ fromImage(QImageReader(&file, format).read(), flags);
+ return !isNull();
+}
+
+bool QGLPixmapData::fromData(const uchar *buffer, uint len, const char *format,
+ Qt::ImageConversionFlags flags)
+{
+ bool alpha;
+ const char *buf = reinterpret_cast<const char *>(buffer);
+ if (m_texture.canBindCompressedTexture(buf, int(len), format, &alpha)) {
+ resize(0, 0);
+ QGLShareContextScope ctx(qt_gl_share_widget()->context());
+ QSize size = m_texture.bindCompressedTexture(buf, int(len), format);
+ if (!size.isEmpty()) {
+ w = size.width();
+ h = size.height();
+ is_null = false;
+ d = 32;
+ m_hasAlpha = alpha;
+ m_source = QImage();
+ m_dirty = isValid();
+ return true;
+ }
+ }
+ return QPixmapData::fromData(buffer, len, format, flags);
+}
+
+bool QGLPixmapData::scroll(int dx, int dy, const QRect &rect)
+{
+ Q_UNUSED(dx);
+ Q_UNUSED(dy);
+ Q_UNUSED(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)
@@ -210,50 +479,148 @@ void QGLPixmapData::fill(const QColor &color)
if (!isValid())
return;
- if (!m_source.isNull()) {
- m_source.fill(PREMUL(color.rgba()));
+ bool hasAlpha = color.alpha() != 255;
+ if (hasAlpha && !m_hasAlpha) {
+ if (m_texture.id) {
+ glDeleteTextures(1, &m_texture.id);
+ m_texture.id = 0;
+ m_dirty = true;
+ }
+ m_hasAlpha = color.alpha() != 255;
+ }
+
+ if (useFramebufferObjects()) {
+ m_source = QImage();
+ m_hasFillColor = true;
+ m_fillColor = color;
} else {
- // ## TODO: improve performance here
- QImage img(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
- img.fill(PREMUL(color.rgba()));
- fromImage(img, 0);
+ if (m_source.isNull()) {
+ m_fillColor = color;
+ m_hasFillColor = true;
+
+ } else if (m_source.depth() == 32) {
+ m_source.fill(PREMUL(color.rgba()));
+
+ } else if (m_source.depth() == 1) {
+ if (color == Qt::color1)
+ m_source.fill(1);
+ else
+ m_source.fill(0);
+ }
}
}
bool QGLPixmapData::hasAlphaChannel() const
{
- return true;
+ return m_hasAlpha;
+}
+
+QImage QGLPixmapData::fillImage(const QColor &color) const
+{
+ QImage img;
+ if (pixelType() == BitmapType) {
+ img = QImage(w, h, QImage::Format_MonoLSB);
+
+ img.setColorCount(2);
+ img.setColor(0, QColor(Qt::color0).rgba());
+ img.setColor(1, QColor(Qt::color1).rgba());
+
+ if (color == Qt::color1)
+ img.fill(1);
+ else
+ img.fill(0);
+ } else {
+ img = QImage(w, h,
+ m_hasAlpha
+ ? QImage::Format_ARGB32_Premultiplied
+ : QImage::Format_RGB32);
+ img.fill(PREMUL(color.rgba()));
+ }
+ return img;
}
+extern QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha);
+
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 if (m_dirty || m_hasFillColor) {
+ return fillImage(m_fillColor);
+ } else {
+ ensureCreated();
+ }
+
+ QGLShareContextScope ctx(qt_gl_share_widget()->context());
+ glBindTexture(GL_TEXTURE_2D, m_texture.id);
+ return qt_gl_read_texture(QSize(w, h), true, true);
+}
+
+struct TextureBuffer
+{
+ QGLFramebufferObject *fbo;
+ QGL2PaintEngineEx *engine;
+};
+
+Q_GLOBAL_STATIC(QGLFramebufferObjectPool, _qgl_fbo_pool)
+QGLFramebufferObjectPool* qgl_fbo_pool()
+{
+ return _qgl_fbo_pool();
+}
+
+void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const
+{
+ if (!isValid())
+ return;
+
+ m_hasFillColor = false;
+
+ 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)
+ glGenFramebuffers(1, &ctx->d_ptr->fbo);
- GLenum format = qt_gl_preferredTextureFormat();
- GLenum target = qt_gl_preferredTextureTarget();
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, ctx->d_ptr->fbo);
+ glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, m_texture.id, 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 = w;
+ const int y0 = 0;
+ const int y1 = h;
- qt_gl_convertFromGLImage(&img);
+ if (!m_renderFbo->isBound())
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, m_renderFbo->handle());
- return img;
+ glDisable(GL_SCISSOR_TEST);
+
+ glBlitFramebufferEXT(x0, y0, x1, y1,
+ x0, y0, x1, y1,
+ GL_COLOR_BUFFER_BIT,
+ GL_NEAREST);
+
+ if (keepCurrentFboBound) {
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
+ } else {
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, m_renderFbo->handle());
+ ctx->d_ptr->current_fbo = m_renderFbo->handle();
+ }
+}
+
+bool QGLPixmapData::useFramebufferObjects()
+{
+ return QGLFramebufferObject::hasOpenGLFramebufferObjects()
+ && QGLFramebufferObject::hasOpenGLFramebufferBlit()
+ && qt_gl_preferGL2Engine();
}
QPaintEngine* QGLPixmapData::paintEngine() const
@@ -261,23 +628,78 @@ QPaintEngine* QGLPixmapData::paintEngine() const
if (!isValid())
return 0;
- m_source = toImage();
- m_dirty = true;
+ if (m_renderFbo)
+ return m_engine;
+
+ if (useFramebufferObjects()) {
+ extern QGLWidget* qt_gl_share_widget();
+
+ if (!QGLContext::currentContext())
+ qt_gl_share_widget()->makeCurrent();
+ QGLShareContextScope ctx(qt_gl_share_widget()->context());
+
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ format.setSamples(4);
+ format.setInternalTextureFormat(GLenum(m_hasAlpha ? GL_RGBA : GL_RGB));
+
+ m_renderFbo = qgl_fbo_pool()->acquire(size(), format);
+ if (m_renderFbo) {
+ if (!m_engine)
+ m_engine = new QGL2PaintEngineEx;
+ return m_engine;
+ }
+
+ qWarning() << "Failed to create pixmap texture buffer of size " << size() << ", falling back to raster paint engine";
+ }
+
+ m_dirty = true;
+ if (m_source.size() != size())
+ m_source = QImage(size(), QImage::Format_ARGB32_Premultiplied);
+ if (m_hasFillColor) {
+ m_source.fill(PREMUL(m_fillColor.rgba()));
+ m_hasFillColor = false;
+ }
return m_source.paintEngine();
}
-GLuint QGLPixmapData::bind() const
+extern QRgb qt_gl_convertToGLFormat(QRgb src_pixel, GLenum texture_format);
+
+// If copyBack is true, bind will copy the contents of the render
+// FBO to the texture (which is not bound to the texture, as it's
+// a multisample FBO).
+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_texture.id;
+ glBindTexture(GL_TEXTURE_2D, id);
+
+ if (m_hasFillColor) {
+ if (!useFramebufferObjects()) {
+ m_source = QImage(w, h, QImage::Format_ARGB32_Premultiplied);
+ m_source.fill(PREMUL(m_fillColor.rgba()));
+ }
+
+ m_hasFillColor = false;
+
+ GLenum format = qt_gl_preferredTextureFormat();
+ QImage tx(w, h, QImage::Format_ARGB32_Premultiplied);
+ tx.fill(qt_gl_convertToGLFormat(m_fillColor.rgba(), format));
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, format, GL_UNSIGNED_BYTE, tx.bits());
+ }
+
+ return id;
}
-GLuint QGLPixmapData::textureId() const
+QGLTexture* QGLPixmapData::texture() const
{
- ensureCreated();
- return m_texture;
+ return &m_texture;
}
extern int qt_defaultDpiX();
@@ -285,19 +707,22 @@ extern int qt_defaultDpiY();
int QGLPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
{
+ if (w == 0)
+ return 0;
+
switch (metric) {
case QPaintDevice::PdmWidth:
- return m_width;
+ return w;
case QPaintDevice::PdmHeight:
- return m_height;
+ return h;
case QPaintDevice::PdmNumColors:
return 0;
case QPaintDevice::PdmDepth:
- return pixelType() == QPixmapData::PixmapType ? 32 : 1;
+ return d;
case QPaintDevice::PdmWidthMM:
- return qRound(m_width * 25.4 / qt_defaultDpiX());
+ return qRound(w * 25.4 / qt_defaultDpiX());
case QPaintDevice::PdmHeightMM:
- return qRound(m_height * 25.4 / qt_defaultDpiY());
+ return qRound(h * 25.4 / qt_defaultDpiY());
case QPaintDevice::PdmDpiX:
case QPaintDevice::PdmPhysicalDpiX:
return qt_defaultDpiX();
@@ -310,4 +735,9 @@ int QGLPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
}
}
+QGLPaintDevice *QGLPixmapData::glDevice() const
+{
+ return &m_glDevice;
+}
+
QT_END_NAMESPACE
diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h
index f053d92..007c52a 100644
--- a/src/opengl/qpixmapdata_gl_p.h
+++ b/src/opengl/qpixmapdata_gl_p.h
@@ -53,13 +53,47 @@
// We mean it.
//
+#include "qgl_p.h"
#include "qgl.h"
#include "private/qpixmapdata_p.h"
+#include "private/qglpaintdevice_p.h"
QT_BEGIN_NAMESPACE
class QPaintEngine;
+class QGLFramebufferObject;
+class QGLFramebufferObjectFormat;
+class QGLPixmapData;
+
+class QGLFramebufferObjectPool
+{
+public:
+ QGLFramebufferObject *acquire(const QSize &size, const QGLFramebufferObjectFormat &format, bool strictSize = false);
+ void release(QGLFramebufferObject *fbo);
+
+private:
+ QList<QGLFramebufferObject *> m_fbos;
+};
+
+QGLFramebufferObjectPool* qgl_fbo_pool();
+
+
+class QGLPixmapGLPaintDevice : public QGLPaintDevice
+{
+public:
+ QPaintEngine* paintEngine() const;
+
+ void beginPaint();
+ void endPaint();
+ QGLContext* context() const;
+ QSize size() const;
+
+ void setPixmapData(QGLPixmapData*);
+private:
+ QGLPixmapData *data;
+};
+
class QGLPixmapData : public QPixmapData
{
@@ -67,37 +101,72 @@ public:
QGLPixmapData(PixelType type);
~QGLPixmapData();
- bool isValid() const;
+ QPixmapData *createCompatiblePixmapData() const;
+ // Re-implemented from QPixmapData:
void resize(int width, int height);
- void fromImage(const QImage &image,
- Qt::ImageConversionFlags flags);
-
+ void fromImage(const QImage &image, Qt::ImageConversionFlags flags);
+ bool fromFile(const QString &filename, const char *format,
+ Qt::ImageConversionFlags flags);
+ bool fromData(const uchar *buffer, uint len, const char *format,
+ Qt::ImageConversionFlags flags);
+ void copy(const QPixmapData *data, const QRect &rect);
+ bool scroll(int dx, int dy, const QRect &rect);
void fill(const QColor &color);
bool hasAlphaChannel() const;
QImage toImage() const;
- QPaintEngine* paintEngine() const;
+ QPaintEngine *paintEngine() const;
+ int metric(QPaintDevice::PaintDeviceMetric metric) const;
- GLuint bind() const;
- GLuint textureId() const;
+ // For accessing as a target:
+ QGLPaintDevice *glDevice() const;
+ // For accessing as a source:
bool isValidContext(const QGLContext *ctx) const;
+ GLuint bind(bool copyBack = true) const;
+ QGLTexture *texture() const;
+
+private:
+ bool isValid() const;
void ensureCreated() const;
-protected:
- int metric(QPaintDevice::PaintDeviceMetric metric) const;
+ bool isUninitialized() const { return m_dirty && m_source.isNull(); }
+
+ bool needsFill() const { return m_hasFillColor; }
+ QColor fillColor() const { return m_fillColor; }
+
+
-private:
QGLPixmapData(const QGLPixmapData &other);
QGLPixmapData &operator=(const QGLPixmapData &other);
- int m_width;
- int m_height;
+ void copyBackFromRenderFbo(bool keepCurrentFboBound) const;
+ QSize size() const { return QSize(w, h); }
- mutable GLuint m_texture;
- mutable bool m_dirty;
+ static bool useFramebufferObjects();
+
+ QImage fillImage(const QColor &color) const;
+
+ mutable QGLFramebufferObject *m_renderFbo;
+ mutable QPaintEngine *m_engine;
+ mutable QGLContext *m_ctx;
mutable QImage m_source;
+ mutable QGLTexture m_texture;
+
+ // the texture is not in sync with the source image
+ mutable bool m_dirty;
+
+ // fill has been called and no painting has been done, so the pixmap is
+ // represented by a single fill color
+ mutable QColor m_fillColor;
+ mutable bool m_hasFillColor;
+
+ mutable bool m_hasAlpha;
+
+ mutable QGLPixmapGLPaintDevice m_glDevice;
+
+ friend class QGLPixmapGLPaintDevice;
};
QT_END_NAMESPACE
diff --git a/src/opengl/qpixmapdata_x11gl_egl.cpp b/src/opengl/qpixmapdata_x11gl_egl.cpp
new file mode 100644
index 0000000..813e6c8
--- /dev/null
+++ b/src/opengl/qpixmapdata_x11gl_egl.cpp
@@ -0,0 +1,252 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qgl_p.h>
+#include <private/qegl_p.h>
+#include <private/qeglproperties_p.h>
+#include <private/qpaintengineex_opengl2_p.h>
+
+#include "qpixmapdata_x11gl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+extern EGLConfig qt_chooseEGLConfigForPixmap(bool hasAlpha, bool readOnly); // in qgl_x11egl.cpp
+extern bool qt_createEGLSurfaceForPixmap(QPixmapData* pmd, bool readOnly); // in qgl_x11egl.cpp
+
+// On 16bpp systems, RGB & ARGB pixmaps are different bit-depths and therefore need
+// different contexts:
+static EGLContext qPixmapARGBSharedEglContext = EGL_NO_CONTEXT;
+static EGLContext qPixmapRGBSharedEglContext = EGL_NO_CONTEXT;
+
+bool QX11GLPixmapData::hasX11GLPixmaps()
+{
+ static bool checkedForX11Pixmaps = false;
+ static bool haveX11Pixmaps = false;
+
+ if (checkedForX11Pixmaps)
+ return haveX11Pixmaps;
+
+ checkedForX11Pixmaps = true;
+
+ QX11PixmapData *argbPixmapData = 0;
+ QX11PixmapData *rgbPixmapData = 0;
+ do {
+ if (qgetenv("QT_USE_X11GL_PIXMAPS").isEmpty())
+ break;
+
+ // Check we actually have EGL configs which support pixmaps
+ EGLConfig argbConfig = qt_chooseEGLConfigForPixmap(true, false);
+ EGLConfig rgbConfig = qt_chooseEGLConfigForPixmap(false, false);
+
+ if (argbConfig == 0 || rgbConfig == 0)
+ break;
+
+ // Create the shared contexts:
+ eglBindAPI(EGL_OPENGL_ES_API);
+ EGLint contextAttribs[] = {
+#if defined(QT_OPENGL_ES_2)
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+#endif
+ EGL_NONE
+ };
+ qPixmapARGBSharedEglContext = eglCreateContext(QEglContext::defaultDisplay(0),
+ argbConfig, 0, contextAttribs);
+
+ if (argbConfig == rgbConfig) {
+ // If the configs are the same, we can re-use the same context.
+ qPixmapRGBSharedEglContext = qPixmapARGBSharedEglContext;
+ } else {
+ qPixmapRGBSharedEglContext = eglCreateContext(QEglContext::defaultDisplay(0),
+ rgbConfig, 0, contextAttribs);
+ }
+
+ argbPixmapData = new QX11PixmapData(QPixmapData::PixmapType);
+ argbPixmapData->resize(100, 100);
+ argbPixmapData->fill(Qt::transparent); // Force ARGB
+
+ if (!qt_createEGLSurfaceForPixmap(argbPixmapData, false))
+ break;
+
+ haveX11Pixmaps = eglMakeCurrent(QEglContext::defaultDisplay(0),
+ (EGLSurface)argbPixmapData->gl_surface,
+ (EGLSurface)argbPixmapData->gl_surface,
+ qPixmapARGBSharedEglContext);
+ if (!haveX11Pixmaps) {
+ EGLint err = eglGetError();
+ qWarning() << "Unable to make pixmap config current:" << err << QEglContext::errorString(err);
+ break;
+ }
+
+ // If the ARGB & RGB configs are the same, we don't need to check RGB too
+ if (haveX11Pixmaps && (argbConfig != rgbConfig)) {
+ rgbPixmapData = new QX11PixmapData(QPixmapData::PixmapType);
+ rgbPixmapData->resize(100, 100);
+ rgbPixmapData->fill(Qt::red);
+
+ // Try to actually create an EGL pixmap surface
+ if (!qt_createEGLSurfaceForPixmap(rgbPixmapData, false))
+ break;
+
+ haveX11Pixmaps = eglMakeCurrent(QEglContext::defaultDisplay(0),
+ (EGLSurface)rgbPixmapData->gl_surface,
+ (EGLSurface)rgbPixmapData->gl_surface,
+ qPixmapRGBSharedEglContext);
+ if (!haveX11Pixmaps) {
+ EGLint err = eglGetError();
+ qWarning() << "Unable to make pixmap config current:" << err << QEglContext::errorString(err);
+ break;
+ }
+ }
+ } while (0);
+
+ if (qPixmapARGBSharedEglContext || qPixmapRGBSharedEglContext) {
+ eglMakeCurrent(QEglContext::defaultDisplay(0),
+ EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ }
+
+ if (argbPixmapData) {
+ if (argbPixmapData->gl_surface)
+ QGLContextPrivate::destroyGlSurfaceForPixmap(argbPixmapData);
+ delete argbPixmapData;
+ argbPixmapData = 0;
+ }
+ if (rgbPixmapData) {
+ if (rgbPixmapData->gl_surface)
+ QGLContextPrivate::destroyGlSurfaceForPixmap(rgbPixmapData);
+ delete rgbPixmapData;
+ rgbPixmapData = 0;
+ }
+
+ if (!haveX11Pixmaps) {
+ // Clean up the context(s) if we can't use X11GL pixmaps
+ if (qPixmapARGBSharedEglContext != EGL_NO_CONTEXT)
+ eglDestroyContext(QEglContext::defaultDisplay(0), qPixmapARGBSharedEglContext);
+
+ if (qPixmapRGBSharedEglContext != qPixmapARGBSharedEglContext &&
+ qPixmapRGBSharedEglContext != EGL_NO_CONTEXT)
+ {
+ eglDestroyContext(QEglContext::defaultDisplay(0), qPixmapRGBSharedEglContext);
+ }
+ qPixmapRGBSharedEglContext = EGL_NO_CONTEXT;
+ qPixmapARGBSharedEglContext = EGL_NO_CONTEXT;
+ }
+
+ if (haveX11Pixmaps)
+ qDebug("QX11GLPixmapData is supported");
+ else
+ qDebug("QX11GLPixmapData is *NOT* being used");
+
+ return haveX11Pixmaps;
+}
+
+QX11GLPixmapData::QX11GLPixmapData()
+ : QX11PixmapData(QPixmapData::PixmapType),
+ ctx(0)
+{
+}
+
+QX11GLPixmapData::~QX11GLPixmapData()
+{
+}
+
+static QGL2PaintEngineEx* qt_gl2_engine_for_pixmaps = 0;
+
+QPaintEngine* QX11GLPixmapData::paintEngine() const
+{
+ // We need to create the context before beginPaint - do it here:
+ if (!ctx) {
+ ctx = new QGLContext(glFormat());
+ if (ctx->d_func()->eglContext == 0)
+ ctx->d_func()->eglContext = new QEglContext();
+ ctx->d_func()->eglContext->openDisplay(0); // ;-)
+ ctx->d_func()->eglContext->setApi(QEgl::OpenGL);
+ ctx->d_func()->eglContext->setContext(hasAlphaChannel() ? qPixmapARGBSharedEglContext
+ : qPixmapRGBSharedEglContext);
+ }
+
+ if (!qt_gl2_engine_for_pixmaps)
+ qt_gl2_engine_for_pixmaps = new QGL2PaintEngineEx();
+
+ // Support multiple painters on multiple pixmaps simultaniously
+ if (qt_gl2_engine_for_pixmaps->isActive()) {
+ qWarning("Pixmap paint engine already active");
+ QPaintEngine* engine = new QGL2PaintEngineEx();
+ engine->setAutoDestruct(true);
+ return engine;
+ }
+
+ return qt_gl2_engine_for_pixmaps;
+}
+
+void QX11GLPixmapData::beginPaint()
+{
+// qDebug("QX11GLPixmapData::beginPaint()");
+ if ((EGLSurface)gl_surface == EGL_NO_SURFACE) {
+ qt_createEGLSurfaceForPixmap(this, false);
+ ctx->d_func()->eglSurface = (EGLSurface)gl_surface;
+ ctx->d_func()->valid = true; // ;-)
+ }
+ QGLPaintDevice::beginPaint();
+}
+
+void QX11GLPixmapData::endPaint()
+{
+ glFinish();
+ QGLPaintDevice::endPaint();
+}
+
+QGLContext* QX11GLPixmapData::context() const
+{
+ return ctx;
+}
+
+QSize QX11GLPixmapData::size() const
+{
+ return QSize(w, h);
+}
+
+
+QGLFormat QX11GLPixmapData::glFormat()
+{
+ return QGLFormat::defaultFormat(); //###
+}
+
+QT_END_NAMESPACE
diff --git a/src/opengl/qpixmapdata_x11gl_p.h b/src/opengl/qpixmapdata_x11gl_p.h
new file mode 100644
index 0000000..bba9bb3
--- /dev/null
+++ b/src/opengl/qpixmapdata_x11gl_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPIXMAPDATA_X11GL_P_H
+#define QPIXMAPDATA_X11GL_P_H
+
+//
+// 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 <private/qpixmapdata_p.h>
+#include <private/qpixmap_x11_p.h>
+#include <private/qglpaintdevice_p.h>
+
+#include <qgl.h>
+
+QT_BEGIN_NAMESPACE
+
+class QX11GLPixmapData : public QX11PixmapData, public QGLPaintDevice
+{
+public:
+ QX11GLPixmapData();
+ virtual ~QX11GLPixmapData();
+
+ // Re-implemented from QGLPaintDevice
+ QPaintEngine* paintEngine() const; // Also re-implements QX11PixmapData::paintEngine
+ void beginPaint();
+ void endPaint();
+ QGLContext* context() const;
+ QSize size() const;
+
+ static bool hasX11GLPixmaps();
+ static QGLFormat glFormat();
+private:
+ mutable QGLContext* ctx;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QPIXMAPDATA_X11GL_P_H
diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp
index 760b415..7194f9d 100644
--- a/src/opengl/qwindowsurface_gl.cpp
+++ b/src/opengl/qwindowsurface_gl.cpp
@@ -49,12 +49,12 @@
#include <qglpixelbuffer.h>
#include <qcolormap.h>
#include <qdesktopwidget.h>
+#include <private/qwidget_p.h>
#include "qdebug.h"
#ifdef Q_WS_X11
#include <private/qt_x11_p.h>
#include <qx11info_x11.h>
-#include <private/qwidget_p.h>
#ifndef QT_OPENGL_ES
#include <GL/glx.h>
@@ -69,7 +69,13 @@
#include <private/qglpixelbuffer_p.h>
#include <private/qgraphicssystem_gl_p.h>
+
+#include <private/qpaintengineex_opengl2_p.h>
+#include <private/qpixmapdata_gl_p.h>
+
+#ifndef QT_OPENGL_ES_2
#include <private/qpaintengine_opengl_p.h>
+#endif
#ifndef GLX_ARB_multisample
#define GLX_SAMPLE_BUFFERS_ARB 100000
@@ -80,6 +86,10 @@
#include "qgl_cl_p.h"
#endif
+#ifdef QT_OPENGL_ES
+#include <private/qegl_p.h>
+#endif
+
QT_BEGIN_NAMESPACE
//
@@ -100,17 +110,19 @@ QGLGraphicsSystem::QGLGraphicsSystem()
int i = 0;
int spec[16];
spec[i++] = GLX_RGBA;
-#if 0
spec[i++] = GLX_DOUBLEBUFFER;
- spec[i++] = GLX_DEPTH_SIZE;
- spec[i++] = 8;
- spec[i++] = GLX_STENCIL_SIZE;
- spec[i++] = 8;
- spec[i++] = GLX_SAMPLE_BUFFERS_ARB;
- spec[i++] = 1;
- spec[i++] = GLX_SAMPLES_ARB;
- spec[i++] = 4;
-#endif
+
+ if (!qgetenv("QT_GL_SWAPBUFFER_PRESERVE").isNull()) {
+ spec[i++] = GLX_DEPTH_SIZE;
+ spec[i++] = 8;
+ spec[i++] = GLX_STENCIL_SIZE;
+ spec[i++] = 8;
+ spec[i++] = GLX_SAMPLE_BUFFERS_ARB;
+ spec[i++] = 1;
+ spec[i++] = GLX_SAMPLES_ARB;
+ spec[i++] = 4;
+ }
+
spec[i++] = XNone;
XVisualInfo *vi = glXChooseVisual(X11->display, X11->defaultScreen, spec);
@@ -164,7 +176,7 @@ QGLGraphicsSystem::QGLGraphicsSystem()
}
}
#elif defined(Q_WS_WIN)
- QGLWindowSurface::surfaceFormat.setDoubleBuffer(false);
+ QGLWindowSurface::surfaceFormat.setDoubleBuffer(true);
qt_win_owndc_required = true;
#endif
@@ -177,25 +189,32 @@ QGLGraphicsSystem::QGLGraphicsSystem()
class QGLGlobalShareWidget
{
public:
- QGLGlobalShareWidget() : widget(0) {}
+ QGLGlobalShareWidget() : widget(0), initializing(false) {}
QGLWidget *shareWidget() {
- if (!widget && !cleanedUp) {
+ if (!initializing && !widget && !cleanedUp) {
+ initializing = true;
widget = new QGLWidget;
+ // We dont need this internal widget to appear in QApplication::topLevelWidgets()
+ if (QWidgetPrivate::allWidgets)
+ QWidgetPrivate::allWidgets->remove(widget);
+ initializing = false;
}
return widget;
}
void cleanup() {
- delete widget;
- widget = 0;
+ QGLWidget *w = widget;
cleanedUp = true;
+ widget = 0;
+ delete w;
}
static bool cleanedUp;
private:
QGLWidget *widget;
+ bool initializing;
};
bool QGLGlobalShareWidget::cleanedUp = false;
@@ -218,6 +237,7 @@ QGLWidget* qt_gl_share_widget()
return _qt_gl_share_widget()->shareWidget();
}
+
struct QGLWindowSurfacePrivate
{
QGLFramebufferObject *fbo;
@@ -227,6 +247,8 @@ struct QGLWindowSurfacePrivate
int tried_fbo : 1;
int tried_pb : 1;
+ int destructive_swap_buffers : 1;
+ int geometry_updated : 1;
QGLContext *ctx;
@@ -236,10 +258,39 @@ struct QGLWindowSurfacePrivate
QSize size;
QList<QImage> buffers;
+ QGLWindowSurfaceGLPaintDevice glDevice;
+ QGLWindowSurface* q_ptr;
};
QGLFormat QGLWindowSurface::surfaceFormat;
+void QGLWindowSurfaceGLPaintDevice::endPaint()
+{
+ glFlush();
+ QGLPaintDevice::endPaint();
+}
+
+QSize QGLWindowSurfaceGLPaintDevice::size() const
+{
+ return d->size;
+}
+
+QGLContext* QGLWindowSurfaceGLPaintDevice::context() const
+{
+ return d->ctx;
+}
+
+
+int QGLWindowSurfaceGLPaintDevice::metric(PaintDeviceMetric m) const
+{
+ return qt_paint_device_metric(d->q_ptr->window(), m);
+}
+
+QPaintEngine *QGLWindowSurfaceGLPaintDevice::paintEngine() const
+{
+ return qt_qgl_paint_engine();
+}
+
QGLWindowSurface::QGLWindowSurface(QWidget *window)
: QWindowSurface(window), d_ptr(new QGLWindowSurfacePrivate)
{
@@ -248,8 +299,17 @@ QGLWindowSurface::QGLWindowSurface(QWidget *window)
d_ptr->pb = 0;
d_ptr->fbo = 0;
d_ptr->ctx = 0;
+#if defined (QT_OPENGL_ES_2)
+ d_ptr->tried_fbo = true;
+ d_ptr->tried_pb = true;
+#else
d_ptr->tried_fbo = false;
d_ptr->tried_pb = false;
+#endif
+ d_ptr->destructive_swap_buffers = qgetenv("QT_GL_SWAPBUFFER_PRESERVE").isNull();
+ d_ptr->glDevice.d = d_ptr;
+ d_ptr->q_ptr = this;
+ d_ptr->geometry_updated = false;
}
QGLWindowSurface::~QGLWindowSurface()
@@ -266,6 +326,28 @@ QGLWindowSurface::~QGLWindowSurface()
delete d_ptr;
}
+void QGLWindowSurface::deleted(QObject *object)
+{
+ // Make sure that the fbo is destroyed before destroying its context.
+ delete d_ptr->fbo;
+ d_ptr->fbo = 0;
+
+ QWidget *widget = qobject_cast<QWidget *>(object);
+ if (widget) {
+ QWidgetPrivate *widgetPrivate = widget->d_func();
+ if (widgetPrivate->extraData()) {
+ union { QGLContext **ctxPtr; void **voidPtr; };
+ voidPtr = &widgetPrivate->extraData()->glContext;
+ int index = d_ptr->contexts.indexOf(ctxPtr);
+ if (index != -1) {
+ delete *ctxPtr;
+ *ctxPtr = 0;
+ d_ptr->contexts.removeAt(index);
+ }
+ }
+ }
+}
+
void QGLWindowSurface::hijackWindow(QWidget *widget)
{
QWidgetPrivate *widgetPrivate = widget->d_func();
@@ -275,37 +357,30 @@ void QGLWindowSurface::hijackWindow(QWidget *widget)
QGLContext *ctx = new QGLContext(surfaceFormat, widget);
ctx->create(qt_gl_share_widget()->context());
-#ifdef Q_WS_MAC
- ctx->updatePaintDevice();
+
+#if defined(Q_WS_X11) && defined(QT_OPENGL_ES)
+ // Create the EGL surface to draw into. QGLContext::chooseContext()
+ // does not do this for X11/EGL, but does do it for other platforms.
+ // This probably belongs in qgl_x11egl.cpp.
+ QGLContextPrivate *ctxpriv = ctx->d_func();
+ ctxpriv->eglSurface = ctxpriv->eglContext->createSurface(widget);
+ if (ctxpriv->eglSurface == EGL_NO_SURFACE) {
+ qWarning() << "hijackWindow() could not create EGL surface";
+ }
+ qDebug("QGLWindowSurface - using EGLConfig %d", reinterpret_cast<int>(ctxpriv->eglContext->config()));
#endif
+
widgetPrivate->extraData()->glContext = ctx;
union { QGLContext **ctxPtr; void **voidPtr; };
+ connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(deleted(QObject*)));
+
voidPtr = &widgetPrivate->extraData()->glContext;
d_ptr->contexts << ctxPtr;
qDebug() << "hijackWindow() context created for" << widget << d_ptr->contexts.size();
}
-#if !defined(QT_OPENGL_ES_2)
-Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_window_surface_paintengine)
-#endif
-
-/*! \reimp */
-QPaintEngine *QGLWindowSurface::paintEngine() const
-{
-#if !defined(QT_OPENGL_ES_2)
- return qt_gl_window_surface_paintengine();
-#else
- return 0;
-#endif
-}
-
-int QGLWindowSurface::metric(PaintDeviceMetric m) const
-{
- return window()->metric(m);
-}
-
QGLContext *QGLWindowSurface::context() const
{
return d_ptr->ctx;
@@ -313,11 +388,13 @@ QGLContext *QGLWindowSurface::context() const
QPaintDevice *QGLWindowSurface::paintDevice()
{
+ updateGeometry();
+
if (d_ptr->pb)
return d_ptr->pb;
if (d_ptr->ctx)
- return this;
+ return &d_ptr->glDevice;
QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
ctx->makeCurrent();
@@ -340,9 +417,24 @@ void QGLWindowSurface::endPaint(const QRegion &rgn)
void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &offset)
{
+ if (context() && widget != window()) {
+ qWarning("No native child widget support in GL window surface without FBOs or pixel buffers");
+ return;
+ }
+
+ //### Find out why d_ptr->geometry_updated isn't always false.
+ // flush() should not be called when d_ptr->geometry_updated is true. It assumes that either
+ // d_ptr->fbo or d_ptr->pb is allocated and has the correct size.
+ if (d_ptr->geometry_updated)
+ return;
+
QWidget *parent = widget->internalWinId() ? widget : widget->nativeParentWidget();
Q_ASSERT(parent);
+ if (!geometry().isValid())
+ return;
+
+ // Needed to support native child-widgets...
hijackWindow(parent);
QRect br = rgn.boundingRect().translated(offset);
@@ -350,55 +442,57 @@ void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &
QPoint wOffset = qt_qwidget_data(parent)->wrect.topLeft();
QRect rect = br.translated(-offset - wOffset);
- const GLenum target = qt_gl_preferredTextureTarget();
+ const GLenum target = GL_TEXTURE_2D;
+ Q_UNUSED(target);
if (context()) {
context()->makeCurrent();
if (context()->format().doubleBuffer()) {
- glBindTexture(target, d_ptr->tex_id);
-
- QVector<QRect> rects = d_ptr->paintedRegion.rects();
- for (int i = 0; i < rects.size(); ++i) {
- QRect br = rects.at(i);
- if (br.isEmpty())
- continue;
+#if !defined(QT_OPENGL_ES_2)
+ if (d_ptr->destructive_swap_buffers) {
+ glBindTexture(target, d_ptr->tex_id);
- const uint bottom = window()->height() - (br.y() + br.height());
- glCopyTexSubImage2D(target, 0, br.x(), bottom, br.x(), bottom, br.width(), br.height());
- }
+ QVector<QRect> rects = d_ptr->paintedRegion.rects();
+ for (int i = 0; i < rects.size(); ++i) {
+ QRect br = rects.at(i);
+ if (br.isEmpty())
+ continue;
- glBindTexture(target, 0);
+ const uint bottom = window()->height() - (br.y() + br.height());
+ glCopyTexSubImage2D(target, 0, br.x(), bottom, br.x(), bottom, br.width(), br.height());
+ }
- QRegion dirtyRegion = QRegion(window()->rect()) - d_ptr->paintedRegion;
+ glBindTexture(target, 0);
- if (!dirtyRegion.isEmpty()) {
- context()->makeCurrent();
+ QRegion dirtyRegion = QRegion(window()->rect()) - d_ptr->paintedRegion;
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
+ if (!dirtyRegion.isEmpty()) {
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
#ifndef QT_OPENGL_ES
- glOrtho(0, window()->width(), window()->height(), 0, -999999, 999999);
+ glOrtho(0, window()->width(), window()->height(), 0, -999999, 999999);
#else
- glOrthof(0, window()->width(), window()->height(), 0, -999999, 999999);
+ glOrthof(0, window()->width(), window()->height(), 0, -999999, 999999);
#endif
- glViewport(0, 0, window()->width(), window()->height());
+ glViewport(0, 0, window()->width(), window()->height());
- QVector<QRect> rects = dirtyRegion.rects();
- glColor4f(1, 1, 1, 1);
- for (int i = 0; i < rects.size(); ++i) {
- QRect rect = rects.at(i);
- if (rect.isEmpty())
- continue;
+ QVector<QRect> rects = dirtyRegion.rects();
+ glColor4f(1, 1, 1, 1);
+ for (int i = 0; i < rects.size(); ++i) {
+ QRect rect = rects.at(i);
+ if (rect.isEmpty())
+ continue;
- drawTexture(rect, d_ptr->tex_id, window()->size(), rect);
+ drawTexture(rect, d_ptr->tex_id, window()->size(), rect);
+ }
}
}
+#endif
d_ptr->paintedRegion = QRegion();
-
context()->swapBuffers();
} else {
glFlush();
@@ -407,8 +501,76 @@ void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &
return;
}
+ QGLContext *previous_ctx = const_cast<QGLContext *>(QGLContext::currentContext());
QGLContext *ctx = reinterpret_cast<QGLContext *>(parent->d_func()->extraData()->glContext);
- GLuint texture;
+
+ // QPainter::end() should have unbound the fbo, otherwise something is very wrong...
+ Q_ASSERT(!d_ptr->fbo || !d_ptr->fbo->isBound());
+
+ if (ctx != previous_ctx) {
+ ctx->makeCurrent();
+ }
+
+ QSize size = widget->rect().size();
+ if (d_ptr->destructive_swap_buffers && ctx->format().doubleBuffer()) {
+ rect = parent->rect();
+ br = rect.translated(wOffset + offset);
+ size = parent->size();
+ }
+
+ glDisable(GL_SCISSOR_TEST);
+
+ if (d_ptr->fbo && (QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit)) {
+ const int h = d_ptr->fbo->height();
+
+ const int sx0 = br.left();
+ const int sx1 = br.left() + br.width();
+ const int sy0 = h - (br.top() + br.height());
+ const int sy1 = h - br.top();
+
+ const int tx0 = rect.left();
+ const int tx1 = rect.left() + rect.width();
+ const int ty0 = parent->height() - (rect.top() + rect.height());
+ const int ty1 = parent->height() - rect.top();
+
+ if (window() == parent || d_ptr->fbo->format().samples() <= 1) {
+ // glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, d_ptr->fbo->handle());
+
+ glBlitFramebufferEXT(sx0, sy0, sx1, sy1,
+ tx0, ty0, tx1, ty1,
+ GL_COLOR_BUFFER_BIT,
+ GL_NEAREST);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
+ } else {
+ // can't do sub-region blits with multisample FBOs
+ QGLFramebufferObject *temp = qgl_fbo_pool()->acquire(d_ptr->fbo->size(), QGLFramebufferObjectFormat());
+
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, temp->handle());
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, d_ptr->fbo->handle());
+
+ glBlitFramebufferEXT(0, 0, d_ptr->fbo->width(), d_ptr->fbo->height(),
+ 0, 0, d_ptr->fbo->width(), d_ptr->fbo->height(),
+ GL_COLOR_BUFFER_BIT,
+ GL_NEAREST);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, temp->handle());
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0);
+
+ glBlitFramebufferEXT(sx0, sy0, sx1, sy1,
+ tx0, ty0, tx1, ty1,
+ GL_COLOR_BUFFER_BIT,
+ GL_NEAREST);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
+
+ qgl_fbo_pool()->release(temp);
+ }
+ }
+#if !defined(QT_OPENGL_ES_2)
+ else {
+ GLuint texture;
if (d_ptr->fbo) {
texture = d_ptr->fbo->texture();
} else {
@@ -420,49 +582,101 @@ void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &
glBindTexture(target, 0);
}
- QSize size = widget->rect().size();
- if (ctx->format().doubleBuffer()) {
- rect = parent->rect();
- br = rect.translated(wOffset);
- size = parent->size();
- }
+ glDisable(GL_DEPTH_TEST);
- ctx->makeCurrent();
-#ifdef Q_WS_MAC
- ctx->updatePaintDevice();
-#endif
- if (d_ptr->fbo)
- d_ptr->fbo->release();
+ if (d_ptr->fbo) {
+ d_ptr->fbo->release();
+ } else {
+ ctx->makeCurrent();
+ }
- 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();
+ }
+#else
+ // OpenGL/ES 2.0 version of the fbo blit.
+ else if (d_ptr->fbo) {
+ Q_UNUSED(target);
+
+ GLuint texture = d_ptr->fbo->texture();
+
+ glDisable(GL_DEPTH_TEST);
+
+ if (d_ptr->fbo->isBound())
+ d_ptr->fbo->release();
+
+ glViewport(0, 0, size.width(), size.height());
+
+ QGLShaderProgram *blitProgram =
+ QGLEngineSharedShaders::shadersForContext(ctx)->blitProgram();
+ blitProgram->bind();
+ blitProgram->setUniformValue("imageTexture", 0 /*QT_IMAGE_TEXTURE_UNIT*/);
+
+ // The shader manager's blit program does not multiply the
+ // vertices by the pmv matrix, so we need to do the effect
+ // of the orthographic projection here ourselves.
+ QRectF r;
+ qreal w = size.width() ? size.width() : 1.0f;
+ qreal h = size.height() ? size.height() : 1.0f;
+ r.setLeft((rect.left() / w) * 2.0f - 1.0f);
+ if (rect.right() == (size.width() - 1))
+ r.setRight(1.0f);
+ else
+ r.setRight((rect.right() / w) * 2.0f - 1.0f);
+ r.setBottom((rect.top() / h) * 2.0f - 1.0f);
+ if (rect.bottom() == (size.height() - 1))
+ r.setTop(1.0f);
+ else
+ r.setTop((rect.bottom() / w) * 2.0f - 1.0f);
+
+ drawTexture(r, texture, window()->size(), br);
+ }
+#endif
if (ctx->format().doubleBuffer())
ctx->swapBuffers();
else
glFlush();
-
- if (d_ptr->fbo)
- d_ptr->fbo->bind();
}
+
void QGLWindowSurface::setGeometry(const QRect &rect)
{
QWindowSurface::setGeometry(rect);
+ d_ptr->geometry_updated = true;
+}
+
+
+void QGLWindowSurface::updateGeometry() {
+ if (!d_ptr->geometry_updated)
+ return;
+ d_ptr->geometry_updated = false;
+
+
+ QRect rect = geometry();
+ hijackWindow(window());
+ QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
+
+#ifdef Q_WS_MAC
+ ctx->updatePaintDevice();
+#endif
- const GLenum target = qt_gl_preferredTextureTarget();
+ const GLenum target = GL_TEXTURE_2D;
if (rect.width() <= 0 || rect.height() <= 0)
return;
@@ -473,13 +687,49 @@ void QGLWindowSurface::setGeometry(const QRect &rect)
d_ptr->size = rect.size();
if (d_ptr->ctx) {
- glBindTexture(target, d_ptr->tex_id);
- glTexImage2D(target, 0, GL_RGBA, rect.width(), rect.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
- glBindTexture(target, 0);
+#ifndef QT_OPENGL_ES_2
+ if (d_ptr->destructive_swap_buffers) {
+ glBindTexture(target, d_ptr->tex_id);
+ glTexImage2D(target, 0, GL_RGBA, rect.width(), rect.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
+ glBindTexture(target, 0);
+ }
+#endif
return;
}
- if (d_ptr->pb || !d_ptr->tried_pb) {
+ if (d_ptr->destructive_swap_buffers
+ && (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject)
+ && (d_ptr->fbo || !d_ptr->tried_fbo)
+ && qt_gl_preferGL2Engine())
+ {
+ d_ptr->tried_fbo = true;
+ ctx->d_ptr->internal_context = true;
+ ctx->makeCurrent();
+ delete d_ptr->fbo;
+
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ format.setInternalTextureFormat(GLenum(GL_RGBA));
+ format.setTextureTarget(target);
+
+ if (QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit)
+ format.setSamples(8);
+
+ d_ptr->fbo = new QGLFramebufferObject(rect.size(), format);
+
+ 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 !defined(QT_OPENGL_ES_2)
+ if (d_ptr->destructive_swap_buffers && (d_ptr->pb || !d_ptr->tried_pb)) {
d_ptr->tried_pb = true;
if (d_ptr->pb) {
@@ -494,7 +744,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);
@@ -507,11 +757,7 @@ void QGLWindowSurface::setGeometry(const QRect &rect)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
-#ifndef QT_OPENGL_ES
glOrtho(0, d_ptr->pb->width(), d_ptr->pb->height(), 0, -999999, 999999);
-#else
- glOrthof(0, d_ptr->pb->width(), d_ptr->pb->height(), 0, -999999, 999999);
-#endif
d_ptr->pb->d_ptr->qctx->d_func()->internal_context = true;
return;
@@ -521,38 +767,21 @@ void QGLWindowSurface::setGeometry(const QRect &rect)
d_ptr->pb = 0;
}
}
+#endif // !defined(QT_OPENGL_ES_2)
- 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);
ctx->makeCurrent();
- glGenTextures(1, &d_ptr->tex_id);
- glBindTexture(target, d_ptr->tex_id);
- glTexImage2D(target, 0, GL_RGBA, rect.width(), rect.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
+#ifndef QT_OPENGL_ES_2
+ if (d_ptr->destructive_swap_buffers) {
+ glGenTextures(1, &d_ptr->tex_id);
+ glBindTexture(target, d_ptr->tex_id);
+ glTexImage2D(target, 0, GL_RGBA, rect.width(), rect.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
- glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glBindTexture(target, 0);
+ glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glBindTexture(target, 0);
+ }
+#endif
qDebug() << "QGLWindowSurface: Using plain widget as window surface" << this;;
d_ptr->ctx = ctx;
@@ -582,7 +811,7 @@ bool QGLWindowSurface::scroll(const QRegion &area, int dx, int dy)
return true;
#endif
- const GLenum target = qt_gl_preferredTextureTarget();
+ const GLenum target = GL_TEXTURE_2D;
glBindTexture(target, d_ptr->tex_id);
glCopyTexImage2D(target, 0, GL_RGBA, br.x(), d_ptr->pb->height() - (br.y() + br.height()), br.width(), br.height(), 0);
@@ -595,7 +824,7 @@ bool QGLWindowSurface::scroll(const QRegion &area, int dx, int dy)
static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize, const QRectF &br)
{
- const GLenum target = qt_gl_preferredTextureTarget();
+ const GLenum target = GL_TEXTURE_2D;
QRectF src = br.isEmpty()
? QRectF(QPointF(), texSize)
: QRectF(QPointF(br.x(), texSize.height() - br.bottom()), br.size());
@@ -623,6 +852,7 @@ static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize,
extern void qt_add_rect_to_array(const QRectF &r, q_vertexType *array); // qpaintengine_opengl.cpp
qt_add_rect_to_array(rect, vertexArray);
+#if !defined(QT_OPENGL_ES_2)
glVertexPointer(2, q_vertexTypeEnum, 0, vertexArray);
glTexCoordPointer(2, q_vertexTypeEnum, 0, texCoordArray);
@@ -637,6 +867,20 @@ static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize,
glDisable(target);
glBindTexture(target, 0);
+#else
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexArray);
+ glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, texCoordArray);
+
+ glBindTexture(target, tex_id);
+
+ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
+
+ glBindTexture(target, 0);
+#endif
}
QImage *QGLWindowSurface::buffer(const QWidget *widget)
diff --git a/src/opengl/qwindowsurface_gl_p.h b/src/opengl/qwindowsurface_gl_p.h
index 125adad..5a9f38c 100644
--- a/src/opengl/qwindowsurface_gl_p.h
+++ b/src/opengl/qwindowsurface_gl_p.h
@@ -56,6 +56,7 @@
#include <qglobal.h>
#include <qgl.h>
#include <private/qwindowsurface_p.h>
+#include <private/qglpaintdevice_p.h>
QT_BEGIN_NAMESPACE
@@ -65,15 +66,28 @@ class QRegion;
class QWidget;
struct QGLWindowSurfacePrivate;
-class QGLWindowSurface : public QWindowSurface, public QPaintDevice
+class QGLWindowSurfaceGLPaintDevice : public QGLPaintDevice
{
public:
+ QPaintEngine* paintEngine() const;
+ void endPaint();
+ QSize size() const;
+ int metric(PaintDeviceMetric m) const;
+ QGLContext* context() const;
+ QGLWindowSurfacePrivate* d;
+};
+
+class QGLWindowSurface : public QObject, public QWindowSurface // , public QPaintDevice
+{
+ Q_OBJECT
+public:
QGLWindowSurface(QWidget *window);
~QGLWindowSurface();
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);
@@ -85,10 +99,8 @@ public:
static QGLFormat surfaceFormat;
- QPaintEngine *paintEngine() const;
-
-protected:
- int metric(PaintDeviceMetric metric) const;
+private slots:
+ void deleted(QObject *object);
private:
void hijackWindow(QWidget *widget);
diff --git a/src/opengl/qwindowsurface_x11gl.cpp b/src/opengl/qwindowsurface_x11gl.cpp
new file mode 100644
index 0000000..db81be2
--- /dev/null
+++ b/src/opengl/qwindowsurface_x11gl.cpp
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QTime>
+#include <QDebug>
+
+#include <private/qt_x11_p.h>
+#include <private/qimagepixmapcleanuphooks_p.h>
+
+#include "qwindowsurface_x11gl_p.h"
+#include "qpixmapdata_x11gl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QX11GLWindowSurface::QX11GLWindowSurface(QWidget* window)
+ : QWindowSurface(window), m_GC(0), m_window(window)
+{
+}
+
+QX11GLWindowSurface::~QX11GLWindowSurface()
+{
+ if (m_GC)
+ XFree(m_GC);
+}
+
+QPaintDevice *QX11GLWindowSurface::paintDevice()
+{
+ return &m_backBuffer;
+}
+
+extern void *qt_getClipRects(const QRegion &r, int &num); // in qpaintengine_x11.cpp
+
+void QX11GLWindowSurface::flush(QWidget *widget, const QRegion &widgetRegion, const QPoint &offset)
+{
+// qDebug("QX11GLWindowSurface::flush()");
+ QTime startTime = QTime::currentTime();
+ if (m_backBuffer.isNull()) {
+ qDebug("QHarmattanWindowSurface::flush() - backBuffer is null, not flushing anything");
+ return;
+ }
+
+ QPoint widgetOffset = qt_qwidget_data(widget)->wrect.topLeft();
+ QRegion windowRegion(widgetRegion);
+ QRect boundingRect = widgetRegion.boundingRect();
+ if (!widgetOffset.isNull())
+ windowRegion.translate(-widgetOffset);
+ QRect windowBoundingRect = windowRegion.boundingRect();
+
+ int rectCount;
+ XRectangle *rects = (XRectangle *)qt_getClipRects(windowRegion, rectCount);
+ if (rectCount <= 0)
+ return;
+// qDebug() << "XSetClipRectangles";
+// for (int i = 0; i < num; ++i)
+// qDebug() << ' ' << i << rects[i].x << rects[i].x << rects[i].y << rects[i].width << rects[i].height;
+
+ if (m_GC == 0) {
+ m_GC = XCreateGC(X11->display, m_window->handle(), 0, 0);
+ XSetGraphicsExposures(X11->display, m_GC, False);
+ }
+
+ XSetClipRectangles(X11->display, m_GC, 0, 0, rects, rectCount, YXBanded);
+ XCopyArea(X11->display, m_backBuffer.handle(), m_window->handle(), m_GC,
+ boundingRect.x() + offset.x(), boundingRect.y() + offset.y(),
+ boundingRect.width(), boundingRect.height(),
+ windowBoundingRect.x(), windowBoundingRect.y());
+}
+
+void QX11GLWindowSurface::setGeometry(const QRect &rect)
+{
+ if (rect.width() > m_backBuffer.size().width() || rect.height() > m_backBuffer.size().height()) {
+ QSize newSize = rect.size();
+// QSize newSize(1024,512);
+ qDebug() << "QX11GLWindowSurface::setGeometry() - creating a pixmap of size" << newSize;
+ QX11GLPixmapData *pd = new QX11GLPixmapData;
+ pd->resize(newSize.width(), newSize.height());
+ m_backBuffer = QPixmap(pd);
+ }
+
+// if (gc)
+// XFreeGC(X11->display, gc);
+// gc = XCreateGC(X11->display, d_ptr->device.handle(), 0, 0);
+// XSetGraphicsExposures(X11->display, gc, False);
+ QWindowSurface::setGeometry(rect);
+}
+
+bool QX11GLWindowSurface::scroll(const QRegion &area, int dx, int dy)
+{
+ Q_UNUSED(area);
+ Q_UNUSED(dx);
+ Q_UNUSED(dy);
+ return false;
+}
+
+/*
+void QX11GLWindowSurface::beginPaint(const QRegion &region)
+{
+}
+
+void QX11GLWindowSurface::endPaint(const QRegion &region)
+{
+}
+
+QImage *QX11GLWindowSurface::buffer(const QWidget *widget)
+{
+}
+*/
+
+QT_END_NAMESPACE
diff --git a/src/opengl/qglpaintdevice_qws_p.h b/src/opengl/qwindowsurface_x11gl_p.h
index 5ee15d3..5ba4dc5 100644
--- a/src/opengl/qglpaintdevice_qws_p.h
+++ b/src/opengl/qwindowsurface_x11gl_p.h
@@ -39,47 +39,43 @@
**
****************************************************************************/
-#ifndef QWSGLPAINTDEVICE_GL_P_H
-#define QWSGLPAINTDEVICE_GL_P_H
+#ifndef QWINDOWSURFACE_X11GL_P_H
+#define QWINDOWSURFACE_X11GL_P_H
//
// W A R N I N G
// -------------
//
-// This file is not part of the Qt API. It exists for the convenience
-// of the QGLWindowSurface class. This header file may change from
-// version to version without notice, or even be removed.
+// 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 <QPaintDevice>
+#include <private/qwindowsurface_p.h>
QT_BEGIN_NAMESPACE
-class QWidget;
-class QWSGLWindowSurface;
-class QWSGLPaintDevicePrivate;
-
-class Q_OPENGL_EXPORT QWSGLPaintDevice : public QPaintDevice
+class QX11GLWindowSurface : public QWindowSurface
{
- Q_DECLARE_PRIVATE(QWSGLPaintDevice)
public:
- QWSGLPaintDevice(QWidget *widget);
- ~QWSGLPaintDevice();
-
- QPaintEngine *paintEngine() const;
-
- int metric(PaintDeviceMetric m) const;
+ QX11GLWindowSurface(QWidget* window);
+ virtual ~QX11GLWindowSurface();
- QWSGLWindowSurface *windowSurface() const;
+ // Inherreted from QWindowSurface
+ QPaintDevice *paintDevice();
+ void flush(QWidget *widget, const QRegion &region, const QPoint &offset);
+ void setGeometry(const QRect &rect);
+ bool scroll(const QRegion &area, int dx, int dy);
private:
- friend class QWSGLWindowSurface;
- QWSGLPaintDevicePrivate *d_ptr;
+ GC m_GC;
+ QPixmap m_backBuffer;
+ QWidget *m_window;
};
QT_END_NAMESPACE
-#endif // QWSGLPAINTDEVICE_GL_P_H
+#endif // QWINDOWSURFACE_X11GL_P_H
diff --git a/src/opengl/util/composition_mode_colorburn.glsl b/src/opengl/util/composition_mode_colorburn.glsl
index a5a153f..c913b97 100644
--- a/src/opengl/util/composition_mode_colorburn.glsl
+++ b/src/opengl/util/composition_mode_colorburn.glsl
@@ -5,8 +5,8 @@
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
- result.rgb = mix(src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a),
- src.a * (src.rgb * dst.a + dst.rgb * src.a - src.a * dst.a) / max(src.rgb, 0.00001) + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a),
+ result.rgb = mix(src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a),
+ src.a * (src.rgb * dst.a + dst.rgb * src.a - src.a * dst.a) / max(src.rgb, 0.00001) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a),
step(src.a * dst.a, src.rgb * dst.a + dst.rgb * src.a));
result.a = src.a + dst.a - src.a * dst.a;
return result;
diff --git a/src/opengl/util/composition_mode_colordodge.glsl b/src/opengl/util/composition_mode_colordodge.glsl
index c194441..b75e83c 100644
--- a/src/opengl/util/composition_mode_colordodge.glsl
+++ b/src/opengl/util/composition_mode_colordodge.glsl
@@ -5,8 +5,8 @@
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
- vec3 temp = src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a);
- result.rgb = mix(dst.rgb * src.a / max(1 - src.rgb / max(src.a, 0.000001), 0.000001) + temp,
+ vec3 temp = src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a);
+ result.rgb = mix(dst.rgb * src.a / max(1.0 - src.rgb / max(src.a, 0.000001), 0.000001) + temp,
src.a * dst.a + temp,
step(src.a * dst.a, src.rgb * dst.a + dst.rgb * src.a));
diff --git a/src/opengl/util/composition_mode_darken.glsl b/src/opengl/util/composition_mode_darken.glsl
index c1e83fd..8bbb82b 100644
--- a/src/opengl/util/composition_mode_darken.glsl
+++ b/src/opengl/util/composition_mode_darken.glsl
@@ -3,7 +3,7 @@
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
- result.rgb = min(src.rgb * dst.a, dst.rgb * src.a) + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a);
+ result.rgb = min(src.rgb * dst.a, dst.rgb * src.a) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a);
result.a = src.a + dst.a - src.a * dst.a;
return result;
}
diff --git a/src/opengl/util/composition_mode_difference.glsl b/src/opengl/util/composition_mode_difference.glsl
index ca13ce7..3c46ec7 100644
--- a/src/opengl/util/composition_mode_difference.glsl
+++ b/src/opengl/util/composition_mode_difference.glsl
@@ -3,7 +3,7 @@
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
- result.rgb = src.rgb + dst.rgb - 2 * min(src.rgb * dst.a, dst.rgb * src.a);
+ result.rgb = src.rgb + dst.rgb - 2.0 * min(src.rgb * dst.a, dst.rgb * src.a);
result.a = src.a + dst.a - src.a * dst.a;
return result;
}
diff --git a/src/opengl/util/composition_mode_exclusion.glsl b/src/opengl/util/composition_mode_exclusion.glsl
index ccd1183..59c2da9 100644
--- a/src/opengl/util/composition_mode_exclusion.glsl
+++ b/src/opengl/util/composition_mode_exclusion.glsl
@@ -3,7 +3,7 @@
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
- result.rgb = (src.rgb * dst.a + dst.rgb * src.a - 2 * src.rgb * dst.rgb) + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a);
+ result.rgb = (src.rgb * dst.a + dst.rgb * src.a - 2.0 * src.rgb * dst.rgb) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a);
result.a = src.a + dst.a - src.a * dst.a;
return result;
}
diff --git a/src/opengl/util/composition_mode_hardlight.glsl b/src/opengl/util/composition_mode_hardlight.glsl
index 9dd4de3..4ea3550 100644
--- a/src/opengl/util/composition_mode_hardlight.glsl
+++ b/src/opengl/util/composition_mode_hardlight.glsl
@@ -5,9 +5,9 @@
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
- result.rgb = mix(2 * src.rgb * dst.rgb + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a),
- src.a * dst.a - 2 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a),
- step(src.a, 2 * src.rgb));
+ result.rgb = mix(2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a),
+ src.a * dst.a - 2.0 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a),
+ step(src.a, 2.0 * src.rgb));
result.a = src.a + dst.a - src.a * dst.a;
return result;
diff --git a/src/opengl/util/composition_mode_lighten.glsl b/src/opengl/util/composition_mode_lighten.glsl
index 1fbd27a..13ef507 100644
--- a/src/opengl/util/composition_mode_lighten.glsl
+++ b/src/opengl/util/composition_mode_lighten.glsl
@@ -3,7 +3,7 @@
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
- result.rgb = max(src.rgb * dst.a, dst.rgb * src.a) + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a);
+ result.rgb = max(src.rgb * dst.a, dst.rgb * src.a) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a);
result.a = src.a + dst.a - src.a * dst.a;
return result;
}
diff --git a/src/opengl/util/composition_mode_multiply.glsl b/src/opengl/util/composition_mode_multiply.glsl
index 268345a..f90b7f0 100644
--- a/src/opengl/util/composition_mode_multiply.glsl
+++ b/src/opengl/util/composition_mode_multiply.glsl
@@ -3,7 +3,7 @@
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
- result.rgb = src.rgb * dst.rgb + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a);
+ result.rgb = src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a);
result.a = src.a + dst.a - src.a * dst.a;
return result;
}
diff --git a/src/opengl/util/composition_mode_overlay.glsl b/src/opengl/util/composition_mode_overlay.glsl
index a9b7226..f621bde 100644
--- a/src/opengl/util/composition_mode_overlay.glsl
+++ b/src/opengl/util/composition_mode_overlay.glsl
@@ -5,9 +5,9 @@
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
- result.rgb = mix(2 * src.rgb * dst.rgb + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a),
- src.a * dst.a - 2 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a),
- step(dst.a, 2 * dst.rgb));
+ result.rgb = mix(2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a),
+ src.a * dst.a - 2.0 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a),
+ step(dst.a, 2.0 * dst.rgb));
result.a = src.a + dst.a - src.a * dst.a;
return result;
}
diff --git a/src/opengl/util/composition_mode_softlight.glsl b/src/opengl/util/composition_mode_softlight.glsl
index 0237827..e4c1f89 100644
--- a/src/opengl/util/composition_mode_softlight.glsl
+++ b/src/opengl/util/composition_mode_softlight.glsl
@@ -1,18 +1,22 @@
-// Dca' = 2.Sca < Sa ?
-// Dca.(Sa - (1 - Dca/Da).(2.Sca - Sa)) + Sca.(1 - Da) + Dca.(1 - Sa) :
-// (8.Dca <= Da ?
-// Dca.(Sa - (1 - Dca/Da).(2.Sca - Sa).(3 - 8.Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa) :
-// (Dca.Sa + ((Dca/Da)^(0.5).Da - Dca).(2.Sca - Sa)) + Sca.(1 - Da) + Dca.(1 - Sa))
+// if 2.Sca <= Sa
+// Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa)
+// otherwise if 2.Sca > Sa and 4.Dca <= Da
+// Dca' = Dca.Sa + Da.(2.Sca - Sa).(4.Dca/Da.(4.Dca/Da + 1).(Dca/Da - 1) + 7.Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa)
+// otherwise if 2.Sca > Sa and 4.Dca > Da
+// Dca' = Dca.Sa + Da.(2.Sca - Sa).((Dca/Da)^0.5 - Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa)
// Da' = Sa + Da - Sa.Da
+
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
float da = max(dst.a, 0.00001);
- result.rgb = mix(dst.rgb * (src.a - (1 - dst.rgb / da) * (2 * src.rgb - src.a)),
- mix(dst.rgb * (src.a - (1 - dst.rgb / da) * (2 * src.rgb - src.a) * (3 - 8 * dst.rgb / da)),
- (dst.rgb * src.a + (sqrt(dst.rgb / da) * dst.a - dst.rgb) * (2 * src.rgb - src.a)),
- step(dst.a, 8 * dst.rgb)),
- step(src.a, 2 * src.rgb)) + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a);
+ vec3 dst_np = dst.rgb / da;
+ result.rgb = mix(dst.rgb * (src.a + (2.0 * src.rgb - src.a) * (1.0 - dst_np)),
+ mix(dst.rgb * src.a + dst.a * (2.0 * src.rgb - src.a) * ((16.0 * dst_np - 12.0) * dst_np + 3.0) * dst_np,
+ dst.rgb * src.a + dst.a * (2.0 * src.rgb - src.a) * (sqrt(dst_np) - dst_np),
+ step(dst.a, 4.0 * dst.rgb)),
+ step(src.a, 2.0 * src.rgb))
+ + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a);
result.a = src.a + dst.a - src.a * dst.a;
return result;
}
diff --git a/src/opengl/util/conical_brush.glsl b/src/opengl/util/conical_brush.glsl
index 83ee2f5..b3ec1d7 100644
--- a/src/opengl/util/conical_brush.glsl
+++ b/src/opengl/util/conical_brush.glsl
@@ -20,7 +20,7 @@ vec4 brush()
/* float val = fmod((atan2(-A.y, A.x) + angle) / (2.0 * M_PI), 1); */
if (abs(A.y) == abs(A.x))
A.y += 0.002;
- float t = (atan2(-A.y, A.x) + angle) / (2.0 * M_PI);
+ float t = (atan(-A.y, A.x) + angle) / (2.0 * M_PI);
float val = t - floor(t);
return texture1D(palette, val);
}
diff --git a/src/opengl/util/ellipse.glsl b/src/opengl/util/ellipse.glsl
deleted file mode 100644
index 860ae77..0000000
--- a/src/opengl/util/ellipse.glsl
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "ellipse_functions.glsl"
-
-void main()
-{
- gl_FragColor = ellipse();
-}
diff --git a/src/opengl/util/ellipse_aa.glsl b/src/opengl/util/ellipse_aa.glsl
index f7a6454..257e3bb 100644
--- a/src/opengl/util/ellipse_aa.glsl
+++ b/src/opengl/util/ellipse_aa.glsl
@@ -1,6 +1,58 @@
-#include "ellipse_functions.glsl"
+uniform vec3 inv_matrix_m0;
+uniform vec3 inv_matrix_m1;
+uniform vec3 inv_matrix_m2;
+
+uniform vec2 ellipse_offset;
+
+// ellipse equation
+
+// s^2/a^2 + t^2/b^2 = 1
+//
+// implicit equation:
+// g(s,t) = 1 - s^2/r_s^2 - t^2/r_t^2
+
+// distance from ellipse:
+// grad = [dg/dx dg/dy]
+// d(s, t) ~= g(s, t) / |grad|
+
+// dg/dx = dg/ds * ds/dx + dg/dt * dt/dx
+// dg/dy = dg/ds * ds/dy + dg/dt * dt/dy
+
+float ellipse_aa()
+{
+ mat3 mat;
+
+ mat[0] = inv_matrix_m0;
+ mat[1] = inv_matrix_m1;
+ mat[2] = inv_matrix_m2;
+
+ vec3 hcoords = mat * vec3(gl_FragCoord.xy + ellipse_offset, 1);
+ float inv_w = 1.0 / hcoords.z;
+ vec2 st = hcoords.xy * inv_w;
+
+ vec4 xy = vec4(mat[0].xy, mat[1].xy);
+ vec2 h = vec2(mat[0].z, mat[1].z);
+
+ vec4 dstdxy = (xy.xzyw - h.xyxy * st.xxyy) * inv_w;
+
+ //dstdxy.x = (mat[0].x - mat[0].z * st.x) * inv_w; // ds/dx
+ //dstdxy.y = (mat[1].x - mat[1].z * st.x) * inv_w; // ds/dy
+ //dstdxy.z = (mat[0].y - mat[0].z * st.y) * inv_w; // dt/dx
+ //dstdxy.w = (mat[1].y - mat[1].z * st.y) * inv_w; // dt/dy
+
+ vec2 inv_r = gl_TexCoord[0].xy;
+ vec2 n = st * inv_r;
+ float g = 1.0 - dot(n, n);
+
+ vec2 dgdst = -2.0 * n * inv_r;
+
+ vec2 grad = vec2(dot(dgdst, dstdxy.xz),
+ dot(dgdst, dstdxy.yw));
+
+ return smoothstep(-0.5, 0.5, g * inversesqrt(dot(grad, grad)));
+}
void main()
{
- gl_FragColor = ellipse_aa();
+ gl_FragColor = ellipse_aa().xxxx;
}
diff --git a/src/opengl/util/ellipse_aa_copy.glsl b/src/opengl/util/ellipse_aa_copy.glsl
deleted file mode 100644
index 5372f58..0000000
--- a/src/opengl/util/ellipse_aa_copy.glsl
+++ /dev/null
@@ -1,11 +0,0 @@
-uniform vec2 r; // r_x and r_y
-
-uniform sampler2D texture;
-uniform vec2 inv_texture_size;
-
-#include "ellipse_functions.glsl"
-
-void main()
-{
- gl_FragColor = ellipse_aa() * texture2D(texture, gl_FragCoord.xy * inv_texture_size);
-}
diff --git a/src/opengl/util/ellipse_aa_radial.glsl b/src/opengl/util/ellipse_aa_radial.glsl
deleted file mode 100644
index 0878f99..0000000
--- a/src/opengl/util/ellipse_aa_radial.glsl
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "ellipse_functions.glsl"
-
-uniform sampler1D palette;
-uniform vec2 fmp;
-uniform float fmp2_m_radius2;
-uniform vec4 inv_matrix;
-uniform vec2 inv_matrix_offset;
-
-void main()
-{
- // float2 A = frag_coord.xy;//mul(inv_matrix, frag_coord.xy) + inv_matrix_offset;
- mat2 mat;
- mat[0][0] = inv_matrix.x;
- mat[0][1] = inv_matrix.y;
- mat[1][0] = inv_matrix.z;
- mat[1][1] = inv_matrix.w;
- vec2 A = gl_FragCoord.xy * mat + inv_matrix_offset;
- vec2 B = fmp;
- float a = fmp2_m_radius2;
- float b = 2.0*dot(A, B);
- float c = -dot(A, A);
- float val = (-b + sqrt(b*b - 4.0*a*c)) / (2.0*a);
- gl_FragColor = texture1D(palette, val) * ellipse_aa();
-}
diff --git a/src/opengl/util/ellipse_functions.glsl b/src/opengl/util/ellipse_functions.glsl
deleted file mode 100644
index eed18e8..0000000
--- a/src/opengl/util/ellipse_functions.glsl
+++ /dev/null
@@ -1,63 +0,0 @@
-uniform vec3 inv_matrix_m0;
-uniform vec3 inv_matrix_m1;
-uniform vec3 inv_matrix_m2;
-
-uniform vec2 ellipse_offset;
-
-float ellipse()
-{
- vec2 st = gl_TexCoord[0].st;
-
- if (dot(st, st) > 1)
- discard;
-
- return 1.0;
-}
-
-// ellipse equation
-
-// s^2/a^2 + t^2/b^2 = 1
-//
-// implicit equation:
-// g(s,t) = 1 - s^2/r_s^2 - t^2/r_t^2
-
-// distance from ellipse:
-// grad = [dg/dx dg/dy]
-// d(s, t) ~= g(s, t) / |grad|
-
-// dg/dx = dg/ds * ds/dx + dg/dt * dt/dx
-// dg/dy = dg/ds * ds/dy + dg/dt * dt/dy
-
-float ellipse_aa()
-{
- mat3 mat;
-
- mat[0] = inv_matrix_m0;
- mat[1] = inv_matrix_m1;
- mat[2] = inv_matrix_m2;
-
- vec3 hcoords = mat * vec3(gl_FragCoord.xy + ellipse_offset, 1);
- float inv_w = 1.0 / hcoords.z;
- vec2 st = hcoords.xy * inv_w;
-
- vec4 xy = vec4(mat[0].xy, mat[1].xy);
- vec2 h = vec2(mat[0].z, mat[1].z);
-
- vec4 dstdxy = (xy.xzyw - h.xyxy * st.xxyy) * inv_w;
-
- //dstdxy.x = (mat[0].x - mat[0].z * st.x) * inv_w; // ds/dx
- //dstdxy.y = (mat[1].x - mat[1].z * st.x) * inv_w; // ds/dy
- //dstdxy.z = (mat[0].y - mat[0].z * st.y) * inv_w; // dt/dx
- //dstdxy.w = (mat[1].y - mat[1].z * st.y) * inv_w; // dt/dy
-
- vec2 inv_r = gl_TexCoord[0].xy;
- vec2 n = st * inv_r;
- float g = 1.0 - dot(n, n);
-
- vec2 dgdst = -2.0 * n * inv_r;
-
- vec2 grad = vec2(dot(dgdst, dstdxy.xz),
- dot(dgdst, dstdxy.yw));
-
- return smoothstep(-0.5, 0.5, g * inversesqrt(dot(grad, grad)));
-}
diff --git a/src/opengl/util/fragmentprograms_p.h b/src/opengl/util/fragmentprograms_p.h
index 364f99f..2241057 100644
--- a/src/opengl/util/fragmentprograms_p.h
+++ b/src/opengl/util/fragmentprograms_p.h
@@ -38,6 +38,7 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+
#ifndef FRAGMENTPROGRAMS_P_H
#define FRAGMENTPROGRAMS_P_H
@@ -71,7 +72,7 @@ enum FragmentVariable {
VAR_FMP2_M_RADIUS2,
VAR_FMP,
VAR_INV_MATRIX_M0,
- VAR_ANGLE,
+ VAR_ANGLE
};
enum FragmentBrushType {
@@ -80,7 +81,7 @@ enum FragmentBrushType {
FRAGMENT_PROGRAM_BRUSH_CONICAL,
FRAGMENT_PROGRAM_BRUSH_LINEAR,
FRAGMENT_PROGRAM_BRUSH_TEXTURE,
- FRAGMENT_PROGRAM_BRUSH_PATTERN,
+ FRAGMENT_PROGRAM_BRUSH_PATTERN
};
enum FragmentCompositionModeType {
@@ -109,12 +110,12 @@ enum FragmentCompositionModeType {
COMPOSITION_MODES_DIFFERENCE_NOMASK,
COMPOSITION_MODES_EXCLUSION_NOMASK,
COMPOSITION_MODE_BLEND_MODE_MASK,
- COMPOSITION_MODE_BLEND_MODE_NOMASK,
+ COMPOSITION_MODE_BLEND_MODE_NOMASK
};
enum FragmentMaskType {
FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA,
- FRAGMENT_PROGRAM_MASK_ELLIPSE_AA,
+ FRAGMENT_PROGRAM_MASK_ELLIPSE_AA
};
static const unsigned int num_fragment_variables = 19;
@@ -131,58 +132,57 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA =
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "ADD R4.x, fragment.position, c[0];\n"
+ "ADD R3.z, fragment.position.x, c[0].x;\n"
"ADD R0.y, fragment.position, -c[0].x;\n"
- "MAX R2.x, R0.y, fragment.texcoord[0].y;\n"
+ "MAX R4.x, fragment.texcoord[0].y, R0.y;\n"
"ADD R0.x, fragment.position.y, c[0];\n"
- "MIN R2.y, R0.x, fragment.texcoord[0].x;\n"
- "ADD R3.x, fragment.position, -c[0];\n"
- "ADD R1.zw, -fragment.texcoord[0], -fragment.texcoord[0];\n"
- "MOV R3.y, R4.x;\n"
- "MOV R0.yw, R2.x;\n"
- "MOV R0.xz, R2.y;\n"
+ "MIN R3.w, R0.x, fragment.texcoord[0].x;\n"
+ "ADD R2.z, fragment.position.x, -c[0].x;\n"
+ "MOV R2.w, R3.z;\n"
+ "MOV R0.yw, R4.x;\n"
+ "MOV R0.xz, R3.w;\n"
"MAD R0, fragment.texcoord[1].xxzz, R0, fragment.texcoord[1].yyww;\n"
- "MAD R1.xy, fragment.position.x, c[0].y, -R0.zwzw;\n"
- "MOV R0.w, R1.x;\n"
- "MOV R1.x, R0.y;\n"
- "MOV R0.z, R0.x;\n"
- "SGE R2.zw, R1.xyxy, R0;\n"
- "MAX R0.xy, R0.zwzw, R1;\n"
- "MIN R0.zw, R0, R1.xyxy;\n"
- "MAD R2.zw, R2, R1, fragment.texcoord[0];\n"
- "ADD R1, R3.xyxy, -R0.zzww;\n"
- "MAD R1, R1, R2.zzww, R2.x;\n"
- "ADD R3.zw, R0.xyxy, R0;\n"
- "ADD R3.y, R2, -R2.x;\n"
- "ADD R2.zw, R1.xyyw, -R2.x;\n"
- "ADD R4.zw, R4.x, -R0;\n"
- "MUL R2.zw, R4, R2;\n"
- "ADD R4.zw, R1.xyyw, R1.xyxz;\n"
- "ADD R1.xz, R2.y, -R1;\n"
- "MAD R2.zw, -R2, c[0].x, R3.y;\n"
- "MAD R3.zw, R3, c[0].x, -R3.x;\n"
- "MAD R3.zw, R3, R3.y, -R2;\n"
- "ADD R1.y, R4.x, -R3.x;\n"
- "MAD R4.zw, -R4, c[0].x, R2.y;\n"
- "MUL R4.zw, R4, R1.y;\n"
- "ADD R1.yw, R0.xxzy, -R3.x;\n"
- "MUL R1.xy, R1.xzzw, R1.ywzw;\n"
- "MAD R1.zw, R1.xyxy, c[0].x, -R4;\n"
- "SGE R1.xy, R4.x, R0;\n"
- "MUL R1.zw, R1.xyxy, R1;\n"
- "MAD R1.xy, R1, R3.zwzw, R2.zwzw;\n"
- "SGE R2.zw, R3.x, R0;\n"
- "ADD R1.zw, R4, R1;\n"
- "ADD R1.zw, R1, -R1.xyxy;\n"
- "MAD R1.xy, R2.zwzw, R1.zwzw, R1;\n"
- "ADD R1.xy, R1, -R3.y;\n"
- "SGE R0.zw, R4.x, R0;\n"
- "MAD R0.zw, R0, R1.xyxy, R3.y;\n"
- "SGE R0.xy, R0, R3.x;\n"
- "MUL R0.xy, R0.zwzw, R0;\n"
- "ADD R0.x, R3.y, -R0;\n"
- "SGE R0.z, R2.y, R2.x;\n"
- "ADD R0.x, R0, -R0.y;\n"
+ "MAD R0.zw, fragment.position.x, c[0].y, -R0;\n"
+ "MOV R2.x, R0;\n"
+ "MOV R2.y, R0.z;\n"
+ "MOV R1.w, R0;\n"
+ "MOV R1.z, R0.y;\n"
+ "MIN R1.xy, R2, R1.zwzw;\n"
+ "SGE R0.xy, R1.zwzw, R2;\n"
+ "ADD R0.zw, -fragment.texcoord[0], -fragment.texcoord[0];\n"
+ "MAD R3.xy, R0, R0.zwzw, fragment.texcoord[0].zwzw;\n"
+ "ADD R0, -R1.xxyy, R2.zwzw;\n"
+ "MAD R0, R0, R3.xxyy, R4.x;\n"
+ "ADD R3.xy, R0.ywzw, R0.xzzw;\n"
+ "ADD R4.zw, R3.w, -R0.xyxz;\n"
+ "ADD R0.zw, -R4.x, R0.xyyw;\n"
+ "ADD R0.xy, R3.z, -R1;\n"
+ "MAX R1.zw, R2.xyxy, R1;\n"
+ "MUL R0.xy, R0, R0.zwzw;\n"
+ "MAD R3.xy, -R3, c[0].x, R3.w;\n"
+ "ADD R2.w, R3.z, -R2.z;\n"
+ "MUL R2.xy, R3, R2.w;\n"
+ "ADD R2.w, R3, -R4.x;\n"
+ "ADD R3.xy, -R2.z, R1.zwzw;\n"
+ "MUL R3.xy, R4.zwzw, R3;\n"
+ "ADD R4.zw, R1.xyxy, R1;\n"
+ "MAD R0.zw, R4, c[0].x, -R2.z;\n"
+ "MAD R0.xy, -R0, c[0].x, R2.w;\n"
+ "MAD R4.zw, R0, R2.w, -R0.xyxy;\n"
+ "SGE R0.zw, R3.z, R1;\n"
+ "MAD R0.xy, R0.zwzw, R4.zwzw, R0;\n"
+ "MAD R3.xy, R3, c[0].x, -R2;\n"
+ "MAD R0.zw, R0, R3.xyxy, R2.xyxy;\n"
+ "ADD R2.xy, R0.zwzw, -R0;\n"
+ "SGE R0.zw, R2.z, R1.xyxy;\n"
+ "MAD R0.xy, R0.zwzw, R2, R0;\n"
+ "SGE R0.zw, R1, R2.z;\n"
+ "ADD R0.xy, R0, -R2.w;\n"
+ "SGE R1.xy, R3.z, R1;\n"
+ "MAD R0.xy, R1, R0, R2.w;\n"
+ "MAD R0.x, -R0, R0.z, R2.w;\n"
+ "SGE R0.z, R3.w, R4.x;\n"
+ "MAD R0.x, -R0.y, R0.w, R0;\n"
"MUL result.color, R0.x, R0.z;\n"
"END\n"
;
@@ -195,32 +195,32 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_MASK_ELLIPSE_AA =
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R1.xyz, R0.y, c[2];\n"
- "MAD R0.xyz, R0.x, c[1], R1;\n"
- "ADD R0.xyz, R0, c[3];\n"
+ "ADD R0.xy, fragment.position, c[3];\n"
+ "MUL R1.xyz, R0.y, c[1];\n"
+ "MAD R0.xyz, R0.x, c[0], R1;\n"
+ "ADD R0.xyz, R0, c[2];\n"
"RCP R2.z, R0.z;\n"
"MUL R0.zw, R0.xyxy, R2.z;\n"
"MUL R2.xy, R0.zwzw, fragment.texcoord[0];\n"
- "MOV R1.xy, c[1];\n"
- "MOV R1.zw, c[2].xyxy;\n"
- "MOV R0.x, c[1].z;\n"
- "MOV R0.y, c[2].z;\n"
- "MAD R0, -R0.xyxy, R0.zzww, R1.xzyw;\n"
+ "MOV R1.xy, c[0];\n"
+ "MOV R1.zw, c[1].xyxy;\n"
+ "MOV R0.x, c[0].z;\n"
+ "MOV R0.y, c[1].z;\n"
+ "MAD R0, R0.zzww, -R0.xyxy, R1.xzyw;\n"
"MUL R1.xy, R2, fragment.texcoord[0];\n"
- "MUL R0, R0, R2.z;\n"
+ "MUL R0, R2.z, R0;\n"
"MUL R1.xy, R1, c[4].x;\n"
"MUL R1.zw, R1.xyxy, R0.xyxz;\n"
- "MUL R0.xy, R1, R0.ywzw;\n"
- "ADD R0.w, R0.x, R0.y;\n"
- "MUL R0.xy, R2, R2;\n"
- "ADD R0.x, R0, R0.y;\n"
- "ADD R0.z, R1, R1.w;\n"
- "MUL R0.zw, R0, R0;\n"
+ "MUL R0.zw, R1.xyxy, R0.xyyw;\n"
"ADD R0.y, R0.z, R0.w;\n"
- "RSQ R0.y, R0.y;\n"
- "ADD R0.x, -R0, c[4].y;\n"
- "MAD_SAT R0.x, R0.y, R0, -c[4].z;\n"
+ "ADD R0.x, R1.z, R1.w;\n"
+ "MUL R0.xy, R0, R0;\n"
+ "ADD R0.x, R0, R0.y;\n"
+ "MUL R0.zw, R2.xyxy, R2.xyxy;\n"
+ "ADD R0.z, R0, R0.w;\n"
+ "ADD R0.y, -R0.z, c[4];\n"
+ "RSQ R0.x, R0.x;\n"
+ "MAD_SAT R0.x, R0, R0.y, -c[4].z;\n"
"MUL R0.y, -R0.x, c[4].w;\n"
"ADD R0.y, R0, c[5].x;\n"
"MUL R0.x, R0, R0;\n"
@@ -230,36 +230,34 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_MASK_ELLIPSE_AA =
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SIMPLE_PORTER_DUFF =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..3],\n"
- " { 1 },\n"
- " program.local[5..6] };\n"
+ "PARAM c[7] = { program.local[0..5],\n"
+ " { 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"MUL R0.xy, fragment.position, c[3];\n"
- "TEX R1, R0, texture[0], 2D;\n"
- "MUL R0.xyz, R1, c[6].y;\n"
- "MUL R2.xyz, R0, fragment.color.primary.w;\n"
- "MUL R0.xyz, fragment.color.primary, c[6].x;\n"
- "MAD R2.xyz, R0, R1.w, R2;\n"
- "ADD R3.xy, fragment.position, c[0];\n"
- "ADD R0.w, -R1, c[4].x;\n"
- "MUL R0.xyz, fragment.color.primary, c[5].y;\n"
- "MAD R2.xyz, R0, R0.w, R2;\n"
- "MUL R0.xyz, R1, c[5].z;\n"
- "ADD R0.w, -fragment.color.primary, c[4].x;\n"
- "MAD R2.xyz, R0, R0.w, R2;\n"
- "ADD R0.y, -R1.w, c[4].x;\n"
- "MUL R0.x, fragment.color.primary.w, R1.w;\n"
- "MUL R0.y, fragment.color.primary.w, R0;\n"
- "MUL R0.z, R1.w, R0.w;\n"
- "DP3 R2.w, R0, c[5];\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "MUL R1.xyz, R0, c[0].y;\n"
+ "MUL R2.xyz, fragment.color.primary.w, R1;\n"
+ "MUL R1.xyz, fragment.color.primary, c[0].x;\n"
+ "MAD R2.xyz, R0.w, R1, R2;\n"
+ "ADD R3.xy, fragment.position, c[4];\n"
+ "ADD R1.w, -R0, c[6].x;\n"
+ "MUL R1.xyz, fragment.color.primary, c[1].y;\n"
+ "MAD R2.xyz, R1.w, R1, R2;\n"
+ "MUL R1.xyz, R0, c[1].z;\n"
+ "ADD R2.w, -fragment.color.primary, c[6].x;\n"
+ "MAD R2.xyz, R2.w, R1, R2;\n"
+ "MUL R1.z, R0.w, R2.w;\n"
+ "MUL R1.x, fragment.color.primary.w, R0.w;\n"
+ "MUL R1.y, fragment.color.primary.w, R1.w;\n"
+ "DP3 R2.w, R1, c[1];\n"
+ "MUL R3.xy, R3, c[2];\n"
+ "TEX R1, R3, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[5];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -270,21 +268,21 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xy, fragment.position, c[3];\n"
- "TEX R1, R0, texture[0], 2D;\n"
- "ADD R0.x, -R1.w, c[4];\n"
- "MUL R0.xyz, fragment.color.primary, R0.x;\n"
- "MAD R0.xyz, fragment.color.primary, R1, R0;\n"
- "ADD R0.w, -fragment.color.primary, c[4].x;\n"
- "MAD R2.xyz, R1, R0.w, R0;\n"
- "ADD R0.z, fragment.color.primary.w, R1.w;\n"
- "MAD R2.w, -fragment.color.primary, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.xy, fragment.position, c[1];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "ADD R1.x, -R0.w, c[4];\n"
+ "MUL R1.xyz, fragment.color.primary, R1.x;\n"
+ "MAD R1.xyz, fragment.color.primary, R0, R1;\n"
+ "ADD R1.w, -fragment.color.primary, c[4].x;\n"
+ "MAD R2.xyz, R0, R1.w, R1;\n"
+ "ADD R1.z, fragment.color.primary.w, R0.w;\n"
+ "MAD R2.w, -fragment.color.primary, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[2];\n"
+ "MUL R1.xy, R1, c[0];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[3];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -294,16 +292,16 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xy, fragment.position, c[3];\n"
- "TEX R1, R0, texture[0], 2D;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "ADD R2, fragment.color.primary, R1;\n"
- "MUL R0.xy, R0, c[1];\n"
- "MAD R2, -fragment.color.primary, R1, R2;\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.xy, fragment.position, c[1];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "ADD R1.xy, fragment.position, c[2];\n"
+ "ADD R2, fragment.color.primary, R0;\n"
+ "MUL R1.xy, R1, c[0];\n"
+ "MAD R2, -fragment.color.primary, R0, R2;\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[3];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -315,7 +313,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xy, fragment.position, c[3];\n"
+ "MUL R0.xy, fragment.position, c[1];\n"
"TEX R1, R0, texture[0], 2D;\n"
"ADD R0.w, -R1, c[4].y;\n"
"MUL R3.xyz, fragment.color.primary, R0.w;\n"
@@ -336,11 +334,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"MAD R2.xyz, R0, R3, R2;\n"
"ADD R0.z, fragment.color.primary.w, R1.w;\n"
"MAD R2.w, -fragment.color.primary, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[2];\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[3];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -352,23 +350,23 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xy, fragment.position, c[3];\n"
- "TEX R1, R0, texture[0], 2D;\n"
- "MUL R2.xyz, R1, fragment.color.primary.w;\n"
- "MUL R0.xyz, fragment.color.primary, R1.w;\n"
- "MIN R0.xyz, R0, R2;\n"
- "ADD R0.w, -R1, c[4].x;\n"
- "MAD R0.xyz, fragment.color.primary, R0.w, R0;\n"
- "ADD R0.w, -fragment.color.primary, c[4].x;\n"
- "MAD R2.xyz, R1, R0.w, R0;\n"
- "ADD R0.z, fragment.color.primary.w, R1.w;\n"
- "MAD R2.w, -fragment.color.primary, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.xy, fragment.position, c[1];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "MUL R2.xyz, fragment.color.primary.w, R0;\n"
+ "MUL R1.xyz, fragment.color.primary, R0.w;\n"
+ "MIN R1.xyz, R1, R2;\n"
+ "ADD R1.w, -R0, c[4].x;\n"
+ "MAD R1.xyz, fragment.color.primary, R1.w, R1;\n"
+ "ADD R1.w, -fragment.color.primary, c[4].x;\n"
+ "MAD R2.xyz, R0, R1.w, R1;\n"
+ "ADD R1.z, fragment.color.primary.w, R0.w;\n"
+ "MAD R2.w, -fragment.color.primary, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[2];\n"
+ "MUL R1.xy, R1, c[0];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[3];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -379,45 +377,45 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xy, fragment.position, c[3];\n"
- "TEX R1, R0, texture[0], 2D;\n"
- "MUL R2.xyz, R1, fragment.color.primary.w;\n"
- "MUL R0.xyz, fragment.color.primary, R1.w;\n"
- "MAX R0.xyz, R0, R2;\n"
- "ADD R0.w, -R1, c[4].x;\n"
- "MAD R0.xyz, fragment.color.primary, R0.w, R0;\n"
- "ADD R0.w, -fragment.color.primary, c[4].x;\n"
- "MAD R2.xyz, R1, R0.w, R0;\n"
- "ADD R0.z, fragment.color.primary.w, R1.w;\n"
- "MAD R2.w, -fragment.color.primary, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.xy, fragment.position, c[1];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "MUL R2.xyz, fragment.color.primary.w, R0;\n"
+ "MUL R1.xyz, fragment.color.primary, R0.w;\n"
+ "MAX R1.xyz, R1, R2;\n"
+ "ADD R1.w, -R0, c[4].x;\n"
+ "MAD R1.xyz, fragment.color.primary, R1.w, R1;\n"
+ "ADD R1.w, -fragment.color.primary, c[4].x;\n"
+ "MAD R2.xyz, R0, R1.w, R1;\n"
+ "ADD R1.z, fragment.color.primary.w, R0.w;\n"
+ "MAD R2.w, -fragment.color.primary, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[2];\n"
+ "MUL R1.xy, R1, c[0];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[3];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_COLORDODGE =
"!!ARBfp1.0\n"
"PARAM c[5] = { program.local[0..3],\n"
- " { 1, 1e-06 } };\n"
+ " { 1, 1e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xy, fragment.position, c[3];\n"
+ "MUL R0.xy, fragment.position, c[1];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "ADD R1.y, -fragment.color.primary.w, c[4].x;\n"
- "MAX R1.x, fragment.color.primary.w, c[4].y;\n"
- "MUL R2.xyz, R0, R1.y;\n"
+ "ADD R1.x, -fragment.color.primary.w, c[4];\n"
+ "MAX R1.y, fragment.color.primary.w, c[4];\n"
+ "MUL R2.xyz, R0, R1.x;\n"
"ADD R1.w, -R0, c[4].x;\n"
"MAD R3.xyz, fragment.color.primary, R1.w, R2;\n"
- "RCP R1.x, R1.x;\n"
- "MAD R1.xyz, -fragment.color.primary, R1.x, c[4].x;\n"
+ "RCP R1.y, R1.y;\n"
+ "MAD R1.xyz, -fragment.color.primary, R1.y, c[4].x;\n"
"MAX R1.xyz, R1, c[4].y;\n"
- "MUL R2.xyz, R0, fragment.color.primary.w;\n"
+ "MUL R2.xyz, fragment.color.primary.w, R0;\n"
"MUL R1.w, fragment.color.primary, R0;\n"
"RCP R1.x, R1.x;\n"
"RCP R1.y, R1.y;\n"
@@ -430,11 +428,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"MAD R2.xyz, R2, R3, R1;\n"
"ADD R1.z, fragment.color.primary.w, R0.w;\n"
"MAD R2.w, -fragment.color.primary, R0, R1.z;\n"
- "ADD R1.xy, fragment.position, c[0];\n"
- "MUL R1.xy, R1, c[1];\n"
+ "ADD R1.xy, fragment.position, c[2];\n"
+ "MUL R1.xy, R1, c[0];\n"
"TEX R1, R1, texture[1], 2D;\n"
"ADD R2, R2, -R0;\n"
- "DP4 R1.x, R1, c[2];\n"
+ "DP4 R1.x, R1, c[3];\n"
"MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -442,29 +440,28 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_COLORBURN =
"!!ARBfp1.0\n"
"PARAM c[5] = { program.local[0..3],\n"
- " { 1, 9.9999997e-06 } };\n"
+ " { 1, 9.9999997e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xy, fragment.position, c[3];\n"
+ "MUL R0.xy, fragment.position, c[1];\n"
"TEX R0, R0, texture[0], 2D;\n"
"ADD R1.w, -R0, c[4].x;\n"
- "MUL R1.xyz, R0, fragment.color.primary.w;\n"
+ "MUL R1.xyz, fragment.color.primary.w, R0;\n"
"MAD R2.xyz, fragment.color.primary, R0.w, R1;\n"
"MAD R1.xyz, -fragment.color.primary.w, R0.w, R2;\n"
"MUL R3.xyz, fragment.color.primary.w, R1;\n"
"MAX R1.xyz, fragment.color.primary, c[4].y;\n"
+ "ADD R2.w, -fragment.color.primary, c[4].x;\n"
"MUL R4.xyz, fragment.color.primary, R1.w;\n"
"RCP R1.x, R1.x;\n"
"RCP R1.y, R1.y;\n"
"RCP R1.z, R1.z;\n"
"MAD R3.xyz, R3, R1, R4;\n"
- "ADD R2.w, -fragment.color.primary, c[4].x;\n"
"MUL R1.xyz, R0, R2.w;\n"
"MAD R1.xyz, fragment.color.primary, R1.w, R1;\n"
- "ADD R2.w, -fragment.color.primary, c[4].x;\n"
"MAD R3.xyz, R0, R2.w, R3;\n"
"MUL R1.w, fragment.color.primary, R0;\n"
"ADD R3.xyz, R3, -R1;\n"
@@ -472,11 +469,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"MAD R2.xyz, R2, R3, R1;\n"
"ADD R1.z, fragment.color.primary.w, R0.w;\n"
"MAD R2.w, -fragment.color.primary, R0, R1.z;\n"
- "ADD R1.xy, fragment.position, c[0];\n"
- "MUL R1.xy, R1, c[1];\n"
+ "ADD R1.xy, fragment.position, c[2];\n"
+ "MUL R1.xy, R1, c[0];\n"
"TEX R1, R1, texture[1], 2D;\n"
"ADD R2, R2, -R0;\n"
- "DP4 R1.x, R1, c[2];\n"
+ "DP4 R1.x, R1, c[3];\n"
"MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -489,7 +486,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xy, fragment.position, c[3];\n"
+ "MUL R0.xy, fragment.position, c[1];\n"
"TEX R1, R0, texture[0], 2D;\n"
"ADD R0.w, -R1, c[4].y;\n"
"MUL R3.xyz, fragment.color.primary, R0.w;\n"
@@ -510,11 +507,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"MAD R2.xyz, R0, R3, R2;\n"
"ADD R0.z, fragment.color.primary.w, R1.w;\n"
"MAD R2.w, -fragment.color.primary, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[2];\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[3];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -522,58 +519,57 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SOFTLIGHT =
"!!ARBfp1.0\n"
"PARAM c[6] = { program.local[0..3],\n"
- " { 1, 9.9999997e-06, 2, 8 },\n"
- " { 3 } };\n"
+ " { 1, 2, 9.9999997e-006, 4 },\n"
+ " { 16, 12, 3 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
"TEMP R5;\n"
- "MUL R0.xy, fragment.position, c[3];\n"
+ "MUL R0.xy, fragment.position, c[1];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "MAX R1.x, R0.w, c[4].y;\n"
- "RCP R1.w, R1.x;\n"
- "MUL R2.xyz, R0, R1.w;\n"
- "MUL R1.xyz, -R2, c[4].w;\n"
- "RSQ R2.w, R2.x;\n"
- "ADD R4.xyz, R1, c[5].x;\n"
- "MAD R1.xyz, -R0, R1.w, c[4].x;\n"
- "RSQ R2.z, R2.z;\n"
- "RSQ R2.y, R2.y;\n"
- "RCP R2.x, R2.w;\n"
- "RCP R2.z, R2.z;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R5.xyz, R2, R0.w, -R0;\n"
- "MAD R2.xyz, fragment.color.primary, c[4].z, -fragment.color.primary.w;\n"
- "MUL R3.xyz, R1, R2;\n"
- "MAD R3.xyz, -R3, R4, fragment.color.primary.w;\n"
- "MUL R4.xyz, R5, R2;\n"
- "MAD R1.xyz, -R1, R2, fragment.color.primary.w;\n"
- "MAD R5.xyz, R0, fragment.color.primary.w, R4;\n"
- "MUL R3.xyz, R0, R3;\n"
- "MUL R4.xyz, R0, c[4].w;\n"
- "ADD R5.xyz, R5, -R3;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "MUL R4.xyz, R4, R5;\n"
- "ADD R2.xyz, R3, R4;\n"
+ "MAX R1.x, R0.w, c[4].z;\n"
+ "RCP R1.x, R1.x;\n"
+ "MUL R2.xyz, R0, R1.x;\n"
+ "MAD R1.xyz, R2, c[5].x, -c[5].y;\n"
+ "MAD R3.xyz, R2, R1, c[5].z;\n"
+ "MAD R1.xyz, fragment.color.primary, c[4].y, -fragment.color.primary.w;\n"
+ "MUL R4.xyz, R0.w, R1;\n"
+ "MUL R5.xyz, R4, R3;\n"
+ "RSQ R1.w, R2.x;\n"
+ "RSQ R2.w, R2.z;\n"
+ "RCP R3.x, R1.w;\n"
+ "RSQ R1.w, R2.y;\n"
+ "MUL R5.xyz, R2, R5;\n"
+ "RCP R3.z, R2.w;\n"
+ "RCP R3.y, R1.w;\n"
+ "ADD R3.xyz, -R2, R3;\n"
+ "MUL R3.xyz, R4, R3;\n"
+ "ADD R2.xyz, -R2, c[4].x;\n"
+ "MAD R1.xyz, R1, R2, fragment.color.primary.w;\n"
+ "MUL R2.xyz, fragment.color.primary, c[4].y;\n"
+ "MAD R4.xyz, fragment.color.primary.w, R0, R5;\n"
+ "MAD R3.xyz, fragment.color.primary.w, R0, R3;\n"
+ "ADD R5.xyz, R3, -R4;\n"
+ "MUL R3.xyz, R0, c[4].w;\n"
+ "SGE R3.xyz, R3, R0.w;\n"
+ "MAD R3.xyz, R3, R5, R4;\n"
+ "MAD R3.xyz, -R0, R1, R3;\n"
"MUL R1.xyz, R0, R1;\n"
- "MUL R3.xyz, fragment.color.primary, c[4].z;\n"
- "ADD R2.xyz, R2, -R1;\n"
- "SGE R3.xyz, R3, fragment.color.primary.w;\n"
- "MUL R2.xyz, R3, R2;\n"
- "ADD R1.xyz, R1, R2;\n"
- "ADD R1.w, -R0, c[4].x;\n"
- "MAD R1.xyz, fragment.color.primary, R1.w, R1;\n"
- "ADD R1.w, -fragment.color.primary, c[4].x;\n"
- "MAD R2.xyz, R0, R1.w, R1;\n"
+ "SGE R2.xyz, R2, fragment.color.primary.w;\n"
+ "MAD R2.xyz, R2, R3, R1;\n"
+ "ADD R1.x, -R0.w, c[4];\n"
+ "MAD R2.xyz, fragment.color.primary, R1.x, R2;\n"
+ "ADD R1.x, -fragment.color.primary.w, c[4];\n"
+ "MAD R2.xyz, R0, R1.x, R2;\n"
"ADD R1.z, fragment.color.primary.w, R0.w;\n"
"MAD R2.w, -fragment.color.primary, R0, R1.z;\n"
- "ADD R1.xy, fragment.position, c[0];\n"
- "MUL R1.xy, R1, c[1];\n"
+ "ADD R1.xy, fragment.position, c[2];\n"
+ "MUL R1.xy, R1, c[0];\n"
"TEX R1, R1, texture[1], 2D;\n"
"ADD R2, R2, -R0;\n"
- "DP4 R1.x, R1, c[2];\n"
+ "DP4 R1.x, R1, c[3];\n"
"MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -586,77 +582,75 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xy, fragment.position, c[3];\n"
- "TEX R1, R0, texture[0], 2D;\n"
- "MUL R2.xyz, R1, fragment.color.primary.w;\n"
- "MUL R0.xyz, fragment.color.primary, R1.w;\n"
- "MIN R0.xyz, R0, R2;\n"
- "ADD R3.xyz, fragment.color.primary, R1;\n"
- "MAD R2.xyz, -R0, c[4].x, R3;\n"
- "ADD R0.z, fragment.color.primary.w, R1.w;\n"
- "MAD R2.w, -fragment.color.primary, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.xy, fragment.position, c[1];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "ADD R1.xyz, fragment.color.primary, R0;\n"
+ "MUL R3.xyz, fragment.color.primary.w, R0;\n"
+ "MUL R2.xyz, fragment.color.primary, R0.w;\n"
+ "MIN R2.xyz, R2, R3;\n"
+ "MAD R2.xyz, -R2, c[4].x, R1;\n"
+ "ADD R1.z, fragment.color.primary.w, R0.w;\n"
+ "MAD R2.w, -fragment.color.primary, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[2];\n"
+ "MUL R1.xy, R1, c[0];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[3];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_EXCLUSION =
"!!ARBfp1.0\n"
"PARAM c[5] = { program.local[0..3],\n"
- " { 1, 2 } };\n"
+ " { 2, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xy, fragment.position, c[3];\n"
- "TEX R1, R0, texture[0], 2D;\n"
- "MUL R0.xyz, R1, fragment.color.primary.w;\n"
- "MAD R2.xyz, fragment.color.primary, R1.w, R0;\n"
- "MUL R0.xyz, fragment.color.primary, R1;\n"
- "MAD R0.xyz, -R0, c[4].y, R2;\n"
- "ADD R0.w, -R1, c[4].x;\n"
- "MAD R0.xyz, fragment.color.primary, R0.w, R0;\n"
- "ADD R0.w, -fragment.color.primary, c[4].x;\n"
- "MAD R2.xyz, R1, R0.w, R0;\n"
- "ADD R0.z, fragment.color.primary.w, R1.w;\n"
- "MAD R2.w, -fragment.color.primary, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.xy, fragment.position, c[1];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "MUL R1.xyz, fragment.color.primary.w, R0;\n"
+ "MAD R2.xyz, fragment.color.primary, R0.w, R1;\n"
+ "MUL R1.xyz, fragment.color.primary, R0;\n"
+ "MAD R1.xyz, -R1, c[4].x, R2;\n"
+ "ADD R1.w, -R0, c[4].y;\n"
+ "MAD R1.xyz, fragment.color.primary, R1.w, R1;\n"
+ "ADD R1.w, -fragment.color.primary, c[4].y;\n"
+ "MAD R2.xyz, R0, R1.w, R1;\n"
+ "ADD R1.z, fragment.color.primary.w, R0.w;\n"
+ "MAD R2.w, -fragment.color.primary, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[2];\n"
+ "MUL R1.xy, R1, c[0];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[3];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[4] = { program.local[0],\n"
- " { 1 },\n"
- " program.local[2..3] };\n"
+ "PARAM c[4] = { program.local[0..2],\n"
+ " { 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xy, fragment.position, c[0];\n"
+ "MUL R0.xy, fragment.position, c[2];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "MUL R1.xyz, R0, c[3].y;\n"
- "MUL R2.xyz, R1, fragment.color.primary.w;\n"
- "MUL R1.xyz, fragment.color.primary, c[3].x;\n"
- "MAD R2.xyz, R1, R0.w, R2;\n"
- "MUL R0.xyz, R0, c[2].z;\n"
- "ADD R1.w, -R0, c[1].x;\n"
- "MUL R1.xyz, fragment.color.primary, c[2].y;\n"
- "MAD R1.xyz, R1, R1.w, R2;\n"
- "ADD R1.w, -fragment.color.primary, c[1].x;\n"
- "MAD result.color.xyz, R0, R1.w, R1;\n"
- "ADD R0.y, -R0.w, c[1].x;\n"
+ "MUL R1.xyz, R0, c[0].y;\n"
+ "MUL R2.xyz, fragment.color.primary.w, R1;\n"
+ "MUL R1.xyz, fragment.color.primary, c[0].x;\n"
+ "MAD R2.xyz, R0.w, R1, R2;\n"
+ "MUL R0.xyz, R0, c[1].z;\n"
+ "ADD R1.w, -R0, c[3].x;\n"
+ "MUL R1.xyz, fragment.color.primary, c[1].y;\n"
+ "MAD R1.xyz, R1.w, R1, R2;\n"
+ "ADD R2.x, -fragment.color.primary.w, c[3];\n"
+ "MAD result.color.xyz, R2.x, R0, R1;\n"
"MUL R0.x, fragment.color.primary.w, R0.w;\n"
- "MUL R0.z, R0.w, R1.w;\n"
- "MUL R0.y, fragment.color.primary.w, R0;\n"
- "DP3 result.color.w, R0, c[2];\n"
+ "MUL R0.z, R0.w, R2.x;\n"
+ "MUL R0.y, fragment.color.primary.w, R1.w;\n"
+ "DP3 result.color.w, R0, c[1];\n"
"END\n"
;
@@ -732,7 +726,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R2;\n"
"MUL R0.xy, fragment.position, c[0];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "MUL R2.xyz, R0, fragment.color.primary.w;\n"
+ "MUL R2.xyz, fragment.color.primary.w, R0;\n"
"MUL R1.xyz, fragment.color.primary, R0.w;\n"
"MIN R1.xyz, R1, R2;\n"
"ADD R1.w, -R0, c[1].x;\n"
@@ -753,7 +747,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R2;\n"
"MUL R0.xy, fragment.position, c[0];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "MUL R2.xyz, R0, fragment.color.primary.w;\n"
+ "MUL R2.xyz, fragment.color.primary.w, R0;\n"
"MUL R1.xyz, fragment.color.primary, R0.w;\n"
"MAX R1.xyz, R1, R2;\n"
"ADD R1.w, -R0, c[1].x;\n"
@@ -768,7 +762,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_COLORDODGE_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[2] = { program.local[0],\n"
- " { 1, 1e-06 } };\n"
+ " { 1, 1e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
@@ -782,7 +776,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"MAD R1.xyz, fragment.color.primary, R1.w, R1;\n"
"MAD R2.xyz, -fragment.color.primary, R2.x, c[1].x;\n"
"MAX R2.xyz, R2, c[1].y;\n"
- "MUL R0.xyz, R0, fragment.color.primary.w;\n"
+ "MUL R0.xyz, fragment.color.primary.w, R0;\n"
"MUL R1.w, fragment.color.primary, R0;\n"
"RCP R2.x, R2.x;\n"
"RCP R2.y, R2.y;\n"
@@ -801,7 +795,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_COLORBURN_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[2] = { program.local[0],\n"
- " { 1, 9.9999997e-06 } };\n"
+ " { 1, 9.9999997e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
@@ -809,7 +803,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R4;\n"
"MUL R0.xy, fragment.position, c[0];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "MUL R1.xyz, R0, fragment.color.primary.w;\n"
+ "MUL R1.xyz, fragment.color.primary.w, R0;\n"
"MAD R2.xyz, fragment.color.primary, R0.w, R1;\n"
"MAD R1.xyz, -fragment.color.primary.w, R0.w, R2;\n"
"MUL R3.xyz, fragment.color.primary.w, R1;\n"
@@ -822,7 +816,6 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"RCP R1.z, R1.z;\n"
"MAD R1.xyz, R3, R1, R4;\n"
"MUL R3.xyz, R0, R2.w;\n"
- "ADD R2.w, -fragment.color.primary, c[1].x;\n"
"MAD R0.xyz, R0, R2.w, R1;\n"
"MAD R1.xyz, fragment.color.primary, R1.w, R3;\n"
"MUL R1.w, fragment.color.primary, R0;\n"
@@ -869,8 +862,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SOFTLIGHT_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[3] = { program.local[0],\n"
- " { 1, 9.9999997e-06, 2, 8 },\n"
- " { 3 } };\n"
+ " { 1, 2, 9.9999997e-006, 4 },\n"
+ " { 16, 12, 3 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
@@ -879,43 +872,42 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R5;\n"
"MUL R0.xy, fragment.position, c[0];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "MAX R1.x, R0.w, c[1].y;\n"
- "RCP R1.w, R1.x;\n"
- "MUL R2.xyz, R0, R1.w;\n"
- "MUL R1.xyz, -R2, c[1].w;\n"
- "ADD R4.xyz, R1, c[2].x;\n"
- "MAD R1.xyz, -R0, R1.w, c[1].x;\n"
- "RSQ R2.w, R2.x;\n"
- "RSQ R2.z, R2.z;\n"
- "RSQ R2.y, R2.y;\n"
- "RCP R2.x, R2.w;\n"
- "RCP R2.z, R2.z;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R5.xyz, R2, R0.w, -R0;\n"
- "MAD R2.xyz, fragment.color.primary, c[1].z, -fragment.color.primary.w;\n"
- "MUL R3.xyz, R1, R2;\n"
- "MAD R3.xyz, -R3, R4, fragment.color.primary.w;\n"
- "MUL R4.xyz, R5, R2;\n"
- "MAD R1.xyz, -R1, R2, fragment.color.primary.w;\n"
- "MAD R5.xyz, R0, fragment.color.primary.w, R4;\n"
- "MUL R3.xyz, R0, R3;\n"
- "MUL R4.xyz, R0, c[1].w;\n"
- "ADD R5.xyz, R5, -R3;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "MUL R4.xyz, R4, R5;\n"
- "ADD R2.xyz, R3, R4;\n"
+ "MAX R1.x, R0.w, c[1].z;\n"
+ "RCP R1.x, R1.x;\n"
+ "MUL R2.xyz, R0, R1.x;\n"
+ "MAD R1.xyz, R2, c[2].x, -c[2].y;\n"
+ "MAD R3.xyz, R2, R1, c[2].z;\n"
+ "MAD R1.xyz, fragment.color.primary, c[1].y, -fragment.color.primary.w;\n"
+ "MUL R4.xyz, R0.w, R1;\n"
+ "MUL R5.xyz, R4, R3;\n"
+ "RSQ R1.w, R2.x;\n"
+ "RCP R3.x, R1.w;\n"
+ "RSQ R2.w, R2.z;\n"
+ "RSQ R1.w, R2.y;\n"
+ "MUL R5.xyz, R2, R5;\n"
+ "RCP R3.z, R2.w;\n"
+ "RCP R3.y, R1.w;\n"
+ "ADD R3.xyz, -R2, R3;\n"
+ "MUL R3.xyz, R4, R3;\n"
+ "ADD R2.xyz, -R2, c[1].x;\n"
+ "MAD R1.xyz, R1, R2, fragment.color.primary.w;\n"
+ "MUL R2.xyz, fragment.color.primary, c[1].y;\n"
+ "MAD R4.xyz, fragment.color.primary.w, R0, R5;\n"
+ "MAD R3.xyz, fragment.color.primary.w, R0, R3;\n"
+ "ADD R5.xyz, R3, -R4;\n"
+ "MUL R3.xyz, R0, c[1].w;\n"
+ "SGE R3.xyz, R3, R0.w;\n"
+ "MAD R3.xyz, R3, R5, R4;\n"
+ "MAD R3.xyz, -R0, R1, R3;\n"
"MUL R1.xyz, R0, R1;\n"
- "MUL R3.xyz, fragment.color.primary, c[1].z;\n"
- "ADD R2.xyz, R2, -R1;\n"
- "SGE R3.xyz, R3, fragment.color.primary.w;\n"
- "MUL R2.xyz, R3, R2;\n"
- "ADD R1.xyz, R1, R2;\n"
- "ADD R1.w, -R0, c[1].x;\n"
- "MAD R1.xyz, fragment.color.primary, R1.w, R1;\n"
- "ADD R1.w, fragment.color.primary, R0;\n"
- "ADD R2.x, -fragment.color.primary.w, c[1];\n"
- "MAD result.color.xyz, R0, R2.x, R1;\n"
- "MAD result.color.w, -fragment.color.primary, R0, R1;\n"
+ "SGE R2.xyz, R2, fragment.color.primary.w;\n"
+ "MAD R2.xyz, R2, R3, R1;\n"
+ "ADD R1.x, -R0.w, c[1];\n"
+ "MAD R2.xyz, fragment.color.primary, R1.x, R2;\n"
+ "ADD R1.x, fragment.color.primary.w, R0.w;\n"
+ "ADD R1.y, -fragment.color.primary.w, c[1].x;\n"
+ "MAD result.color.xyz, R0, R1.y, R2;\n"
+ "MAD result.color.w, -fragment.color.primary, R0, R1.x;\n"
"END\n"
;
@@ -928,7 +920,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R2;\n"
"MUL R0.xy, fragment.position, c[0];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "MUL R2.xyz, R0, fragment.color.primary.w;\n"
+ "MUL R2.xyz, fragment.color.primary.w, R0;\n"
"MUL R1.xyz, fragment.color.primary, R0.w;\n"
"ADD R1.w, fragment.color.primary, R0;\n"
"MIN R1.xyz, R1, R2;\n"
@@ -941,20 +933,20 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_EXCLUSION_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[2] = { program.local[0],\n"
- " { 1, 2 } };\n"
+ " { 2, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"MUL R0.xy, fragment.position, c[0];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "MUL R1.xyz, R0, fragment.color.primary.w;\n"
+ "MUL R1.xyz, fragment.color.primary.w, R0;\n"
"MAD R2.xyz, fragment.color.primary, R0.w, R1;\n"
"MUL R1.xyz, fragment.color.primary, R0;\n"
- "MAD R1.xyz, -R1, c[1].y, R2;\n"
- "ADD R1.w, -R0, c[1].x;\n"
+ "MAD R1.xyz, -R1, c[1].x, R2;\n"
+ "ADD R1.w, -R0, c[1].y;\n"
"MAD R1.xyz, fragment.color.primary, R1.w, R1;\n"
"ADD R1.w, fragment.color.primary, R0;\n"
- "ADD R2.x, -fragment.color.primary.w, c[1];\n"
+ "ADD R2.x, -fragment.color.primary.w, c[1].y;\n"
"MAD result.color.xyz, R0, R2.x, R1;\n"
"MAD result.color.w, -fragment.color.primary, R0, R1;\n"
"END\n"
@@ -964,8 +956,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"!!ARBfp1.0\n"
"PARAM c[3] = { program.local[0..2] };\n"
"TEMP R0;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[1];\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[0], 2D;\n"
"DP4 R0.x, R0, c[2];\n"
"MUL result.color, fragment.color.primary, R0.x;\n"
@@ -974,359 +966,351 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE_BLEND_MODE_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[1] = { program.local[0] };\n"
"MOV result.color, fragment.color.primary;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SIMPLE_PORTER_DUFF =
"!!ARBfp1.0\n"
- "PARAM c[12] = { program.local[0..6],\n"
- " { 2, 4, 1 },\n"
- " program.local[8..11] };\n"
+ "PARAM c[12] = { program.local[0..10],\n"
+ " { 2, 4, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
"ADD R0.z, R0, R0.w;\n"
- "MUL R0.xy, R0, c[6];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "RSQ R0.z, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "ADD R0.x, -R0, R0.z;\n"
- "MUL R0.zw, fragment.position.xyxy, c[9].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MOV R0.y, c[7].x;\n"
- "MUL R0.y, c[8].x, R0;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.x, R0, R0.y;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R2.xyz, R1, c[11].y;\n"
- "MUL R3.xyz, R2, R0.w;\n"
- "MUL R2.xyz, R0, c[11].x;\n"
- "MAD R2.xyz, R2, R1.w, R3;\n"
- "ADD R3.xy, fragment.position, c[0];\n"
- "ADD R2.w, -R1, c[7].z;\n"
- "MUL R0.xyz, R0, c[10].y;\n"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "MUL R0.xyz, R1, c[10].z;\n"
- "ADD R3.z, -R0.w, c[7];\n"
- "MAD R2.xyz, R0, R3.z, R2;\n"
- "MUL R0.y, R0.w, R2.w;\n"
- "MUL R0.x, R0.w, R1.w;\n"
- "MUL R0.z, R1.w, R3;\n"
- "DP3 R2.w, R0, c[10];\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.y, R0.x, c[11].x;\n"
+ "MUL R0.z, R0, c[11].y;\n"
+ "MAD R0.x, R0.y, R0.y, -R0.z;\n"
+ "RSQ R0.x, R0.x;\n"
+ "RCP R0.z, R0.x;\n"
+ "ADD R1.x, -R0.y, R0.z;\n"
+ "MOV R0.x, c[11];\n"
+ "MUL R0.z, R0.x, c[1].x;\n"
+ "RCP R1.y, R0.z;\n"
+ "MUL R0.xy, fragment.position, c[8];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "TEX R1, R1, texture[2], 1D;\n"
+ "MUL R2.xyz, R0, c[5].y;\n"
+ "MUL R3.xyz, R1.w, R2;\n"
+ "MUL R2.xyz, R1, c[5].x;\n"
+ "MAD R2.xyz, R0.w, R2, R3;\n"
+ "ADD R3.xy, fragment.position, c[9];\n"
+ "ADD R2.w, -R0, c[11].z;\n"
+ "MUL R1.xyz, R1, c[6].y;\n"
+ "MAD R2.xyz, R2.w, R1, R2;\n"
+ "MUL R1.xyz, R0, c[6].z;\n"
+ "ADD R3.z, -R1.w, c[11];\n"
+ "MAD R2.xyz, R3.z, R1, R2;\n"
+ "MUL R1.y, R1.w, R2.w;\n"
+ "MUL R1.x, R1.w, R0.w;\n"
+ "MUL R1.z, R0.w, R3;\n"
+ "DP3 R2.w, R1, c[6];\n"
+ "MUL R3.xy, R3, c[7];\n"
+ "TEX R1, R3, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[10];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_MULTIPLY =
"!!ARBfp1.0\n"
- "PARAM c[10] = { program.local[0..6],\n"
- " { 2, 4, 1 },\n"
- " program.local[8..9] };\n"
+ "PARAM c[10] = { program.local[0..8],\n"
+ " { 2, 4, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[6];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.z, R0.y;\n"
- "ADD R0.x, -R0, R0.z;\n"
- "MUL R0.zw, fragment.position.xyxy, c[9].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MOV R0.y, c[7].x;\n"
- "MUL R0.y, c[8].x, R0;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.x, R0, R0.y;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "ADD R2.x, -R1.w, c[7].z;\n"
- "MUL R2.xyz, R0, R2.x;\n"
- "MAD R0.xyz, R0, R1, R2;\n"
- "ADD R2.x, -R0.w, c[7].z;\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.y, R0.x, c[9].x;\n"
+ "MUL R0.z, R0, c[9].y;\n"
+ "MAD R0.x, R0.y, R0.y, -R0.z;\n"
+ "RSQ R0.x, R0.x;\n"
+ "RCP R0.z, R0.x;\n"
+ "ADD R1.x, -R0.y, R0.z;\n"
+ "MOV R0.x, c[9];\n"
+ "MUL R0.z, R0.x, c[1].x;\n"
+ "RCP R1.y, R0.z;\n"
+ "MUL R0.xy, fragment.position, c[6];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "TEX R1, R1, texture[2], 1D;\n"
+ "ADD R2.x, -R0.w, c[9].z;\n"
+ "MUL R2.xyz, R1, R2.x;\n"
+ "MAD R1.xyz, R1, R0, R2;\n"
+ "ADD R2.x, -R1.w, c[9].z;\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[7];\n"
+ "MUL R1.xy, R1, c[5];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[8];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SCREEN =
"!!ARBfp1.0\n"
- "PARAM c[10] = { program.local[0..6],\n"
- " { 2, 4 },\n"
- " program.local[8..9] };\n"
+ "PARAM c[10] = { program.local[0..8],\n"
+ " { 2, 4 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[6];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[7].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[8].x, R0;\n"
- "MUL R1.xy, fragment.position, c[9];\n"
- "ADD R3.xy, fragment.position, c[0];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "ADD R2, R0, R1;\n"
- "MAD R2, -R0, R1, R2;\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.y, R0.x, c[9].x;\n"
+ "MOV R0.x, c[9];\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.z, R0, c[9].y;\n"
+ "MAD R0.z, R0.y, R0.y, -R0;\n"
+ "ADD R3.xy, fragment.position, c[7];\n"
+ "MUL R0.w, R0.x, c[1].x;\n"
+ "RSQ R0.z, R0.z;\n"
+ "RCP R0.x, R0.z;\n"
+ "RCP R0.z, R0.w;\n"
+ "ADD R0.x, -R0.y, R0;\n"
+ "MUL R0.z, R0.x, R0;\n"
+ "TEX R1, R0.z, texture[2], 1D;\n"
+ "MUL R0.xy, fragment.position, c[6];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "ADD R2, R1, R0;\n"
+ "MAD R2, -R1, R0, R2;\n"
+ "MUL R3.xy, R3, c[5];\n"
+ "TEX R1, R3, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[8];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_OVERLAY =
"!!ARBfp1.0\n"
- "PARAM c[10] = { program.local[0..6],\n"
- " { 2, 4, 1 },\n"
- " program.local[8..9] };\n"
+ "PARAM c[10] = { program.local[0..8],\n"
+ " { 2, 4, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[6];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[7].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[8].x, R0;\n"
- "MUL R1.xy, fragment.position, c[9];\n"
+ "MUL R0.y, R0.x, c[9].x;\n"
+ "MOV R0.x, c[9];\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.z, R0, c[9].y;\n"
+ "MAD R0.z, R0.y, R0.y, -R0;\n"
+ "MUL R1.xy, fragment.position, c[6];\n"
"TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
+ "MUL R0.w, R0.x, c[1].x;\n"
+ "RSQ R0.z, R0.z;\n"
+ "RCP R0.x, R0.z;\n"
+ "ADD R2.w, -R1, c[9].z;\n"
+ "RCP R0.z, R0.w;\n"
+ "ADD R0.x, -R0.y, R0;\n"
"MUL R0.x, R0, R0.z;\n"
"TEX R0, R0, texture[2], 1D;\n"
- "ADD R2.w, -R1, c[7].z;\n"
"ADD R3.xyz, R0.w, -R0;\n"
"ADD R2.xyz, R1.w, -R1;\n"
"MUL R2.xyz, R2, R3;\n"
- "MUL R2.xyz, R2, c[7].x;\n"
+ "MUL R2.xyz, R2, c[9].x;\n"
"MAD R2.xyz, R0.w, R1.w, -R2;\n"
"MUL R4.xyz, R0, R2.w;\n"
"MUL R3.xyz, R0, R1;\n"
"MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[7].z;\n"
- "MAD R3.xyz, R3, c[7].x, R4;\n"
+ "ADD R2.x, -R0.w, c[9].z;\n"
+ "MAD R3.xyz, R3, c[9].x, R4;\n"
"MAD R3.xyz, R1, R2.x, R3;\n"
"MAD R0.xyz, R1, R2.x, R0;\n"
- "MUL R2.xyz, R1, c[7].x;\n"
+ "MUL R2.xyz, R1, c[9].x;\n"
"ADD R0.xyz, R0, -R3;\n"
"SGE R2.xyz, R2, R1.w;\n"
"MAD R2.xyz, R2, R0, R3;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[7];\n"
+ "MUL R0.xy, R0, c[5];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[8];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_DARKEN =
"!!ARBfp1.0\n"
- "PARAM c[10] = { program.local[0..6],\n"
- " { 2, 4, 1 },\n"
- " program.local[8..9] };\n"
+ "PARAM c[10] = { program.local[0..8],\n"
+ " { 2, 4, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[6];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[7].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[8].x, R0;\n"
- "MUL R1.xy, fragment.position, c[9];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.y, R0.x, c[9].x;\n"
+ "MUL R0.z, R0, c[9].y;\n"
+ "MAD R0.x, R0.y, R0.y, -R0.z;\n"
+ "RSQ R0.z, R0.x;\n"
+ "MOV R0.x, c[9];\n"
+ "MUL R0.x, R0, c[1];\n"
+ "RCP R0.z, R0.z;\n"
+ "ADD R0.z, -R0.y, R0;\n"
+ "RCP R0.w, R0.x;\n"
+ "MUL R1.x, R0.z, R0.w;\n"
+ "MUL R0.xy, fragment.position, c[6];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "TEX R1, R1, texture[2], 1D;\n"
+ "MUL R3.xyz, R1.w, R0;\n"
+ "MUL R2.xyz, R1, R0.w;\n"
"MIN R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[7].z;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[7].z;\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "ADD R2.w, -R0, c[9].z;\n"
+ "MAD R1.xyz, R1, R2.w, R2;\n"
+ "ADD R2.x, -R1.w, c[9].z;\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[7];\n"
+ "MUL R1.xy, R1, c[5];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[8];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_LIGHTEN =
"!!ARBfp1.0\n"
- "PARAM c[10] = { program.local[0..6],\n"
- " { 2, 4, 1 },\n"
- " program.local[8..9] };\n"
+ "PARAM c[10] = { program.local[0..8],\n"
+ " { 2, 4, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[6];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[7].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[8].x, R0;\n"
- "MUL R1.xy, fragment.position, c[9];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.y, R0.x, c[9].x;\n"
+ "MUL R0.z, R0, c[9].y;\n"
+ "MAD R0.x, R0.y, R0.y, -R0.z;\n"
+ "RSQ R0.z, R0.x;\n"
+ "MOV R0.x, c[9];\n"
+ "MUL R0.x, R0, c[1];\n"
+ "RCP R0.z, R0.z;\n"
+ "ADD R0.z, -R0.y, R0;\n"
+ "RCP R0.w, R0.x;\n"
+ "MUL R1.x, R0.z, R0.w;\n"
+ "MUL R0.xy, fragment.position, c[6];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "TEX R1, R1, texture[2], 1D;\n"
+ "MUL R3.xyz, R1.w, R0;\n"
+ "MUL R2.xyz, R1, R0.w;\n"
"MAX R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[7].z;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[7].z;\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "ADD R2.w, -R0, c[9].z;\n"
+ "MAD R1.xyz, R1, R2.w, R2;\n"
+ "ADD R2.x, -R1.w, c[9].z;\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[7];\n"
+ "MUL R1.xy, R1, c[5];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[8];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_COLORDODGE =
"!!ARBfp1.0\n"
- "PARAM c[10] = { program.local[0..6],\n"
- " { 2, 4, 1, 1e-06 },\n"
- " program.local[8..9] };\n"
+ "PARAM c[10] = { program.local[0..8],\n"
+ " { 2, 4, 1, 1e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[6];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[7].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[8].x, R0;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
+ "MUL R0.y, R0.x, c[9].x;\n"
+ "MOV R0.x, c[9];\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.z, R0, c[9].y;\n"
+ "MAD R0.z, R0.y, R0.y, -R0;\n"
+ "MUL R0.w, R0.x, c[1].x;\n"
+ "RSQ R0.z, R0.z;\n"
+ "RCP R0.x, R0.z;\n"
+ "RCP R0.z, R0.w;\n"
+ "ADD R0.x, -R0.y, R0;\n"
"MUL R0.x, R0, R0.z;\n"
"TEX R0, R0, texture[2], 1D;\n"
- "MAX R1.x, R0.w, c[7].w;\n"
+ "MAX R1.x, R0.w, c[9].w;\n"
"RCP R1.x, R1.x;\n"
- "MAD R1.xyz, -R0, R1.x, c[7].z;\n"
- "MAX R2.xyz, R1, c[7].w;\n"
- "MUL R1.xy, fragment.position, c[9];\n"
+ "MAD R1.xyz, -R0, R1.x, c[9].z;\n"
+ "MAX R2.xyz, R1, c[9].w;\n"
+ "MUL R1.xy, fragment.position, c[6];\n"
"TEX R1, R1, texture[0], 2D;\n"
- "ADD R2.w, -R0, c[7].z;\n"
+ "ADD R2.w, -R0, c[9].z;\n"
"MUL R3.xyz, R1, R2.w;\n"
- "ADD R2.w, -R1, c[7].z;\n"
+ "ADD R2.w, -R1, c[9].z;\n"
"MAD R4.xyz, R0, R2.w, R3;\n"
- "MUL R3.xyz, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"MUL R2.w, R0, R1;\n"
"MAD R0.xyz, R0, R1.w, R3;\n"
"SGE R0.xyz, R0, R2.w;\n"
@@ -1339,57 +1323,56 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
"MAD R2.xyz, R0, R4, R2;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[7];\n"
+ "MUL R0.xy, R0, c[5];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[8];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_COLORBURN =
"!!ARBfp1.0\n"
- "PARAM c[10] = { program.local[0..6],\n"
- " { 2, 4, 1, 9.9999997e-06 },\n"
- " program.local[8..9] };\n"
+ "PARAM c[10] = { program.local[0..8],\n"
+ " { 2, 4, 1, 9.9999997e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
"TEMP R5;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[6];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[7].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[8].x, R0;\n"
- "MUL R1.xy, fragment.position, c[9];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.y, R0.x, c[9].x;\n"
+ "MUL R0.z, R0, c[9].y;\n"
+ "MAD R0.x, R0.y, R0.y, -R0.z;\n"
+ "RSQ R0.z, R0.x;\n"
+ "MOV R0.x, c[9];\n"
+ "MUL R0.w, R0.x, c[1].x;\n"
+ "RCP R0.z, R0.z;\n"
+ "ADD R0.x, -R0.y, R0.z;\n"
+ "RCP R0.y, R0.w;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "MUL R0.x, R0, R0.y;\n"
"TEX R0, R0, texture[2], 1D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
+ "MUL R2.xyz, R0.w, R1;\n"
"MAD R3.xyz, R0, R1.w, R2;\n"
"MAD R2.xyz, -R0.w, R1.w, R3;\n"
"MUL R4.xyz, R0.w, R2;\n"
- "MAX R2.xyz, R0, c[7].w;\n"
- "ADD R2.w, -R1, c[7].z;\n"
+ "MAX R2.xyz, R0, c[9].w;\n"
+ "ADD R2.w, -R1, c[9].z;\n"
"MUL R5.xyz, R0, R2.w;\n"
- "ADD R3.w, -R0, c[7].z;\n"
+ "ADD R3.w, -R0, c[9].z;\n"
"RCP R2.x, R2.x;\n"
"RCP R2.y, R2.y;\n"
"RCP R2.z, R2.z;\n"
@@ -1403,60 +1386,59 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
"MAD R2.xyz, R3, R2, R0;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[7];\n"
+ "MUL R0.xy, R0, c[5];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[8];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_HARDLIGHT =
"!!ARBfp1.0\n"
- "PARAM c[10] = { program.local[0..6],\n"
- " { 2, 4, 1 },\n"
- " program.local[8..9] };\n"
+ "PARAM c[10] = { program.local[0..8],\n"
+ " { 2, 4, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[6];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[7].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[8].x, R0;\n"
- "MUL R1.xy, fragment.position, c[9];\n"
+ "MUL R0.y, R0.x, c[9].x;\n"
+ "MOV R0.x, c[9];\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.z, R0, c[9].y;\n"
+ "MAD R0.z, R0.y, R0.y, -R0;\n"
+ "MUL R1.xy, fragment.position, c[6];\n"
"TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
+ "MUL R0.w, R0.x, c[1].x;\n"
+ "RSQ R0.z, R0.z;\n"
+ "RCP R0.x, R0.z;\n"
+ "ADD R2.w, -R1, c[9].z;\n"
+ "RCP R0.z, R0.w;\n"
+ "ADD R0.x, -R0.y, R0;\n"
"MUL R0.x, R0, R0.z;\n"
"TEX R0, R0, texture[2], 1D;\n"
- "ADD R2.w, -R1, c[7].z;\n"
"ADD R3.xyz, R0.w, -R0;\n"
"ADD R2.xyz, R1.w, -R1;\n"
"MUL R2.xyz, R2, R3;\n"
- "MUL R2.xyz, R2, c[7].x;\n"
+ "MUL R2.xyz, R2, c[9].x;\n"
"MAD R2.xyz, R0.w, R1.w, -R2;\n"
"MUL R4.xyz, R0, R2.w;\n"
"MAD R2.xyz, R0, R2.w, R2;\n"
"MUL R3.xyz, R0, R1;\n"
- "ADD R2.w, -R0, c[7].z;\n"
- "MAD R3.xyz, R3, c[7].x, R4;\n"
- "MUL R0.xyz, R0, c[7].x;\n"
+ "ADD R2.w, -R0, c[9].z;\n"
+ "MAD R3.xyz, R3, c[9].x, R4;\n"
+ "MUL R0.xyz, R0, c[9].x;\n"
"SGE R0.xyz, R0, R0.w;\n"
"MAD R3.xyz, R1, R2.w, R3;\n"
"MAD R2.xyz, R1, R2.w, R2;\n"
@@ -1464,21 +1446,20 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
"MAD R2.xyz, R0, R2, R3;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[7];\n"
+ "MUL R0.xy, R0, c[5];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[8];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SOFTLIGHT =
"!!ARBfp1.0\n"
- "PARAM c[11] = { program.local[0..6],\n"
- " { 2, 4, 1, 9.9999997e-06 },\n"
- " program.local[8..9],\n"
- " { 8, 3 } };\n"
+ "PARAM c[11] = { program.local[0..8],\n"
+ " { 2, 4, 1, 9.9999997e-006 },\n"
+ " { 16, 12, 3 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
@@ -1486,259 +1467,254 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
"TEMP R4;\n"
"TEMP R5;\n"
"TEMP R6;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[6];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.zw, fragment.position.xyxy, c[9].xyxy;\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.y, R0.z, c[9];\n"
+ "MUL R0.x, R0, c[9];\n"
+ "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\n"
"TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MUL R0.x, R0, c[7];\n"
"MAD R0.y, R0.x, R0.x, -R0;\n"
- "MAX R0.z, R1.w, c[7].w;\n"
- "RCP R2.w, R0.z;\n"
- "MUL R2.xyz, R1, R2.w;\n"
- "MUL R6.xyz, -R2, c[10].x;\n"
- "MAD R3.xyz, -R1, R2.w, c[7].z;\n"
"RSQ R0.y, R0.y;\n"
"RCP R0.y, R0.y;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "MOV R0.y, c[7].x;\n"
- "MUL R0.y, c[8].x, R0;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.x, R0, R0.y;\n"
+ "ADD R0.y, -R0.x, R0;\n"
+ "MOV R0.x, c[9];\n"
+ "MUL R0.x, R0, c[1];\n"
+ "MAX R0.z, R1.w, c[9].w;\n"
+ "RCP R0.z, R0.z;\n"
+ "MUL R3.xyz, R1, R0.z;\n"
+ "MAD R4.xyz, R3, c[10].x, -c[10].y;\n"
+ "RCP R0.x, R0.x;\n"
+ "MUL R0.x, R0.y, R0;\n"
"TEX R0, R0, texture[2], 1D;\n"
- "MAD R4.xyz, R0, c[7].x, -R0.w;\n"
- "MUL R5.xyz, R3, R4;\n"
- "MAD R3.xyz, -R3, R4, R0.w;\n"
- "ADD R6.xyz, R6, c[10].y;\n"
- "RSQ R2.x, R2.x;\n"
- "RSQ R2.z, R2.z;\n"
- "RSQ R2.y, R2.y;\n"
- "MAD R5.xyz, -R5, R6, R0.w;\n"
- "MUL R3.xyz, R1, R3;\n"
- "ADD R2.w, -R1, c[7].z;\n"
- "RCP R2.x, R2.x;\n"
- "RCP R2.z, R2.z;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R2.xyz, R2, R1.w, -R1;\n"
- "MUL R6.xyz, R2, R4;\n"
- "MUL R2.xyz, R1, R5;\n"
- "MAD R6.xyz, R1, R0.w, R6;\n"
- "MUL R4.xyz, R0, c[7].x;\n"
- "MUL R5.xyz, R1, c[10].x;\n"
- "ADD R6.xyz, R6, -R2;\n"
- "SGE R5.xyz, R5, R1.w;\n"
- "MUL R5.xyz, R5, R6;\n"
- "ADD R2.xyz, R2, R5;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "ADD R2.xyz, R2, -R3;\n"
- "MUL R2.xyz, R4, R2;\n"
- "ADD R2.xyz, R3, R2;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[7].z;\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
+ "MAD R2.xyz, R0, c[9].x, -R0.w;\n"
+ "MAD R4.xyz, R3, R4, c[10].z;\n"
+ "MUL R5.xyz, R1.w, R2;\n"
+ "MUL R6.xyz, R5, R4;\n"
+ "RSQ R2.w, R3.x;\n"
+ "RCP R4.x, R2.w;\n"
+ "RSQ R2.w, R3.y;\n"
+ "RSQ R3.w, R3.z;\n"
+ "RCP R4.y, R2.w;\n"
+ "RCP R4.z, R3.w;\n"
+ "ADD R4.xyz, -R3, R4;\n"
+ "MUL R6.xyz, R3, R6;\n"
+ "MUL R4.xyz, R5, R4;\n"
+ "ADD R3.xyz, -R3, c[9].z;\n"
+ "MAD R2.xyz, R2, R3, R0.w;\n"
+ "MUL R3.xyz, R0, c[9].x;\n"
+ "MAD R5.xyz, R0.w, R1, R6;\n"
+ "MAD R4.xyz, R0.w, R1, R4;\n"
+ "ADD R6.xyz, R4, -R5;\n"
+ "MUL R4.xyz, R1, c[9].y;\n"
+ "SGE R4.xyz, R4, R1.w;\n"
+ "MAD R4.xyz, R4, R6, R5;\n"
+ "MAD R4.xyz, -R1, R2, R4;\n"
+ "SGE R3.xyz, R3, R0.w;\n"
+ "MUL R2.xyz, R1, R2;\n"
+ "ADD R2.w, -R1, c[9].z;\n"
+ "MAD R2.xyz, R3, R4, R2;\n"
+ "MAD R2.xyz, R0, R2.w, R2;\n"
+ "ADD R0.x, -R0.w, c[9].z;\n"
+ "MAD R2.xyz, R1, R0.x, R2;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[7];\n"
+ "MUL R0.xy, R0, c[5];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[8];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_DIFFERENCE =
"!!ARBfp1.0\n"
- "PARAM c[10] = { program.local[0..6],\n"
- " { 2, 4 },\n"
- " program.local[8..9] };\n"
+ "PARAM c[10] = { program.local[0..8],\n"
+ " { 2, 4 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
"ADD R0.z, R0, R0.w;\n"
- "MUL R0.xy, R0, c[6];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "RSQ R0.z, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "ADD R0.x, -R0, R0.z;\n"
- "MUL R0.zw, fragment.position.xyxy, c[9].xyxy;\n"
- "MOV R0.y, c[7].x;\n"
- "MUL R0.y, c[8].x, R0;\n"
- "RCP R0.y, R0.y;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MUL R0.x, R0, R0.y;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "ADD R3.xyz, R0, R1;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MUL R0.xyz, R0, R1.w;\n"
- "MIN R0.xyz, R0, R2;\n"
- "MAD R2.xyz, -R0, c[7].x, R3;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.y, R0.x, c[9].x;\n"
+ "MUL R0.z, R0, c[9].y;\n"
+ "MAD R0.x, R0.y, R0.y, -R0.z;\n"
+ "RSQ R0.z, R0.x;\n"
+ "MOV R0.x, c[9];\n"
+ "MUL R0.x, R0, c[1];\n"
+ "RCP R0.z, R0.z;\n"
+ "ADD R0.z, -R0.y, R0;\n"
+ "RCP R0.w, R0.x;\n"
+ "MUL R1.x, R0.z, R0.w;\n"
+ "MUL R0.xy, fragment.position, c[6];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "TEX R1, R1, texture[2], 1D;\n"
+ "ADD R2.xyz, R1, R0;\n"
+ "MUL R3.xyz, R1.w, R0;\n"
+ "MUL R1.xyz, R1, R0.w;\n"
+ "MIN R1.xyz, R1, R3;\n"
+ "MAD R2.xyz, -R1, c[9].x, R2;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[7];\n"
+ "MUL R1.xy, R1, c[5];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[8];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_EXCLUSION =
"!!ARBfp1.0\n"
- "PARAM c[10] = { program.local[0..6],\n"
- " { 2, 4, 1 },\n"
- " program.local[8..9] };\n"
+ "PARAM c[10] = { program.local[0..8],\n"
+ " { 2, 4, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[6];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[7].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[8].x, R0;\n"
- "MUL R1.xy, fragment.position, c[9];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MAD R3.xyz, R0, R1.w, R2;\n"
- "MUL R2.xyz, R0, R1;\n"
- "MAD R2.xyz, -R2, c[7].x, R3;\n"
- "ADD R2.w, -R1, c[7].z;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[7].z;\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.y, R0.x, c[9].x;\n"
+ "MUL R0.z, R0, c[9].y;\n"
+ "MAD R0.x, R0.y, R0.y, -R0.z;\n"
+ "RSQ R0.z, R0.x;\n"
+ "MOV R0.x, c[9];\n"
+ "MUL R0.x, R0, c[1];\n"
+ "RCP R0.z, R0.z;\n"
+ "ADD R0.z, -R0.y, R0;\n"
+ "RCP R0.w, R0.x;\n"
+ "MUL R1.x, R0.z, R0.w;\n"
+ "MUL R0.xy, fragment.position, c[6];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "TEX R1, R1, texture[2], 1D;\n"
+ "MUL R2.xyz, R1.w, R0;\n"
+ "MAD R3.xyz, R1, R0.w, R2;\n"
+ "MUL R2.xyz, R1, R0;\n"
+ "MAD R2.xyz, -R2, c[9].x, R3;\n"
+ "ADD R2.w, -R0, c[9].z;\n"
+ "MAD R1.xyz, R1, R2.w, R2;\n"
+ "ADD R2.x, -R1.w, c[9].z;\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[7];\n"
+ "MUL R1.xy, R1, c[5];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[8];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[9] = { program.local[0..3],\n"
- " { 2, 4, 1 },\n"
- " program.local[5..8] };\n"
+ "PARAM c[9] = { program.local[0..7],\n"
+ " { 2, 4, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
"ADD R0.z, R0, R0.w;\n"
- "MUL R0.xy, R0, c[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "RSQ R0.z, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "ADD R0.x, -R0, R0.z;\n"
- "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.y, R0.x, c[8].x;\n"
+ "MUL R0.z, R0, c[8].y;\n"
+ "MAD R0.x, R0.y, R0.y, -R0.z;\n"
+ "RSQ R0.x, R0.x;\n"
+ "RCP R0.z, R0.x;\n"
+ "ADD R0.y, -R0, R0.z;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
"TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MUL R2.xyz, R1, c[8].y;\n"
- "MOV R0.y, c[4].x;\n"
- "MUL R0.y, c[5].x, R0;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.x, R0, R0.y;\n"
+ "MUL R2.xyz, R1, c[5].y;\n"
+ "MOV R0.x, c[8];\n"
+ "MUL R0.x, R0, c[1];\n"
+ "RCP R0.x, R0.x;\n"
+ "MUL R0.x, R0.y, R0;\n"
"TEX R0, R0, texture[1], 1D;\n"
- "MUL R3.xyz, R2, R0.w;\n"
- "MUL R2.xyz, R0, c[8].x;\n"
- "MAD R2.xyz, R2, R1.w, R3;\n"
- "ADD R2.w, -R1, c[4].z;\n"
- "MUL R0.xyz, R0, c[7].y;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[4].z;\n"
- "MUL R1.xyz, R1, c[7].z;\n"
- "MAD result.color.xyz, R1, R2.x, R0;\n"
+ "MUL R3.xyz, R0.w, R2;\n"
+ "MUL R2.xyz, R0, c[5].x;\n"
+ "MAD R2.xyz, R1.w, R2, R3;\n"
+ "ADD R2.w, -R1, c[8].z;\n"
+ "MUL R0.xyz, R0, c[6].y;\n"
+ "MAD R0.xyz, R2.w, R0, R2;\n"
+ "ADD R2.x, -R0.w, c[8].z;\n"
+ "MUL R1.xyz, R1, c[6].z;\n"
+ "MAD result.color.xyz, R2.x, R1, R0;\n"
"MUL R0.x, R0.w, R1.w;\n"
"MUL R0.z, R1.w, R2.x;\n"
"MUL R0.y, R0.w, R2.w;\n"
- "DP3 result.color.w, R0, c[7];\n"
+ "DP3 result.color.w, R0, c[6];\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_MULTIPLY_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..3],\n"
- " { 2, 4, 1 },\n"
- " program.local[5..6] };\n"
+ "PARAM c[7] = { program.local[0..5],\n"
+ " { 2, 4, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[3];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.z, R0.y;\n"
- "ADD R0.x, -R0, R0.z;\n"
- "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.y, R0.x, c[6].x;\n"
+ "MUL R0.z, R0, c[6].y;\n"
+ "MAD R0.x, R0.y, R0.y, -R0.z;\n"
+ "RSQ R0.x, R0.x;\n"
+ "RCP R0.z, R0.x;\n"
+ "ADD R0.y, -R0, R0.z;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n"
"TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MOV R0.y, c[4].x;\n"
- "MUL R0.y, c[5].x, R0;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.x, R0, R0.y;\n"
+ "MOV R0.x, c[6];\n"
+ "MUL R0.x, R0, c[1];\n"
+ "RCP R0.x, R0.x;\n"
+ "MUL R0.x, R0.y, R0;\n"
"TEX R0, R0, texture[1], 1D;\n"
- "ADD R2.x, -R1.w, c[4].z;\n"
+ "ADD R2.x, -R1.w, c[6].z;\n"
"MUL R2.xyz, R0, R2.x;\n"
"MAD R0.xyz, R0, R1, R2;\n"
"ADD R2.x, R0.w, R1.w;\n"
- "ADD R2.y, -R0.w, c[4].z;\n"
+ "ADD R2.y, -R0.w, c[6].z;\n"
"MAD result.color.xyz, R1, R2.y, R0;\n"
"MAD result.color.w, -R0, R1, R2.x;\n"
"END\n"
@@ -1746,32 +1722,31 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SCREEN_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..3],\n"
- " { 2, 4 },\n"
- " program.local[5..6] };\n"
+ "PARAM c[7] = { program.local[0..5],\n"
+ " { 2, 4 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
"ADD R0.z, R0, R0.w;\n"
- "MUL R0.xy, R0, c[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "RSQ R0.z, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "ADD R0.x, -R0, R0.z;\n"
- "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\n"
- "MOV R0.y, c[4].x;\n"
- "MUL R0.y, c[5].x, R0;\n"
- "RCP R0.y, R0.y;\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.y, R0.x, c[6].x;\n"
+ "MUL R0.z, R0, c[6].y;\n"
+ "MAD R0.x, R0.y, R0.y, -R0.z;\n"
+ "RSQ R0.z, R0.x;\n"
+ "MOV R0.x, c[6];\n"
+ "MUL R0.w, R0.x, c[1].x;\n"
+ "RCP R0.z, R0.z;\n"
+ "ADD R0.x, -R0.y, R0.z;\n"
+ "RCP R0.y, R0.w;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n"
"TEX R1, R0.zwzw, texture[0], 2D;\n"
"MUL R0.x, R0, R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
@@ -1782,50 +1757,49 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_OVERLAY_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..3],\n"
- " { 2, 4, 1 },\n"
- " program.local[5..6] };\n"
+ "PARAM c[7] = { program.local[0..5],\n"
+ " { 2, 4, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[3];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[4].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "MUL R1.xy, fragment.position, c[6];\n"
+ "MUL R0.y, R0.x, c[6].x;\n"
+ "MOV R0.x, c[6];\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.z, R0, c[6].y;\n"
+ "MAD R0.z, R0.y, R0.y, -R0;\n"
+ "MUL R1.xy, fragment.position, c[5];\n"
"TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
+ "MUL R0.w, R0.x, c[1].x;\n"
+ "RSQ R0.z, R0.z;\n"
+ "RCP R0.x, R0.z;\n"
+ "ADD R2.w, -R1, c[6].z;\n"
+ "RCP R0.z, R0.w;\n"
+ "ADD R0.x, -R0.y, R0;\n"
"MUL R0.x, R0, R0.z;\n"
"TEX R0, R0, texture[1], 1D;\n"
"ADD R3.xyz, R0.w, -R0;\n"
"ADD R2.xyz, R1.w, -R1;\n"
"MUL R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[4].z;\n"
- "MUL R2.xyz, R2, c[4].x;\n"
+ "MUL R2.xyz, R2, c[6].x;\n"
"MAD R2.xyz, R0.w, R1.w, -R2;\n"
"MAD R2.xyz, R0, R2.w, R2;\n"
"MUL R3.xyz, R0, R2.w;\n"
"MUL R0.xyz, R0, R1;\n"
- "ADD R2.w, -R0, c[4].z;\n"
- "MAD R0.xyz, R0, c[4].x, R3;\n"
+ "ADD R2.w, -R0, c[6].z;\n"
+ "MAD R0.xyz, R0, c[6].x, R3;\n"
"MAD R0.xyz, R1, R2.w, R0;\n"
"MAD R2.xyz, R1, R2.w, R2;\n"
- "MUL R1.xyz, R1, c[4].x;\n"
+ "MUL R1.xyz, R1, c[6].x;\n"
"ADD R2.w, R0, R1;\n"
"ADD R2.xyz, R2, -R0;\n"
"SGE R1.xyz, R1, R1.w;\n"
@@ -1836,43 +1810,42 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_DARKEN_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..3],\n"
- " { 2, 4, 1 },\n"
- " program.local[5..6] };\n"
+ "PARAM c[7] = { program.local[0..5],\n"
+ " { 2, 4, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[3];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[4].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "MUL R1.xy, fragment.position, c[6];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.y, R0.x, c[6].x;\n"
+ "MUL R0.z, R0, c[6].y;\n"
+ "MAD R0.x, R0.y, R0.y, -R0.z;\n"
+ "RSQ R0.z, R0.x;\n"
+ "MOV R0.x, c[6];\n"
+ "MUL R0.w, R0.x, c[1].x;\n"
+ "RCP R0.z, R0.z;\n"
+ "ADD R0.x, -R0.y, R0.z;\n"
+ "RCP R0.y, R0.w;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "MUL R0.x, R0, R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
"MUL R2.xyz, R0, R1.w;\n"
- "MUL R3.xyz, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"MIN R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[4].z;\n"
+ "ADD R2.w, -R1, c[6].z;\n"
"MAD R0.xyz, R0, R2.w, R2;\n"
"ADD R2.x, R0.w, R1.w;\n"
- "ADD R2.y, -R0.w, c[4].z;\n"
+ "ADD R2.y, -R0.w, c[6].z;\n"
"MAD result.color.xyz, R1, R2.y, R0;\n"
"MAD result.color.w, -R0, R1, R2.x;\n"
"END\n"
@@ -1880,43 +1853,42 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_LIGHTEN_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..3],\n"
- " { 2, 4, 1 },\n"
- " program.local[5..6] };\n"
+ "PARAM c[7] = { program.local[0..5],\n"
+ " { 2, 4, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[3];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[4].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "MUL R1.xy, fragment.position, c[6];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.y, R0.x, c[6].x;\n"
+ "MUL R0.z, R0, c[6].y;\n"
+ "MAD R0.x, R0.y, R0.y, -R0.z;\n"
+ "RSQ R0.z, R0.x;\n"
+ "MOV R0.x, c[6];\n"
+ "MUL R0.w, R0.x, c[1].x;\n"
+ "RCP R0.z, R0.z;\n"
+ "ADD R0.x, -R0.y, R0.z;\n"
+ "RCP R0.y, R0.w;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "MUL R0.x, R0, R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
"MUL R2.xyz, R0, R1.w;\n"
- "MUL R3.xyz, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"MAX R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[4].z;\n"
+ "ADD R2.w, -R1, c[6].z;\n"
"MAD R0.xyz, R0, R2.w, R2;\n"
"ADD R2.x, R0.w, R1.w;\n"
- "ADD R2.y, -R0.w, c[4].z;\n"
+ "ADD R2.y, -R0.w, c[6].z;\n"
"MAD result.color.xyz, R1, R2.y, R0;\n"
"MAD result.color.w, -R0, R1, R2.x;\n"
"END\n"
@@ -1924,45 +1896,44 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_COLORDODGE_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..3],\n"
- " { 2, 4, 1, 1e-06 },\n"
- " program.local[5..6] };\n"
+ "PARAM c[7] = { program.local[0..5],\n"
+ " { 2, 4, 1, 1e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[3];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[4].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
+ "MUL R0.y, R0.x, c[6].x;\n"
+ "MOV R0.x, c[6];\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.z, R0, c[6].y;\n"
+ "MAD R0.z, R0.y, R0.y, -R0;\n"
+ "MUL R0.w, R0.x, c[1].x;\n"
+ "RSQ R0.z, R0.z;\n"
+ "RCP R0.x, R0.z;\n"
+ "RCP R0.z, R0.w;\n"
+ "ADD R0.x, -R0.y, R0;\n"
"MUL R0.x, R0, R0.z;\n"
"TEX R0, R0, texture[1], 1D;\n"
- "MAX R1.x, R0.w, c[4].w;\n"
+ "MAX R1.x, R0.w, c[6].w;\n"
"RCP R1.x, R1.x;\n"
- "MAD R1.xyz, -R0, R1.x, c[4].z;\n"
- "MAX R2.xyz, R1, c[4].w;\n"
- "MUL R1.xy, fragment.position, c[6];\n"
+ "MAD R1.xyz, -R0, R1.x, c[6].z;\n"
+ "MAX R2.xyz, R1, c[6].w;\n"
+ "MUL R1.xy, fragment.position, c[5];\n"
"TEX R1, R1, texture[0], 2D;\n"
- "ADD R2.w, -R0, c[4].z;\n"
+ "ADD R2.w, -R0, c[6].z;\n"
"MUL R3.xyz, R1, R2.w;\n"
- "ADD R2.w, -R1, c[4].z;\n"
+ "ADD R2.w, -R1, c[6].z;\n"
"MAD R3.xyz, R0, R2.w, R3;\n"
- "MUL R1.xyz, R1, R0.w;\n"
+ "MUL R1.xyz, R0.w, R1;\n"
"MAD R0.xyz, R0, R1.w, R1;\n"
"MUL R2.w, R0, R1;\n"
"RCP R2.x, R2.x;\n"
@@ -1980,46 +1951,45 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_COLORBURN_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..3],\n"
- " { 2, 4, 1, 9.9999997e-06 },\n"
- " program.local[5..6] };\n"
+ "PARAM c[7] = { program.local[0..5],\n"
+ " { 2, 4, 1, 9.9999997e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
"TEMP R5;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[3];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[4].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "MUL R1.xy, fragment.position, c[6];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.y, R0.x, c[6].x;\n"
+ "MUL R0.z, R0, c[6].y;\n"
+ "MAD R0.x, R0.y, R0.y, -R0.z;\n"
+ "RSQ R0.z, R0.x;\n"
+ "MOV R0.x, c[6];\n"
+ "MUL R0.w, R0.x, c[1].x;\n"
+ "RCP R0.z, R0.z;\n"
+ "ADD R0.x, -R0.y, R0.z;\n"
+ "RCP R0.y, R0.w;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "MUL R0.x, R0, R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
+ "MUL R2.xyz, R0.w, R1;\n"
"MAD R3.xyz, R0, R1.w, R2;\n"
- "ADD R2.w, -R1, c[4].z;\n"
+ "ADD R2.w, -R1, c[6].z;\n"
"MAD R2.xyz, -R0.w, R1.w, R3;\n"
"MUL R4.xyz, R0.w, R2;\n"
- "MAX R2.xyz, R0, c[4].w;\n"
+ "MAX R2.xyz, R0, c[6].w;\n"
"MUL R5.xyz, R0, R2.w;\n"
- "ADD R3.w, -R0, c[4].z;\n"
+ "ADD R3.w, -R0, c[6].z;\n"
"RCP R2.x, R2.x;\n"
"RCP R2.y, R2.y;\n"
"RCP R2.z, R2.z;\n"
@@ -2038,50 +2008,49 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_HARDLIGHT_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..3],\n"
- " { 2, 4, 1 },\n"
- " program.local[5..6] };\n"
+ "PARAM c[7] = { program.local[0..5],\n"
+ " { 2, 4, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[3];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[4].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "MUL R1.xy, fragment.position, c[6];\n"
+ "MUL R0.y, R0.x, c[6].x;\n"
+ "MOV R0.x, c[6];\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.z, R0, c[6].y;\n"
+ "MAD R0.z, R0.y, R0.y, -R0;\n"
+ "MUL R1.xy, fragment.position, c[5];\n"
"TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
+ "MUL R0.w, R0.x, c[1].x;\n"
+ "RSQ R0.z, R0.z;\n"
+ "RCP R0.x, R0.z;\n"
+ "ADD R2.w, -R1, c[6].z;\n"
+ "RCP R0.z, R0.w;\n"
+ "ADD R0.x, -R0.y, R0;\n"
"MUL R0.x, R0, R0.z;\n"
"TEX R0, R0, texture[1], 1D;\n"
- "ADD R2.w, -R1, c[4].z;\n"
"ADD R3.xyz, R0.w, -R0;\n"
"ADD R2.xyz, R1.w, -R1;\n"
"MUL R2.xyz, R2, R3;\n"
- "MUL R2.xyz, R2, c[4].x;\n"
+ "MUL R2.xyz, R2, c[6].x;\n"
"MAD R2.xyz, R0.w, R1.w, -R2;\n"
"MUL R4.xyz, R0, R2.w;\n"
"MUL R3.xyz, R0, R1;\n"
"MAD R2.xyz, R0, R2.w, R2;\n"
- "ADD R2.w, -R0, c[4].z;\n"
- "MUL R0.xyz, R0, c[4].x;\n"
+ "ADD R2.w, -R0, c[6].z;\n"
+ "MUL R0.xyz, R0, c[6].x;\n"
"MAD R2.xyz, R1, R2.w, R2;\n"
- "MAD R3.xyz, R3, c[4].x, R4;\n"
+ "MAD R3.xyz, R3, c[6].x, R4;\n"
"MAD R1.xyz, R1, R2.w, R3;\n"
"ADD R2.w, R0, R1;\n"
"ADD R2.xyz, R2, -R1;\n"
@@ -2093,10 +2062,9 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SOFTLIGHT_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..3],\n"
- " { 2, 4, 1, 9.9999997e-06 },\n"
- " program.local[5..6],\n"
- " { 8, 3 } };\n"
+ "PARAM c[8] = { program.local[0..5],\n"
+ " { 2, 4, 1, 9.9999997e-006 },\n"
+ " { 16, 12, 3 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
@@ -2104,151 +2072,148 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
"TEMP R4;\n"
"TEMP R5;\n"
"TEMP R6;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[3];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.y, R0.z, c[6];\n"
+ "MUL R0.x, R0, c[6];\n"
+ "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n"
"TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MUL R0.x, R0, c[4];\n"
"MAD R0.y, R0.x, R0.x, -R0;\n"
- "MAX R0.z, R1.w, c[4].w;\n"
- "RCP R2.w, R0.z;\n"
- "MUL R2.xyz, R1, R2.w;\n"
- "MUL R6.xyz, -R2, c[7].x;\n"
- "MAD R3.xyz, -R1, R2.w, c[4].z;\n"
"RSQ R0.y, R0.y;\n"
"RCP R0.y, R0.y;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "MOV R0.y, c[4].x;\n"
- "MUL R0.y, c[5].x, R0;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.x, R0, R0.y;\n"
+ "ADD R0.y, -R0.x, R0;\n"
+ "MOV R0.x, c[6];\n"
+ "MUL R0.x, R0, c[1];\n"
+ "MAX R0.z, R1.w, c[6].w;\n"
+ "RCP R0.z, R0.z;\n"
+ "MUL R3.xyz, R1, R0.z;\n"
+ "MAD R4.xyz, R3, c[7].x, -c[7].y;\n"
+ "RCP R0.x, R0.x;\n"
+ "MUL R0.x, R0.y, R0;\n"
"TEX R0, R0, texture[1], 1D;\n"
- "MAD R4.xyz, R0, c[4].x, -R0.w;\n"
- "MUL R5.xyz, R3, R4;\n"
- "MAD R3.xyz, -R3, R4, R0.w;\n"
- "ADD R6.xyz, R6, c[7].y;\n"
- "RSQ R2.x, R2.x;\n"
- "RSQ R2.z, R2.z;\n"
- "RSQ R2.y, R2.y;\n"
- "MAD R5.xyz, -R5, R6, R0.w;\n"
- "MUL R3.xyz, R1, R3;\n"
- "RCP R2.x, R2.x;\n"
- "RCP R2.z, R2.z;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R2.xyz, R2, R1.w, -R1;\n"
- "MUL R6.xyz, R2, R4;\n"
- "MUL R2.xyz, R1, R5;\n"
- "MUL R4.xyz, R0, c[4].x;\n"
- "MAD R6.xyz, R1, R0.w, R6;\n"
- "MUL R5.xyz, R1, c[7].x;\n"
- "ADD R6.xyz, R6, -R2;\n"
- "SGE R5.xyz, R5, R1.w;\n"
- "MUL R5.xyz, R5, R6;\n"
- "ADD R2.xyz, R2, R5;\n"
- "ADD R2.xyz, R2, -R3;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "MUL R2.xyz, R4, R2;\n"
- "ADD R2.xyz, R3, R2;\n"
- "ADD R2.w, -R1, c[4].z;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, R0.w, R1.w;\n"
- "ADD R2.y, -R0.w, c[4].z;\n"
- "MAD result.color.xyz, R1, R2.y, R0;\n"
- "MAD result.color.w, -R0, R1, R2.x;\n"
+ "MAD R2.xyz, R0, c[6].x, -R0.w;\n"
+ "MAD R4.xyz, R3, R4, c[7].z;\n"
+ "MUL R5.xyz, R1.w, R2;\n"
+ "MUL R6.xyz, R5, R4;\n"
+ "RSQ R2.w, R3.x;\n"
+ "RCP R4.x, R2.w;\n"
+ "RSQ R2.w, R3.y;\n"
+ "RSQ R3.w, R3.z;\n"
+ "RCP R4.y, R2.w;\n"
+ "RCP R4.z, R3.w;\n"
+ "ADD R4.xyz, -R3, R4;\n"
+ "MUL R6.xyz, R3, R6;\n"
+ "MUL R4.xyz, R5, R4;\n"
+ "ADD R3.xyz, -R3, c[6].z;\n"
+ "MAD R2.xyz, R2, R3, R0.w;\n"
+ "MUL R3.xyz, R0, c[6].x;\n"
+ "MAD R5.xyz, R0.w, R1, R6;\n"
+ "MAD R4.xyz, R0.w, R1, R4;\n"
+ "ADD R6.xyz, R4, -R5;\n"
+ "MUL R4.xyz, R1, c[6].y;\n"
+ "SGE R4.xyz, R4, R1.w;\n"
+ "MAD R4.xyz, R4, R6, R5;\n"
+ "MAD R4.xyz, -R1, R2, R4;\n"
+ "MUL R2.xyz, R1, R2;\n"
+ "SGE R3.xyz, R3, R0.w;\n"
+ "MAD R2.xyz, R3, R4, R2;\n"
+ "ADD R2.w, -R1, c[6].z;\n"
+ "MAD R2.xyz, R0, R2.w, R2;\n"
+ "ADD R0.x, R0.w, R1.w;\n"
+ "ADD R0.y, -R0.w, c[6].z;\n"
+ "MAD result.color.xyz, R1, R0.y, R2;\n"
+ "MAD result.color.w, -R0, R1, R0.x;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_DIFFERENCE_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..3],\n"
- " { 2, 4 },\n"
- " program.local[5..6] };\n"
+ "PARAM c[7] = { program.local[0..5],\n"
+ " { 2, 4 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[3];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[4].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "MUL R1.xy, fragment.position, c[6];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.y, R0.x, c[6].x;\n"
+ "MUL R0.z, R0, c[6].y;\n"
+ "MAD R0.x, R0.y, R0.y, -R0.z;\n"
+ "RSQ R0.z, R0.x;\n"
+ "MOV R0.x, c[6];\n"
+ "MUL R0.w, R0.x, c[1].x;\n"
+ "RCP R0.z, R0.z;\n"
+ "ADD R0.x, -R0.y, R0.z;\n"
+ "RCP R0.y, R0.w;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "MUL R0.x, R0, R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
"MUL R2.xyz, R0, R1.w;\n"
- "MUL R3.xyz, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"ADD R0.xyz, R0, R1;\n"
"MIN R2.xyz, R2, R3;\n"
"ADD R1.x, R0.w, R1.w;\n"
- "MAD result.color.xyz, -R2, c[4].x, R0;\n"
+ "MAD result.color.xyz, -R2, c[6].x, R0;\n"
"MAD result.color.w, -R0, R1, R1.x;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_EXCLUSION_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..3],\n"
- " { 2, 4, 1 },\n"
- " program.local[5..6] };\n"
+ "PARAM c[7] = { program.local[0..5],\n"
+ " { 2, 4, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[3];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[4].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "MUL R1.xy, fragment.position, c[6];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.y, R0.x, c[6].x;\n"
+ "MUL R0.z, R0, c[6].y;\n"
+ "MAD R0.x, R0.y, R0.y, -R0.z;\n"
+ "RSQ R0.z, R0.x;\n"
+ "MOV R0.x, c[6];\n"
+ "MUL R0.w, R0.x, c[1].x;\n"
+ "RCP R0.z, R0.z;\n"
+ "ADD R0.x, -R0.y, R0.z;\n"
+ "RCP R0.y, R0.w;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "MUL R0.x, R0, R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
+ "MUL R2.xyz, R0.w, R1;\n"
"MAD R3.xyz, R0, R1.w, R2;\n"
"MUL R2.xyz, R0, R1;\n"
- "MAD R2.xyz, -R2, c[4].x, R3;\n"
- "ADD R2.w, -R1, c[4].z;\n"
+ "MAD R2.xyz, -R2, c[6].x, R3;\n"
+ "ADD R2.w, -R1, c[6].z;\n"
"MAD R0.xyz, R0, R2.w, R2;\n"
"ADD R2.x, R0.w, R1.w;\n"
- "ADD R2.y, -R0.w, c[4].z;\n"
+ "ADD R2.y, -R0.w, c[6].z;\n"
"MAD result.color.xyz, R1, R2.y, R0;\n"
"MAD result.color.w, -R0, R1, R2.x;\n"
"END\n"
@@ -2256,35 +2221,34 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODE_BLEND_MODE_MASK =
"!!ARBfp1.0\n"
- "PARAM c[9] = { program.local[0..3],\n"
- " { 2, 4 },\n"
- " program.local[5..8] };\n"
+ "PARAM c[9] = { program.local[0..7],\n"
+ " { 2, 4 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[3];\n"
"ADD R0.z, R0, R0.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.y, R0.z, c[8];\n"
+ "MUL R0.x, R0, c[8];\n"
"MAD R0.y, R0.x, R0.x, -R0;\n"
"RSQ R0.y, R0.y;\n"
"RCP R0.y, R0.y;\n"
"ADD R1.x, -R0, R0.y;\n"
- "MOV R0.z, c[4].x;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "RCP R1.y, R0.z;\n"
- "ADD R0.xy, fragment.position, c[6];\n"
- "MUL R0.xy, R0, c[7];\n"
- "TEX R0, R0, texture[0], 2D;\n"
+ "MOV R0.x, c[8];\n"
+ "MUL R0.x, R0, c[1];\n"
+ "RCP R1.y, R0.x;\n"
+ "ADD R0.zw, fragment.position.xyxy, c[6].xyxy;\n"
+ "MUL R0.zw, R0, c[5].xyxy;\n"
+ "TEX R0, R0.zwzw, texture[0], 2D;\n"
"MUL R1.x, R1, R1.y;\n"
- "DP4 R1.y, R0, c[8];\n"
+ "DP4 R1.y, R0, c[7];\n"
"TEX R0, R1, texture[1], 1D;\n"
"MUL result.color, R0, R1.y;\n"
"END\n"
@@ -2292,28 +2256,27 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODE_BLEND_MODE_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[6] = { program.local[0..3],\n"
- " { 2, 4 },\n"
- " program.local[5] };\n"
+ "PARAM c[6] = { program.local[0..4],\n"
+ " { 2, 4 } };\n"
"TEMP R0;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[3];\n"
+ "MAD R0.xyz, fragment.position.x, c[2], R0;\n"
+ "ADD R0.xyz, R0, c[4];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.xyxy;\n"
- "MUL R0.xy, R0, c[3];\n"
- "ADD R0.x, R0, R0.y;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.z, R0, R0.w;\n"
- "MUL R0.z, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[4].x;\n"
- "RSQ R0.y, R0.y;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "RCP R0.y, R0.y;\n"
- "RCP R0.z, R0.z;\n"
+ "ADD R0.x, R0, R0.y;\n"
+ "MUL R0.z, -R0, c[1].x;\n"
+ "MUL R0.y, R0.z, c[5];\n"
+ "MUL R0.x, R0, c[5];\n"
+ "MAD R0.z, R0.x, R0.x, -R0.y;\n"
+ "MOV R0.y, c[5].x;\n"
+ "RSQ R0.z, R0.z;\n"
+ "MUL R0.w, R0.y, c[1].x;\n"
+ "RCP R0.y, R0.z;\n"
+ "RCP R0.z, R0.w;\n"
"ADD R0.x, -R0, R0.y;\n"
"MUL R0.x, R0, R0.z;\n"
"TEX result.color, R0, texture[0], 1D;\n"
@@ -2322,450 +2285,450 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SIMPLE_PORTER_DUFF =
"!!ARBfp1.0\n"
- "PARAM c[13] = { program.local[0..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494 },\n"
- " program.local[10..12] };\n"
+ "PARAM c[13] = { program.local[0..9],\n"
+ " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n"
+ " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n"
+ " { 0.33299461, 0.99999559, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\n"
- "FLR R0.y, R0.x;\n"
- "MUL R0.zw, fragment.position.xyxy, c[10].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "ADD R0.x, R0, -R0.y;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R2.xyz, R1, c[12].y;\n"
- "MUL R3.xyz, R2, R0.w;\n"
- "MUL R2.xyz, R0, c[12].x;\n"
- "MAD R2.xyz, R2, R1.w, R3;\n"
- "ADD R3.xy, fragment.position, c[0];\n"
- "ADD R2.w, -R1, c[7];\n"
- "MUL R0.xyz, R0, c[11].y;\n"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "MUL R0.xyz, R1, c[11].z;\n"
- "ADD R3.z, -R0.w, c[7].w;\n"
- "MAD R2.xyz, R0, R3.z, R2;\n"
- "MUL R0.y, R0.w, R2.w;\n"
- "MUL R0.x, R0.w, R1.w;\n"
- "MUL R0.z, R1.w, R3;\n"
- "DP3 R2.w, R0, c[11];\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[10].y;\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[11].x, c[11].y;\n"
+ "MAD R1.z, R1, R1.y, -c[11];\n"
+ "MAD R1.z, R1, R1.y, c[11].w;\n"
+ "MAD R1.z, R1, R1.y, -c[12].x;\n"
+ "MAD R1.y, R1.z, R1, c[12];\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R1.y, -R1.x, c[10].w;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[10].z;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R1.x, R0, c[10];\n"
+ "FLR R1.y, R1.x;\n"
+ "MUL R0.xy, fragment.position, c[7];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "ADD R1.x, R1, -R1.y;\n"
+ "TEX R1, R1, texture[2], 1D;\n"
+ "MUL R2.xyz, R0, c[4].y;\n"
+ "MUL R3.xyz, R1.w, R2;\n"
+ "MUL R2.xyz, R1, c[4].x;\n"
+ "MAD R2.xyz, R0.w, R2, R3;\n"
+ "ADD R3.xy, fragment.position, c[8];\n"
+ "ADD R2.w, -R0, c[12].z;\n"
+ "MUL R1.xyz, R1, c[5].y;\n"
+ "MAD R2.xyz, R2.w, R1, R2;\n"
+ "MUL R1.xyz, R0, c[5].z;\n"
+ "ADD R3.z, -R1.w, c[12];\n"
+ "MAD R2.xyz, R3.z, R1, R2;\n"
+ "MUL R1.y, R1.w, R2.w;\n"
+ "MUL R1.x, R1.w, R0.w;\n"
+ "MUL R1.z, R0.w, R3;\n"
+ "DP3 R2.w, R1, c[5];\n"
+ "MUL R3.xy, R3, c[6];\n"
+ "TEX R1, R3, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[9];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_MULTIPLY =
"!!ARBfp1.0\n"
- "PARAM c[11] = { program.local[0..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494 },\n"
- " program.local[10] };\n"
+ "PARAM c[11] = { program.local[0..7],\n"
+ " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n"
+ " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n"
+ " { 0.33299461, 0.99999559, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\n"
- "FLR R0.y, R0.x;\n"
- "MUL R0.zw, fragment.position.xyxy, c[10].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "ADD R0.x, R0, -R0.y;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "ADD R2.x, -R1.w, c[7].w;\n"
- "MUL R2.xyz, R0, R2.x;\n"
- "MAD R0.xyz, R0, R1, R2;\n"
- "ADD R2.x, -R0.w, c[7].w;\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[8].y;\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[9].x, c[9].y;\n"
+ "MAD R1.z, R1, R1.y, -c[9];\n"
+ "MAD R1.z, R1, R1.y, c[9].w;\n"
+ "MAD R1.z, R1, R1.y, -c[10].x;\n"
+ "MAD R1.y, R1.z, R1, c[10];\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R1.y, -R1.x, c[8].w;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[8].z;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R1.x, R0, c[8];\n"
+ "FLR R1.y, R1.x;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "ADD R1.x, R1, -R1.y;\n"
+ "TEX R1, R1, texture[2], 1D;\n"
+ "ADD R2.x, -R0.w, c[10].z;\n"
+ "MUL R2.xyz, R1, R2.x;\n"
+ "MAD R1.xyz, R1, R0, R2;\n"
+ "ADD R2.x, -R1.w, c[10].z;\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SCREEN =
"!!ARBfp1.0\n"
- "PARAM c[11] = { program.local[0..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494 },\n"
- " program.local[10] };\n"
+ "PARAM c[11] = { program.local[0..7],\n"
+ " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n"
+ " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n"
+ " { 0.33299461, 0.99999559 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ADD R3.xy, fragment.position, c[0];\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MUL R1.xy, fragment.position, c[10];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\n"
+ "ADD R3.xy, fragment.position, c[6];\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[8].y;\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[9].x, c[9].y;\n"
+ "MAD R1.z, R1, R1.y, -c[9];\n"
+ "MAD R1.z, R1, R1.y, c[9].w;\n"
+ "MAD R1.z, R1, R1.y, -c[10].x;\n"
+ "MAD R1.y, R1.z, R1, c[10];\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "ADD R1.y, -R1.x, c[8].w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[8].z;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.x, R0, c[8];\n"
"FLR R0.y, R0.x;\n"
- "ADD R0.x, R0, -R0.y;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "ADD R2, R0, R1;\n"
- "MAD R2, -R0, R1, R2;\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "ADD R0.z, R0.x, -R0.y;\n"
+ "TEX R1, R0.z, texture[2], 1D;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "ADD R2, R1, R0;\n"
+ "MAD R2, -R1, R0, R2;\n"
+ "MUL R3.xy, R3, c[4];\n"
+ "TEX R1, R3, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_OVERLAY =
"!!ARBfp1.0\n"
- "PARAM c[11] = { program.local[0..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494, 2 },\n"
- " program.local[10] };\n"
+ "PARAM c[11] = { program.local[0..7],\n"
+ " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n"
+ " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n"
+ " { 3.141593, 0.15915494, 2, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MUL R1.xy, fragment.position, c[10];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R2.w, -R1, c[7];\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[8];\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[8].y, c[8];\n"
+ "MAD R1.z, R1, R1.y, -c[8].w;\n"
+ "MAD R1.z, R1, R1.y, c[9].x;\n"
+ "MAD R1.z, R1, R1.y, -c[9].y;\n"
+ "MAD R1.y, R1.z, R1, c[9].z;\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "ADD R1.y, -R1.x, c[9].w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[10].x;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.x, R0, c[10].y;\n"
"FLR R0.y, R0.x;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[2], 1D;\n"
+ "MUL R1.xy, fragment.position, c[5];\n"
+ "TEX R1, R1, texture[0], 2D;\n"
+ "ADD R2.w, -R1, c[10];\n"
"ADD R3.xyz, R0.w, -R0;\n"
"ADD R2.xyz, R1.w, -R1;\n"
"MUL R2.xyz, R2, R3;\n"
- "MUL R2.xyz, R2, c[9].y;\n"
+ "MUL R2.xyz, R2, c[10].z;\n"
"MAD R2.xyz, R0.w, R1.w, -R2;\n"
"MUL R4.xyz, R0, R2.w;\n"
"MUL R3.xyz, R0, R1;\n"
"MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[7].w;\n"
- "MAD R3.xyz, R3, c[9].y, R4;\n"
+ "ADD R2.x, -R0.w, c[10].w;\n"
+ "MAD R3.xyz, R3, c[10].z, R4;\n"
"MAD R3.xyz, R1, R2.x, R3;\n"
"MAD R0.xyz, R1, R2.x, R0;\n"
- "MUL R2.xyz, R1, c[9].y;\n"
+ "MUL R2.xyz, R1, c[10].z;\n"
"ADD R0.xyz, R0, -R3;\n"
"SGE R2.xyz, R2, R1.w;\n"
"MAD R2.xyz, R2, R0, R3;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[6];\n"
+ "MUL R0.xy, R0, c[4];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_DARKEN =
"!!ARBfp1.0\n"
- "PARAM c[11] = { program.local[0..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494 },\n"
- " program.local[10] };\n"
+ "PARAM c[11] = { program.local[0..7],\n"
+ " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n"
+ " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n"
+ " { 0.33299461, 0.99999559, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MUL R1.xy, fragment.position, c[10];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\n"
- "FLR R0.y, R0.x;\n"
- "ADD R0.x, R0, -R0.y;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[8].y;\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[9].x, c[9].y;\n"
+ "MAD R1.z, R1, R1.y, -c[9];\n"
+ "MAD R1.z, R1, R1.y, c[9].w;\n"
+ "MAD R1.z, R1, R1.y, -c[10].x;\n"
+ "MAD R1.y, R1.z, R1, c[10];\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R1.y, -R1.x, c[8].w;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[8].z;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.z, R0.x, c[8].x;\n"
+ "FLR R0.w, R0.z;\n"
+ "ADD R1.x, R0.z, -R0.w;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "TEX R1, R1, texture[2], 1D;\n"
+ "MUL R3.xyz, R1.w, R0;\n"
+ "MUL R2.xyz, R1, R0.w;\n"
"MIN R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[7];\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[7].w;\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "ADD R2.w, -R0, c[10].z;\n"
+ "MAD R1.xyz, R1, R2.w, R2;\n"
+ "ADD R2.x, -R1.w, c[10].z;\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_LIGHTEN =
"!!ARBfp1.0\n"
- "PARAM c[11] = { program.local[0..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494 },\n"
- " program.local[10] };\n"
+ "PARAM c[11] = { program.local[0..7],\n"
+ " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n"
+ " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n"
+ " { 0.33299461, 0.99999559, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MUL R1.xy, fragment.position, c[10];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\n"
- "FLR R0.y, R0.x;\n"
- "ADD R0.x, R0, -R0.y;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[8].y;\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[9].x, c[9].y;\n"
+ "MAD R1.z, R1, R1.y, -c[9];\n"
+ "MAD R1.z, R1, R1.y, c[9].w;\n"
+ "MAD R1.z, R1, R1.y, -c[10].x;\n"
+ "MAD R1.y, R1.z, R1, c[10];\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R1.y, -R1.x, c[8].w;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[8].z;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.z, R0.x, c[8].x;\n"
+ "FLR R0.w, R0.z;\n"
+ "ADD R1.x, R0.z, -R0.w;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "TEX R1, R1, texture[2], 1D;\n"
+ "MUL R3.xyz, R1.w, R0;\n"
+ "MUL R2.xyz, R1, R0.w;\n"
"MAX R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[7];\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[7].w;\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "ADD R2.w, -R0, c[10].z;\n"
+ "MAD R1.xyz, R1, R2.w, R2;\n"
+ "ADD R2.x, -R1.w, c[10].z;\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_COLORDODGE =
"!!ARBfp1.0\n"
- "PARAM c[11] = { program.local[0..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494, 1e-06 },\n"
- " program.local[10] };\n"
+ "PARAM c[11] = { program.local[0..7],\n"
+ " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n"
+ " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n"
+ " { 3.141593, 0.15915494, 1, 1e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[8];\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[8].y, c[8];\n"
+ "MAD R1.z, R1, R1.y, -c[8].w;\n"
+ "MAD R1.z, R1, R1.y, c[9].x;\n"
+ "MAD R1.z, R1, R1.y, -c[9].y;\n"
+ "MAD R1.y, R1.z, R1, c[9].z;\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R1.y, -R1.x, c[9].w;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[10].x;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.x, R0, c[10].y;\n"
"FLR R0.y, R0.x;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[2], 1D;\n"
- "MAX R1.x, R0.w, c[9].y;\n"
+ "MAX R1.x, R0.w, c[10].w;\n"
"RCP R1.x, R1.x;\n"
- "MAD R1.xyz, -R0, R1.x, c[7].w;\n"
- "MAX R2.xyz, R1, c[9].y;\n"
- "MUL R1.xy, fragment.position, c[10];\n"
+ "MAD R1.xyz, -R0, R1.x, c[10].z;\n"
+ "MAX R2.xyz, R1, c[10].w;\n"
+ "MUL R1.xy, fragment.position, c[5];\n"
"TEX R1, R1, texture[0], 2D;\n"
- "ADD R2.w, -R0, c[7];\n"
+ "ADD R2.w, -R0, c[10].z;\n"
"MUL R3.xyz, R1, R2.w;\n"
- "ADD R2.w, -R1, c[7];\n"
+ "ADD R2.w, -R1, c[10].z;\n"
"MAD R4.xyz, R0, R2.w, R3;\n"
- "MUL R3.xyz, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"MUL R2.w, R0, R1;\n"
"MAD R0.xyz, R0, R1.w, R3;\n"
"SGE R0.xyz, R0, R2.w;\n"
@@ -2778,70 +2741,70 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
"MAD R2.xyz, R0, R4, R2;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[6];\n"
+ "MUL R0.xy, R0, c[4];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_COLORBURN =
"!!ARBfp1.0\n"
- "PARAM c[11] = { program.local[0..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494, 9.9999997e-06 },\n"
- " program.local[10] };\n"
+ "PARAM c[11] = { program.local[0..7],\n"
+ " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n"
+ " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n"
+ " { 3.141593, 0.15915494, 1, 9.9999997e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
"TEMP R5;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"ABS R0.w, R0.x;\n"
"ABS R0.z, R0.y;\n"
"ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[6].x;\n"
+ "ADD R1.x, R0.y, c[8];\n"
"ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
+ "CMP R0.y, -R0.z, R0, R1.x;\n"
"ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MUL R1.xy, fragment.position, c[10];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R2.w, -R1, c[7];\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\n"
+ "MAX R1.x, R0.w, R0.z;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.w, R0.z;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[8].y, c[8];\n"
+ "MAD R1.z, R1, R1.y, -c[8].w;\n"
+ "MAD R1.z, R1, R1.y, c[9].x;\n"
+ "MAD R1.z, R1, R1.y, -c[9].y;\n"
+ "MAD R1.y, R1.z, R1, c[9].z;\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R1.y, -R1.x, c[9].w;\n"
+ "ADD R0.z, -R0.w, R0;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[10].x;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.x, R0, c[10].y;\n"
"FLR R0.y, R0.x;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[2], 1D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
+ "MUL R2.xyz, R0.w, R1;\n"
"MAD R3.xyz, R0, R1.w, R2;\n"
"MAD R2.xyz, -R0.w, R1.w, R3;\n"
"MUL R4.xyz, R0.w, R2;\n"
- "MAX R2.xyz, R0, c[9].y;\n"
- "ADD R3.w, -R0, c[7];\n"
+ "MAX R2.xyz, R0, c[10].w;\n"
+ "ADD R2.w, -R1, c[10].z;\n"
+ "ADD R3.w, -R0, c[10].z;\n"
"MUL R5.xyz, R0, R2.w;\n"
"RCP R2.x, R2.x;\n"
"RCP R2.y, R2.y;\n"
@@ -2856,74 +2819,74 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
"MAD R2.xyz, R3, R2, R0;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[6];\n"
+ "MUL R0.xy, R0, c[4];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_HARDLIGHT =
"!!ARBfp1.0\n"
- "PARAM c[11] = { program.local[0..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494, 2 },\n"
- " program.local[10] };\n"
+ "PARAM c[11] = { program.local[0..7],\n"
+ " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n"
+ " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n"
+ " { 3.141593, 0.15915494, 2, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MUL R1.xy, fragment.position, c[10];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R2.w, -R1, c[7];\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[8];\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[8].y, c[8];\n"
+ "MAD R1.z, R1, R1.y, -c[8].w;\n"
+ "MAD R1.z, R1, R1.y, c[9].x;\n"
+ "MAD R1.z, R1, R1.y, -c[9].y;\n"
+ "MAD R1.y, R1.z, R1, c[9].z;\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "ADD R1.y, -R1.x, c[9].w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[10].x;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.x, R0, c[10].y;\n"
"FLR R0.y, R0.x;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[2], 1D;\n"
+ "MUL R1.xy, fragment.position, c[5];\n"
+ "TEX R1, R1, texture[0], 2D;\n"
+ "ADD R2.w, -R1, c[10];\n"
"ADD R3.xyz, R0.w, -R0;\n"
"ADD R2.xyz, R1.w, -R1;\n"
"MUL R2.xyz, R2, R3;\n"
- "MUL R2.xyz, R2, c[9].y;\n"
+ "MUL R2.xyz, R2, c[10].z;\n"
"MAD R2.xyz, R0.w, R1.w, -R2;\n"
"MUL R4.xyz, R0, R2.w;\n"
"MAD R2.xyz, R0, R2.w, R2;\n"
"MUL R3.xyz, R0, R1;\n"
- "ADD R2.w, -R0, c[7];\n"
- "MAD R3.xyz, R3, c[9].y, R4;\n"
- "MUL R0.xyz, R0, c[9].y;\n"
+ "ADD R2.w, -R0, c[10];\n"
+ "MAD R3.xyz, R3, c[10].z, R4;\n"
+ "MUL R0.xyz, R0, c[10].z;\n"
"SGE R0.xyz, R0, R0.w;\n"
"MAD R3.xyz, R1, R2.w, R3;\n"
"MAD R2.xyz, R1, R2.w, R2;\n"
@@ -2931,23 +2894,22 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
"MAD R2.xyz, R0, R2, R3;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[6];\n"
+ "MUL R0.xy, R0, c[4];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SOFTLIGHT =
"!!ARBfp1.0\n"
- "PARAM c[12] = { program.local[0..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494, 9.9999997e-06, 2, 8 },\n"
- " program.local[10],\n"
+ "PARAM c[13] = { program.local[0..7],\n"
+ " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n"
+ " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n"
+ " { 3.141593, 0.15915494, 1, 2 },\n"
+ " { 9.9999997e-006, 4, 16, 12 },\n"
" { 3 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
@@ -2956,326 +2918,327 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
"TEMP R4;\n"
"TEMP R5;\n"
"TEMP R6;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"ABS R0.w, R0.x;\n"
"ABS R0.z, R0.y;\n"
"ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[6].x;\n"
+ "ADD R1.x, R0.y, c[8];\n"
"ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
+ "CMP R0.y, -R0.z, R0, R1.x;\n"
"ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MOV R1.x, c[7].y;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MUL R0.zw, fragment.position.xyxy, c[10].xyxy;\n"
+ "MAX R1.x, R0.w, R0.z;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.w, R0.z;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[8].y, c[8];\n"
+ "MAD R1.z, R1, R1.y, -c[8].w;\n"
+ "MAD R1.z, R1, R1.y, c[9].x;\n"
+ "MAD R1.z, R1, R1.y, -c[9].y;\n"
+ "MAD R1.y, R1.z, R1, c[9].z;\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R1.y, -R1.x, c[9].w;\n"
+ "ADD R0.z, -R0.w, R0;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[10].x;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n"
"TEX R1, R0.zwzw, texture[0], 2D;\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "MAX R0.z, R1.w, c[11].x;\n"
+ "RCP R2.x, R0.z;\n"
+ "MUL R3.xyz, R1, R2.x;\n"
+ "MAD R4.xyz, R3, c[11].z, -c[11].w;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.x, R0, c[10].y;\n"
"FLR R0.y, R0.x;\n"
- "MAX R0.z, R1.w, c[9].y;\n"
- "RCP R2.w, R0.z;\n"
- "MUL R2.xyz, R1, R2.w;\n"
- "RSQ R3.w, R2.x;\n"
- "RSQ R4.y, R2.z;\n"
- "RCP R4.x, R3.w;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[2], 1D;\n"
- "MAD R3.xyz, R0, c[9].z, -R0.w;\n"
- "RSQ R3.w, R2.y;\n"
- "RCP R4.z, R4.y;\n"
- "RCP R4.y, R3.w;\n"
- "MAD R4.xyz, R4, R1.w, -R1;\n"
- "MUL R6.xyz, R4, R3;\n"
- "MUL R4.xyz, -R2, c[9].w;\n"
- "MAD R2.xyz, -R1, R2.w, c[7].w;\n"
- "ADD R5.xyz, R4, c[11].x;\n"
- "MUL R4.xyz, R2, R3;\n"
- "MAD R4.xyz, -R4, R5, R0.w;\n"
- "MAD R2.xyz, -R2, R3, R0.w;\n"
- "MAD R5.xyz, R1, R0.w, R6;\n"
- "MUL R4.xyz, R1, R4;\n"
- "MUL R6.xyz, R1, c[9].w;\n"
- "ADD R5.xyz, R5, -R4;\n"
- "SGE R6.xyz, R6, R1.w;\n"
- "MUL R5.xyz, R6, R5;\n"
- "ADD R3.xyz, R4, R5;\n"
+ "MAD R2.xyz, R0, c[10].w, -R0.w;\n"
+ "MAD R4.xyz, R3, R4, c[12].x;\n"
+ "MUL R5.xyz, R1.w, R2;\n"
+ "MUL R6.xyz, R5, R4;\n"
+ "RSQ R2.w, R3.x;\n"
+ "RCP R4.x, R2.w;\n"
+ "RSQ R2.w, R3.y;\n"
+ "RSQ R3.w, R3.z;\n"
+ "RCP R4.y, R2.w;\n"
+ "RCP R4.z, R3.w;\n"
+ "ADD R4.xyz, -R3, R4;\n"
+ "MUL R6.xyz, R3, R6;\n"
+ "MUL R4.xyz, R5, R4;\n"
+ "ADD R3.xyz, -R3, c[10].z;\n"
+ "MAD R2.xyz, R2, R3, R0.w;\n"
+ "MUL R3.xyz, R0, c[10].w;\n"
+ "MAD R5.xyz, R0.w, R1, R6;\n"
+ "MAD R4.xyz, R0.w, R1, R4;\n"
+ "ADD R6.xyz, R4, -R5;\n"
+ "MUL R4.xyz, R1, c[11].y;\n"
+ "SGE R4.xyz, R4, R1.w;\n"
+ "MAD R4.xyz, R4, R6, R5;\n"
+ "MAD R4.xyz, -R1, R2, R4;\n"
+ "SGE R3.xyz, R3, R0.w;\n"
"MUL R2.xyz, R1, R2;\n"
- "MUL R4.xyz, R0, c[9].z;\n"
- "ADD R3.xyz, R3, -R2;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "MUL R3.xyz, R4, R3;\n"
- "ADD R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[7];\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[7].w;\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
+ "ADD R2.w, -R1, c[10].z;\n"
+ "MAD R2.xyz, R3, R4, R2;\n"
+ "MAD R2.xyz, R0, R2.w, R2;\n"
+ "ADD R0.x, -R0.w, c[10].z;\n"
+ "MAD R2.xyz, R1, R0.x, R2;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[6];\n"
+ "MUL R0.xy, R0, c[4];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_DIFFERENCE =
"!!ARBfp1.0\n"
- "PARAM c[11] = { program.local[0..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494, 2 },\n"
- " program.local[10] };\n"
+ "PARAM c[11] = { program.local[0..7],\n"
+ " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n"
+ " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n"
+ " { 0.33299461, 0.99999559, 2 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\n"
- "FLR R0.y, R0.x;\n"
- "MUL R0.zw, fragment.position.xyxy, c[10].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "ADD R0.x, R0, -R0.y;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "ADD R3.xyz, R0, R1;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MUL R0.xyz, R0, R1.w;\n"
- "MIN R0.xyz, R0, R2;\n"
- "MAD R2.xyz, -R0, c[9].y, R3;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[8].y;\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[9].x, c[9].y;\n"
+ "MAD R1.z, R1, R1.y, -c[9];\n"
+ "MAD R1.z, R1, R1.y, c[9].w;\n"
+ "MAD R1.z, R1, R1.y, -c[10].x;\n"
+ "MAD R1.y, R1.z, R1, c[10];\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R1.y, -R1.x, c[8].w;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[8].z;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.z, R0.x, c[8].x;\n"
+ "FLR R0.w, R0.z;\n"
+ "ADD R1.x, R0.z, -R0.w;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "TEX R1, R1, texture[2], 1D;\n"
+ "ADD R2.xyz, R1, R0;\n"
+ "MUL R3.xyz, R1.w, R0;\n"
+ "MUL R1.xyz, R1, R0.w;\n"
+ "MIN R1.xyz, R1, R3;\n"
+ "MAD R2.xyz, -R1, c[10].z, R2;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_EXCLUSION =
"!!ARBfp1.0\n"
- "PARAM c[11] = { program.local[0..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494, 2 },\n"
- " program.local[10] };\n"
+ "PARAM c[11] = { program.local[0..7],\n"
+ " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n"
+ " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n"
+ " { 0.33299461, 0.99999559, 2, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MUL R1.xy, fragment.position, c[10];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\n"
- "FLR R0.y, R0.x;\n"
- "ADD R0.x, R0, -R0.y;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MAD R3.xyz, R0, R1.w, R2;\n"
- "MUL R2.xyz, R0, R1;\n"
- "MAD R2.xyz, -R2, c[9].y, R3;\n"
- "ADD R2.w, -R1, c[7];\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[7].w;\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[8].y;\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[9].x, c[9].y;\n"
+ "MAD R1.z, R1, R1.y, -c[9];\n"
+ "MAD R1.z, R1, R1.y, c[9].w;\n"
+ "MAD R1.z, R1, R1.y, -c[10].x;\n"
+ "MAD R1.y, R1.z, R1, c[10];\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R1.y, -R1.x, c[8].w;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[8].z;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.z, R0.x, c[8].x;\n"
+ "FLR R0.w, R0.z;\n"
+ "ADD R1.x, R0.z, -R0.w;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "TEX R1, R1, texture[2], 1D;\n"
+ "MUL R2.xyz, R1.w, R0;\n"
+ "MAD R3.xyz, R1, R0.w, R2;\n"
+ "MUL R2.xyz, R1, R0;\n"
+ "MAD R2.xyz, -R2, c[10].z, R3;\n"
+ "ADD R2.w, -R0, c[10];\n"
+ "MAD R1.xyz, R1, R2.w, R2;\n"
+ "ADD R2.x, -R1.w, c[10].w;\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[10] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494 },\n"
- " program.local[7..9] };\n"
+ "PARAM c[10] = { program.local[0..6],\n"
+ " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n"
+ " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n"
+ " { 0.33299461, 0.99999559, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, c[6];\n"
- "FLR R0.y, R0.x;\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[7].y;\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[8].x, c[8].y;\n"
+ "MAD R1.z, R1, R1.y, -c[8];\n"
+ "MAD R1.z, R1, R1.y, c[8].w;\n"
+ "MAD R1.z, R1, R1.y, -c[9].x;\n"
+ "MAD R1.y, R1.z, R1, c[9];\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "ADD R1.y, -R1.x, c[7].w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[7].z;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\n"
"TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MUL R2.xyz, R1, c[9].y;\n"
+ "MUL R2.xyz, R1, c[4].y;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.x, R0, c[7];\n"
+ "FLR R0.y, R0.x;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
- "MUL R3.xyz, R2, R0.w;\n"
- "MUL R2.xyz, R0, c[9].x;\n"
- "MAD R2.xyz, R2, R1.w, R3;\n"
- "ADD R2.w, -R1, c[4];\n"
- "MUL R0.xyz, R0, c[8].y;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[4].w;\n"
- "MUL R1.xyz, R1, c[8].z;\n"
- "MAD result.color.xyz, R1, R2.x, R0;\n"
+ "MUL R3.xyz, R0.w, R2;\n"
+ "MUL R2.xyz, R0, c[4].x;\n"
+ "MAD R2.xyz, R1.w, R2, R3;\n"
+ "ADD R2.w, -R1, c[9].z;\n"
+ "MUL R0.xyz, R0, c[5].y;\n"
+ "MAD R0.xyz, R2.w, R0, R2;\n"
+ "ADD R2.x, -R0.w, c[9].z;\n"
+ "MUL R1.xyz, R1, c[5].z;\n"
+ "MAD result.color.xyz, R2.x, R1, R0;\n"
"MUL R0.x, R0.w, R1.w;\n"
"MUL R0.z, R1.w, R2.x;\n"
"MUL R0.y, R0.w, R2.w;\n"
- "DP3 result.color.w, R0, c[8];\n"
+ "DP3 result.color.w, R0, c[5];\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_MULTIPLY_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494 },\n"
- " program.local[7] };\n"
+ "PARAM c[8] = { program.local[0..4],\n"
+ " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n"
+ " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n"
+ " { 0.33299461, 0.99999559, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, c[6];\n"
- "FLR R0.y, R0.x;\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[5].y;\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[6].x, c[6].y;\n"
+ "MAD R1.z, R1, R1.y, -c[6];\n"
+ "MAD R1.z, R1, R1.y, c[6].w;\n"
+ "MAD R1.z, R1, R1.y, -c[7].x;\n"
+ "MAD R1.y, R1.z, R1, c[7];\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "ADD R1.y, -R1.x, c[5].w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[5].z;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
"TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.x, R0, c[5];\n"
+ "FLR R0.y, R0.x;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
- "ADD R2.x, -R1.w, c[4].w;\n"
+ "ADD R2.x, -R1.w, c[7].z;\n"
"MUL R2.xyz, R0, R2.x;\n"
"MAD R0.xyz, R0, R1, R2;\n"
"ADD R2.x, R0.w, R1.w;\n"
- "ADD R2.y, -R0.w, c[4].w;\n"
+ "ADD R2.y, -R0.w, c[7].z;\n"
"MAD result.color.xyz, R1, R2.y, R0;\n"
"MAD result.color.w, -R0, R1, R2.x;\n"
"END\n"
@@ -3283,46 +3246,46 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SCREEN_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494 },\n"
- " program.local[7] };\n"
+ "PARAM c[8] = { program.local[0..4],\n"
+ " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n"
+ " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n"
+ " { 0.33299461, 0.99999559 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, c[6];\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[5].y;\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[6].x, c[6].y;\n"
+ "MAD R1.z, R1, R1.y, -c[6];\n"
+ "MAD R1.z, R1, R1.y, c[6].w;\n"
+ "MAD R1.z, R1, R1.y, -c[7].x;\n"
+ "MAD R1.y, R1.z, R1, c[7];\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "ADD R1.y, -R1.x, c[5].w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[5].z;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.x, R0, c[5];\n"
"FLR R0.y, R0.x;\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
"TEX R1, R0.zwzw, texture[0], 2D;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
@@ -3333,64 +3296,64 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_OVERLAY_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494, 2 },\n"
- " program.local[7] };\n"
+ "PARAM c[8] = { program.local[0..4],\n"
+ " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n"
+ " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n"
+ " { 3.141593, 0.15915494, 2, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R2.w, -R1, c[4];\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, c[6];\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[5];\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[5].y, c[5];\n"
+ "MAD R1.z, R1, R1.y, -c[5].w;\n"
+ "MAD R1.z, R1, R1.y, c[6].x;\n"
+ "MAD R1.z, R1, R1.y, -c[6].y;\n"
+ "MAD R1.y, R1.z, R1, c[6].z;\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "ADD R1.y, -R1.x, c[6].w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[7].x;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.x, R0, c[7].y;\n"
"FLR R0.y, R0.x;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
+ "MUL R1.xy, fragment.position, c[4];\n"
+ "TEX R1, R1, texture[0], 2D;\n"
"ADD R3.xyz, R0.w, -R0;\n"
"ADD R2.xyz, R1.w, -R1;\n"
"MUL R2.xyz, R2, R3;\n"
- "MUL R2.xyz, R2, c[6].y;\n"
+ "ADD R2.w, -R1, c[7];\n"
+ "MUL R2.xyz, R2, c[7].z;\n"
"MAD R2.xyz, R0.w, R1.w, -R2;\n"
"MAD R2.xyz, R0, R2.w, R2;\n"
"MUL R3.xyz, R0, R2.w;\n"
"MUL R0.xyz, R0, R1;\n"
- "ADD R2.w, -R0, c[4];\n"
- "MAD R0.xyz, R0, c[6].y, R3;\n"
+ "ADD R2.w, -R0, c[7];\n"
+ "MAD R0.xyz, R0, c[7].z, R3;\n"
"MAD R0.xyz, R1, R2.w, R0;\n"
"MAD R2.xyz, R1, R2.w, R2;\n"
- "MUL R1.xyz, R1, c[6].y;\n"
+ "MUL R1.xyz, R1, c[7].z;\n"
"ADD R2.w, R0, R1;\n"
"ADD R2.xyz, R2, -R0;\n"
"SGE R1.xyz, R1, R1.w;\n"
@@ -3401,57 +3364,57 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_DARKEN_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494 },\n"
- " program.local[7] };\n"
+ "PARAM c[8] = { program.local[0..4],\n"
+ " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n"
+ " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n"
+ " { 0.33299461, 0.99999559, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, c[6];\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[5].y;\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[6].x, c[6].y;\n"
+ "MAD R1.z, R1, R1.y, -c[6];\n"
+ "MAD R1.z, R1, R1.y, c[6].w;\n"
+ "MAD R1.z, R1, R1.y, -c[7].x;\n"
+ "MAD R1.y, R1.z, R1, c[7];\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "ADD R1.y, -R1.x, c[5].w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[5].z;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.x, R0, c[5];\n"
"FLR R0.y, R0.x;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
"MUL R2.xyz, R0, R1.w;\n"
- "MUL R3.xyz, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"MIN R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[4];\n"
+ "ADD R2.w, -R1, c[7].z;\n"
"MAD R0.xyz, R0, R2.w, R2;\n"
"ADD R2.x, R0.w, R1.w;\n"
- "ADD R2.y, -R0.w, c[4].w;\n"
+ "ADD R2.y, -R0.w, c[7].z;\n"
"MAD result.color.xyz, R1, R2.y, R0;\n"
"MAD result.color.w, -R0, R1, R2.x;\n"
"END\n"
@@ -3459,57 +3422,57 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_LIGHTEN_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494 },\n"
- " program.local[7] };\n"
+ "PARAM c[8] = { program.local[0..4],\n"
+ " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n"
+ " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n"
+ " { 0.33299461, 0.99999559, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, c[6];\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[5].y;\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[6].x, c[6].y;\n"
+ "MAD R1.z, R1, R1.y, -c[6];\n"
+ "MAD R1.z, R1, R1.y, c[6].w;\n"
+ "MAD R1.z, R1, R1.y, -c[7].x;\n"
+ "MAD R1.y, R1.z, R1, c[7];\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "ADD R1.y, -R1.x, c[5].w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[5].z;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.x, R0, c[5];\n"
"FLR R0.y, R0.x;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
"MUL R2.xyz, R0, R1.w;\n"
- "MUL R3.xyz, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"MAX R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[4];\n"
+ "ADD R2.w, -R1, c[7].z;\n"
"MAD R0.xyz, R0, R2.w, R2;\n"
"ADD R2.x, R0.w, R1.w;\n"
- "ADD R2.y, -R0.w, c[4].w;\n"
+ "ADD R2.y, -R0.w, c[7].z;\n"
"MAD result.color.xyz, R1, R2.y, R0;\n"
"MAD result.color.w, -R0, R1, R2.x;\n"
"END\n"
@@ -3517,59 +3480,59 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_COLORDODGE_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494, 1e-06 },\n"
- " program.local[7] };\n"
+ "PARAM c[8] = { program.local[0..4],\n"
+ " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n"
+ " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n"
+ " { 3.141593, 0.15915494, 1, 1e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, c[6];\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[5];\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[5].y, c[5];\n"
+ "MAD R1.z, R1, R1.y, -c[5].w;\n"
+ "MAD R1.z, R1, R1.y, c[6].x;\n"
+ "MAD R1.z, R1, R1.y, -c[6].y;\n"
+ "MAD R1.y, R1.z, R1, c[6].z;\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R1.y, -R1.x, c[6].w;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[7].x;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.x, R0, c[7].y;\n"
"FLR R0.y, R0.x;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
- "MAX R1.x, R0.w, c[6].y;\n"
+ "MAX R1.x, R0.w, c[7].w;\n"
"RCP R1.x, R1.x;\n"
- "MAD R1.xyz, -R0, R1.x, c[4].w;\n"
- "MAX R2.xyz, R1, c[6].y;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
+ "MAD R1.xyz, -R0, R1.x, c[7].z;\n"
+ "MAX R2.xyz, R1, c[7].w;\n"
+ "MUL R1.xy, fragment.position, c[4];\n"
"TEX R1, R1, texture[0], 2D;\n"
- "ADD R2.w, -R0, c[4];\n"
+ "ADD R2.w, -R0, c[7].z;\n"
"MUL R3.xyz, R1, R2.w;\n"
- "ADD R2.w, -R1, c[4];\n"
+ "ADD R2.w, -R1, c[7].z;\n"
"MAD R3.xyz, R0, R2.w, R3;\n"
- "MUL R1.xyz, R1, R0.w;\n"
+ "MUL R1.xyz, R0.w, R1;\n"
"MAD R0.xyz, R0, R1.w, R1;\n"
"MUL R2.w, R0, R1;\n"
"RCP R2.x, R2.x;\n"
@@ -3587,60 +3550,60 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_COLORBURN_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494, 9.9999997e-06 },\n"
- " program.local[7] };\n"
+ "PARAM c[8] = { program.local[0..4],\n"
+ " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n"
+ " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n"
+ " { 3.141593, 0.15915494, 1, 9.9999997e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
"TEMP R5;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"ABS R0.w, R0.x;\n"
"ABS R0.z, R0.y;\n"
"ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[3].x;\n"
+ "ADD R1.x, R0.y, c[5];\n"
"ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
+ "CMP R0.y, -R0.z, R0, R1.x;\n"
"ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R2.w, -R1, c[4];\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, c[6];\n"
+ "MAX R1.x, R0.w, R0.z;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.w, R0.z;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[5].y, c[5];\n"
+ "MAD R1.z, R1, R1.y, -c[5].w;\n"
+ "MAD R1.z, R1, R1.y, c[6].x;\n"
+ "MAD R1.z, R1, R1.y, -c[6].y;\n"
+ "MAD R1.y, R1.z, R1, c[6].z;\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R1.y, -R1.x, c[6].w;\n"
+ "ADD R0.z, -R0.w, R0;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[7].x;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.x, R0, c[7].y;\n"
"FLR R0.y, R0.x;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
+ "MUL R2.xyz, R0.w, R1;\n"
"MAD R3.xyz, R0, R1.w, R2;\n"
+ "ADD R2.w, -R1, c[7].z;\n"
"MAD R2.xyz, -R0.w, R1.w, R3;\n"
"MUL R4.xyz, R0.w, R2;\n"
- "MAX R2.xyz, R0, c[6].y;\n"
+ "MAX R2.xyz, R0, c[7].w;\n"
"MUL R5.xyz, R0, R2.w;\n"
- "ADD R3.w, -R0, c[4];\n"
+ "ADD R3.w, -R0, c[7].z;\n"
"RCP R2.x, R2.x;\n"
"RCP R2.y, R2.y;\n"
"RCP R2.z, R2.z;\n"
@@ -3659,64 +3622,64 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_HARDLIGHT_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494, 2 },\n"
- " program.local[7] };\n"
+ "PARAM c[8] = { program.local[0..4],\n"
+ " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n"
+ " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n"
+ " { 3.141593, 0.15915494, 2, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R2.w, -R1, c[4];\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, c[6];\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[5];\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[5].y, c[5];\n"
+ "MAD R1.z, R1, R1.y, -c[5].w;\n"
+ "MAD R1.z, R1, R1.y, c[6].x;\n"
+ "MAD R1.z, R1, R1.y, -c[6].y;\n"
+ "MAD R1.y, R1.z, R1, c[6].z;\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "ADD R1.y, -R1.x, c[6].w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[7].x;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.x, R0, c[7].y;\n"
"FLR R0.y, R0.x;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
+ "MUL R1.xy, fragment.position, c[4];\n"
+ "TEX R1, R1, texture[0], 2D;\n"
+ "ADD R2.w, -R1, c[7];\n"
"ADD R3.xyz, R0.w, -R0;\n"
"ADD R2.xyz, R1.w, -R1;\n"
"MUL R2.xyz, R2, R3;\n"
- "MUL R2.xyz, R2, c[6].y;\n"
+ "MUL R2.xyz, R2, c[7].z;\n"
"MAD R2.xyz, R0.w, R1.w, -R2;\n"
"MUL R4.xyz, R0, R2.w;\n"
"MUL R3.xyz, R0, R1;\n"
"MAD R2.xyz, R0, R2.w, R2;\n"
- "ADD R2.w, -R0, c[4];\n"
- "MUL R0.xyz, R0, c[6].y;\n"
+ "ADD R2.w, -R0, c[7];\n"
+ "MUL R0.xyz, R0, c[7].z;\n"
"MAD R2.xyz, R1, R2.w, R2;\n"
- "MAD R3.xyz, R3, c[6].y, R4;\n"
+ "MAD R3.xyz, R3, c[7].z, R4;\n"
"MAD R1.xyz, R1, R2.w, R3;\n"
"ADD R2.w, R0, R1;\n"
"ADD R2.xyz, R2, -R1;\n"
@@ -3728,12 +3691,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SOFTLIGHT_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[9] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494, 9.9999997e-06, 2, 8 },\n"
- " program.local[7],\n"
+ "PARAM c[10] = { program.local[0..4],\n"
+ " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n"
+ " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n"
+ " { 3.141593, 0.15915494, 1, 2 },\n"
+ " { 9.9999997e-006, 4, 16, 12 },\n"
" { 3 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
@@ -3742,190 +3704,191 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
"TEMP R4;\n"
"TEMP R5;\n"
"TEMP R6;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
"ABS R0.w, R0.x;\n"
"ABS R0.z, R0.y;\n"
"ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[3].x;\n"
+ "ADD R1.x, R0.y, c[5];\n"
"ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
+ "CMP R0.y, -R0.z, R0, R1.x;\n"
"ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MOV R1.x, c[4].y;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
+ "MAX R1.x, R0.w, R0.z;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.w, R0.z;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[5].y, c[5];\n"
+ "MAD R1.z, R1, R1.y, -c[5].w;\n"
+ "MAD R1.z, R1, R1.y, c[6].x;\n"
+ "MAD R1.z, R1, R1.y, -c[6].y;\n"
+ "MAD R1.y, R1.z, R1, c[6].z;\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R1.y, -R1.x, c[6].w;\n"
+ "ADD R0.z, -R0.w, R0;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[7].x;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
"TEX R1, R0.zwzw, texture[0], 2D;\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, c[6];\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "MAX R0.z, R1.w, c[8].x;\n"
+ "RCP R2.x, R0.z;\n"
+ "MUL R3.xyz, R1, R2.x;\n"
+ "MAD R4.xyz, R3, c[8].z, -c[8].w;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.x, R0, c[7].y;\n"
"FLR R0.y, R0.x;\n"
- "MAX R0.z, R1.w, c[6].y;\n"
- "RCP R2.w, R0.z;\n"
- "MUL R2.xyz, R1, R2.w;\n"
- "RSQ R3.w, R2.x;\n"
- "RSQ R4.y, R2.z;\n"
- "RCP R4.x, R3.w;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
- "MAD R3.xyz, R0, c[6].z, -R0.w;\n"
- "RSQ R3.w, R2.y;\n"
- "RCP R4.z, R4.y;\n"
- "RCP R4.y, R3.w;\n"
- "MAD R4.xyz, R4, R1.w, -R1;\n"
- "MUL R6.xyz, R4, R3;\n"
- "MUL R4.xyz, -R2, c[6].w;\n"
- "MAD R2.xyz, -R1, R2.w, c[4].w;\n"
- "ADD R5.xyz, R4, c[8].x;\n"
- "MUL R4.xyz, R2, R3;\n"
- "MAD R4.xyz, -R4, R5, R0.w;\n"
- "MAD R2.xyz, -R2, R3, R0.w;\n"
- "MAD R5.xyz, R1, R0.w, R6;\n"
- "MUL R4.xyz, R1, R4;\n"
- "MUL R6.xyz, R1, c[6].w;\n"
- "ADD R5.xyz, R5, -R4;\n"
- "SGE R6.xyz, R6, R1.w;\n"
- "MUL R5.xyz, R6, R5;\n"
- "ADD R3.xyz, R4, R5;\n"
+ "MAD R2.xyz, R0, c[7].w, -R0.w;\n"
+ "MAD R4.xyz, R3, R4, c[9].x;\n"
+ "MUL R5.xyz, R1.w, R2;\n"
+ "MUL R6.xyz, R5, R4;\n"
+ "RSQ R2.w, R3.x;\n"
+ "RCP R4.x, R2.w;\n"
+ "RSQ R2.w, R3.y;\n"
+ "RSQ R3.w, R3.z;\n"
+ "RCP R4.y, R2.w;\n"
+ "RCP R4.z, R3.w;\n"
+ "ADD R4.xyz, -R3, R4;\n"
+ "MUL R6.xyz, R3, R6;\n"
+ "MUL R4.xyz, R5, R4;\n"
+ "ADD R3.xyz, -R3, c[7].z;\n"
+ "MAD R2.xyz, R2, R3, R0.w;\n"
+ "MUL R3.xyz, R0, c[7].w;\n"
+ "MAD R5.xyz, R0.w, R1, R6;\n"
+ "MAD R4.xyz, R0.w, R1, R4;\n"
+ "ADD R6.xyz, R4, -R5;\n"
+ "MUL R4.xyz, R1, c[8].y;\n"
+ "SGE R4.xyz, R4, R1.w;\n"
+ "MAD R4.xyz, R4, R6, R5;\n"
+ "MAD R4.xyz, -R1, R2, R4;\n"
"MUL R2.xyz, R1, R2;\n"
- "MUL R4.xyz, R0, c[6].z;\n"
- "ADD R3.xyz, R3, -R2;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "MUL R3.xyz, R4, R3;\n"
- "ADD R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[4];\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, R0.w, R1.w;\n"
- "ADD R2.y, -R0.w, c[4].w;\n"
- "MAD result.color.xyz, R1, R2.y, R0;\n"
- "MAD result.color.w, -R0, R1, R2.x;\n"
+ "SGE R3.xyz, R3, R0.w;\n"
+ "MAD R2.xyz, R3, R4, R2;\n"
+ "ADD R2.w, -R1, c[7].z;\n"
+ "MAD R2.xyz, R0, R2.w, R2;\n"
+ "ADD R0.x, R0.w, R1.w;\n"
+ "ADD R0.y, -R0.w, c[7].z;\n"
+ "MAD result.color.xyz, R1, R0.y, R2;\n"
+ "MAD result.color.w, -R0, R1, R0.x;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_DIFFERENCE_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494, 2 },\n"
- " program.local[7] };\n"
+ "PARAM c[8] = { program.local[0..4],\n"
+ " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n"
+ " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n"
+ " { 0.33299461, 0.99999559, 2 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, c[6];\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[5].y;\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[6].x, c[6].y;\n"
+ "MAD R1.z, R1, R1.y, -c[6];\n"
+ "MAD R1.z, R1, R1.y, c[6].w;\n"
+ "MAD R1.z, R1, R1.y, -c[7].x;\n"
+ "MAD R1.y, R1.z, R1, c[7];\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "ADD R1.y, -R1.x, c[5].w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[5].z;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.x, R0, c[5];\n"
"FLR R0.y, R0.x;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
"MUL R2.xyz, R0, R1.w;\n"
- "MUL R3.xyz, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"ADD R0.xyz, R0, R1;\n"
"MIN R2.xyz, R2, R3;\n"
"ADD R1.x, R0.w, R1.w;\n"
- "MAD result.color.xyz, -R2, c[6].y, R0;\n"
+ "MAD result.color.xyz, -R2, c[7].z, R0;\n"
"MAD result.color.w, -R0, R1, R1.x;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_EXCLUSION_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494, 2 },\n"
- " program.local[7] };\n"
+ "PARAM c[8] = { program.local[0..4],\n"
+ " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n"
+ " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n"
+ " { 0.33299461, 0.99999559, 2, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, c[6];\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[5].y;\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[6].x, c[6].y;\n"
+ "MAD R1.z, R1, R1.y, -c[6];\n"
+ "MAD R1.z, R1, R1.y, c[6].w;\n"
+ "MAD R1.z, R1, R1.y, -c[7].x;\n"
+ "MAD R1.y, R1.z, R1, c[7];\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "ADD R1.y, -R1.x, c[5].w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[5].z;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.x, R0, c[5];\n"
"FLR R0.y, R0.x;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
+ "MUL R2.xyz, R0.w, R1;\n"
"MAD R3.xyz, R0, R1.w, R2;\n"
"MUL R2.xyz, R0, R1;\n"
- "MAD R2.xyz, -R2, c[6].y, R3;\n"
- "ADD R2.w, -R1, c[4];\n"
+ "MAD R2.xyz, -R2, c[7].z, R3;\n"
+ "ADD R2.w, -R1, c[7];\n"
"MAD R0.xyz, R0, R2.w, R2;\n"
"ADD R2.x, R0.w, R1.w;\n"
- "ADD R2.y, -R0.w, c[4].w;\n"
+ "ADD R2.y, -R0.w, c[7].w;\n"
"MAD result.color.xyz, R1, R2.y, R0;\n"
"MAD result.color.w, -R0, R1, R2.x;\n"
"END\n"
@@ -3933,49 +3896,49 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODE_BLEND_MODE_MASK =
"!!ARBfp1.0\n"
- "PARAM c[10] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494 },\n"
- " program.local[7..9] };\n"
+ "PARAM c[10] = { program.local[0..6],\n"
+ " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n"
+ " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n"
+ " { 0.33299461, 0.99999559 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.z, R0.x, R0.y, c[5].x;\n"
- "MUL R1.x, R0.z, c[6];\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[7].y;\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[8].x, c[8].y;\n"
+ "MAD R1.z, R1, R1.y, -c[8];\n"
+ "MAD R1.z, R1, R1.y, c[8].w;\n"
+ "MAD R1.z, R1, R1.y, -c[9].x;\n"
+ "MAD R1.y, R1.z, R1, c[9];\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R1.y, -R1.x, c[7].w;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[7].z;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R1.x, R0, c[7];\n"
"FLR R1.y, R1.x;\n"
- "ADD R0.xy, fragment.position, c[7];\n"
- "MUL R0.xy, R0, c[8];\n"
+ "ADD R0.zw, fragment.position.xyxy, c[5].xyxy;\n"
+ "MUL R0.xy, R0.zwzw, c[4];\n"
"TEX R0, R0, texture[0], 2D;\n"
"ADD R1.x, R1, -R1.y;\n"
- "DP4 R1.y, R0, c[9];\n"
+ "DP4 R1.y, R0, c[6];\n"
"TEX R0, R1, texture[1], 1D;\n"
"MUL result.color, R0, R1.y;\n"
"END\n"
@@ -3983,42 +3946,43 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODE_BLEND_MODE_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494 } };\n"
+ "PARAM c[7] = { program.local[0..3],\n"
+ " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n"
+ " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n"
+ " { 0.33299461, 0.99999559 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.x, R1.x;\n"
- "RCP R1.y, R0.w;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, c[6];\n"
+ "ABS R0.z, R0.x;\n"
+ "ABS R0.w, R0.y;\n"
+ "ADD R0.w, R0, -R0.z;\n"
+ "ADD R1.x, R0.y, c[4].y;\n"
+ "ABS R0.w, R0;\n"
+ "CMP R0.y, -R0.w, R0, R1.x;\n"
+ "ABS R0.w, -R0.y;\n"
+ "MAX R1.x, R0.z, R0.w;\n"
+ "RCP R1.y, R1.x;\n"
+ "MIN R1.x, R0.z, R0.w;\n"
+ "MUL R1.x, R1, R1.y;\n"
+ "MUL R1.y, R1.x, R1.x;\n"
+ "MAD R1.z, R1.y, c[5].x, c[5].y;\n"
+ "MAD R1.z, R1, R1.y, -c[5];\n"
+ "MAD R1.z, R1, R1.y, c[5].w;\n"
+ "MAD R1.z, R1, R1.y, -c[6].x;\n"
+ "MAD R1.y, R1.z, R1, c[6];\n"
+ "MUL R1.x, R1.y, R1;\n"
+ "ADD R0.z, -R0, R0.w;\n"
+ "ADD R1.y, -R1.x, c[4].w;\n"
+ "CMP R0.z, -R0, R1.y, R1.x;\n"
+ "ADD R0.w, -R0.z, c[4].z;\n"
+ "CMP R0.x, R0, R0.w, R0.z;\n"
+ "CMP R0.x, -R0.y, -R0, R0;\n"
+ "ADD R0.x, R0, c[0];\n"
+ "MUL R0.x, R0, c[4];\n"
"FLR R0.y, R0.x;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX result.color, R0, texture[0], 1D;\n"
@@ -4027,45 +3991,43 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SIMPLE_PORTER_DUFF =
"!!ARBfp1.0\n"
- "PARAM c[11] = { program.local[0..7],\n"
- " { 1 },\n"
- " program.local[9..10] };\n"
+ "PARAM c[11] = { program.local[0..9],\n"
+ " { 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "ADD R0.x, R0, R0.y;\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MUL R0.x, R0, c[6].z;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R2.xyz, R1, c[10].y;\n"
- "MUL R3.xyz, R2, R0.w;\n"
- "MUL R2.xyz, R0, c[10].x;\n"
- "MAD R2.xyz, R2, R1.w, R3;\n"
- "ADD R3.xy, fragment.position, c[0];\n"
- "MUL R0.xyz, R0, c[9].y;\n"
- "ADD R2.w, -R1, c[8].x;\n"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "MUL R0.xyz, R1, c[9].z;\n"
- "ADD R2.w, -R0, c[8].x;\n"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "ADD R0.y, -R1.w, c[8].x;\n"
- "MUL R0.z, R1.w, R2.w;\n"
- "MUL R0.x, R0.w, R1.w;\n"
- "MUL R0.y, R0.w, R0;\n"
- "DP3 R2.w, R0, c[9];\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.zw, R0.xyxy, c[0].xyxy;\n"
+ "ADD R1.x, R0.z, R0.w;\n"
+ "MUL R0.xy, fragment.position, c[7];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "MUL R1.x, R1, c[0].z;\n"
+ "TEX R1, R1, texture[2], 1D;\n"
+ "MUL R2.xyz, R0, c[4].y;\n"
+ "MUL R3.xyz, R1.w, R2;\n"
+ "MUL R2.xyz, R1, c[4].x;\n"
+ "MAD R2.xyz, R0.w, R2, R3;\n"
+ "ADD R3.xy, fragment.position, c[8];\n"
+ "ADD R2.w, -R0, c[10].x;\n"
+ "MUL R1.xyz, R1, c[5].y;\n"
+ "MAD R2.xyz, R2.w, R1, R2;\n"
+ "MUL R1.xyz, R0, c[5].z;\n"
+ "ADD R3.z, -R1.w, c[10].x;\n"
+ "MAD R2.xyz, R3.z, R1, R2;\n"
+ "MUL R1.y, R1.w, R2.w;\n"
+ "MUL R1.x, R1.w, R0.w;\n"
+ "MUL R1.z, R0.w, R3;\n"
+ "DP3 R2.w, R1, c[5];\n"
+ "MUL R3.xy, R3, c[6];\n"
+ "TEX R1, R3, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[9];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -4076,30 +4038,30 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "ADD R0.x, R0, R0.y;\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MUL R0.x, R0, c[6].z;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "ADD R2.x, -R1.w, c[8];\n"
- "MUL R2.xyz, R0, R2.x;\n"
- "MAD R0.xyz, R0, R1, R2;\n"
+ "MUL R0.zw, R0.xyxy, c[0].xyxy;\n"
+ "ADD R1.x, R0.z, R0.w;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "MUL R1.x, R1, c[0].z;\n"
+ "TEX R1, R1, texture[2], 1D;\n"
"ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R2.xyz, R1, R2.x;\n"
+ "MAD R1.xyz, R1, R0, R2;\n"
+ "ADD R2.x, -R1.w, c[8];\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -4110,25 +4072,25 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[6].z;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "ADD R3.xy, fragment.position, c[0];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "ADD R2, R0, R1;\n"
- "MAD R2, -R0, R1, R2;\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.z, R0.x, c[0];\n"
+ "ADD R3.xy, fragment.position, c[6];\n"
+ "TEX R1, R0.z, texture[2], 1D;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "ADD R2, R1, R0;\n"
+ "MAD R2, -R1, R0, R2;\n"
+ "MUL R3.xy, R3, c[4];\n"
+ "TEX R1, R3, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -4141,16 +4103,16 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[6].z;\n"
+ "MUL R0.x, R0, c[0].z;\n"
"TEX R0, R0, texture[2], 1D;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
+ "MUL R1.xy, fragment.position, c[5];\n"
"TEX R1, R1, texture[0], 2D;\n"
"ADD R2.w, -R1, c[8].y;\n"
"ADD R3.xyz, R0.w, -R0;\n"
@@ -4171,11 +4133,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"MAD R2.xyz, R2, R0, R3;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[6];\n"
+ "MUL R0.xy, R0, c[4];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -4188,32 +4150,32 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[6].z;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "ADD R0.z, R0.x, R0.y;\n"
+ "MUL R1.x, R0.z, c[0].z;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "TEX R1, R1, texture[2], 1D;\n"
+ "MUL R3.xyz, R1.w, R0;\n"
+ "MUL R2.xyz, R1, R0.w;\n"
"MIN R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "ADD R2.w, -R0, c[8].x;\n"
+ "MAD R1.xyz, R1, R2.w, R2;\n"
+ "ADD R2.x, -R1.w, c[8];\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -4225,64 +4187,64 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[6].z;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "ADD R0.z, R0.x, R0.y;\n"
+ "MUL R1.x, R0.z, c[0].z;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "TEX R1, R1, texture[2], 1D;\n"
+ "MUL R3.xyz, R1.w, R0;\n"
+ "MUL R2.xyz, R1, R0.w;\n"
"MAX R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "ADD R2.w, -R0, c[8].x;\n"
+ "MAD R1.xyz, R1, R2.w, R2;\n"
+ "ADD R2.x, -R1.w, c[8];\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_COLORDODGE =
"!!ARBfp1.0\n"
"PARAM c[9] = { program.local[0..7],\n"
- " { 1, 1e-06 } };\n"
+ " { 1, 1e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[6].z;\n"
+ "MUL R0.x, R0, c[0].z;\n"
"TEX R0, R0, texture[2], 1D;\n"
"MAX R1.x, R0.w, c[8].y;\n"
"RCP R1.x, R1.x;\n"
"MAD R2.xyz, -R0, R1.x, c[8].x;\n"
"MAX R2.xyz, R2, c[8].y;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
+ "MUL R1.xy, fragment.position, c[5];\n"
"TEX R1, R1, texture[0], 2D;\n"
"ADD R2.w, -R0, c[8].x;\n"
"MUL R3.xyz, R1, R2.w;\n"
"ADD R2.w, -R1, c[8].x;\n"
"MAD R4.xyz, R0, R2.w, R3;\n"
- "MUL R3.xyz, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"MUL R2.w, R0, R1;\n"
"MAD R0.xyz, R0, R1.w, R3;\n"
"SGE R0.xyz, R0, R2.w;\n"
@@ -4295,11 +4257,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"MAD R2.xyz, R0, R4, R2;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[6];\n"
+ "MUL R0.xy, R0, c[4];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -4307,25 +4269,25 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_COLORBURN =
"!!ARBfp1.0\n"
"PARAM c[9] = { program.local[0..7],\n"
- " { 1, 9.9999997e-06 } };\n"
+ " { 1, 9.9999997e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
"TEMP R5;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[6].z;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "MUL R0.x, R0, c[0].z;\n"
"TEX R0, R0, texture[2], 1D;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
+ "MUL R2.xyz, R0.w, R1;\n"
"MAD R3.xyz, R0, R1.w, R2;\n"
"MAD R2.xyz, -R0.w, R1.w, R3;\n"
"MUL R4.xyz, R0.w, R2;\n"
@@ -4340,18 +4302,17 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"MUL R4.xyz, R1, R3.w;\n"
"MAD R0.xyz, R0, R2.w, R4;\n"
"MUL R2.w, R0, R1;\n"
- "ADD R3.w, -R0, c[8].x;\n"
"MAD R2.xyz, R1, R3.w, R2;\n"
"ADD R2.xyz, R2, -R0;\n"
"SGE R3.xyz, R3, R2.w;\n"
"MAD R2.xyz, R3, R2, R0;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[6];\n"
+ "MUL R0.xy, R0, c[4];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -4365,16 +4326,16 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[6].z;\n"
+ "MUL R0.x, R0, c[0].z;\n"
"TEX R0, R0, texture[2], 1D;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
+ "MUL R1.xy, fragment.position, c[5];\n"
"TEX R1, R1, texture[0], 2D;\n"
"ADD R2.w, -R1, c[8].y;\n"
"ADD R3.xyz, R0.w, -R0;\n"
@@ -4395,11 +4356,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"MAD R2.xyz, R0, R2, R3;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[6];\n"
+ "MUL R0.xy, R0, c[4];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -4407,8 +4368,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SOFTLIGHT =
"!!ARBfp1.0\n"
"PARAM c[10] = { program.local[0..7],\n"
- " { 1, 9.9999997e-06, 2, 8 },\n"
- " { 3 } };\n"
+ " { 1, 2, 9.9999997e-006, 4 },\n"
+ " { 16, 12, 3 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
@@ -4416,59 +4377,58 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R4;\n"
"TEMP R5;\n"
"TEMP R6;\n"
- "MUL R2.xyz, fragment.position.y, c[4];\n"
- "MAD R3.xyz, fragment.position.x, c[3], R2;\n"
- "MUL R0.xy, fragment.position, c[7];\n"
- "TEX R1, R0, texture[0], 2D;\n"
- "MAX R0.x, R1.w, c[8].y;\n"
- "RCP R2.w, R0.x;\n"
- "MUL R0.xyz, R1, R2.w;\n"
- "RSQ R0.w, R0.x;\n"
- "RSQ R2.y, R0.y;\n"
- "ADD R3.xyz, R3, c[5];\n"
- "RCP R2.x, R0.w;\n"
- "RCP R0.w, R3.z;\n"
- "MUL R3.xy, R3, R0.w;\n"
- "RSQ R0.w, R0.z;\n"
- "RCP R2.z, R0.w;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R6.xyz, R2, R1.w, -R1;\n"
- "MUL R2.xyz, -R0, c[8].w;\n"
- "ADD R5.xyz, R2, c[9].x;\n"
- "MAD R2.xyz, -R1, R2.w, c[8].x;\n"
- "MUL R3.xy, R3, c[6];\n"
- "ADD R0.w, R3.x, R3.y;\n"
- "MUL R0.w, R0, c[6].z;\n"
- "TEX R0, R0.w, texture[2], 1D;\n"
- "MAD R3.xyz, R0, c[8].z, -R0.w;\n"
- "MUL R4.xyz, R2, R3;\n"
- "MAD R4.xyz, -R4, R5, R0.w;\n"
- "MUL R5.xyz, R6, R3;\n"
- "MAD R2.xyz, -R2, R3, R0.w;\n"
- "MAD R6.xyz, R1, R0.w, R5;\n"
- "MUL R4.xyz, R1, R4;\n"
- "MUL R5.xyz, R1, c[8].w;\n"
- "ADD R6.xyz, R6, -R4;\n"
- "SGE R5.xyz, R5, R1.w;\n"
- "MUL R5.xyz, R5, R6;\n"
- "ADD R3.xyz, R4, R5;\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
+ "RCP R0.z, R0.z;\n"
+ "MUL R0.xy, R0, R0.z;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "ADD R0.x, R0, R0.y;\n"
+ "MUL R1.xy, fragment.position, c[5];\n"
+ "TEX R1, R1, texture[0], 2D;\n"
+ "MAX R0.z, R1.w, c[8];\n"
+ "RCP R0.z, R0.z;\n"
+ "MUL R3.xyz, R1, R0.z;\n"
+ "MAD R2.xyz, R3, c[9].x, -c[9].y;\n"
+ "MUL R0.x, R0, c[0].z;\n"
+ "TEX R0, R0, texture[2], 1D;\n"
+ "MAD R4.xyz, R3, R2, c[9].z;\n"
+ "MAD R2.xyz, R0, c[8].y, -R0.w;\n"
+ "MUL R5.xyz, R1.w, R2;\n"
+ "MUL R6.xyz, R5, R4;\n"
+ "RSQ R2.w, R3.x;\n"
+ "RCP R4.x, R2.w;\n"
+ "RSQ R2.w, R3.y;\n"
+ "RSQ R3.w, R3.z;\n"
+ "RCP R4.y, R2.w;\n"
+ "RCP R4.z, R3.w;\n"
+ "ADD R4.xyz, -R3, R4;\n"
+ "MUL R6.xyz, R3, R6;\n"
+ "MUL R4.xyz, R5, R4;\n"
+ "ADD R3.xyz, -R3, c[8].x;\n"
+ "MAD R2.xyz, R2, R3, R0.w;\n"
+ "MUL R3.xyz, R0, c[8].y;\n"
+ "MAD R5.xyz, R0.w, R1, R6;\n"
+ "MAD R4.xyz, R0.w, R1, R4;\n"
+ "ADD R6.xyz, R4, -R5;\n"
+ "MUL R4.xyz, R1, c[8].w;\n"
+ "SGE R4.xyz, R4, R1.w;\n"
+ "MAD R4.xyz, R4, R6, R5;\n"
+ "MAD R4.xyz, -R1, R2, R4;\n"
+ "SGE R3.xyz, R3, R0.w;\n"
"MUL R2.xyz, R1, R2;\n"
- "MUL R4.xyz, R0, c[8].z;\n"
- "ADD R3.xyz, R3, -R2;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "MUL R3.xyz, R4, R3;\n"
- "ADD R2.xyz, R2, R3;\n"
"ADD R2.w, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
+ "MAD R2.xyz, R3, R4, R2;\n"
+ "MAD R2.xyz, R0, R2.w, R2;\n"
+ "ADD R0.x, -R0.w, c[8];\n"
+ "MAD R2.xyz, R1, R0.x, R2;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[6];\n"
+ "MUL R0.xy, R0, c[4];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -4481,106 +4441,104 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "ADD R0.x, R0, R0.y;\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MUL R0.x, R0, c[6].z;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "ADD R3.xyz, R0, R1;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MUL R0.xyz, R0, R1.w;\n"
- "MIN R0.xyz, R0, R2;\n"
- "MAD R2.xyz, -R0, c[8].x, R3;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "ADD R0.z, R0.x, R0.y;\n"
+ "MUL R1.x, R0.z, c[0].z;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "TEX R1, R1, texture[2], 1D;\n"
+ "ADD R2.xyz, R1, R0;\n"
+ "MUL R3.xyz, R1.w, R0;\n"
+ "MUL R1.xyz, R1, R0.w;\n"
+ "MIN R1.xyz, R1, R3;\n"
+ "MAD R2.xyz, -R1, c[8].x, R2;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_EXCLUSION =
"!!ARBfp1.0\n"
"PARAM c[9] = { program.local[0..7],\n"
- " { 1, 2 } };\n"
+ " { 2, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[6].z;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MAD R3.xyz, R0, R1.w, R2;\n"
- "MUL R2.xyz, R0, R1;\n"
- "MAD R2.xyz, -R2, c[8].y, R3;\n"
- "ADD R2.w, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "ADD R0.z, R0.x, R0.y;\n"
+ "MUL R1.x, R0.z, c[0].z;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "TEX R1, R1, texture[2], 1D;\n"
+ "MUL R2.xyz, R1.w, R0;\n"
+ "MAD R3.xyz, R1, R0.w, R2;\n"
+ "MUL R2.xyz, R1, R0;\n"
+ "MAD R2.xyz, -R2, c[8].x, R3;\n"
+ "ADD R2.w, -R0, c[8].y;\n"
+ "MAD R1.xyz, R1, R2.w, R2;\n"
+ "ADD R2.x, -R1.w, c[8].y;\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..4],\n"
- " { 1 },\n"
- " program.local[6..7] };\n"
+ "PARAM c[8] = { program.local[0..6],\n"
+ " { 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\n"
"TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MUL R2.xyz, R1, c[7].y;\n"
- "MUL R0.x, R0, c[3].z;\n"
+ "MUL R2.xyz, R1, c[4].y;\n"
+ "MUL R0.x, R0, c[0].z;\n"
"TEX R0, R0, texture[1], 1D;\n"
- "MUL R3.xyz, R2, R0.w;\n"
- "MUL R2.xyz, R0, c[7].x;\n"
- "MAD R2.xyz, R2, R1.w, R3;\n"
- "MUL R0.xyz, R0, c[6].y;\n"
- "ADD R2.w, -R1, c[5].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[5];\n"
- "MUL R1.xyz, R1, c[6].z;\n"
- "MAD result.color.xyz, R1, R2.x, R0;\n"
- "ADD R0.y, -R1.w, c[5].x;\n"
+ "MUL R3.xyz, R0.w, R2;\n"
+ "MUL R2.xyz, R0, c[4].x;\n"
+ "MAD R2.xyz, R1.w, R2, R3;\n"
+ "ADD R2.w, -R1, c[7].x;\n"
+ "MUL R0.xyz, R0, c[5].y;\n"
+ "MAD R0.xyz, R2.w, R0, R2;\n"
+ "ADD R2.x, -R0.w, c[7];\n"
+ "MUL R1.xyz, R1, c[5].z;\n"
+ "MAD result.color.xyz, R2.x, R1, R0;\n"
"MUL R0.x, R0.w, R1.w;\n"
"MUL R0.z, R1.w, R2.x;\n"
- "MUL R0.y, R0.w, R0;\n"
- "DP3 result.color.w, R0, c[6];\n"
+ "MUL R0.y, R0.w, R2.w;\n"
+ "DP3 result.color.w, R0, c[5];\n"
"END\n"
;
@@ -4591,16 +4549,16 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
"MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
"TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MUL R0.x, R0, c[3].z;\n"
+ "MUL R0.x, R0, c[0].z;\n"
"TEX R0, R0, texture[1], 1D;\n"
"ADD R2.x, -R1.w, c[5];\n"
"MUL R2.xyz, R0, R2.x;\n"
@@ -4618,16 +4576,16 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
"MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
"TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MUL R0.x, R0, c[3].z;\n"
+ "MUL R0.x, R0, c[0].z;\n"
"TEX R0, R0, texture[1], 1D;\n"
"ADD R2, R0, R1;\n"
"MAD result.color, -R0, R1, R2;\n"
@@ -4642,14 +4600,14 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[3].z;\n"
+ "MUL R0.x, R0, c[0].z;\n"
"TEX R0, R0, texture[1], 1D;\n"
"MUL R1.xy, fragment.position, c[4];\n"
"TEX R1, R1, texture[0], 2D;\n"
@@ -4683,19 +4641,19 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[3].z;\n"
- "MUL R1.xy, fragment.position, c[4];\n"
- "TEX R1, R1, texture[0], 2D;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "MUL R0.x, R0, c[0].z;\n"
"TEX R0, R0, texture[1], 1D;\n"
"MUL R2.xyz, R0, R1.w;\n"
- "MUL R3.xyz, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"MIN R2.xyz, R2, R3;\n"
"ADD R2.w, -R1, c[5].x;\n"
"MAD R0.xyz, R0, R2.w, R2;\n"
@@ -4714,19 +4672,19 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[3].z;\n"
- "MUL R1.xy, fragment.position, c[4];\n"
- "TEX R1, R1, texture[0], 2D;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "MUL R0.x, R0, c[0].z;\n"
"TEX R0, R0, texture[1], 1D;\n"
"MUL R2.xyz, R0, R1.w;\n"
- "MUL R3.xyz, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"MAX R2.xyz, R2, R3;\n"
"ADD R2.w, -R1, c[5].x;\n"
"MAD R0.xyz, R0, R2.w, R2;\n"
@@ -4740,19 +4698,19 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_COLORDODGE_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[6] = { program.local[0..4],\n"
- " { 1, 1e-06 } };\n"
+ " { 1, 1e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[3].z;\n"
+ "MUL R0.x, R0, c[0].z;\n"
"TEX R0, R0, texture[1], 1D;\n"
"MAX R1.x, R0.w, c[5].y;\n"
"RCP R1.x, R1.x;\n"
@@ -4764,7 +4722,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"MUL R2.xyz, R1, R2.x;\n"
"ADD R2.w, -R1, c[5].x;\n"
"MAD R2.xyz, R0, R2.w, R2;\n"
- "MUL R1.xyz, R1, R0.w;\n"
+ "MUL R1.xyz, R0.w, R1;\n"
"MAD R0.xyz, R0, R1.w, R1;\n"
"MUL R2.w, R0, R1;\n"
"RCP R3.x, R3.x;\n"
@@ -4783,25 +4741,25 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_COLORBURN_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[6] = { program.local[0..4],\n"
- " { 1, 9.9999997e-06 } };\n"
+ " { 1, 9.9999997e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
"TEMP R5;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[3].z;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "MUL R0.x, R0, c[0].z;\n"
"TEX R0, R0, texture[1], 1D;\n"
- "MUL R1.xy, fragment.position, c[4];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
+ "MUL R2.xyz, R0.w, R1;\n"
"MAD R3.xyz, R0, R1.w, R2;\n"
"ADD R2.w, -R1, c[5].x;\n"
"MAD R2.xyz, -R0.w, R1.w, R3;\n"
@@ -4814,9 +4772,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"RCP R2.z, R2.z;\n"
"MAD R2.xyz, R4, R2, R5;\n"
"MUL R4.xyz, R1, R3.w;\n"
- "MAD R0.xyz, R0, R2.w, R4;\n"
- "ADD R3.w, -R0, c[5].x;\n"
"MAD R1.xyz, R1, R3.w, R2;\n"
+ "MAD R0.xyz, R0, R2.w, R4;\n"
"MUL R2.x, R0.w, R1.w;\n"
"ADD R2.w, R0, R1;\n"
"ADD R1.xyz, R1, -R0;\n"
@@ -4835,14 +4792,14 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[3].z;\n"
+ "MUL R0.x, R0, c[0].z;\n"
"TEX R0, R0, texture[1], 1D;\n"
"MUL R1.xy, fragment.position, c[4];\n"
"TEX R1, R1, texture[0], 2D;\n"
@@ -4871,8 +4828,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SOFTLIGHT_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[7] = { program.local[0..4],\n"
- " { 1, 9.9999997e-06, 2, 8 },\n"
- " { 3 } };\n"
+ " { 1, 2, 9.9999997e-006, 4 },\n"
+ " { 16, 12, 3 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
@@ -4880,54 +4837,53 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R4;\n"
"TEMP R5;\n"
"TEMP R6;\n"
- "MUL R2.xyz, fragment.position.y, c[1];\n"
- "MAD R3.xyz, fragment.position.x, c[0], R2;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
- "TEX R1, R0, texture[0], 2D;\n"
- "MAX R0.x, R1.w, c[5].y;\n"
- "RCP R2.w, R0.x;\n"
- "MUL R0.xyz, R1, R2.w;\n"
- "RSQ R0.w, R0.x;\n"
- "RSQ R2.y, R0.y;\n"
- "ADD R3.xyz, R3, c[2];\n"
- "RCP R2.x, R0.w;\n"
- "RCP R0.w, R3.z;\n"
- "MUL R3.xy, R3, R0.w;\n"
- "RSQ R0.w, R0.z;\n"
- "RCP R2.z, R0.w;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R6.xyz, R2, R1.w, -R1;\n"
- "MUL R2.xyz, -R0, c[5].w;\n"
- "ADD R5.xyz, R2, c[6].x;\n"
- "MAD R2.xyz, -R1, R2.w, c[5].x;\n"
- "MUL R3.xy, R3, c[3];\n"
- "ADD R0.w, R3.x, R3.y;\n"
- "MUL R0.w, R0, c[3].z;\n"
- "TEX R0, R0.w, texture[1], 1D;\n"
- "MAD R3.xyz, R0, c[5].z, -R0.w;\n"
- "MUL R4.xyz, R2, R3;\n"
- "MAD R4.xyz, -R4, R5, R0.w;\n"
- "MUL R5.xyz, R6, R3;\n"
- "MAD R2.xyz, -R2, R3, R0.w;\n"
- "MAD R6.xyz, R1, R0.w, R5;\n"
- "MUL R4.xyz, R1, R4;\n"
- "MUL R5.xyz, R1, c[5].w;\n"
- "ADD R6.xyz, R6, -R4;\n"
- "SGE R5.xyz, R5, R1.w;\n"
- "MUL R5.xyz, R5, R6;\n"
- "ADD R3.xyz, R4, R5;\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
+ "RCP R0.z, R0.z;\n"
+ "MUL R0.xy, R0, R0.z;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "ADD R0.x, R0, R0.y;\n"
+ "MUL R1.xy, fragment.position, c[4];\n"
+ "TEX R1, R1, texture[0], 2D;\n"
+ "MAX R0.z, R1.w, c[5];\n"
+ "RCP R0.z, R0.z;\n"
+ "MUL R3.xyz, R1, R0.z;\n"
+ "MAD R2.xyz, R3, c[6].x, -c[6].y;\n"
+ "MUL R0.x, R0, c[0].z;\n"
+ "TEX R0, R0, texture[1], 1D;\n"
+ "MAD R4.xyz, R3, R2, c[6].z;\n"
+ "MAD R2.xyz, R0, c[5].y, -R0.w;\n"
+ "MUL R5.xyz, R1.w, R2;\n"
+ "MUL R6.xyz, R5, R4;\n"
+ "RSQ R2.w, R3.x;\n"
+ "RCP R4.x, R2.w;\n"
+ "RSQ R2.w, R3.y;\n"
+ "RSQ R3.w, R3.z;\n"
+ "RCP R4.y, R2.w;\n"
+ "RCP R4.z, R3.w;\n"
+ "ADD R4.xyz, -R3, R4;\n"
+ "MUL R6.xyz, R3, R6;\n"
+ "MUL R4.xyz, R5, R4;\n"
+ "ADD R3.xyz, -R3, c[5].x;\n"
+ "MAD R2.xyz, R2, R3, R0.w;\n"
+ "MUL R3.xyz, R0, c[5].y;\n"
+ "MAD R5.xyz, R0.w, R1, R6;\n"
+ "MAD R4.xyz, R0.w, R1, R4;\n"
+ "ADD R6.xyz, R4, -R5;\n"
+ "MUL R4.xyz, R1, c[5].w;\n"
+ "SGE R4.xyz, R4, R1.w;\n"
+ "MAD R4.xyz, R4, R6, R5;\n"
+ "MAD R4.xyz, -R1, R2, R4;\n"
"MUL R2.xyz, R1, R2;\n"
- "MUL R4.xyz, R0, c[5].z;\n"
- "ADD R3.xyz, R3, -R2;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "MUL R3.xyz, R4, R3;\n"
- "ADD R2.xyz, R2, R3;\n"
+ "SGE R3.xyz, R3, R0.w;\n"
+ "MAD R2.xyz, R3, R4, R2;\n"
"ADD R2.w, -R1, c[5].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, R0.w, R1.w;\n"
- "ADD R2.y, -R0.w, c[5].x;\n"
- "MAD result.color.xyz, R1, R2.y, R0;\n"
- "MAD result.color.w, -R0, R1, R2.x;\n"
+ "MAD R2.xyz, R0, R2.w, R2;\n"
+ "ADD R0.x, R0.w, R1.w;\n"
+ "ADD R0.y, -R0.w, c[5].x;\n"
+ "MAD result.color.xyz, R1, R0.y, R2;\n"
+ "MAD result.color.w, -R0, R1, R0.x;\n"
"END\n"
;
@@ -4939,19 +4895,19 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[3].z;\n"
- "MUL R1.xy, fragment.position, c[4];\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "MUL R0.x, R0, c[0].z;\n"
"TEX R0, R0, texture[1], 1D;\n"
- "TEX R1, R1, texture[0], 2D;\n"
"MUL R2.xyz, R0, R1.w;\n"
- "MUL R3.xyz, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"ADD R0.xyz, R0, R1;\n"
"MIN R2.xyz, R2, R3;\n"
"ADD R1.x, R0.w, R1.w;\n"
@@ -4963,30 +4919,30 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_EXCLUSION_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[6] = { program.local[0..4],\n"
- " { 1, 2 } };\n"
+ " { 2, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[3].z;\n"
- "MUL R1.xy, fragment.position, c[4];\n"
- "TEX R1, R1, texture[0], 2D;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "MUL R0.x, R0, c[0].z;\n"
"TEX R0, R0, texture[1], 1D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
+ "MUL R2.xyz, R0.w, R1;\n"
"MAD R3.xyz, R0, R1.w, R2;\n"
"MUL R2.xyz, R0, R1;\n"
- "MAD R2.xyz, -R2, c[5].y, R3;\n"
- "ADD R2.w, -R1, c[5].x;\n"
+ "MAD R2.xyz, -R2, c[5].x, R3;\n"
+ "ADD R2.w, -R1, c[5].y;\n"
"MAD R0.xyz, R0, R2.w, R2;\n"
"ADD R2.x, R0.w, R1.w;\n"
- "ADD R2.y, -R0.w, c[5].x;\n"
+ "ADD R2.y, -R0.w, c[5];\n"
"MAD result.color.xyz, R1, R2.y, R0;\n"
"MAD result.color.w, -R0, R1, R2.x;\n"
"END\n"
@@ -4997,18 +4953,18 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"PARAM c[7] = { program.local[0..6] };\n"
"TEMP R0;\n"
"TEMP R1;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.zw, R0.xyxy, R0.z;\n"
- "MUL R0.zw, R0, c[3].xyxy;\n"
+ "MUL R0.zw, R0, c[0].xyxy;\n"
"ADD R1.x, R0.z, R0.w;\n"
- "ADD R0.xy, fragment.position, c[4];\n"
- "MUL R0.xy, R0, c[5];\n"
+ "ADD R0.xy, fragment.position, c[5];\n"
+ "MUL R0.xy, R0, c[4];\n"
"TEX R0, R0, texture[0], 2D;\n"
"DP4 R1.y, R0, c[6];\n"
- "MUL R1.x, R1, c[3].z;\n"
+ "MUL R1.x, R1, c[0].z;\n"
"TEX R0, R1, texture[1], 1D;\n"
"MUL result.color, R0, R1.y;\n"
"END\n"
@@ -5018,58 +4974,55 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"!!ARBfp1.0\n"
"PARAM c[4] = { program.local[0..3] };\n"
"TEMP R0;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[3].z;\n"
+ "MUL R0.x, R0, c[0].z;\n"
"TEX result.color, R0, texture[0], 1D;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_SIMPLE_PORTER_DUFF =
"!!ARBfp1.0\n"
- "PARAM c[11] = { program.local[0..7],\n"
- " { 1 },\n"
- " program.local[9..10] };\n"
+ "PARAM c[11] = { program.local[0..9],\n"
+ " { 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MOV R0.y, -R0;\n"
- "TEX R0, R0, texture[2], 2D;\n"
- "MUL R2.xyz, R1, c[10].y;\n"
- "MUL R3.xyz, R2, R0.w;\n"
- "MUL R2.xyz, R0, c[10].x;\n"
- "MAD R2.xyz, R2, R1.w, R3;\n"
- "ADD R3.xy, fragment.position, c[0];\n"
- "MUL R0.xyz, R0, c[9].y;\n"
- "ADD R2.w, -R1, c[8].x;\n"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "ADD R2.w, -R0, c[8].x;\n"
- "MUL R0.xyz, R1, c[9].z;\n"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "ADD R0.y, -R1.w, c[8].x;\n"
- "MUL R0.z, R1.w, R2.w;\n"
- "MUL R0.x, R0.w, R1.w;\n"
- "MUL R0.y, R0.w, R0;\n"
- "DP3 R2.w, R0, c[9];\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R1.xyz, R0, c[3];\n"
+ "RCP R0.z, R1.z;\n"
+ "MUL R1.xy, R1, R0.z;\n"
+ "MUL R0.xy, fragment.position, c[7];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "MUL R1.xy, R1, c[0];\n"
+ "TEX R1, R1, texture[2], 2D;\n"
+ "MUL R2.xyz, R0, c[4].y;\n"
+ "MUL R3.xyz, R1.w, R2;\n"
+ "MUL R2.xyz, R1, c[4].x;\n"
+ "MAD R2.xyz, R0.w, R2, R3;\n"
+ "ADD R3.xy, fragment.position, c[8];\n"
+ "ADD R2.w, -R0, c[10].x;\n"
+ "MUL R1.xyz, R1, c[5].y;\n"
+ "MAD R2.xyz, R2.w, R1, R2;\n"
+ "MUL R1.xyz, R0, c[5].z;\n"
+ "ADD R3.z, -R1.w, c[10].x;\n"
+ "MAD R2.xyz, R3.z, R1, R2;\n"
+ "MUL R1.y, R1.w, R2.w;\n"
+ "MUL R1.x, R1.w, R0.w;\n"
+ "MUL R1.z, R0.w, R3;\n"
+ "DP3 R2.w, R1, c[5];\n"
+ "MUL R3.xy, R3, c[6];\n"
+ "TEX R1, R3, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[9];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -5080,29 +5033,28 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
- "RCP R1.x, R0.z;\n"
- "MUL R0.xy, R0, R1.x;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MOV R0.y, -R0;\n"
- "TEX R0, R0, texture[2], 2D;\n"
- "ADD R2.x, -R1.w, c[8];\n"
- "MUL R2.xyz, R0, R2.x;\n"
- "MAD R0.xyz, R0, R1, R2;\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R1.xyz, R0, c[3];\n"
+ "RCP R0.z, R1.z;\n"
+ "MUL R1.xy, R1, R0.z;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "MUL R1.xy, R1, c[0];\n"
+ "TEX R1, R1, texture[2], 2D;\n"
"ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R2.xyz, R1, R2.x;\n"
+ "MAD R1.xyz, R1, R0, R2;\n"
+ "ADD R2.x, -R1.w, c[8];\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -5113,24 +5065,23 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MOV R0.y, -R0;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "ADD R3.xy, fragment.position, c[0];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "TEX R0, R0, texture[2], 2D;\n"
- "ADD R2, R0, R1;\n"
- "MAD R2, -R0, R1, R2;\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.zw, R0.xyxy, c[0].xyxy;\n"
+ "ADD R3.xy, fragment.position, c[6];\n"
+ "TEX R1, R0.zwzw, texture[2], 2D;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "ADD R2, R1, R0;\n"
+ "MAD R2, -R1, R0, R2;\n"
+ "MUL R3.xy, R3, c[4];\n"
+ "TEX R1, R3, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -5143,15 +5094,14 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MOV R0.y, -R0;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[2], 2D;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
+ "MUL R1.xy, fragment.position, c[5];\n"
"TEX R1, R1, texture[0], 2D;\n"
"ADD R2.w, -R1, c[8].y;\n"
"ADD R3.xyz, R0.w, -R0;\n"
@@ -5172,11 +5122,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"MAD R2.xyz, R2, R0, R3;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[6];\n"
+ "MUL R0.xy, R0, c[4];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -5189,31 +5139,30 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
- "MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MOV R0.y, -R0;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "TEX R0, R0, texture[2], 2D;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\n"
+ "MUL R0.zw, R0.xyxy, R0.z;\n"
+ "MUL R1.xy, R0.zwzw, c[0];\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "TEX R1, R1, texture[2], 2D;\n"
+ "MUL R3.xyz, R1.w, R0;\n"
+ "MUL R2.xyz, R1, R0.w;\n"
"MIN R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "ADD R2.w, -R0, c[8].x;\n"
+ "MAD R1.xyz, R1, R2.w, R2;\n"
+ "ADD R2.x, -R1.w, c[8];\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -5225,62 +5174,60 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
- "MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MOV R0.y, -R0;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "TEX R0, R0, texture[2], 2D;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\n"
+ "MUL R0.zw, R0.xyxy, R0.z;\n"
+ "MUL R1.xy, R0.zwzw, c[0];\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "TEX R1, R1, texture[2], 2D;\n"
+ "MUL R3.xyz, R1.w, R0;\n"
+ "MUL R2.xyz, R1, R0.w;\n"
"MAX R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "ADD R2.w, -R0, c[8].x;\n"
+ "MAD R1.xyz, R1, R2.w, R2;\n"
+ "ADD R2.x, -R1.w, c[8];\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_COLORDODGE =
"!!ARBfp1.0\n"
"PARAM c[9] = { program.local[0..7],\n"
- " { 1, 1e-06 } };\n"
+ " { 1, 1e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MOV R0.y, -R0;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[2], 2D;\n"
"MAX R1.x, R0.w, c[8].y;\n"
"RCP R1.x, R1.x;\n"
- "MAD R1.xyz, -R0, R1.x, c[8].x;\n"
- "MAX R2.xyz, R1, c[8].y;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
+ "MAD R2.xyz, -R0, R1.x, c[8].x;\n"
+ "MAX R2.xyz, R2, c[8].y;\n"
+ "MUL R1.xy, fragment.position, c[5];\n"
"TEX R1, R1, texture[0], 2D;\n"
"ADD R2.w, -R0, c[8].x;\n"
"MUL R3.xyz, R1, R2.w;\n"
"ADD R2.w, -R1, c[8].x;\n"
"MAD R4.xyz, R0, R2.w, R3;\n"
- "MUL R3.xyz, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"MUL R2.w, R0, R1;\n"
"MAD R0.xyz, R0, R1.w, R3;\n"
"SGE R0.xyz, R0, R2.w;\n"
@@ -5293,11 +5240,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"MAD R2.xyz, R0, R4, R2;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[6];\n"
+ "MUL R0.xy, R0, c[4];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -5305,24 +5252,23 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_COLORBURN =
"!!ARBfp1.0\n"
"PARAM c[9] = { program.local[0..7],\n"
- " { 1, 9.9999997e-06 } };\n"
+ " { 1, 9.9999997e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
"TEMP R5;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MOV R0.y, -R0;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[2], 2D;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
+ "MUL R2.xyz, R0.w, R1;\n"
"MAD R3.xyz, R0, R1.w, R2;\n"
"MAD R2.xyz, -R0.w, R1.w, R3;\n"
"MUL R4.xyz, R0.w, R2;\n"
@@ -5337,18 +5283,17 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"MUL R4.xyz, R1, R3.w;\n"
"MAD R0.xyz, R0, R2.w, R4;\n"
"MUL R2.w, R0, R1;\n"
- "ADD R3.w, -R0, c[8].x;\n"
"MAD R2.xyz, R1, R3.w, R2;\n"
"ADD R2.xyz, R2, -R0;\n"
"SGE R3.xyz, R3, R2.w;\n"
"MAD R2.xyz, R3, R2, R0;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[6];\n"
+ "MUL R0.xy, R0, c[4];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -5362,15 +5307,14 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MOV R0.y, -R0;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[2], 2D;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
+ "MUL R1.xy, fragment.position, c[5];\n"
"TEX R1, R1, texture[0], 2D;\n"
"ADD R2.w, -R1, c[8].y;\n"
"ADD R3.xyz, R0.w, -R0;\n"
@@ -5391,11 +5335,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"MAD R2.xyz, R0, R2, R3;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[6];\n"
+ "MUL R0.xy, R0, c[4];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -5403,8 +5347,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_SOFTLIGHT =
"!!ARBfp1.0\n"
"PARAM c[10] = { program.local[0..7],\n"
- " { 1, 9.9999997e-06, 2, 8 },\n"
- " { 3 } };\n"
+ " { 1, 2, 9.9999997e-006, 4 },\n"
+ " { 16, 12, 3 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
@@ -5412,58 +5356,56 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R4;\n"
"TEMP R5;\n"
"TEMP R6;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MUL R1.xy, fragment.position, c[5];\n"
+ "TEX R1, R1, texture[0], 2D;\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "MAX R0.z, R1.w, c[8].y;\n"
- "RCP R2.w, R0.z;\n"
- "MUL R2.xyz, R1, R2.w;\n"
- "MUL R6.xyz, -R2, c[8].w;\n"
- "MAD R3.xyz, -R1, R2.w, c[8].x;\n"
- "MOV R0.y, -R0;\n"
+ "MAX R0.w, R1, c[8].z;\n"
+ "RCP R0.w, R0.w;\n"
+ "MUL R3.xyz, R1, R0.w;\n"
+ "MAD R2.xyz, R3, c[9].x, -c[9].y;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[2], 2D;\n"
- "MAD R4.xyz, R0, c[8].z, -R0.w;\n"
- "MUL R5.xyz, R3, R4;\n"
- "MAD R3.xyz, -R3, R4, R0.w;\n"
- "ADD R6.xyz, R6, c[9].x;\n"
- "RSQ R2.x, R2.x;\n"
- "RSQ R2.z, R2.z;\n"
- "RSQ R2.y, R2.y;\n"
- "MAD R5.xyz, -R5, R6, R0.w;\n"
- "MUL R3.xyz, R1, R3;\n"
+ "MAD R4.xyz, R3, R2, c[9].z;\n"
+ "MAD R2.xyz, R0, c[8].y, -R0.w;\n"
+ "MUL R5.xyz, R1.w, R2;\n"
+ "MUL R6.xyz, R5, R4;\n"
+ "RSQ R2.w, R3.x;\n"
+ "RCP R4.x, R2.w;\n"
+ "RSQ R2.w, R3.y;\n"
+ "RSQ R3.w, R3.z;\n"
+ "RCP R4.y, R2.w;\n"
+ "RCP R4.z, R3.w;\n"
+ "ADD R4.xyz, -R3, R4;\n"
+ "MUL R6.xyz, R3, R6;\n"
+ "MUL R4.xyz, R5, R4;\n"
+ "ADD R3.xyz, -R3, c[8].x;\n"
+ "MAD R2.xyz, R2, R3, R0.w;\n"
+ "MUL R3.xyz, R0, c[8].y;\n"
+ "MAD R5.xyz, R0.w, R1, R6;\n"
+ "MAD R4.xyz, R0.w, R1, R4;\n"
+ "ADD R6.xyz, R4, -R5;\n"
+ "MUL R4.xyz, R1, c[8].w;\n"
+ "SGE R4.xyz, R4, R1.w;\n"
+ "MAD R4.xyz, R4, R6, R5;\n"
+ "MAD R4.xyz, -R1, R2, R4;\n"
+ "SGE R3.xyz, R3, R0.w;\n"
+ "MUL R2.xyz, R1, R2;\n"
"ADD R2.w, -R1, c[8].x;\n"
- "RCP R2.x, R2.x;\n"
- "RCP R2.z, R2.z;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R2.xyz, R2, R1.w, -R1;\n"
- "MUL R6.xyz, R2, R4;\n"
- "MUL R2.xyz, R1, R5;\n"
- "MAD R6.xyz, R1, R0.w, R6;\n"
- "MUL R4.xyz, R0, c[8].z;\n"
- "MUL R5.xyz, R1, c[8].w;\n"
- "ADD R6.xyz, R6, -R2;\n"
- "SGE R5.xyz, R5, R1.w;\n"
- "MUL R5.xyz, R5, R6;\n"
- "ADD R2.xyz, R2, R5;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "ADD R2.xyz, R2, -R3;\n"
- "MUL R2.xyz, R4, R2;\n"
- "ADD R2.xyz, R3, R2;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
+ "MAD R2.xyz, R3, R4, R2;\n"
+ "MAD R2.xyz, R0, R2.w, R2;\n"
+ "ADD R0.x, -R0.w, c[8];\n"
+ "MAD R2.xyz, R1, R0.x, R2;\n"
"ADD R0.z, R0.w, R1.w;\n"
"MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
+ "ADD R0.xy, fragment.position, c[6];\n"
+ "MUL R0.xy, R0, c[4];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -5476,103 +5418,98 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
- "MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MOV R0.y, -R0;\n"
- "TEX R0, R0, texture[2], 2D;\n"
- "ADD R3.xyz, R0, R1;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MUL R0.xyz, R0, R1.w;\n"
- "MIN R0.xyz, R0, R2;\n"
- "MAD R2.xyz, -R0, c[8].x, R3;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.zw, R0.xyxy, R0.z;\n"
+ "MUL R1.xy, R0.zwzw, c[0];\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "TEX R1, R1, texture[2], 2D;\n"
+ "ADD R2.xyz, R1, R0;\n"
+ "MUL R3.xyz, R1.w, R0;\n"
+ "MUL R1.xyz, R1, R0.w;\n"
+ "MIN R1.xyz, R1, R3;\n"
+ "MAD R2.xyz, -R1, c[8].x, R2;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_EXCLUSION =
"!!ARBfp1.0\n"
"PARAM c[9] = { program.local[0..7],\n"
- " { 1, 2 } };\n"
+ " { 2, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
- "MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MOV R0.y, -R0;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "TEX R0, R0, texture[2], 2D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MAD R3.xyz, R0, R1.w, R2;\n"
- "MUL R2.xyz, R0, R1;\n"
- "MAD R2.xyz, -R2, c[8].y, R3;\n"
- "ADD R2.w, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.zw, R0.xyxy, R0.z;\n"
+ "MUL R1.xy, R0.zwzw, c[0];\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "TEX R1, R1, texture[2], 2D;\n"
+ "MUL R2.xyz, R1.w, R0;\n"
+ "MAD R3.xyz, R1, R0.w, R2;\n"
+ "MUL R2.xyz, R1, R0;\n"
+ "MAD R2.xyz, -R2, c[8].x, R3;\n"
+ "ADD R2.w, -R0, c[8].y;\n"
+ "MAD R1.xyz, R1, R2.w, R2;\n"
+ "ADD R2.x, -R1.w, c[8].y;\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..4],\n"
- " { 1 },\n"
- " program.local[6..7] };\n"
+ "PARAM c[8] = { program.local[0..6],\n"
+ " { 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MUL R2.xyz, R1, c[7].y;\n"
- "MOV R0.y, -R0;\n"
+ "MUL R1.xy, fragment.position, c[6];\n"
+ "TEX R1, R1, texture[0], 2D;\n"
+ "MUL R2.xyz, R1, c[4].y;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[1], 2D;\n"
- "MUL R3.xyz, R2, R0.w;\n"
- "MUL R2.xyz, R0, c[7].x;\n"
- "MAD R2.xyz, R2, R1.w, R3;\n"
- "MUL R0.xyz, R0, c[6].y;\n"
- "ADD R2.w, -R1, c[5].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[5];\n"
- "MUL R1.xyz, R1, c[6].z;\n"
- "MAD result.color.xyz, R1, R2.x, R0;\n"
- "ADD R0.y, -R1.w, c[5].x;\n"
+ "MUL R3.xyz, R0.w, R2;\n"
+ "MUL R2.xyz, R0, c[4].x;\n"
+ "MAD R2.xyz, R1.w, R2, R3;\n"
+ "ADD R2.w, -R1, c[7].x;\n"
+ "MUL R0.xyz, R0, c[5].y;\n"
+ "MAD R0.xyz, R2.w, R0, R2;\n"
+ "ADD R2.x, -R0.w, c[7];\n"
+ "MUL R1.xyz, R1, c[5].z;\n"
+ "MAD result.color.xyz, R2.x, R1, R0;\n"
"MUL R0.x, R0.w, R1.w;\n"
"MUL R0.z, R1.w, R2.x;\n"
- "MUL R0.y, R0.w, R0;\n"
- "DP3 result.color.w, R0, c[6];\n"
+ "MUL R0.y, R0.w, R2.w;\n"
+ "DP3 result.color.w, R0, c[5];\n"
"END\n"
;
@@ -5583,15 +5520,14 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
- "RCP R1.x, R0.z;\n"
- "MUL R0.xy, R0, R1.x;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MOV R0.y, -R0;\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
+ "RCP R0.z, R0.z;\n"
+ "MUL R0.xy, R0, R0.z;\n"
+ "MUL R1.xy, fragment.position, c[4];\n"
+ "TEX R1, R1, texture[0], 2D;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2.x, -R1.w, c[5];\n"
"MUL R2.xyz, R0, R2.x;\n"
@@ -5609,15 +5545,14 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
"MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
"TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MOV R0.y, -R0;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[1], 2D;\n"
"ADD R2, R0, R1;\n"
"MAD result.color, -R0, R1, R2;\n"
@@ -5632,13 +5567,12 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.y, -R0;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[1], 2D;\n"
"MUL R1.xy, fragment.position, c[4];\n"
"TEX R1, R1, texture[0], 2D;\n"
@@ -5672,18 +5606,17 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.y, -R0;\n"
- "MUL R1.xy, fragment.position, c[4];\n"
- "TEX R1, R1, texture[0], 2D;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[1], 2D;\n"
"MUL R2.xyz, R0, R1.w;\n"
- "MUL R3.xyz, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"MIN R2.xyz, R2, R3;\n"
"ADD R2.w, -R1, c[5].x;\n"
"MAD R0.xyz, R0, R2.w, R2;\n"
@@ -5702,18 +5635,17 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.y, -R0;\n"
- "MUL R1.xy, fragment.position, c[4];\n"
- "TEX R1, R1, texture[0], 2D;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[1], 2D;\n"
"MUL R2.xyz, R0, R1.w;\n"
- "MUL R3.xyz, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"MAX R2.xyz, R2, R3;\n"
"ADD R2.w, -R1, c[5].x;\n"
"MAD R0.xyz, R0, R2.w, R2;\n"
@@ -5727,41 +5659,40 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_COLORDODGE_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[6] = { program.local[0..4],\n"
- " { 1, 1e-06 } };\n"
+ " { 1, 1e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.y, -R0;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[1], 2D;\n"
"MAX R1.x, R0.w, c[5].y;\n"
"RCP R1.x, R1.x;\n"
- "MAD R1.xyz, -R0, R1.x, c[5].x;\n"
- "MAX R2.xyz, R1, c[5].y;\n"
+ "MAD R3.xyz, -R0, R1.x, c[5].x;\n"
+ "MAX R3.xyz, R3, c[5].y;\n"
"MUL R1.xy, fragment.position, c[4];\n"
"TEX R1, R1, texture[0], 2D;\n"
- "ADD R2.w, -R0, c[5].x;\n"
- "MUL R3.xyz, R1, R2.w;\n"
+ "ADD R2.x, -R0.w, c[5];\n"
+ "MUL R2.xyz, R1, R2.x;\n"
"ADD R2.w, -R1, c[5].x;\n"
- "MAD R3.xyz, R0, R2.w, R3;\n"
- "MUL R1.xyz, R1, R0.w;\n"
+ "MAD R2.xyz, R0, R2.w, R2;\n"
+ "MUL R1.xyz, R0.w, R1;\n"
"MAD R0.xyz, R0, R1.w, R1;\n"
"MUL R2.w, R0, R1;\n"
- "RCP R2.x, R2.x;\n"
- "RCP R2.y, R2.y;\n"
- "RCP R2.z, R2.z;\n"
- "MAD R2.xyz, R1, R2, R3;\n"
- "MAD R3.xyz, R0.w, R1.w, R3;\n"
+ "RCP R3.x, R3.x;\n"
+ "RCP R3.y, R3.y;\n"
+ "RCP R3.z, R3.z;\n"
+ "MAD R3.xyz, R1, R3, R2;\n"
+ "MAD R2.xyz, R0.w, R1.w, R2;\n"
"ADD R1.x, R0.w, R1.w;\n"
- "ADD R3.xyz, R3, -R2;\n"
+ "ADD R2.xyz, R2, -R3;\n"
"SGE R0.xyz, R0, R2.w;\n"
- "MAD result.color.xyz, R0, R3, R2;\n"
+ "MAD result.color.xyz, R0, R2, R3;\n"
"MAD result.color.w, -R0, R1, R1.x;\n"
"END\n"
;
@@ -5769,24 +5700,23 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_COLORBURN_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[6] = { program.local[0..4],\n"
- " { 1, 9.9999997e-06 } };\n"
+ " { 1, 9.9999997e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
"TEMP R5;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.y, -R0;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[1], 2D;\n"
- "MUL R1.xy, fragment.position, c[4];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
+ "MUL R2.xyz, R0.w, R1;\n"
"MAD R3.xyz, R0, R1.w, R2;\n"
"ADD R2.w, -R1, c[5].x;\n"
"MAD R2.xyz, -R0.w, R1.w, R3;\n"
@@ -5799,9 +5729,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"RCP R2.z, R2.z;\n"
"MAD R2.xyz, R4, R2, R5;\n"
"MUL R4.xyz, R1, R3.w;\n"
- "MAD R0.xyz, R0, R2.w, R4;\n"
- "ADD R3.w, -R0, c[5].x;\n"
"MAD R1.xyz, R1, R3.w, R2;\n"
+ "MAD R0.xyz, R0, R2.w, R4;\n"
"MUL R2.x, R0.w, R1.w;\n"
"ADD R2.w, R0, R1;\n"
"ADD R1.xyz, R1, -R0;\n"
@@ -5820,13 +5749,12 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.y, -R0;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[1], 2D;\n"
"MUL R1.xy, fragment.position, c[4];\n"
"TEX R1, R1, texture[0], 2D;\n"
@@ -5836,27 +5764,27 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"MUL R2.xyz, R2, R3;\n"
"MUL R2.xyz, R2, c[5].x;\n"
"MAD R2.xyz, R0.w, R1.w, -R2;\n"
+ "MAD R2.xyz, R0, R2.w, R2;\n"
"MUL R4.xyz, R0, R2.w;\n"
"MUL R3.xyz, R0, R1;\n"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "ADD R2.w, -R0, c[5].y;\n"
"MUL R0.xyz, R0, c[5].x;\n"
- "MAD R2.xyz, R1, R2.w, R2;\n"
+ "ADD R2.w, -R0, c[5].y;\n"
"MAD R3.xyz, R3, c[5].x, R4;\n"
- "MAD R1.xyz, R1, R2.w, R3;\n"
- "ADD R2.w, R0, R1;\n"
- "ADD R2.xyz, R2, -R1;\n"
+ "MAD R3.xyz, R1, R2.w, R3;\n"
+ "MAD R1.xyz, R1, R2.w, R2;\n"
+ "ADD R2.x, R0.w, R1.w;\n"
+ "ADD R1.xyz, R1, -R3;\n"
"SGE R0.xyz, R0, R0.w;\n"
- "MAD result.color.xyz, R0, R2, R1;\n"
- "MAD result.color.w, -R0, R1, R2;\n"
+ "MAD result.color.xyz, R0, R1, R3;\n"
+ "MAD result.color.w, -R0, R1, R2.x;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_SOFTLIGHT_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[7] = { program.local[0..4],\n"
- " { 1, 9.9999997e-06, 2, 8 },\n"
- " { 3 } };\n"
+ " { 1, 2, 9.9999997e-006, 4 },\n"
+ " { 16, 12, 3 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
@@ -5864,53 +5792,51 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R4;\n"
"TEMP R5;\n"
"TEMP R6;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
"MUL R1.xy, fragment.position, c[4];\n"
"TEX R1, R1, texture[0], 2D;\n"
- "MAX R0.z, R1.w, c[5].y;\n"
- "RCP R2.w, R0.z;\n"
- "MUL R2.xyz, R1, R2.w;\n"
- "MUL R6.xyz, -R2, c[5].w;\n"
- "MAD R3.xyz, -R1, R2.w, c[5].x;\n"
- "MOV R0.y, -R0;\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
+ "RCP R0.z, R0.z;\n"
+ "MUL R0.xy, R0, R0.z;\n"
+ "MAX R0.w, R1, c[5].z;\n"
+ "RCP R0.w, R0.w;\n"
+ "MUL R3.xyz, R1, R0.w;\n"
+ "MAD R2.xyz, R3, c[6].x, -c[6].y;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[1], 2D;\n"
- "MAD R4.xyz, R0, c[5].z, -R0.w;\n"
- "MUL R5.xyz, R3, R4;\n"
- "MAD R3.xyz, -R3, R4, R0.w;\n"
- "ADD R6.xyz, R6, c[6].x;\n"
- "RSQ R2.x, R2.x;\n"
- "RSQ R2.z, R2.z;\n"
- "RSQ R2.y, R2.y;\n"
- "MAD R5.xyz, -R5, R6, R0.w;\n"
- "MUL R3.xyz, R1, R3;\n"
- "RCP R2.x, R2.x;\n"
- "RCP R2.z, R2.z;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R2.xyz, R2, R1.w, -R1;\n"
- "MUL R6.xyz, R2, R4;\n"
- "MUL R2.xyz, R1, R5;\n"
- "MUL R4.xyz, R0, c[5].z;\n"
- "MAD R6.xyz, R1, R0.w, R6;\n"
- "MUL R5.xyz, R1, c[5].w;\n"
- "ADD R6.xyz, R6, -R2;\n"
- "SGE R5.xyz, R5, R1.w;\n"
- "MUL R5.xyz, R5, R6;\n"
- "ADD R2.xyz, R2, R5;\n"
- "ADD R2.xyz, R2, -R3;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "MUL R2.xyz, R4, R2;\n"
- "ADD R2.xyz, R3, R2;\n"
+ "MAD R4.xyz, R3, R2, c[6].z;\n"
+ "MAD R2.xyz, R0, c[5].y, -R0.w;\n"
+ "MUL R5.xyz, R1.w, R2;\n"
+ "MUL R6.xyz, R5, R4;\n"
+ "RSQ R2.w, R3.x;\n"
+ "RCP R4.x, R2.w;\n"
+ "RSQ R2.w, R3.y;\n"
+ "RSQ R3.w, R3.z;\n"
+ "RCP R4.y, R2.w;\n"
+ "RCP R4.z, R3.w;\n"
+ "ADD R4.xyz, -R3, R4;\n"
+ "MUL R6.xyz, R3, R6;\n"
+ "MUL R4.xyz, R5, R4;\n"
+ "ADD R3.xyz, -R3, c[5].x;\n"
+ "MAD R2.xyz, R2, R3, R0.w;\n"
+ "MUL R3.xyz, R0, c[5].y;\n"
+ "MAD R5.xyz, R0.w, R1, R6;\n"
+ "MAD R4.xyz, R0.w, R1, R4;\n"
+ "ADD R6.xyz, R4, -R5;\n"
+ "MUL R4.xyz, R1, c[5].w;\n"
+ "SGE R4.xyz, R4, R1.w;\n"
+ "MAD R4.xyz, R4, R6, R5;\n"
+ "MAD R4.xyz, -R1, R2, R4;\n"
+ "MUL R2.xyz, R1, R2;\n"
+ "SGE R3.xyz, R3, R0.w;\n"
+ "MAD R2.xyz, R3, R4, R2;\n"
"ADD R2.w, -R1, c[5].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, R0.w, R1.w;\n"
- "ADD R2.y, -R0.w, c[5].x;\n"
- "MAD result.color.xyz, R1, R2.y, R0;\n"
- "MAD result.color.w, -R0, R1, R2.x;\n"
+ "MAD R2.xyz, R0, R2.w, R2;\n"
+ "ADD R0.x, R0.w, R1.w;\n"
+ "ADD R0.y, -R0.w, c[5].x;\n"
+ "MAD result.color.xyz, R1, R0.y, R2;\n"
+ "MAD result.color.w, -R0, R1, R0.x;\n"
"END\n"
;
@@ -5922,18 +5848,17 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.y, -R0;\n"
- "MUL R1.xy, fragment.position, c[4];\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[1], 2D;\n"
- "TEX R1, R1, texture[0], 2D;\n"
"MUL R2.xyz, R0, R1.w;\n"
- "MUL R3.xyz, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"ADD R0.xyz, R0, R1;\n"
"MIN R2.xyz, R2, R3;\n"
"ADD R1.x, R0.w, R1.w;\n"
@@ -5945,29 +5870,28 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_EXCLUSION_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[6] = { program.local[0..4],\n"
- " { 1, 2 } };\n"
+ " { 2, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.y, -R0;\n"
- "MUL R1.xy, fragment.position, c[4];\n"
- "TEX R1, R1, texture[0], 2D;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R1, R0.zwzw, texture[0], 2D;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[1], 2D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
+ "MUL R2.xyz, R0.w, R1;\n"
"MAD R3.xyz, R0, R1.w, R2;\n"
"MUL R2.xyz, R0, R1;\n"
- "MAD R2.xyz, -R2, c[5].y, R3;\n"
- "ADD R2.w, -R1, c[5].x;\n"
+ "MAD R2.xyz, -R2, c[5].x, R3;\n"
+ "ADD R2.w, -R1, c[5].y;\n"
"MAD R0.xyz, R0, R2.w, R2;\n"
"ADD R2.x, R0.w, R1.w;\n"
- "ADD R2.y, -R0.w, c[5].x;\n"
+ "ADD R2.y, -R0.w, c[5];\n"
"MAD result.color.xyz, R1, R2.y, R0;\n"
"MAD result.color.w, -R0, R1, R2.x;\n"
"END\n"
@@ -5978,19 +5902,17 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"PARAM c[7] = { program.local[0..6] };\n"
"TEMP R0;\n"
"TEMP R1;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R1.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R1.xyz, R0, c[3];\n"
"RCP R0.z, R1.z;\n"
"MUL R1.xy, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[4];\n"
- "MUL R0.xy, R0, c[5];\n"
+ "ADD R0.xy, fragment.position, c[5];\n"
+ "MUL R0.xy, R0, c[4];\n"
"TEX R0, R0, texture[0], 2D;\n"
"DP4 R1.z, R0, c[6];\n"
- "MUL R1.xy, R1, c[3];\n"
- "MOV R0.x, R1;\n"
- "MOV R0.y, -R1;\n"
- "TEX R0, R0, texture[1], 2D;\n"
+ "MUL R1.xy, R1, c[0];\n"
+ "TEX R0, R1, texture[1], 2D;\n"
"MUL result.color, R0, R1.z;\n"
"END\n"
;
@@ -5999,58 +5921,55 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"!!ARBfp1.0\n"
"PARAM c[4] = { program.local[0..3] };\n"
"TEMP R0;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.y, -R0;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX result.color, R0, texture[0], 2D;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SIMPLE_PORTER_DUFF =
"!!ARBfp1.0\n"
- "PARAM c[11] = { program.local[0..7],\n"
- " { 1 },\n"
- " program.local[9..10] };\n"
+ "PARAM c[11] = { program.local[0..9],\n"
+ " { 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MOV R0.y, -R0;\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "TEX R0.x, R0, texture[2], 2D;\n"
- "MUL R0, fragment.color.primary, R0.x;\n"
- "MUL R2.xyz, R1, c[10].y;\n"
- "MUL R3.xyz, R2, R0.w;\n"
- "MUL R2.xyz, R0, c[10].x;\n"
- "MAD R2.xyz, R2, R1.w, R3;\n"
- "ADD R3.xy, fragment.position, c[0];\n"
- "MUL R0.xyz, R0, c[9].y;\n"
- "ADD R2.w, -R1, c[8].x;\n"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "ADD R2.w, -R0, c[8].x;\n"
- "MUL R0.xyz, R1, c[9].z;\n"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "ADD R0.y, -R1.w, c[8].x;\n"
- "MUL R0.z, R1.w, R2.w;\n"
- "MUL R0.x, R0.w, R1.w;\n"
- "MUL R0.y, R0.w, R0;\n"
- "DP3 R2.w, R0, c[9];\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.zw, R0.xyxy, c[0].xyxy;\n"
+ "TEX R1.x, R0.zwzw, texture[2], 2D;\n"
+ "MUL R0.xy, fragment.position, c[7];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "ADD R1.x, -R1, c[10];\n"
+ "MUL R1, fragment.color.primary, R1.x;\n"
+ "MUL R2.xyz, R0, c[4].y;\n"
+ "MUL R3.xyz, R1.w, R2;\n"
+ "MUL R2.xyz, R1, c[4].x;\n"
+ "MAD R2.xyz, R0.w, R2, R3;\n"
+ "ADD R3.xy, fragment.position, c[8];\n"
+ "ADD R2.w, -R0, c[10].x;\n"
+ "MUL R1.xyz, R1, c[5].y;\n"
+ "MAD R2.xyz, R2.w, R1, R2;\n"
+ "MUL R1.xyz, R0, c[5].z;\n"
+ "ADD R3.z, -R1.w, c[10].x;\n"
+ "MAD R2.xyz, R3.z, R1, R2;\n"
+ "MUL R1.y, R1.w, R2.w;\n"
+ "MUL R1.x, R1.w, R0.w;\n"
+ "MUL R1.z, R0.w, R3;\n"
+ "DP3 R2.w, R1, c[5];\n"
+ "MUL R3.xy, R3, c[6];\n"
+ "TEX R1, R3, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[9];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -6061,58 +5980,59 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MOV R0.y, -R0;\n"
- "TEX R0.x, R0, texture[2], 2D;\n"
- "MUL R0, fragment.color.primary, R0.x;\n"
- "ADD R2.x, -R1.w, c[8];\n"
- "MUL R2.xyz, R0, R2.x;\n"
- "MAD R0.xyz, R0, R1, R2;\n"
+ "MUL R0.zw, R0.xyxy, c[0].xyxy;\n"
+ "TEX R1.x, R0.zwzw, texture[2], 2D;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "ADD R1.x, -R1, c[8];\n"
+ "MUL R1, fragment.color.primary, R1.x;\n"
"ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R2.xyz, R1, R2.x;\n"
+ "MAD R1.xyz, R1, R0, R2;\n"
+ "ADD R2.x, -R1.w, c[8];\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SCREEN =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..7] };\n"
+ "PARAM c[9] = { program.local[0..7],\n"
+ " { 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[2], 2D;\n"
- "MUL R0.xy, fragment.position, c[7];\n"
- "ADD R3.xy, fragment.position, c[0];\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "TEX R0.x, R0, texture[2], 2D;\n"
+ "ADD R0.z, -R0.x, c[8].x;\n"
+ "ADD R3.xy, fragment.position, c[6];\n"
+ "MUL R1, fragment.color.primary, R0.z;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "MUL R1, fragment.color.primary, R1.x;\n"
"ADD R2, R1, R0;\n"
"MAD R2, -R1, R0, R2;\n"
- "MUL R3.xy, R3, c[1];\n"
+ "MUL R3.xy, R3, c[4];\n"
"TEX R1, R3, texture[1], 2D;\n"
"ADD R2, R2, -R0;\n"
- "DP4 R1.x, R1, c[2];\n"
+ "DP4 R1.x, R1, c[7];\n"
"MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -6120,47 +6040,47 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_OVERLAY =
"!!ARBfp1.0\n"
"PARAM c[9] = { program.local[0..7],\n"
- " { 2, 1 } };\n"
+ " { 1, 2 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[2], 2D;\n"
- "MUL R1, fragment.color.primary, R1.x;\n"
- "MUL R0.xy, fragment.position, c[7];\n"
- "TEX R0, R0, texture[0], 2D;\n"
- "ADD R2.w, -R0, c[8].y;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "TEX R0.x, R0, texture[2], 2D;\n"
+ "ADD R0.x, -R0, c[8];\n"
+ "MUL R1, fragment.color.primary, R0.x;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n"
+ "TEX R0, R0.zwzw, texture[0], 2D;\n"
+ "ADD R2.w, -R0, c[8].x;\n"
"ADD R3.xyz, R1.w, -R1;\n"
"ADD R2.xyz, R0.w, -R0;\n"
"MUL R2.xyz, R2, R3;\n"
- "MUL R2.xyz, R2, c[8].x;\n"
+ "MUL R2.xyz, R2, c[8].y;\n"
"MAD R2.xyz, R1.w, R0.w, -R2;\n"
"MUL R4.xyz, R1, R2.w;\n"
"MUL R3.xyz, R1, R0;\n"
"MAD R1.xyz, R1, R2.w, R2;\n"
- "ADD R2.x, -R1.w, c[8].y;\n"
- "MAD R3.xyz, R3, c[8].x, R4;\n"
+ "ADD R2.x, -R1.w, c[8];\n"
+ "MAD R3.xyz, R3, c[8].y, R4;\n"
"MAD R3.xyz, R0, R2.x, R3;\n"
"MAD R1.xyz, R0, R2.x, R1;\n"
- "MUL R2.xyz, R0, c[8].x;\n"
+ "MUL R2.xyz, R0, c[8].y;\n"
"ADD R1.xyz, R1, -R3;\n"
"SGE R2.xyz, R2, R0.w;\n"
"MAD R2.xyz, R2, R1, R3;\n"
"ADD R1.z, R1.w, R0.w;\n"
"MAD R2.w, -R1, R0, R1.z;\n"
- "ADD R1.xy, fragment.position, c[0];\n"
- "MUL R1.xy, R1, c[1];\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
"TEX R1, R1, texture[1], 2D;\n"
"ADD R2, R2, -R0;\n"
- "DP4 R1.x, R1, c[2];\n"
+ "DP4 R1.x, R1, c[7];\n"
"MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -6173,32 +6093,32 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MOV R0.y, -R0;\n"
- "TEX R0.x, R0, texture[2], 2D;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "MUL R0, fragment.color.primary, R0.x;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "TEX R1.x, R0, texture[2], 2D;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "ADD R1.x, -R1, c[8];\n"
+ "MUL R1, fragment.color.primary, R1.x;\n"
+ "MUL R3.xyz, R1.w, R0;\n"
+ "MUL R2.xyz, R1, R0.w;\n"
"MIN R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "ADD R2.w, -R0, c[8].x;\n"
+ "MAD R1.xyz, R1, R2.w, R2;\n"
+ "ADD R2.x, -R1.w, c[8];\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -6210,64 +6130,64 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MOV R0.y, -R0;\n"
- "TEX R0.x, R0, texture[2], 2D;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "MUL R0, fragment.color.primary, R0.x;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "TEX R1.x, R0, texture[2], 2D;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "ADD R1.x, -R1, c[8];\n"
+ "MUL R1, fragment.color.primary, R1.x;\n"
+ "MUL R3.xyz, R1.w, R0;\n"
+ "MUL R2.xyz, R1, R0.w;\n"
"MAX R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "ADD R2.w, -R0, c[8].x;\n"
+ "MAD R1.xyz, R1, R2.w, R2;\n"
+ "ADD R2.x, -R1.w, c[8];\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_COLORDODGE =
"!!ARBfp1.0\n"
"PARAM c[9] = { program.local[0..7],\n"
- " { 1, 1e-06 } };\n"
+ " { 1, 1e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MOV R0.y, -R0;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0.x, R0, texture[2], 2D;\n"
+ "ADD R0.x, -R0, c[8];\n"
"MUL R1, fragment.color.primary, R0.x;\n"
"MAX R0.x, R1.w, c[8].y;\n"
"RCP R0.x, R0.x;\n"
- "MAD R0.xyz, -R1, R0.x, c[8].x;\n"
- "MAX R2.xyz, R0, c[8].y;\n"
- "MUL R0.xy, fragment.position, c[7];\n"
+ "MAD R2.xyz, -R1, R0.x, c[8].x;\n"
+ "MAX R2.xyz, R2, c[8].y;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
"TEX R0, R0, texture[0], 2D;\n"
"ADD R2.w, -R1, c[8].x;\n"
"MUL R3.xyz, R0, R2.w;\n"
"ADD R2.w, -R0, c[8].x;\n"
"MAD R4.xyz, R1, R2.w, R3;\n"
- "MUL R3.xyz, R0, R1.w;\n"
+ "MUL R3.xyz, R1.w, R0;\n"
"MUL R2.w, R1, R0;\n"
"MAD R1.xyz, R1, R0.w, R3;\n"
"SGE R1.xyz, R1, R2.w;\n"
@@ -6280,11 +6200,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"MAD R2.xyz, R1, R4, R2;\n"
"ADD R1.z, R1.w, R0.w;\n"
"MAD R2.w, -R1, R0, R1.z;\n"
- "ADD R1.xy, fragment.position, c[0];\n"
- "MUL R1.xy, R1, c[1];\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
"TEX R1, R1, texture[1], 2D;\n"
"ADD R2, R2, -R0;\n"
- "DP4 R1.x, R1, c[2];\n"
+ "DP4 R1.x, R1, c[7];\n"
"MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -6292,25 +6212,25 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_COLORBURN =
"!!ARBfp1.0\n"
"PARAM c[9] = { program.local[0..7],\n"
- " { 1, 9.9999997e-06 } };\n"
+ " { 1, 9.9999997e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
"TEMP R5;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[2], 2D;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "TEX R0.x, R0, texture[2], 2D;\n"
+ "ADD R1.x, -R0, c[8];\n"
"MUL R1, fragment.color.primary, R1.x;\n"
- "MUL R0.xy, fragment.position, c[7];\n"
- "TEX R0, R0, texture[0], 2D;\n"
- "MUL R2.xyz, R0, R1.w;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n"
+ "TEX R0, R0.zwzw, texture[0], 2D;\n"
+ "MUL R2.xyz, R1.w, R0;\n"
"MAD R3.xyz, R1, R0.w, R2;\n"
"MAD R2.xyz, -R1.w, R0.w, R3;\n"
"MUL R4.xyz, R1.w, R2;\n"
@@ -6325,18 +6245,17 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"MUL R4.xyz, R0, R3.w;\n"
"MAD R1.xyz, R1, R2.w, R4;\n"
"MUL R2.w, R1, R0;\n"
- "ADD R3.w, -R1, c[8].x;\n"
"MAD R2.xyz, R0, R3.w, R2;\n"
"ADD R2.xyz, R2, -R1;\n"
"SGE R3.xyz, R3, R2.w;\n"
"MAD R2.xyz, R3, R2, R1;\n"
"ADD R1.z, R1.w, R0.w;\n"
"MAD R2.w, -R1, R0, R1.z;\n"
- "ADD R1.xy, fragment.position, c[0];\n"
- "MUL R1.xy, R1, c[1];\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
"TEX R1, R1, texture[1], 2D;\n"
"ADD R2, R2, -R0;\n"
- "DP4 R1.x, R1, c[2];\n"
+ "DP4 R1.x, R1, c[7];\n"
"MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -6344,35 +6263,35 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_HARDLIGHT =
"!!ARBfp1.0\n"
"PARAM c[9] = { program.local[0..7],\n"
- " { 2, 1 } };\n"
+ " { 1, 2 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[2], 2D;\n"
- "MUL R1, fragment.color.primary, R1.x;\n"
- "MUL R0.xy, fragment.position, c[7];\n"
- "TEX R0, R0, texture[0], 2D;\n"
- "ADD R2.w, -R0, c[8].y;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "TEX R0.x, R0, texture[2], 2D;\n"
+ "ADD R0.x, -R0, c[8];\n"
+ "MUL R1, fragment.color.primary, R0.x;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n"
+ "TEX R0, R0.zwzw, texture[0], 2D;\n"
+ "ADD R2.w, -R0, c[8].x;\n"
"ADD R3.xyz, R1.w, -R1;\n"
"ADD R2.xyz, R0.w, -R0;\n"
"MUL R2.xyz, R2, R3;\n"
- "MUL R2.xyz, R2, c[8].x;\n"
+ "MUL R2.xyz, R2, c[8].y;\n"
"MAD R2.xyz, R1.w, R0.w, -R2;\n"
"MUL R4.xyz, R1, R2.w;\n"
"MAD R2.xyz, R1, R2.w, R2;\n"
"MUL R3.xyz, R1, R0;\n"
- "ADD R2.w, -R1, c[8].y;\n"
- "MAD R3.xyz, R3, c[8].x, R4;\n"
- "MUL R1.xyz, R1, c[8].x;\n"
+ "ADD R2.w, -R1, c[8].x;\n"
+ "MAD R3.xyz, R3, c[8].y, R4;\n"
+ "MUL R1.xyz, R1, c[8].y;\n"
"SGE R1.xyz, R1, R1.w;\n"
"MAD R3.xyz, R0, R2.w, R3;\n"
"MAD R2.xyz, R0, R2.w, R2;\n"
@@ -6380,11 +6299,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"MAD R2.xyz, R1, R2, R3;\n"
"ADD R1.z, R1.w, R0.w;\n"
"MAD R2.w, -R1, R0, R1.z;\n"
- "ADD R1.xy, fragment.position, c[0];\n"
- "MUL R1.xy, R1, c[1];\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
"TEX R1, R1, texture[1], 2D;\n"
"ADD R2, R2, -R0;\n"
- "DP4 R1.x, R1, c[2];\n"
+ "DP4 R1.x, R1, c[7];\n"
"MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -6392,68 +6311,67 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SOFTLIGHT =
"!!ARBfp1.0\n"
"PARAM c[10] = { program.local[0..7],\n"
- " { 1, 9.9999997e-06, 2, 8 },\n"
- " { 3 } };\n"
+ " { 1, 2, 9.9999997e-006, 4 },\n"
+ " { 16, 12, 3 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
"TEMP R5;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R1.xyz, R0, c[5];\n"
- "RCP R0.z, R1.z;\n"
- "MUL R1.xy, R1, R0.z;\n"
- "MUL R1.xy, R1, c[6];\n"
- "MOV R1.y, -R1;\n"
- "MUL R0.xy, fragment.position, c[7];\n"
- "TEX R0, R0, texture[0], 2D;\n"
- "MAX R1.z, R0.w, c[8].y;\n"
- "RCP R2.w, R1.z;\n"
- "MUL R2.xyz, R0, R2.w;\n"
- "MUL R5.xyz, -R2, c[8].w;\n"
- "MAD R4.xyz, -R0, R2.w, c[8].x;\n"
+ "TEMP R6;\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R1.xyz, R0, c[3];\n"
+ "RCP R1.z, R1.z;\n"
+ "MUL R1.xy, R1, R1.z;\n"
+ "MUL R1.xy, R1, c[0];\n"
"TEX R1.x, R1, texture[2], 2D;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "MAX R1.z, R0.w, c[8];\n"
+ "RCP R1.z, R1.z;\n"
+ "MUL R3.xyz, R0, R1.z;\n"
+ "MAD R2.xyz, R3, c[9].x, -c[9].y;\n"
+ "ADD R1.x, -R1, c[8];\n"
"MUL R1, fragment.color.primary, R1.x;\n"
- "MAD R3.xyz, R1, c[8].z, -R1.w;\n"
- "RSQ R2.x, R2.x;\n"
- "RSQ R2.z, R2.z;\n"
- "RSQ R2.y, R2.y;\n"
- "MUL R4.xyz, R4, R3;\n"
- "ADD R5.xyz, R5, c[9].x;\n"
- "MUL R5.xyz, R4, R5;\n"
- "ADD R4.xyz, R1.w, -R4;\n"
- "ADD R2.w, -R0, c[8].x;\n"
- "RCP R2.x, R2.x;\n"
- "RCP R2.z, R2.z;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R2.xyz, R2, R0.w, -R0;\n"
- "MUL R3.xyz, R2, R3;\n"
- "ADD R2.xyz, R1.w, -R5;\n"
- "MAD R5.xyz, R0, R1.w, R3;\n"
+ "MAD R4.xyz, R3, R2, c[9].z;\n"
+ "MAD R2.xyz, R1, c[8].y, -R1.w;\n"
+ "MUL R5.xyz, R0.w, R2;\n"
+ "MUL R6.xyz, R5, R4;\n"
+ "RSQ R2.w, R3.x;\n"
+ "RCP R4.x, R2.w;\n"
+ "RSQ R2.w, R3.y;\n"
+ "RSQ R3.w, R3.z;\n"
+ "RCP R4.y, R2.w;\n"
+ "RCP R4.z, R3.w;\n"
+ "ADD R4.xyz, -R3, R4;\n"
+ "MUL R6.xyz, R3, R6;\n"
+ "MUL R4.xyz, R5, R4;\n"
+ "ADD R3.xyz, -R3, c[8].x;\n"
+ "MAD R2.xyz, R2, R3, R1.w;\n"
+ "MUL R3.xyz, R1, c[8].y;\n"
+ "MAD R5.xyz, R1.w, R0, R6;\n"
+ "MAD R4.xyz, R1.w, R0, R4;\n"
+ "ADD R6.xyz, R4, -R5;\n"
+ "MUL R4.xyz, R0, c[8].w;\n"
+ "SGE R4.xyz, R4, R0.w;\n"
+ "MAD R4.xyz, R4, R6, R5;\n"
+ "MAD R4.xyz, -R0, R2, R4;\n"
+ "SGE R3.xyz, R3, R1.w;\n"
"MUL R2.xyz, R0, R2;\n"
- "MUL R3.xyz, R0, c[8].w;\n"
- "ADD R5.xyz, R5, -R2;\n"
- "SGE R3.xyz, R3, R0.w;\n"
- "MUL R3.xyz, R3, R5;\n"
- "ADD R2.xyz, R2, R3;\n"
- "MUL R3.xyz, R0, R4;\n"
- "MUL R4.xyz, R1, c[8].z;\n"
- "SGE R4.xyz, R4, R1.w;\n"
- "ADD R2.xyz, R2, -R3;\n"
- "MUL R2.xyz, R4, R2;\n"
- "ADD R2.xyz, R3, R2;\n"
- "MAD R1.xyz, R1, R2.w, R2;\n"
- "ADD R2.x, -R1.w, c[8];\n"
- "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R2.w, -R0, c[8].x;\n"
+ "MAD R2.xyz, R3, R4, R2;\n"
+ "MAD R2.xyz, R1, R2.w, R2;\n"
+ "ADD R1.x, -R1.w, c[8];\n"
+ "MAD R2.xyz, R0, R1.x, R2;\n"
"ADD R1.z, R1.w, R0.w;\n"
"MAD R2.w, -R1, R0, R1.z;\n"
- "ADD R1.xy, fragment.position, c[0];\n"
- "MUL R1.xy, R1, c[1];\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
"TEX R1, R1, texture[1], 2D;\n"
"ADD R2, R2, -R0;\n"
- "DP4 R1.x, R1, c[2];\n"
+ "DP4 R1.x, R1, c[7];\n"
"MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -6461,35 +6379,35 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_DIFFERENCE =
"!!ARBfp1.0\n"
"PARAM c[9] = { program.local[0..7],\n"
- " { 2 } };\n"
+ " { 1, 2 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MOV R0.y, -R0;\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "TEX R0.x, R0, texture[2], 2D;\n"
- "MUL R0, fragment.color.primary, R0.x;\n"
- "ADD R3.xyz, R0, R1;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MUL R0.xyz, R0, R1.w;\n"
- "MIN R0.xyz, R0, R2;\n"
- "MAD R2.xyz, -R0, c[8].x, R3;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "TEX R1.x, R0, texture[2], 2D;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "ADD R1.x, -R1, c[8];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "MUL R1, fragment.color.primary, R1.x;\n"
+ "ADD R2.xyz, R1, R0;\n"
+ "MUL R3.xyz, R1.w, R0;\n"
+ "MUL R1.xyz, R1, R0.w;\n"
+ "MIN R1.xyz, R1, R3;\n"
+ "MAD R2.xyz, -R1, c[8].y, R2;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -6501,72 +6419,69 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MOV R0.y, -R0;\n"
- "TEX R0.x, R0, texture[2], 2D;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "MUL R0, fragment.color.primary, R0.x;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MAD R3.xyz, R0, R1.w, R2;\n"
- "MUL R2.xyz, R0, R1;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "TEX R1.x, R0, texture[2], 2D;\n"
+ "MUL R0.xy, fragment.position, c[5];\n"
+ "TEX R0, R0, texture[0], 2D;\n"
+ "ADD R1.x, -R1, c[8];\n"
+ "MUL R1, fragment.color.primary, R1.x;\n"
+ "MUL R2.xyz, R1.w, R0;\n"
+ "MAD R3.xyz, R1, R0.w, R2;\n"
+ "MUL R2.xyz, R1, R0;\n"
"MAD R2.xyz, -R2, c[8].y, R3;\n"
- "ADD R2.w, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\n"
+ "ADD R2.w, -R0, c[8].x;\n"
+ "MAD R1.xyz, R1, R2.w, R2;\n"
+ "ADD R2.x, -R1.w, c[8];\n"
+ "MAD R2.xyz, R0, R2.x, R1;\n"
+ "ADD R1.z, R1.w, R0.w;\n"
+ "MAD R2.w, -R1, R0, R1.z;\n"
+ "ADD R1.xy, fragment.position, c[6];\n"
+ "MUL R1.xy, R1, c[4];\n"
+ "TEX R1, R1, texture[1], 2D;\n"
+ "ADD R2, R2, -R0;\n"
+ "DP4 R1.x, R1, c[7];\n"
+ "MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..4],\n"
- " { 1 },\n"
- " program.local[6..7] };\n"
+ "PARAM c[8] = { program.local[0..6],\n"
+ " { 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.w, -R0.y;\n"
- "MOV R0.z, R0.x;\n"
- "TEX R1.x, R0.zwzw, texture[1], 2D;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
- "TEX R0, R0, texture[0], 2D;\n"
- "MUL R2.xyz, R0, c[7].y;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "TEX R1.x, R0, texture[1], 2D;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\n"
+ "TEX R0, R0.zwzw, texture[0], 2D;\n"
+ "MUL R2.xyz, R0, c[4].y;\n"
+ "ADD R1.x, -R1, c[7];\n"
"MUL R1, fragment.color.primary, R1.x;\n"
- "MUL R3.xyz, R2, R1.w;\n"
- "MUL R2.xyz, R1, c[7].x;\n"
- "MUL R0.xyz, R0, c[6].z;\n"
- "MAD R2.xyz, R2, R0.w, R3;\n"
- "MUL R1.xyz, R1, c[6].y;\n"
- "ADD R2.w, -R0, c[5].x;\n"
- "MAD R1.xyz, R1, R2.w, R2;\n"
- "ADD R2.x, -R1.w, c[5];\n"
- "MAD result.color.xyz, R0, R2.x, R1;\n"
- "ADD R0.y, -R0.w, c[5].x;\n"
+ "MUL R3.xyz, R1.w, R2;\n"
+ "MUL R2.xyz, R1, c[4].x;\n"
+ "MUL R0.xyz, R0, c[5].z;\n"
+ "MAD R2.xyz, R0.w, R2, R3;\n"
+ "ADD R2.w, -R0, c[7].x;\n"
+ "MUL R1.xyz, R1, c[5].y;\n"
+ "MAD R1.xyz, R2.w, R1, R2;\n"
+ "ADD R2.x, -R1.w, c[7];\n"
+ "MAD result.color.xyz, R2.x, R0, R1;\n"
"MUL R0.x, R1.w, R0.w;\n"
"MUL R0.z, R0.w, R2.x;\n"
- "MUL R0.y, R1.w, R0;\n"
- "DP3 result.color.w, R0, c[6];\n"
+ "MUL R0.y, R1.w, R2.w;\n"
+ "DP3 result.color.w, R0, c[5];\n"
"END\n"
;
@@ -6577,16 +6492,16 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
- "MUL R0.zw, R0.xyxy, R0.z;\n"
- "MUL R1.xy, R0.zwzw, c[3];\n"
- "MOV R1.y, -R1;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
- "TEX R0, R0, texture[0], 2D;\n"
- "TEX R1.x, R1, texture[1], 2D;\n"
+ "MUL R0.xy, R0, R0.z;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "TEX R1.x, R0, texture[1], 2D;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R0, R0.zwzw, texture[0], 2D;\n"
+ "ADD R1.x, -R1, c[5];\n"
"MUL R1, fragment.color.primary, R1.x;\n"
"ADD R2.x, -R0.w, c[5];\n"
"MUL R2.xyz, R1, R2.x;\n"
@@ -6600,21 +6515,21 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SCREEN_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[5] = { program.local[0..4] };\n"
+ "PARAM c[6] = { program.local[0..4],\n"
+ " { 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.w, -R0.y;\n"
- "MOV R0.z, R0.x;\n"
- "TEX R1.x, R0.zwzw, texture[1], 2D;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
- "TEX R0, R0, texture[0], 2D;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "TEX R0.x, R0, texture[1], 2D;\n"
+ "ADD R1.x, -R0, c[5];\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R0, R0.zwzw, texture[0], 2D;\n"
"MUL R1, fragment.color.primary, R1.x;\n"
"ADD R2, R1, R0;\n"
"MAD result.color, -R1, R0, R2;\n"
@@ -6624,36 +6539,36 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_OVERLAY_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[6] = { program.local[0..4],\n"
- " { 2, 1 } };\n"
+ " { 1, 2 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[1], 2D;\n"
- "MUL R1, fragment.color.primary, R1.x;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
- "TEX R0, R0, texture[0], 2D;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "TEX R0.x, R0, texture[1], 2D;\n"
+ "ADD R0.x, -R0, c[5];\n"
+ "MUL R1, fragment.color.primary, R0.x;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R0, R0.zwzw, texture[0], 2D;\n"
"ADD R3.xyz, R1.w, -R1;\n"
"ADD R2.xyz, R0.w, -R0;\n"
"MUL R2.xyz, R2, R3;\n"
- "ADD R2.w, -R0, c[5].y;\n"
- "MUL R2.xyz, R2, c[5].x;\n"
+ "ADD R2.w, -R0, c[5].x;\n"
+ "MUL R2.xyz, R2, c[5].y;\n"
"MAD R2.xyz, R1.w, R0.w, -R2;\n"
"MAD R2.xyz, R1, R2.w, R2;\n"
"MUL R3.xyz, R1, R2.w;\n"
"MUL R1.xyz, R1, R0;\n"
- "ADD R2.w, -R1, c[5].y;\n"
- "MAD R1.xyz, R1, c[5].x, R3;\n"
+ "ADD R2.w, -R1, c[5].x;\n"
+ "MAD R1.xyz, R1, c[5].y, R3;\n"
"MAD R1.xyz, R0, R2.w, R1;\n"
"MAD R2.xyz, R0, R2.w, R2;\n"
- "MUL R0.xyz, R0, c[5].x;\n"
+ "MUL R0.xyz, R0, c[5].y;\n"
"ADD R2.w, R1, R0;\n"
"ADD R2.xyz, R2, -R1;\n"
"SGE R0.xyz, R0, R0.w;\n"
@@ -6670,19 +6585,19 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[1], 2D;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
- "TEX R0, R0, texture[0], 2D;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "TEX R0.x, R0, texture[1], 2D;\n"
+ "ADD R1.x, -R0, c[5];\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R0, R0.zwzw, texture[0], 2D;\n"
"MUL R1, fragment.color.primary, R1.x;\n"
"MUL R2.xyz, R1, R0.w;\n"
- "MUL R3.xyz, R0, R1.w;\n"
+ "MUL R3.xyz, R1.w, R0;\n"
"MIN R2.xyz, R2, R3;\n"
"ADD R2.w, -R0, c[5].x;\n"
"MAD R1.xyz, R1, R2.w, R2;\n"
@@ -6701,19 +6616,19 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[1], 2D;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
- "TEX R0, R0, texture[0], 2D;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "TEX R0.x, R0, texture[1], 2D;\n"
+ "ADD R1.x, -R0, c[5];\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R0, R0.zwzw, texture[0], 2D;\n"
"MUL R1, fragment.color.primary, R1.x;\n"
"MUL R2.xyz, R1, R0.w;\n"
- "MUL R3.xyz, R0, R1.w;\n"
+ "MUL R3.xyz, R1.w, R0;\n"
"MAX R2.xyz, R2, R3;\n"
"ADD R2.w, -R0, c[5].x;\n"
"MAD R1.xyz, R1, R2.w, R2;\n"
@@ -6727,42 +6642,42 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_COLORDODGE_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[6] = { program.local[0..4],\n"
- " { 1, 1e-06 } };\n"
+ " { 1, 1e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.y, -R0;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0.x, R0, texture[1], 2D;\n"
+ "ADD R0.x, -R0, c[5];\n"
"MUL R1, fragment.color.primary, R0.x;\n"
"MAX R0.x, R1.w, c[5].y;\n"
"RCP R0.x, R0.x;\n"
- "MAD R0.xyz, -R1, R0.x, c[5].x;\n"
- "MAX R2.xyz, R0, c[5].y;\n"
+ "MAD R3.xyz, -R1, R0.x, c[5].x;\n"
+ "MAX R3.xyz, R3, c[5].y;\n"
"MUL R0.xy, fragment.position, c[4];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "ADD R2.w, -R1, c[5].x;\n"
- "MUL R3.xyz, R0, R2.w;\n"
+ "ADD R2.x, -R1.w, c[5];\n"
+ "MUL R2.xyz, R0, R2.x;\n"
"ADD R2.w, -R0, c[5].x;\n"
- "MAD R3.xyz, R1, R2.w, R3;\n"
- "MUL R0.xyz, R0, R1.w;\n"
- "RCP R2.x, R2.x;\n"
- "RCP R2.y, R2.y;\n"
- "RCP R2.z, R2.z;\n"
- "MAD R2.xyz, R0, R2, R3;\n"
+ "MAD R2.xyz, R1, R2.w, R2;\n"
+ "MUL R0.xyz, R1.w, R0;\n"
+ "RCP R3.x, R3.x;\n"
+ "RCP R3.y, R3.y;\n"
+ "RCP R3.z, R3.z;\n"
+ "MAD R3.xyz, R0, R3, R2;\n"
"MAD R0.xyz, R1, R0.w, R0;\n"
- "MAD R3.xyz, R1.w, R0.w, R3;\n"
+ "MAD R2.xyz, R1.w, R0.w, R2;\n"
"MUL R2.w, R1, R0;\n"
"ADD R1.x, R1.w, R0.w;\n"
- "ADD R3.xyz, R3, -R2;\n"
+ "ADD R2.xyz, R2, -R3;\n"
"SGE R0.xyz, R0, R2.w;\n"
- "MAD result.color.xyz, R0, R3, R2;\n"
+ "MAD result.color.xyz, R0, R2, R3;\n"
"MAD result.color.w, -R1, R0, R1.x;\n"
"END\n"
;
@@ -6770,25 +6685,25 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_COLORBURN_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[6] = { program.local[0..4],\n"
- " { 1, 9.9999997e-06 } };\n"
+ " { 1, 9.9999997e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
"TEMP R5;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[1], 2D;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "TEX R0.x, R0, texture[1], 2D;\n"
+ "ADD R1.x, -R0, c[5];\n"
"MUL R1, fragment.color.primary, R1.x;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
- "TEX R0, R0, texture[0], 2D;\n"
- "MUL R2.xyz, R0, R1.w;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R0, R0.zwzw, texture[0], 2D;\n"
+ "MUL R2.xyz, R1.w, R0;\n"
"MAD R3.xyz, R1, R0.w, R2;\n"
"ADD R2.w, -R0, c[5].x;\n"
"MAD R2.xyz, -R1.w, R0.w, R3;\n"
@@ -6801,9 +6716,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"RCP R2.z, R2.z;\n"
"MAD R2.xyz, R4, R2, R5;\n"
"MUL R4.xyz, R0, R3.w;\n"
- "MAD R1.xyz, R1, R2.w, R4;\n"
- "ADD R3.w, -R1, c[5].x;\n"
"MAD R0.xyz, R0, R3.w, R2;\n"
+ "MAD R1.xyz, R1, R2.w, R4;\n"
"MUL R2.x, R1.w, R0.w;\n"
"ADD R2.w, R1, R0;\n"
"ADD R0.xyz, R0, -R1;\n"
@@ -6816,133 +6730,132 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_HARDLIGHT_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[6] = { program.local[0..4],\n"
- " { 2, 1 } };\n"
+ " { 1, 2 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[1], 2D;\n"
- "MUL R1, fragment.color.primary, R1.x;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
- "TEX R0, R0, texture[0], 2D;\n"
- "ADD R2.w, -R0, c[5].y;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "TEX R0.x, R0, texture[1], 2D;\n"
+ "ADD R0.x, -R0, c[5];\n"
+ "MUL R1, fragment.color.primary, R0.x;\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R0, R0.zwzw, texture[0], 2D;\n"
+ "ADD R2.w, -R0, c[5].x;\n"
"ADD R3.xyz, R1.w, -R1;\n"
"ADD R2.xyz, R0.w, -R0;\n"
"MUL R2.xyz, R2, R3;\n"
- "MUL R2.xyz, R2, c[5].x;\n"
+ "MUL R2.xyz, R2, c[5].y;\n"
"MAD R2.xyz, R1.w, R0.w, -R2;\n"
+ "MAD R2.xyz, R1, R2.w, R2;\n"
"MUL R4.xyz, R1, R2.w;\n"
"MUL R3.xyz, R1, R0;\n"
- "MAD R2.xyz, R1, R2.w, R2;\n"
- "ADD R2.w, -R1, c[5].y;\n"
- "MUL R1.xyz, R1, c[5].x;\n"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "MAD R3.xyz, R3, c[5].x, R4;\n"
- "MAD R0.xyz, R0, R2.w, R3;\n"
- "ADD R2.w, R1, R0;\n"
- "ADD R2.xyz, R2, -R0;\n"
+ "MUL R1.xyz, R1, c[5].y;\n"
+ "ADD R2.w, -R1, c[5].x;\n"
+ "MAD R3.xyz, R3, c[5].y, R4;\n"
+ "MAD R3.xyz, R0, R2.w, R3;\n"
+ "MAD R0.xyz, R0, R2.w, R2;\n"
+ "ADD R2.x, R1.w, R0.w;\n"
+ "ADD R0.xyz, R0, -R3;\n"
"SGE R1.xyz, R1, R1.w;\n"
- "MAD result.color.xyz, R1, R2, R0;\n"
- "MAD result.color.w, -R1, R0, R2;\n"
+ "MAD result.color.xyz, R1, R0, R3;\n"
+ "MAD result.color.w, -R1, R0, R2.x;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SOFTLIGHT_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[7] = { program.local[0..4],\n"
- " { 1, 9.9999997e-06, 2, 8 },\n"
- " { 3 } };\n"
+ " { 1, 2, 9.9999997e-006, 4 },\n"
+ " { 16, 12, 3 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
"TEMP R5;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R1.xyz, R0, c[2];\n"
- "RCP R0.z, R1.z;\n"
- "MUL R1.xy, R1, R0.z;\n"
- "MUL R1.xy, R1, c[3];\n"
- "MOV R1.y, -R1;\n"
+ "TEMP R6;\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R1.xyz, R0, c[3];\n"
+ "RCP R1.z, R1.z;\n"
+ "MUL R1.xy, R1, R1.z;\n"
+ "MUL R1.xy, R1, c[0];\n"
+ "TEX R1.x, R1, texture[1], 2D;\n"
"MUL R0.xy, fragment.position, c[4];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "MAX R1.z, R0.w, c[5].y;\n"
- "RCP R2.w, R1.z;\n"
- "MUL R2.xyz, R0, R2.w;\n"
- "MUL R5.xyz, -R2, c[5].w;\n"
- "MAD R4.xyz, -R0, R2.w, c[5].x;\n"
- "TEX R1.x, R1, texture[1], 2D;\n"
+ "MAX R1.z, R0.w, c[5];\n"
+ "RCP R1.z, R1.z;\n"
+ "MUL R3.xyz, R0, R1.z;\n"
+ "MAD R2.xyz, R3, c[6].x, -c[6].y;\n"
+ "ADD R1.x, -R1, c[5];\n"
"MUL R1, fragment.color.primary, R1.x;\n"
- "MAD R3.xyz, R1, c[5].z, -R1.w;\n"
- "RSQ R2.x, R2.x;\n"
- "RSQ R2.z, R2.z;\n"
- "RSQ R2.y, R2.y;\n"
- "MUL R4.xyz, R4, R3;\n"
- "ADD R5.xyz, R5, c[6].x;\n"
- "MUL R5.xyz, R4, R5;\n"
- "ADD R4.xyz, R1.w, -R4;\n"
- "RCP R2.x, R2.x;\n"
- "RCP R2.z, R2.z;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R2.xyz, R2, R0.w, -R0;\n"
- "MUL R3.xyz, R2, R3;\n"
- "ADD R2.xyz, R1.w, -R5;\n"
- "MAD R5.xyz, R0, R1.w, R3;\n"
+ "MAD R4.xyz, R3, R2, c[6].z;\n"
+ "MAD R2.xyz, R1, c[5].y, -R1.w;\n"
+ "MUL R5.xyz, R0.w, R2;\n"
+ "MUL R6.xyz, R5, R4;\n"
+ "RSQ R2.w, R3.x;\n"
+ "RCP R4.x, R2.w;\n"
+ "RSQ R2.w, R3.y;\n"
+ "RSQ R3.w, R3.z;\n"
+ "RCP R4.y, R2.w;\n"
+ "RCP R4.z, R3.w;\n"
+ "ADD R4.xyz, -R3, R4;\n"
+ "MUL R6.xyz, R3, R6;\n"
+ "MUL R4.xyz, R5, R4;\n"
+ "ADD R3.xyz, -R3, c[5].x;\n"
+ "MAD R2.xyz, R2, R3, R1.w;\n"
+ "MUL R3.xyz, R1, c[5].y;\n"
+ "MAD R5.xyz, R1.w, R0, R6;\n"
+ "MAD R4.xyz, R1.w, R0, R4;\n"
+ "ADD R6.xyz, R4, -R5;\n"
+ "MUL R4.xyz, R0, c[5].w;\n"
+ "SGE R4.xyz, R4, R0.w;\n"
+ "MAD R4.xyz, R4, R6, R5;\n"
+ "MAD R4.xyz, -R0, R2, R4;\n"
"MUL R2.xyz, R0, R2;\n"
- "MUL R3.xyz, R0, c[5].w;\n"
- "ADD R5.xyz, R5, -R2;\n"
- "SGE R3.xyz, R3, R0.w;\n"
- "MUL R3.xyz, R3, R5;\n"
- "ADD R2.xyz, R2, R3;\n"
- "MUL R3.xyz, R0, R4;\n"
- "MUL R4.xyz, R1, c[5].z;\n"
- "ADD R2.xyz, R2, -R3;\n"
- "SGE R4.xyz, R4, R1.w;\n"
- "MUL R2.xyz, R4, R2;\n"
- "ADD R2.xyz, R3, R2;\n"
+ "SGE R3.xyz, R3, R1.w;\n"
+ "MAD R2.xyz, R3, R4, R2;\n"
"ADD R2.w, -R0, c[5].x;\n"
- "MAD R1.xyz, R1, R2.w, R2;\n"
- "ADD R2.x, R1.w, R0.w;\n"
- "ADD R2.y, -R1.w, c[5].x;\n"
- "MAD result.color.xyz, R0, R2.y, R1;\n"
- "MAD result.color.w, -R1, R0, R2.x;\n"
+ "MAD R2.xyz, R1, R2.w, R2;\n"
+ "ADD R1.x, R1.w, R0.w;\n"
+ "ADD R1.y, -R1.w, c[5].x;\n"
+ "MAD result.color.xyz, R0, R1.y, R2;\n"
+ "MAD result.color.w, -R1, R0, R1.x;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_DIFFERENCE_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[6] = { program.local[0..4],\n"
- " { 2 } };\n"
+ " { 1, 2 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[1], 2D;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "TEX R0.x, R0, texture[1], 2D;\n"
+ "ADD R1.x, -R0, c[5];\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R0, R0.zwzw, texture[0], 2D;\n"
"MUL R1, fragment.color.primary, R1.x;\n"
- "TEX R0, R0, texture[0], 2D;\n"
- "MUL R3.xyz, R0, R1.w;\n"
+ "MUL R3.xyz, R1.w, R0;\n"
"MUL R2.xyz, R1, R0.w;\n"
"ADD R0.xyz, R1, R0;\n"
"MIN R2.xyz, R2, R3;\n"
"ADD R1.x, R1.w, R0.w;\n"
- "MAD result.color.xyz, -R2, c[5].x, R0;\n"
+ "MAD result.color.xyz, -R2, c[5].y, R0;\n"
"MAD result.color.w, -R1, R0, R1.x;\n"
"END\n"
;
@@ -6955,18 +6868,18 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[1], 2D;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
- "TEX R0, R0, texture[0], 2D;\n"
+ "MUL R0.xy, R0, c[0];\n"
+ "TEX R0.x, R0, texture[1], 2D;\n"
+ "ADD R1.x, -R0, c[5];\n"
+ "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
+ "TEX R0, R0.zwzw, texture[0], 2D;\n"
"MUL R1, fragment.color.primary, R1.x;\n"
- "MUL R2.xyz, R0, R1.w;\n"
+ "MUL R2.xyz, R1.w, R0;\n"
"MAD R3.xyz, R1, R0.w, R2;\n"
"MUL R2.xyz, R1, R0;\n"
"MAD R2.xyz, -R2, c[5].y, R3;\n"
@@ -6981,38 +6894,40 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODE_BLEND_MODE_MASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..6] };\n"
+ "PARAM c[8] = { program.local[0..6],\n"
+ " { 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R1.xyz, R0, c[2];\n"
- "RCP R0.z, R1.z;\n"
- "MUL R0.zw, R1.xyxy, R0.z;\n"
- "MUL R1.xy, R0.zwzw, c[3];\n"
- "MOV R1.y, -R1;\n"
- "ADD R0.xy, fragment.position, c[4];\n"
- "MUL R0.xy, R0, c[5];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
+ "RCP R0.z, R0.z;\n"
+ "MUL R0.zw, R0.xyxy, R0.z;\n"
+ "MUL R0.zw, R0, c[0].xyxy;\n"
+ "TEX R1.x, R0.zwzw, texture[1], 2D;\n"
+ "ADD R0.xy, fragment.position, c[5];\n"
+ "MUL R0.xy, R0, c[4];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "TEX R1.x, R1, texture[1], 2D;\n"
- "DP4 R0.x, R0, c[6];\n"
- "MUL R1, fragment.color.primary, R1.x;\n"
- "MUL result.color, R1, R0.x;\n"
+ "DP4 R1.y, R0, c[6];\n"
+ "ADD R1.x, -R1, c[7];\n"
+ "MUL R0, fragment.color.primary, R1.x;\n"
+ "MUL result.color, R0, R1.y;\n"
"END\n"
;
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODE_BLEND_MODE_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[4] = { program.local[0..3] };\n"
+ "PARAM c[5] = { program.local[0..3],\n"
+ " { 1 } };\n"
"TEMP R0;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
+ "MUL R0.xyz, fragment.position.y, c[2];\n"
+ "MAD R0.xyz, fragment.position.x, c[1], R0;\n"
+ "ADD R0.xyz, R0, c[3];\n"
"RCP R0.z, R0.z;\n"
"MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MOV R0.y, -R0;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0.x, R0, texture[0], 2D;\n"
+ "ADD R0.x, -R0, c[4];\n"
"MUL result.color, fragment.color.primary, R0.x;\n"
"END\n"
;
@@ -7195,19 +7110,19 @@ static const char *painter_fragment_program_sources[num_fragment_brushes][num_fr
static int painter_variable_locations[num_fragment_brushes][num_fragment_composition_modes][num_fragment_variables] = {
{
- { -1, -1, -1, 1, -1, 6, 2, -1, 5, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, -1, -1, 3, -1, -1, 2, 0, -1, 0, -1, -1, -1, -1, -1, -1, -1, },
+ { -1, -1, -1, 2, -1, 0, 5, -1, 1, 3, 1, 0, -1, 4, -1, -1, -1, -1, -1, },
+ { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, },
+ { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, },
+ { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, },
+ { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, },
+ { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, },
+ { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, },
+ { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, },
+ { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, },
+ { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, },
+ { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, },
+ { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, },
+ { -1, -1, -1, -1, -1, 0, -1, -1, 1, 2, -1, 0, -1, -1, -1, -1, -1, -1, -1, },
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, -1, -1, -1, },
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, -1, -1, -1, },
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, -1, -1, -1, },
@@ -7219,154 +7134,154 @@ static int painter_variable_locations[num_fragment_brushes][num_fragment_composi
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, -1, -1, -1, },
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, -1, -1, -1, },
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, -1, 0, -1, -1, 0, -1, -1, -1, -1, -1, },
+ { -1, -1, -1, 0, -1, -1, 2, -1, -1, -1, 0, -1, -1, 1, -1, -1, -1, -1, -1, },
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
},
{
- { -1, -1, 4, 1, 5, 11, 2, -1, 10, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 1, -1, 2, 8, -1, -1, 7, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, 7, 2, -1, 8, -1, -1, -1, 0, -1, 1, 6, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, 5, 3, 0, -1, },
+ { -1, -1, 3, 7, 4, 5, 10, -1, 6, 8, 1, 0, 2, 9, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, -1, 4, 5, -1, -1, 6, 7, -1, 0, 1, -1, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, 5, 4, -1, 7, -1, -1, -1, 0, -1, 1, 6, -1, 1, 0, 2, -1, },
+ { -1, -1, 3, -1, 4, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, 1, 0, 2, -1, },
},
{
- { -1, -1, 4, 1, 5, 12, 2, -1, 11, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 1, -1, 2, 9, -1, -1, 8, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, 8, 2, -1, 9, -1, -1, -1, 0, -1, 1, 7, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, 0, 5, },
+ { -1, -1, 2, 6, 3, 4, 9, -1, 5, 7, 1, 0, 2, 8, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, -1, 3, 4, -1, -1, 5, 6, -1, 0, 1, -1, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, 4, 3, -1, 6, -1, -1, -1, 0, -1, 1, 5, -1, -1, -1, 1, 0, },
+ { -1, -1, 2, -1, 3, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, 1, 0, },
},
{
- { -1, 6, 4, 1, 5, 10, 2, -1, 9, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 3, 1, -1, 2, 7, -1, -1, 6, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, 5, 2, -1, 6, -1, -1, -1, 0, -1, 1, 4, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, 0, -1, },
+ { -1, 0, 2, 6, 3, 4, 9, -1, 5, 7, 1, 0, 2, 8, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, -1, 3, 4, -1, -1, 5, 6, -1, 0, 1, -1, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, 4, 3, -1, 6, -1, -1, -1, 0, -1, 1, 5, -1, -1, -1, 1, -1, },
+ { -1, 0, 2, -1, 3, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, 1, -1, },
},
{
- { 2, -1, 4, 1, 5, 10, 2, -1, 9, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 1, -1, 1, -1, 2, 7, -1, -1, 6, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, 5, 2, -1, 6, -1, -1, -1, 0, -1, -1, 4, 3, -1, -1, 0, -1, },
- { 0, -1, 1, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, -1, -1, 0, -1, },
+ { 2, -1, 2, 6, 3, 4, 9, -1, 5, 7, 1, 0, -1, 8, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, 4, -1, -1, 5, 6, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, 4, 3, -1, 6, -1, -1, -1, 0, -1, -1, 5, 0, -1, -1, 1, -1, },
+ { 0, -1, 2, -1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, 1, -1, },
},
{
- { 2, -1, 4, 1, 5, 10, 2, -1, 9, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 1, -1, 1, -1, 2, 7, -1, -1, 6, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, 5, 2, -1, 6, -1, -1, -1, 0, -1, -1, 4, 3, -1, -1, 0, -1, },
- { 0, -1, 1, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, -1, -1, 0, -1, },
+ { 2, -1, 2, 6, 3, 4, 9, -1, 5, 7, 1, 0, -1, 8, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, 4, -1, -1, 5, 6, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, },
+ { 1, -1, 2, 4, 3, -1, 6, -1, -1, -1, 0, -1, -1, 5, 0, -1, -1, 1, -1, },
+ { 0, -1, 2, -1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, 1, -1, },
},
};
static int mask_variable_locations[num_fragment_masks][num_fragment_variables] = {
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
- { -1, -1, 2, -1, 3, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, },
+ { -1, -1, 1, -1, 2, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, },
};
#endif
diff --git a/src/opengl/util/generator.cpp b/src/opengl/util/generator.cpp
index 4704d54..0202fe1 100644
--- a/src/opengl/util/generator.cpp
+++ b/src/opengl/util/generator.cpp
@@ -48,11 +48,14 @@
#include <QTextStream>
#include <QtDebug>
+#include <cstdlib>
QT_BEGIN_NAMESPACE
QT_USE_NAMESPACE
+#define TAB " "
+
typedef QPair<QString, QString> QStringPair;
QString readSourceFile(const QString &sourceFile, bool fragmentProgram = false)
@@ -116,7 +119,7 @@ QList<QStringPair> readConf(const QString &confFile)
lineStream >> enumerator;
if (lineStream.atEnd()) {
- qDebug() << "Error in file" << confFile << "(" << enumerator << ")";
+ qDebug() << "Error in file" << confFile << '(' << enumerator << ')';
exit(0);
}
@@ -242,6 +245,30 @@ QString trimmed(QString source)
return result;
}
+void writeVariablesEnum(QTextStream &out, const char *name, const QSet<QString> &s)
+{
+ out << "enum " << name << " {";
+ QSet<QString>::const_iterator it = s.begin();
+ if (it != s.end()) {
+ out << "\n" TAB "VAR_" << it->toUpper();
+ for (++it; it != s.end(); ++it)
+ out << ",\n" TAB "VAR_" << it->toUpper();
+ }
+ out << "\n};\n\n";
+}
+
+void writeTypesEnum(QTextStream &out, const char *name, const QList<QStringPair> &s)
+{
+ out << "enum " << name << " {";
+ QList<QStringPair>::const_iterator it = s.begin();
+ if (it != s.end()) {
+ out << "\n" TAB << it->first;
+ for (++it; it != s.end(); ++it)
+ out << ",\n" TAB << it->first;
+ }
+ out << "\n};\n\n";
+}
+
void writeIncludeFile(const QSet<QString> &variables,
const QList<QStringPair> &brushes,
const QList<QStringPair> &compositionModes,
@@ -256,7 +283,7 @@ void writeIncludeFile(const QSet<QString> &variables,
QTextStream out(&includeFile);
- QLatin1String tab(" ");
+ QLatin1String tab(TAB);
out << "/****************************************************************************\n"
"**\n"
@@ -264,7 +291,7 @@ void writeIncludeFile(const QSet<QString> &variables,
"** All rights reserved.\n"
"** Contact: Nokia Corporation (qt-info@nokia.com)\n"
"**\n"
- "** This file is part of the test suite of the Qt Toolkit.\n"
+ "** This file is part of the QtOpenGL module of the Qt Toolkit.\n"
"**\n"
"** $QT_BEGIN_LICENSE:LGPL$\n"
"** No Commercial Usage\n"
@@ -314,25 +341,10 @@ void writeIncludeFile(const QSet<QString> &variables,
"//\n"
"\n";
- out << "enum FragmentVariable {\n";
- foreach (QString str, variables)
- out << tab << "VAR_" << str.toUpper() << ",\n";
- out << "};\n\n";
-
- out << "enum FragmentBrushType {\n";
- foreach (QStringPair brush, brushes)
- out << tab << brush.first << ",\n";
- out << "};\n\n";
-
- out << "enum FragmentCompositionModeType {\n";
- foreach (QStringPair mode, compositionModes)
- out << tab << mode.first << ",\n";
- out << "};\n\n";
-
- out << "enum FragmentMaskType {\n";
- foreach (QStringPair mask, masks)
- out << tab << mask.first << ",\n";
- out << "};\n\n";
+ writeVariablesEnum(out, "FragmentVariable", variables);
+ writeTypesEnum(out, "FragmentBrushType", brushes);
+ writeTypesEnum(out, "FragmentCompositionModeType", compositionModes);
+ writeTypesEnum(out, "FragmentMaskType", masks);
out << "static const unsigned int num_fragment_variables = " << variables.size() << ";\n\n";
out << "static const unsigned int num_fragment_brushes = " << brushes.size() << ";\n";
diff --git a/src/opengl/util/generator.pro b/src/opengl/util/generator.pro
index 9425dbe..ac71934 100644
--- a/src/opengl/util/generator.pro
+++ b/src/opengl/util/generator.pro
@@ -9,3 +9,5 @@ INCLUDEPATH += .
# Input
SOURCES += generator.cpp
+
+CONFIG += console
diff --git a/src/opengl/util/masks.conf b/src/opengl/util/masks.conf
index 733ac81..d853d0b 100644
--- a/src/opengl/util/masks.conf
+++ b/src/opengl/util/masks.conf
@@ -1,3 +1,2 @@
FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA trap_exact_aa.glsl
FRAGMENT_PROGRAM_MASK_ELLIPSE_AA ellipse_aa.glsl
-#FRAGMENT_PROGRAM_MASK_ELLIPSE ellipse.glsl
diff --git a/src/opengl/util/pattern_brush.glsl b/src/opengl/util/pattern_brush.glsl
index e070449..31702b8 100644
--- a/src/opengl/util/pattern_brush.glsl
+++ b/src/opengl/util/pattern_brush.glsl
@@ -17,9 +17,7 @@ vec4 brush()
coords *= inv_brush_texture_size;
- coords.y = -coords.y;
-
- float alpha = texture2D(brush_texture, coords).r;
+ float alpha = 1.0 - texture2D(brush_texture, coords).r;
return gl_Color * alpha;
}
diff --git a/src/opengl/util/simple_porter_duff.glsl b/src/opengl/util/simple_porter_duff.glsl
index 83aef48..4cb0599 100644
--- a/src/opengl/util/simple_porter_duff.glsl
+++ b/src/opengl/util/simple_porter_duff.glsl
@@ -7,10 +7,10 @@ vec4 composite(vec4 src, vec4 dst)
result.xyz = porterduff_ab.x * src.xyz * dst.a
+ porterduff_ab.y * dst.xyz * src.a
- + porterduff_xyz.y * src.xyz * (1 - dst.a)
- + porterduff_xyz.z * dst.xyz * (1 - src.a);
+ + porterduff_xyz.y * src.xyz * (1.0 - dst.a)
+ + porterduff_xyz.z * dst.xyz * (1.0 - src.a);
- result.a = dot(porterduff_xyz, vec3(src.a * dst.a, src.a * (1 - dst.a), dst.a * (1 - src.a)));
+ result.a = dot(porterduff_xyz, vec3(src.a * dst.a, src.a * (1.0 - dst.a), dst.a * (1.0 - src.a)));
return result;
}
diff --git a/src/opengl/util/texture_brush.glsl b/src/opengl/util/texture_brush.glsl
index 93865b8..9498255 100644
--- a/src/opengl/util/texture_brush.glsl
+++ b/src/opengl/util/texture_brush.glsl
@@ -17,7 +17,5 @@ vec4 brush()
coords *= inv_brush_texture_size;
- coords.y = -coords.y;
-
return texture2D(brush_texture, coords);
}
diff --git a/src/opengl/util/trap_exact_aa.glsl b/src/opengl/util/trap_exact_aa.glsl
index b96f87d..1637f43 100644
--- a/src/opengl/util/trap_exact_aa.glsl
+++ b/src/opengl/util/trap_exact_aa.glsl
@@ -14,7 +14,7 @@ float quad_aa()
vec2 invA = gl_TexCoord[0].zw;
// transform right line to left to be able to use same calculations for both
- vecX.zw = 2 * gl_FragCoord.x - vecX.zw;
+ vecX.zw = 2.0 * gl_FragCoord.x - vecX.zw;
vec2 topX = vec2(vecX.x, vecX.z);
vec2 bottomX = vec2(vecX.y, vecX.w);
@@ -33,18 +33,18 @@ float quad_aa()
vec2 temp = mix(area - 0.5 * (right - bottomXTemp) * (intersectY.yw - bottom), // left < bottom < right < top
(0.5 * (topXTemp + bottomXTemp) - left) * area, // left < bottom < top < right
- step(topXTemp, right));
+ step(topXTemp, right.xx));
vec2 excluded = 0.5 * (top - intersectY.xz) * (topXTemp - left); // bottom < left < top < right
excluded = mix((top - 0.5 * (intersectY.yw + intersectY.xz)) * (right - left), // bottom < left < right < top
- excluded, step(topXTemp, right));
+ excluded, step(topXTemp, right.xx));
excluded = mix(temp, // left < bottom < right (see calculation of temp)
- excluded, step(bottomXTemp, left));
+ excluded, step(bottomXTemp, left.xx));
excluded = mix(vec2(area, area), // right < bottom < top
- excluded, step(bottomXTemp, right));
+ excluded, step(bottomXTemp, right.xx));
excluded *= step(left, topXTemp);
@@ -53,6 +53,6 @@ float quad_aa()
void main()
{
- gl_FragColor = quad_aa();
+ gl_FragColor = quad_aa().xxxx;
}