Revert 287747 "Make SingleThreadProxy a SchedulerClient"
[chromium-blink-merge.git] / cc / trees / layer_tree_host_unittest_context.cc
blob879e5347e311078e380b072780e3c6ff6f393cd9
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/test/fake_content_layer.h"
22 #include "cc/test/fake_content_layer_client.h"
23 #include "cc/test/fake_content_layer_impl.h"
24 #include "cc/test/fake_delegated_renderer_layer.h"
25 #include "cc/test/fake_delegated_renderer_layer_impl.h"
26 #include "cc/test/fake_layer_tree_host_client.h"
27 #include "cc/test/fake_output_surface.h"
28 #include "cc/test/fake_output_surface_client.h"
29 #include "cc/test/fake_painted_scrollbar_layer.h"
30 #include "cc/test/fake_scoped_ui_resource.h"
31 #include "cc/test/fake_scrollbar.h"
32 #include "cc/test/fake_video_frame_provider.h"
33 #include "cc/test/layer_tree_test.h"
34 #include "cc/test/render_pass_test_common.h"
35 #include "cc/test/test_context_provider.h"
36 #include "cc/test/test_shared_bitmap_manager.h"
37 #include "cc/test/test_web_graphics_context_3d.h"
38 #include "cc/trees/layer_tree_host_impl.h"
39 #include "cc/trees/layer_tree_impl.h"
40 #include "cc/trees/single_thread_proxy.h"
41 #include "gpu/GLES2/gl2extchromium.h"
42 #include "media/base/media.h"
44 using media::VideoFrame;
46 namespace cc {
47 namespace {
49 // These tests deal with losing the 3d graphics context.
50 class LayerTreeHostContextTest : public LayerTreeTest {
51 public:
52 LayerTreeHostContextTest()
53 : LayerTreeTest(),
54 context3d_(NULL),
55 times_to_fail_create_(0),
56 times_to_lose_during_commit_(0),
57 times_to_lose_during_draw_(0),
58 times_to_fail_recreate_(0),
59 times_to_expect_create_failed_(0),
60 times_create_failed_(0),
61 committed_at_least_once_(false),
62 context_should_support_io_surface_(false),
63 fallback_context_works_(false) {
64 media::InitializeMediaLibraryForTesting();
67 void LoseContext() {
68 context3d_->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
69 GL_INNOCENT_CONTEXT_RESET_ARB);
70 context3d_ = NULL;
73 virtual scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() {
74 return TestWebGraphicsContext3D::Create();
77 virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
78 OVERRIDE {
79 if (times_to_fail_create_) {
80 --times_to_fail_create_;
81 ExpectCreateToFail();
82 return scoped_ptr<FakeOutputSurface>();
85 scoped_ptr<TestWebGraphicsContext3D> context3d = CreateContext3d();
86 context3d_ = context3d.get();
88 if (context_should_support_io_surface_) {
89 context3d_->set_have_extension_io_surface(true);
90 context3d_->set_have_extension_egl_image(true);
93 if (delegating_renderer())
94 return FakeOutputSurface::CreateDelegating3d(context3d.Pass());
95 else
96 return FakeOutputSurface::Create3d(context3d.Pass());
99 virtual DrawResult PrepareToDrawOnThread(
100 LayerTreeHostImpl* host_impl,
101 LayerTreeHostImpl::FrameData* frame,
102 DrawResult draw_result) OVERRIDE {
103 EXPECT_EQ(DRAW_SUCCESS, draw_result);
104 if (!times_to_lose_during_draw_)
105 return draw_result;
107 --times_to_lose_during_draw_;
108 LoseContext();
110 times_to_fail_create_ = times_to_fail_recreate_;
111 times_to_fail_recreate_ = 0;
113 return draw_result;
116 virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
117 committed_at_least_once_ = true;
119 if (!times_to_lose_during_commit_)
120 return;
121 --times_to_lose_during_commit_;
122 LoseContext();
124 times_to_fail_create_ = times_to_fail_recreate_;
125 times_to_fail_recreate_ = 0;
128 virtual void DidFailToInitializeOutputSurface() OVERRIDE {
129 ++times_create_failed_;
132 virtual void TearDown() OVERRIDE {
133 LayerTreeTest::TearDown();
134 EXPECT_EQ(times_to_expect_create_failed_, times_create_failed_);
137 void ExpectCreateToFail() { ++times_to_expect_create_failed_; }
139 protected:
140 TestWebGraphicsContext3D* context3d_;
141 int times_to_fail_create_;
142 int times_to_lose_during_commit_;
143 int times_to_lose_during_draw_;
144 int times_to_fail_recreate_;
145 int times_to_expect_create_failed_;
146 int times_create_failed_;
147 bool committed_at_least_once_;
148 bool context_should_support_io_surface_;
149 bool fallback_context_works_;
152 class LayerTreeHostContextTestLostContextSucceeds
153 : public LayerTreeHostContextTest {
154 public:
155 LayerTreeHostContextTestLostContextSucceeds()
156 : LayerTreeHostContextTest(),
157 test_case_(0),
158 num_losses_(0),
159 num_losses_last_test_case_(-1),
160 recovered_context_(true),
161 first_initialized_(false) {}
163 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
165 virtual void DidInitializeOutputSurface() OVERRIDE {
166 if (first_initialized_)
167 ++num_losses_;
168 else
169 first_initialized_ = true;
171 recovered_context_ = true;
174 virtual void AfterTest() OVERRIDE { EXPECT_EQ(7u, test_case_); }
176 virtual void DidCommitAndDrawFrame() OVERRIDE {
177 // If the last frame had a context loss, then we'll commit again to
178 // recover.
179 if (!recovered_context_)
180 return;
181 if (times_to_lose_during_commit_)
182 return;
183 if (times_to_lose_during_draw_)
184 return;
186 recovered_context_ = false;
187 if (NextTestCase())
188 InvalidateAndSetNeedsCommit();
189 else
190 EndTest();
193 virtual void InvalidateAndSetNeedsCommit() {
194 // Cause damage so we try to draw.
195 layer_tree_host()->root_layer()->SetNeedsDisplay();
196 layer_tree_host()->SetNeedsCommit();
199 bool NextTestCase() {
200 static const TestCase kTests[] = {
201 // Losing the context and failing to recreate it (or losing it again
202 // immediately) a small number of times should succeed.
203 {1, // times_to_lose_during_commit
204 0, // times_to_lose_during_draw
205 0, // times_to_fail_recreate
206 false, // fallback_context_works
208 {0, // times_to_lose_during_commit
209 1, // times_to_lose_during_draw
210 0, // times_to_fail_recreate
211 false, // fallback_context_works
213 {1, // times_to_lose_during_commit
214 0, // times_to_lose_during_draw
215 3, // times_to_fail_recreate
216 false, // fallback_context_works
218 {0, // times_to_lose_during_commit
219 1, // times_to_lose_during_draw
220 3, // times_to_fail_recreate
221 false, // fallback_context_works
223 // Losing the context and recreating it any number of times should
224 // succeed.
225 {10, // times_to_lose_during_commit
226 0, // times_to_lose_during_draw
227 0, // times_to_fail_recreate
228 false, // fallback_context_works
230 {0, // times_to_lose_during_commit
231 10, // times_to_lose_during_draw
232 0, // times_to_fail_recreate
233 false, // fallback_context_works
235 // Losing the context, failing to reinitialize it, and making a fallback
236 // context should work.
237 {0, // times_to_lose_during_commit
238 1, // times_to_lose_during_draw
239 0, // times_to_fail_recreate
240 true, // fallback_context_works
241 }, };
243 if (test_case_ >= arraysize(kTests))
244 return false;
245 // Make sure that we lost our context at least once in the last test run so
246 // the test did something.
247 EXPECT_GT(num_losses_, num_losses_last_test_case_);
248 num_losses_last_test_case_ = num_losses_;
250 times_to_lose_during_commit_ =
251 kTests[test_case_].times_to_lose_during_commit;
252 times_to_lose_during_draw_ = kTests[test_case_].times_to_lose_during_draw;
253 times_to_fail_recreate_ = kTests[test_case_].times_to_fail_recreate;
254 fallback_context_works_ = kTests[test_case_].fallback_context_works;
255 ++test_case_;
256 return true;
259 struct TestCase {
260 int times_to_lose_during_commit;
261 int times_to_lose_during_draw;
262 int times_to_fail_recreate;
263 bool fallback_context_works;
266 protected:
267 size_t test_case_;
268 int num_losses_;
269 int num_losses_last_test_case_;
270 bool recovered_context_;
271 bool first_initialized_;
274 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLostContextSucceeds);
276 class LayerTreeHostClientNotReadyDoesNotCreateOutputSurface
277 : public LayerTreeHostContextTest {
278 public:
279 LayerTreeHostClientNotReadyDoesNotCreateOutputSurface()
280 : LayerTreeHostContextTest() {}
282 virtual void WillBeginTest() OVERRIDE {
283 // Override and do not signal SetLayerTreeHostClientReady.
286 virtual void BeginTest() OVERRIDE {
287 PostSetNeedsCommitToMainThread();
288 EndTest();
291 virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
292 OVERRIDE {
293 EXPECT_TRUE(false);
294 return scoped_ptr<OutputSurface>();
297 virtual void DidInitializeOutputSurface() OVERRIDE { EXPECT_TRUE(false); }
299 virtual void AfterTest() OVERRIDE {
303 MULTI_THREAD_TEST_F(LayerTreeHostClientNotReadyDoesNotCreateOutputSurface);
305 class LayerTreeHostContextTestLostContextSucceedsWithContent
306 : public LayerTreeHostContextTestLostContextSucceeds {
307 public:
308 virtual void SetupTree() OVERRIDE {
309 root_ = Layer::Create();
310 root_->SetBounds(gfx::Size(10, 10));
311 root_->SetIsDrawable(true);
313 content_ = FakeContentLayer::Create(&client_);
314 content_->SetBounds(gfx::Size(10, 10));
315 content_->SetIsDrawable(true);
317 root_->AddChild(content_);
319 layer_tree_host()->SetRootLayer(root_);
320 LayerTreeHostContextTest::SetupTree();
323 virtual void InvalidateAndSetNeedsCommit() OVERRIDE {
324 // Invalidate the render surface so we don't try to use a cached copy of the
325 // surface. We want to make sure to test the drawing paths for drawing to
326 // a child surface.
327 content_->SetNeedsDisplay();
328 LayerTreeHostContextTestLostContextSucceeds::InvalidateAndSetNeedsCommit();
331 virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
332 FakeContentLayerImpl* content_impl = static_cast<FakeContentLayerImpl*>(
333 host_impl->active_tree()->root_layer()->children()[0]);
334 // Even though the context was lost, we should have a resource. The
335 // TestWebGraphicsContext3D ensures that this resource is created with
336 // the active context.
337 EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0));
340 protected:
341 FakeContentLayerClient client_;
342 scoped_refptr<Layer> root_;
343 scoped_refptr<ContentLayer> content_;
346 // This test uses TiledLayer to check for a working context.
347 SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
348 LayerTreeHostContextTestLostContextSucceedsWithContent);
350 class LayerTreeHostContextTestCreateOutputSurfaceFails
351 : public LayerTreeHostContextTest {
352 public:
353 // Run a test that initially fails OutputSurface creation |times_to_fail|
354 // times. If |expect_fallback_attempt| is |true|, an attempt to create a
355 // fallback/software OutputSurface is expected to occur.
356 LayerTreeHostContextTestCreateOutputSurfaceFails(int times_to_fail,
357 bool expect_fallback_attempt)
358 : times_to_fail_(times_to_fail),
359 expect_fallback_attempt_(expect_fallback_attempt),
360 did_attempt_fallback_(false),
361 times_initialized_(0) {}
363 virtual void BeginTest() OVERRIDE {
364 times_to_fail_create_ = times_to_fail_;
365 PostSetNeedsCommitToMainThread();
368 virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
369 OVERRIDE {
370 scoped_ptr<FakeOutputSurface> surface =
371 LayerTreeHostContextTest::CreateFakeOutputSurface(fallback);
373 if (surface)
374 EXPECT_EQ(times_to_fail_, times_create_failed_);
376 did_attempt_fallback_ = fallback;
377 return surface.Pass();
380 virtual void DidInitializeOutputSurface() OVERRIDE { times_initialized_++; }
382 virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
383 EndTest();
386 virtual void AfterTest() OVERRIDE {
387 EXPECT_EQ(times_to_fail_, times_create_failed_);
388 EXPECT_NE(0, times_initialized_);
389 EXPECT_EQ(expect_fallback_attempt_, did_attempt_fallback_);
392 private:
393 int times_to_fail_;
394 bool expect_fallback_attempt_;
395 bool did_attempt_fallback_;
396 int times_initialized_;
399 class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
400 : public LayerTreeHostContextTestCreateOutputSurfaceFails {
401 public:
402 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
403 : LayerTreeHostContextTestCreateOutputSurfaceFails(1, false) {}
406 SINGLE_AND_MULTI_THREAD_TEST_F(
407 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce);
409 // After 4 failures we expect an attempt to create a fallback/software
410 // OutputSurface.
411 class LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback
412 : public LayerTreeHostContextTestCreateOutputSurfaceFails {
413 public:
414 LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback()
415 : LayerTreeHostContextTestCreateOutputSurfaceFails(4, true) {}
418 SINGLE_AND_MULTI_THREAD_TEST_F(
419 LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback);
421 class LayerTreeHostContextTestLostContextAndEvictTextures
422 : public LayerTreeHostContextTest {
423 public:
424 LayerTreeHostContextTestLostContextAndEvictTextures()
425 : LayerTreeHostContextTest(),
426 layer_(FakeContentLayer::Create(&client_)),
427 impl_host_(0),
428 num_commits_(0) {}
430 virtual void SetupTree() OVERRIDE {
431 layer_->SetBounds(gfx::Size(10, 20));
432 layer_tree_host()->SetRootLayer(layer_);
433 LayerTreeHostContextTest::SetupTree();
436 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
438 void PostEvictTextures() {
439 if (HasImplThread()) {
440 ImplThreadTaskRunner()->PostTask(
441 FROM_HERE,
442 base::Bind(&LayerTreeHostContextTestLostContextAndEvictTextures::
443 EvictTexturesOnImplThread,
444 base::Unretained(this)));
445 } else {
446 DebugScopedSetImplThread impl(proxy());
447 EvictTexturesOnImplThread();
451 void EvictTexturesOnImplThread() {
452 impl_host_->EvictTexturesForTesting();
453 if (lose_after_evict_)
454 LoseContext();
457 virtual void DidCommitAndDrawFrame() OVERRIDE {
458 if (num_commits_ > 1)
459 return;
460 EXPECT_TRUE(layer_->HaveBackingAt(0, 0));
461 PostEvictTextures();
464 virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
465 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
466 if (num_commits_ > 1)
467 return;
468 ++num_commits_;
469 if (!lose_after_evict_)
470 LoseContext();
471 impl_host_ = impl;
474 virtual void DidInitializeOutputSurface() OVERRIDE { EndTest(); }
476 virtual void AfterTest() OVERRIDE {}
478 protected:
479 bool lose_after_evict_;
480 FakeContentLayerClient client_;
481 scoped_refptr<FakeContentLayer> layer_;
482 LayerTreeHostImpl* impl_host_;
483 int num_commits_;
486 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
487 LoseAfterEvict_SingleThread_DirectRenderer) {
488 lose_after_evict_ = true;
489 RunTest(false, false, false);
492 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
493 LoseAfterEvict_SingleThread_DelegatingRenderer) {
494 lose_after_evict_ = true;
495 RunTest(false, true, false);
498 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
499 LoseAfterEvict_MultiThread_DirectRenderer_MainThreadPaint) {
500 lose_after_evict_ = true;
501 RunTest(true, false, false);
504 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
505 LoseAfterEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
506 lose_after_evict_ = true;
507 RunTest(true, true, false);
510 // Flaky on all platforms, http://crbug.com/310979
511 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
512 DISABLED_LoseAfterEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
513 lose_after_evict_ = true;
514 RunTest(true, true, true);
517 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
518 LoseBeforeEvict_SingleThread_DirectRenderer) {
519 lose_after_evict_ = false;
520 RunTest(false, false, false);
523 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
524 LoseBeforeEvict_SingleThread_DelegatingRenderer) {
525 lose_after_evict_ = false;
526 RunTest(false, true, false);
529 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
530 LoseBeforeEvict_MultiThread_DirectRenderer_MainThreadPaint) {
531 lose_after_evict_ = false;
532 RunTest(true, false, false);
535 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
536 LoseBeforeEvict_MultiThread_DirectRenderer_ImplSidePaint) {
537 lose_after_evict_ = false;
538 RunTest(true, false, true);
541 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
542 LoseBeforeEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
543 lose_after_evict_ = false;
544 RunTest(true, true, false);
547 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
548 LoseBeforeEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
549 lose_after_evict_ = false;
550 RunTest(true, true, true);
553 class LayerTreeHostContextTestLostContextWhileUpdatingResources
554 : public LayerTreeHostContextTest {
555 public:
556 LayerTreeHostContextTestLostContextWhileUpdatingResources()
557 : parent_(FakeContentLayer::Create(&client_)),
558 num_children_(50),
559 times_to_lose_on_end_query_(3) {}
561 virtual scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() OVERRIDE {
562 scoped_ptr<TestWebGraphicsContext3D> context =
563 LayerTreeHostContextTest::CreateContext3d();
564 if (times_to_lose_on_end_query_) {
565 --times_to_lose_on_end_query_;
566 context->set_times_end_query_succeeds(5);
568 return context.Pass();
571 virtual void SetupTree() OVERRIDE {
572 parent_->SetBounds(gfx::Size(num_children_, 1));
574 for (int i = 0; i < num_children_; i++) {
575 scoped_refptr<FakeContentLayer> child =
576 FakeContentLayer::Create(&client_);
577 child->SetPosition(gfx::PointF(i, 0.f));
578 child->SetBounds(gfx::Size(1, 1));
579 parent_->AddChild(child);
582 layer_tree_host()->SetRootLayer(parent_);
583 LayerTreeHostContextTest::SetupTree();
586 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
588 virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
589 EXPECT_EQ(0, times_to_lose_on_end_query_);
590 EndTest();
593 virtual void AfterTest() OVERRIDE {
594 EXPECT_EQ(0, times_to_lose_on_end_query_);
597 private:
598 FakeContentLayerClient client_;
599 scoped_refptr<FakeContentLayer> parent_;
600 int num_children_;
601 int times_to_lose_on_end_query_;
604 SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
605 LayerTreeHostContextTestLostContextWhileUpdatingResources);
607 class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
608 public:
609 LayerTreeHostContextTestLayersNotified()
610 : LayerTreeHostContextTest(), num_commits_(0) {}
612 virtual void SetupTree() OVERRIDE {
613 root_ = FakeContentLayer::Create(&client_);
614 child_ = FakeContentLayer::Create(&client_);
615 grandchild_ = FakeContentLayer::Create(&client_);
617 root_->AddChild(child_);
618 child_->AddChild(grandchild_);
620 layer_tree_host()->SetRootLayer(root_);
621 LayerTreeHostContextTest::SetupTree();
624 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
626 virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
627 LayerTreeHostContextTest::DidActivateTreeOnThread(host_impl);
629 FakeContentLayerImpl* root = static_cast<FakeContentLayerImpl*>(
630 host_impl->active_tree()->root_layer());
631 FakeContentLayerImpl* child =
632 static_cast<FakeContentLayerImpl*>(root->children()[0]);
633 FakeContentLayerImpl* grandchild =
634 static_cast<FakeContentLayerImpl*>(child->children()[0]);
636 ++num_commits_;
637 switch (num_commits_) {
638 case 1:
639 EXPECT_EQ(0u, root->lost_output_surface_count());
640 EXPECT_EQ(0u, child->lost_output_surface_count());
641 EXPECT_EQ(0u, grandchild->lost_output_surface_count());
642 // Lose the context and struggle to recreate it.
643 LoseContext();
644 times_to_fail_create_ = 1;
645 break;
646 case 2:
647 EXPECT_GE(1u, root->lost_output_surface_count());
648 EXPECT_GE(1u, child->lost_output_surface_count());
649 EXPECT_GE(1u, grandchild->lost_output_surface_count());
650 EndTest();
651 break;
652 default:
653 NOTREACHED();
657 virtual void AfterTest() OVERRIDE {}
659 private:
660 int num_commits_;
662 FakeContentLayerClient client_;
663 scoped_refptr<FakeContentLayer> root_;
664 scoped_refptr<FakeContentLayer> child_;
665 scoped_refptr<FakeContentLayer> grandchild_;
668 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified);
670 class LayerTreeHostContextTestDontUseLostResources
671 : public LayerTreeHostContextTest {
672 public:
673 LayerTreeHostContextTestDontUseLostResources() : lost_context_(false) {
674 context_should_support_io_surface_ = true;
676 child_output_surface_ = FakeOutputSurface::Create3d();
677 child_output_surface_->BindToClient(&output_surface_client_);
678 shared_bitmap_manager_.reset(new TestSharedBitmapManager());
679 child_resource_provider_ = ResourceProvider::Create(
680 child_output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1,
681 false);
684 static void EmptyReleaseCallback(unsigned sync_point, bool lost) {}
686 virtual void SetupTree() OVERRIDE {
687 gpu::gles2::GLES2Interface* gl =
688 child_output_surface_->context_provider()->ContextGL();
690 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
692 scoped_ptr<TestRenderPass> pass_for_quad = TestRenderPass::Create();
693 pass_for_quad->SetNew(
694 // AppendOneOfEveryQuadType() makes a RenderPass quad with this id.
695 RenderPass::Id(2, 1),
696 gfx::Rect(0, 0, 10, 10),
697 gfx::Rect(0, 0, 10, 10),
698 gfx::Transform());
700 scoped_ptr<TestRenderPass> pass = TestRenderPass::Create();
701 pass->SetNew(RenderPass::Id(1, 1),
702 gfx::Rect(0, 0, 10, 10),
703 gfx::Rect(0, 0, 10, 10),
704 gfx::Transform());
705 pass->AppendOneOfEveryQuadType(child_resource_provider_.get(),
706 RenderPass::Id(2, 1));
708 frame_data->render_pass_list.push_back(pass_for_quad.PassAs<RenderPass>());
709 frame_data->render_pass_list.push_back(pass.PassAs<RenderPass>());
711 delegated_resource_collection_ = new DelegatedFrameResourceCollection;
712 delegated_frame_provider_ = new DelegatedFrameProvider(
713 delegated_resource_collection_.get(), frame_data.Pass());
715 ResourceProvider::ResourceId resource =
716 child_resource_provider_->CreateResource(
717 gfx::Size(4, 4),
718 GL_CLAMP_TO_EDGE,
719 ResourceProvider::TextureUsageAny,
720 RGBA_8888);
721 ResourceProvider::ScopedWriteLockGL lock(child_resource_provider_.get(),
722 resource);
724 gpu::Mailbox mailbox;
725 gl->GenMailboxCHROMIUM(mailbox.name);
726 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
728 scoped_refptr<Layer> root = Layer::Create();
729 root->SetBounds(gfx::Size(10, 10));
730 root->SetIsDrawable(true);
732 scoped_refptr<FakeDelegatedRendererLayer> delegated =
733 FakeDelegatedRendererLayer::Create(delegated_frame_provider_.get());
734 delegated->SetBounds(gfx::Size(10, 10));
735 delegated->SetIsDrawable(true);
736 root->AddChild(delegated);
738 scoped_refptr<ContentLayer> content = ContentLayer::Create(&client_);
739 content->SetBounds(gfx::Size(10, 10));
740 content->SetIsDrawable(true);
741 root->AddChild(content);
743 scoped_refptr<TextureLayer> texture = TextureLayer::CreateForMailbox(NULL);
744 texture->SetBounds(gfx::Size(10, 10));
745 texture->SetIsDrawable(true);
746 texture->SetTextureMailbox(
747 TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point),
748 SingleReleaseCallback::Create(
749 base::Bind(&LayerTreeHostContextTestDontUseLostResources::
750 EmptyReleaseCallback)));
751 root->AddChild(texture);
753 scoped_refptr<ContentLayer> mask = ContentLayer::Create(&client_);
754 mask->SetBounds(gfx::Size(10, 10));
756 scoped_refptr<ContentLayer> content_with_mask =
757 ContentLayer::Create(&client_);
758 content_with_mask->SetBounds(gfx::Size(10, 10));
759 content_with_mask->SetIsDrawable(true);
760 content_with_mask->SetMaskLayer(mask.get());
761 root->AddChild(content_with_mask);
763 scoped_refptr<VideoLayer> video_color =
764 VideoLayer::Create(&color_frame_provider_);
765 video_color->SetBounds(gfx::Size(10, 10));
766 video_color->SetIsDrawable(true);
767 root->AddChild(video_color);
769 scoped_refptr<VideoLayer> video_hw =
770 VideoLayer::Create(&hw_frame_provider_);
771 video_hw->SetBounds(gfx::Size(10, 10));
772 video_hw->SetIsDrawable(true);
773 root->AddChild(video_hw);
775 scoped_refptr<VideoLayer> video_scaled_hw =
776 VideoLayer::Create(&scaled_hw_frame_provider_);
777 video_scaled_hw->SetBounds(gfx::Size(10, 10));
778 video_scaled_hw->SetIsDrawable(true);
779 root->AddChild(video_scaled_hw);
781 color_video_frame_ = VideoFrame::CreateColorFrame(
782 gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
783 hw_video_frame_ =
784 VideoFrame::WrapNativeTexture(make_scoped_ptr(new gpu::MailboxHolder(
785 mailbox, GL_TEXTURE_2D, sync_point)),
786 media::VideoFrame::ReleaseMailboxCB(),
787 gfx::Size(4, 4),
788 gfx::Rect(0, 0, 4, 4),
789 gfx::Size(4, 4),
790 base::TimeDelta(),
791 VideoFrame::ReadPixelsCB());
792 scaled_hw_video_frame_ =
793 VideoFrame::WrapNativeTexture(make_scoped_ptr(new gpu::MailboxHolder(
794 mailbox, GL_TEXTURE_2D, sync_point)),
795 media::VideoFrame::ReleaseMailboxCB(),
796 gfx::Size(4, 4),
797 gfx::Rect(0, 0, 3, 2),
798 gfx::Size(4, 4),
799 base::TimeDelta(),
800 VideoFrame::ReadPixelsCB());
802 color_frame_provider_.set_frame(color_video_frame_);
803 hw_frame_provider_.set_frame(hw_video_frame_);
804 scaled_hw_frame_provider_.set_frame(scaled_hw_video_frame_);
806 if (!delegating_renderer()) {
807 // TODO(danakj): IOSurface layer can not be transported. crbug.com/239335
808 scoped_refptr<IOSurfaceLayer> io_surface = IOSurfaceLayer::Create();
809 io_surface->SetBounds(gfx::Size(10, 10));
810 io_surface->SetIsDrawable(true);
811 io_surface->SetIOSurfaceProperties(1, gfx::Size(10, 10));
812 root->AddChild(io_surface);
815 // Enable the hud.
816 LayerTreeDebugState debug_state;
817 debug_state.show_property_changed_rects = true;
818 layer_tree_host()->SetDebugState(debug_state);
820 scoped_refptr<PaintedScrollbarLayer> scrollbar =
821 PaintedScrollbarLayer::Create(
822 scoped_ptr<Scrollbar>(new FakeScrollbar).Pass(), content->id());
823 scrollbar->SetBounds(gfx::Size(10, 10));
824 scrollbar->SetIsDrawable(true);
825 root->AddChild(scrollbar);
827 layer_tree_host()->SetRootLayer(root);
828 LayerTreeHostContextTest::SetupTree();
831 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
833 virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
834 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
836 if (host_impl->active_tree()->source_frame_number() == 3) {
837 // On the third commit we're recovering from context loss. Hardware
838 // video frames should not be reused by the VideoFrameProvider, but
839 // software frames can be.
840 hw_frame_provider_.set_frame(NULL);
841 scaled_hw_frame_provider_.set_frame(NULL);
845 virtual DrawResult PrepareToDrawOnThread(
846 LayerTreeHostImpl* host_impl,
847 LayerTreeHostImpl::FrameData* frame,
848 DrawResult draw_result) OVERRIDE {
849 if (host_impl->active_tree()->source_frame_number() == 2) {
850 // Lose the context during draw on the second commit. This will cause
851 // a third commit to recover.
852 context3d_->set_times_bind_texture_succeeds(0);
854 return draw_result;
857 virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
858 OVERRIDE {
859 // This will get called twice:
860 // First when we create the initial output surface...
861 if (layer_tree_host()->source_frame_number() > 0) {
862 // ... and then again after we forced the context to be lost.
863 lost_context_ = true;
865 return LayerTreeHostContextTest::CreateFakeOutputSurface(fallback);
868 virtual void DidCommitAndDrawFrame() OVERRIDE {
869 ASSERT_TRUE(layer_tree_host()->hud_layer());
870 // End the test once we know the 3nd frame drew.
871 if (layer_tree_host()->source_frame_number() < 5) {
872 layer_tree_host()->root_layer()->SetNeedsDisplay();
873 layer_tree_host()->SetNeedsCommit();
874 } else {
875 EndTest();
879 virtual void AfterTest() OVERRIDE { EXPECT_TRUE(lost_context_); }
881 private:
882 FakeContentLayerClient client_;
883 bool lost_context_;
885 FakeOutputSurfaceClient output_surface_client_;
886 scoped_ptr<FakeOutputSurface> child_output_surface_;
887 scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
888 scoped_ptr<ResourceProvider> child_resource_provider_;
890 scoped_refptr<DelegatedFrameResourceCollection>
891 delegated_resource_collection_;
892 scoped_refptr<DelegatedFrameProvider> delegated_frame_provider_;
894 scoped_refptr<VideoFrame> color_video_frame_;
895 scoped_refptr<VideoFrame> hw_video_frame_;
896 scoped_refptr<VideoFrame> scaled_hw_video_frame_;
898 FakeVideoFrameProvider color_frame_provider_;
899 FakeVideoFrameProvider hw_frame_provider_;
900 FakeVideoFrameProvider scaled_hw_frame_provider_;
903 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources);
905 class ImplSidePaintingLayerTreeHostContextTest
906 : public LayerTreeHostContextTest {
907 public:
908 virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
909 settings->impl_side_painting = true;
913 class LayerTreeHostContextTestImplSidePainting
914 : public ImplSidePaintingLayerTreeHostContextTest {
915 public:
916 virtual void SetupTree() OVERRIDE {
917 scoped_refptr<Layer> root = Layer::Create();
918 root->SetBounds(gfx::Size(10, 10));
919 root->SetIsDrawable(true);
921 scoped_refptr<PictureLayer> picture = PictureLayer::Create(&client_);
922 picture->SetBounds(gfx::Size(10, 10));
923 picture->SetIsDrawable(true);
924 root->AddChild(picture);
926 layer_tree_host()->SetRootLayer(root);
927 LayerTreeHostContextTest::SetupTree();
930 virtual void BeginTest() OVERRIDE {
931 times_to_lose_during_commit_ = 1;
932 PostSetNeedsCommitToMainThread();
935 virtual void AfterTest() OVERRIDE {}
937 virtual void DidInitializeOutputSurface() OVERRIDE { EndTest(); }
939 private:
940 FakeContentLayerClient client_;
943 MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting);
945 class ScrollbarLayerLostContext : public LayerTreeHostContextTest {
946 public:
947 ScrollbarLayerLostContext() : commits_(0) {}
949 virtual void BeginTest() OVERRIDE {
950 scoped_refptr<Layer> scroll_layer = Layer::Create();
951 scrollbar_layer_ =
952 FakePaintedScrollbarLayer::Create(false, true, scroll_layer->id());
953 scrollbar_layer_->SetBounds(gfx::Size(10, 100));
954 layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
955 layer_tree_host()->root_layer()->AddChild(scroll_layer);
956 PostSetNeedsCommitToMainThread();
959 virtual void AfterTest() OVERRIDE {}
961 virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
962 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
964 ++commits_;
965 switch (commits_) {
966 case 1:
967 // First (regular) update, we should upload 2 resources (thumb, and
968 // backtrack).
969 EXPECT_EQ(1, scrollbar_layer_->update_count());
970 LoseContext();
971 break;
972 case 2:
973 // Second update, after the lost context, we should still upload 2
974 // resources even if the contents haven't changed.
975 EXPECT_EQ(2, scrollbar_layer_->update_count());
976 EndTest();
977 break;
978 case 3:
979 // Single thread proxy issues extra commits after context lost.
980 // http://crbug.com/287250
981 if (HasImplThread())
982 NOTREACHED();
983 break;
984 default:
985 NOTREACHED();
989 private:
990 int commits_;
991 scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer_;
994 SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext);
996 class UIResourceLostTest : public LayerTreeHostContextTest {
997 public:
998 UIResourceLostTest() : time_step_(0) {}
999 virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
1000 settings->texture_id_allocation_chunk_size = 1;
1002 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
1003 virtual void AfterTest() OVERRIDE {}
1005 // This is called on the main thread after each commit and
1006 // DidActivateTreeOnThread, with the value of time_step_ at the time
1007 // of the call to DidActivateTreeOnThread. Similar tests will do
1008 // work on the main thread in DidCommit but that is unsuitable because
1009 // the main thread work for these tests must happen after
1010 // DidActivateTreeOnThread, which happens after DidCommit with impl-side
1011 // painting.
1012 virtual void StepCompleteOnMainThread(int time_step) = 0;
1014 // Called after DidActivateTreeOnThread. If this is done during the commit,
1015 // the call to StepCompleteOnMainThread will not occur until after
1016 // the commit completes, because the main thread is blocked.
1017 void PostStepCompleteToMainThread() {
1018 proxy()->MainThreadTaskRunner()->PostTask(
1019 FROM_HERE,
1020 base::Bind(&UIResourceLostTest::StepCompleteOnMainThreadInternal,
1021 base::Unretained(this),
1022 time_step_));
1025 void PostLoseContextToImplThread() {
1026 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1027 base::SingleThreadTaskRunner* task_runner =
1028 HasImplThread() ? ImplThreadTaskRunner()
1029 : base::MessageLoopProxy::current();
1030 task_runner->PostTask(FROM_HERE,
1031 base::Bind(&LayerTreeHostContextTest::LoseContext,
1032 base::Unretained(this)));
1035 protected:
1036 int time_step_;
1037 scoped_ptr<FakeScopedUIResource> ui_resource_;
1039 private:
1040 void StepCompleteOnMainThreadInternal(int step) {
1041 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1042 StepCompleteOnMainThread(step);
1046 class UIResourceLostTestSimple : public UIResourceLostTest {
1047 public:
1048 // This is called when the commit is complete and the new layer tree has been
1049 // activated.
1050 virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) = 0;
1052 virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1053 if (!layer_tree_host()->settings().impl_side_painting) {
1054 StepCompleteOnImplThread(impl);
1055 PostStepCompleteToMainThread();
1056 ++time_step_;
1060 virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1061 if (layer_tree_host()->settings().impl_side_painting) {
1062 StepCompleteOnImplThread(impl);
1063 PostStepCompleteToMainThread();
1064 ++time_step_;
1069 // Losing context after an UI resource has been created.
1070 class UIResourceLostAfterCommit : public UIResourceLostTestSimple {
1071 public:
1072 virtual void StepCompleteOnMainThread(int step) OVERRIDE {
1073 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1074 switch (step) {
1075 case 0:
1076 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1077 // Expects a valid UIResourceId.
1078 EXPECT_NE(0, ui_resource_->id());
1079 PostSetNeedsCommitToMainThread();
1080 break;
1081 case 4:
1082 // Release resource before ending the test.
1083 ui_resource_.reset();
1084 EndTest();
1085 break;
1086 case 5:
1087 // Single thread proxy issues extra commits after context lost.
1088 // http://crbug.com/287250
1089 if (HasImplThread())
1090 NOTREACHED();
1091 break;
1092 case 6:
1093 NOTREACHED();
1097 virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) OVERRIDE {
1098 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1099 switch (time_step_) {
1100 case 1:
1101 // The resource should have been created on LTHI after the commit.
1102 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1103 PostSetNeedsCommitToMainThread();
1104 break;
1105 case 2:
1106 LoseContext();
1107 break;
1108 case 3:
1109 // The resources should have been recreated. The bitmap callback should
1110 // have been called once with the resource_lost flag set to true.
1111 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1112 // Resource Id on the impl-side have been recreated as well. Note
1113 // that the same UIResourceId persists after the context lost.
1114 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1115 PostSetNeedsCommitToMainThread();
1116 break;
1121 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostAfterCommit);
1123 // Losing context before UI resource requests can be commited. Three sequences
1124 // of creation/deletion are considered:
1125 // 1. Create one resource -> Context Lost => Expect the resource to have been
1126 // created.
1127 // 2. Delete an exisiting resource (test_id0_) -> create a second resource
1128 // (test_id1_) -> Context Lost => Expect the test_id0_ to be removed and
1129 // test_id1_ to have been created.
1130 // 3. Create one resource -> Delete that same resource -> Context Lost => Expect
1131 // the resource to not exist in the manager.
1132 class UIResourceLostBeforeCommit : public UIResourceLostTestSimple {
1133 public:
1134 UIResourceLostBeforeCommit() : test_id0_(0), test_id1_(0) {}
1136 virtual void StepCompleteOnMainThread(int step) OVERRIDE {
1137 switch (step) {
1138 case 0:
1139 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1140 // Lose the context on the impl thread before the commit.
1141 PostLoseContextToImplThread();
1142 break;
1143 case 2:
1144 // Sequence 2:
1145 // Currently one resource has been created.
1146 test_id0_ = ui_resource_->id();
1147 // Delete this resource.
1148 ui_resource_.reset();
1149 // Create another resource.
1150 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1151 test_id1_ = ui_resource_->id();
1152 // Sanity check that two resource creations return different ids.
1153 EXPECT_NE(test_id0_, test_id1_);
1154 // Lose the context on the impl thread before the commit.
1155 PostLoseContextToImplThread();
1156 break;
1157 case 3:
1158 // Clear the manager of resources.
1159 ui_resource_.reset();
1160 PostSetNeedsCommitToMainThread();
1161 break;
1162 case 4:
1163 // Sequence 3:
1164 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1165 test_id0_ = ui_resource_->id();
1166 // Sanity check the UIResourceId should not be 0.
1167 EXPECT_NE(0, test_id0_);
1168 // Usually ScopedUIResource are deleted from the manager in their
1169 // destructor (so usually ui_resource_.reset()). But here we need
1170 // ui_resource_ for the next step, so call DeleteUIResource directly.
1171 layer_tree_host()->DeleteUIResource(test_id0_);
1172 // Delete the resouce and then lose the context.
1173 PostLoseContextToImplThread();
1174 break;
1175 case 5:
1176 // Release resource before ending the test.
1177 ui_resource_.reset();
1178 EndTest();
1179 break;
1180 case 6:
1181 // Single thread proxy issues extra commits after context lost.
1182 // http://crbug.com/287250
1183 if (HasImplThread())
1184 NOTREACHED();
1185 break;
1186 case 8:
1187 NOTREACHED();
1191 virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) OVERRIDE {
1192 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1193 switch (time_step_) {
1194 case 1:
1195 // Sequence 1 (continued):
1196 // The first context lost happens before the resources were created,
1197 // and because it resulted in no resources being destroyed, it does not
1198 // trigger resource re-creation.
1199 EXPECT_EQ(1, ui_resource_->resource_create_count);
1200 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1201 // Resource Id on the impl-side has been created.
1202 PostSetNeedsCommitToMainThread();
1203 break;
1204 case 3:
1205 // Sequence 2 (continued):
1206 // The previous resource should have been deleted.
1207 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
1208 if (HasImplThread()) {
1209 // The second resource should have been created.
1210 EXPECT_NE(0u, impl->ResourceIdForUIResource(test_id1_));
1211 } else {
1212 // The extra commit that happens at context lost in the single thread
1213 // proxy changes the timing so that the resource has been destroyed.
1214 // http://crbug.com/287250
1215 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id1_));
1217 // The second resource called the resource callback once and since the
1218 // context is lost, a "resource lost" callback was also issued.
1219 EXPECT_EQ(2, ui_resource_->resource_create_count);
1220 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1221 break;
1222 case 5:
1223 // Sequence 3 (continued):
1224 // Expect the resource callback to have been called once.
1225 EXPECT_EQ(1, ui_resource_->resource_create_count);
1226 // No "resource lost" callbacks.
1227 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1228 // The UI resource id should not be valid
1229 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
1230 break;
1234 private:
1235 UIResourceId test_id0_;
1236 UIResourceId test_id1_;
1239 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeCommit);
1241 // Losing UI resource before the pending trees is activated but after the
1242 // commit. Impl-side-painting only.
1243 class UIResourceLostBeforeActivateTree : public UIResourceLostTest {
1244 virtual void StepCompleteOnMainThread(int step) OVERRIDE {
1245 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1246 switch (step) {
1247 case 0:
1248 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1249 PostSetNeedsCommitToMainThread();
1250 break;
1251 case 3:
1252 test_id_ = ui_resource_->id();
1253 ui_resource_.reset();
1254 PostSetNeedsCommitToMainThread();
1255 break;
1256 case 5:
1257 // Release resource before ending the test.
1258 ui_resource_.reset();
1259 EndTest();
1260 break;
1261 case 6:
1262 // Make sure no extra commits happened.
1263 NOTREACHED();
1267 virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1268 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1269 switch (time_step_) {
1270 case 2:
1271 PostSetNeedsCommitToMainThread();
1272 break;
1273 case 4:
1274 PostSetNeedsCommitToMainThread();
1275 break;
1279 virtual void WillActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1280 switch (time_step_) {
1281 case 1:
1282 // The resource creation callback has been called.
1283 EXPECT_EQ(1, ui_resource_->resource_create_count);
1284 // The resource is not yet lost (sanity check).
1285 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1286 // The resource should not have been created yet on the impl-side.
1287 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1288 LoseContext();
1289 break;
1290 case 3:
1291 LoseContext();
1292 break;
1296 virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1297 LayerTreeHostContextTest::DidActivateTreeOnThread(impl);
1298 switch (time_step_) {
1299 case 1:
1300 // The pending requests on the impl-side should have been processed.
1301 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1302 break;
1303 case 2:
1304 // The "lost resource" callback should have been called once.
1305 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1306 break;
1307 case 4:
1308 // The resource is deleted and should not be in the manager. Use
1309 // test_id_ since ui_resource_ has been deleted.
1310 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id_));
1311 break;
1314 PostStepCompleteToMainThread();
1315 ++time_step_;
1318 private:
1319 UIResourceId test_id_;
1322 TEST_F(UIResourceLostBeforeActivateTree,
1323 RunMultiThread_DirectRenderer_ImplSidePaint) {
1324 RunTest(true, false, true);
1327 TEST_F(UIResourceLostBeforeActivateTree,
1328 RunMultiThread_DelegatingRenderer_ImplSidePaint) {
1329 RunTest(true, true, true);
1332 // Resources evicted explicitly and by visibility changes.
1333 class UIResourceLostEviction : public UIResourceLostTestSimple {
1334 public:
1335 virtual void StepCompleteOnMainThread(int step) OVERRIDE {
1336 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1337 switch (step) {
1338 case 0:
1339 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1340 EXPECT_NE(0, ui_resource_->id());
1341 PostSetNeedsCommitToMainThread();
1342 break;
1343 case 2:
1344 // Make the tree not visible.
1345 PostSetVisibleToMainThread(false);
1346 break;
1347 case 3:
1348 // Release resource before ending the test.
1349 ui_resource_.reset();
1350 EndTest();
1351 break;
1352 case 4:
1353 NOTREACHED();
1357 virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* impl,
1358 bool visible) OVERRIDE {
1359 TestWebGraphicsContext3D* context = TestContext();
1360 if (!visible) {
1361 // All resources should have been evicted.
1362 ASSERT_EQ(0u, context->NumTextures());
1363 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1364 EXPECT_EQ(2, ui_resource_->resource_create_count);
1365 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1366 // Drawing is disabled both because of the evicted resources and
1367 // because the renderer is not visible.
1368 EXPECT_FALSE(impl->CanDraw());
1369 // Make the renderer visible again.
1370 PostSetVisibleToMainThread(true);
1374 virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) OVERRIDE {
1375 TestWebGraphicsContext3D* context = TestContext();
1376 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1377 switch (time_step_) {
1378 case 1:
1379 // The resource should have been created on LTHI after the commit.
1380 ASSERT_EQ(1u, context->NumTextures());
1381 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1382 EXPECT_EQ(1, ui_resource_->resource_create_count);
1383 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1384 EXPECT_TRUE(impl->CanDraw());
1385 // Evict all UI resources. This will trigger a commit.
1386 impl->EvictAllUIResources();
1387 ASSERT_EQ(0u, context->NumTextures());
1388 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1389 EXPECT_EQ(1, ui_resource_->resource_create_count);
1390 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1391 EXPECT_FALSE(impl->CanDraw());
1392 break;
1393 case 2:
1394 // The resource should have been recreated.
1395 ASSERT_EQ(1u, context->NumTextures());
1396 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1397 EXPECT_EQ(2, ui_resource_->resource_create_count);
1398 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1399 EXPECT_TRUE(impl->CanDraw());
1400 break;
1401 case 3:
1402 // The resource should have been recreated after visibility was
1403 // restored.
1404 ASSERT_EQ(1u, context->NumTextures());
1405 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1406 EXPECT_EQ(3, ui_resource_->resource_create_count);
1407 EXPECT_EQ(2, ui_resource_->lost_resource_count);
1408 EXPECT_TRUE(impl->CanDraw());
1409 break;
1414 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction);
1416 class LayerTreeHostContextTestSurfaceCreateCallback
1417 : public LayerTreeHostContextTest {
1418 public:
1419 LayerTreeHostContextTestSurfaceCreateCallback()
1420 : LayerTreeHostContextTest(),
1421 layer_(FakeContentLayer::Create(&client_)) {}
1423 virtual void SetupTree() OVERRIDE {
1424 layer_->SetBounds(gfx::Size(10, 20));
1425 layer_tree_host()->SetRootLayer(layer_);
1426 LayerTreeHostContextTest::SetupTree();
1429 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
1431 virtual void DidCommit() OVERRIDE {
1432 switch (layer_tree_host()->source_frame_number()) {
1433 case 1:
1434 EXPECT_EQ(1u, layer_->output_surface_created_count());
1435 layer_tree_host()->SetNeedsCommit();
1436 break;
1437 case 2:
1438 EXPECT_EQ(1u, layer_->output_surface_created_count());
1439 layer_tree_host()->SetNeedsCommit();
1440 break;
1441 case 3:
1442 EXPECT_EQ(1u, layer_->output_surface_created_count());
1443 break;
1444 case 4:
1445 EXPECT_EQ(2u, layer_->output_surface_created_count());
1446 layer_tree_host()->SetNeedsCommit();
1447 break;
1451 virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1452 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1453 switch (LastCommittedSourceFrameNumber(impl)) {
1454 case 0:
1455 break;
1456 case 1:
1457 break;
1458 case 2:
1459 LoseContext();
1460 break;
1461 case 3:
1462 EndTest();
1463 break;
1467 virtual void AfterTest() OVERRIDE {}
1469 protected:
1470 FakeContentLayerClient client_;
1471 scoped_refptr<FakeContentLayer> layer_;
1474 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestSurfaceCreateCallback);
1476 class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame
1477 : public LayerTreeHostContextTest {
1478 protected:
1479 virtual void BeginTest() OVERRIDE {
1480 deferred_ = false;
1481 PostSetNeedsCommitToMainThread();
1484 virtual void ScheduledActionWillSendBeginMainFrame() OVERRIDE {
1485 if (deferred_)
1486 return;
1487 deferred_ = true;
1489 // Defer commits before the BeginFrame arrives, causing it to be delayed.
1490 MainThreadTaskRunner()->PostTask(
1491 FROM_HERE,
1492 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1493 DeferCommitsOnMainThread,
1494 base::Unretained(this),
1495 true));
1496 // Meanwhile, lose the context while we are in defer commits.
1497 ImplThreadTaskRunner()->PostTask(
1498 FROM_HERE,
1499 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1500 LoseContextOnImplThread,
1501 base::Unretained(this)));
1504 void LoseContextOnImplThread() {
1505 LoseContext();
1507 // After losing the context, stop deferring commits.
1508 MainThreadTaskRunner()->PostTask(
1509 FROM_HERE,
1510 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1511 DeferCommitsOnMainThread,
1512 base::Unretained(this),
1513 false));
1516 void DeferCommitsOnMainThread(bool defer_commits) {
1517 layer_tree_host()->SetDeferCommits(defer_commits);
1520 virtual void WillBeginMainFrame() OVERRIDE {
1521 // Don't begin a frame with a lost surface.
1522 EXPECT_FALSE(layer_tree_host()->output_surface_lost());
1525 virtual void DidCommitAndDrawFrame() OVERRIDE { EndTest(); }
1527 virtual void AfterTest() OVERRIDE {}
1529 bool deferred_;
1532 // TODO(danakj): We don't use scheduler with SingleThreadProxy yet.
1533 MULTI_THREAD_TEST_F(LayerTreeHostContextTestLoseAfterSendingBeginMainFrame);
1535 } // namespace
1536 } // namespace cc