1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/trees/layer_tree_host.h"
8 #include "base/callback.h"
9 #include "base/location.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "base/time/time.h"
12 #include "cc/test/fake_content_layer.h"
13 #include "cc/test/fake_content_layer_client.h"
14 #include "cc/test/fake_painted_scrollbar_layer.h"
15 #include "cc/test/fake_picture_layer.h"
16 #include "cc/test/layer_tree_test.h"
17 #include "cc/trees/damage_tracker.h"
18 #include "cc/trees/layer_tree_impl.h"
23 // These tests deal with damage tracking.
24 class LayerTreeHostDamageTest
: public LayerTreeTest
{};
26 // LayerTreeHost::SetNeedsRedraw should damage the whole viewport.
27 class LayerTreeHostDamageTestSetNeedsRedraw
28 : public LayerTreeHostDamageTest
{
29 void SetupTree() override
{
31 scoped_refptr
<FakeContentLayer
> root
=
32 FakeContentLayer::Create(layer_settings(), &client_
);
33 root
->SetBounds(gfx::Size(10, 10));
35 layer_tree_host()->SetRootLayer(root
);
36 LayerTreeHostDamageTest::SetupTree();
39 void BeginTest() override
{
41 PostSetNeedsCommitToMainThread();
44 void DidCommitAndDrawFrame() override
{
45 switch (layer_tree_host()->source_frame_number()) {
47 layer_tree_host()->SetNeedsRedraw();
52 DrawResult
PrepareToDrawOnThread(LayerTreeHostImpl
* impl
,
53 LayerTreeHostImpl::FrameData
* frame_data
,
54 DrawResult draw_result
) override
{
55 EXPECT_EQ(DRAW_SUCCESS
, draw_result
);
57 RenderSurfaceImpl
* root_surface
=
58 impl
->active_tree()->root_layer()->render_surface();
59 gfx::RectF root_damage
=
60 root_surface
->damage_tracker()->current_damage_rect();
62 switch (draw_count_
) {
64 // The first frame has full damage.
65 EXPECT_EQ(gfx::RectF(10.f
, 10.f
).ToString(), root_damage
.ToString());
68 // The second frame has full damage.
69 EXPECT_EQ(gfx::RectF(10.f
, 10.f
).ToString(), root_damage
.ToString());
80 void AfterTest() override
{}
83 FakeContentLayerClient client_
;
86 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestSetNeedsRedraw
);
88 // LayerTreeHost::SetViewportSize should damage the whole viewport.
89 class LayerTreeHostDamageTestSetViewportSize
90 : public LayerTreeHostDamageTest
{
91 void SetupTree() override
{
93 scoped_refptr
<FakeContentLayer
> root
=
94 FakeContentLayer::Create(layer_settings(), &client_
);
95 root
->SetBounds(gfx::Size(10, 10));
97 layer_tree_host()->SetRootLayer(root
);
98 LayerTreeHostDamageTest::SetupTree();
101 void BeginTest() override
{
103 PostSetNeedsCommitToMainThread();
106 void DidCommitAndDrawFrame() override
{
107 switch (layer_tree_host()->source_frame_number()) {
109 layer_tree_host()->SetViewportSize(gfx::Size(15, 15));
114 DrawResult
PrepareToDrawOnThread(LayerTreeHostImpl
* impl
,
115 LayerTreeHostImpl::FrameData
* frame_data
,
116 DrawResult draw_result
) override
{
117 EXPECT_EQ(DRAW_SUCCESS
, draw_result
);
119 RenderSurfaceImpl
* root_surface
=
120 impl
->active_tree()->root_layer()->render_surface();
121 gfx::RectF root_damage
=
122 root_surface
->damage_tracker()->current_damage_rect();
124 switch (draw_count_
) {
126 // The first frame has full damage.
127 EXPECT_EQ(gfx::RectF(10.f
, 10.f
).ToString(), root_damage
.ToString());
130 // The second frame has full damage.
131 EXPECT_EQ(gfx::RectF(15.f
, 15.f
).ToString(), root_damage
.ToString());
142 void AfterTest() override
{}
145 FakeContentLayerClient client_
;
148 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestSetViewportSize
);
150 class LayerTreeHostDamageTestNoDamageDoesNotSwap
151 : public LayerTreeHostDamageTest
{
152 void BeginTest() override
{
153 expect_swap_and_succeed_
= 0;
155 did_swap_and_succeed_
= 0;
156 PostSetNeedsCommitToMainThread();
159 void SetupTree() override
{
160 scoped_refptr
<FakeContentLayer
> root
=
161 FakeContentLayer::Create(layer_settings(), &client_
);
162 root
->SetBounds(gfx::Size(10, 10));
164 // Most of the layer isn't visible.
165 content_
= FakeContentLayer::Create(layer_settings(), &client_
);
166 content_
->SetBounds(gfx::Size(2000, 100));
167 root
->AddChild(content_
);
169 layer_tree_host()->SetRootLayer(root
);
170 LayerTreeHostDamageTest::SetupTree();
173 DrawResult
PrepareToDrawOnThread(LayerTreeHostImpl
* host_impl
,
174 LayerTreeHostImpl::FrameData
* frame_data
,
175 DrawResult draw_result
) override
{
176 EXPECT_EQ(DRAW_SUCCESS
, draw_result
);
178 int source_frame
= host_impl
->active_tree()->source_frame_number();
179 switch (source_frame
) {
181 // The first frame has damage, so we should draw and swap.
182 ++expect_swap_and_succeed_
;
185 // The second frame has no damage, so we should not draw and swap.
188 // The third frame has damage again, so we should draw and swap.
189 ++expect_swap_and_succeed_
;
192 // The fourth frame has no visible damage, so we should not draw and
200 void SwapBuffersOnThread(LayerTreeHostImpl
* host_impl
, bool result
) override
{
203 ++did_swap_and_succeed_
;
204 EXPECT_EQ(expect_swap_and_succeed_
, did_swap_and_succeed_
);
207 void DidCommit() override
{
208 int next_frame
= layer_tree_host()->source_frame_number();
209 switch (next_frame
) {
211 layer_tree_host()->SetNeedsCommit();
214 // Cause visible damage.
215 content_
->SetNeedsDisplayRect(
216 gfx::Rect(layer_tree_host()->device_viewport_size()));
219 // Cause non-visible damage.
220 content_
->SetNeedsDisplayRect(gfx::Rect(1990, 1990, 10, 10));
221 layer_tree_host()->SetNeedsCommit();
226 void AfterTest() override
{
227 EXPECT_EQ(4, did_swaps_
);
228 EXPECT_EQ(2, expect_swap_and_succeed_
);
229 EXPECT_EQ(expect_swap_and_succeed_
, did_swap_and_succeed_
);
232 FakeContentLayerClient client_
;
233 scoped_refptr
<FakeContentLayer
> content_
;
234 int expect_swap_and_succeed_
;
236 int did_swap_and_succeed_
;
239 SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
240 LayerTreeHostDamageTestNoDamageDoesNotSwap
);
242 class LayerTreeHostDamageTestForcedFullDamage
: public LayerTreeHostDamageTest
{
243 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
245 void SetupTree() override
{
246 root_
= FakeContentLayer::Create(layer_settings(), &client_
);
247 child_
= FakeContentLayer::Create(layer_settings(), &client_
);
249 root_
->SetBounds(gfx::Size(500, 500));
250 child_
->SetPosition(gfx::Point(100, 100));
251 child_
->SetBounds(gfx::Size(30, 30));
253 root_
->AddChild(child_
);
254 layer_tree_host()->SetRootLayer(root_
);
255 LayerTreeHostDamageTest::SetupTree();
258 DrawResult
PrepareToDrawOnThread(LayerTreeHostImpl
* host_impl
,
259 LayerTreeHostImpl::FrameData
* frame_data
,
260 DrawResult draw_result
) override
{
261 EXPECT_EQ(DRAW_SUCCESS
, draw_result
);
263 RenderSurfaceImpl
* root_surface
=
264 host_impl
->active_tree()->root_layer()->render_surface();
265 gfx::RectF root_damage
=
266 root_surface
->damage_tracker()->current_damage_rect();
267 root_damage
.Intersect(root_surface
->content_rect());
269 int source_frame
= host_impl
->active_tree()->source_frame_number();
270 switch (source_frame
) {
272 // The first frame draws and clears any damage.
273 EXPECT_EQ(gfx::RectF(root_surface
->content_rect()).ToString(),
274 root_damage
.ToString());
275 EXPECT_FALSE(frame_data
->has_no_damage
);
278 // If we get a frame without damage then we don't draw.
279 EXPECT_EQ(gfx::RectF().ToString(), root_damage
.ToString());
280 EXPECT_TRUE(frame_data
->has_no_damage
);
282 // Then we set full damage for the next frame.
283 host_impl
->SetFullRootLayerDamage();
286 // The whole frame should be damaged as requested.
287 EXPECT_EQ(gfx::RectF(root_surface
->content_rect()).ToString(),
288 root_damage
.ToString());
289 EXPECT_FALSE(frame_data
->has_no_damage
);
291 // Just a part of the next frame should be damaged.
292 child_damage_rect_
= gfx::Rect(10, 11, 12, 13);
295 // The update rect in the child should be damaged and the damaged area
296 // should match the invalidation.
297 EXPECT_EQ(gfx::RectF(100+10, 100+11, 12, 13).ToString(),
298 root_damage
.ToString());
300 // TODO(danakj): Remove this when impl side painting is always on.
301 if (delegating_renderer() ||
302 host_impl
->settings().impl_side_painting
) {
303 // When using a delegating renderer, or using impl side painting, the
304 // entire child is considered damaged as we need to replace its
305 // resources with newly created ones. The damaged area is kept as it
306 // is, but entire child is painted.
308 // The paint rect should match the layer bounds.
309 gfx::RectF paint_rect
= child_
->LastPaintRect();
310 paint_rect
.set_origin(child_
->position());
311 EXPECT_EQ(gfx::RectF(100, 100, 30, 30).ToString(),
312 paint_rect
.ToString());
314 EXPECT_FALSE(frame_data
->has_no_damage
);
316 // If we damage part of the frame, but also damage the full
317 // frame, then the whole frame should be damaged.
318 child_damage_rect_
= gfx::Rect(10, 11, 12, 13);
319 host_impl
->SetFullRootLayerDamage();
322 // The whole frame is damaged.
323 EXPECT_EQ(gfx::RectF(root_surface
->content_rect()).ToString(),
324 root_damage
.ToString());
325 EXPECT_FALSE(frame_data
->has_no_damage
);
333 void DidCommitAndDrawFrame() override
{
335 layer_tree_host()->SetNeedsCommit();
337 if (!child_damage_rect_
.IsEmpty()) {
338 child_
->SetNeedsDisplayRect(child_damage_rect_
);
339 child_damage_rect_
= gfx::Rect();
343 void AfterTest() override
{}
345 FakeContentLayerClient client_
;
346 scoped_refptr
<FakeContentLayer
> root_
;
347 scoped_refptr
<FakeContentLayer
> child_
;
348 gfx::Rect child_damage_rect_
;
351 SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(LayerTreeHostDamageTestForcedFullDamage
);
353 class LayerTreeHostScrollbarDamageTest
: public LayerTreeHostDamageTest
{
354 void SetupTree() override
{
355 scoped_refptr
<Layer
> root_layer
= Layer::Create(layer_settings());
356 root_layer
->SetBounds(gfx::Size(400, 400));
357 root_layer
->SetMasksToBounds(true);
358 layer_tree_host()->SetRootLayer(root_layer
);
360 scoped_refptr
<Layer
> scroll_clip_layer
= Layer::Create(layer_settings());
361 scoped_refptr
<Layer
> content_layer
=
362 FakeContentLayer::Create(layer_settings(), &client_
);
363 content_layer
->SetScrollClipLayerId(scroll_clip_layer
->id());
364 content_layer
->SetScrollOffset(gfx::ScrollOffset(10, 20));
365 content_layer
->SetBounds(gfx::Size(100, 200));
366 scroll_clip_layer
->SetBounds(
367 gfx::Size(content_layer
->bounds().width() - 30,
368 content_layer
->bounds().height() - 50));
369 scroll_clip_layer
->AddChild(content_layer
);
370 root_layer
->AddChild(scroll_clip_layer
);
372 scoped_refptr
<Layer
> scrollbar_layer
= FakePaintedScrollbarLayer::Create(
373 layer_settings(), false, true, content_layer
->id());
374 scrollbar_layer
->SetPosition(gfx::Point(300, 300));
375 scrollbar_layer
->SetBounds(gfx::Size(10, 100));
376 scrollbar_layer
->ToScrollbarLayer()->SetClipLayer(scroll_clip_layer
->id());
377 scrollbar_layer
->ToScrollbarLayer()->SetScrollLayer(content_layer
->id());
378 root_layer
->AddChild(scrollbar_layer
);
380 gfx::RectF
content_rect(content_layer
->position(),
381 content_layer
->bounds());
382 gfx::RectF
scrollbar_rect(scrollbar_layer
->position(),
383 scrollbar_layer
->bounds());
384 EXPECT_FALSE(content_rect
.Intersects(scrollbar_rect
));
386 LayerTreeHostDamageTest::SetupTree();
390 FakeContentLayerClient client_
;
393 class LayerTreeHostDamageTestScrollbarDoesDamage
394 : public LayerTreeHostScrollbarDamageTest
{
395 void BeginTest() override
{
397 PostSetNeedsCommitToMainThread();
400 DrawResult
PrepareToDrawOnThread(LayerTreeHostImpl
* host_impl
,
401 LayerTreeHostImpl::FrameData
* frame_data
,
402 DrawResult draw_result
) override
{
403 EXPECT_EQ(DRAW_SUCCESS
, draw_result
);
404 RenderSurfaceImpl
* root_surface
=
405 host_impl
->active_tree()->root_layer()->render_surface();
406 gfx::RectF root_damage
=
407 root_surface
->damage_tracker()->current_damage_rect();
408 root_damage
.Intersect(root_surface
->content_rect());
409 switch (did_swaps_
) {
411 // The first frame has damage, so we should draw and swap.
414 // The second frame should not damage the scrollbars.
415 EXPECT_FALSE(root_damage
.Intersects(gfx::Rect(300, 300, 10, 100)));
418 // The third frame should damage the scrollbars.
419 EXPECT_TRUE(root_damage
.Contains(gfx::Rect(300, 300, 10, 100)));
422 // The fourth frame should damage the scrollbars.
423 EXPECT_TRUE(root_damage
.Contains(gfx::Rect(300, 300, 10, 100)));
430 void SwapBuffersOnThread(LayerTreeHostImpl
* host_impl
, bool result
) override
{
433 LayerImpl
* root
= host_impl
->active_tree()->root_layer();
434 LayerImpl
* scroll_clip_layer
= root
->children()[0];
435 LayerImpl
* scroll_layer
= scroll_clip_layer
->children()[0];
436 switch (did_swaps_
) {
438 // Test that modifying the position of the content layer (not
439 // scrolling) won't damage the scrollbar.
440 scroll_layer
->SetPosition(gfx::Point(1, 1));
441 scroll_layer
->PushScrollOffsetFromMainThread(
442 scroll_layer
->BaseScrollOffset());
443 host_impl
->SetNeedsRedraw();
446 scroll_layer
->ScrollBy(gfx::Vector2dF(10.f
, 10.f
));
447 host_impl
->SetNeedsRedraw();
450 scroll_layer
->SetBounds(gfx::Size(root
->bounds().width() + 60,
451 root
->bounds().height() + 100));
452 host_impl
->SetNeedsRedraw();
457 void AfterTest() override
{ EXPECT_EQ(4, did_swaps_
); }
462 MULTI_THREAD_TEST_F(LayerTreeHostDamageTestScrollbarDoesDamage
);
464 class LayerTreeHostDamageTestScrollbarCommitDoesNoDamage
465 : public LayerTreeHostScrollbarDamageTest
{
466 void BeginTest() override
{
468 PostSetNeedsCommitToMainThread();
471 DrawResult
PrepareToDrawOnThread(LayerTreeHostImpl
* host_impl
,
472 LayerTreeHostImpl::FrameData
* frame_data
,
473 DrawResult draw_result
) override
{
474 EXPECT_EQ(DRAW_SUCCESS
, draw_result
);
475 RenderSurfaceImpl
* root_surface
=
476 host_impl
->active_tree()->root_layer()->render_surface();
477 gfx::RectF root_damage
=
478 root_surface
->damage_tracker()->current_damage_rect();
479 root_damage
.Intersect(root_surface
->content_rect());
480 int frame
= host_impl
->active_tree()->source_frame_number();
481 switch (did_swaps_
) {
483 // The first frame has damage, so we should draw and swap.
487 // The second frame has scrolled, so the scrollbar should be damaged.
489 EXPECT_TRUE(root_damage
.Contains(gfx::Rect(300, 300, 10, 100)));
492 // The third frame (after the commit) has no changes, so it shouldn't.
494 EXPECT_FALSE(root_damage
.Intersects(gfx::Rect(300, 300, 10, 100)));
503 void SwapBuffersOnThread(LayerTreeHostImpl
* host_impl
, bool result
) override
{
506 LayerImpl
* root
= host_impl
->active_tree()->root_layer();
507 LayerImpl
* scroll_clip_layer
= root
->children()[0];
508 LayerImpl
* scroll_layer
= scroll_clip_layer
->children()[0];
509 switch (did_swaps_
) {
511 // Scroll on the thread. This should damage the scrollbar for the
512 // next draw on the thread.
513 scroll_layer
->ScrollBy(gfx::Vector2dF(10.f
, 10.f
));
514 host_impl
->SetNeedsRedraw();
517 // Forcibly send the scroll to the main thread.
518 PostSetNeedsCommitToMainThread();
521 // First swap after second commit.
530 void AfterTest() override
{ EXPECT_EQ(3, did_swaps_
); }
535 MULTI_THREAD_TEST_F(LayerTreeHostDamageTestScrollbarCommitDoesNoDamage
);