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