Fixing flashing of previous users window upon adding another user to the session
[chromium-blink-merge.git] / cc / trees / layer_tree_host_unittest_context.cc
blob2d23d755f768384b95ce6bf614c0ab3014a233c9
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/fake_content_layer.h"
23 #include "cc/test/fake_content_layer_client.h"
24 #include "cc/test/fake_content_layer_impl.h"
25 #include "cc/test/fake_delegated_renderer_layer.h"
26 #include "cc/test/fake_delegated_renderer_layer_impl.h"
27 #include "cc/test/fake_layer_tree_host_client.h"
28 #include "cc/test/fake_output_surface.h"
29 #include "cc/test/fake_output_surface_client.h"
30 #include "cc/test/fake_painted_scrollbar_layer.h"
31 #include "cc/test/fake_picture_layer.h"
32 #include "cc/test/fake_picture_layer_impl.h"
33 #include "cc/test/fake_scoped_ui_resource.h"
34 #include "cc/test/fake_scrollbar.h"
35 #include "cc/test/fake_video_frame_provider.h"
36 #include "cc/test/layer_tree_test.h"
37 #include "cc/test/render_pass_test_common.h"
38 #include "cc/test/test_context_provider.h"
39 #include "cc/test/test_shared_bitmap_manager.h"
40 #include "cc/test/test_web_graphics_context_3d.h"
41 #include "cc/trees/layer_tree_host_impl.h"
42 #include "cc/trees/layer_tree_impl.h"
43 #include "cc/trees/single_thread_proxy.h"
44 #include "gpu/GLES2/gl2extchromium.h"
45 #include "media/base/media.h"
47 using media::VideoFrame;
49 namespace cc {
50 namespace {
52 // These tests deal with losing the 3d graphics context.
53 class LayerTreeHostContextTest : public LayerTreeTest {
54 public:
55 LayerTreeHostContextTest()
56 : LayerTreeTest(),
57 context3d_(NULL),
58 times_to_fail_create_(0),
59 times_to_lose_during_commit_(0),
60 times_to_lose_during_draw_(0),
61 times_to_fail_recreate_(0),
62 times_to_expect_create_failed_(0),
63 times_create_failed_(0),
64 committed_at_least_once_(false),
65 context_should_support_io_surface_(false),
66 fallback_context_works_(false),
67 async_output_surface_creation_(false) {
68 media::InitializeMediaLibraryForTesting();
71 void LoseContext() {
72 // For sanity-checking tests, they should only call this when the
73 // context is not lost.
74 CHECK(context3d_);
75 context3d_->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
76 GL_INNOCENT_CONTEXT_RESET_ARB);
77 context3d_ = NULL;
80 virtual scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() {
81 return TestWebGraphicsContext3D::Create();
84 scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
85 bool fallback) override {
86 if (times_to_fail_create_) {
87 --times_to_fail_create_;
88 ExpectCreateToFail();
89 return nullptr;
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(bool fallback) override {
178 if (async_output_surface_creation_) {
179 MainThreadTaskRunner()->PostTask(
180 FROM_HERE,
181 base::Bind(&LayerTreeHostContextTestLostContextSucceeds::
182 CreateAndSetOutputSurface,
183 base::Unretained(this),
184 fallback));
185 } else {
186 CreateAndSetOutputSurface(fallback);
190 void CreateAndSetOutputSurface(bool fallback) {
191 layer_tree_host()->SetOutputSurface(
192 LayerTreeHostContextTest::CreateOutputSurface(fallback));
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(bool fallback) 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(bool fallback) 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(bool fallback) 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(bool fallback) override {
425 if (request_count_ == 0) {
426 ExpectCreateToFail();
427 layer_tree_host()->SetOutputSurface(nullptr);
429 EXPECT_GE(2, ++request_count_);
430 EndTest();
433 void BeginTest() override {
434 layer_tree_host()->Composite(base::TimeTicks());
435 layer_tree_host()->Composite(base::TimeTicks());
438 scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) override {
439 EXPECT_TRUE(false);
440 return nullptr;
443 void DidInitializeOutputSurface() override { EXPECT_TRUE(false); }
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(bool fallback) override {
463 MainThreadTaskRunner()->PostTask(
464 FROM_HERE,
465 base::Bind(&LayerTreeHostContextTestCommitAfterDelayedOutputSurface::
466 CreateAndSetOutputSurface,
467 base::Unretained(this),
468 fallback));
471 void CreateAndSetOutputSurface(bool fallback) {
472 creating_output_ = true;
473 layer_tree_host()->SetOutputSurface(
474 LayerTreeHostContextTest::CreateOutputSurface(fallback));
477 void BeginTest() override { layer_tree_host()->Composite(base::TimeTicks()); }
479 void ScheduleComposite() override {
480 if (creating_output_)
481 EndTest();
484 void AfterTest() override {}
486 bool creating_output_;
489 SINGLE_THREAD_NOIMPL_TEST_F(
490 LayerTreeHostContextTestCommitAfterDelayedOutputSurface);
492 class LayerTreeHostContextTestAvoidUnnecessaryComposite
493 : public LayerTreeHostContextTest {
494 public:
495 LayerTreeHostContextTestAvoidUnnecessaryComposite()
496 : LayerTreeHostContextTest(), in_composite_(false) {}
498 void InitializeSettings(LayerTreeSettings* settings) override {
499 settings->single_thread_proxy_scheduler = false;
502 void RequestNewOutputSurface(bool fallback) override {
503 layer_tree_host()->SetOutputSurface(
504 LayerTreeHostContextTest::CreateOutputSurface(fallback));
505 EndTest();
508 void BeginTest() override {
509 in_composite_ = true;
510 layer_tree_host()->Composite(base::TimeTicks());
511 in_composite_ = false;
514 void ScheduleComposite() override { EXPECT_FALSE(in_composite_); }
516 void AfterTest() override {}
518 bool in_composite_;
521 SINGLE_THREAD_NOIMPL_TEST_F(LayerTreeHostContextTestAvoidUnnecessaryComposite);
523 class LayerTreeHostContextTestLostContextSucceedsWithContent
524 : public LayerTreeHostContextTestLostContextSucceeds {
525 public:
526 void SetupTree() override {
527 root_ = Layer::Create();
528 root_->SetBounds(gfx::Size(10, 10));
529 root_->SetIsDrawable(true);
531 // Paint non-solid color.
532 SkPaint paint;
533 paint.setColor(SkColorSetARGB(100, 80, 200, 200));
534 client_.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint);
536 if (layer_tree_host()->settings().impl_side_painting)
537 layer_ = FakePictureLayer::Create(&client_);
538 else
539 layer_ = FakeContentLayer::Create(&client_);
540 layer_->SetBounds(gfx::Size(10, 10));
541 layer_->SetIsDrawable(true);
543 root_->AddChild(layer_);
545 layer_tree_host()->SetRootLayer(root_);
546 LayerTreeHostContextTest::SetupTree();
549 void InvalidateAndSetNeedsCommit() override {
550 // Invalidate the render surface so we don't try to use a cached copy of the
551 // surface. We want to make sure to test the drawing paths for drawing to
552 // a child surface.
553 layer_->SetNeedsDisplay();
554 LayerTreeHostContextTestLostContextSucceeds::InvalidateAndSetNeedsCommit();
557 void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
558 if (!host_impl->settings().impl_side_painting) {
559 FakeContentLayerImpl* content_impl = static_cast<FakeContentLayerImpl*>(
560 host_impl->active_tree()->root_layer()->children()[0]);
561 // Even though the context was lost, we should have a resource. The
562 // TestWebGraphicsContext3D ensures that this resource is created with
563 // the active context.
564 EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0));
565 } else {
566 FakePictureLayerImpl* picture_impl = static_cast<FakePictureLayerImpl*>(
567 host_impl->active_tree()->root_layer()->children()[0]);
568 EXPECT_TRUE(picture_impl->HighResTiling()->TileAt(0, 0)->IsReadyToDraw());
572 protected:
573 FakeContentLayerClient client_;
574 scoped_refptr<Layer> root_;
575 scoped_refptr<Layer> layer_;
578 // This test uses TiledLayer and PictureLayer to check for a working context.
579 SINGLE_AND_MULTI_THREAD_TEST_F(
580 LayerTreeHostContextTestLostContextSucceedsWithContent);
582 class LayerTreeHostContextTestCreateOutputSurfaceFails
583 : public LayerTreeHostContextTest {
584 public:
585 // Run a test that initially fails OutputSurface creation |times_to_fail|
586 // times. If |expect_fallback_attempt| is |true|, an attempt to create a
587 // fallback/software OutputSurface is expected to occur.
588 LayerTreeHostContextTestCreateOutputSurfaceFails(int times_to_fail,
589 bool expect_fallback_attempt)
590 : times_to_fail_(times_to_fail),
591 expect_fallback_attempt_(expect_fallback_attempt),
592 did_attempt_fallback_(false),
593 times_initialized_(0) {
594 times_to_fail_create_ = times_to_fail_;
597 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
599 scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
600 bool fallback) override {
601 scoped_ptr<FakeOutputSurface> surface =
602 LayerTreeHostContextTest::CreateFakeOutputSurface(fallback);
604 if (surface)
605 EXPECT_EQ(times_to_fail_, times_create_failed_);
607 did_attempt_fallback_ = fallback;
608 return surface.Pass();
611 void DidInitializeOutputSurface() override { times_initialized_++; }
613 void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { EndTest(); }
615 void AfterTest() override {
616 EXPECT_EQ(times_to_fail_, times_create_failed_);
617 EXPECT_NE(0, times_initialized_);
618 EXPECT_EQ(expect_fallback_attempt_, did_attempt_fallback_);
621 private:
622 int times_to_fail_;
623 bool expect_fallback_attempt_;
624 bool did_attempt_fallback_;
625 int times_initialized_;
628 class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
629 : public LayerTreeHostContextTestCreateOutputSurfaceFails {
630 public:
631 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
632 : LayerTreeHostContextTestCreateOutputSurfaceFails(1, false) {}
635 SINGLE_AND_MULTI_THREAD_TEST_F(
636 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce);
638 // After 4 failures we expect an attempt to create a fallback/software
639 // OutputSurface.
640 class LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback
641 : public LayerTreeHostContextTestCreateOutputSurfaceFails {
642 public:
643 LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback()
644 : LayerTreeHostContextTestCreateOutputSurfaceFails(4, true) {}
647 SINGLE_AND_MULTI_THREAD_TEST_F(
648 LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback);
650 class LayerTreeHostContextTestLostContextAndEvictTextures
651 : public LayerTreeHostContextTest {
652 public:
653 LayerTreeHostContextTestLostContextAndEvictTextures()
654 : LayerTreeHostContextTest(),
655 impl_host_(0),
656 num_commits_(0),
657 lost_context_(false) {}
659 void SetupTree() override {
660 // Paint non-solid color.
661 SkPaint paint;
662 paint.setColor(SkColorSetARGB(100, 80, 200, 200));
663 client_.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint);
665 if (layer_tree_host()->settings().impl_side_painting) {
666 picture_layer_ = FakePictureLayer::Create(&client_);
667 picture_layer_->SetBounds(gfx::Size(10, 20));
668 layer_tree_host()->SetRootLayer(picture_layer_);
669 } else {
670 content_layer_ = FakeContentLayer::Create(&client_);
671 content_layer_->SetBounds(gfx::Size(10, 20));
672 layer_tree_host()->SetRootLayer(content_layer_);
675 LayerTreeHostContextTest::SetupTree();
678 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
680 void PostEvictTextures() {
681 if (HasImplThread()) {
682 ImplThreadTaskRunner()->PostTask(
683 FROM_HERE,
684 base::Bind(&LayerTreeHostContextTestLostContextAndEvictTextures::
685 EvictTexturesOnImplThread,
686 base::Unretained(this)));
687 } else {
688 DebugScopedSetImplThread impl(proxy());
689 EvictTexturesOnImplThread();
693 void EvictTexturesOnImplThread() {
694 impl_host_->EvictTexturesForTesting();
696 if (lose_after_evict_) {
697 LoseContext();
698 lost_context_ = true;
702 void DidCommitAndDrawFrame() override {
703 if (num_commits_ > 1)
704 return;
705 if (!layer_tree_host()->settings().impl_side_painting) {
706 EXPECT_TRUE(content_layer_->HaveBackingAt(0, 0));
708 PostEvictTextures();
711 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
712 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
713 if (num_commits_ > 1)
714 return;
715 ++num_commits_;
716 if (!lose_after_evict_) {
717 LoseContext();
718 lost_context_ = true;
722 void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
723 if (impl->settings().impl_side_painting) {
724 FakePictureLayerImpl* picture_impl =
725 static_cast<FakePictureLayerImpl*>(impl->active_tree()->root_layer());
726 EXPECT_TRUE(picture_impl->HighResTiling()->TileAt(0, 0)->IsReadyToDraw());
727 } else {
728 FakeContentLayerImpl* content_impl =
729 static_cast<FakeContentLayerImpl*>(impl->active_tree()->root_layer());
730 EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0));
733 impl_host_ = impl;
734 if (lost_context_)
735 EndTest();
738 void DidInitializeOutputSurface() override {}
740 void AfterTest() override {}
742 protected:
743 bool lose_after_evict_;
744 FakeContentLayerClient client_;
745 scoped_refptr<FakeContentLayer> content_layer_;
746 scoped_refptr<FakePictureLayer> picture_layer_;
747 LayerTreeHostImpl* impl_host_;
748 int num_commits_;
749 bool lost_context_;
752 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
753 LoseAfterEvict_SingleThread_DirectRenderer) {
754 lose_after_evict_ = true;
755 RunTest(false, false, false);
758 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
759 LoseAfterEvict_SingleThread_DelegatingRenderer) {
760 lose_after_evict_ = true;
761 RunTest(false, true, false);
764 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
765 LoseAfterEvict_MultiThread_DirectRenderer_MainThreadPaint) {
766 lose_after_evict_ = true;
767 RunTest(true, false, false);
770 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
771 LoseAfterEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
772 lose_after_evict_ = true;
773 RunTest(true, true, false);
776 // Flaky on all platforms, http://crbug.com/310979
777 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
778 DISABLED_LoseAfterEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
779 lose_after_evict_ = true;
780 RunTest(true, true, true);
783 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
784 LoseBeforeEvict_SingleThread_DirectRenderer) {
785 lose_after_evict_ = false;
786 RunTest(false, false, false);
789 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
790 LoseBeforeEvict_SingleThread_DelegatingRenderer) {
791 lose_after_evict_ = false;
792 RunTest(false, true, false);
795 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
796 LoseBeforeEvict_MultiThread_DirectRenderer_MainThreadPaint) {
797 lose_after_evict_ = false;
798 RunTest(true, false, false);
801 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
802 LoseBeforeEvict_MultiThread_DirectRenderer_ImplSidePaint) {
803 lose_after_evict_ = false;
804 RunTest(true, false, true);
807 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
808 LoseBeforeEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
809 lose_after_evict_ = false;
810 RunTest(true, true, false);
813 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
814 LoseBeforeEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
815 lose_after_evict_ = false;
816 RunTest(true, true, true);
819 class LayerTreeHostContextTestLostContextWhileUpdatingResources
820 : public LayerTreeHostContextTest {
821 public:
822 LayerTreeHostContextTestLostContextWhileUpdatingResources()
823 : num_children_(50), times_to_lose_on_end_query_(3) {}
825 scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() override {
826 scoped_ptr<TestWebGraphicsContext3D> context =
827 LayerTreeHostContextTest::CreateContext3d();
828 if (times_to_lose_on_end_query_) {
829 --times_to_lose_on_end_query_;
830 context->set_times_end_query_succeeds(5);
832 return context.Pass();
835 void SetupTree() override {
836 if (layer_tree_host()->settings().impl_side_painting)
837 parent_ = FakePictureLayer::Create(&client_);
838 else
839 parent_ = FakeContentLayer::Create(&client_);
841 parent_->SetBounds(gfx::Size(num_children_, 1));
843 for (int i = 0; i < num_children_; i++) {
844 scoped_refptr<Layer> child;
845 if (layer_tree_host()->settings().impl_side_painting)
846 child = FakePictureLayer::Create(&client_);
847 else
848 child = FakeContentLayer::Create(&client_);
849 child->SetPosition(gfx::PointF(i, 0.f));
850 child->SetBounds(gfx::Size(1, 1));
851 parent_->AddChild(child);
854 layer_tree_host()->SetRootLayer(parent_);
855 LayerTreeHostContextTest::SetupTree();
858 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
860 void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
861 EXPECT_EQ(0, times_to_lose_on_end_query_);
862 EndTest();
865 void AfterTest() override { EXPECT_EQ(0, times_to_lose_on_end_query_); }
867 private:
868 FakeContentLayerClient client_;
869 scoped_refptr<Layer> parent_;
870 int num_children_;
871 int times_to_lose_on_end_query_;
874 SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
875 LayerTreeHostContextTestLostContextWhileUpdatingResources);
877 class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
878 public:
879 LayerTreeHostContextTestLayersNotified()
880 : LayerTreeHostContextTest(), num_commits_(0) {}
882 void SetupTree() override {
883 if (layer_tree_host()->settings().impl_side_painting) {
884 root_ = FakePictureLayer::Create(&client_);
885 child_ = FakePictureLayer::Create(&client_);
886 grandchild_ = FakePictureLayer::Create(&client_);
887 } else {
888 root_ = FakeContentLayer::Create(&client_);
889 child_ = FakeContentLayer::Create(&client_);
890 grandchild_ = FakeContentLayer::Create(&client_);
893 root_->AddChild(child_);
894 child_->AddChild(grandchild_);
896 layer_tree_host()->SetRootLayer(root_);
897 LayerTreeHostContextTest::SetupTree();
900 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
902 void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
903 LayerTreeHostContextTest::DidActivateTreeOnThread(host_impl);
905 FakePictureLayerImpl* root_picture = NULL;
906 FakePictureLayerImpl* child_picture = NULL;
907 FakePictureLayerImpl* grandchild_picture = NULL;
908 FakeContentLayerImpl* root_content = NULL;
909 FakeContentLayerImpl* child_content = NULL;
910 FakeContentLayerImpl* grandchild_content = NULL;
912 if (layer_tree_host()->settings().impl_side_painting) {
913 root_picture = static_cast<FakePictureLayerImpl*>(
914 host_impl->active_tree()->root_layer());
915 child_picture =
916 static_cast<FakePictureLayerImpl*>(root_picture->children()[0]);
917 grandchild_picture =
918 static_cast<FakePictureLayerImpl*>(child_picture->children()[0]);
920 } else {
921 root_content = static_cast<FakeContentLayerImpl*>(
922 host_impl->active_tree()->root_layer());
923 child_content =
924 static_cast<FakeContentLayerImpl*>(root_content->children()[0]);
925 grandchild_content =
926 static_cast<FakeContentLayerImpl*>(child_content->children()[0]);
929 ++num_commits_;
930 switch (num_commits_) {
931 case 1:
932 if (layer_tree_host()->settings().impl_side_painting) {
933 EXPECT_EQ(0u, root_picture->release_resources_count());
934 EXPECT_EQ(0u, child_picture->release_resources_count());
935 EXPECT_EQ(0u, grandchild_picture->release_resources_count());
936 } else {
937 EXPECT_EQ(0u, root_content->lost_output_surface_count());
938 EXPECT_EQ(0u, child_content->lost_output_surface_count());
939 EXPECT_EQ(0u, grandchild_content->lost_output_surface_count());
942 // Lose the context and struggle to recreate it.
943 LoseContext();
944 times_to_fail_create_ = 1;
945 break;
946 case 2:
947 if (layer_tree_host()->settings().impl_side_painting) {
948 EXPECT_TRUE(root_picture->release_resources_count());
949 EXPECT_TRUE(child_picture->release_resources_count());
950 EXPECT_TRUE(grandchild_picture->release_resources_count());
951 } else {
952 EXPECT_TRUE(root_content->lost_output_surface_count());
953 EXPECT_TRUE(child_content->lost_output_surface_count());
954 EXPECT_TRUE(grandchild_content->lost_output_surface_count());
957 EndTest();
958 break;
959 default:
960 NOTREACHED();
964 void AfterTest() override {}
966 private:
967 int num_commits_;
969 FakeContentLayerClient client_;
970 scoped_refptr<Layer> root_;
971 scoped_refptr<Layer> child_;
972 scoped_refptr<Layer> grandchild_;
975 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified);
977 class LayerTreeHostContextTestDontUseLostResources
978 : public LayerTreeHostContextTest {
979 public:
980 LayerTreeHostContextTestDontUseLostResources() : lost_context_(false) {
981 context_should_support_io_surface_ = true;
983 child_output_surface_ = FakeOutputSurface::Create3d();
984 child_output_surface_->BindToClient(&output_surface_client_);
985 shared_bitmap_manager_.reset(new TestSharedBitmapManager());
986 child_resource_provider_ =
987 ResourceProvider::Create(child_output_surface_.get(),
988 shared_bitmap_manager_.get(),
989 NULL,
990 NULL,
992 false,
996 static void EmptyReleaseCallback(unsigned sync_point, bool lost) {}
998 void SetupTree() override {
999 gpu::gles2::GLES2Interface* gl =
1000 child_output_surface_->context_provider()->ContextGL();
1002 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
1004 scoped_ptr<TestRenderPass> pass_for_quad = TestRenderPass::Create();
1005 pass_for_quad->SetNew(
1006 // AppendOneOfEveryQuadType() makes a RenderPass quad with this id.
1007 RenderPassId(2, 1),
1008 gfx::Rect(0, 0, 10, 10),
1009 gfx::Rect(0, 0, 10, 10),
1010 gfx::Transform());
1012 scoped_ptr<TestRenderPass> pass = TestRenderPass::Create();
1013 pass->SetNew(RenderPassId(1, 1),
1014 gfx::Rect(0, 0, 10, 10),
1015 gfx::Rect(0, 0, 10, 10),
1016 gfx::Transform());
1017 pass->AppendOneOfEveryQuadType(child_resource_provider_.get(),
1018 RenderPassId(2, 1));
1020 frame_data->render_pass_list.push_back(pass_for_quad.Pass());
1021 frame_data->render_pass_list.push_back(pass.Pass());
1023 delegated_resource_collection_ = new DelegatedFrameResourceCollection;
1024 delegated_frame_provider_ = new DelegatedFrameProvider(
1025 delegated_resource_collection_.get(), frame_data.Pass());
1027 ResourceProvider::ResourceId resource =
1028 child_resource_provider_->CreateResource(
1029 gfx::Size(4, 4),
1030 GL_CLAMP_TO_EDGE,
1031 ResourceProvider::TextureHintImmutable,
1032 RGBA_8888);
1033 ResourceProvider::ScopedWriteLockGL lock(child_resource_provider_.get(),
1034 resource);
1036 gpu::Mailbox mailbox;
1037 gl->GenMailboxCHROMIUM(mailbox.name);
1038 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1040 scoped_refptr<Layer> root = Layer::Create();
1041 root->SetBounds(gfx::Size(10, 10));
1042 root->SetIsDrawable(true);
1044 scoped_refptr<FakeDelegatedRendererLayer> delegated =
1045 FakeDelegatedRendererLayer::Create(delegated_frame_provider_.get());
1046 delegated->SetBounds(gfx::Size(10, 10));
1047 delegated->SetIsDrawable(true);
1048 root->AddChild(delegated);
1050 scoped_refptr<Layer> layer;
1051 if (layer_tree_host()->settings().impl_side_painting)
1052 layer = PictureLayer::Create(&client_);
1053 else
1054 layer = ContentLayer::Create(&client_);
1055 layer->SetBounds(gfx::Size(10, 10));
1056 layer->SetIsDrawable(true);
1057 root->AddChild(layer);
1059 scoped_refptr<TextureLayer> texture = TextureLayer::CreateForMailbox(NULL);
1060 texture->SetBounds(gfx::Size(10, 10));
1061 texture->SetIsDrawable(true);
1062 texture->SetTextureMailbox(
1063 TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point),
1064 SingleReleaseCallback::Create(
1065 base::Bind(&LayerTreeHostContextTestDontUseLostResources::
1066 EmptyReleaseCallback)));
1067 root->AddChild(texture);
1069 scoped_refptr<Layer> mask;
1070 if (layer_tree_host()->settings().impl_side_painting)
1071 mask = PictureLayer::Create(&client_);
1072 else
1073 mask = ContentLayer::Create(&client_);
1074 mask->SetBounds(gfx::Size(10, 10));
1076 scoped_refptr<Layer> layer_with_mask;
1077 if (layer_tree_host()->settings().impl_side_painting)
1078 layer_with_mask = PictureLayer::Create(&client_);
1079 else
1080 layer_with_mask = ContentLayer::Create(&client_);
1081 layer_with_mask->SetBounds(gfx::Size(10, 10));
1082 layer_with_mask->SetIsDrawable(true);
1083 layer_with_mask->SetMaskLayer(mask.get());
1084 root->AddChild(layer_with_mask);
1086 scoped_refptr<VideoLayer> video_color =
1087 VideoLayer::Create(&color_frame_provider_, media::VIDEO_ROTATION_0);
1088 video_color->SetBounds(gfx::Size(10, 10));
1089 video_color->SetIsDrawable(true);
1090 root->AddChild(video_color);
1092 scoped_refptr<VideoLayer> video_hw =
1093 VideoLayer::Create(&hw_frame_provider_, media::VIDEO_ROTATION_0);
1094 video_hw->SetBounds(gfx::Size(10, 10));
1095 video_hw->SetIsDrawable(true);
1096 root->AddChild(video_hw);
1098 scoped_refptr<VideoLayer> video_scaled_hw =
1099 VideoLayer::Create(&scaled_hw_frame_provider_, media::VIDEO_ROTATION_0);
1100 video_scaled_hw->SetBounds(gfx::Size(10, 10));
1101 video_scaled_hw->SetIsDrawable(true);
1102 root->AddChild(video_scaled_hw);
1104 color_video_frame_ = VideoFrame::CreateColorFrame(
1105 gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
1106 hw_video_frame_ =
1107 VideoFrame::WrapNativeTexture(make_scoped_ptr(new gpu::MailboxHolder(
1108 mailbox, GL_TEXTURE_2D, sync_point)),
1109 media::VideoFrame::ReleaseMailboxCB(),
1110 gfx::Size(4, 4),
1111 gfx::Rect(0, 0, 4, 4),
1112 gfx::Size(4, 4),
1113 base::TimeDelta(),
1114 VideoFrame::ReadPixelsCB());
1115 scaled_hw_video_frame_ =
1116 VideoFrame::WrapNativeTexture(make_scoped_ptr(new gpu::MailboxHolder(
1117 mailbox, GL_TEXTURE_2D, sync_point)),
1118 media::VideoFrame::ReleaseMailboxCB(),
1119 gfx::Size(4, 4),
1120 gfx::Rect(0, 0, 3, 2),
1121 gfx::Size(4, 4),
1122 base::TimeDelta(),
1123 VideoFrame::ReadPixelsCB());
1125 color_frame_provider_.set_frame(color_video_frame_);
1126 hw_frame_provider_.set_frame(hw_video_frame_);
1127 scaled_hw_frame_provider_.set_frame(scaled_hw_video_frame_);
1129 if (!delegating_renderer()) {
1130 // TODO(danakj): IOSurface layer can not be transported. crbug.com/239335
1131 scoped_refptr<IOSurfaceLayer> io_surface = IOSurfaceLayer::Create();
1132 io_surface->SetBounds(gfx::Size(10, 10));
1133 io_surface->SetIsDrawable(true);
1134 io_surface->SetIOSurfaceProperties(1, gfx::Size(10, 10));
1135 root->AddChild(io_surface);
1138 // Enable the hud.
1139 LayerTreeDebugState debug_state;
1140 debug_state.show_property_changed_rects = true;
1141 layer_tree_host()->SetDebugState(debug_state);
1143 scoped_refptr<PaintedScrollbarLayer> scrollbar =
1144 PaintedScrollbarLayer::Create(
1145 scoped_ptr<Scrollbar>(new FakeScrollbar).Pass(), layer->id());
1146 scrollbar->SetBounds(gfx::Size(10, 10));
1147 scrollbar->SetIsDrawable(true);
1148 root->AddChild(scrollbar);
1150 layer_tree_host()->SetRootLayer(root);
1151 LayerTreeHostContextTest::SetupTree();
1154 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
1156 void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
1157 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
1159 if (host_impl->active_tree()->source_frame_number() == 3) {
1160 // On the third commit we're recovering from context loss. Hardware
1161 // video frames should not be reused by the VideoFrameProvider, but
1162 // software frames can be.
1163 hw_frame_provider_.set_frame(NULL);
1164 scaled_hw_frame_provider_.set_frame(NULL);
1168 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
1169 LayerTreeHostImpl::FrameData* frame,
1170 DrawResult draw_result) override {
1171 if (host_impl->active_tree()->source_frame_number() == 2) {
1172 // Lose the context during draw on the second commit. This will cause
1173 // a third commit to recover.
1174 context3d_->set_times_bind_texture_succeeds(0);
1176 return draw_result;
1179 scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
1180 bool fallback) override {
1181 // This will get called twice:
1182 // First when we create the initial output surface...
1183 if (layer_tree_host()->source_frame_number() > 0) {
1184 // ... and then again after we forced the context to be lost.
1185 lost_context_ = true;
1187 return LayerTreeHostContextTest::CreateFakeOutputSurface(fallback);
1190 void DidCommitAndDrawFrame() override {
1191 ASSERT_TRUE(layer_tree_host()->hud_layer());
1192 // End the test once we know the 3nd frame drew.
1193 if (layer_tree_host()->source_frame_number() < 5) {
1194 layer_tree_host()->root_layer()->SetNeedsDisplay();
1195 layer_tree_host()->SetNeedsCommit();
1196 } else {
1197 EndTest();
1201 void AfterTest() override { EXPECT_TRUE(lost_context_); }
1203 private:
1204 FakeContentLayerClient client_;
1205 bool lost_context_;
1207 FakeOutputSurfaceClient output_surface_client_;
1208 scoped_ptr<FakeOutputSurface> child_output_surface_;
1209 scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
1210 scoped_ptr<ResourceProvider> child_resource_provider_;
1212 scoped_refptr<DelegatedFrameResourceCollection>
1213 delegated_resource_collection_;
1214 scoped_refptr<DelegatedFrameProvider> delegated_frame_provider_;
1216 scoped_refptr<VideoFrame> color_video_frame_;
1217 scoped_refptr<VideoFrame> hw_video_frame_;
1218 scoped_refptr<VideoFrame> scaled_hw_video_frame_;
1220 FakeVideoFrameProvider color_frame_provider_;
1221 FakeVideoFrameProvider hw_frame_provider_;
1222 FakeVideoFrameProvider scaled_hw_frame_provider_;
1225 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources);
1227 class ImplSidePaintingLayerTreeHostContextTest
1228 : public LayerTreeHostContextTest {
1229 public:
1230 void InitializeSettings(LayerTreeSettings* settings) override {
1231 settings->impl_side_painting = true;
1235 class LayerTreeHostContextTestImplSidePainting
1236 : public ImplSidePaintingLayerTreeHostContextTest {
1237 public:
1238 void SetupTree() override {
1239 scoped_refptr<Layer> root = Layer::Create();
1240 root->SetBounds(gfx::Size(10, 10));
1241 root->SetIsDrawable(true);
1243 scoped_refptr<PictureLayer> picture = PictureLayer::Create(&client_);
1244 picture->SetBounds(gfx::Size(10, 10));
1245 picture->SetIsDrawable(true);
1246 root->AddChild(picture);
1248 layer_tree_host()->SetRootLayer(root);
1249 LayerTreeHostContextTest::SetupTree();
1252 void BeginTest() override {
1253 times_to_lose_during_commit_ = 1;
1254 PostSetNeedsCommitToMainThread();
1257 void AfterTest() override {}
1259 void DidInitializeOutputSurface() override { EndTest(); }
1261 private:
1262 FakeContentLayerClient client_;
1265 MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting);
1267 class ScrollbarLayerLostContext : public LayerTreeHostContextTest {
1268 public:
1269 ScrollbarLayerLostContext() : commits_(0) {}
1271 void BeginTest() override {
1272 scoped_refptr<Layer> scroll_layer = Layer::Create();
1273 scrollbar_layer_ =
1274 FakePaintedScrollbarLayer::Create(false, true, scroll_layer->id());
1275 scrollbar_layer_->SetBounds(gfx::Size(10, 100));
1276 layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
1277 layer_tree_host()->root_layer()->AddChild(scroll_layer);
1278 PostSetNeedsCommitToMainThread();
1281 void AfterTest() override {}
1283 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
1284 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1286 ++commits_;
1287 switch (commits_) {
1288 case 1:
1289 // First (regular) update, we should upload 2 resources (thumb, and
1290 // backtrack).
1291 EXPECT_EQ(1, scrollbar_layer_->update_count());
1292 LoseContext();
1293 break;
1294 case 2:
1295 // Second update, after the lost context, we should still upload 2
1296 // resources even if the contents haven't changed.
1297 EXPECT_EQ(2, scrollbar_layer_->update_count());
1298 EndTest();
1299 break;
1300 default:
1301 NOTREACHED();
1305 private:
1306 int commits_;
1307 scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer_;
1310 SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext);
1312 class UIResourceLostTest : public LayerTreeHostContextTest {
1313 public:
1314 UIResourceLostTest() : time_step_(0) {}
1315 void InitializeSettings(LayerTreeSettings* settings) override {
1316 settings->renderer_settings.texture_id_allocation_chunk_size = 1;
1318 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
1319 void AfterTest() override {}
1321 // This is called on the main thread after each commit and
1322 // DidActivateTreeOnThread, with the value of time_step_ at the time
1323 // of the call to DidActivateTreeOnThread. Similar tests will do
1324 // work on the main thread in DidCommit but that is unsuitable because
1325 // the main thread work for these tests must happen after
1326 // DidActivateTreeOnThread, which happens after DidCommit with impl-side
1327 // painting.
1328 virtual void StepCompleteOnMainThread(int time_step) = 0;
1330 // Called after DidActivateTreeOnThread. If this is done during the commit,
1331 // the call to StepCompleteOnMainThread will not occur until after
1332 // the commit completes, because the main thread is blocked.
1333 void PostStepCompleteToMainThread() {
1334 proxy()->MainThreadTaskRunner()->PostTask(
1335 FROM_HERE,
1336 base::Bind(&UIResourceLostTest::StepCompleteOnMainThreadInternal,
1337 base::Unretained(this),
1338 time_step_));
1341 void PostLoseContextToImplThread() {
1342 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1343 ImplThreadTaskRunner()->PostTask(
1344 FROM_HERE,
1345 base::Bind(&LayerTreeHostContextTest::LoseContext,
1346 base::Unretained(this)));
1349 protected:
1350 int time_step_;
1351 scoped_ptr<FakeScopedUIResource> ui_resource_;
1353 private:
1354 void StepCompleteOnMainThreadInternal(int step) {
1355 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1356 StepCompleteOnMainThread(step);
1360 class UIResourceLostTestSimple : public UIResourceLostTest {
1361 public:
1362 // This is called when the commit is complete and the new layer tree has been
1363 // activated.
1364 virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) = 0;
1366 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
1367 if (!layer_tree_host()->settings().impl_side_painting) {
1368 StepCompleteOnImplThread(impl);
1369 PostStepCompleteToMainThread();
1370 ++time_step_;
1374 void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
1375 if (layer_tree_host()->settings().impl_side_painting) {
1376 StepCompleteOnImplThread(impl);
1377 PostStepCompleteToMainThread();
1378 ++time_step_;
1383 // Losing context after an UI resource has been created.
1384 class UIResourceLostAfterCommit : public UIResourceLostTestSimple {
1385 public:
1386 void StepCompleteOnMainThread(int step) override {
1387 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1388 switch (step) {
1389 case 0:
1390 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1391 // Expects a valid UIResourceId.
1392 EXPECT_NE(0, ui_resource_->id());
1393 PostSetNeedsCommitToMainThread();
1394 break;
1395 case 4:
1396 // Release resource before ending the test.
1397 ui_resource_ = nullptr;
1398 EndTest();
1399 break;
1400 case 5:
1401 NOTREACHED();
1402 break;
1406 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override {
1407 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1408 switch (time_step_) {
1409 case 1:
1410 // The resource should have been created on LTHI after the commit.
1411 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1412 PostSetNeedsCommitToMainThread();
1413 break;
1414 case 2:
1415 LoseContext();
1416 break;
1417 case 3:
1418 // The resources should have been recreated. The bitmap callback should
1419 // have been called once with the resource_lost flag set to true.
1420 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1421 // Resource Id on the impl-side have been recreated as well. Note
1422 // that the same UIResourceId persists after the context lost.
1423 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1424 PostSetNeedsCommitToMainThread();
1425 break;
1430 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostAfterCommit);
1432 // Losing context before UI resource requests can be commited. Three sequences
1433 // of creation/deletion are considered:
1434 // 1. Create one resource -> Context Lost => Expect the resource to have been
1435 // created.
1436 // 2. Delete an exisiting resource (test_id0_) -> create a second resource
1437 // (test_id1_) -> Context Lost => Expect the test_id0_ to be removed and
1438 // test_id1_ to have been created.
1439 // 3. Create one resource -> Delete that same resource -> Context Lost => Expect
1440 // the resource to not exist in the manager.
1441 class UIResourceLostBeforeCommit : public UIResourceLostTestSimple {
1442 public:
1443 UIResourceLostBeforeCommit() : test_id0_(0), test_id1_(0) {}
1445 void StepCompleteOnMainThread(int step) override {
1446 switch (step) {
1447 case 0:
1448 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1449 // Lose the context on the impl thread before the commit.
1450 PostLoseContextToImplThread();
1451 break;
1452 case 2:
1453 // Sequence 2:
1454 // Currently one resource has been created.
1455 test_id0_ = ui_resource_->id();
1456 // Delete this resource.
1457 ui_resource_ = nullptr;
1458 // Create another resource.
1459 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1460 test_id1_ = ui_resource_->id();
1461 // Sanity check that two resource creations return different ids.
1462 EXPECT_NE(test_id0_, test_id1_);
1463 // Lose the context on the impl thread before the commit.
1464 PostLoseContextToImplThread();
1465 break;
1466 case 3:
1467 // Clear the manager of resources.
1468 ui_resource_ = nullptr;
1469 PostSetNeedsCommitToMainThread();
1470 break;
1471 case 4:
1472 // Sequence 3:
1473 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1474 test_id0_ = ui_resource_->id();
1475 // Sanity check the UIResourceId should not be 0.
1476 EXPECT_NE(0, test_id0_);
1477 // Usually ScopedUIResource are deleted from the manager in their
1478 // destructor (so usually ui_resource_ = nullptr). But here we need
1479 // ui_resource_ for the next step, so call DeleteUIResource directly.
1480 layer_tree_host()->DeleteUIResource(test_id0_);
1481 // Delete the resouce and then lose the context.
1482 PostLoseContextToImplThread();
1483 break;
1484 case 5:
1485 // Release resource before ending the test.
1486 ui_resource_ = nullptr;
1487 EndTest();
1488 break;
1489 case 6:
1490 NOTREACHED();
1491 break;
1495 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override {
1496 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1497 switch (time_step_) {
1498 case 1:
1499 // Sequence 1 (continued):
1500 // The first context lost happens before the resources were created,
1501 // and because it resulted in no resources being destroyed, it does not
1502 // trigger resource re-creation.
1503 EXPECT_EQ(1, ui_resource_->resource_create_count);
1504 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1505 // Resource Id on the impl-side has been created.
1506 PostSetNeedsCommitToMainThread();
1507 break;
1508 case 3:
1509 // Sequence 2 (continued):
1510 // The previous resource should have been deleted.
1511 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
1512 // The second resource should have been created.
1513 EXPECT_NE(0u, impl->ResourceIdForUIResource(test_id1_));
1514 // The second resource called the resource callback once and since the
1515 // context is lost, a "resource lost" callback was also issued.
1516 EXPECT_EQ(2, ui_resource_->resource_create_count);
1517 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1518 break;
1519 case 5:
1520 // Sequence 3 (continued):
1521 // Expect the resource callback to have been called once.
1522 EXPECT_EQ(1, ui_resource_->resource_create_count);
1523 // No "resource lost" callbacks.
1524 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1525 // The UI resource id should not be valid
1526 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
1527 break;
1531 private:
1532 UIResourceId test_id0_;
1533 UIResourceId test_id1_;
1536 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeCommit);
1538 // Losing UI resource before the pending trees is activated but after the
1539 // commit. Impl-side-painting only.
1540 class UIResourceLostBeforeActivateTree : public UIResourceLostTest {
1541 void StepCompleteOnMainThread(int step) override {
1542 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1543 switch (step) {
1544 case 0:
1545 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1546 PostSetNeedsCommitToMainThread();
1547 break;
1548 case 3:
1549 test_id_ = ui_resource_->id();
1550 ui_resource_ = nullptr;
1551 PostSetNeedsCommitToMainThread();
1552 break;
1553 case 5:
1554 // Release resource before ending the test.
1555 ui_resource_ = nullptr;
1556 EndTest();
1557 break;
1558 case 6:
1559 // Make sure no extra commits happened.
1560 NOTREACHED();
1564 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
1565 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1566 switch (time_step_) {
1567 case 2:
1568 PostSetNeedsCommitToMainThread();
1569 break;
1570 case 4:
1571 PostSetNeedsCommitToMainThread();
1572 break;
1576 void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override {
1577 switch (time_step_) {
1578 case 1:
1579 // The resource creation callback has been called.
1580 EXPECT_EQ(1, ui_resource_->resource_create_count);
1581 // The resource is not yet lost (sanity check).
1582 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1583 // The resource should not have been created yet on the impl-side.
1584 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1585 LoseContext();
1586 break;
1587 case 3:
1588 LoseContext();
1589 break;
1593 void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
1594 LayerTreeHostContextTest::DidActivateTreeOnThread(impl);
1595 switch (time_step_) {
1596 case 1:
1597 // The pending requests on the impl-side should have been processed.
1598 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1599 break;
1600 case 2:
1601 // The "lost resource" callback should have been called once.
1602 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1603 break;
1604 case 4:
1605 // The resource is deleted and should not be in the manager. Use
1606 // test_id_ since ui_resource_ has been deleted.
1607 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id_));
1608 break;
1611 PostStepCompleteToMainThread();
1612 ++time_step_;
1615 private:
1616 UIResourceId test_id_;
1619 TEST_F(UIResourceLostBeforeActivateTree,
1620 RunMultiThread_DirectRenderer_ImplSidePaint) {
1621 RunTest(true, false, true);
1624 TEST_F(UIResourceLostBeforeActivateTree,
1625 RunMultiThread_DelegatingRenderer_ImplSidePaint) {
1626 RunTest(true, true, true);
1629 // Resources evicted explicitly and by visibility changes.
1630 class UIResourceLostEviction : public UIResourceLostTestSimple {
1631 public:
1632 void StepCompleteOnMainThread(int step) override {
1633 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1634 switch (step) {
1635 case 0:
1636 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1637 EXPECT_NE(0, ui_resource_->id());
1638 PostSetNeedsCommitToMainThread();
1639 break;
1640 case 2:
1641 // Make the tree not visible.
1642 PostSetVisibleToMainThread(false);
1643 break;
1644 case 3:
1645 // Release resource before ending the test.
1646 ui_resource_ = nullptr;
1647 EndTest();
1648 break;
1649 case 4:
1650 NOTREACHED();
1654 void DidSetVisibleOnImplTree(LayerTreeHostImpl* impl, bool visible) override {
1655 TestWebGraphicsContext3D* context = TestContext();
1656 if (!visible) {
1657 // All resources should have been evicted.
1658 ASSERT_EQ(0u, context->NumTextures());
1659 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1660 EXPECT_EQ(2, ui_resource_->resource_create_count);
1661 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1662 // Drawing is disabled both because of the evicted resources and
1663 // because the renderer is not visible.
1664 EXPECT_FALSE(impl->CanDraw());
1665 // Make the renderer visible again.
1666 PostSetVisibleToMainThread(true);
1670 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override {
1671 TestWebGraphicsContext3D* context = TestContext();
1672 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1673 switch (time_step_) {
1674 case 1:
1675 // The resource should have been created on LTHI after the commit.
1676 ASSERT_EQ(1u, context->NumTextures());
1677 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1678 EXPECT_EQ(1, ui_resource_->resource_create_count);
1679 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1680 EXPECT_TRUE(impl->CanDraw());
1681 // Evict all UI resources. This will trigger a commit.
1682 impl->EvictAllUIResources();
1683 ASSERT_EQ(0u, context->NumTextures());
1684 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1685 EXPECT_EQ(1, ui_resource_->resource_create_count);
1686 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1687 EXPECT_FALSE(impl->CanDraw());
1688 break;
1689 case 2:
1690 // The resource should have been recreated.
1691 ASSERT_EQ(1u, context->NumTextures());
1692 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1693 EXPECT_EQ(2, ui_resource_->resource_create_count);
1694 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1695 EXPECT_TRUE(impl->CanDraw());
1696 break;
1697 case 3:
1698 // The resource should have been recreated after visibility was
1699 // restored.
1700 ASSERT_EQ(1u, context->NumTextures());
1701 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1702 EXPECT_EQ(3, ui_resource_->resource_create_count);
1703 EXPECT_EQ(2, ui_resource_->lost_resource_count);
1704 EXPECT_TRUE(impl->CanDraw());
1705 break;
1710 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction);
1712 class LayerTreeHostContextTestSurfaceCreateCallback
1713 : public LayerTreeHostContextTest {
1714 public:
1715 LayerTreeHostContextTestSurfaceCreateCallback()
1716 : LayerTreeHostContextTest() {}
1718 void SetupTree() override {
1719 if (layer_tree_host()->settings().impl_side_painting) {
1720 picture_layer_ = FakePictureLayer::Create(&client_);
1721 picture_layer_->SetBounds(gfx::Size(10, 20));
1722 layer_tree_host()->SetRootLayer(picture_layer_);
1723 } else {
1724 content_layer_ = FakeContentLayer::Create(&client_);
1725 content_layer_->SetBounds(gfx::Size(10, 20));
1726 layer_tree_host()->SetRootLayer(content_layer_);
1729 LayerTreeHostContextTest::SetupTree();
1732 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
1734 void DidCommit() override {
1735 switch (layer_tree_host()->source_frame_number()) {
1736 case 1:
1737 if (layer_tree_host()->settings().impl_side_painting)
1738 EXPECT_EQ(1u, picture_layer_->output_surface_created_count());
1739 else
1740 EXPECT_EQ(1u, content_layer_->output_surface_created_count());
1741 layer_tree_host()->SetNeedsCommit();
1742 break;
1743 case 2:
1744 if (layer_tree_host()->settings().impl_side_painting)
1745 EXPECT_EQ(1u, picture_layer_->output_surface_created_count());
1746 else
1747 EXPECT_EQ(1u, content_layer_->output_surface_created_count());
1748 layer_tree_host()->SetNeedsCommit();
1749 break;
1750 case 3:
1751 if (layer_tree_host()->settings().impl_side_painting)
1752 EXPECT_EQ(1u, picture_layer_->output_surface_created_count());
1753 else
1754 EXPECT_EQ(1u, content_layer_->output_surface_created_count());
1755 break;
1756 case 4:
1757 if (layer_tree_host()->settings().impl_side_painting)
1758 EXPECT_EQ(2u, picture_layer_->output_surface_created_count());
1759 else
1760 EXPECT_EQ(2u, content_layer_->output_surface_created_count());
1761 layer_tree_host()->SetNeedsCommit();
1762 break;
1766 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
1767 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1768 switch (LastCommittedSourceFrameNumber(impl)) {
1769 case 0:
1770 break;
1771 case 1:
1772 break;
1773 case 2:
1774 LoseContext();
1775 break;
1776 case 3:
1777 EndTest();
1778 break;
1782 void AfterTest() override {}
1784 protected:
1785 FakeContentLayerClient client_;
1786 scoped_refptr<FakePictureLayer> picture_layer_;
1787 scoped_refptr<FakeContentLayer> content_layer_;
1790 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestSurfaceCreateCallback);
1792 class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame
1793 : public LayerTreeHostContextTest {
1794 protected:
1795 void BeginTest() override {
1796 deferred_ = false;
1797 PostSetNeedsCommitToMainThread();
1800 void ScheduledActionWillSendBeginMainFrame() override {
1801 if (deferred_)
1802 return;
1803 deferred_ = true;
1805 // Defer commits before the BeginFrame arrives, causing it to be delayed.
1806 MainThreadTaskRunner()->PostTask(
1807 FROM_HERE,
1808 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1809 DeferCommitsOnMainThread,
1810 base::Unretained(this),
1811 true));
1812 // Meanwhile, lose the context while we are in defer commits.
1813 ImplThreadTaskRunner()->PostTask(
1814 FROM_HERE,
1815 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1816 LoseContextOnImplThread,
1817 base::Unretained(this)));
1820 void LoseContextOnImplThread() {
1821 LoseContext();
1823 // After losing the context, stop deferring commits.
1824 MainThreadTaskRunner()->PostTask(
1825 FROM_HERE,
1826 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1827 DeferCommitsOnMainThread,
1828 base::Unretained(this),
1829 false));
1832 void DeferCommitsOnMainThread(bool defer_commits) {
1833 layer_tree_host()->SetDeferCommits(defer_commits);
1836 void WillBeginMainFrame() override {
1837 // Don't begin a frame with a lost surface.
1838 EXPECT_FALSE(layer_tree_host()->output_surface_lost());
1841 void DidCommitAndDrawFrame() override { EndTest(); }
1843 void AfterTest() override {}
1845 bool deferred_;
1848 SINGLE_AND_MULTI_THREAD_TEST_F(
1849 LayerTreeHostContextTestLoseAfterSendingBeginMainFrame);
1851 } // namespace
1852 } // namespace cc