1 /* 2 * Copyright (C) 2009 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 28 #include "core/html/canvas/WebGLFramebuffer.h" 29 30 #include "core/html/canvas/WebGLRenderingContextBase.h" 31 #include "platform/NotImplemented.h" 32 33 namespace blink { 34 35 namespace { 36 37 Platform3DObject objectOrZero(WebGLObject* object) 38 { 39 return object ? object->object() : 0; 40 } 41 42 class WebGLRenderbufferAttachment FINAL : public WebGLFramebuffer::WebGLAttachment { 43 public: 44 static PassRefPtrWillBeRawPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLRenderbuffer*); 45 46 virtual void trace(Visitor*) OVERRIDE; 47 48 private: 49 explicit WebGLRenderbufferAttachment(WebGLRenderbuffer*); 50 WebGLRenderbufferAttachment() { } 51 52 virtual GLsizei width() const OVERRIDE; 53 virtual GLsizei height() const OVERRIDE; 54 virtual GLenum format() const OVERRIDE; 55 virtual GLenum type() const OVERRIDE; 56 virtual WebGLSharedObject* object() const OVERRIDE; 57 virtual bool isSharedObject(WebGLSharedObject*) const OVERRIDE; 58 virtual bool valid() const OVERRIDE; 59 virtual void onDetached(blink::WebGraphicsContext3D*) OVERRIDE; 60 virtual void attach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE; 61 virtual void unattach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE; 62 63 RefPtrWillBeMember<WebGLRenderbuffer> m_renderbuffer; 64 }; 65 66 PassRefPtrWillBeRawPtr<WebGLFramebuffer::WebGLAttachment> WebGLRenderbufferAttachment::create(WebGLRenderbuffer* renderbuffer) 67 { 68 return adoptRefWillBeNoop(new WebGLRenderbufferAttachment(renderbuffer)); 69 } 70 71 void WebGLRenderbufferAttachment::trace(Visitor* visitor) 72 { 73 visitor->trace(m_renderbuffer); 74 WebGLFramebuffer::WebGLAttachment::trace(visitor); 75 } 76 77 WebGLRenderbufferAttachment::WebGLRenderbufferAttachment(WebGLRenderbuffer* renderbuffer) 78 : m_renderbuffer(renderbuffer) 79 { 80 } 81 82 GLsizei WebGLRenderbufferAttachment::width() const 83 { 84 return m_renderbuffer->width(); 85 } 86 87 GLsizei WebGLRenderbufferAttachment::height() const 88 { 89 return m_renderbuffer->height(); 90 } 91 92 GLenum WebGLRenderbufferAttachment::format() const 93 { 94 GLenum format = m_renderbuffer->internalFormat(); 95 if (format == GL_DEPTH_STENCIL_OES 96 && m_renderbuffer->emulatedStencilBuffer() 97 && m_renderbuffer->emulatedStencilBuffer()->internalFormat() != GL_STENCIL_INDEX8) { 98 return 0; 99 } 100 return format; 101 } 102 103 WebGLSharedObject* WebGLRenderbufferAttachment::object() const 104 { 105 return m_renderbuffer->object() ? m_renderbuffer.get() : 0; 106 } 107 108 bool WebGLRenderbufferAttachment::isSharedObject(WebGLSharedObject* object) const 109 { 110 return object == m_renderbuffer; 111 } 112 113 bool WebGLRenderbufferAttachment::valid() const 114 { 115 return m_renderbuffer->object(); 116 } 117 118 void WebGLRenderbufferAttachment::onDetached(blink::WebGraphicsContext3D* context) 119 { 120 m_renderbuffer->onDetached(context); 121 } 122 123 void WebGLRenderbufferAttachment::attach(blink::WebGraphicsContext3D* context, GLenum attachment) 124 { 125 Platform3DObject object = objectOrZero(m_renderbuffer.get()); 126 if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL && m_renderbuffer->emulatedStencilBuffer()) { 127 context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, object); 128 context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, objectOrZero(m_renderbuffer->emulatedStencilBuffer())); 129 } else { 130 context->framebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, object); 131 } 132 } 133 134 void WebGLRenderbufferAttachment::unattach(blink::WebGraphicsContext3D* context, GLenum attachment) 135 { 136 if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) { 137 context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); 138 context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); 139 } else { 140 context->framebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, 0); 141 } 142 } 143 144 GLenum WebGLRenderbufferAttachment::type() const 145 { 146 notImplemented(); 147 return 0; 148 } 149 150 class WebGLTextureAttachment FINAL : public WebGLFramebuffer::WebGLAttachment { 151 public: 152 static PassRefPtrWillBeRawPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLTexture*, GLenum target, GLint level); 153 154 virtual void trace(Visitor*) OVERRIDE; 155 156 private: 157 WebGLTextureAttachment(WebGLTexture*, GLenum target, GLint level); 158 WebGLTextureAttachment() { } 159 160 virtual GLsizei width() const OVERRIDE; 161 virtual GLsizei height() const OVERRIDE; 162 virtual GLenum format() const OVERRIDE; 163 virtual GLenum type() const OVERRIDE; 164 virtual WebGLSharedObject* object() const OVERRIDE; 165 virtual bool isSharedObject(WebGLSharedObject*) const OVERRIDE; 166 virtual bool valid() const OVERRIDE; 167 virtual void onDetached(blink::WebGraphicsContext3D*) OVERRIDE; 168 virtual void attach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE; 169 virtual void unattach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE; 170 171 RefPtrWillBeMember<WebGLTexture> m_texture; 172 GLenum m_target; 173 GLint m_level; 174 }; 175 176 PassRefPtrWillBeRawPtr<WebGLFramebuffer::WebGLAttachment> WebGLTextureAttachment::create(WebGLTexture* texture, GLenum target, GLint level) 177 { 178 return adoptRefWillBeNoop(new WebGLTextureAttachment(texture, target, level)); 179 } 180 181 void WebGLTextureAttachment::trace(Visitor* visitor) 182 { 183 visitor->trace(m_texture); 184 WebGLFramebuffer::WebGLAttachment::trace(visitor); 185 } 186 187 WebGLTextureAttachment::WebGLTextureAttachment(WebGLTexture* texture, GLenum target, GLint level) 188 : m_texture(texture) 189 , m_target(target) 190 , m_level(level) 191 { 192 } 193 194 GLsizei WebGLTextureAttachment::width() const 195 { 196 return m_texture->getWidth(m_target, m_level); 197 } 198 199 GLsizei WebGLTextureAttachment::height() const 200 { 201 return m_texture->getHeight(m_target, m_level); 202 } 203 204 GLenum WebGLTextureAttachment::format() const 205 { 206 return m_texture->getInternalFormat(m_target, m_level); 207 } 208 209 WebGLSharedObject* WebGLTextureAttachment::object() const 210 { 211 return m_texture->object() ? m_texture.get() : 0; 212 } 213 214 bool WebGLTextureAttachment::isSharedObject(WebGLSharedObject* object) const 215 { 216 return object == m_texture; 217 } 218 219 bool WebGLTextureAttachment::valid() const 220 { 221 return m_texture->object(); 222 } 223 224 void WebGLTextureAttachment::onDetached(blink::WebGraphicsContext3D* context) 225 { 226 m_texture->onDetached(context); 227 } 228 229 void WebGLTextureAttachment::attach(blink::WebGraphicsContext3D* context, GLenum attachment) 230 { 231 Platform3DObject object = objectOrZero(m_texture.get()); 232 context->framebufferTexture2D(GL_FRAMEBUFFER, attachment, m_target, object, m_level); 233 } 234 235 void WebGLTextureAttachment::unattach(blink::WebGraphicsContext3D* context, GLenum attachment) 236 { 237 if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) { 238 context->framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_target, 0, m_level); 239 context->framebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, m_target, 0, m_level); 240 } else { 241 context->framebufferTexture2D(GL_FRAMEBUFFER, attachment, m_target, 0, m_level); 242 } 243 } 244 245 GLenum WebGLTextureAttachment::type() const 246 { 247 return m_texture->getType(m_target, m_level); 248 } 249 250 bool isColorRenderable(GLenum internalformat) 251 { 252 switch (internalformat) { 253 case GL_RGBA4: 254 case GL_RGB5_A1: 255 case GL_RGB565: 256 return true; 257 default: 258 return false; 259 } 260 } 261 262 } // anonymous namespace 263 264 WebGLFramebuffer::WebGLAttachment::WebGLAttachment() 265 { 266 } 267 268 WebGLFramebuffer::WebGLAttachment::~WebGLAttachment() 269 { 270 } 271 272 PassRefPtrWillBeRawPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContextBase* ctx) 273 { 274 return adoptRefWillBeNoop(new WebGLFramebuffer(ctx)); 275 } 276 277 WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContextBase* ctx) 278 : WebGLContextObject(ctx) 279 , m_hasEverBeenBound(false) 280 { 281 setObject(ctx->webContext()->createFramebuffer()); 282 } 283 284 WebGLFramebuffer::~WebGLFramebuffer() 285 { 286 // Delete the platform framebuffer resource. Explicit detachment 287 // is for the benefit of Oilpan, where the framebuffer object 288 // isn't detached when it and the WebGLRenderingContextBase object 289 // it is registered with are both finalized. Without Oilpan, the 290 // object will have been detached. 291 // 292 // To keep the code regular, the trivial detach()ment is always 293 // performed. 294 detachAndDeleteObject(); 295 } 296 297 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum attachment, GLenum texTarget, WebGLTexture* texture, GLint level) 298 { 299 ASSERT(isBound()); 300 removeAttachmentFromBoundFramebuffer(attachment); 301 if (!object()) 302 return; 303 if (texture && texture->object()) { 304 m_attachments.add(attachment, WebGLTextureAttachment::create(texture, texTarget, level)); 305 drawBuffersIfNecessary(false); 306 texture->onAttached(); 307 } 308 } 309 310 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum attachment, WebGLRenderbuffer* renderbuffer) 311 { 312 ASSERT(isBound()); 313 removeAttachmentFromBoundFramebuffer(attachment); 314 if (!object()) 315 return; 316 if (renderbuffer && renderbuffer->object()) { 317 m_attachments.add(attachment, WebGLRenderbufferAttachment::create(renderbuffer)); 318 drawBuffersIfNecessary(false); 319 renderbuffer->onAttached(); 320 } 321 } 322 323 void WebGLFramebuffer::attach(GLenum attachment, GLenum attachmentPoint) 324 { 325 ASSERT(isBound()); 326 WebGLAttachment* attachmentObject = getAttachment(attachment); 327 if (attachmentObject) 328 attachmentObject->attach(context()->webContext(), attachmentPoint); 329 } 330 331 WebGLSharedObject* WebGLFramebuffer::getAttachmentObject(GLenum attachment) const 332 { 333 if (!object()) 334 return 0; 335 WebGLAttachment* attachmentObject = getAttachment(attachment); 336 return attachmentObject ? attachmentObject->object() : 0; 337 } 338 339 bool WebGLFramebuffer::isAttachmentComplete(WebGLAttachment* attachedObject, GLenum attachment, const char** reason) const 340 { 341 ASSERT(attachedObject && attachedObject->valid()); 342 ASSERT(reason); 343 344 GLenum internalformat = attachedObject->format(); 345 WebGLSharedObject* object = attachedObject->object(); 346 ASSERT(object && (object->isTexture() || object->isRenderbuffer())); 347 348 if (attachment == GL_DEPTH_ATTACHMENT) { 349 if (object->isRenderbuffer()) { 350 if (internalformat != GL_DEPTH_COMPONENT16) { 351 *reason = "the internalformat of the attached renderbuffer is not DEPTH_COMPONENT16"; 352 return false; 353 } 354 } else if (object->isTexture()) { 355 GLenum type = attachedObject->type(); 356 if (!(context()->extensionEnabled(WebGLDepthTextureName) && internalformat == GL_DEPTH_COMPONENT 357 && (type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT))) { 358 *reason = "the attached texture is not a depth texture"; 359 return false; 360 } 361 } 362 } else if (attachment == GL_STENCIL_ATTACHMENT) { 363 // Depend on the underlying GL drivers to check stencil textures 364 // and check renderbuffer type here only. 365 if (object->isRenderbuffer()) { 366 if (internalformat != GL_STENCIL_INDEX8) { 367 *reason = "the internalformat of the attached renderbuffer is not STENCIL_INDEX8"; 368 return false; 369 } 370 } 371 } else if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) { 372 if (object->isRenderbuffer()) { 373 if (internalformat != GL_DEPTH_STENCIL_OES) { 374 *reason = "the internalformat of the attached renderbuffer is not DEPTH_STENCIL"; 375 return false; 376 } 377 } else if (object->isTexture()) { 378 GLenum type = attachedObject->type(); 379 if (!(context()->extensionEnabled(WebGLDepthTextureName) && internalformat == GL_DEPTH_STENCIL_OES 380 && type == GL_UNSIGNED_INT_24_8_OES)) { 381 *reason = "the attached texture is not a DEPTH_STENCIL texture"; 382 return false; 383 } 384 } 385 } else if (attachment == GL_COLOR_ATTACHMENT0 386 || (context()->extensionEnabled(WebGLDrawBuffersName) && attachment > GL_COLOR_ATTACHMENT0 387 && attachment < static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + context()->maxColorAttachments()))) { 388 if (object->isRenderbuffer()) { 389 if (!isColorRenderable(internalformat)) { 390 *reason = "the internalformat of the attached renderbuffer is not color-renderable"; 391 return false; 392 } 393 } else if (object->isTexture()) { 394 GLenum type = attachedObject->type(); 395 if (internalformat != GL_RGBA && internalformat != GL_RGB) { 396 *reason = "the internalformat of the attached texture is not color-renderable"; 397 return false; 398 } 399 // TODO: WEBGL_color_buffer_float and EXT_color_buffer_half_float extensions have not been implemented in 400 // WebGL yet. It would be better to depend on the underlying GL drivers to check on rendering to floating point textures 401 // and add the check back to WebGL when above two extensions are implemented. 402 // Assume UNSIGNED_BYTE is renderable here without the need to explicitly check if GL_OES_rgb8_rgba8 extension is supported. 403 if (type != GL_UNSIGNED_BYTE 404 && type != GL_UNSIGNED_SHORT_5_6_5 405 && type != GL_UNSIGNED_SHORT_4_4_4_4 406 && type != GL_UNSIGNED_SHORT_5_5_5_1 407 && !(type == GL_FLOAT && context()->extensionEnabled(OESTextureFloatName)) 408 && !(type == GL_HALF_FLOAT_OES && context()->extensionEnabled(OESTextureHalfFloatName))) { 409 *reason = "unsupported type: The attached texture is not supported to be rendered to"; 410 return false; 411 } 412 } 413 } else { 414 *reason = "unknown framebuffer attachment point"; 415 return false; 416 } 417 418 if (!attachedObject->width() || !attachedObject->height()) { 419 *reason = "attachment has a 0 dimension"; 420 return false; 421 } 422 return true; 423 } 424 425 WebGLFramebuffer::WebGLAttachment* WebGLFramebuffer::getAttachment(GLenum attachment) const 426 { 427 const AttachmentMap::const_iterator it = m_attachments.find(attachment); 428 return (it != m_attachments.end()) ? it->value.get() : 0; 429 } 430 431 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GLenum attachment) 432 { 433 ASSERT(isBound()); 434 if (!object()) 435 return; 436 437 WebGLAttachment* attachmentObject = getAttachment(attachment); 438 if (attachmentObject) { 439 attachmentObject->onDetached(context()->webContext()); 440 m_attachments.remove(attachment); 441 drawBuffersIfNecessary(false); 442 switch (attachment) { 443 case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL: 444 attach(GL_DEPTH_ATTACHMENT, GL_DEPTH_ATTACHMENT); 445 attach(GL_STENCIL_ATTACHMENT, GL_STENCIL_ATTACHMENT); 446 break; 447 case GL_DEPTH_ATTACHMENT: 448 attach(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL, GL_DEPTH_ATTACHMENT); 449 break; 450 case GL_STENCIL_ATTACHMENT: 451 attach(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL, GL_STENCIL_ATTACHMENT); 452 break; 453 } 454 } 455 } 456 457 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(WebGLSharedObject* attachment) 458 { 459 ASSERT(isBound()); 460 if (!object()) 461 return; 462 if (!attachment) 463 return; 464 465 bool checkMore = true; 466 while (checkMore) { 467 checkMore = false; 468 for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) { 469 WebGLAttachment* attachmentObject = it->value.get(); 470 if (attachmentObject->isSharedObject(attachment)) { 471 GLenum attachmentType = it->key; 472 attachmentObject->unattach(context()->webContext(), attachmentType); 473 removeAttachmentFromBoundFramebuffer(attachmentType); 474 checkMore = true; 475 break; 476 } 477 } 478 } 479 } 480 481 GLenum WebGLFramebuffer::colorBufferFormat() const 482 { 483 if (!object()) 484 return 0; 485 WebGLAttachment* attachment = getAttachment(GL_COLOR_ATTACHMENT0); 486 if (!attachment) 487 return 0; 488 return attachment->format(); 489 } 490 491 GLenum WebGLFramebuffer::checkStatus(const char** reason) const 492 { 493 unsigned count = 0; 494 GLsizei width = 0, height = 0; 495 bool haveDepth = false; 496 bool haveStencil = false; 497 bool haveDepthStencil = false; 498 for (AttachmentMap::const_iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) { 499 WebGLAttachment* attachment = it->value.get(); 500 if (!isAttachmentComplete(attachment, it->key, reason)) 501 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 502 if (!attachment->valid()) { 503 *reason = "attachment is not valid"; 504 return GL_FRAMEBUFFER_UNSUPPORTED; 505 } 506 if (!attachment->format()) { 507 *reason = "attachment is an unsupported format"; 508 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 509 } 510 switch (it->key) { 511 case GL_DEPTH_ATTACHMENT: 512 haveDepth = true; 513 break; 514 case GL_STENCIL_ATTACHMENT: 515 haveStencil = true; 516 break; 517 case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL: 518 haveDepthStencil = true; 519 break; 520 } 521 if (!count) { 522 width = attachment->width(); 523 height = attachment->height(); 524 } else { 525 if (width != attachment->width() || height != attachment->height()) { 526 *reason = "attachments do not have the same dimensions"; 527 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; 528 } 529 } 530 ++count; 531 } 532 if (!count) { 533 *reason = "no attachments"; 534 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; 535 } 536 if (!width || !height) { 537 *reason = "framebuffer has a 0 dimension"; 538 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 539 } 540 // WebGL specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments. 541 if ((haveDepthStencil && (haveDepth || haveStencil)) || (haveDepth && haveStencil)) { 542 *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments"; 543 return GL_FRAMEBUFFER_UNSUPPORTED; 544 } 545 return GL_FRAMEBUFFER_COMPLETE; 546 } 547 548 bool WebGLFramebuffer::onAccess(blink::WebGraphicsContext3D* context3d, const char** reason) 549 { 550 if (checkStatus(reason) != GL_FRAMEBUFFER_COMPLETE) 551 return false; 552 return true; 553 } 554 555 bool WebGLFramebuffer::hasStencilBuffer() const 556 { 557 WebGLAttachment* attachment = getAttachment(GL_STENCIL_ATTACHMENT); 558 if (!attachment) 559 attachment = getAttachment(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL); 560 return attachment && attachment->valid(); 561 } 562 563 void WebGLFramebuffer::deleteObjectImpl(blink::WebGraphicsContext3D* context3d, Platform3DObject object) 564 { 565 #if !ENABLE(OILPAN) 566 // With Oilpan, both the AttachmentMap and its WebGLAttachment objects are 567 // GCed objects and cannot be accessed, as they may have been finalized 568 // already during the same GC sweep. 569 // 570 // The WebGLAttachment-derived classes instead handle detachment 571 // on their own when finalizing, so the explicit notification is 572 // not needed. 573 for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) 574 it->value->onDetached(context3d); 575 #endif 576 577 context3d->deleteFramebuffer(object); 578 } 579 580 bool WebGLFramebuffer::isBound() const 581 { 582 return (context()->m_framebufferBinding.get() == this); 583 } 584 585 void WebGLFramebuffer::drawBuffers(const Vector<GLenum>& bufs) 586 { 587 m_drawBuffers = bufs; 588 m_filteredDrawBuffers.resize(m_drawBuffers.size()); 589 for (size_t i = 0; i < m_filteredDrawBuffers.size(); ++i) 590 m_filteredDrawBuffers[i] = GL_NONE; 591 drawBuffersIfNecessary(true); 592 } 593 594 void WebGLFramebuffer::drawBuffersIfNecessary(bool force) 595 { 596 if (!context()->extensionEnabled(WebGLDrawBuffersName)) 597 return; 598 bool reset = force; 599 // This filtering works around graphics driver bugs on Mac OS X. 600 for (size_t i = 0; i < m_drawBuffers.size(); ++i) { 601 if (m_drawBuffers[i] != GL_NONE && getAttachment(m_drawBuffers[i])) { 602 if (m_filteredDrawBuffers[i] != m_drawBuffers[i]) { 603 m_filteredDrawBuffers[i] = m_drawBuffers[i]; 604 reset = true; 605 } 606 } else { 607 if (m_filteredDrawBuffers[i] != GL_NONE) { 608 m_filteredDrawBuffers[i] = GL_NONE; 609 reset = true; 610 } 611 } 612 } 613 if (reset) { 614 context()->webContext()->drawBuffersEXT( 615 m_filteredDrawBuffers.size(), m_filteredDrawBuffers.data()); 616 } 617 } 618 619 GLenum WebGLFramebuffer::getDrawBuffer(GLenum drawBuffer) 620 { 621 int index = static_cast<int>(drawBuffer - GL_DRAW_BUFFER0_EXT); 622 ASSERT(index >= 0); 623 if (index < static_cast<int>(m_drawBuffers.size())) 624 return m_drawBuffers[index]; 625 if (drawBuffer == GL_DRAW_BUFFER0_EXT) 626 return GL_COLOR_ATTACHMENT0; 627 return GL_NONE; 628 } 629 630 void WebGLFramebuffer::trace(Visitor* visitor) 631 { 632 #if ENABLE(OILPAN) 633 visitor->trace(m_attachments); 634 #endif 635 WebGLContextObject::trace(visitor); 636 } 637 638 } 639