Use async compositable IDs for image composite notifications. (bug 1325784 part 4, r=nical)
authorDavid Anderson <dvander@alliedmods.net>
Wed, 04 Jan 2017 10:19:30 -0500
changeset 327959 ed511c350d9dee0d05f6c8ae3dc4cb688891bacd
parent 327958 f27059c293c8ca40470054612b457304c42616c2
child 327960 38cde09a9df35208d2fa0436566ea82665917c90
push id31160
push userphilringnalda@gmail.com
push dateThu, 05 Jan 2017 02:33:44 +0000
treeherdermozilla-central@f13abb8ba9f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1325784
milestone53.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Use async compositable IDs for image composite notifications. (bug 1325784 part 4, r=nical)
gfx/layers/ImageContainer.cpp
gfx/layers/ImageContainer.h
gfx/layers/client/CompositableChild.cpp
gfx/layers/client/CompositableChild.h
gfx/layers/composite/CompositableHost.cpp
gfx/layers/composite/CompositableHost.h
gfx/layers/composite/ImageHost.cpp
gfx/layers/composite/ImageHost.h
gfx/layers/composite/LayerManagerComposite.h
gfx/layers/ipc/CompositorBridgeParent.cpp
gfx/layers/ipc/ImageBridgeChild.cpp
gfx/layers/ipc/ImageBridgeChild.h
gfx/layers/ipc/ImageBridgeParent.cpp
gfx/layers/ipc/ImageBridgeParent.h
gfx/layers/ipc/ImageContainerChild.cpp
gfx/layers/ipc/ImageContainerParent.cpp
gfx/layers/ipc/LayerTransactionParent.cpp
gfx/layers/ipc/LayersMessages.ipdlh
gfx/layers/ipc/PImageBridge.ipdl
--- a/gfx/layers/ImageContainer.cpp
+++ b/gfx/layers/ImageContainer.cpp
@@ -355,17 +355,17 @@ ImageContainer::GetCurrentSize()
   if (mCurrentImages.IsEmpty()) {
     return gfx::IntSize(0, 0);
   }
 
   return mCurrentImages[0].mImage->GetSize();
 }
 
 void
-ImageContainer::NotifyCompositeInternal(const ImageCompositeNotification& aNotification)
+ImageContainer::NotifyComposite(const ImageCompositeNotification& aNotification)
 {
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
 
   // An image composition notification is sent the first time a particular
   // image is composited by an ImageHost. Thus, every time we receive such
   // a notification, a new image has been painted.
   ++mPaintCount;
 
--- a/gfx/layers/ImageContainer.h
+++ b/gfx/layers/ImageContainer.h
@@ -557,16 +557,18 @@ public:
    * Every expired image that is never composited is counted as dropped.
    */
   uint32_t GetDroppedImageCount()
   {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     return mDroppedImageCount;
   }
 
+  void NotifyComposite(const ImageCompositeNotification& aNotification);
+
   PImageContainerChild* GetPImageContainerChild();
 
   /**
    * Main thread only.
    */
   static ProducerID AllocateProducerID();
 
 private:
@@ -580,18 +582,16 @@ private:
   // This is called to ensure we have an active image, this may not be true
   // when we're storing image information in a RemoteImageData structure.
   // NOTE: If we have remote data mRemoteDataMutex should be locked when
   // calling this function!
   void EnsureActiveImage();
 
   void EnsureImageClient(bool aCreate);
 
-  void NotifyCompositeInternal(const ImageCompositeNotification& aNotification);
-
   // ReentrantMonitor to protect thread safe access to the "current
   // image", and any other state which is shared between threads.
   ReentrantMonitor mReentrantMonitor;
 
   nsTArray<OwningImage> mCurrentImages;
 
   // Updates every time mActiveImage changes
   uint32_t mGenerationCounter;
--- a/gfx/layers/client/CompositableChild.cpp
+++ b/gfx/layers/client/CompositableChild.cpp
@@ -66,25 +66,26 @@ CompositableChild::ActorDestroy(ActorDes
 
   if (mCompositableClient) {
     mCompositableClient->mCompositableChild = nullptr;
     mCompositableClient = nullptr;
   }
 }
 
 /* static */ PCompositableChild*
-AsyncCompositableChild::CreateActor()
+AsyncCompositableChild::CreateActor(uint64_t aAsyncID)
 {
-  AsyncCompositableChild* child = new AsyncCompositableChild();
+  AsyncCompositableChild* child = new AsyncCompositableChild(aAsyncID);
   child->AddRef();
   return child;
 }
 
-AsyncCompositableChild::AsyncCompositableChild()
- : mLock("AsyncCompositableChild.mLock")
+AsyncCompositableChild::AsyncCompositableChild(uint64_t aAsyncID)
+ : mLock("AsyncCompositableChild.mLock"),
+   mAsyncID(aAsyncID)
 {
 }
 
 AsyncCompositableChild::~AsyncCompositableChild()
 {
 }
 
 void
--- a/gfx/layers/client/CompositableChild.h
+++ b/gfx/layers/client/CompositableChild.h
@@ -56,31 +56,36 @@ protected:
   CompositableClient* mCompositableClient;
   bool mCanSend;
 };
 
 // This CompositableChild can be used off the main thread.
 class AsyncCompositableChild final : public CompositableChild
 {
 public:
-  static PCompositableChild* CreateActor();
+  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:
-  AsyncCompositableChild();
+  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/composite/CompositableHost.cpp
+++ b/gfx/layers/composite/CompositableHost.cpp
@@ -35,26 +35,20 @@ class Compositor;
  *
  * 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,
-                     PImageContainerParent* aImageContainer = nullptr)
+  CompositableParent(CompositableParentManager* aMgr, const TextureInfo& aTextureInfo)
   {
     MOZ_COUNT_CTOR(CompositableParent);
     mHost = CompositableHost::Create(aTextureInfo);
-    if (aImageContainer) {
-      mHost->SetImageContainer(
-          static_cast<ImageContainerParent*>(aImageContainer));
-    }
   }
 
   ~CompositableParent()
   {
     MOZ_COUNT_DTOR(CompositableParent);
   }
 
   virtual void Destroy() override
@@ -64,17 +58,16 @@ public:
     }
   }
 
   RefPtr<CompositableHost> mHost;
 };
 
 CompositableHost::CompositableHost(const TextureInfo& aTextureInfo)
   : mTextureInfo(aTextureInfo)
-  , mAsyncID(0)
   , mCompositorID(0)
   , mCompositor(nullptr)
   , mLayer(nullptr)
   , mFlashCounter(0)
   , mAttached(false)
   , mKeepAttached(false)
 {
   MOZ_COUNT_CTOR(CompositableHost);
@@ -82,20 +75,19 @@ CompositableHost::CompositableHost(const
 
 CompositableHost::~CompositableHost()
 {
   MOZ_COUNT_DTOR(CompositableHost);
 }
 
 PCompositableParent*
 CompositableHost::CreateIPDLActor(CompositableParentManager* aMgr,
-                                  const TextureInfo& aTextureInfo,
-                                  PImageContainerParent* aImageContainer)
+                                  const TextureInfo& aTextureInfo)
 {
-  return new CompositableParent(aMgr, aTextureInfo, aImageContainer);
+  return new CompositableParent(aMgr, aTextureInfo);
 }
 
 bool
 CompositableHost::DestroyIPDLActor(PCompositableParent* aActor)
 {
   delete aActor;
   return true;
 }
--- a/gfx/layers/composite/CompositableHost.h
+++ b/gfx/layers/composite/CompositableHost.h
@@ -35,23 +35,36 @@ namespace gfx {
 class DataSourceSurface;
 } // namespace gfx
 
 namespace layers {
 
 class Layer;
 class LayerComposite;
 class Compositor;
-class ImageContainerParent;
 class ThebesBufferData;
 class TiledContentHost;
 class CompositableParentManager;
 class PCompositableParent;
 struct EffectChain;
 
+struct AsyncCompositableRef
+{
+  AsyncCompositableRef()
+   : mProcessId(mozilla::ipc::kInvalidProcessId),
+     mAsyncId(0)
+  {}
+  AsyncCompositableRef(base::ProcessId aProcessId, uint64_t aAsyncId)
+   : mProcessId(aProcessId), mAsyncId(aAsyncId)
+  {}
+  explicit operator bool() const { return !!mAsyncId; }
+  base::ProcessId mProcessId;
+  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
  * the layers transaction to update the Compositbale's textures from the
  * content side. The actual update (and any syncronous upload) is done by the
@@ -130,18 +143,16 @@ public:
   Compositor* GetCompositor() const
   {
     return mCompositor;
   }
 
   Layer* GetLayer() const { return mLayer; }
   void SetLayer(Layer* aLayer) { mLayer = aLayer; }
 
-  virtual void SetImageContainer(ImageContainerParent* aImageContainer) {}
-
   virtual TiledContentHost* AsTiledContentHost() { return nullptr; }
 
   typedef uint32_t AttachFlags;
   static const AttachFlags NO_FLAGS = 0;
   static const AttachFlags ALLOW_REATTACH = 1;
   static const AttachFlags KEEP_ATTACHED = 2;
   static const AttachFlags FORCE_DETACH = 2;
 
@@ -207,47 +218,45 @@ public:
   // 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,
-                  PImageContainerParent* aImageContainer = nullptr);
+                  const TextureInfo& textureInfo);
 
   static bool DestroyIPDLActor(PCompositableParent* actor);
 
   static CompositableHost* FromIPDLActor(PCompositableParent* actor);
 
   uint64_t GetCompositorID() const { return mCompositorID; }
 
-  uint64_t GetAsyncID() const { return mAsyncID; }
+  const AsyncCompositableRef& GetAsyncRef() const { return mAsyncRef; }
+  void SetAsyncRef(const AsyncCompositableRef& aRef) { mAsyncRef = aRef; }
 
   void SetCompositorID(uint64_t aID) { mCompositorID = aID; }
 
-  void SetAsyncID(uint64_t aID) { mAsyncID = aID; }
-
   virtual bool Lock() { return false; }
 
   virtual void Unlock() { }
 
   virtual already_AddRefed<TexturedEffect> GenEffect(const gfx::SamplingFilter aSamplingFilter) {
     return nullptr;
   }
 
   /// Called when shutting down the layer tree.
   /// This is a good place to clear all potential gpu resources before the widget
   /// is is destroyed.
   virtual void CleanupResources() {}
 
 protected:
   TextureInfo mTextureInfo;
-  uint64_t mAsyncID;
+  AsyncCompositableRef mAsyncRef;
   uint64_t mCompositorID;
   RefPtr<Compositor> mCompositor;
   Layer* mLayer;
   uint32_t mFlashCounter; // used when the pref "layers.flash-borders" is true.
   bool mAttached;
   bool mKeepAttached;
 };
 
--- a/gfx/layers/composite/ImageHost.cpp
+++ b/gfx/layers/composite/ImageHost.cpp
@@ -24,26 +24,24 @@ namespace mozilla {
 using namespace gfx;
 
 namespace layers {
 
 class ISurfaceAllocator;
 
 ImageHost::ImageHost(const TextureInfo& aTextureInfo)
   : CompositableHost(aTextureInfo)
-  , mImageContainer(nullptr)
   , mLastFrameID(-1)
   , mLastProducerID(-1)
   , mBias(BIAS_NONE)
   , mLocked(false)
 {}
 
 ImageHost::~ImageHost()
 {
-  SetImageContainer(nullptr);
 }
 
 void
 ImageHost::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
 {
   MOZ_ASSERT(!mLocked);
 
   CompositableHost::UseTextureHost(aTextures);
@@ -344,22 +342,25 @@ ImageHost::Composite(LayerComposite* aLa
     DiagnosticFlags diagnosticFlags = DiagnosticFlags::IMAGE;
     if (effect->mType == EffectTypes::NV12) {
       diagnosticFlags |= DiagnosticFlags::NV12;
     } else if (effect->mType == EffectTypes::YCBCR) {
       diagnosticFlags |= DiagnosticFlags::YCBCR;
     }
 
     if (mLastFrameID != img->mFrameID || mLastProducerID != img->mProducerID) {
-      if (mImageContainer) {
+      if (mAsyncRef) {
+        ImageCompositeNotificationInfo info;
+        info.mImageBridgeProcessId = mAsyncRef.mProcessId;
+        info.mNotification = ImageCompositeNotification(
+          mAsyncRef.mAsyncId,
+          img->mTimeStamp, GetCompositor()->GetCompositionTime(),
+          img->mFrameID, img->mProducerID);
         static_cast<LayerManagerComposite*>(aLayer->GetLayerManager())->
-            AppendImageCompositeNotification(ImageCompositeNotification(
-                mImageContainer, nullptr,
-                img->mTimeStamp, GetCompositor()->GetCompositionTime(),
-                img->mFrameID, img->mProducerID));
+            AppendImageCompositeNotification(info);
       }
       mLastFrameID = img->mFrameID;
       mLastProducerID = img->mProducerID;
     }
     aEffectChain.mPrimaryEffect = effect;
     gfx::Rect pictureRect(0, 0, img->mPictureRect.width, img->mPictureRect.height);
     BigImageIterator* it = mCurrentTextureSource->AsBigImageIterator();
     if (it) {
@@ -573,22 +574,10 @@ ImageHost::GenEffect(const gfx::Sampling
 
   return CreateTexturedEffect(mCurrentTextureHost,
                               mCurrentTextureSource,
                               aSamplingFilter,
                               isAlphaPremultiplied,
                               GetRenderState());
 }
 
-void
-ImageHost::SetImageContainer(ImageContainerParent* aImageContainer)
-{
-  if (mImageContainer) {
-    mImageContainer->mImageHosts.RemoveElement(this);
-  }
-  mImageContainer = aImageContainer;
-  if (mImageContainer) {
-    mImageContainer->mImageHosts.AppendElement(this);
-  }
-}
-
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/composite/ImageHost.h
+++ b/gfx/layers/composite/ImageHost.h
@@ -62,18 +62,16 @@ public:
   virtual TextureHost* GetAsTextureHost(gfx::IntRect* aPictureRect = nullptr) override;
 
   virtual void Attach(Layer* aLayer,
                       Compositor* aCompositor,
                       AttachFlags aFlags = NO_FLAGS) override;
 
   virtual void SetCompositor(Compositor* aCompositor) override;
 
-  virtual void SetImageContainer(ImageContainerParent* aImageContainer) override;
-
   gfx::IntSize GetImageSize() const override;
 
   virtual LayerRenderState GetRenderState() override;
 
   virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
 
   virtual void Dump(std::stringstream& aStream,
                     const char* aPrefix = "",
@@ -142,18 +140,16 @@ protected:
    * it depends only on mImages, mCompositor->GetCompositionTime(), and mBias.
    * mBias is updated at the end of Composite().
    */
   const TimedImage* ChooseImage() const;
   TimedImage* ChooseImage();
   int ChooseImageIndex() const;
 
   nsTArray<TimedImage> mImages;
-  // Weak reference, will be null if mImageContainer has been destroyed.
-  ImageContainerParent* mImageContainer;
   int32_t mLastFrameID;
   int32_t mLastProducerID;
   /**
    * Bias to apply to the next frame.
    */
   Bias mBias;
 
   bool mLocked;
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -60,16 +60,21 @@ class RefLayerComposite;
 class PaintedLayerComposite;
 class TextRenderer;
 class CompositingRenderTarget;
 struct FPSState;
 class PaintCounter;
 
 static const int kVisualWarningDuration = 150; // ms
 
+struct ImageCompositeNotificationInfo {
+  base::ProcessId mImageBridgeProcessId;
+  ImageCompositeNotification mNotification;
+};
+
 // An implementation of LayerManager that acts as a pair with ClientLayerManager
 // and is mirrored across IPDL. This gets managed/updated by LayerTransactionParent.
 class HostLayerManager : public LayerManager
 {
 public:
   HostLayerManager();
   ~HostLayerManager();
 
@@ -123,17 +128,17 @@ public:
   virtual void UpdateRenderBounds(const gfx::IntRect& aRect) {}
 
   // Called by CompositorBridgeParent when a new compositor has been created due
   // to a device reset. The layer manager must clear any cached resources
   // attached to the old compositor, and make a best effort at ignoring
   // layer or texture updates against the old compositor.
   virtual void ChangeCompositor(Compositor* aNewCompositor) = 0;
 
-  void ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotification>* aNotifications)
+  void ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotificationInfo>* aNotifications)
   {
     aNotifications->AppendElements(Move(mImageCompositeNotifications));
   }
 
   /**
    * LayerManagerComposite provides sophisticated debug overlays
    * that can request a next frame.
    */
@@ -160,17 +165,17 @@ public:
   // overlay.
   void SetWindowOverlayChanged() { mWindowOverlayChanged = true; }
 
 
   void SetPaintTime(const TimeDuration& aPaintTime) { mLastPaintTime = aPaintTime; }
 
 protected:
   bool mDebugOverlayWantsNextFrame;
-  nsTArray<ImageCompositeNotification> mImageCompositeNotifications;
+  nsTArray<ImageCompositeNotificationInfo> mImageCompositeNotifications;
   // Testing property. If hardware composer is supported, this will return
   // true if the last frame was deemed 'too complicated' to be rendered.
   float mWarningLevel;
   mozilla::TimeStamp mWarnTime;
 
   bool mWindowOverlayChanged;
   TimeDuration mLastPaintTime;
   TimeStamp mRenderStartTime;
@@ -341,27 +346,30 @@ public:
     mUnusedApzTransformWarning = true;
   }
   void DisabledApzWarning() {
     mDisabledApzWarning = true;
   }
 
   bool AsyncPanZoomEnabled() const override;
 
-  void AppendImageCompositeNotification(const ImageCompositeNotification& aNotification)
+public:
+  void AppendImageCompositeNotification(const ImageCompositeNotificationInfo& aNotification)
   {
     // Only send composite notifications when we're drawing to the screen,
     // because that's what they mean.
     // Also when we're not drawing to the screen, DidComposite will not be
     // called to extract and send these notifications, so they might linger
     // and contain stale ImageContainerParent pointers.
     if (!mCompositor->GetTargetContext()) {
       mImageCompositeNotifications.AppendElement(aNotification);
     }
   }
+
+public:
   virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() override
   {
     return mCompositor->GetTextureFactoryIdentifier();
   }
 
   void ForcePresent() override { mCompositor->ForcePresent(); }
 
 private:
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -1719,17 +1719,17 @@ CompositorBridgeParent::LayerTreeState::
 void
 CompositorBridgeParent::DidComposite(TimeStamp& aCompositeStart,
                                      TimeStamp& aCompositeEnd)
 {
   Unused << SendDidComposite(0, mPendingTransaction, aCompositeStart, aCompositeEnd);
   mPendingTransaction = 0;
 
   if (mLayerManager) {
-    nsTArray<ImageCompositeNotification> notifications;
+    nsTArray<ImageCompositeNotificationInfo> notifications;
     mLayerManager->ExtractImageCompositeNotifications(&notifications);
     if (!notifications.IsEmpty()) {
       Unused << ImageBridgeParent::NotifyImageComposites(notifications);
     }
   }
 
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   ForEachIndirectLayerTree([&] (LayerTreeState* lts, const uint64_t& aLayersId) -> void {
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -378,42 +378,42 @@ ImageBridgeChild::Connect(CompositableCl
 {
   MOZ_ASSERT(aCompositable);
   MOZ_ASSERT(InImageBridgeChildThread());
   MOZ_ASSERT(CanSend());
 
   static uint64_t sNextID = 1;
   uint64_t id = sNextID++;
 
-  PImageContainerChild* imageContainerChild = nullptr;
-  if (aImageContainer)
-    imageContainerChild = aImageContainer->GetPImageContainerChild();
+  MOZ_ASSERT(!mImageContainers.Contains(id));
+  mImageContainers.Put(id, aImageContainer);
 
   PCompositableChild* child =
-    SendPCompositableConstructor(aCompositable->GetTextureInfo(),
-                                 id,
-                                 imageContainerChild);
+    SendPCompositableConstructor(aCompositable->GetTextureInfo(), id);
   if (!child) {
     return;
   }
   aCompositable->InitIPDLActor(child, id);
 }
 
 PCompositableChild*
-ImageBridgeChild::AllocPCompositableChild(const TextureInfo& aInfo,
-                                          const uint64_t& aID,
-                                          PImageContainerChild* aChild)
+ImageBridgeChild::AllocPCompositableChild(const TextureInfo& aInfo, const uint64_t& aID)
 {
   MOZ_ASSERT(CanSend());
-  return AsyncCompositableChild::CreateActor();
+  return AsyncCompositableChild::CreateActor(aID);
 }
 
 bool
 ImageBridgeChild::DeallocPCompositableChild(PCompositableChild* aActor)
 {
+  AsyncCompositableChild* actor = static_cast<AsyncCompositableChild*>(aActor);
+  MOZ_ASSERT(actor->GetAsyncID());
+
+  mImageContainers.Remove(actor->GetAsyncID());
+
   AsyncCompositableChild::DestroyActor(aActor);
   return true;
 }
 
 
 Thread* ImageBridgeChild::GetThread() const
 {
   return sImageBridgeChildThread;
@@ -1130,20 +1130,19 @@ ImageBridgeChild::RecvParentAsyncMessage
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 ImageBridgeChild::RecvDidComposite(InfallibleTArray<ImageCompositeNotification>&& aNotifications)
 {
   for (auto& n : aNotifications) {
-    ImageContainerChild* child =
-      static_cast<ImageContainerChild*>(n.imageContainerChild());
-    if (child) {
-      child->NotifyComposite(n);
+    RefPtr<ImageContainer> imageContainer = mImageContainers.Get(n.asyncCompositableID());
+    if (imageContainer) {
+      imageContainer->NotifyComposite(n);
     }
   }
   return IPC_OK();
 }
 
 PTextureChild*
 ImageBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
                                 LayersBackend aLayersBackend,
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -165,18 +165,17 @@ public:
    *
    * 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,
-                                              PImageContainerChild* aChild) override;
+                                              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;
 
@@ -388,14 +387,19 @@ private:
    */
   uint64_t mFwdTransactionId;
 
   /**
    * Hold TextureClients refs until end of their usages on host side.
    * It defer calling of TextureClient recycle callback.
    */
   nsDataHashtable<nsUint64HashKey, RefPtr<TextureClient> > mTexturesWaitingRecycled;
+
+  /**
+   * Mapping from async compositable IDs to image containers.
+   */
+  nsDataHashtable<nsUint64HashKey, RefPtr<ImageContainer>> mImageContainers;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -234,38 +234,41 @@ mozilla::ipc::IPCResult ImageBridgeParen
   for (unsigned int i = 0; i < textures.Length(); ++i) {
     RefPtr<TextureHost> tex = TextureHost::AsTextureHost(textures[i]);
     tex->DeallocateDeviceData();
   }
   return IPC_OK();
 }
 
 PCompositableParent*
-ImageBridgeParent::AllocPCompositableParent(const TextureInfo& aInfo,
-                                            const uint64_t& aID,
-                                            PImageContainerParent* aImageContainer)
+ImageBridgeParent::AllocPCompositableParent(const TextureInfo& aInfo, const uint64_t& aID)
 {
-  PCompositableParent* actor = CompositableHost::CreateIPDLActor(this, aInfo, aImageContainer);
+  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;
+  }
 
   CompositableHost* host = CompositableHost::FromIPDLActor(actor);
 
-  host->SetAsyncID(aID);
+  host->SetAsyncRef(AsyncCompositableRef(OtherPid(), aID));
   mCompositables[aID] = host;
 
   return actor;
 }
 
 bool ImageBridgeParent::DeallocPCompositableParent(PCompositableParent* aActor)
 {
   if (CompositableHost* host = CompositableHost::FromIPDLActor(aActor)) {
-    mCompositables.erase(host->GetAsyncID());
+    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,
@@ -311,45 +314,45 @@ void
 ImageBridgeParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage)
 {
   mozilla::Unused << SendParentAsyncMessages(aMessage);
 }
 
 class ProcessIdComparator
 {
 public:
-  bool Equals(const ImageCompositeNotification& aA,
-              const ImageCompositeNotification& aB) const
+  bool Equals(const ImageCompositeNotificationInfo& aA,
+              const ImageCompositeNotificationInfo& aB) const
   {
-    return aA.imageContainerParent()->OtherPid() == aB.imageContainerParent()->OtherPid();
+    return aA.mImageBridgeProcessId == aB.mImageBridgeProcessId;
   }
-  bool LessThan(const ImageCompositeNotification& aA,
-                const ImageCompositeNotification& aB) const
+  bool LessThan(const ImageCompositeNotificationInfo& aA,
+                const ImageCompositeNotificationInfo& aB) const
   {
-    return aA.imageContainerParent()->OtherPid() < aB.imageContainerParent()->OtherPid();
+    return aA.mImageBridgeProcessId < aB.mImageBridgeProcessId;
   }
 };
 
 /* static */ bool
-ImageBridgeParent::NotifyImageComposites(nsTArray<ImageCompositeNotification>& aNotifications)
+ImageBridgeParent::NotifyImageComposites(nsTArray<ImageCompositeNotificationInfo>& aNotifications)
 {
   // Group the notifications by destination process ID and then send the
   // 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]);
+    notifications.AppendElement(aNotifications[i].mNotification);
     uint32_t end = i + 1;
-    MOZ_ASSERT(aNotifications[i].imageContainerParent());
-    ProcessId pid = aNotifications[i].imageContainerParent()->OtherPid();
+    MOZ_ASSERT(aNotifications[i].mNotification.asyncCompositableID());
+    ProcessId pid = aNotifications[i].mImageBridgeProcessId;
     while (end < aNotifications.Length() &&
-           aNotifications[end].imageContainerParent()->OtherPid() == pid) {
-      notifications.AppendElement(aNotifications[end]);
+           aNotifications[end].mImageBridgeProcessId == pid) {
+      notifications.AppendElement(aNotifications[end].mNotification);
       ++end;
     }
     GetInstance(pid)->SendPendingAsyncMessages();
     if (!GetInstance(pid)->SendDidComposite(notifications)) {
       ok = false;
     }
     i = end;
   }
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -27,16 +27,18 @@ class Thread;
 
 namespace mozilla {
 namespace ipc {
 class Shmem;
 } // namespace ipc
 
 namespace layers {
 
+struct ImageCompositeNotificationInfo;
+
 /**
  * ImageBridgeParent is the manager Protocol of ImageContainerParent.
  * It's purpose is mainly to setup the IPDL connection. Most of the
  * interesting stuff is in ImageContainerParent.
  */
 class ImageBridgeParent final : public PImageBridgeParent,
                                 public CompositableParentManager,
                                 public ShmemAllocator
@@ -74,18 +76,17 @@ public:
   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,
-                                                PImageContainerParent* aImageContainer) override;
+                                                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;
 
@@ -116,17 +117,17 @@ public:
   using CompositableParentManager::SetAboutToSendAsyncMessages;
   static void SetAboutToSendAsyncMessages(base::ProcessId aChildProcessId);
 
   using CompositableParentManager::SendPendingAsyncMessages;
   static void SendPendingAsyncMessages(base::ProcessId aChildProcessId);
 
   static ImageBridgeParent* GetInstance(ProcessId aId);
 
-  static bool NotifyImageComposites(nsTArray<ImageCompositeNotification>& aNotifications);
+  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:
--- a/gfx/layers/ipc/ImageContainerChild.cpp
+++ b/gfx/layers/ipc/ImageContainerChild.cpp
@@ -27,17 +27,17 @@ ImageContainerChild::ForgetImageContaine
 
 void
 ImageContainerChild::NotifyComposite(const ImageCompositeNotification& aNotification)
 {
   MOZ_ASSERT(InImageBridgeChildThread());
 
   MutexAutoLock lock(mLock);
   if (mImageContainer) {
-    mImageContainer->NotifyCompositeInternal(aNotification);
+    mImageContainer->NotifyComposite(aNotification);
   }
 }
 
 void
 ImageContainerChild::RegisterWithIPDL()
 {
   MOZ_ASSERT(!mIPCOpen);
   MOZ_ASSERT(InImageBridgeChildThread());
--- a/gfx/layers/ipc/ImageContainerParent.cpp
+++ b/gfx/layers/ipc/ImageContainerParent.cpp
@@ -11,19 +11,16 @@
 #include "mozilla/layers/ImageHost.h"
 #include "mozilla/Unused.h"
 
 namespace mozilla {
 namespace layers {
 
 ImageContainerParent::~ImageContainerParent()
 {
-  while (!mImageHosts.IsEmpty()) {
-    mImageHosts[mImageHosts.Length() - 1]->SetImageContainer(nullptr);
-  }
 }
 
 mozilla::ipc::IPCResult ImageContainerParent::RecvAsyncDelete()
 {
   Unused << PImageContainerParent::Send__delete__(this);
   return IPC_OK();
 }
 
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -958,17 +958,17 @@ LayerTransactionParent::RecvForceComposi
 {
   mCompositorBridge->ForceComposite(this);
   return IPC_OK();
 }
 
 PCompositableParent*
 LayerTransactionParent::AllocPCompositableParent(const TextureInfo& aInfo)
 {
-  return CompositableHost::CreateIPDLActor(this, aInfo, 0);
+  return CompositableHost::CreateIPDLActor(this, aInfo);
 }
 
 bool
 LayerTransactionParent::DeallocPCompositableParent(PCompositableParent* aActor)
 {
   return CompositableHost::DestroyIPDLActor(aActor);
 }
 
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -518,17 +518,17 @@ struct OpContentBufferSwap {
   nsIntRegion frontUpdatedRegion;
 };
 
 /**
  * An ImageCompositeNotification is sent the first time a particular
  * image is composited by an ImageHost.
  */
 struct ImageCompositeNotification {
-  PImageContainer imageContainer;
+  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.
--- a/gfx/layers/ipc/PImageBridge.ipdl
+++ b/gfx/layers/ipc/PImageBridge.ipdl
@@ -50,19 +50,17 @@ 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,
-                      nullable PImageContainer aImageContainer);
+  async PCompositable(TextureInfo aInfo, uint64_t aId);
   async PTexture(SurfaceDescriptor aSharedData, LayersBackend aBackend, TextureFlags aTextureFlags, uint64_t aSerial);
   async PMediaSystemResourceManager();
   async PImageContainer();
 
 };
 
 
 } // namespace