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