From 39df8cb30e92fd90362223af85ef9718a888e43c Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Mon, 16 Mar 2015 18:22:17 -0700 Subject: [PATCH] Bug 1017865 - Refactor attach/detach for FB attachments. - r=kamidphish --- dom/canvas/WebGLContextGL.cpp | 22 +- dom/canvas/WebGLContextUtils.cpp | 2 + dom/canvas/WebGLFramebuffer.cpp | 564 ++++++++++------------ dom/canvas/WebGLFramebuffer.h | 97 ++-- dom/canvas/WebGLFramebufferAttachable.cpp | 35 +- dom/canvas/WebGLFramebufferAttachable.h | 30 +- dom/canvas/WebGLRenderbuffer.cpp | 2 + dom/canvas/WebGLTexture.cpp | 5 +- 8 files changed, 339 insertions(+), 418 deletions(-) diff --git a/dom/canvas/WebGLContextGL.cpp b/dom/canvas/WebGLContextGL.cpp index 6d1d85c6921c..e80fec56f177 100644 --- a/dom/canvas/WebGLContextGL.cpp +++ b/dom/canvas/WebGLContextGL.cpp @@ -714,12 +714,10 @@ WebGLContext::DeleteRenderbuffer(WebGLRenderbuffer* rbuf) if (mBoundReadFramebuffer) mBoundReadFramebuffer->DetachRenderbuffer(rbuf); - // Invalidate framebuffer status cache - rbuf->NotifyFBsStatusChanged(); + rbuf->InvalidateStatusOfAttachedFBs(); if (mBoundRenderbuffer == rbuf) - BindRenderbuffer(LOCAL_GL_RENDERBUFFER, - static_cast(nullptr)); + BindRenderbuffer(LOCAL_GL_RENDERBUFFER, nullptr); rbuf->RequestDelete(); } @@ -742,8 +740,7 @@ WebGLContext::DeleteTexture(WebGLTexture* tex) if (mBoundReadFramebuffer) mBoundReadFramebuffer->DetachTexture(tex); - // Invalidate framebuffer status cache - tex->NotifyFBsStatusChanged(); + tex->InvalidateStatusOfAttachedFBs(); GLuint activeTexture = mActiveTexture; for (int32_t i = 0; i < mGLMaxTextureUnits; i++) { @@ -752,7 +749,7 @@ WebGLContext::DeleteTexture(WebGLTexture* tex) (mBound3DTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_3D)) { ActiveTexture(LOCAL_GL_TEXTURE0 + i); - BindTexture(tex->Target().get(), static_cast(nullptr)); + BindTexture(tex->Target().get(), nullptr); } } ActiveTexture(LOCAL_GL_TEXTURE0 + activeTexture); @@ -868,11 +865,8 @@ WebGLContext::FramebufferRenderbuffer(GLenum target, GLenum attachment, rbtarget); } - if (!ValidateFramebufferAttachment(fb, attachment, - "framebufferRenderbuffer")) - { + if (!ValidateFramebufferAttachment(fb, attachment, "framebufferRenderbuffer")) return; - } fb->FramebufferRenderbuffer(attachment, rbtarget, wrb); } @@ -1141,11 +1135,11 @@ WebGLContext::GetFramebufferAttachmentParameter(JSContext* cx, } if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) - fb->EnsureColorAttachments(attachment - LOCAL_GL_COLOR_ATTACHMENT0); + fb->EnsureColorAttachPoints(attachment - LOCAL_GL_COLOR_ATTACHMENT0); MakeContextCurrent(); - const WebGLFramebuffer::Attachment& fba = fb->GetAttachment(attachment); + const WebGLFramebuffer::AttachPoint& fba = fb->GetAttachPoint(attachment); if (fba.Renderbuffer()) { switch (pname) { @@ -2324,8 +2318,6 @@ WebGLContext::RenderbufferStorage_base(const char* funcName, GLenum target, height != mBoundRenderbuffer->Height(); if (willRealloc) { - // Invalidate framebuffer status cache - mBoundRenderbuffer->NotifyFBsStatusChanged(); GetAndFlushUnderlyingGLErrors(); mBoundRenderbuffer->RenderbufferStorage(samples, internalFormatForGL, width, height); diff --git a/dom/canvas/WebGLContextUtils.cpp b/dom/canvas/WebGLContextUtils.cpp index 2666662b9861..626609025037 100644 --- a/dom/canvas/WebGLContextUtils.cpp +++ b/dom/canvas/WebGLContextUtils.cpp @@ -604,6 +604,7 @@ WebGLContext::EnumName(GLenum glenum) XX(COMPRESSED_RGB_PVRTC_2BPPV1); XX(COMPRESSED_RGB_PVRTC_4BPPV1); XX(COMPRESSED_RGB_S3TC_DXT1_EXT); + XX(DEPTH_ATTACHMENT); XX(DEPTH_COMPONENT); XX(DEPTH_COMPONENT16); XX(DEPTH_COMPONENT32); @@ -789,6 +790,7 @@ WebGLContext::EnumName(GLenum glenum) XX(RENDERBUFFER_SAMPLES); XX(FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER); XX(MAX_COLOR_ATTACHMENTS); + XX(COLOR_ATTACHMENT0); XX(COLOR_ATTACHMENT1); XX(COLOR_ATTACHMENT2); XX(COLOR_ATTACHMENT3); diff --git a/dom/canvas/WebGLFramebuffer.cpp b/dom/canvas/WebGLFramebuffer.cpp index 59988937b7f6..c34f378d5513 100644 --- a/dom/canvas/WebGLFramebuffer.cpp +++ b/dom/canvas/WebGLFramebuffer.cpp @@ -15,45 +15,21 @@ namespace mozilla { -JSObject* -WebGLFramebuffer::WrapObject(JSContext* cx) -{ - return dom::WebGLFramebufferBinding::Wrap(cx, this); -} - -WebGLFramebuffer::WebGLFramebuffer(WebGLContext* webgl, GLuint fbo) - : WebGLBindableName(fbo) - , WebGLContextBoundObject(webgl) - , mStatus(0) - , mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT) - , mStencilAttachment(LOCAL_GL_STENCIL_ATTACHMENT) - , mDepthStencilAttachment(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) - , mReadBufferMode(LOCAL_GL_COLOR_ATTACHMENT0) -{ - mContext->mFramebuffers.insertBack(this); - - mColorAttachments.SetLength(1); - mColorAttachments[0].mAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0; -} - -WebGLFramebuffer::Attachment::Attachment(FBAttachment attachmentPoint) - : mAttachmentPoint(attachmentPoint) +WebGLFramebuffer::AttachPoint::AttachPoint(WebGLFramebuffer* fb, + FBAttachment attachmentPoint) + : mFB(fb) + , mAttachmentPoint(attachmentPoint) , mTexImageTarget(LOCAL_GL_NONE) - , mNeedsFinalize(false) {} -WebGLFramebuffer::Attachment::~Attachment() -{} - -void -WebGLFramebuffer::Attachment::Reset() +WebGLFramebuffer::AttachPoint::~AttachPoint() { - mTexturePtr = nullptr; - mRenderbufferPtr = nullptr; + MOZ_ASSERT(!mRenderbufferPtr); + MOZ_ASSERT(!mTexturePtr); } bool -WebGLFramebuffer::Attachment::IsDeleteRequested() const +WebGLFramebuffer::AttachPoint::IsDeleteRequested() const { return Texture() ? Texture()->IsDeleteRequested() : Renderbuffer() ? Renderbuffer()->IsDeleteRequested() @@ -61,14 +37,14 @@ WebGLFramebuffer::Attachment::IsDeleteRequested() const } bool -WebGLFramebuffer::Attachment::IsDefined() const +WebGLFramebuffer::AttachPoint::IsDefined() const { return Renderbuffer() || (Texture() && Texture()->HasImageInfoAt(ImageTarget(), 0)); } bool -WebGLFramebuffer::Attachment::HasAlpha() const +WebGLFramebuffer::AttachPoint::HasAlpha() const { MOZ_ASSERT(HasImage()); @@ -86,7 +62,7 @@ WebGLFramebuffer::Attachment::HasAlpha() const } GLenum -WebGLFramebuffer::GetFormatForAttachment(const WebGLFramebuffer::Attachment& attachment) const +WebGLFramebuffer::GetFormatForAttachment(const WebGLFramebuffer::AttachPoint& attachment) const { MOZ_ASSERT(attachment.IsDefined()); MOZ_ASSERT(attachment.Texture() || attachment.Renderbuffer()); @@ -107,7 +83,7 @@ WebGLFramebuffer::GetFormatForAttachment(const WebGLFramebuffer::Attachment& att } TexInternalFormat -WebGLFramebuffer::Attachment::EffectiveInternalFormat() const +WebGLFramebuffer::AttachPoint::EffectiveInternalFormat() const { const WebGLTexture* tex = Texture(); if (tex && tex->HasImageInfoAt(mTexImageTarget, mTexImageLevel)) { @@ -123,7 +99,7 @@ WebGLFramebuffer::Attachment::EffectiveInternalFormat() const } bool -WebGLFramebuffer::Attachment::IsReadableFloat() const +WebGLFramebuffer::AttachPoint::IsReadableFloat() const { TexInternalFormat internalformat = EffectiveInternalFormat(); MOZ_ASSERT(internalformat != LOCAL_GL_NONE); @@ -133,29 +109,50 @@ WebGLFramebuffer::Attachment::IsReadableFloat() const type == LOCAL_GL_HALF_FLOAT; } -void -WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture* tex, - TexImageTarget target, GLint level) +static void +UnmarkAttachment(WebGLFramebuffer::AttachPoint& attachment) { + WebGLFramebufferAttachable* maybe = attachment.Texture(); + if (!maybe) + maybe = attachment.Renderbuffer(); + + if (maybe) + maybe->UnmarkAttachment(attachment); +} + +void +WebGLFramebuffer::AttachPoint::SetTexImage(WebGLTexture* tex, TexImageTarget target, + GLint level) +{ + mFB->InvalidateFramebufferStatus(); + + UnmarkAttachment(*this); + mTexturePtr = tex; mRenderbufferPtr = nullptr; mTexImageTarget = target; mTexImageLevel = level; - mNeedsFinalize = true; + if (tex) + tex->MarkAttachment(*this); } void -WebGLFramebuffer::Attachment::SetRenderbuffer(WebGLRenderbuffer* rb) +WebGLFramebuffer::AttachPoint::SetRenderbuffer(WebGLRenderbuffer* rb) { + mFB->InvalidateFramebufferStatus(); + + UnmarkAttachment(*this); + mTexturePtr = nullptr; mRenderbufferPtr = rb; - mNeedsFinalize = true; + if (rb) + rb->MarkAttachment(*this); } bool -WebGLFramebuffer::Attachment::HasUninitializedImageData() const +WebGLFramebuffer::AttachPoint::HasUninitializedImageData() const { if (!HasImage()) return false; @@ -174,7 +171,7 @@ WebGLFramebuffer::Attachment::HasUninitializedImageData() const } void -WebGLFramebuffer::Attachment::SetImageDataStatus(WebGLImageDataStatus newStatus) +WebGLFramebuffer::AttachPoint::SetImageDataStatus(WebGLImageDataStatus newStatus) { if (!HasImage()) return; @@ -194,7 +191,7 @@ WebGLFramebuffer::Attachment::SetImageDataStatus(WebGLImageDataStatus newStatus) } bool -WebGLFramebuffer::Attachment::HasImage() const +WebGLFramebuffer::AttachPoint::HasImage() const { if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel)) return true; @@ -206,7 +203,7 @@ WebGLFramebuffer::Attachment::HasImage() const } const WebGLRectangleObject& -WebGLFramebuffer::Attachment::RectangleObject() const +WebGLFramebuffer::AttachPoint::RectangleObject() const { MOZ_ASSERT(HasImage(), "Make sure it has an image before requesting the rectangle."); @@ -288,7 +285,7 @@ WebGLContext::IsFormatValidForFB(GLenum sizedFormat) const } bool -WebGLFramebuffer::Attachment::IsComplete() const +WebGLFramebuffer::AttachPoint::IsComplete() const { if (!HasImage()) return false; @@ -356,26 +353,20 @@ WebGLFramebuffer::Attachment::IsComplete() const } void -WebGLFramebuffer::Attachment::FinalizeAttachment(gl::GLContext* gl, +WebGLFramebuffer::AttachPoint::FinalizeAttachment(gl::GLContext* gl, FBAttachment attachmentLoc) const { - if (!mNeedsFinalize) - return; - - mNeedsFinalize = false; - if (!HasImage()) { - if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) { - gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_DEPTH_ATTACHMENT, - LOCAL_GL_RENDERBUFFER, 0); - gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_STENCIL_ATTACHMENT, - LOCAL_GL_RENDERBUFFER, 0); - } else { - gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, - attachmentLoc.get(), + switch (attachmentLoc.get()) { + case LOCAL_GL_DEPTH_ATTACHMENT: + case LOCAL_GL_STENCIL_ATTACHMENT: + case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT: + break; + + default: + gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachmentLoc.get(), LOCAL_GL_RENDERBUFFER, 0); + break; } return; @@ -390,12 +381,10 @@ WebGLFramebuffer::Attachment::FinalizeAttachment(gl::GLContext* gl, const GLuint glName = Texture()->GLName(); if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) { - gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_DEPTH_ATTACHMENT, imageTarget, - glName, mipLevel); - gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_STENCIL_ATTACHMENT, imageTarget, - glName, mipLevel); + gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, + imageTarget, glName, mipLevel); + gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, + imageTarget, glName, mipLevel); } else { gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachmentLoc.get(), imageTarget, glName, mipLevel); @@ -408,17 +397,37 @@ WebGLFramebuffer::Attachment::FinalizeAttachment(gl::GLContext* gl, return; } - MOZ_ASSERT(false, "Should not get here."); + MOZ_CRASH(); +} + +//////////////////////////////////////////////////////////////////////////////// +// WebGLFramebuffer + +WebGLFramebuffer::WebGLFramebuffer(WebGLContext* webgl, GLuint fbo) + : WebGLBindableName(fbo) + , WebGLContextBoundObject(webgl) + , mStatus(0) + , mReadBufferMode(LOCAL_GL_COLOR_ATTACHMENT0) + , mColorAttachment0(this, LOCAL_GL_COLOR_ATTACHMENT0) + , mDepthAttachment(this, LOCAL_GL_DEPTH_ATTACHMENT) + , mStencilAttachment(this, LOCAL_GL_STENCIL_ATTACHMENT) + , mDepthStencilAttachment(this, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) +{ + mContext->mFramebuffers.insertBack(this); } void WebGLFramebuffer::Delete() { - DetachAllAttachments(); - mColorAttachments.Clear(); - mDepthAttachment.Reset(); - mStencilAttachment.Reset(); - mDepthStencilAttachment.Reset(); + mColorAttachment0.Clear(); + mDepthAttachment.Clear(); + mStencilAttachment.Clear(); + mDepthStencilAttachment.Clear(); + + const size_t moreColorAttachmentCount = mMoreColorAttachments.Length(); + for (size_t i = 0; i < moreColorAttachmentCount; i++) { + mMoreColorAttachments[i].Clear(); + } mContext->MakeContextCurrent(); mContext->gl->fDeleteFramebuffers(1, &mGLName); @@ -426,84 +435,33 @@ WebGLFramebuffer::Delete() } void -WebGLFramebuffer::DetachAttachment(WebGLFramebuffer::Attachment& attachment) -{ - if (attachment.Texture()) - attachment.Texture()->DetachFrom(this, attachment.mAttachmentPoint); - - if (attachment.Renderbuffer()) { - attachment.Renderbuffer()->DetachFrom(this, - attachment.mAttachmentPoint); - } -} - -void -WebGLFramebuffer::DetachAllAttachments() -{ - for (size_t i = 0; i < mColorAttachments.Length(); i++) { - DetachAttachment(mColorAttachments[i]); - } - - DetachAttachment(mDepthAttachment); - DetachAttachment(mStencilAttachment); - DetachAttachment(mDepthStencilAttachment); -} - -void -WebGLFramebuffer::FramebufferRenderbuffer(FBAttachment attachPoint, +WebGLFramebuffer::FramebufferRenderbuffer(FBAttachment attachPointEnum, RBTarget rbtarget, WebGLRenderbuffer* rb) { MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this || mContext->mBoundReadFramebuffer == this); - if (!mContext->ValidateObjectAllowNull("framebufferRenderbuffer: renderbuffer", - rb)) - { + if (!mContext->ValidateObjectAllowNull("framebufferRenderbuffer: renderbuffer", rb)) return; - } - /* Get the requested attachment. If result is NULL, attachment is invalid - * and an error is generated. - * - * Don't use GetAttachment(...) here because it opt builds it returns - * mColorAttachment[0] for invalid attachment, which we really don't want to - * mess with. - */ - Attachment* attachment = GetAttachmentOrNull(attachPoint); - if (!attachment) - return; // Error generated internally to GetAttachmentOrNull. + // `attachPoint` is validated by ValidateFramebufferAttachment(). + AttachPoint& attachPoint = GetAttachPoint(attachPointEnum); + attachPoint.SetRenderbuffer(rb); - // Invalidate cached framebuffer status and inform texture of its new - // attachment. - mStatus = 0; - - // Detach current: - if (attachment->Texture()) - attachment->Texture()->DetachFrom(this, attachPoint); - else if (attachment->Renderbuffer()) - attachment->Renderbuffer()->DetachFrom(this, attachPoint); - - // Attach new: - if (rb) - rb->AttachTo(this, attachPoint); - - attachment->SetRenderbuffer(rb); + InvalidateFramebufferStatus(); } void -WebGLFramebuffer::FramebufferTexture2D(FBAttachment attachPoint, +WebGLFramebuffer::FramebufferTexture2D(FBAttachment attachPointEnum, TexImageTarget texImageTarget, WebGLTexture* tex, GLint level) { MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this || mContext->mBoundReadFramebuffer == this); - if (!mContext->ValidateObjectAllowNull("framebufferTexture2D: texture", - tex)) - { + if (!mContext->ValidateObjectAllowNull("framebufferTexture2D: texture", tex)) return; - } if (tex) { bool isTexture2D = tex->Target() == LOCAL_GL_TEXTURE_2D; @@ -520,67 +478,19 @@ WebGLFramebuffer::FramebufferTexture2D(FBAttachment attachPoint, return; } - /* Get the requested attachment. If result is NULL, attachment is invalid - * and an error is generated. - * - * Don't use GetAttachment(...) here because it opt builds it returns - * mColorAttachment[0] for invalid attachment, which we really don't want to - * mess with. - */ - Attachment* attachment = GetAttachmentOrNull(attachPoint); - if (!attachment) - return; // Error generated internally to GetAttachmentOrNull. + AttachPoint& attachPoint = GetAttachPoint(attachPointEnum); + attachPoint.SetTexImage(tex, texImageTarget, level); - // Invalidate cached framebuffer status and inform texture of its new - // attachment. - mStatus = 0; - - // Detach current: - if (attachment->Texture()) - attachment->Texture()->DetachFrom(this, attachPoint); - else if (attachment->Renderbuffer()) - attachment->Renderbuffer()->DetachFrom(this, attachPoint); - - // Attach new: - if (tex) - tex->AttachTo(this, attachPoint); - - attachment->SetTexImage(tex, texImageTarget, level); + InvalidateFramebufferStatus(); } -WebGLFramebuffer::Attachment* -WebGLFramebuffer::GetAttachmentOrNull(FBAttachment attachPoint) +WebGLFramebuffer::AttachPoint& +WebGLFramebuffer::GetAttachPoint(FBAttachment attachPoint) { switch (attachPoint.get()) { - case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT: - return &mDepthStencilAttachment; + case LOCAL_GL_COLOR_ATTACHMENT0: + return mColorAttachment0; - case LOCAL_GL_DEPTH_ATTACHMENT: - return &mDepthAttachment; - - case LOCAL_GL_STENCIL_ATTACHMENT: - return &mStencilAttachment; - - default: - break; - } - - if (!mContext->ValidateFramebufferAttachment(this, attachPoint.get(), - "getAttachmentOrNull")) - { - return nullptr; - } - - size_t colorAttachmentId = attachPoint.get() - LOCAL_GL_COLOR_ATTACHMENT0; - EnsureColorAttachments(colorAttachmentId); - - return &mColorAttachments[colorAttachmentId]; -} - -const WebGLFramebuffer::Attachment& -WebGLFramebuffer::GetAttachment(FBAttachment attachPoint) const -{ - switch (attachPoint.get()) { case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT: return mDepthStencilAttachment; @@ -594,69 +504,58 @@ WebGLFramebuffer::GetAttachment(FBAttachment attachPoint) const break; } - if (!mContext->ValidateFramebufferAttachment(this, attachPoint.get(), - "getAttachment")) - { - MOZ_ASSERT(false); - return mColorAttachments[0]; + if (attachPoint >= LOCAL_GL_COLOR_ATTACHMENT1) { + size_t moreColorAttachmentId = attachPoint.get() - LOCAL_GL_COLOR_ATTACHMENT1; + if (1 + moreColorAttachmentId < WebGLContext::kMaxColorAttachments) { + EnsureColorAttachPoints(1 + moreColorAttachmentId); + return mMoreColorAttachments[moreColorAttachmentId]; + } } - size_t colorAttachmentId = attachPoint.get() - LOCAL_GL_COLOR_ATTACHMENT0; - if (colorAttachmentId >= mColorAttachments.Length()) { - MOZ_ASSERT(false); - return mColorAttachments[0]; - } - - return mColorAttachments[colorAttachmentId]; + MOZ_CRASH("bad `attachPoint` validation"); } void WebGLFramebuffer::DetachTexture(const WebGLTexture* tex) { - for (size_t i = 0; i < (size_t)mColorAttachments.Length(); i++) { - if (mColorAttachments[i].Texture() == tex) { - FramebufferTexture2D(LOCAL_GL_COLOR_ATTACHMENT0+i, - LOCAL_GL_TEXTURE_2D, nullptr, 0); - // It might be attached in multiple places, so don't break. - } - } + if (mColorAttachment0.Texture() == tex) + mColorAttachment0.Clear(); - if (mDepthAttachment.Texture() == tex) { - FramebufferTexture2D(LOCAL_GL_DEPTH_ATTACHMENT, LOCAL_GL_TEXTURE_2D, - nullptr, 0); - } - if (mStencilAttachment.Texture() == tex) { - FramebufferTexture2D(LOCAL_GL_STENCIL_ATTACHMENT, LOCAL_GL_TEXTURE_2D, - nullptr, 0); - } - if (mDepthStencilAttachment.Texture() == tex) { - FramebufferTexture2D(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT, - LOCAL_GL_TEXTURE_2D, nullptr, 0); + if (mDepthAttachment.Texture() == tex) + mDepthAttachment.Clear(); + + if (mStencilAttachment.Texture() == tex) + mStencilAttachment.Clear(); + + if (mDepthStencilAttachment.Texture() == tex) + mDepthStencilAttachment.Clear(); + + const size_t moreColorAttachmentCount = mMoreColorAttachments.Length(); + for (size_t i = 0; i < moreColorAttachmentCount; i++) { + if (mMoreColorAttachments[i].Texture() == tex) + mMoreColorAttachments[i].Clear(); } } void WebGLFramebuffer::DetachRenderbuffer(const WebGLRenderbuffer* rb) { - for (size_t i = 0; i < (size_t)mColorAttachments.Length(); i++) { - if (mColorAttachments[i].Renderbuffer() == rb) { - FramebufferRenderbuffer(LOCAL_GL_COLOR_ATTACHMENT0+i, - LOCAL_GL_RENDERBUFFER, nullptr); - // It might be attached in multiple places, so don't break. - } - } + if (mColorAttachment0.Renderbuffer() == rb) + mColorAttachment0.Clear(); - if (mDepthAttachment.Renderbuffer() == rb) { - FramebufferRenderbuffer(LOCAL_GL_DEPTH_ATTACHMENT, - LOCAL_GL_RENDERBUFFER, nullptr); - } - if (mStencilAttachment.Renderbuffer() == rb) { - FramebufferRenderbuffer(LOCAL_GL_STENCIL_ATTACHMENT, - LOCAL_GL_RENDERBUFFER, nullptr); - } - if (mDepthStencilAttachment.Renderbuffer() == rb) { - FramebufferRenderbuffer(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT, - LOCAL_GL_RENDERBUFFER, nullptr); + if (mDepthAttachment.Renderbuffer() == rb) + mDepthAttachment.Clear(); + + if (mStencilAttachment.Renderbuffer() == rb) + mStencilAttachment.Clear(); + + if (mDepthStencilAttachment.Renderbuffer() == rb) + mDepthStencilAttachment.Clear(); + + const size_t moreColorAttachmentCount = mMoreColorAttachments.Length(); + for (size_t i = 0; i < moreColorAttachmentCount; i++) { + if (mMoreColorAttachments[i].Renderbuffer() == rb) + mMoreColorAttachments[i].Clear(); } } @@ -665,19 +564,21 @@ WebGLFramebuffer::HasDefinedAttachments() const { bool hasAttachments = false; - for (size_t i = 0; i < (size_t)mColorAttachments.Length(); i++) { - hasAttachments |= mColorAttachments[i].IsDefined(); - } - + hasAttachments |= mColorAttachment0.IsDefined(); hasAttachments |= mDepthAttachment.IsDefined(); hasAttachments |= mStencilAttachment.IsDefined(); hasAttachments |= mDepthStencilAttachment.IsDefined(); + const size_t moreColorAttachmentCount = mMoreColorAttachments.Length(); + for (size_t i = 0; i < moreColorAttachmentCount; i++) { + hasAttachments |= mMoreColorAttachments[i].IsDefined(); + } + return hasAttachments; } static bool -IsIncomplete(const WebGLFramebuffer::Attachment& cur) +IsIncomplete(const WebGLFramebuffer::AttachPoint& cur) { return cur.IsDefined() && !cur.IsComplete(); } @@ -687,14 +588,16 @@ WebGLFramebuffer::HasIncompleteAttachments() const { bool hasIncomplete = false; - for (size_t i = 0; i < (size_t)mColorAttachments.Length(); i++) { - hasIncomplete |= IsIncomplete(mColorAttachments[i]); - } - + hasIncomplete |= IsIncomplete(mColorAttachment0); hasIncomplete |= IsIncomplete(mDepthAttachment); hasIncomplete |= IsIncomplete(mStencilAttachment); hasIncomplete |= IsIncomplete(mDepthStencilAttachment); + const size_t moreColorAttachmentCount = mMoreColorAttachments.Length(); + for (size_t i = 0; i < moreColorAttachmentCount; i++) { + hasIncomplete |= IsIncomplete(mMoreColorAttachments[i]); + } + return hasIncomplete; } @@ -703,10 +606,8 @@ WebGLFramebuffer::GetAnyRectObject() const { MOZ_ASSERT(HasDefinedAttachments()); - for (size_t i = 0; i < (size_t)mColorAttachments.Length(); i++) { - if (mColorAttachments[i].HasImage()) - return mColorAttachments[i].RectangleObject(); - } + if (mColorAttachment0.HasImage()) + return mColorAttachment0.RectangleObject(); if (mDepthAttachment.HasImage()) return mDepthAttachment.RectangleObject(); @@ -717,11 +618,17 @@ WebGLFramebuffer::GetAnyRectObject() const if (mDepthStencilAttachment.HasImage()) return mDepthStencilAttachment.RectangleObject(); + const size_t moreColorAttachmentCount = mMoreColorAttachments.Length(); + for (size_t i = 0; i < moreColorAttachmentCount; i++) { + if (mMoreColorAttachments[i].HasImage()) + return mMoreColorAttachments[i].RectangleObject(); + } + MOZ_CRASH("Should not get here."); } static bool -RectsMatch(const WebGLFramebuffer::Attachment& attachment, +RectsMatch(const WebGLFramebuffer::AttachPoint& attachment, const WebGLRectangleObject& rect) { return attachment.RectangleObject().HasSameDimensionsAs(rect); @@ -738,10 +645,8 @@ WebGLFramebuffer::AllImageRectsMatch() const // Alright, we have *a* rect, let's check all the others. bool imageRectsMatch = true; - for (size_t i = 0; i < (size_t)mColorAttachments.Length(); i++) { - if (mColorAttachments[i].HasImage()) - imageRectsMatch &= RectsMatch(mColorAttachments[i], rect); - } + if (mColorAttachment0.HasImage()) + imageRectsMatch &= RectsMatch(mColorAttachment0, rect); if (mDepthAttachment.HasImage()) imageRectsMatch &= RectsMatch(mDepthAttachment, rect); @@ -752,6 +657,12 @@ WebGLFramebuffer::AllImageRectsMatch() const if (mDepthStencilAttachment.HasImage()) imageRectsMatch &= RectsMatch(mDepthStencilAttachment, rect); + const size_t moreColorAttachmentCount = mMoreColorAttachments.Length(); + for (size_t i = 0; i < moreColorAttachmentCount; i++) { + if (mMoreColorAttachments[i].HasImage()) + imageRectsMatch &= RectsMatch(mMoreColorAttachments[i], rect); + } + return imageRectsMatch; } @@ -816,19 +727,17 @@ WebGLFramebuffer::HasCompletePlanes(GLbitfield mask) mContext->mBoundReadFramebuffer == this); bool hasPlanes = true; - if (mask & LOCAL_GL_COLOR_BUFFER_BIT) { - hasPlanes &= ColorAttachmentCount() && - ColorAttachment(0).IsDefined(); - } + if (mask & LOCAL_GL_COLOR_BUFFER_BIT) + hasPlanes &= mColorAttachment0.IsDefined(); if (mask & LOCAL_GL_DEPTH_BUFFER_BIT) { - hasPlanes &= DepthAttachment().IsDefined() || - DepthStencilAttachment().IsDefined(); + hasPlanes &= mDepthAttachment.IsDefined() || + mDepthStencilAttachment.IsDefined(); } if (mask & LOCAL_GL_STENCIL_BUFFER_BIT) { - hasPlanes &= StencilAttachment().IsDefined() || - DepthStencilAttachment().IsDefined(); + hasPlanes &= mStencilAttachment.IsDefined() || + mDepthStencilAttachment.IsDefined(); } return hasPlanes; @@ -844,17 +753,14 @@ WebGLFramebuffer::CheckAndInitializeAttachments() return false; // Cool! We've checked out ok. Just need to initialize. - const size_t colorAttachmentCount = mColorAttachments.Length(); + const size_t moreColorAttachmentCount = mMoreColorAttachments.Length(); // Check if we need to initialize anything { bool hasUninitializedAttachments = false; - for (size_t i = 0; i < colorAttachmentCount; i++) { - if (mColorAttachments[i].HasImage()) - hasUninitializedAttachments |= mColorAttachments[i].HasUninitializedImageData(); - } - + if (mColorAttachment0.HasImage()) + hasUninitializedAttachments |= mColorAttachment0.HasUninitializedImageData(); if (mDepthAttachment.HasImage()) hasUninitializedAttachments |= mDepthAttachment.HasUninitializedImageData(); if (mStencilAttachment.HasImage()) @@ -862,6 +768,11 @@ WebGLFramebuffer::CheckAndInitializeAttachments() if (mDepthStencilAttachment.HasImage()) hasUninitializedAttachments |= mDepthStencilAttachment.HasUninitializedImageData(); + for (size_t i = 0; i < moreColorAttachmentCount; i++) { + if (mMoreColorAttachments[i].HasImage()) + hasUninitializedAttachments |= mMoreColorAttachments[i].HasUninitializedImageData(); + } + if (!hasUninitializedAttachments) return true; } @@ -869,13 +780,11 @@ WebGLFramebuffer::CheckAndInitializeAttachments() // Get buffer-bit-mask and color-attachment-mask-list uint32_t mask = 0; bool colorAttachmentsMask[WebGLContext::kMaxColorAttachments] = { false }; - MOZ_ASSERT(colorAttachmentCount <= WebGLContext::kMaxColorAttachments); + MOZ_ASSERT(1 + moreColorAttachmentCount <= WebGLContext::kMaxColorAttachments); - for (size_t i = 0; i < colorAttachmentCount; i++) { - if (mColorAttachments[i].HasUninitializedImageData()) { - colorAttachmentsMask[i] = true; - mask |= LOCAL_GL_COLOR_BUFFER_BIT; - } + if (mColorAttachment0.HasUninitializedImageData()) { + colorAttachmentsMask[0] = true; + mask |= LOCAL_GL_COLOR_BUFFER_BIT; } if (mDepthAttachment.HasUninitializedImageData() || @@ -890,15 +799,19 @@ WebGLFramebuffer::CheckAndInitializeAttachments() mask |= LOCAL_GL_STENCIL_BUFFER_BIT; } + for (size_t i = 0; i < moreColorAttachmentCount; i++) { + if (mMoreColorAttachments[i].HasUninitializedImageData()) { + colorAttachmentsMask[1 + i] = true; + mask |= LOCAL_GL_COLOR_BUFFER_BIT; + } + } + // Clear! mContext->ForceClearFramebufferWithDefaultValues(mask, colorAttachmentsMask); // Mark all the uninitialized images as initialized. - for (size_t i = 0; i < colorAttachmentCount; i++) { - if (mColorAttachments[i].HasUninitializedImageData()) - mColorAttachments[i].SetImageDataStatus(WebGLImageDataStatus::InitializedImageData); - } - + if (mColorAttachment0.HasUninitializedImageData()) + mColorAttachment0.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData); if (mDepthAttachment.HasUninitializedImageData()) mDepthAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData); if (mStencilAttachment.HasUninitializedImageData()) @@ -906,29 +819,28 @@ WebGLFramebuffer::CheckAndInitializeAttachments() if (mDepthStencilAttachment.HasUninitializedImageData()) mDepthStencilAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData); + for (size_t i = 0; i < moreColorAttachmentCount; i++) { + if (mMoreColorAttachments[i].HasUninitializedImageData()) + mMoreColorAttachments[i].SetImageDataStatus(WebGLImageDataStatus::InitializedImageData); + } + return true; } -void WebGLFramebuffer::EnsureColorAttachments(size_t colorAttachmentId) +void WebGLFramebuffer::EnsureColorAttachPoints(size_t colorAttachmentId) { MOZ_ASSERT(colorAttachmentId < WebGLContext::kMaxColorAttachments); - size_t currentAttachmentCount = mColorAttachments.Length(); - if (colorAttachmentId < currentAttachmentCount) + if (colorAttachmentId < ColorAttachmentCount()) return; - mColorAttachments.SetLength(colorAttachmentId + 1); - - for (size_t i = colorAttachmentId; i >= currentAttachmentCount; i--) { - mColorAttachments[i].mAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0 + i; + size_t colorAttachmentCount = ColorAttachmentCount(); + while (colorAttachmentCount < WebGLContext::kMaxColorAttachments) { + GLenum nextAttachPoint = LOCAL_GL_COLOR_ATTACHMENT0 + colorAttachmentCount; + mMoreColorAttachments.AppendElement(AttachPoint(this, nextAttachPoint)); } -} -void -WebGLFramebuffer::NotifyAttachableChanged() const -{ - // Attachment has changed, so invalidate cached status - mStatus = 0; + MOZ_ASSERT(colorAttachmentCount == ColorAttachmentCount()); } static void @@ -963,18 +875,32 @@ FinalizeDrawAndReadBuffers(gl::GLContext* gl, bool isColorBufferDefined) void WebGLFramebuffer::FinalizeAttachments() const { + MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this || + mContext->mBoundReadFramebuffer == this); + + MOZ_ASSERT(mStatus == LOCAL_GL_FRAMEBUFFER_COMPLETE); + gl::GLContext* gl = mContext->gl; - for (size_t i = 0; i < ColorAttachmentCount(); i++) { - ColorAttachment(i).FinalizeAttachment(gl, LOCAL_GL_COLOR_ATTACHMENT0+i); + // Nuke the depth and stencil attachment points. + gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, + LOCAL_GL_RENDERBUFFER, 0); + gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, + LOCAL_GL_RENDERBUFFER, 0); + + // Call finalize. + mColorAttachment0.FinalizeAttachment(gl, LOCAL_GL_COLOR_ATTACHMENT0); + mDepthAttachment.FinalizeAttachment(gl, LOCAL_GL_DEPTH_ATTACHMENT); + mStencilAttachment.FinalizeAttachment(gl, LOCAL_GL_STENCIL_ATTACHMENT); + mDepthStencilAttachment.FinalizeAttachment(gl, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT); + + const size_t moreColorAttachmentCount = mMoreColorAttachments.Length(); + for (size_t i = 0; i < moreColorAttachmentCount; i++) { + GLenum attachPoint = LOCAL_GL_COLOR_ATTACHMENT0 + 1 + i; + mMoreColorAttachments[i].FinalizeAttachment(gl, attachPoint); } - DepthAttachment().FinalizeAttachment(gl, LOCAL_GL_DEPTH_ATTACHMENT); - StencilAttachment().FinalizeAttachment(gl, LOCAL_GL_STENCIL_ATTACHMENT); - DepthStencilAttachment().FinalizeAttachment(gl, - LOCAL_GL_DEPTH_STENCIL_ATTACHMENT); - - FinalizeDrawAndReadBuffers(gl, ColorAttachment(0).IsDefined()); + FinalizeDrawAndReadBuffers(gl, mColorAttachment0.IsDefined()); } bool @@ -986,7 +912,7 @@ WebGLFramebuffer::ValidateForRead(const char* info, TexInternalFormat* const out return false; } - const auto& attachment = GetAttachment(mReadBufferMode); + const auto& attachPoint = GetAttachPoint(mReadBufferMode); if (!CheckAndInitializeAttachments()) { mContext->ErrorInvalidFramebufferOperation("readPixels: incomplete framebuffer"); @@ -1000,38 +926,46 @@ WebGLFramebuffer::ValidateForRead(const char* info, TexInternalFormat* const out return false; } - if (!attachment.IsDefined()) { + if (!attachPoint.IsDefined()) { mContext->ErrorInvalidOperation("readPixels: "); return false; } - *out_format = attachment.EffectiveInternalFormat(); + *out_format = attachPoint.EffectiveInternalFormat(); return true; } -inline void -ImplCycleCollectionUnlink(mozilla::WebGLFramebuffer::Attachment& field) +//////////////////////////////////////////////////////////////////////////////// +// Goop. + +JSObject* +WebGLFramebuffer::WrapObject(JSContext* cx) { - field.mTexturePtr = nullptr; - field.mRenderbufferPtr = nullptr; + return dom::WebGLFramebufferBinding::Wrap(cx, this); +} + +inline void +ImplCycleCollectionUnlink(mozilla::WebGLFramebuffer::AttachPoint& field) +{ + field.Unlink(); } inline void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback, - mozilla::WebGLFramebuffer::Attachment& field, + mozilla::WebGLFramebuffer::AttachPoint& field, const char* name, uint32_t flags = 0) { - CycleCollectionNoteChild(callback, field.mTexturePtr.get(), name, flags); - CycleCollectionNoteChild(callback, field.mRenderbufferPtr.get(), name, - flags); + CycleCollectionNoteChild(callback, field.Texture(), name, flags); + CycleCollectionNoteChild(callback, field.Renderbuffer(), name, flags); } NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLFramebuffer, - mColorAttachments, + mColorAttachment0, mDepthAttachment, mStencilAttachment, - mDepthStencilAttachment) + mDepthStencilAttachment, + mMoreColorAttachments) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLFramebuffer, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLFramebuffer, Release) diff --git a/dom/canvas/WebGLFramebuffer.h b/dom/canvas/WebGLFramebuffer.h index c390519d498f..1a78511966de 100644 --- a/dom/canvas/WebGLFramebuffer.h +++ b/dom/canvas/WebGLFramebuffer.h @@ -33,20 +33,25 @@ class WebGLFramebuffer MOZ_FINAL public: MOZ_DECLARE_REFCOUNTED_TYPENAME(WebGLFramebuffer) - explicit WebGLFramebuffer(WebGLContext* webgl, GLuint fbo); - - struct Attachment + class AttachPoint { - // deleting a texture or renderbuffer immediately detaches it + public: + WebGLFramebuffer* const mFB; + private: WebGLRefPtr mTexturePtr; WebGLRefPtr mRenderbufferPtr; FBAttachment mAttachmentPoint; TexImageTarget mTexImageTarget; GLint mTexImageLevel; - mutable bool mNeedsFinalize; - explicit Attachment(FBAttachment attachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0); - ~Attachment(); + public: + AttachPoint(WebGLFramebuffer* fb, FBAttachment attachmentPoint); + ~AttachPoint(); + + void Unlink() { + mRenderbufferPtr = nullptr; + mTexturePtr = nullptr; + } bool IsDefined() const; @@ -57,6 +62,10 @@ public: bool HasAlpha() const; bool IsReadableFloat() const; + void Clear() { + SetRenderbuffer(nullptr); + } + void SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level); void SetRenderbuffer(WebGLRenderbuffer* rb); @@ -82,8 +91,6 @@ public: bool HasUninitializedImageData() const; void SetImageDataStatus(WebGLImageDataStatus x); - void Reset(); - const WebGLRectangleObject& RectangleObject() const; bool HasImage() const; @@ -93,6 +100,29 @@ public: FBAttachment attachmentLoc) const; }; +private: + mutable GLenum mStatus; + + GLenum mReadBufferMode; + + // No need to chase pointers for the oft-used color0. + AttachPoint mColorAttachment0; + AttachPoint mDepthAttachment; + AttachPoint mStencilAttachment; + AttachPoint mDepthStencilAttachment; + nsTArray mMoreColorAttachments; + +public: + WebGLFramebuffer(WebGLContext* webgl, GLuint fbo); + +private: + ~WebGLFramebuffer() { + DeleteOnce(); + } + + const WebGLRectangleObject& GetAnyRectObject() const; + +public: void Delete(); void FramebufferRenderbuffer(FBAttachment attachment, RBTarget rbtarget, @@ -102,13 +132,6 @@ public: TexImageTarget texImageTarget, WebGLTexture* tex, GLint level); -private: - void DetachAttachment(WebGLFramebuffer::Attachment& attachment); - void DetachAllAttachments(); - const WebGLRectangleObject& GetAnyRectObject() const; - Attachment* GetAttachmentOrNull(FBAttachment attachment); - -public: bool HasDefinedAttachments() const; bool HasIncompleteAttachments() const; bool AllImageRectsMatch() const; @@ -116,7 +139,7 @@ public: FBStatus CheckFramebufferStatus() const; GLenum - GetFormatForAttachment(const WebGLFramebuffer::Attachment& attachment) const; + GetFormatForAttachment(const WebGLFramebuffer::AttachPoint& attachment) const; bool HasDepthStencilConflict() const { return int(mDepthAttachment.IsDefined()) + @@ -125,25 +148,28 @@ public: } size_t ColorAttachmentCount() const { - return mColorAttachments.Length(); - } - const Attachment& ColorAttachment(size_t colorAttachmentId) const { - return mColorAttachments[colorAttachmentId]; + return 1 + mMoreColorAttachments.Length(); } - const Attachment& DepthAttachment() const { + const AttachPoint& ColorAttachment(size_t colorAttachmentId) const { + MOZ_ASSERT(colorAttachmentId < ColorAttachmentCount()); + return colorAttachmentId ? mMoreColorAttachments[colorAttachmentId - 1] + : mColorAttachment0; + } + + const AttachPoint& DepthAttachment() const { return mDepthAttachment; } - const Attachment& StencilAttachment() const { + const AttachPoint& StencilAttachment() const { return mStencilAttachment; } - const Attachment& DepthStencilAttachment() const { + const AttachPoint& DepthStencilAttachment() const { return mDepthStencilAttachment; } - const Attachment& GetAttachment(FBAttachment attachment) const; + AttachPoint& GetAttachPoint(FBAttachment attachPointEnum); void DetachTexture(const WebGLTexture* tex); @@ -170,26 +196,13 @@ public: bool CheckColorAttachmentNumber(FBAttachment attachment, const char* funcName) const; - void EnsureColorAttachments(size_t colorAttachmentId); + void EnsureColorAttachPoints(size_t colorAttachmentId); - void NotifyAttachableChanged() const; - - bool ValidateForRead(const char* info, TexInternalFormat* const out_format); - -private: - ~WebGLFramebuffer() { - DeleteOnce(); + void InvalidateFramebufferStatus() const { + mStatus = 0; } - mutable GLenum mStatus; - - // we only store pointers to attached renderbuffers, not to attached textures, because - // we will only need to initialize renderbuffers. Textures are already initialized. - nsTArray mColorAttachments; - Attachment mDepthAttachment; - Attachment mStencilAttachment; - Attachment mDepthStencilAttachment; - GLenum mReadBufferMode; + bool ValidateForRead(const char* info, TexInternalFormat* const out_format); }; } // namespace mozilla diff --git a/dom/canvas/WebGLFramebufferAttachable.cpp b/dom/canvas/WebGLFramebufferAttachable.cpp index 67956a156ee8..52050794c26d 100644 --- a/dom/canvas/WebGLFramebufferAttachable.cpp +++ b/dom/canvas/WebGLFramebufferAttachable.cpp @@ -3,35 +3,28 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "WebGLContext.h" #include "WebGLFramebufferAttachable.h" + +#include "WebGLContext.h" #include "WebGLFramebuffer.h" #include "WebGLRenderbuffer.h" #include "WebGLTexture.h" -using namespace mozilla; +namespace mozilla { void -WebGLFramebufferAttachable::AttachTo(WebGLFramebuffer* fb, FBAttachment attachment) +WebGLFramebufferAttachable::MarkAttachment(const WebGLFramebuffer::AttachPoint& attachment) { - MOZ_ASSERT(fb); - if (!fb) - return; - - if (mAttachmentPoints.Contains(AttachmentPoint(fb, attachment))) + if (mAttachmentPoints.Contains(&attachment)) return; // Already attached. Ignore. - mAttachmentPoints.AppendElement(AttachmentPoint(fb, attachment)); + mAttachmentPoints.AppendElement(&attachment); } void -WebGLFramebufferAttachable::DetachFrom(WebGLFramebuffer* fb, FBAttachment attachment) +WebGLFramebufferAttachable::UnmarkAttachment(const WebGLFramebuffer::AttachPoint& attachment) { - MOZ_ASSERT(fb); - if (!fb) - return; - - const size_t i = mAttachmentPoints.IndexOf(AttachmentPoint(fb, attachment)); + const size_t i = mAttachmentPoints.IndexOf(&attachment); if (i == mAttachmentPoints.NoIndex) { MOZ_ASSERT(false, "Is not attached to FB"); return; @@ -41,11 +34,13 @@ WebGLFramebufferAttachable::DetachFrom(WebGLFramebuffer* fb, FBAttachment attach } void -WebGLFramebufferAttachable::NotifyFBsStatusChanged() +WebGLFramebufferAttachable::InvalidateStatusOfAttachedFBs() const { - for (size_t i = 0; i < mAttachmentPoints.Length(); ++i) { - MOZ_ASSERT(mAttachmentPoints[i].mFB, - "Unexpected null pointer; seems that a WebGLFramebuffer forgot to call DetachFrom before dying"); - mAttachmentPoints[i].mFB->NotifyAttachableChanged(); + const size_t count = mAttachmentPoints.Length(); + for (size_t i = 0; i < count; ++i) { + MOZ_ASSERT(mAttachmentPoints[i]->mFB); + mAttachmentPoints[i]->mFB->InvalidateFramebufferStatus(); } } + +} // namespace mozilla diff --git a/dom/canvas/WebGLFramebufferAttachable.h b/dom/canvas/WebGLFramebufferAttachable.h index d295085f593e..b312229506b2 100644 --- a/dom/canvas/WebGLFramebufferAttachable.h +++ b/dom/canvas/WebGLFramebufferAttachable.h @@ -3,12 +3,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef WEBGLFRAMEBUFFERATTACHABLE_H_ -#define WEBGLFRAMEBUFFERATTACHABLE_H_ +#ifndef WEBGL_FRAMEBUFFER_ATTACHABLE_H_ +#define WEBGL_FRAMEBUFFER_ATTACHABLE_H_ #include "GLDefs.h" -#include "nsTArray.h" #include "mozilla/WeakPtr.h" +#include "nsTArray.h" #include "WebGLFramebuffer.h" #include "WebGLStrongTypes.h" @@ -16,29 +16,13 @@ namespace mozilla { class WebGLFramebufferAttachable { - struct AttachmentPoint - { - AttachmentPoint(const WebGLFramebuffer* fb, FBAttachment attachment) - : mFB(fb) - , mAttachment(attachment) - {} - - WeakPtr mFB; - FBAttachment mAttachment; - - bool operator==(const AttachmentPoint& o) const { - return mFB == o.mFB && mAttachment == o.mAttachment; - } - }; - - nsTArray mAttachmentPoints; + nsTArray mAttachmentPoints; public: - // Track FBO/Attachment combinations - void AttachTo(WebGLFramebuffer* fb, FBAttachment attachment); - void DetachFrom(WebGLFramebuffer* fb, FBAttachment attachment); - void NotifyFBsStatusChanged(); + void MarkAttachment(const WebGLFramebuffer::AttachPoint& attachment); + void UnmarkAttachment(const WebGLFramebuffer::AttachPoint& attachment); + void InvalidateStatusOfAttachedFBs() const; }; } // namespace mozilla diff --git a/dom/canvas/WebGLRenderbuffer.cpp b/dom/canvas/WebGLRenderbuffer.cpp index 6aa947f2679d..a887a4d14442 100644 --- a/dom/canvas/WebGLRenderbuffer.cpp +++ b/dom/canvas/WebGLRenderbuffer.cpp @@ -179,6 +179,8 @@ void WebGLRenderbuffer::RenderbufferStorage(GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height) const { + InvalidateStatusOfAttachedFBs(); + gl::GLContext* gl = mContext->gl; MOZ_ASSERT(samples >= 0 && samples <= 256); // Sanity check. diff --git a/dom/canvas/WebGLTexture.cpp b/dom/canvas/WebGLTexture.cpp index 60afc45c9246..752b56760310 100644 --- a/dom/canvas/WebGLTexture.cpp +++ b/dom/canvas/WebGLTexture.cpp @@ -181,6 +181,8 @@ WebGLTexture::SetImageInfo(TexImageTarget texImageTarget, GLint level, MOZ_ASSERT(depth == 1 || texImageTarget == LOCAL_GL_TEXTURE_3D); MOZ_ASSERT(TexImageTargetToTexTarget(texImageTarget) == mTarget); + InvalidateStatusOfAttachedFBs(); + EnsureMaxLevelWithCustomImagesAtLeast(level); ImageInfoAt(texImageTarget, level) = ImageInfo(width, height, depth, @@ -190,9 +192,6 @@ WebGLTexture::SetImageInfo(TexImageTarget texImageTarget, GLint level, if (level > 0) SetCustomMipmap(); - // Invalidate framebuffer status cache. - NotifyFBsStatusChanged(); - SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown); }