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 WebCore { 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 PassRefPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLRenderbuffer*); 45 46 private: 47 WebGLRenderbufferAttachment(WebGLRenderbuffer*); 48 virtual GLsizei width() const OVERRIDE; 49 virtual GLsizei height() const OVERRIDE; 50 virtual GLenum format() const OVERRIDE; 51 virtual GLenum type() const OVERRIDE; 52 virtual WebGLSharedObject* object() const OVERRIDE; 53 virtual bool isSharedObject(WebGLSharedObject*) const OVERRIDE; 54 virtual bool valid() const OVERRIDE; 55 virtual void onDetached(blink::WebGraphicsContext3D*) OVERRIDE; 56 virtual void attach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE; 57 virtual void unattach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE; 58 59 WebGLRenderbufferAttachment() { }; 60 61 RefPtr<WebGLRenderbuffer> m_renderbuffer; 62 }; 63 64 PassRefPtr<WebGLFramebuffer::WebGLAttachment> WebGLRenderbufferAttachment::create(WebGLRenderbuffer* renderbuffer) 65 { 66 return adoptRef(new WebGLRenderbufferAttachment(renderbuffer)); 67 } 68 69 WebGLRenderbufferAttachment::WebGLRenderbufferAttachment(WebGLRenderbuffer* renderbuffer) 70 : m_renderbuffer(renderbuffer) 71 { 72 } 73 74 GLsizei WebGLRenderbufferAttachment::width() const 75 { 76 return m_renderbuffer->width(); 77 } 78 79 GLsizei WebGLRenderbufferAttachment::height() const 80 { 81 return m_renderbuffer->height(); 82 } 83 84 GLenum WebGLRenderbufferAttachment::format() const 85 { 86 GLenum format = m_renderbuffer->internalFormat(); 87 if (format == GL_DEPTH_STENCIL_OES 88 && m_renderbuffer->emulatedStencilBuffer() 89 && m_renderbuffer->emulatedStencilBuffer()->internalFormat() != GL_STENCIL_INDEX8) { 90 return 0; 91 } 92 return format; 93 } 94 95 WebGLSharedObject* WebGLRenderbufferAttachment::object() const 96 { 97 return m_renderbuffer->object() ? m_renderbuffer.get() : 0; 98 } 99 100 bool WebGLRenderbufferAttachment::isSharedObject(WebGLSharedObject* object) const 101 { 102 return object == m_renderbuffer; 103 } 104 105 bool WebGLRenderbufferAttachment::valid() const 106 { 107 return m_renderbuffer->object(); 108 } 109 110 void WebGLRenderbufferAttachment::onDetached(blink::WebGraphicsContext3D* context) 111 { 112 m_renderbuffer->onDetached(context); 113 } 114 115 void WebGLRenderbufferAttachment::attach(blink::WebGraphicsContext3D* context, GLenum attachment) 116 { 117 Platform3DObject object = objectOrZero(m_renderbuffer.get()); 118 if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL && m_renderbuffer->emulatedStencilBuffer()) { 119 context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, object); 120 context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, objectOrZero(m_renderbuffer->emulatedStencilBuffer())); 121 } else { 122 context->framebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, object); 123 } 124 } 125 126 void WebGLRenderbufferAttachment::unattach(blink::WebGraphicsContext3D* context, GLenum attachment) 127 { 128 if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) { 129 context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); 130 context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); 131 } else { 132 context->framebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, 0); 133 } 134 } 135 136 GLenum WebGLRenderbufferAttachment::type() const 137 { 138 notImplemented(); 139 return 0; 140 } 141 142 class WebGLTextureAttachment FINAL : public WebGLFramebuffer::WebGLAttachment { 143 public: 144 static PassRefPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLTexture*, GLenum target, GLint level); 145 146 private: 147 WebGLTextureAttachment(WebGLTexture*, GLenum target, GLint level); 148 virtual GLsizei width() const OVERRIDE; 149 virtual GLsizei height() const OVERRIDE; 150 virtual GLenum format() const OVERRIDE; 151 virtual GLenum type() const OVERRIDE; 152 virtual WebGLSharedObject* object() const OVERRIDE; 153 virtual bool isSharedObject(WebGLSharedObject*) const OVERRIDE; 154 virtual bool valid() const OVERRIDE; 155 virtual void onDetached(blink::WebGraphicsContext3D*) OVERRIDE; 156 virtual void attach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE; 157 virtual void unattach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE; 158 159 WebGLTextureAttachment() { }; 160 161 RefPtr<WebGLTexture> m_texture; 162 GLenum m_target; 163 GLint m_level; 164 }; 165 166 PassRefPtr<WebGLFramebuffer::WebGLAttachment> WebGLTextureAttachment::create(WebGLTexture* texture, GLenum target, GLint level) 167 { 168 return adoptRef(new WebGLTextureAttachment(texture, target, level)); 169 } 170 171 WebGLTextureAttachment::WebGLTextureAttachment(WebGLTexture* texture, GLenum target, GLint level) 172 : m_texture(texture) 173 , m_target(target) 174 , m_level(level) 175 { 176 } 177 178 GLsizei WebGLTextureAttachment::width() const 179 { 180 return m_texture->getWidth(m_target, m_level); 181 } 182 183 GLsizei WebGLTextureAttachment::height() const 184 { 185 return m_texture->getHeight(m_target, m_level); 186 } 187 188 GLenum WebGLTextureAttachment::format() const 189 { 190 return m_texture->getInternalFormat(m_target, m_level); 191 } 192 193 WebGLSharedObject* WebGLTextureAttachment::object() const 194 { 195 return m_texture->object() ? m_texture.get() : 0; 196 } 197 198 bool WebGLTextureAttachment::isSharedObject(WebGLSharedObject* object) const 199 { 200 return object == m_texture; 201 } 202 203 bool WebGLTextureAttachment::valid() const 204 { 205 return m_texture->object(); 206 } 207 208 void WebGLTextureAttachment::onDetached(blink::WebGraphicsContext3D* context) 209 { 210 m_texture->onDetached(context); 211 } 212 213 void WebGLTextureAttachment::attach(blink::WebGraphicsContext3D* context, GLenum attachment) 214 { 215 Platform3DObject object = objectOrZero(m_texture.get()); 216 context->framebufferTexture2D(GL_FRAMEBUFFER, attachment, m_target, object, m_level); 217 } 218 219 void WebGLTextureAttachment::unattach(blink::WebGraphicsContext3D* context, GLenum attachment) 220 { 221 if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) { 222 context->framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_target, 0, m_level); 223 context->framebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, m_target, 0, m_level); 224 } else { 225 context->framebufferTexture2D(GL_FRAMEBUFFER, attachment, m_target, 0, m_level); 226 } 227 } 228 229 GLenum WebGLTextureAttachment::type() const 230 { 231 return m_texture->getType(m_target, m_level); 232 } 233 234 bool isColorRenderable(GLenum internalformat) 235 { 236 switch (internalformat) { 237 case GL_RGBA4: 238 case GL_RGB5_A1: 239 case GL_RGB565: 240 return true; 241 default: 242 return false; 243 } 244 } 245 246 } // anonymous namespace 247 248 WebGLFramebuffer::WebGLAttachment::WebGLAttachment() 249 { 250 } 251 252 WebGLFramebuffer::WebGLAttachment::~WebGLAttachment() 253 { 254 } 255 256 PassRefPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContextBase* ctx) 257 { 258 return adoptRef(new WebGLFramebuffer(ctx)); 259 } 260 261 WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContextBase* ctx) 262 : WebGLContextObject(ctx) 263 , m_hasEverBeenBound(false) 264 { 265 ScriptWrappable::init(this); 266 setObject(ctx->webContext()->createFramebuffer()); 267 } 268 269 WebGLFramebuffer::~WebGLFramebuffer() 270 { 271 deleteObject(0); 272 } 273 274 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum attachment, GLenum texTarget, WebGLTexture* texture, GLint level) 275 { 276 ASSERT(isBound()); 277 removeAttachmentFromBoundFramebuffer(attachment); 278 if (!object()) 279 return; 280 if (texture && texture->object()) { 281 m_attachments.add(attachment, WebGLTextureAttachment::create(texture, texTarget, level)); 282 drawBuffersIfNecessary(false); 283 texture->onAttached(); 284 } 285 } 286 287 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum attachment, WebGLRenderbuffer* renderbuffer) 288 { 289 ASSERT(isBound()); 290 removeAttachmentFromBoundFramebuffer(attachment); 291 if (!object()) 292 return; 293 if (renderbuffer && renderbuffer->object()) { 294 m_attachments.add(attachment, WebGLRenderbufferAttachment::create(renderbuffer)); 295 drawBuffersIfNecessary(false); 296 renderbuffer->onAttached(); 297 } 298 } 299 300 void WebGLFramebuffer::attach(GLenum attachment, GLenum attachmentPoint) 301 { 302 ASSERT(isBound()); 303 WebGLAttachment* attachmentObject = getAttachment(attachment); 304 if (attachmentObject) 305 attachmentObject->attach(context()->webContext(), attachmentPoint); 306 } 307 308 WebGLSharedObject* WebGLFramebuffer::getAttachmentObject(GLenum attachment) const 309 { 310 if (!object()) 311 return 0; 312 WebGLAttachment* attachmentObject = getAttachment(attachment); 313 return attachmentObject ? attachmentObject->object() : 0; 314 } 315 316 bool WebGLFramebuffer::isAttachmentComplete(WebGLAttachment* attachedObject, GLenum attachment, const char** reason) const 317 { 318 ASSERT(attachedObject && attachedObject->valid()); 319 ASSERT(reason); 320 321 GLenum internalformat = attachedObject->format(); 322 WebGLSharedObject* object = attachedObject->object(); 323 ASSERT(object && (object->isTexture() || object->isRenderbuffer())); 324 325 if (attachment == GL_DEPTH_ATTACHMENT) { 326 if (object->isRenderbuffer()) { 327 if (internalformat != GL_DEPTH_COMPONENT16) { 328 *reason = "the internalformat of the attached renderbuffer is not DEPTH_COMPONENT16"; 329 return false; 330 } 331 } else if (object->isTexture()) { 332 GLenum type = attachedObject->type(); 333 if (!(context()->extensionEnabled(WebGLDepthTextureName) && internalformat == GL_DEPTH_COMPONENT 334 && (type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT))) { 335 *reason = "the attached texture is not a depth texture"; 336 return false; 337 } 338 } 339 } else if (attachment == GL_STENCIL_ATTACHMENT) { 340 // Depend on the underlying GL drivers to check stencil textures 341 // and check renderbuffer type here only. 342 if (object->isRenderbuffer()) { 343 if (internalformat != GL_STENCIL_INDEX8) { 344 *reason = "the internalformat of the attached renderbuffer is not STENCIL_INDEX8"; 345 return false; 346 } 347 } 348 } else if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) { 349 if (object->isRenderbuffer()) { 350 if (internalformat != GL_DEPTH_STENCIL_OES) { 351 *reason = "the internalformat of the attached renderbuffer is not DEPTH_STENCIL"; 352 return false; 353 } 354 } else if (object->isTexture()) { 355 GLenum type = attachedObject->type(); 356 if (!(context()->extensionEnabled(WebGLDepthTextureName) && internalformat == GL_DEPTH_STENCIL_OES 357 && type == GL_UNSIGNED_INT_24_8_OES)) { 358 *reason = "the attached texture is not a DEPTH_STENCIL texture"; 359 return false; 360 } 361 } 362 } else if (attachment == GL_COLOR_ATTACHMENT0 363 || (context()->extensionEnabled(WebGLDrawBuffersName) && attachment > GL_COLOR_ATTACHMENT0 364 && attachment < static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + context()->maxColorAttachments()))) { 365 if (object->isRenderbuffer()) { 366 if (!isColorRenderable(internalformat)) { 367 *reason = "the internalformat of the attached renderbuffer is not color-renderable"; 368 return false; 369 } 370 } else if (object->isTexture()) { 371 GLenum type = attachedObject->type(); 372 if (internalformat != GL_RGBA && internalformat != GL_RGB) { 373 *reason = "the internalformat of the attached texture is not color-renderable"; 374 return false; 375 } 376 // TODO: WEBGL_color_buffer_float and EXT_color_buffer_half_float extensions have not been implemented in 377 // WebGL yet. It would be better to depend on the underlying GL drivers to check on rendering to floating point textures 378 // and add the check back to WebGL when above two extensions are implemented. 379 // Assume UNSIGNED_BYTE is renderable here without the need to explicitly check if GL_OES_rgb8_rgba8 extension is supported. 380 if (type != GL_UNSIGNED_BYTE 381 && type != GL_UNSIGNED_SHORT_5_6_5 382 && type != GL_UNSIGNED_SHORT_4_4_4_4 383 && type != GL_UNSIGNED_SHORT_5_5_5_1 384 && !(type == GL_FLOAT && context()->extensionEnabled(OESTextureFloatName)) 385 && !(type == GL_HALF_FLOAT_OES && context()->extensionEnabled(OESTextureHalfFloatName))) { 386 *reason = "unsupported type: The attached texture is not supported to be rendered to"; 387 return false; 388 } 389 } 390 } else { 391 *reason = "unknown framebuffer attachment point"; 392 return false; 393 } 394 395 if (!attachedObject->width() || !attachedObject->height()) { 396 *reason = "attachment has a 0 dimension"; 397 return false; 398 } 399 return true; 400 } 401 402 WebGLFramebuffer::WebGLAttachment* WebGLFramebuffer::getAttachment(GLenum attachment) const 403 { 404 const AttachmentMap::const_iterator it = m_attachments.find(attachment); 405 return (it != m_attachments.end()) ? it->value.get() : 0; 406 } 407 408 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GLenum attachment) 409 { 410 ASSERT(isBound()); 411 if (!object()) 412 return; 413 414 WebGLAttachment* attachmentObject = getAttachment(attachment); 415 if (attachmentObject) { 416 attachmentObject->onDetached(context()->webContext()); 417 m_attachments.remove(attachment); 418 drawBuffersIfNecessary(false); 419 switch (attachment) { 420 case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL: 421 attach(GL_DEPTH_ATTACHMENT, GL_DEPTH_ATTACHMENT); 422 attach(GL_STENCIL_ATTACHMENT, GL_STENCIL_ATTACHMENT); 423 break; 424 case GL_DEPTH_ATTACHMENT: 425 attach(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL, GL_DEPTH_ATTACHMENT); 426 break; 427 case GL_STENCIL_ATTACHMENT: 428 attach(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL, GL_STENCIL_ATTACHMENT); 429 break; 430 } 431 } 432 } 433 434 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(WebGLSharedObject* attachment) 435 { 436 ASSERT(isBound()); 437 if (!object()) 438 return; 439 if (!attachment) 440 return; 441 442 bool checkMore = true; 443 while (checkMore) { 444 checkMore = false; 445 for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) { 446 WebGLAttachment* attachmentObject = it->value.get(); 447 if (attachmentObject->isSharedObject(attachment)) { 448 GLenum attachmentType = it->key; 449 attachmentObject->unattach(context()->webContext(), attachmentType); 450 removeAttachmentFromBoundFramebuffer(attachmentType); 451 checkMore = true; 452 break; 453 } 454 } 455 } 456 } 457 458 GLenum WebGLFramebuffer::colorBufferFormat() const 459 { 460 if (!object()) 461 return 0; 462 WebGLAttachment* attachment = getAttachment(GL_COLOR_ATTACHMENT0); 463 if (!attachment) 464 return 0; 465 return attachment->format(); 466 } 467 468 GLenum WebGLFramebuffer::checkStatus(const char** reason) const 469 { 470 unsigned count = 0; 471 GLsizei width = 0, height = 0; 472 bool haveDepth = false; 473 bool haveStencil = false; 474 bool haveDepthStencil = false; 475 for (AttachmentMap::const_iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) { 476 WebGLAttachment* attachment = it->value.get(); 477 if (!isAttachmentComplete(attachment, it->key, reason)) 478 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 479 if (!attachment->valid()) { 480 *reason = "attachment is not valid"; 481 return GL_FRAMEBUFFER_UNSUPPORTED; 482 } 483 if (!attachment->format()) { 484 *reason = "attachment is an unsupported format"; 485 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 486 } 487 switch (it->key) { 488 case GL_DEPTH_ATTACHMENT: 489 haveDepth = true; 490 break; 491 case GL_STENCIL_ATTACHMENT: 492 haveStencil = true; 493 break; 494 case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL: 495 haveDepthStencil = true; 496 break; 497 } 498 if (!count) { 499 width = attachment->width(); 500 height = attachment->height(); 501 } else { 502 if (width != attachment->width() || height != attachment->height()) { 503 *reason = "attachments do not have the same dimensions"; 504 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; 505 } 506 } 507 ++count; 508 } 509 if (!count) { 510 *reason = "no attachments"; 511 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; 512 } 513 if (!width || !height) { 514 *reason = "framebuffer has a 0 dimension"; 515 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 516 } 517 // WebGL specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments. 518 if ((haveDepthStencil && (haveDepth || haveStencil)) || (haveDepth && haveStencil)) { 519 *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments"; 520 return GL_FRAMEBUFFER_UNSUPPORTED; 521 } 522 return GL_FRAMEBUFFER_COMPLETE; 523 } 524 525 bool WebGLFramebuffer::onAccess(blink::WebGraphicsContext3D* context3d, const char** reason) 526 { 527 if (checkStatus(reason) != GL_FRAMEBUFFER_COMPLETE) 528 return false; 529 return true; 530 } 531 532 bool WebGLFramebuffer::hasStencilBuffer() const 533 { 534 WebGLAttachment* attachment = getAttachment(GL_STENCIL_ATTACHMENT); 535 if (!attachment) 536 attachment = getAttachment(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL); 537 return attachment && attachment->valid(); 538 } 539 540 void WebGLFramebuffer::deleteObjectImpl(blink::WebGraphicsContext3D* context3d, Platform3DObject object) 541 { 542 for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) 543 it->value->onDetached(context3d); 544 545 context3d->deleteFramebuffer(object); 546 } 547 548 bool WebGLFramebuffer::isBound() const 549 { 550 return (context()->m_framebufferBinding.get() == this); 551 } 552 553 void WebGLFramebuffer::drawBuffers(const Vector<GLenum>& bufs) 554 { 555 m_drawBuffers = bufs; 556 m_filteredDrawBuffers.resize(m_drawBuffers.size()); 557 for (size_t i = 0; i < m_filteredDrawBuffers.size(); ++i) 558 m_filteredDrawBuffers[i] = GL_NONE; 559 drawBuffersIfNecessary(true); 560 } 561 562 void WebGLFramebuffer::drawBuffersIfNecessary(bool force) 563 { 564 if (!context()->extensionEnabled(WebGLDrawBuffersName)) 565 return; 566 bool reset = force; 567 // This filtering works around graphics driver bugs on Mac OS X. 568 for (size_t i = 0; i < m_drawBuffers.size(); ++i) { 569 if (m_drawBuffers[i] != GL_NONE && getAttachment(m_drawBuffers[i])) { 570 if (m_filteredDrawBuffers[i] != m_drawBuffers[i]) { 571 m_filteredDrawBuffers[i] = m_drawBuffers[i]; 572 reset = true; 573 } 574 } else { 575 if (m_filteredDrawBuffers[i] != GL_NONE) { 576 m_filteredDrawBuffers[i] = GL_NONE; 577 reset = true; 578 } 579 } 580 } 581 if (reset) { 582 context()->webContext()->drawBuffersEXT( 583 m_filteredDrawBuffers.size(), m_filteredDrawBuffers.data()); 584 } 585 } 586 587 GLenum WebGLFramebuffer::getDrawBuffer(GLenum drawBuffer) 588 { 589 int index = static_cast<int>(drawBuffer - GL_DRAW_BUFFER0_EXT); 590 ASSERT(index >= 0); 591 if (index < static_cast<int>(m_drawBuffers.size())) 592 return m_drawBuffers[index]; 593 if (drawBuffer == GL_DRAW_BUFFER0_EXT) 594 return GL_COLOR_ATTACHMENT0; 595 return GL_NONE; 596 } 597 598 } 599