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 "cc/test/scheduler_test_common.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h"
15 #define EXPECT_ACTION(action, client, action_index, expected_num_actions) \
16 EXPECT_EQ(expected_num_actions, client.num_actions_()); \
17 ASSERT_LT(action_index, client.num_actions_()); \
19 EXPECT_STREQ(action, client.Action(action_index)); \
20 for (int i = expected_num_actions; i < client.num_actions_(); ++i) \
21 ADD_FAILURE() << "Unexpected action: " << client.Action(i) << \
22 " with state:\n" << client.StateForAction(action_index); \
25 #define EXPECT_SINGLE_ACTION(action, client) \
26 EXPECT_ACTION(action, client, 0, 1)
31 void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler) {
32 scheduler->DidCreateAndInitializeOutputSurface();
33 scheduler->SetNeedsCommit();
34 scheduler->FinishCommit();
35 // Go through the motions to draw the commit.
36 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
37 scheduler->OnBeginImplFrameDeadline();
38 // We need another BeginImplFrame so Scheduler calls
39 // SetNeedsBeginImplFrame(false).
40 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
41 scheduler->OnBeginImplFrameDeadline();
44 class FakeSchedulerClient : public SchedulerClient {
47 : needs_begin_impl_frame_(false) {
54 draw_will_happen_ = true;
55 swap_will_happen_if_draw_happens_ = true;
59 Scheduler* CreateScheduler(const SchedulerSettings& settings) {
60 scheduler_ = Scheduler::Create(this, settings);
61 return scheduler_.get();
64 bool needs_begin_impl_frame() { return needs_begin_impl_frame_; }
65 int num_draws() const { return num_draws_; }
66 int num_actions_() const { return static_cast<int>(actions_.size()); }
67 const char* Action(int i) const { return actions_[i]; }
68 base::Value& StateForAction(int i) const { return *states_[i]; }
70 int ActionIndex(const char* action) const {
71 for (size_t i = 0; i < actions_.size(); i++)
72 if (!strcmp(actions_[i], action))
77 bool HasAction(const char* action) const {
78 return ActionIndex(action) >= 0;
81 void SetDrawWillHappen(bool draw_will_happen) {
82 draw_will_happen_ = draw_will_happen;
84 void SetSwapWillHappenIfDrawHappens(bool swap_will_happen_if_draw_happens) {
85 swap_will_happen_if_draw_happens_ = swap_will_happen_if_draw_happens;
88 // Scheduler Implementation.
89 virtual void SetNeedsBeginImplFrame(bool enable) OVERRIDE {
90 actions_.push_back("SetNeedsBeginImplFrame");
91 states_.push_back(scheduler_->StateAsValue().release());
92 needs_begin_impl_frame_ = enable;
94 virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {
95 actions_.push_back("ScheduledActionSendBeginMainFrame");
96 states_.push_back(scheduler_->StateAsValue().release());
98 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
100 actions_.push_back("ScheduledActionDrawAndSwapIfPossible");
101 states_.push_back(scheduler_->StateAsValue().release());
103 bool did_readback = false;
104 return DrawSwapReadbackResult(
106 draw_will_happen_ && swap_will_happen_if_draw_happens_,
109 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
110 actions_.push_back("ScheduledActionDrawAndSwapForced");
111 states_.push_back(scheduler_->StateAsValue().release());
112 bool did_draw = true;
113 bool did_swap = swap_will_happen_if_draw_happens_;
114 bool did_readback = false;
115 return DrawSwapReadbackResult(did_draw, did_swap, did_readback);
117 virtual DrawSwapReadbackResult ScheduledActionDrawAndReadback() OVERRIDE {
118 actions_.push_back("ScheduledActionDrawAndReadback");
119 states_.push_back(scheduler_->StateAsValue().release());
120 bool did_draw = true;
121 bool did_swap = false;
122 bool did_readback = true;
123 return DrawSwapReadbackResult(did_draw, did_swap, did_readback);
125 virtual void ScheduledActionCommit() OVERRIDE {
126 actions_.push_back("ScheduledActionCommit");
127 states_.push_back(scheduler_->StateAsValue().release());
129 virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE {
130 actions_.push_back("ScheduledActionUpdateVisibleTiles");
131 states_.push_back(scheduler_->StateAsValue().release());
133 virtual void ScheduledActionActivatePendingTree() OVERRIDE {
134 actions_.push_back("ScheduledActionActivatePendingTree");
135 states_.push_back(scheduler_->StateAsValue().release());
137 virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {
138 actions_.push_back("ScheduledActionBeginOutputSurfaceCreation");
139 states_.push_back(scheduler_->StateAsValue().release());
141 virtual void ScheduledActionAcquireLayerTexturesForMainThread() OVERRIDE {
142 actions_.push_back("ScheduledActionAcquireLayerTexturesForMainThread");
143 states_.push_back(scheduler_->StateAsValue().release());
145 virtual void ScheduledActionManageTiles() OVERRIDE {
146 actions_.push_back("ScheduledActionManageTiles");
147 states_.push_back(scheduler_->StateAsValue().release());
149 virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {}
150 virtual base::TimeDelta DrawDurationEstimate() OVERRIDE {
151 return base::TimeDelta();
153 virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE {
154 return base::TimeDelta();
156 virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE {
157 return base::TimeDelta();
160 virtual void PostBeginImplFrameDeadline(const base::Closure& closure,
161 base::TimeTicks deadline) OVERRIDE {
162 actions_.push_back("PostBeginImplFrameDeadlineTask");
163 states_.push_back(scheduler_->StateAsValue().release());
166 virtual void DidBeginImplFrameDeadline() OVERRIDE {}
169 bool needs_begin_impl_frame_;
170 bool draw_will_happen_;
171 bool swap_will_happen_if_draw_happens_;
173 std::vector<const char*> actions_;
174 ScopedVector<base::Value> states_;
175 scoped_ptr<Scheduler> scheduler_;
178 TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginImplFrame) {
179 FakeSchedulerClient client;
180 SchedulerSettings default_scheduler_settings;
181 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
182 scheduler->SetCanStart();
183 scheduler->SetVisible(true);
184 scheduler->SetCanDraw(true);
186 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
188 scheduler->DidCreateAndInitializeOutputSurface();
189 EXPECT_EQ(0, client.num_actions_());
192 void RequestCommit(bool deadline_scheduling_enabled) {
193 FakeSchedulerClient client;
194 SchedulerSettings scheduler_settings;
195 scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
196 Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
197 scheduler->SetCanStart();
198 scheduler->SetVisible(true);
199 scheduler->SetCanDraw(true);
201 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
202 InitializeOutputSurfaceAndFirstCommit(scheduler);
204 // SetNeedsCommit should begin the frame on the next BeginImplFrame.
206 scheduler->SetNeedsCommit();
207 EXPECT_TRUE(client.needs_begin_impl_frame());
208 if (deadline_scheduling_enabled) {
209 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
211 EXPECT_EQ(client.num_actions_(), 2);
212 EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
213 EXPECT_TRUE(client.HasAction("SetNeedsBeginImplFrame"));
217 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
218 if (deadline_scheduling_enabled) {
219 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
220 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
222 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
224 EXPECT_TRUE(client.needs_begin_impl_frame());
227 // If we don't swap on the deadline, we need to request another
229 scheduler->OnBeginImplFrameDeadline();
230 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
231 EXPECT_TRUE(client.needs_begin_impl_frame());
234 // FinishCommit should commit
235 scheduler->FinishCommit();
236 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
237 EXPECT_TRUE(client.needs_begin_impl_frame());
240 // BeginImplFrame should prepare the draw.
241 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
242 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
243 EXPECT_TRUE(client.needs_begin_impl_frame());
246 // BeginImplFrame deadline should draw.
247 scheduler->OnBeginImplFrameDeadline();
248 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
249 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
250 EXPECT_TRUE(client.needs_begin_impl_frame());
253 // The following BeginImplFrame deadline should SetNeedsBeginImplFrame(false)
254 // to avoid excessive toggles.
255 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
256 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
259 scheduler->OnBeginImplFrameDeadline();
260 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
261 EXPECT_FALSE(client.needs_begin_impl_frame());
265 TEST(SchedulerTest, RequestCommit) {
266 bool deadline_scheduling_enabled = false;
267 RequestCommit(deadline_scheduling_enabled);
270 TEST(SchedulerTest, RequestCommit_Deadline) {
271 bool deadline_scheduling_enabled = true;
272 RequestCommit(deadline_scheduling_enabled);
275 void RequestCommitAfterBeginMainFrameSent(
276 bool deadline_scheduling_enabled) {
277 FakeSchedulerClient client;
278 SchedulerSettings scheduler_settings;
279 scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
280 Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
281 scheduler->SetCanStart();
282 scheduler->SetVisible(true);
283 scheduler->SetCanDraw(true);
285 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
286 InitializeOutputSurfaceAndFirstCommit(scheduler);
289 // SetNeedsCommit should begin the frame.
290 scheduler->SetNeedsCommit();
291 if (deadline_scheduling_enabled) {
292 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
294 EXPECT_EQ(client.num_actions_(), 2);
295 EXPECT_TRUE(client.HasAction("SetNeedsBeginImplFrame"));
296 EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
300 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
301 if (deadline_scheduling_enabled) {
302 EXPECT_EQ(client.num_actions_(), 2);
303 EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
304 EXPECT_TRUE(client.HasAction("PostBeginImplFrameDeadlineTask"));
306 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
309 EXPECT_TRUE(client.needs_begin_impl_frame());
312 // Now SetNeedsCommit again. Calling here means we need a second commit.
313 scheduler->SetNeedsCommit();
314 EXPECT_EQ(client.num_actions_(), 0);
317 // Finish the first commit.
318 scheduler->FinishCommit();
319 EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
320 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
322 scheduler->OnBeginImplFrameDeadline();
323 if (deadline_scheduling_enabled) {
324 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
325 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
327 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 3);
328 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 3);
329 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 2, 3);
332 // Because we just swapped, the Scheduler should also request the next
333 // BeginImplFrame from the OutputSurface.
334 EXPECT_TRUE(client.needs_begin_impl_frame());
337 // Since another commit is needed, the next BeginImplFrame should initiate
338 // the second commit.
339 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
340 if (deadline_scheduling_enabled) {
341 EXPECT_EQ(client.num_actions_(), 2);
342 EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
343 EXPECT_TRUE(client.HasAction("PostBeginImplFrameDeadlineTask"));
345 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
349 // Finishing the commit before the deadline should post a new deadline task
350 // to trigger the deadline early.
351 scheduler->FinishCommit();
352 EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
353 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
355 scheduler->OnBeginImplFrameDeadline();
356 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
357 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
358 EXPECT_TRUE(client.needs_begin_impl_frame());
361 // On the next BeginImplFrame, verify we go back to a quiescent state and
362 // no longer request BeginImplFrames.
363 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
364 scheduler->OnBeginImplFrameDeadline();
365 EXPECT_FALSE(client.needs_begin_impl_frame());
369 TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
370 bool deadline_scheduling_enabled = false;
371 RequestCommitAfterBeginMainFrameSent(deadline_scheduling_enabled);
374 TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent_Deadline) {
375 bool deadline_scheduling_enabled = true;
376 RequestCommitAfterBeginMainFrameSent(deadline_scheduling_enabled);
379 void TextureAcquisitionCausesCommitInsteadOfDraw(
380 bool deadline_scheduling_enabled) {
381 FakeSchedulerClient client;
382 SchedulerSettings scheduler_settings;
383 scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
384 Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
385 scheduler->SetCanStart();
386 scheduler->SetVisible(true);
387 scheduler->SetCanDraw(true);
388 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
390 InitializeOutputSurfaceAndFirstCommit(scheduler);
392 scheduler->SetNeedsRedraw();
393 EXPECT_TRUE(scheduler->RedrawPending());
394 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
395 EXPECT_TRUE(client.needs_begin_impl_frame());
398 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
399 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
401 scheduler->OnBeginImplFrameDeadline();
402 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
403 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
404 EXPECT_FALSE(scheduler->RedrawPending());
405 EXPECT_TRUE(client.needs_begin_impl_frame());
408 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
409 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
411 scheduler->OnBeginImplFrameDeadline();
412 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
413 EXPECT_FALSE(scheduler->RedrawPending());
414 EXPECT_FALSE(client.needs_begin_impl_frame());
417 scheduler->SetMainThreadNeedsLayerTextures();
418 EXPECT_SINGLE_ACTION("ScheduledActionAcquireLayerTexturesForMainThread",
421 // We should request a BeginImplFrame in anticipation of a draw.
423 scheduler->SetNeedsRedraw();
424 EXPECT_TRUE(scheduler->RedrawPending());
425 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
426 EXPECT_TRUE(client.needs_begin_impl_frame());
428 // No draw happens since the textures are acquired by the main thread.
430 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
431 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
433 scheduler->OnBeginImplFrameDeadline();
434 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
435 EXPECT_TRUE(scheduler->RedrawPending());
436 EXPECT_TRUE(client.needs_begin_impl_frame());
439 scheduler->SetNeedsCommit();
440 if (deadline_scheduling_enabled) {
441 EXPECT_EQ(0, client.num_actions_());
443 EXPECT_SINGLE_ACTION("ScheduledActionSendBeginMainFrame", client);
447 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
448 if (deadline_scheduling_enabled) {
449 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
450 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
452 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
455 // Commit will release the texture.
457 scheduler->FinishCommit();
458 EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
459 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
460 EXPECT_TRUE(scheduler->RedrawPending());
462 // Now we can draw again after the commit happens.
464 scheduler->OnBeginImplFrameDeadline();
465 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
466 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
467 EXPECT_FALSE(scheduler->RedrawPending());
468 EXPECT_TRUE(client.needs_begin_impl_frame());
470 // Make sure we stop requesting BeginImplFrames if we don't swap.
472 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
473 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
475 scheduler->OnBeginImplFrameDeadline();
476 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
477 EXPECT_FALSE(client.needs_begin_impl_frame());
480 TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw) {
481 bool deadline_scheduling_enabled = false;
482 TextureAcquisitionCausesCommitInsteadOfDraw(deadline_scheduling_enabled);
485 TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw_Deadline) {
486 bool deadline_scheduling_enabled = true;
487 TextureAcquisitionCausesCommitInsteadOfDraw(deadline_scheduling_enabled);
490 void TextureAcquisitionCollision(bool deadline_scheduling_enabled) {
491 FakeSchedulerClient client;
492 SchedulerSettings scheduler_settings;
493 scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
494 Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
495 scheduler->SetCanStart();
496 scheduler->SetVisible(true);
497 scheduler->SetCanDraw(true);
499 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
500 InitializeOutputSurfaceAndFirstCommit(scheduler);
503 scheduler->SetNeedsCommit();
504 if (deadline_scheduling_enabled) {
505 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
507 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
508 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
512 scheduler->SetMainThreadNeedsLayerTextures();
513 EXPECT_SINGLE_ACTION(
514 "ScheduledActionAcquireLayerTexturesForMainThread", client);
517 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
518 if (deadline_scheduling_enabled) {
519 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
520 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
522 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
526 scheduler->OnBeginImplFrameDeadline();
527 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
529 // Although the compositor cannot draw because textures are locked by main
530 // thread, we continue requesting SetNeedsBeginImplFrame in anticipation of
532 EXPECT_TRUE(client.needs_begin_impl_frame());
534 // Trigger the commit
535 scheduler->FinishCommit();
536 EXPECT_TRUE(client.needs_begin_impl_frame());
538 // Between commit and draw, texture acquisition for main thread delayed,
539 // and main thread blocks.
541 scheduler->SetMainThreadNeedsLayerTextures();
542 EXPECT_EQ(0, client.num_actions_());
544 // No implicit commit is expected.
546 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
547 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
550 scheduler->OnBeginImplFrameDeadline();
551 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 3);
553 "ScheduledActionAcquireLayerTexturesForMainThread", client, 1, 3);
554 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 2, 3);
555 EXPECT_TRUE(client.needs_begin_impl_frame());
557 // The compositor should not draw because textures are locked by main
560 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
561 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
563 scheduler->OnBeginImplFrameDeadline();
564 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
565 EXPECT_FALSE(client.needs_begin_impl_frame());
567 // The impl thread need an explicit commit from the main thread to lock
570 scheduler->SetNeedsCommit();
571 if (deadline_scheduling_enabled) {
572 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
574 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
575 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
577 EXPECT_TRUE(client.needs_begin_impl_frame());
580 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
581 if (deadline_scheduling_enabled) {
582 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
583 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
585 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
589 // Trigger the commit, which will trigger the deadline task early.
590 scheduler->FinishCommit();
591 EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
592 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
593 EXPECT_TRUE(client.needs_begin_impl_frame());
596 // Verify we draw on the next BeginImplFrame deadline
597 scheduler->OnBeginImplFrameDeadline();
598 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
599 EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
600 EXPECT_TRUE(client.needs_begin_impl_frame());
604 TEST(SchedulerTest, TextureAcquisitionCollision) {
605 bool deadline_scheduling_enabled = false;
606 TextureAcquisitionCollision(deadline_scheduling_enabled);
609 TEST(SchedulerTest, TextureAcquisitionCollision_Deadline) {
610 bool deadline_scheduling_enabled = true;
611 TextureAcquisitionCollision(deadline_scheduling_enabled);
614 void VisibilitySwitchWithTextureAcquisition(bool deadline_scheduling_enabled) {
615 FakeSchedulerClient client;
616 SchedulerSettings scheduler_settings;
617 scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
618 Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
619 scheduler->SetCanStart();
620 scheduler->SetVisible(true);
621 scheduler->SetCanDraw(true);
623 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
625 scheduler->DidCreateAndInitializeOutputSurface();
627 scheduler->SetNeedsCommit();
628 if (deadline_scheduling_enabled) {
629 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
630 scheduler->OnBeginImplFrameDeadline();
632 scheduler->FinishCommit();
633 scheduler->SetMainThreadNeedsLayerTextures();
634 scheduler->SetNeedsCommit();
636 // Verify that pending texture acquisition fires when visibility
637 // is lost in order to avoid a deadlock.
638 scheduler->SetVisible(false);
639 EXPECT_SINGLE_ACTION("ScheduledActionAcquireLayerTexturesForMainThread",
643 scheduler->SetVisible(true);
644 EXPECT_EQ(0, client.num_actions_());
645 EXPECT_TRUE(client.needs_begin_impl_frame());
647 // Regaining visibility with textures acquired by main thread while
648 // compositor is waiting for first draw should result in a request
649 // for a new frame in order to escape a deadlock.
651 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
652 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
653 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
656 TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition) {
657 bool deadline_scheduling_enabled = false;
658 VisibilitySwitchWithTextureAcquisition(deadline_scheduling_enabled);
661 TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition_Deadline) {
662 bool deadline_scheduling_enabled = true;
663 VisibilitySwitchWithTextureAcquisition(deadline_scheduling_enabled);
666 class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
668 virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {}
669 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
671 // Only SetNeedsRedraw the first time this is called
673 scheduler_->SetNeedsRedraw();
674 return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
677 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
679 bool did_draw = true;
680 bool did_swap = true;
681 bool did_readback = false;
682 return DrawSwapReadbackResult(did_draw, did_swap, did_readback);
685 virtual void ScheduledActionCommit() OVERRIDE {}
686 virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {}
687 virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {}
690 // Tests for two different situations:
691 // 1. the scheduler dropping SetNeedsRedraw requests that happen inside
692 // a ScheduledActionDrawAndSwap
693 // 2. the scheduler drawing twice inside a single tick
694 TEST(SchedulerTest, RequestRedrawInsideDraw) {
695 SchedulerClientThatsetNeedsDrawInsideDraw client;
696 SchedulerSettings default_scheduler_settings;
697 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
698 scheduler->SetCanStart();
699 scheduler->SetVisible(true);
700 scheduler->SetCanDraw(true);
701 InitializeOutputSurfaceAndFirstCommit(scheduler);
704 scheduler->SetNeedsRedraw();
705 EXPECT_TRUE(scheduler->RedrawPending());
706 EXPECT_TRUE(client.needs_begin_impl_frame());
707 EXPECT_EQ(0, client.num_draws());
709 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
710 scheduler->OnBeginImplFrameDeadline();
711 EXPECT_EQ(1, client.num_draws());
712 EXPECT_TRUE(scheduler->RedrawPending());
713 EXPECT_TRUE(client.needs_begin_impl_frame());
715 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
716 scheduler->OnBeginImplFrameDeadline();
717 EXPECT_EQ(2, client.num_draws());
718 EXPECT_FALSE(scheduler->RedrawPending());
719 EXPECT_TRUE(client.needs_begin_impl_frame());
721 // We stop requesting BeginImplFrames after a BeginImplFrame where we don't
723 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
724 scheduler->OnBeginImplFrameDeadline();
725 EXPECT_EQ(2, client.num_draws());
726 EXPECT_FALSE(scheduler->RedrawPending());
727 EXPECT_FALSE(client.needs_begin_impl_frame());
730 // Test that requesting redraw inside a failed draw doesn't lose the request.
731 TEST(SchedulerTest, RequestRedrawInsideFailedDraw) {
732 SchedulerClientThatsetNeedsDrawInsideDraw client;
733 SchedulerSettings default_scheduler_settings;
734 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
735 scheduler->SetCanStart();
736 scheduler->SetVisible(true);
737 scheduler->SetCanDraw(true);
738 InitializeOutputSurfaceAndFirstCommit(scheduler);
741 client.SetDrawWillHappen(false);
743 scheduler->SetNeedsRedraw();
744 EXPECT_TRUE(scheduler->RedrawPending());
745 EXPECT_TRUE(client.needs_begin_impl_frame());
746 EXPECT_EQ(0, client.num_draws());
749 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
750 scheduler->OnBeginImplFrameDeadline();
751 EXPECT_EQ(1, client.num_draws());
753 // We have a commit pending and the draw failed, and we didn't lose the redraw
755 EXPECT_TRUE(scheduler->CommitPending());
756 EXPECT_TRUE(scheduler->RedrawPending());
757 EXPECT_TRUE(client.needs_begin_impl_frame());
759 // Fail the draw again.
760 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
761 scheduler->OnBeginImplFrameDeadline();
762 EXPECT_EQ(2, client.num_draws());
763 EXPECT_TRUE(scheduler->CommitPending());
764 EXPECT_TRUE(scheduler->RedrawPending());
765 EXPECT_TRUE(client.needs_begin_impl_frame());
767 // Draw successfully.
768 client.SetDrawWillHappen(true);
769 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
770 scheduler->OnBeginImplFrameDeadline();
771 EXPECT_EQ(3, client.num_draws());
772 EXPECT_TRUE(scheduler->CommitPending());
773 EXPECT_FALSE(scheduler->RedrawPending());
774 EXPECT_TRUE(client.needs_begin_impl_frame());
777 class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
779 SchedulerClientThatSetNeedsCommitInsideDraw()
780 : set_needs_commit_on_next_draw_(false) {}
782 virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {}
783 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
785 // Only SetNeedsCommit the first time this is called
786 if (set_needs_commit_on_next_draw_) {
787 scheduler_->SetNeedsCommit();
788 set_needs_commit_on_next_draw_ = false;
790 return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
793 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
795 bool did_draw = true;
796 bool did_swap = false;
797 bool did_readback = false;
798 return DrawSwapReadbackResult(did_draw, did_swap, did_readback);
801 virtual void ScheduledActionCommit() OVERRIDE {}
802 virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {}
803 virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {}
805 void SetNeedsCommitOnNextDraw() { set_needs_commit_on_next_draw_ = true; }
808 bool set_needs_commit_on_next_draw_;
811 // Tests for the scheduler infinite-looping on SetNeedsCommit requests that
812 // happen inside a ScheduledActionDrawAndSwap
813 TEST(SchedulerTest, RequestCommitInsideDraw) {
814 SchedulerClientThatSetNeedsCommitInsideDraw client;
815 SchedulerSettings default_scheduler_settings;
816 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
817 scheduler->SetCanStart();
818 scheduler->SetVisible(true);
819 scheduler->SetCanDraw(true);
820 InitializeOutputSurfaceAndFirstCommit(scheduler);
823 EXPECT_FALSE(client.needs_begin_impl_frame());
824 scheduler->SetNeedsRedraw();
825 EXPECT_TRUE(scheduler->RedrawPending());
826 EXPECT_EQ(0, client.num_draws());
827 EXPECT_TRUE(client.needs_begin_impl_frame());
829 client.SetNeedsCommitOnNextDraw();
830 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
831 client.SetNeedsCommitOnNextDraw();
832 scheduler->OnBeginImplFrameDeadline();
833 EXPECT_EQ(1, client.num_draws());
834 EXPECT_TRUE(scheduler->CommitPending());
835 EXPECT_TRUE(client.needs_begin_impl_frame());
836 scheduler->FinishCommit();
838 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
839 scheduler->OnBeginImplFrameDeadline();
840 EXPECT_EQ(2, client.num_draws());
842 EXPECT_FALSE(scheduler->RedrawPending());
843 EXPECT_FALSE(scheduler->CommitPending());
844 EXPECT_TRUE(client.needs_begin_impl_frame());
846 // We stop requesting BeginImplFrames after a BeginImplFrame where we don't
848 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
849 scheduler->OnBeginImplFrameDeadline();
850 EXPECT_EQ(2, client.num_draws());
851 EXPECT_FALSE(scheduler->RedrawPending());
852 EXPECT_FALSE(scheduler->CommitPending());
853 EXPECT_FALSE(client.needs_begin_impl_frame());
856 // Tests that when a draw fails then the pending commit should not be dropped.
857 TEST(SchedulerTest, RequestCommitInsideFailedDraw) {
858 SchedulerClientThatsetNeedsDrawInsideDraw client;
859 SchedulerSettings default_scheduler_settings;
860 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
861 scheduler->SetCanStart();
862 scheduler->SetVisible(true);
863 scheduler->SetCanDraw(true);
864 InitializeOutputSurfaceAndFirstCommit(scheduler);
867 client.SetDrawWillHappen(false);
869 scheduler->SetNeedsRedraw();
870 EXPECT_TRUE(scheduler->RedrawPending());
871 EXPECT_TRUE(client.needs_begin_impl_frame());
872 EXPECT_EQ(0, client.num_draws());
875 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
876 scheduler->OnBeginImplFrameDeadline();
877 EXPECT_EQ(1, client.num_draws());
879 // We have a commit pending and the draw failed, and we didn't lose the commit
881 EXPECT_TRUE(scheduler->CommitPending());
882 EXPECT_TRUE(scheduler->RedrawPending());
883 EXPECT_TRUE(client.needs_begin_impl_frame());
885 // Fail the draw again.
886 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
887 scheduler->OnBeginImplFrameDeadline();
888 EXPECT_EQ(2, client.num_draws());
889 EXPECT_TRUE(scheduler->CommitPending());
890 EXPECT_TRUE(scheduler->RedrawPending());
891 EXPECT_TRUE(client.needs_begin_impl_frame());
893 // Draw successfully.
894 client.SetDrawWillHappen(true);
895 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
896 scheduler->OnBeginImplFrameDeadline();
897 EXPECT_EQ(3, client.num_draws());
898 EXPECT_TRUE(scheduler->CommitPending());
899 EXPECT_FALSE(scheduler->RedrawPending());
900 EXPECT_TRUE(client.needs_begin_impl_frame());
903 TEST(SchedulerTest, NoSwapWhenDrawFails) {
904 SchedulerClientThatSetNeedsCommitInsideDraw client;
905 SchedulerSettings default_scheduler_settings;
906 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
907 scheduler->SetCanStart();
908 scheduler->SetVisible(true);
909 scheduler->SetCanDraw(true);
910 InitializeOutputSurfaceAndFirstCommit(scheduler);
913 scheduler->SetNeedsRedraw();
914 EXPECT_TRUE(scheduler->RedrawPending());
915 EXPECT_TRUE(client.needs_begin_impl_frame());
916 EXPECT_EQ(0, client.num_draws());
918 // Draw successfully, this starts a new frame.
919 client.SetNeedsCommitOnNextDraw();
920 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
921 scheduler->OnBeginImplFrameDeadline();
922 EXPECT_EQ(1, client.num_draws());
924 scheduler->SetNeedsRedraw();
925 EXPECT_TRUE(scheduler->RedrawPending());
926 EXPECT_TRUE(client.needs_begin_impl_frame());
928 // Fail to draw, this should not start a frame.
929 client.SetDrawWillHappen(false);
930 client.SetNeedsCommitOnNextDraw();
931 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
932 scheduler->OnBeginImplFrameDeadline();
933 EXPECT_EQ(2, client.num_draws());
936 TEST(SchedulerTest, NoSwapWhenSwapFailsDuringForcedCommit) {
937 FakeSchedulerClient client;
938 SchedulerSettings default_scheduler_settings;
939 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
941 // Tell the client that it will fail to swap.
942 client.SetDrawWillHappen(true);
943 client.SetSwapWillHappenIfDrawHappens(false);
945 // Get the compositor to do a ScheduledActionDrawAndReadback.
946 scheduler->SetCanDraw(true);
947 scheduler->SetNeedsRedraw();
948 scheduler->SetNeedsForcedCommitForReadback();
949 scheduler->FinishCommit();
950 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
953 TEST(SchedulerTest, BackToBackReadbackAllowed) {
954 // Some clients call readbacks twice in a row before the replacement
955 // commit comes in. Make sure it is allowed.
956 FakeSchedulerClient client;
957 SchedulerSettings default_scheduler_settings;
958 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
960 // Get the compositor to do 2 ScheduledActionDrawAndReadbacks before
961 // the replacement commit comes in.
962 scheduler->SetCanDraw(true);
963 scheduler->SetNeedsRedraw();
964 scheduler->SetNeedsForcedCommitForReadback();
965 scheduler->FinishCommit();
966 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
969 scheduler->SetNeedsForcedCommitForReadback();
970 scheduler->FinishCommit();
971 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
973 // The replacement commit comes in after 2 readbacks.
975 scheduler->FinishCommit();
979 class SchedulerClientNeedsManageTilesInDraw : public FakeSchedulerClient {
981 virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
983 scheduler_->SetNeedsManageTiles();
984 return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
988 // Test manage tiles is independant of draws.
989 TEST(SchedulerTest, ManageTiles) {
990 SchedulerClientNeedsManageTilesInDraw client;
991 SchedulerSettings default_scheduler_settings;
992 Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
993 scheduler->SetCanStart();
994 scheduler->SetVisible(true);
995 scheduler->SetCanDraw(true);
996 InitializeOutputSurfaceAndFirstCommit(scheduler);
998 // Request both draw and manage tiles. ManageTiles shouldn't
999 // be trigged until BeginImplFrame.
1001 scheduler->SetNeedsManageTiles();
1002 scheduler->SetNeedsRedraw();
1003 EXPECT_TRUE(scheduler->RedrawPending());
1004 EXPECT_TRUE(scheduler->ManageTilesPending());
1005 EXPECT_TRUE(client.needs_begin_impl_frame());
1006 EXPECT_EQ(0, client.num_draws());
1007 EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
1008 EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1010 // We have no immediate actions to perform, so the BeginImplFrame should post
1011 // the deadline task.
1013 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1014 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1016 // On the deadline, he actions should have occured in the right order.
1018 scheduler->OnBeginImplFrameDeadline();
1019 EXPECT_EQ(1, client.num_draws());
1020 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1021 EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
1022 EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
1023 client.ActionIndex("ScheduledActionManageTiles"));
1024 EXPECT_FALSE(scheduler->RedrawPending());
1025 EXPECT_FALSE(scheduler->ManageTilesPending());
1027 // Request a draw. We don't need a ManageTiles yet.
1029 scheduler->SetNeedsRedraw();
1030 EXPECT_TRUE(scheduler->RedrawPending());
1031 EXPECT_FALSE(scheduler->ManageTilesPending());
1032 EXPECT_TRUE(client.needs_begin_impl_frame());
1033 EXPECT_EQ(0, client.num_draws());
1035 // We have no immediate actions to perform, so the BeginImplFrame should post
1036 // the deadline task.
1038 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1039 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1041 // Draw. The draw will trigger SetNeedsManageTiles, and
1042 // then the ManageTiles action will be triggered after the Draw.
1043 // Afterwards, neither a draw nor ManageTiles are pending.
1045 scheduler->OnBeginImplFrameDeadline();
1046 EXPECT_EQ(1, client.num_draws());
1047 EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1048 EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
1049 EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
1050 client.ActionIndex("ScheduledActionManageTiles"));
1051 EXPECT_FALSE(scheduler->RedrawPending());
1052 EXPECT_FALSE(scheduler->ManageTilesPending());
1054 // We need a BeginImplFrame where we don't swap to go idle.
1056 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1057 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1059 scheduler->OnBeginImplFrameDeadline();
1060 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);;
1061 EXPECT_EQ(0, client.num_draws());
1063 // Now trigger a ManageTiles outside of a draw. We will then need
1064 // a begin-frame for the ManageTiles, but we don't need a draw.
1066 EXPECT_FALSE(client.needs_begin_impl_frame());
1067 scheduler->SetNeedsManageTiles();
1068 EXPECT_TRUE(client.needs_begin_impl_frame());
1069 EXPECT_TRUE(scheduler->ManageTilesPending());
1070 EXPECT_FALSE(scheduler->RedrawPending());
1072 // BeginImplFrame. There will be no draw, only ManageTiles.
1074 scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1075 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1077 scheduler->OnBeginImplFrameDeadline();
1078 EXPECT_EQ(0, client.num_draws());
1079 EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1080 EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));