Bug 1490404 - Part 2: Add retained display list statistics r=mattwoodrow

Differential Revision: https://phabricator.services.mozilla.com/D33680

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Miko Mynttinen 2019-06-06 17:54:14 +00:00
Родитель fbfcf25cc9
Коммит 6c57050ada
4 изменённых файлов: 206 добавлений и 77 удалений

Просмотреть файл

@ -66,7 +66,7 @@ std::string Diagnostics::GetFrameOverlayString(const GPUStats& aStats) {
gpuTimeString = nsPrintfCString("%0.1fms", mGPUDrawMs.Average()).get(); gpuTimeString = nsPrintfCString("%0.1fms", mGPUDrawMs.Average()).get();
} }
// DL = nsDisplayListBuilder // DL = nsDisplayListBuilder, p = partial, f = full
// FLB = FrameLayerBuilder // FLB = FrameLayerBuilder
// R = ClientLayerManager::EndTransaction // R = ClientLayerManager::EndTransaction
// CP = ShadowLayerForwarder::EndTransaction (txn build) // CP = ShadowLayerForwarder::EndTransaction (txn build)
@ -80,17 +80,10 @@ std::string Diagnostics::GetFrameOverlayString(const GPUStats& aStats) {
"[CC] Build: %0.1fms Exec: %0.1fms GPU: %s Fill Ratio: %0.1f/%0.1f", "[CC] Build: %0.1fms Exec: %0.1fms GPU: %s Fill Ratio: %0.1f/%0.1f",
mPrepareMs.Average(), mCompositeMs.Average(), gpuTimeString.c_str(), mPrepareMs.Average(), mCompositeMs.Average(), gpuTimeString.c_str(),
pixelFillRatio, screenFillRatio); pixelFillRatio, screenFillRatio);
nsCString line3; nsPrintfCString line3(
if (mDlb2Ms.Average() != 0.0f) { "[Content] DL p: %0.1f DL f: %0.1fms FLB: %0.1fms Raster: %0.1fms",
line3 += nsPrintfCString( mDlbMs.Average(), mDlb2Ms.Average(), mFlbMs.Average(),
"[Content] DL: %0.1f/%0.1fms FLB: %0.1fms Raster: %0.1fms", mRasterMs.Average());
mDlb2Ms.Average(), mDlbMs.Average(), mFlbMs.Average(),
mRasterMs.Average());
} else {
line3 += nsPrintfCString(
"[Content] DL: %0.1fms FLB: %0.1fms Raster: %0.1fms", mDlbMs.Average(),
mFlbMs.Average(), mRasterMs.Average());
}
nsPrintfCString line4("[IPDL] Build: %0.1fms Send: %0.1fms Update: %0.1fms", nsPrintfCString line4("[IPDL] Build: %0.1fms Send: %0.1fms Update: %0.1fms",
mSerializeMs.Average(), mSendMs.Average(), mSerializeMs.Average(), mSendMs.Average(),
mUpdateMs.Average()); mUpdateMs.Average());

Просмотреть файл

@ -3558,8 +3558,11 @@ struct TemporaryDisplayListBuilder {
const bool aBuildCaret) const bool aBuildCaret)
: mBuilder(aFrame, aBuilderMode, aBuildCaret) {} : mBuilder(aFrame, aBuilderMode, aBuildCaret) {}
~TemporaryDisplayListBuilder() { mList.DeleteAll(&mBuilder); }
nsDisplayListBuilder mBuilder; nsDisplayListBuilder mBuilder;
nsDisplayList mList; nsDisplayList mList;
RetainedDisplayListMetrics mMetrics;
}; };
nsresult nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsresult nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext,
@ -3569,7 +3572,6 @@ nsresult nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext,
nsDisplayListBuilderMode aBuilderMode, nsDisplayListBuilderMode aBuilderMode,
PaintFrameFlags aFlags) { PaintFrameFlags aFlags) {
AUTO_PROFILER_LABEL("nsLayoutUtils::PaintFrame", GRAPHICS); AUTO_PROFILER_LABEL("nsLayoutUtils::PaintFrame", GRAPHICS);
typedef RetainedDisplayListBuilder::PartialUpdateResult PartialUpdateResult;
#ifdef MOZ_DUMP_PAINTING #ifdef MOZ_DUMP_PAINTING
if (!gPaintCountStack) { if (!gPaintCountStack) {
@ -3620,16 +3622,21 @@ nsresult nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext,
Maybe<TemporaryDisplayListBuilder> temporaryBuilder; Maybe<TemporaryDisplayListBuilder> temporaryBuilder;
nsDisplayListBuilder* builder = nullptr; nsDisplayListBuilder* builder = nullptr;
nsDisplayList* list = nullptr; nsDisplayList* list = nullptr;
RetainedDisplayListMetrics* metrics = nullptr;
if (useRetainedBuilder) { if (useRetainedBuilder) {
builder = retainedBuilder->Builder(); builder = retainedBuilder->Builder();
list = retainedBuilder->List(); list = retainedBuilder->List();
metrics = retainedBuilder->Metrics();
} else { } else {
temporaryBuilder.emplace(aFrame, aBuilderMode, buildCaret); temporaryBuilder.emplace(aFrame, aBuilderMode, buildCaret);
builder = &temporaryBuilder->mBuilder; builder = &temporaryBuilder->mBuilder;
list = &temporaryBuilder->mList; list = &temporaryBuilder->mList;
metrics = &temporaryBuilder->mMetrics;
} }
MOZ_ASSERT(builder && list && metrics);
// Retained builder exists, but display list retaining is disabled. // Retained builder exists, but display list retaining is disabled.
if (!useRetainedBuilder && retainedBuilder) { if (!useRetainedBuilder && retainedBuilder) {
// Clear the modified frames lists and frame properties. // Clear the modified frames lists and frame properties.
@ -3639,6 +3646,9 @@ nsresult nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext,
retainedBuilder->List()->DeleteAll(retainedBuilder->Builder()); retainedBuilder->List()->DeleteAll(retainedBuilder->Builder());
} }
metrics->Reset();
metrics->StartBuild();
builder->BeginFrame(); builder->BeginFrame();
if (aFlags & PaintFrameFlags::InTransform) { if (aFlags & PaintFrameFlags::InTransform) {
@ -3745,8 +3755,6 @@ nsresult nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext,
AUTO_PROFILER_TRACING("Paint", "DisplayList", GRAPHICS); AUTO_PROFILER_TRACING("Paint", "DisplayList", GRAPHICS);
PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::DisplayList); PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::DisplayList);
TimeStamp dlStart = TimeStamp::Now();
{ {
// If a scrollable container layer is created in // If a scrollable container layer is created in
// nsDisplayList::PaintForFrame, it will be the scroll parent for display // nsDisplayList::PaintForFrame, it will be the scroll parent for display
@ -3826,28 +3834,35 @@ nsresult nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext,
if (StaticPrefs::LayoutVerifyRetainDisplayList()) { if (StaticPrefs::LayoutVerifyRetainDisplayList()) {
beforeMergeChecker.Set(list, "BM"); beforeMergeChecker.Set(list, "BM");
} }
updateState = retainedBuilder->AttemptPartialUpdate( updateState = retainedBuilder->AttemptPartialUpdate(
aBackstop, beforeMergeChecker ? &toBeMergedChecker : nullptr); aBackstop, beforeMergeChecker ? &toBeMergedChecker : nullptr);
if ((updateState != PartialUpdateResult::Failed) && if ((updateState != PartialUpdateResult::Failed) &&
beforeMergeChecker) { beforeMergeChecker) {
afterMergeChecker.Set(list, "AM"); afterMergeChecker.Set(list, "AM");
} }
metrics->EndPartialBuild(updateState);
} else {
// Partial updates are disabled.
metrics->mPartialUpdateResult = PartialUpdateResult::Failed;
metrics->mPartialUpdateFailReason = PartialUpdateFailReason::Disabled;
} }
if ((updateState != PartialUpdateResult::Failed) && // Rebuild the full display list if the partial display list build failed,
(StaticPrefs::LayoutDisplayListBuildTwice() || afterMergeChecker)) { // or if the merge checker is used.
updateState = PartialUpdateResult::Failed; bool doFullRebuild =
if (StaticPrefs::LayersDrawFPS()) { updateState == PartialUpdateResult::Failed || afterMergeChecker;
if (RefPtr<LayerManager> lm = builder->GetWidgetLayerManager()) {
if (PaintTiming* pt = ClientLayerManager::MaybeGetPaintTiming(lm)) { if (StaticPrefs::LayoutDisplayListBuildTwice()) {
pt->dl2Ms() = (TimeStamp::Now() - dlStart).ToMilliseconds(); // Build display list twice to compare partial and full display list
} // build times.
} metrics->StartBuild();
} doFullRebuild = true;
dlStart = TimeStamp::Now();
} }
if (updateState == PartialUpdateResult::Failed) { if (doFullRebuild) {
list->DeleteAll(builder); list->DeleteAll(builder);
builder->ClearRetainedWindowRegions(); builder->ClearRetainedWindowRegions();
@ -3860,6 +3875,8 @@ nsresult nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext,
visibleRegion, aBackstop); visibleRegion, aBackstop);
builder->LeavePresShell(aFrame, list); builder->LeavePresShell(aFrame, list);
metrics->EndFullBuild();
updateState = PartialUpdateResult::Updated; updateState = PartialUpdateResult::Updated;
if (afterMergeChecker) { if (afterMergeChecker) {
@ -3888,13 +3905,15 @@ nsresult nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext,
builder->SetIsBuilding(false); builder->SetIsBuilding(false);
builder->IncrementPresShellPaintCount(presShell); builder->IncrementPresShellPaintCount(presShell);
}
if (StaticPrefs::LayersDrawFPS()) { if (StaticPrefs::LayersDrawFPS()) {
if (RefPtr<LayerManager> lm = builder->GetWidgetLayerManager()) { RefPtr<LayerManager> lm = builder->GetWidgetLayerManager();
if (PaintTiming* pt = ClientLayerManager::MaybeGetPaintTiming(lm)) { PaintTiming* pt = ClientLayerManager::MaybeGetPaintTiming(lm);
pt->dlMs() = (TimeStamp::Now() - dlStart).ToMilliseconds();
} if (pt) {
} pt->dlMs() = static_cast<float>(metrics->mPartialBuildDuration);
pt->dl2Ms() = static_cast<float>(metrics->mFullBuildDuration);
} }
} }
@ -4116,13 +4135,28 @@ nsresult nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext,
{ {
AUTO_PROFILER_TRACING("Paint", "DisplayListResources", GRAPHICS); AUTO_PROFILER_TRACING("Paint", "DisplayListResources", GRAPHICS);
// Flush the list so we don't trigger the IsEmpty-on-destruction assertion
if (!useRetainedBuilder) {
list->DeleteAll(builder);
}
builder->EndFrame(); builder->EndFrame();
if (!useRetainedBuilder) {
temporaryBuilder.reset();
}
} }
#if 0
if (XRE_IsParentProcess()) {
if (metrics->mPartialUpdateResult == PartialUpdateResult::Failed) {
printf("DL partial update failed: %s, Frame: %p\n",
metrics->FailReasonString(), aFrame);
} else {
printf(
"DL partial build success!"
" new: %d, reused: %d, rebuilt: %d, removed: %d, total: %d\n",
metrics->mNewItems, metrics->mReusedItems, metrics->mRebuiltItems,
metrics->mRemovedItems, metrics->mTotalItems);
}
}
#endif
return NS_OK; return NS_OK;
} }

Просмотреть файл

@ -192,6 +192,7 @@ bool RetainedDisplayListBuilder::PreProcessDisplayList(
} }
item->Destroy(&mBuilder); item->Destroy(&mBuilder);
Metrics()->mRemovedItems++;
i++; i++;
aUpdated = PartialUpdateResult::Updated; aUpdated = PartialUpdateResult::Updated;
@ -396,6 +397,7 @@ void OldItemInfo::Discard(RetainedDisplayListBuilder* aBuilder,
if (mItem) { if (mItem) {
MOZ_ASSERT(mOwnsItem); MOZ_ASSERT(mOwnsItem);
mItem->Destroy(aBuilder->Builder()); mItem->Destroy(aBuilder->Builder());
aBuilder->Metrics()->mRemovedItems++;
} }
mItem = nullptr; mItem = nullptr;
} }
@ -436,6 +438,7 @@ class MergeState {
HasModifiedFrame(aNewItem)); HasModifiedFrame(aNewItem));
if (!aNewItem->HasModifiedFrame() && if (!aNewItem->HasModifiedFrame() &&
HasMatchingItemInOldList(aNewItem, &oldIndex)) { HasMatchingItemInOldList(aNewItem, &oldIndex)) {
mBuilder->Metrics()->mRebuiltItems++;
nsDisplayItem* oldItem = mOldItems[oldIndex.val].mItem; nsDisplayItem* oldItem = mOldItems[oldIndex.val].mItem;
MOZ_DIAGNOSTIC_ASSERT(oldItem->GetPerFrameKey() == MOZ_DIAGNOSTIC_ASSERT(oldItem->GetPerFrameKey() ==
aNewItem->GetPerFrameKey() && aNewItem->GetPerFrameKey() &&
@ -648,6 +651,8 @@ class MergeState {
#endif #endif
mMergedItems.AppendToTop(aItem); mMergedItems.AppendToTop(aItem);
mBuilder->Metrics()->mTotalItems++;
MergedListIndex newIndex = MergedListIndex newIndex =
mMergedDAG.AddNode(aDirectPredecessors, aExtraDirectPredecessor); mMergedDAG.AddNode(aDirectPredecessors, aExtraDirectPredecessor);
return newIndex; return newIndex;
@ -671,6 +676,7 @@ class MergeState {
mBuilder->IncrementSubDocPresShellPaintCount(item); mBuilder->IncrementSubDocPresShellPaintCount(item);
} }
item->SetReused(true); item->SetReused(true);
mBuilder->Metrics()->mReusedItems++;
mOldItems[aNode.val].AddedToMergedList( mOldItems[aNode.val].AddedToMergedList(
AddNewNode(item, Some(aNode), aDirectPredecessors, Nothing())); AddNewNode(item, Some(aNode), aDirectPredecessors, Nothing()));
} }
@ -813,6 +819,7 @@ bool RetainedDisplayListBuilder::MergeDisplayLists(
Maybe<MergedListIndex> previousItemIndex; Maybe<MergedListIndex> previousItemIndex;
while (nsDisplayItem* item = aNewList->RemoveBottom()) { while (nsDisplayItem* item = aNewList->RemoveBottom()) {
Metrics()->mNewItems++;
previousItemIndex = merge.ProcessItemFromNewList(item, previousItemIndex); previousItemIndex = merge.ProcessItemFromNewList(item, previousItemIndex);
} }
@ -1302,11 +1309,26 @@ bool RetainedDisplayListBuilder::ComputeRebuildRegion(
return true; return true;
} }
/* bool RetainedDisplayListBuilder::ShouldBuildPartial(
* A simple early exit heuristic to avoid slow partial display list rebuilds. nsTArray<nsIFrame*>& aModifiedFrames) {
*/ if (mList.IsEmpty()) {
static bool ShouldBuildPartial(nsTArray<nsIFrame*>& aModifiedFrames) { // Partial builds without a previous display list do not make sense.
Metrics()->mPartialUpdateFailReason = PartialUpdateFailReason::EmptyList;
return false;
}
if (aModifiedFrames.Length() > StaticPrefs::LayoutRebuildFrameLimit()) { if (aModifiedFrames.Length() > StaticPrefs::LayoutRebuildFrameLimit()) {
// Computing a dirty rect with too many modified frames can be slow.
Metrics()->mPartialUpdateFailReason = PartialUpdateFailReason::RebuildLimit;
return false;
}
// We don't support retaining with overlay scrollbars, since they require
// us to look at the display list and pick the highest z-index, which
// we can't do during partial building.
if (mBuilder.DisablePartialUpdates()) {
mBuilder.SetDisablePartialUpdates(false);
Metrics()->mPartialUpdateFailReason = PartialUpdateFailReason::Disabled;
return false; return false;
} }
@ -1324,6 +1346,7 @@ static bool ShouldBuildPartial(nsTArray<nsIFrame*>& aModifiedFrames) {
if (type == LayoutFrameType::Viewport || if (type == LayoutFrameType::Viewport ||
type == LayoutFrameType::PageContent || type == LayoutFrameType::PageContent ||
type == LayoutFrameType::Canvas || type == LayoutFrameType::Scrollbar) { type == LayoutFrameType::Canvas || type == LayoutFrameType::Scrollbar) {
Metrics()->mPartialUpdateFailReason = PartialUpdateFailReason::FrameType;
return false; return false;
} }
} }
@ -1331,6 +1354,26 @@ static bool ShouldBuildPartial(nsTArray<nsIFrame*>& aModifiedFrames) {
return true; return true;
} }
void RetainedDisplayListBuilder::InvalidateCaretFramesIfNeeded(
nsTArray<nsIFrame*>& aModifiedFrames) {
if (mPreviousCaret == mBuilder.GetCaretFrame()) {
// The current caret frame is the same as the previous one.
return;
}
if (mPreviousCaret &&
mBuilder.MarkFrameModifiedDuringBuilding(mPreviousCaret)) {
aModifiedFrames.AppendElement(mPreviousCaret);
}
if (mBuilder.GetCaretFrame() &&
mBuilder.MarkFrameModifiedDuringBuilding(mBuilder.GetCaretFrame())) {
aModifiedFrames.AppendElement(mBuilder.GetCaretFrame());
}
mPreviousCaret = mBuilder.GetCaretFrame();
}
static void ClearFrameProps(nsTArray<nsIFrame*>& aFrames) { static void ClearFrameProps(nsTArray<nsIFrame*>& aFrames) {
for (nsIFrame* f : aFrames) { for (nsIFrame* f : aFrames) {
if (f->HasOverrideDirtyRegion()) { if (f->HasOverrideDirtyRegion()) {
@ -1347,13 +1390,10 @@ static void ClearFrameProps(nsTArray<nsIFrame*>& aFrames) {
class AutoClearFramePropsArray { class AutoClearFramePropsArray {
public: public:
explicit AutoClearFramePropsArray(size_t aCapacity) : mFrames(aCapacity) {} explicit AutoClearFramePropsArray(size_t aCapacity) : mFrames(aCapacity) {}
AutoClearFramePropsArray() = default; AutoClearFramePropsArray() = default;
~AutoClearFramePropsArray() { ClearFrameProps(mFrames); } ~AutoClearFramePropsArray() { ClearFrameProps(mFrames); }
nsTArray<nsIFrame*>& Frames() { return mFrames; } nsTArray<nsIFrame*>& Frames() { return mFrames; }
bool IsEmpty() const { return mFrames.IsEmpty(); } bool IsEmpty() const { return mFrames.IsEmpty(); }
private: private:
@ -1367,9 +1407,8 @@ void RetainedDisplayListBuilder::ClearFramesWithProps() {
&framesWithProps.Frames()); &framesWithProps.Frames());
} }
auto RetainedDisplayListBuilder::AttemptPartialUpdate( PartialUpdateResult RetainedDisplayListBuilder::AttemptPartialUpdate(
nscolor aBackstop, mozilla::DisplayListChecker* aChecker) nscolor aBackstop, mozilla::DisplayListChecker* aChecker) {
-> PartialUpdateResult {
mBuilder.RemoveModifiedWindowRegions(); mBuilder.RemoveModifiedWindowRegions();
mBuilder.ClearWindowOpaqueRegion(); mBuilder.ClearWindowOpaqueRegion();
@ -1387,33 +1426,11 @@ auto RetainedDisplayListBuilder::AttemptPartialUpdate(
GetModifiedAndFramesWithProps(&mBuilder, &modifiedFrames.Frames(), GetModifiedAndFramesWithProps(&mBuilder, &modifiedFrames.Frames(),
&framesWithProps.Frames()); &framesWithProps.Frames());
// Do not allow partial builds if the retained display list is empty, or if // Do not allow partial builds if the |ShouldBuildPartial()| heuristic fails.
// ShouldBuildPartial heuristic fails. bool shouldBuildPartial = ShouldBuildPartial(modifiedFrames.Frames());
bool shouldBuildPartial =
!mList.IsEmpty() && ShouldBuildPartial(modifiedFrames.Frames());
// We don't support retaining with overlay scrollbars, since they require if (shouldBuildPartial) {
// us to look at the display list and pick the highest z-index, which InvalidateCaretFramesIfNeeded(modifiedFrames.Frames());
// we can't do during partial building.
if (mBuilder.DisablePartialUpdates()) {
shouldBuildPartial = false;
mBuilder.SetDisablePartialUpdates(false);
}
if (mPreviousCaret != mBuilder.GetCaretFrame()) {
if (mPreviousCaret) {
if (mBuilder.MarkFrameModifiedDuringBuilding(mPreviousCaret)) {
modifiedFrames.Frames().AppendElement(mPreviousCaret);
}
}
if (mBuilder.GetCaretFrame()) {
if (mBuilder.MarkFrameModifiedDuringBuilding(mBuilder.GetCaretFrame())) {
modifiedFrames.Frames().AppendElement(mBuilder.GetCaretFrame());
}
}
mPreviousCaret = mBuilder.GetCaretFrame();
} }
nsRect modifiedDirty; nsRect modifiedDirty;
@ -1465,6 +1482,7 @@ auto RetainedDisplayListBuilder::AttemptPartialUpdate(
mBuilder.LeavePresShell(mBuilder.RootReferenceFrame(), nullptr); mBuilder.LeavePresShell(mBuilder.RootReferenceFrame(), nullptr);
mList.DeleteAll(&mBuilder); mList.DeleteAll(&mBuilder);
modifiedDL.DeleteAll(&mBuilder); modifiedDL.DeleteAll(&mBuilder);
Metrics()->mPartialUpdateFailReason = PartialUpdateFailReason::Content;
return PartialUpdateResult::Failed; return PartialUpdateResult::Failed;
} }

Просмотреть файл

@ -92,6 +92,77 @@ RetainedDisplayListData* GetRetainedDisplayListData(nsIFrame* aRootFrame);
*/ */
RetainedDisplayListData* GetOrSetRetainedDisplayListData(nsIFrame* aRootFrame); RetainedDisplayListData* GetOrSetRetainedDisplayListData(nsIFrame* aRootFrame);
enum class PartialUpdateResult { Failed, NoChange, Updated };
enum class PartialUpdateFailReason {
NA,
EmptyList,
RebuildLimit,
FrameType,
Disabled,
Content
};
struct RetainedDisplayListMetrics {
RetainedDisplayListMetrics() { Reset(); }
void Reset() {
mNewItems = 0;
mRebuiltItems = 0;
mRemovedItems = 0;
mReusedItems = 0;
mTotalItems = 0;
mPartialBuildDuration = 0;
mFullBuildDuration = 0;
mPartialUpdateFailReason = PartialUpdateFailReason::NA;
mPartialUpdateResult = PartialUpdateResult::NoChange;
}
void StartBuild() { mStartTime = mozilla::TimeStamp::Now(); }
void EndFullBuild() { mFullBuildDuration = Elapsed(); }
void EndPartialBuild(PartialUpdateResult aResult) {
mPartialBuildDuration = Elapsed();
mPartialUpdateResult = aResult;
}
double Elapsed() {
return (mozilla::TimeStamp::Now() - mStartTime).ToMilliseconds();
}
const char* FailReasonString() const {
switch (mPartialUpdateFailReason) {
case PartialUpdateFailReason::NA:
return "N/A";
case PartialUpdateFailReason::EmptyList:
return "Empty list";
case PartialUpdateFailReason::RebuildLimit:
return "Rebuild limit";
case PartialUpdateFailReason::FrameType:
return "Frame type";
case PartialUpdateFailReason::Disabled:
return "Disabled";
case PartialUpdateFailReason::Content:
return "Content";
default:
MOZ_ASSERT_UNREACHABLE("Enum value not handled!");
}
}
unsigned int mNewItems;
unsigned int mRebuiltItems;
unsigned int mRemovedItems;
unsigned int mReusedItems;
unsigned int mTotalItems;
mozilla::TimeStamp mStartTime;
double mPartialBuildDuration;
double mFullBuildDuration;
PartialUpdateFailReason mPartialUpdateFailReason;
PartialUpdateResult mPartialUpdateResult;
};
struct RetainedDisplayListBuilder { struct RetainedDisplayListBuilder {
RetainedDisplayListBuilder(nsIFrame* aReferenceFrame, RetainedDisplayListBuilder(nsIFrame* aReferenceFrame,
nsDisplayListBuilderMode aMode, bool aBuildCaret) nsDisplayListBuilderMode aMode, bool aBuildCaret)
@ -102,7 +173,7 @@ struct RetainedDisplayListBuilder {
nsDisplayList* List() { return &mList; } nsDisplayList* List() { return &mList; }
enum class PartialUpdateResult { Failed, NoChange, Updated }; RetainedDisplayListMetrics* Metrics() { return &mMetrics; }
PartialUpdateResult AttemptPartialUpdate( PartialUpdateResult AttemptPartialUpdate(
nscolor aBackstop, mozilla::DisplayListChecker* aChecker); nscolor aBackstop, mozilla::DisplayListChecker* aChecker);
@ -118,6 +189,19 @@ struct RetainedDisplayListBuilder {
NS_DECLARE_FRAME_PROPERTY_DELETABLE(Cached, RetainedDisplayListBuilder) NS_DECLARE_FRAME_PROPERTY_DELETABLE(Cached, RetainedDisplayListBuilder)
private: private:
void IncrementSubDocPresShellPaintCount(nsDisplayItem* aItem);
/**
* Invalidates the current and previous caret frame if they have changed.
*/
void InvalidateCaretFramesIfNeeded(nsTArray<nsIFrame*>& aModifiedFrames);
/**
* A simple early exit heuristic to avoid slow partial display list rebuilds.
* Returns true if a partial display list build should be attempted.
*/
bool ShouldBuildPartial(nsTArray<nsIFrame*>& aModifiedFrames);
/** /**
* Recursively pre-processes the old display list tree before building the * Recursively pre-processes the old display list tree before building the
* new partial display lists, and serializes the old list into an array, * new partial display lists, and serializes the old list into an array,
@ -156,19 +240,19 @@ struct RetainedDisplayListBuilder {
nsRect* aOutDirty, nsRect* aOutDirty,
AnimatedGeometryRoot** aOutModifiedAGR, AnimatedGeometryRoot** aOutModifiedAGR,
nsTArray<nsIFrame*>& aOutFramesWithProps); nsTArray<nsIFrame*>& aOutFramesWithProps);
bool ProcessFrame(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder, bool ProcessFrame(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder,
nsIFrame* aStopAtFrame, nsIFrame* aStopAtFrame,
nsTArray<nsIFrame*>& aOutFramesWithProps, nsTArray<nsIFrame*>& aOutFramesWithProps,
const bool aStopAtStackingContext, nsRect* aOutDirty, const bool aStopAtStackingContext, nsRect* aOutDirty,
AnimatedGeometryRoot** aOutModifiedAGR); AnimatedGeometryRoot** aOutModifiedAGR);
void IncrementSubDocPresShellPaintCount(nsDisplayItem* aItem);
friend class MergeState; friend class MergeState;
nsDisplayListBuilder mBuilder; nsDisplayListBuilder mBuilder;
RetainedDisplayList mList; RetainedDisplayList mList;
WeakFrame mPreviousCaret; WeakFrame mPreviousCaret;
RetainedDisplayListMetrics mMetrics;
}; };
#endif // RETAINEDDISPLAYLISTBUILDER_H_ #endif // RETAINEDDISPLAYLISTBUILDER_H_