Delete chrome.mediaGalleriesPrivate because the functionality unique to it has since...
[chromium-blink-merge.git] / cc / trees / layer_tree_host_unittest_context.cc
blob24ffcd46e4e3a933a2089b59773c81211692600f
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;
50 namespace cc {
51 namespace {
53 // These tests deal with losing the 3d graphics context.
54 class LayerTreeHostContextTest : public LayerTreeTest {
55 public:
56 LayerTreeHostContextTest()
57 : LayerTreeTest(),
58 context3d_(NULL),
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();
72 void LoseContext() {
73 // For sanity-checking tests, they should only call this when the
74 // context is not lost.
75 CHECK(context3d_);
76 context3d_->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
77 GL_INNOCENT_CONTEXT_RESET_ARB);
78 context3d_ = NULL;
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_;
88 ExpectCreateToFail();
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());
102 else
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);
114 return draw_result;
116 EXPECT_EQ(DRAW_SUCCESS, draw_result);
117 if (!times_to_lose_during_draw_)
118 return draw_result;
120 --times_to_lose_during_draw_;
121 LoseContext();
123 times_to_fail_create_ = times_to_fail_recreate_;
124 times_to_fail_recreate_ = 0;
126 return draw_result;
129 void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
130 committed_at_least_once_ = true;
132 if (!times_to_lose_during_commit_)
133 return;
134 --times_to_lose_during_commit_;
135 LoseContext();
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_; }
150 protected:
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 {
166 public:
167 LayerTreeHostContextTestLostContextSucceeds()
168 : LayerTreeHostContextTest(),
169 test_case_(0),
170 num_losses_(0),
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)));
183 } else {
184 CreateAndSetOutputSurface();
188 void CreateAndSetOutputSurface() {
189 scoped_ptr<OutputSurface> surface(
190 LayerTreeHostContextTest::CreateOutputSurface());
191 CHECK(surface);
192 layer_tree_host()->SetOutputSurface(surface.Pass());
195 void DidInitializeOutputSurface() override {
196 if (first_initialized_)
197 ++num_losses_;
198 else
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
208 // recover.
209 if (!recovered_context_)
210 return;
211 if (times_to_lose_during_commit_)
212 return;
213 if (times_to_lose_during_draw_)
214 return;
216 recovered_context_ = false;
217 if (NextTestCase())
218 InvalidateAndSetNeedsCommit();
219 else
220 EndTest();
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
269 // succeed.
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))
317 return false;
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;
330 ++test_case_;
331 return true;
334 struct TestCase {
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;
342 protected:
343 size_t test_case_;
344 int num_losses_;
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 {
354 public:
355 LayerTreeHostClientNotReadyDoesNotCreateOutputSurface()
356 : LayerTreeHostContextTest() {}
358 void WillBeginTest() override {
359 // Override and do not signal SetLayerTreeHostClientReady.
362 void BeginTest() override {
363 PostSetNeedsCommitToMainThread();
364 EndTest();
367 scoped_ptr<OutputSurface> CreateOutputSurface() override {
368 EXPECT_TRUE(false);
369 return nullptr;
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 {
382 public:
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_);
392 EndTest();
395 void BeginTest() override {
396 layer_tree_host()->Composite(base::TimeTicks());
397 layer_tree_host()->Composite(base::TimeTicks());
400 scoped_ptr<OutputSurface> CreateOutputSurface() override {
401 EXPECT_TRUE(false);
402 return nullptr;
405 void DidInitializeOutputSurface() override { EXPECT_TRUE(false); }
407 void AfterTest() override {}
409 int request_count_;
412 SINGLE_THREAD_NOIMPL_TEST_F(MultipleCompositeDoesNotCreateOutputSurface);
414 class FailedCreateDoesNotCreateExtraOutputSurface
415 : public LayerTreeHostContextTest {
416 public:
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_);
442 EndTest();
445 void AfterTest() override {}
447 int request_count_;
450 SINGLE_THREAD_NOIMPL_TEST_F(FailedCreateDoesNotCreateExtraOutputSurface);
452 class LayerTreeHostContextTestCommitAfterDelayedOutputSurface
453 : public LayerTreeHostContextTest {
454 public:
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(
464 FROM_HERE,
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_)
480 EndTest();
483 void AfterTest() override {}
485 bool creating_output_;
488 SINGLE_THREAD_NOIMPL_TEST_F(
489 LayerTreeHostContextTestCommitAfterDelayedOutputSurface);
491 class LayerTreeHostContextTestAvoidUnnecessaryComposite
492 : public LayerTreeHostContextTest {
493 public:
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());
504 EndTest();
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 {}
517 bool in_composite_;
520 SINGLE_THREAD_NOIMPL_TEST_F(LayerTreeHostContextTestAvoidUnnecessaryComposite);
522 class LayerTreeHostContextTestLostContextSucceedsWithContent
523 : public LayerTreeHostContextTestLostContextSucceeds {
524 public:
525 void SetupTree() override {
526 root_ = Layer::Create();
527 root_->SetBounds(gfx::Size(10, 10));
528 root_->SetIsDrawable(true);
530 // Paint non-solid color.
531 SkPaint paint;
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_);
537 else
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
551 // a child surface.
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));
564 } else {
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());
571 protected:
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 {
583 public:
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_);
600 private:
601 int times_to_fail_;
602 int times_initialized_;
605 SINGLE_AND_MULTI_THREAD_TEST_F(
606 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce);
608 class LayerTreeHostContextTestLostContextAndEvictTextures
609 : public LayerTreeHostContextTest {
610 public:
611 LayerTreeHostContextTestLostContextAndEvictTextures()
612 : LayerTreeHostContextTest(),
613 impl_host_(0),
614 num_commits_(0),
615 lost_context_(false) {}
617 void SetupTree() override {
618 // Paint non-solid color.
619 SkPaint paint;
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_);
627 } else {
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(
641 FROM_HERE,
642 base::Bind(&LayerTreeHostContextTestLostContextAndEvictTextures::
643 EvictTexturesOnImplThread,
644 base::Unretained(this)));
645 } else {
646 DebugScopedSetImplThread impl(proxy());
647 EvictTexturesOnImplThread();
651 void EvictTexturesOnImplThread() {
652 impl_host_->EvictTexturesForTesting();
654 if (lose_after_evict_) {
655 LoseContext();
656 lost_context_ = true;
660 void DidCommitAndDrawFrame() override {
661 if (num_commits_ > 1)
662 return;
663 if (!layer_tree_host()->settings().impl_side_painting) {
664 EXPECT_TRUE(content_layer_->HaveBackingAt(0, 0));
666 PostEvictTextures();
669 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
670 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
671 if (num_commits_ > 1)
672 return;
673 ++num_commits_;
674 if (!lose_after_evict_) {
675 LoseContext();
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());
685 } else {
686 FakeContentLayerImpl* content_impl =
687 static_cast<FakeContentLayerImpl*>(impl->active_tree()->root_layer());
688 EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0));
691 impl_host_ = impl;
692 if (lost_context_)
693 EndTest();
696 void DidInitializeOutputSurface() override {}
698 void AfterTest() override {}
700 protected:
701 bool lose_after_evict_;
702 FakeContentLayerClient client_;
703 scoped_refptr<FakeContentLayer> content_layer_;
704 scoped_refptr<FakePictureLayer> picture_layer_;
705 LayerTreeHostImpl* impl_host_;
706 int num_commits_;
707 bool lost_context_;
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 {
779 public:
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_);
796 else
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_);
805 else
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_);
820 EndTest();
823 void AfterTest() override { EXPECT_EQ(0, times_to_lose_on_end_query_); }
825 private:
826 FakeContentLayerClient client_;
827 scoped_refptr<Layer> parent_;
828 int num_children_;
829 int times_to_lose_on_end_query_;
832 SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
833 LayerTreeHostContextTestLostContextWhileUpdatingResources);
835 class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
836 public:
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_);
845 } else {
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());
873 child_picture =
874 static_cast<FakePictureLayerImpl*>(root_picture->children()[0]);
875 grandchild_picture =
876 static_cast<FakePictureLayerImpl*>(child_picture->children()[0]);
878 } else {
879 root_content = static_cast<FakeContentLayerImpl*>(
880 host_impl->active_tree()->root_layer());
881 child_content =
882 static_cast<FakeContentLayerImpl*>(root_content->children()[0]);
883 grandchild_content =
884 static_cast<FakeContentLayerImpl*>(child_content->children()[0]);
887 ++num_commits_;
888 switch (num_commits_) {
889 case 1:
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());
894 } else {
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.
901 LoseContext();
902 times_to_fail_create_ = 1;
903 break;
904 case 2:
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());
909 } else {
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());
915 EndTest();
916 break;
917 default:
918 NOTREACHED();
922 void AfterTest() override {}
924 private:
925 int num_commits_;
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 {
937 public:
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(),
947 NULL,
948 NULL,
950 false,
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.
965 RenderPassId(2, 1),
966 gfx::Rect(0, 0, 10, 10),
967 gfx::Rect(0, 0, 10, 10),
968 gfx::Transform());
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),
974 gfx::Transform());
975 pass->AppendOneOfEveryQuadType(child_resource_provider_.get(),
976 RenderPassId(2, 1));
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(
987 gfx::Size(4, 4),
988 GL_CLAMP_TO_EDGE,
989 ResourceProvider::TextureHintImmutable,
990 RGBA_8888);
991 ResourceProvider::ScopedWriteLockGL lock(child_resource_provider_.get(),
992 resource);
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_);
1011 else
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_);
1030 else
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_);
1037 else
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());
1064 hw_video_frame_ =
1065 VideoFrame::WrapNativeTexture(make_scoped_ptr(new gpu::MailboxHolder(
1066 mailbox, GL_TEXTURE_2D, sync_point)),
1067 media::VideoFrame::ReleaseMailboxCB(),
1068 gfx::Size(4, 4),
1069 gfx::Rect(0, 0, 4, 4),
1070 gfx::Size(4, 4),
1071 base::TimeDelta(),
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(),
1077 gfx::Size(4, 4),
1078 gfx::Rect(0, 0, 3, 2),
1079 gfx::Size(4, 4),
1080 base::TimeDelta(),
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);
1096 // Enable the hud.
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);
1134 return draw_result;
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();
1153 } else {
1154 EndTest();
1158 void AfterTest() override { EXPECT_TRUE(lost_context_); }
1160 private:
1161 FakeContentLayerClient client_;
1162 bool lost_context_;
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 {
1186 public:
1187 void InitializeSettings(LayerTreeSettings* settings) override {
1188 settings->impl_side_painting = true;
1192 class LayerTreeHostContextTestImplSidePainting
1193 : public ImplSidePaintingLayerTreeHostContextTest {
1194 public:
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(); }
1218 private:
1219 FakeContentLayerClient client_;
1222 MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting);
1224 class ScrollbarLayerLostContext : public LayerTreeHostContextTest {
1225 public:
1226 ScrollbarLayerLostContext() : commits_(0) {}
1228 void BeginTest() override {
1229 scoped_refptr<Layer> scroll_layer = Layer::Create();
1230 scrollbar_layer_ =
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);
1243 ++commits_;
1244 switch (commits_) {
1245 case 1:
1246 // First (regular) update, we should upload 2 resources (thumb, and
1247 // backtrack).
1248 EXPECT_EQ(1, scrollbar_layer_->update_count());
1249 LoseContext();
1250 break;
1251 case 2:
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());
1255 EndTest();
1256 break;
1257 default:
1258 NOTREACHED();
1262 private:
1263 int commits_;
1264 scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer_;
1267 SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext);
1269 class UIResourceLostTest : public LayerTreeHostContextTest {
1270 public:
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
1284 // painting.
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(
1292 FROM_HERE,
1293 base::Bind(&UIResourceLostTest::StepCompleteOnMainThreadInternal,
1294 base::Unretained(this),
1295 time_step_));
1298 void PostLoseContextToImplThread() {
1299 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1300 ImplThreadTaskRunner()->PostTask(
1301 FROM_HERE,
1302 base::Bind(&LayerTreeHostContextTest::LoseContext,
1303 base::Unretained(this)));
1306 protected:
1307 int time_step_;
1308 scoped_ptr<FakeScopedUIResource> ui_resource_;
1310 private:
1311 void StepCompleteOnMainThreadInternal(int step) {
1312 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1313 StepCompleteOnMainThread(step);
1317 class UIResourceLostTestSimple : public UIResourceLostTest {
1318 public:
1319 // This is called when the commit is complete and the new layer tree has been
1320 // activated.
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();
1327 ++time_step_;
1331 void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
1332 if (layer_tree_host()->settings().impl_side_painting) {
1333 StepCompleteOnImplThread(impl);
1334 PostStepCompleteToMainThread();
1335 ++time_step_;
1340 // Losing context after an UI resource has been created.
1341 class UIResourceLostAfterCommit : public UIResourceLostTestSimple {
1342 public:
1343 void StepCompleteOnMainThread(int step) override {
1344 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1345 switch (step) {
1346 case 0:
1347 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1348 // Expects a valid UIResourceId.
1349 EXPECT_NE(0, ui_resource_->id());
1350 PostSetNeedsCommitToMainThread();
1351 break;
1352 case 4:
1353 // Release resource before ending the test.
1354 ui_resource_ = nullptr;
1355 EndTest();
1356 break;
1357 case 5:
1358 NOTREACHED();
1359 break;
1363 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override {
1364 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1365 switch (time_step_) {
1366 case 1:
1367 // The resource should have been created on LTHI after the commit.
1368 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1369 PostSetNeedsCommitToMainThread();
1370 break;
1371 case 2:
1372 LoseContext();
1373 break;
1374 case 3:
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();
1382 break;
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
1392 // created.
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 {
1399 public:
1400 UIResourceLostBeforeCommit() : test_id0_(0), test_id1_(0) {}
1402 void StepCompleteOnMainThread(int step) override {
1403 switch (step) {
1404 case 0:
1405 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1406 // Lose the context on the impl thread before the commit.
1407 PostLoseContextToImplThread();
1408 break;
1409 case 2:
1410 // Sequence 2:
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();
1422 break;
1423 case 3:
1424 // Clear the manager of resources.
1425 ui_resource_ = nullptr;
1426 PostSetNeedsCommitToMainThread();
1427 break;
1428 case 4:
1429 // Sequence 3:
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();
1440 break;
1441 case 5:
1442 // Release resource before ending the test.
1443 ui_resource_ = nullptr;
1444 EndTest();
1445 break;
1446 case 6:
1447 NOTREACHED();
1448 break;
1452 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override {
1453 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1454 switch (time_step_) {
1455 case 1:
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();
1464 break;
1465 case 3:
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);
1475 break;
1476 case 5:
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_));
1484 break;
1488 private:
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());
1500 switch (step) {
1501 case 0:
1502 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1503 PostSetNeedsCommitToMainThread();
1504 break;
1505 case 3:
1506 test_id_ = ui_resource_->id();
1507 ui_resource_ = nullptr;
1508 PostSetNeedsCommitToMainThread();
1509 break;
1510 case 5:
1511 // Release resource before ending the test.
1512 ui_resource_ = nullptr;
1513 EndTest();
1514 break;
1515 case 6:
1516 // Make sure no extra commits happened.
1517 NOTREACHED();
1521 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
1522 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1523 switch (time_step_) {
1524 case 2:
1525 PostSetNeedsCommitToMainThread();
1526 break;
1527 case 4:
1528 PostSetNeedsCommitToMainThread();
1529 break;
1533 void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override {
1534 switch (time_step_) {
1535 case 1:
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()));
1542 LoseContext();
1543 break;
1544 case 3:
1545 LoseContext();
1546 break;
1550 void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
1551 LayerTreeHostContextTest::DidActivateTreeOnThread(impl);
1552 switch (time_step_) {
1553 case 1:
1554 // The pending requests on the impl-side should have been processed.
1555 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1556 break;
1557 case 2:
1558 // The "lost resource" callback should have been called once.
1559 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1560 break;
1561 case 4:
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_));
1565 break;
1568 PostStepCompleteToMainThread();
1569 ++time_step_;
1572 private:
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 {
1588 public:
1589 void StepCompleteOnMainThread(int step) override {
1590 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1591 switch (step) {
1592 case 0:
1593 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1594 EXPECT_NE(0, ui_resource_->id());
1595 PostSetNeedsCommitToMainThread();
1596 break;
1597 case 2:
1598 // Make the tree not visible.
1599 PostSetVisibleToMainThread(false);
1600 break;
1601 case 3:
1602 // Release resource before ending the test.
1603 ui_resource_ = nullptr;
1604 EndTest();
1605 break;
1606 case 4:
1607 NOTREACHED();
1611 void DidSetVisibleOnImplTree(LayerTreeHostImpl* impl, bool visible) override {
1612 TestWebGraphicsContext3D* context = TestContext();
1613 if (!visible) {
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_) {
1631 case 1:
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());
1645 break;
1646 case 2:
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());
1653 break;
1654 case 3:
1655 // The resource should have been recreated after visibility was
1656 // restored.
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());
1662 break;
1667 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction);
1669 class LayerTreeHostContextTestSurfaceCreateCallback
1670 : public LayerTreeHostContextTest {
1671 public:
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_);
1680 } else {
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()) {
1693 case 1:
1694 if (layer_tree_host()->settings().impl_side_painting)
1695 EXPECT_EQ(1u, picture_layer_->output_surface_created_count());
1696 else
1697 EXPECT_EQ(1u, content_layer_->output_surface_created_count());
1698 layer_tree_host()->SetNeedsCommit();
1699 break;
1700 case 2:
1701 if (layer_tree_host()->settings().impl_side_painting)
1702 EXPECT_EQ(1u, picture_layer_->output_surface_created_count());
1703 else
1704 EXPECT_EQ(1u, content_layer_->output_surface_created_count());
1705 layer_tree_host()->SetNeedsCommit();
1706 break;
1707 case 3:
1708 if (layer_tree_host()->settings().impl_side_painting)
1709 EXPECT_EQ(1u, picture_layer_->output_surface_created_count());
1710 else
1711 EXPECT_EQ(1u, content_layer_->output_surface_created_count());
1712 break;
1713 case 4:
1714 if (layer_tree_host()->settings().impl_side_painting)
1715 EXPECT_EQ(2u, picture_layer_->output_surface_created_count());
1716 else
1717 EXPECT_EQ(2u, content_layer_->output_surface_created_count());
1718 layer_tree_host()->SetNeedsCommit();
1719 break;
1723 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
1724 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1725 switch (LastCommittedSourceFrameNumber(impl)) {
1726 case 0:
1727 break;
1728 case 1:
1729 break;
1730 case 2:
1731 LoseContext();
1732 break;
1733 case 3:
1734 EndTest();
1735 break;
1739 void AfterTest() override {}
1741 protected:
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 {
1751 protected:
1752 void BeginTest() override {
1753 deferred_ = false;
1754 PostSetNeedsCommitToMainThread();
1757 void ScheduledActionWillSendBeginMainFrame() override {
1758 if (deferred_)
1759 return;
1760 deferred_ = true;
1762 // Defer commits before the BeginFrame arrives, causing it to be delayed.
1763 MainThreadTaskRunner()->PostTask(
1764 FROM_HERE,
1765 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1766 DeferCommitsOnMainThread,
1767 base::Unretained(this),
1768 true));
1769 // Meanwhile, lose the context while we are in defer commits.
1770 ImplThreadTaskRunner()->PostTask(
1771 FROM_HERE,
1772 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1773 LoseContextOnImplThread,
1774 base::Unretained(this)));
1777 void LoseContextOnImplThread() {
1778 LoseContext();
1780 // After losing the context, stop deferring commits.
1781 MainThreadTaskRunner()->PostTask(
1782 FROM_HERE,
1783 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1784 DeferCommitsOnMainThread,
1785 base::Unretained(this),
1786 false));
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 {}
1802 bool deferred_;
1805 SINGLE_AND_MULTI_THREAD_TEST_F(
1806 LayerTreeHostContextTestLoseAfterSendingBeginMainFrame);
1808 } // namespace
1809 } // namespace cc