Commit 80d31ee1 authored by Xianzhu Wang's avatar Xianzhu Wang Committed by Commit Bot

[SPv2] Properly handle infinite cull rects through scroll translations

- Allow infinite cull rect to be properly clipped and expanded through
  scroll translation. This can prevent SPv2 performance regression when
  painting scrolling contents when some ancestor uses infinite cull
  rects. This achieves the similar results of SPv1 painting composited
  scrolling contents.

- Copy and adapt the interest rect tests from composited_layer_mapping_test.cc
  into paint_layer_painter_test.cc

- Add infinite cull rect unit tests

Bug: 792577
Change-Id: Ia784416557e10a3193cd677ad8d31101fd077bc6
Reviewed-on: https://chromium-review.googlesource.com/c/1347354Reviewed-by: default avatarChris Harrelson <chrishtr@chromium.org>
Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611271}
parent e5b4016f
......@@ -202,11 +202,9 @@ static bool ShouldRepaintSubsequence(
PaintLayer& paint_layer,
const PaintLayerPaintingInfo& painting_info,
ShouldRespectOverflowClipType respect_overflow_clip) {
bool needs_repaint = false;
// Repaint subsequence if the layer is marked for needing repaint.
if (paint_layer.NeedsRepaint())
needs_repaint = true;
return true;
// Repaint if previously the layer may be clipped by cull rect, and cull rect
// changes.
......@@ -216,12 +214,10 @@ static bool ShouldRepaintSubsequence(
// new and cached subsequences. Normally we can reuse the cached fully
// painted subsequence even if we would partially paint this time.
RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) &&
paint_layer.PreviousCullRect() != painting_info.cull_rect) {
needs_repaint = true;
}
paint_layer.SetPreviousCullRect(painting_info.cull_rect);
paint_layer.PreviousCullRect() != painting_info.cull_rect)
return true;
return needs_repaint;
return false;
}
static bool ShouldUseInfiniteCullRect(const GraphicsContext& context,
......@@ -259,30 +255,21 @@ void PaintLayerPainter::AdjustForPaintProperties(
PaintLayerFlags& paint_flags) {
const auto& first_fragment = paint_layer_.GetLayoutObject().FirstFragment();
bool is_using_infinite_cull_rect = painting_info.cull_rect.IsInfinite();
bool should_use_infinite_cull_rect =
ShouldUseInfiniteCullRect(context, paint_layer_, painting_info);
if (!is_using_infinite_cull_rect && should_use_infinite_cull_rect) {
if (should_use_infinite_cull_rect)
painting_info.cull_rect = CullRect::Infinite();
is_using_infinite_cull_rect = true;
}
if (painting_info.root_layer == &paint_layer_)
return;
const auto& first_root_fragment =
painting_info.root_layer->GetLayoutObject().FirstFragment();
bool transform_changed =
first_root_fragment.LocalBorderBoxProperties().Transform() !=
first_fragment.LocalBorderBoxProperties().Transform();
// Will use the current layer as the new root layer if the layer requires
// infinite dirty rect or has different transform space from the current
// root layer.
if (!should_use_infinite_cull_rect && !transform_changed)
return;
if (!should_use_infinite_cull_rect) {
const auto& first_root_fragment =
painting_info.root_layer->GetLayoutObject().FirstFragment();
if (first_root_fragment.LocalBorderBoxProperties().Transform() ==
first_fragment.LocalBorderBoxProperties().Transform())
return;
if (!is_using_infinite_cull_rect && transform_changed) {
// painting_info.cull_rect is currently in |painting_info.root_layer|'s
// pixel-snapped border box space. We need to adjust it into
// |paint_layer_|'s space. This handles the following cases:
......@@ -307,14 +294,16 @@ void PaintLayerPainter::AdjustForPaintProperties(
// Convert cull_rect from the layer's transform space to the layer's local
// space.
cull_rect.MoveBy(-RoundedIntPoint(first_fragment.PaintOffset()));
} else {
} else if (!painting_info.cull_rect.IsInfinite()) {
auto rect = painting_info.cull_rect.Rect();
first_root_fragment.MapRectToFragment(first_fragment, rect);
painting_info.cull_rect = CullRect(rect);
}
}
// Make the current layer the new root layer.
// We reach here if the layer requires infinite cull rect or has different
// transform space from the current root layer. Use the current layer as
// the new root layer.
painting_info.root_layer = &paint_layer_;
// These flags no longer apply for the new root layer.
paint_flags &= ~kPaintLayerPaintingSkipRootBackground;
......@@ -645,8 +634,8 @@ PaintResult PaintLayerPainter::PaintLayerContents(
}
}
if (subsequence_recorder)
paint_layer_.SetPreviousPaintResult(result);
paint_layer_.SetPreviousPaintResult(result);
paint_layer_.SetPreviousCullRect(local_painting_info.cull_rect);
return result;
}
......
......@@ -60,7 +60,6 @@ class CORE_EXPORT PaintLayerPainter {
private:
friend class PaintLayerPainterTest;
friend class PaintLayerPainterTestSPv2;
PaintResult PaintChildren(unsigned children_to_visit,
GraphicsContext&,
......
......@@ -47,9 +47,6 @@ void CullRect::Move(const IntSize& offset) {
CullRect::ApplyTransformResult CullRect::ApplyTransformInternal(
const TransformPaintPropertyNode* transform) {
if (IsInfinite())
return kNotExpanded;
if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
if (const auto* scroll = transform->ScrollNode()) {
rect_.Intersect(scroll->ContainerRect());
......@@ -59,8 +56,6 @@ CullRect::ApplyTransformResult CullRect::ApplyTransformInternal(
// Expand the cull rect for scrolling contents in case of composited
// scrolling.
// TODO(wangxianzhu): the expansion distance needs to be scaled to
// screen pixels.
// TODO(wangxianzhu): options for non-composited-scrolling contents:
// 1. to use non-composted-scrolling heuristics to avoid expansion;
// 2. to reduce the 4000px distance, no matter if the contents with be
......@@ -77,37 +72,42 @@ CullRect::ApplyTransformResult CullRect::ApplyTransformInternal(
}
}
rect_ = transform->Matrix().Inverse().MapRect(rect_);
if (!IsInfinite())
rect_ = transform->Matrix().Inverse().MapRect(rect_);
return kNotExpanded;
}
void CullRect::ApplyTransforms(const TransformPaintPropertyNode* from,
const TransformPaintPropertyNode* to,
void CullRect::ApplyTransforms(const TransformPaintPropertyNode* source,
const TransformPaintPropertyNode* destination,
const base::Optional<CullRect>& old_cull_rect) {
DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
Vector<const TransformPaintPropertyNode*> scroll_translations;
for (const auto* t = to; t != from; t = t->Parent()) {
for (const auto* t = destination; t != source; t = t->Parent()) {
if (!t) {
// |from| is not an ancestor of |to|. Simply map.
GeometryMapper::SourceToDestinationRect(from, to, rect_);
// |source| is not an ancestor of |destination|. Simply map.
GeometryMapper::SourceToDestinationRect(source, destination, rect_);
return;
}
if (t->ScrollNode())
scroll_translations.push_back(t);
}
const auto* last_transform = from;
const auto* last_transform = source;
ApplyTransformResult last_scroll_translation_result = kNotExpanded;
for (auto it = scroll_translations.rbegin(); it != scroll_translations.rend();
++it) {
const auto* scroll_translation = *it;
GeometryMapper::SourceToDestinationRect(
last_transform, scroll_translation->Parent(), rect_);
if (!IsInfinite()) {
GeometryMapper::SourceToDestinationRect(
last_transform, scroll_translation->Parent(), rect_);
}
last_scroll_translation_result = ApplyTransformInternal(scroll_translation);
last_transform = scroll_translation;
}
GeometryMapper::SourceToDestinationRect(last_transform, to, rect_);
if (!IsInfinite())
GeometryMapper::SourceToDestinationRect(last_transform, destination, rect_);
if (last_scroll_translation_result == kExpandedForPartialScrollingContents &&
old_cull_rect && !ChangedEnough(*old_cull_rect))
......
......@@ -57,6 +57,44 @@ TEST_F(CullRectTest, IntersectsTransformed) {
EXPECT_FALSE(cull_rect.Intersects(IntRect(52, 52, 1, 1)));
}
TEST_F(CullRectTest, Infinite) {
EXPECT_TRUE(CullRect::Infinite().IsInfinite());
EXPECT_TRUE(CullRect(LayoutRect::InfiniteIntRect()).IsInfinite());
EXPECT_FALSE(CullRect(IntRect(0, 0, 100, 100)).IsInfinite());
}
TEST_F(CullRectTest, Move) {
CullRect cull_rect(IntRect(0, 0, 50, 50));
cull_rect.Move(IntSize());
EXPECT_EQ(IntRect(0, 0, 50, 50), cull_rect.Rect());
cull_rect.Move(IntSize(10, 20));
EXPECT_EQ(IntRect(10, 20, 50, 50), cull_rect.Rect());
}
TEST_F(CullRectTest, MoveInfinite) {
CullRect cull_rect = CullRect::Infinite();
cull_rect.Move(IntSize());
EXPECT_TRUE(cull_rect.IsInfinite());
cull_rect.Move(IntSize(10, 20));
EXPECT_TRUE(cull_rect.IsInfinite());
}
TEST_F(CullRectTest, MoveBy) {
CullRect cull_rect(IntRect(0, 0, 50, 50));
cull_rect.MoveBy(IntPoint());
EXPECT_EQ(IntRect(0, 0, 50, 50), cull_rect.Rect());
cull_rect.MoveBy(IntPoint(10, 20));
EXPECT_EQ(IntRect(10, 20, 50, 50), cull_rect.Rect());
}
TEST_F(CullRectTest, MoveByInfinite) {
CullRect cull_rect = CullRect::Infinite();
cull_rect.MoveBy(IntPoint());
EXPECT_TRUE(cull_rect.IsInfinite());
cull_rect.MoveBy(IntPoint(10, 20));
EXPECT_TRUE(cull_rect.IsInfinite());
}
TEST_F(CullRectTest, ApplyTransform) {
CullRect cull_rect(IntRect(1, 1, 50, 50));
auto transform =
......@@ -66,6 +104,15 @@ TEST_F(CullRectTest, ApplyTransform) {
EXPECT_EQ(IntRect(0, 0, 50, 50), cull_rect.Rect());
}
TEST_F(CullRectTest, ApplyTransformInfinite) {
CullRect cull_rect = CullRect::Infinite();
auto transform =
CreateTransform(t0(), TransformationMatrix().Translate(1, 1));
EXPECT_EQ(kNotExpanded, ApplyTransform(cull_rect, transform.get()));
EXPECT_TRUE(cull_rect.IsInfinite());
}
TEST_F(CullRectTest, ApplyScrollTranslationPartialScrollingContents) {
ScopedSlimmingPaintV2ForTest spv2(true);
......@@ -85,6 +132,13 @@ TEST_F(CullRectTest, ApplyScrollTranslationPartialScrollingContents) {
// Inverse transformed: (3020, 5010, 30, 50)
// Expanded: (-980, 1010, 8030, 8050)
EXPECT_EQ(IntRect(-980, 1010, 8030, 8050), cull_rect.Rect());
cull_rect = CullRect::Infinite();
EXPECT_EQ(kExpandedForPartialScrollingContents,
ApplyTransform(cull_rect, scroll_translation.get()));
// This result differs from the above result in height (8040 vs 8030)
// because it's not clipped by the infinite input cull rect.
EXPECT_EQ(IntRect(-980, 1010, 8040, 8050), cull_rect.Rect());
}
TEST_F(CullRectTest, ApplyScrollTranslationNoIntersectionWithContainerRect) {
......@@ -120,6 +174,13 @@ TEST_F(CullRectTest, ApplyScrollTranslationWholeScrollingContents) {
// Inverse transformed: (30, 25, 30, 50)
// Expanded: (-3970, -3975, 8030, 8050)
EXPECT_EQ(IntRect(-3970, -3975, 8030, 8050), cull_rect.Rect());
cull_rect = CullRect::Infinite();
EXPECT_EQ(kExpandedForWholeScrollingContents,
ApplyTransform(cull_rect, scroll_translation.get()));
// This result differs from the above result in height (8040 vs 8030)
// because it's not clipped by the infinite input cull rect.
EXPECT_EQ(IntRect(-3970, -3975, 8040, 8050), cull_rect.Rect());
}
TEST_F(CullRectTest, ChangedEnoughEmpty) {
......@@ -167,6 +228,10 @@ TEST_F(CullRectTest, ApplyTransformsSameTransform) {
// Should ignore old_cull_rect.
cull_rect2.ApplyTransforms(transform.get(), transform.get(), old_cull_rect);
EXPECT_EQ(cull_rect1, cull_rect2);
CullRect infinite = CullRect::Infinite();
infinite.ApplyTransforms(transform.get(), transform.get(), base::nullopt);
EXPECT_TRUE(infinite.IsInfinite());
}
TEST_F(CullRectTest, ApplyTransformsWithoutScroll) {
......@@ -188,6 +253,10 @@ TEST_F(CullRectTest, ApplyTransformsWithoutScroll) {
// Should ignore old_cull_rect.
cull_rect3.ApplyTransforms(&t0(), t2.get(), old_cull_rect);
EXPECT_EQ(cull_rect2, cull_rect3);
CullRect infinite = CullRect::Infinite();
infinite.ApplyTransforms(&t0(), t2.get(), base::nullopt);
EXPECT_TRUE(infinite.IsInfinite());
}
TEST_F(CullRectTest, ApplyTransformsSingleScrollWholeScrollingContents) {
......@@ -212,6 +281,12 @@ TEST_F(CullRectTest, ApplyTransformsSingleScrollWholeScrollingContents) {
// Should ignore old_cull_rect.
cull_rect2.ApplyTransforms(t1.get(), scroll_translation.get(), old_cull_rect);
EXPECT_EQ(cull_rect1, cull_rect2);
CullRect cull_rect3 = CullRect::Infinite();
cull_rect3.ApplyTransforms(t1.get(), scroll_translation.get(), base::nullopt);
// This result differs from the first result in height (8040 vs 8030)
// because it's not clipped by the infinite input cull rect.
EXPECT_EQ(IntRect(-3970, -3975, 8040, 8050), cull_rect3.Rect());
}
TEST_F(CullRectTest, ApplyTransformsSingleScrollPartialScrollingContents) {
......@@ -242,6 +317,12 @@ TEST_F(CullRectTest, ApplyTransformsSingleScrollPartialScrollingContents) {
// Use the new cull rect if it changed enough.
cull_rect3.ApplyTransforms(t1.get(), scroll_translation.get(), old_cull_rect);
EXPECT_EQ(cull_rect1, cull_rect3);
CullRect cull_rect4 = CullRect::Infinite();
cull_rect4.ApplyTransforms(t1.get(), scroll_translation.get(), base::nullopt);
// This result differs from the first result in height (8040 vs 8030)
// because it's not clipped by the infinite input cull rect.
EXPECT_EQ(IntRect(-980, 1010, 8040, 8050), cull_rect4.Rect());
}
TEST_F(CullRectTest, ApplyTransformsEscapingScroll) {
......
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