Bug 1029719 - Release TextureClient on correct thread. r=jmuizelaar, a=1.4+
authorSotaro Ikeda <sikeda@mozilla.com>
Fri, 27 Jun 2014 06:26:51 -0700
changeset 208726 7be237616cbe7a2510a9639550dcd0dcc05eeb65
parent 208725 a7503d2c73b371d8230d16e31cdc331903812f6c
child 208727 9886da8086bc4ae936924a2f657ae36e959090bd
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmuizelaar, 1
bugs1029719
milestone32.0a2
Bug 1029719 - Release TextureClient on correct thread. r=jmuizelaar, a=1.4+
gfx/layers/client/CompositableClient.cpp
gfx/layers/client/CompositableClient.h
gfx/layers/client/TextureClient.cpp
gfx/layers/client/TextureClient.h
gfx/layers/ipc/ISurfaceAllocator.h
gfx/layers/ipc/ImageBridgeChild.h
gfx/layers/ipc/ImageBridgeParent.cpp
gfx/layers/ipc/ImageBridgeParent.h
widget/gonk/nativewindow/GonkBufferQueueJB.cpp
widget/gonk/nativewindow/GonkBufferQueueKK.cpp
widget/gonk/nativewindow/GonkNativeWindowICS.cpp
--- a/gfx/layers/client/CompositableClient.cpp
+++ b/gfx/layers/client/CompositableClient.cpp
@@ -50,16 +50,27 @@ public:
     }
   }
 
   CompositableClient* mCompositableClient;
 
   uint64_t mAsyncID;
 };
 
+void
+RemoveTextureFromCompositableTracker::ReleaseTextureClient()
+{
+  if (mTextureClient) {
+    TextureClientReleaseTask* task = new TextureClientReleaseTask(mTextureClient);
+    RefPtr<ISurfaceAllocator> allocator = mTextureClient->GetAllocator();
+    mTextureClient = nullptr;
+    allocator->GetMessageLoop()->PostTask(FROM_HERE, task);
+  }
+}
+
 /* static */ void
 CompositableClient::TransactionCompleteted(PCompositableChild* aActor, uint64_t aTransactionId)
 {
   CompositableChild* child = static_cast<CompositableChild*>(aActor);
   child->TransactionCompleteted(aTransactionId);
 }
 
 /* static */ void
--- a/gfx/layers/client/CompositableClient.h
+++ b/gfx/layers/client/CompositableClient.h
@@ -37,42 +37,45 @@ public:
   RemoveTextureFromCompositableTracker()
   {
     MOZ_COUNT_CTOR(RemoveTextureFromCompositableTracker);
   }
 
   ~RemoveTextureFromCompositableTracker()
   {
     MOZ_COUNT_DTOR(RemoveTextureFromCompositableTracker);
+    ReleaseTextureClient();
   }
 
   virtual void Complete() MOZ_OVERRIDE
   {
-    // The TextureClient's recycling is postponed until the transaction
-    // complete.
-    mTextureClient = nullptr;
+    ReleaseTextureClient();
   }
 
   virtual void Cancel() MOZ_OVERRIDE
   {
-    mTextureClient = nullptr;
+    ReleaseTextureClient();
   }
 
   virtual void SetTextureClient(TextureClient* aTextureClient) MOZ_OVERRIDE
   {
+    ReleaseTextureClient();
     mTextureClient = aTextureClient;
   }
 
   virtual void SetReleaseFenceHandle(FenceHandle& aReleaseFenceHandle) MOZ_OVERRIDE
   {
     if (mTextureClient) {
       mTextureClient->SetReleaseFenceHandle(aReleaseFenceHandle);
     }
   }
 
+protected:
+  void ReleaseTextureClient();
+
 private:
   RefPtr<TextureClient> mTextureClient;
 };
 
 /**
  * CompositableClient manages the texture-specific logic for composite layers,
  * independently of the layer. It is the content side of a CompositableClient/
  * CompositableHost pair.
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -195,16 +195,17 @@ TextureClient::InitIPDLActor(Compositabl
   if (!ToSurfaceDescriptor(desc)) {
     return false;
   }
 
   mActor = static_cast<TextureChild*>(aForwarder->CreateTexture(desc, GetFlags()));
   MOZ_ASSERT(mActor);
   mActor->mForwarder = aForwarder;
   mActor->mTextureClient = this;
+  mAllocator = aForwarder;
   mShared = true;
   return mActor->IPCOpen();
 }
 
 PTextureChild*
 TextureClient::GetIPDLActor()
 {
   return mActor;
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -350,29 +350,55 @@ protected:
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) = 0;
 
   void AddFlags(TextureFlags  aFlags)
   {
     MOZ_ASSERT(!IsSharedWithCompositor());
     mFlags |= aFlags;
   }
 
+  ISurfaceAllocator* GetAllocator()
+  {
+    return mAllocator;
+  }
+
   RefPtr<TextureChild> mActor;
+  RefPtr<ISurfaceAllocator> mAllocator;
   TextureFlags mFlags;
   bool mShared;
   bool mValid;
   FenceHandle mReleaseFenceHandle;
   FenceHandle mAcquireFenceHandle;
 
   friend class TextureChild;
+  friend class RemoveTextureFromCompositableTracker;
   friend void TestTextureClientSurface(TextureClient*, gfxImageSurface*);
   friend void TestTextureClientYCbCr(TextureClient*, PlanarYCbCrData&);
 };
 
 /**
+ * Task that releases TextureClient pointer on a specified thread.
+ */
+class TextureClientReleaseTask : public Task
+{
+public:
+    TextureClientReleaseTask(TextureClient* aClient)
+        : mTextureClient(aClient) {
+    }
+
+    virtual void Run() MOZ_OVERRIDE
+    {
+        mTextureClient = nullptr;
+    }
+
+private:
+    mozilla::RefPtr<TextureClient> mTextureClient;
+};
+
+/**
  * TextureClient that wraps a random access buffer such as a Shmem or raw memory.
  * This class must be inherited to implement the memory allocation and access bits.
  * (see ShmemTextureClient and MemoryTextureClient)
  */
 class BufferTextureClient : public TextureClient
                           , public TextureClientYCbCr
 {
 public:
--- a/gfx/layers/ipc/ISurfaceAllocator.h
+++ b/gfx/layers/ipc/ISurfaceAllocator.h
@@ -81,17 +81,19 @@ TemporaryRef<gfx::DataSourceSurface> Get
  * actors without a common polymorphic interface.
  * These methods should be only called in the ipdl implementor's thread, unless
  * specified otherwise in the implementing class.
  */
 class ISurfaceAllocator : public AtomicRefCountedWithFinalize<ISurfaceAllocator>
 {
 public:
   MOZ_DECLARE_REFCOUNTED_TYPENAME(ISurfaceAllocator)
-  ISurfaceAllocator() {}
+  ISurfaceAllocator()
+    : mDefaultMessageLoop(MessageLoop::current())
+  {}
 
   void Finalize();
 
   /**
    * Returns the type of backend that is used off the main thread.
    * We only don't allow changing the backend type at runtime so this value can
    * be queried once and will not change until Gecko is restarted.
    *
@@ -159,30 +161,37 @@ public:
                           uint32_t aUsage,
                           MaybeMagicGrallocBufferHandle* aHandle);
 
   void DeallocGrallocBuffer(MaybeMagicGrallocBufferHandle* aHandle);
 
   virtual bool IPCOpen() const { return true; }
   virtual bool IsSameProcess() const = 0;
 
+  virtual MessageLoop * GetMessageLoop() const
+  {
+    return mDefaultMessageLoop;
+  }
+
   // Returns true if aSurface wraps a Shmem.
   static bool IsShmem(SurfaceDescriptor* aSurface);
 
 protected:
 
   virtual bool IsOnCompositorSide() const = 0;
 
   virtual ~ISurfaceAllocator();
 
   void ShrinkShmemSectionHeap();
 
   // This is used to implement an extremely simple & naive heap allocator.
   std::vector<mozilla::ipc::Shmem> mUsedShmems;
 
+  MessageLoop* mDefaultMessageLoop;
+
   friend class AtomicRefCountedWithFinalize<ISurfaceAllocator>;
 };
 
 class GfxMemoryImageReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
   NS_DECL_ISUPPORTS
 
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -165,17 +165,17 @@ public:
    */
   base::Thread * GetThread() const;
 
   /**
    * Returns the ImageBridgeChild's message loop.
    *
    * Can be called from any thread.
    */
-  MessageLoop * GetMessageLoop() const;
+  virtual MessageLoop * GetMessageLoop() const MOZ_OVERRIDE;
 
   PCompositableChild* AllocPCompositableChild(const TextureInfo& aInfo, uint64_t* aID) MOZ_OVERRIDE;
   bool DeallocPCompositableChild(PCompositableChild* aActor) MOZ_OVERRIDE;
 
   /**
    * This must be called by the static function DeleteImageBridgeSync defined
    * in ImageBridgeChild.cpp ONLY.
    */
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -254,17 +254,17 @@ ImageBridgeParent::RecvChildAsyncMessage
       default:
         NS_ERROR("unknown AsyncChildMessageData type");
         return false;
     }
   }
   return true;
 }
 
-MessageLoop * ImageBridgeParent::GetMessageLoop() {
+MessageLoop * ImageBridgeParent::GetMessageLoop() const {
   return mMessageLoop;
 }
 
 class ReleaseRunnable : public nsRunnable
 {
 public:
   ReleaseRunnable(ImageBridgeParent* aRef)
     : mRef(aRef)
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -83,17 +83,17 @@ public:
   virtual bool
   RecvChildAsyncMessages(const InfallibleTArray<AsyncChildMessageData>& aMessages) MOZ_OVERRIDE;
 
   // Shutdown step 1
   virtual bool RecvWillStop() MOZ_OVERRIDE;
   // Shutdown step 2
   virtual bool RecvStop() MOZ_OVERRIDE;
 
-  MessageLoop * GetMessageLoop();
+  virtual MessageLoop* GetMessageLoop() const MOZ_OVERRIDE;
 
 
   // ISurfaceAllocator
 
   bool AllocShmem(size_t aSize,
                   ipc::SharedMemory::SharedMemoryType aType,
                   ipc::Shmem* aShmem) MOZ_OVERRIDE
   {
--- a/widget/gonk/nativewindow/GonkBufferQueueJB.cpp
+++ b/widget/gonk/nativewindow/GonkBufferQueueJB.cpp
@@ -54,32 +54,16 @@ static const char* scalingModeName(int s
     switch (scalingMode) {
         case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE";
         case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW";
         case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP";
         default: return "Unknown";
     }
 }
 
-class nsProxyReleaseTask : public Task
-{
-public:
-    nsProxyReleaseTask(TextureClient* aClient)
-        : mTextureClient(aClient) {
-    }
-
-    virtual void Run() MOZ_OVERRIDE
-    {
-        mTextureClient = nullptr;
-    }
-
-private:
-    mozilla::RefPtr<TextureClient> mTextureClient;
-};
-
 GonkBufferQueue::GonkBufferQueue(bool allowSynchronousMode,
         const sp<IGraphicBufferAlloc>& allocator) :
     mDefaultWidth(1),
     mDefaultHeight(1),
     mMaxAcquiredBufferCount(1),
     mDefaultMaxBufferCount(2),
     mOverrideMaxBufferCount(0),
     mSynchronousMode(true), // GonkBufferQueue always works in sync mode.
@@ -417,17 +401,17 @@ status_t GonkBufferQueue::dequeueBuffer(
         {
             mSlots[buf].mAcquireCalled = false;
             mSlots[buf].mGraphicBuffer = NULL;
             mSlots[buf].mRequestBufferCalled = false;
             mSlots[buf].mFence = Fence::NO_FENCE;
             if (mSlots[buf].mTextureClient) {
               mSlots[buf].mTextureClient->ClearRecycleCallback();
               // release TextureClient in ImageBridge thread
-              nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[buf].mTextureClient);
+              TextureClientReleaseTask* task = new TextureClientReleaseTask(mSlots[buf].mTextureClient);
               mSlots[buf].mTextureClient = NULL;
               ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task);
             }
             returnFlags |= IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION;
         }
 
         *outFence = mSlots[buf].mFence;
         mSlots[buf].mFence = Fence::NO_FENCE;
@@ -785,17 +769,17 @@ void GonkBufferQueue::freeAllBuffersLock
             "freeAllBuffersLocked called but mQueue is not empty");
     mQueue.clear();
     mBufferHasBeenQueued = false;
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
         mSlots[i].mGraphicBuffer = 0;
         if (mSlots[i].mTextureClient) {
           mSlots[i].mTextureClient->ClearRecycleCallback();
           // release TextureClient in ImageBridge thread
-          nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[i].mTextureClient);
+          TextureClientReleaseTask* task = new TextureClientReleaseTask(mSlots[i].mTextureClient);
           mSlots[i].mTextureClient = NULL;
           ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task);
         }
         if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
             mSlots[i].mNeedsCleanupOnRelease = true;
         }
         mSlots[i].mBufferState = BufferSlot::FREE;
         mSlots[i].mFrameNumber = 0;
--- a/widget/gonk/nativewindow/GonkBufferQueueKK.cpp
+++ b/widget/gonk/nativewindow/GonkBufferQueueKK.cpp
@@ -56,32 +56,16 @@ static const char* scalingModeName(int s
     switch (scalingMode) {
         case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE";
         case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW";
         case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP";
         default: return "Unknown";
     }
 }
 
-class nsProxyReleaseTask : public Task
-{
-public:
-    nsProxyReleaseTask(TextureClient* aClient)
-        : mTextureClient(aClient) {
-    }
-
-    virtual void Run() MOZ_OVERRIDE
-    {
-        mTextureClient = nullptr;
-    }
-
-private:
-    mozilla::RefPtr<TextureClient> mTextureClient;
-};
-
 GonkBufferQueue::GonkBufferQueue(bool allowSynchronousMode,
         const sp<IGraphicBufferAlloc>& allocator) :
     mDefaultWidth(1),
     mDefaultHeight(1),
     mMaxAcquiredBufferCount(1),
     mDefaultMaxBufferCount(2),
     mOverrideMaxBufferCount(0),
 //    mSynchronousMode(true), // GonkBufferQueue always works in sync mode.
@@ -439,17 +423,17 @@ status_t GonkBufferQueue::dequeueBuffer(
         {
             mSlots[buf].mAcquireCalled = false;
             mSlots[buf].mGraphicBuffer = NULL;
             mSlots[buf].mRequestBufferCalled = false;
             mSlots[buf].mFence = Fence::NO_FENCE;
             if (mSlots[buf].mTextureClient) {
               mSlots[buf].mTextureClient->ClearRecycleCallback();
               // release TextureClient in ImageBridge thread
-              nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[buf].mTextureClient);
+              TextureClientReleaseTask* task = new TextureClientReleaseTask(mSlots[buf].mTextureClient);
               mSlots[buf].mTextureClient = NULL;
               ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task);
             }
             returnFlags |= IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION;
         }
 
 
         if (CC_UNLIKELY(mSlots[buf].mFence == NULL)) {
@@ -870,17 +854,17 @@ void GonkBufferQueue::freeAllBuffersLock
             "freeAllBuffersLocked called but mQueue is not empty");
     mQueue.clear();
     mBufferHasBeenQueued = false;
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
         mSlots[i].mGraphicBuffer = 0;
         if (mSlots[i].mTextureClient) {
           mSlots[i].mTextureClient->ClearRecycleCallback();
           // release TextureClient in ImageBridge thread
-          nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[i].mTextureClient);
+          TextureClientReleaseTask* task = new TextureClientReleaseTask(mSlots[i].mTextureClient);
           mSlots[i].mTextureClient = NULL;
           ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task);
         }
         if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
             mSlots[i].mNeedsCleanupOnRelease = true;
         }
         mSlots[i].mBufferState = BufferSlot::FREE;
         mSlots[i].mFrameNumber = 0;
--- a/widget/gonk/nativewindow/GonkNativeWindowICS.cpp
+++ b/widget/gonk/nativewindow/GonkNativeWindowICS.cpp
@@ -32,34 +32,16 @@
 #define CNW_LOGD(...)   DOM_CAMERA_LOGI(__VA_ARGS__)
 #define CNW_LOGE(...)   {(void)printf_stderr(__VA_ARGS__);}
 
 using namespace android;
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 
-class nsProxyReleaseTask : public CancelableTask
-{
-public:
-    nsProxyReleaseTask(TextureClient* aClient)
-        : mTextureClient(aClient) {
-    }
-
-    virtual void Run() MOZ_OVERRIDE
-    {
-        mTextureClient = nullptr;
-    }
-
-    virtual void Cancel() MOZ_OVERRIDE {}
-
-private:
-    mozilla::RefPtr<TextureClient> mTextureClient;
-};
-
 GonkNativeWindow::GonkNativeWindow() :
     mAbandoned(false),
     mDefaultWidth(1),
     mDefaultHeight(1),
     mPixelFormat(PIXEL_FORMAT_RGBA_8888),
     mBufferCount(MIN_BUFFER_SLOTS + 1),
     mConnectedApi(NO_CONNECTED_API),
     mFrameCounter(0),
@@ -84,17 +66,17 @@ void GonkNativeWindow::freeAllBuffersLoc
 {
     CNW_LOGD("freeAllBuffersLocked");
 
     for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
         if (mSlots[i].mGraphicBuffer != NULL) {
             if (mSlots[i].mTextureClient) {
               mSlots[i].mTextureClient->ClearRecycleCallback();
               // release TextureClient in ImageBridge thread
-              nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[i].mTextureClient);
+              TextureClientReleaseTask* task = new TextureClientReleaseTask(mSlots[i].mTextureClient);
               mSlots[i].mTextureClient = NULL;
               ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task);
             }
             mSlots[i].mGraphicBuffer = NULL;
             mSlots[i].mBufferState = BufferSlot::FREE;
             mSlots[i].mFrameNumber = 0;
         }
     }
@@ -106,17 +88,17 @@ void GonkNativeWindow::clearRenderingSta
 
     for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
         if (mSlots[i].mGraphicBuffer != NULL) {
             // Clear RENDERING state buffer
             if (mSlots[i].mBufferState == BufferSlot::RENDERING) {
                 if (mSlots[i].mTextureClient) {
                   mSlots[i].mTextureClient->ClearRecycleCallback();
                   // release TextureClient in ImageBridge thread
-                  nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[i].mTextureClient);
+                  TextureClientReleaseTask* task = new TextureClientReleaseTask(mSlots[i].mTextureClient);
                   mSlots[i].mTextureClient = NULL;
                   ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task);
                 }
                 mSlots[i].mGraphicBuffer = NULL;
                 mSlots[i].mBufferState = BufferSlot::FREE;
                 mSlots[i].mFrameNumber = 0;
             }
         }
@@ -322,17 +304,17 @@ status_t GonkNativeWindow::dequeueBuffer
             (uint32_t(gbuf->height) != h) ||
             (uint32_t(gbuf->format) != format) ||
             ((uint32_t(gbuf->usage) & usage) != usage))) {
             mSlots[buf].mGraphicBuffer = NULL;
             mSlots[buf].mRequestBufferCalled = false;
             if (mSlots[buf].mTextureClient) {
                 mSlots[buf].mTextureClient->ClearRecycleCallback();
                 // release TextureClient in ImageBridge thread
-                nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[buf].mTextureClient);
+                TextureClientReleaseTask* task = new TextureClientReleaseTask(mSlots[buf].mTextureClient);
                 mSlots[buf].mTextureClient = NULL;
                 ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task);
             }
             alloc = true;
         }
     }  // end lock scope
 
     sp<GraphicBuffer> graphicBuffer;