Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(539)

Unified Diff: cc/trees/draw_property_utils.cc

Issue 1056793009: Reconcile property tree and CDP layer skipping logic (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | cc/trees/layer_tree_host_common_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: cc/trees/draw_property_utils.cc
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc
index 83b91f4f36edef54da6d4633d5e5638f163dc0da..50b91cb37b1bd432cefb3cf3a4c3bbf2a1156c42 100644
--- a/cc/trees/draw_property_utils.cc
+++ b/cc/trees/draw_property_utils.cc
@@ -9,6 +9,7 @@
#include "cc/base/math_util.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
+#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/property_tree.h"
#include "cc/trees/property_tree_builder.h"
#include "ui/gfx/geometry/rect_conversions.h"
@@ -157,72 +158,154 @@ static bool TransformToScreenIsKnown(LayerType* layer,
}
template <typename LayerType>
-static bool IsLayerBackFaceExposed(LayerType* layer,
- const TransformTree& tree) {
- if (!TransformToScreenIsKnown(layer, tree))
- return false;
- if (LayerIsInExisting3DRenderingContext(layer))
- return DrawTransformFromPropertyTrees(layer, tree).IsBackFaceVisible();
- return layer->transform().IsBackFaceVisible();
+static bool HasSingularTransform(LayerType* layer, const TransformTree& tree) {
+ const TransformNode* node = tree.Node(layer->transform_tree_index());
+ return !node->data.is_invertible || !node->data.ancestors_are_invertible;
}
template <typename LayerType>
-static bool IsSurfaceBackFaceExposed(LayerType* layer,
- const TransformTree& tree) {
- if (!TransformToScreenIsKnown(layer, tree))
- return false;
+static bool IsLayerBackFaceVisible(LayerType* layer,
+ const TransformTree& tree) {
+ // The current W3C spec on CSS transforms says that backface visibility should
+ // be determined differently depending on whether the layer is in a "3d
+ // rendering context" or not. For Chromium code, we can determine whether we
+ // are in a 3d rendering context by checking if the parent preserves 3d.
+
if (LayerIsInExisting3DRenderingContext(layer))
return DrawTransformFromPropertyTrees(layer, tree).IsBackFaceVisible();
- if (IsRootLayerOfNewRenderingContext(layer))
- return layer->transform().IsBackFaceVisible();
-
- // If the render_surface is not part of a new or existing rendering context,
- // then the layers that contribute to this surface will decide back-face
- // visibility for themselves.
- return false;
+ // In this case, either the layer establishes a new 3d rendering context, or
+ // is not in a 3d rendering context at all.
+ return layer->transform().IsBackFaceVisible();
}
template <typename LayerType>
-static bool HasSingularTransform(LayerType* layer, const TransformTree& tree) {
+static bool IsAnimatingTransformToScreen(LayerType* layer,
+ const TransformTree& tree) {
const TransformNode* node = tree.Node(layer->transform_tree_index());
- return !node->data.is_invertible || !node->data.ancestors_are_invertible;
+ return node->data.to_screen_is_animated;
}
-template <typename LayerType>
-static bool IsBackFaceInvisible(LayerType* layer, const TransformTree& tree) {
- LayerType* backface_test_layer = layer;
- if (layer->use_parent_backface_visibility()) {
- DCHECK(layer->parent());
- DCHECK(!layer->parent()->use_parent_backface_visibility());
- backface_test_layer = layer->parent();
- }
- return !backface_test_layer->double_sided() &&
- IsLayerBackFaceExposed(backface_test_layer, tree);
+static inline bool TransformToScreenIsKnown(Layer* layer,
+ const TransformTree& tree) {
+ return !IsAnimatingTransformToScreen(layer, tree);
}
-template <typename LayerType>
-static bool IsAnimatingTransformToScreen(LayerType* layer,
- const TransformTree& tree) {
- const TransformNode* node = tree.Node(layer->transform_tree_index());
- return node->data.to_screen_is_animated;
+static inline bool TransformToScreenIsKnown(LayerImpl* layer,
+ const TransformTree& tree) {
+ return true;
}
template <typename LayerType>
-static bool IsInvisibleDueToTransform(LayerType* layer,
- const TransformTree& tree) {
- if (IsAnimatingTransformToScreen(layer, tree))
+static bool HasInvertibleOrAnimatedTransform(LayerType* layer) {
+ return layer->transform_is_invertible() || layer->TransformIsAnimating();
+}
+
+static inline bool SubtreeShouldBeSkipped(LayerImpl* layer,
+ bool layer_is_drawn) {
+ // If the layer transform is not invertible, it should not be drawn.
+ // TODO(ajuma): Correctly process subtrees with singular transform for the
+ // case where we may animate to a non-singular transform and wish to
+ // pre-raster.
+ if (!HasInvertibleOrAnimatedTransform(layer))
+ return true;
+
+ // When we need to do a readback/copy of a layer's output, we can not skip
+ // it or any of its ancestors.
+ if (layer->draw_properties().layer_or_descendant_has_copy_request)
+ return false;
+
+ // We cannot skip the the subtree if a descendant has a wheel or touch handler
+ // or the hit testing code will break (it requires fresh transforms, etc).
+ if (layer->draw_properties().layer_or_descendant_has_input_handler)
return false;
- return HasSingularTransform(layer, tree) || IsBackFaceInvisible(layer, tree);
+
+ // If the layer is not drawn, then skip it and its subtree.
+ if (!layer_is_drawn)
+ return true;
+
+ // If layer is on the pending tree and opacity is being animated then
+ // this subtree can't be skipped as we need to create, prioritize and
+ // include tiles for this layer when deciding if tree can be activated.
+ if (layer->layer_tree_impl()->IsPendingTree() && layer->OpacityIsAnimating())
+ return false;
+
+ // The opacity of a layer always applies to its children (either implicitly
+ // via a render surface or explicitly if the parent preserves 3D), so the
+ // entire subtree can be skipped if this layer is fully transparent.
+ return !layer->opacity();
}
-bool LayerIsInvisible(const Layer* layer) {
+static inline bool SubtreeShouldBeSkipped(Layer* layer, bool layer_is_drawn) {
+ // If the layer transform is not invertible, it should not be drawn.
+ if (!layer->transform_is_invertible() && !layer->TransformIsAnimating())
+ return true;
+
+ // When we need to do a readback/copy of a layer's output, we can not skip
+ // it or any of its ancestors.
+ if (layer->draw_properties().layer_or_descendant_has_copy_request)
+ return false;
+
+ // We cannot skip the the subtree if a descendant has a wheel or touch handler
+ // or the hit testing code will break (it requires fresh transforms, etc).
+ if (layer->draw_properties().layer_or_descendant_has_input_handler)
+ return false;
+
+ // If the layer is not drawn, then skip it and its subtree.
+ if (!layer_is_drawn)
+ return true;
+
+ // If the opacity is being animated then the opacity on the main thread is
+ // unreliable (since the impl thread may be using a different opacity), so it
+ // should not be trusted.
+ // In particular, it should not cause the subtree to be skipped.
+ // Similarly, for layers that might animate opacity using an impl-only
+ // animation, their subtree should also not be skipped.
return !layer->opacity() && !layer->OpacityIsAnimating() &&
!layer->OpacityCanAnimateOnImplThread();
}
-bool LayerIsInvisible(const LayerImpl* layer) {
- return !layer->opacity() && !layer->OpacityIsAnimating();
+template <typename LayerType>
+static bool LayerShouldBeSkipped(LayerType* layer,
+ bool layer_is_drawn,
+ const TransformTree& tree) {
+ // Layers can be skipped if any of these conditions are met.
+ // - is not drawn due to it or one of its ancestors being hidden (or having
+ // no copy requests).
+ // - does not draw content.
+ // - is transparent.
+ // - has empty bounds
+ // - the layer is not double-sided, but its back face is visible.
+ //
+ // Some additional conditions need to be computed at a later point after the
+ // recursion is finished.
+ // - the intersection of render_surface content and layer clip_rect is empty
+ // - the visible_content_rect is empty
+ //
+ // Note, if the layer should not have been drawn due to being fully
+ // transparent, we would have skipped the entire subtree and never made it
+ // into this function, so it is safe to omit this check here.
+ if (!layer_is_drawn)
+ return true;
+
+ if (!layer->DrawsContent() || layer->bounds().IsEmpty())
+ return true;
+
+ LayerType* backface_test_layer = layer;
+ if (layer->use_parent_backface_visibility()) {
+ DCHECK(layer->parent());
+ DCHECK(!layer->parent()->use_parent_backface_visibility());
+ backface_test_layer = layer->parent();
+ }
+
+ // The layer should not be drawn if (1) it is not double-sided and (2) the
+ // back of the layer is known to be facing the screen.
+ if (!backface_test_layer->double_sided() &&
+ TransformToScreenIsKnown(backface_test_layer, tree) &&
+ IsLayerBackFaceVisible(backface_test_layer, tree))
+ return true;
+
+ return false;
}
template <typename LayerType>
@@ -230,24 +313,15 @@ void FindLayersThatNeedVisibleRects(LayerType* layer,
const TransformTree& tree,
bool subtree_is_visible_from_ancestor,
std::vector<LayerType*>* layers_to_update) {
- const bool layer_is_invisible = LayerIsInvisible(layer);
- const bool layer_is_backfacing =
- (layer->has_render_surface() && !layer->double_sided() &&
- IsSurfaceBackFaceExposed(layer, tree));
-
- const bool subtree_is_invisble = layer_is_invisible || layer_is_backfacing;
- if (subtree_is_invisble)
- return;
-
bool layer_is_drawn =
layer->HasCopyRequest() ||
(subtree_is_visible_from_ancestor && !layer->hide_layer_and_subtree());
- if (layer_is_drawn && layer->DrawsContent()) {
- const bool visible = !IsInvisibleDueToTransform(layer, tree);
- if (visible)
- layers_to_update->push_back(layer);
- }
+ if (layer->parent() && SubtreeShouldBeSkipped(layer, layer_is_drawn))
+ return;
+
+ if (!LayerShouldBeSkipped(layer, layer_is_drawn, tree))
+ layers_to_update->push_back(layer);
for (size_t i = 0; i < layer->children().size(); ++i) {
FindLayersThatNeedVisibleRects(layer->child_at(i), tree, layer_is_drawn,
« no previous file with comments | « no previous file | cc/trees/layer_tree_host_common_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698