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