Remove "virtual" from all lines that have both "virtual" and "override".
[WebKit-https.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 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 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 "Extensions3D.h"
33 #include "WebGLContextGroup.h"
34 #include "WebGLDrawBuffers.h"
35 #include "WebGLRenderingContextBase.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 Ref<WebGLFramebuffer::WebGLAttachment> create(WebGLRenderbuffer*);
49
50     private:
51         WebGLRenderbufferAttachment(WebGLRenderbuffer*);
52         GC3Dsizei getWidth() const override;
53         GC3Dsizei getHeight() const override;
54         GC3Denum getFormat() const override;
55         WebGLSharedObject* getObject() const override;
56         bool isSharedObject(WebGLSharedObject*) const override;
57         bool isValid() const override;
58         bool isInitialized() const override;
59         void setInitialized() override;
60         void onDetached(GraphicsContext3D*) override;
61         void attach(GraphicsContext3D*, GC3Denum attachment) override;
62         void unattach(GraphicsContext3D*, GC3Denum attachment) override;
63
64         WebGLRenderbufferAttachment() { };
65
66         RefPtr<WebGLRenderbuffer> m_renderbuffer;
67     };
68
69     Ref<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 Ref<WebGLFramebuffer::WebGLAttachment> create(WebGLTexture*, GC3Denum target, GC3Dint level);
143
144     private:
145         WebGLTextureAttachment(WebGLTexture*, GC3Denum target, GC3Dint level);
146         GC3Dsizei getWidth() const override;
147         GC3Dsizei getHeight() const override;
148         GC3Denum getFormat() const override;
149         WebGLSharedObject* getObject() const override;
150         bool isSharedObject(WebGLSharedObject*) const override;
151         bool isValid() const override;
152         bool isInitialized() const override;
153         void setInitialized() override;
154         void onDetached(GraphicsContext3D*) override;
155         void attach(GraphicsContext3D*, GC3Denum attachment) override;
156         void unattach(GraphicsContext3D*, GC3Denum attachment) override;
157
158         WebGLTextureAttachment() { };
159
160         RefPtr<WebGLTexture> m_texture;
161         GC3Denum m_target;
162         GC3Dint m_level;
163     };
164
165     Ref<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 Ref<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContextBase* ctx)
273 {
274     return adoptRef(*new WebGLFramebuffer(ctx));
275 }
276
277 WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContextBase* 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     do {
373         checkMore = false;
374         for (auto& entry : m_attachments) {
375             WebGLAttachment* attachmentObject = entry.value.get();
376             if (attachmentObject->isSharedObject(attachment)) {
377                 GC3Denum attachmentType = entry.key;
378                 attachmentObject->unattach(context()->graphicsContext3D(), attachmentType);
379                 removeAttachmentFromBoundFramebuffer(attachmentType);
380                 checkMore = true;
381                 break;
382             }
383         }
384     } while (checkMore);
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 (auto& entry : m_attachments) {
427         WebGLAttachment* attachment = entry.value.get();
428         if (!isAttachmentComplete(attachment, entry.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         GC3Denum attachmentFormat = attachment->getFormat();
435
436         // Attaching an SRGB_EXT format attachment to a framebuffer is invalid.
437         if (attachmentFormat == Extensions3D::SRGB_EXT)
438             attachmentFormat = 0;
439
440         if (!attachmentFormat) {
441             *reason = "attachment is an unsupported format";
442             return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
443         }
444         switch (entry.key) {
445         case GraphicsContext3D::DEPTH_ATTACHMENT:
446             haveDepth = true;
447             break;
448         case GraphicsContext3D::STENCIL_ATTACHMENT:
449             haveStencil = true;
450             break;
451         case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
452             haveDepthStencil = true;
453             break;
454         }
455         if (!count) {
456             width = attachment->getWidth();
457             height = attachment->getHeight();
458         } else {
459             if (width != attachment->getWidth() || height != attachment->getHeight()) {
460                 *reason = "attachments do not have the same dimensions";
461                 return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
462             }
463         }
464         ++count;
465     }
466     if (!count) {
467         *reason = "no attachments";
468         return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
469     }
470     if (!width || !height) {
471         *reason = "framebuffer has a 0 dimension";
472         return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
473     }
474     // WebGL specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments.
475     if ((haveDepthStencil && (haveDepth || haveStencil)) || (haveDepth && haveStencil)) {
476         *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments";
477         return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
478     }
479     return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
480 }
481
482 bool WebGLFramebuffer::onAccess(GraphicsContext3D* context3d, bool needToInitializeAttachments, const char** reason)
483 {
484     if (checkStatus(reason) != GraphicsContext3D::FRAMEBUFFER_COMPLETE)
485         return false;
486     if (needToInitializeAttachments)
487         return initializeAttachments(context3d, reason);
488     return true;
489 }
490
491 bool WebGLFramebuffer::hasStencilBuffer() const
492 {
493     WebGLAttachment* attachment = getAttachment(GraphicsContext3D::STENCIL_ATTACHMENT);
494     if (!attachment)
495         attachment = getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT);
496     return attachment && attachment->isValid();
497 }
498
499 void WebGLFramebuffer::deleteObjectImpl(GraphicsContext3D* context3d, Platform3DObject object)
500 {
501     for (auto& attachment : m_attachments.values())
502         attachment->onDetached(context3d);
503
504     context3d->deleteFramebuffer(object);
505 }
506
507 bool WebGLFramebuffer::initializeAttachments(GraphicsContext3D* g3d, const char** reason)
508 {
509     ASSERT(object());
510     GC3Dbitfield mask = 0;
511
512     for (auto& entry : m_attachments) {
513         GC3Denum attachmentType = entry.key;
514         WebGLAttachment* attachment = entry.value.get();
515         if (!attachment->isInitialized())
516            mask |= GraphicsContext3D::getClearBitsByAttachmentType(attachmentType);
517     }
518     if (!mask)
519         return true;
520
521     // We only clear un-initialized renderbuffers when they are ready to be
522     // read, i.e., when the framebuffer is complete.
523     if (g3d->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
524         *reason = "framebuffer not complete";
525         return false;
526     }
527
528     bool initColor = mask & GraphicsContext3D::COLOR_BUFFER_BIT;
529     bool initDepth = mask & GraphicsContext3D::DEPTH_BUFFER_BIT;
530     bool initStencil = mask & GraphicsContext3D::STENCIL_BUFFER_BIT;
531
532     GC3Dfloat colorClearValue[] = {0, 0, 0, 0}, depthClearValue = 0;
533     GC3Dint stencilClearValue = 0;
534     GC3Dboolean colorMask[] = {0, 0, 0, 0}, depthMask = 0;
535     GC3Duint stencilMask = 0xffffffff;
536     GC3Dboolean isScissorEnabled = 0;
537     GC3Dboolean isDitherEnabled = 0;
538     if (initColor) {
539         g3d->getFloatv(GraphicsContext3D::COLOR_CLEAR_VALUE, colorClearValue);
540         g3d->getBooleanv(GraphicsContext3D::COLOR_WRITEMASK, colorMask);
541         g3d->clearColor(0, 0, 0, 0);
542         g3d->colorMask(true, true, true, true);
543     }
544     if (initDepth) {
545         g3d->getFloatv(GraphicsContext3D::DEPTH_CLEAR_VALUE, &depthClearValue);
546         g3d->getBooleanv(GraphicsContext3D::DEPTH_WRITEMASK, &depthMask);
547         g3d->clearDepth(1.0f);
548         g3d->depthMask(true);
549     }
550     if (initStencil) {
551         g3d->getIntegerv(GraphicsContext3D::STENCIL_CLEAR_VALUE, &stencilClearValue);
552         g3d->getIntegerv(GraphicsContext3D::STENCIL_WRITEMASK, reinterpret_cast<GC3Dint*>(&stencilMask));
553         g3d->clearStencil(0);
554         g3d->stencilMask(0xffffffff);
555     }
556     isScissorEnabled = g3d->isEnabled(GraphicsContext3D::SCISSOR_TEST);
557     g3d->disable(GraphicsContext3D::SCISSOR_TEST);
558     isDitherEnabled = g3d->isEnabled(GraphicsContext3D::DITHER);
559     g3d->disable(GraphicsContext3D::DITHER);
560
561     g3d->clear(mask);
562
563     if (initColor) {
564         g3d->clearColor(colorClearValue[0], colorClearValue[1], colorClearValue[2], colorClearValue[3]);
565         g3d->colorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
566     }
567     if (initDepth) {
568         g3d->clearDepth(depthClearValue);
569         g3d->depthMask(depthMask);
570     }
571     if (initStencil) {
572         g3d->clearStencil(stencilClearValue);
573         g3d->stencilMask(stencilMask);
574     }
575     if (isScissorEnabled)
576         g3d->enable(GraphicsContext3D::SCISSOR_TEST);
577     else
578         g3d->disable(GraphicsContext3D::SCISSOR_TEST);
579     if (isDitherEnabled)
580         g3d->enable(GraphicsContext3D::DITHER);
581     else
582         g3d->disable(GraphicsContext3D::DITHER);
583
584     for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
585         GC3Denum attachmentType = it->key;
586         WebGLAttachment* attachment = it->value.get();
587         GC3Dbitfield bits = GraphicsContext3D::getClearBitsByAttachmentType(attachmentType);
588         if (bits & mask)
589             attachment->setInitialized();
590     }
591     return true;
592 }
593
594 bool WebGLFramebuffer::isBound() const
595 {
596     return (context()->m_framebufferBinding.get() == this);
597 }
598
599 void WebGLFramebuffer::drawBuffers(const Vector<GC3Denum>& bufs)
600 {
601     m_drawBuffers = bufs;
602     m_filteredDrawBuffers.resize(m_drawBuffers.size());
603     for (auto& buffer : m_filteredDrawBuffers)
604         buffer = GraphicsContext3D::NONE;
605     drawBuffersIfNecessary(true);
606 }
607
608 void WebGLFramebuffer::drawBuffersIfNecessary(bool force)
609 {
610 #if ENABLE(WEBGL2)
611     if (!context()->m_webglDrawBuffers && !context()->isWebGL2())
612         return;
613 #endif
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] != GraphicsContext3D::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] != GraphicsContext3D::NONE) {
624                 m_filteredDrawBuffers[i] = GraphicsContext3D::NONE;
625                 reset = true;
626             }
627         }
628     }
629     if (reset) {
630         context()->graphicsContext3D()->getExtensions()->drawBuffersEXT(
631             m_filteredDrawBuffers.size(), m_filteredDrawBuffers.data());
632     }
633 }
634
635 GC3Denum WebGLFramebuffer::getDrawBuffer(GC3Denum drawBuffer)
636 {
637     int index = static_cast<int>(drawBuffer - Extensions3D::DRAW_BUFFER0_EXT);
638     ASSERT(index >= 0);
639     if (index < static_cast<int>(m_drawBuffers.size()))
640         return m_drawBuffers[index];
641     if (drawBuffer == Extensions3D::DRAW_BUFFER0_EXT)
642         return GraphicsContext3D::COLOR_ATTACHMENT0;
643     return GraphicsContext3D::NONE;
644 }
645
646 }
647
648 #endif // ENABLE(WEBGL)