Bug 925444 - Honor hwc releaseFenceFd on Gonk. r=nical, r=sushil, r=doublec, r=pchang, a=1.3+
authorSotaro Ikeda <sikeda@mozilla.com>
Fri, 10 Jan 2014 09:22:38 -0500
changeset 174680 d75ee062cb7b1be9bce1f3af65563adfcd73c67a
parent 174679 8d3ad38ccd8e5e4eded74aa2ab7adabf554c9836
child 174681 f189cc1d8863f1ee3cf5441a88d7ff96c888c4a5
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical, sushil, doublec, pchang, 1.3
bugs925444
milestone28.0a2
Bug 925444 - Honor hwc releaseFenceFd on Gonk. r=nical, r=sushil, r=doublec, r=pchang, a=1.3+
content/media/omx/OmxDecoder.cpp
content/media/omx/OmxDecoder.h
gfx/layers/GrallocImages.h
gfx/layers/LayersTypes.h
gfx/layers/client/ClientLayerManager.cpp
gfx/layers/client/CompositableClient.cpp
gfx/layers/client/CompositableClient.h
gfx/layers/client/ContentClient.cpp
gfx/layers/client/ContentClient.h
gfx/layers/client/TextureClient.h
gfx/layers/composite/CompositableHost.cpp
gfx/layers/composite/CompositableHost.h
gfx/layers/composite/ContentHost.cpp
gfx/layers/composite/ImageHost.cpp
gfx/layers/composite/TextureHost.h
gfx/layers/ipc/CompositableTransactionParent.cpp
gfx/layers/ipc/CompositableTransactionParent.h
gfx/layers/ipc/FenceUtils.h
gfx/layers/ipc/FenceUtilsGonk.cpp
gfx/layers/ipc/FenceUtilsGonk.h
gfx/layers/ipc/ImageBridgeChild.cpp
gfx/layers/ipc/ImageBridgeParent.cpp
gfx/layers/ipc/LayerTransactionParent.cpp
gfx/layers/ipc/LayersMessages.ipdlh
gfx/layers/moz.build
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
widget/gonk/HwcComposer2D.cpp
widget/gonk/HwcComposer2D.h
widget/gonk/nativewindow/GonkNativeWindowJB.cpp
widget/gonk/nativewindow/GonkNativeWindowJB.h
--- a/content/media/omx/OmxDecoder.cpp
+++ b/content/media/omx/OmxDecoder.cpp
@@ -10,16 +10,19 @@
 #include <cutils/properties.h>
 #include <stagefright/foundation/ADebug.h>
 #include <stagefright/foundation/AMessage.h>
 #include <stagefright/MediaExtractor.h>
 #include <stagefright/MetaData.h>
 #include <stagefright/OMXClient.h>
 #include <stagefright/OMXCodec.h>
 #include <OMX.h>
+#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
+#include <ui/Fence.h>
+#endif
 
 #include "mozilla/Preferences.h"
 #include "mozilla/Types.h"
 #include "mozilla/Monitor.h"
 #include "nsMimeTypes.h"
 #include "MPAPI.h"
 #include "prlog.h"
 
@@ -184,17 +187,17 @@ void
 VideoGraphicBuffer::Unlock()
 {
   android::sp<android::OmxDecoder> omxDecoder = mOmxDecoder.promote();
   if (omxDecoder.get()) {
     // Post kNotifyPostReleaseVideoBuffer message to OmxDecoder via ALooper.
     // The message is delivered to OmxDecoder on ALooper thread.
     // MediaBuffer::release() could take a very long time.
     // PostReleaseVideoBuffer() prevents long time locking.
-    omxDecoder->PostReleaseVideoBuffer(mMediaBuffer);
+    omxDecoder->PostReleaseVideoBuffer(mMediaBuffer, mReleaseFenceHandle);
   } else {
     NS_WARNING("OmxDecoder is not present");
     if (mMediaBuffer) {
       mMediaBuffer->release();
     }
   }
   mMediaBuffer = nullptr;
 }
@@ -805,16 +808,21 @@ bool OmxDecoder::ReadVideo(VideoFrame *a
 
       mozilla::layers::SurfaceDescriptor descWrapper(newDescriptor);
       aFrame->mGraphicBuffer = new mozilla::layers::VideoGraphicBuffer(this, mVideoBuffer, descWrapper);
       aFrame->mRotation = mVideoRotation;
       aFrame->mTimeUs = timeUs;
       aFrame->mKeyFrame = keyFrame;
       aFrame->Y.mWidth = mVideoWidth;
       aFrame->Y.mHeight = mVideoHeight;
+      // MediaBuffer's reference count is already incremented by VideoGraphicBuffer's constructor.
+      // By calling ReleaseVideoBuffer(), MediaBuffer's ref count is changed from 2 to 1.
+      // It is necessary to ensure to return MediaBuffer to OMXCodec
+      // in OmxDecoder::ReleaseAllPendingVideoBuffersLocked().
+      ReleaseVideoBuffer();
     } else if (mVideoBuffer->range_length() > 0) {
       char *data = static_cast<char *>(mVideoBuffer->data()) + mVideoBuffer->range_offset();
       size_t length = mVideoBuffer->range_length();
 
       if (unreadable) {
         LOG(PR_LOG_DEBUG, "video frame is unreadable");
       }
 
@@ -976,47 +984,67 @@ void OmxDecoder::onMessageReceived(const
     }
 
     default:
       TRESPASS();
       break;
   }
 }
 
-void OmxDecoder::PostReleaseVideoBuffer(MediaBuffer *aBuffer)
+void OmxDecoder::PostReleaseVideoBuffer(MediaBuffer *aBuffer, const FenceHandle& aReleaseFenceHandle)
 {
   {
     Mutex::Autolock autoLock(mPendingVideoBuffersLock);
-    mPendingVideoBuffers.push(aBuffer);
+    mPendingVideoBuffers.push(BufferItem(aBuffer, aReleaseFenceHandle));
   }
 
   sp<AMessage> notify =
             new AMessage(kNotifyPostReleaseVideoBuffer, mReflector->id());
   // post AMessage to OmxDecoder via ALooper.
   notify->post();
 }
 
 void OmxDecoder::ReleaseAllPendingVideoBuffersLocked()
 {
-  Vector<MediaBuffer *> releasingVideoBuffers;
+  Vector<BufferItem> releasingVideoBuffers;
   {
     Mutex::Autolock autoLock(mPendingVideoBuffersLock);
 
     int size = mPendingVideoBuffers.size();
     for (int i = 0; i < size; i++) {
-      MediaBuffer *buffer = mPendingVideoBuffers[i];
-      releasingVideoBuffers.push(buffer);
+      releasingVideoBuffers.push(mPendingVideoBuffers[i]);
     }
     mPendingVideoBuffers.clear();
   }
   // Free all pending video buffers without holding mPendingVideoBuffersLock.
   int size = releasingVideoBuffers.size();
   for (int i = 0; i < size; i++) {
     MediaBuffer *buffer;
-    buffer = releasingVideoBuffers[i];
+    buffer = releasingVideoBuffers[i].mMediaBuffer;
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18
+    android::sp<Fence> fence;
+    int fenceFd = -1;
+    fence = releasingVideoBuffers[i].mReleaseFenceHandle.mFence;
+    if (fence.get() && fence->isValid()) {
+      fenceFd = fence->dup();
+    }
+    MOZ_ASSERT(buffer->refcount() == 1);
+    // This code expect MediaBuffer's ref count is 1.
+    // Return gralloc buffer to ANativeWindow
+    ANativeWindow* window = static_cast<ANativeWindow*>(mNativeWindowClient.get());
+    window->cancelBuffer(window,
+                         buffer->graphicBuffer().get(),
+                         fenceFd);
+    // Mark MediaBuffer as rendered.
+    // When gralloc buffer is directly returned to ANativeWindow,
+    // this mark is necesary.
+    sp<MetaData> metaData = buffer->meta_data();
+    metaData->setInt32(kKeyRendered, 1);
+#endif
+    // Return MediaBuffer to OMXCodec.
     buffer->release();
   }
   releasingVideoBuffers.clear();
 }
 
 bool OmxDecoder::ProcessCachedData(int64_t aOffset, bool aWaitForCompletion)
 {
   // We read data in chunks of 32 KiB. We can reduce this
--- a/content/media/omx/OmxDecoder.h
+++ b/content/media/omx/OmxDecoder.h
@@ -5,16 +5,17 @@
 #include <stagefright/DataSource.h>
 #include <stagefright/MediaSource.h>
 #include <utils/RefBase.h>
 #include <stagefright/MediaExtractor.h>
 
 #include "GonkNativeWindow.h"
 #include "GonkNativeWindowClient.h"
 #include "GrallocImages.h"
+#include "gfxipc/FenceUtils.h"
 #include "MP3FrameParser.h"
 #include "MPAPI.h"
 #include "MediaResource.h"
 #include "AbstractMediaDecoder.h"
 #include "OMXCodecProxy.h"
 
 namespace android {
 class OmxDecoder;
@@ -76,16 +77,17 @@ private:
 };
 
 class OmxDecoder : public OMXCodecProxy::EventListener {
   typedef MPAPI::AudioFrame AudioFrame;
   typedef MPAPI::VideoFrame VideoFrame;
   typedef mozilla::MP3FrameParser MP3FrameParser;
   typedef mozilla::MediaResource MediaResource;
   typedef mozilla::AbstractMediaDecoder AbstractMediaDecoder;
+  typedef mozilla::layers::FenceHandle FenceHandle;
 
   enum {
     kPreferSoftwareCodecs = 1,
     kSoftwareCodecsOnly = 8,
     kHardwareCodecsOnly = 16,
   };
 
   enum {
@@ -115,21 +117,36 @@ class OmxDecoder : public OMXCodecProxy:
   MP3FrameParser mMP3FrameParser;
   bool mIsMp3;
 
   // Lifetime of these should be handled by OMXCodec, as long as we release
   //   them after use: see ReleaseVideoBuffer(), ReleaseAudioBuffer()
   MediaBuffer *mVideoBuffer;
   MediaBuffer *mAudioBuffer;
 
+  struct BufferItem {
+    BufferItem()
+     : mMediaBuffer(nullptr)
+    {
+    }
+    BufferItem(MediaBuffer* aMediaBuffer, const FenceHandle& aReleaseFenceHandle)
+     : mMediaBuffer(aMediaBuffer)
+     , mReleaseFenceHandle(aReleaseFenceHandle) {
+    }
+
+    MediaBuffer* mMediaBuffer;
+    // a fence will signal when the current buffer is no longer being read.
+    FenceHandle mReleaseFenceHandle;
+  };
+
   // Hold video's MediaBuffers that are released during video seeking.
   // The holded MediaBuffers are released soon after seek completion.
   // OMXCodec does not accept MediaBuffer during seeking. If MediaBuffer is
   //  returned to OMXCodec during seeking, OMXCodec calls assert.
-  Vector<MediaBuffer *> mPendingVideoBuffers;
+  Vector<BufferItem> mPendingVideoBuffers;
   // The lock protects mPendingVideoBuffers.
   Mutex mPendingVideoBuffersLock;
 
   // Show if OMXCodec is seeking.
   bool mIsVideoSeeking;
   // The lock protects video MediaBuffer release()'s pending operations called
   //  from multiple threads. The pending operations happen only during video
   //  seeking. Holding mSeekLock long time could affect to video rendering.
@@ -228,17 +245,17 @@ public:
 
   //Change decoder into a playing state
   nsresult Play();
 
   //Change decoder into a paused state
   void Pause();
 
   // Post kNotifyPostReleaseVideoBuffer message to OmxDecoder via ALooper.
-  void PostReleaseVideoBuffer(MediaBuffer *aBuffer);
+  void PostReleaseVideoBuffer(MediaBuffer *aBuffer, const FenceHandle& aReleaseFenceHandle);
   // Receive a message from AHandlerReflector.
   // Called on ALooper thread.
   void onMessageReceived(const sp<AMessage> &msg);
 
   bool ProcessCachedData(int64_t aOffset, bool aWaitForCompletion);
 };
 
 }
--- a/gfx/layers/GrallocImages.h
+++ b/gfx/layers/GrallocImages.h
@@ -3,19 +3,20 @@
  * 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 GRALLOCIMAGES_H
 #define GRALLOCIMAGES_H
 
 #ifdef MOZ_WIDGET_GONK
 
-#include "mozilla/layers/LayersSurfaces.h"
+#include "FenceUtils.h"
 #include "ImageLayers.h"
 #include "ImageContainer.h"
+#include "mozilla/layers/LayersSurfaces.h"
 
 #include <ui/GraphicBuffer.h>
 
 namespace mozilla {
 namespace layers {
 
 class GrallocTextureClientOGL;
 
@@ -40,18 +41,29 @@ public:
 
   virtual void Unlock() {}
 
   SurfaceDescriptor GetSurfaceDescriptor()
   {
     return mSurfaceDescriptor;
   }
 
+  void SetReleaseFenceHandle(const FenceHandle& aReleaseFenceHandle)
+  {
+    mReleaseFenceHandle = aReleaseFenceHandle;
+  }
+
+  const FenceHandle& GetReleaseFenceHandle() const
+  {
+    return mReleaseFenceHandle;
+  }
+
 protected:
   SurfaceDescriptor mSurfaceDescriptor;
+  FenceHandle mReleaseFenceHandle;
 };
 
 /**
  * The YUV format supported by Android HAL
  *
  * 4:2:0 - CbCr width and height is half that of Y.
  *
  * This format assumes
--- a/gfx/layers/LayersTypes.h
+++ b/gfx/layers/LayersTypes.h
@@ -30,16 +30,17 @@ struct PRLogModuleInfo;
 
 namespace android {
 class GraphicBuffer;
 }
 
 namespace mozilla {
 namespace layers {
 
+class TextureHostCommon;
 
 typedef uint32_t TextureFlags;
 
 enum LayersBackend {
   LAYERS_NONE = 0,
   LAYERS_BASIC,
   LAYERS_OPENGL,
   LAYERS_D3D9,
@@ -70,29 +71,31 @@ enum LayerRenderStateFlags {
   LAYER_RENDER_STATE_FORMAT_RB_SWAP = 1 << 2
 };
 
 // The 'ifdef MOZ_WIDGET_GONK' sadness here is because we don't want to include
 // android::sp unless we have to.
 struct LayerRenderState {
   LayerRenderState()
 #ifdef MOZ_WIDGET_GONK
-    : mSurface(nullptr), mFlags(0), mHasOwnOffset(false)
+    : mSurface(nullptr), mFlags(0), mHasOwnOffset(false), mTexture(nullptr)
 #endif
   {}
 
 #ifdef MOZ_WIDGET_GONK
   LayerRenderState(android::GraphicBuffer* aSurface,
                    const nsIntSize& aSize,
-                   uint32_t aFlags)
+                   uint32_t aFlags,
+                   TextureHostCommon* aTexture)
     : mSurface(aSurface)
     , mSize(aSize)
     , mFlags(aFlags)
     , mHasOwnOffset(false)
-  {}
+    , mTexture(aTexture)
+   {}
 
   bool YFlipped() const
   { return mFlags & LAYER_RENDER_STATE_Y_FLIPPED; }
 
   bool BufferRotated() const
   { return mFlags & LAYER_RENDER_STATE_BUFFER_ROTATION; }
 
   bool FormatRBSwapped() const
@@ -105,16 +108,17 @@ struct LayerRenderState {
     mHasOwnOffset = true;
   }
 
 #ifdef MOZ_WIDGET_GONK
   // surface to render
   android::sp<android::GraphicBuffer> mSurface;
   // size of mSurface 
   nsIntSize mSize;
+  TextureHostCommon* mTexture;
 #endif
   // see LayerRenderStateFlags
   uint32_t mFlags;
   // the location of the layer's origin on mSurface
   nsIntPoint mOffset;
   // true if mOffset is applicable
   bool mHasOwnOffset;
 };
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -374,17 +374,27 @@ ClientLayerManager::ForwardTransaction()
         // let the camera know that the gralloc buffer is not used anymore on
         // the compositor side and that it can reuse it.
         const ReplyTextureRemoved& rep = reply.get_ReplyTextureRemoved();
         CompositableClient* compositable
           = static_cast<CompositableChild*>(rep.compositableChild())->GetCompositableClient();
         compositable->OnReplyTextureRemoved(rep.textureId());
         break;
       }
-
+      case EditReply::TReturnReleaseFence: {
+        const ReturnReleaseFence& rep = reply.get_ReturnReleaseFence();
+        FenceHandle fence = rep.fence();
+        if (!fence.IsValid()) {
+          break;
+        }
+        CompositableClient* compositable
+          = static_cast<CompositableChild*>(rep.compositableChild())->GetCompositableClient();
+        compositable->SetReleaseFence(fence);
+        break;
+      }
       default:
         NS_RUNTIMEABORT("not reached");
       }
     }
 
     if (sent) {
       mNeedsComposite = false;
     }
--- a/gfx/layers/client/CompositableClient.cpp
+++ b/gfx/layers/client/CompositableClient.cpp
@@ -262,35 +262,65 @@ CompositableClient::NextTextureID()
 
   return mNextTextureID;
 }
 
 bool
 CompositableClient::AddTextureClient(TextureClient* aClient)
 {
   aClient->SetID(NextTextureID());
+  mAddedTextures[aClient->GetID()] = aClient;
   return mForwarder->AddTexture(this, aClient);
 }
 
 void
 CompositableClient::RemoveTextureClient(TextureClient* aClient)
 {
   MOZ_ASSERT(aClient);
   mTexturesToRemove.AppendElement(TextureIDAndFlags(aClient->GetID(),
                                                     aClient->GetFlags()));
   if (aClient->GetFlags() & TEXTURE_DEALLOCATE_CLIENT) {
     TextureClientData* data = aClient->DropTextureData();
     if (data) {
       mTexturesToRemoveCallbacks[aClient->GetID()] = data;
     }
   }
+  {
+    std::map<uint64_t, RefPtr<TextureClient>>::iterator it
+      = mAddedTextures.find(aClient->GetID());
+    if (it != mAddedTextures.end()) {
+      mAddedTextures.erase(it);
+    }
+  }
   aClient->ClearID();
   aClient->MarkInvalid();
 }
 
+TemporaryRef<TextureClient>
+CompositableClient::GetAddedTextureClient(uint64_t aTextureID)
+{
+  std::map<uint64_t, RefPtr<TextureClient>>::iterator it
+    = mAddedTextures.find(aTextureID);
+  if (it != mAddedTextures.end()) {
+    return mAddedTextures[aTextureID];
+  }
+  return nullptr;
+}
+
+TextureClientData*
+CompositableClient::GetRemovingTextureClientData(uint64_t aTextureID)
+{
+  std::map<uint64_t,TextureClientData*>::iterator it
+    = mTexturesToRemoveCallbacks.find(aTextureID);
+  if (it != mTexturesToRemoveCallbacks.end()) {
+    return mTexturesToRemoveCallbacks[aTextureID];
+  }
+  return nullptr;
+}
+
 void
 CompositableClient::OnReplyTextureRemoved(uint64_t aTextureID)
 {
   std::map<uint64_t,TextureClientData*>::iterator it
     = mTexturesToRemoveCallbacks.find(aTextureID);
   if (it != mTexturesToRemoveCallbacks.end()) {
     it->second->DeallocateSharedData(GetForwarder());
     delete it->second;
--- a/gfx/layers/client/CompositableClient.h
+++ b/gfx/layers/client/CompositableClient.h
@@ -4,37 +4,36 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_BUFFERCLIENT_H
 #define MOZILLA_GFX_BUFFERCLIENT_H
 
 #include <stdint.h>                     // for uint64_t
 #include <vector>                       // for vector
 #include <map>                          // for map
+#include "ipc/FenceUtils.h"
 #include "mozilla/Assertions.h"         // for MOZ_CRASH
 #include "mozilla/RefPtr.h"             // for TemporaryRef, RefCounted
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat
 #include "mozilla/layers/CompositorTypes.h"
+#include "mozilla/layers/TextureClient.h"  // for TextureClient, etc
 #include "mozilla/layers/LayersTypes.h"  // for LayersBackend
 #include "mozilla/layers/PCompositableChild.h"  // for PCompositableChild
 #include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "gfxASurface.h"                // for gfxContentType
 
 namespace mozilla {
 namespace layers {
 
 class CompositableClient;
-class DeprecatedTextureClient;
-class TextureClient;
 class BufferTextureClient;
 class ImageBridgeChild;
 class CompositableForwarder;
 class CompositableChild;
 class SurfaceDescriptor;
-class TextureClientData;
 
 /**
  * CompositableClient manages the texture-specific logic for composite layers,
  * independently of the layer. It is the content side of a CompositableClient/
  * CompositableHost pair.
  *
  * CompositableClient's purpose is to send texture data to the compositor side
  * along with any extra information about how the texture is to be composited.
@@ -133,16 +132,22 @@ public:
   virtual bool AddTextureClient(TextureClient* aClient);
 
   /**
    * Tells the Compositor to delete the TextureHost corresponding to this
    * TextureClient.
    */
   virtual void RemoveTextureClient(TextureClient* aClient);
 
+  // XXX: this function is only needed until Bug 897452 is fixed.
+  virtual TemporaryRef<TextureClient> GetAddedTextureClient(uint64_t aTextureID);
+
+  // XXX: this function is only needed until Bug 897452 is fixed.
+  virtual TextureClientData* GetRemovingTextureClientData(uint64_t aTextureID);
+
   /**
    * A hook for the Compositable to execute whatever it held off for next transaction.
    */
   virtual void OnTransaction();
 
   /**
    * A hook for the when the Compositable is detached from it's layer.
    */
@@ -168,26 +173,37 @@ public:
    */
   void FlushTexturesToRemoveCallbacks();
 
   /**
    * Our IPDL actor is being destroyed, get rid of any shmem resources now.
    */
   virtual void OnActorDestroy() = 0;
 
+  /**
+   * If a fence is valid, wait until the fence is completed.
+   * After the wait, clear it.
+   */
+  virtual void WaitAndResetReleaseFence() {}
+
+  virtual void SetReleaseFence(FenceHandle aReleaseFenceHandle) {}
+
 protected:
   // return the next texture ID
   uint64_t NextTextureID();
 
   struct TextureIDAndFlags {
     TextureIDAndFlags(uint64_t aID, TextureFlags aFlags)
     : mID(aID), mFlags(aFlags) {}
     uint64_t mID;
     TextureFlags mFlags;
   };
+
+  // XXX map is necessary on the code that Bug 897452 is not fixed.
+  std::map<uint64_t, RefPtr<TextureClient>> mAddedTextures;
   // The textures to destroy in the next transaction;
   nsTArray<TextureIDAndFlags> mTexturesToRemove;
   std::map<uint64_t, TextureClientData*> mTexturesToRemoveCallbacks;
   uint64_t mNextTextureID;
   CompositableChild* mCompositableChild;
   CompositableForwarder* mForwarder;
 };
 
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -82,16 +82,36 @@ ContentClient::CreateContentClient(Compo
 #endif
   if (useDeprecatedTextures) {
     return new DeprecatedContentClientSingleBuffered(aForwarder);
   } else {
     return new ContentClientSingleBuffered(aForwarder);
   }
 }
 
+#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
+void
+DeprecatedContentClientRemoteBuffer::WaitAndResetReleaseFence()
+{
+  if (mReleaseFence.get() && mReleaseFence->isValid()) {
+    mReleaseFence->waitForever("DeprecatedContentClientRemoteBuffer::WaitAndResetReleaseFence()");
+    mReleaseFence = android::Fence::NO_FENCE;
+  }
+}
+
+void
+DeprecatedContentClientRemoteBuffer::SetReleaseFence(FenceHandle aReleaseFenceHandle)
+{
+  if (!aReleaseFenceHandle.IsValid()) {
+    return;
+  }
+  mReleaseFence = aReleaseFenceHandle.mFence;
+}
+#endif
+
 // We pass a null pointer for the ContentClient Forwarder argument, which means
 // this client will not have a ContentHost on the other side.
 ContentClientBasic::ContentClientBasic()
   : ContentClient(nullptr)
   , RotatedContentBuffer(ContainsVisibleBounds)
 {}
 
 void
@@ -827,16 +847,17 @@ struct AutoDeprecatedTextureClient {
   }
 private:
   DeprecatedTextureClient* mTexture;
 };
 
 void
 DeprecatedContentClientDoubleBuffered::SyncFrontBufferToBackBuffer()
 {
+  WaitAndResetReleaseFence();
   mIsNewBuffer = false;
 
   if (!mFrontAndBackBufferDiffer) {
     return;
   }
   MOZ_ASSERT(mFrontClient);
   MOZ_ASSERT(mFrontClient->GetAccessMode() == DeprecatedTextureClient::ACCESS_READ_ONLY);
   MOZ_ASSERT(!mFrontClientOnWhite ||
@@ -963,16 +984,18 @@ DeprecatedContentClientSingleBuffered::C
                                   *mDeprecatedTextureClient->LockSurfaceDescriptor(),
                                   mTextureInfo,
                                   mDeprecatedTextureClientOnWhite ? mDeprecatedTextureClientOnWhite->LockSurfaceDescriptor() : nullptr);
 }
 
 void
 DeprecatedContentClientSingleBuffered::SyncFrontBufferToBackBuffer()
 {
+  WaitAndResetReleaseFence();
+
   mIsNewBuffer = false;
   if (!mFrontAndBackBufferDiffer) {
     return;
   }
   mFrontAndBackBufferDiffer = false;
 
   DrawTarget* backBuffer = GetDTBuffer();
   if (!backBuffer && mDeprecatedTextureClient) {
--- a/gfx/layers/client/ContentClient.h
+++ b/gfx/layers/client/ContentClient.h
@@ -22,16 +22,20 @@
 #include "mozilla/layers/TextureClient.h"  // for DeprecatedTextureClient
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for nsTArray
 
+#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
+#include <ui/Fence.h>
+#endif
+
 class gfxContext;
 struct gfxMatrix;
 class gfxASurface;
 
 namespace mozilla {
 namespace gfx {
 class DrawTarget;
 }
@@ -311,16 +315,22 @@ public:
    * valid when the texture client is locked, so is mapped out
    * of RotatedContentBuffer when we are done painting.
    * None of the underlying buffer attributes (rect, rotation)
    * are affected by mapping/unmapping.
    */
   virtual void BeginPaint() MOZ_OVERRIDE;
   virtual void EndPaint() MOZ_OVERRIDE;
 
+#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
+  virtual void WaitAndResetReleaseFence()  MOZ_OVERRIDE;
+
+  virtual void SetReleaseFence(FenceHandle aReleaseFenceHandle)  MOZ_OVERRIDE;
+#endif
+
   virtual void Updated(const nsIntRegion& aRegionToDraw,
                        const nsIntRegion& aVisibleRegion,
                        bool aDidSelfCopy);
 
   virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) MOZ_OVERRIDE;
 
   // Expose these protected methods from the superclass.
   virtual const nsIntRect& BufferRect() const
@@ -370,16 +380,20 @@ protected:
   // around, then unlock when we are done painting
   nsTArray<RefPtr<DeprecatedTextureClient> > mOldTextures;
 
   TextureInfo mTextureInfo;
   bool mIsNewBuffer;
   bool mFrontAndBackBufferDiffer;
   gfx::IntSize mSize;
   ContentType mContentType;
+
+#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
+  android::sp<android::Fence> mReleaseFence;
+#endif
 };
 
 /**
  * A double buffered ContentClient. mDeprecatedTextureClient is the back buffer, which
  * we draw into. mFrontClient is the front buffer which we may read from, but
  * not write to, when the compositor does not have the 'soft' lock. We can write
  * into mDeprecatedTextureClient at any time.
  *
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -6,16 +6,17 @@
 #ifndef MOZILLA_GFX_TEXTURECLIENT_H
 #define MOZILLA_GFX_TEXTURECLIENT_H
 
 #include <stddef.h>                     // for size_t
 #include <stdint.h>                     // for uint32_t, uint8_t, uint64_t
 #include "GLContextTypes.h"             // for GLContext (ptr only), etc
 #include "GLTextureImage.h"             // for TextureImage
 #include "ImageTypes.h"                 // for StereoMode
+#include "gfxipc/FenceUtils.h"             // for FenceHandle
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/RefPtr.h"             // for RefPtr, RefCounted
 #include "mozilla/gfx/2D.h"             // for DrawTarget
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat
 #include "mozilla/ipc/Shmem.h"          // for Shmem
 #include "mozilla/layers/CompositorTypes.h"  // for TextureFlags, etc
@@ -118,16 +119,17 @@ public:
  *
  * See:
  *  - CompositableClient::RemoveTextureClient
  *  - CompositableClient::OnReplyTextureRemoved
  */
 class TextureClientData {
 public:
   virtual void DeallocateSharedData(ISurfaceAllocator* allocator) = 0;
+  virtual void SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle) {}
   virtual ~TextureClientData() {}
 };
 
 /**
  * TextureClient is a thin abstraction over texture data that need to be shared
  * between the content process and the compositor process. It is the
  * content-side half of a TextureClient/TextureHost pair. A corresponding
  * TextureHost lives on the compositor-side.
@@ -248,16 +250,18 @@ public:
    * anymore. This usually means it will soon be destroyed.
    */
   void MarkInvalid() { mValid = false; }
 
   // If a texture client holds a reference to shmem, it should override this
   // method to forget about the shmem _without_ releasing it.
   virtual void OnActorDestroy() {}
 
+  virtual void SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle) {}
+
 protected:
   void AddFlags(TextureFlags  aFlags)
   {
     MOZ_ASSERT(!IsSharedWithCompositor());
     mFlags |= aFlags;
   }
 
   uint64_t mID;
--- a/gfx/layers/composite/CompositableHost.cpp
+++ b/gfx/layers/composite/CompositableHost.cpp
@@ -36,31 +36,35 @@ CompositableHost::CompositableHost(const
 CompositableHost::~CompositableHost()
 {
   MOZ_COUNT_DTOR(CompositableHost);
 
   RefPtr<TextureHost> it = mFirstTexture;
   while (it) {
     if (!(it->GetFlags() & TEXTURE_DEALLOCATE_CLIENT)) {
       it->DeallocateSharedData();
+      // Clear strong refrence to CompositableBackendSpecificData
+      it->SetCompositableBackendSpecificData(nullptr);
     }
     it = it->GetNextSibling();
   }
+  if (mBackendData) {
+    mBackendData->ClearData();
+  }
 }
 
 void
 CompositableHost::AddTextureHost(TextureHost* aTexture)
 {
   MOZ_ASSERT(aTexture);
   MOZ_ASSERT(GetTextureHost(aTexture->GetID()) == nullptr,
              "A texture is already present with this ID");
   RefPtr<TextureHost> second = mFirstTexture;
   mFirstTexture = aTexture;
   aTexture->SetNextSibling(second);
-  aTexture->SetCompositableBackendSpecificData(GetCompositableBackendSpecificData());
 }
 
 void
 CompositableHost::RemoveTextureHost(TextureHost* aTexture)
 {
   uint64_t textureID = aTexture->GetID();
   if (mFirstTexture && mFirstTexture->GetID() == textureID) {
     mFirstTexture = mFirstTexture->GetNextSibling();
@@ -70,16 +74,18 @@ CompositableHost::RemoveTextureHost(Text
   while (it) {
     if (it->GetNextSibling() &&
         it->GetNextSibling()->GetID() == textureID) {
       it->SetNextSibling(it->GetNextSibling()->GetNextSibling());
       aTexture->SetNextSibling(nullptr);
     }
     it = it->GetNextSibling();
   }
+  // Clear strong refrence to CompositableBackendSpecificData
+  aTexture->SetCompositableBackendSpecificData(nullptr);
   if (!mFirstTexture && mBackendData) {
     mBackendData->ClearData();
   }
 }
 
 TextureHost*
 CompositableHost::GetTextureHost(uint64_t aTextureID)
 {
--- a/gfx/layers/composite/CompositableHost.h
+++ b/gfx/layers/composite/CompositableHost.h
@@ -15,16 +15,17 @@
 #include "mozilla/RefPtr.h"             // for RefPtr, RefCounted, etc
 #include "mozilla/gfx/Point.h"          // for Point
 #include "mozilla/gfx/Rect.h"           // for Rect
 #include "mozilla/gfx/Types.h"          // for Filter
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/layers/CompositorTypes.h"  // for TextureInfo, etc
 #include "mozilla/layers/LayersTypes.h"  // for LayerRenderState, etc
 #include "mozilla/layers/PCompositableParent.h"
+#include "mozilla/layers/TextureHost.h" // for TextureHostCommon
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nscore.h"                     // for nsACString
 #include "Units.h"                      // for CSSToScreenScale
 
 struct nsIntPoint;
 struct nsIntRect;
@@ -65,17 +66,55 @@ public:
   {
     MOZ_COUNT_CTOR(CompositableBackendSpecificData);
   }
   virtual ~CompositableBackendSpecificData()
   {
     MOZ_COUNT_DTOR(CompositableBackendSpecificData);
   }
   virtual void SetCompositor(Compositor* aCompositor) {}
-  virtual void ClearData() {}
+  virtual void ClearData()
+  {
+    mCurrentReleaseFenceTexture = nullptr;
+    ClearPendingReleaseFenceTextureList();
+  }
+
+  /**
+   * Store a texture currently used for Composition.
+   * This function is called when the texutre might receive ReleaseFence
+   * as a result of Composition.
+   */
+  void SetCurrentReleaseFenceTexture(TextureHostCommon* aTexture)
+  {
+    if (mCurrentReleaseFenceTexture) {
+      mPendingReleaseFenceTextures.push_back(mCurrentReleaseFenceTexture);
+    }
+    mCurrentReleaseFenceTexture = aTexture;
+  }
+
+  virtual std::vector< RefPtr<TextureHostCommon> >& GetPendingReleaseFenceTextureList()
+  {
+    return mPendingReleaseFenceTextures;
+  }
+
+  virtual void ClearPendingReleaseFenceTextureList()
+  {
+    return mPendingReleaseFenceTextures.clear();
+  }
+protected:
+  /**
+   * Store a TextureHost currently used for Composition
+   * and it might receive ReleaseFence for the texutre.
+   */
+  RefPtr<TextureHostCommon> mCurrentReleaseFenceTexture;
+  /**
+   * Store TextureHosts that might have ReleaseFence to be delivered
+   * to TextureClient by CompositableHost.
+   */
+  std::vector< RefPtr<TextureHostCommon> > mPendingReleaseFenceTextures;
 };
 
 /**
  * The compositor-side counterpart to CompositableClient. Responsible for
  * updating textures and data about textures from IPC and how textures are
  * composited (tiling, double buffering, etc.).
  *
  * Update (for images/canvases) and UpdateThebes (for Thebes) are called during
--- a/gfx/layers/composite/ContentHost.cpp
+++ b/gfx/layers/composite/ContentHost.cpp
@@ -694,16 +694,17 @@ DeprecatedContentHostSingleBuffered::Upd
   if (!mDeprecatedTextureHost && !mNewFrontHost) {
     mInitialised = false;
     return;
   }
 
   if (mNewFrontHost) {
     DestroyFrontHost();
     mDeprecatedTextureHost = mNewFrontHost;
+    mDeprecatedTextureHost->SetCompositableBackendSpecificData(GetCompositableBackendSpecificData());
     mNewFrontHost = nullptr;
     if (mNewFrontHostOnWhite) {
       mDeprecatedTextureHostOnWhite = mNewFrontHostOnWhite;
       mNewFrontHostOnWhite = nullptr;
     }
   }
 
   MOZ_ASSERT(mDeprecatedTextureHost);
@@ -895,16 +896,17 @@ DeprecatedContentHostDoubleBuffered::Upd
   }
 
   MOZ_ASSERT(mDeprecatedTextureHost);
   MOZ_ASSERT(!mNewFrontHostOnWhite, "New white host without a new black?");
   MOZ_ASSERT(mBackHost);
 
   RefPtr<DeprecatedTextureHost> oldFront = mDeprecatedTextureHost;
   mDeprecatedTextureHost = mBackHost;
+  mDeprecatedTextureHost->SetCompositableBackendSpecificData(GetCompositableBackendSpecificData());
   mBackHost = oldFront;
 
   oldFront = mDeprecatedTextureHostOnWhite;
   mDeprecatedTextureHostOnWhite = mBackHostOnWhite;
   mBackHostOnWhite = oldFront;
 
   mDeprecatedTextureHost->Update(*mDeprecatedTextureHost->LockSurfaceDescriptor());
   if (mDeprecatedTextureHostOnWhite) {
--- a/gfx/layers/composite/ImageHost.cpp
+++ b/gfx/layers/composite/ImageHost.cpp
@@ -34,16 +34,17 @@ ImageHost::ImageHost(const TextureInfo& 
 {}
 
 ImageHost::~ImageHost() {}
 
 void
 ImageHost::UseTextureHost(TextureHost* aTexture)
 {
   mFrontBuffer = aTexture;
+  mFrontBuffer->SetCompositableBackendSpecificData(GetCompositableBackendSpecificData());
 }
 
 void
 ImageHost::RemoveTextureHost(TextureHost* aTexture)
 {
   CompositableHost::RemoveTextureHost(aTexture);
   if (mFrontBuffer && mFrontBuffer->GetID() == aTexture->GetID()) {
     mFrontBuffer = nullptr;
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -37,16 +37,18 @@ class Shmem;
 
 namespace layers {
 
 class Compositor;
 class CompositableHost;
 class CompositableBackendSpecificData;
 class SurfaceDescriptor;
 class ISurfaceAllocator;
+class TextureHost;
+class TextureHostOGL;
 class TextureSourceOGL;
 class TextureSourceD3D9;
 class TextureSourceD3D11;
 class TextureSourceBasic;
 class TextureParent;
 class DataTextureSource;
 
 /**
@@ -62,26 +64,55 @@ class TileIterator
 public:
   virtual void BeginTileIteration() = 0;
   virtual void EndTileIteration() {};
   virtual nsIntRect GetTileRect() = 0;
   virtual size_t GetTileCount() = 0;
   virtual bool NextTile() = 0;
 };
 
+
+/**
+ * TextureHostCommon is a base class for TextureHost and DeprecatedTextureHost.
+ * They need to be handled in a unified way.
+ * See Bug 925444.
+ * XXX - remove this class when deprecated texture classes are completely removed.
+ */
+class TextureHostCommon : public RefCounted<TextureHostCommon>
+{
+public:
+  TextureHostCommon()
+  {
+    MOZ_COUNT_CTOR(TextureHostCommon);
+  }
+  virtual ~TextureHostCommon()
+  {
+    MOZ_COUNT_DTOR(TextureHostCommon);
+  }
+
+  /**
+   * Cast to a TextureHost
+   */
+  virtual TextureHost* AsHost() { return nullptr; }
+  /**
+   * Cast to a TextureHost for each backend.
+   */
+  virtual TextureHostOGL* AsHostOGL() { return nullptr; }
+};
+
 /**
  * TextureSource is the interface for texture objects that can be composited
  * by a given compositor backend. Since the drawing APIs are different
  * between backends, the TextureSource interface is split into different
  * interfaces (TextureSourceOGL, etc.), and TextureSource mostly provide
  * access to these interfaces.
  *
  * This class is used on the compositor side.
  */
-class TextureSource : public RefCounted<TextureSource>
+class TextureSource : public TextureHostCommon
 {
 public:
   TextureSource();
   virtual ~TextureSource();
 
   /**
    * Return the size of the texture in texels.
    * If this is a tile iterator, GetSize must return the size of the current tile.
@@ -252,24 +283,26 @@ private:
  * lifetime. This means that the lifetime of the underlying shared data
  * matches the lifetime of the TextureClient/Host pair. It also means
  * TextureClient/Host do not implement double buffering, which is the
  * reponsibility of the compositable (which would use two Texture pairs).
  *
  * The Lock/Unlock mecanism here mirrors Lock/Unlock in TextureClient.
  *
  */
-class TextureHost : public RefCounted<TextureHost>
+class TextureHost : public TextureHostCommon
 {
 public:
   TextureHost(uint64_t aID,
               TextureFlags aFlags);
 
   virtual ~TextureHost();
 
+  virtual TextureHost* AsHost() { return this; }
+
   /**
    * Factory method.
    */
   static TemporaryRef<TextureHost> Create(uint64_t aID,
                                           const SurfaceDescriptor& aDesc,
                                           ISurfaceAllocator* aDeallocator,
                                           TextureFlags aFlags);
 
--- a/gfx/layers/ipc/CompositableTransactionParent.cpp
+++ b/gfx/layers/ipc/CompositableTransactionParent.cpp
@@ -3,27 +3,29 @@
  */
 /* 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 "CompositableTransactionParent.h"
 #include "CompositableHost.h"           // for CompositableParent, etc
 #include "CompositorParent.h"           // for CompositorParent
+#include "GLContext.h"                  // for GLContext
 #include "Layers.h"                     // for Layer
 #include "RenderTrace.h"                // for RenderTraceInvalidateEnd, etc
 #include "TiledLayerBuffer.h"           // for TiledLayerComposer
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/ContentHost.h"  // for ContentHostBase
 #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 "nsDebug.h"                    // for NS_WARNING, NS_ASSERTION
 #include "nsRegion.h"                   // for nsIntRegion
 
 namespace mozilla {
 namespace layers {
 
@@ -148,16 +150,17 @@ CompositableParentManager::ReceiveCompos
           ScheduleComposition(op);
         }
       }
 
       if (layer) {
         RenderTraceInvalidateEnd(layer, "FF00FF");
       }
 
+      ReturnReleaseFenceIfNecessary(compositable, replyv, op.compositableParent());
       break;
     }
     case CompositableOperation::TOpPaintTextureRegion: {
       MOZ_LAYERS_LOG(("[ParentSide] Paint ThebesLayer"));
 
       const OpPaintTextureRegion& op = aEdit.get_OpPaintTextureRegion();
       CompositableParent* compositableParent = static_cast<CompositableParent*>(op.compositableParent());
       CompositableHost* compositable =
@@ -173,16 +176,17 @@ CompositableParentManager::ReceiveCompos
       compositable->UpdateThebes(bufferData,
                                  op.updatedRegion(),
                                  thebes->GetValidRegion(),
                                  &frontUpdatedRegion);
       replyv.push_back(
         OpContentBufferSwap(compositableParent, nullptr, frontUpdatedRegion));
 
       RenderTraceInvalidateEnd(thebes, "FF00FF");
+      ReturnReleaseFenceIfNecessary(compositable, replyv, op.compositableParent());
       break;
     }
     case CompositableOperation::TOpPaintTextureIncremental: {
       MOZ_LAYERS_LOG(("[ParentSide] Paint ThebesLayer"));
 
       const OpPaintTextureIncremental& op = aEdit.get_OpPaintTextureIncremental();
 
       CompositableParent* compositableParent = static_cast<CompositableParent*>(op.compositableParent());
@@ -226,20 +230,20 @@ CompositableParentManager::ReceiveCompos
         NS_WARNING("Invalid texture ID");
         break;
       }
       CompositableHost* compositable = AsCompositable(op);
       RefPtr<TextureHost> tex = compositable->GetTextureHost(op.textureID());
 
       MOZ_ASSERT(tex.get());
       compositable->UseTextureHost(tex);
-
       if (IsAsync()) {
         ScheduleComposition(op);
       }
+      ReturnReleaseFenceIfNecessary(compositable, replyv, op.compositableParent());
       break;
     }
     case CompositableOperation::TOpAddTexture: {
       const OpAddTexture& op = aEdit.get_OpAddTexture();
       if (op.textureID() == 0) {
         NS_WARNING("Invalid texture ID");
         break;
       }
@@ -300,23 +304,72 @@ CompositableParentManager::ReceiveCompos
       MOZ_ASSERT(texture);
 
       texture->Updated(op.region().type() == MaybeRegion::TnsIntRegion
                        ? &op.region().get_nsIntRegion()
                        : nullptr); // no region means invalidate the entire surface
 
 
       compositable->UseTextureHost(texture);
-
+      ReturnReleaseFenceIfNecessary(compositable, replyv, op.compositableParent());
       break;
     }
 
     default: {
       MOZ_ASSERT(false, "bad type");
     }
   }
 
   return true;
 }
 
+#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
+void
+CompositableParentManager::ReturnReleaseFenceIfNecessary(CompositableHost* aCompositable,
+                                                         EditReplyVector& replyv,
+                                                         PCompositableParent* aParent)
+{
+  if (!aCompositable || !aCompositable->GetCompositableBackendSpecificData()) {
+    return;
+  }
+
+  const std::vector< RefPtr<TextureHostCommon> > textureList =
+        aCompositable->GetCompositableBackendSpecificData()->GetPendingReleaseFenceTextureList();
+  // Return pending Texture data
+  for (size_t i = 0; i < textureList.size(); i++) {
+    TextureHostOGL* hostOGL = textureList[i]->AsHostOGL();
+    if (!hostOGL) {
+      continue;
+    }
+    android::sp<android::Fence> fence = hostOGL->GetAndResetReleaseFence();
+    if (fence.get() && fence->isValid()) {
+      TextureHost* host = textureList[i]->AsHost();
+      uint64_t id = host ? host->GetID() : 0;
+      FenceHandle handle = FenceHandle(fence);
+      replyv.push_back(ReturnReleaseFence(aParent, nullptr, id, handle));
+      // Hold ReleaseFence handle to prevent fence's file descriptor is closed before IPC happens.
+      mPrevReleaseFenceHandles.push_back(handle);
+    }
+  }
+  aCompositable->GetCompositableBackendSpecificData()->ClearPendingReleaseFenceTextureList();
+}
+#else
+void
+CompositableParentManager::ReturnReleaseFenceIfNecessary(CompositableHost* aCompositable,
+                                                         EditReplyVector& replyv,
+                                                         PCompositableParent* aParent)
+{
+  if (!aCompositable || !aCompositable->GetCompositableBackendSpecificData()) {
+    return;
+  }
+  aCompositable->GetCompositableBackendSpecificData()->ClearPendingReleaseFenceTextureList();
+}
+#endif
+
+void
+CompositableParentManager::ClearPrevReleaseFenceHandles()
+{
+  mPrevReleaseFenceHandles.clear();
+}
+
 } // namespace
 } // namespace
 
--- a/gfx/layers/ipc/CompositableTransactionParent.h
+++ b/gfx/layers/ipc/CompositableTransactionParent.h
@@ -11,16 +11,18 @@
 #include <vector>                       // for vector
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator
 #include "mozilla/layers/LayersMessages.h"  // for EditReply, etc
 
 namespace mozilla {
 namespace layers {
 
+class CompositableHost;
+
 typedef std::vector<mozilla::layers::EditReply> EditReplyVector;
 
 // Since PCompositble has two potential manager protocols, we can't just call
 // the Manager() method usually generated when there's one manager protocol,
 // so both manager protocols implement this and we keep a reference to them
 // through this interface.
 class CompositableParentManager : public ISurfaceAllocator
 {
@@ -32,14 +34,22 @@ protected:
                                  EditReplyVector& replyv);
   bool IsOnCompositorSide() const MOZ_OVERRIDE { return true; }
 
   /**
    * Return true if this protocol is asynchronous with respect to the content
    * thread (ImageBridge for instance).
    */
   virtual bool IsAsync() const { return false; }
+
+  void ReturnReleaseFenceIfNecessary(CompositableHost* aCompositable,
+                                     EditReplyVector& replyv,
+                                     PCompositableParent* aParent);
+  void ClearPrevReleaseFenceHandles();
+
+protected:
+  std::vector<FenceHandle> mPrevReleaseFenceHandles;
 };
 
 } // namespace
 } // namespace
 
 #endif
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/FenceUtils.h
@@ -0,0 +1,43 @@
+/* -*- 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 IPC_FencerUtils_h
+#define IPC_FencerUtils_h
+
+#include "ipc/IPCMessageUtils.h"
+
+/**
+ * FenceHandle is used for delivering Fence object via ipc.
+ */
+#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
+# include "mozilla/layers/FenceUtilsGonk.h"
+#else
+namespace mozilla {
+namespace layers {
+struct FenceHandle {
+  bool operator==(const FenceHandle&) const { return false; }
+  bool IsValid() const { return false; }
+};
+} // namespace layers
+} // namespace mozilla
+#endif // MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
+
+namespace IPC {
+
+#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
+#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; }
+};
+#endif // MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
+
+} // namespace IPC
+
+#endif // IPC_FencerUtils_h
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/FenceUtilsGonk.cpp
@@ -0,0 +1,96 @@
+/* -*- 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 "GLContext.h"
+#include "mozilla/unused.h"
+#include "nsXULAppAPI.h"
+
+#include "FenceUtilsGonk.h"
+
+using namespace android;
+using namespace base;
+using namespace mozilla::layers;
+
+namespace IPC {
+
+void
+ParamTraits<FenceHandle>::Write(Message* aMsg,
+                                const paramType& aParam)
+{
+  Flattenable *flattenable = aParam.mFence.get();
+  size_t nbytes = flattenable->getFlattenedSize();
+  size_t nfds = flattenable->getFdCount();
+
+  char data[nbytes];
+  int fds[nfds];
+  flattenable->flatten(data, nbytes, fds, nfds);
+
+  aMsg->WriteSize(nbytes);
+  aMsg->WriteSize(nfds);
+
+  aMsg->WriteBytes(data, nbytes);
+  for (size_t n = 0; n < nfds; ++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(fds[n], false));
+  }
+}
+
+bool
+ParamTraits<FenceHandle>::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;
+    }
+    // If the GraphicBuffer 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(fd.fd) : fd.fd;
+    fds[n] = dupFd;
+  }
+
+  sp<Fence> buffer(new Fence());
+  Flattenable *flattenable = buffer.get();
+
+  if (NO_ERROR == flattenable->unflatten(data, nbytes, fds, nfds)) {
+    aResult->mFence = buffer;
+    return true;
+  }
+  return false;
+}
+
+} // namespace IPC
+
+namespace mozilla {
+namespace layers {
+
+FenceHandle::FenceHandle(const sp<Fence>& aFence)
+  : mFence(aFence)
+{
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/FenceUtilsGonk.h
@@ -0,0 +1,53 @@
+/* -*- 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_FenceUtilsGonk_h
+#define mozilla_layers_FenceUtilsGonk_h
+
+#include <unistd.h>
+#include <ui/Fence.h>
+
+#include "ipc/IPCMessageUtils.h"
+
+namespace mozilla {
+namespace layers {
+
+struct FenceHandle {
+  typedef android::Fence Fence;
+
+  FenceHandle()
+  { }
+  FenceHandle(const android::sp<Fence>& aFence);
+
+  bool operator==(const FenceHandle& 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);
+};
+
+} // namespace IPC
+
+#endif  // mozilla_layers_FenceUtilsGonk_h
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -530,16 +530,38 @@ ImageBridgeChild::EndTransaction()
       // notify the B2G camera that the gralloc buffer is not used by the
       // compositor anymore and that it can be recycled.
       const ReplyTextureRemoved& rep = reply.get_ReplyTextureRemoved();
       CompositableClient* compositable
         = static_cast<CompositableChild*>(rep.compositableChild())->GetCompositableClient();
       compositable->OnReplyTextureRemoved(rep.textureId());
       break;
     }
+    case EditReply::TReturnReleaseFence: {
+      const ReturnReleaseFence& rep = reply.get_ReturnReleaseFence();
+      FenceHandle fence = rep.fence();
+      if (!fence.IsValid()) {
+        break;
+      }
+      CompositableClient* compositable
+        = static_cast<CompositableChild*>(rep.compositableChild())->GetCompositableClient();
+      RefPtr<TextureClient> texture = compositable->GetAddedTextureClient(rep.textureId());
+      if (texture) {
+        texture->SetReleaseFenceHandle(fence);
+        break;
+      }
+      // This happens when the TextureClient was destroyed but the TextureClientData is
+      // still alive.
+      TextureClientData* data = compositable->GetRemovingTextureClientData(rep.textureId());
+      if (data) {
+        data->SetReleaseFenceHandle(fence);
+        break;
+      }
+      break;
+    }
     default:
       NS_RUNTIMEABORT("not reached");
     }
   }
 }
 
 
 PImageBridgeChild*
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -68,16 +68,19 @@ bool
 ImageBridgeParent::RecvUpdate(const EditArray& aEdits, EditReplyArray* aReply)
 {
   // If we don't actually have a compositor, then don't bother
   // creating any textures.
   if (Compositor::GetBackend() == LAYERS_NONE) {
     return true;
   }
 
+  // Clear ReleaseFence handles used in previous transaction.
+  ClearPrevReleaseFenceHandles();
+
   EditReplyVector replyv;
   for (EditArray::index_type i = 0; i < aEdits.Length(); ++i) {
     ReceiveCompositableUpdate(aEdits[i], replyv);
   }
 
   aReply->SetCapacity(replyv.size());
   if (replyv.size() > 0) {
     aReply->AppendElements(&replyv.front(), replyv.size());
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -195,16 +195,19 @@ LayerTransactionParent::RecvUpdate(const
 #endif
 
   MOZ_LAYERS_LOG(("[ParentSide] received txn with %d edits", cset.Length()));
 
   if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) {
     return true;
   }
 
+  // Clear ReleaseFence handles used in previous transaction.
+  ClearPrevReleaseFenceHandles();
+
   EditReplyVector replyv;
 
   layer_manager()->BeginTransactionWithDrawTarget(nullptr);
 
   for (EditArray::index_type i = 0; i < cset.Length(); ++i) {
     const Edit& edit = cset[i];
 
     switch (edit.type()) {
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -31,16 +31,17 @@ using nsCSSProperty from "nsCSSProperty.
 using mozilla::dom::ScreenOrientation from "mozilla/dom/ScreenOrientation.h";
 using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
 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::DiagnosticTypes from "mozilla/layers/CompositorTypes.h";
 using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
+using struct mozilla::layers::FenceHandle from "gfxipc/FenceUtils.h";
 
 namespace mozilla {
 namespace layers {
 
 struct TargetConfig {
   nsIntRect naturalBounds;
   ScreenRotation rotation;
   nsIntRect clientBounds;
@@ -398,19 +399,26 @@ struct OpTextureSwap {
   SurfaceDescriptor image;
 };
 
 struct ReplyTextureRemoved {
   PCompositable compositable;
   uint64_t textureId;
 };
 
+struct ReturnReleaseFence {
+  PCompositable compositable;
+  uint64_t textureId;
+  FenceHandle fence;
+};
+
 // Unit of a "changeset reply".  This is a weird abstraction, probably
 // only to be used for buffer swapping.
 union EditReply {
   OpContentBufferSwap;
   OpTextureSwap;
 
   ReplyTextureRemoved;
+  ReturnReleaseFence;
 };
 
 } // namespace
 } // namespace
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -21,16 +21,17 @@ EXPORTS += [
     'D3D9SurfaceImage.h',
     'FrameMetrics.h',
     'GrallocImages.h',
     'ImageContainer.h',
     'ImageLayers.h',
     'ImageTypes.h',
     'ipc/CompositorChild.h',
     'ipc/CompositorParent.h',
+    'ipc/FenceUtils.h',
     'ipc/ShadowLayersManager.h',
     'Layers.h',
     'LayerScope.h',
     'LayersLogging.h',
     'LayerSorter.h',
     'LayerTreeInvalidation.h',
     'opengl/Composer2D.h',
     'opengl/OGLShaderProgram.h',
@@ -89,16 +90,17 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'wind
             'd3d11/TextureD3D11.cpp',
             'ipc/ShadowLayerUtilsD3D10.cpp',
         ]
         SOURCES += [
             'd3d11/CompositorD3D11.cpp',
         ]
 
 EXPORTS.gfxipc += [
+    'ipc/FenceUtils.h',
     'ipc/ShadowLayerUtils.h',
 ]
 
 EXPORTS.mozilla.layers += [
     'basic/BasicCompositor.h',
     'basic/MacIOSurfaceTextureHostBasic.h',
     'basic/TextureHostBasic.h',
     'client/CanvasClient.h',
@@ -189,16 +191,24 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk
         'GrallocImages.cpp',
         'opengl/GrallocTextureClient.cpp',
         'opengl/GrallocTextureHost.cpp',
     ]
     SOURCES += [
         'ipc/ShadowLayerUtilsGralloc.cpp',
     ]
 
+    if CONFIG['ANDROID_VERSION'] in ('18'):
+        EXPORTS.mozilla.layers += [
+            'ipc/FenceUtilsGonk.h',
+        ]
+        SOURCES += [
+            'ipc/FenceUtilsGonk.cpp',
+        ]
+
 UNIFIED_SOURCES += [
     'basic/BasicCanvasLayer.cpp',
     'basic/BasicColorLayer.cpp',
     'basic/BasicCompositor.cpp',
     'basic/BasicContainerLayer.cpp',
     'basic/BasicImages.cpp',
     'basic/BasicLayerManager.cpp',
     'basic/BasicLayersImpl.cpp',
--- a/gfx/layers/opengl/GrallocTextureClient.cpp
+++ b/gfx/layers/opengl/GrallocTextureClient.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/. */
 
 #ifdef MOZ_WIDGET_GONK
 
+#include "ipc/FenceUtils.h"
 #include "mozilla/layers/GrallocTextureClient.h"
 #include "mozilla/layers/CompositableClient.h"
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/ShadowLayerUtilsGralloc.h"
 #include "GrallocImages.h"
 #include "gfx2DGlue.h"
 
@@ -33,16 +34,21 @@ public:
   }
 
   virtual void DeallocateSharedData(ISurfaceAllocator*) MOZ_OVERRIDE
   {
     mBufferLocked->Unlock();
     mBufferLocked = nullptr;
   }
 
+  virtual void SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle)
+  {
+    mBufferLocked->SetReleaseFenceHandle(aReleaseFenceHandle);
+  }
+
 private:
   RefPtr<GraphicBufferLocked> mBufferLocked;
 };
 
 class GrallocTextureClientData : public TextureClientData {
 public:
   GrallocTextureClientData(GrallocBufferActor* aActor)
     : mGrallocActor(aActor)
@@ -82,16 +88,25 @@ GrallocTextureClientOGL::DropTextureData
   } else {
     TextureClientData* result = new GrallocTextureClientData(mGrallocActor);
     mGrallocActor = nullptr;
     mGraphicBuffer = nullptr;
     return result;
   }
 }
 
+void
+GrallocTextureClientOGL::SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle)
+{
+  if (!mBufferLocked) {
+    return;
+  }
+  mBufferLocked->SetReleaseFenceHandle(aReleaseFenceHandle);
+}
+
 GrallocTextureClientOGL::GrallocTextureClientOGL(GrallocBufferActor* aActor,
                                                  gfx::IntSize aSize,
                                                  TextureFlags aFlags)
 : BufferTextureClient(nullptr, gfx::FORMAT_UNKNOWN, aFlags)
 , mGrallocFlags(android::GraphicBuffer::USAGE_SW_READ_OFTEN)
 , mMappedBuffer(nullptr)
 {
   InitWith(aActor, aSize);
--- a/gfx/layers/opengl/GrallocTextureClient.h
+++ b/gfx/layers/opengl/GrallocTextureClient.h
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_GRALLOCTEXTURECLIENT_H
 #define MOZILLA_GFX_GRALLOCTEXTURECLIENT_H
 #ifdef MOZ_WIDGET_GONK
 
 #include "mozilla/layers/TextureClient.h"
+#include "ipc/FenceUtils.h" // for FenceHandle
 #include "ISurfaceAllocator.h" // For IsSurfaceDescriptorValid
 #include "mozilla/layers/ShadowLayerUtilsGralloc.h"
 #include <ui/GraphicBuffer.h>
 
 namespace mozilla {
 namespace layers {
 
 class GraphicBufferLocked;
@@ -49,16 +50,18 @@ public:
   virtual bool ImplementsLocking() const MOZ_OVERRIDE { return true; }
 
   virtual bool IsAllocated() const MOZ_OVERRIDE;
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
 
   virtual TextureClientData* DropTextureData() MOZ_OVERRIDE;
 
+  virtual void SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle) MOZ_OVERRIDE;
+
   void InitWith(GrallocBufferActor* aActor, gfx::IntSize aSize);
 
   gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; }
 
   android::GraphicBuffer* GetGraphicBuffer()
   {
     return mGraphicBuffer.get();
   }
--- a/gfx/layers/opengl/GrallocTextureHost.cpp
+++ b/gfx/layers/opengl/GrallocTextureHost.cpp
@@ -173,16 +173,20 @@ GrallocTextureSourceOGL::SetCompositable
 
   if (!mCompositor) {
     return;
   }
 
   // delete old EGLImage
   DeallocateDeviceData();
 
+  if (!aBackendData) {
+    return;
+  }
+
   gl()->MakeCurrent();
   GLuint tex = GetGLTexture();
   GLuint textureTarget = GetTextureTarget();
 
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
   gl()->fBindTexture(textureTarget, tex);
   // create new EGLImage
   mEGLImage = gl()->CreateEGLImageForNativeBuffer(mGraphicBuffer->getNativeBuffer());
@@ -287,17 +291,18 @@ GrallocTextureHostOGL::GetRenderState()
     if (mFlags & TEXTURE_NEEDS_Y_FLIP) {
       flags |= LAYER_RENDER_STATE_Y_FLIPPED;
     }
     if (mFlags & TEXTURE_RB_SWAPPED) {
       flags |= LAYER_RENDER_STATE_FORMAT_RB_SWAP;
     }
     return LayerRenderState(mTextureSource->mGraphicBuffer.get(),
                             gfx::ThebesIntSize(mSize),
-                            flags);
+                            flags,
+                            this);
   }
 
   return LayerRenderState();
 }
 
 TemporaryRef<gfx::DataSourceSurface>
 GrallocTextureHostOGL::GetAsSurface() {
   return mTextureSource ? mTextureSource->GetAsSurface()
@@ -334,12 +339,17 @@ GrallocTextureSourceOGL::GetGLTexture()
 
 void
 GrallocTextureHostOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData)
 {
   mCompositableBackendData = aBackendData;
   if (mTextureSource) {
     mTextureSource->SetCompositableBackendSpecificData(aBackendData);
   }
+  // Register this object to CompositableBackendSpecificData
+  // as current TextureHost.
+  if (aBackendData) {
+    aBackendData->SetCurrentReleaseFenceTexture(this);
+  }
 }
 
 } // namepsace layers
 } // namepsace mozilla
--- a/gfx/layers/opengl/GrallocTextureHost.h
+++ b/gfx/layers/opengl/GrallocTextureHost.h
@@ -67,16 +67,19 @@ public:
 protected:
   CompositorOGL* mCompositor;
   android::sp<android::GraphicBuffer> mGraphicBuffer;
   EGLImage mEGLImage;
   gfx::SurfaceFormat mFormat;
 };
 
 class GrallocTextureHostOGL : public TextureHost
+#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
+                            , public TextureHostOGL
+#endif
 {
   friend class GrallocBufferActor;
 public:
   GrallocTextureHostOGL(uint64_t aID,
                         TextureFlags aFlags,
                         const NewSurfaceDescriptorGralloc& aDescriptor);
 
   virtual ~GrallocTextureHostOGL();
@@ -99,16 +102,23 @@ public:
 
   virtual LayerRenderState GetRenderState() MOZ_OVERRIDE;
 
   virtual NewTextureSource* GetTextureSources() MOZ_OVERRIDE
   {
     return mTextureSource;
   }
 
+#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
+  virtual TextureHostOGL* AsHostOGL() MOZ_OVERRIDE
+  {
+    return this;
+  }
+#endif
+
   virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() MOZ_OVERRIDE;
 
   virtual void SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData) MOZ_OVERRIDE;
 
   bool IsValid() const;
 
   virtual const char* Name() MOZ_OVERRIDE { return "GrallocTextureHostOGL"; }
 
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -196,16 +196,17 @@ CompositableDataGonkOGL::gl() const
 
 void CompositableDataGonkOGL::SetCompositor(Compositor* aCompositor)
 {
   mCompositor = static_cast<CompositorOGL*>(aCompositor);
 }
 
 void CompositableDataGonkOGL::ClearData()
 {
+  CompositableBackendSpecificData::ClearData();
   DeleteTextureIfPresent();
 }
 
 GLuint CompositableDataGonkOGL::GetTexture()
 {
   if (!mTexture) {
     if (gl()->MakeCurrent()) {
       gl()->fGenTextures(1, &mTexture);
@@ -219,16 +220,52 @@ CompositableDataGonkOGL::DeleteTextureIf
 {
   if (mTexture) {
     if (gl()->MakeCurrent()) {
       gl()->fDeleteTextures(1, &mTexture);
     }
   }
 }
 
+#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
+bool
+TextureHostOGL::SetReleaseFence(const android::sp<android::Fence>& aReleaseFence)
+{
+  if (!aReleaseFence.get() || !aReleaseFence->isValid()) {
+    return false;
+  }
+
+  if (!mReleaseFence.get()) {
+    mReleaseFence = aReleaseFence;
+  } else {
+    android::sp<android::Fence> mergedFence = android::Fence::merge(
+                  android::String8::format("TextureHostOGL"),
+                  mReleaseFence, aReleaseFence);
+    if (!mergedFence.get()) {
+      // synchronization is broken, the best we can do is hope fences
+      // signal in order so the new fence will act like a union.
+      // This error handling is same as android::ConsumerBase does.
+      mReleaseFence = aReleaseFence;
+      return false;
+    }
+    mReleaseFence = mergedFence;
+  }
+  return true;
+}
+
+android::sp<android::Fence>
+TextureHostOGL::GetAndResetReleaseFence()
+{
+  android::sp<android::Fence> fence = mReleaseFence;
+  mReleaseFence = android::Fence::NO_FENCE;
+  return fence;
+}
+#endif
+
+
 bool
 TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
                                      TextureFlags aFlags,
                                      nsIntRegion* aDestRegion,
                                      gfx::IntPoint* aSrcOffset)
 {
   MOZ_ASSERT(mGL);
   if (!mGL) {
@@ -1276,16 +1313,25 @@ GrallocDeprecatedTextureHostOGL::Lock()
 
 void
 GrallocDeprecatedTextureHostOGL::Unlock()
 {
   // Lock/Unlock is done internally when binding the gralloc buffer to a gl texture
 }
 
 void
+GrallocDeprecatedTextureHostOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData)
+{
+  mCompositableBackendData = aBackendData;
+  if (aBackendData) {
+    aBackendData->SetCurrentReleaseFenceTexture(this);
+  }
+}
+
+void
 GrallocDeprecatedTextureHostOGL::SetBuffer(SurfaceDescriptor* aBuffer, ISurfaceAllocator* aAllocator)
 {
   MOZ_ASSERT(!mBuffer, "Will leak the old mBuffer");
 
   if (aBuffer != mBuffer) {
     // only done for hacky fix in gecko 23 for bug 862324.
     // Doing this in SwapTextures is not enough, as the crash could occur right after SetBuffer.
     RemoveDeprecatedTextureHostFromGrallocBufferActor(this, mBuffer);
@@ -1315,17 +1361,18 @@ GrallocDeprecatedTextureHostOGL::GetRend
     if (mIsRBSwapped) {
       flags |= LAYER_RENDER_STATE_FORMAT_RB_SWAP;
     }
 
     nsIntSize bufferSize(mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight());
 
     return LayerRenderState(mGraphicBuffer.get(),
                             bufferSize,
-                            flags);
+                            flags,
+                            this);
   }
 
   return LayerRenderState();
 }
 
 GLuint
 GrallocDeprecatedTextureHostOGL::GetGLTexture()
 {
--- a/gfx/layers/opengl/TextureHostOGL.h
+++ b/gfx/layers/opengl/TextureHostOGL.h
@@ -27,16 +27,19 @@
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_WARNING
 #include "nsISupportsImpl.h"            // for TextureImage::Release, etc
 #include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "OGLShaderProgram.h"           // for ShaderProgramType, etc
 #ifdef MOZ_WIDGET_GONK
 #include <ui/GraphicBuffer.h>
+#if ANDROID_VERSION >= 18
+#include <ui/Fence.h>
+#endif
 #endif
 
 class gfxImageSurface;
 class gfxReusableSurfaceWrapper;
 class nsIntRegion;
 struct nsIntPoint;
 struct nsIntRect;
 struct nsIntSize;
@@ -138,16 +141,39 @@ public:
   virtual GLenum GetWrapMode() const = 0;
 
   virtual gfx3DMatrix GetTextureTransform() { return gfx3DMatrix(); }
 
   virtual TextureImageDeprecatedTextureHostOGL* AsTextureImageDeprecatedTextureHost() { return nullptr; }
 };
 
 /**
+ * TextureHostOGL provides the necessary API for platform specific composition.
+ */
+class TextureHostOGL
+{
+public:
+#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
+
+  /**
+   * Store a fence that will signal when the current buffer is no longer being read.
+   * Similar to android's GLConsumer::setReleaseFence()
+   */
+  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();
+protected:
+  android::sp<android::Fence> mReleaseFence;
+#endif
+};
+
+/**
  * A TextureSource backed by a TextureImage.
  *
  * Depending on the underlying TextureImage, may support texture tiling, so
  * make sure to check AsTileIterator() and use the texture accordingly.
  *
  * This TextureSource can be used without a TextureHost and manage it's own
  * GL texture(s).
  */
@@ -831,16 +857,19 @@ private:
 
 // For direct texturing with gralloc buffers. The corresponding DeprecatedTextureClient is DeprecatedTextureClientShmem,
 // which automatically gets gralloc when it can, in which case the compositor sees that the
 // SurfaceDescriptor is gralloc, and decides to use a GrallocDeprecatedTextureHostOGL to do direct texturing,
 // saving the cost of a texture upload.
 class GrallocDeprecatedTextureHostOGL
   : public DeprecatedTextureHost
   , public TextureSourceOGL
+#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
+  , public TextureHostOGL
+#endif
 {
 public:
   GrallocDeprecatedTextureHostOGL();
 
   ~GrallocDeprecatedTextureHostOGL();
 
   virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
 
@@ -878,16 +907,25 @@ public:
   void BindTexture(GLenum aTextureUnit) MOZ_OVERRIDE;
   void UnbindTexture() MOZ_OVERRIDE {}
 
   virtual TextureSourceOGL* AsSourceOGL() MOZ_OVERRIDE
   {
     return this;
   }
 
+#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
+  virtual TextureHostOGL* AsHostOGL() MOZ_OVERRIDE
+  {
+    return this;
+  }
+#endif
+
+  virtual void SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData);
+
   // only overridden for hacky fix in gecko 23 for bug 862324
   // see bug 865908 about fixing this.
   virtual void SetBuffer(SurfaceDescriptor* aBuffer, ISurfaceAllocator* aAllocator) MOZ_OVERRIDE;
 
   // used only for hacky fix in gecko 23 for bug 862324
   virtual void ForgetBuffer()
   {
     if (mBuffer) {
--- a/widget/gonk/HwcComposer2D.cpp
+++ b/widget/gonk/HwcComposer2D.cpp
@@ -14,21 +14,23 @@
  * limitations under the License.
  */
 
 #include <android/log.h>
 #include <string.h>
 
 #include "libdisplay/GonkDisplay.h"
 #include "Framebuffer.h"
+#include "GLContext.h"                  // for GLContext
 #include "HwcUtils.h"
 #include "HwcComposer2D.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/PLayerTransaction.h"
 #include "mozilla/layers/ShadowLayerUtilsGralloc.h"
+#include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
 #include "mozilla/StaticPtr.h"
 #include "cutils/properties.h"
 
 #if ANDROID_VERSION >= 18
 #include "libdisplay/FramebufferSurface.h"
 #endif
 
 #define LOG_TAG "HWComposer"
@@ -58,17 +60,20 @@ namespace mozilla {
 static StaticRefPtr<HwcComposer2D> sInstance;
 
 HwcComposer2D::HwcComposer2D()
     : mMaxLayerCount(0)
     , mList(nullptr)
     , mHwc(nullptr)
     , mColorFill(false)
     , mRBSwapSupport(false)
-    , mPrevRetireFence(-1)
+#if ANDROID_VERSION >= 18
+    , mPrevRetireFence(Fence::NO_FENCE)
+    , mPrevDisplayFence(Fence::NO_FENCE)
+#endif
     , mPrepared(false)
 {
 }
 
 HwcComposer2D::~HwcComposer2D() {
     free(mList);
 }
 
@@ -573,48 +578,41 @@ HwcComposer2D::Prepare(buffer_handle_t f
 bool
 HwcComposer2D::Commit()
 {
     hwc_display_contents_1_t *displays[HWC_NUM_DISPLAY_TYPES] = { nullptr };
     displays[HWC_DISPLAY_PRIMARY] = mList;
 
     int err = mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays);
 
-    // To avoid tearing, workaround for missing releaseFenceFd
-    // waits in Gecko layers, see Bug 925444.
-    if (!mPrevReleaseFds.IsEmpty()) {
-        // Wait for previous retire Fence to signal.
-        // Denotes contents on display have been replaced.
-        // For buffer-sync, framework should not over-write
-        // prev buffers until we close prev releaseFenceFds
-        sp<Fence> fence = new Fence(mPrevRetireFence);
-        if (fence->wait(1000) == -ETIME) {
-            LOGE("Wait timed-out for retireFenceFd %d", mPrevRetireFence);
-        }
-        for (int i = 0; i < mPrevReleaseFds.Length(); i++) {
-            close(mPrevReleaseFds[i]);
-        }
-        close(mPrevRetireFence);
-        mPrevReleaseFds.Clear();
-    }
+
+    mPrevDisplayFence = mPrevRetireFence;
+    mPrevRetireFence = Fence::NO_FENCE;
 
     for (uint32_t j=0; j < (mList->numHwLayers - 1); j++) {
         if (mList->hwLayers[j].releaseFenceFd >= 0) {
-            mPrevReleaseFds.AppendElement(mList->hwLayers[j].releaseFenceFd);
+            int fd = mList->hwLayers[j].releaseFenceFd;
+            mList->hwLayers[j].releaseFenceFd = -1;
+            sp<Fence> fence = new Fence(fd);
+
+            LayerRenderState state = mHwcLayerMap[j]->GetLayer()->GetRenderState();
+            if (!state.mTexture) {
+                continue;
+            }
+            TextureHostOGL* texture = state.mTexture->AsHostOGL();
+            if (!texture) {
+                continue;
+            }
+            texture->SetReleaseFence(fence);
         }
     }
 
     if (mList->retireFenceFd >= 0) {
-        if (!mPrevReleaseFds.IsEmpty()) {
-            mPrevRetireFence = mList->retireFenceFd;
-        } else { // GPU Composition
-            close(mList->retireFenceFd);
-        }
+        mPrevRetireFence = new Fence(mList->retireFenceFd);
     }
-
     mPrepared = false;
     return !err;
 }
 
 void
 HwcComposer2D::Reset()
 {
     LOGD("hwcomposer is already prepared, reset with null set");
--- a/widget/gonk/HwcComposer2D.h
+++ b/widget/gonk/HwcComposer2D.h
@@ -18,16 +18,19 @@
 #define mozilla_HwcComposer2D
 
 #include "Composer2D.h"
 #include "Layers.h"
 #include <vector>
 #include <list>
 
 #include <hardware/hwcomposer.h>
+#if ANDROID_VERSION >= 18
+#include <ui/Fence.h>
+#endif
 
 namespace mozilla {
 
 namespace layers {
 class ContainerLayer;
 class Layer;
 }
 
@@ -77,17 +80,19 @@ private:
     hwc_surface_t           mSur;
     nsIntRect               mScreenRect;
     int                     mMaxLayerCount;
     bool                    mColorFill;
     bool                    mRBSwapSupport;
     //Holds all the dynamically allocated RectVectors needed
     //to render the current frame
     std::list<RectVector>   mVisibleRegions;
-    nsTArray<int>           mPrevReleaseFds;
-    int                     mPrevRetireFence;
+#if ANDROID_VERSION >= 18
+    android::sp<android::Fence>       mPrevRetireFence;
+    android::sp<android::Fence>       mPrevDisplayFence;
+#endif
     nsTArray<layers::LayerComposite*> mHwcLayerMap;
     bool                    mPrepared;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_HwcComposer2D
--- a/widget/gonk/nativewindow/GonkNativeWindowJB.cpp
+++ b/widget/gonk/nativewindow/GonkNativeWindowJB.cpp
@@ -100,54 +100,55 @@ status_t GonkNativeWindow::setDefaultBuf
 }
 
 status_t GonkNativeWindow::setDefaultBufferFormat(uint32_t defaultFormat) {
     Mutex::Autolock _l(mMutex);
     return mBufferQueue->setDefaultBufferFormat(defaultFormat);
 }
 
 already_AddRefed<GraphicBufferLocked>
-GonkNativeWindow::getCurrentBuffer()
-{
+GonkNativeWindow::getCurrentBuffer() {
     Mutex::Autolock _l(mMutex);
     GonkBufferQueue::BufferItem item;
 
     // In asynchronous mode the list is guaranteed to be one buffer
     // deep, while in synchronous mode we use the oldest buffer.
     status_t err = acquireBufferLocked(&item);
     if (err != NO_ERROR) {
         return NULL;
     }
 
   nsRefPtr<GraphicBufferLocked> ret =
     new CameraGraphicBuffer(this, item.mBuf, mBufferQueue->getGeneration(), item.mSurfaceDescriptor);
   return ret.forget();
 }
 
 bool
-GonkNativeWindow::returnBuffer(uint32_t aIndex, uint32_t aGeneration) {
-    BI_LOGD("GonkNativeWindow::returnBuffer: slot=%d (generation=%d)", aIndex, aGeneration);
+GonkNativeWindow::returnBuffer(uint32_t index, uint32_t generation, const sp<Fence>& fence) {
+    BI_LOGD("GonkNativeWindow::returnBuffer: slot=%d (generation=%d)", index, generation);
     Mutex::Autolock lock(mMutex);
 
-    if (aGeneration != mBufferQueue->getGeneration()) {
+    if (generation != mBufferQueue->getGeneration()) {
         BI_LOGD("returnBuffer: buffer is from generation %d (current is %d)",
-          aGeneration, mBufferQueue->getGeneration());
+          generation, mBufferQueue->getGeneration());
         return false;
     }
 
-    status_t err = releaseBufferLocked(aIndex);
+    status_t err;
+    err = addReleaseFenceLocked(index, fence);
+
+    err = releaseBufferLocked(index);
     if (err != NO_ERROR) {
         return false;
     }
   return true;
 }
 
 mozilla::layers::SurfaceDescriptor *
-GonkNativeWindow::getSurfaceDescriptorFromBuffer(ANativeWindowBuffer* buffer)
-{
+GonkNativeWindow::getSurfaceDescriptorFromBuffer(ANativeWindowBuffer* buffer) {
     Mutex::Autolock lock(mMutex);
     return mBufferQueue->getSurfaceDescriptorFromBuffer(buffer);
 }
 void GonkNativeWindow::setNewFrameCallback(
         GonkNativeWindowNewFrameCallback* aCallback) {
     BI_LOGD("setNewFrameCallback");
     Mutex::Autolock lock(mMutex);
     mNewFrameCallback = aCallback;
@@ -156,9 +157,27 @@ void GonkNativeWindow::setNewFrameCallba
 void GonkNativeWindow::onFrameAvailable() {
     GonkConsumerBase::onFrameAvailable();
 
     if (mNewFrameCallback) {
       mNewFrameCallback->OnNewFrame();
     }
 }
 
+void CameraGraphicBuffer::Unlock() {
+    if (mLocked) {
+        android::sp<android::Fence> fence;
+        fence = mReleaseFenceHandle.IsValid() ? mReleaseFenceHandle.mFence : Fence::NO_FENCE;
+        // The window might have been destroyed. The buffer is no longer
+        // valid at that point.
+        sp<GonkNativeWindow> window = mNativeWindow.promote();
+        if (window.get() && window->returnBuffer(mIndex, mGeneration, fence)) {
+            mLocked = false;
+        } else {
+            // If the window doesn't exist any more, release the buffer
+            // directly.
+            ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton();
+            ibc->DeallocSurfaceDescriptorGralloc(mSurfaceDescriptor);
+        }
+    }
+}
+
 } // namespace android
--- a/widget/gonk/nativewindow/GonkNativeWindowJB.h
+++ b/widget/gonk/nativewindow/GonkNativeWindowJB.h
@@ -111,17 +111,17 @@ class GonkNativeWindow: public GonkConsu
     // in dequeueBuffer
     status_t setDefaultBufferFormat(uint32_t defaultFormat);
 
     // Get next frame from the queue, caller owns the returned buffer.
     already_AddRefed<GraphicBufferLocked> getCurrentBuffer();
 
     // Return the buffer to the queue and mark it as FREE. After that
     // the buffer is useable again for the decoder.
-    bool returnBuffer(uint32_t index, uint32_t generation);
+    bool returnBuffer(uint32_t index, uint32_t generation, const sp<Fence>& fence);
 
     SurfaceDescriptor* getSurfaceDescriptorFromBuffer(ANativeWindowBuffer* buffer);
 
     void setNewFrameCallback(GonkNativeWindowNewFrameCallback* aCallback);
 
 protected:
     virtual void onFrameAvailable();
 
@@ -151,32 +151,17 @@ public:
 
     virtual ~CameraGraphicBuffer()
     {
         DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
     }
 
     // Unlock either returns the buffer to the native window or
     // destroys the buffer if the window is already released.
-    virtual void Unlock() MOZ_OVERRIDE
-    {
-        if (mLocked) {
-            // The window might have been destroyed. The buffer is no longer
-            // valid at that point.
-            sp<GonkNativeWindow> window = mNativeWindow.promote();
-            if (window.get() && window->returnBuffer(mIndex, mGeneration)) {
-                mLocked = false;
-            } else {
-                // If the window doesn't exist any more, release the buffer
-                // directly.
-                ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton();
-                ibc->DeallocSurfaceDescriptorGralloc(mSurfaceDescriptor);
-            } 
-        }
-    }
+    virtual void Unlock() MOZ_OVERRIDE;
 
 protected:
     wp<GonkNativeWindow> mNativeWindow;
     uint32_t mIndex;
     uint32_t mGeneration;
     bool mLocked;
 };