Bug 1283947 - Clear pending transactions when ClientLayerManager is assigning to a different refresh driver. r=mattwoodrow a=gchang
authorSamael Wang <freesamael@gmail.com>
Fri, 24 Mar 2017 15:10:07 +0800
changeset 395465 cbc61557e638cec7ce467956ed6525f93ef0441f
parent 395464 62f40b74ee69aa12ab13518bb5a765e7ed37d229
child 395466 f823d309838ffcb8412725301c3d1bbb32adb40e
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow, gchang
bugs1283947
milestone54.0a2
Bug 1283947 - Clear pending transactions when ClientLayerManager is assigning to a different refresh driver. r=mattwoodrow a=gchang
gfx/layers/TransactionIdAllocator.h
gfx/layers/client/ClientLayerManager.cpp
gfx/layers/client/ClientLayerManager.h
layout/base/nsRefreshDriver.cpp
layout/base/nsRefreshDriver.h
--- a/gfx/layers/TransactionIdAllocator.h
+++ b/gfx/layers/TransactionIdAllocator.h
@@ -49,16 +49,35 @@ public:
    * Revoke a transaction id that isn't needed to track
    * completion of asynchronous work. This is similar
    * to NotifyTransactionCompleted except avoids
    * return ordering issues.
    */
   virtual void RevokeTransactionId(uint64_t aTransactionId) = 0;
 
   /**
+   * Stop waiting for pending transactions, if any.
+   *
+   * This is used when ClientLayerManager is assigning to another refresh
+   * driver, and the current refresh driver may never receive transaction
+   * completed notifications.
+   */
+  virtual void ClearPendingTransactions() = 0;
+
+  /**
+   * Transaction id is usually initialized as 0, however when ClientLayerManager
+   * switches to another refresh driver, completed transactions of the previous
+   * refresh driver could be delivered and confuse the newly adopted refresh
+   * driver. To prevent this situation, use this function to reset transaction
+   * id to the last transaction id from previous refresh driver, so that all
+   * completed transactions of previous refresh driver will be ignored.
+   */
+  virtual void ResetInitialTransactionId(uint64_t aTransactionId) = 0;
+
+  /**
    * Get the start time of the current refresh tick.
    */
   virtual mozilla::TimeStamp GetTransactionStart() = 0;
 };
 
 } // namespace layers
 } // namespace mozilla
 
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -506,16 +506,36 @@ ClientLayerManager::GetCompositorSideAPZ
 {
   if (mForwarder->HasShadowManager()) {
     if (!mForwarder->GetShadowManager()->SendGetAPZTestData(aData)) {
       NS_WARNING("Call to PLayerTransactionChild::SendGetAPZTestData() failed");
     }
   }
 }
 
+void
+ClientLayerManager::SetTransactionIdAllocator(TransactionIdAllocator* aAllocator)
+{
+  // When changing the refresh driver, the previous refresh driver may never
+  // receive updates of pending transactions it's waiting for. So clear the
+  // waiting state before assigning another refresh driver.
+  if (mTransactionIdAllocator && (aAllocator != mTransactionIdAllocator)) {
+    mTransactionIdAllocator->ClearPendingTransactions();
+
+    // We should also reset the transaction id of the new allocator to previous
+    // allocator's last transaction id, so that completed transactions for
+    // previous allocator will be ignored and won't confuse the new allocator.
+    if (aAllocator) {
+      aAllocator->ResetInitialTransactionId(mTransactionIdAllocator->LastTransactionId());
+    }
+  }
+
+  mTransactionIdAllocator = aAllocator;
+}
+
 float
 ClientLayerManager::RequestProperty(const nsAString& aProperty)
 {
   if (mForwarder->HasShadowManager()) {
     float value;
     if (!mForwarder->GetShadowManager()->SendRequestProperty(nsString(aProperty), &value)) {
       NS_WARNING("Call to PLayerTransactionChild::SendGetAPZTestData() failed");
     }
--- a/gfx/layers/client/ClientLayerManager.h
+++ b/gfx/layers/client/ClientLayerManager.h
@@ -217,20 +217,17 @@ public:
   // LogTestData...() functions.
   const APZTestData& GetAPZTestData() const {
     return mApzTestData;
   }
 
   // Get a copy of the compositor-side APZ test data for our layers ID.
   void GetCompositorSideAPZTestData(APZTestData* aData) const;
 
-  virtual void SetTransactionIdAllocator(TransactionIdAllocator* aAllocator) override
-  {
-     mTransactionIdAllocator = aAllocator;
-  }
+  virtual void SetTransactionIdAllocator(TransactionIdAllocator* aAllocator) override;
 
   virtual uint64_t GetLastTransactionId() override { return mLatestTransactionId; }
 
   float RequestProperty(const nsAString& aProperty) override;
 
   bool AsyncPanZoomEnabled() const override;
 
   void SetNextPaintSyncId(int32_t aSyncId);
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -2158,16 +2158,29 @@ nsRefreshDriver::RevokeTransactionId(uin
   if (mPendingTransaction == mCompletedTransaction + 2 &&
       mWaitingForTransaction) {
     MOZ_ASSERT(!mSkippedPaints, "How did we skip a paint when we're in the middle of one?");
     FinishedWaitingForTransaction();
   }
   mPendingTransaction--;
 }
 
+void
+nsRefreshDriver::ClearPendingTransactions()
+{
+  mCompletedTransaction = mPendingTransaction;
+  mWaitingForTransaction = false;
+}
+
+void
+nsRefreshDriver::ResetInitialTransactionId(uint64_t aTransactionId)
+{
+  mCompletedTransaction = mPendingTransaction = aTransactionId;
+}
+
 mozilla::TimeStamp
 nsRefreshDriver::GetTransactionStart()
 {
   return mTickStart;
 }
 
 void
 nsRefreshDriver::NotifyTransactionCompleted(uint64_t aTransactionId)
--- a/layout/base/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -304,16 +304,18 @@ public:
    */
   static bool GetJankLevels(mozilla::Vector<uint64_t>& aJank);
 
   // mozilla::layers::TransactionIdAllocator
   uint64_t GetTransactionId() override;
   uint64_t LastTransactionId() const override;
   void NotifyTransactionCompleted(uint64_t aTransactionId) override;
   void RevokeTransactionId(uint64_t aTransactionId) override;
+  void ClearPendingTransactions() override;
+  void ResetInitialTransactionId(uint64_t aTransactionId) override;
   mozilla::TimeStamp GetTransactionStart() override;
 
   bool IsWaitingForPaint(mozilla::TimeStamp aTime);
 
   // nsARefreshObserver
   NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override { return TransactionIdAllocator::AddRef(); }
   NS_IMETHOD_(MozExternalRefCountType) Release(void) override { return TransactionIdAllocator::Release(); }
   virtual void WillRefresh(mozilla::TimeStamp aTime) override;