Roll src/third_party/skia d32087a:1052f51
[chromium-blink-merge.git] / cc / trees / layer_tree_host_unittest_context.cc
blob3a41b5525971e638b9d73a67df5da45e8dfb87e4
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 // This tests the OutputSurface release logic in the following sequence.
386 // SetUp LTH and create and init OutputSurface
387 // LTH::SetVisible(false);
388 // LTH::ReleaseOutputSurface();
389 // ...
390 // LTH::SetVisible(true);
391 // Create and init new OutputSurface
392 class LayerTreeHostClientTakeAwayOutputSurface
393 : public LayerTreeHostContextTest {
394 public:
395 LayerTreeHostClientTakeAwayOutputSurface()
396 : LayerTreeHostContextTest(), setos_counter_(0) {}
398 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
400 void RequestNewOutputSurface() override {
401 if (layer_tree_host()->visible())
402 CreateAndSetOutputSurface();
405 void CreateAndSetOutputSurface() {
406 scoped_ptr<OutputSurface> surface =
407 LayerTreeHostContextTest::CreateOutputSurface();
408 CHECK(surface);
409 setos_counter_++;
410 layer_tree_host()->SetOutputSurface(surface.Pass());
413 void HideAndReleaseOutputSurface() {
414 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
415 layer_tree_host()->SetVisible(false);
416 scoped_ptr<OutputSurface> surface =
417 layer_tree_host()->ReleaseOutputSurface();
418 CHECK(surface);
419 surface->context_provider()->DetachFromThread();
420 MainThreadTaskRunner()->PostTask(
421 FROM_HERE,
422 base::Bind(&LayerTreeHostClientTakeAwayOutputSurface::MakeVisible,
423 base::Unretained(this)));
426 void DidInitializeOutputSurface() override {
427 EXPECT_TRUE(layer_tree_host()->visible());
428 if (setos_counter_ == 1) {
429 MainThreadTaskRunner()->PostTask(
430 FROM_HERE, base::Bind(&LayerTreeHostClientTakeAwayOutputSurface::
431 HideAndReleaseOutputSurface,
432 base::Unretained(this)));
433 } else {
434 EndTest();
438 void MakeVisible() {
439 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
440 layer_tree_host()->SetVisible(true);
443 void AfterTest() override {}
445 int setos_counter_;
448 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostClientTakeAwayOutputSurface);
450 class MultipleCompositeDoesNotCreateOutputSurface
451 : public LayerTreeHostContextTest {
452 public:
453 MultipleCompositeDoesNotCreateOutputSurface()
454 : LayerTreeHostContextTest(), request_count_(0) {}
456 void InitializeSettings(LayerTreeSettings* settings) override {
457 settings->single_thread_proxy_scheduler = false;
458 settings->use_zero_copy = true;
461 void RequestNewOutputSurface() override {
462 EXPECT_GE(1, ++request_count_);
463 EndTest();
466 void BeginTest() override {
467 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
468 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(2));
471 scoped_ptr<OutputSurface> CreateOutputSurface() override {
472 EXPECT_TRUE(false);
473 return nullptr;
476 void DidInitializeOutputSurface() override { EXPECT_TRUE(false); }
478 void AfterTest() override {}
480 int request_count_;
483 // This test uses Composite() which only exists for single thread.
484 SINGLE_THREAD_TEST_F(MultipleCompositeDoesNotCreateOutputSurface);
486 // This test makes sure that once a SingleThreadProxy issues a
487 // DidFailToInitializeOutputSurface, that future Composite calls will not
488 // trigger additional requests for output surfaces.
489 class FailedCreateDoesNotCreateExtraOutputSurface
490 : public LayerTreeHostContextTest {
491 public:
492 FailedCreateDoesNotCreateExtraOutputSurface()
493 : LayerTreeHostContextTest(), num_requests_(0), has_failed_(false) {}
495 void InitializeSettings(LayerTreeSettings* settings) override {
496 settings->single_thread_proxy_scheduler = false;
497 settings->use_zero_copy = true;
500 void RequestNewOutputSurface() override {
501 num_requests_++;
502 // There should be one initial request and then one request from
503 // the LayerTreeTest test hooks DidFailToInitializeOutputSurface (which is
504 // hard to skip). This second request is just ignored and is test cruft.
505 EXPECT_LE(num_requests_, 2);
506 if (num_requests_ > 1)
507 return;
508 ExpectCreateToFail();
509 layer_tree_host()->SetOutputSurface(
510 make_scoped_ptr(new FailureOutputSurface(false)));
513 void BeginTest() override {
514 // First composite tries to create a surface.
515 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
516 EXPECT_EQ(num_requests_, 2);
517 EXPECT_TRUE(has_failed_);
519 // Second composite should not request or fail.
520 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(2));
521 EXPECT_EQ(num_requests_, 2);
522 EndTest();
525 void DidInitializeOutputSurface() override { EXPECT_TRUE(false); }
527 void DidFailToInitializeOutputSurface() override {
528 LayerTreeHostContextTest::DidFailToInitializeOutputSurface();
529 EXPECT_FALSE(has_failed_);
530 has_failed_ = true;
533 void AfterTest() override {}
535 int num_requests_;
536 bool has_failed_;
539 // This test uses Composite() which only exists for single thread.
540 SINGLE_THREAD_TEST_F(FailedCreateDoesNotCreateExtraOutputSurface);
542 class LayerTreeHostContextTestCommitAfterDelayedOutputSurface
543 : public LayerTreeHostContextTest {
544 public:
545 LayerTreeHostContextTestCommitAfterDelayedOutputSurface()
546 : LayerTreeHostContextTest(), creating_output_(false) {}
548 void InitializeSettings(LayerTreeSettings* settings) override {
549 settings->single_thread_proxy_scheduler = false;
550 settings->use_zero_copy = true;
553 void RequestNewOutputSurface() override {
554 MainThreadTaskRunner()->PostTask(
555 FROM_HERE,
556 base::Bind(&LayerTreeHostContextTestCommitAfterDelayedOutputSurface::
557 CreateAndSetOutputSurface,
558 base::Unretained(this)));
561 void CreateAndSetOutputSurface() {
562 creating_output_ = true;
563 layer_tree_host()->SetOutputSurface(
564 LayerTreeHostContextTest::CreateOutputSurface());
567 void BeginTest() override {
568 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
571 void ScheduleComposite() override {
572 if (creating_output_)
573 EndTest();
576 void AfterTest() override {}
578 bool creating_output_;
581 // This test uses Composite() which only exists for single thread.
582 SINGLE_THREAD_TEST_F(LayerTreeHostContextTestCommitAfterDelayedOutputSurface);
584 class LayerTreeHostContextTestAvoidUnnecessaryComposite
585 : public LayerTreeHostContextTest {
586 public:
587 LayerTreeHostContextTestAvoidUnnecessaryComposite()
588 : LayerTreeHostContextTest(), in_composite_(false) {}
590 void InitializeSettings(LayerTreeSettings* settings) override {
591 settings->single_thread_proxy_scheduler = false;
592 settings->use_zero_copy = true;
595 void RequestNewOutputSurface() override {
596 layer_tree_host()->SetOutputSurface(
597 LayerTreeHostContextTest::CreateOutputSurface());
598 EndTest();
601 void BeginTest() override {
602 in_composite_ = true;
603 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
604 in_composite_ = false;
607 void ScheduleComposite() override { EXPECT_FALSE(in_composite_); }
609 void AfterTest() override {}
611 bool in_composite_;
614 // This test uses Composite() which only exists for single thread.
615 SINGLE_THREAD_TEST_F(LayerTreeHostContextTestAvoidUnnecessaryComposite);
617 // This test uses PictureLayer to check for a working context.
618 class LayerTreeHostContextTestLostContextSucceedsWithContent
619 : public LayerTreeHostContextTestLostContextSucceeds {
620 public:
621 void SetupTree() override {
622 root_ = Layer::Create(layer_settings());
623 root_->SetBounds(gfx::Size(10, 10));
624 root_->SetIsDrawable(true);
626 // Paint non-solid color.
627 SkPaint paint;
628 paint.setColor(SkColorSetARGB(100, 80, 200, 200));
629 client_.add_draw_rect(gfx::Rect(5, 5), paint);
631 layer_ = FakePictureLayer::Create(layer_settings(), &client_);
632 layer_->SetBounds(gfx::Size(10, 10));
633 layer_->SetIsDrawable(true);
635 root_->AddChild(layer_);
637 layer_tree_host()->SetRootLayer(root_);
638 LayerTreeHostContextTest::SetupTree();
641 void InvalidateAndSetNeedsCommit() override {
642 // Invalidate the render surface so we don't try to use a cached copy of the
643 // surface. We want to make sure to test the drawing paths for drawing to
644 // a child surface.
645 layer_->SetNeedsDisplay();
646 LayerTreeHostContextTestLostContextSucceeds::InvalidateAndSetNeedsCommit();
649 void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
650 FakePictureLayerImpl* picture_impl = static_cast<FakePictureLayerImpl*>(
651 host_impl->active_tree()->root_layer()->children()[0]);
652 EXPECT_TRUE(picture_impl->HighResTiling()
653 ->TileAt(0, 0)
654 ->draw_info()
655 .IsReadyToDraw());
658 protected:
659 FakeContentLayerClient client_;
660 scoped_refptr<Layer> root_;
661 scoped_refptr<Layer> layer_;
664 SINGLE_AND_MULTI_THREAD_TEST_F(
665 LayerTreeHostContextTestLostContextSucceedsWithContent);
667 class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
668 : public LayerTreeHostContextTest {
669 public:
670 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
671 : times_to_fail_(1), times_initialized_(0) {
672 times_to_fail_create_ = times_to_fail_;
675 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
677 void DidInitializeOutputSurface() override { times_initialized_++; }
679 void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { EndTest(); }
681 void AfterTest() override {
682 EXPECT_EQ(times_to_fail_, times_create_failed_);
683 EXPECT_NE(0, times_initialized_);
686 private:
687 int times_to_fail_;
688 int times_initialized_;
691 SINGLE_AND_MULTI_THREAD_TEST_F(
692 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce);
694 class LayerTreeHostContextTestLostContextAndEvictTextures
695 : public LayerTreeHostContextTest {
696 public:
697 LayerTreeHostContextTestLostContextAndEvictTextures()
698 : LayerTreeHostContextTest(),
699 impl_host_(0),
700 num_commits_(0),
701 lost_context_(false) {}
703 void SetupTree() override {
704 // Paint non-solid color.
705 SkPaint paint;
706 paint.setColor(SkColorSetARGB(100, 80, 200, 200));
707 client_.add_draw_rect(gfx::Rect(5, 5), paint);
709 scoped_refptr<FakePictureLayer> picture_layer =
710 FakePictureLayer::Create(layer_settings(), &client_);
711 picture_layer->SetBounds(gfx::Size(10, 20));
712 layer_tree_host()->SetRootLayer(picture_layer);
714 LayerTreeHostContextTest::SetupTree();
717 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
719 void PostEvictTextures() {
720 if (HasImplThread()) {
721 ImplThreadTaskRunner()->PostTask(
722 FROM_HERE,
723 base::Bind(&LayerTreeHostContextTestLostContextAndEvictTextures::
724 EvictTexturesOnImplThread,
725 base::Unretained(this)));
726 } else {
727 DebugScopedSetImplThread impl(proxy());
728 EvictTexturesOnImplThread();
732 void EvictTexturesOnImplThread() {
733 impl_host_->EvictTexturesForTesting();
735 if (lose_after_evict_) {
736 LoseContext();
737 lost_context_ = true;
741 void DidCommitAndDrawFrame() override {
742 if (num_commits_ > 1)
743 return;
744 PostEvictTextures();
747 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
748 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
749 if (num_commits_ > 1)
750 return;
751 ++num_commits_;
752 if (!lose_after_evict_) {
753 LoseContext();
754 lost_context_ = true;
758 void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
759 FakePictureLayerImpl* picture_impl =
760 static_cast<FakePictureLayerImpl*>(impl->active_tree()->root_layer());
761 EXPECT_TRUE(picture_impl->HighResTiling()
762 ->TileAt(0, 0)
763 ->draw_info()
764 .IsReadyToDraw());
766 impl_host_ = impl;
767 if (lost_context_)
768 EndTest();
771 void DidInitializeOutputSurface() override {}
773 void AfterTest() override {}
775 protected:
776 bool lose_after_evict_;
777 FakeContentLayerClient client_;
778 LayerTreeHostImpl* impl_host_;
779 int num_commits_;
780 bool lost_context_;
783 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
784 LoseAfterEvict_SingleThread_DirectRenderer) {
785 lose_after_evict_ = true;
786 RunTest(false, false);
789 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
790 LoseAfterEvict_SingleThread_DelegatingRenderer) {
791 lose_after_evict_ = true;
792 RunTest(false, true);
795 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
796 LoseAfterEvict_MultiThread_DirectRenderer) {
797 lose_after_evict_ = true;
798 RunTest(true, false);
801 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
802 LoseAfterEvict_MultiThread_DelegatingRenderer) {
803 lose_after_evict_ = true;
804 RunTest(true, true);
807 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
808 LoseBeforeEvict_SingleThread_DirectRenderer) {
809 lose_after_evict_ = false;
810 RunTest(false, false);
813 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
814 LoseBeforeEvict_SingleThread_DelegatingRenderer) {
815 lose_after_evict_ = false;
816 RunTest(false, true);
819 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
820 LoseBeforeEvict_MultiThread_DirectRenderer) {
821 lose_after_evict_ = false;
822 RunTest(true, false);
825 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
826 LoseBeforeEvict_MultiThread_DelegatingRenderer) {
827 lose_after_evict_ = false;
828 RunTest(true, true);
831 class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
832 public:
833 LayerTreeHostContextTestLayersNotified()
834 : LayerTreeHostContextTest(), num_commits_(0) {}
836 void SetupTree() override {
837 root_ = FakePictureLayer::Create(layer_settings(), &client_);
838 child_ = FakePictureLayer::Create(layer_settings(), &client_);
839 grandchild_ = FakePictureLayer::Create(layer_settings(), &client_);
841 root_->AddChild(child_);
842 child_->AddChild(grandchild_);
844 layer_tree_host()->SetRootLayer(root_);
845 LayerTreeHostContextTest::SetupTree();
848 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
850 void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
851 LayerTreeHostContextTest::DidActivateTreeOnThread(host_impl);
853 FakePictureLayerImpl* root_picture = NULL;
854 FakePictureLayerImpl* child_picture = NULL;
855 FakePictureLayerImpl* grandchild_picture = NULL;
857 root_picture = static_cast<FakePictureLayerImpl*>(
858 host_impl->active_tree()->root_layer());
859 child_picture =
860 static_cast<FakePictureLayerImpl*>(root_picture->children()[0]);
861 grandchild_picture =
862 static_cast<FakePictureLayerImpl*>(child_picture->children()[0]);
864 ++num_commits_;
865 switch (num_commits_) {
866 case 1:
867 EXPECT_EQ(0u, root_picture->release_resources_count());
868 EXPECT_EQ(0u, child_picture->release_resources_count());
869 EXPECT_EQ(0u, grandchild_picture->release_resources_count());
871 // Lose the context and struggle to recreate it.
872 LoseContext();
873 times_to_fail_create_ = 1;
874 break;
875 case 2:
876 EXPECT_TRUE(root_picture->release_resources_count());
877 EXPECT_TRUE(child_picture->release_resources_count());
878 EXPECT_TRUE(grandchild_picture->release_resources_count());
880 EndTest();
881 break;
882 default:
883 NOTREACHED();
887 void AfterTest() override {}
889 private:
890 int num_commits_;
892 FakeContentLayerClient client_;
893 scoped_refptr<Layer> root_;
894 scoped_refptr<Layer> child_;
895 scoped_refptr<Layer> grandchild_;
898 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified);
900 class LayerTreeHostContextTestDontUseLostResources
901 : public LayerTreeHostContextTest {
902 public:
903 LayerTreeHostContextTestDontUseLostResources() : lost_context_(false) {
904 context_should_support_io_surface_ = true;
906 child_output_surface_ = FakeOutputSurface::Create3d();
907 child_output_surface_->BindToClient(&output_surface_client_);
908 shared_bitmap_manager_.reset(new TestSharedBitmapManager());
909 child_resource_provider_ = FakeResourceProvider::Create(
910 child_output_surface_.get(), shared_bitmap_manager_.get());
913 static void EmptyReleaseCallback(unsigned sync_point, bool lost) {}
915 void SetupTree() override {
916 gpu::gles2::GLES2Interface* gl =
917 child_output_surface_->context_provider()->ContextGL();
919 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
921 scoped_ptr<RenderPass> pass_for_quad = RenderPass::Create();
922 pass_for_quad->SetNew(
923 // AppendOneOfEveryQuadType() makes a RenderPass quad with this id.
924 RenderPassId(2, 1),
925 gfx::Rect(0, 0, 10, 10),
926 gfx::Rect(0, 0, 10, 10),
927 gfx::Transform());
929 scoped_ptr<RenderPass> pass = RenderPass::Create();
930 pass->SetNew(RenderPassId(1, 1),
931 gfx::Rect(0, 0, 10, 10),
932 gfx::Rect(0, 0, 10, 10),
933 gfx::Transform());
934 uint32_t mailbox_sync_point;
935 AddOneOfEveryQuadType(pass.get(), child_resource_provider_.get(),
936 RenderPassId(2, 1), &mailbox_sync_point);
938 frame_data->render_pass_list.push_back(pass_for_quad.Pass());
939 frame_data->render_pass_list.push_back(pass.Pass());
941 delegated_resource_collection_ = new DelegatedFrameResourceCollection;
942 delegated_frame_provider_ = new DelegatedFrameProvider(
943 delegated_resource_collection_.get(), frame_data.Pass());
945 ResourceId resource = child_resource_provider_->CreateResource(
946 gfx::Size(4, 4), GL_CLAMP_TO_EDGE,
947 ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
948 ResourceProvider::ScopedWriteLockGL lock(child_resource_provider_.get(),
949 resource);
951 gpu::Mailbox mailbox;
952 gl->GenMailboxCHROMIUM(mailbox.name);
953 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
955 scoped_refptr<Layer> root = Layer::Create(layer_settings());
956 root->SetBounds(gfx::Size(10, 10));
957 root->SetIsDrawable(true);
959 scoped_refptr<FakeDelegatedRendererLayer> delegated =
960 FakeDelegatedRendererLayer::Create(layer_settings(),
961 delegated_frame_provider_.get());
962 delegated->SetBounds(gfx::Size(10, 10));
963 delegated->SetIsDrawable(true);
964 root->AddChild(delegated);
966 scoped_refptr<PictureLayer> layer =
967 PictureLayer::Create(layer_settings(), &client_);
968 layer->SetBounds(gfx::Size(10, 10));
969 layer->SetIsDrawable(true);
970 root->AddChild(layer);
972 scoped_refptr<TextureLayer> texture =
973 TextureLayer::CreateForMailbox(layer_settings_, NULL);
974 texture->SetBounds(gfx::Size(10, 10));
975 texture->SetIsDrawable(true);
976 texture->SetTextureMailbox(
977 TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point),
978 SingleReleaseCallback::Create(
979 base::Bind(&LayerTreeHostContextTestDontUseLostResources::
980 EmptyReleaseCallback)));
981 root->AddChild(texture);
983 scoped_refptr<PictureLayer> mask =
984 PictureLayer::Create(layer_settings_, &client_);
985 mask->SetBounds(gfx::Size(10, 10));
987 scoped_refptr<PictureLayer> layer_with_mask =
988 PictureLayer::Create(layer_settings_, &client_);
989 layer_with_mask->SetBounds(gfx::Size(10, 10));
990 layer_with_mask->SetIsDrawable(true);
991 layer_with_mask->SetMaskLayer(mask.get());
992 root->AddChild(layer_with_mask);
994 scoped_refptr<VideoLayer> video_color = VideoLayer::Create(
995 layer_settings_, &color_frame_provider_, media::VIDEO_ROTATION_0);
996 video_color->SetBounds(gfx::Size(10, 10));
997 video_color->SetIsDrawable(true);
998 root->AddChild(video_color);
1000 scoped_refptr<VideoLayer> video_hw = VideoLayer::Create(
1001 layer_settings_, &hw_frame_provider_, media::VIDEO_ROTATION_0);
1002 video_hw->SetBounds(gfx::Size(10, 10));
1003 video_hw->SetIsDrawable(true);
1004 root->AddChild(video_hw);
1006 scoped_refptr<VideoLayer> video_scaled_hw = VideoLayer::Create(
1007 layer_settings_, &scaled_hw_frame_provider_, media::VIDEO_ROTATION_0);
1008 video_scaled_hw->SetBounds(gfx::Size(10, 10));
1009 video_scaled_hw->SetIsDrawable(true);
1010 root->AddChild(video_scaled_hw);
1012 color_video_frame_ = VideoFrame::CreateColorFrame(
1013 gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
1014 hw_video_frame_ = VideoFrame::WrapNativeTexture(
1015 media::PIXEL_FORMAT_ARGB,
1016 gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, sync_point),
1017 media::VideoFrame::ReleaseMailboxCB(), gfx::Size(4, 4),
1018 gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4), base::TimeDelta());
1019 scaled_hw_video_frame_ = VideoFrame::WrapNativeTexture(
1020 media::PIXEL_FORMAT_ARGB,
1021 gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, sync_point),
1022 media::VideoFrame::ReleaseMailboxCB(), gfx::Size(4, 4),
1023 gfx::Rect(0, 0, 3, 2), gfx::Size(4, 4), base::TimeDelta());
1025 color_frame_provider_.set_frame(color_video_frame_);
1026 hw_frame_provider_.set_frame(hw_video_frame_);
1027 scaled_hw_frame_provider_.set_frame(scaled_hw_video_frame_);
1029 scoped_refptr<IOSurfaceLayer> io_surface =
1030 IOSurfaceLayer::Create(layer_settings_);
1031 io_surface->SetBounds(gfx::Size(10, 10));
1032 io_surface->SetIsDrawable(true);
1033 io_surface->SetIOSurfaceProperties(1, gfx::Size(10, 10));
1034 root->AddChild(io_surface);
1036 // Enable the hud.
1037 LayerTreeDebugState debug_state;
1038 debug_state.show_property_changed_rects = true;
1039 layer_tree_host()->SetDebugState(debug_state);
1041 scoped_refptr<PaintedScrollbarLayer> scrollbar =
1042 PaintedScrollbarLayer::Create(
1043 layer_settings_, scoped_ptr<Scrollbar>(new FakeScrollbar).Pass(),
1044 layer->id());
1045 scrollbar->SetBounds(gfx::Size(10, 10));
1046 scrollbar->SetIsDrawable(true);
1047 root->AddChild(scrollbar);
1049 layer_tree_host()->SetRootLayer(root);
1050 LayerTreeHostContextTest::SetupTree();
1053 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
1055 void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
1056 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
1058 if (host_impl->active_tree()->source_frame_number() == 3) {
1059 // On the third commit we're recovering from context loss. Hardware
1060 // video frames should not be reused by the VideoFrameProvider, but
1061 // software frames can be.
1062 hw_frame_provider_.set_frame(NULL);
1063 scaled_hw_frame_provider_.set_frame(NULL);
1067 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
1068 LayerTreeHostImpl::FrameData* frame,
1069 DrawResult draw_result) override {
1070 if (host_impl->active_tree()->source_frame_number() == 2) {
1071 // Lose the context during draw on the second commit. This will cause
1072 // a third commit to recover.
1073 context3d_->set_times_bind_texture_succeeds(0);
1075 return draw_result;
1078 scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
1079 // This will get called twice:
1080 // First when we create the initial output surface...
1081 if (layer_tree_host()->source_frame_number() > 0) {
1082 // ... and then again after we forced the context to be lost.
1083 lost_context_ = true;
1085 return LayerTreeHostContextTest::CreateFakeOutputSurface();
1088 void DidCommitAndDrawFrame() override {
1089 ASSERT_TRUE(layer_tree_host()->hud_layer());
1090 // End the test once we know the 3nd frame drew.
1091 if (layer_tree_host()->source_frame_number() < 5) {
1092 layer_tree_host()->root_layer()->SetNeedsDisplay();
1093 layer_tree_host()->SetNeedsCommit();
1094 } else {
1095 EndTest();
1099 void AfterTest() override { EXPECT_TRUE(lost_context_); }
1101 private:
1102 FakeContentLayerClient client_;
1103 bool lost_context_;
1105 FakeOutputSurfaceClient output_surface_client_;
1106 scoped_ptr<FakeOutputSurface> child_output_surface_;
1107 scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
1108 scoped_ptr<ResourceProvider> child_resource_provider_;
1110 scoped_refptr<DelegatedFrameResourceCollection>
1111 delegated_resource_collection_;
1112 scoped_refptr<DelegatedFrameProvider> delegated_frame_provider_;
1114 scoped_refptr<VideoFrame> color_video_frame_;
1115 scoped_refptr<VideoFrame> hw_video_frame_;
1116 scoped_refptr<VideoFrame> scaled_hw_video_frame_;
1118 FakeVideoFrameProvider color_frame_provider_;
1119 FakeVideoFrameProvider hw_frame_provider_;
1120 FakeVideoFrameProvider scaled_hw_frame_provider_;
1122 LayerSettings layer_settings_;
1125 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources);
1127 class LayerTreeHostContextTestImplSidePainting
1128 : public LayerTreeHostContextTest {
1129 public:
1130 void SetupTree() override {
1131 scoped_refptr<Layer> root = Layer::Create(layer_settings());
1132 root->SetBounds(gfx::Size(10, 10));
1133 root->SetIsDrawable(true);
1135 scoped_refptr<PictureLayer> picture =
1136 PictureLayer::Create(layer_settings(), &client_);
1137 picture->SetBounds(gfx::Size(10, 10));
1138 picture->SetIsDrawable(true);
1139 root->AddChild(picture);
1141 layer_tree_host()->SetRootLayer(root);
1142 LayerTreeHostContextTest::SetupTree();
1145 void BeginTest() override {
1146 times_to_lose_during_commit_ = 1;
1147 PostSetNeedsCommitToMainThread();
1150 void AfterTest() override {}
1152 void DidInitializeOutputSurface() override { EndTest(); }
1154 private:
1155 FakeContentLayerClient client_;
1158 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting);
1160 class ScrollbarLayerLostContext : public LayerTreeHostContextTest {
1161 public:
1162 ScrollbarLayerLostContext() : commits_(0) {}
1164 void BeginTest() override {
1165 scoped_refptr<Layer> scroll_layer = Layer::Create(layer_settings());
1166 scrollbar_layer_ = FakePaintedScrollbarLayer::Create(
1167 layer_settings(), false, true, scroll_layer->id());
1168 scrollbar_layer_->SetBounds(gfx::Size(10, 100));
1169 layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
1170 layer_tree_host()->root_layer()->AddChild(scroll_layer);
1171 PostSetNeedsCommitToMainThread();
1174 void AfterTest() override {}
1176 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
1177 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1179 ++commits_;
1180 switch (commits_) {
1181 case 1:
1182 // First (regular) update, we should upload 2 resources (thumb, and
1183 // backtrack).
1184 EXPECT_EQ(1, scrollbar_layer_->update_count());
1185 LoseContext();
1186 break;
1187 case 2:
1188 // Second update, after the lost context, we should still upload 2
1189 // resources even if the contents haven't changed.
1190 EXPECT_EQ(2, scrollbar_layer_->update_count());
1191 EndTest();
1192 break;
1193 default:
1194 NOTREACHED();
1198 private:
1199 int commits_;
1200 scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer_;
1203 SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext);
1205 class UIResourceLostTest : public LayerTreeHostContextTest {
1206 public:
1207 UIResourceLostTest() : time_step_(0) {}
1208 void InitializeSettings(LayerTreeSettings* settings) override {
1209 settings->renderer_settings.texture_id_allocation_chunk_size = 1;
1211 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
1212 void AfterTest() override {}
1214 // This is called on the main thread after each commit and
1215 // DidActivateTreeOnThread, with the value of time_step_ at the time
1216 // of the call to DidActivateTreeOnThread. Similar tests will do
1217 // work on the main thread in DidCommit but that is unsuitable because
1218 // the main thread work for these tests must happen after
1219 // DidActivateTreeOnThread, which happens after DidCommit with impl-side
1220 // painting.
1221 virtual void StepCompleteOnMainThread(int time_step) = 0;
1223 // Called after DidActivateTreeOnThread. If this is done during the commit,
1224 // the call to StepCompleteOnMainThread will not occur until after
1225 // the commit completes, because the main thread is blocked.
1226 void PostStepCompleteToMainThread() {
1227 proxy()->MainThreadTaskRunner()->PostTask(
1228 FROM_HERE,
1229 base::Bind(&UIResourceLostTest::StepCompleteOnMainThreadInternal,
1230 base::Unretained(this),
1231 time_step_));
1234 void PostLoseContextToImplThread() {
1235 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1236 ImplThreadTaskRunner()->PostTask(
1237 FROM_HERE,
1238 base::Bind(&LayerTreeHostContextTest::LoseContext,
1239 base::Unretained(this)));
1242 protected:
1243 int time_step_;
1244 scoped_ptr<FakeScopedUIResource> ui_resource_;
1246 private:
1247 void StepCompleteOnMainThreadInternal(int step) {
1248 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1249 StepCompleteOnMainThread(step);
1253 class UIResourceLostTestSimple : public UIResourceLostTest {
1254 public:
1255 // This is called when the new layer tree has been activated.
1256 virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) = 0;
1258 void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
1259 StepCompleteOnImplThread(impl);
1260 PostStepCompleteToMainThread();
1261 ++time_step_;
1265 // Losing context after an UI resource has been created.
1266 class UIResourceLostAfterCommit : public UIResourceLostTestSimple {
1267 public:
1268 void StepCompleteOnMainThread(int step) override {
1269 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1270 switch (step) {
1271 case 0:
1272 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1273 // Expects a valid UIResourceId.
1274 EXPECT_NE(0, ui_resource_->id());
1275 PostSetNeedsCommitToMainThread();
1276 break;
1277 case 4:
1278 // Release resource before ending the test.
1279 ui_resource_ = nullptr;
1280 EndTest();
1281 break;
1282 case 5:
1283 NOTREACHED();
1284 break;
1288 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override {
1289 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1290 switch (time_step_) {
1291 case 1:
1292 // The resource should have been created on LTHI after the commit.
1293 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1294 PostSetNeedsCommitToMainThread();
1295 break;
1296 case 2:
1297 LoseContext();
1298 break;
1299 case 3:
1300 // The resources should have been recreated. The bitmap callback should
1301 // have been called once with the resource_lost flag set to true.
1302 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1303 // Resource Id on the impl-side have been recreated as well. Note
1304 // that the same UIResourceId persists after the context lost.
1305 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1306 PostSetNeedsCommitToMainThread();
1307 break;
1312 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostAfterCommit);
1314 // Losing context before UI resource requests can be commited. Three sequences
1315 // of creation/deletion are considered:
1316 // 1. Create one resource -> Context Lost => Expect the resource to have been
1317 // created.
1318 // 2. Delete an exisiting resource (test_id0_) -> create a second resource
1319 // (test_id1_) -> Context Lost => Expect the test_id0_ to be removed and
1320 // test_id1_ to have been created.
1321 // 3. Create one resource -> Delete that same resource -> Context Lost => Expect
1322 // the resource to not exist in the manager.
1323 class UIResourceLostBeforeCommit : public UIResourceLostTestSimple {
1324 public:
1325 UIResourceLostBeforeCommit() : test_id0_(0), test_id1_(0) {}
1327 void StepCompleteOnMainThread(int step) override {
1328 switch (step) {
1329 case 0:
1330 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1331 // Lose the context on the impl thread before the commit.
1332 PostLoseContextToImplThread();
1333 break;
1334 case 2:
1335 // Sequence 2:
1336 // Currently one resource has been created.
1337 test_id0_ = ui_resource_->id();
1338 // Delete this resource.
1339 ui_resource_ = nullptr;
1340 // Create another resource.
1341 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1342 test_id1_ = ui_resource_->id();
1343 // Sanity check that two resource creations return different ids.
1344 EXPECT_NE(test_id0_, test_id1_);
1345 // Lose the context on the impl thread before the commit.
1346 PostLoseContextToImplThread();
1347 break;
1348 case 3:
1349 // Clear the manager of resources.
1350 ui_resource_ = nullptr;
1351 PostSetNeedsCommitToMainThread();
1352 break;
1353 case 4:
1354 // Sequence 3:
1355 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1356 test_id0_ = ui_resource_->id();
1357 // Sanity check the UIResourceId should not be 0.
1358 EXPECT_NE(0, test_id0_);
1359 // Usually ScopedUIResource are deleted from the manager in their
1360 // destructor (so usually ui_resource_ = nullptr). But here we need
1361 // ui_resource_ for the next step, so call DeleteUIResource directly.
1362 layer_tree_host()->DeleteUIResource(test_id0_);
1363 // Delete the resouce and then lose the context.
1364 PostLoseContextToImplThread();
1365 break;
1366 case 5:
1367 // Release resource before ending the test.
1368 ui_resource_ = nullptr;
1369 EndTest();
1370 break;
1371 case 6:
1372 NOTREACHED();
1373 break;
1377 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override {
1378 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1379 switch (time_step_) {
1380 case 1:
1381 // Sequence 1 (continued):
1382 // The first context lost happens before the resources were created,
1383 // and because it resulted in no resources being destroyed, it does not
1384 // trigger resource re-creation.
1385 EXPECT_EQ(1, ui_resource_->resource_create_count);
1386 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1387 // Resource Id on the impl-side has been created.
1388 PostSetNeedsCommitToMainThread();
1389 break;
1390 case 3:
1391 // Sequence 2 (continued):
1392 // The previous resource should have been deleted.
1393 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
1394 // The second resource should have been created.
1395 EXPECT_NE(0u, impl->ResourceIdForUIResource(test_id1_));
1396 // The second resource called the resource callback once and since the
1397 // context is lost, a "resource lost" callback was also issued.
1398 EXPECT_EQ(2, ui_resource_->resource_create_count);
1399 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1400 break;
1401 case 5:
1402 // Sequence 3 (continued):
1403 // Expect the resource callback to have been called once.
1404 EXPECT_EQ(1, ui_resource_->resource_create_count);
1405 // No "resource lost" callbacks.
1406 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1407 // The UI resource id should not be valid
1408 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
1409 break;
1413 private:
1414 UIResourceId test_id0_;
1415 UIResourceId test_id1_;
1418 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeCommit);
1420 // Losing UI resource before the pending trees is activated but after the
1421 // commit. Impl-side-painting only.
1422 class UIResourceLostBeforeActivateTree : public UIResourceLostTest {
1423 void StepCompleteOnMainThread(int step) override {
1424 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1425 switch (step) {
1426 case 0:
1427 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1428 PostSetNeedsCommitToMainThread();
1429 break;
1430 case 3:
1431 test_id_ = ui_resource_->id();
1432 ui_resource_ = nullptr;
1433 PostSetNeedsCommitToMainThread();
1434 break;
1435 case 5:
1436 // Release resource before ending the test.
1437 ui_resource_ = nullptr;
1438 EndTest();
1439 break;
1440 case 6:
1441 // Make sure no extra commits happened.
1442 NOTREACHED();
1446 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
1447 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1448 switch (time_step_) {
1449 case 2:
1450 PostSetNeedsCommitToMainThread();
1451 break;
1452 case 4:
1453 PostSetNeedsCommitToMainThread();
1454 break;
1458 void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override {
1459 switch (time_step_) {
1460 case 1:
1461 // The resource creation callback has been called.
1462 EXPECT_EQ(1, ui_resource_->resource_create_count);
1463 // The resource is not yet lost (sanity check).
1464 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1465 // The resource should not have been created yet on the impl-side.
1466 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1467 LoseContext();
1468 break;
1469 case 3:
1470 LoseContext();
1471 break;
1475 void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
1476 LayerTreeHostContextTest::DidActivateTreeOnThread(impl);
1477 switch (time_step_) {
1478 case 1:
1479 // The pending requests on the impl-side should have been processed.
1480 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1481 break;
1482 case 2:
1483 // The "lost resource" callback should have been called once.
1484 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1485 break;
1486 case 4:
1487 // The resource is deleted and should not be in the manager. Use
1488 // test_id_ since ui_resource_ has been deleted.
1489 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id_));
1490 break;
1493 PostStepCompleteToMainThread();
1494 ++time_step_;
1497 private:
1498 UIResourceId test_id_;
1501 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeActivateTree);
1503 // Resources evicted explicitly and by visibility changes.
1504 class UIResourceLostEviction : public UIResourceLostTestSimple {
1505 public:
1506 void StepCompleteOnMainThread(int step) override {
1507 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1508 switch (step) {
1509 case 0:
1510 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1511 EXPECT_NE(0, ui_resource_->id());
1512 PostSetNeedsCommitToMainThread();
1513 break;
1514 case 2:
1515 // Make the tree not visible.
1516 PostSetVisibleToMainThread(false);
1517 break;
1518 case 3:
1519 // Release resource before ending the test.
1520 ui_resource_ = nullptr;
1521 EndTest();
1522 break;
1523 case 4:
1524 NOTREACHED();
1528 void DidSetVisibleOnImplTree(LayerTreeHostImpl* impl, bool visible) override {
1529 TestWebGraphicsContext3D* context = TestContext();
1530 if (!visible) {
1531 // All resources should have been evicted.
1532 ASSERT_EQ(0u, context->NumTextures());
1533 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1534 EXPECT_EQ(2, ui_resource_->resource_create_count);
1535 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1536 // Drawing is disabled both because of the evicted resources and
1537 // because the renderer is not visible.
1538 EXPECT_FALSE(impl->CanDraw());
1539 // Make the renderer visible again.
1540 PostSetVisibleToMainThread(true);
1544 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override {
1545 TestWebGraphicsContext3D* context = TestContext();
1546 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1547 switch (time_step_) {
1548 case 1:
1549 // The resource should have been created on LTHI after the commit.
1550 ASSERT_EQ(1u, context->NumTextures());
1551 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1552 EXPECT_EQ(1, ui_resource_->resource_create_count);
1553 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1554 EXPECT_TRUE(impl->CanDraw());
1555 // Evict all UI resources. This will trigger a commit.
1556 impl->EvictAllUIResources();
1557 ASSERT_EQ(0u, context->NumTextures());
1558 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1559 EXPECT_EQ(1, ui_resource_->resource_create_count);
1560 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1561 EXPECT_FALSE(impl->CanDraw());
1562 break;
1563 case 2:
1564 // The resource should have been recreated.
1565 ASSERT_EQ(1u, context->NumTextures());
1566 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1567 EXPECT_EQ(2, ui_resource_->resource_create_count);
1568 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1569 EXPECT_TRUE(impl->CanDraw());
1570 break;
1571 case 3:
1572 // The resource should have been recreated after visibility was
1573 // restored.
1574 ASSERT_EQ(1u, context->NumTextures());
1575 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1576 EXPECT_EQ(3, ui_resource_->resource_create_count);
1577 EXPECT_EQ(2, ui_resource_->lost_resource_count);
1578 EXPECT_TRUE(impl->CanDraw());
1579 break;
1584 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction);
1586 class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame
1587 : public LayerTreeHostContextTest {
1588 protected:
1589 void BeginTest() override {
1590 deferred_ = false;
1591 PostSetNeedsCommitToMainThread();
1594 void ScheduledActionWillSendBeginMainFrame() override {
1595 if (deferred_)
1596 return;
1597 deferred_ = true;
1599 // Defer commits before the BeginFrame arrives, causing it to be delayed.
1600 PostSetDeferCommitsToMainThread(true);
1601 // Meanwhile, lose the context while we are in defer commits.
1602 ImplThreadTaskRunner()->PostTask(
1603 FROM_HERE,
1604 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1605 LoseContextOnImplThread,
1606 base::Unretained(this)));
1609 void LoseContextOnImplThread() {
1610 LoseContext();
1612 // After losing the context, stop deferring commits.
1613 PostSetDeferCommitsToMainThread(false);
1616 void WillBeginMainFrame() override {
1617 // Don't begin a frame with a lost surface.
1618 EXPECT_FALSE(layer_tree_host()->output_surface_lost());
1621 void DidCommitAndDrawFrame() override { EndTest(); }
1623 void AfterTest() override {}
1625 bool deferred_;
1628 SINGLE_AND_MULTI_THREAD_TEST_F(
1629 LayerTreeHostContextTestLoseAfterSendingBeginMainFrame);
1631 } // namespace
1632 } // namespace cc