Bug 1000525 - Defer Fence release until IPC delivery complete r=nical
authorSotaro Ikeda <sikeda@mozilla.com>
Mon, 05 May 2014 18:56:40 -0700
changeset 200942 4502fc99eb8226c9200fd852ffdb641698c85ba9
parent 200941 e4d65f093e80f4d4a5882299b355eb87f819e9fc
child 200943 fc63732cd4f164df98007a696b55d23d078f265d
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1000525
milestone32.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1000525 - Defer Fence release until IPC delivery complete r=nical
gfx/layers/client/ClientLayerManager.cpp
gfx/layers/client/TextureClient.cpp
gfx/layers/composite/TextureHost.cpp
gfx/layers/composite/TextureHost.h
gfx/layers/ipc/AsyncTransactionTracker.cpp
gfx/layers/ipc/AsyncTransactionTracker.h
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/PImageBridge.ipdl
gfx/layers/ipc/PLayerTransaction.ipdl
gfx/layers/ipc/PTexture.ipdl
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/ShadowLayers.h
gfx/layers/moz.build
gfx/thebes/gfxPlatform.cpp
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -48,16 +48,24 @@ ClientLayerManager::ClientLayerManager(n
   , mNeedsComposite(false)
   , mForwarder(new ShadowLayerForwarder)
 {
   MOZ_COUNT_CTOR(ClientLayerManager);
 }
 
 ClientLayerManager::~ClientLayerManager()
 {
+  ClearCachedResources();
+  // Stop receiveing AsyncParentMessage at Forwarder.
+  // After the call, the message is directly handled by LayerTransactionChild. 
+  // Basically this function should be called in ShadowLayerForwarder's
+  // destructor. But when the destructor is triggered by 
+  // CompositorChild::Destroy(), the destructor can not handle it correctly.
+  // See Bug 1000525.
+  mForwarder->StopReceiveAsyncParentMessge();
   mRoot = nullptr;
 
   MOZ_COUNT_DTOR(ClientLayerManager);
 }
 
 int32_t
 ClientLayerManager::GetMaxTextureSize() const
 {
@@ -261,19 +269,17 @@ ClientLayerManager::GetRemoteRenderer()
   }
 
   return mWidget->GetRemoteRenderer();
 }
 
 void
 ClientLayerManager::Composite()
 {
-  if (LayerTransactionChild* manager = mForwarder->GetShadowManager()) {
-    manager->SendForceComposite();
-  }
+  mForwarder->Composite();
 }
 
 void
 ClientLayerManager::DidComposite()
 {
   MOZ_ASSERT(mWidget);
   nsIWidgetListener *listener = mWidget->GetWidgetListener();
   if (listener) {
@@ -423,16 +429,17 @@ ClientLayerManager::ForwardTransaction(b
     if (sent) {
       mNeedsComposite = false;
     }
   } else if (HasShadowManager()) {
     NS_WARNING("failed to forward Layers transaction");
   }
 
   mForwarder->RemoveTexturesIfNecessary();
+  mForwarder->SendPendingAsyncMessge();
   mPhase = PHASE_NONE;
 
   // this may result in Layers being deleted, which results in
   // PLayer::Send__delete__() and DeallocShmem()
   mKeepAlive.Clear();
 }
 
 ShadowableLayer*
@@ -493,19 +500,17 @@ ClientLayerManager::GetSimpleTileTexture
 
   return mSimpleTilePools[index];
 }
 
 void
 ClientLayerManager::ClearCachedResources(Layer* aSubtree)
 {
   MOZ_ASSERT(!HasShadowManager() || !aSubtree);
-  if (LayerTransactionChild* manager = mForwarder->GetShadowManager()) {
-    manager->SendClearCachedResources();
-  }
+  mForwarder->ClearCachedResources();
   if (aSubtree) {
     ClearLayer(aSubtree);
   } else if (mRoot) {
     ClearLayer(mRoot);
   }
   for (size_t i = 0; i < mTexturePools.Length(); i++) {
     mTexturePools[i]->Clear();
   }
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -85,27 +85,19 @@ public:
   , mTextureData(nullptr)
   , mTextureClient(nullptr)
   , mIPCOpen(false)
   {
   }
 
   bool Recv__delete__() MOZ_OVERRIDE;
 
-  bool RecvCompositorRecycle(const MaybeFenceHandle& aFence)
+  bool RecvCompositorRecycle()
   {
     RECYCLE_LOG("Receive recycle %p (%p)\n", mTextureClient, mWaitForRecycle.get());
-    if (aFence.type() != aFence.Tnull_t) {
-      FenceHandle fence = aFence.get_FenceHandle();
-      if (fence.IsValid() && mTextureClient) {
-        mTextureClient->SetReleaseFenceHandle(aFence);
-        // HWC might not provide Fence.
-        // In this case, HWC implicitly handles buffer's fence.
-      }
-    }
     mWaitForRecycle = nullptr;
     return true;
   }
 
   void WaitForCompositorRecycle()
   {
     mWaitForRecycle = mTextureClient;
     RECYCLE_LOG("Wait for recycle %p\n", mWaitForRecycle.get());
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -4,16 +4,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/layers/TextureHost.h"
 #include "CompositableHost.h"           // for CompositableHost
 #include "LayersLogging.h"              // for AppendToString
 #include "gfx2DGlue.h"                  // for ToIntSize
 #include "mozilla/gfx/2D.h"             // for DataSourceSurface, Factory
 #include "mozilla/ipc/Shmem.h"          // for Shmem
+#include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTracker
+#include "mozilla/layers/CompositableTransactionParent.h" // for CompositableParentManager
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
 #include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
 #ifdef MOZ_X11
 #include "mozilla/layers/X11TextureHost.h"
 #endif
@@ -31,24 +33,54 @@
 #define RECYCLE_LOG(...) do { } while (0)
 #endif
 
 struct nsIntPoint;
 
 namespace mozilla {
 namespace layers {
 
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+// FenceDeliveryTracker puts off releasing a Fence until a transaction complete.
+class FenceDeliveryTracker : public AsyncTransactionTracker {
+public:
+  FenceDeliveryTracker(const android::sp<android::Fence>& aFence)
+    : mFence(aFence)
+  {
+    MOZ_COUNT_CTOR(FenceDeliveryTracker);
+  }
+
+  ~FenceDeliveryTracker()
+  {
+    MOZ_COUNT_DTOR(FenceDeliveryTracker);
+  }
+
+  virtual void Complete() MOZ_OVERRIDE
+  {
+    mFence = nullptr;
+  }
+
+  virtual void Cancel() MOZ_OVERRIDE
+  {
+    mFence = nullptr;
+  }
+
+private:
+  android::sp<android::Fence> mFence;
+};
+#endif
+
 /**
  * TextureParent is the host-side IPDL glue between TextureClient and TextureHost.
  * It is an IPDL actor just like LayerParent, CompositableParent, etc.
  */
 class TextureParent : public PTextureParent
 {
 public:
-  TextureParent(ISurfaceAllocator* aAllocator);
+  TextureParent(CompositableParentManager* aManager);
 
   ~TextureParent();
 
   bool Init(const SurfaceDescriptor& aSharedData,
             const TextureFlags& aFlags);
 
   void CompositorRecycle();
   virtual bool RecvClientRecycle() MOZ_OVERRIDE;
@@ -56,34 +88,34 @@ public:
   virtual bool RecvRemoveTexture() MOZ_OVERRIDE;
 
   virtual bool RecvRemoveTextureSync() MOZ_OVERRIDE;
 
   TextureHost* GetTextureHost() { return mTextureHost; }
 
   void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 
-  ISurfaceAllocator* mAllocator;
+  CompositableParentManager* mCompositableManager;
   RefPtr<TextureHost> mWaitForClientRecycle;
   RefPtr<TextureHost> mTextureHost;
 };
 
 // static
 PTextureParent*
-TextureHost::CreateIPDLActor(ISurfaceAllocator* aAllocator,
+TextureHost::CreateIPDLActor(CompositableParentManager* aManager,
                              const SurfaceDescriptor& aSharedData,
                              TextureFlags aFlags)
 {
   if (aSharedData.type() == SurfaceDescriptor::TSurfaceDescriptorMemory &&
-      !aAllocator->IsSameProcess())
+      !aManager->IsSameProcess())
   {
     NS_ERROR("A client process is trying to peek at our address space using a MemoryTexture!");
     return nullptr;
   }
-  TextureParent* actor = new TextureParent(aAllocator);
+  TextureParent* actor = new TextureParent(aManager);
   if (!actor->Init(aSharedData, aFlags)) {
     delete actor;
     return nullptr;
   }
   return actor;
 }
 
 // static
@@ -599,18 +631,18 @@ size_t MemoryTextureHost::GetBufferSize(
 {
   // MemoryTextureHost just trusts that the buffer size is large enough to read
   // anything we need to. That's because MemoryTextureHost has to trust the buffer
   // pointer anyway, so the security model here is just that MemoryTexture's
   // are restricted to same-process clients.
   return std::numeric_limits<size_t>::max();
 }
 
-TextureParent::TextureParent(ISurfaceAllocator* aAllocator)
-: mAllocator(aAllocator)
+TextureParent::TextureParent(CompositableParentManager* aCompositableManager)
+: mCompositableManager(aCompositableManager)
 {
   MOZ_COUNT_CTOR(TextureParent);
 }
 
 TextureParent::~TextureParent()
 {
   MOZ_COUNT_DTOR(TextureParent);
   if (mTextureHost) {
@@ -623,33 +655,35 @@ static void RecycleCallback(TextureHost*
   tp->CompositorRecycle();
 }
 
 void
 TextureParent::CompositorRecycle()
 {
   mTextureHost->ClearRecycleCallback();
 
-  MaybeFenceHandle handle = null_t();
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
   if (mTextureHost) {
     TextureHostOGL* hostOGL = mTextureHost->AsHostOGL();
     android::sp<android::Fence> fence = hostOGL->GetAndResetReleaseFence();
     if (fence.get() && fence->isValid()) {
-      handle = FenceHandle(fence);
       // HWC might not provide Fence.
       // In this case, HWC implicitly handles buffer's fence.
+
+      FenceHandle handle = FenceHandle(fence);
+      RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
+      mCompositableManager->SendFenceHandle(tracker, this, handle);
     }
   }
 #endif
-  mozilla::unused << SendCompositorRecycle(handle);
 
-  // Don't forget to prepare for the next reycle
-  // if TextureClient request it.
   if (mTextureHost->GetFlags() & TextureFlags::RECYCLE) {
+    mozilla::unused << SendCompositorRecycle();
+    // Don't forget to prepare for the next reycle
+    // if TextureClient request it.
     mWaitForClientRecycle = mTextureHost;
   }
 }
 
 bool
 TextureParent::RecvClientRecycle()
 {
   // This will allow the RecycleCallback to be called once the compositor
@@ -662,17 +696,17 @@ TextureParent::RecvClientRecycle()
   return true;
 }
 
 bool
 TextureParent::Init(const SurfaceDescriptor& aSharedData,
                     const TextureFlags& aFlags)
 {
   mTextureHost = TextureHost::Create(aSharedData,
-                                     mAllocator,
+                                     mCompositableManager,
                                      aFlags);
   if (mTextureHost) {
     mTextureHost->mActor = this;
     if (aFlags & TextureFlags::RECYCLE) {
       mWaitForClientRecycle = mTextureHost;
       RECYCLE_LOG("Setup recycling for tile %p\n", this);
     }
   }
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -36,16 +36,17 @@ namespace ipc {
 class Shmem;
 }
 
 namespace layers {
 
 class Compositor;
 class CompositableHost;
 class CompositableBackendSpecificData;
+class CompositableParentManager;
 class SurfaceDescriptor;
 class ISurfaceAllocator;
 class TextureHostOGL;
 class TextureSourceOGL;
 class TextureSourceD3D9;
 class TextureSourceD3D11;
 class TextureSourceBasic;
 class DataTextureSource;
@@ -387,17 +388,17 @@ public:
   /**
    * Allocate and deallocate a TextureParent actor.
    *
    * TextureParent< is an implementation detail of TextureHost that is not
    * exposed to the rest of the code base. CreateIPDLActor and DestroyIPDLActor
    * are for use with the managing IPDL protocols only (so that they can
    * implement AllocPTextureParent and DeallocPTextureParent).
    */
-  static PTextureParent* CreateIPDLActor(ISurfaceAllocator* aAllocator,
+  static PTextureParent* CreateIPDLActor(CompositableParentManager* aManager,
                                          const SurfaceDescriptor& aSharedData,
                                          TextureFlags aFlags);
   static bool DestroyIPDLActor(PTextureParent* actor);
 
   /**
    * Destroy the TextureChild/Parent pair.
    */
   static bool SendDeleteIPDLActor(PTextureParent* actor);
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/AsyncTransactionTracker.cpp
@@ -0,0 +1,129 @@
+/* -*- 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 "AsyncTransactionTracker.h"
+
+#include "mozilla/layers/ImageBridgeChild.h"  // for ImageBridgeChild
+
+namespace mozilla {
+namespace layers {
+
+uint64_t AsyncTransactionTracker::sSerialCounter(0);
+Mutex* AsyncTransactionTracker::sLock = nullptr;
+
+AsyncTransactionTracker::AsyncTransactionTracker()
+    : mSerial(GetNextSerial())
+    , mCompletedMonitor("AsyncTransactionTracker.mCompleted")
+    , mCompleted(false)
+{
+}
+
+AsyncTransactionTracker::~AsyncTransactionTracker()
+{
+}
+
+void
+AsyncTransactionTracker::WaitComplete()
+{
+  MOZ_ASSERT(!InImageBridgeChildThread());
+
+  MonitorAutoLock mon(mCompletedMonitor);
+  int count = 0;
+  while (!mCompleted) {
+    if (!NS_SUCCEEDED(mCompletedMonitor.Wait(PR_MillisecondsToInterval(10000)))) {
+      NS_WARNING("Failed to wait Monitor");
+      return;
+    }
+    if (count > 1) {
+      NS_WARNING("Waiting async transaction complete.");
+    }
+    count++;
+  }
+}
+
+void
+AsyncTransactionTracker::NotifyComplete()
+{
+  MonitorAutoLock mon(mCompletedMonitor);
+  MOZ_ASSERT(!mCompleted);
+  mCompleted = true;
+  Complete();
+  mCompletedMonitor.Notify();
+}
+
+void
+AsyncTransactionTracker::NotifyCancel()
+{
+  MonitorAutoLock mon(mCompletedMonitor);
+  MOZ_ASSERT(!mCompleted);
+  mCompleted = true;
+  Cancel();
+  mCompletedMonitor.Notify();
+}
+
+AsyncTransactionTrackersHolder::AsyncTransactionTrackersHolder()
+  : mIsTrackersHolderDestroyed(false)
+{
+  MOZ_COUNT_CTOR(AsyncTransactionTrackersHolder);
+}
+
+AsyncTransactionTrackersHolder::~AsyncTransactionTrackersHolder()
+{
+  if (!mIsTrackersHolderDestroyed) {
+    DestroyAsyncTransactionTrackersHolder();
+  }
+  MOZ_COUNT_DTOR(AsyncTransactionTrackersHolder);
+}
+
+void
+AsyncTransactionTrackersHolder::HoldUntilComplete(AsyncTransactionTracker* aTransactionTracker)
+{
+  if (!aTransactionTracker) {
+    return;
+  }
+
+  if (mIsTrackersHolderDestroyed && aTransactionTracker) {
+    aTransactionTracker->NotifyComplete();
+    return;
+  }
+
+  if (aTransactionTracker) {
+    mAsyncTransactionTrackeres[aTransactionTracker->GetId()] = aTransactionTracker;
+  }
+}
+
+void
+AsyncTransactionTrackersHolder::TransactionCompleteted(uint64_t aTransactionId)
+{
+  std::map<uint64_t, RefPtr<AsyncTransactionTracker> >::iterator it
+    = mAsyncTransactionTrackeres.find(aTransactionId);
+  if (it != mAsyncTransactionTrackeres.end()) {
+    it->second->NotifyCancel();
+    mAsyncTransactionTrackeres.erase(it);
+  }
+}
+
+void
+AsyncTransactionTrackersHolder::ClearAllAsyncTransactionTrackers()
+{
+  std::map<uint64_t, RefPtr<AsyncTransactionTracker> >::iterator it;
+  for (it = mAsyncTransactionTrackeres.begin();
+       it != mAsyncTransactionTrackeres.end(); it++) {
+    it->second->NotifyCancel();
+  }
+  mAsyncTransactionTrackeres.clear();
+}
+
+void
+AsyncTransactionTrackersHolder::DestroyAsyncTransactionTrackersHolder() {
+  mIsTrackersHolderDestroyed = true;
+  ClearAllAsyncTransactionTrackers();
+}
+
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/AsyncTransactionTracker.h
@@ -0,0 +1,134 @@
+/* -*- 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/. */
+
+#ifndef mozilla_layers_AsyncTransactionTracker_h
+#define mozilla_layers_AsyncTransactionTracker_h
+
+#include "mozilla/Atomics.h"
+#include "mozilla/layers/TextureClient.h"  // for TextureClient
+#include "mozilla/Monitor.h"      // for Monitor
+#include "mozilla/RefPtr.h"       // for AtomicRefCounted
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * AsyncTransactionTracker tracks asynchronous transaction.
+ * It is typically used for asynchronous layer transaction handling.
+ */
+class AsyncTransactionTracker
+{
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncTransactionTracker)
+
+  AsyncTransactionTracker();
+
+  static void Initialize()
+  {
+    if (!sLock) {
+      sLock = new Mutex("AsyncTransactionTracker::sLock");
+    }
+  }
+
+  static void Finalize()
+  {
+    if (sLock) {
+      delete sLock;
+      sLock = nullptr;
+    }
+  }
+
+  Monitor& GetReentrantMonitor()
+  {
+    return mCompletedMonitor;
+  }
+
+  /**
+   * Wait until asynchronous transaction complete.
+   */
+  void WaitComplete();
+
+  /**
+   * Notify async transaction complete.
+   */
+  void NotifyComplete();
+
+  /**
+   * Notify async transaction cancel.
+   */
+  void NotifyCancel();
+
+  uint64_t GetId()
+  {
+    return mSerial;
+  }
+
+  /**
+   * Called when asynchronous transaction complete.
+   */
+  virtual void Complete()= 0;
+
+  /**
+   * Called when asynchronous transaction is cancelled.
+   * The cancel typically happens when IPC is disconnected
+   */
+  virtual void Cancel()= 0;
+
+  virtual void SetTextureClient(TextureClient* aTextureClient) {}
+
+protected:
+  virtual ~AsyncTransactionTracker();
+
+  static uint64_t GetNextSerial()
+  {
+    MOZ_ASSERT(sLock);
+    if(sLock) {
+      sLock->Lock();
+    }
+    ++sSerialCounter;
+    if(sLock) {
+      sLock->Unlock();
+    }
+    return sSerialCounter;
+  }
+
+  uint64_t mSerial;
+  Monitor mCompletedMonitor;
+  bool    mCompleted;
+
+  /**
+   * gecko does not provide atomic operation for uint64_t.
+   * Ensure atomicity by using Mutex.
+   */
+  static uint64_t sSerialCounter;
+  static Mutex* sLock;
+};
+
+class AsyncTransactionTrackersHolder
+{
+public:
+  AsyncTransactionTrackersHolder();
+  virtual ~AsyncTransactionTrackersHolder();
+
+  void HoldUntilComplete(AsyncTransactionTracker* aTransactionTracker);
+
+  void TransactionCompleteted(uint64_t aTransactionId);
+
+protected:
+  void ClearAllAsyncTransactionTrackers();
+
+  void DestroyAsyncTransactionTrackersHolder();
+
+  bool mIsTrackersHolderDestroyed;
+  std::map<uint64_t, RefPtr<AsyncTransactionTracker> > mAsyncTransactionTrackeres;
+
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif  // mozilla_layers_AsyncTransactionTracker_h
--- a/gfx/layers/ipc/CompositableForwarder.h
+++ b/gfx/layers/ipc/CompositableForwarder.h
@@ -134,16 +134,26 @@ public:
    * Forcibly remove texture data from TextureClient
    * This function needs to be called after a tansaction with Compositor.
    */
   virtual void RemoveTexturesIfNecessary()
   {
     mTexturesToRemove.Clear();
   }
 
+  virtual void HoldTransactionsToRespond(uint64_t aTransactionId)
+  {
+    mTransactionsToRespond.push_back(aTransactionId);
+  }
+
+  virtual void ClearTransactionsToRespond()
+  {
+    mTransactionsToRespond.clear();
+  }
+
   /**
    * Tell the CompositableHost on the compositor side what texture to use for
    * the next composition.
    */
   virtual void UseTexture(CompositableClient* aCompositable,
                           TextureClient* aClient) = 0;
   virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
                                          TextureClient* aClientOnBlack,
@@ -191,16 +201,17 @@ public:
     return mTextureFactoryIdentifier;
   }
 
   int32_t GetSerial() { return mSerial; }
 
 protected:
   TextureFactoryIdentifier mTextureFactoryIdentifier;
   nsTArray<RefPtr<TextureClient> > mTexturesToRemove;
+  std::vector<uint64_t> mTransactionsToRespond;
   const int32_t mSerial;
   static mozilla::Atomic<int32_t> sSerialCounter;
 };
 
 } // namespace
 } // namespace
 
 #endif
--- a/gfx/layers/ipc/CompositableTransactionParent.cpp
+++ b/gfx/layers/ipc/CompositableTransactionParent.cpp
@@ -19,16 +19,17 @@
 #include "mozilla/layers/SharedBufferManagerParent.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/LayersTypes.h"  // for MOZ_LAYERS_LOG
 #include "mozilla/layers/TextureHost.h"  // for TextureHost
 #include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
 #include "mozilla/layers/ThebesLayerComposite.h"
 #include "mozilla/mozalloc.h"           // for operator delete
+#include "mozilla/unused.h"
 #include "nsDebug.h"                    // for NS_WARNING, NS_ASSERTION
 #include "nsRegion.h"                   // for nsIntRegion
 
 namespace mozilla {
 namespace layers {
 
 class ClientTiledLayerBuffer;
 class Compositor;
--- a/gfx/layers/ipc/CompositableTransactionParent.h
+++ b/gfx/layers/ipc/CompositableTransactionParent.h
@@ -5,32 +5,40 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_LAYERS_COMPOSITABLETRANSACTIONPARENT_H
 #define MOZILLA_LAYERS_COMPOSITABLETRANSACTIONPARENT_H
 
 #include <vector>                       // for vector
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
+#include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTracker
 #include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator
 #include "mozilla/layers/LayersMessages.h"  // for EditReply, etc
 
 namespace mozilla {
 namespace layers {
 
 class CompositableHost;
+class PTextureChild;
 
 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 ISurfaceAllocator
+                                , public AsyncTransactionTrackersHolder
 {
+public:
+  virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
+                               PTextureParent* aTexture,
+                               const FenceHandle& aFence) = 0;
+
 protected:
   /**
    * Handle the IPDL messages that affect PCompositable actors.
    */
   bool ReceiveCompositableUpdate(const CompositableOperation& aEdit,
                                  EditReplyVector& replyv);
   bool IsOnCompositorSide() const MOZ_OVERRIDE { return true; }
 
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -469,16 +469,17 @@ ImageBridgeChild::EndTransaction()
         texture->SetReleaseFenceHandle(fence);
       }
       break;
     }
     default:
       NS_RUNTIMEABORT("not reached");
     }
   }
+  SendPendingAsyncMessge();
 }
 
 
 PImageBridgeChild*
 ImageBridgeChild::StartUpInChildProcess(Transport* aTransport,
                                         ProcessId aOtherProcess)
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
@@ -746,16 +747,39 @@ ImageBridgeChild::AllocPTextureChild(con
 }
 
 bool
 ImageBridgeChild::DeallocPTextureChild(PTextureChild* actor)
 {
   return TextureClient::DestroyIPDLActor(actor);
 }
 
+bool
+ImageBridgeChild::RecvParentAsyncMessage(const mozilla::layers::AsyncParentMessageData& aMessage)
+{
+  switch (aMessage.type()) {
+    case AsyncParentMessageData::TOpDeliverFence: {
+      const OpDeliverFence& op = aMessage.get_OpDeliverFence();
+      FenceHandle fence = op.fence();
+      PTextureChild* child = op.textureChild();
+
+      RefPtr<TextureClient> texture = TextureClient::AsTextureClient(child);
+      if (texture) {
+        texture->SetReleaseFenceHandle(fence);
+      }
+      HoldTransactionsToRespond(op.transactionId());
+      break;
+    }
+    default:
+      NS_ERROR("unknown AsyncParentMessageData type");
+      return false;
+  }
+  return true;
+}
+
 PTextureChild*
 ImageBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
                                 TextureFlags aFlags)
 {
   return SendPTextureConstructor(aSharedData, aFlags);
 }
 
 void
@@ -804,10 +828,26 @@ void ImageBridgeChild::RemoveTexture(Tex
   }
 }
 
 bool ImageBridgeChild::IsSameProcess() const
 {
   return OtherProcess() == ipc::kInvalidProcessHandle;
 }
 
+void ImageBridgeChild::SendPendingAsyncMessge()
+{
+  if (!IsCreated() ||
+      mTransactionsToRespond.empty()) {
+    return;
+  }
+  // Send OpReplyDeliverFence messages
+  InfallibleTArray<AsyncChildMessageData> replies;
+  replies.SetCapacity(mTransactionsToRespond.size());
+  for (size_t i = 0; i < mTransactionsToRespond.size(); i++) {
+    replies.AppendElement(OpReplyDeliverFence(mTransactionsToRespond[i]));
+  }
+  mTransactionsToRespond.clear();
+  SendChildAsyncMessages(replies);
+}
+
 } // layers
 } // mozilla
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -187,16 +187,19 @@ public:
   ~ImageBridgeChild();
 
   virtual PTextureChild*
   AllocPTextureChild(const SurfaceDescriptor& aSharedData, const TextureFlags& aFlags) MOZ_OVERRIDE;
 
   virtual bool
   DeallocPTextureChild(PTextureChild* actor) MOZ_OVERRIDE;
 
+  virtual bool
+  RecvParentAsyncMessage(const mozilla::layers::AsyncParentMessageData& aMessage) MOZ_OVERRIDE;
+
   TemporaryRef<ImageClient> CreateImageClient(CompositableType aType);
   TemporaryRef<ImageClient> CreateImageClientNow(CompositableType aType);
 
   static void DispatchReleaseImageClient(ImageClient* aClient);
   static void DispatchReleaseTextureClient(TextureClient* aClient);
   static void DispatchImageClientUpdate(ImageClient* aClient, ImageContainer* aContainer);
 
   /**
@@ -297,16 +300,18 @@ public:
    */
   virtual void DeallocShmem(mozilla::ipc::Shmem& aShmem);
 
   virtual PTextureChild* CreateTexture(const SurfaceDescriptor& aSharedData,
                                        TextureFlags aFlags) MOZ_OVERRIDE;
 
   virtual bool IsSameProcess() const MOZ_OVERRIDE;
 
+  void SendPendingAsyncMessge();
+
 protected:
   ImageBridgeChild();
   bool DispatchAllocShmemInternal(size_t aSize,
                                   SharedMemory::SharedMemoryType aType,
                                   Shmem* aShmem,
                                   bool aUnsafe);
 
   CompositableTransaction* mTxn;
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -20,16 +20,17 @@
 #include "mozilla/layers/CompositorParent.h"  // for CompositorParent
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayersMessages.h"  // for EditReply
 #include "mozilla/layers/LayersSurfaces.h"  // for PGrallocBufferParent
 #include "mozilla/layers/PCompositableParent.h"
 #include "mozilla/layers/PImageBridgeParent.h"
 #include "mozilla/layers/Compositor.h"
 #include "mozilla/mozalloc.h"           // for operator new, etc
+#include "mozilla/unused.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT, etc
 #include "nsISupportsImpl.h"            // for ImageBridgeParent::Release, etc
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl
 #include "nsTArrayForwardDeclare.h"     // for InfallibleTArray
 #include "nsXULAppAPI.h"                // for XRE_GetIOMessageLoop
 #include "mozilla/layers/TextureHost.h"
 #include "nsThreadUtils.h"
@@ -181,16 +182,47 @@ ImageBridgeParent::AllocPTextureParent(c
 }
 
 bool
 ImageBridgeParent::DeallocPTextureParent(PTextureParent* actor)
 {
   return TextureHost::DestroyIPDLActor(actor);
 }
 
+void
+ImageBridgeParent::SendFenceHandle(AsyncTransactionTracker* aTracker,
+                                   PTextureParent* aTexture,
+                                   const FenceHandle& aFence)
+{
+  HoldUntilComplete(aTracker);
+  mozilla::unused << SendParentAsyncMessage(OpDeliverFence(aTracker->GetId(),
+                                        aTexture, nullptr,
+                                        aFence));
+}
+
+bool
+ImageBridgeParent::RecvChildAsyncMessages(const InfallibleTArray<AsyncChildMessageData>& aMessages)
+{
+  for (AsyncChildMessageArray::index_type i = 0; i < aMessages.Length(); ++i) {
+    const AsyncChildMessageData& message = aMessages[i];
+
+    switch (message.type()) {
+      case AsyncChildMessageData::TOpReplyDeliverFence: {
+        const OpReplyDeliverFence& op = message.get_OpReplyDeliverFence();
+        TransactionCompleteted(op.transactionId());
+        break;
+      }
+      default:
+        NS_ERROR("unknown AsyncChildMessageData type");
+        return false;
+    }
+  }
+  return true;
+}
+
 MessageLoop * ImageBridgeParent::GetMessageLoop() {
   return mMessageLoop;
 }
 
 class ReleaseRunnable : public nsRunnable
 {
 public:
   ReleaseRunnable(ImageBridgeParent* aRef)
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -37,41 +37,50 @@ namespace layers {
  * interesting stuff is in ImageContainerParent.
  */
 class ImageBridgeParent : public PImageBridgeParent,
                           public CompositableParentManager
 {
 public:
   typedef InfallibleTArray<CompositableOperation> EditArray;
   typedef InfallibleTArray<EditReply> EditReplyArray;
+  typedef InfallibleTArray<AsyncChildMessageData> AsyncChildMessageArray;
 
   ImageBridgeParent(MessageLoop* aLoop, Transport* aTransport);
   ~ImageBridgeParent();
 
   virtual LayersBackend GetCompositorBackendType() const MOZ_OVERRIDE;
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
   static PImageBridgeParent*
   Create(Transport* aTransport, ProcessId aOtherProcess);
 
+  // CompositableParentManager
+  virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
+                               PTextureParent* aTexture,
+                               const FenceHandle& aFence) MOZ_OVERRIDE;
+
   // PImageBridge
   virtual bool RecvUpdate(const EditArray& aEdits, EditReplyArray* aReply) MOZ_OVERRIDE;
   virtual bool RecvUpdateNoSwap(const EditArray& aEdits) MOZ_OVERRIDE;
 
   virtual bool IsAsync() const MOZ_OVERRIDE { return true; }
 
   PCompositableParent* AllocPCompositableParent(const TextureInfo& aInfo,
                                                 uint64_t*) MOZ_OVERRIDE;
   bool DeallocPCompositableParent(PCompositableParent* aActor) MOZ_OVERRIDE;
 
   virtual PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
                                               const TextureFlags& aFlags) MOZ_OVERRIDE;
   virtual bool DeallocPTextureParent(PTextureParent* actor) MOZ_OVERRIDE;
 
+  virtual bool
+  RecvChildAsyncMessages(const InfallibleTArray<AsyncChildMessageData>& aMessages) MOZ_OVERRIDE;
+
   bool RecvStop() MOZ_OVERRIDE;
 
   MessageLoop * GetMessageLoop();
 
 
   // ISurfaceAllocator
 
   bool AllocShmem(size_t aSize,
--- a/gfx/layers/ipc/LayerTransactionChild.cpp
+++ b/gfx/layers/ipc/LayerTransactionChild.cpp
@@ -4,16 +4,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "LayerTransactionChild.h"
 #include "mozilla/layers/CompositableClient.h"  // for CompositableChild
 #include "mozilla/layers/PCompositableChild.h"  // for PCompositableChild
 #include "mozilla/layers/PLayerChild.h"  // for PLayerChild
+#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 {
 
@@ -50,16 +51,46 @@ LayerTransactionChild::AllocPCompositabl
 }
 
 bool
 LayerTransactionChild::DeallocPCompositableChild(PCompositableChild* actor)
 {
   return CompositableClient::DestroyIPDLActor(actor);
 }
 
+bool
+LayerTransactionChild::RecvParentAsyncMessage(const mozilla::layers::AsyncParentMessageData& aMessage)
+{
+  switch (aMessage.type()) {
+    case AsyncParentMessageData::TOpDeliverFence: {
+      const OpDeliverFence& op = aMessage.get_OpDeliverFence();
+      FenceHandle fence = op.fence();
+      PTextureChild* child = op.textureChild();
+
+      RefPtr<TextureClient> texture = TextureClient::AsTextureClient(child);
+      if (texture) {
+        texture->SetReleaseFenceHandle(fence);
+      }
+      if (mForwarder) {
+        mForwarder->HoldTransactionsToRespond(op.transactionId());
+      } else {
+        // Send back a response.
+        InfallibleTArray<AsyncChildMessageData> replies;
+        replies.AppendElement(OpReplyDeliverFence(op.transactionId()));
+        SendChildAsyncMessages(replies);
+      }
+      break;
+    }
+    default:
+      NS_ERROR("unknown AsyncParentMessageData type");
+      return false;
+  }
+  return true;
+}
+
 void
 LayerTransactionChild::ActorDestroy(ActorDestroyReason why)
 {
 #ifdef MOZ_B2G
   // Due to poor lifetime management of gralloc (and possibly shmems) we will
   // crash at some point in the future when we get destroyed due to abnormal
   // shutdown. Its better just to crash here. On desktop though, we have a chance
   // of recovering.
--- a/gfx/layers/ipc/LayerTransactionChild.h
+++ b/gfx/layers/ipc/LayerTransactionChild.h
@@ -13,16 +13,17 @@
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/layers/PLayerTransactionChild.h"
 #include "mozilla/RefPtr.h"
 
 namespace mozilla {
 
 namespace layout {
 class RenderFrameChild;
+class ShadowLayerForwarder;
 }
 
 namespace layers {
 
 class LayerTransactionChild : public PLayerTransactionChild
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LayerTransactionChild)
@@ -32,46 +33,55 @@ public:
    * It is expected (checked with an assert) that all shadow layers
    * created by this have already been destroyed and
    * Send__delete__()d by the time this method is called.
    */
   void Destroy();
 
   bool IPCOpen() const { return mIPCOpen; }
 
+  void SetForwarder(ShadowLayerForwarder* aForwarder)
+  {
+    mForwarder = aForwarder;
+  }
+
 protected:
   LayerTransactionChild()
     : mIPCOpen(false)
   {}
   ~LayerTransactionChild() { }
 
   virtual PLayerChild* AllocPLayerChild() MOZ_OVERRIDE;
   virtual bool DeallocPLayerChild(PLayerChild* actor) MOZ_OVERRIDE;
 
   virtual PCompositableChild* AllocPCompositableChild(const TextureInfo& aInfo) MOZ_OVERRIDE;
   virtual bool DeallocPCompositableChild(PCompositableChild* actor) MOZ_OVERRIDE;
 
   virtual PTextureChild* AllocPTextureChild(const SurfaceDescriptor& aSharedData,
                                             const TextureFlags& aFlags) MOZ_OVERRIDE;
   virtual bool DeallocPTextureChild(PTextureChild* actor) MOZ_OVERRIDE;
 
+  virtual bool
+  RecvParentAsyncMessage(const mozilla::layers::AsyncParentMessageData& aMessage) MOZ_OVERRIDE;
+
   virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 
   void AddIPDLReference() {
     MOZ_ASSERT(mIPCOpen == false);
     mIPCOpen = true;
     AddRef();
   }
   void ReleaseIPDLReference() {
     MOZ_ASSERT(mIPCOpen == true);
     mIPCOpen = false;
     Release();
   }
   friend class CompositorChild;
   friend class layout::RenderFrameChild;
 
   bool mIPCOpen;
+  ShadowLayerForwarder* mForwarder;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // MOZILLA_LAYERS_LAYERTRANSACTIONCHILD_H
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -24,16 +24,17 @@
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayersMessages.h"  // for EditReply, etc
 #include "mozilla/layers/LayersSurfaces.h"  // for PGrallocBufferParent
 #include "mozilla/layers/LayersTypes.h"  // for MOZ_LAYERS_LOG
 #include "mozilla/layers/PCompositableParent.h"
 #include "mozilla/layers/PLayerParent.h"  // for PLayerParent
 #include "mozilla/layers/ThebesLayerComposite.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
 #include "nsLayoutUtils.h"              // for nsLayoutUtils
 #include "nsMathUtils.h"                // for NS_round
 #include "nsPoint.h"                    // for nsPoint
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl, etc
@@ -169,23 +170,16 @@ LayerTransactionParent::Destroy()
 }
 
 LayersBackend
 LayerTransactionParent::GetCompositorBackendType() const
 {
   return mLayerManager->GetBackendType();
 }
 
-/* virtual */
-void
-LayerTransactionParent::ActorDestroy(ActorDestroyReason aWhy)
-{
-  // Implement me! Bug 1005171
-}
-
 bool
 LayerTransactionParent::RecvUpdateNoSwap(const InfallibleTArray<Edit>& cset,
                                          const TargetConfig& targetConfig,
                                          const bool& isFirstPaint,
                                          const bool& scheduleComposite)
 {
   return RecvUpdate(cset, targetConfig, isFirstPaint, scheduleComposite, nullptr);
 }
@@ -779,15 +773,52 @@ LayerTransactionParent::AllocPTexturePar
 }
 
 bool
 LayerTransactionParent::DeallocPTextureParent(PTextureParent* actor)
 {
   return TextureHost::DestroyIPDLActor(actor);
 }
 
+bool
+LayerTransactionParent::RecvChildAsyncMessages(const InfallibleTArray<AsyncChildMessageData>& aMessages)
+{
+  for (AsyncChildMessageArray::index_type i = 0; i < aMessages.Length(); ++i) {
+    const AsyncChildMessageData& message = aMessages[i];
+
+    switch (message.type()) {
+      case AsyncChildMessageData::TOpReplyDeliverFence: {
+        const OpReplyDeliverFence& op = message.get_OpReplyDeliverFence();
+        TransactionCompleteted(op.transactionId());
+        break;
+      }
+      default:
+        NS_ERROR("unknown AsyncChildMessageData type");
+        return false;
+    }
+  }
+  return true;
+}
+
+void
+LayerTransactionParent::ActorDestroy(ActorDestroyReason why)
+{
+  DestroyAsyncTransactionTrackersHolder();
+}
+
 bool LayerTransactionParent::IsSameProcess() const
 {
   return OtherProcess() == ipc::kInvalidProcessHandle;
 }
 
+void
+LayerTransactionParent::SendFenceHandle(AsyncTransactionTracker* aTracker,
+                                        PTextureParent* aTexture,
+                                        const FenceHandle& aFence)
+{
+  HoldUntilComplete(aTracker);
+  mozilla::unused << SendParentAsyncMessage(OpDeliverFence(aTracker->GetId(),
+                                        aTexture, nullptr,
+                                        aFence));
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/LayerTransactionParent.h
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -38,16 +38,17 @@ class CompositableParent;
 class ShadowLayersManager;
 
 class LayerTransactionParent : public PLayerTransactionParent,
                                public CompositableParentManager
 {
   typedef mozilla::layout::RenderFrameParent RenderFrameParent;
   typedef InfallibleTArray<Edit> EditArray;
   typedef InfallibleTArray<EditReply> EditReplyArray;
+  typedef InfallibleTArray<AsyncChildMessageData> AsyncChildMessageArray;
 
 public:
   LayerTransactionParent(LayerManagerComposite* aManager,
                          ShadowLayersManager* aLayersManager,
                          uint64_t aId);
   ~LayerTransactionParent();
 
   void Destroy();
@@ -74,19 +75,21 @@ public:
   {
     PLayerTransactionParent::DeallocShmem(aShmem);
   }
 
   virtual LayersBackend GetCompositorBackendType() const MOZ_OVERRIDE;
 
   virtual bool IsSameProcess() const MOZ_OVERRIDE;
 
+  // CompositableParentManager
+  virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
+                               PTextureParent* aTexture,
+                               const FenceHandle& aFence) MOZ_OVERRIDE;
 protected:
-  virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
-
   virtual bool RecvUpdate(const EditArray& cset,
                           const TargetConfig& targetConfig,
                           const bool& isFirstPaint,
                           const bool& scheduleComposite,
                           EditReplyArray* reply) MOZ_OVERRIDE;
 
   virtual bool RecvUpdateNoSwap(const EditArray& cset,
                                 const TargetConfig& targetConfig,
@@ -110,16 +113,21 @@ protected:
 
   virtual PCompositableParent* AllocPCompositableParent(const TextureInfo& aInfo) MOZ_OVERRIDE;
   virtual bool DeallocPCompositableParent(PCompositableParent* actor) MOZ_OVERRIDE;
 
   virtual PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
                                               const TextureFlags& aFlags) MOZ_OVERRIDE;
   virtual bool DeallocPTextureParent(PTextureParent* actor) MOZ_OVERRIDE;
 
+  virtual bool
+  RecvChildAsyncMessages(const InfallibleTArray<AsyncChildMessageData>& aMessages) MOZ_OVERRIDE;
+
+  virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
+
   bool Attach(ShadowLayerParent* aLayerParent,
               CompositableHost* aCompositable,
               bool aIsAsyncVideo);
 
   void AddIPDLReference() {
     MOZ_ASSERT(mIPCOpen == false);
     mIPCOpen = true;
     AddRef();
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -352,16 +352,26 @@ union MaybeRegion {
 };
 
 struct OpUpdateTexture {
   PCompositable compositable;
   PTexture texture;
   MaybeRegion region;
 };
 
+struct OpDeliverFence {
+  uint64_t transactionId;
+  PTexture texture;
+  FenceHandle fence;
+};
+
+struct OpReplyDeliverFence {
+  uint64_t transactionId;
+};
+
 union CompositableOperation {
   OpUpdatePictureRect;
 
   OpCreatedIncrementalTexture;
 
   OpPaintTextureRegion;
   OpPaintTextureIncremental;
 
@@ -423,10 +433,18 @@ struct ReturnReleaseFence {
 // only to be used for buffer swapping.
 union EditReply {
   OpContentBufferSwap;
   OpTextureSwap;
 
   ReturnReleaseFence;
 };
 
+union AsyncParentMessageData {
+  OpDeliverFence;
+};
+
+union AsyncChildMessageData {
+  OpReplyDeliverFence;
+};
+
 } // namespace
 } // namespace
--- a/gfx/layers/ipc/PImageBridge.ipdl
+++ b/gfx/layers/ipc/PImageBridge.ipdl
@@ -23,30 +23,35 @@ namespace layers {
  * frames directly to the compositor thread/process without relying on the main thread
  * which might be too busy dealing with content script.
  */
 intr protocol PImageBridge
 {
   manages PCompositable;
   manages PTexture;
 
+child:
+  async ParentAsyncMessage(AsyncParentMessageData aMessage);
+
 parent:
 
   sync Update(CompositableOperation[] ops) returns (EditReply[] reply);
   async UpdateNoSwap(CompositableOperation[] ops);
 
   // First step of the destruction sequence. This puts all the ImageContainerParents
   // in a state in which they can't send asynchronous messages to their child
   // counterpart so as to not race with the upcomming __delete__ message.
   // In the child side, the __delete__ messages are not sent right after Stop,
   // they are scheduled in the ImageBridgeChild's message queue in order to ensure
   // that all the messages from the parent side have been received and processed
   // before sending __delete__.
   sync Stop();
 
   sync PCompositable(TextureInfo aInfo) returns (uint64_t id);
   async PTexture(SurfaceDescriptor aSharedData, TextureFlags aTextureFlags);
+
+  async ChildAsyncMessages(AsyncChildMessageData[] aMessages);
 };
 
 
 } // namespace
 } // namespace
 
--- a/gfx/layers/ipc/PLayerTransaction.ipdl
+++ b/gfx/layers/ipc/PLayerTransaction.ipdl
@@ -36,16 +36,19 @@ union MaybeTransform {
 };
 
 sync protocol PLayerTransaction {
   manager PRenderFrame or PCompositor;
   manages PLayer;
   manages PCompositable;
   manages PTexture;
 
+child:
+  async ParentAsyncMessage(AsyncParentMessageData aMessage);
+
 parent:
   async PLayer();
   async PCompositable(TextureInfo aTextureInfo);
   async PTexture(SurfaceDescriptor aSharedData, TextureFlags aTextureFlags);
 
   // The isFirstPaint flag can be used to indicate that this is the first update
   // for a particular document.
   sync Update(Edit[] cset, TargetConfig targetConfig, bool isFirstPaint, bool scheduleComposite)
@@ -75,17 +78,19 @@ parent:
 
   // We don't need to send a sync transaction if
   // no transaction operate require a swap.
   async UpdateNoSwap(Edit[] cset, TargetConfig targetConfig, bool isFirstPaint, bool scheduleComposite);
 
   // Drop any front buffers that might be retained on the compositor
   // side.
   async ClearCachedResources();
-  
+
   // Schedule a composite if one isn't already scheduled.
   async ForceComposite();
 
+  async ChildAsyncMessages(AsyncChildMessageData[] aMessages);
+
   async __delete__();
 };
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/PTexture.ipdl
+++ b/gfx/layers/ipc/PTexture.ipdl
@@ -6,36 +6,30 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include LayersSurfaces;
 include protocol PLayerTransaction;
 include protocol PImageBridge;
 include "mozilla/GfxMessageUtils.h";
 
 using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
-using struct mozilla::layers::FenceHandle from "mozilla/layers/FenceUtils.h";
 
 namespace mozilla {
 namespace layers {
 
-union MaybeFenceHandle {
-  FenceHandle;
-  null_t;
-};
-
 /**
  * PTexture is the IPDL glue between a TextureClient and a TextureHost.
  */
 sync protocol PTexture {
     manager PImageBridge or PLayerTransaction;
 
 child:
     async __delete__();
 
-    async CompositorRecycle(MaybeFenceHandle aFence);
+    async CompositorRecycle();
 
 parent:
 
     async ClientRecycle();
 
     /**
      * Asynchronously tell the Compositor side to remove the texture.
      */
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -172,16 +172,19 @@ ShadowLayerForwarder::ShadowLayerForward
 {
   mTxn = new Transaction();
 }
 
 ShadowLayerForwarder::~ShadowLayerForwarder()
 {
   NS_ABORT_IF_FALSE(mTxn->Finished(), "unfinished transaction?");
   delete mTxn;
+  if (mShadowManager) {
+    mShadowManager->SetForwarder(nullptr);
+  }
 }
 
 void
 ShadowLayerForwarder::BeginTransaction(const nsIntRect& aTargetBounds,
                                        ScreenRotation aRotation,
                                        const nsIntRect& aClientBounds,
                                        ScreenOrientation aOrientation)
 {
@@ -567,37 +570,40 @@ ShadowLayerForwarder::EndTransaction(Inf
 }
 
 bool
 ShadowLayerForwarder::AllocShmem(size_t aSize,
                                  ipc::SharedMemory::SharedMemoryType aType,
                                  ipc::Shmem* aShmem)
 {
   NS_ABORT_IF_FALSE(HasShadowManager(), "no shadow manager");
-  if (!mShadowManager->IPCOpen()) {
+  if (!HasShadowManager() ||
+      !mShadowManager->IPCOpen()) {
     return false;
   }
   return mShadowManager->AllocShmem(aSize, aType, aShmem);
 }
 bool
 ShadowLayerForwarder::AllocUnsafeShmem(size_t aSize,
                                           ipc::SharedMemory::SharedMemoryType aType,
                                           ipc::Shmem* aShmem)
 {
   NS_ABORT_IF_FALSE(HasShadowManager(), "no shadow manager");
-  if (!mShadowManager->IPCOpen()) {
+  if (!HasShadowManager() ||
+      !mShadowManager->IPCOpen()) {
     return false;
   }
   return mShadowManager->AllocUnsafeShmem(aSize, aType, aShmem);
 }
 void
 ShadowLayerForwarder::DeallocShmem(ipc::Shmem& aShmem)
 {
   NS_ABORT_IF_FALSE(HasShadowManager(), "no shadow manager");
-  if (!mShadowManager->IPCOpen()) {
+  if (!HasShadowManager() ||
+      !mShadowManager->IPCOpen()) {
     return;
   }
   mShadowManager->DeallocShmem(aShmem);
 }
 
 bool
 ShadowLayerForwarder::IPCOpen() const
 {
@@ -617,17 +623,18 @@ ShadowLayerForwarder::IsSameProcess() co
   * We bail out when we have no shadow manager. That can happen when the
   * layer manager is created by the preallocated process.
   * See bug 914843 for details.
   */
 PLayerChild*
 ShadowLayerForwarder::ConstructShadowFor(ShadowableLayer* aLayer)
 {
   NS_ABORT_IF_FALSE(HasShadowManager(), "no manager to forward to");
-  if (!mShadowManager->IPCOpen()) {
+  if (!HasShadowManager() ||
+      !mShadowManager->IPCOpen()) {
     return nullptr;
   }
   return mShadowManager->SendPLayerConstructor(new ShadowLayerChild(aLayer));
 }
 
 #if !defined(MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS)
 
 /*static*/ void
@@ -640,17 +647,18 @@ ShadowLayerForwarder::PlatformSyncBefore
 void
 ShadowLayerForwarder::Connect(CompositableClient* aCompositable)
 {
 #ifdef GFX_COMPOSITOR_LOGGING
   printf("ShadowLayerForwarder::Connect(Compositable)\n");
 #endif
   MOZ_ASSERT(aCompositable);
   MOZ_ASSERT(mShadowManager);
-  if (!mShadowManager->IPCOpen()) {
+  if (!HasShadowManager() ||
+      !mShadowManager->IPCOpen()) {
     return;
   }
   PCompositableChild* actor =
     mShadowManager->SendPCompositableConstructor(aCompositable->GetTextureInfo());
   MOZ_ASSERT(actor);
   aCompositable->InitIPDLActor(actor);
 }
 
@@ -682,23 +690,70 @@ void ShadowLayerForwarder::AttachAsyncCo
   mTxn->AddEdit(OpAttachAsyncCompositable(nullptr, Shadow(aLayer),
                                           aCompositableID));
 }
 
 PTextureChild*
 ShadowLayerForwarder::CreateTexture(const SurfaceDescriptor& aSharedData,
                                     TextureFlags aFlags)
 {
-  if (!mShadowManager->IPCOpen()) {
+  if (!HasShadowManager() ||
+      !mShadowManager->IPCOpen()) {
     return nullptr;
   }
   return mShadowManager->SendPTextureConstructor(aSharedData, aFlags);
 }
 
 
 void ShadowLayerForwarder::SetShadowManager(PLayerTransactionChild* aShadowManager)
 {
   mShadowManager = static_cast<LayerTransactionChild*>(aShadowManager);
+  mShadowManager->SetForwarder(this);
+}
+
+void ShadowLayerForwarder::StopReceiveAsyncParentMessge()
+{
+  if (!HasShadowManager() ||
+      !mShadowManager->IPCOpen()) {
+    return;
+  }
+  SendPendingAsyncMessge();
+  mShadowManager->SetForwarder(nullptr);
+}
+
+void ShadowLayerForwarder::ClearCachedResources()
+{
+  if (!HasShadowManager() ||
+      !mShadowManager->IPCOpen()) {
+    return;
+  }
+  SendPendingAsyncMessge();
+  mShadowManager->SendClearCachedResources();
 }
 
+void ShadowLayerForwarder::Composite()
+{
+  if (!HasShadowManager() ||
+      !mShadowManager->IPCOpen()) {
+    return;
+  }
+  mShadowManager->SendForceComposite();
+}
+
+void ShadowLayerForwarder::SendPendingAsyncMessge()
+{
+  if (!HasShadowManager() ||
+      !mShadowManager->IPCOpen() ||
+      mTransactionsToRespond.empty()) {
+    return;
+  }
+  // Send OpReplyDeliverFence messages
+  InfallibleTArray<AsyncChildMessageData> replies;
+  replies.SetCapacity(mTransactionsToRespond.size());
+  for (size_t i = 0; i < mTransactionsToRespond.size(); i++) {
+    replies.AppendElement(OpReplyDeliverFence(mTransactionsToRespond[i]));
+  }
+  mTransactionsToRespond.clear();
+  mShadowManager->SendChildAsyncMessages(replies);
+}
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -294,16 +294,24 @@ public:
                       bool aScheduleComposite,
                       bool* aSent);
 
   /**
    * Set an actor through which layer updates will be pushed.
    */
   void SetShadowManager(PLayerTransactionChild* aShadowManager);
 
+  void StopReceiveAsyncParentMessge();
+
+  void ClearCachedResources();
+
+  void Composite();
+
+  void SendPendingAsyncMessge();
+
   /**
    * True if this is forwarding to a LayerManagerComposite.
    */
   bool HasShadowManager() const { return !!mShadowManager; }
   LayerTransactionChild* GetShadowManager() const { return mShadowManager.get(); }
 
   virtual void WindowOverlayChanged() { mWindowOverlayChanged = true; }
 
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -130,16 +130,17 @@ EXPORTS.mozilla.layers += [
     'composite/LayerManagerComposite.h',
     'composite/TextureHost.h',
     'composite/ThebesLayerComposite.h',
     'Compositor.h',
     'CompositorTypes.h',
     'D3D9SurfaceImage.h',
     'Effects.h',
     'ImageDataSerializer.h',
+    'ipc/AsyncTransactionTracker.h',
     'ipc/CompositableForwarder.h',
     'ipc/CompositableTransactionParent.h',
     'ipc/CompositorChild.h',
     'ipc/CompositorParent.h',
     'ipc/FenceUtils.h',
     'ipc/ImageBridgeChild.h',
     'ipc/ImageBridgeParent.h',
     'ipc/ISurfaceAllocator.h',
@@ -268,16 +269,17 @@ UNIFIED_SOURCES += [
     'composite/TextureHost.cpp',
     'composite/ThebesLayerComposite.cpp',
     'composite/TiledContentHost.cpp',
     'Compositor.cpp',
     'CopyableCanvasLayer.cpp',
     'Effects.cpp',
     'ImageDataSerializer.cpp',
     'ImageLayers.cpp',
+    'ipc/AsyncTransactionTracker.cpp',
     'ipc/CompositableTransactionParent.cpp',
     'ipc/CompositorChild.cpp',
     'ipc/CompositorParent.cpp',
     'ipc/ImageBridgeChild.cpp',
     'ipc/ImageBridgeParent.cpp',
     'ipc/ISurfaceAllocator.cpp',
     'ipc/LayerTransactionChild.cpp',
     'ipc/LayerTransactionParent.cpp',
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2,16 +2,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG /* Allow logging in the release build */
 #endif
 
+#include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTracker
 #include "mozilla/layers/CompositorChild.h"
 #include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/SharedBufferManagerChild.h"
 #include "mozilla/layers/ISurfaceAllocator.h"     // for GfxMemoryImageReporter
 
 #include "prlog.h"
 
@@ -330,16 +331,18 @@ gfxPlatform::Init()
     }
     gEverInitialized = true;
 
     // Initialize the preferences by creating the singleton.
     gfxPrefs::GetSingleton();
 
     gGfxPlatformPrefsLock = new Mutex("gfxPlatform::gGfxPlatformPrefsLock");
 
+    AsyncTransactionTracker::Initialize();
+
     /* Initialize the GfxInfo service.
      * Note: we can't call functions on GfxInfo that depend
      * on gPlatform until after it has been initialized
      * below. GfxInfo initialization annotates our
      * crash reports so we want to do it before
      * we try to load any drivers and do device detection
      * incase that code crashes. See bug #591561. */
     nsCOMPtr<nsIGfxInfo> gfxInfo;
@@ -500,16 +503,18 @@ gfxPlatform::Shutdown()
     // This will block this thread untill the ImageBridge protocol is completely
     // deleted.
     ImageBridgeChild::ShutDown();
 #ifdef MOZ_WIDGET_GONK
     SharedBufferManagerChild::ShutDown();
 #endif
     CompositorParent::ShutDown();
 
+    AsyncTransactionTracker::Finalize();
+
     delete gGfxPlatformPrefsLock;
 
     gfxPrefs::DestroySingleton();
     gfxFont::DestroySingletons();
 
     delete gPlatform;
     gPlatform = nullptr;
 }