#include <msp/gl/extensions/arb_draw_buffers.h>
+#include <msp/gl/extensions/arb_direct_state_access.h>
#include <msp/gl/extensions/ext_framebuffer_blit.h>
#include <msp/gl/extensions/ext_framebuffer_object.h>
+#include <msp/gl/extensions/msp_draw_buffer.h>
#include "error.h"
#include "framebuffer.h"
#include "misc.h"
{
static Require _req(EXT_framebuffer_object);
- glGenFramebuffers(1, &id);
+ if(ARB_direct_state_access)
+ glCreateFramebuffers(1, &id);
+ else
+ glGenFramebuffers(1, &id);
}
Framebuffer::~Framebuffer()
void Framebuffer::update_attachment(unsigned mask) const
{
- if(current()==this)
+ if(!ARB_direct_state_access && current()!=this)
+ {
+ dirty |= mask;
+ return;
+ }
+
+ std::vector<GLenum> color_bufs;
+ color_bufs.reserve(attachments.size());
+ for(unsigned i=0; i<attachments.size(); ++i)
{
- std::vector<GLenum> color_bufs;
- color_bufs.reserve(attachments.size());
- for(unsigned i=0; i<attachments.size(); ++i)
+ const Attachment &attch = attachments[i];
+ if(mask&(1<<i))
{
- const Attachment &attch = attachments[i];
- if(mask&(1<<i))
+ if(attch.type==GL_RENDERBUFFER)
{
- if(attch.type==GL_RENDERBUFFER)
+ 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<Texture2D *>(attch.tex)->allocate(attch.level);
+ }
+ else if(attch.type==GL_TEXTURE_2D)
+ {
+ static_cast<Texture2D *>(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_CUBE_MAP)
- {
- static_cast<TextureCube *>(attch.tex)->allocate(attch.level);
- glFramebufferTexture2D(GL_FRAMEBUFFER, attch.attachment, attch.cube_face, attch.tex->get_id(), attch.level);
- }
+ }
+ else if(attch.type==GL_TEXTURE_CUBE_MAP)
+ {
+ static_cast<TextureCube *>(attch.tex)->allocate(attch.level);
+ if(ARB_direct_state_access)
+ glNamedFramebufferTextureLayer(id, attch.attachment, attch.tex->get_id(), attch.level, attch.layer);
else
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, attch.attachment, 0, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, attch.attachment, TextureCube::enumerate_faces(attch.layer), attch.tex->get_id(), attch.level);
}
-
- if(attch.attachment>=COLOR_ATTACHMENT0 && attch.attachment<=COLOR_ATTACHMENT3)
- color_bufs.push_back(attch.attachment);
+ else if(ARB_direct_state_access)
+ glNamedFramebufferRenderbuffer(id, attch.attachment, 0, 0);
+ else
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, attch.attachment, 0, 0);
}
- if(color_bufs.empty())
- {
- glDrawBuffer(GL_NONE);
- glReadBuffer(GL_NONE);
- }
- else if(color_bufs.size()==1)
- {
- glDrawBuffer(color_bufs.front());
- glReadBuffer(color_bufs.front());
- }
- else
- {
- static Require _req(ARB_draw_buffers);
- glDrawBuffers(color_bufs.size(), &color_bufs[0]);
- glReadBuffer(color_bufs.front());
- }
+ if(attch.attachment>=COLOR_ATTACHMENT0 && attch.attachment<=COLOR_ATTACHMENT3)
+ color_bufs.push_back(attch.attachment);
+ }
+
+ 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
- dirty |= mask;
+ {
+ if(ARB_draw_buffers)
+ glDrawBuffers(color_bufs.size(), &color_bufs[0]);
+ else if(MSP_draw_buffer)
+ glDrawBuffer(first_buffer);
+
+ if(MSP_draw_buffer)
+ glReadBuffer(first_buffer);
+ }
}
void Framebuffer::check_size()
throw invalid_operation("Framebuffer::attach");
unsigned i = get_attachment_index(attch);
- attachments[i].set(tex, 0, level);
+ attachments[i].set(tex, level, 0);
update_attachment(1<<i);
check_size();
}
throw invalid_operation("Framebuffer::attach");
unsigned i = get_attachment_index(attch);
- attachments[i].set(tex, face, level);
+ attachments[i].set(tex, level, TextureCube::get_face_index(face));
update_attachment(1<<i);
check_size();
}
FramebufferStatus Framebuffer::check_status() const
{
- BindRestore _bind(this);
- return static_cast<FramebufferStatus>(glCheckFramebufferStatus(GL_FRAMEBUFFER));
+ if(ARB_direct_state_access)
+ return static_cast<FramebufferStatus>(glCheckNamedFramebufferStatus(id, GL_FRAMEBUFFER));
+ else
+ {
+ BindRestore _bind(this);
+ return static_cast<FramebufferStatus>(glCheckFramebufferStatus(GL_FRAMEBUFFER));
+ }
}
void Framebuffer::require_complete() const
{
static Require _req(EXT_framebuffer_blit);
+ if(ARB_direct_state_access)
+ {
+ glBlitNamedFramebuffer(other.id, id, sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1, bits, (filter ? GL_LINEAR : GL_NEAREST));
+ return;
+ }
+
const Framebuffer *old = current();
if(set_current(this))
{
Framebuffer::Attachment::Attachment(FramebufferAttachment a):
attachment(a),
type(0),
- level(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, GLenum f, unsigned l)
+void Framebuffer::Attachment::set(Texture &t, unsigned l, unsigned z)
{
type = t.get_target();
tex = &t;
- cube_face = f;
level = l;
+ layer = z;
}
void Framebuffer::Attachment::clear()