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 "WebGLRenderingContext.h" 36 37namespace WebCore { 38 39namespace { 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 override; 53 virtual GC3Dsizei getHeight() const override; 54 virtual GC3Denum getFormat() const override; 55 virtual WebGLSharedObject* getObject() const override; 56 virtual bool isSharedObject(WebGLSharedObject*) const override; 57 virtual bool isValid() const override; 58 virtual bool isInitialized() const override; 59 virtual void setInitialized() override; 60 virtual void onDetached(GraphicsContext3D*) override; 61 virtual void attach(GraphicsContext3D*, GC3Denum attachment) override; 62 virtual void unattach(GraphicsContext3D*, GC3Denum attachment) override; 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 override; 147 virtual GC3Dsizei getHeight() const override; 148 virtual GC3Denum getFormat() const override; 149 virtual WebGLSharedObject* getObject() const override; 150 virtual bool isSharedObject(WebGLSharedObject*) const override; 151 virtual bool isValid() const override; 152 virtual bool isInitialized() const override; 153 virtual void setInitialized() override; 154 virtual void onDetached(GraphicsContext3D*) override; 155 virtual void attach(GraphicsContext3D*, GC3Denum attachment) override; 156 virtual 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 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 264WebGLFramebuffer::WebGLAttachment::WebGLAttachment() 265{ 266} 267 268WebGLFramebuffer::WebGLAttachment::~WebGLAttachment() 269{ 270} 271 272PassRefPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContext* ctx) 273{ 274 return adoptRef(new WebGLFramebuffer(ctx)); 275} 276 277WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContext* ctx) 278 : WebGLContextObject(ctx) 279 , m_hasEverBeenBound(false) 280{ 281 setObject(ctx->graphicsContext3D()->createFramebuffer()); 282} 283 284WebGLFramebuffer::~WebGLFramebuffer() 285{ 286 deleteObject(0); 287} 288 289void 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 302void 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 315void 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 323WebGLSharedObject* 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 331WebGLFramebuffer::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 337void 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 363void 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 387GC3Dsizei 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 398GC3Dsizei 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 409GC3Denum 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 419GC3Denum 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 476bool 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 485bool 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 493void 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 501bool 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 588bool WebGLFramebuffer::isBound() const 589{ 590 return (context()->m_framebufferBinding.get() == this); 591} 592 593void 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 602void WebGLFramebuffer::drawBuffersIfNecessary(bool force) 603{ 604 if (!context()->m_webglDrawBuffers) 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 627GC3Denum 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) 641