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