X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fcore%2Fframebuffer.cpp;h=cc8dec4f5358346fbf53f33c002a745420fb098b;hp=810f0cf1c2675da6741648568408d221412d7c77;hb=38712d8ecc57d043a2419ffbaeeb57f7a6586f14;hpb=87b74b1263710b0acb9e0b72283e972fd54ee91b diff --git a/source/core/framebuffer.cpp b/source/core/framebuffer.cpp index 810f0cf1..cc8dec4f 100644 --- a/source/core/framebuffer.cpp +++ b/source/core/framebuffer.cpp @@ -1,423 +1,215 @@ -#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; namespace Msp { namespace GL { -void operator<<(LexicalConverter &conv, FramebufferStatus status) -{ - switch(status) - { - case FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - conv.result("incomplete attachment"); - break; - case FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - conv.result("missing attachment"); - break; - case FRAMEBUFFER_INCOMPLETE_DIMENSIONS: - conv.result("mismatched attachment dimensions"); - break; - case FRAMEBUFFER_INCOMPLETE_FORMATS: - conv.result("mismatched attachment formats"); - break; - case FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: - conv.result("missing draw buffer attachment"); - break; - case FRAMEBUFFER_INCOMPLETE_READ_BUFFER: - conv.result("missing read buffer attachment"); - break; - case FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: - conv.result("mismatched attachment sample counts"); - break; - case FRAMEBUFFER_INCOMPLETE_LAYER_COUNT: - conv.result("mismatched attachment layer counts"); - break; - case FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: - conv.result("mismatched attachment layering"); - break; - case FRAMEBUFFER_UNSUPPORTED: - conv.result("unsupported"); - break; - default: - conv.result(lexical_cast(status, "%#x")); - break; - } -} - -framebuffer_incomplete::framebuffer_incomplete(FramebufferStatus status): - runtime_error(lexical_cast(status)) +framebuffer_incomplete::framebuffer_incomplete(const std::string &reason): + runtime_error(reason) { } -Framebuffer::Framebuffer(unsigned i): - id(i), +Framebuffer::Framebuffer(bool s): + FramebufferBackend(s), dirty(0) { - if(id) - throw invalid_argument("System framebuffer must have id 0"); - - glGetIntegerv(GL_VIEWPORT, &view.left); - width = view.width; - height = view.height; + if(s) + { + format = get_system_format(); + get_system_size(width, height); + } } Framebuffer::Framebuffer(): + FramebufferBackend(false), width(0), height(0), dirty(0) -{ - static Require _req(EXT_framebuffer_object); +{ } - if(ARB_direct_state_access) - glCreateFramebuffers(1, &id); - else - glGenFramebuffers(1, &id); +Framebuffer::Framebuffer(FrameAttachment fa): + Framebuffer() +{ + set_format(fa); } -Framebuffer::~Framebuffer() +Framebuffer::Framebuffer(const FrameFormat &f): + Framebuffer() { - if(id) - glDeleteFramebuffers(1, &id); - if(current()==this) - unbind(); + set_format(f); } -void Framebuffer::update_attachment(unsigned mask) const +void Framebuffer::set_format(const FrameFormat &fmt) { - if(!ARB_direct_state_access && current()!=this) - { - dirty |= mask; - return; - } - - vector color_bufs; - color_bufs.reserve(attachments.size()); - for(unsigned i=0; iget_id()); - else - glFramebufferRenderbuffer(GL_FRAMEBUFFER, attch.attachment, GL_RENDERBUFFER, attch.rbuf->get_id()); - } - else if(attch.type) - { - if(ARB_direct_state_access) - { - if(attch.type==GL_TEXTURE_2D || attch.layer<0) - glNamedFramebufferTexture(id, attch.attachment, attch.tex->get_id(), attch.level); - else - glNamedFramebufferTextureLayer(id, attch.attachment, attch.tex->get_id(), attch.level, attch.layer); - } - else if(attch.type==GL_TEXTURE_2D) - glFramebufferTexture2D(GL_FRAMEBUFFER, attch.attachment, attch.type, attch.tex->get_id(), attch.level); - else if(attch.layer<0) - glFramebufferTexture(GL_FRAMEBUFFER, attch.attachment, attch.tex->get_id(), attch.level); - else if(attch.type==GL_TEXTURE_2D_ARRAY) - glFramebufferTextureLayer(GL_FRAMEBUFFER, attch.attachment, attch.tex->get_id(), attch.level, attch.layer); - else if(attch.type==GL_TEXTURE_3D) - glFramebufferTexture3D(GL_FRAMEBUFFER, attch.attachment, attch.type, attch.tex->get_id(), attch.level, attch.layer); - else if(attch.type==GL_TEXTURE_CUBE_MAP) - glFramebufferTexture2D(GL_FRAMEBUFFER, attch.attachment, TextureCube::enumerate_faces(attch.layer), attch.tex->get_id(), attch.level); - } - else if(ARB_direct_state_access) - glNamedFramebufferRenderbuffer(id, attch.attachment, 0, 0); - else - glFramebufferRenderbuffer(GL_FRAMEBUFFER, attch.attachment, 0, 0); - } - - if(attch.attachment>=COLOR_ATTACHMENT0 && attch.attachment<=COLOR_ATTACHMENT3) - color_bufs.push_back(attch.attachment); - } + if(!format.empty() || !id) + throw invalid_operation("Framebuffer::set_format"); + if(fmt.empty() || !is_format_supported(fmt)) + throw invalid_argument("Framebuffer::set_format"); - if(color_bufs.size()>1) - static Require _req(ARB_draw_buffers); - - GLenum first_buffer = (color_bufs.empty() ? GL_NONE : color_bufs.front()); - if(ARB_direct_state_access) - { - /* ARB_direct_state_access ties the availability of these functions to - framebuffers themselves, so no further checks are needed. */ - glNamedFramebufferDrawBuffers(id, color_bufs.size(), &color_bufs[0]); - glNamedFramebufferReadBuffer(id, first_buffer); - } - else - { - if(ARB_draw_buffers) - glDrawBuffers(color_bufs.size(), &color_bufs[0]); - else if(MSP_buffer_control) - glDrawBuffer(first_buffer); + format = fmt; + attachments.resize(format.size()); +} - if(MSP_buffer_control) - glReadBuffer(first_buffer); - } +void Framebuffer::update() const +{ + FramebufferBackend::update(dirty); + 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) + unsigned w = 0; + unsigned h = 0; + if(const Texture2D *tex2d = dynamic_cast(a.tex)) { - width = i->rbuf->get_width(); - height = i->rbuf->get_height(); + w = max(tex2d->get_width()>>a.level, 1U); + h = max(tex2d->get_height()>>a.level, 1U); } - else if(i->type==GL_TEXTURE_2D) + else if(const Texture2DMultisample *tex2d_ms = dynamic_cast(a.tex)) { - Texture2D *tex = static_cast(i->tex); - width = max(tex->get_width()>>i->level, 1U); - height = max(tex->get_height()>>i->level, 1U); + w = tex2d_ms->get_width(); + h = tex2d_ms->get_height(); } - else if(i->type==GL_TEXTURE_3D || i->type==GL_TEXTURE_2D_ARRAY) + else if(const Texture3D *tex3d = dynamic_cast(a.tex)) { - Texture3D *tex = static_cast(i->tex); - width = max(tex->get_width()>>i->level, 1U); - height = max(tex->get_height()>>i->level, 1U); + w = max(tex3d->get_width()>>a.level, 1U); + h = max(tex3d->get_height()>>a.level, 1U); } - else if(i->type==GL_TEXTURE_CUBE_MAP) + else if(const TextureCube *tex_cube = dynamic_cast(a.tex)) { - width = max(static_cast(i->tex)->get_size()>>i->level, 1U); - height = width; + w = max(tex_cube->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"); + + unsigned i = 0; + for(FrameAttachment a: format) + { + if(a==attch) + { + attachments[i].set(tex, level, layer); + dirty |= 1<(glCheckNamedFramebufferStatus(id, GL_FRAMEBUFFER)); - else + int i = format.index(attch); + if(i>=0) { - BindRestore _bind(this); - return static_cast(glCheckFramebufferStatus(GL_FRAMEBUFFER)); + 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) -{ - 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)) + bool layered = (!attachments.empty() && attachments.front().layer<0); + for(const Attachment &a: attachments) { - glBindFramebuffer(GL_FRAMEBUFFER, id); - if(dirty) - { - update_attachment(dirty); - dirty = 0; - } - - if(width && height) - glViewport(view.left, view.bottom, view.width, view.height); + if(!a.tex) + throw framebuffer_incomplete("missing attachment"); + if(layered!=(a.layer<0)) + throw framebuffer_incomplete("inconsistent layering"); } -} -const Framebuffer *Framebuffer::current() -{ - if(!cur_obj) - cur_obj = &system(); - return cur_obj; -} - -void Framebuffer::unbind() -{ - system().bind(); + FramebufferBackend::require_complete(); } Framebuffer &Framebuffer::system() { - static Framebuffer sys_framebuf(0); + static Framebuffer sys_framebuf(true); return sys_framebuf; } -Framebuffer::Attachment::Attachment(FramebufferAttachment a): - attachment(a), - type(0), - level(0), - layer(0) -{ } - -void Framebuffer::Attachment::set(Renderbuffer &r) -{ - type = GL_RENDERBUFFER; - rbuf = &r; - level = 0; - layer = 0; -} - void Framebuffer::Attachment::set(Texture &t, unsigned l, int z) { - type = t.get_target(); tex = &t; level = l; layer = z; @@ -425,16 +217,8 @@ void Framebuffer::Attachment::set(Texture &t, unsigned l, int z) void Framebuffer::Attachment::clear() { - type = 0; + tex = 0; } - -Framebuffer::Viewport::Viewport(): - left(0), - bottom(0), - width(0), - height(0) -{ } - } // namespace GL } // namespace Msp