Upstream version 5.34.104.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 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(WebGLRenderingContext* ctx)
257 {
258     return adoptRef(new WebGLFramebuffer(ctx));
259 }
260
261 WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContext* ctx)
262     : WebGLContextObject(ctx)
263     , m_hasEverBeenBound(false)
264 {
265     ScriptWrappable::init(this);
266     setObject(ctx->webGraphicsContext3D()->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()->webGraphicsContext3D(), 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()->m_webglDepthTexture && 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()->m_webglDepthTexture && 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()->m_webglDrawBuffers && 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()->m_oesTextureFloat)
385                 && !(type == GL_HALF_FLOAT_OES && context()->m_oesTextureHalfFloat)) {
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()->webGraphicsContext3D());
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()->webGraphicsContext3D(), attachmentType);
450                 removeAttachmentFromBoundFramebuffer(attachmentType);
451                 checkMore = true;
452                 break;
453             }
454         }
455     }
456 }
457
458 GLsizei WebGLFramebuffer::colorBufferWidth() const
459 {
460     if (!object())
461         return 0;
462     WebGLAttachment* attachment = getAttachment(GL_COLOR_ATTACHMENT0);
463     if (!attachment)
464         return 0;
465
466     return attachment->width();
467 }
468
469 GLsizei WebGLFramebuffer::colorBufferHeight() const
470 {
471     if (!object())
472         return 0;
473     WebGLAttachment* attachment = getAttachment(GL_COLOR_ATTACHMENT0);
474     if (!attachment)
475         return 0;
476
477     return attachment->height();
478 }
479
480 GLenum WebGLFramebuffer::colorBufferFormat() const
481 {
482     if (!object())
483         return 0;
484     WebGLAttachment* attachment = getAttachment(GL_COLOR_ATTACHMENT0);
485     if (!attachment)
486         return 0;
487     return attachment->format();
488 }
489
490 GLenum WebGLFramebuffer::checkStatus(const char** reason) const
491 {
492     unsigned int count = 0;
493     GLsizei width = 0, height = 0;
494     bool haveDepth = false;
495     bool haveStencil = false;
496     bool haveDepthStencil = false;
497     for (AttachmentMap::const_iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
498         WebGLAttachment* attachment = it->value.get();
499         if (!isAttachmentComplete(attachment, it->key, reason))
500             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
501         if (!attachment->valid()) {
502             *reason = "attachment is not valid";
503             return GL_FRAMEBUFFER_UNSUPPORTED;
504         }
505         if (!attachment->format()) {
506             *reason = "attachment is an unsupported format";
507             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
508         }
509         switch (it->key) {
510         case GL_DEPTH_ATTACHMENT:
511             haveDepth = true;
512             break;
513         case GL_STENCIL_ATTACHMENT:
514             haveStencil = true;
515             break;
516         case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL:
517             haveDepthStencil = true;
518             break;
519         }
520         if (!count) {
521             width = attachment->width();
522             height = attachment->height();
523         } else {
524             if (width != attachment->width() || height != attachment->height()) {
525                 *reason = "attachments do not have the same dimensions";
526                 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
527             }
528         }
529         ++count;
530     }
531     if (!count) {
532         *reason = "no attachments";
533         return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
534     }
535     if (!width || !height) {
536         *reason = "framebuffer has a 0 dimension";
537         return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
538     }
539     // WebGL specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments.
540     if ((haveDepthStencil && (haveDepth || haveStencil)) || (haveDepth && haveStencil)) {
541         *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments";
542         return GL_FRAMEBUFFER_UNSUPPORTED;
543     }
544     return GL_FRAMEBUFFER_COMPLETE;
545 }
546
547 bool WebGLFramebuffer::onAccess(blink::WebGraphicsContext3D* context3d, const char** reason)
548 {
549     if (checkStatus(reason) != GL_FRAMEBUFFER_COMPLETE)
550         return false;
551     return true;
552 }
553
554 bool WebGLFramebuffer::hasStencilBuffer() const
555 {
556     WebGLAttachment* attachment = getAttachment(GL_STENCIL_ATTACHMENT);
557     if (!attachment)
558         attachment = getAttachment(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL);
559     return attachment && attachment->valid();
560 }
561
562 void WebGLFramebuffer::deleteObjectImpl(blink::WebGraphicsContext3D* context3d, Platform3DObject object)
563 {
564     for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it)
565         it->value->onDetached(context3d);
566
567     context3d->deleteFramebuffer(object);
568 }
569
570 bool WebGLFramebuffer::isBound() const
571 {
572     return (context()->m_framebufferBinding.get() == this);
573 }
574
575 void WebGLFramebuffer::drawBuffers(const Vector<GLenum>& bufs)
576 {
577     m_drawBuffers = bufs;
578     m_filteredDrawBuffers.resize(m_drawBuffers.size());
579     for (size_t i = 0; i < m_filteredDrawBuffers.size(); ++i)
580         m_filteredDrawBuffers[i] = GL_NONE;
581     drawBuffersIfNecessary(true);
582 }
583
584 void WebGLFramebuffer::drawBuffersIfNecessary(bool force)
585 {
586     if (!context()->m_webglDrawBuffers)
587         return;
588     bool reset = force;
589     // This filtering works around graphics driver bugs on Mac OS X.
590     for (size_t i = 0; i < m_drawBuffers.size(); ++i) {
591         if (m_drawBuffers[i] != GL_NONE && getAttachment(m_drawBuffers[i])) {
592             if (m_filteredDrawBuffers[i] != m_drawBuffers[i]) {
593                 m_filteredDrawBuffers[i] = m_drawBuffers[i];
594                 reset = true;
595             }
596         } else {
597             if (m_filteredDrawBuffers[i] != GL_NONE) {
598                 m_filteredDrawBuffers[i] = GL_NONE;
599                 reset = true;
600             }
601         }
602     }
603     if (reset) {
604         context()->webGraphicsContext3D()->drawBuffersEXT(
605             m_filteredDrawBuffers.size(), m_filteredDrawBuffers.data());
606     }
607 }
608
609 GLenum WebGLFramebuffer::getDrawBuffer(GLenum drawBuffer)
610 {
611     int index = static_cast<int>(drawBuffer - GL_DRAW_BUFFER0_EXT);
612     ASSERT(index >= 0);
613     if (index < static_cast<int>(m_drawBuffers.size()))
614         return m_drawBuffers[index];
615     if (drawBuffer == GL_DRAW_BUFFER0_EXT)
616         return GL_COLOR_ATTACHMENT0;
617     return GL_NONE;
618 }
619
620 }