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/test/test_simple_task_runner.h"
14 #include "base/time/time.h"
15 #include "cc/test/scheduler_test_common.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
19 #define EXPECT_ACTION(action, client, action_index, expected_num_actions) \
20 EXPECT_EQ(expected_num_actions, client.num_actions_()); \
21 ASSERT_LT(action_index, client.num_actions_()); \
23 EXPECT_STREQ(action, client.Action(action_index)); \
24 for (int i = expected_num_actions; i < client.num_actions_(); ++i) \
25 ADD_FAILURE() << "Unexpected action: " << client.Action(i) << \
26 " with state:\n" << client.StateForAction(action_index); \
29 #define EXPECT_SINGLE_ACTION(action, client) \
30 EXPECT_ACTION(action, client, 0, 1)
35 class FakeSchedulerClient
;
37 void InitializeOutputSurfaceAndFirstCommit(Scheduler
* scheduler
,
38 FakeSchedulerClient
* client
);
40 class FakeSchedulerClient
: public SchedulerClient
{
42 FakeSchedulerClient() : needs_begin_frame_(false), automatic_swap_ack_(true) {
49 draw_will_happen_
= true;
50 swap_will_happen_if_draw_happens_
= true;
52 log_anticipated_draw_time_change_
= false;
55 Scheduler
* CreateScheduler(const SchedulerSettings
& settings
) {
56 task_runner_
= new base::TestSimpleTaskRunner
;
57 scheduler_
= Scheduler::Create(this, settings
, 0, task_runner_
);
58 return scheduler_
.get();
61 // Most tests don't care about DidAnticipatedDrawTimeChange, so only record it
63 void set_log_anticipated_draw_time_change(bool log
) {
64 log_anticipated_draw_time_change_
= log
;
66 bool needs_begin_frame() { return needs_begin_frame_
; }
67 int num_draws() const { return num_draws_
; }
68 int num_actions_() const { return static_cast<int>(actions_
.size()); }
69 const char* Action(int i
) const { return actions_
[i
]; }
70 base::Value
& StateForAction(int i
) const { return *states_
[i
]; }
71 base::TimeTicks
posted_begin_impl_frame_deadline() const {
72 return posted_begin_impl_frame_deadline_
;
75 base::TestSimpleTaskRunner
& task_runner() { return *task_runner_
; }
77 int ActionIndex(const char* action
) const {
78 for (size_t i
= 0; i
< actions_
.size(); i
++)
79 if (!strcmp(actions_
[i
], action
))
84 bool HasAction(const char* action
) const {
85 return ActionIndex(action
) >= 0;
88 void SetDrawWillHappen(bool draw_will_happen
) {
89 draw_will_happen_
= draw_will_happen
;
91 void SetSwapWillHappenIfDrawHappens(bool swap_will_happen_if_draw_happens
) {
92 swap_will_happen_if_draw_happens_
= swap_will_happen_if_draw_happens
;
94 void SetAutomaticSwapAck(bool automatic_swap_ack
) {
95 automatic_swap_ack_
= automatic_swap_ack
;
98 // SchedulerClient implementation.
99 virtual void SetNeedsBeginFrame(bool enable
) OVERRIDE
{
100 actions_
.push_back("SetNeedsBeginFrame");
101 states_
.push_back(scheduler_
->StateAsValue().release());
102 needs_begin_frame_
= enable
;
104 virtual void WillBeginImplFrame(const BeginFrameArgs
& args
) OVERRIDE
{
105 actions_
.push_back("WillBeginImplFrame");
106 states_
.push_back(scheduler_
->StateAsValue().release());
108 virtual void ScheduledActionSendBeginMainFrame() OVERRIDE
{
109 actions_
.push_back("ScheduledActionSendBeginMainFrame");
110 states_
.push_back(scheduler_
->StateAsValue().release());
112 virtual void ScheduledActionAnimate() OVERRIDE
{
113 actions_
.push_back("ScheduledActionAnimate");
114 states_
.push_back(scheduler_
->StateAsValue().release());
116 virtual DrawSwapReadbackResult
ScheduledActionDrawAndSwapIfPossible()
118 actions_
.push_back("ScheduledActionDrawAndSwapIfPossible");
119 states_
.push_back(scheduler_
->StateAsValue().release());
121 bool did_readback
= false;
122 DrawSwapReadbackResult::DrawResult result
=
124 ? DrawSwapReadbackResult::DRAW_SUCCESS
125 : DrawSwapReadbackResult::DRAW_ABORTED_CHECKERBOARD_ANIMATIONS
;
126 bool swap_will_happen
=
127 draw_will_happen_
&& swap_will_happen_if_draw_happens_
;
128 if (swap_will_happen
) {
129 scheduler_
->DidSwapBuffers();
130 if (automatic_swap_ack_
)
131 scheduler_
->DidSwapBuffersComplete();
133 return DrawSwapReadbackResult(
135 draw_will_happen_
&& swap_will_happen_if_draw_happens_
,
138 virtual DrawSwapReadbackResult
ScheduledActionDrawAndSwapForced() OVERRIDE
{
139 actions_
.push_back("ScheduledActionDrawAndSwapForced");
140 states_
.push_back(scheduler_
->StateAsValue().release());
141 bool did_request_swap
= swap_will_happen_if_draw_happens_
;
142 bool did_readback
= false;
143 return DrawSwapReadbackResult(
144 DrawSwapReadbackResult::DRAW_SUCCESS
, did_request_swap
, did_readback
);
146 virtual DrawSwapReadbackResult
ScheduledActionDrawAndReadback() OVERRIDE
{
147 actions_
.push_back("ScheduledActionDrawAndReadback");
148 states_
.push_back(scheduler_
->StateAsValue().release());
149 bool did_request_swap
= false;
150 bool did_readback
= true;
151 return DrawSwapReadbackResult(
152 DrawSwapReadbackResult::DRAW_SUCCESS
, did_request_swap
, did_readback
);
154 virtual void ScheduledActionCommit() OVERRIDE
{
155 actions_
.push_back("ScheduledActionCommit");
156 states_
.push_back(scheduler_
->StateAsValue().release());
158 virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE
{
159 actions_
.push_back("ScheduledActionUpdateVisibleTiles");
160 states_
.push_back(scheduler_
->StateAsValue().release());
162 virtual void ScheduledActionActivatePendingTree() OVERRIDE
{
163 actions_
.push_back("ScheduledActionActivatePendingTree");
164 states_
.push_back(scheduler_
->StateAsValue().release());
166 virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE
{
167 actions_
.push_back("ScheduledActionBeginOutputSurfaceCreation");
168 states_
.push_back(scheduler_
->StateAsValue().release());
170 virtual void ScheduledActionManageTiles() OVERRIDE
{
171 actions_
.push_back("ScheduledActionManageTiles");
172 states_
.push_back(scheduler_
->StateAsValue().release());
174 virtual void DidAnticipatedDrawTimeChange(base::TimeTicks
) OVERRIDE
{
175 if (log_anticipated_draw_time_change_
)
176 actions_
.push_back("DidAnticipatedDrawTimeChange");
178 virtual base::TimeDelta
DrawDurationEstimate() OVERRIDE
{
179 return base::TimeDelta();
181 virtual base::TimeDelta
BeginMainFrameToCommitDurationEstimate() OVERRIDE
{
182 return base::TimeDelta();
184 virtual base::TimeDelta
CommitToActivateDurationEstimate() OVERRIDE
{
185 return base::TimeDelta();
188 virtual void DidBeginImplFrameDeadline() OVERRIDE
{}
191 bool needs_begin_frame_
;
192 bool draw_will_happen_
;
193 bool swap_will_happen_if_draw_happens_
;
194 bool automatic_swap_ack_
;
196 bool log_anticipated_draw_time_change_
;
197 base::TimeTicks posted_begin_impl_frame_deadline_
;
198 std::vector
<const char*> actions_
;
199 ScopedVector
<base::Value
> states_
;
200 scoped_ptr
<Scheduler
> scheduler_
;
201 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner_
;
204 void InitializeOutputSurfaceAndFirstCommit(Scheduler
* scheduler
,
205 FakeSchedulerClient
* client
) {
206 bool client_initiates_begin_frame
=
207 scheduler
->settings().begin_frame_scheduling_enabled
&&
208 scheduler
->settings().throttle_frame_production
;
210 scheduler
->DidCreateAndInitializeOutputSurface();
211 scheduler
->SetNeedsCommit();
212 scheduler
->NotifyBeginMainFrameStarted();
213 scheduler
->NotifyReadyToCommit();
214 // Go through the motions to draw the commit.
215 if (client_initiates_begin_frame
)
216 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
218 client
->task_runner().RunPendingTasks(); // Run posted BeginFrame.
220 // Run the posted deadline task.
221 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
222 client
->task_runner().RunPendingTasks();
223 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
225 // We need another BeginImplFrame so Scheduler calls
226 // SetNeedsBeginFrame(false).
227 if (client_initiates_begin_frame
)
228 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
230 client
->task_runner().RunPendingTasks(); // Run posted BeginFrame.
232 // Run the posted deadline task.
233 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
234 client
->task_runner().RunPendingTasks();
235 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
238 TEST(SchedulerTest
, InitializeOutputSurfaceDoesNotBeginImplFrame
) {
239 FakeSchedulerClient client
;
240 SchedulerSettings default_scheduler_settings
;
241 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
242 scheduler
->SetCanStart();
243 scheduler
->SetVisible(true);
244 scheduler
->SetCanDraw(true);
246 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client
);
248 scheduler
->DidCreateAndInitializeOutputSurface();
249 EXPECT_EQ(0, client
.num_actions_());
252 TEST(SchedulerTest
, RequestCommit
) {
253 FakeSchedulerClient client
;
254 SchedulerSettings scheduler_settings
;
255 Scheduler
* scheduler
= client
.CreateScheduler(scheduler_settings
);
256 scheduler
->SetCanStart();
257 scheduler
->SetVisible(true);
258 scheduler
->SetCanDraw(true);
260 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client
);
261 InitializeOutputSurfaceAndFirstCommit(scheduler
, &client
);
263 // SetNeedsCommit should begin the frame on the next BeginImplFrame.
265 scheduler
->SetNeedsCommit();
266 EXPECT_TRUE(client
.needs_begin_frame());
267 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client
);
270 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
271 EXPECT_ACTION("WillBeginImplFrame", client
, 0, 2);
272 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client
, 1, 2);
273 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
274 EXPECT_TRUE(client
.needs_begin_frame());
277 // If we don't swap on the deadline, we wait for the next BeginFrame.
278 client
.task_runner().RunPendingTasks(); // Run posted deadline.
279 EXPECT_EQ(0, client
.num_actions_());
280 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
281 EXPECT_TRUE(client
.needs_begin_frame());
284 // NotifyReadyToCommit should trigger the commit.
285 scheduler
->NotifyBeginMainFrameStarted();
286 scheduler
->NotifyReadyToCommit();
287 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client
);
288 EXPECT_TRUE(client
.needs_begin_frame());
291 // BeginImplFrame should prepare the draw.
292 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
293 EXPECT_ACTION("WillBeginImplFrame", client
, 0, 2);
294 EXPECT_ACTION("ScheduledActionAnimate", client
, 1, 2);
295 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
296 EXPECT_TRUE(client
.needs_begin_frame());
299 // BeginImplFrame deadline should draw.
300 client
.task_runner().RunPendingTasks(); // Run posted deadline.
301 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client
, 0, 1);
302 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
303 EXPECT_TRUE(client
.needs_begin_frame());
306 // The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
307 // to avoid excessive toggles.
308 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
309 EXPECT_SINGLE_ACTION("WillBeginImplFrame", client
);
310 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
313 client
.task_runner().RunPendingTasks(); // Run posted deadline.
314 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client
);
315 EXPECT_FALSE(client
.needs_begin_frame());
319 TEST(SchedulerTest
, RequestCommitAfterBeginMainFrameSent
) {
320 FakeSchedulerClient client
;
321 SchedulerSettings scheduler_settings
;
322 Scheduler
* scheduler
= client
.CreateScheduler(scheduler_settings
);
323 scheduler
->SetCanStart();
324 scheduler
->SetVisible(true);
325 scheduler
->SetCanDraw(true);
327 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client
);
328 InitializeOutputSurfaceAndFirstCommit(scheduler
, &client
);
331 // SetNeedsCommit should begin the frame.
332 scheduler
->SetNeedsCommit();
333 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client
);
336 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
337 EXPECT_ACTION("WillBeginImplFrame", client
, 0, 2);
338 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client
, 1, 2);
339 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
341 EXPECT_TRUE(client
.needs_begin_frame());
344 // Now SetNeedsCommit again. Calling here means we need a second commit.
345 scheduler
->SetNeedsCommit();
346 EXPECT_EQ(client
.num_actions_(), 0);
349 // Finish the first commit.
350 scheduler
->NotifyBeginMainFrameStarted();
351 scheduler
->NotifyReadyToCommit();
352 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client
);
353 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
355 client
.task_runner().RunPendingTasks(); // Run posted deadline.
356 EXPECT_ACTION("ScheduledActionAnimate", client
, 0, 2);
357 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client
, 1, 2);
358 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
360 // Because we just swapped, the Scheduler should also request the next
361 // BeginImplFrame from the OutputSurface.
362 EXPECT_TRUE(client
.needs_begin_frame());
364 // Since another commit is needed, the next BeginImplFrame should initiate
365 // the second commit.
366 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
367 EXPECT_ACTION("WillBeginImplFrame", client
, 0, 2);
368 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client
, 1, 2);
369 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
372 // Finishing the commit before the deadline should post a new deadline task
373 // to trigger the deadline early.
374 scheduler
->NotifyBeginMainFrameStarted();
375 scheduler
->NotifyReadyToCommit();
376 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client
);
377 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
379 client
.task_runner().RunPendingTasks(); // Run posted deadline.
380 EXPECT_ACTION("ScheduledActionAnimate", client
, 0, 2);
381 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client
, 1, 2);
382 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
383 EXPECT_TRUE(client
.needs_begin_frame());
386 // On the next BeginImplFrame, verify we go back to a quiescent state and
387 // no longer request BeginImplFrames.
388 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
389 client
.task_runner().RunPendingTasks(); // Run posted deadline.
390 EXPECT_FALSE(client
.needs_begin_frame());
394 class SchedulerClientThatsetNeedsDrawInsideDraw
: public FakeSchedulerClient
{
396 virtual void ScheduledActionSendBeginMainFrame() OVERRIDE
{}
397 virtual DrawSwapReadbackResult
ScheduledActionDrawAndSwapIfPossible()
399 // Only SetNeedsRedraw the first time this is called
401 scheduler_
->SetNeedsRedraw();
402 return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
405 virtual DrawSwapReadbackResult
ScheduledActionDrawAndSwapForced() OVERRIDE
{
407 bool did_request_swap
= true;
408 bool did_readback
= false;
409 return DrawSwapReadbackResult(
410 DrawSwapReadbackResult::DRAW_SUCCESS
, did_request_swap
, did_readback
);
413 virtual void ScheduledActionCommit() OVERRIDE
{}
414 virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE
{}
415 virtual void DidAnticipatedDrawTimeChange(base::TimeTicks
) OVERRIDE
{}
418 // Tests for two different situations:
419 // 1. the scheduler dropping SetNeedsRedraw requests that happen inside
420 // a ScheduledActionDrawAndSwap
421 // 2. the scheduler drawing twice inside a single tick
422 TEST(SchedulerTest
, RequestRedrawInsideDraw
) {
423 SchedulerClientThatsetNeedsDrawInsideDraw client
;
424 SchedulerSettings default_scheduler_settings
;
425 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
426 scheduler
->SetCanStart();
427 scheduler
->SetVisible(true);
428 scheduler
->SetCanDraw(true);
429 InitializeOutputSurfaceAndFirstCommit(scheduler
, &client
);
432 scheduler
->SetNeedsRedraw();
433 EXPECT_TRUE(scheduler
->RedrawPending());
434 EXPECT_TRUE(client
.needs_begin_frame());
435 EXPECT_EQ(0, client
.num_draws());
437 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
438 client
.task_runner().RunPendingTasks(); // Run posted deadline.
439 EXPECT_EQ(1, client
.num_draws());
440 EXPECT_TRUE(scheduler
->RedrawPending());
441 EXPECT_TRUE(client
.needs_begin_frame());
443 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
444 client
.task_runner().RunPendingTasks(); // Run posted deadline.
445 EXPECT_EQ(2, client
.num_draws());
446 EXPECT_FALSE(scheduler
->RedrawPending());
447 EXPECT_TRUE(client
.needs_begin_frame());
449 // We stop requesting BeginImplFrames after a BeginImplFrame where we don't
451 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
452 client
.task_runner().RunPendingTasks(); // Run posted deadline.
453 EXPECT_EQ(2, client
.num_draws());
454 EXPECT_FALSE(scheduler
->RedrawPending());
455 EXPECT_FALSE(client
.needs_begin_frame());
458 // Test that requesting redraw inside a failed draw doesn't lose the request.
459 TEST(SchedulerTest
, RequestRedrawInsideFailedDraw
) {
460 SchedulerClientThatsetNeedsDrawInsideDraw client
;
461 SchedulerSettings default_scheduler_settings
;
462 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
463 scheduler
->SetCanStart();
464 scheduler
->SetVisible(true);
465 scheduler
->SetCanDraw(true);
466 InitializeOutputSurfaceAndFirstCommit(scheduler
, &client
);
469 client
.SetDrawWillHappen(false);
471 scheduler
->SetNeedsRedraw();
472 EXPECT_TRUE(scheduler
->RedrawPending());
473 EXPECT_TRUE(client
.needs_begin_frame());
474 EXPECT_EQ(0, client
.num_draws());
477 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
478 client
.task_runner().RunPendingTasks(); // Run posted deadline.
479 EXPECT_EQ(1, client
.num_draws());
481 // We have a commit pending and the draw failed, and we didn't lose the redraw
483 EXPECT_TRUE(scheduler
->CommitPending());
484 EXPECT_TRUE(scheduler
->RedrawPending());
485 EXPECT_TRUE(client
.needs_begin_frame());
487 // Fail the draw again.
488 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
489 client
.task_runner().RunPendingTasks(); // Run posted deadline.
490 EXPECT_EQ(2, client
.num_draws());
491 EXPECT_TRUE(scheduler
->CommitPending());
492 EXPECT_TRUE(scheduler
->RedrawPending());
493 EXPECT_TRUE(client
.needs_begin_frame());
495 // Draw successfully.
496 client
.SetDrawWillHappen(true);
497 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
498 client
.task_runner().RunPendingTasks(); // Run posted deadline.
499 EXPECT_EQ(3, client
.num_draws());
500 EXPECT_TRUE(scheduler
->CommitPending());
501 EXPECT_FALSE(scheduler
->RedrawPending());
502 EXPECT_TRUE(client
.needs_begin_frame());
505 class SchedulerClientThatSetNeedsCommitInsideDraw
: public FakeSchedulerClient
{
507 SchedulerClientThatSetNeedsCommitInsideDraw()
508 : set_needs_commit_on_next_draw_(false) {}
510 virtual void ScheduledActionSendBeginMainFrame() OVERRIDE
{}
511 virtual DrawSwapReadbackResult
ScheduledActionDrawAndSwapIfPossible()
513 // Only SetNeedsCommit the first time this is called
514 if (set_needs_commit_on_next_draw_
) {
515 scheduler_
->SetNeedsCommit();
516 set_needs_commit_on_next_draw_
= false;
518 return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
521 virtual DrawSwapReadbackResult
ScheduledActionDrawAndSwapForced() OVERRIDE
{
523 bool did_request_swap
= false;
524 bool did_readback
= false;
525 return DrawSwapReadbackResult(
526 DrawSwapReadbackResult::DRAW_SUCCESS
, did_request_swap
, did_readback
);
529 virtual void ScheduledActionCommit() OVERRIDE
{}
530 virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE
{}
531 virtual void DidAnticipatedDrawTimeChange(base::TimeTicks
) OVERRIDE
{}
533 void SetNeedsCommitOnNextDraw() { set_needs_commit_on_next_draw_
= true; }
536 bool set_needs_commit_on_next_draw_
;
539 // Tests for the scheduler infinite-looping on SetNeedsCommit requests that
540 // happen inside a ScheduledActionDrawAndSwap
541 TEST(SchedulerTest
, RequestCommitInsideDraw
) {
542 SchedulerClientThatSetNeedsCommitInsideDraw client
;
543 SchedulerSettings default_scheduler_settings
;
544 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
545 scheduler
->SetCanStart();
546 scheduler
->SetVisible(true);
547 scheduler
->SetCanDraw(true);
548 InitializeOutputSurfaceAndFirstCommit(scheduler
, &client
);
551 EXPECT_FALSE(client
.needs_begin_frame());
552 scheduler
->SetNeedsRedraw();
553 EXPECT_TRUE(scheduler
->RedrawPending());
554 EXPECT_EQ(0, client
.num_draws());
555 EXPECT_TRUE(client
.needs_begin_frame());
557 client
.SetNeedsCommitOnNextDraw();
558 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
559 client
.SetNeedsCommitOnNextDraw();
560 client
.task_runner().RunPendingTasks(); // Run posted deadline.
561 EXPECT_EQ(1, client
.num_draws());
562 EXPECT_TRUE(scheduler
->CommitPending());
563 EXPECT_TRUE(client
.needs_begin_frame());
564 scheduler
->NotifyBeginMainFrameStarted();
565 scheduler
->NotifyReadyToCommit();
567 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
568 client
.task_runner().RunPendingTasks(); // Run posted deadline.
569 EXPECT_EQ(2, client
.num_draws());
571 EXPECT_FALSE(scheduler
->RedrawPending());
572 EXPECT_FALSE(scheduler
->CommitPending());
573 EXPECT_TRUE(client
.needs_begin_frame());
575 // We stop requesting BeginImplFrames after a BeginImplFrame where we don't
577 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
578 client
.task_runner().RunPendingTasks(); // Run posted deadline.
579 EXPECT_EQ(2, client
.num_draws());
580 EXPECT_FALSE(scheduler
->RedrawPending());
581 EXPECT_FALSE(scheduler
->CommitPending());
582 EXPECT_FALSE(client
.needs_begin_frame());
585 // Tests that when a draw fails then the pending commit should not be dropped.
586 TEST(SchedulerTest
, RequestCommitInsideFailedDraw
) {
587 SchedulerClientThatsetNeedsDrawInsideDraw client
;
588 SchedulerSettings default_scheduler_settings
;
589 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
590 scheduler
->SetCanStart();
591 scheduler
->SetVisible(true);
592 scheduler
->SetCanDraw(true);
593 InitializeOutputSurfaceAndFirstCommit(scheduler
, &client
);
596 client
.SetDrawWillHappen(false);
598 scheduler
->SetNeedsRedraw();
599 EXPECT_TRUE(scheduler
->RedrawPending());
600 EXPECT_TRUE(client
.needs_begin_frame());
601 EXPECT_EQ(0, client
.num_draws());
604 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
605 client
.task_runner().RunPendingTasks(); // Run posted deadline.
606 EXPECT_EQ(1, client
.num_draws());
608 // We have a commit pending and the draw failed, and we didn't lose the commit
610 EXPECT_TRUE(scheduler
->CommitPending());
611 EXPECT_TRUE(scheduler
->RedrawPending());
612 EXPECT_TRUE(client
.needs_begin_frame());
614 // Fail the draw again.
615 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
617 client
.task_runner().RunPendingTasks(); // Run posted deadline.
618 EXPECT_EQ(2, client
.num_draws());
619 EXPECT_TRUE(scheduler
->CommitPending());
620 EXPECT_TRUE(scheduler
->RedrawPending());
621 EXPECT_TRUE(client
.needs_begin_frame());
623 // Draw successfully.
624 client
.SetDrawWillHappen(true);
625 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
626 client
.task_runner().RunPendingTasks(); // Run posted deadline.
627 EXPECT_EQ(3, client
.num_draws());
628 EXPECT_TRUE(scheduler
->CommitPending());
629 EXPECT_FALSE(scheduler
->RedrawPending());
630 EXPECT_TRUE(client
.needs_begin_frame());
633 TEST(SchedulerTest
, NoSwapWhenDrawFails
) {
634 SchedulerClientThatSetNeedsCommitInsideDraw client
;
635 SchedulerSettings default_scheduler_settings
;
636 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
637 scheduler
->SetCanStart();
638 scheduler
->SetVisible(true);
639 scheduler
->SetCanDraw(true);
640 InitializeOutputSurfaceAndFirstCommit(scheduler
, &client
);
643 scheduler
->SetNeedsRedraw();
644 EXPECT_TRUE(scheduler
->RedrawPending());
645 EXPECT_TRUE(client
.needs_begin_frame());
646 EXPECT_EQ(0, client
.num_draws());
648 // Draw successfully, this starts a new frame.
649 client
.SetNeedsCommitOnNextDraw();
650 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
651 client
.task_runner().RunPendingTasks(); // Run posted deadline.
652 EXPECT_EQ(1, client
.num_draws());
654 scheduler
->SetNeedsRedraw();
655 EXPECT_TRUE(scheduler
->RedrawPending());
656 EXPECT_TRUE(client
.needs_begin_frame());
658 // Fail to draw, this should not start a frame.
659 client
.SetDrawWillHappen(false);
660 client
.SetNeedsCommitOnNextDraw();
661 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
662 client
.task_runner().RunPendingTasks(); // Run posted deadline.
663 EXPECT_EQ(2, client
.num_draws());
666 TEST(SchedulerTest
, NoSwapWhenSwapFailsDuringForcedCommit
) {
667 FakeSchedulerClient client
;
668 SchedulerSettings default_scheduler_settings
;
669 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
671 // Tell the client that it will fail to swap.
672 client
.SetDrawWillHappen(true);
673 client
.SetSwapWillHappenIfDrawHappens(false);
675 // Get the compositor to do a ScheduledActionDrawAndReadback.
676 scheduler
->SetCanDraw(true);
677 scheduler
->SetNeedsRedraw();
678 scheduler
->SetNeedsForcedCommitForReadback();
679 scheduler
->NotifyBeginMainFrameStarted();
680 scheduler
->NotifyReadyToCommit();
681 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndReadback"));
684 TEST(SchedulerTest
, BackToBackReadbackAllowed
) {
685 // Some clients call readbacks twice in a row before the replacement
686 // commit comes in. Make sure it is allowed.
687 FakeSchedulerClient client
;
688 SchedulerSettings default_scheduler_settings
;
689 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
691 // Get the compositor to do 2 ScheduledActionDrawAndReadbacks before
692 // the replacement commit comes in.
693 scheduler
->SetCanDraw(true);
694 scheduler
->SetNeedsRedraw();
695 scheduler
->SetNeedsForcedCommitForReadback();
696 scheduler
->NotifyBeginMainFrameStarted();
697 scheduler
->NotifyReadyToCommit();
698 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndReadback"));
701 scheduler
->SetNeedsForcedCommitForReadback();
702 scheduler
->NotifyBeginMainFrameStarted();
703 scheduler
->NotifyReadyToCommit();
704 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndReadback"));
706 // The replacement commit comes in after 2 readbacks.
708 scheduler
->NotifyBeginMainFrameStarted();
709 scheduler
->NotifyReadyToCommit();
713 class SchedulerClientNeedsManageTilesInDraw
: public FakeSchedulerClient
{
715 virtual DrawSwapReadbackResult
ScheduledActionDrawAndSwapIfPossible()
717 scheduler_
->SetNeedsManageTiles();
718 return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
722 // Test manage tiles is independant of draws.
723 TEST(SchedulerTest
, ManageTiles
) {
724 SchedulerClientNeedsManageTilesInDraw client
;
725 SchedulerSettings default_scheduler_settings
;
726 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
727 scheduler
->SetCanStart();
728 scheduler
->SetVisible(true);
729 scheduler
->SetCanDraw(true);
730 InitializeOutputSurfaceAndFirstCommit(scheduler
, &client
);
732 // Request both draw and manage tiles. ManageTiles shouldn't
733 // be trigged until BeginImplFrame.
735 scheduler
->SetNeedsManageTiles();
736 scheduler
->SetNeedsRedraw();
737 EXPECT_TRUE(scheduler
->RedrawPending());
738 EXPECT_TRUE(scheduler
->ManageTilesPending());
739 EXPECT_TRUE(client
.needs_begin_frame());
740 EXPECT_EQ(0, client
.num_draws());
741 EXPECT_FALSE(client
.HasAction("ScheduledActionManageTiles"));
742 EXPECT_FALSE(client
.HasAction("ScheduledActionDrawAndSwapIfPossible"));
744 // We have no immediate actions to perform, so the BeginImplFrame should post
745 // the deadline task.
747 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
748 EXPECT_ACTION("WillBeginImplFrame", client
, 0, 2);
749 EXPECT_ACTION("ScheduledActionAnimate", client
, 1, 2);
750 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
752 // On the deadline, he actions should have occured in the right order.
754 client
.task_runner().RunPendingTasks(); // Run posted deadline.
755 EXPECT_EQ(1, client
.num_draws());
756 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndSwapIfPossible"));
757 EXPECT_TRUE(client
.HasAction("ScheduledActionManageTiles"));
758 EXPECT_LT(client
.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
759 client
.ActionIndex("ScheduledActionManageTiles"));
760 EXPECT_FALSE(scheduler
->RedrawPending());
761 EXPECT_FALSE(scheduler
->ManageTilesPending());
762 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
764 // Request a draw. We don't need a ManageTiles yet.
766 scheduler
->SetNeedsRedraw();
767 EXPECT_TRUE(scheduler
->RedrawPending());
768 EXPECT_FALSE(scheduler
->ManageTilesPending());
769 EXPECT_TRUE(client
.needs_begin_frame());
770 EXPECT_EQ(0, client
.num_draws());
772 // We have no immediate actions to perform, so the BeginImplFrame should post
773 // the deadline task.
775 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
776 EXPECT_ACTION("WillBeginImplFrame", client
, 0, 2);
777 EXPECT_ACTION("ScheduledActionAnimate", client
, 1, 2);
778 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
780 // Draw. The draw will trigger SetNeedsManageTiles, and
781 // then the ManageTiles action will be triggered after the Draw.
782 // Afterwards, neither a draw nor ManageTiles are pending.
784 client
.task_runner().RunPendingTasks(); // Run posted deadline.
785 EXPECT_EQ(1, client
.num_draws());
786 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndSwapIfPossible"));
787 EXPECT_TRUE(client
.HasAction("ScheduledActionManageTiles"));
788 EXPECT_LT(client
.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
789 client
.ActionIndex("ScheduledActionManageTiles"));
790 EXPECT_FALSE(scheduler
->RedrawPending());
791 EXPECT_FALSE(scheduler
->ManageTilesPending());
792 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
794 // We need a BeginImplFrame where we don't swap to go idle.
796 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
797 EXPECT_SINGLE_ACTION("WillBeginImplFrame", client
);
798 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
800 client
.task_runner().RunPendingTasks(); // Run posted deadline.
801 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client
);
802 EXPECT_FALSE(client
.needs_begin_frame());
803 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
804 EXPECT_EQ(0, client
.num_draws());
806 // Now trigger a ManageTiles outside of a draw. We will then need
807 // a begin-frame for the ManageTiles, but we don't need a draw.
809 EXPECT_FALSE(client
.needs_begin_frame());
810 scheduler
->SetNeedsManageTiles();
811 EXPECT_TRUE(client
.needs_begin_frame());
812 EXPECT_TRUE(scheduler
->ManageTilesPending());
813 EXPECT_FALSE(scheduler
->RedrawPending());
815 // BeginImplFrame. There will be no draw, only ManageTiles.
817 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
818 EXPECT_SINGLE_ACTION("WillBeginImplFrame", client
);
819 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
821 client
.task_runner().RunPendingTasks(); // Run posted deadline.
822 EXPECT_EQ(0, client
.num_draws());
823 EXPECT_FALSE(client
.HasAction("ScheduledActionDrawAndSwapIfPossible"));
824 EXPECT_TRUE(client
.HasAction("ScheduledActionManageTiles"));
825 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
828 // Test that ManageTiles only happens once per frame. If an external caller
829 // initiates it, then the state machine should not ManageTiles on that frame.
830 TEST(SchedulerTest
, ManageTilesOncePerFrame
) {
831 FakeSchedulerClient 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
, &client
);
839 // If DidManageTiles during a frame, then ManageTiles should not occur again.
840 scheduler
->SetNeedsManageTiles();
841 scheduler
->SetNeedsRedraw();
843 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
844 EXPECT_ACTION("WillBeginImplFrame", client
, 0, 2);
845 EXPECT_ACTION("ScheduledActionAnimate", client
, 1, 2);
846 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
848 EXPECT_TRUE(scheduler
->ManageTilesPending());
849 scheduler
->DidManageTiles(); // An explicit ManageTiles.
850 EXPECT_FALSE(scheduler
->ManageTilesPending());
853 client
.task_runner().RunPendingTasks(); // Run posted deadline.
854 EXPECT_EQ(1, client
.num_draws());
855 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndSwapIfPossible"));
856 EXPECT_FALSE(client
.HasAction("ScheduledActionManageTiles"));
857 EXPECT_FALSE(scheduler
->RedrawPending());
858 EXPECT_FALSE(scheduler
->ManageTilesPending());
859 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
861 // Next frame without DidManageTiles should ManageTiles with draw.
862 scheduler
->SetNeedsManageTiles();
863 scheduler
->SetNeedsRedraw();
865 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
866 EXPECT_ACTION("WillBeginImplFrame", client
, 0, 2);
867 EXPECT_ACTION("ScheduledActionAnimate", client
, 1, 2);
868 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
871 client
.task_runner().RunPendingTasks(); // Run posted deadline.
872 EXPECT_EQ(1, client
.num_draws());
873 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndSwapIfPossible"));
874 EXPECT_TRUE(client
.HasAction("ScheduledActionManageTiles"));
875 EXPECT_LT(client
.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
876 client
.ActionIndex("ScheduledActionManageTiles"));
877 EXPECT_FALSE(scheduler
->RedrawPending());
878 EXPECT_FALSE(scheduler
->ManageTilesPending());
879 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
880 scheduler
->DidManageTiles(); // Corresponds to ScheduledActionManageTiles
882 // If we get another DidManageTiles within the same frame, we should
883 // not ManageTiles on the next frame.
884 scheduler
->DidManageTiles(); // An explicit ManageTiles.
885 scheduler
->SetNeedsManageTiles();
886 scheduler
->SetNeedsRedraw();
888 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
889 EXPECT_ACTION("WillBeginImplFrame", client
, 0, 2);
890 EXPECT_ACTION("ScheduledActionAnimate", client
, 1, 2);
891 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
893 EXPECT_TRUE(scheduler
->ManageTilesPending());
896 client
.task_runner().RunPendingTasks(); // Run posted deadline.
897 EXPECT_EQ(1, client
.num_draws());
898 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndSwapIfPossible"));
899 EXPECT_FALSE(client
.HasAction("ScheduledActionManageTiles"));
900 EXPECT_FALSE(scheduler
->RedrawPending());
901 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
903 // If we get another DidManageTiles, we should not ManageTiles on the next
904 // frame. This verifies we don't alternate calling ManageTiles once and twice.
905 EXPECT_TRUE(scheduler
->ManageTilesPending());
906 scheduler
->DidManageTiles(); // An explicit ManageTiles.
907 EXPECT_FALSE(scheduler
->ManageTilesPending());
908 scheduler
->SetNeedsManageTiles();
909 scheduler
->SetNeedsRedraw();
911 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
912 EXPECT_ACTION("WillBeginImplFrame", client
, 0, 2);
913 EXPECT_ACTION("ScheduledActionAnimate", client
, 1, 2);
914 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
916 EXPECT_TRUE(scheduler
->ManageTilesPending());
919 client
.task_runner().RunPendingTasks(); // Run posted deadline.
920 EXPECT_EQ(1, client
.num_draws());
921 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndSwapIfPossible"));
922 EXPECT_FALSE(client
.HasAction("ScheduledActionManageTiles"));
923 EXPECT_FALSE(scheduler
->RedrawPending());
924 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
926 // Next frame without DidManageTiles should ManageTiles with draw.
927 scheduler
->SetNeedsManageTiles();
928 scheduler
->SetNeedsRedraw();
930 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
931 EXPECT_ACTION("WillBeginImplFrame", client
, 0, 2);
932 EXPECT_ACTION("ScheduledActionAnimate", client
, 1, 2);
933 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
936 client
.task_runner().RunPendingTasks(); // Run posted deadline.
937 EXPECT_EQ(1, client
.num_draws());
938 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndSwapIfPossible"));
939 EXPECT_TRUE(client
.HasAction("ScheduledActionManageTiles"));
940 EXPECT_LT(client
.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
941 client
.ActionIndex("ScheduledActionManageTiles"));
942 EXPECT_FALSE(scheduler
->RedrawPending());
943 EXPECT_FALSE(scheduler
->ManageTilesPending());
944 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
945 scheduler
->DidManageTiles(); // Corresponds to ScheduledActionManageTiles
948 TEST(SchedulerTest
, TriggerBeginFrameDeadlineEarly
) {
949 SchedulerClientNeedsManageTilesInDraw client
;
950 SchedulerSettings default_scheduler_settings
;
951 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
952 scheduler
->SetCanStart();
953 scheduler
->SetVisible(true);
954 scheduler
->SetCanDraw(true);
955 InitializeOutputSurfaceAndFirstCommit(scheduler
, &client
);
958 scheduler
->SetNeedsRedraw();
959 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
961 // The deadline should be zero since there is no work other than drawing
963 EXPECT_EQ(base::TimeTicks(), client
.posted_begin_impl_frame_deadline());
966 class SchedulerClientWithFixedEstimates
: public FakeSchedulerClient
{
968 SchedulerClientWithFixedEstimates(
969 base::TimeDelta draw_duration
,
970 base::TimeDelta begin_main_frame_to_commit_duration
,
971 base::TimeDelta commit_to_activate_duration
)
972 : draw_duration_(draw_duration
),
973 begin_main_frame_to_commit_duration_(
974 begin_main_frame_to_commit_duration
),
975 commit_to_activate_duration_(commit_to_activate_duration
) {}
977 virtual base::TimeDelta
DrawDurationEstimate() OVERRIDE
{
978 return draw_duration_
;
980 virtual base::TimeDelta
BeginMainFrameToCommitDurationEstimate() OVERRIDE
{
981 return begin_main_frame_to_commit_duration_
;
983 virtual base::TimeDelta
CommitToActivateDurationEstimate() OVERRIDE
{
984 return commit_to_activate_duration_
;
988 base::TimeDelta draw_duration_
;
989 base::TimeDelta begin_main_frame_to_commit_duration_
;
990 base::TimeDelta commit_to_activate_duration_
;
993 void MainFrameInHighLatencyMode(int64 begin_main_frame_to_commit_estimate_in_ms
,
994 int64 commit_to_activate_estimate_in_ms
,
995 bool smoothness_takes_priority
,
996 bool should_send_begin_main_frame
) {
997 // Set up client with specified estimates (draw duration is set to 1).
998 SchedulerClientWithFixedEstimates
client(
999 base::TimeDelta::FromMilliseconds(1),
1000 base::TimeDelta::FromMilliseconds(
1001 begin_main_frame_to_commit_estimate_in_ms
),
1002 base::TimeDelta::FromMilliseconds(commit_to_activate_estimate_in_ms
));
1003 SchedulerSettings default_scheduler_settings
;
1004 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
1005 scheduler
->SetCanStart();
1006 scheduler
->SetVisible(true);
1007 scheduler
->SetCanDraw(true);
1008 scheduler
->SetSmoothnessTakesPriority(smoothness_takes_priority
);
1009 InitializeOutputSurfaceAndFirstCommit(scheduler
, &client
);
1011 // Impl thread hits deadline before commit finishes.
1013 scheduler
->SetNeedsCommit();
1014 EXPECT_FALSE(scheduler
->MainThreadIsInHighLatencyMode());
1015 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
1016 EXPECT_FALSE(scheduler
->MainThreadIsInHighLatencyMode());
1017 client
.task_runner().RunPendingTasks(); // Run posted deadline.
1018 EXPECT_TRUE(scheduler
->MainThreadIsInHighLatencyMode());
1019 scheduler
->NotifyBeginMainFrameStarted();
1020 scheduler
->NotifyReadyToCommit();
1021 EXPECT_TRUE(scheduler
->MainThreadIsInHighLatencyMode());
1022 EXPECT_TRUE(client
.HasAction("ScheduledActionSendBeginMainFrame"));
1025 scheduler
->SetNeedsCommit();
1026 EXPECT_TRUE(scheduler
->MainThreadIsInHighLatencyMode());
1027 scheduler
->BeginFrame(BeginFrameArgs::CreateForTesting());
1028 EXPECT_TRUE(scheduler
->MainThreadIsInHighLatencyMode());
1029 client
.task_runner().RunPendingTasks(); // Run posted deadline.
1030 EXPECT_EQ(scheduler
->MainThreadIsInHighLatencyMode(),
1031 should_send_begin_main_frame
);
1032 EXPECT_EQ(client
.HasAction("ScheduledActionSendBeginMainFrame"),
1033 should_send_begin_main_frame
);
1037 SkipMainFrameIfHighLatencyAndCanCommitAndActivateBeforeDeadline
) {
1038 // Set up client so that estimates indicate that we can commit and activate
1039 // before the deadline (~8ms by default).
1040 MainFrameInHighLatencyMode(1, 1, false, false);
1043 TEST(SchedulerTest
, NotSkipMainFrameIfHighLatencyAndCanCommitTooLong
) {
1044 // Set up client so that estimates indicate that the commit cannot finish
1045 // before the deadline (~8ms by default).
1046 MainFrameInHighLatencyMode(10, 1, false, true);
1049 TEST(SchedulerTest
, NotSkipMainFrameIfHighLatencyAndCanActivateTooLong
) {
1050 // Set up client so that estimates indicate that the activate cannot finish
1051 // before the deadline (~8ms by default).
1052 MainFrameInHighLatencyMode(1, 10, false, true);
1055 TEST(SchedulerTest
, NotSkipMainFrameInPreferSmoothnessMode
) {
1056 // Set up client so that estimates indicate that we can commit and activate
1057 // before the deadline (~8ms by default), but also enable smoothness takes
1059 MainFrameInHighLatencyMode(1, 1, true, true);
1062 TEST(SchedulerTest
, PollForCommitCompletion
) {
1063 // Since we are simulating a long commit, set up a client with draw duration
1064 // estimates that prevent skipping main frames to get to low latency mode.
1065 SchedulerClientWithFixedEstimates
client(
1066 base::TimeDelta::FromMilliseconds(1),
1067 base::TimeDelta::FromMilliseconds(32),
1068 base::TimeDelta::FromMilliseconds(32));
1069 client
.set_log_anticipated_draw_time_change(true);
1070 SchedulerSettings default_scheduler_settings
;
1071 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
1073 scheduler
->SetCanDraw(true);
1074 scheduler
->SetCanStart();
1075 scheduler
->SetVisible(true);
1076 scheduler
->DidCreateAndInitializeOutputSurface();
1078 scheduler
->SetNeedsCommit();
1079 EXPECT_TRUE(scheduler
->CommitPending());
1080 scheduler
->NotifyBeginMainFrameStarted();
1081 scheduler
->NotifyReadyToCommit();
1082 scheduler
->SetNeedsRedraw();
1084 BeginFrameArgs frame_args
= BeginFrameArgs::CreateForTesting();
1085 frame_args
.interval
= base::TimeDelta::FromMilliseconds(1000);
1086 scheduler
->BeginFrame(frame_args
);
1088 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
1089 client
.task_runner().RunPendingTasks(); // Run posted deadline.
1090 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
1092 scheduler
->DidSwapBuffers();
1093 scheduler
->DidSwapBuffersComplete();
1095 // At this point, we've drawn a frame. Start another commit, but hold off on
1096 // the NotifyReadyToCommit for now.
1097 EXPECT_FALSE(scheduler
->CommitPending());
1098 scheduler
->SetNeedsCommit();
1099 scheduler
->BeginFrame(frame_args
);
1100 EXPECT_TRUE(scheduler
->CommitPending());
1102 // Draw and swap the frame, but don't ack the swap to simulate the Browser
1103 // blocking on the renderer.
1104 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
1105 client
.task_runner().RunPendingTasks(); // Run posted deadline.
1106 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
1107 scheduler
->DidSwapBuffers();
1109 // Spin the event loop a few times and make sure we get more
1110 // DidAnticipateDrawTimeChange calls every time.
1111 int actions_so_far
= client
.num_actions_();
1113 // Does three iterations to make sure that the timer is properly repeating.
1114 for (int i
= 0; i
< 3; ++i
) {
1115 EXPECT_EQ((frame_args
.interval
* 2).InMicroseconds(),
1116 client
.task_runner().NextPendingTaskDelay().InMicroseconds())
1117 << *scheduler
->StateAsValue();
1118 client
.task_runner().RunPendingTasks();
1119 EXPECT_GT(client
.num_actions_(), actions_so_far
);
1120 EXPECT_STREQ(client
.Action(client
.num_actions_() - 1),
1121 "DidAnticipatedDrawTimeChange");
1122 actions_so_far
= client
.num_actions_();
1125 // Do the same thing after BeginMainFrame starts but still before activation.
1126 scheduler
->NotifyBeginMainFrameStarted();
1127 for (int i
= 0; i
< 3; ++i
) {
1128 EXPECT_EQ((frame_args
.interval
* 2).InMicroseconds(),
1129 client
.task_runner().NextPendingTaskDelay().InMicroseconds())
1130 << *scheduler
->StateAsValue();
1131 client
.task_runner().RunPendingTasks();
1132 EXPECT_GT(client
.num_actions_(), actions_so_far
);
1133 EXPECT_STREQ(client
.Action(client
.num_actions_() - 1),
1134 "DidAnticipatedDrawTimeChange");
1135 actions_so_far
= client
.num_actions_();
1139 TEST(SchedulerTest
, BeginRetroFrame
) {
1140 FakeSchedulerClient client
;
1141 SchedulerSettings scheduler_settings
;
1142 Scheduler
* scheduler
= client
.CreateScheduler(scheduler_settings
);
1143 scheduler
->SetCanStart();
1144 scheduler
->SetVisible(true);
1145 scheduler
->SetCanDraw(true);
1146 InitializeOutputSurfaceAndFirstCommit(scheduler
, &client
);
1148 // SetNeedsCommit should begin the frame on the next BeginImplFrame.
1150 scheduler
->SetNeedsCommit();
1151 EXPECT_TRUE(client
.needs_begin_frame());
1152 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client
);
1155 // Create a BeginFrame with a long deadline to avoid race conditions.
1156 // This is the first BeginFrame, which will be handled immediately.
1157 BeginFrameArgs args
= BeginFrameArgs::CreateForTesting();
1158 args
.deadline
+= base::TimeDelta::FromHours(1);
1159 scheduler
->BeginFrame(args
);
1160 EXPECT_ACTION("WillBeginImplFrame", client
, 0, 2);
1161 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client
, 1, 2);
1162 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
1163 EXPECT_TRUE(client
.needs_begin_frame());
1166 // Queue BeginFrames while we are still handling the previous BeginFrame.
1167 args
.frame_time
+= base::TimeDelta::FromSeconds(1);
1168 scheduler
->BeginFrame(args
);
1169 args
.frame_time
+= base::TimeDelta::FromSeconds(1);
1170 scheduler
->BeginFrame(args
);
1172 // If we don't swap on the deadline, we wait for the next BeginImplFrame.
1173 client
.task_runner().RunPendingTasks(); // Run posted deadline.
1174 EXPECT_EQ(0, client
.num_actions_());
1175 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
1176 EXPECT_TRUE(client
.needs_begin_frame());
1179 // NotifyReadyToCommit should trigger the commit.
1180 scheduler
->NotifyBeginMainFrameStarted();
1181 scheduler
->NotifyReadyToCommit();
1182 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client
);
1183 EXPECT_TRUE(client
.needs_begin_frame());
1186 // BeginImplFrame should prepare the draw.
1187 client
.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
1188 EXPECT_ACTION("WillBeginImplFrame", client
, 0, 2);
1189 EXPECT_ACTION("ScheduledActionAnimate", client
, 1, 2);
1190 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
1191 EXPECT_TRUE(client
.needs_begin_frame());
1194 // BeginImplFrame deadline should draw.
1195 client
.task_runner().RunPendingTasks(); // Run posted deadline.
1196 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client
, 0, 1);
1197 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
1198 EXPECT_TRUE(client
.needs_begin_frame());
1201 // The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
1202 // to avoid excessive toggles.
1203 client
.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
1204 EXPECT_SINGLE_ACTION("WillBeginImplFrame", client
);
1205 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
1208 client
.task_runner().RunPendingTasks(); // Run posted deadline.
1209 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client
);
1210 EXPECT_FALSE(client
.needs_begin_frame());
1214 TEST(SchedulerTest
, BeginRetroFrame_SwapThrottled
) {
1215 FakeSchedulerClient client
;
1216 SchedulerSettings scheduler_settings
;
1217 Scheduler
* scheduler
= client
.CreateScheduler(scheduler_settings
);
1218 scheduler
->SetCanStart();
1219 scheduler
->SetVisible(true);
1220 scheduler
->SetCanDraw(true);
1221 InitializeOutputSurfaceAndFirstCommit(scheduler
, &client
);
1223 // To test swap ack throttling, this test disables automatic swap acks.
1224 scheduler
->SetMaxSwapsPending(1);
1225 client
.SetAutomaticSwapAck(false);
1227 // SetNeedsCommit should begin the frame on the next BeginImplFrame.
1229 scheduler
->SetNeedsCommit();
1230 EXPECT_TRUE(client
.needs_begin_frame());
1231 EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client
);
1234 // Create a BeginFrame with a long deadline to avoid race conditions.
1235 // This is the first BeginFrame, which will be handled immediately.
1236 BeginFrameArgs args
= BeginFrameArgs::CreateForTesting();
1237 args
.deadline
+= base::TimeDelta::FromHours(1);
1238 scheduler
->BeginFrame(args
);
1239 EXPECT_ACTION("WillBeginImplFrame", client
, 0, 2);
1240 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client
, 1, 2);
1241 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
1242 EXPECT_TRUE(client
.needs_begin_frame());
1245 // Queue BeginFrame while we are still handling the previous BeginFrame.
1246 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
1247 args
.frame_time
+= base::TimeDelta::FromSeconds(1);
1248 scheduler
->BeginFrame(args
);
1249 EXPECT_EQ(0, client
.num_actions_());
1250 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
1253 // NotifyReadyToCommit should trigger the pending commit and draw.
1254 scheduler
->NotifyBeginMainFrameStarted();
1255 scheduler
->NotifyReadyToCommit();
1256 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client
);
1257 EXPECT_TRUE(client
.needs_begin_frame());
1260 // Swapping will put us into a swap throttled state.
1261 client
.task_runner().RunPendingTasks(); // Run posted deadline.
1262 EXPECT_ACTION("ScheduledActionAnimate", client
, 0, 2);
1263 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client
, 1, 2);
1264 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
1265 EXPECT_TRUE(client
.needs_begin_frame());
1268 // While swap throttled, BeginRetroFrames should trigger BeginImplFrames
1269 // but not a BeginMainFrame or draw.
1270 scheduler
->SetNeedsCommit();
1271 client
.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
1272 EXPECT_ACTION("WillBeginImplFrame", client
, 0, 1);
1273 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
1274 EXPECT_TRUE(client
.needs_begin_frame());
1277 // Queue BeginFrame while we are still handling the previous BeginFrame.
1278 args
.frame_time
+= base::TimeDelta::FromSeconds(1);
1279 scheduler
->BeginFrame(args
);
1280 EXPECT_EQ(0, client
.num_actions_());
1281 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
1282 EXPECT_TRUE(client
.needs_begin_frame());
1285 // Take us out of a swap throttled state.
1286 scheduler
->DidSwapBuffersComplete();
1287 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client
, 0, 1);
1288 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
1289 EXPECT_TRUE(client
.needs_begin_frame());
1292 // BeginImplFrame deadline should draw.
1293 scheduler
->SetNeedsRedraw();
1294 client
.task_runner().RunPendingTasks(); // Run posted deadline.
1295 EXPECT_ACTION("ScheduledActionAnimate", client
, 0, 2);
1296 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client
, 1, 2);
1297 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
1298 EXPECT_TRUE(client
.needs_begin_frame());
1302 void BeginFramesNotFromClient(bool begin_frame_scheduling_enabled
,
1303 bool throttle_frame_production
) {
1304 FakeSchedulerClient client
;
1305 SchedulerSettings scheduler_settings
;
1306 scheduler_settings
.begin_frame_scheduling_enabled
=
1307 begin_frame_scheduling_enabled
;
1308 scheduler_settings
.throttle_frame_production
= throttle_frame_production
;
1309 Scheduler
* scheduler
= client
.CreateScheduler(scheduler_settings
);
1310 scheduler
->SetCanStart();
1311 scheduler
->SetVisible(true);
1312 scheduler
->SetCanDraw(true);
1313 InitializeOutputSurfaceAndFirstCommit(scheduler
, &client
);
1315 // SetNeedsCommit should begin the frame on the next BeginImplFrame
1316 // without calling SetNeedsBeginFrame.
1318 scheduler
->SetNeedsCommit();
1319 EXPECT_FALSE(client
.needs_begin_frame());
1320 EXPECT_EQ(0, client
.num_actions_());
1323 // When the client-driven BeginFrame are disabled, the scheduler posts it's
1324 // own BeginFrame tasks.
1325 client
.task_runner().RunPendingTasks(); // Run posted BeginFrame.
1326 EXPECT_ACTION("WillBeginImplFrame", client
, 0, 2);
1327 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client
, 1, 2);
1328 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
1329 EXPECT_FALSE(client
.needs_begin_frame());
1332 // If we don't swap on the deadline, we wait for the next BeginFrame.
1333 client
.task_runner().RunPendingTasks(); // Run posted deadline.
1334 EXPECT_EQ(0, client
.num_actions_());
1335 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
1336 EXPECT_FALSE(client
.needs_begin_frame());
1339 // NotifyReadyToCommit should trigger the commit.
1340 scheduler
->NotifyBeginMainFrameStarted();
1341 scheduler
->NotifyReadyToCommit();
1342 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client
);
1343 EXPECT_FALSE(client
.needs_begin_frame());
1346 // BeginImplFrame should prepare the draw.
1347 client
.task_runner().RunPendingTasks(); // Run posted BeginFrame.
1348 EXPECT_ACTION("WillBeginImplFrame", client
, 0, 2);
1349 EXPECT_ACTION("ScheduledActionAnimate", client
, 1, 2);
1350 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
1351 EXPECT_FALSE(client
.needs_begin_frame());
1354 // BeginImplFrame deadline should draw.
1355 client
.task_runner().RunPendingTasks(); // Run posted deadline.
1356 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client
, 0, 1);
1357 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
1358 EXPECT_FALSE(client
.needs_begin_frame());
1361 // The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
1362 // to avoid excessive toggles.
1363 client
.task_runner().RunPendingTasks(); // Run posted BeginFrame.
1364 EXPECT_SINGLE_ACTION("WillBeginImplFrame", client
);
1365 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
1368 // Make sure SetNeedsBeginFrame isn't called on the client
1369 // when the BeginFrame is no longer needed.
1370 client
.task_runner().RunPendingTasks(); // Run posted deadline.
1371 EXPECT_EQ(0, client
.num_actions_());
1372 EXPECT_FALSE(client
.needs_begin_frame());
1376 TEST(SchedulerTest
, SyntheticBeginFrames
) {
1377 bool begin_frame_scheduling_enabled
= false;
1378 bool throttle_frame_production
= true;
1379 BeginFramesNotFromClient(begin_frame_scheduling_enabled
,
1380 throttle_frame_production
);
1383 TEST(SchedulerTest
, VSyncThrottlingDisabled
) {
1384 bool begin_frame_scheduling_enabled
= true;
1385 bool throttle_frame_production
= false;
1386 BeginFramesNotFromClient(begin_frame_scheduling_enabled
,
1387 throttle_frame_production
);
1390 TEST(SchedulerTest
, SyntheticBeginFrames_And_VSyncThrottlingDisabled
) {
1391 bool begin_frame_scheduling_enabled
= false;
1392 bool throttle_frame_production
= false;
1393 BeginFramesNotFromClient(begin_frame_scheduling_enabled
,
1394 throttle_frame_production
);
1397 void BeginFramesNotFromClient_SwapThrottled(bool begin_frame_scheduling_enabled
,
1398 bool throttle_frame_production
) {
1399 FakeSchedulerClient client
;
1400 SchedulerSettings scheduler_settings
;
1401 scheduler_settings
.begin_frame_scheduling_enabled
=
1402 begin_frame_scheduling_enabled
;
1403 scheduler_settings
.throttle_frame_production
= throttle_frame_production
;
1404 Scheduler
* scheduler
= client
.CreateScheduler(scheduler_settings
);
1405 scheduler
->SetCanStart();
1406 scheduler
->SetVisible(true);
1407 scheduler
->SetCanDraw(true);
1408 InitializeOutputSurfaceAndFirstCommit(scheduler
, &client
);
1410 // To test swap ack throttling, this test disables automatic swap acks.
1411 scheduler
->SetMaxSwapsPending(1);
1412 client
.SetAutomaticSwapAck(false);
1414 // SetNeedsCommit should begin the frame on the next BeginImplFrame.
1416 scheduler
->SetNeedsCommit();
1417 EXPECT_FALSE(client
.needs_begin_frame());
1418 EXPECT_EQ(0, client
.num_actions_());
1421 // Trigger the first BeginImplFrame and BeginMainFrame
1422 client
.task_runner().RunPendingTasks(); // Run posted BeginFrame.
1423 EXPECT_ACTION("WillBeginImplFrame", client
, 0, 2);
1424 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client
, 1, 2);
1425 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
1426 EXPECT_FALSE(client
.needs_begin_frame());
1429 // NotifyReadyToCommit should trigger the pending commit and draw.
1430 scheduler
->NotifyBeginMainFrameStarted();
1431 scheduler
->NotifyReadyToCommit();
1432 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client
);
1433 EXPECT_FALSE(client
.needs_begin_frame());
1436 // Swapping will put us into a swap throttled state.
1437 client
.task_runner().RunPendingTasks(); // Run posted deadline.
1438 EXPECT_ACTION("ScheduledActionAnimate", client
, 0, 2);
1439 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client
, 1, 2);
1440 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
1441 EXPECT_FALSE(client
.needs_begin_frame());
1444 // While swap throttled, BeginFrames should trigger BeginImplFrames,
1445 // but not a BeginMainFrame or draw.
1446 scheduler
->SetNeedsCommit();
1447 client
.task_runner().RunPendingTasks(); // Run posted BeginFrame.
1448 EXPECT_ACTION("WillBeginImplFrame", client
, 0, 1);
1449 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
1450 EXPECT_FALSE(client
.needs_begin_frame());
1453 // Take us out of a swap throttled state.
1454 scheduler
->DidSwapBuffersComplete();
1455 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client
, 0, 1);
1456 EXPECT_TRUE(scheduler
->BeginImplFrameDeadlinePending());
1457 EXPECT_FALSE(client
.needs_begin_frame());
1460 // BeginImplFrame deadline should draw.
1461 scheduler
->SetNeedsRedraw();
1462 client
.task_runner().RunPendingTasks(); // Run posted deadline.
1463 EXPECT_ACTION("ScheduledActionAnimate", client
, 0, 2);
1464 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client
, 1, 2);
1465 EXPECT_FALSE(scheduler
->BeginImplFrameDeadlinePending());
1466 EXPECT_FALSE(client
.needs_begin_frame());
1470 TEST(SchedulerTest
, SyntheticBeginFrames_SwapThrottled
) {
1471 bool begin_frame_scheduling_enabled
= false;
1472 bool throttle_frame_production
= true;
1473 BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled
,
1474 throttle_frame_production
);
1477 TEST(SchedulerTest
, VSyncThrottlingDisabled_SwapThrottled
) {
1478 bool begin_frame_scheduling_enabled
= true;
1479 bool throttle_frame_production
= false;
1480 BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled
,
1481 throttle_frame_production
);
1485 SyntheticBeginFrames_And_VSyncThrottlingDisabled_SwapThrottled
) {
1486 bool begin_frame_scheduling_enabled
= false;
1487 bool throttle_frame_production
= false;
1488 BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled
,
1489 throttle_frame_production
);