diff options
Diffstat (limited to 'src/gui/opengl')
-rw-r--r-- | src/gui/opengl/opengl.pri | 6 | ||||
-rw-r--r-- | src/gui/opengl/qopengl.cpp | 21 | ||||
-rw-r--r-- | src/gui/opengl/qopengldebug.h | 5 | ||||
-rw-r--r-- | src/gui/opengl/qopenglengineshadermanager.cpp | 97 | ||||
-rw-r--r-- | src/gui/opengl/qopenglengineshadermanager_p.h | 1 | ||||
-rw-r--r-- | src/gui/opengl/qopenglfunctions.h | 568 | ||||
-rw-r--r-- | src/gui/opengl/qopenglprogrambinarycache.cpp | 336 | ||||
-rw-r--r-- | src/gui/opengl/qopenglprogrambinarycache_p.h | 100 | ||||
-rw-r--r-- | src/gui/opengl/qopenglshaderprogram.cpp | 541 | ||||
-rw-r--r-- | src/gui/opengl/qopenglshaderprogram.h | 12 | ||||
-rw-r--r-- | src/gui/opengl/qopengltextureblitter.cpp | 4 | ||||
-rw-r--r-- | src/gui/opengl/qopengltextureglyphcache.cpp | 12 |
12 files changed, 943 insertions, 760 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 eb08492254..e61473cb7b 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> @@ -221,29 +222,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..c7e457b364 100644 --- a/src/gui/opengl/qopenglengineshadermanager.cpp +++ b/src/gui/opengl/qopenglengineshadermanager.cpp @@ -208,8 +208,6 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context) snippetsPopulated = true; } - QOpenGLShader* fragShader; - QOpenGLShader* vertexShader; QByteArray vertexSource; QByteArray fragSource; @@ -227,19 +225,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 +261,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 +288,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 +349,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 +402,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/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/qopenglprogrambinarycache.cpp b/src/gui/opengl/qopenglprogrambinarycache.cpp new file mode 100644 index 0000000000..5c8e425e29 --- /dev/null +++ b/src/gui/opengl/qopenglprogrambinarycache.cpp @@ -0,0 +1,336 @@ +/**************************************************************************** +** +** 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 = 0x1; +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); +} + +static const int HEADER_SIZE = 3 * sizeof(quint32); + +bool QOpenGLProgramBinaryCache::verifyHeader(const QByteArray &buf) const +{ + if (buf.size() < HEADER_SIZE) { + qCDebug(DBG_SHADER_CACHE, "Cached size too small"); + return false; + } + const quint32 *p = reinterpret_cast<const quint32 *>(buf.constData()); + if (*p++ != BINSHADER_MAGIC) { + qCDebug(DBG_SHADER_CACHE, "Magic does not match"); + return false; + } + if (*p++ != BINSHADER_VERSION) { + qCDebug(DBG_SHADER_CACHE, "Version does not match"); + return false; + } + if (*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[HEADER_SIZE]; + qint64 bytesRead = qt_safe_read(fdw.fd, header, HEADER_SIZE); + if (bytesRead == HEADER_SIZE) + buf = QByteArray::fromRawData(header, HEADER_SIZE); +#else + QFile f(fn); + if (!f.open(QIODevice::ReadOnly)) + return false; + buf = f.read(HEADER_SIZE); +#endif + + if (!verifyHeader(buf)) { + undertaker.setActive(); + return false; + } + + const quint32 *p; +#ifdef Q_OS_UNIX + if (!fdw.map()) { + undertaker.setActive(); + return false; + } + p = reinterpret_cast<const quint32 *>(static_cast<const char *>(fdw.ptr) + HEADER_SIZE); +#else + buf = f.readAll(); + p = reinterpret_cast<const quint32 *>(buf.constData()); +#endif + + GLEnvInfo info; + + quint32 v = *p++; + QByteArray vendor = QByteArray::fromRawData(reinterpret_cast<const char *>(p), v); + if (vendor != info.glvendor) { + qCDebug(DBG_SHADER_CACHE, "GL_VENDOR does not match (%s, %s)", vendor.constData(), info.glvendor.constData()); + undertaker.setActive(); + return false; + } + p = reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(p) + v); + v = *p++; + QByteArray renderer = QByteArray::fromRawData(reinterpret_cast<const char *>(p), v); + if (renderer != info.glrenderer) { + qCDebug(DBG_SHADER_CACHE, "GL_RENDERER does not match (%s, %s)", renderer.constData(), info.glrenderer.constData()); + undertaker.setActive(); + return false; + } + p = reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(p) + v); + v = *p++; + QByteArray version = QByteArray::fromRawData(reinterpret_cast<const char *>(p), v); + if (version != info.glversion) { + qCDebug(DBG_SHADER_CACHE, "GL_VERSION does not match (%s, %s)", version.constData(), info.glversion.constData()); + undertaker.setActive(); + return false; + } + p = reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(p) + v); + + quint32 blobFormat = *p++; + quint32 blobSize = *p++; + + return setProgramBinary(programId, blobFormat, p, blobSize) + && m_memCache.insert(cacheKey, new MemCacheEntry(p, blobSize, blobFormat)); +} + +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); + int totalSize = blobSize + 8 + 12 + 12 + info.glvendor.size() + info.glrenderer.size() + info.glversion.size(); + 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); + quint32 *p = reinterpret_cast<quint32 *>(blob.data()); + + *p++ = BINSHADER_MAGIC; + *p++ = BINSHADER_VERSION; + *p++ = BINSHADER_QTVERSION; + + *p++ = info.glvendor.size(); + memcpy(p, info.glvendor.constData(), info.glvendor.size()); + p = reinterpret_cast<quint32 *>(reinterpret_cast<char *>(p) + info.glvendor.size()); + *p++ = info.glrenderer.size(); + memcpy(p, info.glrenderer.constData(), info.glrenderer.size()); + p = reinterpret_cast<quint32 *>(reinterpret_cast<char *>(p) + info.glrenderer.size()); + *p++ = info.glversion.size(); + memcpy(p, info.glversion.constData(), info.glversion.size()); + p = reinterpret_cast<quint32 *>(reinterpret_cast<char *>(p) + info.glversion.size()); + + GLint outSize = 0; + quint32 *blobFormat = p++; + *p++ = blobSize; + funcs->glGetProgramBinary(programId, blobSize, &outSize, blobFormat, p); + if (blobSize != outSize) { + qCDebug(DBG_SHADER_CACHE, "glGetProgramBinary returned size %d instead of %d", outSize, blobSize); + return; + } + + 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..d296f327c8 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); @@ -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/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/qopengltextureglyphcache.cpp b/src/gui/opengl/qopengltextureglyphcache.cpp index 9a7b1eb21d..afd5004cec 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); |