]> git.tdb.fi Git - libs/gl.git/blob - source/core/framebuffer.cpp
Restructure system framebuffer and make WindowView own it
[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         dirty(0)
21 { }
22
23 Framebuffer::Framebuffer():
24         FramebufferBackend(false),
25         width(0),
26         height(0),
27         dirty(0)
28 { }
29
30 Framebuffer::Framebuffer(FrameAttachment fa):
31         Framebuffer()
32 {
33         set_format(fa);
34 }
35
36 Framebuffer::Framebuffer(const FrameFormat &f):
37         Framebuffer()
38 {
39         set_format(f);
40 }
41
42 void Framebuffer::set_format(const FrameFormat &fmt)
43 {
44         if(!format.empty())
45                 throw invalid_operation("Framebuffer::set_format");
46         if(fmt.empty() || !is_format_supported(fmt))
47                 throw invalid_argument("Framebuffer::set_format");
48
49         format = fmt;
50         attachments.resize(format.size());
51 }
52
53 void Framebuffer::update() const
54 {
55         FramebufferBackend::update(dirty);
56         dirty = 0;
57 }
58
59 void Framebuffer::check_size()
60 {
61         bool first = true;
62         for(Attachment &a: attachments)
63                 if(a.tex)
64                 {
65                         unsigned w = 0;
66                         unsigned h = 0;
67                         if(const Texture2D *tex2d = dynamic_cast<const Texture2D *>(a.tex))
68                         {
69                                 w = max(tex2d->get_width()>>a.level, 1U);
70                                 h = max(tex2d->get_height()>>a.level, 1U);
71                         }
72                         else if(const Texture2DMultisample *tex2d_ms = dynamic_cast<const Texture2DMultisample *>(a.tex))
73                         {
74                                 w = tex2d_ms->get_width();
75                                 h = tex2d_ms->get_height();
76                         }
77                         else if(const Texture3D *tex3d = dynamic_cast<const Texture3D *>(a.tex))
78                         {
79                                 w = max(tex3d->get_width()>>a.level, 1U);
80                                 h = max(tex3d->get_height()>>a.level, 1U);
81                         }
82                         else if(const TextureCube *tex_cube = dynamic_cast<const TextureCube *>(a.tex))
83                         {
84                                 w = max(tex_cube->get_size()>>a.level, 1U);
85                                 h = w;
86                         }
87
88                         if(first)
89                         {
90                                 width = w;
91                                 height = h;
92                                 first = false;
93                         }
94                         else
95                         {
96                                 width = min(width, w);
97                                 height = min(height, h);
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 void Framebuffer::require_complete() const
173 {
174         bool layered = (!attachments.empty() && attachments.front().layer<0);
175         for(const Attachment &a: attachments)
176         {
177                 if(!a.tex)
178                         throw framebuffer_incomplete("missing attachment");
179                 if(layered!=(a.layer<0))
180                         throw framebuffer_incomplete("inconsistent layering");
181         }
182
183         FramebufferBackend::require_complete();
184 }
185
186
187 void Framebuffer::Attachment::set(Texture &t, unsigned l, int z)
188 {
189         tex = &t;
190         level = l;
191         layer = z;
192 }
193
194 void Framebuffer::Attachment::clear()
195 {
196         tex = 0;
197 }
198
199 } // namespace GL
200 } // namespace Msp