Bug 1001417 - Forward fence objects in SharedSurfaceGralloc to Compositor r=jgilbert,nical
authorSotaro Ikeda <sikeda@mozilla.com>
Sun, 08 Jun 2014 06:18:53 -0700
changeset 206720 229dc47b5059d1feb9a32af179e0141616a482a7
parent 206719 14563aa75f9cad6ef06bd077ac113877095774b4
child 206721 1159503d1f38f745a105b7484f70104021d193a6
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)
reviewersjgilbert, nical
bugs1001417
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 1001417 - Forward fence objects in SharedSurfaceGralloc to Compositor r=jgilbert,nical
gfx/gl/GLLibraryEGL.cpp
gfx/gl/GLLibraryEGL.h
gfx/gl/SharedSurfaceGralloc.cpp
gfx/layers/client/CanvasClient.cpp
gfx/layers/client/CompositableClient.cpp
gfx/layers/client/CompositableClient.h
gfx/layers/client/TextureClient.h
gfx/layers/ipc/AsyncTransactionTracker.cpp
gfx/layers/ipc/CompositableForwarder.h
gfx/layers/ipc/FenceUtils.h
gfx/layers/ipc/FenceUtilsGonk.cpp
gfx/layers/ipc/FenceUtilsGonk.h
gfx/layers/ipc/ImageBridgeChild.cpp
gfx/layers/ipc/ImageBridgeChild.h
gfx/layers/ipc/ImageBridgeParent.cpp
gfx/layers/ipc/LayerTransactionChild.cpp
gfx/layers/ipc/LayerTransactionChild.h
gfx/layers/ipc/LayerTransactionParent.cpp
gfx/layers/ipc/LayersMessages.ipdlh
gfx/layers/ipc/PImageBridge.ipdl
gfx/layers/ipc/PLayerTransaction.ipdl
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/ShadowLayers.h
gfx/layers/opengl/GrallocTextureClient.cpp
gfx/layers/opengl/GrallocTextureClient.h
gfx/layers/opengl/GrallocTextureHost.cpp
gfx/layers/opengl/GrallocTextureHost.h
gfx/layers/opengl/TextureHostOGL.cpp
gfx/layers/opengl/TextureHostOGL.h
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -328,16 +328,34 @@ GLLibraryEGL::EnsureInitialized()
 
             mSymbols.fCreateImage = nullptr;
             mSymbols.fDestroyImage = nullptr;
         }
     } else {
         MarkExtensionUnsupported(KHR_image_pixmap);
     }
 
+    if (IsExtensionSupported(ANDROID_native_fence_sync)) {
+        GLLibraryLoader::SymLoadStruct nativeFenceSymbols[] = {
+            { (PRFuncPtr*) &mSymbols.fDupNativeFenceFDANDROID, { "eglDupNativeFenceFDANDROID", nullptr } },
+            { nullptr, { nullptr } }
+        };
+
+        bool success = GLLibraryLoader::LoadSymbols(mEGLLibrary,
+                                                    &nativeFenceSymbols[0],
+                                                    lookupFunction);
+        if (!success) {
+            NS_ERROR("EGL supports ANDROID_native_fence_sync without exposing its functions!");
+
+            MarkExtensionUnsupported(ANDROID_native_fence_sync);
+
+            mSymbols.fDupNativeFenceFDANDROID = nullptr;
+        }
+    }
+
     mInitialized = true;
     reporter.SetSuccessful();
     return true;
 }
 
 void
 GLLibraryEGL::InitExtensions()
 {
--- a/gfx/gl/GLLibraryEGL.h
+++ b/gfx/gl/GLLibraryEGL.h
@@ -407,16 +407,24 @@ public:
     EGLBoolean fGetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLint *value)
     {
         BEFORE_GL_CALL;
         EGLBoolean b = mSymbols.fGetSyncAttrib(dpy, sync, attribute, value);
         AFTER_GL_CALL;
         return b;
     }
 
+    EGLint fDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSync sync)
+    {
+        MOZ_ASSERT(mSymbols.fDupNativeFenceFDANDROID);
+        BEFORE_GL_CALL;
+        EGLint ret = mSymbols.fDupNativeFenceFDANDROID(dpy, sync);
+        AFTER_GL_CALL;
+        return ret;
+    }
 
     EGLDisplay Display() {
         return mEGLDisplay;
     }
 
     bool IsANGLE() const {
         return mIsANGLE;
     }
@@ -517,16 +525,18 @@ public:
         typedef EGLSync (GLAPIENTRY * pfnCreateSync)(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
         pfnCreateSync fCreateSync;
         typedef EGLBoolean (GLAPIENTRY * pfnDestroySync)(EGLDisplay dpy, EGLSync sync);
         pfnDestroySync fDestroySync;
         typedef EGLint (GLAPIENTRY * pfnClientWaitSync)(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);
         pfnClientWaitSync fClientWaitSync;
         typedef EGLBoolean (GLAPIENTRY * pfnGetSyncAttrib)(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLint *value);
         pfnGetSyncAttrib fGetSyncAttrib;
+        typedef EGLint (GLAPIENTRY * pfnDupNativeFenceFDANDROID)(EGLDisplay dpy, EGLSync sync);
+        pfnDupNativeFenceFDANDROID fDupNativeFenceFDANDROID;
     } mSymbols;
 
 #ifdef DEBUG
     static void BeforeGLCall(const char* glFunction);
     static void AfterGLCall(const char* glFunction);
 #endif
 
 #ifdef MOZ_B2G
--- a/gfx/gl/SharedSurfaceGralloc.cpp
+++ b/gfx/gl/SharedSurfaceGralloc.cpp
@@ -148,21 +148,34 @@ SharedSurface_Gralloc::Fence()
         mSync = 0;
     }
 
     // When Android native fences are available, try
     // them first since they're more likely to work.
     // Android native fences are also likely to perform better.
     if (mEGL->IsExtensionSupported(GLLibraryEGL::ANDROID_native_fence_sync)) {
         mGL->MakeCurrent();
-        mSync = mEGL->fCreateSync(mEGL->Display(),
-                                  LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID,
-                                  nullptr);
-        if (mSync) {
+        EGLSync sync = mEGL->fCreateSync(mEGL->Display(),
+                                         LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID,
+                                         nullptr);
+        if (sync) {
             mGL->fFlush();
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+            int fenceFd = mEGL->fDupNativeFenceFDANDROID(mEGL->Display(), sync);
+            if (fenceFd != -1) {
+                mEGL->fDestroySync(mEGL->Display(), sync);
+                android::sp<android::Fence> fence(new android::Fence(fenceFd));
+                FenceHandle handle = FenceHandle(fence);
+                mTextureClient->SetAcquireFenceHandle(handle);
+            } else {
+                mSync = sync;
+            }
+#else
+            mSync = sync;
+#endif
             return;
         }
     }
 
     if (mEGL->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync)) {
         mGL->MakeCurrent();
         mSync = mEGL->fCreateSync(mEGL->Display(),
                                   LOCAL_EGL_SYNC_FENCE,
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -166,17 +166,17 @@ CanvasClientSurfaceStream::Update(gfx::I
 
     // If IPDLActor is null means this TextureClient didn't AddTextureClient yet
     if (!grallocTextureClient->GetIPDLActor()) {
       grallocTextureClient->SetTextureFlags(mTextureInfo.mTextureFlags);
       AddTextureClient(grallocTextureClient);
     }
 
     if (grallocTextureClient->GetIPDLActor()) {
-      GetForwarder()->UseTexture(this, grallocTextureClient);
+      UseTexture(grallocTextureClient);
     }
 
     if (mBuffer && CompositorChild::ChildProcessHasCompositor()) {
       // remove old buffer from CompositableHost
       RefPtr<AsyncTransactionTracker> tracker = new RemoveTextureFromCompositableTracker();
       // Hold TextureClient until transaction complete.
       tracker->SetTextureClient(mBuffer);
       mBuffer->SetRemoveFromCompositableTracker(tracker);
--- a/gfx/layers/client/CompositableClient.cpp
+++ b/gfx/layers/client/CompositableClient.cpp
@@ -198,15 +198,33 @@ CompositableClient::AddTextureClient(Tex
 }
 
 void
 CompositableClient::OnTransaction()
 {
 }
 
 void
+CompositableClient::UseTexture(TextureClient* aTexture)
+{
+  MOZ_ASSERT(aTexture);
+  if (!aTexture) {
+    return;
+  }
+
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+  FenceHandle handle = aTexture->GetAcquireFenceHandle();
+  if (handle.IsValid()) {
+    RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(handle);
+    mForwarder->SendFenceHandle(tracker, aTexture->GetIPDLActor(), handle);
+  }
+#endif
+  mForwarder->UseTexture(this, aTexture);
+}
+
+void
 CompositableClient::RemoveTexture(TextureClient* aTexture)
 {
   mForwarder->RemoveTextureFromCompositable(this, aTexture);
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/client/CompositableClient.h
+++ b/gfx/layers/client/CompositableClient.h
@@ -184,16 +184,18 @@ public:
   virtual void OnDetach() {}
 
   /**
    * Clear any resources that are not immediately necessary. This may be called
    * in low-memory conditions.
    */
   virtual void ClearCachedResources() {}
 
+  virtual void UseTexture(TextureClient* aTexture);
+
   /**
    * Should be called when deataching a TextureClient from a Compositable, because
    * some platforms need to do some extra book keeping when this happens (for
    * example to properly keep track of fences on Gonk).
    *
    * See AutoRemoveTexture to automatically invoke this at the end of a scope.
    */
   virtual void RemoveTexture(TextureClient* aTexture);
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -286,23 +286,36 @@ public:
    * Triggers the destruction of the shared data and the corresponding TextureHost.
    *
    * If the texture flags contain TextureFlags::DEALLOCATE_CLIENT, the destruction
    * will be synchronously coordinated with the compositor side, otherwise it
    * will be done asynchronously.
    */
   void ForceRemove();
 
-  virtual void SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle) {}
+  virtual void SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle)
+  {
+    mReleaseFenceHandle = aReleaseFenceHandle;
+  }
 
   const FenceHandle& GetReleaseFenceHandle() const
   {
     return mReleaseFenceHandle;
   }
 
+  virtual void SetAcquireFenceHandle(FenceHandle aAcquireFenceHandle)
+  {
+    mAcquireFenceHandle = aAcquireFenceHandle;
+  }
+
+  const FenceHandle& GetAcquireFenceHandle() const
+  {
+    return mAcquireFenceHandle;
+  }
+
   /**
    * Set AsyncTransactionTracker of RemoveTextureFromCompositableAsync() transaction.
    */
   virtual void SetRemoveFromCompositableTracker(AsyncTransactionTracker* aTracker) {}
 
   /**
    * This function waits until the buffer is no longer being used.
    */
@@ -342,16 +355,17 @@ protected:
     mFlags |= aFlags;
   }
 
   RefPtr<TextureChild> mActor;
   TextureFlags mFlags;
   bool mShared;
   bool mValid;
   FenceHandle mReleaseFenceHandle;
+  FenceHandle mAcquireFenceHandle;
 
   friend class TextureChild;
   friend void TestTextureClientSurface(TextureClient*, gfxImageSurface*);
   friend void TestTextureClientYCbCr(TextureClient*, PlanarYCbCrData&);
 };
 
 /**
  * TextureClient that wraps a random access buffer such as a Shmem or raw memory.
old mode 100644
new mode 100755
--- a/gfx/layers/ipc/AsyncTransactionTracker.cpp
+++ b/gfx/layers/ipc/AsyncTransactionTracker.cpp
@@ -84,19 +84,23 @@ AsyncTransactionTrackersHolder::AsyncTra
 
 AsyncTransactionTrackersHolder::~AsyncTransactionTrackersHolder()
 {
   if (!mIsTrackersHolderDestroyed) {
     DestroyAsyncTransactionTrackersHolder();
   }
 
   {
-    MOZ_ASSERT(sHolderLock);
-    MutexAutoLock lock(*sHolderLock);
+    if (sHolderLock) {
+      sHolderLock->Lock();
+    }
     sTrackersHolders.erase(mSerial);
+    if (sHolderLock) {
+      sHolderLock->Unlock();
+    }
   }
   MOZ_COUNT_DTOR(AsyncTransactionTrackersHolder);
 }
 
 void
 AsyncTransactionTrackersHolder::HoldUntilComplete(AsyncTransactionTracker* aTransactionTracker)
 {
   if (!aTransactionTracker) {
@@ -165,23 +169,28 @@ AsyncTransactionTrackersHolder::SetRelea
     return;
   }
   holder->SetReleaseFenceHandle(aReleaseFenceHandle, aTransactionId);
 }
 
 void
 AsyncTransactionTrackersHolder::ClearAllAsyncTransactionTrackers()
 {
-  MutexAutoLock lock(*sHolderLock);
+  if (sHolderLock) {
+    sHolderLock->Lock();
+  }
   std::map<uint64_t, RefPtr<AsyncTransactionTracker> >::iterator it;
   for (it = mAsyncTransactionTrackeres.begin();
        it != mAsyncTransactionTrackeres.end(); it++) {
     it->second->NotifyCancel();
   }
   mAsyncTransactionTrackeres.clear();
+  if (sHolderLock) {
+    sHolderLock->Unlock();
+  }
 }
 
 void
 AsyncTransactionTrackersHolder::DestroyAsyncTransactionTrackersHolder() {
   mIsTrackersHolderDestroyed = true;
   ClearAllAsyncTransactionTrackers();
 }
 
--- a/gfx/layers/ipc/CompositableForwarder.h
+++ b/gfx/layers/ipc/CompositableForwarder.h
@@ -179,16 +179,21 @@ public:
   /**
    * Tell the compositor side that the shared data has been modified so that
    * it can react accordingly (upload textures, etc.).
    */
   virtual void UpdatedTexture(CompositableClient* aCompositable,
                               TextureClient* aTexture,
                               nsIntRegion* aRegion) = 0;
 
+
+  virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
+                               PTextureChild* aTexture,
+                               const FenceHandle& aFence) = 0;
+
   void IdentifyTextureHost(const TextureFactoryIdentifier& aIdentifier);
 
   virtual int32_t GetMaxTextureSize() const MOZ_OVERRIDE
   {
     return mTextureFactoryIdentifier.mMaxTextureSize;
   }
 
   bool IsOnCompositorSide() const MOZ_OVERRIDE { return false; }
--- a/gfx/layers/ipc/FenceUtils.h
+++ b/gfx/layers/ipc/FenceUtils.h
@@ -13,31 +13,52 @@
 /**
  * FenceHandle is used for delivering Fence object via ipc.
  */
 #if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
 # include "mozilla/layers/FenceUtilsGonk.h"
 #else
 namespace mozilla {
 namespace layers {
+
+struct FenceHandleFromChild;
+
 struct FenceHandle {
+  FenceHandle() {}
+  FenceHandle(const FenceHandleFromChild& aFenceHandle) {}
   bool operator==(const FenceHandle&) const { return false; }
   bool IsValid() const { return false; }
 };
+
+struct FenceHandleFromChild {
+  FenceHandleFromChild() {}
+  FenceHandleFromChild(const FenceHandle& aFence) {}
+  bool operator==(const FenceHandle&) const { return false; }
+  bool operator==(const FenceHandleFromChild&) const { return false; }
+  bool IsValid() const { return false; }
+};
+
 } // namespace layers
 } // namespace mozilla
 #endif // MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
 
 namespace IPC {
 
 #if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
 #else
 template <>
 struct ParamTraits<mozilla::layers::FenceHandle> {
   typedef mozilla::layers::FenceHandle paramType;
   static void Write(Message*, const paramType&) {}
   static bool Read(const Message*, void**, paramType*) { return false; }
 };
+
+template <>
+struct ParamTraits<mozilla::layers::FenceHandleFromChild> {
+  typedef mozilla::layers::FenceHandleFromChild paramType;
+  static void Write(Message*, const paramType&) {}
+  static bool Read(const Message*, void**, paramType*) { return false; }
+};
 #endif // MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
 
 } // namespace IPC
 
 #endif // IPC_FencerUtils_h
--- a/gfx/layers/ipc/FenceUtilsGonk.cpp
+++ b/gfx/layers/ipc/FenceUtilsGonk.cpp
@@ -104,20 +104,123 @@ ParamTraits<FenceHandle>::Read(const Mes
   if (NO_ERROR == flattenable->unflatten(data, nbytes, fds, nfds)) {
 #endif
     aResult->mFence = buffer;
     return true;
   }
   return false;
 }
 
+void
+ParamTraits<FenceHandleFromChild>::Write(Message* aMsg,
+                                         const paramType& aParam)
+{
+#if ANDROID_VERSION >= 19
+  sp<Fence> flattenable = aParam.mFence;
+#else
+  Flattenable *flattenable = aParam.mFence.get();
+#endif
+  size_t nbytes = flattenable->getFlattenedSize();
+  size_t nfds = flattenable->getFdCount();
+
+  char data[nbytes];
+  int fds[nfds];
+
+#if ANDROID_VERSION >= 19
+  // Make a copy of "data" and "fds" for flatten() to avoid casting problem
+  void *pdata = (void *)data;
+  int *pfds = fds;
+
+  flattenable->flatten(pdata, nbytes, pfds, nfds);
+
+  // In Kitkat, flatten() will change the value of nbytes and nfds, which dues
+  // to multiple parcelable object consumption. The actual size and fd count
+  // which returned by getFlattenedSize() and getFdCount() are not changed.
+  // So we change nbytes and nfds back by call corresponding calls.
+  nbytes = flattenable->getFlattenedSize();
+  nfds = flattenable->getFdCount();
+#else
+  flattenable->flatten(data, nbytes, fds, nfds);
+#endif
+  aMsg->WriteSize(nbytes);
+  aMsg->WriteSize(nfds);
+
+  aMsg->WriteBytes(data, nbytes);
+  for (size_t n = 0; n < nfds; ++n) {
+    // If the Fence was shared cross-process, SCM_RIGHTS does
+    // the right thing and dup's the fd.  If it's shared cross-thread,
+    // SCM_RIGHTS doesn't dup the fd.  That's surprising, but we just
+    // deal with it here.  NB: only the "default" (master) process can
+    // alloc gralloc buffers.
+    bool sameProcess = (XRE_GetProcessType() == GeckoProcessType_Default);
+    int dupFd = sameProcess ? dup(fds[n]) : fds[n];
+    //int dupFd = fds[n];
+
+    // These buffers can't die in transit because they're created
+    // synchonously and the parent-side buffer can only be dropped if
+    // there's a crash.
+    aMsg->WriteFileDescriptor(FileDescriptor(dupFd, false));
+  }
+}
+
+bool
+ParamTraits<FenceHandleFromChild>::Read(const Message* aMsg,
+                                        void** aIter, paramType* aResult)
+{
+  size_t nbytes;
+  size_t nfds;
+  const char* data;
+
+  if (!aMsg->ReadSize(aIter, &nbytes) ||
+      !aMsg->ReadSize(aIter, &nfds) ||
+      !aMsg->ReadBytes(aIter, &data, nbytes)) {
+    return false;
+  }
+
+  int fds[nfds];
+
+  for (size_t n = 0; n < nfds; ++n) {
+    FileDescriptor fd;
+    if (!aMsg->ReadFileDescriptor(aIter, &fd)) {
+      return false;
+    }
+    fds[n] = fd.fd;
+  }
+
+  sp<Fence> buffer(new Fence());
+#if ANDROID_VERSION >= 19
+  // Make a copy of "data" and "fds" for unflatten() to avoid casting problem
+  void const *pdata = (void const *)data;
+  int const *pfds = fds;
+
+  if (NO_ERROR == buffer->unflatten(pdata, nbytes, pfds, nfds)) {
+#else
+  Flattenable *flattenable = buffer.get();
+
+  if (NO_ERROR == flattenable->unflatten(data, nbytes, fds, nfds)) {
+#endif
+    aResult->mFence = buffer;
+    return true;
+  }
+  return false;
+}
+
 } // namespace IPC
 
 namespace mozilla {
 namespace layers {
 
 FenceHandle::FenceHandle(const sp<Fence>& aFence)
   : mFence(aFence)
 {
 }
 
+FenceHandle::FenceHandle(const FenceHandleFromChild& aFenceHandle) {
+  mFence = aFenceHandle.mFence;
+}
+
+FenceHandleFromChild::FenceHandleFromChild(const sp<Fence>& aFence)
+  : mFence(aFence)
+{
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/FenceUtilsGonk.h
+++ b/gfx/layers/ipc/FenceUtilsGonk.h
@@ -11,43 +11,82 @@
 #include <unistd.h>
 #include <ui/Fence.h>
 
 #include "ipc/IPCMessageUtils.h"
 
 namespace mozilla {
 namespace layers {
 
+struct FenceHandleFromChild;
+
 struct FenceHandle {
   typedef android::Fence Fence;
 
   FenceHandle()
   { }
   FenceHandle(const android::sp<Fence>& aFence);
 
+  FenceHandle(const FenceHandleFromChild& aFenceHandle);
+
   bool operator==(const FenceHandle& aOther) const {
     return mFence.get() == aOther.mFence.get();
   }
 
   bool IsValid() const
   {
     return mFence.get() && mFence->isValid();
   }
 
   android::sp<Fence> mFence;
 };
 
+struct FenceHandleFromChild {
+  typedef android::Fence Fence;
+
+  FenceHandleFromChild()
+  { }
+  FenceHandleFromChild(const android::sp<Fence>& aFence);
+
+  FenceHandleFromChild(const FenceHandle& aFence) {
+    mFence = aFence.mFence;
+  }
+
+  bool operator==(const FenceHandle& aOther) const {
+    return mFence.get() == aOther.mFence.get();
+  }
+
+  bool operator==(const FenceHandleFromChild& aOther) const {
+    return mFence.get() == aOther.mFence.get();
+  }
+
+  bool IsValid() const
+  {
+    return mFence.get() && mFence->isValid();
+  }
+
+  android::sp<Fence> mFence;
+};
+
 } // namespace layers
 } // namespace mozilla
 
 namespace IPC {
 
 template <>
 struct ParamTraits<mozilla::layers::FenceHandle> {
   typedef mozilla::layers::FenceHandle paramType;
 
   static void Write(Message* aMsg, const paramType& aParam);
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult);
 };
 
+template <>
+struct ParamTraits<mozilla::layers::FenceHandleFromChild> {
+  typedef mozilla::layers::FenceHandleFromChild paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam);
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult);
+};
+
 } // namespace IPC
 
 #endif  // mozilla_layers_FenceUtilsGonk_h
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -147,16 +147,29 @@ ImageBridgeChild::UpdatedTexture(Composi
   MaybeRegion region = aRegion ? MaybeRegion(*aRegion)
                                : MaybeRegion(null_t());
   mTxn->AddNoSwapEdit(OpUpdateTexture(nullptr, aCompositable->GetIPDLActor(),
                                       nullptr, aTexture->GetIPDLActor(),
                                       region));
 }
 
 void
+ImageBridgeChild::SendFenceHandle(AsyncTransactionTracker* aTracker,
+                                  PTextureChild* aTexture,
+                                  const FenceHandle& aFence)
+{
+  HoldUntilComplete(aTracker);
+  InfallibleTArray<AsyncChildMessageData> messages;
+  messages.AppendElement(OpDeliverFenceFromChild(aTracker->GetId(),
+                                                 nullptr, aTexture,
+                                                 FenceHandleFromChild(aFence)));
+  SendChildAsyncMessages(messages);
+}
+
+void
 ImageBridgeChild::UpdatePictureRect(CompositableClient* aCompositable,
                                     const nsIntRect& aRect)
 {
   MOZ_ASSERT(aCompositable);
   MOZ_ASSERT(aCompositable->GetIPDLActor());
   mTxn->AddNoSwapEdit(OpUpdatePictureRect(nullptr, aCompositable->GetIPDLActor(), aRect));
 }
 
@@ -528,16 +541,18 @@ ImageBridgeChild::EndTransaction()
 
 
 PImageBridgeChild*
 ImageBridgeChild::StartUpInChildProcess(Transport* aTransport,
                                         ProcessId aOtherProcess)
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
 
+  gfxPlatform::GetPlatform();
+
   ProcessHandle processHandle;
   if (!base::OpenProcessHandle(aOtherProcess, &processHandle)) {
     return nullptr;
   }
 
   sImageBridgeChildThread = new Thread("ImageBridgeChild");
   if (!sImageBridgeChildThread->Start()) {
     return nullptr;
@@ -797,17 +812,17 @@ ImageBridgeChild::AllocPTextureChild(con
 
 bool
 ImageBridgeChild::DeallocPTextureChild(PTextureChild* actor)
 {
   return TextureClient::DestroyIPDLActor(actor);
 }
 
 bool
-ImageBridgeChild::RecvParentAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessages)
+ImageBridgeChild::RecvParentAsyncMessages(const InfallibleTArray<AsyncParentMessageData>& aMessages)
 {
   for (AsyncParentMessageArray::index_type i = 0; i < aMessages.Length(); ++i) {
     const AsyncParentMessageData& message = aMessages[i];
 
     switch (message.type()) {
       case AsyncParentMessageData::TOpDeliverFence: {
         const OpDeliverFence& op = message.get_OpDeliverFence();
         FenceHandle fence = op.fence();
@@ -828,23 +843,28 @@ ImageBridgeChild::RecvParentAsyncMessage
                                                               op.destHolderId(),
                                                               op.destTransactionId());
         // Send back a response.
         InfallibleTArray<AsyncChildMessageData> replies;
         replies.AppendElement(OpReplyDeliverFence(op.transactionId()));
         SendChildAsyncMessages(replies);
         break;
       }
+      case AsyncParentMessageData::TOpReplyDeliverFence: {
+        const OpReplyDeliverFence& op = message.get_OpReplyDeliverFence();
+        TransactionCompleteted(op.transactionId());
+        break;
+      }
       case AsyncParentMessageData::TOpReplyRemoveTexture: {
         const OpReplyRemoveTexture& op = message.get_OpReplyRemoveTexture();
 
         AsyncTransactionTrackersHolder::TransactionCompleteted(op.holderId(),
                                                                op.transactionId());
-      break;
-    }
+        break;
+      }
       default:
         NS_ERROR("unknown AsyncParentMessageData type");
         return false;
     }
   }
   return true;
 }
 
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -6,16 +6,17 @@
 #ifndef MOZILLA_GFX_IMAGEBRIDGECHILD_H
 #define MOZILLA_GFX_IMAGEBRIDGECHILD_H
 
 #include <stddef.h>                     // for size_t
 #include <stdint.h>                     // for uint32_t, uint64_t
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/RefPtr.h"             // for TemporaryRef
 #include "mozilla/ipc/SharedMemory.h"   // for SharedMemory, etc
+#include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTrackerHolder
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/CompositorTypes.h"  // for TextureIdentifier, etc
 #include "mozilla/layers/PImageBridgeChild.h"
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT
 #include "nsRegion.h"                   // for nsIntRegion
 class MessageLoop;
 struct nsIntPoint;
 struct nsIntRect;
@@ -96,16 +97,17 @@ bool InImageBridgeChildThread();
  * until the layer transaction happens. This means this scenario is not harmful.
  *
  * Since sending an image through imageBridge triggers compositing, the main thread is
  * not used at all (except for the very first transaction that provides the
  * CompositableHost with an AsyncID).
  */
 class ImageBridgeChild : public PImageBridgeChild
                        , public CompositableForwarder
+                       , public AsyncTransactionTrackersHolder
 {
   friend class ImageContainer;
   typedef InfallibleTArray<AsyncParentMessageData> AsyncParentMessageArray;
 public:
 
   /**
    * Creates the image bridge with a dedicated thread for ImageBridgeChild.
    *
@@ -181,17 +183,17 @@ public:
 
   virtual PTextureChild*
   AllocPTextureChild(const SurfaceDescriptor& aSharedData, const TextureFlags& aFlags) MOZ_OVERRIDE;
 
   virtual bool
   DeallocPTextureChild(PTextureChild* actor) MOZ_OVERRIDE;
 
   virtual bool
-  RecvParentAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessages) MOZ_OVERRIDE;
+  RecvParentAsyncMessages(const InfallibleTArray<AsyncParentMessageData>& aMessages) 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);
 
@@ -217,16 +219,20 @@ public:
    * See CompositableForwarder::UseTexture
    */
   virtual void UseTexture(CompositableClient* aCompositable,
                           TextureClient* aClient) MOZ_OVERRIDE;
   virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
                                          TextureClient* aClientOnBlack,
                                          TextureClient* aClientOnWhite) MOZ_OVERRIDE;
 
+  virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
+                               PTextureChild* aTexture,
+                               const FenceHandle& aFence) MOZ_OVERRIDE;
+
   virtual void RemoveTextureFromCompositable(CompositableClient* aCompositable,
                                              TextureClient* aTexture) MOZ_OVERRIDE;
 
   virtual void RemoveTextureFromCompositableAsync(AsyncTransactionTracker* aAsyncTransactionTracker,
                                                   CompositableClient* aCompositable,
                                                   TextureClient* aTexture) MOZ_OVERRIDE;
 
   virtual void RemoveTexture(TextureClient* aTexture) MOZ_OVERRIDE;
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -18,16 +18,17 @@
 #include "mozilla/ipc/Transport.h"      // for Transport
 #include "mozilla/layers/CompositableTransactionParent.h"
 #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/TextureHostOGL.h"  // for TextureHostOGL
 #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
@@ -203,32 +204,53 @@ ImageBridgeParent::SendFenceHandle(Async
                                    PTextureParent* aTexture,
                                    const FenceHandle& aFence)
 {
   HoldUntilComplete(aTracker);
   InfallibleTArray<AsyncParentMessageData> messages;
   messages.AppendElement(OpDeliverFence(aTracker->GetId(),
                                         aTexture, nullptr,
                                         aFence));
-  mozilla::unused << SendParentAsyncMessage(messages);
+  mozilla::unused << SendParentAsyncMessages(messages);
 }
 
 void
 ImageBridgeParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage)
 {
-  mozilla::unused << SendParentAsyncMessage(aMessage);
+  mozilla::unused << SendParentAsyncMessages(aMessage);
 }
 
 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::TOpDeliverFenceFromChild: {
+        const OpDeliverFenceFromChild& op = message.get_OpDeliverFenceFromChild();
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+        FenceHandle fence = FenceHandle(op.fence());
+        PTextureParent* parent = op.textureParent();
+
+        TextureHostOGL* hostOGL = nullptr;
+        RefPtr<TextureHost> texture = TextureHost::AsTextureHost(parent);
+        if (texture) {
+          hostOGL = texture->AsHostOGL();
+        }
+        if (hostOGL) {
+          hostOGL->SetAcquireFence(fence.mFence);
+        }
+#endif
+        // Send back a response.
+        InfallibleTArray<AsyncParentMessageData> replies;
+        replies.AppendElement(OpReplyDeliverFence(op.transactionId()));
+        mozilla::unused << SendParentAsyncMessages(replies);
+        break;
+      }
       case AsyncChildMessageData::TOpReplyDeliverFence: {
         const OpReplyDeliverFence& op = message.get_OpReplyDeliverFence();
         TransactionCompleteted(op.transactionId());
         break;
       }
       default:
         NS_ERROR("unknown AsyncChildMessageData type");
         return false;
@@ -299,17 +321,17 @@ bool ImageBridgeParent::IsSameProcess() 
   return OtherProcess() == ipc::kInvalidProcessHandle;
 }
 
 void
 ImageBridgeParent::ReplyRemoveTexture(const OpReplyRemoveTexture& aReply)
 {
   InfallibleTArray<AsyncParentMessageData> messages;
   messages.AppendElement(aReply);
-  mozilla::unused << SendParentAsyncMessage(messages);
+  mozilla::unused << SendParentAsyncMessages(messages);
 }
 
 /*static*/ void
 ImageBridgeParent::ReplyRemoveTexture(base::ProcessId aChildProcessId,
                                       const OpReplyRemoveTexture& aReply)
 {
   ImageBridgeParent* imageBridge = ImageBridgeParent::GetInstance(aChildProcessId);
   if (!imageBridge) {
@@ -334,17 +356,17 @@ ImageBridgeParent::SendFenceHandleToTrac
 
   RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
   HoldUntilComplete(tracker);
   InfallibleTArray<AsyncParentMessageData> messages;
   messages.AppendElement(OpDeliverFenceToTracker(tracker->GetId(),
                                                  aDestHolderId,
                                                  aTransactionId,
                                                  fence));
-  mozilla::unused << SendParentAsyncMessage(messages);
+  mozilla::unused << SendParentAsyncMessages(messages);
 }
 
 /*static*/ void
 ImageBridgeParent::SendFenceHandleToTrackerIfPresent(base::ProcessId aChildProcessId,
                                                      uint64_t aDestHolderId,
                                                      uint64_t aTransactionId,
                                                      PTextureParent* aTexture)
 {
--- a/gfx/layers/ipc/LayerTransactionChild.cpp
+++ b/gfx/layers/ipc/LayerTransactionChild.cpp
@@ -61,17 +61,17 @@ LayerTransactionChild::AllocPCompositabl
 
 bool
 LayerTransactionChild::DeallocPCompositableChild(PCompositableChild* actor)
 {
   return CompositableClient::DestroyIPDLActor(actor);
 }
 
 bool
-LayerTransactionChild::RecvParentAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessages)
+LayerTransactionChild::RecvParentAsyncMessages(const InfallibleTArray<AsyncParentMessageData>& aMessages)
 {
   for (AsyncParentMessageArray::index_type i = 0; i < aMessages.Length(); ++i) {
     const AsyncParentMessageData& message = aMessages[i];
 
     switch (message.type()) {
       case AsyncParentMessageData::TOpDeliverFence: {
         const OpDeliverFence& op = message.get_OpDeliverFence();
         FenceHandle fence = op.fence();
@@ -86,27 +86,46 @@ LayerTransactionChild::RecvParentAsyncMe
         } else {
           // Send back a response.
           InfallibleTArray<AsyncChildMessageData> replies;
           replies.AppendElement(OpReplyDeliverFence(op.transactionId()));
           SendChildAsyncMessages(replies);
         }
         break;
       }
+      case AsyncParentMessageData::TOpReplyDeliverFence: {
+        const OpReplyDeliverFence& op = message.get_OpReplyDeliverFence();
+        TransactionCompleteted(op.transactionId());
+        break;
+      }
       default:
         NS_ERROR("unknown AsyncParentMessageData type");
         return false;
     }
   }
   return true;
 }
 
 void
+LayerTransactionChild::SendFenceHandle(AsyncTransactionTracker* aTracker,
+                                       PTextureChild* aTexture,
+                                       const FenceHandle& aFence)
+{
+  HoldUntilComplete(aTracker);
+  InfallibleTArray<AsyncChildMessageData> messages;
+  messages.AppendElement(OpDeliverFenceFromChild(aTracker->GetId(),
+                                                 nullptr, aTexture,
+                                                 FenceHandleFromChild(aFence)));
+  SendChildAsyncMessages(messages);
+}
+
+void
 LayerTransactionChild::ActorDestroy(ActorDestroyReason why)
 {
+  DestroyAsyncTransactionTrackersHolder();
 #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.
   if (why == AbnormalShutdown) {
     NS_RUNTIMEABORT("ActorDestroy by IPC channel failure at LayerTransactionChild");
   }
--- a/gfx/layers/ipc/LayerTransactionChild.h
+++ b/gfx/layers/ipc/LayerTransactionChild.h
@@ -6,29 +6,31 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_LAYERS_LAYERTRANSACTIONCHILD_H
 #define MOZILLA_LAYERS_LAYERTRANSACTIONCHILD_H
 
 #include <stdint.h>                     // for uint32_t
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTracker
 #include "mozilla/layers/PLayerTransactionChild.h"
 #include "mozilla/RefPtr.h"
 
 namespace mozilla {
 
 namespace layout {
 class RenderFrameChild;
 class ShadowLayerForwarder;
 }
 
 namespace layers {
 
 class LayerTransactionChild : public PLayerTransactionChild
+                            , public AsyncTransactionTrackersHolder
 {
   typedef InfallibleTArray<AsyncParentMessageData> AsyncParentMessageArray;
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LayerTransactionChild)
   /**
    * Clean this up, finishing with Send__delete__().
    *
    * It is expected (checked with an assert) that all shadow layers
@@ -42,16 +44,20 @@ public:
   void SetHasNoCompositor() { mHasNoCompositor = true; }
   bool HasNoCompositor() { return mHasNoCompositor; }
 
   void SetForwarder(ShadowLayerForwarder* aForwarder)
   {
     mForwarder = aForwarder;
   }
 
+  virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
+                               PTextureChild* aTexture,
+                               const FenceHandle& aFence);
+
 protected:
   LayerTransactionChild()
     : mForwarder(nullptr)
     , mIPCOpen(false)
     , mDestroyed(false)
     , mHasNoCompositor(false)
   {}
   ~LayerTransactionChild() { }
@@ -62,17 +68,17 @@ protected:
   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 InfallibleTArray<AsyncParentMessageData>& aMessages) MOZ_OVERRIDE;
+  RecvParentAsyncMessages(const InfallibleTArray<AsyncParentMessageData>& aMessages) MOZ_OVERRIDE;
 
   virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 
   void AddIPDLReference() {
     MOZ_ASSERT(mIPCOpen == false);
     mIPCOpen = true;
     AddRef();
   }
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -22,16 +22,17 @@
 #include "mozilla/layers/ContainerLayerComposite.h"
 #include "mozilla/layers/ImageLayerComposite.h"
 #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/TextureHostOGL.h"  // for TextureHostOGL
 #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
@@ -797,16 +798,37 @@ LayerTransactionParent::DeallocPTextureP
 
 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::TOpDeliverFenceFromChild: {
+        const OpDeliverFenceFromChild& op = message.get_OpDeliverFenceFromChild();
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+        FenceHandle fence = FenceHandle(op.fence());
+        PTextureParent* parent = op.textureParent();
+
+        TextureHostOGL* hostOGL = nullptr;
+        RefPtr<TextureHost> texture = TextureHost::AsTextureHost(parent);
+        if (texture) {
+          hostOGL = texture->AsHostOGL();
+        }
+        if (hostOGL) {
+          hostOGL->SetAcquireFence(fence.mFence);
+        }
+#endif
+        // Send back a response.
+        InfallibleTArray<AsyncParentMessageData> replies;
+        replies.AppendElement(OpReplyDeliverFence(op.transactionId()));
+        mozilla::unused << SendParentAsyncMessages(replies);
+        break;
+      }
       case AsyncChildMessageData::TOpReplyDeliverFence: {
         const OpReplyDeliverFence& op = message.get_OpReplyDeliverFence();
         TransactionCompleteted(op.transactionId());
         break;
       }
       default:
         NS_ERROR("unknown AsyncChildMessageData type");
         return false;
@@ -831,19 +853,19 @@ LayerTransactionParent::SendFenceHandle(
                                         PTextureParent* aTexture,
                                         const FenceHandle& aFence)
 {
   HoldUntilComplete(aTracker);
   InfallibleTArray<AsyncParentMessageData> messages;
   messages.AppendElement(OpDeliverFence(aTracker->GetId(),
                                         aTexture, nullptr,
                                         aFence));
-  mozilla::unused << SendParentAsyncMessage(messages);
+  mozilla::unused << SendParentAsyncMessages(messages);
 }
 
 void
 LayerTransactionParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage)
 {
-  mozilla::unused << SendParentAsyncMessage(aMessage);
+  mozilla::unused << SendParentAsyncMessages(aMessage);
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -35,16 +35,17 @@ using mozilla::LayerMargin from "Units.h
 using mozilla::LayerPoint from "Units.h";
 using mozilla::LayerRect from "Units.h";
 using mozilla::layers::ScaleMode from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::EventRegions from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::DiagnosticTypes from "mozilla/layers/CompositorTypes.h";
 using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
 using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
 using struct mozilla::layers::FenceHandle from "mozilla/layers/FenceUtils.h";
+using struct mozilla::layers::FenceHandleFromChild from "mozilla/layers/FenceUtils.h";
 using mozilla::layers::TextureIdentifier from "mozilla/layers/CompositorTypes.h";
 
 namespace mozilla {
 namespace layers {
 
 struct TargetConfig {
   nsIntRect naturalBounds;
   ScreenRotation rotation;
@@ -382,16 +383,22 @@ struct OpDeliverFence {
 
 struct OpDeliverFenceToTracker {
   uint64_t transactionId;
   uint64_t destHolderId;
   uint64_t destTransactionId;
   FenceHandle fence;
 };
 
+struct OpDeliverFenceFromChild {
+  uint64_t transactionId;
+  PTexture texture;
+  FenceHandleFromChild fence;
+};
+
 struct OpReplyDeliverFence {
   uint64_t transactionId;
 };
 
 union CompositableOperation {
   OpUpdatePictureRect;
 
   OpCreatedIncrementalTexture;
@@ -461,17 +468,19 @@ union EditReply {
   OpTextureSwap;
 
   ReturnReleaseFence;
 };
 
 union AsyncParentMessageData {
   OpDeliverFence;
   OpDeliverFenceToTracker;
+  OpReplyDeliverFence;
   OpReplyRemoveTexture;
 };
 
 union AsyncChildMessageData {
+  OpDeliverFenceFromChild;
   OpReplyDeliverFence;
 };
 
 } // namespace
 } // namespace
--- a/gfx/layers/ipc/PImageBridge.ipdl
+++ b/gfx/layers/ipc/PImageBridge.ipdl
@@ -24,17 +24,17 @@ namespace layers {
  * which might be too busy dealing with content script.
  */
 intr protocol PImageBridge
 {
   manages PCompositable;
   manages PTexture;
 
 child:
-  async ParentAsyncMessage(AsyncParentMessageData[] aMessages);
+  async ParentAsyncMessages(AsyncParentMessageData[] aMessages);
 
 parent:
 
   sync Update(CompositableOperation[] ops) returns (EditReply[] reply);
   async UpdateNoSwap(CompositableOperation[] ops);
 
   // First step of the destruction sequence. This puts ImageBridge
   // in a state in which it can't send asynchronous messages
--- a/gfx/layers/ipc/PLayerTransaction.ipdl
+++ b/gfx/layers/ipc/PLayerTransaction.ipdl
@@ -38,17 +38,17 @@ union MaybeTransform {
 
 sync protocol PLayerTransaction {
   manager PRenderFrame or PCompositor;
   manages PLayer;
   manages PCompositable;
   manages PTexture;
 
 child:
-  async ParentAsyncMessage(AsyncParentMessageData[] aMessages);
+  async ParentAsyncMessages(AsyncParentMessageData[] aMessages);
 
 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.
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -406,16 +406,27 @@ ShadowLayerForwarder::UseComponentAlphaT
   MOZ_ASSERT(aTextureOnWhite->GetIPDLActor());
   MOZ_ASSERT(aTextureOnBlack->GetSize() == aTextureOnWhite->GetSize());
   mTxn->AddEdit(OpUseComponentAlphaTextures(nullptr, aCompositable->GetIPDLActor(),
                                             nullptr, aTextureOnBlack->GetIPDLActor(),
                                             nullptr, aTextureOnWhite->GetIPDLActor()));
 }
 
 void
+ShadowLayerForwarder::SendFenceHandle(AsyncTransactionTracker* aTracker,
+                                        PTextureChild* aTexture,
+                                        const FenceHandle& aFence)
+{
+  if (!HasShadowManager() || !mShadowManager->IPCOpen()) {
+    return;
+  }
+  mShadowManager->SendFenceHandle(aTracker, aTexture, aFence);
+}
+
+void
 ShadowLayerForwarder::RemoveTextureFromCompositable(CompositableClient* aCompositable,
                                                     TextureClient* aTexture)
 {
   MOZ_ASSERT(aCompositable);
   MOZ_ASSERT(aTexture);
   MOZ_ASSERT(aCompositable->GetIPDLActor());
   MOZ_ASSERT(aTexture->GetIPDLActor());
   mTxn->AddEdit(OpRemoveTexture(nullptr, aCompositable->GetIPDLActor(),
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -283,16 +283,20 @@ public:
    * See CompositableForwarder::UseTexture
    */
   virtual void UseTexture(CompositableClient* aCompositable,
                           TextureClient* aClient) MOZ_OVERRIDE;
   virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
                                          TextureClient* aClientOnBlack,
                                          TextureClient* aClientOnWhite) MOZ_OVERRIDE;
 
+  virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
+                               PTextureChild* aTexture,
+                               const FenceHandle& aFence) MOZ_OVERRIDE;
+
   /**
    * End the current transaction and forward it to LayerManagerComposite.
    * |aReplies| are directions from the LayerManagerComposite to the
    * caller of EndTransaction().
    */
   bool EndTransaction(InfallibleTArray<EditReply>* aReplies,
                       const nsIntRegion& aRegionToClear,
                       uint64_t aId,
--- a/gfx/layers/opengl/GrallocTextureClient.cpp
+++ b/gfx/layers/opengl/GrallocTextureClient.cpp
@@ -71,22 +71,16 @@ GrallocTextureClientOGL::ToSurfaceDescri
     return false;
   }
 
   aOutDescriptor = NewSurfaceDescriptorGralloc(mGrallocHandle, mSize);
   return true;
 }
 
 void
-GrallocTextureClientOGL::SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle)
-{
-  mReleaseFenceHandle = aReleaseFenceHandle;
-}
-
-void
 GrallocTextureClientOGL::SetRemoveFromCompositableTracker(AsyncTransactionTracker* aTracker)
 {
   mRemoveFromCompositableTracker = aTracker;
 }
 
 void
 GrallocTextureClientOGL::WaitForBufferOwnership()
 {
--- a/gfx/layers/opengl/GrallocTextureClient.h
+++ b/gfx/layers/opengl/GrallocTextureClient.h
@@ -55,18 +55,16 @@ public:
   virtual bool ImplementsLocking() const MOZ_OVERRIDE { return true; }
 
   virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; }
 
   virtual bool IsAllocated() const MOZ_OVERRIDE;
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
 
-  virtual void SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle) MOZ_OVERRIDE;
-
   virtual void SetRemoveFromCompositableTracker(AsyncTransactionTracker* aTracker) MOZ_OVERRIDE;
 
   virtual void WaitForBufferOwnership() MOZ_OVERRIDE;
 
   void InitWith(MaybeMagicGrallocBufferHandle aDesc, gfx::IntSize aSize);
 
   void SetTextureFlags(TextureFlags aFlags) { AddFlags(aFlags); }
 
--- a/gfx/layers/opengl/GrallocTextureHost.cpp
+++ b/gfx/layers/opengl/GrallocTextureHost.cpp
@@ -85,19 +85,21 @@ TextureTargetForAndroidPixelFormat(andro
       // like undesirable behaviour. We'd rather have a subtle artifact.
       MOZ_ASSERT(false, "Unknown Android pixel format.");
       return LOCAL_GL_TEXTURE_EXTERNAL;
     }
   }
 }
 
 GrallocTextureSourceOGL::GrallocTextureSourceOGL(CompositorOGL* aCompositor,
+                                                 GrallocTextureHostOGL* aTextureHost,
                                                  android::GraphicBuffer* aGraphicBuffer,
                                                  gfx::SurfaceFormat aFormat)
   : mCompositor(aCompositor)
+  , mTextureHost(aTextureHost)
   , mGraphicBuffer(aGraphicBuffer)
   , mEGLImage(0)
   , mFormat(aFormat)
   , mNeedsReset(true)
 {
   MOZ_ASSERT(mGraphicBuffer.get());
 }
 
@@ -295,16 +297,17 @@ GrallocTextureHostOGL::GrallocTextureHos
   if (graphicBuffer) {
     format =
       SurfaceFormatForAndroidPixelFormat(graphicBuffer->getPixelFormat(),
                                          aFlags & TextureFlags::RB_SWAPPED);
   } else {
     NS_WARNING("gralloc buffer is nullptr");
   }
   mTextureSource = new GrallocTextureSourceOGL(nullptr,
+                                               this,
                                                graphicBuffer,
                                                format);
 }
 
 GrallocTextureHostOGL::~GrallocTextureHostOGL()
 {
   mTextureSource = nullptr;
 }
@@ -435,16 +438,22 @@ GrallocTextureSourceOGL::GetGLTexture()
   }
 
   return mTexture;
 }
 
 void
 GrallocTextureSourceOGL::BindEGLImage()
 {
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+  if (mTextureHost) {
+    mTextureHost->WaitAcquireFenceSyncComplete();
+  }
+#endif
+
   if (mCompositableBackendData) {
     CompositableDataGonkOGL* backend = static_cast<CompositableDataGonkOGL*>(mCompositableBackendData.get());
     backend->BindEGLImage(GetTextureTarget(), mEGLImage);
   } else {
     gl()->fEGLImageTargetTexture2D(GetTextureTarget(), mEGLImage);
   }
 }
 
--- a/gfx/layers/opengl/GrallocTextureHost.h
+++ b/gfx/layers/opengl/GrallocTextureHost.h
@@ -18,16 +18,17 @@ class GrallocTextureHostOGL;
 
 class GrallocTextureSourceOGL : public NewTextureSource
                               , public TextureSourceOGL
 {
 public:
   friend class GrallocTextureHostOGL;
 
   GrallocTextureSourceOGL(CompositorOGL* aCompositor,
+                          GrallocTextureHostOGL* aTextureHost,
                           android::GraphicBuffer* aGraphicBuffer,
                           gfx::SurfaceFormat aFormat);
 
   virtual ~GrallocTextureSourceOGL();
 
   virtual bool IsValid() const MOZ_OVERRIDE;
 
   virtual void BindTexture(GLenum aTextureUnit, gfx::Filter aFilter) MOZ_OVERRIDE;
@@ -51,28 +52,30 @@ public:
 
   gl::GLContext* gl() const;
 
   virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
 
   void ForgetBuffer()
   {
     mGraphicBuffer = nullptr;
+    mTextureHost = nullptr;
   }
 
   TemporaryRef<gfx::DataSourceSurface> GetAsSurface();
 
   GLuint GetGLTexture();
 
   void BindEGLImage();
 
   void Lock();
 
 protected:
   CompositorOGL* mCompositor;
+  GrallocTextureHostOGL* mTextureHost;
   android::sp<android::GraphicBuffer> mGraphicBuffer;
   EGLImage mEGLImage;
   GLuint mTexture;
   gfx::SurfaceFormat mFormat;
   bool mNeedsReset;
 };
 
 class GrallocTextureHostOGL : public TextureHost
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -1,15 +1,16 @@
 /* -*- 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 "TextureHostOGL.h"
 #include "GLContext.h"                  // for GLContext, etc
+#include "GLLibraryEGL.h"               // for GLLibraryEGL
 #include "GLSharedHandleHelpers.h"
 #include "GLUploadHelpers.h"
 #include "GLReadTexImageHelper.h"
 #include "SharedSurface.h"              // for SharedSurface
 #include "SharedSurfaceEGL.h"           // for SharedSurface_EGLImage
 #include "SharedSurfaceGL.h"            // for SharedSurface_GLTexture, etc
 #include "SurfaceStream.h"              // for SurfaceStream
 #include "SurfaceTypes.h"               // for SharedSurfaceType, etc
@@ -215,16 +216,66 @@ android::sp<android::Fence>
 TextureHostOGL::GetAndResetReleaseFence()
 {
   // Hold previous ReleaseFence to prevent Fence delivery failure via gecko IPC.
   mPrevReleaseFence = mReleaseFence;
   // Reset current ReleaseFence.
   mReleaseFence = android::Fence::NO_FENCE;
   return mPrevReleaseFence;
 }
+
+void
+TextureHostOGL::SetAcquireFence(const android::sp<android::Fence>& aAcquireFence)
+{
+  mAcquireFence = aAcquireFence;
+}
+
+android::sp<android::Fence>
+TextureHostOGL::GetAcquireFence()
+{
+  return mAcquireFence;
+}
+
+void
+TextureHostOGL::WaitAcquireFenceSyncComplete()
+{
+  if (!mAcquireFence.get() || !mAcquireFence->isValid()) {
+    return;
+  }
+
+  int fenceFd = mAcquireFence->dup();
+  if (fenceFd == -1) {
+    NS_WARNING("failed to dup fence fd");
+    return;
+  }
+
+  EGLint attribs[] = {
+              LOCAL_EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
+              LOCAL_EGL_NONE
+          };
+
+  EGLSync sync = sEGLLibrary.fCreateSync(EGL_DISPLAY(),
+                                         LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID,
+                                         attribs);
+  if (!sync) {
+    NS_WARNING("failed to create native fence sync");
+    return;
+  }
+
+  EGLint status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(),
+                                              sync,
+                                              0,
+                                              LOCAL_EGL_FOREVER);
+  if (status != LOCAL_EGL_CONDITION_SATISFIED) {
+    NS_WARNING("failed to wait native fence sync");
+  }
+  MOZ_ALWAYS_TRUE( sEGLLibrary.fDestroySync(EGL_DISPLAY(), sync) );
+  mAcquireFence = nullptr;
+}
+
 #endif
 
 bool
 TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
                                      nsIntRegion* aDestRegion,
                                      gfx::IntPoint* aSrcOffset)
 {
   MOZ_ASSERT(mGL);
--- a/gfx/layers/opengl/TextureHostOGL.h
+++ b/gfx/layers/opengl/TextureHostOGL.h
@@ -167,19 +167,27 @@ public:
    */
   virtual bool SetReleaseFence(const android::sp<android::Fence>& aReleaseFence);
 
   /**
    * Return a releaseFence's Fence and clear a reference to the Fence.
    */
   virtual android::sp<android::Fence> GetAndResetReleaseFence();
 
+  virtual void SetAcquireFence(const android::sp<android::Fence>& aAcquireFence);
+
+  virtual android::sp<android::Fence> GetAcquireFence();
+
+  virtual void WaitAcquireFenceSyncComplete();
+
 protected:
   android::sp<android::Fence> mReleaseFence;
 
+  android::sp<android::Fence> mAcquireFence;
+
   /**
    * Hold previous ReleaseFence to prevent Fence delivery failure via gecko IPC.
    * Fence is a kernel object and its lifetime is managed by a reference count.
    * Until the Fence is delivered to client side, need to hold Fence on host side.
    */
   android::sp<android::Fence> mPrevReleaseFence;
 #endif
 };