Upstream version 9.38.198.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/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     ScriptWrappable::init(this);
282     setObject(ctx->webContext()->createFramebuffer());
283 }
284
285 WebGLFramebuffer::~WebGLFramebuffer()
286 {
287     // Delete the platform framebuffer resource. Explicit detachment
288     // is for the benefit of Oilpan, where the framebuffer object
289     // isn't detached when it and the WebGLRenderingContextBase object
290     // it is registered with are both finalized. Without Oilpan, the
291     // object will have been detached.
292     //
293     // To keep the code regular, the trivial detach()ment is always
294     // performed.
295     detachAndDeleteObject();
296 }
297
298 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum attachment, GLenum texTarget, WebGLTexture* texture, GLint level)
299 {
300     ASSERT(isBound());
301     removeAttachmentFromBoundFramebuffer(attachment);
302     if (!object())
303         return;
304     if (texture && texture->object()) {
305         m_attachments.add(attachment, WebGLTextureAttachment::create(texture, texTarget, level));
306         drawBuffersIfNecessary(false);
307         texture->onAttached();
308     }
309 }
310
311 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum attachment, WebGLRenderbuffer* renderbuffer)
312 {
313     ASSERT(isBound());
314     removeAttachmentFromBoundFramebuffer(attachment);
315     if (!object())
316         return;
317     if (renderbuffer && renderbuffer->object()) {
318         m_attachments.add(attachment, WebGLRenderbufferAttachment::create(renderbuffer));
319         drawBuffersIfNecessary(false);
320         renderbuffer->onAttached();
321     }
322 }
323
324 void WebGLFramebuffer::attach(GLenum attachment, GLenum attachmentPoint)
325 {
326     ASSERT(isBound());
327     WebGLAttachment* attachmentObject = getAttachment(attachment);
328     if (attachmentObject)
329         attachmentObject->attach(context()->webContext(), attachmentPoint);
330 }
331
332 WebGLSharedObject* WebGLFramebuffer::getAttachmentObject(GLenum attachment) const
333 {
334     if (!object())
335         return 0;
336     WebGLAttachment* attachmentObject = getAttachment(attachment);
337     return attachmentObject ? attachmentObject->object() : 0;
338 }
339
340 bool WebGLFramebuffer::isAttachmentComplete(WebGLAttachment* attachedObject, GLenum attachment, const char** reason) const
341 {
342     ASSERT(attachedObject && attachedObject->valid());
343     ASSERT(reason);
344
345     GLenum internalformat = attachedObject->format();
346     WebGLSharedObject* object = attachedObject->object();
347     ASSERT(object && (object->isTexture() || object->isRenderbuffer()));
348
349     if (attachment == GL_DEPTH_ATTACHMENT) {
350         if (object->isRenderbuffer()) {
351             if (internalformat != GL_DEPTH_COMPONENT16) {
352                 *reason = "the internalformat of the attached renderbuffer is not DEPTH_COMPONENT16";
353                 return false;
354             }
355         } else if (object->isTexture()) {
356             GLenum type = attachedObject->type();
357             if (!(context()->extensionEnabled(WebGLDepthTextureName) && internalformat == GL_DEPTH_COMPONENT
358                 && (type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT))) {
359                 *reason = "the attached texture is not a depth texture";
360                 return false;
361             }
362         }
363     } else if (attachment == GL_STENCIL_ATTACHMENT) {
364         // Depend on the underlying GL drivers to check stencil textures
365         // and check renderbuffer type here only.
366         if (object->isRenderbuffer()) {
367             if (internalformat != GL_STENCIL_INDEX8) {
368                 *reason = "the internalformat of the attached renderbuffer is not STENCIL_INDEX8";
369                 return false;
370             }
371         }
372     } else if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) {
373         if (object->isRenderbuffer()) {
374             if (internalformat != GL_DEPTH_STENCIL_OES) {
375                 *reason = "the internalformat of the attached renderbuffer is not DEPTH_STENCIL";
376                 return false;
377             }
378         } else if (object->isTexture()) {
379             GLenum type = attachedObject->type();
380             if (!(context()->extensionEnabled(WebGLDepthTextureName) && internalformat == GL_DEPTH_STENCIL_OES
381                 && type == GL_UNSIGNED_INT_24_8_OES)) {
382                 *reason = "the attached texture is not a DEPTH_STENCIL texture";
383                 return false;
384             }
385         }
386     } else if (attachment == GL_COLOR_ATTACHMENT0
387         || (context()->extensionEnabled(WebGLDrawBuffersName) && attachment > GL_COLOR_ATTACHMENT0
388             && attachment < static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + context()->maxColorAttachments()))) {
389         if (object->isRenderbuffer()) {
390             if (!isColorRenderable(internalformat)) {
391                 *reason = "the internalformat of the attached renderbuffer is not color-renderable";
392                 return false;
393             }
394         } else if (object->isTexture()) {
395             GLenum type = attachedObject->type();
396             if (internalformat != GL_RGBA && internalformat != GL_RGB) {
397                 *reason = "the internalformat of the attached texture is not color-renderable";
398                 return false;
399             }
400             // TODO: WEBGL_color_buffer_float and EXT_color_buffer_half_float extensions have not been implemented in
401             // WebGL yet. It would be better to depend on the underlying GL drivers to check on rendering to floating point textures
402             // and add the check back to WebGL when above two extensions are implemented.
403             // Assume UNSIGNED_BYTE is renderable here without the need to explicitly check if GL_OES_rgb8_rgba8 extension is supported.
404             if (type != GL_UNSIGNED_BYTE
405                 && type != GL_UNSIGNED_SHORT_5_6_5
406                 && type != GL_UNSIGNED_SHORT_4_4_4_4
407                 && type != GL_UNSIGNED_SHORT_5_5_5_1
408                 && !(type == GL_FLOAT && context()->extensionEnabled(OESTextureFloatName))
409                 && !(type == GL_HALF_FLOAT_OES && context()->extensionEnabled(OESTextureHalfFloatName))) {
410                 *reason = "unsupported type: The attached texture is not supported to be rendered to";
411                 return false;
412             }
413         }
414     } else {
415         *reason = "unknown framebuffer attachment point";
416         return false;
417     }
418
419     if (!attachedObject->width() || !attachedObject->height()) {
420         *reason = "attachment has a 0 dimension";
421         return false;
422     }
423     return true;
424 }
425
426 WebGLFramebuffer::WebGLAttachment* WebGLFramebuffer::getAttachment(GLenum attachment) const
427 {
428     const AttachmentMap::const_iterator it = m_attachments.find(attachment);
429     return (it != m_attachments.end()) ? it->value.get() : 0;
430 }
431
432 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GLenum attachment)
433 {
434     ASSERT(isBound());
435     if (!object())
436         return;
437
438     WebGLAttachment* attachmentObject = getAttachment(attachment);
439     if (attachmentObject) {
440         attachmentObject->onDetached(context()->webContext());
441         m_attachments.remove(attachment);
442         drawBuffersIfNecessary(false);
443         switch (attachment) {
444         case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL:
445             attach(GL_DEPTH_ATTACHMENT, GL_DEPTH_ATTACHMENT);
446             attach(GL_STENCIL_ATTACHMENT, GL_STENCIL_ATTACHMENT);
447             break;
448         case GL_DEPTH_ATTACHMENT:
449             attach(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL, GL_DEPTH_ATTACHMENT);
450             break;
451         case GL_STENCIL_ATTACHMENT:
452             attach(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL, GL_STENCIL_ATTACHMENT);
453             break;
454         }
455     }
456 }
457
458 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(WebGLSharedObject* attachment)
459 {
460     ASSERT(isBound());
461     if (!object())
462         return;
463     if (!attachment)
464         return;
465
466     bool checkMore = true;
467     while (checkMore) {
468         checkMore = false;
469         for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
470             WebGLAttachment* attachmentObject = it->value.get();
471             if (attachmentObject->isSharedObject(attachment)) {
472                 GLenum attachmentType = it->key;
473                 attachmentObject->unattach(context()->webContext(), attachmentType);
474                 removeAttachmentFromBoundFramebuffer(attachmentType);
475                 checkMore = true;
476                 break;
477             }
478         }
479     }
480 }
481
482 GLenum WebGLFramebuffer::colorBufferFormat() const
483 {
484     if (!object())
485         return 0;
486     WebGLAttachment* attachment = getAttachment(GL_COLOR_ATTACHMENT0);
487     if (!attachment)
488         return 0;
489     return attachment->format();
490 }
491
492 GLenum WebGLFramebuffer::checkStatus(const char** reason) const
493 {
494     unsigned count = 0;
495     GLsizei width = 0, height = 0;
496     bool haveDepth = false;
497     bool haveStencil = false;
498     bool haveDepthStencil = false;
499     for (AttachmentMap::const_iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
500         WebGLAttachment* attachment = it->value.get();
501         if (!isAttachmentComplete(attachment, it->key, reason))
502             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
503         if (!attachment->valid()) {
504             *reason = "attachment is not valid";
505             return GL_FRAMEBUFFER_UNSUPPORTED;
506         }
507         if (!attachment->format()) {
508             *reason = "attachment is an unsupported format";
509             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
510         }
511         switch (it->key) {
512         case GL_DEPTH_ATTACHMENT:
513             haveDepth = true;
514             break;
515         case GL_STENCIL_ATTACHMENT:
516             haveStencil = true;
517             break;
518         case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL:
519             haveDepthStencil = true;
520             break;
521         }
522         if (!count) {
523             width = attachment->width();
524             height = attachment->height();
525         } else {
526             if (width != attachment->width() || height != attachment->height()) {
527                 *reason = "attachments do not have the same dimensions";
528                 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
529             }
530         }
531         ++count;
532     }
533     if (!count) {
534         *reason = "no attachments";
535         return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
536     }
537     if (!width || !height) {
538         *reason = "framebuffer has a 0 dimension";
539         return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
540     }
541     // WebGL specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments.
542     if ((haveDepthStencil && (haveDepth || haveStencil)) || (haveDepth && haveStencil)) {
543         *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments";
544         return GL_FRAMEBUFFER_UNSUPPORTED;
545     }
546     return GL_FRAMEBUFFER_COMPLETE;
547 }
548
549 bool WebGLFramebuffer::onAccess(blink::WebGraphicsContext3D* context3d, const char** reason)
550 {
551     if (checkStatus(reason) != GL_FRAMEBUFFER_COMPLETE)
552         return false;
553     return true;
554 }
555
556 bool WebGLFramebuffer::hasStencilBuffer() const
557 {
558     WebGLAttachment* attachment = getAttachment(GL_STENCIL_ATTACHMENT);
559     if (!attachment)
560         attachment = getAttachment(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL);
561     return attachment && attachment->valid();
562 }
563
564 void WebGLFramebuffer::deleteObjectImpl(blink::WebGraphicsContext3D* context3d, Platform3DObject object)
565 {
566 #if !ENABLE(OILPAN)
567     // With Oilpan, both the AttachmentMap and its WebGLAttachment objects are
568     // GCed objects and cannot be accessed, as they may have been finalized
569     // already during the same GC sweep.
570     //
571     // The WebGLAttachment-derived classes instead handle detachment
572     // on their own when finalizing, so the explicit notification is
573     // not needed.
574     for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it)
575         it->value->onDetached(context3d);
576 #endif
577
578     context3d->deleteFramebuffer(object);
579 }
580
581 bool WebGLFramebuffer::isBound() const
582 {
583     return (context()->m_framebufferBinding.get() == this);
584 }
585
586 void WebGLFramebuffer::drawBuffers(const Vector<GLenum>& bufs)
587 {
588     m_drawBuffers = bufs;
589     m_filteredDrawBuffers.resize(m_drawBuffers.size());
590     for (size_t i = 0; i < m_filteredDrawBuffers.size(); ++i)
591         m_filteredDrawBuffers[i] = GL_NONE;
592     drawBuffersIfNecessary(true);
593 }
594
595 void WebGLFramebuffer::drawBuffersIfNecessary(bool force)
596 {
597     if (!context()->extensionEnabled(WebGLDrawBuffersName))
598         return;
599     bool reset = force;
600     // This filtering works around graphics driver bugs on Mac OS X.
601     for (size_t i = 0; i < m_drawBuffers.size(); ++i) {
602         if (m_drawBuffers[i] != GL_NONE && getAttachment(m_drawBuffers[i])) {
603             if (m_filteredDrawBuffers[i] != m_drawBuffers[i]) {
604                 m_filteredDrawBuffers[i] = m_drawBuffers[i];
605                 reset = true;
606             }
607         } else {
608             if (m_filteredDrawBuffers[i] != GL_NONE) {
609                 m_filteredDrawBuffers[i] = GL_NONE;
610                 reset = true;
611             }
612         }
613     }
614     if (reset) {
615         context()->webContext()->drawBuffersEXT(
616             m_filteredDrawBuffers.size(), m_filteredDrawBuffers.data());
617     }
618 }
619
620 GLenum WebGLFramebuffer::getDrawBuffer(GLenum drawBuffer)
621 {
622     int index = static_cast<int>(drawBuffer - GL_DRAW_BUFFER0_EXT);
623     ASSERT(index >= 0);
624     if (index < static_cast<int>(m_drawBuffers.size()))
625         return m_drawBuffers[index];
626     if (drawBuffer == GL_DRAW_BUFFER0_EXT)
627         return GL_COLOR_ATTACHMENT0;
628     return GL_NONE;
629 }
630
631 void WebGLFramebuffer::trace(Visitor* visitor)
632 {
633 #if ENABLE(OILPAN)
634     visitor->trace(m_attachments);
635 #endif
636     WebGLContextObject::trace(visitor);
637 }
638
639 }