Adding Peter Thatcher to the owners file.
[chromium-blink-merge.git] / cc / trees / layer_tree_host_unittest_context.cc
blob8b09054894341ee5995163ffbd2d9d39c481c9c7
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(host_impl->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 // This test makes sure that once a SingleThreadProxy issues a
415 // DidFailToInitializeOutputSurface, that future Composite calls will not
416 // trigger additional requests for output surfaces.
417 class FailedCreateDoesNotCreateExtraOutputSurface
418 : public LayerTreeHostContextTest {
419 public:
420 FailedCreateDoesNotCreateExtraOutputSurface()
421 : LayerTreeHostContextTest(), num_requests_(0), has_failed_(false) {}
423 void InitializeSettings(LayerTreeSettings* settings) override {
424 settings->single_thread_proxy_scheduler = false;
427 void RequestNewOutputSurface() override {
428 num_requests_++;
429 // There should be one initial request and then one request from
430 // the LayerTreeTest test hooks DidFailToInitializeOutputSurface (which is
431 // hard to skip). This second request is just ignored and is test cruft.
432 EXPECT_LE(num_requests_, 2);
433 if (num_requests_ > 1)
434 return;
435 ExpectCreateToFail();
436 layer_tree_host()->SetOutputSurface(
437 make_scoped_ptr(new FailureOutputSurface(false)));
440 void BeginTest() override {
441 // First composite tries to create a surface.
442 layer_tree_host()->Composite(base::TimeTicks());
443 EXPECT_EQ(num_requests_, 2);
444 EXPECT_TRUE(has_failed_);
446 // Second composite should not request or fail.
447 layer_tree_host()->Composite(base::TimeTicks());
448 EXPECT_EQ(num_requests_, 2);
449 EndTest();
452 void DidInitializeOutputSurface() override { EXPECT_TRUE(false); }
454 void DidFailToInitializeOutputSurface() override {
455 LayerTreeHostContextTest::DidFailToInitializeOutputSurface();
456 EXPECT_FALSE(has_failed_);
457 has_failed_ = true;
460 void AfterTest() override {}
462 int num_requests_;
463 bool has_failed_;
466 SINGLE_THREAD_NOIMPL_TEST_F(FailedCreateDoesNotCreateExtraOutputSurface);
468 class LayerTreeHostContextTestCommitAfterDelayedOutputSurface
469 : public LayerTreeHostContextTest {
470 public:
471 LayerTreeHostContextTestCommitAfterDelayedOutputSurface()
472 : LayerTreeHostContextTest(), creating_output_(false) {}
474 void InitializeSettings(LayerTreeSettings* settings) override {
475 settings->single_thread_proxy_scheduler = false;
478 void RequestNewOutputSurface() override {
479 MainThreadTaskRunner()->PostTask(
480 FROM_HERE,
481 base::Bind(&LayerTreeHostContextTestCommitAfterDelayedOutputSurface::
482 CreateAndSetOutputSurface,
483 base::Unretained(this)));
486 void CreateAndSetOutputSurface() {
487 creating_output_ = true;
488 layer_tree_host()->SetOutputSurface(
489 LayerTreeHostContextTest::CreateOutputSurface());
492 void BeginTest() override { layer_tree_host()->Composite(base::TimeTicks()); }
494 void ScheduleComposite() override {
495 if (creating_output_)
496 EndTest();
499 void AfterTest() override {}
501 bool creating_output_;
504 SINGLE_THREAD_NOIMPL_TEST_F(
505 LayerTreeHostContextTestCommitAfterDelayedOutputSurface);
507 class LayerTreeHostContextTestAvoidUnnecessaryComposite
508 : public LayerTreeHostContextTest {
509 public:
510 LayerTreeHostContextTestAvoidUnnecessaryComposite()
511 : LayerTreeHostContextTest(), in_composite_(false) {}
513 void InitializeSettings(LayerTreeSettings* settings) override {
514 settings->single_thread_proxy_scheduler = false;
517 void RequestNewOutputSurface() override {
518 layer_tree_host()->SetOutputSurface(
519 LayerTreeHostContextTest::CreateOutputSurface());
520 EndTest();
523 void BeginTest() override {
524 in_composite_ = true;
525 layer_tree_host()->Composite(base::TimeTicks());
526 in_composite_ = false;
529 void ScheduleComposite() override { EXPECT_FALSE(in_composite_); }
531 void AfterTest() override {}
533 bool in_composite_;
536 SINGLE_THREAD_NOIMPL_TEST_F(LayerTreeHostContextTestAvoidUnnecessaryComposite);
538 class LayerTreeHostContextTestLostContextSucceedsWithContent
539 : public LayerTreeHostContextTestLostContextSucceeds {
540 public:
541 void SetupTree() override {
542 root_ = Layer::Create();
543 root_->SetBounds(gfx::Size(10, 10));
544 root_->SetIsDrawable(true);
546 // Paint non-solid color.
547 SkPaint paint;
548 paint.setColor(SkColorSetARGB(100, 80, 200, 200));
549 client_.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint);
551 if (layer_tree_host()->settings().impl_side_painting)
552 layer_ = FakePictureLayer::Create(&client_);
553 else
554 layer_ = FakeContentLayer::Create(&client_);
555 layer_->SetBounds(gfx::Size(10, 10));
556 layer_->SetIsDrawable(true);
558 root_->AddChild(layer_);
560 layer_tree_host()->SetRootLayer(root_);
561 LayerTreeHostContextTest::SetupTree();
564 void InvalidateAndSetNeedsCommit() override {
565 // Invalidate the render surface so we don't try to use a cached copy of the
566 // surface. We want to make sure to test the drawing paths for drawing to
567 // a child surface.
568 layer_->SetNeedsDisplay();
569 LayerTreeHostContextTestLostContextSucceeds::InvalidateAndSetNeedsCommit();
572 void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
573 if (!host_impl->settings().impl_side_painting) {
574 FakeContentLayerImpl* content_impl = static_cast<FakeContentLayerImpl*>(
575 host_impl->active_tree()->root_layer()->children()[0]);
576 // Even though the context was lost, we should have a resource. The
577 // TestWebGraphicsContext3D ensures that this resource is created with
578 // the active context.
579 EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0));
580 } else {
581 FakePictureLayerImpl* picture_impl = static_cast<FakePictureLayerImpl*>(
582 host_impl->active_tree()->root_layer()->children()[0]);
583 EXPECT_TRUE(picture_impl->HighResTiling()->TileAt(0, 0)->IsReadyToDraw());
587 protected:
588 FakeContentLayerClient client_;
589 scoped_refptr<Layer> root_;
590 scoped_refptr<Layer> layer_;
593 // This test uses TiledLayer and PictureLayer to check for a working context.
594 SINGLE_AND_MULTI_THREAD_TEST_F(
595 LayerTreeHostContextTestLostContextSucceedsWithContent);
597 class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
598 : public LayerTreeHostContextTest {
599 public:
600 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
601 : times_to_fail_(1), times_initialized_(0) {
602 times_to_fail_create_ = times_to_fail_;
605 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
607 void DidInitializeOutputSurface() override { times_initialized_++; }
609 void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { EndTest(); }
611 void AfterTest() override {
612 EXPECT_EQ(times_to_fail_, times_create_failed_);
613 EXPECT_NE(0, times_initialized_);
616 private:
617 int times_to_fail_;
618 int times_initialized_;
621 SINGLE_AND_MULTI_THREAD_TEST_F(
622 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce);
624 class LayerTreeHostContextTestLostContextAndEvictTextures
625 : public LayerTreeHostContextTest {
626 public:
627 LayerTreeHostContextTestLostContextAndEvictTextures()
628 : LayerTreeHostContextTest(),
629 impl_host_(0),
630 num_commits_(0),
631 lost_context_(false) {}
633 void SetupTree() override {
634 // Paint non-solid color.
635 SkPaint paint;
636 paint.setColor(SkColorSetARGB(100, 80, 200, 200));
637 client_.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint);
639 if (layer_tree_host()->settings().impl_side_painting) {
640 picture_layer_ = FakePictureLayer::Create(&client_);
641 picture_layer_->SetBounds(gfx::Size(10, 20));
642 layer_tree_host()->SetRootLayer(picture_layer_);
643 } else {
644 content_layer_ = FakeContentLayer::Create(&client_);
645 content_layer_->SetBounds(gfx::Size(10, 20));
646 layer_tree_host()->SetRootLayer(content_layer_);
649 LayerTreeHostContextTest::SetupTree();
652 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
654 void PostEvictTextures() {
655 if (HasImplThread()) {
656 ImplThreadTaskRunner()->PostTask(
657 FROM_HERE,
658 base::Bind(&LayerTreeHostContextTestLostContextAndEvictTextures::
659 EvictTexturesOnImplThread,
660 base::Unretained(this)));
661 } else {
662 DebugScopedSetImplThread impl(proxy());
663 EvictTexturesOnImplThread();
667 void EvictTexturesOnImplThread() {
668 impl_host_->EvictTexturesForTesting();
670 if (lose_after_evict_) {
671 LoseContext();
672 lost_context_ = true;
676 void DidCommitAndDrawFrame() override {
677 if (num_commits_ > 1)
678 return;
679 if (!layer_tree_host()->settings().impl_side_painting) {
680 EXPECT_TRUE(content_layer_->HaveBackingAt(0, 0));
682 PostEvictTextures();
685 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
686 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
687 if (num_commits_ > 1)
688 return;
689 ++num_commits_;
690 if (!lose_after_evict_) {
691 LoseContext();
692 lost_context_ = true;
696 void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
697 if (impl->settings().impl_side_painting) {
698 FakePictureLayerImpl* picture_impl =
699 static_cast<FakePictureLayerImpl*>(impl->active_tree()->root_layer());
700 EXPECT_TRUE(picture_impl->HighResTiling()->TileAt(0, 0)->IsReadyToDraw());
701 } else {
702 FakeContentLayerImpl* content_impl =
703 static_cast<FakeContentLayerImpl*>(impl->active_tree()->root_layer());
704 EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0));
707 impl_host_ = impl;
708 if (lost_context_)
709 EndTest();
712 void DidInitializeOutputSurface() override {}
714 void AfterTest() override {}
716 protected:
717 bool lose_after_evict_;
718 FakeContentLayerClient client_;
719 scoped_refptr<FakeContentLayer> content_layer_;
720 scoped_refptr<FakePictureLayer> picture_layer_;
721 LayerTreeHostImpl* impl_host_;
722 int num_commits_;
723 bool lost_context_;
726 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
727 LoseAfterEvict_SingleThread_DirectRenderer) {
728 lose_after_evict_ = true;
729 RunTest(false, false, false);
732 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
733 LoseAfterEvict_SingleThread_DelegatingRenderer) {
734 lose_after_evict_ = true;
735 RunTest(false, true, false);
738 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
739 LoseAfterEvict_MultiThread_DirectRenderer_MainThreadPaint) {
740 lose_after_evict_ = true;
741 RunTest(true, false, false);
744 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
745 LoseAfterEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
746 lose_after_evict_ = true;
747 RunTest(true, true, false);
750 // Flaky on all platforms, http://crbug.com/310979
751 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
752 DISABLED_LoseAfterEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
753 lose_after_evict_ = true;
754 RunTest(true, true, true);
757 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
758 LoseBeforeEvict_SingleThread_DirectRenderer) {
759 lose_after_evict_ = false;
760 RunTest(false, false, false);
763 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
764 LoseBeforeEvict_SingleThread_DelegatingRenderer) {
765 lose_after_evict_ = false;
766 RunTest(false, true, false);
769 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
770 LoseBeforeEvict_MultiThread_DirectRenderer_MainThreadPaint) {
771 lose_after_evict_ = false;
772 RunTest(true, false, false);
775 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
776 LoseBeforeEvict_MultiThread_DirectRenderer_ImplSidePaint) {
777 lose_after_evict_ = false;
778 RunTest(true, false, true);
781 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
782 LoseBeforeEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
783 lose_after_evict_ = false;
784 RunTest(true, true, false);
787 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
788 LoseBeforeEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
789 lose_after_evict_ = false;
790 RunTest(true, true, true);
793 class LayerTreeHostContextTestLostContextWhileUpdatingResources
794 : public LayerTreeHostContextTest {
795 public:
796 LayerTreeHostContextTestLostContextWhileUpdatingResources()
797 : num_children_(50), times_to_lose_on_end_query_(3) {}
799 scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() override {
800 scoped_ptr<TestWebGraphicsContext3D> context =
801 LayerTreeHostContextTest::CreateContext3d();
802 if (times_to_lose_on_end_query_) {
803 --times_to_lose_on_end_query_;
804 context->set_times_end_query_succeeds(5);
806 return context.Pass();
809 void SetupTree() override {
810 if (layer_tree_host()->settings().impl_side_painting)
811 parent_ = FakePictureLayer::Create(&client_);
812 else
813 parent_ = FakeContentLayer::Create(&client_);
815 parent_->SetBounds(gfx::Size(num_children_, 1));
817 for (int i = 0; i < num_children_; i++) {
818 scoped_refptr<Layer> child;
819 if (layer_tree_host()->settings().impl_side_painting)
820 child = FakePictureLayer::Create(&client_);
821 else
822 child = FakeContentLayer::Create(&client_);
823 child->SetPosition(gfx::PointF(i, 0.f));
824 child->SetBounds(gfx::Size(1, 1));
825 parent_->AddChild(child);
828 layer_tree_host()->SetRootLayer(parent_);
829 LayerTreeHostContextTest::SetupTree();
832 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
834 void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
835 EXPECT_EQ(0, times_to_lose_on_end_query_);
836 EndTest();
839 void AfterTest() override { EXPECT_EQ(0, times_to_lose_on_end_query_); }
841 private:
842 FakeContentLayerClient client_;
843 scoped_refptr<Layer> parent_;
844 int num_children_;
845 int times_to_lose_on_end_query_;
848 SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
849 LayerTreeHostContextTestLostContextWhileUpdatingResources);
851 class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
852 public:
853 LayerTreeHostContextTestLayersNotified()
854 : LayerTreeHostContextTest(), num_commits_(0) {}
856 void SetupTree() override {
857 if (layer_tree_host()->settings().impl_side_painting) {
858 root_ = FakePictureLayer::Create(&client_);
859 child_ = FakePictureLayer::Create(&client_);
860 grandchild_ = FakePictureLayer::Create(&client_);
861 } else {
862 root_ = FakeContentLayer::Create(&client_);
863 child_ = FakeContentLayer::Create(&client_);
864 grandchild_ = FakeContentLayer::Create(&client_);
867 root_->AddChild(child_);
868 child_->AddChild(grandchild_);
870 layer_tree_host()->SetRootLayer(root_);
871 LayerTreeHostContextTest::SetupTree();
874 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
876 void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
877 LayerTreeHostContextTest::DidActivateTreeOnThread(host_impl);
879 FakePictureLayerImpl* root_picture = NULL;
880 FakePictureLayerImpl* child_picture = NULL;
881 FakePictureLayerImpl* grandchild_picture = NULL;
882 FakeContentLayerImpl* root_content = NULL;
883 FakeContentLayerImpl* child_content = NULL;
884 FakeContentLayerImpl* grandchild_content = NULL;
886 if (host_impl->settings().impl_side_painting) {
887 root_picture = static_cast<FakePictureLayerImpl*>(
888 host_impl->active_tree()->root_layer());
889 child_picture =
890 static_cast<FakePictureLayerImpl*>(root_picture->children()[0]);
891 grandchild_picture =
892 static_cast<FakePictureLayerImpl*>(child_picture->children()[0]);
894 } else {
895 root_content = static_cast<FakeContentLayerImpl*>(
896 host_impl->active_tree()->root_layer());
897 child_content =
898 static_cast<FakeContentLayerImpl*>(root_content->children()[0]);
899 grandchild_content =
900 static_cast<FakeContentLayerImpl*>(child_content->children()[0]);
903 ++num_commits_;
904 switch (num_commits_) {
905 case 1:
906 if (host_impl->settings().impl_side_painting) {
907 EXPECT_EQ(0u, root_picture->release_resources_count());
908 EXPECT_EQ(0u, child_picture->release_resources_count());
909 EXPECT_EQ(0u, grandchild_picture->release_resources_count());
910 } else {
911 EXPECT_EQ(0u, root_content->lost_output_surface_count());
912 EXPECT_EQ(0u, child_content->lost_output_surface_count());
913 EXPECT_EQ(0u, grandchild_content->lost_output_surface_count());
916 // Lose the context and struggle to recreate it.
917 LoseContext();
918 times_to_fail_create_ = 1;
919 break;
920 case 2:
921 if (host_impl->settings().impl_side_painting) {
922 EXPECT_TRUE(root_picture->release_resources_count());
923 EXPECT_TRUE(child_picture->release_resources_count());
924 EXPECT_TRUE(grandchild_picture->release_resources_count());
925 } else {
926 EXPECT_TRUE(root_content->lost_output_surface_count());
927 EXPECT_TRUE(child_content->lost_output_surface_count());
928 EXPECT_TRUE(grandchild_content->lost_output_surface_count());
931 EndTest();
932 break;
933 default:
934 NOTREACHED();
938 void AfterTest() override {}
940 private:
941 int num_commits_;
943 FakeContentLayerClient client_;
944 scoped_refptr<Layer> root_;
945 scoped_refptr<Layer> child_;
946 scoped_refptr<Layer> grandchild_;
949 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified);
951 class LayerTreeHostContextTestDontUseLostResources
952 : public LayerTreeHostContextTest {
953 public:
954 LayerTreeHostContextTestDontUseLostResources() : lost_context_(false) {
955 context_should_support_io_surface_ = true;
957 child_output_surface_ = FakeOutputSurface::Create3d();
958 child_output_surface_->BindToClient(&output_surface_client_);
959 shared_bitmap_manager_.reset(new TestSharedBitmapManager());
960 child_resource_provider_ =
961 ResourceProvider::Create(child_output_surface_.get(),
962 shared_bitmap_manager_.get(),
963 NULL,
964 NULL,
966 false,
970 static void EmptyReleaseCallback(unsigned sync_point, bool lost) {}
972 void SetupTree() override {
973 gpu::gles2::GLES2Interface* gl =
974 child_output_surface_->context_provider()->ContextGL();
976 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
978 scoped_ptr<TestRenderPass> pass_for_quad = TestRenderPass::Create();
979 pass_for_quad->SetNew(
980 // AppendOneOfEveryQuadType() makes a RenderPass quad with this id.
981 RenderPassId(2, 1),
982 gfx::Rect(0, 0, 10, 10),
983 gfx::Rect(0, 0, 10, 10),
984 gfx::Transform());
986 scoped_ptr<TestRenderPass> pass = TestRenderPass::Create();
987 pass->SetNew(RenderPassId(1, 1),
988 gfx::Rect(0, 0, 10, 10),
989 gfx::Rect(0, 0, 10, 10),
990 gfx::Transform());
991 pass->AppendOneOfEveryQuadType(child_resource_provider_.get(),
992 RenderPassId(2, 1));
994 frame_data->render_pass_list.push_back(pass_for_quad.Pass());
995 frame_data->render_pass_list.push_back(pass.Pass());
997 delegated_resource_collection_ = new DelegatedFrameResourceCollection;
998 delegated_frame_provider_ = new DelegatedFrameProvider(
999 delegated_resource_collection_.get(), frame_data.Pass());
1001 ResourceProvider::ResourceId resource =
1002 child_resource_provider_->CreateResource(
1003 gfx::Size(4, 4), GL_CLAMP_TO_EDGE,
1004 ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
1005 ResourceProvider::ScopedWriteLockGL lock(child_resource_provider_.get(),
1006 resource);
1008 gpu::Mailbox mailbox;
1009 gl->GenMailboxCHROMIUM(mailbox.name);
1010 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1012 scoped_refptr<Layer> root = Layer::Create();
1013 root->SetBounds(gfx::Size(10, 10));
1014 root->SetIsDrawable(true);
1016 scoped_refptr<FakeDelegatedRendererLayer> delegated =
1017 FakeDelegatedRendererLayer::Create(delegated_frame_provider_.get());
1018 delegated->SetBounds(gfx::Size(10, 10));
1019 delegated->SetIsDrawable(true);
1020 root->AddChild(delegated);
1022 scoped_refptr<Layer> layer;
1023 if (layer_tree_host()->settings().impl_side_painting)
1024 layer = PictureLayer::Create(&client_);
1025 else
1026 layer = ContentLayer::Create(&client_);
1027 layer->SetBounds(gfx::Size(10, 10));
1028 layer->SetIsDrawable(true);
1029 root->AddChild(layer);
1031 scoped_refptr<TextureLayer> texture = TextureLayer::CreateForMailbox(NULL);
1032 texture->SetBounds(gfx::Size(10, 10));
1033 texture->SetIsDrawable(true);
1034 texture->SetTextureMailbox(
1035 TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point),
1036 SingleReleaseCallback::Create(
1037 base::Bind(&LayerTreeHostContextTestDontUseLostResources::
1038 EmptyReleaseCallback)));
1039 root->AddChild(texture);
1041 scoped_refptr<Layer> mask;
1042 if (layer_tree_host()->settings().impl_side_painting)
1043 mask = PictureLayer::Create(&client_);
1044 else
1045 mask = ContentLayer::Create(&client_);
1046 mask->SetBounds(gfx::Size(10, 10));
1048 scoped_refptr<Layer> layer_with_mask;
1049 if (layer_tree_host()->settings().impl_side_painting)
1050 layer_with_mask = PictureLayer::Create(&client_);
1051 else
1052 layer_with_mask = ContentLayer::Create(&client_);
1053 layer_with_mask->SetBounds(gfx::Size(10, 10));
1054 layer_with_mask->SetIsDrawable(true);
1055 layer_with_mask->SetMaskLayer(mask.get());
1056 root->AddChild(layer_with_mask);
1058 scoped_refptr<VideoLayer> video_color =
1059 VideoLayer::Create(&color_frame_provider_, media::VIDEO_ROTATION_0);
1060 video_color->SetBounds(gfx::Size(10, 10));
1061 video_color->SetIsDrawable(true);
1062 root->AddChild(video_color);
1064 scoped_refptr<VideoLayer> video_hw =
1065 VideoLayer::Create(&hw_frame_provider_, media::VIDEO_ROTATION_0);
1066 video_hw->SetBounds(gfx::Size(10, 10));
1067 video_hw->SetIsDrawable(true);
1068 root->AddChild(video_hw);
1070 scoped_refptr<VideoLayer> video_scaled_hw =
1071 VideoLayer::Create(&scaled_hw_frame_provider_, media::VIDEO_ROTATION_0);
1072 video_scaled_hw->SetBounds(gfx::Size(10, 10));
1073 video_scaled_hw->SetIsDrawable(true);
1074 root->AddChild(video_scaled_hw);
1076 color_video_frame_ = VideoFrame::CreateColorFrame(
1077 gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
1078 hw_video_frame_ = VideoFrame::WrapNativeTexture(
1079 make_scoped_ptr(
1080 new gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, sync_point)),
1081 media::VideoFrame::ReleaseMailboxCB(), gfx::Size(4, 4),
1082 gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4), base::TimeDelta(), false);
1083 scaled_hw_video_frame_ = VideoFrame::WrapNativeTexture(
1084 make_scoped_ptr(
1085 new gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, sync_point)),
1086 media::VideoFrame::ReleaseMailboxCB(), gfx::Size(4, 4),
1087 gfx::Rect(0, 0, 3, 2), gfx::Size(4, 4), base::TimeDelta(), false);
1089 color_frame_provider_.set_frame(color_video_frame_);
1090 hw_frame_provider_.set_frame(hw_video_frame_);
1091 scaled_hw_frame_provider_.set_frame(scaled_hw_video_frame_);
1093 if (!delegating_renderer()) {
1094 // TODO(danakj): IOSurface layer can not be transported. crbug.com/239335
1095 scoped_refptr<IOSurfaceLayer> io_surface = IOSurfaceLayer::Create();
1096 io_surface->SetBounds(gfx::Size(10, 10));
1097 io_surface->SetIsDrawable(true);
1098 io_surface->SetIOSurfaceProperties(1, gfx::Size(10, 10));
1099 root->AddChild(io_surface);
1102 // Enable the hud.
1103 LayerTreeDebugState debug_state;
1104 debug_state.show_property_changed_rects = true;
1105 layer_tree_host()->SetDebugState(debug_state);
1107 scoped_refptr<PaintedScrollbarLayer> scrollbar =
1108 PaintedScrollbarLayer::Create(
1109 scoped_ptr<Scrollbar>(new FakeScrollbar).Pass(), layer->id());
1110 scrollbar->SetBounds(gfx::Size(10, 10));
1111 scrollbar->SetIsDrawable(true);
1112 root->AddChild(scrollbar);
1114 layer_tree_host()->SetRootLayer(root);
1115 LayerTreeHostContextTest::SetupTree();
1118 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
1120 void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
1121 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
1123 if (host_impl->active_tree()->source_frame_number() == 3) {
1124 // On the third commit we're recovering from context loss. Hardware
1125 // video frames should not be reused by the VideoFrameProvider, but
1126 // software frames can be.
1127 hw_frame_provider_.set_frame(NULL);
1128 scaled_hw_frame_provider_.set_frame(NULL);
1132 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
1133 LayerTreeHostImpl::FrameData* frame,
1134 DrawResult draw_result) override {
1135 if (host_impl->active_tree()->source_frame_number() == 2) {
1136 // Lose the context during draw on the second commit. This will cause
1137 // a third commit to recover.
1138 context3d_->set_times_bind_texture_succeeds(0);
1140 return draw_result;
1143 scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
1144 // This will get called twice:
1145 // First when we create the initial output surface...
1146 if (layer_tree_host()->source_frame_number() > 0) {
1147 // ... and then again after we forced the context to be lost.
1148 lost_context_ = true;
1150 return LayerTreeHostContextTest::CreateFakeOutputSurface();
1153 void DidCommitAndDrawFrame() override {
1154 ASSERT_TRUE(layer_tree_host()->hud_layer());
1155 // End the test once we know the 3nd frame drew.
1156 if (layer_tree_host()->source_frame_number() < 5) {
1157 layer_tree_host()->root_layer()->SetNeedsDisplay();
1158 layer_tree_host()->SetNeedsCommit();
1159 } else {
1160 EndTest();
1164 void AfterTest() override { EXPECT_TRUE(lost_context_); }
1166 private:
1167 FakeContentLayerClient client_;
1168 bool lost_context_;
1170 FakeOutputSurfaceClient output_surface_client_;
1171 scoped_ptr<FakeOutputSurface> child_output_surface_;
1172 scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
1173 scoped_ptr<ResourceProvider> child_resource_provider_;
1175 scoped_refptr<DelegatedFrameResourceCollection>
1176 delegated_resource_collection_;
1177 scoped_refptr<DelegatedFrameProvider> delegated_frame_provider_;
1179 scoped_refptr<VideoFrame> color_video_frame_;
1180 scoped_refptr<VideoFrame> hw_video_frame_;
1181 scoped_refptr<VideoFrame> scaled_hw_video_frame_;
1183 FakeVideoFrameProvider color_frame_provider_;
1184 FakeVideoFrameProvider hw_frame_provider_;
1185 FakeVideoFrameProvider scaled_hw_frame_provider_;
1188 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources);
1190 class ImplSidePaintingLayerTreeHostContextTest
1191 : public LayerTreeHostContextTest {
1192 public:
1193 void InitializeSettings(LayerTreeSettings* settings) override {
1194 settings->impl_side_painting = true;
1198 class LayerTreeHostContextTestImplSidePainting
1199 : public ImplSidePaintingLayerTreeHostContextTest {
1200 public:
1201 void SetupTree() override {
1202 scoped_refptr<Layer> root = Layer::Create();
1203 root->SetBounds(gfx::Size(10, 10));
1204 root->SetIsDrawable(true);
1206 scoped_refptr<PictureLayer> picture = PictureLayer::Create(&client_);
1207 picture->SetBounds(gfx::Size(10, 10));
1208 picture->SetIsDrawable(true);
1209 root->AddChild(picture);
1211 layer_tree_host()->SetRootLayer(root);
1212 LayerTreeHostContextTest::SetupTree();
1215 void BeginTest() override {
1216 times_to_lose_during_commit_ = 1;
1217 PostSetNeedsCommitToMainThread();
1220 void AfterTest() override {}
1222 void DidInitializeOutputSurface() override { EndTest(); }
1224 private:
1225 FakeContentLayerClient client_;
1228 MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting);
1230 class ScrollbarLayerLostContext : public LayerTreeHostContextTest {
1231 public:
1232 ScrollbarLayerLostContext() : commits_(0) {}
1234 void BeginTest() override {
1235 scoped_refptr<Layer> scroll_layer = Layer::Create();
1236 scrollbar_layer_ =
1237 FakePaintedScrollbarLayer::Create(false, true, scroll_layer->id());
1238 scrollbar_layer_->SetBounds(gfx::Size(10, 100));
1239 layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
1240 layer_tree_host()->root_layer()->AddChild(scroll_layer);
1241 PostSetNeedsCommitToMainThread();
1244 void AfterTest() override {}
1246 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
1247 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1249 ++commits_;
1250 switch (commits_) {
1251 case 1:
1252 // First (regular) update, we should upload 2 resources (thumb, and
1253 // backtrack).
1254 EXPECT_EQ(1, scrollbar_layer_->update_count());
1255 LoseContext();
1256 break;
1257 case 2:
1258 // Second update, after the lost context, we should still upload 2
1259 // resources even if the contents haven't changed.
1260 EXPECT_EQ(2, scrollbar_layer_->update_count());
1261 EndTest();
1262 break;
1263 default:
1264 NOTREACHED();
1268 private:
1269 int commits_;
1270 scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer_;
1273 SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext);
1275 class UIResourceLostTest : public LayerTreeHostContextTest {
1276 public:
1277 UIResourceLostTest() : time_step_(0) {}
1278 void InitializeSettings(LayerTreeSettings* settings) override {
1279 settings->renderer_settings.texture_id_allocation_chunk_size = 1;
1281 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
1282 void AfterTest() override {}
1284 // This is called on the main thread after each commit and
1285 // DidActivateTreeOnThread, with the value of time_step_ at the time
1286 // of the call to DidActivateTreeOnThread. Similar tests will do
1287 // work on the main thread in DidCommit but that is unsuitable because
1288 // the main thread work for these tests must happen after
1289 // DidActivateTreeOnThread, which happens after DidCommit with impl-side
1290 // painting.
1291 virtual void StepCompleteOnMainThread(int time_step) = 0;
1293 // Called after DidActivateTreeOnThread. If this is done during the commit,
1294 // the call to StepCompleteOnMainThread will not occur until after
1295 // the commit completes, because the main thread is blocked.
1296 void PostStepCompleteToMainThread() {
1297 proxy()->MainThreadTaskRunner()->PostTask(
1298 FROM_HERE,
1299 base::Bind(&UIResourceLostTest::StepCompleteOnMainThreadInternal,
1300 base::Unretained(this),
1301 time_step_));
1304 void PostLoseContextToImplThread() {
1305 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1306 ImplThreadTaskRunner()->PostTask(
1307 FROM_HERE,
1308 base::Bind(&LayerTreeHostContextTest::LoseContext,
1309 base::Unretained(this)));
1312 protected:
1313 int time_step_;
1314 scoped_ptr<FakeScopedUIResource> ui_resource_;
1316 private:
1317 void StepCompleteOnMainThreadInternal(int step) {
1318 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1319 StepCompleteOnMainThread(step);
1323 class UIResourceLostTestSimple : public UIResourceLostTest {
1324 public:
1325 // This is called when the commit is complete and the new layer tree has been
1326 // activated.
1327 virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) = 0;
1329 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
1330 if (!impl->settings().impl_side_painting) {
1331 StepCompleteOnImplThread(impl);
1332 PostStepCompleteToMainThread();
1333 ++time_step_;
1337 void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
1338 if (impl->settings().impl_side_painting) {
1339 StepCompleteOnImplThread(impl);
1340 PostStepCompleteToMainThread();
1341 ++time_step_;
1346 // Losing context after an UI resource has been created.
1347 class UIResourceLostAfterCommit : public UIResourceLostTestSimple {
1348 public:
1349 void StepCompleteOnMainThread(int step) override {
1350 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1351 switch (step) {
1352 case 0:
1353 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1354 // Expects a valid UIResourceId.
1355 EXPECT_NE(0, ui_resource_->id());
1356 PostSetNeedsCommitToMainThread();
1357 break;
1358 case 4:
1359 // Release resource before ending the test.
1360 ui_resource_ = nullptr;
1361 EndTest();
1362 break;
1363 case 5:
1364 NOTREACHED();
1365 break;
1369 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override {
1370 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1371 switch (time_step_) {
1372 case 1:
1373 // The resource should have been created on LTHI after the commit.
1374 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1375 PostSetNeedsCommitToMainThread();
1376 break;
1377 case 2:
1378 LoseContext();
1379 break;
1380 case 3:
1381 // The resources should have been recreated. The bitmap callback should
1382 // have been called once with the resource_lost flag set to true.
1383 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1384 // Resource Id on the impl-side have been recreated as well. Note
1385 // that the same UIResourceId persists after the context lost.
1386 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1387 PostSetNeedsCommitToMainThread();
1388 break;
1393 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostAfterCommit);
1395 // Losing context before UI resource requests can be commited. Three sequences
1396 // of creation/deletion are considered:
1397 // 1. Create one resource -> Context Lost => Expect the resource to have been
1398 // created.
1399 // 2. Delete an exisiting resource (test_id0_) -> create a second resource
1400 // (test_id1_) -> Context Lost => Expect the test_id0_ to be removed and
1401 // test_id1_ to have been created.
1402 // 3. Create one resource -> Delete that same resource -> Context Lost => Expect
1403 // the resource to not exist in the manager.
1404 class UIResourceLostBeforeCommit : public UIResourceLostTestSimple {
1405 public:
1406 UIResourceLostBeforeCommit() : test_id0_(0), test_id1_(0) {}
1408 void StepCompleteOnMainThread(int step) override {
1409 switch (step) {
1410 case 0:
1411 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1412 // Lose the context on the impl thread before the commit.
1413 PostLoseContextToImplThread();
1414 break;
1415 case 2:
1416 // Sequence 2:
1417 // Currently one resource has been created.
1418 test_id0_ = ui_resource_->id();
1419 // Delete this resource.
1420 ui_resource_ = nullptr;
1421 // Create another resource.
1422 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1423 test_id1_ = ui_resource_->id();
1424 // Sanity check that two resource creations return different ids.
1425 EXPECT_NE(test_id0_, test_id1_);
1426 // Lose the context on the impl thread before the commit.
1427 PostLoseContextToImplThread();
1428 break;
1429 case 3:
1430 // Clear the manager of resources.
1431 ui_resource_ = nullptr;
1432 PostSetNeedsCommitToMainThread();
1433 break;
1434 case 4:
1435 // Sequence 3:
1436 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1437 test_id0_ = ui_resource_->id();
1438 // Sanity check the UIResourceId should not be 0.
1439 EXPECT_NE(0, test_id0_);
1440 // Usually ScopedUIResource are deleted from the manager in their
1441 // destructor (so usually ui_resource_ = nullptr). But here we need
1442 // ui_resource_ for the next step, so call DeleteUIResource directly.
1443 layer_tree_host()->DeleteUIResource(test_id0_);
1444 // Delete the resouce and then lose the context.
1445 PostLoseContextToImplThread();
1446 break;
1447 case 5:
1448 // Release resource before ending the test.
1449 ui_resource_ = nullptr;
1450 EndTest();
1451 break;
1452 case 6:
1453 NOTREACHED();
1454 break;
1458 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override {
1459 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1460 switch (time_step_) {
1461 case 1:
1462 // Sequence 1 (continued):
1463 // The first context lost happens before the resources were created,
1464 // and because it resulted in no resources being destroyed, it does not
1465 // trigger resource re-creation.
1466 EXPECT_EQ(1, ui_resource_->resource_create_count);
1467 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1468 // Resource Id on the impl-side has been created.
1469 PostSetNeedsCommitToMainThread();
1470 break;
1471 case 3:
1472 // Sequence 2 (continued):
1473 // The previous resource should have been deleted.
1474 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
1475 // The second resource should have been created.
1476 EXPECT_NE(0u, impl->ResourceIdForUIResource(test_id1_));
1477 // The second resource called the resource callback once and since the
1478 // context is lost, a "resource lost" callback was also issued.
1479 EXPECT_EQ(2, ui_resource_->resource_create_count);
1480 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1481 break;
1482 case 5:
1483 // Sequence 3 (continued):
1484 // Expect the resource callback to have been called once.
1485 EXPECT_EQ(1, ui_resource_->resource_create_count);
1486 // No "resource lost" callbacks.
1487 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1488 // The UI resource id should not be valid
1489 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
1490 break;
1494 private:
1495 UIResourceId test_id0_;
1496 UIResourceId test_id1_;
1499 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeCommit);
1501 // Losing UI resource before the pending trees is activated but after the
1502 // commit. Impl-side-painting only.
1503 class UIResourceLostBeforeActivateTree : public UIResourceLostTest {
1504 void StepCompleteOnMainThread(int step) override {
1505 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1506 switch (step) {
1507 case 0:
1508 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1509 PostSetNeedsCommitToMainThread();
1510 break;
1511 case 3:
1512 test_id_ = ui_resource_->id();
1513 ui_resource_ = nullptr;
1514 PostSetNeedsCommitToMainThread();
1515 break;
1516 case 5:
1517 // Release resource before ending the test.
1518 ui_resource_ = nullptr;
1519 EndTest();
1520 break;
1521 case 6:
1522 // Make sure no extra commits happened.
1523 NOTREACHED();
1527 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
1528 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1529 switch (time_step_) {
1530 case 2:
1531 PostSetNeedsCommitToMainThread();
1532 break;
1533 case 4:
1534 PostSetNeedsCommitToMainThread();
1535 break;
1539 void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override {
1540 switch (time_step_) {
1541 case 1:
1542 // The resource creation callback has been called.
1543 EXPECT_EQ(1, ui_resource_->resource_create_count);
1544 // The resource is not yet lost (sanity check).
1545 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1546 // The resource should not have been created yet on the impl-side.
1547 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1548 LoseContext();
1549 break;
1550 case 3:
1551 LoseContext();
1552 break;
1556 void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
1557 LayerTreeHostContextTest::DidActivateTreeOnThread(impl);
1558 switch (time_step_) {
1559 case 1:
1560 // The pending requests on the impl-side should have been processed.
1561 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1562 break;
1563 case 2:
1564 // The "lost resource" callback should have been called once.
1565 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1566 break;
1567 case 4:
1568 // The resource is deleted and should not be in the manager. Use
1569 // test_id_ since ui_resource_ has been deleted.
1570 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id_));
1571 break;
1574 PostStepCompleteToMainThread();
1575 ++time_step_;
1578 private:
1579 UIResourceId test_id_;
1582 TEST_F(UIResourceLostBeforeActivateTree,
1583 RunMultiThread_DirectRenderer_ImplSidePaint) {
1584 RunTest(true, false, true);
1587 TEST_F(UIResourceLostBeforeActivateTree,
1588 RunMultiThread_DelegatingRenderer_ImplSidePaint) {
1589 RunTest(true, true, true);
1592 // Resources evicted explicitly and by visibility changes.
1593 class UIResourceLostEviction : public UIResourceLostTestSimple {
1594 public:
1595 void StepCompleteOnMainThread(int step) override {
1596 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1597 switch (step) {
1598 case 0:
1599 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1600 EXPECT_NE(0, ui_resource_->id());
1601 PostSetNeedsCommitToMainThread();
1602 break;
1603 case 2:
1604 // Make the tree not visible.
1605 PostSetVisibleToMainThread(false);
1606 break;
1607 case 3:
1608 // Release resource before ending the test.
1609 ui_resource_ = nullptr;
1610 EndTest();
1611 break;
1612 case 4:
1613 NOTREACHED();
1617 void DidSetVisibleOnImplTree(LayerTreeHostImpl* impl, bool visible) override {
1618 TestWebGraphicsContext3D* context = TestContext();
1619 if (!visible) {
1620 // All resources should have been evicted.
1621 ASSERT_EQ(0u, context->NumTextures());
1622 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1623 EXPECT_EQ(2, ui_resource_->resource_create_count);
1624 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1625 // Drawing is disabled both because of the evicted resources and
1626 // because the renderer is not visible.
1627 EXPECT_FALSE(impl->CanDraw());
1628 // Make the renderer visible again.
1629 PostSetVisibleToMainThread(true);
1633 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override {
1634 TestWebGraphicsContext3D* context = TestContext();
1635 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1636 switch (time_step_) {
1637 case 1:
1638 // The resource should have been created on LTHI after the commit.
1639 ASSERT_EQ(1u, context->NumTextures());
1640 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1641 EXPECT_EQ(1, ui_resource_->resource_create_count);
1642 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1643 EXPECT_TRUE(impl->CanDraw());
1644 // Evict all UI resources. This will trigger a commit.
1645 impl->EvictAllUIResources();
1646 ASSERT_EQ(0u, context->NumTextures());
1647 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1648 EXPECT_EQ(1, ui_resource_->resource_create_count);
1649 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1650 EXPECT_FALSE(impl->CanDraw());
1651 break;
1652 case 2:
1653 // The resource should have been recreated.
1654 ASSERT_EQ(1u, context->NumTextures());
1655 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1656 EXPECT_EQ(2, ui_resource_->resource_create_count);
1657 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1658 EXPECT_TRUE(impl->CanDraw());
1659 break;
1660 case 3:
1661 // The resource should have been recreated after visibility was
1662 // restored.
1663 ASSERT_EQ(1u, context->NumTextures());
1664 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1665 EXPECT_EQ(3, ui_resource_->resource_create_count);
1666 EXPECT_EQ(2, ui_resource_->lost_resource_count);
1667 EXPECT_TRUE(impl->CanDraw());
1668 break;
1673 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction);
1675 class LayerTreeHostContextTestSurfaceCreateCallback
1676 : public LayerTreeHostContextTest {
1677 public:
1678 LayerTreeHostContextTestSurfaceCreateCallback()
1679 : LayerTreeHostContextTest() {}
1681 void SetupTree() override {
1682 if (layer_tree_host()->settings().impl_side_painting) {
1683 picture_layer_ = FakePictureLayer::Create(&client_);
1684 picture_layer_->SetBounds(gfx::Size(10, 20));
1685 layer_tree_host()->SetRootLayer(picture_layer_);
1686 } else {
1687 content_layer_ = FakeContentLayer::Create(&client_);
1688 content_layer_->SetBounds(gfx::Size(10, 20));
1689 layer_tree_host()->SetRootLayer(content_layer_);
1692 LayerTreeHostContextTest::SetupTree();
1695 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
1697 void DidCommit() override {
1698 switch (layer_tree_host()->source_frame_number()) {
1699 case 1:
1700 if (layer_tree_host()->settings().impl_side_painting)
1701 EXPECT_EQ(1u, picture_layer_->output_surface_created_count());
1702 else
1703 EXPECT_EQ(1u, content_layer_->output_surface_created_count());
1704 layer_tree_host()->SetNeedsCommit();
1705 break;
1706 case 2:
1707 if (layer_tree_host()->settings().impl_side_painting)
1708 EXPECT_EQ(1u, picture_layer_->output_surface_created_count());
1709 else
1710 EXPECT_EQ(1u, content_layer_->output_surface_created_count());
1711 layer_tree_host()->SetNeedsCommit();
1712 break;
1713 case 3:
1714 if (layer_tree_host()->settings().impl_side_painting)
1715 EXPECT_EQ(1u, picture_layer_->output_surface_created_count());
1716 else
1717 EXPECT_EQ(1u, content_layer_->output_surface_created_count());
1718 break;
1719 case 4:
1720 if (layer_tree_host()->settings().impl_side_painting)
1721 EXPECT_EQ(2u, picture_layer_->output_surface_created_count());
1722 else
1723 EXPECT_EQ(2u, content_layer_->output_surface_created_count());
1724 layer_tree_host()->SetNeedsCommit();
1725 break;
1729 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
1730 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1731 switch (LastCommittedSourceFrameNumber(impl)) {
1732 case 0:
1733 break;
1734 case 1:
1735 break;
1736 case 2:
1737 LoseContext();
1738 break;
1739 case 3:
1740 EndTest();
1741 break;
1745 void AfterTest() override {}
1747 protected:
1748 FakeContentLayerClient client_;
1749 scoped_refptr<FakePictureLayer> picture_layer_;
1750 scoped_refptr<FakeContentLayer> content_layer_;
1753 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestSurfaceCreateCallback);
1755 class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame
1756 : public LayerTreeHostContextTest {
1757 protected:
1758 void BeginTest() override {
1759 deferred_ = false;
1760 PostSetNeedsCommitToMainThread();
1763 void ScheduledActionWillSendBeginMainFrame() override {
1764 if (deferred_)
1765 return;
1766 deferred_ = true;
1768 // Defer commits before the BeginFrame arrives, causing it to be delayed.
1769 PostSetDeferCommitsToMainThread(true);
1770 // Meanwhile, lose the context while we are in defer commits.
1771 ImplThreadTaskRunner()->PostTask(
1772 FROM_HERE,
1773 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1774 LoseContextOnImplThread,
1775 base::Unretained(this)));
1778 void LoseContextOnImplThread() {
1779 LoseContext();
1781 // After losing the context, stop deferring commits.
1782 PostSetDeferCommitsToMainThread(false);
1785 void WillBeginMainFrame() override {
1786 // Don't begin a frame with a lost surface.
1787 EXPECT_FALSE(layer_tree_host()->output_surface_lost());
1790 void DidCommitAndDrawFrame() override { EndTest(); }
1792 void AfterTest() override {}
1794 bool deferred_;
1797 SINGLE_AND_MULTI_THREAD_TEST_F(
1798 LayerTreeHostContextTestLoseAfterSendingBeginMainFrame);
1800 } // namespace
1801 } // namespace cc