From: Mikko Rasa Date: Wed, 15 Sep 2010 19:14:55 +0000 (+0000) Subject: Rewrite Framebuffer to defer attach/detach operations until bound X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=commitdiff_plain;h=3663bed18358a2399b2a8a8f7779d85e0ed81bd0 Rewrite Framebuffer to defer attach/detach operations until bound 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 --- diff --git a/source/framebuffer.cpp b/source/framebuffer.cpp index cf3761d0..8dbd2d0e 100644 --- a/source/framebuffer.cpp +++ b/source/framebuffer.cpp @@ -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; iget_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::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(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<::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<(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::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(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; 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(static_cast(a)|static_cast(b)); } -void viewport(int, int, unsigned, unsigned); -void clear(BufferBits); -void draw_buffer(RWBuffer); -void read_buffer(RWBuffer); - } // namespace GL } // namespace Msp diff --git a/source/pipeline.cpp b/source/pipeline.cpp index 54ef25a1..517037a0 100644 --- a/source/pipeline.cpp +++ b/source/pipeline.cpp @@ -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::const_iterator i=effects.begin(); i!=effects.end(); ++i) diff --git a/source/renderbuffer.cpp b/source/renderbuffer.cpp index 0d3a76b5..95cf56b8 100644 --- a/source/renderbuffer.cpp +++ b/source/renderbuffer.cpp @@ -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); diff --git a/source/shadowmap.cpp b/source/shadowmap.cpp index 25b0d6d6..bedfcfd5 100644 --- a/source/shadowmap.cpp +++ b/source/shadowmap.cpp @@ -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);