1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/trees/layer_tree_host.h"
7 #include "base/basictypes.h"
8 #include "cc/layers/content_layer.h"
9 #include "cc/layers/delegated_frame_provider.h"
10 #include "cc/layers/delegated_frame_resource_collection.h"
11 #include "cc/layers/heads_up_display_layer.h"
12 #include "cc/layers/io_surface_layer.h"
13 #include "cc/layers/layer_impl.h"
14 #include "cc/layers/painted_scrollbar_layer.h"
15 #include "cc/layers/picture_layer.h"
16 #include "cc/layers/texture_layer.h"
17 #include "cc/layers/texture_layer_impl.h"
18 #include "cc/layers/video_layer.h"
19 #include "cc/layers/video_layer_impl.h"
20 #include "cc/output/filter_operations.h"
21 #include "cc/resources/single_release_callback.h"
22 #include "cc/test/failure_output_surface.h"
23 #include "cc/test/fake_content_layer.h"
24 #include "cc/test/fake_content_layer_client.h"
25 #include "cc/test/fake_content_layer_impl.h"
26 #include "cc/test/fake_delegated_renderer_layer.h"
27 #include "cc/test/fake_delegated_renderer_layer_impl.h"
28 #include "cc/test/fake_layer_tree_host_client.h"
29 #include "cc/test/fake_output_surface.h"
30 #include "cc/test/fake_output_surface_client.h"
31 #include "cc/test/fake_painted_scrollbar_layer.h"
32 #include "cc/test/fake_picture_layer.h"
33 #include "cc/test/fake_picture_layer_impl.h"
34 #include "cc/test/fake_scoped_ui_resource.h"
35 #include "cc/test/fake_scrollbar.h"
36 #include "cc/test/fake_video_frame_provider.h"
37 #include "cc/test/layer_tree_test.h"
38 #include "cc/test/render_pass_test_common.h"
39 #include "cc/test/test_context_provider.h"
40 #include "cc/test/test_shared_bitmap_manager.h"
41 #include "cc/test/test_web_graphics_context_3d.h"
42 #include "cc/trees/layer_tree_host_impl.h"
43 #include "cc/trees/layer_tree_impl.h"
44 #include "cc/trees/single_thread_proxy.h"
45 #include "gpu/GLES2/gl2extchromium.h"
46 #include "media/base/media.h"
48 using media::VideoFrame
;
53 // These tests deal with losing the 3d graphics context.
54 class LayerTreeHostContextTest
: public LayerTreeTest
{
56 LayerTreeHostContextTest()
59 times_to_fail_create_(0),
60 times_to_lose_during_commit_(0),
61 times_to_lose_during_draw_(0),
62 times_to_fail_recreate_(0),
63 times_to_expect_create_failed_(0),
64 times_create_failed_(0),
65 committed_at_least_once_(false),
66 context_should_support_io_surface_(false),
67 fallback_context_works_(false),
68 async_output_surface_creation_(false) {
69 media::InitializeMediaLibraryForTesting();
73 // For sanity-checking tests, they should only call this when the
74 // context is not lost.
76 context3d_
->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB
,
77 GL_INNOCENT_CONTEXT_RESET_ARB
);
81 virtual scoped_ptr
<TestWebGraphicsContext3D
> CreateContext3d() {
82 return TestWebGraphicsContext3D::Create();
85 scoped_ptr
<FakeOutputSurface
> CreateFakeOutputSurface() override
{
86 if (times_to_fail_create_
) {
87 --times_to_fail_create_
;
89 return make_scoped_ptr(new FailureOutputSurface(delegating_renderer()));
92 scoped_ptr
<TestWebGraphicsContext3D
> context3d
= CreateContext3d();
93 context3d_
= context3d
.get();
95 if (context_should_support_io_surface_
) {
96 context3d_
->set_have_extension_io_surface(true);
97 context3d_
->set_have_extension_egl_image(true);
100 if (delegating_renderer())
101 return FakeOutputSurface::CreateDelegating3d(context3d
.Pass());
103 return FakeOutputSurface::Create3d(context3d
.Pass());
106 DrawResult
PrepareToDrawOnThread(LayerTreeHostImpl
* host_impl
,
107 LayerTreeHostImpl::FrameData
* frame
,
108 DrawResult draw_result
) override
{
109 if (draw_result
== DRAW_ABORTED_MISSING_HIGH_RES_CONTENT
) {
110 // Only valid for single-threaded impl-side painting, which activates
111 // immediately and will try to draw again when content has finished.
112 DCHECK(!host_impl
->proxy()->HasImplThread());
113 DCHECK(layer_tree_host()->settings().impl_side_painting
);
116 EXPECT_EQ(DRAW_SUCCESS
, draw_result
);
117 if (!times_to_lose_during_draw_
)
120 --times_to_lose_during_draw_
;
123 times_to_fail_create_
= times_to_fail_recreate_
;
124 times_to_fail_recreate_
= 0;
129 void CommitCompleteOnThread(LayerTreeHostImpl
* host_impl
) override
{
130 committed_at_least_once_
= true;
132 if (!times_to_lose_during_commit_
)
134 --times_to_lose_during_commit_
;
137 times_to_fail_create_
= times_to_fail_recreate_
;
138 times_to_fail_recreate_
= 0;
141 void DidFailToInitializeOutputSurface() override
{ ++times_create_failed_
; }
143 void TearDown() override
{
144 LayerTreeTest::TearDown();
145 EXPECT_EQ(times_to_expect_create_failed_
, times_create_failed_
);
148 void ExpectCreateToFail() { ++times_to_expect_create_failed_
; }
151 TestWebGraphicsContext3D
* context3d_
;
152 int times_to_fail_create_
;
153 int times_to_lose_during_commit_
;
154 int times_to_lose_during_draw_
;
155 int times_to_fail_recreate_
;
156 int times_to_expect_create_failed_
;
157 int times_create_failed_
;
158 bool committed_at_least_once_
;
159 bool context_should_support_io_surface_
;
160 bool fallback_context_works_
;
161 bool async_output_surface_creation_
;
164 class LayerTreeHostContextTestLostContextSucceeds
165 : public LayerTreeHostContextTest
{
167 LayerTreeHostContextTestLostContextSucceeds()
168 : LayerTreeHostContextTest(),
171 num_losses_last_test_case_(-1),
172 recovered_context_(true),
173 first_initialized_(false) {}
175 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
177 void RequestNewOutputSurface() override
{
178 if (async_output_surface_creation_
) {
179 MainThreadTaskRunner()->PostTask(
180 FROM_HERE
, base::Bind(&LayerTreeHostContextTestLostContextSucceeds::
181 CreateAndSetOutputSurface
,
182 base::Unretained(this)));
184 CreateAndSetOutputSurface();
188 void CreateAndSetOutputSurface() {
189 scoped_ptr
<OutputSurface
> surface(
190 LayerTreeHostContextTest::CreateOutputSurface());
192 layer_tree_host()->SetOutputSurface(surface
.Pass());
195 void DidInitializeOutputSurface() override
{
196 if (first_initialized_
)
199 first_initialized_
= true;
201 recovered_context_
= true;
204 void AfterTest() override
{ EXPECT_EQ(11u, test_case_
); }
206 void DidCommitAndDrawFrame() override
{
207 // If the last frame had a context loss, then we'll commit again to
209 if (!recovered_context_
)
211 if (times_to_lose_during_commit_
)
213 if (times_to_lose_during_draw_
)
216 recovered_context_
= false;
218 InvalidateAndSetNeedsCommit();
223 virtual void InvalidateAndSetNeedsCommit() {
224 // Cause damage so we try to draw.
225 layer_tree_host()->root_layer()->SetNeedsDisplay();
226 layer_tree_host()->SetNeedsCommit();
229 bool NextTestCase() {
230 static const TestCase kTests
[] = {
231 // Losing the context and failing to recreate it (or losing it again
232 // immediately) a small number of times should succeed.
234 1, // times_to_lose_during_commit
235 0, // times_to_lose_during_draw
236 0, // times_to_fail_recreate
237 false, // fallback_context_works
238 false, // async_output_surface_creation
241 0, // times_to_lose_during_commit
242 1, // times_to_lose_during_draw
243 0, // times_to_fail_recreate
244 false, // fallback_context_works
245 false, // async_output_surface_creation
248 1, // times_to_lose_during_commit
249 0, // times_to_lose_during_draw
250 3, // times_to_fail_recreate
251 false, // fallback_context_works
252 false, // async_output_surface_creation
255 0, // times_to_lose_during_commit
256 1, // times_to_lose_during_draw
257 3, // times_to_fail_recreate
258 false, // fallback_context_works
259 false, // async_output_surface_creation
262 0, // times_to_lose_during_commit
263 1, // times_to_lose_during_draw
264 3, // times_to_fail_recreate
265 false, // fallback_context_works
266 true, // async_output_surface_creation
268 // Losing the context and recreating it any number of times should
271 10, // times_to_lose_during_commit
272 0, // times_to_lose_during_draw
273 0, // times_to_fail_recreate
274 false, // fallback_context_works
275 false, // async_output_surface_creation
278 0, // times_to_lose_during_commit
279 10, // times_to_lose_during_draw
280 0, // times_to_fail_recreate
281 false, // fallback_context_works
282 false, // async_output_surface_creation
285 10, // times_to_lose_during_commit
286 0, // times_to_lose_during_draw
287 0, // times_to_fail_recreate
288 false, // fallback_context_works
289 true, // async_output_surface_creation
292 0, // times_to_lose_during_commit
293 10, // times_to_lose_during_draw
294 0, // times_to_fail_recreate
295 false, // fallback_context_works
296 true, // async_output_surface_creation
298 // Losing the context, failing to reinitialize it, and making a fallback
299 // context should work.
301 0, // times_to_lose_during_commit
302 1, // times_to_lose_during_draw
303 0, // times_to_fail_recreate
304 true, // fallback_context_works
305 false, // async_output_surface_creation
308 0, // times_to_lose_during_commit
309 1, // times_to_lose_during_draw
310 0, // times_to_fail_recreate
311 true, // fallback_context_works
312 true, // async_output_surface_creation
316 if (test_case_
>= arraysize(kTests
))
318 // Make sure that we lost our context at least once in the last test run so
319 // the test did something.
320 EXPECT_GT(num_losses_
, num_losses_last_test_case_
);
321 num_losses_last_test_case_
= num_losses_
;
323 times_to_lose_during_commit_
=
324 kTests
[test_case_
].times_to_lose_during_commit
;
325 times_to_lose_during_draw_
= kTests
[test_case_
].times_to_lose_during_draw
;
326 times_to_fail_recreate_
= kTests
[test_case_
].times_to_fail_recreate
;
327 fallback_context_works_
= kTests
[test_case_
].fallback_context_works
;
328 async_output_surface_creation_
=
329 kTests
[test_case_
].async_output_surface_creation
;
335 int times_to_lose_during_commit
;
336 int times_to_lose_during_draw
;
337 int times_to_fail_recreate
;
338 bool fallback_context_works
;
339 bool async_output_surface_creation
;
345 int num_losses_last_test_case_
;
346 bool recovered_context_
;
347 bool first_initialized_
;
350 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLostContextSucceeds
);
352 class LayerTreeHostClientNotReadyDoesNotCreateOutputSurface
353 : public LayerTreeHostContextTest
{
355 LayerTreeHostClientNotReadyDoesNotCreateOutputSurface()
356 : LayerTreeHostContextTest() {}
358 void WillBeginTest() override
{
359 // Override and do not signal SetLayerTreeHostClientReady.
362 void BeginTest() override
{
363 PostSetNeedsCommitToMainThread();
367 scoped_ptr
<OutputSurface
> CreateOutputSurface() override
{
372 void DidInitializeOutputSurface() override
{ EXPECT_TRUE(false); }
374 void AfterTest() override
{}
377 SINGLE_AND_MULTI_THREAD_TEST_F(
378 LayerTreeHostClientNotReadyDoesNotCreateOutputSurface
);
380 class MultipleCompositeDoesNotCreateOutputSurface
381 : public LayerTreeHostContextTest
{
383 MultipleCompositeDoesNotCreateOutputSurface()
384 : LayerTreeHostContextTest(), request_count_(0) {}
386 void InitializeSettings(LayerTreeSettings
* settings
) override
{
387 settings
->single_thread_proxy_scheduler
= false;
390 void RequestNewOutputSurface() override
{
391 EXPECT_GE(1, ++request_count_
);
395 void BeginTest() override
{
396 layer_tree_host()->Composite(base::TimeTicks());
397 layer_tree_host()->Composite(base::TimeTicks());
400 scoped_ptr
<OutputSurface
> CreateOutputSurface() override
{
405 void DidInitializeOutputSurface() override
{ EXPECT_TRUE(false); }
407 void AfterTest() override
{}
412 SINGLE_THREAD_NOIMPL_TEST_F(MultipleCompositeDoesNotCreateOutputSurface
);
414 class FailedCreateDoesNotCreateExtraOutputSurface
415 : public LayerTreeHostContextTest
{
417 FailedCreateDoesNotCreateExtraOutputSurface()
418 : LayerTreeHostContextTest(), request_count_(0) {}
420 void InitializeSettings(LayerTreeSettings
* settings
) override
{
421 settings
->single_thread_proxy_scheduler
= false;
424 void RequestNewOutputSurface() override
{
425 if (request_count_
== 0) {
426 ExpectCreateToFail();
427 layer_tree_host()->SetOutputSurface(
428 make_scoped_ptr(new FailureOutputSurface(false)));
432 void BeginTest() override
{
433 layer_tree_host()->Composite(base::TimeTicks());
434 layer_tree_host()->Composite(base::TimeTicks());
437 void DidInitializeOutputSurface() override
{ EXPECT_TRUE(false); }
439 void DidFailToInitializeOutputSurface() override
{
440 LayerTreeHostContextTest::DidFailToInitializeOutputSurface();
441 EXPECT_GE(2, ++request_count_
);
445 void AfterTest() override
{}
450 SINGLE_THREAD_NOIMPL_TEST_F(FailedCreateDoesNotCreateExtraOutputSurface
);
452 class LayerTreeHostContextTestCommitAfterDelayedOutputSurface
453 : public LayerTreeHostContextTest
{
455 LayerTreeHostContextTestCommitAfterDelayedOutputSurface()
456 : LayerTreeHostContextTest(), creating_output_(false) {}
458 void InitializeSettings(LayerTreeSettings
* settings
) override
{
459 settings
->single_thread_proxy_scheduler
= false;
462 void RequestNewOutputSurface() override
{
463 MainThreadTaskRunner()->PostTask(
465 base::Bind(&LayerTreeHostContextTestCommitAfterDelayedOutputSurface::
466 CreateAndSetOutputSurface
,
467 base::Unretained(this)));
470 void CreateAndSetOutputSurface() {
471 creating_output_
= true;
472 layer_tree_host()->SetOutputSurface(
473 LayerTreeHostContextTest::CreateOutputSurface());
476 void BeginTest() override
{ layer_tree_host()->Composite(base::TimeTicks()); }
478 void ScheduleComposite() override
{
479 if (creating_output_
)
483 void AfterTest() override
{}
485 bool creating_output_
;
488 SINGLE_THREAD_NOIMPL_TEST_F(
489 LayerTreeHostContextTestCommitAfterDelayedOutputSurface
);
491 class LayerTreeHostContextTestAvoidUnnecessaryComposite
492 : public LayerTreeHostContextTest
{
494 LayerTreeHostContextTestAvoidUnnecessaryComposite()
495 : LayerTreeHostContextTest(), in_composite_(false) {}
497 void InitializeSettings(LayerTreeSettings
* settings
) override
{
498 settings
->single_thread_proxy_scheduler
= false;
501 void RequestNewOutputSurface() override
{
502 layer_tree_host()->SetOutputSurface(
503 LayerTreeHostContextTest::CreateOutputSurface());
507 void BeginTest() override
{
508 in_composite_
= true;
509 layer_tree_host()->Composite(base::TimeTicks());
510 in_composite_
= false;
513 void ScheduleComposite() override
{ EXPECT_FALSE(in_composite_
); }
515 void AfterTest() override
{}
520 SINGLE_THREAD_NOIMPL_TEST_F(LayerTreeHostContextTestAvoidUnnecessaryComposite
);
522 class LayerTreeHostContextTestLostContextSucceedsWithContent
523 : public LayerTreeHostContextTestLostContextSucceeds
{
525 void SetupTree() override
{
526 root_
= Layer::Create();
527 root_
->SetBounds(gfx::Size(10, 10));
528 root_
->SetIsDrawable(true);
530 // Paint non-solid color.
532 paint
.setColor(SkColorSetARGB(100, 80, 200, 200));
533 client_
.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint
);
535 if (layer_tree_host()->settings().impl_side_painting
)
536 layer_
= FakePictureLayer::Create(&client_
);
538 layer_
= FakeContentLayer::Create(&client_
);
539 layer_
->SetBounds(gfx::Size(10, 10));
540 layer_
->SetIsDrawable(true);
542 root_
->AddChild(layer_
);
544 layer_tree_host()->SetRootLayer(root_
);
545 LayerTreeHostContextTest::SetupTree();
548 void InvalidateAndSetNeedsCommit() override
{
549 // Invalidate the render surface so we don't try to use a cached copy of the
550 // surface. We want to make sure to test the drawing paths for drawing to
552 layer_
->SetNeedsDisplay();
553 LayerTreeHostContextTestLostContextSucceeds::InvalidateAndSetNeedsCommit();
556 void DrawLayersOnThread(LayerTreeHostImpl
* host_impl
) override
{
557 if (!host_impl
->settings().impl_side_painting
) {
558 FakeContentLayerImpl
* content_impl
= static_cast<FakeContentLayerImpl
*>(
559 host_impl
->active_tree()->root_layer()->children()[0]);
560 // Even though the context was lost, we should have a resource. The
561 // TestWebGraphicsContext3D ensures that this resource is created with
562 // the active context.
563 EXPECT_TRUE(content_impl
->HaveResourceForTileAt(0, 0));
565 FakePictureLayerImpl
* picture_impl
= static_cast<FakePictureLayerImpl
*>(
566 host_impl
->active_tree()->root_layer()->children()[0]);
567 EXPECT_TRUE(picture_impl
->HighResTiling()->TileAt(0, 0)->IsReadyToDraw());
572 FakeContentLayerClient client_
;
573 scoped_refptr
<Layer
> root_
;
574 scoped_refptr
<Layer
> layer_
;
577 // This test uses TiledLayer and PictureLayer to check for a working context.
578 SINGLE_AND_MULTI_THREAD_TEST_F(
579 LayerTreeHostContextTestLostContextSucceedsWithContent
);
581 class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
582 : public LayerTreeHostContextTest
{
584 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
585 : times_to_fail_(1), times_initialized_(0) {
586 times_to_fail_create_
= times_to_fail_
;
589 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
591 void DidInitializeOutputSurface() override
{ times_initialized_
++; }
593 void DrawLayersOnThread(LayerTreeHostImpl
* host_impl
) override
{ EndTest(); }
595 void AfterTest() override
{
596 EXPECT_EQ(times_to_fail_
, times_create_failed_
);
597 EXPECT_NE(0, times_initialized_
);
602 int times_initialized_
;
605 SINGLE_AND_MULTI_THREAD_TEST_F(
606 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
);
608 class LayerTreeHostContextTestLostContextAndEvictTextures
609 : public LayerTreeHostContextTest
{
611 LayerTreeHostContextTestLostContextAndEvictTextures()
612 : LayerTreeHostContextTest(),
615 lost_context_(false) {}
617 void SetupTree() override
{
618 // Paint non-solid color.
620 paint
.setColor(SkColorSetARGB(100, 80, 200, 200));
621 client_
.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint
);
623 if (layer_tree_host()->settings().impl_side_painting
) {
624 picture_layer_
= FakePictureLayer::Create(&client_
);
625 picture_layer_
->SetBounds(gfx::Size(10, 20));
626 layer_tree_host()->SetRootLayer(picture_layer_
);
628 content_layer_
= FakeContentLayer::Create(&client_
);
629 content_layer_
->SetBounds(gfx::Size(10, 20));
630 layer_tree_host()->SetRootLayer(content_layer_
);
633 LayerTreeHostContextTest::SetupTree();
636 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
638 void PostEvictTextures() {
639 if (HasImplThread()) {
640 ImplThreadTaskRunner()->PostTask(
642 base::Bind(&LayerTreeHostContextTestLostContextAndEvictTextures::
643 EvictTexturesOnImplThread
,
644 base::Unretained(this)));
646 DebugScopedSetImplThread
impl(proxy());
647 EvictTexturesOnImplThread();
651 void EvictTexturesOnImplThread() {
652 impl_host_
->EvictTexturesForTesting();
654 if (lose_after_evict_
) {
656 lost_context_
= true;
660 void DidCommitAndDrawFrame() override
{
661 if (num_commits_
> 1)
663 if (!layer_tree_host()->settings().impl_side_painting
) {
664 EXPECT_TRUE(content_layer_
->HaveBackingAt(0, 0));
669 void CommitCompleteOnThread(LayerTreeHostImpl
* impl
) override
{
670 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
671 if (num_commits_
> 1)
674 if (!lose_after_evict_
) {
676 lost_context_
= true;
680 void DrawLayersOnThread(LayerTreeHostImpl
* impl
) override
{
681 if (impl
->settings().impl_side_painting
) {
682 FakePictureLayerImpl
* picture_impl
=
683 static_cast<FakePictureLayerImpl
*>(impl
->active_tree()->root_layer());
684 EXPECT_TRUE(picture_impl
->HighResTiling()->TileAt(0, 0)->IsReadyToDraw());
686 FakeContentLayerImpl
* content_impl
=
687 static_cast<FakeContentLayerImpl
*>(impl
->active_tree()->root_layer());
688 EXPECT_TRUE(content_impl
->HaveResourceForTileAt(0, 0));
696 void DidInitializeOutputSurface() override
{}
698 void AfterTest() override
{}
701 bool lose_after_evict_
;
702 FakeContentLayerClient client_
;
703 scoped_refptr
<FakeContentLayer
> content_layer_
;
704 scoped_refptr
<FakePictureLayer
> picture_layer_
;
705 LayerTreeHostImpl
* impl_host_
;
710 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
711 LoseAfterEvict_SingleThread_DirectRenderer
) {
712 lose_after_evict_
= true;
713 RunTest(false, false, false);
716 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
717 LoseAfterEvict_SingleThread_DelegatingRenderer
) {
718 lose_after_evict_
= true;
719 RunTest(false, true, false);
722 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
723 LoseAfterEvict_MultiThread_DirectRenderer_MainThreadPaint
) {
724 lose_after_evict_
= true;
725 RunTest(true, false, false);
728 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
729 LoseAfterEvict_MultiThread_DelegatingRenderer_MainThreadPaint
) {
730 lose_after_evict_
= true;
731 RunTest(true, true, false);
734 // Flaky on all platforms, http://crbug.com/310979
735 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
736 DISABLED_LoseAfterEvict_MultiThread_DelegatingRenderer_ImplSidePaint
) {
737 lose_after_evict_
= true;
738 RunTest(true, true, true);
741 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
742 LoseBeforeEvict_SingleThread_DirectRenderer
) {
743 lose_after_evict_
= false;
744 RunTest(false, false, false);
747 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
748 LoseBeforeEvict_SingleThread_DelegatingRenderer
) {
749 lose_after_evict_
= false;
750 RunTest(false, true, false);
753 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
754 LoseBeforeEvict_MultiThread_DirectRenderer_MainThreadPaint
) {
755 lose_after_evict_
= false;
756 RunTest(true, false, false);
759 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
760 LoseBeforeEvict_MultiThread_DirectRenderer_ImplSidePaint
) {
761 lose_after_evict_
= false;
762 RunTest(true, false, true);
765 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
766 LoseBeforeEvict_MultiThread_DelegatingRenderer_MainThreadPaint
) {
767 lose_after_evict_
= false;
768 RunTest(true, true, false);
771 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures
,
772 LoseBeforeEvict_MultiThread_DelegatingRenderer_ImplSidePaint
) {
773 lose_after_evict_
= false;
774 RunTest(true, true, true);
777 class LayerTreeHostContextTestLostContextWhileUpdatingResources
778 : public LayerTreeHostContextTest
{
780 LayerTreeHostContextTestLostContextWhileUpdatingResources()
781 : num_children_(50), times_to_lose_on_end_query_(3) {}
783 scoped_ptr
<TestWebGraphicsContext3D
> CreateContext3d() override
{
784 scoped_ptr
<TestWebGraphicsContext3D
> context
=
785 LayerTreeHostContextTest::CreateContext3d();
786 if (times_to_lose_on_end_query_
) {
787 --times_to_lose_on_end_query_
;
788 context
->set_times_end_query_succeeds(5);
790 return context
.Pass();
793 void SetupTree() override
{
794 if (layer_tree_host()->settings().impl_side_painting
)
795 parent_
= FakePictureLayer::Create(&client_
);
797 parent_
= FakeContentLayer::Create(&client_
);
799 parent_
->SetBounds(gfx::Size(num_children_
, 1));
801 for (int i
= 0; i
< num_children_
; i
++) {
802 scoped_refptr
<Layer
> child
;
803 if (layer_tree_host()->settings().impl_side_painting
)
804 child
= FakePictureLayer::Create(&client_
);
806 child
= FakeContentLayer::Create(&client_
);
807 child
->SetPosition(gfx::PointF(i
, 0.f
));
808 child
->SetBounds(gfx::Size(1, 1));
809 parent_
->AddChild(child
);
812 layer_tree_host()->SetRootLayer(parent_
);
813 LayerTreeHostContextTest::SetupTree();
816 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
818 void DrawLayersOnThread(LayerTreeHostImpl
* host_impl
) override
{
819 EXPECT_EQ(0, times_to_lose_on_end_query_
);
823 void AfterTest() override
{ EXPECT_EQ(0, times_to_lose_on_end_query_
); }
826 FakeContentLayerClient client_
;
827 scoped_refptr
<Layer
> parent_
;
829 int times_to_lose_on_end_query_
;
832 SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
833 LayerTreeHostContextTestLostContextWhileUpdatingResources
);
835 class LayerTreeHostContextTestLayersNotified
: public LayerTreeHostContextTest
{
837 LayerTreeHostContextTestLayersNotified()
838 : LayerTreeHostContextTest(), num_commits_(0) {}
840 void SetupTree() override
{
841 if (layer_tree_host()->settings().impl_side_painting
) {
842 root_
= FakePictureLayer::Create(&client_
);
843 child_
= FakePictureLayer::Create(&client_
);
844 grandchild_
= FakePictureLayer::Create(&client_
);
846 root_
= FakeContentLayer::Create(&client_
);
847 child_
= FakeContentLayer::Create(&client_
);
848 grandchild_
= FakeContentLayer::Create(&client_
);
851 root_
->AddChild(child_
);
852 child_
->AddChild(grandchild_
);
854 layer_tree_host()->SetRootLayer(root_
);
855 LayerTreeHostContextTest::SetupTree();
858 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
860 void DidActivateTreeOnThread(LayerTreeHostImpl
* host_impl
) override
{
861 LayerTreeHostContextTest::DidActivateTreeOnThread(host_impl
);
863 FakePictureLayerImpl
* root_picture
= NULL
;
864 FakePictureLayerImpl
* child_picture
= NULL
;
865 FakePictureLayerImpl
* grandchild_picture
= NULL
;
866 FakeContentLayerImpl
* root_content
= NULL
;
867 FakeContentLayerImpl
* child_content
= NULL
;
868 FakeContentLayerImpl
* grandchild_content
= NULL
;
870 if (layer_tree_host()->settings().impl_side_painting
) {
871 root_picture
= static_cast<FakePictureLayerImpl
*>(
872 host_impl
->active_tree()->root_layer());
874 static_cast<FakePictureLayerImpl
*>(root_picture
->children()[0]);
876 static_cast<FakePictureLayerImpl
*>(child_picture
->children()[0]);
879 root_content
= static_cast<FakeContentLayerImpl
*>(
880 host_impl
->active_tree()->root_layer());
882 static_cast<FakeContentLayerImpl
*>(root_content
->children()[0]);
884 static_cast<FakeContentLayerImpl
*>(child_content
->children()[0]);
888 switch (num_commits_
) {
890 if (layer_tree_host()->settings().impl_side_painting
) {
891 EXPECT_EQ(0u, root_picture
->release_resources_count());
892 EXPECT_EQ(0u, child_picture
->release_resources_count());
893 EXPECT_EQ(0u, grandchild_picture
->release_resources_count());
895 EXPECT_EQ(0u, root_content
->lost_output_surface_count());
896 EXPECT_EQ(0u, child_content
->lost_output_surface_count());
897 EXPECT_EQ(0u, grandchild_content
->lost_output_surface_count());
900 // Lose the context and struggle to recreate it.
902 times_to_fail_create_
= 1;
905 if (layer_tree_host()->settings().impl_side_painting
) {
906 EXPECT_TRUE(root_picture
->release_resources_count());
907 EXPECT_TRUE(child_picture
->release_resources_count());
908 EXPECT_TRUE(grandchild_picture
->release_resources_count());
910 EXPECT_TRUE(root_content
->lost_output_surface_count());
911 EXPECT_TRUE(child_content
->lost_output_surface_count());
912 EXPECT_TRUE(grandchild_content
->lost_output_surface_count());
922 void AfterTest() override
{}
927 FakeContentLayerClient client_
;
928 scoped_refptr
<Layer
> root_
;
929 scoped_refptr
<Layer
> child_
;
930 scoped_refptr
<Layer
> grandchild_
;
933 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified
);
935 class LayerTreeHostContextTestDontUseLostResources
936 : public LayerTreeHostContextTest
{
938 LayerTreeHostContextTestDontUseLostResources() : lost_context_(false) {
939 context_should_support_io_surface_
= true;
941 child_output_surface_
= FakeOutputSurface::Create3d();
942 child_output_surface_
->BindToClient(&output_surface_client_
);
943 shared_bitmap_manager_
.reset(new TestSharedBitmapManager());
944 child_resource_provider_
=
945 ResourceProvider::Create(child_output_surface_
.get(),
946 shared_bitmap_manager_
.get(),
954 static void EmptyReleaseCallback(unsigned sync_point
, bool lost
) {}
956 void SetupTree() override
{
957 gpu::gles2::GLES2Interface
* gl
=
958 child_output_surface_
->context_provider()->ContextGL();
960 scoped_ptr
<DelegatedFrameData
> frame_data(new DelegatedFrameData
);
962 scoped_ptr
<TestRenderPass
> pass_for_quad
= TestRenderPass::Create();
963 pass_for_quad
->SetNew(
964 // AppendOneOfEveryQuadType() makes a RenderPass quad with this id.
966 gfx::Rect(0, 0, 10, 10),
967 gfx::Rect(0, 0, 10, 10),
970 scoped_ptr
<TestRenderPass
> pass
= TestRenderPass::Create();
971 pass
->SetNew(RenderPassId(1, 1),
972 gfx::Rect(0, 0, 10, 10),
973 gfx::Rect(0, 0, 10, 10),
975 pass
->AppendOneOfEveryQuadType(child_resource_provider_
.get(),
978 frame_data
->render_pass_list
.push_back(pass_for_quad
.Pass());
979 frame_data
->render_pass_list
.push_back(pass
.Pass());
981 delegated_resource_collection_
= new DelegatedFrameResourceCollection
;
982 delegated_frame_provider_
= new DelegatedFrameProvider(
983 delegated_resource_collection_
.get(), frame_data
.Pass());
985 ResourceProvider::ResourceId resource
=
986 child_resource_provider_
->CreateResource(
989 ResourceProvider::TextureHintImmutable
,
991 ResourceProvider::ScopedWriteLockGL
lock(child_resource_provider_
.get(),
994 gpu::Mailbox mailbox
;
995 gl
->GenMailboxCHROMIUM(mailbox
.name
);
996 GLuint sync_point
= gl
->InsertSyncPointCHROMIUM();
998 scoped_refptr
<Layer
> root
= Layer::Create();
999 root
->SetBounds(gfx::Size(10, 10));
1000 root
->SetIsDrawable(true);
1002 scoped_refptr
<FakeDelegatedRendererLayer
> delegated
=
1003 FakeDelegatedRendererLayer::Create(delegated_frame_provider_
.get());
1004 delegated
->SetBounds(gfx::Size(10, 10));
1005 delegated
->SetIsDrawable(true);
1006 root
->AddChild(delegated
);
1008 scoped_refptr
<Layer
> layer
;
1009 if (layer_tree_host()->settings().impl_side_painting
)
1010 layer
= PictureLayer::Create(&client_
);
1012 layer
= ContentLayer::Create(&client_
);
1013 layer
->SetBounds(gfx::Size(10, 10));
1014 layer
->SetIsDrawable(true);
1015 root
->AddChild(layer
);
1017 scoped_refptr
<TextureLayer
> texture
= TextureLayer::CreateForMailbox(NULL
);
1018 texture
->SetBounds(gfx::Size(10, 10));
1019 texture
->SetIsDrawable(true);
1020 texture
->SetTextureMailbox(
1021 TextureMailbox(mailbox
, GL_TEXTURE_2D
, sync_point
),
1022 SingleReleaseCallback::Create(
1023 base::Bind(&LayerTreeHostContextTestDontUseLostResources::
1024 EmptyReleaseCallback
)));
1025 root
->AddChild(texture
);
1027 scoped_refptr
<Layer
> mask
;
1028 if (layer_tree_host()->settings().impl_side_painting
)
1029 mask
= PictureLayer::Create(&client_
);
1031 mask
= ContentLayer::Create(&client_
);
1032 mask
->SetBounds(gfx::Size(10, 10));
1034 scoped_refptr
<Layer
> layer_with_mask
;
1035 if (layer_tree_host()->settings().impl_side_painting
)
1036 layer_with_mask
= PictureLayer::Create(&client_
);
1038 layer_with_mask
= ContentLayer::Create(&client_
);
1039 layer_with_mask
->SetBounds(gfx::Size(10, 10));
1040 layer_with_mask
->SetIsDrawable(true);
1041 layer_with_mask
->SetMaskLayer(mask
.get());
1042 root
->AddChild(layer_with_mask
);
1044 scoped_refptr
<VideoLayer
> video_color
=
1045 VideoLayer::Create(&color_frame_provider_
, media::VIDEO_ROTATION_0
);
1046 video_color
->SetBounds(gfx::Size(10, 10));
1047 video_color
->SetIsDrawable(true);
1048 root
->AddChild(video_color
);
1050 scoped_refptr
<VideoLayer
> video_hw
=
1051 VideoLayer::Create(&hw_frame_provider_
, media::VIDEO_ROTATION_0
);
1052 video_hw
->SetBounds(gfx::Size(10, 10));
1053 video_hw
->SetIsDrawable(true);
1054 root
->AddChild(video_hw
);
1056 scoped_refptr
<VideoLayer
> video_scaled_hw
=
1057 VideoLayer::Create(&scaled_hw_frame_provider_
, media::VIDEO_ROTATION_0
);
1058 video_scaled_hw
->SetBounds(gfx::Size(10, 10));
1059 video_scaled_hw
->SetIsDrawable(true);
1060 root
->AddChild(video_scaled_hw
);
1062 color_video_frame_
= VideoFrame::CreateColorFrame(
1063 gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
1065 VideoFrame::WrapNativeTexture(make_scoped_ptr(new gpu::MailboxHolder(
1066 mailbox
, GL_TEXTURE_2D
, sync_point
)),
1067 media::VideoFrame::ReleaseMailboxCB(),
1069 gfx::Rect(0, 0, 4, 4),
1072 VideoFrame::ReadPixelsCB());
1073 scaled_hw_video_frame_
=
1074 VideoFrame::WrapNativeTexture(make_scoped_ptr(new gpu::MailboxHolder(
1075 mailbox
, GL_TEXTURE_2D
, sync_point
)),
1076 media::VideoFrame::ReleaseMailboxCB(),
1078 gfx::Rect(0, 0, 3, 2),
1081 VideoFrame::ReadPixelsCB());
1083 color_frame_provider_
.set_frame(color_video_frame_
);
1084 hw_frame_provider_
.set_frame(hw_video_frame_
);
1085 scaled_hw_frame_provider_
.set_frame(scaled_hw_video_frame_
);
1087 if (!delegating_renderer()) {
1088 // TODO(danakj): IOSurface layer can not be transported. crbug.com/239335
1089 scoped_refptr
<IOSurfaceLayer
> io_surface
= IOSurfaceLayer::Create();
1090 io_surface
->SetBounds(gfx::Size(10, 10));
1091 io_surface
->SetIsDrawable(true);
1092 io_surface
->SetIOSurfaceProperties(1, gfx::Size(10, 10));
1093 root
->AddChild(io_surface
);
1097 LayerTreeDebugState debug_state
;
1098 debug_state
.show_property_changed_rects
= true;
1099 layer_tree_host()->SetDebugState(debug_state
);
1101 scoped_refptr
<PaintedScrollbarLayer
> scrollbar
=
1102 PaintedScrollbarLayer::Create(
1103 scoped_ptr
<Scrollbar
>(new FakeScrollbar
).Pass(), layer
->id());
1104 scrollbar
->SetBounds(gfx::Size(10, 10));
1105 scrollbar
->SetIsDrawable(true);
1106 root
->AddChild(scrollbar
);
1108 layer_tree_host()->SetRootLayer(root
);
1109 LayerTreeHostContextTest::SetupTree();
1112 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
1114 void CommitCompleteOnThread(LayerTreeHostImpl
* host_impl
) override
{
1115 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl
);
1117 if (host_impl
->active_tree()->source_frame_number() == 3) {
1118 // On the third commit we're recovering from context loss. Hardware
1119 // video frames should not be reused by the VideoFrameProvider, but
1120 // software frames can be.
1121 hw_frame_provider_
.set_frame(NULL
);
1122 scaled_hw_frame_provider_
.set_frame(NULL
);
1126 DrawResult
PrepareToDrawOnThread(LayerTreeHostImpl
* host_impl
,
1127 LayerTreeHostImpl::FrameData
* frame
,
1128 DrawResult draw_result
) override
{
1129 if (host_impl
->active_tree()->source_frame_number() == 2) {
1130 // Lose the context during draw on the second commit. This will cause
1131 // a third commit to recover.
1132 context3d_
->set_times_bind_texture_succeeds(0);
1137 scoped_ptr
<FakeOutputSurface
> CreateFakeOutputSurface() override
{
1138 // This will get called twice:
1139 // First when we create the initial output surface...
1140 if (layer_tree_host()->source_frame_number() > 0) {
1141 // ... and then again after we forced the context to be lost.
1142 lost_context_
= true;
1144 return LayerTreeHostContextTest::CreateFakeOutputSurface();
1147 void DidCommitAndDrawFrame() override
{
1148 ASSERT_TRUE(layer_tree_host()->hud_layer());
1149 // End the test once we know the 3nd frame drew.
1150 if (layer_tree_host()->source_frame_number() < 5) {
1151 layer_tree_host()->root_layer()->SetNeedsDisplay();
1152 layer_tree_host()->SetNeedsCommit();
1158 void AfterTest() override
{ EXPECT_TRUE(lost_context_
); }
1161 FakeContentLayerClient client_
;
1164 FakeOutputSurfaceClient output_surface_client_
;
1165 scoped_ptr
<FakeOutputSurface
> child_output_surface_
;
1166 scoped_ptr
<SharedBitmapManager
> shared_bitmap_manager_
;
1167 scoped_ptr
<ResourceProvider
> child_resource_provider_
;
1169 scoped_refptr
<DelegatedFrameResourceCollection
>
1170 delegated_resource_collection_
;
1171 scoped_refptr
<DelegatedFrameProvider
> delegated_frame_provider_
;
1173 scoped_refptr
<VideoFrame
> color_video_frame_
;
1174 scoped_refptr
<VideoFrame
> hw_video_frame_
;
1175 scoped_refptr
<VideoFrame
> scaled_hw_video_frame_
;
1177 FakeVideoFrameProvider color_frame_provider_
;
1178 FakeVideoFrameProvider hw_frame_provider_
;
1179 FakeVideoFrameProvider scaled_hw_frame_provider_
;
1182 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources
);
1184 class ImplSidePaintingLayerTreeHostContextTest
1185 : public LayerTreeHostContextTest
{
1187 void InitializeSettings(LayerTreeSettings
* settings
) override
{
1188 settings
->impl_side_painting
= true;
1192 class LayerTreeHostContextTestImplSidePainting
1193 : public ImplSidePaintingLayerTreeHostContextTest
{
1195 void SetupTree() override
{
1196 scoped_refptr
<Layer
> root
= Layer::Create();
1197 root
->SetBounds(gfx::Size(10, 10));
1198 root
->SetIsDrawable(true);
1200 scoped_refptr
<PictureLayer
> picture
= PictureLayer::Create(&client_
);
1201 picture
->SetBounds(gfx::Size(10, 10));
1202 picture
->SetIsDrawable(true);
1203 root
->AddChild(picture
);
1205 layer_tree_host()->SetRootLayer(root
);
1206 LayerTreeHostContextTest::SetupTree();
1209 void BeginTest() override
{
1210 times_to_lose_during_commit_
= 1;
1211 PostSetNeedsCommitToMainThread();
1214 void AfterTest() override
{}
1216 void DidInitializeOutputSurface() override
{ EndTest(); }
1219 FakeContentLayerClient client_
;
1222 MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting
);
1224 class ScrollbarLayerLostContext
: public LayerTreeHostContextTest
{
1226 ScrollbarLayerLostContext() : commits_(0) {}
1228 void BeginTest() override
{
1229 scoped_refptr
<Layer
> scroll_layer
= Layer::Create();
1231 FakePaintedScrollbarLayer::Create(false, true, scroll_layer
->id());
1232 scrollbar_layer_
->SetBounds(gfx::Size(10, 100));
1233 layer_tree_host()->root_layer()->AddChild(scrollbar_layer_
);
1234 layer_tree_host()->root_layer()->AddChild(scroll_layer
);
1235 PostSetNeedsCommitToMainThread();
1238 void AfterTest() override
{}
1240 void CommitCompleteOnThread(LayerTreeHostImpl
* impl
) override
{
1241 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1246 // First (regular) update, we should upload 2 resources (thumb, and
1248 EXPECT_EQ(1, scrollbar_layer_
->update_count());
1252 // Second update, after the lost context, we should still upload 2
1253 // resources even if the contents haven't changed.
1254 EXPECT_EQ(2, scrollbar_layer_
->update_count());
1264 scoped_refptr
<FakePaintedScrollbarLayer
> scrollbar_layer_
;
1267 SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext
);
1269 class UIResourceLostTest
: public LayerTreeHostContextTest
{
1271 UIResourceLostTest() : time_step_(0) {}
1272 void InitializeSettings(LayerTreeSettings
* settings
) override
{
1273 settings
->renderer_settings
.texture_id_allocation_chunk_size
= 1;
1275 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
1276 void AfterTest() override
{}
1278 // This is called on the main thread after each commit and
1279 // DidActivateTreeOnThread, with the value of time_step_ at the time
1280 // of the call to DidActivateTreeOnThread. Similar tests will do
1281 // work on the main thread in DidCommit but that is unsuitable because
1282 // the main thread work for these tests must happen after
1283 // DidActivateTreeOnThread, which happens after DidCommit with impl-side
1285 virtual void StepCompleteOnMainThread(int time_step
) = 0;
1287 // Called after DidActivateTreeOnThread. If this is done during the commit,
1288 // the call to StepCompleteOnMainThread will not occur until after
1289 // the commit completes, because the main thread is blocked.
1290 void PostStepCompleteToMainThread() {
1291 proxy()->MainThreadTaskRunner()->PostTask(
1293 base::Bind(&UIResourceLostTest::StepCompleteOnMainThreadInternal
,
1294 base::Unretained(this),
1298 void PostLoseContextToImplThread() {
1299 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1300 ImplThreadTaskRunner()->PostTask(
1302 base::Bind(&LayerTreeHostContextTest::LoseContext
,
1303 base::Unretained(this)));
1308 scoped_ptr
<FakeScopedUIResource
> ui_resource_
;
1311 void StepCompleteOnMainThreadInternal(int step
) {
1312 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1313 StepCompleteOnMainThread(step
);
1317 class UIResourceLostTestSimple
: public UIResourceLostTest
{
1319 // This is called when the commit is complete and the new layer tree has been
1321 virtual void StepCompleteOnImplThread(LayerTreeHostImpl
* impl
) = 0;
1323 void CommitCompleteOnThread(LayerTreeHostImpl
* impl
) override
{
1324 if (!layer_tree_host()->settings().impl_side_painting
) {
1325 StepCompleteOnImplThread(impl
);
1326 PostStepCompleteToMainThread();
1331 void DidActivateTreeOnThread(LayerTreeHostImpl
* impl
) override
{
1332 if (layer_tree_host()->settings().impl_side_painting
) {
1333 StepCompleteOnImplThread(impl
);
1334 PostStepCompleteToMainThread();
1340 // Losing context after an UI resource has been created.
1341 class UIResourceLostAfterCommit
: public UIResourceLostTestSimple
{
1343 void StepCompleteOnMainThread(int step
) override
{
1344 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1347 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1348 // Expects a valid UIResourceId.
1349 EXPECT_NE(0, ui_resource_
->id());
1350 PostSetNeedsCommitToMainThread();
1353 // Release resource before ending the test.
1354 ui_resource_
= nullptr;
1363 void StepCompleteOnImplThread(LayerTreeHostImpl
* impl
) override
{
1364 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1365 switch (time_step_
) {
1367 // The resource should have been created on LTHI after the commit.
1368 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1369 PostSetNeedsCommitToMainThread();
1375 // The resources should have been recreated. The bitmap callback should
1376 // have been called once with the resource_lost flag set to true.
1377 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1378 // Resource Id on the impl-side have been recreated as well. Note
1379 // that the same UIResourceId persists after the context lost.
1380 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1381 PostSetNeedsCommitToMainThread();
1387 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostAfterCommit
);
1389 // Losing context before UI resource requests can be commited. Three sequences
1390 // of creation/deletion are considered:
1391 // 1. Create one resource -> Context Lost => Expect the resource to have been
1393 // 2. Delete an exisiting resource (test_id0_) -> create a second resource
1394 // (test_id1_) -> Context Lost => Expect the test_id0_ to be removed and
1395 // test_id1_ to have been created.
1396 // 3. Create one resource -> Delete that same resource -> Context Lost => Expect
1397 // the resource to not exist in the manager.
1398 class UIResourceLostBeforeCommit
: public UIResourceLostTestSimple
{
1400 UIResourceLostBeforeCommit() : test_id0_(0), test_id1_(0) {}
1402 void StepCompleteOnMainThread(int step
) override
{
1405 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1406 // Lose the context on the impl thread before the commit.
1407 PostLoseContextToImplThread();
1411 // Currently one resource has been created.
1412 test_id0_
= ui_resource_
->id();
1413 // Delete this resource.
1414 ui_resource_
= nullptr;
1415 // Create another resource.
1416 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1417 test_id1_
= ui_resource_
->id();
1418 // Sanity check that two resource creations return different ids.
1419 EXPECT_NE(test_id0_
, test_id1_
);
1420 // Lose the context on the impl thread before the commit.
1421 PostLoseContextToImplThread();
1424 // Clear the manager of resources.
1425 ui_resource_
= nullptr;
1426 PostSetNeedsCommitToMainThread();
1430 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1431 test_id0_
= ui_resource_
->id();
1432 // Sanity check the UIResourceId should not be 0.
1433 EXPECT_NE(0, test_id0_
);
1434 // Usually ScopedUIResource are deleted from the manager in their
1435 // destructor (so usually ui_resource_ = nullptr). But here we need
1436 // ui_resource_ for the next step, so call DeleteUIResource directly.
1437 layer_tree_host()->DeleteUIResource(test_id0_
);
1438 // Delete the resouce and then lose the context.
1439 PostLoseContextToImplThread();
1442 // Release resource before ending the test.
1443 ui_resource_
= nullptr;
1452 void StepCompleteOnImplThread(LayerTreeHostImpl
* impl
) override
{
1453 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1454 switch (time_step_
) {
1456 // Sequence 1 (continued):
1457 // The first context lost happens before the resources were created,
1458 // and because it resulted in no resources being destroyed, it does not
1459 // trigger resource re-creation.
1460 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1461 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1462 // Resource Id on the impl-side has been created.
1463 PostSetNeedsCommitToMainThread();
1466 // Sequence 2 (continued):
1467 // The previous resource should have been deleted.
1468 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(test_id0_
));
1469 // The second resource should have been created.
1470 EXPECT_NE(0u, impl
->ResourceIdForUIResource(test_id1_
));
1471 // The second resource called the resource callback once and since the
1472 // context is lost, a "resource lost" callback was also issued.
1473 EXPECT_EQ(2, ui_resource_
->resource_create_count
);
1474 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1477 // Sequence 3 (continued):
1478 // Expect the resource callback to have been called once.
1479 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1480 // No "resource lost" callbacks.
1481 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1482 // The UI resource id should not be valid
1483 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(test_id0_
));
1489 UIResourceId test_id0_
;
1490 UIResourceId test_id1_
;
1493 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeCommit
);
1495 // Losing UI resource before the pending trees is activated but after the
1496 // commit. Impl-side-painting only.
1497 class UIResourceLostBeforeActivateTree
: public UIResourceLostTest
{
1498 void StepCompleteOnMainThread(int step
) override
{
1499 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1502 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1503 PostSetNeedsCommitToMainThread();
1506 test_id_
= ui_resource_
->id();
1507 ui_resource_
= nullptr;
1508 PostSetNeedsCommitToMainThread();
1511 // Release resource before ending the test.
1512 ui_resource_
= nullptr;
1516 // Make sure no extra commits happened.
1521 void CommitCompleteOnThread(LayerTreeHostImpl
* impl
) override
{
1522 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1523 switch (time_step_
) {
1525 PostSetNeedsCommitToMainThread();
1528 PostSetNeedsCommitToMainThread();
1533 void WillActivateTreeOnThread(LayerTreeHostImpl
* impl
) override
{
1534 switch (time_step_
) {
1536 // The resource creation callback has been called.
1537 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1538 // The resource is not yet lost (sanity check).
1539 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1540 // The resource should not have been created yet on the impl-side.
1541 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1550 void DidActivateTreeOnThread(LayerTreeHostImpl
* impl
) override
{
1551 LayerTreeHostContextTest::DidActivateTreeOnThread(impl
);
1552 switch (time_step_
) {
1554 // The pending requests on the impl-side should have been processed.
1555 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1558 // The "lost resource" callback should have been called once.
1559 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1562 // The resource is deleted and should not be in the manager. Use
1563 // test_id_ since ui_resource_ has been deleted.
1564 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(test_id_
));
1568 PostStepCompleteToMainThread();
1573 UIResourceId test_id_
;
1576 TEST_F(UIResourceLostBeforeActivateTree
,
1577 RunMultiThread_DirectRenderer_ImplSidePaint
) {
1578 RunTest(true, false, true);
1581 TEST_F(UIResourceLostBeforeActivateTree
,
1582 RunMultiThread_DelegatingRenderer_ImplSidePaint
) {
1583 RunTest(true, true, true);
1586 // Resources evicted explicitly and by visibility changes.
1587 class UIResourceLostEviction
: public UIResourceLostTestSimple
{
1589 void StepCompleteOnMainThread(int step
) override
{
1590 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1593 ui_resource_
= FakeScopedUIResource::Create(layer_tree_host());
1594 EXPECT_NE(0, ui_resource_
->id());
1595 PostSetNeedsCommitToMainThread();
1598 // Make the tree not visible.
1599 PostSetVisibleToMainThread(false);
1602 // Release resource before ending the test.
1603 ui_resource_
= nullptr;
1611 void DidSetVisibleOnImplTree(LayerTreeHostImpl
* impl
, bool visible
) override
{
1612 TestWebGraphicsContext3D
* context
= TestContext();
1614 // All resources should have been evicted.
1615 ASSERT_EQ(0u, context
->NumTextures());
1616 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1617 EXPECT_EQ(2, ui_resource_
->resource_create_count
);
1618 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1619 // Drawing is disabled both because of the evicted resources and
1620 // because the renderer is not visible.
1621 EXPECT_FALSE(impl
->CanDraw());
1622 // Make the renderer visible again.
1623 PostSetVisibleToMainThread(true);
1627 void StepCompleteOnImplThread(LayerTreeHostImpl
* impl
) override
{
1628 TestWebGraphicsContext3D
* context
= TestContext();
1629 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1630 switch (time_step_
) {
1632 // The resource should have been created on LTHI after the commit.
1633 ASSERT_EQ(1u, context
->NumTextures());
1634 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1635 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1636 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1637 EXPECT_TRUE(impl
->CanDraw());
1638 // Evict all UI resources. This will trigger a commit.
1639 impl
->EvictAllUIResources();
1640 ASSERT_EQ(0u, context
->NumTextures());
1641 EXPECT_EQ(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1642 EXPECT_EQ(1, ui_resource_
->resource_create_count
);
1643 EXPECT_EQ(0, ui_resource_
->lost_resource_count
);
1644 EXPECT_FALSE(impl
->CanDraw());
1647 // The resource should have been recreated.
1648 ASSERT_EQ(1u, context
->NumTextures());
1649 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1650 EXPECT_EQ(2, ui_resource_
->resource_create_count
);
1651 EXPECT_EQ(1, ui_resource_
->lost_resource_count
);
1652 EXPECT_TRUE(impl
->CanDraw());
1655 // The resource should have been recreated after visibility was
1657 ASSERT_EQ(1u, context
->NumTextures());
1658 EXPECT_NE(0u, impl
->ResourceIdForUIResource(ui_resource_
->id()));
1659 EXPECT_EQ(3, ui_resource_
->resource_create_count
);
1660 EXPECT_EQ(2, ui_resource_
->lost_resource_count
);
1661 EXPECT_TRUE(impl
->CanDraw());
1667 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction
);
1669 class LayerTreeHostContextTestSurfaceCreateCallback
1670 : public LayerTreeHostContextTest
{
1672 LayerTreeHostContextTestSurfaceCreateCallback()
1673 : LayerTreeHostContextTest() {}
1675 void SetupTree() override
{
1676 if (layer_tree_host()->settings().impl_side_painting
) {
1677 picture_layer_
= FakePictureLayer::Create(&client_
);
1678 picture_layer_
->SetBounds(gfx::Size(10, 20));
1679 layer_tree_host()->SetRootLayer(picture_layer_
);
1681 content_layer_
= FakeContentLayer::Create(&client_
);
1682 content_layer_
->SetBounds(gfx::Size(10, 20));
1683 layer_tree_host()->SetRootLayer(content_layer_
);
1686 LayerTreeHostContextTest::SetupTree();
1689 void BeginTest() override
{ PostSetNeedsCommitToMainThread(); }
1691 void DidCommit() override
{
1692 switch (layer_tree_host()->source_frame_number()) {
1694 if (layer_tree_host()->settings().impl_side_painting
)
1695 EXPECT_EQ(1u, picture_layer_
->output_surface_created_count());
1697 EXPECT_EQ(1u, content_layer_
->output_surface_created_count());
1698 layer_tree_host()->SetNeedsCommit();
1701 if (layer_tree_host()->settings().impl_side_painting
)
1702 EXPECT_EQ(1u, picture_layer_
->output_surface_created_count());
1704 EXPECT_EQ(1u, content_layer_
->output_surface_created_count());
1705 layer_tree_host()->SetNeedsCommit();
1708 if (layer_tree_host()->settings().impl_side_painting
)
1709 EXPECT_EQ(1u, picture_layer_
->output_surface_created_count());
1711 EXPECT_EQ(1u, content_layer_
->output_surface_created_count());
1714 if (layer_tree_host()->settings().impl_side_painting
)
1715 EXPECT_EQ(2u, picture_layer_
->output_surface_created_count());
1717 EXPECT_EQ(2u, content_layer_
->output_surface_created_count());
1718 layer_tree_host()->SetNeedsCommit();
1723 void CommitCompleteOnThread(LayerTreeHostImpl
* impl
) override
{
1724 LayerTreeHostContextTest::CommitCompleteOnThread(impl
);
1725 switch (LastCommittedSourceFrameNumber(impl
)) {
1739 void AfterTest() override
{}
1742 FakeContentLayerClient client_
;
1743 scoped_refptr
<FakePictureLayer
> picture_layer_
;
1744 scoped_refptr
<FakeContentLayer
> content_layer_
;
1747 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestSurfaceCreateCallback
);
1749 class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame
1750 : public LayerTreeHostContextTest
{
1752 void BeginTest() override
{
1754 PostSetNeedsCommitToMainThread();
1757 void ScheduledActionWillSendBeginMainFrame() override
{
1762 // Defer commits before the BeginFrame arrives, causing it to be delayed.
1763 MainThreadTaskRunner()->PostTask(
1765 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1766 DeferCommitsOnMainThread
,
1767 base::Unretained(this),
1769 // Meanwhile, lose the context while we are in defer commits.
1770 ImplThreadTaskRunner()->PostTask(
1772 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1773 LoseContextOnImplThread
,
1774 base::Unretained(this)));
1777 void LoseContextOnImplThread() {
1780 // After losing the context, stop deferring commits.
1781 MainThreadTaskRunner()->PostTask(
1783 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1784 DeferCommitsOnMainThread
,
1785 base::Unretained(this),
1789 void DeferCommitsOnMainThread(bool defer_commits
) {
1790 layer_tree_host()->SetDeferCommits(defer_commits
);
1793 void WillBeginMainFrame() override
{
1794 // Don't begin a frame with a lost surface.
1795 EXPECT_FALSE(layer_tree_host()->output_surface_lost());
1798 void DidCommitAndDrawFrame() override
{ EndTest(); }
1800 void AfterTest() override
{}
1805 SINGLE_AND_MULTI_THREAD_TEST_F(
1806 LayerTreeHostContextTestLoseAfterSendingBeginMainFrame
);