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/delegated_frame_provider.h"
10 #include "cc/layers/delegated_frame_resource_collection.h"
11 #include "cc/layers/heads_up_display_layer.h"
12 #include "cc/layers/io_surface_layer.h"
13 #include "cc/layers/layer_impl.h"
14 #include "cc/layers/painted_scrollbar_layer.h"
15 #include "cc/layers/picture_layer.h"
16 #include "cc/layers/texture_layer.h"
17 #include "cc/layers/texture_layer_impl.h"
18 #include "cc/layers/video_layer.h"
19 #include "cc/layers/video_layer_impl.h"
20 #include "cc/output/filter_operations.h"
21 #include "cc/resources/single_release_callback.h"
22 #include "cc/test/failure_output_surface.h"
23 #include "cc/test/fake_content_layer.h"
24 #include "cc/test/fake_content_layer_client.h"
25 #include "cc/test/fake_content_layer_impl.h"
26 #include "cc/test/fake_delegated_renderer_layer.h"
27 #include "cc/test/fake_delegated_renderer_layer_impl.h"
28 #include "cc/test/fake_layer_tree_host_client.h"
29 #include "cc/test/fake_output_surface.h"
30 #include "cc/test/fake_output_surface_client.h"
31 #include "cc/test/fake_painted_scrollbar_layer.h"
32 #include "cc/test/fake_picture_layer.h"
33 #include "cc/test/fake_picture_layer_impl.h"
34 #include "cc/test/fake_resource_provider.h"
35 #include "cc/test/fake_scoped_ui_resource.h"
36 #include "cc/test/fake_scrollbar.h"
37 #include "cc/test/fake_video_frame_provider.h"
38 #include "cc/test/layer_tree_test.h"
39 #include "cc/test/render_pass_test_common.h"
40 #include "cc/test/test_context_provider.h"
41 #include "cc/test/test_shared_bitmap_manager.h"
42 #include "cc/test/test_web_graphics_context_3d.h"
43 #include "cc/trees/layer_tree_host_impl.h"
44 #include "cc/trees/layer_tree_impl.h"
45 #include "cc/trees/single_thread_proxy.h"
46 #include "gpu/GLES2/gl2extchromium.h"
47 #include "media/base/media.h"
49 using media::VideoFrame
;
54 // These tests deal with losing the 3d graphics context.
55 class LayerTreeHostContextTest
: public LayerTreeTest
{
57 LayerTreeHostContextTest()
60 times_to_fail_create_(0),
61 times_to_lose_during_commit_(0),
62 times_to_lose_during_draw_(0),
63 times_to_fail_recreate_(0),
64 times_to_expect_create_failed_(0),
65 times_create_failed_(0),
66 committed_at_least_once_(false),
67 context_should_support_io_surface_(false),
68 fallback_context_works_(false),
69 async_output_surface_creation_(false) {
70 media::InitializeMediaLibraryForTesting();
74 // For sanity-checking tests, they should only call this when the
75 // context is not lost.
77 context3d_
->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB
,
78 GL_INNOCENT_CONTEXT_RESET_ARB
);
82 virtual scoped_ptr
<TestWebGraphicsContext3D
> CreateContext3d() {
83 return TestWebGraphicsContext3D::Create();
86 scoped_ptr
<FakeOutputSurface
> CreateFakeOutputSurface() override
{
87 if (times_to_fail_create_
) {
88 --times_to_fail_create_
;
90 return make_scoped_ptr(new FailureOutputSurface(delegating_renderer()));
93 scoped_ptr
<TestWebGraphicsContext3D
> context3d
= CreateContext3d();
94 context3d_
= context3d
.get();
96 if (context_should_support_io_surface_
) {
97 context3d_
->set_have_extension_io_surface(true);
98 context3d_
->set_have_extension_egl_image(true);
101 if (delegating_renderer())
102 return FakeOutputSurface::CreateDelegating3d(context3d
.Pass());
104 return FakeOutputSurface::Create3d(context3d
.Pass());
107 DrawResult
PrepareToDrawOnThread(LayerTreeHostImpl
* host_impl
,
108 LayerTreeHostImpl::FrameData
* frame
,
109 DrawResult draw_result
) override
{
110 if (draw_result
== DRAW_ABORTED_MISSING_HIGH_RES_CONTENT
) {
111 // Only valid for single-threaded impl-side painting, which activates
112 // immediately and will try to draw again when content has finished.
113 DCHECK(!host_impl
->proxy()->HasImplThread());
114 DCHECK(host_impl
->settings().impl_side_painting
);
117 EXPECT_EQ(DRAW_SUCCESS
, draw_result
);
118 if (!times_to_lose_during_draw_
)
121 --times_to_lose_during_draw_
;
124 times_to_fail_create_
= times_to_fail_recreate_
;
125 times_to_fail_recreate_
= 0;
130 void CommitCompleteOnThread(LayerTreeHostImpl
* host_impl
) override
{
131 committed_at_least_once_
= true;
133 if (!times_to_lose_during_commit_
)
135 --times_to_lose_during_commit_
;
138 times_to_fail_create_
= times_to_fail_recreate_
;
139 times_to_fail_recreate_
= 0;
142 void DidFailToInitializeOutputSurface() override
{ ++times_create_failed_
; }
144 void TearDown() override
{
145 LayerTreeTest::TearDown();
146 EXPECT_EQ(times_to_expect_create_failed_
, times_create_failed_
);
149 void ExpectCreateToFail() { ++times_to_expect_create_failed_
; }
152 TestWebGraphicsContext3D
* context3d_
;
153 int times_to_fail_create_
;
154 int times_to_lose_during_commit_
;
155 int times_to_lose_during_draw_
;
156 int times_to_fail_recreate_
;
157 int times_to_expect_create_failed_
;
158 int times_create_failed_
;
159 bool committed_at_least_once_
;
160 bool context_should_support_io_surface_
;
161 bool fallback_context_works_
;
162 bool async_output_surface_creation_
;
165 class LayerTreeHostContextTestLostContextSucceeds
166 : public LayerTreeHostContextTest
{
168 LayerTreeHostContextTestLostContextSucceeds()
169 : LayerTreeHostContextTest(),
172 num_losses_last_test_case_(-1),
173 recovered_context_(true),
174 first_initialized_(false) {}
176 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
178 void RequestNewOutputSurface() override
{
179 if (async_output_surface_creation_
) {
180 MainThreadTaskRunner()->PostTask(
181 FROM_HERE
, base::Bind(&LayerTreeHostContextTestLostContextSucceeds::
182 CreateAndSetOutputSurface
,
183 base::Unretained(this)));
185 CreateAndSetOutputSurface();
189 void CreateAndSetOutputSurface() {
190 scoped_ptr
<OutputSurface
> surface(
191 LayerTreeHostContextTest::CreateOutputSurface());
193 layer_tree_host()->SetOutputSurface(surface
.Pass());
196 void DidInitializeOutputSurface() override
{
197 if (first_initialized_
)
200 first_initialized_
= true;
202 recovered_context_
= true;
205 void AfterTest() override
{ EXPECT_EQ(11u, test_case_
); }
207 void DidCommitAndDrawFrame() override
{
208 // If the last frame had a context loss, then we'll commit again to
210 if (!recovered_context_
)
212 if (times_to_lose_during_commit_
)
214 if (times_to_lose_during_draw_
)
217 recovered_context_
= false;
219 InvalidateAndSetNeedsCommit();
224 virtual void InvalidateAndSetNeedsCommit() {
225 // Cause damage so we try to draw.
226 layer_tree_host()->root_layer()->SetNeedsDisplay();
227 layer_tree_host()->SetNeedsCommit();
230 bool NextTestCase() {
231 static const TestCase kTests
[] = {
232 // Losing the context and failing to recreate it (or losing it again
233 // immediately) a small number of times should succeed.
235 1, // times_to_lose_during_commit
236 0, // times_to_lose_during_draw
237 0, // times_to_fail_recreate
238 false, // fallback_context_works
239 false, // async_output_surface_creation
242 0, // times_to_lose_during_commit
243 1, // times_to_lose_during_draw
244 0, // times_to_fail_recreate
245 false, // fallback_context_works
246 false, // async_output_surface_creation
249 1, // times_to_lose_during_commit
250 0, // times_to_lose_during_draw
251 3, // times_to_fail_recreate
252 false, // fallback_context_works
253 false, // async_output_surface_creation
256 0, // times_to_lose_during_commit
257 1, // times_to_lose_during_draw
258 3, // times_to_fail_recreate
259 false, // fallback_context_works
260 false, // async_output_surface_creation
263 0, // times_to_lose_during_commit
264 1, // times_to_lose_during_draw
265 3, // times_to_fail_recreate
266 false, // fallback_context_works
267 true, // async_output_surface_creation
269 // Losing the context and recreating it any number of times should
272 10, // times_to_lose_during_commit
273 0, // times_to_lose_during_draw
274 0, // times_to_fail_recreate
275 false, // fallback_context_works
276 false, // async_output_surface_creation
279 0, // times_to_lose_during_commit
280 10, // times_to_lose_during_draw
281 0, // times_to_fail_recreate
282 false, // fallback_context_works
283 false, // async_output_surface_creation
286 10, // times_to_lose_during_commit
287 0, // times_to_lose_during_draw
288 0, // times_to_fail_recreate
289 false, // fallback_context_works
290 true, // async_output_surface_creation
293 0, // times_to_lose_during_commit
294 10, // times_to_lose_during_draw
295 0, // times_to_fail_recreate
296 false, // fallback_context_works
297 true, // async_output_surface_creation
299 // Losing the context, failing to reinitialize it, and making a fallback
300 // context should work.
302 0, // times_to_lose_during_commit
303 1, // times_to_lose_during_draw
304 0, // times_to_fail_recreate
305 true, // fallback_context_works
306 false, // async_output_surface_creation
309 0, // times_to_lose_during_commit
310 1, // times_to_lose_during_draw
311 0, // times_to_fail_recreate
312 true, // fallback_context_works
313 true, // async_output_surface_creation
317 if (test_case_
>= arraysize(kTests
))
319 // Make sure that we lost our context at least once in the last test run so
320 // the test did something.
321 EXPECT_GT(num_losses_
, num_losses_last_test_case_
);
322 num_losses_last_test_case_
= num_losses_
;
324 times_to_lose_during_commit_
=
325 kTests
[test_case_
].times_to_lose_during_commit
;
326 times_to_lose_during_draw_
= kTests
[test_case_
].times_to_lose_during_draw
;
327 times_to_fail_recreate_
= kTests
[test_case_
].times_to_fail_recreate
;
328 fallback_context_works_
= kTests
[test_case_
].fallback_context_works
;
329 async_output_surface_creation_
=
330 kTests
[test_case_
].async_output_surface_creation
;
336 int times_to_lose_during_commit
;
337 int times_to_lose_during_draw
;
338 int times_to_fail_recreate
;
339 bool fallback_context_works
;
340 bool async_output_surface_creation
;
346 int num_losses_last_test_case_
;
347 bool recovered_context_
;
348 bool first_initialized_
;
351 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLostContextSucceeds
);
353 class LayerTreeHostClientNotReadyDoesNotCreateOutputSurface
354 : public LayerTreeHostContextTest
{
356 LayerTreeHostClientNotReadyDoesNotCreateOutputSurface()
357 : LayerTreeHostContextTest() {}
359 void WillBeginTest() override
{
360 // Override and do not signal SetLayerTreeHostClientReady.
363 void BeginTest() override
{
364 PostSetNeedsCommitToMainThread();
368 scoped_ptr
<OutputSurface
> CreateOutputSurface() override
{
373 void DidInitializeOutputSurface() override
{ EXPECT_TRUE(false); }
375 void AfterTest() override
{}
378 SINGLE_AND_MULTI_THREAD_TEST_F(
379 LayerTreeHostClientNotReadyDoesNotCreateOutputSurface
);
381 class MultipleCompositeDoesNotCreateOutputSurface
382 : public LayerTreeHostContextTest
{
384 MultipleCompositeDoesNotCreateOutputSurface()
385 : LayerTreeHostContextTest(), request_count_(0) {}
387 void InitializeSettings(LayerTreeSettings
* settings
) override
{
388 settings
->single_thread_proxy_scheduler
= false;
389 settings
->use_zero_copy
= true;
392 void RequestNewOutputSurface() override
{
393 EXPECT_GE(1, ++request_count_
);
397 void BeginTest() override
{
398 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
399 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(2));
402 scoped_ptr
<OutputSurface
> CreateOutputSurface() override
{
407 void DidInitializeOutputSurface() override
{ EXPECT_TRUE(false); }
409 void AfterTest() override
{}
414 SINGLE_THREAD_NOIMPL_TEST_F(MultipleCompositeDoesNotCreateOutputSurface
);
416 // This test makes sure that once a SingleThreadProxy issues a
417 // DidFailToInitializeOutputSurface, that future Composite calls will not
418 // trigger additional requests for output surfaces.
419 class FailedCreateDoesNotCreateExtraOutputSurface
420 : public LayerTreeHostContextTest
{
422 FailedCreateDoesNotCreateExtraOutputSurface()
423 : LayerTreeHostContextTest(), num_requests_(0), has_failed_(false) {}
425 void InitializeSettings(LayerTreeSettings
* settings
) override
{
426 settings
->single_thread_proxy_scheduler
= false;
427 settings
->use_zero_copy
= true;
430 void RequestNewOutputSurface() override
{
432 // There should be one initial request and then one request from
433 // the LayerTreeTest test hooks DidFailToInitializeOutputSurface (which is
434 // hard to skip). This second request is just ignored and is test cruft.
435 EXPECT_LE(num_requests_
, 2);
436 if (num_requests_
> 1)
438 ExpectCreateToFail();
439 layer_tree_host()->SetOutputSurface(
440 make_scoped_ptr(new FailureOutputSurface(false)));
443 void BeginTest() override
{
444 // First composite tries to create a surface.
445 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
446 EXPECT_EQ(num_requests_
, 2);
447 EXPECT_TRUE(has_failed_
);
449 // Second composite should not request or fail.
450 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(2));
451 EXPECT_EQ(num_requests_
, 2);
455 void DidInitializeOutputSurface() override
{ EXPECT_TRUE(false); }
457 void DidFailToInitializeOutputSurface() override
{
458 LayerTreeHostContextTest::DidFailToInitializeOutputSurface();
459 EXPECT_FALSE(has_failed_
);
463 void AfterTest() override
{}
469 SINGLE_THREAD_NOIMPL_TEST_F(FailedCreateDoesNotCreateExtraOutputSurface
);
471 class LayerTreeHostContextTestCommitAfterDelayedOutputSurface
472 : public LayerTreeHostContextTest
{
474 LayerTreeHostContextTestCommitAfterDelayedOutputSurface()
475 : LayerTreeHostContextTest(), creating_output_(false) {}
477 void InitializeSettings(LayerTreeSettings
* settings
) override
{
478 settings
->single_thread_proxy_scheduler
= false;
479 settings
->use_zero_copy
= true;
482 void RequestNewOutputSurface() override
{
483 MainThreadTaskRunner()->PostTask(
485 base::Bind(&LayerTreeHostContextTestCommitAfterDelayedOutputSurface::
486 CreateAndSetOutputSurface
,
487 base::Unretained(this)));
490 void CreateAndSetOutputSurface() {
491 creating_output_
= true;
492 layer_tree_host()->SetOutputSurface(
493 LayerTreeHostContextTest::CreateOutputSurface());
496 void BeginTest() override
{
497 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
500 void ScheduleComposite() override
{
501 if (creating_output_
)
505 void AfterTest() override
{}
507 bool creating_output_
;
510 SINGLE_THREAD_NOIMPL_TEST_F(
511 LayerTreeHostContextTestCommitAfterDelayedOutputSurface
);
513 class LayerTreeHostContextTestAvoidUnnecessaryComposite
514 : public LayerTreeHostContextTest
{
516 LayerTreeHostContextTestAvoidUnnecessaryComposite()
517 : LayerTreeHostContextTest(), in_composite_(false) {}
519 void InitializeSettings(LayerTreeSettings
* settings
) override
{
520 settings
->single_thread_proxy_scheduler
= false;
521 settings
->use_zero_copy
= true;
524 void RequestNewOutputSurface() override
{
525 layer_tree_host()->SetOutputSurface(
526 LayerTreeHostContextTest::CreateOutputSurface());
530 void BeginTest() override
{
531 in_composite_
= true;
532 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
533 in_composite_
= false;
536 void ScheduleComposite() override
{ EXPECT_FALSE(in_composite_
); }
538 void AfterTest() override
{}
543 SINGLE_THREAD_NOIMPL_TEST_F(LayerTreeHostContextTestAvoidUnnecessaryComposite
);
545 class LayerTreeHostContextTestLostContextSucceedsWithContent
546 : public LayerTreeHostContextTestLostContextSucceeds
{
548 void SetupTree() override
{
549 root_
= Layer::Create(layer_settings());
550 root_
->SetBounds(gfx::Size(10, 10));
551 root_
->SetIsDrawable(true);
553 // Paint non-solid color.
555 paint
.setColor(SkColorSetARGB(100, 80, 200, 200));
556 client_
.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint
);
558 if (layer_tree_host()->settings().impl_side_painting
)
559 layer_
= FakePictureLayer::Create(layer_settings(), &client_
);
561 layer_
= FakeContentLayer::Create(layer_settings(), &client_
);
562 layer_
->SetBounds(gfx::Size(10, 10));
563 layer_
->SetIsDrawable(true);
565 root_
->AddChild(layer_
);
567 layer_tree_host()->SetRootLayer(root_
);
568 LayerTreeHostContextTest::SetupTree();
571 void InvalidateAndSetNeedsCommit() override
{
572 // Invalidate the render surface so we don't try to use a cached copy of the
573 // surface. We want to make sure to test the drawing paths for drawing to
575 layer_
->SetNeedsDisplay();
576 LayerTreeHostContextTestLostContextSucceeds::InvalidateAndSetNeedsCommit();
579 void DrawLayersOnThread(LayerTreeHostImpl
* host_impl
) override
{
580 if (!host_impl
->settings().impl_side_painting
) {
581 FakeContentLayerImpl
* content_impl
= static_cast<FakeContentLayerImpl
*>(
582 host_impl
->active_tree()->root_layer()->children()[0]);
583 // Even though the context was lost, we should have a resource. The
584 // TestWebGraphicsContext3D ensures that this resource is created with
585 // the active context.
586 EXPECT_TRUE(content_impl
->HaveResourceForTileAt(0, 0));
588 FakePictureLayerImpl
* picture_impl
= static_cast<FakePictureLayerImpl
*>(
589 host_impl
->active_tree()->root_layer()->children()[0]);
590 EXPECT_TRUE(picture_impl
->HighResTiling()
598 FakeContentLayerClient client_
;
599 scoped_refptr
<Layer
> root_
;
600 scoped_refptr
<Layer
> layer_
;
603 // This test uses TiledLayer and PictureLayer to check for a working context.
604 SINGLE_AND_MULTI_THREAD_TEST_F(
605 LayerTreeHostContextTestLostContextSucceedsWithContent
);
607 class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
608 : public LayerTreeHostContextTest
{
610 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
611 : times_to_fail_(1), times_initialized_(0) {
612 times_to_fail_create_
= times_to_fail_
;
615 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
617 void DidInitializeOutputSurface() override
{ times_initialized_
++; }
619 void DrawLayersOnThread(LayerTreeHostImpl
* host_impl
) override
{ EndTest(); }
621 void AfterTest() override
{
622 EXPECT_EQ(times_to_fail_
, times_create_failed_
);
623 EXPECT_NE(0, times_initialized_
);
628 int times_initialized_
;
631 SINGLE_AND_MULTI_THREAD_TEST_F(
632 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
);
634 class LayerTreeHostContextTestLostContextAndEvictTextures
635 : public LayerTreeHostContextTest
{
637 LayerTreeHostContextTestLostContextAndEvictTextures()
638 : LayerTreeHostContextTest(),
641 lost_context_(false) {}
643 void SetupTree() override
{
644 // Paint non-solid color.
646 paint
.setColor(SkColorSetARGB(100, 80, 200, 200));
647 client_
.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint
);
649 if (layer_tree_host()->settings().impl_side_painting
) {
650 picture_layer_
= FakePictureLayer::Create(layer_settings(), &client_
);
651 picture_layer_
->SetBounds(gfx::Size(10, 20));
652 layer_tree_host()->SetRootLayer(picture_layer_
);
654 content_layer_
= FakeContentLayer::Create(layer_settings(), &client_
);
655 content_layer_
->SetBounds(gfx::Size(10, 20));
656 layer_tree_host()->SetRootLayer(content_layer_
);
659 LayerTreeHostContextTest::SetupTree();
662 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
664 void PostEvictTextures() {
665 if (HasImplThread()) {
666 ImplThreadTaskRunner()->PostTask(
668 base::Bind(&LayerTreeHostContextTestLostContextAndEvictTextures::
669 EvictTexturesOnImplThread
,
670 base::Unretained(this)));
672 DebugScopedSetImplThread
impl(proxy());
673 EvictTexturesOnImplThread();
677 void EvictTexturesOnImplThread() {
678 impl_host_
->EvictTexturesForTesting();
680 if (lose_after_evict_
) {
682 lost_context_
= true;
686 void DidCommitAndDrawFrame() override
{
687 if (num_commits_
> 1)
689 if (!layer_tree_host()->settings().impl_side_painting
) {
690 EXPECT_TRUE(content_layer_
->HaveBackingAt(0, 0));
695 void CommitCompleteOnThread(LayerTreeHostImpl
* impl
) override
{
696 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
697 if (num_commits_
> 1)
700 if (!lose_after_evict_
) {
702 lost_context_
= true;
706 void DrawLayersOnThread(LayerTreeHostImpl
* impl
) override
{
707 if (impl
->settings().impl_side_painting
) {
708 FakePictureLayerImpl
* picture_impl
=
709 static_cast<FakePictureLayerImpl
*>(impl
->active_tree()->root_layer());
710 EXPECT_TRUE(picture_impl
->HighResTiling()
715 FakeContentLayerImpl
* content_impl
=
716 static_cast<FakeContentLayerImpl
*>(impl
->active_tree()->root_layer());
717 EXPECT_TRUE(content_impl
->HaveResourceForTileAt(0, 0));
725 void DidInitializeOutputSurface() override
{}
727 void AfterTest() override
{}
730 bool lose_after_evict_
;
731 FakeContentLayerClient client_
;
732 scoped_refptr
<FakeContentLayer
> content_layer_
;
733 scoped_refptr
<FakePictureLayer
> picture_layer_
;
734 LayerTreeHostImpl
* impl_host_
;
739 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
740 LoseAfterEvict_SingleThread_DirectRenderer
) {
741 lose_after_evict_
= true;
742 RunTest(false, false, false);
745 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
746 LoseAfterEvict_SingleThread_DelegatingRenderer
) {
747 lose_after_evict_
= true;
748 RunTest(false, true, false);
751 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
752 LoseAfterEvict_MultiThread_DirectRenderer_MainThreadPaint
) {
753 lose_after_evict_
= true;
754 RunTest(true, false, false);
757 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
758 LoseAfterEvict_MultiThread_DelegatingRenderer_MainThreadPaint
) {
759 lose_after_evict_
= true;
760 RunTest(true, true, false);
763 // Flaky on all platforms, http://crbug.com/310979
764 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
765 DISABLED_LoseAfterEvict_MultiThread_DelegatingRenderer_ImplSidePaint
) {
766 lose_after_evict_
= true;
767 RunTest(true, true, true);
770 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
771 LoseBeforeEvict_SingleThread_DirectRenderer
) {
772 lose_after_evict_
= false;
773 RunTest(false, false, false);
776 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
777 LoseBeforeEvict_SingleThread_DelegatingRenderer
) {
778 lose_after_evict_
= false;
779 RunTest(false, true, false);
782 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
783 LoseBeforeEvict_MultiThread_DirectRenderer_MainThreadPaint
) {
784 lose_after_evict_
= false;
785 RunTest(true, false, false);
788 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
789 LoseBeforeEvict_MultiThread_DirectRenderer_ImplSidePaint
) {
790 lose_after_evict_
= false;
791 RunTest(true, false, true);
794 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
795 LoseBeforeEvict_MultiThread_DelegatingRenderer_MainThreadPaint
) {
796 lose_after_evict_
= false;
797 RunTest(true, true, false);
800 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
801 LoseBeforeEvict_MultiThread_DelegatingRenderer_ImplSidePaint
) {
802 lose_after_evict_
= false;
803 RunTest(true, true, true);
806 class LayerTreeHostContextTestLostContextWhileUpdatingResources
807 : public LayerTreeHostContextTest
{
809 LayerTreeHostContextTestLostContextWhileUpdatingResources()
810 : num_children_(50), times_to_lose_on_end_query_(3) {}
812 scoped_ptr
<TestWebGraphicsContext3D
> CreateContext3d() override
{
813 scoped_ptr
<TestWebGraphicsContext3D
> context
=
814 LayerTreeHostContextTest::CreateContext3d();
815 if (times_to_lose_on_end_query_
) {
816 --times_to_lose_on_end_query_
;
817 context
->set_times_end_query_succeeds(5);
819 return context
.Pass();
822 void SetupTree() override
{
823 if (layer_tree_host()->settings().impl_side_painting
)
824 parent_
= FakePictureLayer::Create(layer_settings(), &client_
);
826 parent_
= FakeContentLayer::Create(layer_settings(), &client_
);
828 parent_
->SetBounds(gfx::Size(num_children_
, 1));
830 for (int i
= 0; i
< num_children_
; i
++) {
831 scoped_refptr
<Layer
> child
;
832 if (layer_tree_host()->settings().impl_side_painting
)
833 child
= FakePictureLayer::Create(layer_settings(), &client_
);
835 child
= FakeContentLayer::Create(layer_settings(), &client_
);
836 child
->SetPosition(gfx::PointF(i
, 0.f
));
837 child
->SetBounds(gfx::Size(1, 1));
838 parent_
->AddChild(child
);
841 layer_tree_host()->SetRootLayer(parent_
);
842 LayerTreeHostContextTest::SetupTree();
845 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
847 void DrawLayersOnThread(LayerTreeHostImpl
* host_impl
) override
{
848 EXPECT_EQ(0, times_to_lose_on_end_query_
);
852 void AfterTest() override
{ EXPECT_EQ(0, times_to_lose_on_end_query_
); }
855 FakeContentLayerClient client_
;
856 scoped_refptr
<Layer
> parent_
;
858 int times_to_lose_on_end_query_
;
861 SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
862 LayerTreeHostContextTestLostContextWhileUpdatingResources
);
864 class LayerTreeHostContextTestLayersNotified
: public LayerTreeHostContextTest
{
866 LayerTreeHostContextTestLayersNotified()
867 : LayerTreeHostContextTest(), num_commits_(0) {}
869 void SetupTree() override
{
870 if (layer_tree_host()->settings().impl_side_painting
) {
871 root_
= FakePictureLayer::Create(layer_settings(), &client_
);
872 child_
= FakePictureLayer::Create(layer_settings(), &client_
);
873 grandchild_
= FakePictureLayer::Create(layer_settings(), &client_
);
875 root_
= FakeContentLayer::Create(layer_settings(), &client_
);
876 child_
= FakeContentLayer::Create(layer_settings(), &client_
);
877 grandchild_
= FakeContentLayer::Create(layer_settings(), &client_
);
880 root_
->AddChild(child_
);
881 child_
->AddChild(grandchild_
);
883 layer_tree_host()->SetRootLayer(root_
);
884 LayerTreeHostContextTest::SetupTree();
887 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
889 void DidActivateTreeOnThread(LayerTreeHostImpl
* host_impl
) override
{
890 LayerTreeHostContextTest::DidActivateTreeOnThread(host_impl
);
892 FakePictureLayerImpl
* root_picture
= NULL
;
893 FakePictureLayerImpl
* child_picture
= NULL
;
894 FakePictureLayerImpl
* grandchild_picture
= NULL
;
895 FakeContentLayerImpl
* root_content
= NULL
;
896 FakeContentLayerImpl
* child_content
= NULL
;
897 FakeContentLayerImpl
* grandchild_content
= NULL
;
899 if (host_impl
->settings().impl_side_painting
) {
900 root_picture
= static_cast<FakePictureLayerImpl
*>(
901 host_impl
->active_tree()->root_layer());
903 static_cast<FakePictureLayerImpl
*>(root_picture
->children()[0]);
905 static_cast<FakePictureLayerImpl
*>(child_picture
->children()[0]);
908 root_content
= static_cast<FakeContentLayerImpl
*>(
909 host_impl
->active_tree()->root_layer());
911 static_cast<FakeContentLayerImpl
*>(root_content
->children()[0]);
913 static_cast<FakeContentLayerImpl
*>(child_content
->children()[0]);
917 switch (num_commits_
) {
919 if (host_impl
->settings().impl_side_painting
) {
920 EXPECT_EQ(0u, root_picture
->release_resources_count());
921 EXPECT_EQ(0u, child_picture
->release_resources_count());
922 EXPECT_EQ(0u, grandchild_picture
->release_resources_count());
924 EXPECT_EQ(0u, root_content
->lost_output_surface_count());
925 EXPECT_EQ(0u, child_content
->lost_output_surface_count());
926 EXPECT_EQ(0u, grandchild_content
->lost_output_surface_count());
929 // Lose the context and struggle to recreate it.
931 times_to_fail_create_
= 1;
934 if (host_impl
->settings().impl_side_painting
) {
935 EXPECT_TRUE(root_picture
->release_resources_count());
936 EXPECT_TRUE(child_picture
->release_resources_count());
937 EXPECT_TRUE(grandchild_picture
->release_resources_count());
939 EXPECT_TRUE(root_content
->lost_output_surface_count());
940 EXPECT_TRUE(child_content
->lost_output_surface_count());
941 EXPECT_TRUE(grandchild_content
->lost_output_surface_count());
951 void AfterTest() override
{}
956 FakeContentLayerClient client_
;
957 scoped_refptr
<Layer
> root_
;
958 scoped_refptr
<Layer
> child_
;
959 scoped_refptr
<Layer
> grandchild_
;
962 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified
);
964 class LayerTreeHostContextTestDontUseLostResources
965 : public LayerTreeHostContextTest
{
967 LayerTreeHostContextTestDontUseLostResources() : lost_context_(false) {
968 context_should_support_io_surface_
= true;
970 child_output_surface_
= FakeOutputSurface::Create3d();
971 child_output_surface_
->BindToClient(&output_surface_client_
);
972 shared_bitmap_manager_
.reset(new TestSharedBitmapManager());
973 child_resource_provider_
= FakeResourceProvider::Create(
974 child_output_surface_
.get(), shared_bitmap_manager_
.get());
977 static void EmptyReleaseCallback(unsigned sync_point
, bool lost
) {}
979 void SetupTree() override
{
980 gpu::gles2::GLES2Interface
* gl
=
981 child_output_surface_
->context_provider()->ContextGL();
983 scoped_ptr
<DelegatedFrameData
> frame_data(new DelegatedFrameData
);
985 scoped_ptr
<TestRenderPass
> pass_for_quad
= TestRenderPass::Create();
986 pass_for_quad
->SetNew(
987 // AppendOneOfEveryQuadType() makes a RenderPass quad with this id.
989 gfx::Rect(0, 0, 10, 10),
990 gfx::Rect(0, 0, 10, 10),
993 scoped_ptr
<TestRenderPass
> pass
= TestRenderPass::Create();
994 pass
->SetNew(RenderPassId(1, 1),
995 gfx::Rect(0, 0, 10, 10),
996 gfx::Rect(0, 0, 10, 10),
998 pass
->AppendOneOfEveryQuadType(child_resource_provider_
.get(),
1001 frame_data
->render_pass_list
.push_back(pass_for_quad
.Pass());
1002 frame_data
->render_pass_list
.push_back(pass
.Pass());
1004 delegated_resource_collection_
= new DelegatedFrameResourceCollection
;
1005 delegated_frame_provider_
= new DelegatedFrameProvider(
1006 delegated_resource_collection_
.get(), frame_data
.Pass());
1008 ResourceId resource
= child_resource_provider_
->CreateResource(
1009 gfx::Size(4, 4), GL_CLAMP_TO_EDGE
,
1010 ResourceProvider::TEXTURE_HINT_IMMUTABLE
, RGBA_8888
);
1011 ResourceProvider::ScopedWriteLockGL
lock(child_resource_provider_
.get(),
1014 gpu::Mailbox mailbox
;
1015 gl
->GenMailboxCHROMIUM(mailbox
.name
);
1016 GLuint sync_point
= gl
->InsertSyncPointCHROMIUM();
1018 scoped_refptr
<Layer
> root
= Layer::Create(layer_settings());
1019 root
->SetBounds(gfx::Size(10, 10));
1020 root
->SetIsDrawable(true);
1022 scoped_refptr
<FakeDelegatedRendererLayer
> delegated
=
1023 FakeDelegatedRendererLayer::Create(layer_settings(),
1024 delegated_frame_provider_
.get());
1025 delegated
->SetBounds(gfx::Size(10, 10));
1026 delegated
->SetIsDrawable(true);
1027 root
->AddChild(delegated
);
1029 scoped_refptr
<Layer
> layer
;
1030 if (layer_tree_host()->settings().impl_side_painting
)
1031 layer
= PictureLayer::Create(layer_settings(), &client_
);
1033 layer
= ContentLayer::Create(layer_settings(), &client_
);
1034 layer
->SetBounds(gfx::Size(10, 10));
1035 layer
->SetIsDrawable(true);
1036 root
->AddChild(layer
);
1038 scoped_refptr
<TextureLayer
> texture
=
1039 TextureLayer::CreateForMailbox(layer_settings_
, NULL
);
1040 texture
->SetBounds(gfx::Size(10, 10));
1041 texture
->SetIsDrawable(true);
1042 texture
->SetTextureMailbox(
1043 TextureMailbox(mailbox
, GL_TEXTURE_2D
, sync_point
),
1044 SingleReleaseCallback::Create(
1045 base::Bind(&LayerTreeHostContextTestDontUseLostResources::
1046 EmptyReleaseCallback
)));
1047 root
->AddChild(texture
);
1049 scoped_refptr
<Layer
> mask
;
1050 if (layer_tree_host()->settings().impl_side_painting
)
1051 mask
= PictureLayer::Create(layer_settings_
, &client_
);
1053 mask
= ContentLayer::Create(layer_settings_
, &client_
);
1054 mask
->SetBounds(gfx::Size(10, 10));
1056 scoped_refptr
<Layer
> layer_with_mask
;
1057 if (layer_tree_host()->settings().impl_side_painting
)
1058 layer_with_mask
= PictureLayer::Create(layer_settings_
, &client_
);
1060 layer_with_mask
= ContentLayer::Create(layer_settings_
, &client_
);
1061 layer_with_mask
->SetBounds(gfx::Size(10, 10));
1062 layer_with_mask
->SetIsDrawable(true);
1063 layer_with_mask
->SetMaskLayer(mask
.get());
1064 root
->AddChild(layer_with_mask
);
1066 scoped_refptr
<VideoLayer
> video_color
= VideoLayer::Create(
1067 layer_settings_
, &color_frame_provider_
, media::VIDEO_ROTATION_0
);
1068 video_color
->SetBounds(gfx::Size(10, 10));
1069 video_color
->SetIsDrawable(true);
1070 root
->AddChild(video_color
);
1072 scoped_refptr
<VideoLayer
> video_hw
= VideoLayer::Create(
1073 layer_settings_
, &hw_frame_provider_
, media::VIDEO_ROTATION_0
);
1074 video_hw
->SetBounds(gfx::Size(10, 10));
1075 video_hw
->SetIsDrawable(true);
1076 root
->AddChild(video_hw
);
1078 scoped_refptr
<VideoLayer
> video_scaled_hw
= VideoLayer::Create(
1079 layer_settings_
, &scaled_hw_frame_provider_
, media::VIDEO_ROTATION_0
);
1080 video_scaled_hw
->SetBounds(gfx::Size(10, 10));
1081 video_scaled_hw
->SetIsDrawable(true);
1082 root
->AddChild(video_scaled_hw
);
1084 color_video_frame_
= VideoFrame::CreateColorFrame(
1085 gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
1086 hw_video_frame_
= VideoFrame::WrapNativeTexture(
1087 gpu::MailboxHolder(mailbox
, GL_TEXTURE_2D
, sync_point
),
1088 media::VideoFrame::ReleaseMailboxCB(), gfx::Size(4, 4),
1089 gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4), base::TimeDelta(),
1090 false /* allow_overlay */, true /* has_alpha */);
1091 scaled_hw_video_frame_
= VideoFrame::WrapNativeTexture(
1092 gpu::MailboxHolder(mailbox
, GL_TEXTURE_2D
, sync_point
),
1093 media::VideoFrame::ReleaseMailboxCB(), gfx::Size(4, 4),
1094 gfx::Rect(0, 0, 3, 2), gfx::Size(4, 4), base::TimeDelta(),
1095 false /* allow_overlay */, true /* has_alpha */);
1097 color_frame_provider_
.set_frame(color_video_frame_
);
1098 hw_frame_provider_
.set_frame(hw_video_frame_
);
1099 scaled_hw_frame_provider_
.set_frame(scaled_hw_video_frame_
);
1101 if (!delegating_renderer()) {
1102 // TODO(danakj): IOSurface layer can not be transported. crbug.com/239335
1103 scoped_refptr
<IOSurfaceLayer
> io_surface
=
1104 IOSurfaceLayer::Create(layer_settings_
);
1105 io_surface
->SetBounds(gfx::Size(10, 10));
1106 io_surface
->SetIsDrawable(true);
1107 io_surface
->SetIOSurfaceProperties(1, gfx::Size(10, 10));
1108 root
->AddChild(io_surface
);
1112 LayerTreeDebugState debug_state
;
1113 debug_state
.show_property_changed_rects
= true;
1114 layer_tree_host()->SetDebugState(debug_state
);
1116 scoped_refptr
<PaintedScrollbarLayer
> scrollbar
=
1117 PaintedScrollbarLayer::Create(
1118 layer_settings_
, scoped_ptr
<Scrollbar
>(new FakeScrollbar
).Pass(),
1120 scrollbar
->SetBounds(gfx::Size(10, 10));
1121 scrollbar
->SetIsDrawable(true);
1122 root
->AddChild(scrollbar
);
1124 layer_tree_host()->SetRootLayer(root
);
1125 LayerTreeHostContextTest::SetupTree();
1128 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
1130 void CommitCompleteOnThread(LayerTreeHostImpl
* host_impl
) override
{
1131 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl
);
1133 if (host_impl
->active_tree()->source_frame_number() == 3) {
1134 // On the third commit we're recovering from context loss. Hardware
1135 // video frames should not be reused by the VideoFrameProvider, but
1136 // software frames can be.
1137 hw_frame_provider_
.set_frame(NULL
);
1138 scaled_hw_frame_provider_
.set_frame(NULL
);
1142 DrawResult
PrepareToDrawOnThread(LayerTreeHostImpl
* host_impl
,
1143 LayerTreeHostImpl::FrameData
* frame
,
1144 DrawResult draw_result
) override
{
1145 if (host_impl
->active_tree()->source_frame_number() == 2) {
1146 // Lose the context during draw on the second commit. This will cause
1147 // a third commit to recover.
1148 context3d_
->set_times_bind_texture_succeeds(0);
1153 scoped_ptr
<FakeOutputSurface
> CreateFakeOutputSurface() override
{
1154 // This will get called twice:
1155 // First when we create the initial output surface...
1156 if (layer_tree_host()->source_frame_number() > 0) {
1157 // ... and then again after we forced the context to be lost.
1158 lost_context_
= true;
1160 return LayerTreeHostContextTest::CreateFakeOutputSurface();
1163 void DidCommitAndDrawFrame() override
{
1164 ASSERT_TRUE(layer_tree_host()->hud_layer());
1165 // End the test once we know the 3nd frame drew.
1166 if (layer_tree_host()->source_frame_number() < 5) {
1167 layer_tree_host()->root_layer()->SetNeedsDisplay();
1168 layer_tree_host()->SetNeedsCommit();
1174 void AfterTest() override
{ EXPECT_TRUE(lost_context_
); }
1177 FakeContentLayerClient client_
;
1180 FakeOutputSurfaceClient output_surface_client_
;
1181 scoped_ptr
<FakeOutputSurface
> child_output_surface_
;
1182 scoped_ptr
<SharedBitmapManager
> shared_bitmap_manager_
;
1183 scoped_ptr
<ResourceProvider
> child_resource_provider_
;
1185 scoped_refptr
<DelegatedFrameResourceCollection
>
1186 delegated_resource_collection_
;
1187 scoped_refptr
<DelegatedFrameProvider
> delegated_frame_provider_
;
1189 scoped_refptr
<VideoFrame
> color_video_frame_
;
1190 scoped_refptr
<VideoFrame
> hw_video_frame_
;
1191 scoped_refptr
<VideoFrame
> scaled_hw_video_frame_
;
1193 FakeVideoFrameProvider color_frame_provider_
;
1194 FakeVideoFrameProvider hw_frame_provider_
;
1195 FakeVideoFrameProvider scaled_hw_frame_provider_
;
1197 LayerSettings layer_settings_
;
1200 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources
);
1202 class ImplSidePaintingLayerTreeHostContextTest
1203 : public LayerTreeHostContextTest
{
1205 void InitializeSettings(LayerTreeSettings
* settings
) override
{
1206 settings
->impl_side_painting
= true;
1210 class LayerTreeHostContextTestImplSidePainting
1211 : public ImplSidePaintingLayerTreeHostContextTest
{
1213 void SetupTree() override
{
1214 scoped_refptr
<Layer
> root
= Layer::Create(layer_settings());
1215 root
->SetBounds(gfx::Size(10, 10));
1216 root
->SetIsDrawable(true);
1218 scoped_refptr
<PictureLayer
> picture
=
1219 PictureLayer::Create(layer_settings(), &client_
);
1220 picture
->SetBounds(gfx::Size(10, 10));
1221 picture
->SetIsDrawable(true);
1222 root
->AddChild(picture
);
1224 layer_tree_host()->SetRootLayer(root
);
1225 LayerTreeHostContextTest::SetupTree();
1228 void BeginTest() override
{
1229 times_to_lose_during_commit_
= 1;
1230 PostSetNeedsCommitToMainThread();
1233 void AfterTest() override
{}
1235 void DidInitializeOutputSurface() override
{ EndTest(); }
1238 FakeContentLayerClient client_
;
1241 MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting
);
1243 class ScrollbarLayerLostContext
: public LayerTreeHostContextTest
{
1245 ScrollbarLayerLostContext() : commits_(0) {}
1247 void BeginTest() override
{
1248 scoped_refptr
<Layer
> scroll_layer
= Layer::Create(layer_settings());
1249 scrollbar_layer_
= FakePaintedScrollbarLayer::Create(
1250 layer_settings(), false, true, scroll_layer
->id());
1251 scrollbar_layer_
->SetBounds(gfx::Size(10, 100));
1252 layer_tree_host()->root_layer()->AddChild(scrollbar_layer_
);
1253 layer_tree_host()->root_layer()->AddChild(scroll_layer
);
1254 PostSetNeedsCommitToMainThread();
1257 void AfterTest() override
{}
1259 void CommitCompleteOnThread(LayerTreeHostImpl
* impl
) override
{
1260 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1265 // First (regular) update, we should upload 2 resources (thumb, and
1267 EXPECT_EQ(1, scrollbar_layer_
->update_count());
1271 // Second update, after the lost context, we should still upload 2
1272 // resources even if the contents haven't changed.
1273 EXPECT_EQ(2, scrollbar_layer_
->update_count());
1283 scoped_refptr
<FakePaintedScrollbarLayer
> scrollbar_layer_
;
1286 SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext
);
1288 class UIResourceLostTest
: public LayerTreeHostContextTest
{
1290 UIResourceLostTest() : time_step_(0) {}
1291 void InitializeSettings(LayerTreeSettings
* settings
) override
{
1292 settings
->renderer_settings
.texture_id_allocation_chunk_size
= 1;
1294 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
1295 void AfterTest() override
{}
1297 // This is called on the main thread after each commit and
1298 // DidActivateTreeOnThread, with the value of time_step_ at the time
1299 // of the call to DidActivateTreeOnThread. Similar tests will do
1300 // work on the main thread in DidCommit but that is unsuitable because
1301 // the main thread work for these tests must happen after
1302 // DidActivateTreeOnThread, which happens after DidCommit with impl-side
1304 virtual void StepCompleteOnMainThread(int time_step
) = 0;
1306 // Called after DidActivateTreeOnThread. If this is done during the commit,
1307 // the call to StepCompleteOnMainThread will not occur until after
1308 // the commit completes, because the main thread is blocked.
1309 void PostStepCompleteToMainThread() {
1310 proxy()->MainThreadTaskRunner()->PostTask(
1312 base::Bind(&UIResourceLostTest::StepCompleteOnMainThreadInternal
,
1313 base::Unretained(this),
1317 void PostLoseContextToImplThread() {
1318 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1319 ImplThreadTaskRunner()->PostTask(
1321 base::Bind(&LayerTreeHostContextTest::LoseContext
,
1322 base::Unretained(this)));
1327 scoped_ptr
<FakeScopedUIResource
> ui_resource_
;
1330 void StepCompleteOnMainThreadInternal(int step
) {
1331 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1332 StepCompleteOnMainThread(step
);
1336 class UIResourceLostTestSimple
: public UIResourceLostTest
{
1338 // This is called when the commit is complete and the new layer tree has been
1340 virtual void StepCompleteOnImplThread(LayerTreeHostImpl
* impl
) = 0;
1342 void CommitCompleteOnThread(LayerTreeHostImpl
* impl
) override
{
1343 if (!impl
->settings().impl_side_painting
) {
1344 StepCompleteOnImplThread(impl
);
1345 PostStepCompleteToMainThread();
1350 void DidActivateTreeOnThread(LayerTreeHostImpl
* impl
) override
{
1351 if (impl
->settings().impl_side_painting
) {
1352 StepCompleteOnImplThread(impl
);
1353 PostStepCompleteToMainThread();
1359 // Losing context after an UI resource has been created.
1360 class UIResourceLostAfterCommit
: public UIResourceLostTestSimple
{
1362 void StepCompleteOnMainThread(int step
) override
{
1363 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1366 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1367 // Expects a valid UIResourceId.
1368 EXPECT_NE(0, ui_resource_
->id());
1369 PostSetNeedsCommitToMainThread();
1372 // Release resource before ending the test.
1373 ui_resource_
= nullptr;
1382 void StepCompleteOnImplThread(LayerTreeHostImpl
* impl
) override
{
1383 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1384 switch (time_step_
) {
1386 // The resource should have been created on LTHI after the commit.
1387 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1388 PostSetNeedsCommitToMainThread();
1394 // The resources should have been recreated. The bitmap callback should
1395 // have been called once with the resource_lost flag set to true.
1396 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1397 // Resource Id on the impl-side have been recreated as well. Note
1398 // that the same UIResourceId persists after the context lost.
1399 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1400 PostSetNeedsCommitToMainThread();
1406 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostAfterCommit
);
1408 // Losing context before UI resource requests can be commited. Three sequences
1409 // of creation/deletion are considered:
1410 // 1. Create one resource -> Context Lost => Expect the resource to have been
1412 // 2. Delete an exisiting resource (test_id0_) -> create a second resource
1413 // (test_id1_) -> Context Lost => Expect the test_id0_ to be removed and
1414 // test_id1_ to have been created.
1415 // 3. Create one resource -> Delete that same resource -> Context Lost => Expect
1416 // the resource to not exist in the manager.
1417 class UIResourceLostBeforeCommit
: public UIResourceLostTestSimple
{
1419 UIResourceLostBeforeCommit() : test_id0_(0), test_id1_(0) {}
1421 void StepCompleteOnMainThread(int step
) override
{
1424 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1425 // Lose the context on the impl thread before the commit.
1426 PostLoseContextToImplThread();
1430 // Currently one resource has been created.
1431 test_id0_
= ui_resource_
->id();
1432 // Delete this resource.
1433 ui_resource_
= nullptr;
1434 // Create another resource.
1435 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1436 test_id1_
= ui_resource_
->id();
1437 // Sanity check that two resource creations return different ids.
1438 EXPECT_NE(test_id0_
, test_id1_
);
1439 // Lose the context on the impl thread before the commit.
1440 PostLoseContextToImplThread();
1443 // Clear the manager of resources.
1444 ui_resource_
= nullptr;
1445 PostSetNeedsCommitToMainThread();
1449 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1450 test_id0_
= ui_resource_
->id();
1451 // Sanity check the UIResourceId should not be 0.
1452 EXPECT_NE(0, test_id0_
);
1453 // Usually ScopedUIResource are deleted from the manager in their
1454 // destructor (so usually ui_resource_ = nullptr). But here we need
1455 // ui_resource_ for the next step, so call DeleteUIResource directly.
1456 layer_tree_host()->DeleteUIResource(test_id0_
);
1457 // Delete the resouce and then lose the context.
1458 PostLoseContextToImplThread();
1461 // Release resource before ending the test.
1462 ui_resource_
= nullptr;
1471 void StepCompleteOnImplThread(LayerTreeHostImpl
* impl
) override
{
1472 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1473 switch (time_step_
) {
1475 // Sequence 1 (continued):
1476 // The first context lost happens before the resources were created,
1477 // and because it resulted in no resources being destroyed, it does not
1478 // trigger resource re-creation.
1479 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1480 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1481 // Resource Id on the impl-side has been created.
1482 PostSetNeedsCommitToMainThread();
1485 // Sequence 2 (continued):
1486 // The previous resource should have been deleted.
1487 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(test_id0_
));
1488 // The second resource should have been created.
1489 EXPECT_NE(0u, impl
->ResourceIdForUIResource(test_id1_
));
1490 // The second resource called the resource callback once and since the
1491 // context is lost, a "resource lost" callback was also issued.
1492 EXPECT_EQ(2, ui_resource_
->resource_create_count
);
1493 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1496 // Sequence 3 (continued):
1497 // Expect the resource callback to have been called once.
1498 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1499 // No "resource lost" callbacks.
1500 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1501 // The UI resource id should not be valid
1502 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(test_id0_
));
1508 UIResourceId test_id0_
;
1509 UIResourceId test_id1_
;
1512 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeCommit
);
1514 // Losing UI resource before the pending trees is activated but after the
1515 // commit. Impl-side-painting only.
1516 class UIResourceLostBeforeActivateTree
: public UIResourceLostTest
{
1517 void StepCompleteOnMainThread(int step
) override
{
1518 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1521 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1522 PostSetNeedsCommitToMainThread();
1525 test_id_
= ui_resource_
->id();
1526 ui_resource_
= nullptr;
1527 PostSetNeedsCommitToMainThread();
1530 // Release resource before ending the test.
1531 ui_resource_
= nullptr;
1535 // Make sure no extra commits happened.
1540 void CommitCompleteOnThread(LayerTreeHostImpl
* impl
) override
{
1541 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1542 switch (time_step_
) {
1544 PostSetNeedsCommitToMainThread();
1547 PostSetNeedsCommitToMainThread();
1552 void WillActivateTreeOnThread(LayerTreeHostImpl
* impl
) override
{
1553 switch (time_step_
) {
1555 // The resource creation callback has been called.
1556 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1557 // The resource is not yet lost (sanity check).
1558 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1559 // The resource should not have been created yet on the impl-side.
1560 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1569 void DidActivateTreeOnThread(LayerTreeHostImpl
* impl
) override
{
1570 LayerTreeHostContextTest::DidActivateTreeOnThread(impl
);
1571 switch (time_step_
) {
1573 // The pending requests on the impl-side should have been processed.
1574 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1577 // The "lost resource" callback should have been called once.
1578 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1581 // The resource is deleted and should not be in the manager. Use
1582 // test_id_ since ui_resource_ has been deleted.
1583 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(test_id_
));
1587 PostStepCompleteToMainThread();
1592 UIResourceId test_id_
;
1595 TEST_F(UIResourceLostBeforeActivateTree
,
1596 RunMultiThread_DirectRenderer_ImplSidePaint
) {
1597 RunTest(true, false, true);
1600 TEST_F(UIResourceLostBeforeActivateTree
,
1601 RunMultiThread_DelegatingRenderer_ImplSidePaint
) {
1602 RunTest(true, true, true);
1605 // Resources evicted explicitly and by visibility changes.
1606 class UIResourceLostEviction
: public UIResourceLostTestSimple
{
1608 void StepCompleteOnMainThread(int step
) override
{
1609 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1612 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1613 EXPECT_NE(0, ui_resource_
->id());
1614 PostSetNeedsCommitToMainThread();
1617 // Make the tree not visible.
1618 PostSetVisibleToMainThread(false);
1621 // Release resource before ending the test.
1622 ui_resource_
= nullptr;
1630 void DidSetVisibleOnImplTree(LayerTreeHostImpl
* impl
, bool visible
) override
{
1631 TestWebGraphicsContext3D
* context
= TestContext();
1633 // All resources should have been evicted.
1634 ASSERT_EQ(0u, context
->NumTextures());
1635 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1636 EXPECT_EQ(2, ui_resource_
->resource_create_count
);
1637 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1638 // Drawing is disabled both because of the evicted resources and
1639 // because the renderer is not visible.
1640 EXPECT_FALSE(impl
->CanDraw());
1641 // Make the renderer visible again.
1642 PostSetVisibleToMainThread(true);
1646 void StepCompleteOnImplThread(LayerTreeHostImpl
* impl
) override
{
1647 TestWebGraphicsContext3D
* context
= TestContext();
1648 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1649 switch (time_step_
) {
1651 // The resource should have been created on LTHI after the commit.
1652 ASSERT_EQ(1u, context
->NumTextures());
1653 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1654 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1655 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1656 EXPECT_TRUE(impl
->CanDraw());
1657 // Evict all UI resources. This will trigger a commit.
1658 impl
->EvictAllUIResources();
1659 ASSERT_EQ(0u, context
->NumTextures());
1660 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1661 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1662 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1663 EXPECT_FALSE(impl
->CanDraw());
1666 // The resource should have been recreated.
1667 ASSERT_EQ(1u, context
->NumTextures());
1668 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1669 EXPECT_EQ(2, ui_resource_
->resource_create_count
);
1670 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1671 EXPECT_TRUE(impl
->CanDraw());
1674 // The resource should have been recreated after visibility was
1676 ASSERT_EQ(1u, context
->NumTextures());
1677 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1678 EXPECT_EQ(3, ui_resource_
->resource_create_count
);
1679 EXPECT_EQ(2, ui_resource_
->lost_resource_count
);
1680 EXPECT_TRUE(impl
->CanDraw());
1686 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction
);
1688 class LayerTreeHostContextTestSurfaceCreateCallback
1689 : public LayerTreeHostContextTest
{
1691 LayerTreeHostContextTestSurfaceCreateCallback()
1692 : LayerTreeHostContextTest() {}
1694 void SetupTree() override
{
1695 if (layer_tree_host()->settings().impl_side_painting
) {
1696 picture_layer_
= FakePictureLayer::Create(layer_settings(), &client_
);
1697 picture_layer_
->SetBounds(gfx::Size(10, 20));
1698 layer_tree_host()->SetRootLayer(picture_layer_
);
1700 content_layer_
= FakeContentLayer::Create(layer_settings(), &client_
);
1701 content_layer_
->SetBounds(gfx::Size(10, 20));
1702 layer_tree_host()->SetRootLayer(content_layer_
);
1705 LayerTreeHostContextTest::SetupTree();
1708 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
1710 void DidCommit() override
{
1711 switch (layer_tree_host()->source_frame_number()) {
1713 if (layer_tree_host()->settings().impl_side_painting
)
1714 EXPECT_EQ(1u, picture_layer_
->output_surface_created_count());
1716 EXPECT_EQ(1u, content_layer_
->output_surface_created_count());
1717 layer_tree_host()->SetNeedsCommit();
1720 if (layer_tree_host()->settings().impl_side_painting
)
1721 EXPECT_EQ(1u, picture_layer_
->output_surface_created_count());
1723 EXPECT_EQ(1u, content_layer_
->output_surface_created_count());
1724 layer_tree_host()->SetNeedsCommit();
1727 if (layer_tree_host()->settings().impl_side_painting
)
1728 EXPECT_EQ(1u, picture_layer_
->output_surface_created_count());
1730 EXPECT_EQ(1u, content_layer_
->output_surface_created_count());
1733 if (layer_tree_host()->settings().impl_side_painting
)
1734 EXPECT_EQ(2u, picture_layer_
->output_surface_created_count());
1736 EXPECT_EQ(2u, content_layer_
->output_surface_created_count());
1737 layer_tree_host()->SetNeedsCommit();
1742 void CommitCompleteOnThread(LayerTreeHostImpl
* impl
) override
{
1743 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1744 switch (LastCommittedSourceFrameNumber(impl
)) {
1758 void AfterTest() override
{}
1761 FakeContentLayerClient client_
;
1762 scoped_refptr
<FakePictureLayer
> picture_layer_
;
1763 scoped_refptr
<FakeContentLayer
> content_layer_
;
1766 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestSurfaceCreateCallback
);
1768 class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame
1769 : public LayerTreeHostContextTest
{
1771 void BeginTest() override
{
1773 PostSetNeedsCommitToMainThread();
1776 void ScheduledActionWillSendBeginMainFrame() override
{
1781 // Defer commits before the BeginFrame arrives, causing it to be delayed.
1782 PostSetDeferCommitsToMainThread(true);
1783 // Meanwhile, lose the context while we are in defer commits.
1784 ImplThreadTaskRunner()->PostTask(
1786 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1787 LoseContextOnImplThread
,
1788 base::Unretained(this)));
1791 void LoseContextOnImplThread() {
1794 // After losing the context, stop deferring commits.
1795 PostSetDeferCommitsToMainThread(false);
1798 void WillBeginMainFrame() override
{
1799 // Don't begin a frame with a lost surface.
1800 EXPECT_FALSE(layer_tree_host()->output_surface_lost());
1803 void DidCommitAndDrawFrame() override
{ EndTest(); }
1805 void AfterTest() override
{}
1810 SINGLE_AND_MULTI_THREAD_TEST_F(
1811 LayerTreeHostContextTestLoseAfterSendingBeginMainFrame
);