X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fcore%2Fframebuffer.cpp;h=e9d8863ca16e4e0379a11e9777def136cb596d2e;hp=795465cbbad37f28c9e2f208e22a080e055310f4;hb=3a1b9cbe2441ae670a97541dc8ccb0a2860c8302;hpb=3a6eb030fb4eca4c2a317f270704fddf31613130 diff --git a/source/core/framebuffer.cpp b/source/core/framebuffer.cpp index 795465cb..e9d8863c 100644 --- a/source/core/framebuffer.cpp +++ b/source/core/framebuffer.cpp @@ -1,16 +1,17 @@ #include #include -#include #include #include #include #include +#include #include "error.h" #include "framebuffer.h" #include "misc.h" -#include "renderbuffer.h" #include "texture2d.h" +#include "texture2dmultisample.h" #include "texture3d.h" +#include "windowview.h" using namespace std; @@ -64,23 +65,44 @@ framebuffer_incomplete::framebuffer_incomplete(FramebufferStatus status): Framebuffer::Framebuffer(unsigned i): id(i), + status(FRAMEBUFFER_COMPLETE), dirty(0) { if(id) throw invalid_argument("System framebuffer must have id 0"); - glGetIntegerv(GL_VIEWPORT, &view.left); - width = view.width; - height = view.height; + int view[4]; + glGetIntegerv(GL_VIEWPORT, view); + width = view[2]; + height = view[3]; } -Framebuffer::Framebuffer(): - width(0), - height(0), - dirty(0) +Framebuffer::Framebuffer() +{ + init(); +} + +Framebuffer::Framebuffer(FrameAttachment fa) +{ + init(); + set_format(fa); +} + +Framebuffer::Framebuffer(const FrameFormat &f) +{ + init(); + set_format(f); +} + +void Framebuffer::init() { static Require _req(EXT_framebuffer_object); + width = 0; + height = 0; + status = FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; + dirty = 0; + if(ARB_direct_state_access) glCreateFramebuffers(1, &id); else @@ -91,66 +113,59 @@ Framebuffer::~Framebuffer() { if(id) glDeleteFramebuffers(1, &id); - if(current()==this) - unbind(); } -void Framebuffer::update_attachment(unsigned mask) const +void Framebuffer::set_format(const FrameFormat &fmt) { - if(!ARB_direct_state_access && current()!=this) - { - dirty |= mask; - return; - } + if(!format.empty()) + throw invalid_operation("Framebuffer::set_format"); + if(fmt.empty()) + throw invalid_argument("Framebuffer::set_format"); + format = fmt; + attachments.resize(format.size()); +} + +void Framebuffer::update() const +{ vector color_bufs; - color_bufs.reserve(attachments.size()); - for(unsigned i=0; i(*j)); + if(dirty&(1<get_target(); if(ARB_direct_state_access) - glNamedFramebufferRenderbuffer(id, attch.attachment, GL_RENDERBUFFER, attch.rbuf->get_id()); - else - glFramebufferRenderbuffer(GL_FRAMEBUFFER, attch.attachment, GL_RENDERBUFFER, attch.rbuf->get_id()); - } - else if(attch.type==GL_TEXTURE_2D) - { - static_cast(attch.tex)->allocate(attch.level); - if(ARB_direct_state_access) - glNamedFramebufferTexture(id, attch.attachment, attch.tex->get_id(), attch.level); - else - glFramebufferTexture2D(GL_FRAMEBUFFER, attch.attachment, attch.type, attch.tex->get_id(), attch.level); - } - else if(attch.type==GL_TEXTURE_3D || attch.type==GL_TEXTURE_2D_ARRAY) - { - static_cast(attch.tex)->allocate(attch.level); - if(ARB_direct_state_access) - glNamedFramebufferTextureLayer(id, attch.attachment, attch.tex->get_id(), attch.level, attch.layer); - else if(attch.type==GL_TEXTURE_2D_ARRAY) - glFramebufferTextureLayer(GL_FRAMEBUFFER, attch.attachment, attch.tex->get_id(), attch.level, attch.layer); - else - glFramebufferTexture3D(GL_FRAMEBUFFER, attch.attachment, attch.type, attch.tex->get_id(), attch.level, attch.layer); - } - else if(attch.type==GL_TEXTURE_CUBE_MAP) - { - static_cast(attch.tex)->allocate(attch.level); - if(ARB_direct_state_access) - glNamedFramebufferTextureLayer(id, attch.attachment, attch.tex->get_id(), attch.level, attch.layer); - else - glFramebufferTexture2D(GL_FRAMEBUFFER, attch.attachment, TextureCube::enumerate_faces(attch.layer), attch.tex->get_id(), attch.level); + { + if(type==GL_TEXTURE_2D || type==GL_TEXTURE_2D_MULTISAMPLE || attch.layer<0) + glNamedFramebufferTexture(id, gl_attach_point, attch.tex->get_id(), attch.level); + else + glNamedFramebufferTextureLayer(id, gl_attach_point, attch.tex->get_id(), attch.level, attch.layer); + } + else if(type==GL_TEXTURE_2D || type==GL_TEXTURE_2D_MULTISAMPLE) + glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, type, attch.tex->get_id(), attch.level); + else if(attch.layer<0) + glFramebufferTexture(GL_FRAMEBUFFER, gl_attach_point, attch.tex->get_id(), attch.level); + else if(type==GL_TEXTURE_2D_ARRAY) + glFramebufferTextureLayer(GL_FRAMEBUFFER, gl_attach_point, attch.tex->get_id(), attch.level, attch.layer); + else if(type==GL_TEXTURE_3D) + glFramebufferTexture3D(GL_FRAMEBUFFER, gl_attach_point, type, attch.tex->get_id(), attch.level, attch.layer); + else if(type==GL_TEXTURE_CUBE_MAP) + glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, TextureCube::enumerate_faces(attch.layer), attch.tex->get_id(), attch.level); } else if(ARB_direct_state_access) - glNamedFramebufferRenderbuffer(id, attch.attachment, 0, 0); + glNamedFramebufferTexture(id, gl_attach_point, 0, 0); else - glFramebufferRenderbuffer(GL_FRAMEBUFFER, attch.attachment, 0, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, GL_TEXTURE_2D, 0, 0); } - if(attch.attachment>=COLOR_ATTACHMENT0 && attch.attachment<=COLOR_ATTACHMENT3) - color_bufs.push_back(attch.attachment); + if(gl_attach_point!=GL_DEPTH_ATTACHMENT && gl_attach_point!=GL_STENCIL_ATTACHMENT) + color_bufs.push_back(gl_attach_point); } if(color_bufs.size()>1) @@ -174,219 +189,157 @@ void Framebuffer::update_attachment(unsigned mask) const if(MSP_buffer_control) glReadBuffer(first_buffer); } + + if(ARB_direct_state_access) + status = static_cast(glCheckNamedFramebufferStatus(id, GL_FRAMEBUFFER)); + else + status = static_cast(glCheckFramebufferStatus(GL_FRAMEBUFFER)); + + dirty = 0; } void Framebuffer::check_size() { - bool full_viewport = (view.left==0 && view.bottom==0 && view.width==width && view.height==height); - for(vector::iterator i=attachments.begin(); i!=attachments.end(); ++i) - if(i->type) + bool first = true; + for(Attachment &a: attachments) + if(a.tex) { - if(i->type==GL_RENDERBUFFER) + GLenum type = a.tex->get_target(); + unsigned w = 0; + unsigned h = 0; + if(type==GL_TEXTURE_2D) { - width = i->rbuf->get_width(); - height = i->rbuf->get_height(); + Texture2D *tex = static_cast(a.tex); + w = max(tex->get_width()>>a.level, 1U); + h = max(tex->get_height()>>a.level, 1U); } - else if(i->type==GL_TEXTURE_2D) + else if(type==GL_TEXTURE_2D_MULTISAMPLE) { - Texture2D *tex = static_cast(i->tex); - width = max(tex->get_width()>>i->level, 1U); - height = max(tex->get_height()>>i->level, 1U); + Texture2DMultisample *tex = static_cast(a.tex); + w = tex->get_width(); + h = tex->get_height(); } - else if(i->type==GL_TEXTURE_3D || i->type==GL_TEXTURE_2D_ARRAY) + else if(type==GL_TEXTURE_3D || type==GL_TEXTURE_2D_ARRAY) { - Texture3D *tex = static_cast(i->tex); - width = max(tex->get_width()>>i->level, 1U); - height = max(tex->get_height()>>i->level, 1U); + Texture3D *tex = static_cast(a.tex); + w = max(tex->get_width()>>a.level, 1U); + h = max(tex->get_height()>>a.level, 1U); } - else if(i->type==GL_TEXTURE_CUBE_MAP) + else if(type==GL_TEXTURE_CUBE_MAP) { - width = max(static_cast(i->tex)->get_size()>>i->level, 1U); - height = width; + w = max(static_cast(a.tex)->get_size()>>a.level, 1U); + h = w; } - if(full_viewport) - reset_viewport(); - break; - } -} -unsigned Framebuffer::get_attachment_index(FramebufferAttachment attch) -{ - for(unsigned i=0; i1 && samples!=format.get_samples()) || (format.get_samples()==1 && samples)) + throw incompatible_data("Framebuffer::attach"); -void Framebuffer::detach(FramebufferAttachment attch) -{ - if(!id) - throw invalid_operation("Framebuffer::detach"); + unsigned i = 0; + for(const uint16_t *j=format.begin(); j!=format.end(); ++j, ++i) + if(*j==attch) + { + attachments[i].set(tex, level, layer); + dirty |= 1<(glCheckNamedFramebufferStatus(id, GL_FRAMEBUFFER)); - else - { - BindRestore _bind(this); - return static_cast(glCheckFramebufferStatus(GL_FRAMEBUFFER)); - } + tex.allocate(level); + set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, 0, 0); } -void Framebuffer::require_complete() const +void Framebuffer::attach(FrameAttachment attch, Texture2DMultisample &tex) { - FramebufferStatus status = check_status(); - if(status!=FRAMEBUFFER_COMPLETE) - throw framebuffer_incomplete(status); + set_attachment(make_typed_attachment(attch, tex.get_format()), tex, 0, 0, tex.get_samples()); } -void Framebuffer::viewport(int l, int b, unsigned w, unsigned h) +void Framebuffer::attach(FrameAttachment attch, Texture3D &tex, unsigned layer, unsigned level) { - view.left = l; - view.bottom = b; - view.width = w; - view.height = h; - - if(current()==this) - glViewport(view.left, view.bottom, view.width, view.height); + tex.allocate(level); + set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, layer, 0); } -void Framebuffer::reset_viewport() +void Framebuffer::attach(FrameAttachment attch, TextureCube &tex, TextureCubeFace face, unsigned level) { - viewport(0, 0, width, height); + tex.allocate(level); + set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, TextureCube::get_face_index(face), 0); } -void Framebuffer::clear() +void Framebuffer::attach_layered(FrameAttachment attch, Texture3D &tex, unsigned level) { - clear(COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT|STENCIL_BUFFER_BIT); + static Require _req(ARB_geometry_shader4); + tex.allocate(level); + set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, -1, 0); } -void Framebuffer::clear(BufferBits bits) +void Framebuffer::attach_layered(FrameAttachment attch, TextureCube &tex, unsigned level) { - BindRestore _bind(this); - glClear(bits); + static Require _req(ARB_geometry_shader4); + tex.allocate(level); + set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, -1, 0); } -void Framebuffer::blit_from(const Framebuffer &other, int sx0, int sy0, int sx1, int sy1, int dx0, int dy0, int dx1, int dy1, BufferBits bits, bool filter) +void Framebuffer::detach(FrameAttachment attch) { - static Require _req(EXT_framebuffer_blit); + if(!id) + throw invalid_operation("Framebuffer::detach"); - if(ARB_direct_state_access) + int i = format.index(attch); + if(i>=0) { - glBlitNamedFramebuffer(other.id, id, sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1, bits, (filter ? GL_LINEAR : GL_NEAREST)); - return; + attachments[i].clear(); + dirty |= 1<id : 0)); -} - -void Framebuffer::blit_from(const Framebuffer &other, int sx, int sy, unsigned wd, unsigned ht, int dx, int dy, BufferBits bits) -{ - blit_from(other, sx, sy, sx+wd, sy+ht, dx, dy, dx+wd, dy+ht, bits, false); } -void Framebuffer::blit_from(const Framebuffer &other, BufferBits bits, bool filter) +void Framebuffer::resize(const WindowView &view) { - blit_from(other, 0, 0, other.width, other.height, 0, 0, width, height, bits, filter); -} - -void Framebuffer::bind() const -{ - if(id && attachments.empty()) - throw invalid_operation("Framebuffer::bind"); - - if(set_current(this)) - { - glBindFramebuffer(GL_FRAMEBUFFER, id); - if(dirty) - { - update_attachment(dirty); - dirty = 0; - } + if(id) + throw invalid_operation("Framebuffer::resize"); - if(width && height) - glViewport(view.left, view.bottom, view.width, view.height); - } + width = view.get_width(); + height = view.get_height(); } -const Framebuffer *Framebuffer::current() +void Framebuffer::require_complete() const { - if(!cur_obj) - cur_obj = &system(); - return cur_obj; + if(status!=FRAMEBUFFER_COMPLETE) + throw framebuffer_incomplete(status); } -void Framebuffer::unbind() +void Framebuffer::set_debug_name(const string &name) { - system().bind(); +#ifdef DEBUG + if(KHR_debug) + glObjectLabel(GL_FRAMEBUFFER, id, name.size(), name.c_str()); +#else + (void)name; +#endif } Framebuffer &Framebuffer::system() @@ -396,24 +349,14 @@ Framebuffer &Framebuffer::system() } -Framebuffer::Attachment::Attachment(FramebufferAttachment a): - attachment(a), - type(0), +Framebuffer::Attachment::Attachment(): + tex(0), level(0), layer(0) { } -void Framebuffer::Attachment::set(Renderbuffer &r) +void Framebuffer::Attachment::set(Texture &t, unsigned l, int z) { - type = GL_RENDERBUFFER; - rbuf = &r; - level = 0; - layer = 0; -} - -void Framebuffer::Attachment::set(Texture &t, unsigned l, unsigned z) -{ - type = t.get_target(); tex = &t; level = l; layer = z; @@ -421,16 +364,8 @@ void Framebuffer::Attachment::set(Texture &t, unsigned l, unsigned z) void Framebuffer::Attachment::clear() { - type = 0; + tex = 0; } - -Framebuffer::Viewport::Viewport(): - left(0), - bottom(0), - width(0), - height(0) -{ } - } // namespace GL } // namespace Msp