☠☠ backed out by 1dcc4d0ee3d7 ☠ ☠ | |
author | Nicolas Silva <nsilva@mozilla.com> |
Tue, 28 Jun 2016 14:07:00 +0200 | |
changeset 302949 | f534fcb785c9044c1714343113d4685c53d0eefa |
parent 302948 | 6ee8762044bd45934bf9b786a6ac3be8ca5007ce |
child 302950 | 61465f67b5911d7544cf6e3e13f60b7ffec05365 |
push id | 30354 |
push user | cbook@mozilla.com |
push date | Wed, 29 Jun 2016 14:23:15 +0000 |
treeherder | autoland@0c56fe904602 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | Bas |
bugs | 1167235 |
milestone | 50.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -740,16 +740,46 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(C NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CanvasGradient, mContext) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CanvasPattern, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CanvasPattern, Release) NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CanvasPattern, mContext) +class CanvasShutdownObserver final : public nsIObserver +{ +public: + explicit CanvasShutdownObserver(CanvasRenderingContext2D* aCanvas) + : mCanvas(aCanvas) + {} + + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER +private: + ~CanvasShutdownObserver() {} + + CanvasRenderingContext2D* mCanvas; +}; + +NS_IMPL_ISUPPORTS(CanvasShutdownObserver, nsIObserver) + +NS_IMETHODIMP +CanvasShutdownObserver::Observe(nsISupports *aSubject, + const char *aTopic, + const char16_t *aData) +{ + if (mCanvas && strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) { + mCanvas->OnShutdown(); + nsContentUtils::UnregisterShutdownObserver(this); + } + + return NS_OK; +} + class CanvasDrawObserver { public: explicit CanvasDrawObserver(CanvasRenderingContext2D* aCanvasContext); // Only enumerate draw calls that could affect the heuristic enum DrawCallType { PutImageData, @@ -1039,28 +1069,32 @@ CanvasRenderingContext2D::CanvasRenderin , mIsEntireFrameInvalid(false) , mPredictManyRedrawCalls(false) , mIsCapturedFrameInvalid(false) , mPathTransformWillUpdate(false) , mInvalidateCount(0) { sNumLivingContexts++; + mShutdownObserver = new CanvasShutdownObserver(this); + nsContentUtils::RegisterShutdownObserver(mShutdownObserver); + // The default is to use OpenGL mode if (gfxPlatform::GetPlatform()->UseAcceleratedCanvas()) { mDrawObserver = new CanvasDrawObserver(this); } else { mRenderingMode = RenderingMode::SoftwareBackendMode; } } CanvasRenderingContext2D::~CanvasRenderingContext2D() { RemoveDrawObserver(); RemovePostRefreshObserver(); + RemoveShutdownObserver(); Reset(); // Drop references from all CanvasRenderingContext2DUserData to this context for (uint32_t i = 0; i < mUserDatas.Length(); ++i) { mUserDatas[i]->Forget(); } sNumLivingContexts--; if (!sNumLivingContexts) { NS_IF_RELEASE(sErrorTarget); @@ -1144,16 +1178,39 @@ CanvasRenderingContext2D::Reset() mIsEntireFrameInvalid = false; mPredictManyRedrawCalls = false; mIsCapturedFrameInvalid = false; return NS_OK; } void +CanvasRenderingContext2D::OnShutdown() +{ + mShutdownObserver = nullptr; + + RefPtr<PersistentBufferProvider> provider = mBufferProvider; + + Reset(); + + if (provider) { + provider->OnShutdown(); + } +} + +void +CanvasRenderingContext2D::RemoveShutdownObserver() +{ + if (mShutdownObserver) { + nsContentUtils::UnregisterShutdownObserver(mShutdownObserver); + mShutdownObserver = nullptr; + } +} + +void CanvasRenderingContext2D::SetStyleFromString(const nsAString& aStr, Style aWhichStyle) { MOZ_ASSERT(!aStr.IsVoid()); nscolor color; if (!ParseColor(aStr, &color)) { return; @@ -1451,16 +1508,23 @@ CanvasRenderingContext2D::CheckSizeForSk // screen size acts as max threshold return threshold < 0 || (aSize.width * aSize.height) <= threshold; } CanvasRenderingContext2D::RenderingMode CanvasRenderingContext2D::EnsureTarget(const gfx::Rect* aCoveredRect, RenderingMode aRenderingMode) { + if (AlreadyShutDown()) { + gfxCriticalError() << "Attempt to render into a Canvas2d after shutdown."; + EnsureErrorTarget(); + mTarget = sErrorTarget; + return aRenderingMode; + } + // This would make no sense, so make sure we don't get ourselves in a mess MOZ_ASSERT(mRenderingMode != RenderingMode::DefaultBackendMode); RenderingMode mode = (aRenderingMode == RenderingMode::DefaultBackendMode) ? mRenderingMode : aRenderingMode; if (mTarget && mode == mRenderingMode) { return mRenderingMode; } @@ -5686,16 +5750,20 @@ void CanvasRenderingContext2D::RemoveDra delete mDrawObserver; mDrawObserver = nullptr; } } PersistentBufferProvider* CanvasRenderingContext2D::GetBufferProvider(LayerManager* aManager) { + if (AlreadyShutDown()) { + return nullptr; + } + if (mBufferProvider) { return mBufferProvider; } if (!mTarget) { return nullptr; }
--- a/dom/canvas/CanvasRenderingContext2D.h +++ b/dom/canvas/CanvasRenderingContext2D.h @@ -49,16 +49,17 @@ class CanvasPath; extern const mozilla::gfx::Float SIGMA_MAX; template<typename T> class Optional; struct CanvasBidiProcessor; class CanvasRenderingContext2DUserData; class CanvasDrawObserver; +class CanvasShutdownObserver; /** ** CanvasRenderingContext2D **/ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal, public nsWrapperCache { @@ -540,16 +541,17 @@ public: // Given a point, return hit region ID if it exists nsString GetHitRegion(const mozilla::gfx::Point& aPoint) override; // return true and fills in the bound rect if element has a hit region. bool GetHitRegionRect(Element* aElement, nsRect& aRect) override; + void OnShutdown(); protected: nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY, uint32_t aWidth, uint32_t aHeight, JSObject** aRetval); nsresult PutImageData_explicit(int32_t aX, int32_t aY, uint32_t aW, uint32_t aH, dom::Uint8ClampedArray* aArray, bool aHasDirtyRect, int32_t aDirtyX, int32_t aDirtyY, @@ -744,16 +746,20 @@ protected: uint32_t SkiaGLTex() const; // This observes our draw calls at the beginning of the canvas // lifetime and switches to software or GPU mode depending on // what it thinks is best CanvasDrawObserver* mDrawObserver; void RemoveDrawObserver(); + RefPtr<CanvasShutdownObserver> mShutdownObserver; + void RemoveShutdownObserver(); + bool AlreadyShutDown() const { return !mShutdownObserver; } + /** * Flag to avoid duplicate calls to InvalidateFrame. Set to true whenever * Redraw is called, reset to false when Render is called. */ bool mIsEntireFrameInvalid; /** * When this is set, the first call to Redraw(gfxRect) should set * mIsEntireFrameInvalid since we expect it will be followed by
--- a/dom/html/HTMLCanvasElement.cpp +++ b/dom/html/HTMLCanvasElement.cpp @@ -348,18 +348,17 @@ HTMLCanvasElementObserver::HandleEvent(n NS_IMPL_ISUPPORTS(HTMLCanvasElementObserver, nsIObserver) // --------------------------------------------------------------------------- HTMLCanvasElement::HTMLCanvasElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo) : nsGenericHTMLElement(aNodeInfo), mResetLayer(true) , mWriteOnly(false) -{ -} +{} HTMLCanvasElement::~HTMLCanvasElement() { if (mContextObserver) { mContextObserver->Destroy(); mContextObserver = nullptr; }
--- a/gfx/layers/PersistentBufferProvider.cpp +++ b/gfx/layers/PersistentBufferProvider.cpp @@ -121,26 +121,17 @@ PersistentBufferProviderShared::Persiste PersistentBufferProviderShared::~PersistentBufferProviderShared() { MOZ_COUNT_DTOR(PersistentBufferProviderShared); if (IsActivityTracked()) { mFwd->GetActiveResourceTracker().RemoveObject(this); } - mDrawTarget = nullptr; - if (mBack && mBack->IsLocked()) { - mBack->Unlock(); - } - if (mFront && mFront->IsLocked()) { - mFront->Unlock(); - } - if (mBuffer && mBuffer->IsLocked()) { - mBuffer->Unlock(); - } + Destroy(); } already_AddRefed<gfx::DrawTarget> PersistentBufferProviderShared::BorrowDrawTarget(const gfx::IntRect& aPersistedRect) { if (!mFwd->IPCOpen()) { return nullptr; } @@ -271,10 +262,33 @@ PersistentBufferProviderShared::NotifyIn if (mBuffer && mBuffer->IsLocked()) { // mBuffer should never be locked MOZ_ASSERT(false); mBuffer->Unlock(); } mBuffer = nullptr; } +void +PersistentBufferProviderShared::Destroy() +{ + mSnapshot = nullptr; + mDrawTarget = nullptr; + + if (mFront && mFront->IsLocked()) { + mFront->Unlock(); + } + + if (mBack && mBack->IsLocked()) { + mBack->Unlock(); + } + + if (mBuffer && mBuffer->IsLocked()) { + mBuffer->Unlock(); + } + + mFront = nullptr; + mBack = nullptr; + mBuffer = nullptr; +} + } // namespace layers } // namespace mozilla \ No newline at end of file
--- a/gfx/layers/PersistentBufferProvider.h +++ b/gfx/layers/PersistentBufferProvider.h @@ -55,16 +55,18 @@ public: */ virtual bool ReturnDrawTarget(already_AddRefed<gfx::DrawTarget> aDT) = 0; virtual already_AddRefed<gfx::SourceSurface> BorrowSnapshot() = 0; virtual void ReturnSnapshot(already_AddRefed<gfx::SourceSurface> aSnapshot) = 0; virtual TextureClient* GetTextureClient() { return nullptr; } + + virtual void OnShutdown() {} }; class PersistentBufferProviderBasic : public PersistentBufferProvider { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PersistentBufferProviderBasic, override) @@ -116,23 +118,27 @@ public: virtual void ReturnSnapshot(already_AddRefed<gfx::SourceSurface> aSnapshot) override; TextureClient* GetTextureClient() override { return mFront; } virtual void NotifyInactive() override; + virtual void OnShutdown() override { Destroy(); } + protected: PersistentBufferProviderShared(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, CompositableForwarder* aFwd, RefPtr<TextureClient>& aTexture); ~PersistentBufferProviderShared(); + void Destroy(); + gfx::IntSize mSize; gfx::SurfaceFormat mFormat; RefPtr<CompositableForwarder> mFwd; // The texture presented to the compositor. RefPtr<TextureClient> mFront; // The texture that the canvas uses. RefPtr<TextureClient> mBack; // An extra texture we keep around temporarily to avoid allocating.
--- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -359,16 +359,18 @@ DeallocateTextureClient(TextureDeallocPa } void TextureClient::Destroy(bool aForceSync) { if (mActor) { mActor->Lock(); } + mReadLock = nullptr; + CancelWaitFenceHandleOnImageBridge(); RefPtr<TextureChild> actor = mActor; mActor = nullptr; if (actor && !actor->mDestroyed.compareExchange(false, true)) { actor->Unlock(); actor = nullptr; }