]> git.tdb.fi Git - libs/gl.git/blob - source/backends/opengl/framebuffer_backend.cpp
Check the flat qualifier from the correct member
[libs/gl.git] / source / backends / opengl / framebuffer_backend.cpp
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"
14 #include "gl.h"
15
16 using namespace std;
17
18 namespace Msp {
19 namespace GL {
20
21 OpenGLFramebuffer::OpenGLFramebuffer(bool is_system):
22         status(is_system ? GL_FRAMEBUFFER_COMPLETE : GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT)
23 {
24         if(!is_system)
25         {
26                 static Require _req(EXT_framebuffer_object);
27
28                 if(ARB_direct_state_access)
29                         glCreateFramebuffers(1, &id);
30                 else
31                         glGenFramebuffers(1, &id);
32         }
33 }
34
35 OpenGLFramebuffer::OpenGLFramebuffer(OpenGLFramebuffer &&other):
36         id(other.id),
37         status(other.status)
38 {
39         other.id = 0;
40 }
41
42 OpenGLFramebuffer::~OpenGLFramebuffer()
43 {
44         if(id)
45                 glDeleteFramebuffers(1, &id);
46         if(resolve_id)
47                 glDeleteFramebuffers(1, &resolve_id);
48 }
49
50 void OpenGLFramebuffer::set_system_format(const FrameFormat &fmt)
51 {
52         static_cast<Framebuffer *>(this)->format = fmt;
53 }
54
55 bool OpenGLFramebuffer::is_format_supported(const FrameFormat &fmt)
56 {
57         // Pretend everything is supported if we can't check
58         if(!ARB_internalformat_query || !ARB_internalformat_query2)
59                 return true;
60
61         unsigned target = (fmt.get_samples()>1 ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D);
62         for(FrameAttachment a: fmt)
63         {
64                 unsigned pf = get_gl_pixelformat(get_attachment_pixelformat(a));
65                 int supported = 0;
66                 glGetInternalformativ(target, pf, GL_FRAMEBUFFER_RENDERABLE, 1, &supported);
67                 if(supported!=GL_FULL_SUPPORT)
68                         return false;
69         }
70
71         return true;
72 }
73
74 void OpenGLFramebuffer::format_changed(const FrameFormat &format)
75 {
76         if(format.get_samples()>1 && !resolve_id)
77         {
78                 if(ARB_direct_state_access)
79                         glCreateFramebuffers(1, &resolve_id);
80                 else
81                         glGenFramebuffers(1, &resolve_id);
82         }
83 }
84
85 void OpenGLFramebuffer::require_layered()
86 {
87         static Require _req(ARB_geometry_shader4);
88 }
89
90 void OpenGLFramebuffer::resize_system(unsigned w, unsigned h)
91 {
92         Framebuffer &self = *static_cast<Framebuffer *>(this);
93         self.width = w;
94         self.height = h;
95 }
96
97 void OpenGLFramebuffer::update(unsigned mask) const
98 {
99         const Framebuffer &self = *static_cast<const Framebuffer *>(this);
100
101         update(mask, false);
102         if(self.has_resolve_attachments())
103         {
104                 if(!ARB_direct_state_access)
105                         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_id);
106
107                 update(mask, true);
108
109                 if(!ARB_direct_state_access)
110                         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, id);
111         }
112 }
113
114 void OpenGLFramebuffer::update(unsigned mask, bool resolve) const
115 {
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);
119
120         vector<GLenum> color_bufs;
121         color_bufs.reserve(self.format.size());
122         unsigned i = 0;
123         for(FrameAttachment a: self.format)
124         {
125                 GLenum gl_attach_point = get_gl_attachment(a);
126                 if(mask&(1<<i))
127                 {
128                         const Framebuffer::Attachment &attch = self.attachments[i];
129                         Texture *tex = attch.*member;
130                         if(tex)
131                         {
132                                 if(ARB_direct_state_access)
133                                 {
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);
136                                         else
137                                                 glNamedFramebufferTextureLayer(obj_id, gl_attach_point, tex->id, attch.level, attch.layer);
138                                 }
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);
149                         }
150                         else if(ARB_direct_state_access)
151                                 glNamedFramebufferTexture(obj_id, gl_attach_point, 0, 0);
152                         else
153                                 glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, GL_TEXTURE_2D, 0, 0);
154                 }
155
156                 if(gl_attach_point!=GL_DEPTH_ATTACHMENT && gl_attach_point!=GL_STENCIL_ATTACHMENT)
157                         color_bufs.push_back(gl_attach_point);
158
159                 ++i;
160         }
161
162         if(color_bufs.size()>1)
163                 static Require _req(ARB_draw_buffers);
164
165         GLenum first_buffer = (color_bufs.empty() ? GL_NONE : color_bufs.front());
166         if(ARB_direct_state_access)
167         {
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);
172         }
173         else
174         {
175                 if(ARB_draw_buffers)
176                         glDrawBuffers(color_bufs.size(), &color_bufs[0]);
177                 else if(MSP_buffer_control)
178                         glDrawBuffer(first_buffer);
179
180                 if(MSP_buffer_control)
181                         glReadBuffer(first_buffer);
182         }
183
184         if(!resolve)
185         {
186                 if(ARB_direct_state_access)
187                         status = glCheckNamedFramebufferStatus(obj_id, GL_FRAMEBUFFER);
188                 else
189                         status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
190         }
191 }
192
193 void OpenGLFramebuffer::require_complete() const
194 {
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));
201 }
202
203 void OpenGLFramebuffer::set_debug_name(const string &name)
204 {
205 #ifdef DEBUG
206         if(KHR_debug)
207         {
208                 glObjectLabel(GL_FRAMEBUFFER, id, name.size(), name.c_str());
209                 if(resolve_id)
210                 {
211                         string resolve_name = name+" [resolve]";
212                         glObjectLabel(GL_FRAMEBUFFER, resolve_id, resolve_name.size(), resolve_name.c_str());
213                 }
214         }
215 #else
216         (void)name;
217 #endif
218 }
219
220 } // namespace GL
221 } // namespace Msp