Commit 17957e83 authored by Vladimir Levin's avatar Vladimir Levin Committed by Commit Bot

Add code to ignore parent alias clips in PaintChunksToCcLayer conversion

This patch adds the ability to create parent alias clips, with the code
to skip those when generating display item lists. Also adds tests.

R=trchen@chromium.org, chrishtr@chromium.org

Bug: 870521
Cq-Include-Trybots: luci.chromium.try:linux_layout_tests_slimming_paint_v2;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: Ia60e89a7c74bcda785c8b8cce971eda48d2e0fd6
Reviewed-on: https://chromium-review.googlesource.com/1208717
Commit-Queue: vmpstr <vmpstr@chromium.org>
Reviewed-by: default avatarTien-Ren Chen <trchen@chromium.org>
Reviewed-by: default avatarChris Harrelson <chrishtr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#589268}
parent 978740fb
...@@ -29,8 +29,8 @@ class ConversionContext { ...@@ -29,8 +29,8 @@ class ConversionContext {
cc::DisplayItemList& cc_list) cc::DisplayItemList& cc_list)
: layer_state_(layer_state), : layer_state_(layer_state),
layer_offset_(layer_offset), layer_offset_(layer_offset),
current_transform_(layer_state.Transform()), current_transform_(layer_state.Transform()->Unalias()),
current_clip_(layer_state.Clip()), current_clip_(layer_state.Clip()->Unalias()),
current_effect_(layer_state.Effect()), current_effect_(layer_state.Effect()),
chunk_to_layer_mapper_(layer_state_, chunk_to_layer_mapper_(layer_state_,
layer_offset_, layer_offset_,
...@@ -311,12 +311,13 @@ static bool CombineClip(const ClipPaintPropertyNode* clip, ...@@ -311,12 +311,13 @@ static bool CombineClip(const ClipPaintPropertyNode* clip,
} }
void ConversionContext::SwitchToClip(const ClipPaintPropertyNode* target_clip) { void ConversionContext::SwitchToClip(const ClipPaintPropertyNode* target_clip) {
target_clip = target_clip->Unalias();
if (target_clip == current_clip_) if (target_clip == current_clip_)
return; return;
// Step 1: Exit all clips until the lowest common ancestor is found. // Step 1: Exit all clips until the lowest common ancestor is found.
const ClipPaintPropertyNode* lca_clip = const ClipPaintPropertyNode* lca_clip =
&LowestCommonAncestor(*target_clip, *current_clip_); LowestCommonAncestor(*target_clip, *current_clip_).Unalias();
while (current_clip_ != lca_clip) { while (current_clip_ != lca_clip) {
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
DCHECK(state_stack_.size() && state_stack_.back().type == StateEntry::kClip) DCHECK(state_stack_.size() && state_stack_.back().type == StateEntry::kClip)
...@@ -327,7 +328,7 @@ void ConversionContext::SwitchToClip(const ClipPaintPropertyNode* target_clip) { ...@@ -327,7 +328,7 @@ void ConversionContext::SwitchToClip(const ClipPaintPropertyNode* target_clip) {
#endif #endif
if (!state_stack_.size() || state_stack_.back().type != StateEntry::kClip) if (!state_stack_.size() || state_stack_.back().type != StateEntry::kClip)
break; break;
current_clip_ = current_clip_->Parent(); current_clip_ = current_clip_->Parent()->Unalias();
StateEntry& previous_state = state_stack_.back(); StateEntry& previous_state = state_stack_.back();
if (current_clip_ == lca_clip) { if (current_clip_ == lca_clip) {
// |lca_clip| is an intermediate clip in a series of combined clips. // |lca_clip| is an intermediate clip in a series of combined clips.
...@@ -345,7 +346,7 @@ void ConversionContext::SwitchToClip(const ClipPaintPropertyNode* target_clip) { ...@@ -345,7 +346,7 @@ void ConversionContext::SwitchToClip(const ClipPaintPropertyNode* target_clip) {
// At this point the current clip must be an ancestor of the target. // At this point the current clip must be an ancestor of the target.
Vector<const ClipPaintPropertyNode*, 1u> pending_clips; Vector<const ClipPaintPropertyNode*, 1u> pending_clips;
for (const ClipPaintPropertyNode* clip = target_clip; clip != current_clip_; for (const ClipPaintPropertyNode* clip = target_clip; clip != current_clip_;
clip = clip->Parent()) { clip = clip->Parent()->Unalias()) {
// This should never happen unless the DCHECK in step 1 failed. // This should never happen unless the DCHECK in step 1 failed.
if (!clip) if (!clip)
break; break;
...@@ -377,6 +378,7 @@ void ConversionContext::SwitchToClip(const ClipPaintPropertyNode* target_clip) { ...@@ -377,6 +378,7 @@ void ConversionContext::SwitchToClip(const ClipPaintPropertyNode* target_clip) {
void ConversionContext::StartClip( void ConversionContext::StartClip(
const FloatRoundedRect& combined_clip_rect, const FloatRoundedRect& combined_clip_rect,
const ClipPaintPropertyNode* lowest_combined_clip_node) { const ClipPaintPropertyNode* lowest_combined_clip_node) {
DCHECK_EQ(lowest_combined_clip_node, lowest_combined_clip_node->Unalias());
auto* local_transform = auto* local_transform =
lowest_combined_clip_node->LocalTransformSpace()->Unalias(); lowest_combined_clip_node->LocalTransformSpace()->Unalias();
if (local_transform != current_transform_) if (local_transform != current_transform_)
......
...@@ -1104,5 +1104,87 @@ TEST_F(PaintChunksToCcLayerTest, EffectUndoesNoopTransform) { ...@@ -1104,5 +1104,87 @@ TEST_F(PaintChunksToCcLayerTest, EffectUndoesNoopTransform) {
cc::PaintOpType::Restore // end t1 cc::PaintOpType::Restore // end t1
})); }));
} }
TEST_F(PaintChunksToCcLayerTest, NoopClipDoesNotEmitItems) {
FloatRoundedRect clip_rect(0.f, 0.f, 1.f, 1.f);
auto c1 = CreateClip(c0(), &t0(), clip_rect);
auto noop_c2 = ClipPaintPropertyNode::CreateAlias(*c1);
auto noop_c3 = ClipPaintPropertyNode::CreateAlias(*noop_c2);
auto c4 = CreateClip(*noop_c3, &t0(), clip_rect);
TestChunks chunks;
chunks.AddChunk(t0(), c0(), e0());
chunks.AddChunk(t0(), *c1, e0());
chunks.AddChunk(t0(), *noop_c2, e0());
chunks.AddChunk(t0(), *noop_c3, e0());
chunks.AddChunk(t0(), *c4, e0());
chunks.AddChunk(t0(), *noop_c2, e0());
chunks.AddChunk(t0(), *c1, e0());
auto output =
PaintChunksToCcLayer::Convert(
chunks.chunks, PropertyTreeState::Root(), gfx::Vector2dF(),
chunks.items, cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer)
->ReleaseAsRecord();
EXPECT_THAT(*output,
PaintRecordMatcher::Make({
cc::PaintOpType::DrawRecord, // c0
cc::PaintOpType::Save, cc::PaintOpType::ClipRect, // c1
cc::PaintOpType::DrawRecord, // draw with c1
cc::PaintOpType::DrawRecord, // draw with noop_c2
cc::PaintOpType::DrawRecord, // draw_with noop_c3
cc::PaintOpType::Save, cc::PaintOpType::ClipRect, // c4
cc::PaintOpType::DrawRecord, // draw with c4
cc::PaintOpType::Restore, // end c4
cc::PaintOpType::DrawRecord, // draw with noop_c2
cc::PaintOpType::DrawRecord, // draw with c1
cc::PaintOpType::Restore // end noop_c2 (or c1)
}));
}
TEST_F(PaintChunksToCcLayerTest, EffectUndoesNoopClip) {
FloatRoundedRect clip_rect(0.f, 0.f, 1.f, 1.f);
auto c1 = CreateClip(c0(), &t0(), clip_rect);
auto noop_c2 = ClipPaintPropertyNode::CreateAlias(*c1);
auto e1 = CreateOpacityEffect(e0(), &t0(), c1.get(), 0.5);
TestChunks chunks;
chunks.AddChunk(t0(), *noop_c2, e0());
chunks.AddChunk(t0(), *noop_c2, *e1);
auto output =
PaintChunksToCcLayer::Convert(
chunks.chunks, PropertyTreeState::Root(), gfx::Vector2dF(),
chunks.items, cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer)
->ReleaseAsRecord();
EXPECT_THAT(*output,
PaintRecordMatcher::Make({
cc::PaintOpType::Save, cc::PaintOpType::ClipRect, // noop_c2
cc::PaintOpType::DrawRecord, // draw with noop_c2
cc::PaintOpType::SaveLayerAlpha, // e1
cc::PaintOpType::DrawRecord, // draw with e1
cc::PaintOpType::Restore, // end e1
cc::PaintOpType::Restore // end noop_c2
}));
}
TEST_F(PaintChunksToCcLayerTest, StartWithAliasClip) {
auto noop_c1 = ClipPaintPropertyNode::CreateAlias(c0());
TestChunks chunks;
chunks.AddChunk(t0(), *noop_c1, e0());
auto output =
PaintChunksToCcLayer::Convert(
chunks.chunks, PropertyTreeState(&t0(), noop_c1.get(), &e0()),
gfx::Vector2dF(), chunks.items,
cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer)
->ReleaseAsRecord();
EXPECT_THAT(*output, PaintRecordMatcher::Make({cc::PaintOpType::DrawRecord}));
}
} // namespace } // namespace
} // namespace blink } // namespace blink
...@@ -10,11 +10,12 @@ ...@@ -10,11 +10,12 @@
namespace blink { namespace blink {
const ClipPaintPropertyNode& ClipPaintPropertyNode::Root() { const ClipPaintPropertyNode& ClipPaintPropertyNode::Root() {
DEFINE_STATIC_REF( DEFINE_STATIC_REF(ClipPaintPropertyNode, root,
ClipPaintPropertyNode, root, base::AdoptRef(new ClipPaintPropertyNode(
base::AdoptRef(new ClipPaintPropertyNode( nullptr,
nullptr, State{&TransformPaintPropertyNode::Root(), State{&TransformPaintPropertyNode::Root(),
FloatRoundedRect(LayoutRect::InfiniteIntRect())}))); FloatRoundedRect(LayoutRect::InfiniteIntRect())},
true /* is_parent_alias */)));
return *root; return *root;
} }
......
...@@ -59,7 +59,15 @@ class PLATFORM_EXPORT ClipPaintPropertyNode ...@@ -59,7 +59,15 @@ class PLATFORM_EXPORT ClipPaintPropertyNode
static scoped_refptr<ClipPaintPropertyNode> Create( static scoped_refptr<ClipPaintPropertyNode> Create(
const ClipPaintPropertyNode& parent, const ClipPaintPropertyNode& parent,
State&& state) { State&& state) {
return base::AdoptRef(new ClipPaintPropertyNode(&parent, std::move(state))); return base::AdoptRef(new ClipPaintPropertyNode(
&parent, std::move(state), false /* is_parent_alias */));
}
static scoped_refptr<ClipPaintPropertyNode> CreateAlias(
const ClipPaintPropertyNode& parent) {
return base::AdoptRef(new ClipPaintPropertyNode(
&parent,
State{nullptr, FloatRoundedRect(LayoutRect::InfiniteIntRect())},
true /* is_parent_alias */));
} }
bool Update(const ClipPaintPropertyNode& parent, State&& state) { bool Update(const ClipPaintPropertyNode& parent, State&& state) {
...@@ -67,6 +75,7 @@ class PLATFORM_EXPORT ClipPaintPropertyNode ...@@ -67,6 +75,7 @@ class PLATFORM_EXPORT ClipPaintPropertyNode
if (state == state_) if (state == state_)
return parent_changed; return parent_changed;
DCHECK(!IsParentAlias()) << "Changed the state of an alias node.";
SetChanged(); SetChanged();
state_ = std::move(state); state_ = std::move(state);
return true; return true;
...@@ -86,8 +95,20 @@ class PLATFORM_EXPORT ClipPaintPropertyNode ...@@ -86,8 +95,20 @@ class PLATFORM_EXPORT ClipPaintPropertyNode
return parent == Parent() && state_.EqualIgnoringHitTestRects(state); return parent == Parent() && state_.EqualIgnoringHitTestRects(state);
} }
// Returns the local transform space of this node. Note that the function
// first unaliases the node, meaning that it walks up the parent chain until
// it finds a concrete node (not a parent alias) or root. The reason for this
// is that a parent alias conceptually doesn't have a local transform space,
// so we just want to return a convenient space which would eliminate extra
// work. The parent's transform node qualifies as that. Also note, although
// this is a walk up the parent chain, the only case it would be heavy is if
// there is a long chain of nested aliases, which is unlikely.
const TransformPaintPropertyNode* LocalTransformSpace() const { const TransformPaintPropertyNode* LocalTransformSpace() const {
return state_.local_transform_space.get(); // TODO(vmpstr): If this becomes a performance problem, then we should audit
// the call sites and explicitly unalias clip nodes everywhere. If this is
// done, then here we can add a DCHECK that we never invoke this function on
// a parent alias.
return Unalias()->state_.local_transform_space.get();
} }
const FloatRoundedRect& ClipRect() const { return state_.clip_rect; } const FloatRoundedRect& ClipRect() const { return state_.clip_rect; }
const FloatRoundedRect& ClipRectExcludingOverlayScrollbars() const { const FloatRoundedRect& ClipRectExcludingOverlayScrollbars() const {
...@@ -106,13 +127,15 @@ class PLATFORM_EXPORT ClipPaintPropertyNode ...@@ -106,13 +127,15 @@ class PLATFORM_EXPORT ClipPaintPropertyNode
// The clone function is used by FindPropertiesNeedingUpdate.h for recording // The clone function is used by FindPropertiesNeedingUpdate.h for recording
// a clip node before it has been updated, to later detect changes. // a clip node before it has been updated, to later detect changes.
scoped_refptr<ClipPaintPropertyNode> Clone() const { scoped_refptr<ClipPaintPropertyNode> Clone() const {
return base::AdoptRef(new ClipPaintPropertyNode(Parent(), State(state_))); return base::AdoptRef(
new ClipPaintPropertyNode(Parent(), State(state_), IsParentAlias()));
} }
// The equality operator is used by FindPropertiesNeedingUpdate.h for checking // The equality operator is used by FindPropertiesNeedingUpdate.h for checking
// if a clip node has changed. // if a clip node has changed.
bool operator==(const ClipPaintPropertyNode& o) const { bool operator==(const ClipPaintPropertyNode& o) const {
return Parent() == o.Parent() && state_ == o.state_; return Parent() == o.Parent() && state_ == o.state_ &&
IsParentAlias() == o.IsParentAlias();
} }
#endif #endif
...@@ -122,8 +145,10 @@ class PLATFORM_EXPORT ClipPaintPropertyNode ...@@ -122,8 +145,10 @@ class PLATFORM_EXPORT ClipPaintPropertyNode
size_t CacheMemoryUsageInBytes() const; size_t CacheMemoryUsageInBytes() const;
private: private:
ClipPaintPropertyNode(const ClipPaintPropertyNode* parent, State&& state) ClipPaintPropertyNode(const ClipPaintPropertyNode* parent,
: PaintPropertyNode(parent), state_(std::move(state)) {} State&& state,
bool is_parent_alias)
: PaintPropertyNode(parent, is_parent_alias), state_(std::move(state)) {}
// For access to GetClipCache(); // For access to GetClipCache();
friend class GeometryMapper; friend class GeometryMapper;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment