• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (c) 2002-2014 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 #include "libGLESv2/main.h"
12 #include "libGLESv2/formatutils.h"
13 #include "libGLESv2/Texture.h"
14 #include "libGLESv2/Context.h"
15 #include "libGLESv2/Renderbuffer.h"
16 #include "libGLESv2/FramebufferAttachment.h"
17 #include "libGLESv2/renderer/Renderer.h"
18 #include "libGLESv2/renderer/RenderTarget.h"
19 #include "libGLESv2/renderer/d3d/TextureD3D.h"
20 
21 #include "common/utilities.h"
22 
23 namespace rx
24 {
GetAttachmentRenderTarget(gl::FramebufferAttachment * attachment)25 RenderTarget *GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment)
26 {
27     if (attachment->isTexture())
28     {
29         gl::Texture *texture = attachment->getTexture();
30         ASSERT(texture);
31         TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation());
32         const gl::ImageIndex *index = attachment->getTextureImageIndex();
33         ASSERT(index);
34         return textureD3D->getRenderTarget(*index);
35     }
36 
37     gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer();
38     ASSERT(renderbuffer);
39 
40     // TODO: cast to RenderbufferD3D
41     return renderbuffer->getStorage()->getRenderTarget();
42 }
43 
44 // Note: RenderTarget serials should ideally be in the RenderTargets themselves.
GetAttachmentSerial(gl::FramebufferAttachment * attachment)45 unsigned int GetAttachmentSerial(gl::FramebufferAttachment *attachment)
46 {
47     if (attachment->isTexture())
48     {
49         gl::Texture *texture = attachment->getTexture();
50         ASSERT(texture);
51         TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation());
52         const gl::ImageIndex *index = attachment->getTextureImageIndex();
53         ASSERT(index);
54         return textureD3D->getRenderTargetSerial(*index);
55     }
56 
57     gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer();
58     ASSERT(renderbuffer);
59 
60     // TODO: cast to RenderbufferD3D
61     return renderbuffer->getStorage()->getSerial();
62 }
63 
64 }
65 
66 namespace gl
67 {
68 
Framebuffer(rx::Renderer * renderer,GLuint id)69 Framebuffer::Framebuffer(rx::Renderer *renderer, GLuint id)
70     : mRenderer(renderer),
71       mId(id),
72       mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
73       mDepthbuffer(NULL),
74       mStencilbuffer(NULL)
75 {
76     for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
77     {
78         mColorbuffers[colorAttachment] = NULL;
79         mDrawBufferStates[colorAttachment] = GL_NONE;
80     }
81     mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
82 }
83 
~Framebuffer()84 Framebuffer::~Framebuffer()
85 {
86     for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
87     {
88         SafeDelete(mColorbuffers[colorAttachment]);
89     }
90     SafeDelete(mDepthbuffer);
91     SafeDelete(mStencilbuffer);
92 }
93 
createAttachment(GLenum binding,GLenum type,GLuint handle,GLint level,GLint layer) const94 FramebufferAttachment *Framebuffer::createAttachment(GLenum binding, GLenum type, GLuint handle, GLint level, GLint layer) const
95 {
96     if (handle == 0)
97     {
98         return NULL;
99     }
100 
101     gl::Context *context = gl::getContext();
102 
103     switch (type)
104     {
105       case GL_NONE:
106         return NULL;
107 
108       case GL_RENDERBUFFER:
109         return new RenderbufferAttachment(binding, context->getRenderbuffer(handle));
110 
111       case GL_TEXTURE_2D:
112         {
113             Texture *texture = context->getTexture(handle);
114             if (texture && texture->getTarget() == GL_TEXTURE_2D)
115             {
116                 return new TextureAttachment(binding, texture, ImageIndex::Make2D(level));
117             }
118             else
119             {
120                 return NULL;
121             }
122         }
123 
124       case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
125       case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
126       case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
127       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
128       case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
129       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
130         {
131             Texture *texture = context->getTexture(handle);
132             if (texture && texture->getTarget() == GL_TEXTURE_CUBE_MAP)
133             {
134                 return new TextureAttachment(binding, texture, ImageIndex::MakeCube(type, level));
135             }
136             else
137             {
138                 return NULL;
139             }
140         }
141 
142       case GL_TEXTURE_3D:
143         {
144             Texture *texture = context->getTexture(handle);
145             if (texture && texture->getTarget() == GL_TEXTURE_3D)
146             {
147                 return new TextureAttachment(binding, texture, ImageIndex::Make3D(level, layer));
148             }
149             else
150             {
151                 return NULL;
152             }
153         }
154 
155       case GL_TEXTURE_2D_ARRAY:
156         {
157             Texture *texture = context->getTexture(handle);
158             if (texture && texture->getTarget() == GL_TEXTURE_2D_ARRAY)
159             {
160                 return new TextureAttachment(binding, texture, ImageIndex::Make2DArray(level, layer));
161             }
162             else
163             {
164                 return NULL;
165             }
166         }
167 
168       default:
169         UNREACHABLE();
170         return NULL;
171     }
172 }
173 
setColorbuffer(unsigned int colorAttachment,GLenum type,GLuint colorbuffer,GLint level,GLint layer)174 void Framebuffer::setColorbuffer(unsigned int colorAttachment, GLenum type, GLuint colorbuffer, GLint level, GLint layer)
175 {
176     ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
177     SafeDelete(mColorbuffers[colorAttachment]);
178     GLenum binding = colorAttachment + GL_COLOR_ATTACHMENT0;
179     mColorbuffers[colorAttachment] = createAttachment(binding, type, colorbuffer, level, layer);
180 }
181 
setDepthbuffer(GLenum type,GLuint depthbuffer,GLint level,GLint layer)182 void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer, GLint level, GLint layer)
183 {
184     SafeDelete(mDepthbuffer);
185     mDepthbuffer = createAttachment(GL_DEPTH_ATTACHMENT, type, depthbuffer, level, layer);
186 }
187 
setStencilbuffer(GLenum type,GLuint stencilbuffer,GLint level,GLint layer)188 void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer, GLint level, GLint layer)
189 {
190     SafeDelete(mStencilbuffer);
191     mStencilbuffer = createAttachment(GL_STENCIL_ATTACHMENT, type, stencilbuffer, level, layer);
192 }
193 
setDepthStencilBuffer(GLenum type,GLuint depthStencilBuffer,GLint level,GLint layer)194 void Framebuffer::setDepthStencilBuffer(GLenum type, GLuint depthStencilBuffer, GLint level, GLint layer)
195 {
196     FramebufferAttachment *attachment = createAttachment(GL_DEPTH_STENCIL_ATTACHMENT, type, depthStencilBuffer, level, layer);
197 
198     SafeDelete(mDepthbuffer);
199     SafeDelete(mStencilbuffer);
200 
201     // ensure this is a legitimate depth+stencil format
202     if (attachment && attachment->getDepthSize() > 0 && attachment->getStencilSize() > 0)
203     {
204         mDepthbuffer = attachment;
205 
206         // Make a new attachment object to ensure we do not double-delete
207         // See angle issue 686
208         mStencilbuffer = createAttachment(GL_DEPTH_STENCIL_ATTACHMENT, type, depthStencilBuffer, level, layer);
209     }
210 }
211 
detachTexture(GLuint textureId)212 void Framebuffer::detachTexture(GLuint textureId)
213 {
214     for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
215     {
216         FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
217 
218         if (attachment && attachment->isTextureWithId(textureId))
219         {
220             SafeDelete(mColorbuffers[colorAttachment]);
221         }
222     }
223 
224     if (mDepthbuffer && mDepthbuffer->isTextureWithId(textureId))
225     {
226         SafeDelete(mDepthbuffer);
227     }
228 
229     if (mStencilbuffer && mStencilbuffer->isTextureWithId(textureId))
230     {
231         SafeDelete(mStencilbuffer);
232     }
233 }
234 
detachRenderbuffer(GLuint renderbufferId)235 void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
236 {
237     for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
238     {
239         FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
240 
241         if (attachment && attachment->isRenderbufferWithId(renderbufferId))
242         {
243             SafeDelete(mColorbuffers[colorAttachment]);
244         }
245     }
246 
247     if (mDepthbuffer && mDepthbuffer->isRenderbufferWithId(renderbufferId))
248     {
249         SafeDelete(mDepthbuffer);
250     }
251 
252     if (mStencilbuffer && mStencilbuffer->isRenderbufferWithId(renderbufferId))
253     {
254         SafeDelete(mStencilbuffer);
255     }
256 }
257 
getColorbuffer(unsigned int colorAttachment) const258 FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
259 {
260     ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
261     return mColorbuffers[colorAttachment];
262 }
263 
getDepthbuffer() const264 FramebufferAttachment *Framebuffer::getDepthbuffer() const
265 {
266     return mDepthbuffer;
267 }
268 
getStencilbuffer() const269 FramebufferAttachment *Framebuffer::getStencilbuffer() const
270 {
271     return mStencilbuffer;
272 }
273 
getDepthStencilBuffer() const274 FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
275 {
276     return (hasValidDepthStencil() ? mDepthbuffer : NULL);
277 }
278 
getDepthOrStencilbuffer() const279 FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
280 {
281     FramebufferAttachment *depthstencilbuffer = mDepthbuffer;
282 
283     if (!depthstencilbuffer)
284     {
285         depthstencilbuffer = mStencilbuffer;
286     }
287 
288     return depthstencilbuffer;
289 }
290 
getReadColorbuffer() const291 FramebufferAttachment *Framebuffer::getReadColorbuffer() const
292 {
293     // Will require more logic if glReadBuffers is supported
294     return mColorbuffers[0];
295 }
296 
getReadColorbufferType() const297 GLenum Framebuffer::getReadColorbufferType() const
298 {
299     // Will require more logic if glReadBuffers is supported
300     return (mColorbuffers[0] ? mColorbuffers[0]->type() : GL_NONE);
301 }
302 
getFirstColorbuffer() const303 FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
304 {
305     for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
306     {
307         if (mColorbuffers[colorAttachment])
308         {
309             return mColorbuffers[colorAttachment];
310         }
311     }
312 
313     return NULL;
314 }
315 
getAttachment(GLenum attachment) const316 FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
317 {
318     if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
319     {
320         return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
321     }
322     else
323     {
324         switch (attachment)
325         {
326           case GL_DEPTH_ATTACHMENT:
327             return getDepthbuffer();
328           case GL_STENCIL_ATTACHMENT:
329             return getStencilbuffer();
330           case GL_DEPTH_STENCIL_ATTACHMENT:
331             return getDepthStencilBuffer();
332           default:
333             UNREACHABLE();
334             return NULL;
335         }
336     }
337 }
338 
getDrawBufferState(unsigned int colorAttachment) const339 GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
340 {
341     return mDrawBufferStates[colorAttachment];
342 }
343 
setDrawBufferState(unsigned int colorAttachment,GLenum drawBuffer)344 void Framebuffer::setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer)
345 {
346     mDrawBufferStates[colorAttachment] = drawBuffer;
347 }
348 
isEnabledColorAttachment(unsigned int colorAttachment) const349 bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
350 {
351     return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE);
352 }
353 
hasEnabledColorAttachment() const354 bool Framebuffer::hasEnabledColorAttachment() const
355 {
356     for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
357     {
358         if (isEnabledColorAttachment(colorAttachment))
359         {
360             return true;
361         }
362     }
363 
364     return false;
365 }
366 
hasStencil() const367 bool Framebuffer::hasStencil() const
368 {
369     return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0);
370 }
371 
usingExtendedDrawBuffers() const372 bool Framebuffer::usingExtendedDrawBuffers() const
373 {
374     for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
375     {
376         if (isEnabledColorAttachment(colorAttachment))
377         {
378             return true;
379         }
380     }
381 
382     return false;
383 }
384 
completeness() const385 GLenum Framebuffer::completeness() const
386 {
387     int width = 0;
388     int height = 0;
389     unsigned int colorbufferSize = 0;
390     int samples = -1;
391     bool missingAttachment = true;
392     GLuint clientVersion = mRenderer->getCurrentClientVersion();
393 
394     for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
395     {
396         const FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
397 
398         if (colorbuffer)
399         {
400             if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
401             {
402                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
403             }
404 
405             GLenum internalformat = colorbuffer->getInternalFormat();
406             // TODO(geofflang): use context's texture caps
407             const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
408             const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
409             if (colorbuffer->isTexture())
410             {
411                 if (!formatCaps.renderable)
412                 {
413                     return GL_FRAMEBUFFER_UNSUPPORTED;
414                 }
415 
416                 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
417                 {
418                     return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
419                 }
420             }
421             else
422             {
423                 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
424                 {
425                     return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
426                 }
427             }
428 
429             if (!missingAttachment)
430             {
431                 // all color attachments must have the same width and height
432                 if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height)
433                 {
434                     return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
435                 }
436 
437                 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
438                 // all color attachments have the same number of samples for the FBO to be complete.
439                 if (colorbuffer->getSamples() != samples)
440                 {
441                     return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
442                 }
443 
444                 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
445                 // in GLES 3.0, there is no such restriction
446                 if (clientVersion < 3)
447                 {
448                     if (formatInfo.pixelBytes != colorbufferSize)
449                     {
450                         return GL_FRAMEBUFFER_UNSUPPORTED;
451                     }
452                 }
453 
454                 // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness
455                 for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++)
456                 {
457                     const FramebufferAttachment *previousAttachment = mColorbuffers[previousColorAttachment];
458 
459                     if (previousAttachment &&
460                         (colorbuffer->id() == previousAttachment->id() &&
461                          colorbuffer->type() == previousAttachment->type()))
462                     {
463                         return GL_FRAMEBUFFER_UNSUPPORTED;
464                     }
465                 }
466             }
467             else
468             {
469                 width = colorbuffer->getWidth();
470                 height = colorbuffer->getHeight();
471                 samples = colorbuffer->getSamples();
472                 colorbufferSize = formatInfo.pixelBytes;
473                 missingAttachment = false;
474             }
475         }
476     }
477 
478     if (mDepthbuffer)
479     {
480         if (mDepthbuffer->getWidth() == 0 || mDepthbuffer->getHeight() == 0)
481         {
482             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
483         }
484 
485         GLenum internalformat = mDepthbuffer->getInternalFormat();
486         // TODO(geofflang): use context's texture caps
487         const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
488         const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
489         if (mDepthbuffer->isTexture())
490         {
491             // depth texture attachments require OES/ANGLE_depth_texture
492             // TODO(geofflang): use context's extensions
493             if (!mRenderer->getRendererExtensions().depthTextures)
494             {
495                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
496             }
497 
498             if (!formatCaps.renderable)
499             {
500                 return GL_FRAMEBUFFER_UNSUPPORTED;
501             }
502 
503             if (formatInfo.depthBits == 0)
504             {
505                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
506             }
507         }
508         else
509         {
510             if (!formatCaps.renderable || formatInfo.depthBits == 0)
511             {
512                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
513             }
514         }
515 
516         if (missingAttachment)
517         {
518             width = mDepthbuffer->getWidth();
519             height = mDepthbuffer->getHeight();
520             samples = mDepthbuffer->getSamples();
521             missingAttachment = false;
522         }
523         else if (width != mDepthbuffer->getWidth() || height != mDepthbuffer->getHeight())
524         {
525             return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
526         }
527         else if (samples != mDepthbuffer->getSamples())
528         {
529             return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
530         }
531     }
532 
533     if (mStencilbuffer)
534     {
535         if (mStencilbuffer->getWidth() == 0 || mStencilbuffer->getHeight() == 0)
536         {
537             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
538         }
539 
540         GLenum internalformat = mStencilbuffer->getInternalFormat();
541         // TODO(geofflang): use context's texture caps
542         const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
543         const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
544         if (mStencilbuffer->isTexture())
545         {
546             // texture stencil attachments come along as part
547             // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
548             // TODO(geofflang): use context's extensions
549             if (!mRenderer->getRendererExtensions().depthTextures)
550             {
551                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
552             }
553 
554             if (!formatCaps.renderable)
555             {
556                 return GL_FRAMEBUFFER_UNSUPPORTED;
557             }
558 
559             if (formatInfo.stencilBits == 0)
560             {
561                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
562             }
563         }
564         else
565         {
566             if (!formatCaps.renderable || formatInfo.stencilBits == 0)
567             {
568                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
569             }
570         }
571 
572         if (missingAttachment)
573         {
574             width = mStencilbuffer->getWidth();
575             height = mStencilbuffer->getHeight();
576             samples = mStencilbuffer->getSamples();
577             missingAttachment = false;
578         }
579         else if (width != mStencilbuffer->getWidth() || height != mStencilbuffer->getHeight())
580         {
581             return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
582         }
583         else if (samples != mStencilbuffer->getSamples())
584         {
585             return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
586         }
587     }
588 
589     // if we have both a depth and stencil buffer, they must refer to the same object
590     // since we only support packed_depth_stencil and not separate depth and stencil
591     if (mDepthbuffer && mStencilbuffer && !hasValidDepthStencil())
592     {
593         return GL_FRAMEBUFFER_UNSUPPORTED;
594     }
595 
596     // we need to have at least one attachment to be complete
597     if (missingAttachment)
598     {
599         return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
600     }
601 
602     return GL_FRAMEBUFFER_COMPLETE;
603 }
604 
invalidate(const Caps & caps,GLsizei numAttachments,const GLenum * attachments)605 void Framebuffer::invalidate(const Caps &caps, GLsizei numAttachments, const GLenum *attachments)
606 {
607     GLuint maxDimension = caps.maxRenderbufferSize;
608     invalidateSub(caps, numAttachments, attachments, 0, 0, maxDimension, maxDimension);
609 }
610 
invalidateSub(const Caps & caps,GLsizei numAttachments,const GLenum * attachments,GLint x,GLint y,GLsizei width,GLsizei height)611 void Framebuffer::invalidateSub(const Caps &caps, GLsizei numAttachments, const GLenum *attachments,
612                                 GLint x, GLint y, GLsizei width, GLsizei height)
613 {
614     ASSERT(completeness() == GL_FRAMEBUFFER_COMPLETE);
615     for (GLsizei attachIndex = 0; attachIndex < numAttachments; ++attachIndex)
616     {
617         GLenum attachmentTarget = attachments[attachIndex];
618 
619         gl::FramebufferAttachment *attachment =
620             (attachmentTarget == GL_DEPTH_STENCIL_ATTACHMENT) ? getDepthOrStencilbuffer() :
621                                                                 getAttachment(attachmentTarget);
622 
623         if (attachment)
624         {
625             rx::RenderTarget *renderTarget = rx::GetAttachmentRenderTarget(attachment);
626             if (renderTarget)
627             {
628                 renderTarget->invalidate(x, y, width, height);
629             }
630         }
631     }
632 }
633 
DefaultFramebuffer(rx::Renderer * renderer,Colorbuffer * colorbuffer,DepthStencilbuffer * depthStencil)634 DefaultFramebuffer::DefaultFramebuffer(rx::Renderer *renderer, Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil)
635     : Framebuffer(renderer, 0)
636 {
637     Renderbuffer *colorRenderbuffer = new Renderbuffer(0, colorbuffer);
638     mColorbuffers[0] = new RenderbufferAttachment(GL_BACK, colorRenderbuffer);
639 
640     GLenum depthStencilActualFormat = depthStencil->getActualFormat();
641     const gl::InternalFormat &depthStencilFormatInfo = GetInternalFormatInfo(depthStencilActualFormat);
642 
643     if (depthStencilFormatInfo.depthBits != 0 || depthStencilFormatInfo.stencilBits != 0)
644     {
645         Renderbuffer *depthStencilBuffer = new Renderbuffer(0, depthStencil);
646 
647         // Make a new attachment objects to ensure we do not double-delete
648         // See angle issue 686
649         mDepthbuffer = (depthStencilFormatInfo.depthBits != 0 ? new RenderbufferAttachment(GL_DEPTH_ATTACHMENT, depthStencilBuffer) : NULL);
650         mStencilbuffer = (depthStencilFormatInfo.stencilBits != 0 ? new RenderbufferAttachment(GL_STENCIL_ATTACHMENT, depthStencilBuffer) : NULL);
651     }
652     else
653     {
654         // This method transfers ownership, so delete the unused storage if we don't keep it.
655         SafeDelete(depthStencil);
656     }
657 
658     mDrawBufferStates[0] = GL_BACK;
659     mReadBufferState = GL_BACK;
660 }
661 
getSamples() const662 int Framebuffer::getSamples() const
663 {
664     if (completeness() == GL_FRAMEBUFFER_COMPLETE)
665     {
666         // for a complete framebuffer, all attachments must have the same sample count
667         // in this case return the first nonzero sample size
668         for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
669         {
670             if (mColorbuffers[colorAttachment])
671             {
672                 return mColorbuffers[colorAttachment]->getSamples();
673             }
674         }
675     }
676 
677     return 0;
678 }
679 
hasValidDepthStencil() const680 bool Framebuffer::hasValidDepthStencil() const
681 {
682     // A valid depth-stencil attachment has the same resource bound to both the
683     // depth and stencil attachment points.
684     return (mDepthbuffer && mStencilbuffer &&
685             mDepthbuffer->type() == mStencilbuffer->type() &&
686             mDepthbuffer->id() == mStencilbuffer->id());
687 }
688 
getColorbuffersForRender() const689 ColorbufferInfo Framebuffer::getColorbuffersForRender() const
690 {
691     ColorbufferInfo colorbuffersForRender;
692 
693     for (size_t colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; ++colorAttachment)
694     {
695         GLenum drawBufferState = mDrawBufferStates[colorAttachment];
696         FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
697 
698         if (colorbuffer != NULL && drawBufferState != GL_NONE)
699         {
700             ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment));
701             colorbuffersForRender.push_back(colorbuffer);
702         }
703 #if (ANGLE_MRT_PERF_WORKAROUND == ANGLE_WORKAROUND_DISABLED)
704         else
705         {
706             colorbuffersForRender.push_back(NULL);
707         }
708 #endif
709     }
710 
711     return colorbuffersForRender;
712 }
713 
completeness() const714 GLenum DefaultFramebuffer::completeness() const
715 {
716     // The default framebuffer *must* always be complete, though it may not be
717     // subject to the same rules as application FBOs. ie, it could have 0x0 size.
718     return GL_FRAMEBUFFER_COMPLETE;
719 }
720 
getAttachment(GLenum attachment) const721 FramebufferAttachment *DefaultFramebuffer::getAttachment(GLenum attachment) const
722 {
723     switch (attachment)
724     {
725       case GL_COLOR:
726       case GL_BACK:
727         return getColorbuffer(0);
728       case GL_DEPTH:
729         return getDepthbuffer();
730       case GL_STENCIL:
731         return getStencilbuffer();
732       case GL_DEPTH_STENCIL:
733         return getDepthStencilBuffer();
734       default:
735         UNREACHABLE();
736         return NULL;
737     }
738 }
739 
740 }
741