1 #include <msp/gl/extensions/arb_draw_buffers.h>
2 #include <msp/gl/extensions/arb_direct_state_access.h>
3 #include <msp/gl/extensions/arb_geometry_shader4.h>
4 #include <msp/gl/extensions/arb_internalformat_query.h>
5 #include <msp/gl/extensions/arb_internalformat_query2.h>
6 #include <msp/gl/extensions/ext_framebuffer_object.h>
7 #include <msp/gl/extensions/ext_texture_array.h>
8 #include <msp/gl/extensions/ext_texture3d.h>
9 #include <msp/gl/extensions/msp_buffer_control.h>
10 #include <msp/gl/extensions/khr_debug.h>
11 #include <msp/strings/format.h>
12 #include "framebuffer.h"
13 #include "framebuffer_backend.h"
21 OpenGLFramebuffer::OpenGLFramebuffer(bool is_system):
22 status(is_system ? GL_FRAMEBUFFER_COMPLETE : GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT)
26 static Require _req(EXT_framebuffer_object);
28 if(ARB_direct_state_access)
29 glCreateFramebuffers(1, &id);
31 glGenFramebuffers(1, &id);
35 OpenGLFramebuffer::OpenGLFramebuffer(OpenGLFramebuffer &&other):
42 OpenGLFramebuffer::~OpenGLFramebuffer()
45 glDeleteFramebuffers(1, &id);
47 glDeleteFramebuffers(1, &resolve_id);
50 void OpenGLFramebuffer::set_system_format(const FrameFormat &fmt)
52 static_cast<Framebuffer *>(this)->format = fmt;
55 bool OpenGLFramebuffer::is_format_supported(const FrameFormat &fmt)
57 // Pretend everything is supported if we can't check
58 if(!ARB_internalformat_query || !ARB_internalformat_query2)
61 unsigned target = (fmt.get_samples()>1 ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D);
62 for(FrameAttachment a: fmt)
64 unsigned pf = get_gl_pixelformat(get_attachment_pixelformat(a));
66 glGetInternalformativ(target, pf, GL_FRAMEBUFFER_RENDERABLE, 1, &supported);
67 if(supported!=GL_FULL_SUPPORT)
74 void OpenGLFramebuffer::format_changed(const FrameFormat &format)
76 if(format.get_samples()>1 && !resolve_id)
78 if(ARB_direct_state_access)
79 glCreateFramebuffers(1, &resolve_id);
81 glGenFramebuffers(1, &resolve_id);
85 void OpenGLFramebuffer::require_layered()
87 static Require _req(ARB_geometry_shader4);
90 void OpenGLFramebuffer::resize_system(unsigned w, unsigned h)
92 Framebuffer &self = *static_cast<Framebuffer *>(this);
97 void OpenGLFramebuffer::update(unsigned mask) const
99 const Framebuffer &self = *static_cast<const Framebuffer *>(this);
102 if(self.has_resolve_attachments())
104 if(!ARB_direct_state_access)
105 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_id);
109 if(!ARB_direct_state_access)
110 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, id);
114 void OpenGLFramebuffer::update(unsigned mask, bool resolve) const
116 const Framebuffer &self = *static_cast<const Framebuffer *>(this);
117 unsigned obj_id = (resolve ? resolve_id : id);
118 Texture *Framebuffer::Attachment::*member = (resolve ? &Framebuffer::Attachment::resolve : &Framebuffer::Attachment::tex);
120 vector<GLenum> color_bufs;
121 color_bufs.reserve(self.format.size());
123 for(FrameAttachment a: self.format)
125 GLenum gl_attach_point = get_gl_attachment(a);
128 const Framebuffer::Attachment &attch = self.attachments[i];
129 Texture *tex = attch.*member;
132 if(ARB_direct_state_access)
134 if(tex->target==GL_TEXTURE_2D || tex->target==GL_TEXTURE_2D_MULTISAMPLE || attch.layer<0)
135 glNamedFramebufferTexture(obj_id, gl_attach_point, tex->id, attch.level);
137 glNamedFramebufferTextureLayer(obj_id, gl_attach_point, tex->id, attch.level, attch.layer);
139 else if(tex->target==GL_TEXTURE_2D || tex->target==GL_TEXTURE_2D_MULTISAMPLE)
140 glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, tex->target, tex->id, attch.level);
141 else if(attch.layer<0)
142 glFramebufferTexture(GL_FRAMEBUFFER, gl_attach_point, tex->id, attch.level);
143 else if(tex->target==GL_TEXTURE_2D_ARRAY)
144 glFramebufferTextureLayer(GL_FRAMEBUFFER, gl_attach_point, tex->id, attch.level, attch.layer);
145 else if(tex->target==GL_TEXTURE_3D)
146 glFramebufferTexture3D(GL_FRAMEBUFFER, gl_attach_point, tex->target, tex->id, attch.level, attch.layer);
147 else if(tex->target==GL_TEXTURE_CUBE_MAP)
148 glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, get_gl_cube_face(static_cast<TextureCubeFace>(attch.layer)), tex->id, attch.level);
150 else if(ARB_direct_state_access)
151 glNamedFramebufferTexture(obj_id, gl_attach_point, 0, 0);
153 glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, GL_TEXTURE_2D, 0, 0);
156 if(gl_attach_point!=GL_DEPTH_ATTACHMENT && gl_attach_point!=GL_STENCIL_ATTACHMENT)
157 color_bufs.push_back(gl_attach_point);
162 if(color_bufs.size()>1)
163 static Require _req(ARB_draw_buffers);
165 GLenum first_buffer = (color_bufs.empty() ? GL_NONE : color_bufs.front());
166 if(ARB_direct_state_access)
168 /* ARB_direct_state_access ties the availability of these functions to
169 framebuffers themselves, so no further checks are needed. */
170 glNamedFramebufferDrawBuffers(obj_id, color_bufs.size(), &color_bufs[0]);
171 glNamedFramebufferReadBuffer(obj_id, first_buffer);
176 glDrawBuffers(color_bufs.size(), &color_bufs[0]);
177 else if(MSP_buffer_control)
178 glDrawBuffer(first_buffer);
180 if(MSP_buffer_control)
181 glReadBuffer(first_buffer);
186 if(ARB_direct_state_access)
187 status = glCheckNamedFramebufferStatus(obj_id, GL_FRAMEBUFFER);
189 status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
193 void OpenGLFramebuffer::require_complete() const
195 if(status==GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)
196 throw framebuffer_incomplete("incomplete or unsupported attachment");
197 if(status==GL_FRAMEBUFFER_UNSUPPORTED)
198 throw framebuffer_incomplete("unsupported configuration");
199 if(status!=GL_FRAMEBUFFER_COMPLETE)
200 throw framebuffer_incomplete(Msp::format("incomplete (%#x)", status));
203 void OpenGLFramebuffer::set_debug_name(const string &name)
208 glObjectLabel(GL_FRAMEBUFFER, id, name.size(), name.c_str());
211 string resolve_name = name+" [resolve]";
212 glObjectLabel(GL_FRAMEBUFFER, resolve_id, resolve_name.size(), resolve_name.c_str());