a48e1d0cdd4b8b1199f2c27aeadbc9cb57caba6b
[WebKit.git] / Source / WebCore / 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 #if ENABLE(WEBGL)
29
30 #include "WebGLFramebuffer.h"
31
32 #include "EXTDrawBuffers.h"
33 #include "Extensions3D.h"
34 #include "WebGLContextGroup.h"
35 #include "WebGLRenderingContext.h"
36
37 namespace WebCore {
38
39 namespace {
40
41     Platform3DObject objectOrZero(WebGLObject* object)
42     {
43         return object ? object->object() : 0;
44     }
45
46     class WebGLRenderbufferAttachment : public WebGLFramebuffer::WebGLAttachment {
47     public:
48         static PassRefPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLRenderbuffer*);
49
50     private:
51         WebGLRenderbufferAttachment(WebGLRenderbuffer*);
52         virtual GC3Dsizei getWidth() const;
53         virtual GC3Dsizei getHeight() const;
54         virtual GC3Denum getFormat() const;
55         virtual WebGLSharedObject* getObject() const;
56         virtual bool isSharedObject(WebGLSharedObject*) const;
57         virtual bool isValid() const;
58         virtual bool isInitialized() const;
59         virtual void setInitialized();
60         virtual void onDetached(GraphicsContext3D*);
61         virtual void attach(GraphicsContext3D*, GC3Denum attachment);
62         virtual void unattach(GraphicsContext3D*, GC3Denum attachment);
63
64         WebGLRenderbufferAttachment() { };
65
66         RefPtr<WebGLRenderbuffer> m_renderbuffer;
67     };
68
69     PassRefPtr<WebGLFramebuffer::WebGLAttachment> WebGLRenderbufferAttachment::create(WebGLRenderbuffer* renderbuffer)
70     {
71         return adoptRef(new WebGLRenderbufferAttachment(renderbuffer));
72     }
73
74     WebGLRenderbufferAttachment::WebGLRenderbufferAttachment(WebGLRenderbuffer* renderbuffer)
75         : m_renderbuffer(renderbuffer)
76     {
77     }
78
79     GC3Dsizei WebGLRenderbufferAttachment::getWidth() const
80     {
81         return m_renderbuffer->getWidth();
82     }
83
84     GC3Dsizei WebGLRenderbufferAttachment::getHeight() const
85     {
86         return m_renderbuffer->getHeight();
87     }
88
89     GC3Denum WebGLRenderbufferAttachment::getFormat() const
90     {
91         return m_renderbuffer->getInternalFormat();
92     }
93
94     WebGLSharedObject* WebGLRenderbufferAttachment::getObject() const
95     {
96         return m_renderbuffer->object() ? m_renderbuffer.get() : 0;
97     }
98
99     bool WebGLRenderbufferAttachment::isSharedObject(WebGLSharedObject* object) const
100     {
101         return object == m_renderbuffer;
102     }
103
104     bool WebGLRenderbufferAttachment::isValid() const
105     {
106         return m_renderbuffer->object();
107     }
108
109     bool WebGLRenderbufferAttachment::isInitialized() const
110     {
111         return m_renderbuffer->object() && m_renderbuffer->isInitialized();
112     }
113
114     void WebGLRenderbufferAttachment::setInitialized()
115     {
116         if (m_renderbuffer->object())
117             m_renderbuffer->setInitialized();
118     }
119
120     void WebGLRenderbufferAttachment::onDetached(GraphicsContext3D* context)
121     {
122         m_renderbuffer->onDetached(context);
123     }
124
125     void WebGLRenderbufferAttachment::attach(GraphicsContext3D* context, GC3Denum attachment)
126     {
127         Platform3DObject object = objectOrZero(m_renderbuffer.get());
128         context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, attachment, GraphicsContext3D::RENDERBUFFER, object);
129     }
130
131     void WebGLRenderbufferAttachment::unattach(GraphicsContext3D* context, GC3Denum attachment)
132     {
133         if (attachment == GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT) {
134             context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, 0);
135             context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, 0);
136         } else
137             context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, attachment, GraphicsContext3D::RENDERBUFFER, 0);
138     }
139
140     class WebGLTextureAttachment : public WebGLFramebuffer::WebGLAttachment {
141     public:
142         static PassRefPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLTexture*, GC3Denum target, GC3Dint level);
143
144     private:
145         WebGLTextureAttachment(WebGLTexture*, GC3Denum target, GC3Dint level);
146         virtual GC3Dsizei getWidth() const;
147         virtual GC3Dsizei getHeight() const;
148         virtual GC3Denum getFormat() const;
149         virtual WebGLSharedObject* getObject() const;
150         virtual bool isSharedObject(WebGLSharedObject*) const;
151         virtual bool isValid() const;
152         virtual bool isInitialized() const;
153         virtual void setInitialized();
154         virtual void onDetached(GraphicsContext3D*);
155         virtual void attach(GraphicsContext3D*, GC3Denum attachment);
156         virtual void unattach(GraphicsContext3D*, GC3Denum attachment);
157
158         WebGLTextureAttachment() { };
159
160         RefPtr<WebGLTexture> m_texture;
161         GC3Denum m_target;
162         GC3Dint m_level;
163     };
164
165     PassRefPtr<WebGLFramebuffer::WebGLAttachment> WebGLTextureAttachment::create(WebGLTexture* texture, GC3Denum target, GC3Dint level)
166     {
167         return adoptRef(new WebGLTextureAttachment(texture, target, level));
168     }
169
170     WebGLTextureAttachment::WebGLTextureAttachment(WebGLTexture* texture, GC3Denum target, GC3Dint level)
171         : m_texture(texture)
172         , m_target(target)
173         , m_level(level)
174     {
175     }
176
177     GC3Dsizei WebGLTextureAttachment::getWidth() const
178     {
179         return m_texture->getWidth(m_target, m_level);
180     }
181
182     GC3Dsizei WebGLTextureAttachment::getHeight() const
183     {
184         return m_texture->getHeight(m_target, m_level);
185     }
186
187     GC3Denum WebGLTextureAttachment::getFormat() const
188     {
189         return m_texture->getInternalFormat(m_target, m_level);
190     }
191
192     WebGLSharedObject* WebGLTextureAttachment::getObject() const
193     {
194         return m_texture->object() ? m_texture.get() : 0;
195     }
196
197     bool WebGLTextureAttachment::isSharedObject(WebGLSharedObject* object) const
198     {
199         return object == m_texture;
200     }
201
202     bool WebGLTextureAttachment::isValid() const
203     {
204         return m_texture->object();
205     }
206
207     bool WebGLTextureAttachment::isInitialized() const
208     {
209         // Textures are assumed to be initialized.
210         return true;
211     }
212
213     void WebGLTextureAttachment::setInitialized()
214     {
215         // Textures are assumed to be initialized.
216     }
217
218     void WebGLTextureAttachment::onDetached(GraphicsContext3D* context)
219     {
220         m_texture->onDetached(context);
221     }
222
223     void WebGLTextureAttachment::attach(GraphicsContext3D* context, GC3Denum attachment)
224     {
225         Platform3DObject object = objectOrZero(m_texture.get());
226         context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, attachment, m_target, object, m_level);
227     }
228
229     void WebGLTextureAttachment::unattach(GraphicsContext3D* context, GC3Denum attachment)
230     {
231         if (attachment == GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT) {
232             context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, m_target, 0, m_level);
233             context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, m_target, 0, m_level);
234         } else
235             context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, attachment, m_target, 0, m_level);
236     }
237
238     bool isAttachmentComplete(WebGLFramebuffer::WebGLAttachment* attachedObject, GC3Denum attachment, const char** reason)
239     {
240         ASSERT(attachedObject && attachedObject->isValid());
241         ASSERT(reason);
242         GC3Denum format = attachedObject->getFormat();
243         unsigned need = GraphicsContext3D::getClearBitsByAttachmentType(attachment);
244         unsigned have = GraphicsContext3D::getClearBitsByFormat(format);
245
246         if ((need & have) != need) {
247             *reason = "attachment type is not correct for attachment";
248             return false;
249         }
250         if (!attachedObject->getWidth() || !attachedObject->getHeight()) {
251             *reason = "attachment has a 0 dimension";
252             return false;
253         }
254         if ((attachment == GraphicsContext3D::DEPTH_ATTACHMENT || attachment == GraphicsContext3D::STENCIL_ATTACHMENT)
255             && format == GraphicsContext3D::DEPTH_STENCIL) {
256           *reason = "attachment DEPTH_STENCIL not allowed on DEPTH or STENCIL attachment";
257           return false;
258         }
259         return true;
260     }
261
262 } // anonymous namespace
263
264 WebGLFramebuffer::WebGLAttachment::WebGLAttachment()
265 {
266 }
267
268 WebGLFramebuffer::WebGLAttachment::~WebGLAttachment()
269 {
270 }
271
272 PassRefPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContext* ctx)
273 {
274     return adoptRef(new WebGLFramebuffer(ctx));
275 }
276
277 WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContext* ctx)
278     : WebGLContextObject(ctx)
279     , m_hasEverBeenBound(false)
280 {
281     setObject(ctx->graphicsContext3D()->createFramebuffer());
282 }
283
284 WebGLFramebuffer::~WebGLFramebuffer()
285 {
286     deleteObject(0);
287 }
288
289 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GC3Denum attachment, GC3Denum texTarget, WebGLTexture* texture, GC3Dint level)
290 {
291     ASSERT(isBound());
292     removeAttachmentFromBoundFramebuffer(attachment);
293     if (!object())
294         return;
295     if (texture && texture->object()) {
296         m_attachments.add(attachment, WebGLTextureAttachment::create(texture, texTarget, level));
297         drawBuffersIfNecessary(false);
298         texture->onAttached();
299     }
300 }
301
302 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GC3Denum attachment, WebGLRenderbuffer* renderbuffer)
303 {
304     ASSERT(isBound());
305     removeAttachmentFromBoundFramebuffer(attachment);
306     if (!object())
307         return;
308     if (renderbuffer && renderbuffer->object()) {
309         m_attachments.add(attachment, WebGLRenderbufferAttachment::create(renderbuffer));
310         drawBuffersIfNecessary(false);
311         renderbuffer->onAttached();
312     }
313 }
314
315 void WebGLFramebuffer::attach(GC3Denum attachment, GC3Denum attachmentPoint)
316 {
317     ASSERT(isBound());
318     WebGLAttachment* attachmentObject = getAttachment(attachment);
319     if (attachmentObject)
320         attachmentObject->attach(context()->graphicsContext3D(), attachmentPoint);
321 }
322
323 WebGLSharedObject* WebGLFramebuffer::getAttachmentObject(GC3Denum attachment) const
324 {
325     if (!object())
326         return 0;
327     WebGLAttachment* attachmentObject = getAttachment(attachment);
328     return attachmentObject ? attachmentObject->getObject() : 0;
329 }
330
331 WebGLFramebuffer::WebGLAttachment* WebGLFramebuffer::getAttachment(GC3Denum attachment) const
332 {
333     const AttachmentMap::const_iterator it = m_attachments.find(attachment);
334     return (it != m_attachments.end()) ? it->value.get() : 0;
335 }
336
337 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GC3Denum attachment)
338 {
339     ASSERT(isBound());
340     if (!object())
341         return;
342
343     WebGLAttachment* attachmentObject = getAttachment(attachment);
344     if (attachmentObject) {
345         attachmentObject->onDetached(context()->graphicsContext3D());
346         m_attachments.remove(attachment);
347         drawBuffersIfNecessary(false);
348         switch (attachment) {
349         case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
350             attach(GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::DEPTH_ATTACHMENT);
351             attach(GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::STENCIL_ATTACHMENT);
352             break;
353         case GraphicsContext3D::DEPTH_ATTACHMENT:
354             attach(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT, GraphicsContext3D::DEPTH_ATTACHMENT);
355             break;
356         case GraphicsContext3D::STENCIL_ATTACHMENT:
357             attach(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT, GraphicsContext3D::STENCIL_ATTACHMENT);
358             break;
359         }
360     }
361 }
362
363 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(WebGLSharedObject* attachment)
364 {
365     ASSERT(isBound());
366     if (!object())
367         return;
368     if (!attachment)
369         return;
370
371     bool checkMore = true;
372     while (checkMore) {
373         checkMore = false;
374         for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
375             WebGLAttachment* attachmentObject = it->value.get();
376             if (attachmentObject->isSharedObject(attachment)) {
377                 GC3Denum attachmentType = it->key;
378                 attachmentObject->unattach(context()->graphicsContext3D(), attachmentType);
379                 removeAttachmentFromBoundFramebuffer(attachmentType);
380                 checkMore = true;
381                 break;
382             }
383         }
384     }
385 }
386
387 GC3Dsizei WebGLFramebuffer::getColorBufferWidth() const
388 {
389     if (!object())
390         return 0;
391     WebGLAttachment* attachment = getAttachment(GraphicsContext3D::COLOR_ATTACHMENT0);
392     if (!attachment)
393         return 0;
394
395     return attachment->getWidth();
396 }
397
398 GC3Dsizei WebGLFramebuffer::getColorBufferHeight() const
399 {
400     if (!object())
401         return 0;
402     WebGLAttachment* attachment = getAttachment(GraphicsContext3D::COLOR_ATTACHMENT0);
403     if (!attachment)
404         return 0;
405
406     return attachment->getHeight();
407 }
408
409 GC3Denum WebGLFramebuffer::getColorBufferFormat() const
410 {
411     if (!object())
412         return 0;
413     WebGLAttachment* attachment = getAttachment(GraphicsContext3D::COLOR_ATTACHMENT0);
414     if (!attachment)
415         return 0;
416     return attachment->getFormat();
417 }
418
419 GC3Denum WebGLFramebuffer::checkStatus(const char** reason) const
420 {
421     unsigned int count = 0;
422     GC3Dsizei width = 0, height = 0;
423     bool haveDepth = false;
424     bool haveStencil = false;
425     bool haveDepthStencil = false;
426     for (AttachmentMap::const_iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
427         WebGLAttachment* attachment = it->value.get();
428         if (!isAttachmentComplete(attachment, it->key, reason))
429             return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
430         if (!attachment->isValid()) {
431             *reason = "attachment is not valid";
432             return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
433         }
434         if (!attachment->getFormat()) {
435             *reason = "attachment is an unsupported format";
436             return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
437         }
438         switch (it->key) {
439         case GraphicsContext3D::DEPTH_ATTACHMENT:
440             haveDepth = true;
441             break;
442         case GraphicsContext3D::STENCIL_ATTACHMENT:
443             haveStencil = true;
444             break;
445         case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
446             haveDepthStencil = true;
447             break;
448         }
449         if (!count) {
450             width = attachment->getWidth();
451             height = attachment->getHeight();
452         } else {
453             if (width != attachment->getWidth() || height != attachment->getHeight()) {
454                 *reason = "attachments do not have the same dimensions";
455                 return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
456             }
457         }
458         ++count;
459     }
460     if (!count) {
461         *reason = "no attachments";
462         return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
463     }
464     if (!width || !height) {
465         *reason = "framebuffer has a 0 dimension";
466         return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
467     }
468     // WebGL specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments.
469     if ((haveDepthStencil && (haveDepth || haveStencil)) || (haveDepth && haveStencil)) {
470         *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments";
471         return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
472     }
473     return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
474 }
475
476 bool WebGLFramebuffer::onAccess(GraphicsContext3D* context3d, bool needToInitializeAttachments, const char** reason)
477 {
478     if (checkStatus(reason) != GraphicsContext3D::FRAMEBUFFER_COMPLETE)
479         return false;
480     if (needToInitializeAttachments)
481         return initializeAttachments(context3d, reason);
482     return true;
483 }
484
485 bool WebGLFramebuffer::hasStencilBuffer() const
486 {
487     WebGLAttachment* attachment = getAttachment(GraphicsContext3D::STENCIL_ATTACHMENT);
488     if (!attachment)
489         attachment = getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT);
490     return attachment && attachment->isValid();
491 }
492
493 void WebGLFramebuffer::deleteObjectImpl(GraphicsContext3D* context3d, Platform3DObject object)
494 {
495     for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it)
496         it->value->onDetached(context3d);
497
498     context3d->deleteFramebuffer(object);
499 }
500
501 bool WebGLFramebuffer::initializeAttachments(GraphicsContext3D* g3d, const char** reason)
502 {
503     ASSERT(object());
504     GC3Dbitfield mask = 0;
505
506     for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
507         GC3Denum attachmentType = it->key;
508         WebGLAttachment* attachment = it->value.get();
509         if (!attachment->isInitialized())
510            mask |= GraphicsContext3D::getClearBitsByAttachmentType(attachmentType);
511     }
512     if (!mask)
513         return true;
514
515     // We only clear un-initialized renderbuffers when they are ready to be
516     // read, i.e., when the framebuffer is complete.
517     if (g3d->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
518         *reason = "framebuffer not complete";
519         return false;
520     }
521
522     bool initColor = mask & GraphicsContext3D::COLOR_BUFFER_BIT;
523     bool initDepth = mask & GraphicsContext3D::DEPTH_BUFFER_BIT;
524     bool initStencil = mask & GraphicsContext3D::STENCIL_BUFFER_BIT;
525
526     GC3Dfloat colorClearValue[] = {0, 0, 0, 0}, depthClearValue = 0;
527     GC3Dint stencilClearValue = 0;
528     GC3Dboolean colorMask[] = {0, 0, 0, 0}, depthMask = 0;
529     GC3Duint stencilMask = 0xffffffff;
530     GC3Dboolean isScissorEnabled = 0;
531     GC3Dboolean isDitherEnabled = 0;
532     if (initColor) {
533         g3d->getFloatv(GraphicsContext3D::COLOR_CLEAR_VALUE, colorClearValue);
534         g3d->getBooleanv(GraphicsContext3D::COLOR_WRITEMASK, colorMask);
535         g3d->clearColor(0, 0, 0, 0);
536         g3d->colorMask(true, true, true, true);
537     }
538     if (initDepth) {
539         g3d->getFloatv(GraphicsContext3D::DEPTH_CLEAR_VALUE, &depthClearValue);
540         g3d->getBooleanv(GraphicsContext3D::DEPTH_WRITEMASK, &depthMask);
541         g3d->clearDepth(1.0f);
542         g3d->depthMask(true);
543     }
544     if (initStencil) {
545         g3d->getIntegerv(GraphicsContext3D::STENCIL_CLEAR_VALUE, &stencilClearValue);
546         g3d->getIntegerv(GraphicsContext3D::STENCIL_WRITEMASK, reinterpret_cast<GC3Dint*>(&stencilMask));
547         g3d->clearStencil(0);
548         g3d->stencilMask(0xffffffff);
549     }
550     isScissorEnabled = g3d->isEnabled(GraphicsContext3D::SCISSOR_TEST);
551     g3d->disable(GraphicsContext3D::SCISSOR_TEST);
552     isDitherEnabled = g3d->isEnabled(GraphicsContext3D::DITHER);
553     g3d->disable(GraphicsContext3D::DITHER);
554
555     g3d->clear(mask);
556
557     if (initColor) {
558         g3d->clearColor(colorClearValue[0], colorClearValue[1], colorClearValue[2], colorClearValue[3]);
559         g3d->colorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
560     }
561     if (initDepth) {
562         g3d->clearDepth(depthClearValue);
563         g3d->depthMask(depthMask);
564     }
565     if (initStencil) {
566         g3d->clearStencil(stencilClearValue);
567         g3d->stencilMask(stencilMask);
568     }
569     if (isScissorEnabled)
570         g3d->enable(GraphicsContext3D::SCISSOR_TEST);
571     else
572         g3d->disable(GraphicsContext3D::SCISSOR_TEST);
573     if (isDitherEnabled)
574         g3d->enable(GraphicsContext3D::DITHER);
575     else
576         g3d->disable(GraphicsContext3D::DITHER);
577
578     for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
579         GC3Denum attachmentType = it->key;
580         WebGLAttachment* attachment = it->value.get();
581         GC3Dbitfield bits = GraphicsContext3D::getClearBitsByAttachmentType(attachmentType);
582         if (bits & mask)
583             attachment->setInitialized();
584     }
585     return true;
586 }
587
588 bool WebGLFramebuffer::isBound() const
589 {
590     return (context()->m_framebufferBinding.get() == this);
591 }
592
593 void WebGLFramebuffer::drawBuffers(const Vector<GC3Denum>& bufs)
594 {
595     m_drawBuffers = bufs;
596     m_filteredDrawBuffers.resize(m_drawBuffers.size());
597     for (size_t i = 0; i < m_filteredDrawBuffers.size(); ++i)
598         m_filteredDrawBuffers[i] = GraphicsContext3D::NONE;
599     drawBuffersIfNecessary(true);
600 }
601
602 void WebGLFramebuffer::drawBuffersIfNecessary(bool force)
603 {
604     if (!context()->m_extDrawBuffers)
605         return;
606     bool reset = force;
607     // This filtering works around graphics driver bugs on Mac OS X.
608     for (size_t i = 0; i < m_drawBuffers.size(); ++i) {
609         if (m_drawBuffers[i] != GraphicsContext3D::NONE && getAttachment(m_drawBuffers[i])) {
610             if (m_filteredDrawBuffers[i] != m_drawBuffers[i]) {
611                 m_filteredDrawBuffers[i] = m_drawBuffers[i];
612                 reset = true;
613             }
614         } else {
615             if (m_filteredDrawBuffers[i] != GraphicsContext3D::NONE) {
616                 m_filteredDrawBuffers[i] = GraphicsContext3D::NONE;
617                 reset = true;
618             }
619         }
620     }
621     if (reset) {
622         context()->graphicsContext3D()->getExtensions()->drawBuffersEXT(
623             m_filteredDrawBuffers.size(), m_filteredDrawBuffers.data());
624     }
625 }
626
627 GC3Denum WebGLFramebuffer::getDrawBuffer(GC3Denum drawBuffer)
628 {
629     int index = static_cast<int>(drawBuffer - Extensions3D::DRAW_BUFFER0_EXT);
630     ASSERT(index >= 0);
631     if (index < static_cast<int>(m_drawBuffers.size()))
632         return m_drawBuffers[index];
633     if (drawBuffer == Extensions3D::DRAW_BUFFER0_EXT)
634         return GraphicsContext3D::COLOR_ATTACHMENT0;
635     return GraphicsContext3D::NONE;
636 }
637
638 }
639
640 #endif // ENABLE(WEBGL)