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. 4 5 #include "cc/trees/layer_tree_host.h" 6 7 #include "base/bind.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_test_common.h" 16 #include "cc/test/layer_tree_test.h" 17 #include "cc/trees/damage_tracker.h" 18 #include "cc/trees/layer_tree_impl.h" 19 20 namespace cc { 21 namespace { 22 23 // These tests deal with damage tracking. 24 class LayerTreeHostDamageTest : public LayerTreeTest {}; 25 26 // LayerTreeHost::SetNeedsRedraw should damage the whole viewport. 27 class LayerTreeHostDamageTestSetNeedsRedraw 28 : public LayerTreeHostDamageTest { SetupTree()29 void SetupTree() override { 30 // Viewport is 10x10. 31 scoped_refptr<FakePictureLayer> root = FakePictureLayer::Create(&client_); 32 root->SetBounds(gfx::Size(10, 10)); 33 34 layer_tree_host()->SetRootLayer(root); 35 LayerTreeHostDamageTest::SetupTree(); 36 client_.set_bounds(root->bounds()); 37 } 38 BeginTest()39 void BeginTest() override { 40 draw_count_ = 0; 41 PostSetNeedsCommitToMainThread(); 42 } 43 DidCommitAndDrawFrame()44 void DidCommitAndDrawFrame() override { 45 switch (layer_tree_host()->SourceFrameNumber()) { 46 case 1: 47 layer_tree_host()->SetNeedsRedrawRect( 48 layer_tree_host()->device_viewport_rect()); 49 break; 50 } 51 } 52 PrepareToDrawOnThread(LayerTreeHostImpl * impl,LayerTreeHostImpl::FrameData * frame_data,DrawResult draw_result)53 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* impl, 54 LayerTreeHostImpl::FrameData* frame_data, 55 DrawResult draw_result) override { 56 EXPECT_EQ(DRAW_SUCCESS, draw_result); 57 58 RenderSurfaceImpl* root_surface = 59 GetRenderSurface(impl->active_tree()->root_layer()); 60 gfx::Rect root_damage; 61 EXPECT_TRUE( 62 root_surface->damage_tracker()->GetDamageRectIfValid(&root_damage)); 63 64 switch (draw_count_) { 65 case 0: 66 // The first frame has full damage. 67 EXPECT_EQ(gfx::Rect(10, 10), root_damage); 68 break; 69 case 1: 70 // The second frame has full damage. 71 EXPECT_EQ(gfx::Rect(10, 10), root_damage); 72 EndTest(); 73 break; 74 case 2: 75 NOTREACHED(); 76 } 77 78 ++draw_count_; 79 return draw_result; 80 } 81 82 int draw_count_; 83 FakeContentLayerClient client_; 84 }; 85 86 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestSetNeedsRedraw); 87 88 // LayerTreeHost::SetViewportRectAndScale should damage the whole viewport. 89 class LayerTreeHostDamageTestSetViewportRectAndScale 90 : public LayerTreeHostDamageTest { SetupTree()91 void SetupTree() override { 92 // Viewport is 10x10. 93 scoped_refptr<FakePictureLayer> root = FakePictureLayer::Create(&client_); 94 root->SetBounds(gfx::Size(10, 10)); 95 96 layer_tree_host()->SetRootLayer(root); 97 LayerTreeHostDamageTest::SetupTree(); 98 client_.set_bounds(root->bounds()); 99 } 100 BeginTest()101 void BeginTest() override { 102 draw_count_ = 0; 103 PostSetNeedsCommitToMainThread(); 104 } 105 DidCommitAndDrawFrame()106 void DidCommitAndDrawFrame() override { 107 switch (layer_tree_host()->SourceFrameNumber()) { 108 case 1: 109 layer_tree_host()->SetViewportRectAndScale(gfx::Rect(15, 15), 1.f, 110 GetCurrentLocalSurfaceId()); 111 break; 112 } 113 } 114 PrepareToDrawOnThread(LayerTreeHostImpl * impl,LayerTreeHostImpl::FrameData * frame_data,DrawResult draw_result)115 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* impl, 116 LayerTreeHostImpl::FrameData* frame_data, 117 DrawResult draw_result) override { 118 EXPECT_EQ(DRAW_SUCCESS, draw_result); 119 120 RenderSurfaceImpl* root_surface = 121 GetRenderSurface(impl->active_tree()->root_layer()); 122 gfx::Rect root_damage; 123 EXPECT_TRUE( 124 root_surface->damage_tracker()->GetDamageRectIfValid(&root_damage)); 125 126 switch (draw_count_) { 127 case 0: 128 // The first frame has full damage. 129 EXPECT_EQ(gfx::Rect(10, 10), root_damage); 130 break; 131 case 1: 132 // The second frame has full damage. 133 EXPECT_EQ(gfx::Rect(15, 15), root_damage); 134 EndTest(); 135 break; 136 case 2: 137 NOTREACHED(); 138 } 139 140 ++draw_count_; 141 return draw_result; 142 } 143 144 int draw_count_; 145 FakeContentLayerClient client_; 146 }; 147 148 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestSetViewportRectAndScale); 149 150 class LayerTreeHostDamageTestNoDamageDoesNotSwap 151 : public LayerTreeHostDamageTest { BeginTest()152 void BeginTest() override { 153 PostSetNeedsCommitToMainThread(); 154 } 155 SetupTree()156 void SetupTree() override { 157 scoped_refptr<FakePictureLayer> root = FakePictureLayer::Create(&client_); 158 root->SetBounds(gfx::Size(10, 10)); 159 160 // Most of the layer isn't visible. 161 content_ = FakePictureLayer::Create(&client_); 162 content_->SetBounds(gfx::Size(2000, 100)); 163 root->AddChild(content_); 164 165 layer_tree_host()->SetRootLayer(root); 166 LayerTreeHostDamageTest::SetupTree(); 167 client_.set_bounds(root->bounds()); 168 } 169 PrepareToDrawOnThread(LayerTreeHostImpl * host_impl,LayerTreeHostImpl::FrameData * frame_data,DrawResult draw_result)170 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, 171 LayerTreeHostImpl::FrameData* frame_data, 172 DrawResult draw_result) override { 173 EXPECT_EQ(DRAW_SUCCESS, draw_result); 174 175 int source_frame = host_impl->active_tree()->source_frame_number(); 176 switch (source_frame) { 177 case 0: 178 // The first frame has damage, so we should draw and swap. 179 EXPECT_FALSE(frame_data->has_no_damage); 180 ++expect_swap_; 181 break; 182 case 1: 183 // The second frame has no damage, so we should not draw and swap. 184 EXPECT_TRUE(frame_data->has_no_damage); 185 break; 186 case 2: 187 // The third frame has damage again, so we should draw and swap. 188 EXPECT_FALSE(frame_data->has_no_damage); 189 ++expect_swap_; 190 break; 191 case 3: 192 // The fourth frame has no visible damage, so we should not draw and 193 // swap. 194 EXPECT_TRUE(frame_data->has_no_damage); 195 EndTest(); 196 break; 197 } 198 return draw_result; 199 } 200 DisplayDidDrawAndSwapOnThread()201 void DisplayDidDrawAndSwapOnThread() override { 202 ++did_swap_; 203 EXPECT_EQ(expect_swap_, did_swap_); 204 } 205 DidCommit()206 void DidCommit() override { 207 int next_frame = layer_tree_host()->SourceFrameNumber(); 208 switch (next_frame) { 209 case 1: 210 layer_tree_host()->SetNeedsCommit(); 211 break; 212 case 2: 213 // Cause visible damage. 214 content_->SetNeedsDisplayRect( 215 layer_tree_host()->device_viewport_rect()); 216 break; 217 case 3: 218 // Cause non-visible damage. 219 content_->SetNeedsDisplayRect(gfx::Rect(1990, 1990, 10, 10)); 220 layer_tree_host()->SetNeedsCommit(); 221 break; 222 } 223 } 224 AfterTest()225 void AfterTest() override { 226 EXPECT_EQ(2, expect_swap_); 227 EXPECT_EQ(expect_swap_, did_swap_); 228 } 229 230 FakeContentLayerClient client_; 231 scoped_refptr<FakePictureLayer> content_; 232 int expect_swap_ = 0; 233 int did_swap_ = 0; 234 }; 235 236 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestNoDamageDoesNotSwap); 237 238 class LayerTreeHostDamageTestForcedFullDamage : public LayerTreeHostDamageTest { BeginTest()239 void BeginTest() override { PostSetNeedsCommitToMainThread(); } 240 SetupTree()241 void SetupTree() override { 242 root_ = FakePictureLayer::Create(&client_); 243 child_ = FakePictureLayer::Create(&client_); 244 245 root_->SetBounds(gfx::Size(500, 500)); 246 child_->SetPosition(gfx::PointF(100.f, 100.f)); 247 child_->SetBounds(gfx::Size(30, 30)); 248 249 root_->AddChild(child_); 250 layer_tree_host()->SetRootLayer(root_); 251 LayerTreeHostDamageTest::SetupTree(); 252 client_.set_bounds(root_->bounds()); 253 } 254 PrepareToDrawOnThread(LayerTreeHostImpl * host_impl,LayerTreeHostImpl::FrameData * frame_data,DrawResult draw_result)255 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, 256 LayerTreeHostImpl::FrameData* frame_data, 257 DrawResult draw_result) override { 258 EXPECT_EQ(DRAW_SUCCESS, draw_result); 259 260 RenderSurfaceImpl* root_surface = 261 GetRenderSurface(host_impl->active_tree()->root_layer()); 262 gfx::Rect root_damage; 263 EXPECT_TRUE( 264 root_surface->damage_tracker()->GetDamageRectIfValid(&root_damage)); 265 root_damage.Intersect(root_surface->content_rect()); 266 267 int source_frame = host_impl->active_tree()->source_frame_number(); 268 switch (source_frame) { 269 case 0: 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); 273 break; 274 case 1: 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); 278 279 // Then we set full damage for the next frame. 280 host_impl->SetFullViewportDamage(); 281 break; 282 case 2: 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); 286 287 // Just a part of the next frame should be damaged. 288 child_damage_rect_ = gfx::Rect(10, 11, 12, 13); 289 break; 290 case 3: 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); 295 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->SetFullViewportDamage(); 300 break; 301 case 4: 302 // The whole frame is damaged. 303 EXPECT_EQ(root_surface->content_rect(), root_damage); 304 EXPECT_FALSE(frame_data->has_no_damage); 305 306 EndTest(); 307 break; 308 } 309 return draw_result; 310 } 311 DidCommitAndDrawFrame()312 void DidCommitAndDrawFrame() override { 313 if (!TestEnded()) 314 layer_tree_host()->SetNeedsCommit(); 315 316 if (!child_damage_rect_.IsEmpty()) { 317 child_->SetNeedsDisplayRect(child_damage_rect_); 318 child_damage_rect_ = gfx::Rect(); 319 } 320 } 321 322 FakeContentLayerClient client_; 323 scoped_refptr<FakePictureLayer> root_; 324 scoped_refptr<FakePictureLayer> child_; 325 gfx::Rect child_damage_rect_; 326 }; 327 328 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestForcedFullDamage); 329 330 class LayerTreeHostScrollbarDamageTest : public LayerTreeHostDamageTest { SetupTree()331 void SetupTree() override { 332 scoped_refptr<Layer> root_layer = Layer::Create(); 333 root_layer->SetBounds(gfx::Size(400, 400)); 334 root_layer->SetMasksToBounds(true); 335 layer_tree_host()->SetRootLayer(root_layer); 336 337 content_layer_ = FakePictureLayer::Create(&client_); 338 content_layer_->SetElementId( 339 LayerIdToElementIdForTesting(content_layer_->id())); 340 content_layer_->SetScrollable(root_layer->bounds()); 341 content_layer_->SetScrollOffset(gfx::ScrollOffset(10, 20)); 342 content_layer_->SetBounds(gfx::Size(100, 200)); 343 content_layer_->SetIsDrawable(true); 344 root_layer->AddChild(content_layer_); 345 346 scoped_refptr<Layer> scrollbar_layer = FakePaintedScrollbarLayer::Create( 347 false, true, content_layer_->element_id()); 348 scrollbar_layer->SetPosition(gfx::PointF(300.f, 300.f)); 349 scrollbar_layer->SetBounds(gfx::Size(10, 100)); 350 root_layer->AddChild(scrollbar_layer); 351 352 gfx::RectF content_rect(content_layer_->position(), 353 gfx::SizeF(content_layer_->bounds())); 354 gfx::RectF scrollbar_rect(scrollbar_layer->position(), 355 gfx::SizeF(scrollbar_layer->bounds())); 356 EXPECT_FALSE(content_rect.Intersects(scrollbar_rect)); 357 358 LayerTreeHostDamageTest::SetupTree(); 359 client_.set_bounds(root_layer->bounds()); 360 } 361 362 private: 363 FakeContentLayerClient client_; 364 365 protected: 366 scoped_refptr<Layer> content_layer_; 367 }; 368 369 class LayerTreeHostDamageTestScrollbarDoesDamage 370 : public LayerTreeHostScrollbarDamageTest { BeginTest()371 void BeginTest() override { 372 num_draws_ = 0; 373 PostSetNeedsCommitToMainThread(); 374 } 375 PrepareToDrawOnThread(LayerTreeHostImpl * host_impl,LayerTreeHostImpl::FrameData * frame_data,DrawResult draw_result)376 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, 377 LayerTreeHostImpl::FrameData* frame_data, 378 DrawResult draw_result) override { 379 EXPECT_EQ(DRAW_SUCCESS, draw_result); 380 RenderSurfaceImpl* root_surface = 381 GetRenderSurface(host_impl->active_tree()->root_layer()); 382 gfx::Rect root_damage; 383 EXPECT_TRUE( 384 root_surface->damage_tracker()->GetDamageRectIfValid(&root_damage)); 385 root_damage.Intersect(root_surface->content_rect()); 386 switch (num_draws_) { 387 case 0: 388 // The first frame has damage, so we should draw and swap. 389 break; 390 case 1: 391 // The second frame should not damage the scrollbars. 392 EXPECT_FALSE(root_damage.Intersects(gfx::Rect(300, 300, 10, 100))); 393 break; 394 case 2: 395 // The third frame should damage the scrollbars. 396 EXPECT_TRUE(root_damage.Contains(gfx::Rect(300, 300, 10, 100))); 397 break; 398 case 3: 399 // The fourth frame should damage the scrollbars. 400 EXPECT_TRUE(root_damage.Contains(gfx::Rect(300, 300, 10, 100))); 401 EndTest(); 402 break; 403 } 404 return draw_result; 405 } 406 DrawLayersOnThread(LayerTreeHostImpl * host_impl)407 void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { 408 ++num_draws_; 409 LayerImpl* scroll_layer = 410 host_impl->active_tree()->LayerById(content_layer_->id()); 411 switch (num_draws_) { 412 case 1: 413 // Test that modifying the position of the content layer (not 414 // scrolling) won't damage the scrollbar. 415 MainThreadTaskRunner()->PostTask( 416 FROM_HERE, 417 base::BindOnce(&LayerTreeHostDamageTestScrollbarDoesDamage:: 418 ModifyContentLayerPosition, 419 base::Unretained(this))); 420 break; 421 case 2: 422 scroll_layer->ScrollBy(gfx::Vector2dF(10.f, 10.f)); 423 host_impl->SetNeedsRedraw(); 424 break; 425 case 3: 426 // We will resize the content layer, on the main thread. 427 MainThreadTaskRunner()->PostTask( 428 FROM_HERE, 429 base::BindOnce( 430 &LayerTreeHostDamageTestScrollbarDoesDamage::ResizeScrollLayer, 431 base::Unretained(this))); 432 break; 433 } 434 } 435 ModifyContentLayerPosition()436 void ModifyContentLayerPosition() { 437 EXPECT_EQ(1, num_draws_); 438 content_layer_->SetPosition(gfx::PointF(10.f, 10.f)); 439 } 440 ResizeScrollLayer()441 void ResizeScrollLayer() { 442 EXPECT_EQ(3, num_draws_); 443 Layer* root = layer_tree_host()->root_layer(); 444 content_layer_->SetBounds( 445 gfx::Size(root->bounds().width() + 60, root->bounds().height() + 100)); 446 } 447 AfterTest()448 void AfterTest() override { EXPECT_EQ(4, num_draws_); } 449 450 int num_draws_; 451 }; 452 453 MULTI_THREAD_TEST_F(LayerTreeHostDamageTestScrollbarDoesDamage); 454 455 class LayerTreeHostDamageTestScrollbarCommitDoesNoDamage 456 : public LayerTreeHostScrollbarDamageTest { BeginTest()457 void BeginTest() override { 458 num_draws_ = 0; 459 PostSetNeedsCommitToMainThread(); 460 } 461 PrepareToDrawOnThread(LayerTreeHostImpl * host_impl,LayerTreeHostImpl::FrameData * frame_data,DrawResult draw_result)462 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, 463 LayerTreeHostImpl::FrameData* frame_data, 464 DrawResult draw_result) override { 465 EXPECT_EQ(DRAW_SUCCESS, draw_result); 466 RenderSurfaceImpl* root_surface = 467 GetRenderSurface(host_impl->active_tree()->root_layer()); 468 gfx::Rect root_damage; 469 EXPECT_TRUE( 470 root_surface->damage_tracker()->GetDamageRectIfValid(&root_damage)); 471 root_damage.Intersect(root_surface->content_rect()); 472 int frame = host_impl->active_tree()->source_frame_number(); 473 switch (num_draws_) { 474 case 0: 475 // The first frame has damage, so we should draw and swap. 476 EXPECT_EQ(0, frame); 477 break; 478 case 1: 479 // The second frame has scrolled, so the scrollbar should be damaged. 480 EXPECT_EQ(0, frame); 481 EXPECT_TRUE(root_damage.Contains(gfx::Rect(300, 300, 10, 100))); 482 break; 483 case 2: 484 // The third frame (after the commit) has no changes, so it shouldn't. 485 EXPECT_EQ(1, frame); 486 EXPECT_FALSE(root_damage.Intersects(gfx::Rect(300, 300, 10, 100))); 487 break; 488 default: 489 NOTREACHED(); 490 break; 491 } 492 return draw_result; 493 } 494 DrawLayersOnThread(LayerTreeHostImpl * host_impl)495 void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { 496 ++num_draws_; 497 LayerImpl* scroll_layer = 498 host_impl->active_tree()->LayerById(content_layer_->id()); 499 switch (num_draws_) { 500 case 1: 501 // Scroll on the thread. This should damage the scrollbar for the 502 // next draw on the thread. 503 scroll_layer->ScrollBy(gfx::Vector2dF(10.f, 10.f)); 504 host_impl->SetNeedsRedraw(); 505 break; 506 case 2: 507 // Forcibly send the scroll to the main thread. 508 PostSetNeedsCommitToMainThread(); 509 break; 510 case 3: 511 // First swap after second commit. 512 EndTest(); 513 break; 514 default: 515 NOTREACHED(); 516 break; 517 } 518 } 519 AfterTest()520 void AfterTest() override { EXPECT_EQ(3, num_draws_); } 521 522 int num_draws_; 523 }; 524 525 MULTI_THREAD_TEST_F(LayerTreeHostDamageTestScrollbarCommitDoesNoDamage); 526 527 } // namespace 528 } // namespace cc 529