From cc1a7a9eca3b86c70f65c3731cfc6d64ca95f0ab Mon Sep 17 00:00:00 2001 From: Rivo Laks Date: Wed, 18 Apr 2007 15:22:13 +0000 Subject: [PATCH] Add GLRenderTarget class. The render target is used to render the scene (or part of it) onto texture. This texture can then be used e.g. to do some postprocessing. Demo effect coming soon. Move checkGLError() to kwineffects.* Add GLTexture ctor which takes width and height and creates an empty texture (to be used with GLRenderTarget to render onto it) svn path=/branches/work/kwin_composite/; revision=655489 --- lib/kwinglutils.cpp | 96 +++++++++++++++++++++++++++++++++++++++++++++ lib/kwinglutils.h | 47 ++++++++++++++++++++++ scene_opengl.cpp | 8 ---- 3 files changed, 143 insertions(+), 8 deletions(-) diff --git a/lib/kwinglutils.cpp b/lib/kwinglutils.cpp index 43afde79b3..9f7b8e4517 100644 --- a/lib/kwinglutils.cpp +++ b/lib/kwinglutils.cpp @@ -18,6 +18,7 @@ License. See the file "COPYING" for the exact licensing terms. #include #include #include +#include #define MAKE_GL_VERSION(major, minor, release) ( ((major) << 16) | ((minor) << 8) | (release) ) @@ -90,6 +91,13 @@ bool hasGLExtension(const QString& extension) return glExtensions.contains(extension); } +void checkGLError( const char* txt ) + { + GLenum err = glGetError(); + if( err != GL_NO_ERROR ) + kWarning() << "GL error (" << txt << "): 0x" << QString::number( err, 16 ) << endl; + } + int nearestPowerOfTwo( int x ) { // This method had been copied from Qt's nearest_gl_texture_size() @@ -138,6 +146,24 @@ GLTexture::GLTexture( const QString& fileName ) load( fileName ); } +GLTexture::GLTexture( int width, int height ) + { + init(); + + if( NPOTTextureSupported() || ( isPowerOfTwo( width ) && isPowerOfTwo( height ))) + { + mTarget = GL_TEXTURE_2D; + mScale.setWidth( 1.0 ); + mScale.setHeight( 1.0 ); + can_use_mipmaps = true; + + glGenTextures( 1, &mTexture ); + bind(); + glTexImage2D( mTarget, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + unbind(); + } + } + GLTexture::~GLTexture() { discard(); @@ -591,6 +617,76 @@ bool GLShader::setAttribute(const QString& name, float value) return (location >= 0); } + + +/*** GLRenderTarget ***/ +GLRenderTarget::GLRenderTarget(GLTexture* color) + { + // Reset variables + mValid = false; + + mTexture = color; + + // Make sure FBO is supported + if(hasGLExtension("GL_EXT_framebuffer_object") && glFramebufferTexture2D && + mTexture && !mTexture->isNull()) + { + initFBO(); + } + } + +GLRenderTarget::~GLRenderTarget() + { + if(mValid) + { + glDeleteFramebuffers(1, &mFramebuffer); + } + } + +bool GLRenderTarget::enable() + { + if(!valid()) + { + kError(1212) << k_funcinfo << "Can't enable invalid render target!" << endl; + return false; + } + + glBindFramebuffer(GL_FRAMEBUFFER_EXT, mFramebuffer); + + return true; + } + +bool GLRenderTarget::disable() + { + if(!valid()) + { + kError(1212) << k_funcinfo << "Can't disable invalid render target!" << endl; + return false; + } + + glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); + mTexture->setDirty(); + + return true; + } + +void GLRenderTarget::initFBO() + { + glGenFramebuffers(1, &mFramebuffer); + glBindFramebuffer(GL_FRAMEBUFFER_EXT, mFramebuffer); + + glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, mTexture->texture(), 0); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT); + if(status != GL_FRAMEBUFFER_COMPLETE_EXT) + { + kError(1212) << k_funcinfo << "Invalid fb status: " << status << endl; + } + + glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); + + mValid = true; + } #endif } // namespace diff --git a/lib/kwinglutils.h b/lib/kwinglutils.h index 9bc9aaa3bc..bef11250e5 100644 --- a/lib/kwinglutils.h +++ b/lib/kwinglutils.h @@ -51,6 +51,9 @@ bool KWIN_EXPORT hasGLXVersion(int major, int minor, int release = 0); // use for both OpenGL and GLX extensions bool KWIN_EXPORT hasGLExtension(const QString& extension); +// detect OpenGL error (add to various places in code to pinpoint the place) +void KWIN_EXPORT checkGLError( const char* txt ); + inline bool KWIN_EXPORT isPowerOfTwo( int x ) { return (( x & ( x - 1 )) == 0 ); } int KWIN_EXPORT nearestPowerOfTwo( int x ); @@ -63,6 +66,7 @@ class KWIN_EXPORT GLTexture GLTexture( const QImage& image, GLenum target = GL_TEXTURE_2D ); GLTexture( const QPixmap& pixmap, GLenum target = GL_TEXTURE_2D ); GLTexture( const QString& fileName ); + GLTexture( int width, int height ); virtual ~GLTexture(); bool isNull() const; @@ -145,6 +149,49 @@ class KWIN_EXPORT GLShader static bool mVertexShaderSupported; }; +/** + * @short Render target object + * + * Render target object enables you to render onto a texture. This texture can + * later be used to e.g. do post-processing of the scene. + * + * @author Rivo Laks + **/ +class KWIN_EXPORT GLRenderTarget +{ + public: + /** + * Constructs a GLRenderTarget + * @param color texture where the scene will be rendered onto + **/ + GLRenderTarget(GLTexture* color); + ~GLRenderTarget(); + + /** + * Enables this render target. + * All OpenGL commands from now on affect this render target until the + * @ref disable method is called + **/ + bool enable(); + /** + * Disables this render target, activating whichever target was active + * when @ref enable was called. + **/ + bool disable(); + + bool valid() const { return mValid; } + + + protected: + void initFBO(); + + + private: + GLTexture* mTexture; + bool mValid; + + GLuint mFramebuffer; +}; #endif } // namespace diff --git a/scene_opengl.cpp b/scene_opengl.cpp index d2b406c6d9..4d5ddddbb9 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -97,14 +97,6 @@ XShmSegmentInfo SceneOpenGL::shm; #endif -// detect OpenGL error (add to various places in code to pinpoint the place) -static void checkGLError( const char* txt ) - { - GLenum err = glGetError(); - if( err != GL_NO_ERROR ) - kWarning() << "GL error (" << txt << "): 0x" << QString::number( err, 16 ) << endl; - } - SceneOpenGL::SceneOpenGL( Workspace* ws ) : Scene( ws ) {