Home | History | Annotate | Download | only in scheduler
      1 // Copyright 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 #include "cc/scheduler/scheduler.h"
      5 
      6 #include <string>
      7 #include <vector>
      8 
      9 #include "base/logging.h"
     10 #include "base/memory/scoped_vector.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/run_loop.h"
     13 #include "base/time/time.h"
     14 #include "cc/test/scheduler_test_common.h"
     15 #include "testing/gmock/include/gmock/gmock.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 
     18 #define EXPECT_ACTION(action, client, action_index, expected_num_actions) \
     19   EXPECT_EQ(expected_num_actions, client.num_actions_());                 \
     20   ASSERT_LT(action_index, client.num_actions_());                         \
     21   do {                                                                    \
     22     EXPECT_STREQ(action, client.Action(action_index));                    \
     23     for (int i = expected_num_actions; i < client.num_actions_(); ++i)    \
     24       ADD_FAILURE() << "Unexpected action: " << client.Action(i) <<       \
     25           " with state:\n" << client.StateForAction(action_index);        \
     26   } while (false)
     27 
     28 #define EXPECT_SINGLE_ACTION(action, client) \
     29   EXPECT_ACTION(action, client, 0, 1)
     30 
     31 namespace cc {
     32 namespace {
     33 
     34 void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler) {
     35   scheduler->DidCreateAndInitializeOutputSurface();
     36   scheduler->SetNeedsCommit();
     37   scheduler->FinishCommit();
     38   // Go through the motions to draw the commit.
     39   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
     40   scheduler->OnBeginImplFrameDeadline();
     41   // We need another BeginImplFrame so Scheduler calls
     42   // SetNeedsBeginImplFrame(false).
     43   scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
     44   scheduler->OnBeginImplFrameDeadline();
     45 }
     46 
     47 class FakeSchedulerClient : public SchedulerClient {
     48  public:
     49   FakeSchedulerClient()
     50   : needs_begin_impl_frame_(false) {
     51     Reset();
     52   }
     53 
     54   void Reset() {
     55     actions_.clear();
     56     states_.clear();
     57     draw_will_happen_ = true;
     58     swap_will_happen_if_draw_happens_ = true;
     59     num_draws_ = 0;
     60     log_anticipated_draw_time_change_ = false;
     61   }
     62 
     63   Scheduler* CreateScheduler(const SchedulerSettings& settings) {
     64     scheduler_ = Scheduler::Create(this, settings, 0);
     65     return scheduler_.get();
     66   }
     67 
     68   // Most tests don't care about DidAnticipatedDrawTimeChange, so only record it
     69   // for tests that do.
     70   void set_log_anticipated_draw_time_change(bool log) {
     71     log_anticipated_draw_time_change_ = log;
     72   }
     73   bool needs_begin_impl_frame() { return needs_begin_impl_frame_; }
     74   int num_draws() const { return num_draws_; }
     75   int num_actions_() const { return static_cast<int>(actions_.size()); }
     76   const char* Action(int i) const { return actions_[i]; }
     77   base::Value& StateForAction(int i) const { return *states_[i]; }
     78 
     79   int ActionIndex(const char* action) const {
     80     for (size_t i = 0; i < actions_.size(); i++)
     81       if (!strcmp(actions_[i], action))
     82         return i;
     83     return -1;
     84   }
     85 
     86   bool HasAction(const char* action) const {
     87     return ActionIndex(action) >= 0;
     88   }
     89 
     90   void SetDrawWillHappen(bool draw_will_happen) {
     91     draw_will_happen_ = draw_will_happen;
     92   }
     93   void SetSwapWillHappenIfDrawHappens(bool swap_will_happen_if_draw_happens) {
     94     swap_will_happen_if_draw_happens_ = swap_will_happen_if_draw_happens;
     95   }
     96 
     97   // SchedulerClient implementation.
     98   virtual void SetNeedsBeginImplFrame(bool enable) OVERRIDE {
     99     actions_.push_back("SetNeedsBeginImplFrame");
    100     states_.push_back(scheduler_->StateAsValue().release());
    101     needs_begin_impl_frame_ = enable;
    102   }
    103   virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {
    104     actions_.push_back("ScheduledActionSendBeginMainFrame");
    105     states_.push_back(scheduler_->StateAsValue().release());
    106   }
    107   virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
    108       OVERRIDE {
    109     actions_.push_back("ScheduledActionDrawAndSwapIfPossible");
    110     states_.push_back(scheduler_->StateAsValue().release());
    111     num_draws_++;
    112     bool did_readback = false;
    113     return DrawSwapReadbackResult(
    114         draw_will_happen_,
    115         draw_will_happen_ && swap_will_happen_if_draw_happens_,
    116         did_readback);
    117   }
    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   }
    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   }
    134   virtual void ScheduledActionCommit() OVERRIDE {
    135     actions_.push_back("ScheduledActionCommit");
    136     states_.push_back(scheduler_->StateAsValue().release());
    137   }
    138   virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE {
    139     actions_.push_back("ScheduledActionUpdateVisibleTiles");
    140     states_.push_back(scheduler_->StateAsValue().release());
    141   }
    142   virtual void ScheduledActionActivatePendingTree() OVERRIDE {
    143     actions_.push_back("ScheduledActionActivatePendingTree");
    144     states_.push_back(scheduler_->StateAsValue().release());
    145   }
    146   virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {
    147     actions_.push_back("ScheduledActionBeginOutputSurfaceCreation");
    148     states_.push_back(scheduler_->StateAsValue().release());
    149   }
    150   virtual void ScheduledActionAcquireLayerTexturesForMainThread() OVERRIDE {
    151     actions_.push_back("ScheduledActionAcquireLayerTexturesForMainThread");
    152     states_.push_back(scheduler_->StateAsValue().release());
    153   }
    154   virtual void ScheduledActionManageTiles() OVERRIDE {
    155     actions_.push_back("ScheduledActionManageTiles");
    156     states_.push_back(scheduler_->StateAsValue().release());
    157   }
    158   virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {
    159     if (log_anticipated_draw_time_change_)
    160       actions_.push_back("DidAnticipatedDrawTimeChange");
    161   }
    162   virtual base::TimeDelta DrawDurationEstimate() OVERRIDE {
    163     return base::TimeDelta();
    164   }
    165   virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE {
    166     return base::TimeDelta();
    167   }
    168   virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE {
    169     return base::TimeDelta();
    170   }
    171 
    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 
    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 
    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 
    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 
    278 TEST(SchedulerTest, RequestCommit) {
    279   bool deadline_scheduling_enabled = false;
    280   RequestCommit(deadline_scheduling_enabled);
    281 }
    282 
    283 TEST(SchedulerTest, RequestCommit_Deadline) {
    284   bool deadline_scheduling_enabled = true;
    285   RequestCommit(deadline_scheduling_enabled);
    286 }
    287 
    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 
    382 TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
    383   bool deadline_scheduling_enabled = false;
    384   RequestCommitAfterBeginMainFrameSent(deadline_scheduling_enabled);
    385 }
    386 
    387 TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent_Deadline) {
    388   bool deadline_scheduling_enabled = true;
    389   RequestCommitAfterBeginMainFrameSent(deadline_scheduling_enabled);
    390 }
    391 
    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 
    493 TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw) {
    494   bool deadline_scheduling_enabled = false;
    495   TextureAcquisitionCausesCommitInsteadOfDraw(deadline_scheduling_enabled);
    496 }
    497 
    498 TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw_Deadline) {
    499   bool deadline_scheduling_enabled = true;
    500   TextureAcquisitionCausesCommitInsteadOfDraw(deadline_scheduling_enabled);
    501 }
    502 
    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 
    617 TEST(SchedulerTest, TextureAcquisitionCollision) {
    618   bool deadline_scheduling_enabled = false;
    619   TextureAcquisitionCollision(deadline_scheduling_enabled);
    620 }
    621 
    622 TEST(SchedulerTest, TextureAcquisitionCollision_Deadline) {
    623   bool deadline_scheduling_enabled = true;
    624   TextureAcquisitionCollision(deadline_scheduling_enabled);
    625 }
    626 
    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 
    669 TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition) {
    670   bool deadline_scheduling_enabled = false;
    671   VisibilitySwitchWithTextureAcquisition(deadline_scheduling_enabled);
    672 }
    673 
    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:
    681   virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {}
    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 
    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 
    698   virtual void ScheduledActionCommit() OVERRIDE {}
    699   virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {}
    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
    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.
    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:
    792   SchedulerClientThatSetNeedsCommitInsideDraw()
    793       : set_needs_commit_on_next_draw_(false) {}
    794 
    795   virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {}
    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 
    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 
    814   virtual void ScheduledActionCommit() OVERRIDE {}
    815   virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {}
    816   virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {}
    817 
    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
    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.
    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 
    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 
    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 
    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:
    994   virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
    995       OVERRIDE {
    996     scheduler_->SetNeedsManageTiles();
    997     return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
    998   }
    999 };
   1000 
   1001 // Test manage tiles is independant of draws.
   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.
   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:
   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 
   1155   virtual base::TimeDelta DrawDurationEstimate() OVERRIDE {
   1156     return draw_duration_;
   1157   }
   1158   virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE {
   1159     return begin_main_frame_to_commit_duration_;
   1160   }
   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 
   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 
   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 
   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 
   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 
   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 
   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