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.
5 #include "cc/test/layer_tree_test.h"
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/thread_impl.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_layer_tree_host_client.h"
19 #include "cc/test/fake_output_surface.h"
20 #include "cc/test/occlusion_tracker_test_common.h"
21 #include "cc/test/tiled_layer_test_common.h"
22 #include "cc/trees/layer_tree_host_impl.h"
23 #include "cc/trees/single_thread_proxy.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "ui/gfx/size_conversions.h"
29 TestHooks::TestHooks()
31 new FakeLayerTreeHostClient(FakeLayerTreeHostClient::DIRECT_3D
)) {}
33 TestHooks::~TestHooks() {}
35 bool TestHooks::PrepareToDrawOnThread(LayerTreeHostImpl
* host_impl
,
36 LayerTreeHostImpl::FrameData
* frame_data
,
41 bool TestHooks::CanActivatePendingTree() {
45 scoped_ptr
<OutputSurface
> TestHooks::CreateOutputSurface() {
46 return CreateFakeOutputSurface();
49 scoped_refptr
<cc::ContextProvider
> TestHooks::
50 OffscreenContextProviderForMainThread() {
51 return fake_client_
->OffscreenContextProviderForMainThread();
54 scoped_refptr
<cc::ContextProvider
> TestHooks::
55 OffscreenContextProviderForCompositorThread() {
56 return fake_client_
->OffscreenContextProviderForCompositorThread();
59 // Adapts LayerTreeHostImpl for test. Runs real code, then invokes test hooks.
60 class LayerTreeHostImplForTesting
: public LayerTreeHostImpl
{
62 static scoped_ptr
<LayerTreeHostImplForTesting
> Create(
63 TestHooks
* test_hooks
,
64 const LayerTreeSettings
& settings
,
65 LayerTreeHostImplClient
* host_impl_client
,
67 RenderingStatsInstrumentation
* stats_instrumentation
) {
68 return make_scoped_ptr(
69 new LayerTreeHostImplForTesting(test_hooks
,
73 stats_instrumentation
));
77 LayerTreeHostImplForTesting(
78 TestHooks
* test_hooks
,
79 const LayerTreeSettings
& settings
,
80 LayerTreeHostImplClient
* host_impl_client
,
82 RenderingStatsInstrumentation
* stats_instrumentation
)
83 : LayerTreeHostImpl(settings
,
86 stats_instrumentation
),
87 test_hooks_(test_hooks
) {}
89 virtual void BeginCommit() OVERRIDE
{
90 LayerTreeHostImpl::BeginCommit();
91 test_hooks_
->BeginCommitOnThread(this);
94 virtual void CommitComplete() OVERRIDE
{
95 LayerTreeHostImpl::CommitComplete();
96 test_hooks_
->CommitCompleteOnThread(this);
98 if (!settings().impl_side_painting
)
99 test_hooks_
->TreeActivatedOnThread(this);
102 virtual bool PrepareToDraw(FrameData
* frame
, gfx::Rect damage_rect
) OVERRIDE
{
103 bool result
= LayerTreeHostImpl::PrepareToDraw(frame
, damage_rect
);
104 if (!test_hooks_
->PrepareToDrawOnThread(this, frame
, result
))
109 virtual void DrawLayers(FrameData
* frame
,
110 base::TimeTicks frame_begin_time
) OVERRIDE
{
111 LayerTreeHostImpl::DrawLayers(frame
, frame_begin_time
);
112 test_hooks_
->DrawLayersOnThread(this);
115 virtual bool SwapBuffers(const LayerTreeHostImpl::FrameData
& frame
) OVERRIDE
{
116 bool result
= LayerTreeHostImpl::SwapBuffers(frame
);
117 test_hooks_
->SwapBuffersOnThread(this, result
);
121 virtual bool ActivatePendingTreeIfNeeded() OVERRIDE
{
125 if (!test_hooks_
->CanActivatePendingTree())
128 bool activated
= LayerTreeHostImpl::ActivatePendingTreeIfNeeded();
130 test_hooks_
->TreeActivatedOnThread(this);
134 virtual bool InitializeRenderer(scoped_ptr
<OutputSurface
> output_surface
)
136 bool success
= LayerTreeHostImpl::InitializeRenderer(output_surface
.Pass());
137 test_hooks_
->InitializedRendererOnThread(this, success
);
141 virtual void SetVisible(bool visible
) OVERRIDE
{
142 LayerTreeHostImpl::SetVisible(visible
);
143 test_hooks_
->DidSetVisibleOnImplTree(this, visible
);
146 virtual void AnimateLayers(base::TimeTicks monotonic_time
,
147 base::Time wall_clock_time
) OVERRIDE
{
148 test_hooks_
->WillAnimateLayers(this, monotonic_time
);
149 LayerTreeHostImpl::AnimateLayers(monotonic_time
, wall_clock_time
);
150 test_hooks_
->AnimateLayers(this, monotonic_time
);
153 virtual void UpdateAnimationState(bool start_ready_animations
) OVERRIDE
{
154 LayerTreeHostImpl::UpdateAnimationState(start_ready_animations
);
155 bool has_unfinished_animation
= false;
156 AnimationRegistrar::AnimationControllerMap::const_iterator iter
=
157 active_animation_controllers().begin();
158 for (; iter
!= active_animation_controllers().end(); ++iter
) {
159 if (iter
->second
->HasActiveAnimation()) {
160 has_unfinished_animation
= true;
164 test_hooks_
->UpdateAnimationState(this, has_unfinished_animation
);
167 virtual base::TimeDelta
LowFrequencyAnimationInterval() const OVERRIDE
{
168 return base::TimeDelta::FromMilliseconds(16);
172 TestHooks
* test_hooks_
;
175 // Adapts LayerTreeHost for test. Injects LayerTreeHostImplForTesting.
176 class LayerTreeHostForTesting
: public cc::LayerTreeHost
{
178 static scoped_ptr
<LayerTreeHostForTesting
> Create(
179 TestHooks
* test_hooks
,
180 cc::LayerTreeHostClient
* host_client
,
181 const cc::LayerTreeSettings
& settings
,
182 scoped_ptr
<cc::Thread
> impl_thread
) {
183 scoped_ptr
<LayerTreeHostForTesting
> layer_tree_host(
184 new LayerTreeHostForTesting(test_hooks
, host_client
, settings
));
185 bool success
= layer_tree_host
->Initialize(impl_thread
.Pass());
186 EXPECT_TRUE(success
);
187 return layer_tree_host
.Pass();
190 virtual scoped_ptr
<cc::LayerTreeHostImpl
> CreateLayerTreeHostImpl(
191 cc::LayerTreeHostImplClient
* host_impl_client
) OVERRIDE
{
192 return LayerTreeHostImplForTesting::Create(
197 rendering_stats_instrumentation()).PassAs
<cc::LayerTreeHostImpl
>();
200 virtual void SetNeedsCommit() OVERRIDE
{
203 LayerTreeHost::SetNeedsCommit();
206 void set_test_started(bool started
) { test_started_
= started
; }
208 virtual void DidDeferCommit() OVERRIDE
{
209 test_hooks_
->DidDeferCommit();
213 LayerTreeHostForTesting(TestHooks
* test_hooks
,
214 cc::LayerTreeHostClient
* client
,
215 const cc::LayerTreeSettings
& settings
)
216 : LayerTreeHost(client
, settings
),
217 test_hooks_(test_hooks
),
218 test_started_(false) {}
220 TestHooks
* test_hooks_
;
224 // Implementation of LayerTreeHost callback interface.
225 class LayerTreeHostClientForTesting
: public LayerTreeHostClient
{
227 static scoped_ptr
<LayerTreeHostClientForTesting
> Create(
228 TestHooks
* test_hooks
) {
229 return make_scoped_ptr(new LayerTreeHostClientForTesting(test_hooks
));
231 virtual ~LayerTreeHostClientForTesting() {}
233 virtual void WillBeginFrame() OVERRIDE
{}
235 virtual void DidBeginFrame() OVERRIDE
{}
237 virtual void Animate(double monotonic_time
) OVERRIDE
{
238 test_hooks_
->Animate(base::TimeTicks::FromInternalValue(
239 monotonic_time
* base::Time::kMicrosecondsPerSecond
));
242 virtual void Layout() OVERRIDE
{
243 test_hooks_
->Layout();
246 virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta
,
247 float scale
) OVERRIDE
{
248 test_hooks_
->ApplyScrollAndScale(scroll_delta
, scale
);
251 virtual scoped_ptr
<OutputSurface
> CreateOutputSurface() OVERRIDE
{
252 return test_hooks_
->CreateOutputSurface();
255 virtual void DidRecreateOutputSurface(bool succeeded
) OVERRIDE
{
256 test_hooks_
->DidRecreateOutputSurface(succeeded
);
259 virtual void WillRetryRecreateOutputSurface() OVERRIDE
{
260 test_hooks_
->WillRetryRecreateOutputSurface();
263 virtual scoped_ptr
<InputHandler
> CreateInputHandler() OVERRIDE
{
264 return scoped_ptr
<InputHandler
>();
267 virtual void WillCommit() OVERRIDE
{}
269 virtual void DidCommit() OVERRIDE
{
270 test_hooks_
->DidCommit();
273 virtual void DidCommitAndDrawFrame() OVERRIDE
{
274 test_hooks_
->DidCommitAndDrawFrame();
277 virtual void DidCompleteSwapBuffers() OVERRIDE
{}
279 virtual void ScheduleComposite() OVERRIDE
{
280 test_hooks_
->ScheduleComposite();
283 virtual scoped_refptr
<cc::ContextProvider
>
284 OffscreenContextProviderForMainThread() OVERRIDE
{
285 return test_hooks_
->OffscreenContextProviderForMainThread();
288 virtual scoped_refptr
<cc::ContextProvider
>
289 OffscreenContextProviderForCompositorThread() OVERRIDE
{
290 return test_hooks_
->OffscreenContextProviderForCompositorThread();
294 explicit LayerTreeHostClientForTesting(TestHooks
* test_hooks
)
295 : test_hooks_(test_hooks
) {}
297 TestHooks
* test_hooks_
;
300 LayerTreeTest::LayerTreeTest()
302 end_when_begin_returns_(false),
305 schedule_when_set_visible_true_(false),
310 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
311 main_thread_weak_ptr_
= weak_factory_
.GetWeakPtr();
313 // Tests should timeout quickly unless --cc-layer-tree-test-no-timeout was
314 // specified (for running in a debugger).
315 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
316 if (!command_line
->HasSwitch("cc-layer-tree-test-no-timeout"))
317 timeout_seconds_
= 5;
320 LayerTreeTest::~LayerTreeTest() {}
322 void LayerTreeTest::EndTest() {
323 // For the case where we EndTest during BeginTest(), set a flag to indicate
324 // that the test should end the second BeginTest regains control.
326 end_when_begin_returns_
= true;
327 } else if (proxy()) {
328 // Racy timeouts and explicit EndTest calls might have cleaned up
329 // the tree host. Should check proxy first.
330 proxy()->MainThread()->PostTask(
331 base::Bind(&LayerTreeTest::RealEndTest
, main_thread_weak_ptr_
));
335 void LayerTreeTest::EndTestAfterDelay(int delay_milliseconds
) {
336 proxy()->MainThread()->PostTask(
337 base::Bind(&LayerTreeTest::EndTest
, main_thread_weak_ptr_
));
340 void LayerTreeTest::PostAddAnimationToMainThread(
341 Layer
* layer_to_receive_animation
) {
342 proxy()->MainThread()->PostTask(
343 base::Bind(&LayerTreeTest::DispatchAddAnimation
,
344 main_thread_weak_ptr_
,
345 base::Unretained(layer_to_receive_animation
)));
348 void LayerTreeTest::PostAddInstantAnimationToMainThread(
349 Layer
* layer_to_receive_animation
) {
350 proxy()->MainThread()->PostTask(
351 base::Bind(&LayerTreeTest::DispatchAddInstantAnimation
,
352 main_thread_weak_ptr_
,
353 base::Unretained(layer_to_receive_animation
)));
356 void LayerTreeTest::PostSetNeedsCommitToMainThread() {
357 proxy()->MainThread()->PostTask(
358 base::Bind(&LayerTreeTest::DispatchSetNeedsCommit
,
359 main_thread_weak_ptr_
));
362 void LayerTreeTest::PostAcquireLayerTextures() {
363 proxy()->MainThread()->PostTask(
364 base::Bind(&LayerTreeTest::DispatchAcquireLayerTextures
,
365 main_thread_weak_ptr_
));
368 void LayerTreeTest::PostSetNeedsRedrawToMainThread() {
369 proxy()->MainThread()->PostTask(
370 base::Bind(&LayerTreeTest::DispatchSetNeedsRedraw
,
371 main_thread_weak_ptr_
));
374 void LayerTreeTest::PostSetNeedsRedrawRectToMainThread(
375 const gfx::Rect
& damage_rect
) {
376 proxy()->MainThread()->PostTask(
377 base::Bind(&LayerTreeTest::DispatchSetNeedsRedrawRect
,
378 main_thread_weak_ptr_
, damage_rect
));
381 void LayerTreeTest::PostSetVisibleToMainThread(bool visible
) {
382 proxy()->MainThread()->PostTask(
383 base::Bind(&LayerTreeTest::DispatchSetVisible
,
384 main_thread_weak_ptr_
,
388 void LayerTreeTest::DoBeginTest() {
389 client_
= LayerTreeHostClientForTesting::Create(this);
391 scoped_ptr
<cc::Thread
> impl_ccthread(NULL
);
393 impl_ccthread
= cc::ThreadImpl::CreateForDifferentThread(
394 impl_thread_
->message_loop_proxy());
396 layer_tree_host_
= LayerTreeHostForTesting::Create(this,
399 impl_ccthread
.Pass());
400 ASSERT_TRUE(layer_tree_host_
);
405 layer_tree_host_
->SetSurfaceReady();
408 if (end_when_begin_returns_
)
411 // Allow commits to happen once BeginTest() has had a chance to post tasks
412 // so that those tasks will happen before the first commit.
413 if (layer_tree_host_
) {
414 static_cast<LayerTreeHostForTesting
*>(layer_tree_host_
.get())->
415 set_test_started(true);
419 void LayerTreeTest::SetupTree() {
420 if (!layer_tree_host_
->root_layer()) {
421 scoped_refptr
<Layer
> root_layer
= Layer::Create();
422 root_layer
->SetAnchorPoint(gfx::PointF());
423 root_layer
->SetBounds(gfx::Size(1, 1));
424 root_layer
->SetIsDrawable(true);
425 layer_tree_host_
->SetRootLayer(root_layer
);
428 gfx::Size root_bounds
= layer_tree_host_
->root_layer()->bounds();
429 gfx::Size device_root_bounds
= gfx::ToCeiledSize(
430 gfx::ScaleSize(root_bounds
, layer_tree_host_
->device_scale_factor()));
431 layer_tree_host_
->SetViewportSize(device_root_bounds
);
434 void LayerTreeTest::Timeout() {
439 void LayerTreeTest::ScheduleComposite() {
440 if (!started_
|| scheduled_
)
443 proxy()->MainThread()->PostTask(
444 base::Bind(&LayerTreeTest::DispatchComposite
, main_thread_weak_ptr_
));
447 void LayerTreeTest::RealEndTest() {
450 if (layer_tree_host_
&& proxy()->CommitPendingForTesting()) {
451 proxy()->MainThread()->PostTask(
452 base::Bind(&LayerTreeTest::RealEndTest
, main_thread_weak_ptr_
));
456 MessageLoop::current()->Quit();
459 void LayerTreeTest::DispatchAddInstantAnimation(
460 Layer
* layer_to_receive_animation
) {
461 DCHECK(!proxy() || proxy()->IsMainThread());
463 if (layer_to_receive_animation
) {
464 AddOpacityTransitionToLayer(layer_to_receive_animation
,
472 void LayerTreeTest::DispatchAddAnimation(Layer
* layer_to_receive_animation
) {
473 DCHECK(!proxy() || proxy()->IsMainThread());
475 if (layer_to_receive_animation
) {
476 AddOpacityTransitionToLayer(layer_to_receive_animation
,
484 void LayerTreeTest::DispatchSetNeedsCommit() {
485 DCHECK(!proxy() || proxy()->IsMainThread());
487 if (layer_tree_host_
)
488 layer_tree_host_
->SetNeedsCommit();
491 void LayerTreeTest::DispatchAcquireLayerTextures() {
492 DCHECK(!proxy() || proxy()->IsMainThread());
494 if (layer_tree_host_
)
495 layer_tree_host_
->AcquireLayerTextures();
498 void LayerTreeTest::DispatchSetNeedsRedraw() {
499 DCHECK(!proxy() || proxy()->IsMainThread());
501 if (layer_tree_host_
)
502 layer_tree_host_
->SetNeedsRedraw();
505 void LayerTreeTest::DispatchSetNeedsRedrawRect(const gfx::Rect
& damage_rect
) {
506 DCHECK(!proxy() || proxy()->IsMainThread());
508 if (layer_tree_host_
)
509 layer_tree_host_
->SetNeedsRedrawRect(damage_rect
);
512 void LayerTreeTest::DispatchSetVisible(bool visible
) {
513 DCHECK(!proxy() || proxy()->IsMainThread());
515 if (!layer_tree_host_
)
518 layer_tree_host_
->SetVisible(visible
);
520 // If the LTH is being made visible and a previous ScheduleComposite() was
521 // deferred because the LTH was not visible, re-schedule the composite now.
522 if (layer_tree_host_
->visible() && schedule_when_set_visible_true_
)
526 void LayerTreeTest::DispatchComposite() {
529 if (!layer_tree_host_
)
532 // If the LTH is not visible, defer the composite until the LTH is made
534 if (!layer_tree_host_
->visible()) {
535 schedule_when_set_visible_true_
= true;
539 schedule_when_set_visible_true_
= false;
540 base::TimeTicks now
= base::TimeTicks::Now();
541 layer_tree_host_
->UpdateAnimations(now
);
542 layer_tree_host_
->Composite(now
);
545 void LayerTreeTest::RunTest(bool threaded
) {
547 impl_thread_
.reset(new base::Thread("LayerTreeTest"));
548 ASSERT_TRUE(impl_thread_
->Start());
551 main_ccthread_
= cc::ThreadImpl::CreateForCurrentThread();
553 // Spend less time waiting for vsync because the output is mocked out.
554 settings_
.refresh_rate
= 200.0;
555 InitializeSettings(&settings_
);
557 main_ccthread_
->PostTask(
558 base::Bind(&LayerTreeTest::DoBeginTest
, base::Unretained(this)));
560 if (timeout_seconds_
) {
561 timeout_
.Reset(base::Bind(&LayerTreeTest::Timeout
, base::Unretained(this)));
562 main_ccthread_
->PostDelayedTask(
564 base::TimeDelta::FromSeconds(timeout_seconds_
));
567 MessageLoop::current()->Run();
568 if (layer_tree_host_
&& layer_tree_host_
->root_layer())
569 layer_tree_host_
->root_layer()->SetLayerTreeHost(NULL
);
570 layer_tree_host_
.reset();
574 ASSERT_FALSE(layer_tree_host_
.get());
577 FAIL() << "Test timed out";