IndexedDB: fsync after transactions.
[chromium-blink-merge.git] / cc / trees / layer_tree_host_unittest_context.cc
blob57c780b7aca1b1cc6386b14b71949fbd02139c1f
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_web_graphics_context_3d.h"
37 #include "cc/trees/layer_tree_host_impl.h"
38 #include "cc/trees/layer_tree_impl.h"
39 #include "cc/trees/single_thread_proxy.h"
40 #include "gpu/GLES2/gl2extchromium.h"
41 #include "media/base/media.h"
43 using media::VideoFrame;
45 namespace cc {
46 namespace {
48 // These tests deal with losing the 3d graphics context.
49 class LayerTreeHostContextTest : public LayerTreeTest {
50 public:
51 LayerTreeHostContextTest()
52 : LayerTreeTest(),
53 context3d_(NULL),
54 times_to_fail_create_(0),
55 times_to_lose_during_commit_(0),
56 times_to_lose_during_draw_(0),
57 times_to_fail_recreate_(0),
58 times_to_fail_create_offscreen_(0),
59 times_to_fail_recreate_offscreen_(0),
60 times_to_expect_create_failed_(0),
61 times_create_failed_(0),
62 times_offscreen_created_(0),
63 committed_at_least_once_(false),
64 context_should_support_io_surface_(false),
65 fallback_context_works_(false) {
66 media::InitializeMediaLibraryForTesting();
69 void LoseContext() {
70 context3d_->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
71 GL_INNOCENT_CONTEXT_RESET_ARB);
72 context3d_ = NULL;
75 virtual scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() {
76 return TestWebGraphicsContext3D::Create();
79 virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurfaceForTest(
80 bool fallback) OVERRIDE {
81 if (times_to_fail_create_) {
82 --times_to_fail_create_;
83 ExpectCreateToFail();
84 return scoped_ptr<FakeOutputSurface>();
87 scoped_ptr<TestWebGraphicsContext3D> context3d = CreateContext3d();
88 context3d_ = context3d.get();
90 if (context_should_support_io_surface_) {
91 context3d_->set_have_extension_io_surface(true);
92 context3d_->set_have_extension_egl_image(true);
95 if (delegating_renderer())
96 return FakeOutputSurface::CreateDelegating3d(context3d.Pass());
97 else
98 return FakeOutputSurface::Create3d(context3d.Pass());
101 scoped_ptr<TestWebGraphicsContext3D> CreateOffscreenContext3d() {
102 if (!context3d_)
103 return scoped_ptr<TestWebGraphicsContext3D>();
105 ++times_offscreen_created_;
107 if (times_to_fail_create_offscreen_) {
108 --times_to_fail_create_offscreen_;
109 ExpectCreateToFail();
110 return scoped_ptr<TestWebGraphicsContext3D>();
113 scoped_ptr<TestWebGraphicsContext3D> offscreen_context3d =
114 TestWebGraphicsContext3D::Create().Pass();
115 DCHECK(offscreen_context3d);
116 context3d_->add_share_group_context(offscreen_context3d.get());
118 return offscreen_context3d.Pass();
121 virtual scoped_refptr<ContextProvider> OffscreenContextProvider() OVERRIDE {
122 if (!offscreen_contexts_.get() ||
123 offscreen_contexts_->DestroyedOnMainThread()) {
124 offscreen_contexts_ =
125 TestContextProvider::Create(CreateOffscreenContext3d());
127 return offscreen_contexts_;
130 virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
131 LayerTreeHostImpl::FrameData* frame,
132 bool result) OVERRIDE {
133 EXPECT_TRUE(result);
134 if (!times_to_lose_during_draw_)
135 return result;
137 --times_to_lose_during_draw_;
138 LoseContext();
140 times_to_fail_create_ = times_to_fail_recreate_;
141 times_to_fail_recreate_ = 0;
142 times_to_fail_create_offscreen_ = times_to_fail_recreate_offscreen_;
143 times_to_fail_recreate_offscreen_ = 0;
145 return result;
148 virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
149 committed_at_least_once_ = true;
151 if (!times_to_lose_during_commit_)
152 return;
153 --times_to_lose_during_commit_;
154 LoseContext();
156 times_to_fail_create_ = times_to_fail_recreate_;
157 times_to_fail_recreate_ = 0;
158 times_to_fail_create_offscreen_ = times_to_fail_recreate_offscreen_;
159 times_to_fail_recreate_offscreen_ = 0;
162 virtual void DidFailToInitializeOutputSurface() OVERRIDE {
163 ++times_create_failed_;
166 virtual void TearDown() OVERRIDE {
167 LayerTreeTest::TearDown();
168 EXPECT_EQ(times_to_expect_create_failed_, times_create_failed_);
171 void ExpectCreateToFail() { ++times_to_expect_create_failed_; }
173 protected:
174 TestWebGraphicsContext3D* context3d_;
175 int times_to_fail_create_;
176 int times_to_lose_during_commit_;
177 int times_to_lose_during_draw_;
178 int times_to_fail_recreate_;
179 int times_to_fail_create_offscreen_;
180 int times_to_fail_recreate_offscreen_;
181 int times_to_expect_create_failed_;
182 int times_create_failed_;
183 int times_offscreen_created_;
184 bool committed_at_least_once_;
185 bool context_should_support_io_surface_;
186 bool fallback_context_works_;
188 scoped_refptr<TestContextProvider> offscreen_contexts_;
191 class LayerTreeHostContextTestLostContextSucceeds
192 : public LayerTreeHostContextTest {
193 public:
194 LayerTreeHostContextTestLostContextSucceeds()
195 : LayerTreeHostContextTest(),
196 test_case_(0),
197 num_losses_(0),
198 num_losses_last_test_case_(-1),
199 recovered_context_(true),
200 first_initialized_(false) {}
202 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
204 virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
205 EXPECT_TRUE(succeeded);
207 if (first_initialized_)
208 ++num_losses_;
209 else
210 first_initialized_ = true;
212 recovered_context_ = true;
215 virtual void AfterTest() OVERRIDE { EXPECT_EQ(9u, test_case_); }
217 virtual void DidCommitAndDrawFrame() OVERRIDE {
218 // If the last frame had a context loss, then we'll commit again to
219 // recover.
220 if (!recovered_context_)
221 return;
222 if (times_to_lose_during_commit_)
223 return;
224 if (times_to_lose_during_draw_)
225 return;
227 recovered_context_ = false;
228 if (NextTestCase())
229 InvalidateAndSetNeedsCommit();
230 else
231 EndTest();
234 virtual void InvalidateAndSetNeedsCommit() {
235 // Cause damage so we try to draw.
236 layer_tree_host()->root_layer()->SetNeedsDisplay();
237 layer_tree_host()->SetNeedsCommit();
240 bool NextTestCase() {
241 static const TestCase kTests[] = {
242 // Losing the context and failing to recreate it (or losing it again
243 // immediately) a small number of times should succeed.
244 {1, // times_to_lose_during_commit
245 0, // times_to_lose_during_draw
246 0, // times_to_fail_recreate
247 0, // times_to_fail_recreate_offscreen
248 false, // fallback_context_works
250 {0, // times_to_lose_during_commit
251 1, // times_to_lose_during_draw
252 0, // times_to_fail_recreate
253 0, // times_to_fail_recreate_offscreen
254 false, // fallback_context_works
256 {1, // times_to_lose_during_commit
257 0, // times_to_lose_during_draw
258 3, // times_to_fail_recreate
259 0, // times_to_fail_recreate_offscreen
260 false, // fallback_context_works
262 {0, // times_to_lose_during_commit
263 1, // times_to_lose_during_draw
264 3, // times_to_fail_recreate
265 0, // times_to_fail_recreate_offscreen
266 false, // fallback_context_works
268 {1, // times_to_lose_during_commit
269 0, // times_to_lose_during_draw
270 0, // times_to_fail_recreate
271 3, // times_to_fail_recreate_offscreen
272 false, // fallback_context_works
274 {0, // times_to_lose_during_commit
275 1, // times_to_lose_during_draw
276 0, // times_to_fail_recreate
277 3, // times_to_fail_recreate_offscreen
278 false, // fallback_context_works
280 // Losing the context and recreating it any number of times should
281 // succeed.
282 {10, // times_to_lose_during_commit
283 0, // times_to_lose_during_draw
284 0, // times_to_fail_recreate
285 0, // times_to_fail_recreate_offscreen
286 false, // fallback_context_works
288 {0, // times_to_lose_during_commit
289 10, // times_to_lose_during_draw
290 0, // times_to_fail_recreate
291 0, // times_to_fail_recreate_offscreen
292 false, // fallback_context_works
294 // Losing the context, failing to reinitialize it, and making a fallback
295 // context should work.
296 {0, // times_to_lose_during_commit
297 1, // times_to_lose_during_draw
298 0, // times_to_fail_recreate
299 0, // times_to_fail_recreate_offscreen
300 true, // fallback_context_works
301 }, };
303 if (test_case_ >= arraysize(kTests))
304 return false;
305 // Make sure that we lost our context at least once in the last test run so
306 // the test did something.
307 EXPECT_GT(num_losses_, num_losses_last_test_case_);
308 num_losses_last_test_case_ = num_losses_;
310 times_to_lose_during_commit_ =
311 kTests[test_case_].times_to_lose_during_commit;
312 times_to_lose_during_draw_ = kTests[test_case_].times_to_lose_during_draw;
313 times_to_fail_recreate_ = kTests[test_case_].times_to_fail_recreate;
314 times_to_fail_recreate_offscreen_ =
315 kTests[test_case_].times_to_fail_recreate_offscreen;
316 fallback_context_works_ = kTests[test_case_].fallback_context_works;
317 ++test_case_;
318 return true;
321 struct TestCase {
322 int times_to_lose_during_commit;
323 int times_to_lose_during_draw;
324 int times_to_fail_recreate;
325 int times_to_fail_recreate_offscreen;
326 bool fallback_context_works;
329 protected:
330 size_t test_case_;
331 int num_losses_;
332 int num_losses_last_test_case_;
333 bool recovered_context_;
334 bool first_initialized_;
337 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLostContextSucceeds);
339 class LayerTreeHostClientNotReadyDoesNotCreateOutputSurface
340 : public LayerTreeHostContextTest {
341 public:
342 LayerTreeHostClientNotReadyDoesNotCreateOutputSurface()
343 : LayerTreeHostContextTest() {}
345 virtual void WillBeginTest() OVERRIDE {
346 // Override and do not signal SetLayerTreeHostClientReady.
349 virtual void BeginTest() OVERRIDE {
350 PostSetNeedsCommitToMainThread();
351 EndTest();
354 virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
355 OVERRIDE {
356 EXPECT_TRUE(false);
357 return scoped_ptr<OutputSurface>();
360 virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
361 EXPECT_TRUE(false);
364 virtual void AfterTest() OVERRIDE {
368 MULTI_THREAD_TEST_F(LayerTreeHostClientNotReadyDoesNotCreateOutputSurface);
370 class LayerTreeHostContextTestLostContextSucceedsWithContent
371 : public LayerTreeHostContextTestLostContextSucceeds {
372 public:
373 LayerTreeHostContextTestLostContextSucceedsWithContent()
374 : LayerTreeHostContextTestLostContextSucceeds() {}
376 virtual void SetupTree() OVERRIDE {
377 root_ = Layer::Create();
378 root_->SetBounds(gfx::Size(10, 10));
379 root_->SetAnchorPoint(gfx::PointF());
380 root_->SetIsDrawable(true);
382 content_ = FakeContentLayer::Create(&client_);
383 content_->SetBounds(gfx::Size(10, 10));
384 content_->SetAnchorPoint(gfx::PointF());
385 content_->SetIsDrawable(true);
386 if (use_surface_) {
387 content_->SetForceRenderSurface(true);
388 // Filters require us to create an offscreen context.
389 FilterOperations filters;
390 filters.Append(FilterOperation::CreateGrayscaleFilter(0.5f));
391 content_->SetFilters(filters);
392 content_->SetBackgroundFilters(filters);
395 root_->AddChild(content_);
397 layer_tree_host()->SetRootLayer(root_);
398 LayerTreeHostContextTest::SetupTree();
401 virtual void InvalidateAndSetNeedsCommit() OVERRIDE {
402 // Invalidate the render surface so we don't try to use a cached copy of the
403 // surface. We want to make sure to test the drawing paths for drawing to
404 // a child surface.
405 content_->SetNeedsDisplay();
406 LayerTreeHostContextTestLostContextSucceeds::InvalidateAndSetNeedsCommit();
409 virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
410 FakeContentLayerImpl* content_impl = static_cast<FakeContentLayerImpl*>(
411 host_impl->active_tree()->root_layer()->children()[0]);
412 // Even though the context was lost, we should have a resource. The
413 // TestWebGraphicsContext3D ensures that this resource is created with
414 // the active context.
415 EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0));
417 ContextProvider* contexts = host_impl->offscreen_context_provider();
418 if (use_surface_) {
419 ASSERT_TRUE(contexts);
420 EXPECT_TRUE(contexts->ContextGL());
421 // TODO(danakj): Make a fake GrContext.
422 // EXPECT_TRUE(contexts->GrContext());
423 } else {
424 EXPECT_FALSE(contexts);
428 virtual void AfterTest() OVERRIDE {
429 LayerTreeHostContextTestLostContextSucceeds::AfterTest();
430 if (use_surface_) {
431 // 1 create to start with +
432 // 4 from test cases that lose the offscreen context directly +
433 // 2 from test cases that create a fallback +
434 // All the test cases that recreate both contexts only once
435 // per time it is lost.
436 EXPECT_EQ(4 + 1 + 2 + num_losses_, times_offscreen_created_);
437 } else {
438 EXPECT_EQ(0, times_offscreen_created_);
442 protected:
443 bool use_surface_;
444 FakeContentLayerClient client_;
445 scoped_refptr<Layer> root_;
446 scoped_refptr<ContentLayer> content_;
449 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
450 NoSurface_SingleThread_DirectRenderer) {
451 use_surface_ = false;
452 RunTest(false, false, false);
455 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
456 NoSurface_SingleThread_DelegatingRenderer) {
457 use_surface_ = false;
458 RunTest(false, true, false);
461 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
462 NoSurface_MultiThread_DirectRenderer_MainThreadPaint) {
463 use_surface_ = false;
464 RunTest(true, false, false);
467 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
468 NoSurface_MultiThread_DelegatingRenderer_MainThreadPaint) {
469 use_surface_ = false;
470 RunTest(true, true, false);
473 // Surfaces don't exist with a delegating renderer.
474 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
475 WithSurface_SingleThread_DirectRenderer) {
476 use_surface_ = true;
477 RunTest(false, false, false);
480 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
481 WithSurface_MultiThread_DirectRenderer_MainThreadPaint) {
482 use_surface_ = true;
483 RunTest(true, false, false);
486 class LayerTreeHostContextTestCreateOutputSurfaceFails
487 : public LayerTreeHostContextTest {
488 public:
489 // Run a test that initially fails OutputSurface creation |times_to_fail|
490 // times. If |expect_fallback_attempt| is |true|, an attempt to create a
491 // fallback/software OutputSurface is expected to occur.
492 LayerTreeHostContextTestCreateOutputSurfaceFails(int times_to_fail,
493 bool expect_fallback_attempt,
494 bool expect_to_give_up)
495 : times_to_fail_(times_to_fail),
496 expect_fallback_attempt_(expect_fallback_attempt),
497 expect_to_give_up_(expect_to_give_up),
498 did_attempt_fallback_(false),
499 times_initialized_(0) {}
501 virtual void BeginTest() OVERRIDE {
502 times_to_fail_create_ = times_to_fail_;
503 PostSetNeedsCommitToMainThread();
506 virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
507 OVERRIDE {
508 scoped_ptr<OutputSurface> surface =
509 LayerTreeHostContextTest::CreateOutputSurface(fallback);
511 if (surface)
512 EXPECT_EQ(times_to_fail_, times_create_failed_);
514 did_attempt_fallback_ = fallback;
515 return surface.Pass();
518 virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
519 if (succeeded)
520 times_initialized_++;
521 else
522 EndTest();
525 virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
526 EndTest();
529 virtual void AfterTest() OVERRIDE {
530 EXPECT_EQ(times_to_fail_, times_create_failed_);
531 EXPECT_EQ(expect_to_give_up_, times_initialized_ == 0);
532 EXPECT_EQ(expect_fallback_attempt_, did_attempt_fallback_);
535 private:
536 int times_to_fail_;
537 bool expect_fallback_attempt_;
538 bool expect_to_give_up_;
539 bool did_attempt_fallback_;
540 int times_initialized_;
543 class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
544 : public LayerTreeHostContextTestCreateOutputSurfaceFails {
545 public:
546 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
547 : LayerTreeHostContextTestCreateOutputSurfaceFails(1, false, false) {}
550 SINGLE_AND_MULTI_THREAD_TEST_F(
551 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce);
553 // After 4 failures we expect an attempt to create a fallback/software
554 // OutputSurface.
555 class LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback
556 : public LayerTreeHostContextTestCreateOutputSurfaceFails {
557 public:
558 LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback()
559 : LayerTreeHostContextTestCreateOutputSurfaceFails(4, true, false) {}
562 SINGLE_AND_MULTI_THREAD_TEST_F(
563 LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback);
565 // If we fail that often, we should be giving up cleanly.
566 class LayerTreeHostContextTestCreateOutputSurfaceIsHopeless
567 : public LayerTreeHostContextTestCreateOutputSurfaceFails {
568 public:
569 LayerTreeHostContextTestCreateOutputSurfaceIsHopeless()
570 : LayerTreeHostContextTestCreateOutputSurfaceFails(5, true, true) {}
573 SINGLE_AND_MULTI_THREAD_TEST_F(
574 LayerTreeHostContextTestCreateOutputSurfaceIsHopeless);
577 class LayerTreeHostContextTestOffscreenContextFails
578 : public LayerTreeHostContextTest {
579 public:
580 virtual void SetupTree() OVERRIDE {
581 root_ = Layer::Create();
582 root_->SetBounds(gfx::Size(10, 10));
583 root_->SetAnchorPoint(gfx::PointF());
584 root_->SetIsDrawable(true);
586 content_ = FakeContentLayer::Create(&client_);
587 content_->SetBounds(gfx::Size(10, 10));
588 content_->SetAnchorPoint(gfx::PointF());
589 content_->SetIsDrawable(true);
590 content_->SetForceRenderSurface(true);
591 // Filters require us to create an offscreen context.
592 FilterOperations filters;
593 filters.Append(FilterOperation::CreateGrayscaleFilter(0.5f));
594 content_->SetFilters(filters);
595 content_->SetBackgroundFilters(filters);
597 root_->AddChild(content_);
599 layer_tree_host()->SetRootLayer(root_);
600 LayerTreeHostContextTest::SetupTree();
603 virtual void BeginTest() OVERRIDE {
604 times_to_fail_create_offscreen_ = 1;
605 PostSetNeedsCommitToMainThread();
608 virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
609 ContextProvider* contexts = host_impl->offscreen_context_provider();
610 EXPECT_FALSE(contexts);
612 // This did not lead to create failure.
613 times_to_expect_create_failed_ = 0;
614 EndTest();
617 virtual void AfterTest() OVERRIDE {}
619 protected:
620 FakeContentLayerClient client_;
621 scoped_refptr<Layer> root_;
622 scoped_refptr<ContentLayer> content_;
625 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestOffscreenContextFails);
627 class LayerTreeHostContextTestLostContextFails
628 : public LayerTreeHostContextTest {
629 public:
630 LayerTreeHostContextTestLostContextFails()
631 : LayerTreeHostContextTest(), num_commits_(0), first_initialized_(false) {
632 times_to_lose_during_commit_ = 1;
635 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
637 virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
638 if (first_initialized_) {
639 EXPECT_FALSE(succeeded);
640 EndTest();
641 } else {
642 first_initialized_ = true;
646 virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
647 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
649 ++num_commits_;
650 if (num_commits_ == 1) {
651 // When the context is ok, we should have these things.
652 EXPECT_TRUE(host_impl->output_surface());
653 EXPECT_TRUE(host_impl->renderer());
654 EXPECT_TRUE(host_impl->resource_provider());
655 return;
658 // When context recreation fails we shouldn't be left with any of them.
659 EXPECT_FALSE(host_impl->output_surface());
660 EXPECT_FALSE(host_impl->renderer());
661 EXPECT_FALSE(host_impl->resource_provider());
664 virtual void AfterTest() OVERRIDE {}
666 private:
667 int num_commits_;
668 bool first_initialized_;
671 class LayerTreeHostContextTestLostContextAndEvictTextures
672 : public LayerTreeHostContextTest {
673 public:
674 LayerTreeHostContextTestLostContextAndEvictTextures()
675 : LayerTreeHostContextTest(),
676 layer_(FakeContentLayer::Create(&client_)),
677 impl_host_(0),
678 num_commits_(0) {}
680 virtual void SetupTree() OVERRIDE {
681 layer_->SetBounds(gfx::Size(10, 20));
682 layer_tree_host()->SetRootLayer(layer_);
683 LayerTreeHostContextTest::SetupTree();
686 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
688 void PostEvictTextures() {
689 if (HasImplThread()) {
690 ImplThreadTaskRunner()->PostTask(
691 FROM_HERE,
692 base::Bind(&LayerTreeHostContextTestLostContextAndEvictTextures::
693 EvictTexturesOnImplThread,
694 base::Unretained(this)));
695 } else {
696 DebugScopedSetImplThread impl(proxy());
697 EvictTexturesOnImplThread();
701 void EvictTexturesOnImplThread() {
702 impl_host_->EvictTexturesForTesting();
703 if (lose_after_evict_)
704 LoseContext();
707 virtual void DidCommitAndDrawFrame() OVERRIDE {
708 if (num_commits_ > 1)
709 return;
710 EXPECT_TRUE(layer_->HaveBackingAt(0, 0));
711 PostEvictTextures();
714 virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
715 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
716 if (num_commits_ > 1)
717 return;
718 ++num_commits_;
719 if (!lose_after_evict_)
720 LoseContext();
721 impl_host_ = impl;
724 virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
725 EXPECT_TRUE(succeeded);
726 EndTest();
729 virtual void AfterTest() OVERRIDE {}
731 protected:
732 bool lose_after_evict_;
733 FakeContentLayerClient client_;
734 scoped_refptr<FakeContentLayer> layer_;
735 LayerTreeHostImpl* impl_host_;
736 int num_commits_;
739 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
740 LoseAfterEvict_SingleThread_DirectRenderer) {
741 lose_after_evict_ = true;
742 RunTest(false, false, false);
745 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
746 LoseAfterEvict_SingleThread_DelegatingRenderer) {
747 lose_after_evict_ = true;
748 RunTest(false, true, false);
751 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
752 LoseAfterEvict_MultiThread_DirectRenderer_MainThreadPaint) {
753 lose_after_evict_ = true;
754 RunTest(true, false, false);
757 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
758 LoseAfterEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
759 lose_after_evict_ = true;
760 RunTest(true, true, false);
763 // Flaky on all platforms, http://crbug.com/310979
764 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
765 DISABLED_LoseAfterEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
766 lose_after_evict_ = true;
767 RunTest(true, true, true);
770 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
771 LoseBeforeEvict_SingleThread_DirectRenderer) {
772 lose_after_evict_ = false;
773 RunTest(false, false, false);
776 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
777 LoseBeforeEvict_SingleThread_DelegatingRenderer) {
778 lose_after_evict_ = false;
779 RunTest(false, true, false);
782 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
783 LoseBeforeEvict_MultiThread_DirectRenderer_MainThreadPaint) {
784 lose_after_evict_ = false;
785 RunTest(true, false, false);
788 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
789 LoseBeforeEvict_MultiThread_DirectRenderer_ImplSidePaint) {
790 lose_after_evict_ = false;
791 RunTest(true, false, true);
794 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
795 LoseBeforeEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
796 lose_after_evict_ = false;
797 RunTest(true, true, false);
800 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
801 LoseBeforeEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
802 lose_after_evict_ = false;
803 RunTest(true, true, true);
806 class LayerTreeHostContextTestLostContextWhileUpdatingResources
807 : public LayerTreeHostContextTest {
808 public:
809 LayerTreeHostContextTestLostContextWhileUpdatingResources()
810 : parent_(FakeContentLayer::Create(&client_)),
811 num_children_(50),
812 times_to_lose_on_end_query_(3) {}
814 virtual scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() OVERRIDE {
815 scoped_ptr<TestWebGraphicsContext3D> context =
816 LayerTreeHostContextTest::CreateContext3d();
817 if (times_to_lose_on_end_query_) {
818 --times_to_lose_on_end_query_;
819 context->set_times_end_query_succeeds(5);
821 return context.Pass();
824 virtual void SetupTree() OVERRIDE {
825 parent_->SetBounds(gfx::Size(num_children_, 1));
827 for (int i = 0; i < num_children_; i++) {
828 scoped_refptr<FakeContentLayer> child =
829 FakeContentLayer::Create(&client_);
830 child->SetPosition(gfx::PointF(i, 0.f));
831 child->SetBounds(gfx::Size(1, 1));
832 parent_->AddChild(child);
835 layer_tree_host()->SetRootLayer(parent_);
836 LayerTreeHostContextTest::SetupTree();
839 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
841 virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
842 EXPECT_EQ(0, times_to_lose_on_end_query_);
843 EndTest();
846 virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
847 EXPECT_TRUE(succeeded);
850 virtual void AfterTest() OVERRIDE {
851 EXPECT_EQ(0, times_to_lose_on_end_query_);
854 private:
855 FakeContentLayerClient client_;
856 scoped_refptr<FakeContentLayer> parent_;
857 int num_children_;
858 int times_to_lose_on_end_query_;
861 SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
862 LayerTreeHostContextTestLostContextWhileUpdatingResources);
864 class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
865 public:
866 LayerTreeHostContextTestLayersNotified()
867 : LayerTreeHostContextTest(), num_commits_(0) {}
869 virtual void SetupTree() OVERRIDE {
870 root_ = FakeContentLayer::Create(&client_);
871 child_ = FakeContentLayer::Create(&client_);
872 grandchild_ = FakeContentLayer::Create(&client_);
874 root_->AddChild(child_);
875 child_->AddChild(grandchild_);
877 layer_tree_host()->SetRootLayer(root_);
878 LayerTreeHostContextTest::SetupTree();
881 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
883 virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
884 LayerTreeHostContextTest::DidActivateTreeOnThread(host_impl);
886 FakeContentLayerImpl* root = static_cast<FakeContentLayerImpl*>(
887 host_impl->active_tree()->root_layer());
888 FakeContentLayerImpl* child =
889 static_cast<FakeContentLayerImpl*>(root->children()[0]);
890 FakeContentLayerImpl* grandchild =
891 static_cast<FakeContentLayerImpl*>(child->children()[0]);
893 ++num_commits_;
894 switch (num_commits_) {
895 case 1:
896 EXPECT_EQ(0u, root->lost_output_surface_count());
897 EXPECT_EQ(0u, child->lost_output_surface_count());
898 EXPECT_EQ(0u, grandchild->lost_output_surface_count());
899 // Lose the context and struggle to recreate it.
900 LoseContext();
901 times_to_fail_create_ = 1;
902 break;
903 case 2:
904 EXPECT_GE(1u, root->lost_output_surface_count());
905 EXPECT_GE(1u, child->lost_output_surface_count());
906 EXPECT_GE(1u, grandchild->lost_output_surface_count());
907 EndTest();
908 break;
909 default:
910 NOTREACHED();
914 virtual void AfterTest() OVERRIDE {}
916 private:
917 int num_commits_;
919 FakeContentLayerClient client_;
920 scoped_refptr<FakeContentLayer> root_;
921 scoped_refptr<FakeContentLayer> child_;
922 scoped_refptr<FakeContentLayer> grandchild_;
925 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified);
927 class LayerTreeHostContextTestDontUseLostResources
928 : public LayerTreeHostContextTest {
929 public:
930 LayerTreeHostContextTestDontUseLostResources() : lost_context_(false) {
931 context_should_support_io_surface_ = true;
933 child_output_surface_ = FakeOutputSurface::Create3d();
934 child_output_surface_->BindToClient(&output_surface_client_);
935 child_resource_provider_ = ResourceProvider::Create(
936 child_output_surface_.get(), NULL, 0, false, 1);
939 static void EmptyReleaseCallback(unsigned sync_point, bool lost) {}
941 virtual void SetupTree() OVERRIDE {
942 gpu::gles2::GLES2Interface* gl =
943 child_output_surface_->context_provider()->ContextGL();
945 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
947 scoped_ptr<TestRenderPass> pass_for_quad = TestRenderPass::Create();
948 pass_for_quad->SetNew(
949 // AppendOneOfEveryQuadType() makes a RenderPass quad with this id.
950 RenderPass::Id(2, 1),
951 gfx::Rect(0, 0, 10, 10),
952 gfx::Rect(0, 0, 10, 10),
953 gfx::Transform());
955 scoped_ptr<TestRenderPass> pass = TestRenderPass::Create();
956 pass->SetNew(RenderPass::Id(1, 1),
957 gfx::Rect(0, 0, 10, 10),
958 gfx::Rect(0, 0, 10, 10),
959 gfx::Transform());
960 pass->AppendOneOfEveryQuadType(child_resource_provider_.get(),
961 RenderPass::Id(2, 1));
963 frame_data->render_pass_list.push_back(pass_for_quad.PassAs<RenderPass>());
964 frame_data->render_pass_list.push_back(pass.PassAs<RenderPass>());
966 delegated_resource_collection_ = new DelegatedFrameResourceCollection;
967 delegated_frame_provider_ = new DelegatedFrameProvider(
968 delegated_resource_collection_.get(), frame_data.Pass());
970 ResourceProvider::ResourceId resource =
971 child_resource_provider_->CreateResource(
972 gfx::Size(4, 4),
973 GL_CLAMP_TO_EDGE,
974 ResourceProvider::TextureUsageAny,
975 RGBA_8888);
976 ResourceProvider::ScopedWriteLockGL lock(child_resource_provider_.get(),
977 resource);
979 gpu::Mailbox mailbox;
980 gl->GenMailboxCHROMIUM(mailbox.name);
981 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
983 scoped_refptr<Layer> root = Layer::Create();
984 root->SetBounds(gfx::Size(10, 10));
985 root->SetAnchorPoint(gfx::PointF());
986 root->SetIsDrawable(true);
988 scoped_refptr<FakeDelegatedRendererLayer> delegated =
989 FakeDelegatedRendererLayer::Create(delegated_frame_provider_.get());
990 delegated->SetBounds(gfx::Size(10, 10));
991 delegated->SetAnchorPoint(gfx::PointF());
992 delegated->SetIsDrawable(true);
993 root->AddChild(delegated);
995 scoped_refptr<ContentLayer> content = ContentLayer::Create(&client_);
996 content->SetBounds(gfx::Size(10, 10));
997 content->SetAnchorPoint(gfx::PointF());
998 content->SetIsDrawable(true);
999 root->AddChild(content);
1001 scoped_refptr<TextureLayer> texture = TextureLayer::CreateForMailbox(NULL);
1002 texture->SetBounds(gfx::Size(10, 10));
1003 texture->SetAnchorPoint(gfx::PointF());
1004 texture->SetIsDrawable(true);
1005 texture->SetTextureMailbox(
1006 TextureMailbox(mailbox, sync_point),
1007 SingleReleaseCallback::Create(
1008 base::Bind(&LayerTreeHostContextTestDontUseLostResources::
1009 EmptyReleaseCallback)));
1010 root->AddChild(texture);
1012 scoped_refptr<ContentLayer> mask = ContentLayer::Create(&client_);
1013 mask->SetBounds(gfx::Size(10, 10));
1014 mask->SetAnchorPoint(gfx::PointF());
1016 scoped_refptr<ContentLayer> content_with_mask =
1017 ContentLayer::Create(&client_);
1018 content_with_mask->SetBounds(gfx::Size(10, 10));
1019 content_with_mask->SetAnchorPoint(gfx::PointF());
1020 content_with_mask->SetIsDrawable(true);
1021 content_with_mask->SetMaskLayer(mask.get());
1022 root->AddChild(content_with_mask);
1024 scoped_refptr<VideoLayer> video_color =
1025 VideoLayer::Create(&color_frame_provider_);
1026 video_color->SetBounds(gfx::Size(10, 10));
1027 video_color->SetAnchorPoint(gfx::PointF());
1028 video_color->SetIsDrawable(true);
1029 root->AddChild(video_color);
1031 scoped_refptr<VideoLayer> video_hw =
1032 VideoLayer::Create(&hw_frame_provider_);
1033 video_hw->SetBounds(gfx::Size(10, 10));
1034 video_hw->SetAnchorPoint(gfx::PointF());
1035 video_hw->SetIsDrawable(true);
1036 root->AddChild(video_hw);
1038 scoped_refptr<VideoLayer> video_scaled_hw =
1039 VideoLayer::Create(&scaled_hw_frame_provider_);
1040 video_scaled_hw->SetBounds(gfx::Size(10, 10));
1041 video_scaled_hw->SetAnchorPoint(gfx::PointF());
1042 video_scaled_hw->SetIsDrawable(true);
1043 root->AddChild(video_scaled_hw);
1045 color_video_frame_ = VideoFrame::CreateColorFrame(
1046 gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
1047 hw_video_frame_ = VideoFrame::WrapNativeTexture(
1048 make_scoped_ptr(new VideoFrame::MailboxHolder(
1049 mailbox,
1050 sync_point,
1051 VideoFrame::MailboxHolder::TextureNoLongerNeededCallback())),
1052 GL_TEXTURE_2D,
1053 gfx::Size(4, 4),
1054 gfx::Rect(0, 0, 4, 4),
1055 gfx::Size(4, 4),
1056 base::TimeDelta(),
1057 VideoFrame::ReadPixelsCB(),
1058 base::Closure());
1059 scaled_hw_video_frame_ = VideoFrame::WrapNativeTexture(
1060 make_scoped_ptr(new VideoFrame::MailboxHolder(
1061 mailbox,
1062 sync_point,
1063 VideoFrame::MailboxHolder::TextureNoLongerNeededCallback())),
1064 GL_TEXTURE_2D,
1065 gfx::Size(4, 4),
1066 gfx::Rect(0, 0, 3, 2),
1067 gfx::Size(4, 4),
1068 base::TimeDelta(),
1069 VideoFrame::ReadPixelsCB(),
1070 base::Closure());
1072 color_frame_provider_.set_frame(color_video_frame_);
1073 hw_frame_provider_.set_frame(hw_video_frame_);
1074 scaled_hw_frame_provider_.set_frame(scaled_hw_video_frame_);
1076 if (!delegating_renderer()) {
1077 // TODO(danakj): IOSurface layer can not be transported. crbug.com/239335
1078 scoped_refptr<IOSurfaceLayer> io_surface = IOSurfaceLayer::Create();
1079 io_surface->SetBounds(gfx::Size(10, 10));
1080 io_surface->SetAnchorPoint(gfx::PointF());
1081 io_surface->SetIsDrawable(true);
1082 io_surface->SetIOSurfaceProperties(1, gfx::Size(10, 10));
1083 root->AddChild(io_surface);
1086 // Enable the hud.
1087 LayerTreeDebugState debug_state;
1088 debug_state.show_property_changed_rects = true;
1089 layer_tree_host()->SetDebugState(debug_state);
1091 scoped_refptr<PaintedScrollbarLayer> scrollbar =
1092 PaintedScrollbarLayer::Create(
1093 scoped_ptr<Scrollbar>(new FakeScrollbar).Pass(), content->id());
1094 scrollbar->SetBounds(gfx::Size(10, 10));
1095 scrollbar->SetAnchorPoint(gfx::PointF());
1096 scrollbar->SetIsDrawable(true);
1097 root->AddChild(scrollbar);
1099 layer_tree_host()->SetRootLayer(root);
1100 LayerTreeHostContextTest::SetupTree();
1103 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
1105 virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
1106 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
1108 if (host_impl->active_tree()->source_frame_number() == 3) {
1109 // On the third commit we're recovering from context loss. Hardware
1110 // video frames should not be reused by the VideoFrameProvider, but
1111 // software frames can be.
1112 hw_frame_provider_.set_frame(NULL);
1113 scaled_hw_frame_provider_.set_frame(NULL);
1117 virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
1118 LayerTreeHostImpl::FrameData* frame,
1119 bool result) OVERRIDE {
1120 if (host_impl->active_tree()->source_frame_number() == 2) {
1121 // Lose the context during draw on the second commit. This will cause
1122 // a third commit to recover.
1123 context3d_->set_times_bind_texture_succeeds(0);
1125 return true;
1128 virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
1129 OVERRIDE {
1130 // This will get called twice:
1131 // First when we create the initial output surface...
1132 if (layer_tree_host()->source_frame_number() > 0) {
1133 // ... and then again after we forced the context to be lost on the third
1134 // frame. Verify this assumption here.
1135 lost_context_ = true;
1136 EXPECT_EQ(layer_tree_host()->source_frame_number(), 3);
1138 return LayerTreeHostContextTest::CreateOutputSurface(fallback);
1141 virtual void DidCommitAndDrawFrame() OVERRIDE {
1142 ASSERT_TRUE(layer_tree_host()->hud_layer());
1143 // End the test once we know the 3nd frame drew.
1144 if (layer_tree_host()->source_frame_number() < 4) {
1145 layer_tree_host()->root_layer()->SetNeedsDisplay();
1146 layer_tree_host()->SetNeedsCommit();
1147 } else {
1148 EndTest();
1152 virtual void AfterTest() OVERRIDE { EXPECT_TRUE(lost_context_); }
1154 private:
1155 FakeContentLayerClient client_;
1156 bool lost_context_;
1158 FakeOutputSurfaceClient output_surface_client_;
1159 scoped_ptr<FakeOutputSurface> child_output_surface_;
1160 scoped_ptr<ResourceProvider> child_resource_provider_;
1162 scoped_refptr<DelegatedFrameResourceCollection>
1163 delegated_resource_collection_;
1164 scoped_refptr<DelegatedFrameProvider> delegated_frame_provider_;
1166 scoped_refptr<VideoFrame> color_video_frame_;
1167 scoped_refptr<VideoFrame> hw_video_frame_;
1168 scoped_refptr<VideoFrame> scaled_hw_video_frame_;
1170 FakeVideoFrameProvider color_frame_provider_;
1171 FakeVideoFrameProvider hw_frame_provider_;
1172 FakeVideoFrameProvider scaled_hw_frame_provider_;
1175 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources);
1177 class LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit
1178 : public LayerTreeHostContextTest {
1179 public:
1180 virtual void BeginTest() OVERRIDE {
1181 // This must be called immediately after creating LTH, before the first
1182 // OutputSurface is initialized.
1183 ASSERT_TRUE(layer_tree_host()->output_surface_lost());
1185 times_output_surface_created_ = 0;
1187 // Post the SetNeedsCommit before the readback to make sure it is run
1188 // on the main thread before the readback's replacement commit when
1189 // we have a threaded compositor.
1190 PostSetNeedsCommitToMainThread();
1192 char pixels[4];
1193 bool result =
1194 layer_tree_host()->CompositeAndReadback(&pixels, gfx::Rect(1, 1));
1195 EXPECT_EQ(!delegating_renderer(), result);
1196 EXPECT_EQ(1, times_output_surface_created_);
1199 virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
1200 EXPECT_TRUE(succeeded);
1201 ++times_output_surface_created_;
1204 virtual void DidCommitAndDrawFrame() OVERRIDE { EndTest(); }
1206 virtual void AfterTest() OVERRIDE {
1207 // Should not try to create output surface again after successfully
1208 // created by CompositeAndReadback.
1209 EXPECT_EQ(1, times_output_surface_created_);
1212 virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
1213 LayerTreeHostImpl::FrameData* frame_data,
1214 bool result) OVERRIDE {
1215 EXPECT_GE(host_impl->active_tree()->source_frame_number(), 0);
1216 EXPECT_LE(host_impl->active_tree()->source_frame_number(), 1);
1217 return true;
1220 virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
1221 // We should only draw for the readback and the replacement commit.
1222 // The replacement commit will also be the first commit after output
1223 // surface initialization.
1224 EXPECT_GE(host_impl->active_tree()->source_frame_number(), 0);
1225 EXPECT_LE(host_impl->active_tree()->source_frame_number(), 1);
1228 virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
1229 bool result) OVERRIDE {
1230 // We should only swap for the replacement commit.
1231 EXPECT_EQ(host_impl->active_tree()->source_frame_number(), 1);
1232 EndTest();
1235 private:
1236 int times_output_surface_created_;
1239 SINGLE_AND_MULTI_THREAD_TEST_F(
1240 LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit);
1242 // This test verifies that losing an output surface during a
1243 // simultaneous readback and forced redraw works and does not deadlock.
1244 class LayerTreeHostContextTestLoseOutputSurfaceDuringReadbackAndForcedDraw
1245 : public LayerTreeHostContextTest {
1246 protected:
1247 static const int kFirstOutputSurfaceInitSourceFrameNumber = 0;
1248 static const int kReadbackSourceFrameNumber = 1;
1249 static const int kReadbackReplacementSourceFrameNumber = 2;
1250 static const int kSecondOutputSurfaceInitSourceFrameNumber = 3;
1252 LayerTreeHostContextTestLoseOutputSurfaceDuringReadbackAndForcedDraw()
1253 : did_react_to_first_commit_(false) {}
1255 virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
1256 // This enables forced draws after a single prepare to draw failure.
1257 settings->timeout_and_draw_when_animation_checkerboards = true;
1258 settings->maximum_number_of_failed_draws_before_draw_is_forced_ = 1;
1261 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
1263 virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
1264 LayerTreeHostImpl::FrameData* frame_data,
1265 bool result) OVERRIDE {
1266 int sfn = host_impl->active_tree()->source_frame_number();
1267 EXPECT_TRUE(sfn == kFirstOutputSurfaceInitSourceFrameNumber ||
1268 sfn == kSecondOutputSurfaceInitSourceFrameNumber ||
1269 sfn == kReadbackSourceFrameNumber)
1270 << sfn;
1272 // Before we react to the failed draw by initiating the forced draw
1273 // sequence, start a readback on the main thread and then lose the context
1274 // to start output surface initialization all at the same time.
1275 if (sfn == kFirstOutputSurfaceInitSourceFrameNumber &&
1276 !did_react_to_first_commit_) {
1277 did_react_to_first_commit_ = true;
1278 PostReadbackToMainThread();
1279 LoseContext();
1282 return false;
1285 virtual void InitializedRendererOnThread(LayerTreeHostImpl* host_impl,
1286 bool success) OVERRIDE {
1287 // -1 is for the first output surface initialization.
1288 int sfn = host_impl->active_tree()->source_frame_number();
1289 EXPECT_TRUE(sfn == -1 || sfn == kReadbackReplacementSourceFrameNumber)
1290 << sfn;
1293 virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
1294 // We should only draw the first commit after output surface initialization
1295 // and attempt to draw the readback commit (which will fail).
1296 // All others should abort because the output surface is lost.
1297 int sfn = host_impl->active_tree()->source_frame_number();
1298 EXPECT_TRUE(sfn == kSecondOutputSurfaceInitSourceFrameNumber ||
1299 sfn == kReadbackSourceFrameNumber)
1300 << sfn;
1303 virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
1304 bool result) OVERRIDE {
1305 // We should only swap the first commit after the second output surface
1306 // initialization.
1307 int sfn = host_impl->active_tree()->source_frame_number();
1308 EXPECT_TRUE(sfn == kSecondOutputSurfaceInitSourceFrameNumber) << sfn;
1309 EndTest();
1312 virtual void AfterTest() OVERRIDE {}
1314 int did_react_to_first_commit_;
1317 MULTI_THREAD_TEST_F(
1318 LayerTreeHostContextTestLoseOutputSurfaceDuringReadbackAndForcedDraw);
1320 // This test verifies that losing an output surface right before a
1321 // simultaneous readback and forced redraw works and does not deadlock.
1322 class LayerTreeHostContextTestReadbackWithForcedDrawAndOutputSurfaceInit
1323 : public LayerTreeHostContextTest {
1324 protected:
1325 static const int kFirstOutputSurfaceInitSourceFrameNumber = 0;
1326 static const int kReadbackSourceFrameNumber = 1;
1327 static const int kForcedDrawCommitSourceFrameNumber = 2;
1328 static const int kSecondOutputSurfaceInitSourceFrameNumber = 2;
1330 LayerTreeHostContextTestReadbackWithForcedDrawAndOutputSurfaceInit()
1331 : did_lose_context_(false) {}
1333 virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
1334 // This enables forced draws after a single prepare to draw failure.
1335 settings->timeout_and_draw_when_animation_checkerboards = true;
1336 settings->maximum_number_of_failed_draws_before_draw_is_forced_ = 1;
1339 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
1341 virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
1342 LayerTreeHostImpl::FrameData* frame_data,
1343 bool result) OVERRIDE {
1344 int sfn = host_impl->active_tree()->source_frame_number();
1345 EXPECT_TRUE(sfn == kFirstOutputSurfaceInitSourceFrameNumber ||
1346 sfn == kSecondOutputSurfaceInitSourceFrameNumber ||
1347 sfn == kReadbackSourceFrameNumber)
1348 << sfn;
1350 // Before we react to the failed draw by initiating the forced draw
1351 // sequence, start a readback on the main thread and then lose the context
1352 // to start output surface initialization all at the same time.
1353 if (sfn == kFirstOutputSurfaceInitSourceFrameNumber && !did_lose_context_) {
1354 did_lose_context_ = true;
1355 LoseContext();
1358 // Returning false will result in a forced draw.
1359 return false;
1362 virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
1363 EXPECT_TRUE(succeeded);
1364 if (layer_tree_host()->source_frame_number() > 0) {
1365 // Perform a readback right after the second output surface
1366 // initialization.
1367 char pixels[4];
1368 layer_tree_host()->CompositeAndReadback(&pixels, gfx::Rect(0, 0, 1, 1));
1372 virtual void InitializedRendererOnThread(LayerTreeHostImpl* host_impl,
1373 bool success) OVERRIDE {
1374 // -1 is for the first output surface initialization.
1375 int sfn = host_impl->active_tree()->source_frame_number();
1376 EXPECT_TRUE(sfn == -1 || sfn == kFirstOutputSurfaceInitSourceFrameNumber)
1377 << sfn;
1380 virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
1381 // We should only draw the first commit after output surface initialization
1382 // and attempt to draw the readback commit (which will fail).
1383 // All others should abort because the output surface is lost.
1384 int sfn = host_impl->active_tree()->source_frame_number();
1385 EXPECT_TRUE(sfn == kForcedDrawCommitSourceFrameNumber ||
1386 sfn == kReadbackSourceFrameNumber)
1387 << sfn;
1390 virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
1391 bool result) OVERRIDE {
1392 // We should only swap the first commit after the second output surface
1393 // initialization.
1394 int sfn = host_impl->active_tree()->source_frame_number();
1395 EXPECT_TRUE(sfn == kForcedDrawCommitSourceFrameNumber) << sfn;
1396 EndTest();
1399 virtual void AfterTest() OVERRIDE {}
1401 int did_lose_context_;
1404 MULTI_THREAD_TEST_F(
1405 LayerTreeHostContextTestReadbackWithForcedDrawAndOutputSurfaceInit);
1407 class ImplSidePaintingLayerTreeHostContextTest
1408 : public LayerTreeHostContextTest {
1409 public:
1410 virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
1411 settings->impl_side_painting = true;
1415 class LayerTreeHostContextTestImplSidePainting
1416 : public ImplSidePaintingLayerTreeHostContextTest {
1417 public:
1418 virtual void SetupTree() OVERRIDE {
1419 scoped_refptr<Layer> root = Layer::Create();
1420 root->SetBounds(gfx::Size(10, 10));
1421 root->SetAnchorPoint(gfx::PointF());
1422 root->SetIsDrawable(true);
1424 scoped_refptr<PictureLayer> picture = PictureLayer::Create(&client_);
1425 picture->SetBounds(gfx::Size(10, 10));
1426 picture->SetAnchorPoint(gfx::PointF());
1427 picture->SetIsDrawable(true);
1428 root->AddChild(picture);
1430 layer_tree_host()->SetRootLayer(root);
1431 LayerTreeHostContextTest::SetupTree();
1434 virtual void BeginTest() OVERRIDE {
1435 times_to_lose_during_commit_ = 1;
1436 PostSetNeedsCommitToMainThread();
1439 virtual void AfterTest() OVERRIDE {}
1441 virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
1442 EXPECT_TRUE(succeeded);
1443 EndTest();
1446 private:
1447 FakeContentLayerClient client_;
1450 MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting);
1452 class ScrollbarLayerLostContext : public LayerTreeHostContextTest {
1453 public:
1454 ScrollbarLayerLostContext() : commits_(0) {}
1456 virtual void BeginTest() OVERRIDE {
1457 scoped_refptr<Layer> scroll_layer = Layer::Create();
1458 scrollbar_layer_ =
1459 FakePaintedScrollbarLayer::Create(false, true, scroll_layer->id());
1460 scrollbar_layer_->SetBounds(gfx::Size(10, 100));
1461 layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
1462 layer_tree_host()->root_layer()->AddChild(scroll_layer);
1463 PostSetNeedsCommitToMainThread();
1466 virtual void AfterTest() OVERRIDE {}
1468 virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1469 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1471 ++commits_;
1472 switch (commits_) {
1473 case 1:
1474 // First (regular) update, we should upload 2 resources (thumb, and
1475 // backtrack).
1476 EXPECT_EQ(1, scrollbar_layer_->update_count());
1477 LoseContext();
1478 break;
1479 case 2:
1480 // Second update, after the lost context, we should still upload 2
1481 // resources even if the contents haven't changed.
1482 EXPECT_EQ(2, scrollbar_layer_->update_count());
1483 EndTest();
1484 break;
1485 case 3:
1486 // Single thread proxy issues extra commits after context lost.
1487 // http://crbug.com/287250
1488 if (HasImplThread())
1489 NOTREACHED();
1490 break;
1491 default:
1492 NOTREACHED();
1496 private:
1497 int commits_;
1498 scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer_;
1501 SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext);
1503 class UIResourceLostTest : public LayerTreeHostContextTest {
1504 public:
1505 UIResourceLostTest() : time_step_(0) {}
1506 virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
1507 settings->texture_id_allocation_chunk_size = 1;
1509 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
1510 virtual void AfterTest() OVERRIDE {}
1512 // This is called on the main thread after each commit and
1513 // DidActivateTreeOnThread, with the value of time_step_ at the time
1514 // of the call to DidActivateTreeOnThread. Similar tests will do
1515 // work on the main thread in DidCommit but that is unsuitable because
1516 // the main thread work for these tests must happen after
1517 // DidActivateTreeOnThread, which happens after DidCommit with impl-side
1518 // painting.
1519 virtual void StepCompleteOnMainThread(int time_step) = 0;
1521 // Called after DidActivateTreeOnThread. If this is done during the commit,
1522 // the call to StepCompleteOnMainThread will not occur until after
1523 // the commit completes, because the main thread is blocked.
1524 void PostStepCompleteToMainThread() {
1525 proxy()->MainThreadTaskRunner()->PostTask(
1526 FROM_HERE,
1527 base::Bind(&UIResourceLostTest::StepCompleteOnMainThreadInternal,
1528 base::Unretained(this),
1529 time_step_));
1532 void PostLoseContextToImplThread() {
1533 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1534 base::SingleThreadTaskRunner* task_runner =
1535 HasImplThread() ? ImplThreadTaskRunner()
1536 : base::MessageLoopProxy::current();
1537 task_runner->PostTask(FROM_HERE,
1538 base::Bind(&LayerTreeHostContextTest::LoseContext,
1539 base::Unretained(this)));
1542 protected:
1543 int time_step_;
1544 scoped_ptr<FakeScopedUIResource> ui_resource_;
1546 private:
1547 void StepCompleteOnMainThreadInternal(int step) {
1548 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1549 StepCompleteOnMainThread(step);
1553 class UIResourceLostTestSimple : public UIResourceLostTest {
1554 public:
1555 // This is called when the commit is complete and the new layer tree has been
1556 // activated.
1557 virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) = 0;
1559 virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1560 if (!layer_tree_host()->settings().impl_side_painting) {
1561 StepCompleteOnImplThread(impl);
1562 PostStepCompleteToMainThread();
1563 ++time_step_;
1567 virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1568 if (layer_tree_host()->settings().impl_side_painting) {
1569 StepCompleteOnImplThread(impl);
1570 PostStepCompleteToMainThread();
1571 ++time_step_;
1576 // Losing context after an UI resource has been created.
1577 class UIResourceLostAfterCommit : public UIResourceLostTestSimple {
1578 public:
1579 virtual void StepCompleteOnMainThread(int step) OVERRIDE {
1580 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1581 switch (step) {
1582 case 0:
1583 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1584 // Expects a valid UIResourceId.
1585 EXPECT_NE(0, ui_resource_->id());
1586 PostSetNeedsCommitToMainThread();
1587 break;
1588 case 4:
1589 // Release resource before ending the test.
1590 ui_resource_.reset();
1591 EndTest();
1592 break;
1593 case 5:
1594 // Single thread proxy issues extra commits after context lost.
1595 // http://crbug.com/287250
1596 if (HasImplThread())
1597 NOTREACHED();
1598 break;
1599 case 6:
1600 NOTREACHED();
1604 virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) OVERRIDE {
1605 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1606 switch (time_step_) {
1607 case 1:
1608 // The resource should have been created on LTHI after the commit.
1609 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1610 PostSetNeedsCommitToMainThread();
1611 break;
1612 case 2:
1613 LoseContext();
1614 break;
1615 case 3:
1616 // The resources should have been recreated. The bitmap callback should
1617 // have been called once with the resource_lost flag set to true.
1618 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1619 // Resource Id on the impl-side have been recreated as well. Note
1620 // that the same UIResourceId persists after the context lost.
1621 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1622 PostSetNeedsCommitToMainThread();
1623 break;
1628 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostAfterCommit);
1630 // Losing context before UI resource requests can be commited. Three sequences
1631 // of creation/deletion are considered:
1632 // 1. Create one resource -> Context Lost => Expect the resource to have been
1633 // created.
1634 // 2. Delete an exisiting resource (test_id0_) -> create a second resource
1635 // (test_id1_) -> Context Lost => Expect the test_id0_ to be removed and
1636 // test_id1_ to have been created.
1637 // 3. Create one resource -> Delete that same resource -> Context Lost => Expect
1638 // the resource to not exist in the manager.
1639 class UIResourceLostBeforeCommit : public UIResourceLostTestSimple {
1640 public:
1641 UIResourceLostBeforeCommit() : test_id0_(0), test_id1_(0) {}
1643 virtual void StepCompleteOnMainThread(int step) OVERRIDE {
1644 switch (step) {
1645 case 0:
1646 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1647 // Lose the context on the impl thread before the commit.
1648 PostLoseContextToImplThread();
1649 break;
1650 case 2:
1651 // Sequence 2:
1652 // Currently one resource has been created.
1653 test_id0_ = ui_resource_->id();
1654 // Delete this resource.
1655 ui_resource_.reset();
1656 // Create another resource.
1657 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1658 test_id1_ = ui_resource_->id();
1659 // Sanity check that two resource creations return different ids.
1660 EXPECT_NE(test_id0_, test_id1_);
1661 // Lose the context on the impl thread before the commit.
1662 PostLoseContextToImplThread();
1663 break;
1664 case 3:
1665 // Clear the manager of resources.
1666 ui_resource_.reset();
1667 PostSetNeedsCommitToMainThread();
1668 break;
1669 case 4:
1670 // Sequence 3:
1671 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1672 test_id0_ = ui_resource_->id();
1673 // Sanity check the UIResourceId should not be 0.
1674 EXPECT_NE(0, test_id0_);
1675 // Usually ScopedUIResource are deleted from the manager in their
1676 // destructor (so usually ui_resource_.reset()). But here we need
1677 // ui_resource_ for the next step, so call DeleteUIResource directly.
1678 layer_tree_host()->DeleteUIResource(test_id0_);
1679 // Delete the resouce and then lose the context.
1680 PostLoseContextToImplThread();
1681 break;
1682 case 5:
1683 // Release resource before ending the test.
1684 ui_resource_.reset();
1685 EndTest();
1686 break;
1687 case 6:
1688 // Single thread proxy issues extra commits after context lost.
1689 // http://crbug.com/287250
1690 if (HasImplThread())
1691 NOTREACHED();
1692 break;
1693 case 8:
1694 NOTREACHED();
1698 virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) OVERRIDE {
1699 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1700 switch (time_step_) {
1701 case 1:
1702 // Sequence 1 (continued):
1703 // The first context lost happens before the resources were created,
1704 // and because it resulted in no resources being destroyed, it does not
1705 // trigger resource re-creation.
1706 EXPECT_EQ(1, ui_resource_->resource_create_count);
1707 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1708 // Resource Id on the impl-side has been created.
1709 PostSetNeedsCommitToMainThread();
1710 break;
1711 case 3:
1712 // Sequence 2 (continued):
1713 // The previous resource should have been deleted.
1714 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
1715 if (HasImplThread()) {
1716 // The second resource should have been created.
1717 EXPECT_NE(0u, impl->ResourceIdForUIResource(test_id1_));
1718 } else {
1719 // The extra commit that happens at context lost in the single thread
1720 // proxy changes the timing so that the resource has been destroyed.
1721 // http://crbug.com/287250
1722 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id1_));
1724 // The second resource called the resource callback once and since the
1725 // context is lost, a "resource lost" callback was also issued.
1726 EXPECT_EQ(2, ui_resource_->resource_create_count);
1727 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1728 break;
1729 case 5:
1730 // Sequence 3 (continued):
1731 // Expect the resource callback to have been called once.
1732 EXPECT_EQ(1, ui_resource_->resource_create_count);
1733 // No "resource lost" callbacks.
1734 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1735 // The UI resource id should not be valid
1736 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
1737 break;
1741 private:
1742 UIResourceId test_id0_;
1743 UIResourceId test_id1_;
1746 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeCommit);
1748 // Losing UI resource before the pending trees is activated but after the
1749 // commit. Impl-side-painting only.
1750 class UIResourceLostBeforeActivateTree : public UIResourceLostTest {
1751 virtual void StepCompleteOnMainThread(int step) OVERRIDE {
1752 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1753 switch (step) {
1754 case 0:
1755 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1756 PostSetNeedsCommitToMainThread();
1757 break;
1758 case 3:
1759 test_id_ = ui_resource_->id();
1760 ui_resource_.reset();
1761 PostSetNeedsCommitToMainThread();
1762 break;
1763 case 5:
1764 // Release resource before ending the test.
1765 ui_resource_.reset();
1766 EndTest();
1767 break;
1768 case 6:
1769 // Make sure no extra commits happened.
1770 NOTREACHED();
1774 virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1775 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1776 switch (time_step_) {
1777 case 2:
1778 PostSetNeedsCommitToMainThread();
1779 break;
1780 case 4:
1781 PostSetNeedsCommitToMainThread();
1782 break;
1786 virtual void WillActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1787 switch (time_step_) {
1788 case 1:
1789 // The resource creation callback has been called.
1790 EXPECT_EQ(1, ui_resource_->resource_create_count);
1791 // The resource is not yet lost (sanity check).
1792 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1793 // The resource should not have been created yet on the impl-side.
1794 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1795 LoseContext();
1796 break;
1797 case 3:
1798 LoseContext();
1799 break;
1803 virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1804 LayerTreeHostContextTest::DidActivateTreeOnThread(impl);
1805 switch (time_step_) {
1806 case 1:
1807 // The pending requests on the impl-side should have been processed.
1808 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1809 break;
1810 case 2:
1811 // The "lost resource" callback should have been called once.
1812 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1813 break;
1814 case 4:
1815 // The resource is deleted and should not be in the manager. Use
1816 // test_id_ since ui_resource_ has been deleted.
1817 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id_));
1818 break;
1821 PostStepCompleteToMainThread();
1822 ++time_step_;
1825 private:
1826 UIResourceId test_id_;
1829 TEST_F(UIResourceLostBeforeActivateTree,
1830 RunMultiThread_DirectRenderer_ImplSidePaint) {
1831 RunTest(true, false, true);
1834 TEST_F(UIResourceLostBeforeActivateTree,
1835 RunMultiThread_DelegatingRenderer_ImplSidePaint) {
1836 RunTest(true, true, true);
1839 // Resources evicted explicitly and by visibility changes.
1840 class UIResourceLostEviction : public UIResourceLostTestSimple {
1841 public:
1842 virtual void StepCompleteOnMainThread(int step) OVERRIDE {
1843 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1844 switch (step) {
1845 case 0:
1846 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1847 EXPECT_NE(0, ui_resource_->id());
1848 PostSetNeedsCommitToMainThread();
1849 break;
1850 case 2:
1851 // Make the tree not visible.
1852 PostSetVisibleToMainThread(false);
1853 break;
1854 case 3:
1855 // Release resource before ending the test.
1856 ui_resource_.reset();
1857 EndTest();
1858 break;
1859 case 4:
1860 NOTREACHED();
1864 virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* impl,
1865 bool visible) OVERRIDE {
1866 TestWebGraphicsContext3D* context = TestContext();
1867 if (!visible) {
1868 // All resources should have been evicted.
1869 ASSERT_EQ(0u, context->NumTextures());
1870 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1871 EXPECT_EQ(2, ui_resource_->resource_create_count);
1872 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1873 // Drawing is disabled both because of the evicted resources and
1874 // because the renderer is not visible.
1875 EXPECT_FALSE(impl->CanDraw());
1876 // Make the renderer visible again.
1877 PostSetVisibleToMainThread(true);
1881 virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) OVERRIDE {
1882 TestWebGraphicsContext3D* context = TestContext();
1883 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1884 switch (time_step_) {
1885 case 1:
1886 // The resource should have been created on LTHI after the commit.
1887 ASSERT_EQ(1u, context->NumTextures());
1888 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1889 EXPECT_EQ(1, ui_resource_->resource_create_count);
1890 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1891 EXPECT_TRUE(impl->CanDraw());
1892 // Evict all UI resources. This will trigger a commit.
1893 impl->EvictAllUIResources();
1894 ASSERT_EQ(0u, context->NumTextures());
1895 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1896 EXPECT_EQ(1, ui_resource_->resource_create_count);
1897 EXPECT_EQ(0, ui_resource_->lost_resource_count);
1898 EXPECT_FALSE(impl->CanDraw());
1899 break;
1900 case 2:
1901 // The resource should have been recreated.
1902 ASSERT_EQ(1u, context->NumTextures());
1903 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1904 EXPECT_EQ(2, ui_resource_->resource_create_count);
1905 EXPECT_EQ(1, ui_resource_->lost_resource_count);
1906 EXPECT_TRUE(impl->CanDraw());
1907 break;
1908 case 3:
1909 // The resource should have been recreated after visibility was
1910 // restored.
1911 ASSERT_EQ(1u, context->NumTextures());
1912 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1913 EXPECT_EQ(3, ui_resource_->resource_create_count);
1914 EXPECT_EQ(2, ui_resource_->lost_resource_count);
1915 EXPECT_TRUE(impl->CanDraw());
1916 break;
1921 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction);
1923 class LayerTreeHostContextTestSurfaceCreateCallback
1924 : public LayerTreeHostContextTest {
1925 public:
1926 LayerTreeHostContextTestSurfaceCreateCallback()
1927 : LayerTreeHostContextTest(),
1928 layer_(FakeContentLayer::Create(&client_)) {}
1930 virtual void SetupTree() OVERRIDE {
1931 layer_->SetBounds(gfx::Size(10, 20));
1932 layer_tree_host()->SetRootLayer(layer_);
1933 LayerTreeHostContextTest::SetupTree();
1936 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
1938 virtual void DidCommit() OVERRIDE {
1939 switch (layer_tree_host()->source_frame_number()) {
1940 case 1:
1941 EXPECT_EQ(1u, layer_->output_surface_created_count());
1942 layer_tree_host()->SetNeedsCommit();
1943 break;
1944 case 2:
1945 EXPECT_EQ(1u, layer_->output_surface_created_count());
1946 layer_tree_host()->SetNeedsCommit();
1947 break;
1948 case 3:
1949 EXPECT_EQ(1u, layer_->output_surface_created_count());
1950 break;
1951 case 4:
1952 EXPECT_EQ(2u, layer_->output_surface_created_count());
1953 layer_tree_host()->SetNeedsCommit();
1954 break;
1958 virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1959 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1960 switch (LastCommittedSourceFrameNumber(impl)) {
1961 case 0:
1962 break;
1963 case 1:
1964 break;
1965 case 2:
1966 LoseContext();
1967 break;
1968 case 3:
1969 EndTest();
1970 break;
1974 virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
1975 EXPECT_TRUE(succeeded);
1978 virtual void AfterTest() OVERRIDE {}
1980 protected:
1981 FakeContentLayerClient client_;
1982 scoped_refptr<FakeContentLayer> layer_;
1985 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestSurfaceCreateCallback);
1987 } // namespace
1988 } // namespace cc