-
-
Save JulianThijssen/475914981ea35446d86d8bfda8e5f24c to your computer and use it in GitHub Desktop.
Changes made to Qt for GSoC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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