Bug 1260611 - Part 1: Opt-in to waiting for compositor recycling for TextureClientRecycleAllocator. r=sotaro a=ritu
authorMatt Woodrow <mwoodrow@mozilla.com>
Fri, 22 Apr 2016 15:39:56 +1200
changeset 378923 f9dd2fb1b99188f72b429a9e126e90a6ab50d0d1
parent 378922 7abf386fee3f6aa34f9d3058dd033af8c495a5ef
child 378924 fa709c256861d88fa9d2bd7d2e0ad4a4f30c58ee
push id21011
push usermak77@bonardo.net
push dateThu, 16 Jun 2016 13:40:45 +0000
reviewerssotaro, ritu
bugs1260611
milestone47.0
Bug 1260611 - Part 1: Opt-in to waiting for compositor recycling for TextureClientRecycleAllocator. r=sotaro a=ritu
gfx/layers/client/TextureClient.cpp
gfx/layers/client/TextureClient.h
gfx/layers/client/TextureClientRecycleAllocator.cpp
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -907,16 +907,17 @@ TextureClient::TextureClient(TextureData
 , mActor(nullptr)
 , mData(aData)
 , mFlags(aFlags)
 , mOpenMode(OpenMode::OPEN_NONE)
 #ifdef DEBUG
 , mExpectedDtRefs(0)
 #endif
 , mIsLocked(false)
+, mInUse(false)
 , mAddedToCompositableClient(false)
 , mWorkaroundAnnoyingSharedSurfaceLifetimeIssues(false)
 , mWorkaroundAnnoyingSharedSurfaceOwnershipIssues(false)
 #ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
 , mPoolTracker(nullptr)
 #endif
 {
   mFlags |= mData->GetTextureFlags();
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -326,16 +326,23 @@ public:
   void Unlock();
 
   bool IsLocked() const { return mIsLocked; }
 
   bool CanExposeDrawTarget() const { return mData->SupportsMoz2D(); }
 
   bool CanExposeMappedData() const { return mData->CanExposeMappedData(); }
 
+  /* TextureClientRecycleAllocator tracking to decide if we need
+   * to check with the compositor before recycling.
+   * Should be superceeded (and removed) by bug 1252835.
+   */
+  void SetInUse(bool aInUse) { mInUse = aInUse; }
+  bool IsInUse() { return mInUse; }
+
   /**
    * Returns a DrawTarget to draw into the TextureClient.
    * This function should never be called when not on the main thread!
    *
    * This must never be called on a TextureClient that is not sucessfully locked.
    * When called several times within one Lock/Unlock pair, this method should
    * return the same DrawTarget.
    * The DrawTarget is automatically flushed by the TextureClient when the latter
@@ -624,16 +631,17 @@ protected:
   TextureFlags mFlags;
   FenceHandle mReleaseFenceHandle;
   FenceHandle mAcquireFenceHandle;
   gl::GfxTextureWasteTracker mWasteTracker;
 
   OpenMode mOpenMode;
   DebugOnly<uint32_t> mExpectedDtRefs;
   bool mIsLocked;
+  bool mInUse;
 
   bool mAddedToCompositableClient;
   bool mWorkaroundAnnoyingSharedSurfaceLifetimeIssues;
   bool mWorkaroundAnnoyingSharedSurfaceOwnershipIssues;
 
   RefPtr<TextureReadbackSink> mReadbackSink;
 
   friend class TextureChild;
--- a/gfx/layers/client/TextureClientRecycleAllocator.cpp
+++ b/gfx/layers/client/TextureClientRecycleAllocator.cpp
@@ -175,33 +175,59 @@ TextureClientRecycleAllocator::CreateOrR
     // Register TextureClient
     mInUseClients[textureHolder->GetTextureClient()] = textureHolder;
   }
   RefPtr<TextureClient> client(textureHolder->GetTextureClient());
 
   // Make sure the texture holds a reference to us, and ask it to call RecycleTextureClient when its
   // ref count drops to 1.
   client->SetRecycleAllocator(this);
+  client->SetInUse(true);
   return client.forget();
 }
 
 already_AddRefed<TextureClient>
 TextureClientRecycleAllocator::Allocate(gfx::SurfaceFormat aFormat,
                                         gfx::IntSize aSize,
                                         BackendSelector aSelector,
                                         TextureFlags aTextureFlags,
                                         TextureAllocationFlags aAllocFlags)
 {
   return TextureClient::CreateForDrawing(mSurfaceAllocator, aFormat, aSize, aSelector,
                                          aTextureFlags, aAllocFlags);
 }
 
+class TextureClientWaitTask : public Task
+{
+public:
+  explicit TextureClientWaitTask(TextureClient* aClient)
+    : mTextureClient(aClient)
+  {}
+
+  virtual void Run() override
+  {
+    mTextureClient->WaitForCompositorRecycle();
+  }
+
+private:
+  RefPtr<TextureClient> mTextureClient;
+};
+
 void
 TextureClientRecycleAllocator::RecycleTextureClient(TextureClient* aClient)
 {
+  if (aClient->IsInUse()) {
+    aClient->SetInUse(false);
+    // This adds another ref to aClient, and drops it after a round trip
+    // to the compositor. We should then get this callback a second time
+    // and can recycle properly.
+    Task* task = new TextureClientWaitTask(aClient);
+    mSurfaceAllocator->GetMessageLoop()->PostTask(FROM_HERE, task);
+    return;
+  }
   // Clearing the recycle allocator drops a reference, so make sure we stay alive
   // for the duration of this function.
   RefPtr<TextureClientRecycleAllocator> kungFuDeathGrip(this);
   aClient->SetRecycleAllocator(nullptr);
 
   RefPtr<TextureClientHolder> textureHolder;
   {
     MutexAutoLock lock(mLock);