summaryrefslogtreecommitdiffstats
path: root/chromium/cc/trees/draw_property_utils.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/cc/trees/draw_property_utils.cc')
-rw-r--r--chromium/cc/trees/draw_property_utils.cc742
1 files changed, 501 insertions, 241 deletions
diff --git a/chromium/cc/trees/draw_property_utils.cc b/chromium/cc/trees/draw_property_utils.cc
index 57241bad713..ad08ae82627 100644
--- a/chromium/cc/trees/draw_property_utils.cc
+++ b/chromium/cc/trees/draw_property_utils.cc
@@ -8,6 +8,7 @@
#include <vector>
+#include "base/containers/adapters.h"
#include "base/containers/stack.h"
#include "cc/base/math_util.h"
#include "cc/layers/draw_properties.h"
@@ -30,21 +31,21 @@ namespace draw_property_utils {
namespace {
-static gfx::Rect ToEnclosingClipRect(const gfx::RectF& clip_rect) {
+gfx::Rect ToEnclosingClipRect(const gfx::RectF& clip_rect) {
constexpr float kClipError = 0.00001f;
return gfx::ToEnclosingRectIgnoringError(clip_rect, kClipError);
}
-static bool IsRootLayer(const Layer* layer) {
+bool IsRootLayer(const Layer* layer) {
return !layer->parent();
}
-static bool IsRootLayer(const LayerImpl* layer) {
+bool IsRootLayer(const LayerImpl* layer) {
return layer->layer_tree_impl()->IsRootLayer(layer);
}
-static void PostConcatSurfaceContentsScale(const EffectNode* effect_node,
- gfx::Transform* transform) {
+void PostConcatSurfaceContentsScale(const EffectNode* effect_node,
+ gfx::Transform* transform) {
if (!effect_node) {
// This can happen when PaintArtifactCompositor builds property trees as it
// doesn't set effect ids on clip nodes.
@@ -55,11 +56,11 @@ static void PostConcatSurfaceContentsScale(const EffectNode* effect_node,
effect_node->surface_contents_scale.y(), 1.f);
}
-static bool ConvertRectBetweenSurfaceSpaces(const PropertyTrees* property_trees,
- int source_effect_id,
- int dest_effect_id,
- gfx::RectF clip_in_source_space,
- gfx::RectF* clip_in_dest_space) {
+bool ConvertRectBetweenSurfaceSpaces(const PropertyTrees* property_trees,
+ int source_effect_id,
+ int dest_effect_id,
+ gfx::RectF clip_in_source_space,
+ gfx::RectF* clip_in_dest_space) {
const EffectNode* source_effect_node =
property_trees->effect_tree.Node(source_effect_id);
int source_transform_id = source_effect_node->transform_id;
@@ -89,7 +90,7 @@ static bool ConvertRectBetweenSurfaceSpaces(const PropertyTrees* property_trees,
return true;
}
-static ConditionalClip ComputeTargetRectInLocalSpace(
+ConditionalClip ComputeTargetRectInLocalSpace(
gfx::RectF rect,
const PropertyTrees* property_trees,
int target_transform_id,
@@ -110,7 +111,7 @@ static ConditionalClip ComputeTargetRectInLocalSpace(
MathUtil::ProjectClippedRect(target_to_local, rect)};
}
-static ConditionalClip ComputeLocalRectInTargetSpace(
+ConditionalClip ComputeLocalRectInTargetSpace(
gfx::RectF rect,
const PropertyTrees* property_trees,
int current_transform_id,
@@ -131,10 +132,10 @@ static ConditionalClip ComputeLocalRectInTargetSpace(
MathUtil::ProjectClippedRect(current_to_target, rect)};
}
-static ConditionalClip ComputeCurrentClip(const ClipNode* clip_node,
- const PropertyTrees* property_trees,
- int target_transform_id,
- int target_effect_id) {
+ConditionalClip ComputeCurrentClip(const ClipNode* clip_node,
+ const PropertyTrees* property_trees,
+ int target_transform_id,
+ int target_effect_id) {
if (clip_node->transform_id != target_transform_id) {
return ComputeLocalRectInTargetSpace(clip_node->clip, property_trees,
clip_node->transform_id,
@@ -152,12 +153,12 @@ static ConditionalClip ComputeCurrentClip(const ClipNode* clip_node,
return ConditionalClip{true /* is_clipped */, current_clip};
}
-static bool ApplyClipNodeToAccumulatedClip(const PropertyTrees* property_trees,
- bool include_expanding_clips,
- int target_id,
- int target_transform_id,
- const ClipNode* clip_node,
- gfx::RectF* accumulated_clip) {
+bool ApplyClipNodeToAccumulatedClip(const PropertyTrees* property_trees,
+ bool include_expanding_clips,
+ int target_id,
+ int target_transform_id,
+ const ClipNode* clip_node,
+ gfx::RectF* accumulated_clip) {
switch (clip_node->clip_type) {
case ClipNode::ClipType::APPLIES_LOCAL_CLIP: {
ConditionalClip current_clip = ComputeCurrentClip(
@@ -207,10 +208,10 @@ static bool ApplyClipNodeToAccumulatedClip(const PropertyTrees* property_trees,
return true;
}
-static ConditionalClip ComputeAccumulatedClip(PropertyTrees* property_trees,
- bool include_expanding_clips,
- int local_clip_id,
- int target_id) {
+ConditionalClip ComputeAccumulatedClip(PropertyTrees* property_trees,
+ bool include_expanding_clips,
+ int local_clip_id,
+ int target_id) {
ClipRectData* cached_data =
property_trees->FetchClipRectFromCache(local_clip_id, target_id);
if (cached_data->target_id != EffectTree::kInvalidNodeId) {
@@ -325,15 +326,14 @@ static ConditionalClip ComputeAccumulatedClip(PropertyTrees* property_trees,
return clip;
}
-static bool HasSingularTransform(int transform_tree_index,
- const TransformTree& tree) {
+bool HasSingularTransform(int transform_tree_index, const TransformTree& tree) {
const TransformNode* node = tree.Node(transform_tree_index);
return !node->is_invertible || !node->ancestors_are_invertible;
}
-static int LowestCommonAncestor(int clip_id_1,
- int clip_id_2,
- const ClipTree* clip_tree) {
+int LowestCommonAncestor(int clip_id_1,
+ int clip_id_2,
+ const ClipTree* clip_tree) {
const ClipNode* clip_node_1 = clip_tree->Node(clip_id_1);
const ClipNode* clip_node_2 = clip_tree->Node(clip_id_2);
while (clip_node_1->id != clip_node_2->id) {
@@ -345,9 +345,9 @@ static int LowestCommonAncestor(int clip_id_1,
return clip_node_1->id;
}
-static void SetHasContributingLayerThatEscapesClip(int lca_clip_id,
- int target_effect_id,
- EffectTree* effect_tree) {
+void SetHasContributingLayerThatEscapesClip(int lca_clip_id,
+ int target_effect_id,
+ EffectTree* effect_tree) {
const EffectNode* effect_node = effect_tree->Node(target_effect_id);
// Find all ancestor targets starting from effect_node who are clipped by
// a descendant of lowest ancestor clip and set their
@@ -362,14 +362,14 @@ static void SetHasContributingLayerThatEscapesClip(int lca_clip_id,
}
template <typename LayerType>
-static int TransformTreeIndexForBackfaceVisibility(LayerType* layer,
- const TransformTree& tree) {
+int TransformTreeIndexForBackfaceVisibility(LayerType* layer,
+ const TransformTree& tree) {
if (!layer->use_parent_backface_visibility() || !layer->has_transform_node())
return layer->transform_tree_index();
return tree.Node(layer->transform_tree_index())->parent_id;
}
-static bool IsTargetSpaceTransformBackFaceVisible(
+bool IsTargetSpaceTransformBackFaceVisible(
Layer* layer,
int transform_tree_index,
const PropertyTrees* property_trees) {
@@ -378,7 +378,7 @@ static bool IsTargetSpaceTransformBackFaceVisible(
return false;
}
-static bool IsTargetSpaceTransformBackFaceVisible(
+bool IsTargetSpaceTransformBackFaceVisible(
LayerImpl* layer,
int transform_tree_index,
const PropertyTrees* property_trees) {
@@ -390,30 +390,30 @@ static bool IsTargetSpaceTransformBackFaceVisible(
}
template <typename LayerType>
-static bool IsLayerBackFaceVisible(LayerType* layer,
- int transform_tree_index,
- const PropertyTrees* property_trees) {
+bool IsLayerBackFaceVisible(LayerType* layer,
+ int transform_tree_index,
+ const PropertyTrees* property_trees) {
return IsTargetSpaceTransformBackFaceVisible(layer, transform_tree_index,
property_trees);
}
-static inline bool TransformToScreenIsKnown(Layer* layer,
- int transform_tree_index,
- const TransformTree& tree) {
+inline bool TransformToScreenIsKnown(Layer* layer,
+ int transform_tree_index,
+ const TransformTree& tree) {
const TransformNode* node = tree.Node(transform_tree_index);
return !node->to_screen_is_potentially_animated;
}
-static inline bool TransformToScreenIsKnown(LayerImpl* layer,
- int transform_tree_index,
- const TransformTree& tree) {
+inline bool TransformToScreenIsKnown(LayerImpl* layer,
+ int transform_tree_index,
+ const TransformTree& tree) {
return true;
}
template <typename LayerType>
-static bool LayerNeedsUpdateInternal(LayerType* layer,
- bool layer_is_drawn,
- const PropertyTrees* property_trees) {
+bool LayerNeedsUpdate(LayerType* layer,
+ bool layer_is_drawn,
+ const PropertyTrees* property_trees) {
// 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).
@@ -454,7 +454,7 @@ static bool LayerNeedsUpdateInternal(LayerType* layer,
}
template <typename LayerType>
-static inline bool LayerShouldBeSkippedInternal(
+inline bool LayerShouldBeSkippedForDrawPropertiesComputation(
LayerType* layer,
const TransformTree& transform_tree,
const EffectTree& effect_tree) {
@@ -470,7 +470,7 @@ static inline bool LayerShouldBeSkippedInternal(
effect_node->hidden_by_backface_visibility || !effect_node->is_drawn;
}
-static gfx::Rect LayerDrawableContentRect(
+gfx::Rect LayerDrawableContentRect(
const LayerImpl* layer,
const gfx::Rect& layer_bounds_in_target_space,
const gfx::Rect& clip_rect) {
@@ -480,8 +480,8 @@ static gfx::Rect LayerDrawableContentRect(
return layer_bounds_in_target_space;
}
-static void SetSurfaceIsClipped(const ClipTree& clip_tree,
- RenderSurfaceImpl* render_surface) {
+void SetSurfaceIsClipped(const ClipTree& clip_tree,
+ RenderSurfaceImpl* render_surface) {
bool is_clipped;
if (render_surface->EffectTreeIndex() == EffectTree::kContentsRootNodeId) {
// Root render surface is always clipped.
@@ -504,8 +504,8 @@ static void SetSurfaceIsClipped(const ClipTree& clip_tree,
render_surface->SetIsClipped(is_clipped);
}
-static void SetSurfaceDrawOpacity(const EffectTree& tree,
- RenderSurfaceImpl* render_surface) {
+void SetSurfaceDrawOpacity(const EffectTree& tree,
+ RenderSurfaceImpl* render_surface) {
// Draw opacity of a surface is the product of opacities between the surface
// (included) and its target surface (excluded).
const EffectNode* node = tree.Node(render_surface->EffectTreeIndex());
@@ -517,7 +517,7 @@ static void SetSurfaceDrawOpacity(const EffectTree& tree,
render_surface->SetDrawOpacity(draw_opacity);
}
-static float LayerDrawOpacity(const LayerImpl* layer, const EffectTree& tree) {
+float LayerDrawOpacity(const LayerImpl* layer, const EffectTree& tree) {
if (!layer->render_target())
return 0.f;
@@ -536,20 +536,18 @@ static float LayerDrawOpacity(const LayerImpl* layer, const EffectTree& tree) {
}
template <typename LayerType>
-static gfx::Transform ScreenSpaceTransformInternal(LayerType* layer,
- const TransformTree& tree) {
+gfx::Transform ScreenSpaceTransformInternal(LayerType* layer,
+ const TransformTree& tree) {
gfx::Transform xform(1, 0, 0, 1, layer->offset_to_transform_parent().x(),
layer->offset_to_transform_parent().y());
gfx::Transform ssxform = tree.ToScreen(layer->transform_tree_index());
xform.ConcatTransform(ssxform);
- if (layer->should_flatten_screen_space_transform_from_property_tree())
- xform.FlattenTo2d();
return xform;
}
-static void SetSurfaceClipRect(const ClipNode* parent_clip_node,
- PropertyTrees* property_trees,
- RenderSurfaceImpl* render_surface) {
+void SetSurfaceClipRect(const ClipNode* parent_clip_node,
+ PropertyTrees* property_trees,
+ RenderSurfaceImpl* render_surface) {
if (!render_surface->is_clipped()) {
render_surface->SetClipRect(gfx::Rect());
return;
@@ -573,8 +571,8 @@ static void SetSurfaceClipRect(const ClipNode* parent_clip_node,
}
}
-static void SetSurfaceDrawTransform(const PropertyTrees* property_trees,
- RenderSurfaceImpl* render_surface) {
+void SetSurfaceDrawTransform(const PropertyTrees* property_trees,
+ RenderSurfaceImpl* render_surface) {
const TransformTree& transform_tree = property_trees->transform_tree;
const EffectTree& effect_tree = property_trees->effect_tree;
const TransformNode* transform_node =
@@ -597,8 +595,7 @@ static void SetSurfaceDrawTransform(const PropertyTrees* property_trees,
render_surface->SetDrawTransform(render_surface_transform);
}
-static gfx::Rect LayerVisibleRect(PropertyTrees* property_trees,
- LayerImpl* layer) {
+gfx::Rect LayerVisibleRect(PropertyTrees* property_trees, LayerImpl* layer) {
const EffectNode* effect_node =
property_trees->effect_tree.Node(layer->effect_tree_index());
int effect_ancestor_with_cache_render_surface =
@@ -655,8 +652,7 @@ static gfx::Rect LayerVisibleRect(PropertyTrees* property_trees,
return visible_rect;
}
-static ConditionalClip LayerClipRect(PropertyTrees* property_trees,
- LayerImpl* layer) {
+ConditionalClip LayerClipRect(PropertyTrees* property_trees, LayerImpl* layer) {
const EffectTree* effect_tree = &property_trees->effect_tree;
const EffectNode* effect_node = effect_tree->Node(layer->effect_tree_index());
const EffectNode* target_node =
@@ -668,7 +664,7 @@ static ConditionalClip LayerClipRect(PropertyTrees* property_trees,
layer->clip_tree_index(), target_node->id);
}
-static std::pair<gfx::RRectF, bool> GetRoundedCornerRRect(
+std::pair<gfx::RRectF, bool> GetRoundedCornerRRect(
const PropertyTrees* property_trees,
int effect_tree_index,
bool for_render_surface) {
@@ -693,9 +689,16 @@ static std::pair<gfx::RRectF, bool> GetRoundedCornerRRect(
break;
}
- // Simply break if we reached a node that has a render surface or is the
- // render target.
- if (node->HasRenderSurface() || node->id == target_id)
+ // If the iteration has reached a node in the parent chain that has a render
+ // surface, then break. If this iteration is for a render surface to begin
+ // with, then ensure |node| is a parent of |effect_node|.
+ if (node->HasRenderSurface() &&
+ (!for_render_surface || effect_node != node)) {
+ break;
+ }
+
+ // Simply break if we reached a node that is the render target.
+ if (node->id == target_id)
break;
node = effect_tree->parent(node);
@@ -710,17 +713,16 @@ static std::pair<gfx::RRectF, bool> GetRoundedCornerRRect(
if (!property_trees->GetToTarget(node->transform_id, target_id, &to_target))
return kEmptyRoundedCornerInfo;
- DCHECK(to_target.Preserves2dAxisAlignment());
+ auto result =
+ std::make_pair(node->rounded_corner_bounds, node->is_fast_rounded_corner);
- SkRRect result;
- if (!SkRRect(node->rounded_corner_bounds)
- .transform(to_target.matrix(), &result)) {
+ if (!to_target.TransformRRectF(&result.first))
return kEmptyRoundedCornerInfo;
- }
- return std::make_pair(gfx::RRectF(result), node->is_fast_rounded_corner);
+
+ return result;
}
-static void UpdateRenderTarget(EffectTree* effect_tree) {
+void UpdateRenderTarget(EffectTree* effect_tree) {
for (int i = EffectTree::kContentsRootNodeId;
i < static_cast<int>(effect_tree->size()); ++i) {
EffectNode* node = effect_tree->Node(i);
@@ -735,7 +737,7 @@ static void UpdateRenderTarget(EffectTree* effect_tree) {
}
}
-static void ComputeClips(PropertyTrees* property_trees) {
+void ComputeClips(PropertyTrees* property_trees) {
DCHECK(!property_trees->transform_tree.needs_update());
ClipTree* clip_tree = &property_trees->clip_tree;
if (!clip_tree->needs_update())
@@ -765,6 +767,352 @@ static void ComputeClips(PropertyTrees* property_trees) {
clip_tree->set_needs_update(false);
}
+void ComputeSurfaceDrawProperties(PropertyTrees* property_trees,
+ RenderSurfaceImpl* render_surface) {
+ SetSurfaceIsClipped(property_trees->clip_tree, render_surface);
+ SetSurfaceDrawOpacity(property_trees->effect_tree, render_surface);
+ SetSurfaceDrawTransform(property_trees, render_surface);
+
+ render_surface->SetRoundedCornerRRect(
+ GetRoundedCornerRRect(property_trees, render_surface->EffectTreeIndex(),
+ /*for_render_surface*/ true)
+ .first);
+ render_surface->SetScreenSpaceTransform(
+ property_trees->ToScreenSpaceTransformWithoutSurfaceContentsScale(
+ render_surface->TransformTreeIndex(),
+ render_surface->EffectTreeIndex()));
+
+ const ClipNode* clip_node =
+ property_trees->clip_tree.Node(render_surface->ClipTreeIndex());
+ SetSurfaceClipRect(clip_node, property_trees, render_surface);
+}
+
+void AddSurfaceToRenderSurfaceList(RenderSurfaceImpl* render_surface,
+ RenderSurfaceList* render_surface_list,
+ PropertyTrees* property_trees) {
+ // |render_surface| must appear after its target, so first make sure its
+ // target is in the list.
+ RenderSurfaceImpl* target = render_surface->render_target();
+ bool is_root =
+ render_surface->EffectTreeIndex() == EffectTree::kContentsRootNodeId;
+ if (!is_root && !target->is_render_surface_list_member()) {
+ AddSurfaceToRenderSurfaceList(target, render_surface_list, property_trees);
+ }
+ render_surface->ClearAccumulatedContentRect();
+ render_surface_list->push_back(render_surface);
+ render_surface->set_is_render_surface_list_member(true);
+ if (is_root) {
+ // The root surface does not contribute to any other surface, it has no
+ // target.
+ render_surface->set_contributes_to_drawn_surface(false);
+ } else {
+ bool contributes_to_drawn_surface =
+ property_trees->effect_tree.ContributesToDrawnSurface(
+ render_surface->EffectTreeIndex());
+ render_surface->set_contributes_to_drawn_surface(
+ contributes_to_drawn_surface);
+ }
+
+ ComputeSurfaceDrawProperties(property_trees, render_surface);
+
+ // Ignore occlusion from outside the surface when surface contents need to be
+ // fully drawn. Layers with copy-request need to be complete. We could be
+ // smarter about layers with filters that move pixels and exclude regions
+ // where both layers and the filters are occluded, but this seems like
+ // overkill.
+ // TODO(senorblanco): make this smarter for the SkImageFilter case (check for
+ // pixel-moving filters)
+ const FilterOperations& filters = render_surface->Filters();
+ bool is_occlusion_immune = render_surface->HasCopyRequest() ||
+ render_surface->ShouldCacheRenderSurface() ||
+ filters.HasReferenceFilter() ||
+ filters.HasFilterThatMovesPixels();
+ if (is_occlusion_immune) {
+ render_surface->SetNearestOcclusionImmuneAncestor(render_surface);
+ } else if (is_root) {
+ render_surface->SetNearestOcclusionImmuneAncestor(nullptr);
+ } else {
+ render_surface->SetNearestOcclusionImmuneAncestor(
+ render_surface->render_target()->nearest_occlusion_immune_ancestor());
+ }
+}
+
+bool SkipForInvertibility(const LayerImpl* layer,
+ PropertyTrees* property_trees) {
+ const TransformNode* transform_node =
+ property_trees->transform_tree.Node(layer->transform_tree_index());
+ const EffectNode* effect_node =
+ property_trees->effect_tree.Node(layer->effect_tree_index());
+ bool non_root_copy_request =
+ effect_node->closest_ancestor_with_copy_request_id >
+ EffectTree::kContentsRootNodeId;
+ gfx::Transform from_target;
+ // If there is a copy request, we check the invertibility of the transform
+ // between the node corresponding to the layer and the node corresponding to
+ // the copy request. Otherwise, we are interested in the invertibility of
+ // screen space transform which is already cached on the transform node.
+ return non_root_copy_request
+ ? !property_trees->GetFromTarget(
+ layer->transform_tree_index(),
+ effect_node->closest_ancestor_with_copy_request_id,
+ &from_target)
+ : !transform_node->ancestors_are_invertible;
+}
+
+void ComputeInitialRenderSurfaceList(LayerTreeImpl* layer_tree_impl,
+ PropertyTrees* property_trees,
+ RenderSurfaceList* render_surface_list) {
+ EffectTree& effect_tree = property_trees->effect_tree;
+ for (int i = EffectTree::kContentsRootNodeId;
+ i < static_cast<int>(effect_tree.size()); ++i) {
+ if (RenderSurfaceImpl* render_surface = effect_tree.GetRenderSurface(i)) {
+ render_surface->set_is_render_surface_list_member(false);
+ render_surface->reset_num_contributors();
+ }
+ }
+
+ RenderSurfaceImpl* root_surface =
+ effect_tree.GetRenderSurface(EffectTree::kContentsRootNodeId);
+ // The root surface always gets added to the render surface list.
+ AddSurfaceToRenderSurfaceList(root_surface, render_surface_list,
+ property_trees);
+ // For all non-skipped layers, add their target to the render surface list if
+ // it's not already been added, and add their content rect to the target
+ // surface's accumulated content rect.
+ for (LayerImpl* layer : *layer_tree_impl) {
+ DCHECK(layer);
+ layer->EnsureValidPropertyTreeIndices();
+
+ layer->set_contributes_to_drawn_render_surface(false);
+ layer->set_raster_even_if_not_drawn(false);
+
+ bool is_root = layer_tree_impl->IsRootLayer(layer);
+
+ bool skip_draw_properties_computation =
+ LayerShouldBeSkippedForDrawPropertiesComputation(
+ layer, property_trees->transform_tree, property_trees->effect_tree);
+
+ bool skip_for_invertibility = SkipForInvertibility(layer, property_trees);
+
+ bool skip_layer = !is_root && (skip_draw_properties_computation ||
+ skip_for_invertibility);
+
+ layer->set_raster_even_if_not_drawn(skip_for_invertibility &&
+ !skip_draw_properties_computation);
+ if (skip_layer)
+ continue;
+
+ bool layer_is_drawn =
+ property_trees->effect_tree.Node(layer->effect_tree_index())->is_drawn;
+ bool layer_should_be_drawn =
+ LayerNeedsUpdate(layer, layer_is_drawn, property_trees);
+ if (!layer_should_be_drawn)
+ continue;
+
+ RenderSurfaceImpl* render_target = layer->render_target();
+ if (!render_target->is_render_surface_list_member()) {
+ AddSurfaceToRenderSurfaceList(render_target, render_surface_list,
+ property_trees);
+ }
+
+ layer->set_contributes_to_drawn_render_surface(true);
+
+ // The layer contributes its drawable content rect to its render target.
+ render_target->AccumulateContentRectFromContributingLayer(layer);
+ render_target->increment_num_contributors();
+ }
+}
+
+void ComputeSurfaceContentRects(PropertyTrees* property_trees,
+ RenderSurfaceList* render_surface_list,
+ int max_texture_size) {
+ // Walk the list backwards, accumulating each surface's content rect into its
+ // target's content rect.
+ for (RenderSurfaceImpl* render_surface :
+ base::Reversed(*render_surface_list)) {
+ if (render_surface->EffectTreeIndex() == EffectTree::kContentsRootNodeId) {
+ // The root surface's content rect is always the entire viewport.
+ render_surface->SetContentRectToViewport();
+ continue;
+ }
+
+ // Now all contributing drawable content rect has been accumulated to this
+ // render surface, calculate the content rect.
+ render_surface->CalculateContentRectFromAccumulatedContentRect(
+ max_texture_size);
+
+ // Now the render surface's content rect is calculated correctly, it could
+ // contribute to its render target.
+ RenderSurfaceImpl* render_target = render_surface->render_target();
+ DCHECK(render_target->is_render_surface_list_member());
+ render_target->AccumulateContentRectFromContributingRenderSurface(
+ render_surface);
+ render_target->increment_num_contributors();
+ }
+}
+
+void ComputeListOfNonEmptySurfaces(LayerTreeImpl* layer_tree_impl,
+ PropertyTrees* property_trees,
+ RenderSurfaceList* initial_surface_list,
+ RenderSurfaceList* final_surface_list) {
+ // Walk the initial surface list forwards. The root surface and each
+ // surface with a non-empty content rect go into the final render surface
+ // layer list. Surfaces with empty content rects or whose target isn't in
+ // the final list do not get added to the final list.
+ bool removed_surface = false;
+ for (RenderSurfaceImpl* surface : *initial_surface_list) {
+ bool is_root =
+ surface->EffectTreeIndex() == EffectTree::kContentsRootNodeId;
+ RenderSurfaceImpl* target_surface = surface->render_target();
+ if (!is_root && (surface->content_rect().IsEmpty() ||
+ !target_surface->is_render_surface_list_member())) {
+ surface->set_is_render_surface_list_member(false);
+ removed_surface = true;
+ target_surface->decrement_num_contributors();
+ continue;
+ }
+ final_surface_list->push_back(surface);
+ }
+ if (removed_surface) {
+ for (LayerImpl* layer : *layer_tree_impl) {
+ if (layer->contributes_to_drawn_render_surface()) {
+ RenderSurfaceImpl* render_target = layer->render_target();
+ if (!render_target->is_render_surface_list_member()) {
+ layer->set_contributes_to_drawn_render_surface(false);
+ render_target->decrement_num_contributors();
+ }
+ }
+ }
+ }
+}
+
+void CalculateRenderSurfaceLayerList(LayerTreeImpl* layer_tree_impl,
+ PropertyTrees* property_trees,
+ RenderSurfaceList* render_surface_list,
+ const int max_texture_size) {
+ RenderSurfaceList initial_render_surface_list;
+
+ // First compute a list that might include surfaces that later turn out to
+ // have an empty content rect. After surface content rects are computed,
+ // produce a final list that omits empty surfaces.
+ ComputeInitialRenderSurfaceList(layer_tree_impl, property_trees,
+ &initial_render_surface_list);
+ ComputeSurfaceContentRects(property_trees, &initial_render_surface_list,
+ max_texture_size);
+ ComputeListOfNonEmptySurfaces(layer_tree_impl, property_trees,
+ &initial_render_surface_list,
+ render_surface_list);
+}
+
+void RecordRenderSurfaceReasonsForTracing(
+ const PropertyTrees* property_trees,
+ const RenderSurfaceList* render_surface_list) {
+ static const auto* tracing_enabled =
+ TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("cc");
+ if (!*tracing_enabled ||
+ // Don't output single root render surface.
+ render_surface_list->size() <= 1)
+ return;
+
+ TRACE_EVENT_INSTANT1("cc", "RenderSurfaceReasonCount",
+ TRACE_EVENT_SCOPE_THREAD, "total",
+ render_surface_list->size());
+
+ // kTest is the last value which is not included for tracing.
+ constexpr auto kNumReasons = static_cast<size_t>(RenderSurfaceReason::kTest);
+ int reason_counts[kNumReasons] = {0};
+ for (const auto* render_surface : *render_surface_list) {
+ const auto* effect_node =
+ property_trees->effect_tree.Node(render_surface->EffectTreeIndex());
+ reason_counts[static_cast<size_t>(effect_node->render_surface_reason)]++;
+ }
+ for (size_t i = 0; i < kNumReasons; i++) {
+ if (!reason_counts[i])
+ continue;
+ TRACE_EVENT_INSTANT1(
+ "cc", "RenderSurfaceReasonCount", TRACE_EVENT_SCOPE_THREAD,
+ RenderSurfaceReasonToString(static_cast<RenderSurfaceReason>(i)),
+ reason_counts[i]);
+ }
+}
+
+void UpdateElasticOverscroll(
+ PropertyTrees* property_trees,
+ TransformNode* overscroll_elasticity_transform_node,
+ const gfx::Vector2dF& elastic_overscroll) {
+ if (!overscroll_elasticity_transform_node) {
+ DCHECK(elastic_overscroll.IsZero());
+ return;
+ }
+
+ if (overscroll_elasticity_transform_node->scroll_offset ==
+ gfx::ScrollOffset(elastic_overscroll))
+ return;
+
+ overscroll_elasticity_transform_node->scroll_offset =
+ gfx::ScrollOffset(elastic_overscroll);
+ overscroll_elasticity_transform_node->needs_local_transform_update = true;
+ property_trees->transform_tree.set_needs_update(true);
+}
+
+void ComputeDrawPropertiesOfVisibleLayers(const LayerImplList* layer_list,
+ PropertyTrees* property_trees) {
+ // Compute transforms
+ for (LayerImpl* layer : *layer_list) {
+ const TransformNode* transform_node =
+ property_trees->transform_tree.Node(layer->transform_tree_index());
+
+ layer->draw_properties().screen_space_transform =
+ ScreenSpaceTransformInternal(layer, property_trees->transform_tree);
+ layer->draw_properties().target_space_transform = DrawTransform(
+ layer, property_trees->transform_tree, property_trees->effect_tree);
+ layer->draw_properties().screen_space_transform_is_animating =
+ transform_node->to_screen_is_potentially_animated;
+ auto rounded_corner_info =
+ GetRoundedCornerRRect(property_trees, layer->effect_tree_index(),
+ /*from_render_surface*/ false);
+ layer->draw_properties().rounded_corner_bounds = rounded_corner_info.first;
+ layer->draw_properties().is_fast_rounded_corner =
+ rounded_corner_info.second;
+ }
+
+ // Compute effects and determine if render surfaces have contributing layers
+ // that escape clip.
+ for (LayerImpl* layer : *layer_list) {
+ layer->draw_properties().opacity =
+ LayerDrawOpacity(layer, property_trees->effect_tree);
+ RenderSurfaceImpl* render_target = layer->render_target();
+ int lca_clip_id = LowestCommonAncestor(layer->clip_tree_index(),
+ render_target->ClipTreeIndex(),
+ &property_trees->clip_tree);
+ if (lca_clip_id != render_target->ClipTreeIndex()) {
+ SetHasContributingLayerThatEscapesClip(lca_clip_id,
+ render_target->EffectTreeIndex(),
+ &property_trees->effect_tree);
+ }
+ }
+
+ // Compute clips and visible rects
+ for (LayerImpl* layer : *layer_list) {
+ ConditionalClip clip = LayerClipRect(property_trees, layer);
+ // is_clipped should be set before visible rect computation as it is used
+ // there.
+ layer->draw_properties().is_clipped = clip.is_clipped;
+ layer->draw_properties().clip_rect = ToEnclosingClipRect(clip.clip_rect);
+ layer->draw_properties().visible_layer_rect =
+ LayerVisibleRect(property_trees, layer);
+ }
+
+ // Compute drawable content rects
+ for (LayerImpl* layer : *layer_list) {
+ gfx::Rect bounds_in_target_space = MathUtil::MapEnclosingClippedRect(
+ layer->draw_properties().target_space_transform,
+ gfx::Rect(layer->bounds()));
+ layer->draw_properties().drawable_content_rect = LayerDrawableContentRect(
+ layer, bounds_in_target_space, layer->draw_properties().clip_rect);
+ }
+}
+
} // namespace
void ConcatInverseSurfaceContentsScale(const EffectNode* effect_node,
@@ -776,23 +1124,9 @@ void ConcatInverseSurfaceContentsScale(const EffectNode* effect_node,
1.0 / effect_node->surface_contents_scale.y());
}
-bool LayerShouldBeSkippedForDrawPropertiesComputation(
- LayerImpl* layer,
- const TransformTree& transform_tree,
- const EffectTree& effect_tree) {
- return LayerShouldBeSkippedInternal(layer, transform_tree, effect_tree);
-}
-
-bool LayerShouldBeSkippedForDrawPropertiesComputation(
- Layer* layer,
- const TransformTree& transform_tree,
- const EffectTree& effect_tree) {
- return LayerShouldBeSkippedInternal(layer, transform_tree, effect_tree);
-}
-
void FindLayersThatNeedUpdates(LayerTreeHost* layer_tree_host,
- const PropertyTrees* property_trees,
LayerList* update_layer_list) {
+ const PropertyTrees* property_trees = layer_tree_host->property_trees();
const TransformTree& transform_tree = property_trees->transform_tree;
const EffectTree& effect_tree = property_trees->effect_tree;
for (auto* layer : *layer_tree_host) {
@@ -806,20 +1140,12 @@ void FindLayersThatNeedUpdates(LayerTreeHost* layer_tree_host,
if (LayerNeedsUpdate(layer, layer_is_drawn, property_trees)) {
update_layer_list->push_back(layer);
}
-
- // Append mask layers to the update layer list. They don't have valid
- // visible rects, so need to get added after the above calculation.
- if (PictureLayer* mask_layer = layer->mask_layer()) {
- // Layers with empty bounds should never be painted, including masks.
- if (!mask_layer->bounds().IsEmpty())
- update_layer_list->push_back(mask_layer);
- }
}
}
void FindLayersThatNeedUpdates(LayerTreeImpl* layer_tree_impl,
- const PropertyTrees* property_trees,
std::vector<LayerImpl*>* visible_layer_list) {
+ const PropertyTrees* property_trees = layer_tree_impl->property_trees();
const TransformTree& transform_tree = property_trees->transform_tree;
const EffectTree& effect_tree = property_trees->effect_tree;
@@ -868,11 +1194,10 @@ void ComputeEffects(EffectTree* effect_tree) {
effect_tree->set_needs_update(false);
}
-void UpdatePropertyTrees(LayerTreeHost* layer_tree_host,
- PropertyTrees* property_trees) {
+void UpdatePropertyTrees(LayerTreeHost* layer_tree_host) {
DCHECK(layer_tree_host);
+ auto* property_trees = layer_tree_host->property_trees();
DCHECK(property_trees);
- DCHECK_EQ(layer_tree_host->property_trees(), property_trees);
if (property_trees->transform_tree.needs_update()) {
property_trees->clip_tree.set_needs_update(true);
property_trees->effect_tree.set_needs_update(true);
@@ -899,18 +1224,6 @@ void UpdatePropertyTreesAndRenderSurfaces(LayerImpl* root_layer,
ComputeClips(property_trees);
}
-bool LayerNeedsUpdate(Layer* layer,
- bool layer_is_drawn,
- const PropertyTrees* property_trees) {
- return LayerNeedsUpdateInternal(layer, layer_is_drawn, property_trees);
-}
-
-bool LayerNeedsUpdate(LayerImpl* layer,
- bool layer_is_drawn,
- const PropertyTrees* property_trees) {
- return LayerNeedsUpdateInternal(layer, layer_is_drawn, property_trees);
-}
-
gfx::Transform DrawTransform(const LayerImpl* layer,
const TransformTree& transform_tree,
const EffectTree& effect_tree) {
@@ -921,8 +1234,6 @@ gfx::Transform DrawTransform(const LayerImpl* layer,
transform_tree.property_trees()->GetToTarget(
layer->transform_tree_index(), layer->render_target_effect_tree_index(),
&xform);
- if (layer->should_flatten_screen_space_transform_from_property_tree())
- xform.FlattenTo2d();
xform.Translate(layer->offset_to_transform_parent().x(),
layer->offset_to_transform_parent().y());
return xform;
@@ -938,110 +1249,6 @@ gfx::Transform ScreenSpaceTransform(const LayerImpl* layer,
return ScreenSpaceTransformInternal(layer, tree);
}
-void ComputeDrawPropertiesOfVisibleLayers(const LayerImplList* layer_list,
- PropertyTrees* property_trees) {
- // Compute transforms
- for (LayerImpl* layer : *layer_list) {
- const TransformNode* transform_node =
- property_trees->transform_tree.Node(layer->transform_tree_index());
-
- layer->draw_properties().screen_space_transform =
- ScreenSpaceTransformInternal(layer, property_trees->transform_tree);
- layer->draw_properties().target_space_transform = DrawTransform(
- layer, property_trees->transform_tree, property_trees->effect_tree);
- layer->draw_properties().screen_space_transform_is_animating =
- transform_node->to_screen_is_potentially_animated;
- auto rounded_corner_info =
- GetRoundedCornerRRect(property_trees, layer->effect_tree_index(),
- /*from_render_surface*/ false);
- layer->draw_properties().rounded_corner_bounds = rounded_corner_info.first;
- layer->draw_properties().is_fast_rounded_corner =
- rounded_corner_info.second;
- }
-
- // Compute effects and determine if render surfaces have contributing layers
- // that escape clip.
- for (LayerImpl* layer : *layer_list) {
- layer->draw_properties().opacity =
- LayerDrawOpacity(layer, property_trees->effect_tree);
- RenderSurfaceImpl* render_target = layer->render_target();
- int lca_clip_id = LowestCommonAncestor(layer->clip_tree_index(),
- render_target->ClipTreeIndex(),
- &property_trees->clip_tree);
- if (lca_clip_id != render_target->ClipTreeIndex()) {
- SetHasContributingLayerThatEscapesClip(lca_clip_id,
- render_target->EffectTreeIndex(),
- &property_trees->effect_tree);
- }
- }
-
- // Compute clips and visible rects
- for (LayerImpl* layer : *layer_list) {
- ConditionalClip clip = LayerClipRect(property_trees, layer);
- // is_clipped should be set before visible rect computation as it is used
- // there.
- layer->draw_properties().is_clipped = clip.is_clipped;
- layer->draw_properties().clip_rect = ToEnclosingClipRect(clip.clip_rect);
- layer->draw_properties().visible_layer_rect =
- LayerVisibleRect(property_trees, layer);
- }
-
- // Compute drawable content rects
- for (LayerImpl* layer : *layer_list) {
- gfx::Rect bounds_in_target_space = MathUtil::MapEnclosingClippedRect(
- layer->draw_properties().target_space_transform,
- gfx::Rect(layer->bounds()));
- layer->draw_properties().drawable_content_rect = LayerDrawableContentRect(
- layer, bounds_in_target_space, layer->draw_properties().clip_rect);
- }
-}
-
-void ComputeMaskDrawProperties(LayerImpl* mask_layer,
- PropertyTrees* property_trees) {
- // Mask draw properties are used only for rastering, so most of the draw
- // properties computed for other layers are not needed.
- // Draw transform of a mask layer has to be a 2d scale.
- // TODO(sunxd): the draw transform of a mask layer misses the "scale to fit"
- // factor from mask layer to its parent. So does the screen space transform.
- // It does not cause a problem because currently we only have 1:1 mask layer.
- mask_layer->draw_properties().target_space_transform = DrawTransform(
- mask_layer, property_trees->transform_tree, property_trees->effect_tree);
- mask_layer->draw_properties().screen_space_transform =
- ScreenSpaceTransformInternal(mask_layer,
- property_trees->transform_tree);
-
- ConditionalClip clip = LayerClipRect(property_trees, mask_layer);
- // is_clipped should be set before visible rect computation as it is used
- // there.
- mask_layer->draw_properties().is_clipped = clip.is_clipped;
- mask_layer->draw_properties().clip_rect = ToEnclosingClipRect(clip.clip_rect);
- // Calculate actual visible layer rect for mask layers, since we could have
- // tiled mask layers and the tile manager would need this info for rastering.
- mask_layer->draw_properties().visible_layer_rect =
- LayerVisibleRect(property_trees, mask_layer);
- mask_layer->draw_properties().opacity = 1;
-}
-
-void ComputeSurfaceDrawProperties(PropertyTrees* property_trees,
- RenderSurfaceImpl* render_surface) {
- SetSurfaceIsClipped(property_trees->clip_tree, render_surface);
- SetSurfaceDrawOpacity(property_trees->effect_tree, render_surface);
- SetSurfaceDrawTransform(property_trees, render_surface);
-
- render_surface->SetRoundedCornerRRect(
- GetRoundedCornerRRect(property_trees, render_surface->EffectTreeIndex(),
- /*for_render_surface*/ true)
- .first);
- render_surface->SetScreenSpaceTransform(
- property_trees->ToScreenSpaceTransformWithoutSurfaceContentsScale(
- render_surface->TransformTreeIndex(),
- render_surface->EffectTreeIndex()));
-
- const ClipNode* clip_node =
- property_trees->clip_tree.Node(render_surface->ClipTreeIndex());
- SetSurfaceClipRect(clip_node, property_trees, render_surface);
-}
-
void UpdatePageScaleFactor(PropertyTrees* property_trees,
TransformNode* page_scale_node,
float page_scale_factor) {
@@ -1061,24 +1268,77 @@ void UpdatePageScaleFactor(PropertyTrees* property_trees,
property_trees->transform_tree.set_needs_update(true);
}
-void UpdateElasticOverscroll(PropertyTrees* property_trees,
- const ElementId overscroll_elasticity_element_id,
- const gfx::Vector2dF& elastic_overscroll) {
- if (!overscroll_elasticity_element_id) {
- DCHECK(elastic_overscroll.IsZero());
- return;
+void CalculateDrawProperties(
+ LayerTreeImpl* layer_tree_impl,
+ RenderSurfaceList* output_render_surface_list,
+ LayerImplList* output_update_layer_list_for_testing) {
+ output_render_surface_list->clear();
+
+ LayerImplList visible_layer_list;
+ // Since page scale and elastic overscroll are SyncedProperties, changes
+ // on the active tree immediately affect the pending tree, so instead of
+ // trying to update property trees whenever these values change, we
+ // update property trees before using them.
+
+ // We should never be setting a non-unit page scale factor on an oopif
+ // subframe ... if we attempt this log it and fail.
+ // TODO(wjmaclean): Remove as part of conditions for closing the bug.
+ // https://crbug.com/845097
+ PropertyTrees* property_trees = layer_tree_impl->property_trees();
+ if (layer_tree_impl->current_page_scale_factor() !=
+ property_trees->transform_tree.page_scale_factor() &&
+ !layer_tree_impl->PageScaleTransformNode()) {
+ LOG(ERROR) << "Setting PageScale on subframe: new psf = "
+ << layer_tree_impl->page_scale_factor() << ", old psf = "
+ << property_trees->transform_tree.page_scale_factor()
+ << ", in_oopif = "
+ << layer_tree_impl->settings().is_layer_tree_for_subframe;
+ NOTREACHED();
}
- TransformNode* node = property_trees->transform_tree.FindNodeFromElementId(
- overscroll_elasticity_element_id);
- DCHECK(node);
+ UpdatePageScaleFactor(property_trees,
+ layer_tree_impl->PageScaleTransformNode(),
+ layer_tree_impl->current_page_scale_factor());
+ UpdateElasticOverscroll(property_trees,
+ layer_tree_impl->OverscrollElasticityTransformNode(),
+ layer_tree_impl->current_elastic_overscroll());
+ // Similarly, the device viewport and device transform are shared
+ // by both trees.
+ property_trees->clip_tree.SetViewportClip(
+ gfx::RectF(layer_tree_impl->GetDeviceViewport()));
+ property_trees->transform_tree.SetRootScaleAndTransform(
+ layer_tree_impl->device_scale_factor(), layer_tree_impl->DrawTransform());
+ UpdatePropertyTreesAndRenderSurfaces(layer_tree_impl->root_layer(),
+ property_trees);
+
+ {
+ TRACE_EVENT0("cc", "draw_property_utils::FindLayersThatNeedUpdates");
+ FindLayersThatNeedUpdates(layer_tree_impl, &visible_layer_list);
+ }
- if (node->scroll_offset == gfx::ScrollOffset(elastic_overscroll))
- return;
+ {
+ TRACE_EVENT1("cc",
+ "draw_property_utils::ComputeDrawPropertiesOfVisibleLayers",
+ "visible_layers", visible_layer_list.size());
+ ComputeDrawPropertiesOfVisibleLayers(&visible_layer_list, property_trees);
+ }
- node->scroll_offset = gfx::ScrollOffset(elastic_overscroll);
- node->needs_local_transform_update = true;
- property_trees->transform_tree.set_needs_update(true);
+ {
+ TRACE_EVENT0("cc", "CalculateRenderSurfaceLayerList");
+ CalculateRenderSurfaceLayerList(layer_tree_impl, property_trees,
+ output_render_surface_list,
+ layer_tree_impl->max_texture_size());
+ }
+ RecordRenderSurfaceReasonsForTracing(property_trees,
+ output_render_surface_list);
+
+ // A root layer render_surface should always exist after
+ // CalculateDrawProperties.
+ DCHECK(property_trees->effect_tree.GetRenderSurface(
+ EffectTree::kContentsRootNodeId));
+
+ if (output_update_layer_list_for_testing)
+ *output_update_layer_list_for_testing = std::move(visible_layer_list);
}
} // namespace draw_property_utils