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/time/time.h"
11 #include "cc/layers/solid_color_layer.h"
12 #include "cc/test/fake_content_layer_client.h"
13 #include "cc/test/fake_painted_scrollbar_layer.h"
14 #include "cc/test/fake_picture_layer.h"
15 #include "cc/test/layer_tree_test.h"
16 #include "cc/trees/damage_tracker.h"
17 #include "cc/trees/layer_tree_impl.h"
22 // These tests deal with damage tracking.
23 class LayerTreeHostDamageTest
: public LayerTreeTest
{};
25 // LayerTreeHost::SetNeedsRedraw should damage the whole viewport.
26 class LayerTreeHostDamageTestSetNeedsRedraw
27 : public LayerTreeHostDamageTest
{
28 void SetupTree() override
{
30 scoped_refptr
<FakePictureLayer
> root
=
31 FakePictureLayer::Create(layer_settings(), &client_
);
32 root
->SetBounds(gfx::Size(10, 10));
34 layer_tree_host()->SetRootLayer(root
);
35 LayerTreeHostDamageTest::SetupTree();
38 void BeginTest() override
{
40 PostSetNeedsCommitToMainThread();
43 void DidCommitAndDrawFrame() override
{
44 switch (layer_tree_host()->source_frame_number()) {
46 layer_tree_host()->SetNeedsRedraw();
51 DrawResult
PrepareToDrawOnThread(LayerTreeHostImpl
* impl
,
52 LayerTreeHostImpl::FrameData
* frame_data
,
53 DrawResult draw_result
) override
{
54 EXPECT_EQ(DRAW_SUCCESS
, draw_result
);
56 RenderSurfaceImpl
* root_surface
=
57 impl
->active_tree()->root_layer()->render_surface();
58 gfx::Rect root_damage
=
59 root_surface
->damage_tracker()->current_damage_rect();
61 switch (draw_count_
) {
63 // The first frame has full damage.
64 EXPECT_EQ(gfx::Rect(10, 10), root_damage
);
67 // The second frame has full damage.
68 EXPECT_EQ(gfx::Rect(10, 10), root_damage
);
79 void AfterTest() override
{}
82 FakeContentLayerClient client_
;
85 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestSetNeedsRedraw
);
87 // LayerTreeHost::SetViewportSize should damage the whole viewport.
88 class LayerTreeHostDamageTestSetViewportSize
89 : public LayerTreeHostDamageTest
{
90 void SetupTree() override
{
92 scoped_refptr
<FakePictureLayer
> root
=
93 FakePictureLayer::Create(layer_settings(), &client_
);
94 root
->SetBounds(gfx::Size(10, 10));
96 layer_tree_host()->SetRootLayer(root
);
97 LayerTreeHostDamageTest::SetupTree();
100 void BeginTest() override
{
102 PostSetNeedsCommitToMainThread();
105 void DidCommitAndDrawFrame() override
{
106 switch (layer_tree_host()->source_frame_number()) {
108 layer_tree_host()->SetViewportSize(gfx::Size(15, 15));
113 DrawResult
PrepareToDrawOnThread(LayerTreeHostImpl
* impl
,
114 LayerTreeHostImpl::FrameData
* frame_data
,
115 DrawResult draw_result
) override
{
116 EXPECT_EQ(DRAW_SUCCESS
, draw_result
);
118 RenderSurfaceImpl
* root_surface
=
119 impl
->active_tree()->root_layer()->render_surface();
120 gfx::Rect root_damage
=
121 root_surface
->damage_tracker()->current_damage_rect();
123 switch (draw_count_
) {
125 // The first frame has full damage.
126 EXPECT_EQ(gfx::Rect(10, 10), root_damage
);
129 // The second frame has full damage.
130 EXPECT_EQ(gfx::Rect(15, 15), root_damage
);
141 void AfterTest() override
{}
144 FakeContentLayerClient client_
;
147 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestSetViewportSize
);
149 class LayerTreeHostDamageTestNoDamageDoesNotSwap
150 : public LayerTreeHostDamageTest
{
151 void BeginTest() override
{
152 expect_swap_and_succeed_
= 0;
154 did_swap_and_succeed_
= 0;
155 PostSetNeedsCommitToMainThread();
158 void SetupTree() override
{
159 scoped_refptr
<FakePictureLayer
> root
=
160 FakePictureLayer::Create(layer_settings(), &client_
);
161 root
->SetBounds(gfx::Size(10, 10));
163 // Most of the layer isn't visible.
164 content_
= FakePictureLayer::Create(layer_settings(), &client_
);
165 content_
->SetBounds(gfx::Size(2000, 100));
166 root
->AddChild(content_
);
168 layer_tree_host()->SetRootLayer(root
);
169 LayerTreeHostDamageTest::SetupTree();
172 DrawResult
PrepareToDrawOnThread(LayerTreeHostImpl
* host_impl
,
173 LayerTreeHostImpl::FrameData
* frame_data
,
174 DrawResult draw_result
) override
{
175 EXPECT_EQ(DRAW_SUCCESS
, draw_result
);
177 int source_frame
= host_impl
->active_tree()->source_frame_number();
178 switch (source_frame
) {
180 // The first frame has damage, so we should draw and swap.
181 ++expect_swap_and_succeed_
;
184 // The second frame has no damage, so we should not draw and swap.
187 // The third frame has damage again, so we should draw and swap.
188 ++expect_swap_and_succeed_
;
191 // The fourth frame has no visible damage, so we should not draw and
199 void SwapBuffersOnThread(LayerTreeHostImpl
* host_impl
, bool result
) override
{
202 ++did_swap_and_succeed_
;
203 EXPECT_EQ(expect_swap_and_succeed_
, did_swap_and_succeed_
);
206 void DidCommit() override
{
207 int next_frame
= layer_tree_host()->source_frame_number();
208 switch (next_frame
) {
210 layer_tree_host()->SetNeedsCommit();
213 // Cause visible damage.
214 content_
->SetNeedsDisplayRect(
215 gfx::Rect(layer_tree_host()->device_viewport_size()));
218 // Cause non-visible damage.
219 content_
->SetNeedsDisplayRect(gfx::Rect(1990, 1990, 10, 10));
220 layer_tree_host()->SetNeedsCommit();
225 void AfterTest() override
{
226 EXPECT_EQ(4, did_swaps_
);
227 EXPECT_EQ(2, expect_swap_and_succeed_
);
228 EXPECT_EQ(expect_swap_and_succeed_
, did_swap_and_succeed_
);
231 FakeContentLayerClient client_
;
232 scoped_refptr
<FakePictureLayer
> content_
;
233 int expect_swap_and_succeed_
;
235 int did_swap_and_succeed_
;
238 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestNoDamageDoesNotSwap
);
240 class LayerTreeHostDamageTestForcedFullDamage
: public LayerTreeHostDamageTest
{
241 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
243 void SetupTree() override
{
244 root_
= FakePictureLayer::Create(layer_settings(), &client_
);
245 child_
= FakePictureLayer::Create(layer_settings(), &client_
);
247 root_
->SetBounds(gfx::Size(500, 500));
248 child_
->SetPosition(gfx::Point(100, 100));
249 child_
->SetBounds(gfx::Size(30, 30));
251 root_
->AddChild(child_
);
252 layer_tree_host()->SetRootLayer(root_
);
253 LayerTreeHostDamageTest::SetupTree();
256 DrawResult
PrepareToDrawOnThread(LayerTreeHostImpl
* host_impl
,
257 LayerTreeHostImpl::FrameData
* frame_data
,
258 DrawResult draw_result
) override
{
259 EXPECT_EQ(DRAW_SUCCESS
, draw_result
);
261 RenderSurfaceImpl
* root_surface
=
262 host_impl
->active_tree()->root_layer()->render_surface();
263 gfx::Rect root_damage
=
264 root_surface
->damage_tracker()->current_damage_rect();
265 root_damage
.Intersect(root_surface
->content_rect());
267 int source_frame
= host_impl
->active_tree()->source_frame_number();
268 switch (source_frame
) {
270 // The first frame draws and clears any damage.
271 EXPECT_EQ(root_surface
->content_rect(), root_damage
);
272 EXPECT_FALSE(frame_data
->has_no_damage
);
275 // If we get a frame without damage then we don't draw.
276 EXPECT_EQ(gfx::Rect(), root_damage
);
277 EXPECT_TRUE(frame_data
->has_no_damage
);
279 // Then we set full damage for the next frame.
280 host_impl
->SetFullRootLayerDamage();
283 // The whole frame should be damaged as requested.
284 EXPECT_EQ(root_surface
->content_rect(), root_damage
);
285 EXPECT_FALSE(frame_data
->has_no_damage
);
287 // Just a part of the next frame should be damaged.
288 child_damage_rect_
= gfx::Rect(10, 11, 12, 13);
291 // The update rect in the child should be damaged and the damaged area
292 // should match the invalidation.
293 EXPECT_EQ(gfx::Rect(100 + 10, 100 + 11, 12, 13), root_damage
);
294 EXPECT_FALSE(frame_data
->has_no_damage
);
296 // If we damage part of the frame, but also damage the full
297 // frame, then the whole frame should be damaged.
298 child_damage_rect_
= gfx::Rect(10, 11, 12, 13);
299 host_impl
->SetFullRootLayerDamage();
302 // The whole frame is damaged.
303 EXPECT_EQ(root_surface
->content_rect(), root_damage
);
304 EXPECT_FALSE(frame_data
->has_no_damage
);
312 void DidCommitAndDrawFrame() override
{
314 layer_tree_host()->SetNeedsCommit();
316 if (!child_damage_rect_
.IsEmpty()) {
317 child_
->SetNeedsDisplayRect(child_damage_rect_
);
318 child_damage_rect_
= gfx::Rect();
322 void AfterTest() override
{}
324 FakeContentLayerClient client_
;
325 scoped_refptr
<FakePictureLayer
> root_
;
326 scoped_refptr
<FakePictureLayer
> child_
;
327 gfx::Rect child_damage_rect_
;
330 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestForcedFullDamage
);
332 class LayerTreeHostScrollbarDamageTest
: public LayerTreeHostDamageTest
{
333 void SetupTree() override
{
334 scoped_refptr
<Layer
> root_layer
= Layer::Create(layer_settings());
335 root_layer
->SetBounds(gfx::Size(400, 400));
336 root_layer
->SetMasksToBounds(true);
337 layer_tree_host()->SetRootLayer(root_layer
);
339 scoped_refptr
<Layer
> scroll_clip_layer
= Layer::Create(layer_settings());
340 scoped_refptr
<Layer
> content_layer
=
341 FakePictureLayer::Create(layer_settings(), &client_
);
342 content_layer
->SetScrollClipLayerId(scroll_clip_layer
->id());
343 content_layer
->SetScrollOffset(gfx::ScrollOffset(10, 20));
344 content_layer
->SetBounds(gfx::Size(100, 200));
345 content_layer
->SetIsDrawable(true);
346 scroll_clip_layer
->SetBounds(
347 gfx::Size(content_layer
->bounds().width() - 30,
348 content_layer
->bounds().height() - 50));
349 scroll_clip_layer
->AddChild(content_layer
);
350 root_layer
->AddChild(scroll_clip_layer
);
352 scoped_refptr
<Layer
> scrollbar_layer
= FakePaintedScrollbarLayer::Create(
353 layer_settings(), false, true, content_layer
->id());
354 scrollbar_layer
->SetPosition(gfx::Point(300, 300));
355 scrollbar_layer
->SetBounds(gfx::Size(10, 100));
356 scrollbar_layer
->ToScrollbarLayer()->SetClipLayer(scroll_clip_layer
->id());
357 scrollbar_layer
->ToScrollbarLayer()->SetScrollLayer(content_layer
->id());
358 root_layer
->AddChild(scrollbar_layer
);
360 gfx::RectF
content_rect(content_layer
->position(),
361 content_layer
->bounds());
362 gfx::RectF
scrollbar_rect(scrollbar_layer
->position(),
363 scrollbar_layer
->bounds());
364 EXPECT_FALSE(content_rect
.Intersects(scrollbar_rect
));
366 LayerTreeHostDamageTest::SetupTree();
370 FakeContentLayerClient client_
;
373 class LayerTreeHostDamageTestScrollbarDoesDamage
374 : public LayerTreeHostScrollbarDamageTest
{
375 void BeginTest() override
{
377 PostSetNeedsCommitToMainThread();
380 DrawResult
PrepareToDrawOnThread(LayerTreeHostImpl
* host_impl
,
381 LayerTreeHostImpl::FrameData
* frame_data
,
382 DrawResult draw_result
) override
{
383 EXPECT_EQ(DRAW_SUCCESS
, draw_result
);
384 RenderSurfaceImpl
* root_surface
=
385 host_impl
->active_tree()->root_layer()->render_surface();
386 gfx::Rect root_damage
=
387 root_surface
->damage_tracker()->current_damage_rect();
388 root_damage
.Intersect(root_surface
->content_rect());
389 switch (did_swaps_
) {
391 // The first frame has damage, so we should draw and swap.
394 // The second frame should not damage the scrollbars.
395 EXPECT_FALSE(root_damage
.Intersects(gfx::Rect(300, 300, 10, 100)));
398 // The third frame should damage the scrollbars.
399 EXPECT_TRUE(root_damage
.Contains(gfx::Rect(300, 300, 10, 100)));
402 // The fourth frame should damage the scrollbars.
403 EXPECT_TRUE(root_damage
.Contains(gfx::Rect(300, 300, 10, 100)));
410 void SwapBuffersOnThread(LayerTreeHostImpl
* host_impl
, bool result
) override
{
413 LayerImpl
* root
= host_impl
->active_tree()->root_layer();
414 LayerImpl
* scroll_clip_layer
= root
->children()[0];
415 LayerImpl
* scroll_layer
= scroll_clip_layer
->children()[0];
416 switch (did_swaps_
) {
418 // Test that modifying the position of the content layer (not
419 // scrolling) won't damage the scrollbar.
420 MainThreadTaskRunner()->PostTask(
421 FROM_HERE
, base::Bind(&LayerTreeHostDamageTestScrollbarDoesDamage::
422 ModifyContentLayerPosition
,
423 base::Unretained(this)));
426 scroll_layer
->ScrollBy(gfx::Vector2dF(10.f
, 10.f
));
427 host_impl
->SetNeedsRedraw();
430 // We will resize the content layer, on the main thread.
431 MainThreadTaskRunner()->PostTask(
434 &LayerTreeHostDamageTestScrollbarDoesDamage::ResizeScrollLayer
,
435 base::Unretained(this)));
440 void ModifyContentLayerPosition() {
441 EXPECT_EQ(1, did_swaps_
);
442 Layer
* root
= layer_tree_host()->root_layer();
443 Layer
* scroll_clip_layer
= root
->child_at(0);
444 Layer
* scroll_layer
= scroll_clip_layer
->child_at(0);
445 scroll_layer
->SetPosition(gfx::Point(10, 10));
448 void ResizeScrollLayer() {
449 EXPECT_EQ(3, did_swaps_
);
450 Layer
* root
= layer_tree_host()->root_layer();
451 Layer
* scroll_clip_layer
= root
->child_at(0);
452 Layer
* scroll_layer
= scroll_clip_layer
->child_at(0);
453 scroll_layer
->SetBounds(
454 gfx::Size(root
->bounds().width() + 60, root
->bounds().height() + 100));
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::Rect 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
);