#include <msp/gl/extensions/arb_draw_buffers.h>
#include <msp/gl/extensions/arb_direct_state_access.h>
+#include <msp/gl/extensions/arb_geometry_shader4.h>
+#include <msp/gl/extensions/arb_internalformat_query.h>
+#include <msp/gl/extensions/arb_internalformat_query2.h>
#include <msp/gl/extensions/ext_framebuffer_object.h>
#include <msp/gl/extensions/ext_texture_array.h>
#include <msp/gl/extensions/ext_texture3d.h>
#include <msp/gl/extensions/msp_buffer_control.h>
#include <msp/gl/extensions/khr_debug.h>
+#include <msp/strings/format.h>
#include "error.h"
#include "framebuffer.h"
-#include "misc.h"
#include "texture2d.h"
#include "texture2dmultisample.h"
#include "texture3d.h"
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<string, unsigned>(status, "%#x"));
- break;
- }
-}
-
-framebuffer_incomplete::framebuffer_incomplete(FramebufferStatus status):
- runtime_error(lexical_cast<string>(status))
+framebuffer_incomplete::framebuffer_incomplete(const std::string &reason):
+ runtime_error(reason)
{ }
Framebuffer::Framebuffer(unsigned i):
id(i),
- status(FRAMEBUFFER_COMPLETE),
+ status(GL_FRAMEBUFFER_COMPLETE),
dirty(0)
{
if(id)
throw invalid_argument("System framebuffer must have id 0");
+ if(EXT_framebuffer_object)
+ {
+ int value;
+ glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_BACK, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &value);
+ if(value==GL_NONE)
+ glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_FRONT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &value);
+ if(value!=GL_NONE)
+ format = (format,COLOR_ATTACHMENT);
+
+ glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &value);
+ if(value!=GL_NONE)
+ format = (format,DEPTH_ATTACHMENT);
+
+ glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_STENCIL, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &value);
+ if(value!=GL_NONE)
+ format = (format,STENCIL_ATTACHMENT);
+ }
+
int view[4];
glGetIntegerv(GL_VIEWPORT, view);
width = view[2];
width = 0;
height = 0;
- status = FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
+ status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
dirty = 0;
if(ARB_direct_state_access)
void Framebuffer::set_format(const FrameFormat &fmt)
{
- if(!format.empty())
+ if(!format.empty() || !id)
throw invalid_operation("Framebuffer::set_format");
if(fmt.empty())
throw invalid_argument("Framebuffer::set_format");
+ if(ARB_internalformat_query && ARB_internalformat_query2)
+ {
+ unsigned target = (fmt.get_samples()>1 ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D);
+ for(FrameAttachment a: fmt)
+ {
+ unsigned pf = get_gl_pixelformat(get_attachment_pixelformat(a));
+ int supported = 0;
+ glGetInternalformativ(target, pf, GL_FRAMEBUFFER_RENDERABLE, 1, &supported);
+ if(supported!=GL_FULL_SUPPORT)
+ throw invalid_argument("Framebuffer::set_format");
+ }
+ }
+
format = fmt;
attachments.resize(format.size());
}
}
if(ARB_direct_state_access)
- status = static_cast<FramebufferStatus>(glCheckNamedFramebufferStatus(id, GL_FRAMEBUFFER));
+ status = glCheckNamedFramebufferStatus(id, GL_FRAMEBUFFER);
else
- status = static_cast<FramebufferStatus>(glCheckFramebufferStatus(GL_FRAMEBUFFER));
+ status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
dirty = 0;
}
void Framebuffer::require_complete() const
{
- if(status!=FRAMEBUFFER_COMPLETE)
- throw framebuffer_incomplete(status);
+ if(!id)
+ return;
+
+ 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");
+ }
+
+ if(status==GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)
+ throw framebuffer_incomplete("incomplete or unsupported attachment");
+ if(status==GL_FRAMEBUFFER_UNSUPPORTED)
+ throw framebuffer_incomplete("unsupported configuration");
+ if(status!=GL_FRAMEBUFFER_COMPLETE)
+ throw framebuffer_incomplete(Msp::format("incomplete (%#x)", status));
}
void Framebuffer::set_debug_name(const string &name)