]> git.tdb.fi Git - libs/gl.git/commitdiff
Rewrite Framebuffer to defer attach/detach operations until bound
authorMikko Rasa <tdb@tdb.fi>
Wed, 15 Sep 2010 19:14:55 +0000 (19:14 +0000)
committerMikko Rasa <tdb@tdb.fi>
Wed, 15 Sep 2010 19:14:55 +0000 (19:14 +0000)
Set draw buffer and depth mask automatically according to attachments
Treat system framebuffer as an object as well
Move the clear function inside the Framebuffer class
Use temporary binding in RenderBuffer::storage

source/framebuffer.cpp
source/framebuffer.h
source/pipeline.cpp
source/renderbuffer.cpp
source/shadowmap.cpp

index cf3761d0abb2d26d639ace3ac1a16c8ea9534cb9..8dbd2d0ee93bd20940b26326c1d2aaeb0c3f25a1 100644 (file)
@@ -17,152 +17,202 @@ using namespace std;
 namespace Msp {
 namespace GL {
 
+Framebuffer::Framebuffer(unsigned i):
+       id(i),
+       dirty(0)
+{
+       if(id)
+               throw InvalidParameterValue("System framebuffer must have id 0");
+
+       int viewport[4];
+       glGetIntegerv(GL_VIEWPORT, viewport);
+       width = viewport[2];
+       height = viewport[3];
+}
+
 Framebuffer::Framebuffer():
        width(0),
-       height(0)
+       height(0),
+       dirty(0)
 {
        static RequireExtension _ext("GL_EXT_framebuffer_object");
 
        glGenFramebuffersEXT(1, &id);
-       bind();
 }
 
 Framebuffer::~Framebuffer()
 {
-       glDeleteFramebuffersEXT(1, &id);
+       if(id)
+               glDeleteFramebuffersEXT(1, &id);
+       if(current()==this)
+               unbind();
 }
 
-void Framebuffer::bind() const
+void Framebuffer::update_attachment(unsigned mask) const
 {
-       const Framebuffer *old = current();
-       if(set_current(this))
+       if(current()==this)
        {
-               if(!old)
-                       get(GL_VIEWPORT, sys_viewport);
-               glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
-               if(width && height)
-                       viewport(0, 0, width, height);
+               bool has_color = false;
+               bool has_depth = false;
+               for(unsigned i=0; i<attachments.size(); ++i)
+               {
+                       const Attachment &attch = attachments[i];
+                       if(mask&(1<<i))
+                       {
+                               if(attch.type==GL_RENDERBUFFER_EXT)
+                                       glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attch.attachment, GL_RENDERBUFFER_EXT, attch.rbuf->get_id());
+                               else if(attch.type==GL_TEXTURE_2D)
+                                       glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attch.attachment, attch.type, attch.tex->get_id(), attch.level);
+                               else
+                                       glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attch.attachment, 0, 0);
+                       }
+
+                       if(attch.attachment>=COLOR_ATTACHMENT0 && attch.attachment<=COLOR_ATTACHMENT3)
+                               has_color = true;
+                       if(attch.attachment==DEPTH_ATTACHMENT)
+                               has_depth = true;
+               }
+
+               glDrawBuffer(has_color ? GL_FRONT : GL_NONE);
+               glDepthMask(has_depth);
        }
+       else
+               dirty |= mask;
+}
+
+void Framebuffer::check_size()
+{
+       for(vector<Attachment>::iterator i=attachments.begin(); i!=attachments.end(); ++i)
+               if(i->type)
+               {
+                       if(i->type==GL_RENDERBUFFER_EXT)
+                       {
+                               width = i->rbuf->get_width();
+                               height = i->rbuf->get_height();
+                       }
+                       else if(i->type==GL_TEXTURE_2D)
+                       {
+                               Texture2D *tex = static_cast<Texture2D *>(i->tex);
+                               width = tex->get_width();
+                               height = tex->get_height();
+                       }
+                       if(current()==this)
+                               glViewport(0, 0, width, height);
+                       break;
+               }
 }
 
 void Framebuffer::attach(FramebufferAttachment attch, Renderbuffer &rbuf)
 {
-       bind();
-       glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attch, GL_RENDERBUFFER_EXT, rbuf.get_id());
-       get_or_create_attachment(attch) = rbuf;
+       if(!id)
+               throw InvalidState("Can't attach to system framebuffer");
+
+       unsigned i = get_attachment_index(attch);
+       attachments[i].set(rbuf);
+       update_attachment(1<<i);
        check_size();
 }
 
 void Framebuffer::attach(FramebufferAttachment attch, Texture2D &tex, int level)
 {
-       bind();
-       glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attch, tex.get_target(), tex.get_id(), level);
-       get_or_create_attachment(attch) = tex;
+       if(!id)
+               throw InvalidState("Can't attach to system framebuffer");
+
+       unsigned i = get_attachment_index(attch);
+       attachments[i].set(tex, level);
+       update_attachment(1<<i);
        check_size();
 }
 
 void Framebuffer::detach(FramebufferAttachment attch)
 {
-       bind();
-       for(vector<Attachment>::iterator i=attachments.begin(); i!=attachments.end(); ++i)
-               if(i->attachment==attch)
-               {
-                       if(i->type==GL_RENDERBUFFER_EXT)
-                               glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attch, GL_RENDERBUFFER_EXT, 0);
-                       else if(i->type==GL_TEXTURE_2D)
-                               glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attch, GL_TEXTURE_2D, 0, 0);
-                       attachments.erase(i);
-                       check_size();
-                       return;
-               }
+       if(!id)
+               throw InvalidState("Can't detach from system framebuffer");
+
+       unsigned i = get_attachment_index(attch);
+       attachments[i].clear();
+       update_attachment(1<<i);
+       check_size();
 }
 
 FramebufferStatus Framebuffer::check_status() const
 {
-       bind();
+       Bind _bind(this, true);
        return static_cast<FramebufferStatus>(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
 }
 
-void Framebuffer::unbind()
+void Framebuffer::clear(BufferBits bits)
+{
+       Bind _bind(this, true);
+       glClear(bits);
+}
+
+void Framebuffer::bind() const
 {
-       if(set_current(0))
+       if(set_current(this))
        {
-               glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
-               viewport(sys_viewport[0], sys_viewport[1], sys_viewport[2], sys_viewport[3]);
+               glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
+               if(dirty)
+               {
+                       update_attachment(dirty);
+                       dirty = 0;
+               }
+               if(width && height)
+                       glViewport(0, 0, width, height);
        }
 }
 
-Framebuffer::Attachment &Framebuffer::get_or_create_attachment(FramebufferAttachment attch)
+const Framebuffer *Framebuffer::current()
+{      
+       if(!cur_obj)
+               cur_obj = &system();
+       return cur_obj;
+}
+
+void Framebuffer::unbind()
 {
-       for(vector<Attachment>::iterator i=attachments.begin(); i!=attachments.end(); ++i)
-               if(i->attachment==attch)
-                       return *i;
-       attachments.push_back(Attachment(attch));
-       return attachments.back();
+       system().bind();
 }
 
-void Framebuffer::check_size()
+Framebuffer &Framebuffer::system()
 {
-       if(!attachments.empty())
-       {
-               const Attachment &attch = attachments.front();
-               if(attch.type==GL_RENDERBUFFER_EXT)
-               {
-                       width = attch.rbuf->get_width();
-                       height = attch.rbuf->get_height();
-               }
-               else if(attch.type==GL_TEXTURE_2D)
-               {
-                       Texture2D *tex = static_cast<Texture2D *>(attch.tex);
-                       width = tex->get_width();
-                       height = tex->get_height();
-               }
-               if(current()==this)
-                       viewport(0, 0, width, height);
-       }
+       static Framebuffer sys_framebuf(0);
+       return sys_framebuf;
 }
 
-int Framebuffer::sys_viewport[4] = { 0, 0, 1, 1 };
+unsigned Framebuffer::get_attachment_index(FramebufferAttachment attch)
+{
+       for(unsigned i=0; i<attachments.size(); ++i)
+               if(attachments[i].attachment==attch)
+                       return i;
+       attachments.push_back(Attachment(attch));
+       return attachments.size()-1;
+}
 
 
 Framebuffer::Attachment::Attachment(FramebufferAttachment a):
        attachment(a),
-       type(0)
+       type(0),
+       level(0)
 { }
 
-Framebuffer::Attachment &Framebuffer::Attachment::operator=(Renderbuffer &r)
+void Framebuffer::Attachment::set(Renderbuffer &r)
 {
        type = GL_RENDERBUFFER_EXT;
        rbuf = &r;
-       return *this;
+       level = 0;
 }
 
-Framebuffer::Attachment &Framebuffer::Attachment::operator=(Texture &t)
+void Framebuffer::Attachment::set(Texture &t, int l)
 {
        type = t.get_target();
        tex = &t;
-       return *this;
-}
-
-
-void viewport(int x, int y, unsigned w, unsigned h)
-{
-       glViewport(x, y, w, h);
-}
-
-void clear(BufferBits bits)
-{
-       glClear(bits);
-}
-
-void draw_buffer(RWBuffer buf)
-{
-       glDrawBuffer(buf);
+       level = l;
 }
 
-void read_buffer(RWBuffer buf)
+void Framebuffer::Attachment::clear()
 {
-       glReadBuffer(buf);
+       type = 0;
 }
 
 } // namespace GL
index b4f43f77f47473a12381eb499eb13a3c6d658c13..514208d6db161fd3635f39538760bc6435160b94 100644 (file)
@@ -86,25 +86,29 @@ private:
                        Renderbuffer *rbuf;
                        Texture *tex;
                };
+               int level;
 
                Attachment(FramebufferAttachment);
-               Attachment &operator=(Renderbuffer &);
-               Attachment &operator=(Texture &);
+               void set(Renderbuffer &);
+               void set(Texture &, int);
+               void clear();
        };
 
        unsigned id;
        std::vector<Attachment> attachments;
        unsigned width;
        unsigned height;
+       mutable unsigned dirty;
 
-       static int sys_viewport[4];
-
+       Framebuffer(unsigned);
 public:
        Framebuffer();
        ~Framebuffer();
 
-       void bind() const;
-
+private:
+       void update_attachment(unsigned) const;
+       void check_size();
+public:
        void attach(FramebufferAttachment attch, Renderbuffer &rbuf);
        void attach(FramebufferAttachment attch, Texture2D &tex, int level);
        void detach(FramebufferAttachment attch);
@@ -116,21 +120,24 @@ public:
        */
        FramebufferStatus check_status() const;
 
+       void clear(BufferBits);
+
+       void bind() const;
+
+       static const Framebuffer *current();
        static void unbind();
+
+       static Framebuffer &system();
 private:
-       void maybe_bind() const;
-       Attachment &get_or_create_attachment(FramebufferAttachment);
-       void check_size();
+       unsigned get_attachment_index(FramebufferAttachment);
+
+public:
+       
 };
 
 inline BufferBits operator|(BufferBits a, BufferBits b)
 { return static_cast<BufferBits>(static_cast<int>(a)|static_cast<int>(b)); }
 
-void viewport(int, int, unsigned, unsigned);
-void clear(BufferBits);
-void draw_buffer(RWBuffer);
-void read_buffer(RWBuffer);
-
 } // namespace GL
 } // namespace Msp
 
index 54ef25a10bca8e59a123eb96322123e393595640..517037a0029785198fd724c44e5c92943f11ee82 100644 (file)
@@ -95,7 +95,6 @@ void Pipeline::add_postprocessor(PostProcessor &pp)
                depth_buf = new Renderbuffer;
                depth_buf->storage(DEPTH_COMPONENT, width, height);
                fbo->attach(DEPTH_ATTACHMENT, *depth_buf);
-               Framebuffer::unbind();
        }
 }
 
@@ -125,7 +124,7 @@ void Pipeline::render_all() const
        if(fbo)
        {
                fbo->bind();
-               clear(COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT);
+               fbo->clear(COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT);
        }
 
        for(vector<Effect *>::const_iterator i=effects.begin(); i!=effects.end(); ++i)
index 0d3a76b57b125af9dd470b24d9da79431b1871b4..95cf56b8a06f49a8dcb0984936a5f86bc11fc405 100644 (file)
@@ -27,7 +27,7 @@ Renderbuffer::~Renderbuffer()
 
 void Renderbuffer::storage(PixelFormat fmt, unsigned w, unsigned h)
 {
-       bind();
+       Bind _bind(this, true);
        width = w;
        height = h;
        glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, fmt, width, height);
index 25b0d6d66f4345246f120b2087c9766fd71143d3..bedfcfd51c0f1e2aa4d1f5bd374e1c5b8a342620 100644 (file)
@@ -34,8 +34,6 @@ ShadowMap::ShadowMap(unsigned s, const Scene &c, const Light &l):
        depth_buf.storage(DEPTH_COMPONENT, size, size, 0);
        depth_buf.image(0, DEPTH_COMPONENT, UNSIGNED_BYTE, 0);
        fbo.attach(DEPTH_ATTACHMENT, depth_buf, 0);
-       draw_buffer(NO_BUFFER);
-       Framebuffer::unbind();
 }
 
 void ShadowMap::set_target(const Vector3 &t, float r)
@@ -108,19 +106,14 @@ void ShadowMap::prepare()
                push_matrix();
                load_matrix(matrix);
 
-               const Framebuffer *old_fbo = Framebuffer::current();
-               fbo.bind();
-               clear(DEPTH_BUFFER_BIT);
+               Bind bind_fbo(fbo, true);
+               fbo.clear(DEPTH_BUFFER_BIT);
                scene.render("shadow");
 
                matrix_mode(PROJECTION);
                pop_matrix();
                matrix_mode(MODELVIEW);
                pop_matrix();
-               if(old_fbo)
-                       old_fbo->bind();
-               else
-                       Framebuffer::unbind();
        }
 
        depth_buf.bind_to(unit);