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