1 // Copyright 2011 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/test/layer_tree_test.h" 6 7 #include "base/command_line.h" 8 #include "cc/animation/animation.h" 9 #include "cc/animation/animation_registrar.h" 10 #include "cc/animation/layer_animation_controller.h" 11 #include "cc/animation/timing_function.h" 12 #include "cc/base/switches.h" 13 #include "cc/input/input_handler.h" 14 #include "cc/layers/content_layer.h" 15 #include "cc/layers/layer.h" 16 #include "cc/layers/layer_impl.h" 17 #include "cc/test/animation_test_common.h" 18 #include "cc/test/fake_context_provider.h" 19 #include "cc/test/fake_layer_tree_host_client.h" 20 #include "cc/test/fake_output_surface.h" 21 #include "cc/test/occlusion_tracker_test_common.h" 22 #include "cc/test/tiled_layer_test_common.h" 23 #include "cc/trees/layer_tree_host_impl.h" 24 #include "cc/trees/single_thread_proxy.h" 25 #include "testing/gmock/include/gmock/gmock.h" 26 #include "ui/gfx/size_conversions.h" 27 28 namespace cc { 29 30 TestHooks::TestHooks() {} 31 32 TestHooks::~TestHooks() {} 33 34 bool TestHooks::PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, 35 LayerTreeHostImpl::FrameData* frame_data, 36 bool result) { 37 return true; 38 } 39 40 bool TestHooks::CanActivatePendingTree(LayerTreeHostImpl* host_impl) { 41 return true; 42 } 43 44 bool TestHooks::CanActivatePendingTreeIfNeeded(LayerTreeHostImpl* host_impl) { 45 return true; 46 } 47 48 // Adapts LayerTreeHostImpl for test. Runs real code, then invokes test hooks. 49 class LayerTreeHostImplForTesting : public LayerTreeHostImpl { 50 public: 51 static scoped_ptr<LayerTreeHostImplForTesting> Create( 52 TestHooks* test_hooks, 53 const LayerTreeSettings& settings, 54 LayerTreeHostImplClient* host_impl_client, 55 Proxy* proxy, 56 RenderingStatsInstrumentation* stats_instrumentation) { 57 return make_scoped_ptr( 58 new LayerTreeHostImplForTesting(test_hooks, 59 settings, 60 host_impl_client, 61 proxy, 62 stats_instrumentation)); 63 } 64 65 protected: 66 LayerTreeHostImplForTesting( 67 TestHooks* test_hooks, 68 const LayerTreeSettings& settings, 69 LayerTreeHostImplClient* host_impl_client, 70 Proxy* proxy, 71 RenderingStatsInstrumentation* stats_instrumentation) 72 : LayerTreeHostImpl(settings, 73 host_impl_client, 74 proxy, 75 stats_instrumentation), 76 test_hooks_(test_hooks) {} 77 78 virtual void BeginCommit() OVERRIDE { 79 LayerTreeHostImpl::BeginCommit(); 80 test_hooks_->BeginCommitOnThread(this); 81 } 82 83 virtual void CommitComplete() OVERRIDE { 84 LayerTreeHostImpl::CommitComplete(); 85 test_hooks_->CommitCompleteOnThread(this); 86 87 if (!settings().impl_side_painting) { 88 test_hooks_->WillActivateTreeOnThread(this); 89 test_hooks_->DidActivateTreeOnThread(this); 90 } 91 } 92 93 virtual bool PrepareToDraw(FrameData* frame, gfx::Rect damage_rect) OVERRIDE { 94 bool result = LayerTreeHostImpl::PrepareToDraw(frame, damage_rect); 95 if (!test_hooks_->PrepareToDrawOnThread(this, frame, result)) 96 result = false; 97 return result; 98 } 99 100 virtual void DrawLayers(FrameData* frame, 101 base::TimeTicks frame_begin_time) OVERRIDE { 102 LayerTreeHostImpl::DrawLayers(frame, frame_begin_time); 103 test_hooks_->DrawLayersOnThread(this); 104 } 105 106 virtual bool SwapBuffers(const LayerTreeHostImpl::FrameData& frame) OVERRIDE { 107 bool result = LayerTreeHostImpl::SwapBuffers(frame); 108 test_hooks_->SwapBuffersOnThread(this, result); 109 return result; 110 } 111 112 virtual void OnSwapBuffersComplete(const CompositorFrameAck* ack) OVERRIDE { 113 LayerTreeHostImpl::OnSwapBuffersComplete(ack); 114 test_hooks_->SwapBuffersCompleteOnThread(this); 115 } 116 117 virtual void ActivatePendingTreeIfNeeded() OVERRIDE { 118 if (!pending_tree()) 119 return; 120 121 if (!test_hooks_->CanActivatePendingTreeIfNeeded(this)) 122 return; 123 124 LayerTreeHostImpl::ActivatePendingTreeIfNeeded(); 125 } 126 127 virtual void ActivatePendingTree() OVERRIDE { 128 if (!test_hooks_->CanActivatePendingTree(this)) 129 return; 130 131 test_hooks_->WillActivateTreeOnThread(this); 132 LayerTreeHostImpl::ActivatePendingTree(); 133 DCHECK(!pending_tree()); 134 test_hooks_->DidActivateTreeOnThread(this); 135 } 136 137 virtual bool InitializeRenderer(scoped_ptr<OutputSurface> output_surface) 138 OVERRIDE { 139 bool success = LayerTreeHostImpl::InitializeRenderer(output_surface.Pass()); 140 test_hooks_->InitializedRendererOnThread(this, success); 141 return success; 142 } 143 144 virtual void SetVisible(bool visible) OVERRIDE { 145 LayerTreeHostImpl::SetVisible(visible); 146 test_hooks_->DidSetVisibleOnImplTree(this, visible); 147 } 148 149 virtual void AnimateLayers(base::TimeTicks monotonic_time, 150 base::Time wall_clock_time) OVERRIDE { 151 test_hooks_->WillAnimateLayers(this, monotonic_time); 152 LayerTreeHostImpl::AnimateLayers(monotonic_time, wall_clock_time); 153 test_hooks_->AnimateLayers(this, monotonic_time); 154 } 155 156 virtual void UpdateAnimationState(bool start_ready_animations) OVERRIDE { 157 LayerTreeHostImpl::UpdateAnimationState(start_ready_animations); 158 bool has_unfinished_animation = false; 159 AnimationRegistrar::AnimationControllerMap::const_iterator iter = 160 active_animation_controllers().begin(); 161 for (; iter != active_animation_controllers().end(); ++iter) { 162 if (iter->second->HasActiveAnimation()) { 163 has_unfinished_animation = true; 164 break; 165 } 166 } 167 test_hooks_->UpdateAnimationState(this, has_unfinished_animation); 168 } 169 170 virtual base::TimeDelta LowFrequencyAnimationInterval() const OVERRIDE { 171 return base::TimeDelta::FromMilliseconds(16); 172 } 173 174 private: 175 TestHooks* test_hooks_; 176 }; 177 178 // Adapts LayerTreeHost for test. Injects LayerTreeHostImplForTesting. 179 class LayerTreeHostForTesting : public cc::LayerTreeHost { 180 public: 181 static scoped_ptr<LayerTreeHostForTesting> Create( 182 TestHooks* test_hooks, 183 cc::LayerTreeHostClient* host_client, 184 const cc::LayerTreeSettings& settings, 185 scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) { 186 scoped_ptr<LayerTreeHostForTesting> layer_tree_host( 187 new LayerTreeHostForTesting(test_hooks, host_client, settings)); 188 bool success = layer_tree_host->Initialize(impl_task_runner); 189 EXPECT_TRUE(success); 190 return layer_tree_host.Pass(); 191 } 192 193 virtual scoped_ptr<cc::LayerTreeHostImpl> CreateLayerTreeHostImpl( 194 cc::LayerTreeHostImplClient* host_impl_client) OVERRIDE { 195 return LayerTreeHostImplForTesting::Create( 196 test_hooks_, 197 settings(), 198 host_impl_client, 199 proxy(), 200 rendering_stats_instrumentation()).PassAs<cc::LayerTreeHostImpl>(); 201 } 202 203 virtual void SetNeedsCommit() OVERRIDE { 204 if (!test_started_) 205 return; 206 LayerTreeHost::SetNeedsCommit(); 207 } 208 209 void set_test_started(bool started) { test_started_ = started; } 210 211 virtual void DidDeferCommit() OVERRIDE { 212 test_hooks_->DidDeferCommit(); 213 } 214 215 private: 216 LayerTreeHostForTesting(TestHooks* test_hooks, 217 cc::LayerTreeHostClient* client, 218 const cc::LayerTreeSettings& settings) 219 : LayerTreeHost(client, settings), 220 test_hooks_(test_hooks), 221 test_started_(false) {} 222 223 TestHooks* test_hooks_; 224 bool test_started_; 225 }; 226 227 // Implementation of LayerTreeHost callback interface. 228 class LayerTreeHostClientForTesting : public LayerTreeHostClient { 229 public: 230 static scoped_ptr<LayerTreeHostClientForTesting> Create( 231 TestHooks* test_hooks) { 232 return make_scoped_ptr(new LayerTreeHostClientForTesting(test_hooks)); 233 } 234 virtual ~LayerTreeHostClientForTesting() {} 235 236 virtual void WillBeginFrame() OVERRIDE { test_hooks_->WillBeginFrame(); } 237 238 virtual void DidBeginFrame() OVERRIDE { test_hooks_->DidBeginFrame(); } 239 240 virtual void Animate(double monotonic_time) OVERRIDE { 241 test_hooks_->Animate(base::TimeTicks::FromInternalValue( 242 monotonic_time * base::Time::kMicrosecondsPerSecond)); 243 } 244 245 virtual void Layout() OVERRIDE { 246 test_hooks_->Layout(); 247 } 248 249 virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta, 250 float scale) OVERRIDE { 251 test_hooks_->ApplyScrollAndScale(scroll_delta, scale); 252 } 253 254 virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) 255 OVERRIDE { 256 return test_hooks_->CreateOutputSurface(fallback); 257 } 258 259 virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE { 260 test_hooks_->DidInitializeOutputSurface(succeeded); 261 } 262 263 virtual void DidFailToInitializeOutputSurface() OVERRIDE { 264 test_hooks_->DidFailToInitializeOutputSurface(); 265 } 266 267 virtual void WillCommit() OVERRIDE { test_hooks_->WillCommit(); } 268 269 virtual void DidCommit() OVERRIDE { 270 test_hooks_->DidCommit(); 271 } 272 273 virtual void DidCommitAndDrawFrame() OVERRIDE { 274 test_hooks_->DidCommitAndDrawFrame(); 275 } 276 277 virtual void DidCompleteSwapBuffers() OVERRIDE { 278 test_hooks_->DidCompleteSwapBuffers(); 279 } 280 281 virtual void ScheduleComposite() OVERRIDE { 282 test_hooks_->ScheduleComposite(); 283 } 284 285 virtual scoped_refptr<cc::ContextProvider> 286 OffscreenContextProviderForMainThread() OVERRIDE { 287 return test_hooks_->OffscreenContextProviderForMainThread(); 288 } 289 290 virtual scoped_refptr<cc::ContextProvider> 291 OffscreenContextProviderForCompositorThread() OVERRIDE { 292 return test_hooks_->OffscreenContextProviderForCompositorThread(); 293 } 294 295 private: 296 explicit LayerTreeHostClientForTesting(TestHooks* test_hooks) 297 : test_hooks_(test_hooks) {} 298 299 TestHooks* test_hooks_; 300 }; 301 302 LayerTreeTest::LayerTreeTest() 303 : beginning_(false), 304 end_when_begin_returns_(false), 305 timed_out_(false), 306 scheduled_(false), 307 schedule_when_set_visible_true_(false), 308 started_(false), 309 ended_(false), 310 delegating_renderer_(false), 311 timeout_seconds_(0), 312 weak_factory_(this) { 313 main_thread_weak_ptr_ = weak_factory_.GetWeakPtr(); 314 315 // Tests should timeout quickly unless --cc-layer-tree-test-no-timeout was 316 // specified (for running in a debugger). 317 CommandLine* command_line = CommandLine::ForCurrentProcess(); 318 if (!command_line->HasSwitch(switches::kCCLayerTreeTestNoTimeout)) 319 timeout_seconds_ = 5; 320 } 321 322 LayerTreeTest::~LayerTreeTest() {} 323 324 void LayerTreeTest::EndTest() { 325 // For the case where we EndTest during BeginTest(), set a flag to indicate 326 // that the test should end the second BeginTest regains control. 327 ended_ = true; 328 329 if (beginning_) { 330 end_when_begin_returns_ = true; 331 } else if (proxy()) { 332 // Racy timeouts and explicit EndTest calls might have cleaned up 333 // the tree host. Should check proxy first. 334 proxy()->MainThreadTaskRunner()->PostTask( 335 FROM_HERE, 336 base::Bind(&LayerTreeTest::RealEndTest, main_thread_weak_ptr_)); 337 } 338 } 339 340 void LayerTreeTest::EndTestAfterDelay(int delay_milliseconds) { 341 proxy()->MainThreadTaskRunner()->PostTask( 342 FROM_HERE, 343 base::Bind(&LayerTreeTest::EndTest, main_thread_weak_ptr_)); 344 } 345 346 void LayerTreeTest::PostAddAnimationToMainThread( 347 Layer* layer_to_receive_animation) { 348 proxy()->MainThreadTaskRunner()->PostTask( 349 FROM_HERE, 350 base::Bind(&LayerTreeTest::DispatchAddAnimation, 351 main_thread_weak_ptr_, 352 base::Unretained(layer_to_receive_animation))); 353 } 354 355 void LayerTreeTest::PostAddInstantAnimationToMainThread( 356 Layer* layer_to_receive_animation) { 357 proxy()->MainThreadTaskRunner()->PostTask( 358 FROM_HERE, 359 base::Bind(&LayerTreeTest::DispatchAddInstantAnimation, 360 main_thread_weak_ptr_, 361 base::Unretained(layer_to_receive_animation))); 362 } 363 364 void LayerTreeTest::PostSetNeedsCommitToMainThread() { 365 proxy()->MainThreadTaskRunner()->PostTask( 366 FROM_HERE, 367 base::Bind(&LayerTreeTest::DispatchSetNeedsCommit, 368 main_thread_weak_ptr_)); 369 } 370 371 void LayerTreeTest::PostAcquireLayerTextures() { 372 proxy()->MainThreadTaskRunner()->PostTask( 373 FROM_HERE, 374 base::Bind(&LayerTreeTest::DispatchAcquireLayerTextures, 375 main_thread_weak_ptr_)); 376 } 377 378 void LayerTreeTest::PostSetNeedsRedrawToMainThread() { 379 proxy()->MainThreadTaskRunner()->PostTask( 380 FROM_HERE, 381 base::Bind(&LayerTreeTest::DispatchSetNeedsRedraw, 382 main_thread_weak_ptr_)); 383 } 384 385 void LayerTreeTest::PostSetNeedsRedrawRectToMainThread(gfx::Rect damage_rect) { 386 proxy()->MainThreadTaskRunner()->PostTask( 387 FROM_HERE, 388 base::Bind(&LayerTreeTest::DispatchSetNeedsRedrawRect, 389 main_thread_weak_ptr_, damage_rect)); 390 } 391 392 void LayerTreeTest::PostSetVisibleToMainThread(bool visible) { 393 proxy()->MainThreadTaskRunner()->PostTask( 394 FROM_HERE, 395 base::Bind(&LayerTreeTest::DispatchSetVisible, 396 main_thread_weak_ptr_, 397 visible)); 398 } 399 400 void LayerTreeTest::DoBeginTest() { 401 client_ = LayerTreeHostClientForTesting::Create(this); 402 403 DCHECK(!impl_thread_ || impl_thread_->message_loop_proxy().get()); 404 layer_tree_host_ = LayerTreeHostForTesting::Create( 405 this, 406 client_.get(), 407 settings_, 408 impl_thread_ ? impl_thread_->message_loop_proxy() : NULL); 409 ASSERT_TRUE(layer_tree_host_); 410 411 started_ = true; 412 beginning_ = true; 413 SetupTree(); 414 layer_tree_host_->SetLayerTreeHostClientReady(); 415 BeginTest(); 416 beginning_ = false; 417 if (end_when_begin_returns_) 418 RealEndTest(); 419 420 // Allow commits to happen once BeginTest() has had a chance to post tasks 421 // so that those tasks will happen before the first commit. 422 if (layer_tree_host_) { 423 static_cast<LayerTreeHostForTesting*>(layer_tree_host_.get())-> 424 set_test_started(true); 425 } 426 } 427 428 void LayerTreeTest::SetupTree() { 429 if (!layer_tree_host_->root_layer()) { 430 scoped_refptr<Layer> root_layer = Layer::Create(); 431 root_layer->SetAnchorPoint(gfx::PointF()); 432 root_layer->SetBounds(gfx::Size(1, 1)); 433 root_layer->SetIsDrawable(true); 434 layer_tree_host_->SetRootLayer(root_layer); 435 } 436 437 gfx::Size root_bounds = layer_tree_host_->root_layer()->bounds(); 438 gfx::Size device_root_bounds = gfx::ToCeiledSize( 439 gfx::ScaleSize(root_bounds, layer_tree_host_->device_scale_factor())); 440 layer_tree_host_->SetViewportSize(device_root_bounds); 441 } 442 443 void LayerTreeTest::Timeout() { 444 timed_out_ = true; 445 EndTest(); 446 } 447 448 void LayerTreeTest::ScheduleComposite() { 449 if (!started_ || scheduled_) 450 return; 451 scheduled_ = true; 452 proxy()->MainThreadTaskRunner()->PostTask( 453 FROM_HERE, 454 base::Bind(&LayerTreeTest::DispatchComposite, main_thread_weak_ptr_)); 455 } 456 457 void LayerTreeTest::RealEndTest() { 458 if (layer_tree_host_ && proxy()->CommitPendingForTesting()) { 459 proxy()->MainThreadTaskRunner()->PostTask( 460 FROM_HERE, 461 base::Bind(&LayerTreeTest::RealEndTest, main_thread_weak_ptr_)); 462 return; 463 } 464 465 base::MessageLoop::current()->Quit(); 466 } 467 468 void LayerTreeTest::DispatchAddInstantAnimation( 469 Layer* layer_to_receive_animation) { 470 DCHECK(!proxy() || proxy()->IsMainThread()); 471 472 if (layer_to_receive_animation) { 473 AddOpacityTransitionToLayer(layer_to_receive_animation, 474 0, 475 0, 476 0.5, 477 false); 478 } 479 } 480 481 void LayerTreeTest::DispatchAddAnimation(Layer* layer_to_receive_animation) { 482 DCHECK(!proxy() || proxy()->IsMainThread()); 483 484 if (layer_to_receive_animation) { 485 AddOpacityTransitionToLayer(layer_to_receive_animation, 486 0.000001, 487 0, 488 0.5, 489 true); 490 } 491 } 492 493 void LayerTreeTest::DispatchSetNeedsCommit() { 494 DCHECK(!proxy() || proxy()->IsMainThread()); 495 496 if (layer_tree_host_) 497 layer_tree_host_->SetNeedsCommit(); 498 } 499 500 void LayerTreeTest::DispatchAcquireLayerTextures() { 501 DCHECK(!proxy() || proxy()->IsMainThread()); 502 503 if (layer_tree_host_) 504 layer_tree_host_->AcquireLayerTextures(); 505 } 506 507 void LayerTreeTest::DispatchSetNeedsRedraw() { 508 DCHECK(!proxy() || proxy()->IsMainThread()); 509 510 if (layer_tree_host_) 511 layer_tree_host_->SetNeedsRedraw(); 512 } 513 514 void LayerTreeTest::DispatchSetNeedsRedrawRect(gfx::Rect damage_rect) { 515 DCHECK(!proxy() || proxy()->IsMainThread()); 516 517 if (layer_tree_host_) 518 layer_tree_host_->SetNeedsRedrawRect(damage_rect); 519 } 520 521 void LayerTreeTest::DispatchSetVisible(bool visible) { 522 DCHECK(!proxy() || proxy()->IsMainThread()); 523 524 if (!layer_tree_host_) 525 return; 526 527 layer_tree_host_->SetVisible(visible); 528 529 // If the LTH is being made visible and a previous ScheduleComposite() was 530 // deferred because the LTH was not visible, re-schedule the composite now. 531 if (layer_tree_host_->visible() && schedule_when_set_visible_true_) 532 ScheduleComposite(); 533 } 534 535 void LayerTreeTest::DispatchComposite() { 536 scheduled_ = false; 537 538 if (!layer_tree_host_) 539 return; 540 541 // If the LTH is not visible, defer the composite until the LTH is made 542 // visible. 543 if (!layer_tree_host_->visible()) { 544 schedule_when_set_visible_true_ = true; 545 return; 546 } 547 548 schedule_when_set_visible_true_ = false; 549 base::TimeTicks now = base::TimeTicks::Now(); 550 layer_tree_host_->Composite(now); 551 } 552 553 void LayerTreeTest::RunTest(bool threaded, 554 bool delegating_renderer, 555 bool impl_side_painting) { 556 if (threaded) { 557 impl_thread_.reset(new base::Thread("Compositor")); 558 ASSERT_TRUE(impl_thread_->Start()); 559 } 560 561 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_ = 562 base::MessageLoopProxy::current(); 563 564 delegating_renderer_ = delegating_renderer; 565 566 // Spend less time waiting for BeginFrame because the output is 567 // mocked out. 568 settings_.refresh_rate = 200.0; 569 if (impl_side_painting) { 570 DCHECK(threaded) << 571 "Don't run single thread + impl side painting, it doesn't exist."; 572 settings_.impl_side_painting = true; 573 } 574 InitializeSettings(&settings_); 575 576 main_task_runner_->PostTask( 577 FROM_HERE, 578 base::Bind(&LayerTreeTest::DoBeginTest, base::Unretained(this))); 579 580 if (timeout_seconds_) { 581 timeout_.Reset(base::Bind(&LayerTreeTest::Timeout, base::Unretained(this))); 582 main_task_runner_->PostDelayedTask( 583 FROM_HERE, 584 timeout_.callback(), 585 base::TimeDelta::FromSeconds(timeout_seconds_)); 586 } 587 588 base::MessageLoop::current()->Run(); 589 if (layer_tree_host_ && layer_tree_host_->root_layer()) 590 layer_tree_host_->root_layer()->SetLayerTreeHost(NULL); 591 layer_tree_host_.reset(); 592 593 timeout_.Cancel(); 594 595 ASSERT_FALSE(layer_tree_host_.get()); 596 client_.reset(); 597 if (timed_out_) { 598 FAIL() << "Test timed out"; 599 return; 600 } 601 AfterTest(); 602 } 603 604 scoped_ptr<OutputSurface> LayerTreeTest::CreateOutputSurface(bool fallback) { 605 scoped_ptr<FakeOutputSurface> output_surface; 606 if (delegating_renderer_) 607 output_surface = FakeOutputSurface::CreateDelegating3d(); 608 else 609 output_surface = FakeOutputSurface::Create3d(); 610 output_surface_ = output_surface.get(); 611 return output_surface.PassAs<OutputSurface>(); 612 } 613 614 scoped_refptr<cc::ContextProvider> LayerTreeTest:: 615 OffscreenContextProviderForMainThread() { 616 if (!main_thread_contexts_.get() || 617 main_thread_contexts_->DestroyedOnMainThread()) { 618 main_thread_contexts_ = FakeContextProvider::Create(); 619 if (!main_thread_contexts_->BindToCurrentThread()) 620 main_thread_contexts_ = NULL; 621 } 622 return main_thread_contexts_; 623 } 624 625 scoped_refptr<cc::ContextProvider> LayerTreeTest:: 626 OffscreenContextProviderForCompositorThread() { 627 if (!compositor_thread_contexts_.get() || 628 compositor_thread_contexts_->DestroyedOnMainThread()) 629 compositor_thread_contexts_ = FakeContextProvider::Create(); 630 return compositor_thread_contexts_; 631 } 632 633 } // namespace cc 634