Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2009 Apple Inc. All rights reserved. | 2 * Copyright (C) 2009 Apple Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 196 WebGLFramebuffer* WebGLFramebuffer::create(WebGLRenderingContextBase* ctx) | 196 WebGLFramebuffer* WebGLFramebuffer::create(WebGLRenderingContextBase* ctx) |
| 197 { | 197 { |
| 198 return new WebGLFramebuffer(ctx); | 198 return new WebGLFramebuffer(ctx); |
| 199 } | 199 } |
| 200 | 200 |
| 201 WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContextBase* ctx) | 201 WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContextBase* ctx) |
| 202 : WebGLContextObject(ctx) | 202 : WebGLContextObject(ctx) |
| 203 , m_object(0) | 203 , m_object(0) |
| 204 , m_destructionInProgress(false) | 204 , m_destructionInProgress(false) |
| 205 , m_hasEverBeenBound(false) | 205 , m_hasEverBeenBound(false) |
| 206 , m_webGL1DepthStencilConsistent(true) | |
| 206 , m_readBuffer(GL_COLOR_ATTACHMENT0) | 207 , m_readBuffer(GL_COLOR_ATTACHMENT0) |
| 207 { | 208 { |
| 208 ctx->contextGL()->GenFramebuffers(1, &m_object); | 209 ctx->contextGL()->GenFramebuffers(1, &m_object); |
| 209 } | 210 } |
| 210 | 211 |
| 211 WebGLFramebuffer::~WebGLFramebuffer() | 212 WebGLFramebuffer::~WebGLFramebuffer() |
| 212 { | 213 { |
| 213 // Attachments in |m_attachments| will be deleted from other | 214 // Attachments in |m_attachments| will be deleted from other |
| 214 // places, and we must not touch that map in deleteObjectImpl once | 215 // places, and we must not touch that map in deleteObjectImpl once |
| 215 // the destructor has been entered. | 216 // the destructor has been entered. |
| 216 m_destructionInProgress = true; | 217 m_destructionInProgress = true; |
| 217 | 218 |
| 218 // See the comment in WebGLObject::detachAndDeleteObject(). | 219 // See the comment in WebGLObject::detachAndDeleteObject(). |
| 219 detachAndDeleteObject(); | 220 detachAndDeleteObject(); |
| 220 } | 221 } |
| 221 | 222 |
| 222 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum target, GLenum at tachment, GLenum texTarget, WebGLTexture* texture, GLint level, GLint layer) | 223 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum target, GLenum at tachment, GLenum texTarget, WebGLTexture* texture, GLint level, GLint layer) |
| 223 { | 224 { |
| 224 ASSERT(isBound(target)); | 225 DCHECK(m_object); |
| 225 removeAttachmentFromBoundFramebuffer(target, attachment); | 226 DCHECK(isBound(target)); |
| 226 if (!m_object) | 227 if (context()->isWebGL2OrHigher()) { |
| 227 return; | 228 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { |
| 228 if (texture && texture->object()) { | 229 setAttachmentInternal(target, GL_DEPTH_ATTACHMENT, texTarget, textur e, level, layer); |
| 229 m_attachments.add(attachment, WebGLTextureAttachment::create(texture, te xTarget, level, layer)); | 230 setAttachmentInternal(target, GL_STENCIL_ATTACHMENT, texTarget, text ure, level, layer); |
| 230 drawBuffersIfNecessary(false); | 231 } else { |
| 231 texture->onAttached(); | 232 setAttachmentInternal(target, attachment, texTarget, texture, level, layer); |
| 233 } | |
| 234 GLuint textureId = objectOrZero(texture); | |
| 235 // texTarget can be 0 if detaching using framebufferTextureLayer. | |
| 236 DCHECK(texTarget || !textureId); | |
| 237 switch (texTarget) { | |
| 238 case 0: | |
| 239 case GL_TEXTURE_3D: | |
| 240 case GL_TEXTURE_2D_ARRAY: | |
| 241 context()->contextGL()->FramebufferTextureLayer(target, attachment, textureId, level, layer); | |
| 242 break; | |
| 243 default: | |
| 244 DCHECK_EQ(layer, 0); | |
| 245 context()->contextGL()->FramebufferTexture2D(target, attachment, tex Target, textureId, level); | |
| 246 break; | |
| 247 } | |
| 248 } else { | |
| 249 DCHECK_EQ(layer, 0); | |
| 250 setAttachmentInternal(target, attachment, texTarget, texture, level, lay er); | |
| 251 switch (attachment) { | |
| 252 case GL_DEPTH_ATTACHMENT: | |
| 253 case GL_STENCIL_ATTACHMENT: | |
| 254 case GL_DEPTH_STENCIL_ATTACHMENT: | |
| 255 commitWebGL1DepthStencilIfConsistent(target); | |
| 256 break; | |
| 257 default: | |
| 258 context()->contextGL()->FramebufferTexture2D(target, attachment, tex Target, objectOrZero(texture), level); | |
| 259 break; | |
| 260 } | |
| 232 } | 261 } |
| 233 } | 262 } |
| 234 | 263 |
| 235 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum target, GLenum at tachment, WebGLRenderbuffer* renderbuffer) | 264 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum target, GLenum at tachment, WebGLRenderbuffer* renderbuffer) |
| 236 { | 265 { |
| 237 ASSERT(isBound(target)); | 266 DCHECK(m_object); |
| 238 removeAttachmentFromBoundFramebuffer(target, attachment); | 267 DCHECK(isBound(target)); |
| 239 if (!m_object) | 268 if (context()->isWebGL2OrHigher()) { |
| 240 return; | 269 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { |
| 241 if (renderbuffer && renderbuffer->object()) { | 270 setAttachmentInternal(target, GL_DEPTH_ATTACHMENT, renderbuffer); |
| 242 m_attachments.add(attachment, WebGLRenderbufferAttachment::create(render buffer)); | 271 setAttachmentInternal(target, GL_STENCIL_ATTACHMENT, renderbuffer); |
| 243 drawBuffersIfNecessary(false); | 272 } else { |
| 244 renderbuffer->onAttached(); | 273 setAttachmentInternal(target, attachment, renderbuffer); |
| 274 } | |
| 275 context()->contextGL()->FramebufferRenderbuffer(target, attachment, GL_R ENDERBUFFER, objectOrZero(renderbuffer)); | |
| 276 } else { | |
| 277 setAttachmentInternal(target, attachment, renderbuffer); | |
| 278 switch (attachment) { | |
| 279 case GL_DEPTH_ATTACHMENT: | |
| 280 case GL_STENCIL_ATTACHMENT: | |
| 281 case GL_DEPTH_STENCIL_ATTACHMENT: | |
| 282 commitWebGL1DepthStencilIfConsistent(target); | |
| 283 break; | |
| 284 default: | |
| 285 context()->contextGL()->FramebufferRenderbuffer(target, attachment, GL_RENDERBUFFER, objectOrZero(renderbuffer)); | |
| 286 break; | |
| 287 } | |
| 245 } | 288 } |
| 246 } | 289 } |
| 247 | 290 |
| 248 void WebGLFramebuffer::attach(GLenum target, GLenum attachment, GLenum attachmen tPoint) | |
| 249 { | |
| 250 ASSERT(isBound(target)); | |
| 251 WebGLAttachment* attachmentObject = getAttachment(attachment); | |
| 252 if (attachmentObject) | |
| 253 attachmentObject->attach(context()->contextGL(), target, attachmentPoint ); | |
| 254 } | |
| 255 | |
| 256 WebGLSharedObject* WebGLFramebuffer::getAttachmentObject(GLenum attachment) cons t | 291 WebGLSharedObject* WebGLFramebuffer::getAttachmentObject(GLenum attachment) cons t |
| 257 { | 292 { |
| 258 if (!m_object) | 293 if (!m_object) |
| 259 return nullptr; | 294 return nullptr; |
| 260 WebGLAttachment* attachmentObject = getAttachment(attachment); | 295 WebGLAttachment* attachmentObject = getAttachment(attachment); |
| 261 return attachmentObject ? attachmentObject->object() : nullptr; | 296 return attachmentObject ? attachmentObject->object() : nullptr; |
| 262 } | 297 } |
| 263 | 298 |
| 264 WebGLFramebuffer::WebGLAttachment* WebGLFramebuffer::getAttachment(GLenum attach ment) const | 299 WebGLFramebuffer::WebGLAttachment* WebGLFramebuffer::getAttachment(GLenum attach ment) const |
| 265 { | 300 { |
| 266 const AttachmentMap::const_iterator it = m_attachments.find(attachment); | 301 const AttachmentMap::const_iterator it = m_attachments.find(attachment); |
| 267 return (it != m_attachments.end()) ? it->value.get() : 0; | 302 return (it != m_attachments.end()) ? it->value.get() : 0; |
| 268 } | 303 } |
| 269 | 304 |
| 270 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GLenum target, GLenu m attachment) | |
| 271 { | |
| 272 ASSERT(isBound(target)); | |
| 273 if (!m_object) | |
| 274 return; | |
| 275 | |
| 276 WebGLAttachment* attachmentObject = getAttachment(attachment); | |
| 277 if (attachmentObject) { | |
| 278 attachmentObject->onDetached(context()->contextGL()); | |
| 279 m_attachments.remove(attachment); | |
| 280 drawBuffersIfNecessary(false); | |
| 281 switch (attachment) { | |
| 282 case GL_DEPTH_STENCIL_ATTACHMENT: | |
| 283 attach(target, GL_DEPTH_ATTACHMENT, GL_DEPTH_ATTACHMENT); | |
| 284 attach(target, GL_STENCIL_ATTACHMENT, GL_STENCIL_ATTACHMENT); | |
| 285 break; | |
| 286 case GL_DEPTH_ATTACHMENT: | |
| 287 case GL_STENCIL_ATTACHMENT: | |
| 288 attach(target, GL_DEPTH_STENCIL_ATTACHMENT, GL_DEPTH_STENCIL_ATTACHM ENT); | |
| 289 break; | |
| 290 } | |
| 291 } | |
| 292 } | |
| 293 | |
| 294 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GLenum target, WebGL SharedObject* attachment) | 305 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GLenum target, WebGL SharedObject* attachment) |
| 295 { | 306 { |
| 296 ASSERT(isBound(target)); | 307 ASSERT(isBound(target)); |
| 297 if (!m_object) | 308 if (!m_object) |
| 298 return; | 309 return; |
| 299 if (!attachment) | 310 if (!attachment) |
| 300 return; | 311 return; |
| 301 | 312 |
| 302 bool checkMore = true; | 313 bool checkMore = true; |
| 314 bool isWebGL1 = !context()->isWebGL2OrHigher(); | |
| 315 bool checkWebGL1DepthStencil = false; | |
| 303 while (checkMore) { | 316 while (checkMore) { |
| 304 checkMore = false; | 317 checkMore = false; |
| 305 for (const auto& it : m_attachments) { | 318 for (const auto& it : m_attachments) { |
| 306 WebGLAttachment* attachmentObject = it.value.get(); | 319 WebGLAttachment* attachmentObject = it.value.get(); |
| 307 if (attachmentObject->isSharedObject(attachment)) { | 320 if (attachmentObject->isSharedObject(attachment)) { |
| 308 GLenum attachmentType = it.key; | 321 GLenum attachmentType = it.key; |
| 309 attachmentObject->unattach(context()->contextGL(), target, attac hmentType); | 322 switch (attachmentType) { |
| 310 removeAttachmentFromBoundFramebuffer(target, attachmentType); | 323 case GL_DEPTH_ATTACHMENT: |
| 324 case GL_STENCIL_ATTACHMENT: | |
| 325 case GL_DEPTH_STENCIL_ATTACHMENT: | |
| 326 if (isWebGL1) { | |
| 327 checkWebGL1DepthStencil = true; | |
| 328 } else { | |
| 329 attachmentObject->unattach(context()->contextGL(), targe t, attachmentType); | |
| 330 } | |
| 331 break; | |
| 332 default: | |
| 333 attachmentObject->unattach(context()->contextGL(), target, a ttachmentType); | |
| 334 break; | |
| 335 } | |
| 336 removeAttachmentInternal(target, attachmentType); | |
| 311 checkMore = true; | 337 checkMore = true; |
| 312 break; | 338 break; |
| 313 } | 339 } |
| 314 } | 340 } |
| 315 } | 341 } |
| 342 if (checkWebGL1DepthStencil) | |
| 343 commitWebGL1DepthStencilIfConsistent(target); | |
| 316 } | 344 } |
| 317 | 345 |
| 318 GLenum WebGLFramebuffer::checkDepthStencilStatus(const char** reason) const | 346 GLenum WebGLFramebuffer::checkDepthStencilStatus(const char** reason) const |
| 319 { | 347 { |
| 320 if (context()->isWebGL2OrHigher()) | 348 if (context()->isWebGL2OrHigher() || m_webGL1DepthStencilConsistent) |
| 321 return GL_FRAMEBUFFER_COMPLETE; | 349 return GL_FRAMEBUFFER_COMPLETE; |
| 322 WebGLAttachment* depthAttachment = nullptr; | 350 *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments"; |
| 323 WebGLAttachment* stencilAttachment = nullptr; | 351 return GL_FRAMEBUFFER_UNSUPPORTED; |
| 324 WebGLAttachment* depthStencilAttachment = nullptr; | |
| 325 for (const auto& it : m_attachments) { | |
| 326 WebGLAttachment* attachment = it.value.get(); | |
| 327 ASSERT(attachment); | |
| 328 switch (it.key) { | |
| 329 case GL_DEPTH_ATTACHMENT: | |
| 330 depthAttachment = attachment; | |
| 331 break; | |
| 332 case GL_STENCIL_ATTACHMENT: | |
| 333 stencilAttachment = attachment; | |
| 334 break; | |
| 335 case GL_DEPTH_STENCIL_ATTACHMENT: | |
| 336 depthStencilAttachment = attachment; | |
| 337 break; | |
| 338 default: | |
| 339 break; | |
| 340 } | |
| 341 } | |
| 342 if ((depthStencilAttachment && (depthAttachment || stencilAttachment)) | |
| 343 || (depthAttachment && stencilAttachment)) { | |
| 344 *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments"; | |
| 345 return GL_FRAMEBUFFER_UNSUPPORTED; | |
| 346 } | |
| 347 return GL_FRAMEBUFFER_COMPLETE; | |
| 348 } | 352 } |
| 349 | 353 |
| 350 bool WebGLFramebuffer::hasStencilBuffer() const | 354 bool WebGLFramebuffer::hasStencilBuffer() const |
| 351 { | 355 { |
| 352 WebGLAttachment* attachment = getAttachment(GL_STENCIL_ATTACHMENT); | 356 WebGLAttachment* attachment = getAttachment(GL_STENCIL_ATTACHMENT); |
| 353 if (!attachment) | 357 if (!attachment) |
| 354 attachment = getAttachment(GL_DEPTH_STENCIL_ATTACHMENT); | 358 attachment = getAttachment(GL_DEPTH_STENCIL_ATTACHMENT); |
| 355 return attachment && attachment->valid(); | 359 return attachment && attachment->valid(); |
| 356 } | 360 } |
| 357 | 361 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 404 } | 408 } |
| 405 } | 409 } |
| 406 } | 410 } |
| 407 if (reset) { | 411 if (reset) { |
| 408 context()->contextGL()->DrawBuffersEXT( | 412 context()->contextGL()->DrawBuffersEXT( |
| 409 m_filteredDrawBuffers.size(), m_filteredDrawBuffers.data()); | 413 m_filteredDrawBuffers.size(), m_filteredDrawBuffers.data()); |
| 410 } | 414 } |
| 411 } | 415 } |
| 412 } | 416 } |
| 413 | 417 |
| 418 void WebGLFramebuffer::setAttachmentInternal(GLenum target, GLenum attachment, G Lenum texTarget, WebGLTexture* texture, GLint level, GLint layer) | |
| 419 { | |
| 420 DCHECK(isBound(target)); | |
| 421 DCHECK(m_object); | |
| 422 removeAttachmentInternal(target, attachment); | |
| 423 if (texture && texture->object()) { | |
| 424 m_attachments.add(attachment, WebGLTextureAttachment::create(texture, te xTarget, level, layer)); | |
| 425 drawBuffersIfNecessary(false); | |
| 426 texture->onAttached(); | |
| 427 } | |
| 428 } | |
| 429 | |
| 430 void WebGLFramebuffer::setAttachmentInternal(GLenum target, GLenum attachment, W ebGLRenderbuffer* renderbuffer) | |
| 431 { | |
| 432 DCHECK(isBound(target)); | |
| 433 DCHECK(m_object); | |
| 434 removeAttachmentInternal(target, attachment); | |
| 435 if (renderbuffer && renderbuffer->object()) { | |
| 436 m_attachments.add(attachment, WebGLRenderbufferAttachment::create(render buffer)); | |
| 437 drawBuffersIfNecessary(false); | |
| 438 renderbuffer->onAttached(); | |
| 439 } | |
| 440 } | |
| 441 | |
| 442 void WebGLFramebuffer::removeAttachmentInternal(GLenum target, GLenum attachment ) | |
| 443 { | |
| 444 DCHECK(isBound(target)); | |
| 445 DCHECK(m_object); | |
| 446 | |
| 447 WebGLAttachment* attachmentObject = getAttachment(attachment); | |
| 448 if (attachmentObject) { | |
| 449 attachmentObject->onDetached(context()->contextGL()); | |
| 450 m_attachments.remove(attachment); | |
| 451 drawBuffersIfNecessary(false); | |
| 452 } | |
| 453 } | |
| 454 | |
| 455 void WebGLFramebuffer::commitWebGL1DepthStencilIfConsistent(GLenum target) | |
| 456 { | |
| 457 DCHECK(!context()->isWebGL2OrHigher()); | |
| 458 WebGLAttachment* depthAttachment = nullptr; | |
| 459 WebGLAttachment* stencilAttachment = nullptr; | |
| 460 WebGLAttachment* depthStencilAttachment = nullptr; | |
| 461 int count = 0; | |
| 462 for (const auto& it : m_attachments) { | |
| 463 WebGLAttachment* attachment = it.value.get(); | |
| 464 DCHECK(attachment); | |
| 465 switch (it.key) { | |
| 466 case GL_DEPTH_ATTACHMENT: | |
| 467 depthAttachment = attachment; | |
| 468 ++count; | |
| 469 break; | |
| 470 case GL_STENCIL_ATTACHMENT: | |
| 471 stencilAttachment = attachment; | |
| 472 ++count; | |
| 473 break; | |
| 474 case GL_DEPTH_STENCIL_ATTACHMENT: | |
| 475 depthStencilAttachment = attachment; | |
| 476 ++count; | |
| 477 break; | |
| 478 default: | |
| 479 break; | |
| 480 } | |
| 481 } | |
| 482 | |
| 483 m_webGL1DepthStencilConsistent = count <= 1; | |
| 484 if (!m_webGL1DepthStencilConsistent) | |
| 485 return; | |
|
Ken Russell (switch to Gerrit)
2016/09/29 03:07:43
Can this lazy flushing of the framebuffer's attach
| |
| 486 | |
| 487 gpu::gles2::GLES2Interface* gl = context()->contextGL(); | |
| 488 if (depthAttachment) { | |
| 489 depthAttachment->attach(gl, target, GL_DEPTH_ATTACHMENT); | |
| 490 gl->FramebufferRenderbuffer(target, GL_STENCIL_ATTACHMENT, GL_RENDERBUFF ER, 0); | |
| 491 } else if (stencilAttachment) { | |
| 492 gl->FramebufferRenderbuffer(target, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER , 0); | |
| 493 stencilAttachment->attach(gl, target, GL_STENCIL_ATTACHMENT); | |
| 494 } else if (depthStencilAttachment) { | |
| 495 depthStencilAttachment->attach(gl, target, GL_DEPTH_STENCIL_ATTACHMENT); | |
| 496 } else { | |
| 497 gl->FramebufferRenderbuffer(target, GL_DEPTH_STENCIL_ATTACHMENT, GL_REND ERBUFFER, 0); | |
| 498 } | |
| 499 } | |
| 500 | |
| 414 GLenum WebGLFramebuffer::getDrawBuffer(GLenum drawBuffer) | 501 GLenum WebGLFramebuffer::getDrawBuffer(GLenum drawBuffer) |
| 415 { | 502 { |
| 416 int index = static_cast<int>(drawBuffer - GL_DRAW_BUFFER0_EXT); | 503 int index = static_cast<int>(drawBuffer - GL_DRAW_BUFFER0_EXT); |
| 417 ASSERT(index >= 0); | 504 ASSERT(index >= 0); |
| 418 if (index < static_cast<int>(m_drawBuffers.size())) | 505 if (index < static_cast<int>(m_drawBuffers.size())) |
| 419 return m_drawBuffers[index]; | 506 return m_drawBuffers[index]; |
| 420 if (drawBuffer == GL_DRAW_BUFFER0_EXT) | 507 if (drawBuffer == GL_DRAW_BUFFER0_EXT) |
| 421 return GL_COLOR_ATTACHMENT0; | 508 return GL_COLOR_ATTACHMENT0; |
| 422 return GL_NONE; | 509 return GL_NONE; |
| 423 } | 510 } |
| 424 | 511 |
| 425 void WebGLFramebuffer::visitChildDOMWrappers(v8::Isolate* isolate, const v8::Per sistent<v8::Object>& wrapper) | 512 void WebGLFramebuffer::visitChildDOMWrappers(v8::Isolate* isolate, const v8::Per sistent<v8::Object>& wrapper) |
| 426 { | 513 { |
| 427 for (const auto& attachment : m_attachments) { | 514 for (const auto& attachment : m_attachments) { |
| 428 DOMWrapperWorld::setWrapperReferencesInAllWorlds(wrapper, attachment.val ue->object(), isolate); | 515 DOMWrapperWorld::setWrapperReferencesInAllWorlds(wrapper, attachment.val ue->object(), isolate); |
| 429 } | 516 } |
| 430 } | 517 } |
| 431 | 518 |
| 432 DEFINE_TRACE(WebGLFramebuffer) | 519 DEFINE_TRACE(WebGLFramebuffer) |
| 433 { | 520 { |
| 434 visitor->trace(m_attachments); | 521 visitor->trace(m_attachments); |
| 435 WebGLContextObject::trace(visitor); | 522 WebGLContextObject::trace(visitor); |
| 436 } | 523 } |
| 437 | 524 |
| 438 } // namespace blink | 525 } // namespace blink |
| OLD | NEW |