X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fcore%2Fframebuffer.cpp;h=cc8dec4f5358346fbf53f33c002a745420fb098b;hp=851b6431b2fb134d470b1116262411af471532be;hb=959efbf61663efd7879070ce0447e02c8a447ce0;hpb=a4d83d3748cdde8cf30683d36a040d3dfacfd693 diff --git a/source/core/framebuffer.cpp b/source/core/framebuffer.cpp index 851b6431..cc8dec4f 100644 --- a/source/core/framebuffer.cpp +++ b/source/core/framebuffer.cpp @@ -1,13 +1,5 @@ -#include -#include -#include -#include -#include -#include -#include #include "error.h" #include "framebuffer.h" -#include "misc.h" #include "texture2d.h" #include "texture2dmultisample.h" #include "texture3d.h" @@ -18,108 +10,46 @@ 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), - status(FRAMEBUFFER_COMPLETE), +Framebuffer::Framebuffer(bool s): + FramebufferBackend(s), dirty(0) { - if(id) - throw invalid_argument("System framebuffer must have id 0"); - - int view[4]; - glGetIntegerv(GL_VIEWPORT, view); - width = view[2]; - height = view[3]; + if(s) + { + format = get_system_format(); + get_system_size(width, height); + } } -Framebuffer::Framebuffer() -{ - init(); -} +Framebuffer::Framebuffer(): + FramebufferBackend(false), + width(0), + height(0), + dirty(0) +{ } -Framebuffer::Framebuffer(FrameAttachment fa) +Framebuffer::Framebuffer(FrameAttachment fa): + Framebuffer() { - init(); set_format(fa); } -Framebuffer::Framebuffer(const FrameFormat &f) +Framebuffer::Framebuffer(const FrameFormat &f): + Framebuffer() { - 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 - glGenFramebuffers(1, &id); -} - -Framebuffer::~Framebuffer() -{ - if(id) - glDeleteFramebuffers(1, &id); -} - void Framebuffer::set_format(const FrameFormat &fmt) { - if(!format.empty()) + if(!format.empty() || !id) throw invalid_operation("Framebuffer::set_format"); - if(fmt.empty()) + if(fmt.empty() || !is_format_supported(fmt)) throw invalid_argument("Framebuffer::set_format"); format = fmt; @@ -128,75 +58,7 @@ void Framebuffer::set_format(const FrameFormat &fmt) void Framebuffer::update() const { - vector color_bufs; - color_bufs.reserve(format.size()); - unsigned i = 0; - for(FrameAttachment a: format) - { - GLenum gl_attach_point = get_gl_attachment(a); - if(dirty&(1<get_target(); - if(ARB_direct_state_access) - { - 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) - glNamedFramebufferTexture(id, gl_attach_point, 0, 0); - else - glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, GL_TEXTURE_2D, 0, 0); - } - - if(gl_attach_point!=GL_DEPTH_ATTACHMENT && gl_attach_point!=GL_STENCIL_ATTACHMENT) - color_bufs.push_back(gl_attach_point); - - ++i; - } - - 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); - - 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)); - + FramebufferBackend::update(dirty); dirty = 0; } @@ -206,30 +68,26 @@ void Framebuffer::check_size() for(Attachment &a: attachments) if(a.tex) { - GLenum type = a.tex->get_target(); unsigned w = 0; unsigned h = 0; - if(type==GL_TEXTURE_2D) + if(const Texture2D *tex2d = dynamic_cast(a.tex)) { - Texture2D *tex = static_cast(a.tex); - w = max(tex->get_width()>>a.level, 1U); - h = max(tex->get_height()>>a.level, 1U); + w = max(tex2d->get_width()>>a.level, 1U); + h = max(tex2d->get_height()>>a.level, 1U); } - else if(type==GL_TEXTURE_2D_MULTISAMPLE) + else if(const Texture2DMultisample *tex2d_ms = dynamic_cast(a.tex)) { - Texture2DMultisample *tex = static_cast(a.tex); - w = tex->get_width(); - h = tex->get_height(); + w = tex2d_ms->get_width(); + h = tex2d_ms->get_height(); } - else if(type==GL_TEXTURE_3D || type==GL_TEXTURE_2D_ARRAY) + else if(const Texture3D *tex3d = dynamic_cast(a.tex)) { - Texture3D *tex = static_cast(a.tex); - w = max(tex->get_width()>>a.level, 1U); - h = max(tex->get_height()>>a.level, 1U); + w = max(tex3d->get_width()>>a.level, 1U); + h = max(tex3d->get_height()>>a.level, 1U); } - else if(type==GL_TEXTURE_CUBE_MAP) + else if(const TextureCube *tex_cube = dynamic_cast(a.tex)) { - w = max(static_cast(a.tex)->get_size()>>a.level, 1U); + w = max(tex_cube->get_size()>>a.level, 1U); h = w; } @@ -273,7 +131,6 @@ void Framebuffer::set_attachment(FrameAttachment attch, Texture &tex, unsigned l void Framebuffer::attach(FrameAttachment attch, Texture2D &tex, unsigned level) { - tex.allocate(level); set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, 0, 0); } @@ -284,27 +141,23 @@ void Framebuffer::attach(FrameAttachment attch, Texture2DMultisample &tex) void Framebuffer::attach(FrameAttachment attch, Texture3D &tex, unsigned layer, unsigned level) { - tex.allocate(level); set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, layer, 0); } void Framebuffer::attach(FrameAttachment attch, TextureCube &tex, TextureCubeFace face, unsigned level) { - tex.allocate(level); - set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, TextureCube::get_face_index(face), 0); + set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, face, 0); } void Framebuffer::attach_layered(FrameAttachment attch, Texture3D &tex, unsigned level) { - static Require _req(ARB_geometry_shader4); - tex.allocate(level); + require_layered(); set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, -1, 0); } void Framebuffer::attach_layered(FrameAttachment attch, TextureCube &tex, unsigned level) { - static Require _req(ARB_geometry_shader4); - tex.allocate(level); + require_layered(); set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, -1, 0); } @@ -333,33 +186,28 @@ void Framebuffer::resize(const WindowView &view) void Framebuffer::require_complete() const { - if(status!=FRAMEBUFFER_COMPLETE) - throw framebuffer_incomplete(status); -} + if(!id) + return; -void Framebuffer::set_debug_name(const string &name) -{ -#ifdef DEBUG - if(KHR_debug) - glObjectLabel(GL_FRAMEBUFFER, id, name.size(), name.c_str()); -#else - (void)name; -#endif + bool layered = (!attachments.empty() && attachments.front().layer<0); + for(const Attachment &a: attachments) + { + if(!a.tex) + throw framebuffer_incomplete("missing attachment"); + if(layered!=(a.layer<0)) + throw framebuffer_incomplete("inconsistent layering"); + } + + FramebufferBackend::require_complete(); } Framebuffer &Framebuffer::system() { - static Framebuffer sys_framebuf(0); + static Framebuffer sys_framebuf(true); return sys_framebuf; } -Framebuffer::Attachment::Attachment(): - tex(0), - level(0), - layer(0) -{ } - void Framebuffer::Attachment::set(Texture &t, unsigned l, int z) { tex = &t;