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
23namespace rx
24{
25RenderTarget *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.
45unsigned 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
66namespace gl
67{
68
69Framebuffer::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
84Framebuffer::~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
94FramebufferAttachment *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
174void 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
182void 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
188void 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
194void 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
212void 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
235void 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
258FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
259{
260    ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
261    return mColorbuffers[colorAttachment];
262}
263
264FramebufferAttachment *Framebuffer::getDepthbuffer() const
265{
266    return mDepthbuffer;
267}
268
269FramebufferAttachment *Framebuffer::getStencilbuffer() const
270{
271    return mStencilbuffer;
272}
273
274FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
275{
276    return (hasValidDepthStencil() ? mDepthbuffer : NULL);
277}
278
279FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
280{
281    FramebufferAttachment *depthstencilbuffer = mDepthbuffer;
282
283    if (!depthstencilbuffer)
284    {
285        depthstencilbuffer = mStencilbuffer;
286    }
287
288    return depthstencilbuffer;
289}
290
291FramebufferAttachment *Framebuffer::getReadColorbuffer() const
292{
293    // Will require more logic if glReadBuffers is supported
294    return mColorbuffers[0];
295}
296
297GLenum Framebuffer::getReadColorbufferType() const
298{
299    // Will require more logic if glReadBuffers is supported
300    return (mColorbuffers[0] ? mColorbuffers[0]->type() : GL_NONE);
301}
302
303FramebufferAttachment *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
316FramebufferAttachment *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
339GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
340{
341    return mDrawBufferStates[colorAttachment];
342}
343
344void Framebuffer::setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer)
345{
346    mDrawBufferStates[colorAttachment] = drawBuffer;
347}
348
349bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
350{
351    return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE);
352}
353
354bool 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
367bool Framebuffer::hasStencil() const
368{
369    return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0);
370}
371
372bool 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
385GLenum 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
605void 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
611void 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
634DefaultFramebuffer::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
662int 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
680bool 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
689ColorbufferInfo 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
714GLenum 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
721FramebufferAttachment *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