From 66d8c5030b51c00277069cd7a66175f481522b2b Mon Sep 17 00:00:00 2001 From: Rivo Laks Date: Mon, 5 Feb 2007 18:11:15 +0000 Subject: [PATCH] Add GLSL shader support and GLShader class. Add two preprocessor macros to simplify resolving of OpenGL functions. svn path=/branches/work/kwin_composite/; revision=630553 --- glutils.cpp | 262 +++++++++++++++++++++++++++++++++++++++++++++++++++- glutils.h | 83 +++++++++++++++++ 2 files changed, 342 insertions(+), 3 deletions(-) diff --git a/glutils.cpp b/glutils.cpp index d2883a470f..cba3496f1d 100644 --- a/glutils.cpp +++ b/glutils.cpp @@ -10,11 +10,23 @@ License. See the file "COPYING" for the exact licensing terms. #include "glutils.h" +#include +#include + #include #define MAKE_GL_VERSION(major, minor, release) ( ((major) << 16) | ((minor) << 8) | (release) ) +// Resolves given function, using getProcAddress +#define GL_RESOLVE( function ) function = (function ## _func)getProcAddress( #function ); +// Same as above but tries to use function "backup" if "function" doesn't exist +// Useful when same functionality is also defined in an extension +#define GL_RESOLVE_WITH_EXT( function, backup ) \ + function = (function ## _func)getProcAddress( #function ); \ + if( !function ) \ + function = (function ## _func)getProcAddress( #backup ); + namespace KWinInternal { @@ -59,6 +71,28 @@ glFramebufferTexture3D_func glFramebufferTexture3D; glFramebufferRenderbuffer_func glFramebufferRenderbuffer; glGetFramebufferAttachmentParameteriv_func glGetFramebufferAttachmentParameteriv; glGenerateMipmap_func glGenerateMipmap; +// Shader functions +glCreateShader_func glCreateShader; +glShaderSource_func glShaderSource; +glCompileShader_func glCompileShader; +glDeleteShader_func glDeleteShader; +glCreateProgram_func glCreateProgram; +glAttachShader_func glAttachShader; +glLinkProgram_func glLinkProgram; +glUseProgram_func glUseProgram; +glDeleteProgram_func glDeleteProgram; +glGetShaderInfoLog_func glGetShaderInfoLog; +glGetProgramInfoLog_func glGetProgramInfoLog; +glGetProgramiv_func glGetProgramiv; +glGetShaderiv_func glGetShaderiv; +glUniform1f_func glUniform1f; +glUniform1i_func glUniform1i; +glUniform1fv_func glUniform1fv; +glUniform2fv_func glUniform2fv; +glValidateProgram_func glValidateProgram; +glGetUniformLocation_func glGetUniformLocation; +glVertexAttrib1f_func glVertexAttrib1f; +glGetAttribLocation_func glGetAttribLocation; // Functions @@ -126,9 +160,7 @@ void initGL() // handle OpenGL extensions functions if( hasGLExtension( "GL_ARB_multitexture" )) { - glActiveTexture = (glActiveTexture_func) getProcAddress( "glActiveTexture" ); - if( !glActiveTexture ) - glActiveTexture = (glActiveTexture_func) getProcAddress( "glActiveTextureARB" ); + GL_RESOLVE_WITH_EXT( glActiveTexture, glActiveTextureARB ); // Get number of texture units glGetIntegerv(GL_MAX_TEXTURE_UNITS, &glTextureUnitsCount); } @@ -185,6 +217,30 @@ void initGL() glGetFramebufferAttachmentParameteriv = NULL; glGenerateMipmap = NULL; } + if( hasGLExtension( "GL_ARB_shading_language_100" ) && hasGLExtension( "GL_ARB_fragment_shader" )) + { + GL_RESOLVE_WITH_EXT( glCreateShader, glCreateShaderObjectARB ); + GL_RESOLVE_WITH_EXT( glShaderSource, glShaderSourceARB ); + GL_RESOLVE_WITH_EXT( glCompileShader, glCompileShaderARB ); + GL_RESOLVE_WITH_EXT( glDeleteShader, glDeleteObjectARB ); + GL_RESOLVE_WITH_EXT( glCreateProgram, glCreateProgramObjectARB ); + GL_RESOLVE_WITH_EXT( glAttachShader, glAttachObjectARB ); + GL_RESOLVE_WITH_EXT( glLinkProgram, glLinkProgramARB ); + GL_RESOLVE_WITH_EXT( glUseProgram, glUseProgramObjectARB ); + GL_RESOLVE_WITH_EXT( glDeleteProgram, glDeleteObjectARB ); + GL_RESOLVE_WITH_EXT( glGetShaderInfoLog, glGetInfoLogARB ); + GL_RESOLVE_WITH_EXT( glGetProgramInfoLog, glGetInfoLogARB ); + GL_RESOLVE_WITH_EXT( glGetProgramiv, glGetObjectParameterivARB ); + GL_RESOLVE_WITH_EXT( glGetShaderiv, glGetObjectParameterivARB ); + GL_RESOLVE_WITH_EXT( glUniform1f, glUniform1fARB ); + GL_RESOLVE_WITH_EXT( glUniform1i, glUniform1iARB ); + GL_RESOLVE_WITH_EXT( glUniform1fv, glUniform1fvARB ); + GL_RESOLVE_WITH_EXT( glUniform2fv, glUniform2fvARB ); + GL_RESOLVE_WITH_EXT( glValidateProgram, glValidateProgramARB ); + GL_RESOLVE_WITH_EXT( glGetUniformLocation, glGetUniformLocationARB ); + GL_RESOLVE_WITH_EXT( glVertexAttrib1f, glVertexAttrib1fARB ); + GL_RESOLVE_WITH_EXT( glGetAttribLocation, glGetAttribLocationARB ); + } } bool hasGLVersion(int major, int minor, int release) @@ -202,4 +258,204 @@ bool hasGLExtension(const QString& extension) return glExtensions.contains(extension); } + + +GLShader::GLShader(const QString& vertexfile, const QString& fragmentfile) + { + mValid = false; + mVariableLocations = 0; + + loadFromFiles(vertexfile, fragmentfile); + } + +bool GLShader::loadFromFiles(const QString& vertexfile, const QString& fragmentfile) + { + QFile vf(vertexfile); + if(!vf.open(IO_ReadOnly)) + { + kError(1212) << k_funcinfo << "Couldn't open '" << vertexfile << "' for reading!" << endl; + return false; + } + QString vertexsource(vf.readAll()); + + QFile ff(fragmentfile); + if(!ff.open(IO_ReadOnly)) + { + kError(1212) << k_funcinfo << "Couldn't open '" << fragmentfile << "' for reading!" << endl; + return false; + } + QString fragsource(ff.readAll()); + + return load(vertexsource, fragsource); + } + +bool GLShader::load(const QString& vertexsource, const QString& fragmentsource) + { + GLuint vertexshader; + GLuint fragmentshader; + + GLsizei logsize, logarraysize; + char* log = 0; + + // Create program object + mProgram = glCreateProgram(); + if(!vertexsource.isEmpty()) + { + // Create shader object + vertexshader = glCreateShader(GL_VERTEX_SHADER); + // Load it + const QByteArray& srcba = vertexsource.toLatin1(); + const char* src = srcba.data(); + glShaderSource(vertexshader, 1, &src, NULL); + // Compile the shader + glCompileShader(vertexshader); + // Make sure it compiled correctly + int compiled; + glGetShaderiv(fragmentshader, GL_COMPILE_STATUS, &compiled); + // Get info log + glGetShaderiv(vertexshader, GL_INFO_LOG_LENGTH, &logarraysize); + log = new char[logarraysize]; + glGetShaderInfoLog(vertexshader, logarraysize, &logsize, log); + if(!compiled) + { + kError(1212) << k_funcinfo << "Couldn't compile vertex shader! Log:" << endl << log << endl; + delete[] log; + return false; + } + else if(logsize > 0) + kDebug(1212) << "Vertex shader compilation log:" << endl << log << endl; + // Attach the shader to the program + glAttachShader(mProgram, vertexshader); + // Delete shader + glDeleteShader(vertexshader); + delete[] log; + } + + + if(!fragmentsource.isEmpty()) + { + fragmentshader = glCreateShader(GL_FRAGMENT_SHADER); + // Load it + const QByteArray& srcba = fragmentsource.toLatin1(); + const char* src = srcba.data(); + glShaderSource(fragmentshader, 1, &src, NULL); + //glShaderSource(fragmentshader, 1, &fragmentsrc.latin1(), NULL); + // Compile the shader + glCompileShader(fragmentshader); + // Make sure it compiled correctly + int compiled; + glGetShaderiv(fragmentshader, GL_COMPILE_STATUS, &compiled); + // Get info log + glGetShaderiv(fragmentshader, GL_INFO_LOG_LENGTH, &logarraysize); + log = new char[logarraysize]; + glGetShaderInfoLog(fragmentshader, logarraysize, &logsize, log); + if(!compiled) + { + kError(1212) << k_funcinfo << "Couldn't compile fragment shader! Log:" << endl << log << endl; + delete[] log; + return false; + } + else if(logsize > 0) + kDebug(1212) << "Fragment shader compilation log:" << endl << log << endl; + // Attach the shader to the program + glAttachShader(mProgram, fragmentshader); + // Delete shader + glDeleteShader(fragmentshader); + delete[] log; + } + + + // Link the program + glLinkProgram(mProgram); + // Make sure it linked correctly + int linked; + glGetProgramiv(mProgram, GL_LINK_STATUS, &linked); + // Get info log + glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &logarraysize); + log = new char[logarraysize]; + glGetProgramInfoLog(mProgram, logarraysize, &logsize, log); + if(!linked) + { + kError(1212) << k_funcinfo << "Couldn't link the program! Log" << endl << log << endl; + delete[] log; + return false; + } + else if(logsize > 0) + kDebug(1212) << "Shader linking log:" << endl << log << endl; + delete[] log; + + mVariableLocations = new QHash; + + mValid = true; + return true; + } + +void GLShader::bind() + { + glUseProgram(mProgram); + } + +void GLShader::unbind() + { + glUseProgram(0); + } + +int GLShader::uniformLocation(const QString& name) + { + if(!mVariableLocations) + { + return -1; + } + if(!mVariableLocations->contains(name)) + { + int location = glGetUniformLocation(mProgram, name.toLatin1().data()); + mVariableLocations->insert(name, location); + } + return mVariableLocations->value(name); + } + +bool GLShader::setUniform(const QString& name, float value) + { + int location = uniformLocation(name); + if(location >= 0) + { + glUniform1f(location, value); + } + return (location >= 0); + } + +bool GLShader::setUniform(const QString& name, int value) + { + int location = uniformLocation(name); + if(location >= 0) + { + glUniform1i(location, value); + } + return (location >= 0); + } + +int GLShader::attributeLocation(const QString& name) + { + if(!mVariableLocations) + { + return -1; + } + if(!mVariableLocations->contains(name)) + { + int location = glGetAttribLocation(mProgram, name.toLatin1().data()); + mVariableLocations->insert(name, location); + } + return mVariableLocations->value(name); + } + +bool GLShader::setAttribute(const QString& name, float value) + { + int location = attributeLocation(name); + if(location >= 0) + { + glVertexAttrib1f(location, value); + } + return (location >= 0); + } + } // namespace diff --git a/glutils.h b/glutils.h index 362825ab41..6c2606102a 100644 --- a/glutils.h +++ b/glutils.h @@ -21,6 +21,8 @@ License. See the file "COPYING" for the exact licensing terms. #include #include +template< class K, class V > class QHash; + namespace KWinInternal { @@ -45,6 +47,35 @@ bool hasGLExtension(const QString& extension); inline bool isPowerOfTwo( int x ) { return (( x & ( x - 1 )) == 0 ); } + +class GLShader + { + public: + GLShader(const QString& vertexfile, const QString& fragmentfile); + + bool isValid() const { return mValid; } + void bind(); + void unbind(); + + int uniformLocation(const QString& name); + bool setUniform(const QString& name, float value); + bool setUniform(const QString& name, int value); + int attributeLocation(const QString& name); + bool setAttribute(const QString& name, float value); + + + protected: + bool loadFromFiles(const QString& vertexfile, const QString& fragmentfile); + bool load(const QString& vertexsource, const QString& fragmentsource); + + + private: + unsigned int mProgram; + bool mValid; + QHash< QString, int >* mVariableLocations; + }; + + // Defines /* ** GLX_EXT_texture_from_pixmap @@ -73,6 +104,14 @@ inline bool isPowerOfTwo( int x ) { return (( x & ( x - 1 )) == 0 ); } #define GLX_FRONT_LEFT_EXT 0x20DE +// Shader stuff +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 + + // Function pointers // finding of OpenGL extensions functions typedef void (*glXFuncPtr)(); @@ -134,6 +173,50 @@ extern glFramebufferTexture3D_func glFramebufferTexture3D; extern glFramebufferRenderbuffer_func glFramebufferRenderbuffer; extern glGetFramebufferAttachmentParameteriv_func glGetFramebufferAttachmentParameteriv; extern glGenerateMipmap_func glGenerateMipmap; +// Shader stuff +typedef GLuint (*glCreateShader_func)(GLenum); +typedef GLvoid (*glShaderSource_func)(GLuint, GLsizei, const GLchar**, const GLint*); +typedef GLvoid (*glCompileShader_func)(GLuint); +typedef GLvoid (*glDeleteShader_func)(GLuint); +typedef GLuint (*glCreateProgram_func)(); +typedef GLvoid (*glAttachShader_func)(GLuint, GLuint); +typedef GLvoid (*glLinkProgram_func)(GLuint); +typedef GLvoid (*glUseProgram_func)(GLuint); +typedef GLvoid (*glDeleteProgram_func)(GLuint); +typedef GLvoid (*glGetShaderInfoLog_func)(GLuint, GLsizei, GLsizei*, GLchar*); +typedef GLvoid (*glGetProgramInfoLog_func)(GLuint, GLsizei, GLsizei*, GLchar*); +typedef GLvoid (*glGetProgramiv_func)(GLuint, GLenum, GLint*); +typedef GLvoid (*glGetShaderiv_func)(GLuint, GLenum, GLint*); +typedef GLvoid (*glUniform1f_func)(GLint, GLfloat); +typedef GLvoid (*glUniform1i_func)(GLint, GLint); +typedef GLvoid (*glUniform1fv_func)(GLint, GLsizei, const GLfloat*); +typedef GLvoid (*glUniform2fv_func)(GLint, GLsizei, const GLfloat*); +typedef GLvoid (*glUniform3fv_func)(GLint, GLsizei, const GLfloat*); +typedef GLvoid (*glValidateProgram_func)(GLuint); +typedef GLint (*glGetUniformLocation_func)(GLuint, const GLchar*); +typedef GLvoid (*glVertexAttrib1f_func)(GLuint, GLfloat); +typedef GLint (*glGetAttribLocation_func)(GLuint, const GLchar*); +extern glCreateShader_func glCreateShader; +extern glShaderSource_func glShaderSource; +extern glCompileShader_func glCompileShader; +extern glDeleteShader_func glDeleteShader; +extern glCreateProgram_func glCreateProgram; +extern glAttachShader_func glAttachShader; +extern glLinkProgram_func glLinkProgram; +extern glUseProgram_func glUseProgram; +extern glDeleteProgram_func glDeleteProgram; +extern glGetShaderInfoLog_func glGetShaderInfoLog; +extern glGetProgramInfoLog_func glGetProgramInfoLog; +extern glGetProgramiv_func glGetProgramiv; +extern glGetShaderiv_func glGetShaderiv; +extern glUniform1f_func glUniform1f; +extern glUniform1i_func glUniform1i; +extern glUniform1fv_func glUniform1fv; +extern glUniform2fv_func glUniform2fv; +extern glValidateProgram_func glValidateProgram; +extern glGetUniformLocation_func glGetUniformLocation; +extern glVertexAttrib1f_func glVertexAttrib1f; +extern glGetAttribLocation_func glGetAttribLocation; } // namespace