Signed-off-by: Pekka Paalanen <[email protected]> --- plugins/opengl/include/opengl/framebufferobject.h | 102 +++++++++++ plugins/opengl/src/framebufferobject.cpp | 185 +++++++++++++++++++++ 2 files changed, 287 insertions(+), 0 deletions(-) create mode 100644 plugins/opengl/include/opengl/framebufferobject.h create mode 100644 plugins/opengl/src/framebufferobject.cpp
diff --git a/plugins/opengl/include/opengl/framebufferobject.h b/plugins/opengl/include/opengl/framebufferobject.h new file mode 100644 index 0000000..a830de7 --- /dev/null +++ b/plugins/opengl/include/opengl/framebufferobject.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2011 Collabora, Ltd. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Collabora Ltd. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Collabora Ltd. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * COLLABORA LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL COLLABORA LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Pekka Paalanen <[email protected]> + */ + +#ifndef _COMPIZ_GLFRAMEBUFFEROBJECT_H +#define _COMPIZ_GLFRAMEBUFFEROBJECT_H + +#include <opengl/opengl.h> + +struct PrivateGLFramebufferObject; + +/** + * Class representing a framebuffer object in GL, supporting only one + * color attachment as per GLES 2 spec. The color attachment is referred + * to as the texture (of the FBO). + * + * Usage: + * 1. create a GLFramebufferObject (requires a GL context) + * 2. call allocate (size), and check status () + * 3. old = bind () + * 4. do your rendering + * 5. rebind (old) + * 6. use the rendered texture via tex () + * 7. go to 2 or 3, or delete to quit (requires a GL context) + * + * TODO: add depth/stencil attachments + * FIXME: written for OpenGL ES 2 only, desktop OpenGL might not work. + */ +class GLFramebufferObject +{ + public: + GLFramebufferObject (); + ~GLFramebufferObject (); + + /** + * Ensure the texture is of the given size, recreating it if needed, + * and replace the FBO color attachment with it. The texture contents + * become undefined. The texture has RGBA channels. + * + * Returns true on success, and false on texture allocation failure. + */ + bool allocate (const CompSize &size); + + /** + * Bind this as the current FBO, previous binding in GL context is + * undone. GL rendering is now targeted to this FBO. + * Returns a pointer to the previously bound FBO, or NULL if + * the previous binding was zero (the window system provided + * framebuffer). + * + * The previous FBO is no longer bound, so you can use its + * texture. To restore the previous FBO, call rebind (FBO) with + * the returned pointer as the argument. + */ + GLFramebufferObject *bind (); + + /** + * Bind the given FBO as the current FBO, without looking up the + * previous binding. The argument can be NULL, in which case the + * window system provided framebuffer gets bound (FBO is unbound). + */ + static void rebind (GLFramebufferObject *fbo); + + /** + * Check the FBO completeness. Returns true on complete. + * Otherwise returns false and reports the error to log. + */ + bool checkStatus (); + + /** + * Return a pointer to the texture that is the color attachment. + * This will return NULL, if allocate () has not been called, or + * the last allocate () call failed. + */ + GLTexture *tex (); + + private: + PrivateGLFramebufferObject *priv; +}; + +#endif // _COMPIZ_GLFRAMEBUFFEROBJECT_H diff --git a/plugins/opengl/src/framebufferobject.cpp b/plugins/opengl/src/framebufferobject.cpp new file mode 100644 index 0000000..1c6997f --- /dev/null +++ b/plugins/opengl/src/framebufferobject.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2011 Collabora, Ltd. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Collabora Ltd. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Collabora Ltd. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * COLLABORA LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL COLLABORA LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Pekka Paalanen <[email protected]> + */ + +#include <map> +#include <opengl/framebufferobject.h> +#include <opengl/texture.h> + +struct PrivateGLFramebufferObject +{ + PrivateGLFramebufferObject () : + fboId (0), + glTex (NULL) + { + } + + void pushFBO (); + void popFBO (); + + GLuint fboId; + GLuint tmpId; + GLTexture *glTex; + + static std::map<GLuint, GLFramebufferObject *> idMap; +}; + +std::map<GLuint, GLFramebufferObject *> PrivateGLFramebufferObject::idMap; + +void PrivateGLFramebufferObject::pushFBO () +{ + GLint id = 0; + glGetIntegerv (GL_FRAMEBUFFER_BINDING, &id); + tmpId = id; + if (tmpId == fboId) + return; + + (*GL::bindFramebuffer) (GL_FRAMEBUFFER, fboId); +} + +void PrivateGLFramebufferObject::popFBO () +{ + if (tmpId != fboId) + (*GL::bindFramebuffer) (GL_FRAMEBUFFER, tmpId); +} + +GLFramebufferObject::GLFramebufferObject () : + priv (new PrivateGLFramebufferObject) +{ +#ifndef USE_GLES + compLogMessage ("opengl", CompLogLevelWarn, + "GLFramebufferObject may not work on desktop OpenGL"); +#endif + (*GL::genFramebuffers) (1, &priv->fboId); + if (priv->fboId != 0) + PrivateGLFramebufferObject::idMap[priv->fboId] = this; +} + +GLFramebufferObject::~GLFramebufferObject () +{ + if (priv->glTex) + GLTexture::decRef (priv->glTex); + + PrivateGLFramebufferObject::idMap.erase (priv->fboId); + (*GL::deleteFramebuffers) (1, &priv->fboId); + + delete priv; +} + +bool GLFramebufferObject::allocate (const CompSize &size) +{ + if (!priv->glTex || + size.width () != priv->glTex->width () || + size.height () != priv->glTex->height ()) + { + if (priv->glTex) + GLTexture::decRef (priv->glTex); + priv->glTex = NULL; + + GLTexture::List list = GLTexture::imageBufferToTexture (NULL, size); + if (list.size () != 1 || list[0] == NULL) + return false; + + priv->glTex = list[0]; + GLTexture::incRef (priv->glTex); + } + + priv->pushFBO (); + (*GL::framebufferTexture2D) (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + priv->glTex->target (), + priv->glTex->name (), 0); + priv->popFBO (); + return true; +} + +GLFramebufferObject *GLFramebufferObject::bind () +{ + GLFramebufferObject *old = NULL; + GLint id = 0; + + glGetIntegerv (GL_FRAMEBUFFER_BINDING, &id); + if (id != 0) + { + std::map<GLuint, GLFramebufferObject *>::iterator it; + it = PrivateGLFramebufferObject::idMap.find (id); + + if (it != PrivateGLFramebufferObject::idMap.end ()) + old = it->second; + else + compLogMessage ("opengl", CompLogLevelError, + "An FBO without GLFramebufferObject cannot be restored"); + } + + (*GL::bindFramebuffer) (GL_FRAMEBUFFER, priv->fboId); + + return old; +} + +// static +void GLFramebufferObject::rebind (GLFramebufferObject *fbo) +{ + GLuint id = fbo ? fbo->priv->fboId : 0; + (*GL::bindFramebuffer) (GL_FRAMEBUFFER, id); +} + +static const char *getFboErrorString (GLint status) +{ + switch (status) + { + case GL_FRAMEBUFFER_COMPLETE: + return "GL_FRAMEBUFFER_COMPLETE"; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; +#ifdef USE_GLES + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS"; +#endif + case GL_FRAMEBUFFER_UNSUPPORTED: + return "GL_FRAMEBUFFER_UNSUPPORTED"; + default: + return "unexpected status"; + } +} + +bool GLFramebufferObject::checkStatus () +{ + priv->pushFBO (); + GLint status = (*GL::checkFramebufferStatus) (GL_FRAMEBUFFER); + priv->popFBO (); + + if (status == GL_FRAMEBUFFER_COMPLETE) + return true; + + compLogMessage ("opengl", CompLogLevelError, + "FBO is incomplete: %s (0x%04x)", + getFboErrorString (status), status); + return false; +} + +GLTexture *GLFramebufferObject::tex () +{ + return priv->glTex; +} -- 1.7.3.4 _______________________________________________ dev mailing list [email protected] http://lists.compiz.org/mailman/listinfo/dev
