From ece68b195235370364769cc8f67bac6da34301cd Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Wed, 22 Jan 2014 19:59:34 -0800 Subject: [PATCH] Bug 962392 - Clean up WebGLFramebuffer, particularly handling of RectangleObjects. - r=dglastonbury --- content/canvas/src/WebGLContext.h | 3 +- content/canvas/src/WebGLContextGL.cpp | 62 +-- content/canvas/src/WebGLContextVertices.cpp | 2 +- content/canvas/src/WebGLFramebuffer.cpp | 459 ++++++++++++-------- content/canvas/src/WebGLFramebuffer.h | 52 ++- 5 files changed, 338 insertions(+), 240 deletions(-) diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h index fa80829a989d..7577a88447a1 100644 --- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -230,7 +230,8 @@ public: // all context resources to be lost. uint32_t Generation() { return mGeneration.value(); } - const WebGLRectangleObject *FramebufferRectangleObject() const; + // Returns null if the current bound FB is not likely complete. + const WebGLRectangleObject* CurValidFBRectObject() const; static const size_t sMaxColorAttachments = 16; diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp index aa3533a0e02b..0a5b4108c5b8 100644 --- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -53,9 +53,22 @@ using namespace mozilla::gfx; static bool BaseTypeAndSizeFromUniformType(GLenum uType, GLenum *baseType, GLint *unitSize); static GLenum InternalFormatForFormatAndType(GLenum format, GLenum type, bool isGLES2); -const WebGLRectangleObject *WebGLContext::FramebufferRectangleObject() const { - return mBoundFramebuffer ? mBoundFramebuffer->RectangleObject() - : static_cast(this); +const WebGLRectangleObject* +WebGLContext::CurValidFBRectObject() const +{ + const WebGLRectangleObject* rect = nullptr; + + if (mBoundFramebuffer) { + // We don't really need to ask the driver. + // Use 'precheck' to just check that our internal state looks good. + GLenum precheckStatus = mBoundFramebuffer->PrecheckFramebufferStatus(); + if (precheckStatus == LOCAL_GL_FRAMEBUFFER_COMPLETE) + rect = &mBoundFramebuffer->RectangleObject(); + } else { + rect = static_cast(this); + } + + return rect; } WebGLContext::FakeBlackTexture::FakeBlackTexture(GLContext *gl, GLenum target, GLenum format) @@ -347,11 +360,8 @@ GLenum WebGLContext::CheckFramebufferStatus(GLenum target) { if (IsContextLost()) - { return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED; - } - MakeContextCurrent(); if (target != LOCAL_GL_FRAMEBUFFER) { ErrorInvalidEnum("checkFramebufferStatus: target must be FRAMEBUFFER"); return 0; @@ -359,42 +369,8 @@ WebGLContext::CheckFramebufferStatus(GLenum target) if (!mBoundFramebuffer) return LOCAL_GL_FRAMEBUFFER_COMPLETE; - if(mBoundFramebuffer->HasDepthStencilConflict()) - return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED; - bool hasImages = false; - hasImages |= mBoundFramebuffer->DepthAttachment().IsDefined(); - hasImages |= mBoundFramebuffer->StencilAttachment().IsDefined(); - hasImages |= mBoundFramebuffer->DepthStencilAttachment().IsDefined(); - - if (!hasImages) { - int32_t colorAttachmentCount = mBoundFramebuffer->mColorAttachments.Length(); - - for(int32_t i = 0; i < colorAttachmentCount; i++) { - if (mBoundFramebuffer->ColorAttachment(i).IsDefined()) { - hasImages = true; - break; - } - } - - /* http://www.khronos.org/registry/gles/specs/2.0/es_full_spec_2.0.25.pdf section 4.4.5 (page 118) - GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT - No images are attached to the framebuffer. - */ - if (!hasImages) { - return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; - } - } - - if(mBoundFramebuffer->HasIncompleteAttachment()) - return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - if(mBoundFramebuffer->HasAttachmentsOfMismatchedDimensions()) - return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; - - // Ok, attach our chosen flavor of {DEPTH, STENCIL, DEPTH_STENCIL}. - mBoundFramebuffer->FinalizeAttachments(); - - return gl->fCheckFramebufferStatus(target); + return mBoundFramebuffer->CheckFramebufferStatus(); } void @@ -409,7 +385,7 @@ WebGLContext::CopyTexSubImage2D_base(GLenum target, GLsizei height, bool sub) { - const WebGLRectangleObject *framebufferRect = FramebufferRectangleObject(); + const WebGLRectangleObject* framebufferRect = CurValidFBRectObject(); GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0; GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0; @@ -2269,7 +2245,7 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, if (pixels.IsNull()) return ErrorInvalidValue("readPixels: null destination buffer"); - const WebGLRectangleObject *framebufferRect = FramebufferRectangleObject(); + const WebGLRectangleObject* framebufferRect = CurValidFBRectObject(); GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0; GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0; diff --git a/content/canvas/src/WebGLContextVertices.cpp b/content/canvas/src/WebGLContextVertices.cpp index 665ab1002f3d..51737375174b 100644 --- a/content/canvas/src/WebGLContextVertices.cpp +++ b/content/canvas/src/WebGLContextVertices.cpp @@ -735,7 +735,7 @@ void WebGLContext::Draw_cleanup() } // Let's check the viewport - const WebGLRectangleObject* rect = FramebufferRectangleObject(); + const WebGLRectangleObject* rect = CurValidFBRectObject(); if (rect) { if (mViewportWidth > rect->Width() || mViewportHeight > rect->Height()) diff --git a/content/canvas/src/WebGLFramebuffer.cpp b/content/canvas/src/WebGLFramebuffer.cpp index 66438975b10d..6f3f9bea257d 100644 --- a/content/canvas/src/WebGLFramebuffer.cpp +++ b/content/canvas/src/WebGLFramebuffer.cpp @@ -12,16 +12,18 @@ #include "WebGLTexture.h" #include "WebGLRenderbuffer.h" #include "GLContext.h" +#include "WebGLContextUtils.h" using namespace mozilla; using namespace mozilla::gl; JSObject* -WebGLFramebuffer::WrapObject(JSContext *cx, JS::Handle scope) { +WebGLFramebuffer::WrapObject(JSContext* cx, JS::Handle scope) +{ return dom::WebGLFramebufferBinding::Wrap(cx, scope, this); } -WebGLFramebuffer::WebGLFramebuffer(WebGLContext *context) +WebGLFramebuffer::WebGLFramebuffer(WebGLContext* context) : WebGLContextBoundObject(context) , mHasEverBeenBound(false) , mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT) @@ -38,14 +40,16 @@ WebGLFramebuffer::WebGLFramebuffer(WebGLContext *context) } bool -WebGLFramebuffer::Attachment::IsDeleteRequested() const { +WebGLFramebuffer::Attachment::IsDeleteRequested() const +{ return Texture() ? Texture()->IsDeleteRequested() : Renderbuffer() ? Renderbuffer()->IsDeleteRequested() : false; } bool -WebGLFramebuffer::Attachment::HasAlpha() const { +WebGLFramebuffer::Attachment::HasAlpha() const +{ GLenum format = 0; if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel)) format = Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).InternalFormat(); @@ -55,7 +59,8 @@ WebGLFramebuffer::Attachment::HasAlpha() const { } void -WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture *tex, GLenum target, GLint level) { +WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture* tex, GLenum target, GLint level) +{ mTexturePtr = tex; mRenderbufferPtr = nullptr; mTexImageTarget = target; @@ -63,50 +68,68 @@ WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture *tex, GLenum target, GLin } bool -WebGLFramebuffer::Attachment::HasUninitializedImageData() const { - if (mRenderbufferPtr) { - return mRenderbufferPtr->HasUninitializedImageData(); - } else if (mTexturePtr) { - if (!mTexturePtr->HasImageInfoAt(mTexImageTarget, mTexImageLevel)) - return false; - return mTexturePtr->ImageInfoAt(mTexImageTarget, mTexImageLevel).HasUninitializedImageData(); - } else { +WebGLFramebuffer::Attachment::HasUninitializedImageData() const +{ + if (!HasImage()) return false; + + if (Renderbuffer()) { + return Renderbuffer()->HasUninitializedImageData(); + } else if (Texture()) { + MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel)); + return Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).HasUninitializedImageData(); } + + MOZ_ASSERT(false, "Should not get here."); + return false; } void -WebGLFramebuffer::Attachment::SetImageDataStatus(WebGLImageDataStatus newStatus) { +WebGLFramebuffer::Attachment::SetImageDataStatus(WebGLImageDataStatus newStatus) +{ + if (!HasImage()) + return; + if (mRenderbufferPtr) { mRenderbufferPtr->SetImageDataStatus(newStatus); + return; } else if (mTexturePtr) { mTexturePtr->SetImageDataStatus(mTexImageTarget, mTexImageLevel, newStatus); - } else { - MOZ_ASSERT(false); // should not get here, worth crashing a debug build. + return; } -} -const WebGLRectangleObject* -WebGLFramebuffer::Attachment::RectangleObject() const { - if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel)) - return &Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel); - else if (Renderbuffer()) - return Renderbuffer(); - else - return nullptr; + MOZ_ASSERT(false, "Should not get here."); } bool -WebGLFramebuffer::Attachment::HasSameDimensionsAs(const Attachment& other) const { - const WebGLRectangleObject *thisRect = RectangleObject(); - const WebGLRectangleObject *otherRect = other.RectangleObject(); - return thisRect && - otherRect && - thisRect->HasSameDimensionsAs(*otherRect); +WebGLFramebuffer::Attachment::HasImage() const +{ + if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel)) + return true; + else if (Renderbuffer()) + return true; + + return false; +} + +const WebGLRectangleObject& +WebGLFramebuffer::Attachment::RectangleObject() const +{ + MOZ_ASSERT(HasImage(), "Make sure it has an image before requesting the rectangle."); + + if (Texture()) { + MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel)); + return Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel); + } else if (Renderbuffer()) { + return *Renderbuffer(); + } + + MOZ_CRASH("Should not get here."); } static inline bool -IsValidAttachedTextureColorFormat(GLenum format) { +IsValidAttachedTextureColorFormat(GLenum format) +{ return ( /* linear 8-bit formats */ format == LOCAL_GL_ALPHA || @@ -126,31 +149,34 @@ IsValidAttachedTextureColorFormat(GLenum format) { } bool -WebGLFramebuffer::Attachment::IsComplete() const { - const WebGLRectangleObject *thisRect = RectangleObject(); - - if (!thisRect || - !thisRect->Width() || - !thisRect->Height()) +WebGLFramebuffer::Attachment::IsComplete() const +{ + if (!HasImage()) return false; - if (mTexturePtr) { - if (!mTexturePtr->HasImageInfoAt(mTexImageTarget, mTexImageLevel)) - return false; + const WebGLRectangleObject& rect = RectangleObject(); + if (!rect.Width() || + !rect.Height()) + { + return false; + } + + if (mTexturePtr) { + MOZ_ASSERT(mTexturePtr->HasImageInfoAt(mTexImageTarget, mTexImageLevel)); GLenum format = mTexturePtr->ImageInfoAt(mTexImageTarget, mTexImageLevel).InternalFormat(); if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT) { return format == LOCAL_GL_DEPTH_COMPONENT; - } - else if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) { + } else if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) { return format == LOCAL_GL_DEPTH_STENCIL; - } - else if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 && - mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + WebGLContext::sMaxColorAttachments)) { + } else if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 && + mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + WebGLContext::sMaxColorAttachments)) + { return IsValidAttachedTextureColorFormat(format); } - MOZ_CRASH("Invalid WebGL attachment poin?"); + MOZ_ASSERT(false, "Invalid WebGL attachment point?"); + return false; } if (mRenderbufferPtr) { @@ -158,29 +184,31 @@ WebGLFramebuffer::Attachment::IsComplete() const { if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT) { return format == LOCAL_GL_DEPTH_COMPONENT16; - } - else if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT) { + } else if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT) { return format == LOCAL_GL_STENCIL_INDEX8; - } - else if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) { + } else if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) { return format == LOCAL_GL_DEPTH_STENCIL; + } else if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 && + mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + WebGLContext::sMaxColorAttachments)) + { + return format == LOCAL_GL_RGB565 || + format == LOCAL_GL_RGB5_A1 || + format == LOCAL_GL_RGBA4 || + format == LOCAL_GL_SRGB8_ALPHA8_EXT; } - else if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 && - mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + WebGLContext::sMaxColorAttachments)) { - return (format == LOCAL_GL_RGB565 || - format == LOCAL_GL_RGB5_A1 || - format == LOCAL_GL_RGBA4 || - format == LOCAL_GL_SRGB8_ALPHA8_EXT); - } - MOZ_CRASH("Invalid WebGL attachment poin?"); + MOZ_ASSERT(false, "Invalid WebGL attachment point?"); + return false; } - MOZ_ASSERT(false); // should never get there + MOZ_ASSERT(false, "Should not get here."); return false; } void -WebGLFramebuffer::Attachment::FinalizeAttachment(GLenum attachmentLoc) const { +WebGLFramebuffer::Attachment::FinalizeAttachment(GLenum attachmentLoc) const +{ + MOZ_ASSERT(HasImage()); + if (Texture()) { GLContext* gl = Texture()->Context()->gl; if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) { @@ -200,16 +228,17 @@ WebGLFramebuffer::Attachment::FinalizeAttachment(GLenum attachmentLoc) const { return; } - // Neither? - MOZ_ASSERT(false, "FB attachment without a tex or RB."); + MOZ_ASSERT(false, "Should not get here."); } void -WebGLFramebuffer::Delete() { +WebGLFramebuffer::Delete() +{ mColorAttachments.Clear(); mDepthAttachment.Reset(); mStencilAttachment.Reset(); mDepthStencilAttachment.Reset(); + mContext->MakeContextCurrent(); mContext->gl->fDeleteFramebuffers(1, &mGLName); LinkedListElement::removeFrom(mContext->mFramebuffers); @@ -217,15 +246,13 @@ WebGLFramebuffer::Delete() { void WebGLFramebuffer::FramebufferRenderbuffer(GLenum target, - GLenum attachment, - GLenum rbtarget, - WebGLRenderbuffer *wrb) + GLenum attachment, + GLenum rbtarget, + WebGLRenderbuffer* wrb) { MOZ_ASSERT(mContext->mBoundFramebuffer == this); if (!mContext->ValidateObjectAllowNull("framebufferRenderbuffer: renderbuffer", wrb)) - { return; - } if (target != LOCAL_GL_FRAMEBUFFER) return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: target", target); @@ -258,10 +285,10 @@ WebGLFramebuffer::FramebufferRenderbuffer(GLenum target, void WebGLFramebuffer::FramebufferTexture2D(GLenum target, - GLenum attachment, - GLenum textarget, - WebGLTexture *wtex, - GLint level) + GLenum attachment, + GLenum textarget, + WebGLTexture* wtex, + GLint level) { MOZ_ASSERT(mContext->mBoundFramebuffer == this); if (!mContext->ValidateObjectAllowNull("framebufferTexture2D: texture", @@ -276,7 +303,9 @@ WebGLFramebuffer::FramebufferTexture2D(GLenum target, if (textarget != LOCAL_GL_TEXTURE_2D && (textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X || textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)) + { return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: invalid texture target", textarget); + } if (wtex) { bool isTexture2D = wtex->Target() == LOCAL_GL_TEXTURE_2D; @@ -300,9 +329,8 @@ WebGLFramebuffer::FramebufferTexture2D(GLenum target, mDepthStencilAttachment.SetTexImage(wtex, textarget, level); break; default: - if (!CheckColorAttachementNumber(attachment, "framebufferTexture2D")){ + if (!CheckColorAttachementNumber(attachment, "framebufferTexture2D")) return; - } size_t colorAttachmentId = size_t(attachment - LOCAL_GL_COLOR_ATTACHMENT0); EnsureColorAttachments(colorAttachmentId); @@ -311,42 +339,9 @@ WebGLFramebuffer::FramebufferTexture2D(GLenum target, } } -bool -WebGLFramebuffer::HasIncompleteAttachment() const { - int32_t colorAttachmentCount = mColorAttachments.Length(); - - for (int32_t i = 0; i < colorAttachmentCount; i++) - { - if (mColorAttachments[i].IsDefined() && !mColorAttachments[i].IsComplete()) - { - return true; - } - } - - return ((mDepthAttachment.IsDefined() && !mDepthAttachment.IsComplete()) || - (mStencilAttachment.IsDefined() && !mStencilAttachment.IsComplete()) || - (mDepthStencilAttachment.IsDefined() && !mDepthStencilAttachment.IsComplete())); -} - -bool -WebGLFramebuffer::HasAttachmentsOfMismatchedDimensions() const { - int32_t colorAttachmentCount = mColorAttachments.Length(); - - for (int32_t i = 1; i < colorAttachmentCount; i++) - { - if (mColorAttachments[i].IsDefined() && !mColorAttachments[i].HasSameDimensionsAs(mColorAttachments[0])) - { - return true; - } - } - - return ((mDepthAttachment.IsDefined() && !mDepthAttachment.HasSameDimensionsAs(mColorAttachments[0])) || - (mStencilAttachment.IsDefined() && !mStencilAttachment.HasSameDimensionsAs(mColorAttachments[0])) || - (mDepthStencilAttachment.IsDefined() && !mDepthStencilAttachment.HasSameDimensionsAs(mColorAttachments[0]))); -} - const WebGLFramebuffer::Attachment& -WebGLFramebuffer::GetAttachment(GLenum attachment) const { +WebGLFramebuffer::GetAttachment(GLenum attachment) const +{ if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) return mDepthStencilAttachment; if (attachment == LOCAL_GL_DEPTH_ATTACHMENT) @@ -359,8 +354,7 @@ WebGLFramebuffer::GetAttachment(GLenum attachment) const { return mColorAttachments[0]; } - uint32_t colorAttachmentId = uint32_t(attachment - LOCAL_GL_COLOR_ATTACHMENT0); - + size_t colorAttachmentId = attachment - LOCAL_GL_COLOR_ATTACHMENT0; if (colorAttachmentId >= mColorAttachments.Length()) { MOZ_ASSERT(false); return mColorAttachments[0]; @@ -370,10 +364,9 @@ WebGLFramebuffer::GetAttachment(GLenum attachment) const { } void -WebGLFramebuffer::DetachTexture(const WebGLTexture *tex) { - int32_t colorAttachmentCount = mColorAttachments.Length(); - - for (int32_t i = 0; i < colorAttachmentCount; i++) { +WebGLFramebuffer::DetachTexture(const WebGLTexture* tex) +{ + for (size_t i = 0; i < mColorAttachments.Length(); i++) { if (mColorAttachments[i].Texture() == tex) { FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_TEXTURE_2D, nullptr, 0); // a texture might be attached more that once while editing the framebuffer @@ -389,10 +382,9 @@ WebGLFramebuffer::DetachTexture(const WebGLTexture *tex) { } void -WebGLFramebuffer::DetachRenderbuffer(const WebGLRenderbuffer *rb) { - int32_t colorAttachmentCount = mColorAttachments.Length(); - - for (int32_t i = 0; i < colorAttachmentCount; i++) { +WebGLFramebuffer::DetachRenderbuffer(const WebGLRenderbuffer* rb) +{ + for (size_t i = 0; i < mColorAttachments.Length(); i++) { if (mColorAttachments[0].Renderbuffer() == rb) { FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_RENDERBUFFER, nullptr); // a renderbuffer might be attached more that once while editing the framebuffer @@ -408,62 +400,191 @@ WebGLFramebuffer::DetachRenderbuffer(const WebGLRenderbuffer *rb) { } bool -WebGLFramebuffer::CheckAndInitializeAttachments() +WebGLFramebuffer::HasDefinedAttachments() const +{ + bool hasAttachments = false; + + for (size_t i = 0; i < mColorAttachments.Length(); i++) { + hasAttachments |= mColorAttachments[i].IsDefined(); + } + + hasAttachments |= mDepthAttachment.IsDefined(); + hasAttachments |= mStencilAttachment.IsDefined(); + hasAttachments |= mDepthStencilAttachment.IsDefined(); + + return hasAttachments; +} + + +static bool +IsIncomplete(const WebGLFramebuffer::Attachment& cur) +{ + return cur.IsDefined() && !cur.IsComplete(); +} + +bool +WebGLFramebuffer::HasIncompleteAttachments() const +{ + bool hasIncomplete = false; + + for (size_t i = 0; i < mColorAttachments.Length(); i++) { + hasIncomplete |= IsIncomplete(mColorAttachments[i]); + } + + hasIncomplete |= IsIncomplete(mDepthAttachment); + hasIncomplete |= IsIncomplete(mStencilAttachment); + hasIncomplete |= IsIncomplete(mDepthStencilAttachment); + + return hasIncomplete; +} + + +const WebGLRectangleObject& +WebGLFramebuffer::GetAnyRectObject() const +{ + MOZ_ASSERT(HasDefinedAttachments()); + + for (size_t i = 0; i < mColorAttachments.Length(); i++) { + if (mColorAttachments[i].HasImage()) + return mColorAttachments[i].RectangleObject(); + } + + if (mDepthAttachment.HasImage()) + return mDepthAttachment.RectangleObject(); + + if (mStencilAttachment.HasImage()) + return mStencilAttachment.RectangleObject(); + + if (mDepthStencilAttachment.HasImage()) + return mDepthStencilAttachment.RectangleObject(); + + MOZ_CRASH("Should not get here."); +} + + +static bool +RectsMatch(const WebGLFramebuffer::Attachment& attachment, + const WebGLRectangleObject& rect) +{ + return attachment.RectangleObject().HasSameDimensionsAs(rect); +} + +bool +WebGLFramebuffer::AllImageRectsMatch() const +{ + MOZ_ASSERT(HasDefinedAttachments()); + MOZ_ASSERT(!HasIncompleteAttachments()); + + const WebGLRectangleObject& rect = GetAnyRectObject(); + + // Alright, we have *a* rect, let's check all the others. + bool imageRectsMatch = true; + + for (size_t i = 0; i < mColorAttachments.Length(); i++) { + if (mColorAttachments[i].HasImage()) + imageRectsMatch &= RectsMatch(mColorAttachments[i], rect); + } + + if (mDepthAttachment.HasImage()) + imageRectsMatch &= RectsMatch(mDepthAttachment, rect); + + if (mStencilAttachment.HasImage()) + imageRectsMatch &= RectsMatch(mStencilAttachment, rect); + + if (mDepthStencilAttachment.HasImage()) + imageRectsMatch &= RectsMatch(mDepthStencilAttachment, rect); + + return imageRectsMatch; +} + + +const WebGLRectangleObject& +WebGLFramebuffer::RectangleObject() const +{ + // If we're using this as the RectObj of an FB, we need to be sure the FB + // has a consistent rect. + MOZ_ASSERT(AllImageRectsMatch(), "Did you mean `GetAnyRectObject`?"); + return GetAnyRectObject(); +} + +GLenum +WebGLFramebuffer::PrecheckFramebufferStatus() const { MOZ_ASSERT(mContext->mBoundFramebuffer == this); - // enforce WebGL section 6.5 which is WebGL-specific, hence OpenGL itself would not - // generate the INVALID_FRAMEBUFFER_OPERATION that we need here + + if (!HasDefinedAttachments()) + return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; // No attachments + + if (HasIncompleteAttachments()) + return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + + if (!AllImageRectsMatch()) + return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; // No consistent size + if (HasDepthStencilConflict()) - return false; + return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED; - if (HasIncompleteAttachment()) - return false; + return LOCAL_GL_FRAMEBUFFER_COMPLETE; +} +GLenum +WebGLFramebuffer::CheckFramebufferStatus() const +{ + GLenum precheckStatus = PrecheckFramebufferStatus(); + if (precheckStatus != LOCAL_GL_FRAMEBUFFER_COMPLETE) + return precheckStatus; + + // Looks good on our end. Let's ask the driver. mContext->MakeContextCurrent(); // Ok, attach our chosen flavor of {DEPTH, STENCIL, DEPTH_STENCIL}. FinalizeAttachments(); + return mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); +} + + + +bool +WebGLFramebuffer::CheckAndInitializeAttachments() +{ + MOZ_ASSERT(mContext->mBoundFramebuffer == this); + + if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE) + return false; + + // Cool! We've checked out ok. Just need to initialize. size_t colorAttachmentCount = size_t(mColorAttachments.Length()); + // Check if we need to initialize anything { - bool hasUnitializedAttachments = false; + bool hasUninitializedAttachments = false; for (size_t i = 0; i < colorAttachmentCount; i++) { - hasUnitializedAttachments |= mColorAttachments[i].HasUninitializedImageData(); + if (mColorAttachments[i].HasImage()) + hasUninitializedAttachments |= mColorAttachments[i].HasUninitializedImageData(); } - if (!hasUnitializedAttachments && - !mDepthAttachment.HasUninitializedImageData() && - !mStencilAttachment.HasUninitializedImageData() && - !mDepthStencilAttachment.HasUninitializedImageData()) - { + if (mDepthAttachment.HasImage()) + hasUninitializedAttachments |= mDepthAttachment.HasUninitializedImageData(); + if (mStencilAttachment.HasImage()) + hasUninitializedAttachments |= mStencilAttachment.HasUninitializedImageData(); + if (mDepthStencilAttachment.HasImage()) + hasUninitializedAttachments |= mDepthStencilAttachment.HasUninitializedImageData(); + + if (!hasUninitializedAttachments) return true; - } } - // ensure INVALID_FRAMEBUFFER_OPERATION in zero-size case - const WebGLRectangleObject *rect = mColorAttachments[0].RectangleObject(); - if (!rect || - !rect->Width() || - !rect->Height()) - return false; - - GLenum status = mContext->CheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); - if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) - return false; - + // Get buffer-bit-mask and color-attachment-mask-list uint32_t mask = 0; bool colorAttachmentsMask[WebGLContext::sMaxColorAttachments] = { false }; + MOZ_ASSERT(colorAttachmentCount <= WebGLContext::sMaxColorAttachments); - MOZ_ASSERT( colorAttachmentCount <= WebGLContext::sMaxColorAttachments ); - - for (size_t i = 0; i < colorAttachmentCount; i++) - { - colorAttachmentsMask[i] = mColorAttachments[i].HasUninitializedImageData(); - - if (colorAttachmentsMask[i]) { - mask |= LOCAL_GL_COLOR_BUFFER_BIT; + for (size_t i = 0; i < colorAttachmentCount; i++) { + if (mColorAttachments[i].HasUninitializedImageData()) { + colorAttachmentsMask[i] = true; + mask |= LOCAL_GL_COLOR_BUFFER_BIT; } } @@ -479,10 +600,11 @@ WebGLFramebuffer::CheckAndInitializeAttachments() mask |= LOCAL_GL_STENCIL_BUFFER_BIT; } + // Clear! mContext->ForceClearFramebufferWithDefaultValues(mask, colorAttachmentsMask); - for (size_t i = 0; i < colorAttachmentCount; i++) - { + // Mark all the uninitialized images as initialized. + for (size_t i = 0; i < colorAttachmentCount; i++) { if (mColorAttachments[i].HasUninitializedImageData()) mColorAttachments[i].SetImageDataStatus(WebGLImageDataStatus::InitializedImageData); } @@ -497,30 +619,25 @@ WebGLFramebuffer::CheckAndInitializeAttachments() return true; } -bool WebGLFramebuffer::CheckColorAttachementNumber(GLenum attachment, const char * functionName) const +bool WebGLFramebuffer::CheckColorAttachementNumber(GLenum attachment, const char* functionName) const { const char* const errorFormating = "%s: attachment: invalid enum value 0x%x"; - if (mContext->IsExtensionEnabled(WebGLContext::WEBGL_draw_buffers)) - { + if (mContext->IsExtensionEnabled(WebGLContext::WEBGL_draw_buffers)) { if (attachment < LOCAL_GL_COLOR_ATTACHMENT0 || attachment >= GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + mContext->mGLMaxColorAttachments)) { mContext->ErrorInvalidEnum(errorFormating, functionName, attachment); return false; } - } - else if (attachment != LOCAL_GL_COLOR_ATTACHMENT0) - { + } else if (attachment != LOCAL_GL_COLOR_ATTACHMENT0) { if (attachment > LOCAL_GL_COLOR_ATTACHMENT0 && attachment <= LOCAL_GL_COLOR_ATTACHMENT15) { mContext->ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x. " "Try the WEBGL_draw_buffers extension if supported.", functionName, attachment); return false; - } - else - { + } else { mContext->ErrorInvalidEnum(errorFormating, functionName, attachment); return false; } @@ -529,14 +646,13 @@ bool WebGLFramebuffer::CheckColorAttachementNumber(GLenum attachment, const char return true; } -void WebGLFramebuffer::EnsureColorAttachments(size_t colorAttachmentId) { +void WebGLFramebuffer::EnsureColorAttachments(size_t colorAttachmentId) +{ + MOZ_ASSERT(colorAttachmentId < WebGLContext::sMaxColorAttachments); + size_t currentAttachmentCount = mColorAttachments.Length(); - - if (mColorAttachments.Length() > colorAttachmentId) { + if (colorAttachmentId < currentAttachmentCount) return; - } - - MOZ_ASSERT( colorAttachmentId < WebGLContext::sMaxColorAttachments ); mColorAttachments.SetLength(colorAttachmentId + 1); @@ -546,7 +662,8 @@ void WebGLFramebuffer::EnsureColorAttachments(size_t colorAttachmentId) { } void -WebGLFramebuffer::FinalizeAttachments() const { +WebGLFramebuffer::FinalizeAttachments() const +{ for (size_t i = 0; i < ColorAttachmentCount(); i++) { if (ColorAttachment(i).IsDefined()) ColorAttachment(i).FinalizeAttachment(LOCAL_GL_COLOR_ATTACHMENT0 + i); diff --git a/content/canvas/src/WebGLFramebuffer.h b/content/canvas/src/WebGLFramebuffer.h index 033adb74d736..ef359ed52e2a 100644 --- a/content/canvas/src/WebGLFramebuffer.h +++ b/content/canvas/src/WebGLFramebuffer.h @@ -27,7 +27,7 @@ class WebGLFramebuffer MOZ_FINAL , public WebGLContextBoundObject { public: - WebGLFramebuffer(WebGLContext *context); + WebGLFramebuffer(WebGLContext* context); ~WebGLFramebuffer() { DeleteOnce(); @@ -54,21 +54,21 @@ public: bool HasAlpha() const; - void SetTexImage(WebGLTexture *tex, GLenum target, GLint level); - void SetRenderbuffer(WebGLRenderbuffer *rb) { + void SetTexImage(WebGLTexture* tex, GLenum target, GLint level); + void SetRenderbuffer(WebGLRenderbuffer* rb) { mTexturePtr = nullptr; mRenderbufferPtr = rb; } - const WebGLTexture *Texture() const { + const WebGLTexture* Texture() const { return mTexturePtr; } - WebGLTexture *Texture() { + WebGLTexture* Texture() { return mTexturePtr; } - const WebGLRenderbuffer *Renderbuffer() const { + const WebGLRenderbuffer* Renderbuffer() const { return mRenderbufferPtr; } - WebGLRenderbuffer *Renderbuffer() { + WebGLRenderbuffer* Renderbuffer() { return mRenderbufferPtr; } GLenum TexImageTarget() const { @@ -86,9 +86,9 @@ public: mRenderbufferPtr = nullptr; } - const WebGLRectangleObject* RectangleObject() const; - bool HasSameDimensionsAs(const Attachment& other) const; + const WebGLRectangleObject& RectangleObject() const; + bool HasImage() const; bool IsComplete() const; void FinalizeAttachment(GLenum attachmentLoc) const; @@ -103,15 +103,23 @@ public: void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum rbtarget, - WebGLRenderbuffer *wrb); + WebGLRenderbuffer* wrb); void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, - WebGLTexture *wtex, + WebGLTexture* wtex, GLint level); - bool HasIncompleteAttachment() const; +private: + const WebGLRectangleObject& GetAnyRectObject() const; + +public: + bool HasDefinedAttachments() const; + bool HasIncompleteAttachments() const; + bool AllImageRectsMatch() const; + GLenum PrecheckFramebufferStatus() const; + GLenum CheckFramebufferStatus() const; bool HasDepthStencilConflict() const { return int(mDepthAttachment.IsDefined()) + @@ -119,12 +127,10 @@ public: int(mDepthStencilAttachment.IsDefined()) >= 2; } - bool HasAttachmentsOfMismatchedDimensions() const; - - const size_t ColorAttachmentCount() const { + size_t ColorAttachmentCount() const { return mColorAttachments.Length(); } - const Attachment& ColorAttachment(uint32_t colorAttachmentId) const { + const Attachment& ColorAttachment(size_t colorAttachmentId) const { return mColorAttachments[colorAttachmentId]; } @@ -142,21 +148,19 @@ public: const Attachment& GetAttachment(GLenum attachment) const; - void DetachTexture(const WebGLTexture *tex); + void DetachTexture(const WebGLTexture* tex); - void DetachRenderbuffer(const WebGLRenderbuffer *rb); + void DetachRenderbuffer(const WebGLRenderbuffer* rb); - const WebGLRectangleObject *RectangleObject() { - return mColorAttachments[0].RectangleObject(); - } + const WebGLRectangleObject& RectangleObject() const; - WebGLContext *GetParentObject() const { + WebGLContext* GetParentObject() const { return Context(); } void FinalizeAttachments() const; - virtual JSObject* WrapObject(JSContext *cx, + virtual JSObject* WrapObject(JSContext* cx, JS::Handle scope) MOZ_OVERRIDE; NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer) @@ -164,7 +168,7 @@ public: bool CheckAndInitializeAttachments(); - bool CheckColorAttachementNumber(GLenum attachment, const char * functionName) const; + bool CheckColorAttachementNumber(GLenum attachment, const char* functionName) const; GLuint mGLName; bool mHasEverBeenBound;