diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index 8d8a4c4bbcf8..8b0e20b11604 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -644,7 +644,7 @@ private: DECL_GFX_PREF(Live, "layout.css.touch_action.enabled", TouchActionEnabled, bool, false); DECL_GFX_PREF(Live, "layout.display-list.build-twice", LayoutDisplayListBuildTwice, bool, false); - DECL_GFX_PREF(Live, "layout.display-list.retain", LayoutRetainDisplayList, bool, true); + DECL_GFX_PREF(Once, "layout.display-list.retain", LayoutRetainDisplayList, bool, true); DECL_GFX_PREF(Live, "layout.display-list.rebuild-frame-limit", LayoutRebuildFrameLimit, uint32_t, 500); DECL_GFX_PREF(Live, "layout.display-list.dump", LayoutDumpDisplayList, bool, false); DECL_GFX_PREF(Live, "layout.display-list.dump-content", LayoutDumpDisplayListContent, bool, false); diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 424021c1b4f7..8b4446c7f7c5 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -3618,33 +3618,6 @@ nsLayoutUtils::AddExtraBackgroundItems(nsDisplayListBuilder& aBuilder, } } -/** - * Returns a retained display list builder for frame |aFrame|. If there is no - * retained display list builder property set for the frame, and if the flag - * |aRetainingEnabled| is true, a new retained display list builder is created, - * stored as a property for the frame, and returned. - */ -static RetainedDisplayListBuilder* -GetOrCreateRetainedDisplayListBuilder(nsIFrame* aFrame, bool aRetainingEnabled, - bool aBuildCaret) -{ - RetainedDisplayListBuilder* retainedBuilder = - aFrame->GetProperty(RetainedDisplayListBuilder::Cached()); - - if (retainedBuilder) { - return retainedBuilder; - } - - if (aRetainingEnabled) { - retainedBuilder = - new RetainedDisplayListBuilder(aFrame, nsDisplayListBuilderMode::PAINTING, - aBuildCaret); - aFrame->SetProperty(RetainedDisplayListBuilder::Cached(), retainedBuilder); - } - - return retainedBuilder; -} - nsresult nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame, const nsRegion& aDirtyRegion, nscolor aBackstop, @@ -3681,28 +3654,31 @@ nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame, TimeStamp startBuildDisplayList = TimeStamp::Now(); - const bool buildCaret = !(aFlags & PaintFrameFlags::PAINT_HIDE_CARET); - const bool isForPainting = (aFlags & PaintFrameFlags::PAINT_WIDGET_LAYERS) && - aBuilderMode == nsDisplayListBuilderMode::PAINTING; - - // Retained display list builder is currently only used for content processes. - const bool retainingEnabled = isForPainting && - gfxPrefs::LayoutRetainDisplayList() && XRE_IsContentProcess(); - - RetainedDisplayListBuilder* retainedBuilder = - GetOrCreateRetainedDisplayListBuilder(aFrame, retainingEnabled, buildCaret); - - // Only use the retained display list builder if the retaining is currently - // enabled. This check is needed because it is possible that the pref has been - // disabled after creating the retained display list builder. - const bool useRetainedBuilder = retainedBuilder && retainingEnabled; - Maybe nonRetainedBuilder; Maybe nonRetainedList; nsDisplayListBuilder* builderPtr = nullptr; nsDisplayList* listPtr = nullptr; + RetainedDisplayListBuilder* retainedBuilder = nullptr; - if (useRetainedBuilder) { + const bool buildCaret = !(aFlags & PaintFrameFlags::PAINT_HIDE_CARET); + + // Enable display list retaining if the pref is set and if we are in a + // content process. + const bool retainDisplayList = + gfxPrefs::LayoutRetainDisplayList() && XRE_IsContentProcess(); + + if (retainDisplayList && + aBuilderMode == nsDisplayListBuilderMode::PAINTING && + (aFlags & PaintFrameFlags::PAINT_WIDGET_LAYERS)) { + retainedBuilder = aFrame->GetProperty(RetainedDisplayListBuilder::Cached()); + + if (!retainedBuilder) { + retainedBuilder = + new RetainedDisplayListBuilder(aFrame, aBuilderMode, buildCaret); + aFrame->SetProperty(RetainedDisplayListBuilder::Cached(), retainedBuilder); + } + + MOZ_ASSERT(retainedBuilder); builderPtr = retainedBuilder->Builder(); listPtr = retainedBuilder->List(); } else { @@ -3711,16 +3687,6 @@ nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame, nonRetainedList.emplace(); listPtr = nonRetainedList.ptr(); } - - // Retained builder exists, but display list retaining is disabled. - if (!useRetainedBuilder && retainedBuilder) { - // Clear the modified frames lists and frame properties. - retainedBuilder->ClearModifiedFrameProps(); - - // Clear the retained display list. - retainedBuilder->List()->DeleteAll(retainedBuilder->Builder()); - } - nsDisplayListBuilder& builder = *builderPtr; nsDisplayList& list = *listPtr; @@ -3850,12 +3816,14 @@ nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame, builder.IsBuildingLayerEventRegions() && nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(presShell)); + const bool paintedPreviously = + aFrame->HasProperty(nsIFrame::ModifiedFrameList()); + // Attempt to do a partial build and merge into the existing list. // This calls BuildDisplayListForStacking context on a subset of the // viewport. bool merged = false; - - if (useRetainedBuilder) { + if (retainedBuilder && paintedPreviously) { merged = retainedBuilder->AttemptPartialUpdate(aBackstop); } @@ -4089,11 +4057,12 @@ nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame, AUTO_PROFILER_TRACING("Paint", "DisplayListResources"); // Flush the list so we don't trigger the IsEmpty-on-destruction assertion - if (!useRetainedBuilder) { + if (!retainedBuilder) { list.DeleteAll(&builder); + builder.EndFrame(); + } else { + builder.EndFrame(); } - - builder.EndFrame(); } return NS_OK; } diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 0e8e265422f6..1bf5869e7195 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -1052,6 +1052,14 @@ nsIFrame::MarkNeedsDisplayItemRebuild() modifiedFrames->AppendElement(this); + // TODO: this is a bit of a hack. We are using ModifiedFrameList property to + // decide whether we are trying to reuse the display list. + if (displayRoot != rootFrame && + !displayRoot->HasProperty(nsIFrame::ModifiedFrameList())) { + displayRoot->SetProperty(nsIFrame::ModifiedFrameList(), + new nsTArray()); + } + MOZ_ASSERT(PresContext()->LayoutPhaseCount(eLayoutPhase_DisplayListBuilding) == 0); SetFrameIsModified(true); diff --git a/layout/painting/RetainedDisplayListBuilder.cpp b/layout/painting/RetainedDisplayListBuilder.cpp index 15bb9f6326fb..0d0cb0a3196e 100644 --- a/layout/painting/RetainedDisplayListBuilder.cpp +++ b/layout/painting/RetainedDisplayListBuilder.cpp @@ -792,15 +792,6 @@ ClearFrameProps(nsTArray& aFrames) } } -void -RetainedDisplayListBuilder::ClearModifiedFrameProps() -{ - nsTArray modifiedFrames = - GetModifiedFrames(mBuilder.RootReferenceFrame()); - - ClearFrameProps(modifiedFrames); -} - bool RetainedDisplayListBuilder::AttemptPartialUpdate(nscolor aBackstop) { diff --git a/layout/painting/RetainedDisplayListBuilder.h b/layout/painting/RetainedDisplayListBuilder.h index ec284493614b..dcdace565a3d 100644 --- a/layout/painting/RetainedDisplayListBuilder.h +++ b/layout/painting/RetainedDisplayListBuilder.h @@ -27,14 +27,6 @@ struct RetainedDisplayListBuilder { bool AttemptPartialUpdate(nscolor aBackstop); - /** - * Iterates through the display list builder reference frame document and - * subdocuments, and clears the modified frame lists from the root frames. - * Also clears the frame properties set by RetainedDisplayListBuilder for all - * the frames in the modified frame lists. - */ - void ClearModifiedFrameProps(); - NS_DECLARE_FRAME_PROPERTY_DELETABLE(Cached, RetainedDisplayListBuilder) private: