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

Reply via email to