--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3794,17 +3794,20 @@ nsLayoutUtils::PaintFrame(gfxContext* aR
nsRect dirtyRect = visibleRegion.GetBounds();
{
AUTO_PROFILER_LABEL("nsLayoutUtils::PaintFrame:BuildDisplayList",
GRAPHICS);
AutoProfilerTracing tracing("Paint", "DisplayList");
PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::DisplayList);
- TimeStamp dlStart = TimeStamp::Now();
+
+ TimeStamp dlTotalStart = TimeStamp::Now();
+ double retainedBuildTime = 0.0, fullBuildTime = 0.0;
+ DisplayListStatistics stats;
{
// If a scrollable container layer is created in nsDisplayList::PaintForFrame,
// it will be the scroll parent for display items that are built in the
// BuildDisplayListForStackingContext call below. We need to set the scroll
// parent on the display list builder while we build those items, so that they
// can pick up their scroll parent's id.
ViewID id = FrameMetrics::NULL_SCROLL_ID;
@@ -3826,64 +3829,75 @@ nsLayoutUtils::PaintFrame(gfxContext* aR
}
}
nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(&builder, id);
builder.SetVisibleRect(dirtyRect);
builder.SetIsBuilding(true);
+ TimeStamp dlStart = TimeStamp::Now();
+
const bool paintedPreviously =
aFrame->HasProperty(nsIFrame::ModifiedFrameList());
bool merged = false;
if (retainedBuilder && paintedPreviously) {
- merged = retainedBuilder->AttemptPartialUpdate(aBackstop);
+ merged = retainedBuilder->AttemptPartialUpdate(aBackstop, stats);
+ stats.triedPartial = true;
+ stats.merged = merged;
}
+ retainedBuildTime = (TimeStamp::Now() - dlStart).ToMilliseconds();
if (merged && gfxPrefs::LayoutDisplayListBuildTwice()) {
merged = false;
- if (gfxPrefs::LayersDrawFPS()) {
- if (RefPtr<LayerManager> lm = builder.GetWidgetLayerManager()) {
- if (PaintTiming* pt = ClientLayerManager::MaybeGetPaintTiming(lm)) {
- pt->dl2Ms() = (TimeStamp::Now() - dlStart).ToMilliseconds();
- }
- }
- }
dlStart = TimeStamp::Now();
}
if (!merged) {
list.DeleteAll(&builder);
builder.EnterPresShell(aFrame);
builder.SetDirtyRect(dirtyRect);
builder.ClearWindowDraggingRegion();
aFrame->BuildDisplayListForStackingContext(&builder, &list);
AddExtraBackgroundItems(builder, list, aFrame, canvasArea, visibleRegion, aBackstop);
builder.LeavePresShell(aFrame, &list);
}
+ fullBuildTime = (TimeStamp::Now() - dlStart).ToMilliseconds();
}
builder.SetIsBuilding(false);
// if (XRE_IsContentProcess()) {
// printf_stderr("Painting --- Full list:\n");
// nsFrame::PrintDisplayList(&builder, list);
// }
builder.IncrementPresShellPaintCount(presShell);
if (gfxPrefs::LayersDrawFPS()) {
- if (RefPtr<LayerManager> lm = builder.GetWidgetLayerManager()) {
- if (PaintTiming* pt = ClientLayerManager::MaybeGetPaintTiming(lm)) {
- pt->dlMs() = (TimeStamp::Now() - dlStart).ToMilliseconds();
- }
+ RefPtr<LayerManager> lm = builder.GetWidgetLayerManager();
+ PaintTiming* pt = ClientLayerManager::MaybeGetPaintTiming(lm);
+
+ if (pt && gfxPrefs::LayoutDisplayListBuildTwice()) {
+ pt->dlMs() = retainedBuildTime;
+ pt->dl2Ms() = fullBuildTime;
+ } else if (pt) {
+ pt->dlMs() = (TimeStamp::Now() - dlTotalStart).ToMilliseconds();
}
}
+
+ if (stats.triedPartial && gfxPrefs::LayoutDisplayListBuildTwice()) {
+ printf(R"({ "retained": %.3f, "full": %.3f, "modifiedFrames": %d, )"
+ R"("listSize": %d, "hadCanvas": %d, "hadViewPort": %d, )"
+ R"("merged": %d },)" "\n",
+ retainedBuildTime, fullBuildTime, stats.modifiedFrames, list.Count(),
+ stats.hadCanvas, stats.hadViewport, stats.merged);
+ }
}
Telemetry::AccumulateTimeDelta(Telemetry::PAINT_BUILD_DISPLAYLIST_TIME,
startBuildDisplayList);
bool profilerNeedsDisplayList =
profiler_feature_active(ProfilerFeature::DisplayListDump);
bool consoleNeedsDisplayList = gfxUtils::DumpDisplayList() || gfxEnv::DumpPaint();
--- a/layout/painting/RetainedDisplayListBuilder.cpp
+++ b/layout/painting/RetainedDisplayListBuilder.cpp
@@ -677,27 +677,45 @@ RetainedDisplayListBuilder::ComputeRebui
}
}
return true;
}
bool
-RetainedDisplayListBuilder::AttemptPartialUpdate(nscolor aBackstop)
+RetainedDisplayListBuilder::AttemptPartialUpdate(nscolor aBackstop,
+ DisplayListStatistics& aStats)
{
mBuilder.RemoveModifiedWindowDraggingRegion();
if (mBuilder.ShouldSyncDecodeImages()) {
MarkFramesWithItemsAndImagesModified(&mList);
}
mBuilder.EnterPresShell(mBuilder.RootReferenceFrame());
std::vector<WeakFrame> modifiedFrames = GetModifiedFrames(mBuilder.RootReferenceFrame());
+ aStats.modifiedFrames = modifiedFrames.size();
+ for (WeakFrame& frame : modifiedFrames) {
+ if (!frame) {
+ continue;
+ }
+
+ LayoutFrameType type = frame->Type();
+ if (type == LayoutFrameType::Viewport ||
+ type == LayoutFrameType::PageContent) {
+ aStats.hadViewport = true;
+ }
+
+ if (type == LayoutFrameType::Canvas) {
+ aStats.hadCanvas = true;
+ }
+ }
+
if (mPreviousCaret != mBuilder.GetCaretFrame()) {
if (mPreviousCaret) {
mBuilder.MarkFrameModifiedDuringBuilding(mPreviousCaret);
}
if (mBuilder.GetCaretFrame()) {
mBuilder.MarkFrameModifiedDuringBuilding(mBuilder.GetCaretFrame());
}
--- a/layout/painting/RetainedDisplayListBuilder.h
+++ b/layout/painting/RetainedDisplayListBuilder.h
@@ -2,32 +2,41 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef RETAINEDDISPLAYLISTBUILDER_H_
#define RETAINEDDISPLAYLISTBUILDER_H_
#include "nsDisplayList.h"
+struct DisplayListStatistics {
+ uint32_t modifiedFrames = 0;
+ bool triedPartial = false;
+ bool merged = false;
+
+ bool hadCanvas = false;
+ bool hadViewport = false;
+};
+
struct RetainedDisplayListBuilder {
RetainedDisplayListBuilder(nsIFrame* aReferenceFrame,
nsDisplayListBuilderMode aMode,
bool aBuildCaret)
: mBuilder(aReferenceFrame, aMode, aBuildCaret, true)
{}
~RetainedDisplayListBuilder()
{
mList.DeleteAll(&mBuilder);
}
nsDisplayListBuilder* Builder() { return &mBuilder; }
nsDisplayList* List() { return &mList; }
- bool AttemptPartialUpdate(nscolor aBackstop);
+ bool AttemptPartialUpdate(nscolor aBackstop, DisplayListStatistics& aStats);
NS_DECLARE_FRAME_PROPERTY_DELETABLE(Cached, RetainedDisplayListBuilder)
private:
void PreProcessDisplayList(nsDisplayList* aList, AnimatedGeometryRoot* aAGR);
void MergeDisplayLists(nsDisplayList* aNewList,
nsDisplayList* aOldList,