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