layer_tree_host_unittest_context.cc revision 558790d6acca3451cf3a6b497803a5f07d0bec58
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/heads_up_display_layer.h"
10#include "cc/layers/io_surface_layer.h"
11#include "cc/layers/layer_impl.h"
12#include "cc/layers/picture_layer.h"
13#include "cc/layers/scrollbar_layer.h"
14#include "cc/layers/texture_layer.h"
15#include "cc/layers/texture_layer_impl.h"
16#include "cc/layers/video_layer.h"
17#include "cc/layers/video_layer_impl.h"
18#include "cc/output/filter_operations.h"
19#include "cc/test/fake_content_layer.h"
20#include "cc/test/fake_content_layer_client.h"
21#include "cc/test/fake_content_layer_impl.h"
22#include "cc/test/fake_context_provider.h"
23#include "cc/test/fake_delegated_renderer_layer.h"
24#include "cc/test/fake_delegated_renderer_layer_impl.h"
25#include "cc/test/fake_layer_tree_host_client.h"
26#include "cc/test/fake_output_surface.h"
27#include "cc/test/fake_scrollbar.h"
28#include "cc/test/fake_scrollbar_layer.h"
29#include "cc/test/fake_video_frame_provider.h"
30#include "cc/test/layer_tree_test.h"
31#include "cc/test/render_pass_test_common.h"
32#include "cc/test/test_web_graphics_context_3d.h"
33#include "cc/trees/layer_tree_host_impl.h"
34#include "cc/trees/layer_tree_impl.h"
35#include "cc/trees/single_thread_proxy.h"
36#include "gpu/GLES2/gl2extchromium.h"
37#include "media/base/media.h"
38
39using media::VideoFrame;
40using WebKit::WebGraphicsContext3D;
41
42namespace cc {
43namespace {
44
45// These tests deal with losing the 3d graphics context.
46class LayerTreeHostContextTest : public LayerTreeTest {
47 public:
48  LayerTreeHostContextTest()
49      : LayerTreeTest(),
50        context3d_(NULL),
51        times_to_fail_create_(0),
52        times_to_fail_initialize_(0),
53        times_to_lose_on_create_(0),
54        times_to_lose_during_commit_(0),
55        times_to_lose_during_draw_(0),
56        times_to_fail_recreate_(0),
57        times_to_fail_reinitialize_(0),
58        times_to_lose_on_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    media::InitializeMediaLibraryForTesting();
67  }
68
69  void LoseContext() {
70    context3d_->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
71                                    GL_INNOCENT_CONTEXT_RESET_ARB);
72    context3d_ = NULL;
73  }
74
75  virtual scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() {
76    return TestWebGraphicsContext3D::Create();
77  }
78
79  virtual scoped_ptr<OutputSurface> CreateOutputSurface() OVERRIDE {
80    if (times_to_fail_create_) {
81      --times_to_fail_create_;
82      ExpectCreateToFail();
83      return scoped_ptr<OutputSurface>();
84    }
85
86    scoped_ptr<TestWebGraphicsContext3D> context3d = CreateContext3d();
87    context3d_ = context3d.get();
88
89    if (context_should_support_io_surface_) {
90      context3d_->set_have_extension_io_surface(true);
91      context3d_->set_have_extension_egl_image(true);
92    }
93
94    if (times_to_fail_initialize_) {
95      --times_to_fail_initialize_;
96      // Make the context get lost during reinitialization.
97      // The number of times MakeCurrent succeeds is not important, and
98      // can be changed if needed to make this pass with future changes.
99      context3d_->set_times_make_current_succeeds(2);
100      ExpectCreateToFail();
101    } else if (times_to_lose_on_create_) {
102      --times_to_lose_on_create_;
103      LoseContext();
104      ExpectCreateToFail();
105    }
106
107    if (delegating_renderer()) {
108      return FakeOutputSurface::CreateDelegating3d(
109          context3d.PassAs<WebGraphicsContext3D>()).PassAs<OutputSurface>();
110    }
111    return FakeOutputSurface::Create3d(
112        context3d.PassAs<WebGraphicsContext3D>()).PassAs<OutputSurface>();
113  }
114
115  scoped_ptr<TestWebGraphicsContext3D> CreateOffscreenContext3d() {
116    if (!context3d_)
117      return scoped_ptr<TestWebGraphicsContext3D>();
118
119    ++times_offscreen_created_;
120
121    if (times_to_fail_create_offscreen_) {
122      --times_to_fail_create_offscreen_;
123      ExpectCreateToFail();
124      return scoped_ptr<TestWebGraphicsContext3D>();
125    }
126
127    scoped_ptr<TestWebGraphicsContext3D> offscreen_context3d =
128        TestWebGraphicsContext3D::Create().Pass();
129    DCHECK(offscreen_context3d);
130    context3d_->add_share_group_context(offscreen_context3d.get());
131
132    return offscreen_context3d.Pass();
133  }
134
135  virtual scoped_refptr<cc::ContextProvider>
136  OffscreenContextProviderForMainThread() OVERRIDE {
137    DCHECK(!HasImplThread());
138
139    if (!offscreen_contexts_main_thread_.get() ||
140        offscreen_contexts_main_thread_->DestroyedOnMainThread()) {
141      offscreen_contexts_main_thread_ = FakeContextProvider::Create(
142          base::Bind(&LayerTreeHostContextTest::CreateOffscreenContext3d,
143                     base::Unretained(this)));
144      if (offscreen_contexts_main_thread_.get() &&
145          !offscreen_contexts_main_thread_->BindToCurrentThread())
146        offscreen_contexts_main_thread_ = NULL;
147    }
148    return offscreen_contexts_main_thread_;
149  }
150
151  virtual scoped_refptr<cc::ContextProvider>
152  OffscreenContextProviderForCompositorThread() OVERRIDE {
153    DCHECK(HasImplThread());
154
155    if (!offscreen_contexts_compositor_thread_.get() ||
156        offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) {
157      offscreen_contexts_compositor_thread_ = FakeContextProvider::Create(
158          base::Bind(&LayerTreeHostContextTest::CreateOffscreenContext3d,
159                     base::Unretained(this)));
160    }
161    return offscreen_contexts_compositor_thread_;
162  }
163
164  virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
165                                     LayerTreeHostImpl::FrameData* frame,
166                                     bool result) OVERRIDE {
167    EXPECT_TRUE(result);
168    if (!times_to_lose_during_draw_)
169      return result;
170
171    --times_to_lose_during_draw_;
172    context3d_->set_times_make_current_succeeds(0);
173
174    times_to_fail_create_ = times_to_fail_recreate_;
175    times_to_fail_recreate_ = 0;
176    times_to_fail_initialize_ = times_to_fail_reinitialize_;
177    times_to_fail_reinitialize_ = 0;
178    times_to_lose_on_create_ = times_to_lose_on_recreate_;
179    times_to_lose_on_recreate_ = 0;
180    times_to_fail_create_offscreen_ = times_to_fail_recreate_offscreen_;
181    times_to_fail_recreate_offscreen_ = 0;
182
183    return result;
184  }
185
186  virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
187    committed_at_least_once_ = true;
188
189    if (!times_to_lose_during_commit_)
190      return;
191    --times_to_lose_during_commit_;
192    LoseContext();
193
194    times_to_fail_create_ = times_to_fail_recreate_;
195    times_to_fail_recreate_ = 0;
196    times_to_fail_initialize_ = times_to_fail_reinitialize_;
197    times_to_fail_reinitialize_ = 0;
198    times_to_lose_on_create_ = times_to_lose_on_recreate_;
199    times_to_lose_on_recreate_ = 0;
200    times_to_fail_create_offscreen_ = times_to_fail_recreate_offscreen_;
201    times_to_fail_recreate_offscreen_ = 0;
202  }
203
204  virtual void DidFailToInitializeOutputSurface() OVERRIDE {
205    ++times_create_failed_;
206  }
207
208  virtual void TearDown() OVERRIDE {
209    LayerTreeTest::TearDown();
210    EXPECT_EQ(times_to_expect_create_failed_, times_create_failed_);
211  }
212
213  void ExpectCreateToFail() {
214    ++times_to_expect_create_failed_;
215  }
216
217 protected:
218  TestWebGraphicsContext3D* context3d_;
219  int times_to_fail_create_;
220  int times_to_fail_initialize_;
221  int times_to_lose_on_create_;
222  int times_to_lose_during_commit_;
223  int times_to_lose_during_draw_;
224  int times_to_fail_recreate_;
225  int times_to_fail_reinitialize_;
226  int times_to_lose_on_recreate_;
227  int times_to_fail_create_offscreen_;
228  int times_to_fail_recreate_offscreen_;
229  int times_to_expect_create_failed_;
230  int times_create_failed_;
231  int times_offscreen_created_;
232  bool committed_at_least_once_;
233  bool context_should_support_io_surface_;
234
235  scoped_refptr<FakeContextProvider> offscreen_contexts_main_thread_;
236  scoped_refptr<FakeContextProvider> offscreen_contexts_compositor_thread_;
237};
238
239class LayerTreeHostContextTestLostContextSucceeds
240    : public LayerTreeHostContextTest {
241 public:
242  LayerTreeHostContextTestLostContextSucceeds()
243      : LayerTreeHostContextTest(),
244        test_case_(0),
245        num_losses_(0),
246        recovered_context_(true),
247        first_initialized_(false) {}
248
249  virtual void BeginTest() OVERRIDE {
250    PostSetNeedsCommitToMainThread();
251  }
252
253  virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
254    EXPECT_TRUE(succeeded);
255
256    if (first_initialized_)
257      ++num_losses_;
258    else
259      first_initialized_ = true;
260
261    recovered_context_ = true;
262  }
263
264  virtual void AfterTest() OVERRIDE {
265    EXPECT_EQ(10u, test_case_);
266    EXPECT_EQ(8 + 10 + 10, num_losses_);
267  }
268
269  virtual void DidCommitAndDrawFrame() OVERRIDE {
270    // If the last frame had a context loss, then we'll commit again to
271    // recover.
272    if (!recovered_context_)
273      return;
274    if (times_to_lose_during_commit_)
275      return;
276    if (times_to_lose_during_draw_)
277      return;
278
279    recovered_context_ = false;
280    if (NextTestCase())
281      InvalidateAndSetNeedsCommit();
282    else
283      EndTest();
284  }
285
286  virtual void InvalidateAndSetNeedsCommit() {
287    // Cause damage so we try to draw.
288    layer_tree_host()->root_layer()->SetNeedsDisplay();
289    layer_tree_host()->SetNeedsCommit();
290  }
291
292  bool NextTestCase() {
293    static const TestCase kTests[] = {
294      // Losing the context and failing to recreate it (or losing it again
295      // immediately) a small number of times should succeed.
296      { 1,  // times_to_lose_during_commit
297        0,  // times_to_lose_during_draw
298        3,  // times_to_fail_reinitialize
299        0,  // times_to_fail_recreate
300        0,  // times_to_lose_on_recreate
301        0,  // times_to_fail_recreate_offscreen
302      },
303      { 0,  // times_to_lose_during_commit
304        1,  // times_to_lose_during_draw
305        3,  // times_to_fail_reinitialize
306        0,  // times_to_fail_recreate
307        0,  // times_to_lose_on_recreate
308        0,  // times_to_fail_recreate_offscreen
309      },
310      { 1,  // times_to_lose_during_commit
311        0,  // times_to_lose_during_draw
312        0,  // times_to_fail_reinitialize
313        3,  // times_to_fail_recreate
314        0,  // times_to_lose_on_recreate
315        0,  // times_to_fail_recreate_offscreen
316      },
317      { 0,  // times_to_lose_during_commit
318        1,  // times_to_lose_during_draw
319        0,  // times_to_fail_reinitialize
320        3,  // times_to_fail_recreate
321        0,  // times_to_lose_on_recreate
322        0,  // times_to_fail_recreate_offscreen
323      },
324      { 1,  // times_to_lose_during_commit
325        0,  // times_to_lose_during_draw
326        0,  // times_to_fail_reinitialize
327        0,  // times_to_fail_recreate
328        3,  // times_to_lose_on_recreate
329        0,  // times_to_fail_recreate_offscreen
330      },
331      { 0,  // times_to_lose_during_commit
332        1,  // times_to_lose_during_draw
333        0,  // times_to_fail_reinitialize
334        0,  // times_to_fail_recreate
335        3,  // times_to_lose_on_recreate
336        0,  // times_to_fail_recreate_offscreen
337      },
338      { 1,  // times_to_lose_during_commit
339        0,  // times_to_lose_during_draw
340        0,  // times_to_fail_reinitialize
341        0,  // times_to_fail_recreate
342        0,  // times_to_lose_on_recreate
343        3,  // times_to_fail_recreate_offscreen
344      },
345      { 0,  // times_to_lose_during_commit
346        1,  // times_to_lose_during_draw
347        0,  // times_to_fail_reinitialize
348        0,  // times_to_fail_recreate
349        0,  // times_to_lose_on_recreate
350        3,  // times_to_fail_recreate_offscreen
351      },
352      // Losing the context and recreating it any number of times should
353      // succeed.
354      { 10,  // times_to_lose_during_commit
355        0,  // times_to_lose_during_draw
356        0,  // times_to_fail_reinitialize
357        0,  // times_to_fail_recreate
358        0,  // times_to_lose_on_recreate
359        0,  // times_to_fail_recreate_offscreen
360      },
361      { 0,  // times_to_lose_during_commit
362        10,  // times_to_lose_during_draw
363        0,  // times_to_fail_reinitialize
364        0,  // times_to_fail_recreate
365        0,  // times_to_lose_on_recreate
366        0,  // times_to_fail_recreate_offscreen
367      },
368    };
369
370    if (test_case_ >= arraysize(kTests))
371      return false;
372
373    times_to_lose_during_commit_ =
374        kTests[test_case_].times_to_lose_during_commit;
375    times_to_lose_during_draw_ =
376        kTests[test_case_].times_to_lose_during_draw;
377    times_to_fail_reinitialize_ = kTests[test_case_].times_to_fail_reinitialize;
378    times_to_fail_recreate_ = kTests[test_case_].times_to_fail_recreate;
379    times_to_lose_on_recreate_ = kTests[test_case_].times_to_lose_on_recreate;
380    times_to_fail_recreate_offscreen_ =
381        kTests[test_case_].times_to_fail_recreate_offscreen;
382    ++test_case_;
383    return true;
384  }
385
386  struct TestCase {
387    int times_to_lose_during_commit;
388    int times_to_lose_during_draw;
389    int times_to_fail_reinitialize;
390    int times_to_fail_recreate;
391    int times_to_lose_on_recreate;
392    int times_to_fail_recreate_offscreen;
393  };
394
395 protected:
396  size_t test_case_;
397  int num_losses_;
398  bool recovered_context_;
399  bool first_initialized_;
400};
401
402SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLostContextSucceeds);
403
404class LayerTreeHostContextTestLostContextSucceedsWithContent
405    : public LayerTreeHostContextTestLostContextSucceeds {
406 public:
407  LayerTreeHostContextTestLostContextSucceedsWithContent()
408      : LayerTreeHostContextTestLostContextSucceeds() {}
409
410  virtual void SetupTree() OVERRIDE {
411    root_ = Layer::Create();
412    root_->SetBounds(gfx::Size(10, 10));
413    root_->SetAnchorPoint(gfx::PointF());
414    root_->SetIsDrawable(true);
415
416    content_ = FakeContentLayer::Create(&client_);
417    content_->SetBounds(gfx::Size(10, 10));
418    content_->SetAnchorPoint(gfx::PointF());
419    content_->SetIsDrawable(true);
420    if (use_surface_) {
421      content_->SetForceRenderSurface(true);
422      // Filters require us to create an offscreen context.
423      FilterOperations filters;
424      filters.Append(FilterOperation::CreateGrayscaleFilter(0.5f));
425      content_->SetFilters(filters);
426      content_->SetBackgroundFilters(filters);
427    }
428
429    root_->AddChild(content_);
430
431    layer_tree_host()->SetRootLayer(root_);
432    LayerTreeHostContextTest::SetupTree();
433  }
434
435  virtual void InvalidateAndSetNeedsCommit() OVERRIDE {
436    // Invalidate the render surface so we don't try to use a cached copy of the
437    // surface.  We want to make sure to test the drawing paths for drawing to
438    // a child surface.
439    content_->SetNeedsDisplay();
440    LayerTreeHostContextTestLostContextSucceeds::InvalidateAndSetNeedsCommit();
441  }
442
443  virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
444    FakeContentLayerImpl* content_impl = static_cast<FakeContentLayerImpl*>(
445        host_impl->active_tree()->root_layer()->children()[0]);
446    // Even though the context was lost, we should have a resource. The
447    // TestWebGraphicsContext3D ensures that this resource is created with
448    // the active context.
449    EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0));
450
451    cc::ContextProvider* contexts =
452        host_impl->resource_provider()->offscreen_context_provider();
453    if (use_surface_) {
454      EXPECT_TRUE(contexts->Context3d());
455      // TODO(danakj): Make a fake GrContext.
456      // EXPECT_TRUE(contexts->GrContext());
457    } else {
458      EXPECT_FALSE(contexts);
459    }
460  }
461
462  virtual void AfterTest() OVERRIDE {
463    LayerTreeHostContextTestLostContextSucceeds::AfterTest();
464    if (use_surface_) {
465      // 1 create to start with +
466      // 6 from test cases that fail on initializing the renderer (after the
467      // offscreen context is created) +
468      // 6 from test cases that lose the offscreen context directly +
469      // All the test cases that recreate both contexts only once
470      // per time it is lost.
471      EXPECT_EQ(6 + 6 + 1 + num_losses_, times_offscreen_created_);
472    } else {
473      EXPECT_EQ(0, times_offscreen_created_);
474    }
475  }
476
477 protected:
478  bool use_surface_;
479  FakeContentLayerClient client_;
480  scoped_refptr<Layer> root_;
481  scoped_refptr<ContentLayer> content_;
482};
483
484TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
485       NoSurface_SingleThread_DirectRenderer) {
486  use_surface_ = false;
487  RunTest(false, false, false);
488}
489
490TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
491       NoSurface_SingleThread_DelegatingRenderer) {
492  use_surface_ = false;
493  RunTest(false, true, false);
494}
495
496TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
497       NoSurface_MultiThread_DirectRenderer_MainThreadPaint) {
498  use_surface_ = false;
499  RunTest(true, false, false);
500}
501
502TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
503       NoSurface_MultiThread_DirectRenderer_ImplSidePaint) {
504  use_surface_ = false;
505  RunTest(true, false, true);
506}
507
508TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
509       NoSurface_MultiThread_DelegatingRenderer_MainThreadPaint) {
510  use_surface_ = false;
511  RunTest(true, true, false);
512}
513
514TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
515       NoSurface_MultiThread_DelegatingRenderer_ImplSidePaint) {
516  use_surface_ = false;
517  RunTest(true, true, true);
518}
519
520// Surfaces don't exist with a delegating renderer.
521TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
522       WithSurface_SingleThread_DirectRenderer) {
523  use_surface_ = true;
524  RunTest(false, false, false);
525}
526
527TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
528       WithSurface_MultiThread_DirectRenderer_MainThreadPaint) {
529  use_surface_ = true;
530  RunTest(true, false, false);
531}
532
533TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
534       WithSurface_MultiThread_DirectRenderer_ImplSidePaint) {
535  use_surface_ = true;
536  RunTest(true, false, true);
537}
538
539class LayerTreeHostContextTestOffscreenContextFails
540    : public LayerTreeHostContextTest {
541 public:
542  virtual void SetupTree() OVERRIDE {
543    root_ = Layer::Create();
544    root_->SetBounds(gfx::Size(10, 10));
545    root_->SetAnchorPoint(gfx::PointF());
546    root_->SetIsDrawable(true);
547
548    content_ = FakeContentLayer::Create(&client_);
549    content_->SetBounds(gfx::Size(10, 10));
550    content_->SetAnchorPoint(gfx::PointF());
551    content_->SetIsDrawable(true);
552    content_->SetForceRenderSurface(true);
553    // Filters require us to create an offscreen context.
554    FilterOperations filters;
555    filters.Append(FilterOperation::CreateGrayscaleFilter(0.5f));
556    content_->SetFilters(filters);
557    content_->SetBackgroundFilters(filters);
558
559    root_->AddChild(content_);
560
561    layer_tree_host()->SetRootLayer(root_);
562    LayerTreeHostContextTest::SetupTree();
563  }
564
565  virtual void BeginTest() OVERRIDE {
566    times_to_fail_create_offscreen_ = 1;
567    PostSetNeedsCommitToMainThread();
568  }
569
570  virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
571    cc::ContextProvider* contexts =
572        host_impl->resource_provider()->offscreen_context_provider();
573    EXPECT_FALSE(contexts);
574
575    // This did not lead to create failure.
576    times_to_expect_create_failed_ = 0;
577    EndTest();
578  }
579
580  virtual void AfterTest() OVERRIDE {}
581
582 protected:
583  FakeContentLayerClient client_;
584  scoped_refptr<Layer> root_;
585  scoped_refptr<ContentLayer> content_;
586};
587
588SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestOffscreenContextFails);
589
590class LayerTreeHostContextTestLostContextFails
591    : public LayerTreeHostContextTest {
592 public:
593  LayerTreeHostContextTestLostContextFails()
594      : LayerTreeHostContextTest(),
595        num_commits_(0),
596        first_initialized_(false) {
597    times_to_lose_during_commit_ = 1;
598  }
599
600  virtual void BeginTest() OVERRIDE {
601    PostSetNeedsCommitToMainThread();
602  }
603
604  virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
605    if (first_initialized_) {
606      EXPECT_FALSE(succeeded);
607      EndTest();
608    } else {
609      first_initialized_ = true;
610    }
611  }
612
613  virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
614    LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
615
616    ++num_commits_;
617    if (num_commits_ == 1) {
618      // When the context is ok, we should have these things.
619      EXPECT_TRUE(host_impl->output_surface());
620      EXPECT_TRUE(host_impl->renderer());
621      EXPECT_TRUE(host_impl->resource_provider());
622      return;
623    }
624
625    // When context recreation fails we shouldn't be left with any of them.
626    EXPECT_FALSE(host_impl->output_surface());
627    EXPECT_FALSE(host_impl->renderer());
628    EXPECT_FALSE(host_impl->resource_provider());
629  }
630
631  virtual void AfterTest() OVERRIDE {}
632
633 private:
634  int num_commits_;
635  bool first_initialized_;
636};
637
638TEST_F(LayerTreeHostContextTestLostContextFails,
639       FailReinitialize100_SingleThread_DirectRenderer) {
640  times_to_fail_reinitialize_ = 100;
641  times_to_fail_recreate_ = 0;
642  times_to_lose_on_recreate_ = 0;
643  RunTest(false, false, false);
644}
645
646TEST_F(LayerTreeHostContextTestLostContextFails,
647       FailReinitialize100_SingleThread_DelegatingRenderer) {
648  times_to_fail_reinitialize_ = 100;
649  times_to_fail_recreate_ = 0;
650  times_to_lose_on_recreate_ = 0;
651  RunTest(false, true, false);
652}
653
654TEST_F(LayerTreeHostContextTestLostContextFails,
655       FailReinitialize100_MultiThread_DirectRenderer_MainThreadPaint) {
656  times_to_fail_reinitialize_ = 100;
657  times_to_fail_recreate_ = 0;
658  times_to_lose_on_recreate_ = 0;
659  RunTest(true, false, false);
660}
661
662TEST_F(LayerTreeHostContextTestLostContextFails,
663       FailReinitialize100_MultiThread_DirectRenderer_ImplSidePaint) {
664  times_to_fail_reinitialize_ = 100;
665  times_to_fail_recreate_ = 0;
666  times_to_lose_on_recreate_ = 0;
667  RunTest(true, false, true);
668}
669
670TEST_F(LayerTreeHostContextTestLostContextFails,
671       FailReinitialize100_MultiThread_DelegatingRenderer_MainThreadPaint) {
672  times_to_fail_reinitialize_ = 100;
673  times_to_fail_recreate_ = 0;
674  times_to_lose_on_recreate_ = 0;
675  RunTest(true, true, false);
676}
677
678TEST_F(LayerTreeHostContextTestLostContextFails,
679       FailReinitialize100_MultiThread_DelegatingRenderer_ImplSidePaint) {
680  times_to_fail_reinitialize_ = 100;
681  times_to_fail_recreate_ = 0;
682  times_to_lose_on_recreate_ = 0;
683  RunTest(true, true, true);
684}
685
686TEST_F(LayerTreeHostContextTestLostContextFails,
687       FailRecreate100_SingleThread_DirectRenderer) {
688  times_to_fail_reinitialize_ = 0;
689  times_to_fail_recreate_ = 100;
690  times_to_lose_on_recreate_ = 0;
691  RunTest(false, false, false);
692}
693
694TEST_F(LayerTreeHostContextTestLostContextFails,
695       FailRecreate100_SingleThread_DelegatingRenderer) {
696  times_to_fail_reinitialize_ = 0;
697  times_to_fail_recreate_ = 100;
698  times_to_lose_on_recreate_ = 0;
699  RunTest(false, true, false);
700}
701
702TEST_F(LayerTreeHostContextTestLostContextFails,
703       FailRecreate100_MultiThread_DirectRenderer_MainThreadPaint) {
704  times_to_fail_reinitialize_ = 0;
705  times_to_fail_recreate_ = 100;
706  times_to_lose_on_recreate_ = 0;
707  RunTest(true, false, false);
708}
709
710TEST_F(LayerTreeHostContextTestLostContextFails,
711       FailRecreate100_MultiThread_DirectRenderer_ImplSidePaint) {
712  times_to_fail_reinitialize_ = 0;
713  times_to_fail_recreate_ = 100;
714  times_to_lose_on_recreate_ = 0;
715  RunTest(true, false, true);
716}
717
718TEST_F(LayerTreeHostContextTestLostContextFails,
719       FailRecreate100_MultiThread_DelegatingRenderer_MainThreadPaint) {
720  times_to_fail_reinitialize_ = 0;
721  times_to_fail_recreate_ = 100;
722  times_to_lose_on_recreate_ = 0;
723  RunTest(true, true, false);
724}
725
726TEST_F(LayerTreeHostContextTestLostContextFails,
727       FailRecreate100_MultiThread_DelegatingRenderer_ImplSidePaint) {
728  times_to_fail_reinitialize_ = 0;
729  times_to_fail_recreate_ = 100;
730  times_to_lose_on_recreate_ = 0;
731  RunTest(true, true, true);
732}
733
734TEST_F(LayerTreeHostContextTestLostContextFails,
735       LoseOnRecreate100_SingleThread_DirectRenderer) {
736  times_to_fail_reinitialize_ = 0;
737  times_to_fail_recreate_ = 0;
738  times_to_lose_on_recreate_ = 100;
739  RunTest(false, false, false);
740}
741
742TEST_F(LayerTreeHostContextTestLostContextFails,
743       LoseOnRecreate100_SingleThread_DelegatingRenderer) {
744  times_to_fail_reinitialize_ = 0;
745  times_to_fail_recreate_ = 0;
746  times_to_lose_on_recreate_ = 100;
747  RunTest(false, true, false);
748}
749
750TEST_F(LayerTreeHostContextTestLostContextFails,
751       LoseOnRecreate100_MultiThread_DirectRenderer_MainThreadPaint) {
752  times_to_fail_reinitialize_ = 0;
753  times_to_fail_recreate_ = 0;
754  times_to_lose_on_recreate_ = 100;
755  RunTest(true, false, false);
756}
757
758TEST_F(LayerTreeHostContextTestLostContextFails,
759       LoseOnRecreate100_MultiThread_DirectRenderer_ImplSidePaint) {
760  times_to_fail_reinitialize_ = 0;
761  times_to_fail_recreate_ = 0;
762  times_to_lose_on_recreate_ = 100;
763  RunTest(true, false, true);
764}
765
766TEST_F(LayerTreeHostContextTestLostContextFails,
767       LoseOnRecreate100_MultiThread_DelegatingRenderer_MainThreadPaint) {
768  times_to_fail_reinitialize_ = 0;
769  times_to_fail_recreate_ = 0;
770  times_to_lose_on_recreate_ = 100;
771  RunTest(true, true, false);
772}
773
774TEST_F(LayerTreeHostContextTestLostContextFails,
775       LoseOnRecreate100_MultiThread_DelegatingRenderer_ImplSidePaint) {
776  times_to_fail_reinitialize_ = 0;
777  times_to_fail_recreate_ = 0;
778  times_to_lose_on_recreate_ = 100;
779  RunTest(true, true, true);
780}
781
782class LayerTreeHostContextTestFinishAllRenderingAfterLoss
783    : public LayerTreeHostContextTest {
784 public:
785  virtual void BeginTest() OVERRIDE {
786    // Lose the context until the compositor gives up on it.
787    first_initialized_ = false;
788    times_to_lose_during_commit_ = 1;
789    times_to_fail_reinitialize_ = 10;
790    PostSetNeedsCommitToMainThread();
791  }
792
793  virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
794    if (first_initialized_) {
795      EXPECT_FALSE(succeeded);
796      layer_tree_host()->FinishAllRendering();
797      EndTest();
798    } else {
799      first_initialized_ = true;
800    }
801  }
802
803  virtual void AfterTest() OVERRIDE {}
804
805 private:
806  bool first_initialized_;
807};
808
809SINGLE_AND_MULTI_THREAD_TEST_F(
810    LayerTreeHostContextTestFinishAllRenderingAfterLoss);
811
812class LayerTreeHostContextTestLostContextAndEvictTextures
813    : public LayerTreeHostContextTest {
814 public:
815  LayerTreeHostContextTestLostContextAndEvictTextures()
816      : LayerTreeHostContextTest(),
817        layer_(FakeContentLayer::Create(&client_)),
818        impl_host_(0),
819        num_commits_(0) {}
820
821  virtual void SetupTree() OVERRIDE {
822    layer_->SetBounds(gfx::Size(10, 20));
823    layer_tree_host()->SetRootLayer(layer_);
824    LayerTreeHostContextTest::SetupTree();
825  }
826
827  virtual void BeginTest() OVERRIDE {
828    PostSetNeedsCommitToMainThread();
829  }
830
831  void PostEvictTextures() {
832    if (HasImplThread()) {
833      ImplThreadTaskRunner()->PostTask(
834          FROM_HERE,
835          base::Bind(
836              &LayerTreeHostContextTestLostContextAndEvictTextures::
837              EvictTexturesOnImplThread,
838              base::Unretained(this)));
839    } else {
840      DebugScopedSetImplThread impl(proxy());
841      EvictTexturesOnImplThread();
842    }
843  }
844
845  void EvictTexturesOnImplThread() {
846    impl_host_->EvictTexturesForTesting();
847    if (lose_after_evict_)
848      LoseContext();
849  }
850
851  virtual void DidCommitAndDrawFrame() OVERRIDE {
852    if (num_commits_ > 1)
853      return;
854    EXPECT_TRUE(layer_->HaveBackingAt(0, 0));
855    PostEvictTextures();
856  }
857
858  virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
859    LayerTreeHostContextTest::CommitCompleteOnThread(impl);
860    if (num_commits_ > 1)
861      return;
862    ++num_commits_;
863    if (!lose_after_evict_)
864      LoseContext();
865    impl_host_ = impl;
866  }
867
868  virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
869    EXPECT_TRUE(succeeded);
870    EndTest();
871  }
872
873  virtual void AfterTest() OVERRIDE {}
874
875 protected:
876  bool lose_after_evict_;
877  FakeContentLayerClient client_;
878  scoped_refptr<FakeContentLayer> layer_;
879  LayerTreeHostImpl* impl_host_;
880  int num_commits_;
881};
882
883TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
884       LoseAfterEvict_SingleThread_DirectRenderer) {
885  lose_after_evict_ = true;
886  RunTest(false, false, false);
887}
888
889TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
890       LoseAfterEvict_SingleThread_DelegatingRenderer) {
891  lose_after_evict_ = true;
892  RunTest(false, true, false);
893}
894
895TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
896       LoseAfterEvict_MultiThread_DirectRenderer_MainThreadPaint) {
897  lose_after_evict_ = true;
898  RunTest(true, false, false);
899}
900
901TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
902       LoseAfterEvict_MultiThread_DirectRenderer_ImplSidePaint) {
903  lose_after_evict_ = true;
904  RunTest(true, false, true);
905}
906
907TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
908       LoseAfterEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
909  lose_after_evict_ = true;
910  RunTest(true, true, false);
911}
912
913TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
914       LoseAfterEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
915  lose_after_evict_ = true;
916  RunTest(true, true, true);
917}
918
919TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
920       LoseBeforeEvict_SingleThread_DirectRenderer) {
921  lose_after_evict_ = false;
922  RunTest(false, false, false);
923}
924
925TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
926       LoseBeforeEvict_SingleThread_DelegatingRenderer) {
927  lose_after_evict_ = false;
928  RunTest(false, true, false);
929}
930
931TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
932       LoseBeforeEvict_MultiThread_DirectRenderer_MainThreadPaint) {
933  lose_after_evict_ = false;
934  RunTest(true, false, false);
935}
936
937TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
938       LoseBeforeEvict_MultiThread_DirectRenderer_ImplSidePaint) {
939  lose_after_evict_ = false;
940  RunTest(true, false, true);
941}
942
943TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
944       LoseBeforeEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
945  lose_after_evict_ = false;
946  RunTest(true, true, false);
947}
948
949TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
950       LoseBeforeEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
951  lose_after_evict_ = false;
952  RunTest(true, true, true);
953}
954
955class LayerTreeHostContextTestLostContextWhileUpdatingResources
956    : public LayerTreeHostContextTest {
957 public:
958  LayerTreeHostContextTestLostContextWhileUpdatingResources()
959      : parent_(FakeContentLayer::Create(&client_)),
960        num_children_(50),
961        times_to_lose_on_end_query_(3) {}
962
963  virtual scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() OVERRIDE {
964    scoped_ptr<TestWebGraphicsContext3D> context =
965        LayerTreeHostContextTest::CreateContext3d();
966    if (times_to_lose_on_end_query_) {
967      --times_to_lose_on_end_query_;
968      context->set_times_end_query_succeeds(5);
969    }
970    return context.Pass();
971  }
972
973  virtual void SetupTree() OVERRIDE {
974    parent_->SetBounds(gfx::Size(num_children_, 1));
975
976    for (int i = 0; i < num_children_; i++) {
977      scoped_refptr<FakeContentLayer> child =
978          FakeContentLayer::Create(&client_);
979      child->SetPosition(gfx::PointF(i, 0.f));
980      child->SetBounds(gfx::Size(1, 1));
981      parent_->AddChild(child);
982    }
983
984    layer_tree_host()->SetRootLayer(parent_);
985    LayerTreeHostContextTest::SetupTree();
986  }
987
988  virtual void BeginTest() OVERRIDE {
989    PostSetNeedsCommitToMainThread();
990  }
991
992  virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
993    LayerTreeHostContextTest::CommitCompleteOnThread(impl);
994    EndTest();
995  }
996
997  virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
998    EXPECT_TRUE(succeeded);
999  }
1000
1001  virtual void AfterTest() OVERRIDE {
1002    EXPECT_EQ(0, times_to_lose_on_end_query_);
1003  }
1004
1005 private:
1006  FakeContentLayerClient client_;
1007  scoped_refptr<FakeContentLayer> parent_;
1008  int num_children_;
1009  int times_to_lose_on_end_query_;
1010};
1011
1012SINGLE_AND_MULTI_THREAD_TEST_F(
1013    LayerTreeHostContextTestLostContextWhileUpdatingResources);
1014
1015class LayerTreeHostContextTestLayersNotified
1016    : public LayerTreeHostContextTest {
1017 public:
1018  LayerTreeHostContextTestLayersNotified()
1019      : LayerTreeHostContextTest(),
1020        num_commits_(0) {}
1021
1022  virtual void SetupTree() OVERRIDE {
1023    root_ = FakeContentLayer::Create(&client_);
1024    child_ = FakeContentLayer::Create(&client_);
1025    grandchild_ = FakeContentLayer::Create(&client_);
1026
1027    root_->AddChild(child_);
1028    child_->AddChild(grandchild_);
1029
1030    layer_tree_host()->SetRootLayer(root_);
1031    LayerTreeHostContextTest::SetupTree();
1032  }
1033
1034  virtual void BeginTest() OVERRIDE {
1035    PostSetNeedsCommitToMainThread();
1036  }
1037
1038  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
1039    LayerTreeHostContextTest::DidActivateTreeOnThread(host_impl);
1040
1041    FakeContentLayerImpl* root = static_cast<FakeContentLayerImpl*>(
1042        host_impl->active_tree()->root_layer());
1043    FakeContentLayerImpl* child = static_cast<FakeContentLayerImpl*>(
1044        root->children()[0]);
1045    FakeContentLayerImpl* grandchild = static_cast<FakeContentLayerImpl*>(
1046        child->children()[0]);
1047
1048    ++num_commits_;
1049    switch (num_commits_) {
1050      case 1:
1051        EXPECT_EQ(0u, root->lost_output_surface_count());
1052        EXPECT_EQ(0u, child->lost_output_surface_count());
1053        EXPECT_EQ(0u, grandchild->lost_output_surface_count());
1054        // Lose the context and struggle to recreate it.
1055        LoseContext();
1056        times_to_fail_create_ = 1;
1057        break;
1058      case 2:
1059        EXPECT_EQ(1u, root->lost_output_surface_count());
1060        EXPECT_EQ(1u, child->lost_output_surface_count());
1061        EXPECT_EQ(1u, grandchild->lost_output_surface_count());
1062        // Lose the context and again during recreate.
1063        LoseContext();
1064        times_to_lose_on_create_ = 1;
1065        break;
1066      case 3:
1067        EXPECT_EQ(3u, root->lost_output_surface_count());
1068        EXPECT_EQ(3u, child->lost_output_surface_count());
1069        EXPECT_EQ(3u, grandchild->lost_output_surface_count());
1070        // Lose the context and again during reinitialization.
1071        LoseContext();
1072        times_to_fail_initialize_ = 1;
1073        break;
1074      case 4:
1075        EXPECT_EQ(5u, root->lost_output_surface_count());
1076        EXPECT_EQ(5u, child->lost_output_surface_count());
1077        EXPECT_EQ(5u, grandchild->lost_output_surface_count());
1078        EndTest();
1079        break;
1080      default:
1081        NOTREACHED();
1082    }
1083  }
1084
1085  virtual void AfterTest() OVERRIDE {}
1086
1087 private:
1088  int num_commits_;
1089
1090  FakeContentLayerClient client_;
1091  scoped_refptr<FakeContentLayer> root_;
1092  scoped_refptr<FakeContentLayer> child_;
1093  scoped_refptr<FakeContentLayer> grandchild_;
1094};
1095
1096SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified);
1097
1098class LayerTreeHostContextTestDontUseLostResources
1099    : public LayerTreeHostContextTest {
1100 public:
1101  virtual void SetupTree() OVERRIDE {
1102    scoped_refptr<Layer> root_ = Layer::Create();
1103    root_->SetBounds(gfx::Size(10, 10));
1104    root_->SetAnchorPoint(gfx::PointF());
1105    root_->SetIsDrawable(true);
1106
1107    scoped_refptr<FakeDelegatedRendererLayer> delegated_ =
1108        FakeDelegatedRendererLayer::Create(NULL);
1109    delegated_->SetBounds(gfx::Size(10, 10));
1110    delegated_->SetAnchorPoint(gfx::PointF());
1111    delegated_->SetIsDrawable(true);
1112    root_->AddChild(delegated_);
1113
1114    scoped_refptr<ContentLayer> content_ = ContentLayer::Create(&client_);
1115    content_->SetBounds(gfx::Size(10, 10));
1116    content_->SetAnchorPoint(gfx::PointF());
1117    content_->SetIsDrawable(true);
1118    root_->AddChild(content_);
1119
1120    scoped_refptr<TextureLayer> texture_ = TextureLayer::Create(NULL);
1121    texture_->SetBounds(gfx::Size(10, 10));
1122    texture_->SetAnchorPoint(gfx::PointF());
1123    texture_->SetIsDrawable(true);
1124    root_->AddChild(texture_);
1125
1126    scoped_refptr<ContentLayer> mask_ = ContentLayer::Create(&client_);
1127    mask_->SetBounds(gfx::Size(10, 10));
1128    mask_->SetAnchorPoint(gfx::PointF());
1129
1130    scoped_refptr<ContentLayer> content_with_mask_ =
1131        ContentLayer::Create(&client_);
1132    content_with_mask_->SetBounds(gfx::Size(10, 10));
1133    content_with_mask_->SetAnchorPoint(gfx::PointF());
1134    content_with_mask_->SetIsDrawable(true);
1135    content_with_mask_->SetMaskLayer(mask_.get());
1136    root_->AddChild(content_with_mask_);
1137
1138    scoped_refptr<VideoLayer> video_color_ = VideoLayer::Create(
1139        &color_frame_provider_);
1140    video_color_->SetBounds(gfx::Size(10, 10));
1141    video_color_->SetAnchorPoint(gfx::PointF());
1142    video_color_->SetIsDrawable(true);
1143    root_->AddChild(video_color_);
1144
1145    scoped_refptr<VideoLayer> video_hw_ = VideoLayer::Create(
1146        &hw_frame_provider_);
1147    video_hw_->SetBounds(gfx::Size(10, 10));
1148    video_hw_->SetAnchorPoint(gfx::PointF());
1149    video_hw_->SetIsDrawable(true);
1150    root_->AddChild(video_hw_);
1151
1152    scoped_refptr<VideoLayer> video_scaled_hw_ = VideoLayer::Create(
1153        &scaled_hw_frame_provider_);
1154    video_scaled_hw_->SetBounds(gfx::Size(10, 10));
1155    video_scaled_hw_->SetAnchorPoint(gfx::PointF());
1156    video_scaled_hw_->SetIsDrawable(true);
1157    root_->AddChild(video_scaled_hw_);
1158
1159    if (!delegating_renderer()) {
1160      // TODO(danakj): IOSurface layer can not be transported. crbug.com/239335
1161      scoped_refptr<IOSurfaceLayer> io_surface_ = IOSurfaceLayer::Create();
1162      io_surface_->SetBounds(gfx::Size(10, 10));
1163      io_surface_->SetAnchorPoint(gfx::PointF());
1164      io_surface_->SetIsDrawable(true);
1165      io_surface_->SetIOSurfaceProperties(1, gfx::Size(10, 10));
1166      root_->AddChild(io_surface_);
1167    }
1168
1169    // Enable the hud.
1170    LayerTreeDebugState debug_state;
1171    debug_state.show_property_changed_rects = true;
1172    layer_tree_host()->SetDebugState(debug_state);
1173
1174    scoped_refptr<ScrollbarLayer> scrollbar_ = ScrollbarLayer::Create(
1175        scoped_ptr<Scrollbar>(new FakeScrollbar).Pass(),
1176        content_->id());
1177    scrollbar_->SetBounds(gfx::Size(10, 10));
1178    scrollbar_->SetAnchorPoint(gfx::PointF());
1179    scrollbar_->SetIsDrawable(true);
1180    root_->AddChild(scrollbar_);
1181
1182    layer_tree_host()->SetRootLayer(root_);
1183    LayerTreeHostContextTest::SetupTree();
1184  }
1185
1186  virtual void BeginTest() OVERRIDE {
1187    context_should_support_io_surface_ = true;
1188    PostSetNeedsCommitToMainThread();
1189  }
1190
1191  virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
1192    LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
1193
1194    ResourceProvider* resource_provider = host_impl->resource_provider();
1195
1196    if (host_impl->active_tree()->source_frame_number() == 0) {
1197      // Set up impl resources on the first commit.
1198
1199      scoped_ptr<TestRenderPass> pass_for_quad = TestRenderPass::Create();
1200      pass_for_quad->SetNew(
1201          // AppendOneOfEveryQuadType() makes a RenderPass quad with this id.
1202          RenderPass::Id(1, 1),
1203          gfx::Rect(0, 0, 10, 10),
1204          gfx::Rect(0, 0, 10, 10),
1205          gfx::Transform());
1206
1207      scoped_ptr<TestRenderPass> pass = TestRenderPass::Create();
1208      pass->SetNew(
1209          RenderPass::Id(2, 1),
1210          gfx::Rect(0, 0, 10, 10),
1211          gfx::Rect(0, 0, 10, 10),
1212          gfx::Transform());
1213      pass->AppendOneOfEveryQuadType(resource_provider, RenderPass::Id(2, 1));
1214
1215      ScopedPtrVector<RenderPass> pass_list;
1216      pass_list.push_back(pass_for_quad.PassAs<RenderPass>());
1217      pass_list.push_back(pass.PassAs<RenderPass>());
1218
1219      // First child is the delegated layer.
1220      FakeDelegatedRendererLayerImpl* delegated_impl =
1221          static_cast<FakeDelegatedRendererLayerImpl*>(
1222              host_impl->active_tree()->root_layer()->children()[0]);
1223      delegated_impl->SetFrameDataForRenderPasses(&pass_list);
1224      EXPECT_TRUE(pass_list.empty());
1225
1226      // Third child is the texture layer.
1227      TextureLayerImpl* texture_impl =
1228          static_cast<TextureLayerImpl*>(
1229              host_impl->active_tree()->root_layer()->children()[2]);
1230      texture_impl->set_texture_id(
1231          resource_provider->GraphicsContext3D()->createTexture());
1232
1233      DCHECK(resource_provider->GraphicsContext3D());
1234      ResourceProvider::ResourceId texture = resource_provider->CreateResource(
1235          gfx::Size(4, 4),
1236          resource_provider->default_resource_type(),
1237          ResourceProvider::TextureUsageAny);
1238      ResourceProvider::ScopedWriteLockGL lock(resource_provider, texture);
1239
1240      gpu::Mailbox mailbox;
1241      resource_provider->GraphicsContext3D()->genMailboxCHROMIUM(mailbox.name);
1242      unsigned sync_point =
1243          resource_provider->GraphicsContext3D()->insertSyncPoint();
1244
1245      color_video_frame_ = VideoFrame::CreateColorFrame(
1246          gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
1247      hw_video_frame_ = VideoFrame::WrapNativeTexture(
1248          new VideoFrame::MailboxHolder(
1249              mailbox,
1250              sync_point,
1251              VideoFrame::MailboxHolder::TextureNoLongerNeededCallback()),
1252          GL_TEXTURE_2D,
1253          gfx::Size(4, 4), gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4),
1254          base::TimeDelta(),
1255          VideoFrame::ReadPixelsCB(),
1256          base::Closure());
1257      scaled_hw_video_frame_ = VideoFrame::WrapNativeTexture(
1258          new VideoFrame::MailboxHolder(
1259              mailbox,
1260              sync_point,
1261              VideoFrame::MailboxHolder::TextureNoLongerNeededCallback()),
1262          GL_TEXTURE_2D,
1263          gfx::Size(4, 4), gfx::Rect(0, 0, 3, 2), gfx::Size(4, 4),
1264          base::TimeDelta(),
1265          VideoFrame::ReadPixelsCB(),
1266          base::Closure());
1267
1268      color_frame_provider_.set_frame(color_video_frame_);
1269      hw_frame_provider_.set_frame(hw_video_frame_);
1270      scaled_hw_frame_provider_.set_frame(scaled_hw_video_frame_);
1271      return;
1272    }
1273
1274    if (host_impl->active_tree()->source_frame_number() == 3) {
1275      // On the third commit we're recovering from context loss. Hardware
1276      // video frames should not be reused by the VideoFrameProvider, but
1277      // software frames can be.
1278      hw_frame_provider_.set_frame(NULL);
1279      scaled_hw_frame_provider_.set_frame(NULL);
1280    }
1281  }
1282
1283  virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
1284                                     LayerTreeHostImpl::FrameData* frame,
1285                                     bool result) OVERRIDE {
1286    if (host_impl->active_tree()->source_frame_number() == 2) {
1287      // Lose the context during draw on the second commit. This will cause
1288      // a third commit to recover.
1289      if (context3d_)
1290        context3d_->set_times_bind_texture_succeeds(4);
1291    }
1292    return true;
1293  }
1294
1295  virtual void DidCommitAndDrawFrame() OVERRIDE {
1296    ASSERT_TRUE(layer_tree_host()->hud_layer());
1297    // End the test once we know the 3nd frame drew.
1298    if (layer_tree_host()->source_frame_number() == 4)
1299      EndTest();
1300    else
1301      layer_tree_host()->SetNeedsCommit();
1302  }
1303
1304  virtual void AfterTest() OVERRIDE {}
1305
1306 private:
1307  FakeContentLayerClient client_;
1308
1309  scoped_refptr<Layer> root_;
1310  scoped_refptr<DelegatedRendererLayer> delegated_;
1311  scoped_refptr<ContentLayer> content_;
1312  scoped_refptr<TextureLayer> texture_;
1313  scoped_refptr<ContentLayer> mask_;
1314  scoped_refptr<ContentLayer> content_with_mask_;
1315  scoped_refptr<VideoLayer> video_color_;
1316  scoped_refptr<VideoLayer> video_hw_;
1317  scoped_refptr<VideoLayer> video_scaled_hw_;
1318  scoped_refptr<IOSurfaceLayer> io_surface_;
1319  scoped_refptr<ScrollbarLayer> scrollbar_;
1320
1321  scoped_refptr<VideoFrame> color_video_frame_;
1322  scoped_refptr<VideoFrame> hw_video_frame_;
1323  scoped_refptr<VideoFrame> scaled_hw_video_frame_;
1324
1325  FakeVideoFrameProvider color_frame_provider_;
1326  FakeVideoFrameProvider hw_frame_provider_;
1327  FakeVideoFrameProvider scaled_hw_frame_provider_;
1328};
1329
1330SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources);
1331
1332class LayerTreeHostContextTestLosesFirstOutputSurface
1333    : public LayerTreeHostContextTest {
1334 public:
1335  LayerTreeHostContextTestLosesFirstOutputSurface() {
1336    // Always fail. This needs to be set before LayerTreeHost is created.
1337    times_to_lose_on_create_ = 1000;
1338  }
1339
1340  virtual void BeginTest() OVERRIDE {
1341    PostSetNeedsCommitToMainThread();
1342  }
1343
1344  virtual void AfterTest() OVERRIDE {}
1345
1346  virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
1347    EXPECT_FALSE(succeeded);
1348
1349    // If we make it this far without crashing, we pass!
1350    EndTest();
1351  }
1352
1353  virtual void DidCommitAndDrawFrame() OVERRIDE {
1354    EXPECT_TRUE(false);
1355  }
1356};
1357
1358SINGLE_AND_MULTI_THREAD_TEST_F(
1359    LayerTreeHostContextTestLosesFirstOutputSurface);
1360
1361class LayerTreeHostContextTestRetriesFirstInitializationAndSucceeds
1362    : public LayerTreeHostContextTest {
1363 public:
1364  virtual void AfterTest() OVERRIDE {}
1365
1366  virtual void BeginTest() OVERRIDE {
1367    times_to_fail_initialize_ = 2;
1368    PostSetNeedsCommitToMainThread();
1369  }
1370
1371  virtual void DidCommitAndDrawFrame() OVERRIDE {
1372    EndTest();
1373  }
1374};
1375
1376SINGLE_AND_MULTI_THREAD_TEST_F(
1377    LayerTreeHostContextTestRetriesFirstInitializationAndSucceeds);
1378
1379class LayerTreeHostContextTestRetryWorksWithForcedInit
1380    : public LayerTreeHostContextTestRetriesFirstInitializationAndSucceeds {
1381 public:
1382  virtual void DidFailToInitializeOutputSurface() OVERRIDE {
1383    LayerTreeHostContextTestRetriesFirstInitializationAndSucceeds
1384        ::DidFailToInitializeOutputSurface();
1385
1386    if (times_create_failed_ == 1) {
1387      // CompositeAndReadback force recreates the output surface, which should
1388      // fail.
1389      char pixels[4];
1390      EXPECT_FALSE(layer_tree_host()->CompositeAndReadback(
1391            &pixels, gfx::Rect(1, 1)));
1392    }
1393  }
1394};
1395
1396SINGLE_AND_MULTI_THREAD_TEST_F(
1397    LayerTreeHostContextTestRetryWorksWithForcedInit);
1398
1399class LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit
1400    : public LayerTreeHostContextTest {
1401 public:
1402  virtual void BeginTest() OVERRIDE {
1403    // This must be called immediately after creating LTH, before the first
1404    // OutputSurface is initialized.
1405    ASSERT_TRUE(layer_tree_host()->output_surface_lost());
1406
1407    times_output_surface_created_ = 0;
1408
1409    char pixels[4];
1410    bool result = layer_tree_host()->CompositeAndReadback(
1411        &pixels, gfx::Rect(1, 1));
1412    EXPECT_EQ(!delegating_renderer(), result);
1413    EXPECT_EQ(1, times_output_surface_created_);
1414
1415    PostSetNeedsCommitToMainThread();
1416  }
1417
1418  virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
1419    EXPECT_TRUE(succeeded);
1420    ++times_output_surface_created_;
1421  }
1422
1423  virtual void DidCommitAndDrawFrame() OVERRIDE {
1424    EndTest();
1425  }
1426
1427  virtual void AfterTest() OVERRIDE {
1428    // Should not try to create output surface again after successfully
1429    // created by CompositeAndReadback.
1430    EXPECT_EQ(1, times_output_surface_created_);
1431  }
1432
1433 private:
1434  int times_output_surface_created_;
1435};
1436
1437SINGLE_AND_MULTI_THREAD_TEST_F(
1438    LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit);
1439
1440class ImplSidePaintingLayerTreeHostContextTest
1441    : public LayerTreeHostContextTest {
1442 public:
1443  virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
1444    settings->impl_side_painting = true;
1445  }
1446};
1447
1448class LayerTreeHostContextTestImplSidePainting
1449    : public ImplSidePaintingLayerTreeHostContextTest {
1450 public:
1451  virtual void SetupTree() OVERRIDE {
1452    scoped_refptr<Layer> root = Layer::Create();
1453    root->SetBounds(gfx::Size(10, 10));
1454    root->SetAnchorPoint(gfx::PointF());
1455    root->SetIsDrawable(true);
1456
1457    scoped_refptr<PictureLayer> picture = PictureLayer::Create(&client_);
1458    picture->SetBounds(gfx::Size(10, 10));
1459    picture->SetAnchorPoint(gfx::PointF());
1460    picture->SetIsDrawable(true);
1461    root->AddChild(picture);
1462
1463    layer_tree_host()->SetRootLayer(root);
1464    LayerTreeHostContextTest::SetupTree();
1465  }
1466
1467  virtual void BeginTest() OVERRIDE {
1468    times_to_lose_during_commit_ = 1;
1469    PostSetNeedsCommitToMainThread();
1470  }
1471
1472  virtual void AfterTest() OVERRIDE {}
1473
1474  virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
1475    EXPECT_TRUE(succeeded);
1476    EndTest();
1477  }
1478
1479 private:
1480  FakeContentLayerClient client_;
1481};
1482
1483MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting);
1484
1485class ScrollbarLayerLostContext : public LayerTreeHostContextTest {
1486 public:
1487  ScrollbarLayerLostContext() : commits_(0) {}
1488
1489  virtual void BeginTest() OVERRIDE {
1490    scoped_refptr<Layer> scroll_layer = Layer::Create();
1491    scrollbar_layer_ = FakeScrollbarLayer::Create(
1492        false, true, scroll_layer->id());
1493    scrollbar_layer_->SetBounds(gfx::Size(10, 100));
1494    layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
1495    layer_tree_host()->root_layer()->AddChild(scroll_layer);
1496    PostSetNeedsCommitToMainThread();
1497  }
1498
1499  virtual void AfterTest() OVERRIDE {}
1500
1501  virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1502    LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1503
1504    ++commits_;
1505    size_t upload_count = scrollbar_layer_->last_update_full_upload_size() +
1506        scrollbar_layer_->last_update_partial_upload_size();
1507    switch (commits_) {
1508      case 1:
1509        // First (regular) update, we should upload 2 resources (thumb, and
1510        // backtrack).
1511        EXPECT_EQ(1, scrollbar_layer_->update_count());
1512        EXPECT_EQ(2u, upload_count);
1513        LoseContext();
1514        break;
1515      case 2:
1516        // Second update, after the lost context, we should still upload 2
1517        // resources even if the contents haven't changed.
1518        EXPECT_EQ(2, scrollbar_layer_->update_count());
1519        EXPECT_EQ(2u, upload_count);
1520        EndTest();
1521        break;
1522      default:
1523        NOTREACHED();
1524    }
1525  }
1526
1527 private:
1528  int commits_;
1529  scoped_refptr<FakeScrollbarLayer> scrollbar_layer_;
1530};
1531
1532SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext);
1533
1534class LayerTreeHostContextTestFailsToCreateSurface
1535    : public LayerTreeHostContextTest {
1536 public:
1537  LayerTreeHostContextTestFailsToCreateSurface()
1538      : LayerTreeHostContextTest(),
1539        failure_count_(0) {
1540    times_to_lose_on_create_ = 10;
1541  }
1542
1543  virtual void BeginTest() OVERRIDE {
1544    PostSetNeedsCommitToMainThread();
1545  }
1546
1547  virtual void AfterTest() OVERRIDE {}
1548
1549  virtual void DidInitializeOutputSurface(bool success) OVERRIDE {
1550    EXPECT_FALSE(success);
1551    EXPECT_EQ(0, failure_count_);
1552    times_to_lose_on_create_ = 0;
1553    failure_count_++;
1554    // Normally, the embedder should stop trying to use the compositor at
1555    // this point, but let's force it back into action when we shouldn't.
1556    char pixels[4];
1557    EXPECT_FALSE(
1558        layer_tree_host()->CompositeAndReadback(pixels, gfx::Rect(1, 1)));
1559    // If we've made it this far without crashing, we've succeeded.
1560    EndTest();
1561  }
1562
1563 private:
1564  int failure_count_;
1565};
1566
1567SINGLE_AND_MULTI_THREAD_TEST_F(
1568    LayerTreeHostContextTestFailsToCreateSurface);
1569
1570// Not reusing LayerTreeTest because it expects creating LTH to always succeed.
1571class LayerTreeHostTestCannotCreateIfCannotCreateOutputSurface
1572    : public testing::Test,
1573      public FakeLayerTreeHostClient {
1574 public:
1575  LayerTreeHostTestCannotCreateIfCannotCreateOutputSurface()
1576      : FakeLayerTreeHostClient(FakeLayerTreeHostClient::DIRECT_3D) {}
1577
1578  // FakeLayerTreeHostClient implementation.
1579  virtual scoped_ptr<OutputSurface> CreateOutputSurface() OVERRIDE {
1580    return scoped_ptr<OutputSurface>();
1581  }
1582
1583  void RunTest(bool threaded,
1584               bool delegating_renderer,
1585               bool impl_side_painting) {
1586    scoped_ptr<base::Thread> impl_thread;
1587    if (threaded) {
1588      impl_thread.reset(new base::Thread("LayerTreeTest"));
1589      ASSERT_TRUE(impl_thread->Start());
1590      ASSERT_TRUE(impl_thread->message_loop_proxy().get());
1591    }
1592
1593    LayerTreeSettings settings;
1594    settings.impl_side_painting = impl_side_painting;
1595    scoped_ptr<LayerTreeHost> layer_tree_host = LayerTreeHost::Create(
1596        this,
1597        settings,
1598        impl_thread ? impl_thread->message_loop_proxy() : NULL);
1599    EXPECT_FALSE(layer_tree_host);
1600  }
1601};
1602
1603SINGLE_AND_MULTI_THREAD_TEST_F(
1604    LayerTreeHostTestCannotCreateIfCannotCreateOutputSurface);
1605
1606}  // namespace
1607}  // namespace cc
1608