]> git.tdb.fi Git - libs/gl.git/blobdiff - source/backends/opengl/framebuffer_backend.cpp
Move all OpenGL-specific code to a separate directory
[libs/gl.git] / source / backends / opengl / framebuffer_backend.cpp
diff --git a/source/backends/opengl/framebuffer_backend.cpp b/source/backends/opengl/framebuffer_backend.cpp
new file mode 100644 (file)
index 0000000..1adcb7f
--- /dev/null
@@ -0,0 +1,192 @@
+#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 "framebuffer.h"
+#include "framebuffer_backend.h"
+#include "gl.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+OpenGLFramebuffer::OpenGLFramebuffer(bool is_system):
+       id(0),
+       status(is_system ? GL_FRAMEBUFFER_COMPLETE : GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT)
+{
+       if(!is_system)
+       {
+               static Require _req(EXT_framebuffer_object);
+
+               if(ARB_direct_state_access)
+                       glCreateFramebuffers(1, &id);
+               else
+                       glGenFramebuffers(1, &id);
+       }
+}
+
+OpenGLFramebuffer::~OpenGLFramebuffer()
+{
+       if(id)
+               glDeleteFramebuffers(1, &id);
+}
+
+FrameFormat OpenGLFramebuffer::get_system_format()
+{
+       FrameFormat format;
+
+       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);
+       }
+
+       return format;
+}
+
+void OpenGLFramebuffer::get_system_size(unsigned &width, unsigned &height)
+{
+       int view[4];
+       glGetIntegerv(GL_VIEWPORT, view);
+       width = view[2];
+       height = view[3];
+}
+
+bool OpenGLFramebuffer::is_format_supported(const FrameFormat &fmt)
+{
+       // Pretend everything is supported if we can't check
+       if(!ARB_internalformat_query || !ARB_internalformat_query2)
+               return true;
+
+       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)
+                       return false;
+       }
+
+       return true;
+}
+
+void OpenGLFramebuffer::require_layered()
+{
+       static Require _req(ARB_geometry_shader4);
+}
+
+void OpenGLFramebuffer::update(unsigned mask) const
+{
+       const FrameFormat &format = static_cast<const Framebuffer *>(this)->format;
+       vector<GLenum> color_bufs;
+       color_bufs.reserve(format.size());
+       unsigned i = 0;
+       for(FrameAttachment a: format)
+       {
+               GLenum gl_attach_point = get_gl_attachment(a);
+               if(mask&(1<<i))
+               {
+                       const Framebuffer::Attachment &attch = static_cast<const Framebuffer *>(this)->attachments[i];
+                       if(attch.tex)
+                       {
+                               if(ARB_direct_state_access)
+                               {
+                                       if(attch.tex->target==GL_TEXTURE_2D || attch.tex->target==GL_TEXTURE_2D_MULTISAMPLE || attch.layer<0)
+                                               glNamedFramebufferTexture(id, gl_attach_point, attch.tex->id, attch.level);
+                                       else
+                                               glNamedFramebufferTextureLayer(id, gl_attach_point, attch.tex->id, attch.level, attch.layer);
+                               }
+                               else if(attch.tex->target==GL_TEXTURE_2D || attch.tex->target==GL_TEXTURE_2D_MULTISAMPLE)
+                                       glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, attch.tex->target, attch.tex->id, attch.level);
+                               else if(attch.layer<0)
+                                       glFramebufferTexture(GL_FRAMEBUFFER, gl_attach_point, attch.tex->id, attch.level);
+                               else if(attch.tex->target==GL_TEXTURE_2D_ARRAY)
+                                       glFramebufferTextureLayer(GL_FRAMEBUFFER, gl_attach_point, attch.tex->id, attch.level, attch.layer);
+                               else if(attch.tex->target==GL_TEXTURE_3D)
+                                       glFramebufferTexture3D(GL_FRAMEBUFFER, gl_attach_point, attch.tex->target, attch.tex->id, attch.level, attch.layer);
+                               else if(attch.tex->target==GL_TEXTURE_CUBE_MAP)
+                                       glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, get_gl_cube_face(static_cast<TextureCubeFace>(attch.layer)), attch.tex->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 = glCheckNamedFramebufferStatus(id, GL_FRAMEBUFFER);
+       else
+               status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+}
+
+void OpenGLFramebuffer::require_complete() const
+{
+       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 OpenGLFramebuffer::set_debug_name(const string &name)
+{
+#ifdef DEBUG
+       if(KHR_debug)
+               glObjectLabel(GL_FRAMEBUFFER, id, name.size(), name.c_str());
+#else
+       (void)name;
+#endif
+}
+
+} // namespace GL
+} // namespace Msp