Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@JulianThijssen
Created August 23, 2016 13:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JulianThijssen/475914981ea35446d86d8bfda8e5f24c to your computer and use it in GitHub Desktop.
Save JulianThijssen/475914981ea35446d86d8bfda8e5f24c to your computer and use it in GitHub Desktop.
Changes made to Qt for GSoC
commit 690ac461b5bbe310639dd8805f2910e8345096d4
Author: Julian Thijssen <Nimthora@gmail.com>
Date: Wed Jul 27 15:45:31 2016 +0200
Converted paintengine for OpenGL3+ core profile contexts
This change allows a user to paint on a QOpenGLWidget with a QPainter,
whenever an OpenGL3+ Core Profile format is used or enforced (such as
on macOS).
- Core Profile shaders add that use modern keywords (in, out, etc.).
- Paint engine binds a single VAO and two VBOs.
- Vertex and texture data is uploaded to VBO instead
of directly to the GPU.
Change-Id: I6323a7ea2aaa9e111651ebbffd3e40259c8e7a9c
diff --git a/src/gui/opengl/qopenglengineshadermanager.cpp b/src/gui/opengl/qopenglengineshadermanager.cpp
index 4e3d14b..c633236 100644
--- a/src/gui/opengl/qopenglengineshadermanager.cpp
+++ b/src/gui/opengl/qopenglengineshadermanager.cpp
@@ -131,58 +131,116 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context)
const char** code = qShaderSnippets; // shortcut
- code[MainVertexShader] = qopenglslMainVertexShader;
- code[MainWithTexCoordsVertexShader] = qopenglslMainWithTexCoordsVertexShader;
- code[MainWithTexCoordsAndOpacityVertexShader] = qopenglslMainWithTexCoordsAndOpacityVertexShader;
-
- code[UntransformedPositionVertexShader] = qopenglslUntransformedPositionVertexShader;
- code[PositionOnlyVertexShader] = qopenglslPositionOnlyVertexShader;
- code[ComplexGeometryPositionOnlyVertexShader] = qopenglslComplexGeometryPositionOnlyVertexShader;
- code[PositionWithPatternBrushVertexShader] = qopenglslPositionWithPatternBrushVertexShader;
- code[PositionWithLinearGradientBrushVertexShader] = qopenglslPositionWithLinearGradientBrushVertexShader;
- code[PositionWithConicalGradientBrushVertexShader] = qopenglslPositionWithConicalGradientBrushVertexShader;
- code[PositionWithRadialGradientBrushVertexShader] = qopenglslPositionWithRadialGradientBrushVertexShader;
- code[PositionWithTextureBrushVertexShader] = qopenglslPositionWithTextureBrushVertexShader;
- code[AffinePositionWithPatternBrushVertexShader] = qopenglslAffinePositionWithPatternBrushVertexShader;
- code[AffinePositionWithLinearGradientBrushVertexShader] = qopenglslAffinePositionWithLinearGradientBrushVertexShader;
- code[AffinePositionWithConicalGradientBrushVertexShader] = qopenglslAffinePositionWithConicalGradientBrushVertexShader;
- code[AffinePositionWithRadialGradientBrushVertexShader] = qopenglslAffinePositionWithRadialGradientBrushVertexShader;
- code[AffinePositionWithTextureBrushVertexShader] = qopenglslAffinePositionWithTextureBrushVertexShader;
-
- code[MainFragmentShader_CMO] = qopenglslMainFragmentShader_CMO;
- code[MainFragmentShader_CM] = qopenglslMainFragmentShader_CM;
- code[MainFragmentShader_MO] = qopenglslMainFragmentShader_MO;
- code[MainFragmentShader_M] = qopenglslMainFragmentShader_M;
- code[MainFragmentShader_CO] = qopenglslMainFragmentShader_CO;
- code[MainFragmentShader_C] = qopenglslMainFragmentShader_C;
- code[MainFragmentShader_O] = qopenglslMainFragmentShader_O;
- code[MainFragmentShader] = qopenglslMainFragmentShader;
- code[MainFragmentShader_ImageArrays] = qopenglslMainFragmentShader_ImageArrays;
-
- code[ImageSrcFragmentShader] = qopenglslImageSrcFragmentShader;
- code[ImageSrcWithPatternFragmentShader] = qopenglslImageSrcWithPatternFragmentShader;
- code[NonPremultipliedImageSrcFragmentShader] = qopenglslNonPremultipliedImageSrcFragmentShader;
- code[GrayscaleImageSrcFragmentShader] = qopenglslGrayscaleImageSrcFragmentShader;
- code[AlphaImageSrcFragmentShader] = qopenglslAlphaImageSrcFragmentShader;
- code[CustomImageSrcFragmentShader] = qopenglslCustomSrcFragmentShader; // Calls "customShader", which must be appended
- code[SolidBrushSrcFragmentShader] = qopenglslSolidBrushSrcFragmentShader;
- if (context->isOpenGLES())
- code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_ES;
- else
- code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_desktop;
- code[TextureBrushSrcWithPatternFragmentShader] = qopenglslTextureBrushSrcWithPatternFragmentShader;
- code[PatternBrushSrcFragmentShader] = qopenglslPatternBrushSrcFragmentShader;
- code[LinearGradientBrushSrcFragmentShader] = qopenglslLinearGradientBrushSrcFragmentShader;
- code[RadialGradientBrushSrcFragmentShader] = qopenglslRadialGradientBrushSrcFragmentShader;
- code[ConicalGradientBrushSrcFragmentShader] = qopenglslConicalGradientBrushSrcFragmentShader;
- code[ShockingPinkSrcFragmentShader] = qopenglslShockingPinkSrcFragmentShader;
-
- code[NoMaskFragmentShader] = "";
- code[MaskFragmentShader] = qopenglslMaskFragmentShader;
- code[RgbMaskFragmentShaderPass1] = qopenglslRgbMaskFragmentShaderPass1;
- code[RgbMaskFragmentShaderPass2] = qopenglslRgbMaskFragmentShaderPass2;
- code[RgbMaskWithGammaFragmentShader] = ""; //###
+ // Check if the user has requested an OpenGL 3.2 Core Profile or higher
+ // and if so use GLSL 1.5 core shaders instead of legacy ones.
+ const QSurfaceFormat &fmt = context->format();
+ if (fmt.profile() == QSurfaceFormat::CoreProfile && fmt.version() >= qMakePair(3,2)) {
+ code[MainVertexShader] = qopenglslMainVertexShader_core;
+ code[MainWithTexCoordsVertexShader] = qopenglslMainWithTexCoordsVertexShader_core;
+ code[MainWithTexCoordsAndOpacityVertexShader] = qopenglslMainWithTexCoordsAndOpacityVertexShader_core;
+
+ code[UntransformedPositionVertexShader] = qopenglslUntransformedPositionVertexShader_core;
+ code[PositionOnlyVertexShader] = qopenglslPositionOnlyVertexShader_core;
+ code[ComplexGeometryPositionOnlyVertexShader] = qopenglslComplexGeometryPositionOnlyVertexShader_core;
+ code[PositionWithPatternBrushVertexShader] = qopenglslPositionWithPatternBrushVertexShader_core;
+ code[PositionWithLinearGradientBrushVertexShader] = qopenglslPositionWithLinearGradientBrushVertexShader_core;
+ code[PositionWithConicalGradientBrushVertexShader] = qopenglslPositionWithConicalGradientBrushVertexShader_core;
+ code[PositionWithRadialGradientBrushVertexShader] = qopenglslPositionWithRadialGradientBrushVertexShader_core;
+ code[PositionWithTextureBrushVertexShader] = qopenglslPositionWithTextureBrushVertexShader_core;
+ code[AffinePositionWithPatternBrushVertexShader] = qopenglslAffinePositionWithPatternBrushVertexShader_core;
+ code[AffinePositionWithLinearGradientBrushVertexShader] = qopenglslAffinePositionWithLinearGradientBrushVertexShader_core;
+ code[AffinePositionWithConicalGradientBrushVertexShader] = qopenglslAffinePositionWithConicalGradientBrushVertexShader_core;
+ code[AffinePositionWithRadialGradientBrushVertexShader] = qopenglslAffinePositionWithRadialGradientBrushVertexShader_core;
+ code[AffinePositionWithTextureBrushVertexShader] = qopenglslAffinePositionWithTextureBrushVertexShader_core;
+
+ code[MainFragmentShader_CMO] = qopenglslMainFragmentShader_CMO_core;
+ code[MainFragmentShader_CM] = qopenglslMainFragmentShader_CM_core;
+ code[MainFragmentShader_MO] = qopenglslMainFragmentShader_MO_core;
+ code[MainFragmentShader_M] = qopenglslMainFragmentShader_M_core;
+ code[MainFragmentShader_CO] = qopenglslMainFragmentShader_CO_core;
+ code[MainFragmentShader_C] = qopenglslMainFragmentShader_C_core;
+ code[MainFragmentShader_O] = qopenglslMainFragmentShader_O_core;
+ code[MainFragmentShader] = qopenglslMainFragmentShader_core;
+ code[MainFragmentShader_ImageArrays] = qopenglslMainFragmentShader_ImageArrays_core;
+
+ code[ImageSrcFragmentShader] = qopenglslImageSrcFragmentShader_core;
+ code[ImageSrcWithPatternFragmentShader] = qopenglslImageSrcWithPatternFragmentShader_core;
+ code[NonPremultipliedImageSrcFragmentShader] = qopenglslNonPremultipliedImageSrcFragmentShader_core;
+ code[GrayscaleImageSrcFragmentShader] = qopenglslGrayscaleImageSrcFragmentShader_core;
+ code[AlphaImageSrcFragmentShader] = qopenglslAlphaImageSrcFragmentShader_core;
+ code[CustomImageSrcFragmentShader] = qopenglslCustomSrcFragmentShader_core; // Calls "customShader", which must be appended
+ code[SolidBrushSrcFragmentShader] = qopenglslSolidBrushSrcFragmentShader_core;
+
+ code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_desktop_core;
+ code[TextureBrushSrcWithPatternFragmentShader] = qopenglslTextureBrushSrcWithPatternFragmentShader_core;
+ code[PatternBrushSrcFragmentShader] = qopenglslPatternBrushSrcFragmentShader_core;
+ code[LinearGradientBrushSrcFragmentShader] = qopenglslLinearGradientBrushSrcFragmentShader_core;
+ code[RadialGradientBrushSrcFragmentShader] = qopenglslRadialGradientBrushSrcFragmentShader_core;
+ code[ConicalGradientBrushSrcFragmentShader] = qopenglslConicalGradientBrushSrcFragmentShader_core;
+ code[ShockingPinkSrcFragmentShader] = qopenglslShockingPinkSrcFragmentShader_core;
+
+ code[NoMaskFragmentShader] = "";
+ code[MaskFragmentShader] = qopenglslMaskFragmentShader_core;
+ code[RgbMaskFragmentShaderPass1] = qopenglslRgbMaskFragmentShaderPass1_core;
+ code[RgbMaskFragmentShaderPass2] = qopenglslRgbMaskFragmentShaderPass2_core;
+ code[RgbMaskWithGammaFragmentShader] = ""; //###
+ } else {
+ code[MainVertexShader] = qopenglslMainVertexShader;
+ code[MainWithTexCoordsVertexShader] = qopenglslMainWithTexCoordsVertexShader;
+ code[MainWithTexCoordsAndOpacityVertexShader] = qopenglslMainWithTexCoordsAndOpacityVertexShader;
+
+ code[UntransformedPositionVertexShader] = qopenglslUntransformedPositionVertexShader;
+ code[PositionOnlyVertexShader] = qopenglslPositionOnlyVertexShader;
+ code[ComplexGeometryPositionOnlyVertexShader] = qopenglslComplexGeometryPositionOnlyVertexShader;
+ code[PositionWithPatternBrushVertexShader] = qopenglslPositionWithPatternBrushVertexShader;
+ code[PositionWithLinearGradientBrushVertexShader] = qopenglslPositionWithLinearGradientBrushVertexShader;
+ code[PositionWithConicalGradientBrushVertexShader] = qopenglslPositionWithConicalGradientBrushVertexShader;
+ code[PositionWithRadialGradientBrushVertexShader] = qopenglslPositionWithRadialGradientBrushVertexShader;
+ code[PositionWithTextureBrushVertexShader] = qopenglslPositionWithTextureBrushVertexShader;
+ code[AffinePositionWithPatternBrushVertexShader] = qopenglslAffinePositionWithPatternBrushVertexShader;
+ code[AffinePositionWithLinearGradientBrushVertexShader] = qopenglslAffinePositionWithLinearGradientBrushVertexShader;
+ code[AffinePositionWithConicalGradientBrushVertexShader] = qopenglslAffinePositionWithConicalGradientBrushVertexShader;
+ code[AffinePositionWithRadialGradientBrushVertexShader] = qopenglslAffinePositionWithRadialGradientBrushVertexShader;
+ code[AffinePositionWithTextureBrushVertexShader] = qopenglslAffinePositionWithTextureBrushVertexShader;
+
+ code[MainFragmentShader_CMO] = qopenglslMainFragmentShader_CMO;
+ code[MainFragmentShader_CM] = qopenglslMainFragmentShader_CM;
+ code[MainFragmentShader_MO] = qopenglslMainFragmentShader_MO;
+ code[MainFragmentShader_M] = qopenglslMainFragmentShader_M;
+ code[MainFragmentShader_CO] = qopenglslMainFragmentShader_CO;
+ code[MainFragmentShader_C] = qopenglslMainFragmentShader_C;
+ code[MainFragmentShader_O] = qopenglslMainFragmentShader_O;
+ code[MainFragmentShader] = qopenglslMainFragmentShader;
+ code[MainFragmentShader_ImageArrays] = qopenglslMainFragmentShader_ImageArrays;
+
+ code[ImageSrcFragmentShader] = qopenglslImageSrcFragmentShader;
+ code[ImageSrcWithPatternFragmentShader] = qopenglslImageSrcWithPatternFragmentShader;
+ code[NonPremultipliedImageSrcFragmentShader] = qopenglslNonPremultipliedImageSrcFragmentShader;
+ code[GrayscaleImageSrcFragmentShader] = qopenglslGrayscaleImageSrcFragmentShader;
+ code[AlphaImageSrcFragmentShader] = qopenglslAlphaImageSrcFragmentShader;
+ code[CustomImageSrcFragmentShader] = qopenglslCustomSrcFragmentShader; // Calls "customShader", which must be appended
+ code[SolidBrushSrcFragmentShader] = qopenglslSolidBrushSrcFragmentShader;
+ if (context->isOpenGLES())
+ code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_ES;
+ else
+ code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_desktop;
+ code[TextureBrushSrcWithPatternFragmentShader] = qopenglslTextureBrushSrcWithPatternFragmentShader;
+ code[PatternBrushSrcFragmentShader] = qopenglslPatternBrushSrcFragmentShader;
+ code[LinearGradientBrushSrcFragmentShader] = qopenglslLinearGradientBrushSrcFragmentShader;
+ code[RadialGradientBrushSrcFragmentShader] = qopenglslRadialGradientBrushSrcFragmentShader;
+ code[ConicalGradientBrushSrcFragmentShader] = qopenglslConicalGradientBrushSrcFragmentShader;
+ code[ShockingPinkSrcFragmentShader] = qopenglslShockingPinkSrcFragmentShader;
+
+ code[NoMaskFragmentShader] = "";
+ code[MaskFragmentShader] = qopenglslMaskFragmentShader;
+ code[RgbMaskFragmentShaderPass1] = qopenglslRgbMaskFragmentShaderPass1;
+ code[RgbMaskFragmentShaderPass2] = qopenglslRgbMaskFragmentShaderPass2;
+ code[RgbMaskWithGammaFragmentShader] = ""; //###
+ }
+ // These shaders are not implemented yet and therefore are the same
+ // for all profiles. Implementations should make a version for both
+ // profiles and put the appropriate lines in the if-statement above.
code[NoCompositionModeFragmentShader] = "";
code[MultiplyCompositionModeFragmentShader] = ""; //###
code[ScreenCompositionModeFragmentShader] = ""; //###
diff --git a/src/gui/opengl/qopenglengineshadersource_p.h b/src/gui/opengl/qopenglengineshadersource_p.h
index 876d277..819162e 100644
--- a/src/gui/opengl/qopenglengineshadersource_p.h
+++ b/src/gui/opengl/qopenglengineshadersource_p.h
@@ -56,8 +56,6 @@
QT_BEGIN_NAMESPACE
-
-
static const char* const qopenglslMainVertexShader = "\n\
void setPosition(); \n\
void main(void) \n\
@@ -531,40 +529,498 @@ static const char* const qopenglslRgbMaskFragmentShaderPass2 = "\n\
ExclusionCompositionModeFragmentShader,
*/
-// OpenGL 3.2 core profile versions of shaders that are used by QOpenGLTextureGlyphCache
+/*
+ OpenGL 3.2+ Core Profile shaders
+ The following shader snippets are copies of the snippets above
+ but use the modern GLSL 1.5 keywords. New shaders should make
+ a snippet for both profiles and add them appropriately in the
+ shader manager.
+*/
+static const char* const qopenglslMainVertexShader_core =
+ "#version 150 core\n\
+ void setPosition(); \n\
+ void main(void) \n\
+ { \n\
+ setPosition(); \n\
+ }\n";
-static const char* const qopenglslMainWithTexCoordsVertexShader_core = "#version 150 core \n\
- in vec2 textureCoordArray; \n\
- out vec2 textureCoords; \n\
- void setPosition(); \n\
- void main(void) \n\
- { \n\
- setPosition(); \n\
- textureCoords = textureCoordArray; \n\
- }\n";
+static const char* const qopenglslMainWithTexCoordsVertexShader_core =
+ "#version 150 core\n\
+ in highp vec2 textureCoordArray; \n\
+ out highp vec2 textureCoords; \n\
+ void setPosition(); \n\
+ void main(void) \n\
+ { \n\
+ setPosition(); \n\
+ textureCoords = textureCoordArray; \n\
+ }\n";
+
+static const char* const qopenglslMainWithTexCoordsAndOpacityVertexShader_core =
+ "#version 150 core\n\
+ in highp vec2 textureCoordArray; \n\
+ in lowp float opacityArray; \n\
+ out highp vec2 textureCoords; \n\
+ out lowp float opacity; \n\
+ void setPosition(); \n\
+ void main(void) \n\
+ { \n\
+ setPosition(); \n\
+ textureCoords = textureCoordArray; \n\
+ opacity = opacityArray; \n\
+ }\n";
+
+// NOTE: We let GL do the perspective correction so texture lookups in the fragment
+// shader are also perspective corrected.
+static const char* const qopenglslPositionOnlyVertexShader_core = "\n\
+ in highp vec2 vertexCoordsArray; \n\
+ in highp vec3 pmvMatrix1; \n\
+ in highp vec3 pmvMatrix2; \n\
+ in highp vec3 pmvMatrix3; \n\
+ void setPosition(void) \n\
+ { \n\
+ highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\
+ vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\
+ gl_Position = vec4(transformedPos.xy, 0.0, transformedPos.z); \n\
+ }\n";
+
+static const char* const qopenglslComplexGeometryPositionOnlyVertexShader_core = "\n\
+ in highp vec2 vertexCoordsArray; \n\
+ uniform highp mat3 matrix; \n\
+ void setPosition(void) \n\
+ { \n\
+ gl_Position = vec4(matrix * vec3(vertexCoordsArray, 1), 1);\n\
+ } \n";
static const char* const qopenglslUntransformedPositionVertexShader_core = "\n\
- in vec4 vertexCoordsArray; \n\
- void setPosition(void) \n\
- { \n\
- gl_Position = vertexCoordsArray; \n\
- }\n";
-
-static const char* const qopenglslMainFragmentShader_core = "#version 150 core \n\
- vec4 srcPixel(); \n\
- out vec4 fragColor; \n\
- void main() \n\
- { \n\
- fragColor = srcPixel(); \n\
- }\n";
+ in highp vec4 vertexCoordsArray; \n\
+ void setPosition(void) \n\
+ { \n\
+ gl_Position = vertexCoordsArray; \n\
+ }\n";
+
+// Pattern Brush - This assumes the texture size is 8x8 and thus, the inverted size is 0.125
+static const char* const qopenglslPositionWithPatternBrushVertexShader_core = "\n\
+ in highp vec2 vertexCoordsArray; \n\
+ in highp vec3 pmvMatrix1; \n\
+ in highp vec3 pmvMatrix2; \n\
+ in highp vec3 pmvMatrix3; \n\
+ out highp vec2 patternTexCoords; \n\
+ uniform mediump vec2 halfViewportSize; \n\
+ uniform highp vec2 invertedTextureSize; \n\
+ uniform highp mat3 brushTransform; \n\
+ void setPosition(void) \n\
+ { \n\
+ highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\
+ vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\
+ gl_Position.xy = transformedPos.xy / transformedPos.z; \n\
+ mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\
+ mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1.0); \n\
+ mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\
+ gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\
+ patternTexCoords.xy = (hTexCoords.xy * 0.125) * invertedHTexCoordsZ; \n\
+ }\n";
+
+static const char* const qopenglslAffinePositionWithPatternBrushVertexShader_core
+ = qopenglslPositionWithPatternBrushVertexShader_core;
+
+static const char* const qopenglslPatternBrushSrcFragmentShader_core = "\n\
+ in highp vec2 patternTexCoords;\n\
+ uniform sampler2D brushTexture; \n\
+ uniform lowp vec4 patternColor; \n\
+ lowp vec4 srcPixel() \n\
+ { \n\
+ return patternColor * (1.0 - texture(brushTexture, patternTexCoords).r); \n\
+ }\n";
+
+
+// Linear Gradient Brush
+static const char* const qopenglslPositionWithLinearGradientBrushVertexShader_core = "\n\
+ in highp vec2 vertexCoordsArray; \n\
+ in highp vec3 pmvMatrix1; \n\
+ in highp vec3 pmvMatrix2; \n\
+ in highp vec3 pmvMatrix3; \n\
+ out mediump float index; \n\
+ uniform mediump vec2 halfViewportSize; \n\
+ uniform highp vec3 linearData; \n\
+ uniform highp mat3 brushTransform; \n\
+ void setPosition() \n\
+ { \n\
+ highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\
+ vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\
+ gl_Position.xy = transformedPos.xy / transformedPos.z; \n\
+ mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\
+ mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\
+ mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\
+ gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\
+ index = (dot(linearData.xy, hTexCoords.xy) * linearData.z) * invertedHTexCoordsZ; \n\
+ }\n";
+
+static const char* const qopenglslAffinePositionWithLinearGradientBrushVertexShader_core
+ = qopenglslPositionWithLinearGradientBrushVertexShader_core;
+
+static const char* const qopenglslLinearGradientBrushSrcFragmentShader_core = "\n\
+ uniform sampler2D brushTexture; \n\
+ in mediump float index; \n\
+ lowp vec4 srcPixel() \n\
+ { \n\
+ mediump vec2 val = vec2(index, 0.5); \n\
+ return texture(brushTexture, val); \n\
+ }\n";
+
+
+// Conical Gradient Brush
+static const char* const qopenglslPositionWithConicalGradientBrushVertexShader_core = "\n\
+ in highp vec2 vertexCoordsArray; \n\
+ in highp vec3 pmvMatrix1; \n\
+ in highp vec3 pmvMatrix2; \n\
+ in highp vec3 pmvMatrix3; \n\
+ out highp vec2 A; \n\
+ uniform mediump vec2 halfViewportSize; \n\
+ uniform highp mat3 brushTransform; \n\
+ void setPosition(void) \n\
+ { \n\
+ highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\
+ vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\
+ gl_Position.xy = transformedPos.xy / transformedPos.z; \n\
+ mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\
+ mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\
+ mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\
+ gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\
+ A = hTexCoords.xy * invertedHTexCoordsZ; \n\
+ }\n";
+
+static const char* const qopenglslAffinePositionWithConicalGradientBrushVertexShader_core
+ = qopenglslPositionWithConicalGradientBrushVertexShader_core;
+
+static const char* const qopenglslConicalGradientBrushSrcFragmentShader_core = "\n\
+ #define INVERSE_2PI 0.1591549430918953358 \n\
+ in highp vec2 A; \n\
+ uniform sampler2D brushTexture; \n\
+ uniform mediump float angle; \n\
+ lowp vec4 srcPixel() \n\
+ { \n\
+ highp float t; \n\
+ if (abs(A.y) == abs(A.x)) \n\
+ t = (atan(-A.y + 0.002, A.x) + angle) * INVERSE_2PI; \n\
+ else \n\
+ t = (atan(-A.y, A.x) + angle) * INVERSE_2PI; \n\
+ return texture(brushTexture, vec2(t - floor(t), 0.5)); \n\
+ }\n";
+
+
+// Radial Gradient Brush
+static const char* const qopenglslPositionWithRadialGradientBrushVertexShader_core = "\n\
+ in highp vec2 vertexCoordsArray;\n\
+ in highp vec3 pmvMatrix1; \n\
+ in highp vec3 pmvMatrix2; \n\
+ in highp vec3 pmvMatrix3; \n\
+ out highp float b; \n\
+ out highp vec2 A; \n\
+ uniform mediump vec2 halfViewportSize; \n\
+ uniform highp mat3 brushTransform; \n\
+ uniform highp vec2 fmp; \n\
+ uniform mediump vec3 bradius; \n\
+ void setPosition(void) \n\
+ {\n\
+ highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\
+ vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\
+ gl_Position.xy = transformedPos.xy / transformedPos.z; \n\
+ mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\
+ mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\
+ mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\
+ gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\
+ A = hTexCoords.xy * invertedHTexCoordsZ; \n\
+ b = bradius.x + 2.0 * dot(A, fmp); \n\
+ }\n";
+
+static const char* const qopenglslAffinePositionWithRadialGradientBrushVertexShader_core
+ = qopenglslPositionWithRadialGradientBrushVertexShader_core;
+
+static const char* const qopenglslRadialGradientBrushSrcFragmentShader_core = "\n\
+ in highp float b; \n\
+ in highp vec2 A; \n\
+ uniform sampler2D brushTexture; \n\
+ uniform highp float fmp2_m_radius2; \n\
+ uniform highp float inverse_2_fmp2_m_radius2; \n\
+ uniform highp float sqrfr; \n\
+ uniform mediump vec3 bradius; \n\
+ \n\
+ lowp vec4 srcPixel() \n\
+ { \n\
+ highp float c = sqrfr-dot(A, A); \n\
+ highp float det = b*b - 4.0*fmp2_m_radius2*c; \n\
+ lowp vec4 result = vec4(0.0); \n\
+ if (det >= 0.0) { \n\
+ highp float detSqrt = sqrt(det); \n\
+ highp float w = max((-b - detSqrt) * inverse_2_fmp2_m_radius2, (-b + detSqrt) * inverse_2_fmp2_m_radius2); \n\
+ if (bradius.y + w * bradius.z >= 0.0) \n\
+ result = texture(brushTexture, vec2(w, 0.5)); \n\
+ } \n\
+ return result; \n\
+ }\n";
+
+
+// Texture Brush
+static const char* const qopenglslPositionWithTextureBrushVertexShader_core = "\n\
+ in highp vec2 vertexCoordsArray; \n\
+ in highp vec3 pmvMatrix1; \n\
+ in highp vec3 pmvMatrix2; \n\
+ in highp vec3 pmvMatrix3; \n\
+ out highp vec2 brushTextureCoords; \n\
+ uniform mediump vec2 halfViewportSize; \n\
+ uniform highp vec2 invertedTextureSize; \n\
+ uniform highp mat3 brushTransform; \n\
+ \n\
+ void setPosition(void) \n\
+ { \n\
+ highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\
+ vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\
+ gl_Position.xy = transformedPos.xy / transformedPos.z; \n\
+ mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\
+ mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\
+ mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\
+ gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\
+ brushTextureCoords.xy = (hTexCoords.xy * invertedTextureSize) * gl_Position.w; \n\
+ }\n";
+
+static const char* const qopenglslAffinePositionWithTextureBrushVertexShader_core
+ = qopenglslPositionWithTextureBrushVertexShader_core;
+
+static const char* const qopenglslTextureBrushSrcFragmentShader_desktop_core = "\n\
+ in highp vec2 brushTextureCoords; \n\
+ uniform sampler2D brushTexture; \n\
+ lowp vec4 srcPixel() \n\
+ { \n\
+ return texture(brushTexture, brushTextureCoords); \n\
+ }\n";
+
+static const char* const qopenglslTextureBrushSrcWithPatternFragmentShader_core = "\n\
+ in highp vec2 brushTextureCoords; \n\
+ uniform lowp vec4 patternColor; \n\
+ uniform sampler2D brushTexture; \n\
+ lowp vec4 srcPixel() \n\
+ { \n\
+ return patternColor * (1.0 - texture(brushTexture, brushTextureCoords).r); \n\
+ }\n";
+
+// Solid Fill Brush
+static const char* const qopenglslSolidBrushSrcFragmentShader_core = "\n\
+ uniform lowp vec4 fragmentColor; \n\
+ lowp vec4 srcPixel() \n\
+ { \n\
+ return fragmentColor; \n\
+ }\n";
static const char* const qopenglslImageSrcFragmentShader_core = "\n\
- in vec2 textureCoords; \n\
- uniform sampler2D imageTexture; \n\
- vec4 srcPixel() \n\
- { \n"
- "return texture(imageTexture, textureCoords); \n"
- "}\n";
+ in highp vec2 textureCoords; \n\
+ uniform sampler2D imageTexture; \n\
+ lowp vec4 srcPixel() \n\
+ { \n\
+ return texture(imageTexture, textureCoords); \n\
+ }\n";
+
+static const char* const qopenglslCustomSrcFragmentShader_core = "\n\
+ in highp vec2 textureCoords; \n\
+ uniform sampler2D imageTexture; \n\
+ lowp vec4 srcPixel() \n\
+ { \n\
+ return customShader(imageTexture, textureCoords); \n\
+ }\n";
+
+static const char* const qopenglslImageSrcWithPatternFragmentShader_core = "\n\
+ in highp vec2 textureCoords; \n\
+ uniform lowp vec4 patternColor; \n\
+ uniform sampler2D imageTexture; \n\
+ lowp vec4 srcPixel() \n\
+ { \n\
+ return patternColor * (1.0 - texture(imageTexture, textureCoords).r); \n\
+ }\n";
+
+static const char* const qopenglslNonPremultipliedImageSrcFragmentShader_core = "\n\
+ in highp vec2 textureCoords; \n\
+ uniform sampler2D imageTexture; \n\
+ lowp vec4 srcPixel() \n\
+ { \n\
+ lowp vec4 sample = texture(imageTexture, textureCoords); \n\
+ sample.rgb = sample.rgb * sample.a; \n\
+ return sample; \n\
+ }\n";
+
+static const char* const qopenglslGrayscaleImageSrcFragmentShader_core = "\n\
+ in highp vec2 textureCoords; \n\
+ uniform sampler2D imageTexture; \n\
+ lowp vec4 srcPixel() \n\
+ { \n\
+ return texture(imageTexture, textureCoords).rrra; \n\
+ }\n";
+
+static const char* const qopenglslAlphaImageSrcFragmentShader_core = "\n\
+ in highp vec2 textureCoords; \n\
+ uniform sampler2D imageTexture; \n\
+ lowp vec4 srcPixel() \n\
+ { \n\
+ return vec4(0, 0, 0, texture(imageTexture, textureCoords).r); \n\
+ }\n";
+
+static const char* const qopenglslShockingPinkSrcFragmentShader_core = "\n\
+ lowp vec4 srcPixel() \n\
+ { \n\
+ return vec4(0.98, 0.06, 0.75, 1.0); \n\
+ }\n";
+
+static const char* const qopenglslMainFragmentShader_ImageArrays_core =
+ "#version 150 core\n\
+ in lowp float opacity; \n\
+ out vec4 fragColor; \n\
+ lowp vec4 srcPixel(); \n\
+ void main() \n\
+ { \n\
+ fragColor = srcPixel() * opacity; \n\
+ }\n";
+
+static const char* const qopenglslMainFragmentShader_CMO_core =
+ "#version 150 core\n\
+ out vec4 fragColor; \n\
+ uniform lowp float globalOpacity; \n\
+ lowp vec4 srcPixel(); \n\
+ lowp vec4 applyMask(lowp vec4); \n\
+ lowp vec4 compose(lowp vec4); \n\
+ void main() \n\
+ { \n\
+ fragColor = applyMask(compose(srcPixel()*globalOpacity))); \n\
+ }\n";
+
+static const char* const qopenglslMainFragmentShader_CM_core =
+ "#version 150 core\n\
+ out vec4 fragColor; \n\
+ lowp vec4 srcPixel(); \n\
+ lowp vec4 applyMask(lowp vec4); \n\
+ lowp vec4 compose(lowp vec4); \n\
+ void main() \n\
+ { \n\
+ fragColor = applyMask(compose(srcPixel())); \n\
+ }\n";
+
+static const char* const qopenglslMainFragmentShader_MO_core =
+ "#version 150 core\n\
+ out vec4 fragColor; \n\
+ uniform lowp float globalOpacity; \n\
+ lowp vec4 srcPixel(); \n\
+ lowp vec4 applyMask(lowp vec4); \n\
+ void main() \n\
+ { \n\
+ fragColor = applyMask(srcPixel()*globalOpacity); \n\
+ }\n";
+
+static const char* const qopenglslMainFragmentShader_M_core =
+ "#version 150 core\n\
+ out vec4 fragColor; \n\
+ lowp vec4 srcPixel(); \n\
+ lowp vec4 applyMask(lowp vec4); \n\
+ void main() \n\
+ { \n\
+ fragColor = applyMask(srcPixel()); \n\
+ }\n";
+
+static const char* const qopenglslMainFragmentShader_CO_core =
+ "#version 150 core\n\
+ out vec4 fragColor; \n\
+ uniform lowp float globalOpacity; \n\
+ lowp vec4 srcPixel(); \n\
+ lowp vec4 compose(lowp vec4); \n\
+ void main() \n\
+ { \n\
+ fragColor = compose(srcPixel()*globalOpacity); \n\
+ }\n";
+
+static const char* const qopenglslMainFragmentShader_C_core =
+ "#version 150 core\n\
+ out vec4 fragColor; \n\
+ lowp vec4 srcPixel(); \n\
+ lowp vec4 compose(lowp vec4); \n\
+ void main() \n\
+ { \n\
+ fragColor = compose(srcPixel()); \n\
+ }\n";
+
+static const char* const qopenglslMainFragmentShader_O_core =
+ "#version 150 core\n\
+ out vec4 fragColor; \n\
+ uniform lowp float globalOpacity; \n\
+ lowp vec4 srcPixel(); \n\
+ void main() \n\
+ { \n\
+ fragColor = srcPixel()*globalOpacity; \n\
+ }\n";
+
+static const char* const qopenglslMainFragmentShader_core =
+ "#version 150 core\n\
+ out vec4 fragColor; \n\
+ lowp vec4 srcPixel(); \n\
+ void main() \n\
+ { \n\
+ fragColor = srcPixel(); \n\
+ }\n";
+
+static const char* const qopenglslMaskFragmentShader_core = "\n\
+ in highp vec2 textureCoords;\n\
+ uniform sampler2D maskTexture;\n\
+ lowp vec4 applyMask(lowp vec4 src) \n\
+ {\n\
+ lowp vec4 mask = texture(maskTexture, textureCoords); \n\
+ return src * mask.a; \n\
+ }\n";
+
+// 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 qopenglslRgbMaskFragmentShaderPass1_core = "\n\
+ in highp vec2 textureCoords;\n\
+ uniform sampler2D maskTexture;\n\
+ lowp vec4 applyMask(lowp vec4 src) \n\
+ { \n\
+ lowp vec4 mask = texture(maskTexture, textureCoords); \n\
+ return src.a * mask; \n\
+ }\n";
+
+static const char* const qopenglslRgbMaskFragmentShaderPass2_core = "\n\
+ in highp vec2 textureCoords;\n\
+ uniform sampler2D maskTexture;\n\
+ lowp vec4 applyMask(lowp vec4 src) \n\
+ { \n\
+ lowp vec4 mask = texture(maskTexture, textureCoords); \n\
+ return src * mask; \n\
+ }\n";
+
+/*
+ Left to implement:
+ RgbMaskFragmentShader_core,
+ RgbMaskWithGammaFragmentShader_core,
+
+ MultiplyCompositionModeFragmentShader_core,
+ ScreenCompositionModeFragmentShader_core,
+ OverlayCompositionModeFragmentShader_core,
+ DarkenCompositionModeFragmentShader_core,
+ LightenCompositionModeFragmentShader_core,
+ ColorDodgeCompositionModeFragmentShader_core,
+ ColorBurnCompositionModeFragmentShader_core,
+ HardLightCompositionModeFragmentShader_core,
+ SoftLightCompositionModeFragmentShader_core,
+ DifferenceCompositionModeFragmentShader_core,
+ ExclusionCompositionModeFragmentShader_core,
+*/
QT_END_NAMESPACE
diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp
index d93871c..e174c68 100644
--- a/src/gui/opengl/qopenglpaintengine.cpp
+++ b/src/gui/opengl/qopenglpaintengine.cpp
@@ -99,6 +99,10 @@ QOpenGL2PaintEngineExPrivate::~QOpenGL2PaintEngineExPrivate()
{
delete shaderManager;
+ vertexBuffer.destroy();
+ texCoordBuffer.destroy();
+ vao.destroy();
+
if (elementIndicesVBOId != 0) {
funcs.glDeleteBuffers(1, &elementIndicesVBOId);
elementIndicesVBOId = 0;
@@ -578,6 +582,12 @@ void QOpenGL2PaintEngineExPrivate::drawTexture(const QOpenGLRect& dest, const QO
setCoords(staticVertexCoordinateArray, dest);
setCoords(staticTextureCoordinateArray, srcTextureRect);
+ setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true);
+ setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, true);
+
+ uploadData(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray, 8);
+ uploadData(QT_TEXTURE_COORDS_ATTR, staticTextureCoordinateArray, 8);
+
funcs.glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
@@ -664,6 +674,9 @@ void QOpenGL2PaintEngineExPrivate::resetGLState()
float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
funcs.glVertexAttrib4fv(3, color);
}
+ if (vao.isCreated()) {
+ vao.release();
+ }
}
void QOpenGL2PaintEngineEx::endNativePainting()
@@ -696,16 +709,16 @@ void QOpenGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
}
if (newMode == ImageDrawingMode) {
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray);
- setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, staticTextureCoordinateArray);
+ uploadData(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray, 8);
+ uploadData(QT_TEXTURE_COORDS_ATTR, staticTextureCoordinateArray, 8);
}
if (newMode == ImageArrayDrawingMode || newMode == ImageOpacityArrayDrawingMode) {
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data());
- setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data());
+ uploadData(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data(), vertexCoordinateArray.vertexCount() * 2);
+ uploadData(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data(), textureCoordinateArray.vertexCount() * 2);
if (newMode == ImageOpacityArrayDrawingMode)
- setVertexAttributePointer(QT_OPACITY_ATTR, (GLfloat*)opacityArray.data());
+ uploadData(QT_OPACITY_ATTR, (GLfloat*)opacityArray.data(), opacityArray.size());
}
// This needs to change when we implement high-quality anti-aliasing...
@@ -824,9 +837,9 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
prepareForDraw(currentBrush.isOpaque());
#ifdef QT_OPENGL_CACHE_AS_VBOS
funcs.glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0);
+ //setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0); Commented out because deprecated function
#else
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, cache->vertices);
+ uploadData(QT_VERTEX_COORDS_ATTR, cache->vertices, cache->vertexCount * 2);
#endif
funcs.glDrawArrays(cache->primitiveType, 0, cache->vertexCount);
@@ -920,7 +933,7 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
#ifdef QT_OPENGL_CACHE_AS_VBOS
funcs.glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache->ibo);
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0);
+ //setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0); Commented out because deprecated function
if (cache->indexType == QVertexIndexVector::UnsignedInt)
funcs.glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, 0);
else
@@ -928,7 +941,7 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
funcs.glBindBuffer(GL_ARRAY_BUFFER, 0);
#else
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, cache->vertices);
+ uploadData(QT_VERTEX_COORDS_ATTR, cache->vertices, cache->vertexCount * 2);
if (cache->indexType == QVertexIndexVector::UnsignedInt)
funcs.glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, (qint32 *)cache->indices);
else
@@ -957,7 +970,7 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
vertices[i] = float(inverseScale * polys.vertices.at(i));
prepareForDraw(currentBrush.isOpaque());
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, vertices.constData());
+ uploadData(QT_VERTEX_COORDS_ATTR, vertices.constData(), vertices.size());
if (funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint))
funcs.glDrawElements(GL_TRIANGLES, polys.indices.size(), GL_UNSIGNED_INT, polys.indices.data());
else
@@ -1072,10 +1085,9 @@ void QOpenGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data,
funcs.glStencilMask(GL_STENCIL_HIGH_BIT);
#if 0
funcs.glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data);
+ setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data); // Commented out because deprecated function
funcs.glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
#else
-
funcs.glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
if (q->state()->clipTestEnabled) {
funcs.glStencilFunc(GL_LEQUAL, q->state()->currentClip | GL_STENCIL_HIGH_BIT,
@@ -1083,7 +1095,8 @@ void QOpenGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data,
} else {
funcs.glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff);
}
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data);
+
+ uploadData(QT_VERTEX_COORDS_ATTR, data, count * 2);
funcs.glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
#endif
}
@@ -1213,7 +1226,8 @@ bool QOpenGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
void QOpenGL2PaintEngineExPrivate::composite(const QOpenGLRect& boundingRect)
{
setCoords(staticVertexCoordinateArray, boundingRect);
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray);
+
+ uploadData(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray, 8);
funcs.glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
@@ -1222,16 +1236,12 @@ void QOpenGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stop
GLenum primitive)
{
// Now setup the pointer to the vertex array:
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data);
+ uploadData(QT_VERTEX_COORDS_ATTR, data, stops[stopCount-1] * 2);
int previousStop = 0;
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)
- qDebug(" %02d: [%.2f, %.2f]", i, vertexArray.data()[i].x, vertexArray.data()[i].y);
-*/
+
funcs.glDrawArrays(primitive, previousStop, stop - previousStop);
previousStop = stop;
}
@@ -1242,6 +1252,7 @@ void QOpenGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stop
QOpenGL2PaintEngineEx::QOpenGL2PaintEngineEx()
: QPaintEngineEx(*(new QOpenGL2PaintEngineExPrivate(this)))
{
+
}
QOpenGL2PaintEngineEx::~QOpenGL2PaintEngineEx()
@@ -1276,7 +1287,6 @@ void QOpenGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
QPaintEngineEx::stroke(path, pen);
return;
}
-
ensureActive();
d->setBrush(penBrush);
d->stroke(path, pen);
@@ -1320,17 +1330,12 @@ void QOpenGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &p
if (!stroker.vertexCount())
return;
-
+ funcs.glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
if (opaque) {
prepareForDraw(opaque);
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, stroker.vertices());
- funcs.glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2);
-
-// QBrush b(Qt::green);
-// d->setBrush(&b);
-// d->prepareForDraw(true);
-// glDrawArrays(GL_LINE_STRIP, 0, d->stroker.vertexCount() / 2);
+ uploadData(QT_VERTEX_COORDS_ATTR, stroker.vertices(), stroker.vertexCount());
+ funcs.glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2);
} else {
qreal width = qpen_widthf(pen) / 2;
if (width == 0)
@@ -1839,8 +1844,8 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly
}
if (glyphFormat != QFontEngine::Format_ARGB || recreateVertexArrays) {
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data());
- setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data());
+ uploadData(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data(), vertexCoordinates->vertexCount() * 2);
+ uploadData(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data(), textureCoordinates->vertexCount() * 2);
}
if (!snapToPixelGrid) {
@@ -2081,6 +2086,29 @@ bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev)
d->funcs.initializeOpenGLFunctions();
+ // Generate a new Vertex Array Object if we don't have one already
+ if (!d->vao.isCreated()) {
+ bool created = d->vao.create();
+
+ // If we managed to create it then we have a profile that supports VAOs
+ if (created) {
+ d->vao.bind();
+
+ // Generate a new Vertex Buffer Object if we don't have one already
+ if (!d->vertexBuffer.isCreated()) {
+ d->vertexBuffer.create();
+ // Set its usage to StreamDraw, we will use this buffer only a few times before refilling it
+ d->vertexBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw);
+ }
+ // Generate a new Texture Buffer Object if we don't have one already
+ if (!d->texCoordBuffer.isCreated()) {
+ d->texCoordBuffer.create();
+ // Set its usage to StreamDraw, we will use this buffer only a few times before refilling it
+ d->texCoordBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw);
+ }
+ }
+ }
+
for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i)
d->vertexAttributeArraysEnabledState[i] = false;
@@ -2162,6 +2190,10 @@ void QOpenGL2PaintEngineEx::ensureActive()
Q_D(QOpenGL2PaintEngineEx);
QOpenGLContext *ctx = d->ctx;
+ if (d->vao.isCreated()) {
+ d->vao.bind();
+ }
+
if (isActive() && ctx->d_func()->active_engine != this) {
ctx->d_func()->active_engine = this;
d->needsSync = true;
diff --git a/src/gui/opengl/qopenglpaintengine_p.h b/src/gui/opengl/qopenglpaintengine_p.h
index c9f3282..dc9e431 100644
--- a/src/gui/opengl/qopenglpaintengine_p.h
+++ b/src/gui/opengl/qopenglpaintengine_p.h
@@ -64,6 +64,9 @@
#include <private/qopenglextensions_p.h>
+#include <QOpenGLVertexArrayObject>
+#include <QOpenGLBuffer>
+
enum EngineMode {
ImageDrawingMode,
TextDrawingMode,
@@ -192,7 +195,9 @@ public:
snapToPixelGrid(false),
nativePaintingActive(false),
inverseScale(1),
- lastTextureUnitUsed(QT_UNKNOWN_TEXTURE_UNIT)
+ lastTextureUnitUsed(QT_UNKNOWN_TEXTURE_UNIT),
+ vertexBuffer(QOpenGLBuffer::VertexBuffer),
+ texCoordBuffer(QOpenGLBuffer::VertexBuffer)
{ }
~QOpenGL2PaintEngineExPrivate();
@@ -221,7 +226,7 @@ public:
void drawCachedGlyphs(QFontEngine::GlyphFormat glyphFormat, QStaticTextItem *staticTextItem);
// Calls glVertexAttributePointer if the pointer has changed
- inline void setVertexAttributePointer(unsigned int arrayIndex, const GLfloat *pointer);
+ inline void uploadData(unsigned int arrayIndex, const GLfloat *data, const GLuint size);
// draws whatever is in the vertex array:
void drawVertexArrays(const float *data, int *stops, int stopCount, GLenum primitive);
@@ -312,6 +317,10 @@ public:
GLenum lastTextureUnitUsed;
GLuint lastTextureUsed;
+ QOpenGLVertexArrayObject vao;
+ QOpenGLBuffer vertexBuffer;
+ QOpenGLBuffer texCoordBuffer;
+
bool needsSync;
bool multisamplingAlwaysEnabled;
@@ -325,17 +334,38 @@ public:
};
-void QOpenGL2PaintEngineExPrivate::setVertexAttributePointer(unsigned int arrayIndex, const GLfloat *pointer)
+void QOpenGL2PaintEngineExPrivate::uploadData(unsigned int arrayIndex, const GLfloat *data, const GLuint size)
{
Q_ASSERT(arrayIndex < 3);
- if (pointer == vertexAttribPointers[arrayIndex])
- return;
-
- vertexAttribPointers[arrayIndex] = pointer;
- if (arrayIndex == QT_OPACITY_ATTR)
- funcs.glVertexAttribPointer(arrayIndex, 1, GL_FLOAT, GL_FALSE, 0, pointer);
- else
- funcs.glVertexAttribPointer(arrayIndex, 2, GL_FLOAT, GL_FALSE, 0, pointer);
+
+ // If a vertex array object is created we have a profile that supports them
+ // and we will upload the data via a QOpenGLBuffer. Otherwise we will use
+ // the legacy way of uploading the data via glVertexAttribPointer.
+ if (vao.isCreated()) {
+ if (arrayIndex == QT_VERTEX_COORDS_ATTR) {
+ vertexBuffer.bind();
+ vertexBuffer.allocate(data, size * sizeof(float));
+ }
+ if (arrayIndex == QT_TEXTURE_COORDS_ATTR) {
+ texCoordBuffer.bind();
+ texCoordBuffer.allocate(data, size * sizeof(float));
+ }
+ if (arrayIndex == QT_OPACITY_ATTR)
+ funcs.glVertexAttribPointer(arrayIndex, 1, GL_FLOAT, GL_FALSE, 0, 0);
+ else
+ funcs.glVertexAttribPointer(arrayIndex, 2, GL_FLOAT, GL_FALSE, 0, 0);
+ } else {
+ // If we already uploaded the data we don't have to do it again
+ if (data == vertexAttribPointers[arrayIndex])
+ return;
+
+ // Store the data in cache and upload it to the graphics card.
+ vertexAttribPointers[arrayIndex] = data;
+ if (arrayIndex == QT_OPACITY_ATTR)
+ funcs.glVertexAttribPointer(arrayIndex, 1, GL_FLOAT, GL_FALSE, 0, data);
+ else
+ funcs.glVertexAttribPointer(arrayIndex, 2, GL_FLOAT, GL_FALSE, 0, data);
+ }
}
QT_END_NAMESPACE
diff --git a/src/gui/opengl/qopengltextureglyphcache.cpp b/src/gui/opengl/qopengltextureglyphcache.cpp
index 9a7b1eb..3a03989 100644
--- a/src/gui/opengl/qopengltextureglyphcache.cpp
+++ b/src/gui/opengl/qopengltextureglyphcache.cpp
@@ -380,8 +380,8 @@ void QOpenGLTextureGlyphCache::resizeTextureData(int width, int height)
blitProgram = m_blitProgram;
} else {
- pex->setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, m_vertexCoordinateArray);
- pex->setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, m_textureCoordinateArray);
+ pex->uploadData(QT_VERTEX_COORDS_ATTR, m_vertexCoordinateArray, 8);
+ pex->uploadData(QT_TEXTURE_COORDS_ATTR, m_textureCoordinateArray, 8);
pex->shaderManager->useBlitProgram();
blitProgram = pex->shaderManager->blitProgram();
diff --git a/src/gui/opengl/qtriangulatingstroker.cpp b/src/gui/opengl/qtriangulatingstroker.cpp
index d9a3231..a7ce6c8 100644
--- a/src/gui/opengl/qtriangulatingstroker.cpp
+++ b/src/gui/opengl/qtriangulatingstroker.cpp
@@ -261,7 +261,7 @@ void QTriangulatingStroker::moveTo(const qreal *pts)
normalVector(m_cx, m_cy, x2, y2, &m_nvx, &m_nvy);
- // To acheive jumps we insert zero-area tringles. This is done by
+ // To achieve jumps we insert zero-area triangles. 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();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment