зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1728258 - Compute AnimatedGeometryRoot frames in RetainedDisplayListBuilder without needing the existing object stored on nsDisplayItem. r=miko,mstange
Differential Revision: https://phabricator.services.mozilla.com/D124153
This commit is contained in:
Родитель
9bdea2da6b
Коммит
e060744ad1
|
@ -43,6 +43,29 @@
|
|||
* we would have built both in the new list if they intersected. Given that, we
|
||||
* can align items that appear in both lists, and any items that appear between
|
||||
* matched items can be inserted into the merged list in any order.
|
||||
*
|
||||
* Frames that are a stacking context, containing blocks for position:fixed
|
||||
* descendants, and don't have any continuations (see
|
||||
* CanStoreDisplayListBuildingRect) trigger recursion into the algorithm with
|
||||
* separate retaining decisions made.
|
||||
*
|
||||
* RDL defines the concept of an AnimatedGeometryRoot (AGR), the nearest
|
||||
* ancestor frame which can be moved asynchronously on the compositor thread.
|
||||
* These are currently nsDisplayItems which return true from CanMoveAsync
|
||||
* (animated nsDisplayTransform and nsDisplayStickyPosition) and
|
||||
* ActiveScrolledRoots.
|
||||
*
|
||||
* For each context that we run the retaining algorithm, there can only be
|
||||
* mutations to one AnimatedGeometryRoot. This is because we are unable to
|
||||
* reason about intersections of items that might then move relative to each
|
||||
* other without RDL running again. If there are mutations to multiple
|
||||
* AnimatedGeometryRoots, then we bail out and rebuild all the items in the
|
||||
* context.
|
||||
*
|
||||
* Otherwise, when mutations are restricted to a single AGR, we pre-process the
|
||||
* old display list and mark the frames for all existing (unmodified!) items
|
||||
* that belong to a different AGR and ensure that we rebuild those items for
|
||||
* correct sorting with the modified ones.
|
||||
*/
|
||||
|
||||
using mozilla::dom::Document;
|
||||
|
@ -101,8 +124,7 @@ static void MarkFramesWithItemsAndImagesModified(nsDisplayList* aList) {
|
|||
}
|
||||
}
|
||||
|
||||
static AnimatedGeometryRoot* SelectAGRForFrame(
|
||||
nsIFrame* aFrame, AnimatedGeometryRoot* aParentAGR) {
|
||||
static nsIFrame* SelectAGRForFrame(nsIFrame* aFrame, nsIFrame* aParentAGR) {
|
||||
if (!aFrame->IsStackingContext() || !aFrame->IsFixedPosContainingBlock()) {
|
||||
return aParentAGR;
|
||||
}
|
||||
|
@ -114,7 +136,7 @@ static AnimatedGeometryRoot* SelectAGRForFrame(
|
|||
nsDisplayListBuilder::DisplayListBuildingData* data =
|
||||
aFrame->GetProperty(nsDisplayListBuilder::DisplayListBuildingRect());
|
||||
|
||||
return data && data->mModifiedAGR ? data->mModifiedAGR.get() : nullptr;
|
||||
return data && data->mModifiedAGR ? data->mModifiedAGR : nullptr;
|
||||
}
|
||||
|
||||
void RetainedDisplayListBuilder::AddSizeOfIncludingThis(
|
||||
|
@ -148,9 +170,10 @@ bool AnyContentAncestorModified(nsIFrame* aFrame, nsIFrame* aStopAtFrame) {
|
|||
// to mark, as child stacking contexts might. It would be nice if we could
|
||||
// jump into those immediately rather than walking the entire thing.
|
||||
bool RetainedDisplayListBuilder::PreProcessDisplayList(
|
||||
RetainedDisplayList* aList, AnimatedGeometryRoot* aAGR,
|
||||
PartialUpdateResult& aUpdated, nsIFrame* aOuterFrame, uint32_t aCallerKey,
|
||||
uint32_t aNestingDepth, bool aKeepLinked) {
|
||||
RetainedDisplayList* aList, nsIFrame* aAGR, PartialUpdateResult& aUpdated,
|
||||
nsIFrame* aAsyncAncestor, const ActiveScrolledRoot* aAsyncAncestorASR,
|
||||
nsIFrame* aOuterFrame, uint32_t aCallerKey, uint32_t aNestingDepth,
|
||||
bool aKeepLinked) {
|
||||
// The DAG merging algorithm does not have strong mechanisms in place to keep
|
||||
// the complexity of the resulting DAG under control. In some cases we can
|
||||
// build up edges very quickly. Detect those cases and force a full display
|
||||
|
@ -258,10 +281,21 @@ bool RetainedDisplayListBuilder::PreProcessDisplayList(
|
|||
keepLinked = true;
|
||||
}
|
||||
|
||||
if (!PreProcessDisplayList(item->GetChildren(),
|
||||
SelectAGRForFrame(f, aAGR), aUpdated,
|
||||
item->Frame(), item->GetPerFrameKey(),
|
||||
aNestingDepth + 1, keepLinked)) {
|
||||
// If this item's frame is an AGR (can be moved asynchronously by the
|
||||
// compositor), then use that frame for descendants. Also pass the ASR
|
||||
// for that item, so that descendants can compare to see if any new
|
||||
// ASRs have been pushed since.
|
||||
nsIFrame* asyncAncestor = aAsyncAncestor;
|
||||
const ActiveScrolledRoot* asyncAncestorASR = aAsyncAncestorASR;
|
||||
if (item->CanMoveAsync()) {
|
||||
asyncAncestor = item->Frame();
|
||||
asyncAncestorASR = item->GetActiveScrolledRoot();
|
||||
}
|
||||
|
||||
if (!PreProcessDisplayList(
|
||||
item->GetChildren(), SelectAGRForFrame(f, aAGR), aUpdated,
|
||||
asyncAncestor, asyncAncestorASR, item->Frame(),
|
||||
item->GetPerFrameKey(), aNestingDepth + 1, keepLinked)) {
|
||||
MOZ_RELEASE_ASSERT(
|
||||
!aKeepLinked,
|
||||
"Can't early return since we need to move the out list back");
|
||||
|
@ -276,7 +310,19 @@ bool RetainedDisplayListBuilder::PreProcessDisplayList(
|
|||
// sibling of the changed thing to get correct ordering. The changed content
|
||||
// is a frame though, and it's hard to map that to container items in this
|
||||
// list.
|
||||
if (aAGR && item->GetAnimatedGeometryRoot()->GetAsyncAGR() != aAGR) {
|
||||
// If an ancestor display item is an AGR, and our ASR matches the ASR
|
||||
// of that item, then there can't have been any new ASRs pushed since that
|
||||
// item, so that item is our AGR. Otherwise, our AGR is our ASR.
|
||||
nsIFrame* agrFrame = nullptr;
|
||||
if (aAsyncAncestorASR == item->GetActiveScrolledRoot()) {
|
||||
agrFrame = aAsyncAncestor;
|
||||
} else {
|
||||
MOZ_ASSERT(item->GetActiveScrolledRoot());
|
||||
agrFrame =
|
||||
item->GetActiveScrolledRoot()->mScrollableFrame->GetScrolledFrame();
|
||||
}
|
||||
|
||||
if (aAGR && agrFrame != aAGR) {
|
||||
mBuilder.MarkFrameForDisplayIfVisible(f, mBuilder.RootReferenceFrame());
|
||||
}
|
||||
|
||||
|
@ -934,7 +980,7 @@ static bool CanStoreDisplayListBuildingRect(nsDisplayListBuilder* aBuilder,
|
|||
|
||||
static bool ProcessFrameInternal(nsIFrame* aFrame,
|
||||
nsDisplayListBuilder* aBuilder,
|
||||
AnimatedGeometryRoot** aAGR, nsRect& aOverflow,
|
||||
nsIFrame** aAGR, nsRect& aOverflow,
|
||||
const nsIFrame* aStopAtFrame,
|
||||
nsTArray<nsIFrame*>& aOutFramesWithProps,
|
||||
const bool aStopAtStackingContext) {
|
||||
|
@ -970,7 +1016,7 @@ static bool ProcessFrameInternal(nsIFrame* aFrame,
|
|||
|
||||
// Tracking AGRs for the placeholder processing is not necessary, as the
|
||||
// goal is to only modify the DisplayListBuildingData rect.
|
||||
AnimatedGeometryRoot* dummyAGR = nullptr;
|
||||
nsIFrame* dummyAGR = nullptr;
|
||||
|
||||
// Find a common ancestor frame to handle frame continuations.
|
||||
// TODO: It might be possible to write a more specific and efficient
|
||||
|
@ -1112,7 +1158,7 @@ static bool ProcessFrameInternal(nsIFrame* aFrame,
|
|||
bool RetainedDisplayListBuilder::ProcessFrame(
|
||||
nsIFrame* aFrame, nsDisplayListBuilder* aBuilder, nsIFrame* aStopAtFrame,
|
||||
nsTArray<nsIFrame*>& aOutFramesWithProps, const bool aStopAtStackingContext,
|
||||
nsRect* aOutDirty, AnimatedGeometryRoot** aOutModifiedAGR) {
|
||||
nsRect* aOutDirty, nsIFrame** aOutModifiedAGR) {
|
||||
if (aFrame->HasOverrideDirtyRegion()) {
|
||||
aOutFramesWithProps.AppendElement(aFrame);
|
||||
}
|
||||
|
@ -1125,6 +1171,7 @@ bool RetainedDisplayListBuilder::ProcessFrame(
|
|||
// combined with the ancestor walk for TransformFrameRectToAncestor.
|
||||
AnimatedGeometryRoot* agr =
|
||||
aBuilder->FindAnimatedGeometryRootFor(aFrame)->GetAsyncAGR();
|
||||
nsIFrame* agrFrame = agr ? agr->mFrame : nullptr;
|
||||
|
||||
CRR_LOG("Processing frame %p with agr %p\n", aFrame, agr->mFrame);
|
||||
|
||||
|
@ -1146,7 +1193,7 @@ bool RetainedDisplayListBuilder::ProcessFrame(
|
|||
overflow.UnionRect(overflow, aBuilder->GetCaretRect());
|
||||
}
|
||||
|
||||
if (!ProcessFrameInternal(aFrame, aBuilder, &agr, overflow, aStopAtFrame,
|
||||
if (!ProcessFrameInternal(aFrame, aBuilder, &agrFrame, overflow, aStopAtFrame,
|
||||
aOutFramesWithProps, aStopAtStackingContext)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1160,9 +1207,9 @@ bool RetainedDisplayListBuilder::ProcessFrame(
|
|||
// really complex to track which items would need to be marked in
|
||||
// MarkFramesForDifferentAGR.
|
||||
if (!*aOutModifiedAGR) {
|
||||
CRR_LOG("Setting %p as root stacking context AGR\n", agr);
|
||||
*aOutModifiedAGR = agr;
|
||||
} else if (agr && *aOutModifiedAGR != agr) {
|
||||
CRR_LOG("Setting %p as root stacking context AGR\n", agrFrame);
|
||||
*aOutModifiedAGR = agrFrame;
|
||||
} else if (agrFrame && *aOutModifiedAGR != agrFrame) {
|
||||
CRR_LOG("Found multiple AGRs in root stacking context, giving up\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -1236,8 +1283,7 @@ static void FindContainingBlocks(nsIFrame* aFrame,
|
|||
*/
|
||||
bool RetainedDisplayListBuilder::ComputeRebuildRegion(
|
||||
nsTArray<nsIFrame*>& aModifiedFrames, nsRect* aOutDirty,
|
||||
AnimatedGeometryRoot** aOutModifiedAGR,
|
||||
nsTArray<nsIFrame*>& aOutFramesWithProps) {
|
||||
nsIFrame** aOutModifiedAGR, nsTArray<nsIFrame*>& aOutFramesWithProps) {
|
||||
CRR_LOG("Computing rebuild regions for %zu frames:\n",
|
||||
aModifiedFrames.Length());
|
||||
nsTArray<nsIFrame*> extraFrames;
|
||||
|
@ -1399,12 +1445,13 @@ PartialUpdateResult RetainedDisplayListBuilder::AttemptPartialUpdate(
|
|||
bool shouldBuildPartial = ShouldBuildPartial(modifiedFrames.Frames());
|
||||
|
||||
nsRect modifiedDirty;
|
||||
AnimatedGeometryRoot* modifiedAGR = nullptr;
|
||||
nsIFrame* modifiedAGR = nullptr;
|
||||
PartialUpdateResult result = PartialUpdateResult::NoChange;
|
||||
if (!shouldBuildPartial ||
|
||||
!ComputeRebuildRegion(modifiedFrames.Frames(), &modifiedDirty,
|
||||
&modifiedAGR, framesWithProps.Frames()) ||
|
||||
!PreProcessDisplayList(&mList, modifiedAGR, result)) {
|
||||
!PreProcessDisplayList(&mList, modifiedAGR, result,
|
||||
mBuilder.RootReferenceFrame(), nullptr)) {
|
||||
mBuilder.SetPartialBuildFailed(true);
|
||||
mBuilder.LeavePresShell(mBuilder.RootReferenceFrame(), nullptr);
|
||||
mList.DeleteAll(&mBuilder);
|
||||
|
|
|
@ -215,13 +215,11 @@ struct RetainedDisplayListBuilder {
|
|||
* aKeepLinked=true internally for sub-lists that can't be changed to keep the
|
||||
* original list structure linked for fast re-use.
|
||||
*/
|
||||
bool PreProcessDisplayList(RetainedDisplayList* aList,
|
||||
AnimatedGeometryRoot* aAGR,
|
||||
PartialUpdateResult& aUpdated,
|
||||
nsIFrame* aOuterFrame = nullptr,
|
||||
uint32_t aCallerKey = 0,
|
||||
uint32_t aNestingDepth = 0,
|
||||
bool aKeepLinked = false);
|
||||
bool PreProcessDisplayList(
|
||||
RetainedDisplayList* aList, nsIFrame* aAGR, PartialUpdateResult& aUpdated,
|
||||
nsIFrame* aAsyncAncestor, const ActiveScrolledRoot* aAsyncAncestorASR,
|
||||
nsIFrame* aOuterFrame = nullptr, uint32_t aCallerKey = 0,
|
||||
uint32_t aNestingDepth = 0, bool aKeepLinked = false);
|
||||
|
||||
/**
|
||||
* Merges items from aNewList into non-invalidated items from aOldList and
|
||||
|
@ -241,15 +239,14 @@ struct RetainedDisplayListBuilder {
|
|||
nsDisplayItem* aOuterItem = nullptr);
|
||||
|
||||
bool ComputeRebuildRegion(nsTArray<nsIFrame*>& aModifiedFrames,
|
||||
nsRect* aOutDirty,
|
||||
AnimatedGeometryRoot** aOutModifiedAGR,
|
||||
nsRect* aOutDirty, nsIFrame** aOutModifiedAGR,
|
||||
nsTArray<nsIFrame*>& aOutFramesWithProps);
|
||||
|
||||
bool ProcessFrame(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aStopAtFrame,
|
||||
nsTArray<nsIFrame*>& aOutFramesWithProps,
|
||||
const bool aStopAtStackingContext, nsRect* aOutDirty,
|
||||
AnimatedGeometryRoot** aOutModifiedAGR);
|
||||
nsIFrame** aOutModifiedAGR);
|
||||
|
||||
friend class MergeState;
|
||||
|
||||
|
|
|
@ -1501,7 +1501,7 @@ class nsDisplayListBuilder {
|
|||
OutOfFlowDisplayData)
|
||||
|
||||
struct DisplayListBuildingData {
|
||||
RefPtr<AnimatedGeometryRoot> mModifiedAGR = nullptr;
|
||||
nsIFrame* mModifiedAGR = nullptr;
|
||||
nsRect mDirtyRect;
|
||||
};
|
||||
NS_DECLARE_FRAME_PROPERTY_DELETABLE(DisplayListBuildingRect,
|
||||
|
@ -2364,6 +2364,12 @@ class nsDisplayItem : public nsDisplayItemLink {
|
|||
|
||||
virtual bool CreatesStackingContextHelper() { return false; }
|
||||
|
||||
/**
|
||||
* Returns true if this item can be moved asynchronously on the compositor,
|
||||
* see RetainedDisplayListBuilder.cpp comments.
|
||||
*/
|
||||
virtual bool CanMoveAsync() { return false; }
|
||||
|
||||
protected:
|
||||
// This is never instantiated directly (it has pure virtual methods), so no
|
||||
// need to count constructors and destructors.
|
||||
|
@ -5615,6 +5621,8 @@ class nsDisplayStickyPosition : public nsDisplayOwnLayer {
|
|||
|
||||
bool CreatesStackingContextHelper() override { return true; }
|
||||
|
||||
bool CanMoveAsync() override { return true; }
|
||||
|
||||
private:
|
||||
NS_DISPLAY_ALLOW_CLONING()
|
||||
|
||||
|
@ -6443,6 +6451,11 @@ class nsDisplayTransform : public nsPaintedDisplayItem {
|
|||
|
||||
void WriteDebugInfo(std::stringstream& aStream) override;
|
||||
|
||||
bool CanMoveAsync() override {
|
||||
return EffectCompositor::HasAnimationsForCompositor(
|
||||
mFrame, DisplayItemType::TYPE_TRANSFORM);
|
||||
}
|
||||
|
||||
/**
|
||||
* This item is an additional item as the boundary between parent
|
||||
* and child 3D rendering context.
|
||||
|
|
Загрузка…
Ссылка в новой задаче