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