Home | History | Annotate | Download | only in canvas
      1 /*
      2  * Copyright (C) 2009 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 
     28 #include "core/html/canvas/WebGLFramebuffer.h"
     29 
     30 #include "core/html/canvas/WebGLRenderingContextBase.h"
     31 #include "platform/NotImplemented.h"
     32 
     33 namespace blink {
     34 
     35 namespace {
     36 
     37     Platform3DObject objectOrZero(WebGLObject* object)
     38     {
     39         return object ? object->object() : 0;
     40     }
     41 
     42     class WebGLRenderbufferAttachment FINAL : public WebGLFramebuffer::WebGLAttachment {
     43     public:
     44         static PassRefPtrWillBeRawPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLRenderbuffer*);
     45 
     46         virtual void trace(Visitor*) OVERRIDE;
     47 
     48     private:
     49         explicit WebGLRenderbufferAttachment(WebGLRenderbuffer*);
     50         WebGLRenderbufferAttachment() { }
     51 
     52         virtual GLsizei width() const OVERRIDE;
     53         virtual GLsizei height() const OVERRIDE;
     54         virtual GLenum format() const OVERRIDE;
     55         virtual GLenum type() const OVERRIDE;
     56         virtual WebGLSharedObject* object() const OVERRIDE;
     57         virtual bool isSharedObject(WebGLSharedObject*) const OVERRIDE;
     58         virtual bool valid() const OVERRIDE;
     59         virtual void onDetached(blink::WebGraphicsContext3D*) OVERRIDE;
     60         virtual void attach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE;
     61         virtual void unattach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE;
     62 
     63         RefPtrWillBeMember<WebGLRenderbuffer> m_renderbuffer;
     64     };
     65 
     66     PassRefPtrWillBeRawPtr<WebGLFramebuffer::WebGLAttachment> WebGLRenderbufferAttachment::create(WebGLRenderbuffer* renderbuffer)
     67     {
     68         return adoptRefWillBeNoop(new WebGLRenderbufferAttachment(renderbuffer));
     69     }
     70 
     71     void WebGLRenderbufferAttachment::trace(Visitor* visitor)
     72     {
     73         visitor->trace(m_renderbuffer);
     74         WebGLFramebuffer::WebGLAttachment::trace(visitor);
     75     }
     76 
     77     WebGLRenderbufferAttachment::WebGLRenderbufferAttachment(WebGLRenderbuffer* renderbuffer)
     78         : m_renderbuffer(renderbuffer)
     79     {
     80     }
     81 
     82     GLsizei WebGLRenderbufferAttachment::width() const
     83     {
     84         return m_renderbuffer->width();
     85     }
     86 
     87     GLsizei WebGLRenderbufferAttachment::height() const
     88     {
     89         return m_renderbuffer->height();
     90     }
     91 
     92     GLenum WebGLRenderbufferAttachment::format() const
     93     {
     94         GLenum format = m_renderbuffer->internalFormat();
     95         if (format == GL_DEPTH_STENCIL_OES
     96             && m_renderbuffer->emulatedStencilBuffer()
     97             && m_renderbuffer->emulatedStencilBuffer()->internalFormat() != GL_STENCIL_INDEX8) {
     98             return 0;
     99         }
    100         return format;
    101     }
    102 
    103     WebGLSharedObject* WebGLRenderbufferAttachment::object() const
    104     {
    105         return m_renderbuffer->object() ? m_renderbuffer.get() : 0;
    106     }
    107 
    108     bool WebGLRenderbufferAttachment::isSharedObject(WebGLSharedObject* object) const
    109     {
    110         return object == m_renderbuffer;
    111     }
    112 
    113     bool WebGLRenderbufferAttachment::valid() const
    114     {
    115         return m_renderbuffer->object();
    116     }
    117 
    118     void WebGLRenderbufferAttachment::onDetached(blink::WebGraphicsContext3D* context)
    119     {
    120         m_renderbuffer->onDetached(context);
    121     }
    122 
    123     void WebGLRenderbufferAttachment::attach(blink::WebGraphicsContext3D* context, GLenum attachment)
    124     {
    125         Platform3DObject object = objectOrZero(m_renderbuffer.get());
    126         if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL && m_renderbuffer->emulatedStencilBuffer()) {
    127             context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, object);
    128             context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, objectOrZero(m_renderbuffer->emulatedStencilBuffer()));
    129         } else {
    130             context->framebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, object);
    131         }
    132     }
    133 
    134     void WebGLRenderbufferAttachment::unattach(blink::WebGraphicsContext3D* context, GLenum attachment)
    135     {
    136         if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) {
    137             context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
    138             context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
    139         } else {
    140             context->framebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, 0);
    141         }
    142     }
    143 
    144     GLenum WebGLRenderbufferAttachment::type() const
    145     {
    146         notImplemented();
    147         return 0;
    148     }
    149 
    150     class WebGLTextureAttachment FINAL : public WebGLFramebuffer::WebGLAttachment {
    151     public:
    152         static PassRefPtrWillBeRawPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLTexture*, GLenum target, GLint level);
    153 
    154         virtual void trace(Visitor*) OVERRIDE;
    155 
    156     private:
    157         WebGLTextureAttachment(WebGLTexture*, GLenum target, GLint level);
    158         WebGLTextureAttachment() { }
    159 
    160         virtual GLsizei width() const OVERRIDE;
    161         virtual GLsizei height() const OVERRIDE;
    162         virtual GLenum format() const OVERRIDE;
    163         virtual GLenum type() const OVERRIDE;
    164         virtual WebGLSharedObject* object() const OVERRIDE;
    165         virtual bool isSharedObject(WebGLSharedObject*) const OVERRIDE;
    166         virtual bool valid() const OVERRIDE;
    167         virtual void onDetached(blink::WebGraphicsContext3D*) OVERRIDE;
    168         virtual void attach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE;
    169         virtual void unattach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE;
    170 
    171         RefPtrWillBeMember<WebGLTexture> m_texture;
    172         GLenum m_target;
    173         GLint m_level;
    174     };
    175 
    176     PassRefPtrWillBeRawPtr<WebGLFramebuffer::WebGLAttachment> WebGLTextureAttachment::create(WebGLTexture* texture, GLenum target, GLint level)
    177     {
    178         return adoptRefWillBeNoop(new WebGLTextureAttachment(texture, target, level));
    179     }
    180 
    181     void WebGLTextureAttachment::trace(Visitor* visitor)
    182     {
    183         visitor->trace(m_texture);
    184         WebGLFramebuffer::WebGLAttachment::trace(visitor);
    185     }
    186 
    187     WebGLTextureAttachment::WebGLTextureAttachment(WebGLTexture* texture, GLenum target, GLint level)
    188         : m_texture(texture)
    189         , m_target(target)
    190         , m_level(level)
    191     {
    192     }
    193 
    194     GLsizei WebGLTextureAttachment::width() const
    195     {
    196         return m_texture->getWidth(m_target, m_level);
    197     }
    198 
    199     GLsizei WebGLTextureAttachment::height() const
    200     {
    201         return m_texture->getHeight(m_target, m_level);
    202     }
    203 
    204     GLenum WebGLTextureAttachment::format() const
    205     {
    206         return m_texture->getInternalFormat(m_target, m_level);
    207     }
    208 
    209     WebGLSharedObject* WebGLTextureAttachment::object() const
    210     {
    211         return m_texture->object() ? m_texture.get() : 0;
    212     }
    213 
    214     bool WebGLTextureAttachment::isSharedObject(WebGLSharedObject* object) const
    215     {
    216         return object == m_texture;
    217     }
    218 
    219     bool WebGLTextureAttachment::valid() const
    220     {
    221         return m_texture->object();
    222     }
    223 
    224     void WebGLTextureAttachment::onDetached(blink::WebGraphicsContext3D* context)
    225     {
    226         m_texture->onDetached(context);
    227     }
    228 
    229     void WebGLTextureAttachment::attach(blink::WebGraphicsContext3D* context, GLenum attachment)
    230     {
    231         Platform3DObject object = objectOrZero(m_texture.get());
    232         context->framebufferTexture2D(GL_FRAMEBUFFER, attachment, m_target, object, m_level);
    233     }
    234 
    235     void WebGLTextureAttachment::unattach(blink::WebGraphicsContext3D* context, GLenum attachment)
    236     {
    237         if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) {
    238             context->framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_target, 0, m_level);
    239             context->framebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, m_target, 0, m_level);
    240         } else {
    241             context->framebufferTexture2D(GL_FRAMEBUFFER, attachment, m_target, 0, m_level);
    242         }
    243     }
    244 
    245     GLenum WebGLTextureAttachment::type() const
    246     {
    247         return m_texture->getType(m_target, m_level);
    248     }
    249 
    250     bool isColorRenderable(GLenum internalformat)
    251     {
    252         switch (internalformat) {
    253         case GL_RGBA4:
    254         case GL_RGB5_A1:
    255         case GL_RGB565:
    256             return true;
    257         default:
    258             return false;
    259         }
    260     }
    261 
    262 } // anonymous namespace
    263 
    264 WebGLFramebuffer::WebGLAttachment::WebGLAttachment()
    265 {
    266 }
    267 
    268 WebGLFramebuffer::WebGLAttachment::~WebGLAttachment()
    269 {
    270 }
    271 
    272 PassRefPtrWillBeRawPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContextBase* ctx)
    273 {
    274     return adoptRefWillBeNoop(new WebGLFramebuffer(ctx));
    275 }
    276 
    277 WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContextBase* ctx)
    278     : WebGLContextObject(ctx)
    279     , m_hasEverBeenBound(false)
    280 {
    281     setObject(ctx->webContext()->createFramebuffer());
    282 }
    283 
    284 WebGLFramebuffer::~WebGLFramebuffer()
    285 {
    286     // Delete the platform framebuffer resource. Explicit detachment
    287     // is for the benefit of Oilpan, where the framebuffer object
    288     // isn't detached when it and the WebGLRenderingContextBase object
    289     // it is registered with are both finalized. Without Oilpan, the
    290     // object will have been detached.
    291     //
    292     // To keep the code regular, the trivial detach()ment is always
    293     // performed.
    294     detachAndDeleteObject();
    295 }
    296 
    297 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum attachment, GLenum texTarget, WebGLTexture* texture, GLint level)
    298 {
    299     ASSERT(isBound());
    300     removeAttachmentFromBoundFramebuffer(attachment);
    301     if (!object())
    302         return;
    303     if (texture && texture->object()) {
    304         m_attachments.add(attachment, WebGLTextureAttachment::create(texture, texTarget, level));
    305         drawBuffersIfNecessary(false);
    306         texture->onAttached();
    307     }
    308 }
    309 
    310 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum attachment, WebGLRenderbuffer* renderbuffer)
    311 {
    312     ASSERT(isBound());
    313     removeAttachmentFromBoundFramebuffer(attachment);
    314     if (!object())
    315         return;
    316     if (renderbuffer && renderbuffer->object()) {
    317         m_attachments.add(attachment, WebGLRenderbufferAttachment::create(renderbuffer));
    318         drawBuffersIfNecessary(false);
    319         renderbuffer->onAttached();
    320     }
    321 }
    322 
    323 void WebGLFramebuffer::attach(GLenum attachment, GLenum attachmentPoint)
    324 {
    325     ASSERT(isBound());
    326     WebGLAttachment* attachmentObject = getAttachment(attachment);
    327     if (attachmentObject)
    328         attachmentObject->attach(context()->webContext(), attachmentPoint);
    329 }
    330 
    331 WebGLSharedObject* WebGLFramebuffer::getAttachmentObject(GLenum attachment) const
    332 {
    333     if (!object())
    334         return 0;
    335     WebGLAttachment* attachmentObject = getAttachment(attachment);
    336     return attachmentObject ? attachmentObject->object() : 0;
    337 }
    338 
    339 bool WebGLFramebuffer::isAttachmentComplete(WebGLAttachment* attachedObject, GLenum attachment, const char** reason) const
    340 {
    341     ASSERT(attachedObject && attachedObject->valid());
    342     ASSERT(reason);
    343 
    344     GLenum internalformat = attachedObject->format();
    345     WebGLSharedObject* object = attachedObject->object();
    346     ASSERT(object && (object->isTexture() || object->isRenderbuffer()));
    347 
    348     if (attachment == GL_DEPTH_ATTACHMENT) {
    349         if (object->isRenderbuffer()) {
    350             if (internalformat != GL_DEPTH_COMPONENT16) {
    351                 *reason = "the internalformat of the attached renderbuffer is not DEPTH_COMPONENT16";
    352                 return false;
    353             }
    354         } else if (object->isTexture()) {
    355             GLenum type = attachedObject->type();
    356             if (!(context()->extensionEnabled(WebGLDepthTextureName) && internalformat == GL_DEPTH_COMPONENT
    357                 && (type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT))) {
    358                 *reason = "the attached texture is not a depth texture";
    359                 return false;
    360             }
    361         }
    362     } else if (attachment == GL_STENCIL_ATTACHMENT) {
    363         // Depend on the underlying GL drivers to check stencil textures
    364         // and check renderbuffer type here only.
    365         if (object->isRenderbuffer()) {
    366             if (internalformat != GL_STENCIL_INDEX8) {
    367                 *reason = "the internalformat of the attached renderbuffer is not STENCIL_INDEX8";
    368                 return false;
    369             }
    370         }
    371     } else if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) {
    372         if (object->isRenderbuffer()) {
    373             if (internalformat != GL_DEPTH_STENCIL_OES) {
    374                 *reason = "the internalformat of the attached renderbuffer is not DEPTH_STENCIL";
    375                 return false;
    376             }
    377         } else if (object->isTexture()) {
    378             GLenum type = attachedObject->type();
    379             if (!(context()->extensionEnabled(WebGLDepthTextureName) && internalformat == GL_DEPTH_STENCIL_OES
    380                 && type == GL_UNSIGNED_INT_24_8_OES)) {
    381                 *reason = "the attached texture is not a DEPTH_STENCIL texture";
    382                 return false;
    383             }
    384         }
    385     } else if (attachment == GL_COLOR_ATTACHMENT0
    386         || (context()->extensionEnabled(WebGLDrawBuffersName) && attachment > GL_COLOR_ATTACHMENT0
    387             && attachment < static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + context()->maxColorAttachments()))) {
    388         if (object->isRenderbuffer()) {
    389             if (!isColorRenderable(internalformat)) {
    390                 *reason = "the internalformat of the attached renderbuffer is not color-renderable";
    391                 return false;
    392             }
    393         } else if (object->isTexture()) {
    394             GLenum type = attachedObject->type();
    395             if (internalformat != GL_RGBA && internalformat != GL_RGB) {
    396                 *reason = "the internalformat of the attached texture is not color-renderable";
    397                 return false;
    398             }
    399             // TODO: WEBGL_color_buffer_float and EXT_color_buffer_half_float extensions have not been implemented in
    400             // WebGL yet. It would be better to depend on the underlying GL drivers to check on rendering to floating point textures
    401             // and add the check back to WebGL when above two extensions are implemented.
    402             // Assume UNSIGNED_BYTE is renderable here without the need to explicitly check if GL_OES_rgb8_rgba8 extension is supported.
    403             if (type != GL_UNSIGNED_BYTE
    404                 && type != GL_UNSIGNED_SHORT_5_6_5
    405                 && type != GL_UNSIGNED_SHORT_4_4_4_4
    406                 && type != GL_UNSIGNED_SHORT_5_5_5_1
    407                 && !(type == GL_FLOAT && context()->extensionEnabled(OESTextureFloatName))
    408                 && !(type == GL_HALF_FLOAT_OES && context()->extensionEnabled(OESTextureHalfFloatName))) {
    409                 *reason = "unsupported type: The attached texture is not supported to be rendered to";
    410                 return false;
    411             }
    412         }
    413     } else {
    414         *reason = "unknown framebuffer attachment point";
    415         return false;
    416     }
    417 
    418     if (!attachedObject->width() || !attachedObject->height()) {
    419         *reason = "attachment has a 0 dimension";
    420         return false;
    421     }
    422     return true;
    423 }
    424 
    425 WebGLFramebuffer::WebGLAttachment* WebGLFramebuffer::getAttachment(GLenum attachment) const
    426 {
    427     const AttachmentMap::const_iterator it = m_attachments.find(attachment);
    428     return (it != m_attachments.end()) ? it->value.get() : 0;
    429 }
    430 
    431 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GLenum attachment)
    432 {
    433     ASSERT(isBound());
    434     if (!object())
    435         return;
    436 
    437     WebGLAttachment* attachmentObject = getAttachment(attachment);
    438     if (attachmentObject) {
    439         attachmentObject->onDetached(context()->webContext());
    440         m_attachments.remove(attachment);
    441         drawBuffersIfNecessary(false);
    442         switch (attachment) {
    443         case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL:
    444             attach(GL_DEPTH_ATTACHMENT, GL_DEPTH_ATTACHMENT);
    445             attach(GL_STENCIL_ATTACHMENT, GL_STENCIL_ATTACHMENT);
    446             break;
    447         case GL_DEPTH_ATTACHMENT:
    448             attach(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL, GL_DEPTH_ATTACHMENT);
    449             break;
    450         case GL_STENCIL_ATTACHMENT:
    451             attach(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL, GL_STENCIL_ATTACHMENT);
    452             break;
    453         }
    454     }
    455 }
    456 
    457 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(WebGLSharedObject* attachment)
    458 {
    459     ASSERT(isBound());
    460     if (!object())
    461         return;
    462     if (!attachment)
    463         return;
    464 
    465     bool checkMore = true;
    466     while (checkMore) {
    467         checkMore = false;
    468         for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
    469             WebGLAttachment* attachmentObject = it->value.get();
    470             if (attachmentObject->isSharedObject(attachment)) {
    471                 GLenum attachmentType = it->key;
    472                 attachmentObject->unattach(context()->webContext(), attachmentType);
    473                 removeAttachmentFromBoundFramebuffer(attachmentType);
    474                 checkMore = true;
    475                 break;
    476             }
    477         }
    478     }
    479 }
    480 
    481 GLenum WebGLFramebuffer::colorBufferFormat() const
    482 {
    483     if (!object())
    484         return 0;
    485     WebGLAttachment* attachment = getAttachment(GL_COLOR_ATTACHMENT0);
    486     if (!attachment)
    487         return 0;
    488     return attachment->format();
    489 }
    490 
    491 GLenum WebGLFramebuffer::checkStatus(const char** reason) const
    492 {
    493     unsigned count = 0;
    494     GLsizei width = 0, height = 0;
    495     bool haveDepth = false;
    496     bool haveStencil = false;
    497     bool haveDepthStencil = false;
    498     for (AttachmentMap::const_iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
    499         WebGLAttachment* attachment = it->value.get();
    500         if (!isAttachmentComplete(attachment, it->key, reason))
    501             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    502         if (!attachment->valid()) {
    503             *reason = "attachment is not valid";
    504             return GL_FRAMEBUFFER_UNSUPPORTED;
    505         }
    506         if (!attachment->format()) {
    507             *reason = "attachment is an unsupported format";
    508             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    509         }
    510         switch (it->key) {
    511         case GL_DEPTH_ATTACHMENT:
    512             haveDepth = true;
    513             break;
    514         case GL_STENCIL_ATTACHMENT:
    515             haveStencil = true;
    516             break;
    517         case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL:
    518             haveDepthStencil = true;
    519             break;
    520         }
    521         if (!count) {
    522             width = attachment->width();
    523             height = attachment->height();
    524         } else {
    525             if (width != attachment->width() || height != attachment->height()) {
    526                 *reason = "attachments do not have the same dimensions";
    527                 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
    528             }
    529         }
    530         ++count;
    531     }
    532     if (!count) {
    533         *reason = "no attachments";
    534         return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
    535     }
    536     if (!width || !height) {
    537         *reason = "framebuffer has a 0 dimension";
    538         return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    539     }
    540     // WebGL specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments.
    541     if ((haveDepthStencil && (haveDepth || haveStencil)) || (haveDepth && haveStencil)) {
    542         *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments";
    543         return GL_FRAMEBUFFER_UNSUPPORTED;
    544     }
    545     return GL_FRAMEBUFFER_COMPLETE;
    546 }
    547 
    548 bool WebGLFramebuffer::onAccess(blink::WebGraphicsContext3D* context3d, const char** reason)
    549 {
    550     if (checkStatus(reason) != GL_FRAMEBUFFER_COMPLETE)
    551         return false;
    552     return true;
    553 }
    554 
    555 bool WebGLFramebuffer::hasStencilBuffer() const
    556 {
    557     WebGLAttachment* attachment = getAttachment(GL_STENCIL_ATTACHMENT);
    558     if (!attachment)
    559         attachment = getAttachment(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL);
    560     return attachment && attachment->valid();
    561 }
    562 
    563 void WebGLFramebuffer::deleteObjectImpl(blink::WebGraphicsContext3D* context3d, Platform3DObject object)
    564 {
    565 #if !ENABLE(OILPAN)
    566     // With Oilpan, both the AttachmentMap and its WebGLAttachment objects are
    567     // GCed objects and cannot be accessed, as they may have been finalized
    568     // already during the same GC sweep.
    569     //
    570     // The WebGLAttachment-derived classes instead handle detachment
    571     // on their own when finalizing, so the explicit notification is
    572     // not needed.
    573     for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it)
    574         it->value->onDetached(context3d);
    575 #endif
    576 
    577     context3d->deleteFramebuffer(object);
    578 }
    579 
    580 bool WebGLFramebuffer::isBound() const
    581 {
    582     return (context()->m_framebufferBinding.get() == this);
    583 }
    584 
    585 void WebGLFramebuffer::drawBuffers(const Vector<GLenum>& bufs)
    586 {
    587     m_drawBuffers = bufs;
    588     m_filteredDrawBuffers.resize(m_drawBuffers.size());
    589     for (size_t i = 0; i < m_filteredDrawBuffers.size(); ++i)
    590         m_filteredDrawBuffers[i] = GL_NONE;
    591     drawBuffersIfNecessary(true);
    592 }
    593 
    594 void WebGLFramebuffer::drawBuffersIfNecessary(bool force)
    595 {
    596     if (!context()->extensionEnabled(WebGLDrawBuffersName))
    597         return;
    598     bool reset = force;
    599     // This filtering works around graphics driver bugs on Mac OS X.
    600     for (size_t i = 0; i < m_drawBuffers.size(); ++i) {
    601         if (m_drawBuffers[i] != GL_NONE && getAttachment(m_drawBuffers[i])) {
    602             if (m_filteredDrawBuffers[i] != m_drawBuffers[i]) {
    603                 m_filteredDrawBuffers[i] = m_drawBuffers[i];
    604                 reset = true;
    605             }
    606         } else {
    607             if (m_filteredDrawBuffers[i] != GL_NONE) {
    608                 m_filteredDrawBuffers[i] = GL_NONE;
    609                 reset = true;
    610             }
    611         }
    612     }
    613     if (reset) {
    614         context()->webContext()->drawBuffersEXT(
    615             m_filteredDrawBuffers.size(), m_filteredDrawBuffers.data());
    616     }
    617 }
    618 
    619 GLenum WebGLFramebuffer::getDrawBuffer(GLenum drawBuffer)
    620 {
    621     int index = static_cast<int>(drawBuffer - GL_DRAW_BUFFER0_EXT);
    622     ASSERT(index >= 0);
    623     if (index < static_cast<int>(m_drawBuffers.size()))
    624         return m_drawBuffers[index];
    625     if (drawBuffer == GL_DRAW_BUFFER0_EXT)
    626         return GL_COLOR_ATTACHMENT0;
    627     return GL_NONE;
    628 }
    629 
    630 void WebGLFramebuffer::trace(Visitor* visitor)
    631 {
    632 #if ENABLE(OILPAN)
    633     visitor->trace(m_attachments);
    634 #endif
    635     WebGLContextObject::trace(visitor);
    636 }
    637 
    638 }
    639