Bug 1411472 - Add support of PersistentBufferProviderShared r=nical
authorsotaro <sotaro.ikeda.g@gmail.com>
Tue, 07 Nov 2017 09:31:58 +0900
changeset 434939 89513063a10631897ae55d14828e965c8ebe7aab
parent 434938 cd9f14f9ea6d4bcd175874352c402613503a86d8
child 434940 bee168acd12893a551d9a1e2b9204c667ce629a1
push id117
push userfmarier@mozilla.com
push dateTue, 28 Nov 2017 20:17:16 +0000
reviewersnical
bugs1411472
milestone58.0a1
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) {
@@ -5593,17 +5595,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(gfxMatrix(matrix._11, matrix._12, matrix._21,
                                 matrix._22, matrix._31, matrix._32));
   } else {
     IntSize dtSize = IntSize::Ceil(sw, sh);
--- 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,109 @@ 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 {
+    MOZ_ASSERT(mKnowsCompositor->GetCompositorBackendType() == LayersBackend::LAYERS_CLIENT);
+    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 +218,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 +286,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 +308,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);
@@ -381,16 +396,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++;
@@ -565,18 +589,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.
@@ -542,16 +546,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,
                                                       uint64_t aDeviceResetSeqNo)
 {
   WrBridge()->IdentifyTextureHost(aNewIdentifier);
 }
 
 TextureFactoryIdentifier
@@ -622,10 +637,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;
@@ -114,16 +117,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();
 
@@ -152,16 +158,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);