Bug 1411472 - Add support of PersistentBufferProviderShared r=nical
authorsotaro <sotaro.ikeda.g@gmail.com>
Thu, 16 Nov 2017 14:47:26 +0900
changeset 392194 4a74a02c20ba4649bfdb5bdd49f5907c6f22b2d5
parent 392193 917dfffde62acfc2315de61385f82dfb6f29a440
child 392195 92235deefc25008210fc2d433cb92174d6adf1b1
child 392292 3fa17ac9d0ee1b379dd3b27392725d55735be5f4
push id55477
push userrgurzau@mozilla.com
push dateThu, 16 Nov 2017 10:16:50 +0000
treeherderautoland@1dd02399f872 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1411472
milestone59.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
Bug 1411472 - Add support of PersistentBufferProviderShared r=nical
dom/canvas/CanvasRenderingContext2D.cpp
gfx/layers/PersistentBufferProvider.cpp
gfx/layers/PersistentBufferProvider.h
gfx/layers/ShareableCanvasRenderer.cpp
gfx/layers/ipc/KnowsCompositor.h
gfx/layers/ipc/ShadowLayers.h
gfx/layers/wr/WebRenderBridgeChild.cpp
gfx/layers/wr/WebRenderBridgeChild.h
gfx/layers/wr/WebRenderCanvasRenderer.cpp
gfx/layers/wr/WebRenderLayerManager.cpp
gfx/layers/wr/WebRenderLayerManager.h
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -1879,17 +1879,19 @@ CanvasRenderingContext2D::TrySharedTarge
 {
   aOutDT = nullptr;
   aOutProvider = nullptr;
 
   if (!mCanvasElement || !mCanvasElement->OwnerDoc()) {
     return false;
   }
 
-  if (mBufferProvider && mBufferProvider->GetType() == LayersBackend::LAYERS_CLIENT) {
+  if (mBufferProvider &&
+      (mBufferProvider->GetType() == LayersBackend::LAYERS_CLIENT ||
+       mBufferProvider->GetType() == LayersBackend::LAYERS_WR)) {
     // we are already using a shared buffer provider, we are allocating a new one
     // because the current one failed so let's just fall back to the basic provider.
     return false;
   }
 
   RefPtr<LayerManager> layerManager = LayerManagerFromCanvasElement(mCanvasElement);
 
   if (!layerManager) {
@@ -5591,17 +5593,19 @@ CanvasRenderingContext2D::DrawWindow(nsG
       GlobalAlpha() == 1.0f) {
     op = UsedOperation();
     if (!IsTargetValid()) {
       aError.Throw(NS_ERROR_FAILURE);
       return;
     }
   }
   if (op == CompositionOp::OP_OVER &&
-      (!mBufferProvider || mBufferProvider->GetType() != LayersBackend::LAYERS_CLIENT))
+      (!mBufferProvider ||
+       (mBufferProvider->GetType() != LayersBackend::LAYERS_CLIENT &&
+        mBufferProvider->GetType() != LayersBackend::LAYERS_WR)))
   {
     thebes = gfxContext::CreateOrNull(mTarget);
     MOZ_ASSERT(thebes); // already checked the draw target above
                         // (in SupportsAzureContentForDrawTarget)
     thebes->SetMatrix(matrix);
   } else {
     IntSize dtSize = IntSize::Ceil(sw, sh);
     if (!Factory::AllowedSurfaceSize(dtSize)) {
--- a/gfx/layers/PersistentBufferProvider.cpp
+++ b/gfx/layers/PersistentBufferProvider.cpp
@@ -3,16 +3,17 @@
 /* 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/layers/TextureClient.h"
 #include "mozilla/gfx/Logging.h"
 #include "pratom.h"
 #include "gfxPlatform.h"
 
 namespace mozilla {
 
 using namespace gfx;
 
@@ -83,97 +84,108 @@ PersistentBufferProviderBasic::Create(gf
   return provider.forget();
 }
 
 
 //static
 already_AddRefed<PersistentBufferProviderShared>
 PersistentBufferProviderShared::Create(gfx::IntSize aSize,
                                        gfx::SurfaceFormat aFormat,
-                                       ShadowLayerForwarder* aFwd)
+                                       KnowsCompositor* aKnowsCompositor)
 {
-  if (!aFwd || !aFwd->GetTextureForwarder()->IPCOpen()) {
+  if (!aKnowsCompositor || !aKnowsCompositor->GetTextureForwarder()->IPCOpen()) {
     return nullptr;
   }
 
   RefPtr<TextureClient> texture = TextureClient::CreateForDrawing(
-    aFwd, aFormat, aSize,
+    aKnowsCompositor, aFormat, aSize,
     BackendSelector::Canvas,
     TextureFlags::DEFAULT,
     TextureAllocationFlags::ALLOC_DEFAULT
   );
 
   if (!texture) {
     return nullptr;
   }
 
   RefPtr<PersistentBufferProviderShared> provider =
-    new PersistentBufferProviderShared(aSize, aFormat, aFwd, texture);
+    new PersistentBufferProviderShared(aSize, aFormat, aKnowsCompositor, texture);
   return provider.forget();
 }
 
 PersistentBufferProviderShared::PersistentBufferProviderShared(gfx::IntSize aSize,
                                                                gfx::SurfaceFormat aFormat,
-                                                               ShadowLayerForwarder* aFwd,
+                                                               KnowsCompositor* aKnowsCompositor,
                                                                RefPtr<TextureClient>& aTexture)
 
 : mSize(aSize)
 , mFormat(aFormat)
-, mFwd(aFwd)
+, mKnowsCompositor(aKnowsCompositor)
 , mFront(Nothing())
 {
+  MOZ_ASSERT(aKnowsCompositor);
   if (mTextures.append(aTexture)) {
     mBack = Some<uint32_t>(0);
   }
   MOZ_COUNT_CTOR(PersistentBufferProviderShared);
 }
 
 PersistentBufferProviderShared::~PersistentBufferProviderShared()
 {
   MOZ_COUNT_DTOR(PersistentBufferProviderShared);
 
   if (IsActivityTracked()) {
-    mFwd->GetActiveResourceTracker().RemoveObject(this);
+    mKnowsCompositor->GetActiveResourceTracker()->RemoveObject(this);
   }
 
   Destroy();
 }
 
-bool
-PersistentBufferProviderShared::SetForwarder(ShadowLayerForwarder* aFwd)
+LayersBackend
+PersistentBufferProviderShared::GetType()
 {
-  MOZ_ASSERT(aFwd);
-  if (!aFwd) {
+  if (mKnowsCompositor->GetCompositorBackendType() == LayersBackend::LAYERS_WR) {
+    return LayersBackend::LAYERS_WR;
+  } else {
+    return LayersBackend::LAYERS_CLIENT;
+  }
+}
+
+bool
+PersistentBufferProviderShared::SetKnowsCompositor(KnowsCompositor* aKnowsCompositor)
+{
+  MOZ_ASSERT(aKnowsCompositor);
+  if (!aKnowsCompositor) {
     return false;
   }
 
-  if (mFwd == aFwd) {
+  if (mKnowsCompositor == aKnowsCompositor) {
     // The forwarder should not change most of the time.
     return true;
   }
 
   if (IsActivityTracked()) {
-    mFwd->GetActiveResourceTracker().RemoveObject(this);
+    mKnowsCompositor->GetActiveResourceTracker()->RemoveObject(this);
   }
 
-  if (mFwd->GetTextureForwarder() != aFwd->GetTextureForwarder() ||
-      mFwd->GetCompositorBackendType() != aFwd->GetCompositorBackendType()) {
+  if (mKnowsCompositor->GetTextureForwarder() != aKnowsCompositor->GetTextureForwarder() ||
+      mKnowsCompositor->GetCompositorBackendType() != aKnowsCompositor->GetCompositorBackendType()) {
     // We are going to be used with an different and/or incompatible forwarder.
     // This should be extremely rare. We have to copy the front buffer into a
     // texture that is compatible with the new forwarder.
 
     // Grab the current front buffer.
     RefPtr<TextureClient> prevTexture = GetTexture(mFront);
 
     // Get rid of everything else
     Destroy();
 
     if (prevTexture) {
       RefPtr<TextureClient> newTexture = TextureClient::CreateForDrawing(
-        aFwd, mFormat, mSize,
+        aKnowsCompositor, mFormat, mSize,
         BackendSelector::Canvas,
         TextureFlags::DEFAULT,
         TextureAllocationFlags::ALLOC_DEFAULT
       );
 
       MOZ_ASSERT(newTexture);
       if (!newTexture) {
         return false;
@@ -205,43 +217,43 @@ PersistentBufferProviderShared::SetForwa
       if (!mTextures.append(newTexture)) {
         return false;
       }
       mFront = Some<uint32_t>(mTextures.length() - 1);
       mBack = mFront;
     }
   }
 
-  mFwd = aFwd;
+  mKnowsCompositor = aKnowsCompositor;
 
   return true;
 }
 
 TextureClient*
 PersistentBufferProviderShared::GetTexture(const Maybe<uint32_t>& aIndex)
 {
   if (aIndex.isNothing() || !CheckIndex(aIndex.value())) {
     return nullptr;
   }
   return mTextures[aIndex.value()];
 }
 
 already_AddRefed<gfx::DrawTarget>
 PersistentBufferProviderShared::BorrowDrawTarget(const gfx::IntRect& aPersistedRect)
 {
-  if (!mFwd->GetTextureForwarder()->IPCOpen()) {
+  if (!mKnowsCompositor->GetTextureForwarder()->IPCOpen()) {
     return nullptr;
   }
 
   MOZ_ASSERT(!mSnapshot);
 
   if (IsActivityTracked()) {
-    mFwd->GetActiveResourceTracker().MarkUsed(this);
+    mKnowsCompositor->GetActiveResourceTracker()->MarkUsed(this);
   } else {
-    mFwd->GetActiveResourceTracker().AddObject(this);
+    mKnowsCompositor->GetActiveResourceTracker()->AddObject(this);
   }
 
   if (mDrawTarget) {
     RefPtr<gfx::DrawTarget> dt(mDrawTarget);
     return dt.forget();
   }
 
   auto previousBackBuffer = mBack;
@@ -273,17 +285,17 @@ PersistentBufferProviderShared::BorrowDr
       // We should never need to buffer that many textures, something's wrong.
       // 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 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();
+      mKnowsCompositor->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;
         }
@@ -295,17 +307,17 @@ PersistentBufferProviderShared::BorrowDr
         // 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,
+      mKnowsCompositor, mFormat, mSize,
       BackendSelector::Canvas,
       TextureFlags::DEFAULT,
       TextureAllocationFlags::ALLOC_DEFAULT
     );
 
     MOZ_ASSERT(newTexture);
     if (newTexture) {
       if (mTextures.append(newTexture)) {
--- a/gfx/layers/PersistentBufferProvider.h
+++ b/gfx/layers/PersistentBufferProvider.h
@@ -4,31 +4,33 @@
  * 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 MOZILLA_GFX_PersistentBUFFERPROVIDER_H
 #define MOZILLA_GFX_PersistentBUFFERPROVIDER_H
 
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/RefPtr.h"             // for RefPtr, already_AddRefed, etc
+#include "mozilla/layers/KnowsCompositor.h"
 #include "mozilla/layers/LayersTypes.h"
-#include "mozilla/layers/ShadowLayers.h"
+#include "mozilla/RefCounted.h"
 #include "mozilla/gfx/Types.h"
 #include "mozilla/Vector.h"
 
 namespace mozilla {
 
 namespace gfx {
   class SourceSurface;
   class DrawTarget;
 }
 
 namespace layers {
 
 class CopyableCanvasLayer;
+class TextureClient;
 
 /**
  * A PersistentBufferProvider is for users which require the temporary use of
  * a DrawTarget to draw into. When they're done drawing they return the
  * DrawTarget, when they later need to continue drawing they get a DrawTarget
  * from the provider again, the provider will guarantee the contents of the
  * previously returned DrawTarget is persisted into the one newly returned.
  */
@@ -60,17 +62,17 @@ public:
   virtual already_AddRefed<gfx::SourceSurface> BorrowSnapshot() = 0;
 
   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 bool SetKnowsCompositor(KnowsCompositor* aKnowsCompositor) { 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).
@@ -115,54 +117,54 @@ private:
 class PersistentBufferProviderShared : public PersistentBufferProvider
                                      , public ActiveResource
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PersistentBufferProviderShared, override)
 
   static already_AddRefed<PersistentBufferProviderShared>
   Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
-         ShadowLayerForwarder* aFwd);
+         KnowsCompositor* aKnowsCompositor);
 
-  virtual LayersBackend GetType() override { return LayersBackend::LAYERS_CLIENT; }
+  virtual LayersBackend GetType() override;
 
   virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget(const gfx::IntRect& aPersistedRect) override;
 
   virtual bool ReturnDrawTarget(already_AddRefed<gfx::DrawTarget> aDT) override;
 
   virtual already_AddRefed<gfx::SourceSurface> BorrowSnapshot() override;
 
   virtual void ReturnSnapshot(already_AddRefed<gfx::SourceSurface> aSnapshot) override;
 
   virtual TextureClient* GetTextureClient() override;
 
   virtual void NotifyInactive() override;
 
   virtual void OnShutdown() override { Destroy(); }
 
-  virtual bool SetForwarder(ShadowLayerForwarder* aFwd) override;
+  virtual bool SetKnowsCompositor(KnowsCompositor* aKnowsCompositor) override;
 
   virtual void ClearCachedResources() override;
 
   virtual bool PreservesDrawingState() const override { return false; }
 protected:
   PersistentBufferProviderShared(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
-                                 ShadowLayerForwarder* aFwd,
+                                 KnowsCompositor* aKnowsCompositor,
                                  RefPtr<TextureClient>& aTexture);
 
   ~PersistentBufferProviderShared();
 
   TextureClient* GetTexture(const Maybe<uint32_t>& aIndex);
   bool CheckIndex(uint32_t aIndex) { return aIndex < mTextures.length(); }
 
   void Destroy();
 
   gfx::IntSize mSize;
   gfx::SurfaceFormat mFormat;
-  RefPtr<ShadowLayerForwarder> mFwd;
+  RefPtr<KnowsCompositor> mKnowsCompositor;
   Vector<RefPtr<TextureClient>, 4> mTextures;
   // Offset of the texture in mTextures that the canvas uses.
   Maybe<uint32_t> mBack;
   // Offset of the texture in mTextures that is presented to the compositor.
   Maybe<uint32_t> mFront;
 
   RefPtr<gfx::DrawTarget> mDrawTarget;
   RefPtr<gfx::SourceSurface > mSnapshot;
--- a/gfx/layers/ShareableCanvasRenderer.cpp
+++ b/gfx/layers/ShareableCanvasRenderer.cpp
@@ -221,17 +221,17 @@ ShareableCanvasRenderer::UpdateComposita
 
   if (!IsDirty()) {
     return;
   }
   ResetDirty();
 
   FirePreTransactionCallback();
   if (mBufferProvider && mBufferProvider->GetTextureClient()) {
-    if (!mBufferProvider->SetForwarder(GetForwarder()->AsLayerForwarder())) {
+    if (!mBufferProvider->SetKnowsCompositor(GetForwarder())) {
       gfxCriticalNote << "BufferProvider::SetForwarder failed";
       return;
     }
     mCanvasClient->UpdateFromTexture(mBufferProvider->GetTextureClient());
   } else {
     mCanvasClient->Update(gfx::IntSize(mSize.width, mSize.height), this);
   }
 
--- a/gfx/layers/ipc/KnowsCompositor.h
+++ b/gfx/layers/ipc/KnowsCompositor.h
@@ -4,25 +4,57 @@
  * 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 MOZILLA_LAYERS_KNOWSCOMPOSITOR
 #define MOZILLA_LAYERS_KNOWSCOMPOSITOR
 
 #include "mozilla/layers/LayersTypes.h"  // for LayersBackend
 #include "mozilla/layers/CompositorTypes.h"
+#include "nsExpirationTracker.h"
 
 namespace mozilla {
 namespace layers {
 
 class SyncObjectClient;
 class TextureForwarder;
 class LayersIPCActor;
 
 /**
+ * See ActiveResourceTracker below.
+ */
+class ActiveResource
+{
+public:
+ virtual void NotifyInactive() = 0;
+  nsExpirationState* GetExpirationState() { return &mExpirationState; }
+  bool IsActivityTracked() { return mExpirationState.IsTracked(); }
+private:
+  nsExpirationState mExpirationState;
+};
+
+/**
+ * A convenience class on top of nsExpirationTracker
+ */
+class ActiveResourceTracker : public nsExpirationTracker<ActiveResource, 3>
+{
+public:
+  ActiveResourceTracker(uint32_t aExpirationCycle, const char* aName,
+                        nsIEventTarget* aEventTarget)
+  : nsExpirationTracker(aExpirationCycle, aName, aEventTarget)
+  {}
+
+  virtual void NotifyExpired(ActiveResource* aResource) override
+  {
+    RemoveObject(aResource);
+    aResource->NotifyInactive();
+  }
+};
+
+/**
  * An abstract interface for classes that are tied to a specific Compositor across
  * IPDL and uses TextureFactoryIdentifier to describe this Compositor.
  */
 class KnowsCompositor {
 public:
   NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
 
   KnowsCompositor();
@@ -74,20 +106,38 @@ public:
 
   bool DeviceCanReset() const {
     return GetCompositorBackendType() != LayersBackend::LAYERS_BASIC;
   }
 
   int32_t GetSerial() { return mSerial; }
 
   /**
+   * 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.
+   */
+  virtual void SyncWithCompositor()
+  {
+    MOZ_ASSERT_UNREACHABLE("Unimplemented");
+  }
+
+  /**
    * Helpers for finding other related interface. These are infallible.
    */
   virtual TextureForwarder* GetTextureForwarder() = 0;
   virtual LayersIPCActor* GetLayersIPCActor() = 0;
+  virtual ActiveResourceTracker* GetActiveResourceTracker()
+  {
+    MOZ_ASSERT_UNREACHABLE("Unimplemented");
+    return nullptr;
+  }
 
 protected:
   TextureFactoryIdentifier mTextureFactoryIdentifier;
   RefPtr<SyncObjectClient> mSyncObject;
 
   const int32_t mSerial;
   static mozilla::Atomic<int32_t> sSerialCounter;
 };
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -21,17 +21,16 @@
 #include "mozilla/layers/TextureForwarder.h"
 #include "mozilla/layers/CompositorTypes.h"  // for OpenMode, etc
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArrayForwardDeclare.h"     // for InfallibleTArray
 #include "nsIWidget.h"
 #include <vector>
-#include "nsExpirationTracker.h"
 
 namespace mozilla {
 namespace layers {
 
 class ClientLayerManager;
 class CompositorBridgeChild;
 class FixedSizeSmallShmemSectionAllocator;
 class ImageContainer;
@@ -41,47 +40,16 @@ class LayerTransactionChild;
 class ShadowableLayer;
 class SurfaceDescriptor;
 class TextureClient;
 class ThebesBuffer;
 class ThebesBufferData;
 class Transaction;
 
 /**
- * See ActiveResourceTracker below.
- */
-class ActiveResource
-{
-public:
- virtual void NotifyInactive() = 0;
-  nsExpirationState* GetExpirationState() { return &mExpirationState; }
-  bool IsActivityTracked() { return mExpirationState.IsTracked(); }
-private:
-  nsExpirationState mExpirationState;
-};
-
-/**
- * A convenience class on top of nsExpirationTracker
- */
-class ActiveResourceTracker : public nsExpirationTracker<ActiveResource, 3>
-{
-public:
-  ActiveResourceTracker(uint32_t aExpirationCycle, const char* aName,
-                        nsIEventTarget* aEventTarget)
-  : nsExpirationTracker(aExpirationCycle, aName, aEventTarget)
-  {}
-
-  virtual void NotifyExpired(ActiveResource* aResource) override
-  {
-    RemoveObject(aResource);
-    aResource->NotifyInactive();
-  }
-};
-
-/**
  * We want to share layer trees across thread contexts and address
  * spaces for several reasons; chief among them
  *
  *  - a parent process can paint a child process's layer tree while
  *    the child process is blocked, say on content script.  This is
  *    important on mobile devices where UI responsiveness is key.
  *
  *  - a dedicated "compositor" process can asynchronously (wrt the
@@ -404,30 +372,22 @@ public:
     return mPaintTiming;
   }
 
   ShadowLayerForwarder* AsLayerForwarder() override { return this; }
 
   // 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();
+  void SyncWithCompositor() override;
 
   TextureForwarder* GetTextureForwarder() override { return GetCompositorBridgeChild(); }
   LayersIPCActor* GetLayersIPCActor() override { return this; }
 
-  ActiveResourceTracker& GetActiveResourceTracker() { return *mActiveResourceTracker.get(); }
+  ActiveResourceTracker* GetActiveResourceTracker() override { return mActiveResourceTracker.get(); }
 
   CompositorBridgeChild* GetCompositorBridgeChild();
 
   nsIEventTarget* GetEventTarget() { return mEventTarget; };
 
 protected:
   virtual ~ShadowLayerForwarder();
 
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "mozilla/layers/WebRenderBridgeChild.h"
 
 #include "gfxPlatform.h"
+#include "mozilla/dom/TabGroup.h"
 #include "mozilla/layers/CompositableClient.h"
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/IpcResourceUpdateQueue.h"
 #include "mozilla/layers/StackingContextHelper.h"
 #include "mozilla/layers/PTextureChild.h"
 #include "mozilla/layers/WebRenderLayerManager.h"
 #include "mozilla/webrender/WebRenderAPI.h"
@@ -31,37 +32,51 @@ WebRenderBridgeChild::WebRenderBridgeChi
   , mManager(nullptr)
   , mIPCOpen(false)
   , mDestroyed(false)
   , mFontKeysDeleted(0)
   , mFontInstanceKeysDeleted(0)
 {
 }
 
+WebRenderBridgeChild::~WebRenderBridgeChild()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mDestroyed);
+}
+
 void
 WebRenderBridgeChild::Destroy(bool aIsSync)
 {
   if (!IPCOpen()) {
     return;
   }
-  // mDestroyed is used to prevent calling Send__delete__() twice.
-  // When this function is called from CompositorBridgeChild::Destroy().
-  mDestroyed = true;
-  mManager = nullptr;
+
+  DoDestroy();
 
   if (aIsSync) {
     SendShutdownSync();
   } else {
     SendShutdown();
   }
 }
 
 void
 WebRenderBridgeChild::ActorDestroy(ActorDestroyReason why)
 {
+  DoDestroy();
+}
+
+void
+WebRenderBridgeChild::DoDestroy()
+{
+  // mDestroyed is used to prevent calling Send__delete__() twice.
+  // When this function is called from CompositorBridgeChild::Destroy().
+  // mActiveResourceTracker is not cleared here, since it is
+  // used by PersistentBufferProviderShared.
   mDestroyed = true;
   mManager = nullptr;
 }
 
 void
 WebRenderBridgeChild::AddWebRenderParentCommand(const WebRenderParentCommand& aCmd)
 {
   MOZ_ASSERT(mIsInTransaction || mIsInClearCachedResources);
@@ -397,16 +412,25 @@ WebRenderBridgeChild::GetTextureForwarde
 
 LayersIPCActor*
 WebRenderBridgeChild::GetLayersIPCActor()
 {
   return static_cast<LayersIPCActor*>(GetCompositorBridgeChild());
 }
 
 void
+WebRenderBridgeChild::SyncWithCompositor()
+{
+  auto compositorBridge = GetCompositorBridgeChild();
+  if (compositorBridge && compositorBridge->IPCOpen()) {
+    compositorBridge->SendSyncWithCompositor();
+  }
+}
+
+void
 WebRenderBridgeChild::Connect(CompositableClient* aCompositable,
                               ImageContainer* aImageContainer)
 {
   MOZ_ASSERT(!mDestroyed);
   MOZ_ASSERT(aCompositable);
 
   static uint64_t sNextID = 1;
   uint64_t id = sNextID++;
@@ -581,18 +605,26 @@ WebRenderBridgeChild::EndClearCachedReso
   ProcessWebRenderParentCommands();
   SendClearCachedResources();
   mIsInClearCachedResources = false;
 }
 
 void
 WebRenderBridgeChild::SetWebRenderLayerManager(WebRenderLayerManager* aManager)
 {
-  MOZ_ASSERT(aManager);
+  MOZ_ASSERT(aManager && !mManager);
   mManager = aManager;
+
+  nsCOMPtr<nsIEventTarget> eventTarget = nullptr;
+  if (dom::TabGroup* tabGroup = mManager->GetTabGroup()) {
+    eventTarget = tabGroup->EventTargetFor(TaskCategory::Other);
+  }
+  MOZ_ASSERT(eventTarget || !XRE_IsContentProcess());
+  mActiveResourceTracker = MakeUnique<ActiveResourceTracker>(
+    1000, "CompositableForwarder", eventTarget);
 }
 
 ipc::IShmemAllocator*
 WebRenderBridgeChild::GetShmemAllocator()
 {
   return static_cast<CompositorBridgeChild*>(Manager());
 }
 
--- a/gfx/layers/wr/WebRenderBridgeChild.h
+++ b/gfx/layers/wr/WebRenderBridgeChild.h
@@ -83,16 +83,18 @@ public:
 
   CompositorBridgeChild* GetCompositorBridgeChild();
 
   wr::PipelineId GetPipeline() { return mPipelineId; }
 
   // KnowsCompositor
   TextureForwarder* GetTextureForwarder() override;
   LayersIPCActor* GetLayersIPCActor() override;
+  void SyncWithCompositor() override;
+  ActiveResourceTracker* GetActiveResourceTracker() override { return mActiveResourceTracker.get(); }
 
   void AddPipelineIdForAsyncCompositable(const wr::PipelineId& aPipelineId,
                                          const CompositableHandle& aHandlee);
   void AddPipelineIdForCompositable(const wr::PipelineId& aPipelineId,
                                     const CompositableHandle& aHandlee);
   void RemovePipelineIdForCompositable(const wr::PipelineId& aPipelineId);
 
   wr::ExternalImageId AllocExternalImageIdForCompositable(CompositableClient* aCompositable);
@@ -146,17 +148,17 @@ public:
 
   void SetWebRenderLayerManager(WebRenderLayerManager* aManager);
 
   ipc::IShmemAllocator* GetShmemAllocator();
 
 private:
   friend class CompositorBridgeChild;
 
-  ~WebRenderBridgeChild() {}
+  ~WebRenderBridgeChild();
 
   wr::ExternalImageId GetNextExternalImageId();
 
   // CompositableForwarder
   void Connect(CompositableClient* aCompositable,
                ImageContainer* aImageContainer = nullptr) override;
   void UseTiledLayerBuffer(CompositableClient* aCompositable,
                            const SurfaceDescriptorTiles& aTiledDescriptor) override;
@@ -174,16 +176,18 @@ private:
                                  TextureClient* aClientOnBlack,
                                  TextureClient* aClientOnWhite) override;
   void UpdateFwdTransactionId() override;
   uint64_t GetFwdTransactionId() override;
   bool InForwarderThread() override;
 
   void ActorDestroy(ActorDestroyReason why) override;
 
+  void DoDestroy();
+
   virtual mozilla::ipc::IPCResult RecvWrUpdated(const wr::IdNamespace& aNewIdNamespace) override;
 
   void AddIPDLReference() {
     MOZ_ASSERT(mIPCOpen == false);
     mIPCOpen = true;
     AddRef();
   }
   void ReleaseIPDLReference() {
@@ -209,14 +213,16 @@ private:
   bool mIPCOpen;
   bool mDestroyed;
 
   uint32_t mFontKeysDeleted;
   nsDataHashtable<UnscaledFontHashKey, wr::FontKey> mFontKeys;
 
   uint32_t mFontInstanceKeysDeleted;
   nsDataHashtable<ScaledFontHashKey, wr::FontInstanceKey> mFontInstanceKeys;
+
+  UniquePtr<ActiveResourceTracker> mActiveResourceTracker;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_layers_WebRenderBridgeChild_h
--- a/gfx/layers/wr/WebRenderCanvasRenderer.cpp
+++ b/gfx/layers/wr/WebRenderCanvasRenderer.cpp
@@ -3,16 +3,17 @@
 /* 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 "WebRenderCanvasRenderer.h"
 
 #include "GLContext.h"
 #include "GLScreenBuffer.h"
+#include "mozilla/layers/CompositorBridgeChild.h"
 #include "SharedSurfaceGL.h"
 #include "WebRenderBridgeChild.h"
 #include "WebRenderLayerManager.h"
 
 namespace mozilla {
 namespace layers {
 
 CompositableForwarder*
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -5,16 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebRenderLayerManager.h"
 
 #include "BasicLayers.h"
 #include "gfxPrefs.h"
 #include "GeckoProfiler.h"
 #include "LayersLogging.h"
+#include "mozilla/dom/TabChild.h"
+#include "mozilla/dom/TabGroup.h"
 #include "mozilla/gfx/DrawEventRecorder.h"
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/IpcResourceUpdateQueue.h"
 #include "mozilla/layers/StackingContextHelper.h"
 #include "mozilla/layers/TextureClient.h"
 #include "mozilla/layers/WebRenderBridgeChild.h"
 #include "mozilla/layers/UpdateImageHelper.h"
 #include "nsDisplayList.h"
@@ -83,16 +85,18 @@ void
 WebRenderLayerManager::Destroy()
 {
   DoDestroy(/* aIsSync */ false);
 }
 
 void
 WebRenderLayerManager::DoDestroy(bool aIsSync)
 {
+  MOZ_ASSERT(NS_IsMainThread());
+
   if (IsDestroyed()) {
     return;
   }
 
   LayerManager::Destroy();
 
   if (WrBridge()) {
     // Just clear ImageKeys, they are deleted during WebRenderAPI destruction.
@@ -524,16 +528,27 @@ WebRenderLayerManager::ClearCachedResour
 
 void
 WebRenderLayerManager::WrUpdated()
 {
   mWebRenderCommandBuilder.ClearCachedResources();
   DiscardLocalImages();
 }
 
+dom::TabGroup*
+WebRenderLayerManager::GetTabGroup()
+{
+  if (mWidget) {
+    if (dom::TabChild* tabChild = mWidget->GetOwningTabChild()) {
+      return tabChild->TabGroup();
+    }
+  }
+  return nullptr;
+}
+
 void
 WebRenderLayerManager::UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier& aNewIdentifier)
 {
   WrBridge()->IdentifyTextureHost(aNewIdentifier);
 }
 
 TextureFactoryIdentifier
 WebRenderLayerManager::GetTextureFactoryIdentifier()
@@ -603,10 +618,24 @@ bool
 WebRenderLayerManager::SetPendingScrollUpdateForNextTransaction(FrameMetrics::ViewID aScrollId,
                                                                 const ScrollUpdateInfo& aUpdateInfo)
 {
   // If we ever support changing the scroll position in an "empty transactions"
   // properly in WR we can fill this in. Covered by bug 1382259.
   return false;
 }
 
+already_AddRefed<PersistentBufferProvider>
+WebRenderLayerManager::CreatePersistentBufferProvider(const gfx::IntSize& aSize,
+                                                      gfx::SurfaceFormat aFormat)
+{
+  if (gfxPrefs::PersistentBufferProviderSharedEnabled()) {
+    RefPtr<PersistentBufferProvider> provider
+      = PersistentBufferProviderShared::Create(aSize, aFormat, AsKnowsCompositor());
+    if (provider) {
+      return provider.forget();
+    }
+  }
+  return LayerManager::CreatePersistentBufferProvider(aSize, aFormat);
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -25,16 +25,19 @@
 #include "nsDisplayList.h"
 
 class nsIWidget;
 
 namespace mozilla {
 
 struct ActiveScrolledRoot;
 
+namespace dom {
+class TabGroup;
+}
 
 namespace layers {
 
 class CompositorBridgeChild;
 class KnowsCompositor;
 class PCompositorBridgeChild;
 class WebRenderBridgeChild;
 class WebRenderParentCommand;
@@ -113,16 +116,19 @@ public:
   virtual void SetNeedsComposite(bool aNeedsComposite) override
   {
     mNeedsComposite = aNeedsComposite;
   }
   virtual bool NeedsComposite() const override { return mNeedsComposite; }
   virtual void SetIsFirstPaint() override { mIsFirstPaint = true; }
   virtual void SetFocusTarget(const FocusTarget& aFocusTarget) override;
 
+  virtual already_AddRefed<PersistentBufferProvider>
+  CreatePersistentBufferProvider(const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat) override;
+
   bool AsyncPanZoomEnabled() const override;
 
   // adds an imagekey to a list of keys that will be discarded on the next
   // transaction or destruction
   void AddImageKeyForDiscard(wr::ImageKey);
   void DiscardImages();
   void DiscardLocalImages();
 
@@ -151,16 +157,18 @@ public:
 
   WebRenderCommandBuilder& CommandBuilder() { return mWebRenderCommandBuilder; }
   WebRenderUserDataRefTable* GetWebRenderUserDataTable() { return mWebRenderCommandBuilder.GetWebRenderUserDataTable(); }
   WebRenderScrollData& GetScrollData() { return mScrollData; }
 
   void WrUpdated();
   void WindowOverlayChanged() { mWindowOverlayChanged = true; }
 
+  dom::TabGroup* GetTabGroup();
+
 private:
   /**
    * Take a snapshot of the parent context, and copy
    * it into mTarget.
    */
   void MakeSnapshotIfRequired(LayoutDeviceIntSize aSize);
 
   void ClearLayer(Layer* aLayer);