зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
fbfcf25cc9
Коммит
6c57050ada
|
@ -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_
|
||||||
|
|
Загрузка…
Ссылка в новой задаче