From fe849f50ca83f50f6068b7d494cb228fae1d6309 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Mon, 1 Feb 2010 14:30:01 +0100 Subject: Geometry Shader support in QGLShaderProgram --- src/opengl/qglextensions.cpp | 6 ++ src/opengl/qglextensions_p.h | 46 ++++++++++++ src/opengl/qglshaderprogram.cpp | 153 ++++++++++++++++++++++++++++++++++++++++ src/opengl/qglshaderprogram.h | 24 ++++++- 4 files changed, 228 insertions(+), 1 deletion(-) diff --git a/src/opengl/qglextensions.cpp b/src/opengl/qglextensions.cpp index c091191..a4b2dc1 100644 --- a/src/opengl/qglextensions.cpp +++ b/src/opengl/qglextensions.cpp @@ -220,6 +220,12 @@ bool qt_resolve_buffer_extensions(QGLContext *ctx) bool qt_resolve_glsl_extensions(QGLContext *ctx) { + // Geometry shaders are optional... + glProgramParameteriEXT = (_glProgramParameteriEXT) ctx->getProcAddress(QLatin1String("glProgramParameteriEXT")); + glFramebufferTextureEXT = (_glFramebufferTextureEXT) ctx->getProcAddress(QLatin1String("glFramebufferTextureEXT")); + glFramebufferTextureLayerEXT = (_glFramebufferTextureLayerEXT) ctx->getProcAddress(QLatin1String("glFramebufferTextureLayerEXT")); + glFramebufferTextureFaceEXT = (_glFramebufferTextureFaceEXT) ctx->getProcAddress(QLatin1String("glFramebufferTextureFaceEXT")); + #if defined(QT_OPENGL_ES_2) // The GLSL shader functions are always present in OpenGL/ES 2.0. // The only exceptions are glGetProgramBinaryOES and glProgramBinaryOES. diff --git a/src/opengl/qglextensions_p.h b/src/opengl/qglextensions_p.h index 86096d2..e65e3a1 100644 --- a/src/opengl/qglextensions_p.h +++ b/src/opengl/qglextensions_p.h @@ -184,6 +184,15 @@ typedef void (APIENTRY *_glBlitFramebufferEXT) (int srcX0, int srcY0, int srcX1, typedef void (APIENTRY *_glRenderbufferStorageMultisampleEXT) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +// GL_EXT_geometry_shader4 +typedef void (APIENTRY *_glProgramParameteriEXT)(GLuint program, GLenum pname, GLint value); +typedef void (APIENTRY *_glFramebufferTextureEXT)(GLenum target, GLenum attachment, + GLuint texture, GLint level); +typedef void (APIENTRY *_glFramebufferTextureLayerEXT)(GLenum target, GLenum attachment, + GLuint texture, GLint level, GLint layer); +typedef void (APIENTRY *_glFramebufferTextureFaceEXT)(GLenum target, GLenum attachment, + GLuint texture, GLint level, GLenum face); + // ARB_texture_compression typedef void (APIENTRY *_glCompressedTexImage2DARB) (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); @@ -294,6 +303,10 @@ struct QGLExtensionFuncs qt_glMapBufferARB = 0; qt_glUnmapBufferARB = 0; + qt_glProgramParameteriEXT = 0; + qt_glFramebufferTextureEXT = 0; + qt_glFramebufferTextureLayerEXT = 0; + qt_glFramebufferTextureFaceEXT = 0; #if !defined(QT_OPENGL_ES) // Texture compression qt_glCompressedTexImage2DARB = 0; @@ -406,6 +419,11 @@ struct QGLExtensionFuncs _glMapBufferARB qt_glMapBufferARB; _glUnmapBufferARB qt_glUnmapBufferARB; + // Geometry shaders... + _glProgramParameteriEXT qt_glProgramParameteriEXT; + _glFramebufferTextureEXT qt_glFramebufferTextureEXT; + _glFramebufferTextureLayerEXT qt_glFramebufferTextureLayerEXT; + _glFramebufferTextureFaceEXT qt_glFramebufferTextureFaceEXT; #if !defined(QT_OPENGL_ES) // Texture compression _glCompressedTexImage2DARB qt_glCompressedTexImage2DARB; @@ -642,6 +660,29 @@ struct QGLExtensionFuncs #define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A #endif +// Geometry shader defines +#ifndef GL_GEOMETRY_SHADER_EXT +# define GL_GEOMETRY_SHADER_EXT 0x8DD9 +# define GL_GEOMETRY_VERTICES_OUT_EXT 0x8DDA +# define GL_GEOMETRY_INPUT_TYPE_EXT 0x8DDB +# define GL_GEOMETRY_OUTPUT_TYPE_EXT 0x8DDC +# define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29 +# define GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT 0x8DDD +# define GL_MAX_VERTEX_VARYING_COMPONENTS_EXT 0x8DDE +# define GL_MAX_VARYING_COMPONENTS_EXT 0x8B4B +# define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF +# define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0 +# define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1 +# define GL_LINES_ADJACENCY_EXT 0xA +# define GL_LINE_STRIP_ADJACENCY_EXT 0xB +# define GL_TRIANGLES_ADJACENCY_EXT 0xC +# define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0xD +# define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8 +# define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT 0x8DA9 +# define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7 +# define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4 +# define GL_PROGRAM_POINT_SIZE_EXT 0x8642 +#endif #if !defined(QT_OPENGL_ES_2) #define glProgramStringARB QGLContextPrivate::extensionFuncs(ctx).qt_glProgramStringARB @@ -759,6 +800,11 @@ struct QGLExtensionFuncs #define glClearDepth glClearDepthf #endif +#define glProgramParameteriEXT QGLContextPrivate::extensionFuncs(ctx).qt_glProgramParameteriEXT +#define glFramebufferTextureEXT QGLContextPrivate::extensionFuncs(ctx).qt_glFramebufferTextureEXT +#define glFramebufferTextureLayerEXT QGLContextPrivate::extensionFuncs(ctx).qt_glFramebufferTextureLayerEXT +#define glFramebufferTextureFaceEXT QGLContextPrivate::extensionFuncs(ctx).qt_glFramebufferTextureFaceEXT + #if !defined(QT_OPENGL_ES) #define glCompressedTexImage2D QGLContextPrivate::extensionFuncs(ctx).qt_glCompressedTexImage2DARB #endif diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp index 5e2f1f5..43d1df8 100644 --- a/src/opengl/qglshaderprogram.cpp +++ b/src/opengl/qglshaderprogram.cpp @@ -213,6 +213,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) { @@ -496,6 +498,10 @@ GLuint QGLShader::shaderId() const return d->shaderGuard.id(); } + + + + #undef ctx #define ctx programGuard.context() @@ -508,8 +514,12 @@ public: , linked(false) , inited(false) , removingShaders(false) + , geometryVertexCount(64) + , geometryInputType(0) + , geometryOutputType(0) , vertexShader(0) , fragmentShader(0) + , geometryShader(0) { } ~QGLShaderProgramPrivate(); @@ -518,11 +528,17 @@ public: bool linked; bool inited; bool removingShaders; + + int geometryVertexCount; + GLenum geometryInputType; + GLenum geometryOutputType; + QString log; QList shaders; QList anonShaders; QGLShader *vertexShader; QGLShader *fragmentShader; + QGLShader *geometryShader; bool hasShader(QGLShader::ShaderType type) const; }; @@ -820,6 +836,22 @@ bool QGLShaderProgram::link() GLuint program = d->programGuard.id(); if (!program) return false; + + // 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); GLint value = 0; glGetProgramiv(program, GL_LINK_STATUS, &value); @@ -2830,6 +2862,97 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x4 * #undef ctx /*! + Returns the hardware limit for how many vertices a geometry shader + can output. + + \sa setGeometryShaderOutputVertexCount +*/ +int QGLShaderProgram::maxGeometryOutputVertices() const +{ + int 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. + + 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. + + This parameter takes effect the ntext time the program is linked. +*/ +int QGLShaderProgram::geometryOutputVertexCount() const +{ + return d_func()->geometryVertexCount; +} + + +/*! + Sets the output type from the geometry shader, if active. + + 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. + */ + +GLenum QGLShaderProgram::geometryInputType() const +{ + return d_func()->geometryInputType; +} + + +/*! + Sets the output type from the geometry shader, if active. + + This parameter takes effect the next time the program is linked. +*/ +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. + */ +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. @@ -2861,6 +2984,36 @@ 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. +*/ +bool QGLShader::hasShaders(ShaderType type, const QGLContext *context) +{ +#if !defined(QT_OPENGL_ES_2) + if (!context) + context = QGLContext::currentContext(); + if (!context) + return false; +#endif + bool resolved = qt_resolve_glsl_extensions(const_cast(context)); + if (!resolved) + return false; + const QGLContext *ctx = context; + if ((type & Geometry) && !glProgramParameteriEXT) + return false; + return true; +} + + + #ifdef Q_MAC_COMPAT_GL_FUNCTIONS /*! \internal */ void QGLShaderProgram::setUniformValue(int location, QMacCompatGLint value) diff --git a/src/opengl/qglshaderprogram.h b/src/opengl/qglshaderprogram.h index 24ab986..face66e 100644 --- a/src/opengl/qglshaderprogram.h +++ b/src/opengl/qglshaderprogram.h @@ -66,7 +66,8 @@ public: enum ShaderTypeBit { Vertex = 0x0001, - Fragment = 0x0002 + Fragment = 0x0002, + Geometry = 0x0004 }; Q_DECLARE_FLAGS(ShaderType, ShaderTypeBit) @@ -88,6 +89,8 @@ public: GLuint shaderId() const; + static bool hasShaders(ShaderType type, const QGLContext *context = 0); + private: friend class QGLShaderProgram; @@ -104,6 +107,14 @@ class Q_OPENGL_EXPORT QGLShaderProgram : public QObject { Q_OBJECT public: + enum GeometryTypes + { + LinesWithAdjacencyGeometryType = 0xa, + LineStripWithAdjacencyGeometryType = 0xb, + TrianglesWithAdjacencyGeometryType = 0xc, + TriangleStripWithAdjacencyGeometryType = 0xd + }; + explicit QGLShaderProgram(QObject *parent = 0); explicit QGLShaderProgram(const QGLContext *context, QObject *parent = 0); virtual ~QGLShaderProgram(); @@ -128,6 +139,17 @@ public: GLuint programId() const; + int maxGeometryOutputVertices() const; + + void setGeometryOutputVertexCount(int count); + int geometryOutputVertexCount() const; + + void setGeometryInputType(GLenum inputType); + GLenum geometryInputType() const; + + void setGeometryOutputType(GLenum outputType); + GLenum geometryOutputType() const; + void bindAttributeLocation(const char *name, int location); void bindAttributeLocation(const QByteArray& name, int location); void bindAttributeLocation(const QString& name, int location); -- cgit v0.12 From 760319b312aceb2cc7438ad09eecd305c1b663e8 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Thu, 4 Feb 2010 06:48:30 -0800 Subject: Fix Geometry shaders based on review --- src/opengl/qglshaderprogram.cpp | 24 +++++++++++++++--------- src/opengl/qglshaderprogram.h | 2 +- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp index 43d1df8..7af488d 100644 --- a/src/opengl/qglshaderprogram.cpp +++ b/src/opengl/qglshaderprogram.cpp @@ -517,9 +517,6 @@ public: , geometryVertexCount(64) , geometryInputType(0) , geometryOutputType(0) - , vertexShader(0) - , fragmentShader(0) - , geometryShader(0) { } ~QGLShaderProgramPrivate(); @@ -536,9 +533,6 @@ public: QString log; QList shaders; QList anonShaders; - QGLShader *vertexShader; - QGLShader *fragmentShader; - QGLShader *geometryShader; bool hasShader(QGLShader::ShaderType type) const; }; @@ -564,6 +558,17 @@ bool QGLShaderProgramPrivate::hasShader(QGLShader::ShaderType type) const #define ctx d->programGuard.context() /*! + \enum GeometryTypes + + Defines the geometry types specificed by the GL_EXT_geometry_shader4 extension + + \value LinesWithAdjacencyGeometryType Corresponds to GL_LINES_ADJACENCY. + \value LineStripWithAdjacencyGeometryType Corresponds to GL_LINE_STRIP_ADJACENCY. + \value TrianglesWithAdjacencyGeometryType Corresponds to GL_TRIANGLES_ADJACENCY. + \value TriangleStripWithAdjacencyGeometryType Corresponds to GL_TRIANGLE_STRIP_ADJACENCY. + */ + +/*! Constructs a new shader program and attaches it to \a parent. The program will be invalid until addShader() is called. @@ -2995,7 +3000,7 @@ void QGLShaderProgram::shaderDestroyed() The \a context is used to resolve the GLSL extensions. If \a context is null, then QGLContext::currentContext() is used. */ -bool QGLShader::hasShaders(ShaderType type, const QGLContext *context) +bool QGLShader::hasOpenGLShaders(ShaderType type, const QGLContext *context) { #if !defined(QT_OPENGL_ES_2) if (!context) @@ -3006,9 +3011,10 @@ bool QGLShader::hasShaders(ShaderType type, const QGLContext *context) bool resolved = qt_resolve_glsl_extensions(const_cast(context)); if (!resolved) return false; - const QGLContext *ctx = context; - if ((type & Geometry) && !glProgramParameteriEXT) + + if ((type & Geometry) && !QByteArray((const char *) glGetString(GL_EXTENSIONS)).contains("GL_EXT_geometry_shader4")) return false; + return true; } diff --git a/src/opengl/qglshaderprogram.h b/src/opengl/qglshaderprogram.h index face66e..6dfbb77 100644 --- a/src/opengl/qglshaderprogram.h +++ b/src/opengl/qglshaderprogram.h @@ -89,7 +89,7 @@ public: GLuint shaderId() const; - static bool hasShaders(ShaderType type, const QGLContext *context = 0); + static bool hasOpenGLShaders(ShaderType type, const QGLContext *context = 0); private: friend class QGLShaderProgram; -- cgit v0.12 From e98c07e5247a5ad4876c4add595ec1897b73b190 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Mon, 8 Feb 2010 13:03:34 +0100 Subject: Another round of Geometry shader review. Reviewed-by: Trond --- src/opengl/qglshaderprogram.cpp | 18 +++++------------- src/opengl/qglshaderprogram.h | 16 ++++++++-------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp index 7af488d..22db731 100644 --- a/src/opengl/qglshaderprogram.cpp +++ b/src/opengl/qglshaderprogram.cpp @@ -558,17 +558,6 @@ bool QGLShaderProgramPrivate::hasShader(QGLShader::ShaderType type) const #define ctx d->programGuard.context() /*! - \enum GeometryTypes - - Defines the geometry types specificed by the GL_EXT_geometry_shader4 extension - - \value LinesWithAdjacencyGeometryType Corresponds to GL_LINES_ADJACENCY. - \value LineStripWithAdjacencyGeometryType Corresponds to GL_LINE_STRIP_ADJACENCY. - \value TrianglesWithAdjacencyGeometryType Corresponds to GL_TRIANGLES_ADJACENCY. - \value TriangleStripWithAdjacencyGeometryType Corresponds to GL_TRIANGLE_STRIP_ADJACENCY. - */ - -/*! Constructs a new shader program and attaches it to \a parent. The program will be invalid until addShader() is called. @@ -612,6 +601,7 @@ bool QGLShaderProgram::init() context = QGLContext::currentContext(); d->programGuard.setContext(context); } + if (!context) return false; if (qt_resolve_glsl_extensions(const_cast(context))) { @@ -3002,12 +2992,14 @@ void QGLShaderProgram::shaderDestroyed() */ bool QGLShader::hasOpenGLShaders(ShaderType type, const QGLContext *context) { -#if !defined(QT_OPENGL_ES_2) if (!context) context = QGLContext::currentContext(); if (!context) return false; -#endif + + if ((type & ~(Geometry | Vertex | Fragment)) || type == 0) + return false; + bool resolved = qt_resolve_glsl_extensions(const_cast(context)); if (!resolved) return false; diff --git a/src/opengl/qglshaderprogram.h b/src/opengl/qglshaderprogram.h index 6dfbb77..56034ee 100644 --- a/src/opengl/qglshaderprogram.h +++ b/src/opengl/qglshaderprogram.h @@ -103,18 +103,18 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QGLShader::ShaderType) class QGLShaderProgramPrivate; +#ifndef GL_EXT_geometry_shader4 +# define GL_LINES_ADJACENCY_EXT 0xA +# define GL_LINE_STRIP_ADJACENCY_EXT 0xB +# define GL_TRIANGLES_ADJACENCY_EXT 0xC +# define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0xD +#endif + + class Q_OPENGL_EXPORT QGLShaderProgram : public QObject { Q_OBJECT public: - enum GeometryTypes - { - LinesWithAdjacencyGeometryType = 0xa, - LineStripWithAdjacencyGeometryType = 0xb, - TrianglesWithAdjacencyGeometryType = 0xc, - TriangleStripWithAdjacencyGeometryType = 0xd - }; - explicit QGLShaderProgram(QObject *parent = 0); explicit QGLShaderProgram(const QGLContext *context, QObject *parent = 0); virtual ~QGLShaderProgram(); -- cgit v0.12