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 // This tests the OutputSurface release logic in the following sequence.
386 // SetUp LTH and create and init OutputSurface
387 // LTH::SetVisible(false);
388 // LTH::ReleaseOutputSurface();
390 // LTH::SetVisible(true);
391 // Create and init new OutputSurface
392 class LayerTreeHostClientTakeAwayOutputSurface
393 : public LayerTreeHostContextTest
{
395 LayerTreeHostClientTakeAwayOutputSurface()
396 : LayerTreeHostContextTest(), setos_counter_(0) {}
398 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
400 void RequestNewOutputSurface() override
{
401 if (layer_tree_host()->visible())
402 CreateAndSetOutputSurface();
405 void CreateAndSetOutputSurface() {
406 scoped_ptr
<OutputSurface
> surface
=
407 LayerTreeHostContextTest::CreateOutputSurface();
410 layer_tree_host()->SetOutputSurface(surface
.Pass());
413 void HideAndReleaseOutputSurface() {
414 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
415 layer_tree_host()->SetVisible(false);
416 scoped_ptr
<OutputSurface
> surface
=
417 layer_tree_host()->ReleaseOutputSurface();
419 surface
->context_provider()->DetachFromThread();
420 MainThreadTaskRunner()->PostTask(
422 base::Bind(&LayerTreeHostClientTakeAwayOutputSurface::MakeVisible
,
423 base::Unretained(this)));
426 void DidInitializeOutputSurface() override
{
427 EXPECT_TRUE(layer_tree_host()->visible());
428 if (setos_counter_
== 1) {
429 MainThreadTaskRunner()->PostTask(
430 FROM_HERE
, base::Bind(&LayerTreeHostClientTakeAwayOutputSurface::
431 HideAndReleaseOutputSurface
,
432 base::Unretained(this)));
439 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
440 layer_tree_host()->SetVisible(true);
443 void AfterTest() override
{}
448 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostClientTakeAwayOutputSurface
);
450 class MultipleCompositeDoesNotCreateOutputSurface
451 : public LayerTreeHostContextTest
{
453 MultipleCompositeDoesNotCreateOutputSurface()
454 : LayerTreeHostContextTest(), request_count_(0) {}
456 void InitializeSettings(LayerTreeSettings
* settings
) override
{
457 settings
->single_thread_proxy_scheduler
= false;
458 settings
->use_zero_copy
= true;
461 void RequestNewOutputSurface() override
{
462 EXPECT_GE(1, ++request_count_
);
466 void BeginTest() override
{
467 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
468 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(2));
471 scoped_ptr
<OutputSurface
> CreateOutputSurface() override
{
476 void DidInitializeOutputSurface() override
{ EXPECT_TRUE(false); }
478 void AfterTest() override
{}
483 // This test uses Composite() which only exists for single thread.
484 SINGLE_THREAD_TEST_F(MultipleCompositeDoesNotCreateOutputSurface
);
486 // This test makes sure that once a SingleThreadProxy issues a
487 // DidFailToInitializeOutputSurface, that future Composite calls will not
488 // trigger additional requests for output surfaces.
489 class FailedCreateDoesNotCreateExtraOutputSurface
490 : public LayerTreeHostContextTest
{
492 FailedCreateDoesNotCreateExtraOutputSurface()
493 : LayerTreeHostContextTest(), num_requests_(0), has_failed_(false) {}
495 void InitializeSettings(LayerTreeSettings
* settings
) override
{
496 settings
->single_thread_proxy_scheduler
= false;
497 settings
->use_zero_copy
= true;
500 void RequestNewOutputSurface() override
{
502 // There should be one initial request and then one request from
503 // the LayerTreeTest test hooks DidFailToInitializeOutputSurface (which is
504 // hard to skip). This second request is just ignored and is test cruft.
505 EXPECT_LE(num_requests_
, 2);
506 if (num_requests_
> 1)
508 ExpectCreateToFail();
509 layer_tree_host()->SetOutputSurface(
510 make_scoped_ptr(new FailureOutputSurface(false)));
513 void BeginTest() override
{
514 // First composite tries to create a surface.
515 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
516 EXPECT_EQ(num_requests_
, 2);
517 EXPECT_TRUE(has_failed_
);
519 // Second composite should not request or fail.
520 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(2));
521 EXPECT_EQ(num_requests_
, 2);
525 void DidInitializeOutputSurface() override
{ EXPECT_TRUE(false); }
527 void DidFailToInitializeOutputSurface() override
{
528 LayerTreeHostContextTest::DidFailToInitializeOutputSurface();
529 EXPECT_FALSE(has_failed_
);
533 void AfterTest() override
{}
539 // This test uses Composite() which only exists for single thread.
540 SINGLE_THREAD_TEST_F(FailedCreateDoesNotCreateExtraOutputSurface
);
542 class LayerTreeHostContextTestCommitAfterDelayedOutputSurface
543 : public LayerTreeHostContextTest
{
545 LayerTreeHostContextTestCommitAfterDelayedOutputSurface()
546 : LayerTreeHostContextTest(), creating_output_(false) {}
548 void InitializeSettings(LayerTreeSettings
* settings
) override
{
549 settings
->single_thread_proxy_scheduler
= false;
550 settings
->use_zero_copy
= true;
553 void RequestNewOutputSurface() override
{
554 MainThreadTaskRunner()->PostTask(
556 base::Bind(&LayerTreeHostContextTestCommitAfterDelayedOutputSurface::
557 CreateAndSetOutputSurface
,
558 base::Unretained(this)));
561 void CreateAndSetOutputSurface() {
562 creating_output_
= true;
563 layer_tree_host()->SetOutputSurface(
564 LayerTreeHostContextTest::CreateOutputSurface());
567 void BeginTest() override
{
568 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
571 void ScheduleComposite() override
{
572 if (creating_output_
)
576 void AfterTest() override
{}
578 bool creating_output_
;
581 // This test uses Composite() which only exists for single thread.
582 SINGLE_THREAD_TEST_F(LayerTreeHostContextTestCommitAfterDelayedOutputSurface
);
584 class LayerTreeHostContextTestAvoidUnnecessaryComposite
585 : public LayerTreeHostContextTest
{
587 LayerTreeHostContextTestAvoidUnnecessaryComposite()
588 : LayerTreeHostContextTest(), in_composite_(false) {}
590 void InitializeSettings(LayerTreeSettings
* settings
) override
{
591 settings
->single_thread_proxy_scheduler
= false;
592 settings
->use_zero_copy
= true;
595 void RequestNewOutputSurface() override
{
596 layer_tree_host()->SetOutputSurface(
597 LayerTreeHostContextTest::CreateOutputSurface());
601 void BeginTest() override
{
602 in_composite_
= true;
603 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
604 in_composite_
= false;
607 void ScheduleComposite() override
{ EXPECT_FALSE(in_composite_
); }
609 void AfterTest() override
{}
614 // This test uses Composite() which only exists for single thread.
615 SINGLE_THREAD_TEST_F(LayerTreeHostContextTestAvoidUnnecessaryComposite
);
617 // This test uses PictureLayer to check for a working context.
618 class LayerTreeHostContextTestLostContextSucceedsWithContent
619 : public LayerTreeHostContextTestLostContextSucceeds
{
621 void SetupTree() override
{
622 root_
= Layer::Create(layer_settings());
623 root_
->SetBounds(gfx::Size(10, 10));
624 root_
->SetIsDrawable(true);
626 // Paint non-solid color.
628 paint
.setColor(SkColorSetARGB(100, 80, 200, 200));
629 client_
.add_draw_rect(gfx::Rect(5, 5), paint
);
631 layer_
= FakePictureLayer::Create(layer_settings(), &client_
);
632 layer_
->SetBounds(gfx::Size(10, 10));
633 layer_
->SetIsDrawable(true);
635 root_
->AddChild(layer_
);
637 layer_tree_host()->SetRootLayer(root_
);
638 LayerTreeHostContextTest::SetupTree();
641 void InvalidateAndSetNeedsCommit() override
{
642 // Invalidate the render surface so we don't try to use a cached copy of the
643 // surface. We want to make sure to test the drawing paths for drawing to
645 layer_
->SetNeedsDisplay();
646 LayerTreeHostContextTestLostContextSucceeds::InvalidateAndSetNeedsCommit();
649 void DrawLayersOnThread(LayerTreeHostImpl
* host_impl
) override
{
650 FakePictureLayerImpl
* picture_impl
= static_cast<FakePictureLayerImpl
*>(
651 host_impl
->active_tree()->root_layer()->children()[0]);
652 EXPECT_TRUE(picture_impl
->HighResTiling()
659 FakeContentLayerClient client_
;
660 scoped_refptr
<Layer
> root_
;
661 scoped_refptr
<Layer
> layer_
;
664 SINGLE_AND_MULTI_THREAD_TEST_F(
665 LayerTreeHostContextTestLostContextSucceedsWithContent
);
667 class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
668 : public LayerTreeHostContextTest
{
670 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
671 : times_to_fail_(1), times_initialized_(0) {
672 times_to_fail_create_
= times_to_fail_
;
675 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
677 void DidInitializeOutputSurface() override
{ times_initialized_
++; }
679 void DrawLayersOnThread(LayerTreeHostImpl
* host_impl
) override
{ EndTest(); }
681 void AfterTest() override
{
682 EXPECT_EQ(times_to_fail_
, times_create_failed_
);
683 EXPECT_NE(0, times_initialized_
);
688 int times_initialized_
;
691 SINGLE_AND_MULTI_THREAD_TEST_F(
692 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
);
694 class LayerTreeHostContextTestLostContextAndEvictTextures
695 : public LayerTreeHostContextTest
{
697 LayerTreeHostContextTestLostContextAndEvictTextures()
698 : LayerTreeHostContextTest(),
701 lost_context_(false) {}
703 void SetupTree() override
{
704 // Paint non-solid color.
706 paint
.setColor(SkColorSetARGB(100, 80, 200, 200));
707 client_
.add_draw_rect(gfx::Rect(5, 5), paint
);
709 scoped_refptr
<FakePictureLayer
> picture_layer
=
710 FakePictureLayer::Create(layer_settings(), &client_
);
711 picture_layer
->SetBounds(gfx::Size(10, 20));
712 layer_tree_host()->SetRootLayer(picture_layer
);
714 LayerTreeHostContextTest::SetupTree();
717 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
719 void PostEvictTextures() {
720 if (HasImplThread()) {
721 ImplThreadTaskRunner()->PostTask(
723 base::Bind(&LayerTreeHostContextTestLostContextAndEvictTextures::
724 EvictTexturesOnImplThread
,
725 base::Unretained(this)));
727 DebugScopedSetImplThread
impl(proxy());
728 EvictTexturesOnImplThread();
732 void EvictTexturesOnImplThread() {
733 impl_host_
->EvictTexturesForTesting();
735 if (lose_after_evict_
) {
737 lost_context_
= true;
741 void DidCommitAndDrawFrame() override
{
742 if (num_commits_
> 1)
747 void CommitCompleteOnThread(LayerTreeHostImpl
* impl
) override
{
748 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
749 if (num_commits_
> 1)
752 if (!lose_after_evict_
) {
754 lost_context_
= true;
758 void DrawLayersOnThread(LayerTreeHostImpl
* impl
) override
{
759 FakePictureLayerImpl
* picture_impl
=
760 static_cast<FakePictureLayerImpl
*>(impl
->active_tree()->root_layer());
761 EXPECT_TRUE(picture_impl
->HighResTiling()
771 void DidInitializeOutputSurface() override
{}
773 void AfterTest() override
{}
776 bool lose_after_evict_
;
777 FakeContentLayerClient client_
;
778 LayerTreeHostImpl
* impl_host_
;
783 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
784 LoseAfterEvict_SingleThread_DirectRenderer
) {
785 lose_after_evict_
= true;
786 RunTest(false, false);
789 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
790 LoseAfterEvict_SingleThread_DelegatingRenderer
) {
791 lose_after_evict_
= true;
792 RunTest(false, true);
795 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
796 LoseAfterEvict_MultiThread_DirectRenderer
) {
797 lose_after_evict_
= true;
798 RunTest(true, false);
801 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
802 LoseAfterEvict_MultiThread_DelegatingRenderer
) {
803 lose_after_evict_
= true;
807 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
808 LoseBeforeEvict_SingleThread_DirectRenderer
) {
809 lose_after_evict_
= false;
810 RunTest(false, false);
813 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
814 LoseBeforeEvict_SingleThread_DelegatingRenderer
) {
815 lose_after_evict_
= false;
816 RunTest(false, true);
819 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
820 LoseBeforeEvict_MultiThread_DirectRenderer
) {
821 lose_after_evict_
= false;
822 RunTest(true, false);
825 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
826 LoseBeforeEvict_MultiThread_DelegatingRenderer
) {
827 lose_after_evict_
= false;
831 class LayerTreeHostContextTestLayersNotified
: public LayerTreeHostContextTest
{
833 LayerTreeHostContextTestLayersNotified()
834 : LayerTreeHostContextTest(), num_commits_(0) {}
836 void SetupTree() override
{
837 root_
= FakePictureLayer::Create(layer_settings(), &client_
);
838 child_
= FakePictureLayer::Create(layer_settings(), &client_
);
839 grandchild_
= FakePictureLayer::Create(layer_settings(), &client_
);
841 root_
->AddChild(child_
);
842 child_
->AddChild(grandchild_
);
844 layer_tree_host()->SetRootLayer(root_
);
845 LayerTreeHostContextTest::SetupTree();
848 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
850 void DidActivateTreeOnThread(LayerTreeHostImpl
* host_impl
) override
{
851 LayerTreeHostContextTest::DidActivateTreeOnThread(host_impl
);
853 FakePictureLayerImpl
* root_picture
= NULL
;
854 FakePictureLayerImpl
* child_picture
= NULL
;
855 FakePictureLayerImpl
* grandchild_picture
= NULL
;
857 root_picture
= static_cast<FakePictureLayerImpl
*>(
858 host_impl
->active_tree()->root_layer());
860 static_cast<FakePictureLayerImpl
*>(root_picture
->children()[0]);
862 static_cast<FakePictureLayerImpl
*>(child_picture
->children()[0]);
865 switch (num_commits_
) {
867 EXPECT_EQ(0u, root_picture
->release_resources_count());
868 EXPECT_EQ(0u, child_picture
->release_resources_count());
869 EXPECT_EQ(0u, grandchild_picture
->release_resources_count());
871 // Lose the context and struggle to recreate it.
873 times_to_fail_create_
= 1;
876 EXPECT_TRUE(root_picture
->release_resources_count());
877 EXPECT_TRUE(child_picture
->release_resources_count());
878 EXPECT_TRUE(grandchild_picture
->release_resources_count());
887 void AfterTest() override
{}
892 FakeContentLayerClient client_
;
893 scoped_refptr
<Layer
> root_
;
894 scoped_refptr
<Layer
> child_
;
895 scoped_refptr
<Layer
> grandchild_
;
898 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified
);
900 class LayerTreeHostContextTestDontUseLostResources
901 : public LayerTreeHostContextTest
{
903 LayerTreeHostContextTestDontUseLostResources() : lost_context_(false) {
904 context_should_support_io_surface_
= true;
906 child_output_surface_
= FakeOutputSurface::Create3d();
907 child_output_surface_
->BindToClient(&output_surface_client_
);
908 shared_bitmap_manager_
.reset(new TestSharedBitmapManager());
909 child_resource_provider_
= FakeResourceProvider::Create(
910 child_output_surface_
.get(), shared_bitmap_manager_
.get());
913 static void EmptyReleaseCallback(unsigned sync_point
, bool lost
) {}
915 void SetupTree() override
{
916 gpu::gles2::GLES2Interface
* gl
=
917 child_output_surface_
->context_provider()->ContextGL();
919 scoped_ptr
<DelegatedFrameData
> frame_data(new DelegatedFrameData
);
921 scoped_ptr
<RenderPass
> pass_for_quad
= RenderPass::Create();
922 pass_for_quad
->SetNew(
923 // AppendOneOfEveryQuadType() makes a RenderPass quad with this id.
925 gfx::Rect(0, 0, 10, 10),
926 gfx::Rect(0, 0, 10, 10),
929 scoped_ptr
<RenderPass
> pass
= RenderPass::Create();
930 pass
->SetNew(RenderPassId(1, 1),
931 gfx::Rect(0, 0, 10, 10),
932 gfx::Rect(0, 0, 10, 10),
934 uint32_t mailbox_sync_point
;
935 AddOneOfEveryQuadType(pass
.get(), child_resource_provider_
.get(),
936 RenderPassId(2, 1), &mailbox_sync_point
);
938 frame_data
->render_pass_list
.push_back(pass_for_quad
.Pass());
939 frame_data
->render_pass_list
.push_back(pass
.Pass());
941 delegated_resource_collection_
= new DelegatedFrameResourceCollection
;
942 delegated_frame_provider_
= new DelegatedFrameProvider(
943 delegated_resource_collection_
.get(), frame_data
.Pass());
945 ResourceId resource
= child_resource_provider_
->CreateResource(
946 gfx::Size(4, 4), GL_CLAMP_TO_EDGE
,
947 ResourceProvider::TEXTURE_HINT_IMMUTABLE
, RGBA_8888
);
948 ResourceProvider::ScopedWriteLockGL
lock(child_resource_provider_
.get(),
951 gpu::Mailbox mailbox
;
952 gl
->GenMailboxCHROMIUM(mailbox
.name
);
953 GLuint sync_point
= gl
->InsertSyncPointCHROMIUM();
955 scoped_refptr
<Layer
> root
= Layer::Create(layer_settings());
956 root
->SetBounds(gfx::Size(10, 10));
957 root
->SetIsDrawable(true);
959 scoped_refptr
<FakeDelegatedRendererLayer
> delegated
=
960 FakeDelegatedRendererLayer::Create(layer_settings(),
961 delegated_frame_provider_
.get());
962 delegated
->SetBounds(gfx::Size(10, 10));
963 delegated
->SetIsDrawable(true);
964 root
->AddChild(delegated
);
966 scoped_refptr
<PictureLayer
> layer
=
967 PictureLayer::Create(layer_settings(), &client_
);
968 layer
->SetBounds(gfx::Size(10, 10));
969 layer
->SetIsDrawable(true);
970 root
->AddChild(layer
);
972 scoped_refptr
<TextureLayer
> texture
=
973 TextureLayer::CreateForMailbox(layer_settings_
, NULL
);
974 texture
->SetBounds(gfx::Size(10, 10));
975 texture
->SetIsDrawable(true);
976 texture
->SetTextureMailbox(
977 TextureMailbox(mailbox
, GL_TEXTURE_2D
, sync_point
),
978 SingleReleaseCallback::Create(
979 base::Bind(&LayerTreeHostContextTestDontUseLostResources::
980 EmptyReleaseCallback
)));
981 root
->AddChild(texture
);
983 scoped_refptr
<PictureLayer
> mask
=
984 PictureLayer::Create(layer_settings_
, &client_
);
985 mask
->SetBounds(gfx::Size(10, 10));
987 scoped_refptr
<PictureLayer
> layer_with_mask
=
988 PictureLayer::Create(layer_settings_
, &client_
);
989 layer_with_mask
->SetBounds(gfx::Size(10, 10));
990 layer_with_mask
->SetIsDrawable(true);
991 layer_with_mask
->SetMaskLayer(mask
.get());
992 root
->AddChild(layer_with_mask
);
994 scoped_refptr
<VideoLayer
> video_color
= VideoLayer::Create(
995 layer_settings_
, &color_frame_provider_
, media::VIDEO_ROTATION_0
);
996 video_color
->SetBounds(gfx::Size(10, 10));
997 video_color
->SetIsDrawable(true);
998 root
->AddChild(video_color
);
1000 scoped_refptr
<VideoLayer
> video_hw
= VideoLayer::Create(
1001 layer_settings_
, &hw_frame_provider_
, media::VIDEO_ROTATION_0
);
1002 video_hw
->SetBounds(gfx::Size(10, 10));
1003 video_hw
->SetIsDrawable(true);
1004 root
->AddChild(video_hw
);
1006 scoped_refptr
<VideoLayer
> video_scaled_hw
= VideoLayer::Create(
1007 layer_settings_
, &scaled_hw_frame_provider_
, media::VIDEO_ROTATION_0
);
1008 video_scaled_hw
->SetBounds(gfx::Size(10, 10));
1009 video_scaled_hw
->SetIsDrawable(true);
1010 root
->AddChild(video_scaled_hw
);
1012 color_video_frame_
= VideoFrame::CreateColorFrame(
1013 gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
1014 hw_video_frame_
= VideoFrame::WrapNativeTexture(
1015 media::PIXEL_FORMAT_ARGB
,
1016 gpu::MailboxHolder(mailbox
, GL_TEXTURE_2D
, sync_point
),
1017 media::VideoFrame::ReleaseMailboxCB(), gfx::Size(4, 4),
1018 gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4), base::TimeDelta());
1019 scaled_hw_video_frame_
= VideoFrame::WrapNativeTexture(
1020 media::PIXEL_FORMAT_ARGB
,
1021 gpu::MailboxHolder(mailbox
, GL_TEXTURE_2D
, sync_point
),
1022 media::VideoFrame::ReleaseMailboxCB(), gfx::Size(4, 4),
1023 gfx::Rect(0, 0, 3, 2), gfx::Size(4, 4), base::TimeDelta());
1025 color_frame_provider_
.set_frame(color_video_frame_
);
1026 hw_frame_provider_
.set_frame(hw_video_frame_
);
1027 scaled_hw_frame_provider_
.set_frame(scaled_hw_video_frame_
);
1029 scoped_refptr
<IOSurfaceLayer
> io_surface
=
1030 IOSurfaceLayer::Create(layer_settings_
);
1031 io_surface
->SetBounds(gfx::Size(10, 10));
1032 io_surface
->SetIsDrawable(true);
1033 io_surface
->SetIOSurfaceProperties(1, gfx::Size(10, 10));
1034 root
->AddChild(io_surface
);
1037 LayerTreeDebugState debug_state
;
1038 debug_state
.show_property_changed_rects
= true;
1039 layer_tree_host()->SetDebugState(debug_state
);
1041 scoped_refptr
<PaintedScrollbarLayer
> scrollbar
=
1042 PaintedScrollbarLayer::Create(
1043 layer_settings_
, scoped_ptr
<Scrollbar
>(new FakeScrollbar
).Pass(),
1045 scrollbar
->SetBounds(gfx::Size(10, 10));
1046 scrollbar
->SetIsDrawable(true);
1047 root
->AddChild(scrollbar
);
1049 layer_tree_host()->SetRootLayer(root
);
1050 LayerTreeHostContextTest::SetupTree();
1053 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
1055 void CommitCompleteOnThread(LayerTreeHostImpl
* host_impl
) override
{
1056 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl
);
1058 if (host_impl
->active_tree()->source_frame_number() == 3) {
1059 // On the third commit we're recovering from context loss. Hardware
1060 // video frames should not be reused by the VideoFrameProvider, but
1061 // software frames can be.
1062 hw_frame_provider_
.set_frame(NULL
);
1063 scaled_hw_frame_provider_
.set_frame(NULL
);
1067 DrawResult
PrepareToDrawOnThread(LayerTreeHostImpl
* host_impl
,
1068 LayerTreeHostImpl::FrameData
* frame
,
1069 DrawResult draw_result
) override
{
1070 if (host_impl
->active_tree()->source_frame_number() == 2) {
1071 // Lose the context during draw on the second commit. This will cause
1072 // a third commit to recover.
1073 context3d_
->set_times_bind_texture_succeeds(0);
1078 scoped_ptr
<FakeOutputSurface
> CreateFakeOutputSurface() override
{
1079 // This will get called twice:
1080 // First when we create the initial output surface...
1081 if (layer_tree_host()->source_frame_number() > 0) {
1082 // ... and then again after we forced the context to be lost.
1083 lost_context_
= true;
1085 return LayerTreeHostContextTest::CreateFakeOutputSurface();
1088 void DidCommitAndDrawFrame() override
{
1089 ASSERT_TRUE(layer_tree_host()->hud_layer());
1090 // End the test once we know the 3nd frame drew.
1091 if (layer_tree_host()->source_frame_number() < 5) {
1092 layer_tree_host()->root_layer()->SetNeedsDisplay();
1093 layer_tree_host()->SetNeedsCommit();
1099 void AfterTest() override
{ EXPECT_TRUE(lost_context_
); }
1102 FakeContentLayerClient client_
;
1105 FakeOutputSurfaceClient output_surface_client_
;
1106 scoped_ptr
<FakeOutputSurface
> child_output_surface_
;
1107 scoped_ptr
<SharedBitmapManager
> shared_bitmap_manager_
;
1108 scoped_ptr
<ResourceProvider
> child_resource_provider_
;
1110 scoped_refptr
<DelegatedFrameResourceCollection
>
1111 delegated_resource_collection_
;
1112 scoped_refptr
<DelegatedFrameProvider
> delegated_frame_provider_
;
1114 scoped_refptr
<VideoFrame
> color_video_frame_
;
1115 scoped_refptr
<VideoFrame
> hw_video_frame_
;
1116 scoped_refptr
<VideoFrame
> scaled_hw_video_frame_
;
1118 FakeVideoFrameProvider color_frame_provider_
;
1119 FakeVideoFrameProvider hw_frame_provider_
;
1120 FakeVideoFrameProvider scaled_hw_frame_provider_
;
1122 LayerSettings layer_settings_
;
1125 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources
);
1127 class LayerTreeHostContextTestImplSidePainting
1128 : public LayerTreeHostContextTest
{
1130 void SetupTree() override
{
1131 scoped_refptr
<Layer
> root
= Layer::Create(layer_settings());
1132 root
->SetBounds(gfx::Size(10, 10));
1133 root
->SetIsDrawable(true);
1135 scoped_refptr
<PictureLayer
> picture
=
1136 PictureLayer::Create(layer_settings(), &client_
);
1137 picture
->SetBounds(gfx::Size(10, 10));
1138 picture
->SetIsDrawable(true);
1139 root
->AddChild(picture
);
1141 layer_tree_host()->SetRootLayer(root
);
1142 LayerTreeHostContextTest::SetupTree();
1145 void BeginTest() override
{
1146 times_to_lose_during_commit_
= 1;
1147 PostSetNeedsCommitToMainThread();
1150 void AfterTest() override
{}
1152 void DidInitializeOutputSurface() override
{ EndTest(); }
1155 FakeContentLayerClient client_
;
1158 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting
);
1160 class ScrollbarLayerLostContext
: public LayerTreeHostContextTest
{
1162 ScrollbarLayerLostContext() : commits_(0) {}
1164 void BeginTest() override
{
1165 scoped_refptr
<Layer
> scroll_layer
= Layer::Create(layer_settings());
1166 scrollbar_layer_
= FakePaintedScrollbarLayer::Create(
1167 layer_settings(), false, true, scroll_layer
->id());
1168 scrollbar_layer_
->SetBounds(gfx::Size(10, 100));
1169 layer_tree_host()->root_layer()->AddChild(scrollbar_layer_
);
1170 layer_tree_host()->root_layer()->AddChild(scroll_layer
);
1171 PostSetNeedsCommitToMainThread();
1174 void AfterTest() override
{}
1176 void CommitCompleteOnThread(LayerTreeHostImpl
* impl
) override
{
1177 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1182 // First (regular) update, we should upload 2 resources (thumb, and
1184 EXPECT_EQ(1, scrollbar_layer_
->update_count());
1188 // Second update, after the lost context, we should still upload 2
1189 // resources even if the contents haven't changed.
1190 EXPECT_EQ(2, scrollbar_layer_
->update_count());
1200 scoped_refptr
<FakePaintedScrollbarLayer
> scrollbar_layer_
;
1203 SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext
);
1205 class UIResourceLostTest
: public LayerTreeHostContextTest
{
1207 UIResourceLostTest() : time_step_(0) {}
1208 void InitializeSettings(LayerTreeSettings
* settings
) override
{
1209 settings
->renderer_settings
.texture_id_allocation_chunk_size
= 1;
1211 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
1212 void AfterTest() override
{}
1214 // This is called on the main thread after each commit and
1215 // DidActivateTreeOnThread, with the value of time_step_ at the time
1216 // of the call to DidActivateTreeOnThread. Similar tests will do
1217 // work on the main thread in DidCommit but that is unsuitable because
1218 // the main thread work for these tests must happen after
1219 // DidActivateTreeOnThread, which happens after DidCommit with impl-side
1221 virtual void StepCompleteOnMainThread(int time_step
) = 0;
1223 // Called after DidActivateTreeOnThread. If this is done during the commit,
1224 // the call to StepCompleteOnMainThread will not occur until after
1225 // the commit completes, because the main thread is blocked.
1226 void PostStepCompleteToMainThread() {
1227 proxy()->MainThreadTaskRunner()->PostTask(
1229 base::Bind(&UIResourceLostTest::StepCompleteOnMainThreadInternal
,
1230 base::Unretained(this),
1234 void PostLoseContextToImplThread() {
1235 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1236 ImplThreadTaskRunner()->PostTask(
1238 base::Bind(&LayerTreeHostContextTest::LoseContext
,
1239 base::Unretained(this)));
1244 scoped_ptr
<FakeScopedUIResource
> ui_resource_
;
1247 void StepCompleteOnMainThreadInternal(int step
) {
1248 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1249 StepCompleteOnMainThread(step
);
1253 class UIResourceLostTestSimple
: public UIResourceLostTest
{
1255 // This is called when the new layer tree has been activated.
1256 virtual void StepCompleteOnImplThread(LayerTreeHostImpl
* impl
) = 0;
1258 void DidActivateTreeOnThread(LayerTreeHostImpl
* impl
) override
{
1259 StepCompleteOnImplThread(impl
);
1260 PostStepCompleteToMainThread();
1265 // Losing context after an UI resource has been created.
1266 class UIResourceLostAfterCommit
: public UIResourceLostTestSimple
{
1268 void StepCompleteOnMainThread(int step
) override
{
1269 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1272 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1273 // Expects a valid UIResourceId.
1274 EXPECT_NE(0, ui_resource_
->id());
1275 PostSetNeedsCommitToMainThread();
1278 // Release resource before ending the test.
1279 ui_resource_
= nullptr;
1288 void StepCompleteOnImplThread(LayerTreeHostImpl
* impl
) override
{
1289 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1290 switch (time_step_
) {
1292 // The resource should have been created on LTHI after the commit.
1293 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1294 PostSetNeedsCommitToMainThread();
1300 // The resources should have been recreated. The bitmap callback should
1301 // have been called once with the resource_lost flag set to true.
1302 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1303 // Resource Id on the impl-side have been recreated as well. Note
1304 // that the same UIResourceId persists after the context lost.
1305 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1306 PostSetNeedsCommitToMainThread();
1312 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostAfterCommit
);
1314 // Losing context before UI resource requests can be commited. Three sequences
1315 // of creation/deletion are considered:
1316 // 1. Create one resource -> Context Lost => Expect the resource to have been
1318 // 2. Delete an exisiting resource (test_id0_) -> create a second resource
1319 // (test_id1_) -> Context Lost => Expect the test_id0_ to be removed and
1320 // test_id1_ to have been created.
1321 // 3. Create one resource -> Delete that same resource -> Context Lost => Expect
1322 // the resource to not exist in the manager.
1323 class UIResourceLostBeforeCommit
: public UIResourceLostTestSimple
{
1325 UIResourceLostBeforeCommit() : test_id0_(0), test_id1_(0) {}
1327 void StepCompleteOnMainThread(int step
) override
{
1330 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1331 // Lose the context on the impl thread before the commit.
1332 PostLoseContextToImplThread();
1336 // Currently one resource has been created.
1337 test_id0_
= ui_resource_
->id();
1338 // Delete this resource.
1339 ui_resource_
= nullptr;
1340 // Create another resource.
1341 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1342 test_id1_
= ui_resource_
->id();
1343 // Sanity check that two resource creations return different ids.
1344 EXPECT_NE(test_id0_
, test_id1_
);
1345 // Lose the context on the impl thread before the commit.
1346 PostLoseContextToImplThread();
1349 // Clear the manager of resources.
1350 ui_resource_
= nullptr;
1351 PostSetNeedsCommitToMainThread();
1355 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1356 test_id0_
= ui_resource_
->id();
1357 // Sanity check the UIResourceId should not be 0.
1358 EXPECT_NE(0, test_id0_
);
1359 // Usually ScopedUIResource are deleted from the manager in their
1360 // destructor (so usually ui_resource_ = nullptr). But here we need
1361 // ui_resource_ for the next step, so call DeleteUIResource directly.
1362 layer_tree_host()->DeleteUIResource(test_id0_
);
1363 // Delete the resouce and then lose the context.
1364 PostLoseContextToImplThread();
1367 // Release resource before ending the test.
1368 ui_resource_
= nullptr;
1377 void StepCompleteOnImplThread(LayerTreeHostImpl
* impl
) override
{
1378 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1379 switch (time_step_
) {
1381 // Sequence 1 (continued):
1382 // The first context lost happens before the resources were created,
1383 // and because it resulted in no resources being destroyed, it does not
1384 // trigger resource re-creation.
1385 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1386 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1387 // Resource Id on the impl-side has been created.
1388 PostSetNeedsCommitToMainThread();
1391 // Sequence 2 (continued):
1392 // The previous resource should have been deleted.
1393 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(test_id0_
));
1394 // The second resource should have been created.
1395 EXPECT_NE(0u, impl
->ResourceIdForUIResource(test_id1_
));
1396 // The second resource called the resource callback once and since the
1397 // context is lost, a "resource lost" callback was also issued.
1398 EXPECT_EQ(2, ui_resource_
->resource_create_count
);
1399 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1402 // Sequence 3 (continued):
1403 // Expect the resource callback to have been called once.
1404 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1405 // No "resource lost" callbacks.
1406 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1407 // The UI resource id should not be valid
1408 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(test_id0_
));
1414 UIResourceId test_id0_
;
1415 UIResourceId test_id1_
;
1418 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeCommit
);
1420 // Losing UI resource before the pending trees is activated but after the
1421 // commit. Impl-side-painting only.
1422 class UIResourceLostBeforeActivateTree
: public UIResourceLostTest
{
1423 void StepCompleteOnMainThread(int step
) override
{
1424 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1427 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1428 PostSetNeedsCommitToMainThread();
1431 test_id_
= ui_resource_
->id();
1432 ui_resource_
= nullptr;
1433 PostSetNeedsCommitToMainThread();
1436 // Release resource before ending the test.
1437 ui_resource_
= nullptr;
1441 // Make sure no extra commits happened.
1446 void CommitCompleteOnThread(LayerTreeHostImpl
* impl
) override
{
1447 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1448 switch (time_step_
) {
1450 PostSetNeedsCommitToMainThread();
1453 PostSetNeedsCommitToMainThread();
1458 void WillActivateTreeOnThread(LayerTreeHostImpl
* impl
) override
{
1459 switch (time_step_
) {
1461 // The resource creation callback has been called.
1462 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1463 // The resource is not yet lost (sanity check).
1464 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1465 // The resource should not have been created yet on the impl-side.
1466 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1475 void DidActivateTreeOnThread(LayerTreeHostImpl
* impl
) override
{
1476 LayerTreeHostContextTest::DidActivateTreeOnThread(impl
);
1477 switch (time_step_
) {
1479 // The pending requests on the impl-side should have been processed.
1480 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1483 // The "lost resource" callback should have been called once.
1484 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1487 // The resource is deleted and should not be in the manager. Use
1488 // test_id_ since ui_resource_ has been deleted.
1489 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(test_id_
));
1493 PostStepCompleteToMainThread();
1498 UIResourceId test_id_
;
1501 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeActivateTree
);
1503 // Resources evicted explicitly and by visibility changes.
1504 class UIResourceLostEviction
: public UIResourceLostTestSimple
{
1506 void StepCompleteOnMainThread(int step
) override
{
1507 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1510 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1511 EXPECT_NE(0, ui_resource_
->id());
1512 PostSetNeedsCommitToMainThread();
1515 // Make the tree not visible.
1516 PostSetVisibleToMainThread(false);
1519 // Release resource before ending the test.
1520 ui_resource_
= nullptr;
1528 void DidSetVisibleOnImplTree(LayerTreeHostImpl
* impl
, bool visible
) override
{
1529 TestWebGraphicsContext3D
* context
= TestContext();
1531 // All resources should have been evicted.
1532 ASSERT_EQ(0u, context
->NumTextures());
1533 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1534 EXPECT_EQ(2, ui_resource_
->resource_create_count
);
1535 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1536 // Drawing is disabled both because of the evicted resources and
1537 // because the renderer is not visible.
1538 EXPECT_FALSE(impl
->CanDraw());
1539 // Make the renderer visible again.
1540 PostSetVisibleToMainThread(true);
1544 void StepCompleteOnImplThread(LayerTreeHostImpl
* impl
) override
{
1545 TestWebGraphicsContext3D
* context
= TestContext();
1546 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1547 switch (time_step_
) {
1549 // The resource should have been created on LTHI after the commit.
1550 ASSERT_EQ(1u, context
->NumTextures());
1551 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1552 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1553 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1554 EXPECT_TRUE(impl
->CanDraw());
1555 // Evict all UI resources. This will trigger a commit.
1556 impl
->EvictAllUIResources();
1557 ASSERT_EQ(0u, context
->NumTextures());
1558 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1559 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1560 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1561 EXPECT_FALSE(impl
->CanDraw());
1564 // The resource should have been recreated.
1565 ASSERT_EQ(1u, context
->NumTextures());
1566 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1567 EXPECT_EQ(2, ui_resource_
->resource_create_count
);
1568 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1569 EXPECT_TRUE(impl
->CanDraw());
1572 // The resource should have been recreated after visibility was
1574 ASSERT_EQ(1u, context
->NumTextures());
1575 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1576 EXPECT_EQ(3, ui_resource_
->resource_create_count
);
1577 EXPECT_EQ(2, ui_resource_
->lost_resource_count
);
1578 EXPECT_TRUE(impl
->CanDraw());
1584 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction
);
1586 class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame
1587 : public LayerTreeHostContextTest
{
1589 void BeginTest() override
{
1591 PostSetNeedsCommitToMainThread();
1594 void ScheduledActionWillSendBeginMainFrame() override
{
1599 // Defer commits before the BeginFrame arrives, causing it to be delayed.
1600 PostSetDeferCommitsToMainThread(true);
1601 // Meanwhile, lose the context while we are in defer commits.
1602 ImplThreadTaskRunner()->PostTask(
1604 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1605 LoseContextOnImplThread
,
1606 base::Unretained(this)));
1609 void LoseContextOnImplThread() {
1612 // After losing the context, stop deferring commits.
1613 PostSetDeferCommitsToMainThread(false);
1616 void WillBeginMainFrame() override
{
1617 // Don't begin a frame with a lost surface.
1618 EXPECT_FALSE(layer_tree_host()->output_surface_lost());
1621 void DidCommitAndDrawFrame() override
{ EndTest(); }
1623 void AfterTest() override
{}
1628 SINGLE_AND_MULTI_THREAD_TEST_F(
1629 LayerTreeHostContextTestLoseAfterSendingBeginMainFrame
);