• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "precompiled.h"
2 //
3 // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6 //
7 
8 // Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer
9 // objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
10 
11 #include "libGLESv2/Framebuffer.h"
12 
13 #include "libGLESv2/main.h"
14 #include "libGLESv2/utilities.h"
15 #include "libGLESv2/Texture.h"
16 #include "libGLESv2/Context.h"
17 #include "libGLESv2/renderer/Renderer.h"
18 #include "libGLESv2/Renderbuffer.h"
19 
20 namespace gl
21 {
22 
Framebuffer(rx::Renderer * renderer)23 Framebuffer::Framebuffer(rx::Renderer *renderer)
24     : mRenderer(renderer)
25 {
26     for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
27     {
28         mColorbufferTypes[colorAttachment] = GL_NONE;
29         mDrawBufferStates[colorAttachment] = GL_NONE;
30     }
31     mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
32     mReadBufferState = GL_COLOR_ATTACHMENT0_EXT;
33 
34     mDepthbufferType = GL_NONE;
35     mStencilbufferType = GL_NONE;
36 }
37 
~Framebuffer()38 Framebuffer::~Framebuffer()
39 {
40     for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
41     {
42         mColorbufferPointers[colorAttachment].set(NULL);
43     }
44     mDepthbufferPointer.set(NULL);
45     mStencilbufferPointer.set(NULL);
46 }
47 
lookupRenderbuffer(GLenum type,GLuint handle) const48 Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const
49 {
50     gl::Context *context = gl::getContext();
51     Renderbuffer *buffer = NULL;
52 
53     if (type == GL_NONE)
54     {
55         buffer = NULL;
56     }
57     else if (type == GL_RENDERBUFFER)
58     {
59         buffer = context->getRenderbuffer(handle);
60     }
61     else if (IsInternalTextureTarget(type))
62     {
63         buffer = context->getTexture(handle)->getRenderbuffer(type);
64     }
65     else
66     {
67         UNREACHABLE();
68     }
69 
70     return buffer;
71 }
72 
setColorbuffer(unsigned int colorAttachment,GLenum type,GLuint colorbuffer)73 void Framebuffer::setColorbuffer(unsigned int colorAttachment, GLenum type, GLuint colorbuffer)
74 {
75     ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
76     mColorbufferTypes[colorAttachment] = (colorbuffer != 0) ? type : GL_NONE;
77     mColorbufferPointers[colorAttachment].set(lookupRenderbuffer(type, colorbuffer));
78 }
79 
setDepthbuffer(GLenum type,GLuint depthbuffer)80 void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer)
81 {
82     mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE;
83     mDepthbufferPointer.set(lookupRenderbuffer(type, depthbuffer));
84 }
85 
setStencilbuffer(GLenum type,GLuint stencilbuffer)86 void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer)
87 {
88     mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE;
89     mStencilbufferPointer.set(lookupRenderbuffer(type, stencilbuffer));
90 }
91 
detachTexture(GLuint texture)92 void Framebuffer::detachTexture(GLuint texture)
93 {
94     for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
95     {
96         if (mColorbufferPointers[colorAttachment].id() == texture && IsInternalTextureTarget(mColorbufferTypes[colorAttachment]))
97         {
98             mColorbufferTypes[colorAttachment] = GL_NONE;
99             mColorbufferPointers[colorAttachment].set(NULL);
100         }
101     }
102 
103     if (mDepthbufferPointer.id() == texture && IsInternalTextureTarget(mDepthbufferType))
104     {
105         mDepthbufferType = GL_NONE;
106         mDepthbufferPointer.set(NULL);
107     }
108 
109     if (mStencilbufferPointer.id() == texture && IsInternalTextureTarget(mStencilbufferType))
110     {
111         mStencilbufferType = GL_NONE;
112         mStencilbufferPointer.set(NULL);
113     }
114 }
115 
detachRenderbuffer(GLuint renderbuffer)116 void Framebuffer::detachRenderbuffer(GLuint renderbuffer)
117 {
118     for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
119     {
120         if (mColorbufferPointers[colorAttachment].id() == renderbuffer && mColorbufferTypes[colorAttachment] == GL_RENDERBUFFER)
121         {
122             mColorbufferTypes[colorAttachment] = GL_NONE;
123             mColorbufferPointers[colorAttachment].set(NULL);
124         }
125     }
126 
127     if (mDepthbufferPointer.id() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER)
128     {
129         mDepthbufferType = GL_NONE;
130         mDepthbufferPointer.set(NULL);
131     }
132 
133     if (mStencilbufferPointer.id() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER)
134     {
135         mStencilbufferType = GL_NONE;
136         mStencilbufferPointer.set(NULL);
137     }
138 }
139 
getRenderTargetSerial(unsigned int colorAttachment) const140 unsigned int Framebuffer::getRenderTargetSerial(unsigned int colorAttachment) const
141 {
142     ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
143 
144     Renderbuffer *colorbuffer = mColorbufferPointers[colorAttachment].get();
145 
146     if (colorbuffer)
147     {
148         return colorbuffer->getSerial();
149     }
150 
151     return 0;
152 }
153 
getDepthbufferSerial() const154 unsigned int Framebuffer::getDepthbufferSerial() const
155 {
156     Renderbuffer *depthbuffer = mDepthbufferPointer.get();
157 
158     if (depthbuffer)
159     {
160         return depthbuffer->getSerial();
161     }
162 
163     return 0;
164 }
165 
getStencilbufferSerial() const166 unsigned int Framebuffer::getStencilbufferSerial() const
167 {
168     Renderbuffer *stencilbuffer = mStencilbufferPointer.get();
169 
170     if (stencilbuffer)
171     {
172         return stencilbuffer->getSerial();
173     }
174 
175     return 0;
176 }
177 
getColorbuffer(unsigned int colorAttachment) const178 Renderbuffer *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
179 {
180     ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
181     return mColorbufferPointers[colorAttachment].get();
182 }
183 
getDepthbuffer() const184 Renderbuffer *Framebuffer::getDepthbuffer() const
185 {
186     return mDepthbufferPointer.get();
187 }
188 
getStencilbuffer() const189 Renderbuffer *Framebuffer::getStencilbuffer() const
190 {
191     return mStencilbufferPointer.get();
192 }
193 
getDepthOrStencilbuffer() const194 Renderbuffer *Framebuffer::getDepthOrStencilbuffer() const
195 {
196     Renderbuffer *depthstencilbuffer = mDepthbufferPointer.get();
197 
198     if (!depthstencilbuffer)
199     {
200         depthstencilbuffer = mStencilbufferPointer.get();
201     }
202 
203     return depthstencilbuffer;
204 }
205 
getReadColorbuffer() const206 Renderbuffer *Framebuffer::getReadColorbuffer() const
207 {
208     // Will require more logic if glReadBuffers is supported
209     return mColorbufferPointers[0].get();
210 }
211 
getReadColorbufferType() const212 GLenum Framebuffer::getReadColorbufferType() const
213 {
214     // Will require more logic if glReadBuffers is supported
215     return mColorbufferTypes[0];
216 }
217 
getFirstColorbuffer() const218 Renderbuffer *Framebuffer::getFirstColorbuffer() const
219 {
220     for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
221     {
222         if (mColorbufferTypes[colorAttachment] != GL_NONE)
223         {
224             return mColorbufferPointers[colorAttachment].get();
225         }
226     }
227 
228     return NULL;
229 }
230 
getColorbufferType(unsigned int colorAttachment) const231 GLenum Framebuffer::getColorbufferType(unsigned int colorAttachment) const
232 {
233     ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
234     return mColorbufferTypes[colorAttachment];
235 }
236 
getDepthbufferType() const237 GLenum Framebuffer::getDepthbufferType() const
238 {
239     return mDepthbufferType;
240 }
241 
getStencilbufferType() const242 GLenum Framebuffer::getStencilbufferType() const
243 {
244     return mStencilbufferType;
245 }
246 
getColorbufferHandle(unsigned int colorAttachment) const247 GLuint Framebuffer::getColorbufferHandle(unsigned int colorAttachment) const
248 {
249     ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
250     return mColorbufferPointers[colorAttachment].id();
251 }
252 
getDepthbufferHandle() const253 GLuint Framebuffer::getDepthbufferHandle() const
254 {
255     return mDepthbufferPointer.id();
256 }
257 
getStencilbufferHandle() const258 GLuint Framebuffer::getStencilbufferHandle() const
259 {
260     return mStencilbufferPointer.id();
261 }
262 
getDrawBufferState(unsigned int colorAttachment) const263 GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
264 {
265     return mDrawBufferStates[colorAttachment];
266 }
267 
setDrawBufferState(unsigned int colorAttachment,GLenum drawBuffer)268 void Framebuffer::setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer)
269 {
270     mDrawBufferStates[colorAttachment] = drawBuffer;
271 }
272 
isEnabledColorAttachment(unsigned int colorAttachment) const273 bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
274 {
275     return (mColorbufferTypes[colorAttachment] != GL_NONE && mDrawBufferStates[colorAttachment] != GL_NONE);
276 }
277 
hasEnabledColorAttachment() const278 bool Framebuffer::hasEnabledColorAttachment() const
279 {
280     for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
281     {
282         if (isEnabledColorAttachment(colorAttachment))
283         {
284             return true;
285         }
286     }
287 
288     return false;
289 }
290 
hasStencil() const291 bool Framebuffer::hasStencil() const
292 {
293     if (mStencilbufferType != GL_NONE)
294     {
295         const Renderbuffer *stencilbufferObject = getStencilbuffer();
296 
297         if (stencilbufferObject)
298         {
299             return stencilbufferObject->getStencilSize() > 0;
300         }
301     }
302 
303     return false;
304 }
305 
usingExtendedDrawBuffers() const306 bool Framebuffer::usingExtendedDrawBuffers() const
307 {
308     for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
309     {
310         if (isEnabledColorAttachment(colorAttachment))
311         {
312             return true;
313         }
314     }
315 
316     return false;
317 }
318 
completeness() const319 GLenum Framebuffer::completeness() const
320 {
321     int width = 0;
322     int height = 0;
323     int colorbufferSize = 0;
324     int samples = -1;
325     bool missingAttachment = true;
326 
327     for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
328     {
329         if (mColorbufferTypes[colorAttachment] != GL_NONE)
330         {
331             const Renderbuffer *colorbuffer = getColorbuffer(colorAttachment);
332 
333             if (!colorbuffer)
334             {
335                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
336             }
337 
338             if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
339             {
340                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
341             }
342 
343             if (mColorbufferTypes[colorAttachment] == GL_RENDERBUFFER)
344             {
345                 if (!gl::IsColorRenderable(colorbuffer->getInternalFormat()))
346                 {
347                     return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
348                 }
349             }
350             else if (IsInternalTextureTarget(mColorbufferTypes[colorAttachment]))
351             {
352                 GLint internalformat = colorbuffer->getInternalFormat();
353                 GLenum format = gl::ExtractFormat(internalformat);
354 
355                 if (IsCompressed(format) ||
356                     format == GL_ALPHA ||
357                     format == GL_LUMINANCE ||
358                     format == GL_LUMINANCE_ALPHA)
359                 {
360                     return GL_FRAMEBUFFER_UNSUPPORTED;
361                 }
362 
363                 bool filtering, renderable;
364 
365                 if ((gl::IsFloat32Format(internalformat) && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) ||
366                     (gl::IsFloat16Format(internalformat) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable)))
367                 {
368                     return GL_FRAMEBUFFER_UNSUPPORTED;
369                 }
370 
371                 if (gl::IsDepthTexture(internalformat) || gl::IsStencilTexture(internalformat))
372                 {
373                     return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
374                 }
375             }
376             else
377             {
378                 UNREACHABLE();
379                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
380             }
381 
382             if (!missingAttachment)
383             {
384                 // all color attachments must have the same width and height
385                 if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height)
386                 {
387                     return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
388                 }
389 
390                 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
391                 // all color attachments have the same number of samples for the FBO to be complete.
392                 if (colorbuffer->getSamples() != samples)
393                 {
394                     return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
395                 }
396 
397                 // all color attachments attachments must have the same number of bitplanes
398                 if (gl::ComputePixelSize(colorbuffer->getInternalFormat()) != colorbufferSize)
399                 {
400                     return GL_FRAMEBUFFER_UNSUPPORTED;
401                 }
402 
403                 // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness
404                 for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++)
405                 {
406                     if (mColorbufferPointers[colorAttachment].get() == mColorbufferPointers[previousColorAttachment].get())
407                     {
408                         return GL_FRAMEBUFFER_UNSUPPORTED;
409                     }
410                 }
411             }
412             else
413             {
414                 width = colorbuffer->getWidth();
415                 height = colorbuffer->getHeight();
416                 samples = colorbuffer->getSamples();
417                 colorbufferSize = gl::ComputePixelSize(colorbuffer->getInternalFormat());
418                 missingAttachment = false;
419             }
420         }
421     }
422 
423     const Renderbuffer *depthbuffer = NULL;
424     const Renderbuffer *stencilbuffer = NULL;
425 
426     if (mDepthbufferType != GL_NONE)
427     {
428         depthbuffer = getDepthbuffer();
429 
430         if (!depthbuffer)
431         {
432             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
433         }
434 
435         if (depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0)
436         {
437             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
438         }
439 
440         if (mDepthbufferType == GL_RENDERBUFFER)
441         {
442             if (!gl::IsDepthRenderable(depthbuffer->getInternalFormat()))
443             {
444                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
445             }
446         }
447         else if (IsInternalTextureTarget(mDepthbufferType))
448         {
449             GLint internalformat = depthbuffer->getInternalFormat();
450 
451             // depth texture attachments require OES/ANGLE_depth_texture
452             if (!mRenderer->getDepthTextureSupport())
453             {
454                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
455             }
456 
457             if (!gl::IsDepthTexture(internalformat))
458             {
459                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
460             }
461         }
462         else
463         {
464             UNREACHABLE();
465             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
466         }
467 
468         if (missingAttachment)
469         {
470             width = depthbuffer->getWidth();
471             height = depthbuffer->getHeight();
472             samples = depthbuffer->getSamples();
473             missingAttachment = false;
474         }
475         else if (width != depthbuffer->getWidth() || height != depthbuffer->getHeight())
476         {
477             return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
478         }
479         else if (samples != depthbuffer->getSamples())
480         {
481             return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
482         }
483     }
484 
485     if (mStencilbufferType != GL_NONE)
486     {
487         stencilbuffer = getStencilbuffer();
488 
489         if (!stencilbuffer)
490         {
491             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
492         }
493 
494         if (stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0)
495         {
496             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
497         }
498 
499         if (mStencilbufferType == GL_RENDERBUFFER)
500         {
501             if (!gl::IsStencilRenderable(stencilbuffer->getInternalFormat()))
502             {
503                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
504             }
505         }
506         else if (IsInternalTextureTarget(mStencilbufferType))
507         {
508             GLint internalformat = stencilbuffer->getInternalFormat();
509 
510             // texture stencil attachments come along as part
511             // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
512             if (!mRenderer->getDepthTextureSupport())
513             {
514                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
515             }
516 
517             if (!gl::IsStencilTexture(internalformat))
518             {
519                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
520             }
521         }
522         else
523         {
524             UNREACHABLE();
525             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
526         }
527 
528         if (missingAttachment)
529         {
530             width = stencilbuffer->getWidth();
531             height = stencilbuffer->getHeight();
532             samples = stencilbuffer->getSamples();
533             missingAttachment = false;
534         }
535         else if (width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight())
536         {
537             return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
538         }
539         else if (samples != stencilbuffer->getSamples())
540         {
541             return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
542         }
543     }
544 
545     // if we have both a depth and stencil buffer, they must refer to the same object
546     // since we only support packed_depth_stencil and not separate depth and stencil
547     if (depthbuffer && stencilbuffer && (depthbuffer != stencilbuffer))
548     {
549         return GL_FRAMEBUFFER_UNSUPPORTED;
550     }
551 
552     // we need to have at least one attachment to be complete
553     if (missingAttachment)
554     {
555         return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
556     }
557 
558     return GL_FRAMEBUFFER_COMPLETE;
559 }
560 
DefaultFramebuffer(rx::Renderer * renderer,Colorbuffer * colorbuffer,DepthStencilbuffer * depthStencil)561 DefaultFramebuffer::DefaultFramebuffer(rx::Renderer *renderer, Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil)
562     : Framebuffer(renderer)
563 {
564     mColorbufferPointers[0].set(new Renderbuffer(mRenderer, 0, colorbuffer));
565 
566     Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(mRenderer, 0, depthStencil);
567     mDepthbufferPointer.set(depthStencilRenderbuffer);
568     mStencilbufferPointer.set(depthStencilRenderbuffer);
569 
570     mColorbufferTypes[0] = GL_RENDERBUFFER;
571     mDepthbufferType = (depthStencilRenderbuffer->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
572     mStencilbufferType = (depthStencilRenderbuffer->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
573 
574     mDrawBufferStates[0] = GL_BACK;
575     mReadBufferState = GL_BACK;
576 }
577 
getSamples() const578 int Framebuffer::getSamples() const
579 {
580     if (completeness() == GL_FRAMEBUFFER_COMPLETE)
581     {
582         // for a complete framebuffer, all attachments must have the same sample count
583         // in this case return the first nonzero sample size
584         for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
585         {
586             if (mColorbufferTypes[colorAttachment] != GL_NONE)
587             {
588                 return getColorbuffer(colorAttachment)->getSamples();
589             }
590         }
591     }
592 
593     return 0;
594 }
595 
completeness() const596 GLenum DefaultFramebuffer::completeness() const
597 {
598     // The default framebuffer *must* always be complete, though it may not be
599     // subject to the same rules as application FBOs. ie, it could have 0x0 size.
600     return GL_FRAMEBUFFER_COMPLETE;
601 }
602 
603 }
604