1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // Framebuffer.cpp: Implements the Framebuffer class. Implements GL framebuffer
16 // objects and related functionality.
17
18 #include "Framebuffer.h"
19
20 #include "main.h"
21 #include "Renderbuffer.h"
22 #include "Texture.h"
23 #include "utilities.h"
24
25 namespace gl
26 {
27
Framebuffer()28 Framebuffer::Framebuffer()
29 {
30 mColorbufferType = GL_NONE;
31 mDepthbufferType = GL_NONE;
32 mStencilbufferType = GL_NONE;
33 }
34
~Framebuffer()35 Framebuffer::~Framebuffer()
36 {
37 mColorbufferPointer = nullptr;
38 mDepthbufferPointer = nullptr;
39 mStencilbufferPointer = nullptr;
40 }
41
lookupRenderbuffer(GLenum type,GLuint handle) const42 Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const
43 {
44 Context *context = getContext();
45 Renderbuffer *buffer = nullptr;
46
47 if(type == GL_NONE)
48 {
49 buffer = nullptr;
50 }
51 else if(type == GL_RENDERBUFFER)
52 {
53 buffer = context->getRenderbuffer(handle);
54 }
55 else if(IsTextureTarget(type))
56 {
57 buffer = context->getTexture(handle)->getRenderbuffer(type);
58 }
59 else UNREACHABLE(type);
60
61 return buffer;
62 }
63
setColorbuffer(GLenum type,GLuint colorbuffer)64 void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer)
65 {
66 mColorbufferType = (colorbuffer != 0) ? type : GL_NONE;
67 mColorbufferPointer = lookupRenderbuffer(type, colorbuffer);
68 }
69
setDepthbuffer(GLenum type,GLuint depthbuffer)70 void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer)
71 {
72 mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE;
73 mDepthbufferPointer = lookupRenderbuffer(type, depthbuffer);
74 }
75
setStencilbuffer(GLenum type,GLuint stencilbuffer)76 void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer)
77 {
78 mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE;
79 mStencilbufferPointer = lookupRenderbuffer(type, stencilbuffer);
80 }
81
detachTexture(GLuint texture)82 void Framebuffer::detachTexture(GLuint texture)
83 {
84 if(mColorbufferPointer.name() == texture && IsTextureTarget(mColorbufferType))
85 {
86 mColorbufferType = GL_NONE;
87 mColorbufferPointer = nullptr;
88 }
89
90 if(mDepthbufferPointer.name() == texture && IsTextureTarget(mDepthbufferType))
91 {
92 mDepthbufferType = GL_NONE;
93 mDepthbufferPointer = nullptr;
94 }
95
96 if(mStencilbufferPointer.name() == texture && IsTextureTarget(mStencilbufferType))
97 {
98 mStencilbufferType = GL_NONE;
99 mStencilbufferPointer = nullptr;
100 }
101 }
102
detachRenderbuffer(GLuint renderbuffer)103 void Framebuffer::detachRenderbuffer(GLuint renderbuffer)
104 {
105 if(mColorbufferPointer.name() == renderbuffer && mColorbufferType == GL_RENDERBUFFER)
106 {
107 mColorbufferType = GL_NONE;
108 mColorbufferPointer = nullptr;
109 }
110
111 if(mDepthbufferPointer.name() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER)
112 {
113 mDepthbufferType = GL_NONE;
114 mDepthbufferPointer = nullptr;
115 }
116
117 if(mStencilbufferPointer.name() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER)
118 {
119 mStencilbufferType = GL_NONE;
120 mStencilbufferPointer = nullptr;
121 }
122 }
123
124 // Increments refcount on surface.
125 // caller must Release() the returned surface
getRenderTarget()126 Image *Framebuffer::getRenderTarget()
127 {
128 Renderbuffer *colorbuffer = mColorbufferPointer;
129
130 if(colorbuffer)
131 {
132 return colorbuffer->getRenderTarget();
133 }
134
135 return nullptr;
136 }
137
138 // Increments refcount on surface.
139 // caller must Release() the returned surface
getDepthStencil()140 Image *Framebuffer::getDepthStencil()
141 {
142 Renderbuffer *depthstencilbuffer = mDepthbufferPointer;
143
144 if(!depthstencilbuffer)
145 {
146 depthstencilbuffer = mStencilbufferPointer;
147 }
148
149 if(depthstencilbuffer)
150 {
151 return depthstencilbuffer->getRenderTarget();
152 }
153
154 return nullptr;
155 }
156
getColorbuffer()157 Renderbuffer *Framebuffer::getColorbuffer()
158 {
159 return mColorbufferPointer;
160 }
161
getDepthbuffer()162 Renderbuffer *Framebuffer::getDepthbuffer()
163 {
164 return mDepthbufferPointer;
165 }
166
getStencilbuffer()167 Renderbuffer *Framebuffer::getStencilbuffer()
168 {
169 return mStencilbufferPointer;
170 }
171
getColorbufferType()172 GLenum Framebuffer::getColorbufferType()
173 {
174 return mColorbufferType;
175 }
176
getDepthbufferType()177 GLenum Framebuffer::getDepthbufferType()
178 {
179 return mDepthbufferType;
180 }
181
getStencilbufferType()182 GLenum Framebuffer::getStencilbufferType()
183 {
184 return mStencilbufferType;
185 }
186
getColorbufferName()187 GLuint Framebuffer::getColorbufferName()
188 {
189 return mColorbufferPointer.name();
190 }
191
getDepthbufferName()192 GLuint Framebuffer::getDepthbufferName()
193 {
194 return mDepthbufferPointer.name();
195 }
196
getStencilbufferName()197 GLuint Framebuffer::getStencilbufferName()
198 {
199 return mStencilbufferPointer.name();
200 }
201
hasStencil()202 bool Framebuffer::hasStencil()
203 {
204 if(mStencilbufferType != GL_NONE)
205 {
206 Renderbuffer *stencilbufferObject = getStencilbuffer();
207
208 if(stencilbufferObject)
209 {
210 return stencilbufferObject->getStencilSize() > 0;
211 }
212 }
213
214 return false;
215 }
216
completeness()217 GLenum Framebuffer::completeness()
218 {
219 int width;
220 int height;
221 int samples;
222
223 return completeness(width, height, samples);
224 }
225
completeness(int & width,int & height,int & samples)226 GLenum Framebuffer::completeness(int &width, int &height, int &samples)
227 {
228 width = -1;
229 height = -1;
230 samples = -1;
231
232 if(mColorbufferType != GL_NONE)
233 {
234 Renderbuffer *colorbuffer = getColorbuffer();
235
236 if(!colorbuffer)
237 {
238 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
239 }
240
241 if(colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
242 {
243 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
244 }
245
246 if(mColorbufferType == GL_RENDERBUFFER)
247 {
248 if(!gl::IsColorRenderable(colorbuffer->getFormat()))
249 {
250 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
251 }
252 }
253 else if(IsTextureTarget(mColorbufferType))
254 {
255 GLenum format = colorbuffer->getFormat();
256
257 if(IsCompressed(format) ||
258 format == GL_ALPHA ||
259 format == GL_LUMINANCE ||
260 format == GL_LUMINANCE_ALPHA)
261 {
262 return GL_FRAMEBUFFER_UNSUPPORTED;
263 }
264
265 if(gl::IsDepthTexture(format) || gl::IsStencilTexture(format))
266 {
267 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
268 }
269 }
270 else
271 {
272 UNREACHABLE(mColorbufferType);
273 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
274 }
275
276 width = colorbuffer->getWidth();
277 height = colorbuffer->getHeight();
278 samples = colorbuffer->getSamples();
279 }
280
281 Renderbuffer *depthbuffer = nullptr;
282 Renderbuffer *stencilbuffer = nullptr;
283
284 if(mDepthbufferType != GL_NONE)
285 {
286 depthbuffer = getDepthbuffer();
287
288 if(!depthbuffer)
289 {
290 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
291 }
292
293 if(depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0)
294 {
295 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
296 }
297
298 if(mDepthbufferType == GL_RENDERBUFFER)
299 {
300 if(!gl::IsDepthRenderable(depthbuffer->getFormat()))
301 {
302 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
303 }
304 }
305 else if(IsTextureTarget(mDepthbufferType))
306 {
307 if(!gl::IsDepthTexture(depthbuffer->getFormat()))
308 {
309 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
310 }
311 }
312 else
313 {
314 UNREACHABLE(mDepthbufferType);
315 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
316 }
317
318 if(width == -1 || height == -1)
319 {
320 width = depthbuffer->getWidth();
321 height = depthbuffer->getHeight();
322 samples = depthbuffer->getSamples();
323 }
324 else if(width != depthbuffer->getWidth() || height != depthbuffer->getHeight())
325 {
326 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
327 }
328 else if(samples != depthbuffer->getSamples())
329 {
330 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
331 }
332 }
333
334 if(mStencilbufferType != GL_NONE)
335 {
336 stencilbuffer = getStencilbuffer();
337
338 if(!stencilbuffer)
339 {
340 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
341 }
342
343 if(stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0)
344 {
345 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
346 }
347
348 if(mStencilbufferType == GL_RENDERBUFFER)
349 {
350 if(!gl::IsStencilRenderable(stencilbuffer->getFormat()))
351 {
352 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
353 }
354 }
355 else if(IsTextureTarget(mStencilbufferType))
356 {
357 GLenum internalformat = stencilbuffer->getFormat();
358
359 if(!gl::IsStencilTexture(internalformat))
360 {
361 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
362 }
363 }
364 else
365 {
366 UNREACHABLE(mStencilbufferType);
367 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
368 }
369
370 if(width == -1 || height == -1)
371 {
372 width = stencilbuffer->getWidth();
373 height = stencilbuffer->getHeight();
374 samples = stencilbuffer->getSamples();
375 }
376 else if(width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight())
377 {
378 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
379 }
380 else if(samples != stencilbuffer->getSamples())
381 {
382 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
383 }
384 }
385
386 // If we have both a depth and stencil buffer, they must refer to the same object
387 // since we only support packed_depth_stencil and not separate depth and stencil
388 if(depthbuffer && stencilbuffer && (depthbuffer != stencilbuffer))
389 {
390 return GL_FRAMEBUFFER_UNSUPPORTED;
391 }
392
393 // We need to have at least one attachment to be complete
394 if(width == -1 || height == -1)
395 {
396 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
397 }
398
399 return GL_FRAMEBUFFER_COMPLETE;
400 }
401
DefaultFramebuffer(Colorbuffer * colorbuffer,DepthStencilbuffer * depthStencil)402 DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil)
403 {
404 mColorbufferPointer = new Renderbuffer(0, colorbuffer);
405
406 Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil);
407 mDepthbufferPointer = depthStencilRenderbuffer;
408 mStencilbufferPointer = depthStencilRenderbuffer;
409
410 mColorbufferType = GL_RENDERBUFFER;
411 mDepthbufferType = (depthStencilRenderbuffer->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
412 mStencilbufferType = (depthStencilRenderbuffer->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
413 }
414
completeness()415 GLenum DefaultFramebuffer::completeness()
416 {
417 // The default framebuffer should always be complete
418 ASSERT(Framebuffer::completeness() == GL_FRAMEBUFFER_COMPLETE);
419
420 return GL_FRAMEBUFFER_COMPLETE;
421 }
422
423 }
424