]> git.tdb.fi Git - libs/gl.git/blob - source/backends/opengl/framebuffer_backend.cpp
Restructure system framebuffer and make WindowView own it
[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 void OpenGLFramebuffer::set_system_format(const FrameFormat &fmt)
43 {
44         static_cast<Framebuffer *>(this)->format = fmt;
45 }
46
47 bool OpenGLFramebuffer::is_format_supported(const FrameFormat &fmt)
48 {
49         // Pretend everything is supported if we can't check
50         if(!ARB_internalformat_query || !ARB_internalformat_query2)
51                 return true;
52
53         unsigned target = (fmt.get_samples()>1 ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D);
54         for(FrameAttachment a: fmt)
55         {
56                 unsigned pf = get_gl_pixelformat(get_attachment_pixelformat(a));
57                 int supported = 0;
58                 glGetInternalformativ(target, pf, GL_FRAMEBUFFER_RENDERABLE, 1, &supported);
59                 if(supported!=GL_FULL_SUPPORT)
60                         return false;
61         }
62
63         return true;
64 }
65
66 void OpenGLFramebuffer::require_layered()
67 {
68         static Require _req(ARB_geometry_shader4);
69 }
70
71 void OpenGLFramebuffer::resize_system(unsigned w, unsigned h)
72 {
73         Framebuffer *self = static_cast<Framebuffer *>(this);
74         self->width = w;
75         self->height = h;
76 }
77
78 void OpenGLFramebuffer::update(unsigned mask) const
79 {
80         const FrameFormat &format = static_cast<const Framebuffer *>(this)->format;
81         vector<GLenum> color_bufs;
82         color_bufs.reserve(format.size());
83         unsigned i = 0;
84         for(FrameAttachment a: format)
85         {
86                 GLenum gl_attach_point = get_gl_attachment(a);
87                 if(mask&(1<<i))
88                 {
89                         const Framebuffer::Attachment &attch = static_cast<const Framebuffer *>(this)->attachments[i];
90                         if(attch.tex)
91                         {
92                                 if(ARB_direct_state_access)
93                                 {
94                                         if(attch.tex->target==GL_TEXTURE_2D || attch.tex->target==GL_TEXTURE_2D_MULTISAMPLE || attch.layer<0)
95                                                 glNamedFramebufferTexture(id, gl_attach_point, attch.tex->id, attch.level);
96                                         else
97                                                 glNamedFramebufferTextureLayer(id, gl_attach_point, attch.tex->id, attch.level, attch.layer);
98                                 }
99                                 else if(attch.tex->target==GL_TEXTURE_2D || attch.tex->target==GL_TEXTURE_2D_MULTISAMPLE)
100                                         glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, attch.tex->target, attch.tex->id, attch.level);
101                                 else if(attch.layer<0)
102                                         glFramebufferTexture(GL_FRAMEBUFFER, gl_attach_point, attch.tex->id, attch.level);
103                                 else if(attch.tex->target==GL_TEXTURE_2D_ARRAY)
104                                         glFramebufferTextureLayer(GL_FRAMEBUFFER, gl_attach_point, attch.tex->id, attch.level, attch.layer);
105                                 else if(attch.tex->target==GL_TEXTURE_3D)
106                                         glFramebufferTexture3D(GL_FRAMEBUFFER, gl_attach_point, attch.tex->target, attch.tex->id, attch.level, attch.layer);
107                                 else if(attch.tex->target==GL_TEXTURE_CUBE_MAP)
108                                         glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, get_gl_cube_face(static_cast<TextureCubeFace>(attch.layer)), attch.tex->id, attch.level);
109                         }
110                         else if(ARB_direct_state_access)
111                                 glNamedFramebufferTexture(id, gl_attach_point, 0, 0);
112                         else
113                                 glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, GL_TEXTURE_2D, 0, 0);
114                 }
115
116                 if(gl_attach_point!=GL_DEPTH_ATTACHMENT && gl_attach_point!=GL_STENCIL_ATTACHMENT)
117                         color_bufs.push_back(gl_attach_point);
118
119                 ++i;
120         }
121
122         if(color_bufs.size()>1)
123                 static Require _req(ARB_draw_buffers);
124
125         GLenum first_buffer = (color_bufs.empty() ? GL_NONE : color_bufs.front());
126         if(ARB_direct_state_access)
127         {
128                 /* ARB_direct_state_access ties the availability of these functions to
129                 framebuffers themselves, so no further checks are needed. */
130                 glNamedFramebufferDrawBuffers(id, color_bufs.size(), &color_bufs[0]);
131                 glNamedFramebufferReadBuffer(id, first_buffer);
132         }
133         else
134         {
135                 if(ARB_draw_buffers)
136                         glDrawBuffers(color_bufs.size(), &color_bufs[0]);
137                 else if(MSP_buffer_control)
138                         glDrawBuffer(first_buffer);
139
140                 if(MSP_buffer_control)
141                         glReadBuffer(first_buffer);
142         }
143
144         if(ARB_direct_state_access)
145                 status = glCheckNamedFramebufferStatus(id, GL_FRAMEBUFFER);
146         else
147                 status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
148 }
149
150 void OpenGLFramebuffer::require_complete() const
151 {
152         if(status==GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)
153                 throw framebuffer_incomplete("incomplete or unsupported attachment");
154         if(status==GL_FRAMEBUFFER_UNSUPPORTED)
155                 throw framebuffer_incomplete("unsupported configuration");
156         if(status!=GL_FRAMEBUFFER_COMPLETE)
157                 throw framebuffer_incomplete(Msp::format("incomplete (%#x)", status));
158 }
159
160 void OpenGLFramebuffer::set_debug_name(const string &name)
161 {
162 #ifdef DEBUG
163         if(KHR_debug)
164                 glObjectLabel(GL_FRAMEBUFFER, id, name.size(), name.c_str());
165 #else
166         (void)name;
167 #endif
168 }
169
170 } // namespace GL
171 } // namespace Msp