Bug 1098654 - Add a cache for animated geometry roots on the display list builder. r=roc
authorKartikaya Gupta <kgupta@mozilla.com>
Tue, 30 Dec 2014 09:40:01 -0500
changeset 238308 f971784902fe040c4c13b4ba72ff64d495e886ac
parent 238307 c1dc4e9356f83ca31ff4ffb410fc57d0d54f6018
child 238309 64cadfdf55f17fda9bdd6851e086bb69d44634d6
push id7472
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 20:36:27 +0000
treeherdermozilla-aurora@300ca104f8fb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs1098654
milestone37.0a1
Bug 1098654 - Add a cache for animated geometry roots on the display list builder. r=roc
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -1177,43 +1177,65 @@ nsDisplayListBuilder::IsAnimatedGeometry
   }
 
   if (aParent) {
     *aParent = parent;
   }
   return false;
 }
 
+bool
+nsDisplayListBuilder::GetCachedAnimatedGeometryRoot(const nsIFrame* aFrame,
+                                                    const nsIFrame* aStopAtAncestor,
+                                                    nsIFrame** aOutResult)
+{
+  AnimatedGeometryRootLookup lookup(aFrame, aStopAtAncestor);
+  return mAnimatedGeometryRootCache.Get(lookup, aOutResult);
+}
+
 static nsIFrame*
 ComputeAnimatedGeometryRootFor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
-                               const nsIFrame* aStopAtAncestor = nullptr)
+                               const nsIFrame* aStopAtAncestor = nullptr,
+                               bool aUseCache = false)
 {
   nsIFrame* cursor = aFrame;
   while (cursor != aStopAtAncestor) {
+    if (aUseCache) {
+      nsIFrame* result;
+      if (aBuilder->GetCachedAnimatedGeometryRoot(cursor, aStopAtAncestor, &result)) {
+        return result;
+      }
+    }
     nsIFrame* next;
     if (aBuilder->IsAnimatedGeometryRoot(cursor, &next))
       return cursor;
     cursor = next;
   }
   return cursor;
 }
 
 nsIFrame*
 nsDisplayListBuilder::FindAnimatedGeometryRootFor(nsIFrame* aFrame, const nsIFrame* aStopAtAncestor)
 {
   if (aFrame == mCurrentFrame) {
     return mCurrentAnimatedGeometryRoot;
   }
-  return ComputeAnimatedGeometryRootFor(this, aFrame, aStopAtAncestor);
+
+  nsIFrame* result = ComputeAnimatedGeometryRootFor(this, aFrame, aStopAtAncestor, true);
+  AnimatedGeometryRootLookup lookup(aFrame, aStopAtAncestor);
+  mAnimatedGeometryRootCache.Put(lookup, result);
+  return result;
 }
 
 void
 nsDisplayListBuilder::RecomputeCurrentAnimatedGeometryRoot()
 {
   mCurrentAnimatedGeometryRoot = ComputeAnimatedGeometryRootFor(this, const_cast<nsIFrame *>(mCurrentFrame));
+  AnimatedGeometryRootLookup lookup(mCurrentFrame, nullptr);
+  mAnimatedGeometryRootCache.Put(lookup, mCurrentAnimatedGeometryRoot);
 }
 
 void
 nsDisplayListBuilder::AdjustWindowDraggingRegion(nsIFrame* aFrame)
 {
   if (!IsForPainting() || IsInSubdocument() || IsInTransform()) {
     return;
   }
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -790,16 +790,25 @@ public:
    * The cost should be fully calculated during the layer building phase
    * and a decission to allow or disallow will-change for all frames of
    * that document will be made by IsInWillChangeBudget.
    */
   void AddToWillChangeBudget(nsIFrame* aFrame, const nsSize& aSize);
 
   bool IsInWillChangeBudget(nsIFrame* aFrame) const;
 
+  /**
+   * Look up the cached animated geometry root for aFrame subject to
+   * aStopAtAncestor. Store the nsIFrame* result into *aOutResult, and return
+   * true if the cache was hit. Return false if the cache was not hit.
+   */
+  bool GetCachedAnimatedGeometryRoot(const nsIFrame* aFrame,
+                                     const nsIFrame* aStopAtAncestor,
+                                     nsIFrame** aOutResult);
+
 private:
   void MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, nsIFrame* aFrame,
                                     const nsRect& aDirtyRect);
 
   struct PresShellState {
     nsIPresShell* mPresShell;
     nsIFrame*     mCaretFrame;
     nsRect        mCaretRect;
@@ -835,16 +844,38 @@ private:
   // BuildDisplayList on.
   const nsIFrame*                mCurrentFrame;
   // The reference frame for mCurrentFrame.
   const nsIFrame*                mCurrentReferenceFrame;
   // The offset from mCurrentFrame to mCurrentReferenceFrame.
   nsPoint                        mCurrentOffsetToReferenceFrame;
   // The animated geometry root for mCurrentFrame.
   nsIFrame*                      mCurrentAnimatedGeometryRoot;
+
+  struct AnimatedGeometryRootLookup {
+    const nsIFrame* mFrame;
+    const nsIFrame* mStopAtFrame;
+
+    AnimatedGeometryRootLookup(const nsIFrame* aFrame, const nsIFrame* aStopAtFrame)
+      : mFrame(aFrame)
+      , mStopAtFrame(aStopAtFrame)
+    {
+    }
+
+    PLDHashNumber Hash() const {
+      return mozilla::HashBytes(this, sizeof(this));
+    }
+
+    bool operator==(const AnimatedGeometryRootLookup& aOther) const {
+      return mFrame == aOther.mFrame && mStopAtFrame == aOther.mStopAtFrame;
+    }
+  };
+  // Cache for storing animated geometry roots for arbitrary frames
+  nsDataHashtable<nsGenericHashKey<AnimatedGeometryRootLookup>, nsIFrame*>
+                                 mAnimatedGeometryRootCache;
   // will-change budget tracker
   nsDataHashtable<nsPtrHashKey<nsPresContext>, DocumentWillChangeBudget>
                                  mWillChangeBudget;
   // Assert that we never check the budget before its fully calculated.
   mutable mozilla::DebugOnly<bool> mWillChangeBudgetCalculated;
   // Relative to mCurrentFrame.
   nsRect                         mDirtyRect;
   nsRegion                       mWindowExcludeGlassRegion;