Index: third_party/WebKit/Source/modules/webgl/WebGLFramebuffer.cpp |
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLFramebuffer.cpp b/third_party/WebKit/Source/modules/webgl/WebGLFramebuffer.cpp |
index bfdfdfa7bf7825fc37f3d6ad1534457bc4e4d889..06e3fdf3f54c49b07ef2904622f26b48ec0c26af 100644 |
--- a/third_party/WebKit/Source/modules/webgl/WebGLFramebuffer.cpp |
+++ b/third_party/WebKit/Source/modules/webgl/WebGLFramebuffer.cpp |
@@ -208,6 +208,7 @@ WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContextBase* ctx) |
m_object(0), |
m_destructionInProgress(false), |
m_hasEverBeenBound(false), |
+ m_webGL1DepthStencilConsistent(true), |
m_readBuffer(GL_COLOR_ATTACHMENT0) { |
ctx->contextGL()->GenFramebuffers(1, &m_object); |
} |
@@ -228,15 +229,48 @@ void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum target, |
WebGLTexture* texture, |
GLint level, |
GLint layer) { |
- ASSERT(isBound(target)); |
- removeAttachmentFromBoundFramebuffer(target, attachment); |
- if (!m_object) |
- return; |
- if (texture && texture->object()) { |
- m_attachments.add(attachment, WebGLTextureAttachment::create( |
- texture, texTarget, level, layer)); |
- drawBuffersIfNecessary(false); |
- texture->onAttached(); |
+ DCHECK(m_object); |
+ DCHECK(isBound(target)); |
+ if (context()->isWebGL2OrHigher()) { |
+ if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { |
+ setAttachmentInternal(target, GL_DEPTH_ATTACHMENT, texTarget, texture, |
+ level, layer); |
+ setAttachmentInternal(target, GL_STENCIL_ATTACHMENT, texTarget, texture, |
+ level, layer); |
+ } else { |
+ setAttachmentInternal(target, attachment, texTarget, texture, level, |
+ layer); |
+ } |
+ GLuint textureId = objectOrZero(texture); |
+ // texTarget can be 0 if detaching using framebufferTextureLayer. |
+ DCHECK(texTarget || !textureId); |
+ switch (texTarget) { |
+ case 0: |
+ case GL_TEXTURE_3D: |
+ case GL_TEXTURE_2D_ARRAY: |
+ context()->contextGL()->FramebufferTextureLayer( |
+ target, attachment, textureId, level, layer); |
+ break; |
+ default: |
+ DCHECK_EQ(layer, 0); |
+ context()->contextGL()->FramebufferTexture2D( |
+ target, attachment, texTarget, textureId, level); |
+ break; |
+ } |
+ } else { |
+ DCHECK_EQ(layer, 0); |
+ setAttachmentInternal(target, attachment, texTarget, texture, level, layer); |
+ switch (attachment) { |
+ case GL_DEPTH_ATTACHMENT: |
+ case GL_STENCIL_ATTACHMENT: |
+ case GL_DEPTH_STENCIL_ATTACHMENT: |
+ commitWebGL1DepthStencilIfConsistent(target); |
+ break; |
+ default: |
+ context()->contextGL()->FramebufferTexture2D( |
+ target, attachment, texTarget, objectOrZero(texture), level); |
+ break; |
+ } |
} |
} |
@@ -244,27 +278,33 @@ void WebGLFramebuffer::setAttachmentForBoundFramebuffer( |
GLenum target, |
GLenum attachment, |
WebGLRenderbuffer* renderbuffer) { |
- ASSERT(isBound(target)); |
- removeAttachmentFromBoundFramebuffer(target, attachment); |
- if (!m_object) |
- return; |
- if (renderbuffer && renderbuffer->object()) { |
- m_attachments.add(attachment, |
- WebGLRenderbufferAttachment::create(renderbuffer)); |
- drawBuffersIfNecessary(false); |
- renderbuffer->onAttached(); |
+ DCHECK(m_object); |
+ DCHECK(isBound(target)); |
+ if (context()->isWebGL2OrHigher()) { |
+ if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { |
+ setAttachmentInternal(target, GL_DEPTH_ATTACHMENT, renderbuffer); |
+ setAttachmentInternal(target, GL_STENCIL_ATTACHMENT, renderbuffer); |
+ } else { |
+ setAttachmentInternal(target, attachment, renderbuffer); |
+ } |
+ context()->contextGL()->FramebufferRenderbuffer( |
+ target, attachment, GL_RENDERBUFFER, objectOrZero(renderbuffer)); |
+ } else { |
+ setAttachmentInternal(target, attachment, renderbuffer); |
+ switch (attachment) { |
+ case GL_DEPTH_ATTACHMENT: |
+ case GL_STENCIL_ATTACHMENT: |
+ case GL_DEPTH_STENCIL_ATTACHMENT: |
+ commitWebGL1DepthStencilIfConsistent(target); |
+ break; |
+ default: |
+ context()->contextGL()->FramebufferRenderbuffer( |
+ target, attachment, GL_RENDERBUFFER, objectOrZero(renderbuffer)); |
+ break; |
+ } |
} |
} |
-void WebGLFramebuffer::attach(GLenum target, |
- GLenum attachment, |
- GLenum attachmentPoint) { |
- ASSERT(isBound(target)); |
- WebGLAttachment* attachmentObject = getAttachment(attachment); |
- if (attachmentObject) |
- attachmentObject->attach(context()->contextGL(), target, attachmentPoint); |
-} |
- |
WebGLSharedObject* WebGLFramebuffer::getAttachmentObject( |
GLenum attachment) const { |
if (!m_object) |
@@ -279,31 +319,6 @@ WebGLFramebuffer::WebGLAttachment* WebGLFramebuffer::getAttachment( |
return (it != m_attachments.end()) ? it->value.get() : 0; |
} |
-void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GLenum target, |
- GLenum attachment) { |
- ASSERT(isBound(target)); |
- if (!m_object) |
- return; |
- |
- WebGLAttachment* attachmentObject = getAttachment(attachment); |
- if (attachmentObject) { |
- attachmentObject->onDetached(context()->contextGL()); |
- m_attachments.remove(attachment); |
- drawBuffersIfNecessary(false); |
- switch (attachment) { |
- case GL_DEPTH_STENCIL_ATTACHMENT: |
- attach(target, GL_DEPTH_ATTACHMENT, GL_DEPTH_ATTACHMENT); |
- attach(target, GL_STENCIL_ATTACHMENT, GL_STENCIL_ATTACHMENT); |
- break; |
- case GL_DEPTH_ATTACHMENT: |
- case GL_STENCIL_ATTACHMENT: |
- attach(target, GL_DEPTH_STENCIL_ATTACHMENT, |
- GL_DEPTH_STENCIL_ATTACHMENT); |
- break; |
- } |
- } |
-} |
- |
void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer( |
GLenum target, |
WebGLSharedObject* attachment) { |
@@ -314,51 +329,45 @@ void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer( |
return; |
bool checkMore = true; |
+ bool isWebGL1 = !context()->isWebGL2OrHigher(); |
+ bool checkWebGL1DepthStencil = false; |
while (checkMore) { |
checkMore = false; |
for (const auto& it : m_attachments) { |
WebGLAttachment* attachmentObject = it.value.get(); |
if (attachmentObject->isSharedObject(attachment)) { |
GLenum attachmentType = it.key; |
- attachmentObject->unattach(context()->contextGL(), target, |
- attachmentType); |
- removeAttachmentFromBoundFramebuffer(target, attachmentType); |
+ switch (attachmentType) { |
+ case GL_DEPTH_ATTACHMENT: |
+ case GL_STENCIL_ATTACHMENT: |
+ case GL_DEPTH_STENCIL_ATTACHMENT: |
+ if (isWebGL1) { |
+ checkWebGL1DepthStencil = true; |
+ } else { |
+ attachmentObject->unattach(context()->contextGL(), target, |
+ attachmentType); |
+ } |
+ break; |
+ default: |
+ attachmentObject->unattach(context()->contextGL(), target, |
+ attachmentType); |
+ break; |
+ } |
+ removeAttachmentInternal(target, attachmentType); |
checkMore = true; |
break; |
} |
} |
} |
+ if (checkWebGL1DepthStencil) |
+ commitWebGL1DepthStencilIfConsistent(target); |
} |
GLenum WebGLFramebuffer::checkDepthStencilStatus(const char** reason) const { |
- if (context()->isWebGL2OrHigher()) |
+ if (context()->isWebGL2OrHigher() || m_webGL1DepthStencilConsistent) |
return GL_FRAMEBUFFER_COMPLETE; |
- WebGLAttachment* depthAttachment = nullptr; |
- WebGLAttachment* stencilAttachment = nullptr; |
- WebGLAttachment* depthStencilAttachment = nullptr; |
- for (const auto& it : m_attachments) { |
- WebGLAttachment* attachment = it.value.get(); |
- ASSERT(attachment); |
- switch (it.key) { |
- case GL_DEPTH_ATTACHMENT: |
- depthAttachment = attachment; |
- break; |
- case GL_STENCIL_ATTACHMENT: |
- stencilAttachment = attachment; |
- break; |
- case GL_DEPTH_STENCIL_ATTACHMENT: |
- depthStencilAttachment = attachment; |
- break; |
- default: |
- break; |
- } |
- } |
- if ((depthStencilAttachment && (depthAttachment || stencilAttachment)) || |
- (depthAttachment && stencilAttachment)) { |
- *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments"; |
- return GL_FRAMEBUFFER_UNSUPPORTED; |
- } |
- return GL_FRAMEBUFFER_COMPLETE; |
+ *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments"; |
+ return GL_FRAMEBUFFER_UNSUPPORTED; |
} |
bool WebGLFramebuffer::hasStencilBuffer() const { |
@@ -420,6 +429,98 @@ void WebGLFramebuffer::drawBuffersIfNecessary(bool force) { |
} |
} |
+void WebGLFramebuffer::setAttachmentInternal(GLenum target, |
+ GLenum attachment, |
+ GLenum texTarget, |
+ WebGLTexture* texture, |
+ GLint level, |
+ GLint layer) { |
+ DCHECK(isBound(target)); |
+ DCHECK(m_object); |
+ removeAttachmentInternal(target, attachment); |
+ if (texture && texture->object()) { |
+ m_attachments.add(attachment, WebGLTextureAttachment::create( |
+ texture, texTarget, level, layer)); |
+ drawBuffersIfNecessary(false); |
+ texture->onAttached(); |
+ } |
+} |
+ |
+void WebGLFramebuffer::setAttachmentInternal(GLenum target, |
+ GLenum attachment, |
+ WebGLRenderbuffer* renderbuffer) { |
+ DCHECK(isBound(target)); |
+ DCHECK(m_object); |
+ removeAttachmentInternal(target, attachment); |
+ if (renderbuffer && renderbuffer->object()) { |
+ m_attachments.add(attachment, |
+ WebGLRenderbufferAttachment::create(renderbuffer)); |
+ drawBuffersIfNecessary(false); |
+ renderbuffer->onAttached(); |
+ } |
+} |
+ |
+void WebGLFramebuffer::removeAttachmentInternal(GLenum target, |
+ GLenum attachment) { |
+ DCHECK(isBound(target)); |
+ DCHECK(m_object); |
+ |
+ WebGLAttachment* attachmentObject = getAttachment(attachment); |
+ if (attachmentObject) { |
+ attachmentObject->onDetached(context()->contextGL()); |
+ m_attachments.remove(attachment); |
+ drawBuffersIfNecessary(false); |
+ } |
+} |
+ |
+void WebGLFramebuffer::commitWebGL1DepthStencilIfConsistent(GLenum target) { |
+ DCHECK(!context()->isWebGL2OrHigher()); |
+ WebGLAttachment* depthAttachment = nullptr; |
+ WebGLAttachment* stencilAttachment = nullptr; |
+ WebGLAttachment* depthStencilAttachment = nullptr; |
+ int count = 0; |
+ for (const auto& it : m_attachments) { |
+ WebGLAttachment* attachment = it.value.get(); |
+ DCHECK(attachment); |
+ switch (it.key) { |
+ case GL_DEPTH_ATTACHMENT: |
+ depthAttachment = attachment; |
+ ++count; |
+ break; |
+ case GL_STENCIL_ATTACHMENT: |
+ stencilAttachment = attachment; |
+ ++count; |
+ break; |
+ case GL_DEPTH_STENCIL_ATTACHMENT: |
+ depthStencilAttachment = attachment; |
+ ++count; |
+ break; |
+ default: |
+ break; |
+ } |
+ } |
+ |
+ m_webGL1DepthStencilConsistent = count <= 1; |
+ if (!m_webGL1DepthStencilConsistent) |
+ return; |
+ |
+ gpu::gles2::GLES2Interface* gl = context()->contextGL(); |
+ if (depthAttachment) { |
+ depthAttachment->attach(gl, target, GL_DEPTH_ATTACHMENT); |
+ gl->FramebufferRenderbuffer(target, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
+ 0); |
+ } else if (stencilAttachment) { |
+ gl->FramebufferRenderbuffer(target, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, |
+ 0); |
+ stencilAttachment->attach(gl, target, GL_STENCIL_ATTACHMENT); |
+ } else if (depthStencilAttachment) { |
+ depthStencilAttachment->attach(gl, target, GL_DEPTH_STENCIL_ATTACHMENT); |
+ } else { |
+ gl->FramebufferRenderbuffer(target, GL_DEPTH_STENCIL_ATTACHMENT, |
+ GL_RENDERBUFFER, 0); |
+ } |
+} |
+ |
GLenum WebGLFramebuffer::getDrawBuffer(GLenum drawBuffer) { |
int index = static_cast<int>(drawBuffer - GL_DRAW_BUFFER0_EXT); |
ASSERT(index >= 0); |