[Mac] Convert ServiceApplication to not need a custom NSApp class.
[chromium-blink-merge.git] / cc / trees / layer_tree_host_unittest_context.cc
blob20f51149c0add0c625e57b3cc96b67acc862981e
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.
5 #include "cc/trees/layer_tree_host.h"
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/video_layer.h"
16 #include "cc/layers/video_layer_impl.h"
17 #include "cc/test/fake_content_layer.h"
18 #include "cc/test/fake_content_layer_client.h"
19 #include "cc/test/fake_content_layer_impl.h"
20 #include "cc/test/fake_context_provider.h"
21 #include "cc/test/fake_delegated_renderer_layer.h"
22 #include "cc/test/fake_delegated_renderer_layer_impl.h"
23 #include "cc/test/fake_output_surface.h"
24 #include "cc/test/fake_scrollbar_layer.h"
25 #include "cc/test/fake_scrollbar_theme_painter.h"
26 #include "cc/test/fake_video_frame_provider.h"
27 #include "cc/test/fake_web_scrollbar.h"
28 #include "cc/test/fake_web_scrollbar_theme_geometry.h"
29 #include "cc/test/layer_tree_test.h"
30 #include "cc/test/render_pass_test_common.h"
31 #include "cc/test/test_web_graphics_context_3d.h"
32 #include "cc/trees/layer_tree_host_impl.h"
33 #include "cc/trees/layer_tree_impl.h"
34 #include "cc/trees/single_thread_proxy.h"
35 #include "gpu/GLES2/gl2extchromium.h"
36 #include "media/base/media.h"
37 #include "third_party/WebKit/Source/Platform/chromium/public/WebFilterOperations.h"
39 using media::VideoFrame;
40 using WebKit::WebGraphicsContext3D;
42 namespace cc {
43 namespace {
45 // These tests deal with losing the 3d graphics context.
46 class 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_recreate_retried_(0),
62 times_recreate_retried_(0),
63 times_offscreen_created_(0),
64 committed_at_least_once_(false) {
65 media::InitializeMediaLibraryForTesting();
68 void LoseContext() {
69 context3d_->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
70 GL_INNOCENT_CONTEXT_RESET_ARB);
71 context3d_ = NULL;
74 virtual scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() {
75 return TestWebGraphicsContext3D::Create();
78 virtual scoped_ptr<OutputSurface> CreateOutputSurface() OVERRIDE {
79 if (times_to_fail_create_) {
80 --times_to_fail_create_;
81 ExpectRecreateToRetry();
82 return scoped_ptr<OutputSurface>();
85 scoped_ptr<TestWebGraphicsContext3D> context3d = CreateContext3d();
86 context3d_ = context3d.get();
88 if (times_to_fail_initialize_) {
89 --times_to_fail_initialize_;
90 // Make the context get lost during reinitialization.
91 // The number of times MakeCurrent succeeds is not important, and
92 // can be changed if needed to make this pass with future changes.
93 context3d_->set_times_make_current_succeeds(2);
94 ExpectRecreateToRetry();
95 } else if (times_to_lose_on_create_) {
96 --times_to_lose_on_create_;
97 LoseContext();
98 ExpectRecreateToRetry();
101 return FakeOutputSurface::Create3d(
102 context3d.PassAs<WebGraphicsContext3D>()).PassAs<OutputSurface>();
105 scoped_ptr<TestWebGraphicsContext3D> CreateOffscreenContext3d() {
106 if (!context3d_)
107 return scoped_ptr<TestWebGraphicsContext3D>();
109 ++times_offscreen_created_;
111 if (times_to_fail_create_offscreen_) {
112 --times_to_fail_create_offscreen_;
113 ExpectRecreateToRetry();
114 return scoped_ptr<TestWebGraphicsContext3D>();
117 scoped_ptr<TestWebGraphicsContext3D> offscreen_context3d =
118 TestWebGraphicsContext3D::Create().Pass();
119 DCHECK(offscreen_context3d);
120 context3d_->add_share_group_context(offscreen_context3d.get());
122 return offscreen_context3d.Pass();
125 virtual scoped_refptr<cc::ContextProvider>
126 OffscreenContextProviderForMainThread() OVERRIDE {
127 DCHECK(!ImplThread());
129 if (!offscreen_contexts_main_thread_ ||
130 offscreen_contexts_main_thread_->DestroyedOnMainThread()) {
131 offscreen_contexts_main_thread_ = FakeContextProvider::Create(
132 base::Bind(&LayerTreeHostContextTest::CreateOffscreenContext3d,
133 base::Unretained(this)));
134 if (offscreen_contexts_main_thread_ &&
135 !offscreen_contexts_main_thread_->BindToCurrentThread())
136 offscreen_contexts_main_thread_ = NULL;
138 return offscreen_contexts_main_thread_;
141 virtual scoped_refptr<cc::ContextProvider>
142 OffscreenContextProviderForCompositorThread() OVERRIDE {
143 DCHECK(ImplThread());
145 if (!offscreen_contexts_compositor_thread_ ||
146 offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) {
147 offscreen_contexts_compositor_thread_ = FakeContextProvider::Create(
148 base::Bind(&LayerTreeHostContextTest::CreateOffscreenContext3d,
149 base::Unretained(this)));
151 return offscreen_contexts_compositor_thread_;
154 virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
155 LayerTreeHostImpl::FrameData* frame,
156 bool result)
157 OVERRIDE {
158 bool expect_success = !frame->has_no_damage;
159 EXPECT_EQ(expect_success, result);
160 if (!times_to_lose_during_draw_)
161 return result;
163 --times_to_lose_during_draw_;
164 context3d_->set_times_make_current_succeeds(0);
166 times_to_fail_create_ = times_to_fail_recreate_;
167 times_to_fail_recreate_ = 0;
168 times_to_fail_initialize_ = times_to_fail_reinitialize_;
169 times_to_fail_reinitialize_ = 0;
170 times_to_lose_on_create_ = times_to_lose_on_recreate_;
171 times_to_lose_on_recreate_ = 0;
172 times_to_fail_create_offscreen_ = times_to_fail_recreate_offscreen_;
173 times_to_fail_recreate_offscreen_ = 0;
175 return result;
178 virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
179 committed_at_least_once_ = true;
181 if (!times_to_lose_during_commit_)
182 return;
183 --times_to_lose_during_commit_;
184 LoseContext();
186 times_to_fail_create_ = times_to_fail_recreate_;
187 times_to_fail_recreate_ = 0;
188 times_to_fail_initialize_ = times_to_fail_reinitialize_;
189 times_to_fail_reinitialize_ = 0;
190 times_to_lose_on_create_ = times_to_lose_on_recreate_;
191 times_to_lose_on_recreate_ = 0;
192 times_to_fail_create_offscreen_ = times_to_fail_recreate_offscreen_;
193 times_to_fail_recreate_offscreen_ = 0;
196 virtual void WillRetryRecreateOutputSurface() OVERRIDE {
197 ++times_recreate_retried_;
200 virtual void TearDown() OVERRIDE {
201 LayerTreeTest::TearDown();
202 EXPECT_EQ(times_to_expect_recreate_retried_, times_recreate_retried_);
205 void ExpectRecreateToRetry() {
206 if (committed_at_least_once_)
207 ++times_to_expect_recreate_retried_;
210 protected:
211 TestWebGraphicsContext3D* context3d_;
212 int times_to_fail_create_;
213 int times_to_fail_initialize_;
214 int times_to_lose_on_create_;
215 int times_to_lose_during_commit_;
216 int times_to_lose_during_draw_;
217 int times_to_fail_recreate_;
218 int times_to_fail_reinitialize_;
219 int times_to_lose_on_recreate_;
220 int times_to_fail_create_offscreen_;
221 int times_to_fail_recreate_offscreen_;
222 int times_to_expect_recreate_retried_;
223 int times_recreate_retried_;
224 int times_offscreen_created_;
225 bool committed_at_least_once_;
227 scoped_refptr<FakeContextProvider> offscreen_contexts_main_thread_;
228 scoped_refptr<FakeContextProvider> offscreen_contexts_compositor_thread_;
231 class LayerTreeHostContextTestLostContextSucceeds
232 : public LayerTreeHostContextTest {
233 public:
234 LayerTreeHostContextTestLostContextSucceeds()
235 : LayerTreeHostContextTest(),
236 test_case_(0),
237 num_losses_(0),
238 recovered_context_(true) {}
240 virtual void BeginTest() OVERRIDE {
241 PostSetNeedsCommitToMainThread();
244 virtual void DidRecreateOutputSurface(bool succeeded) OVERRIDE {
245 EXPECT_TRUE(succeeded);
246 ++num_losses_;
247 recovered_context_ = true;
250 virtual void AfterTest() OVERRIDE {
251 EXPECT_EQ(10u, test_case_);
252 EXPECT_EQ(8 + 10 + 10, num_losses_);
255 virtual void DidCommitAndDrawFrame() OVERRIDE {
256 // If the last frame had a context loss, then we'll commit again to
257 // recover.
258 if (!recovered_context_)
259 return;
260 if (times_to_lose_during_commit_)
261 return;
262 if (times_to_lose_during_draw_)
263 return;
265 recovered_context_ = false;
266 if (NextTestCase())
267 InvalidateAndSetNeedsCommit();
268 else
269 EndTest();
272 virtual void InvalidateAndSetNeedsCommit() {
273 // Cause damage so we try to draw.
274 layer_tree_host()->root_layer()->SetNeedsDisplay();
277 bool NextTestCase() {
278 static const TestCase kTests[] = {
279 // Losing the context and failing to recreate it (or losing it again
280 // immediately) a small number of times should succeed.
281 { 1, // times_to_lose_during_commit
282 0, // times_to_lose_during_draw
283 3, // times_to_fail_reinitialize
284 0, // times_to_fail_recreate
285 0, // times_to_lose_on_recreate
286 0, // times_to_fail_recreate_offscreen
288 { 0, // times_to_lose_during_commit
289 1, // times_to_lose_during_draw
290 3, // times_to_fail_reinitialize
291 0, // times_to_fail_recreate
292 0, // times_to_lose_on_recreate
293 0, // times_to_fail_recreate_offscreen
295 { 1, // times_to_lose_during_commit
296 0, // times_to_lose_during_draw
297 0, // times_to_fail_reinitialize
298 3, // times_to_fail_recreate
299 0, // times_to_lose_on_recreate
300 0, // times_to_fail_recreate_offscreen
302 { 0, // times_to_lose_during_commit
303 1, // times_to_lose_during_draw
304 0, // times_to_fail_reinitialize
305 3, // times_to_fail_recreate
306 0, // times_to_lose_on_recreate
307 0, // times_to_fail_recreate_offscreen
309 { 1, // times_to_lose_during_commit
310 0, // times_to_lose_during_draw
311 0, // times_to_fail_reinitialize
312 0, // times_to_fail_recreate
313 3, // times_to_lose_on_recreate
314 0, // times_to_fail_recreate_offscreen
316 { 0, // times_to_lose_during_commit
317 1, // times_to_lose_during_draw
318 0, // times_to_fail_reinitialize
319 0, // times_to_fail_recreate
320 3, // times_to_lose_on_recreate
321 0, // times_to_fail_recreate_offscreen
323 { 1, // times_to_lose_during_commit
324 0, // times_to_lose_during_draw
325 0, // times_to_fail_reinitialize
326 0, // times_to_fail_recreate
327 0, // times_to_lose_on_recreate
328 3, // times_to_fail_recreate_offscreen
330 { 0, // times_to_lose_during_commit
331 1, // times_to_lose_during_draw
332 0, // times_to_fail_reinitialize
333 0, // times_to_fail_recreate
334 0, // times_to_lose_on_recreate
335 3, // times_to_fail_recreate_offscreen
337 // Losing the context and recreating it any number of times should
338 // succeed.
339 { 10, // times_to_lose_during_commit
340 0, // times_to_lose_during_draw
341 0, // times_to_fail_reinitialize
342 0, // times_to_fail_recreate
343 0, // times_to_lose_on_recreate
344 0, // times_to_fail_recreate_offscreen
346 { 0, // times_to_lose_during_commit
347 10, // times_to_lose_during_draw
348 0, // times_to_fail_reinitialize
349 0, // times_to_fail_recreate
350 0, // times_to_lose_on_recreate
351 0, // times_to_fail_recreate_offscreen
355 if (test_case_ >= arraysize(kTests))
356 return false;
358 times_to_lose_during_commit_ =
359 kTests[test_case_].times_to_lose_during_commit;
360 times_to_lose_during_draw_ =
361 kTests[test_case_].times_to_lose_during_draw;
362 times_to_fail_reinitialize_ = kTests[test_case_].times_to_fail_reinitialize;
363 times_to_fail_recreate_ = kTests[test_case_].times_to_fail_recreate;
364 times_to_lose_on_recreate_ = kTests[test_case_].times_to_lose_on_recreate;
365 times_to_fail_recreate_offscreen_ =
366 kTests[test_case_].times_to_fail_recreate_offscreen;
367 ++test_case_;
368 return true;
371 struct TestCase {
372 int times_to_lose_during_commit;
373 int times_to_lose_during_draw;
374 int times_to_fail_reinitialize;
375 int times_to_fail_recreate;
376 int times_to_lose_on_recreate;
377 int times_to_fail_recreate_offscreen;
380 protected:
381 size_t test_case_;
382 int num_losses_;
383 bool recovered_context_;
386 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLostContextSucceeds);
388 class LayerTreeHostContextTestLostContextSucceedsWithContent
389 : public LayerTreeHostContextTestLostContextSucceeds {
390 public:
391 LayerTreeHostContextTestLostContextSucceedsWithContent()
392 : LayerTreeHostContextTestLostContextSucceeds() {}
394 virtual void SetupTree() OVERRIDE {
395 root_ = Layer::Create();
396 root_->SetBounds(gfx::Size(10, 10));
397 root_->SetAnchorPoint(gfx::PointF());
398 root_->SetIsDrawable(true);
400 content_ = FakeContentLayer::Create(&client_);
401 content_->SetBounds(gfx::Size(10, 10));
402 content_->SetAnchorPoint(gfx::PointF());
403 content_->SetIsDrawable(true);
404 if (use_surface_) {
405 content_->SetForceRenderSurface(true);
406 // Filters require us to create an offscreen context.
407 WebKit::WebFilterOperations filters;
408 filters.append(WebKit::WebFilterOperation::createGrayscaleFilter(0.5f));
409 content_->SetFilters(filters);
410 content_->SetBackgroundFilters(filters);
413 root_->AddChild(content_);
415 layer_tree_host()->SetRootLayer(root_);
416 LayerTreeHostContextTest::SetupTree();
419 virtual void InvalidateAndSetNeedsCommit() OVERRIDE {
420 // Invalidate the render surface so we don't try to use a cached copy of the
421 // surface. We want to make sure to test the drawing paths for drawing to
422 // a child surface.
423 content_->SetNeedsDisplay();
424 LayerTreeHostContextTestLostContextSucceeds::InvalidateAndSetNeedsCommit();
427 virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
428 FakeContentLayerImpl* content_impl = static_cast<FakeContentLayerImpl*>(
429 host_impl->active_tree()->root_layer()->children()[0]);
430 // Even though the context was lost, we should have a resource. The
431 // TestWebGraphicsContext3D ensures that this resource is created with
432 // the active context.
433 EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0));
435 cc::ContextProvider* contexts =
436 host_impl->resource_provider()->offscreen_context_provider();
437 if (use_surface_) {
438 EXPECT_TRUE(contexts->Context3d());
439 // TODO(danakj): Make a fake GrContext.
440 // EXPECT_TRUE(contexts->GrContext());
441 } else {
442 EXPECT_FALSE(contexts);
446 virtual void AfterTest() OVERRIDE {
447 LayerTreeHostContextTestLostContextSucceeds::AfterTest();
448 if (use_surface_) {
449 // 1 create to start with +
450 // 6 from test cases that fail on initializing the renderer (after the
451 // offscreen context is created) +
452 // 6 from test cases that lose the offscreen context directly +
453 // All the test cases that recreate both contexts only once
454 // per time it is lost.
455 EXPECT_EQ(6 + 6 + 1 + num_losses_, times_offscreen_created_);
456 } else {
457 EXPECT_EQ(0, times_offscreen_created_);
461 protected:
462 bool use_surface_;
463 FakeContentLayerClient client_;
464 scoped_refptr<Layer> root_;
465 scoped_refptr<ContentLayer> content_;
468 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
469 NoSurface_SingleThread) {
470 use_surface_ = false;
471 RunTest(false);
474 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
475 NoSurface_MultiThread) {
476 use_surface_ = false;
477 RunTest(true);
480 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
481 WithSurface_SingleThread) {
482 use_surface_ = true;
483 RunTest(false);
486 TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
487 WithSurface_MultiThread) {
488 use_surface_ = true;
489 RunTest(true);
492 class LayerTreeHostContextTestOffscreenContextFails
493 : public LayerTreeHostContextTest {
494 public:
495 virtual void SetupTree() OVERRIDE {
496 root_ = Layer::Create();
497 root_->SetBounds(gfx::Size(10, 10));
498 root_->SetAnchorPoint(gfx::PointF());
499 root_->SetIsDrawable(true);
501 content_ = FakeContentLayer::Create(&client_);
502 content_->SetBounds(gfx::Size(10, 10));
503 content_->SetAnchorPoint(gfx::PointF());
504 content_->SetIsDrawable(true);
505 content_->SetForceRenderSurface(true);
506 // Filters require us to create an offscreen context.
507 WebKit::WebFilterOperations filters;
508 filters.append(WebKit::WebFilterOperation::createGrayscaleFilter(0.5f));
509 content_->SetFilters(filters);
510 content_->SetBackgroundFilters(filters);
512 root_->AddChild(content_);
514 layer_tree_host()->SetRootLayer(root_);
515 LayerTreeHostContextTest::SetupTree();
518 virtual void BeginTest() OVERRIDE {
519 times_to_fail_create_offscreen_ = 1;
520 PostSetNeedsCommitToMainThread();
523 virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
524 cc::ContextProvider* contexts =
525 host_impl->resource_provider()->offscreen_context_provider();
526 EXPECT_FALSE(contexts);
527 EndTest();
530 virtual void AfterTest() OVERRIDE {}
532 protected:
533 FakeContentLayerClient client_;
534 scoped_refptr<Layer> root_;
535 scoped_refptr<ContentLayer> content_;
538 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestOffscreenContextFails);
540 class LayerTreeHostContextTestLostContextFails
541 : public LayerTreeHostContextTest {
542 public:
543 LayerTreeHostContextTestLostContextFails()
544 : LayerTreeHostContextTest(),
545 num_commits_(0) {
546 times_to_lose_during_commit_ = 1;
549 virtual void BeginTest() OVERRIDE {
550 PostSetNeedsCommitToMainThread();
553 virtual void DidRecreateOutputSurface(bool succeeded) OVERRIDE {
554 EXPECT_FALSE(succeeded);
555 EndTest();
558 virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
559 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
561 ++num_commits_;
562 if (num_commits_ == 1) {
563 // When the context is ok, we should have these things.
564 EXPECT_TRUE(host_impl->output_surface());
565 EXPECT_TRUE(host_impl->renderer());
566 EXPECT_TRUE(host_impl->resource_provider());
567 return;
570 // When context recreation fails we shouldn't be left with any of them.
571 EXPECT_FALSE(host_impl->output_surface());
572 EXPECT_FALSE(host_impl->renderer());
573 EXPECT_FALSE(host_impl->resource_provider());
576 virtual void AfterTest() OVERRIDE {}
578 private:
579 int num_commits_;
582 TEST_F(LayerTreeHostContextTestLostContextFails,
583 FailReinitialize100_SingleThread) {
584 times_to_fail_reinitialize_ = 100;
585 times_to_fail_recreate_ = 0;
586 times_to_lose_on_recreate_ = 0;
587 RunTest(false);
590 TEST_F(LayerTreeHostContextTestLostContextFails,
591 FailReinitialize100_MultiThread) {
592 times_to_fail_reinitialize_ = 100;
593 times_to_fail_recreate_ = 0;
594 times_to_lose_on_recreate_ = 0;
595 RunTest(true);
598 TEST_F(LayerTreeHostContextTestLostContextFails,
599 FailRecreate100_SingleThread) {
600 times_to_fail_reinitialize_ = 0;
601 times_to_fail_recreate_ = 100;
602 times_to_lose_on_recreate_ = 0;
603 RunTest(false);
606 TEST_F(LayerTreeHostContextTestLostContextFails,
607 FailRecreate100_MultiThread) {
608 times_to_fail_reinitialize_ = 0;
609 times_to_fail_recreate_ = 100;
610 times_to_lose_on_recreate_ = 0;
611 RunTest(true);
614 TEST_F(LayerTreeHostContextTestLostContextFails,
615 LoseOnRecreate100_SingleThread) {
616 times_to_fail_reinitialize_ = 0;
617 times_to_fail_recreate_ = 0;
618 times_to_lose_on_recreate_ = 100;
619 RunTest(false);
622 TEST_F(LayerTreeHostContextTestLostContextFails,
623 LoseOnRecreate100_MultiThread) {
624 times_to_fail_reinitialize_ = 0;
625 times_to_fail_recreate_ = 0;
626 times_to_lose_on_recreate_ = 100;
627 RunTest(true);
630 class LayerTreeHostContextTestFinishAllRenderingAfterLoss
631 : public LayerTreeHostContextTest {
632 public:
633 virtual void BeginTest() OVERRIDE {
634 // Lose the context until the compositor gives up on it.
635 times_to_lose_during_commit_ = 1;
636 times_to_fail_reinitialize_ = 10;
637 PostSetNeedsCommitToMainThread();
640 virtual void DidRecreateOutputSurface(bool succeeded) OVERRIDE {
641 EXPECT_FALSE(succeeded);
642 layer_tree_host()->FinishAllRendering();
643 EndTest();
646 virtual void AfterTest() OVERRIDE {}
649 SINGLE_AND_MULTI_THREAD_TEST_F(
650 LayerTreeHostContextTestFinishAllRenderingAfterLoss);
652 class LayerTreeHostContextTestLostContextAndEvictTextures
653 : public LayerTreeHostContextTest {
654 public:
655 LayerTreeHostContextTestLostContextAndEvictTextures()
656 : LayerTreeHostContextTest(),
657 layer_(FakeContentLayer::Create(&client_)),
658 impl_host_(0),
659 num_commits_(0) {}
661 virtual void SetupTree() OVERRIDE {
662 layer_->SetBounds(gfx::Size(10, 20));
663 layer_tree_host()->SetRootLayer(layer_);
664 LayerTreeHostContextTest::SetupTree();
667 virtual void BeginTest() OVERRIDE {
668 PostSetNeedsCommitToMainThread();
671 void PostEvictTextures() {
672 if (ImplThread()) {
673 ImplThread()->PostTask(
674 base::Bind(
675 &LayerTreeHostContextTestLostContextAndEvictTextures::
676 EvictTexturesOnImplThread,
677 base::Unretained(this)));
678 } else {
679 DebugScopedSetImplThread impl(proxy());
680 EvictTexturesOnImplThread();
684 void EvictTexturesOnImplThread() {
685 impl_host_->EnforceManagedMemoryPolicy(ManagedMemoryPolicy(0));
686 if (lose_after_evict_)
687 LoseContext();
690 virtual void DidCommitAndDrawFrame() OVERRIDE {
691 if (num_commits_ > 1)
692 return;
693 EXPECT_TRUE(layer_->HaveBackingAt(0, 0));
694 PostEvictTextures();
697 virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
698 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
699 if (num_commits_ > 1)
700 return;
701 ++num_commits_;
702 if (!lose_after_evict_)
703 LoseContext();
704 impl_host_ = impl;
707 virtual void DidRecreateOutputSurface(bool succeeded) OVERRIDE {
708 EXPECT_TRUE(succeeded);
709 EndTest();
712 virtual void AfterTest() OVERRIDE {}
714 protected:
715 bool lose_after_evict_;
716 FakeContentLayerClient client_;
717 scoped_refptr<FakeContentLayer> layer_;
718 LayerTreeHostImpl* impl_host_;
719 int num_commits_;
722 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
723 LoseAfterEvict_SingleThread) {
724 lose_after_evict_ = true;
725 RunTest(false);
728 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
729 LoseAfterEvict_MultiThread) {
730 lose_after_evict_ = true;
731 RunTest(true);
734 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
735 LoseBeforeEvict_SingleThread) {
736 lose_after_evict_ = false;
737 RunTest(false);
740 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
741 LoseBeforeEvict_MultiThread) {
742 lose_after_evict_ = false;
743 RunTest(true);
746 class LayerTreeHostContextTestLostContextWhileUpdatingResources
747 : public LayerTreeHostContextTest {
748 public:
749 LayerTreeHostContextTestLostContextWhileUpdatingResources()
750 : parent_(FakeContentLayer::Create(&client_)),
751 num_children_(50),
752 times_to_lose_on_end_query_(3) {}
754 virtual scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() OVERRIDE {
755 scoped_ptr<TestWebGraphicsContext3D> context =
756 LayerTreeHostContextTest::CreateContext3d();
757 if (times_to_lose_on_end_query_) {
758 --times_to_lose_on_end_query_;
759 context->set_times_end_query_succeeds(5);
761 return context.Pass();
764 virtual void SetupTree() OVERRIDE {
765 parent_->SetBounds(gfx::Size(num_children_, 1));
767 for (int i = 0; i < num_children_; i++) {
768 scoped_refptr<FakeContentLayer> child =
769 FakeContentLayer::Create(&client_);
770 child->SetPosition(gfx::PointF(i, 0.f));
771 child->SetBounds(gfx::Size(1, 1));
772 parent_->AddChild(child);
775 layer_tree_host()->SetRootLayer(parent_);
776 LayerTreeHostContextTest::SetupTree();
779 virtual void BeginTest() OVERRIDE {
780 PostSetNeedsCommitToMainThread();
783 virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
784 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
785 EndTest();
788 virtual void DidRecreateOutputSurface(bool succeeded) OVERRIDE {
789 EXPECT_TRUE(succeeded);
792 virtual void AfterTest() OVERRIDE {
793 EXPECT_EQ(0, times_to_lose_on_end_query_);
796 private:
797 FakeContentLayerClient client_;
798 scoped_refptr<FakeContentLayer> parent_;
799 int num_children_;
800 int times_to_lose_on_end_query_;
803 SINGLE_AND_MULTI_THREAD_TEST_F(
804 LayerTreeHostContextTestLostContextWhileUpdatingResources);
806 class LayerTreeHostContextTestLayersNotified
807 : public LayerTreeHostContextTest {
808 public:
809 LayerTreeHostContextTestLayersNotified()
810 : LayerTreeHostContextTest(),
811 num_commits_(0) {}
813 virtual void SetupTree() OVERRIDE {
814 root_ = FakeContentLayer::Create(&client_);
815 child_ = FakeContentLayer::Create(&client_);
816 grandchild_ = FakeContentLayer::Create(&client_);
818 root_->AddChild(child_);
819 child_->AddChild(grandchild_);
821 layer_tree_host()->SetRootLayer(root_);
822 LayerTreeHostContextTest::SetupTree();
825 virtual void BeginTest() OVERRIDE {
826 PostSetNeedsCommitToMainThread();
829 virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
830 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
832 FakeContentLayerImpl* root = static_cast<FakeContentLayerImpl*>(
833 host_impl->active_tree()->root_layer());
834 FakeContentLayerImpl* child = static_cast<FakeContentLayerImpl*>(
835 root->children()[0]);
836 FakeContentLayerImpl* grandchild = static_cast<FakeContentLayerImpl*>(
837 child->children()[0]);
839 ++num_commits_;
840 switch (num_commits_) {
841 case 1:
842 EXPECT_EQ(0u, root->lost_output_surface_count());
843 EXPECT_EQ(0u, child->lost_output_surface_count());
844 EXPECT_EQ(0u, grandchild->lost_output_surface_count());
845 // Lose the context and struggle to recreate it.
846 LoseContext();
847 times_to_fail_create_ = 1;
848 break;
849 case 2:
850 EXPECT_EQ(1u, root->lost_output_surface_count());
851 EXPECT_EQ(1u, child->lost_output_surface_count());
852 EXPECT_EQ(1u, grandchild->lost_output_surface_count());
853 // Lose the context and again during recreate.
854 LoseContext();
855 times_to_lose_on_create_ = 1;
856 break;
857 case 3:
858 EXPECT_EQ(3u, root->lost_output_surface_count());
859 EXPECT_EQ(3u, child->lost_output_surface_count());
860 EXPECT_EQ(3u, grandchild->lost_output_surface_count());
861 // Lose the context and again during reinitialization.
862 LoseContext();
863 times_to_fail_initialize_ = 1;
864 break;
865 case 4:
866 EXPECT_EQ(5u, root->lost_output_surface_count());
867 EXPECT_EQ(5u, child->lost_output_surface_count());
868 EXPECT_EQ(5u, grandchild->lost_output_surface_count());
869 EndTest();
870 break;
871 default:
872 NOTREACHED();
876 virtual void AfterTest() OVERRIDE {}
878 private:
879 int num_commits_;
881 FakeContentLayerClient client_;
882 scoped_refptr<FakeContentLayer> root_;
883 scoped_refptr<FakeContentLayer> child_;
884 scoped_refptr<FakeContentLayer> grandchild_;
887 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified);
889 class LayerTreeHostContextTestDontUseLostResources
890 : public LayerTreeHostContextTest {
891 public:
892 virtual void SetupTree() OVERRIDE {
893 context3d_->set_have_extension_io_surface(true);
894 context3d_->set_have_extension_egl_image(true);
896 scoped_refptr<Layer> root_ = Layer::Create();
897 root_->SetBounds(gfx::Size(10, 10));
898 root_->SetAnchorPoint(gfx::PointF());
899 root_->SetIsDrawable(true);
901 scoped_refptr<FakeDelegatedRendererLayer> delegated_ =
902 FakeDelegatedRendererLayer::Create();
903 delegated_->SetBounds(gfx::Size(10, 10));
904 delegated_->SetAnchorPoint(gfx::PointF());
905 delegated_->SetIsDrawable(true);
906 root_->AddChild(delegated_);
908 scoped_refptr<ContentLayer> content_ = ContentLayer::Create(&client_);
909 content_->SetBounds(gfx::Size(10, 10));
910 content_->SetAnchorPoint(gfx::PointF());
911 content_->SetIsDrawable(true);
912 root_->AddChild(content_);
914 scoped_refptr<TextureLayer> texture_ = TextureLayer::Create(NULL);
915 texture_->SetBounds(gfx::Size(10, 10));
916 texture_->SetAnchorPoint(gfx::PointF());
917 texture_->SetTextureId(TestWebGraphicsContext3D::kExternalTextureId);
918 texture_->SetIsDrawable(true);
919 root_->AddChild(texture_);
921 scoped_refptr<ContentLayer> mask_ = ContentLayer::Create(&client_);
922 mask_->SetBounds(gfx::Size(10, 10));
923 mask_->SetAnchorPoint(gfx::PointF());
925 scoped_refptr<ContentLayer> content_with_mask_ =
926 ContentLayer::Create(&client_);
927 content_with_mask_->SetBounds(gfx::Size(10, 10));
928 content_with_mask_->SetAnchorPoint(gfx::PointF());
929 content_with_mask_->SetIsDrawable(true);
930 content_with_mask_->SetMaskLayer(mask_.get());
931 root_->AddChild(content_with_mask_);
933 scoped_refptr<VideoLayer> video_color_ = VideoLayer::Create(
934 &color_frame_provider_);
935 video_color_->SetBounds(gfx::Size(10, 10));
936 video_color_->SetAnchorPoint(gfx::PointF());
937 video_color_->SetIsDrawable(true);
938 root_->AddChild(video_color_);
940 scoped_refptr<VideoLayer> video_hw_ = VideoLayer::Create(
941 &hw_frame_provider_);
942 video_hw_->SetBounds(gfx::Size(10, 10));
943 video_hw_->SetAnchorPoint(gfx::PointF());
944 video_hw_->SetIsDrawable(true);
945 root_->AddChild(video_hw_);
947 scoped_refptr<VideoLayer> video_scaled_hw_ = VideoLayer::Create(
948 &scaled_hw_frame_provider_);
949 video_scaled_hw_->SetBounds(gfx::Size(10, 10));
950 video_scaled_hw_->SetAnchorPoint(gfx::PointF());
951 video_scaled_hw_->SetIsDrawable(true);
952 root_->AddChild(video_scaled_hw_);
954 scoped_refptr<IOSurfaceLayer> io_surface_ = IOSurfaceLayer::Create();
955 io_surface_->SetBounds(gfx::Size(10, 10));
956 io_surface_->SetAnchorPoint(gfx::PointF());
957 io_surface_->SetIsDrawable(true);
958 io_surface_->SetIOSurfaceProperties(1, gfx::Size(10, 10));
959 root_->AddChild(io_surface_);
961 // Enable the hud.
962 LayerTreeDebugState debug_state;
963 debug_state.show_property_changed_rects = true;
964 layer_tree_host()->SetDebugState(debug_state);
966 bool paint_scrollbar = true;
967 bool has_thumb = true;
968 scoped_refptr<ScrollbarLayer> scrollbar_ = ScrollbarLayer::Create(
969 FakeWebScrollbar::Create().PassAs<WebKit::WebScrollbar>(),
970 FakeScrollbarThemePainter::Create(paint_scrollbar)
971 .PassAs<ScrollbarThemePainter>(),
972 FakeWebScrollbarThemeGeometry::Create(has_thumb)
973 .PassAs<WebKit::WebScrollbarThemeGeometry>(),
974 content_->id());
975 scrollbar_->SetBounds(gfx::Size(10, 10));
976 scrollbar_->SetAnchorPoint(gfx::PointF());
977 scrollbar_->SetIsDrawable(true);
978 root_->AddChild(scrollbar_);
980 layer_tree_host()->SetRootLayer(root_);
981 LayerTreeHostContextTest::SetupTree();
984 virtual void BeginTest() OVERRIDE {
985 PostSetNeedsCommitToMainThread();
988 virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
989 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
991 ResourceProvider* resource_provider = host_impl->resource_provider();
993 if (host_impl->active_tree()->source_frame_number() == 0) {
994 // Set up impl resources on the first commit.
996 scoped_ptr<TestRenderPass> pass_for_quad = TestRenderPass::Create();
997 pass_for_quad->SetNew(
998 // AppendOneOfEveryQuadType() makes a RenderPass quad with this id.
999 RenderPass::Id(1, 1),
1000 gfx::Rect(0, 0, 10, 10),
1001 gfx::Rect(0, 0, 10, 10),
1002 gfx::Transform());
1004 scoped_ptr<TestRenderPass> pass = TestRenderPass::Create();
1005 pass->SetNew(
1006 RenderPass::Id(2, 1),
1007 gfx::Rect(0, 0, 10, 10),
1008 gfx::Rect(0, 0, 10, 10),
1009 gfx::Transform());
1010 pass->AppendOneOfEveryQuadType(resource_provider, RenderPass::Id(2, 1));
1012 ScopedPtrVector<RenderPass> pass_list;
1013 pass_list.push_back(pass_for_quad.PassAs<RenderPass>());
1014 pass_list.push_back(pass.PassAs<RenderPass>());
1016 // First child is the delegated layer.
1017 FakeDelegatedRendererLayerImpl* delegated_impl =
1018 static_cast<FakeDelegatedRendererLayerImpl*>(
1019 host_impl->active_tree()->root_layer()->children()[0]);
1020 delegated_impl->SetFrameDataForRenderPasses(&pass_list);
1021 EXPECT_TRUE(pass_list.empty());
1023 color_video_frame_ = VideoFrame::CreateColorFrame(
1024 gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
1025 hw_video_frame_ = VideoFrame::WrapNativeTexture(
1026 resource_provider->GraphicsContext3D()->createTexture(),
1027 GL_TEXTURE_2D,
1028 gfx::Size(4, 4), gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4),
1029 base::TimeDelta(),
1030 VideoFrame::ReadPixelsCB(),
1031 base::Closure());
1032 scaled_hw_video_frame_ = VideoFrame::WrapNativeTexture(
1033 resource_provider->GraphicsContext3D()->createTexture(),
1034 GL_TEXTURE_2D,
1035 gfx::Size(4, 4), gfx::Rect(0, 0, 3, 2), gfx::Size(4, 4),
1036 base::TimeDelta(),
1037 VideoFrame::ReadPixelsCB(),
1038 base::Closure());
1040 color_frame_provider_.set_frame(color_video_frame_);
1041 hw_frame_provider_.set_frame(hw_video_frame_);
1042 scaled_hw_frame_provider_.set_frame(scaled_hw_video_frame_);
1043 return;
1046 if (host_impl->active_tree()->source_frame_number() == 3) {
1047 // On the third commit we're recovering from context loss. Hardware
1048 // video frames should not be reused by the VideoFrameProvider, but
1049 // software frames can be.
1050 hw_frame_provider_.set_frame(NULL);
1051 scaled_hw_frame_provider_.set_frame(NULL);
1055 virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
1056 LayerTreeHostImpl::FrameData* frame,
1057 bool result) OVERRIDE {
1058 if (host_impl->active_tree()->source_frame_number() == 2) {
1059 // Lose the context during draw on the second commit. This will cause
1060 // a third commit to recover.
1061 if (context3d_)
1062 context3d_->set_times_bind_texture_succeeds(4);
1064 return true;
1067 virtual void DidCommitAndDrawFrame() OVERRIDE {
1068 ASSERT_TRUE(layer_tree_host()->hud_layer());
1069 // End the test once we know the 3nd frame drew.
1070 if (layer_tree_host()->commit_number() == 4)
1071 EndTest();
1072 else
1073 layer_tree_host()->SetNeedsCommit();
1076 virtual void AfterTest() OVERRIDE {}
1078 private:
1079 FakeContentLayerClient client_;
1081 scoped_refptr<Layer> root_;
1082 scoped_refptr<DelegatedRendererLayer> delegated_;
1083 scoped_refptr<ContentLayer> content_;
1084 scoped_refptr<TextureLayer> texture_;
1085 scoped_refptr<ContentLayer> mask_;
1086 scoped_refptr<ContentLayer> content_with_mask_;
1087 scoped_refptr<VideoLayer> video_color_;
1088 scoped_refptr<VideoLayer> video_hw_;
1089 scoped_refptr<VideoLayer> video_scaled_hw_;
1090 scoped_refptr<IOSurfaceLayer> io_surface_;
1091 scoped_refptr<ScrollbarLayer> scrollbar_;
1093 scoped_refptr<VideoFrame> color_video_frame_;
1094 scoped_refptr<VideoFrame> hw_video_frame_;
1095 scoped_refptr<VideoFrame> scaled_hw_video_frame_;
1097 FakeVideoFrameProvider color_frame_provider_;
1098 FakeVideoFrameProvider hw_frame_provider_;
1099 FakeVideoFrameProvider scaled_hw_frame_provider_;
1102 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources);
1104 class LayerTreeHostContextTestFailsImmediately
1105 : public LayerTreeHostContextTest {
1106 public:
1107 LayerTreeHostContextTestFailsImmediately()
1108 : LayerTreeHostContextTest() {}
1110 virtual ~LayerTreeHostContextTestFailsImmediately() {}
1112 virtual void BeginTest() OVERRIDE {
1113 PostSetNeedsCommitToMainThread();
1116 virtual void AfterTest() OVERRIDE {}
1118 virtual scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() OVERRIDE {
1119 scoped_ptr<TestWebGraphicsContext3D> context =
1120 LayerTreeHostContextTest::CreateContext3d();
1121 context->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
1122 GL_INNOCENT_CONTEXT_RESET_ARB);
1123 return context.Pass();
1126 virtual void DidRecreateOutputSurface(bool succeeded) OVERRIDE {
1127 EXPECT_FALSE(succeeded);
1128 // If we make it this far without crashing, we pass!
1129 EndTest();
1133 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestFailsImmediately);
1135 class ImplSidePaintingLayerTreeHostContextTest
1136 : public LayerTreeHostContextTest {
1137 public:
1138 virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
1139 settings->impl_side_painting = true;
1143 class LayerTreeHostContextTestImplSidePainting
1144 : public ImplSidePaintingLayerTreeHostContextTest {
1145 public:
1146 virtual void SetupTree() OVERRIDE {
1147 scoped_refptr<Layer> root = Layer::Create();
1148 root->SetBounds(gfx::Size(10, 10));
1149 root->SetAnchorPoint(gfx::PointF());
1150 root->SetIsDrawable(true);
1152 scoped_refptr<PictureLayer> picture = PictureLayer::Create(&client_);
1153 picture->SetBounds(gfx::Size(10, 10));
1154 picture->SetAnchorPoint(gfx::PointF());
1155 picture->SetIsDrawable(true);
1156 root->AddChild(picture);
1158 layer_tree_host()->SetRootLayer(root);
1159 LayerTreeHostContextTest::SetupTree();
1162 virtual void BeginTest() OVERRIDE {
1163 times_to_lose_during_commit_ = 1;
1164 PostSetNeedsCommitToMainThread();
1167 virtual void AfterTest() OVERRIDE {}
1169 virtual void DidRecreateOutputSurface(bool succeeded) OVERRIDE {
1170 EXPECT_TRUE(succeeded);
1171 EndTest();
1174 private:
1175 FakeContentLayerClient client_;
1178 MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting);
1180 class ScrollbarLayerLostContext : public LayerTreeHostContextTest {
1181 public:
1182 ScrollbarLayerLostContext() : commits_(0) {}
1184 virtual void BeginTest() OVERRIDE {
1185 scoped_refptr<Layer> scroll_layer = Layer::Create();
1186 scrollbar_layer_ = FakeScrollbarLayer::Create(
1187 false, true, scroll_layer->id());
1188 scrollbar_layer_->SetBounds(gfx::Size(10, 100));
1189 layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
1190 layer_tree_host()->root_layer()->AddChild(scroll_layer);
1191 PostSetNeedsCommitToMainThread();
1194 virtual void AfterTest() OVERRIDE {}
1196 virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
1197 LayerTreeHostContextTest::CommitCompleteOnThread(impl);
1199 ++commits_;
1200 size_t upload_count = scrollbar_layer_->last_update_full_upload_size() +
1201 scrollbar_layer_->last_update_partial_upload_size();
1202 switch (commits_) {
1203 case 1:
1204 // First (regular) update, we should upload 2 resources (thumb, and
1205 // backtrack).
1206 EXPECT_EQ(1, scrollbar_layer_->update_count());
1207 EXPECT_EQ(2u, upload_count);
1208 LoseContext();
1209 break;
1210 case 2:
1211 // Second update, after the lost context, we should still upload 2
1212 // resources even if the contents haven't changed.
1213 EXPECT_EQ(2, scrollbar_layer_->update_count());
1214 EXPECT_EQ(2u, upload_count);
1215 EndTest();
1216 break;
1217 default:
1218 NOTREACHED();
1222 private:
1223 int commits_;
1224 scoped_refptr<FakeScrollbarLayer> scrollbar_layer_;
1227 SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext);
1229 class LayerTreeHostContextTestFailsToCreateSurface
1230 : public LayerTreeHostContextTest {
1231 public:
1232 LayerTreeHostContextTestFailsToCreateSurface()
1233 : LayerTreeHostContextTest(),
1234 failure_count_(0) {
1235 times_to_lose_on_create_ = 10;
1238 virtual void BeginTest() OVERRIDE {
1239 PostSetNeedsCommitToMainThread();
1242 virtual void AfterTest() OVERRIDE {}
1244 virtual void DidRecreateOutputSurface(bool success) OVERRIDE {
1245 EXPECT_FALSE(success);
1246 EXPECT_EQ(0, failure_count_);
1247 times_to_lose_on_create_ = 0;
1248 failure_count_++;
1249 // Normally, the embedder should stop trying to use the compositor at
1250 // this point, but let's force it back into action when we shouldn't.
1251 char pixels[4];
1252 EXPECT_FALSE(
1253 layer_tree_host()->CompositeAndReadback(pixels, gfx::Rect(1, 1)));
1254 // If we've made it this far without crashing, we've succeeded.
1255 EndTest();
1258 private:
1259 int failure_count_;
1262 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestFailsToCreateSurface);
1264 } // namespace
1265 } // namespace cc