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 "core/platform/NotImplemented.h" 32#include "core/platform/graphics/Extensions3D.h" 33 34namespace WebCore { 35 36namespace { 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 getWidth() const; 50 virtual GC3Dsizei getHeight() const; 51 virtual GC3Denum getFormat() const; 52 virtual GC3Denum getType() const; 53 virtual WebGLSharedObject* getObject() const; 54 virtual bool isSharedObject(WebGLSharedObject*) const; 55 virtual bool isValid() const; 56 virtual bool isInitialized() 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::getWidth() const 78 { 79 return m_renderbuffer->getWidth(); 80 } 81 82 GC3Dsizei WebGLRenderbufferAttachment::getHeight() const 83 { 84 return m_renderbuffer->getHeight(); 85 } 86 87 GC3Denum WebGLRenderbufferAttachment::getFormat() const 88 { 89 GC3Denum format = m_renderbuffer->getInternalFormat(); 90 if (format == GraphicsContext3D::DEPTH_STENCIL 91 && m_renderbuffer->emulatedStencilBuffer() 92 && m_renderbuffer->emulatedStencilBuffer()->getInternalFormat() != GraphicsContext3D::STENCIL_INDEX8) { 93 return 0; 94 } 95 return format; 96 } 97 98 WebGLSharedObject* WebGLRenderbufferAttachment::getObject() 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::isValid() const 109 { 110 return m_renderbuffer->object(); 111 } 112 113 bool WebGLRenderbufferAttachment::isInitialized() const 114 { 115 return m_renderbuffer->object() && m_renderbuffer->isInitialized(); 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 == GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT && m_renderbuffer->emulatedStencilBuffer()) { 133 context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, object); 134 context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, objectOrZero(m_renderbuffer->emulatedStencilBuffer())); 135 } else { 136 context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, attachment, GraphicsContext3D::RENDERBUFFER, object); 137 } 138 } 139 140 void WebGLRenderbufferAttachment::unattach(GraphicsContext3D* context, GC3Denum attachment) 141 { 142 if (attachment == GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT) { 143 context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, 0); 144 context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, 0); 145 } else 146 context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, attachment, GraphicsContext3D::RENDERBUFFER, 0); 147 } 148 149 GC3Denum WebGLRenderbufferAttachment::getType() const 150 { 151 notImplemented(); 152 return 0; 153 } 154 155 class WebGLTextureAttachment : public WebGLFramebuffer::WebGLAttachment { 156 public: 157 static PassRefPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLTexture*, GC3Denum target, GC3Dint level); 158 159 private: 160 WebGLTextureAttachment(WebGLTexture*, GC3Denum target, GC3Dint level); 161 virtual GC3Dsizei getWidth() const; 162 virtual GC3Dsizei getHeight() const; 163 virtual GC3Denum getFormat() const; 164 virtual GC3Denum getType() const; 165 virtual WebGLSharedObject* getObject() const; 166 virtual bool isSharedObject(WebGLSharedObject*) const; 167 virtual bool isValid() const; 168 virtual bool isInitialized() const; 169 virtual void setInitialized(); 170 virtual void onDetached(GraphicsContext3D*); 171 virtual void attach(GraphicsContext3D*, GC3Denum attachment); 172 virtual void unattach(GraphicsContext3D*, GC3Denum attachment); 173 174 WebGLTextureAttachment() { }; 175 176 RefPtr<WebGLTexture> m_texture; 177 GC3Denum m_target; 178 GC3Dint m_level; 179 }; 180 181 PassRefPtr<WebGLFramebuffer::WebGLAttachment> WebGLTextureAttachment::create(WebGLTexture* texture, GC3Denum target, GC3Dint level) 182 { 183 return adoptRef(new WebGLTextureAttachment(texture, target, level)); 184 } 185 186 WebGLTextureAttachment::WebGLTextureAttachment(WebGLTexture* texture, GC3Denum target, GC3Dint level) 187 : m_texture(texture) 188 , m_target(target) 189 , m_level(level) 190 { 191 } 192 193 GC3Dsizei WebGLTextureAttachment::getWidth() const 194 { 195 return m_texture->getWidth(m_target, m_level); 196 } 197 198 GC3Dsizei WebGLTextureAttachment::getHeight() const 199 { 200 return m_texture->getHeight(m_target, m_level); 201 } 202 203 GC3Denum WebGLTextureAttachment::getFormat() const 204 { 205 return m_texture->getInternalFormat(m_target, m_level); 206 } 207 208 WebGLSharedObject* WebGLTextureAttachment::getObject() const 209 { 210 return m_texture->object() ? m_texture.get() : 0; 211 } 212 213 bool WebGLTextureAttachment::isSharedObject(WebGLSharedObject* object) const 214 { 215 return object == m_texture; 216 } 217 218 bool WebGLTextureAttachment::isValid() const 219 { 220 return m_texture->object(); 221 } 222 223 bool WebGLTextureAttachment::isInitialized() const 224 { 225 // Textures are assumed to be initialized. 226 return true; 227 } 228 229 void WebGLTextureAttachment::setInitialized() 230 { 231 // Textures are assumed to be initialized. 232 } 233 234 void WebGLTextureAttachment::onDetached(GraphicsContext3D* context) 235 { 236 m_texture->onDetached(context); 237 } 238 239 void WebGLTextureAttachment::attach(GraphicsContext3D* context, GC3Denum attachment) 240 { 241 Platform3DObject object = objectOrZero(m_texture.get()); 242 context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, attachment, m_target, object, m_level); 243 } 244 245 void WebGLTextureAttachment::unattach(GraphicsContext3D* context, GC3Denum attachment) 246 { 247 if (attachment == GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT) { 248 context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, m_target, 0, m_level); 249 context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, m_target, 0, m_level); 250 } else 251 context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, attachment, m_target, 0, m_level); 252 } 253 254 GC3Denum WebGLTextureAttachment::getType() const 255 { 256 return m_texture->getType(m_target, m_level); 257 } 258 259 bool isColorRenderable(GC3Denum internalformat) 260 { 261 switch (internalformat) { 262 case GraphicsContext3D::RGBA4: 263 case GraphicsContext3D::RGB5_A1: 264 case GraphicsContext3D::RGB565: 265 return true; 266 default: 267 return false; 268 } 269 } 270 271} // anonymous namespace 272 273WebGLFramebuffer::WebGLAttachment::WebGLAttachment() 274{ 275} 276 277WebGLFramebuffer::WebGLAttachment::~WebGLAttachment() 278{ 279} 280 281PassRefPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContext* ctx) 282{ 283 return adoptRef(new WebGLFramebuffer(ctx)); 284} 285 286WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContext* ctx) 287 : WebGLContextObject(ctx) 288 , m_hasEverBeenBound(false) 289{ 290 ScriptWrappable::init(this); 291 setObject(ctx->graphicsContext3D()->createFramebuffer()); 292} 293 294WebGLFramebuffer::~WebGLFramebuffer() 295{ 296 deleteObject(0); 297} 298 299void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GC3Denum attachment, GC3Denum texTarget, WebGLTexture* texture, GC3Dint level) 300{ 301 ASSERT(isBound()); 302 removeAttachmentFromBoundFramebuffer(attachment); 303 if (!object()) 304 return; 305 if (texture && texture->object()) { 306 m_attachments.add(attachment, WebGLTextureAttachment::create(texture, texTarget, level)); 307 drawBuffersIfNecessary(false); 308 texture->onAttached(); 309 } 310} 311 312void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GC3Denum attachment, WebGLRenderbuffer* renderbuffer) 313{ 314 ASSERT(isBound()); 315 removeAttachmentFromBoundFramebuffer(attachment); 316 if (!object()) 317 return; 318 if (renderbuffer && renderbuffer->object()) { 319 m_attachments.add(attachment, WebGLRenderbufferAttachment::create(renderbuffer)); 320 drawBuffersIfNecessary(false); 321 renderbuffer->onAttached(); 322 } 323} 324 325void WebGLFramebuffer::attach(GC3Denum attachment, GC3Denum attachmentPoint) 326{ 327 ASSERT(isBound()); 328 WebGLAttachment* attachmentObject = getAttachment(attachment); 329 if (attachmentObject) 330 attachmentObject->attach(context()->graphicsContext3D(), attachmentPoint); 331} 332 333WebGLSharedObject* WebGLFramebuffer::getAttachmentObject(GC3Denum attachment) const 334{ 335 if (!object()) 336 return 0; 337 WebGLAttachment* attachmentObject = getAttachment(attachment); 338 return attachmentObject ? attachmentObject->getObject() : 0; 339} 340 341bool WebGLFramebuffer::isAttachmentComplete(WebGLAttachment* attachedObject, GC3Denum attachment, const char** reason) const 342{ 343 ASSERT(attachedObject && attachedObject->isValid()); 344 ASSERT(reason); 345 346 GC3Denum internalformat = attachedObject->getFormat(); 347 WebGLSharedObject* object = attachedObject->getObject(); 348 ASSERT(object && (object->isTexture() || object->isRenderbuffer())); 349 350 if (attachment == GraphicsContext3D::DEPTH_ATTACHMENT) { 351 if (object->isRenderbuffer()) { 352 if (internalformat != GraphicsContext3D::DEPTH_COMPONENT16) { 353 *reason = "the internalformat of the attached renderbuffer is not DEPTH_COMPONENT16"; 354 return false; 355 } 356 } else if (object->isTexture()) { 357 GC3Denum type = attachedObject->getType(); 358 if (!(context()->m_webglDepthTexture && internalformat == GraphicsContext3D::DEPTH_COMPONENT 359 && (type == GraphicsContext3D::UNSIGNED_SHORT || type == GraphicsContext3D::UNSIGNED_INT))) { 360 *reason = "the attached texture is not a depth texture"; 361 return false; 362 } 363 } 364 } else if (attachment == GraphicsContext3D::STENCIL_ATTACHMENT) { 365 // Depend on the underlying GL drivers to check stencil textures 366 // and check renderbuffer type here only. 367 if (object->isRenderbuffer()) { 368 if (internalformat != GraphicsContext3D::STENCIL_INDEX8) { 369 *reason = "the internalformat of the attached renderbuffer is not STENCIL_INDEX8"; 370 return false; 371 } 372 } 373 } else if (attachment == GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT) { 374 if (object->isRenderbuffer()) { 375 if (internalformat != GraphicsContext3D::DEPTH_STENCIL) { 376 *reason = "the internalformat of the attached renderbuffer is not DEPTH_STENCIL"; 377 return false; 378 } 379 } else if (object->isTexture()) { 380 GC3Denum type = attachedObject->getType(); 381 if (!(context()->m_webglDepthTexture && internalformat == GraphicsContext3D::DEPTH_STENCIL 382 && type == GraphicsContext3D::UNSIGNED_INT_24_8)) { 383 *reason = "the attached texture is not a DEPTH_STENCIL texture"; 384 return false; 385 } 386 } 387 } else if (attachment == GraphicsContext3D::COLOR_ATTACHMENT0 388 || (context()->m_webglDrawBuffers && attachment > GraphicsContext3D::COLOR_ATTACHMENT0 389 && attachment < static_cast<GC3Denum>(GraphicsContext3D::COLOR_ATTACHMENT0 + context()->getMaxColorAttachments()))) { 390 if (object->isRenderbuffer()) { 391 if (!isColorRenderable(internalformat)) { 392 *reason = "the internalformat of the attached renderbuffer is not color-renderable"; 393 return false; 394 } 395 } else if (object->isTexture()) { 396 GC3Denum type = attachedObject->getType(); 397 if (internalformat != GraphicsContext3D::RGBA && internalformat != GraphicsContext3D::RGB) { 398 *reason = "the internalformat of the attached texture is not color-renderable"; 399 return false; 400 } 401 // TODO: WEBGL_color_buffer_float and EXT_color_buffer_half_float extensions have not been implemented in 402 // WebGL yet. It would be better to depend on the underlying GL drivers to check on rendering to floating point textures 403 // and add the check back to WebGL when above two extensions are implemented. 404 // Assume UNSIGNED_BYTE is renderable here without the need to explicitly check if GL_OES_rgb8_rgba8 extension is supported. 405 if (type != GraphicsContext3D::UNSIGNED_BYTE 406 && type != GraphicsContext3D::UNSIGNED_SHORT_5_6_5 407 && type != GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4 408 && type != GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1 409 && !(type == GraphicsContext3D::FLOAT && context()->m_oesTextureFloat) 410 && !(type == GraphicsContext3D::HALF_FLOAT_OES && context()->m_oesTextureHalfFloat)) { 411 *reason = "unsupported type: The attached texture is not supported to be rendered to"; 412 return false; 413 } 414 } 415 } else { 416 *reason = "unknown framebuffer attachment point"; 417 return false; 418 } 419 420 if (!attachedObject->getWidth() || !attachedObject->getHeight()) { 421 *reason = "attachment has a 0 dimension"; 422 return false; 423 } 424 return true; 425} 426 427WebGLFramebuffer::WebGLAttachment* WebGLFramebuffer::getAttachment(GC3Denum attachment) const 428{ 429 const AttachmentMap::const_iterator it = m_attachments.find(attachment); 430 return (it != m_attachments.end()) ? it->value.get() : 0; 431} 432 433void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GC3Denum attachment) 434{ 435 ASSERT(isBound()); 436 if (!object()) 437 return; 438 439 WebGLAttachment* attachmentObject = getAttachment(attachment); 440 if (attachmentObject) { 441 attachmentObject->onDetached(context()->graphicsContext3D()); 442 m_attachments.remove(attachment); 443 drawBuffersIfNecessary(false); 444 switch (attachment) { 445 case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT: 446 attach(GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::DEPTH_ATTACHMENT); 447 attach(GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::STENCIL_ATTACHMENT); 448 break; 449 case GraphicsContext3D::DEPTH_ATTACHMENT: 450 attach(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT, GraphicsContext3D::DEPTH_ATTACHMENT); 451 break; 452 case GraphicsContext3D::STENCIL_ATTACHMENT: 453 attach(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT, GraphicsContext3D::STENCIL_ATTACHMENT); 454 break; 455 } 456 } 457} 458 459void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(WebGLSharedObject* attachment) 460{ 461 ASSERT(isBound()); 462 if (!object()) 463 return; 464 if (!attachment) 465 return; 466 467 bool checkMore = true; 468 while (checkMore) { 469 checkMore = false; 470 for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) { 471 WebGLAttachment* attachmentObject = it->value.get(); 472 if (attachmentObject->isSharedObject(attachment)) { 473 GC3Denum attachmentType = it->key; 474 attachmentObject->unattach(context()->graphicsContext3D(), attachmentType); 475 removeAttachmentFromBoundFramebuffer(attachmentType); 476 checkMore = true; 477 break; 478 } 479 } 480 } 481} 482 483GC3Dsizei WebGLFramebuffer::getColorBufferWidth() const 484{ 485 if (!object()) 486 return 0; 487 WebGLAttachment* attachment = getAttachment(GraphicsContext3D::COLOR_ATTACHMENT0); 488 if (!attachment) 489 return 0; 490 491 return attachment->getWidth(); 492} 493 494GC3Dsizei WebGLFramebuffer::getColorBufferHeight() const 495{ 496 if (!object()) 497 return 0; 498 WebGLAttachment* attachment = getAttachment(GraphicsContext3D::COLOR_ATTACHMENT0); 499 if (!attachment) 500 return 0; 501 502 return attachment->getHeight(); 503} 504 505GC3Denum WebGLFramebuffer::getColorBufferFormat() const 506{ 507 if (!object()) 508 return 0; 509 WebGLAttachment* attachment = getAttachment(GraphicsContext3D::COLOR_ATTACHMENT0); 510 if (!attachment) 511 return 0; 512 return attachment->getFormat(); 513} 514 515GC3Denum WebGLFramebuffer::checkStatus(const char** reason) const 516{ 517 unsigned int count = 0; 518 GC3Dsizei width = 0, height = 0; 519 bool haveDepth = false; 520 bool haveStencil = false; 521 bool haveDepthStencil = false; 522 for (AttachmentMap::const_iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) { 523 WebGLAttachment* attachment = it->value.get(); 524 if (!isAttachmentComplete(attachment, it->key, reason)) 525 return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 526 if (!attachment->isValid()) { 527 *reason = "attachment is not valid"; 528 return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED; 529 } 530 if (!attachment->getFormat()) { 531 *reason = "attachment is an unsupported format"; 532 return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 533 } 534 switch (it->key) { 535 case GraphicsContext3D::DEPTH_ATTACHMENT: 536 haveDepth = true; 537 break; 538 case GraphicsContext3D::STENCIL_ATTACHMENT: 539 haveStencil = true; 540 break; 541 case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT: 542 haveDepthStencil = true; 543 break; 544 } 545 if (!count) { 546 width = attachment->getWidth(); 547 height = attachment->getHeight(); 548 } else { 549 if (width != attachment->getWidth() || height != attachment->getHeight()) { 550 *reason = "attachments do not have the same dimensions"; 551 return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_DIMENSIONS; 552 } 553 } 554 ++count; 555 } 556 if (!count) { 557 *reason = "no attachments"; 558 return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; 559 } 560 if (!width || !height) { 561 *reason = "framebuffer has a 0 dimension"; 562 return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 563 } 564 // WebGL specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments. 565 if ((haveDepthStencil && (haveDepth || haveStencil)) || (haveDepth && haveStencil)) { 566 *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments"; 567 return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED; 568 } 569 return GraphicsContext3D::FRAMEBUFFER_COMPLETE; 570} 571 572bool WebGLFramebuffer::onAccess(GraphicsContext3D* context3d, const char** reason) 573{ 574 if (checkStatus(reason) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) 575 return false; 576 return true; 577} 578 579bool WebGLFramebuffer::hasStencilBuffer() const 580{ 581 WebGLAttachment* attachment = getAttachment(GraphicsContext3D::STENCIL_ATTACHMENT); 582 if (!attachment) 583 attachment = getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT); 584 return attachment && attachment->isValid(); 585} 586 587void WebGLFramebuffer::deleteObjectImpl(GraphicsContext3D* context3d, Platform3DObject object) 588{ 589 for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) 590 it->value->onDetached(context3d); 591 592 context3d->deleteFramebuffer(object); 593} 594 595bool WebGLFramebuffer::isBound() const 596{ 597 return (context()->m_framebufferBinding.get() == this); 598} 599 600void WebGLFramebuffer::drawBuffers(const Vector<GC3Denum>& bufs) 601{ 602 m_drawBuffers = bufs; 603 m_filteredDrawBuffers.resize(m_drawBuffers.size()); 604 for (size_t i = 0; i < m_filteredDrawBuffers.size(); ++i) 605 m_filteredDrawBuffers[i] = GraphicsContext3D::NONE; 606 drawBuffersIfNecessary(true); 607} 608 609void WebGLFramebuffer::drawBuffersIfNecessary(bool force) 610{ 611 if (!context()->m_webglDrawBuffers) 612 return; 613 bool reset = force; 614 // This filtering works around graphics driver bugs on Mac OS X. 615 for (size_t i = 0; i < m_drawBuffers.size(); ++i) { 616 if (m_drawBuffers[i] != GraphicsContext3D::NONE && getAttachment(m_drawBuffers[i])) { 617 if (m_filteredDrawBuffers[i] != m_drawBuffers[i]) { 618 m_filteredDrawBuffers[i] = m_drawBuffers[i]; 619 reset = true; 620 } 621 } else { 622 if (m_filteredDrawBuffers[i] != GraphicsContext3D::NONE) { 623 m_filteredDrawBuffers[i] = GraphicsContext3D::NONE; 624 reset = true; 625 } 626 } 627 } 628 if (reset) { 629 context()->graphicsContext3D()->getExtensions()->drawBuffersEXT( 630 m_filteredDrawBuffers.size(), m_filteredDrawBuffers.data()); 631 } 632} 633 634GC3Denum WebGLFramebuffer::getDrawBuffer(GC3Denum drawBuffer) 635{ 636 int index = static_cast<int>(drawBuffer - Extensions3D::DRAW_BUFFER0_EXT); 637 ASSERT(index >= 0); 638 if (index < static_cast<int>(m_drawBuffers.size())) 639 return m_drawBuffers[index]; 640 if (drawBuffer == Extensions3D::DRAW_BUFFER0_EXT) 641 return GraphicsContext3D::COLOR_ATTACHMENT0; 642 return GraphicsContext3D::NONE; 643} 644 645} 646