1 // Copyright 2011 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 #include "cc/scheduler/scheduler.h" 5 6 #include <string> 7 #include <vector> 8 9 #include "base/logging.h" 10 #include "base/memory/scoped_vector.h" 11 #include "base/message_loop/message_loop.h" 12 #include "base/run_loop.h" 13 #include "base/time/time.h" 14 #include "cc/test/scheduler_test_common.h" 15 #include "testing/gmock/include/gmock/gmock.h" 16 #include "testing/gtest/include/gtest/gtest.h" 17 18 #define EXPECT_ACTION(action, client, action_index, expected_num_actions) \ 19 EXPECT_EQ(expected_num_actions, client.num_actions_()); \ 20 ASSERT_LT(action_index, client.num_actions_()); \ 21 do { \ 22 EXPECT_STREQ(action, client.Action(action_index)); \ 23 for (int i = expected_num_actions; i < client.num_actions_(); ++i) \ 24 ADD_FAILURE() << "Unexpected action: " << client.Action(i) << \ 25 " with state:\n" << client.StateForAction(action_index); \ 26 } while (false) 27 28 #define EXPECT_SINGLE_ACTION(action, client) \ 29 EXPECT_ACTION(action, client, 0, 1) 30 31 namespace cc { 32 namespace { 33 34 void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler) { 35 scheduler->DidCreateAndInitializeOutputSurface(); 36 scheduler->SetNeedsCommit(); 37 scheduler->FinishCommit(); 38 // Go through the motions to draw the commit. 39 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 40 scheduler->OnBeginImplFrameDeadline(); 41 // We need another BeginImplFrame so Scheduler calls 42 // SetNeedsBeginImplFrame(false). 43 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 44 scheduler->OnBeginImplFrameDeadline(); 45 } 46 47 class FakeSchedulerClient : public SchedulerClient { 48 public: 49 FakeSchedulerClient() 50 : needs_begin_impl_frame_(false) { 51 Reset(); 52 } 53 54 void Reset() { 55 actions_.clear(); 56 states_.clear(); 57 draw_will_happen_ = true; 58 swap_will_happen_if_draw_happens_ = true; 59 num_draws_ = 0; 60 log_anticipated_draw_time_change_ = false; 61 } 62 63 Scheduler* CreateScheduler(const SchedulerSettings& settings) { 64 scheduler_ = Scheduler::Create(this, settings, 0); 65 return scheduler_.get(); 66 } 67 68 // Most tests don't care about DidAnticipatedDrawTimeChange, so only record it 69 // for tests that do. 70 void set_log_anticipated_draw_time_change(bool log) { 71 log_anticipated_draw_time_change_ = log; 72 } 73 bool needs_begin_impl_frame() { return needs_begin_impl_frame_; } 74 int num_draws() const { return num_draws_; } 75 int num_actions_() const { return static_cast<int>(actions_.size()); } 76 const char* Action(int i) const { return actions_[i]; } 77 base::Value& StateForAction(int i) const { return *states_[i]; } 78 79 int ActionIndex(const char* action) const { 80 for (size_t i = 0; i < actions_.size(); i++) 81 if (!strcmp(actions_[i], action)) 82 return i; 83 return -1; 84 } 85 86 bool HasAction(const char* action) const { 87 return ActionIndex(action) >= 0; 88 } 89 90 void SetDrawWillHappen(bool draw_will_happen) { 91 draw_will_happen_ = draw_will_happen; 92 } 93 void SetSwapWillHappenIfDrawHappens(bool swap_will_happen_if_draw_happens) { 94 swap_will_happen_if_draw_happens_ = swap_will_happen_if_draw_happens; 95 } 96 97 // SchedulerClient implementation. 98 virtual void SetNeedsBeginImplFrame(bool enable) OVERRIDE { 99 actions_.push_back("SetNeedsBeginImplFrame"); 100 states_.push_back(scheduler_->StateAsValue().release()); 101 needs_begin_impl_frame_ = enable; 102 } 103 virtual void ScheduledActionSendBeginMainFrame() OVERRIDE { 104 actions_.push_back("ScheduledActionSendBeginMainFrame"); 105 states_.push_back(scheduler_->StateAsValue().release()); 106 } 107 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible() 108 OVERRIDE { 109 actions_.push_back("ScheduledActionDrawAndSwapIfPossible"); 110 states_.push_back(scheduler_->StateAsValue().release()); 111 num_draws_++; 112 bool did_readback = false; 113 return DrawSwapReadbackResult( 114 draw_will_happen_, 115 draw_will_happen_ && swap_will_happen_if_draw_happens_, 116 did_readback); 117 } 118 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE { 119 actions_.push_back("ScheduledActionDrawAndSwapForced"); 120 states_.push_back(scheduler_->StateAsValue().release()); 121 bool did_draw = true; 122 bool did_swap = swap_will_happen_if_draw_happens_; 123 bool did_readback = false; 124 return DrawSwapReadbackResult(did_draw, did_swap, did_readback); 125 } 126 virtual DrawSwapReadbackResult ScheduledActionDrawAndReadback() OVERRIDE { 127 actions_.push_back("ScheduledActionDrawAndReadback"); 128 states_.push_back(scheduler_->StateAsValue().release()); 129 bool did_draw = true; 130 bool did_swap = false; 131 bool did_readback = true; 132 return DrawSwapReadbackResult(did_draw, did_swap, did_readback); 133 } 134 virtual void ScheduledActionCommit() OVERRIDE { 135 actions_.push_back("ScheduledActionCommit"); 136 states_.push_back(scheduler_->StateAsValue().release()); 137 } 138 virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE { 139 actions_.push_back("ScheduledActionUpdateVisibleTiles"); 140 states_.push_back(scheduler_->StateAsValue().release()); 141 } 142 virtual void ScheduledActionActivatePendingTree() OVERRIDE { 143 actions_.push_back("ScheduledActionActivatePendingTree"); 144 states_.push_back(scheduler_->StateAsValue().release()); 145 } 146 virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE { 147 actions_.push_back("ScheduledActionBeginOutputSurfaceCreation"); 148 states_.push_back(scheduler_->StateAsValue().release()); 149 } 150 virtual void ScheduledActionAcquireLayerTexturesForMainThread() OVERRIDE { 151 actions_.push_back("ScheduledActionAcquireLayerTexturesForMainThread"); 152 states_.push_back(scheduler_->StateAsValue().release()); 153 } 154 virtual void ScheduledActionManageTiles() OVERRIDE { 155 actions_.push_back("ScheduledActionManageTiles"); 156 states_.push_back(scheduler_->StateAsValue().release()); 157 } 158 virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE { 159 if (log_anticipated_draw_time_change_) 160 actions_.push_back("DidAnticipatedDrawTimeChange"); 161 } 162 virtual base::TimeDelta DrawDurationEstimate() OVERRIDE { 163 return base::TimeDelta(); 164 } 165 virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE { 166 return base::TimeDelta(); 167 } 168 virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE { 169 return base::TimeDelta(); 170 } 171 172 virtual void PostBeginImplFrameDeadline(const base::Closure& closure, 173 base::TimeTicks deadline) OVERRIDE { 174 actions_.push_back("PostBeginImplFrameDeadlineTask"); 175 states_.push_back(scheduler_->StateAsValue().release()); 176 } 177 178 virtual void DidBeginImplFrameDeadline() OVERRIDE {} 179 180 protected: 181 bool needs_begin_impl_frame_; 182 bool draw_will_happen_; 183 bool swap_will_happen_if_draw_happens_; 184 int num_draws_; 185 bool log_anticipated_draw_time_change_; 186 std::vector<const char*> actions_; 187 ScopedVector<base::Value> states_; 188 scoped_ptr<Scheduler> scheduler_; 189 }; 190 191 TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginImplFrame) { 192 FakeSchedulerClient client; 193 SchedulerSettings default_scheduler_settings; 194 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 195 scheduler->SetCanStart(); 196 scheduler->SetVisible(true); 197 scheduler->SetCanDraw(true); 198 199 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 200 client.Reset(); 201 scheduler->DidCreateAndInitializeOutputSurface(); 202 EXPECT_EQ(0, client.num_actions_()); 203 } 204 205 void RequestCommit(bool deadline_scheduling_enabled) { 206 FakeSchedulerClient client; 207 SchedulerSettings scheduler_settings; 208 scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled; 209 Scheduler* scheduler = client.CreateScheduler(scheduler_settings); 210 scheduler->SetCanStart(); 211 scheduler->SetVisible(true); 212 scheduler->SetCanDraw(true); 213 214 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 215 InitializeOutputSurfaceAndFirstCommit(scheduler); 216 217 // SetNeedsCommit should begin the frame on the next BeginImplFrame. 218 client.Reset(); 219 scheduler->SetNeedsCommit(); 220 EXPECT_TRUE(client.needs_begin_impl_frame()); 221 if (deadline_scheduling_enabled) { 222 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); 223 } else { 224 EXPECT_EQ(client.num_actions_(), 2); 225 EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame")); 226 EXPECT_TRUE(client.HasAction("SetNeedsBeginImplFrame")); 227 } 228 client.Reset(); 229 230 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 231 if (deadline_scheduling_enabled) { 232 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2); 233 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2); 234 } else { 235 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 236 } 237 EXPECT_TRUE(client.needs_begin_impl_frame()); 238 client.Reset(); 239 240 // If we don't swap on the deadline, we need to request another 241 // BeginImplFrame. 242 scheduler->OnBeginImplFrameDeadline(); 243 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); 244 EXPECT_TRUE(client.needs_begin_impl_frame()); 245 client.Reset(); 246 247 // FinishCommit should commit 248 scheduler->FinishCommit(); 249 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); 250 EXPECT_TRUE(client.needs_begin_impl_frame()); 251 client.Reset(); 252 253 // BeginImplFrame should prepare the draw. 254 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 255 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 256 EXPECT_TRUE(client.needs_begin_impl_frame()); 257 client.Reset(); 258 259 // BeginImplFrame deadline should draw. 260 scheduler->OnBeginImplFrameDeadline(); 261 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); 262 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2); 263 EXPECT_TRUE(client.needs_begin_impl_frame()); 264 client.Reset(); 265 266 // The following BeginImplFrame deadline should SetNeedsBeginImplFrame(false) 267 // to avoid excessive toggles. 268 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 269 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 270 client.Reset(); 271 272 scheduler->OnBeginImplFrameDeadline(); 273 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); 274 EXPECT_FALSE(client.needs_begin_impl_frame()); 275 client.Reset(); 276 } 277 278 TEST(SchedulerTest, RequestCommit) { 279 bool deadline_scheduling_enabled = false; 280 RequestCommit(deadline_scheduling_enabled); 281 } 282 283 TEST(SchedulerTest, RequestCommit_Deadline) { 284 bool deadline_scheduling_enabled = true; 285 RequestCommit(deadline_scheduling_enabled); 286 } 287 288 void RequestCommitAfterBeginMainFrameSent( 289 bool deadline_scheduling_enabled) { 290 FakeSchedulerClient client; 291 SchedulerSettings scheduler_settings; 292 scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled; 293 Scheduler* scheduler = client.CreateScheduler(scheduler_settings); 294 scheduler->SetCanStart(); 295 scheduler->SetVisible(true); 296 scheduler->SetCanDraw(true); 297 298 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 299 InitializeOutputSurfaceAndFirstCommit(scheduler); 300 client.Reset(); 301 302 // SetNeedsCommit should begin the frame. 303 scheduler->SetNeedsCommit(); 304 if (deadline_scheduling_enabled) { 305 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); 306 } else { 307 EXPECT_EQ(client.num_actions_(), 2); 308 EXPECT_TRUE(client.HasAction("SetNeedsBeginImplFrame")); 309 EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame")); 310 } 311 312 client.Reset(); 313 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 314 if (deadline_scheduling_enabled) { 315 EXPECT_EQ(client.num_actions_(), 2); 316 EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame")); 317 EXPECT_TRUE(client.HasAction("PostBeginImplFrameDeadlineTask")); 318 } else { 319 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 320 } 321 322 EXPECT_TRUE(client.needs_begin_impl_frame()); 323 client.Reset(); 324 325 // Now SetNeedsCommit again. Calling here means we need a second commit. 326 scheduler->SetNeedsCommit(); 327 EXPECT_EQ(client.num_actions_(), 0); 328 client.Reset(); 329 330 // Finish the first commit. 331 scheduler->FinishCommit(); 332 EXPECT_ACTION("ScheduledActionCommit", client, 0, 2); 333 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2); 334 client.Reset(); 335 scheduler->OnBeginImplFrameDeadline(); 336 if (deadline_scheduling_enabled) { 337 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); 338 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2); 339 } else { 340 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 3); 341 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 3); 342 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 2, 3); 343 } 344 345 // Because we just swapped, the Scheduler should also request the next 346 // BeginImplFrame from the OutputSurface. 347 EXPECT_TRUE(client.needs_begin_impl_frame()); 348 client.Reset(); 349 350 // Since another commit is needed, the next BeginImplFrame should initiate 351 // the second commit. 352 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 353 if (deadline_scheduling_enabled) { 354 EXPECT_EQ(client.num_actions_(), 2); 355 EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame")); 356 EXPECT_TRUE(client.HasAction("PostBeginImplFrameDeadlineTask")); 357 } else { 358 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 359 } 360 client.Reset(); 361 362 // Finishing the commit before the deadline should post a new deadline task 363 // to trigger the deadline early. 364 scheduler->FinishCommit(); 365 EXPECT_ACTION("ScheduledActionCommit", client, 0, 2); 366 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2); 367 client.Reset(); 368 scheduler->OnBeginImplFrameDeadline(); 369 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); 370 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2); 371 EXPECT_TRUE(client.needs_begin_impl_frame()); 372 client.Reset(); 373 374 // On the next BeginImplFrame, verify we go back to a quiescent state and 375 // no longer request BeginImplFrames. 376 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 377 scheduler->OnBeginImplFrameDeadline(); 378 EXPECT_FALSE(client.needs_begin_impl_frame()); 379 client.Reset(); 380 } 381 382 TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) { 383 bool deadline_scheduling_enabled = false; 384 RequestCommitAfterBeginMainFrameSent(deadline_scheduling_enabled); 385 } 386 387 TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent_Deadline) { 388 bool deadline_scheduling_enabled = true; 389 RequestCommitAfterBeginMainFrameSent(deadline_scheduling_enabled); 390 } 391 392 void TextureAcquisitionCausesCommitInsteadOfDraw( 393 bool deadline_scheduling_enabled) { 394 FakeSchedulerClient client; 395 SchedulerSettings scheduler_settings; 396 scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled; 397 Scheduler* scheduler = client.CreateScheduler(scheduler_settings); 398 scheduler->SetCanStart(); 399 scheduler->SetVisible(true); 400 scheduler->SetCanDraw(true); 401 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 402 403 InitializeOutputSurfaceAndFirstCommit(scheduler); 404 client.Reset(); 405 scheduler->SetNeedsRedraw(); 406 EXPECT_TRUE(scheduler->RedrawPending()); 407 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); 408 EXPECT_TRUE(client.needs_begin_impl_frame()); 409 410 client.Reset(); 411 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 412 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 413 client.Reset(); 414 scheduler->OnBeginImplFrameDeadline(); 415 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); 416 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2); 417 EXPECT_FALSE(scheduler->RedrawPending()); 418 EXPECT_TRUE(client.needs_begin_impl_frame()); 419 420 client.Reset(); 421 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 422 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 423 client.Reset(); 424 scheduler->OnBeginImplFrameDeadline(); 425 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); 426 EXPECT_FALSE(scheduler->RedrawPending()); 427 EXPECT_FALSE(client.needs_begin_impl_frame()); 428 429 client.Reset(); 430 scheduler->SetMainThreadNeedsLayerTextures(); 431 EXPECT_SINGLE_ACTION("ScheduledActionAcquireLayerTexturesForMainThread", 432 client); 433 434 // We should request a BeginImplFrame in anticipation of a draw. 435 client.Reset(); 436 scheduler->SetNeedsRedraw(); 437 EXPECT_TRUE(scheduler->RedrawPending()); 438 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); 439 EXPECT_TRUE(client.needs_begin_impl_frame()); 440 441 // No draw happens since the textures are acquired by the main thread. 442 client.Reset(); 443 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 444 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 445 client.Reset(); 446 scheduler->OnBeginImplFrameDeadline(); 447 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); 448 EXPECT_TRUE(scheduler->RedrawPending()); 449 EXPECT_TRUE(client.needs_begin_impl_frame()); 450 451 client.Reset(); 452 scheduler->SetNeedsCommit(); 453 if (deadline_scheduling_enabled) { 454 EXPECT_EQ(0, client.num_actions_()); 455 } else { 456 EXPECT_SINGLE_ACTION("ScheduledActionSendBeginMainFrame", client); 457 } 458 459 client.Reset(); 460 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 461 if (deadline_scheduling_enabled) { 462 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2); 463 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2); 464 } else { 465 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 466 } 467 468 // Commit will release the texture. 469 client.Reset(); 470 scheduler->FinishCommit(); 471 EXPECT_ACTION("ScheduledActionCommit", client, 0, 2); 472 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2); 473 EXPECT_TRUE(scheduler->RedrawPending()); 474 475 // Now we can draw again after the commit happens. 476 client.Reset(); 477 scheduler->OnBeginImplFrameDeadline(); 478 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); 479 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2); 480 EXPECT_FALSE(scheduler->RedrawPending()); 481 EXPECT_TRUE(client.needs_begin_impl_frame()); 482 483 // Make sure we stop requesting BeginImplFrames if we don't swap. 484 client.Reset(); 485 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 486 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 487 client.Reset(); 488 scheduler->OnBeginImplFrameDeadline(); 489 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); 490 EXPECT_FALSE(client.needs_begin_impl_frame()); 491 } 492 493 TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw) { 494 bool deadline_scheduling_enabled = false; 495 TextureAcquisitionCausesCommitInsteadOfDraw(deadline_scheduling_enabled); 496 } 497 498 TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw_Deadline) { 499 bool deadline_scheduling_enabled = true; 500 TextureAcquisitionCausesCommitInsteadOfDraw(deadline_scheduling_enabled); 501 } 502 503 void TextureAcquisitionCollision(bool deadline_scheduling_enabled) { 504 FakeSchedulerClient client; 505 SchedulerSettings scheduler_settings; 506 scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled; 507 Scheduler* scheduler = client.CreateScheduler(scheduler_settings); 508 scheduler->SetCanStart(); 509 scheduler->SetVisible(true); 510 scheduler->SetCanDraw(true); 511 512 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 513 InitializeOutputSurfaceAndFirstCommit(scheduler); 514 515 client.Reset(); 516 scheduler->SetNeedsCommit(); 517 if (deadline_scheduling_enabled) { 518 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); 519 } else { 520 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2); 521 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2); 522 } 523 524 client.Reset(); 525 scheduler->SetMainThreadNeedsLayerTextures(); 526 EXPECT_SINGLE_ACTION( 527 "ScheduledActionAcquireLayerTexturesForMainThread", client); 528 529 client.Reset(); 530 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 531 if (deadline_scheduling_enabled) { 532 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2); 533 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2); 534 } else { 535 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 536 } 537 538 client.Reset(); 539 scheduler->OnBeginImplFrameDeadline(); 540 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); 541 542 // Although the compositor cannot draw because textures are locked by main 543 // thread, we continue requesting SetNeedsBeginImplFrame in anticipation of 544 // the unlock. 545 EXPECT_TRUE(client.needs_begin_impl_frame()); 546 547 // Trigger the commit 548 scheduler->FinishCommit(); 549 EXPECT_TRUE(client.needs_begin_impl_frame()); 550 551 // Between commit and draw, texture acquisition for main thread delayed, 552 // and main thread blocks. 553 client.Reset(); 554 scheduler->SetMainThreadNeedsLayerTextures(); 555 EXPECT_EQ(0, client.num_actions_()); 556 557 // No implicit commit is expected. 558 client.Reset(); 559 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 560 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 561 562 client.Reset(); 563 scheduler->OnBeginImplFrameDeadline(); 564 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 3); 565 EXPECT_ACTION( 566 "ScheduledActionAcquireLayerTexturesForMainThread", client, 1, 3); 567 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 2, 3); 568 EXPECT_TRUE(client.needs_begin_impl_frame()); 569 570 // The compositor should not draw because textures are locked by main 571 // thread. 572 client.Reset(); 573 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 574 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 575 client.Reset(); 576 scheduler->OnBeginImplFrameDeadline(); 577 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); 578 EXPECT_FALSE(client.needs_begin_impl_frame()); 579 580 // The impl thread need an explicit commit from the main thread to lock 581 // the textures. 582 client.Reset(); 583 scheduler->SetNeedsCommit(); 584 if (deadline_scheduling_enabled) { 585 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); 586 } else { 587 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2); 588 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2); 589 } 590 EXPECT_TRUE(client.needs_begin_impl_frame()); 591 592 client.Reset(); 593 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 594 if (deadline_scheduling_enabled) { 595 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2); 596 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2); 597 } else { 598 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 599 } 600 client.Reset(); 601 602 // Trigger the commit, which will trigger the deadline task early. 603 scheduler->FinishCommit(); 604 EXPECT_ACTION("ScheduledActionCommit", client, 0, 2); 605 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2); 606 EXPECT_TRUE(client.needs_begin_impl_frame()); 607 client.Reset(); 608 609 // Verify we draw on the next BeginImplFrame deadline 610 scheduler->OnBeginImplFrameDeadline(); 611 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); 612 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2); 613 EXPECT_TRUE(client.needs_begin_impl_frame()); 614 client.Reset(); 615 } 616 617 TEST(SchedulerTest, TextureAcquisitionCollision) { 618 bool deadline_scheduling_enabled = false; 619 TextureAcquisitionCollision(deadline_scheduling_enabled); 620 } 621 622 TEST(SchedulerTest, TextureAcquisitionCollision_Deadline) { 623 bool deadline_scheduling_enabled = true; 624 TextureAcquisitionCollision(deadline_scheduling_enabled); 625 } 626 627 void VisibilitySwitchWithTextureAcquisition(bool deadline_scheduling_enabled) { 628 FakeSchedulerClient client; 629 SchedulerSettings scheduler_settings; 630 scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled; 631 Scheduler* scheduler = client.CreateScheduler(scheduler_settings); 632 scheduler->SetCanStart(); 633 scheduler->SetVisible(true); 634 scheduler->SetCanDraw(true); 635 636 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 637 client.Reset(); 638 scheduler->DidCreateAndInitializeOutputSurface(); 639 640 scheduler->SetNeedsCommit(); 641 if (deadline_scheduling_enabled) { 642 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 643 scheduler->OnBeginImplFrameDeadline(); 644 } 645 scheduler->FinishCommit(); 646 scheduler->SetMainThreadNeedsLayerTextures(); 647 scheduler->SetNeedsCommit(); 648 client.Reset(); 649 // Verify that pending texture acquisition fires when visibility 650 // is lost in order to avoid a deadlock. 651 scheduler->SetVisible(false); 652 EXPECT_SINGLE_ACTION("ScheduledActionAcquireLayerTexturesForMainThread", 653 client); 654 655 client.Reset(); 656 scheduler->SetVisible(true); 657 EXPECT_EQ(0, client.num_actions_()); 658 EXPECT_TRUE(client.needs_begin_impl_frame()); 659 660 // Regaining visibility with textures acquired by main thread while 661 // compositor is waiting for first draw should result in a request 662 // for a new frame in order to escape a deadlock. 663 client.Reset(); 664 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 665 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2); 666 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2); 667 } 668 669 TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition) { 670 bool deadline_scheduling_enabled = false; 671 VisibilitySwitchWithTextureAcquisition(deadline_scheduling_enabled); 672 } 673 674 TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition_Deadline) { 675 bool deadline_scheduling_enabled = true; 676 VisibilitySwitchWithTextureAcquisition(deadline_scheduling_enabled); 677 } 678 679 class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient { 680 public: 681 virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {} 682 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible() 683 OVERRIDE { 684 // Only SetNeedsRedraw the first time this is called 685 if (!num_draws_) 686 scheduler_->SetNeedsRedraw(); 687 return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible(); 688 } 689 690 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE { 691 NOTREACHED(); 692 bool did_draw = true; 693 bool did_swap = true; 694 bool did_readback = false; 695 return DrawSwapReadbackResult(did_draw, did_swap, did_readback); 696 } 697 698 virtual void ScheduledActionCommit() OVERRIDE {} 699 virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {} 700 virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {} 701 }; 702 703 // Tests for two different situations: 704 // 1. the scheduler dropping SetNeedsRedraw requests that happen inside 705 // a ScheduledActionDrawAndSwap 706 // 2. the scheduler drawing twice inside a single tick 707 TEST(SchedulerTest, RequestRedrawInsideDraw) { 708 SchedulerClientThatsetNeedsDrawInsideDraw client; 709 SchedulerSettings default_scheduler_settings; 710 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 711 scheduler->SetCanStart(); 712 scheduler->SetVisible(true); 713 scheduler->SetCanDraw(true); 714 InitializeOutputSurfaceAndFirstCommit(scheduler); 715 client.Reset(); 716 717 scheduler->SetNeedsRedraw(); 718 EXPECT_TRUE(scheduler->RedrawPending()); 719 EXPECT_TRUE(client.needs_begin_impl_frame()); 720 EXPECT_EQ(0, client.num_draws()); 721 722 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 723 scheduler->OnBeginImplFrameDeadline(); 724 EXPECT_EQ(1, client.num_draws()); 725 EXPECT_TRUE(scheduler->RedrawPending()); 726 EXPECT_TRUE(client.needs_begin_impl_frame()); 727 728 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 729 scheduler->OnBeginImplFrameDeadline(); 730 EXPECT_EQ(2, client.num_draws()); 731 EXPECT_FALSE(scheduler->RedrawPending()); 732 EXPECT_TRUE(client.needs_begin_impl_frame()); 733 734 // We stop requesting BeginImplFrames after a BeginImplFrame where we don't 735 // swap. 736 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 737 scheduler->OnBeginImplFrameDeadline(); 738 EXPECT_EQ(2, client.num_draws()); 739 EXPECT_FALSE(scheduler->RedrawPending()); 740 EXPECT_FALSE(client.needs_begin_impl_frame()); 741 } 742 743 // Test that requesting redraw inside a failed draw doesn't lose the request. 744 TEST(SchedulerTest, RequestRedrawInsideFailedDraw) { 745 SchedulerClientThatsetNeedsDrawInsideDraw client; 746 SchedulerSettings default_scheduler_settings; 747 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 748 scheduler->SetCanStart(); 749 scheduler->SetVisible(true); 750 scheduler->SetCanDraw(true); 751 InitializeOutputSurfaceAndFirstCommit(scheduler); 752 client.Reset(); 753 754 client.SetDrawWillHappen(false); 755 756 scheduler->SetNeedsRedraw(); 757 EXPECT_TRUE(scheduler->RedrawPending()); 758 EXPECT_TRUE(client.needs_begin_impl_frame()); 759 EXPECT_EQ(0, client.num_draws()); 760 761 // Fail the draw. 762 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 763 scheduler->OnBeginImplFrameDeadline(); 764 EXPECT_EQ(1, client.num_draws()); 765 766 // We have a commit pending and the draw failed, and we didn't lose the redraw 767 // request. 768 EXPECT_TRUE(scheduler->CommitPending()); 769 EXPECT_TRUE(scheduler->RedrawPending()); 770 EXPECT_TRUE(client.needs_begin_impl_frame()); 771 772 // Fail the draw again. 773 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 774 scheduler->OnBeginImplFrameDeadline(); 775 EXPECT_EQ(2, client.num_draws()); 776 EXPECT_TRUE(scheduler->CommitPending()); 777 EXPECT_TRUE(scheduler->RedrawPending()); 778 EXPECT_TRUE(client.needs_begin_impl_frame()); 779 780 // Draw successfully. 781 client.SetDrawWillHappen(true); 782 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 783 scheduler->OnBeginImplFrameDeadline(); 784 EXPECT_EQ(3, client.num_draws()); 785 EXPECT_TRUE(scheduler->CommitPending()); 786 EXPECT_FALSE(scheduler->RedrawPending()); 787 EXPECT_TRUE(client.needs_begin_impl_frame()); 788 } 789 790 class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient { 791 public: 792 SchedulerClientThatSetNeedsCommitInsideDraw() 793 : set_needs_commit_on_next_draw_(false) {} 794 795 virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {} 796 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible() 797 OVERRIDE { 798 // Only SetNeedsCommit the first time this is called 799 if (set_needs_commit_on_next_draw_) { 800 scheduler_->SetNeedsCommit(); 801 set_needs_commit_on_next_draw_ = false; 802 } 803 return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible(); 804 } 805 806 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE { 807 NOTREACHED(); 808 bool did_draw = true; 809 bool did_swap = false; 810 bool did_readback = false; 811 return DrawSwapReadbackResult(did_draw, did_swap, did_readback); 812 } 813 814 virtual void ScheduledActionCommit() OVERRIDE {} 815 virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {} 816 virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {} 817 818 void SetNeedsCommitOnNextDraw() { set_needs_commit_on_next_draw_ = true; } 819 820 private: 821 bool set_needs_commit_on_next_draw_; 822 }; 823 824 // Tests for the scheduler infinite-looping on SetNeedsCommit requests that 825 // happen inside a ScheduledActionDrawAndSwap 826 TEST(SchedulerTest, RequestCommitInsideDraw) { 827 SchedulerClientThatSetNeedsCommitInsideDraw client; 828 SchedulerSettings default_scheduler_settings; 829 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 830 scheduler->SetCanStart(); 831 scheduler->SetVisible(true); 832 scheduler->SetCanDraw(true); 833 InitializeOutputSurfaceAndFirstCommit(scheduler); 834 client.Reset(); 835 836 EXPECT_FALSE(client.needs_begin_impl_frame()); 837 scheduler->SetNeedsRedraw(); 838 EXPECT_TRUE(scheduler->RedrawPending()); 839 EXPECT_EQ(0, client.num_draws()); 840 EXPECT_TRUE(client.needs_begin_impl_frame()); 841 842 client.SetNeedsCommitOnNextDraw(); 843 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 844 client.SetNeedsCommitOnNextDraw(); 845 scheduler->OnBeginImplFrameDeadline(); 846 EXPECT_EQ(1, client.num_draws()); 847 EXPECT_TRUE(scheduler->CommitPending()); 848 EXPECT_TRUE(client.needs_begin_impl_frame()); 849 scheduler->FinishCommit(); 850 851 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 852 scheduler->OnBeginImplFrameDeadline(); 853 EXPECT_EQ(2, client.num_draws()); 854 855 EXPECT_FALSE(scheduler->RedrawPending()); 856 EXPECT_FALSE(scheduler->CommitPending()); 857 EXPECT_TRUE(client.needs_begin_impl_frame()); 858 859 // We stop requesting BeginImplFrames after a BeginImplFrame where we don't 860 // swap. 861 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 862 scheduler->OnBeginImplFrameDeadline(); 863 EXPECT_EQ(2, client.num_draws()); 864 EXPECT_FALSE(scheduler->RedrawPending()); 865 EXPECT_FALSE(scheduler->CommitPending()); 866 EXPECT_FALSE(client.needs_begin_impl_frame()); 867 } 868 869 // Tests that when a draw fails then the pending commit should not be dropped. 870 TEST(SchedulerTest, RequestCommitInsideFailedDraw) { 871 SchedulerClientThatsetNeedsDrawInsideDraw client; 872 SchedulerSettings default_scheduler_settings; 873 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 874 scheduler->SetCanStart(); 875 scheduler->SetVisible(true); 876 scheduler->SetCanDraw(true); 877 InitializeOutputSurfaceAndFirstCommit(scheduler); 878 client.Reset(); 879 880 client.SetDrawWillHappen(false); 881 882 scheduler->SetNeedsRedraw(); 883 EXPECT_TRUE(scheduler->RedrawPending()); 884 EXPECT_TRUE(client.needs_begin_impl_frame()); 885 EXPECT_EQ(0, client.num_draws()); 886 887 // Fail the draw. 888 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 889 scheduler->OnBeginImplFrameDeadline(); 890 EXPECT_EQ(1, client.num_draws()); 891 892 // We have a commit pending and the draw failed, and we didn't lose the commit 893 // request. 894 EXPECT_TRUE(scheduler->CommitPending()); 895 EXPECT_TRUE(scheduler->RedrawPending()); 896 EXPECT_TRUE(client.needs_begin_impl_frame()); 897 898 // Fail the draw again. 899 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 900 scheduler->OnBeginImplFrameDeadline(); 901 EXPECT_EQ(2, client.num_draws()); 902 EXPECT_TRUE(scheduler->CommitPending()); 903 EXPECT_TRUE(scheduler->RedrawPending()); 904 EXPECT_TRUE(client.needs_begin_impl_frame()); 905 906 // Draw successfully. 907 client.SetDrawWillHappen(true); 908 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 909 scheduler->OnBeginImplFrameDeadline(); 910 EXPECT_EQ(3, client.num_draws()); 911 EXPECT_TRUE(scheduler->CommitPending()); 912 EXPECT_FALSE(scheduler->RedrawPending()); 913 EXPECT_TRUE(client.needs_begin_impl_frame()); 914 } 915 916 TEST(SchedulerTest, NoSwapWhenDrawFails) { 917 SchedulerClientThatSetNeedsCommitInsideDraw client; 918 SchedulerSettings default_scheduler_settings; 919 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 920 scheduler->SetCanStart(); 921 scheduler->SetVisible(true); 922 scheduler->SetCanDraw(true); 923 InitializeOutputSurfaceAndFirstCommit(scheduler); 924 client.Reset(); 925 926 scheduler->SetNeedsRedraw(); 927 EXPECT_TRUE(scheduler->RedrawPending()); 928 EXPECT_TRUE(client.needs_begin_impl_frame()); 929 EXPECT_EQ(0, client.num_draws()); 930 931 // Draw successfully, this starts a new frame. 932 client.SetNeedsCommitOnNextDraw(); 933 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 934 scheduler->OnBeginImplFrameDeadline(); 935 EXPECT_EQ(1, client.num_draws()); 936 937 scheduler->SetNeedsRedraw(); 938 EXPECT_TRUE(scheduler->RedrawPending()); 939 EXPECT_TRUE(client.needs_begin_impl_frame()); 940 941 // Fail to draw, this should not start a frame. 942 client.SetDrawWillHappen(false); 943 client.SetNeedsCommitOnNextDraw(); 944 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 945 scheduler->OnBeginImplFrameDeadline(); 946 EXPECT_EQ(2, client.num_draws()); 947 } 948 949 TEST(SchedulerTest, NoSwapWhenSwapFailsDuringForcedCommit) { 950 FakeSchedulerClient client; 951 SchedulerSettings default_scheduler_settings; 952 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 953 954 // Tell the client that it will fail to swap. 955 client.SetDrawWillHappen(true); 956 client.SetSwapWillHappenIfDrawHappens(false); 957 958 // Get the compositor to do a ScheduledActionDrawAndReadback. 959 scheduler->SetCanDraw(true); 960 scheduler->SetNeedsRedraw(); 961 scheduler->SetNeedsForcedCommitForReadback(); 962 scheduler->FinishCommit(); 963 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback")); 964 } 965 966 TEST(SchedulerTest, BackToBackReadbackAllowed) { 967 // Some clients call readbacks twice in a row before the replacement 968 // commit comes in. Make sure it is allowed. 969 FakeSchedulerClient client; 970 SchedulerSettings default_scheduler_settings; 971 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 972 973 // Get the compositor to do 2 ScheduledActionDrawAndReadbacks before 974 // the replacement commit comes in. 975 scheduler->SetCanDraw(true); 976 scheduler->SetNeedsRedraw(); 977 scheduler->SetNeedsForcedCommitForReadback(); 978 scheduler->FinishCommit(); 979 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback")); 980 981 client.Reset(); 982 scheduler->SetNeedsForcedCommitForReadback(); 983 scheduler->FinishCommit(); 984 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback")); 985 986 // The replacement commit comes in after 2 readbacks. 987 client.Reset(); 988 scheduler->FinishCommit(); 989 } 990 991 992 class SchedulerClientNeedsManageTilesInDraw : public FakeSchedulerClient { 993 public: 994 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible() 995 OVERRIDE { 996 scheduler_->SetNeedsManageTiles(); 997 return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible(); 998 } 999 }; 1000 1001 // Test manage tiles is independant of draws. 1002 TEST(SchedulerTest, ManageTiles) { 1003 SchedulerClientNeedsManageTilesInDraw client; 1004 SchedulerSettings default_scheduler_settings; 1005 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 1006 scheduler->SetCanStart(); 1007 scheduler->SetVisible(true); 1008 scheduler->SetCanDraw(true); 1009 InitializeOutputSurfaceAndFirstCommit(scheduler); 1010 1011 // Request both draw and manage tiles. ManageTiles shouldn't 1012 // be trigged until BeginImplFrame. 1013 client.Reset(); 1014 scheduler->SetNeedsManageTiles(); 1015 scheduler->SetNeedsRedraw(); 1016 EXPECT_TRUE(scheduler->RedrawPending()); 1017 EXPECT_TRUE(scheduler->ManageTilesPending()); 1018 EXPECT_TRUE(client.needs_begin_impl_frame()); 1019 EXPECT_EQ(0, client.num_draws()); 1020 EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles")); 1021 EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); 1022 1023 // We have no immediate actions to perform, so the BeginImplFrame should post 1024 // the deadline task. 1025 client.Reset(); 1026 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 1027 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 1028 1029 // On the deadline, he actions should have occured in the right order. 1030 client.Reset(); 1031 scheduler->OnBeginImplFrameDeadline(); 1032 EXPECT_EQ(1, client.num_draws()); 1033 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); 1034 EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles")); 1035 EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"), 1036 client.ActionIndex("ScheduledActionManageTiles")); 1037 EXPECT_FALSE(scheduler->RedrawPending()); 1038 EXPECT_FALSE(scheduler->ManageTilesPending()); 1039 1040 // Request a draw. We don't need a ManageTiles yet. 1041 client.Reset(); 1042 scheduler->SetNeedsRedraw(); 1043 EXPECT_TRUE(scheduler->RedrawPending()); 1044 EXPECT_FALSE(scheduler->ManageTilesPending()); 1045 EXPECT_TRUE(client.needs_begin_impl_frame()); 1046 EXPECT_EQ(0, client.num_draws()); 1047 1048 // We have no immediate actions to perform, so the BeginImplFrame should post 1049 // the deadline task. 1050 client.Reset(); 1051 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 1052 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 1053 1054 // Draw. The draw will trigger SetNeedsManageTiles, and 1055 // then the ManageTiles action will be triggered after the Draw. 1056 // Afterwards, neither a draw nor ManageTiles are pending. 1057 client.Reset(); 1058 scheduler->OnBeginImplFrameDeadline(); 1059 EXPECT_EQ(1, client.num_draws()); 1060 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); 1061 EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles")); 1062 EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"), 1063 client.ActionIndex("ScheduledActionManageTiles")); 1064 EXPECT_FALSE(scheduler->RedrawPending()); 1065 EXPECT_FALSE(scheduler->ManageTilesPending()); 1066 1067 // We need a BeginImplFrame where we don't swap to go idle. 1068 client.Reset(); 1069 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 1070 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 1071 client.Reset(); 1072 scheduler->OnBeginImplFrameDeadline(); 1073 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);; 1074 EXPECT_EQ(0, client.num_draws()); 1075 1076 // Now trigger a ManageTiles outside of a draw. We will then need 1077 // a begin-frame for the ManageTiles, but we don't need a draw. 1078 client.Reset(); 1079 EXPECT_FALSE(client.needs_begin_impl_frame()); 1080 scheduler->SetNeedsManageTiles(); 1081 EXPECT_TRUE(client.needs_begin_impl_frame()); 1082 EXPECT_TRUE(scheduler->ManageTilesPending()); 1083 EXPECT_FALSE(scheduler->RedrawPending()); 1084 1085 // BeginImplFrame. There will be no draw, only ManageTiles. 1086 client.Reset(); 1087 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 1088 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 1089 client.Reset(); 1090 scheduler->OnBeginImplFrameDeadline(); 1091 EXPECT_EQ(0, client.num_draws()); 1092 EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); 1093 EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles")); 1094 } 1095 1096 // Test that ManageTiles only happens once per frame. If an external caller 1097 // initiates it, then the state machine should not on that frame. 1098 TEST(SchedulerTest, ManageTilesOncePerFrame) { 1099 FakeSchedulerClient client; 1100 SchedulerSettings default_scheduler_settings; 1101 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 1102 scheduler->SetCanStart(); 1103 scheduler->SetVisible(true); 1104 scheduler->SetCanDraw(true); 1105 InitializeOutputSurfaceAndFirstCommit(scheduler); 1106 1107 // If DidManageTiles during a frame, then ManageTiles should not occur again. 1108 scheduler->SetNeedsManageTiles(); 1109 scheduler->SetNeedsRedraw(); 1110 client.Reset(); 1111 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 1112 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 1113 1114 EXPECT_TRUE(scheduler->ManageTilesPending()); 1115 scheduler->DidManageTiles(); 1116 EXPECT_FALSE(scheduler->ManageTilesPending()); 1117 1118 client.Reset(); 1119 scheduler->OnBeginImplFrameDeadline(); 1120 EXPECT_EQ(1, client.num_draws()); 1121 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); 1122 EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles")); 1123 EXPECT_FALSE(scheduler->RedrawPending()); 1124 EXPECT_FALSE(scheduler->ManageTilesPending()); 1125 1126 // Next frame without DidManageTiles should ManageTiles with draw. 1127 scheduler->SetNeedsManageTiles(); 1128 scheduler->SetNeedsRedraw(); 1129 client.Reset(); 1130 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 1131 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); 1132 1133 client.Reset(); 1134 scheduler->OnBeginImplFrameDeadline(); 1135 EXPECT_EQ(1, client.num_draws()); 1136 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); 1137 EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles")); 1138 EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"), 1139 client.ActionIndex("ScheduledActionManageTiles")); 1140 EXPECT_FALSE(scheduler->RedrawPending()); 1141 EXPECT_FALSE(scheduler->ManageTilesPending()); 1142 } 1143 1144 class SchedulerClientWithFixedEstimates : public FakeSchedulerClient { 1145 public: 1146 SchedulerClientWithFixedEstimates( 1147 base::TimeDelta draw_duration, 1148 base::TimeDelta begin_main_frame_to_commit_duration, 1149 base::TimeDelta commit_to_activate_duration) 1150 : draw_duration_(draw_duration), 1151 begin_main_frame_to_commit_duration_( 1152 begin_main_frame_to_commit_duration), 1153 commit_to_activate_duration_(commit_to_activate_duration) {} 1154 1155 virtual base::TimeDelta DrawDurationEstimate() OVERRIDE { 1156 return draw_duration_; 1157 } 1158 virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE { 1159 return begin_main_frame_to_commit_duration_; 1160 } 1161 virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE { 1162 return commit_to_activate_duration_; 1163 } 1164 1165 private: 1166 base::TimeDelta draw_duration_; 1167 base::TimeDelta begin_main_frame_to_commit_duration_; 1168 base::TimeDelta commit_to_activate_duration_; 1169 }; 1170 1171 void MainFrameInHighLatencyMode(int64 begin_main_frame_to_commit_estimate_in_ms, 1172 int64 commit_to_activate_estimate_in_ms, 1173 bool should_send_begin_main_frame) { 1174 // Set up client with specified estimates (draw duration is set to 1). 1175 SchedulerClientWithFixedEstimates client( 1176 base::TimeDelta::FromMilliseconds(1), 1177 base::TimeDelta::FromMilliseconds( 1178 begin_main_frame_to_commit_estimate_in_ms), 1179 base::TimeDelta::FromMilliseconds(commit_to_activate_estimate_in_ms)); 1180 SchedulerSettings scheduler_settings; 1181 scheduler_settings.deadline_scheduling_enabled = true; 1182 scheduler_settings.switch_to_low_latency_if_possible = true; 1183 Scheduler* scheduler = client.CreateScheduler(scheduler_settings); 1184 scheduler->SetCanStart(); 1185 scheduler->SetVisible(true); 1186 scheduler->SetCanDraw(true); 1187 InitializeOutputSurfaceAndFirstCommit(scheduler); 1188 1189 // Impl thread hits deadline before commit finishes. 1190 client.Reset(); 1191 scheduler->SetNeedsCommit(); 1192 EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode()); 1193 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 1194 EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode()); 1195 scheduler->OnBeginImplFrameDeadline(); 1196 EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode()); 1197 scheduler->FinishCommit(); 1198 EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode()); 1199 EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame")); 1200 1201 client.Reset(); 1202 scheduler->SetNeedsCommit(); 1203 EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode()); 1204 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); 1205 EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode()); 1206 scheduler->OnBeginImplFrameDeadline(); 1207 EXPECT_EQ(scheduler->MainThreadIsInHighLatencyMode(), 1208 should_send_begin_main_frame); 1209 EXPECT_EQ(client.HasAction("ScheduledActionSendBeginMainFrame"), 1210 should_send_begin_main_frame); 1211 } 1212 1213 TEST(SchedulerTest, 1214 SkipMainFrameIfHighLatencyAndCanCommitAndActivateBeforeDeadline) { 1215 // Set up client so that estimates indicate that we can commit and activate 1216 // before the deadline (~8ms by default). 1217 MainFrameInHighLatencyMode(1, 1, false); 1218 } 1219 1220 TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanCommitTooLong) { 1221 // Set up client so that estimates indicate that the commit cannot finish 1222 // before the deadline (~8ms by default). 1223 MainFrameInHighLatencyMode(10, 1, true); 1224 } 1225 1226 TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanActivateTooLong) { 1227 // Set up client so that estimates indicate that the activate cannot finish 1228 // before the deadline (~8ms by default). 1229 MainFrameInHighLatencyMode(1, 10, true); 1230 } 1231 1232 void SpinForMillis(int millis) { 1233 base::RunLoop run_loop; 1234 base::MessageLoop::current()->PostDelayedTask( 1235 FROM_HERE, 1236 run_loop.QuitClosure(), 1237 base::TimeDelta::FromMilliseconds(millis)); 1238 run_loop.Run(); 1239 } 1240 1241 TEST(SchedulerTest, PollForCommitCompletion) { 1242 FakeSchedulerClient client; 1243 client.set_log_anticipated_draw_time_change(true); 1244 SchedulerSettings settings = SchedulerSettings(); 1245 settings.throttle_frame_production = false; 1246 Scheduler* scheduler = client.CreateScheduler(settings); 1247 1248 scheduler->SetCanDraw(true); 1249 scheduler->SetCanStart(); 1250 scheduler->SetVisible(true); 1251 scheduler->DidCreateAndInitializeOutputSurface(); 1252 1253 scheduler->SetNeedsCommit(); 1254 EXPECT_TRUE(scheduler->CommitPending()); 1255 scheduler->FinishCommit(); 1256 scheduler->SetNeedsRedraw(); 1257 BeginFrameArgs impl_frame_args = BeginFrameArgs::CreateForTesting(); 1258 const int interval = 1; 1259 impl_frame_args.interval = base::TimeDelta::FromMilliseconds(interval); 1260 scheduler->BeginImplFrame(impl_frame_args); 1261 scheduler->OnBeginImplFrameDeadline(); 1262 1263 // At this point, we've drawn a frame. Start another commit, but hold off on 1264 // the FinishCommit for now. 1265 EXPECT_FALSE(scheduler->CommitPending()); 1266 scheduler->SetNeedsCommit(); 1267 EXPECT_TRUE(scheduler->CommitPending()); 1268 1269 // Spin the event loop a few times and make sure we get more 1270 // DidAnticipateDrawTimeChange calls every time. 1271 int actions_so_far = client.num_actions_(); 1272 1273 // Does three iterations to make sure that the timer is properly repeating. 1274 for (int i = 0; i < 3; ++i) { 1275 // Wait for 2x the frame interval to match 1276 // Scheduler::advance_commit_state_timer_'s rate. 1277 SpinForMillis(interval * 2); 1278 EXPECT_GT(client.num_actions_(), actions_so_far); 1279 EXPECT_STREQ(client.Action(client.num_actions_() - 1), 1280 "DidAnticipatedDrawTimeChange"); 1281 actions_so_far = client.num_actions_(); 1282 } 1283 } 1284 1285 } // namespace 1286 } // namespace cc 1287