57c780b7aca1b1cc6386b14b71949fbd02139c1f
[platform/framework/web/crosswalk.git] / src / cc / trees / layer_tree_host_unittest_context.cc
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.
4
5 #include "cc/trees/layer_tree_host.h"
6
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"
42
43 using media::VideoFrame;
44
45 namespace cc {
46 namespace {
47
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();
67   }
68
69   void LoseContext() {
70     context3d_->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
71                                     GL_INNOCENT_CONTEXT_RESET_ARB);
72     context3d_ = NULL;
73   }
74
75   virtual scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() {
76     return TestWebGraphicsContext3D::Create();
77   }
78
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>();
85     }
86
87     scoped_ptr<TestWebGraphicsContext3D> context3d = CreateContext3d();
88     context3d_ = context3d.get();
89
90     if (context_should_support_io_surface_) {
91       context3d_->set_have_extension_io_surface(true);
92       context3d_->set_have_extension_egl_image(true);
93     }
94
95     if (delegating_renderer())
96       return FakeOutputSurface::CreateDelegating3d(context3d.Pass());
97     else
98       return FakeOutputSurface::Create3d(context3d.Pass());
99   }
100
101   scoped_ptr<TestWebGraphicsContext3D> CreateOffscreenContext3d() {
102     if (!context3d_)
103       return scoped_ptr<TestWebGraphicsContext3D>();
104
105     ++times_offscreen_created_;
106
107     if (times_to_fail_create_offscreen_) {
108       --times_to_fail_create_offscreen_;
109       ExpectCreateToFail();
110       return scoped_ptr<TestWebGraphicsContext3D>();
111     }
112
113     scoped_ptr<TestWebGraphicsContext3D> offscreen_context3d =
114         TestWebGraphicsContext3D::Create().Pass();
115     DCHECK(offscreen_context3d);
116     context3d_->add_share_group_context(offscreen_context3d.get());
117
118     return offscreen_context3d.Pass();
119   }
120
121   virtual scoped_refptr<ContextProvider> OffscreenContextProvider() OVERRIDE {
122     if (!offscreen_contexts_.get() ||
123         offscreen_contexts_->DestroyedOnMainThread()) {
124       offscreen_contexts_ =
125           TestContextProvider::Create(CreateOffscreenContext3d());
126     }
127     return offscreen_contexts_;
128   }
129
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;
136
137     --times_to_lose_during_draw_;
138     LoseContext();
139
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;
144
145     return result;
146   }
147
148   virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
149     committed_at_least_once_ = true;
150
151     if (!times_to_lose_during_commit_)
152       return;
153     --times_to_lose_during_commit_;
154     LoseContext();
155
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;
160   }
161
162   virtual void DidFailToInitializeOutputSurface() OVERRIDE {
163     ++times_create_failed_;
164   }
165
166   virtual void TearDown() OVERRIDE {
167     LayerTreeTest::TearDown();
168     EXPECT_EQ(times_to_expect_create_failed_, times_create_failed_);
169   }
170
171   void ExpectCreateToFail() { ++times_to_expect_create_failed_; }
172
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_;
187
188   scoped_refptr<TestContextProvider> offscreen_contexts_;
189 };
190
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) {}
201
202   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
203
204   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
205     EXPECT_TRUE(succeeded);
206
207     if (first_initialized_)
208       ++num_losses_;
209     else
210       first_initialized_ = true;
211
212     recovered_context_ = true;
213   }
214
215   virtual void AfterTest() OVERRIDE { EXPECT_EQ(9u, test_case_); }
216
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;
226
227     recovered_context_ = false;
228     if (NextTestCase())
229       InvalidateAndSetNeedsCommit();
230     else
231       EndTest();
232   }
233
234   virtual void InvalidateAndSetNeedsCommit() {
235     // Cause damage so we try to draw.
236     layer_tree_host()->root_layer()->SetNeedsDisplay();
237     layer_tree_host()->SetNeedsCommit();
238   }
239
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
249         },
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
255         },
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
261         },
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
267         },
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
273         },
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
279         },
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
287         },
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
293         },
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         }, };
302
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_;
309
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;
319   }
320
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;
327   };
328
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_;
335 };
336
337 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLostContextSucceeds);
338
339 class LayerTreeHostClientNotReadyDoesNotCreateOutputSurface
340     : public LayerTreeHostContextTest {
341  public:
342   LayerTreeHostClientNotReadyDoesNotCreateOutputSurface()
343       : LayerTreeHostContextTest() {}
344
345   virtual void WillBeginTest() OVERRIDE {
346     // Override and do not signal SetLayerTreeHostClientReady.
347   }
348
349   virtual void BeginTest() OVERRIDE {
350     PostSetNeedsCommitToMainThread();
351     EndTest();
352   }
353
354   virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
355       OVERRIDE {
356     EXPECT_TRUE(false);
357     return scoped_ptr<OutputSurface>();
358   }
359
360   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
361     EXPECT_TRUE(false);
362   }
363
364   virtual void AfterTest() OVERRIDE {
365   }
366 };
367
368 MULTI_THREAD_TEST_F(LayerTreeHostClientNotReadyDoesNotCreateOutputSurface);
369
370 class LayerTreeHostContextTestLostContextSucceedsWithContent
371     : public LayerTreeHostContextTestLostContextSucceeds {
372  public:
373   LayerTreeHostContextTestLostContextSucceedsWithContent()
374       : LayerTreeHostContextTestLostContextSucceeds() {}
375
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);
381
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);
393     }
394
395     root_->AddChild(content_);
396
397     layer_tree_host()->SetRootLayer(root_);
398     LayerTreeHostContextTest::SetupTree();
399   }
400
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();
407   }
408
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));
416
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);
425     }
426   }
427
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_);
439     }
440   }
441
442  protected:
443   bool use_surface_;
444   FakeContentLayerClient client_;
445   scoped_refptr<Layer> root_;
446   scoped_refptr<ContentLayer> content_;
447 };
448
449 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
450        NoSurface_SingleThread_DirectRenderer) {
451   use_surface_ = false;
452   RunTest(false, false, false);
453 }
454
455 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
456        NoSurface_SingleThread_DelegatingRenderer) {
457   use_surface_ = false;
458   RunTest(false, true, false);
459 }
460
461 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
462        NoSurface_MultiThread_DirectRenderer_MainThreadPaint) {
463   use_surface_ = false;
464   RunTest(true, false, false);
465 }
466
467 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
468        NoSurface_MultiThread_DelegatingRenderer_MainThreadPaint) {
469   use_surface_ = false;
470   RunTest(true, true, false);
471 }
472
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);
478 }
479
480 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
481        WithSurface_MultiThread_DirectRenderer_MainThreadPaint) {
482   use_surface_ = true;
483   RunTest(true, false, false);
484 }
485
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) {}
500
501   virtual void BeginTest() OVERRIDE {
502     times_to_fail_create_ = times_to_fail_;
503     PostSetNeedsCommitToMainThread();
504   }
505
506   virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
507       OVERRIDE {
508     scoped_ptr<OutputSurface> surface =
509         LayerTreeHostContextTest::CreateOutputSurface(fallback);
510
511     if (surface)
512       EXPECT_EQ(times_to_fail_, times_create_failed_);
513
514     did_attempt_fallback_ = fallback;
515     return surface.Pass();
516   }
517
518   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
519     if (succeeded)
520       times_initialized_++;
521     else
522       EndTest();
523   }
524
525   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
526     EndTest();
527   }
528
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_);
533   }
534
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_;
541 };
542
543 class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
544     : public LayerTreeHostContextTestCreateOutputSurfaceFails {
545  public:
546   LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
547       : LayerTreeHostContextTestCreateOutputSurfaceFails(1, false, false) {}
548 };
549
550 SINGLE_AND_MULTI_THREAD_TEST_F(
551     LayerTreeHostContextTestCreateOutputSurfaceFailsOnce);
552
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) {}
560 };
561
562 SINGLE_AND_MULTI_THREAD_TEST_F(
563     LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback);
564
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) {}
571 };
572
573 SINGLE_AND_MULTI_THREAD_TEST_F(
574     LayerTreeHostContextTestCreateOutputSurfaceIsHopeless);
575
576
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);
585
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);
596
597     root_->AddChild(content_);
598
599     layer_tree_host()->SetRootLayer(root_);
600     LayerTreeHostContextTest::SetupTree();
601   }
602
603   virtual void BeginTest() OVERRIDE {
604     times_to_fail_create_offscreen_ = 1;
605     PostSetNeedsCommitToMainThread();
606   }
607
608   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
609     ContextProvider* contexts = host_impl->offscreen_context_provider();
610     EXPECT_FALSE(contexts);
611
612     // This did not lead to create failure.
613     times_to_expect_create_failed_ = 0;
614     EndTest();
615   }
616
617   virtual void AfterTest() OVERRIDE {}
618
619  protected:
620   FakeContentLayerClient client_;
621   scoped_refptr<Layer> root_;
622   scoped_refptr<ContentLayer> content_;
623 };
624
625 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestOffscreenContextFails);
626
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;
633   }
634
635   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
636
637   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
638     if (first_initialized_) {
639       EXPECT_FALSE(succeeded);
640       EndTest();
641     } else {
642       first_initialized_ = true;
643     }
644   }
645
646   virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
647     LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
648
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;
656     }
657
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());
662   }
663
664   virtual void AfterTest() OVERRIDE {}
665
666  private:
667   int num_commits_;
668   bool first_initialized_;
669 };
670
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) {}
679
680   virtual void SetupTree() OVERRIDE {
681     layer_->SetBounds(gfx::Size(10, 20));
682     layer_tree_host()->SetRootLayer(layer_);
683     LayerTreeHostContextTest::SetupTree();
684   }
685
686   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
687
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();
698     }
699   }
700
701   void EvictTexturesOnImplThread() {
702     impl_host_->EvictTexturesForTesting();
703     if (lose_after_evict_)
704       LoseContext();
705   }
706
707   virtual void DidCommitAndDrawFrame() OVERRIDE {
708     if (num_commits_ > 1)
709       return;
710     EXPECT_TRUE(layer_->HaveBackingAt(0, 0));
711     PostEvictTextures();
712   }
713
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;
722   }
723
724   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
725     EXPECT_TRUE(succeeded);
726     EndTest();
727   }
728
729   virtual void AfterTest() OVERRIDE {}
730
731  protected:
732   bool lose_after_evict_;
733   FakeContentLayerClient client_;
734   scoped_refptr<FakeContentLayer> layer_;
735   LayerTreeHostImpl* impl_host_;
736   int num_commits_;
737 };
738
739 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
740        LoseAfterEvict_SingleThread_DirectRenderer) {
741   lose_after_evict_ = true;
742   RunTest(false, false, false);
743 }
744
745 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
746        LoseAfterEvict_SingleThread_DelegatingRenderer) {
747   lose_after_evict_ = true;
748   RunTest(false, true, false);
749 }
750
751 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
752        LoseAfterEvict_MultiThread_DirectRenderer_MainThreadPaint) {
753   lose_after_evict_ = true;
754   RunTest(true, false, false);
755 }
756
757 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
758        LoseAfterEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
759   lose_after_evict_ = true;
760   RunTest(true, true, false);
761 }
762
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);
768 }
769
770 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
771        LoseBeforeEvict_SingleThread_DirectRenderer) {
772   lose_after_evict_ = false;
773   RunTest(false, false, false);
774 }
775
776 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
777        LoseBeforeEvict_SingleThread_DelegatingRenderer) {
778   lose_after_evict_ = false;
779   RunTest(false, true, false);
780 }
781
782 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
783        LoseBeforeEvict_MultiThread_DirectRenderer_MainThreadPaint) {
784   lose_after_evict_ = false;
785   RunTest(true, false, false);
786 }
787
788 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
789        LoseBeforeEvict_MultiThread_DirectRenderer_ImplSidePaint) {
790   lose_after_evict_ = false;
791   RunTest(true, false, true);
792 }
793
794 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
795        LoseBeforeEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
796   lose_after_evict_ = false;
797   RunTest(true, true, false);
798 }
799
800 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
801        LoseBeforeEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
802   lose_after_evict_ = false;
803   RunTest(true, true, true);
804 }
805
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) {}
813
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);
820     }
821     return context.Pass();
822   }
823
824   virtual void SetupTree() OVERRIDE {
825     parent_->SetBounds(gfx::Size(num_children_, 1));
826
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);
833     }
834
835     layer_tree_host()->SetRootLayer(parent_);
836     LayerTreeHostContextTest::SetupTree();
837   }
838
839   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
840
841   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
842     EXPECT_EQ(0, times_to_lose_on_end_query_);
843     EndTest();
844   }
845
846   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
847     EXPECT_TRUE(succeeded);
848   }
849
850   virtual void AfterTest() OVERRIDE {
851     EXPECT_EQ(0, times_to_lose_on_end_query_);
852   }
853
854  private:
855   FakeContentLayerClient client_;
856   scoped_refptr<FakeContentLayer> parent_;
857   int num_children_;
858   int times_to_lose_on_end_query_;
859 };
860
861 SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
862     LayerTreeHostContextTestLostContextWhileUpdatingResources);
863
864 class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
865  public:
866   LayerTreeHostContextTestLayersNotified()
867       : LayerTreeHostContextTest(), num_commits_(0) {}
868
869   virtual void SetupTree() OVERRIDE {
870     root_ = FakeContentLayer::Create(&client_);
871     child_ = FakeContentLayer::Create(&client_);
872     grandchild_ = FakeContentLayer::Create(&client_);
873
874     root_->AddChild(child_);
875     child_->AddChild(grandchild_);
876
877     layer_tree_host()->SetRootLayer(root_);
878     LayerTreeHostContextTest::SetupTree();
879   }
880
881   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
882
883   virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
884     LayerTreeHostContextTest::DidActivateTreeOnThread(host_impl);
885
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]);
892
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();
911     }
912   }
913
914   virtual void AfterTest() OVERRIDE {}
915
916  private:
917   int num_commits_;
918
919   FakeContentLayerClient client_;
920   scoped_refptr<FakeContentLayer> root_;
921   scoped_refptr<FakeContentLayer> child_;
922   scoped_refptr<FakeContentLayer> grandchild_;
923 };
924
925 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified);
926
927 class LayerTreeHostContextTestDontUseLostResources
928     : public LayerTreeHostContextTest {
929  public:
930   LayerTreeHostContextTestDontUseLostResources() : lost_context_(false) {
931     context_should_support_io_surface_ = true;
932
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);
937   }
938
939   static void EmptyReleaseCallback(unsigned sync_point, bool lost) {}
940
941   virtual void SetupTree() OVERRIDE {
942     gpu::gles2::GLES2Interface* gl =
943         child_output_surface_->context_provider()->ContextGL();
944
945     scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
946
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());
954
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));
962
963     frame_data->render_pass_list.push_back(pass_for_quad.PassAs<RenderPass>());
964     frame_data->render_pass_list.push_back(pass.PassAs<RenderPass>());
965
966     delegated_resource_collection_ = new DelegatedFrameResourceCollection;
967     delegated_frame_provider_ = new DelegatedFrameProvider(
968         delegated_resource_collection_.get(), frame_data.Pass());
969
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);
978
979     gpu::Mailbox mailbox;
980     gl->GenMailboxCHROMIUM(mailbox.name);
981     GLuint sync_point = gl->InsertSyncPointCHROMIUM();
982
983     scoped_refptr<Layer> root = Layer::Create();
984     root->SetBounds(gfx::Size(10, 10));
985     root->SetAnchorPoint(gfx::PointF());
986     root->SetIsDrawable(true);
987
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);
994
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);
1000
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);
1011
1012     scoped_refptr<ContentLayer> mask = ContentLayer::Create(&client_);
1013     mask->SetBounds(gfx::Size(10, 10));
1014     mask->SetAnchorPoint(gfx::PointF());
1015
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);
1023
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);
1030
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);
1037
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);
1044
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());
1071
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_);
1075
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);
1084     }
1085
1086     // Enable the hud.
1087     LayerTreeDebugState debug_state;
1088     debug_state.show_property_changed_rects = true;
1089     layer_tree_host()->SetDebugState(debug_state);
1090
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);
1098
1099     layer_tree_host()->SetRootLayer(root);
1100     LayerTreeHostContextTest::SetupTree();
1101   }
1102
1103   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
1104
1105   virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
1106     LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
1107
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);
1114     }
1115   }
1116
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);
1124     }
1125     return true;
1126   }
1127
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);
1137     }
1138     return LayerTreeHostContextTest::CreateOutputSurface(fallback);
1139   }
1140
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();
1149     }
1150   }
1151
1152   virtual void AfterTest() OVERRIDE { EXPECT_TRUE(lost_context_); }
1153
1154  private:
1155   FakeContentLayerClient client_;
1156   bool lost_context_;
1157
1158   FakeOutputSurfaceClient output_surface_client_;
1159   scoped_ptr<FakeOutputSurface> child_output_surface_;
1160   scoped_ptr<ResourceProvider> child_resource_provider_;
1161
1162   scoped_refptr<DelegatedFrameResourceCollection>
1163       delegated_resource_collection_;
1164   scoped_refptr<DelegatedFrameProvider> delegated_frame_provider_;
1165
1166   scoped_refptr<VideoFrame> color_video_frame_;
1167   scoped_refptr<VideoFrame> hw_video_frame_;
1168   scoped_refptr<VideoFrame> scaled_hw_video_frame_;
1169
1170   FakeVideoFrameProvider color_frame_provider_;
1171   FakeVideoFrameProvider hw_frame_provider_;
1172   FakeVideoFrameProvider scaled_hw_frame_provider_;
1173 };
1174
1175 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources);
1176
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());
1184
1185     times_output_surface_created_ = 0;
1186
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();
1191
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_);
1197   }
1198
1199   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
1200     EXPECT_TRUE(succeeded);
1201     ++times_output_surface_created_;
1202   }
1203
1204   virtual void DidCommitAndDrawFrame() OVERRIDE { EndTest(); }
1205
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_);
1210   }
1211
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;
1218   }
1219
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);
1226   }
1227
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();
1233   }
1234
1235  private:
1236   int times_output_surface_created_;
1237 };
1238
1239 SINGLE_AND_MULTI_THREAD_TEST_F(
1240     LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit);
1241
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;
1251
1252   LayerTreeHostContextTestLoseOutputSurfaceDuringReadbackAndForcedDraw()
1253       : did_react_to_first_commit_(false) {}
1254
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;
1259   }
1260
1261   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
1262
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;
1271
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();
1280     }
1281
1282     return false;
1283   }
1284
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;
1291   }
1292
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;
1301   }
1302
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();
1310   }
1311
1312   virtual void AfterTest() OVERRIDE {}
1313
1314   int did_react_to_first_commit_;
1315 };
1316
1317 MULTI_THREAD_TEST_F(
1318     LayerTreeHostContextTestLoseOutputSurfaceDuringReadbackAndForcedDraw);
1319
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;
1329
1330   LayerTreeHostContextTestReadbackWithForcedDrawAndOutputSurfaceInit()
1331       : did_lose_context_(false) {}
1332
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;
1337   }
1338
1339   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
1340
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;
1349
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();
1356     }
1357
1358     // Returning false will result in a forced draw.
1359     return false;
1360   }
1361
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));
1369     }
1370   }
1371
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;
1378   }
1379
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;
1388   }
1389
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();
1397   }
1398
1399   virtual void AfterTest() OVERRIDE {}
1400
1401   int did_lose_context_;
1402 };
1403
1404 MULTI_THREAD_TEST_F(
1405     LayerTreeHostContextTestReadbackWithForcedDrawAndOutputSurfaceInit);
1406
1407 class ImplSidePaintingLayerTreeHostContextTest
1408     : public LayerTreeHostContextTest {
1409  public:
1410   virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
1411     settings->impl_side_painting = true;
1412   }
1413 };
1414
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);
1423
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);
1429
1430     layer_tree_host()->SetRootLayer(root);
1431     LayerTreeHostContextTest::SetupTree();
1432   }
1433
1434   virtual void BeginTest() OVERRIDE {
1435     times_to_lose_during_commit_ = 1;
1436     PostSetNeedsCommitToMainThread();
1437   }
1438
1439   virtual void AfterTest() OVERRIDE {}
1440
1441   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
1442     EXPECT_TRUE(succeeded);
1443     EndTest();
1444   }
1445
1446  private:
1447   FakeContentLayerClient client_;
1448 };
1449
1450 MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting);
1451
1452 class ScrollbarLayerLostContext : public LayerTreeHostContextTest {
1453  public:
1454   ScrollbarLayerLostContext() : commits_(0) {}
1455
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();
1464   }
1465
1466   virtual void AfterTest() OVERRIDE {}
1467
1468   virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1469     LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1470
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();
1493     }
1494   }
1495
1496  private:
1497   int commits_;
1498   scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer_;
1499 };
1500
1501 SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext);
1502
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;
1508   }
1509   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
1510   virtual void AfterTest() OVERRIDE {}
1511
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;
1520
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_));
1530   }
1531
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)));
1540   }
1541
1542  protected:
1543   int time_step_;
1544   scoped_ptr<FakeScopedUIResource> ui_resource_;
1545
1546  private:
1547   void StepCompleteOnMainThreadInternal(int step) {
1548     EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1549     StepCompleteOnMainThread(step);
1550   }
1551 };
1552
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;
1558
1559   virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1560     if (!layer_tree_host()->settings().impl_side_painting) {
1561       StepCompleteOnImplThread(impl);
1562       PostStepCompleteToMainThread();
1563       ++time_step_;
1564     }
1565   }
1566
1567   virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1568     if (layer_tree_host()->settings().impl_side_painting) {
1569       StepCompleteOnImplThread(impl);
1570       PostStepCompleteToMainThread();
1571       ++time_step_;
1572     }
1573   }
1574 };
1575
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();
1601     }
1602   }
1603
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;
1624     }
1625   }
1626 };
1627
1628 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostAfterCommit);
1629
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) {}
1642
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();
1695     }
1696   }
1697
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_));
1723         }
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;
1738     }
1739   }
1740
1741  private:
1742   UIResourceId test_id0_;
1743   UIResourceId test_id1_;
1744 };
1745
1746 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeCommit);
1747
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();
1771     }
1772   }
1773
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;
1783     }
1784   }
1785
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;
1800     }
1801   }
1802
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;
1819     }
1820
1821     PostStepCompleteToMainThread();
1822     ++time_step_;
1823   }
1824
1825  private:
1826   UIResourceId test_id_;
1827 };
1828
1829 TEST_F(UIResourceLostBeforeActivateTree,
1830        RunMultiThread_DirectRenderer_ImplSidePaint) {
1831   RunTest(true, false, true);
1832 }
1833
1834 TEST_F(UIResourceLostBeforeActivateTree,
1835        RunMultiThread_DelegatingRenderer_ImplSidePaint) {
1836   RunTest(true, true, true);
1837 }
1838
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();
1861     }
1862   }
1863
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);
1878     }
1879   }
1880
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;
1917     }
1918   }
1919 };
1920
1921 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction);
1922
1923 class LayerTreeHostContextTestSurfaceCreateCallback
1924     : public LayerTreeHostContextTest {
1925  public:
1926   LayerTreeHostContextTestSurfaceCreateCallback()
1927       : LayerTreeHostContextTest(),
1928         layer_(FakeContentLayer::Create(&client_)) {}
1929
1930   virtual void SetupTree() OVERRIDE {
1931     layer_->SetBounds(gfx::Size(10, 20));
1932     layer_tree_host()->SetRootLayer(layer_);
1933     LayerTreeHostContextTest::SetupTree();
1934   }
1935
1936   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
1937
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;
1955     }
1956   }
1957
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;
1971     }
1972   }
1973
1974   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
1975     EXPECT_TRUE(succeeded);
1976   }
1977
1978   virtual void AfterTest() OVERRIDE {}
1979
1980  protected:
1981   FakeContentLayerClient client_;
1982   scoped_refptr<FakeContentLayer> layer_;
1983 };
1984
1985 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestSurfaceCreateCallback);
1986
1987 }  // namespace
1988 }  // namespace cc