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