]> git.tdb.fi Git - libs/gl.git/blob - source/core/framebuffer.cpp
Add flat interpolation qualifier for integer inputs in fragment shader
[libs/gl.git] / source / core / framebuffer.cpp
1 #include "error.h"
2 #include "framebuffer.h"
3 #include "texture2d.h"
4 #include "texture2dmultisample.h"
5 #include "texture3d.h"
6 #include "windowview.h"
7
8 using namespace std;
9
10 namespace Msp {
11 namespace GL {
12
13 framebuffer_incomplete::framebuffer_incomplete(const std::string &reason):
14         runtime_error(reason)
15 { }
16
17
18 Framebuffer::Framebuffer(bool s):
19         FramebufferBackend(s)
20 { }
21
22 Framebuffer::Framebuffer():
23         FramebufferBackend(false)
24 { }
25
26 Framebuffer::Framebuffer(FrameAttachment fa):
27         Framebuffer()
28 {
29         set_format(fa);
30 }
31
32 Framebuffer::Framebuffer(const FrameFormat &f):
33         Framebuffer()
34 {
35         set_format(f);
36 }
37
38 void Framebuffer::set_format(const FrameFormat &fmt)
39 {
40         if(!format.empty())
41                 throw invalid_operation("Framebuffer::set_format");
42         if(fmt.empty() || !is_format_supported(fmt))
43                 throw invalid_argument("Framebuffer::set_format");
44
45         format = fmt;
46         attachments.resize(format.size());
47         format_changed(format);
48 }
49
50 void Framebuffer::update() const
51 {
52         FramebufferBackend::update(dirty);
53         dirty = 0;
54 }
55
56 void Framebuffer::check_size()
57 {
58         bool first = true;
59         for(Attachment &a: attachments)
60                 if(a.tex)
61                 {
62                         unsigned w = 0;
63                         unsigned h = 0;
64                         unsigned l = 1;
65                         if(const Texture2D *tex2d = dynamic_cast<const Texture2D *>(a.tex))
66                         {
67                                 w = max(tex2d->get_width()>>a.level, 1U);
68                                 h = max(tex2d->get_height()>>a.level, 1U);
69                         }
70                         else if(const Texture2DMultisample *tex2d_ms = dynamic_cast<const Texture2DMultisample *>(a.tex))
71                         {
72                                 w = tex2d_ms->get_width();
73                                 h = tex2d_ms->get_height();
74                         }
75                         else if(const Texture3D *tex3d = dynamic_cast<const Texture3D *>(a.tex))
76                         {
77                                 w = max(tex3d->get_width()>>a.level, 1U);
78                                 h = max(tex3d->get_height()>>a.level, 1U);
79                                 l = (a.layer<0 ? tex3d->get_depth() : 1);
80                         }
81                         else if(const TextureCube *tex_cube = dynamic_cast<const TextureCube *>(a.tex))
82                         {
83                                 w = max(tex_cube->get_size()>>a.level, 1U);
84                                 h = w;
85                                 l = (a.layer<0 ? 6 : 1);
86                         }
87
88                         if(first)
89                         {
90                                 width = w;
91                                 height = h;
92                                 layers = l;
93                                 first = false;
94                         }
95                         else
96                         {
97                                 width = min(width, w);
98                                 height = min(height, h);
99                                 layers = min(layers, l);
100                         }
101                 }
102 }
103
104 void Framebuffer::set_attachment(FrameAttachment attch, Texture &tex, Texture *res, unsigned level, int layer, unsigned samples)
105 {
106         if(format.empty() || attachments.empty())
107                 throw invalid_operation("Framebuffer::attach");
108
109         if((format.get_samples()>1 && samples!=format.get_samples()) || (format.get_samples()==1 && samples))
110                 throw incompatible_data("Framebuffer::attach");
111
112         unsigned i = 0;
113         for(FrameAttachment a: format)
114         {
115                 if(a==attch)
116                 {
117                         attachments[i].set(tex, res, level, layer);
118                         dirty |= 1<<i;
119                         check_size();
120                         return;
121                 }
122                 ++i;
123         }
124
125         throw incompatible_data("Framebuffer::attach");
126 }
127
128 void Framebuffer::attach(FrameAttachment attch, Texture2D &tex, unsigned level)
129 {
130         set_attachment(make_typed_attachment(attch, tex.get_format()), tex, 0, level, 0, 0);
131 }
132
133 void Framebuffer::attach(FrameAttachment attch, Texture2DMultisample &tex, Texture2D *res)
134 {
135         set_attachment(make_typed_attachment(attch, tex.get_format()), tex, res, 0, 0, tex.get_samples());
136 }
137
138 void Framebuffer::attach(FrameAttachment attch, Texture3D &tex, unsigned layer, unsigned level)
139 {
140         set_attachment(make_typed_attachment(attch, tex.get_format()), tex, 0, level, layer, 0);
141 }
142
143 void Framebuffer::attach(FrameAttachment attch, TextureCube &tex, TextureCubeFace face, unsigned level)
144 {
145         set_attachment(make_typed_attachment(attch, tex.get_format()), tex, 0, level, face, 0);
146 }
147
148 void Framebuffer::attach_layered(FrameAttachment attch, Texture3D &tex, unsigned level)
149 {
150         require_layered();
151         set_attachment(make_typed_attachment(attch, tex.get_format()), tex, 0, level, -1, 0);
152 }
153
154 void Framebuffer::attach_layered(FrameAttachment attch, TextureCube &tex, unsigned level)
155 {
156         require_layered();
157         set_attachment(make_typed_attachment(attch, tex.get_format()), tex, 0, level, -1, 0);
158 }
159
160 void Framebuffer::detach(FrameAttachment attch)
161 {
162         if(attachments.empty())
163                 throw invalid_operation("Framebuffer::detach");
164
165         int i = format.index(attch);
166         if(i>=0)
167         {
168                 attachments[i].clear();
169                 dirty |= 1<<i;
170                 check_size();
171         }
172 }
173
174 const Texture *Framebuffer::get_attachment(FrameAttachment attch) const
175 {
176         if(attachments.empty())
177                 return 0;
178
179         int i = format.index(attch);
180         return (i>=0 ? attachments[i].tex : 0);
181 }
182
183 const Texture *Framebuffer::get_attachment(unsigned i) const
184 {
185         return (i<attachments.size() ? attachments[i].tex : 0);
186 }
187
188 const Texture *Framebuffer::get_resolve_attachment(FrameAttachment attch) const
189 {
190         if(attachments.empty())
191                 return 0;
192
193         int i = format.index(attch);
194         return (i>=0 ? attachments[i].resolve : 0);
195 }
196
197 const Texture *Framebuffer::get_resolve_attachment(unsigned i) const
198 {
199         return (i<attachments.size() ? attachments[i].resolve : 0);
200 }
201
202 bool Framebuffer::has_resolve_attachments() const
203 {
204         for(const Attachment &a: attachments)
205                 if(a.resolve)
206                         return true;
207         return false;
208 }
209
210 void Framebuffer::require_complete() const
211 {
212         bool layered = (!attachments.empty() && attachments.front().layer<0);
213         for(const Attachment &a: attachments)
214         {
215                 if(!a.tex)
216                         throw framebuffer_incomplete("missing attachment");
217                 if(layered!=(a.layer<0))
218                         throw framebuffer_incomplete("inconsistent layering");
219         }
220
221         FramebufferBackend::require_complete();
222 }
223
224
225 void Framebuffer::Attachment::set(Texture &t, Texture *r, unsigned l, int z)
226 {
227         tex = &t;
228         resolve = r;
229         level = l;
230         layer = z;
231 }
232
233 void Framebuffer::Attachment::clear()
234 {
235         tex = 0;
236 }
237
238 } // namespace GL
239 } // namespace Msp