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