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