Revert "[BGPT] Simplify and improve performance of transform decomposition"
This reverts commit 7181ee07e464941e2aa3889dd19c7c3ea5eebd8d.
Reason for revert: Caused problem of direct transform update. Some
transform decomposited for some layer contributing to the offset of
the layer can't be directly updated.
Original change's description:
> [BGPT] Simplify and improve performance of transform decomposition
>
> Instead of decompositing transforms of pending layers before updating
> cc transforms, now decomposite a pending layer's transforms just after
> we create cc effect, clip and scroll nodes. We don't decomposite a
> transform if the cc transform node has been created during creating
> other cc property nodes.
>
> Because decompositing transform of a layer is just to move the
> transform pointer up along the transform path, it won't affect other
> layers which may not decomposite the same transforms.
>
> This improves performance by avoiding hash map accesses and additional
> pending layer iteration and blink paint property tree walks.
>
> Change-Id: Idfdc6bc510cfb83a1b3eb3956cc2fb0a11d457a2
> Bug: 954520, 954493
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1597205
> Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org>
> Reviewed-by: Mason Freed <masonfreed@chromium.org>
> Reviewed-by: Philip Rogers <pdr@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#657459}
TBR=wangxianzhu@chromium.org,pdr@chromium.org,masonfreed@chromium.org
# Not skipping CQ checks because original CL landed > 1 day ago.
Bug: 954520, 954493, 966350
Change-Id: I300cdecc444c63ad5fb2c962289e7dcde480bbd7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1629231
Reviewed-by: Xianzhu Wang <wangxianzhu@chromium.org>
Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#663354}
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
index adeb47f..db269ac6 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -385,35 +385,10 @@
rect_known_to_be_opaque = FloatRect();
}
-// A pending layer can decomposite its transform node if:
-// 1. We have not created a cc::TransformNode for it during this update.
-// 2. It is not the root transform node.
-// 3. It is a 2d translation only.
-// 4. The transform is not used for scrolling - its ScrollNode() is nullptr.
-// 5. It has no direct compositing reasons, other than k3DTransform. Note
-// that if it has a k3DTransform reason, check #3 above ensures that it
-// isn't really 3D.
-// 6. It has FlattensInheritedTransform matching that of its direct parent.
-// 7. It has backface visibility matching its direct parent.
-static bool CanDecompositeTransform(const TransformPaintPropertyNode& node) {
- // TODO(masonfreed): CAP is not yet implemented here.
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- return false;
- return node.CcNodeId(g_s_property_tree_sequence_number) == -1 &&
- !node.IsRoot() && node.IsIdentityOr2DTranslation() &&
- !node.ScrollNode() && !node.IsAffectedByOuterViewportBoundsDelta() &&
- !node.HasDirectCompositingReasonsOtherThan3dTransform() &&
- node.FlattensInheritedTransformSameAsParent() &&
- node.BackfaceVisibilitySameAsParent();
-}
-
-void PaintArtifactCompositor::PendingLayer::DecompositeTransforms() {
- const auto* transform = &property_tree_state.Transform().Unalias();
- while (CanDecompositeTransform(*transform)) {
- offset_to_transform_parent += transform->Translation2D();
- transform = SafeUnalias(transform->Parent());
- }
- property_tree_state.SetTransform(*transform);
+void PaintArtifactCompositor::PendingLayer::DecompositeTransform() {
+ const auto& transform = property_tree_state.Transform().Unalias();
+ property_tree_state.SetTransform(*transform.Parent());
+ offset_to_transform_parent += transform.Translation2D();
}
const PaintChunk& PaintArtifactCompositor::PendingLayer::FirstPaintChunk(
@@ -797,6 +772,95 @@
}
}
+// Walk the pending layer list and build up a table of transform nodes that
+// can be de-composited (replaced with offset_to_transform_parent). A
+// transform node can be de-composited if:
+// 1. It is not the root transform node.
+// 2. It is a 2d translation only.
+// 3. The transform is not used for scrolling - its ScrollNode() is nullptr.
+// 4. It has no direct compositing reasons, other than k3DTransform. Note
+// that if it has a k3DTransform reason, check #2 above ensures that it
+// isn't really 3D.
+// 5. It has FlattensInheritedTransform matching that of its direct parent.
+// 6. It has backface visibility matching its direct parent.
+// 7. No clips have local_transform_space referring to this transform node.
+// 8. No effects have local_transform_space referring to this transform node.
+// 9. All child transform nodes are also able to be de-composited.
+// This algorithm should be O(t+c+e) where t,c,e are the number of transform,
+// clip, and effect nodes in the full tree.
+void PaintArtifactCompositor::DecompositeTransforms() {
+ // TODO(masonfreed): CAP is not yet implemented here.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+ WTF::HashMap<const TransformPaintPropertyNode*, bool> can_be_decomposited;
+ WTF::HashSet<const void*> clips_and_effects_seen;
+ for (const auto& pending_layer : pending_layers_) {
+ const auto& property_state = pending_layer.property_tree_state;
+
+ // Lambda to handle marking a transform node false, and walking up all true
+ // parents and marking them false as well. This also handles inserting
+ // transform_node if it isn't in the map, and keeps track of clips or
+ // effects.
+ auto mark_not_decompositable =
+ [&can_be_decomposited](
+ const TransformPaintPropertyNode* transform_node) {
+ DCHECK(transform_node);
+ while (transform_node && !transform_node->IsRoot()) {
+ if (!can_be_decomposited.Contains(transform_node)) {
+ can_be_decomposited.insert(transform_node, false);
+ } else {
+ if (!can_be_decomposited.at(transform_node))
+ break;
+ can_be_decomposited.Set(transform_node, false);
+ }
+ transform_node = SafeUnalias(transform_node->Parent());
+ }
+ };
+
+ // Add the transform and all transform parents to the map.
+ for (const auto* node = &property_state.Transform().Unalias();
+ node && !can_be_decomposited.Contains(node);
+ node = SafeUnalias(node->Parent())) {
+ can_be_decomposited.insert(node, !node->IsRoot());
+ if (!node->IsIdentityOr2DTranslation() || node->ScrollNode() ||
+ node->IsAffectedByOuterViewportBoundsDelta() ||
+ node->HasDirectCompositingReasonsOtherThan3dTransform() ||
+ !node->FlattensInheritedTransformSameAsParent() ||
+ !node->BackfaceVisibilitySameAsParent()) {
+ mark_not_decompositable(node);
+ }
+ }
+
+ // Add clips and effects, and their parents, that we haven't already seen.
+ for (const auto* node = &property_state.Clip().Unalias();
+ node && !clips_and_effects_seen.Contains(node);
+ node = SafeUnalias(node->Parent())) {
+ clips_and_effects_seen.insert(node);
+ if (!node->IsRoot())
+ mark_not_decompositable(&node->LocalTransformSpace());
+ }
+ for (const auto* node = &property_state.Effect().Unalias();
+ node && !clips_and_effects_seen.Contains(node);
+ node = SafeUnalias(node->Parent())) {
+ clips_and_effects_seen.insert(node);
+ if (!node->IsRoot())
+ mark_not_decompositable(&node->LocalTransformSpace());
+ }
+ }
+
+ // Now, for any transform nodes that can be de-composited, re-map their
+ // transform to point to the correct parent, and set the
+ // offset_to_transform_parent.
+ for (auto& pending_layer : pending_layers_) {
+ const auto* transform_node = &pending_layer.property_tree_state.Transform();
+ while (transform_node && !transform_node->IsRoot() &&
+ can_be_decomposited.at(transform_node)) {
+ pending_layer.DecompositeTransform();
+ transform_node = SafeUnalias(transform_node->Parent());
+ }
+ }
+}
+
void PaintArtifactCompositor::Update(
scoped_refptr<const PaintArtifact> paint_artifact,
const ViewportProperties& viewport_properties,
@@ -844,23 +908,45 @@
for (auto& entry : synthesized_clip_cache_)
entry.in_use = false;
+ // See if we can de-composite any transforms.
+ DecompositeTransforms();
+
for (auto& pending_layer : pending_layers_) {
const auto& property_state = pending_layer.property_tree_state;
+ const auto& transform = property_state.Transform();
const auto& clip = property_state.Clip();
- if (&clip.LocalTransformSpace() == &property_state.Transform()) {
+
+ if (&clip.LocalTransformSpace() == &transform) {
// Limit layer bounds to hide the areas that will be never visible because
// of the clip.
pending_layer.bounds.Intersect(clip.ClipRect().Rect());
- } else if (const auto* scroll = property_state.Transform().ScrollNode()) {
+ } else if (const auto* scroll = transform.ScrollNode()) {
// Limit layer bounds to the scroll range to hide the areas that will
// never be scrolled into the visible area.
pending_layer.bounds.Intersect(FloatRect(
IntRect(scroll->ContainerRect().Location(), scroll->ContentsSize())));
}
+ scoped_refptr<cc::Layer> layer = CompositedLayerForPendingLayer(
+ paint_artifact, pending_layer, new_content_layer_clients,
+ new_scroll_hit_test_layers);
+
+ // Pre-CompositeAfterPaint, touch action rects are updated through
+ // ScrollingCoordinator::UpdateLayerTouchActionRects.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ auto paint_chunks = paint_artifact->GetPaintChunkSubset(
+ pending_layer.paint_chunk_indices);
+ UpdateTouchActionRects(layer.get(), layer->offset_to_transform_parent(),
+ property_state, paint_chunks);
+ }
+
+ layer->SetLayerTreeHost(root_layer_->layer_tree_host());
+
+ int transform_id =
+ property_tree_manager.EnsureCompositorTransformNode(transform);
int clip_id = property_tree_manager.EnsureCompositorClipNode(clip);
int effect_id = property_tree_manager.SwitchToEffectNodeWithSynthesizedClip(
- property_state.Effect(), clip);
+ property_state.Effect(), clip, layer->DrawsContent());
blink_effects.resize(effect_id + 1);
blink_effects[effect_id] = &property_state.Effect();
// The compositor scroll node is not directly stored in the property tree
@@ -870,32 +956,6 @@
int scroll_id =
property_tree_manager.EnsureCompositorScrollNode(scroll_translation);
- // Decomposite and update transform after updating all other property nodes
- // have been updated, so that we don't decomposite the transform nodes that
- // are referenced by the other property nodes of this layer.
- // Note that this may change property_state.Transform().
- pending_layer.DecompositeTransforms();
- int transform_id = property_tree_manager.EnsureCompositorTransformNode(
- property_state.Transform());
-
- scoped_refptr<cc::Layer> layer = CompositedLayerForPendingLayer(
- paint_artifact, pending_layer, new_content_layer_clients,
- new_scroll_hit_test_layers);
-
- if (layer->DrawsContent())
- property_tree_manager.ClearPendingSyntheticMaskLayers();
-
- layer->SetLayerTreeHost(root_layer_->layer_tree_host());
-
- // In Pre-CompositeAfterPaint, touch action rects are updated through
- // ScrollingCoordinator::UpdateLayerTouchActionRects.
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- auto paint_chunks = paint_artifact->GetPaintChunkSubset(
- pending_layer.paint_chunk_indices);
- UpdateTouchActionRects(layer.get(), layer->offset_to_transform_parent(),
- property_state, paint_chunks);
- }
-
layer_list_builder.Add(layer);
layer->set_property_tree_sequence_number(
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
index 5a2c3fc..3e13c67 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
@@ -213,7 +213,7 @@
// to the chunks as Skia commands.
void Upcast(const PropertyTreeState&);
- void DecompositeTransforms();
+ void DecompositeTransform();
const PaintChunk& FirstPaintChunk(const PaintArtifact&) const;
@@ -225,6 +225,8 @@
bool requires_own_layer;
};
+ void DecompositeTransforms();
+
// Collects the PaintChunks into groups which will end up in the same
// cc layer. This is the entry point of the layerization algorithm.
void CollectPendingLayers(const PaintArtifact&, const Settings& settings);
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
index 317430a..562b3e5 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
@@ -672,7 +672,8 @@
int PropertyTreeManager::SwitchToEffectNodeWithSynthesizedClip(
const EffectPaintPropertyNode& next_effect,
- const ClipPaintPropertyNode& next_clip) {
+ const ClipPaintPropertyNode& next_clip,
+ bool layer_draws_content) {
// This function is expected to be invoked right before emitting each layer.
// It keeps track of the nesting of clip and effects, output a composited
// effect node whenever an effect is entered, or a non-trivial clip is
@@ -728,6 +729,9 @@
BuildEffectNodesRecursively(next_effect);
SynthesizeCcEffectsForClipsIfNeeded(next_clip, SkBlendMode::kSrcOver);
+ if (layer_draws_content)
+ pending_synthetic_mask_layers_.clear();
+
return current_.effect_id;
}
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h
index a9811c2..ffbe436 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h
+++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h
@@ -110,12 +110,8 @@
// effect, i.e. applying the clip as a mask.
int SwitchToEffectNodeWithSynthesizedClip(
const EffectPaintPropertyNode& next_effect,
- const ClipPaintPropertyNode& next_clip);
-
- void ClearPendingSyntheticMaskLayers() {
- pending_synthetic_mask_layers_.clear();
- }
-
+ const ClipPaintPropertyNode& next_clip,
+ bool layer_draws_content);
// Expected to be invoked after emitting the last layer. This will exit all
// effects on the effect stack, generating clip mask layers for all the
// unclosed synthesized clips.