Bug 1558926 - Part 2: Use DisplayItemCache in WebRenderCommandBuilder
authorMiko Mynttinen <mikokm@gmail.com>
Mon, 27 Jan 2020 14:18:17 +0000
changeset 511844 8c51225cdfa3e48af497a8d17655e956247abdd7
parent 511843 8ac92137eff968a3ceeca7809f94bc51a1f97571
child 511845 8ef0c5a62e56ba9a570d53e7a1616d912024420d
push id37060
push useraciure@mozilla.com
push dateMon, 27 Jan 2020 21:39:55 +0000
treeherdermozilla-central@df59b74d33d7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1558926
milestone74.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 1558926 - Part 2: Use DisplayItemCache in WebRenderCommandBuilder Differential Revision: https://phabricator.services.mozilla.com/D60756
gfx/layers/wr/WebRenderCommandBuilder.cpp
gfx/layers/wr/WebRenderCommandBuilder.h
layout/painting/RetainedDisplayListBuilder.cpp
layout/painting/nsDisplayList.h
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -1539,16 +1539,31 @@ void WebRenderCommandBuilder::DoGrouping
                      .PostTranslate(residualOffset.x, residualOffset.y);
   group.mScale = scale;
   group.mScrollId = scrollId;
   g.ConstructGroups(aDisplayListBuilder, this, aBuilder, aResources, &group,
                     aList, aSc);
   mCurrentClipManager->EndList(aSc);
 }
 
+WebRenderCommandBuilder::WebRenderCommandBuilder(
+    WebRenderLayerManager* aManager)
+    : mManager(aManager),
+      mRootStackingContexts(nullptr),
+      mCurrentClipManager(nullptr),
+      mLastAsr(nullptr),
+      mDumpIndent(0),
+      mDoGrouping(false),
+      mContainsSVGGroup(false) {
+  if (XRE_IsContentProcess() &&
+      StaticPrefs::gfx_webrender_enable_item_cache_AtStartup()) {
+    mDisplayItemCache.SetCapacity(10000, 10000);
+  }
+}
+
 void WebRenderCommandBuilder::Destroy() {
   mLastCanvasDatas.Clear();
   ClearCachedResources();
 }
 
 void WebRenderCommandBuilder::EmptyTransaction() {
   // We need to update canvases that might have changed.
   for (auto iter = mLastCanvasDatas.Iter(); !iter.Done(); iter.Next()) {
@@ -1583,16 +1598,23 @@ void WebRenderCommandBuilder::BuildWebRe
     mBuilderDumpIndex[renderRoot] = 0;
   }
   MOZ_ASSERT(mLayerScrollDatas.IsEmpty());
   mLastCanvasDatas.Clear();
   mLastAsr = nullptr;
   mContainsSVGGroup = false;
   MOZ_ASSERT(mDumpIndent == 0);
 
+  if (mDisplayItemCache.IsEnabled()) {
+    mDisplayItemCache.UpdateState(aDisplayListBuilder->PartialBuildFailed(),
+                                  aBuilder.CurrentPipelineId());
+    aBuilder.SetDisplayListCacheSize(mDisplayItemCache.CurrentCacheSize());
+    // mDisplayItemCache.Stats().Reset();
+  }
+
   {
     nsPresContext* presContext =
         aDisplayListBuilder->RootReferenceFrame()->PresContext();
     bool isTopLevelContent =
         presContext->Document()->IsTopLevelContentDocument();
 
     wr::RenderRootArray<Maybe<StackingContextHelper>> pageRootScs;
     for (auto renderRoot : wr::kRenderRoots) {
@@ -1652,27 +1674,62 @@ void WebRenderCommandBuilder::BuildWebRe
       mClipManagers[renderRoot].EndBuild();
     }
   }
   mLayerScrollDatas.Clear();
 
   // Remove the user data those are not displayed on the screen and
   // also reset the data to unused for next transaction.
   RemoveUnusedAndResetWebRenderUserData();
+
+  if (mDisplayItemCache.IsEnabled()) {
+    // mDisplayItemCache.Stats().Print();
+  }
 }
 
 bool WebRenderCommandBuilder::ShouldDumpDisplayList(
     nsDisplayListBuilder* aBuilder) {
   return aBuilder != nullptr && aBuilder->IsInActiveDocShell() &&
          ((XRE_IsParentProcess() &&
            StaticPrefs::gfx_webrender_dl_dump_parent()) ||
           (XRE_IsContentProcess() &&
            StaticPrefs::gfx_webrender_dl_dump_content()));
 }
 
+void WebRenderCommandBuilder::CreateWebRenderCommands(
+    nsDisplayItem* aItem, mozilla::wr::DisplayListBuilder& aBuilder,
+    mozilla::wr::IpcResourceUpdateQueue& aResources,
+    const StackingContextHelper& aSc,
+    nsDisplayListBuilder* aDisplayListBuilder) {
+  auto* item = aItem->AsPaintedDisplayItem();
+  MOZ_RELEASE_ASSERT(item, "Tried to paint item that cannot be painted");
+
+  if (mDisplayItemCache.ReuseItem(item, aBuilder)) {
+    // No further processing should be needed, since the item was reused.
+    return;
+  }
+
+  mDisplayItemCache.MaybeStartCaching(item, aBuilder);
+
+  aItem->SetPaintRect(aItem->GetBuildingRect());
+  RenderRootStateManager* manager =
+      mManager->GetRenderRootStateManager(aBuilder.GetRenderRoot());
+
+  // Note: this call to CreateWebRenderCommands can recurse back into
+  // this function if the |item| is a wrapper for a sublist.
+  const bool createdWRCommands = aItem->CreateWebRenderCommands(
+      aBuilder, aResources, aSc, manager, aDisplayListBuilder);
+
+  if (!createdWRCommands) {
+    PushItemAsImage(aItem, aBuilder, aResources, aSc, aDisplayListBuilder);
+  }
+
+  mDisplayItemCache.MaybeEndCaching(aBuilder);
+}
+
 void WebRenderCommandBuilder::CreateWebRenderCommandsFromDisplayList(
     nsDisplayList* aDisplayList, nsDisplayItem* aWrappingItem,
     nsDisplayListBuilder* aDisplayListBuilder, const StackingContextHelper& aSc,
     wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources) {
   AutoRestore<ClipManager*> prevClipManager(mCurrentClipManager);
   mCurrentClipManager = &mClipManagers[aBuilder.GetRenderRoot()];
   if (mDoGrouping) {
     MOZ_RELEASE_ASSERT(
@@ -1764,26 +1821,18 @@ void WebRenderCommandBuilder::CreateWebR
 
       if (dumpEnabled) {
         std::stringstream ss;
         nsFrame::PrintDisplayItem(aDisplayListBuilder, item, ss,
                                   static_cast<uint32_t>(mDumpIndent));
         printf_stderr("%s", ss.str().c_str());
       }
 
-      // Note: this call to CreateWebRenderCommands can recurse back into
-      // this function if the |item| is a wrapper for a sublist.
-      item->SetPaintRect(item->GetBuildingRect());
-      RenderRootStateManager* manager =
-          mManager->GetRenderRootStateManager(aBuilder.GetRenderRoot());
-      bool createdWRCommands = item->CreateWebRenderCommands(
-          aBuilder, aResources, aSc, manager, aDisplayListBuilder);
-      if (!createdWRCommands) {
-        PushItemAsImage(item, aBuilder, aResources, aSc, aDisplayListBuilder);
-      }
+      CreateWebRenderCommands(item, aBuilder, aResources, aSc,
+                              aDisplayListBuilder);
 
       if (dumpEnabled) {
         mBuilderDumpIndex[aBuilder.GetRenderRoot()] = aBuilder.Dump(
             mDumpIndent + 1, Some(mBuilderDumpIndex[aBuilder.GetRenderRoot()]),
             Nothing());
       }
     }
 
--- a/gfx/layers/wr/WebRenderCommandBuilder.h
+++ b/gfx/layers/wr/WebRenderCommandBuilder.h
@@ -10,16 +10,17 @@
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "mozilla/layers/ClipManager.h"
 #include "mozilla/layers/RenderRootBoundary.h"
 #include "mozilla/layers/WebRenderMessages.h"
 #include "mozilla/layers/WebRenderScrollData.h"
 #include "mozilla/layers/WebRenderUserData.h"
 #include "nsDisplayList.h"
 #include "nsIFrame.h"
+#include "DisplayItemCache.h"
 
 namespace mozilla {
 
 namespace layers {
 
 class CanvasLayer;
 class ImageClient;
 class ImageContainer;
@@ -77,24 +78,17 @@ class WebRenderScrollDataCollection {
 };
 
 class WebRenderCommandBuilder final {
   typedef nsTHashtable<nsRefPtrHashKey<WebRenderUserData>>
       WebRenderUserDataRefTable;
   typedef nsTHashtable<nsRefPtrHashKey<WebRenderCanvasData>> CanvasDataSet;
 
  public:
-  explicit WebRenderCommandBuilder(WebRenderLayerManager* aManager)
-      : mManager(aManager),
-        mRootStackingContexts(nullptr),
-        mCurrentClipManager(nullptr),
-        mLastAsr(nullptr),
-        mDumpIndent(0),
-        mDoGrouping(false),
-        mContainsSVGGroup(false) {}
+  explicit WebRenderCommandBuilder(WebRenderLayerManager* aManager);
 
   void Destroy();
 
   void EmptyTransaction();
 
   bool NeedsEmptyTransaction();
 
   void BuildWebRenderCommands(
@@ -228,16 +222,21 @@ class WebRenderCommandBuilder final {
     WebRenderCommandBuilder& mBuilder;
     RenderRootBoundary mBoundary;
     size_t mLayerCountBeforeRecursing;
   };
   friend class ScrollDataBoundaryWrapper;
 
  private:
   RenderRootStateManager* GetRenderRootStateManager(wr::RenderRoot aRenderRoot);
+  void CreateWebRenderCommands(nsDisplayItem* aItem,
+                               mozilla::wr::DisplayListBuilder& aBuilder,
+                               mozilla::wr::IpcResourceUpdateQueue& aResources,
+                               const StackingContextHelper& aSc,
+                               nsDisplayListBuilder* aDisplayListBuilder);
 
   wr::RenderRootArray<Maybe<StackingContextHelper>>* mRootStackingContexts;
   wr::RenderRootArray<ClipManager> mClipManagers;
   ClipManager* mCurrentClipManager;
 
   // We use this as a temporary data structure while building the mScrollData
   // inside a layers-free transaction.
   WebRenderScrollDataCollection mLayerScrollDatas;
@@ -251,16 +250,18 @@ class WebRenderCommandBuilder final {
   WebRenderUserDataRefTable mWebRenderUserDatas;
 
   // Store of WebRenderCanvasData objects for use in empty transactions
   CanvasDataSet mLastCanvasDatas;
 
   wr::RenderRootArray<wr::usize> mBuilderDumpIndex;
   wr::usize mDumpIndent;
 
+  DisplayItemCache mDisplayItemCache;
+
  public:
   // Whether consecutive inactive display items should be grouped into one
   // blob image.
   bool mDoGrouping;
 
   // True if the most recently build display list contained an svg that
   // we did grouping for.
   bool mContainsSVGGroup;
--- a/layout/painting/RetainedDisplayListBuilder.cpp
+++ b/layout/painting/RetainedDisplayListBuilder.cpp
@@ -1444,16 +1444,17 @@ PartialUpdateResult RetainedDisplayListB
 
   nsRect modifiedDirty;
   AnimatedGeometryRoot* modifiedAGR = nullptr;
   PartialUpdateResult result = PartialUpdateResult::NoChange;
   if (!shouldBuildPartial ||
       !ComputeRebuildRegion(modifiedFrames.Frames(), &modifiedDirty,
                             &modifiedAGR, framesWithProps.Frames()) ||
       !PreProcessDisplayList(&mList, modifiedAGR, result)) {
+    mBuilder.SetPartialBuildFailed(true);
     mBuilder.LeavePresShell(mBuilder.RootReferenceFrame(), nullptr);
     mList.DeleteAll(&mBuilder);
     return PartialUpdateResult::Failed;
   }
 
   // This is normally handled by EnterPresShell, but we skipped it so that we
   // didn't call MarkFrameForDisplayIfVisible before ComputeRebuildRegion.
   nsIScrollableFrame* sf = mBuilder.RootReferenceFrame()
@@ -1468,31 +1469,31 @@ PartialUpdateResult RetainedDisplayListB
   }
 
   modifiedDirty.IntersectRect(
       modifiedDirty,
       mBuilder.RootReferenceFrame()->GetVisualOverflowRectRelativeToSelf());
 
   mBuilder.SetDirtyRect(modifiedDirty);
   mBuilder.SetPartialUpdate(true);
+  mBuilder.SetPartialBuildFailed(false);
 
   nsDisplayList modifiedDL;
   mBuilder.RootReferenceFrame()->BuildDisplayListForStackingContext(
       &mBuilder, &modifiedDL);
   if (!modifiedDL.IsEmpty()) {
     nsLayoutUtils::AddExtraBackgroundItems(
         &mBuilder, &modifiedDL, mBuilder.RootReferenceFrame(),
         nsRect(nsPoint(0, 0), mBuilder.RootReferenceFrame()->GetSize()),
         mBuilder.RootReferenceFrame()->GetVisualOverflowRectRelativeToSelf(),
         aBackstop);
   }
   mBuilder.SetPartialUpdate(false);
 
   if (mBuilder.PartialBuildFailed()) {
-    mBuilder.SetPartialBuildFailed(false);
     mBuilder.LeavePresShell(mBuilder.RootReferenceFrame(), nullptr);
     mList.DeleteAll(&mBuilder);
     modifiedDL.DeleteAll(&mBuilder);
     Metrics()->mPartialUpdateFailReason = PartialUpdateFailReason::Content;
     return PartialUpdateResult::Failed;
   }
 
   if (aChecker) {
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -3208,31 +3208,34 @@ class nsPaintedDisplayItem : public nsDi
   /**
    * Paint this item to some rendering context.
    */
   virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
     // TODO(miko): Make this a pure virtual function to force implementation.
     MOZ_ASSERT_UNREACHABLE("Paint() is not implemented!");
   }
 
+  Maybe<uint16_t>& CacheIndex() { return mCacheIndex; }
+
  protected:
   nsPaintedDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
       : nsDisplayItem(aBuilder, aFrame) {}
 
   nsPaintedDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                        const ActiveScrolledRoot* aActiveScrolledRoot)
       : nsDisplayItem(aBuilder, aFrame, aActiveScrolledRoot) {}
 
   nsPaintedDisplayItem(nsDisplayListBuilder* aBuilder,
                        const nsPaintedDisplayItem& aOther)
       : nsDisplayItem(aBuilder, aOther) {}
 
  private:
   mozilla::DisplayItemData* mDisplayItemData = nullptr;
   mozilla::layers::LayerManager* mDisplayItemDataLayerManager = nullptr;
+  mozilla::Maybe<uint16_t> mCacheIndex;
 };
 
 /**
  * Manages a singly-linked list of display list items.
  *
  * mSentinel is the sentinel list value, the first value in the null-terminated
  * linked list of items. mTop is the last item in the list (whose 'above'
  * pointer is null). This class has no virtual methods. So list objects are just