diff options
Diffstat (limited to 'src/gui/opengl')
20 files changed, 1805 insertions, 904 deletions
diff --git a/src/gui/opengl/opengl.pri b/src/gui/opengl/opengl.pri index 1a1022b3a7..4c778b184e 100644 --- a/src/gui/opengl/opengl.pri +++ b/src/gui/opengl/opengl.pri @@ -33,7 +33,8 @@ qtConfig(opengl) { opengl/qopengltexture_p.h \ opengl/qopengltexturehelper_p.h \ opengl/qopenglpixeltransferoptions.h \ - opengl/qopenglextrafunctions.h + opengl/qopenglextrafunctions.h \ + opengl/qopenglprogrambinarycache_p.h SOURCES += opengl/qopengl.cpp \ opengl/qopenglfunctions.cpp \ @@ -55,7 +56,8 @@ qtConfig(opengl) { opengl/qopengltextureblitter.cpp \ opengl/qopengltexture.cpp \ opengl/qopengltexturehelper.cpp \ - opengl/qopenglpixeltransferoptions.cpp + opengl/qopenglpixeltransferoptions.cpp \ + opengl/qopenglprogrambinarycache.cpp !qtConfig(opengles2) { HEADERS += opengl/qopenglfunctions_1_0.h \ diff --git a/src/gui/opengl/qopengl.cpp b/src/gui/opengl/qopengl.cpp index 384cd0bd13..7e663d48bb 100644 --- a/src/gui/opengl/qopengl.cpp +++ b/src/gui/opengl/qopengl.cpp @@ -42,6 +42,7 @@ #include "qopenglcontext.h" #include "qopenglfunctions.h" +#include "qoperatingsystemversion.h" #include "qoffscreensurface.h" #include <QtCore/QDebug> @@ -223,29 +224,25 @@ struct OsTypeTerm static QString hostOsRelease() { QString ver; #ifdef Q_OS_WIN - switch (QSysInfo::windowsVersion()) { - case QSysInfo::WV_XP: - case QSysInfo::WV_2003: - ver = QStringLiteral("xp"); - break; - case QSysInfo::WV_VISTA: - ver = QStringLiteral("vista"); - break; - case QSysInfo::WV_WINDOWS7: + const auto osver = QOperatingSystemVersion::current(); +#define Q_WINVER(major, minor) (major << 8 | minor) + switch (Q_WINVER(osver.majorVersion(), osver.minorVersion())) { + case Q_WINVER(6, 1): ver = QStringLiteral("7"); break; - case QSysInfo::WV_WINDOWS8: + case Q_WINVER(6, 2): ver = QStringLiteral("8"); break; - case QSysInfo::WV_WINDOWS8_1: + case Q_WINVER(6, 3): ver = QStringLiteral("8.1"); break; - case QSysInfo::WV_WINDOWS10: + case Q_WINVER(10, 0): ver = QStringLiteral("10"); break; default: break; } +#undef Q_WINVER #endif return ver; } diff --git a/src/gui/opengl/qopengldebug.h b/src/gui/opengl/qopengldebug.h index 74b2731f7e..6b10c36291 100644 --- a/src/gui/opengl/qopengldebug.h +++ b/src/gui/opengl/qopengldebug.h @@ -52,6 +52,11 @@ #include <QtCore/qdebug.h> #include <QtGui/qopenglcontext.h> +#if defined(Q_CLANG_QDOC) +#undef GLuint +typedef unsigned int GLuint; +#endif + QT_BEGIN_NAMESPACE class QOpenGLDebugLogger; diff --git a/src/gui/opengl/qopenglengineshadermanager.cpp b/src/gui/opengl/qopenglengineshadermanager.cpp index 1d3e47f93b..dd9e8e9d1e 100644 --- a/src/gui/opengl/qopenglengineshadermanager.cpp +++ b/src/gui/opengl/qopenglengineshadermanager.cpp @@ -126,11 +126,65 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context) around without having to change the order of the glsl strings. It is hoped this will make future hard-to-find runtime bugs more obvious and generally give more solid code. */ - static bool snippetsPopulated = false; - if (!snippetsPopulated) { - const char** code = qShaderSnippets; // shortcut + // Check if the user has requested an OpenGL 3.2 Core Profile or higher + // and if so use GLSL 1.50 core shaders instead of legacy ones. + const QSurfaceFormat &fmt = context->format(); + const bool isCoreProfile = fmt.profile() == QSurfaceFormat::CoreProfile && fmt.version() >= qMakePair(3,2); + + const char** code = qShaderSnippets; // shortcut + + if (isCoreProfile) { + 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; @@ -182,34 +236,34 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context) code[RgbMaskFragmentShaderPass1] = qopenglslRgbMaskFragmentShaderPass1; code[RgbMaskFragmentShaderPass2] = qopenglslRgbMaskFragmentShaderPass2; code[RgbMaskWithGammaFragmentShader] = ""; //### + } - code[NoCompositionModeFragmentShader] = ""; - code[MultiplyCompositionModeFragmentShader] = ""; //### - code[ScreenCompositionModeFragmentShader] = ""; //### - code[OverlayCompositionModeFragmentShader] = ""; //### - code[DarkenCompositionModeFragmentShader] = ""; //### - code[LightenCompositionModeFragmentShader] = ""; //### - code[ColorDodgeCompositionModeFragmentShader] = ""; //### - code[ColorBurnCompositionModeFragmentShader] = ""; //### - code[HardLightCompositionModeFragmentShader] = ""; //### - code[SoftLightCompositionModeFragmentShader] = ""; //### - code[DifferenceCompositionModeFragmentShader] = ""; //### - code[ExclusionCompositionModeFragmentShader] = ""; //### + // 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] = ""; //### + code[OverlayCompositionModeFragmentShader] = ""; //### + code[DarkenCompositionModeFragmentShader] = ""; //### + code[LightenCompositionModeFragmentShader] = ""; //### + code[ColorDodgeCompositionModeFragmentShader] = ""; //### + code[ColorBurnCompositionModeFragmentShader] = ""; //### + code[HardLightCompositionModeFragmentShader] = ""; //### + code[SoftLightCompositionModeFragmentShader] = ""; //### + code[DifferenceCompositionModeFragmentShader] = ""; //### + code[ExclusionCompositionModeFragmentShader] = ""; //### #if defined(QT_DEBUG) - // Check that all the elements have been filled: - for (int i = 0; i < TotalSnippetCount; ++i) { - if (Q_UNLIKELY(!qShaderSnippets[i])) { - qFatal("Shader snippet for %s (#%d) is missing!", - snippetNameStr(SnippetName(i)).constData(), i); - } + // Check that all the elements have been filled: + for (int i = 0; i < TotalSnippetCount; ++i) { + if (Q_UNLIKELY(!qShaderSnippets[i])) { + qFatal("Shader snippet for %s (#%d) is missing!", + snippetNameStr(SnippetName(i)).constData(), i); } -#endif - snippetsPopulated = true; } +#endif - QOpenGLShader* fragShader; - QOpenGLShader* vertexShader; QByteArray vertexSource; QByteArray fragSource; @@ -227,19 +281,11 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context) bool inCache = simpleShaderCache.load(simpleShaderProg, context); if (!inCache) { - vertexShader = new QOpenGLShader(QOpenGLShader::Vertex); - shaders.append(vertexShader); - if (!vertexShader->compileSourceCode(vertexSource)) + if (!simpleShaderProg->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource)) qWarning("Vertex shader for simpleShaderProg (MainVertexShader & PositionOnlyVertexShader) failed to compile"); - - fragShader = new QOpenGLShader(QOpenGLShader::Fragment); - shaders.append(fragShader); - if (!fragShader->compileSourceCode(fragSource)) + if (!simpleShaderProg->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragSource)) qWarning("Fragment shader for simpleShaderProg (MainFragmentShader & ShockingPinkSrcFragmentShader) failed to compile"); - simpleShaderProg->addShader(vertexShader); - simpleShaderProg->addShader(fragShader); - simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); simpleShaderProg->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR); simpleShaderProg->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR); @@ -271,19 +317,11 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context) inCache = blitShaderCache.load(blitShaderProg, context); if (!inCache) { - vertexShader = new QOpenGLShader(QOpenGLShader::Vertex); - shaders.append(vertexShader); - if (!vertexShader->compileSourceCode(vertexSource)) + if (!blitShaderProg->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource)) qWarning("Vertex shader for blitShaderProg (MainWithTexCoordsVertexShader & UntransformedPositionVertexShader) failed to compile"); - - fragShader = new QOpenGLShader(QOpenGLShader::Fragment); - shaders.append(fragShader); - if (!fragShader->compileSourceCode(fragSource)) + if (!blitShaderProg->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragSource)) qWarning("Fragment shader for blitShaderProg (MainFragmentShader & ImageSrcFragmentShader) failed to compile"); - blitShaderProg->addShader(vertexShader); - blitShaderProg->addShader(fragShader); - blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); blitShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); } @@ -306,9 +344,6 @@ QOpenGLEngineSharedShaders::~QOpenGLEngineSharedShaders() #ifdef QT_GL_SHARED_SHADER_DEBUG qDebug(" -> ~QOpenGLEngineSharedShaders() %p for thread %p.", this, QThread::currentThread()); #endif - qDeleteAll(shaders); - shaders.clear(); - qDeleteAll(cachedPrograms); cachedPrograms.clear(); @@ -370,50 +405,37 @@ QOpenGLEngineShaderProg *QOpenGLEngineSharedShaders::findProgramInCache(const QO bool inCache = shaderCache.load(shaderProgram.data(), QOpenGLContext::currentContext()); if (!inCache) { - - QScopedPointer<QOpenGLShader> fragShader(new QOpenGLShader(QOpenGLShader::Fragment)); - QByteArray description; + if (!shaderProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource)) { + QByteArray description; #if defined(QT_DEBUG) - // Name the shader for easier debugging - description.append("Fragment shader: main="); - description.append(snippetNameStr(prog.mainFragShader)); - description.append(", srcPixel="); - description.append(snippetNameStr(prog.srcPixelFragShader)); - if (prog.compositionFragShader) { - description.append(", composition="); - description.append(snippetNameStr(prog.compositionFragShader)); - } - if (prog.maskFragShader) { - description.append(", mask="); - description.append(snippetNameStr(prog.maskFragShader)); - } - fragShader->setObjectName(QString::fromLatin1(description)); + description.append("Vertex shader: main="); + description.append(snippetNameStr(prog.mainVertexShader)); + description.append(", position="); + description.append(snippetNameStr(prog.positionVertexShader)); #endif - if (!fragShader->compileSourceCode(fragSource)) { qWarning("Warning: \"%s\" failed to compile!", description.constData()); break; } - - QScopedPointer<QOpenGLShader> vertexShader(new QOpenGLShader(QOpenGLShader::Vertex)); + if (!shaderProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragSource)) { + QByteArray description; #if defined(QT_DEBUG) - // Name the shader for easier debugging - description.clear(); - description.append("Vertex shader: main="); - description.append(snippetNameStr(prog.mainVertexShader)); - description.append(", position="); - description.append(snippetNameStr(prog.positionVertexShader)); - vertexShader->setObjectName(QString::fromLatin1(description)); + description.append("Fragment shader: main="); + description.append(snippetNameStr(prog.mainFragShader)); + description.append(", srcPixel="); + description.append(snippetNameStr(prog.srcPixelFragShader)); + if (prog.compositionFragShader) { + description.append(", composition="); + description.append(snippetNameStr(prog.compositionFragShader)); + } + if (prog.maskFragShader) { + description.append(", mask="); + description.append(snippetNameStr(prog.maskFragShader)); + } #endif - if (!vertexShader->compileSourceCode(vertexSource)) { qWarning("Warning: \"%s\" failed to compile!", description.constData()); break; } - shaders.append(vertexShader.data()); - shaders.append(fragShader.data()); - shaderProgram->addShader(vertexShader.take()); - shaderProgram->addShader(fragShader.take()); - // We have to bind the vertex attribute names before the program is linked: shaderProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); if (prog.useTextureCoords) @@ -436,18 +458,9 @@ QOpenGLEngineShaderProg *QOpenGLEngineSharedShaders::findProgramInCache(const QO shaderCache.store(newProg->program, QOpenGLContext::currentContext()); } else { QString error; - error = QLatin1String("Shader program failed to link,"); -#if defined(QT_DEBUG) - QLatin1String br("\n"); - error += QLatin1String("\n Shaders Used:\n"); - for (int i = 0; i < newProg->program->shaders().count(); ++i) { - QOpenGLShader *shader = newProg->program->shaders().at(i); - error += QLatin1String(" ") + shader->objectName() + QLatin1String(": \n") - + QLatin1String(shader->sourceCode()) + br; - } -#endif - error += QLatin1String(" Error Log:\n") - + QLatin1String(" ") + newProg->program->log(); + error = QLatin1String("Shader program failed to link") + + QLatin1String(" Error Log:\n") + + QLatin1String(" ") + newProg->program->log(); qWarning() << error; break; } diff --git a/src/gui/opengl/qopenglengineshadermanager_p.h b/src/gui/opengl/qopenglengineshadermanager_p.h index 23b2ccf486..377501457d 100644 --- a/src/gui/opengl/qopenglengineshadermanager_p.h +++ b/src/gui/opengl/qopenglengineshadermanager_p.h @@ -366,7 +366,6 @@ private: QOpenGLShaderProgram *blitShaderProg; QOpenGLShaderProgram *simpleShaderProg; QList<QOpenGLEngineShaderProg*> cachedPrograms; - QList<QOpenGLShader *> shaders; static const char* qShaderSnippets[TotalSnippetCount]; }; diff --git a/src/gui/opengl/qopenglengineshadersource_p.h b/src/gui/opengl/qopenglengineshadersource_p.h index 1e88ac63b5..a165643839 100644 --- a/src/gui/opengl/qopenglengineshadersource_p.h +++ b/src/gui/opengl/qopenglengineshadersource_p.h @@ -58,7 +58,6 @@ QT_BEGIN_NAMESPACE - static const char* const qopenglslMainVertexShader = "\n\ void setPosition(); \n\ void main(void) \n\ @@ -532,40 +531,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 qopenglslMainWithTexCoordsAndOpacityVertexShader_core = + "#version 150 core\n\ + in vec2 textureCoordArray; \n\ + in float opacityArray; \n\ + out vec2 textureCoords; \n\ + out 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 vec2 vertexCoordsArray; \n\ + in vec3 pmvMatrix1; \n\ + in vec3 pmvMatrix2; \n\ + in vec3 pmvMatrix3; \n\ + void setPosition(void) \n\ + { \n\ + 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 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 qopenglslComplexGeometryPositionOnlyVertexShader_core = "\n\ + in vec2 vertexCoordsArray; \n\ + uniform 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 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 vec2 vertexCoordsArray; \n\ + in vec3 pmvMatrix1; \n\ + in vec3 pmvMatrix2; \n\ + in vec3 pmvMatrix3; \n\ + out vec2 patternTexCoords; \n\ + uniform vec2 halfViewportSize; \n\ + uniform vec2 invertedTextureSize; \n\ + uniform mat3 brushTransform; \n\ + void setPosition(void) \n\ + { \n\ + mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ + vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ + gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ + vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ + vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1.0); \n\ + 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 vec2 patternTexCoords;\n\ + uniform sampler2D brushTexture; \n\ + uniform vec4 patternColor; \n\ + 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 vec2 vertexCoordsArray; \n\ + in vec3 pmvMatrix1; \n\ + in vec3 pmvMatrix2; \n\ + in vec3 pmvMatrix3; \n\ + out float index; \n\ + uniform vec2 halfViewportSize; \n\ + uniform vec3 linearData; \n\ + uniform mat3 brushTransform; \n\ + void setPosition() \n\ + { \n\ + mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ + vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ + gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ + vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ + vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\ + 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 float index; \n\ + vec4 srcPixel() \n\ + { \n\ + vec2 val = vec2(index, 0.5); \n\ + return texture(brushTexture, val); \n\ + }\n"; + + +// Conical Gradient Brush +static const char* const qopenglslPositionWithConicalGradientBrushVertexShader_core = "\n\ + in vec2 vertexCoordsArray; \n\ + in vec3 pmvMatrix1; \n\ + in vec3 pmvMatrix2; \n\ + in vec3 pmvMatrix3; \n\ + out vec2 A; \n\ + uniform vec2 halfViewportSize; \n\ + uniform mat3 brushTransform; \n\ + void setPosition(void) \n\ + { \n\ + mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ + vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ + gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ + vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ + vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\ + 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 vec2 A; \n\ + uniform sampler2D brushTexture; \n\ + uniform float angle; \n\ + vec4 srcPixel() \n\ + { \n\ + 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 vec2 vertexCoordsArray;\n\ + in vec3 pmvMatrix1; \n\ + in vec3 pmvMatrix2; \n\ + in vec3 pmvMatrix3; \n\ + out float b; \n\ + out vec2 A; \n\ + uniform vec2 halfViewportSize; \n\ + uniform mat3 brushTransform; \n\ + uniform vec2 fmp; \n\ + uniform vec3 bradius; \n\ + void setPosition(void) \n\ + {\n\ + mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ + vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ + gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ + vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ + vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\ + 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 float b; \n\ + in vec2 A; \n\ + uniform sampler2D brushTexture; \n\ + uniform float fmp2_m_radius2; \n\ + uniform float inverse_2_fmp2_m_radius2; \n\ + uniform float sqrfr; \n\ + uniform vec3 bradius; \n\ + \n\ + vec4 srcPixel() \n\ + { \n\ + float c = sqrfr-dot(A, A); \n\ + float det = b*b - 4.0*fmp2_m_radius2*c; \n\ + vec4 result = vec4(0.0); \n\ + if (det >= 0.0) { \n\ + float detSqrt = sqrt(det); \n\ + 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 vec2 vertexCoordsArray; \n\ + in vec3 pmvMatrix1; \n\ + in vec3 pmvMatrix2; \n\ + in vec3 pmvMatrix3; \n\ + out vec2 brushTextureCoords; \n\ + uniform vec2 halfViewportSize; \n\ + uniform vec2 invertedTextureSize; \n\ + uniform mat3 brushTransform; \n\ + \n\ + void setPosition(void) \n\ + { \n\ + mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ + vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ + gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ + vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ + vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\ + 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 vec2 brushTextureCoords; \n\ + uniform sampler2D brushTexture; \n\ + vec4 srcPixel() \n\ + { \n\ + return texture(brushTexture, brushTextureCoords); \n\ + }\n"; + +static const char* const qopenglslTextureBrushSrcWithPatternFragmentShader_core = "\n\ + in vec2 brushTextureCoords; \n\ + uniform vec4 patternColor; \n\ + uniform sampler2D brushTexture; \n\ + 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 vec4 fragmentColor; \n\ + 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 vec2 textureCoords; \n\ + uniform sampler2D imageTexture; \n\ + vec4 srcPixel() \n\ + { \n\ + return texture(imageTexture, textureCoords); \n\ + }\n"; + +static const char* const qopenglslCustomSrcFragmentShader_core = "\n\ + in vec2 textureCoords; \n\ + uniform sampler2D imageTexture; \n\ + vec4 srcPixel() \n\ + { \n\ + return customShader(imageTexture, textureCoords); \n\ + }\n"; + +static const char* const qopenglslImageSrcWithPatternFragmentShader_core = "\n\ + in vec2 textureCoords; \n\ + uniform vec4 patternColor; \n\ + uniform sampler2D imageTexture; \n\ + vec4 srcPixel() \n\ + { \n\ + return patternColor * (1.0 - texture(imageTexture, textureCoords).r); \n\ + }\n"; + +static const char* const qopenglslNonPremultipliedImageSrcFragmentShader_core = "\n\ + in vec2 textureCoords; \n\ + uniform sampler2D imageTexture; \n\ + vec4 srcPixel() \n\ + { \n\ + 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 vec2 textureCoords; \n\ + uniform sampler2D imageTexture; \n\ + vec4 srcPixel() \n\ + { \n\ + return texture(imageTexture, textureCoords).rrra; \n\ + }\n"; + +static const char* const qopenglslAlphaImageSrcFragmentShader_core = "\n\ + in vec2 textureCoords; \n\ + uniform sampler2D imageTexture; \n\ + vec4 srcPixel() \n\ + { \n\ + return vec4(0, 0, 0, texture(imageTexture, textureCoords).r); \n\ + }\n"; + +static const char* const qopenglslShockingPinkSrcFragmentShader_core = "\n\ + 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 float opacity; \n\ + out vec4 fragColor; \n\ + 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 float globalOpacity; \n\ + vec4 srcPixel(); \n\ + vec4 applyMask(vec4); \n\ + vec4 compose(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\ + vec4 srcPixel(); \n\ + vec4 applyMask(vec4); \n\ + vec4 compose(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 float globalOpacity; \n\ + vec4 srcPixel(); \n\ + vec4 applyMask(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\ + vec4 srcPixel(); \n\ + vec4 applyMask(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 float globalOpacity; \n\ + vec4 srcPixel(); \n\ + vec4 compose(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\ + vec4 srcPixel(); \n\ + vec4 compose(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 float globalOpacity; \n\ + 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\ + vec4 srcPixel(); \n\ + void main() \n\ + { \n\ + fragColor = srcPixel(); \n\ + }\n"; + +static const char* const qopenglslMaskFragmentShader_core = "\n\ + in vec2 textureCoords;\n\ + uniform sampler2D maskTexture;\n\ + vec4 applyMask(vec4 src) \n\ + {\n\ + vec4 mask = texture(maskTexture, textureCoords); \n\ + return src * mask.r; \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 vec2 textureCoords;\n\ + uniform sampler2D maskTexture;\n\ + vec4 applyMask(vec4 src) \n\ + { \n\ + vec4 mask = texture(maskTexture, textureCoords); \n\ + return src.a * mask; \n\ + }\n"; + +static const char* const qopenglslRgbMaskFragmentShaderPass2_core = "\n\ + in vec2 textureCoords;\n\ + uniform sampler2D maskTexture;\n\ + vec4 applyMask(vec4 src) \n\ + { \n\ + 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/qopenglfunctions.h b/src/gui/opengl/qopenglfunctions.h index aad48571b3..f1a717f659 100644 --- a/src/gui/opengl/qopenglfunctions.h +++ b/src/gui/opengl/qopenglfunctions.h @@ -591,499 +591,319 @@ struct QOpenGLFunctionsPrivate inline void QOpenGLFunctions::glBindTexture(GLenum target, GLuint texture) { -#ifdef QT_OPENGL_ES_2 - ::glBindTexture(target, texture); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.BindTexture(target, texture); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glBlendFunc(GLenum sfactor, GLenum dfactor) { -#ifdef QT_OPENGL_ES_2 - ::glBlendFunc(sfactor, dfactor); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.BlendFunc(sfactor, dfactor); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glClear(GLbitfield mask) { -#ifdef QT_OPENGL_ES_2 - ::glClear(mask); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Clear(mask); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { -#ifdef QT_OPENGL_ES_2 - ::glClearColor(red, green, blue, alpha); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.ClearColor(red, green, blue, alpha); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glClearStencil(GLint s) { -#ifdef QT_OPENGL_ES_2 - ::glClearStencil(s); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.ClearStencil(s); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { -#ifdef QT_OPENGL_ES_2 - ::glColorMask(red, green, blue, alpha); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.ColorMask(red, green, blue, alpha); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { -#ifdef QT_OPENGL_ES_2 - ::glCopyTexImage2D(target, level, internalformat, x, y, width,height, border); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.CopyTexImage2D(target, level, internalformat, x, y, width,height, border); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { -#ifdef QT_OPENGL_ES_2 - ::glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glCullFace(GLenum mode) { -#ifdef QT_OPENGL_ES_2 - ::glCullFace(mode); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.CullFace(mode); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glDeleteTextures(GLsizei n, const GLuint* textures) { -#ifdef QT_OPENGL_ES_2 - ::glDeleteTextures(n, textures); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.DeleteTextures(n, textures); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glDepthFunc(GLenum func) { -#ifdef QT_OPENGL_ES_2 - ::glDepthFunc(func); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.DepthFunc(func); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glDepthMask(GLboolean flag) { -#ifdef QT_OPENGL_ES_2 - ::glDepthMask(flag); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.DepthMask(flag); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glDisable(GLenum cap) { -#ifdef QT_OPENGL_ES_2 - ::glDisable(cap); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Disable(cap); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glDrawArrays(GLenum mode, GLint first, GLsizei count) { -#ifdef QT_OPENGL_ES_2 - ::glDrawArrays(mode, first, count); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.DrawArrays(mode, first, count); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) { -#ifdef QT_OPENGL_ES_2 - ::glDrawElements(mode, count, type, indices); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.DrawElements(mode, count, type, indices); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glEnable(GLenum cap) { -#ifdef QT_OPENGL_ES_2 - ::glEnable(cap); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Enable(cap); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glFinish() { -#ifdef QT_OPENGL_ES_2 - ::glFinish(); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Finish(); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glFlush() { -#ifdef QT_OPENGL_ES_2 - ::glFlush(); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Flush(); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glFrontFace(GLenum mode) { -#ifdef QT_OPENGL_ES_2 - ::glFrontFace(mode); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.FrontFace(mode); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGenTextures(GLsizei n, GLuint* textures) { -#ifdef QT_OPENGL_ES_2 - ::glGenTextures(n, textures); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GenTextures(n, textures); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGetBooleanv(GLenum pname, GLboolean* params) { -#ifdef QT_OPENGL_ES_2 - ::glGetBooleanv(pname, params); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetBooleanv(pname, params); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline GLenum QOpenGLFunctions::glGetError() { -#ifdef QT_OPENGL_ES_2 - GLenum result = ::glGetError(); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); GLenum result = d_ptr->f.GetError(); -#endif return result; } inline void QOpenGLFunctions::glGetFloatv(GLenum pname, GLfloat* params) { -#ifdef QT_OPENGL_ES_2 - ::glGetFloatv(pname, params); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetFloatv(pname, params); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGetIntegerv(GLenum pname, GLint* params) { -#ifdef QT_OPENGL_ES_2 - ::glGetIntegerv(pname, params); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetIntegerv(pname, params); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline const GLubyte *QOpenGLFunctions::glGetString(GLenum name) { -#ifdef QT_OPENGL_ES_2 - const GLubyte *result = ::glGetString(name); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); const GLubyte *result = d_ptr->f.GetString(name); -#endif Q_OPENGL_FUNCTIONS_DEBUG return result; } inline void QOpenGLFunctions::glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) { -#ifdef QT_OPENGL_ES_2 - ::glGetTexParameterfv(target, pname, params); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetTexParameterfv(target, pname, params); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) { -#ifdef QT_OPENGL_ES_2 - ::glGetTexParameteriv(target, pname, params); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetTexParameteriv(target, pname, params); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glHint(GLenum target, GLenum mode) { -#ifdef QT_OPENGL_ES_2 - ::glHint(target, mode); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Hint(target, mode); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline GLboolean QOpenGLFunctions::glIsEnabled(GLenum cap) { -#ifdef QT_OPENGL_ES_2 - GLboolean result = ::glIsEnabled(cap); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); GLboolean result = d_ptr->f.IsEnabled(cap); -#endif Q_OPENGL_FUNCTIONS_DEBUG return result; } inline GLboolean QOpenGLFunctions::glIsTexture(GLuint texture) { -#ifdef QT_OPENGL_ES_2 - GLboolean result = ::glIsTexture(texture); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); GLboolean result = d_ptr->f.IsTexture(texture); -#endif Q_OPENGL_FUNCTIONS_DEBUG return result; } inline void QOpenGLFunctions::glLineWidth(GLfloat width) { -#ifdef QT_OPENGL_ES_2 - ::glLineWidth(width); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.LineWidth(width); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glPixelStorei(GLenum pname, GLint param) { -#ifdef QT_OPENGL_ES_2 - ::glPixelStorei(pname, param); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.PixelStorei(pname, param); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glPolygonOffset(GLfloat factor, GLfloat units) { -#ifdef QT_OPENGL_ES_2 - ::glPolygonOffset(factor, units); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.PolygonOffset(factor, units); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) { -#ifdef QT_OPENGL_ES_2 - ::glReadPixels(x, y, width, height, format, type, pixels); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.ReadPixels(x, y, width, height, format, type, pixels); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glScissor(GLint x, GLint y, GLsizei width, GLsizei height) { -#ifdef QT_OPENGL_ES_2 - ::glScissor(x, y, width, height); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Scissor(x, y, width, height); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glStencilFunc(GLenum func, GLint ref, GLuint mask) { -#ifdef QT_OPENGL_ES_2 - ::glStencilFunc(func, ref, mask); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.StencilFunc(func, ref, mask); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glStencilMask(GLuint mask) { -#ifdef QT_OPENGL_ES_2 - ::glStencilMask(mask); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.StencilMask(mask); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) { -#ifdef QT_OPENGL_ES_2 - ::glStencilOp(fail, zfail, zpass); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.StencilOp(fail, zfail, zpass); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) { -#ifdef QT_OPENGL_ES_2 - ::glTexImage2D(target, level, internalformat, width,height, border, format, type, pixels); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.TexImage2D(target, level, internalformat, width,height, border, format, type, pixels); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glTexParameterf(GLenum target, GLenum pname, GLfloat param) { -#ifdef QT_OPENGL_ES_2 - ::glTexParameterf(target, pname, param); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.TexParameterf(target, pname, param); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params) { -#ifdef QT_OPENGL_ES_2 - ::glTexParameterfv(target, pname, params); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.TexParameterfv(target, pname, params); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glTexParameteri(GLenum target, GLenum pname, GLint param) { -#ifdef QT_OPENGL_ES_2 - ::glTexParameteri(target, pname, param); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.TexParameteri(target, pname, param); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glTexParameteriv(GLenum target, GLenum pname, const GLint* params) { -#ifdef QT_OPENGL_ES_2 - ::glTexParameteriv(target, pname, params); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.TexParameteriv(target, pname, params); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels) { -#ifdef QT_OPENGL_ES_2 - ::glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.TexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glViewport(GLint x, GLint y, GLsizei width, GLsizei height) { -#ifdef QT_OPENGL_ES_2 - ::glViewport(x, y, width, height); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Viewport(x, y, width, height); -#endif Q_OPENGL_FUNCTIONS_DEBUG } @@ -1091,45 +911,29 @@ inline void QOpenGLFunctions::glViewport(GLint x, GLint y, GLsizei width, GLsize inline void QOpenGLFunctions::glActiveTexture(GLenum texture) { -#ifdef QT_OPENGL_ES_2 - ::glActiveTexture(texture); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.ActiveTexture(texture); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glAttachShader(GLuint program, GLuint shader) { -#ifdef QT_OPENGL_ES_2 - ::glAttachShader(program, shader); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.AttachShader(program, shader); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glBindAttribLocation(GLuint program, GLuint index, const char* name) { -#ifdef QT_OPENGL_ES_2 - ::glBindAttribLocation(program, index, name); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.BindAttribLocation(program, index, name); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glBindBuffer(GLenum target, GLuint buffer) { -#ifdef QT_OPENGL_ES_2 - ::glBindBuffer(target, buffer); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.BindBuffer(target, buffer); -#endif Q_OPENGL_FUNCTIONS_DEBUG } @@ -1137,1034 +941,662 @@ inline void QOpenGLFunctions::glBindFramebuffer(GLenum target, GLuint framebuffe { if (framebuffer == 0) framebuffer = QOpenGLContext::currentContext()->defaultFramebufferObject(); -#ifdef QT_OPENGL_ES_2 - ::glBindFramebuffer(target, framebuffer); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.BindFramebuffer(target, framebuffer); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glBindRenderbuffer(GLenum target, GLuint renderbuffer) { -#ifdef QT_OPENGL_ES_2 - ::glBindRenderbuffer(target, renderbuffer); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.BindRenderbuffer(target, renderbuffer); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { -#ifdef QT_OPENGL_ES_2 - ::glBlendColor(red, green, blue, alpha); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.BlendColor(red, green, blue, alpha); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glBlendEquation(GLenum mode) { -#ifdef QT_OPENGL_ES_2 - ::glBlendEquation(mode); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.BlendEquation(mode); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) { -#ifdef QT_OPENGL_ES_2 - ::glBlendEquationSeparate(modeRGB, modeAlpha); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.BlendEquationSeparate(modeRGB, modeAlpha); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { -#ifdef QT_OPENGL_ES_2 - ::glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.BlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glBufferData(GLenum target, qopengl_GLsizeiptr size, const void* data, GLenum usage) { -#ifdef QT_OPENGL_ES_2 - ::glBufferData(target, size, data, usage); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.BufferData(target, size, data, usage); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glBufferSubData(GLenum target, qopengl_GLintptr offset, qopengl_GLsizeiptr size, const void* data) { -#ifdef QT_OPENGL_ES_2 - ::glBufferSubData(target, offset, size, data); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.BufferSubData(target, offset, size, data); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline GLenum QOpenGLFunctions::glCheckFramebufferStatus(GLenum target) { -#ifdef QT_OPENGL_ES_2 - GLenum result = ::glCheckFramebufferStatus(target); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); GLenum result = d_ptr->f.CheckFramebufferStatus(target); -#endif Q_OPENGL_FUNCTIONS_DEBUG return result; } inline void QOpenGLFunctions::glClearDepthf(GLclampf depth) { -#ifndef QT_OPENGL_ES Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.ClearDepthf(depth); -#else - ::glClearDepthf(depth); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glCompileShader(GLuint shader) { -#ifdef QT_OPENGL_ES_2 - ::glCompileShader(shader); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.CompileShader(shader); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data) { -#ifdef QT_OPENGL_ES_2 - ::glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.CompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data) { -#ifdef QT_OPENGL_ES_2 - ::glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.CompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline GLuint QOpenGLFunctions::glCreateProgram() { -#ifdef QT_OPENGL_ES_2 - GLuint result = ::glCreateProgram(); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); GLuint result = d_ptr->f.CreateProgram(); -#endif Q_OPENGL_FUNCTIONS_DEBUG return result; } inline GLuint QOpenGLFunctions::glCreateShader(GLenum type) { -#ifdef QT_OPENGL_ES_2 - GLuint result = ::glCreateShader(type); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); GLuint result = d_ptr->f.CreateShader(type); -#endif Q_OPENGL_FUNCTIONS_DEBUG return result; } inline void QOpenGLFunctions::glDeleteBuffers(GLsizei n, const GLuint* buffers) { -#ifdef QT_OPENGL_ES_2 - ::glDeleteBuffers(n, buffers); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.DeleteBuffers(n, buffers); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) { -#ifdef QT_OPENGL_ES_2 - ::glDeleteFramebuffers(n, framebuffers); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.DeleteFramebuffers(n, framebuffers); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glDeleteProgram(GLuint program) { -#ifdef QT_OPENGL_ES_2 - ::glDeleteProgram(program); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.DeleteProgram(program); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) { -#ifdef QT_OPENGL_ES_2 - ::glDeleteRenderbuffers(n, renderbuffers); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.DeleteRenderbuffers(n, renderbuffers); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glDeleteShader(GLuint shader) { -#ifdef QT_OPENGL_ES_2 - ::glDeleteShader(shader); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.DeleteShader(shader); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glDepthRangef(GLclampf zNear, GLclampf zFar) { -#ifndef QT_OPENGL_ES Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.DepthRangef(zNear, zFar); -#else - ::glDepthRangef(zNear, zFar); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glDetachShader(GLuint program, GLuint shader) { -#ifdef QT_OPENGL_ES_2 - ::glDetachShader(program, shader); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.DetachShader(program, shader); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glDisableVertexAttribArray(GLuint index) { -#ifdef QT_OPENGL_ES_2 - ::glDisableVertexAttribArray(index); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.DisableVertexAttribArray(index); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glEnableVertexAttribArray(GLuint index) { -#ifdef QT_OPENGL_ES_2 - ::glEnableVertexAttribArray(index); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.EnableVertexAttribArray(index); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) { -#ifdef QT_OPENGL_ES_2 - ::glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.FramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { -#ifdef QT_OPENGL_ES_2 - ::glFramebufferTexture2D(target, attachment, textarget, texture, level); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.FramebufferTexture2D(target, attachment, textarget, texture, level); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGenBuffers(GLsizei n, GLuint* buffers) { -#ifdef QT_OPENGL_ES_2 - ::glGenBuffers(n, buffers); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GenBuffers(n, buffers); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGenerateMipmap(GLenum target) { -#ifdef QT_OPENGL_ES_2 - ::glGenerateMipmap(target); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GenerateMipmap(target); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGenFramebuffers(GLsizei n, GLuint* framebuffers) { -#ifdef QT_OPENGL_ES_2 - ::glGenFramebuffers(n, framebuffers); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GenFramebuffers(n, framebuffers); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) { -#ifdef QT_OPENGL_ES_2 - ::glGenRenderbuffers(n, renderbuffers); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GenRenderbuffers(n, renderbuffers); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) { -#ifdef QT_OPENGL_ES_2 - ::glGetActiveAttrib(program, index, bufsize, length, size, type, name); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetActiveAttrib(program, index, bufsize, length, size, type, name); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) { -#ifdef QT_OPENGL_ES_2 - ::glGetActiveUniform(program, index, bufsize, length, size, type, name); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetActiveUniform(program, index, bufsize, length, size, type, name); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) { -#ifdef QT_OPENGL_ES_2 - ::glGetAttachedShaders(program, maxcount, count, shaders); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetAttachedShaders(program, maxcount, count, shaders); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline GLint QOpenGLFunctions::glGetAttribLocation(GLuint program, const char* name) { -#ifdef QT_OPENGL_ES_2 - GLint result = ::glGetAttribLocation(program, name); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); GLint result = d_ptr->f.GetAttribLocation(program, name); -#endif Q_OPENGL_FUNCTIONS_DEBUG return result; } inline void QOpenGLFunctions::glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) { -#ifdef QT_OPENGL_ES_2 - ::glGetBufferParameteriv(target, pname, params); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetBufferParameteriv(target, pname, params); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params) { -#ifdef QT_OPENGL_ES_2 - ::glGetFramebufferAttachmentParameteriv(target, attachment, pname, params); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetFramebufferAttachmentParameteriv(target, attachment, pname, params); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGetProgramiv(GLuint program, GLenum pname, GLint* params) { -#ifdef QT_OPENGL_ES_2 - ::glGetProgramiv(program, pname, params); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetProgramiv(program, pname, params); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) { -#ifdef QT_OPENGL_ES_2 - ::glGetProgramInfoLog(program, bufsize, length, infolog); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetProgramInfoLog(program, bufsize, length, infolog); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) { -#ifdef QT_OPENGL_ES_2 - ::glGetRenderbufferParameteriv(target, pname, params); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetRenderbufferParameteriv(target, pname, params); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGetShaderiv(GLuint shader, GLenum pname, GLint* params) { -#ifdef QT_OPENGL_ES_2 - ::glGetShaderiv(shader, pname, params); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetShaderiv(shader, pname, params); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) { -#ifdef QT_OPENGL_ES_2 - ::glGetShaderInfoLog(shader, bufsize, length, infolog); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetShaderInfoLog(shader, bufsize, length, infolog); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) { -#ifdef QT_OPENGL_ES_2 - ::glGetShaderPrecisionFormat(shadertype, precisiontype, range, precision); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetShaderPrecisionFormat(shadertype, precisiontype, range, precision); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, char* source) { -#ifdef QT_OPENGL_ES_2 - ::glGetShaderSource(shader, bufsize, length, source); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetShaderSource(shader, bufsize, length, source); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGetUniformfv(GLuint program, GLint location, GLfloat* params) { -#ifdef QT_OPENGL_ES_2 - ::glGetUniformfv(program, location, params); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetUniformfv(program, location, params); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGetUniformiv(GLuint program, GLint location, GLint* params) { -#ifdef QT_OPENGL_ES_2 - ::glGetUniformiv(program, location, params); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetUniformiv(program, location, params); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline GLint QOpenGLFunctions::glGetUniformLocation(GLuint program, const char* name) { -#ifdef QT_OPENGL_ES_2 - GLint result = ::glGetUniformLocation(program, name); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); GLint result = d_ptr->f.GetUniformLocation(program, name); -#endif Q_OPENGL_FUNCTIONS_DEBUG return result; } inline void QOpenGLFunctions::glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) { -#ifdef QT_OPENGL_ES_2 - ::glGetVertexAttribfv(index, pname, params); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetVertexAttribfv(index, pname, params); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) { -#ifdef QT_OPENGL_ES_2 - ::glGetVertexAttribiv(index, pname, params); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetVertexAttribiv(index, pname, params); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glGetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer) { -#ifdef QT_OPENGL_ES_2 - ::glGetVertexAttribPointerv(index, pname, pointer); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.GetVertexAttribPointerv(index, pname, pointer); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline GLboolean QOpenGLFunctions::glIsBuffer(GLuint buffer) { -#ifdef QT_OPENGL_ES_2 - GLboolean result = ::glIsBuffer(buffer); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); GLboolean result = d_ptr->f.IsBuffer(buffer); -#endif Q_OPENGL_FUNCTIONS_DEBUG return result; } inline GLboolean QOpenGLFunctions::glIsFramebuffer(GLuint framebuffer) { -#ifdef QT_OPENGL_ES_2 - GLboolean result = ::glIsFramebuffer(framebuffer); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); GLboolean result = d_ptr->f.IsFramebuffer(framebuffer); -#endif Q_OPENGL_FUNCTIONS_DEBUG return result; } inline GLboolean QOpenGLFunctions::glIsProgram(GLuint program) { -#ifdef QT_OPENGL_ES_2 - GLboolean result = ::glIsProgram(program); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); GLboolean result = d_ptr->f.IsProgram(program); -#endif Q_OPENGL_FUNCTIONS_DEBUG return result; } inline GLboolean QOpenGLFunctions::glIsRenderbuffer(GLuint renderbuffer) { -#ifdef QT_OPENGL_ES_2 - GLboolean result = ::glIsRenderbuffer(renderbuffer); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); GLboolean result = d_ptr->f.IsRenderbuffer(renderbuffer); -#endif Q_OPENGL_FUNCTIONS_DEBUG return result; } inline GLboolean QOpenGLFunctions::glIsShader(GLuint shader) { -#ifdef QT_OPENGL_ES_2 - GLboolean result = ::glIsShader(shader); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); GLboolean result = d_ptr->f.IsShader(shader); -#endif Q_OPENGL_FUNCTIONS_DEBUG return result; } inline void QOpenGLFunctions::glLinkProgram(GLuint program) { -#ifdef QT_OPENGL_ES_2 - ::glLinkProgram(program); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.LinkProgram(program); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glReleaseShaderCompiler() { -#ifdef QT_OPENGL_ES_2 - ::glReleaseShaderCompiler(); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.ReleaseShaderCompiler(); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { -#ifdef QT_OPENGL_ES_2 - ::glRenderbufferStorage(target, internalformat, width, height); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.RenderbufferStorage(target, internalformat, width, height); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glSampleCoverage(GLclampf value, GLboolean invert) { -#ifdef QT_OPENGL_ES_2 - ::glSampleCoverage(value, invert); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.SampleCoverage(value, invert); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length) { -#ifdef QT_OPENGL_ES_2 - ::glShaderBinary(n, shaders, binaryformat, binary, length); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.ShaderBinary(n, shaders, binaryformat, binary, length); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glShaderSource(GLuint shader, GLsizei count, const char** string, const GLint* length) { -#ifdef QT_OPENGL_ES_2 - ::glShaderSource(shader, count, string, length); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.ShaderSource(shader, count, string, length); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) { -#ifdef QT_OPENGL_ES_2 - ::glStencilFuncSeparate(face, func, ref, mask); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.StencilFuncSeparate(face, func, ref, mask); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glStencilMaskSeparate(GLenum face, GLuint mask) { -#ifdef QT_OPENGL_ES_2 - ::glStencilMaskSeparate(face, mask); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.StencilMaskSeparate(face, mask); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) { -#ifdef QT_OPENGL_ES_2 - ::glStencilOpSeparate(face, fail, zfail, zpass); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.StencilOpSeparate(face, fail, zfail, zpass); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUniform1f(GLint location, GLfloat x) { -#ifdef QT_OPENGL_ES_2 - ::glUniform1f(location, x); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Uniform1f(location, x); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUniform1fv(GLint location, GLsizei count, const GLfloat* v) { -#ifdef QT_OPENGL_ES_2 - ::glUniform1fv(location, count, v); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Uniform1fv(location, count, v); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUniform1i(GLint location, GLint x) { -#ifdef QT_OPENGL_ES_2 - ::glUniform1i(location, x); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Uniform1i(location, x); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUniform1iv(GLint location, GLsizei count, const GLint* v) { -#ifdef QT_OPENGL_ES_2 - ::glUniform1iv(location, count, v); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Uniform1iv(location, count, v); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUniform2f(GLint location, GLfloat x, GLfloat y) { -#ifdef QT_OPENGL_ES_2 - ::glUniform2f(location, x, y); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Uniform2f(location, x, y); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUniform2fv(GLint location, GLsizei count, const GLfloat* v) { -#ifdef QT_OPENGL_ES_2 - ::glUniform2fv(location, count, v); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Uniform2fv(location, count, v); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUniform2i(GLint location, GLint x, GLint y) { -#ifdef QT_OPENGL_ES_2 - ::glUniform2i(location, x, y); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Uniform2i(location, x, y); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUniform2iv(GLint location, GLsizei count, const GLint* v) { -#ifdef QT_OPENGL_ES_2 - ::glUniform2iv(location, count, v); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Uniform2iv(location, count, v); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) { -#ifdef QT_OPENGL_ES_2 - ::glUniform3f(location, x, y, z); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Uniform3f(location, x, y, z); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUniform3fv(GLint location, GLsizei count, const GLfloat* v) { -#ifdef QT_OPENGL_ES_2 - ::glUniform3fv(location, count, v); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Uniform3fv(location, count, v); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUniform3i(GLint location, GLint x, GLint y, GLint z) { -#ifdef QT_OPENGL_ES_2 - ::glUniform3i(location, x, y, z); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Uniform3i(location, x, y, z); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUniform3iv(GLint location, GLsizei count, const GLint* v) { -#ifdef QT_OPENGL_ES_2 - ::glUniform3iv(location, count, v); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Uniform3iv(location, count, v); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { -#ifdef QT_OPENGL_ES_2 - ::glUniform4f(location, x, y, z, w); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Uniform4f(location, x, y, z, w); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUniform4fv(GLint location, GLsizei count, const GLfloat* v) { -#ifdef QT_OPENGL_ES_2 - ::glUniform4fv(location, count, v); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Uniform4fv(location, count, v); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) { -#ifdef QT_OPENGL_ES_2 - ::glUniform4i(location, x, y, z, w); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Uniform4i(location, x, y, z, w); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUniform4iv(GLint location, GLsizei count, const GLint* v) { -#ifdef QT_OPENGL_ES_2 - ::glUniform4iv(location, count, v); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.Uniform4iv(location, count, v); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { -#ifdef QT_OPENGL_ES_2 - ::glUniformMatrix2fv(location, count, transpose, value); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.UniformMatrix2fv(location, count, transpose, value); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { -#ifdef QT_OPENGL_ES_2 - ::glUniformMatrix3fv(location, count, transpose, value); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.UniformMatrix3fv(location, count, transpose, value); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { -#ifdef QT_OPENGL_ES_2 - ::glUniformMatrix4fv(location, count, transpose, value); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.UniformMatrix4fv(location, count, transpose, value); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glUseProgram(GLuint program) { -#ifdef QT_OPENGL_ES_2 - ::glUseProgram(program); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.UseProgram(program); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glValidateProgram(GLuint program) { -#ifdef QT_OPENGL_ES_2 - ::glValidateProgram(program); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.ValidateProgram(program); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glVertexAttrib1f(GLuint indx, GLfloat x) { -#ifdef QT_OPENGL_ES_2 - ::glVertexAttrib1f(indx, x); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.VertexAttrib1f(indx, x); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glVertexAttrib1fv(GLuint indx, const GLfloat* values) { -#ifdef QT_OPENGL_ES_2 - ::glVertexAttrib1fv(indx, values); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.VertexAttrib1fv(indx, values); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) { -#ifdef QT_OPENGL_ES_2 - ::glVertexAttrib2f(indx, x, y); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.VertexAttrib2f(indx, x, y); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glVertexAttrib2fv(GLuint indx, const GLfloat* values) { -#ifdef QT_OPENGL_ES_2 - ::glVertexAttrib2fv(indx, values); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.VertexAttrib2fv(indx, values); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) { -#ifdef QT_OPENGL_ES_2 - ::glVertexAttrib3f(indx, x, y, z); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.VertexAttrib3f(indx, x, y, z); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glVertexAttrib3fv(GLuint indx, const GLfloat* values) { -#ifdef QT_OPENGL_ES_2 - ::glVertexAttrib3fv(indx, values); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.VertexAttrib3fv(indx, values); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { -#ifdef QT_OPENGL_ES_2 - ::glVertexAttrib4f(indx, x, y, z, w); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.VertexAttrib4f(indx, x, y, z, w); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glVertexAttrib4fv(GLuint indx, const GLfloat* values) { -#ifdef QT_OPENGL_ES_2 - ::glVertexAttrib4fv(indx, values); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.VertexAttrib4fv(indx, values); -#endif Q_OPENGL_FUNCTIONS_DEBUG } inline void QOpenGLFunctions::glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr) { -#ifdef QT_OPENGL_ES_2 - ::glVertexAttribPointer(indx, size, type, normalized, stride, ptr); -#else Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); d_ptr->f.VertexAttribPointer(indx, size, type, normalized, stride, ptr); -#endif Q_OPENGL_FUNCTIONS_DEBUG } diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index 90652a5ab8..aeb4fc0b7a 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -99,6 +99,12 @@ QOpenGL2PaintEngineExPrivate::~QOpenGL2PaintEngineExPrivate() { delete shaderManager; + vertexBuffer.destroy(); + texCoordBuffer.destroy(); + opacityBuffer.destroy(); + indexBuffer.destroy(); + vao.destroy(); + if (elementIndicesVBOId != 0) { funcs.glDeleteBuffers(1, &elementIndicesVBOId); elementIndicesVBOId = 0; @@ -578,6 +584,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 +676,11 @@ void QOpenGL2PaintEngineExPrivate::resetGLState() float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; funcs.glVertexAttrib4fv(3, color); } + if (vao.isCreated()) { + vao.release(); + funcs.glBindBuffer(GL_ARRAY_BUFFER, 0); + funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } } void QOpenGL2PaintEngineEx::endNativePainting() @@ -696,16 +713,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... @@ -761,6 +778,8 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path) if (matrixDirty) updateMatrix(); + const bool supportsElementIndexUint = funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint); + const QPointF* const points = reinterpret_cast<const QPointF*>(path.points()); // Check to see if there's any hints @@ -824,9 +843,10 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path) prepareForDraw(currentBrush.isOpaque()); #ifdef QT_OPENGL_CACHE_AS_VBOS funcs.glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); + uploadData(QT_VERTEX_COORD_ATTR, 0, cache->vertexCount); setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0); #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); @@ -881,7 +901,7 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path) // Flatten the path at the current scale factor and fill it into the cache struct. if (updateCache) { - QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale)); + QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale), 1, supportsElementIndexUint); cache->vertexCount = polys.vertices.size() / 2; cache->indexCount = polys.indices.size(); cache->primitiveType = GL_TRIANGLES; @@ -920,6 +940,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); + uploadData(QT_VERTEX_COORDS_ATTR, 0, cache->vertexCount); setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0); if (cache->indexType == QVertexIndexVector::UnsignedInt) funcs.glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, 0); @@ -928,11 +949,10 @@ 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); - if (cache->indexType == QVertexIndexVector::UnsignedInt) - funcs.glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, (qint32 *)cache->indices); - else - funcs.glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_SHORT, (qint16 *)cache->indices); + uploadData(QT_VERTEX_COORDS_ATTR, cache->vertices, cache->vertexCount * 2); + const GLenum indexValueType = cache->indexType == QVertexIndexVector::UnsignedInt ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; + const bool useIndexVbo = uploadIndexData(cache->indices, indexValueType, cache->indexCount); + funcs.glDrawElements(cache->primitiveType, cache->indexCount, indexValueType, useIndexVbo ? nullptr : cache->indices); #endif } else { @@ -950,18 +970,17 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path) && (bbox.top() > -0x8000 * inverseScale) && (bbox.bottom() < 0x8000 * inverseScale); if (withinLimits) { - QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale)); + QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale), 1, supportsElementIndexUint); QVarLengthArray<float> vertices(polys.vertices.size()); for (int i = 0; i < polys.vertices.size(); ++i) vertices[i] = float(inverseScale * polys.vertices.at(i)); prepareForDraw(currentBrush.isOpaque()); - setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, vertices.constData()); - if (funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint)) - funcs.glDrawElements(GL_TRIANGLES, polys.indices.size(), GL_UNSIGNED_INT, polys.indices.data()); - else - funcs.glDrawElements(GL_TRIANGLES, polys.indices.size(), GL_UNSIGNED_SHORT, polys.indices.data()); + uploadData(QT_VERTEX_COORDS_ATTR, vertices.constData(), vertices.size()); + const GLenum indexValueType = funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; + const bool useIndexVbo = uploadIndexData(polys.indices.data(), indexValueType, polys.indices.size()); + funcs.glDrawElements(GL_TRIANGLES, polys.indices.size(), indexValueType, useIndexVbo ? nullptr : polys.indices.data()); } else { // We can't handle big, concave painter paths with OpenGL without stencil buffer. qWarning("Painter path exceeds +/-32767 pixels."); @@ -1083,7 +1102,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 +1233,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 +1243,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; } @@ -1323,14 +1340,9 @@ void QOpenGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &p 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 +1851,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) { @@ -1904,7 +1916,8 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly #if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0); #else - funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data()); + const bool useIndexVbo = uploadIndexData(elementIndices.data(), GL_UNSIGNED_SHORT, 6 * numGlyphs); + funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, useIndexVbo ? nullptr : elementIndices.data()); #endif shaderManager->setMaskType(QOpenGLEngineShaderManager::SubPixelMaskPass2); @@ -1955,7 +1968,8 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0); funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); #else - funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data()); + const bool useIndexVbo = uploadIndexData(elementIndices.data(), GL_UNSIGNED_SHORT, 6 * numGlyphs); + funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, useIndexVbo ? nullptr : elementIndices.data()); #endif } @@ -2074,6 +2088,15 @@ bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev) return false; } + if (d->ctx != QOpenGLContext::currentContext() + || (d->ctx && QOpenGLContext::currentContext() && d->ctx->format() != QOpenGLContext::currentContext()->format())) { + d->vertexBuffer.destroy(); + d->texCoordBuffer.destroy(); + d->opacityBuffer.destroy(); + d->indexBuffer.destroy(); + d->vao.destroy(); + } + d->ctx = QOpenGLContext::currentContext(); d->ctx->d_func()->active_engine = this; @@ -2081,6 +2104,42 @@ bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev) d->funcs.initializeOpenGLFunctions(); + // Generate a new Vertex Array Object if we don't have one already. We can + // only hit the VAO-based path when using a core profile context. This is + // because while non-core contexts can support VAOs via extensions, legacy + // components like the QtOpenGL module do not know about VAOs. There are + // still tests for QGL-QOpenGL paint engine interoperability, so keep the + // status quo for now, and avoid introducing a VAO in non-core contexts. + const bool needsVAO = d->ctx->format().profile() == QSurfaceFormat::CoreProfile + && d->ctx->format().version() >= qMakePair(3, 2); + if (needsVAO && !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); + } + if (!d->texCoordBuffer.isCreated()) { + d->texCoordBuffer.create(); + d->texCoordBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw); + } + if (!d->opacityBuffer.isCreated()) { + d->opacityBuffer.create(); + d->opacityBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw); + } + if (!d->indexBuffer.isCreated()) { + d->indexBuffer.create(); + d->indexBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw); + } + } + } + for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i) d->vertexAttributeArraysEnabledState[i] = false; @@ -2162,6 +2221,9 @@ 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 807efb1ec2..679b3c0557 100644 --- a/src/gui/opengl/qopenglpaintengine_p.h +++ b/src/gui/opengl/qopenglpaintengine_p.h @@ -65,6 +65,9 @@ #include <private/qopenglextensions_p.h> +#include <QOpenGLVertexArrayObject> +#include <QOpenGLBuffer> + enum EngineMode { ImageDrawingMode, TextDrawingMode, @@ -193,7 +196,11 @@ public: snapToPixelGrid(false), nativePaintingActive(false), inverseScale(1), - lastTextureUnitUsed(QT_UNKNOWN_TEXTURE_UNIT) + lastTextureUnitUsed(QT_UNKNOWN_TEXTURE_UNIT), + vertexBuffer(QOpenGLBuffer::VertexBuffer), + texCoordBuffer(QOpenGLBuffer::VertexBuffer), + opacityBuffer(QOpenGLBuffer::VertexBuffer), + indexBuffer(QOpenGLBuffer::IndexBuffer) { } ~QOpenGL2PaintEngineExPrivate(); @@ -222,7 +229,8 @@ 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, GLuint count); + inline bool uploadIndexData(const void *data, GLenum indexValueType, GLuint count); // draws whatever is in the vertex array: void drawVertexArrays(const float *data, int *stops, int stopCount, GLenum primitive); @@ -313,6 +321,12 @@ public: GLenum lastTextureUnitUsed; GLuint lastTextureUsed; + QOpenGLVertexArrayObject vao; + QOpenGLBuffer vertexBuffer; + QOpenGLBuffer texCoordBuffer; + QOpenGLBuffer opacityBuffer; + QOpenGLBuffer indexBuffer; + bool needsSync; bool multisamplingAlwaysEnabled; @@ -326,17 +340,55 @@ public: }; -void QOpenGL2PaintEngineExPrivate::setVertexAttributePointer(unsigned int arrayIndex, const GLfloat *pointer) +void QOpenGL2PaintEngineExPrivate::uploadData(unsigned int arrayIndex, const GLfloat *data, GLuint count) { 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, count * sizeof(float)); + } + if (arrayIndex == QT_TEXTURE_COORDS_ATTR) { + texCoordBuffer.bind(); + texCoordBuffer.allocate(data, count * sizeof(float)); + } + if (arrayIndex == QT_OPACITY_ATTR) { + opacityBuffer.bind(); + opacityBuffer.allocate(data, count * 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); + } +} + +bool QOpenGL2PaintEngineExPrivate::uploadIndexData(const void *data, GLenum indexValueType, GLuint count) +{ + // Follow the uploadData() logic: VBOs are used only when VAO support is available. + // Otherwise the legacy client-side pointer path is used. + if (vao.isCreated()) { + Q_ASSERT(indexValueType == GL_UNSIGNED_SHORT || indexValueType == GL_UNSIGNED_INT); + indexBuffer.bind(); + indexBuffer.allocate(data, count * (indexValueType == GL_UNSIGNED_SHORT ? sizeof(quint16) : sizeof(quint32))); + return true; + } + return false; } QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglprogrambinarycache.cpp b/src/gui/opengl/qopenglprogrambinarycache.cpp new file mode 100644 index 0000000000..06373e1113 --- /dev/null +++ b/src/gui/opengl/qopenglprogrambinarycache.cpp @@ -0,0 +1,376 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopenglprogrambinarycache_p.h" +#include <QOpenGLContext> +#include <QOpenGLExtraFunctions> +#include <QStandardPaths> +#include <QDir> +#include <QSaveFile> +#include <QLoggingCategory> + +#ifdef Q_OS_UNIX +#include <sys/mman.h> +#include <private/qcore_unix_p.h> +#endif + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(DBG_SHADER_CACHE) + +#ifndef GL_PROGRAM_BINARY_LENGTH +#define GL_PROGRAM_BINARY_LENGTH 0x8741 +#endif + +const quint32 BINSHADER_MAGIC = 0x5174; +const quint32 BINSHADER_VERSION = 0x2; +const quint32 BINSHADER_QTVERSION = QT_VERSION; + +struct GLEnvInfo +{ + GLEnvInfo(); + + QByteArray glvendor; + QByteArray glrenderer; + QByteArray glversion; +}; + +GLEnvInfo::GLEnvInfo() +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + Q_ASSERT(ctx); + QOpenGLFunctions *f = ctx->functions(); + const char *vendor = reinterpret_cast<const char *>(f->glGetString(GL_VENDOR)); + const char *renderer = reinterpret_cast<const char *>(f->glGetString(GL_RENDERER)); + const char *version = reinterpret_cast<const char *>(f->glGetString(GL_VERSION)); + if (vendor) + glvendor = QByteArray(vendor); + if (renderer) + glrenderer = QByteArray(renderer); + if (version) + glversion = QByteArray(version); +} + +static inline bool qt_ensureWritableDir(const QString &name) +{ + QDir::root().mkpath(name); + return QFileInfo(name).isWritable(); +} + +QOpenGLProgramBinaryCache::QOpenGLProgramBinaryCache() + : m_cacheWritable(false) +{ + const QString subPath = QLatin1String("/qtshadercache/"); + const QString sharedCachePath = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation); + if (!sharedCachePath.isEmpty()) { + m_cacheDir = sharedCachePath + subPath; + m_cacheWritable = qt_ensureWritableDir(m_cacheDir); + } + if (!m_cacheWritable) { + m_cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + subPath; + m_cacheWritable = qt_ensureWritableDir(m_cacheDir); + } + qCDebug(DBG_SHADER_CACHE, "Cache location '%s' writable = %d", qPrintable(m_cacheDir), m_cacheWritable); +} + +QString QOpenGLProgramBinaryCache::cacheFileName(const QByteArray &cacheKey) const +{ + return m_cacheDir + QString::fromUtf8(cacheKey); +} + +#define BASE_HEADER_SIZE (int(3 * sizeof(quint32))) +#define FULL_HEADER_SIZE(stringsSize) (BASE_HEADER_SIZE + 12 + stringsSize + 8) +#define PADDING_SIZE(fullHeaderSize) (((fullHeaderSize + 3) & ~3) - fullHeaderSize) + +static inline quint32 readUInt(const uchar **p) +{ + quint32 v; + memcpy(&v, *p, sizeof(quint32)); + *p += sizeof(quint32); + return v; +} + +static inline QByteArray readStr(const uchar **p) +{ + quint32 len = readUInt(p); + QByteArray ba = QByteArray::fromRawData(reinterpret_cast<const char *>(*p), len); + *p += len; + return ba; +} + +bool QOpenGLProgramBinaryCache::verifyHeader(const QByteArray &buf) const +{ + if (buf.size() < BASE_HEADER_SIZE) { + qCDebug(DBG_SHADER_CACHE, "Cached size too small"); + return false; + } + const uchar *p = reinterpret_cast<const uchar *>(buf.constData()); + if (readUInt(&p) != BINSHADER_MAGIC) { + qCDebug(DBG_SHADER_CACHE, "Magic does not match"); + return false; + } + if (readUInt(&p) != BINSHADER_VERSION) { + qCDebug(DBG_SHADER_CACHE, "Version does not match"); + return false; + } + if (readUInt(&p) != BINSHADER_QTVERSION) { + qCDebug(DBG_SHADER_CACHE, "Qt version does not match"); + return false; + } + return true; +} + +bool QOpenGLProgramBinaryCache::setProgramBinary(uint programId, uint blobFormat, const void *p, uint blobSize) +{ + QOpenGLExtraFunctions *funcs = QOpenGLContext::currentContext()->extraFunctions(); + while (funcs->glGetError() != GL_NO_ERROR) { } + funcs->glProgramBinary(programId, blobFormat, p, blobSize); + int err = funcs->glGetError(); + qCDebug(DBG_SHADER_CACHE, "Program binary set for program %u, size %d, format 0x%x, err = 0x%x", + programId, blobSize, blobFormat, err); + return err == 0; +} + +#ifdef Q_OS_UNIX +class FdWrapper +{ +public: + FdWrapper(const QString &fn) + : ptr(MAP_FAILED) + { + fd = qt_safe_open(QFile::encodeName(fn).constData(), O_RDONLY); + } + ~FdWrapper() + { + if (ptr != MAP_FAILED) + munmap(ptr, mapSize); + if (fd != -1) + qt_safe_close(fd); + } + bool map() + { + off_t offs = lseek(fd, 0, SEEK_END); + if (offs == (off_t) -1) { + qErrnoWarning(errno, "lseek failed for program binary"); + return false; + } + mapSize = static_cast<size_t>(offs); + ptr = mmap(nullptr, mapSize, PROT_READ, MAP_SHARED, fd, 0); + return ptr != MAP_FAILED; + } + + int fd; + void *ptr; + size_t mapSize; +}; +#endif + +class DeferredFileRemove +{ +public: + DeferredFileRemove(const QString &fn) + : fn(fn), + active(false) + { + } + ~DeferredFileRemove() + { + if (active) + QFile(fn).remove(); + } + void setActive() + { + active = true; + } + + QString fn; + bool active; +}; + +bool QOpenGLProgramBinaryCache::load(const QByteArray &cacheKey, uint programId) +{ + if (m_memCache.contains(cacheKey)) { + const MemCacheEntry *e = m_memCache[cacheKey]; + return setProgramBinary(programId, e->format, e->blob.constData(), e->blob.size()); + } + + QByteArray buf; + const QString fn = cacheFileName(cacheKey); + DeferredFileRemove undertaker(fn); +#ifdef Q_OS_UNIX + FdWrapper fdw(fn); + if (fdw.fd == -1) + return false; + char header[BASE_HEADER_SIZE]; + qint64 bytesRead = qt_safe_read(fdw.fd, header, BASE_HEADER_SIZE); + if (bytesRead == BASE_HEADER_SIZE) + buf = QByteArray::fromRawData(header, BASE_HEADER_SIZE); +#else + QFile f(fn); + if (!f.open(QIODevice::ReadOnly)) + return false; + buf = f.read(BASE_HEADER_SIZE); +#endif + + if (!verifyHeader(buf)) { + undertaker.setActive(); + return false; + } + + const uchar *p; +#ifdef Q_OS_UNIX + if (!fdw.map()) { + undertaker.setActive(); + return false; + } + p = static_cast<const uchar *>(fdw.ptr) + BASE_HEADER_SIZE; +#else + buf = f.readAll(); + p = reinterpret_cast<const uchar *>(buf.constData()); +#endif + + GLEnvInfo info; + + QByteArray vendor = readStr(&p); + if (vendor != info.glvendor) { + // readStr returns non-null terminated strings just pointing to inside + // 'p' so must print these via the stream qCDebug and not constData(). + qCDebug(DBG_SHADER_CACHE) << "GL_VENDOR does not match" << vendor << info.glvendor; + undertaker.setActive(); + return false; + } + QByteArray renderer = readStr(&p); + if (renderer != info.glrenderer) { + qCDebug(DBG_SHADER_CACHE) << "GL_RENDERER does not match" << renderer << info.glrenderer; + undertaker.setActive(); + return false; + } + QByteArray version = readStr(&p); + if (version != info.glversion) { + qCDebug(DBG_SHADER_CACHE) << "GL_VERSION does not match" << version << info.glversion; + undertaker.setActive(); + return false; + } + + quint32 blobFormat = readUInt(&p); + quint32 blobSize = readUInt(&p); + + p += PADDING_SIZE(FULL_HEADER_SIZE(vendor.size() + renderer.size() + version.size())); + + return setProgramBinary(programId, blobFormat, p, blobSize) + && m_memCache.insert(cacheKey, new MemCacheEntry(p, blobSize, blobFormat)); +} + +static inline void writeUInt(uchar **p, quint32 value) +{ + memcpy(*p, &value, sizeof(quint32)); + *p += sizeof(quint32); +} + +static inline void writeStr(uchar **p, const QByteArray &str) +{ + writeUInt(p, str.size()); + memcpy(*p, str.constData(), str.size()); + *p += str.size(); +} + +void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId) +{ + if (!m_cacheWritable) + return; + + GLEnvInfo info; + + QOpenGLExtraFunctions *funcs = QOpenGLContext::currentContext()->extraFunctions(); + GLint blobSize = 0; + while (funcs->glGetError() != GL_NO_ERROR) { } + funcs->glGetProgramiv(programId, GL_PROGRAM_BINARY_LENGTH, &blobSize); + + const int headerSize = FULL_HEADER_SIZE(info.glvendor.size() + info.glrenderer.size() + info.glversion.size()); + + // Add padding to make the blob start 4-byte aligned in order to support + // OpenGL implementations on ARM that choke on non-aligned pointers passed + // to glProgramBinary. + const int paddingSize = PADDING_SIZE(headerSize); + + const int totalSize = headerSize + paddingSize + blobSize; + + qCDebug(DBG_SHADER_CACHE, "Program binary is %d bytes, err = 0x%x, total %d", blobSize, funcs->glGetError(), totalSize); + if (!blobSize) + return; + + QByteArray blob(totalSize, Qt::Uninitialized); + uchar *p = reinterpret_cast<uchar *>(blob.data()); + + writeUInt(&p, BINSHADER_MAGIC); + writeUInt(&p, BINSHADER_VERSION); + writeUInt(&p, BINSHADER_QTVERSION); + + writeStr(&p, info.glvendor); + writeStr(&p, info.glrenderer); + writeStr(&p, info.glversion); + + quint32 blobFormat = 0; + uchar *blobFormatPtr = p; + writeUInt(&p, blobFormat); + writeUInt(&p, blobSize); + + for (int i = 0; i < paddingSize; ++i) + *p++ = 0; + + GLint outSize = 0; + funcs->glGetProgramBinary(programId, blobSize, &outSize, &blobFormat, p); + if (blobSize != outSize) { + qCDebug(DBG_SHADER_CACHE, "glGetProgramBinary returned size %d instead of %d", outSize, blobSize); + return; + } + + writeUInt(&blobFormatPtr, blobFormat); + + QSaveFile f(cacheFileName(cacheKey)); + if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + f.write(blob); + if (!f.commit()) + qCDebug(DBG_SHADER_CACHE, "Failed to write %s to shader cache", qPrintable(f.fileName())); + } else { + qCDebug(DBG_SHADER_CACHE, "Failed to create %s in shader cache", qPrintable(f.fileName())); + } +} + +QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglprogrambinarycache_p.h b/src/gui/opengl/qopenglprogrambinarycache_p.h new file mode 100644 index 0000000000..a0e1f91e25 --- /dev/null +++ b/src/gui/opengl/qopenglprogrambinarycache_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENGLPROGRAMBINARYCACHE_P_H +#define QOPENGLPROGRAMBINARYCACHE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtGui/qtguiglobal.h> +#include <QtGui/qopenglshaderprogram.h> +#include <QtCore/qcache.h> + +QT_BEGIN_NAMESPACE + +class QOpenGLProgramBinaryCache +{ +public: + struct ShaderDesc { + ShaderDesc() { } + ShaderDesc(QOpenGLShader::ShaderType type, const QByteArray &source = QByteArray()) + : type(type), source(source) + { } + QOpenGLShader::ShaderType type; + QByteArray source; + }; + struct ProgramDesc { + QVector<ShaderDesc> shaders; + }; + + QOpenGLProgramBinaryCache(); + + bool load(const QByteArray &cacheKey, uint programId); + void save(const QByteArray &cacheKey, uint programId); + +private: + QString cacheFileName(const QByteArray &cacheKey) const; + bool verifyHeader(const QByteArray &buf) const; + bool setProgramBinary(uint programId, uint blobFormat, const void *p, uint blobSize); + + QString m_cacheDir; + bool m_cacheWritable; + struct MemCacheEntry { + MemCacheEntry(const void *p, int size, uint format) + : blob(reinterpret_cast<const char *>(p), size), + format(format) + { } + QByteArray blob; + uint format; + }; + QCache<QByteArray, MemCacheEntry> m_memCache; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp index cd582c5285..c9552fd321 100644 --- a/src/gui/opengl/qopenglshaderprogram.cpp +++ b/src/gui/opengl/qopenglshaderprogram.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qopenglshaderprogram.h" +#include "qopenglprogrambinarycache_p.h" #include "qopenglfunctions.h" #include "private/qopenglcontext_p.h" #include <QtCore/private/qobject_p.h> @@ -46,6 +47,9 @@ #include <QtCore/qvarlengtharray.h> #include <QtCore/qvector.h> #include <QtCore/qregularexpression.h> +#include <QtCore/qloggingcategory.h> +#include <QtCore/qcryptographichash.h> +#include <QtCore/qcoreapplication.h> #include <QtGui/qtransform.h> #include <QtGui/QColor> #include <QtGui/QSurfaceFormat> @@ -127,6 +131,20 @@ QT_BEGIN_NAMESPACE on the shader program. The shader program's id can be explicitly created using the create() function. + \section2 Caching Program Binaries + + As of Qt 5.9, support for caching program binaries on disk is built in. To + enable this, switch to using addCacheableShaderFromSourceCode() and + addCacheableShaderFromSourceFile(). With an OpenGL ES 3.x context or support + for \c{GL_ARB_get_program_binary}, this will transparently cache program + binaries under QStandardPaths::GenericCacheLocation or + QStandardPaths::CacheLocation. When support is not available, calling the + cacheable function variants is equivalent to the normal ones. + + \note Some drivers do not have any binary formats available, even though + they advertise the extension or offer OpenGL ES 3.0. In this case program + binary support will be disabled. + \sa QOpenGLShader */ @@ -162,6 +180,84 @@ QT_BEGIN_NAMESPACE based on the core feature (requires OpenGL >= 4.3). */ +Q_LOGGING_CATEGORY(DBG_SHADER_CACHE, "qt.opengl.diskcache") + +// For GLES 3.1/3.2 +#ifndef GL_GEOMETRY_SHADER +#define GL_GEOMETRY_SHADER 0x8DD9 +#endif +#ifndef GL_TESS_CONTROL_SHADER +#define GL_TESS_CONTROL_SHADER 0x8E88 +#endif +#ifndef GL_TESS_EVALUATION_SHADER +#define GL_TESS_EVALUATION_SHADER 0x8E87 +#endif +#ifndef GL_COMPUTE_SHADER +#define GL_COMPUTE_SHADER 0x91B9 +#endif +#ifndef GL_MAX_GEOMETRY_OUTPUT_VERTICES +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#endif +#ifndef GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 +#endif +#ifndef GL_PATCH_VERTICES +#define GL_PATCH_VERTICES 0x8E72 +#endif +#ifndef GL_PATCH_DEFAULT_OUTER_LEVEL +#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 +#endif +#ifndef GL_PATCH_DEFAULT_INNER_LEVEL +#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 +#endif + +#ifndef GL_NUM_PROGRAM_BINARY_FORMATS +#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE +#endif + +static inline bool isFormatGLES(const QSurfaceFormat &f) +{ + return (f.renderableType() == QSurfaceFormat::OpenGLES); +} + +static inline bool supportsGeometry(const QSurfaceFormat &f) +{ +#ifndef QT_OPENGL_ES_2 + if (!isFormatGLES(f)) + return (f.version() >= qMakePair<int, int>(3, 2)); + else + return false; +#else + Q_UNUSED(f); + return false; +#endif +} + +static inline bool supportsCompute(const QSurfaceFormat &f) +{ +#ifndef QT_OPENGL_ES_2 + if (!isFormatGLES(f)) + return (f.version() >= qMakePair<int, int>(4, 3)); + else + return (f.version() >= qMakePair<int, int>(3, 1)); +#else + return (f.version() >= qMakePair<int, int>(3, 1)); +#endif +} + +static inline bool supportsTessellation(const QSurfaceFormat &f) +{ +#ifndef QT_OPENGL_ES_2 + if (!isFormatGLES(f)) + return (f.version() >= qMakePair<int, int>(4, 0)); + else + return false; +#else + Q_UNUSED(f); + return false; +#endif +} + class QOpenGLShaderPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QOpenGLShader) @@ -171,22 +267,16 @@ public: , shaderType(type) , compiled(false) , glfuncs(new QOpenGLFunctions(ctx)) -#ifndef QT_OPENGL_ES_2 , supportsGeometryShaders(false) , supportsTessellationShaders(false) -#endif + , supportsComputeShaders(false) { -#ifndef QT_OPENGL_ES_2 - if (!ctx->isOpenGLES()) { - QSurfaceFormat f = ctx->format(); - - // Geometry shaders require OpenGL >= 3.2 - if (shaderType & QOpenGLShader::Geometry) - supportsGeometryShaders = (f.version() >= qMakePair<int, int>(3, 2)); - else if (shaderType & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation)) - supportsTessellationShaders = (f.version() >= qMakePair<int, int>(4, 0)); - } -#endif + if (shaderType & QOpenGLShader::Geometry) + supportsGeometryShaders = supportsGeometry(ctx->format()); + else if (shaderType & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation)) + supportsTessellationShaders = supportsTessellation(ctx->format()); + else if (shaderType & QOpenGLShader::Compute) + supportsComputeShaders = supportsCompute(ctx->format()); } ~QOpenGLShaderPrivate(); @@ -197,13 +287,13 @@ public: QOpenGLFunctions *glfuncs; -#ifndef QT_OPENGL_ES_2 // Support for geometry shaders bool supportsGeometryShaders; - // Support for tessellation shaders bool supportsTessellationShaders; -#endif + // Support for compute shaders + bool supportsComputeShaders; + bool create(); bool compile(QOpenGLShader *q); @@ -229,24 +319,18 @@ bool QOpenGLShaderPrivate::create() QOpenGLContext *context = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext()); if (!context) return false; - GLuint shader; + GLuint shader = 0; if (shaderType == QOpenGLShader::Vertex) { shader = glfuncs->glCreateShader(GL_VERTEX_SHADER); -#if defined(QT_OPENGL_3_2) } else if (shaderType == QOpenGLShader::Geometry && supportsGeometryShaders) { shader = glfuncs->glCreateShader(GL_GEOMETRY_SHADER); -#endif -#if defined(QT_OPENGL_4) } else if (shaderType == QOpenGLShader::TessellationControl && supportsTessellationShaders) { shader = glfuncs->glCreateShader(GL_TESS_CONTROL_SHADER); } else if (shaderType == QOpenGLShader::TessellationEvaluation && supportsTessellationShaders) { shader = glfuncs->glCreateShader(GL_TESS_EVALUATION_SHADER); -#endif -#if defined(QT_OPENGL_4_3) - } else if (shaderType == QOpenGLShader::Compute) { + } else if (shaderType == QOpenGLShader::Compute && supportsComputeShaders) { shader = glfuncs->glCreateShader(GL_COMPUTE_SHADER); -#endif - } else { + } else if (shaderType == QOpenGLShader::Fragment) { shader = glfuncs->glCreateShader(GL_FRAGMENT_SHADER); } if (!shader) { @@ -710,6 +794,7 @@ public: #ifndef QT_OPENGL_ES_2 , tessellationFuncs(0) #endif + , linkBinaryRecursion(false) { } ~QOpenGLShaderProgramPrivate(); @@ -731,6 +816,13 @@ public: #endif bool hasShader(QOpenGLShader::ShaderType type) const; + + QOpenGLProgramBinaryCache::ProgramDesc binaryProgram; + bool isCacheDisabled() const; + bool compileCacheable(); + bool linkBinary(); + + bool linkBinaryRecursion; }; namespace { @@ -962,6 +1054,139 @@ bool QOpenGLShaderProgram::addShaderFromSourceFile } /*! + Registers the shader of the specified \a type and \a source to this + program. Unlike addShaderFromSourceCode(), this function does not perform + compilation. Compilation is deferred to link(), and may not happen at all, + because link() may potentially use a program binary from Qt's shader disk + cache. This will typically lead to a significant increase in performance. + + \return true if the shader has been registered or, in the non-cached case, + compiled successfully; false if there was an error. The compilation error + messages can be retrieved via log(). + + When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for + example, or the OpenGL context has no support for context binaries, calling + this function is equivalent to addShaderFromSourceCode(). + + \since 5.9 + \sa addShaderFromSourceCode(), addCacheableShaderFromSourceFile() + */ +bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const char *source) +{ + Q_D(QOpenGLShaderProgram); + if (!init()) + return false; + if (d->isCacheDisabled()) + return addShaderFromSourceCode(type, source); + + return addCacheableShaderFromSourceCode(type, QByteArray(source)); +} + +/*! + \overload + + Registers the shader of the specified \a type and \a source to this + program. Unlike addShaderFromSourceCode(), this function does not perform + compilation. Compilation is deferred to link(), and may not happen at all, + because link() may potentially use a program binary from Qt's shader disk + cache. This will typically lead to a significant increase in performance. + + \return true if the shader has been registered or, in the non-cached case, + compiled successfully; false if there was an error. The compilation error + messages can be retrieved via log(). + + When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for + example, or the OpenGL context has no support for context binaries, calling + this function is equivalent to addShaderFromSourceCode(). + + \since 5.9 + \sa addShaderFromSourceCode(), addCacheableShaderFromSourceFile() + */ +bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const QByteArray &source) +{ + Q_D(QOpenGLShaderProgram); + if (!init()) + return false; + if (d->isCacheDisabled()) + return addShaderFromSourceCode(type, source); + + d->binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(type, source)); + return true; +} + +/*! + \overload + + Registers the shader of the specified \a type and \a source to this + program. Unlike addShaderFromSourceCode(), this function does not perform + compilation. Compilation is deferred to link(), and may not happen at all, + because link() may potentially use a program binary from Qt's shader disk + cache. This will typically lead to a significant increase in performance. + + When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for + example, or the OpenGL context has no support for context binaries, calling + this function is equivalent to addShaderFromSourceCode(). + + \since 5.9 + \sa addShaderFromSourceCode(), addCacheableShaderFromSourceFile() + */ +bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const QString &source) +{ + Q_D(QOpenGLShaderProgram); + if (!init()) + return false; + if (d->isCacheDisabled()) + return addShaderFromSourceCode(type, source); + + return addCacheableShaderFromSourceCode(type, source.toUtf8().constData()); +} + +/*! + Registers the shader of the specified \a type and \a fileName to this + program. Unlike addShaderFromSourceFile(), this function does not perform + compilation. Compilation is deferred to link(), and may not happen at all, + because link() may potentially use a program binary from Qt's shader disk + cache. This will typically lead to a significant increase in performance. + + \return true if the file has been read successfully, false if the file could + not be opened or the normal, non-cached compilation of the shader has + failed. The compilation error messages can be retrieved via log(). + + When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for + example, or the OpenGL context has no support for context binaries, calling + this function is equivalent to addShaderFromSourceFile(). + + \since 5.9 + \sa addShaderFromSourceFile(), addCacheableShaderFromSourceCode() + */ +bool QOpenGLShaderProgram::addCacheableShaderFromSourceFile(QOpenGLShader::ShaderType type, const QString &fileName) +{ + Q_D(QOpenGLShaderProgram); + if (!init()) + return false; + if (d->isCacheDisabled()) + return addShaderFromSourceFile(type, fileName); + + QOpenGLProgramBinaryCache::ShaderDesc shader(type); + // NB! It could be tempting to defer reading the file contents and just + // hash the filename as the cache key, perhaps combined with last-modified + // timestamp checks. However, this would raise a number of issues (no + // timestamps for files in the resource system; preference for global, not + // per-application cache items (where filenames may clash); resource-based + // shaders from libraries like Qt Quick; etc.), so just avoid it. + QFile f(fileName); + if (f.open(QIODevice::ReadOnly | QIODevice::Text)) { + shader.source = f.readAll(); + f.close(); + } else { + qWarning("QOpenGLShaderProgram: Unable to open file %s", qPrintable(fileName)); + return false; + } + d->binaryProgram.shaders.append(shader); + return true; +} + +/*! Removes \a shader from this shader program. The object is not deleted. The shader program must be valid in the current QOpenGLContext. @@ -1019,6 +1244,7 @@ void QOpenGLShaderProgram::removeAllShaders() qDeleteAll(d->anonShaders); d->shaders.clear(); d->anonShaders.clear(); + d->binaryProgram = QOpenGLProgramBinaryCache::ProgramDesc(); d->linked = false; // Program needs to be relinked. d->removingShaders = false; } @@ -1035,6 +1261,16 @@ void QOpenGLShaderProgram::removeAllShaders() If the shader program was already linked, calling this function again will force it to be re-linked. + When shaders were added to this program via + addCacheableShaderFromSourceCode() or addCacheableShaderFromSourceFile(), + program binaries are supported, and a cached binary is available on disk, + actual compilation and linking are skipped. Instead, link() will initialize + the program with the binary blob via glProgramBinary(). If there is no + cached version of the program or it was generated with a different driver + version, the shaders will be compiled from source and the program will get + linked normally. This allows seamless upgrading of the graphics drivers, + without having to worry about potentially incompatible binary formats. + \sa addShader(), log() */ bool QOpenGLShaderProgram::link() @@ -1044,12 +1280,17 @@ bool QOpenGLShaderProgram::link() if (!program) return false; + if (!d->linkBinaryRecursion && d->shaders.isEmpty() && !d->binaryProgram.shaders.isEmpty()) + return d->linkBinary(); + GLint value; if (d->shaders.isEmpty()) { // If there are no explicit shaders, then it is possible that the - // application added a program binary with glProgramBinaryOES(), - // or otherwise populated the shaders itself. Check to see if the - // program is already linked and bail out if so. + // application added a program binary with glProgramBinaryOES(), or + // otherwise populated the shaders itself. This is also the case when + // we are recursively called back from linkBinary() after a successful + // glProgramBinary(). Check to see if the program is already linked and + // bail out if so. value = 0; d->glfuncs->glGetProgramiv(program, GL_LINK_STATUS, &value); d->linked = (value != 0); @@ -1069,7 +1310,7 @@ bool QOpenGLShaderProgram::link() GLint len; d->glfuncs->glGetProgramInfoLog(program, value, &len, logbuf); d->log = QString::fromLatin1(logbuf); - if (!d->linked) { + if (!d->linked && !d->linkBinaryRecursion) { QString name = objectName(); if (name.isEmpty()) qWarning("QOpenGLShader::link: %ls", qUtf16Printable(d->log)); @@ -3230,10 +3471,8 @@ void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4 int QOpenGLShaderProgram::maxGeometryOutputVertices() const { GLint n = 0; -#if defined(QT_OPENGL_3_2) Q_D(const QOpenGLShaderProgram); d->glfuncs->glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &n); -#endif return n; } @@ -3257,7 +3496,7 @@ int QOpenGLShaderProgram::maxGeometryOutputVertices() const */ void QOpenGLShaderProgram::setPatchVertexCount(int count) { -#if defined(QT_OPENGL_4) +#ifndef QT_OPENGL_ES_2 Q_D(QOpenGLShaderProgram); if (d->tessellationFuncs) d->tessellationFuncs->glPatchParameteri(GL_PATCH_VERTICES, count); @@ -3276,13 +3515,15 @@ void QOpenGLShaderProgram::setPatchVertexCount(int count) */ int QOpenGLShaderProgram::patchVertexCount() const { +#ifndef QT_OPENGL_ES_2 int patchVertices = 0; -#if defined(QT_OPENGL_4) Q_D(const QOpenGLShaderProgram); if (d->tessellationFuncs) d->tessellationFuncs->glGetIntegerv(GL_PATCH_VERTICES, &patchVertices); -#endif return patchVertices; +#else + return 0; +#endif } /*! @@ -3304,21 +3545,21 @@ int QOpenGLShaderProgram::patchVertexCount() const */ void QOpenGLShaderProgram::setDefaultOuterTessellationLevels(const QVector<float> &levels) { -#if defined(QT_OPENGL_4) - QVector<float> tessLevels = levels; - - // Ensure we have the required 4 outer tessellation levels - // Use default of 1 for missing entries (same as spec) - const int argCount = 4; - if (tessLevels.size() < argCount) { - tessLevels.reserve(argCount); - for (int i = tessLevels.size(); i < argCount; ++i) - tessLevels.append(1.0f); - } - +#ifndef QT_OPENGL_ES_2 Q_D(QOpenGLShaderProgram); - if (d->tessellationFuncs) + if (d->tessellationFuncs) { + QVector<float> tessLevels = levels; + + // Ensure we have the required 4 outer tessellation levels + // Use default of 1 for missing entries (same as spec) + const int argCount = 4; + if (tessLevels.size() < argCount) { + tessLevels.reserve(argCount); + for (int i = tessLevels.size(); i < argCount; ++i) + tessLevels.append(1.0f); + } d->tessellationFuncs->glPatchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, tessLevels.data()); + } #else Q_UNUSED(levels); #endif @@ -3341,13 +3582,15 @@ void QOpenGLShaderProgram::setDefaultOuterTessellationLevels(const QVector<float */ QVector<float> QOpenGLShaderProgram::defaultOuterTessellationLevels() const { +#ifndef QT_OPENGL_ES_2 QVector<float> tessLevels(4, 1.0f); -#if defined(QT_OPENGL_4) Q_D(const QOpenGLShaderProgram); if (d->tessellationFuncs) d->tessellationFuncs->glGetFloatv(GL_PATCH_DEFAULT_OUTER_LEVEL, tessLevels.data()); -#endif return tessLevels; +#else + return QVector<float>(); +#endif } /*! @@ -3369,21 +3612,21 @@ QVector<float> QOpenGLShaderProgram::defaultOuterTessellationLevels() const */ void QOpenGLShaderProgram::setDefaultInnerTessellationLevels(const QVector<float> &levels) { -#if defined(QT_OPENGL_4) - QVector<float> tessLevels = levels; - - // Ensure we have the required 2 inner tessellation levels - // Use default of 1 for missing entries (same as spec) - const int argCount = 2; - if (tessLevels.size() < argCount) { - tessLevels.reserve(argCount); - for (int i = tessLevels.size(); i < argCount; ++i) - tessLevels.append(1.0f); - } - +#ifndef QT_OPENGL_ES_2 Q_D(QOpenGLShaderProgram); - if (d->tessellationFuncs) + if (d->tessellationFuncs) { + QVector<float> tessLevels = levels; + + // Ensure we have the required 2 inner tessellation levels + // Use default of 1 for missing entries (same as spec) + const int argCount = 2; + if (tessLevels.size() < argCount) { + tessLevels.reserve(argCount); + for (int i = tessLevels.size(); i < argCount; ++i) + tessLevels.append(1.0f); + } d->tessellationFuncs->glPatchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, tessLevels.data()); + } #else Q_UNUSED(levels); #endif @@ -3406,13 +3649,15 @@ void QOpenGLShaderProgram::setDefaultInnerTessellationLevels(const QVector<float */ QVector<float> QOpenGLShaderProgram::defaultInnerTessellationLevels() const { +#ifndef QT_OPENGL_ES_2 QVector<float> tessLevels(2, 1.0f); -#if defined(QT_OPENGL_4) Q_D(const QOpenGLShaderProgram); if (d->tessellationFuncs) d->tessellationFuncs->glGetFloatv(GL_PATCH_DEFAULT_INNER_LEVEL, tessLevels.data()); -#endif return tessLevels; +#else + return QVector<float>(); +#endif } @@ -3425,16 +3670,11 @@ QVector<float> QOpenGLShaderProgram::defaultInnerTessellationLevels() const */ bool QOpenGLShaderProgram::hasOpenGLShaderPrograms(QOpenGLContext *context) { -#if !defined(QT_OPENGL_ES_2) if (!context) context = QOpenGLContext::currentContext(); if (!context) return false; return QOpenGLFunctions(context).hasOpenGLFeature(QOpenGLFunctions::Shaders); -#else - Q_UNUSED(context); - return true; -#endif } /*! @@ -3465,37 +3705,148 @@ bool QOpenGLShader::hasOpenGLShaders(ShaderType type, QOpenGLContext *context) if ((type & ~(Geometry | Vertex | Fragment | TessellationControl | TessellationEvaluation | Compute)) || type == 0) return false; - QSurfaceFormat format = context->format(); - if (type == Geometry) { -#ifndef QT_OPENGL_ES_2 - // Geometry shaders require OpenGL 3.2 or newer - QSurfaceFormat format = context->format(); - return (!context->isOpenGLES()) - && (format.version() >= qMakePair<int, int>(3, 2)); -#else - // No geometry shader support in OpenGL ES2 - return false; -#endif - } else if (type == TessellationControl || type == TessellationEvaluation) { -#if !defined(QT_OPENGL_ES_2) - return (!context->isOpenGLES()) - && (format.version() >= qMakePair<int, int>(4, 0)); -#else - // No tessellation shader support in OpenGL ES2 - return false; -#endif - } else if (type == Compute) { -#if defined(QT_OPENGL_4_3) - return (format.version() >= qMakePair<int, int>(4, 3)); -#else - // No compute shader support without OpenGL 4.3 or newer - return false; -#endif - } + if (type & QOpenGLShader::Geometry) + return supportsGeometry(context->format()); + else if (type & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation)) + return supportsTessellation(context->format()); + else if (type & QOpenGLShader::Compute) + return supportsCompute(context->format()); // Unconditional support of vertex and fragment shaders implicitly assumes // a minimum OpenGL version of 2.0 return true; } +// While unlikely, one application can in theory use contexts with different versions +// or profiles. Therefore any version- or extension-specific checks must be done on a +// per-context basis, not just once per process. QOpenGLSharedResource enables this, +// although it's once-per-sharing-context-group, not per-context. Still, this should +// be good enough in practice. +class QOpenGLProgramBinarySupportCheck : public QOpenGLSharedResource +{ +public: + QOpenGLProgramBinarySupportCheck(QOpenGLContext *context); + void invalidateResource() override { } + void freeResource(QOpenGLContext *) override { } + + bool isSupported() const { return m_supported; } + +private: + bool m_supported; +}; + +QOpenGLProgramBinarySupportCheck::QOpenGLProgramBinarySupportCheck(QOpenGLContext *context) + : QOpenGLSharedResource(context->shareGroup()), + m_supported(false) +{ + if (QCoreApplication::testAttribute(Qt::AA_DisableShaderDiskCache)) { + qCDebug(DBG_SHADER_CACHE, "Shader cache disabled via app attribute"); + return; + } + if (qEnvironmentVariableIntValue("QT_DISABLE_SHADER_DISK_CACHE")) { + qCDebug(DBG_SHADER_CACHE, "Shader cache disabled via env var"); + return; + } + + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (ctx) { + if (ctx->isOpenGLES()) { + qCDebug(DBG_SHADER_CACHE, "OpenGL ES v%d context", ctx->format().majorVersion()); + if (ctx->format().majorVersion() >= 3) + m_supported = true; + } else { + const bool hasExt = ctx->hasExtension("GL_ARB_get_program_binary"); + qCDebug(DBG_SHADER_CACHE, "GL_ARB_get_program_binary support = %d", hasExt); + if (hasExt) + m_supported = true; + } + if (m_supported) { + GLint fmtCount = 0; + ctx->functions()->glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &fmtCount); + qCDebug(DBG_SHADER_CACHE, "Supported binary format count = %d", fmtCount); + m_supported = fmtCount > 0; + } + } + qCDebug(DBG_SHADER_CACHE, "Shader cache supported = %d", m_supported); +} + +class QOpenGLProgramBinarySupportCheckWrapper +{ +public: + QOpenGLProgramBinarySupportCheck *get(QOpenGLContext *context) + { + return m_resource.value<QOpenGLProgramBinarySupportCheck>(context); + } + +private: + QOpenGLMultiGroupSharedResource m_resource; +}; + +bool QOpenGLShaderProgramPrivate::isCacheDisabled() const +{ + static QOpenGLProgramBinarySupportCheckWrapper binSupportCheck; + return !binSupportCheck.get(QOpenGLContext::currentContext())->isSupported(); +} + +bool QOpenGLShaderProgramPrivate::compileCacheable() +{ + Q_Q(QOpenGLShaderProgram); + for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : qAsConst(binaryProgram.shaders)) { + QScopedPointer<QOpenGLShader> s(new QOpenGLShader(shader.type, q)); + if (!s->compileSourceCode(shader.source)) { + log = s->log(); + return false; + } + anonShaders.append(s.take()); + if (!q->addShader(anonShaders.last())) + return false; + } + return true; +} + +bool QOpenGLShaderProgramPrivate::linkBinary() +{ + static QOpenGLProgramBinaryCache binCache; + + Q_Q(QOpenGLShaderProgram); + + QCryptographicHash keyBuilder(QCryptographicHash::Sha1); + for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : qAsConst(binaryProgram.shaders)) + keyBuilder.addData(shader.source); + + const QByteArray cacheKey = keyBuilder.result().toHex(); + if (DBG_SHADER_CACHE().isEnabled(QtDebugMsg)) + qCDebug(DBG_SHADER_CACHE, "program with %d shaders, cache key %s", + binaryProgram.shaders.count(), cacheKey.constData()); + + bool needsCompile = true; + if (binCache.load(cacheKey, q->programId())) { + qCDebug(DBG_SHADER_CACHE, "Program binary received from cache"); + linkBinaryRecursion = true; + bool ok = q->link(); + linkBinaryRecursion = false; + if (ok) + needsCompile = false; + else + qCDebug(DBG_SHADER_CACHE, "Link failed after glProgramBinary"); + } + + bool needsSave = false; + if (needsCompile) { + qCDebug(DBG_SHADER_CACHE, "Program binary not in cache, compiling"); + if (compileCacheable()) + needsSave = true; + else + return false; + } + + linkBinaryRecursion = true; + bool ok = q->link(); + linkBinaryRecursion = false; + if (ok && needsSave) + binCache.save(cacheKey, q->programId()); + + return ok; +} + QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglshaderprogram.h b/src/gui/opengl/qopenglshaderprogram.h index 2da359c535..fd4d82ecf9 100644 --- a/src/gui/opengl/qopenglshaderprogram.h +++ b/src/gui/opengl/qopenglshaderprogram.h @@ -50,6 +50,13 @@ #include <QtGui/qvector4d.h> #include <QtGui/qmatrix4x4.h> +#if defined(Q_CLANG_QDOC) +#undef GLint +typedef int GLint; +#undef GLfloat +typedef double GLfloat; +#endif + QT_BEGIN_NAMESPACE @@ -119,6 +126,11 @@ public: bool addShaderFromSourceCode(QOpenGLShader::ShaderType type, const QString& source); bool addShaderFromSourceFile(QOpenGLShader::ShaderType type, const QString& fileName); + bool addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const char *source); + bool addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const QByteArray &source); + bool addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const QString &source); + bool addCacheableShaderFromSourceFile(QOpenGLShader::ShaderType type, const QString &fileName); + void removeAllShaders(); virtual bool link(); diff --git a/src/gui/opengl/qopengltexture.cpp b/src/gui/opengl/qopengltexture.cpp index c9b08f60b1..3696378bd1 100644 --- a/src/gui/opengl/qopengltexture.cpp +++ b/src/gui/opengl/qopengltexture.cpp @@ -1351,7 +1351,7 @@ void QOpenGLTexturePrivate::allocateImmutableStorage() storageAllocated = true; } -void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::CubeMapFace cubeFace, +void QOpenGLTexturePrivate::setData(int mipLevel, int layer, int layerCount, QOpenGLTexture::CubeMapFace cubeFace, QOpenGLTexture::PixelFormat sourceFormat, QOpenGLTexture::PixelType sourceType, const void *data, const QOpenGLPixelTransferOptions * const options) { @@ -1359,6 +1359,7 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub case QOpenGLTexture::Target1D: Q_UNUSED(layer); Q_UNUSED(cubeFace); + Q_UNUSED(layerCount); texFuncs->glTextureSubImage1D(textureId, target, bindingTarget, mipLevel, 0, mipLevelSize( mipLevel, dimensions[0] ), sourceFormat, sourceType, data, options); @@ -1369,13 +1370,14 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub texFuncs->glTextureSubImage2D(textureId, target, bindingTarget, mipLevel, 0, layer, mipLevelSize(mipLevel, dimensions[0]), - 1, + layerCount, sourceFormat, sourceType, data, options); break; case QOpenGLTexture::Target2D: Q_UNUSED(layer); Q_UNUSED(cubeFace); + Q_UNUSED(layerCount); texFuncs->glTextureSubImage2D(textureId, target, bindingTarget, mipLevel, 0, 0, mipLevelSize(mipLevel, dimensions[0]), @@ -1389,12 +1391,13 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub 0, 0, layer, mipLevelSize(mipLevel, dimensions[0]), mipLevelSize(mipLevel, dimensions[1]), - 1, + layerCount, sourceFormat, sourceType, data, options); break; case QOpenGLTexture::Target3D: Q_UNUSED(cubeFace); + Q_UNUSED(layerCount); texFuncs->glTextureSubImage3D(textureId, target, bindingTarget, mipLevel, 0, 0, layer, mipLevelSize(mipLevel, dimensions[0]), @@ -1405,6 +1408,7 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub case QOpenGLTexture::TargetCubeMap: Q_UNUSED(layer); + Q_UNUSED(layerCount); texFuncs->glTextureSubImage2D(textureId, cubeFace, bindingTarget, mipLevel, 0, 0, mipLevelSize(mipLevel, dimensions[0]), @@ -1419,7 +1423,7 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub 0, 0, layerFace, mipLevelSize(mipLevel, dimensions[0]), mipLevelSize(mipLevel, dimensions[1]), - 1, + layerCount, sourceFormat, sourceType, data, options); break; } @@ -1428,6 +1432,7 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub Q_UNUSED(mipLevel); Q_UNUSED(layer); Q_UNUSED(cubeFace); + Q_UNUSED(layerCount); texFuncs->glTextureSubImage2D(textureId, target, bindingTarget, 0, 0, 0, dimensions[0], @@ -1450,7 +1455,8 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub } } -void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTexture::CubeMapFace cubeFace, +void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, int layerCount, + QOpenGLTexture::CubeMapFace cubeFace, int dataSize, const void *data, const QOpenGLPixelTransferOptions * const options) { @@ -1465,6 +1471,7 @@ void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTe case QOpenGLTexture::Target1D: Q_UNUSED(layer); Q_UNUSED(cubeFace); + Q_UNUSED(layerCount); if (needsFullSpec) { texFuncs->glCompressedTextureImage1D(textureId, target, bindingTarget, mipLevel, format, @@ -1483,7 +1490,7 @@ void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTe texFuncs->glCompressedTextureSubImage2D(textureId, target, bindingTarget, mipLevel, 0, layer, mipLevelSize(mipLevel, dimensions[0]), - 1, + layerCount, format, dataSize, data, options); } break; @@ -1491,6 +1498,7 @@ void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTe case QOpenGLTexture::Target2D: Q_UNUSED(layer); Q_UNUSED(cubeFace); + Q_UNUSED(layerCount); if (needsFullSpec) { texFuncs->glCompressedTextureImage2D(textureId, target, bindingTarget, mipLevel, format, @@ -1513,13 +1521,14 @@ void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTe 0, 0, layer, mipLevelSize(mipLevel, dimensions[0]), mipLevelSize(mipLevel, dimensions[1]), - 1, + layerCount, format, dataSize, data, options); } break; case QOpenGLTexture::Target3D: Q_UNUSED(cubeFace); + Q_UNUSED(layerCount); if (needsFullSpec) { texFuncs->glCompressedTextureImage3D(textureId, target, bindingTarget, mipLevel, format, @@ -1539,6 +1548,7 @@ void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTe case QOpenGLTexture::TargetCubeMap: Q_UNUSED(layer); + Q_UNUSED(layerCount); if (needsFullSpec) { texFuncs->glCompressedTextureImage2D(textureId, cubeFace, bindingTarget, mipLevel, format, @@ -1562,7 +1572,7 @@ void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTe 0, 0, layerFace, mipLevelSize(mipLevel, dimensions[0]), mipLevelSize(mipLevel, dimensions[1]), - 1, + layerCount, format, dataSize, data, options); } break; @@ -3286,7 +3296,23 @@ void QOpenGLTexture::setData(int mipLevel, int layer, CubeMapFace cubeFace, "To do so call allocateStorage() before this function"); return; } - d->setData(mipLevel, layer, cubeFace, sourceFormat, sourceType, data, options); + d->setData(mipLevel, layer, 1, cubeFace, sourceFormat, sourceType, data, options); +} + +/*! + \since 5.9 + \overload +*/ +void QOpenGLTexture::setData(int mipLevel, int layer, int layerCount, QOpenGLTexture::CubeMapFace cubeFace, QOpenGLTexture::PixelFormat sourceFormat, QOpenGLTexture::PixelType sourceType, const void *data, const QOpenGLPixelTransferOptions * const options) +{ + Q_D(QOpenGLTexture); + Q_ASSERT(d->textureId); + if (!isStorageAllocated()) { + qWarning("Cannot set data on a texture that does not have storage allocated.\n" + "To do so call allocateStorage() before this function"); + return; + } + d->setData(mipLevel, layer, layerCount, cubeFace, sourceFormat, sourceType, data, options); } /*! @@ -3299,7 +3325,7 @@ void QOpenGLTexture::setData(int mipLevel, int layer, { Q_D(QOpenGLTexture); Q_ASSERT(d->textureId); - d->setData(mipLevel, layer, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); + d->setData(mipLevel, layer, 1, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); } /*! @@ -3312,7 +3338,7 @@ void QOpenGLTexture::setData(int mipLevel, { Q_D(QOpenGLTexture); Q_ASSERT(d->textureId); - d->setData(mipLevel, 0, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); + d->setData(mipLevel, 0, 1, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); } /*! @@ -3324,7 +3350,7 @@ void QOpenGLTexture::setData(PixelFormat sourceFormat, PixelType sourceType, { Q_D(QOpenGLTexture); Q_ASSERT(d->textureId); - d->setData(0, 0, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); + d->setData(0, 0, 1, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); } #if QT_DEPRECATED_SINCE(5, 3) @@ -3345,7 +3371,7 @@ void QOpenGLTexture::setData(int mipLevel, int layer, CubeMapFace cubeFace, "To do so call allocateStorage() before this function"); return; } - d->setData(mipLevel, layer, cubeFace, sourceFormat, sourceType, data, options); + d->setData(mipLevel, layer, 1, cubeFace, sourceFormat, sourceType, data, options); } /*! @@ -3358,7 +3384,7 @@ void QOpenGLTexture::setData(int mipLevel, int layer, { Q_D(QOpenGLTexture); Q_ASSERT(d->textureId); - d->setData(mipLevel, layer, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); + d->setData(mipLevel, layer, 1, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); } /*! @@ -3371,7 +3397,7 @@ void QOpenGLTexture::setData(int mipLevel, { Q_D(QOpenGLTexture); Q_ASSERT(d->textureId); - d->setData(mipLevel, 0, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); + d->setData(mipLevel, 0, 1, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); } /*! @@ -3383,7 +3409,7 @@ void QOpenGLTexture::setData(PixelFormat sourceFormat, PixelType sourceType, { Q_D(QOpenGLTexture); Q_ASSERT(d->textureId); - d->setData(0, 0, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); + d->setData(0, 0, 1, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); } #endif @@ -3444,7 +3470,23 @@ void QOpenGLTexture::setCompressedData(int mipLevel, int layer, CubeMapFace cube "To do so call allocateStorage() before this function"); return; } - d->setCompressedData(mipLevel, layer, cubeFace, dataSize, data, options); + d->setCompressedData(mipLevel, layer, 1, cubeFace, dataSize, data, options); +} + +/*! + \since 5.9 + \overload +*/ +void QOpenGLTexture::setCompressedData(int mipLevel, int layer, int layerCount, QOpenGLTexture::CubeMapFace cubeFace, int dataSize, const void *data, const QOpenGLPixelTransferOptions * const options) +{ + Q_D(QOpenGLTexture); + Q_ASSERT(d->textureId); + if (!isStorageAllocated()) { + qWarning("Cannot set data on a texture that does not have storage allocated.\n" + "To do so call allocateStorage() before this function"); + return; + } + d->setCompressedData(mipLevel, layer, layerCount, cubeFace, dataSize, data, options); } /*! @@ -3455,7 +3497,7 @@ void QOpenGLTexture::setCompressedData(int mipLevel, int layer, int dataSize, co { Q_D(QOpenGLTexture); Q_ASSERT(d->textureId); - d->setCompressedData(mipLevel, layer, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); + d->setCompressedData(mipLevel, layer, 1, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); } /*! @@ -3466,7 +3508,7 @@ void QOpenGLTexture::setCompressedData(int mipLevel, int dataSize, const void *d { Q_D(QOpenGLTexture); Q_ASSERT(d->textureId); - d->setCompressedData(mipLevel, 0, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); + d->setCompressedData(mipLevel, 0, 1, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); } /*! @@ -3477,7 +3519,7 @@ void QOpenGLTexture::setCompressedData(int dataSize, const void *data, { Q_D(QOpenGLTexture); Q_ASSERT(d->textureId); - d->setCompressedData(0, 0, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); + d->setCompressedData(0, 0, 1, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); } #if QT_DEPRECATED_SINCE(5, 3) @@ -3496,7 +3538,7 @@ void QOpenGLTexture::setCompressedData(int mipLevel, int layer, CubeMapFace cube "To do so call allocateStorage() before this function"); return; } - d->setCompressedData(mipLevel, layer, cubeFace, dataSize, data, options); + d->setCompressedData(mipLevel, layer, 1, cubeFace, dataSize, data, options); } /*! @@ -3508,7 +3550,7 @@ void QOpenGLTexture::setCompressedData(int mipLevel, int layer, int dataSize, vo { Q_D(QOpenGLTexture); Q_ASSERT(d->textureId); - d->setCompressedData(mipLevel, layer, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); + d->setCompressedData(mipLevel, layer, 1, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); } /*! @@ -3520,7 +3562,7 @@ void QOpenGLTexture::setCompressedData(int mipLevel, int dataSize, void *data, { Q_D(QOpenGLTexture); Q_ASSERT(d->textureId); - d->setCompressedData(mipLevel, 0, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); + d->setCompressedData(mipLevel, 0, 1, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); } /*! @@ -3532,7 +3574,7 @@ void QOpenGLTexture::setCompressedData(int dataSize, void *data, { Q_D(QOpenGLTexture); Q_ASSERT(d->textureId); - d->setCompressedData(0, 0, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); + d->setCompressedData(0, 0, 1, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); } #endif diff --git a/src/gui/opengl/qopengltexture.h b/src/gui/opengl/qopengltexture.h index d0a3bfec8b..6e6f7ef1f2 100644 --- a/src/gui/opengl/qopengltexture.h +++ b/src/gui/opengl/qopengltexture.h @@ -472,6 +472,9 @@ public: void setData(int mipLevel, int layer, CubeMapFace cubeFace, PixelFormat sourceFormat, PixelType sourceType, const void *data, const QOpenGLPixelTransferOptions * const options = Q_NULLPTR); + void setData(int mipLevel, int layer, int layerCount, CubeMapFace cubeFace, + PixelFormat sourceFormat, PixelType sourceType, + const void *data, const QOpenGLPixelTransferOptions * const options = Q_NULLPTR); void setData(int mipLevel, int layer, PixelFormat sourceFormat, PixelType sourceType, const void *data, const QOpenGLPixelTransferOptions * const options = Q_NULLPTR); @@ -499,6 +502,9 @@ public: void setCompressedData(int mipLevel, int layer, CubeMapFace cubeFace, int dataSize, const void *data, const QOpenGLPixelTransferOptions * const options = Q_NULLPTR); + void setCompressedData(int mipLevel, int layer, int layerCount, CubeMapFace cubeFace, + int dataSize, const void *data, + const QOpenGLPixelTransferOptions * const options = Q_NULLPTR); void setCompressedData(int mipLevel, int layer, int dataSize, const void *data, const QOpenGLPixelTransferOptions * const options = Q_NULLPTR); diff --git a/src/gui/opengl/qopengltexture_p.h b/src/gui/opengl/qopengltexture_p.h index 9914316bb4..f7694f77bc 100644 --- a/src/gui/opengl/qopengltexture_p.h +++ b/src/gui/opengl/qopengltexture_p.h @@ -98,13 +98,14 @@ public: void allocateStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType); void allocateMutableStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType); void allocateImmutableStorage(); - void setData(int mipLevel, int layer, QOpenGLTexture::CubeMapFace cubeFace, + void setData(int mipLevel, int layer, int layerCount, QOpenGLTexture::CubeMapFace cubeFace, QOpenGLTexture::PixelFormat sourceFormat, QOpenGLTexture::PixelType sourceType, const void *data, const QOpenGLPixelTransferOptions * const options); - void setCompressedData(int mipLevel, int layer, QOpenGLTexture::CubeMapFace cubeFace, + void setCompressedData(int mipLevel, int layer, int layerCount, QOpenGLTexture::CubeMapFace cubeFace, int dataSize, const void *data, const QOpenGLPixelTransferOptions * const options); + void setWrapMode(QOpenGLTexture::WrapMode mode); void setWrapMode(QOpenGLTexture::CoordinateDirection direction, QOpenGLTexture::WrapMode mode); QOpenGLTexture::WrapMode wrapMode(QOpenGLTexture::CoordinateDirection direction) const; diff --git a/src/gui/opengl/qopengltextureblitter.cpp b/src/gui/opengl/qopengltextureblitter.cpp index 858fc0d857..b65df9dc82 100644 --- a/src/gui/opengl/qopengltextureblitter.cpp +++ b/src/gui/opengl/qopengltextureblitter.cpp @@ -330,8 +330,8 @@ bool QOpenGLTextureBlitterPrivate::buildProgram(ProgramIndex idx, const char *vs p->glProgram.reset(new QOpenGLShaderProgram); - p->glProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, vs); - p->glProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, fs); + p->glProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vs); + p->glProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fs); p->glProgram->link(); if (!p->glProgram->isLinked()) { qWarning() << "Could not link shader program:\n" << p->glProgram->log(); diff --git a/src/gui/opengl/qopengltexturecache.cpp b/src/gui/opengl/qopengltexturecache.cpp index 688226551d..27aa8db33a 100644 --- a/src/gui/opengl/qopengltexturecache.cpp +++ b/src/gui/opengl/qopengltexturecache.cpp @@ -371,7 +371,7 @@ static void freeTexture(QOpenGLFunctions *funcs, GLuint id) funcs->glDeleteTextures(1, &id); } -QOpenGLCachedTexture::QOpenGLCachedTexture(GLuint id, int options, QOpenGLContext *context) : m_options(options) +QOpenGLCachedTexture::QOpenGLCachedTexture(GLuint id, QOpenGLTextureCache::BindOptions options, QOpenGLContext *context) : m_options(options) { m_resource = new QOpenGLSharedResourceGuard(context, id, freeTexture); } diff --git a/src/gui/opengl/qopengltexturecache_p.h b/src/gui/opengl/qopengltexturecache_p.h index c68b068739..4a438c8d95 100644 --- a/src/gui/opengl/qopengltexturecache_p.h +++ b/src/gui/opengl/qopengltexturecache_p.h @@ -60,19 +60,7 @@ QT_BEGIN_NAMESPACE -class QOpenGLCachedTexture -{ -public: - QOpenGLCachedTexture(GLuint id, int options, QOpenGLContext *context); - ~QOpenGLCachedTexture() { m_resource->free(); } - - GLuint id() const { return m_resource->id(); } - int options() const { return m_options; } - -private: - QOpenGLSharedResourceGuard *m_resource; - int m_options; -}; +class QOpenGLCachedTexture; class Q_GUI_EXPORT QOpenGLTextureCache : public QOpenGLSharedResource { @@ -106,6 +94,20 @@ private: Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLTextureCache::BindOptions) +class QOpenGLCachedTexture +{ +public: + QOpenGLCachedTexture(GLuint id, QOpenGLTextureCache::BindOptions options, QOpenGLContext *context); + ~QOpenGLCachedTexture() { m_resource->free(); } + + GLuint id() const { return m_resource->id(); } + QOpenGLTextureCache::BindOptions options() const { return m_options; } + +private: + QOpenGLSharedResourceGuard *m_resource; + QOpenGLTextureCache::BindOptions m_options; +}; + QT_END_NAMESPACE #endif diff --git a/src/gui/opengl/qopengltextureglyphcache.cpp b/src/gui/opengl/qopengltextureglyphcache.cpp index 9a7b1eb21d..62b069a1d0 100644 --- a/src/gui/opengl/qopengltextureglyphcache.cpp +++ b/src/gui/opengl/qopengltextureglyphcache.cpp @@ -342,22 +342,14 @@ void QOpenGLTextureGlyphCache::resizeTextureData(int width, int height) QString source; source.append(QLatin1String(isCoreProfile ? qopenglslMainWithTexCoordsVertexShader_core : qopenglslMainWithTexCoordsVertexShader)); source.append(QLatin1String(isCoreProfile ? qopenglslUntransformedPositionVertexShader_core : qopenglslUntransformedPositionVertexShader)); - - QOpenGLShader *vertexShader = new QOpenGLShader(QOpenGLShader::Vertex, m_blitProgram); - vertexShader->compileSourceCode(source); - - m_blitProgram->addShader(vertexShader); + m_blitProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, source); } { QString source; source.append(QLatin1String(isCoreProfile ? qopenglslMainFragmentShader_core : qopenglslMainFragmentShader)); source.append(QLatin1String(isCoreProfile ? qopenglslImageSrcFragmentShader_core : qopenglslImageSrcFragmentShader)); - - QOpenGLShader *fragmentShader = new QOpenGLShader(QOpenGLShader::Fragment, m_blitProgram); - fragmentShader->compileSourceCode(source); - - m_blitProgram->addShader(fragmentShader); + m_blitProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, source); } m_blitProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); @@ -380,8 +372,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(); |