Bug 977880 - Handle ReleaseFence on tiled thebes layer r=cwiiis,nical,BenWa
authorSotaro Ikeda <sikeda@mozilla.com>
Wed, 26 Mar 2014 18:01:15 -0700
changeset 175569 19bcfceeb47716255da3ee5f62e04daf4c6e27a5
parent 175405 5953c846bb5aba0650a67400be524fde32097901
child 175570 f57540c2b7a59de88475c4a0a51cb3ca343d8952
push id26493
push usercbook@mozilla.com
push dateThu, 27 Mar 2014 13:08:27 +0000
treeherdermozilla-central@ab29e6fff0b9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscwiiis, nical, BenWa
bugs977880
milestone31.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 977880 - Handle ReleaseFence on tiled thebes layer r=cwiiis,nical,BenWa
gfx/layers/TiledLayerBuffer.h
gfx/layers/client/SimpleTextureClientPool.cpp
gfx/layers/client/SimpleTextureClientPool.h
gfx/layers/client/TextureClient.cpp
gfx/layers/client/TextureClient.h
gfx/layers/client/TextureClientPool.cpp
gfx/layers/client/TextureClientPool.h
gfx/layers/composite/TextureHost.cpp
gfx/layers/composite/TextureHost.h
gfx/layers/composite/ThebesLayerComposite.cpp
gfx/layers/composite/TiledContentHost.cpp
gfx/layers/composite/TiledContentHost.h
gfx/layers/ipc/CompositableTransactionParent.cpp
gfx/layers/ipc/PTexture.ipdl
gfx/layers/opengl/CompositorOGL.cpp
gfx/layers/opengl/GrallocTextureClient.cpp
gfx/layers/opengl/GrallocTextureClient.h
gfx/layers/opengl/GrallocTextureHost.h
gfx/layers/opengl/TextureHostOGL.cpp
gfx/layers/opengl/TextureHostOGL.h
widget/gonk/libdisplay/GonkDisplay.h
--- a/gfx/layers/TiledLayerBuffer.h
+++ b/gfx/layers/TiledLayerBuffer.h
@@ -14,16 +14,20 @@
 #include <stdint.h>                     // for uint16_t, uint32_t
 #include <sys/types.h>                  // for int32_t
 #include "nsDebug.h"                    // for NS_ABORT_IF_FALSE
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for nsTArray
 
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+#include <ui/Fence.h>
+#endif
+
 namespace mozilla {
 namespace layers {
 
 // An abstract implementation of a tile buffer. This code covers the logic of
 // moving and reusing tiles and leaves the validation up to the implementor. To
 // avoid the overhead of virtual dispatch, we employ the curiously recurring
 // template pattern.
 //
@@ -201,16 +205,24 @@ public:
   virtual void UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
                                    const SurfaceDescriptorTiles& aTiledDescriptor) = 0;
 
   /**
    * If some part of the buffer is being rendered at a lower precision, this
    * returns that region. If it is not, an empty region will be returned.
    */
   virtual const nsIntRegion& GetValidLowPrecisionRegion() const = 0;
+
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+  /**
+   * Store a fence that will signal when the current buffer is no longer being read.
+   * Similar to android's GLConsumer::setReleaseFence()
+   */
+  virtual void SetReleaseFence(const android::sp<android::Fence>& aReleaseFence) = 0;
+#endif
 };
 
 // Normal integer division truncates towards zero,
 // we instead want to floor to hangle negative numbers.
 static inline int floor_div(int a, int b)
 {
   int rem = a % b;
   int div = a/b;
--- a/gfx/layers/client/SimpleTextureClientPool.cpp
+++ b/gfx/layers/client/SimpleTextureClientPool.cpp
@@ -59,16 +59,17 @@ SimpleTextureClientPool::SimpleTextureCl
 
 TemporaryRef<TextureClient>
 SimpleTextureClientPool::GetTextureClient(bool aAutoRecycle)
 {
   // Try to fetch a client from the pool
   RefPtr<TextureClient> textureClient;
   if (mAvailableTextureClients.size()) {
     textureClient = mAvailableTextureClients.top();
+    textureClient->WaitReleaseFence();
     mAvailableTextureClients.pop();
     RECYCLE_LOG("%s Skip allocate (%i left), returning %p\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), mAvailableTextureClients.size(), textureClient.get());
 
   } else {
     // No unused clients in the pool, create one
     if (gfxPrefs::ForceShmemTiles()) {
       textureClient = TextureClient::CreateBufferTextureClient(mSurfaceAllocator,
         mFormat, TEXTURE_IMMEDIATE_UPLOAD | TEXTURE_RECYCLE, gfx::BackendType::NONE);
--- a/gfx/layers/client/SimpleTextureClientPool.h
+++ b/gfx/layers/client/SimpleTextureClientPool.h
@@ -74,16 +74,19 @@ private:
   //     -- the thinking is that recently-used elements are most likely
   //     to be in any data cache, so we can get some wins there
   //     -- the converse though is that if there is some GPU locking going on
   //     the most recently used elements may also have the most contention;
   //     if we see that, then we should use push_back() to add new elements
   //   when we shrink this list, we use pop(), but should use pop_back() to
   //   nuke the oldest.
   // We may need to switch to a std::deque
+  // On b2g gonk, std::queue might be a better choice.
+  // On ICS, fence wait happens implicitly before drawing.
+  // Since JB, fence wait happens explicitly when fetching a client from the pool.
   std::stack<RefPtr<TextureClient> > mAvailableTextureClients;
   std::list<RefPtr<TextureClient> > mOutstandingTextureClients;
 
   nsRefPtr<nsITimer> mTimer;
   RefPtr<ISurfaceAllocator> mSurfaceAllocator;
 };
 
 }
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -91,19 +91,27 @@ public:
 
   ~TextureChild()
   {
     MOZ_COUNT_DTOR(TextureChild);
   }
 
   bool Recv__delete__() MOZ_OVERRIDE;
 
-  bool RecvCompositorRecycle()
+  bool RecvCompositorRecycle(const MaybeFenceHandle& aFence)
   {
     RECYCLE_LOG("Receive recycle %p (%p)\n", mTextureClient, mWaitForRecycle.get());
+    if (aFence.type() != aFence.Tnull_t) {
+      FenceHandle fence = aFence.get_FenceHandle();
+      if (fence.IsValid() && mTextureClient) {
+        mTextureClient->SetReleaseFenceHandle(aFence);
+        // HWC might not provide Fence.
+        // In this case, HWC implicitly handles buffer's fence.
+      }
+    }
     mWaitForRecycle = nullptr;
     return true;
   }
 
   void WaitForCompositorRecycle()
   {
     mWaitForRecycle = mTextureClient;
     RECYCLE_LOG("Wait for recycle %p\n", mWaitForRecycle.get());
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -335,16 +335,23 @@ public:
 
   virtual void SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle) {}
 
   const FenceHandle& GetReleaseFenceHandle() const
   {
     return mReleaseFenceHandle;
   }
 
+  /**
+   * Wait until the current buffer is no longer being read.
+   *
+   * Platform support is necessary. gonk JB supports this function.
+   */
+  virtual void WaitReleaseFence() {}
+
 private:
   /**
    * Called once, just before the destructor.
    *
    * Here goes the shut-down code that uses virtual methods.
    * Must only be called by Release().
    */
   void Finalize();
--- a/gfx/layers/client/TextureClientPool.cpp
+++ b/gfx/layers/client/TextureClientPool.cpp
@@ -39,16 +39,17 @@ TemporaryRef<TextureClient>
 TextureClientPool::GetTextureClient()
 {
   mOutstandingClients++;
 
   // Try to fetch a client from the pool
   RefPtr<TextureClient> textureClient;
   if (mTextureClients.size()) {
     textureClient = mTextureClients.top();
+    textureClient->WaitReleaseFence();
     mTextureClients.pop();
     return textureClient;
   }
 
   // We're increasing the number of outstanding TextureClients without reusing a
   // client, we may need to free a deferred-return TextureClient.
   ShrinkToMaximumSize();
 
--- a/gfx/layers/client/TextureClientPool.h
+++ b/gfx/layers/client/TextureClientPool.h
@@ -94,16 +94,19 @@ private:
   // to remain active.
   static const uint32_t sMaxTextureClients = 50;
 
   gfx::SurfaceFormat mFormat;
   gfx::IntSize mSize;
 
   uint32_t mOutstandingClients;
 
+  // On b2g gonk, std::queue might be a better choice.
+  // On ICS, fence wait happens implicitly before drawing.
+  // Since JB, fence wait happens explicitly when fetching a client from the pool.
   std::stack<RefPtr<TextureClient> > mTextureClients;
   std::stack<RefPtr<TextureClient> > mTextureClientsDeferred;
   nsRefPtr<nsITimer> mTimer;
   RefPtr<ISurfaceAllocator> mSurfaceAllocator;
 };
 
 }
 }
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -9,16 +9,17 @@
 #include "gfx2DGlue.h"                  // for ToIntSize
 #include "gfxImageSurface.h"            // for gfxImageSurface
 #include "mozilla/gfx/2D.h"             // for DataSourceSurface, Factory
 #include "mozilla/ipc/Shmem.h"          // for Shmem
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
+#include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
 #ifdef MOZ_X11
 #include "mozilla/layers/X11TextureHost.h"
 #endif
 #include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "nsAString.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsPrintfCString.h"            // for nsPrintfCString
 #include "mozilla/layers/PTextureParent.h"
@@ -255,16 +256,25 @@ CreateBackendIndependentTextureHost(cons
     default: {
       NS_WARNING("No backend independent TextureHost for this descriptor type");
     }
   }
   return result;
 }
 
 void
+TextureHost::CompositorRecycle()
+{
+  if (!mActor) {
+    return;
+  }
+  static_cast<TextureParent*>(mActor)->CompositorRecycle();
+}
+
+void
 TextureHost::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData)
 {
     mCompositableBackendData = aBackendData;
 }
 
 
 TextureHost::TextureHost(TextureFlags aFlags)
     : mActor(nullptr)
@@ -740,17 +750,30 @@ static void RecycleCallback(TextureHost*
   TextureParent* tp = reinterpret_cast<TextureParent*>(aClosure);
   tp->CompositorRecycle();
 }
 
 void
 TextureParent::CompositorRecycle()
 {
   mTextureHost->ClearRecycleCallback();
-  mozilla::unused << SendCompositorRecycle();
+
+  MaybeFenceHandle handle = null_t();
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+  if (mTextureHost) {
+    TextureHostOGL* hostOGL = mTextureHost->AsHostOGL();
+    android::sp<android::Fence> fence = hostOGL->GetAndResetReleaseFence();
+    if (fence.get() && fence->isValid()) {
+      handle = FenceHandle(fence);
+      // HWC might not provide Fence.
+      // In this case, HWC implicitly handles buffer's fence.
+    }
+  }
+#endif
+  mozilla::unused << SendCompositorRecycle(handle);
 
   // Don't forget to prepare for the next reycle
   mWaitForClientRecycle = mTextureHost;
 }
 
 bool
 TextureParent::RecvClientRecycle()
 {
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -283,16 +283,26 @@ public:
   /**
    * Factory method.
    */
   static TemporaryRef<TextureHost> Create(const SurfaceDescriptor& aDesc,
                                           ISurfaceAllocator* aDeallocator,
                                           TextureFlags aFlags);
 
   /**
+   * Tell to TextureChild that TextureHost is recycled.
+   * This function should be called from TextureHost's RecycleCallback.
+   * If SetRecycleCallback is set to TextureHost.
+   * TextureHost can be recycled by calling RecycleCallback
+   * when reference count becomes one.
+   * One reference count is always added by TextureChild.
+   */
+  void CompositorRecycle();
+
+  /**
    * Lock the texture host for compositing.
    */
   virtual bool Lock() { return true; }
 
   /**
    * Unlock the texture host after compositing.
    */
   virtual void Unlock() {}
--- a/gfx/layers/composite/ThebesLayerComposite.cpp
+++ b/gfx/layers/composite/ThebesLayerComposite.cpp
@@ -86,17 +86,20 @@ Layer*
 ThebesLayerComposite::GetLayer()
 {
   return this;
 }
 
 TiledLayerComposer*
 ThebesLayerComposite::GetTiledLayerComposer()
 {
-  MOZ_ASSERT(mBuffer && mBuffer->IsAttached());
+  if (!mBuffer) {
+    return nullptr;
+  }
+  MOZ_ASSERT(mBuffer->IsAttached());
   return mBuffer->AsTiledLayerComposer();
 }
 
 LayerRenderState
 ThebesLayerComposite::GetRenderState()
 {
   if (!mBuffer || !mBuffer->IsAttached() || mDestroyed) {
     return LayerRenderState();
--- a/gfx/layers/composite/TiledContentHost.cpp
+++ b/gfx/layers/composite/TiledContentHost.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TiledContentHost.h"
 #include "ThebesLayerComposite.h"       // for ThebesLayerComposite
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/Effects.h"     // for TexturedEffect, Effect, etc
+#include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
 #include "nsAString.h"
 #include "nsDebug.h"                    // for NS_WARNING
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsPrintfCString.h"            // for nsPrintfCString
 #include "nsRect.h"                     // for nsIntRect
 #include "nsSize.h"                     // for nsIntSize
 #include "mozilla/layers/TiledContentClient.h"
 
@@ -26,16 +27,22 @@ namespace layers {
 class Layer;
 
 TiledLayerBufferComposite::TiledLayerBufferComposite()
   : mFrameResolution(1.0)
   , mHasDoubleBufferedTiles(false)
   , mUninitialized(true)
 {}
 
+/* static */ void
+TiledLayerBufferComposite::RecycleCallback(TextureHost* textureHost, void* aClosure)
+{
+  textureHost->CompositorRecycle();
+}
+
 TiledLayerBufferComposite::TiledLayerBufferComposite(ISurfaceAllocator* aAllocator,
                                                      const SurfaceDescriptorTiles& aDescriptor,
                                                      const nsIntRegion& aOldPaintedRegion)
 {
   mUninitialized = false;
   mHasDoubleBufferedTiles = false;
   mValidRegion = aDescriptor.validRegion();
   mPaintedRegion = aDescriptor.paintedRegion();
@@ -51,16 +58,21 @@ TiledLayerBufferComposite::TiledLayerBuf
 
   const InfallibleTArray<TileDescriptor>& tiles = aDescriptor.tiles();
   for(size_t i = 0; i < tiles.Length(); i++) {
     RefPtr<TextureHost> texture;
     const TileDescriptor& tileDesc = tiles[i];
     switch (tileDesc.type()) {
       case TileDescriptor::TTexturedTileDescriptor : {
         texture = TextureHost::AsTextureHost(tileDesc.get_TexturedTileDescriptor().textureParent());
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+        if (!gfxPrefs::LayersUseSimpleTiles()) {
+          texture->SetRecycleCallback(RecycleCallback, nullptr);
+        }
+#endif
         const TileLock& ipcLock = tileDesc.get_TexturedTileDescriptor().sharedLock();
         nsRefPtr<gfxSharedReadLock> sharedLock;
         if (ipcLock.type() == TileLock::TShmemSection) {
           sharedLock = gfxShmSharedReadLock::Open(aAllocator, ipcLock.get_ShmemSection());
         } else {
           sharedLock = reinterpret_cast<gfxMemorySharedReadLock*>(ipcLock.get_uintptr_t());
           if (sharedLock) {
             // The corresponding AddRef is in TiledClient::GetTileDescriptor
@@ -155,16 +167,33 @@ TiledLayerBufferComposite::SetCompositor
     return;
   }
   for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
     if (mRetainedTiles[i].IsPlaceholderTile()) continue;
     mRetainedTiles[i].mTextureHost->SetCompositor(aCompositor);
   }
 }
 
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+void
+TiledLayerBufferComposite::SetReleaseFence(const android::sp<android::Fence>& aReleaseFence)
+{
+  for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
+    if (!mRetainedTiles[i].mTextureHost) {
+      continue;
+    }
+    TextureHostOGL* texture = mRetainedTiles[i].mTextureHost->AsHostOGL();
+    if (!texture) {
+      continue;
+    }
+    texture->SetReleaseFence(new android::Fence(aReleaseFence->dup()));
+  }
+}
+#endif
+
 TiledContentHost::TiledContentHost(const TextureInfo& aTextureInfo)
   : ContentHost(aTextureInfo)
   , mTiledBuffer(TiledLayerBufferComposite())
   , mLowPrecisionTiledBuffer(TiledLayerBufferComposite())
   , mOldTiledBuffer(TiledLayerBufferComposite())
   , mOldLowPrecisionTiledBuffer(TiledLayerBufferComposite())
   , mPendingUpload(false)
   , mPendingLowPrecisionUpload(false)
--- a/gfx/layers/composite/TiledContentHost.h
+++ b/gfx/layers/composite/TiledContentHost.h
@@ -22,16 +22,20 @@
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/LayersTypes.h"  // for LayerRenderState, etc
 #include "mozilla/layers/TextureHost.h"  // for DeprecatedTextureHost
 #include "mozilla/layers/TiledContentClient.h"
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nscore.h"                     // for nsACString
 
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+#include <ui/Fence.h>
+#endif
+
 class gfxReusableSurfaceWrapper;
 struct nsIntPoint;
 struct nsIntRect;
 struct nsIntSize;
 
 namespace mozilla {
 namespace gfx {
 class Matrix4x4;
@@ -128,16 +132,24 @@ public:
   void Upload();
 
   void SetCompositor(Compositor* aCompositor);
 
   bool HasDoubleBufferedTiles() { return mHasDoubleBufferedTiles; }
 
   bool IsValid() const { return !mUninitialized; }
 
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+  virtual void SetReleaseFence(const android::sp<android::Fence>& aReleaseFence);
+#endif
+
+  // Recycle callback for TextureHost.
+  // Used when TiledContentClient is present in client side.
+  static void RecycleCallback(TextureHost* textureHost, void* aClosure);
+
 protected:
   TileHost ValidateTile(TileHost aTile,
                         const nsIntPoint& aTileRect,
                         const nsIntRegion& dirtyRect);
 
   // do nothing, the desctructor in the texture host takes care of releasing resources
   void ReleaseTile(TileHost aTile) {}
 
@@ -238,16 +250,28 @@ public:
 #ifdef MOZ_DUMP_PAINTING
   virtual void Dump(FILE* aFile=nullptr,
                     const char* aPrefix="",
                     bool aDumpHtml=false) MOZ_OVERRIDE;
 #endif
 
   virtual void PrintInfo(nsACString& aTo, const char* aPrefix);
 
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+  /**
+   * Store a fence that will signal when the current buffer is no longer being read.
+   * Similar to android's GLConsumer::setReleaseFence()
+   */
+  virtual void SetReleaseFence(const android::sp<android::Fence>& aReleaseFence)
+  {
+    mTiledBuffer.SetReleaseFence(aReleaseFence);
+    mLowPrecisionTiledBuffer.SetReleaseFence(aReleaseFence);
+  }
+#endif
+
 private:
   void RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
                          const nsIntRegion& aValidRegion,
                          EffectChain& aEffectChain,
                          float aOpacity,
                          const gfx::Filter& aFilter,
                          const gfx::Rect& aClipRect,
                          const nsIntRegion& aMaskRegion,
--- a/gfx/layers/ipc/CompositableTransactionParent.cpp
+++ b/gfx/layers/ipc/CompositableTransactionParent.cpp
@@ -299,17 +299,17 @@ CompositableParentManager::ReceiveCompos
     default: {
       MOZ_ASSERT(false, "bad type");
     }
   }
 
   return true;
 }
 
-#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
 void
 CompositableParentManager::ReturnTextureDataIfNecessary(CompositableHost* aCompositable,
                                                         EditReplyVector& replyv,
                                                         PCompositableParent* aParent)
 {
   if (!aCompositable || !aCompositable->GetCompositableBackendSpecificData()) {
     return;
   }
--- a/gfx/layers/ipc/PTexture.ipdl
+++ b/gfx/layers/ipc/PTexture.ipdl
@@ -7,30 +7,36 @@
 
 include LayersSurfaces;
 include protocol PLayerTransaction;
 include protocol PImageBridge;
 include protocol PGrallocBuffer;
 include "mozilla/GfxMessageUtils.h";
 
 using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
+using struct mozilla::layers::FenceHandle from "mozilla/layers/FenceUtils.h";
 
 namespace mozilla {
 namespace layers {
 
+union MaybeFenceHandle {
+  FenceHandle;
+  null_t;
+};
+
 /**
  * PTexture is the IPDL glue between a TextureClient and a TextureHost.
  */
 sync protocol PTexture {
     manager PImageBridge or PLayerTransaction;
 
 child:
     async __delete__();
 
-    async CompositorRecycle();
+    async CompositorRecycle(MaybeFenceHandle aFence);
 
 parent:
 
     async ClientRecycle();
 
     /**
      * Asynchronously tell the Compositor side to remove the texture.
      */
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -22,32 +22,34 @@
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "gfxPrefs.h"                   // for gfxPrefs
 #include "gfxRect.h"                    // for gfxRect
 #include "gfxUtils.h"                   // for NextPowerOfTwo, gfxUtils, etc
 #include "mozilla/ArrayUtils.h"         // for ArrayLength
 #include "mozilla/Preferences.h"        // for Preferences
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4, Matrix
+#include "mozilla/layers/LayerManagerComposite.h"  // for LayerComposite, etc
 #include "mozilla/layers/CompositingRenderTargetOGL.h"
 #include "mozilla/layers/Effects.h"     // for EffectChain, TexturedEffect, etc
 #include "mozilla/layers/TextureHost.h"  // for TextureSource, etc
 #include "mozilla/layers/TextureHostOGL.h"  // for TextureSourceOGL, etc
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "nsAString.h"
 #include "nsIConsoleService.h"          // for nsIConsoleService, etc
 #include "nsIWidget.h"                  // for nsIWidget
 #include "nsLiteralString.h"            // for NS_LITERAL_STRING
 #include "nsMathUtils.h"                // for NS_roundf
 #include "nsRect.h"                     // for nsIntRect
 #include "nsServiceManagerUtils.h"      // for do_GetService
 #include "nsString.h"                   // for nsString, nsAutoCString, etc
 #include "DecomposeIntoNoRepeatTriangles.h"
 #include "ScopedGLHelpers.h"
 #include "GLReadTexImageHelper.h"
+#include "TiledLayerBuffer.h"           // for TiledLayerComposer
 
 #if MOZ_ANDROID_OMTC
 #include "TexturePoolOGL.h"
 #endif
 
 #include "GeckoProfiler.h"
 
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
@@ -1199,35 +1201,53 @@ CompositorOGL::EndFrame()
   mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
   mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
 }
 
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
 void
 CompositorOGL::SetFBAcquireFence(Layer* aLayer)
 {
+  // OpenGL does not provide ReleaseFence for rendering.
+  // Instead use FBAcquireFence as layer buffer's ReleaseFence
+  // to prevent flickering and tearing.
+  // FBAcquireFence is FramebufferSurface's AcquireFence.
+  // AcquireFence will be signaled when a buffer's content is available.
+  // See Bug 974152.
+
   if (!aLayer) {
     return;
   }
 
   const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion();
   if (visibleRegion.IsEmpty()) {
       return;
   }
 
-  // Set FBAcquireFence to child
+  // Set FBAcquireFence on ContainerLayer's childs
   ContainerLayer* container = aLayer->AsContainerLayer();
   if (container) {
     for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
       SetFBAcquireFence(child);
     }
     return;
   }
 
-  // Set FBAcquireFence to TexutreHost
+  // Set FBAcquireFence as tiles' ReleaseFence on TiledLayerComposer.
+  TiledLayerComposer* composer = nullptr;
+  LayerComposite* shadow = aLayer->AsLayerComposite();
+  if (shadow) {
+    composer = shadow->GetTiledLayerComposer();
+    if (composer) {
+      composer->SetReleaseFence(new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd()));
+      return;
+    }
+  }
+
+  // Set FBAcquireFence as layer buffer's ReleaseFence
   LayerRenderState state = aLayer->GetRenderState();
   if (!state.mTexture) {
     return;
   }
   TextureHostOGL* texture = state.mTexture->AsHostOGL();
   if (!texture) {
     return;
   }
--- a/gfx/layers/opengl/GrallocTextureClient.cpp
+++ b/gfx/layers/opengl/GrallocTextureClient.cpp
@@ -182,40 +182,47 @@ GrallocTextureClientOGL::SetReleaseFence
 {
   if (mBufferLocked) {
     mBufferLocked->SetReleaseFenceHandle(aReleaseFenceHandle);
   } else {
     mReleaseFenceHandle = aReleaseFenceHandle;
   }
 }
 
+void
+GrallocTextureClientOGL::WaitReleaseFence()
+{
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+   if (mReleaseFenceHandle.IsValid()) {
+     android::sp<Fence> fence = mReleaseFenceHandle.mFence;
+#if ANDROID_VERSION == 17
+     fence->waitForever(1000, "GrallocTextureClientOGL::Lock");
+     // 1000 is what Android uses. It is warning timeout ms.
+     // This timeous is removed since ANDROID_VERSION 18. 
+#else
+     fence->waitForever("GrallocTextureClientOGL::Lock");
+#endif
+     mReleaseFenceHandle = FenceHandle();
+   }
+#endif
+}
+
 bool
 GrallocTextureClientOGL::Lock(OpenMode aMode)
 {
   MOZ_ASSERT(IsValid());
   if (!IsValid() || !IsAllocated()) {
     return false;
   }
 
   if (mMappedBuffer) {
     return true;
   }
 
-#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
-  if (mReleaseFenceHandle.IsValid()) {
-    android::sp<Fence> fence = mReleaseFenceHandle.mFence;
-#if ANDROID_VERSION == 17
-    fence->waitForever(1000, "GrallocTextureClientOGL::Lock");
-    // 1000 is what Android uses. It is warning timeout ms.
-#else
-    fence->waitForever("GrallocTextureClientOGL::Lock");
-#endif
-    mReleaseFenceHandle = FenceHandle();
-  }
-#endif
+  WaitReleaseFence();
 
   uint32_t usage = 0;
   if (aMode & OPEN_READ) {
     usage |= GRALLOC_USAGE_SW_READ_OFTEN;
   }
   if (aMode & OPEN_WRITE) {
     usage |= GRALLOC_USAGE_SW_WRITE_OFTEN;
   }
--- a/gfx/layers/opengl/GrallocTextureClient.h
+++ b/gfx/layers/opengl/GrallocTextureClient.h
@@ -58,20 +58,17 @@ public:
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
 
   virtual bool UpdateSurface(gfxASurface* aSurface) MOZ_OVERRIDE;
 
   virtual TextureClientData* DropTextureData() MOZ_OVERRIDE;
 
   virtual void SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle) MOZ_OVERRIDE;
 
-  const FenceHandle& GetReleaseFenceHandle() const
-  {
-    return mReleaseFenceHandle;
-  }
+  virtual void WaitReleaseFence() MOZ_OVERRIDE;
 
   void InitWith(GrallocBufferActor* aActor, gfx::IntSize aSize);
 
   void SetTextureFlags(TextureFlags aFlags) { AddFlags(aFlags); }
 
   gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; }
 
   android::GraphicBuffer* GetGraphicBuffer()
--- a/gfx/layers/opengl/GrallocTextureHost.h
+++ b/gfx/layers/opengl/GrallocTextureHost.h
@@ -69,17 +69,17 @@ protected:
   android::sp<android::GraphicBuffer> mGraphicBuffer;
   EGLImage mEGLImage;
   GLuint mTexture;
   gfx::SurfaceFormat mFormat;
   bool mNeedsReset;
 };
 
 class GrallocTextureHostOGL : public TextureHost
-#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
                             , public TextureHostOGL
 #endif
 {
   friend class GrallocBufferActor;
 public:
   GrallocTextureHostOGL(TextureFlags aFlags,
                         const NewSurfaceDescriptorGralloc& aDescriptor);
 
@@ -105,17 +105,17 @@ public:
 
   virtual LayerRenderState GetRenderState() MOZ_OVERRIDE;
 
   virtual NewTextureSource* GetTextureSources() MOZ_OVERRIDE
   {
     return mTextureSource;
   }
 
-#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
   virtual TextureHostOGL* AsHostOGL() MOZ_OVERRIDE
   {
     return this;
   }
 #endif
 
   virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() MOZ_OVERRIDE;
 
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -192,21 +192,23 @@ CompositableDataGonkOGL::DeleteTextureIf
   if (mTexture) {
     if (gl()->MakeCurrent()) {
       gl()->fDeleteTextures(1, &mTexture);
     }
     mTexture = 0;
   }
 }
 
-#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
 bool
 TextureHostOGL::SetReleaseFence(const android::sp<android::Fence>& aReleaseFence)
 {
   if (!aReleaseFence.get() || !aReleaseFence->isValid()) {
+    // HWC might not provide Fence.
+    // In this case, HWC implicitly handles buffer's fence.
     return false;
   }
 
   if (!mReleaseFence.get()) {
     mReleaseFence = aReleaseFence;
   } else {
     android::sp<android::Fence> mergedFence = android::Fence::merge(
                   android::String8::format("TextureHostOGL"),
@@ -221,19 +223,21 @@ TextureHostOGL::SetReleaseFence(const an
     mReleaseFence = mergedFence;
   }
   return true;
 }
 
 android::sp<android::Fence>
 TextureHostOGL::GetAndResetReleaseFence()
 {
-  android::sp<android::Fence> fence = mReleaseFence;
+  // Hold previous ReleaseFence to prevent Fence delivery failure via gecko IPC.
+  mPrevReleaseFence = mReleaseFence;
+  // Reset current ReleaseFence.
   mReleaseFence = android::Fence::NO_FENCE;
-  return fence;
+  return mPrevReleaseFence;
 }
 #endif
 
 bool
 TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
                                      nsIntRegion* aDestRegion,
                                      gfx::IntPoint* aSrcOffset)
 {
--- a/gfx/layers/opengl/TextureHostOGL.h
+++ b/gfx/layers/opengl/TextureHostOGL.h
@@ -152,30 +152,38 @@ private:
 };
 
 /**
  * TextureHostOGL provides the necessary API for platform specific composition.
  */
 class TextureHostOGL
 {
 public:
-#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
 
   /**
    * 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;
+
+  /**
+   * 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
 };
 
 /**
  * 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.
--- a/widget/gonk/libdisplay/GonkDisplay.h
+++ b/widget/gonk/libdisplay/GonkDisplay.h
@@ -44,18 +44,27 @@ public:
     virtual bool SwapBuffers(EGLDisplay dpy, EGLSurface sur) = 0;
 
     virtual ANativeWindowBuffer* DequeueBuffer() = 0;
 
     virtual bool QueueBuffer(ANativeWindowBuffer* buf) = 0;
 
     virtual void UpdateFBSurface(EGLDisplay dpy, EGLSurface sur) = 0;
 
+    /**
+     * Set FramebufferSurface ReleaseFence's file descriptor.
+     * ReleaseFence will be signaled after the HWC has finished reading
+     * from a buffer.
+     */
     virtual void SetFBReleaseFd(int fd) = 0;
 
+    /**
+     * Get FramebufferSurface AcquireFence's file descriptor
+     * AcquireFence will be signaled when a buffer's content is available.
+     */
     virtual int GetPrevFBAcquireFd() = 0;
 
     float xdpi;
     uint32_t surfaceformat;
 };
 
 __attribute__ ((weak))
 GonkDisplay* GetGonkDisplay();