Backed out 6 changesets (bug 1323957) for intermittent GPU process leaks on a CLOSED TREE.
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 11 Jan 2017 23:09:14 -0500
changeset 376342 81cb9fa2f304dace120f625953aa8b711a30dd9e
parent 376341 46d3af166fcea535f960e2e3dde5728bea86f14b
child 376343 70e02ac9f66b0db9f1d957dc5cfc0db8ba16964e
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1323957
milestone53.0a1
backs out8fe93d5f82a8f4b26be458bf48285606bdf9eb59
5d1615317a36285a6ca6fd747a79141442c6e75a
1ec74a022e80c96dcd7d3113788431af7c5e078b
0a97bbdd54d56cf4b46770b010f4689f7ad5f2bb
70fab4f6d367de679d2358ce5e5994a3b4004cfd
c5ca5b7fcacd561812eae29c41a2b68e3fcdb824
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
Backed out 6 changesets (bug 1323957) for intermittent GPU process leaks on a CLOSED TREE. Backed out changeset 8fe93d5f82a8 (bug 1323957) Backed out changeset 5d1615317a36 (bug 1323957) Backed out changeset 1ec74a022e80 (bug 1323957) Backed out changeset 0a97bbdd54d5 (bug 1323957) Backed out changeset 70fab4f6d367 (bug 1323957) Backed out changeset c5ca5b7fcacd (bug 1323957)
dom/plugins/ipc/PluginInstanceParent.cpp
gfx/ipc/GfxMessageUtils.h
gfx/layers/AsyncCanvasRenderer.cpp
gfx/layers/AsyncCanvasRenderer.h
gfx/layers/ImageContainer.cpp
gfx/layers/ImageContainer.h
gfx/layers/LayersTypes.h
gfx/layers/client/CanvasClient.cpp
gfx/layers/client/CanvasClient.h
gfx/layers/client/ClientLayerManager.cpp
gfx/layers/client/ClientPaintedLayer.cpp
gfx/layers/client/CompositableChild.cpp
gfx/layers/client/CompositableChild.h
gfx/layers/client/CompositableClient.cpp
gfx/layers/client/CompositableClient.h
gfx/layers/client/ContentClient.h
gfx/layers/client/ImageClient.cpp
gfx/layers/client/ImageClient.h
gfx/layers/composite/CompositableHost.cpp
gfx/layers/composite/CompositableHost.h
gfx/layers/composite/ImageHost.cpp
gfx/layers/ipc/CompositableForwarder.cpp
gfx/layers/ipc/CompositableForwarder.h
gfx/layers/ipc/CompositableTransactionParent.cpp
gfx/layers/ipc/CompositableTransactionParent.h
gfx/layers/ipc/ImageBridgeChild.cpp
gfx/layers/ipc/ImageBridgeChild.h
gfx/layers/ipc/ImageBridgeParent.cpp
gfx/layers/ipc/ImageBridgeParent.h
gfx/layers/ipc/LayerTransactionChild.cpp
gfx/layers/ipc/LayerTransactionChild.h
gfx/layers/ipc/LayerTransactionParent.cpp
gfx/layers/ipc/LayerTransactionParent.h
gfx/layers/ipc/LayersMessages.ipdlh
gfx/layers/ipc/PCompositable.ipdl
gfx/layers/ipc/PCompositorBridge.ipdl
gfx/layers/ipc/PImageBridge.ipdl
gfx/layers/ipc/PLayerTransaction.ipdl
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/ShadowLayers.h
gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
gfx/layers/ipc/SharedRGBImage.cpp
gfx/layers/moz.build
widget/nsBaseWidget.cpp
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -1201,17 +1201,17 @@ PluginInstanceParent::EndUpdateBackgroun
 #if defined(XP_WIN)
 nsresult
 PluginInstanceParent::SetScrollCaptureId(uint64_t aScrollCaptureId)
 {
   if (aScrollCaptureId == ImageContainer::sInvalidAsyncContainerId) {
     return NS_ERROR_FAILURE;
   }
 
-  mImageContainer = new ImageContainer(CompositableHandle(aScrollCaptureId));
+  mImageContainer = new ImageContainer(aScrollCaptureId);
   return NS_OK;
 }
 
 nsresult
 PluginInstanceParent::GetScrollCaptureContainer(ImageContainer** aContainer)
 {
   if (!aContainer || !mImageContainer) {
     return NS_ERROR_FAILURE;
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -708,29 +708,16 @@ struct ParamTraits<mozilla::layers::Laye
   static void Write(Message* msg, const paramType& param) {
     WriteParam(msg, param.mHandle);
   }
   static bool Read(const Message* msg, PickleIterator* iter, paramType* result) {
     return ReadParam(msg, iter, &result->mHandle);
   }
 };
 
-template<>
-struct ParamTraits<mozilla::layers::CompositableHandle>
-{
-  typedef mozilla::layers::CompositableHandle paramType;
-
-  static void Write(Message* msg, const paramType& param) {
-    WriteParam(msg, param.mHandle);
-  }
-  static bool Read(const Message* msg, PickleIterator* iter, paramType* result) {
-    return ReadParam(msg, iter, &result->mHandle);
-  }
-};
-
 // Helper class for reading bitfields.
 // If T has bitfields members, derive ParamTraits<T> from BitfieldHelper<T>.
 template <typename ParamType>
 struct BitfieldHelper
 {
   // We need this helper because we can't get the address of a bitfield to
   // pass directly to ReadParam. So instead we read it into a temporary bool
   // and set the bitfield using a setter function
--- a/gfx/layers/AsyncCanvasRenderer.cpp
+++ b/gfx/layers/AsyncCanvasRenderer.cpp
@@ -24,16 +24,17 @@ namespace layers {
 
 AsyncCanvasRenderer::AsyncCanvasRenderer()
   : mHTMLCanvasElement(nullptr)
   , mContext(nullptr)
   , mGLContext(nullptr)
   , mIsAlphaPremultiplied(true)
   , mWidth(0)
   , mHeight(0)
+  , mCanvasClientAsyncID(0)
   , mCanvasClient(nullptr)
   , mMutex("AsyncCanvasRenderer::mMutex")
 {
   MOZ_COUNT_CTOR(AsyncCanvasRenderer);
 }
 
 AsyncCanvasRenderer::~AsyncCanvasRenderer()
 {
@@ -110,19 +111,19 @@ AsyncCanvasRenderer::NotifyElementAboutI
   }
 }
 
 void
 AsyncCanvasRenderer::SetCanvasClient(CanvasClient* aClient)
 {
   mCanvasClient = aClient;
   if (aClient) {
-    mCanvasClientAsyncHandle = aClient->GetAsyncHandle();
+    mCanvasClientAsyncID = aClient->GetAsyncID();
   } else {
-    mCanvasClientAsyncHandle = CompositableHandle();
+    mCanvasClientAsyncID = 0;
   }
 }
 
 void
 AsyncCanvasRenderer::SetActiveThread()
 {
   MutexAutoLock lock(mMutex);
   mActiveThread = NS_GetCurrentThread();
--- a/gfx/layers/AsyncCanvasRenderer.h
+++ b/gfx/layers/AsyncCanvasRenderer.h
@@ -101,19 +101,19 @@ public:
                  const char16_t *aEncoderOptions,
                  nsIInputStream **aStream);
 
   gfx::IntSize GetSize() const
   {
     return gfx::IntSize(mWidth, mHeight);
   }
 
-  CompositableHandle GetCanvasClientAsyncHandle() const
+  uint64_t GetCanvasClientAsyncID() const
   {
-    return mCanvasClientAsyncHandle;
+    return mCanvasClientAsyncID;
   }
 
   CanvasClient* GetCanvasClient() const
   {
     return mCanvasClient;
   }
 
   already_AddRefed<nsIThread> GetActiveThread();
@@ -135,17 +135,17 @@ private:
 
   // Readback current WebGL's content and return it as DataSourceSurface.
   already_AddRefed<gfx::DataSourceSurface> UpdateTarget();
 
   bool mIsAlphaPremultiplied;
 
   uint32_t mWidth;
   uint32_t mHeight;
-  CompositableHandle mCanvasClientAsyncHandle;
+  uint64_t mCanvasClientAsyncID;
 
   // The lifetime of this pointer is controlled by OffscreenCanvas
   // Can be accessed in active thread and ImageBridge thread.
   // But we never accessed it at the same time on both thread. So no
   // need to protect this member.
   CanvasClient* mCanvasClient;
 
   // When backend is LAYER_BASIC and SharedSurface type is Basic.
--- a/gfx/layers/ImageContainer.cpp
+++ b/gfx/layers/ImageContainer.cpp
@@ -105,53 +105,55 @@ ImageContainer::EnsureImageClient(bool a
   if (!aCreate && (!mImageClient || mImageClient->GetForwarder()->GetLayersIPCActor()->IPCOpen())) {
     return;
   }
 
   RefPtr<ImageBridgeChild> imageBridge = ImageBridgeChild::GetSingleton();
   if (imageBridge) {
     mImageClient = imageBridge->CreateImageClient(CompositableType::IMAGE, this);
     if (mImageClient) {
-      mAsyncContainerHandle = mImageClient->GetAsyncHandle();
+      mAsyncContainerID = mImageClient->GetAsyncID();
     }
   }
 }
 
 ImageContainer::ImageContainer(Mode flag)
 : mReentrantMonitor("ImageContainer.mReentrantMonitor"),
   mGenerationCounter(++sGenerationCounter),
   mPaintCount(0),
   mDroppedImageCount(0),
   mImageFactory(new ImageFactory()),
   mRecycleBin(new BufferRecycleBin()),
   mCurrentProducerID(-1)
 {
   if (flag == ASYNCHRONOUS) {
     EnsureImageClient(true);
+  } else {
+    mAsyncContainerID = sInvalidAsyncContainerId;
   }
 }
 
-ImageContainer::ImageContainer(const CompositableHandle& aHandle)
+ImageContainer::ImageContainer(uint64_t aAsyncContainerID)
   : mReentrantMonitor("ImageContainer.mReentrantMonitor"),
   mGenerationCounter(++sGenerationCounter),
   mPaintCount(0),
   mDroppedImageCount(0),
   mImageFactory(nullptr),
   mRecycleBin(nullptr),
-  mAsyncContainerHandle(aHandle),
+  mAsyncContainerID(aAsyncContainerID),
   mCurrentProducerID(-1)
 {
-  MOZ_ASSERT(mAsyncContainerHandle);
+  MOZ_ASSERT(mAsyncContainerID != sInvalidAsyncContainerId);
 }
 
 ImageContainer::~ImageContainer()
 {
-  if (mAsyncContainerHandle) {
+  if (mAsyncContainerID) {
     if (RefPtr<ImageBridgeChild> imageBridge = ImageBridgeChild::GetSingleton()) {
-      imageBridge->ForgetImageContainer(mAsyncContainerHandle);
+      imageBridge->ForgetImageContainer(mAsyncContainerID);
     }
   }
 }
 
 RefPtr<PlanarYCbCrImage>
 ImageContainer::CreatePlanarYCbCrImage()
 {
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
@@ -307,24 +309,24 @@ ImageContainer::SetCurrentImagesInTransa
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   NS_ASSERTION(!mImageClient, "Should use async image transfer with ImageBridge.");
 
   SetCurrentImageInternal(aImages);
 }
 
 bool ImageContainer::IsAsync() const
 {
-  return !!mAsyncContainerHandle;
+  return mAsyncContainerID != sInvalidAsyncContainerId;
 }
 
-CompositableHandle ImageContainer::GetAsyncContainerHandle()
+uint64_t ImageContainer::GetAsyncContainerID()
 {
   NS_ASSERTION(IsAsync(),"Shared image ID is only relevant to async ImageContainers");
   EnsureImageClient(false);
-  return mAsyncContainerHandle;
+  return mAsyncContainerID;
 }
 
 bool
 ImageContainer::HasCurrentImage()
 {
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
 
   return !mCurrentImages.IsEmpty();
--- a/gfx/layers/ImageContainer.h
+++ b/gfx/layers/ImageContainer.h
@@ -361,17 +361,17 @@ public:
 
   explicit ImageContainer(ImageContainer::Mode flag = SYNCHRONOUS);
 
   /**
    * Create ImageContainer just to hold another ASYNCHRONOUS ImageContainer's
    * async container ID.
    * @param aAsyncContainerID async container ID for which we are a proxy
    */
-  explicit ImageContainer(const CompositableHandle& aHandle);
+  explicit ImageContainer(uint64_t aAsyncContainerID);
 
   typedef uint32_t FrameID;
   typedef uint32_t ProducerID;
 
   RefPtr<PlanarYCbCrImage> CreatePlanarYCbCrImage();
 
   // Factory methods for shared image types.
   RefPtr<SharedRGBImage> CreateSharedRGBImage();
@@ -462,17 +462,17 @@ public:
   /**
    * If this ImageContainer uses ImageBridge, returns the ID associated to
    * this container, for use in the ImageBridge protocol.
    * Returns 0 if this ImageContainer does not use ImageBridge. Note that
    * 0 is always an invalid ID for asynchronous image containers.
    *
    * Can be called from any thread.
    */
-  CompositableHandle GetAsyncContainerHandle();
+  uint64_t GetAsyncContainerID();
 
   /**
    * Returns if the container currently has an image.
    * Can be called on any thread. This method takes mReentrantMonitor
    * when accessing thread-shared state.
    */
   bool HasCurrentImage();
 
@@ -620,17 +620,17 @@ private:
   // sucessfully created with ENABLE_ASYNC, or points to null otherwise.
   // 'unsuccessful' in this case only means that the ImageClient could not
   // be created, most likely because off-main-thread compositing is not enabled.
   // In this case the ImageContainer is perfectly usable, but it will forward
   // frames to the compositor through transactions in the main thread rather than
   // asynchronusly using the ImageBridge IPDL protocol.
   RefPtr<ImageClient> mImageClient;
 
-  CompositableHandle mAsyncContainerHandle;
+  uint64_t mAsyncContainerID;
 
   nsTArray<FrameID> mFrameIDsNotYetComposited;
   // ProducerID for last current image(s), including the frames in
   // mFrameIDsNotYetComposited
   ProducerID mCurrentProducerID;
 
   static mozilla::Atomic<uint32_t> sGenerationCounter;
 };
--- a/gfx/layers/LayersTypes.h
+++ b/gfx/layers/LayersTypes.h
@@ -274,42 +274,12 @@ public:
   }
   uint64_t Value() const {
     return mHandle;
   }
 private:
   uint64_t mHandle;
 };
 
-// This is used to communicate Compositables across IPC channels. The Handle is valid
-// for layers in the same PLayerTransaction or PImageBridge. Handles are created by
-// ClientLayerManager or ImageBridgeChild, and are cached in the parent side on first
-// use.
-class CompositableHandle
-{
-  friend struct IPC::ParamTraits<mozilla::layers::CompositableHandle>;
-public:
-  CompositableHandle() : mHandle(0)
-  {}
-  CompositableHandle(const CompositableHandle& aOther) : mHandle(aOther.mHandle)
-  {}
-  explicit CompositableHandle(uint64_t aHandle) : mHandle(aHandle)
-  {}
-  bool IsValid() const {
-    return mHandle != 0;
-  }
-  explicit operator bool() const {
-    return IsValid();
-  }
-  bool operator ==(const CompositableHandle& aOther) const {
-    return mHandle == aOther.mHandle;
-  }
-  uint64_t Value() const {
-    return mHandle;
-  }
-private:
-  uint64_t mHandle;
-};
-
 } // namespace layers
 } // namespace mozilla
 
 #endif /* GFX_LAYERSTYPES_H */
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -50,24 +50,24 @@ CanvasClient::CreateCanvasClient(CanvasC
 void
 CanvasClientBridge::UpdateAsync(AsyncCanvasRenderer* aRenderer)
 {
   if (!GetForwarder() || !mLayer || !aRenderer ||
       !aRenderer->GetCanvasClient()) {
     return;
   }
 
-  CompositableHandle asyncID = aRenderer->GetCanvasClientAsyncHandle();
-  if (!asyncID || mAsyncHandle == asyncID) {
+  uint64_t asyncID = aRenderer->GetCanvasClientAsyncID();
+  if (asyncID == 0 || mAsyncID == asyncID) {
     return;
   }
 
   static_cast<ShadowLayerForwarder*>(GetForwarder())
     ->AttachAsyncCompositable(asyncID, mLayer);
-  mAsyncHandle = asyncID;
+  mAsyncID = asyncID;
 }
 
 void
 CanvasClient2D::UpdateFromTexture(TextureClient* aTexture)
 {
   MOZ_ASSERT(aTexture);
 
   if (!aTexture->IsSharedWithCompositor()) {
--- a/gfx/layers/client/CanvasClient.h
+++ b/gfx/layers/client/CanvasClient.h
@@ -179,16 +179,17 @@ public:
  * only forward its AsyncID here
  */
 class CanvasClientBridge final : public CanvasClient
 {
 public:
   CanvasClientBridge(CompositableForwarder* aLayerForwarder,
                      TextureFlags aFlags)
     : CanvasClient(aLayerForwarder, aFlags)
+    , mAsyncID(0)
     , mLayer(nullptr)
   {
   }
 
   TextureInfo GetTextureInfo() const override
   {
     return TextureInfo(CompositableType::IMAGE);
   }
@@ -200,16 +201,16 @@ public:
   virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) override;
 
   void SetLayer(ShadowableLayer* aLayer)
   {
     mLayer = aLayer;
   }
 
 protected:
-  CompositableHandle mAsyncHandle;
+  uint64_t mAsyncID;
   ShadowableLayer* mLayer;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -8,16 +8,17 @@
 #include "gfxPrefs.h"                   // for gfxPrefs::LayersTile...
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/Hal.h"
 #include "mozilla/dom/ScreenOrientation.h"  // for ScreenOrientation
 #include "mozilla/dom/TabChild.h"       // for TabChild
 #include "mozilla/hal_sandbox/PHal.h"   // for ScreenConfiguration
 #include "mozilla/layers/CompositableClient.h"
 #include "mozilla/layers/CompositorBridgeChild.h" // for CompositorBridgeChild
+#include "mozilla/layers/ContentClient.h"
 #include "mozilla/layers/FrameUniformityData.h"
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/LayersMessages.h"  // for EditReply, etc
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/LayerTransactionChild.h"
 #include "mozilla/layers/PersistentBufferProvider.h"
 #include "ClientReadbackLayer.h"        // for ClientReadbackLayer
 #include "nsAString.h"
@@ -665,22 +666,45 @@ ClientLayerManager::ForwardTransaction(b
     transactionStart = mTransactionStart;
   }
 
   if (gfxPrefs::AlwaysPaint() && XRE_IsContentProcess()) {
     mForwarder->SendPaintTime(mLatestTransactionId, mLastPaintTime);
   }
 
   // forward this transaction's changeset to our LayerManagerComposite
-  bool sent = false;
-  bool ok = mForwarder->EndTransaction(
-    mRegionToClear, mLatestTransactionId, aScheduleComposite,
-    mPaintSequenceNumber, mIsRepeatTransaction, transactionStart,
-    &sent);
-  if (ok) {
+  bool sent;
+  AutoTArray<EditReply, 10> replies;
+  if (mForwarder->EndTransaction(&replies, mRegionToClear,
+        mLatestTransactionId, aScheduleComposite, mPaintSequenceNumber,
+        mIsRepeatTransaction, transactionStart, &sent)) {
+    for (nsTArray<EditReply>::size_type i = 0; i < replies.Length(); ++i) {
+      const EditReply& reply = replies[i];
+
+      switch (reply.type()) {
+      case EditReply::TOpContentBufferSwap: {
+        MOZ_LAYERS_LOG(("[LayersForwarder] DoubleBufferSwap"));
+
+        const OpContentBufferSwap& obs = reply.get_OpContentBufferSwap();
+
+        RefPtr<CompositableClient> compositable =
+          CompositableClient::FromIPDLActor(obs.compositableChild());
+        ContentClientRemote* contentClient =
+          static_cast<ContentClientRemote*>(compositable.get());
+        MOZ_ASSERT(contentClient);
+
+        contentClient->SwapBuffers(obs.frontUpdatedRegion());
+
+        break;
+      }
+      default:
+        MOZ_CRASH("not reached");
+      }
+    }
+
     if (sent) {
       mNeedsComposite = false;
     }
   } else if (HasShadowManager()) {
     NS_WARNING("failed to forward Layers transaction");
   }
 
   if (!sent) {
--- a/gfx/layers/client/ClientPaintedLayer.cpp
+++ b/gfx/layers/client/ClientPaintedLayer.cpp
@@ -94,17 +94,17 @@ ClientPaintedLayer::PaintThebes()
   }
 
   if (didUpdate) {
     Mutated();
 
     mValidRegion.Or(mValidRegion, state.mRegionToDraw);
 
     ContentClientRemote* contentClientRemote = static_cast<ContentClientRemote*>(mContentClient.get());
-    MOZ_ASSERT(contentClientRemote->GetIPCHandle());
+    MOZ_ASSERT(contentClientRemote->GetIPDLActor());
 
     // Hold(this) ensures this layer is kept alive through the current transaction
     // The ContentClient assumes this layer is kept alive (e.g., in CreateBuffer),
     // so deleting this Hold for whatever reason will break things.
     ClientManager()->Hold(this);
     contentClientRemote->Updated(state.mRegionToDraw,
                                  mVisibleRegion.ToUnknownRegion(),
                                  state.mDidSelfCopy);
new file mode 100644
--- /dev/null
+++ b/gfx/layers/client/CompositableChild.cpp
@@ -0,0 +1,116 @@
+/* -*- 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 "CompositableChild.h"
+#include "CompositableClient.h"
+
+namespace mozilla {
+namespace layers {
+
+/* static */ PCompositableChild*
+CompositableChild::CreateActor()
+{
+  CompositableChild* child = new CompositableChild();
+  child->AddRef();
+  return child;
+}
+
+/* static */ void
+CompositableChild::DestroyActor(PCompositableChild* aChild)
+{
+  static_cast<CompositableChild*>(aChild)->Release();
+}
+
+CompositableChild::CompositableChild()
+ : mCompositableClient(nullptr),
+   mCanSend(true)
+{
+}
+
+CompositableChild::~CompositableChild()
+{
+}
+
+bool
+CompositableChild::IsConnected() const
+{
+  return mCompositableClient && mCanSend;
+}
+
+void
+CompositableChild::Init(CompositableClient* aCompositable)
+{
+  mCompositableClient = aCompositable;
+}
+
+void
+CompositableChild::RevokeCompositableClient()
+{
+  mCompositableClient = nullptr;
+}
+
+RefPtr<CompositableClient>
+CompositableChild::GetCompositableClient()
+{
+  return mCompositableClient;
+}
+
+void
+CompositableChild::ActorDestroy(ActorDestroyReason)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  mCanSend = false;
+
+  if (mCompositableClient) {
+    mCompositableClient->mCompositableChild = nullptr;
+    mCompositableClient = nullptr;
+  }
+}
+
+/* static */ PCompositableChild*
+AsyncCompositableChild::CreateActor(uint64_t aAsyncID)
+{
+  AsyncCompositableChild* child = new AsyncCompositableChild(aAsyncID);
+  child->AddRef();
+  return child;
+}
+
+AsyncCompositableChild::AsyncCompositableChild(uint64_t aAsyncID)
+ : mLock("AsyncCompositableChild.mLock"),
+   mAsyncID(aAsyncID)
+{
+}
+
+AsyncCompositableChild::~AsyncCompositableChild()
+{
+}
+
+void
+AsyncCompositableChild::ActorDestroy(ActorDestroyReason)
+{
+  mCanSend = false;
+
+  // We do not revoke CompositableClient::mCompositableChild here, since that
+  // could race with the main thread.
+  RevokeCompositableClient();
+}
+
+void
+AsyncCompositableChild::RevokeCompositableClient()
+{
+  MutexAutoLock lock(mLock);
+  mCompositableClient = nullptr;
+}
+
+RefPtr<CompositableClient>
+AsyncCompositableChild::GetCompositableClient()
+{
+  MutexAutoLock lock(mLock);
+  return CompositableChild::GetCompositableClient();
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/client/CompositableChild.h
@@ -0,0 +1,91 @@
+/* -*- 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/. */
+
+#ifndef mozilla_gfx_layers_client_CompositableChild_h
+#define mozilla_gfx_layers_client_CompositableChild_h
+
+#include <stdint.h>
+#include "IPDLActor.h"
+#include "mozilla/Mutex.h"
+#include "mozilla/layers/PCompositableChild.h"
+
+namespace mozilla {
+namespace layers {
+
+class CompositableClient;
+class AsyncCompositableChild;
+
+/**
+ * IPDL actor used by CompositableClient to match with its corresponding
+ * CompositableHost on the compositor side.
+ *
+ * CompositableChild is owned by a CompositableClient.
+ */
+class CompositableChild : public PCompositableChild
+{
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositableChild)
+
+  static PCompositableChild* CreateActor();
+  static void DestroyActor(PCompositableChild* aChild);
+
+  void Init(CompositableClient* aCompositable);
+  virtual void RevokeCompositableClient();
+
+  virtual void ActorDestroy(ActorDestroyReason) override;
+
+  virtual RefPtr<CompositableClient> GetCompositableClient();
+
+  virtual AsyncCompositableChild* AsAsyncCompositableChild() {
+    return nullptr;
+  }
+
+  // These should only be called on the IPDL thread.
+  bool IsConnected() const;
+  bool CanSend() const {
+    return mCanSend;
+  }
+
+protected:
+  CompositableChild();
+  virtual ~CompositableChild();
+
+protected:
+  CompositableClient* mCompositableClient;
+  bool mCanSend;
+};
+
+// This CompositableChild can be used off the main thread.
+class AsyncCompositableChild final : public CompositableChild
+{
+public:
+  static PCompositableChild* CreateActor(uint64_t aAsyncID);
+
+  void RevokeCompositableClient() override;
+  RefPtr<CompositableClient> GetCompositableClient() override;
+
+  void ActorDestroy(ActorDestroyReason) override;
+
+  AsyncCompositableChild* AsAsyncCompositableChild() override {
+    return this;
+  }
+
+  uint64_t GetAsyncID() const {
+    return mAsyncID;
+  }
+
+protected:
+  explicit AsyncCompositableChild(uint64_t aAsyncID);
+  ~AsyncCompositableChild() override;
+
+private:
+  Mutex mLock;
+  uint64_t mAsyncID;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_gfx_layers_client_CompositableChild_h
--- a/gfx/layers/client/CompositableClient.cpp
+++ b/gfx/layers/client/CompositableClient.cpp
@@ -1,106 +1,135 @@
 /* -*- 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 "mozilla/layers/CompositableClient.h"
 #include <stdint.h>                     // for uint64_t, uint32_t
 #include "gfxPlatform.h"                // for gfxPlatform
+#include "mozilla/layers/CompositableChild.h"
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/TextureClient.h"  // for TextureClient, etc
 #include "mozilla/layers/TextureClientOGL.h"
 #include "mozilla/mozalloc.h"           // for operator delete, etc
+#include "mozilla/layers/PCompositableChild.h"
 #include "mozilla/layers/TextureClientRecycleAllocator.h"
 #ifdef XP_WIN
 #include "gfxWindowsPlatform.h"         // for gfxWindowsPlatform
 #include "mozilla/layers/TextureD3D11.h"
 #include "mozilla/layers/TextureD3D9.h"
 #endif
 #include "gfxUtils.h"
 #include "IPDLActor.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 
 void
-CompositableClient::InitIPDL(const CompositableHandle& aHandle)
+CompositableClient::InitIPDLActor(PCompositableChild* aActor, uint64_t aAsyncID)
 {
-  MOZ_ASSERT(aHandle);
+  MOZ_ASSERT(aActor);
 
   mForwarder->AssertInForwarderThread();
 
-  mHandle = aHandle;
-  mIsAsync = !NS_IsMainThread();
+  mAsyncID = aAsyncID;
+  mCompositableChild = static_cast<CompositableChild*>(aActor);
+  mCompositableChild->Init(this);
+}
+
+/* static */ RefPtr<CompositableClient>
+CompositableClient::FromIPDLActor(PCompositableChild* aActor)
+{
+  MOZ_ASSERT(aActor);
+
+  RefPtr<CompositableClient> client = static_cast<CompositableChild*>(aActor)->GetCompositableClient();
+  if (!client) {
+    return nullptr;
+  }
+
+  client->mForwarder->AssertInForwarderThread();
+  return client;
 }
 
 CompositableClient::CompositableClient(CompositableForwarder* aForwarder,
                                        TextureFlags aTextureFlags)
 : mForwarder(aForwarder)
 , mTextureFlags(aTextureFlags)
-, mIsAsync(false)
+, mAsyncID(0)
 {
 }
 
 CompositableClient::~CompositableClient()
 {
   Destroy();
 }
 
 LayersBackend
 CompositableClient::GetCompositorBackendType() const
 {
   return mForwarder->GetCompositorBackendType();
 }
 
+PCompositableChild*
+CompositableClient::GetIPDLActor() const
+{
+  return mCompositableChild;
+}
+
 bool
 CompositableClient::Connect(ImageContainer* aImageContainer)
 {
-  MOZ_ASSERT(!mHandle);
-  if (!GetForwarder() || mHandle) {
+  MOZ_ASSERT(!mCompositableChild);
+  if (!GetForwarder() || GetIPDLActor()) {
     return false;
   }
 
   GetForwarder()->AssertInForwarderThread();
   GetForwarder()->Connect(this, aImageContainer);
   return true;
 }
 
 bool
 CompositableClient::IsConnected() const
 {
   // CanSend() is only reliable in the same thread as the IPDL channel.
   mForwarder->AssertInForwarderThread();
-  return !!mHandle;
+  return mCompositableChild && mCompositableChild->IsConnected();
 }
 
 void
 CompositableClient::Destroy()
 {
+  if (!mCompositableChild) {
+    return;
+  }
+
   if (mTextureClientRecycler) {
     mTextureClientRecycler->Destroy();
   }
 
-  if (mHandle) {
-    mForwarder->ReleaseCompositable(mHandle);
-    mHandle = CompositableHandle();
-  }
+  // Take away our IPDL's actor reference back to us.
+  mCompositableChild->RevokeCompositableClient();
+
+  // Schedule the IPDL actor to be destroyed on the forwarder's thread.
+  mForwarder->Destroy(mCompositableChild);
+  mCompositableChild = nullptr;
 }
 
-CompositableHandle
-CompositableClient::GetAsyncHandle() const
+uint64_t
+CompositableClient::GetAsyncID() const
 {
-  if (mIsAsync) {
-    return mHandle;
+  if (mCompositableChild) {
+    return mAsyncID;
   }
-  return CompositableHandle();
+  return 0; // zero is always an invalid async ID
 }
 
 already_AddRefed<TextureClient>
 CompositableClient::CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
                                               gfx::IntSize aSize,
                                               gfx::BackendType aMoz2DBackend,
                                               TextureFlags aTextureFlags)
 {
--- a/gfx/layers/client/CompositableClient.h
+++ b/gfx/layers/client/CompositableClient.h
@@ -22,17 +22,16 @@ namespace layers {
 
 class CompositableClient;
 class ImageBridgeChild;
 class ImageContainer;
 class CompositableForwarder;
 class CompositableChild;
 class PCompositableChild;
 class TextureClientRecycleAllocator;
-class ContentClientRemote;
 
 /**
  * CompositableClient manages the texture-specific logic for composite layers,
  * independently of the layer. It is the content side of a CompositableClient/
  * CompositableHost pair.
  *
  * CompositableClient's purpose is to send texture data to the compositor side
  * along with any extra information about how the texture is to be composited.
@@ -109,37 +108,32 @@ public:
    * Establishes the connection with compositor side through IPDL
    */
   virtual bool Connect(ImageContainer* aImageContainer = nullptr);
 
   void Destroy();
 
   bool IsConnected() const;
 
+  PCompositableChild* GetIPDLActor() const;
+
   CompositableForwarder* GetForwarder() const
   {
     return mForwarder;
   }
 
   /**
    * This identifier is what lets us attach async compositables with a shadow
    * layer. It is not used if the compositable is used with the regular shadow
    * layer forwarder.
    *
-   * If this returns empty, it means the compositable is not async (it is used
+   * If this returns zero, it means the compositable is not async (it is used
    * on the main thread).
    */
-  CompositableHandle GetAsyncHandle() const;
-
-  /**
-   * Handle for IPDL communication.
-   */
-  CompositableHandle GetIPCHandle() const {
-    return mHandle;
-  }
+  uint64_t GetAsyncID() const;
 
   /**
    * Tells the Compositor to create a TextureHost for this TextureClient.
    */
   virtual bool AddTextureClient(TextureClient* aClient);
 
   /**
    * A hook for the when the Compositable is detached from it's layer.
@@ -161,38 +155,38 @@ public:
   /**
    * Should be called when deataching a TextureClient from a Compositable, because
    * some platforms need to do some extra book keeping when this happens.
    *
    * See AutoRemoveTexture to automatically invoke this at the end of a scope.
    */
   virtual void RemoveTexture(TextureClient* aTexture);
 
-  virtual ContentClientRemote* AsContentClientRemote() { return nullptr; }
+  static RefPtr<CompositableClient> FromIPDLActor(PCompositableChild* aActor);
 
-  void InitIPDL(const CompositableHandle& aHandle);
+  void InitIPDLActor(PCompositableChild* aActor, uint64_t aAsyncID = 0);
 
   TextureFlags GetTextureFlags() const { return mTextureFlags; }
 
   TextureClientRecycleAllocator* GetTextureClientRecycler();
 
   bool HasTextureClientRecycler() { return !!mTextureClientRecycler; }
 
   static void DumpTextureClient(std::stringstream& aStream,
                                 TextureClient* aTexture,
                                 TextureDumpMode aCompress);
 protected:
+  RefPtr<CompositableChild> mCompositableChild;
   RefPtr<CompositableForwarder> mForwarder;
   // Some layers may want to enforce some flags to all their textures
   // (like disallowing tiling)
   TextureFlags mTextureFlags;
   RefPtr<TextureClientRecycleAllocator> mTextureClientRecycler;
 
-  CompositableHandle mHandle;
-  bool mIsAsync;
+  uint64_t mAsyncID;
 
   friend class CompositableChild;
 };
 
 /**
  * Helper to call RemoveTexture at the end of a scope.
  */
 struct AutoRemoveTexture
--- a/gfx/layers/client/ContentClient.h
+++ b/gfx/layers/client/ContentClient.h
@@ -114,20 +114,16 @@ class ContentClientRemote : public Conte
 public:
   explicit ContentClientRemote(CompositableForwarder* aForwarder)
     : ContentClient(aForwarder)
   {}
 
   virtual void Updated(const nsIntRegion& aRegionToDraw,
                        const nsIntRegion& aVisibleRegion,
                        bool aDidSelfCopy) = 0;
-
-  ContentClientRemote* AsContentClientRemote() override {
-    return this;
-  }
 };
 
 // thin wrapper around RotatedContentBuffer, for on-mtc
 class ContentClientBasic final : public ContentClient
                                , protected RotatedContentBuffer
 {
 public:
   explicit ContentClientBasic(gfx::BackendType aBackend);
--- a/gfx/layers/client/ImageClient.cpp
+++ b/gfx/layers/client/ImageClient.cpp
@@ -273,27 +273,28 @@ ImageClient::ImageClient(CompositableFor
 , mLayer(nullptr)
 , mType(aType)
 , mLastUpdateGenerationCounter(0)
 {}
 
 ImageClientBridge::ImageClientBridge(CompositableForwarder* aFwd,
                                      TextureFlags aFlags)
 : ImageClient(aFwd, aFlags, CompositableType::IMAGE_BRIDGE)
+, mAsyncContainerID(0)
 {
 }
 
 bool
 ImageClientBridge::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags)
 {
   if (!GetForwarder() || !mLayer) {
     return false;
   }
-  if (mAsyncContainerHandle == aContainer->GetAsyncContainerHandle()) {
+  if (mAsyncContainerID == aContainer->GetAsyncContainerID()) {
     return true;
   }
-  mAsyncContainerHandle = aContainer->GetAsyncContainerHandle();
-  static_cast<ShadowLayerForwarder*>(GetForwarder())->AttachAsyncCompositable(mAsyncContainerHandle, mLayer);
+  mAsyncContainerID = aContainer->GetAsyncContainerID();
+  static_cast<ShadowLayerForwarder*>(GetForwarder())->AttachAsyncCompositable(mAsyncContainerID, mLayer);
   return true;
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/client/ImageClient.h
+++ b/gfx/layers/client/ImageClient.h
@@ -124,15 +124,15 @@ public:
   virtual bool Connect(ImageContainer* aImageContainer) override { return false; }
 
   virtual TextureInfo GetTextureInfo() const override
   {
     return TextureInfo(mType);
   }
 
 protected:
-  CompositableHandle mAsyncContainerHandle;
+  uint64_t mAsyncContainerID;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif
--- a/gfx/layers/composite/CompositableHost.cpp
+++ b/gfx/layers/composite/CompositableHost.cpp
@@ -12,26 +12,59 @@
 #include "ImageHost.h"                  // for ImageHostBuffered, etc
 #include "TiledContentHost.h"           // for TiledContentHost
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/TextureHost.h"  // for TextureHost, etc
 #include "mozilla/RefPtr.h"                   // for nsRefPtr
 #include "nsDebug.h"                    // for NS_WARNING
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "gfxPlatform.h"                // for gfxPlatform
+#include "mozilla/layers/PCompositableParent.h"
 #include "IPDLActor.h"
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace layers {
 
 class Compositor;
 
+/**
+ * IPDL actor used by CompositableHost to match with its corresponding
+ * CompositableClient on the content side.
+ *
+ * CompositableParent is owned by the IPDL system. It's deletion is triggered
+ * by either the CompositableChild's deletion, or by the IPDL communication
+ * going down.
+ */
+class CompositableParent : public ParentActor<PCompositableParent>
+{
+public:
+  CompositableParent(CompositableParentManager* aMgr, const TextureInfo& aTextureInfo)
+  {
+    MOZ_COUNT_CTOR(CompositableParent);
+    mHost = CompositableHost::Create(aTextureInfo);
+  }
+
+  ~CompositableParent()
+  {
+    MOZ_COUNT_DTOR(CompositableParent);
+  }
+
+  virtual void Destroy() override
+  {
+    if (mHost) {
+      mHost->Detach(nullptr, CompositableHost::FORCE_DETACH);
+    }
+  }
+
+  RefPtr<CompositableHost> mHost;
+};
+
 CompositableHost::CompositableHost(const TextureInfo& aTextureInfo)
   : mTextureInfo(aTextureInfo)
   , mCompositorID(0)
   , mCompositor(nullptr)
   , mLayer(nullptr)
   , mFlashCounter(0)
   , mAttached(false)
   , mKeepAttached(false)
@@ -39,16 +72,37 @@ CompositableHost::CompositableHost(const
   MOZ_COUNT_CTOR(CompositableHost);
 }
 
 CompositableHost::~CompositableHost()
 {
   MOZ_COUNT_DTOR(CompositableHost);
 }
 
+PCompositableParent*
+CompositableHost::CreateIPDLActor(CompositableParentManager* aMgr,
+                                  const TextureInfo& aTextureInfo)
+{
+  return new CompositableParent(aMgr, aTextureInfo);
+}
+
+bool
+CompositableHost::DestroyIPDLActor(PCompositableParent* aActor)
+{
+  delete aActor;
+  return true;
+}
+
+CompositableHost*
+CompositableHost::FromIPDLActor(PCompositableParent* aActor)
+{
+  MOZ_ASSERT(aActor);
+  return static_cast<CompositableParent*>(aActor)->mHost;
+}
+
 void
 CompositableHost::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
 {
   if (GetCompositor()) {
     for (auto& texture : aTextures) {
       texture.mTexture->SetCompositor(GetCompositor());
     }
   }
@@ -150,10 +204,16 @@ CompositableHost::DumpTextureHost(std::s
   }
   RefPtr<gfx::DataSourceSurface> dSurf = aTexture->GetAsSurface();
   if (!dSurf) {
     return;
   }
   aStream << gfxUtils::GetAsDataURI(dSurf).get();
 }
 
+void
+CompositableHost::ReceivedDestroy(PCompositableParent* aActor)
+{
+  static_cast<CompositableParent*>(aActor)->RecvDestroy();
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/composite/CompositableHost.h
+++ b/gfx/layers/composite/CompositableHost.h
@@ -38,29 +38,31 @@ class DataSourceSurface;
 namespace layers {
 
 class Layer;
 class LayerComposite;
 class Compositor;
 class ThebesBufferData;
 class TiledContentHost;
 class CompositableParentManager;
+class PCompositableParent;
 struct EffectChain;
 
 struct AsyncCompositableRef
 {
   AsyncCompositableRef()
-   : mProcessId(mozilla::ipc::kInvalidProcessId)
+   : mProcessId(mozilla::ipc::kInvalidProcessId),
+     mAsyncId(0)
   {}
-  AsyncCompositableRef(base::ProcessId aProcessId, const CompositableHandle& aHandle)
-   : mProcessId(aProcessId), mHandle(aHandle)
+  AsyncCompositableRef(base::ProcessId aProcessId, uint64_t aAsyncId)
+   : mProcessId(aProcessId), mAsyncId(aAsyncId)
   {}
-  explicit operator bool() const { return !!mHandle; }
+  explicit operator bool() const { return !!mAsyncId; }
   base::ProcessId mProcessId;
-  CompositableHandle mHandle;
+  uint64_t mAsyncId;
 };
 
 /**
  * The compositor-side counterpart to CompositableClient. Responsible for
  * updating textures and data about textures from IPC and how textures are
  * composited (tiling, double buffering, etc.).
  *
  * Update (for images/canvases) and UpdateThebes (for Thebes) are called during
@@ -73,17 +75,17 @@ struct AsyncCompositableRef
  * rendering.
  */
 class CompositableHost
 {
 protected:
   virtual ~CompositableHost();
 
 public:
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositableHost)
+  NS_INLINE_DECL_REFCOUNTING(CompositableHost)
   explicit CompositableHost(const TextureInfo& aTextureInfo);
 
   static already_AddRefed<CompositableHost> Create(const TextureInfo& aTextureInfo);
 
   virtual CompositableType GetType() = 0;
 
   // If base class overrides, it should still call the parent implementation
   virtual void SetCompositor(Compositor* aCompositor);
@@ -181,16 +183,19 @@ public:
         aFlags & FORCE_DETACH) {
       SetLayer(nullptr);
       mAttached = false;
       mKeepAttached = false;
     }
   }
   bool IsAttached() { return mAttached; }
 
+  static void
+  ReceivedDestroy(PCompositableParent* aActor);
+
   virtual void Dump(std::stringstream& aStream,
                     const char* aPrefix="",
                     bool aDumpHtml=false) { }
   static void DumpTextureHost(std::stringstream& aStream, TextureHost* aTexture);
 
   virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() { return nullptr; }
 
   virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) = 0;
@@ -211,16 +216,24 @@ public:
   virtual void RemoveTextureHost(TextureHost* aTexture);
 
   // Called every time this is composited
   void BumpFlashCounter() {
     mFlashCounter = mFlashCounter >= DIAGNOSTIC_FLASH_COUNTER_MAX
                   ? DIAGNOSTIC_FLASH_COUNTER_MAX : mFlashCounter + 1;
   }
 
+  static PCompositableParent*
+  CreateIPDLActor(CompositableParentManager* mgr,
+                  const TextureInfo& textureInfo);
+
+  static bool DestroyIPDLActor(PCompositableParent* actor);
+
+  static CompositableHost* FromIPDLActor(PCompositableParent* actor);
+
   uint64_t GetCompositorID() const { return mCompositorID; }
 
   const AsyncCompositableRef& GetAsyncRef() const { return mAsyncRef; }
   void SetAsyncRef(const AsyncCompositableRef& aRef) { mAsyncRef = aRef; }
 
   void SetCompositorID(uint64_t aID) { mCompositorID = aID; }
 
   virtual bool Lock() { return false; }
--- a/gfx/layers/composite/ImageHost.cpp
+++ b/gfx/layers/composite/ImageHost.cpp
@@ -345,17 +345,17 @@ ImageHost::Composite(LayerComposite* aLa
       diagnosticFlags |= DiagnosticFlags::YCBCR;
     }
 
     if (mLastFrameID != img->mFrameID || mLastProducerID != img->mProducerID) {
       if (mAsyncRef) {
         ImageCompositeNotificationInfo info;
         info.mImageBridgeProcessId = mAsyncRef.mProcessId;
         info.mNotification = ImageCompositeNotification(
-          mAsyncRef.mHandle,
+          mAsyncRef.mAsyncId,
           img->mTimeStamp, GetCompositor()->GetCompositionTime(),
           img->mFrameID, img->mProducerID);
         static_cast<LayerManagerComposite*>(aLayer->GetLayerManager())->
             AppendImageCompositeNotification(info);
       }
       mLastFrameID = img->mFrameID;
       mLastProducerID = img->mProducerID;
     }
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/CompositableForwarder.cpp
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "CompositableForwarder.h"
+#include "mozilla/layers/CompositableChild.h"
+
+namespace mozilla {
+namespace layers {
+
+void
+CompositableForwarder::Destroy(CompositableChild* aCompositable)
+{
+  AssertInForwarderThread();
+
+  if (!aCompositable->CanSend()) {
+    return;
+  }
+
+  if (!DestroyInTransaction(aCompositable, false)) {
+    aCompositable->SendDestroy();
+  }
+}
+
+} // namespace layers
+} // namespace mozilla
--- a/gfx/layers/ipc/CompositableForwarder.h
+++ b/gfx/layers/ipc/CompositableForwarder.h
@@ -66,18 +66,20 @@ public:
   /**
    * Communicate to the compositor that aRegion in the texture identified by
    * aCompositable and aIdentifier has been updated to aThebesBuffer.
    */
   virtual void UpdateTextureRegion(CompositableClient* aCompositable,
                                    const ThebesBufferData& aThebesBufferData,
                                    const nsIntRegion& aUpdatedRegion) = 0;
 
-  virtual void ReleaseCompositable(const CompositableHandle& aHandle) = 0;
+  virtual void Destroy(CompositableChild* aCompositable);
+
   virtual bool DestroyInTransaction(PTextureChild* aTexture, bool synchronously) = 0;
+  virtual bool DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously) = 0;
 
   /**
    * Tell the CompositableHost on the compositor side to remove the texture
    * from the CompositableHost.
    * This function does not delete the TextureHost corresponding to the
    * TextureClient passed in parameter.
    * When the TextureClient has TEXTURE_DEALLOCATE_CLIENT flag,
    * the transaction becomes synchronous.
--- a/gfx/layers/ipc/CompositableTransactionParent.cpp
+++ b/gfx/layers/ipc/CompositableTransactionParent.cpp
@@ -61,20 +61,17 @@ ScheduleComposition(CompositableHost* aC
 }
 
 bool
 CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation& aEdit,
                                                      EditReplyVector& replyv)
 {
   // Ignore all operations on compositables created on stale compositors. We
   // return true because the child is unable to handle errors.
-  RefPtr<CompositableHost> compositable = FindCompositable(aEdit.compositable());
-  if (!compositable) {
-    return false;
-  }
+  CompositableHost* compositable = CompositableHost::FromIPDLActor(aEdit.compositableParent());
   if (compositable->GetCompositor() && !compositable->GetCompositor()->IsValid()) {
     return true;
   }
 
   switch (aEdit.detail().type()) {
     case CompositableOperationDetail::TOpPaintTextureRegion: {
       MOZ_LAYERS_LOG(("[ParentSide] Paint PaintedLayer"));
 
@@ -93,17 +90,17 @@ CompositableParentManager::ReceiveCompos
       if (!compositable->UpdateThebes(bufferData,
                                       op.updatedRegion(),
                                       thebes->GetValidRegion(),
                                       &frontUpdatedRegion))
       {
         return false;
       }
       replyv.push_back(
-        OpContentBufferSwap(aEdit.compositable(), frontUpdatedRegion));
+        OpContentBufferSwap(aEdit.compositableParent(), nullptr, frontUpdatedRegion));
 
       RenderTraceInvalidateEnd(thebes, "FF00FF");
       break;
     }
     case CompositableOperationDetail::TOpUseTiledLayerBuffer: {
       MOZ_LAYERS_LOG(("[ParentSide] Paint TiledLayerBuffer"));
       const OpUseTiledLayerBuffer& op = aEdit.detail().get_OpUseTiledLayerBuffer();
       TiledContentHost* tiledHost = compositable->AsTiledContentHost();
@@ -227,67 +224,22 @@ void
 CompositableParentManager::DestroyActor(const OpDestroy& aOp)
 {
   switch (aOp.type()) {
     case OpDestroy::TPTextureParent: {
       auto actor = aOp.get_PTextureParent();
       TextureHost::ReceivedDestroy(actor);
       break;
     }
-    case OpDestroy::TCompositableHandle: {
-      ReleaseCompositable(aOp.get_CompositableHandle());
+    case OpDestroy::TPCompositableParent: {
+      auto actor = aOp.get_PCompositableParent();
+      CompositableHost::ReceivedDestroy(actor);
       break;
     }
     default: {
       MOZ_ASSERT(false, "unsupported type");
     }
   }
 }
 
-RefPtr<CompositableHost>
-CompositableParentManager::AddCompositable(const CompositableHandle& aHandle,
-				           const TextureInfo& aInfo)
-{
-  if (mCompositables.find(aHandle.Value()) != mCompositables.end()) {
-    NS_ERROR("Client should not allocate duplicate handles");
-    return nullptr;
-  }
-  if (!aHandle) {
-    NS_ERROR("Client should not allocate 0 as a handle");
-    return nullptr;
-  }
-
-  RefPtr<CompositableHost> host = CompositableHost::Create(aInfo);
-  if (!host) {
-    return nullptr;
-  }
-
-  mCompositables[aHandle.Value()] = host;
-  return host;
-}
-
-RefPtr<CompositableHost>
-CompositableParentManager::FindCompositable(const CompositableHandle& aHandle)
-{
-  auto iter = mCompositables.find(aHandle.Value());
-  if (iter == mCompositables.end()) {
-    return nullptr;
-  }
-  return iter->second;
-}
-
-void
-CompositableParentManager::ReleaseCompositable(const CompositableHandle& aHandle)
-{
-  auto iter = mCompositables.find(aHandle.Value());
-  if (iter == mCompositables.end()) {
-    return;
-  }
-
-  RefPtr<CompositableHost> host = iter->second;
-  mCompositables.erase(iter);
-
-  host->Detach(nullptr, CompositableHost::FORCE_DETACH);
-}
-
 } // namespace layers
 } // namespace mozilla
 
--- a/gfx/layers/ipc/CompositableTransactionParent.h
+++ b/gfx/layers/ipc/CompositableTransactionParent.h
@@ -7,21 +7,22 @@
 
 #ifndef MOZILLA_LAYERS_COMPOSITABLETRANSACTIONPARENT_H
 #define MOZILLA_LAYERS_COMPOSITABLETRANSACTIONPARENT_H
 
 #include <vector>                       // for vector
 #include "mozilla/Attributes.h"         // for override
 #include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator
 #include "mozilla/layers/LayersMessages.h"  // for EditReply, etc
-#include "CompositableHost.h"
 
 namespace mozilla {
 namespace layers {
 
+class CompositableHost;
+
 typedef std::vector<mozilla::layers::EditReply> EditReplyVector;
 
 // Since PCompositble has two potential manager protocols, we can't just call
 // the Manager() method usually generated when there's one manager protocol,
 // so both manager protocols implement this and we keep a reference to them
 // through this interface.
 class CompositableParentManager : public HostIPCAllocator
 {
@@ -33,34 +34,22 @@ public:
   void UpdateFwdTransactionId(uint64_t aTransactionId)
   {
     MOZ_ASSERT(mFwdTransactionId < aTransactionId);
     mFwdTransactionId = aTransactionId;
   }
 
   uint64_t GetFwdTransactionId() { return mFwdTransactionId; }
 
-  RefPtr<CompositableHost> AddCompositable(
-    const CompositableHandle& aHandle,
-    const TextureInfo& aInfo);
-  RefPtr<CompositableHost> FindCompositable(const CompositableHandle& aHandle);
-
 protected:
   /**
    * Handle the IPDL messages that affect PCompositable actors.
    */
   bool ReceiveCompositableUpdate(const CompositableOperation& aEdit,
                                  EditReplyVector& replyv);
 
-  void ReleaseCompositable(const CompositableHandle& aHandle);
-
   uint64_t mFwdTransactionId = 0;
-
-  /**
-   * Mapping form IDs to CompositableHosts.
-   */
-  std::map<uint64_t, RefPtr<CompositableHost>> mCompositables;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -18,21 +18,23 @@
 #include "mozilla/Monitor.h"            // for Monitor, MonitorAutoLock
 #include "mozilla/ReentrantMonitor.h"   // for ReentrantMonitor, etc
 #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
 #include "mozilla/ipc/Transport.h"      // for Transport
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/layers/AsyncCanvasRenderer.h"
 #include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager
 #include "mozilla/media/MediaSystemResourceManagerChild.h" // for MediaSystemResourceManagerChild
+#include "mozilla/layers/CompositableChild.h"
 #include "mozilla/layers/CompositableClient.h"  // for CompositableChild, etc
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator
 #include "mozilla/layers/ImageClient.h"  // for ImageClient
 #include "mozilla/layers/LayersMessages.h"  // for CompositableOperation
+#include "mozilla/layers/PCompositableChild.h"  // for PCompositableChild
 #include "mozilla/layers/TextureClient.h"  // for TextureClient
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "mtransport/runnable_utils.h"
 #include "nsContentUtils.h"
 #include "nsISupportsImpl.h"            // for ImageContainer::AddRef, etc
 #include "nsTArray.h"                   // for AutoTArray, nsTArray, etc
 #include "nsTArrayForwardDeclare.h"     // for AutoTArray
@@ -148,17 +150,17 @@ struct AutoEndTransaction {
   CompositableTransaction* mTxn;
 };
 
 void
 ImageBridgeChild::UseTextures(CompositableClient* aCompositable,
                               const nsTArray<TimedTextureClient>& aTextures)
 {
   MOZ_ASSERT(aCompositable);
-  MOZ_ASSERT(aCompositable->GetIPCHandle());
+  MOZ_ASSERT(aCompositable->GetIPDLActor());
   MOZ_ASSERT(aCompositable->IsConnected());
 
   AutoTArray<TimedTexture,4> textures;
 
   for (auto& t : aTextures) {
     MOZ_ASSERT(t.mTextureClient);
     MOZ_ASSERT(t.mTextureClient->GetIPDLActor());
 
@@ -172,17 +174,17 @@ ImageBridgeChild::UseTextures(Compositab
     textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(),
                                         readLock,
                                         t.mTimeStamp, t.mPictureRect,
                                         t.mFrameID, t.mProducerID));
 
     // Wait end of usage on host side if TextureFlags::RECYCLE is set
     HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient);
   }
-  mTxn->AddNoSwapEdit(CompositableOperation(aCompositable->GetIPCHandle(),
+  mTxn->AddNoSwapEdit(CompositableOperation(nullptr, aCompositable->GetIPDLActor(),
                                             OpUseTexture(textures)));
 }
 
 void
 ImageBridgeChild::UseComponentAlphaTextures(CompositableClient* aCompositable,
                                             TextureClient* aTextureOnBlack,
                                             TextureClient* aTextureOnWhite)
 {
@@ -199,17 +201,18 @@ ImageBridgeChild::UseComponentAlphaTextu
   aTextureOnBlack->SerializeReadLock(readLockB);
   aTextureOnWhite->SerializeReadLock(readLockW);
 
   HoldUntilCompositableRefReleasedIfNecessary(aTextureOnBlack);
   HoldUntilCompositableRefReleasedIfNecessary(aTextureOnWhite);
 
   mTxn->AddNoSwapEdit(
     CompositableOperation(
-      aCompositable->GetIPCHandle(),
+      nullptr,
+      aCompositable->GetIPDLActor(),
       OpUseComponentAlphaTextures(
         nullptr, aTextureOnBlack->GetIPDLActor(),
         nullptr, aTextureOnWhite->GetIPDLActor(),
         readLockB, readLockW
       )
     )
   );
 }
@@ -264,16 +267,24 @@ ImageBridgeChild::ShutdownStep1(Synchron
   AutoCompleteTask complete(aTask);
 
   MOZ_ASSERT(InImageBridgeChildThread(),
              "Should be in ImageBridgeChild thread.");
 
   MediaSystemResourceManager::Shutdown();
 
   // Force all managed protocols to shut themselves down cleanly
+  InfallibleTArray<PCompositableChild*> compositables;
+  ManagedPCompositableChild(compositables);
+  for (int i = compositables.Length() - 1; i >= 0; --i) {
+    auto compositable = CompositableClient::FromIPDLActor(compositables[i]);
+    if (compositable) {
+      compositable->Destroy();
+    }
+  }
   InfallibleTArray<PTextureChild*> textures;
   ManagedPTextureChild(textures);
   for (int i = textures.Length() - 1; i >= 0; --i) {
     RefPtr<TextureClient> client = TextureClient::AsTextureClient(textures[i]);
     if (client) {
       client->Destroy();
     }
   }
@@ -290,27 +301,28 @@ ImageBridgeChild::ShutdownStep1(Synchron
 // dispatched function
 void
 ImageBridgeChild::ShutdownStep2(SynchronousTask* aTask)
 {
   AutoCompleteTask complete(aTask);
 
   MOZ_ASSERT(InImageBridgeChildThread(),
              "Should be in ImageBridgeChild thread.");
-  Close();
+
+  if (!mCalledClose) {
+    Close();
+    mCalledClose = true;
+  }
 }
 
 void
 ImageBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   mCanSend = false;
-  {
-    MutexAutoLock lock(mContainerMapLock);
-    mImageContainers.Clear();
-  }
+  mCalledClose = true;
 }
 
 void
 ImageBridgeChild::DeallocPImageBridgeChild()
 {
   this->Release();
 }
 
@@ -332,17 +344,17 @@ ImageBridgeChild::CreateCanvasClientSync
                                          RefPtr<CanvasClient>* const outResult)
 {
   AutoCompleteTask complete(aTask);
   *outResult = CreateCanvasClientNow(aType, aFlags);
 }
 
 ImageBridgeChild::ImageBridgeChild()
   : mCanSend(false)
-  , mDestroyed(false)
+  , mCalledClose(false)
   , mFwdTransactionId(0)
   , mContainerMapLock("ImageBridgeChild.mContainerMapLock")
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   mTxn = new CompositableTransaction();
 }
 
@@ -374,26 +386,51 @@ ImageBridgeChild::Connect(CompositableCl
   uint64_t id = sNextID++;
 
   {
     MutexAutoLock lock(mContainerMapLock);
     MOZ_ASSERT(!mImageContainers.Contains(id));
     mImageContainers.Put(id, aImageContainer);
   }
 
-  CompositableHandle handle(id);
-  aCompositable->InitIPDL(handle);
-  SendNewCompositable(handle, aCompositable->GetTextureInfo());
+  PCompositableChild* child =
+    SendPCompositableConstructor(aCompositable->GetTextureInfo(), id);
+  if (!child) {
+    return;
+  }
+  aCompositable->InitIPDLActor(child, id);
 }
 
 void
-ImageBridgeChild::ForgetImageContainer(const CompositableHandle& aHandle)
+ImageBridgeChild::ForgetImageContainer(uint64_t aAsyncContainerID)
 {
   MutexAutoLock lock(mContainerMapLock);
-  mImageContainers.Remove(aHandle.Value());
+  mImageContainers.Remove(aAsyncContainerID);
+}
+
+PCompositableChild*
+ImageBridgeChild::AllocPCompositableChild(const TextureInfo& aInfo, const uint64_t& aID)
+{
+  MOZ_ASSERT(CanSend());
+  return AsyncCompositableChild::CreateActor(aID);
+}
+
+bool
+ImageBridgeChild::DeallocPCompositableChild(PCompositableChild* aActor)
+{
+  AsyncCompositableChild* actor = static_cast<AsyncCompositableChild*>(aActor);
+  MOZ_ASSERT(actor->GetAsyncID());
+
+  {
+    MutexAutoLock lock(mContainerMapLock);
+    mImageContainers.Remove(actor->GetAsyncID());
+  }
+
+  AsyncCompositableChild::DestroyActor(aActor);
+  return true;
 }
 
 Thread* ImageBridgeChild::GetThread() const
 {
   return sImageBridgeChildThread;
 }
 
 /* static */ RefPtr<ImageBridgeChild>
@@ -419,16 +456,17 @@ ImageBridgeChild::DispatchReleaseTexture
 
   RefPtr<ImageBridgeChild> imageBridge = ImageBridgeChild::GetSingleton();
   if (!imageBridge) {
     // TextureClient::Release should normally happen in the ImageBridgeChild
     // thread because it usually generate some IPDL messages.
     // However, if we take this branch it means that the ImageBridgeChild
     // has already shut down, along with the TextureChild, which means no
     // message will be sent and it is safe to run this code from any thread.
+    MOZ_ASSERT(aClient->GetIPDLActor() == nullptr);
     RELEASE_MANUALLY(aClient);
     return;
   }
 
   RefPtr<Runnable> runnable = WrapRunnable(
     imageBridge,
     &ImageBridgeChild::ReleaseTextureClientNow,
     aClient);
@@ -730,18 +768,16 @@ ImageBridgeChild::WillShutdown()
     RefPtr<Runnable> runnable = WrapRunnable(
       RefPtr<ImageBridgeChild>(this),
       &ImageBridgeChild::ShutdownStep2,
       &task);
     GetMessageLoop()->PostTask(runnable.forget());
 
     task.Wait();
   }
-
-  mDestroyed = true;
 }
 
 void
 ImageBridgeChild::InitSameProcess()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
 
   MOZ_ASSERT(!sImageBridgeChildSingleton);
@@ -994,22 +1030,16 @@ ImageBridgeChild::DeallocShmem(ipc::Shme
 {
   if (InImageBridgeChildThread()) {
     if (!CanSend()) {
       return false;
     }
     return PImageBridgeChild::DeallocShmem(aShmem);
   }
 
-  // If we can't post a task, then we definitely cannot send, so there's
-  // no reason to queue up this send.
-  if (!CanPostTask()) {
-    return false;
-  }
-
   SynchronousTask task("AllocatorProxy Dealloc");
   bool result = false;
 
   RefPtr<Runnable> runnable = WrapRunnable(
     RefPtr<ImageBridgeChild>(this),
     &ImageBridgeChild::ProxyDeallocShmemNow,
     &task,
     &aShmem,
@@ -1073,17 +1103,17 @@ ImageBridgeChild::RecvParentAsyncMessage
 
 mozilla::ipc::IPCResult
 ImageBridgeChild::RecvDidComposite(InfallibleTArray<ImageCompositeNotification>&& aNotifications)
 {
   for (auto& n : aNotifications) {
     RefPtr<ImageContainer> imageContainer;
     {
       MutexAutoLock lock(mContainerMapLock);
-      imageContainer = mImageContainers.Get(n.compositable().Value());
+      imageContainer = mImageContainers.Get(n.asyncCompositableID());
     }
     if (imageContainer) {
       imageContainer->NotifyComposite(n);
     }
   }
   return IPC_OK();
 }
 
@@ -1115,95 +1145,62 @@ IBCAddOpDestroy(CompositableTransaction*
 
 bool
 ImageBridgeChild::DestroyInTransaction(PTextureChild* aTexture, bool synchronously)
 {
   return IBCAddOpDestroy(mTxn, OpDestroy(aTexture), synchronously);
 }
 
 bool
-ImageBridgeChild::DestroyInTransaction(const CompositableHandle& aHandle)
+ImageBridgeChild::DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously)
 {
-  return IBCAddOpDestroy(mTxn, OpDestroy(aHandle), false);
+  return IBCAddOpDestroy(mTxn, OpDestroy(aCompositable), synchronously);
 }
 
+
 void
 ImageBridgeChild::RemoveTextureFromCompositable(CompositableClient* aCompositable,
                                                 TextureClient* aTexture)
 {
   MOZ_ASSERT(CanSend());
   MOZ_ASSERT(aTexture);
   MOZ_ASSERT(aTexture->IsSharedWithCompositor());
   MOZ_ASSERT(aCompositable->IsConnected());
   if (!aTexture || !aTexture->IsSharedWithCompositor() || !aCompositable->IsConnected()) {
     return;
   }
 
   CompositableOperation op(
-    aCompositable->GetIPCHandle(),
+    nullptr, aCompositable->GetIPDLActor(),
     OpRemoveTexture(nullptr, aTexture->GetIPDLActor()));
 
   if (aTexture->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
     mTxn->AddEdit(op);
   } else {
     mTxn->AddNoSwapEdit(op);
   }
 }
 
 bool ImageBridgeChild::IsSameProcess() const
 {
   return OtherPid() == base::GetCurrentProcId();
 }
 
-bool
-ImageBridgeChild::CanPostTask() const
-{
-  // During shutdown, the cycle collector may free objects that are holding a
-  // reference to ImageBridgeChild. Since this happens on the main thread,
-  // ImageBridgeChild will attempt to post a task to the ImageBridge thread.
-  // However the thread manager has already been shut down, so the task cannot
-  // post.
-  //
-  // It's okay if this races. We only care about the shutdown case where
-  // everything's happening on the main thread. Even if it races outside of
-  // shutdown, it's still harmless to post the task, since the task must
-  // check CanSend().
-  return !mDestroyed;
-}
-
 void
-ImageBridgeChild::ReleaseCompositable(const CompositableHandle& aHandle)
+ImageBridgeChild::Destroy(CompositableChild* aCompositable)
 {
   if (!InImageBridgeChildThread()) {
-    // If we can't post a task, then we definitely cannot send, so there's
-    // no reason to queue up this send.
-    if (!CanPostTask()) {
-      return;
-    }
-
     RefPtr<Runnable> runnable = WrapRunnable(
       RefPtr<ImageBridgeChild>(this),
-      &ImageBridgeChild::ReleaseCompositable,
-      aHandle);
+      &ImageBridgeChild::Destroy,
+      RefPtr<CompositableChild>(aCompositable));
     GetMessageLoop()->PostTask(runnable.forget());
     return;
   }
-
-  if (!CanSend()) {
-    return;
-  }
-
-  if (!DestroyInTransaction(aHandle)) {
-    SendReleaseCompositable(aHandle);
-  }
-
-  {
-    MutexAutoLock lock(mContainerMapLock);
-    mImageContainers.Remove(aHandle.Value());
-  }
+  CompositableForwarder::Destroy(aCompositable);
 }
 
 bool
 ImageBridgeChild::CanSend() const
 {
   MOZ_ASSERT(InImageBridgeChildThread());
   return mCanSend;
 }
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -163,16 +163,20 @@ public:
    * Returns the ImageBridgeChild's message loop.
    *
    * Can be called from any thread.
    */
   virtual MessageLoop * GetMessageLoop() const override;
 
   virtual base::ProcessId GetParentPid() const override { return OtherPid(); }
 
+  PCompositableChild* AllocPCompositableChild(const TextureInfo& aInfo,
+                                              const uint64_t& aID) override;
+  bool DeallocPCompositableChild(PCompositableChild* aActor) override;
+
   virtual PTextureChild*
   AllocPTextureChild(const SurfaceDescriptor& aSharedData, const LayersBackend& aLayersBackend, const TextureFlags& aFlags, const uint64_t& aSerial) override;
 
   virtual bool
   DeallocPTextureChild(PTextureChild* actor) override;
 
   PMediaSystemResourceManagerChild*
   AllocPMediaSystemResourceManagerChild() override;
@@ -259,36 +263,36 @@ public:
    * See CompositableForwarder::UseTextures
    */
   virtual void UseTextures(CompositableClient* aCompositable,
                            const nsTArray<TimedTextureClient>& aTextures) override;
   virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
                                          TextureClient* aClientOnBlack,
                                          TextureClient* aClientOnWhite) override;
 
-  void ReleaseCompositable(const CompositableHandle& aHandle) override;
+  void Destroy(CompositableChild* aCompositable) override;
 
-  void ForgetImageContainer(const CompositableHandle& aHandle);
+  void ForgetImageContainer(uint64_t aAsyncContainerID);
 
   /**
    * Hold TextureClient ref until end of usage on host side if TextureFlags::RECYCLE is set.
    * Host side's usage is checked via CompositableRef.
    */
   void HoldUntilCompositableRefReleasedIfNecessary(TextureClient* aClient);
 
   /**
    * Notify id of Texture When host side end its use. Transaction id is used to
    * make sure if there is no newer usage.
    */
   void NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId);
 
   virtual void CancelWaitForRecycle(uint64_t aTextureId) override;
 
   virtual bool DestroyInTransaction(PTextureChild* aTexture, bool synchronously) override;
-  bool DestroyInTransaction(const CompositableHandle& aHandle);
+  virtual bool DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously) override;
 
   virtual void RemoveTextureFromCompositable(CompositableClient* aCompositable,
                                              TextureClient* aTexture) override;
 
   virtual void UseTiledLayerBuffer(CompositableClient* aCompositable,
                                    const SurfaceDescriptorTiles& aTileLayerDescriptor) override
   {
     MOZ_CRASH("should not be called");
@@ -355,25 +359,24 @@ protected:
   void ShutdownStep1(SynchronousTask* aTask);
   void ShutdownStep2(SynchronousTask* aTask);
   void MarkShutDown();
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
   void DeallocPImageBridgeChild() override;
 
   bool CanSend() const;
-  bool CanPostTask() const;
 
   static void ShutdownSingleton();
 
 private:
   CompositableTransaction* mTxn;
 
   bool mCanSend;
-  mozilla::Atomic<bool> mDestroyed;
+  bool mCalledClose;
 
   /**
    * Transaction id of CompositableForwarder.
    * It is incrementaed by UpdateFwdTransactionId() in each BeginTransaction() call.
    */
   uint64_t mFwdTransactionId;
 
   /**
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/HalTypes.h"           // for hal::THREAD_PRIORITY_COMPOSITOR
 #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/ipc/Transport.h"      // for Transport
 #include "mozilla/media/MediaSystemResourceManagerParent.h" // for MediaSystemResourceManagerParent
 #include "mozilla/layers/CompositableTransactionParent.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayersMessages.h"  // for EditReply
+#include "mozilla/layers/PCompositableParent.h"
 #include "mozilla/layers/PImageBridgeParent.h"
 #include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
 #include "mozilla/layers/Compositor.h"
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "mozilla/Unused.h"
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT, etc
 #include "nsISupportsImpl.h"            // for ImageBridgeParent::Release, etc
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl
@@ -226,33 +227,44 @@ mozilla::ipc::IPCResult ImageBridgeParen
   ManagedPTextureParent(textures);
   for (unsigned int i = 0; i < textures.Length(); ++i) {
     RefPtr<TextureHost> tex = TextureHost::AsTextureHost(textures[i]);
     tex->DeallocateDeviceData();
   }
   return IPC_OK();
 }
 
-mozilla::ipc::IPCResult
-ImageBridgeParent::RecvNewCompositable(const CompositableHandle& aHandle, const TextureInfo& aInfo)
+PCompositableParent*
+ImageBridgeParent::AllocPCompositableParent(const TextureInfo& aInfo, const uint64_t& aID)
 {
-  RefPtr<CompositableHost> host = AddCompositable(aHandle, aInfo);
-  if (!host) {
-    return IPC_FAIL_NO_REASON(this);
+  PCompositableParent* actor = CompositableHost::CreateIPDLActor(this, aInfo);
+  if (mCompositables.find(aID) != mCompositables.end()) {
+    NS_ERROR("Async compositable ID already exists");
+    return actor;
+  }
+  if (!aID) {
+    NS_ERROR("Expected non-zero async compositable ID");
+    return actor;
   }
 
-  host->SetAsyncRef(AsyncCompositableRef(OtherPid(), aHandle));
-  return IPC_OK();
+  CompositableHost* host = CompositableHost::FromIPDLActor(actor);
+
+  host->SetAsyncRef(AsyncCompositableRef(OtherPid(), aID));
+  mCompositables[aID] = host;
+
+  return actor;
 }
 
-mozilla::ipc::IPCResult
-ImageBridgeParent::RecvReleaseCompositable(const CompositableHandle& aHandle)
+bool ImageBridgeParent::DeallocPCompositableParent(PCompositableParent* aActor)
 {
-  ReleaseCompositable(aHandle);
-  return IPC_OK();
+  if (CompositableHost* host = CompositableHost::FromIPDLActor(aActor)) {
+    const AsyncCompositableRef& ref = host->GetAsyncRef();
+    mCompositables.erase(ref.mAsyncId);
+  }
+  return CompositableHost::DestroyIPDLActor(aActor);
 }
 
 PTextureParent*
 ImageBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData,
                                        const LayersBackend& aLayersBackend,
                                        const TextureFlags& aFlags,
                                        const uint64_t& aSerial)
 {
@@ -307,17 +319,17 @@ ImageBridgeParent::NotifyImageComposites
   // notifications in one message per group.
   aNotifications.Sort(ProcessIdComparator());
   uint32_t i = 0;
   bool ok = true;
   while (i < aNotifications.Length()) {
     AutoTArray<ImageCompositeNotification,1> notifications;
     notifications.AppendElement(aNotifications[i].mNotification);
     uint32_t end = i + 1;
-    MOZ_ASSERT(aNotifications[i].mNotification.compositable());
+    MOZ_ASSERT(aNotifications[i].mNotification.asyncCompositableID());
     ProcessId pid = aNotifications[i].mImageBridgeProcessId;
     while (end < aNotifications.Length() &&
            aNotifications[end].mImageBridgeProcessId == pid) {
       notifications.AppendElement(aNotifications[end].mNotification);
       ++end;
     }
     GetInstance(pid)->SendPendingAsyncMessages();
     if (!GetInstance(pid)->SendDidComposite(notifications)) {
@@ -421,10 +433,20 @@ ImageBridgeParent::NotifyNotUsed(PTextur
   mPendingAsyncMessage.push_back(
     OpNotifyNotUsed(textureId, aTransactionId));
 
   if (!IsAboutToSendAsyncMessages()) {
     SendPendingAsyncMessages();
   }
 }
 
+CompositableHost*
+ImageBridgeParent::FindCompositable(uint64_t aId)
+{
+  auto iter = mCompositables.find(aId);
+  if (iter == mCompositables.end()) {
+    return nullptr;
+  }
+  return iter->second;
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -72,26 +72,26 @@ public:
   // PImageBridge
   virtual mozilla::ipc::IPCResult RecvImageBridgeThreadId(const PlatformThreadId& aThreadId) override;
   virtual mozilla::ipc::IPCResult RecvUpdate(EditArray&& aEdits, OpDestroyArray&& aToDestroy,
                                           const uint64_t& aFwdTransactionId,
                                           EditReplyArray* aReply) override;
   virtual mozilla::ipc::IPCResult RecvUpdateNoSwap(EditArray&& aEdits, OpDestroyArray&& aToDestroy,
                                                 const uint64_t& aFwdTransactionId) override;
 
+  PCompositableParent* AllocPCompositableParent(const TextureInfo& aInfo,
+                                                const uint64_t& aID) override;
+  bool DeallocPCompositableParent(PCompositableParent* aActor) override;
+
   virtual PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
                                               const LayersBackend& aLayersBackend,
                                               const TextureFlags& aFlags,
                                               const uint64_t& aSerial) override;
   virtual bool DeallocPTextureParent(PTextureParent* actor) override;
 
-  virtual mozilla::ipc::IPCResult RecvNewCompositable(const CompositableHandle& aHandle,
-                                                      const TextureInfo& aInfo) override;
-  virtual mozilla::ipc::IPCResult RecvReleaseCompositable(const CompositableHandle& aHandle) override;
-
   PMediaSystemResourceManagerParent* AllocPMediaSystemResourceManagerParent() override;
   bool DeallocPMediaSystemResourceManagerParent(PMediaSystemResourceManagerParent* aActor) override;
 
   // Shutdown step 1
   virtual mozilla::ipc::IPCResult RecvWillClose() override;
 
   MessageLoop* GetMessageLoop() const { return mMessageLoop; }
 
@@ -118,16 +118,18 @@ public:
   static ImageBridgeParent* GetInstance(ProcessId aId);
 
   static bool NotifyImageComposites(nsTArray<ImageCompositeNotificationInfo>& aNotifications);
 
   virtual bool UsesImageBridge() const override { return true; }
 
   virtual bool IPCOpen() const override { return !mClosed; }
 
+  CompositableHost* FindCompositable(uint64_t aId);
+
 protected:
   void OnChannelConnected(int32_t pid) override;
 
   void Bind(Endpoint<PImageBridgeParent>&& aEndpoint);
 
 private:
   void DeferredDestroy();
   MessageLoop* mMessageLoop;
@@ -141,14 +143,41 @@ private:
   /**
    * Map of all living ImageBridgeParent instances
    */
   static std::map<base::ProcessId, ImageBridgeParent*> sImageBridges;
 
   static MessageLoop* sMainLoop;
 
   RefPtr<CompositorThreadHolder> mCompositorThreadHolder;
+
+  /**
+   * PCompositable and PLayer can, in the case of async textures, be managed by
+   * different top level protocols. In this case they don't share the same
+   * communication channel and we can't send an OpAttachCompositable (PCompositable,
+   * PLayer) message.
+   *
+   * In order to attach a layer and the right compositable if the the compositable
+   * is async, we store references to the async compositables in a CompositableMap
+   * that is accessed only on the compositor thread. During a layer transaction we
+   * send the message OpAttachAsyncCompositable(ID, PLayer), and on the compositor
+   * side we lookup the ID in the map and attach the corresponding compositable to
+   * the layer.
+   *
+   * CompositableMap must be global because the image bridge doesn't have any
+   * reference to whatever we have created with PLayerTransaction. So, the only way to
+   * actually connect these two worlds is to have something global that they can
+   * both query (in the same  thread). The map is not allocated the map on the
+   * stack to avoid the badness of static initialization.
+   *
+   * Also, we have a compositor/PLayerTransaction protocol/etc. per layer manager, and the
+   * ImageBridge is used by all the existing compositors that have a video, so
+   * there isn't an instance or "something" that lives outside the boudaries of a
+   * given layer manager on the compositor thread except the image bridge and the
+   * thread itself.
+   */
+  std::map<uint64_t, CompositableHost*> mCompositables;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // gfx_layers_ipc_ImageBridgeParent_h_
--- a/gfx/layers/ipc/LayerTransactionChild.cpp
+++ b/gfx/layers/ipc/LayerTransactionChild.cpp
@@ -2,16 +2,18 @@
  * vim: sw=2 ts=8 et :
  */
 /* 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 "LayerTransactionChild.h"
 #include "mozilla/gfx/Logging.h"
+#include "mozilla/layers/CompositableChild.h"
+#include "mozilla/layers/PCompositableChild.h"  // for PCompositableChild
 #include "mozilla/layers/ShadowLayers.h"  // for ShadowLayerForwarder
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT, etc
 #include "nsTArray.h"                   // for nsTArray
 #include "mozilla/layers/TextureClient.h"
 
 namespace mozilla {
 namespace layers {
@@ -29,16 +31,31 @@ LayerTransactionChild::Destroy()
   // ShadowLayerForwarder's destructor.
   // When it happens, IPCOpen() is still true.
   // See bug 1004191.
   mDestroyed = true;
 
   SendShutdown();
 }
 
+
+PCompositableChild*
+LayerTransactionChild::AllocPCompositableChild(const TextureInfo& aInfo)
+{
+  MOZ_ASSERT(!mDestroyed);
+  return CompositableChild::CreateActor();
+}
+
+bool
+LayerTransactionChild::DeallocPCompositableChild(PCompositableChild* actor)
+{
+  CompositableChild::DestroyActor(actor);
+  return true;
+}
+
 void
 LayerTransactionChild::ActorDestroy(ActorDestroyReason why)
 {
   mDestroyed = true;
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/LayerTransactionChild.h
+++ b/gfx/layers/ipc/LayerTransactionChild.h
@@ -52,16 +52,19 @@ protected:
   explicit LayerTransactionChild(const uint64_t& aId)
     : mForwarder(nullptr)
     , mIPCOpen(false)
     , mDestroyed(false)
     , mId(aId)
   {}
   ~LayerTransactionChild() { }
 
+  virtual PCompositableChild* AllocPCompositableChild(const TextureInfo& aInfo) override;
+  virtual bool DeallocPCompositableChild(PCompositableChild* actor) override;
+
   virtual void ActorDestroy(ActorDestroyReason why) override;
 
   void AddIPDLReference() {
     MOZ_ASSERT(mIPCOpen == false);
     mIPCOpen = true;
     AddRef();
   }
   void ReleaseIPDLReference() {
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -19,16 +19,17 @@
 #include "mozilla/layers/ColorLayerComposite.h"
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/ContainerLayerComposite.h"
 #include "mozilla/layers/ImageBridgeParent.h" // for ImageBridgeParent
 #include "mozilla/layers/ImageLayerComposite.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayersMessages.h"  // for EditReply, etc
 #include "mozilla/layers/LayersTypes.h"  // for MOZ_LAYERS_LOG
+#include "mozilla/layers/PCompositableParent.h"
 #include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
 #include "mozilla/layers/PaintedLayerComposite.h"
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "mozilla/Unused.h"
 #include "nsCoord.h"                    // for NSAppUnitsToFloatPixels
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT
 #include "nsDeviceContext.h"            // for AppUnitsPerCSSPixel
 #include "nsISupportsImpl.h"            // for Layer::Release, etc
@@ -558,17 +559,17 @@ LayerTransactionParent::RecvUpdate(const
       if (!ReceiveCompositableUpdate(edit.get_CompositableOperation(),
                                 replyv)) {
         return IPC_FAIL_NO_REASON(this);
       }
       break;
     }
     case Edit::TOpAttachCompositable: {
       const OpAttachCompositable& op = edit.get_OpAttachCompositable();
-      RefPtr<CompositableHost> host = FindCompositable(op.compositable());
+      CompositableHost* host = CompositableHost::FromIPDLActor(op.compositableParent());
       if (mPendingCompositorUpdates) {
         // Do not attach compositables from old layer trees. Return true since
         // content cannot handle errors.
         return IPC_OK();
       }
       if (!Attach(AsLayer(op.layer()), host, false)) {
         return IPC_FAIL_NO_REASON(this);
       }
@@ -583,17 +584,17 @@ LayerTransactionParent::RecvUpdate(const
         // Do not attach compositables from old layer trees. Return true since
         // content cannot handle errors.
         return IPC_OK();
       }
       ImageBridgeParent* imageBridge = ImageBridgeParent::GetInstance(OtherPid());
       if (!imageBridge) {
         return IPC_FAIL_NO_REASON(this);
       }
-      RefPtr<CompositableHost> host = imageBridge->FindCompositable(op.compositable());
+      CompositableHost* host = imageBridge->FindCompositable(op.containerID());
       if (!host) {
         NS_ERROR("CompositableHost not found in the map");
         return IPC_FAIL_NO_REASON(this);
       }
       if (!Attach(AsLayer(op.layer()), host, true)) {
         return IPC_FAIL_NO_REASON(this);
       }
       if (mLayerManager->GetCompositor()) {
@@ -926,16 +927,28 @@ LayerTransactionParent::RecvClearCachedR
 
 mozilla::ipc::IPCResult
 LayerTransactionParent::RecvForceComposite()
 {
   mCompositorBridge->ForceComposite(this);
   return IPC_OK();
 }
 
+PCompositableParent*
+LayerTransactionParent::AllocPCompositableParent(const TextureInfo& aInfo)
+{
+  return CompositableHost::CreateIPDLActor(this, aInfo);
+}
+
+bool
+LayerTransactionParent::DeallocPCompositableParent(PCompositableParent* aActor)
+{
+  return CompositableHost::DestroyIPDLActor(aActor);
+}
+
 void
 LayerTransactionParent::ActorDestroy(ActorDestroyReason why)
 {
 }
 
 bool
 LayerTransactionParent::AllocShmem(size_t aSize,
                                    ipc::SharedMemory::SharedMemoryType aType,
@@ -1013,40 +1026,24 @@ LayerTransactionParent::AsLayer(const La
 {
   if (!aHandle) {
     return nullptr;
   }
   return mLayerMap.Get(aHandle.Value()).get();
 }
 
 mozilla::ipc::IPCResult
-LayerTransactionParent::RecvNewCompositable(const CompositableHandle& aHandle, const TextureInfo& aInfo)
-{
-  if (!AddCompositable(aHandle, aInfo)) {
-    return IPC_FAIL_NO_REASON(this);
-  }
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
 LayerTransactionParent::RecvReleaseLayer(const LayerHandle& aHandle)
 {
   if (!aHandle || !mLayerMap.Contains(aHandle.Value())) {
     return IPC_FAIL_NO_REASON(this);
   }
 
   Maybe<RefPtr<Layer>> maybeLayer = mLayerMap.GetAndRemove(aHandle.Value());
   if (maybeLayer) {
     (*maybeLayer)->Disconnect();
   }
 
   return IPC_OK();
 }
 
-mozilla::ipc::IPCResult
-LayerTransactionParent::RecvReleaseCompositable(const CompositableHandle& aHandle)
-{
-  ReleaseCompositable(aHandle);
-  return IPC_OK();
-}
-
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/LayerTransactionParent.h
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -115,20 +115,17 @@ protected:
                                                 const TimeDuration& aPaintTime) override;
 
   virtual mozilla::ipc::IPCResult RecvUpdate(const TransactionInfo& aInfo,
                                              EditReplyArray* reply) override;
 
   virtual mozilla::ipc::IPCResult RecvUpdateNoSwap(const TransactionInfo& aInfo) override;
 
   virtual mozilla::ipc::IPCResult RecvSetLayerObserverEpoch(const uint64_t& aLayerObserverEpoch) override;
-  virtual mozilla::ipc::IPCResult RecvNewCompositable(const CompositableHandle& aHandle,
-                                                      const TextureInfo& aInfo) override;
   virtual mozilla::ipc::IPCResult RecvReleaseLayer(const LayerHandle& aHandle) override;
-  virtual mozilla::ipc::IPCResult RecvReleaseCompositable(const CompositableHandle& aHandle) override;
 
   virtual mozilla::ipc::IPCResult RecvClearCachedResources() override;
   virtual mozilla::ipc::IPCResult RecvForceComposite() override;
   virtual mozilla::ipc::IPCResult RecvSetTestSampleTime(const TimeStamp& aTime) override;
   virtual mozilla::ipc::IPCResult RecvLeaveTestMode() override;
   virtual mozilla::ipc::IPCResult RecvGetAnimationOpacity(const LayerHandle& aLayerHandle,
                                                           float* aOpacity,
                                                           bool* aHasAnimationOpacity) override;
@@ -140,16 +137,19 @@ protected:
   virtual mozilla::ipc::IPCResult RecvSetAsyncZoom(const FrameMetrics::ViewID& aId,
                                                    const float& aValue) override;
   virtual mozilla::ipc::IPCResult RecvFlushApzRepaints() override;
   virtual mozilla::ipc::IPCResult RecvGetAPZTestData(APZTestData* aOutData) override;
   virtual mozilla::ipc::IPCResult RecvRequestProperty(const nsString& aProperty, float* aValue) override;
   virtual mozilla::ipc::IPCResult RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId,
                                                              nsTArray<ScrollableLayerGuid>&& aTargets) override;
 
+  virtual PCompositableParent* AllocPCompositableParent(const TextureInfo& aInfo) override;
+  virtual bool DeallocPCompositableParent(PCompositableParent* actor) override;
+
   virtual void ActorDestroy(ActorDestroyReason why) override;
 
   template <typename T>
   bool BindLayer(const RefPtr<Layer>& aLayer, const T& aCreateOp) {
     return BindLayerToHandle(aLayer, aCreateOp.layer());
   }
 
   bool BindLayerToHandle(RefPtr<Layer> aLayer, const LayerHandle& aHandle);
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: sw=2 ts=8 et :
  */
 /* 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 LayersSurfaces;
+include protocol PCompositable;
 include protocol PCompositorBridge;
 include protocol PRenderFrame;
 include protocol PTexture;
 
 include "gfxipc/ShadowLayerUtils.h";
 include "mozilla/GfxMessageUtils.h";
 include "ImageLayers.h";
 
@@ -44,17 +45,16 @@ using struct mozilla::layers::ScrollMeta
 using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
 using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::MaybeLayerClip from "FrameMetrics.h";
 using mozilla::gfx::Glyph from "Layers.h";
 using mozilla::layers::BorderColors from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::BorderCorners from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::BorderWidths from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::LayerHandle from "mozilla/layers/LayersTypes.h";
-using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
 
 namespace mozilla {
 namespace layers {
 
 struct TargetConfig {
   IntRect naturalBounds;
   ScreenRotation rotation;
   ScreenOrientationInternal orientation;
@@ -68,22 +68,22 @@ struct OpCreateImageLayer      { LayerHa
 struct OpCreateColorLayer      { LayerHandle layer; };
 struct OpCreateTextLayer       { LayerHandle layer; };
 struct OpCreateBorderLayer       { LayerHandle layer; };
 struct OpCreateCanvasLayer     { LayerHandle layer; };
 struct OpCreateRefLayer        { LayerHandle layer; };
 
 struct OpAttachCompositable {
   LayerHandle layer;
-  CompositableHandle compositable;
+  PCompositable compositable;
 };
 
 struct OpAttachAsyncCompositable {
   LayerHandle layer;
-  CompositableHandle compositable;
+  uint64_t containerID;
 };
 
 struct ThebesBufferData {
   IntRect rect;
   IntPoint rotation;
 };
 
 struct CubicBezierFunction {
@@ -464,17 +464,17 @@ union CompositableOperationDetail {
   OpRemoveTexture;
 
   OpUseTexture;
   OpUseComponentAlphaTextures;
   OpUseOverlaySource;
 };
 
 struct CompositableOperation {
-  CompositableHandle compositable;
+  PCompositable compositable;
   CompositableOperationDetail detail;
 };
 
 // A unit of a changeset; a set of these comprise a changeset
 // If adding a new edit type that requires the hit testing tree to be updated,
 // set the updateHitTestingTree flag to true in RecvUpdate()
 union Edit {
   OpCreatePaintedLayer;
@@ -502,32 +502,32 @@ union Edit {
 
   CompositableOperation;
 };
 
 // Operations related to destroying resources, always handled after the other
 // operations for safety.
 union OpDestroy {
   PTexture;
-  CompositableHandle;
+  PCompositable;
 };
 
 // Replies to operations
 
 struct OpContentBufferSwap {
-  CompositableHandle compositable;
+  PCompositable compositable;
   nsIntRegion frontUpdatedRegion;
 };
 
 /**
  * An ImageCompositeNotification is sent the first time a particular
  * image is composited by an ImageHost.
  */
 struct ImageCompositeNotification {
-  CompositableHandle compositable;
+  uint64_t asyncCompositableID;
   TimeStamp imageTimeStamp;
   TimeStamp firstCompositeTimeStamp;
   uint32_t frameID;
   uint32_t producerID;
 };
 
 // Unit of a "changeset reply".  This is a weird abstraction, probably
 // only to be used for buffer swapping.
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/PCompositable.ipdl
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* 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 protocol PLayerTransaction;
+include protocol PImageBridge;
+include protocol PCompositorBridge;
+
+namespace mozilla {
+namespace layers {
+
+async protocol PCompositable
+{
+    manager PImageBridge or PLayerTransaction;
+child:
+    async __delete__();
+parent:
+    /**
+     * Asynchronously tell the compositor side to remove the texture.
+     */
+    async Destroy();
+};
+
+} // namespace
+} // namespace
--- a/gfx/layers/ipc/PCompositorBridge.ipdl
+++ b/gfx/layers/ipc/PCompositorBridge.ipdl
@@ -6,16 +6,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include LayersSurfaces;
 include LayersMessages;
 include PlatformWidgetTypes;
 include protocol PAPZ;
 include protocol PAPZCTreeManager;
 include protocol PBrowser;
+include protocol PCompositable;
 include protocol PCompositorWidget;
 include protocol PLayerTransaction;
 include protocol PTexture;
 include "mozilla/GfxMessageUtils.h";
 
 using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
 using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
 using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
--- a/gfx/layers/ipc/PImageBridge.ipdl
+++ b/gfx/layers/ipc/PImageBridge.ipdl
@@ -1,37 +1,38 @@
 /* -*- 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 LayersSurfaces;
 include LayersMessages;
+include protocol PCompositable;
 include protocol PTexture;
 include ProtocolTypes;
 include protocol PMediaSystemResourceManager;
 
 include "mozilla/GfxMessageUtils.h";
 
 using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
 using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h";
-using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
 
 using PlatformThreadId from "base/platform_thread.h";
 
 namespace mozilla {
 namespace layers {
 
 /**
  * The PImageBridge protocol is used to allow isolated threads or processes to push
  * frames directly to the compositor thread/process without relying on the main thread
  * which might be too busy dealing with content script.
  */
 sync protocol PImageBridge
 {
+  manages PCompositable;
   manages PTexture;
   manages PMediaSystemResourceManager;
 
 child:
   async ParentAsyncMessages(AsyncParentMessageData[] aMessages);
 
   async DidComposite(ImageCompositeNotification[] aNotifications);
 
@@ -47,19 +48,18 @@ parent:
   // in a state in which it can't send asynchronous messages
   // so as to not race with the channel getting closed.
   // In the child side, the Closing the channel does not happen right after WillClose,
   // it is scheduled in the ImageBridgeChild's message queue in order to ensure
   // that all of the messages from the parent side have been received and processed
   // before sending closing the channel.
   sync WillClose();
 
+  async PCompositable(TextureInfo aInfo, uint64_t aId);
   async PTexture(SurfaceDescriptor aSharedData, LayersBackend aBackend, TextureFlags aTextureFlags, uint64_t aSerial);
   async PMediaSystemResourceManager();
 
-  sync NewCompositable(CompositableHandle aHandle, TextureInfo aInfo);
-  async ReleaseCompositable(CompositableHandle aHandle);
 };
 
 
 } // namespace
 } // namespace
 
--- a/gfx/layers/ipc/PLayerTransaction.ipdl
+++ b/gfx/layers/ipc/PLayerTransaction.ipdl
@@ -2,30 +2,30 @@
  * vim: sw=2 ts=8 et :
  */
 /* 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 LayersSurfaces;
 include LayersMessages;
+include protocol PCompositable;
 include protocol PCompositorBridge;
 include protocol PRenderFrame;
 include protocol PTexture;
 
 include "mozilla/GfxMessageUtils.h";
 
 using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
 using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 using class mozilla::layers::APZTestData from "mozilla/layers/APZTestData.h";
 using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
 using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
 using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::LayerHandle from "mozilla/layers/LayersTypes.h";
-using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
 
 /**
  * The layers protocol is spoken between thread contexts that manage
  * layer (sub)trees.  The protocol comprises atomically publishing
  * layer subtrees to a "shadow" thread context (which grafts the
  * subtree into its own tree), and atomically updating a published
  * subtree.  ("Atomic" in this sense is wrt painting.)
  */
@@ -35,36 +35,35 @@ namespace layers {
 
 union MaybeTransform {
   Matrix4x4;
   void_t;
 };
 
 sync protocol PLayerTransaction {
   manager PCompositorBridge;
+  manages PCompositable;
 
 parent:
+  async PCompositable(TextureInfo aTextureInfo);
+
   // The isFirstPaint flag can be used to indicate that this is the first update
   // for a particular document.
   sync Update(TransactionInfo txn) returns (EditReply[] reply);
 
   async PaintTime(uint64_t id, TimeDuration paintTime);
 
   // We don't need to send a sync transaction if
   // no transaction operate require a swap.
   async UpdateNoSwap(TransactionInfo txn);
 
   async SetLayerObserverEpoch(uint64_t layerObserverEpoch);
 
-  // Create a new Compositable.
-  async NewCompositable(CompositableHandle handle, TextureInfo info);
-
-  // Release an object that is no longer in use.
+  // Release a layer that is no longer in use.
   async ReleaseLayer(LayerHandle layer);
-  async ReleaseCompositable(CompositableHandle compositable);
 
   // Testing APIs
 
   // Enter test mode, set the sample time to sampleTime, and resample
   // animations. sampleTime must not be null.
   sync SetTestSampleTime(TimeStamp sampleTime);
   // Leave test mode and resume normal compositing
   sync LeaveTestMode();
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -17,23 +17,23 @@
 #include "gfxPlatform.h"                // for gfxImageFormat, gfxPlatform
 //#include "gfxSharedImageSurface.h"      // for gfxSharedImageSurface
 #include "ipc/IPCMessageUtils.h"        // for gfxContentType, null_t
 #include "IPDLActor.h"
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/layers/CompositableClient.h"  // for CompositableClient, etc
 #include "mozilla/layers/CompositorBridgeChild.h"
-#include "mozilla/layers/ContentClient.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/LayersMessages.h"  // for Edit, etc
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
 #include "mozilla/layers/LayersTypes.h"  // for MOZ_LAYERS_LOG
 #include "mozilla/layers/LayerTransactionChild.h"
+#include "mozilla/layers/PCompositableChild.h"
 #include "mozilla/layers/PTextureChild.h"
 #include "ShadowLayerUtils.h"
 #include "mozilla/layers/TextureClient.h"  // for TextureClient
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "nsTArray.h"                   // for AutoTArray, nsTArray, etc
 #include "nsXULAppAPI.h"                // for XRE_GetProcessType, etc
 #include "mozilla/ReentrantMonitor.h"
 
@@ -377,34 +377,34 @@ ShadowLayerForwarder::UseTiledLayerBuffe
                                           const SurfaceDescriptorTiles& aTileLayerDescriptor)
 {
   MOZ_ASSERT(aCompositable);
 
   if (!aCompositable->IsConnected()) {
     return;
   }
 
-  mTxn->AddNoSwapPaint(CompositableOperation(aCompositable->GetIPCHandle(),
+  mTxn->AddNoSwapPaint(CompositableOperation(nullptr, aCompositable->GetIPDLActor(),
                                              OpUseTiledLayerBuffer(aTileLayerDescriptor)));
 }
 
 void
 ShadowLayerForwarder::UpdateTextureRegion(CompositableClient* aCompositable,
                                           const ThebesBufferData& aThebesBufferData,
                                           const nsIntRegion& aUpdatedRegion)
 {
   MOZ_ASSERT(aCompositable);
 
   if (!aCompositable->IsConnected()) {
     return;
   }
 
   mTxn->AddPaint(
     CompositableOperation(
-      aCompositable->GetIPCHandle(),
+      nullptr, aCompositable->GetIPDLActor(),
       OpPaintTextureRegion(aThebesBufferData, aUpdatedRegion)));
 }
 
 void
 ShadowLayerForwarder::UseTextures(CompositableClient* aCompositable,
                                   const nsTArray<TimedTextureClient>& aTextures)
 {
   MOZ_ASSERT(aCompositable);
@@ -430,51 +430,51 @@ ShadowLayerForwarder::UseTextures(Compos
 
       // We use IMMEDIATE_UPLOAD when we want to be sure that the upload cannot
       // race with updates on the main thread. In this case we want the transaction
       // to be synchronous.
       mTxn->MarkSyncTransaction();
     }
     mClientLayerManager->GetCompositorBridgeChild()->HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient);
   }
-  mTxn->AddEdit(CompositableOperation(aCompositable->GetIPCHandle(),
+  mTxn->AddEdit(CompositableOperation(nullptr, aCompositable->GetIPDLActor(),
                                       OpUseTexture(textures)));
 }
 
 void
 ShadowLayerForwarder::UseComponentAlphaTextures(CompositableClient* aCompositable,
                                                 TextureClient* aTextureOnBlack,
                                                 TextureClient* aTextureOnWhite)
 {
   MOZ_ASSERT(aCompositable);
 
   if (!aCompositable->IsConnected()) {
     return;
   }
 
   MOZ_ASSERT(aTextureOnWhite);
   MOZ_ASSERT(aTextureOnBlack);
-  MOZ_ASSERT(aCompositable->GetIPCHandle());
+  MOZ_ASSERT(aCompositable->GetIPDLActor());
   MOZ_ASSERT(aTextureOnBlack->GetIPDLActor());
   MOZ_ASSERT(aTextureOnWhite->GetIPDLActor());
   MOZ_ASSERT(aTextureOnBlack->GetSize() == aTextureOnWhite->GetSize());
   MOZ_RELEASE_ASSERT(aTextureOnWhite->GetIPDLActor()->GetIPCChannel() == mShadowManager->GetIPCChannel());
   MOZ_RELEASE_ASSERT(aTextureOnBlack->GetIPDLActor()->GetIPCChannel() == mShadowManager->GetIPCChannel());
 
   ReadLockDescriptor readLockW;
   ReadLockDescriptor readLockB;
   aTextureOnBlack->SerializeReadLock(readLockB);
   aTextureOnWhite->SerializeReadLock(readLockW);
 
   mClientLayerManager->GetCompositorBridgeChild()->HoldUntilCompositableRefReleasedIfNecessary(aTextureOnBlack);
   mClientLayerManager->GetCompositorBridgeChild()->HoldUntilCompositableRefReleasedIfNecessary(aTextureOnWhite);
 
   mTxn->AddEdit(
     CompositableOperation(
-      aCompositable->GetIPCHandle(),
+      nullptr, aCompositable->GetIPDLActor(),
       OpUseComponentAlphaTextures(
         nullptr, aTextureOnBlack->GetIPDLActor(),
         nullptr, aTextureOnWhite->GetIPDLActor(),
         readLockB, readLockW)
       )
     );
 }
 
@@ -495,19 +495,19 @@ AddOpDestroy(Transaction* aTxn, const Op
 
 bool
 ShadowLayerForwarder::DestroyInTransaction(PTextureChild* aTexture, bool synchronously)
 {
   return AddOpDestroy(mTxn, OpDestroy(aTexture), synchronously);
 }
 
 bool
-ShadowLayerForwarder::DestroyInTransaction(const CompositableHandle& aHandle)
+ShadowLayerForwarder::DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously)
 {
-  return AddOpDestroy(mTxn, OpDestroy(aHandle), false);
+  return AddOpDestroy(mTxn, OpDestroy(aCompositable), synchronously);
 }
 
 void
 ShadowLayerForwarder::RemoveTextureFromCompositable(CompositableClient* aCompositable,
                                                     TextureClient* aTexture)
 {
   MOZ_ASSERT(aCompositable);
   MOZ_ASSERT(aTexture);
@@ -515,17 +515,17 @@ ShadowLayerForwarder::RemoveTextureFromC
   MOZ_RELEASE_ASSERT(aTexture->GetIPDLActor()->GetIPCChannel() == mShadowManager->GetIPCChannel());
   if (!aCompositable->IsConnected() || !aTexture->GetIPDLActor()) {
     // We don't have an actor anymore, don't try to use it!
     return;
   }
 
   mTxn->AddEdit(
     CompositableOperation(
-      aCompositable->GetIPCHandle(),
+      nullptr, aCompositable->GetIPDLActor(),
       OpRemoveTexture(nullptr, aTexture->GetIPDLActor())));
   if (aTexture->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
     mTxn->MarkSyncTransaction();
   }
 }
 
 bool
 ShadowLayerForwarder::InWorkerThread()
@@ -554,17 +554,18 @@ ShadowLayerForwarder::SendPaintTime(uint
 {
   if (!IPCOpen() ||
       !mShadowManager->SendPaintTime(aId, aPaintTime)) {
     NS_WARNING("Could not send paint times over IPC");
   }
 }
 
 bool
-ShadowLayerForwarder::EndTransaction(const nsIntRegion& aRegionToClear,
+ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies,
+                                     const nsIntRegion& aRegionToClear,
                                      uint64_t aId,
                                      bool aScheduleComposite,
                                      uint32_t aPaintSequenceNumber,
                                      bool aIsRepeatTransaction,
                                      const mozilla::TimeStamp& aTransactionStart,
                                      bool* aSent)
 {
   *aSent = false;
@@ -729,26 +730,23 @@ ShadowLayerForwarder::EndTransaction(con
   info.targetConfig() = targetConfig;
 
   if (!GetTextureForwarder()->IsSameProcess()) {
     MOZ_LAYERS_LOG(("[LayersForwarder] syncing before send..."));
     PlatformSyncBeforeUpdate();
   }
 
   profiler_tracing("Paint", "Rasterize", TRACING_INTERVAL_END);
-
-  AutoTArray<EditReply, 10> replies;
   if (mTxn->mSwapRequired) {
     MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction..."));
     RenderTraceScope rendertrace3("Forward Transaction", "000093");
-    if (!mShadowManager->SendUpdate(info, &replies)) {
+    if (!mShadowManager->SendUpdate(info, aReplies)) {
       MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
       return false;
     }
-    ProcessReplies(replies);
   } else {
     // If we don't require a swap we can call SendUpdateNoSwap which
     // assumes that aReplies is empty (DEBUG assertion)
     MOZ_LAYERS_LOG(("[LayersForwarder] sending no swap transaction..."));
     RenderTraceScope rendertrace3("Forward NoSwap Transaction", "000093");
     if (!mShadowManager->SendUpdateNoSwap(info)) {
       MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
       return false;
@@ -758,49 +756,16 @@ ShadowLayerForwarder::EndTransaction(con
   *aSent = true;
   mIsFirstPaint = false;
   mPaintSyncId = 0;
   MOZ_LAYERS_LOG(("[LayersForwarder] ... done"));
   return true;
 }
 
 void
-ShadowLayerForwarder::ProcessReplies(const nsTArray<EditReply>& aReplies)
-{
-  for (const auto& reply : aReplies) {
-    switch (reply.type()) {
-    case EditReply::TOpContentBufferSwap: {
-      MOZ_LAYERS_LOG(("[LayersForwarder] DoubleBufferSwap"));
-
-      const OpContentBufferSwap& obs = reply.get_OpContentBufferSwap();
-
-      RefPtr<CompositableClient> compositable = FindCompositable(obs.compositable());
-      ContentClientRemote* contentClient = compositable->AsContentClientRemote();
-      MOZ_ASSERT(contentClient);
-
-      contentClient->SwapBuffers(obs.frontUpdatedRegion());
-      break;
-    }
-    default:
-      MOZ_CRASH("not reached");
-    }
-  }
-}
-
-RefPtr<CompositableClient>
-ShadowLayerForwarder::FindCompositable(const CompositableHandle& aHandle)
-{
-  CompositableClient* client = nullptr;
-  if (!mCompositables.Get(aHandle.Value(), &client)) {
-    return nullptr;
-  }
-  return client;
-}
-
-void
 ShadowLayerForwarder::SetLayerObserverEpoch(uint64_t aLayerObserverEpoch)
 {
   if (!IPCOpen()) {
     return;
   }
   Unused << mShadowManager->SendSetLayerObserverEpoch(aLayerObserverEpoch);
 }
 
@@ -846,41 +811,38 @@ ShadowLayerForwarder::Connect(Compositab
 #ifdef GFX_COMPOSITOR_LOGGING
   printf("ShadowLayerForwarder::Connect(Compositable)\n");
 #endif
   MOZ_ASSERT(aCompositable);
   MOZ_ASSERT(mShadowManager);
   if (!IPCOpen()) {
     return;
   }
-
-  static uint64_t sNextID = 1;
-  uint64_t id = sNextID++;
-
-  mCompositables.Put(id, aCompositable);
-
-  CompositableHandle handle(id);
-  aCompositable->InitIPDL(handle);
-  mShadowManager->SendNewCompositable(handle, aCompositable->GetTextureInfo());
+  PCompositableChild* actor =
+    mShadowManager->SendPCompositableConstructor(aCompositable->GetTextureInfo());
+  if (!actor) {
+    return;
+  }
+  aCompositable->InitIPDLActor(actor);
 }
 
 void ShadowLayerForwarder::Attach(CompositableClient* aCompositable,
                                   ShadowableLayer* aLayer)
 {
   MOZ_ASSERT(aLayer);
   MOZ_ASSERT(aCompositable);
-  mTxn->AddEdit(OpAttachCompositable(Shadow(aLayer), aCompositable->GetIPCHandle()));
+  mTxn->AddEdit(OpAttachCompositable(Shadow(aLayer), nullptr, aCompositable->GetIPDLActor()));
 }
 
-void ShadowLayerForwarder::AttachAsyncCompositable(const CompositableHandle& aHandle,
+void ShadowLayerForwarder::AttachAsyncCompositable(uint64_t aCompositableID,
                                                    ShadowableLayer* aLayer)
 {
   MOZ_ASSERT(aLayer);
-  MOZ_ASSERT(aHandle);
-  mTxn->AddEdit(OpAttachAsyncCompositable(Shadow(aLayer), aHandle));
+  MOZ_ASSERT(aCompositableID != 0); // zero is always an invalid compositable id.
+  mTxn->AddEdit(OpAttachAsyncCompositable(Shadow(aLayer), aCompositableID));
 }
 
 void ShadowLayerForwarder::SetShadowManager(PLayerTransactionChild* aShadowManager)
 {
   mShadowManager = static_cast<LayerTransactionChild*>(aShadowManager);
   mShadowManager->SetForwarder(this);
 }
 
@@ -1084,26 +1046,16 @@ void
 ShadowLayerForwarder::SyncWithCompositor()
 {
   auto compositorBridge = GetCompositorBridgeChild();
   if (compositorBridge && compositorBridge->IPCOpen()) {
     compositorBridge->SendSyncWithCompositor();
   }
 }
 
-void
-ShadowLayerForwarder::ReleaseCompositable(const CompositableHandle& aHandle)
-{
-  AssertInForwarderThread();
-  if (!DestroyInTransaction(aHandle)) {
-    mShadowManager->SendReleaseCompositable(aHandle);
-  }
-  mCompositables.Remove(aHandle.Value());
-}
-
 ShadowableLayer::~ShadowableLayer()
 {
   if (mShadow) {
     mForwarder->ReleaseLayer(GetShadow());
   }
 }
 
 } // namespace layers
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -177,17 +177,17 @@ public:
   /**
    * Adds an edit in the transaction in order to attach a Compositable that
    * is not managed by this ShadowLayerForwarder (for example, by ImageBridge
    * in the case of async-video).
    * Since the compositable is not managed by this forwarder, we can't use
    * the compositable or it's IPDL actor here, so we use an ID instead, that
    * is matched on the compositor side.
    */
-  void AttachAsyncCompositable(const CompositableHandle& aHandle,
+  void AttachAsyncCompositable(uint64_t aCompositableID,
                                ShadowableLayer* aLayer);
 
   /**
    * Begin recording a transaction to be forwarded atomically to a
    * LayerManagerComposite.
    */
   void BeginTransaction(const gfx::IntRect& aTargetBounds,
                         ScreenRotation aRotation,
@@ -246,19 +246,18 @@ public:
                ShadowableLayer* aMaskLayer);
 
   /**
    * See CompositableForwarder::UseTiledLayerBuffer
    */
   void UseTiledLayerBuffer(CompositableClient* aCompositable,
                                    const SurfaceDescriptorTiles& aTileLayerDescriptor) override;
 
-  void ReleaseCompositable(const CompositableHandle& aHandle) override;
   bool DestroyInTransaction(PTextureChild* aTexture, bool synchronously) override;
-  bool DestroyInTransaction(const CompositableHandle& aHandle);
+  bool DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously) override;
 
   virtual void RemoveTextureFromCompositable(CompositableClient* aCompositable,
                                              TextureClient* aTexture) override;
 
   /**
    * Communicate to the compositor that aRegion in the texture identified by aLayer
    * and aIdentifier has been updated to aThebesBuffer.
    */
@@ -280,17 +279,18 @@ public:
    */
   void SendPaintTime(uint64_t aId, TimeDuration aPaintTime);
 
   /**
    * End the current transaction and forward it to LayerManagerComposite.
    * |aReplies| are directions from the LayerManagerComposite to the
    * caller of EndTransaction().
    */
-  bool EndTransaction(const nsIntRegion& aRegionToClear,
+  bool EndTransaction(InfallibleTArray<EditReply>* aReplies,
+                      const nsIntRegion& aRegionToClear,
                       uint64_t aId,
                       bool aScheduleComposite,
                       uint32_t aPaintSequenceNumber,
                       bool aIsRepeatTransaction,
                       const mozilla::TimeStamp& aTransactionStart,
                       bool* aSent);
 
   /**
@@ -415,20 +415,16 @@ protected:
   explicit ShadowLayerForwarder(ClientLayerManager* aClientLayerManager);
 
 #ifdef DEBUG
   void CheckSurfaceDescriptor(const SurfaceDescriptor* aDescriptor) const;
 #else
   void CheckSurfaceDescriptor(const SurfaceDescriptor* aDescriptor) const {}
 #endif
 
-  void ProcessReplies(const nsTArray<EditReply>& aReplies);
-
-  RefPtr<CompositableClient> FindCompositable(const CompositableHandle& aHandle);
-
   bool InWorkerThread();
 
   CompositorBridgeChild* GetCompositorBridgeChild();
 
   RefPtr<LayerTransactionChild> mShadowManager;
   RefPtr<CompositorBridgeChild> mCompositorBridgeChild;
 
 private:
@@ -438,17 +434,16 @@ private:
   MessageLoop* mMessageLoop;
   DiagnosticTypes mDiagnosticTypes;
   bool mIsFirstPaint;
   bool mWindowOverlayChanged;
   int32_t mPaintSyncId;
   InfallibleTArray<PluginWindowData> mPluginWindowData;
   UniquePtr<ActiveResourceTracker> mActiveResourceTracker;
   uint64_t mNextLayerHandle;
-  nsDataHashtable<nsUint64HashKey, CompositableClient*> mCompositables;
 };
 
 class CompositableClient;
 
 /**
  * A ShadowableLayer is a Layer can be shared with a parent context
  * through a ShadowLayerForwarder.  A ShadowableLayer maps to a
  * Shadow*Layer in a parent context.
--- a/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
+++ b/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
@@ -31,17 +31,18 @@ SharedPlanarYCbCrImage::SharedPlanarYCbC
 : mCompositable(aCompositable)
 {
   MOZ_COUNT_CTOR(SharedPlanarYCbCrImage);
 }
 
 SharedPlanarYCbCrImage::~SharedPlanarYCbCrImage() {
   MOZ_COUNT_DTOR(SharedPlanarYCbCrImage);
 
-  if (mCompositable->GetAsyncHandle() && !InImageBridgeChildThread()) {
+  if (mCompositable->GetAsyncID() != 0 &&
+      !InImageBridgeChildThread()) {
     if (mTextureClient) {
       ADDREF_MANUALLY(mTextureClient);
       ImageBridgeChild::DispatchReleaseTextureClient(mTextureClient);
       mTextureClient = nullptr;
     }
   }
 }
 
--- a/gfx/layers/ipc/SharedRGBImage.cpp
+++ b/gfx/layers/ipc/SharedRGBImage.cpp
@@ -58,17 +58,18 @@ SharedRGBImage::SharedRGBImage(ImageClie
 {
   MOZ_COUNT_CTOR(SharedRGBImage);
 }
 
 SharedRGBImage::~SharedRGBImage()
 {
   MOZ_COUNT_DTOR(SharedRGBImage);
 
-  if (mCompositable->GetAsyncHandle() && !InImageBridgeChildThread()) {
+  if (mCompositable->GetAsyncID() != 0 &&
+      !InImageBridgeChildThread()) {
     ADDREF_MANUALLY(mTextureClient);
     ImageBridgeChild::DispatchReleaseTextureClient(mTextureClient);
     mTextureClient = nullptr;
   }
 }
 
 bool
 SharedRGBImage::Allocate(gfx::IntSize aSize, gfx::SurfaceFormat aFormat)
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -124,16 +124,17 @@ EXPORTS.mozilla.layers += [
     'AxisPhysicsModel.h',
     'AxisPhysicsMSDModel.h',
     'basic/BasicCompositor.h',
     'basic/MacIOSurfaceTextureHostBasic.h',
     'basic/TextureHostBasic.h',
     'BSPTree.h',
     'BufferTexture.h',
     'client/CanvasClient.h',
+    'client/CompositableChild.h',
     'client/CompositableClient.h',
     'client/ContentClient.h',
     'client/GPUVideoTextureClient.h',
     'client/ImageClient.h',
     'client/SingleTiledContentClient.h',
     'client/TextureClient.h',
     'client/TextureClientPool.h',
     'client/TextureClientRecycleAllocator.h',
@@ -288,16 +289,17 @@ UNIFIED_SOURCES += [
     'client/ClientCanvasLayer.cpp',
     'client/ClientColorLayer.cpp',
     'client/ClientContainerLayer.cpp',
     'client/ClientImageLayer.cpp',
     'client/ClientLayerManager.cpp',
     'client/ClientPaintedLayer.cpp',
     'client/ClientTextLayer.cpp',
     'client/ClientTiledPaintedLayer.cpp',
+    'client/CompositableChild.cpp',
     'client/CompositableClient.cpp',
     'client/ContentClient.cpp',
     'client/GPUVideoTextureClient.cpp',
     'client/ImageClient.cpp',
     'client/SingleTiledContentClient.cpp',
     'client/TextureClient.cpp',
     'client/TextureClientPool.cpp',
     'client/TextureClientRecycleAllocator.cpp',
@@ -324,16 +326,17 @@ UNIFIED_SOURCES += [
     'Effects.cpp',
     'FrameMetrics.cpp',
     'GLImages.cpp',
     'ImageDataSerializer.cpp',
     'ImageLayers.cpp',
     'ipc/APZChild.cpp',
     'ipc/APZCTreeManagerChild.cpp',
     'ipc/APZCTreeManagerParent.cpp',
+    'ipc/CompositableForwarder.cpp',
     'ipc/CompositableTransactionParent.cpp',
     'ipc/CompositorBench.cpp',
     'ipc/CompositorBridgeChild.cpp',
     'ipc/CompositorBridgeParent.cpp',
     'ipc/CompositorThread.cpp',
     'ipc/CompositorVsyncScheduler.cpp',
     'ipc/CrossProcessCompositorBridgeParent.cpp',
     'ipc/ImageBridgeChild.cpp',
@@ -394,16 +397,17 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'coco
         'opengl/MacIOSurfaceTextureHostOGL.cpp',
     ]
 
 IPDL_SOURCES = [
     'ipc/LayersMessages.ipdlh',
     'ipc/LayersSurfaces.ipdlh',
     'ipc/PAPZ.ipdl',
     'ipc/PAPZCTreeManager.ipdl',
+    'ipc/PCompositable.ipdl',
     'ipc/PCompositorBridge.ipdl',
     'ipc/PImageBridge.ipdl',
     'ipc/PLayerTransaction.ipdl',
     'ipc/PTexture.ipdl',
     'ipc/PVideoBridge.ipdl',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -2204,17 +2204,17 @@ nsBaseWidget::CreateScrollCaptureContain
 {
   mScrollCaptureContainer =
     LayerManager::CreateImageContainer(ImageContainer::ASYNCHRONOUS);
   if (!mScrollCaptureContainer) {
     NS_WARNING("Failed to create ImageContainer for widget image capture.");
     return ImageContainer::sInvalidAsyncContainerId;
   }
 
-  return mScrollCaptureContainer->GetAsyncContainerHandle().Value();
+  return mScrollCaptureContainer->GetAsyncContainerID();
 }
 
 void
 nsBaseWidget::UpdateScrollCapture()
 {
   // Don't capture if no container or no size.
   if (!mScrollCaptureContainer || mBounds.width <= 0 || mBounds.height <= 0) {
     return;