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