author | Nicolas Silva <nsilva@mozilla.com> |
Tue, 11 Oct 2016 13:23:11 +0200 | |
changeset 324218 | 900960e68528c73afb6cfb3d97400bb3311386cf |
parent 324217 | f96d497c78a7f3d73d8e5079e2fcb1eca80e574f |
child 324219 | 49228a69b071bc200360aa43845b42b996759479 |
push id | 34648 |
push user | cbook@mozilla.com |
push date | Fri, 25 Nov 2016 15:31:22 +0000 |
treeherder | autoland@c4d075822fbf [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | Bas |
bugs | 1300121 |
milestone | 53.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 @@ -1636,17 +1636,21 @@ CanvasRenderingContext2D::EnsureTarget(c !TrySkiaGLTarget(newTarget, newProvider)) { // Fall back to software. mode = RenderingMode::SoftwareBackendMode; } if (mode == RenderingMode::SoftwareBackendMode && !TrySharedTarget(newTarget, newProvider) && !TryBasicTarget(newTarget, newProvider)) { - gfxCriticalError() << "Failed borrow shared and basic targets."; + + gfxCriticalError( + CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(GetSize())) + ) << "Failed borrow shared and basic targets."; + SetErrorState(); return mode; } MOZ_ASSERT(newTarget); MOZ_ASSERT(newProvider);
--- a/gfx/layers/PersistentBufferProvider.cpp +++ b/gfx/layers/PersistentBufferProvider.cpp @@ -1,16 +1,17 @@ /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This Source Code Form is subject to the terms of the Mozilla Public * 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 "PersistentBufferProvider.h" #include "Layers.h" +#include "mozilla/layers/ShadowLayers.h" #include "mozilla/gfx/Logging.h" #include "pratom.h" #include "gfxPlatform.h" namespace mozilla { using namespace gfx; @@ -237,18 +238,16 @@ PersistentBufferProviderShared::BorrowDr mFwd->GetActiveResourceTracker().AddObject(this); } if (mDrawTarget) { RefPtr<gfx::DrawTarget> dt(mDrawTarget); return dt.forget(); } - mFront = Nothing(); - auto previousBackBuffer = mBack; TextureClient* tex = GetTexture(mBack); // First try to reuse the current back buffer. If we can do that it means // we can skip copying its content to the new back buffer. if (tex && tex->IsReadLocked()) { // The back buffer is currently used by the compositor, we can't draw @@ -266,27 +265,42 @@ PersistentBufferProviderShared::BorrowDr } } } if (!tex) { // We have to allocate a new texture. if (mTextures.length() >= 4) { // We should never need to buffer that many textures, something's wrong. - MOZ_ASSERT(false); // In theory we throttle the main thread when the compositor can't keep up, // so we shoud never get in a situation where we sent 4 textures to the - // compositor and the latter as not released any of them. - // This seems to happen, however, in some edge cases such as just after a - // device reset (cf. Bug 1291163). - // It would be pretty bad to keep piling textures up at this point so we - // call NotifyInactive to remove some of our textures. - NotifyInactive(); - // Give up now. The caller can fall-back to a non-shared buffer provider. - return nullptr; + // compositor and the latter has not released any of them. + // In practice, though, the throttling mechanism appears to have some issues, + // especially when switching between layer managers (during tab-switch). + // To make sure we don't get too far ahead of the compositor, we send a + // sync ping to the compositor thread... + mFwd->SyncWithCompositor(); + // ...and try again. + for (uint32_t i = 0; i < mTextures.length(); ++i) { + if (!mTextures[i]->IsReadLocked()) { + gfxCriticalNote << "Managed to allocate after flush."; + mBack = Some(i); + tex = mTextures[i]; + break; + } + } + + if (!tex) { + gfxCriticalError() << "Unexpected BufferProvider over-production."; + // It would be pretty bad to keep piling textures up at this point so we + // call NotifyInactive to remove some of our textures. + NotifyInactive(); + // Give up now. The caller can fall-back to a non-shared buffer provider. + return nullptr; + } } RefPtr<TextureClient> newTexture = TextureClient::CreateForDrawing( mFwd, mFormat, mSize, BackendSelector::Canvas, TextureFlags::DEFAULT, TextureAllocationFlags::ALLOC_DEFAULT ); @@ -397,16 +411,22 @@ PersistentBufferProviderShared::ReturnSn if (front) { front->Unlock(); } } void PersistentBufferProviderShared::NotifyInactive() { + ClearCachedResources(); +} + +void +PersistentBufferProviderShared::ClearCachedResources() +{ RefPtr<TextureClient> front = GetTexture(mFront); RefPtr<TextureClient> back = GetTexture(mBack); // Clear all textures (except the front and back ones that we just kept). mTextures.clear(); if (back) { if (mTextures.append(back)) {
--- a/gfx/layers/PersistentBufferProvider.h +++ b/gfx/layers/PersistentBufferProvider.h @@ -61,16 +61,18 @@ public: virtual void ReturnSnapshot(already_AddRefed<gfx::SourceSurface> aSnapshot) = 0; virtual TextureClient* GetTextureClient() { return nullptr; } virtual void OnShutdown() {} virtual bool SetForwarder(ShadowLayerForwarder* aFwd) { return true; } + virtual void ClearCachedResources() {} + /** * Return true if this provider preserves the drawing state (clips, transforms, * etc.) across frames. In practice this means users of the provider can skip * popping all of the clips at the end of the frames and pushing them back at * the beginning of the following frames, which can be costly (cf. bug 1294351). */ virtual bool PreservesDrawingState() const = 0; }; @@ -132,16 +134,18 @@ public: virtual TextureClient* GetTextureClient() override; virtual void NotifyInactive() override; virtual void OnShutdown() override { Destroy(); } virtual bool SetForwarder(ShadowLayerForwarder* aFwd) override; + virtual void ClearCachedResources() override; + virtual bool PreservesDrawingState() const override { return false; } protected: PersistentBufferProviderShared(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, ShadowLayerForwarder* aFwd, RefPtr<TextureClient>& aTexture); ~PersistentBufferProviderShared();
--- a/gfx/layers/client/CanvasClient.h +++ b/gfx/layers/client/CanvasClient.h @@ -97,17 +97,17 @@ public: TextureInfo GetTextureInfo() const override { return TextureInfo(CompositableType::IMAGE, mTextureFlags); } virtual void Clear() override { - mBackBuffer = mFrontBuffer = nullptr; + mBackBuffer = mFrontBuffer = mBufferProviderTexture = nullptr; } virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) override; virtual void UpdateFromTexture(TextureClient* aBuffer) override; virtual bool AddTextureClient(TextureClient* aTexture) override {
--- a/gfx/layers/client/ClientCanvasLayer.cpp +++ b/gfx/layers/client/ClientCanvasLayer.cpp @@ -26,16 +26,19 @@ using namespace mozilla::gfx; using namespace mozilla::gl; namespace mozilla { namespace layers { ClientCanvasLayer::~ClientCanvasLayer() { MOZ_COUNT_DTOR(ClientCanvasLayer); + if (mBufferProvider) { + mBufferProvider->ClearCachedResources(); + } if (mCanvasClient) { mCanvasClient->OnDetach(); mCanvasClient = nullptr; } } void ClientCanvasLayer::Initialize(const Data& aData)
--- a/gfx/layers/client/ClientCanvasLayer.h +++ b/gfx/layers/client/ClientCanvasLayer.h @@ -51,38 +51,47 @@ public: } virtual void Initialize(const Data& aData) override; virtual void RenderLayer() override; virtual void ClearCachedResources() override { + if (mBufferProvider) { + mBufferProvider->ClearCachedResources(); + } if (mCanvasClient) { mCanvasClient->Clear(); } } virtual void HandleMemoryPressure() override { + if (mBufferProvider) { + mBufferProvider->ClearCachedResources(); + } if (mCanvasClient) { mCanvasClient->HandleMemoryPressure(); } } virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) override { aAttrs = CanvasLayerAttributes(mSamplingFilter, mBounds); } virtual Layer* AsLayer() override { return this; } virtual ShadowableLayer* AsShadowableLayer() override { return this; } virtual void Disconnect() override { + if (mBufferProvider) { + mBufferProvider->ClearCachedResources(); + } mCanvasClient = nullptr; ClientLayer::Disconnect(); } virtual CompositableClient* GetCompositableClient() override { return mCanvasClient; }
--- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -1045,10 +1045,19 @@ ShadowLayerForwarder::GetCompositorBridg } if (!mShadowManager) { return nullptr; } mCompositorBridgeChild = static_cast<CompositorBridgeChild*>(mShadowManager->Manager()); return mCompositorBridgeChild; } +void +ShadowLayerForwarder::SyncWithCompositor() +{ + auto compositorBridge = GetCompositorBridgeChild(); + if (compositorBridge && compositorBridge->IPCOpen()) { + compositorBridge->SendSyncWithCompositor(); + } +} + } // namespace layers } // namespace mozilla
--- a/gfx/layers/ipc/ShadowLayers.h +++ b/gfx/layers/ipc/ShadowLayers.h @@ -387,16 +387,26 @@ public: bool InForwarderThread() override { return NS_IsMainThread(); } // Returns true if aSurface wraps a Shmem. static bool IsShmem(SurfaceDescriptor* aSurface); + /** + * Sends a synchronous ping to the compsoitor. + * + * This is bad for performance and should only be called as a last resort if the + * compositor may be blocked for a long period of time, to avoid that the content + * process accumulates resource allocations that the compositor is not consuming + * and releasing. + */ + void SyncWithCompositor(); + TextureForwarder* GetTextureForwarder() override { return GetCompositorBridgeChild(); } LayersIPCActor* GetLayersIPCActor() override { return this; } ActiveResourceTracker& GetActiveResourceTracker() { return *mActiveResourceTracker.get(); } protected: virtual ~ShadowLayerForwarder(); explicit ShadowLayerForwarder(ClientLayerManager* aClientLayerManager);