Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / cc / scheduler / scheduler_unittest.cc
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"
5
6 #include <string>
7 #include <vector>
8
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"
17
18 #define EXPECT_ACTION(action, client, action_index, expected_num_actions) \
19   EXPECT_EQ(expected_num_actions, client.num_actions_());                 \
20   ASSERT_LT(action_index, client.num_actions_());                         \
21   do {                                                                    \
22     EXPECT_STREQ(action, client.Action(action_index));                    \
23     for (int i = expected_num_actions; i < client.num_actions_(); ++i)    \
24       ADD_FAILURE() << "Unexpected action: " << client.Action(i) <<       \
25           " with state:\n" << client.StateForAction(action_index);        \
26   } while (false)
27
28 #define EXPECT_SINGLE_ACTION(action, client) \
29   EXPECT_ACTION(action, client, 0, 1)
30
31 namespace cc {
32 namespace {
33
34 void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler) {
35   scheduler->DidCreateAndInitializeOutputSurface();
36   scheduler->SetNeedsCommit();
37   scheduler->FinishCommit();
38   // Go through the motions to draw the commit.
39   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
40   scheduler->OnBeginImplFrameDeadline();
41   // We need another BeginImplFrame so Scheduler calls
42   // SetNeedsBeginImplFrame(false).
43   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
44   scheduler->OnBeginImplFrameDeadline();
45 }
46
47 class FakeSchedulerClient : public SchedulerClient {
48  public:
49   FakeSchedulerClient()
50   : needs_begin_impl_frame_(false) {
51     Reset();
52   }
53
54   void Reset() {
55     actions_.clear();
56     states_.clear();
57     draw_will_happen_ = true;
58     swap_will_happen_if_draw_happens_ = true;
59     num_draws_ = 0;
60     log_anticipated_draw_time_change_ = false;
61   }
62
63   Scheduler* CreateScheduler(const SchedulerSettings& settings) {
64     scheduler_ = Scheduler::Create(this, settings, 0);
65     return scheduler_.get();
66   }
67
68   // Most tests don't care about DidAnticipatedDrawTimeChange, so only record it
69   // for tests that do.
70   void set_log_anticipated_draw_time_change(bool log) {
71     log_anticipated_draw_time_change_ = log;
72   }
73   bool needs_begin_impl_frame() { return needs_begin_impl_frame_; }
74   int num_draws() const { return num_draws_; }
75   int num_actions_() const { return static_cast<int>(actions_.size()); }
76   const char* Action(int i) const { return actions_[i]; }
77   base::Value& StateForAction(int i) const { return *states_[i]; }
78
79   int ActionIndex(const char* action) const {
80     for (size_t i = 0; i < actions_.size(); i++)
81       if (!strcmp(actions_[i], action))
82         return i;
83     return -1;
84   }
85
86   bool HasAction(const char* action) const {
87     return ActionIndex(action) >= 0;
88   }
89
90   void SetDrawWillHappen(bool draw_will_happen) {
91     draw_will_happen_ = draw_will_happen;
92   }
93   void SetSwapWillHappenIfDrawHappens(bool swap_will_happen_if_draw_happens) {
94     swap_will_happen_if_draw_happens_ = swap_will_happen_if_draw_happens;
95   }
96
97   // SchedulerClient implementation.
98   virtual void SetNeedsBeginImplFrame(bool enable) OVERRIDE {
99     actions_.push_back("SetNeedsBeginImplFrame");
100     states_.push_back(scheduler_->StateAsValue().release());
101     needs_begin_impl_frame_ = enable;
102   }
103   virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {
104     actions_.push_back("ScheduledActionSendBeginMainFrame");
105     states_.push_back(scheduler_->StateAsValue().release());
106   }
107   virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
108       OVERRIDE {
109     actions_.push_back("ScheduledActionDrawAndSwapIfPossible");
110     states_.push_back(scheduler_->StateAsValue().release());
111     num_draws_++;
112     bool did_readback = false;
113     DrawSwapReadbackResult::DrawResult result =
114         draw_will_happen_
115             ? DrawSwapReadbackResult::DRAW_SUCCESS
116             : DrawSwapReadbackResult::DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
117     return DrawSwapReadbackResult(
118         result,
119         draw_will_happen_ && swap_will_happen_if_draw_happens_,
120         did_readback);
121   }
122   virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
123     actions_.push_back("ScheduledActionDrawAndSwapForced");
124     states_.push_back(scheduler_->StateAsValue().release());
125     bool did_swap = swap_will_happen_if_draw_happens_;
126     bool did_readback = false;
127     return DrawSwapReadbackResult(
128         DrawSwapReadbackResult::DRAW_SUCCESS, did_swap, did_readback);
129   }
130   virtual DrawSwapReadbackResult ScheduledActionDrawAndReadback() OVERRIDE {
131     actions_.push_back("ScheduledActionDrawAndReadback");
132     states_.push_back(scheduler_->StateAsValue().release());
133     bool did_swap = false;
134     bool did_readback = true;
135     return DrawSwapReadbackResult(
136         DrawSwapReadbackResult::DRAW_SUCCESS, did_swap, did_readback);
137   }
138   virtual void ScheduledActionCommit() OVERRIDE {
139     actions_.push_back("ScheduledActionCommit");
140     states_.push_back(scheduler_->StateAsValue().release());
141   }
142   virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE {
143     actions_.push_back("ScheduledActionUpdateVisibleTiles");
144     states_.push_back(scheduler_->StateAsValue().release());
145   }
146   virtual void ScheduledActionActivatePendingTree() OVERRIDE {
147     actions_.push_back("ScheduledActionActivatePendingTree");
148     states_.push_back(scheduler_->StateAsValue().release());
149   }
150   virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {
151     actions_.push_back("ScheduledActionBeginOutputSurfaceCreation");
152     states_.push_back(scheduler_->StateAsValue().release());
153   }
154   virtual void ScheduledActionAcquireLayerTexturesForMainThread() OVERRIDE {
155     actions_.push_back("ScheduledActionAcquireLayerTexturesForMainThread");
156     states_.push_back(scheduler_->StateAsValue().release());
157   }
158   virtual void ScheduledActionManageTiles() OVERRIDE {
159     actions_.push_back("ScheduledActionManageTiles");
160     states_.push_back(scheduler_->StateAsValue().release());
161   }
162   virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {
163     if (log_anticipated_draw_time_change_)
164       actions_.push_back("DidAnticipatedDrawTimeChange");
165   }
166   virtual base::TimeDelta DrawDurationEstimate() OVERRIDE {
167     return base::TimeDelta();
168   }
169   virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE {
170     return base::TimeDelta();
171   }
172   virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE {
173     return base::TimeDelta();
174   }
175
176   virtual void PostBeginImplFrameDeadline(const base::Closure& closure,
177                                           base::TimeTicks deadline) OVERRIDE {
178     actions_.push_back("PostBeginImplFrameDeadlineTask");
179     states_.push_back(scheduler_->StateAsValue().release());
180   }
181
182   virtual void DidBeginImplFrameDeadline() OVERRIDE {}
183
184  protected:
185   bool needs_begin_impl_frame_;
186   bool draw_will_happen_;
187   bool swap_will_happen_if_draw_happens_;
188   int num_draws_;
189   bool log_anticipated_draw_time_change_;
190   std::vector<const char*> actions_;
191   ScopedVector<base::Value> states_;
192   scoped_ptr<Scheduler> scheduler_;
193 };
194
195 TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginImplFrame) {
196   FakeSchedulerClient client;
197   SchedulerSettings default_scheduler_settings;
198   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
199   scheduler->SetCanStart();
200   scheduler->SetVisible(true);
201   scheduler->SetCanDraw(true);
202
203   EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
204   client.Reset();
205   scheduler->DidCreateAndInitializeOutputSurface();
206   EXPECT_EQ(0, client.num_actions_());
207 }
208
209 void RequestCommit(bool deadline_scheduling_enabled) {
210   FakeSchedulerClient client;
211   SchedulerSettings scheduler_settings;
212   scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
213   Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
214   scheduler->SetCanStart();
215   scheduler->SetVisible(true);
216   scheduler->SetCanDraw(true);
217
218   EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
219   InitializeOutputSurfaceAndFirstCommit(scheduler);
220
221   // SetNeedsCommit should begin the frame on the next BeginImplFrame.
222   client.Reset();
223   scheduler->SetNeedsCommit();
224   EXPECT_TRUE(client.needs_begin_impl_frame());
225   if (deadline_scheduling_enabled) {
226     EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
227   } else {
228     EXPECT_EQ(client.num_actions_(), 2);
229     EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
230     EXPECT_TRUE(client.HasAction("SetNeedsBeginImplFrame"));
231   }
232   client.Reset();
233
234   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
235   if (deadline_scheduling_enabled) {
236     EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
237     EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
238   } else {
239     EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
240   }
241   EXPECT_TRUE(client.needs_begin_impl_frame());
242   client.Reset();
243
244   // If we don't swap on the deadline, we need to request another
245   // BeginImplFrame.
246   scheduler->OnBeginImplFrameDeadline();
247   EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
248   EXPECT_TRUE(client.needs_begin_impl_frame());
249   client.Reset();
250
251   // FinishCommit should commit
252   scheduler->FinishCommit();
253   EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
254   EXPECT_TRUE(client.needs_begin_impl_frame());
255   client.Reset();
256
257   // BeginImplFrame should prepare the draw.
258   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
259   EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
260   EXPECT_TRUE(client.needs_begin_impl_frame());
261   client.Reset();
262
263   // BeginImplFrame deadline should draw.
264   scheduler->OnBeginImplFrameDeadline();
265   EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
266   EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
267   EXPECT_TRUE(client.needs_begin_impl_frame());
268   client.Reset();
269
270   // The following BeginImplFrame deadline should SetNeedsBeginImplFrame(false)
271   // to avoid excessive toggles.
272   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
273   EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
274   client.Reset();
275
276   scheduler->OnBeginImplFrameDeadline();
277   EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
278   EXPECT_FALSE(client.needs_begin_impl_frame());
279   client.Reset();
280 }
281
282 TEST(SchedulerTest, RequestCommit) {
283   bool deadline_scheduling_enabled = false;
284   RequestCommit(deadline_scheduling_enabled);
285 }
286
287 TEST(SchedulerTest, RequestCommit_Deadline) {
288   bool deadline_scheduling_enabled = true;
289   RequestCommit(deadline_scheduling_enabled);
290 }
291
292 void RequestCommitAfterBeginMainFrameSent(
293     bool deadline_scheduling_enabled) {
294   FakeSchedulerClient client;
295   SchedulerSettings scheduler_settings;
296   scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
297   Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
298   scheduler->SetCanStart();
299   scheduler->SetVisible(true);
300   scheduler->SetCanDraw(true);
301
302   EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
303   InitializeOutputSurfaceAndFirstCommit(scheduler);
304   client.Reset();
305
306   // SetNeedsCommit should begin the frame.
307   scheduler->SetNeedsCommit();
308   if (deadline_scheduling_enabled) {
309     EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
310   } else {
311     EXPECT_EQ(client.num_actions_(), 2);
312     EXPECT_TRUE(client.HasAction("SetNeedsBeginImplFrame"));
313     EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
314   }
315
316   client.Reset();
317   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
318   if (deadline_scheduling_enabled) {
319     EXPECT_EQ(client.num_actions_(), 2);
320     EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
321     EXPECT_TRUE(client.HasAction("PostBeginImplFrameDeadlineTask"));
322   } else {
323     EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
324   }
325
326   EXPECT_TRUE(client.needs_begin_impl_frame());
327   client.Reset();
328
329   // Now SetNeedsCommit again. Calling here means we need a second commit.
330   scheduler->SetNeedsCommit();
331   EXPECT_EQ(client.num_actions_(), 0);
332   client.Reset();
333
334   // Finish the first commit.
335   scheduler->FinishCommit();
336   EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
337   EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
338   client.Reset();
339   scheduler->OnBeginImplFrameDeadline();
340   if (deadline_scheduling_enabled) {
341     EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
342     EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
343   } else {
344     EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 3);
345     EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 3);
346     EXPECT_ACTION("SetNeedsBeginImplFrame", client, 2, 3);
347   }
348
349   // Because we just swapped, the Scheduler should also request the next
350   // BeginImplFrame from the OutputSurface.
351   EXPECT_TRUE(client.needs_begin_impl_frame());
352   client.Reset();
353
354   // Since another commit is needed, the next BeginImplFrame should initiate
355   // the second commit.
356   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
357   if (deadline_scheduling_enabled) {
358     EXPECT_EQ(client.num_actions_(), 2);
359     EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
360     EXPECT_TRUE(client.HasAction("PostBeginImplFrameDeadlineTask"));
361   } else {
362     EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
363   }
364   client.Reset();
365
366   // Finishing the commit before the deadline should post a new deadline task
367   // to trigger the deadline early.
368   scheduler->FinishCommit();
369   EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
370   EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
371   client.Reset();
372   scheduler->OnBeginImplFrameDeadline();
373   EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
374   EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
375   EXPECT_TRUE(client.needs_begin_impl_frame());
376   client.Reset();
377
378   // On the next BeginImplFrame, verify we go back to a quiescent state and
379   // no longer request BeginImplFrames.
380   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
381   scheduler->OnBeginImplFrameDeadline();
382   EXPECT_FALSE(client.needs_begin_impl_frame());
383   client.Reset();
384 }
385
386 TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
387   bool deadline_scheduling_enabled = false;
388   RequestCommitAfterBeginMainFrameSent(deadline_scheduling_enabled);
389 }
390
391 TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent_Deadline) {
392   bool deadline_scheduling_enabled = true;
393   RequestCommitAfterBeginMainFrameSent(deadline_scheduling_enabled);
394 }
395
396 void TextureAcquisitionCausesCommitInsteadOfDraw(
397     bool deadline_scheduling_enabled) {
398   FakeSchedulerClient client;
399   SchedulerSettings scheduler_settings;
400   scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
401   Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
402   scheduler->SetCanStart();
403   scheduler->SetVisible(true);
404   scheduler->SetCanDraw(true);
405   EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
406
407   InitializeOutputSurfaceAndFirstCommit(scheduler);
408   client.Reset();
409   scheduler->SetNeedsRedraw();
410   EXPECT_TRUE(scheduler->RedrawPending());
411   EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
412   EXPECT_TRUE(client.needs_begin_impl_frame());
413
414   client.Reset();
415   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
416   EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
417   client.Reset();
418   scheduler->OnBeginImplFrameDeadline();
419   EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
420   EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
421   EXPECT_FALSE(scheduler->RedrawPending());
422   EXPECT_TRUE(client.needs_begin_impl_frame());
423
424   client.Reset();
425   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
426   EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
427   client.Reset();
428   scheduler->OnBeginImplFrameDeadline();
429   EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
430   EXPECT_FALSE(scheduler->RedrawPending());
431   EXPECT_FALSE(client.needs_begin_impl_frame());
432
433   client.Reset();
434   scheduler->SetMainThreadNeedsLayerTextures();
435   EXPECT_SINGLE_ACTION("ScheduledActionAcquireLayerTexturesForMainThread",
436                        client);
437
438   // We should request a BeginImplFrame in anticipation of a draw.
439   client.Reset();
440   scheduler->SetNeedsRedraw();
441   EXPECT_TRUE(scheduler->RedrawPending());
442   EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
443   EXPECT_TRUE(client.needs_begin_impl_frame());
444
445   // No draw happens since the textures are acquired by the main thread.
446   client.Reset();
447   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
448   EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
449   client.Reset();
450   scheduler->OnBeginImplFrameDeadline();
451   EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
452   EXPECT_TRUE(scheduler->RedrawPending());
453   EXPECT_TRUE(client.needs_begin_impl_frame());
454
455   client.Reset();
456   scheduler->SetNeedsCommit();
457   if (deadline_scheduling_enabled) {
458     EXPECT_EQ(0, client.num_actions_());
459   } else {
460     EXPECT_SINGLE_ACTION("ScheduledActionSendBeginMainFrame", client);
461   }
462
463   client.Reset();
464   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
465   if (deadline_scheduling_enabled) {
466     EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
467     EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
468   } else {
469     EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
470   }
471
472   // Commit will release the texture.
473   client.Reset();
474   scheduler->FinishCommit();
475   EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
476   EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
477   EXPECT_TRUE(scheduler->RedrawPending());
478
479   // Now we can draw again after the commit happens.
480   client.Reset();
481   scheduler->OnBeginImplFrameDeadline();
482   EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
483   EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
484   EXPECT_FALSE(scheduler->RedrawPending());
485   EXPECT_TRUE(client.needs_begin_impl_frame());
486
487   // Make sure we stop requesting BeginImplFrames if we don't swap.
488   client.Reset();
489   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
490   EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
491   client.Reset();
492   scheduler->OnBeginImplFrameDeadline();
493   EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
494   EXPECT_FALSE(client.needs_begin_impl_frame());
495 }
496
497 TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw) {
498   bool deadline_scheduling_enabled = false;
499   TextureAcquisitionCausesCommitInsteadOfDraw(deadline_scheduling_enabled);
500 }
501
502 TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw_Deadline) {
503   bool deadline_scheduling_enabled = true;
504   TextureAcquisitionCausesCommitInsteadOfDraw(deadline_scheduling_enabled);
505 }
506
507 void TextureAcquisitionCollision(bool deadline_scheduling_enabled) {
508   FakeSchedulerClient client;
509   SchedulerSettings scheduler_settings;
510   scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
511   Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
512   scheduler->SetCanStart();
513   scheduler->SetVisible(true);
514   scheduler->SetCanDraw(true);
515
516   EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
517   InitializeOutputSurfaceAndFirstCommit(scheduler);
518
519   client.Reset();
520   scheduler->SetNeedsCommit();
521 if (deadline_scheduling_enabled) {
522     EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
523   } else {
524     EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
525     EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
526   }
527
528   client.Reset();
529   scheduler->SetMainThreadNeedsLayerTextures();
530   EXPECT_SINGLE_ACTION(
531       "ScheduledActionAcquireLayerTexturesForMainThread", client);
532
533   client.Reset();
534   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
535   if (deadline_scheduling_enabled) {
536     EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
537     EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
538   } else {
539     EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
540   }
541
542   client.Reset();
543   scheduler->OnBeginImplFrameDeadline();
544   EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
545
546   // Although the compositor cannot draw because textures are locked by main
547   // thread, we continue requesting SetNeedsBeginImplFrame in anticipation of
548   // the unlock.
549   EXPECT_TRUE(client.needs_begin_impl_frame());
550
551   // Trigger the commit
552   scheduler->FinishCommit();
553   EXPECT_TRUE(client.needs_begin_impl_frame());
554
555   // Between commit and draw, texture acquisition for main thread delayed,
556   // and main thread blocks.
557   client.Reset();
558   scheduler->SetMainThreadNeedsLayerTextures();
559   EXPECT_EQ(0, client.num_actions_());
560
561   // No implicit commit is expected.
562   client.Reset();
563   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
564   EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
565
566   client.Reset();
567   scheduler->OnBeginImplFrameDeadline();
568   EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 3);
569   EXPECT_ACTION(
570       "ScheduledActionAcquireLayerTexturesForMainThread", client, 1, 3);
571   EXPECT_ACTION("SetNeedsBeginImplFrame", client, 2, 3);
572   EXPECT_TRUE(client.needs_begin_impl_frame());
573
574   // The compositor should not draw because textures are locked by main
575   // thread.
576   client.Reset();
577   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
578   EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
579   client.Reset();
580   scheduler->OnBeginImplFrameDeadline();
581   EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
582   EXPECT_FALSE(client.needs_begin_impl_frame());
583
584   // The impl thread need an explicit commit from the main thread to lock
585   // the textures.
586   client.Reset();
587   scheduler->SetNeedsCommit();
588   if (deadline_scheduling_enabled) {
589     EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
590   } else {
591     EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
592     EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
593   }
594   EXPECT_TRUE(client.needs_begin_impl_frame());
595
596   client.Reset();
597   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
598   if (deadline_scheduling_enabled) {
599     EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
600     EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
601   } else {
602     EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
603   }
604   client.Reset();
605
606   // Trigger the commit, which will trigger the deadline task early.
607   scheduler->FinishCommit();
608   EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
609   EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
610   EXPECT_TRUE(client.needs_begin_impl_frame());
611   client.Reset();
612
613   // Verify we draw on the next BeginImplFrame deadline
614   scheduler->OnBeginImplFrameDeadline();
615   EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
616   EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
617   EXPECT_TRUE(client.needs_begin_impl_frame());
618   client.Reset();
619 }
620
621 TEST(SchedulerTest, TextureAcquisitionCollision) {
622   bool deadline_scheduling_enabled = false;
623   TextureAcquisitionCollision(deadline_scheduling_enabled);
624 }
625
626 TEST(SchedulerTest, TextureAcquisitionCollision_Deadline) {
627   bool deadline_scheduling_enabled = true;
628   TextureAcquisitionCollision(deadline_scheduling_enabled);
629 }
630
631 void VisibilitySwitchWithTextureAcquisition(bool deadline_scheduling_enabled) {
632   FakeSchedulerClient client;
633   SchedulerSettings scheduler_settings;
634   scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
635   Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
636   scheduler->SetCanStart();
637   scheduler->SetVisible(true);
638   scheduler->SetCanDraw(true);
639
640   EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
641   client.Reset();
642   scheduler->DidCreateAndInitializeOutputSurface();
643
644   scheduler->SetNeedsCommit();
645   if (deadline_scheduling_enabled) {
646     scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
647     scheduler->OnBeginImplFrameDeadline();
648   }
649   scheduler->FinishCommit();
650   scheduler->SetMainThreadNeedsLayerTextures();
651   scheduler->SetNeedsCommit();
652   client.Reset();
653   // Verify that pending texture acquisition fires when visibility
654   // is lost in order to avoid a deadlock.
655   scheduler->SetVisible(false);
656   EXPECT_SINGLE_ACTION("ScheduledActionAcquireLayerTexturesForMainThread",
657                        client);
658
659   client.Reset();
660   scheduler->SetVisible(true);
661   EXPECT_EQ(0, client.num_actions_());
662   EXPECT_TRUE(client.needs_begin_impl_frame());
663
664   // Regaining visibility with textures acquired by main thread while
665   // compositor is waiting for first draw should result in a request
666   // for a new frame in order to escape a deadlock.
667   client.Reset();
668   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
669   EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
670   EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
671 }
672
673 TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition) {
674   bool deadline_scheduling_enabled = false;
675   VisibilitySwitchWithTextureAcquisition(deadline_scheduling_enabled);
676 }
677
678 TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition_Deadline) {
679   bool deadline_scheduling_enabled = true;
680   VisibilitySwitchWithTextureAcquisition(deadline_scheduling_enabled);
681 }
682
683 class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
684  public:
685   virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {}
686   virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
687       OVERRIDE {
688     // Only SetNeedsRedraw the first time this is called
689     if (!num_draws_)
690       scheduler_->SetNeedsRedraw();
691     return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
692   }
693
694   virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
695     NOTREACHED();
696     bool did_swap = true;
697     bool did_readback = false;
698     return DrawSwapReadbackResult(
699         DrawSwapReadbackResult::DRAW_SUCCESS, did_swap, did_readback);
700   }
701
702   virtual void ScheduledActionCommit() OVERRIDE {}
703   virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {}
704   virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {}
705 };
706
707 // Tests for two different situations:
708 // 1. the scheduler dropping SetNeedsRedraw requests that happen inside
709 //    a ScheduledActionDrawAndSwap
710 // 2. the scheduler drawing twice inside a single tick
711 TEST(SchedulerTest, RequestRedrawInsideDraw) {
712   SchedulerClientThatsetNeedsDrawInsideDraw client;
713   SchedulerSettings default_scheduler_settings;
714   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
715   scheduler->SetCanStart();
716   scheduler->SetVisible(true);
717   scheduler->SetCanDraw(true);
718   InitializeOutputSurfaceAndFirstCommit(scheduler);
719   client.Reset();
720
721   scheduler->SetNeedsRedraw();
722   EXPECT_TRUE(scheduler->RedrawPending());
723   EXPECT_TRUE(client.needs_begin_impl_frame());
724   EXPECT_EQ(0, client.num_draws());
725
726   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
727   scheduler->OnBeginImplFrameDeadline();
728   EXPECT_EQ(1, client.num_draws());
729   EXPECT_TRUE(scheduler->RedrawPending());
730   EXPECT_TRUE(client.needs_begin_impl_frame());
731
732   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
733   scheduler->OnBeginImplFrameDeadline();
734   EXPECT_EQ(2, client.num_draws());
735   EXPECT_FALSE(scheduler->RedrawPending());
736   EXPECT_TRUE(client.needs_begin_impl_frame());
737
738   // We stop requesting BeginImplFrames after a BeginImplFrame where we don't
739   // swap.
740   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
741   scheduler->OnBeginImplFrameDeadline();
742   EXPECT_EQ(2, client.num_draws());
743   EXPECT_FALSE(scheduler->RedrawPending());
744   EXPECT_FALSE(client.needs_begin_impl_frame());
745 }
746
747 // Test that requesting redraw inside a failed draw doesn't lose the request.
748 TEST(SchedulerTest, RequestRedrawInsideFailedDraw) {
749   SchedulerClientThatsetNeedsDrawInsideDraw client;
750   SchedulerSettings default_scheduler_settings;
751   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
752   scheduler->SetCanStart();
753   scheduler->SetVisible(true);
754   scheduler->SetCanDraw(true);
755   InitializeOutputSurfaceAndFirstCommit(scheduler);
756   client.Reset();
757
758   client.SetDrawWillHappen(false);
759
760   scheduler->SetNeedsRedraw();
761   EXPECT_TRUE(scheduler->RedrawPending());
762   EXPECT_TRUE(client.needs_begin_impl_frame());
763   EXPECT_EQ(0, client.num_draws());
764
765   // Fail the draw.
766   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
767   scheduler->OnBeginImplFrameDeadline();
768   EXPECT_EQ(1, client.num_draws());
769
770   // We have a commit pending and the draw failed, and we didn't lose the redraw
771   // request.
772   EXPECT_TRUE(scheduler->CommitPending());
773   EXPECT_TRUE(scheduler->RedrawPending());
774   EXPECT_TRUE(client.needs_begin_impl_frame());
775
776   // Fail the draw again.
777   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
778   scheduler->OnBeginImplFrameDeadline();
779   EXPECT_EQ(2, client.num_draws());
780   EXPECT_TRUE(scheduler->CommitPending());
781   EXPECT_TRUE(scheduler->RedrawPending());
782   EXPECT_TRUE(client.needs_begin_impl_frame());
783
784   // Draw successfully.
785   client.SetDrawWillHappen(true);
786   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
787   scheduler->OnBeginImplFrameDeadline();
788   EXPECT_EQ(3, client.num_draws());
789   EXPECT_TRUE(scheduler->CommitPending());
790   EXPECT_FALSE(scheduler->RedrawPending());
791   EXPECT_TRUE(client.needs_begin_impl_frame());
792 }
793
794 class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
795  public:
796   SchedulerClientThatSetNeedsCommitInsideDraw()
797       : set_needs_commit_on_next_draw_(false) {}
798
799   virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {}
800   virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
801       OVERRIDE {
802     // Only SetNeedsCommit the first time this is called
803     if (set_needs_commit_on_next_draw_) {
804       scheduler_->SetNeedsCommit();
805       set_needs_commit_on_next_draw_ = false;
806     }
807     return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
808   }
809
810   virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
811     NOTREACHED();
812     bool did_swap = false;
813     bool did_readback = false;
814     return DrawSwapReadbackResult(
815         DrawSwapReadbackResult::DRAW_SUCCESS, did_swap, did_readback);
816   }
817
818   virtual void ScheduledActionCommit() OVERRIDE {}
819   virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {}
820   virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {}
821
822   void SetNeedsCommitOnNextDraw() { set_needs_commit_on_next_draw_ = true; }
823
824  private:
825   bool set_needs_commit_on_next_draw_;
826 };
827
828 // Tests for the scheduler infinite-looping on SetNeedsCommit requests that
829 // happen inside a ScheduledActionDrawAndSwap
830 TEST(SchedulerTest, RequestCommitInsideDraw) {
831   SchedulerClientThatSetNeedsCommitInsideDraw client;
832   SchedulerSettings default_scheduler_settings;
833   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
834   scheduler->SetCanStart();
835   scheduler->SetVisible(true);
836   scheduler->SetCanDraw(true);
837   InitializeOutputSurfaceAndFirstCommit(scheduler);
838   client.Reset();
839
840   EXPECT_FALSE(client.needs_begin_impl_frame());
841   scheduler->SetNeedsRedraw();
842   EXPECT_TRUE(scheduler->RedrawPending());
843   EXPECT_EQ(0, client.num_draws());
844   EXPECT_TRUE(client.needs_begin_impl_frame());
845
846   client.SetNeedsCommitOnNextDraw();
847   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
848   client.SetNeedsCommitOnNextDraw();
849   scheduler->OnBeginImplFrameDeadline();
850   EXPECT_EQ(1, client.num_draws());
851   EXPECT_TRUE(scheduler->CommitPending());
852   EXPECT_TRUE(client.needs_begin_impl_frame());
853   scheduler->FinishCommit();
854
855   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
856   scheduler->OnBeginImplFrameDeadline();
857   EXPECT_EQ(2, client.num_draws());
858
859   EXPECT_FALSE(scheduler->RedrawPending());
860   EXPECT_FALSE(scheduler->CommitPending());
861   EXPECT_TRUE(client.needs_begin_impl_frame());
862
863   // We stop requesting BeginImplFrames after a BeginImplFrame where we don't
864   // swap.
865   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
866   scheduler->OnBeginImplFrameDeadline();
867   EXPECT_EQ(2, client.num_draws());
868   EXPECT_FALSE(scheduler->RedrawPending());
869   EXPECT_FALSE(scheduler->CommitPending());
870   EXPECT_FALSE(client.needs_begin_impl_frame());
871 }
872
873 // Tests that when a draw fails then the pending commit should not be dropped.
874 TEST(SchedulerTest, RequestCommitInsideFailedDraw) {
875   SchedulerClientThatsetNeedsDrawInsideDraw client;
876   SchedulerSettings default_scheduler_settings;
877   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
878   scheduler->SetCanStart();
879   scheduler->SetVisible(true);
880   scheduler->SetCanDraw(true);
881   InitializeOutputSurfaceAndFirstCommit(scheduler);
882   client.Reset();
883
884   client.SetDrawWillHappen(false);
885
886   scheduler->SetNeedsRedraw();
887   EXPECT_TRUE(scheduler->RedrawPending());
888   EXPECT_TRUE(client.needs_begin_impl_frame());
889   EXPECT_EQ(0, client.num_draws());
890
891   // Fail the draw.
892   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
893   scheduler->OnBeginImplFrameDeadline();
894   EXPECT_EQ(1, client.num_draws());
895
896   // We have a commit pending and the draw failed, and we didn't lose the commit
897   // request.
898   EXPECT_TRUE(scheduler->CommitPending());
899   EXPECT_TRUE(scheduler->RedrawPending());
900   EXPECT_TRUE(client.needs_begin_impl_frame());
901
902   // Fail the draw again.
903   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
904   scheduler->OnBeginImplFrameDeadline();
905   EXPECT_EQ(2, client.num_draws());
906   EXPECT_TRUE(scheduler->CommitPending());
907   EXPECT_TRUE(scheduler->RedrawPending());
908   EXPECT_TRUE(client.needs_begin_impl_frame());
909
910   // Draw successfully.
911   client.SetDrawWillHappen(true);
912   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
913   scheduler->OnBeginImplFrameDeadline();
914   EXPECT_EQ(3, client.num_draws());
915   EXPECT_TRUE(scheduler->CommitPending());
916   EXPECT_FALSE(scheduler->RedrawPending());
917   EXPECT_TRUE(client.needs_begin_impl_frame());
918 }
919
920 TEST(SchedulerTest, NoSwapWhenDrawFails) {
921   SchedulerClientThatSetNeedsCommitInsideDraw client;
922   SchedulerSettings default_scheduler_settings;
923   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
924   scheduler->SetCanStart();
925   scheduler->SetVisible(true);
926   scheduler->SetCanDraw(true);
927   InitializeOutputSurfaceAndFirstCommit(scheduler);
928   client.Reset();
929
930   scheduler->SetNeedsRedraw();
931   EXPECT_TRUE(scheduler->RedrawPending());
932   EXPECT_TRUE(client.needs_begin_impl_frame());
933   EXPECT_EQ(0, client.num_draws());
934
935   // Draw successfully, this starts a new frame.
936   client.SetNeedsCommitOnNextDraw();
937   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
938   scheduler->OnBeginImplFrameDeadline();
939   EXPECT_EQ(1, client.num_draws());
940
941   scheduler->SetNeedsRedraw();
942   EXPECT_TRUE(scheduler->RedrawPending());
943   EXPECT_TRUE(client.needs_begin_impl_frame());
944
945   // Fail to draw, this should not start a frame.
946   client.SetDrawWillHappen(false);
947   client.SetNeedsCommitOnNextDraw();
948   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
949   scheduler->OnBeginImplFrameDeadline();
950   EXPECT_EQ(2, client.num_draws());
951 }
952
953 TEST(SchedulerTest, NoSwapWhenSwapFailsDuringForcedCommit) {
954   FakeSchedulerClient client;
955   SchedulerSettings default_scheduler_settings;
956   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
957
958   // Tell the client that it will fail to swap.
959   client.SetDrawWillHappen(true);
960   client.SetSwapWillHappenIfDrawHappens(false);
961
962   // Get the compositor to do a ScheduledActionDrawAndReadback.
963   scheduler->SetCanDraw(true);
964   scheduler->SetNeedsRedraw();
965   scheduler->SetNeedsForcedCommitForReadback();
966   scheduler->FinishCommit();
967   EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
968 }
969
970 TEST(SchedulerTest, BackToBackReadbackAllowed) {
971   // Some clients call readbacks twice in a row before the replacement
972   // commit comes in.  Make sure it is allowed.
973   FakeSchedulerClient client;
974   SchedulerSettings default_scheduler_settings;
975   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
976
977   // Get the compositor to do 2 ScheduledActionDrawAndReadbacks before
978   // the replacement commit comes in.
979   scheduler->SetCanDraw(true);
980   scheduler->SetNeedsRedraw();
981   scheduler->SetNeedsForcedCommitForReadback();
982   scheduler->FinishCommit();
983   EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
984
985   client.Reset();
986   scheduler->SetNeedsForcedCommitForReadback();
987   scheduler->FinishCommit();
988   EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
989
990   // The replacement commit comes in after 2 readbacks.
991   client.Reset();
992   scheduler->FinishCommit();
993 }
994
995
996 class SchedulerClientNeedsManageTilesInDraw : public FakeSchedulerClient {
997  public:
998   virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
999       OVERRIDE {
1000     scheduler_->SetNeedsManageTiles();
1001     return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
1002   }
1003 };
1004
1005 // Test manage tiles is independant of draws.
1006 TEST(SchedulerTest, ManageTiles) {
1007   SchedulerClientNeedsManageTilesInDraw client;
1008   SchedulerSettings default_scheduler_settings;
1009   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
1010   scheduler->SetCanStart();
1011   scheduler->SetVisible(true);
1012   scheduler->SetCanDraw(true);
1013   InitializeOutputSurfaceAndFirstCommit(scheduler);
1014
1015   // Request both draw and manage tiles. ManageTiles shouldn't
1016   // be trigged until BeginImplFrame.
1017   client.Reset();
1018   scheduler->SetNeedsManageTiles();
1019   scheduler->SetNeedsRedraw();
1020   EXPECT_TRUE(scheduler->RedrawPending());
1021   EXPECT_TRUE(scheduler->ManageTilesPending());
1022   EXPECT_TRUE(client.needs_begin_impl_frame());
1023   EXPECT_EQ(0, client.num_draws());
1024   EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
1025   EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1026
1027   // We have no immediate actions to perform, so the BeginImplFrame should post
1028   // the deadline task.
1029   client.Reset();
1030   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1031   EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1032
1033   // On the deadline, he actions should have occured in the right order.
1034   client.Reset();
1035   scheduler->OnBeginImplFrameDeadline();
1036   EXPECT_EQ(1, client.num_draws());
1037   EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1038   EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
1039   EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
1040             client.ActionIndex("ScheduledActionManageTiles"));
1041   EXPECT_FALSE(scheduler->RedrawPending());
1042   EXPECT_FALSE(scheduler->ManageTilesPending());
1043
1044   // Request a draw. We don't need a ManageTiles yet.
1045   client.Reset();
1046   scheduler->SetNeedsRedraw();
1047   EXPECT_TRUE(scheduler->RedrawPending());
1048   EXPECT_FALSE(scheduler->ManageTilesPending());
1049   EXPECT_TRUE(client.needs_begin_impl_frame());
1050   EXPECT_EQ(0, client.num_draws());
1051
1052   // We have no immediate actions to perform, so the BeginImplFrame should post
1053   // the deadline task.
1054   client.Reset();
1055   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1056   EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1057
1058   // Draw. The draw will trigger SetNeedsManageTiles, and
1059   // then the ManageTiles action will be triggered after the Draw.
1060   // Afterwards, neither a draw nor ManageTiles are pending.
1061   client.Reset();
1062   scheduler->OnBeginImplFrameDeadline();
1063   EXPECT_EQ(1, client.num_draws());
1064   EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1065   EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
1066   EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
1067             client.ActionIndex("ScheduledActionManageTiles"));
1068   EXPECT_FALSE(scheduler->RedrawPending());
1069   EXPECT_FALSE(scheduler->ManageTilesPending());
1070
1071   // We need a BeginImplFrame where we don't swap to go idle.
1072   client.Reset();
1073   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1074   EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1075   client.Reset();
1076   scheduler->OnBeginImplFrameDeadline();
1077   EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);;
1078   EXPECT_EQ(0, client.num_draws());
1079
1080   // Now trigger a ManageTiles outside of a draw. We will then need
1081   // a begin-frame for the ManageTiles, but we don't need a draw.
1082   client.Reset();
1083   EXPECT_FALSE(client.needs_begin_impl_frame());
1084   scheduler->SetNeedsManageTiles();
1085   EXPECT_TRUE(client.needs_begin_impl_frame());
1086   EXPECT_TRUE(scheduler->ManageTilesPending());
1087   EXPECT_FALSE(scheduler->RedrawPending());
1088
1089   // BeginImplFrame. There will be no draw, only ManageTiles.
1090   client.Reset();
1091   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1092   EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1093   client.Reset();
1094   scheduler->OnBeginImplFrameDeadline();
1095   EXPECT_EQ(0, client.num_draws());
1096   EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1097   EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
1098 }
1099
1100 // Test that ManageTiles only happens once per frame.  If an external caller
1101 // initiates it, then the state machine should not ManageTiles on that frame.
1102 TEST(SchedulerTest, ManageTilesOncePerFrame) {
1103   FakeSchedulerClient client;
1104   SchedulerSettings default_scheduler_settings;
1105   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
1106   scheduler->SetCanStart();
1107   scheduler->SetVisible(true);
1108   scheduler->SetCanDraw(true);
1109   InitializeOutputSurfaceAndFirstCommit(scheduler);
1110
1111   // If DidManageTiles during a frame, then ManageTiles should not occur again.
1112   scheduler->SetNeedsManageTiles();
1113   scheduler->SetNeedsRedraw();
1114   client.Reset();
1115   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1116   EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1117
1118   EXPECT_TRUE(scheduler->ManageTilesPending());
1119   scheduler->DidManageTiles();  // An explicit ManageTiles.
1120   EXPECT_FALSE(scheduler->ManageTilesPending());
1121
1122   client.Reset();
1123   scheduler->OnBeginImplFrameDeadline();
1124   EXPECT_EQ(1, client.num_draws());
1125   EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1126   EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
1127   EXPECT_FALSE(scheduler->RedrawPending());
1128   EXPECT_FALSE(scheduler->ManageTilesPending());
1129
1130   // Next frame without DidManageTiles should ManageTiles with draw.
1131   scheduler->SetNeedsManageTiles();
1132   scheduler->SetNeedsRedraw();
1133   client.Reset();
1134   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1135   EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1136
1137   client.Reset();
1138   scheduler->OnBeginImplFrameDeadline();
1139   EXPECT_EQ(1, client.num_draws());
1140   EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1141   EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
1142   EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
1143             client.ActionIndex("ScheduledActionManageTiles"));
1144   EXPECT_FALSE(scheduler->RedrawPending());
1145   EXPECT_FALSE(scheduler->ManageTilesPending());
1146   scheduler->DidManageTiles();  // Corresponds to ScheduledActionManageTiles
1147
1148   // If we get another DidManageTiles within the same frame, we should
1149   // not ManageTiles on the next frame.
1150   scheduler->DidManageTiles();  // An explicit ManageTiles.
1151   scheduler->SetNeedsManageTiles();
1152   scheduler->SetNeedsRedraw();
1153   client.Reset();
1154   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1155   EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1156
1157   EXPECT_TRUE(scheduler->ManageTilesPending());
1158
1159   client.Reset();
1160   scheduler->OnBeginImplFrameDeadline();
1161   EXPECT_EQ(1, client.num_draws());
1162   EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1163   EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
1164   EXPECT_FALSE(scheduler->RedrawPending());
1165
1166   // If we get another DidManageTiles, we should not ManageTiles on the next
1167   // frame. This verifies we don't alternate calling ManageTiles once and twice.
1168   EXPECT_TRUE(scheduler->ManageTilesPending());
1169   scheduler->DidManageTiles();  // An explicit ManageTiles.
1170   EXPECT_FALSE(scheduler->ManageTilesPending());
1171   scheduler->SetNeedsManageTiles();
1172   scheduler->SetNeedsRedraw();
1173   client.Reset();
1174   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1175   EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1176
1177   EXPECT_TRUE(scheduler->ManageTilesPending());
1178
1179   client.Reset();
1180   scheduler->OnBeginImplFrameDeadline();
1181   EXPECT_EQ(1, client.num_draws());
1182   EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1183   EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
1184   EXPECT_FALSE(scheduler->RedrawPending());
1185
1186   // Next frame without DidManageTiles should ManageTiles with draw.
1187   scheduler->SetNeedsManageTiles();
1188   scheduler->SetNeedsRedraw();
1189   client.Reset();
1190   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1191   EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
1192
1193   client.Reset();
1194   scheduler->OnBeginImplFrameDeadline();
1195   EXPECT_EQ(1, client.num_draws());
1196   EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
1197   EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
1198   EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
1199             client.ActionIndex("ScheduledActionManageTiles"));
1200   EXPECT_FALSE(scheduler->RedrawPending());
1201   EXPECT_FALSE(scheduler->ManageTilesPending());
1202   scheduler->DidManageTiles();  // Corresponds to ScheduledActionManageTiles
1203 }
1204
1205 class SchedulerClientWithFixedEstimates : public FakeSchedulerClient {
1206  public:
1207   SchedulerClientWithFixedEstimates(
1208       base::TimeDelta draw_duration,
1209       base::TimeDelta begin_main_frame_to_commit_duration,
1210       base::TimeDelta commit_to_activate_duration)
1211       : draw_duration_(draw_duration),
1212         begin_main_frame_to_commit_duration_(
1213             begin_main_frame_to_commit_duration),
1214         commit_to_activate_duration_(commit_to_activate_duration) {}
1215
1216   virtual base::TimeDelta DrawDurationEstimate() OVERRIDE {
1217     return draw_duration_;
1218   }
1219   virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE {
1220     return begin_main_frame_to_commit_duration_;
1221   }
1222   virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE {
1223     return commit_to_activate_duration_;
1224   }
1225
1226  private:
1227     base::TimeDelta draw_duration_;
1228     base::TimeDelta begin_main_frame_to_commit_duration_;
1229     base::TimeDelta commit_to_activate_duration_;
1230 };
1231
1232 void MainFrameInHighLatencyMode(int64 begin_main_frame_to_commit_estimate_in_ms,
1233                                 int64 commit_to_activate_estimate_in_ms,
1234                                 bool should_send_begin_main_frame) {
1235   // Set up client with specified estimates (draw duration is set to 1).
1236   SchedulerClientWithFixedEstimates client(
1237       base::TimeDelta::FromMilliseconds(1),
1238       base::TimeDelta::FromMilliseconds(
1239           begin_main_frame_to_commit_estimate_in_ms),
1240       base::TimeDelta::FromMilliseconds(commit_to_activate_estimate_in_ms));
1241   SchedulerSettings scheduler_settings;
1242   scheduler_settings.deadline_scheduling_enabled = true;
1243   scheduler_settings.switch_to_low_latency_if_possible = true;
1244   Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
1245   scheduler->SetCanStart();
1246   scheduler->SetVisible(true);
1247   scheduler->SetCanDraw(true);
1248   InitializeOutputSurfaceAndFirstCommit(scheduler);
1249
1250   // Impl thread hits deadline before commit finishes.
1251   client.Reset();
1252   scheduler->SetNeedsCommit();
1253   EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode());
1254   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1255   EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode());
1256   scheduler->OnBeginImplFrameDeadline();
1257   EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
1258   scheduler->FinishCommit();
1259   EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
1260   EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
1261
1262   client.Reset();
1263   scheduler->SetNeedsCommit();
1264   EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
1265   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
1266   EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
1267   scheduler->OnBeginImplFrameDeadline();
1268   EXPECT_EQ(scheduler->MainThreadIsInHighLatencyMode(),
1269             should_send_begin_main_frame);
1270   EXPECT_EQ(client.HasAction("ScheduledActionSendBeginMainFrame"),
1271             should_send_begin_main_frame);
1272 }
1273
1274 TEST(SchedulerTest,
1275     SkipMainFrameIfHighLatencyAndCanCommitAndActivateBeforeDeadline) {
1276   // Set up client so that estimates indicate that we can commit and activate
1277   // before the deadline (~8ms by default).
1278   MainFrameInHighLatencyMode(1, 1, false);
1279 }
1280
1281 TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanCommitTooLong) {
1282   // Set up client so that estimates indicate that the commit cannot finish
1283   // before the deadline (~8ms by default).
1284   MainFrameInHighLatencyMode(10, 1, true);
1285 }
1286
1287 TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanActivateTooLong) {
1288   // Set up client so that estimates indicate that the activate cannot finish
1289   // before the deadline (~8ms by default).
1290   MainFrameInHighLatencyMode(1, 10, true);
1291 }
1292
1293 void SpinForMillis(int millis) {
1294   base::RunLoop run_loop;
1295   base::MessageLoop::current()->PostDelayedTask(
1296       FROM_HERE,
1297       run_loop.QuitClosure(),
1298       base::TimeDelta::FromMilliseconds(millis));
1299   run_loop.Run();
1300 }
1301
1302 TEST(SchedulerTest, PollForCommitCompletion) {
1303   FakeSchedulerClient client;
1304   client.set_log_anticipated_draw_time_change(true);
1305   SchedulerSettings settings = SchedulerSettings();
1306   settings.throttle_frame_production = false;
1307   Scheduler* scheduler = client.CreateScheduler(settings);
1308
1309   scheduler->SetCanDraw(true);
1310   scheduler->SetCanStart();
1311   scheduler->SetVisible(true);
1312   scheduler->DidCreateAndInitializeOutputSurface();
1313
1314   scheduler->SetNeedsCommit();
1315   EXPECT_TRUE(scheduler->CommitPending());
1316   scheduler->FinishCommit();
1317   scheduler->SetNeedsRedraw();
1318   BeginFrameArgs impl_frame_args = BeginFrameArgs::CreateForTesting();
1319   const int interval = 1;
1320   impl_frame_args.interval = base::TimeDelta::FromMilliseconds(interval);
1321   scheduler->BeginImplFrame(impl_frame_args);
1322   scheduler->OnBeginImplFrameDeadline();
1323
1324   // At this point, we've drawn a frame.  Start another commit, but hold off on
1325   // the FinishCommit for now.
1326   EXPECT_FALSE(scheduler->CommitPending());
1327   scheduler->SetNeedsCommit();
1328   EXPECT_TRUE(scheduler->CommitPending());
1329
1330   // Spin the event loop a few times and make sure we get more
1331   // DidAnticipateDrawTimeChange calls every time.
1332   int actions_so_far = client.num_actions_();
1333
1334   // Does three iterations to make sure that the timer is properly repeating.
1335   for (int i = 0; i < 3; ++i) {
1336     // Wait for 2x the frame interval to match
1337     // Scheduler::advance_commit_state_timer_'s rate.
1338     SpinForMillis(interval * 2);
1339     EXPECT_GT(client.num_actions_(), actions_so_far);
1340     EXPECT_STREQ(client.Action(client.num_actions_() - 1),
1341                  "DidAnticipatedDrawTimeChange");
1342     actions_so_far = client.num_actions_();
1343   }
1344 }
1345
1346 }  // namespace
1347 }  // namespace cc