Infobar material design refresh: bg color
[chromium-blink-merge.git] / cc / trees / layer_tree_host_unittest_context.cc
blob7c766fe8bedc60376fafb543e8f51667e2c40682
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/trees/layer_tree_host.h"
7 #include "base/basictypes.h"
8 #include "cc/layers/delegated_frame_provider.h"
9 #include "cc/layers/delegated_frame_resource_collection.h"
10 #include "cc/layers/heads_up_display_layer.h"
11 #include "cc/layers/io_surface_layer.h"
12 #include "cc/layers/layer_impl.h"
13 #include "cc/layers/painted_scrollbar_layer.h"
14 #include "cc/layers/picture_layer.h"
15 #include "cc/layers/texture_layer.h"
16 #include "cc/layers/texture_layer_impl.h"
17 #include "cc/layers/video_layer.h"
18 #include "cc/layers/video_layer_impl.h"
19 #include "cc/output/filter_operations.h"
20 #include "cc/resources/single_release_callback.h"
21 #include "cc/test/failure_output_surface.h"
22 #include "cc/test/fake_content_layer_client.h"
23 #include "cc/test/fake_delegated_renderer_layer.h"
24 #include "cc/test/fake_delegated_renderer_layer_impl.h"
25 #include "cc/test/fake_layer_tree_host_client.h"
26 #include "cc/test/fake_output_surface.h"
27 #include "cc/test/fake_output_surface_client.h"
28 #include "cc/test/fake_painted_scrollbar_layer.h"
29 #include "cc/test/fake_picture_layer.h"
30 #include "cc/test/fake_picture_layer_impl.h"
31 #include "cc/test/fake_resource_provider.h"
32 #include "cc/test/fake_scoped_ui_resource.h"
33 #include "cc/test/fake_scrollbar.h"
34 #include "cc/test/fake_video_frame_provider.h"
35 #include "cc/test/layer_tree_test.h"
36 #include "cc/test/render_pass_test_utils.h"
37 #include "cc/test/test_context_provider.h"
38 #include "cc/test/test_shared_bitmap_manager.h"
39 #include "cc/test/test_web_graphics_context_3d.h"
40 #include "cc/trees/layer_tree_host_impl.h"
41 #include "cc/trees/layer_tree_impl.h"
42 #include "cc/trees/single_thread_proxy.h"
43 #include "gpu/GLES2/gl2extchromium.h"
44 #include "media/base/media.h"
46 using media::VideoFrame;
48 namespace cc {
49 namespace {
51 // These tests deal with losing the 3d graphics context.
52 class LayerTreeHostContextTest : public LayerTreeTest {
53 public:
54 LayerTreeHostContextTest()
55 : LayerTreeTest(),
56 context3d_(NULL),
57 times_to_fail_create_(0),
58 times_to_lose_during_commit_(0),
59 times_to_lose_during_draw_(0),
60 times_to_fail_recreate_(0),
61 times_to_expect_create_failed_(0),
62 times_create_failed_(0),
63 committed_at_least_once_(false),
64 context_should_support_io_surface_(false),
65 fallback_context_works_(false),
66 async_output_surface_creation_(false) {
67 media::InitializeMediaLibrary();
70 void LoseContext() {
71 // CreateFakeOutputSurface happens on a different thread, so lock context3d_
72 // to make sure we don't set it to null after recreating it there.
73 base::AutoLock lock(context3d_lock_);
74 // For sanity-checking tests, they should only call this when the
75 // context is not lost.
76 CHECK(context3d_);
77 context3d_->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
78 GL_INNOCENT_CONTEXT_RESET_ARB);
79 context3d_ = NULL;
82 virtual scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() {
83 return TestWebGraphicsContext3D::Create();
86 scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
87 if (times_to_fail_create_) {
88 --times_to_fail_create_;
89 ExpectCreateToFail();
90 return make_scoped_ptr(new FailureOutputSurface(delegating_renderer()));
93 scoped_ptr<TestWebGraphicsContext3D> context3d = CreateContext3d();
94 base::AutoLock lock(context3d_lock_);
95 context3d_ = context3d.get();
97 if (context_should_support_io_surface_) {
98 context3d_->set_have_extension_io_surface(true);
99 context3d_->set_have_extension_egl_image(true);
102 if (delegating_renderer())
103 return FakeOutputSurface::CreateDelegating3d(context3d.Pass());
104 else
105 return FakeOutputSurface::Create3d(context3d.Pass());
108 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
109 LayerTreeHostImpl::FrameData* frame,
110 DrawResult draw_result) override {
111 if (draw_result == DRAW_ABORTED_MISSING_HIGH_RES_CONTENT) {
112 // Only valid for single-threaded compositing, which activates
113 // immediately and will try to draw again when content has finished.
114 DCHECK(!host_impl->proxy()->HasImplThread());
115 return draw_result;
117 EXPECT_EQ(DRAW_SUCCESS, draw_result);
118 if (!times_to_lose_during_draw_)
119 return draw_result;
121 --times_to_lose_during_draw_;
122 LoseContext();
124 times_to_fail_create_ = times_to_fail_recreate_;
125 times_to_fail_recreate_ = 0;
127 return draw_result;
130 void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
131 committed_at_least_once_ = true;
133 if (!times_to_lose_during_commit_)
134 return;
135 --times_to_lose_during_commit_;
136 LoseContext();
138 times_to_fail_create_ = times_to_fail_recreate_;
139 times_to_fail_recreate_ = 0;
142 void DidFailToInitializeOutputSurface() override { ++times_create_failed_; }
144 void TearDown() override {
145 LayerTreeTest::TearDown();
146 EXPECT_EQ(times_to_expect_create_failed_, times_create_failed_);
149 void ExpectCreateToFail() { ++times_to_expect_create_failed_; }
151 protected:
152 // Protects use of context3d_ so LoseContext and CreateFakeOutputSurface
153 // can both use it on different threads.
154 base::Lock context3d_lock_;
155 TestWebGraphicsContext3D* context3d_;
157 int times_to_fail_create_;
158 int times_to_lose_during_commit_;
159 int times_to_lose_during_draw_;
160 int times_to_fail_recreate_;
161 int times_to_expect_create_failed_;
162 int times_create_failed_;
163 bool committed_at_least_once_;
164 bool context_should_support_io_surface_;
165 bool fallback_context_works_;
166 bool async_output_surface_creation_;
169 class LayerTreeHostContextTestLostContextSucceeds
170 : public LayerTreeHostContextTest {
171 public:
172 LayerTreeHostContextTestLostContextSucceeds()
173 : LayerTreeHostContextTest(),
174 test_case_(0),
175 num_losses_(0),
176 num_losses_last_test_case_(-1),
177 recovered_context_(true),
178 first_initialized_(false) {}
180 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
182 void RequestNewOutputSurface() override {
183 if (async_output_surface_creation_) {
184 MainThreadTaskRunner()->PostTask(
185 FROM_HERE, base::Bind(&LayerTreeHostContextTestLostContextSucceeds::
186 CreateAndSetOutputSurface,
187 base::Unretained(this)));
188 } else {
189 CreateAndSetOutputSurface();
193 void CreateAndSetOutputSurface() {
194 scoped_ptr<OutputSurface> surface(
195 LayerTreeHostContextTest::CreateOutputSurface());
196 CHECK(surface);
197 layer_tree_host()->SetOutputSurface(surface.Pass());
200 void DidInitializeOutputSurface() override {
201 if (first_initialized_)
202 ++num_losses_;
203 else
204 first_initialized_ = true;
206 recovered_context_ = true;
209 void AfterTest() override { EXPECT_EQ(11u, test_case_); }
211 void DidCommitAndDrawFrame() override {
212 // If the last frame had a context loss, then we'll commit again to
213 // recover.
214 if (!recovered_context_)
215 return;
216 if (times_to_lose_during_commit_)
217 return;
218 if (times_to_lose_during_draw_)
219 return;
221 recovered_context_ = false;
222 if (NextTestCase())
223 InvalidateAndSetNeedsCommit();
224 else
225 EndTest();
228 virtual void InvalidateAndSetNeedsCommit() {
229 // Cause damage so we try to draw.
230 layer_tree_host()->root_layer()->SetNeedsDisplay();
231 layer_tree_host()->SetNeedsCommit();
234 bool NextTestCase() {
235 static const TestCase kTests[] = {
236 // Losing the context and failing to recreate it (or losing it again
237 // immediately) a small number of times should succeed.
239 1, // times_to_lose_during_commit
240 0, // times_to_lose_during_draw
241 0, // times_to_fail_recreate
242 false, // fallback_context_works
243 false, // async_output_surface_creation
246 0, // times_to_lose_during_commit
247 1, // times_to_lose_during_draw
248 0, // times_to_fail_recreate
249 false, // fallback_context_works
250 false, // async_output_surface_creation
253 1, // times_to_lose_during_commit
254 0, // times_to_lose_during_draw
255 3, // times_to_fail_recreate
256 false, // fallback_context_works
257 false, // async_output_surface_creation
260 0, // times_to_lose_during_commit
261 1, // times_to_lose_during_draw
262 3, // times_to_fail_recreate
263 false, // fallback_context_works
264 false, // async_output_surface_creation
267 0, // times_to_lose_during_commit
268 1, // times_to_lose_during_draw
269 3, // times_to_fail_recreate
270 false, // fallback_context_works
271 true, // async_output_surface_creation
273 // Losing the context and recreating it any number of times should
274 // succeed.
276 10, // times_to_lose_during_commit
277 0, // times_to_lose_during_draw
278 0, // times_to_fail_recreate
279 false, // fallback_context_works
280 false, // async_output_surface_creation
283 0, // times_to_lose_during_commit
284 10, // times_to_lose_during_draw
285 0, // times_to_fail_recreate
286 false, // fallback_context_works
287 false, // async_output_surface_creation
290 10, // times_to_lose_during_commit
291 0, // times_to_lose_during_draw
292 0, // times_to_fail_recreate
293 false, // fallback_context_works
294 true, // async_output_surface_creation
297 0, // times_to_lose_during_commit
298 10, // times_to_lose_during_draw
299 0, // times_to_fail_recreate
300 false, // fallback_context_works
301 true, // async_output_surface_creation
303 // Losing the context, failing to reinitialize it, and making a fallback
304 // context should work.
306 0, // times_to_lose_during_commit
307 1, // times_to_lose_during_draw
308 0, // times_to_fail_recreate
309 true, // fallback_context_works
310 false, // async_output_surface_creation
313 0, // times_to_lose_during_commit
314 1, // times_to_lose_during_draw
315 0, // times_to_fail_recreate
316 true, // fallback_context_works
317 true, // async_output_surface_creation
321 if (test_case_ >= arraysize(kTests))
322 return false;
323 // Make sure that we lost our context at least once in the last test run so
324 // the test did something.
325 EXPECT_GT(num_losses_, num_losses_last_test_case_);
326 num_losses_last_test_case_ = num_losses_;
328 times_to_lose_during_commit_ =
329 kTests[test_case_].times_to_lose_during_commit;
330 times_to_lose_during_draw_ = kTests[test_case_].times_to_lose_during_draw;
331 times_to_fail_recreate_ = kTests[test_case_].times_to_fail_recreate;
332 fallback_context_works_ = kTests[test_case_].fallback_context_works;
333 async_output_surface_creation_ =
334 kTests[test_case_].async_output_surface_creation;
335 ++test_case_;
336 return true;
339 struct TestCase {
340 int times_to_lose_during_commit;
341 int times_to_lose_during_draw;
342 int times_to_fail_recreate;
343 bool fallback_context_works;
344 bool async_output_surface_creation;
347 protected:
348 size_t test_case_;
349 int num_losses_;
350 int num_losses_last_test_case_;
351 bool recovered_context_;
352 bool first_initialized_;
355 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLostContextSucceeds);
357 class LayerTreeHostClientNotReadyDoesNotCreateOutputSurface
358 : public LayerTreeHostContextTest {
359 public:
360 LayerTreeHostClientNotReadyDoesNotCreateOutputSurface()
361 : LayerTreeHostContextTest() {}
363 void WillBeginTest() override {
364 // Override and do not signal SetLayerTreeHostClientReady.
367 void BeginTest() override {
368 PostSetNeedsCommitToMainThread();
369 EndTest();
372 scoped_ptr<OutputSurface> CreateOutputSurface() override {
373 EXPECT_TRUE(false);
374 return nullptr;
377 void DidInitializeOutputSurface() override { EXPECT_TRUE(false); }
379 void AfterTest() override {}
382 SINGLE_AND_MULTI_THREAD_TEST_F(
383 LayerTreeHostClientNotReadyDoesNotCreateOutputSurface);
385 class MultipleCompositeDoesNotCreateOutputSurface
386 : public LayerTreeHostContextTest {
387 public:
388 MultipleCompositeDoesNotCreateOutputSurface()
389 : LayerTreeHostContextTest(), request_count_(0) {}
391 void InitializeSettings(LayerTreeSettings* settings) override {
392 settings->single_thread_proxy_scheduler = false;
393 settings->use_zero_copy = true;
396 void RequestNewOutputSurface() override {
397 EXPECT_GE(1, ++request_count_);
398 EndTest();
401 void BeginTest() override {
402 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
403 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(2));
406 scoped_ptr<OutputSurface> CreateOutputSurface() override {
407 EXPECT_TRUE(false);
408 return nullptr;
411 void DidInitializeOutputSurface() override { EXPECT_TRUE(false); }
413 void AfterTest() override {}
415 int request_count_;
418 // This test uses Composite() which only exists for single thread.
419 SINGLE_THREAD_TEST_F(MultipleCompositeDoesNotCreateOutputSurface);
421 // This test makes sure that once a SingleThreadProxy issues a
422 // DidFailToInitializeOutputSurface, that future Composite calls will not
423 // trigger additional requests for output surfaces.
424 class FailedCreateDoesNotCreateExtraOutputSurface
425 : public LayerTreeHostContextTest {
426 public:
427 FailedCreateDoesNotCreateExtraOutputSurface()
428 : LayerTreeHostContextTest(), num_requests_(0), has_failed_(false) {}
430 void InitializeSettings(LayerTreeSettings* settings) override {
431 settings->single_thread_proxy_scheduler = false;
432 settings->use_zero_copy = true;
435 void RequestNewOutputSurface() override {
436 num_requests_++;
437 // There should be one initial request and then one request from
438 // the LayerTreeTest test hooks DidFailToInitializeOutputSurface (which is
439 // hard to skip). This second request is just ignored and is test cruft.
440 EXPECT_LE(num_requests_, 2);
441 if (num_requests_ > 1)
442 return;
443 ExpectCreateToFail();
444 layer_tree_host()->SetOutputSurface(
445 make_scoped_ptr(new FailureOutputSurface(false)));
448 void BeginTest() override {
449 // First composite tries to create a surface.
450 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
451 EXPECT_EQ(num_requests_, 2);
452 EXPECT_TRUE(has_failed_);
454 // Second composite should not request or fail.
455 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(2));
456 EXPECT_EQ(num_requests_, 2);
457 EndTest();
460 void DidInitializeOutputSurface() override { EXPECT_TRUE(false); }
462 void DidFailToInitializeOutputSurface() override {
463 LayerTreeHostContextTest::DidFailToInitializeOutputSurface();
464 EXPECT_FALSE(has_failed_);
465 has_failed_ = true;
468 void AfterTest() override {}
470 int num_requests_;
471 bool has_failed_;
474 // This test uses Composite() which only exists for single thread.
475 SINGLE_THREAD_TEST_F(FailedCreateDoesNotCreateExtraOutputSurface);
477 class LayerTreeHostContextTestCommitAfterDelayedOutputSurface
478 : public LayerTreeHostContextTest {
479 public:
480 LayerTreeHostContextTestCommitAfterDelayedOutputSurface()
481 : LayerTreeHostContextTest(), creating_output_(false) {}
483 void InitializeSettings(LayerTreeSettings* settings) override {
484 settings->single_thread_proxy_scheduler = false;
485 settings->use_zero_copy = true;
488 void RequestNewOutputSurface() override {
489 MainThreadTaskRunner()->PostTask(
490 FROM_HERE,
491 base::Bind(&LayerTreeHostContextTestCommitAfterDelayedOutputSurface::
492 CreateAndSetOutputSurface,
493 base::Unretained(this)));
496 void CreateAndSetOutputSurface() {
497 creating_output_ = true;
498 layer_tree_host()->SetOutputSurface(
499 LayerTreeHostContextTest::CreateOutputSurface());
502 void BeginTest() override {
503 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
506 void ScheduleComposite() override {
507 if (creating_output_)
508 EndTest();
511 void AfterTest() override {}
513 bool creating_output_;
516 // This test uses Composite() which only exists for single thread.
517 SINGLE_THREAD_TEST_F(LayerTreeHostContextTestCommitAfterDelayedOutputSurface);
519 class LayerTreeHostContextTestAvoidUnnecessaryComposite
520 : public LayerTreeHostContextTest {
521 public:
522 LayerTreeHostContextTestAvoidUnnecessaryComposite()
523 : LayerTreeHostContextTest(), in_composite_(false) {}
525 void InitializeSettings(LayerTreeSettings* settings) override {
526 settings->single_thread_proxy_scheduler = false;
527 settings->use_zero_copy = true;
530 void RequestNewOutputSurface() override {
531 layer_tree_host()->SetOutputSurface(
532 LayerTreeHostContextTest::CreateOutputSurface());
533 EndTest();
536 void BeginTest() override {
537 in_composite_ = true;
538 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
539 in_composite_ = false;
542 void ScheduleComposite() override { EXPECT_FALSE(in_composite_); }
544 void AfterTest() override {}
546 bool in_composite_;
549 // This test uses Composite() which only exists for single thread.
550 SINGLE_THREAD_TEST_F(LayerTreeHostContextTestAvoidUnnecessaryComposite);
552 // This test uses PictureLayer to check for a working context.
553 class LayerTreeHostContextTestLostContextSucceedsWithContent
554 : public LayerTreeHostContextTestLostContextSucceeds {
555 public:
556 void SetupTree() override {
557 root_ = Layer::Create(layer_settings());
558 root_->SetBounds(gfx::Size(10, 10));
559 root_->SetIsDrawable(true);
561 // Paint non-solid color.
562 SkPaint paint;
563 paint.setColor(SkColorSetARGB(100, 80, 200, 200));
564 client_.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint);
566 layer_ = FakePictureLayer::Create(layer_settings(), &client_);
567 layer_->SetBounds(gfx::Size(10, 10));
568 layer_->SetIsDrawable(true);
570 root_->AddChild(layer_);
572 layer_tree_host()->SetRootLayer(root_);
573 LayerTreeHostContextTest::SetupTree();
576 void InvalidateAndSetNeedsCommit() override {
577 // Invalidate the render surface so we don't try to use a cached copy of the
578 // surface. We want to make sure to test the drawing paths for drawing to
579 // a child surface.
580 layer_->SetNeedsDisplay();
581 LayerTreeHostContextTestLostContextSucceeds::InvalidateAndSetNeedsCommit();
584 void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
585 FakePictureLayerImpl* picture_impl = static_cast<FakePictureLayerImpl*>(
586 host_impl->active_tree()->root_layer()->children()[0]);
587 EXPECT_TRUE(picture_impl->HighResTiling()
588 ->TileAt(0, 0)
589 ->draw_info()
590 .IsReadyToDraw());
593 protected:
594 FakeContentLayerClient client_;
595 scoped_refptr<Layer> root_;
596 scoped_refptr<Layer> layer_;
599 SINGLE_AND_MULTI_THREAD_TEST_F(
600 LayerTreeHostContextTestLostContextSucceedsWithContent);
602 class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
603 : public LayerTreeHostContextTest {
604 public:
605 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
606 : times_to_fail_(1), times_initialized_(0) {
607 times_to_fail_create_ = times_to_fail_;
610 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
612 void DidInitializeOutputSurface() override { times_initialized_++; }
614 void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { EndTest(); }
616 void AfterTest() override {
617 EXPECT_EQ(times_to_fail_, times_create_failed_);
618 EXPECT_NE(0, times_initialized_);
621 private:
622 int times_to_fail_;
623 int times_initialized_;
626 SINGLE_AND_MULTI_THREAD_TEST_F(
627 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce);
629 class LayerTreeHostContextTestLostContextAndEvictTextures
630 : public LayerTreeHostContextTest {
631 public:
632 LayerTreeHostContextTestLostContextAndEvictTextures()
633 : LayerTreeHostContextTest(),
634 impl_host_(0),
635 num_commits_(0),
636 lost_context_(false) {}
638 void SetupTree() override {
639 // Paint non-solid color.
640 SkPaint paint;
641 paint.setColor(SkColorSetARGB(100, 80, 200, 200));
642 client_.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint);
644 scoped_refptr<FakePictureLayer> picture_layer =
645 FakePictureLayer::Create(layer_settings(), &client_);
646 picture_layer->SetBounds(gfx::Size(10, 20));
647 layer_tree_host()->SetRootLayer(picture_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 PostEvictTextures();
682 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
683 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
684 if (num_commits_ > 1)
685 return;
686 ++num_commits_;
687 if (!lose_after_evict_) {
688 LoseContext();
689 lost_context_ = true;
693 void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
694 FakePictureLayerImpl* picture_impl =
695 static_cast<FakePictureLayerImpl*>(impl->active_tree()->root_layer());
696 EXPECT_TRUE(picture_impl->HighResTiling()
697 ->TileAt(0, 0)
698 ->draw_info()
699 .IsReadyToDraw());
701 impl_host_ = impl;
702 if (lost_context_)
703 EndTest();
706 void DidInitializeOutputSurface() override {}
708 void AfterTest() override {}
710 protected:
711 bool lose_after_evict_;
712 FakeContentLayerClient client_;
713 LayerTreeHostImpl* impl_host_;
714 int num_commits_;
715 bool lost_context_;
718 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
719 LoseAfterEvict_SingleThread_DirectRenderer) {
720 lose_after_evict_ = true;
721 RunTest(false, false);
724 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
725 LoseAfterEvict_SingleThread_DelegatingRenderer) {
726 lose_after_evict_ = true;
727 RunTest(false, true);
730 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
731 LoseAfterEvict_MultiThread_DirectRenderer) {
732 lose_after_evict_ = true;
733 RunTest(true, false);
736 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
737 LoseAfterEvict_MultiThread_DelegatingRenderer) {
738 lose_after_evict_ = true;
739 RunTest(true, true);
742 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
743 LoseBeforeEvict_SingleThread_DirectRenderer) {
744 lose_after_evict_ = false;
745 RunTest(false, false);
748 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
749 LoseBeforeEvict_SingleThread_DelegatingRenderer) {
750 lose_after_evict_ = false;
751 RunTest(false, true);
754 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
755 LoseBeforeEvict_MultiThread_DirectRenderer) {
756 lose_after_evict_ = false;
757 RunTest(true, false);
760 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
761 LoseBeforeEvict_MultiThread_DelegatingRenderer) {
762 lose_after_evict_ = false;
763 RunTest(true, true);
766 class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
767 public:
768 LayerTreeHostContextTestLayersNotified()
769 : LayerTreeHostContextTest(), num_commits_(0) {}
771 void SetupTree() override {
772 root_ = FakePictureLayer::Create(layer_settings(), &client_);
773 child_ = FakePictureLayer::Create(layer_settings(), &client_);
774 grandchild_ = FakePictureLayer::Create(layer_settings(), &client_);
776 root_->AddChild(child_);
777 child_->AddChild(grandchild_);
779 layer_tree_host()->SetRootLayer(root_);
780 LayerTreeHostContextTest::SetupTree();
783 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
785 void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
786 LayerTreeHostContextTest::DidActivateTreeOnThread(host_impl);
788 FakePictureLayerImpl* root_picture = NULL;
789 FakePictureLayerImpl* child_picture = NULL;
790 FakePictureLayerImpl* grandchild_picture = NULL;
792 root_picture = static_cast<FakePictureLayerImpl*>(
793 host_impl->active_tree()->root_layer());
794 child_picture =
795 static_cast<FakePictureLayerImpl*>(root_picture->children()[0]);
796 grandchild_picture =
797 static_cast<FakePictureLayerImpl*>(child_picture->children()[0]);
799 ++num_commits_;
800 switch (num_commits_) {
801 case 1:
802 EXPECT_EQ(0u, root_picture->release_resources_count());
803 EXPECT_EQ(0u, child_picture->release_resources_count());
804 EXPECT_EQ(0u, grandchild_picture->release_resources_count());
806 // Lose the context and struggle to recreate it.
807 LoseContext();
808 times_to_fail_create_ = 1;
809 break;
810 case 2:
811 EXPECT_TRUE(root_picture->release_resources_count());
812 EXPECT_TRUE(child_picture->release_resources_count());
813 EXPECT_TRUE(grandchild_picture->release_resources_count());
815 EndTest();
816 break;
817 default:
818 NOTREACHED();
822 void AfterTest() override {}
824 private:
825 int num_commits_;
827 FakeContentLayerClient client_;
828 scoped_refptr<Layer> root_;
829 scoped_refptr<Layer> child_;
830 scoped_refptr<Layer> grandchild_;
833 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified);
835 class LayerTreeHostContextTestDontUseLostResources
836 : public LayerTreeHostContextTest {
837 public:
838 LayerTreeHostContextTestDontUseLostResources() : lost_context_(false) {
839 context_should_support_io_surface_ = true;
841 child_output_surface_ = FakeOutputSurface::Create3d();
842 child_output_surface_->BindToClient(&output_surface_client_);
843 shared_bitmap_manager_.reset(new TestSharedBitmapManager());
844 child_resource_provider_ = FakeResourceProvider::Create(
845 child_output_surface_.get(), shared_bitmap_manager_.get());
848 static void EmptyReleaseCallback(unsigned sync_point, bool lost) {}
850 void SetupTree() override {
851 gpu::gles2::GLES2Interface* gl =
852 child_output_surface_->context_provider()->ContextGL();
854 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
856 scoped_ptr<RenderPass> pass_for_quad = RenderPass::Create();
857 pass_for_quad->SetNew(
858 // AppendOneOfEveryQuadType() makes a RenderPass quad with this id.
859 RenderPassId(2, 1),
860 gfx::Rect(0, 0, 10, 10),
861 gfx::Rect(0, 0, 10, 10),
862 gfx::Transform());
864 scoped_ptr<RenderPass> pass = RenderPass::Create();
865 pass->SetNew(RenderPassId(1, 1),
866 gfx::Rect(0, 0, 10, 10),
867 gfx::Rect(0, 0, 10, 10),
868 gfx::Transform());
869 uint32_t mailbox_sync_point;
870 AddOneOfEveryQuadType(pass.get(), child_resource_provider_.get(),
871 RenderPassId(2, 1), &mailbox_sync_point);
873 frame_data->render_pass_list.push_back(pass_for_quad.Pass());
874 frame_data->render_pass_list.push_back(pass.Pass());
876 delegated_resource_collection_ = new DelegatedFrameResourceCollection;
877 delegated_frame_provider_ = new DelegatedFrameProvider(
878 delegated_resource_collection_.get(), frame_data.Pass());
880 ResourceId resource = child_resource_provider_->CreateResource(
881 gfx::Size(4, 4), GL_CLAMP_TO_EDGE,
882 ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
883 ResourceProvider::ScopedWriteLockGL lock(child_resource_provider_.get(),
884 resource);
886 gpu::Mailbox mailbox;
887 gl->GenMailboxCHROMIUM(mailbox.name);
888 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
890 scoped_refptr<Layer> root = Layer::Create(layer_settings());
891 root->SetBounds(gfx::Size(10, 10));
892 root->SetIsDrawable(true);
894 scoped_refptr<FakeDelegatedRendererLayer> delegated =
895 FakeDelegatedRendererLayer::Create(layer_settings(),
896 delegated_frame_provider_.get());
897 delegated->SetBounds(gfx::Size(10, 10));
898 delegated->SetIsDrawable(true);
899 root->AddChild(delegated);
901 scoped_refptr<PictureLayer> layer =
902 PictureLayer::Create(layer_settings(), &client_);
903 layer->SetBounds(gfx::Size(10, 10));
904 layer->SetIsDrawable(true);
905 root->AddChild(layer);
907 scoped_refptr<TextureLayer> texture =
908 TextureLayer::CreateForMailbox(layer_settings_, NULL);
909 texture->SetBounds(gfx::Size(10, 10));
910 texture->SetIsDrawable(true);
911 texture->SetTextureMailbox(
912 TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point),
913 SingleReleaseCallback::Create(
914 base::Bind(&LayerTreeHostContextTestDontUseLostResources::
915 EmptyReleaseCallback)));
916 root->AddChild(texture);
918 scoped_refptr<PictureLayer> mask =
919 PictureLayer::Create(layer_settings_, &client_);
920 mask->SetBounds(gfx::Size(10, 10));
922 scoped_refptr<PictureLayer> layer_with_mask =
923 PictureLayer::Create(layer_settings_, &client_);
924 layer_with_mask->SetBounds(gfx::Size(10, 10));
925 layer_with_mask->SetIsDrawable(true);
926 layer_with_mask->SetMaskLayer(mask.get());
927 root->AddChild(layer_with_mask);
929 scoped_refptr<VideoLayer> video_color = VideoLayer::Create(
930 layer_settings_, &color_frame_provider_, media::VIDEO_ROTATION_0);
931 video_color->SetBounds(gfx::Size(10, 10));
932 video_color->SetIsDrawable(true);
933 root->AddChild(video_color);
935 scoped_refptr<VideoLayer> video_hw = VideoLayer::Create(
936 layer_settings_, &hw_frame_provider_, media::VIDEO_ROTATION_0);
937 video_hw->SetBounds(gfx::Size(10, 10));
938 video_hw->SetIsDrawable(true);
939 root->AddChild(video_hw);
941 scoped_refptr<VideoLayer> video_scaled_hw = VideoLayer::Create(
942 layer_settings_, &scaled_hw_frame_provider_, media::VIDEO_ROTATION_0);
943 video_scaled_hw->SetBounds(gfx::Size(10, 10));
944 video_scaled_hw->SetIsDrawable(true);
945 root->AddChild(video_scaled_hw);
947 color_video_frame_ = VideoFrame::CreateColorFrame(
948 gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
949 hw_video_frame_ = VideoFrame::WrapNativeTexture(
950 media::PIXEL_FORMAT_ARGB,
951 gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, sync_point),
952 media::VideoFrame::ReleaseMailboxCB(), gfx::Size(4, 4),
953 gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4), base::TimeDelta());
954 scaled_hw_video_frame_ = VideoFrame::WrapNativeTexture(
955 media::PIXEL_FORMAT_ARGB,
956 gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, sync_point),
957 media::VideoFrame::ReleaseMailboxCB(), gfx::Size(4, 4),
958 gfx::Rect(0, 0, 3, 2), gfx::Size(4, 4), base::TimeDelta());
960 color_frame_provider_.set_frame(color_video_frame_);
961 hw_frame_provider_.set_frame(hw_video_frame_);
962 scaled_hw_frame_provider_.set_frame(scaled_hw_video_frame_);
964 scoped_refptr<IOSurfaceLayer> io_surface =
965 IOSurfaceLayer::Create(layer_settings_);
966 io_surface->SetBounds(gfx::Size(10, 10));
967 io_surface->SetIsDrawable(true);
968 io_surface->SetIOSurfaceProperties(1, gfx::Size(10, 10));
969 root->AddChild(io_surface);
971 // Enable the hud.
972 LayerTreeDebugState debug_state;
973 debug_state.show_property_changed_rects = true;
974 layer_tree_host()->SetDebugState(debug_state);
976 scoped_refptr<PaintedScrollbarLayer> scrollbar =
977 PaintedScrollbarLayer::Create(
978 layer_settings_, scoped_ptr<Scrollbar>(new FakeScrollbar).Pass(),
979 layer->id());
980 scrollbar->SetBounds(gfx::Size(10, 10));
981 scrollbar->SetIsDrawable(true);
982 root->AddChild(scrollbar);
984 layer_tree_host()->SetRootLayer(root);
985 LayerTreeHostContextTest::SetupTree();
988 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
990 void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
991 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
993 if (host_impl->active_tree()->source_frame_number() == 3) {
994 // On the third commit we're recovering from context loss. Hardware
995 // video frames should not be reused by the VideoFrameProvider, but
996 // software frames can be.
997 hw_frame_provider_.set_frame(NULL);
998 scaled_hw_frame_provider_.set_frame(NULL);
1002 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
1003 LayerTreeHostImpl::FrameData* frame,
1004 DrawResult draw_result) override {
1005 if (host_impl->active_tree()->source_frame_number() == 2) {
1006 // Lose the context during draw on the second commit. This will cause
1007 // a third commit to recover.
1008 context3d_->set_times_bind_texture_succeeds(0);
1010 return draw_result;
1013 scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
1014 // This will get called twice:
1015 // First when we create the initial output surface...
1016 if (layer_tree_host()->source_frame_number() > 0) {
1017 // ... and then again after we forced the context to be lost.
1018 lost_context_ = true;
1020 return LayerTreeHostContextTest::CreateFakeOutputSurface();
1023 void DidCommitAndDrawFrame() override {
1024 ASSERT_TRUE(layer_tree_host()->hud_layer());
1025 // End the test once we know the 3nd frame drew.
1026 if (layer_tree_host()->source_frame_number() < 5) {
1027 layer_tree_host()->root_layer()->SetNeedsDisplay();
1028 layer_tree_host()->SetNeedsCommit();
1029 } else {
1030 EndTest();
1034 void AfterTest() override { EXPECT_TRUE(lost_context_); }
1036 private:
1037 FakeContentLayerClient client_;
1038 bool lost_context_;
1040 FakeOutputSurfaceClient output_surface_client_;
1041 scoped_ptr<FakeOutputSurface> child_output_surface_;
1042 scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
1043 scoped_ptr<ResourceProvider> child_resource_provider_;
1045 scoped_refptr<DelegatedFrameResourceCollection>
1046 delegated_resource_collection_;
1047 scoped_refptr<DelegatedFrameProvider> delegated_frame_provider_;
1049 scoped_refptr<VideoFrame> color_video_frame_;
1050 scoped_refptr<VideoFrame> hw_video_frame_;
1051 scoped_refptr<VideoFrame> scaled_hw_video_frame_;
1053 FakeVideoFrameProvider color_frame_provider_;
1054 FakeVideoFrameProvider hw_frame_provider_;
1055 FakeVideoFrameProvider scaled_hw_frame_provider_;
1057 LayerSettings layer_settings_;
1060 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources);
1062 class LayerTreeHostContextTestImplSidePainting
1063 : public LayerTreeHostContextTest {
1064 public:
1065 void SetupTree() override {
1066 scoped_refptr<Layer> root = Layer::Create(layer_settings());
1067 root->SetBounds(gfx::Size(10, 10));
1068 root->SetIsDrawable(true);
1070 scoped_refptr<PictureLayer> picture =
1071 PictureLayer::Create(layer_settings(), &client_);
1072 picture->SetBounds(gfx::Size(10, 10));
1073 picture->SetIsDrawable(true);
1074 root->AddChild(picture);
1076 layer_tree_host()->SetRootLayer(root);
1077 LayerTreeHostContextTest::SetupTree();
1080 void BeginTest() override {
1081 times_to_lose_during_commit_ = 1;
1082 PostSetNeedsCommitToMainThread();
1085 void AfterTest() override {}
1087 void DidInitializeOutputSurface() override { EndTest(); }
1089 private:
1090 FakeContentLayerClient client_;
1093 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting);
1095 class ScrollbarLayerLostContext : public LayerTreeHostContextTest {
1096 public:
1097 ScrollbarLayerLostContext() : commits_(0) {}
1099 void BeginTest() override {
1100 scoped_refptr<Layer> scroll_layer = Layer::Create(layer_settings());
1101 scrollbar_layer_ = FakePaintedScrollbarLayer::Create(
1102 layer_settings(), false, true, scroll_layer->id());
1103 scrollbar_layer_->SetBounds(gfx::Size(10, 100));
1104 layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
1105 layer_tree_host()->root_layer()->AddChild(scroll_layer);
1106 PostSetNeedsCommitToMainThread();
1109 void AfterTest() override {}
1111 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
1112 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1114 ++commits_;
1115 switch (commits_) {
1116 case 1:
1117 // First (regular) update, we should upload 2 resources (thumb, and
1118 // backtrack).
1119 EXPECT_EQ(1, scrollbar_layer_->update_count());
1120 LoseContext();
1121 break;
1122 case 2:
1123 // Second update, after the lost context, we should still upload 2
1124 // resources even if the contents haven't changed.
1125 EXPECT_EQ(2, scrollbar_layer_->update_count());
1126 EndTest();
1127 break;
1128 default:
1129 NOTREACHED();
1133 private:
1134 int commits_;
1135 scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer_;
1138 SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext);
1140 class UIResourceLostTest : public LayerTreeHostContextTest {
1141 public:
1142 UIResourceLostTest() : time_step_(0) {}
1143 void InitializeSettings(LayerTreeSettings* settings) override {
1144 settings->renderer_settings.texture_id_allocation_chunk_size = 1;
1146 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
1147 void AfterTest() override {}
1149 // This is called on the main thread after each commit and
1150 // DidActivateTreeOnThread, with the value of time_step_ at the time
1151 // of the call to DidActivateTreeOnThread. Similar tests will do
1152 // work on the main thread in DidCommit but that is unsuitable because
1153 // the main thread work for these tests must happen after
1154 // DidActivateTreeOnThread, which happens after DidCommit with impl-side
1155 // painting.
1156 virtual void StepCompleteOnMainThread(int time_step) = 0;
1158 // Called after DidActivateTreeOnThread. If this is done during the commit,
1159 // the call to StepCompleteOnMainThread will not occur until after
1160 // the commit completes, because the main thread is blocked.
1161 void PostStepCompleteToMainThread() {
1162 proxy()->MainThreadTaskRunner()->PostTask(
1163 FROM_HERE,
1164 base::Bind(&UIResourceLostTest::StepCompleteOnMainThreadInternal,
1165 base::Unretained(this),
1166 time_step_));
1169 void PostLoseContextToImplThread() {
1170 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1171 ImplThreadTaskRunner()->PostTask(
1172 FROM_HERE,
1173 base::Bind(&LayerTreeHostContextTest::LoseContext,
1174 base::Unretained(this)));
1177 protected:
1178 int time_step_;
1179 scoped_ptr<FakeScopedUIResource> ui_resource_;
1181 private:
1182 void StepCompleteOnMainThreadInternal(int step) {
1183 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1184 StepCompleteOnMainThread(step);
1188 class UIResourceLostTestSimple : public UIResourceLostTest {
1189 public:
1190 // This is called when the new layer tree has been activated.
1191 virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) = 0;
1193 void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
1194 StepCompleteOnImplThread(impl);
1195 PostStepCompleteToMainThread();
1196 ++time_step_;
1200 // Losing context after an UI resource has been created.
1201 class UIResourceLostAfterCommit : public UIResourceLostTestSimple {
1202 public:
1203 void StepCompleteOnMainThread(int step) override {
1204 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1205 switch (step) {
1206 case 0:
1207 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1208 // Expects a valid UIResourceId.
1209 EXPECT_NE(0, ui_resource_->id());
1210 PostSetNeedsCommitToMainThread();
1211 break;
1212 case 4:
1213 // Release resource before ending the test.
1214 ui_resource_ = nullptr;
1215 EndTest();
1216 break;
1217 case 5:
1218 NOTREACHED();
1219 break;
1223 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override {
1224 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1225 switch (time_step_) {
1226 case 1:
1227 // The resource should have been created on LTHI after the commit.
1228 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1229 PostSetNeedsCommitToMainThread();
1230 break;
1231 case 2:
1232 LoseContext();
1233 break;
1234 case 3:
1235 // The resources should have been recreated. The bitmap callback should
1236 // have been called once with the resource_lost flag set to true.
1237 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1238 // Resource Id on the impl-side have been recreated as well. Note
1239 // that the same UIResourceId persists after the context lost.
1240 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1241 PostSetNeedsCommitToMainThread();
1242 break;
1247 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostAfterCommit);
1249 // Losing context before UI resource requests can be commited. Three sequences
1250 // of creation/deletion are considered:
1251 // 1. Create one resource -> Context Lost => Expect the resource to have been
1252 // created.
1253 // 2. Delete an exisiting resource (test_id0_) -> create a second resource
1254 // (test_id1_) -> Context Lost => Expect the test_id0_ to be removed and
1255 // test_id1_ to have been created.
1256 // 3. Create one resource -> Delete that same resource -> Context Lost => Expect
1257 // the resource to not exist in the manager.
1258 class UIResourceLostBeforeCommit : public UIResourceLostTestSimple {
1259 public:
1260 UIResourceLostBeforeCommit() : test_id0_(0), test_id1_(0) {}
1262 void StepCompleteOnMainThread(int step) override {
1263 switch (step) {
1264 case 0:
1265 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1266 // Lose the context on the impl thread before the commit.
1267 PostLoseContextToImplThread();
1268 break;
1269 case 2:
1270 // Sequence 2:
1271 // Currently one resource has been created.
1272 test_id0_ = ui_resource_->id();
1273 // Delete this resource.
1274 ui_resource_ = nullptr;
1275 // Create another resource.
1276 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1277 test_id1_ = ui_resource_->id();
1278 // Sanity check that two resource creations return different ids.
1279 EXPECT_NE(test_id0_, test_id1_);
1280 // Lose the context on the impl thread before the commit.
1281 PostLoseContextToImplThread();
1282 break;
1283 case 3:
1284 // Clear the manager of resources.
1285 ui_resource_ = nullptr;
1286 PostSetNeedsCommitToMainThread();
1287 break;
1288 case 4:
1289 // Sequence 3:
1290 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1291 test_id0_ = ui_resource_->id();
1292 // Sanity check the UIResourceId should not be 0.
1293 EXPECT_NE(0, test_id0_);
1294 // Usually ScopedUIResource are deleted from the manager in their
1295 // destructor (so usually ui_resource_ = nullptr). But here we need
1296 // ui_resource_ for the next step, so call DeleteUIResource directly.
1297 layer_tree_host()->DeleteUIResource(test_id0_);
1298 // Delete the resouce and then lose the context.
1299 PostLoseContextToImplThread();
1300 break;
1301 case 5:
1302 // Release resource before ending the test.
1303 ui_resource_ = nullptr;
1304 EndTest();
1305 break;
1306 case 6:
1307 NOTREACHED();
1308 break;
1312 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override {
1313 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1314 switch (time_step_) {
1315 case 1:
1316 // Sequence 1 (continued):
1317 // The first context lost happens before the resources were created,
1318 // and because it resulted in no resources being destroyed, it does not
1319 // trigger resource re-creation.
1320 EXPECT_EQ(1, ui_resource_->resource_create_count);
1321 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1322 // Resource Id on the impl-side has been created.
1323 PostSetNeedsCommitToMainThread();
1324 break;
1325 case 3:
1326 // Sequence 2 (continued):
1327 // The previous resource should have been deleted.
1328 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
1329 // The second resource should have been created.
1330 EXPECT_NE(0u, impl->ResourceIdForUIResource(test_id1_));
1331 // The second resource called the resource callback once and since the
1332 // context is lost, a "resource lost" callback was also issued.
1333 EXPECT_EQ(2, ui_resource_->resource_create_count);
1334 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1335 break;
1336 case 5:
1337 // Sequence 3 (continued):
1338 // Expect the resource callback to have been called once.
1339 EXPECT_EQ(1, ui_resource_->resource_create_count);
1340 // No "resource lost" callbacks.
1341 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1342 // The UI resource id should not be valid
1343 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
1344 break;
1348 private:
1349 UIResourceId test_id0_;
1350 UIResourceId test_id1_;
1353 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeCommit);
1355 // Losing UI resource before the pending trees is activated but after the
1356 // commit. Impl-side-painting only.
1357 class UIResourceLostBeforeActivateTree : public UIResourceLostTest {
1358 void StepCompleteOnMainThread(int step) override {
1359 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1360 switch (step) {
1361 case 0:
1362 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1363 PostSetNeedsCommitToMainThread();
1364 break;
1365 case 3:
1366 test_id_ = ui_resource_->id();
1367 ui_resource_ = nullptr;
1368 PostSetNeedsCommitToMainThread();
1369 break;
1370 case 5:
1371 // Release resource before ending the test.
1372 ui_resource_ = nullptr;
1373 EndTest();
1374 break;
1375 case 6:
1376 // Make sure no extra commits happened.
1377 NOTREACHED();
1381 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
1382 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1383 switch (time_step_) {
1384 case 2:
1385 PostSetNeedsCommitToMainThread();
1386 break;
1387 case 4:
1388 PostSetNeedsCommitToMainThread();
1389 break;
1393 void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override {
1394 switch (time_step_) {
1395 case 1:
1396 // The resource creation callback has been called.
1397 EXPECT_EQ(1, ui_resource_->resource_create_count);
1398 // The resource is not yet lost (sanity check).
1399 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1400 // The resource should not have been created yet on the impl-side.
1401 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1402 LoseContext();
1403 break;
1404 case 3:
1405 LoseContext();
1406 break;
1410 void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
1411 LayerTreeHostContextTest::DidActivateTreeOnThread(impl);
1412 switch (time_step_) {
1413 case 1:
1414 // The pending requests on the impl-side should have been processed.
1415 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1416 break;
1417 case 2:
1418 // The "lost resource" callback should have been called once.
1419 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1420 break;
1421 case 4:
1422 // The resource is deleted and should not be in the manager. Use
1423 // test_id_ since ui_resource_ has been deleted.
1424 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id_));
1425 break;
1428 PostStepCompleteToMainThread();
1429 ++time_step_;
1432 private:
1433 UIResourceId test_id_;
1436 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeActivateTree);
1438 // Resources evicted explicitly and by visibility changes.
1439 class UIResourceLostEviction : public UIResourceLostTestSimple {
1440 public:
1441 void StepCompleteOnMainThread(int step) override {
1442 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1443 switch (step) {
1444 case 0:
1445 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1446 EXPECT_NE(0, ui_resource_->id());
1447 PostSetNeedsCommitToMainThread();
1448 break;
1449 case 2:
1450 // Make the tree not visible.
1451 PostSetVisibleToMainThread(false);
1452 break;
1453 case 3:
1454 // Release resource before ending the test.
1455 ui_resource_ = nullptr;
1456 EndTest();
1457 break;
1458 case 4:
1459 NOTREACHED();
1463 void DidSetVisibleOnImplTree(LayerTreeHostImpl* impl, bool visible) override {
1464 TestWebGraphicsContext3D* context = TestContext();
1465 if (!visible) {
1466 // All resources should have been evicted.
1467 ASSERT_EQ(0u, context->NumTextures());
1468 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1469 EXPECT_EQ(2, ui_resource_->resource_create_count);
1470 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1471 // Drawing is disabled both because of the evicted resources and
1472 // because the renderer is not visible.
1473 EXPECT_FALSE(impl->CanDraw());
1474 // Make the renderer visible again.
1475 PostSetVisibleToMainThread(true);
1479 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override {
1480 TestWebGraphicsContext3D* context = TestContext();
1481 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1482 switch (time_step_) {
1483 case 1:
1484 // The resource should have been created on LTHI after the commit.
1485 ASSERT_EQ(1u, context->NumTextures());
1486 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1487 EXPECT_EQ(1, ui_resource_->resource_create_count);
1488 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1489 EXPECT_TRUE(impl->CanDraw());
1490 // Evict all UI resources. This will trigger a commit.
1491 impl->EvictAllUIResources();
1492 ASSERT_EQ(0u, context->NumTextures());
1493 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1494 EXPECT_EQ(1, ui_resource_->resource_create_count);
1495 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1496 EXPECT_FALSE(impl->CanDraw());
1497 break;
1498 case 2:
1499 // The resource should have been recreated.
1500 ASSERT_EQ(1u, context->NumTextures());
1501 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1502 EXPECT_EQ(2, ui_resource_->resource_create_count);
1503 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1504 EXPECT_TRUE(impl->CanDraw());
1505 break;
1506 case 3:
1507 // The resource should have been recreated after visibility was
1508 // restored.
1509 ASSERT_EQ(1u, context->NumTextures());
1510 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1511 EXPECT_EQ(3, ui_resource_->resource_create_count);
1512 EXPECT_EQ(2, ui_resource_->lost_resource_count);
1513 EXPECT_TRUE(impl->CanDraw());
1514 break;
1519 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction);
1521 class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame
1522 : public LayerTreeHostContextTest {
1523 protected:
1524 void BeginTest() override {
1525 deferred_ = false;
1526 PostSetNeedsCommitToMainThread();
1529 void ScheduledActionWillSendBeginMainFrame() override {
1530 if (deferred_)
1531 return;
1532 deferred_ = true;
1534 // Defer commits before the BeginFrame arrives, causing it to be delayed.
1535 PostSetDeferCommitsToMainThread(true);
1536 // Meanwhile, lose the context while we are in defer commits.
1537 ImplThreadTaskRunner()->PostTask(
1538 FROM_HERE,
1539 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1540 LoseContextOnImplThread,
1541 base::Unretained(this)));
1544 void LoseContextOnImplThread() {
1545 LoseContext();
1547 // After losing the context, stop deferring commits.
1548 PostSetDeferCommitsToMainThread(false);
1551 void WillBeginMainFrame() override {
1552 // Don't begin a frame with a lost surface.
1553 EXPECT_FALSE(layer_tree_host()->output_surface_lost());
1556 void DidCommitAndDrawFrame() override { EndTest(); }
1558 void AfterTest() override {}
1560 bool deferred_;
1563 SINGLE_AND_MULTI_THREAD_TEST_F(
1564 LayerTreeHostContextTestLoseAfterSendingBeginMainFrame);
1566 } // namespace
1567 } // namespace cc