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