Bug 1633453 - Clear display item cache when the display list send fails or WR backend changes r=jrmuizel
authorMiko Mynttinen <mikokm@gmail.com>
Wed, 29 Apr 2020 02:26:08 +0000
changeset 526665 29ed956cc6c3a91db481750de108a8446d604286
parent 526664 a59c015f4369f818c77ec540cd9dbc5e2f9c5f88
child 526666 8609782d78d127c495269680a7054cad13167d42
push id37361
push usermalexandru@mozilla.com
push dateWed, 29 Apr 2020 21:55:39 +0000
treeherdermozilla-central@bc0932b38478 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1633453
milestone77.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 1633453 - Clear display item cache when the display list send fails or WR backend changes r=jrmuizel Differential Revision: https://phabricator.services.mozilla.com/D72692
gfx/layers/wr/DisplayItemCache.cpp
gfx/layers/wr/DisplayItemCache.h
gfx/layers/wr/WebRenderBridgeChild.cpp
gfx/layers/wr/WebRenderBridgeChild.h
gfx/layers/wr/WebRenderLayerManager.cpp
--- a/gfx/layers/wr/DisplayItemCache.cpp
+++ b/gfx/layers/wr/DisplayItemCache.cpp
@@ -67,25 +67,25 @@ void DisplayItemCache::UpdateState() {
   if (IsEmpty()) {
     // The cache is empty so nothing needs to be updated.
     mInvalid = false;
     return;
   }
 
   // Clear the cache if the current state is invalid.
   if (mInvalid) {
-    ClearCache();
+    Clear();
   } else {
     FreeUnusedSlots();
   }
 
   mInvalid = false;
 }
 
-void DisplayItemCache::ClearCache() {
+void DisplayItemCache::Clear() {
   memset(mSlots.Elements(), 0, mSlots.Length() * sizeof(Slot));
   mFreeSlots.ClearAndRetainStorage();
 
   for (size_t i = 0; i < CurrentSize(); ++i) {
     mFreeSlots.AppendElement(i);
   }
 }
 
@@ -127,17 +127,17 @@ void DisplayItemCache::FreeUnusedSlots()
 }
 
 void DisplayItemCache::SetCapacity(const size_t aInitialSize,
                                    const size_t aMaximumSize) {
   mMaximumSize = aMaximumSize;
   mSlots.SetCapacity(aMaximumSize);
   mSlots.SetLength(aInitialSize);
   mFreeSlots.SetCapacity(aMaximumSize);
-  ClearCache();
+  Clear();
 }
 
 Maybe<uint16_t> DisplayItemCache::AssignSlot(nsPaintedDisplayItem* aItem) {
   if (!mCaching || !aItem->CanBeReused() || !aItem->CanBeCached()) {
     return Nothing();
   }
 
   auto& slot = aItem->CacheIndex();
--- a/gfx/layers/wr/DisplayItemCache.h
+++ b/gfx/layers/wr/DisplayItemCache.h
@@ -61,16 +61,21 @@ class CacheStats {
  * spatial id can change between display lists, even if the Gecko display items
  * have not. This state is tracked by DisplayItemCache.
  */
 class DisplayItemCache final {
  public:
   DisplayItemCache();
 
   /**
+   * Clears the cache.
+   */
+  void Clear();
+
+  /**
    * Sets the initial and max cache size to given |aInitialSize| and |aMaxSize|.
    */
   void SetCapacity(const size_t aInitialSize, const size_t aMaximumSize);
 
   /**
    * Sets the display list used by the cache.
    */
   void SetDisplayList(nsDisplayListBuilder* aBuilder, nsDisplayList* aList);
@@ -137,17 +142,16 @@ class DisplayItemCache final {
   struct Slot {
     Slot() : mSpaceAndClip{}, mOccupied(false), mUsed(false) {}
 
     wr::WrSpaceAndClipChain mSpaceAndClip;
     bool mOccupied;
     bool mUsed;
   };
 
-  void ClearCache();
   void FreeUnusedSlots();
   Maybe<uint16_t> GetNextFreeSlot();
   bool GrowIfPossible();
   void UpdateState();
 
   // The lifetime of display lists exceed the lifetime of DisplayItemCache.
   // This pointer stores the address of the display list that is using this
   // cache, and it is only used for pointer comparisons.
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -99,17 +99,17 @@ void WebRenderBridgeChild::UpdateResourc
   nsTArray<RefCountedShmem> smallShmems;
   nsTArray<ipc::Shmem> largeShmems;
   aResources.Flush(resourceUpdates, smallShmems, largeShmems);
 
   this->SendUpdateResources(resourceUpdates, smallShmems,
                             std::move(largeShmems), aRenderRoot);
 }
 
-void WebRenderBridgeChild::EndTransaction(
+bool WebRenderBridgeChild::EndTransaction(
     nsTArray<RenderRootDisplayListData>& aRenderRoots,
     TransactionId aTransactionId, bool aContainsSVGGroup,
     const mozilla::VsyncId& aVsyncId, const mozilla::TimeStamp& aVsyncStartTime,
     const mozilla::TimeStamp& aRefreshStartTime,
     const mozilla::TimeStamp& aTxnStartTime, const nsCString& aTxnURL) {
   MOZ_ASSERT(!mDestroyed);
   MOZ_ASSERT(mIsInTransaction);
 
@@ -122,27 +122,29 @@ void WebRenderBridgeChild::EndTransactio
   }
 
   nsTArray<CompositionPayload> payloads;
   if (mManager) {
     mManager->TakeCompositionPayloads(payloads);
   }
 
   mSentDisplayList = true;
-  this->SendSetDisplayList(
+  bool ret = this->SendSetDisplayList(
       std::move(aRenderRoots), mDestroyedActors, GetFwdTransactionId(),
       aTransactionId, aContainsSVGGroup, aVsyncId, aVsyncStartTime,
       aRefreshStartTime, aTxnStartTime, aTxnURL, fwdTime, payloads);
 
   // With multiple render roots, we may not have sent all of our
   // mParentCommands, so go ahead and go through our mParentCommands and ensure
   // they get sent.
   ProcessWebRenderParentCommands();
   mDestroyedActors.Clear();
   mIsInTransaction = false;
+
+  return ret;
 }
 
 void WebRenderBridgeChild::EndEmptyTransaction(
     const FocusTarget& aFocusTarget,
     nsTArray<RenderRootUpdates>& aRenderRootUpdates,
     TransactionId aTransactionId, const mozilla::VsyncId& aVsyncId,
     const mozilla::TimeStamp& aVsyncStartTime,
     const mozilla::TimeStamp& aRefreshStartTime,
--- a/gfx/layers/wr/WebRenderBridgeChild.h
+++ b/gfx/layers/wr/WebRenderBridgeChild.h
@@ -68,17 +68,17 @@ class WebRenderBridgeChild final : publi
                                  wr::RenderRoot aRenderRoot);
   bool HasWebRenderParentCommands(wr::RenderRoot aRenderRoot) {
     return !mParentCommands.IsEmpty();
   }
 
   void UpdateResources(wr::IpcResourceUpdateQueue& aResources,
                        wr::RenderRoot aRenderRoot);
   void BeginTransaction();
-  void EndTransaction(nsTArray<RenderRootDisplayListData>& aRenderRoots,
+  bool EndTransaction(nsTArray<RenderRootDisplayListData>& aRenderRoots,
                       TransactionId aTransactionId, bool aContainsSVGroup,
                       const mozilla::VsyncId& aVsyncId,
                       const mozilla::TimeStamp& aVsyncStartTime,
                       const mozilla::TimeStamp& aRefreshStartTime,
                       const mozilla::TimeStamp& aTxnStartTime,
                       const nsCString& aTxtURL);
   void EndEmptyTransaction(const FocusTarget& aFocusTarget,
                            nsTArray<RenderRootUpdates>& aRenderRootUpdates,
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -428,21 +428,26 @@ void WebRenderLayerManager::EndTransacti
       resourceUpdates.SubQueue(renderRoot)
           .Flush(renderRootDL->mResourceUpdates, renderRootDL->mSmallShmems,
                  renderRootDL->mLargeShmems);
       renderRootDL->mRect =
           LayoutDeviceRect(LayoutDevicePoint(), LayoutDeviceSize(size));
       renderRootDL->mScrollData.emplace(std::move(mScrollData));
     }
 
-    WrBridge()->EndTransaction(renderRootDLs, mLatestTransactionId,
-                               containsSVGGroup,
-                               mTransactionIdAllocator->GetVsyncId(),
-                               mTransactionIdAllocator->GetVsyncStart(),
-                               refreshStart, mTransactionStart, mURL);
+    bool ret = WrBridge()->EndTransaction(
+        renderRootDLs, mLatestTransactionId, containsSVGGroup,
+        mTransactionIdAllocator->GetVsyncId(),
+        mTransactionIdAllocator->GetVsyncStart(), refreshStart,
+        mTransactionStart, mURL);
+    if (!ret) {
+      // Failed to send display list, reset display item cache state.
+      mDisplayItemCache.Clear();
+    }
+
     WrBridge()->SendSetFocusTarget(mFocusTarget);
     mFocusTarget = FocusTarget();
   }
 
   // Discard animations after calling WrBridge()->EndTransaction().
   // It updates mWrEpoch in WebRenderBridgeParent. The updated mWrEpoch is
   // necessary for deleting animations at the correct time.
   for (auto& stateManager : mStateManagers) {
@@ -610,16 +615,17 @@ void WebRenderLayerManager::ClearCachedR
   }
   WrBridge()->EndClearCachedResources();
 }
 
 void WebRenderLayerManager::WrUpdated() {
   ClearAsyncAnimations();
   mWebRenderCommandBuilder.ClearCachedResources();
   DiscardLocalImages();
+  mDisplayItemCache.Clear();
 
   if (mWidget) {
     if (dom::BrowserChild* browserChild = mWidget->GetOwningBrowserChild()) {
       browserChild->SchedulePaint();
     }
   }
 }