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"
7 #include "base/basictypes.h"
8 #include "cc/layers/content_layer.h"
9 #include "cc/layers/heads_up_display_layer.h"
10 #include "cc/layers/io_surface_layer.h"
11 #include "cc/layers/layer_impl.h"
12 #include "cc/layers/picture_layer.h"
13 #include "cc/layers/scrollbar_layer.h"
14 #include "cc/layers/texture_layer.h"
15 #include "cc/layers/video_layer.h"
16 #include "cc/layers/video_layer_impl.h"
17 #include "cc/test/fake_content_layer.h"
18 #include "cc/test/fake_content_layer_client.h"
19 #include "cc/test/fake_content_layer_impl.h"
20 #include "cc/test/fake_context_provider.h"
21 #include "cc/test/fake_delegated_renderer_layer.h"
22 #include "cc/test/fake_delegated_renderer_layer_impl.h"
23 #include "cc/test/fake_output_surface.h"
24 #include "cc/test/fake_scrollbar_layer.h"
25 #include "cc/test/fake_scrollbar_theme_painter.h"
26 #include "cc/test/fake_video_frame_provider.h"
27 #include "cc/test/fake_web_scrollbar.h"
28 #include "cc/test/fake_web_scrollbar_theme_geometry.h"
29 #include "cc/test/layer_tree_test.h"
30 #include "cc/test/render_pass_test_common.h"
31 #include "cc/test/test_web_graphics_context_3d.h"
32 #include "cc/trees/layer_tree_host_impl.h"
33 #include "cc/trees/layer_tree_impl.h"
34 #include "cc/trees/single_thread_proxy.h"
35 #include "gpu/GLES2/gl2extchromium.h"
36 #include "media/base/media.h"
37 #include "third_party/WebKit/Source/Platform/chromium/public/WebFilterOperations.h"
39 using media::VideoFrame
;
40 using WebKit::WebGraphicsContext3D
;
45 // These tests deal with losing the 3d graphics context.
46 class LayerTreeHostContextTest
: public LayerTreeTest
{
48 LayerTreeHostContextTest()
51 times_to_fail_create_(0),
52 times_to_fail_initialize_(0),
53 times_to_lose_on_create_(0),
54 times_to_lose_during_commit_(0),
55 times_to_lose_during_draw_(0),
56 times_to_fail_recreate_(0),
57 times_to_fail_reinitialize_(0),
58 times_to_lose_on_recreate_(0),
59 times_to_fail_create_offscreen_(0),
60 times_to_fail_recreate_offscreen_(0),
61 times_to_expect_recreate_retried_(0),
62 times_recreate_retried_(0),
63 times_offscreen_created_(0),
64 committed_at_least_once_(false) {
65 media::InitializeMediaLibraryForTesting();
69 context3d_
->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB
,
70 GL_INNOCENT_CONTEXT_RESET_ARB
);
74 virtual scoped_ptr
<TestWebGraphicsContext3D
> CreateContext3d() {
75 return TestWebGraphicsContext3D::Create();
78 virtual scoped_ptr
<OutputSurface
> CreateOutputSurface() OVERRIDE
{
79 if (times_to_fail_create_
) {
80 --times_to_fail_create_
;
81 ExpectRecreateToRetry();
82 return scoped_ptr
<OutputSurface
>();
85 scoped_ptr
<TestWebGraphicsContext3D
> context3d
= CreateContext3d();
86 context3d_
= context3d
.get();
88 if (times_to_fail_initialize_
) {
89 --times_to_fail_initialize_
;
90 // Make the context get lost during reinitialization.
91 // The number of times MakeCurrent succeeds is not important, and
92 // can be changed if needed to make this pass with future changes.
93 context3d_
->set_times_make_current_succeeds(2);
94 ExpectRecreateToRetry();
95 } else if (times_to_lose_on_create_
) {
96 --times_to_lose_on_create_
;
98 ExpectRecreateToRetry();
101 return FakeOutputSurface::Create3d(
102 context3d
.PassAs
<WebGraphicsContext3D
>()).PassAs
<OutputSurface
>();
105 scoped_ptr
<TestWebGraphicsContext3D
> CreateOffscreenContext3d() {
107 return scoped_ptr
<TestWebGraphicsContext3D
>();
109 ++times_offscreen_created_
;
111 if (times_to_fail_create_offscreen_
) {
112 --times_to_fail_create_offscreen_
;
113 ExpectRecreateToRetry();
114 return scoped_ptr
<TestWebGraphicsContext3D
>();
117 scoped_ptr
<TestWebGraphicsContext3D
> offscreen_context3d
=
118 TestWebGraphicsContext3D::Create().Pass();
119 DCHECK(offscreen_context3d
);
120 context3d_
->add_share_group_context(offscreen_context3d
.get());
122 return offscreen_context3d
.Pass();
125 virtual scoped_refptr
<cc::ContextProvider
>
126 OffscreenContextProviderForMainThread() OVERRIDE
{
127 DCHECK(!ImplThread());
129 if (!offscreen_contexts_main_thread_
||
130 offscreen_contexts_main_thread_
->DestroyedOnMainThread()) {
131 offscreen_contexts_main_thread_
= FakeContextProvider::Create(
132 base::Bind(&LayerTreeHostContextTest::CreateOffscreenContext3d
,
133 base::Unretained(this)));
134 if (offscreen_contexts_main_thread_
&&
135 !offscreen_contexts_main_thread_
->BindToCurrentThread())
136 offscreen_contexts_main_thread_
= NULL
;
138 return offscreen_contexts_main_thread_
;
141 virtual scoped_refptr
<cc::ContextProvider
>
142 OffscreenContextProviderForCompositorThread() OVERRIDE
{
143 DCHECK(ImplThread());
145 if (!offscreen_contexts_compositor_thread_
||
146 offscreen_contexts_compositor_thread_
->DestroyedOnMainThread()) {
147 offscreen_contexts_compositor_thread_
= FakeContextProvider::Create(
148 base::Bind(&LayerTreeHostContextTest::CreateOffscreenContext3d
,
149 base::Unretained(this)));
151 return offscreen_contexts_compositor_thread_
;
154 virtual bool PrepareToDrawOnThread(LayerTreeHostImpl
* host_impl
,
155 LayerTreeHostImpl::FrameData
* frame
,
158 bool expect_success
= !frame
->has_no_damage
;
159 EXPECT_EQ(expect_success
, result
);
160 if (!times_to_lose_during_draw_
)
163 --times_to_lose_during_draw_
;
164 context3d_
->set_times_make_current_succeeds(0);
166 times_to_fail_create_
= times_to_fail_recreate_
;
167 times_to_fail_recreate_
= 0;
168 times_to_fail_initialize_
= times_to_fail_reinitialize_
;
169 times_to_fail_reinitialize_
= 0;
170 times_to_lose_on_create_
= times_to_lose_on_recreate_
;
171 times_to_lose_on_recreate_
= 0;
172 times_to_fail_create_offscreen_
= times_to_fail_recreate_offscreen_
;
173 times_to_fail_recreate_offscreen_
= 0;
178 virtual void CommitCompleteOnThread(LayerTreeHostImpl
* host_impl
) OVERRIDE
{
179 committed_at_least_once_
= true;
181 if (!times_to_lose_during_commit_
)
183 --times_to_lose_during_commit_
;
186 times_to_fail_create_
= times_to_fail_recreate_
;
187 times_to_fail_recreate_
= 0;
188 times_to_fail_initialize_
= times_to_fail_reinitialize_
;
189 times_to_fail_reinitialize_
= 0;
190 times_to_lose_on_create_
= times_to_lose_on_recreate_
;
191 times_to_lose_on_recreate_
= 0;
192 times_to_fail_create_offscreen_
= times_to_fail_recreate_offscreen_
;
193 times_to_fail_recreate_offscreen_
= 0;
196 virtual void WillRetryRecreateOutputSurface() OVERRIDE
{
197 ++times_recreate_retried_
;
200 virtual void TearDown() OVERRIDE
{
201 LayerTreeTest::TearDown();
202 EXPECT_EQ(times_to_expect_recreate_retried_
, times_recreate_retried_
);
205 void ExpectRecreateToRetry() {
206 if (committed_at_least_once_
)
207 ++times_to_expect_recreate_retried_
;
211 TestWebGraphicsContext3D
* context3d_
;
212 int times_to_fail_create_
;
213 int times_to_fail_initialize_
;
214 int times_to_lose_on_create_
;
215 int times_to_lose_during_commit_
;
216 int times_to_lose_during_draw_
;
217 int times_to_fail_recreate_
;
218 int times_to_fail_reinitialize_
;
219 int times_to_lose_on_recreate_
;
220 int times_to_fail_create_offscreen_
;
221 int times_to_fail_recreate_offscreen_
;
222 int times_to_expect_recreate_retried_
;
223 int times_recreate_retried_
;
224 int times_offscreen_created_
;
225 bool committed_at_least_once_
;
227 scoped_refptr
<FakeContextProvider
> offscreen_contexts_main_thread_
;
228 scoped_refptr
<FakeContextProvider
> offscreen_contexts_compositor_thread_
;
231 class LayerTreeHostContextTestLostContextSucceeds
232 : public LayerTreeHostContextTest
{
234 LayerTreeHostContextTestLostContextSucceeds()
235 : LayerTreeHostContextTest(),
238 recovered_context_(true) {}
240 virtual void BeginTest() OVERRIDE
{
241 PostSetNeedsCommitToMainThread();
244 virtual void DidRecreateOutputSurface(bool succeeded
) OVERRIDE
{
245 EXPECT_TRUE(succeeded
);
247 recovered_context_
= true;
250 virtual void AfterTest() OVERRIDE
{
251 EXPECT_EQ(10u, test_case_
);
252 EXPECT_EQ(8 + 10 + 10, num_losses_
);
255 virtual void DidCommitAndDrawFrame() OVERRIDE
{
256 // If the last frame had a context loss, then we'll commit again to
258 if (!recovered_context_
)
260 if (times_to_lose_during_commit_
)
262 if (times_to_lose_during_draw_
)
265 recovered_context_
= false;
267 InvalidateAndSetNeedsCommit();
272 virtual void InvalidateAndSetNeedsCommit() {
273 // Cause damage so we try to draw.
274 layer_tree_host()->root_layer()->SetNeedsDisplay();
277 bool NextTestCase() {
278 static const TestCase kTests
[] = {
279 // Losing the context and failing to recreate it (or losing it again
280 // immediately) a small number of times should succeed.
281 { 1, // times_to_lose_during_commit
282 0, // times_to_lose_during_draw
283 3, // times_to_fail_reinitialize
284 0, // times_to_fail_recreate
285 0, // times_to_lose_on_recreate
286 0, // times_to_fail_recreate_offscreen
288 { 0, // times_to_lose_during_commit
289 1, // times_to_lose_during_draw
290 3, // times_to_fail_reinitialize
291 0, // times_to_fail_recreate
292 0, // times_to_lose_on_recreate
293 0, // times_to_fail_recreate_offscreen
295 { 1, // times_to_lose_during_commit
296 0, // times_to_lose_during_draw
297 0, // times_to_fail_reinitialize
298 3, // times_to_fail_recreate
299 0, // times_to_lose_on_recreate
300 0, // times_to_fail_recreate_offscreen
302 { 0, // times_to_lose_during_commit
303 1, // times_to_lose_during_draw
304 0, // times_to_fail_reinitialize
305 3, // times_to_fail_recreate
306 0, // times_to_lose_on_recreate
307 0, // times_to_fail_recreate_offscreen
309 { 1, // times_to_lose_during_commit
310 0, // times_to_lose_during_draw
311 0, // times_to_fail_reinitialize
312 0, // times_to_fail_recreate
313 3, // times_to_lose_on_recreate
314 0, // times_to_fail_recreate_offscreen
316 { 0, // times_to_lose_during_commit
317 1, // times_to_lose_during_draw
318 0, // times_to_fail_reinitialize
319 0, // times_to_fail_recreate
320 3, // times_to_lose_on_recreate
321 0, // times_to_fail_recreate_offscreen
323 { 1, // times_to_lose_during_commit
324 0, // times_to_lose_during_draw
325 0, // times_to_fail_reinitialize
326 0, // times_to_fail_recreate
327 0, // times_to_lose_on_recreate
328 3, // times_to_fail_recreate_offscreen
330 { 0, // times_to_lose_during_commit
331 1, // times_to_lose_during_draw
332 0, // times_to_fail_reinitialize
333 0, // times_to_fail_recreate
334 0, // times_to_lose_on_recreate
335 3, // times_to_fail_recreate_offscreen
337 // Losing the context and recreating it any number of times should
339 { 10, // times_to_lose_during_commit
340 0, // times_to_lose_during_draw
341 0, // times_to_fail_reinitialize
342 0, // times_to_fail_recreate
343 0, // times_to_lose_on_recreate
344 0, // times_to_fail_recreate_offscreen
346 { 0, // times_to_lose_during_commit
347 10, // times_to_lose_during_draw
348 0, // times_to_fail_reinitialize
349 0, // times_to_fail_recreate
350 0, // times_to_lose_on_recreate
351 0, // times_to_fail_recreate_offscreen
355 if (test_case_
>= arraysize(kTests
))
358 times_to_lose_during_commit_
=
359 kTests
[test_case_
].times_to_lose_during_commit
;
360 times_to_lose_during_draw_
=
361 kTests
[test_case_
].times_to_lose_during_draw
;
362 times_to_fail_reinitialize_
= kTests
[test_case_
].times_to_fail_reinitialize
;
363 times_to_fail_recreate_
= kTests
[test_case_
].times_to_fail_recreate
;
364 times_to_lose_on_recreate_
= kTests
[test_case_
].times_to_lose_on_recreate
;
365 times_to_fail_recreate_offscreen_
=
366 kTests
[test_case_
].times_to_fail_recreate_offscreen
;
372 int times_to_lose_during_commit
;
373 int times_to_lose_during_draw
;
374 int times_to_fail_reinitialize
;
375 int times_to_fail_recreate
;
376 int times_to_lose_on_recreate
;
377 int times_to_fail_recreate_offscreen
;
383 bool recovered_context_
;
386 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLostContextSucceeds
);
388 class LayerTreeHostContextTestLostContextSucceedsWithContent
389 : public LayerTreeHostContextTestLostContextSucceeds
{
391 LayerTreeHostContextTestLostContextSucceedsWithContent()
392 : LayerTreeHostContextTestLostContextSucceeds() {}
394 virtual void SetupTree() OVERRIDE
{
395 root_
= Layer::Create();
396 root_
->SetBounds(gfx::Size(10, 10));
397 root_
->SetAnchorPoint(gfx::PointF());
398 root_
->SetIsDrawable(true);
400 content_
= FakeContentLayer::Create(&client_
);
401 content_
->SetBounds(gfx::Size(10, 10));
402 content_
->SetAnchorPoint(gfx::PointF());
403 content_
->SetIsDrawable(true);
405 content_
->SetForceRenderSurface(true);
406 // Filters require us to create an offscreen context.
407 WebKit::WebFilterOperations filters
;
408 filters
.append(WebKit::WebFilterOperation::createGrayscaleFilter(0.5f
));
409 content_
->SetFilters(filters
);
410 content_
->SetBackgroundFilters(filters
);
413 root_
->AddChild(content_
);
415 layer_tree_host()->SetRootLayer(root_
);
416 LayerTreeHostContextTest::SetupTree();
419 virtual void InvalidateAndSetNeedsCommit() OVERRIDE
{
420 // Invalidate the render surface so we don't try to use a cached copy of the
421 // surface. We want to make sure to test the drawing paths for drawing to
423 content_
->SetNeedsDisplay();
424 LayerTreeHostContextTestLostContextSucceeds::InvalidateAndSetNeedsCommit();
427 virtual void DrawLayersOnThread(LayerTreeHostImpl
* host_impl
) OVERRIDE
{
428 FakeContentLayerImpl
* content_impl
= static_cast<FakeContentLayerImpl
*>(
429 host_impl
->active_tree()->root_layer()->children()[0]);
430 // Even though the context was lost, we should have a resource. The
431 // TestWebGraphicsContext3D ensures that this resource is created with
432 // the active context.
433 EXPECT_TRUE(content_impl
->HaveResourceForTileAt(0, 0));
435 cc::ContextProvider
* contexts
=
436 host_impl
->resource_provider()->offscreen_context_provider();
438 EXPECT_TRUE(contexts
->Context3d());
439 // TODO(danakj): Make a fake GrContext.
440 // EXPECT_TRUE(contexts->GrContext());
442 EXPECT_FALSE(contexts
);
446 virtual void AfterTest() OVERRIDE
{
447 LayerTreeHostContextTestLostContextSucceeds::AfterTest();
449 // 1 create to start with +
450 // 6 from test cases that fail on initializing the renderer (after the
451 // offscreen context is created) +
452 // 6 from test cases that lose the offscreen context directly +
453 // All the test cases that recreate both contexts only once
454 // per time it is lost.
455 EXPECT_EQ(6 + 6 + 1 + num_losses_
, times_offscreen_created_
);
457 EXPECT_EQ(0, times_offscreen_created_
);
463 FakeContentLayerClient client_
;
464 scoped_refptr
<Layer
> root_
;
465 scoped_refptr
<ContentLayer
> content_
;
468 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent
,
469 NoSurface_SingleThread
) {
470 use_surface_
= false;
474 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent
,
475 NoSurface_MultiThread
) {
476 use_surface_
= false;
480 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent
,
481 WithSurface_SingleThread
) {
486 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent
,
487 WithSurface_MultiThread
) {
492 class LayerTreeHostContextTestOffscreenContextFails
493 : public LayerTreeHostContextTest
{
495 virtual void SetupTree() OVERRIDE
{
496 root_
= Layer::Create();
497 root_
->SetBounds(gfx::Size(10, 10));
498 root_
->SetAnchorPoint(gfx::PointF());
499 root_
->SetIsDrawable(true);
501 content_
= FakeContentLayer::Create(&client_
);
502 content_
->SetBounds(gfx::Size(10, 10));
503 content_
->SetAnchorPoint(gfx::PointF());
504 content_
->SetIsDrawable(true);
505 content_
->SetForceRenderSurface(true);
506 // Filters require us to create an offscreen context.
507 WebKit::WebFilterOperations filters
;
508 filters
.append(WebKit::WebFilterOperation::createGrayscaleFilter(0.5f
));
509 content_
->SetFilters(filters
);
510 content_
->SetBackgroundFilters(filters
);
512 root_
->AddChild(content_
);
514 layer_tree_host()->SetRootLayer(root_
);
515 LayerTreeHostContextTest::SetupTree();
518 virtual void BeginTest() OVERRIDE
{
519 times_to_fail_create_offscreen_
= 1;
520 PostSetNeedsCommitToMainThread();
523 virtual void DrawLayersOnThread(LayerTreeHostImpl
* host_impl
) OVERRIDE
{
524 cc::ContextProvider
* contexts
=
525 host_impl
->resource_provider()->offscreen_context_provider();
526 EXPECT_FALSE(contexts
);
530 virtual void AfterTest() OVERRIDE
{}
533 FakeContentLayerClient client_
;
534 scoped_refptr
<Layer
> root_
;
535 scoped_refptr
<ContentLayer
> content_
;
538 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestOffscreenContextFails
);
540 class LayerTreeHostContextTestLostContextFails
541 : public LayerTreeHostContextTest
{
543 LayerTreeHostContextTestLostContextFails()
544 : LayerTreeHostContextTest(),
546 times_to_lose_during_commit_
= 1;
549 virtual void BeginTest() OVERRIDE
{
550 PostSetNeedsCommitToMainThread();
553 virtual void DidRecreateOutputSurface(bool succeeded
) OVERRIDE
{
554 EXPECT_FALSE(succeeded
);
558 virtual void CommitCompleteOnThread(LayerTreeHostImpl
* host_impl
) OVERRIDE
{
559 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl
);
562 if (num_commits_
== 1) {
563 // When the context is ok, we should have these things.
564 EXPECT_TRUE(host_impl
->output_surface());
565 EXPECT_TRUE(host_impl
->renderer());
566 EXPECT_TRUE(host_impl
->resource_provider());
570 // When context recreation fails we shouldn't be left with any of them.
571 EXPECT_FALSE(host_impl
->output_surface());
572 EXPECT_FALSE(host_impl
->renderer());
573 EXPECT_FALSE(host_impl
->resource_provider());
576 virtual void AfterTest() OVERRIDE
{}
582 TEST_F(LayerTreeHostContextTestLostContextFails
,
583 FailReinitialize100_SingleThread
) {
584 times_to_fail_reinitialize_
= 100;
585 times_to_fail_recreate_
= 0;
586 times_to_lose_on_recreate_
= 0;
590 TEST_F(LayerTreeHostContextTestLostContextFails
,
591 FailReinitialize100_MultiThread
) {
592 times_to_fail_reinitialize_
= 100;
593 times_to_fail_recreate_
= 0;
594 times_to_lose_on_recreate_
= 0;
598 TEST_F(LayerTreeHostContextTestLostContextFails
,
599 FailRecreate100_SingleThread
) {
600 times_to_fail_reinitialize_
= 0;
601 times_to_fail_recreate_
= 100;
602 times_to_lose_on_recreate_
= 0;
606 TEST_F(LayerTreeHostContextTestLostContextFails
,
607 FailRecreate100_MultiThread
) {
608 times_to_fail_reinitialize_
= 0;
609 times_to_fail_recreate_
= 100;
610 times_to_lose_on_recreate_
= 0;
614 TEST_F(LayerTreeHostContextTestLostContextFails
,
615 LoseOnRecreate100_SingleThread
) {
616 times_to_fail_reinitialize_
= 0;
617 times_to_fail_recreate_
= 0;
618 times_to_lose_on_recreate_
= 100;
622 TEST_F(LayerTreeHostContextTestLostContextFails
,
623 LoseOnRecreate100_MultiThread
) {
624 times_to_fail_reinitialize_
= 0;
625 times_to_fail_recreate_
= 0;
626 times_to_lose_on_recreate_
= 100;
630 class LayerTreeHostContextTestFinishAllRenderingAfterLoss
631 : public LayerTreeHostContextTest
{
633 virtual void BeginTest() OVERRIDE
{
634 // Lose the context until the compositor gives up on it.
635 times_to_lose_during_commit_
= 1;
636 times_to_fail_reinitialize_
= 10;
637 PostSetNeedsCommitToMainThread();
640 virtual void DidRecreateOutputSurface(bool succeeded
) OVERRIDE
{
641 EXPECT_FALSE(succeeded
);
642 layer_tree_host()->FinishAllRendering();
646 virtual void AfterTest() OVERRIDE
{}
649 SINGLE_AND_MULTI_THREAD_TEST_F(
650 LayerTreeHostContextTestFinishAllRenderingAfterLoss
);
652 class LayerTreeHostContextTestLostContextAndEvictTextures
653 : public LayerTreeHostContextTest
{
655 LayerTreeHostContextTestLostContextAndEvictTextures()
656 : LayerTreeHostContextTest(),
657 layer_(FakeContentLayer::Create(&client_
)),
661 virtual void SetupTree() OVERRIDE
{
662 layer_
->SetBounds(gfx::Size(10, 20));
663 layer_tree_host()->SetRootLayer(layer_
);
664 LayerTreeHostContextTest::SetupTree();
667 virtual void BeginTest() OVERRIDE
{
668 PostSetNeedsCommitToMainThread();
671 void PostEvictTextures() {
673 ImplThread()->PostTask(
675 &LayerTreeHostContextTestLostContextAndEvictTextures::
676 EvictTexturesOnImplThread
,
677 base::Unretained(this)));
679 DebugScopedSetImplThread
impl(proxy());
680 EvictTexturesOnImplThread();
684 void EvictTexturesOnImplThread() {
685 impl_host_
->EnforceManagedMemoryPolicy(ManagedMemoryPolicy(0));
686 if (lose_after_evict_
)
690 virtual void DidCommitAndDrawFrame() OVERRIDE
{
691 if (num_commits_
> 1)
693 EXPECT_TRUE(layer_
->HaveBackingAt(0, 0));
697 virtual void CommitCompleteOnThread(LayerTreeHostImpl
* impl
) OVERRIDE
{
698 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
699 if (num_commits_
> 1)
702 if (!lose_after_evict_
)
707 virtual void DidRecreateOutputSurface(bool succeeded
) OVERRIDE
{
708 EXPECT_TRUE(succeeded
);
712 virtual void AfterTest() OVERRIDE
{}
715 bool lose_after_evict_
;
716 FakeContentLayerClient client_
;
717 scoped_refptr
<FakeContentLayer
> layer_
;
718 LayerTreeHostImpl
* impl_host_
;
722 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
723 LoseAfterEvict_SingleThread
) {
724 lose_after_evict_
= true;
728 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
729 LoseAfterEvict_MultiThread
) {
730 lose_after_evict_
= true;
734 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
735 LoseBeforeEvict_SingleThread
) {
736 lose_after_evict_
= false;
740 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
741 LoseBeforeEvict_MultiThread
) {
742 lose_after_evict_
= false;
746 class LayerTreeHostContextTestLostContextWhileUpdatingResources
747 : public LayerTreeHostContextTest
{
749 LayerTreeHostContextTestLostContextWhileUpdatingResources()
750 : parent_(FakeContentLayer::Create(&client_
)),
752 times_to_lose_on_end_query_(3) {}
754 virtual scoped_ptr
<TestWebGraphicsContext3D
> CreateContext3d() OVERRIDE
{
755 scoped_ptr
<TestWebGraphicsContext3D
> context
=
756 LayerTreeHostContextTest::CreateContext3d();
757 if (times_to_lose_on_end_query_
) {
758 --times_to_lose_on_end_query_
;
759 context
->set_times_end_query_succeeds(5);
761 return context
.Pass();
764 virtual void SetupTree() OVERRIDE
{
765 parent_
->SetBounds(gfx::Size(num_children_
, 1));
767 for (int i
= 0; i
< num_children_
; i
++) {
768 scoped_refptr
<FakeContentLayer
> child
=
769 FakeContentLayer::Create(&client_
);
770 child
->SetPosition(gfx::PointF(i
, 0.f
));
771 child
->SetBounds(gfx::Size(1, 1));
772 parent_
->AddChild(child
);
775 layer_tree_host()->SetRootLayer(parent_
);
776 LayerTreeHostContextTest::SetupTree();
779 virtual void BeginTest() OVERRIDE
{
780 PostSetNeedsCommitToMainThread();
783 virtual void CommitCompleteOnThread(LayerTreeHostImpl
* impl
) OVERRIDE
{
784 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
788 virtual void DidRecreateOutputSurface(bool succeeded
) OVERRIDE
{
789 EXPECT_TRUE(succeeded
);
792 virtual void AfterTest() OVERRIDE
{
793 EXPECT_EQ(0, times_to_lose_on_end_query_
);
797 FakeContentLayerClient client_
;
798 scoped_refptr
<FakeContentLayer
> parent_
;
800 int times_to_lose_on_end_query_
;
803 SINGLE_AND_MULTI_THREAD_TEST_F(
804 LayerTreeHostContextTestLostContextWhileUpdatingResources
);
806 class LayerTreeHostContextTestLayersNotified
807 : public LayerTreeHostContextTest
{
809 LayerTreeHostContextTestLayersNotified()
810 : LayerTreeHostContextTest(),
813 virtual void SetupTree() OVERRIDE
{
814 root_
= FakeContentLayer::Create(&client_
);
815 child_
= FakeContentLayer::Create(&client_
);
816 grandchild_
= FakeContentLayer::Create(&client_
);
818 root_
->AddChild(child_
);
819 child_
->AddChild(grandchild_
);
821 layer_tree_host()->SetRootLayer(root_
);
822 LayerTreeHostContextTest::SetupTree();
825 virtual void BeginTest() OVERRIDE
{
826 PostSetNeedsCommitToMainThread();
829 virtual void CommitCompleteOnThread(LayerTreeHostImpl
* host_impl
) OVERRIDE
{
830 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl
);
832 FakeContentLayerImpl
* root
= static_cast<FakeContentLayerImpl
*>(
833 host_impl
->active_tree()->root_layer());
834 FakeContentLayerImpl
* child
= static_cast<FakeContentLayerImpl
*>(
835 root
->children()[0]);
836 FakeContentLayerImpl
* grandchild
= static_cast<FakeContentLayerImpl
*>(
837 child
->children()[0]);
840 switch (num_commits_
) {
842 EXPECT_EQ(0u, root
->lost_output_surface_count());
843 EXPECT_EQ(0u, child
->lost_output_surface_count());
844 EXPECT_EQ(0u, grandchild
->lost_output_surface_count());
845 // Lose the context and struggle to recreate it.
847 times_to_fail_create_
= 1;
850 EXPECT_EQ(1u, root
->lost_output_surface_count());
851 EXPECT_EQ(1u, child
->lost_output_surface_count());
852 EXPECT_EQ(1u, grandchild
->lost_output_surface_count());
853 // Lose the context and again during recreate.
855 times_to_lose_on_create_
= 1;
858 EXPECT_EQ(3u, root
->lost_output_surface_count());
859 EXPECT_EQ(3u, child
->lost_output_surface_count());
860 EXPECT_EQ(3u, grandchild
->lost_output_surface_count());
861 // Lose the context and again during reinitialization.
863 times_to_fail_initialize_
= 1;
866 EXPECT_EQ(5u, root
->lost_output_surface_count());
867 EXPECT_EQ(5u, child
->lost_output_surface_count());
868 EXPECT_EQ(5u, grandchild
->lost_output_surface_count());
876 virtual void AfterTest() OVERRIDE
{}
881 FakeContentLayerClient client_
;
882 scoped_refptr
<FakeContentLayer
> root_
;
883 scoped_refptr
<FakeContentLayer
> child_
;
884 scoped_refptr
<FakeContentLayer
> grandchild_
;
887 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified
);
889 class LayerTreeHostContextTestDontUseLostResources
890 : public LayerTreeHostContextTest
{
892 virtual void SetupTree() OVERRIDE
{
893 context3d_
->set_have_extension_io_surface(true);
894 context3d_
->set_have_extension_egl_image(true);
896 scoped_refptr
<Layer
> root_
= Layer::Create();
897 root_
->SetBounds(gfx::Size(10, 10));
898 root_
->SetAnchorPoint(gfx::PointF());
899 root_
->SetIsDrawable(true);
901 scoped_refptr
<FakeDelegatedRendererLayer
> delegated_
=
902 FakeDelegatedRendererLayer::Create();
903 delegated_
->SetBounds(gfx::Size(10, 10));
904 delegated_
->SetAnchorPoint(gfx::PointF());
905 delegated_
->SetIsDrawable(true);
906 root_
->AddChild(delegated_
);
908 scoped_refptr
<ContentLayer
> content_
= ContentLayer::Create(&client_
);
909 content_
->SetBounds(gfx::Size(10, 10));
910 content_
->SetAnchorPoint(gfx::PointF());
911 content_
->SetIsDrawable(true);
912 root_
->AddChild(content_
);
914 scoped_refptr
<TextureLayer
> texture_
= TextureLayer::Create(NULL
);
915 texture_
->SetBounds(gfx::Size(10, 10));
916 texture_
->SetAnchorPoint(gfx::PointF());
917 texture_
->SetTextureId(TestWebGraphicsContext3D::kExternalTextureId
);
918 texture_
->SetIsDrawable(true);
919 root_
->AddChild(texture_
);
921 scoped_refptr
<ContentLayer
> mask_
= ContentLayer::Create(&client_
);
922 mask_
->SetBounds(gfx::Size(10, 10));
923 mask_
->SetAnchorPoint(gfx::PointF());
925 scoped_refptr
<ContentLayer
> content_with_mask_
=
926 ContentLayer::Create(&client_
);
927 content_with_mask_
->SetBounds(gfx::Size(10, 10));
928 content_with_mask_
->SetAnchorPoint(gfx::PointF());
929 content_with_mask_
->SetIsDrawable(true);
930 content_with_mask_
->SetMaskLayer(mask_
.get());
931 root_
->AddChild(content_with_mask_
);
933 scoped_refptr
<VideoLayer
> video_color_
= VideoLayer::Create(
934 &color_frame_provider_
);
935 video_color_
->SetBounds(gfx::Size(10, 10));
936 video_color_
->SetAnchorPoint(gfx::PointF());
937 video_color_
->SetIsDrawable(true);
938 root_
->AddChild(video_color_
);
940 scoped_refptr
<VideoLayer
> video_hw_
= VideoLayer::Create(
941 &hw_frame_provider_
);
942 video_hw_
->SetBounds(gfx::Size(10, 10));
943 video_hw_
->SetAnchorPoint(gfx::PointF());
944 video_hw_
->SetIsDrawable(true);
945 root_
->AddChild(video_hw_
);
947 scoped_refptr
<VideoLayer
> video_scaled_hw_
= VideoLayer::Create(
948 &scaled_hw_frame_provider_
);
949 video_scaled_hw_
->SetBounds(gfx::Size(10, 10));
950 video_scaled_hw_
->SetAnchorPoint(gfx::PointF());
951 video_scaled_hw_
->SetIsDrawable(true);
952 root_
->AddChild(video_scaled_hw_
);
954 scoped_refptr
<IOSurfaceLayer
> io_surface_
= IOSurfaceLayer::Create();
955 io_surface_
->SetBounds(gfx::Size(10, 10));
956 io_surface_
->SetAnchorPoint(gfx::PointF());
957 io_surface_
->SetIsDrawable(true);
958 io_surface_
->SetIOSurfaceProperties(1, gfx::Size(10, 10));
959 root_
->AddChild(io_surface_
);
962 LayerTreeDebugState debug_state
;
963 debug_state
.show_property_changed_rects
= true;
964 layer_tree_host()->SetDebugState(debug_state
);
966 bool paint_scrollbar
= true;
967 bool has_thumb
= true;
968 scoped_refptr
<ScrollbarLayer
> scrollbar_
= ScrollbarLayer::Create(
969 FakeWebScrollbar::Create().PassAs
<WebKit::WebScrollbar
>(),
970 FakeScrollbarThemePainter::Create(paint_scrollbar
)
971 .PassAs
<ScrollbarThemePainter
>(),
972 FakeWebScrollbarThemeGeometry::Create(has_thumb
)
973 .PassAs
<WebKit::WebScrollbarThemeGeometry
>(),
975 scrollbar_
->SetBounds(gfx::Size(10, 10));
976 scrollbar_
->SetAnchorPoint(gfx::PointF());
977 scrollbar_
->SetIsDrawable(true);
978 root_
->AddChild(scrollbar_
);
980 layer_tree_host()->SetRootLayer(root_
);
981 LayerTreeHostContextTest::SetupTree();
984 virtual void BeginTest() OVERRIDE
{
985 PostSetNeedsCommitToMainThread();
988 virtual void CommitCompleteOnThread(LayerTreeHostImpl
* host_impl
) OVERRIDE
{
989 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl
);
991 ResourceProvider
* resource_provider
= host_impl
->resource_provider();
993 if (host_impl
->active_tree()->source_frame_number() == 0) {
994 // Set up impl resources on the first commit.
996 scoped_ptr
<TestRenderPass
> pass_for_quad
= TestRenderPass::Create();
997 pass_for_quad
->SetNew(
998 // AppendOneOfEveryQuadType() makes a RenderPass quad with this id.
999 RenderPass::Id(1, 1),
1000 gfx::Rect(0, 0, 10, 10),
1001 gfx::Rect(0, 0, 10, 10),
1004 scoped_ptr
<TestRenderPass
> pass
= TestRenderPass::Create();
1006 RenderPass::Id(2, 1),
1007 gfx::Rect(0, 0, 10, 10),
1008 gfx::Rect(0, 0, 10, 10),
1010 pass
->AppendOneOfEveryQuadType(resource_provider
, RenderPass::Id(2, 1));
1012 ScopedPtrVector
<RenderPass
> pass_list
;
1013 pass_list
.push_back(pass_for_quad
.PassAs
<RenderPass
>());
1014 pass_list
.push_back(pass
.PassAs
<RenderPass
>());
1016 // First child is the delegated layer.
1017 FakeDelegatedRendererLayerImpl
* delegated_impl
=
1018 static_cast<FakeDelegatedRendererLayerImpl
*>(
1019 host_impl
->active_tree()->root_layer()->children()[0]);
1020 delegated_impl
->SetFrameDataForRenderPasses(&pass_list
);
1021 EXPECT_TRUE(pass_list
.empty());
1023 color_video_frame_
= VideoFrame::CreateColorFrame(
1024 gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
1025 hw_video_frame_
= VideoFrame::WrapNativeTexture(
1026 resource_provider
->GraphicsContext3D()->createTexture(),
1028 gfx::Size(4, 4), gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4),
1030 VideoFrame::ReadPixelsCB(),
1032 scaled_hw_video_frame_
= VideoFrame::WrapNativeTexture(
1033 resource_provider
->GraphicsContext3D()->createTexture(),
1035 gfx::Size(4, 4), gfx::Rect(0, 0, 3, 2), gfx::Size(4, 4),
1037 VideoFrame::ReadPixelsCB(),
1040 color_frame_provider_
.set_frame(color_video_frame_
);
1041 hw_frame_provider_
.set_frame(hw_video_frame_
);
1042 scaled_hw_frame_provider_
.set_frame(scaled_hw_video_frame_
);
1046 if (host_impl
->active_tree()->source_frame_number() == 3) {
1047 // On the third commit we're recovering from context loss. Hardware
1048 // video frames should not be reused by the VideoFrameProvider, but
1049 // software frames can be.
1050 hw_frame_provider_
.set_frame(NULL
);
1051 scaled_hw_frame_provider_
.set_frame(NULL
);
1055 virtual bool PrepareToDrawOnThread(LayerTreeHostImpl
* host_impl
,
1056 LayerTreeHostImpl::FrameData
* frame
,
1057 bool result
) OVERRIDE
{
1058 if (host_impl
->active_tree()->source_frame_number() == 2) {
1059 // Lose the context during draw on the second commit. This will cause
1060 // a third commit to recover.
1062 context3d_
->set_times_bind_texture_succeeds(4);
1067 virtual void DidCommitAndDrawFrame() OVERRIDE
{
1068 ASSERT_TRUE(layer_tree_host()->hud_layer());
1069 // End the test once we know the 3nd frame drew.
1070 if (layer_tree_host()->commit_number() == 4)
1073 layer_tree_host()->SetNeedsCommit();
1076 virtual void AfterTest() OVERRIDE
{}
1079 FakeContentLayerClient client_
;
1081 scoped_refptr
<Layer
> root_
;
1082 scoped_refptr
<DelegatedRendererLayer
> delegated_
;
1083 scoped_refptr
<ContentLayer
> content_
;
1084 scoped_refptr
<TextureLayer
> texture_
;
1085 scoped_refptr
<ContentLayer
> mask_
;
1086 scoped_refptr
<ContentLayer
> content_with_mask_
;
1087 scoped_refptr
<VideoLayer
> video_color_
;
1088 scoped_refptr
<VideoLayer
> video_hw_
;
1089 scoped_refptr
<VideoLayer
> video_scaled_hw_
;
1090 scoped_refptr
<IOSurfaceLayer
> io_surface_
;
1091 scoped_refptr
<ScrollbarLayer
> scrollbar_
;
1093 scoped_refptr
<VideoFrame
> color_video_frame_
;
1094 scoped_refptr
<VideoFrame
> hw_video_frame_
;
1095 scoped_refptr
<VideoFrame
> scaled_hw_video_frame_
;
1097 FakeVideoFrameProvider color_frame_provider_
;
1098 FakeVideoFrameProvider hw_frame_provider_
;
1099 FakeVideoFrameProvider scaled_hw_frame_provider_
;
1102 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources
);
1104 class LayerTreeHostContextTestFailsImmediately
1105 : public LayerTreeHostContextTest
{
1107 LayerTreeHostContextTestFailsImmediately()
1108 : LayerTreeHostContextTest() {}
1110 virtual ~LayerTreeHostContextTestFailsImmediately() {}
1112 virtual void BeginTest() OVERRIDE
{
1113 PostSetNeedsCommitToMainThread();
1116 virtual void AfterTest() OVERRIDE
{}
1118 virtual scoped_ptr
<TestWebGraphicsContext3D
> CreateContext3d() OVERRIDE
{
1119 scoped_ptr
<TestWebGraphicsContext3D
> context
=
1120 LayerTreeHostContextTest::CreateContext3d();
1121 context
->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB
,
1122 GL_INNOCENT_CONTEXT_RESET_ARB
);
1123 return context
.Pass();
1126 virtual void DidRecreateOutputSurface(bool succeeded
) OVERRIDE
{
1127 EXPECT_FALSE(succeeded
);
1128 // If we make it this far without crashing, we pass!
1133 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestFailsImmediately
);
1135 class ImplSidePaintingLayerTreeHostContextTest
1136 : public LayerTreeHostContextTest
{
1138 virtual void InitializeSettings(LayerTreeSettings
* settings
) OVERRIDE
{
1139 settings
->impl_side_painting
= true;
1143 class LayerTreeHostContextTestImplSidePainting
1144 : public ImplSidePaintingLayerTreeHostContextTest
{
1146 virtual void SetupTree() OVERRIDE
{
1147 scoped_refptr
<Layer
> root
= Layer::Create();
1148 root
->SetBounds(gfx::Size(10, 10));
1149 root
->SetAnchorPoint(gfx::PointF());
1150 root
->SetIsDrawable(true);
1152 scoped_refptr
<PictureLayer
> picture
= PictureLayer::Create(&client_
);
1153 picture
->SetBounds(gfx::Size(10, 10));
1154 picture
->SetAnchorPoint(gfx::PointF());
1155 picture
->SetIsDrawable(true);
1156 root
->AddChild(picture
);
1158 layer_tree_host()->SetRootLayer(root
);
1159 LayerTreeHostContextTest::SetupTree();
1162 virtual void BeginTest() OVERRIDE
{
1163 times_to_lose_during_commit_
= 1;
1164 PostSetNeedsCommitToMainThread();
1167 virtual void AfterTest() OVERRIDE
{}
1169 virtual void DidRecreateOutputSurface(bool succeeded
) OVERRIDE
{
1170 EXPECT_TRUE(succeeded
);
1175 FakeContentLayerClient client_
;
1178 MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting
);
1180 class ScrollbarLayerLostContext
: public LayerTreeHostContextTest
{
1182 ScrollbarLayerLostContext() : commits_(0) {}
1184 virtual void BeginTest() OVERRIDE
{
1185 scoped_refptr
<Layer
> scroll_layer
= Layer::Create();
1186 scrollbar_layer_
= FakeScrollbarLayer::Create(
1187 false, true, scroll_layer
->id());
1188 scrollbar_layer_
->SetBounds(gfx::Size(10, 100));
1189 layer_tree_host()->root_layer()->AddChild(scrollbar_layer_
);
1190 layer_tree_host()->root_layer()->AddChild(scroll_layer
);
1191 PostSetNeedsCommitToMainThread();
1194 virtual void AfterTest() OVERRIDE
{}
1196 virtual void CommitCompleteOnThread(LayerTreeHostImpl
* impl
) OVERRIDE
{
1197 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1200 size_t upload_count
= scrollbar_layer_
->last_update_full_upload_size() +
1201 scrollbar_layer_
->last_update_partial_upload_size();
1204 // First (regular) update, we should upload 2 resources (thumb, and
1206 EXPECT_EQ(1, scrollbar_layer_
->update_count());
1207 EXPECT_EQ(2u, upload_count
);
1211 // Second update, after the lost context, we should still upload 2
1212 // resources even if the contents haven't changed.
1213 EXPECT_EQ(2, scrollbar_layer_
->update_count());
1214 EXPECT_EQ(2u, upload_count
);
1224 scoped_refptr
<FakeScrollbarLayer
> scrollbar_layer_
;
1227 SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext
);