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;
49 // These tests deal with losing the 3d graphics context.
50 class LayerTreeHostContextTest : public LayerTreeTest {
52 LayerTreeHostContextTest()
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();
68 context3d_->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
69 GL_INNOCENT_CONTEXT_RESET_ARB);
73 virtual scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() {
74 return TestWebGraphicsContext3D::Create();
77 virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
79 if (times_to_fail_create_) {
80 --times_to_fail_create_;
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());
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_)
107 --times_to_lose_during_draw_;
110 times_to_fail_create_ = times_to_fail_recreate_;
111 times_to_fail_recreate_ = 0;
116 virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
117 committed_at_least_once_ = true;
119 if (!times_to_lose_during_commit_)
121 --times_to_lose_during_commit_;
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_; }
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 {
155 LayerTreeHostContextTestLostContextSucceeds()
156 : LayerTreeHostContextTest(),
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_)
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
179 if (!recovered_context_)
181 if (times_to_lose_during_commit_)
183 if (times_to_lose_during_draw_)
186 recovered_context_ = false;
188 InvalidateAndSetNeedsCommit();
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.
204 1, // times_to_lose_during_commit
205 0, // times_to_lose_during_draw
206 0, // times_to_fail_recreate
207 false, // fallback_context_works
210 0, // times_to_lose_during_commit
211 1, // times_to_lose_during_draw
212 0, // times_to_fail_recreate
213 false, // fallback_context_works
216 1, // times_to_lose_during_commit
217 0, // times_to_lose_during_draw
218 3, // times_to_fail_recreate
219 false, // fallback_context_works
222 0, // times_to_lose_during_commit
223 1, // times_to_lose_during_draw
224 3, // times_to_fail_recreate
225 false, // fallback_context_works
227 // Losing the context and recreating it any number of times should
230 10, // times_to_lose_during_commit
231 0, // times_to_lose_during_draw
232 0, // times_to_fail_recreate
233 false, // fallback_context_works
236 0, // times_to_lose_during_commit
237 10, // times_to_lose_during_draw
238 0, // times_to_fail_recreate
239 false, // fallback_context_works
241 // Losing the context, failing to reinitialize it, and making a fallback
242 // context should work.
244 0, // times_to_lose_during_commit
245 1, // times_to_lose_during_draw
246 0, // times_to_fail_recreate
247 true, // fallback_context_works
251 if (test_case_ >= arraysize(kTests))
253 // Make sure that we lost our context at least once in the last test run so
254 // the test did something.
255 EXPECT_GT(num_losses_, num_losses_last_test_case_);
256 num_losses_last_test_case_ = num_losses_;
258 times_to_lose_during_commit_ =
259 kTests[test_case_].times_to_lose_during_commit;
260 times_to_lose_during_draw_ = kTests[test_case_].times_to_lose_during_draw;
261 times_to_fail_recreate_ = kTests[test_case_].times_to_fail_recreate;
262 fallback_context_works_ = kTests[test_case_].fallback_context_works;
268 int times_to_lose_during_commit;
269 int times_to_lose_during_draw;
270 int times_to_fail_recreate;
271 bool fallback_context_works;
277 int num_losses_last_test_case_;
278 bool recovered_context_;
279 bool first_initialized_;
282 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLostContextSucceeds);
284 class LayerTreeHostClientNotReadyDoesNotCreateOutputSurface
285 : public LayerTreeHostContextTest {
287 LayerTreeHostClientNotReadyDoesNotCreateOutputSurface()
288 : LayerTreeHostContextTest() {}
290 virtual void WillBeginTest() OVERRIDE {
291 // Override and do not signal SetLayerTreeHostClientReady.
294 virtual void BeginTest() OVERRIDE {
295 PostSetNeedsCommitToMainThread();
299 virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
302 return scoped_ptr<OutputSurface>();
305 virtual void DidInitializeOutputSurface() OVERRIDE { EXPECT_TRUE(false); }
307 virtual void AfterTest() OVERRIDE {
311 MULTI_THREAD_TEST_F(LayerTreeHostClientNotReadyDoesNotCreateOutputSurface);
313 class LayerTreeHostContextTestLostContextSucceedsWithContent
314 : public LayerTreeHostContextTestLostContextSucceeds {
316 virtual void SetupTree() OVERRIDE {
317 root_ = Layer::Create();
318 root_->SetBounds(gfx::Size(10, 10));
319 root_->SetIsDrawable(true);
321 content_ = FakeContentLayer::Create(&client_);
322 content_->SetBounds(gfx::Size(10, 10));
323 content_->SetIsDrawable(true);
325 root_->AddChild(content_);
327 layer_tree_host()->SetRootLayer(root_);
328 LayerTreeHostContextTest::SetupTree();
331 virtual void InvalidateAndSetNeedsCommit() OVERRIDE {
332 // Invalidate the render surface so we don't try to use a cached copy of the
333 // surface. We want to make sure to test the drawing paths for drawing to
335 content_->SetNeedsDisplay();
336 LayerTreeHostContextTestLostContextSucceeds::InvalidateAndSetNeedsCommit();
339 virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
340 FakeContentLayerImpl* content_impl = static_cast<FakeContentLayerImpl*>(
341 host_impl->active_tree()->root_layer()->children()[0]);
342 // Even though the context was lost, we should have a resource. The
343 // TestWebGraphicsContext3D ensures that this resource is created with
344 // the active context.
345 EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0));
349 FakeContentLayerClient client_;
350 scoped_refptr<Layer> root_;
351 scoped_refptr<ContentLayer> content_;
354 // This test uses TiledLayer to check for a working context.
355 SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
356 LayerTreeHostContextTestLostContextSucceedsWithContent);
358 class LayerTreeHostContextTestCreateOutputSurfaceFails
359 : public LayerTreeHostContextTest {
361 // Run a test that initially fails OutputSurface creation |times_to_fail|
362 // times. If |expect_fallback_attempt| is |true|, an attempt to create a
363 // fallback/software OutputSurface is expected to occur.
364 LayerTreeHostContextTestCreateOutputSurfaceFails(int times_to_fail,
365 bool expect_fallback_attempt)
366 : times_to_fail_(times_to_fail),
367 expect_fallback_attempt_(expect_fallback_attempt),
368 did_attempt_fallback_(false),
369 times_initialized_(0) {}
371 virtual void BeginTest() OVERRIDE {
372 times_to_fail_create_ = times_to_fail_;
373 PostSetNeedsCommitToMainThread();
376 virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
378 scoped_ptr<FakeOutputSurface> surface =
379 LayerTreeHostContextTest::CreateFakeOutputSurface(fallback);
382 EXPECT_EQ(times_to_fail_, times_create_failed_);
384 did_attempt_fallback_ = fallback;
385 return surface.Pass();
388 virtual void DidInitializeOutputSurface() OVERRIDE { times_initialized_++; }
390 virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
394 virtual void AfterTest() OVERRIDE {
395 EXPECT_EQ(times_to_fail_, times_create_failed_);
396 EXPECT_NE(0, times_initialized_);
397 EXPECT_EQ(expect_fallback_attempt_, did_attempt_fallback_);
402 bool expect_fallback_attempt_;
403 bool did_attempt_fallback_;
404 int times_initialized_;
407 class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
408 : public LayerTreeHostContextTestCreateOutputSurfaceFails {
410 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
411 : LayerTreeHostContextTestCreateOutputSurfaceFails(1, false) {}
414 SINGLE_AND_MULTI_THREAD_TEST_F(
415 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce);
417 // After 4 failures we expect an attempt to create a fallback/software
419 class LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback
420 : public LayerTreeHostContextTestCreateOutputSurfaceFails {
422 LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback()
423 : LayerTreeHostContextTestCreateOutputSurfaceFails(4, true) {}
426 SINGLE_AND_MULTI_THREAD_TEST_F(
427 LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback);
429 class LayerTreeHostContextTestLostContextAndEvictTextures
430 : public LayerTreeHostContextTest {
432 LayerTreeHostContextTestLostContextAndEvictTextures()
433 : LayerTreeHostContextTest(),
434 layer_(FakeContentLayer::Create(&client_)),
438 virtual void SetupTree() OVERRIDE {
439 layer_->SetBounds(gfx::Size(10, 20));
440 layer_tree_host()->SetRootLayer(layer_);
441 LayerTreeHostContextTest::SetupTree();
444 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
446 void PostEvictTextures() {
447 if (HasImplThread()) {
448 ImplThreadTaskRunner()->PostTask(
450 base::Bind(&LayerTreeHostContextTestLostContextAndEvictTextures::
451 EvictTexturesOnImplThread,
452 base::Unretained(this)));
454 DebugScopedSetImplThread impl(proxy());
455 EvictTexturesOnImplThread();
459 void EvictTexturesOnImplThread() {
460 impl_host_->EvictTexturesForTesting();
461 if (lose_after_evict_)
465 virtual void DidCommitAndDrawFrame() OVERRIDE {
466 if (num_commits_ > 1)
468 EXPECT_TRUE(layer_->HaveBackingAt(0, 0));
472 virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
473 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
474 if (num_commits_ > 1)
477 if (!lose_after_evict_)
482 virtual void DidInitializeOutputSurface() OVERRIDE { EndTest(); }
484 virtual void AfterTest() OVERRIDE {}
487 bool lose_after_evict_;
488 FakeContentLayerClient client_;
489 scoped_refptr<FakeContentLayer> layer_;
490 LayerTreeHostImpl* impl_host_;
494 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
495 LoseAfterEvict_SingleThread_DirectRenderer) {
496 lose_after_evict_ = true;
497 RunTest(false, false, false);
500 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
501 LoseAfterEvict_SingleThread_DelegatingRenderer) {
502 lose_after_evict_ = true;
503 RunTest(false, true, false);
506 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
507 LoseAfterEvict_MultiThread_DirectRenderer_MainThreadPaint) {
508 lose_after_evict_ = true;
509 RunTest(true, false, false);
512 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
513 LoseAfterEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
514 lose_after_evict_ = true;
515 RunTest(true, true, false);
518 // Flaky on all platforms, http://crbug.com/310979
519 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
520 DISABLED_LoseAfterEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
521 lose_after_evict_ = true;
522 RunTest(true, true, true);
525 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
526 LoseBeforeEvict_SingleThread_DirectRenderer) {
527 lose_after_evict_ = false;
528 RunTest(false, false, false);
531 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
532 LoseBeforeEvict_SingleThread_DelegatingRenderer) {
533 lose_after_evict_ = false;
534 RunTest(false, true, false);
537 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
538 LoseBeforeEvict_MultiThread_DirectRenderer_MainThreadPaint) {
539 lose_after_evict_ = false;
540 RunTest(true, false, false);
543 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
544 LoseBeforeEvict_MultiThread_DirectRenderer_ImplSidePaint) {
545 lose_after_evict_ = false;
546 RunTest(true, false, true);
549 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
550 LoseBeforeEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
551 lose_after_evict_ = false;
552 RunTest(true, true, false);
555 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
556 LoseBeforeEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
557 lose_after_evict_ = false;
558 RunTest(true, true, true);
561 class LayerTreeHostContextTestLostContextWhileUpdatingResources
562 : public LayerTreeHostContextTest {
564 LayerTreeHostContextTestLostContextWhileUpdatingResources()
565 : parent_(FakeContentLayer::Create(&client_)),
567 times_to_lose_on_end_query_(3) {}
569 virtual scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() OVERRIDE {
570 scoped_ptr<TestWebGraphicsContext3D> context =
571 LayerTreeHostContextTest::CreateContext3d();
572 if (times_to_lose_on_end_query_) {
573 --times_to_lose_on_end_query_;
574 context->set_times_end_query_succeeds(5);
576 return context.Pass();
579 virtual void SetupTree() OVERRIDE {
580 parent_->SetBounds(gfx::Size(num_children_, 1));
582 for (int i = 0; i < num_children_; i++) {
583 scoped_refptr<FakeContentLayer> child =
584 FakeContentLayer::Create(&client_);
585 child->SetPosition(gfx::PointF(i, 0.f));
586 child->SetBounds(gfx::Size(1, 1));
587 parent_->AddChild(child);
590 layer_tree_host()->SetRootLayer(parent_);
591 LayerTreeHostContextTest::SetupTree();
594 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
596 virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
597 EXPECT_EQ(0, times_to_lose_on_end_query_);
601 virtual void AfterTest() OVERRIDE {
602 EXPECT_EQ(0, times_to_lose_on_end_query_);
606 FakeContentLayerClient client_;
607 scoped_refptr<FakeContentLayer> parent_;
609 int times_to_lose_on_end_query_;
612 SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
613 LayerTreeHostContextTestLostContextWhileUpdatingResources);
615 class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
617 LayerTreeHostContextTestLayersNotified()
618 : LayerTreeHostContextTest(), num_commits_(0) {}
620 virtual void SetupTree() OVERRIDE {
621 root_ = FakeContentLayer::Create(&client_);
622 child_ = FakeContentLayer::Create(&client_);
623 grandchild_ = FakeContentLayer::Create(&client_);
625 root_->AddChild(child_);
626 child_->AddChild(grandchild_);
628 layer_tree_host()->SetRootLayer(root_);
629 LayerTreeHostContextTest::SetupTree();
632 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
634 virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
635 LayerTreeHostContextTest::DidActivateTreeOnThread(host_impl);
637 FakeContentLayerImpl* root = static_cast<FakeContentLayerImpl*>(
638 host_impl->active_tree()->root_layer());
639 FakeContentLayerImpl* child =
640 static_cast<FakeContentLayerImpl*>(root->children()[0]);
641 FakeContentLayerImpl* grandchild =
642 static_cast<FakeContentLayerImpl*>(child->children()[0]);
645 switch (num_commits_) {
647 EXPECT_EQ(0u, root->lost_output_surface_count());
648 EXPECT_EQ(0u, child->lost_output_surface_count());
649 EXPECT_EQ(0u, grandchild->lost_output_surface_count());
650 // Lose the context and struggle to recreate it.
652 times_to_fail_create_ = 1;
655 EXPECT_GE(1u, root->lost_output_surface_count());
656 EXPECT_GE(1u, child->lost_output_surface_count());
657 EXPECT_GE(1u, grandchild->lost_output_surface_count());
665 virtual void AfterTest() OVERRIDE {}
670 FakeContentLayerClient client_;
671 scoped_refptr<FakeContentLayer> root_;
672 scoped_refptr<FakeContentLayer> child_;
673 scoped_refptr<FakeContentLayer> grandchild_;
676 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified);
678 class LayerTreeHostContextTestDontUseLostResources
679 : public LayerTreeHostContextTest {
681 LayerTreeHostContextTestDontUseLostResources() : lost_context_(false) {
682 context_should_support_io_surface_ = true;
684 child_output_surface_ = FakeOutputSurface::Create3d();
685 child_output_surface_->BindToClient(&output_surface_client_);
686 shared_bitmap_manager_.reset(new TestSharedBitmapManager());
687 child_resource_provider_ = ResourceProvider::Create(
688 child_output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1,
692 static void EmptyReleaseCallback(unsigned sync_point, bool lost) {}
694 virtual void SetupTree() OVERRIDE {
695 gpu::gles2::GLES2Interface* gl =
696 child_output_surface_->context_provider()->ContextGL();
698 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
700 scoped_ptr<TestRenderPass> pass_for_quad = TestRenderPass::Create();
701 pass_for_quad->SetNew(
702 // AppendOneOfEveryQuadType() makes a RenderPass quad with this id.
703 RenderPass::Id(2, 1),
704 gfx::Rect(0, 0, 10, 10),
705 gfx::Rect(0, 0, 10, 10),
708 scoped_ptr<TestRenderPass> pass = TestRenderPass::Create();
709 pass->SetNew(RenderPass::Id(1, 1),
710 gfx::Rect(0, 0, 10, 10),
711 gfx::Rect(0, 0, 10, 10),
713 pass->AppendOneOfEveryQuadType(child_resource_provider_.get(),
714 RenderPass::Id(2, 1));
716 frame_data->render_pass_list.push_back(pass_for_quad.PassAs<RenderPass>());
717 frame_data->render_pass_list.push_back(pass.PassAs<RenderPass>());
719 delegated_resource_collection_ = new DelegatedFrameResourceCollection;
720 delegated_frame_provider_ = new DelegatedFrameProvider(
721 delegated_resource_collection_.get(), frame_data.Pass());
723 ResourceProvider::ResourceId resource =
724 child_resource_provider_->CreateResource(
727 ResourceProvider::TextureUsageAny,
729 ResourceProvider::ScopedWriteLockGL lock(child_resource_provider_.get(),
732 gpu::Mailbox mailbox;
733 gl->GenMailboxCHROMIUM(mailbox.name);
734 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
736 scoped_refptr<Layer> root = Layer::Create();
737 root->SetBounds(gfx::Size(10, 10));
738 root->SetIsDrawable(true);
740 scoped_refptr<FakeDelegatedRendererLayer> delegated =
741 FakeDelegatedRendererLayer::Create(delegated_frame_provider_.get());
742 delegated->SetBounds(gfx::Size(10, 10));
743 delegated->SetIsDrawable(true);
744 root->AddChild(delegated);
746 scoped_refptr<ContentLayer> content = ContentLayer::Create(&client_);
747 content->SetBounds(gfx::Size(10, 10));
748 content->SetIsDrawable(true);
749 root->AddChild(content);
751 scoped_refptr<TextureLayer> texture = TextureLayer::CreateForMailbox(NULL);
752 texture->SetBounds(gfx::Size(10, 10));
753 texture->SetIsDrawable(true);
754 texture->SetTextureMailbox(
755 TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point),
756 SingleReleaseCallback::Create(
757 base::Bind(&LayerTreeHostContextTestDontUseLostResources::
758 EmptyReleaseCallback)));
759 root->AddChild(texture);
761 scoped_refptr<ContentLayer> mask = ContentLayer::Create(&client_);
762 mask->SetBounds(gfx::Size(10, 10));
764 scoped_refptr<ContentLayer> content_with_mask =
765 ContentLayer::Create(&client_);
766 content_with_mask->SetBounds(gfx::Size(10, 10));
767 content_with_mask->SetIsDrawable(true);
768 content_with_mask->SetMaskLayer(mask.get());
769 root->AddChild(content_with_mask);
771 scoped_refptr<VideoLayer> video_color =
772 VideoLayer::Create(&color_frame_provider_, media::VIDEO_ROTATION_0);
773 video_color->SetBounds(gfx::Size(10, 10));
774 video_color->SetIsDrawable(true);
775 root->AddChild(video_color);
777 scoped_refptr<VideoLayer> video_hw =
778 VideoLayer::Create(&hw_frame_provider_, media::VIDEO_ROTATION_0);
779 video_hw->SetBounds(gfx::Size(10, 10));
780 video_hw->SetIsDrawable(true);
781 root->AddChild(video_hw);
783 scoped_refptr<VideoLayer> video_scaled_hw =
784 VideoLayer::Create(&scaled_hw_frame_provider_, media::VIDEO_ROTATION_0);
785 video_scaled_hw->SetBounds(gfx::Size(10, 10));
786 video_scaled_hw->SetIsDrawable(true);
787 root->AddChild(video_scaled_hw);
789 color_video_frame_ = VideoFrame::CreateColorFrame(
790 gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
792 VideoFrame::WrapNativeTexture(make_scoped_ptr(new gpu::MailboxHolder(
793 mailbox, GL_TEXTURE_2D, sync_point)),
794 media::VideoFrame::ReleaseMailboxCB(),
796 gfx::Rect(0, 0, 4, 4),
799 VideoFrame::ReadPixelsCB());
800 scaled_hw_video_frame_ =
801 VideoFrame::WrapNativeTexture(make_scoped_ptr(new gpu::MailboxHolder(
802 mailbox, GL_TEXTURE_2D, sync_point)),
803 media::VideoFrame::ReleaseMailboxCB(),
805 gfx::Rect(0, 0, 3, 2),
808 VideoFrame::ReadPixelsCB());
810 color_frame_provider_.set_frame(color_video_frame_);
811 hw_frame_provider_.set_frame(hw_video_frame_);
812 scaled_hw_frame_provider_.set_frame(scaled_hw_video_frame_);
814 if (!delegating_renderer()) {
815 // TODO(danakj): IOSurface layer can not be transported. crbug.com/239335
816 scoped_refptr<IOSurfaceLayer> io_surface = IOSurfaceLayer::Create();
817 io_surface->SetBounds(gfx::Size(10, 10));
818 io_surface->SetIsDrawable(true);
819 io_surface->SetIOSurfaceProperties(1, gfx::Size(10, 10));
820 root->AddChild(io_surface);
824 LayerTreeDebugState debug_state;
825 debug_state.show_property_changed_rects = true;
826 layer_tree_host()->SetDebugState(debug_state);
828 scoped_refptr<PaintedScrollbarLayer> scrollbar =
829 PaintedScrollbarLayer::Create(
830 scoped_ptr<Scrollbar>(new FakeScrollbar).Pass(), content->id());
831 scrollbar->SetBounds(gfx::Size(10, 10));
832 scrollbar->SetIsDrawable(true);
833 root->AddChild(scrollbar);
835 layer_tree_host()->SetRootLayer(root);
836 LayerTreeHostContextTest::SetupTree();
839 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
841 virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
842 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
844 if (host_impl->active_tree()->source_frame_number() == 3) {
845 // On the third commit we're recovering from context loss. Hardware
846 // video frames should not be reused by the VideoFrameProvider, but
847 // software frames can be.
848 hw_frame_provider_.set_frame(NULL);
849 scaled_hw_frame_provider_.set_frame(NULL);
853 virtual DrawResult PrepareToDrawOnThread(
854 LayerTreeHostImpl* host_impl,
855 LayerTreeHostImpl::FrameData* frame,
856 DrawResult draw_result) OVERRIDE {
857 if (host_impl->active_tree()->source_frame_number() == 2) {
858 // Lose the context during draw on the second commit. This will cause
859 // a third commit to recover.
860 context3d_->set_times_bind_texture_succeeds(0);
865 virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
867 // This will get called twice:
868 // First when we create the initial output surface...
869 if (layer_tree_host()->source_frame_number() > 0) {
870 // ... and then again after we forced the context to be lost.
871 lost_context_ = true;
873 return LayerTreeHostContextTest::CreateFakeOutputSurface(fallback);
876 virtual void DidCommitAndDrawFrame() OVERRIDE {
877 ASSERT_TRUE(layer_tree_host()->hud_layer());
878 // End the test once we know the 3nd frame drew.
879 if (layer_tree_host()->source_frame_number() < 5) {
880 layer_tree_host()->root_layer()->SetNeedsDisplay();
881 layer_tree_host()->SetNeedsCommit();
887 virtual void AfterTest() OVERRIDE { EXPECT_TRUE(lost_context_); }
890 FakeContentLayerClient client_;
893 FakeOutputSurfaceClient output_surface_client_;
894 scoped_ptr<FakeOutputSurface> child_output_surface_;
895 scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
896 scoped_ptr<ResourceProvider> child_resource_provider_;
898 scoped_refptr<DelegatedFrameResourceCollection>
899 delegated_resource_collection_;
900 scoped_refptr<DelegatedFrameProvider> delegated_frame_provider_;
902 scoped_refptr<VideoFrame> color_video_frame_;
903 scoped_refptr<VideoFrame> hw_video_frame_;
904 scoped_refptr<VideoFrame> scaled_hw_video_frame_;
906 FakeVideoFrameProvider color_frame_provider_;
907 FakeVideoFrameProvider hw_frame_provider_;
908 FakeVideoFrameProvider scaled_hw_frame_provider_;
911 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources);
913 class ImplSidePaintingLayerTreeHostContextTest
914 : public LayerTreeHostContextTest {
916 virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
917 settings->impl_side_painting = true;
921 class LayerTreeHostContextTestImplSidePainting
922 : public ImplSidePaintingLayerTreeHostContextTest {
924 virtual void SetupTree() OVERRIDE {
925 scoped_refptr<Layer> root = Layer::Create();
926 root->SetBounds(gfx::Size(10, 10));
927 root->SetIsDrawable(true);
929 scoped_refptr<PictureLayer> picture = PictureLayer::Create(&client_);
930 picture->SetBounds(gfx::Size(10, 10));
931 picture->SetIsDrawable(true);
932 root->AddChild(picture);
934 layer_tree_host()->SetRootLayer(root);
935 LayerTreeHostContextTest::SetupTree();
938 virtual void BeginTest() OVERRIDE {
939 times_to_lose_during_commit_ = 1;
940 PostSetNeedsCommitToMainThread();
943 virtual void AfterTest() OVERRIDE {}
945 virtual void DidInitializeOutputSurface() OVERRIDE { EndTest(); }
948 FakeContentLayerClient client_;
951 MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting);
953 class ScrollbarLayerLostContext : public LayerTreeHostContextTest {
955 ScrollbarLayerLostContext() : commits_(0) {}
957 virtual void BeginTest() OVERRIDE {
958 scoped_refptr<Layer> scroll_layer = Layer::Create();
960 FakePaintedScrollbarLayer::Create(false, true, scroll_layer->id());
961 scrollbar_layer_->SetBounds(gfx::Size(10, 100));
962 layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
963 layer_tree_host()->root_layer()->AddChild(scroll_layer);
964 PostSetNeedsCommitToMainThread();
967 virtual void AfterTest() OVERRIDE {}
969 virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
970 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
975 // First (regular) update, we should upload 2 resources (thumb, and
977 EXPECT_EQ(1, scrollbar_layer_->update_count());
981 // Second update, after the lost context, we should still upload 2
982 // resources even if the contents haven't changed.
983 EXPECT_EQ(2, scrollbar_layer_->update_count());
987 // Single thread proxy issues extra commits after context lost.
988 // http://crbug.com/287250
999 scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer_;
1002 SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext);
1004 class UIResourceLostTest : public LayerTreeHostContextTest {
1006 UIResourceLostTest() : time_step_(0) {}
1007 virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
1008 settings->texture_id_allocation_chunk_size = 1;
1010 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
1011 virtual void AfterTest() OVERRIDE {}
1013 // This is called on the main thread after each commit and
1014 // DidActivateTreeOnThread, with the value of time_step_ at the time
1015 // of the call to DidActivateTreeOnThread. Similar tests will do
1016 // work on the main thread in DidCommit but that is unsuitable because
1017 // the main thread work for these tests must happen after
1018 // DidActivateTreeOnThread, which happens after DidCommit with impl-side
1020 virtual void StepCompleteOnMainThread(int time_step) = 0;
1022 // Called after DidActivateTreeOnThread. If this is done during the commit,
1023 // the call to StepCompleteOnMainThread will not occur until after
1024 // the commit completes, because the main thread is blocked.
1025 void PostStepCompleteToMainThread() {
1026 proxy()->MainThreadTaskRunner()->PostTask(
1028 base::Bind(&UIResourceLostTest::StepCompleteOnMainThreadInternal,
1029 base::Unretained(this),
1033 void PostLoseContextToImplThread() {
1034 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1035 base::SingleThreadTaskRunner* task_runner =
1036 HasImplThread() ? ImplThreadTaskRunner()
1037 : base::MessageLoopProxy::current();
1038 task_runner->PostTask(FROM_HERE,
1039 base::Bind(&LayerTreeHostContextTest::LoseContext,
1040 base::Unretained(this)));
1045 scoped_ptr<FakeScopedUIResource> ui_resource_;
1048 void StepCompleteOnMainThreadInternal(int step) {
1049 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1050 StepCompleteOnMainThread(step);
1054 class UIResourceLostTestSimple : public UIResourceLostTest {
1056 // This is called when the commit is complete and the new layer tree has been
1058 virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) = 0;
1060 virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1061 if (!layer_tree_host()->settings().impl_side_painting) {
1062 StepCompleteOnImplThread(impl);
1063 PostStepCompleteToMainThread();
1068 virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1069 if (layer_tree_host()->settings().impl_side_painting) {
1070 StepCompleteOnImplThread(impl);
1071 PostStepCompleteToMainThread();
1077 // Losing context after an UI resource has been created.
1078 class UIResourceLostAfterCommit : public UIResourceLostTestSimple {
1080 virtual void StepCompleteOnMainThread(int step) OVERRIDE {
1081 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1084 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1085 // Expects a valid UIResourceId.
1086 EXPECT_NE(0, ui_resource_->id());
1087 PostSetNeedsCommitToMainThread();
1090 // Release resource before ending the test.
1091 ui_resource_.reset();
1095 // Single thread proxy issues extra commits after context lost.
1096 // http://crbug.com/287250
1097 if (HasImplThread())
1105 virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) OVERRIDE {
1106 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1107 switch (time_step_) {
1109 // The resource should have been created on LTHI after the commit.
1110 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1111 PostSetNeedsCommitToMainThread();
1117 // The resources should have been recreated. The bitmap callback should
1118 // have been called once with the resource_lost flag set to true.
1119 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1120 // Resource Id on the impl-side have been recreated as well. Note
1121 // that the same UIResourceId persists after the context lost.
1122 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1123 PostSetNeedsCommitToMainThread();
1129 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostAfterCommit);
1131 // Losing context before UI resource requests can be commited. Three sequences
1132 // of creation/deletion are considered:
1133 // 1. Create one resource -> Context Lost => Expect the resource to have been
1135 // 2. Delete an exisiting resource (test_id0_) -> create a second resource
1136 // (test_id1_) -> Context Lost => Expect the test_id0_ to be removed and
1137 // test_id1_ to have been created.
1138 // 3. Create one resource -> Delete that same resource -> Context Lost => Expect
1139 // the resource to not exist in the manager.
1140 class UIResourceLostBeforeCommit : public UIResourceLostTestSimple {
1142 UIResourceLostBeforeCommit() : test_id0_(0), test_id1_(0) {}
1144 virtual void StepCompleteOnMainThread(int step) OVERRIDE {
1147 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1148 // Lose the context on the impl thread before the commit.
1149 PostLoseContextToImplThread();
1153 // Currently one resource has been created.
1154 test_id0_ = ui_resource_->id();
1155 // Delete this resource.
1156 ui_resource_.reset();
1157 // Create another resource.
1158 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1159 test_id1_ = ui_resource_->id();
1160 // Sanity check that two resource creations return different ids.
1161 EXPECT_NE(test_id0_, test_id1_);
1162 // Lose the context on the impl thread before the commit.
1163 PostLoseContextToImplThread();
1166 // Clear the manager of resources.
1167 ui_resource_.reset();
1168 PostSetNeedsCommitToMainThread();
1172 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1173 test_id0_ = ui_resource_->id();
1174 // Sanity check the UIResourceId should not be 0.
1175 EXPECT_NE(0, test_id0_);
1176 // Usually ScopedUIResource are deleted from the manager in their
1177 // destructor (so usually ui_resource_.reset()). But here we need
1178 // ui_resource_ for the next step, so call DeleteUIResource directly.
1179 layer_tree_host()->DeleteUIResource(test_id0_);
1180 // Delete the resouce and then lose the context.
1181 PostLoseContextToImplThread();
1184 // Release resource before ending the test.
1185 ui_resource_.reset();
1189 // Single thread proxy issues extra commits after context lost.
1190 // http://crbug.com/287250
1191 if (HasImplThread())
1199 virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) OVERRIDE {
1200 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1201 switch (time_step_) {
1203 // Sequence 1 (continued):
1204 // The first context lost happens before the resources were created,
1205 // and because it resulted in no resources being destroyed, it does not
1206 // trigger resource re-creation.
1207 EXPECT_EQ(1, ui_resource_->resource_create_count);
1208 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1209 // Resource Id on the impl-side has been created.
1210 PostSetNeedsCommitToMainThread();
1213 // Sequence 2 (continued):
1214 // The previous resource should have been deleted.
1215 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
1216 if (HasImplThread()) {
1217 // The second resource should have been created.
1218 EXPECT_NE(0u, impl->ResourceIdForUIResource(test_id1_));
1220 // The extra commit that happens at context lost in the single thread
1221 // proxy changes the timing so that the resource has been destroyed.
1222 // http://crbug.com/287250
1223 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id1_));
1225 // The second resource called the resource callback once and since the
1226 // context is lost, a "resource lost" callback was also issued.
1227 EXPECT_EQ(2, ui_resource_->resource_create_count);
1228 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1231 // Sequence 3 (continued):
1232 // Expect the resource callback to have been called once.
1233 EXPECT_EQ(1, ui_resource_->resource_create_count);
1234 // No "resource lost" callbacks.
1235 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1236 // The UI resource id should not be valid
1237 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
1243 UIResourceId test_id0_;
1244 UIResourceId test_id1_;
1247 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeCommit);
1249 // Losing UI resource before the pending trees is activated but after the
1250 // commit. Impl-side-painting only.
1251 class UIResourceLostBeforeActivateTree : public UIResourceLostTest {
1252 virtual void StepCompleteOnMainThread(int step) OVERRIDE {
1253 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1256 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1257 PostSetNeedsCommitToMainThread();
1260 test_id_ = ui_resource_->id();
1261 ui_resource_.reset();
1262 PostSetNeedsCommitToMainThread();
1265 // Release resource before ending the test.
1266 ui_resource_.reset();
1270 // Make sure no extra commits happened.
1275 virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1276 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1277 switch (time_step_) {
1279 PostSetNeedsCommitToMainThread();
1282 PostSetNeedsCommitToMainThread();
1287 virtual void WillActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1288 switch (time_step_) {
1290 // The resource creation callback has been called.
1291 EXPECT_EQ(1, ui_resource_->resource_create_count);
1292 // The resource is not yet lost (sanity check).
1293 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1294 // The resource should not have been created yet on the impl-side.
1295 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1304 virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1305 LayerTreeHostContextTest::DidActivateTreeOnThread(impl);
1306 switch (time_step_) {
1308 // The pending requests on the impl-side should have been processed.
1309 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1312 // The "lost resource" callback should have been called once.
1313 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1316 // The resource is deleted and should not be in the manager. Use
1317 // test_id_ since ui_resource_ has been deleted.
1318 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id_));
1322 PostStepCompleteToMainThread();
1327 UIResourceId test_id_;
1330 TEST_F(UIResourceLostBeforeActivateTree,
1331 RunMultiThread_DirectRenderer_ImplSidePaint) {
1332 RunTest(true, false, true);
1335 TEST_F(UIResourceLostBeforeActivateTree,
1336 RunMultiThread_DelegatingRenderer_ImplSidePaint) {
1337 RunTest(true, true, true);
1340 // Resources evicted explicitly and by visibility changes.
1341 class UIResourceLostEviction : public UIResourceLostTestSimple {
1343 virtual void StepCompleteOnMainThread(int step) OVERRIDE {
1344 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1347 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1348 EXPECT_NE(0, ui_resource_->id());
1349 PostSetNeedsCommitToMainThread();
1352 // Make the tree not visible.
1353 PostSetVisibleToMainThread(false);
1356 // Release resource before ending the test.
1357 ui_resource_.reset();
1365 virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* impl,
1366 bool visible) OVERRIDE {
1367 TestWebGraphicsContext3D* context = TestContext();
1369 // All resources should have been evicted.
1370 ASSERT_EQ(0u, context->NumTextures());
1371 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1372 EXPECT_EQ(2, ui_resource_->resource_create_count);
1373 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1374 // Drawing is disabled both because of the evicted resources and
1375 // because the renderer is not visible.
1376 EXPECT_FALSE(impl->CanDraw());
1377 // Make the renderer visible again.
1378 PostSetVisibleToMainThread(true);
1382 virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) OVERRIDE {
1383 TestWebGraphicsContext3D* context = TestContext();
1384 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1385 switch (time_step_) {
1387 // The resource should have been created on LTHI after the commit.
1388 ASSERT_EQ(1u, context->NumTextures());
1389 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1390 EXPECT_EQ(1, ui_resource_->resource_create_count);
1391 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1392 EXPECT_TRUE(impl->CanDraw());
1393 // Evict all UI resources. This will trigger a commit.
1394 impl->EvictAllUIResources();
1395 ASSERT_EQ(0u, context->NumTextures());
1396 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1397 EXPECT_EQ(1, ui_resource_->resource_create_count);
1398 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1399 EXPECT_FALSE(impl->CanDraw());
1402 // The resource should have been recreated.
1403 ASSERT_EQ(1u, context->NumTextures());
1404 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1405 EXPECT_EQ(2, ui_resource_->resource_create_count);
1406 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1407 EXPECT_TRUE(impl->CanDraw());
1410 // The resource should have been recreated after visibility was
1412 ASSERT_EQ(1u, context->NumTextures());
1413 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1414 EXPECT_EQ(3, ui_resource_->resource_create_count);
1415 EXPECT_EQ(2, ui_resource_->lost_resource_count);
1416 EXPECT_TRUE(impl->CanDraw());
1422 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction);
1424 class LayerTreeHostContextTestSurfaceCreateCallback
1425 : public LayerTreeHostContextTest {
1427 LayerTreeHostContextTestSurfaceCreateCallback()
1428 : LayerTreeHostContextTest(),
1429 layer_(FakeContentLayer::Create(&client_)) {}
1431 virtual void SetupTree() OVERRIDE {
1432 layer_->SetBounds(gfx::Size(10, 20));
1433 layer_tree_host()->SetRootLayer(layer_);
1434 LayerTreeHostContextTest::SetupTree();
1437 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
1439 virtual void DidCommit() OVERRIDE {
1440 switch (layer_tree_host()->source_frame_number()) {
1442 EXPECT_EQ(1u, layer_->output_surface_created_count());
1443 layer_tree_host()->SetNeedsCommit();
1446 EXPECT_EQ(1u, layer_->output_surface_created_count());
1447 layer_tree_host()->SetNeedsCommit();
1450 EXPECT_EQ(1u, layer_->output_surface_created_count());
1453 EXPECT_EQ(2u, layer_->output_surface_created_count());
1454 layer_tree_host()->SetNeedsCommit();
1459 virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1460 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1461 switch (LastCommittedSourceFrameNumber(impl)) {
1475 virtual void AfterTest() OVERRIDE {}
1478 FakeContentLayerClient client_;
1479 scoped_refptr<FakeContentLayer> layer_;
1482 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestSurfaceCreateCallback);
1484 class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame
1485 : public LayerTreeHostContextTest {
1487 virtual void BeginTest() OVERRIDE {
1489 PostSetNeedsCommitToMainThread();
1492 virtual void ScheduledActionWillSendBeginMainFrame() OVERRIDE {
1497 // Defer commits before the BeginFrame arrives, causing it to be delayed.
1498 MainThreadTaskRunner()->PostTask(
1500 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1501 DeferCommitsOnMainThread,
1502 base::Unretained(this),
1504 // Meanwhile, lose the context while we are in defer commits.
1505 ImplThreadTaskRunner()->PostTask(
1507 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1508 LoseContextOnImplThread,
1509 base::Unretained(this)));
1512 void LoseContextOnImplThread() {
1515 // After losing the context, stop deferring commits.
1516 MainThreadTaskRunner()->PostTask(
1518 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
1519 DeferCommitsOnMainThread,
1520 base::Unretained(this),
1524 void DeferCommitsOnMainThread(bool defer_commits) {
1525 layer_tree_host()->SetDeferCommits(defer_commits);
1528 virtual void WillBeginMainFrame() OVERRIDE {
1529 // Don't begin a frame with a lost surface.
1530 EXPECT_FALSE(layer_tree_host()->output_surface_lost());
1533 virtual void DidCommitAndDrawFrame() OVERRIDE { EndTest(); }
1535 virtual void AfterTest() OVERRIDE {}
1540 // TODO(danakj): We don't use scheduler with SingleThreadProxy yet.
1541 MULTI_THREAD_TEST_F(LayerTreeHostContextTestLoseAfterSendingBeginMainFrame);