Include all dupe types (event when value is zero) in scan stats.
[chromium-blink-merge.git] / cc / trees / layer_tree_host_unittest_context.cc
blobe4402601687db6b803fab1d5e91b4ca421369270
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/trees/layer_tree_host.h"
7 #include "base/basictypes.h"
8 #include "cc/layers/content_layer.h"
9 #include "cc/layers/delegated_frame_provider.h"
10 #include "cc/layers/delegated_frame_resource_collection.h"
11 #include "cc/layers/heads_up_display_layer.h"
12 #include "cc/layers/io_surface_layer.h"
13 #include "cc/layers/layer_impl.h"
14 #include "cc/layers/painted_scrollbar_layer.h"
15 #include "cc/layers/picture_layer.h"
16 #include "cc/layers/texture_layer.h"
17 #include "cc/layers/texture_layer_impl.h"
18 #include "cc/layers/video_layer.h"
19 #include "cc/layers/video_layer_impl.h"
20 #include "cc/output/filter_operations.h"
21 #include "cc/resources/single_release_callback.h"
22 #include "cc/test/failure_output_surface.h"
23 #include "cc/test/fake_content_layer.h"
24 #include "cc/test/fake_content_layer_client.h"
25 #include "cc/test/fake_content_layer_impl.h"
26 #include "cc/test/fake_delegated_renderer_layer.h"
27 #include "cc/test/fake_delegated_renderer_layer_impl.h"
28 #include "cc/test/fake_layer_tree_host_client.h"
29 #include "cc/test/fake_output_surface.h"
30 #include "cc/test/fake_output_surface_client.h"
31 #include "cc/test/fake_painted_scrollbar_layer.h"
32 #include "cc/test/fake_picture_layer.h"
33 #include "cc/test/fake_picture_layer_impl.h"
34 #include "cc/test/fake_resource_provider.h"
35 #include "cc/test/fake_scoped_ui_resource.h"
36 #include "cc/test/fake_scrollbar.h"
37 #include "cc/test/fake_video_frame_provider.h"
38 #include "cc/test/layer_tree_test.h"
39 #include "cc/test/render_pass_test_common.h"
40 #include "cc/test/test_context_provider.h"
41 #include "cc/test/test_shared_bitmap_manager.h"
42 #include "cc/test/test_web_graphics_context_3d.h"
43 #include "cc/trees/layer_tree_host_impl.h"
44 #include "cc/trees/layer_tree_impl.h"
45 #include "cc/trees/single_thread_proxy.h"
46 #include "gpu/GLES2/gl2extchromium.h"
47 #include "media/base/media.h"
49 using media::VideoFrame;
51 namespace cc {
52 namespace {
54 // These tests deal with losing the 3d graphics context.
55 class LayerTreeHostContextTest : public LayerTreeTest {
56 public:
57 LayerTreeHostContextTest()
58 : LayerTreeTest(),
59 context3d_(NULL),
60 times_to_fail_create_(0),
61 times_to_lose_during_commit_(0),
62 times_to_lose_during_draw_(0),
63 times_to_fail_recreate_(0),
64 times_to_expect_create_failed_(0),
65 times_create_failed_(0),
66 committed_at_least_once_(false),
67 context_should_support_io_surface_(false),
68 fallback_context_works_(false),
69 async_output_surface_creation_(false) {
70 media::InitializeMediaLibraryForTesting();
73 void LoseContext() {
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 context3d_ = context3d.get();
96 if (context_should_support_io_surface_) {
97 context3d_->set_have_extension_io_surface(true);
98 context3d_->set_have_extension_egl_image(true);
101 if (delegating_renderer())
102 return FakeOutputSurface::CreateDelegating3d(context3d.Pass());
103 else
104 return FakeOutputSurface::Create3d(context3d.Pass());
107 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
108 LayerTreeHostImpl::FrameData* frame,
109 DrawResult draw_result) override {
110 if (draw_result == DRAW_ABORTED_MISSING_HIGH_RES_CONTENT) {
111 // Only valid for single-threaded impl-side painting, which activates
112 // immediately and will try to draw again when content has finished.
113 DCHECK(!host_impl->proxy()->HasImplThread());
114 DCHECK(host_impl->settings().impl_side_painting);
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 TestWebGraphicsContext3D* context3d_;
153 int times_to_fail_create_;
154 int times_to_lose_during_commit_;
155 int times_to_lose_during_draw_;
156 int times_to_fail_recreate_;
157 int times_to_expect_create_failed_;
158 int times_create_failed_;
159 bool committed_at_least_once_;
160 bool context_should_support_io_surface_;
161 bool fallback_context_works_;
162 bool async_output_surface_creation_;
165 class LayerTreeHostContextTestLostContextSucceeds
166 : public LayerTreeHostContextTest {
167 public:
168 LayerTreeHostContextTestLostContextSucceeds()
169 : LayerTreeHostContextTest(),
170 test_case_(0),
171 num_losses_(0),
172 num_losses_last_test_case_(-1),
173 recovered_context_(true),
174 first_initialized_(false) {}
176 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
178 void RequestNewOutputSurface() override {
179 if (async_output_surface_creation_) {
180 MainThreadTaskRunner()->PostTask(
181 FROM_HERE, base::Bind(&LayerTreeHostContextTestLostContextSucceeds::
182 CreateAndSetOutputSurface,
183 base::Unretained(this)));
184 } else {
185 CreateAndSetOutputSurface();
189 void CreateAndSetOutputSurface() {
190 scoped_ptr<OutputSurface> surface(
191 LayerTreeHostContextTest::CreateOutputSurface());
192 CHECK(surface);
193 layer_tree_host()->SetOutputSurface(surface.Pass());
196 void DidInitializeOutputSurface() override {
197 if (first_initialized_)
198 ++num_losses_;
199 else
200 first_initialized_ = true;
202 recovered_context_ = true;
205 void AfterTest() override { EXPECT_EQ(11u, test_case_); }
207 void DidCommitAndDrawFrame() override {
208 // If the last frame had a context loss, then we'll commit again to
209 // recover.
210 if (!recovered_context_)
211 return;
212 if (times_to_lose_during_commit_)
213 return;
214 if (times_to_lose_during_draw_)
215 return;
217 recovered_context_ = false;
218 if (NextTestCase())
219 InvalidateAndSetNeedsCommit();
220 else
221 EndTest();
224 virtual void InvalidateAndSetNeedsCommit() {
225 // Cause damage so we try to draw.
226 layer_tree_host()->root_layer()->SetNeedsDisplay();
227 layer_tree_host()->SetNeedsCommit();
230 bool NextTestCase() {
231 static const TestCase kTests[] = {
232 // Losing the context and failing to recreate it (or losing it again
233 // immediately) a small number of times should succeed.
235 1, // times_to_lose_during_commit
236 0, // times_to_lose_during_draw
237 0, // times_to_fail_recreate
238 false, // fallback_context_works
239 false, // async_output_surface_creation
242 0, // times_to_lose_during_commit
243 1, // times_to_lose_during_draw
244 0, // times_to_fail_recreate
245 false, // fallback_context_works
246 false, // async_output_surface_creation
249 1, // times_to_lose_during_commit
250 0, // times_to_lose_during_draw
251 3, // times_to_fail_recreate
252 false, // fallback_context_works
253 false, // async_output_surface_creation
256 0, // times_to_lose_during_commit
257 1, // times_to_lose_during_draw
258 3, // times_to_fail_recreate
259 false, // fallback_context_works
260 false, // async_output_surface_creation
263 0, // times_to_lose_during_commit
264 1, // times_to_lose_during_draw
265 3, // times_to_fail_recreate
266 false, // fallback_context_works
267 true, // async_output_surface_creation
269 // Losing the context and recreating it any number of times should
270 // succeed.
272 10, // times_to_lose_during_commit
273 0, // times_to_lose_during_draw
274 0, // times_to_fail_recreate
275 false, // fallback_context_works
276 false, // async_output_surface_creation
279 0, // times_to_lose_during_commit
280 10, // times_to_lose_during_draw
281 0, // times_to_fail_recreate
282 false, // fallback_context_works
283 false, // async_output_surface_creation
286 10, // times_to_lose_during_commit
287 0, // times_to_lose_during_draw
288 0, // times_to_fail_recreate
289 false, // fallback_context_works
290 true, // async_output_surface_creation
293 0, // times_to_lose_during_commit
294 10, // times_to_lose_during_draw
295 0, // times_to_fail_recreate
296 false, // fallback_context_works
297 true, // async_output_surface_creation
299 // Losing the context, failing to reinitialize it, and making a fallback
300 // context should work.
302 0, // times_to_lose_during_commit
303 1, // times_to_lose_during_draw
304 0, // times_to_fail_recreate
305 true, // fallback_context_works
306 false, // async_output_surface_creation
309 0, // times_to_lose_during_commit
310 1, // times_to_lose_during_draw
311 0, // times_to_fail_recreate
312 true, // fallback_context_works
313 true, // async_output_surface_creation
317 if (test_case_ >= arraysize(kTests))
318 return false;
319 // Make sure that we lost our context at least once in the last test run so
320 // the test did something.
321 EXPECT_GT(num_losses_, num_losses_last_test_case_);
322 num_losses_last_test_case_ = num_losses_;
324 times_to_lose_during_commit_ =
325 kTests[test_case_].times_to_lose_during_commit;
326 times_to_lose_during_draw_ = kTests[test_case_].times_to_lose_during_draw;
327 times_to_fail_recreate_ = kTests[test_case_].times_to_fail_recreate;
328 fallback_context_works_ = kTests[test_case_].fallback_context_works;
329 async_output_surface_creation_ =
330 kTests[test_case_].async_output_surface_creation;
331 ++test_case_;
332 return true;
335 struct TestCase {
336 int times_to_lose_during_commit;
337 int times_to_lose_during_draw;
338 int times_to_fail_recreate;
339 bool fallback_context_works;
340 bool async_output_surface_creation;
343 protected:
344 size_t test_case_;
345 int num_losses_;
346 int num_losses_last_test_case_;
347 bool recovered_context_;
348 bool first_initialized_;
351 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLostContextSucceeds);
353 class LayerTreeHostClientNotReadyDoesNotCreateOutputSurface
354 : public LayerTreeHostContextTest {
355 public:
356 LayerTreeHostClientNotReadyDoesNotCreateOutputSurface()
357 : LayerTreeHostContextTest() {}
359 void WillBeginTest() override {
360 // Override and do not signal SetLayerTreeHostClientReady.
363 void BeginTest() override {
364 PostSetNeedsCommitToMainThread();
365 EndTest();
368 scoped_ptr<OutputSurface> CreateOutputSurface() override {
369 EXPECT_TRUE(false);
370 return nullptr;
373 void DidInitializeOutputSurface() override { EXPECT_TRUE(false); }
375 void AfterTest() override {}
378 SINGLE_AND_MULTI_THREAD_TEST_F(
379 LayerTreeHostClientNotReadyDoesNotCreateOutputSurface);
381 class MultipleCompositeDoesNotCreateOutputSurface
382 : public LayerTreeHostContextTest {
383 public:
384 MultipleCompositeDoesNotCreateOutputSurface()
385 : LayerTreeHostContextTest(), request_count_(0) {}
387 void InitializeSettings(LayerTreeSettings* settings) override {
388 settings->single_thread_proxy_scheduler = false;
389 settings->use_zero_copy = true;
392 void RequestNewOutputSurface() override {
393 EXPECT_GE(1, ++request_count_);
394 EndTest();
397 void BeginTest() override {
398 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
399 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(2));
402 scoped_ptr<OutputSurface> CreateOutputSurface() override {
403 EXPECT_TRUE(false);
404 return nullptr;
407 void DidInitializeOutputSurface() override { EXPECT_TRUE(false); }
409 void AfterTest() override {}
411 int request_count_;
414 SINGLE_THREAD_NOIMPL_TEST_F(MultipleCompositeDoesNotCreateOutputSurface);
416 // This test makes sure that once a SingleThreadProxy issues a
417 // DidFailToInitializeOutputSurface, that future Composite calls will not
418 // trigger additional requests for output surfaces.
419 class FailedCreateDoesNotCreateExtraOutputSurface
420 : public LayerTreeHostContextTest {
421 public:
422 FailedCreateDoesNotCreateExtraOutputSurface()
423 : LayerTreeHostContextTest(), num_requests_(0), has_failed_(false) {}
425 void InitializeSettings(LayerTreeSettings* settings) override {
426 settings->single_thread_proxy_scheduler = false;
427 settings->use_zero_copy = true;
430 void RequestNewOutputSurface() override {
431 num_requests_++;
432 // There should be one initial request and then one request from
433 // the LayerTreeTest test hooks DidFailToInitializeOutputSurface (which is
434 // hard to skip). This second request is just ignored and is test cruft.
435 EXPECT_LE(num_requests_, 2);
436 if (num_requests_ > 1)
437 return;
438 ExpectCreateToFail();
439 layer_tree_host()->SetOutputSurface(
440 make_scoped_ptr(new FailureOutputSurface(false)));
443 void BeginTest() override {
444 // First composite tries to create a surface.
445 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
446 EXPECT_EQ(num_requests_, 2);
447 EXPECT_TRUE(has_failed_);
449 // Second composite should not request or fail.
450 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(2));
451 EXPECT_EQ(num_requests_, 2);
452 EndTest();
455 void DidInitializeOutputSurface() override { EXPECT_TRUE(false); }
457 void DidFailToInitializeOutputSurface() override {
458 LayerTreeHostContextTest::DidFailToInitializeOutputSurface();
459 EXPECT_FALSE(has_failed_);
460 has_failed_ = true;
463 void AfterTest() override {}
465 int num_requests_;
466 bool has_failed_;
469 SINGLE_THREAD_NOIMPL_TEST_F(FailedCreateDoesNotCreateExtraOutputSurface);
471 class LayerTreeHostContextTestCommitAfterDelayedOutputSurface
472 : public LayerTreeHostContextTest {
473 public:
474 LayerTreeHostContextTestCommitAfterDelayedOutputSurface()
475 : LayerTreeHostContextTest(), creating_output_(false) {}
477 void InitializeSettings(LayerTreeSettings* settings) override {
478 settings->single_thread_proxy_scheduler = false;
479 settings->use_zero_copy = true;
482 void RequestNewOutputSurface() override {
483 MainThreadTaskRunner()->PostTask(
484 FROM_HERE,
485 base::Bind(&LayerTreeHostContextTestCommitAfterDelayedOutputSurface::
486 CreateAndSetOutputSurface,
487 base::Unretained(this)));
490 void CreateAndSetOutputSurface() {
491 creating_output_ = true;
492 layer_tree_host()->SetOutputSurface(
493 LayerTreeHostContextTest::CreateOutputSurface());
496 void BeginTest() override {
497 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
500 void ScheduleComposite() override {
501 if (creating_output_)
502 EndTest();
505 void AfterTest() override {}
507 bool creating_output_;
510 SINGLE_THREAD_NOIMPL_TEST_F(
511 LayerTreeHostContextTestCommitAfterDelayedOutputSurface);
513 class LayerTreeHostContextTestAvoidUnnecessaryComposite
514 : public LayerTreeHostContextTest {
515 public:
516 LayerTreeHostContextTestAvoidUnnecessaryComposite()
517 : LayerTreeHostContextTest(), in_composite_(false) {}
519 void InitializeSettings(LayerTreeSettings* settings) override {
520 settings->single_thread_proxy_scheduler = false;
521 settings->use_zero_copy = true;
524 void RequestNewOutputSurface() override {
525 layer_tree_host()->SetOutputSurface(
526 LayerTreeHostContextTest::CreateOutputSurface());
527 EndTest();
530 void BeginTest() override {
531 in_composite_ = true;
532 layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(1));
533 in_composite_ = false;
536 void ScheduleComposite() override { EXPECT_FALSE(in_composite_); }
538 void AfterTest() override {}
540 bool in_composite_;
543 SINGLE_THREAD_NOIMPL_TEST_F(LayerTreeHostContextTestAvoidUnnecessaryComposite);
545 class LayerTreeHostContextTestLostContextSucceedsWithContent
546 : public LayerTreeHostContextTestLostContextSucceeds {
547 public:
548 void SetupTree() override {
549 root_ = Layer::Create(layer_settings());
550 root_->SetBounds(gfx::Size(10, 10));
551 root_->SetIsDrawable(true);
553 // Paint non-solid color.
554 SkPaint paint;
555 paint.setColor(SkColorSetARGB(100, 80, 200, 200));
556 client_.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint);
558 if (layer_tree_host()->settings().impl_side_painting)
559 layer_ = FakePictureLayer::Create(layer_settings(), &client_);
560 else
561 layer_ = FakeContentLayer::Create(layer_settings(), &client_);
562 layer_->SetBounds(gfx::Size(10, 10));
563 layer_->SetIsDrawable(true);
565 root_->AddChild(layer_);
567 layer_tree_host()->SetRootLayer(root_);
568 LayerTreeHostContextTest::SetupTree();
571 void InvalidateAndSetNeedsCommit() override {
572 // Invalidate the render surface so we don't try to use a cached copy of the
573 // surface. We want to make sure to test the drawing paths for drawing to
574 // a child surface.
575 layer_->SetNeedsDisplay();
576 LayerTreeHostContextTestLostContextSucceeds::InvalidateAndSetNeedsCommit();
579 void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
580 if (!host_impl->settings().impl_side_painting) {
581 FakeContentLayerImpl* content_impl = static_cast<FakeContentLayerImpl*>(
582 host_impl->active_tree()->root_layer()->children()[0]);
583 // Even though the context was lost, we should have a resource. The
584 // TestWebGraphicsContext3D ensures that this resource is created with
585 // the active context.
586 EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0));
587 } else {
588 FakePictureLayerImpl* picture_impl = static_cast<FakePictureLayerImpl*>(
589 host_impl->active_tree()->root_layer()->children()[0]);
590 EXPECT_TRUE(picture_impl->HighResTiling()
591 ->TileAt(0, 0)
592 ->draw_info()
593 .IsReadyToDraw());
597 protected:
598 FakeContentLayerClient client_;
599 scoped_refptr<Layer> root_;
600 scoped_refptr<Layer> layer_;
603 // This test uses TiledLayer and PictureLayer to check for a working context.
604 SINGLE_AND_MULTI_THREAD_TEST_F(
605 LayerTreeHostContextTestLostContextSucceedsWithContent);
607 class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
608 : public LayerTreeHostContextTest {
609 public:
610 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
611 : times_to_fail_(1), times_initialized_(0) {
612 times_to_fail_create_ = times_to_fail_;
615 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
617 void DidInitializeOutputSurface() override { times_initialized_++; }
619 void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { EndTest(); }
621 void AfterTest() override {
622 EXPECT_EQ(times_to_fail_, times_create_failed_);
623 EXPECT_NE(0, times_initialized_);
626 private:
627 int times_to_fail_;
628 int times_initialized_;
631 SINGLE_AND_MULTI_THREAD_TEST_F(
632 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce);
634 class LayerTreeHostContextTestLostContextAndEvictTextures
635 : public LayerTreeHostContextTest {
636 public:
637 LayerTreeHostContextTestLostContextAndEvictTextures()
638 : LayerTreeHostContextTest(),
639 impl_host_(0),
640 num_commits_(0),
641 lost_context_(false) {}
643 void SetupTree() override {
644 // Paint non-solid color.
645 SkPaint paint;
646 paint.setColor(SkColorSetARGB(100, 80, 200, 200));
647 client_.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint);
649 if (layer_tree_host()->settings().impl_side_painting) {
650 picture_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
651 picture_layer_->SetBounds(gfx::Size(10, 20));
652 layer_tree_host()->SetRootLayer(picture_layer_);
653 } else {
654 content_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
655 content_layer_->SetBounds(gfx::Size(10, 20));
656 layer_tree_host()->SetRootLayer(content_layer_);
659 LayerTreeHostContextTest::SetupTree();
662 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
664 void PostEvictTextures() {
665 if (HasImplThread()) {
666 ImplThreadTaskRunner()->PostTask(
667 FROM_HERE,
668 base::Bind(&LayerTreeHostContextTestLostContextAndEvictTextures::
669 EvictTexturesOnImplThread,
670 base::Unretained(this)));
671 } else {
672 DebugScopedSetImplThread impl(proxy());
673 EvictTexturesOnImplThread();
677 void EvictTexturesOnImplThread() {
678 impl_host_->EvictTexturesForTesting();
680 if (lose_after_evict_) {
681 LoseContext();
682 lost_context_ = true;
686 void DidCommitAndDrawFrame() override {
687 if (num_commits_ > 1)
688 return;
689 if (!layer_tree_host()->settings().impl_side_painting) {
690 EXPECT_TRUE(content_layer_->HaveBackingAt(0, 0));
692 PostEvictTextures();
695 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
696 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
697 if (num_commits_ > 1)
698 return;
699 ++num_commits_;
700 if (!lose_after_evict_) {
701 LoseContext();
702 lost_context_ = true;
706 void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
707 if (impl->settings().impl_side_painting) {
708 FakePictureLayerImpl* picture_impl =
709 static_cast<FakePictureLayerImpl*>(impl->active_tree()->root_layer());
710 EXPECT_TRUE(picture_impl->HighResTiling()
711 ->TileAt(0, 0)
712 ->draw_info()
713 .IsReadyToDraw());
714 } else {
715 FakeContentLayerImpl* content_impl =
716 static_cast<FakeContentLayerImpl*>(impl->active_tree()->root_layer());
717 EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0));
720 impl_host_ = impl;
721 if (lost_context_)
722 EndTest();
725 void DidInitializeOutputSurface() override {}
727 void AfterTest() override {}
729 protected:
730 bool lose_after_evict_;
731 FakeContentLayerClient client_;
732 scoped_refptr<FakeContentLayer> content_layer_;
733 scoped_refptr<FakePictureLayer> picture_layer_;
734 LayerTreeHostImpl* impl_host_;
735 int num_commits_;
736 bool lost_context_;
739 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
740 LoseAfterEvict_SingleThread_DirectRenderer) {
741 lose_after_evict_ = true;
742 RunTest(false, false, false);
745 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
746 LoseAfterEvict_SingleThread_DelegatingRenderer) {
747 lose_after_evict_ = true;
748 RunTest(false, true, false);
751 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
752 LoseAfterEvict_MultiThread_DirectRenderer_MainThreadPaint) {
753 lose_after_evict_ = true;
754 RunTest(true, false, false);
757 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
758 LoseAfterEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
759 lose_after_evict_ = true;
760 RunTest(true, true, false);
763 // Flaky on all platforms, http://crbug.com/310979
764 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
765 DISABLED_LoseAfterEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
766 lose_after_evict_ = true;
767 RunTest(true, true, true);
770 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
771 LoseBeforeEvict_SingleThread_DirectRenderer) {
772 lose_after_evict_ = false;
773 RunTest(false, false, false);
776 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
777 LoseBeforeEvict_SingleThread_DelegatingRenderer) {
778 lose_after_evict_ = false;
779 RunTest(false, true, false);
782 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
783 LoseBeforeEvict_MultiThread_DirectRenderer_MainThreadPaint) {
784 lose_after_evict_ = false;
785 RunTest(true, false, false);
788 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
789 LoseBeforeEvict_MultiThread_DirectRenderer_ImplSidePaint) {
790 lose_after_evict_ = false;
791 RunTest(true, false, true);
794 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
795 LoseBeforeEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
796 lose_after_evict_ = false;
797 RunTest(true, true, false);
800 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
801 LoseBeforeEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
802 lose_after_evict_ = false;
803 RunTest(true, true, true);
806 class LayerTreeHostContextTestLostContextWhileUpdatingResources
807 : public LayerTreeHostContextTest {
808 public:
809 LayerTreeHostContextTestLostContextWhileUpdatingResources()
810 : num_children_(50), times_to_lose_on_end_query_(3) {}
812 scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() override {
813 scoped_ptr<TestWebGraphicsContext3D> context =
814 LayerTreeHostContextTest::CreateContext3d();
815 if (times_to_lose_on_end_query_) {
816 --times_to_lose_on_end_query_;
817 context->set_times_end_query_succeeds(5);
819 return context.Pass();
822 void SetupTree() override {
823 if (layer_tree_host()->settings().impl_side_painting)
824 parent_ = FakePictureLayer::Create(layer_settings(), &client_);
825 else
826 parent_ = FakeContentLayer::Create(layer_settings(), &client_);
828 parent_->SetBounds(gfx::Size(num_children_, 1));
830 for (int i = 0; i < num_children_; i++) {
831 scoped_refptr<Layer> child;
832 if (layer_tree_host()->settings().impl_side_painting)
833 child = FakePictureLayer::Create(layer_settings(), &client_);
834 else
835 child = FakeContentLayer::Create(layer_settings(), &client_);
836 child->SetPosition(gfx::PointF(i, 0.f));
837 child->SetBounds(gfx::Size(1, 1));
838 parent_->AddChild(child);
841 layer_tree_host()->SetRootLayer(parent_);
842 LayerTreeHostContextTest::SetupTree();
845 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
847 void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
848 EXPECT_EQ(0, times_to_lose_on_end_query_);
849 EndTest();
852 void AfterTest() override { EXPECT_EQ(0, times_to_lose_on_end_query_); }
854 private:
855 FakeContentLayerClient client_;
856 scoped_refptr<Layer> parent_;
857 int num_children_;
858 int times_to_lose_on_end_query_;
861 SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
862 LayerTreeHostContextTestLostContextWhileUpdatingResources);
864 class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
865 public:
866 LayerTreeHostContextTestLayersNotified()
867 : LayerTreeHostContextTest(), num_commits_(0) {}
869 void SetupTree() override {
870 if (layer_tree_host()->settings().impl_side_painting) {
871 root_ = FakePictureLayer::Create(layer_settings(), &client_);
872 child_ = FakePictureLayer::Create(layer_settings(), &client_);
873 grandchild_ = FakePictureLayer::Create(layer_settings(), &client_);
874 } else {
875 root_ = FakeContentLayer::Create(layer_settings(), &client_);
876 child_ = FakeContentLayer::Create(layer_settings(), &client_);
877 grandchild_ = FakeContentLayer::Create(layer_settings(), &client_);
880 root_->AddChild(child_);
881 child_->AddChild(grandchild_);
883 layer_tree_host()->SetRootLayer(root_);
884 LayerTreeHostContextTest::SetupTree();
887 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
889 void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
890 LayerTreeHostContextTest::DidActivateTreeOnThread(host_impl);
892 FakePictureLayerImpl* root_picture = NULL;
893 FakePictureLayerImpl* child_picture = NULL;
894 FakePictureLayerImpl* grandchild_picture = NULL;
895 FakeContentLayerImpl* root_content = NULL;
896 FakeContentLayerImpl* child_content = NULL;
897 FakeContentLayerImpl* grandchild_content = NULL;
899 if (host_impl->settings().impl_side_painting) {
900 root_picture = static_cast<FakePictureLayerImpl*>(
901 host_impl->active_tree()->root_layer());
902 child_picture =
903 static_cast<FakePictureLayerImpl*>(root_picture->children()[0]);
904 grandchild_picture =
905 static_cast<FakePictureLayerImpl*>(child_picture->children()[0]);
907 } else {
908 root_content = static_cast<FakeContentLayerImpl*>(
909 host_impl->active_tree()->root_layer());
910 child_content =
911 static_cast<FakeContentLayerImpl*>(root_content->children()[0]);
912 grandchild_content =
913 static_cast<FakeContentLayerImpl*>(child_content->children()[0]);
916 ++num_commits_;
917 switch (num_commits_) {
918 case 1:
919 if (host_impl->settings().impl_side_painting) {
920 EXPECT_EQ(0u, root_picture->release_resources_count());
921 EXPECT_EQ(0u, child_picture->release_resources_count());
922 EXPECT_EQ(0u, grandchild_picture->release_resources_count());
923 } else {
924 EXPECT_EQ(0u, root_content->lost_output_surface_count());
925 EXPECT_EQ(0u, child_content->lost_output_surface_count());
926 EXPECT_EQ(0u, grandchild_content->lost_output_surface_count());
929 // Lose the context and struggle to recreate it.
930 LoseContext();
931 times_to_fail_create_ = 1;
932 break;
933 case 2:
934 if (host_impl->settings().impl_side_painting) {
935 EXPECT_TRUE(root_picture->release_resources_count());
936 EXPECT_TRUE(child_picture->release_resources_count());
937 EXPECT_TRUE(grandchild_picture->release_resources_count());
938 } else {
939 EXPECT_TRUE(root_content->lost_output_surface_count());
940 EXPECT_TRUE(child_content->lost_output_surface_count());
941 EXPECT_TRUE(grandchild_content->lost_output_surface_count());
944 EndTest();
945 break;
946 default:
947 NOTREACHED();
951 void AfterTest() override {}
953 private:
954 int num_commits_;
956 FakeContentLayerClient client_;
957 scoped_refptr<Layer> root_;
958 scoped_refptr<Layer> child_;
959 scoped_refptr<Layer> grandchild_;
962 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified);
964 class LayerTreeHostContextTestDontUseLostResources
965 : public LayerTreeHostContextTest {
966 public:
967 LayerTreeHostContextTestDontUseLostResources() : lost_context_(false) {
968 context_should_support_io_surface_ = true;
970 child_output_surface_ = FakeOutputSurface::Create3d();
971 child_output_surface_->BindToClient(&output_surface_client_);
972 shared_bitmap_manager_.reset(new TestSharedBitmapManager());
973 child_resource_provider_ = FakeResourceProvider::Create(
974 child_output_surface_.get(), shared_bitmap_manager_.get());
977 static void EmptyReleaseCallback(unsigned sync_point, bool lost) {}
979 void SetupTree() override {
980 gpu::gles2::GLES2Interface* gl =
981 child_output_surface_->context_provider()->ContextGL();
983 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
985 scoped_ptr<TestRenderPass> pass_for_quad = TestRenderPass::Create();
986 pass_for_quad->SetNew(
987 // AppendOneOfEveryQuadType() makes a RenderPass quad with this id.
988 RenderPassId(2, 1),
989 gfx::Rect(0, 0, 10, 10),
990 gfx::Rect(0, 0, 10, 10),
991 gfx::Transform());
993 scoped_ptr<TestRenderPass> pass = TestRenderPass::Create();
994 pass->SetNew(RenderPassId(1, 1),
995 gfx::Rect(0, 0, 10, 10),
996 gfx::Rect(0, 0, 10, 10),
997 gfx::Transform());
998 pass->AppendOneOfEveryQuadType(child_resource_provider_.get(),
999 RenderPassId(2, 1));
1001 frame_data->render_pass_list.push_back(pass_for_quad.Pass());
1002 frame_data->render_pass_list.push_back(pass.Pass());
1004 delegated_resource_collection_ = new DelegatedFrameResourceCollection;
1005 delegated_frame_provider_ = new DelegatedFrameProvider(
1006 delegated_resource_collection_.get(), frame_data.Pass());
1008 ResourceId resource = child_resource_provider_->CreateResource(
1009 gfx::Size(4, 4), GL_CLAMP_TO_EDGE,
1010 ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
1011 ResourceProvider::ScopedWriteLockGL lock(child_resource_provider_.get(),
1012 resource);
1014 gpu::Mailbox mailbox;
1015 gl->GenMailboxCHROMIUM(mailbox.name);
1016 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1018 scoped_refptr<Layer> root = Layer::Create(layer_settings());
1019 root->SetBounds(gfx::Size(10, 10));
1020 root->SetIsDrawable(true);
1022 scoped_refptr<FakeDelegatedRendererLayer> delegated =
1023 FakeDelegatedRendererLayer::Create(layer_settings(),
1024 delegated_frame_provider_.get());
1025 delegated->SetBounds(gfx::Size(10, 10));
1026 delegated->SetIsDrawable(true);
1027 root->AddChild(delegated);
1029 scoped_refptr<Layer> layer;
1030 if (layer_tree_host()->settings().impl_side_painting)
1031 layer = PictureLayer::Create(layer_settings(), &client_);
1032 else
1033 layer = ContentLayer::Create(layer_settings(), &client_);
1034 layer->SetBounds(gfx::Size(10, 10));
1035 layer->SetIsDrawable(true);
1036 root->AddChild(layer);
1038 scoped_refptr<TextureLayer> texture =
1039 TextureLayer::CreateForMailbox(layer_settings_, NULL);
1040 texture->SetBounds(gfx::Size(10, 10));
1041 texture->SetIsDrawable(true);
1042 texture->SetTextureMailbox(
1043 TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point),
1044 SingleReleaseCallback::Create(
1045 base::Bind(&LayerTreeHostContextTestDontUseLostResources::
1046 EmptyReleaseCallback)));
1047 root->AddChild(texture);
1049 scoped_refptr<Layer> mask;
1050 if (layer_tree_host()->settings().impl_side_painting)
1051 mask = PictureLayer::Create(layer_settings_, &client_);
1052 else
1053 mask = ContentLayer::Create(layer_settings_, &client_);
1054 mask->SetBounds(gfx::Size(10, 10));
1056 scoped_refptr<Layer> layer_with_mask;
1057 if (layer_tree_host()->settings().impl_side_painting)
1058 layer_with_mask = PictureLayer::Create(layer_settings_, &client_);
1059 else
1060 layer_with_mask = ContentLayer::Create(layer_settings_, &client_);
1061 layer_with_mask->SetBounds(gfx::Size(10, 10));
1062 layer_with_mask->SetIsDrawable(true);
1063 layer_with_mask->SetMaskLayer(mask.get());
1064 root->AddChild(layer_with_mask);
1066 scoped_refptr<VideoLayer> video_color = VideoLayer::Create(
1067 layer_settings_, &color_frame_provider_, media::VIDEO_ROTATION_0);
1068 video_color->SetBounds(gfx::Size(10, 10));
1069 video_color->SetIsDrawable(true);
1070 root->AddChild(video_color);
1072 scoped_refptr<VideoLayer> video_hw = VideoLayer::Create(
1073 layer_settings_, &hw_frame_provider_, media::VIDEO_ROTATION_0);
1074 video_hw->SetBounds(gfx::Size(10, 10));
1075 video_hw->SetIsDrawable(true);
1076 root->AddChild(video_hw);
1078 scoped_refptr<VideoLayer> video_scaled_hw = VideoLayer::Create(
1079 layer_settings_, &scaled_hw_frame_provider_, media::VIDEO_ROTATION_0);
1080 video_scaled_hw->SetBounds(gfx::Size(10, 10));
1081 video_scaled_hw->SetIsDrawable(true);
1082 root->AddChild(video_scaled_hw);
1084 color_video_frame_ = VideoFrame::CreateColorFrame(
1085 gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
1086 hw_video_frame_ = VideoFrame::WrapNativeTexture(
1087 gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, sync_point),
1088 media::VideoFrame::ReleaseMailboxCB(), gfx::Size(4, 4),
1089 gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4), base::TimeDelta(),
1090 false /* allow_overlay */, true /* has_alpha */);
1091 scaled_hw_video_frame_ = VideoFrame::WrapNativeTexture(
1092 gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, sync_point),
1093 media::VideoFrame::ReleaseMailboxCB(), gfx::Size(4, 4),
1094 gfx::Rect(0, 0, 3, 2), gfx::Size(4, 4), base::TimeDelta(),
1095 false /* allow_overlay */, true /* has_alpha */);
1097 color_frame_provider_.set_frame(color_video_frame_);
1098 hw_frame_provider_.set_frame(hw_video_frame_);
1099 scaled_hw_frame_provider_.set_frame(scaled_hw_video_frame_);
1101 if (!delegating_renderer()) {
1102 // TODO(danakj): IOSurface layer can not be transported. crbug.com/239335
1103 scoped_refptr<IOSurfaceLayer> io_surface =
1104 IOSurfaceLayer::Create(layer_settings_);
1105 io_surface->SetBounds(gfx::Size(10, 10));
1106 io_surface->SetIsDrawable(true);
1107 io_surface->SetIOSurfaceProperties(1, gfx::Size(10, 10));
1108 root->AddChild(io_surface);
1111 // Enable the hud.
1112 LayerTreeDebugState debug_state;
1113 debug_state.show_property_changed_rects = true;
1114 layer_tree_host()->SetDebugState(debug_state);
1116 scoped_refptr<PaintedScrollbarLayer> scrollbar =
1117 PaintedScrollbarLayer::Create(
1118 layer_settings_, scoped_ptr<Scrollbar>(new FakeScrollbar).Pass(),
1119 layer->id());
1120 scrollbar->SetBounds(gfx::Size(10, 10));
1121 scrollbar->SetIsDrawable(true);
1122 root->AddChild(scrollbar);
1124 layer_tree_host()->SetRootLayer(root);
1125 LayerTreeHostContextTest::SetupTree();
1128 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
1130 void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
1131 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
1133 if (host_impl->active_tree()->source_frame_number() == 3) {
1134 // On the third commit we're recovering from context loss. Hardware
1135 // video frames should not be reused by the VideoFrameProvider, but
1136 // software frames can be.
1137 hw_frame_provider_.set_frame(NULL);
1138 scaled_hw_frame_provider_.set_frame(NULL);
1142 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
1143 LayerTreeHostImpl::FrameData* frame,
1144 DrawResult draw_result) override {
1145 if (host_impl->active_tree()->source_frame_number() == 2) {
1146 // Lose the context during draw on the second commit. This will cause
1147 // a third commit to recover.
1148 context3d_->set_times_bind_texture_succeeds(0);
1150 return draw_result;
1153 scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
1154 // This will get called twice:
1155 // First when we create the initial output surface...
1156 if (layer_tree_host()->source_frame_number() > 0) {
1157 // ... and then again after we forced the context to be lost.
1158 lost_context_ = true;
1160 return LayerTreeHostContextTest::CreateFakeOutputSurface();
1163 void DidCommitAndDrawFrame() override {
1164 ASSERT_TRUE(layer_tree_host()->hud_layer());
1165 // End the test once we know the 3nd frame drew.
1166 if (layer_tree_host()->source_frame_number() < 5) {
1167 layer_tree_host()->root_layer()->SetNeedsDisplay();
1168 layer_tree_host()->SetNeedsCommit();
1169 } else {
1170 EndTest();
1174 void AfterTest() override { EXPECT_TRUE(lost_context_); }
1176 private:
1177 FakeContentLayerClient client_;
1178 bool lost_context_;
1180 FakeOutputSurfaceClient output_surface_client_;
1181 scoped_ptr<FakeOutputSurface> child_output_surface_;
1182 scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
1183 scoped_ptr<ResourceProvider> child_resource_provider_;
1185 scoped_refptr<DelegatedFrameResourceCollection>
1186 delegated_resource_collection_;
1187 scoped_refptr<DelegatedFrameProvider> delegated_frame_provider_;
1189 scoped_refptr<VideoFrame> color_video_frame_;
1190 scoped_refptr<VideoFrame> hw_video_frame_;
1191 scoped_refptr<VideoFrame> scaled_hw_video_frame_;
1193 FakeVideoFrameProvider color_frame_provider_;
1194 FakeVideoFrameProvider hw_frame_provider_;
1195 FakeVideoFrameProvider scaled_hw_frame_provider_;
1197 LayerSettings layer_settings_;
1200 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources);
1202 class ImplSidePaintingLayerTreeHostContextTest
1203 : public LayerTreeHostContextTest {
1204 public:
1205 void InitializeSettings(LayerTreeSettings* settings) override {
1206 settings->impl_side_painting = true;
1210 class LayerTreeHostContextTestImplSidePainting
1211 : public ImplSidePaintingLayerTreeHostContextTest {
1212 public:
1213 void SetupTree() override {
1214 scoped_refptr<Layer> root = Layer::Create(layer_settings());
1215 root->SetBounds(gfx::Size(10, 10));
1216 root->SetIsDrawable(true);
1218 scoped_refptr<PictureLayer> picture =
1219 PictureLayer::Create(layer_settings(), &client_);
1220 picture->SetBounds(gfx::Size(10, 10));
1221 picture->SetIsDrawable(true);
1222 root->AddChild(picture);
1224 layer_tree_host()->SetRootLayer(root);
1225 LayerTreeHostContextTest::SetupTree();
1228 void BeginTest() override {
1229 times_to_lose_during_commit_ = 1;
1230 PostSetNeedsCommitToMainThread();
1233 void AfterTest() override {}
1235 void DidInitializeOutputSurface() override { EndTest(); }
1237 private:
1238 FakeContentLayerClient client_;
1241 MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting);
1243 class ScrollbarLayerLostContext : public LayerTreeHostContextTest {
1244 public:
1245 ScrollbarLayerLostContext() : commits_(0) {}
1247 void BeginTest() override {
1248 scoped_refptr<Layer> scroll_layer = Layer::Create(layer_settings());
1249 scrollbar_layer_ = FakePaintedScrollbarLayer::Create(
1250 layer_settings(), false, true, scroll_layer->id());
1251 scrollbar_layer_->SetBounds(gfx::Size(10, 100));
1252 layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
1253 layer_tree_host()->root_layer()->AddChild(scroll_layer);
1254 PostSetNeedsCommitToMainThread();
1257 void AfterTest() override {}
1259 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
1260 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1262 ++commits_;
1263 switch (commits_) {
1264 case 1:
1265 // First (regular) update, we should upload 2 resources (thumb, and
1266 // backtrack).
1267 EXPECT_EQ(1, scrollbar_layer_->update_count());
1268 LoseContext();
1269 break;
1270 case 2:
1271 // Second update, after the lost context, we should still upload 2
1272 // resources even if the contents haven't changed.
1273 EXPECT_EQ(2, scrollbar_layer_->update_count());
1274 EndTest();
1275 break;
1276 default:
1277 NOTREACHED();
1281 private:
1282 int commits_;
1283 scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer_;
1286 SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext);
1288 class UIResourceLostTest : public LayerTreeHostContextTest {
1289 public:
1290 UIResourceLostTest() : time_step_(0) {}
1291 void InitializeSettings(LayerTreeSettings* settings) override {
1292 settings->renderer_settings.texture_id_allocation_chunk_size = 1;
1294 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
1295 void AfterTest() override {}
1297 // This is called on the main thread after each commit and
1298 // DidActivateTreeOnThread, with the value of time_step_ at the time
1299 // of the call to DidActivateTreeOnThread. Similar tests will do
1300 // work on the main thread in DidCommit but that is unsuitable because
1301 // the main thread work for these tests must happen after
1302 // DidActivateTreeOnThread, which happens after DidCommit with impl-side
1303 // painting.
1304 virtual void StepCompleteOnMainThread(int time_step) = 0;
1306 // Called after DidActivateTreeOnThread. If this is done during the commit,
1307 // the call to StepCompleteOnMainThread will not occur until after
1308 // the commit completes, because the main thread is blocked.
1309 void PostStepCompleteToMainThread() {
1310 proxy()->MainThreadTaskRunner()->PostTask(
1311 FROM_HERE,
1312 base::Bind(&UIResourceLostTest::StepCompleteOnMainThreadInternal,
1313 base::Unretained(this),
1314 time_step_));
1317 void PostLoseContextToImplThread() {
1318 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1319 ImplThreadTaskRunner()->PostTask(
1320 FROM_HERE,
1321 base::Bind(&LayerTreeHostContextTest::LoseContext,
1322 base::Unretained(this)));
1325 protected:
1326 int time_step_;
1327 scoped_ptr<FakeScopedUIResource> ui_resource_;
1329 private:
1330 void StepCompleteOnMainThreadInternal(int step) {
1331 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1332 StepCompleteOnMainThread(step);
1336 class UIResourceLostTestSimple : public UIResourceLostTest {
1337 public:
1338 // This is called when the commit is complete and the new layer tree has been
1339 // activated.
1340 virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) = 0;
1342 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
1343 if (!impl->settings().impl_side_painting) {
1344 StepCompleteOnImplThread(impl);
1345 PostStepCompleteToMainThread();
1346 ++time_step_;
1350 void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
1351 if (impl->settings().impl_side_painting) {
1352 StepCompleteOnImplThread(impl);
1353 PostStepCompleteToMainThread();
1354 ++time_step_;
1359 // Losing context after an UI resource has been created.
1360 class UIResourceLostAfterCommit : public UIResourceLostTestSimple {
1361 public:
1362 void StepCompleteOnMainThread(int step) override {
1363 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1364 switch (step) {
1365 case 0:
1366 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1367 // Expects a valid UIResourceId.
1368 EXPECT_NE(0, ui_resource_->id());
1369 PostSetNeedsCommitToMainThread();
1370 break;
1371 case 4:
1372 // Release resource before ending the test.
1373 ui_resource_ = nullptr;
1374 EndTest();
1375 break;
1376 case 5:
1377 NOTREACHED();
1378 break;
1382 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override {
1383 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1384 switch (time_step_) {
1385 case 1:
1386 // The resource should have been created on LTHI after the commit.
1387 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1388 PostSetNeedsCommitToMainThread();
1389 break;
1390 case 2:
1391 LoseContext();
1392 break;
1393 case 3:
1394 // The resources should have been recreated. The bitmap callback should
1395 // have been called once with the resource_lost flag set to true.
1396 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1397 // Resource Id on the impl-side have been recreated as well. Note
1398 // that the same UIResourceId persists after the context lost.
1399 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1400 PostSetNeedsCommitToMainThread();
1401 break;
1406 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostAfterCommit);
1408 // Losing context before UI resource requests can be commited. Three sequences
1409 // of creation/deletion are considered:
1410 // 1. Create one resource -> Context Lost => Expect the resource to have been
1411 // created.
1412 // 2. Delete an exisiting resource (test_id0_) -> create a second resource
1413 // (test_id1_) -> Context Lost => Expect the test_id0_ to be removed and
1414 // test_id1_ to have been created.
1415 // 3. Create one resource -> Delete that same resource -> Context Lost => Expect
1416 // the resource to not exist in the manager.
1417 class UIResourceLostBeforeCommit : public UIResourceLostTestSimple {
1418 public:
1419 UIResourceLostBeforeCommit() : test_id0_(0), test_id1_(0) {}
1421 void StepCompleteOnMainThread(int step) override {
1422 switch (step) {
1423 case 0:
1424 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1425 // Lose the context on the impl thread before the commit.
1426 PostLoseContextToImplThread();
1427 break;
1428 case 2:
1429 // Sequence 2:
1430 // Currently one resource has been created.
1431 test_id0_ = ui_resource_->id();
1432 // Delete this resource.
1433 ui_resource_ = nullptr;
1434 // Create another resource.
1435 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1436 test_id1_ = ui_resource_->id();
1437 // Sanity check that two resource creations return different ids.
1438 EXPECT_NE(test_id0_, test_id1_);
1439 // Lose the context on the impl thread before the commit.
1440 PostLoseContextToImplThread();
1441 break;
1442 case 3:
1443 // Clear the manager of resources.
1444 ui_resource_ = nullptr;
1445 PostSetNeedsCommitToMainThread();
1446 break;
1447 case 4:
1448 // Sequence 3:
1449 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1450 test_id0_ = ui_resource_->id();
1451 // Sanity check the UIResourceId should not be 0.
1452 EXPECT_NE(0, test_id0_);
1453 // Usually ScopedUIResource are deleted from the manager in their
1454 // destructor (so usually ui_resource_ = nullptr). But here we need
1455 // ui_resource_ for the next step, so call DeleteUIResource directly.
1456 layer_tree_host()->DeleteUIResource(test_id0_);
1457 // Delete the resouce and then lose the context.
1458 PostLoseContextToImplThread();
1459 break;
1460 case 5:
1461 // Release resource before ending the test.
1462 ui_resource_ = nullptr;
1463 EndTest();
1464 break;
1465 case 6:
1466 NOTREACHED();
1467 break;
1471 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override {
1472 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1473 switch (time_step_) {
1474 case 1:
1475 // Sequence 1 (continued):
1476 // The first context lost happens before the resources were created,
1477 // and because it resulted in no resources being destroyed, it does not
1478 // trigger resource re-creation.
1479 EXPECT_EQ(1, ui_resource_->resource_create_count);
1480 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1481 // Resource Id on the impl-side has been created.
1482 PostSetNeedsCommitToMainThread();
1483 break;
1484 case 3:
1485 // Sequence 2 (continued):
1486 // The previous resource should have been deleted.
1487 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
1488 // The second resource should have been created.
1489 EXPECT_NE(0u, impl->ResourceIdForUIResource(test_id1_));
1490 // The second resource called the resource callback once and since the
1491 // context is lost, a "resource lost" callback was also issued.
1492 EXPECT_EQ(2, ui_resource_->resource_create_count);
1493 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1494 break;
1495 case 5:
1496 // Sequence 3 (continued):
1497 // Expect the resource callback to have been called once.
1498 EXPECT_EQ(1, ui_resource_->resource_create_count);
1499 // No "resource lost" callbacks.
1500 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1501 // The UI resource id should not be valid
1502 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
1503 break;
1507 private:
1508 UIResourceId test_id0_;
1509 UIResourceId test_id1_;
1512 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeCommit);
1514 // Losing UI resource before the pending trees is activated but after the
1515 // commit. Impl-side-painting only.
1516 class UIResourceLostBeforeActivateTree : public UIResourceLostTest {
1517 void StepCompleteOnMainThread(int step) override {
1518 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1519 switch (step) {
1520 case 0:
1521 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1522 PostSetNeedsCommitToMainThread();
1523 break;
1524 case 3:
1525 test_id_ = ui_resource_->id();
1526 ui_resource_ = nullptr;
1527 PostSetNeedsCommitToMainThread();
1528 break;
1529 case 5:
1530 // Release resource before ending the test.
1531 ui_resource_ = nullptr;
1532 EndTest();
1533 break;
1534 case 6:
1535 // Make sure no extra commits happened.
1536 NOTREACHED();
1540 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
1541 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1542 switch (time_step_) {
1543 case 2:
1544 PostSetNeedsCommitToMainThread();
1545 break;
1546 case 4:
1547 PostSetNeedsCommitToMainThread();
1548 break;
1552 void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override {
1553 switch (time_step_) {
1554 case 1:
1555 // The resource creation callback has been called.
1556 EXPECT_EQ(1, ui_resource_->resource_create_count);
1557 // The resource is not yet lost (sanity check).
1558 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1559 // The resource should not have been created yet on the impl-side.
1560 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1561 LoseContext();
1562 break;
1563 case 3:
1564 LoseContext();
1565 break;
1569 void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
1570 LayerTreeHostContextTest::DidActivateTreeOnThread(impl);
1571 switch (time_step_) {
1572 case 1:
1573 // The pending requests on the impl-side should have been processed.
1574 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1575 break;
1576 case 2:
1577 // The "lost resource" callback should have been called once.
1578 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1579 break;
1580 case 4:
1581 // The resource is deleted and should not be in the manager. Use
1582 // test_id_ since ui_resource_ has been deleted.
1583 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id_));
1584 break;
1587 PostStepCompleteToMainThread();
1588 ++time_step_;
1591 private:
1592 UIResourceId test_id_;
1595 TEST_F(UIResourceLostBeforeActivateTree,
1596 RunMultiThread_DirectRenderer_ImplSidePaint) {
1597 RunTest(true, false, true);
1600 TEST_F(UIResourceLostBeforeActivateTree,
1601 RunMultiThread_DelegatingRenderer_ImplSidePaint) {
1602 RunTest(true, true, true);
1605 // Resources evicted explicitly and by visibility changes.
1606 class UIResourceLostEviction : public UIResourceLostTestSimple {
1607 public:
1608 void StepCompleteOnMainThread(int step) override {
1609 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1610 switch (step) {
1611 case 0:
1612 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1613 EXPECT_NE(0, ui_resource_->id());
1614 PostSetNeedsCommitToMainThread();
1615 break;
1616 case 2:
1617 // Make the tree not visible.
1618 PostSetVisibleToMainThread(false);
1619 break;
1620 case 3:
1621 // Release resource before ending the test.
1622 ui_resource_ = nullptr;
1623 EndTest();
1624 break;
1625 case 4:
1626 NOTREACHED();
1630 void DidSetVisibleOnImplTree(LayerTreeHostImpl* impl, bool visible) override {
1631 TestWebGraphicsContext3D* context = TestContext();
1632 if (!visible) {
1633 // All resources should have been evicted.
1634 ASSERT_EQ(0u, context->NumTextures());
1635 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1636 EXPECT_EQ(2, ui_resource_->resource_create_count);
1637 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1638 // Drawing is disabled both because of the evicted resources and
1639 // because the renderer is not visible.
1640 EXPECT_FALSE(impl->CanDraw());
1641 // Make the renderer visible again.
1642 PostSetVisibleToMainThread(true);
1646 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override {
1647 TestWebGraphicsContext3D* context = TestContext();
1648 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1649 switch (time_step_) {
1650 case 1:
1651 // The resource should have been created on LTHI after the commit.
1652 ASSERT_EQ(1u, context->NumTextures());
1653 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1654 EXPECT_EQ(1, ui_resource_->resource_create_count);
1655 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1656 EXPECT_TRUE(impl->CanDraw());
1657 // Evict all UI resources. This will trigger a commit.
1658 impl->EvictAllUIResources();
1659 ASSERT_EQ(0u, context->NumTextures());
1660 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1661 EXPECT_EQ(1, ui_resource_->resource_create_count);
1662 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1663 EXPECT_FALSE(impl->CanDraw());
1664 break;
1665 case 2:
1666 // The resource should have been recreated.
1667 ASSERT_EQ(1u, context->NumTextures());
1668 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1669 EXPECT_EQ(2, ui_resource_->resource_create_count);
1670 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1671 EXPECT_TRUE(impl->CanDraw());
1672 break;
1673 case 3:
1674 // The resource should have been recreated after visibility was
1675 // restored.
1676 ASSERT_EQ(1u, context->NumTextures());
1677 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1678 EXPECT_EQ(3, ui_resource_->resource_create_count);
1679 EXPECT_EQ(2, ui_resource_->lost_resource_count);
1680 EXPECT_TRUE(impl->CanDraw());
1681 break;
1686 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction);
1688 class LayerTreeHostContextTestSurfaceCreateCallback
1689 : public LayerTreeHostContextTest {
1690 public:
1691 LayerTreeHostContextTestSurfaceCreateCallback()
1692 : LayerTreeHostContextTest() {}
1694 void SetupTree() override {
1695 if (layer_tree_host()->settings().impl_side_painting) {
1696 picture_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
1697 picture_layer_->SetBounds(gfx::Size(10, 20));
1698 layer_tree_host()->SetRootLayer(picture_layer_);
1699 } else {
1700 content_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
1701 content_layer_->SetBounds(gfx::Size(10, 20));
1702 layer_tree_host()->SetRootLayer(content_layer_);
1705 LayerTreeHostContextTest::SetupTree();
1708 void BeginTest() override { PostSetNeedsCommitToMainThread(); }
1710 void DidCommit() override {
1711 switch (layer_tree_host()->source_frame_number()) {
1712 case 1:
1713 if (layer_tree_host()->settings().impl_side_painting)
1714 EXPECT_EQ(1u, picture_layer_->output_surface_created_count());
1715 else
1716 EXPECT_EQ(1u, content_layer_->output_surface_created_count());
1717 layer_tree_host()->SetNeedsCommit();
1718 break;
1719 case 2:
1720 if (layer_tree_host()->settings().impl_side_painting)
1721 EXPECT_EQ(1u, picture_layer_->output_surface_created_count());
1722 else
1723 EXPECT_EQ(1u, content_layer_->output_surface_created_count());
1724 layer_tree_host()->SetNeedsCommit();
1725 break;
1726 case 3:
1727 if (layer_tree_host()->settings().impl_side_painting)
1728 EXPECT_EQ(1u, picture_layer_->output_surface_created_count());
1729 else
1730 EXPECT_EQ(1u, content_layer_->output_surface_created_count());
1731 break;
1732 case 4:
1733 if (layer_tree_host()->settings().impl_side_painting)
1734 EXPECT_EQ(2u, picture_layer_->output_surface_created_count());
1735 else
1736 EXPECT_EQ(2u, content_layer_->output_surface_created_count());
1737 layer_tree_host()->SetNeedsCommit();
1738 break;
1742 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
1743 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1744 switch (LastCommittedSourceFrameNumber(impl)) {
1745 case 0:
1746 break;
1747 case 1:
1748 break;
1749 case 2:
1750 LoseContext();
1751 break;
1752 case 3:
1753 EndTest();
1754 break;
1758 void AfterTest() override {}
1760 protected:
1761 FakeContentLayerClient client_;
1762 scoped_refptr<FakePictureLayer> picture_layer_;
1763 scoped_refptr<FakeContentLayer> content_layer_;
1766 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestSurfaceCreateCallback);
1768 class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame
1769 : public LayerTreeHostContextTest {
1770 protected:
1771 void BeginTest() override {
1772 deferred_ = false;
1773 PostSetNeedsCommitToMainThread();
1776 void ScheduledActionWillSendBeginMainFrame() override {
1777 if (deferred_)
1778 return;
1779 deferred_ = true;
1781 // Defer commits before the BeginFrame arrives, causing it to be delayed.
1782 PostSetDeferCommitsToMainThread(true);
1783 // Meanwhile, lose the context while we are in defer commits.
1784 ImplThreadTaskRunner()->PostTask(
1785 FROM_HERE,
1786 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1787 LoseContextOnImplThread,
1788 base::Unretained(this)));
1791 void LoseContextOnImplThread() {
1792 LoseContext();
1794 // After losing the context, stop deferring commits.
1795 PostSetDeferCommitsToMainThread(false);
1798 void WillBeginMainFrame() override {
1799 // Don't begin a frame with a lost surface.
1800 EXPECT_FALSE(layer_tree_host()->output_surface_lost());
1803 void DidCommitAndDrawFrame() override { EndTest(); }
1805 void AfterTest() override {}
1807 bool deferred_;
1810 SINGLE_AND_MULTI_THREAD_TEST_F(
1811 LayerTreeHostContextTestLoseAfterSendingBeginMainFrame);
1813 } // namespace
1814 } // namespace cc