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/delegated_frame_provider.h"
9 #include "cc/layers/delegated_frame_resource_collection.h"
10 #include "cc/layers/heads_up_display_layer.h"
11 #include "cc/layers/io_surface_layer.h"
12 #include "cc/layers/layer_impl.h"
13 #include "cc/layers/painted_scrollbar_layer.h"
14 #include "cc/layers/picture_layer.h"
15 #include "cc/layers/texture_layer.h"
16 #include "cc/layers/texture_layer_impl.h"
17 #include "cc/layers/video_layer.h"
18 #include "cc/layers/video_layer_impl.h"
19 #include "cc/output/filter_operations.h"
20 #include "cc/resources/single_release_callback.h"
21 #include "cc/test/failure_output_surface.h"
22 #include "cc/test/fake_content_layer_client.h"
23 #include "cc/test/fake_delegated_renderer_layer.h"
24 #include "cc/test/fake_delegated_renderer_layer_impl.h"
25 #include "cc/test/fake_layer_tree_host_client.h"
26 #include "cc/test/fake_output_surface.h"
27 #include "cc/test/fake_output_surface_client.h"
28 #include "cc/test/fake_painted_scrollbar_layer.h"
29 #include "cc/test/fake_picture_layer.h"
30 #include "cc/test/fake_picture_layer_impl.h"
31 #include "cc/test/fake_resource_provider.h"
32 #include "cc/test/fake_scoped_ui_resource.h"
33 #include "cc/test/fake_scrollbar.h"
34 #include "cc/test/fake_video_frame_provider.h"
35 #include "cc/test/layer_tree_test.h"
36 #include "cc/test/render_pass_test_utils.h"
37 #include "cc/test/test_context_provider.h"
38 #include "cc/test/test_shared_bitmap_manager.h"
39 #include "cc/test/test_web_graphics_context_3d.h"
40 #include "cc/trees/layer_tree_host_impl.h"
41 #include "cc/trees/layer_tree_impl.h"
42 #include "cc/trees/single_thread_proxy.h"
43 #include "gpu/GLES2/gl2extchromium.h"
44 #include "media/base/media.h"
46 using media::VideoFrame
;
51 // These tests deal with losing the 3d graphics context.
52 class LayerTreeHostContextTest
: public LayerTreeTest
{
54 LayerTreeHostContextTest()
57 times_to_fail_create_(0),
58 times_to_lose_during_commit_(0),
59 times_to_lose_during_draw_(0),
60 times_to_fail_recreate_(0),
61 times_to_expect_create_failed_(0),
62 times_create_failed_(0),
63 committed_at_least_once_(false),
64 context_should_support_io_surface_(false),
65 fallback_context_works_(false),
66 async_output_surface_creation_(false) {
67 media::InitializeMediaLibrary();
71 // CreateFakeOutputSurface happens on a different thread, so lock context3d_
72 // to make sure we don't set it to null after recreating it there.
73 base::AutoLock
lock(context3d_lock_
);
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 base::AutoLock
lock(context3d_lock_
);
95 context3d_
= context3d
.get();
97 if (context_should_support_io_surface_
) {
98 context3d_
->set_have_extension_io_surface(true);
99 context3d_
->set_have_extension_egl_image(true);
102 if (delegating_renderer())
103 return FakeOutputSurface::CreateDelegating3d(context3d
.Pass());
105 return FakeOutputSurface::Create3d(context3d
.Pass());
108 DrawResult
PrepareToDrawOnThread(LayerTreeHostImpl
* host_impl
,
109 LayerTreeHostImpl::FrameData
* frame
,
110 DrawResult draw_result
) override
{
111 if (draw_result
== DRAW_ABORTED_MISSING_HIGH_RES_CONTENT
) {
112 // Only valid for single-threaded compositing, which activates
113 // immediately and will try to draw again when content has finished.
114 DCHECK(!host_impl
->proxy()->HasImplThread());
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 // Protects use of context3d_ so LoseContext and CreateFakeOutputSurface
153 // can both use it on different threads.
154 base::Lock context3d_lock_
;
155 TestWebGraphicsContext3D
* context3d_
;
157 int times_to_fail_create_
;
158 int times_to_lose_during_commit_
;
159 int times_to_lose_during_draw_
;
160 int times_to_fail_recreate_
;
161 int times_to_expect_create_failed_
;
162 int times_create_failed_
;
163 bool committed_at_least_once_
;
164 bool context_should_support_io_surface_
;
165 bool fallback_context_works_
;
166 bool async_output_surface_creation_
;
169 class LayerTreeHostContextTestLostContextSucceeds
170 : public LayerTreeHostContextTest
{
172 LayerTreeHostContextTestLostContextSucceeds()
173 : LayerTreeHostContextTest(),
176 num_losses_last_test_case_(-1),
177 recovered_context_(true),
178 first_initialized_(false) {}
180 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
182 void RequestNewOutputSurface() override
{
183 if (async_output_surface_creation_
) {
184 MainThreadTaskRunner()->PostTask(
185 FROM_HERE
, base::Bind(&LayerTreeHostContextTestLostContextSucceeds::
186 CreateAndSetOutputSurface
,
187 base::Unretained(this)));
189 CreateAndSetOutputSurface();
193 void CreateAndSetOutputSurface() {
194 scoped_ptr
<OutputSurface
> surface(
195 LayerTreeHostContextTest::CreateOutputSurface());
197 layer_tree_host()->SetOutputSurface(surface
.Pass());
200 void DidInitializeOutputSurface() override
{
201 if (first_initialized_
)
204 first_initialized_
= true;
206 recovered_context_
= true;
209 void AfterTest() override
{ EXPECT_EQ(11u, test_case_
); }
211 void DidCommitAndDrawFrame() override
{
212 // If the last frame had a context loss, then we'll commit again to
214 if (!recovered_context_
)
216 if (times_to_lose_during_commit_
)
218 if (times_to_lose_during_draw_
)
221 recovered_context_
= false;
223 InvalidateAndSetNeedsCommit();
228 virtual void InvalidateAndSetNeedsCommit() {
229 // Cause damage so we try to draw.
230 layer_tree_host()->root_layer()->SetNeedsDisplay();
231 layer_tree_host()->SetNeedsCommit();
234 bool NextTestCase() {
235 static const TestCase kTests
[] = {
236 // Losing the context and failing to recreate it (or losing it again
237 // immediately) a small number of times should succeed.
239 1, // times_to_lose_during_commit
240 0, // times_to_lose_during_draw
241 0, // times_to_fail_recreate
242 false, // fallback_context_works
243 false, // async_output_surface_creation
246 0, // times_to_lose_during_commit
247 1, // times_to_lose_during_draw
248 0, // times_to_fail_recreate
249 false, // fallback_context_works
250 false, // async_output_surface_creation
253 1, // times_to_lose_during_commit
254 0, // times_to_lose_during_draw
255 3, // times_to_fail_recreate
256 false, // fallback_context_works
257 false, // async_output_surface_creation
260 0, // times_to_lose_during_commit
261 1, // times_to_lose_during_draw
262 3, // times_to_fail_recreate
263 false, // fallback_context_works
264 false, // async_output_surface_creation
267 0, // times_to_lose_during_commit
268 1, // times_to_lose_during_draw
269 3, // times_to_fail_recreate
270 false, // fallback_context_works
271 true, // async_output_surface_creation
273 // Losing the context and recreating it any number of times should
276 10, // times_to_lose_during_commit
277 0, // times_to_lose_during_draw
278 0, // times_to_fail_recreate
279 false, // fallback_context_works
280 false, // async_output_surface_creation
283 0, // times_to_lose_during_commit
284 10, // times_to_lose_during_draw
285 0, // times_to_fail_recreate
286 false, // fallback_context_works
287 false, // async_output_surface_creation
290 10, // times_to_lose_during_commit
291 0, // times_to_lose_during_draw
292 0, // times_to_fail_recreate
293 false, // fallback_context_works
294 true, // async_output_surface_creation
297 0, // times_to_lose_during_commit
298 10, // times_to_lose_during_draw
299 0, // times_to_fail_recreate
300 false, // fallback_context_works
301 true, // async_output_surface_creation
303 // Losing the context, failing to reinitialize it, and making a fallback
304 // context should work.
306 0, // times_to_lose_during_commit
307 1, // times_to_lose_during_draw
308 0, // times_to_fail_recreate
309 true, // fallback_context_works
310 false, // async_output_surface_creation
313 0, // times_to_lose_during_commit
314 1, // times_to_lose_during_draw
315 0, // times_to_fail_recreate
316 true, // fallback_context_works
317 true, // async_output_surface_creation
321 if (test_case_
>= arraysize(kTests
))
323 // Make sure that we lost our context at least once in the last test run so
324 // the test did something.
325 EXPECT_GT(num_losses_
, num_losses_last_test_case_
);
326 num_losses_last_test_case_
= num_losses_
;
328 times_to_lose_during_commit_
=
329 kTests
[test_case_
].times_to_lose_during_commit
;
330 times_to_lose_during_draw_
= kTests
[test_case_
].times_to_lose_during_draw
;
331 times_to_fail_recreate_
= kTests
[test_case_
].times_to_fail_recreate
;
332 fallback_context_works_
= kTests
[test_case_
].fallback_context_works
;
333 async_output_surface_creation_
=
334 kTests
[test_case_
].async_output_surface_creation
;
340 int times_to_lose_during_commit
;
341 int times_to_lose_during_draw
;
342 int times_to_fail_recreate
;
343 bool fallback_context_works
;
344 bool async_output_surface_creation
;
350 int num_losses_last_test_case_
;
351 bool recovered_context_
;
352 bool first_initialized_
;
355 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLostContextSucceeds
);
357 class LayerTreeHostClientNotReadyDoesNotCreateOutputSurface
358 : public LayerTreeHostContextTest
{
360 LayerTreeHostClientNotReadyDoesNotCreateOutputSurface()
361 : LayerTreeHostContextTest() {}
363 void WillBeginTest() override
{
364 // Override and do not signal SetLayerTreeHostClientReady.
367 void BeginTest() override
{
368 PostSetNeedsCommitToMainThread();
372 scoped_ptr
<OutputSurface
> CreateOutputSurface() override
{
377 void DidInitializeOutputSurface() override
{ EXPECT_TRUE(false); }
379 void AfterTest() override
{}
382 SINGLE_AND_MULTI_THREAD_TEST_F(
383 LayerTreeHostClientNotReadyDoesNotCreateOutputSurface
);
385 class MultipleCompositeDoesNotCreateOutputSurface
386 : public LayerTreeHostContextTest
{
388 MultipleCompositeDoesNotCreateOutputSurface()
389 : LayerTreeHostContextTest(), request_count_(0) {}
391 void InitializeSettings(LayerTreeSettings
* settings
) override
{
392 settings
->single_thread_proxy_scheduler
= false;
393 settings
->use_zero_copy
= true;
396 void RequestNewOutputSurface() override
{
397 EXPECT_GE(1, ++request_count_
);
401 void BeginTest() override
{
402 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
403 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(2));
406 scoped_ptr
<OutputSurface
> CreateOutputSurface() override
{
411 void DidInitializeOutputSurface() override
{ EXPECT_TRUE(false); }
413 void AfterTest() override
{}
418 // This test uses Composite() which only exists for single thread.
419 SINGLE_THREAD_TEST_F(MultipleCompositeDoesNotCreateOutputSurface
);
421 // This test makes sure that once a SingleThreadProxy issues a
422 // DidFailToInitializeOutputSurface, that future Composite calls will not
423 // trigger additional requests for output surfaces.
424 class FailedCreateDoesNotCreateExtraOutputSurface
425 : public LayerTreeHostContextTest
{
427 FailedCreateDoesNotCreateExtraOutputSurface()
428 : LayerTreeHostContextTest(), num_requests_(0), has_failed_(false) {}
430 void InitializeSettings(LayerTreeSettings
* settings
) override
{
431 settings
->single_thread_proxy_scheduler
= false;
432 settings
->use_zero_copy
= true;
435 void RequestNewOutputSurface() override
{
437 // There should be one initial request and then one request from
438 // the LayerTreeTest test hooks DidFailToInitializeOutputSurface (which is
439 // hard to skip). This second request is just ignored and is test cruft.
440 EXPECT_LE(num_requests_
, 2);
441 if (num_requests_
> 1)
443 ExpectCreateToFail();
444 layer_tree_host()->SetOutputSurface(
445 make_scoped_ptr(new FailureOutputSurface(false)));
448 void BeginTest() override
{
449 // First composite tries to create a surface.
450 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
451 EXPECT_EQ(num_requests_
, 2);
452 EXPECT_TRUE(has_failed_
);
454 // Second composite should not request or fail.
455 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(2));
456 EXPECT_EQ(num_requests_
, 2);
460 void DidInitializeOutputSurface() override
{ EXPECT_TRUE(false); }
462 void DidFailToInitializeOutputSurface() override
{
463 LayerTreeHostContextTest::DidFailToInitializeOutputSurface();
464 EXPECT_FALSE(has_failed_
);
468 void AfterTest() override
{}
474 // This test uses Composite() which only exists for single thread.
475 SINGLE_THREAD_TEST_F(FailedCreateDoesNotCreateExtraOutputSurface
);
477 class LayerTreeHostContextTestCommitAfterDelayedOutputSurface
478 : public LayerTreeHostContextTest
{
480 LayerTreeHostContextTestCommitAfterDelayedOutputSurface()
481 : LayerTreeHostContextTest(), creating_output_(false) {}
483 void InitializeSettings(LayerTreeSettings
* settings
) override
{
484 settings
->single_thread_proxy_scheduler
= false;
485 settings
->use_zero_copy
= true;
488 void RequestNewOutputSurface() override
{
489 MainThreadTaskRunner()->PostTask(
491 base::Bind(&LayerTreeHostContextTestCommitAfterDelayedOutputSurface::
492 CreateAndSetOutputSurface
,
493 base::Unretained(this)));
496 void CreateAndSetOutputSurface() {
497 creating_output_
= true;
498 layer_tree_host()->SetOutputSurface(
499 LayerTreeHostContextTest::CreateOutputSurface());
502 void BeginTest() override
{
503 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
506 void ScheduleComposite() override
{
507 if (creating_output_
)
511 void AfterTest() override
{}
513 bool creating_output_
;
516 // This test uses Composite() which only exists for single thread.
517 SINGLE_THREAD_TEST_F(LayerTreeHostContextTestCommitAfterDelayedOutputSurface
);
519 class LayerTreeHostContextTestAvoidUnnecessaryComposite
520 : public LayerTreeHostContextTest
{
522 LayerTreeHostContextTestAvoidUnnecessaryComposite()
523 : LayerTreeHostContextTest(), in_composite_(false) {}
525 void InitializeSettings(LayerTreeSettings
* settings
) override
{
526 settings
->single_thread_proxy_scheduler
= false;
527 settings
->use_zero_copy
= true;
530 void RequestNewOutputSurface() override
{
531 layer_tree_host()->SetOutputSurface(
532 LayerTreeHostContextTest::CreateOutputSurface());
536 void BeginTest() override
{
537 in_composite_
= true;
538 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
539 in_composite_
= false;
542 void ScheduleComposite() override
{ EXPECT_FALSE(in_composite_
); }
544 void AfterTest() override
{}
549 // This test uses Composite() which only exists for single thread.
550 SINGLE_THREAD_TEST_F(LayerTreeHostContextTestAvoidUnnecessaryComposite
);
552 // This test uses PictureLayer to check for a working context.
553 class LayerTreeHostContextTestLostContextSucceedsWithContent
554 : public LayerTreeHostContextTestLostContextSucceeds
{
556 void SetupTree() override
{
557 root_
= Layer::Create(layer_settings());
558 root_
->SetBounds(gfx::Size(10, 10));
559 root_
->SetIsDrawable(true);
561 // Paint non-solid color.
563 paint
.setColor(SkColorSetARGB(100, 80, 200, 200));
564 client_
.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint
);
566 layer_
= FakePictureLayer::Create(layer_settings(), &client_
);
567 layer_
->SetBounds(gfx::Size(10, 10));
568 layer_
->SetIsDrawable(true);
570 root_
->AddChild(layer_
);
572 layer_tree_host()->SetRootLayer(root_
);
573 LayerTreeHostContextTest::SetupTree();
576 void InvalidateAndSetNeedsCommit() override
{
577 // Invalidate the render surface so we don't try to use a cached copy of the
578 // surface. We want to make sure to test the drawing paths for drawing to
580 layer_
->SetNeedsDisplay();
581 LayerTreeHostContextTestLostContextSucceeds::InvalidateAndSetNeedsCommit();
584 void DrawLayersOnThread(LayerTreeHostImpl
* host_impl
) override
{
585 FakePictureLayerImpl
* picture_impl
= static_cast<FakePictureLayerImpl
*>(
586 host_impl
->active_tree()->root_layer()->children()[0]);
587 EXPECT_TRUE(picture_impl
->HighResTiling()
594 FakeContentLayerClient client_
;
595 scoped_refptr
<Layer
> root_
;
596 scoped_refptr
<Layer
> layer_
;
599 SINGLE_AND_MULTI_THREAD_TEST_F(
600 LayerTreeHostContextTestLostContextSucceedsWithContent
);
602 class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
603 : public LayerTreeHostContextTest
{
605 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
606 : times_to_fail_(1), times_initialized_(0) {
607 times_to_fail_create_
= times_to_fail_
;
610 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
612 void DidInitializeOutputSurface() override
{ times_initialized_
++; }
614 void DrawLayersOnThread(LayerTreeHostImpl
* host_impl
) override
{ EndTest(); }
616 void AfterTest() override
{
617 EXPECT_EQ(times_to_fail_
, times_create_failed_
);
618 EXPECT_NE(0, times_initialized_
);
623 int times_initialized_
;
626 SINGLE_AND_MULTI_THREAD_TEST_F(
627 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
);
629 class LayerTreeHostContextTestLostContextAndEvictTextures
630 : public LayerTreeHostContextTest
{
632 LayerTreeHostContextTestLostContextAndEvictTextures()
633 : LayerTreeHostContextTest(),
636 lost_context_(false) {}
638 void SetupTree() override
{
639 // Paint non-solid color.
641 paint
.setColor(SkColorSetARGB(100, 80, 200, 200));
642 client_
.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint
);
644 scoped_refptr
<FakePictureLayer
> picture_layer
=
645 FakePictureLayer::Create(layer_settings(), &client_
);
646 picture_layer
->SetBounds(gfx::Size(10, 20));
647 layer_tree_host()->SetRootLayer(picture_layer
);
649 LayerTreeHostContextTest::SetupTree();
652 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
654 void PostEvictTextures() {
655 if (HasImplThread()) {
656 ImplThreadTaskRunner()->PostTask(
658 base::Bind(&LayerTreeHostContextTestLostContextAndEvictTextures::
659 EvictTexturesOnImplThread
,
660 base::Unretained(this)));
662 DebugScopedSetImplThread
impl(proxy());
663 EvictTexturesOnImplThread();
667 void EvictTexturesOnImplThread() {
668 impl_host_
->EvictTexturesForTesting();
670 if (lose_after_evict_
) {
672 lost_context_
= true;
676 void DidCommitAndDrawFrame() override
{
677 if (num_commits_
> 1)
682 void CommitCompleteOnThread(LayerTreeHostImpl
* impl
) override
{
683 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
684 if (num_commits_
> 1)
687 if (!lose_after_evict_
) {
689 lost_context_
= true;
693 void DrawLayersOnThread(LayerTreeHostImpl
* impl
) override
{
694 FakePictureLayerImpl
* picture_impl
=
695 static_cast<FakePictureLayerImpl
*>(impl
->active_tree()->root_layer());
696 EXPECT_TRUE(picture_impl
->HighResTiling()
706 void DidInitializeOutputSurface() override
{}
708 void AfterTest() override
{}
711 bool lose_after_evict_
;
712 FakeContentLayerClient client_
;
713 LayerTreeHostImpl
* impl_host_
;
718 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
719 LoseAfterEvict_SingleThread_DirectRenderer
) {
720 lose_after_evict_
= true;
721 RunTest(false, false);
724 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
725 LoseAfterEvict_SingleThread_DelegatingRenderer
) {
726 lose_after_evict_
= true;
727 RunTest(false, true);
730 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
731 LoseAfterEvict_MultiThread_DirectRenderer
) {
732 lose_after_evict_
= true;
733 RunTest(true, false);
736 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
737 LoseAfterEvict_MultiThread_DelegatingRenderer
) {
738 lose_after_evict_
= true;
742 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
743 LoseBeforeEvict_SingleThread_DirectRenderer
) {
744 lose_after_evict_
= false;
745 RunTest(false, false);
748 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
749 LoseBeforeEvict_SingleThread_DelegatingRenderer
) {
750 lose_after_evict_
= false;
751 RunTest(false, true);
754 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
755 LoseBeforeEvict_MultiThread_DirectRenderer
) {
756 lose_after_evict_
= false;
757 RunTest(true, false);
760 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
761 LoseBeforeEvict_MultiThread_DelegatingRenderer
) {
762 lose_after_evict_
= false;
766 class LayerTreeHostContextTestLayersNotified
: public LayerTreeHostContextTest
{
768 LayerTreeHostContextTestLayersNotified()
769 : LayerTreeHostContextTest(), num_commits_(0) {}
771 void SetupTree() override
{
772 root_
= FakePictureLayer::Create(layer_settings(), &client_
);
773 child_
= FakePictureLayer::Create(layer_settings(), &client_
);
774 grandchild_
= FakePictureLayer::Create(layer_settings(), &client_
);
776 root_
->AddChild(child_
);
777 child_
->AddChild(grandchild_
);
779 layer_tree_host()->SetRootLayer(root_
);
780 LayerTreeHostContextTest::SetupTree();
783 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
785 void DidActivateTreeOnThread(LayerTreeHostImpl
* host_impl
) override
{
786 LayerTreeHostContextTest::DidActivateTreeOnThread(host_impl
);
788 FakePictureLayerImpl
* root_picture
= NULL
;
789 FakePictureLayerImpl
* child_picture
= NULL
;
790 FakePictureLayerImpl
* grandchild_picture
= NULL
;
792 root_picture
= static_cast<FakePictureLayerImpl
*>(
793 host_impl
->active_tree()->root_layer());
795 static_cast<FakePictureLayerImpl
*>(root_picture
->children()[0]);
797 static_cast<FakePictureLayerImpl
*>(child_picture
->children()[0]);
800 switch (num_commits_
) {
802 EXPECT_EQ(0u, root_picture
->release_resources_count());
803 EXPECT_EQ(0u, child_picture
->release_resources_count());
804 EXPECT_EQ(0u, grandchild_picture
->release_resources_count());
806 // Lose the context and struggle to recreate it.
808 times_to_fail_create_
= 1;
811 EXPECT_TRUE(root_picture
->release_resources_count());
812 EXPECT_TRUE(child_picture
->release_resources_count());
813 EXPECT_TRUE(grandchild_picture
->release_resources_count());
822 void AfterTest() override
{}
827 FakeContentLayerClient client_
;
828 scoped_refptr
<Layer
> root_
;
829 scoped_refptr
<Layer
> child_
;
830 scoped_refptr
<Layer
> grandchild_
;
833 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified
);
835 class LayerTreeHostContextTestDontUseLostResources
836 : public LayerTreeHostContextTest
{
838 LayerTreeHostContextTestDontUseLostResources() : lost_context_(false) {
839 context_should_support_io_surface_
= true;
841 child_output_surface_
= FakeOutputSurface::Create3d();
842 child_output_surface_
->BindToClient(&output_surface_client_
);
843 shared_bitmap_manager_
.reset(new TestSharedBitmapManager());
844 child_resource_provider_
= FakeResourceProvider::Create(
845 child_output_surface_
.get(), shared_bitmap_manager_
.get());
848 static void EmptyReleaseCallback(unsigned sync_point
, bool lost
) {}
850 void SetupTree() override
{
851 gpu::gles2::GLES2Interface
* gl
=
852 child_output_surface_
->context_provider()->ContextGL();
854 scoped_ptr
<DelegatedFrameData
> frame_data(new DelegatedFrameData
);
856 scoped_ptr
<RenderPass
> pass_for_quad
= RenderPass::Create();
857 pass_for_quad
->SetNew(
858 // AppendOneOfEveryQuadType() makes a RenderPass quad with this id.
860 gfx::Rect(0, 0, 10, 10),
861 gfx::Rect(0, 0, 10, 10),
864 scoped_ptr
<RenderPass
> pass
= RenderPass::Create();
865 pass
->SetNew(RenderPassId(1, 1),
866 gfx::Rect(0, 0, 10, 10),
867 gfx::Rect(0, 0, 10, 10),
869 uint32_t mailbox_sync_point
;
870 AddOneOfEveryQuadType(pass
.get(), child_resource_provider_
.get(),
871 RenderPassId(2, 1), &mailbox_sync_point
);
873 frame_data
->render_pass_list
.push_back(pass_for_quad
.Pass());
874 frame_data
->render_pass_list
.push_back(pass
.Pass());
876 delegated_resource_collection_
= new DelegatedFrameResourceCollection
;
877 delegated_frame_provider_
= new DelegatedFrameProvider(
878 delegated_resource_collection_
.get(), frame_data
.Pass());
880 ResourceId resource
= child_resource_provider_
->CreateResource(
881 gfx::Size(4, 4), GL_CLAMP_TO_EDGE
,
882 ResourceProvider::TEXTURE_HINT_IMMUTABLE
, RGBA_8888
);
883 ResourceProvider::ScopedWriteLockGL
lock(child_resource_provider_
.get(),
886 gpu::Mailbox mailbox
;
887 gl
->GenMailboxCHROMIUM(mailbox
.name
);
888 GLuint sync_point
= gl
->InsertSyncPointCHROMIUM();
890 scoped_refptr
<Layer
> root
= Layer::Create(layer_settings());
891 root
->SetBounds(gfx::Size(10, 10));
892 root
->SetIsDrawable(true);
894 scoped_refptr
<FakeDelegatedRendererLayer
> delegated
=
895 FakeDelegatedRendererLayer::Create(layer_settings(),
896 delegated_frame_provider_
.get());
897 delegated
->SetBounds(gfx::Size(10, 10));
898 delegated
->SetIsDrawable(true);
899 root
->AddChild(delegated
);
901 scoped_refptr
<PictureLayer
> layer
=
902 PictureLayer::Create(layer_settings(), &client_
);
903 layer
->SetBounds(gfx::Size(10, 10));
904 layer
->SetIsDrawable(true);
905 root
->AddChild(layer
);
907 scoped_refptr
<TextureLayer
> texture
=
908 TextureLayer::CreateForMailbox(layer_settings_
, NULL
);
909 texture
->SetBounds(gfx::Size(10, 10));
910 texture
->SetIsDrawable(true);
911 texture
->SetTextureMailbox(
912 TextureMailbox(mailbox
, GL_TEXTURE_2D
, sync_point
),
913 SingleReleaseCallback::Create(
914 base::Bind(&LayerTreeHostContextTestDontUseLostResources::
915 EmptyReleaseCallback
)));
916 root
->AddChild(texture
);
918 scoped_refptr
<PictureLayer
> mask
=
919 PictureLayer::Create(layer_settings_
, &client_
);
920 mask
->SetBounds(gfx::Size(10, 10));
922 scoped_refptr
<PictureLayer
> layer_with_mask
=
923 PictureLayer::Create(layer_settings_
, &client_
);
924 layer_with_mask
->SetBounds(gfx::Size(10, 10));
925 layer_with_mask
->SetIsDrawable(true);
926 layer_with_mask
->SetMaskLayer(mask
.get());
927 root
->AddChild(layer_with_mask
);
929 scoped_refptr
<VideoLayer
> video_color
= VideoLayer::Create(
930 layer_settings_
, &color_frame_provider_
, media::VIDEO_ROTATION_0
);
931 video_color
->SetBounds(gfx::Size(10, 10));
932 video_color
->SetIsDrawable(true);
933 root
->AddChild(video_color
);
935 scoped_refptr
<VideoLayer
> video_hw
= VideoLayer::Create(
936 layer_settings_
, &hw_frame_provider_
, media::VIDEO_ROTATION_0
);
937 video_hw
->SetBounds(gfx::Size(10, 10));
938 video_hw
->SetIsDrawable(true);
939 root
->AddChild(video_hw
);
941 scoped_refptr
<VideoLayer
> video_scaled_hw
= VideoLayer::Create(
942 layer_settings_
, &scaled_hw_frame_provider_
, media::VIDEO_ROTATION_0
);
943 video_scaled_hw
->SetBounds(gfx::Size(10, 10));
944 video_scaled_hw
->SetIsDrawable(true);
945 root
->AddChild(video_scaled_hw
);
947 color_video_frame_
= VideoFrame::CreateColorFrame(
948 gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
949 hw_video_frame_
= VideoFrame::WrapNativeTexture(
950 media::PIXEL_FORMAT_ARGB
,
951 gpu::MailboxHolder(mailbox
, GL_TEXTURE_2D
, sync_point
),
952 media::VideoFrame::ReleaseMailboxCB(), gfx::Size(4, 4),
953 gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4), base::TimeDelta());
954 scaled_hw_video_frame_
= VideoFrame::WrapNativeTexture(
955 media::PIXEL_FORMAT_ARGB
,
956 gpu::MailboxHolder(mailbox
, GL_TEXTURE_2D
, sync_point
),
957 media::VideoFrame::ReleaseMailboxCB(), gfx::Size(4, 4),
958 gfx::Rect(0, 0, 3, 2), gfx::Size(4, 4), base::TimeDelta());
960 color_frame_provider_
.set_frame(color_video_frame_
);
961 hw_frame_provider_
.set_frame(hw_video_frame_
);
962 scaled_hw_frame_provider_
.set_frame(scaled_hw_video_frame_
);
964 scoped_refptr
<IOSurfaceLayer
> io_surface
=
965 IOSurfaceLayer::Create(layer_settings_
);
966 io_surface
->SetBounds(gfx::Size(10, 10));
967 io_surface
->SetIsDrawable(true);
968 io_surface
->SetIOSurfaceProperties(1, gfx::Size(10, 10));
969 root
->AddChild(io_surface
);
972 LayerTreeDebugState debug_state
;
973 debug_state
.show_property_changed_rects
= true;
974 layer_tree_host()->SetDebugState(debug_state
);
976 scoped_refptr
<PaintedScrollbarLayer
> scrollbar
=
977 PaintedScrollbarLayer::Create(
978 layer_settings_
, scoped_ptr
<Scrollbar
>(new FakeScrollbar
).Pass(),
980 scrollbar
->SetBounds(gfx::Size(10, 10));
981 scrollbar
->SetIsDrawable(true);
982 root
->AddChild(scrollbar
);
984 layer_tree_host()->SetRootLayer(root
);
985 LayerTreeHostContextTest::SetupTree();
988 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
990 void CommitCompleteOnThread(LayerTreeHostImpl
* host_impl
) override
{
991 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl
);
993 if (host_impl
->active_tree()->source_frame_number() == 3) {
994 // On the third commit we're recovering from context loss. Hardware
995 // video frames should not be reused by the VideoFrameProvider, but
996 // software frames can be.
997 hw_frame_provider_
.set_frame(NULL
);
998 scaled_hw_frame_provider_
.set_frame(NULL
);
1002 DrawResult
PrepareToDrawOnThread(LayerTreeHostImpl
* host_impl
,
1003 LayerTreeHostImpl::FrameData
* frame
,
1004 DrawResult draw_result
) override
{
1005 if (host_impl
->active_tree()->source_frame_number() == 2) {
1006 // Lose the context during draw on the second commit. This will cause
1007 // a third commit to recover.
1008 context3d_
->set_times_bind_texture_succeeds(0);
1013 scoped_ptr
<FakeOutputSurface
> CreateFakeOutputSurface() override
{
1014 // This will get called twice:
1015 // First when we create the initial output surface...
1016 if (layer_tree_host()->source_frame_number() > 0) {
1017 // ... and then again after we forced the context to be lost.
1018 lost_context_
= true;
1020 return LayerTreeHostContextTest::CreateFakeOutputSurface();
1023 void DidCommitAndDrawFrame() override
{
1024 ASSERT_TRUE(layer_tree_host()->hud_layer());
1025 // End the test once we know the 3nd frame drew.
1026 if (layer_tree_host()->source_frame_number() < 5) {
1027 layer_tree_host()->root_layer()->SetNeedsDisplay();
1028 layer_tree_host()->SetNeedsCommit();
1034 void AfterTest() override
{ EXPECT_TRUE(lost_context_
); }
1037 FakeContentLayerClient client_
;
1040 FakeOutputSurfaceClient output_surface_client_
;
1041 scoped_ptr
<FakeOutputSurface
> child_output_surface_
;
1042 scoped_ptr
<SharedBitmapManager
> shared_bitmap_manager_
;
1043 scoped_ptr
<ResourceProvider
> child_resource_provider_
;
1045 scoped_refptr
<DelegatedFrameResourceCollection
>
1046 delegated_resource_collection_
;
1047 scoped_refptr
<DelegatedFrameProvider
> delegated_frame_provider_
;
1049 scoped_refptr
<VideoFrame
> color_video_frame_
;
1050 scoped_refptr
<VideoFrame
> hw_video_frame_
;
1051 scoped_refptr
<VideoFrame
> scaled_hw_video_frame_
;
1053 FakeVideoFrameProvider color_frame_provider_
;
1054 FakeVideoFrameProvider hw_frame_provider_
;
1055 FakeVideoFrameProvider scaled_hw_frame_provider_
;
1057 LayerSettings layer_settings_
;
1060 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources
);
1062 class LayerTreeHostContextTestImplSidePainting
1063 : public LayerTreeHostContextTest
{
1065 void SetupTree() override
{
1066 scoped_refptr
<Layer
> root
= Layer::Create(layer_settings());
1067 root
->SetBounds(gfx::Size(10, 10));
1068 root
->SetIsDrawable(true);
1070 scoped_refptr
<PictureLayer
> picture
=
1071 PictureLayer::Create(layer_settings(), &client_
);
1072 picture
->SetBounds(gfx::Size(10, 10));
1073 picture
->SetIsDrawable(true);
1074 root
->AddChild(picture
);
1076 layer_tree_host()->SetRootLayer(root
);
1077 LayerTreeHostContextTest::SetupTree();
1080 void BeginTest() override
{
1081 times_to_lose_during_commit_
= 1;
1082 PostSetNeedsCommitToMainThread();
1085 void AfterTest() override
{}
1087 void DidInitializeOutputSurface() override
{ EndTest(); }
1090 FakeContentLayerClient client_
;
1093 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting
);
1095 class ScrollbarLayerLostContext
: public LayerTreeHostContextTest
{
1097 ScrollbarLayerLostContext() : commits_(0) {}
1099 void BeginTest() override
{
1100 scoped_refptr
<Layer
> scroll_layer
= Layer::Create(layer_settings());
1101 scrollbar_layer_
= FakePaintedScrollbarLayer::Create(
1102 layer_settings(), false, true, scroll_layer
->id());
1103 scrollbar_layer_
->SetBounds(gfx::Size(10, 100));
1104 layer_tree_host()->root_layer()->AddChild(scrollbar_layer_
);
1105 layer_tree_host()->root_layer()->AddChild(scroll_layer
);
1106 PostSetNeedsCommitToMainThread();
1109 void AfterTest() override
{}
1111 void CommitCompleteOnThread(LayerTreeHostImpl
* impl
) override
{
1112 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1117 // First (regular) update, we should upload 2 resources (thumb, and
1119 EXPECT_EQ(1, scrollbar_layer_
->update_count());
1123 // Second update, after the lost context, we should still upload 2
1124 // resources even if the contents haven't changed.
1125 EXPECT_EQ(2, scrollbar_layer_
->update_count());
1135 scoped_refptr
<FakePaintedScrollbarLayer
> scrollbar_layer_
;
1138 SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext
);
1140 class UIResourceLostTest
: public LayerTreeHostContextTest
{
1142 UIResourceLostTest() : time_step_(0) {}
1143 void InitializeSettings(LayerTreeSettings
* settings
) override
{
1144 settings
->renderer_settings
.texture_id_allocation_chunk_size
= 1;
1146 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
1147 void AfterTest() override
{}
1149 // This is called on the main thread after each commit and
1150 // DidActivateTreeOnThread, with the value of time_step_ at the time
1151 // of the call to DidActivateTreeOnThread. Similar tests will do
1152 // work on the main thread in DidCommit but that is unsuitable because
1153 // the main thread work for these tests must happen after
1154 // DidActivateTreeOnThread, which happens after DidCommit with impl-side
1156 virtual void StepCompleteOnMainThread(int time_step
) = 0;
1158 // Called after DidActivateTreeOnThread. If this is done during the commit,
1159 // the call to StepCompleteOnMainThread will not occur until after
1160 // the commit completes, because the main thread is blocked.
1161 void PostStepCompleteToMainThread() {
1162 proxy()->MainThreadTaskRunner()->PostTask(
1164 base::Bind(&UIResourceLostTest::StepCompleteOnMainThreadInternal
,
1165 base::Unretained(this),
1169 void PostLoseContextToImplThread() {
1170 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1171 ImplThreadTaskRunner()->PostTask(
1173 base::Bind(&LayerTreeHostContextTest::LoseContext
,
1174 base::Unretained(this)));
1179 scoped_ptr
<FakeScopedUIResource
> ui_resource_
;
1182 void StepCompleteOnMainThreadInternal(int step
) {
1183 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1184 StepCompleteOnMainThread(step
);
1188 class UIResourceLostTestSimple
: public UIResourceLostTest
{
1190 // This is called when the new layer tree has been activated.
1191 virtual void StepCompleteOnImplThread(LayerTreeHostImpl
* impl
) = 0;
1193 void DidActivateTreeOnThread(LayerTreeHostImpl
* impl
) override
{
1194 StepCompleteOnImplThread(impl
);
1195 PostStepCompleteToMainThread();
1200 // Losing context after an UI resource has been created.
1201 class UIResourceLostAfterCommit
: public UIResourceLostTestSimple
{
1203 void StepCompleteOnMainThread(int step
) override
{
1204 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1207 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1208 // Expects a valid UIResourceId.
1209 EXPECT_NE(0, ui_resource_
->id());
1210 PostSetNeedsCommitToMainThread();
1213 // Release resource before ending the test.
1214 ui_resource_
= nullptr;
1223 void StepCompleteOnImplThread(LayerTreeHostImpl
* impl
) override
{
1224 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1225 switch (time_step_
) {
1227 // The resource should have been created on LTHI after the commit.
1228 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1229 PostSetNeedsCommitToMainThread();
1235 // The resources should have been recreated. The bitmap callback should
1236 // have been called once with the resource_lost flag set to true.
1237 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1238 // Resource Id on the impl-side have been recreated as well. Note
1239 // that the same UIResourceId persists after the context lost.
1240 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1241 PostSetNeedsCommitToMainThread();
1247 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostAfterCommit
);
1249 // Losing context before UI resource requests can be commited. Three sequences
1250 // of creation/deletion are considered:
1251 // 1. Create one resource -> Context Lost => Expect the resource to have been
1253 // 2. Delete an exisiting resource (test_id0_) -> create a second resource
1254 // (test_id1_) -> Context Lost => Expect the test_id0_ to be removed and
1255 // test_id1_ to have been created.
1256 // 3. Create one resource -> Delete that same resource -> Context Lost => Expect
1257 // the resource to not exist in the manager.
1258 class UIResourceLostBeforeCommit
: public UIResourceLostTestSimple
{
1260 UIResourceLostBeforeCommit() : test_id0_(0), test_id1_(0) {}
1262 void StepCompleteOnMainThread(int step
) override
{
1265 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1266 // Lose the context on the impl thread before the commit.
1267 PostLoseContextToImplThread();
1271 // Currently one resource has been created.
1272 test_id0_
= ui_resource_
->id();
1273 // Delete this resource.
1274 ui_resource_
= nullptr;
1275 // Create another resource.
1276 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1277 test_id1_
= ui_resource_
->id();
1278 // Sanity check that two resource creations return different ids.
1279 EXPECT_NE(test_id0_
, test_id1_
);
1280 // Lose the context on the impl thread before the commit.
1281 PostLoseContextToImplThread();
1284 // Clear the manager of resources.
1285 ui_resource_
= nullptr;
1286 PostSetNeedsCommitToMainThread();
1290 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1291 test_id0_
= ui_resource_
->id();
1292 // Sanity check the UIResourceId should not be 0.
1293 EXPECT_NE(0, test_id0_
);
1294 // Usually ScopedUIResource are deleted from the manager in their
1295 // destructor (so usually ui_resource_ = nullptr). But here we need
1296 // ui_resource_ for the next step, so call DeleteUIResource directly.
1297 layer_tree_host()->DeleteUIResource(test_id0_
);
1298 // Delete the resouce and then lose the context.
1299 PostLoseContextToImplThread();
1302 // Release resource before ending the test.
1303 ui_resource_
= nullptr;
1312 void StepCompleteOnImplThread(LayerTreeHostImpl
* impl
) override
{
1313 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1314 switch (time_step_
) {
1316 // Sequence 1 (continued):
1317 // The first context lost happens before the resources were created,
1318 // and because it resulted in no resources being destroyed, it does not
1319 // trigger resource re-creation.
1320 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1321 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1322 // Resource Id on the impl-side has been created.
1323 PostSetNeedsCommitToMainThread();
1326 // Sequence 2 (continued):
1327 // The previous resource should have been deleted.
1328 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(test_id0_
));
1329 // The second resource should have been created.
1330 EXPECT_NE(0u, impl
->ResourceIdForUIResource(test_id1_
));
1331 // The second resource called the resource callback once and since the
1332 // context is lost, a "resource lost" callback was also issued.
1333 EXPECT_EQ(2, ui_resource_
->resource_create_count
);
1334 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1337 // Sequence 3 (continued):
1338 // Expect the resource callback to have been called once.
1339 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1340 // No "resource lost" callbacks.
1341 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1342 // The UI resource id should not be valid
1343 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(test_id0_
));
1349 UIResourceId test_id0_
;
1350 UIResourceId test_id1_
;
1353 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeCommit
);
1355 // Losing UI resource before the pending trees is activated but after the
1356 // commit. Impl-side-painting only.
1357 class UIResourceLostBeforeActivateTree
: public UIResourceLostTest
{
1358 void StepCompleteOnMainThread(int step
) override
{
1359 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1362 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1363 PostSetNeedsCommitToMainThread();
1366 test_id_
= ui_resource_
->id();
1367 ui_resource_
= nullptr;
1368 PostSetNeedsCommitToMainThread();
1371 // Release resource before ending the test.
1372 ui_resource_
= nullptr;
1376 // Make sure no extra commits happened.
1381 void CommitCompleteOnThread(LayerTreeHostImpl
* impl
) override
{
1382 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1383 switch (time_step_
) {
1385 PostSetNeedsCommitToMainThread();
1388 PostSetNeedsCommitToMainThread();
1393 void WillActivateTreeOnThread(LayerTreeHostImpl
* impl
) override
{
1394 switch (time_step_
) {
1396 // The resource creation callback has been called.
1397 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1398 // The resource is not yet lost (sanity check).
1399 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1400 // The resource should not have been created yet on the impl-side.
1401 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1410 void DidActivateTreeOnThread(LayerTreeHostImpl
* impl
) override
{
1411 LayerTreeHostContextTest::DidActivateTreeOnThread(impl
);
1412 switch (time_step_
) {
1414 // The pending requests on the impl-side should have been processed.
1415 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1418 // The "lost resource" callback should have been called once.
1419 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1422 // The resource is deleted and should not be in the manager. Use
1423 // test_id_ since ui_resource_ has been deleted.
1424 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(test_id_
));
1428 PostStepCompleteToMainThread();
1433 UIResourceId test_id_
;
1436 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeActivateTree
);
1438 // Resources evicted explicitly and by visibility changes.
1439 class UIResourceLostEviction
: public UIResourceLostTestSimple
{
1441 void StepCompleteOnMainThread(int step
) override
{
1442 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1445 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1446 EXPECT_NE(0, ui_resource_
->id());
1447 PostSetNeedsCommitToMainThread();
1450 // Make the tree not visible.
1451 PostSetVisibleToMainThread(false);
1454 // Release resource before ending the test.
1455 ui_resource_
= nullptr;
1463 void DidSetVisibleOnImplTree(LayerTreeHostImpl
* impl
, bool visible
) override
{
1464 TestWebGraphicsContext3D
* context
= TestContext();
1466 // All resources should have been evicted.
1467 ASSERT_EQ(0u, context
->NumTextures());
1468 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1469 EXPECT_EQ(2, ui_resource_
->resource_create_count
);
1470 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1471 // Drawing is disabled both because of the evicted resources and
1472 // because the renderer is not visible.
1473 EXPECT_FALSE(impl
->CanDraw());
1474 // Make the renderer visible again.
1475 PostSetVisibleToMainThread(true);
1479 void StepCompleteOnImplThread(LayerTreeHostImpl
* impl
) override
{
1480 TestWebGraphicsContext3D
* context
= TestContext();
1481 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1482 switch (time_step_
) {
1484 // The resource should have been created on LTHI after the commit.
1485 ASSERT_EQ(1u, context
->NumTextures());
1486 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1487 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1488 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1489 EXPECT_TRUE(impl
->CanDraw());
1490 // Evict all UI resources. This will trigger a commit.
1491 impl
->EvictAllUIResources();
1492 ASSERT_EQ(0u, context
->NumTextures());
1493 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1494 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1495 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1496 EXPECT_FALSE(impl
->CanDraw());
1499 // The resource should have been recreated.
1500 ASSERT_EQ(1u, context
->NumTextures());
1501 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1502 EXPECT_EQ(2, ui_resource_
->resource_create_count
);
1503 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1504 EXPECT_TRUE(impl
->CanDraw());
1507 // The resource should have been recreated after visibility was
1509 ASSERT_EQ(1u, context
->NumTextures());
1510 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1511 EXPECT_EQ(3, ui_resource_
->resource_create_count
);
1512 EXPECT_EQ(2, ui_resource_
->lost_resource_count
);
1513 EXPECT_TRUE(impl
->CanDraw());
1519 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction
);
1521 class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame
1522 : public LayerTreeHostContextTest
{
1524 void BeginTest() override
{
1526 PostSetNeedsCommitToMainThread();
1529 void ScheduledActionWillSendBeginMainFrame() override
{
1534 // Defer commits before the BeginFrame arrives, causing it to be delayed.
1535 PostSetDeferCommitsToMainThread(true);
1536 // Meanwhile, lose the context while we are in defer commits.
1537 ImplThreadTaskRunner()->PostTask(
1539 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1540 LoseContextOnImplThread
,
1541 base::Unretained(this)));
1544 void LoseContextOnImplThread() {
1547 // After losing the context, stop deferring commits.
1548 PostSetDeferCommitsToMainThread(false);
1551 void WillBeginMainFrame() override
{
1552 // Don't begin a frame with a lost surface.
1553 EXPECT_FALSE(layer_tree_host()->output_surface_lost());
1556 void DidCommitAndDrawFrame() override
{ EndTest(); }
1558 void AfterTest() override
{}
1563 SINGLE_AND_MULTI_THREAD_TEST_F(
1564 LayerTreeHostContextTestLoseAfterSendingBeginMainFrame
);