1 //
2 // Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer
8 // objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
9 
10 #include "libGLESv2/Framebuffer.h"
11 
12 #include "libGLESv2/main.h"
13 #include "libGLESv2/Renderbuffer.h"
14 #include "libGLESv2/Texture.h"
15 #include "libGLESv2/utilities.h"
16 
17 namespace gl
18 {
19 
Framebuffer()20 Framebuffer::Framebuffer()
21 {
22     mColorbufferType = GL_NONE;
23     mDepthbufferType = GL_NONE;
24     mStencilbufferType = GL_NONE;
25 }
26 
~Framebuffer()27 Framebuffer::~Framebuffer()
28 {
29     mColorbufferPointer.set(NULL);
30     mDepthbufferPointer.set(NULL);
31     mStencilbufferPointer.set(NULL);
32 }
33 
lookupRenderbuffer(GLenum type,GLuint handle) const34 Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const
35 {
36     gl::Context *context = gl::getContext();
37     Renderbuffer *buffer = NULL;
38 
39     if (type == GL_NONE)
40     {
41         buffer = NULL;
42     }
43     else if (type == GL_RENDERBUFFER)
44     {
45         buffer = context->getRenderbuffer(handle);
46     }
47     else if (IsTextureTarget(type))
48     {
49         buffer = context->getTexture(handle)->getColorbuffer(type);
50     }
51     else
52     {
53         UNREACHABLE();
54     }
55 
56     return buffer;
57 }
58 
setColorbuffer(GLenum type,GLuint colorbuffer)59 void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer)
60 {
61     mColorbufferType = type;
62     mColorbufferPointer.set(lookupRenderbuffer(type, colorbuffer));
63 }
64 
setDepthbuffer(GLenum type,GLuint depthbuffer)65 void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer)
66 {
67     mDepthbufferType = type;
68     mDepthbufferPointer.set(lookupRenderbuffer(type, depthbuffer));
69 }
70 
setStencilbuffer(GLenum type,GLuint stencilbuffer)71 void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer)
72 {
73     mStencilbufferType = type;
74     mStencilbufferPointer.set(lookupRenderbuffer(type, stencilbuffer));
75 }
76 
detachTexture(GLuint texture)77 void Framebuffer::detachTexture(GLuint texture)
78 {
79     if (mColorbufferPointer.id() == texture && IsTextureTarget(mColorbufferType))
80     {
81         mColorbufferType = GL_NONE;
82         mColorbufferPointer.set(NULL);
83     }
84 
85     if (mDepthbufferPointer.id() == texture && IsTextureTarget(mDepthbufferType))
86     {
87         mDepthbufferType = GL_NONE;
88         mDepthbufferPointer.set(NULL);
89     }
90 
91     if (mStencilbufferPointer.id() == texture && IsTextureTarget(mStencilbufferType))
92     {
93         mStencilbufferType = GL_NONE;
94         mStencilbufferPointer.set(NULL);
95     }
96 }
97 
detachRenderbuffer(GLuint renderbuffer)98 void Framebuffer::detachRenderbuffer(GLuint renderbuffer)
99 {
100     if (mColorbufferPointer.id() == renderbuffer && mColorbufferType == GL_RENDERBUFFER)
101     {
102         mColorbufferType = GL_NONE;
103         mColorbufferPointer.set(NULL);
104     }
105 
106     if (mDepthbufferPointer.id() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER)
107     {
108         mDepthbufferType = GL_NONE;
109         mDepthbufferPointer.set(NULL);
110     }
111 
112     if (mStencilbufferPointer.id() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER)
113     {
114         mStencilbufferType = GL_NONE;
115         mStencilbufferPointer.set(NULL);
116     }
117 }
118 
getRenderTargetSerial()119 unsigned int Framebuffer::getRenderTargetSerial()
120 {
121     Renderbuffer *colorbuffer = mColorbufferPointer.get();
122 
123     if (colorbuffer)
124     {
125         return colorbuffer->getSerial();
126     }
127 
128     return 0;
129 }
130 
getRenderTarget()131 IDirect3DSurface9 *Framebuffer::getRenderTarget()
132 {
133     Renderbuffer *colorbuffer = mColorbufferPointer.get();
134 
135     if (colorbuffer)
136     {
137         return colorbuffer->getRenderTarget();
138     }
139 
140     return NULL;
141 }
142 
getDepthStencil()143 IDirect3DSurface9 *Framebuffer::getDepthStencil()
144 {
145     Renderbuffer *depthstencilbuffer = mDepthbufferPointer.get();
146 
147     if (!depthstencilbuffer)
148     {
149         depthstencilbuffer = mStencilbufferPointer.get();
150     }
151 
152     if (depthstencilbuffer)
153     {
154         return depthstencilbuffer->getDepthStencil();
155     }
156 
157     return NULL;
158 }
159 
getDepthbufferSerial()160 unsigned int Framebuffer::getDepthbufferSerial()
161 {
162     Renderbuffer *depthbuffer = mDepthbufferPointer.get();
163 
164     if (depthbuffer)
165     {
166         return depthbuffer->getSerial();
167     }
168 
169     return 0;
170 }
171 
getStencilbufferSerial()172 unsigned int Framebuffer::getStencilbufferSerial()
173 {
174     Renderbuffer *stencilbuffer = mStencilbufferPointer.get();
175 
176     if (stencilbuffer)
177     {
178         return stencilbuffer->getSerial();
179     }
180 
181     return 0;
182 }
183 
getColorbuffer()184 Colorbuffer *Framebuffer::getColorbuffer()
185 {
186     Renderbuffer *rb = mColorbufferPointer.get();
187 
188     if (rb != NULL && rb->isColorbuffer())
189     {
190         return static_cast<Colorbuffer*>(rb->getStorage());
191     }
192     else
193     {
194         return NULL;
195     }
196 }
197 
getDepthbuffer()198 DepthStencilbuffer *Framebuffer::getDepthbuffer()
199 {
200     Renderbuffer *rb = mDepthbufferPointer.get();
201 
202     if (rb != NULL && rb->isDepthbuffer())
203     {
204         return static_cast<DepthStencilbuffer*>(rb->getStorage());
205     }
206     else
207     {
208         return NULL;
209     }
210 }
211 
getStencilbuffer()212 DepthStencilbuffer *Framebuffer::getStencilbuffer()
213 {
214     Renderbuffer *rb = mStencilbufferPointer.get();
215 
216     if (rb != NULL && rb->isStencilbuffer())
217     {
218         return static_cast<DepthStencilbuffer*>(rb->getStorage());
219     }
220     else
221     {
222         return NULL;
223     }
224 }
225 
getColorbufferType()226 GLenum Framebuffer::getColorbufferType()
227 {
228     return mColorbufferType;
229 }
230 
getDepthbufferType()231 GLenum Framebuffer::getDepthbufferType()
232 {
233     return mDepthbufferType;
234 }
235 
getStencilbufferType()236 GLenum Framebuffer::getStencilbufferType()
237 {
238     return mStencilbufferType;
239 }
240 
getColorbufferHandle()241 GLuint Framebuffer::getColorbufferHandle()
242 {
243     return mColorbufferPointer.id();
244 }
245 
getDepthbufferHandle()246 GLuint Framebuffer::getDepthbufferHandle()
247 {
248     return mDepthbufferPointer.id();
249 }
250 
getStencilbufferHandle()251 GLuint Framebuffer::getStencilbufferHandle()
252 {
253     return mStencilbufferPointer.id();
254 }
255 
hasStencil()256 bool Framebuffer::hasStencil()
257 {
258     if (mStencilbufferType != GL_NONE)
259     {
260         DepthStencilbuffer *stencilbufferObject = getStencilbuffer();
261 
262         if (stencilbufferObject)
263         {
264             return stencilbufferObject->getStencilSize() > 0;
265         }
266     }
267 
268     return false;
269 }
270 
isMultisample()271 bool Framebuffer::isMultisample()
272 {
273     // If the framebuffer is not complete, attachment samples may be mismatched, and it
274     // cannot be used as a multisample framebuffer. If it is complete, it is required to
275     // have a color attachment, and all its attachments must have the same number of samples,
276     // so the number of samples for the colorbuffer will indicate whether the framebuffer is
277     // multisampled.
278     if (completeness() == GL_FRAMEBUFFER_COMPLETE && getColorbuffer()->getSamples() > 0)
279     {
280         return true;
281     }
282     else
283     {
284         return false;
285     }
286 }
287 
completeness()288 GLenum Framebuffer::completeness()
289 {
290     int width = 0;
291     int height = 0;
292     int samples = -1;
293 
294     if (mColorbufferType != GL_NONE)
295     {
296         Colorbuffer *colorbuffer = getColorbuffer();
297 
298         if (!colorbuffer)
299         {
300             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
301         }
302 
303         if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
304         {
305             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
306         }
307 
308         if (mColorbufferType == GL_RENDERBUFFER)
309         {
310             if (!gl::IsColorRenderable(colorbuffer->getFormat()))
311             {
312                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
313             }
314         }
315         else if (IsTextureTarget(mColorbufferType))
316         {
317             if (IsCompressed(colorbuffer->getFormat()))
318             {
319                 return GL_FRAMEBUFFER_UNSUPPORTED;
320             }
321 
322             if (colorbuffer->isFloatingPoint() && (!getContext()->supportsFloatRenderableTextures() ||
323                                                    !getContext()->supportsHalfFloatRenderableTextures()))
324             {
325                 return GL_FRAMEBUFFER_UNSUPPORTED;
326             }
327 
328             if (colorbuffer->getFormat() == GL_LUMINANCE || colorbuffer->getFormat() == GL_LUMINANCE_ALPHA)
329             {
330                 return GL_FRAMEBUFFER_UNSUPPORTED;
331             }
332         }
333         else UNREACHABLE();
334 
335         width = colorbuffer->getWidth();
336         height = colorbuffer->getHeight();
337         samples = colorbuffer->getSamples();
338     }
339     else
340     {
341         return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
342     }
343 
344     DepthStencilbuffer *depthbuffer = NULL;
345     DepthStencilbuffer *stencilbuffer = NULL;
346 
347     if (mDepthbufferType != GL_NONE)
348     {
349         if (mDepthbufferType != GL_RENDERBUFFER)
350         {
351             return GL_FRAMEBUFFER_UNSUPPORTED;   // Requires GL_OES_depth_texture
352         }
353 
354         depthbuffer = getDepthbuffer();
355 
356         if (!depthbuffer)
357         {
358             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
359         }
360 
361         if (depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0)
362         {
363             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
364         }
365 
366         if (width == 0)
367         {
368             width = depthbuffer->getWidth();
369             height = depthbuffer->getHeight();
370         }
371         else if (width != depthbuffer->getWidth() || height != depthbuffer->getHeight())
372         {
373             return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
374         }
375 
376         if (samples == -1)
377         {
378             samples = depthbuffer->getSamples();
379         }
380         else if (samples != depthbuffer->getSamples())
381         {
382             return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
383         }
384     }
385 
386     if (mStencilbufferType != GL_NONE)
387     {
388         if (mStencilbufferType != GL_RENDERBUFFER)
389         {
390             return GL_FRAMEBUFFER_UNSUPPORTED;
391         }
392 
393         stencilbuffer = getStencilbuffer();
394 
395         if (!stencilbuffer)
396         {
397             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
398         }
399 
400         if (stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0)
401         {
402             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
403         }
404 
405         if (width == 0)
406         {
407             width = stencilbuffer->getWidth();
408             height = stencilbuffer->getHeight();
409         }
410         else if (width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight())
411         {
412             return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
413         }
414 
415         if (samples == -1)
416         {
417             samples = stencilbuffer->getSamples();
418         }
419         else if (samples != stencilbuffer->getSamples())
420         {
421             return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
422         }
423     }
424 
425     if (mDepthbufferType == GL_RENDERBUFFER && mStencilbufferType == GL_RENDERBUFFER)
426     {
427         if (depthbuffer->getFormat() != GL_DEPTH24_STENCIL8_OES ||
428             stencilbuffer->getFormat() != GL_DEPTH24_STENCIL8_OES ||
429             depthbuffer->getSerial() != stencilbuffer->getSerial())
430         {
431             return GL_FRAMEBUFFER_UNSUPPORTED;
432         }
433     }
434 
435     return GL_FRAMEBUFFER_COMPLETE;
436 }
437 
DefaultFramebuffer(Colorbuffer * color,DepthStencilbuffer * depthStencil)438 DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *color, DepthStencilbuffer *depthStencil)
439 {
440     mColorbufferType = GL_RENDERBUFFER;
441     mDepthbufferType = (depthStencil->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
442     mStencilbufferType = (depthStencil->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
443 
444     mColorbufferPointer.set(new Renderbuffer(0, color));
445 
446     Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil);
447     mDepthbufferPointer.set(depthStencilRenderbuffer);
448     mStencilbufferPointer.set(depthStencilRenderbuffer);
449 }
450 
getSamples()451 int Framebuffer::getSamples()
452 {
453     if (completeness() == GL_FRAMEBUFFER_COMPLETE)
454     {
455         return getColorbuffer()->getSamples();
456     }
457     else
458     {
459         return 0;
460     }
461 }
462 
completeness()463 GLenum DefaultFramebuffer::completeness()
464 {
465     // The default framebuffer should always be complete
466     ASSERT(Framebuffer::completeness() == GL_FRAMEBUFFER_COMPLETE);
467 
468     return GL_FRAMEBUFFER_COMPLETE;
469 }
470 
471 }
472