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