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/WebGLRenderingContext.h"
     31 #include "platform/NotImplemented.h"
     32 #include "platform/graphics/Extensions3D.h"
     33 
     34 namespace WebCore {
     35 
     36 namespace {
     37 
     38     Platform3DObject objectOrZero(WebGLObject* object)
     39     {
     40         return object ? object->object() : 0;
     41     }
     42 
     43     class WebGLRenderbufferAttachment : public WebGLFramebuffer::WebGLAttachment {
     44     public:
     45         static PassRefPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLRenderbuffer*);
     46 
     47     private:
     48         WebGLRenderbufferAttachment(WebGLRenderbuffer*);
     49         virtual GC3Dsizei width() const;
     50         virtual GC3Dsizei height() const;
     51         virtual GC3Denum format() const;
     52         virtual GC3Denum type() const;
     53         virtual WebGLSharedObject* object() const;
     54         virtual bool isSharedObject(WebGLSharedObject*) const;
     55         virtual bool valid() const;
     56         virtual bool initialized() const;
     57         virtual void setInitialized();
     58         virtual void onDetached(GraphicsContext3D*);
     59         virtual void attach(GraphicsContext3D*, GC3Denum attachment);
     60         virtual void unattach(GraphicsContext3D*, GC3Denum attachment);
     61 
     62         WebGLRenderbufferAttachment() { };
     63 
     64         RefPtr<WebGLRenderbuffer> m_renderbuffer;
     65     };
     66 
     67     PassRefPtr<WebGLFramebuffer::WebGLAttachment> WebGLRenderbufferAttachment::create(WebGLRenderbuffer* renderbuffer)
     68     {
     69         return adoptRef(new WebGLRenderbufferAttachment(renderbuffer));
     70     }
     71 
     72     WebGLRenderbufferAttachment::WebGLRenderbufferAttachment(WebGLRenderbuffer* renderbuffer)
     73         : m_renderbuffer(renderbuffer)
     74     {
     75     }
     76 
     77     GC3Dsizei WebGLRenderbufferAttachment::width() const
     78     {
     79         return m_renderbuffer->width();
     80     }
     81 
     82     GC3Dsizei WebGLRenderbufferAttachment::height() const
     83     {
     84         return m_renderbuffer->height();
     85     }
     86 
     87     GC3Denum WebGLRenderbufferAttachment::format() const
     88     {
     89         GC3Denum format = m_renderbuffer->internalFormat();
     90         if (format == GL_DEPTH_STENCIL_OES
     91             && m_renderbuffer->emulatedStencilBuffer()
     92             && m_renderbuffer->emulatedStencilBuffer()->internalFormat() != GL_STENCIL_INDEX8) {
     93             return 0;
     94         }
     95         return format;
     96     }
     97 
     98     WebGLSharedObject* WebGLRenderbufferAttachment::object() const
     99     {
    100         return m_renderbuffer->object() ? m_renderbuffer.get() : 0;
    101     }
    102 
    103     bool WebGLRenderbufferAttachment::isSharedObject(WebGLSharedObject* object) const
    104     {
    105         return object == m_renderbuffer;
    106     }
    107 
    108     bool WebGLRenderbufferAttachment::valid() const
    109     {
    110         return m_renderbuffer->object();
    111     }
    112 
    113     bool WebGLRenderbufferAttachment::initialized() const
    114     {
    115         return m_renderbuffer->object() && m_renderbuffer->initialized();
    116     }
    117 
    118     void WebGLRenderbufferAttachment::setInitialized()
    119     {
    120         if (m_renderbuffer->object())
    121             m_renderbuffer->setInitialized();
    122     }
    123 
    124     void WebGLRenderbufferAttachment::onDetached(GraphicsContext3D* context)
    125     {
    126         m_renderbuffer->onDetached(context);
    127     }
    128 
    129     void WebGLRenderbufferAttachment::attach(GraphicsContext3D* context, GC3Denum attachment)
    130     {
    131         Platform3DObject object = objectOrZero(m_renderbuffer.get());
    132         if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL && m_renderbuffer->emulatedStencilBuffer()) {
    133             context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, object);
    134             context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, objectOrZero(m_renderbuffer->emulatedStencilBuffer()));
    135         } else {
    136             context->framebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, object);
    137         }
    138     }
    139 
    140     void WebGLRenderbufferAttachment::unattach(GraphicsContext3D* context, GC3Denum attachment)
    141     {
    142         if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) {
    143             context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
    144             context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
    145         } else {
    146             context->framebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, 0);
    147         }
    148     }
    149 
    150     GC3Denum WebGLRenderbufferAttachment::type() const
    151     {
    152         notImplemented();
    153         return 0;
    154     }
    155 
    156     class WebGLTextureAttachment : public WebGLFramebuffer::WebGLAttachment {
    157     public:
    158         static PassRefPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLTexture*, GC3Denum target, GC3Dint level);
    159 
    160     private:
    161         WebGLTextureAttachment(WebGLTexture*, GC3Denum target, GC3Dint level);
    162         virtual GC3Dsizei width() const;
    163         virtual GC3Dsizei height() const;
    164         virtual GC3Denum format() const;
    165         virtual GC3Denum type() const;
    166         virtual WebGLSharedObject* object() const;
    167         virtual bool isSharedObject(WebGLSharedObject*) const;
    168         virtual bool valid() const;
    169         virtual bool initialized() const;
    170         virtual void setInitialized();
    171         virtual void onDetached(GraphicsContext3D*);
    172         virtual void attach(GraphicsContext3D*, GC3Denum attachment);
    173         virtual void unattach(GraphicsContext3D*, GC3Denum attachment);
    174 
    175         WebGLTextureAttachment() { };
    176 
    177         RefPtr<WebGLTexture> m_texture;
    178         GC3Denum m_target;
    179         GC3Dint m_level;
    180     };
    181 
    182     PassRefPtr<WebGLFramebuffer::WebGLAttachment> WebGLTextureAttachment::create(WebGLTexture* texture, GC3Denum target, GC3Dint level)
    183     {
    184         return adoptRef(new WebGLTextureAttachment(texture, target, level));
    185     }
    186 
    187     WebGLTextureAttachment::WebGLTextureAttachment(WebGLTexture* texture, GC3Denum target, GC3Dint level)
    188         : m_texture(texture)
    189         , m_target(target)
    190         , m_level(level)
    191     {
    192     }
    193 
    194     GC3Dsizei WebGLTextureAttachment::width() const
    195     {
    196         return m_texture->getWidth(m_target, m_level);
    197     }
    198 
    199     GC3Dsizei WebGLTextureAttachment::height() const
    200     {
    201         return m_texture->getHeight(m_target, m_level);
    202     }
    203 
    204     GC3Denum 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     bool WebGLTextureAttachment::initialized() const
    225     {
    226         // Textures are assumed to be initialized.
    227         return true;
    228     }
    229 
    230     void WebGLTextureAttachment::setInitialized()
    231     {
    232         // Textures are assumed to be initialized.
    233     }
    234 
    235     void WebGLTextureAttachment::onDetached(GraphicsContext3D* context)
    236     {
    237         m_texture->onDetached(context);
    238     }
    239 
    240     void WebGLTextureAttachment::attach(GraphicsContext3D* context, GC3Denum attachment)
    241     {
    242         Platform3DObject object = objectOrZero(m_texture.get());
    243         context->framebufferTexture2D(GL_FRAMEBUFFER, attachment, m_target, object, m_level);
    244     }
    245 
    246     void WebGLTextureAttachment::unattach(GraphicsContext3D* context, GC3Denum attachment)
    247     {
    248         if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) {
    249             context->framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_target, 0, m_level);
    250             context->framebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, m_target, 0, m_level);
    251         } else {
    252             context->framebufferTexture2D(GL_FRAMEBUFFER, attachment, m_target, 0, m_level);
    253         }
    254     }
    255 
    256     GC3Denum WebGLTextureAttachment::type() const
    257     {
    258         return m_texture->getType(m_target, m_level);
    259     }
    260 
    261     bool isColorRenderable(GC3Denum internalformat)
    262     {
    263         switch (internalformat) {
    264         case GL_RGBA4:
    265         case GL_RGB5_A1:
    266         case GL_RGB565:
    267             return true;
    268         default:
    269             return false;
    270         }
    271     }
    272 
    273 } // anonymous namespace
    274 
    275 WebGLFramebuffer::WebGLAttachment::WebGLAttachment()
    276 {
    277 }
    278 
    279 WebGLFramebuffer::WebGLAttachment::~WebGLAttachment()
    280 {
    281 }
    282 
    283 PassRefPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContext* ctx)
    284 {
    285     return adoptRef(new WebGLFramebuffer(ctx));
    286 }
    287 
    288 WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContext* ctx)
    289     : WebGLContextObject(ctx)
    290     , m_hasEverBeenBound(false)
    291 {
    292     ScriptWrappable::init(this);
    293     setObject(ctx->graphicsContext3D()->createFramebuffer());
    294 }
    295 
    296 WebGLFramebuffer::~WebGLFramebuffer()
    297 {
    298     deleteObject(0);
    299 }
    300 
    301 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GC3Denum attachment, GC3Denum texTarget, WebGLTexture* texture, GC3Dint level)
    302 {
    303     ASSERT(isBound());
    304     removeAttachmentFromBoundFramebuffer(attachment);
    305     if (!object())
    306         return;
    307     if (texture && texture->object()) {
    308         m_attachments.add(attachment, WebGLTextureAttachment::create(texture, texTarget, level));
    309         drawBuffersIfNecessary(false);
    310         texture->onAttached();
    311     }
    312 }
    313 
    314 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GC3Denum attachment, WebGLRenderbuffer* renderbuffer)
    315 {
    316     ASSERT(isBound());
    317     removeAttachmentFromBoundFramebuffer(attachment);
    318     if (!object())
    319         return;
    320     if (renderbuffer && renderbuffer->object()) {
    321         m_attachments.add(attachment, WebGLRenderbufferAttachment::create(renderbuffer));
    322         drawBuffersIfNecessary(false);
    323         renderbuffer->onAttached();
    324     }
    325 }
    326 
    327 void WebGLFramebuffer::attach(GC3Denum attachment, GC3Denum attachmentPoint)
    328 {
    329     ASSERT(isBound());
    330     WebGLAttachment* attachmentObject = getAttachment(attachment);
    331     if (attachmentObject)
    332         attachmentObject->attach(context()->graphicsContext3D(), attachmentPoint);
    333 }
    334 
    335 WebGLSharedObject* WebGLFramebuffer::getAttachmentObject(GC3Denum attachment) const
    336 {
    337     if (!object())
    338         return 0;
    339     WebGLAttachment* attachmentObject = getAttachment(attachment);
    340     return attachmentObject ? attachmentObject->object() : 0;
    341 }
    342 
    343 bool WebGLFramebuffer::isAttachmentComplete(WebGLAttachment* attachedObject, GC3Denum attachment, const char** reason) const
    344 {
    345     ASSERT(attachedObject && attachedObject->valid());
    346     ASSERT(reason);
    347 
    348     GC3Denum internalformat = attachedObject->format();
    349     WebGLSharedObject* object = attachedObject->object();
    350     ASSERT(object && (object->isTexture() || object->isRenderbuffer()));
    351 
    352     if (attachment == GL_DEPTH_ATTACHMENT) {
    353         if (object->isRenderbuffer()) {
    354             if (internalformat != GL_DEPTH_COMPONENT16) {
    355                 *reason = "the internalformat of the attached renderbuffer is not DEPTH_COMPONENT16";
    356                 return false;
    357             }
    358         } else if (object->isTexture()) {
    359             GC3Denum type = attachedObject->type();
    360             if (!(context()->m_webglDepthTexture && internalformat == GL_DEPTH_COMPONENT
    361                 && (type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT))) {
    362                 *reason = "the attached texture is not a depth texture";
    363                 return false;
    364             }
    365         }
    366     } else if (attachment == GL_STENCIL_ATTACHMENT) {
    367         // Depend on the underlying GL drivers to check stencil textures
    368         // and check renderbuffer type here only.
    369         if (object->isRenderbuffer()) {
    370             if (internalformat != GL_STENCIL_INDEX8) {
    371                 *reason = "the internalformat of the attached renderbuffer is not STENCIL_INDEX8";
    372                 return false;
    373             }
    374         }
    375     } else if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) {
    376         if (object->isRenderbuffer()) {
    377             if (internalformat != GL_DEPTH_STENCIL_OES) {
    378                 *reason = "the internalformat of the attached renderbuffer is not DEPTH_STENCIL";
    379                 return false;
    380             }
    381         } else if (object->isTexture()) {
    382             GC3Denum type = attachedObject->type();
    383             if (!(context()->m_webglDepthTexture && internalformat == GL_DEPTH_STENCIL_OES
    384                 && type == GL_UNSIGNED_INT_24_8_OES)) {
    385                 *reason = "the attached texture is not a DEPTH_STENCIL texture";
    386                 return false;
    387             }
    388         }
    389     } else if (attachment == GL_COLOR_ATTACHMENT0
    390         || (context()->m_webglDrawBuffers && attachment > GL_COLOR_ATTACHMENT0
    391             && attachment < static_cast<GC3Denum>(GL_COLOR_ATTACHMENT0 + context()->maxColorAttachments()))) {
    392         if (object->isRenderbuffer()) {
    393             if (!isColorRenderable(internalformat)) {
    394                 *reason = "the internalformat of the attached renderbuffer is not color-renderable";
    395                 return false;
    396             }
    397         } else if (object->isTexture()) {
    398             GC3Denum type = attachedObject->type();
    399             if (internalformat != GL_RGBA && internalformat != GL_RGB) {
    400                 *reason = "the internalformat of the attached texture is not color-renderable";
    401                 return false;
    402             }
    403             // TODO: WEBGL_color_buffer_float and EXT_color_buffer_half_float extensions have not been implemented in
    404             // WebGL yet. It would be better to depend on the underlying GL drivers to check on rendering to floating point textures
    405             // and add the check back to WebGL when above two extensions are implemented.
    406             // Assume UNSIGNED_BYTE is renderable here without the need to explicitly check if GL_OES_rgb8_rgba8 extension is supported.
    407             if (type != GL_UNSIGNED_BYTE
    408                 && type != GL_UNSIGNED_SHORT_5_6_5
    409                 && type != GL_UNSIGNED_SHORT_4_4_4_4
    410                 && type != GL_UNSIGNED_SHORT_5_5_5_1
    411                 && !(type == GL_FLOAT && context()->m_oesTextureFloat)
    412                 && !(type == GL_HALF_FLOAT_OES && context()->m_oesTextureHalfFloat)) {
    413                 *reason = "unsupported type: The attached texture is not supported to be rendered to";
    414                 return false;
    415             }
    416         }
    417     } else {
    418         *reason = "unknown framebuffer attachment point";
    419         return false;
    420     }
    421 
    422     if (!attachedObject->width() || !attachedObject->height()) {
    423         *reason = "attachment has a 0 dimension";
    424         return false;
    425     }
    426     return true;
    427 }
    428 
    429 WebGLFramebuffer::WebGLAttachment* WebGLFramebuffer::getAttachment(GC3Denum attachment) const
    430 {
    431     const AttachmentMap::const_iterator it = m_attachments.find(attachment);
    432     return (it != m_attachments.end()) ? it->value.get() : 0;
    433 }
    434 
    435 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GC3Denum attachment)
    436 {
    437     ASSERT(isBound());
    438     if (!object())
    439         return;
    440 
    441     WebGLAttachment* attachmentObject = getAttachment(attachment);
    442     if (attachmentObject) {
    443         attachmentObject->onDetached(context()->graphicsContext3D());
    444         m_attachments.remove(attachment);
    445         drawBuffersIfNecessary(false);
    446         switch (attachment) {
    447         case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL:
    448             attach(GL_DEPTH_ATTACHMENT, GL_DEPTH_ATTACHMENT);
    449             attach(GL_STENCIL_ATTACHMENT, GL_STENCIL_ATTACHMENT);
    450             break;
    451         case GL_DEPTH_ATTACHMENT:
    452             attach(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL, GL_DEPTH_ATTACHMENT);
    453             break;
    454         case GL_STENCIL_ATTACHMENT:
    455             attach(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL, GL_STENCIL_ATTACHMENT);
    456             break;
    457         }
    458     }
    459 }
    460 
    461 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(WebGLSharedObject* attachment)
    462 {
    463     ASSERT(isBound());
    464     if (!object())
    465         return;
    466     if (!attachment)
    467         return;
    468 
    469     bool checkMore = true;
    470     while (checkMore) {
    471         checkMore = false;
    472         for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
    473             WebGLAttachment* attachmentObject = it->value.get();
    474             if (attachmentObject->isSharedObject(attachment)) {
    475                 GC3Denum attachmentType = it->key;
    476                 attachmentObject->unattach(context()->graphicsContext3D(), attachmentType);
    477                 removeAttachmentFromBoundFramebuffer(attachmentType);
    478                 checkMore = true;
    479                 break;
    480             }
    481         }
    482     }
    483 }
    484 
    485 GC3Dsizei WebGLFramebuffer::colorBufferWidth() const
    486 {
    487     if (!object())
    488         return 0;
    489     WebGLAttachment* attachment = getAttachment(GL_COLOR_ATTACHMENT0);
    490     if (!attachment)
    491         return 0;
    492 
    493     return attachment->width();
    494 }
    495 
    496 GC3Dsizei WebGLFramebuffer::colorBufferHeight() const
    497 {
    498     if (!object())
    499         return 0;
    500     WebGLAttachment* attachment = getAttachment(GL_COLOR_ATTACHMENT0);
    501     if (!attachment)
    502         return 0;
    503 
    504     return attachment->height();
    505 }
    506 
    507 GC3Denum WebGLFramebuffer::colorBufferFormat() const
    508 {
    509     if (!object())
    510         return 0;
    511     WebGLAttachment* attachment = getAttachment(GL_COLOR_ATTACHMENT0);
    512     if (!attachment)
    513         return 0;
    514     return attachment->format();
    515 }
    516 
    517 GC3Denum WebGLFramebuffer::checkStatus(const char** reason) const
    518 {
    519     unsigned int count = 0;
    520     GC3Dsizei width = 0, height = 0;
    521     bool haveDepth = false;
    522     bool haveStencil = false;
    523     bool haveDepthStencil = false;
    524     for (AttachmentMap::const_iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
    525         WebGLAttachment* attachment = it->value.get();
    526         if (!isAttachmentComplete(attachment, it->key, reason))
    527             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    528         if (!attachment->valid()) {
    529             *reason = "attachment is not valid";
    530             return GL_FRAMEBUFFER_UNSUPPORTED;
    531         }
    532         if (!attachment->format()) {
    533             *reason = "attachment is an unsupported format";
    534             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    535         }
    536         switch (it->key) {
    537         case GL_DEPTH_ATTACHMENT:
    538             haveDepth = true;
    539             break;
    540         case GL_STENCIL_ATTACHMENT:
    541             haveStencil = true;
    542             break;
    543         case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL:
    544             haveDepthStencil = true;
    545             break;
    546         }
    547         if (!count) {
    548             width = attachment->width();
    549             height = attachment->height();
    550         } else {
    551             if (width != attachment->width() || height != attachment->height()) {
    552                 *reason = "attachments do not have the same dimensions";
    553                 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
    554             }
    555         }
    556         ++count;
    557     }
    558     if (!count) {
    559         *reason = "no attachments";
    560         return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
    561     }
    562     if (!width || !height) {
    563         *reason = "framebuffer has a 0 dimension";
    564         return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    565     }
    566     // WebGL specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments.
    567     if ((haveDepthStencil && (haveDepth || haveStencil)) || (haveDepth && haveStencil)) {
    568         *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments";
    569         return GL_FRAMEBUFFER_UNSUPPORTED;
    570     }
    571     return GL_FRAMEBUFFER_COMPLETE;
    572 }
    573 
    574 bool WebGLFramebuffer::onAccess(GraphicsContext3D* context3d, const char** reason)
    575 {
    576     if (checkStatus(reason) != GL_FRAMEBUFFER_COMPLETE)
    577         return false;
    578     return true;
    579 }
    580 
    581 bool WebGLFramebuffer::hasStencilBuffer() const
    582 {
    583     WebGLAttachment* attachment = getAttachment(GL_STENCIL_ATTACHMENT);
    584     if (!attachment)
    585         attachment = getAttachment(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL);
    586     return attachment && attachment->valid();
    587 }
    588 
    589 void WebGLFramebuffer::deleteObjectImpl(GraphicsContext3D* context3d, Platform3DObject object)
    590 {
    591     for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it)
    592         it->value->onDetached(context3d);
    593 
    594     context3d->deleteFramebuffer(object);
    595 }
    596 
    597 bool WebGLFramebuffer::isBound() const
    598 {
    599     return (context()->m_framebufferBinding.get() == this);
    600 }
    601 
    602 void WebGLFramebuffer::drawBuffers(const Vector<GC3Denum>& bufs)
    603 {
    604     m_drawBuffers = bufs;
    605     m_filteredDrawBuffers.resize(m_drawBuffers.size());
    606     for (size_t i = 0; i < m_filteredDrawBuffers.size(); ++i)
    607         m_filteredDrawBuffers[i] = GL_NONE;
    608     drawBuffersIfNecessary(true);
    609 }
    610 
    611 void WebGLFramebuffer::drawBuffersIfNecessary(bool force)
    612 {
    613     if (!context()->m_webglDrawBuffers)
    614         return;
    615     bool reset = force;
    616     // This filtering works around graphics driver bugs on Mac OS X.
    617     for (size_t i = 0; i < m_drawBuffers.size(); ++i) {
    618         if (m_drawBuffers[i] != GL_NONE && getAttachment(m_drawBuffers[i])) {
    619             if (m_filteredDrawBuffers[i] != m_drawBuffers[i]) {
    620                 m_filteredDrawBuffers[i] = m_drawBuffers[i];
    621                 reset = true;
    622             }
    623         } else {
    624             if (m_filteredDrawBuffers[i] != GL_NONE) {
    625                 m_filteredDrawBuffers[i] = GL_NONE;
    626                 reset = true;
    627             }
    628         }
    629     }
    630     if (reset) {
    631         context()->graphicsContext3D()->extensions()->drawBuffersEXT(
    632             m_filteredDrawBuffers.size(), m_filteredDrawBuffers.data());
    633     }
    634 }
    635 
    636 GC3Denum WebGLFramebuffer::getDrawBuffer(GC3Denum drawBuffer)
    637 {
    638     int index = static_cast<int>(drawBuffer - Extensions3D::DRAW_BUFFER0_EXT);
    639     ASSERT(index >= 0);
    640     if (index < static_cast<int>(m_drawBuffers.size()))
    641         return m_drawBuffers[index];
    642     if (drawBuffer == Extensions3D::DRAW_BUFFER0_EXT)
    643         return GL_COLOR_ATTACHMENT0;
    644     return GL_NONE;
    645 }
    646 
    647 }
    648