]> git.tdb.fi Git - libs/gl.git/blob - source/core/framebuffer.cpp
Track the number of layers in Framebuffer
[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 }
48
49 void Framebuffer::update() const
50 {
51         FramebufferBackend::update(dirty);
52         dirty = 0;
53 }
54
55 void Framebuffer::check_size()
56 {
57         bool first = true;
58         for(Attachment &a: attachments)
59                 if(a.tex)
60                 {
61                         unsigned w = 0;
62                         unsigned h = 0;
63                         unsigned l = 1;
64                         if(const Texture2D *tex2d = dynamic_cast<const Texture2D *>(a.tex))
65                         {
66                                 w = max(tex2d->get_width()>>a.level, 1U);
67                                 h = max(tex2d->get_height()>>a.level, 1U);
68                         }
69                         else if(const Texture2DMultisample *tex2d_ms = dynamic_cast<const Texture2DMultisample *>(a.tex))
70                         {
71                                 w = tex2d_ms->get_width();
72                                 h = tex2d_ms->get_height();
73                         }
74                         else if(const Texture3D *tex3d = dynamic_cast<const Texture3D *>(a.tex))
75                         {
76                                 w = max(tex3d->get_width()>>a.level, 1U);
77                                 h = max(tex3d->get_height()>>a.level, 1U);
78                                 l = (a.layer<0 ? tex3d->get_depth() : 1);
79                         }
80                         else if(const TextureCube *tex_cube = dynamic_cast<const TextureCube *>(a.tex))
81                         {
82                                 w = max(tex_cube->get_size()>>a.level, 1U);
83                                 h = w;
84                         }
85
86                         if(first)
87                         {
88                                 width = w;
89                                 height = h;
90                                 layers = l;
91                                 first = false;
92                         }
93                         else
94                         {
95                                 width = min(width, w);
96                                 height = min(height, h);
97                                 layers = min(layers, l);
98                         }
99                 }
100 }
101
102 void Framebuffer::set_attachment(FrameAttachment attch, Texture &tex, unsigned level, int layer, unsigned samples)
103 {
104         if(format.empty() || attachments.empty())
105                 throw invalid_operation("Framebuffer::attach");
106
107         if((format.get_samples()>1 && samples!=format.get_samples()) || (format.get_samples()==1 && samples))
108                 throw incompatible_data("Framebuffer::attach");
109
110         unsigned i = 0;
111         for(FrameAttachment a: format)
112         {
113                 if(a==attch)
114                 {
115                         attachments[i].set(tex, level, layer);
116                         dirty |= 1<<i;
117                         check_size();
118                         return;
119                 }
120                 ++i;
121         }
122
123         throw incompatible_data("Framebuffer::attach");
124 }
125
126 void Framebuffer::attach(FrameAttachment attch, Texture2D &tex, unsigned level)
127 {
128         set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, 0, 0);
129 }
130
131 void Framebuffer::attach(FrameAttachment attch, Texture2DMultisample &tex)
132 {
133         set_attachment(make_typed_attachment(attch, tex.get_format()), tex, 0, 0, tex.get_samples());
134 }
135
136 void Framebuffer::attach(FrameAttachment attch, Texture3D &tex, unsigned layer, unsigned level)
137 {
138         set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, layer, 0);
139 }
140
141 void Framebuffer::attach(FrameAttachment attch, TextureCube &tex, TextureCubeFace face, unsigned level)
142 {
143         set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, face, 0);
144 }
145
146 void Framebuffer::attach_layered(FrameAttachment attch, Texture3D &tex, unsigned level)
147 {
148         require_layered();
149         set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, -1, 0);
150 }
151
152 void Framebuffer::attach_layered(FrameAttachment attch, TextureCube &tex, unsigned level)
153 {
154         require_layered();
155         set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, -1, 0);
156 }
157
158 void Framebuffer::detach(FrameAttachment attch)
159 {
160         if(attachments.empty())
161                 throw invalid_operation("Framebuffer::detach");
162
163         int i = format.index(attch);
164         if(i>=0)
165         {
166                 attachments[i].clear();
167                 dirty |= 1<<i;
168                 check_size();
169         }
170 }
171
172 const Texture *Framebuffer::get_attachment(FrameAttachment attch) const
173 {
174         if(attachments.empty())
175                 return 0;
176
177         int i = format.index(attch);
178         return (i>=0 ? attachments[i].tex : 0);
179 }
180
181 const Texture *Framebuffer::get_attachment(unsigned i) const
182 {
183         return (i<attachments.size() ? attachments[i].tex : 0);
184 }
185
186 void Framebuffer::require_complete() const
187 {
188         bool layered = (!attachments.empty() && attachments.front().layer<0);
189         for(const Attachment &a: attachments)
190         {
191                 if(!a.tex)
192                         throw framebuffer_incomplete("missing attachment");
193                 if(layered!=(a.layer<0))
194                         throw framebuffer_incomplete("inconsistent layering");
195         }
196
197         FramebufferBackend::require_complete();
198 }
199
200
201 void Framebuffer::Attachment::set(Texture &t, unsigned l, int z)
202 {
203         tex = &t;
204         level = l;
205         layer = z;
206 }
207
208 void Framebuffer::Attachment::clear()
209 {
210         tex = 0;
211 }
212
213 } // namespace GL
214 } // namespace Msp