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"
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"
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_()); \
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); \
28 #define EXPECT_SINGLE_ACTION(action, client) \
29 EXPECT_ACTION(action, client, 0, 1)
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();
47 class FakeSchedulerClient : public SchedulerClient {
50 : needs_begin_impl_frame_(false) {
57 draw_will_happen_ = true;
58 swap_will_happen_if_draw_happens_ = true;
60 log_anticipated_draw_time_change_ = false;
63 Scheduler* CreateScheduler(const SchedulerSettings& settings) {
64 scheduler_ = Scheduler::Create(this, settings, 0);
65 return scheduler_.get();
68 // Most tests don't care about DidAnticipatedDrawTimeChange, so only record it
70 void set_log_anticipated_draw_time_change(bool log) {
71 log_anticipated_draw_time_change_ = log;
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]; }
79 int ActionIndex(const char* action) const {
80 for (size_t i = 0; i < actions_.size(); i++)
81 if (!strcmp(actions_[i], action))
86 bool HasAction(const char* action) const {
87 return ActionIndex(action) >= 0;
90 void SetDrawWillHappen(bool draw_will_happen) {
91 draw_will_happen_ = draw_will_happen;
93 void SetSwapWillHappenIfDrawHappens(bool swap_will_happen_if_draw_happens) {
94 swap_will_happen_if_draw_happens_ = swap_will_happen_if_draw_happens;
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;
103 virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {
104 actions_.push_back("ScheduledActionSendBeginMainFrame");
105 states_.push_back(scheduler_->StateAsValue().release());
107 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
109 actions_.push_back("ScheduledActionDrawAndSwapIfPossible");
110 states_.push_back(scheduler_->StateAsValue().release());
112 bool did_readback = false;
113 DrawSwapReadbackResult::DrawResult result =
115 ? DrawSwapReadbackResult::DRAW_SUCCESS
116 : DrawSwapReadbackResult::DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
117 return DrawSwapReadbackResult(
119 draw_will_happen_ && swap_will_happen_if_draw_happens_,
122 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
123 actions_.push_back("ScheduledActionDrawAndSwapForced");
124 states_.push_back(scheduler_->StateAsValue().release());
125 bool did_swap = swap_will_happen_if_draw_happens_;
126 bool did_readback = false;
127 return DrawSwapReadbackResult(
128 DrawSwapReadbackResult::DRAW_SUCCESS, did_swap, did_readback);
130 virtual DrawSwapReadbackResult ScheduledActionDrawAndReadback() OVERRIDE {
131 actions_.push_back("ScheduledActionDrawAndReadback");
132 states_.push_back(scheduler_->StateAsValue().release());
133 bool did_swap = false;
134 bool did_readback = true;
135 return DrawSwapReadbackResult(
136 DrawSwapReadbackResult::DRAW_SUCCESS, did_swap, did_readback);
138 virtual void ScheduledActionCommit() OVERRIDE {
139 actions_.push_back("ScheduledActionCommit");
140 states_.push_back(scheduler_->StateAsValue().release());
142 virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE {
143 actions_.push_back("ScheduledActionUpdateVisibleTiles");
144 states_.push_back(scheduler_->StateAsValue().release());
146 virtual void ScheduledActionActivatePendingTree() OVERRIDE {
147 actions_.push_back("ScheduledActionActivatePendingTree");
148 states_.push_back(scheduler_->StateAsValue().release());
150 virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {
151 actions_.push_back("ScheduledActionBeginOutputSurfaceCreation");
152 states_.push_back(scheduler_->StateAsValue().release());
154 virtual void ScheduledActionAcquireLayerTexturesForMainThread() OVERRIDE {
155 actions_.push_back("ScheduledActionAcquireLayerTexturesForMainThread");
156 states_.push_back(scheduler_->StateAsValue().release());
158 virtual void ScheduledActionManageTiles() OVERRIDE {
159 actions_.push_back("ScheduledActionManageTiles");
160 states_.push_back(scheduler_->StateAsValue().release());
162 virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {
163 if (log_anticipated_draw_time_change_)
164 actions_.push_back("DidAnticipatedDrawTimeChange");
166 virtual base::TimeDelta DrawDurationEstimate() OVERRIDE {
167 return base::TimeDelta();
169 virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE {
170 return base::TimeDelta();
172 virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE {
173 return base::TimeDelta();
176 virtual void PostBeginImplFrameDeadline(const base::Closure& closure,
177 base::TimeTicks deadline) OVERRIDE {
178 actions_.push_back("PostBeginImplFrameDeadlineTask");
179 states_.push_back(scheduler_->StateAsValue().release());
182 virtual void DidBeginImplFrameDeadline() OVERRIDE {}
185 bool needs_begin_impl_frame_;
186 bool draw_will_happen_;
187 bool swap_will_happen_if_draw_happens_;
189 bool log_anticipated_draw_time_change_;
190 std::vector<const char*> actions_;
191 ScopedVector<base::Value> states_;
192 scoped_ptr<Scheduler> scheduler_;
195 TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginImplFrame) {
196 FakeSchedulerClient client;
197 SchedulerSettings default_scheduler_settings;
198 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
199 scheduler->SetCanStart();
200 scheduler->SetVisible(true);
201 scheduler->SetCanDraw(true);
203 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
205 scheduler->DidCreateAndInitializeOutputSurface();
206 EXPECT_EQ(0, client.num_actions_());
209 void RequestCommit(bool deadline_scheduling_enabled) {
210 FakeSchedulerClient client;
211 SchedulerSettings scheduler_settings;
212 scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
213 Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
214 scheduler->SetCanStart();
215 scheduler->SetVisible(true);
216 scheduler->SetCanDraw(true);
218 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
219 InitializeOutputSurfaceAndFirstCommit(scheduler);
221 // SetNeedsCommit should begin the frame on the next BeginImplFrame.
223 scheduler->SetNeedsCommit();
224 EXPECT_TRUE(client.needs_begin_impl_frame());
225 if (deadline_scheduling_enabled) {
226 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
228 EXPECT_EQ(client.num_actions_(), 2);
229 EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
230 EXPECT_TRUE(client.HasAction("SetNeedsBeginImplFrame"));
234 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
235 if (deadline_scheduling_enabled) {
236 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
237 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
239 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
241 EXPECT_TRUE(client.needs_begin_impl_frame());
244 // If we don't swap on the deadline, we need to request another
246 scheduler->OnBeginImplFrameDeadline();
247 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
248 EXPECT_TRUE(client.needs_begin_impl_frame());
251 // FinishCommit should commit
252 scheduler->FinishCommit();
253 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
254 EXPECT_TRUE(client.needs_begin_impl_frame());
257 // BeginImplFrame should prepare the draw.
258 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
259 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
260 EXPECT_TRUE(client.needs_begin_impl_frame());
263 // BeginImplFrame deadline should draw.
264 scheduler->OnBeginImplFrameDeadline();
265 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
266 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
267 EXPECT_TRUE(client.needs_begin_impl_frame());
270 // The following BeginImplFrame deadline should SetNeedsBeginImplFrame(false)
271 // to avoid excessive toggles.
272 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
273 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
276 scheduler->OnBeginImplFrameDeadline();
277 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
278 EXPECT_FALSE(client.needs_begin_impl_frame());
282 TEST(SchedulerTest, RequestCommit) {
283 bool deadline_scheduling_enabled = false;
284 RequestCommit(deadline_scheduling_enabled);
287 TEST(SchedulerTest, RequestCommit_Deadline) {
288 bool deadline_scheduling_enabled = true;
289 RequestCommit(deadline_scheduling_enabled);
292 void RequestCommitAfterBeginMainFrameSent(
293 bool deadline_scheduling_enabled) {
294 FakeSchedulerClient client;
295 SchedulerSettings scheduler_settings;
296 scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
297 Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
298 scheduler->SetCanStart();
299 scheduler->SetVisible(true);
300 scheduler->SetCanDraw(true);
302 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
303 InitializeOutputSurfaceAndFirstCommit(scheduler);
306 // SetNeedsCommit should begin the frame.
307 scheduler->SetNeedsCommit();
308 if (deadline_scheduling_enabled) {
309 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
311 EXPECT_EQ(client.num_actions_(), 2);
312 EXPECT_TRUE(client.HasAction("SetNeedsBeginImplFrame"));
313 EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
317 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
318 if (deadline_scheduling_enabled) {
319 EXPECT_EQ(client.num_actions_(), 2);
320 EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
321 EXPECT_TRUE(client.HasAction("PostBeginImplFrameDeadlineTask"));
323 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
326 EXPECT_TRUE(client.needs_begin_impl_frame());
329 // Now SetNeedsCommit again. Calling here means we need a second commit.
330 scheduler->SetNeedsCommit();
331 EXPECT_EQ(client.num_actions_(), 0);
334 // Finish the first commit.
335 scheduler->FinishCommit();
336 EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
337 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
339 scheduler->OnBeginImplFrameDeadline();
340 if (deadline_scheduling_enabled) {
341 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
342 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
344 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 3);
345 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 3);
346 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 2, 3);
349 // Because we just swapped, the Scheduler should also request the next
350 // BeginImplFrame from the OutputSurface.
351 EXPECT_TRUE(client.needs_begin_impl_frame());
354 // Since another commit is needed, the next BeginImplFrame should initiate
355 // the second commit.
356 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
357 if (deadline_scheduling_enabled) {
358 EXPECT_EQ(client.num_actions_(), 2);
359 EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
360 EXPECT_TRUE(client.HasAction("PostBeginImplFrameDeadlineTask"));
362 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
366 // Finishing the commit before the deadline should post a new deadline task
367 // to trigger the deadline early.
368 scheduler->FinishCommit();
369 EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
370 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
372 scheduler->OnBeginImplFrameDeadline();
373 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
374 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
375 EXPECT_TRUE(client.needs_begin_impl_frame());
378 // On the next BeginImplFrame, verify we go back to a quiescent state and
379 // no longer request BeginImplFrames.
380 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
381 scheduler->OnBeginImplFrameDeadline();
382 EXPECT_FALSE(client.needs_begin_impl_frame());
386 TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
387 bool deadline_scheduling_enabled = false;
388 RequestCommitAfterBeginMainFrameSent(deadline_scheduling_enabled);
391 TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent_Deadline) {
392 bool deadline_scheduling_enabled = true;
393 RequestCommitAfterBeginMainFrameSent(deadline_scheduling_enabled);
396 void TextureAcquisitionCausesCommitInsteadOfDraw(
397 bool deadline_scheduling_enabled) {
398 FakeSchedulerClient client;
399 SchedulerSettings scheduler_settings;
400 scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
401 Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
402 scheduler->SetCanStart();
403 scheduler->SetVisible(true);
404 scheduler->SetCanDraw(true);
405 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
407 InitializeOutputSurfaceAndFirstCommit(scheduler);
409 scheduler->SetNeedsRedraw();
410 EXPECT_TRUE(scheduler->RedrawPending());
411 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
412 EXPECT_TRUE(client.needs_begin_impl_frame());
415 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
416 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
418 scheduler->OnBeginImplFrameDeadline();
419 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
420 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
421 EXPECT_FALSE(scheduler->RedrawPending());
422 EXPECT_TRUE(client.needs_begin_impl_frame());
425 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
426 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
428 scheduler->OnBeginImplFrameDeadline();
429 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
430 EXPECT_FALSE(scheduler->RedrawPending());
431 EXPECT_FALSE(client.needs_begin_impl_frame());
434 scheduler->SetMainThreadNeedsLayerTextures();
435 EXPECT_SINGLE_ACTION("ScheduledActionAcquireLayerTexturesForMainThread",
438 // We should request a BeginImplFrame in anticipation of a draw.
440 scheduler->SetNeedsRedraw();
441 EXPECT_TRUE(scheduler->RedrawPending());
442 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
443 EXPECT_TRUE(client.needs_begin_impl_frame());
445 // No draw happens since the textures are acquired by the main thread.
447 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
448 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
450 scheduler->OnBeginImplFrameDeadline();
451 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
452 EXPECT_TRUE(scheduler->RedrawPending());
453 EXPECT_TRUE(client.needs_begin_impl_frame());
456 scheduler->SetNeedsCommit();
457 if (deadline_scheduling_enabled) {
458 EXPECT_EQ(0, client.num_actions_());
460 EXPECT_SINGLE_ACTION("ScheduledActionSendBeginMainFrame", client);
464 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
465 if (deadline_scheduling_enabled) {
466 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
467 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
469 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
472 // Commit will release the texture.
474 scheduler->FinishCommit();
475 EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
476 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
477 EXPECT_TRUE(scheduler->RedrawPending());
479 // Now we can draw again after the commit happens.
481 scheduler->OnBeginImplFrameDeadline();
482 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
483 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
484 EXPECT_FALSE(scheduler->RedrawPending());
485 EXPECT_TRUE(client.needs_begin_impl_frame());
487 // Make sure we stop requesting BeginImplFrames if we don't swap.
489 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
490 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
492 scheduler->OnBeginImplFrameDeadline();
493 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
494 EXPECT_FALSE(client.needs_begin_impl_frame());
497 TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw) {
498 bool deadline_scheduling_enabled = false;
499 TextureAcquisitionCausesCommitInsteadOfDraw(deadline_scheduling_enabled);
502 TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw_Deadline) {
503 bool deadline_scheduling_enabled = true;
504 TextureAcquisitionCausesCommitInsteadOfDraw(deadline_scheduling_enabled);
507 void TextureAcquisitionCollision(bool deadline_scheduling_enabled) {
508 FakeSchedulerClient client;
509 SchedulerSettings scheduler_settings;
510 scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
511 Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
512 scheduler->SetCanStart();
513 scheduler->SetVisible(true);
514 scheduler->SetCanDraw(true);
516 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
517 InitializeOutputSurfaceAndFirstCommit(scheduler);
520 scheduler->SetNeedsCommit();
521 if (deadline_scheduling_enabled) {
522 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
524 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
525 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
529 scheduler->SetMainThreadNeedsLayerTextures();
530 EXPECT_SINGLE_ACTION(
531 "ScheduledActionAcquireLayerTexturesForMainThread", client);
534 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
535 if (deadline_scheduling_enabled) {
536 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
537 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
539 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
543 scheduler->OnBeginImplFrameDeadline();
544 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
546 // Although the compositor cannot draw because textures are locked by main
547 // thread, we continue requesting SetNeedsBeginImplFrame in anticipation of
549 EXPECT_TRUE(client.needs_begin_impl_frame());
551 // Trigger the commit
552 scheduler->FinishCommit();
553 EXPECT_TRUE(client.needs_begin_impl_frame());
555 // Between commit and draw, texture acquisition for main thread delayed,
556 // and main thread blocks.
558 scheduler->SetMainThreadNeedsLayerTextures();
559 EXPECT_EQ(0, client.num_actions_());
561 // No implicit commit is expected.
563 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
564 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
567 scheduler->OnBeginImplFrameDeadline();
568 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 3);
570 "ScheduledActionAcquireLayerTexturesForMainThread", client, 1, 3);
571 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 2, 3);
572 EXPECT_TRUE(client.needs_begin_impl_frame());
574 // The compositor should not draw because textures are locked by main
577 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
578 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
580 scheduler->OnBeginImplFrameDeadline();
581 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
582 EXPECT_FALSE(client.needs_begin_impl_frame());
584 // The impl thread need an explicit commit from the main thread to lock
587 scheduler->SetNeedsCommit();
588 if (deadline_scheduling_enabled) {
589 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
591 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
592 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
594 EXPECT_TRUE(client.needs_begin_impl_frame());
597 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
598 if (deadline_scheduling_enabled) {
599 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
600 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
602 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
606 // Trigger the commit, which will trigger the deadline task early.
607 scheduler->FinishCommit();
608 EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
609 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
610 EXPECT_TRUE(client.needs_begin_impl_frame());
613 // Verify we draw on the next BeginImplFrame deadline
614 scheduler->OnBeginImplFrameDeadline();
615 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
616 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
617 EXPECT_TRUE(client.needs_begin_impl_frame());
621 TEST(SchedulerTest, TextureAcquisitionCollision) {
622 bool deadline_scheduling_enabled = false;
623 TextureAcquisitionCollision(deadline_scheduling_enabled);
626 TEST(SchedulerTest, TextureAcquisitionCollision_Deadline) {
627 bool deadline_scheduling_enabled = true;
628 TextureAcquisitionCollision(deadline_scheduling_enabled);
631 void VisibilitySwitchWithTextureAcquisition(bool deadline_scheduling_enabled) {
632 FakeSchedulerClient client;
633 SchedulerSettings scheduler_settings;
634 scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
635 Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
636 scheduler->SetCanStart();
637 scheduler->SetVisible(true);
638 scheduler->SetCanDraw(true);
640 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
642 scheduler->DidCreateAndInitializeOutputSurface();
644 scheduler->SetNeedsCommit();
645 if (deadline_scheduling_enabled) {
646 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
647 scheduler->OnBeginImplFrameDeadline();
649 scheduler->FinishCommit();
650 scheduler->SetMainThreadNeedsLayerTextures();
651 scheduler->SetNeedsCommit();
653 // Verify that pending texture acquisition fires when visibility
654 // is lost in order to avoid a deadlock.
655 scheduler->SetVisible(false);
656 EXPECT_SINGLE_ACTION("ScheduledActionAcquireLayerTexturesForMainThread",
660 scheduler->SetVisible(true);
661 EXPECT_EQ(0, client.num_actions_());
662 EXPECT_TRUE(client.needs_begin_impl_frame());
664 // Regaining visibility with textures acquired by main thread while
665 // compositor is waiting for first draw should result in a request
666 // for a new frame in order to escape a deadlock.
668 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
669 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
670 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
673 TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition) {
674 bool deadline_scheduling_enabled = false;
675 VisibilitySwitchWithTextureAcquisition(deadline_scheduling_enabled);
678 TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition_Deadline) {
679 bool deadline_scheduling_enabled = true;
680 VisibilitySwitchWithTextureAcquisition(deadline_scheduling_enabled);
683 class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
685 virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {}
686 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
688 // Only SetNeedsRedraw the first time this is called
690 scheduler_->SetNeedsRedraw();
691 return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
694 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
696 bool did_swap = true;
697 bool did_readback = false;
698 return DrawSwapReadbackResult(
699 DrawSwapReadbackResult::DRAW_SUCCESS, did_swap, did_readback);
702 virtual void ScheduledActionCommit() OVERRIDE {}
703 virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {}
704 virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {}
707 // Tests for two different situations:
708 // 1. the scheduler dropping SetNeedsRedraw requests that happen inside
709 // a ScheduledActionDrawAndSwap
710 // 2. the scheduler drawing twice inside a single tick
711 TEST(SchedulerTest, RequestRedrawInsideDraw) {
712 SchedulerClientThatsetNeedsDrawInsideDraw client;
713 SchedulerSettings default_scheduler_settings;
714 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
715 scheduler->SetCanStart();
716 scheduler->SetVisible(true);
717 scheduler->SetCanDraw(true);
718 InitializeOutputSurfaceAndFirstCommit(scheduler);
721 scheduler->SetNeedsRedraw();
722 EXPECT_TRUE(scheduler->RedrawPending());
723 EXPECT_TRUE(client.needs_begin_impl_frame());
724 EXPECT_EQ(0, client.num_draws());
726 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
727 scheduler->OnBeginImplFrameDeadline();
728 EXPECT_EQ(1, client.num_draws());
729 EXPECT_TRUE(scheduler->RedrawPending());
730 EXPECT_TRUE(client.needs_begin_impl_frame());
732 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
733 scheduler->OnBeginImplFrameDeadline();
734 EXPECT_EQ(2, client.num_draws());
735 EXPECT_FALSE(scheduler->RedrawPending());
736 EXPECT_TRUE(client.needs_begin_impl_frame());
738 // We stop requesting BeginImplFrames after a BeginImplFrame where we don't
740 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
741 scheduler->OnBeginImplFrameDeadline();
742 EXPECT_EQ(2, client.num_draws());
743 EXPECT_FALSE(scheduler->RedrawPending());
744 EXPECT_FALSE(client.needs_begin_impl_frame());
747 // Test that requesting redraw inside a failed draw doesn't lose the request.
748 TEST(SchedulerTest, RequestRedrawInsideFailedDraw) {
749 SchedulerClientThatsetNeedsDrawInsideDraw client;
750 SchedulerSettings default_scheduler_settings;
751 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
752 scheduler->SetCanStart();
753 scheduler->SetVisible(true);
754 scheduler->SetCanDraw(true);
755 InitializeOutputSurfaceAndFirstCommit(scheduler);
758 client.SetDrawWillHappen(false);
760 scheduler->SetNeedsRedraw();
761 EXPECT_TRUE(scheduler->RedrawPending());
762 EXPECT_TRUE(client.needs_begin_impl_frame());
763 EXPECT_EQ(0, client.num_draws());
766 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
767 scheduler->OnBeginImplFrameDeadline();
768 EXPECT_EQ(1, client.num_draws());
770 // We have a commit pending and the draw failed, and we didn't lose the redraw
772 EXPECT_TRUE(scheduler->CommitPending());
773 EXPECT_TRUE(scheduler->RedrawPending());
774 EXPECT_TRUE(client.needs_begin_impl_frame());
776 // Fail the draw again.
777 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
778 scheduler->OnBeginImplFrameDeadline();
779 EXPECT_EQ(2, client.num_draws());
780 EXPECT_TRUE(scheduler->CommitPending());
781 EXPECT_TRUE(scheduler->RedrawPending());
782 EXPECT_TRUE(client.needs_begin_impl_frame());
784 // Draw successfully.
785 client.SetDrawWillHappen(true);
786 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
787 scheduler->OnBeginImplFrameDeadline();
788 EXPECT_EQ(3, client.num_draws());
789 EXPECT_TRUE(scheduler->CommitPending());
790 EXPECT_FALSE(scheduler->RedrawPending());
791 EXPECT_TRUE(client.needs_begin_impl_frame());
794 class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
796 SchedulerClientThatSetNeedsCommitInsideDraw()
797 : set_needs_commit_on_next_draw_(false) {}
799 virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {}
800 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
802 // Only SetNeedsCommit the first time this is called
803 if (set_needs_commit_on_next_draw_) {
804 scheduler_->SetNeedsCommit();
805 set_needs_commit_on_next_draw_ = false;
807 return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
810 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
812 bool did_swap = false;
813 bool did_readback = false;
814 return DrawSwapReadbackResult(
815 DrawSwapReadbackResult::DRAW_SUCCESS, did_swap, did_readback);
818 virtual void ScheduledActionCommit() OVERRIDE {}
819 virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {}
820 virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {}
822 void SetNeedsCommitOnNextDraw() { set_needs_commit_on_next_draw_ = true; }
825 bool set_needs_commit_on_next_draw_;
828 // Tests for the scheduler infinite-looping on SetNeedsCommit requests that
829 // happen inside a ScheduledActionDrawAndSwap
830 TEST(SchedulerTest, RequestCommitInsideDraw) {
831 SchedulerClientThatSetNeedsCommitInsideDraw client;
832 SchedulerSettings default_scheduler_settings;
833 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
834 scheduler->SetCanStart();
835 scheduler->SetVisible(true);
836 scheduler->SetCanDraw(true);
837 InitializeOutputSurfaceAndFirstCommit(scheduler);
840 EXPECT_FALSE(client.needs_begin_impl_frame());
841 scheduler->SetNeedsRedraw();
842 EXPECT_TRUE(scheduler->RedrawPending());
843 EXPECT_EQ(0, client.num_draws());
844 EXPECT_TRUE(client.needs_begin_impl_frame());
846 client.SetNeedsCommitOnNextDraw();
847 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
848 client.SetNeedsCommitOnNextDraw();
849 scheduler->OnBeginImplFrameDeadline();
850 EXPECT_EQ(1, client.num_draws());
851 EXPECT_TRUE(scheduler->CommitPending());
852 EXPECT_TRUE(client.needs_begin_impl_frame());
853 scheduler->FinishCommit();
855 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
856 scheduler->OnBeginImplFrameDeadline();
857 EXPECT_EQ(2, client.num_draws());
859 EXPECT_FALSE(scheduler->RedrawPending());
860 EXPECT_FALSE(scheduler->CommitPending());
861 EXPECT_TRUE(client.needs_begin_impl_frame());
863 // We stop requesting BeginImplFrames after a BeginImplFrame where we don't
865 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
866 scheduler->OnBeginImplFrameDeadline();
867 EXPECT_EQ(2, client.num_draws());
868 EXPECT_FALSE(scheduler->RedrawPending());
869 EXPECT_FALSE(scheduler->CommitPending());
870 EXPECT_FALSE(client.needs_begin_impl_frame());
873 // Tests that when a draw fails then the pending commit should not be dropped.
874 TEST(SchedulerTest, RequestCommitInsideFailedDraw) {
875 SchedulerClientThatsetNeedsDrawInsideDraw client;
876 SchedulerSettings default_scheduler_settings;
877 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
878 scheduler->SetCanStart();
879 scheduler->SetVisible(true);
880 scheduler->SetCanDraw(true);
881 InitializeOutputSurfaceAndFirstCommit(scheduler);
884 client.SetDrawWillHappen(false);
886 scheduler->SetNeedsRedraw();
887 EXPECT_TRUE(scheduler->RedrawPending());
888 EXPECT_TRUE(client.needs_begin_impl_frame());
889 EXPECT_EQ(0, client.num_draws());
892 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
893 scheduler->OnBeginImplFrameDeadline();
894 EXPECT_EQ(1, client.num_draws());
896 // We have a commit pending and the draw failed, and we didn't lose the commit
898 EXPECT_TRUE(scheduler->CommitPending());
899 EXPECT_TRUE(scheduler->RedrawPending());
900 EXPECT_TRUE(client.needs_begin_impl_frame());
902 // Fail the draw again.
903 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
904 scheduler->OnBeginImplFrameDeadline();
905 EXPECT_EQ(2, client.num_draws());
906 EXPECT_TRUE(scheduler->CommitPending());
907 EXPECT_TRUE(scheduler->RedrawPending());
908 EXPECT_TRUE(client.needs_begin_impl_frame());
910 // Draw successfully.
911 client.SetDrawWillHappen(true);
912 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
913 scheduler->OnBeginImplFrameDeadline();
914 EXPECT_EQ(3, client.num_draws());
915 EXPECT_TRUE(scheduler->CommitPending());
916 EXPECT_FALSE(scheduler->RedrawPending());
917 EXPECT_TRUE(client.needs_begin_impl_frame());
920 TEST(SchedulerTest, NoSwapWhenDrawFails) {
921 SchedulerClientThatSetNeedsCommitInsideDraw client;
922 SchedulerSettings default_scheduler_settings;
923 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
924 scheduler->SetCanStart();
925 scheduler->SetVisible(true);
926 scheduler->SetCanDraw(true);
927 InitializeOutputSurfaceAndFirstCommit(scheduler);
930 scheduler->SetNeedsRedraw();
931 EXPECT_TRUE(scheduler->RedrawPending());
932 EXPECT_TRUE(client.needs_begin_impl_frame());
933 EXPECT_EQ(0, client.num_draws());
935 // Draw successfully, this starts a new frame.
936 client.SetNeedsCommitOnNextDraw();
937 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
938 scheduler->OnBeginImplFrameDeadline();
939 EXPECT_EQ(1, client.num_draws());
941 scheduler->SetNeedsRedraw();
942 EXPECT_TRUE(scheduler->RedrawPending());
943 EXPECT_TRUE(client.needs_begin_impl_frame());
945 // Fail to draw, this should not start a frame.
946 client.SetDrawWillHappen(false);
947 client.SetNeedsCommitOnNextDraw();
948 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
949 scheduler->OnBeginImplFrameDeadline();
950 EXPECT_EQ(2, client.num_draws());
953 TEST(SchedulerTest, NoSwapWhenSwapFailsDuringForcedCommit) {
954 FakeSchedulerClient client;
955 SchedulerSettings default_scheduler_settings;
956 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
958 // Tell the client that it will fail to swap.
959 client.SetDrawWillHappen(true);
960 client.SetSwapWillHappenIfDrawHappens(false);
962 // Get the compositor to do a ScheduledActionDrawAndReadback.
963 scheduler->SetCanDraw(true);
964 scheduler->SetNeedsRedraw();
965 scheduler->SetNeedsForcedCommitForReadback();
966 scheduler->FinishCommit();
967 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
970 TEST(SchedulerTest, BackToBackReadbackAllowed) {
971 // Some clients call readbacks twice in a row before the replacement
972 // commit comes in. Make sure it is allowed.
973 FakeSchedulerClient client;
974 SchedulerSettings default_scheduler_settings;
975 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
977 // Get the compositor to do 2 ScheduledActionDrawAndReadbacks before
978 // the replacement commit comes in.
979 scheduler->SetCanDraw(true);
980 scheduler->SetNeedsRedraw();
981 scheduler->SetNeedsForcedCommitForReadback();
982 scheduler->FinishCommit();
983 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
986 scheduler->SetNeedsForcedCommitForReadback();
987 scheduler->FinishCommit();
988 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
990 // The replacement commit comes in after 2 readbacks.
992 scheduler->FinishCommit();
996 class SchedulerClientNeedsManageTilesInDraw : public FakeSchedulerClient {
998 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
1000 scheduler_->SetNeedsManageTiles();
1001 return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
1005 // Test manage tiles is independant of draws.
1006 TEST(SchedulerTest, ManageTiles) {
1007 SchedulerClientNeedsManageTilesInDraw client;
1008 SchedulerSettings default_scheduler_settings;
1009 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
1010 scheduler->SetCanStart();
1011 scheduler->SetVisible(true);
1012 scheduler->SetCanDraw(true);
1013 InitializeOutputSurfaceAndFirstCommit(scheduler);
1015 // Request both draw and manage tiles. ManageTiles shouldn't
1016 // be trigged until BeginImplFrame.
1018 scheduler->SetNeedsManageTiles();
1019 scheduler->SetNeedsRedraw();
1020 EXPECT_TRUE(scheduler->RedrawPending());
1021 EXPECT_TRUE(scheduler->ManageTilesPending());
1022 EXPECT_TRUE(client.needs_begin_impl_frame());
1023 EXPECT_EQ(0, client.num_draws());
1024 EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
1025 EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1027 // We have no immediate actions to perform, so the BeginImplFrame should post
1028 // the deadline task.
1030 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1031 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1033 // On the deadline, he actions should have occured in the right order.
1035 scheduler->OnBeginImplFrameDeadline();
1036 EXPECT_EQ(1, client.num_draws());
1037 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1038 EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
1039 EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
1040 client.ActionIndex("ScheduledActionManageTiles"));
1041 EXPECT_FALSE(scheduler->RedrawPending());
1042 EXPECT_FALSE(scheduler->ManageTilesPending());
1044 // Request a draw. We don't need a ManageTiles yet.
1046 scheduler->SetNeedsRedraw();
1047 EXPECT_TRUE(scheduler->RedrawPending());
1048 EXPECT_FALSE(scheduler->ManageTilesPending());
1049 EXPECT_TRUE(client.needs_begin_impl_frame());
1050 EXPECT_EQ(0, client.num_draws());
1052 // We have no immediate actions to perform, so the BeginImplFrame should post
1053 // the deadline task.
1055 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1056 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1058 // Draw. The draw will trigger SetNeedsManageTiles, and
1059 // then the ManageTiles action will be triggered after the Draw.
1060 // Afterwards, neither a draw nor ManageTiles are pending.
1062 scheduler->OnBeginImplFrameDeadline();
1063 EXPECT_EQ(1, client.num_draws());
1064 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1065 EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
1066 EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
1067 client.ActionIndex("ScheduledActionManageTiles"));
1068 EXPECT_FALSE(scheduler->RedrawPending());
1069 EXPECT_FALSE(scheduler->ManageTilesPending());
1071 // We need a BeginImplFrame where we don't swap to go idle.
1073 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1074 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1076 scheduler->OnBeginImplFrameDeadline();
1077 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);;
1078 EXPECT_EQ(0, client.num_draws());
1080 // Now trigger a ManageTiles outside of a draw. We will then need
1081 // a begin-frame for the ManageTiles, but we don't need a draw.
1083 EXPECT_FALSE(client.needs_begin_impl_frame());
1084 scheduler->SetNeedsManageTiles();
1085 EXPECT_TRUE(client.needs_begin_impl_frame());
1086 EXPECT_TRUE(scheduler->ManageTilesPending());
1087 EXPECT_FALSE(scheduler->RedrawPending());
1089 // BeginImplFrame. There will be no draw, only ManageTiles.
1091 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1092 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1094 scheduler->OnBeginImplFrameDeadline();
1095 EXPECT_EQ(0, client.num_draws());
1096 EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1097 EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
1100 // Test that ManageTiles only happens once per frame. If an external caller
1101 // initiates it, then the state machine should not ManageTiles on that frame.
1102 TEST(SchedulerTest, ManageTilesOncePerFrame) {
1103 FakeSchedulerClient client;
1104 SchedulerSettings default_scheduler_settings;
1105 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
1106 scheduler->SetCanStart();
1107 scheduler->SetVisible(true);
1108 scheduler->SetCanDraw(true);
1109 InitializeOutputSurfaceAndFirstCommit(scheduler);
1111 // If DidManageTiles during a frame, then ManageTiles should not occur again.
1112 scheduler->SetNeedsManageTiles();
1113 scheduler->SetNeedsRedraw();
1115 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1116 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1118 EXPECT_TRUE(scheduler->ManageTilesPending());
1119 scheduler->DidManageTiles(); // An explicit ManageTiles.
1120 EXPECT_FALSE(scheduler->ManageTilesPending());
1123 scheduler->OnBeginImplFrameDeadline();
1124 EXPECT_EQ(1, client.num_draws());
1125 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1126 EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
1127 EXPECT_FALSE(scheduler->RedrawPending());
1128 EXPECT_FALSE(scheduler->ManageTilesPending());
1130 // Next frame without DidManageTiles should ManageTiles with draw.
1131 scheduler->SetNeedsManageTiles();
1132 scheduler->SetNeedsRedraw();
1134 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1135 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1138 scheduler->OnBeginImplFrameDeadline();
1139 EXPECT_EQ(1, client.num_draws());
1140 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1141 EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
1142 EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
1143 client.ActionIndex("ScheduledActionManageTiles"));
1144 EXPECT_FALSE(scheduler->RedrawPending());
1145 EXPECT_FALSE(scheduler->ManageTilesPending());
1146 scheduler->DidManageTiles(); // Corresponds to ScheduledActionManageTiles
1148 // If we get another DidManageTiles within the same frame, we should
1149 // not ManageTiles on the next frame.
1150 scheduler->DidManageTiles(); // An explicit ManageTiles.
1151 scheduler->SetNeedsManageTiles();
1152 scheduler->SetNeedsRedraw();
1154 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1155 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1157 EXPECT_TRUE(scheduler->ManageTilesPending());
1160 scheduler->OnBeginImplFrameDeadline();
1161 EXPECT_EQ(1, client.num_draws());
1162 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1163 EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
1164 EXPECT_FALSE(scheduler->RedrawPending());
1166 // If we get another DidManageTiles, we should not ManageTiles on the next
1167 // frame. This verifies we don't alternate calling ManageTiles once and twice.
1168 EXPECT_TRUE(scheduler->ManageTilesPending());
1169 scheduler->DidManageTiles(); // An explicit ManageTiles.
1170 EXPECT_FALSE(scheduler->ManageTilesPending());
1171 scheduler->SetNeedsManageTiles();
1172 scheduler->SetNeedsRedraw();
1174 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1175 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1177 EXPECT_TRUE(scheduler->ManageTilesPending());
1180 scheduler->OnBeginImplFrameDeadline();
1181 EXPECT_EQ(1, client.num_draws());
1182 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1183 EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
1184 EXPECT_FALSE(scheduler->RedrawPending());
1186 // Next frame without DidManageTiles should ManageTiles with draw.
1187 scheduler->SetNeedsManageTiles();
1188 scheduler->SetNeedsRedraw();
1190 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1191 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1194 scheduler->OnBeginImplFrameDeadline();
1195 EXPECT_EQ(1, client.num_draws());
1196 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1197 EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
1198 EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
1199 client.ActionIndex("ScheduledActionManageTiles"));
1200 EXPECT_FALSE(scheduler->RedrawPending());
1201 EXPECT_FALSE(scheduler->ManageTilesPending());
1202 scheduler->DidManageTiles(); // Corresponds to ScheduledActionManageTiles
1205 class SchedulerClientWithFixedEstimates : public FakeSchedulerClient {
1207 SchedulerClientWithFixedEstimates(
1208 base::TimeDelta draw_duration,
1209 base::TimeDelta begin_main_frame_to_commit_duration,
1210 base::TimeDelta commit_to_activate_duration)
1211 : draw_duration_(draw_duration),
1212 begin_main_frame_to_commit_duration_(
1213 begin_main_frame_to_commit_duration),
1214 commit_to_activate_duration_(commit_to_activate_duration) {}
1216 virtual base::TimeDelta DrawDurationEstimate() OVERRIDE {
1217 return draw_duration_;
1219 virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE {
1220 return begin_main_frame_to_commit_duration_;
1222 virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE {
1223 return commit_to_activate_duration_;
1227 base::TimeDelta draw_duration_;
1228 base::TimeDelta begin_main_frame_to_commit_duration_;
1229 base::TimeDelta commit_to_activate_duration_;
1232 void MainFrameInHighLatencyMode(int64 begin_main_frame_to_commit_estimate_in_ms,
1233 int64 commit_to_activate_estimate_in_ms,
1234 bool should_send_begin_main_frame) {
1235 // Set up client with specified estimates (draw duration is set to 1).
1236 SchedulerClientWithFixedEstimates client(
1237 base::TimeDelta::FromMilliseconds(1),
1238 base::TimeDelta::FromMilliseconds(
1239 begin_main_frame_to_commit_estimate_in_ms),
1240 base::TimeDelta::FromMilliseconds(commit_to_activate_estimate_in_ms));
1241 SchedulerSettings scheduler_settings;
1242 scheduler_settings.deadline_scheduling_enabled = true;
1243 scheduler_settings.switch_to_low_latency_if_possible = true;
1244 Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
1245 scheduler->SetCanStart();
1246 scheduler->SetVisible(true);
1247 scheduler->SetCanDraw(true);
1248 InitializeOutputSurfaceAndFirstCommit(scheduler);
1250 // Impl thread hits deadline before commit finishes.
1252 scheduler->SetNeedsCommit();
1253 EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode());
1254 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1255 EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode());
1256 scheduler->OnBeginImplFrameDeadline();
1257 EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
1258 scheduler->FinishCommit();
1259 EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
1260 EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
1263 scheduler->SetNeedsCommit();
1264 EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
1265 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1266 EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
1267 scheduler->OnBeginImplFrameDeadline();
1268 EXPECT_EQ(scheduler->MainThreadIsInHighLatencyMode(),
1269 should_send_begin_main_frame);
1270 EXPECT_EQ(client.HasAction("ScheduledActionSendBeginMainFrame"),
1271 should_send_begin_main_frame);
1275 SkipMainFrameIfHighLatencyAndCanCommitAndActivateBeforeDeadline) {
1276 // Set up client so that estimates indicate that we can commit and activate
1277 // before the deadline (~8ms by default).
1278 MainFrameInHighLatencyMode(1, 1, false);
1281 TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanCommitTooLong) {
1282 // Set up client so that estimates indicate that the commit cannot finish
1283 // before the deadline (~8ms by default).
1284 MainFrameInHighLatencyMode(10, 1, true);
1287 TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanActivateTooLong) {
1288 // Set up client so that estimates indicate that the activate cannot finish
1289 // before the deadline (~8ms by default).
1290 MainFrameInHighLatencyMode(1, 10, true);
1293 void SpinForMillis(int millis) {
1294 base::RunLoop run_loop;
1295 base::MessageLoop::current()->PostDelayedTask(
1297 run_loop.QuitClosure(),
1298 base::TimeDelta::FromMilliseconds(millis));
1302 TEST(SchedulerTest, PollForCommitCompletion) {
1303 FakeSchedulerClient client;
1304 client.set_log_anticipated_draw_time_change(true);
1305 SchedulerSettings settings = SchedulerSettings();
1306 settings.throttle_frame_production = false;
1307 Scheduler* scheduler = client.CreateScheduler(settings);
1309 scheduler->SetCanDraw(true);
1310 scheduler->SetCanStart();
1311 scheduler->SetVisible(true);
1312 scheduler->DidCreateAndInitializeOutputSurface();
1314 scheduler->SetNeedsCommit();
1315 EXPECT_TRUE(scheduler->CommitPending());
1316 scheduler->FinishCommit();
1317 scheduler->SetNeedsRedraw();
1318 BeginFrameArgs impl_frame_args = BeginFrameArgs::CreateForTesting();
1319 const int interval = 1;
1320 impl_frame_args.interval = base::TimeDelta::FromMilliseconds(interval);
1321 scheduler->BeginImplFrame(impl_frame_args);
1322 scheduler->OnBeginImplFrameDeadline();
1324 // At this point, we've drawn a frame. Start another commit, but hold off on
1325 // the FinishCommit for now.
1326 EXPECT_FALSE(scheduler->CommitPending());
1327 scheduler->SetNeedsCommit();
1328 EXPECT_TRUE(scheduler->CommitPending());
1330 // Spin the event loop a few times and make sure we get more
1331 // DidAnticipateDrawTimeChange calls every time.
1332 int actions_so_far = client.num_actions_();
1334 // Does three iterations to make sure that the timer is properly repeating.
1335 for (int i = 0; i < 3; ++i) {
1336 // Wait for 2x the frame interval to match
1337 // Scheduler::advance_commit_state_timer_'s rate.
1338 SpinForMillis(interval * 2);
1339 EXPECT_GT(client.num_actions_(), actions_so_far);
1340 EXPECT_STREQ(client.Action(client.num_actions_() - 1),
1341 "DidAnticipatedDrawTimeChange");
1342 actions_so_far = client.num_actions_();