diff options
Diffstat (limited to 'src/opengl/qglshaderprogram.cpp')
-rw-r--r-- | src/opengl/qglshaderprogram.cpp | 412 |
1 files changed, 397 insertions, 15 deletions
diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp index 79484fa..55fd922 100644 --- a/src/opengl/qglshaderprogram.cpp +++ b/src/opengl/qglshaderprogram.cpp @@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE -#if !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) +#if !defined(QT_OPENGL_ES_1) /*! \class QGLShaderProgram @@ -143,6 +143,8 @@ 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 GL_EXT_geometry_shader4 extension. */ #ifndef GL_FRAGMENT_SHADER @@ -226,6 +228,8 @@ bool QGLShaderPrivate::create() GLuint shader; if (shaderType == QGLShader::Vertex) shader = glCreateShader(GL_VERTEX_SHADER); + else if (shaderType == QGLShader::Geometry) + shader = glCreateShader(GL_GEOMETRY_SHADER_EXT); else shader = glCreateShader(GL_FRAGMENT_SHADER); if (!shader) { @@ -509,6 +513,10 @@ GLuint QGLShader::shaderId() const return d->shaderGuard.id(); } + + + + #undef ctx #define ctx programGuard.context() @@ -521,8 +529,9 @@ public: , linked(false) , inited(false) , removingShaders(false) - , vertexShader(0) - , fragmentShader(0) + , geometryVertexCount(64) + , geometryInputType(0) + , geometryOutputType(0) { } ~QGLShaderProgramPrivate(); @@ -531,11 +540,14 @@ public: bool linked; bool inited; bool removingShaders; + + int geometryVertexCount; + GLenum geometryInputType; + GLenum geometryOutputType; + QString log; QList<QGLShader *> shaders; QList<QGLShader *> anonShaders; - QGLShader *vertexShader; - QGLShader *fragmentShader; bool hasShader(QGLShader::ShaderType type) const; }; @@ -604,6 +616,7 @@ bool QGLShaderProgram::init() context = QGLContext::currentContext(); d->programGuard.setContext(context); } + if (!context) return false; if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(context))) { @@ -831,6 +844,7 @@ bool QGLShaderProgram::link() GLuint program = d->programGuard.id(); if (!program) return false; + GLint value; if (d->shaders.isEmpty()) { // If there are no explicit shaders, then it is possible that the @@ -843,6 +857,22 @@ bool QGLShaderProgram::link() if (d->linked) return true; } + + // Set up the geometry shader parameters + if (glProgramParameteriEXT) { + foreach (QGLShader *shader, d->shaders) { + if (shader->shaderType() & QGLShader::Geometry) { + glProgramParameteriEXT(program, GL_GEOMETRY_INPUT_TYPE_EXT, + d->geometryInputType); + glProgramParameteriEXT(program, GL_GEOMETRY_OUTPUT_TYPE_EXT, + d->geometryOutputType); + glProgramParameteriEXT(program, GL_GEOMETRY_VERTICES_OUT_EXT, + d->geometryVertexCount); + break; + } + } + } + glLinkProgram(program); value = 0; glGetProgramiv(program, GL_LINK_STATUS, &value); @@ -1260,7 +1290,8 @@ void QGLShaderProgram::setAttributeValue(int location, const QColor& value) Q_D(QGLShaderProgram); Q_UNUSED(d); if (location != -1) { - GLfloat values[4] = {value.redF(), value.greenF(), value.blueF(), value.alphaF()}; + GLfloat values[4] = {GLfloat(value.redF()), GLfloat(value.greenF()), + GLfloat(value.blueF()), GLfloat(value.alphaF())}; glVertexAttrib4fv(location, values); } } @@ -1426,6 +1457,38 @@ void QGLShaderProgram::setAttributeArray } /*! + Sets an array of vertex \a values on the attribute at \a location + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + The \a type indicates the type of elements in the \a values array, + usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a tupleSize + indicates the number of components per vertex: 1, 2, 3, or 4. + + The array will become active when enableAttributeArray() is called + on the \a location. Otherwise the value specified with + setAttributeValue() for \a location will be used. + + The setAttributeBuffer() function can be used to set the attribute + array to an offset within a vertex buffer. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray(), setAttributeBuffer() + \since 4.7 +*/ +void QGLShaderProgram::setAttributeArray + (int location, GLenum type, const void *values, int tupleSize, int stride) +{ + Q_D(QGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + glVertexAttribPointer(location, tupleSize, type, GL_FALSE, + stride, values); + } +} + +/*! \overload Sets an array of vertex \a values on the attribute called \a name @@ -1511,6 +1574,92 @@ void QGLShaderProgram::setAttributeArray } /*! + \overload + + Sets an array of vertex \a values on the attribute called \a name + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + The \a type indicates the type of elements in the \a values array, + usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a tupleSize + indicates the number of components per vertex: 1, 2, 3, or 4. + + The array will become active when enableAttributeArray() is called + on the \a name. Otherwise the value specified with + setAttributeValue() for \a name will be used. + + The setAttributeBuffer() function can be used to set the attribute + array to an offset within a vertex buffer. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray(), setAttributeBuffer() + \since 4.7 +*/ +void QGLShaderProgram::setAttributeArray + (const char *name, GLenum type, const void *values, int tupleSize, int stride) +{ + setAttributeArray(attributeLocation(name), type, values, tupleSize, stride); +} + +/*! + Sets an array of vertex values on the attribute at \a location in + this shader program, starting at a specific \a offset in the + currently bound vertex buffer. The \a stride indicates the number + of bytes between vertices. A default \a stride value of zero + indicates that the vertices are densely packed in the value array. + + The \a type indicates the type of elements in the vertex value + array, usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a + tupleSize indicates the number of components per vertex: 1, 2, 3, + or 4. + + The array will become active when enableAttributeArray() is called + on the \a location. Otherwise the value specified with + setAttributeValue() for \a location will be used. + + \sa setAttributeArray() + \since 4.7 +*/ +void QGLShaderProgram::setAttributeBuffer + (int location, GLenum type, int offset, int tupleSize, int stride) +{ + Q_D(QGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + glVertexAttribPointer(location, tupleSize, type, GL_FALSE, stride, + reinterpret_cast<const void *>(offset)); + } +} + +/*! + \overload + + Sets an array of vertex values on the attribute called \a name + in this shader program, starting at a specific \a offset in the + currently bound vertex buffer. The \a stride indicates the number + of bytes between vertices. A default \a stride value of zero + indicates that the vertices are densely packed in the value array. + + The \a type indicates the type of elements in the vertex value + array, usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a + tupleSize indicates the number of components per vertex: 1, 2, 3, + or 4. + + The array will become active when enableAttributeArray() is called + on the \a name. Otherwise the value specified with + setAttributeValue() for \a name will be used. + + \sa setAttributeArray() + \since 4.7 +*/ +void QGLShaderProgram::setAttributeBuffer + (const char *name, GLenum type, int offset, int tupleSize, int stride) +{ + setAttributeBuffer(attributeLocation(name), type, offset, tupleSize, stride); +} + +/*! Enables the vertex array at \a location in this shader program so that the value set by setAttributeArray() on \a location will be used by the shader program. @@ -1877,7 +2026,8 @@ void QGLShaderProgram::setUniformValue(int location, const QColor& color) Q_D(QGLShaderProgram); Q_UNUSED(d); if (location != -1) { - GLfloat values[4] = {color.redF(), color.greenF(), color.blueF(), color.alphaF()}; + GLfloat values[4] = {GLfloat(color.redF()), GLfloat(color.greenF()), + GLfloat(color.blueF()), GLfloat(color.alphaF())}; glUniform4fv(location, 1, values); } } @@ -1906,7 +2056,7 @@ void QGLShaderProgram::setUniformValue(int location, const QPoint& point) Q_D(QGLShaderProgram); Q_UNUSED(d); if (location != -1) { - GLfloat values[4] = {point.x(), point.y()}; + GLfloat values[4] = {GLfloat(point.x()), GLfloat(point.y())}; glUniform2fv(location, 1, values); } } @@ -1935,7 +2085,7 @@ void QGLShaderProgram::setUniformValue(int location, const QPointF& point) Q_D(QGLShaderProgram); Q_UNUSED(d); if (location != -1) { - GLfloat values[4] = {point.x(), point.y()}; + GLfloat values[4] = {GLfloat(point.x()), GLfloat(point.y())}; glUniform2fv(location, 1, values); } } @@ -1964,7 +2114,7 @@ void QGLShaderProgram::setUniformValue(int location, const QSize& size) Q_D(QGLShaderProgram); Q_UNUSED(d); if (location != -1) { - GLfloat values[4] = {size.width(), size.width()}; + GLfloat values[4] = {GLfloat(size.width()), GLfloat(size.width())}; glUniform2fv(location, 1, values); } } @@ -1993,7 +2143,7 @@ void QGLShaderProgram::setUniformValue(int location, const QSizeF& size) Q_D(QGLShaderProgram); Q_UNUSED(d); if (location != -1) { - GLfloat values[4] = {size.width(), size.height()}; + GLfloat values[4] = {GLfloat(size.width()), GLfloat(size.height())}; glUniform2fv(location, 1, values); } } @@ -2307,6 +2457,42 @@ void QGLShaderProgram::setUniformValue(const char *name, const QMatrix4x4& value \overload Sets the uniform variable at \a location in the current context + to a 2x2 matrix \a value. The matrix elements must be specified + in column-major order. + + \sa setAttributeValue() + \since 4.7 +*/ +void QGLShaderProgram::setUniformValue(int location, const GLfloat value[2][2]) +{ + Q_D(QGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + glUniformMatrix2fv(location, 1, GL_FALSE, value[0]); +} + +/*! + \overload + + Sets the uniform variable at \a location in the current context + to a 3x3 matrix \a value. The matrix elements must be specified + in column-major order. + + \sa setAttributeValue() + \since 4.7 +*/ +void QGLShaderProgram::setUniformValue(int location, const GLfloat value[3][3]) +{ + Q_D(QGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + glUniformMatrix3fv(location, 1, GL_FALSE, value[0]); +} + +/*! + \overload + + Sets the uniform variable at \a location in the current context to a 4x4 matrix \a value. The matrix elements must be specified in column-major order. @@ -2320,6 +2506,37 @@ void QGLShaderProgram::setUniformValue(int location, const GLfloat value[4][4]) glUniformMatrix4fv(location, 1, GL_FALSE, value[0]); } + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 2x2 matrix \a value. The matrix elements must be specified + in column-major order. + + \sa setAttributeValue() + \since 4.7 +*/ +void QGLShaderProgram::setUniformValue(const char *name, const GLfloat value[2][2]) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 3x3 matrix \a value. The matrix elements must be specified + in column-major order. + + \sa setAttributeValue() + \since 4.7 +*/ +void QGLShaderProgram::setUniformValue(const char *name, const GLfloat value[3][3]) +{ + setUniformValue(uniformLocation(name), value); +} + /*! \overload @@ -2347,9 +2564,9 @@ void QGLShaderProgram::setUniformValue(int location, const QTransform& value) Q_UNUSED(d); if (location != -1) { GLfloat mat[3][3] = { - {value.m11(), value.m12(), value.m13()}, - {value.m21(), value.m22(), value.m23()}, - {value.m31(), value.m32(), value.m33()} + {GLfloat(value.m11()), GLfloat(value.m12()), GLfloat(value.m13())}, + {GLfloat(value.m21()), GLfloat(value.m22()), GLfloat(value.m23())}, + {GLfloat(value.m31()), GLfloat(value.m32()), GLfloat(value.m33())} }; glUniformMatrix3fv(location, 1, GL_FALSE, mat[0]); } @@ -2862,6 +3079,108 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x4 * #undef ctx /*! + Returns the hardware limit for how many vertices a geometry shader + can output. + + \since 4.7 + + \sa setGeometryOutputVertexCount() +*/ +int QGLShaderProgram::maxGeometryOutputVertices() const +{ + GLint n; + glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT, &n); + return n; +} + +/*! + Sets the maximum number of vertices the current geometry shader + program will produce, if active, to \a count. + + \since 4.7 + + This parameter takes effect the next time the program is linked. +*/ +void QGLShaderProgram::setGeometryOutputVertexCount(int count) +{ +#ifndef QT_NO_DEBUG + int max = maxGeometryOutputVertices(); + if (count > max) { + qWarning("QGLShaderProgram::setGeometryOutputVertexCount: count: %d higher than maximum: %d", + count, max); + } +#endif + d_func()->geometryVertexCount = count; +} + + +/*! + Returns the maximum number of vertices the current geometry shader + program will produce, if active. + + \since 4.7 + + This parameter takes effect the ntext time the program is linked. +*/ +int QGLShaderProgram::geometryOutputVertexCount() const +{ + return d_func()->geometryVertexCount; +} + + +/*! + Sets the input type from \a inputType. + + This parameter takes effect the next time the program is linked. +*/ +void QGLShaderProgram::setGeometryInputType(GLenum inputType) +{ + d_func()->geometryInputType = inputType; +} + + +/*! + Returns the geometry shader input type, if active. + + This parameter takes effect the next time the program is linked. + + \since 4.7 + */ + +GLenum QGLShaderProgram::geometryInputType() const +{ + return d_func()->geometryInputType; +} + + +/*! + Sets the output type from the geometry shader, if active, to + \a outputType. + + This parameter takes effect the next time the program is linked. + + \since 4.7 +*/ +void QGLShaderProgram::setGeometryOutputType(GLenum outputType) +{ + d_func()->geometryOutputType = outputType; +} + + +/*! + Returns the geometry shader output type, if active. + + This parameter takes effect the next time the program is linked. + + \since 4.7 + */ +GLenum QGLShaderProgram::geometryOutputType() const +{ + return d_func()->geometryOutputType; +} + + +/*! Returns true if shader programs written in the OpenGL Shading Language (GLSL) are supported on this system; false otherwise. @@ -2893,8 +3212,71 @@ void QGLShaderProgram::shaderDestroyed() removeShader(shader); } + +#undef ctx +#undef context + +/*! + Returns true if shader programs of type \a type are supported on + this system; false otherwise. + + The \a context is used to resolve the GLSL extensions. + If \a context is null, then QGLContext::currentContext() is used. + + \since 4.7 +*/ +bool QGLShader::hasOpenGLShaders(ShaderType type, const QGLContext *context) +{ + if (!context) + context = QGLContext::currentContext(); + if (!context) + return false; + + if ((type & ~(Geometry | Vertex | Fragment)) || type == 0) + return false; + + bool resolved = qt_resolve_glsl_extensions(const_cast<QGLContext *>(context)); + if (!resolved) + return false; + + if ((type & Geometry) && !QByteArray((const char *) glGetString(GL_EXTENSIONS)).contains("GL_EXT_geometry_shader4")) + return false; + + return true; +} + + + #ifdef Q_MAC_COMPAT_GL_FUNCTIONS /*! \internal */ +void QGLShaderProgram::setAttributeArray + (int location, QMacCompatGLenum type, const void *values, int tupleSize, int stride) +{ + setAttributeArray(location, GLenum(type), values, tupleSize, stride); +} + +/*! \internal */ +void QGLShaderProgram::setAttributeArray + (const char *name, QMacCompatGLenum type, const void *values, int tupleSize, int stride) +{ + setAttributeArray(name, GLenum(type), values, tupleSize, stride); +} + +/*! \internal */ +void QGLShaderProgram::setAttributeBuffer + (int location, QMacCompatGLenum type, int offset, int tupleSize, int stride) +{ + setAttributeBuffer(location, GLenum(type), offset, tupleSize, stride); +} + +/*! \internal */ +void QGLShaderProgram::setAttributeBuffer + (const char *name, QMacCompatGLenum type, int offset, int tupleSize, int stride) +{ + setAttributeBuffer(name, GLenum(type), offset, tupleSize, stride); +} + +/*! \internal */ void QGLShaderProgram::setUniformValue(int location, QMacCompatGLint value) { setUniformValue(location, GLint(value)); @@ -2943,6 +3325,6 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QMacCompatGL } #endif -#endif // !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) +#endif // !defined(QT_OPENGL_ES_1) QT_END_NAMESPACE |