summaryrefslogtreecommitdiffstats
path: root/src/gui/opengl/qopenglshaderprogram.cpp
diff options
context:
space:
mode:
authorOswald Buddenhagen <[email protected]>2013-03-20 13:46:57 +0100
committerOswald Buddenhagen <[email protected]>2013-03-20 13:49:28 +0100
commit76c0be34cd4ff4564693162fa7528463e23ce9d8 (patch)
treef165b7bc319548fb0082365411a871028f92e89e /src/gui/opengl/qopenglshaderprogram.cpp
parent27b4fe96b59e9e63d1e570e802c072e9afdfb2d4 (diff)
parent36cb3f3f655a9090c82de609010cbfb88651a0f3 (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.cpp318
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;
}