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