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
--- 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;