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