]> git.tdb.fi Git - libs/gl.git/blob - source/backends/opengl/framebuffer_backend.cpp
1adcb7f93515c2eef68b4419957704fb81640520
[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         id(0),
23         status(is_system ? GL_FRAMEBUFFER_COMPLETE : GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT)
24 {
25         if(!is_system)
26         {
27                 static Require _req(EXT_framebuffer_object);
28
29                 if(ARB_direct_state_access)
30                         glCreateFramebuffers(1, &id);
31                 else
32                         glGenFramebuffers(1, &id);
33         }
34 }
35
36 OpenGLFramebuffer::~OpenGLFramebuffer()
37 {
38         if(id)
39                 glDeleteFramebuffers(1, &id);
40 }
41
42 FrameFormat OpenGLFramebuffer::get_system_format()
43 {
44         FrameFormat format;
45
46         if(EXT_framebuffer_object)
47         {
48                 int value;
49                 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_BACK, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &value);
50                 if(value==GL_NONE)
51                         glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_FRONT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &value);
52                 if(value!=GL_NONE)
53                         format = (format,COLOR_ATTACHMENT);
54
55                 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &value);
56                 if(value!=GL_NONE)
57                         format = (format,DEPTH_ATTACHMENT);
58
59                 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_STENCIL, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &value);
60                 if(value!=GL_NONE)
61                         format = (format,STENCIL_ATTACHMENT);
62         }
63
64         return format;
65 }
66
67 void OpenGLFramebuffer::get_system_size(unsigned &width, unsigned &height)
68 {
69         int view[4];
70         glGetIntegerv(GL_VIEWPORT, view);
71         width = view[2];
72         height = view[3];
73 }
74
75 bool OpenGLFramebuffer::is_format_supported(const FrameFormat &fmt)
76 {
77         // Pretend everything is supported if we can't check
78         if(!ARB_internalformat_query || !ARB_internalformat_query2)
79                 return true;
80
81         unsigned target = (fmt.get_samples()>1 ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D);
82         for(FrameAttachment a: fmt)
83         {
84                 unsigned pf = get_gl_pixelformat(get_attachment_pixelformat(a));
85                 int supported = 0;
86                 glGetInternalformativ(target, pf, GL_FRAMEBUFFER_RENDERABLE, 1, &supported);
87                 if(supported!=GL_FULL_SUPPORT)
88                         return false;
89         }
90
91         return true;
92 }
93
94 void OpenGLFramebuffer::require_layered()
95 {
96         static Require _req(ARB_geometry_shader4);
97 }
98
99 void OpenGLFramebuffer::update(unsigned mask) const
100 {
101         const FrameFormat &format = static_cast<const Framebuffer *>(this)->format;
102         vector<GLenum> color_bufs;
103         color_bufs.reserve(format.size());
104         unsigned i = 0;
105         for(FrameAttachment a: format)
106         {
107                 GLenum gl_attach_point = get_gl_attachment(a);
108                 if(mask&(1<<i))
109                 {
110                         const Framebuffer::Attachment &attch = static_cast<const Framebuffer *>(this)->attachments[i];
111                         if(attch.tex)
112                         {
113                                 if(ARB_direct_state_access)
114                                 {
115                                         if(attch.tex->target==GL_TEXTURE_2D || attch.tex->target==GL_TEXTURE_2D_MULTISAMPLE || attch.layer<0)
116                                                 glNamedFramebufferTexture(id, gl_attach_point, attch.tex->id, attch.level);
117                                         else
118                                                 glNamedFramebufferTextureLayer(id, gl_attach_point, attch.tex->id, attch.level, attch.layer);
119                                 }
120                                 else if(attch.tex->target==GL_TEXTURE_2D || attch.tex->target==GL_TEXTURE_2D_MULTISAMPLE)
121                                         glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, attch.tex->target, attch.tex->id, attch.level);
122                                 else if(attch.layer<0)
123                                         glFramebufferTexture(GL_FRAMEBUFFER, gl_attach_point, attch.tex->id, attch.level);
124                                 else if(attch.tex->target==GL_TEXTURE_2D_ARRAY)
125                                         glFramebufferTextureLayer(GL_FRAMEBUFFER, gl_attach_point, attch.tex->id, attch.level, attch.layer);
126                                 else if(attch.tex->target==GL_TEXTURE_3D)
127                                         glFramebufferTexture3D(GL_FRAMEBUFFER, gl_attach_point, attch.tex->target, attch.tex->id, attch.level, attch.layer);
128                                 else if(attch.tex->target==GL_TEXTURE_CUBE_MAP)
129                                         glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, get_gl_cube_face(static_cast<TextureCubeFace>(attch.layer)), attch.tex->id, attch.level);
130                         }
131                         else if(ARB_direct_state_access)
132                                 glNamedFramebufferTexture(id, gl_attach_point, 0, 0);
133                         else
134                                 glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, GL_TEXTURE_2D, 0, 0);
135                 }
136
137                 if(gl_attach_point!=GL_DEPTH_ATTACHMENT && gl_attach_point!=GL_STENCIL_ATTACHMENT)
138                         color_bufs.push_back(gl_attach_point);
139
140                 ++i;
141         }
142
143         if(color_bufs.size()>1)
144                 static Require _req(ARB_draw_buffers);
145
146         GLenum first_buffer = (color_bufs.empty() ? GL_NONE : color_bufs.front());
147         if(ARB_direct_state_access)
148         {
149                 /* ARB_direct_state_access ties the availability of these functions to
150                 framebuffers themselves, so no further checks are needed. */
151                 glNamedFramebufferDrawBuffers(id, color_bufs.size(), &color_bufs[0]);
152                 glNamedFramebufferReadBuffer(id, first_buffer);
153         }
154         else
155         {
156                 if(ARB_draw_buffers)
157                         glDrawBuffers(color_bufs.size(), &color_bufs[0]);
158                 else if(MSP_buffer_control)
159                         glDrawBuffer(first_buffer);
160
161                 if(MSP_buffer_control)
162                         glReadBuffer(first_buffer);
163         }
164
165         if(ARB_direct_state_access)
166                 status = glCheckNamedFramebufferStatus(id, GL_FRAMEBUFFER);
167         else
168                 status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
169 }
170
171 void OpenGLFramebuffer::require_complete() const
172 {
173         if(status==GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)
174                 throw framebuffer_incomplete("incomplete or unsupported attachment");
175         if(status==GL_FRAMEBUFFER_UNSUPPORTED)
176                 throw framebuffer_incomplete("unsupported configuration");
177         if(status!=GL_FRAMEBUFFER_COMPLETE)
178                 throw framebuffer_incomplete(Msp::format("incomplete (%#x)", status));
179 }
180
181 void OpenGLFramebuffer::set_debug_name(const string &name)
182 {
183 #ifdef DEBUG
184         if(KHR_debug)
185                 glObjectLabel(GL_FRAMEBUFFER, id, name.size(), name.c_str());
186 #else
187         (void)name;
188 #endif
189 }
190
191 } // namespace GL
192 } // namespace Msp