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/debug/trace_event.h"
10#include "base/logging.h"
11#include "base/memory/scoped_vector.h"
12#include "base/message_loop/message_loop.h"
13#include "base/run_loop.h"
14#include "base/time/time.h"
15#include "cc/test/begin_frame_args_test.h"
16#include "cc/test/ordered_simple_task_runner.h"
17#include "cc/test/scheduler_test_common.h"
18#include "testing/gmock/include/gmock/gmock.h"
19#include "testing/gtest/include/gtest/gtest.h"
20
21#define EXPECT_ACTION(action, client, action_index, expected_num_actions) \
22  do {                                                                    \
23    EXPECT_EQ(expected_num_actions, client.num_actions_());               \
24    if (action_index >= 0) {                                              \
25      ASSERT_LT(action_index, client.num_actions_()) << scheduler;        \
26      EXPECT_STREQ(action, client.Action(action_index));                  \
27    }                                                                     \
28    for (int i = expected_num_actions; i < client.num_actions_(); ++i)    \
29      ADD_FAILURE() << "Unexpected action: " << client.Action(i)          \
30                    << " with state:\n" << client.StateForAction(i);      \
31  } while (false)
32
33#define EXPECT_NO_ACTION(client) EXPECT_ACTION("", client, -1, 0)
34
35#define EXPECT_SINGLE_ACTION(action, client) \
36  EXPECT_ACTION(action, client, 0, 1)
37
38namespace cc {
39namespace {
40
41class FakeSchedulerClient;
42
43void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler,
44                                           FakeSchedulerClient* client);
45
46class FakeSchedulerClient : public SchedulerClient {
47 public:
48  FakeSchedulerClient()
49      : needs_begin_frame_(false),
50        automatic_swap_ack_(true),
51        swap_contains_incomplete_tile_(false),
52        redraw_will_happen_if_update_visible_tiles_happens_(false),
53        now_src_(TestNowSource::Create()) {
54    Reset();
55  }
56
57  void Reset() {
58    actions_.clear();
59    states_.clear();
60    draw_will_happen_ = true;
61    swap_will_happen_if_draw_happens_ = true;
62    num_draws_ = 0;
63    log_anticipated_draw_time_change_ = false;
64  }
65
66  TestScheduler* CreateScheduler(const SchedulerSettings& settings) {
67    scheduler_ = TestScheduler::Create(now_src_, this, settings, 0);
68    // Fail if we need to run 100 tasks in a row.
69    task_runner().SetRunTaskLimit(100);
70    return scheduler_.get();
71  }
72
73  // Most tests don't care about DidAnticipatedDrawTimeChange, so only record it
74  // for tests that do.
75  void set_log_anticipated_draw_time_change(bool log) {
76    log_anticipated_draw_time_change_ = log;
77  }
78  bool needs_begin_frame() { return needs_begin_frame_; }
79  int num_draws() const { return num_draws_; }
80  int num_actions_() const { return static_cast<int>(actions_.size()); }
81  const char* Action(int i) const { return actions_[i]; }
82  std::string StateForAction(int i) const { return states_[i]->ToString(); }
83  base::TimeTicks posted_begin_impl_frame_deadline() const {
84    return posted_begin_impl_frame_deadline_;
85  }
86
87  void AdvanceFrame() {
88    bool external_begin_frame =
89        scheduler_->settings().begin_frame_scheduling_enabled &&
90        scheduler_->settings().throttle_frame_production;
91
92    if (external_begin_frame) {
93      scheduler_->BeginFrame(CreateBeginFrameArgsForTesting(now_src_));
94    }
95
96    EXPECT_TRUE(task_runner().RunTasksWhile(ImplFrameDeadlinePending(false)));
97    EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
98  }
99
100  OrderedSimpleTaskRunner& task_runner() { return scheduler_->task_runner(); }
101  TestNowSource* now_src() { return now_src_.get(); }
102
103  int ActionIndex(const char* action) const {
104    for (size_t i = 0; i < actions_.size(); i++)
105      if (!strcmp(actions_[i], action))
106        return i;
107    return -1;
108  }
109
110  void SetSwapContainsIncompleteTile(bool contain) {
111    swap_contains_incomplete_tile_ = contain;
112  }
113
114  bool HasAction(const char* action) const {
115    return ActionIndex(action) >= 0;
116  }
117
118  void SetDrawWillHappen(bool draw_will_happen) {
119    draw_will_happen_ = draw_will_happen;
120  }
121  void SetSwapWillHappenIfDrawHappens(bool swap_will_happen_if_draw_happens) {
122    swap_will_happen_if_draw_happens_ = swap_will_happen_if_draw_happens;
123  }
124  void SetAutomaticSwapAck(bool automatic_swap_ack) {
125    automatic_swap_ack_ = automatic_swap_ack;
126  }
127  void SetRedrawWillHappenIfUpdateVisibleTilesHappens(bool redraw) {
128    redraw_will_happen_if_update_visible_tiles_happens_ = redraw;
129  }
130  // SchedulerClient implementation.
131  virtual void SetNeedsBeginFrame(bool enable) OVERRIDE {
132    actions_.push_back("SetNeedsBeginFrame");
133    states_.push_back(scheduler_->AsValue());
134    needs_begin_frame_ = enable;
135  }
136  virtual void WillBeginImplFrame(const BeginFrameArgs& args) OVERRIDE {
137    actions_.push_back("WillBeginImplFrame");
138    states_.push_back(scheduler_->AsValue());
139  }
140  virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {
141    actions_.push_back("ScheduledActionSendBeginMainFrame");
142    states_.push_back(scheduler_->AsValue());
143  }
144  virtual void ScheduledActionAnimate() OVERRIDE {
145    actions_.push_back("ScheduledActionAnimate");
146    states_.push_back(scheduler_->AsValue());
147  }
148  virtual DrawResult ScheduledActionDrawAndSwapIfPossible() OVERRIDE {
149    actions_.push_back("ScheduledActionDrawAndSwapIfPossible");
150    states_.push_back(scheduler_->AsValue());
151    num_draws_++;
152    DrawResult result =
153        draw_will_happen_ ? DRAW_SUCCESS : DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
154    bool swap_will_happen =
155        draw_will_happen_ && swap_will_happen_if_draw_happens_;
156    if (swap_will_happen) {
157      scheduler_->DidSwapBuffers();
158      if (swap_contains_incomplete_tile_) {
159        scheduler_->SetSwapUsedIncompleteTile(true);
160        swap_contains_incomplete_tile_ = false;
161      } else {
162        scheduler_->SetSwapUsedIncompleteTile(false);
163      }
164
165      if (automatic_swap_ack_)
166        scheduler_->DidSwapBuffersComplete();
167    }
168    return result;
169  }
170  virtual DrawResult ScheduledActionDrawAndSwapForced() OVERRIDE {
171    actions_.push_back("ScheduledActionDrawAndSwapForced");
172    states_.push_back(scheduler_->AsValue());
173    return DRAW_SUCCESS;
174  }
175  virtual void ScheduledActionCommit() OVERRIDE {
176    actions_.push_back("ScheduledActionCommit");
177    states_.push_back(scheduler_->AsValue());
178  }
179  virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE {
180    actions_.push_back("ScheduledActionUpdateVisibleTiles");
181    states_.push_back(scheduler_->AsValue());
182    if (redraw_will_happen_if_update_visible_tiles_happens_)
183      scheduler_->SetNeedsRedraw();
184  }
185  virtual void ScheduledActionActivateSyncTree() OVERRIDE {
186    actions_.push_back("ScheduledActionActivateSyncTree");
187    states_.push_back(scheduler_->AsValue());
188  }
189  virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {
190    actions_.push_back("ScheduledActionBeginOutputSurfaceCreation");
191    states_.push_back(scheduler_->AsValue());
192  }
193  virtual void ScheduledActionManageTiles() OVERRIDE {
194    actions_.push_back("ScheduledActionManageTiles");
195    states_.push_back(scheduler_->AsValue());
196  }
197  virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {
198    if (log_anticipated_draw_time_change_)
199      actions_.push_back("DidAnticipatedDrawTimeChange");
200  }
201  virtual base::TimeDelta DrawDurationEstimate() OVERRIDE {
202    return base::TimeDelta();
203  }
204  virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE {
205    return base::TimeDelta();
206  }
207  virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE {
208    return base::TimeDelta();
209  }
210
211  virtual void DidBeginImplFrameDeadline() OVERRIDE {}
212
213  base::Callback<bool(void)> ImplFrameDeadlinePending(bool state) {
214    return base::Bind(&FakeSchedulerClient::ImplFrameDeadlinePendingCallback,
215                      base::Unretained(this),
216                      state);
217  }
218
219 protected:
220  bool ImplFrameDeadlinePendingCallback(bool state) {
221    return scheduler_->BeginImplFrameDeadlinePending() == state;
222  }
223
224  bool needs_begin_frame_;
225  bool draw_will_happen_;
226  bool swap_will_happen_if_draw_happens_;
227  bool automatic_swap_ack_;
228  int num_draws_;
229  bool log_anticipated_draw_time_change_;
230  bool swap_contains_incomplete_tile_;
231  bool redraw_will_happen_if_update_visible_tiles_happens_;
232  base::TimeTicks posted_begin_impl_frame_deadline_;
233  std::vector<const char*> actions_;
234  std::vector<scoped_refptr<base::debug::ConvertableToTraceFormat> > states_;
235  scoped_ptr<TestScheduler> scheduler_;
236  scoped_refptr<TestNowSource> now_src_;
237};
238
239void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler,
240                                           FakeSchedulerClient* client) {
241  TRACE_EVENT0("cc",
242               "SchedulerUnitTest::InitializeOutputSurfaceAndFirstCommit");
243
244  scheduler->DidCreateAndInitializeOutputSurface();
245  scheduler->SetNeedsCommit();
246  scheduler->NotifyBeginMainFrameStarted();
247  scheduler->NotifyReadyToCommit();
248  if (scheduler->settings().impl_side_painting)
249    scheduler->NotifyReadyToActivate();
250
251  // Go through the motions to draw the commit.
252  client->AdvanceFrame();
253
254  // Run the posted deadline task.
255  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
256  client->task_runner().RunTasksWhile(client->ImplFrameDeadlinePending(true));
257  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
258
259  // We need another BeginImplFrame so Scheduler calls
260  // SetNeedsBeginFrame(false).
261  client->AdvanceFrame();
262
263  // Run the posted deadline task.
264  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
265  client->task_runner().RunTasksWhile(client->ImplFrameDeadlinePending(true));
266  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
267}
268
269TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginImplFrame) {
270  FakeSchedulerClient client;
271  SchedulerSettings default_scheduler_settings;
272  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
273  scheduler->SetCanStart();
274  scheduler->SetVisible(true);
275  scheduler->SetCanDraw(true);
276
277  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
278  client.Reset();
279  scheduler->DidCreateAndInitializeOutputSurface();
280  EXPECT_NO_ACTION(client);
281}
282
283TEST(SchedulerTest, RequestCommit) {
284  FakeSchedulerClient client;
285  SchedulerSettings scheduler_settings;
286  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
287  scheduler->SetCanStart();
288  scheduler->SetVisible(true);
289  scheduler->SetCanDraw(true);
290
291  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
292  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
293
294  // SetNeedsCommit should begin the frame on the next BeginImplFrame.
295  client.Reset();
296  scheduler->SetNeedsCommit();
297  EXPECT_TRUE(client.needs_begin_frame());
298  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
299  client.Reset();
300
301  client.AdvanceFrame();
302  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
303  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
304  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
305  EXPECT_TRUE(client.needs_begin_frame());
306  client.Reset();
307
308  // If we don't swap on the deadline, we wait for the next BeginFrame.
309  client.task_runner().RunPendingTasks();  // Run posted deadline.
310  EXPECT_NO_ACTION(client);
311  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
312  EXPECT_TRUE(client.needs_begin_frame());
313  client.Reset();
314
315  // NotifyReadyToCommit should trigger the commit.
316  scheduler->NotifyBeginMainFrameStarted();
317  scheduler->NotifyReadyToCommit();
318  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
319  EXPECT_TRUE(client.needs_begin_frame());
320  client.Reset();
321
322  // BeginImplFrame should prepare the draw.
323  client.AdvanceFrame();
324  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
325  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
326  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
327  EXPECT_TRUE(client.needs_begin_frame());
328  client.Reset();
329
330  // BeginImplFrame deadline should draw.
331  client.task_runner().RunPendingTasks();  // Run posted deadline.
332  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
333  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
334  EXPECT_TRUE(client.needs_begin_frame());
335  client.Reset();
336
337  // The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
338  // to avoid excessive toggles.
339  client.AdvanceFrame();
340  EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
341  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
342  client.Reset();
343
344  client.task_runner().RunPendingTasks();  // Run posted deadline.
345  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
346  EXPECT_FALSE(client.needs_begin_frame());
347  client.Reset();
348}
349
350TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
351  FakeSchedulerClient client;
352  SchedulerSettings scheduler_settings;
353  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
354  scheduler->SetCanStart();
355  scheduler->SetVisible(true);
356  scheduler->SetCanDraw(true);
357
358  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
359  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
360  client.Reset();
361
362  // SetNeedsCommit should begin the frame.
363  scheduler->SetNeedsCommit();
364  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
365
366  client.Reset();
367  client.AdvanceFrame();
368  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
369  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
370  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
371
372  EXPECT_TRUE(client.needs_begin_frame());
373  client.Reset();
374
375  // Now SetNeedsCommit again. Calling here means we need a second commit.
376  scheduler->SetNeedsCommit();
377  EXPECT_EQ(client.num_actions_(), 0);
378  client.Reset();
379
380  // Finish the first commit.
381  scheduler->NotifyBeginMainFrameStarted();
382  scheduler->NotifyReadyToCommit();
383  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
384  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
385  client.Reset();
386  client.task_runner().RunPendingTasks();  // Run posted deadline.
387  EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
388  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
389  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
390
391  // Because we just swapped, the Scheduler should also request the next
392  // BeginImplFrame from the OutputSurface.
393  EXPECT_TRUE(client.needs_begin_frame());
394  client.Reset();
395  // Since another commit is needed, the next BeginImplFrame should initiate
396  // the second commit.
397  client.AdvanceFrame();
398  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
399  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
400  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
401  client.Reset();
402
403  // Finishing the commit before the deadline should post a new deadline task
404  // to trigger the deadline early.
405  scheduler->NotifyBeginMainFrameStarted();
406  scheduler->NotifyReadyToCommit();
407  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
408  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
409  client.Reset();
410  client.task_runner().RunPendingTasks();  // Run posted deadline.
411  EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
412  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
413  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
414  EXPECT_TRUE(client.needs_begin_frame());
415  client.Reset();
416
417  // On the next BeginImplFrame, verify we go back to a quiescent state and
418  // no longer request BeginImplFrames.
419  client.AdvanceFrame();
420  client.task_runner().RunPendingTasks();  // Run posted deadline.
421  EXPECT_FALSE(client.needs_begin_frame());
422  client.Reset();
423}
424
425class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
426 public:
427  virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {}
428  virtual DrawResult ScheduledActionDrawAndSwapIfPossible()
429      OVERRIDE {
430    // Only SetNeedsRedraw the first time this is called
431    if (!num_draws_)
432      scheduler_->SetNeedsRedraw();
433    return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
434  }
435
436  virtual DrawResult ScheduledActionDrawAndSwapForced() OVERRIDE {
437    NOTREACHED();
438    return DRAW_SUCCESS;
439  }
440
441  virtual void ScheduledActionCommit() OVERRIDE {}
442  virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {}
443  virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {}
444};
445
446// Tests for two different situations:
447// 1. the scheduler dropping SetNeedsRedraw requests that happen inside
448//    a ScheduledActionDrawAndSwap
449// 2. the scheduler drawing twice inside a single tick
450TEST(SchedulerTest, RequestRedrawInsideDraw) {
451  SchedulerClientThatsetNeedsDrawInsideDraw client;
452  SchedulerSettings default_scheduler_settings;
453  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
454  scheduler->SetCanStart();
455  scheduler->SetVisible(true);
456  scheduler->SetCanDraw(true);
457  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
458  client.Reset();
459
460  scheduler->SetNeedsRedraw();
461  EXPECT_TRUE(scheduler->RedrawPending());
462  EXPECT_TRUE(client.needs_begin_frame());
463  EXPECT_EQ(0, client.num_draws());
464
465  client.AdvanceFrame();
466  client.task_runner().RunPendingTasks();  // Run posted deadline.
467  EXPECT_EQ(1, client.num_draws());
468  EXPECT_TRUE(scheduler->RedrawPending());
469  EXPECT_TRUE(client.needs_begin_frame());
470
471  client.AdvanceFrame();
472  client.task_runner().RunPendingTasks();  // Run posted deadline.
473  EXPECT_EQ(2, client.num_draws());
474  EXPECT_FALSE(scheduler->RedrawPending());
475  EXPECT_TRUE(client.needs_begin_frame());
476
477  // We stop requesting BeginImplFrames after a BeginImplFrame where we don't
478  // swap.
479  client.AdvanceFrame();
480  client.task_runner().RunPendingTasks();  // Run posted deadline.
481  EXPECT_EQ(2, client.num_draws());
482  EXPECT_FALSE(scheduler->RedrawPending());
483  EXPECT_FALSE(client.needs_begin_frame());
484}
485
486// Test that requesting redraw inside a failed draw doesn't lose the request.
487TEST(SchedulerTest, RequestRedrawInsideFailedDraw) {
488  SchedulerClientThatsetNeedsDrawInsideDraw client;
489  SchedulerSettings default_scheduler_settings;
490  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
491  scheduler->SetCanStart();
492  scheduler->SetVisible(true);
493  scheduler->SetCanDraw(true);
494  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
495  client.Reset();
496
497  client.SetDrawWillHappen(false);
498
499  scheduler->SetNeedsRedraw();
500  EXPECT_TRUE(scheduler->RedrawPending());
501  EXPECT_TRUE(client.needs_begin_frame());
502  EXPECT_EQ(0, client.num_draws());
503
504  // Fail the draw.
505  client.AdvanceFrame();
506  client.task_runner().RunPendingTasks();  // Run posted deadline.
507  EXPECT_EQ(1, client.num_draws());
508
509  // We have a commit pending and the draw failed, and we didn't lose the redraw
510  // request.
511  EXPECT_TRUE(scheduler->CommitPending());
512  EXPECT_TRUE(scheduler->RedrawPending());
513  EXPECT_TRUE(client.needs_begin_frame());
514
515  // Fail the draw again.
516  client.AdvanceFrame();
517  client.task_runner().RunPendingTasks();  // Run posted deadline.
518  EXPECT_EQ(2, client.num_draws());
519  EXPECT_TRUE(scheduler->CommitPending());
520  EXPECT_TRUE(scheduler->RedrawPending());
521  EXPECT_TRUE(client.needs_begin_frame());
522
523  // Draw successfully.
524  client.SetDrawWillHappen(true);
525  client.AdvanceFrame();
526  client.task_runner().RunPendingTasks();  // Run posted deadline.
527  EXPECT_EQ(3, client.num_draws());
528  EXPECT_TRUE(scheduler->CommitPending());
529  EXPECT_FALSE(scheduler->RedrawPending());
530  EXPECT_TRUE(client.needs_begin_frame());
531}
532
533class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
534 public:
535  SchedulerClientThatSetNeedsCommitInsideDraw()
536      : set_needs_commit_on_next_draw_(false) {}
537
538  virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {}
539  virtual DrawResult ScheduledActionDrawAndSwapIfPossible()
540      OVERRIDE {
541    // Only SetNeedsCommit the first time this is called
542    if (set_needs_commit_on_next_draw_) {
543      scheduler_->SetNeedsCommit();
544      set_needs_commit_on_next_draw_ = false;
545    }
546    return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
547  }
548
549  virtual DrawResult ScheduledActionDrawAndSwapForced() OVERRIDE {
550    NOTREACHED();
551    return DRAW_SUCCESS;
552  }
553
554  virtual void ScheduledActionCommit() OVERRIDE {}
555  virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {}
556  virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {}
557
558  void SetNeedsCommitOnNextDraw() { set_needs_commit_on_next_draw_ = true; }
559
560 private:
561  bool set_needs_commit_on_next_draw_;
562};
563
564// Tests for the scheduler infinite-looping on SetNeedsCommit requests that
565// happen inside a ScheduledActionDrawAndSwap
566TEST(SchedulerTest, RequestCommitInsideDraw) {
567  SchedulerClientThatSetNeedsCommitInsideDraw client;
568  SchedulerSettings default_scheduler_settings;
569  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
570  scheduler->SetCanStart();
571  scheduler->SetVisible(true);
572  scheduler->SetCanDraw(true);
573  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
574  client.Reset();
575
576  EXPECT_FALSE(client.needs_begin_frame());
577  scheduler->SetNeedsRedraw();
578  EXPECT_TRUE(scheduler->RedrawPending());
579  EXPECT_EQ(0, client.num_draws());
580  EXPECT_TRUE(client.needs_begin_frame());
581
582  client.SetNeedsCommitOnNextDraw();
583  client.AdvanceFrame();
584  client.SetNeedsCommitOnNextDraw();
585  client.task_runner().RunPendingTasks();  // Run posted deadline.
586  EXPECT_EQ(1, client.num_draws());
587  EXPECT_TRUE(scheduler->CommitPending());
588  EXPECT_TRUE(client.needs_begin_frame());
589  scheduler->NotifyBeginMainFrameStarted();
590  scheduler->NotifyReadyToCommit();
591
592  client.AdvanceFrame();
593  client.task_runner().RunPendingTasks();  // Run posted deadline.
594  EXPECT_EQ(2, client.num_draws());
595
596  EXPECT_FALSE(scheduler->RedrawPending());
597  EXPECT_FALSE(scheduler->CommitPending());
598  EXPECT_TRUE(client.needs_begin_frame());
599
600  // We stop requesting BeginImplFrames after a BeginImplFrame where we don't
601  // swap.
602  client.AdvanceFrame();
603  client.task_runner().RunPendingTasks();  // Run posted deadline.
604  EXPECT_EQ(2, client.num_draws());
605  EXPECT_FALSE(scheduler->RedrawPending());
606  EXPECT_FALSE(scheduler->CommitPending());
607  EXPECT_FALSE(client.needs_begin_frame());
608}
609
610// Tests that when a draw fails then the pending commit should not be dropped.
611TEST(SchedulerTest, RequestCommitInsideFailedDraw) {
612  SchedulerClientThatsetNeedsDrawInsideDraw client;
613  SchedulerSettings default_scheduler_settings;
614  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
615  scheduler->SetCanStart();
616  scheduler->SetVisible(true);
617  scheduler->SetCanDraw(true);
618  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
619  client.Reset();
620
621  client.SetDrawWillHappen(false);
622
623  scheduler->SetNeedsRedraw();
624  EXPECT_TRUE(scheduler->RedrawPending());
625  EXPECT_TRUE(client.needs_begin_frame());
626  EXPECT_EQ(0, client.num_draws());
627
628  // Fail the draw.
629  client.AdvanceFrame();
630  client.task_runner().RunPendingTasks();  // Run posted deadline.
631  EXPECT_EQ(1, client.num_draws());
632
633  // We have a commit pending and the draw failed, and we didn't lose the commit
634  // request.
635  EXPECT_TRUE(scheduler->CommitPending());
636  EXPECT_TRUE(scheduler->RedrawPending());
637  EXPECT_TRUE(client.needs_begin_frame());
638
639  // Fail the draw again.
640  client.AdvanceFrame();
641
642  client.task_runner().RunPendingTasks();  // Run posted deadline.
643  EXPECT_EQ(2, client.num_draws());
644  EXPECT_TRUE(scheduler->CommitPending());
645  EXPECT_TRUE(scheduler->RedrawPending());
646  EXPECT_TRUE(client.needs_begin_frame());
647
648  // Draw successfully.
649  client.SetDrawWillHappen(true);
650  client.AdvanceFrame();
651  client.task_runner().RunPendingTasks();  // Run posted deadline.
652  EXPECT_EQ(3, client.num_draws());
653  EXPECT_TRUE(scheduler->CommitPending());
654  EXPECT_FALSE(scheduler->RedrawPending());
655  EXPECT_TRUE(client.needs_begin_frame());
656}
657
658TEST(SchedulerTest, NoSwapWhenDrawFails) {
659  SchedulerClientThatSetNeedsCommitInsideDraw client;
660  SchedulerSettings default_scheduler_settings;
661  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
662  scheduler->SetCanStart();
663  scheduler->SetVisible(true);
664  scheduler->SetCanDraw(true);
665  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
666  client.Reset();
667
668  scheduler->SetNeedsRedraw();
669  EXPECT_TRUE(scheduler->RedrawPending());
670  EXPECT_TRUE(client.needs_begin_frame());
671  EXPECT_EQ(0, client.num_draws());
672
673  // Draw successfully, this starts a new frame.
674  client.SetNeedsCommitOnNextDraw();
675  client.AdvanceFrame();
676  client.task_runner().RunPendingTasks();  // Run posted deadline.
677  EXPECT_EQ(1, client.num_draws());
678
679  scheduler->SetNeedsRedraw();
680  EXPECT_TRUE(scheduler->RedrawPending());
681  EXPECT_TRUE(client.needs_begin_frame());
682
683  // Fail to draw, this should not start a frame.
684  client.SetDrawWillHappen(false);
685  client.SetNeedsCommitOnNextDraw();
686  client.AdvanceFrame();
687  client.task_runner().RunPendingTasks();  // Run posted deadline.
688  EXPECT_EQ(2, client.num_draws());
689}
690
691class SchedulerClientNeedsManageTilesInDraw : public FakeSchedulerClient {
692 public:
693  virtual DrawResult ScheduledActionDrawAndSwapIfPossible()
694      OVERRIDE {
695    scheduler_->SetNeedsManageTiles();
696    return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
697  }
698};
699
700// Test manage tiles is independant of draws.
701TEST(SchedulerTest, ManageTiles) {
702  SchedulerClientNeedsManageTilesInDraw client;
703  SchedulerSettings default_scheduler_settings;
704  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
705  scheduler->SetCanStart();
706  scheduler->SetVisible(true);
707  scheduler->SetCanDraw(true);
708  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
709
710  // Request both draw and manage tiles. ManageTiles shouldn't
711  // be trigged until BeginImplFrame.
712  client.Reset();
713  scheduler->SetNeedsManageTiles();
714  scheduler->SetNeedsRedraw();
715  EXPECT_TRUE(scheduler->RedrawPending());
716  EXPECT_TRUE(scheduler->ManageTilesPending());
717  EXPECT_TRUE(client.needs_begin_frame());
718  EXPECT_EQ(0, client.num_draws());
719  EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
720  EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
721
722  // We have no immediate actions to perform, so the BeginImplFrame should post
723  // the deadline task.
724  client.Reset();
725  client.AdvanceFrame();
726  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
727  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
728  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
729
730  // On the deadline, he actions should have occured in the right order.
731  client.Reset();
732  client.task_runner().RunPendingTasks();  // Run posted deadline.
733  EXPECT_EQ(1, client.num_draws());
734  EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
735  EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
736  EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
737            client.ActionIndex("ScheduledActionManageTiles"));
738  EXPECT_FALSE(scheduler->RedrawPending());
739  EXPECT_FALSE(scheduler->ManageTilesPending());
740  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
741
742  // Request a draw. We don't need a ManageTiles yet.
743  client.Reset();
744  scheduler->SetNeedsRedraw();
745  EXPECT_TRUE(scheduler->RedrawPending());
746  EXPECT_FALSE(scheduler->ManageTilesPending());
747  EXPECT_TRUE(client.needs_begin_frame());
748  EXPECT_EQ(0, client.num_draws());
749
750  // We have no immediate actions to perform, so the BeginImplFrame should post
751  // the deadline task.
752  client.Reset();
753  client.AdvanceFrame();
754  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
755  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
756  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
757
758  // Draw. The draw will trigger SetNeedsManageTiles, and
759  // then the ManageTiles action will be triggered after the Draw.
760  // Afterwards, neither a draw nor ManageTiles are pending.
761  client.Reset();
762  client.task_runner().RunPendingTasks();  // Run posted deadline.
763  EXPECT_EQ(1, client.num_draws());
764  EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
765  EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
766  EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
767            client.ActionIndex("ScheduledActionManageTiles"));
768  EXPECT_FALSE(scheduler->RedrawPending());
769  EXPECT_FALSE(scheduler->ManageTilesPending());
770  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
771
772  // We need a BeginImplFrame where we don't swap to go idle.
773  client.Reset();
774  client.AdvanceFrame();
775  EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
776  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
777  client.Reset();
778  client.task_runner().RunPendingTasks();  // Run posted deadline.
779  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
780  EXPECT_FALSE(client.needs_begin_frame());
781  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
782  EXPECT_EQ(0, client.num_draws());
783
784  // Now trigger a ManageTiles outside of a draw. We will then need
785  // a begin-frame for the ManageTiles, but we don't need a draw.
786  client.Reset();
787  EXPECT_FALSE(client.needs_begin_frame());
788  scheduler->SetNeedsManageTiles();
789  EXPECT_TRUE(client.needs_begin_frame());
790  EXPECT_TRUE(scheduler->ManageTilesPending());
791  EXPECT_FALSE(scheduler->RedrawPending());
792
793  // BeginImplFrame. There will be no draw, only ManageTiles.
794  client.Reset();
795  client.AdvanceFrame();
796  EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
797  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
798  client.Reset();
799  client.task_runner().RunPendingTasks();  // Run posted deadline.
800  EXPECT_EQ(0, client.num_draws());
801  EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
802  EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
803  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
804}
805
806// Test that ManageTiles only happens once per frame.  If an external caller
807// initiates it, then the state machine should not ManageTiles on that frame.
808TEST(SchedulerTest, ManageTilesOncePerFrame) {
809  FakeSchedulerClient client;
810  SchedulerSettings default_scheduler_settings;
811  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
812  scheduler->SetCanStart();
813  scheduler->SetVisible(true);
814  scheduler->SetCanDraw(true);
815  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
816
817  // If DidManageTiles during a frame, then ManageTiles should not occur again.
818  scheduler->SetNeedsManageTiles();
819  scheduler->SetNeedsRedraw();
820  client.Reset();
821  client.AdvanceFrame();
822  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
823  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
824  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
825
826  EXPECT_TRUE(scheduler->ManageTilesPending());
827  scheduler->DidManageTiles();  // An explicit ManageTiles.
828  EXPECT_FALSE(scheduler->ManageTilesPending());
829
830  client.Reset();
831  client.task_runner().RunPendingTasks();  // Run posted deadline.
832  EXPECT_EQ(1, client.num_draws());
833  EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
834  EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
835  EXPECT_FALSE(scheduler->RedrawPending());
836  EXPECT_FALSE(scheduler->ManageTilesPending());
837  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
838
839  // Next frame without DidManageTiles should ManageTiles with draw.
840  scheduler->SetNeedsManageTiles();
841  scheduler->SetNeedsRedraw();
842  client.Reset();
843  client.AdvanceFrame();
844  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
845  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
846  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
847
848  client.Reset();
849  client.task_runner().RunPendingTasks();  // Run posted deadline.
850  EXPECT_EQ(1, client.num_draws());
851  EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
852  EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
853  EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
854            client.ActionIndex("ScheduledActionManageTiles"));
855  EXPECT_FALSE(scheduler->RedrawPending());
856  EXPECT_FALSE(scheduler->ManageTilesPending());
857  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
858  scheduler->DidManageTiles();  // Corresponds to ScheduledActionManageTiles
859
860  // If we get another DidManageTiles within the same frame, we should
861  // not ManageTiles on the next frame.
862  scheduler->DidManageTiles();  // An explicit ManageTiles.
863  scheduler->SetNeedsManageTiles();
864  scheduler->SetNeedsRedraw();
865  client.Reset();
866  client.AdvanceFrame();
867  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
868  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
869  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
870
871  EXPECT_TRUE(scheduler->ManageTilesPending());
872
873  client.Reset();
874  client.task_runner().RunPendingTasks();  // Run posted deadline.
875  EXPECT_EQ(1, client.num_draws());
876  EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
877  EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
878  EXPECT_FALSE(scheduler->RedrawPending());
879  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
880
881  // If we get another DidManageTiles, we should not ManageTiles on the next
882  // frame. This verifies we don't alternate calling ManageTiles once and twice.
883  EXPECT_TRUE(scheduler->ManageTilesPending());
884  scheduler->DidManageTiles();  // An explicit ManageTiles.
885  EXPECT_FALSE(scheduler->ManageTilesPending());
886  scheduler->SetNeedsManageTiles();
887  scheduler->SetNeedsRedraw();
888  client.Reset();
889  client.AdvanceFrame();
890  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
891  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
892  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
893
894  EXPECT_TRUE(scheduler->ManageTilesPending());
895
896  client.Reset();
897  client.task_runner().RunPendingTasks();  // Run posted deadline.
898  EXPECT_EQ(1, client.num_draws());
899  EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
900  EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
901  EXPECT_FALSE(scheduler->RedrawPending());
902  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
903
904  // Next frame without DidManageTiles should ManageTiles with draw.
905  scheduler->SetNeedsManageTiles();
906  scheduler->SetNeedsRedraw();
907  client.Reset();
908  client.AdvanceFrame();
909  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
910  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
911  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
912
913  client.Reset();
914  client.task_runner().RunPendingTasks();  // Run posted deadline.
915  EXPECT_EQ(1, client.num_draws());
916  EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
917  EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
918  EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
919            client.ActionIndex("ScheduledActionManageTiles"));
920  EXPECT_FALSE(scheduler->RedrawPending());
921  EXPECT_FALSE(scheduler->ManageTilesPending());
922  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
923  scheduler->DidManageTiles();  // Corresponds to ScheduledActionManageTiles
924}
925
926TEST(SchedulerTest, ShouldUpdateVisibleTiles) {
927  FakeSchedulerClient client;
928  SchedulerSettings scheduler_settings;
929  scheduler_settings.impl_side_painting = true;
930  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
931  scheduler->SetCanStart();
932  scheduler->SetVisible(true);
933  scheduler->SetCanDraw(true);
934  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
935
936  client.SetRedrawWillHappenIfUpdateVisibleTilesHappens(true);
937
938  // SetNeedsCommit should begin the frame.
939  client.Reset();
940  scheduler->SetNeedsCommit();
941  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
942
943  client.Reset();
944  client.AdvanceFrame();
945  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
946  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
947  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
948
949  client.Reset();
950  scheduler->NotifyBeginMainFrameStarted();
951  scheduler->NotifyReadyToCommit();
952  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
953
954  client.Reset();
955  scheduler->NotifyReadyToActivate();
956  EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client);
957
958  client.Reset();
959  client.SetSwapContainsIncompleteTile(true);
960  client.task_runner().RunPendingTasks();  // Run posted deadline.
961  EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
962  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
963  EXPECT_FALSE(scheduler->RedrawPending());
964
965  client.Reset();
966  client.AdvanceFrame();
967  EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
968  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
969
970  client.Reset();
971  client.task_runner().RunPendingTasks();  // Run posted deadline.
972  EXPECT_ACTION("ScheduledActionUpdateVisibleTiles", client, 0, 3);
973  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 3);
974  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 2, 3);
975
976  client.Reset();
977  client.AdvanceFrame();
978  EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
979  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
980
981  // No more UpdateVisibleTiles().
982  client.Reset();
983  client.task_runner().RunPendingTasks();  // Run posted deadline.
984  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
985  EXPECT_FALSE(client.needs_begin_frame());
986}
987
988TEST(SchedulerTest, TriggerBeginFrameDeadlineEarly) {
989  SchedulerClientNeedsManageTilesInDraw client;
990  SchedulerSettings default_scheduler_settings;
991  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
992  scheduler->SetCanStart();
993  scheduler->SetVisible(true);
994  scheduler->SetCanDraw(true);
995  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
996
997  client.Reset();
998  scheduler->SetNeedsRedraw();
999  client.AdvanceFrame();
1000
1001  // The deadline should be zero since there is no work other than drawing
1002  // pending.
1003  EXPECT_EQ(base::TimeTicks(), client.posted_begin_impl_frame_deadline());
1004}
1005
1006class SchedulerClientWithFixedEstimates : public FakeSchedulerClient {
1007 public:
1008  SchedulerClientWithFixedEstimates(
1009      base::TimeDelta draw_duration,
1010      base::TimeDelta begin_main_frame_to_commit_duration,
1011      base::TimeDelta commit_to_activate_duration)
1012      : draw_duration_(draw_duration),
1013        begin_main_frame_to_commit_duration_(
1014            begin_main_frame_to_commit_duration),
1015        commit_to_activate_duration_(commit_to_activate_duration) {}
1016
1017  virtual base::TimeDelta DrawDurationEstimate() OVERRIDE {
1018    return draw_duration_;
1019  }
1020  virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE {
1021    return begin_main_frame_to_commit_duration_;
1022  }
1023  virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE {
1024    return commit_to_activate_duration_;
1025  }
1026
1027 private:
1028    base::TimeDelta draw_duration_;
1029    base::TimeDelta begin_main_frame_to_commit_duration_;
1030    base::TimeDelta commit_to_activate_duration_;
1031};
1032
1033void MainFrameInHighLatencyMode(int64 begin_main_frame_to_commit_estimate_in_ms,
1034                                int64 commit_to_activate_estimate_in_ms,
1035                                bool impl_latency_takes_priority,
1036                                bool should_send_begin_main_frame) {
1037  // Set up client with specified estimates (draw duration is set to 1).
1038  SchedulerClientWithFixedEstimates client(
1039      base::TimeDelta::FromMilliseconds(1),
1040      base::TimeDelta::FromMilliseconds(
1041          begin_main_frame_to_commit_estimate_in_ms),
1042      base::TimeDelta::FromMilliseconds(commit_to_activate_estimate_in_ms));
1043  SchedulerSettings default_scheduler_settings;
1044  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
1045  scheduler->SetCanStart();
1046  scheduler->SetVisible(true);
1047  scheduler->SetCanDraw(true);
1048  scheduler->SetImplLatencyTakesPriority(impl_latency_takes_priority);
1049  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
1050
1051  // Impl thread hits deadline before commit finishes.
1052  client.Reset();
1053  scheduler->SetNeedsCommit();
1054  EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode());
1055  client.AdvanceFrame();
1056  EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode());
1057  client.task_runner().RunPendingTasks();  // Run posted deadline.
1058  EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
1059  scheduler->NotifyBeginMainFrameStarted();
1060  scheduler->NotifyReadyToCommit();
1061  EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
1062  EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
1063
1064  client.Reset();
1065  scheduler->SetNeedsCommit();
1066  EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
1067  client.AdvanceFrame();
1068  EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
1069  client.task_runner().RunPendingTasks();  // Run posted deadline.
1070  EXPECT_EQ(scheduler->MainThreadIsInHighLatencyMode(),
1071            should_send_begin_main_frame);
1072  EXPECT_EQ(client.HasAction("ScheduledActionSendBeginMainFrame"),
1073            should_send_begin_main_frame);
1074}
1075
1076TEST(SchedulerTest,
1077    SkipMainFrameIfHighLatencyAndCanCommitAndActivateBeforeDeadline) {
1078  // Set up client so that estimates indicate that we can commit and activate
1079  // before the deadline (~8ms by default).
1080  MainFrameInHighLatencyMode(1, 1, false, false);
1081}
1082
1083TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanCommitTooLong) {
1084  // Set up client so that estimates indicate that the commit cannot finish
1085  // before the deadline (~8ms by default).
1086  MainFrameInHighLatencyMode(10, 1, false, true);
1087}
1088
1089TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanActivateTooLong) {
1090  // Set up client so that estimates indicate that the activate cannot finish
1091  // before the deadline (~8ms by default).
1092  MainFrameInHighLatencyMode(1, 10, false, true);
1093}
1094
1095TEST(SchedulerTest, NotSkipMainFrameInPreferImplLatencyMode) {
1096  // Set up client so that estimates indicate that we can commit and activate
1097  // before the deadline (~8ms by default), but also enable impl latency takes
1098  // priority mode.
1099  MainFrameInHighLatencyMode(1, 1, true, true);
1100}
1101
1102TEST(SchedulerTest, PollForCommitCompletion) {
1103  // Since we are simulating a long commit, set up a client with draw duration
1104  // estimates that prevent skipping main frames to get to low latency mode.
1105  SchedulerClientWithFixedEstimates client(
1106      base::TimeDelta::FromMilliseconds(1),
1107      base::TimeDelta::FromMilliseconds(32),
1108      base::TimeDelta::FromMilliseconds(32));
1109  client.set_log_anticipated_draw_time_change(true);
1110  SchedulerSettings default_scheduler_settings;
1111  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
1112
1113  scheduler->SetCanDraw(true);
1114  scheduler->SetCanStart();
1115  scheduler->SetVisible(true);
1116  scheduler->DidCreateAndInitializeOutputSurface();
1117
1118  scheduler->SetNeedsCommit();
1119  EXPECT_TRUE(scheduler->CommitPending());
1120  scheduler->NotifyBeginMainFrameStarted();
1121  scheduler->NotifyReadyToCommit();
1122  scheduler->SetNeedsRedraw();
1123
1124  BeginFrameArgs frame_args = CreateBeginFrameArgsForTesting(client.now_src());
1125  frame_args.interval = base::TimeDelta::FromMilliseconds(1000);
1126  scheduler->BeginFrame(frame_args);
1127
1128  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1129  client.task_runner().RunPendingTasks();  // Run posted deadline.
1130  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
1131
1132  scheduler->DidSwapBuffers();
1133  scheduler->DidSwapBuffersComplete();
1134
1135  // At this point, we've drawn a frame. Start another commit, but hold off on
1136  // the NotifyReadyToCommit for now.
1137  EXPECT_FALSE(scheduler->CommitPending());
1138  scheduler->SetNeedsCommit();
1139  scheduler->BeginFrame(frame_args);
1140  EXPECT_TRUE(scheduler->CommitPending());
1141
1142  // Draw and swap the frame, but don't ack the swap to simulate the Browser
1143  // blocking on the renderer.
1144  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1145  client.task_runner().RunPendingTasks();  // Run posted deadline.
1146  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
1147  scheduler->DidSwapBuffers();
1148
1149  // Spin the event loop a few times and make sure we get more
1150  // DidAnticipateDrawTimeChange calls every time.
1151  int actions_so_far = client.num_actions_();
1152
1153  // Does three iterations to make sure that the timer is properly repeating.
1154  for (int i = 0; i < 3; ++i) {
1155    EXPECT_EQ((frame_args.interval * 2).InMicroseconds(),
1156              client.task_runner().DelayToNextTaskTime().InMicroseconds())
1157        << scheduler->AsValue()->ToString();
1158    client.task_runner().RunPendingTasks();
1159    EXPECT_GT(client.num_actions_(), actions_so_far);
1160    EXPECT_STREQ(client.Action(client.num_actions_() - 1),
1161                 "DidAnticipatedDrawTimeChange");
1162    actions_so_far = client.num_actions_();
1163  }
1164
1165  // Do the same thing after BeginMainFrame starts but still before activation.
1166  scheduler->NotifyBeginMainFrameStarted();
1167  for (int i = 0; i < 3; ++i) {
1168    EXPECT_EQ((frame_args.interval * 2).InMicroseconds(),
1169              client.task_runner().DelayToNextTaskTime().InMicroseconds())
1170        << scheduler->AsValue()->ToString();
1171    client.task_runner().RunPendingTasks();
1172    EXPECT_GT(client.num_actions_(), actions_so_far);
1173    EXPECT_STREQ(client.Action(client.num_actions_() - 1),
1174                 "DidAnticipatedDrawTimeChange");
1175    actions_so_far = client.num_actions_();
1176  }
1177}
1178
1179TEST(SchedulerTest, BeginRetroFrame) {
1180  FakeSchedulerClient client;
1181  SchedulerSettings scheduler_settings;
1182  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
1183  scheduler->SetCanStart();
1184  scheduler->SetVisible(true);
1185  scheduler->SetCanDraw(true);
1186  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
1187
1188  // SetNeedsCommit should begin the frame on the next BeginImplFrame.
1189  client.Reset();
1190  scheduler->SetNeedsCommit();
1191  EXPECT_TRUE(client.needs_begin_frame());
1192  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
1193  client.Reset();
1194
1195  // Create a BeginFrame with a long deadline to avoid race conditions.
1196  // This is the first BeginFrame, which will be handled immediately.
1197  BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
1198  args.deadline += base::TimeDelta::FromHours(1);
1199  scheduler->BeginFrame(args);
1200  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
1201  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
1202  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1203  EXPECT_TRUE(client.needs_begin_frame());
1204  client.Reset();
1205
1206  // Queue BeginFrames while we are still handling the previous BeginFrame.
1207  args.frame_time += base::TimeDelta::FromSeconds(1);
1208  scheduler->BeginFrame(args);
1209  args.frame_time += base::TimeDelta::FromSeconds(1);
1210  scheduler->BeginFrame(args);
1211
1212  // If we don't swap on the deadline, we wait for the next BeginImplFrame.
1213  client.task_runner().RunPendingTasks();  // Run posted deadline.
1214  EXPECT_NO_ACTION(client);
1215  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
1216  EXPECT_TRUE(client.needs_begin_frame());
1217  client.Reset();
1218
1219  // NotifyReadyToCommit should trigger the commit.
1220  scheduler->NotifyBeginMainFrameStarted();
1221  scheduler->NotifyReadyToCommit();
1222  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
1223  EXPECT_TRUE(client.needs_begin_frame());
1224  client.Reset();
1225
1226  // BeginImplFrame should prepare the draw.
1227  client.task_runner().RunPendingTasks();  // Run posted BeginRetroFrame.
1228  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
1229  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
1230  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1231  EXPECT_TRUE(client.needs_begin_frame());
1232  client.Reset();
1233
1234  // BeginImplFrame deadline should draw.
1235  client.task_runner().RunPendingTasks();  // Run posted deadline.
1236  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
1237  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
1238  EXPECT_TRUE(client.needs_begin_frame());
1239  client.Reset();
1240
1241  // The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
1242  // to avoid excessive toggles.
1243  client.task_runner().RunPendingTasks();  // Run posted BeginRetroFrame.
1244  EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
1245  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1246  client.Reset();
1247
1248  client.task_runner().RunPendingTasks();  // Run posted deadline.
1249  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
1250  EXPECT_FALSE(client.needs_begin_frame());
1251  client.Reset();
1252}
1253
1254TEST(SchedulerTest, BeginRetroFrame_SwapThrottled) {
1255  FakeSchedulerClient client;
1256  SchedulerSettings scheduler_settings;
1257  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
1258  scheduler->SetCanStart();
1259  scheduler->SetVisible(true);
1260  scheduler->SetCanDraw(true);
1261  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
1262
1263  // To test swap ack throttling, this test disables automatic swap acks.
1264  scheduler->SetMaxSwapsPending(1);
1265  client.SetAutomaticSwapAck(false);
1266
1267  // SetNeedsCommit should begin the frame on the next BeginImplFrame.
1268  client.Reset();
1269  scheduler->SetNeedsCommit();
1270  EXPECT_TRUE(client.needs_begin_frame());
1271  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
1272  client.Reset();
1273
1274  // Create a BeginFrame with a long deadline to avoid race conditions.
1275  // This is the first BeginFrame, which will be handled immediately.
1276  BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
1277  args.deadline += base::TimeDelta::FromHours(1);
1278  scheduler->BeginFrame(args);
1279  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
1280  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
1281  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1282  EXPECT_TRUE(client.needs_begin_frame());
1283  client.Reset();
1284
1285  // Queue BeginFrame while we are still handling the previous BeginFrame.
1286  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1287  args.frame_time += base::TimeDelta::FromSeconds(1);
1288  scheduler->BeginFrame(args);
1289  EXPECT_NO_ACTION(client);
1290  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1291  client.Reset();
1292
1293  // NotifyReadyToCommit should trigger the pending commit and draw.
1294  scheduler->NotifyBeginMainFrameStarted();
1295  scheduler->NotifyReadyToCommit();
1296  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
1297  EXPECT_TRUE(client.needs_begin_frame());
1298  client.Reset();
1299
1300  // Swapping will put us into a swap throttled state.
1301  client.task_runner().RunPendingTasks();  // Run posted deadline.
1302  EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
1303  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
1304  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
1305  EXPECT_TRUE(client.needs_begin_frame());
1306  client.Reset();
1307
1308  // While swap throttled, BeginRetroFrames should trigger BeginImplFrames
1309  // but not a BeginMainFrame or draw.
1310  scheduler->SetNeedsCommit();
1311  client.task_runner().RunPendingTasks();  // Run posted BeginRetroFrame.
1312  EXPECT_ACTION("WillBeginImplFrame", client, 0, 1);
1313  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1314  EXPECT_TRUE(client.needs_begin_frame());
1315  client.Reset();
1316
1317  // Queue BeginFrame while we are still handling the previous BeginFrame.
1318  args.frame_time += base::TimeDelta::FromSeconds(1);
1319  scheduler->BeginFrame(args);
1320  EXPECT_NO_ACTION(client);
1321  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1322  EXPECT_TRUE(client.needs_begin_frame());
1323  client.Reset();
1324
1325  // Take us out of a swap throttled state.
1326  scheduler->DidSwapBuffersComplete();
1327  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1);
1328  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1329  EXPECT_TRUE(client.needs_begin_frame());
1330  client.Reset();
1331
1332  // BeginImplFrame deadline should draw.
1333  scheduler->SetNeedsRedraw();
1334
1335  EXPECT_TRUE(client.task_runner().RunTasksWhile(
1336      client.ImplFrameDeadlinePending(true)));
1337
1338  EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
1339  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
1340  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
1341  EXPECT_TRUE(client.needs_begin_frame());
1342  client.Reset();
1343}
1344
1345void BeginFramesNotFromClient(bool begin_frame_scheduling_enabled,
1346                              bool throttle_frame_production) {
1347  FakeSchedulerClient client;
1348  SchedulerSettings scheduler_settings;
1349  scheduler_settings.begin_frame_scheduling_enabled =
1350      begin_frame_scheduling_enabled;
1351  scheduler_settings.throttle_frame_production = throttle_frame_production;
1352  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
1353  scheduler->SetCanStart();
1354  scheduler->SetVisible(true);
1355  scheduler->SetCanDraw(true);
1356  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
1357
1358  // SetNeedsCommit should begin the frame on the next BeginImplFrame
1359  // without calling SetNeedsBeginFrame.
1360  client.Reset();
1361  scheduler->SetNeedsCommit();
1362  EXPECT_FALSE(client.needs_begin_frame());
1363  EXPECT_NO_ACTION(client);
1364  client.Reset();
1365
1366  // When the client-driven BeginFrame are disabled, the scheduler posts it's
1367  // own BeginFrame tasks.
1368  client.task_runner().RunPendingTasks();  // Run posted BeginFrame.
1369  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
1370  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
1371  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1372  EXPECT_FALSE(client.needs_begin_frame());
1373  client.Reset();
1374
1375  // If we don't swap on the deadline, we wait for the next BeginFrame.
1376  client.task_runner().RunPendingTasks();  // Run posted deadline.
1377  EXPECT_NO_ACTION(client);
1378  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
1379  EXPECT_FALSE(client.needs_begin_frame());
1380  client.Reset();
1381
1382  // NotifyReadyToCommit should trigger the commit.
1383  scheduler->NotifyBeginMainFrameStarted();
1384  scheduler->NotifyReadyToCommit();
1385  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
1386  EXPECT_FALSE(client.needs_begin_frame());
1387  client.Reset();
1388
1389  // BeginImplFrame should prepare the draw.
1390  client.task_runner().RunPendingTasks();  // Run posted BeginFrame.
1391  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
1392  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
1393  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1394  EXPECT_FALSE(client.needs_begin_frame());
1395  client.Reset();
1396
1397  // BeginImplFrame deadline should draw.
1398  client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true));
1399  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
1400  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
1401  EXPECT_FALSE(client.needs_begin_frame());
1402  client.Reset();
1403
1404  // The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
1405  // to avoid excessive toggles.
1406  client.task_runner().RunPendingTasks();  // Run posted BeginFrame.
1407  EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
1408  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1409  client.Reset();
1410
1411  // Make sure SetNeedsBeginFrame isn't called on the client
1412  // when the BeginFrame is no longer needed.
1413  client.task_runner().RunPendingTasks();  // Run posted deadline.
1414  EXPECT_NO_ACTION(client);
1415  EXPECT_FALSE(client.needs_begin_frame());
1416  client.Reset();
1417}
1418
1419TEST(SchedulerTest, SyntheticBeginFrames) {
1420  bool begin_frame_scheduling_enabled = false;
1421  bool throttle_frame_production = true;
1422  BeginFramesNotFromClient(begin_frame_scheduling_enabled,
1423                           throttle_frame_production);
1424}
1425
1426TEST(SchedulerTest, VSyncThrottlingDisabled) {
1427  bool begin_frame_scheduling_enabled = true;
1428  bool throttle_frame_production = false;
1429  BeginFramesNotFromClient(begin_frame_scheduling_enabled,
1430                           throttle_frame_production);
1431}
1432
1433TEST(SchedulerTest, SyntheticBeginFrames_And_VSyncThrottlingDisabled) {
1434  bool begin_frame_scheduling_enabled = false;
1435  bool throttle_frame_production = false;
1436  BeginFramesNotFromClient(begin_frame_scheduling_enabled,
1437                           throttle_frame_production);
1438}
1439
1440void BeginFramesNotFromClient_SwapThrottled(bool begin_frame_scheduling_enabled,
1441                                            bool throttle_frame_production) {
1442  FakeSchedulerClient client;
1443  SchedulerSettings scheduler_settings;
1444  scheduler_settings.begin_frame_scheduling_enabled =
1445      begin_frame_scheduling_enabled;
1446  scheduler_settings.throttle_frame_production = throttle_frame_production;
1447  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
1448  scheduler->SetCanStart();
1449  scheduler->SetVisible(true);
1450  scheduler->SetCanDraw(true);
1451  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
1452
1453  // To test swap ack throttling, this test disables automatic swap acks.
1454  scheduler->SetMaxSwapsPending(1);
1455  client.SetAutomaticSwapAck(false);
1456
1457  // SetNeedsCommit should begin the frame on the next BeginImplFrame.
1458  client.Reset();
1459  scheduler->SetNeedsCommit();
1460  EXPECT_FALSE(client.needs_begin_frame());
1461  EXPECT_NO_ACTION(client);
1462  client.Reset();
1463
1464  // Trigger the first BeginImplFrame and BeginMainFrame
1465  client.task_runner().RunPendingTasks();  // Run posted BeginFrame.
1466  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
1467  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
1468  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1469  EXPECT_FALSE(client.needs_begin_frame());
1470  client.Reset();
1471
1472  // NotifyReadyToCommit should trigger the pending commit and draw.
1473  scheduler->NotifyBeginMainFrameStarted();
1474  scheduler->NotifyReadyToCommit();
1475  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
1476  EXPECT_FALSE(client.needs_begin_frame());
1477  client.Reset();
1478
1479  // Swapping will put us into a swap throttled state.
1480  client.task_runner().RunPendingTasks();  // Run posted deadline.
1481  EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
1482  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
1483  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
1484  EXPECT_FALSE(client.needs_begin_frame());
1485  client.Reset();
1486
1487  // While swap throttled, BeginFrames should trigger BeginImplFrames,
1488  // but not a BeginMainFrame or draw.
1489  scheduler->SetNeedsCommit();
1490  client.task_runner().RunPendingTasks();  // Run posted BeginFrame.
1491  EXPECT_ACTION("WillBeginImplFrame", client, 0, 1);
1492  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1493  EXPECT_FALSE(client.needs_begin_frame());
1494  client.Reset();
1495
1496  // Take us out of a swap throttled state.
1497  scheduler->DidSwapBuffersComplete();
1498  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1);
1499  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1500  EXPECT_FALSE(client.needs_begin_frame());
1501  client.Reset();
1502
1503  // BeginImplFrame deadline should draw.
1504  scheduler->SetNeedsRedraw();
1505  client.task_runner().RunPendingTasks();  // Run posted deadline.
1506  EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
1507  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
1508  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
1509  EXPECT_FALSE(client.needs_begin_frame());
1510  client.Reset();
1511}
1512
1513TEST(SchedulerTest, SyntheticBeginFrames_SwapThrottled) {
1514  bool begin_frame_scheduling_enabled = false;
1515  bool throttle_frame_production = true;
1516  BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
1517                                         throttle_frame_production);
1518}
1519
1520TEST(SchedulerTest, VSyncThrottlingDisabled_SwapThrottled) {
1521  bool begin_frame_scheduling_enabled = true;
1522  bool throttle_frame_production = false;
1523  BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
1524                                         throttle_frame_production);
1525}
1526
1527TEST(SchedulerTest,
1528     SyntheticBeginFrames_And_VSyncThrottlingDisabled_SwapThrottled) {
1529  bool begin_frame_scheduling_enabled = false;
1530  bool throttle_frame_production = false;
1531  BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
1532                                         throttle_frame_production);
1533}
1534
1535TEST(SchedulerTest, DidLoseOutputSurfaceAfterOutputSurfaceIsInitialized) {
1536  FakeSchedulerClient client;
1537  SchedulerSettings scheduler_settings;
1538  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
1539  scheduler->SetCanStart();
1540  scheduler->SetVisible(true);
1541  scheduler->SetCanDraw(true);
1542
1543  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
1544  client.Reset();
1545  scheduler->DidCreateAndInitializeOutputSurface();
1546  EXPECT_NO_ACTION(client);
1547
1548  scheduler->DidLoseOutputSurface();
1549  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
1550}
1551
1552TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStarted) {
1553  FakeSchedulerClient client;
1554  SchedulerSettings scheduler_settings;
1555  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
1556  scheduler->SetCanStart();
1557  scheduler->SetVisible(true);
1558  scheduler->SetCanDraw(true);
1559
1560  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
1561  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
1562  // SetNeedsCommit should begin the frame.
1563  client.Reset();
1564  scheduler->SetNeedsCommit();
1565  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
1566
1567  client.Reset();
1568  client.AdvanceFrame();
1569  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
1570  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
1571  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1572
1573  client.Reset();
1574  scheduler->DidLoseOutputSurface();
1575  // Do nothing when impl frame is in deadine pending state.
1576  EXPECT_NO_ACTION(client);
1577
1578  client.Reset();
1579  scheduler->NotifyBeginMainFrameStarted();
1580  scheduler->NotifyReadyToCommit();
1581  EXPECT_ACTION("ScheduledActionCommit", client, 0, 1);
1582
1583  client.Reset();
1584  client.task_runner().RunPendingTasks();  // Run posted deadline.
1585  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
1586}
1587
1588void DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(
1589    bool impl_side_painting) {
1590  FakeSchedulerClient client;
1591  SchedulerSettings scheduler_settings;
1592  scheduler_settings.impl_side_painting = impl_side_painting;
1593  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
1594  scheduler->SetCanStart();
1595  scheduler->SetVisible(true);
1596  scheduler->SetCanDraw(true);
1597
1598  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
1599  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
1600
1601  // SetNeedsCommit should begin the frame.
1602  client.Reset();
1603  scheduler->SetNeedsCommit();
1604  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
1605
1606  client.Reset();
1607  client.AdvanceFrame();
1608  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
1609  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
1610  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1611
1612  client.Reset();
1613  scheduler->DidLoseOutputSurface();
1614  // Do nothing when impl frame is in deadine pending state.
1615  EXPECT_NO_ACTION(client);
1616
1617  client.Reset();
1618  // Run posted deadline.
1619  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1620  client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true));
1621  // OnBeginImplFrameDeadline didn't schedule any actions because main frame is
1622  // not yet completed.
1623  EXPECT_NO_ACTION(client);
1624  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
1625
1626  // BeginImplFrame is not started.
1627  client.task_runner().RunUntilTime(client.now_src()->Now() +
1628                                    base::TimeDelta::FromMilliseconds(10));
1629  EXPECT_NO_ACTION(client);
1630  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
1631
1632  client.Reset();
1633  scheduler->NotifyBeginMainFrameStarted();
1634  scheduler->NotifyReadyToCommit();
1635  if (impl_side_painting) {
1636    EXPECT_ACTION("ScheduledActionCommit", client, 0, 3);
1637    EXPECT_ACTION("ScheduledActionActivateSyncTree", client, 1, 3);
1638    EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 2, 3);
1639  } else {
1640    EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
1641    EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 1, 2);
1642  }
1643}
1644
1645TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency) {
1646  bool impl_side_painting = false;
1647  DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(impl_side_painting);
1648}
1649
1650TEST(SchedulerTest,
1651     DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatencyWithImplPaint) {
1652  bool impl_side_painting = true;
1653  DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(impl_side_painting);
1654}
1655
1656void DidLoseOutputSurfaceAfterReadyToCommit(bool impl_side_painting) {
1657  FakeSchedulerClient client;
1658  SchedulerSettings scheduler_settings;
1659  scheduler_settings.impl_side_painting = impl_side_painting;
1660  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
1661  scheduler->SetCanStart();
1662  scheduler->SetVisible(true);
1663  scheduler->SetCanDraw(true);
1664
1665  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
1666  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
1667
1668  // SetNeedsCommit should begin the frame.
1669  client.Reset();
1670  scheduler->SetNeedsCommit();
1671  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
1672
1673  client.Reset();
1674  client.AdvanceFrame();
1675  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
1676  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
1677  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1678
1679  client.Reset();
1680  scheduler->NotifyBeginMainFrameStarted();
1681  scheduler->NotifyReadyToCommit();
1682  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
1683
1684  client.Reset();
1685  scheduler->DidLoseOutputSurface();
1686  if (impl_side_painting) {
1687    // Sync tree should be forced to activate.
1688    EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client);
1689  } else {
1690    // Do nothing when impl frame is in deadine pending state.
1691    EXPECT_NO_ACTION(client);
1692  }
1693
1694  client.Reset();
1695  client.task_runner().RunPendingTasks();  // Run posted deadline.
1696  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
1697}
1698
1699TEST(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommit) {
1700  DidLoseOutputSurfaceAfterReadyToCommit(false);
1701}
1702
1703TEST(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommitWithImplPainting) {
1704  DidLoseOutputSurfaceAfterReadyToCommit(true);
1705}
1706
1707TEST(SchedulerTest, DidLoseOutputSurfaceAfterSetNeedsManageTiles) {
1708  FakeSchedulerClient client;
1709  SchedulerSettings scheduler_settings;
1710  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
1711  scheduler->SetCanStart();
1712  scheduler->SetVisible(true);
1713  scheduler->SetCanDraw(true);
1714  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
1715
1716  client.Reset();
1717  scheduler->SetNeedsManageTiles();
1718  scheduler->SetNeedsRedraw();
1719  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
1720  EXPECT_TRUE(client.needs_begin_frame());
1721
1722  client.Reset();
1723  client.AdvanceFrame();
1724  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
1725  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
1726  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1727
1728  client.Reset();
1729  scheduler->DidLoseOutputSurface();
1730  EXPECT_NO_ACTION(client);
1731
1732  client.Reset();
1733  client.task_runner().RunPendingTasks();  // Run posted deadline.
1734  EXPECT_ACTION("ScheduledActionManageTiles", client, 0, 2);
1735  EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 1, 2);
1736}
1737
1738TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginRetroFramePosted) {
1739  FakeSchedulerClient client;
1740  SchedulerSettings scheduler_settings;
1741  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
1742  scheduler->SetCanStart();
1743  scheduler->SetVisible(true);
1744  scheduler->SetCanDraw(true);
1745  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
1746
1747  // SetNeedsCommit should begin the frame on the next BeginImplFrame.
1748  client.Reset();
1749  scheduler->SetNeedsCommit();
1750  EXPECT_TRUE(client.needs_begin_frame());
1751  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
1752
1753  // Create a BeginFrame with a long deadline to avoid race conditions.
1754  // This is the first BeginFrame, which will be handled immediately.
1755  client.Reset();
1756  BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
1757  args.deadline += base::TimeDelta::FromHours(1);
1758  scheduler->BeginFrame(args);
1759  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
1760  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
1761  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1762  EXPECT_TRUE(client.needs_begin_frame());
1763
1764  // Queue BeginFrames while we are still handling the previous BeginFrame.
1765  args.frame_time += base::TimeDelta::FromSeconds(1);
1766  scheduler->BeginFrame(args);
1767  args.frame_time += base::TimeDelta::FromSeconds(1);
1768  scheduler->BeginFrame(args);
1769
1770  // If we don't swap on the deadline, we wait for the next BeginImplFrame.
1771  client.Reset();
1772  client.task_runner().RunPendingTasks();  // Run posted deadline.
1773  EXPECT_NO_ACTION(client);
1774  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
1775  EXPECT_TRUE(client.needs_begin_frame());
1776
1777  // NotifyReadyToCommit should trigger the commit.
1778  client.Reset();
1779  scheduler->NotifyBeginMainFrameStarted();
1780  scheduler->NotifyReadyToCommit();
1781  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
1782  EXPECT_TRUE(client.needs_begin_frame());
1783
1784  client.Reset();
1785  EXPECT_FALSE(scheduler->IsBeginRetroFrameArgsEmpty());
1786  scheduler->DidLoseOutputSurface();
1787  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
1788  EXPECT_TRUE(client.needs_begin_frame());
1789  EXPECT_TRUE(scheduler->IsBeginRetroFrameArgsEmpty());
1790
1791  // Posted BeginRetroFrame is aborted.
1792  client.Reset();
1793  client.task_runner().RunPendingTasks();
1794  EXPECT_NO_ACTION(client);
1795}
1796
1797TEST(SchedulerTest, DidLoseOutputSurfaceDuringBeginRetroFrameRunning) {
1798  FakeSchedulerClient client;
1799  SchedulerSettings scheduler_settings;
1800  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
1801  scheduler->SetCanStart();
1802  scheduler->SetVisible(true);
1803  scheduler->SetCanDraw(true);
1804  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
1805
1806  // SetNeedsCommit should begin the frame on the next BeginImplFrame.
1807  client.Reset();
1808  scheduler->SetNeedsCommit();
1809  EXPECT_TRUE(client.needs_begin_frame());
1810  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
1811
1812  // Create a BeginFrame with a long deadline to avoid race conditions.
1813  // This is the first BeginFrame, which will be handled immediately.
1814  client.Reset();
1815  BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
1816  args.deadline += base::TimeDelta::FromHours(1);
1817  scheduler->BeginFrame(args);
1818  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
1819  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
1820  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1821  EXPECT_TRUE(client.needs_begin_frame());
1822
1823  // Queue BeginFrames while we are still handling the previous BeginFrame.
1824  args.frame_time += base::TimeDelta::FromSeconds(1);
1825  scheduler->BeginFrame(args);
1826  args.frame_time += base::TimeDelta::FromSeconds(1);
1827  scheduler->BeginFrame(args);
1828
1829  // If we don't swap on the deadline, we wait for the next BeginImplFrame.
1830  client.Reset();
1831  client.task_runner().RunPendingTasks();  // Run posted deadline.
1832  EXPECT_NO_ACTION(client);
1833  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
1834  EXPECT_TRUE(client.needs_begin_frame());
1835
1836  // NotifyReadyToCommit should trigger the commit.
1837  client.Reset();
1838  scheduler->NotifyBeginMainFrameStarted();
1839  scheduler->NotifyReadyToCommit();
1840  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
1841  EXPECT_TRUE(client.needs_begin_frame());
1842
1843  // BeginImplFrame should prepare the draw.
1844  client.Reset();
1845  client.task_runner().RunPendingTasks();  // Run posted BeginRetroFrame.
1846  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
1847  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
1848  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1849  EXPECT_TRUE(client.needs_begin_frame());
1850
1851  client.Reset();
1852  EXPECT_FALSE(scheduler->IsBeginRetroFrameArgsEmpty());
1853  scheduler->DidLoseOutputSurface();
1854  EXPECT_NO_ACTION(client);
1855  EXPECT_TRUE(scheduler->IsBeginRetroFrameArgsEmpty());
1856
1857  // BeginImplFrame deadline should abort drawing.
1858  client.Reset();
1859  client.task_runner().RunPendingTasks();  // Run posted deadline.
1860  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
1861  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
1862  EXPECT_TRUE(client.needs_begin_frame());
1863
1864  // No more BeginRetroFrame because BeginRetroFrame queue is cleared.
1865  client.Reset();
1866  client.task_runner().RunPendingTasks();
1867  EXPECT_NO_ACTION(client);
1868}
1869
1870TEST(SchedulerTest,
1871     StopBeginFrameAfterDidLoseOutputSurfaceWithSyntheticBeginFrameSource) {
1872  FakeSchedulerClient client;
1873  SchedulerSettings scheduler_settings;
1874  scheduler_settings.begin_frame_scheduling_enabled = false;
1875  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
1876  scheduler->SetCanStart();
1877  scheduler->SetVisible(true);
1878  scheduler->SetCanDraw(true);
1879  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
1880
1881  // SetNeedsCommit should begin the frame on the next BeginImplFrame.
1882  client.Reset();
1883  EXPECT_FALSE(scheduler->IsSyntheticBeginFrameSourceActive());
1884  scheduler->SetNeedsCommit();
1885  EXPECT_TRUE(scheduler->IsSyntheticBeginFrameSourceActive());
1886
1887  client.Reset();
1888  client.task_runner().RunPendingTasks();  // Run posted Tick.
1889  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
1890  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
1891  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1892  EXPECT_TRUE(scheduler->IsSyntheticBeginFrameSourceActive());
1893
1894  // NotifyReadyToCommit should trigger the commit.
1895  client.Reset();
1896  scheduler->NotifyBeginMainFrameStarted();
1897  scheduler->NotifyReadyToCommit();
1898  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
1899  EXPECT_TRUE(scheduler->IsSyntheticBeginFrameSourceActive());
1900
1901  client.Reset();
1902  scheduler->DidLoseOutputSurface();
1903  EXPECT_EQ(0, client.num_actions_());
1904  EXPECT_FALSE(scheduler->IsSyntheticBeginFrameSourceActive());
1905
1906  client.Reset();
1907  client.task_runner().RunPendingTasks();  // Run posted deadline.
1908  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
1909  EXPECT_FALSE(scheduler->IsSyntheticBeginFrameSourceActive());
1910}
1911
1912TEST(SchedulerTest, ScheduledActionActivateAfterBecomingInvisible) {
1913  FakeSchedulerClient client;
1914  SchedulerSettings scheduler_settings;
1915  scheduler_settings.impl_side_painting = true;
1916  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
1917  scheduler->SetCanStart();
1918  scheduler->SetVisible(true);
1919  scheduler->SetCanDraw(true);
1920
1921  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
1922  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
1923
1924  // SetNeedsCommit should begin the frame.
1925  client.Reset();
1926  scheduler->SetNeedsCommit();
1927  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
1928
1929  client.Reset();
1930  client.AdvanceFrame();
1931  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
1932  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
1933  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
1934
1935  client.Reset();
1936  scheduler->NotifyBeginMainFrameStarted();
1937  scheduler->NotifyReadyToCommit();
1938  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
1939
1940  client.Reset();
1941  scheduler->SetVisible(false);
1942  // Sync tree should be forced to activate.
1943  EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client);
1944}
1945
1946}  // namespace
1947}  // namespace cc
1948