diff options
| author | Oswald Buddenhagen <[email protected]> | 2013-03-20 13:46:57 +0100 |
|---|---|---|
| committer | Oswald Buddenhagen <[email protected]> | 2013-03-20 13:49:28 +0100 |
| commit | 76c0be34cd4ff4564693162fa7528463e23ce9d8 (patch) | |
| tree | f165b7bc319548fb0082365411a871028f92e89e /src/gui/opengl/qopenglshaderprogram.cpp | |
| parent | 27b4fe96b59e9e63d1e570e802c072e9afdfb2d4 (diff) | |
| parent | 36cb3f3f655a9090c82de609010cbfb88651a0f3 (diff) | |
Merge branch 'dev' into stable
This starts Qt 5.1 release cycle
Conflicts:
src/gui/text/qfontdatabase.cpp
src/gui/text/qharfbuzz_copy_p.h
src/widgets/kernel/qapplication.cpp
src/widgets/kernel/qcoreapplication.cpp
Change-Id: I72fbf83ab3c2206aeea1b089428b0fc2a89bd62b
Diffstat (limited to 'src/gui/opengl/qopenglshaderprogram.cpp')
| -rw-r--r-- | src/gui/opengl/qopenglshaderprogram.cpp | 318 |
1 files changed, 305 insertions, 13 deletions
diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp index 88c9c8008cd..1cde0cb92d2 100644 --- a/src/gui/opengl/qopenglshaderprogram.cpp +++ b/src/gui/opengl/qopenglshaderprogram.cpp @@ -49,6 +49,11 @@ #include <QtCore/qvector.h> #include <QtGui/qtransform.h> #include <QtGui/QColor> +#include <QtGui/QSurfaceFormat> + +#if !defined(QT_OPENGL_ES_2) +#include <QtGui/qopenglfunctions_4_0_core.h> +#endif QT_BEGIN_NAMESPACE @@ -145,6 +150,14 @@ QT_BEGIN_NAMESPACE \value Vertex Vertex shader written in the OpenGL Shading Language (GLSL). \value Fragment Fragment shader written in the OpenGL Shading Language (GLSL). + \value Geometry Geometry shaders written in the OpenGL Shading Language (GLSL) + based on the OpenGL core feature (requires OpenGL >= 3.2). + \value TessellationControl Tessellation control shaders written in the OpenGL + shading language (GLSL), based on the core feature (requires OpenGL >= 4.0). + \value TessellationEvaluation Tessellation evaluation shaders written in the OpenGL + shading language (GLSL), based on the core feature (requires OpenGL >= 4.0). + \value Compute Compute shaders written in the OpenGL shading language (GLSL), + based on the core feature (requires OpenGL >= 4.3). */ class QOpenGLShaderPrivate : public QObjectPrivate @@ -156,7 +169,20 @@ public: , shaderType(type) , compiled(false) , glfuncs(new QOpenGLFunctions(ctx)) +#ifndef QT_OPENGL_ES_2 + , supportsGeometryShaders(false) + , supportsTessellationShaders(false) +#endif { +#ifndef QT_OPENGL_ES_2 + 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 } ~QOpenGLShaderPrivate(); @@ -167,6 +193,14 @@ public: QOpenGLFunctions *glfuncs; +#ifndef QT_OPENGL_ES_2 + // Support for geometry shaders + bool supportsGeometryShaders; + + // Support for tessellation shaders + bool supportsTessellationShaders; +#endif + bool create(); bool compile(QOpenGLShader *q); void deleteShader(); @@ -192,10 +226,25 @@ bool QOpenGLShaderPrivate::create() if (!context) return false; GLuint shader; - if (shaderType == QOpenGLShader::Vertex) + if (shaderType == QOpenGLShader::Vertex) { shader = glfuncs->glCreateShader(GL_VERTEX_SHADER); - else +#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) { + shader = glfuncs->glCreateShader(GL_COMPUTE_SHADER); +#endif + } else { shader = glfuncs->glCreateShader(GL_FRAGMENT_SHADER); + } if (!shader) { qWarning() << "QOpenGLShader: could not create shader"; return false; @@ -234,6 +283,8 @@ bool QOpenGLShaderPrivate::compile(QOpenGLShader *q) type = types[0]; else if (shaderType == QOpenGLShader::Vertex) type = types[1]; + else if (shaderType == QOpenGLShader::Geometry) + type = types[2]; // Get info and source code lengths GLint infoLogLength = 0; @@ -329,18 +380,12 @@ QOpenGLShader::ShaderType QOpenGLShader::shaderType() const return d->shaderType; } -// The precision qualifiers are useful on OpenGL/ES systems, -// but usually not present on desktop systems. Define the -// keywords to empty strings on desktop systems. -#if !defined(QT_OPENGL_ES) || defined(QT_OPENGL_FORCE_SHADER_DEFINES) -#define QOpenGL_DEFINE_QUALIFIERS 1 static const char qualifierDefines[] = "#define lowp\n" "#define mediump\n" "#define highp\n"; -#else - +#if defined(QT_OPENGL_ES) && !defined(QT_OPENGL_FORCE_SHADER_DEFINES) // The "highp" qualifier doesn't exist in fragment shaders // on all ES platforms. When it doesn't exist, use "mediump". #define QOpenGL_REDEFINE_HIGHP 1 @@ -380,10 +425,19 @@ bool QOpenGLShader::compileSourceCode(const char *source) src.append(source); srclen.append(GLint(headerLen)); } -#ifdef QOpenGL_DEFINE_QUALIFIERS - src.append(qualifierDefines); - srclen.append(GLint(sizeof(qualifierDefines) - 1)); + + // The precision qualifiers are useful on OpenGL/ES systems, + // but usually not present on desktop systems. + const QSurfaceFormat currentSurfaceFormat = QOpenGLContext::currentContext()->format(); + if (currentSurfaceFormat.renderableType() == QSurfaceFormat::OpenGL +#ifdef QT_OPENGL_FORCE_SHADER_DEFINES + || true #endif + ) { + src.append(qualifierDefines); + srclen.append(GLint(sizeof(qualifierDefines) - 1)); + } + #ifdef QOpenGL_REDEFINE_HIGHP if (d->shaderType == Fragment) { src.append(redefineHighp); @@ -510,6 +564,9 @@ public: , inited(false) , removingShaders(false) , glfuncs(new QOpenGLFunctions) +#ifndef QT_OPENGL_ES_2 + , tessellationFuncs(0) +#endif { } ~QOpenGLShaderProgramPrivate(); @@ -525,6 +582,11 @@ public: QOpenGLFunctions *glfuncs; +#ifndef QT_OPENGL_ES_2 + // Tessellation shader support + QOpenGLFunctions_4_0_Core *tessellationFuncs; +#endif + bool hasShader(QOpenGLShader::ShaderType type) const; }; @@ -582,6 +644,16 @@ bool QOpenGLShaderProgram::init() if (!context) return false; d->glfuncs->initializeOpenGLFunctions(); + +#ifndef QT_OPENGL_ES_2 + // Resolve OpenGL 4 functions for tessellation shader support + QSurfaceFormat format = context->format(); + if (format.version() >= qMakePair<int, int>(4, 0)) { + d->tessellationFuncs = context->versionFunctions<QOpenGLFunctions_4_0_Core>(); + d->tessellationFuncs->initializeOpenGLFunctions(); + } +#endif + GLuint program = d->glfuncs->glCreateProgram(); if (!program) { qWarning() << "QOpenGLShaderProgram: could not create shader program"; @@ -2927,6 +2999,198 @@ void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4 } /*! + Returns the hardware limit for how many vertices a geometry shader + can output. +*/ +int QOpenGLShaderProgram::maxGeometryOutputVertices() const +{ + GLint n = 0; +#if defined(QT_OPENGL_3_2) + glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &n); +#endif + return n; +} + +/*! + Use this function to specify to OpenGL the number of vertices in + a patch to \a count. A patch is a custom OpenGL primitive whose interpretation + is entirely defined by the tessellation shader stages. Therefore, calling + this function only makes sense when using a QOpenGLShaderProgram + containing tessellation stage shaders. When using OpenGL tessellation, + the only primitive that can be rendered with \c{glDraw*()} functions is + \c{GL_PATCHES}. + + This is equivalent to calling glPatchParameteri(GL_PATCH_VERTICES, count). + + \note This modifies global OpenGL state and is not specific to this + QOpenGLShaderProgram instance. You should call this in your render + function when needed, as QOpenGLShaderProgram will not apply this for + you. This is purely a convenience function. + + \sa patchVertexCount() +*/ +void QOpenGLShaderProgram::setPatchVertexCount(int count) +{ +#if defined(QT_OPENGL_4) + Q_D(QOpenGLShaderProgram); + if (d->tessellationFuncs) + d->tessellationFuncs->glPatchParameteri(GL_PATCH_VERTICES, count); +#else + Q_UNUSED(count); +#endif +} + +/*! + Returns the number of vertices per-patch to be used when rendering. + + \note This returns the global OpenGL state value. It is not specific to + this QOpenGLShaderProgram instance. + + \sa setPatchVertexCount() +*/ +int QOpenGLShaderProgram::patchVertexCount() const +{ + 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; +} + +/*! + Sets the default outer tessellation levels to be used by the tessellation + primitive generator in the event that the tessellation control shader + does not output them to \a levels. For more details on OpenGL and Tessellation + shaders see \l{OpenGL Tessellation Shaders}. + + The \a levels argument should be a QVector consisting of 4 floats. Not all + of the values make sense for all tessellation modes. If you specify a vector with + fewer than 4 elements, the remaining elements will be given a default value of 1. + + \note This modifies global OpenGL state and is not specific to this + QOpenGLShaderProgram instance. You should call this in your render + function when needed, as QOpenGLShaderProgram will not apply this for + you. This is purely a convenience function. + + \sa defaultOuterTessellationLevels(), setDefaultInnerTessellationLevels() +*/ +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); + } + + Q_D(QOpenGLShaderProgram); + if (d->tessellationFuncs) + d->tessellationFuncs->glPatchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, tessLevels.data()); +#else + Q_UNUSED(levels); +#endif +} + +/*! + Returns the default outer tessellation levels to be used by the tessellation + primitive generator in the event that the tessellation control shader + does not output them. For more details on OpenGL and Tessellation shaders see + \l{OpenGL Tessellation Shaders}. + + Returns a QVector of floats describing the outer tessellation levels. The vector + will always have four elements but not all of them make sense for every mode + of tessellation. + + \note This returns the global OpenGL state value. It is not specific to + this QOpenGLShaderProgram instance. + + \sa setDefaultOuterTessellationLevels(), defaultInnerTessellationLevels() +*/ +QVector<float> QOpenGLShaderProgram::defaultOuterTessellationLevels() const +{ + 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; +} + +/*! + Sets the default outer tessellation levels to be used by the tessellation + primitive generator in the event that the tessellation control shader + does not output them to \a levels. For more details on OpenGL and Tessellation shaders see + \l{OpenGL Tessellation Shaders}. + + The \a levels argument should be a QVector consisting of 2 floats. Not all + of the values make sense for all tessellation modes. If you specify a vector with + fewer than 2 elements, the remaining elements will be given a default value of 1. + + \note This modifies global OpenGL state and is not specific to this + QOpenGLShaderProgram instance. You should call this in your render + function when needed, as QOpenGLShaderProgram will not apply this for + you. This is purely a convenience function. + + \sa defaultInnerTessellationLevels(), setDefaultOuterTessellationLevels() +*/ +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); + } + + Q_D(QOpenGLShaderProgram); + if (d->tessellationFuncs) + d->tessellationFuncs->glPatchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, tessLevels.data()); +#else + Q_UNUSED(levels); +#endif +} + +/*! + Returns the default inner tessellation levels to be used by the tessellation + primitive generator in the event that the tessellation control shader + does not output them. For more details on OpenGL and Tessellation shaders see + \l{OpenGL Tessellation Shaders}. + + Returns a QVector of floats describing the inner tessellation levels. The vector + will always have two elements but not all of them make sense for every mode + of tessellation. + + \note This returns the global OpenGL state value. It is not specific to + this QOpenGLShaderProgram instance. + + \sa setDefaultInnerTessellationLevels(), defaultOuterTessellationLevels() +*/ +QVector<float> QOpenGLShaderProgram::defaultInnerTessellationLevels() const +{ + QVector<float> tessLevels(2, 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; +} + + +/*! Returns true if shader programs written in the OpenGL Shading Language (GLSL) are supported on this system; false otherwise. @@ -2972,9 +3236,37 @@ bool QOpenGLShader::hasOpenGLShaders(ShaderType type, QOpenGLContext *context) if (!context) return false; - if ((type & ~(Vertex | Fragment)) || type == 0) + 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 (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 (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 + } + // Unconditional support of vertex and fragment shaders implicitly assumes + // a minimum OpenGL version of 2.0 return true; } |
