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/debug/trace_event.h" 10 #include "base/logging.h" 11 #include "base/memory/scoped_vector.h" 12 #include "base/message_loop/message_loop.h" 13 #include "base/run_loop.h" 14 #include "base/time/time.h" 15 #include "cc/test/begin_frame_args_test.h" 16 #include "cc/test/ordered_simple_task_runner.h" 17 #include "cc/test/scheduler_test_common.h" 18 #include "testing/gmock/include/gmock/gmock.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 21 #define EXPECT_ACTION(action, client, action_index, expected_num_actions) \ 22 do { \ 23 EXPECT_EQ(expected_num_actions, client.num_actions_()); \ 24 if (action_index >= 0) { \ 25 ASSERT_LT(action_index, client.num_actions_()) << scheduler; \ 26 EXPECT_STREQ(action, client.Action(action_index)); \ 27 } \ 28 for (int i = expected_num_actions; i < client.num_actions_(); ++i) \ 29 ADD_FAILURE() << "Unexpected action: " << client.Action(i) \ 30 << " with state:\n" << client.StateForAction(i); \ 31 } while (false) 32 33 #define EXPECT_NO_ACTION(client) EXPECT_ACTION("", client, -1, 0) 34 35 #define EXPECT_SINGLE_ACTION(action, client) \ 36 EXPECT_ACTION(action, client, 0, 1) 37 38 namespace cc { 39 namespace { 40 41 class FakeSchedulerClient; 42 43 void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler, 44 FakeSchedulerClient* client); 45 46 class FakeSchedulerClient : public SchedulerClient { 47 public: 48 FakeSchedulerClient() 49 : needs_begin_frame_(false), 50 automatic_swap_ack_(true), 51 swap_contains_incomplete_tile_(false), 52 redraw_will_happen_if_update_visible_tiles_happens_(false), 53 now_src_(TestNowSource::Create()) { 54 Reset(); 55 } 56 57 void Reset() { 58 actions_.clear(); 59 states_.clear(); 60 draw_will_happen_ = true; 61 swap_will_happen_if_draw_happens_ = true; 62 num_draws_ = 0; 63 log_anticipated_draw_time_change_ = false; 64 } 65 66 TestScheduler* CreateScheduler(const SchedulerSettings& settings) { 67 scheduler_ = TestScheduler::Create(now_src_, this, settings, 0); 68 // Fail if we need to run 100 tasks in a row. 69 task_runner().SetRunTaskLimit(100); 70 return scheduler_.get(); 71 } 72 73 // Most tests don't care about DidAnticipatedDrawTimeChange, so only record it 74 // for tests that do. 75 void set_log_anticipated_draw_time_change(bool log) { 76 log_anticipated_draw_time_change_ = log; 77 } 78 bool needs_begin_frame() { return needs_begin_frame_; } 79 int num_draws() const { return num_draws_; } 80 int num_actions_() const { return static_cast<int>(actions_.size()); } 81 const char* Action(int i) const { return actions_[i]; } 82 std::string StateForAction(int i) const { return states_[i]->ToString(); } 83 base::TimeTicks posted_begin_impl_frame_deadline() const { 84 return posted_begin_impl_frame_deadline_; 85 } 86 87 void AdvanceFrame() { 88 bool external_begin_frame = 89 scheduler_->settings().begin_frame_scheduling_enabled && 90 scheduler_->settings().throttle_frame_production; 91 92 if (external_begin_frame) { 93 scheduler_->BeginFrame(CreateBeginFrameArgsForTesting(now_src_)); 94 } 95 96 EXPECT_TRUE(task_runner().RunTasksWhile(ImplFrameDeadlinePending(false))); 97 EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); 98 } 99 100 OrderedSimpleTaskRunner& task_runner() { return scheduler_->task_runner(); } 101 TestNowSource* now_src() { return now_src_.get(); } 102 103 int ActionIndex(const char* action) const { 104 for (size_t i = 0; i < actions_.size(); i++) 105 if (!strcmp(actions_[i], action)) 106 return i; 107 return -1; 108 } 109 110 void SetSwapContainsIncompleteTile(bool contain) { 111 swap_contains_incomplete_tile_ = contain; 112 } 113 114 bool HasAction(const char* action) const { 115 return ActionIndex(action) >= 0; 116 } 117 118 void SetDrawWillHappen(bool draw_will_happen) { 119 draw_will_happen_ = draw_will_happen; 120 } 121 void SetSwapWillHappenIfDrawHappens(bool swap_will_happen_if_draw_happens) { 122 swap_will_happen_if_draw_happens_ = swap_will_happen_if_draw_happens; 123 } 124 void SetAutomaticSwapAck(bool automatic_swap_ack) { 125 automatic_swap_ack_ = automatic_swap_ack; 126 } 127 void SetRedrawWillHappenIfUpdateVisibleTilesHappens(bool redraw) { 128 redraw_will_happen_if_update_visible_tiles_happens_ = redraw; 129 } 130 // SchedulerClient implementation. 131 virtual void SetNeedsBeginFrame(bool enable) OVERRIDE { 132 actions_.push_back("SetNeedsBeginFrame"); 133 states_.push_back(scheduler_->AsValue()); 134 needs_begin_frame_ = enable; 135 } 136 virtual void WillBeginImplFrame(const BeginFrameArgs& args) OVERRIDE { 137 actions_.push_back("WillBeginImplFrame"); 138 states_.push_back(scheduler_->AsValue()); 139 } 140 virtual void ScheduledActionSendBeginMainFrame() OVERRIDE { 141 actions_.push_back("ScheduledActionSendBeginMainFrame"); 142 states_.push_back(scheduler_->AsValue()); 143 } 144 virtual void ScheduledActionAnimate() OVERRIDE { 145 actions_.push_back("ScheduledActionAnimate"); 146 states_.push_back(scheduler_->AsValue()); 147 } 148 virtual DrawResult ScheduledActionDrawAndSwapIfPossible() OVERRIDE { 149 actions_.push_back("ScheduledActionDrawAndSwapIfPossible"); 150 states_.push_back(scheduler_->AsValue()); 151 num_draws_++; 152 DrawResult result = 153 draw_will_happen_ ? DRAW_SUCCESS : DRAW_ABORTED_CHECKERBOARD_ANIMATIONS; 154 bool swap_will_happen = 155 draw_will_happen_ && swap_will_happen_if_draw_happens_; 156 if (swap_will_happen) { 157 scheduler_->DidSwapBuffers(); 158 if (swap_contains_incomplete_tile_) { 159 scheduler_->SetSwapUsedIncompleteTile(true); 160 swap_contains_incomplete_tile_ = false; 161 } else { 162 scheduler_->SetSwapUsedIncompleteTile(false); 163 } 164 165 if (automatic_swap_ack_) 166 scheduler_->DidSwapBuffersComplete(); 167 } 168 return result; 169 } 170 virtual DrawResult ScheduledActionDrawAndSwapForced() OVERRIDE { 171 actions_.push_back("ScheduledActionDrawAndSwapForced"); 172 states_.push_back(scheduler_->AsValue()); 173 return DRAW_SUCCESS; 174 } 175 virtual void ScheduledActionCommit() OVERRIDE { 176 actions_.push_back("ScheduledActionCommit"); 177 states_.push_back(scheduler_->AsValue()); 178 } 179 virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE { 180 actions_.push_back("ScheduledActionUpdateVisibleTiles"); 181 states_.push_back(scheduler_->AsValue()); 182 if (redraw_will_happen_if_update_visible_tiles_happens_) 183 scheduler_->SetNeedsRedraw(); 184 } 185 virtual void ScheduledActionActivateSyncTree() OVERRIDE { 186 actions_.push_back("ScheduledActionActivateSyncTree"); 187 states_.push_back(scheduler_->AsValue()); 188 } 189 virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE { 190 actions_.push_back("ScheduledActionBeginOutputSurfaceCreation"); 191 states_.push_back(scheduler_->AsValue()); 192 } 193 virtual void ScheduledActionManageTiles() OVERRIDE { 194 actions_.push_back("ScheduledActionManageTiles"); 195 states_.push_back(scheduler_->AsValue()); 196 } 197 virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE { 198 if (log_anticipated_draw_time_change_) 199 actions_.push_back("DidAnticipatedDrawTimeChange"); 200 } 201 virtual base::TimeDelta DrawDurationEstimate() OVERRIDE { 202 return base::TimeDelta(); 203 } 204 virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE { 205 return base::TimeDelta(); 206 } 207 virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE { 208 return base::TimeDelta(); 209 } 210 211 virtual void DidBeginImplFrameDeadline() OVERRIDE {} 212 213 base::Callback<bool(void)> ImplFrameDeadlinePending(bool state) { 214 return base::Bind(&FakeSchedulerClient::ImplFrameDeadlinePendingCallback, 215 base::Unretained(this), 216 state); 217 } 218 219 protected: 220 bool ImplFrameDeadlinePendingCallback(bool state) { 221 return scheduler_->BeginImplFrameDeadlinePending() == state; 222 } 223 224 bool needs_begin_frame_; 225 bool draw_will_happen_; 226 bool swap_will_happen_if_draw_happens_; 227 bool automatic_swap_ack_; 228 int num_draws_; 229 bool log_anticipated_draw_time_change_; 230 bool swap_contains_incomplete_tile_; 231 bool redraw_will_happen_if_update_visible_tiles_happens_; 232 base::TimeTicks posted_begin_impl_frame_deadline_; 233 std::vector<const char*> actions_; 234 std::vector<scoped_refptr<base::debug::ConvertableToTraceFormat> > states_; 235 scoped_ptr<TestScheduler> scheduler_; 236 scoped_refptr<TestNowSource> now_src_; 237 }; 238 239 void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler, 240 FakeSchedulerClient* client) { 241 TRACE_EVENT0("cc", 242 "SchedulerUnitTest::InitializeOutputSurfaceAndFirstCommit"); 243 244 scheduler->DidCreateAndInitializeOutputSurface(); 245 scheduler->SetNeedsCommit(); 246 scheduler->NotifyBeginMainFrameStarted(); 247 scheduler->NotifyReadyToCommit(); 248 if (scheduler->settings().impl_side_painting) 249 scheduler->NotifyReadyToActivate(); 250 251 // Go through the motions to draw the commit. 252 client->AdvanceFrame(); 253 254 // Run the posted deadline task. 255 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 256 client->task_runner().RunTasksWhile(client->ImplFrameDeadlinePending(true)); 257 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 258 259 // We need another BeginImplFrame so Scheduler calls 260 // SetNeedsBeginFrame(false). 261 client->AdvanceFrame(); 262 263 // Run the posted deadline task. 264 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 265 client->task_runner().RunTasksWhile(client->ImplFrameDeadlinePending(true)); 266 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 267 } 268 269 TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginImplFrame) { 270 FakeSchedulerClient client; 271 SchedulerSettings default_scheduler_settings; 272 TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 273 scheduler->SetCanStart(); 274 scheduler->SetVisible(true); 275 scheduler->SetCanDraw(true); 276 277 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 278 client.Reset(); 279 scheduler->DidCreateAndInitializeOutputSurface(); 280 EXPECT_NO_ACTION(client); 281 } 282 283 TEST(SchedulerTest, RequestCommit) { 284 FakeSchedulerClient client; 285 SchedulerSettings scheduler_settings; 286 TestScheduler* scheduler = client.CreateScheduler(scheduler_settings); 287 scheduler->SetCanStart(); 288 scheduler->SetVisible(true); 289 scheduler->SetCanDraw(true); 290 291 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 292 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 293 294 // SetNeedsCommit should begin the frame on the next BeginImplFrame. 295 client.Reset(); 296 scheduler->SetNeedsCommit(); 297 EXPECT_TRUE(client.needs_begin_frame()); 298 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); 299 client.Reset(); 300 301 client.AdvanceFrame(); 302 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 303 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); 304 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 305 EXPECT_TRUE(client.needs_begin_frame()); 306 client.Reset(); 307 308 // If we don't swap on the deadline, we wait for the next BeginFrame. 309 client.task_runner().RunPendingTasks(); // Run posted deadline. 310 EXPECT_NO_ACTION(client); 311 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 312 EXPECT_TRUE(client.needs_begin_frame()); 313 client.Reset(); 314 315 // NotifyReadyToCommit should trigger the commit. 316 scheduler->NotifyBeginMainFrameStarted(); 317 scheduler->NotifyReadyToCommit(); 318 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); 319 EXPECT_TRUE(client.needs_begin_frame()); 320 client.Reset(); 321 322 // BeginImplFrame should prepare the draw. 323 client.AdvanceFrame(); 324 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 325 EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); 326 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 327 EXPECT_TRUE(client.needs_begin_frame()); 328 client.Reset(); 329 330 // BeginImplFrame deadline should draw. 331 client.task_runner().RunPendingTasks(); // Run posted deadline. 332 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1); 333 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 334 EXPECT_TRUE(client.needs_begin_frame()); 335 client.Reset(); 336 337 // The following BeginImplFrame deadline should SetNeedsBeginFrame(false) 338 // to avoid excessive toggles. 339 client.AdvanceFrame(); 340 EXPECT_SINGLE_ACTION("WillBeginImplFrame", client); 341 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 342 client.Reset(); 343 344 client.task_runner().RunPendingTasks(); // Run posted deadline. 345 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); 346 EXPECT_FALSE(client.needs_begin_frame()); 347 client.Reset(); 348 } 349 350 TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) { 351 FakeSchedulerClient client; 352 SchedulerSettings scheduler_settings; 353 TestScheduler* scheduler = client.CreateScheduler(scheduler_settings); 354 scheduler->SetCanStart(); 355 scheduler->SetVisible(true); 356 scheduler->SetCanDraw(true); 357 358 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 359 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 360 client.Reset(); 361 362 // SetNeedsCommit should begin the frame. 363 scheduler->SetNeedsCommit(); 364 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); 365 366 client.Reset(); 367 client.AdvanceFrame(); 368 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 369 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); 370 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 371 372 EXPECT_TRUE(client.needs_begin_frame()); 373 client.Reset(); 374 375 // Now SetNeedsCommit again. Calling here means we need a second commit. 376 scheduler->SetNeedsCommit(); 377 EXPECT_EQ(client.num_actions_(), 0); 378 client.Reset(); 379 380 // Finish the first commit. 381 scheduler->NotifyBeginMainFrameStarted(); 382 scheduler->NotifyReadyToCommit(); 383 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); 384 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 385 client.Reset(); 386 client.task_runner().RunPendingTasks(); // Run posted deadline. 387 EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2); 388 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2); 389 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 390 391 // Because we just swapped, the Scheduler should also request the next 392 // BeginImplFrame from the OutputSurface. 393 EXPECT_TRUE(client.needs_begin_frame()); 394 client.Reset(); 395 // Since another commit is needed, the next BeginImplFrame should initiate 396 // the second commit. 397 client.AdvanceFrame(); 398 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 399 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); 400 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 401 client.Reset(); 402 403 // Finishing the commit before the deadline should post a new deadline task 404 // to trigger the deadline early. 405 scheduler->NotifyBeginMainFrameStarted(); 406 scheduler->NotifyReadyToCommit(); 407 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); 408 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 409 client.Reset(); 410 client.task_runner().RunPendingTasks(); // Run posted deadline. 411 EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2); 412 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2); 413 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 414 EXPECT_TRUE(client.needs_begin_frame()); 415 client.Reset(); 416 417 // On the next BeginImplFrame, verify we go back to a quiescent state and 418 // no longer request BeginImplFrames. 419 client.AdvanceFrame(); 420 client.task_runner().RunPendingTasks(); // Run posted deadline. 421 EXPECT_FALSE(client.needs_begin_frame()); 422 client.Reset(); 423 } 424 425 class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient { 426 public: 427 virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {} 428 virtual DrawResult ScheduledActionDrawAndSwapIfPossible() 429 OVERRIDE { 430 // Only SetNeedsRedraw the first time this is called 431 if (!num_draws_) 432 scheduler_->SetNeedsRedraw(); 433 return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible(); 434 } 435 436 virtual DrawResult ScheduledActionDrawAndSwapForced() OVERRIDE { 437 NOTREACHED(); 438 return DRAW_SUCCESS; 439 } 440 441 virtual void ScheduledActionCommit() OVERRIDE {} 442 virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {} 443 virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {} 444 }; 445 446 // Tests for two different situations: 447 // 1. the scheduler dropping SetNeedsRedraw requests that happen inside 448 // a ScheduledActionDrawAndSwap 449 // 2. the scheduler drawing twice inside a single tick 450 TEST(SchedulerTest, RequestRedrawInsideDraw) { 451 SchedulerClientThatsetNeedsDrawInsideDraw client; 452 SchedulerSettings default_scheduler_settings; 453 TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 454 scheduler->SetCanStart(); 455 scheduler->SetVisible(true); 456 scheduler->SetCanDraw(true); 457 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 458 client.Reset(); 459 460 scheduler->SetNeedsRedraw(); 461 EXPECT_TRUE(scheduler->RedrawPending()); 462 EXPECT_TRUE(client.needs_begin_frame()); 463 EXPECT_EQ(0, client.num_draws()); 464 465 client.AdvanceFrame(); 466 client.task_runner().RunPendingTasks(); // Run posted deadline. 467 EXPECT_EQ(1, client.num_draws()); 468 EXPECT_TRUE(scheduler->RedrawPending()); 469 EXPECT_TRUE(client.needs_begin_frame()); 470 471 client.AdvanceFrame(); 472 client.task_runner().RunPendingTasks(); // Run posted deadline. 473 EXPECT_EQ(2, client.num_draws()); 474 EXPECT_FALSE(scheduler->RedrawPending()); 475 EXPECT_TRUE(client.needs_begin_frame()); 476 477 // We stop requesting BeginImplFrames after a BeginImplFrame where we don't 478 // swap. 479 client.AdvanceFrame(); 480 client.task_runner().RunPendingTasks(); // Run posted deadline. 481 EXPECT_EQ(2, client.num_draws()); 482 EXPECT_FALSE(scheduler->RedrawPending()); 483 EXPECT_FALSE(client.needs_begin_frame()); 484 } 485 486 // Test that requesting redraw inside a failed draw doesn't lose the request. 487 TEST(SchedulerTest, RequestRedrawInsideFailedDraw) { 488 SchedulerClientThatsetNeedsDrawInsideDraw client; 489 SchedulerSettings default_scheduler_settings; 490 TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 491 scheduler->SetCanStart(); 492 scheduler->SetVisible(true); 493 scheduler->SetCanDraw(true); 494 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 495 client.Reset(); 496 497 client.SetDrawWillHappen(false); 498 499 scheduler->SetNeedsRedraw(); 500 EXPECT_TRUE(scheduler->RedrawPending()); 501 EXPECT_TRUE(client.needs_begin_frame()); 502 EXPECT_EQ(0, client.num_draws()); 503 504 // Fail the draw. 505 client.AdvanceFrame(); 506 client.task_runner().RunPendingTasks(); // Run posted deadline. 507 EXPECT_EQ(1, client.num_draws()); 508 509 // We have a commit pending and the draw failed, and we didn't lose the redraw 510 // request. 511 EXPECT_TRUE(scheduler->CommitPending()); 512 EXPECT_TRUE(scheduler->RedrawPending()); 513 EXPECT_TRUE(client.needs_begin_frame()); 514 515 // Fail the draw again. 516 client.AdvanceFrame(); 517 client.task_runner().RunPendingTasks(); // Run posted deadline. 518 EXPECT_EQ(2, client.num_draws()); 519 EXPECT_TRUE(scheduler->CommitPending()); 520 EXPECT_TRUE(scheduler->RedrawPending()); 521 EXPECT_TRUE(client.needs_begin_frame()); 522 523 // Draw successfully. 524 client.SetDrawWillHappen(true); 525 client.AdvanceFrame(); 526 client.task_runner().RunPendingTasks(); // Run posted deadline. 527 EXPECT_EQ(3, client.num_draws()); 528 EXPECT_TRUE(scheduler->CommitPending()); 529 EXPECT_FALSE(scheduler->RedrawPending()); 530 EXPECT_TRUE(client.needs_begin_frame()); 531 } 532 533 class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient { 534 public: 535 SchedulerClientThatSetNeedsCommitInsideDraw() 536 : set_needs_commit_on_next_draw_(false) {} 537 538 virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {} 539 virtual DrawResult ScheduledActionDrawAndSwapIfPossible() 540 OVERRIDE { 541 // Only SetNeedsCommit the first time this is called 542 if (set_needs_commit_on_next_draw_) { 543 scheduler_->SetNeedsCommit(); 544 set_needs_commit_on_next_draw_ = false; 545 } 546 return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible(); 547 } 548 549 virtual DrawResult ScheduledActionDrawAndSwapForced() OVERRIDE { 550 NOTREACHED(); 551 return DRAW_SUCCESS; 552 } 553 554 virtual void ScheduledActionCommit() OVERRIDE {} 555 virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {} 556 virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {} 557 558 void SetNeedsCommitOnNextDraw() { set_needs_commit_on_next_draw_ = true; } 559 560 private: 561 bool set_needs_commit_on_next_draw_; 562 }; 563 564 // Tests for the scheduler infinite-looping on SetNeedsCommit requests that 565 // happen inside a ScheduledActionDrawAndSwap 566 TEST(SchedulerTest, RequestCommitInsideDraw) { 567 SchedulerClientThatSetNeedsCommitInsideDraw client; 568 SchedulerSettings default_scheduler_settings; 569 TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 570 scheduler->SetCanStart(); 571 scheduler->SetVisible(true); 572 scheduler->SetCanDraw(true); 573 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 574 client.Reset(); 575 576 EXPECT_FALSE(client.needs_begin_frame()); 577 scheduler->SetNeedsRedraw(); 578 EXPECT_TRUE(scheduler->RedrawPending()); 579 EXPECT_EQ(0, client.num_draws()); 580 EXPECT_TRUE(client.needs_begin_frame()); 581 582 client.SetNeedsCommitOnNextDraw(); 583 client.AdvanceFrame(); 584 client.SetNeedsCommitOnNextDraw(); 585 client.task_runner().RunPendingTasks(); // Run posted deadline. 586 EXPECT_EQ(1, client.num_draws()); 587 EXPECT_TRUE(scheduler->CommitPending()); 588 EXPECT_TRUE(client.needs_begin_frame()); 589 scheduler->NotifyBeginMainFrameStarted(); 590 scheduler->NotifyReadyToCommit(); 591 592 client.AdvanceFrame(); 593 client.task_runner().RunPendingTasks(); // Run posted deadline. 594 EXPECT_EQ(2, client.num_draws()); 595 596 EXPECT_FALSE(scheduler->RedrawPending()); 597 EXPECT_FALSE(scheduler->CommitPending()); 598 EXPECT_TRUE(client.needs_begin_frame()); 599 600 // We stop requesting BeginImplFrames after a BeginImplFrame where we don't 601 // swap. 602 client.AdvanceFrame(); 603 client.task_runner().RunPendingTasks(); // Run posted deadline. 604 EXPECT_EQ(2, client.num_draws()); 605 EXPECT_FALSE(scheduler->RedrawPending()); 606 EXPECT_FALSE(scheduler->CommitPending()); 607 EXPECT_FALSE(client.needs_begin_frame()); 608 } 609 610 // Tests that when a draw fails then the pending commit should not be dropped. 611 TEST(SchedulerTest, RequestCommitInsideFailedDraw) { 612 SchedulerClientThatsetNeedsDrawInsideDraw client; 613 SchedulerSettings default_scheduler_settings; 614 TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 615 scheduler->SetCanStart(); 616 scheduler->SetVisible(true); 617 scheduler->SetCanDraw(true); 618 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 619 client.Reset(); 620 621 client.SetDrawWillHappen(false); 622 623 scheduler->SetNeedsRedraw(); 624 EXPECT_TRUE(scheduler->RedrawPending()); 625 EXPECT_TRUE(client.needs_begin_frame()); 626 EXPECT_EQ(0, client.num_draws()); 627 628 // Fail the draw. 629 client.AdvanceFrame(); 630 client.task_runner().RunPendingTasks(); // Run posted deadline. 631 EXPECT_EQ(1, client.num_draws()); 632 633 // We have a commit pending and the draw failed, and we didn't lose the commit 634 // request. 635 EXPECT_TRUE(scheduler->CommitPending()); 636 EXPECT_TRUE(scheduler->RedrawPending()); 637 EXPECT_TRUE(client.needs_begin_frame()); 638 639 // Fail the draw again. 640 client.AdvanceFrame(); 641 642 client.task_runner().RunPendingTasks(); // Run posted deadline. 643 EXPECT_EQ(2, client.num_draws()); 644 EXPECT_TRUE(scheduler->CommitPending()); 645 EXPECT_TRUE(scheduler->RedrawPending()); 646 EXPECT_TRUE(client.needs_begin_frame()); 647 648 // Draw successfully. 649 client.SetDrawWillHappen(true); 650 client.AdvanceFrame(); 651 client.task_runner().RunPendingTasks(); // Run posted deadline. 652 EXPECT_EQ(3, client.num_draws()); 653 EXPECT_TRUE(scheduler->CommitPending()); 654 EXPECT_FALSE(scheduler->RedrawPending()); 655 EXPECT_TRUE(client.needs_begin_frame()); 656 } 657 658 TEST(SchedulerTest, NoSwapWhenDrawFails) { 659 SchedulerClientThatSetNeedsCommitInsideDraw client; 660 SchedulerSettings default_scheduler_settings; 661 TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 662 scheduler->SetCanStart(); 663 scheduler->SetVisible(true); 664 scheduler->SetCanDraw(true); 665 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 666 client.Reset(); 667 668 scheduler->SetNeedsRedraw(); 669 EXPECT_TRUE(scheduler->RedrawPending()); 670 EXPECT_TRUE(client.needs_begin_frame()); 671 EXPECT_EQ(0, client.num_draws()); 672 673 // Draw successfully, this starts a new frame. 674 client.SetNeedsCommitOnNextDraw(); 675 client.AdvanceFrame(); 676 client.task_runner().RunPendingTasks(); // Run posted deadline. 677 EXPECT_EQ(1, client.num_draws()); 678 679 scheduler->SetNeedsRedraw(); 680 EXPECT_TRUE(scheduler->RedrawPending()); 681 EXPECT_TRUE(client.needs_begin_frame()); 682 683 // Fail to draw, this should not start a frame. 684 client.SetDrawWillHappen(false); 685 client.SetNeedsCommitOnNextDraw(); 686 client.AdvanceFrame(); 687 client.task_runner().RunPendingTasks(); // Run posted deadline. 688 EXPECT_EQ(2, client.num_draws()); 689 } 690 691 class SchedulerClientNeedsManageTilesInDraw : public FakeSchedulerClient { 692 public: 693 virtual DrawResult ScheduledActionDrawAndSwapIfPossible() 694 OVERRIDE { 695 scheduler_->SetNeedsManageTiles(); 696 return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible(); 697 } 698 }; 699 700 // Test manage tiles is independant of draws. 701 TEST(SchedulerTest, ManageTiles) { 702 SchedulerClientNeedsManageTilesInDraw client; 703 SchedulerSettings default_scheduler_settings; 704 TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 705 scheduler->SetCanStart(); 706 scheduler->SetVisible(true); 707 scheduler->SetCanDraw(true); 708 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 709 710 // Request both draw and manage tiles. ManageTiles shouldn't 711 // be trigged until BeginImplFrame. 712 client.Reset(); 713 scheduler->SetNeedsManageTiles(); 714 scheduler->SetNeedsRedraw(); 715 EXPECT_TRUE(scheduler->RedrawPending()); 716 EXPECT_TRUE(scheduler->ManageTilesPending()); 717 EXPECT_TRUE(client.needs_begin_frame()); 718 EXPECT_EQ(0, client.num_draws()); 719 EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles")); 720 EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); 721 722 // We have no immediate actions to perform, so the BeginImplFrame should post 723 // the deadline task. 724 client.Reset(); 725 client.AdvanceFrame(); 726 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 727 EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); 728 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 729 730 // On the deadline, he actions should have occured in the right order. 731 client.Reset(); 732 client.task_runner().RunPendingTasks(); // Run posted deadline. 733 EXPECT_EQ(1, client.num_draws()); 734 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); 735 EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles")); 736 EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"), 737 client.ActionIndex("ScheduledActionManageTiles")); 738 EXPECT_FALSE(scheduler->RedrawPending()); 739 EXPECT_FALSE(scheduler->ManageTilesPending()); 740 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 741 742 // Request a draw. We don't need a ManageTiles yet. 743 client.Reset(); 744 scheduler->SetNeedsRedraw(); 745 EXPECT_TRUE(scheduler->RedrawPending()); 746 EXPECT_FALSE(scheduler->ManageTilesPending()); 747 EXPECT_TRUE(client.needs_begin_frame()); 748 EXPECT_EQ(0, client.num_draws()); 749 750 // We have no immediate actions to perform, so the BeginImplFrame should post 751 // the deadline task. 752 client.Reset(); 753 client.AdvanceFrame(); 754 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 755 EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); 756 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 757 758 // Draw. The draw will trigger SetNeedsManageTiles, and 759 // then the ManageTiles action will be triggered after the Draw. 760 // Afterwards, neither a draw nor ManageTiles are pending. 761 client.Reset(); 762 client.task_runner().RunPendingTasks(); // Run posted deadline. 763 EXPECT_EQ(1, client.num_draws()); 764 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); 765 EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles")); 766 EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"), 767 client.ActionIndex("ScheduledActionManageTiles")); 768 EXPECT_FALSE(scheduler->RedrawPending()); 769 EXPECT_FALSE(scheduler->ManageTilesPending()); 770 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 771 772 // We need a BeginImplFrame where we don't swap to go idle. 773 client.Reset(); 774 client.AdvanceFrame(); 775 EXPECT_SINGLE_ACTION("WillBeginImplFrame", client); 776 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 777 client.Reset(); 778 client.task_runner().RunPendingTasks(); // Run posted deadline. 779 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); 780 EXPECT_FALSE(client.needs_begin_frame()); 781 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 782 EXPECT_EQ(0, client.num_draws()); 783 784 // Now trigger a ManageTiles outside of a draw. We will then need 785 // a begin-frame for the ManageTiles, but we don't need a draw. 786 client.Reset(); 787 EXPECT_FALSE(client.needs_begin_frame()); 788 scheduler->SetNeedsManageTiles(); 789 EXPECT_TRUE(client.needs_begin_frame()); 790 EXPECT_TRUE(scheduler->ManageTilesPending()); 791 EXPECT_FALSE(scheduler->RedrawPending()); 792 793 // BeginImplFrame. There will be no draw, only ManageTiles. 794 client.Reset(); 795 client.AdvanceFrame(); 796 EXPECT_SINGLE_ACTION("WillBeginImplFrame", client); 797 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 798 client.Reset(); 799 client.task_runner().RunPendingTasks(); // Run posted deadline. 800 EXPECT_EQ(0, client.num_draws()); 801 EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); 802 EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles")); 803 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 804 } 805 806 // Test that ManageTiles only happens once per frame. If an external caller 807 // initiates it, then the state machine should not ManageTiles on that frame. 808 TEST(SchedulerTest, ManageTilesOncePerFrame) { 809 FakeSchedulerClient client; 810 SchedulerSettings default_scheduler_settings; 811 TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 812 scheduler->SetCanStart(); 813 scheduler->SetVisible(true); 814 scheduler->SetCanDraw(true); 815 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 816 817 // If DidManageTiles during a frame, then ManageTiles should not occur again. 818 scheduler->SetNeedsManageTiles(); 819 scheduler->SetNeedsRedraw(); 820 client.Reset(); 821 client.AdvanceFrame(); 822 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 823 EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); 824 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 825 826 EXPECT_TRUE(scheduler->ManageTilesPending()); 827 scheduler->DidManageTiles(); // An explicit ManageTiles. 828 EXPECT_FALSE(scheduler->ManageTilesPending()); 829 830 client.Reset(); 831 client.task_runner().RunPendingTasks(); // Run posted deadline. 832 EXPECT_EQ(1, client.num_draws()); 833 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); 834 EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles")); 835 EXPECT_FALSE(scheduler->RedrawPending()); 836 EXPECT_FALSE(scheduler->ManageTilesPending()); 837 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 838 839 // Next frame without DidManageTiles should ManageTiles with draw. 840 scheduler->SetNeedsManageTiles(); 841 scheduler->SetNeedsRedraw(); 842 client.Reset(); 843 client.AdvanceFrame(); 844 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 845 EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); 846 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 847 848 client.Reset(); 849 client.task_runner().RunPendingTasks(); // Run posted deadline. 850 EXPECT_EQ(1, client.num_draws()); 851 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); 852 EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles")); 853 EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"), 854 client.ActionIndex("ScheduledActionManageTiles")); 855 EXPECT_FALSE(scheduler->RedrawPending()); 856 EXPECT_FALSE(scheduler->ManageTilesPending()); 857 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 858 scheduler->DidManageTiles(); // Corresponds to ScheduledActionManageTiles 859 860 // If we get another DidManageTiles within the same frame, we should 861 // not ManageTiles on the next frame. 862 scheduler->DidManageTiles(); // An explicit ManageTiles. 863 scheduler->SetNeedsManageTiles(); 864 scheduler->SetNeedsRedraw(); 865 client.Reset(); 866 client.AdvanceFrame(); 867 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 868 EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); 869 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 870 871 EXPECT_TRUE(scheduler->ManageTilesPending()); 872 873 client.Reset(); 874 client.task_runner().RunPendingTasks(); // Run posted deadline. 875 EXPECT_EQ(1, client.num_draws()); 876 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); 877 EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles")); 878 EXPECT_FALSE(scheduler->RedrawPending()); 879 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 880 881 // If we get another DidManageTiles, we should not ManageTiles on the next 882 // frame. This verifies we don't alternate calling ManageTiles once and twice. 883 EXPECT_TRUE(scheduler->ManageTilesPending()); 884 scheduler->DidManageTiles(); // An explicit ManageTiles. 885 EXPECT_FALSE(scheduler->ManageTilesPending()); 886 scheduler->SetNeedsManageTiles(); 887 scheduler->SetNeedsRedraw(); 888 client.Reset(); 889 client.AdvanceFrame(); 890 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 891 EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); 892 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 893 894 EXPECT_TRUE(scheduler->ManageTilesPending()); 895 896 client.Reset(); 897 client.task_runner().RunPendingTasks(); // Run posted deadline. 898 EXPECT_EQ(1, client.num_draws()); 899 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); 900 EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles")); 901 EXPECT_FALSE(scheduler->RedrawPending()); 902 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 903 904 // Next frame without DidManageTiles should ManageTiles with draw. 905 scheduler->SetNeedsManageTiles(); 906 scheduler->SetNeedsRedraw(); 907 client.Reset(); 908 client.AdvanceFrame(); 909 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 910 EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); 911 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 912 913 client.Reset(); 914 client.task_runner().RunPendingTasks(); // Run posted deadline. 915 EXPECT_EQ(1, client.num_draws()); 916 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); 917 EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles")); 918 EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"), 919 client.ActionIndex("ScheduledActionManageTiles")); 920 EXPECT_FALSE(scheduler->RedrawPending()); 921 EXPECT_FALSE(scheduler->ManageTilesPending()); 922 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 923 scheduler->DidManageTiles(); // Corresponds to ScheduledActionManageTiles 924 } 925 926 TEST(SchedulerTest, ShouldUpdateVisibleTiles) { 927 FakeSchedulerClient client; 928 SchedulerSettings scheduler_settings; 929 scheduler_settings.impl_side_painting = true; 930 TestScheduler* scheduler = client.CreateScheduler(scheduler_settings); 931 scheduler->SetCanStart(); 932 scheduler->SetVisible(true); 933 scheduler->SetCanDraw(true); 934 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 935 936 client.SetRedrawWillHappenIfUpdateVisibleTilesHappens(true); 937 938 // SetNeedsCommit should begin the frame. 939 client.Reset(); 940 scheduler->SetNeedsCommit(); 941 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); 942 943 client.Reset(); 944 client.AdvanceFrame(); 945 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 946 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); 947 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 948 949 client.Reset(); 950 scheduler->NotifyBeginMainFrameStarted(); 951 scheduler->NotifyReadyToCommit(); 952 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); 953 954 client.Reset(); 955 scheduler->NotifyReadyToActivate(); 956 EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client); 957 958 client.Reset(); 959 client.SetSwapContainsIncompleteTile(true); 960 client.task_runner().RunPendingTasks(); // Run posted deadline. 961 EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2); 962 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2); 963 EXPECT_FALSE(scheduler->RedrawPending()); 964 965 client.Reset(); 966 client.AdvanceFrame(); 967 EXPECT_SINGLE_ACTION("WillBeginImplFrame", client); 968 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 969 970 client.Reset(); 971 client.task_runner().RunPendingTasks(); // Run posted deadline. 972 EXPECT_ACTION("ScheduledActionUpdateVisibleTiles", client, 0, 3); 973 EXPECT_ACTION("ScheduledActionAnimate", client, 1, 3); 974 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 2, 3); 975 976 client.Reset(); 977 client.AdvanceFrame(); 978 EXPECT_SINGLE_ACTION("WillBeginImplFrame", client); 979 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 980 981 // No more UpdateVisibleTiles(). 982 client.Reset(); 983 client.task_runner().RunPendingTasks(); // Run posted deadline. 984 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); 985 EXPECT_FALSE(client.needs_begin_frame()); 986 } 987 988 TEST(SchedulerTest, TriggerBeginFrameDeadlineEarly) { 989 SchedulerClientNeedsManageTilesInDraw client; 990 SchedulerSettings default_scheduler_settings; 991 TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 992 scheduler->SetCanStart(); 993 scheduler->SetVisible(true); 994 scheduler->SetCanDraw(true); 995 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 996 997 client.Reset(); 998 scheduler->SetNeedsRedraw(); 999 client.AdvanceFrame(); 1000 1001 // The deadline should be zero since there is no work other than drawing 1002 // pending. 1003 EXPECT_EQ(base::TimeTicks(), client.posted_begin_impl_frame_deadline()); 1004 } 1005 1006 class SchedulerClientWithFixedEstimates : public FakeSchedulerClient { 1007 public: 1008 SchedulerClientWithFixedEstimates( 1009 base::TimeDelta draw_duration, 1010 base::TimeDelta begin_main_frame_to_commit_duration, 1011 base::TimeDelta commit_to_activate_duration) 1012 : draw_duration_(draw_duration), 1013 begin_main_frame_to_commit_duration_( 1014 begin_main_frame_to_commit_duration), 1015 commit_to_activate_duration_(commit_to_activate_duration) {} 1016 1017 virtual base::TimeDelta DrawDurationEstimate() OVERRIDE { 1018 return draw_duration_; 1019 } 1020 virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE { 1021 return begin_main_frame_to_commit_duration_; 1022 } 1023 virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE { 1024 return commit_to_activate_duration_; 1025 } 1026 1027 private: 1028 base::TimeDelta draw_duration_; 1029 base::TimeDelta begin_main_frame_to_commit_duration_; 1030 base::TimeDelta commit_to_activate_duration_; 1031 }; 1032 1033 void MainFrameInHighLatencyMode(int64 begin_main_frame_to_commit_estimate_in_ms, 1034 int64 commit_to_activate_estimate_in_ms, 1035 bool impl_latency_takes_priority, 1036 bool should_send_begin_main_frame) { 1037 // Set up client with specified estimates (draw duration is set to 1). 1038 SchedulerClientWithFixedEstimates client( 1039 base::TimeDelta::FromMilliseconds(1), 1040 base::TimeDelta::FromMilliseconds( 1041 begin_main_frame_to_commit_estimate_in_ms), 1042 base::TimeDelta::FromMilliseconds(commit_to_activate_estimate_in_ms)); 1043 SchedulerSettings default_scheduler_settings; 1044 TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 1045 scheduler->SetCanStart(); 1046 scheduler->SetVisible(true); 1047 scheduler->SetCanDraw(true); 1048 scheduler->SetImplLatencyTakesPriority(impl_latency_takes_priority); 1049 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 1050 1051 // Impl thread hits deadline before commit finishes. 1052 client.Reset(); 1053 scheduler->SetNeedsCommit(); 1054 EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode()); 1055 client.AdvanceFrame(); 1056 EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode()); 1057 client.task_runner().RunPendingTasks(); // Run posted deadline. 1058 EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode()); 1059 scheduler->NotifyBeginMainFrameStarted(); 1060 scheduler->NotifyReadyToCommit(); 1061 EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode()); 1062 EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame")); 1063 1064 client.Reset(); 1065 scheduler->SetNeedsCommit(); 1066 EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode()); 1067 client.AdvanceFrame(); 1068 EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode()); 1069 client.task_runner().RunPendingTasks(); // Run posted deadline. 1070 EXPECT_EQ(scheduler->MainThreadIsInHighLatencyMode(), 1071 should_send_begin_main_frame); 1072 EXPECT_EQ(client.HasAction("ScheduledActionSendBeginMainFrame"), 1073 should_send_begin_main_frame); 1074 } 1075 1076 TEST(SchedulerTest, 1077 SkipMainFrameIfHighLatencyAndCanCommitAndActivateBeforeDeadline) { 1078 // Set up client so that estimates indicate that we can commit and activate 1079 // before the deadline (~8ms by default). 1080 MainFrameInHighLatencyMode(1, 1, false, false); 1081 } 1082 1083 TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanCommitTooLong) { 1084 // Set up client so that estimates indicate that the commit cannot finish 1085 // before the deadline (~8ms by default). 1086 MainFrameInHighLatencyMode(10, 1, false, true); 1087 } 1088 1089 TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanActivateTooLong) { 1090 // Set up client so that estimates indicate that the activate cannot finish 1091 // before the deadline (~8ms by default). 1092 MainFrameInHighLatencyMode(1, 10, false, true); 1093 } 1094 1095 TEST(SchedulerTest, NotSkipMainFrameInPreferImplLatencyMode) { 1096 // Set up client so that estimates indicate that we can commit and activate 1097 // before the deadline (~8ms by default), but also enable impl latency takes 1098 // priority mode. 1099 MainFrameInHighLatencyMode(1, 1, true, true); 1100 } 1101 1102 TEST(SchedulerTest, PollForCommitCompletion) { 1103 // Since we are simulating a long commit, set up a client with draw duration 1104 // estimates that prevent skipping main frames to get to low latency mode. 1105 SchedulerClientWithFixedEstimates client( 1106 base::TimeDelta::FromMilliseconds(1), 1107 base::TimeDelta::FromMilliseconds(32), 1108 base::TimeDelta::FromMilliseconds(32)); 1109 client.set_log_anticipated_draw_time_change(true); 1110 SchedulerSettings default_scheduler_settings; 1111 TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings); 1112 1113 scheduler->SetCanDraw(true); 1114 scheduler->SetCanStart(); 1115 scheduler->SetVisible(true); 1116 scheduler->DidCreateAndInitializeOutputSurface(); 1117 1118 scheduler->SetNeedsCommit(); 1119 EXPECT_TRUE(scheduler->CommitPending()); 1120 scheduler->NotifyBeginMainFrameStarted(); 1121 scheduler->NotifyReadyToCommit(); 1122 scheduler->SetNeedsRedraw(); 1123 1124 BeginFrameArgs frame_args = CreateBeginFrameArgsForTesting(client.now_src()); 1125 frame_args.interval = base::TimeDelta::FromMilliseconds(1000); 1126 scheduler->BeginFrame(frame_args); 1127 1128 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1129 client.task_runner().RunPendingTasks(); // Run posted deadline. 1130 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 1131 1132 scheduler->DidSwapBuffers(); 1133 scheduler->DidSwapBuffersComplete(); 1134 1135 // At this point, we've drawn a frame. Start another commit, but hold off on 1136 // the NotifyReadyToCommit for now. 1137 EXPECT_FALSE(scheduler->CommitPending()); 1138 scheduler->SetNeedsCommit(); 1139 scheduler->BeginFrame(frame_args); 1140 EXPECT_TRUE(scheduler->CommitPending()); 1141 1142 // Draw and swap the frame, but don't ack the swap to simulate the Browser 1143 // blocking on the renderer. 1144 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1145 client.task_runner().RunPendingTasks(); // Run posted deadline. 1146 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 1147 scheduler->DidSwapBuffers(); 1148 1149 // Spin the event loop a few times and make sure we get more 1150 // DidAnticipateDrawTimeChange calls every time. 1151 int actions_so_far = client.num_actions_(); 1152 1153 // Does three iterations to make sure that the timer is properly repeating. 1154 for (int i = 0; i < 3; ++i) { 1155 EXPECT_EQ((frame_args.interval * 2).InMicroseconds(), 1156 client.task_runner().DelayToNextTaskTime().InMicroseconds()) 1157 << scheduler->AsValue()->ToString(); 1158 client.task_runner().RunPendingTasks(); 1159 EXPECT_GT(client.num_actions_(), actions_so_far); 1160 EXPECT_STREQ(client.Action(client.num_actions_() - 1), 1161 "DidAnticipatedDrawTimeChange"); 1162 actions_so_far = client.num_actions_(); 1163 } 1164 1165 // Do the same thing after BeginMainFrame starts but still before activation. 1166 scheduler->NotifyBeginMainFrameStarted(); 1167 for (int i = 0; i < 3; ++i) { 1168 EXPECT_EQ((frame_args.interval * 2).InMicroseconds(), 1169 client.task_runner().DelayToNextTaskTime().InMicroseconds()) 1170 << scheduler->AsValue()->ToString(); 1171 client.task_runner().RunPendingTasks(); 1172 EXPECT_GT(client.num_actions_(), actions_so_far); 1173 EXPECT_STREQ(client.Action(client.num_actions_() - 1), 1174 "DidAnticipatedDrawTimeChange"); 1175 actions_so_far = client.num_actions_(); 1176 } 1177 } 1178 1179 TEST(SchedulerTest, BeginRetroFrame) { 1180 FakeSchedulerClient client; 1181 SchedulerSettings scheduler_settings; 1182 TestScheduler* scheduler = client.CreateScheduler(scheduler_settings); 1183 scheduler->SetCanStart(); 1184 scheduler->SetVisible(true); 1185 scheduler->SetCanDraw(true); 1186 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 1187 1188 // SetNeedsCommit should begin the frame on the next BeginImplFrame. 1189 client.Reset(); 1190 scheduler->SetNeedsCommit(); 1191 EXPECT_TRUE(client.needs_begin_frame()); 1192 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); 1193 client.Reset(); 1194 1195 // Create a BeginFrame with a long deadline to avoid race conditions. 1196 // This is the first BeginFrame, which will be handled immediately. 1197 BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src()); 1198 args.deadline += base::TimeDelta::FromHours(1); 1199 scheduler->BeginFrame(args); 1200 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 1201 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); 1202 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1203 EXPECT_TRUE(client.needs_begin_frame()); 1204 client.Reset(); 1205 1206 // Queue BeginFrames while we are still handling the previous BeginFrame. 1207 args.frame_time += base::TimeDelta::FromSeconds(1); 1208 scheduler->BeginFrame(args); 1209 args.frame_time += base::TimeDelta::FromSeconds(1); 1210 scheduler->BeginFrame(args); 1211 1212 // If we don't swap on the deadline, we wait for the next BeginImplFrame. 1213 client.task_runner().RunPendingTasks(); // Run posted deadline. 1214 EXPECT_NO_ACTION(client); 1215 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 1216 EXPECT_TRUE(client.needs_begin_frame()); 1217 client.Reset(); 1218 1219 // NotifyReadyToCommit should trigger the commit. 1220 scheduler->NotifyBeginMainFrameStarted(); 1221 scheduler->NotifyReadyToCommit(); 1222 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); 1223 EXPECT_TRUE(client.needs_begin_frame()); 1224 client.Reset(); 1225 1226 // BeginImplFrame should prepare the draw. 1227 client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame. 1228 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 1229 EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); 1230 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1231 EXPECT_TRUE(client.needs_begin_frame()); 1232 client.Reset(); 1233 1234 // BeginImplFrame deadline should draw. 1235 client.task_runner().RunPendingTasks(); // Run posted deadline. 1236 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1); 1237 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 1238 EXPECT_TRUE(client.needs_begin_frame()); 1239 client.Reset(); 1240 1241 // The following BeginImplFrame deadline should SetNeedsBeginFrame(false) 1242 // to avoid excessive toggles. 1243 client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame. 1244 EXPECT_SINGLE_ACTION("WillBeginImplFrame", client); 1245 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1246 client.Reset(); 1247 1248 client.task_runner().RunPendingTasks(); // Run posted deadline. 1249 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); 1250 EXPECT_FALSE(client.needs_begin_frame()); 1251 client.Reset(); 1252 } 1253 1254 TEST(SchedulerTest, BeginRetroFrame_SwapThrottled) { 1255 FakeSchedulerClient client; 1256 SchedulerSettings scheduler_settings; 1257 TestScheduler* scheduler = client.CreateScheduler(scheduler_settings); 1258 scheduler->SetCanStart(); 1259 scheduler->SetVisible(true); 1260 scheduler->SetCanDraw(true); 1261 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 1262 1263 // To test swap ack throttling, this test disables automatic swap acks. 1264 scheduler->SetMaxSwapsPending(1); 1265 client.SetAutomaticSwapAck(false); 1266 1267 // SetNeedsCommit should begin the frame on the next BeginImplFrame. 1268 client.Reset(); 1269 scheduler->SetNeedsCommit(); 1270 EXPECT_TRUE(client.needs_begin_frame()); 1271 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); 1272 client.Reset(); 1273 1274 // Create a BeginFrame with a long deadline to avoid race conditions. 1275 // This is the first BeginFrame, which will be handled immediately. 1276 BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src()); 1277 args.deadline += base::TimeDelta::FromHours(1); 1278 scheduler->BeginFrame(args); 1279 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 1280 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); 1281 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1282 EXPECT_TRUE(client.needs_begin_frame()); 1283 client.Reset(); 1284 1285 // Queue BeginFrame while we are still handling the previous BeginFrame. 1286 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1287 args.frame_time += base::TimeDelta::FromSeconds(1); 1288 scheduler->BeginFrame(args); 1289 EXPECT_NO_ACTION(client); 1290 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1291 client.Reset(); 1292 1293 // NotifyReadyToCommit should trigger the pending commit and draw. 1294 scheduler->NotifyBeginMainFrameStarted(); 1295 scheduler->NotifyReadyToCommit(); 1296 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); 1297 EXPECT_TRUE(client.needs_begin_frame()); 1298 client.Reset(); 1299 1300 // Swapping will put us into a swap throttled state. 1301 client.task_runner().RunPendingTasks(); // Run posted deadline. 1302 EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2); 1303 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2); 1304 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 1305 EXPECT_TRUE(client.needs_begin_frame()); 1306 client.Reset(); 1307 1308 // While swap throttled, BeginRetroFrames should trigger BeginImplFrames 1309 // but not a BeginMainFrame or draw. 1310 scheduler->SetNeedsCommit(); 1311 client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame. 1312 EXPECT_ACTION("WillBeginImplFrame", client, 0, 1); 1313 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1314 EXPECT_TRUE(client.needs_begin_frame()); 1315 client.Reset(); 1316 1317 // Queue BeginFrame while we are still handling the previous BeginFrame. 1318 args.frame_time += base::TimeDelta::FromSeconds(1); 1319 scheduler->BeginFrame(args); 1320 EXPECT_NO_ACTION(client); 1321 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1322 EXPECT_TRUE(client.needs_begin_frame()); 1323 client.Reset(); 1324 1325 // Take us out of a swap throttled state. 1326 scheduler->DidSwapBuffersComplete(); 1327 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1); 1328 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1329 EXPECT_TRUE(client.needs_begin_frame()); 1330 client.Reset(); 1331 1332 // BeginImplFrame deadline should draw. 1333 scheduler->SetNeedsRedraw(); 1334 1335 EXPECT_TRUE(client.task_runner().RunTasksWhile( 1336 client.ImplFrameDeadlinePending(true))); 1337 1338 EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2); 1339 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2); 1340 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 1341 EXPECT_TRUE(client.needs_begin_frame()); 1342 client.Reset(); 1343 } 1344 1345 void BeginFramesNotFromClient(bool begin_frame_scheduling_enabled, 1346 bool throttle_frame_production) { 1347 FakeSchedulerClient client; 1348 SchedulerSettings scheduler_settings; 1349 scheduler_settings.begin_frame_scheduling_enabled = 1350 begin_frame_scheduling_enabled; 1351 scheduler_settings.throttle_frame_production = throttle_frame_production; 1352 TestScheduler* scheduler = client.CreateScheduler(scheduler_settings); 1353 scheduler->SetCanStart(); 1354 scheduler->SetVisible(true); 1355 scheduler->SetCanDraw(true); 1356 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 1357 1358 // SetNeedsCommit should begin the frame on the next BeginImplFrame 1359 // without calling SetNeedsBeginFrame. 1360 client.Reset(); 1361 scheduler->SetNeedsCommit(); 1362 EXPECT_FALSE(client.needs_begin_frame()); 1363 EXPECT_NO_ACTION(client); 1364 client.Reset(); 1365 1366 // When the client-driven BeginFrame are disabled, the scheduler posts it's 1367 // own BeginFrame tasks. 1368 client.task_runner().RunPendingTasks(); // Run posted BeginFrame. 1369 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 1370 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); 1371 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1372 EXPECT_FALSE(client.needs_begin_frame()); 1373 client.Reset(); 1374 1375 // If we don't swap on the deadline, we wait for the next BeginFrame. 1376 client.task_runner().RunPendingTasks(); // Run posted deadline. 1377 EXPECT_NO_ACTION(client); 1378 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 1379 EXPECT_FALSE(client.needs_begin_frame()); 1380 client.Reset(); 1381 1382 // NotifyReadyToCommit should trigger the commit. 1383 scheduler->NotifyBeginMainFrameStarted(); 1384 scheduler->NotifyReadyToCommit(); 1385 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); 1386 EXPECT_FALSE(client.needs_begin_frame()); 1387 client.Reset(); 1388 1389 // BeginImplFrame should prepare the draw. 1390 client.task_runner().RunPendingTasks(); // Run posted BeginFrame. 1391 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 1392 EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); 1393 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1394 EXPECT_FALSE(client.needs_begin_frame()); 1395 client.Reset(); 1396 1397 // BeginImplFrame deadline should draw. 1398 client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true)); 1399 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1); 1400 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 1401 EXPECT_FALSE(client.needs_begin_frame()); 1402 client.Reset(); 1403 1404 // The following BeginImplFrame deadline should SetNeedsBeginFrame(false) 1405 // to avoid excessive toggles. 1406 client.task_runner().RunPendingTasks(); // Run posted BeginFrame. 1407 EXPECT_SINGLE_ACTION("WillBeginImplFrame", client); 1408 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1409 client.Reset(); 1410 1411 // Make sure SetNeedsBeginFrame isn't called on the client 1412 // when the BeginFrame is no longer needed. 1413 client.task_runner().RunPendingTasks(); // Run posted deadline. 1414 EXPECT_NO_ACTION(client); 1415 EXPECT_FALSE(client.needs_begin_frame()); 1416 client.Reset(); 1417 } 1418 1419 TEST(SchedulerTest, SyntheticBeginFrames) { 1420 bool begin_frame_scheduling_enabled = false; 1421 bool throttle_frame_production = true; 1422 BeginFramesNotFromClient(begin_frame_scheduling_enabled, 1423 throttle_frame_production); 1424 } 1425 1426 TEST(SchedulerTest, VSyncThrottlingDisabled) { 1427 bool begin_frame_scheduling_enabled = true; 1428 bool throttle_frame_production = false; 1429 BeginFramesNotFromClient(begin_frame_scheduling_enabled, 1430 throttle_frame_production); 1431 } 1432 1433 TEST(SchedulerTest, SyntheticBeginFrames_And_VSyncThrottlingDisabled) { 1434 bool begin_frame_scheduling_enabled = false; 1435 bool throttle_frame_production = false; 1436 BeginFramesNotFromClient(begin_frame_scheduling_enabled, 1437 throttle_frame_production); 1438 } 1439 1440 void BeginFramesNotFromClient_SwapThrottled(bool begin_frame_scheduling_enabled, 1441 bool throttle_frame_production) { 1442 FakeSchedulerClient client; 1443 SchedulerSettings scheduler_settings; 1444 scheduler_settings.begin_frame_scheduling_enabled = 1445 begin_frame_scheduling_enabled; 1446 scheduler_settings.throttle_frame_production = throttle_frame_production; 1447 TestScheduler* scheduler = client.CreateScheduler(scheduler_settings); 1448 scheduler->SetCanStart(); 1449 scheduler->SetVisible(true); 1450 scheduler->SetCanDraw(true); 1451 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 1452 1453 // To test swap ack throttling, this test disables automatic swap acks. 1454 scheduler->SetMaxSwapsPending(1); 1455 client.SetAutomaticSwapAck(false); 1456 1457 // SetNeedsCommit should begin the frame on the next BeginImplFrame. 1458 client.Reset(); 1459 scheduler->SetNeedsCommit(); 1460 EXPECT_FALSE(client.needs_begin_frame()); 1461 EXPECT_NO_ACTION(client); 1462 client.Reset(); 1463 1464 // Trigger the first BeginImplFrame and BeginMainFrame 1465 client.task_runner().RunPendingTasks(); // Run posted BeginFrame. 1466 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 1467 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); 1468 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1469 EXPECT_FALSE(client.needs_begin_frame()); 1470 client.Reset(); 1471 1472 // NotifyReadyToCommit should trigger the pending commit and draw. 1473 scheduler->NotifyBeginMainFrameStarted(); 1474 scheduler->NotifyReadyToCommit(); 1475 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); 1476 EXPECT_FALSE(client.needs_begin_frame()); 1477 client.Reset(); 1478 1479 // Swapping will put us into a swap throttled state. 1480 client.task_runner().RunPendingTasks(); // Run posted deadline. 1481 EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2); 1482 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2); 1483 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 1484 EXPECT_FALSE(client.needs_begin_frame()); 1485 client.Reset(); 1486 1487 // While swap throttled, BeginFrames should trigger BeginImplFrames, 1488 // but not a BeginMainFrame or draw. 1489 scheduler->SetNeedsCommit(); 1490 client.task_runner().RunPendingTasks(); // Run posted BeginFrame. 1491 EXPECT_ACTION("WillBeginImplFrame", client, 0, 1); 1492 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1493 EXPECT_FALSE(client.needs_begin_frame()); 1494 client.Reset(); 1495 1496 // Take us out of a swap throttled state. 1497 scheduler->DidSwapBuffersComplete(); 1498 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1); 1499 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1500 EXPECT_FALSE(client.needs_begin_frame()); 1501 client.Reset(); 1502 1503 // BeginImplFrame deadline should draw. 1504 scheduler->SetNeedsRedraw(); 1505 client.task_runner().RunPendingTasks(); // Run posted deadline. 1506 EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2); 1507 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2); 1508 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 1509 EXPECT_FALSE(client.needs_begin_frame()); 1510 client.Reset(); 1511 } 1512 1513 TEST(SchedulerTest, SyntheticBeginFrames_SwapThrottled) { 1514 bool begin_frame_scheduling_enabled = false; 1515 bool throttle_frame_production = true; 1516 BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled, 1517 throttle_frame_production); 1518 } 1519 1520 TEST(SchedulerTest, VSyncThrottlingDisabled_SwapThrottled) { 1521 bool begin_frame_scheduling_enabled = true; 1522 bool throttle_frame_production = false; 1523 BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled, 1524 throttle_frame_production); 1525 } 1526 1527 TEST(SchedulerTest, 1528 SyntheticBeginFrames_And_VSyncThrottlingDisabled_SwapThrottled) { 1529 bool begin_frame_scheduling_enabled = false; 1530 bool throttle_frame_production = false; 1531 BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled, 1532 throttle_frame_production); 1533 } 1534 1535 TEST(SchedulerTest, DidLoseOutputSurfaceAfterOutputSurfaceIsInitialized) { 1536 FakeSchedulerClient client; 1537 SchedulerSettings scheduler_settings; 1538 TestScheduler* scheduler = client.CreateScheduler(scheduler_settings); 1539 scheduler->SetCanStart(); 1540 scheduler->SetVisible(true); 1541 scheduler->SetCanDraw(true); 1542 1543 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 1544 client.Reset(); 1545 scheduler->DidCreateAndInitializeOutputSurface(); 1546 EXPECT_NO_ACTION(client); 1547 1548 scheduler->DidLoseOutputSurface(); 1549 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 1550 } 1551 1552 TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStarted) { 1553 FakeSchedulerClient client; 1554 SchedulerSettings scheduler_settings; 1555 TestScheduler* scheduler = client.CreateScheduler(scheduler_settings); 1556 scheduler->SetCanStart(); 1557 scheduler->SetVisible(true); 1558 scheduler->SetCanDraw(true); 1559 1560 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 1561 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 1562 // SetNeedsCommit should begin the frame. 1563 client.Reset(); 1564 scheduler->SetNeedsCommit(); 1565 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); 1566 1567 client.Reset(); 1568 client.AdvanceFrame(); 1569 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 1570 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); 1571 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1572 1573 client.Reset(); 1574 scheduler->DidLoseOutputSurface(); 1575 // Do nothing when impl frame is in deadine pending state. 1576 EXPECT_NO_ACTION(client); 1577 1578 client.Reset(); 1579 scheduler->NotifyBeginMainFrameStarted(); 1580 scheduler->NotifyReadyToCommit(); 1581 EXPECT_ACTION("ScheduledActionCommit", client, 0, 1); 1582 1583 client.Reset(); 1584 client.task_runner().RunPendingTasks(); // Run posted deadline. 1585 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 1586 } 1587 1588 void DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency( 1589 bool impl_side_painting) { 1590 FakeSchedulerClient client; 1591 SchedulerSettings scheduler_settings; 1592 scheduler_settings.impl_side_painting = impl_side_painting; 1593 TestScheduler* scheduler = client.CreateScheduler(scheduler_settings); 1594 scheduler->SetCanStart(); 1595 scheduler->SetVisible(true); 1596 scheduler->SetCanDraw(true); 1597 1598 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 1599 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 1600 1601 // SetNeedsCommit should begin the frame. 1602 client.Reset(); 1603 scheduler->SetNeedsCommit(); 1604 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); 1605 1606 client.Reset(); 1607 client.AdvanceFrame(); 1608 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 1609 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); 1610 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1611 1612 client.Reset(); 1613 scheduler->DidLoseOutputSurface(); 1614 // Do nothing when impl frame is in deadine pending state. 1615 EXPECT_NO_ACTION(client); 1616 1617 client.Reset(); 1618 // Run posted deadline. 1619 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1620 client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true)); 1621 // OnBeginImplFrameDeadline didn't schedule any actions because main frame is 1622 // not yet completed. 1623 EXPECT_NO_ACTION(client); 1624 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 1625 1626 // BeginImplFrame is not started. 1627 client.task_runner().RunUntilTime(client.now_src()->Now() + 1628 base::TimeDelta::FromMilliseconds(10)); 1629 EXPECT_NO_ACTION(client); 1630 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 1631 1632 client.Reset(); 1633 scheduler->NotifyBeginMainFrameStarted(); 1634 scheduler->NotifyReadyToCommit(); 1635 if (impl_side_painting) { 1636 EXPECT_ACTION("ScheduledActionCommit", client, 0, 3); 1637 EXPECT_ACTION("ScheduledActionActivateSyncTree", client, 1, 3); 1638 EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 2, 3); 1639 } else { 1640 EXPECT_ACTION("ScheduledActionCommit", client, 0, 2); 1641 EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 1, 2); 1642 } 1643 } 1644 1645 TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency) { 1646 bool impl_side_painting = false; 1647 DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(impl_side_painting); 1648 } 1649 1650 TEST(SchedulerTest, 1651 DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatencyWithImplPaint) { 1652 bool impl_side_painting = true; 1653 DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(impl_side_painting); 1654 } 1655 1656 void DidLoseOutputSurfaceAfterReadyToCommit(bool impl_side_painting) { 1657 FakeSchedulerClient client; 1658 SchedulerSettings scheduler_settings; 1659 scheduler_settings.impl_side_painting = impl_side_painting; 1660 TestScheduler* scheduler = client.CreateScheduler(scheduler_settings); 1661 scheduler->SetCanStart(); 1662 scheduler->SetVisible(true); 1663 scheduler->SetCanDraw(true); 1664 1665 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 1666 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 1667 1668 // SetNeedsCommit should begin the frame. 1669 client.Reset(); 1670 scheduler->SetNeedsCommit(); 1671 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); 1672 1673 client.Reset(); 1674 client.AdvanceFrame(); 1675 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 1676 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); 1677 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1678 1679 client.Reset(); 1680 scheduler->NotifyBeginMainFrameStarted(); 1681 scheduler->NotifyReadyToCommit(); 1682 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); 1683 1684 client.Reset(); 1685 scheduler->DidLoseOutputSurface(); 1686 if (impl_side_painting) { 1687 // Sync tree should be forced to activate. 1688 EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client); 1689 } else { 1690 // Do nothing when impl frame is in deadine pending state. 1691 EXPECT_NO_ACTION(client); 1692 } 1693 1694 client.Reset(); 1695 client.task_runner().RunPendingTasks(); // Run posted deadline. 1696 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 1697 } 1698 1699 TEST(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommit) { 1700 DidLoseOutputSurfaceAfterReadyToCommit(false); 1701 } 1702 1703 TEST(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommitWithImplPainting) { 1704 DidLoseOutputSurfaceAfterReadyToCommit(true); 1705 } 1706 1707 TEST(SchedulerTest, DidLoseOutputSurfaceAfterSetNeedsManageTiles) { 1708 FakeSchedulerClient client; 1709 SchedulerSettings scheduler_settings; 1710 TestScheduler* scheduler = client.CreateScheduler(scheduler_settings); 1711 scheduler->SetCanStart(); 1712 scheduler->SetVisible(true); 1713 scheduler->SetCanDraw(true); 1714 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 1715 1716 client.Reset(); 1717 scheduler->SetNeedsManageTiles(); 1718 scheduler->SetNeedsRedraw(); 1719 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); 1720 EXPECT_TRUE(client.needs_begin_frame()); 1721 1722 client.Reset(); 1723 client.AdvanceFrame(); 1724 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 1725 EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); 1726 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1727 1728 client.Reset(); 1729 scheduler->DidLoseOutputSurface(); 1730 EXPECT_NO_ACTION(client); 1731 1732 client.Reset(); 1733 client.task_runner().RunPendingTasks(); // Run posted deadline. 1734 EXPECT_ACTION("ScheduledActionManageTiles", client, 0, 2); 1735 EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 1, 2); 1736 } 1737 1738 TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginRetroFramePosted) { 1739 FakeSchedulerClient client; 1740 SchedulerSettings scheduler_settings; 1741 TestScheduler* scheduler = client.CreateScheduler(scheduler_settings); 1742 scheduler->SetCanStart(); 1743 scheduler->SetVisible(true); 1744 scheduler->SetCanDraw(true); 1745 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 1746 1747 // SetNeedsCommit should begin the frame on the next BeginImplFrame. 1748 client.Reset(); 1749 scheduler->SetNeedsCommit(); 1750 EXPECT_TRUE(client.needs_begin_frame()); 1751 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); 1752 1753 // Create a BeginFrame with a long deadline to avoid race conditions. 1754 // This is the first BeginFrame, which will be handled immediately. 1755 client.Reset(); 1756 BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src()); 1757 args.deadline += base::TimeDelta::FromHours(1); 1758 scheduler->BeginFrame(args); 1759 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 1760 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); 1761 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1762 EXPECT_TRUE(client.needs_begin_frame()); 1763 1764 // Queue BeginFrames while we are still handling the previous BeginFrame. 1765 args.frame_time += base::TimeDelta::FromSeconds(1); 1766 scheduler->BeginFrame(args); 1767 args.frame_time += base::TimeDelta::FromSeconds(1); 1768 scheduler->BeginFrame(args); 1769 1770 // If we don't swap on the deadline, we wait for the next BeginImplFrame. 1771 client.Reset(); 1772 client.task_runner().RunPendingTasks(); // Run posted deadline. 1773 EXPECT_NO_ACTION(client); 1774 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 1775 EXPECT_TRUE(client.needs_begin_frame()); 1776 1777 // NotifyReadyToCommit should trigger the commit. 1778 client.Reset(); 1779 scheduler->NotifyBeginMainFrameStarted(); 1780 scheduler->NotifyReadyToCommit(); 1781 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); 1782 EXPECT_TRUE(client.needs_begin_frame()); 1783 1784 client.Reset(); 1785 EXPECT_FALSE(scheduler->IsBeginRetroFrameArgsEmpty()); 1786 scheduler->DidLoseOutputSurface(); 1787 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 1788 EXPECT_TRUE(client.needs_begin_frame()); 1789 EXPECT_TRUE(scheduler->IsBeginRetroFrameArgsEmpty()); 1790 1791 // Posted BeginRetroFrame is aborted. 1792 client.Reset(); 1793 client.task_runner().RunPendingTasks(); 1794 EXPECT_NO_ACTION(client); 1795 } 1796 1797 TEST(SchedulerTest, DidLoseOutputSurfaceDuringBeginRetroFrameRunning) { 1798 FakeSchedulerClient client; 1799 SchedulerSettings scheduler_settings; 1800 TestScheduler* scheduler = client.CreateScheduler(scheduler_settings); 1801 scheduler->SetCanStart(); 1802 scheduler->SetVisible(true); 1803 scheduler->SetCanDraw(true); 1804 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 1805 1806 // SetNeedsCommit should begin the frame on the next BeginImplFrame. 1807 client.Reset(); 1808 scheduler->SetNeedsCommit(); 1809 EXPECT_TRUE(client.needs_begin_frame()); 1810 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); 1811 1812 // Create a BeginFrame with a long deadline to avoid race conditions. 1813 // This is the first BeginFrame, which will be handled immediately. 1814 client.Reset(); 1815 BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src()); 1816 args.deadline += base::TimeDelta::FromHours(1); 1817 scheduler->BeginFrame(args); 1818 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 1819 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); 1820 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1821 EXPECT_TRUE(client.needs_begin_frame()); 1822 1823 // Queue BeginFrames while we are still handling the previous BeginFrame. 1824 args.frame_time += base::TimeDelta::FromSeconds(1); 1825 scheduler->BeginFrame(args); 1826 args.frame_time += base::TimeDelta::FromSeconds(1); 1827 scheduler->BeginFrame(args); 1828 1829 // If we don't swap on the deadline, we wait for the next BeginImplFrame. 1830 client.Reset(); 1831 client.task_runner().RunPendingTasks(); // Run posted deadline. 1832 EXPECT_NO_ACTION(client); 1833 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 1834 EXPECT_TRUE(client.needs_begin_frame()); 1835 1836 // NotifyReadyToCommit should trigger the commit. 1837 client.Reset(); 1838 scheduler->NotifyBeginMainFrameStarted(); 1839 scheduler->NotifyReadyToCommit(); 1840 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); 1841 EXPECT_TRUE(client.needs_begin_frame()); 1842 1843 // BeginImplFrame should prepare the draw. 1844 client.Reset(); 1845 client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame. 1846 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 1847 EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); 1848 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1849 EXPECT_TRUE(client.needs_begin_frame()); 1850 1851 client.Reset(); 1852 EXPECT_FALSE(scheduler->IsBeginRetroFrameArgsEmpty()); 1853 scheduler->DidLoseOutputSurface(); 1854 EXPECT_NO_ACTION(client); 1855 EXPECT_TRUE(scheduler->IsBeginRetroFrameArgsEmpty()); 1856 1857 // BeginImplFrame deadline should abort drawing. 1858 client.Reset(); 1859 client.task_runner().RunPendingTasks(); // Run posted deadline. 1860 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 1861 EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); 1862 EXPECT_TRUE(client.needs_begin_frame()); 1863 1864 // No more BeginRetroFrame because BeginRetroFrame queue is cleared. 1865 client.Reset(); 1866 client.task_runner().RunPendingTasks(); 1867 EXPECT_NO_ACTION(client); 1868 } 1869 1870 TEST(SchedulerTest, 1871 StopBeginFrameAfterDidLoseOutputSurfaceWithSyntheticBeginFrameSource) { 1872 FakeSchedulerClient client; 1873 SchedulerSettings scheduler_settings; 1874 scheduler_settings.begin_frame_scheduling_enabled = false; 1875 TestScheduler* scheduler = client.CreateScheduler(scheduler_settings); 1876 scheduler->SetCanStart(); 1877 scheduler->SetVisible(true); 1878 scheduler->SetCanDraw(true); 1879 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 1880 1881 // SetNeedsCommit should begin the frame on the next BeginImplFrame. 1882 client.Reset(); 1883 EXPECT_FALSE(scheduler->IsSyntheticBeginFrameSourceActive()); 1884 scheduler->SetNeedsCommit(); 1885 EXPECT_TRUE(scheduler->IsSyntheticBeginFrameSourceActive()); 1886 1887 client.Reset(); 1888 client.task_runner().RunPendingTasks(); // Run posted Tick. 1889 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 1890 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); 1891 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1892 EXPECT_TRUE(scheduler->IsSyntheticBeginFrameSourceActive()); 1893 1894 // NotifyReadyToCommit should trigger the commit. 1895 client.Reset(); 1896 scheduler->NotifyBeginMainFrameStarted(); 1897 scheduler->NotifyReadyToCommit(); 1898 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); 1899 EXPECT_TRUE(scheduler->IsSyntheticBeginFrameSourceActive()); 1900 1901 client.Reset(); 1902 scheduler->DidLoseOutputSurface(); 1903 EXPECT_EQ(0, client.num_actions_()); 1904 EXPECT_FALSE(scheduler->IsSyntheticBeginFrameSourceActive()); 1905 1906 client.Reset(); 1907 client.task_runner().RunPendingTasks(); // Run posted deadline. 1908 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 1909 EXPECT_FALSE(scheduler->IsSyntheticBeginFrameSourceActive()); 1910 } 1911 1912 TEST(SchedulerTest, ScheduledActionActivateAfterBecomingInvisible) { 1913 FakeSchedulerClient client; 1914 SchedulerSettings scheduler_settings; 1915 scheduler_settings.impl_side_painting = true; 1916 TestScheduler* scheduler = client.CreateScheduler(scheduler_settings); 1917 scheduler->SetCanStart(); 1918 scheduler->SetVisible(true); 1919 scheduler->SetCanDraw(true); 1920 1921 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); 1922 InitializeOutputSurfaceAndFirstCommit(scheduler, &client); 1923 1924 // SetNeedsCommit should begin the frame. 1925 client.Reset(); 1926 scheduler->SetNeedsCommit(); 1927 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); 1928 1929 client.Reset(); 1930 client.AdvanceFrame(); 1931 EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); 1932 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); 1933 EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); 1934 1935 client.Reset(); 1936 scheduler->NotifyBeginMainFrameStarted(); 1937 scheduler->NotifyReadyToCommit(); 1938 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); 1939 1940 client.Reset(); 1941 scheduler->SetVisible(false); 1942 // Sync tree should be forced to activate. 1943 EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client); 1944 } 1945 1946 } // namespace 1947 } // namespace cc 1948