baf2b2ddbad5f0d43995504ebc24e2a96957b848
[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> CreateFakeOutputSurface(bool fallback)
80       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 DrawSwapReadbackResult::DrawResult PrepareToDrawOnThread(
131       LayerTreeHostImpl* host_impl,
132       LayerTreeHostImpl::FrameData* frame,
133       DrawSwapReadbackResult::DrawResult draw_result) OVERRIDE {
134     EXPECT_EQ(DrawSwapReadbackResult::DRAW_SUCCESS, draw_result);
135     if (!times_to_lose_during_draw_)
136       return draw_result;
137
138     --times_to_lose_during_draw_;
139     LoseContext();
140
141     times_to_fail_create_ = times_to_fail_recreate_;
142     times_to_fail_recreate_ = 0;
143     times_to_fail_create_offscreen_ = times_to_fail_recreate_offscreen_;
144     times_to_fail_recreate_offscreen_ = 0;
145
146     return draw_result;
147   }
148
149   virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
150     committed_at_least_once_ = true;
151
152     if (!times_to_lose_during_commit_)
153       return;
154     --times_to_lose_during_commit_;
155     LoseContext();
156
157     times_to_fail_create_ = times_to_fail_recreate_;
158     times_to_fail_recreate_ = 0;
159     times_to_fail_create_offscreen_ = times_to_fail_recreate_offscreen_;
160     times_to_fail_recreate_offscreen_ = 0;
161   }
162
163   virtual void DidFailToInitializeOutputSurface() OVERRIDE {
164     ++times_create_failed_;
165   }
166
167   virtual void TearDown() OVERRIDE {
168     LayerTreeTest::TearDown();
169     EXPECT_EQ(times_to_expect_create_failed_, times_create_failed_);
170   }
171
172   void ExpectCreateToFail() { ++times_to_expect_create_failed_; }
173
174  protected:
175   TestWebGraphicsContext3D* context3d_;
176   int times_to_fail_create_;
177   int times_to_lose_during_commit_;
178   int times_to_lose_during_draw_;
179   int times_to_fail_recreate_;
180   int times_to_fail_create_offscreen_;
181   int times_to_fail_recreate_offscreen_;
182   int times_to_expect_create_failed_;
183   int times_create_failed_;
184   int times_offscreen_created_;
185   bool committed_at_least_once_;
186   bool context_should_support_io_surface_;
187   bool fallback_context_works_;
188
189   scoped_refptr<TestContextProvider> offscreen_contexts_;
190 };
191
192 class LayerTreeHostContextTestLostContextSucceeds
193     : public LayerTreeHostContextTest {
194  public:
195   LayerTreeHostContextTestLostContextSucceeds()
196       : LayerTreeHostContextTest(),
197         test_case_(0),
198         num_losses_(0),
199         num_losses_last_test_case_(-1),
200         recovered_context_(true),
201         first_initialized_(false) {}
202
203   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
204
205   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
206     EXPECT_TRUE(succeeded);
207
208     if (first_initialized_)
209       ++num_losses_;
210     else
211       first_initialized_ = true;
212
213     recovered_context_ = true;
214   }
215
216   virtual void AfterTest() OVERRIDE { EXPECT_EQ(9u, test_case_); }
217
218   virtual void DidCommitAndDrawFrame() OVERRIDE {
219     // If the last frame had a context loss, then we'll commit again to
220     // recover.
221     if (!recovered_context_)
222       return;
223     if (times_to_lose_during_commit_)
224       return;
225     if (times_to_lose_during_draw_)
226       return;
227
228     recovered_context_ = false;
229     if (NextTestCase())
230       InvalidateAndSetNeedsCommit();
231     else
232       EndTest();
233   }
234
235   virtual void InvalidateAndSetNeedsCommit() {
236     // Cause damage so we try to draw.
237     layer_tree_host()->root_layer()->SetNeedsDisplay();
238     layer_tree_host()->SetNeedsCommit();
239   }
240
241   bool NextTestCase() {
242     static const TestCase kTests[] = {
243         // Losing the context and failing to recreate it (or losing it again
244         // immediately) a small number of times should succeed.
245         {1,      // times_to_lose_during_commit
246          0,      // times_to_lose_during_draw
247          0,      // times_to_fail_recreate
248          0,      // times_to_fail_recreate_offscreen
249          false,  // fallback_context_works
250         },
251         {0,      // times_to_lose_during_commit
252          1,      // times_to_lose_during_draw
253          0,      // times_to_fail_recreate
254          0,      // times_to_fail_recreate_offscreen
255          false,  // fallback_context_works
256         },
257         {1,      // times_to_lose_during_commit
258          0,      // times_to_lose_during_draw
259          3,      // times_to_fail_recreate
260          0,      // times_to_fail_recreate_offscreen
261          false,  // fallback_context_works
262         },
263         {0,      // times_to_lose_during_commit
264          1,      // times_to_lose_during_draw
265          3,      // times_to_fail_recreate
266          0,      // times_to_fail_recreate_offscreen
267          false,  // fallback_context_works
268         },
269         {1,      // times_to_lose_during_commit
270          0,      // times_to_lose_during_draw
271          0,      // times_to_fail_recreate
272          3,      // times_to_fail_recreate_offscreen
273          false,  // fallback_context_works
274         },
275         {0,      // times_to_lose_during_commit
276          1,      // times_to_lose_during_draw
277          0,      // times_to_fail_recreate
278          3,      // times_to_fail_recreate_offscreen
279          false,  // fallback_context_works
280         },
281         // Losing the context and recreating it any number of times should
282         // succeed.
283         {10,     // times_to_lose_during_commit
284          0,      // times_to_lose_during_draw
285          0,      // times_to_fail_recreate
286          0,      // times_to_fail_recreate_offscreen
287          false,  // fallback_context_works
288         },
289         {0,      // times_to_lose_during_commit
290          10,     // times_to_lose_during_draw
291          0,      // times_to_fail_recreate
292          0,      // times_to_fail_recreate_offscreen
293          false,  // fallback_context_works
294         },
295         // Losing the context, failing to reinitialize it, and making a fallback
296         // context should work.
297         {0,     // times_to_lose_during_commit
298          1,     // times_to_lose_during_draw
299          0,     // times_to_fail_recreate
300          0,     // times_to_fail_recreate_offscreen
301          true,  // fallback_context_works
302         }, };
303
304     if (test_case_ >= arraysize(kTests))
305       return false;
306     // Make sure that we lost our context at least once in the last test run so
307     // the test did something.
308     EXPECT_GT(num_losses_, num_losses_last_test_case_);
309     num_losses_last_test_case_ = num_losses_;
310
311     times_to_lose_during_commit_ =
312         kTests[test_case_].times_to_lose_during_commit;
313     times_to_lose_during_draw_ = kTests[test_case_].times_to_lose_during_draw;
314     times_to_fail_recreate_ = kTests[test_case_].times_to_fail_recreate;
315     times_to_fail_recreate_offscreen_ =
316         kTests[test_case_].times_to_fail_recreate_offscreen;
317     fallback_context_works_ = kTests[test_case_].fallback_context_works;
318     ++test_case_;
319     return true;
320   }
321
322   struct TestCase {
323     int times_to_lose_during_commit;
324     int times_to_lose_during_draw;
325     int times_to_fail_recreate;
326     int times_to_fail_recreate_offscreen;
327     bool fallback_context_works;
328   };
329
330  protected:
331   size_t test_case_;
332   int num_losses_;
333   int num_losses_last_test_case_;
334   bool recovered_context_;
335   bool first_initialized_;
336 };
337
338 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLostContextSucceeds);
339
340 class LayerTreeHostClientNotReadyDoesNotCreateOutputSurface
341     : public LayerTreeHostContextTest {
342  public:
343   LayerTreeHostClientNotReadyDoesNotCreateOutputSurface()
344       : LayerTreeHostContextTest() {}
345
346   virtual void WillBeginTest() OVERRIDE {
347     // Override and do not signal SetLayerTreeHostClientReady.
348   }
349
350   virtual void BeginTest() OVERRIDE {
351     PostSetNeedsCommitToMainThread();
352     EndTest();
353   }
354
355   virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
356       OVERRIDE {
357     EXPECT_TRUE(false);
358     return scoped_ptr<OutputSurface>();
359   }
360
361   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
362     EXPECT_TRUE(false);
363   }
364
365   virtual void AfterTest() OVERRIDE {
366   }
367 };
368
369 MULTI_THREAD_TEST_F(LayerTreeHostClientNotReadyDoesNotCreateOutputSurface);
370
371 class LayerTreeHostContextTestLostContextSucceedsWithContent
372     : public LayerTreeHostContextTestLostContextSucceeds {
373  public:
374   LayerTreeHostContextTestLostContextSucceedsWithContent()
375       : LayerTreeHostContextTestLostContextSucceeds() {}
376
377   virtual void SetupTree() OVERRIDE {
378     root_ = Layer::Create();
379     root_->SetBounds(gfx::Size(10, 10));
380     root_->SetAnchorPoint(gfx::PointF());
381     root_->SetIsDrawable(true);
382
383     content_ = FakeContentLayer::Create(&client_);
384     content_->SetBounds(gfx::Size(10, 10));
385     content_->SetAnchorPoint(gfx::PointF());
386     content_->SetIsDrawable(true);
387     if (use_surface_) {
388       content_->SetForceRenderSurface(true);
389       // Filters require us to create an offscreen context.
390       FilterOperations filters;
391       filters.Append(FilterOperation::CreateGrayscaleFilter(0.5f));
392       content_->SetFilters(filters);
393       content_->SetBackgroundFilters(filters);
394     }
395
396     root_->AddChild(content_);
397
398     layer_tree_host()->SetRootLayer(root_);
399     LayerTreeHostContextTest::SetupTree();
400   }
401
402   virtual void InvalidateAndSetNeedsCommit() OVERRIDE {
403     // Invalidate the render surface so we don't try to use a cached copy of the
404     // surface.  We want to make sure to test the drawing paths for drawing to
405     // a child surface.
406     content_->SetNeedsDisplay();
407     LayerTreeHostContextTestLostContextSucceeds::InvalidateAndSetNeedsCommit();
408   }
409
410   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
411     FakeContentLayerImpl* content_impl = static_cast<FakeContentLayerImpl*>(
412         host_impl->active_tree()->root_layer()->children()[0]);
413     // Even though the context was lost, we should have a resource. The
414     // TestWebGraphicsContext3D ensures that this resource is created with
415     // the active context.
416     EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0));
417
418     ContextProvider* contexts = host_impl->offscreen_context_provider();
419     if (use_surface_) {
420       ASSERT_TRUE(contexts);
421       EXPECT_TRUE(contexts->ContextGL());
422       // TODO(danakj): Make a fake GrContext.
423       // EXPECT_TRUE(contexts->GrContext());
424     } else {
425       EXPECT_FALSE(contexts);
426     }
427   }
428
429   virtual void AfterTest() OVERRIDE {
430     LayerTreeHostContextTestLostContextSucceeds::AfterTest();
431     if (use_surface_) {
432       // 1 create to start with +
433       // 4 from test cases that lose the offscreen context directly +
434       // 2 from test cases that create a fallback +
435       // All the test cases that recreate both contexts only once
436       // per time it is lost.
437       EXPECT_EQ(4 + 1 + 2 + num_losses_, times_offscreen_created_);
438     } else {
439       EXPECT_EQ(0, times_offscreen_created_);
440     }
441   }
442
443  protected:
444   bool use_surface_;
445   FakeContentLayerClient client_;
446   scoped_refptr<Layer> root_;
447   scoped_refptr<ContentLayer> content_;
448 };
449
450 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
451        NoSurface_SingleThread_DirectRenderer) {
452   use_surface_ = false;
453   RunTest(false, false, false);
454 }
455
456 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
457        NoSurface_SingleThread_DelegatingRenderer) {
458   use_surface_ = false;
459   RunTest(false, true, false);
460 }
461
462 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
463        NoSurface_MultiThread_DirectRenderer_MainThreadPaint) {
464   use_surface_ = false;
465   RunTest(true, false, false);
466 }
467
468 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
469        NoSurface_MultiThread_DelegatingRenderer_MainThreadPaint) {
470   use_surface_ = false;
471   RunTest(true, true, false);
472 }
473
474 // Surfaces don't exist with a delegating renderer.
475 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
476        WithSurface_SingleThread_DirectRenderer) {
477   use_surface_ = true;
478   RunTest(false, false, false);
479 }
480
481 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
482        WithSurface_MultiThread_DirectRenderer_MainThreadPaint) {
483   use_surface_ = true;
484   RunTest(true, false, false);
485 }
486
487 class LayerTreeHostContextTestCreateOutputSurfaceFails
488     : public LayerTreeHostContextTest {
489  public:
490   // Run a test that initially fails OutputSurface creation |times_to_fail|
491   // times. If |expect_fallback_attempt| is |true|, an attempt to create a
492   // fallback/software OutputSurface is expected to occur.
493   LayerTreeHostContextTestCreateOutputSurfaceFails(int times_to_fail,
494                                                    bool expect_fallback_attempt,
495                                                    bool expect_to_give_up)
496       : times_to_fail_(times_to_fail),
497         expect_fallback_attempt_(expect_fallback_attempt),
498         expect_to_give_up_(expect_to_give_up),
499         did_attempt_fallback_(false),
500         times_initialized_(0) {}
501
502   virtual void BeginTest() OVERRIDE {
503     times_to_fail_create_ = times_to_fail_;
504     PostSetNeedsCommitToMainThread();
505   }
506
507   virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
508       OVERRIDE {
509     scoped_ptr<FakeOutputSurface> surface =
510         LayerTreeHostContextTest::CreateFakeOutputSurface(fallback);
511
512     if (surface)
513       EXPECT_EQ(times_to_fail_, times_create_failed_);
514
515     did_attempt_fallback_ = fallback;
516     return surface.Pass();
517   }
518
519   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
520     if (succeeded)
521       times_initialized_++;
522     else
523       EndTest();
524   }
525
526   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
527     EndTest();
528   }
529
530   virtual void AfterTest() OVERRIDE {
531     EXPECT_EQ(times_to_fail_, times_create_failed_);
532     EXPECT_EQ(expect_to_give_up_, times_initialized_ == 0);
533     EXPECT_EQ(expect_fallback_attempt_, did_attempt_fallback_);
534   }
535
536  private:
537   int times_to_fail_;
538   bool expect_fallback_attempt_;
539   bool expect_to_give_up_;
540   bool did_attempt_fallback_;
541   int times_initialized_;
542 };
543
544 class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
545     : public LayerTreeHostContextTestCreateOutputSurfaceFails {
546  public:
547   LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
548       : LayerTreeHostContextTestCreateOutputSurfaceFails(1, false, false) {}
549 };
550
551 SINGLE_AND_MULTI_THREAD_TEST_F(
552     LayerTreeHostContextTestCreateOutputSurfaceFailsOnce);
553
554 // After 4 failures we expect an attempt to create a fallback/software
555 // OutputSurface.
556 class LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback
557     : public LayerTreeHostContextTestCreateOutputSurfaceFails {
558  public:
559   LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback()
560       : LayerTreeHostContextTestCreateOutputSurfaceFails(4, true, false) {}
561 };
562
563 SINGLE_AND_MULTI_THREAD_TEST_F(
564     LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback);
565
566 // If we fail that often, we should be giving up cleanly.
567 class LayerTreeHostContextTestCreateOutputSurfaceIsHopeless
568     : public LayerTreeHostContextTestCreateOutputSurfaceFails {
569  public:
570   LayerTreeHostContextTestCreateOutputSurfaceIsHopeless()
571       : LayerTreeHostContextTestCreateOutputSurfaceFails(5, true, true) {}
572 };
573
574 SINGLE_AND_MULTI_THREAD_TEST_F(
575     LayerTreeHostContextTestCreateOutputSurfaceIsHopeless);
576
577
578 class LayerTreeHostContextTestOffscreenContextFails
579     : public LayerTreeHostContextTest {
580  public:
581   virtual void SetupTree() OVERRIDE {
582     root_ = Layer::Create();
583     root_->SetBounds(gfx::Size(10, 10));
584     root_->SetAnchorPoint(gfx::PointF());
585     root_->SetIsDrawable(true);
586
587     content_ = FakeContentLayer::Create(&client_);
588     content_->SetBounds(gfx::Size(10, 10));
589     content_->SetAnchorPoint(gfx::PointF());
590     content_->SetIsDrawable(true);
591     content_->SetForceRenderSurface(true);
592     // Filters require us to create an offscreen context.
593     FilterOperations filters;
594     filters.Append(FilterOperation::CreateGrayscaleFilter(0.5f));
595     content_->SetFilters(filters);
596     content_->SetBackgroundFilters(filters);
597
598     root_->AddChild(content_);
599
600     layer_tree_host()->SetRootLayer(root_);
601     LayerTreeHostContextTest::SetupTree();
602   }
603
604   virtual void BeginTest() OVERRIDE {
605     times_to_fail_create_offscreen_ = 1;
606     PostSetNeedsCommitToMainThread();
607   }
608
609   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
610     ContextProvider* contexts = host_impl->offscreen_context_provider();
611     EXPECT_FALSE(contexts);
612
613     // This did not lead to create failure.
614     times_to_expect_create_failed_ = 0;
615     EndTest();
616   }
617
618   virtual void AfterTest() OVERRIDE {}
619
620  protected:
621   FakeContentLayerClient client_;
622   scoped_refptr<Layer> root_;
623   scoped_refptr<ContentLayer> content_;
624 };
625
626 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestOffscreenContextFails);
627
628 class LayerTreeHostContextTestLostContextFails
629     : public LayerTreeHostContextTest {
630  public:
631   LayerTreeHostContextTestLostContextFails()
632       : LayerTreeHostContextTest(), num_commits_(0), first_initialized_(false) {
633     times_to_lose_during_commit_ = 1;
634   }
635
636   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
637
638   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
639     if (first_initialized_) {
640       EXPECT_FALSE(succeeded);
641       EndTest();
642     } else {
643       first_initialized_ = true;
644     }
645   }
646
647   virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
648     LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
649
650     ++num_commits_;
651     if (num_commits_ == 1) {
652       // When the context is ok, we should have these things.
653       EXPECT_TRUE(host_impl->output_surface());
654       EXPECT_TRUE(host_impl->renderer());
655       EXPECT_TRUE(host_impl->resource_provider());
656       return;
657     }
658
659     // When context recreation fails we shouldn't be left with any of them.
660     EXPECT_FALSE(host_impl->output_surface());
661     EXPECT_FALSE(host_impl->renderer());
662     EXPECT_FALSE(host_impl->resource_provider());
663   }
664
665   virtual void AfterTest() OVERRIDE {}
666
667  private:
668   int num_commits_;
669   bool first_initialized_;
670 };
671
672 class LayerTreeHostContextTestLostContextAndEvictTextures
673     : public LayerTreeHostContextTest {
674  public:
675   LayerTreeHostContextTestLostContextAndEvictTextures()
676       : LayerTreeHostContextTest(),
677         layer_(FakeContentLayer::Create(&client_)),
678         impl_host_(0),
679         num_commits_(0) {}
680
681   virtual void SetupTree() OVERRIDE {
682     layer_->SetBounds(gfx::Size(10, 20));
683     layer_tree_host()->SetRootLayer(layer_);
684     LayerTreeHostContextTest::SetupTree();
685   }
686
687   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
688
689   void PostEvictTextures() {
690     if (HasImplThread()) {
691       ImplThreadTaskRunner()->PostTask(
692           FROM_HERE,
693           base::Bind(&LayerTreeHostContextTestLostContextAndEvictTextures::
694                           EvictTexturesOnImplThread,
695                      base::Unretained(this)));
696     } else {
697       DebugScopedSetImplThread impl(proxy());
698       EvictTexturesOnImplThread();
699     }
700   }
701
702   void EvictTexturesOnImplThread() {
703     impl_host_->EvictTexturesForTesting();
704     if (lose_after_evict_)
705       LoseContext();
706   }
707
708   virtual void DidCommitAndDrawFrame() OVERRIDE {
709     if (num_commits_ > 1)
710       return;
711     EXPECT_TRUE(layer_->HaveBackingAt(0, 0));
712     PostEvictTextures();
713   }
714
715   virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
716     LayerTreeHostContextTest::CommitCompleteOnThread(impl);
717     if (num_commits_ > 1)
718       return;
719     ++num_commits_;
720     if (!lose_after_evict_)
721       LoseContext();
722     impl_host_ = impl;
723   }
724
725   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
726     EXPECT_TRUE(succeeded);
727     EndTest();
728   }
729
730   virtual void AfterTest() OVERRIDE {}
731
732  protected:
733   bool lose_after_evict_;
734   FakeContentLayerClient client_;
735   scoped_refptr<FakeContentLayer> layer_;
736   LayerTreeHostImpl* impl_host_;
737   int num_commits_;
738 };
739
740 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
741        LoseAfterEvict_SingleThread_DirectRenderer) {
742   lose_after_evict_ = true;
743   RunTest(false, false, false);
744 }
745
746 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
747        LoseAfterEvict_SingleThread_DelegatingRenderer) {
748   lose_after_evict_ = true;
749   RunTest(false, true, false);
750 }
751
752 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
753        LoseAfterEvict_MultiThread_DirectRenderer_MainThreadPaint) {
754   lose_after_evict_ = true;
755   RunTest(true, false, false);
756 }
757
758 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
759        LoseAfterEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
760   lose_after_evict_ = true;
761   RunTest(true, true, false);
762 }
763
764 // Flaky on all platforms, http://crbug.com/310979
765 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
766        DISABLED_LoseAfterEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
767   lose_after_evict_ = true;
768   RunTest(true, true, true);
769 }
770
771 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
772        LoseBeforeEvict_SingleThread_DirectRenderer) {
773   lose_after_evict_ = false;
774   RunTest(false, false, false);
775 }
776
777 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
778        LoseBeforeEvict_SingleThread_DelegatingRenderer) {
779   lose_after_evict_ = false;
780   RunTest(false, true, false);
781 }
782
783 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
784        LoseBeforeEvict_MultiThread_DirectRenderer_MainThreadPaint) {
785   lose_after_evict_ = false;
786   RunTest(true, false, false);
787 }
788
789 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
790        LoseBeforeEvict_MultiThread_DirectRenderer_ImplSidePaint) {
791   lose_after_evict_ = false;
792   RunTest(true, false, true);
793 }
794
795 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
796        LoseBeforeEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
797   lose_after_evict_ = false;
798   RunTest(true, true, false);
799 }
800
801 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
802        LoseBeforeEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
803   lose_after_evict_ = false;
804   RunTest(true, true, true);
805 }
806
807 class LayerTreeHostContextTestLostContextWhileUpdatingResources
808     : public LayerTreeHostContextTest {
809  public:
810   LayerTreeHostContextTestLostContextWhileUpdatingResources()
811       : parent_(FakeContentLayer::Create(&client_)),
812         num_children_(50),
813         times_to_lose_on_end_query_(3) {}
814
815   virtual scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() OVERRIDE {
816     scoped_ptr<TestWebGraphicsContext3D> context =
817         LayerTreeHostContextTest::CreateContext3d();
818     if (times_to_lose_on_end_query_) {
819       --times_to_lose_on_end_query_;
820       context->set_times_end_query_succeeds(5);
821     }
822     return context.Pass();
823   }
824
825   virtual void SetupTree() OVERRIDE {
826     parent_->SetBounds(gfx::Size(num_children_, 1));
827
828     for (int i = 0; i < num_children_; i++) {
829       scoped_refptr<FakeContentLayer> child =
830           FakeContentLayer::Create(&client_);
831       child->SetPosition(gfx::PointF(i, 0.f));
832       child->SetBounds(gfx::Size(1, 1));
833       parent_->AddChild(child);
834     }
835
836     layer_tree_host()->SetRootLayer(parent_);
837     LayerTreeHostContextTest::SetupTree();
838   }
839
840   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
841
842   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
843     EXPECT_EQ(0, times_to_lose_on_end_query_);
844     EndTest();
845   }
846
847   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
848     EXPECT_TRUE(succeeded);
849   }
850
851   virtual void AfterTest() OVERRIDE {
852     EXPECT_EQ(0, times_to_lose_on_end_query_);
853   }
854
855  private:
856   FakeContentLayerClient client_;
857   scoped_refptr<FakeContentLayer> parent_;
858   int num_children_;
859   int times_to_lose_on_end_query_;
860 };
861
862 SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
863     LayerTreeHostContextTestLostContextWhileUpdatingResources);
864
865 class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
866  public:
867   LayerTreeHostContextTestLayersNotified()
868       : LayerTreeHostContextTest(), num_commits_(0) {}
869
870   virtual void SetupTree() OVERRIDE {
871     root_ = FakeContentLayer::Create(&client_);
872     child_ = FakeContentLayer::Create(&client_);
873     grandchild_ = FakeContentLayer::Create(&client_);
874
875     root_->AddChild(child_);
876     child_->AddChild(grandchild_);
877
878     layer_tree_host()->SetRootLayer(root_);
879     LayerTreeHostContextTest::SetupTree();
880   }
881
882   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
883
884   virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
885     LayerTreeHostContextTest::DidActivateTreeOnThread(host_impl);
886
887     FakeContentLayerImpl* root = static_cast<FakeContentLayerImpl*>(
888         host_impl->active_tree()->root_layer());
889     FakeContentLayerImpl* child =
890         static_cast<FakeContentLayerImpl*>(root->children()[0]);
891     FakeContentLayerImpl* grandchild =
892         static_cast<FakeContentLayerImpl*>(child->children()[0]);
893
894     ++num_commits_;
895     switch (num_commits_) {
896       case 1:
897         EXPECT_EQ(0u, root->lost_output_surface_count());
898         EXPECT_EQ(0u, child->lost_output_surface_count());
899         EXPECT_EQ(0u, grandchild->lost_output_surface_count());
900         // Lose the context and struggle to recreate it.
901         LoseContext();
902         times_to_fail_create_ = 1;
903         break;
904       case 2:
905         EXPECT_GE(1u, root->lost_output_surface_count());
906         EXPECT_GE(1u, child->lost_output_surface_count());
907         EXPECT_GE(1u, grandchild->lost_output_surface_count());
908         EndTest();
909         break;
910       default:
911         NOTREACHED();
912     }
913   }
914
915   virtual void AfterTest() OVERRIDE {}
916
917  private:
918   int num_commits_;
919
920   FakeContentLayerClient client_;
921   scoped_refptr<FakeContentLayer> root_;
922   scoped_refptr<FakeContentLayer> child_;
923   scoped_refptr<FakeContentLayer> grandchild_;
924 };
925
926 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified);
927
928 class LayerTreeHostContextTestDontUseLostResources
929     : public LayerTreeHostContextTest {
930  public:
931   LayerTreeHostContextTestDontUseLostResources() : lost_context_(false) {
932     context_should_support_io_surface_ = true;
933
934     child_output_surface_ = FakeOutputSurface::Create3d();
935     child_output_surface_->BindToClient(&output_surface_client_);
936     child_resource_provider_ = ResourceProvider::Create(
937         child_output_surface_.get(), NULL, 0, false, 1);
938   }
939
940   static void EmptyReleaseCallback(unsigned sync_point, bool lost) {}
941
942   virtual void SetupTree() OVERRIDE {
943     gpu::gles2::GLES2Interface* gl =
944         child_output_surface_->context_provider()->ContextGL();
945
946     scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
947
948     scoped_ptr<TestRenderPass> pass_for_quad = TestRenderPass::Create();
949     pass_for_quad->SetNew(
950         // AppendOneOfEveryQuadType() makes a RenderPass quad with this id.
951         RenderPass::Id(2, 1),
952         gfx::Rect(0, 0, 10, 10),
953         gfx::Rect(0, 0, 10, 10),
954         gfx::Transform());
955
956     scoped_ptr<TestRenderPass> pass = TestRenderPass::Create();
957     pass->SetNew(RenderPass::Id(1, 1),
958                  gfx::Rect(0, 0, 10, 10),
959                  gfx::Rect(0, 0, 10, 10),
960                  gfx::Transform());
961     pass->AppendOneOfEveryQuadType(child_resource_provider_.get(),
962                                    RenderPass::Id(2, 1));
963
964     frame_data->render_pass_list.push_back(pass_for_quad.PassAs<RenderPass>());
965     frame_data->render_pass_list.push_back(pass.PassAs<RenderPass>());
966
967     delegated_resource_collection_ = new DelegatedFrameResourceCollection;
968     delegated_frame_provider_ = new DelegatedFrameProvider(
969         delegated_resource_collection_.get(), frame_data.Pass());
970
971     ResourceProvider::ResourceId resource =
972         child_resource_provider_->CreateResource(
973             gfx::Size(4, 4),
974             GL_CLAMP_TO_EDGE,
975             ResourceProvider::TextureUsageAny,
976             RGBA_8888);
977     ResourceProvider::ScopedWriteLockGL lock(child_resource_provider_.get(),
978                                              resource);
979
980     gpu::Mailbox mailbox;
981     gl->GenMailboxCHROMIUM(mailbox.name);
982     GLuint sync_point = gl->InsertSyncPointCHROMIUM();
983
984     scoped_refptr<Layer> root = Layer::Create();
985     root->SetBounds(gfx::Size(10, 10));
986     root->SetAnchorPoint(gfx::PointF());
987     root->SetIsDrawable(true);
988
989     scoped_refptr<FakeDelegatedRendererLayer> delegated =
990         FakeDelegatedRendererLayer::Create(delegated_frame_provider_.get());
991     delegated->SetBounds(gfx::Size(10, 10));
992     delegated->SetAnchorPoint(gfx::PointF());
993     delegated->SetIsDrawable(true);
994     root->AddChild(delegated);
995
996     scoped_refptr<ContentLayer> content = ContentLayer::Create(&client_);
997     content->SetBounds(gfx::Size(10, 10));
998     content->SetAnchorPoint(gfx::PointF());
999     content->SetIsDrawable(true);
1000     root->AddChild(content);
1001
1002     scoped_refptr<TextureLayer> texture = TextureLayer::CreateForMailbox(NULL);
1003     texture->SetBounds(gfx::Size(10, 10));
1004     texture->SetAnchorPoint(gfx::PointF());
1005     texture->SetIsDrawable(true);
1006     texture->SetTextureMailbox(
1007         TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point),
1008         SingleReleaseCallback::Create(
1009             base::Bind(&LayerTreeHostContextTestDontUseLostResources::
1010                             EmptyReleaseCallback)));
1011     root->AddChild(texture);
1012
1013     scoped_refptr<ContentLayer> mask = ContentLayer::Create(&client_);
1014     mask->SetBounds(gfx::Size(10, 10));
1015     mask->SetAnchorPoint(gfx::PointF());
1016
1017     scoped_refptr<ContentLayer> content_with_mask =
1018         ContentLayer::Create(&client_);
1019     content_with_mask->SetBounds(gfx::Size(10, 10));
1020     content_with_mask->SetAnchorPoint(gfx::PointF());
1021     content_with_mask->SetIsDrawable(true);
1022     content_with_mask->SetMaskLayer(mask.get());
1023     root->AddChild(content_with_mask);
1024
1025     scoped_refptr<VideoLayer> video_color =
1026         VideoLayer::Create(&color_frame_provider_);
1027     video_color->SetBounds(gfx::Size(10, 10));
1028     video_color->SetAnchorPoint(gfx::PointF());
1029     video_color->SetIsDrawable(true);
1030     root->AddChild(video_color);
1031
1032     scoped_refptr<VideoLayer> video_hw =
1033         VideoLayer::Create(&hw_frame_provider_);
1034     video_hw->SetBounds(gfx::Size(10, 10));
1035     video_hw->SetAnchorPoint(gfx::PointF());
1036     video_hw->SetIsDrawable(true);
1037     root->AddChild(video_hw);
1038
1039     scoped_refptr<VideoLayer> video_scaled_hw =
1040         VideoLayer::Create(&scaled_hw_frame_provider_);
1041     video_scaled_hw->SetBounds(gfx::Size(10, 10));
1042     video_scaled_hw->SetAnchorPoint(gfx::PointF());
1043     video_scaled_hw->SetIsDrawable(true);
1044     root->AddChild(video_scaled_hw);
1045
1046     color_video_frame_ = VideoFrame::CreateColorFrame(
1047         gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
1048     hw_video_frame_ =
1049         VideoFrame::WrapNativeTexture(make_scoped_ptr(new gpu::MailboxHolder(
1050                                           mailbox, GL_TEXTURE_2D, sync_point)),
1051                                       media::VideoFrame::ReleaseMailboxCB(),
1052                                       gfx::Size(4, 4),
1053                                       gfx::Rect(0, 0, 4, 4),
1054                                       gfx::Size(4, 4),
1055                                       base::TimeDelta(),
1056                                       VideoFrame::ReadPixelsCB());
1057     scaled_hw_video_frame_ =
1058         VideoFrame::WrapNativeTexture(make_scoped_ptr(new gpu::MailboxHolder(
1059                                           mailbox, GL_TEXTURE_2D, sync_point)),
1060                                       media::VideoFrame::ReleaseMailboxCB(),
1061                                       gfx::Size(4, 4),
1062                                       gfx::Rect(0, 0, 3, 2),
1063                                       gfx::Size(4, 4),
1064                                       base::TimeDelta(),
1065                                       VideoFrame::ReadPixelsCB());
1066
1067     color_frame_provider_.set_frame(color_video_frame_);
1068     hw_frame_provider_.set_frame(hw_video_frame_);
1069     scaled_hw_frame_provider_.set_frame(scaled_hw_video_frame_);
1070
1071     if (!delegating_renderer()) {
1072       // TODO(danakj): IOSurface layer can not be transported. crbug.com/239335
1073       scoped_refptr<IOSurfaceLayer> io_surface = IOSurfaceLayer::Create();
1074       io_surface->SetBounds(gfx::Size(10, 10));
1075       io_surface->SetAnchorPoint(gfx::PointF());
1076       io_surface->SetIsDrawable(true);
1077       io_surface->SetIOSurfaceProperties(1, gfx::Size(10, 10));
1078       root->AddChild(io_surface);
1079     }
1080
1081     // Enable the hud.
1082     LayerTreeDebugState debug_state;
1083     debug_state.show_property_changed_rects = true;
1084     layer_tree_host()->SetDebugState(debug_state);
1085
1086     scoped_refptr<PaintedScrollbarLayer> scrollbar =
1087         PaintedScrollbarLayer::Create(
1088             scoped_ptr<Scrollbar>(new FakeScrollbar).Pass(), content->id());
1089     scrollbar->SetBounds(gfx::Size(10, 10));
1090     scrollbar->SetAnchorPoint(gfx::PointF());
1091     scrollbar->SetIsDrawable(true);
1092     root->AddChild(scrollbar);
1093
1094     layer_tree_host()->SetRootLayer(root);
1095     LayerTreeHostContextTest::SetupTree();
1096   }
1097
1098   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
1099
1100   virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
1101     LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
1102
1103     if (host_impl->active_tree()->source_frame_number() == 3) {
1104       // On the third commit we're recovering from context loss. Hardware
1105       // video frames should not be reused by the VideoFrameProvider, but
1106       // software frames can be.
1107       hw_frame_provider_.set_frame(NULL);
1108       scaled_hw_frame_provider_.set_frame(NULL);
1109     }
1110   }
1111
1112   virtual DrawSwapReadbackResult::DrawResult PrepareToDrawOnThread(
1113       LayerTreeHostImpl* host_impl,
1114       LayerTreeHostImpl::FrameData* frame,
1115       DrawSwapReadbackResult::DrawResult draw_result) OVERRIDE {
1116     if (host_impl->active_tree()->source_frame_number() == 2) {
1117       // Lose the context during draw on the second commit. This will cause
1118       // a third commit to recover.
1119       context3d_->set_times_bind_texture_succeeds(0);
1120     }
1121     return draw_result;
1122   }
1123
1124   virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
1125       OVERRIDE {
1126     // This will get called twice:
1127     // First when we create the initial output surface...
1128     if (layer_tree_host()->source_frame_number() > 0) {
1129       // ... and then again after we forced the context to be lost on the third
1130       // frame. Verify this assumption here.
1131       lost_context_ = true;
1132       EXPECT_EQ(layer_tree_host()->source_frame_number(), 3);
1133     }
1134     return LayerTreeHostContextTest::CreateFakeOutputSurface(fallback);
1135   }
1136
1137   virtual void DidCommitAndDrawFrame() OVERRIDE {
1138     ASSERT_TRUE(layer_tree_host()->hud_layer());
1139     // End the test once we know the 3nd frame drew.
1140     if (layer_tree_host()->source_frame_number() < 4) {
1141       layer_tree_host()->root_layer()->SetNeedsDisplay();
1142       layer_tree_host()->SetNeedsCommit();
1143     } else {
1144       EndTest();
1145     }
1146   }
1147
1148   virtual void AfterTest() OVERRIDE { EXPECT_TRUE(lost_context_); }
1149
1150  private:
1151   FakeContentLayerClient client_;
1152   bool lost_context_;
1153
1154   FakeOutputSurfaceClient output_surface_client_;
1155   scoped_ptr<FakeOutputSurface> child_output_surface_;
1156   scoped_ptr<ResourceProvider> child_resource_provider_;
1157
1158   scoped_refptr<DelegatedFrameResourceCollection>
1159       delegated_resource_collection_;
1160   scoped_refptr<DelegatedFrameProvider> delegated_frame_provider_;
1161
1162   scoped_refptr<VideoFrame> color_video_frame_;
1163   scoped_refptr<VideoFrame> hw_video_frame_;
1164   scoped_refptr<VideoFrame> scaled_hw_video_frame_;
1165
1166   FakeVideoFrameProvider color_frame_provider_;
1167   FakeVideoFrameProvider hw_frame_provider_;
1168   FakeVideoFrameProvider scaled_hw_frame_provider_;
1169 };
1170
1171 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources);
1172
1173 class LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit
1174     : public LayerTreeHostContextTest {
1175  public:
1176   virtual void BeginTest() OVERRIDE {
1177     // This must be called immediately after creating LTH, before the first
1178     // OutputSurface is initialized.
1179     ASSERT_TRUE(layer_tree_host()->output_surface_lost());
1180
1181     times_output_surface_created_ = 0;
1182
1183     // Post the SetNeedsCommit before the readback to make sure it is run
1184     // on the main thread before the readback's replacement commit when
1185     // we have a threaded compositor.
1186     PostSetNeedsCommitToMainThread();
1187
1188     char pixels[4];
1189     bool result =
1190         layer_tree_host()->CompositeAndReadback(&pixels, gfx::Rect(1, 1));
1191     EXPECT_EQ(!delegating_renderer(), result);
1192     EXPECT_EQ(1, times_output_surface_created_);
1193   }
1194
1195   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
1196     EXPECT_TRUE(succeeded);
1197     ++times_output_surface_created_;
1198   }
1199
1200   virtual void DidCommitAndDrawFrame() OVERRIDE { EndTest(); }
1201
1202   virtual void AfterTest() OVERRIDE {
1203     // Should not try to create output surface again after successfully
1204     // created by CompositeAndReadback.
1205     EXPECT_EQ(1, times_output_surface_created_);
1206   }
1207
1208   virtual DrawSwapReadbackResult::DrawResult PrepareToDrawOnThread(
1209       LayerTreeHostImpl* host_impl,
1210       LayerTreeHostImpl::FrameData* frame_data,
1211       DrawSwapReadbackResult::DrawResult draw_result) OVERRIDE {
1212     EXPECT_GE(host_impl->active_tree()->source_frame_number(), 0);
1213     EXPECT_LE(host_impl->active_tree()->source_frame_number(), 1);
1214     return draw_result;
1215   }
1216
1217   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
1218     // We should only draw for the readback and the replacement commit.
1219     // The replacement commit will also be the first commit after output
1220     // surface initialization.
1221     EXPECT_GE(host_impl->active_tree()->source_frame_number(), 0);
1222     EXPECT_LE(host_impl->active_tree()->source_frame_number(), 1);
1223   }
1224
1225   virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
1226                                    bool result) OVERRIDE {
1227     // We should only swap for the replacement commit.
1228     EXPECT_EQ(host_impl->active_tree()->source_frame_number(), 1);
1229     EndTest();
1230   }
1231
1232  private:
1233   int times_output_surface_created_;
1234 };
1235
1236 SINGLE_AND_MULTI_THREAD_TEST_F(
1237     LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit);
1238
1239 // This test verifies that losing an output surface during a
1240 // simultaneous readback and forced redraw works and does not deadlock.
1241 class LayerTreeHostContextTestLoseOutputSurfaceDuringReadbackAndForcedDraw
1242     : public LayerTreeHostContextTest {
1243  protected:
1244   static const int kFirstOutputSurfaceInitSourceFrameNumber = 0;
1245   static const int kReadbackSourceFrameNumber = 1;
1246   static const int kReadbackReplacementSourceFrameNumber = 2;
1247   static const int kSecondOutputSurfaceInitSourceFrameNumber = 3;
1248
1249   LayerTreeHostContextTestLoseOutputSurfaceDuringReadbackAndForcedDraw()
1250       : did_react_to_first_commit_(false) {}
1251
1252   virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
1253     // This enables forced draws after a single prepare to draw failure.
1254     settings->timeout_and_draw_when_animation_checkerboards = true;
1255     settings->maximum_number_of_failed_draws_before_draw_is_forced_ = 1;
1256   }
1257
1258   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
1259
1260   virtual DrawSwapReadbackResult::DrawResult PrepareToDrawOnThread(
1261       LayerTreeHostImpl* host_impl,
1262       LayerTreeHostImpl::FrameData* frame_data,
1263       DrawSwapReadbackResult::DrawResult draw_result) OVERRIDE {
1264     int sfn = host_impl->active_tree()->source_frame_number();
1265     EXPECT_TRUE(sfn == kFirstOutputSurfaceInitSourceFrameNumber ||
1266                 sfn == kSecondOutputSurfaceInitSourceFrameNumber ||
1267                 sfn == kReadbackSourceFrameNumber)
1268         << sfn;
1269
1270     // Before we react to the failed draw by initiating the forced draw
1271     // sequence, start a readback on the main thread and then lose the context
1272     // to start output surface initialization all at the same time.
1273     if (sfn == kFirstOutputSurfaceInitSourceFrameNumber &&
1274         !did_react_to_first_commit_) {
1275       did_react_to_first_commit_ = true;
1276       PostReadbackToMainThread();
1277       LoseContext();
1278     }
1279
1280     return DrawSwapReadbackResult::DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
1281   }
1282
1283   virtual void InitializedRendererOnThread(LayerTreeHostImpl* host_impl,
1284                                            bool success) OVERRIDE {
1285     // -1 is for the first output surface initialization.
1286     int sfn = host_impl->active_tree()->source_frame_number();
1287     EXPECT_TRUE(sfn == -1 || sfn == kReadbackReplacementSourceFrameNumber)
1288         << sfn;
1289   }
1290
1291   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
1292     // We should only draw the first commit after output surface initialization
1293     // and attempt to draw the readback commit (which will fail).
1294     // All others should abort because the output surface is lost.
1295     int sfn = host_impl->active_tree()->source_frame_number();
1296     EXPECT_TRUE(sfn == kSecondOutputSurfaceInitSourceFrameNumber ||
1297                 sfn == kReadbackSourceFrameNumber)
1298         << sfn;
1299   }
1300
1301   virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
1302                                    bool result) OVERRIDE {
1303     // We should only swap the first commit after the second output surface
1304     // initialization.
1305     int sfn = host_impl->active_tree()->source_frame_number();
1306     EXPECT_TRUE(sfn == kSecondOutputSurfaceInitSourceFrameNumber) << sfn;
1307     EndTest();
1308   }
1309
1310   virtual void AfterTest() OVERRIDE {}
1311
1312   int did_react_to_first_commit_;
1313 };
1314
1315 MULTI_THREAD_TEST_F(
1316     LayerTreeHostContextTestLoseOutputSurfaceDuringReadbackAndForcedDraw);
1317
1318 // This test verifies that losing an output surface right before a
1319 // simultaneous readback and forced redraw works and does not deadlock.
1320 class LayerTreeHostContextTestReadbackWithForcedDrawAndOutputSurfaceInit
1321     : public LayerTreeHostContextTest {
1322  protected:
1323   static const int kFirstOutputSurfaceInitSourceFrameNumber = 0;
1324   static const int kReadbackSourceFrameNumber = 1;
1325   static const int kForcedDrawCommitSourceFrameNumber = 2;
1326   static const int kSecondOutputSurfaceInitSourceFrameNumber = 2;
1327
1328   LayerTreeHostContextTestReadbackWithForcedDrawAndOutputSurfaceInit()
1329       : did_lose_context_(false) {}
1330
1331   virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
1332     // This enables forced draws after a single prepare to draw failure.
1333     settings->timeout_and_draw_when_animation_checkerboards = true;
1334     settings->maximum_number_of_failed_draws_before_draw_is_forced_ = 1;
1335   }
1336
1337   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
1338
1339   virtual DrawSwapReadbackResult::DrawResult PrepareToDrawOnThread(
1340       LayerTreeHostImpl* host_impl,
1341       LayerTreeHostImpl::FrameData* frame_data,
1342       DrawSwapReadbackResult::DrawResult draw_result) OVERRIDE {
1343     int sfn = host_impl->active_tree()->source_frame_number();
1344     EXPECT_TRUE(sfn == kFirstOutputSurfaceInitSourceFrameNumber ||
1345                 sfn == kSecondOutputSurfaceInitSourceFrameNumber ||
1346                 sfn == kReadbackSourceFrameNumber)
1347         << sfn;
1348
1349     // Before we react to the failed draw by initiating the forced draw
1350     // sequence, start a readback on the main thread and then lose the context
1351     // to start output surface initialization all at the same time.
1352     if (sfn == kFirstOutputSurfaceInitSourceFrameNumber && !did_lose_context_) {
1353       did_lose_context_ = true;
1354       LoseContext();
1355     }
1356
1357     // Returning false will result in a forced draw.
1358     return DrawSwapReadbackResult::DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
1359   }
1360
1361   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
1362     EXPECT_TRUE(succeeded);
1363     if (layer_tree_host()->source_frame_number() > 0) {
1364       // Perform a readback right after the second output surface
1365       // initialization.
1366       char pixels[4];
1367       layer_tree_host()->CompositeAndReadback(&pixels, gfx::Rect(0, 0, 1, 1));
1368     }
1369   }
1370
1371   virtual void InitializedRendererOnThread(LayerTreeHostImpl* host_impl,
1372                                            bool success) OVERRIDE {
1373     // -1 is for the first output surface initialization.
1374     int sfn = host_impl->active_tree()->source_frame_number();
1375     EXPECT_TRUE(sfn == -1 || sfn == kFirstOutputSurfaceInitSourceFrameNumber)
1376         << sfn;
1377   }
1378
1379   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
1380     // We should only draw the first commit after output surface initialization
1381     // and attempt to draw the readback commit (which will fail).
1382     // All others should abort because the output surface is lost.
1383     int sfn = host_impl->active_tree()->source_frame_number();
1384     EXPECT_TRUE(sfn == kForcedDrawCommitSourceFrameNumber ||
1385                 sfn == kReadbackSourceFrameNumber)
1386         << sfn;
1387   }
1388
1389   virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
1390                                    bool result) OVERRIDE {
1391     // We should only swap the first commit after the second output surface
1392     // initialization.
1393     int sfn = host_impl->active_tree()->source_frame_number();
1394     EXPECT_TRUE(sfn == kForcedDrawCommitSourceFrameNumber) << sfn;
1395     EndTest();
1396   }
1397
1398   virtual void AfterTest() OVERRIDE {}
1399
1400   int did_lose_context_;
1401 };
1402
1403 MULTI_THREAD_TEST_F(
1404     LayerTreeHostContextTestReadbackWithForcedDrawAndOutputSurfaceInit);
1405
1406 class ImplSidePaintingLayerTreeHostContextTest
1407     : public LayerTreeHostContextTest {
1408  public:
1409   virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
1410     settings->impl_side_painting = true;
1411   }
1412 };
1413
1414 class LayerTreeHostContextTestImplSidePainting
1415     : public ImplSidePaintingLayerTreeHostContextTest {
1416  public:
1417   virtual void SetupTree() OVERRIDE {
1418     scoped_refptr<Layer> root = Layer::Create();
1419     root->SetBounds(gfx::Size(10, 10));
1420     root->SetAnchorPoint(gfx::PointF());
1421     root->SetIsDrawable(true);
1422
1423     scoped_refptr<PictureLayer> picture = PictureLayer::Create(&client_);
1424     picture->SetBounds(gfx::Size(10, 10));
1425     picture->SetAnchorPoint(gfx::PointF());
1426     picture->SetIsDrawable(true);
1427     root->AddChild(picture);
1428
1429     layer_tree_host()->SetRootLayer(root);
1430     LayerTreeHostContextTest::SetupTree();
1431   }
1432
1433   virtual void BeginTest() OVERRIDE {
1434     times_to_lose_during_commit_ = 1;
1435     PostSetNeedsCommitToMainThread();
1436   }
1437
1438   virtual void AfterTest() OVERRIDE {}
1439
1440   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
1441     EXPECT_TRUE(succeeded);
1442     EndTest();
1443   }
1444
1445  private:
1446   FakeContentLayerClient client_;
1447 };
1448
1449 MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting);
1450
1451 class ScrollbarLayerLostContext : public LayerTreeHostContextTest {
1452  public:
1453   ScrollbarLayerLostContext() : commits_(0) {}
1454
1455   virtual void BeginTest() OVERRIDE {
1456     scoped_refptr<Layer> scroll_layer = Layer::Create();
1457     scrollbar_layer_ =
1458         FakePaintedScrollbarLayer::Create(false, true, scroll_layer->id());
1459     scrollbar_layer_->SetBounds(gfx::Size(10, 100));
1460     layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
1461     layer_tree_host()->root_layer()->AddChild(scroll_layer);
1462     PostSetNeedsCommitToMainThread();
1463   }
1464
1465   virtual void AfterTest() OVERRIDE {}
1466
1467   virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1468     LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1469
1470     ++commits_;
1471     switch (commits_) {
1472       case 1:
1473         // First (regular) update, we should upload 2 resources (thumb, and
1474         // backtrack).
1475         EXPECT_EQ(1, scrollbar_layer_->update_count());
1476         LoseContext();
1477         break;
1478       case 2:
1479         // Second update, after the lost context, we should still upload 2
1480         // resources even if the contents haven't changed.
1481         EXPECT_EQ(2, scrollbar_layer_->update_count());
1482         EndTest();
1483         break;
1484       case 3:
1485         // Single thread proxy issues extra commits after context lost.
1486         // http://crbug.com/287250
1487         if (HasImplThread())
1488           NOTREACHED();
1489         break;
1490       default:
1491         NOTREACHED();
1492     }
1493   }
1494
1495  private:
1496   int commits_;
1497   scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer_;
1498 };
1499
1500 SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext);
1501
1502 class UIResourceLostTest : public LayerTreeHostContextTest {
1503  public:
1504   UIResourceLostTest() : time_step_(0) {}
1505   virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
1506     settings->texture_id_allocation_chunk_size = 1;
1507   }
1508   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
1509   virtual void AfterTest() OVERRIDE {}
1510
1511   // This is called on the main thread after each commit and
1512   // DidActivateTreeOnThread, with the value of time_step_ at the time
1513   // of the call to DidActivateTreeOnThread. Similar tests will do
1514   // work on the main thread in DidCommit but that is unsuitable because
1515   // the main thread work for these tests must happen after
1516   // DidActivateTreeOnThread, which happens after DidCommit with impl-side
1517   // painting.
1518   virtual void StepCompleteOnMainThread(int time_step) = 0;
1519
1520   // Called after DidActivateTreeOnThread. If this is done during the commit,
1521   // the call to StepCompleteOnMainThread will not occur until after
1522   // the commit completes, because the main thread is blocked.
1523   void PostStepCompleteToMainThread() {
1524     proxy()->MainThreadTaskRunner()->PostTask(
1525         FROM_HERE,
1526         base::Bind(&UIResourceLostTest::StepCompleteOnMainThreadInternal,
1527                    base::Unretained(this),
1528                    time_step_));
1529   }
1530
1531   void PostLoseContextToImplThread() {
1532     EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1533     base::SingleThreadTaskRunner* task_runner =
1534         HasImplThread() ? ImplThreadTaskRunner()
1535                         : base::MessageLoopProxy::current();
1536     task_runner->PostTask(FROM_HERE,
1537                           base::Bind(&LayerTreeHostContextTest::LoseContext,
1538                                      base::Unretained(this)));
1539   }
1540
1541  protected:
1542   int time_step_;
1543   scoped_ptr<FakeScopedUIResource> ui_resource_;
1544
1545  private:
1546   void StepCompleteOnMainThreadInternal(int step) {
1547     EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1548     StepCompleteOnMainThread(step);
1549   }
1550 };
1551
1552 class UIResourceLostTestSimple : public UIResourceLostTest {
1553  public:
1554   // This is called when the commit is complete and the new layer tree has been
1555   // activated.
1556   virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) = 0;
1557
1558   virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1559     if (!layer_tree_host()->settings().impl_side_painting) {
1560       StepCompleteOnImplThread(impl);
1561       PostStepCompleteToMainThread();
1562       ++time_step_;
1563     }
1564   }
1565
1566   virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1567     if (layer_tree_host()->settings().impl_side_painting) {
1568       StepCompleteOnImplThread(impl);
1569       PostStepCompleteToMainThread();
1570       ++time_step_;
1571     }
1572   }
1573 };
1574
1575 // Losing context after an UI resource has been created.
1576 class UIResourceLostAfterCommit : public UIResourceLostTestSimple {
1577  public:
1578   virtual void StepCompleteOnMainThread(int step) OVERRIDE {
1579     EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1580     switch (step) {
1581       case 0:
1582         ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1583         // Expects a valid UIResourceId.
1584         EXPECT_NE(0, ui_resource_->id());
1585         PostSetNeedsCommitToMainThread();
1586         break;
1587       case 4:
1588         // Release resource before ending the test.
1589         ui_resource_.reset();
1590         EndTest();
1591         break;
1592       case 5:
1593         // Single thread proxy issues extra commits after context lost.
1594         // http://crbug.com/287250
1595         if (HasImplThread())
1596           NOTREACHED();
1597         break;
1598       case 6:
1599         NOTREACHED();
1600     }
1601   }
1602
1603   virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) OVERRIDE {
1604     LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1605     switch (time_step_) {
1606       case 1:
1607         // The resource should have been created on LTHI after the commit.
1608         EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1609         PostSetNeedsCommitToMainThread();
1610         break;
1611       case 2:
1612         LoseContext();
1613         break;
1614       case 3:
1615         // The resources should have been recreated. The bitmap callback should
1616         // have been called once with the resource_lost flag set to true.
1617         EXPECT_EQ(1, ui_resource_->lost_resource_count);
1618         // Resource Id on the impl-side have been recreated as well. Note
1619         // that the same UIResourceId persists after the context lost.
1620         EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1621         PostSetNeedsCommitToMainThread();
1622         break;
1623     }
1624   }
1625 };
1626
1627 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostAfterCommit);
1628
1629 // Losing context before UI resource requests can be commited.  Three sequences
1630 // of creation/deletion are considered:
1631 // 1. Create one resource -> Context Lost => Expect the resource to have been
1632 // created.
1633 // 2. Delete an exisiting resource (test_id0_) -> create a second resource
1634 // (test_id1_) -> Context Lost => Expect the test_id0_ to be removed and
1635 // test_id1_ to have been created.
1636 // 3. Create one resource -> Delete that same resource -> Context Lost => Expect
1637 // the resource to not exist in the manager.
1638 class UIResourceLostBeforeCommit : public UIResourceLostTestSimple {
1639  public:
1640   UIResourceLostBeforeCommit() : test_id0_(0), test_id1_(0) {}
1641
1642   virtual void StepCompleteOnMainThread(int step) OVERRIDE {
1643     switch (step) {
1644       case 0:
1645         ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1646         // Lose the context on the impl thread before the commit.
1647         PostLoseContextToImplThread();
1648         break;
1649       case 2:
1650         // Sequence 2:
1651         // Currently one resource has been created.
1652         test_id0_ = ui_resource_->id();
1653         // Delete this resource.
1654         ui_resource_.reset();
1655         // Create another resource.
1656         ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1657         test_id1_ = ui_resource_->id();
1658         // Sanity check that two resource creations return different ids.
1659         EXPECT_NE(test_id0_, test_id1_);
1660         // Lose the context on the impl thread before the commit.
1661         PostLoseContextToImplThread();
1662         break;
1663       case 3:
1664         // Clear the manager of resources.
1665         ui_resource_.reset();
1666         PostSetNeedsCommitToMainThread();
1667         break;
1668       case 4:
1669         // Sequence 3:
1670         ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1671         test_id0_ = ui_resource_->id();
1672         // Sanity check the UIResourceId should not be 0.
1673         EXPECT_NE(0, test_id0_);
1674         // Usually ScopedUIResource are deleted from the manager in their
1675         // destructor (so usually ui_resource_.reset()).  But here we need
1676         // ui_resource_ for the next step, so call DeleteUIResource directly.
1677         layer_tree_host()->DeleteUIResource(test_id0_);
1678         // Delete the resouce and then lose the context.
1679         PostLoseContextToImplThread();
1680         break;
1681       case 5:
1682         // Release resource before ending the test.
1683         ui_resource_.reset();
1684         EndTest();
1685         break;
1686       case 6:
1687         // Single thread proxy issues extra commits after context lost.
1688         // http://crbug.com/287250
1689         if (HasImplThread())
1690           NOTREACHED();
1691         break;
1692       case 8:
1693         NOTREACHED();
1694     }
1695   }
1696
1697   virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) OVERRIDE {
1698     LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1699     switch (time_step_) {
1700       case 1:
1701         // Sequence 1 (continued):
1702         // The first context lost happens before the resources were created,
1703         // and because it resulted in no resources being destroyed, it does not
1704         // trigger resource re-creation.
1705         EXPECT_EQ(1, ui_resource_->resource_create_count);
1706         EXPECT_EQ(0, ui_resource_->lost_resource_count);
1707         // Resource Id on the impl-side has been created.
1708         PostSetNeedsCommitToMainThread();
1709         break;
1710       case 3:
1711         // Sequence 2 (continued):
1712         // The previous resource should have been deleted.
1713         EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
1714         if (HasImplThread()) {
1715           // The second resource should have been created.
1716           EXPECT_NE(0u, impl->ResourceIdForUIResource(test_id1_));
1717         } else {
1718           // The extra commit that happens at context lost in the single thread
1719           // proxy changes the timing so that the resource has been destroyed.
1720           // http://crbug.com/287250
1721           EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id1_));
1722         }
1723         // The second resource called the resource callback once and since the
1724         // context is lost, a "resource lost" callback was also issued.
1725         EXPECT_EQ(2, ui_resource_->resource_create_count);
1726         EXPECT_EQ(1, ui_resource_->lost_resource_count);
1727         break;
1728       case 5:
1729         // Sequence 3 (continued):
1730         // Expect the resource callback to have been called once.
1731         EXPECT_EQ(1, ui_resource_->resource_create_count);
1732         // No "resource lost" callbacks.
1733         EXPECT_EQ(0, ui_resource_->lost_resource_count);
1734         // The UI resource id should not be valid
1735         EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
1736         break;
1737     }
1738   }
1739
1740  private:
1741   UIResourceId test_id0_;
1742   UIResourceId test_id1_;
1743 };
1744
1745 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeCommit);
1746
1747 // Losing UI resource before the pending trees is activated but after the
1748 // commit.  Impl-side-painting only.
1749 class UIResourceLostBeforeActivateTree : public UIResourceLostTest {
1750   virtual void StepCompleteOnMainThread(int step) OVERRIDE {
1751     EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1752     switch (step) {
1753       case 0:
1754         ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1755         PostSetNeedsCommitToMainThread();
1756         break;
1757       case 3:
1758         test_id_ = ui_resource_->id();
1759         ui_resource_.reset();
1760         PostSetNeedsCommitToMainThread();
1761         break;
1762       case 5:
1763         // Release resource before ending the test.
1764         ui_resource_.reset();
1765         EndTest();
1766         break;
1767       case 6:
1768         // Make sure no extra commits happened.
1769         NOTREACHED();
1770     }
1771   }
1772
1773   virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1774     LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1775     switch (time_step_) {
1776       case 2:
1777         PostSetNeedsCommitToMainThread();
1778         break;
1779       case 4:
1780         PostSetNeedsCommitToMainThread();
1781         break;
1782     }
1783   }
1784
1785   virtual void WillActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1786     switch (time_step_) {
1787       case 1:
1788         // The resource creation callback has been called.
1789         EXPECT_EQ(1, ui_resource_->resource_create_count);
1790         // The resource is not yet lost (sanity check).
1791         EXPECT_EQ(0, ui_resource_->lost_resource_count);
1792         // The resource should not have been created yet on the impl-side.
1793         EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1794         LoseContext();
1795         break;
1796       case 3:
1797         LoseContext();
1798         break;
1799     }
1800   }
1801
1802   virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1803     LayerTreeHostContextTest::DidActivateTreeOnThread(impl);
1804     switch (time_step_) {
1805       case 1:
1806         // The pending requests on the impl-side should have been processed.
1807         EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1808         break;
1809       case 2:
1810         // The "lost resource" callback should have been called once.
1811         EXPECT_EQ(1, ui_resource_->lost_resource_count);
1812         break;
1813       case 4:
1814         // The resource is deleted and should not be in the manager.  Use
1815         // test_id_ since ui_resource_ has been deleted.
1816         EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id_));
1817         break;
1818     }
1819
1820     PostStepCompleteToMainThread();
1821     ++time_step_;
1822   }
1823
1824  private:
1825   UIResourceId test_id_;
1826 };
1827
1828 TEST_F(UIResourceLostBeforeActivateTree,
1829        RunMultiThread_DirectRenderer_ImplSidePaint) {
1830   RunTest(true, false, true);
1831 }
1832
1833 TEST_F(UIResourceLostBeforeActivateTree,
1834        RunMultiThread_DelegatingRenderer_ImplSidePaint) {
1835   RunTest(true, true, true);
1836 }
1837
1838 // Resources evicted explicitly and by visibility changes.
1839 class UIResourceLostEviction : public UIResourceLostTestSimple {
1840  public:
1841   virtual void StepCompleteOnMainThread(int step) OVERRIDE {
1842     EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
1843     switch (step) {
1844       case 0:
1845         ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
1846         EXPECT_NE(0, ui_resource_->id());
1847         PostSetNeedsCommitToMainThread();
1848         break;
1849       case 2:
1850         // Make the tree not visible.
1851         PostSetVisibleToMainThread(false);
1852         break;
1853       case 3:
1854         // Release resource before ending the test.
1855         ui_resource_.reset();
1856         EndTest();
1857         break;
1858       case 4:
1859         NOTREACHED();
1860     }
1861   }
1862
1863   virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* impl,
1864                                        bool visible) OVERRIDE {
1865     TestWebGraphicsContext3D* context = TestContext();
1866     if (!visible) {
1867       // All resources should have been evicted.
1868       ASSERT_EQ(0u, context->NumTextures());
1869       EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1870       EXPECT_EQ(2, ui_resource_->resource_create_count);
1871       EXPECT_EQ(1, ui_resource_->lost_resource_count);
1872       // Drawing is disabled both because of the evicted resources and
1873       // because the renderer is not visible.
1874       EXPECT_FALSE(impl->CanDraw());
1875       // Make the renderer visible again.
1876       PostSetVisibleToMainThread(true);
1877     }
1878   }
1879
1880   virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) OVERRIDE {
1881     TestWebGraphicsContext3D* context = TestContext();
1882     LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1883     switch (time_step_) {
1884       case 1:
1885         // The resource should have been created on LTHI after the commit.
1886         ASSERT_EQ(1u, context->NumTextures());
1887         EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1888         EXPECT_EQ(1, ui_resource_->resource_create_count);
1889         EXPECT_EQ(0, ui_resource_->lost_resource_count);
1890         EXPECT_TRUE(impl->CanDraw());
1891         // Evict all UI resources. This will trigger a commit.
1892         impl->EvictAllUIResources();
1893         ASSERT_EQ(0u, context->NumTextures());
1894         EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1895         EXPECT_EQ(1, ui_resource_->resource_create_count);
1896         EXPECT_EQ(0, ui_resource_->lost_resource_count);
1897         EXPECT_FALSE(impl->CanDraw());
1898         break;
1899       case 2:
1900         // The resource should have been recreated.
1901         ASSERT_EQ(1u, context->NumTextures());
1902         EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1903         EXPECT_EQ(2, ui_resource_->resource_create_count);
1904         EXPECT_EQ(1, ui_resource_->lost_resource_count);
1905         EXPECT_TRUE(impl->CanDraw());
1906         break;
1907       case 3:
1908         // The resource should have been recreated after visibility was
1909         // restored.
1910         ASSERT_EQ(1u, context->NumTextures());
1911         EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
1912         EXPECT_EQ(3, ui_resource_->resource_create_count);
1913         EXPECT_EQ(2, ui_resource_->lost_resource_count);
1914         EXPECT_TRUE(impl->CanDraw());
1915         break;
1916     }
1917   }
1918 };
1919
1920 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction);
1921
1922 class LayerTreeHostContextTestSurfaceCreateCallback
1923     : public LayerTreeHostContextTest {
1924  public:
1925   LayerTreeHostContextTestSurfaceCreateCallback()
1926       : LayerTreeHostContextTest(),
1927         layer_(FakeContentLayer::Create(&client_)) {}
1928
1929   virtual void SetupTree() OVERRIDE {
1930     layer_->SetBounds(gfx::Size(10, 20));
1931     layer_tree_host()->SetRootLayer(layer_);
1932     LayerTreeHostContextTest::SetupTree();
1933   }
1934
1935   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
1936
1937   virtual void DidCommit() OVERRIDE {
1938     switch (layer_tree_host()->source_frame_number()) {
1939       case 1:
1940         EXPECT_EQ(1u, layer_->output_surface_created_count());
1941         layer_tree_host()->SetNeedsCommit();
1942         break;
1943       case 2:
1944         EXPECT_EQ(1u, layer_->output_surface_created_count());
1945         layer_tree_host()->SetNeedsCommit();
1946         break;
1947       case 3:
1948         EXPECT_EQ(1u, layer_->output_surface_created_count());
1949         break;
1950       case 4:
1951         EXPECT_EQ(2u, layer_->output_surface_created_count());
1952         layer_tree_host()->SetNeedsCommit();
1953         break;
1954     }
1955   }
1956
1957   virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1958     LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1959     switch (LastCommittedSourceFrameNumber(impl)) {
1960       case 0:
1961         break;
1962       case 1:
1963         break;
1964       case 2:
1965         LoseContext();
1966         break;
1967       case 3:
1968         EndTest();
1969         break;
1970     }
1971   }
1972
1973   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
1974     EXPECT_TRUE(succeeded);
1975   }
1976
1977   virtual void AfterTest() OVERRIDE {}
1978
1979  protected:
1980   FakeContentLayerClient client_;
1981   scoped_refptr<FakeContentLayer> layer_;
1982 };
1983
1984 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestSurfaceCreateCallback);
1985
1986 }  // namespace
1987 }  // namespace cc