1 // Copyright 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 #include "cc/scheduler/scheduler.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_vector.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/time/time.h"
14 #include "cc/test/scheduler_test_common.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
18 #define EXPECT_ACTION(action, client, action_index, expected_num_actions) \
19 EXPECT_EQ(expected_num_actions, client.num_actions_()); \
20 ASSERT_LT(action_index, client.num_actions_()); \
22 EXPECT_STREQ(action, client.Action(action_index)); \
23 for (int i = expected_num_actions; i < client.num_actions_(); ++i) \
24 ADD_FAILURE() << "Unexpected action: " << client.Action(i) << \
25 " with state:\n" << client.StateForAction(action_index); \
28 #define EXPECT_SINGLE_ACTION(action, client) \
29 EXPECT_ACTION(action, client, 0, 1)
34 void InitializeOutputSurfaceAndFirstCommit(Scheduler
* scheduler
) {
35 scheduler
->DidCreateAndInitializeOutputSurface();
36 scheduler
->SetNeedsCommit();
37 scheduler
->NotifyBeginMainFrameStarted();
38 scheduler
->NotifyReadyToCommit();
39 // Go through the motions to draw the commit.
40 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
41 scheduler
->OnBeginImplFrameDeadline();
42 // We need another BeginImplFrame so Scheduler calls
43 // SetNeedsBeginImplFrame(false).
44 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
45 scheduler
->OnBeginImplFrameDeadline();
48 class FakeSchedulerClient
: public SchedulerClient
{
51 : needs_begin_impl_frame_(false) {
58 draw_will_happen_
= true;
59 swap_will_happen_if_draw_happens_
= true;
61 log_anticipated_draw_time_change_
= false;
64 Scheduler
* CreateScheduler(const SchedulerSettings
& settings
) {
65 scheduler_
= Scheduler::Create(this, settings
, 0);
66 return scheduler_
.get();
69 // Most tests don't care about DidAnticipatedDrawTimeChange, so only record it
71 void set_log_anticipated_draw_time_change(bool log
) {
72 log_anticipated_draw_time_change_
= log
;
74 bool needs_begin_impl_frame() { return needs_begin_impl_frame_
; }
75 int num_draws() const { return num_draws_
; }
76 int num_actions_() const { return static_cast<int>(actions_
.size()); }
77 const char* Action(int i
) const { return actions_
[i
]; }
78 base::Value
& StateForAction(int i
) const { return *states_
[i
]; }
79 base::TimeTicks
posted_begin_impl_frame_deadline() const {
80 return posted_begin_impl_frame_deadline_
;
83 int ActionIndex(const char* action
) const {
84 for (size_t i
= 0; i
< actions_
.size(); i
++)
85 if (!strcmp(actions_
[i
], action
))
90 bool HasAction(const char* action
) const {
91 return ActionIndex(action
) >= 0;
94 void SetDrawWillHappen(bool draw_will_happen
) {
95 draw_will_happen_
= draw_will_happen
;
97 void SetSwapWillHappenIfDrawHappens(bool swap_will_happen_if_draw_happens
) {
98 swap_will_happen_if_draw_happens_
= swap_will_happen_if_draw_happens
;
101 // SchedulerClient implementation.
102 virtual void SetNeedsBeginImplFrame(bool enable
) OVERRIDE
{
103 actions_
.push_back("SetNeedsBeginImplFrame");
104 states_
.push_back(scheduler_
->StateAsValue().release());
105 needs_begin_impl_frame_
= enable
;
107 virtual void ScheduledActionSendBeginMainFrame() OVERRIDE
{
108 actions_
.push_back("ScheduledActionSendBeginMainFrame");
109 states_
.push_back(scheduler_
->StateAsValue().release());
111 virtual DrawSwapReadbackResult
ScheduledActionDrawAndSwapIfPossible()
113 actions_
.push_back("ScheduledActionDrawAndSwapIfPossible");
114 states_
.push_back(scheduler_
->StateAsValue().release());
116 bool did_readback
= false;
117 DrawSwapReadbackResult::DrawResult result
=
119 ? DrawSwapReadbackResult::DRAW_SUCCESS
120 : DrawSwapReadbackResult::DRAW_ABORTED_CHECKERBOARD_ANIMATIONS
;
121 return DrawSwapReadbackResult(
123 draw_will_happen_
&& swap_will_happen_if_draw_happens_
,
126 virtual DrawSwapReadbackResult
ScheduledActionDrawAndSwapForced() OVERRIDE
{
127 actions_
.push_back("ScheduledActionDrawAndSwapForced");
128 states_
.push_back(scheduler_
->StateAsValue().release());
129 bool did_swap
= swap_will_happen_if_draw_happens_
;
130 bool did_readback
= false;
131 return DrawSwapReadbackResult(
132 DrawSwapReadbackResult::DRAW_SUCCESS
, did_swap
, did_readback
);
134 virtual DrawSwapReadbackResult
ScheduledActionDrawAndReadback() OVERRIDE
{
135 actions_
.push_back("ScheduledActionDrawAndReadback");
136 states_
.push_back(scheduler_
->StateAsValue().release());
137 bool did_swap
= false;
138 bool did_readback
= true;
139 return DrawSwapReadbackResult(
140 DrawSwapReadbackResult::DRAW_SUCCESS
, did_swap
, did_readback
);
142 virtual void ScheduledActionCommit() OVERRIDE
{
143 actions_
.push_back("ScheduledActionCommit");
144 states_
.push_back(scheduler_
->StateAsValue().release());
146 virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE
{
147 actions_
.push_back("ScheduledActionUpdateVisibleTiles");
148 states_
.push_back(scheduler_
->StateAsValue().release());
150 virtual void ScheduledActionActivatePendingTree() OVERRIDE
{
151 actions_
.push_back("ScheduledActionActivatePendingTree");
152 states_
.push_back(scheduler_
->StateAsValue().release());
154 virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE
{
155 actions_
.push_back("ScheduledActionBeginOutputSurfaceCreation");
156 states_
.push_back(scheduler_
->StateAsValue().release());
158 virtual void ScheduledActionAcquireLayerTexturesForMainThread() OVERRIDE
{
159 actions_
.push_back("ScheduledActionAcquireLayerTexturesForMainThread");
160 states_
.push_back(scheduler_
->StateAsValue().release());
162 virtual void ScheduledActionManageTiles() OVERRIDE
{
163 actions_
.push_back("ScheduledActionManageTiles");
164 states_
.push_back(scheduler_
->StateAsValue().release());
166 virtual void DidAnticipatedDrawTimeChange(base::TimeTicks
) OVERRIDE
{
167 if (log_anticipated_draw_time_change_
)
168 actions_
.push_back("DidAnticipatedDrawTimeChange");
170 virtual base::TimeDelta
DrawDurationEstimate() OVERRIDE
{
171 return base::TimeDelta();
173 virtual base::TimeDelta
BeginMainFrameToCommitDurationEstimate() OVERRIDE
{
174 return base::TimeDelta();
176 virtual base::TimeDelta
CommitToActivateDurationEstimate() OVERRIDE
{
177 return base::TimeDelta();
180 virtual void PostBeginImplFrameDeadline(const base::Closure
& closure
,
181 base::TimeTicks deadline
) OVERRIDE
{
182 actions_
.push_back("PostBeginImplFrameDeadlineTask");
183 states_
.push_back(scheduler_
->StateAsValue().release());
184 posted_begin_impl_frame_deadline_
= deadline
;
187 virtual void DidBeginImplFrameDeadline() OVERRIDE
{}
190 bool needs_begin_impl_frame_
;
191 bool draw_will_happen_
;
192 bool swap_will_happen_if_draw_happens_
;
194 bool log_anticipated_draw_time_change_
;
195 base::TimeTicks posted_begin_impl_frame_deadline_
;
196 std::vector
<const char*> actions_
;
197 ScopedVector
<base::Value
> states_
;
198 scoped_ptr
<Scheduler
> scheduler_
;
201 TEST(SchedulerTest
, InitializeOutputSurfaceDoesNotBeginImplFrame
) {
202 FakeSchedulerClient client
;
203 SchedulerSettings default_scheduler_settings
;
204 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
205 scheduler
->SetCanStart();
206 scheduler
->SetVisible(true);
207 scheduler
->SetCanDraw(true);
209 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client
);
211 scheduler
->DidCreateAndInitializeOutputSurface();
212 EXPECT_EQ(0, client
.num_actions_());
215 TEST(SchedulerTest
, RequestCommit
) {
216 FakeSchedulerClient client
;
217 SchedulerSettings scheduler_settings
;
218 Scheduler
* scheduler
= client
.CreateScheduler(scheduler_settings
);
219 scheduler
->SetCanStart();
220 scheduler
->SetVisible(true);
221 scheduler
->SetCanDraw(true);
223 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client
);
224 InitializeOutputSurfaceAndFirstCommit(scheduler
);
226 // SetNeedsCommit should begin the frame on the next BeginImplFrame.
228 scheduler
->SetNeedsCommit();
229 EXPECT_TRUE(client
.needs_begin_impl_frame());
230 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client
);
233 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
234 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client
, 0, 2);
235 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client
, 1, 2);
236 EXPECT_TRUE(client
.needs_begin_impl_frame());
239 // If we don't swap on the deadline, we need to request another
241 scheduler
->OnBeginImplFrameDeadline();
242 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client
);
243 EXPECT_TRUE(client
.needs_begin_impl_frame());
246 // NotifyReadyToCommit should trigger the commit.
247 scheduler
->NotifyBeginMainFrameStarted();
248 scheduler
->NotifyReadyToCommit();
249 EXPECT_SINGLE_ACTION("ScheduledActionCommit", client
);
250 EXPECT_TRUE(client
.needs_begin_impl_frame());
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());
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());
266 // The following BeginImplFrame deadline should SetNeedsBeginImplFrame(false)
267 // to avoid excessive toggles.
268 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
269 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client
);
272 scheduler
->OnBeginImplFrameDeadline();
273 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client
);
274 EXPECT_FALSE(client
.needs_begin_impl_frame());
278 TEST(SchedulerTest
, RequestCommitAfterBeginMainFrameSent
) {
279 FakeSchedulerClient client
;
280 SchedulerSettings scheduler_settings
;
281 Scheduler
* scheduler
= client
.CreateScheduler(scheduler_settings
);
282 scheduler
->SetCanStart();
283 scheduler
->SetVisible(true);
284 scheduler
->SetCanDraw(true);
286 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client
);
287 InitializeOutputSurfaceAndFirstCommit(scheduler
);
290 // SetNeedsCommit should begin the frame.
291 scheduler
->SetNeedsCommit();
292 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client
);
295 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
296 EXPECT_EQ(client
.num_actions_(), 2);
297 EXPECT_TRUE(client
.HasAction("ScheduledActionSendBeginMainFrame"));
298 EXPECT_TRUE(client
.HasAction("PostBeginImplFrameDeadlineTask"));
300 EXPECT_TRUE(client
.needs_begin_impl_frame());
303 // Now SetNeedsCommit again. Calling here means we need a second commit.
304 scheduler
->SetNeedsCommit();
305 EXPECT_EQ(client
.num_actions_(), 0);
308 // Finish the first commit.
309 scheduler
->NotifyBeginMainFrameStarted();
310 scheduler
->NotifyReadyToCommit();
311 EXPECT_ACTION("ScheduledActionCommit", client
, 0, 2);
312 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client
, 1, 2);
314 scheduler
->OnBeginImplFrameDeadline();
315 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client
, 0, 2);
316 EXPECT_ACTION("SetNeedsBeginImplFrame", client
, 1, 2);
318 // Because we just swapped, the Scheduler should also request the next
319 // BeginImplFrame from the OutputSurface.
320 EXPECT_TRUE(client
.needs_begin_impl_frame());
323 // Since another commit is needed, the next BeginImplFrame should initiate
324 // the second commit.
325 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
326 EXPECT_EQ(client
.num_actions_(), 2);
327 EXPECT_TRUE(client
.HasAction("ScheduledActionSendBeginMainFrame"));
328 EXPECT_TRUE(client
.HasAction("PostBeginImplFrameDeadlineTask"));
331 // Finishing the commit before the deadline should post a new deadline task
332 // to trigger the deadline early.
333 scheduler
->NotifyBeginMainFrameStarted();
334 scheduler
->NotifyReadyToCommit();
335 EXPECT_ACTION("ScheduledActionCommit", client
, 0, 2);
336 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client
, 1, 2);
338 scheduler
->OnBeginImplFrameDeadline();
339 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client
, 0, 2);
340 EXPECT_ACTION("SetNeedsBeginImplFrame", client
, 1, 2);
341 EXPECT_TRUE(client
.needs_begin_impl_frame());
344 // On the next BeginImplFrame, verify we go back to a quiescent state and
345 // no longer request BeginImplFrames.
346 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
347 scheduler
->OnBeginImplFrameDeadline();
348 EXPECT_FALSE(client
.needs_begin_impl_frame());
352 TEST(SchedulerTest
, TextureAcquisitionCausesCommitInsteadOfDraw
) {
353 FakeSchedulerClient client
;
354 SchedulerSettings scheduler_settings
;
355 Scheduler
* scheduler
= client
.CreateScheduler(scheduler_settings
);
356 scheduler
->SetCanStart();
357 scheduler
->SetVisible(true);
358 scheduler
->SetCanDraw(true);
359 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client
);
361 InitializeOutputSurfaceAndFirstCommit(scheduler
);
363 scheduler
->SetNeedsRedraw();
364 EXPECT_TRUE(scheduler
->RedrawPending());
365 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client
);
366 EXPECT_TRUE(client
.needs_begin_impl_frame());
369 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
370 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client
);
372 scheduler
->OnBeginImplFrameDeadline();
373 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client
, 0, 2);
374 EXPECT_ACTION("SetNeedsBeginImplFrame", client
, 1, 2);
375 EXPECT_FALSE(scheduler
->RedrawPending());
376 EXPECT_TRUE(client
.needs_begin_impl_frame());
379 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
380 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client
);
382 scheduler
->OnBeginImplFrameDeadline();
383 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client
);
384 EXPECT_FALSE(scheduler
->RedrawPending());
385 EXPECT_FALSE(client
.needs_begin_impl_frame());
388 scheduler
->SetMainThreadNeedsLayerTextures();
389 EXPECT_SINGLE_ACTION("ScheduledActionAcquireLayerTexturesForMainThread",
392 // We should request a BeginImplFrame in anticipation of a draw.
394 scheduler
->SetNeedsRedraw();
395 EXPECT_TRUE(scheduler
->RedrawPending());
396 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client
);
397 EXPECT_TRUE(client
.needs_begin_impl_frame());
399 // No draw happens since the textures are acquired by the main thread.
401 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
402 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client
);
404 scheduler
->OnBeginImplFrameDeadline();
405 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client
);
406 EXPECT_TRUE(scheduler
->RedrawPending());
407 EXPECT_TRUE(client
.needs_begin_impl_frame());
410 scheduler
->SetNeedsCommit();
411 EXPECT_EQ(0, client
.num_actions_());
414 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
415 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client
, 0, 2);
416 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client
, 1, 2);
418 // Commit will release the texture.
420 scheduler
->NotifyBeginMainFrameStarted();
421 scheduler
->NotifyReadyToCommit();
422 EXPECT_ACTION("ScheduledActionCommit", client
, 0, 2);
423 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client
, 1, 2);
424 EXPECT_TRUE(scheduler
->RedrawPending());
426 // Now we can draw again after the commit happens.
428 scheduler
->OnBeginImplFrameDeadline();
429 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client
, 0, 2);
430 EXPECT_ACTION("SetNeedsBeginImplFrame", client
, 1, 2);
431 EXPECT_FALSE(scheduler
->RedrawPending());
432 EXPECT_TRUE(client
.needs_begin_impl_frame());
434 // Make sure we stop requesting BeginImplFrames if we don't swap.
436 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
437 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client
);
439 scheduler
->OnBeginImplFrameDeadline();
440 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client
);
441 EXPECT_FALSE(client
.needs_begin_impl_frame());
444 TEST(SchedulerTest
, TextureAcquisitionCollision
) {
445 FakeSchedulerClient client
;
446 SchedulerSettings scheduler_settings
;
447 Scheduler
* scheduler
= client
.CreateScheduler(scheduler_settings
);
448 scheduler
->SetCanStart();
449 scheduler
->SetVisible(true);
450 scheduler
->SetCanDraw(true);
452 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client
);
453 InitializeOutputSurfaceAndFirstCommit(scheduler
);
456 scheduler
->SetNeedsCommit();
457 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client
);
460 scheduler
->SetMainThreadNeedsLayerTextures();
461 EXPECT_SINGLE_ACTION(
462 "ScheduledActionAcquireLayerTexturesForMainThread", client
);
465 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
466 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client
, 0, 2);
467 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client
, 1, 2);
470 scheduler
->OnBeginImplFrameDeadline();
471 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client
);
473 // Although the compositor cannot draw because textures are locked by main
474 // thread, we continue requesting SetNeedsBeginImplFrame in anticipation of
476 EXPECT_TRUE(client
.needs_begin_impl_frame());
478 // Trigger the commit.
479 scheduler
->NotifyBeginMainFrameStarted();
480 scheduler
->NotifyReadyToCommit();
481 EXPECT_TRUE(client
.needs_begin_impl_frame());
483 // Between commit and draw, texture acquisition for main thread delayed,
484 // and main thread blocks.
486 scheduler
->SetMainThreadNeedsLayerTextures();
487 EXPECT_EQ(0, client
.num_actions_());
489 // No implicit commit is expected.
491 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
492 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client
);
495 scheduler
->OnBeginImplFrameDeadline();
496 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client
, 0, 3);
498 "ScheduledActionAcquireLayerTexturesForMainThread", client
, 1, 3);
499 EXPECT_ACTION("SetNeedsBeginImplFrame", client
, 2, 3);
500 EXPECT_TRUE(client
.needs_begin_impl_frame());
502 // The compositor should not draw because textures are locked by main
505 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
506 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client
);
508 scheduler
->OnBeginImplFrameDeadline();
509 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client
);
510 EXPECT_FALSE(client
.needs_begin_impl_frame());
512 // The impl thread need an explicit commit from the main thread to lock
515 scheduler
->SetNeedsCommit();
516 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client
);
517 EXPECT_TRUE(client
.needs_begin_impl_frame());
520 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
521 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client
, 0, 2);
522 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client
, 1, 2);
525 // Trigger the commit, which will trigger the deadline task early.
526 scheduler
->NotifyBeginMainFrameStarted();
527 scheduler
->NotifyReadyToCommit();
528 EXPECT_ACTION("ScheduledActionCommit", client
, 0, 2);
529 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client
, 1, 2);
530 EXPECT_TRUE(client
.needs_begin_impl_frame());
533 // Verify we draw on the next BeginImplFrame deadline
534 scheduler
->OnBeginImplFrameDeadline();
535 EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client
, 0, 2);
536 EXPECT_ACTION("SetNeedsBeginImplFrame", client
, 1, 2);
537 EXPECT_TRUE(client
.needs_begin_impl_frame());
541 TEST(SchedulerTest
, VisibilitySwitchWithTextureAcquisition
) {
542 FakeSchedulerClient client
;
543 SchedulerSettings scheduler_settings
;
544 Scheduler
* scheduler
= client
.CreateScheduler(scheduler_settings
);
545 scheduler
->SetCanStart();
546 scheduler
->SetVisible(true);
547 scheduler
->SetCanDraw(true);
549 EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client
);
551 scheduler
->DidCreateAndInitializeOutputSurface();
553 scheduler
->SetNeedsCommit();
554 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
555 scheduler
->OnBeginImplFrameDeadline();
556 scheduler
->NotifyBeginMainFrameStarted();
557 scheduler
->NotifyReadyToCommit();
558 scheduler
->SetMainThreadNeedsLayerTextures();
559 scheduler
->SetNeedsCommit();
561 // Verify that pending texture acquisition fires when visibility
562 // is lost in order to avoid a deadlock.
563 scheduler
->SetVisible(false);
564 EXPECT_SINGLE_ACTION("ScheduledActionAcquireLayerTexturesForMainThread",
568 scheduler
->SetVisible(true);
569 EXPECT_EQ(0, client
.num_actions_());
570 EXPECT_TRUE(client
.needs_begin_impl_frame());
572 // Regaining visibility with textures acquired by main thread while
573 // compositor is waiting for first draw should result in a request
574 // for a new frame in order to escape a deadlock.
576 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
577 EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client
, 0, 2);
578 EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client
, 1, 2);
581 class SchedulerClientThatsetNeedsDrawInsideDraw
: public FakeSchedulerClient
{
583 virtual void ScheduledActionSendBeginMainFrame() OVERRIDE
{}
584 virtual DrawSwapReadbackResult
ScheduledActionDrawAndSwapIfPossible()
586 // Only SetNeedsRedraw the first time this is called
588 scheduler_
->SetNeedsRedraw();
589 return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
592 virtual DrawSwapReadbackResult
ScheduledActionDrawAndSwapForced() OVERRIDE
{
594 bool did_swap
= true;
595 bool did_readback
= false;
596 return DrawSwapReadbackResult(
597 DrawSwapReadbackResult::DRAW_SUCCESS
, did_swap
, did_readback
);
600 virtual void ScheduledActionCommit() OVERRIDE
{}
601 virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE
{}
602 virtual void DidAnticipatedDrawTimeChange(base::TimeTicks
) OVERRIDE
{}
605 // Tests for two different situations:
606 // 1. the scheduler dropping SetNeedsRedraw requests that happen inside
607 // a ScheduledActionDrawAndSwap
608 // 2. the scheduler drawing twice inside a single tick
609 TEST(SchedulerTest
, RequestRedrawInsideDraw
) {
610 SchedulerClientThatsetNeedsDrawInsideDraw client
;
611 SchedulerSettings default_scheduler_settings
;
612 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
613 scheduler
->SetCanStart();
614 scheduler
->SetVisible(true);
615 scheduler
->SetCanDraw(true);
616 InitializeOutputSurfaceAndFirstCommit(scheduler
);
619 scheduler
->SetNeedsRedraw();
620 EXPECT_TRUE(scheduler
->RedrawPending());
621 EXPECT_TRUE(client
.needs_begin_impl_frame());
622 EXPECT_EQ(0, client
.num_draws());
624 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
625 scheduler
->OnBeginImplFrameDeadline();
626 EXPECT_EQ(1, client
.num_draws());
627 EXPECT_TRUE(scheduler
->RedrawPending());
628 EXPECT_TRUE(client
.needs_begin_impl_frame());
630 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
631 scheduler
->OnBeginImplFrameDeadline();
632 EXPECT_EQ(2, client
.num_draws());
633 EXPECT_FALSE(scheduler
->RedrawPending());
634 EXPECT_TRUE(client
.needs_begin_impl_frame());
636 // We stop requesting BeginImplFrames after a BeginImplFrame where we don't
638 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
639 scheduler
->OnBeginImplFrameDeadline();
640 EXPECT_EQ(2, client
.num_draws());
641 EXPECT_FALSE(scheduler
->RedrawPending());
642 EXPECT_FALSE(client
.needs_begin_impl_frame());
645 // Test that requesting redraw inside a failed draw doesn't lose the request.
646 TEST(SchedulerTest
, RequestRedrawInsideFailedDraw
) {
647 SchedulerClientThatsetNeedsDrawInsideDraw client
;
648 SchedulerSettings default_scheduler_settings
;
649 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
650 scheduler
->SetCanStart();
651 scheduler
->SetVisible(true);
652 scheduler
->SetCanDraw(true);
653 InitializeOutputSurfaceAndFirstCommit(scheduler
);
656 client
.SetDrawWillHappen(false);
658 scheduler
->SetNeedsRedraw();
659 EXPECT_TRUE(scheduler
->RedrawPending());
660 EXPECT_TRUE(client
.needs_begin_impl_frame());
661 EXPECT_EQ(0, client
.num_draws());
664 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
665 scheduler
->OnBeginImplFrameDeadline();
666 EXPECT_EQ(1, client
.num_draws());
668 // We have a commit pending and the draw failed, and we didn't lose the redraw
670 EXPECT_TRUE(scheduler
->CommitPending());
671 EXPECT_TRUE(scheduler
->RedrawPending());
672 EXPECT_TRUE(client
.needs_begin_impl_frame());
674 // Fail the draw again.
675 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
676 scheduler
->OnBeginImplFrameDeadline();
677 EXPECT_EQ(2, client
.num_draws());
678 EXPECT_TRUE(scheduler
->CommitPending());
679 EXPECT_TRUE(scheduler
->RedrawPending());
680 EXPECT_TRUE(client
.needs_begin_impl_frame());
682 // Draw successfully.
683 client
.SetDrawWillHappen(true);
684 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
685 scheduler
->OnBeginImplFrameDeadline();
686 EXPECT_EQ(3, client
.num_draws());
687 EXPECT_TRUE(scheduler
->CommitPending());
688 EXPECT_FALSE(scheduler
->RedrawPending());
689 EXPECT_TRUE(client
.needs_begin_impl_frame());
692 class SchedulerClientThatSetNeedsCommitInsideDraw
: public FakeSchedulerClient
{
694 SchedulerClientThatSetNeedsCommitInsideDraw()
695 : set_needs_commit_on_next_draw_(false) {}
697 virtual void ScheduledActionSendBeginMainFrame() OVERRIDE
{}
698 virtual DrawSwapReadbackResult
ScheduledActionDrawAndSwapIfPossible()
700 // Only SetNeedsCommit the first time this is called
701 if (set_needs_commit_on_next_draw_
) {
702 scheduler_
->SetNeedsCommit();
703 set_needs_commit_on_next_draw_
= false;
705 return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
708 virtual DrawSwapReadbackResult
ScheduledActionDrawAndSwapForced() OVERRIDE
{
710 bool did_swap
= false;
711 bool did_readback
= false;
712 return DrawSwapReadbackResult(
713 DrawSwapReadbackResult::DRAW_SUCCESS
, did_swap
, did_readback
);
716 virtual void ScheduledActionCommit() OVERRIDE
{}
717 virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE
{}
718 virtual void DidAnticipatedDrawTimeChange(base::TimeTicks
) OVERRIDE
{}
720 void SetNeedsCommitOnNextDraw() { set_needs_commit_on_next_draw_
= true; }
723 bool set_needs_commit_on_next_draw_
;
726 // Tests for the scheduler infinite-looping on SetNeedsCommit requests that
727 // happen inside a ScheduledActionDrawAndSwap
728 TEST(SchedulerTest
, RequestCommitInsideDraw
) {
729 SchedulerClientThatSetNeedsCommitInsideDraw client
;
730 SchedulerSettings default_scheduler_settings
;
731 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
732 scheduler
->SetCanStart();
733 scheduler
->SetVisible(true);
734 scheduler
->SetCanDraw(true);
735 InitializeOutputSurfaceAndFirstCommit(scheduler
);
738 EXPECT_FALSE(client
.needs_begin_impl_frame());
739 scheduler
->SetNeedsRedraw();
740 EXPECT_TRUE(scheduler
->RedrawPending());
741 EXPECT_EQ(0, client
.num_draws());
742 EXPECT_TRUE(client
.needs_begin_impl_frame());
744 client
.SetNeedsCommitOnNextDraw();
745 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
746 client
.SetNeedsCommitOnNextDraw();
747 scheduler
->OnBeginImplFrameDeadline();
748 EXPECT_EQ(1, client
.num_draws());
749 EXPECT_TRUE(scheduler
->CommitPending());
750 EXPECT_TRUE(client
.needs_begin_impl_frame());
751 scheduler
->NotifyBeginMainFrameStarted();
752 scheduler
->NotifyReadyToCommit();
754 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
755 scheduler
->OnBeginImplFrameDeadline();
756 EXPECT_EQ(2, client
.num_draws());
758 EXPECT_FALSE(scheduler
->RedrawPending());
759 EXPECT_FALSE(scheduler
->CommitPending());
760 EXPECT_TRUE(client
.needs_begin_impl_frame());
762 // We stop requesting BeginImplFrames after a BeginImplFrame where we don't
764 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
765 scheduler
->OnBeginImplFrameDeadline();
766 EXPECT_EQ(2, client
.num_draws());
767 EXPECT_FALSE(scheduler
->RedrawPending());
768 EXPECT_FALSE(scheduler
->CommitPending());
769 EXPECT_FALSE(client
.needs_begin_impl_frame());
772 // Tests that when a draw fails then the pending commit should not be dropped.
773 TEST(SchedulerTest
, RequestCommitInsideFailedDraw
) {
774 SchedulerClientThatsetNeedsDrawInsideDraw client
;
775 SchedulerSettings default_scheduler_settings
;
776 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
777 scheduler
->SetCanStart();
778 scheduler
->SetVisible(true);
779 scheduler
->SetCanDraw(true);
780 InitializeOutputSurfaceAndFirstCommit(scheduler
);
783 client
.SetDrawWillHappen(false);
785 scheduler
->SetNeedsRedraw();
786 EXPECT_TRUE(scheduler
->RedrawPending());
787 EXPECT_TRUE(client
.needs_begin_impl_frame());
788 EXPECT_EQ(0, client
.num_draws());
791 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
792 scheduler
->OnBeginImplFrameDeadline();
793 EXPECT_EQ(1, client
.num_draws());
795 // We have a commit pending and the draw failed, and we didn't lose the commit
797 EXPECT_TRUE(scheduler
->CommitPending());
798 EXPECT_TRUE(scheduler
->RedrawPending());
799 EXPECT_TRUE(client
.needs_begin_impl_frame());
801 // Fail the draw again.
802 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
803 scheduler
->OnBeginImplFrameDeadline();
804 EXPECT_EQ(2, client
.num_draws());
805 EXPECT_TRUE(scheduler
->CommitPending());
806 EXPECT_TRUE(scheduler
->RedrawPending());
807 EXPECT_TRUE(client
.needs_begin_impl_frame());
809 // Draw successfully.
810 client
.SetDrawWillHappen(true);
811 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
812 scheduler
->OnBeginImplFrameDeadline();
813 EXPECT_EQ(3, client
.num_draws());
814 EXPECT_TRUE(scheduler
->CommitPending());
815 EXPECT_FALSE(scheduler
->RedrawPending());
816 EXPECT_TRUE(client
.needs_begin_impl_frame());
819 TEST(SchedulerTest
, NoSwapWhenDrawFails
) {
820 SchedulerClientThatSetNeedsCommitInsideDraw client
;
821 SchedulerSettings default_scheduler_settings
;
822 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
823 scheduler
->SetCanStart();
824 scheduler
->SetVisible(true);
825 scheduler
->SetCanDraw(true);
826 InitializeOutputSurfaceAndFirstCommit(scheduler
);
829 scheduler
->SetNeedsRedraw();
830 EXPECT_TRUE(scheduler
->RedrawPending());
831 EXPECT_TRUE(client
.needs_begin_impl_frame());
832 EXPECT_EQ(0, client
.num_draws());
834 // Draw successfully, this starts a new frame.
835 client
.SetNeedsCommitOnNextDraw();
836 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
837 scheduler
->OnBeginImplFrameDeadline();
838 EXPECT_EQ(1, client
.num_draws());
840 scheduler
->SetNeedsRedraw();
841 EXPECT_TRUE(scheduler
->RedrawPending());
842 EXPECT_TRUE(client
.needs_begin_impl_frame());
844 // Fail to draw, this should not start a frame.
845 client
.SetDrawWillHappen(false);
846 client
.SetNeedsCommitOnNextDraw();
847 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
848 scheduler
->OnBeginImplFrameDeadline();
849 EXPECT_EQ(2, client
.num_draws());
852 TEST(SchedulerTest
, NoSwapWhenSwapFailsDuringForcedCommit
) {
853 FakeSchedulerClient client
;
854 SchedulerSettings default_scheduler_settings
;
855 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
857 // Tell the client that it will fail to swap.
858 client
.SetDrawWillHappen(true);
859 client
.SetSwapWillHappenIfDrawHappens(false);
861 // Get the compositor to do a ScheduledActionDrawAndReadback.
862 scheduler
->SetCanDraw(true);
863 scheduler
->SetNeedsRedraw();
864 scheduler
->SetNeedsForcedCommitForReadback();
865 scheduler
->NotifyBeginMainFrameStarted();
866 scheduler
->NotifyReadyToCommit();
867 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndReadback"));
870 TEST(SchedulerTest
, BackToBackReadbackAllowed
) {
871 // Some clients call readbacks twice in a row before the replacement
872 // commit comes in. Make sure it is allowed.
873 FakeSchedulerClient client
;
874 SchedulerSettings default_scheduler_settings
;
875 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
877 // Get the compositor to do 2 ScheduledActionDrawAndReadbacks before
878 // the replacement commit comes in.
879 scheduler
->SetCanDraw(true);
880 scheduler
->SetNeedsRedraw();
881 scheduler
->SetNeedsForcedCommitForReadback();
882 scheduler
->NotifyBeginMainFrameStarted();
883 scheduler
->NotifyReadyToCommit();
884 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndReadback"));
887 scheduler
->SetNeedsForcedCommitForReadback();
888 scheduler
->NotifyBeginMainFrameStarted();
889 scheduler
->NotifyReadyToCommit();
890 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndReadback"));
892 // The replacement commit comes in after 2 readbacks.
894 scheduler
->NotifyBeginMainFrameStarted();
895 scheduler
->NotifyReadyToCommit();
899 class SchedulerClientNeedsManageTilesInDraw
: public FakeSchedulerClient
{
901 virtual DrawSwapReadbackResult
ScheduledActionDrawAndSwapIfPossible()
903 scheduler_
->SetNeedsManageTiles();
904 return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
908 // Test manage tiles is independant of draws.
909 TEST(SchedulerTest
, ManageTiles
) {
910 SchedulerClientNeedsManageTilesInDraw client
;
911 SchedulerSettings default_scheduler_settings
;
912 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
913 scheduler
->SetCanStart();
914 scheduler
->SetVisible(true);
915 scheduler
->SetCanDraw(true);
916 InitializeOutputSurfaceAndFirstCommit(scheduler
);
918 // Request both draw and manage tiles. ManageTiles shouldn't
919 // be trigged until BeginImplFrame.
921 scheduler
->SetNeedsManageTiles();
922 scheduler
->SetNeedsRedraw();
923 EXPECT_TRUE(scheduler
->RedrawPending());
924 EXPECT_TRUE(scheduler
->ManageTilesPending());
925 EXPECT_TRUE(client
.needs_begin_impl_frame());
926 EXPECT_EQ(0, client
.num_draws());
927 EXPECT_FALSE(client
.HasAction("ScheduledActionManageTiles"));
928 EXPECT_FALSE(client
.HasAction("ScheduledActionDrawAndSwapIfPossible"));
930 // We have no immediate actions to perform, so the BeginImplFrame should post
931 // the deadline task.
933 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
934 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client
);
936 // On the deadline, he actions should have occured in the right order.
938 scheduler
->OnBeginImplFrameDeadline();
939 EXPECT_EQ(1, client
.num_draws());
940 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndSwapIfPossible"));
941 EXPECT_TRUE(client
.HasAction("ScheduledActionManageTiles"));
942 EXPECT_LT(client
.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
943 client
.ActionIndex("ScheduledActionManageTiles"));
944 EXPECT_FALSE(scheduler
->RedrawPending());
945 EXPECT_FALSE(scheduler
->ManageTilesPending());
947 // Request a draw. We don't need a ManageTiles yet.
949 scheduler
->SetNeedsRedraw();
950 EXPECT_TRUE(scheduler
->RedrawPending());
951 EXPECT_FALSE(scheduler
->ManageTilesPending());
952 EXPECT_TRUE(client
.needs_begin_impl_frame());
953 EXPECT_EQ(0, client
.num_draws());
955 // We have no immediate actions to perform, so the BeginImplFrame should post
956 // the deadline task.
958 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
959 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client
);
961 // Draw. The draw will trigger SetNeedsManageTiles, and
962 // then the ManageTiles action will be triggered after the Draw.
963 // Afterwards, neither a draw nor ManageTiles are pending.
965 scheduler
->OnBeginImplFrameDeadline();
966 EXPECT_EQ(1, client
.num_draws());
967 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndSwapIfPossible"));
968 EXPECT_TRUE(client
.HasAction("ScheduledActionManageTiles"));
969 EXPECT_LT(client
.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
970 client
.ActionIndex("ScheduledActionManageTiles"));
971 EXPECT_FALSE(scheduler
->RedrawPending());
972 EXPECT_FALSE(scheduler
->ManageTilesPending());
974 // We need a BeginImplFrame where we don't swap to go idle.
976 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
977 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client
);
979 scheduler
->OnBeginImplFrameDeadline();
980 EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client
);
981 EXPECT_EQ(0, client
.num_draws());
983 // Now trigger a ManageTiles outside of a draw. We will then need
984 // a begin-frame for the ManageTiles, but we don't need a draw.
986 EXPECT_FALSE(client
.needs_begin_impl_frame());
987 scheduler
->SetNeedsManageTiles();
988 EXPECT_TRUE(client
.needs_begin_impl_frame());
989 EXPECT_TRUE(scheduler
->ManageTilesPending());
990 EXPECT_FALSE(scheduler
->RedrawPending());
992 // BeginImplFrame. There will be no draw, only ManageTiles.
994 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
995 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client
);
997 scheduler
->OnBeginImplFrameDeadline();
998 EXPECT_EQ(0, client
.num_draws());
999 EXPECT_FALSE(client
.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1000 EXPECT_TRUE(client
.HasAction("ScheduledActionManageTiles"));
1003 // Test that ManageTiles only happens once per frame. If an external caller
1004 // initiates it, then the state machine should not ManageTiles on that frame.
1005 TEST(SchedulerTest
, ManageTilesOncePerFrame
) {
1006 FakeSchedulerClient client
;
1007 SchedulerSettings default_scheduler_settings
;
1008 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
1009 scheduler
->SetCanStart();
1010 scheduler
->SetVisible(true);
1011 scheduler
->SetCanDraw(true);
1012 InitializeOutputSurfaceAndFirstCommit(scheduler
);
1014 // If DidManageTiles during a frame, then ManageTiles should not occur again.
1015 scheduler
->SetNeedsManageTiles();
1016 scheduler
->SetNeedsRedraw();
1018 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1019 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client
);
1021 EXPECT_TRUE(scheduler
->ManageTilesPending());
1022 scheduler
->DidManageTiles(); // An explicit ManageTiles.
1023 EXPECT_FALSE(scheduler
->ManageTilesPending());
1026 scheduler
->OnBeginImplFrameDeadline();
1027 EXPECT_EQ(1, client
.num_draws());
1028 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1029 EXPECT_FALSE(client
.HasAction("ScheduledActionManageTiles"));
1030 EXPECT_FALSE(scheduler
->RedrawPending());
1031 EXPECT_FALSE(scheduler
->ManageTilesPending());
1033 // Next frame without DidManageTiles should ManageTiles with draw.
1034 scheduler
->SetNeedsManageTiles();
1035 scheduler
->SetNeedsRedraw();
1037 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1038 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client
);
1041 scheduler
->OnBeginImplFrameDeadline();
1042 EXPECT_EQ(1, client
.num_draws());
1043 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1044 EXPECT_TRUE(client
.HasAction("ScheduledActionManageTiles"));
1045 EXPECT_LT(client
.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
1046 client
.ActionIndex("ScheduledActionManageTiles"));
1047 EXPECT_FALSE(scheduler
->RedrawPending());
1048 EXPECT_FALSE(scheduler
->ManageTilesPending());
1049 scheduler
->DidManageTiles(); // Corresponds to ScheduledActionManageTiles
1051 // If we get another DidManageTiles within the same frame, we should
1052 // not ManageTiles on the next frame.
1053 scheduler
->DidManageTiles(); // An explicit ManageTiles.
1054 scheduler
->SetNeedsManageTiles();
1055 scheduler
->SetNeedsRedraw();
1057 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1058 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client
);
1060 EXPECT_TRUE(scheduler
->ManageTilesPending());
1063 scheduler
->OnBeginImplFrameDeadline();
1064 EXPECT_EQ(1, client
.num_draws());
1065 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1066 EXPECT_FALSE(client
.HasAction("ScheduledActionManageTiles"));
1067 EXPECT_FALSE(scheduler
->RedrawPending());
1069 // If we get another DidManageTiles, we should not ManageTiles on the next
1070 // frame. This verifies we don't alternate calling ManageTiles once and twice.
1071 EXPECT_TRUE(scheduler
->ManageTilesPending());
1072 scheduler
->DidManageTiles(); // An explicit ManageTiles.
1073 EXPECT_FALSE(scheduler
->ManageTilesPending());
1074 scheduler
->SetNeedsManageTiles();
1075 scheduler
->SetNeedsRedraw();
1077 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1078 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client
);
1080 EXPECT_TRUE(scheduler
->ManageTilesPending());
1083 scheduler
->OnBeginImplFrameDeadline();
1084 EXPECT_EQ(1, client
.num_draws());
1085 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1086 EXPECT_FALSE(client
.HasAction("ScheduledActionManageTiles"));
1087 EXPECT_FALSE(scheduler
->RedrawPending());
1089 // Next frame without DidManageTiles should ManageTiles with draw.
1090 scheduler
->SetNeedsManageTiles();
1091 scheduler
->SetNeedsRedraw();
1093 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1094 EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client
);
1097 scheduler
->OnBeginImplFrameDeadline();
1098 EXPECT_EQ(1, client
.num_draws());
1099 EXPECT_TRUE(client
.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1100 EXPECT_TRUE(client
.HasAction("ScheduledActionManageTiles"));
1101 EXPECT_LT(client
.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
1102 client
.ActionIndex("ScheduledActionManageTiles"));
1103 EXPECT_FALSE(scheduler
->RedrawPending());
1104 EXPECT_FALSE(scheduler
->ManageTilesPending());
1105 scheduler
->DidManageTiles(); // Corresponds to ScheduledActionManageTiles
1108 TEST(SchedulerTest
, TriggerBeginFrameDeadlineEarly
) {
1109 SchedulerClientNeedsManageTilesInDraw client
;
1110 SchedulerSettings default_scheduler_settings
;
1111 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
1112 scheduler
->SetCanStart();
1113 scheduler
->SetVisible(true);
1114 scheduler
->SetCanDraw(true);
1115 InitializeOutputSurfaceAndFirstCommit(scheduler
);
1118 BeginFrameArgs impl_frame_args
= BeginFrameArgs::CreateForTesting();
1119 scheduler
->SetNeedsRedraw();
1120 scheduler
->BeginImplFrame(impl_frame_args
);
1122 // The deadline should be zero since there is no work other than drawing
1124 EXPECT_EQ(base::TimeTicks(), client
.posted_begin_impl_frame_deadline());
1127 class SchedulerClientWithFixedEstimates
: public FakeSchedulerClient
{
1129 SchedulerClientWithFixedEstimates(
1130 base::TimeDelta draw_duration
,
1131 base::TimeDelta begin_main_frame_to_commit_duration
,
1132 base::TimeDelta commit_to_activate_duration
)
1133 : draw_duration_(draw_duration
),
1134 begin_main_frame_to_commit_duration_(
1135 begin_main_frame_to_commit_duration
),
1136 commit_to_activate_duration_(commit_to_activate_duration
) {}
1138 virtual base::TimeDelta
DrawDurationEstimate() OVERRIDE
{
1139 return draw_duration_
;
1141 virtual base::TimeDelta
BeginMainFrameToCommitDurationEstimate() OVERRIDE
{
1142 return begin_main_frame_to_commit_duration_
;
1144 virtual base::TimeDelta
CommitToActivateDurationEstimate() OVERRIDE
{
1145 return commit_to_activate_duration_
;
1149 base::TimeDelta draw_duration_
;
1150 base::TimeDelta begin_main_frame_to_commit_duration_
;
1151 base::TimeDelta commit_to_activate_duration_
;
1154 void MainFrameInHighLatencyMode(int64 begin_main_frame_to_commit_estimate_in_ms
,
1155 int64 commit_to_activate_estimate_in_ms
,
1156 bool smoothness_takes_priority
,
1157 bool should_send_begin_main_frame
) {
1158 // Set up client with specified estimates (draw duration is set to 1).
1159 SchedulerClientWithFixedEstimates
client(
1160 base::TimeDelta::FromMilliseconds(1),
1161 base::TimeDelta::FromMilliseconds(
1162 begin_main_frame_to_commit_estimate_in_ms
),
1163 base::TimeDelta::FromMilliseconds(commit_to_activate_estimate_in_ms
));
1164 SchedulerSettings default_scheduler_settings
;
1165 Scheduler
* scheduler
= client
.CreateScheduler(default_scheduler_settings
);
1166 scheduler
->SetCanStart();
1167 scheduler
->SetVisible(true);
1168 scheduler
->SetCanDraw(true);
1169 scheduler
->SetSmoothnessTakesPriority(smoothness_takes_priority
);
1170 InitializeOutputSurfaceAndFirstCommit(scheduler
);
1172 // Impl thread hits deadline before commit finishes.
1174 scheduler
->SetNeedsCommit();
1175 EXPECT_FALSE(scheduler
->MainThreadIsInHighLatencyMode());
1176 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1177 EXPECT_FALSE(scheduler
->MainThreadIsInHighLatencyMode());
1178 scheduler
->OnBeginImplFrameDeadline();
1179 EXPECT_TRUE(scheduler
->MainThreadIsInHighLatencyMode());
1180 scheduler
->NotifyBeginMainFrameStarted();
1181 scheduler
->NotifyReadyToCommit();
1182 EXPECT_TRUE(scheduler
->MainThreadIsInHighLatencyMode());
1183 EXPECT_TRUE(client
.HasAction("ScheduledActionSendBeginMainFrame"));
1186 scheduler
->SetNeedsCommit();
1187 EXPECT_TRUE(scheduler
->MainThreadIsInHighLatencyMode());
1188 scheduler
->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1189 EXPECT_TRUE(scheduler
->MainThreadIsInHighLatencyMode());
1190 scheduler
->OnBeginImplFrameDeadline();
1191 EXPECT_EQ(scheduler
->MainThreadIsInHighLatencyMode(),
1192 should_send_begin_main_frame
);
1193 EXPECT_EQ(client
.HasAction("ScheduledActionSendBeginMainFrame"),
1194 should_send_begin_main_frame
);
1198 SkipMainFrameIfHighLatencyAndCanCommitAndActivateBeforeDeadline
) {
1199 // Set up client so that estimates indicate that we can commit and activate
1200 // before the deadline (~8ms by default).
1201 MainFrameInHighLatencyMode(1, 1, false, false);
1204 TEST(SchedulerTest
, NotSkipMainFrameIfHighLatencyAndCanCommitTooLong
) {
1205 // Set up client so that estimates indicate that the commit cannot finish
1206 // before the deadline (~8ms by default).
1207 MainFrameInHighLatencyMode(10, 1, false, true);
1210 TEST(SchedulerTest
, NotSkipMainFrameIfHighLatencyAndCanActivateTooLong
) {
1211 // Set up client so that estimates indicate that the activate cannot finish
1212 // before the deadline (~8ms by default).
1213 MainFrameInHighLatencyMode(1, 10, false, true);
1216 TEST(SchedulerTest
, NotSkipMainFrameInPreferSmoothnessMode
) {
1217 // Set up client so that estimates indicate that we can commit and activate
1218 // before the deadline (~8ms by default), but also enable smoothness takes
1220 MainFrameInHighLatencyMode(1, 1, true, true);
1223 void SpinForMillis(int millis
) {
1224 base::RunLoop run_loop
;
1225 base::MessageLoop::current()->PostDelayedTask(
1227 run_loop
.QuitClosure(),
1228 base::TimeDelta::FromMilliseconds(millis
));
1232 TEST(SchedulerTest
, PollForCommitCompletion
) {
1233 // Since we are simulating a long commit, set up a client with draw duration
1234 // estimates that prevent skipping main frames to get to low latency mode.
1235 SchedulerClientWithFixedEstimates
client(
1236 base::TimeDelta::FromMilliseconds(1),
1237 base::TimeDelta::FromMilliseconds(32),
1238 base::TimeDelta::FromMilliseconds(32));
1239 client
.set_log_anticipated_draw_time_change(true);
1240 SchedulerSettings settings
= SchedulerSettings();
1241 settings
.throttle_frame_production
= false;
1242 Scheduler
* scheduler
= client
.CreateScheduler(settings
);
1244 scheduler
->SetCanDraw(true);
1245 scheduler
->SetCanStart();
1246 scheduler
->SetVisible(true);
1247 scheduler
->DidCreateAndInitializeOutputSurface();
1249 scheduler
->SetNeedsCommit();
1250 EXPECT_TRUE(scheduler
->CommitPending());
1251 scheduler
->NotifyBeginMainFrameStarted();
1252 scheduler
->NotifyReadyToCommit();
1253 scheduler
->SetNeedsRedraw();
1254 BeginFrameArgs impl_frame_args
= BeginFrameArgs::CreateForTesting();
1255 const int interval
= 1;
1256 impl_frame_args
.interval
= base::TimeDelta::FromMilliseconds(interval
);
1257 scheduler
->BeginImplFrame(impl_frame_args
);
1258 scheduler
->OnBeginImplFrameDeadline();
1260 // At this point, we've drawn a frame. Start another commit, but hold off on
1261 // the NotifyReadyToCommit for now.
1262 EXPECT_FALSE(scheduler
->CommitPending());
1263 scheduler
->SetNeedsCommit();
1264 EXPECT_TRUE(scheduler
->CommitPending());
1266 // Spin the event loop a few times and make sure we get more
1267 // DidAnticipateDrawTimeChange calls every time.
1268 int actions_so_far
= client
.num_actions_();
1270 // Does three iterations to make sure that the timer is properly repeating.
1271 for (int i
= 0; i
< 3; ++i
) {
1272 // Wait for 2x the frame interval to match
1273 // Scheduler::advance_commit_state_timer_'s rate.
1274 SpinForMillis(interval
* 2);
1275 EXPECT_GT(client
.num_actions_(), actions_so_far
);
1276 EXPECT_STREQ(client
.Action(client
.num_actions_() - 1),
1277 "DidAnticipatedDrawTimeChange");
1278 actions_so_far
= client
.num_actions_();