Bug 1247554 - Refactor will-change budget internals into general-purpose AGR budget; r?benwa draft
authorJamie Nicol <jnicol@mozilla.com>
Thu, 11 Feb 2016 14:16:38 +0000
changeset 331269 06655cf94beb42d31827089224d92a6880d0aaad
parent 331237 6ea654cad929c9bedd8a4161a182b6189fbeae6a
child 331270 3743b3f6c40b2721ca5579c5992bffe2b01b6e17
push id10951
push userbmo:jnicol@mozilla.com
push dateTue, 16 Feb 2016 18:31:48 +0000
reviewersbenwa
bugs1247554
milestone47.0a1
Bug 1247554 - Refactor will-change budget internals into general-purpose AGR budget; r?benwa The public interface remains the same, but internally to nsDisplayListBuilder make the will-change budget an instance of a more general "AGR budget". This will allow us to easily budget the creation of AGRs due to other reasons as well. MozReview-Commit-ID: JVqbhuhsMpL
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -590,26 +590,29 @@ nsDisplayListBuilder::AddAnimationsAndTr
   } else if (aProperty == eCSSProperty_opacity) {
     data = null_t();
   }
 
   AddAnimationsForProperty(aFrame, aProperty, compositorAnimations,
                            aLayer, data, pending);
 }
 
+const float gWillChangeAreaMultiplier = 3.0f;
+
 nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
     Mode aMode, bool aBuildCaret)
     : mReferenceFrame(aReferenceFrame),
       mIgnoreScrollFrame(nullptr),
       mLayerEventRegions(nullptr),
       mCurrentTableItem(nullptr),
       mCurrentFrame(aReferenceFrame),
       mCurrentReferenceFrame(aReferenceFrame),
       mCurrentAGR(&mRootAGR),
       mRootAGR(aReferenceFrame, nullptr),
+      mWillChangeBudget(gWillChangeAreaMultiplier),
       mDirtyRect(-1,-1,-1,-1),
       mGlassDisplayItem(nullptr),
       mPendingScrollInfoItems(nullptr),
       mCommittedScrollInfoItems(nullptr),
       mMode(aMode),
       mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID),
       mCurrentScrollbarTarget(FrameMetrics::NULL_SCROLL_ID),
       mCurrentScrollbarFlags(0),
@@ -1249,74 +1252,85 @@ nsDisplayListBuilder::AdjustWindowDraggi
 LayoutDeviceIntRegion
 nsDisplayListBuilder::GetWindowDraggingRegion() const
 {
   LayoutDeviceIntRegion result;
   result.Sub(mWindowDraggingRegion, mWindowNoDraggingRegion);;
   return result;
 }
 
-const uint32_t gWillChangeAreaMultiplier = 3;
-static uint32_t GetWillChangeCost(const nsSize& aSize) {
+static uint32_t GetAGRBudgetCost(const nsSize& aSize) {
   // There's significant overhead for each layer created from Gecko
   // (IPC+Shared Objects) and from the backend (like an OpenGL texture).
   // Therefore we set a minimum cost threshold of a 64x64 area.
   int minBudgetCost = 64 * 64;
 
   uint32_t budgetCost =
     std::max(minBudgetCost,
       nsPresContext::AppUnitsToIntCSSPixels(aSize.width) *
       nsPresContext::AppUnitsToIntCSSPixels(aSize.height));
 
   return budgetCost;
 }
 
 bool
-nsDisplayListBuilder::AddToWillChangeBudget(nsIFrame* aFrame,
-                                            const nsSize& aSize) {
+nsDisplayListBuilder::AddToAGRBudget(AGRBudget& aBudget,
+                                     nsIFrame* aFrame,
+                                     const nsSize& aSize)
+{
   if (mBudgetSet.Contains(aFrame)) {
     return true; // Already accounted
   }
 
   nsPresContext* key = aFrame->PresContext();
-  if (!mWillChangeBudget.Contains(key)) {
-    mWillChangeBudget.Put(key, DocumentWillChangeBudget());
-  }
-
-  DocumentWillChangeBudget budget;
-  mWillChangeBudget.Get(key, &budget);
+  if (!aBudget.mDocuments.Contains(key)) {
+    aBudget.mDocuments.Put(key, DocumentAGRBudget());
+  }
+
+  DocumentAGRBudget budget;
+  aBudget.mDocuments.Get(key, &budget);
 
   nsRect area = aFrame->PresContext()->GetVisibleArea();
   uint32_t budgetLimit = nsPresContext::AppUnitsToIntCSSPixels(area.width) *
     nsPresContext::AppUnitsToIntCSSPixels(area.height);
 
-  uint32_t cost = GetWillChangeCost(aSize);
-  bool onBudget = (budget.mBudget + cost) /
-                    gWillChangeAreaMultiplier < budgetLimit;
+  uint32_t cost = GetAGRBudgetCost(aSize);
+  bool onBudget;
+  if (aBudget.mAreaMultiplier < 1) {
+    onBudget = budget.mBudget + cost < budgetLimit * aBudget.mAreaMultiplier;
+  } else {
+    onBudget = (budget.mBudget + cost) / aBudget.mAreaMultiplier < budgetLimit;
+  }
 
   if (onBudget) {
     budget.mBudget += cost;
-    mWillChangeBudget.Put(key, budget);
+    aBudget.mDocuments.Put(key, budget);
     mBudgetSet.PutEntry(aFrame);
   }
 
   return onBudget;
 }
 
 bool
+nsDisplayListBuilder::AddToWillChangeBudget(nsIFrame* aFrame,
+                                            const nsSize& aSize) {
+  return AddToAGRBudget(mWillChangeBudget, aFrame, aSize);
+}
+
+bool
 nsDisplayListBuilder::IsInWillChangeBudget(nsIFrame* aFrame,
                                            const nsSize& aSize) {
   bool onBudget = AddToWillChangeBudget(aFrame, aSize);
 
   if (!onBudget) {
     nsString usageStr;
-    usageStr.AppendInt(GetWillChangeCost(aSize));
+    usageStr.AppendInt(GetAGRBudgetCost(aSize));
 
     nsString multiplierStr;
-    multiplierStr.AppendInt(gWillChangeAreaMultiplier);
+    multiplierStr.AppendFloat(gWillChangeAreaMultiplier);
 
     nsString limitStr;
     nsRect area = aFrame->PresContext()->GetVisibleArea();
     uint32_t budgetLimit = nsPresContext::AppUnitsToIntCSSPixels(area.width) *
       nsPresContext::AppUnitsToIntCSSPixels(area.height);
     limitStr.AppendInt(budgetLimit);
 
     const char16_t* params[] = { multiplierStr.get(), limitStr.get() };
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -1177,24 +1177,35 @@ private:
   };
 
   PresShellState* CurrentPresShellState() {
     NS_ASSERTION(mPresShellStates.Length() > 0,
                  "Someone forgot to enter a presshell");
     return &mPresShellStates[mPresShellStates.Length() - 1];
   }
 
-  struct DocumentWillChangeBudget {
-    DocumentWillChangeBudget()
+  struct DocumentAGRBudget {
+    DocumentAGRBudget()
       : mBudget(0)
     {}
 
     uint32_t mBudget;
   };
 
+  struct AGRBudget {
+    explicit AGRBudget(float aAreaMultiplier)
+      : mAreaMultiplier(aAreaMultiplier)
+      {}
+
+    nsDataHashtable<nsPtrHashKey<nsPresContext>, DocumentAGRBudget> mDocuments;
+    float mAreaMultiplier;
+  };
+
+  bool AddToAGRBudget(AGRBudget& aBudget, nsIFrame* aFrame, const nsSize& aSize);
+
   nsIFrame* const                mReferenceFrame;
   nsIFrame*                      mIgnoreScrollFrame;
   nsDisplayLayerEventRegions*    mLayerEventRegions;
   PLArenaPool                    mPool;
   nsCOMPtr<nsISelection>         mBoundingSelection;
   AutoTArray<PresShellState,8> mPresShellStates;
   AutoTArray<nsIFrame*,100>    mFramesMarkedForDisplay;
   AutoTArray<ThemeGeometry,2>  mThemeGeometries;
@@ -1207,18 +1218,17 @@ private:
   const nsIFrame*                mCurrentReferenceFrame;
   // The offset from mCurrentFrame to mCurrentReferenceFrame.
   nsPoint                        mCurrentOffsetToReferenceFrame;
 
   AnimatedGeometryRoot*          mCurrentAGR;
   AnimatedGeometryRoot           mRootAGR;
 
   // will-change budget tracker
-  nsDataHashtable<nsPtrHashKey<nsPresContext>, DocumentWillChangeBudget>
-                                 mWillChangeBudget;
+  AGRBudget mWillChangeBudget;
 
   // Any frame listed in this set is already counted in the budget
   // and thus is in-budget.
   nsTHashtable<nsPtrHashKey<nsIFrame> > mBudgetSet;
 
   // rects are relative to the frame's reference frame
   nsDataHashtable<nsPtrHashKey<nsIFrame>, nsRect> mDirtyRectForScrolledContents;