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 
      5 #include "cc/scheduler/scheduler.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/logging.h"
     11 #include "cc/test/scheduler_test_common.h"
     12 #include "testing/gmock/include/gmock/gmock.h"
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 
     15 #define EXPECT_ACTION(action, client, action_index, expected_num_actions) \
     16   EXPECT_EQ(expected_num_actions, client.num_actions_());                 \
     17   ASSERT_LT(action_index, client.num_actions_());                         \
     18   do {                                                                    \
     19     EXPECT_STREQ(action, client.Action(action_index));                    \
     20     for (int i = expected_num_actions; i < client.num_actions_(); ++i)    \
     21       ADD_FAILURE() << "Unexpected action: " << client.Action(i) <<       \
     22           " with state:\n" << client.StateForAction(action_index);        \
     23   } while (false)
     24 
     25 #define EXPECT_SINGLE_ACTION(action, client) \
     26   EXPECT_ACTION(action, client, 0, 1)
     27 
     28 namespace cc {
     29 namespace {
     30 
     31 class FakeSchedulerClient : public SchedulerClient {
     32  public:
     33   FakeSchedulerClient()
     34   : needs_begin_frame_(false) {
     35     Reset();
     36   }
     37 
     38   void Reset() {
     39     actions_.clear();
     40     states_.clear();
     41     draw_will_happen_ = true;
     42     swap_will_happen_if_draw_happens_ = true;
     43     num_draws_ = 0;
     44   }
     45 
     46   Scheduler* CreateScheduler(const SchedulerSettings& settings) {
     47     scheduler_ = Scheduler::Create(this, settings);
     48     return scheduler_.get();
     49   }
     50 
     51   bool needs_begin_frame() { return needs_begin_frame_; }
     52   int num_draws() const { return num_draws_; }
     53   int num_actions_() const { return static_cast<int>(actions_.size()); }
     54   const char* Action(int i) const { return actions_[i]; }
     55   std::string StateForAction(int i) const { return states_[i]; }
     56 
     57   bool HasAction(const char* action) const {
     58     for (size_t i = 0; i < actions_.size(); i++)
     59       if (!strcmp(actions_[i], action))
     60         return true;
     61     return false;
     62   }
     63 
     64   void SetDrawWillHappen(bool draw_will_happen) {
     65     draw_will_happen_ = draw_will_happen;
     66   }
     67   void SetSwapWillHappenIfDrawHappens(bool swap_will_happen_if_draw_happens) {
     68     swap_will_happen_if_draw_happens_ = swap_will_happen_if_draw_happens;
     69   }
     70 
     71   // Scheduler Implementation.
     72   virtual void SetNeedsBeginFrameOnImplThread(bool enable) OVERRIDE {
     73     actions_.push_back("SetNeedsBeginFrameOnImplThread");
     74     states_.push_back(scheduler_->StateAsStringForTesting());
     75     needs_begin_frame_ = enable;
     76   }
     77   virtual void ScheduledActionSendBeginFrameToMainThread() OVERRIDE {
     78     actions_.push_back("ScheduledActionSendBeginFrameToMainThread");
     79     states_.push_back(scheduler_->StateAsStringForTesting());
     80   }
     81   virtual ScheduledActionDrawAndSwapResult
     82   ScheduledActionDrawAndSwapIfPossible() OVERRIDE {
     83     actions_.push_back("ScheduledActionDrawAndSwapIfPossible");
     84     states_.push_back(scheduler_->StateAsStringForTesting());
     85     num_draws_++;
     86     return ScheduledActionDrawAndSwapResult(draw_will_happen_,
     87                                             draw_will_happen_ &&
     88                                             swap_will_happen_if_draw_happens_);
     89   }
     90   virtual ScheduledActionDrawAndSwapResult ScheduledActionDrawAndSwapForced()
     91       OVERRIDE {
     92     actions_.push_back("ScheduledActionDrawAndSwapForced");
     93     states_.push_back(scheduler_->StateAsStringForTesting());
     94     return ScheduledActionDrawAndSwapResult(true,
     95                                             swap_will_happen_if_draw_happens_);
     96   }
     97   virtual void ScheduledActionCommit() OVERRIDE {
     98     actions_.push_back("ScheduledActionCommit");
     99     states_.push_back(scheduler_->StateAsStringForTesting());
    100   }
    101   virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE {
    102     actions_.push_back("ScheduledActionUpdateVisibleTiles");
    103     states_.push_back(scheduler_->StateAsStringForTesting());
    104   }
    105   virtual void ScheduledActionActivatePendingTreeIfNeeded() OVERRIDE {
    106     actions_.push_back("ScheduledActionActivatePendingTreeIfNeeded");
    107     states_.push_back(scheduler_->StateAsStringForTesting());
    108   }
    109   virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {
    110     actions_.push_back("ScheduledActionBeginOutputSurfaceCreation");
    111     states_.push_back(scheduler_->StateAsStringForTesting());
    112   }
    113   virtual void ScheduledActionAcquireLayerTexturesForMainThread() OVERRIDE {
    114     actions_.push_back("ScheduledActionAcquireLayerTexturesForMainThread");
    115     states_.push_back(scheduler_->StateAsStringForTesting());
    116   }
    117   virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {}
    118   virtual base::TimeDelta DrawDurationEstimate() OVERRIDE {
    119     return base::TimeDelta();
    120   }
    121   virtual base::TimeDelta BeginFrameToCommitDurationEstimate() OVERRIDE {
    122     return base::TimeDelta();
    123   }
    124   virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE {
    125     return base::TimeDelta();
    126   }
    127 
    128  protected:
    129   bool needs_begin_frame_;
    130   bool draw_will_happen_;
    131   bool swap_will_happen_if_draw_happens_;
    132   int num_draws_;
    133   std::vector<const char*> actions_;
    134   std::vector<std::string> states_;
    135   scoped_ptr<Scheduler> scheduler_;
    136 };
    137 
    138 TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginFrame) {
    139   FakeSchedulerClient client;
    140   SchedulerSettings default_scheduler_settings;
    141   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
    142   scheduler->SetCanStart();
    143   scheduler->SetVisible(true);
    144   scheduler->SetCanDraw(true);
    145 
    146   EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
    147   client.Reset();
    148   scheduler->DidCreateAndInitializeOutputSurface();
    149   EXPECT_EQ(0, client.num_actions_());
    150 }
    151 
    152 TEST(SchedulerTest, RequestCommit) {
    153   FakeSchedulerClient client;
    154   SchedulerSettings default_scheduler_settings;
    155   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
    156   scheduler->SetCanStart();
    157   scheduler->SetVisible(true);
    158   scheduler->SetCanDraw(true);
    159 
    160   EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
    161   client.Reset();
    162   scheduler->DidCreateAndInitializeOutputSurface();
    163 
    164   // SetNeedsCommit should begin the frame.
    165   scheduler->SetNeedsCommit();
    166   EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2);
    167   EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2);
    168   EXPECT_TRUE(client.needs_begin_frame());
    169   client.Reset();
    170 
    171   // FinishCommit should commit
    172   scheduler->FinishCommit();
    173   EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
    174   EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2);
    175   EXPECT_TRUE(client.needs_begin_frame());
    176   client.Reset();
    177 
    178   // BeginFrame should draw.
    179   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    180   EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
    181   EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2);
    182   EXPECT_FALSE(client.needs_begin_frame());
    183   client.Reset();
    184 }
    185 
    186 TEST(SchedulerTest, RequestCommitAfterBeginFrameSentToMainThread) {
    187   FakeSchedulerClient client;
    188   SchedulerSettings default_scheduler_settings;
    189   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
    190   scheduler->SetCanStart();
    191   scheduler->SetVisible(true);
    192   scheduler->SetCanDraw(true);
    193 
    194   EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
    195   client.Reset();
    196   scheduler->DidCreateAndInitializeOutputSurface();
    197 
    198   // SetNedsCommit should begin the frame.
    199   scheduler->SetNeedsCommit();
    200   EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2);
    201   EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2);
    202   client.Reset();
    203 
    204   // Now SetNeedsCommit again. Calling here means we need a second frame.
    205   scheduler->SetNeedsCommit();
    206   EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 0, 1);
    207   client.Reset();
    208 
    209   // Since another commit is needed, FinishCommit should commit,
    210   // then begin another frame.
    211   scheduler->FinishCommit();
    212   EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
    213   EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2);
    214   client.Reset();
    215 
    216   // Tick should draw but then begin another frame.
    217   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    218   EXPECT_TRUE(client.needs_begin_frame());
    219   EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
    220   EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 1, 2);
    221   client.Reset();
    222 
    223   // Go back to quiescent state and verify we no longer request BeginFrames.
    224   scheduler->FinishCommit();
    225   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    226   EXPECT_FALSE(client.needs_begin_frame());
    227 }
    228 
    229 TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw) {
    230   FakeSchedulerClient client;
    231   SchedulerSettings default_scheduler_settings;
    232   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
    233   scheduler->SetCanStart();
    234   scheduler->SetVisible(true);
    235   scheduler->SetCanDraw(true);
    236   EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
    237 
    238   client.Reset();
    239   scheduler->DidCreateAndInitializeOutputSurface();
    240   scheduler->SetNeedsRedraw();
    241   EXPECT_TRUE(scheduler->RedrawPending());
    242   EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client);
    243   EXPECT_TRUE(client.needs_begin_frame());
    244 
    245   client.Reset();
    246   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    247   EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
    248   EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2);
    249   EXPECT_FALSE(scheduler->RedrawPending());
    250   EXPECT_FALSE(client.needs_begin_frame());
    251 
    252   client.Reset();
    253   scheduler->SetMainThreadNeedsLayerTextures();
    254   EXPECT_SINGLE_ACTION("ScheduledActionAcquireLayerTexturesForMainThread",
    255                        client);
    256 
    257   // We should request a BeginFrame in anticipation of a draw.
    258   client.Reset();
    259   scheduler->SetNeedsRedraw();
    260   EXPECT_TRUE(scheduler->RedrawPending());
    261   EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client);
    262   EXPECT_TRUE(client.needs_begin_frame());
    263 
    264   // No draw happens since the textures are acquired by the main thread.
    265   client.Reset();
    266   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    267   EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client);
    268   EXPECT_TRUE(scheduler->RedrawPending());
    269   EXPECT_TRUE(client.needs_begin_frame());
    270 
    271   scheduler->SetNeedsCommit();
    272   EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 0, 2);
    273   EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 1, 2);
    274   EXPECT_TRUE(client.needs_begin_frame());
    275 
    276   // Commit will release the texture.
    277   client.Reset();
    278   scheduler->FinishCommit();
    279   EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
    280   EXPECT_TRUE(scheduler->RedrawPending());
    281   EXPECT_TRUE(client.needs_begin_frame());
    282 
    283   // Now we can draw again after the commit happens.
    284   client.Reset();
    285   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    286   EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
    287   EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2);
    288   EXPECT_FALSE(scheduler->RedrawPending());
    289   EXPECT_FALSE(client.needs_begin_frame());
    290   client.Reset();
    291 }
    292 
    293 TEST(SchedulerTest, TextureAcquisitionCollision) {
    294   FakeSchedulerClient client;
    295   SchedulerSettings default_scheduler_settings;
    296   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
    297   scheduler->SetCanStart();
    298   scheduler->SetVisible(true);
    299   scheduler->SetCanDraw(true);
    300 
    301   EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
    302   client.Reset();
    303   scheduler->DidCreateAndInitializeOutputSurface();
    304 
    305   scheduler->SetNeedsCommit();
    306   scheduler->SetMainThreadNeedsLayerTextures();
    307   EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 4);
    308   EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 4);
    309   EXPECT_ACTION("ScheduledActionAcquireLayerTexturesForMainThread",
    310                 client,
    311                 2,
    312                 4);
    313   EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 3, 4);
    314   client.Reset();
    315 
    316   // Although the compositor cannot draw because textures are locked by main
    317   // thread, we continue requesting SetNeedsBeginFrame in anticipation of the
    318   // unlock.
    319   EXPECT_TRUE(client.needs_begin_frame());
    320 
    321   // Trigger the commit
    322   scheduler->FinishCommit();
    323   EXPECT_TRUE(client.needs_begin_frame());
    324   client.Reset();
    325 
    326   // Between commit and draw, texture acquisition for main thread delayed,
    327   // and main thread blocks.
    328   scheduler->SetMainThreadNeedsLayerTextures();
    329   EXPECT_EQ(0, client.num_actions_());
    330   client.Reset();
    331 
    332   // No implicit commit is expected.
    333   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    334   EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 3);
    335   EXPECT_ACTION("ScheduledActionAcquireLayerTexturesForMainThread",
    336                 client,
    337                 1,
    338                 3);
    339   EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 2, 3);
    340   client.Reset();
    341 
    342   // Compositor not scheduled to draw because textures are locked by main
    343   // thread.
    344   EXPECT_FALSE(client.needs_begin_frame());
    345 
    346   // Needs an explicit commit from the main thread.
    347   scheduler->SetNeedsCommit();
    348   EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2);
    349   EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2);
    350   client.Reset();
    351 
    352   // Trigger the commit
    353   scheduler->FinishCommit();
    354   EXPECT_TRUE(client.needs_begin_frame());
    355 }
    356 
    357 TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition) {
    358   FakeSchedulerClient client;
    359   SchedulerSettings default_scheduler_settings;
    360   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
    361   scheduler->SetCanStart();
    362   scheduler->SetVisible(true);
    363   scheduler->SetCanDraw(true);
    364 
    365   EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
    366   client.Reset();
    367   scheduler->DidCreateAndInitializeOutputSurface();
    368 
    369   scheduler->SetNeedsCommit();
    370   scheduler->FinishCommit();
    371   scheduler->SetMainThreadNeedsLayerTextures();
    372   scheduler->SetNeedsCommit();
    373   client.Reset();
    374   // Verify that pending texture acquisition fires when visibility
    375   // is lost in order to avoid a deadlock.
    376   scheduler->SetVisible(false);
    377   EXPECT_SINGLE_ACTION("ScheduledActionAcquireLayerTexturesForMainThread",
    378                        client);
    379   client.Reset();
    380 
    381   // Already sent a begin frame on this current frame, so wait.
    382   scheduler->SetVisible(true);
    383   EXPECT_EQ(0, client.num_actions_());
    384   client.Reset();
    385 
    386   // Regaining visibility with textures acquired by main thread while
    387   // compositor is waiting for first draw should result in a request
    388   // for a new frame in order to escape a deadlock.
    389   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    390   EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2);
    391   EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2);
    392 }
    393 
    394 class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
    395  public:
    396   virtual void ScheduledActionSendBeginFrameToMainThread() OVERRIDE {}
    397   virtual ScheduledActionDrawAndSwapResult
    398   ScheduledActionDrawAndSwapIfPossible() OVERRIDE {
    399     // Only SetNeedsRedraw the first time this is called
    400     if (!num_draws_)
    401       scheduler_->SetNeedsRedraw();
    402     return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
    403   }
    404 
    405   virtual ScheduledActionDrawAndSwapResult ScheduledActionDrawAndSwapForced()
    406       OVERRIDE {
    407     NOTREACHED();
    408     return ScheduledActionDrawAndSwapResult(true, true);
    409   }
    410 
    411   virtual void ScheduledActionCommit() OVERRIDE {}
    412   virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {}
    413   virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {}
    414 };
    415 
    416 // Tests for two different situations:
    417 // 1. the scheduler dropping SetNeedsRedraw requests that happen inside
    418 //    a ScheduledActionDrawAndSwap
    419 // 2. the scheduler drawing twice inside a single tick
    420 TEST(SchedulerTest, RequestRedrawInsideDraw) {
    421   SchedulerClientThatsetNeedsDrawInsideDraw client;
    422   SchedulerSettings default_scheduler_settings;
    423   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
    424   scheduler->SetCanStart();
    425   scheduler->SetVisible(true);
    426   scheduler->SetCanDraw(true);
    427   scheduler->DidCreateAndInitializeOutputSurface();
    428 
    429   scheduler->SetNeedsRedraw();
    430   EXPECT_TRUE(scheduler->RedrawPending());
    431   EXPECT_TRUE(client.needs_begin_frame());
    432   EXPECT_EQ(0, client.num_draws());
    433 
    434   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    435   EXPECT_EQ(1, client.num_draws());
    436   EXPECT_TRUE(scheduler->RedrawPending());
    437   EXPECT_TRUE(client.needs_begin_frame());
    438 
    439   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    440   EXPECT_EQ(2, client.num_draws());
    441   EXPECT_FALSE(scheduler->RedrawPending());
    442   EXPECT_FALSE(client.needs_begin_frame());
    443 }
    444 
    445 // Test that requesting redraw inside a failed draw doesn't lose the request.
    446 TEST(SchedulerTest, RequestRedrawInsideFailedDraw) {
    447   SchedulerClientThatsetNeedsDrawInsideDraw client;
    448   SchedulerSettings default_scheduler_settings;
    449   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
    450   scheduler->SetCanStart();
    451   scheduler->SetVisible(true);
    452   scheduler->SetCanDraw(true);
    453   scheduler->DidCreateAndInitializeOutputSurface();
    454 
    455   client.SetDrawWillHappen(false);
    456 
    457   scheduler->SetNeedsRedraw();
    458   EXPECT_TRUE(scheduler->RedrawPending());
    459   EXPECT_TRUE(client.needs_begin_frame());
    460   EXPECT_EQ(0, client.num_draws());
    461 
    462   // Fail the draw.
    463   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    464   EXPECT_EQ(1, client.num_draws());
    465 
    466   // We have a commit pending and the draw failed, and we didn't lose the redraw
    467   // request.
    468   EXPECT_TRUE(scheduler->CommitPending());
    469   EXPECT_TRUE(scheduler->RedrawPending());
    470   EXPECT_TRUE(client.needs_begin_frame());
    471 
    472   // Fail the draw again.
    473   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    474   EXPECT_EQ(2, client.num_draws());
    475   EXPECT_TRUE(scheduler->CommitPending());
    476   EXPECT_TRUE(scheduler->RedrawPending());
    477   EXPECT_TRUE(client.needs_begin_frame());
    478 
    479   // Draw successfully.
    480   client.SetDrawWillHappen(true);
    481   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    482   EXPECT_EQ(3, client.num_draws());
    483   EXPECT_TRUE(scheduler->CommitPending());
    484   EXPECT_FALSE(scheduler->RedrawPending());
    485   EXPECT_TRUE(client.needs_begin_frame());
    486 }
    487 
    488 class SchedulerClientThatsetNeedsCommitInsideDraw : public FakeSchedulerClient {
    489  public:
    490   virtual void ScheduledActionSendBeginFrameToMainThread() OVERRIDE {}
    491   virtual ScheduledActionDrawAndSwapResult
    492   ScheduledActionDrawAndSwapIfPossible() OVERRIDE {
    493     // Only SetNeedsCommit the first time this is called
    494     if (!num_draws_)
    495       scheduler_->SetNeedsCommit();
    496     return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
    497   }
    498 
    499   virtual ScheduledActionDrawAndSwapResult ScheduledActionDrawAndSwapForced()
    500       OVERRIDE {
    501     NOTREACHED();
    502     return ScheduledActionDrawAndSwapResult(true, true);
    503   }
    504 
    505   virtual void ScheduledActionCommit() OVERRIDE {}
    506   virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {}
    507   virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {}
    508 };
    509 
    510 // Tests for the scheduler infinite-looping on SetNeedsCommit requests that
    511 // happen inside a ScheduledActionDrawAndSwap
    512 TEST(SchedulerTest, RequestCommitInsideDraw) {
    513   SchedulerClientThatsetNeedsCommitInsideDraw client;
    514   SchedulerSettings default_scheduler_settings;
    515   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
    516   scheduler->SetCanStart();
    517   scheduler->SetVisible(true);
    518   scheduler->SetCanDraw(true);
    519   scheduler->DidCreateAndInitializeOutputSurface();
    520 
    521   scheduler->SetNeedsRedraw();
    522   EXPECT_TRUE(scheduler->RedrawPending());
    523   EXPECT_EQ(0, client.num_draws());
    524   EXPECT_TRUE(client.needs_begin_frame());
    525 
    526   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    527   EXPECT_EQ(1, client.num_draws());
    528   EXPECT_TRUE(scheduler->CommitPending());
    529   EXPECT_TRUE(client.needs_begin_frame());
    530   scheduler->FinishCommit();
    531 
    532   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    533   EXPECT_EQ(2, client.num_draws());;
    534   EXPECT_FALSE(scheduler->RedrawPending());
    535   EXPECT_FALSE(scheduler->CommitPending());
    536   EXPECT_FALSE(client.needs_begin_frame());
    537 }
    538 
    539 // Tests that when a draw fails then the pending commit should not be dropped.
    540 TEST(SchedulerTest, RequestCommitInsideFailedDraw) {
    541   SchedulerClientThatsetNeedsDrawInsideDraw client;
    542   SchedulerSettings default_scheduler_settings;
    543   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
    544   scheduler->SetCanStart();
    545   scheduler->SetVisible(true);
    546   scheduler->SetCanDraw(true);
    547   scheduler->DidCreateAndInitializeOutputSurface();
    548 
    549   client.SetDrawWillHappen(false);
    550 
    551   scheduler->SetNeedsRedraw();
    552   EXPECT_TRUE(scheduler->RedrawPending());
    553   EXPECT_TRUE(client.needs_begin_frame());
    554   EXPECT_EQ(0, client.num_draws());
    555 
    556   // Fail the draw.
    557   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    558   EXPECT_EQ(1, client.num_draws());
    559 
    560   // We have a commit pending and the draw failed, and we didn't lose the commit
    561   // request.
    562   EXPECT_TRUE(scheduler->CommitPending());
    563   EXPECT_TRUE(scheduler->RedrawPending());
    564   EXPECT_TRUE(client.needs_begin_frame());
    565 
    566   // Fail the draw again.
    567   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    568   EXPECT_EQ(2, client.num_draws());
    569   EXPECT_TRUE(scheduler->CommitPending());
    570   EXPECT_TRUE(scheduler->RedrawPending());
    571   EXPECT_TRUE(client.needs_begin_frame());
    572 
    573   // Draw successfully.
    574   client.SetDrawWillHappen(true);
    575   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    576   EXPECT_EQ(3, client.num_draws());
    577   EXPECT_TRUE(scheduler->CommitPending());
    578   EXPECT_FALSE(scheduler->RedrawPending());
    579   EXPECT_TRUE(client.needs_begin_frame());
    580 }
    581 
    582 TEST(SchedulerTest, NoSwapWhenDrawFails) {
    583   SchedulerClientThatsetNeedsCommitInsideDraw client;
    584   SchedulerSettings default_scheduler_settings;
    585   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
    586   scheduler->SetCanStart();
    587   scheduler->SetVisible(true);
    588   scheduler->SetCanDraw(true);
    589   scheduler->DidCreateAndInitializeOutputSurface();
    590 
    591   scheduler->SetNeedsRedraw();
    592   EXPECT_TRUE(scheduler->RedrawPending());
    593   EXPECT_TRUE(client.needs_begin_frame());
    594   EXPECT_EQ(0, client.num_draws());
    595 
    596   // Draw successfully, this starts a new frame.
    597   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    598   EXPECT_EQ(1, client.num_draws());
    599 
    600   scheduler->SetNeedsRedraw();
    601   EXPECT_TRUE(scheduler->RedrawPending());
    602   EXPECT_TRUE(client.needs_begin_frame());
    603 
    604   // Fail to draw, this should not start a frame.
    605   client.SetDrawWillHappen(false);
    606   scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
    607   EXPECT_EQ(2, client.num_draws());
    608 }
    609 
    610 TEST(SchedulerTest, NoSwapWhenSwapFailsDuringForcedCommit) {
    611   FakeSchedulerClient client;
    612   SchedulerSettings default_scheduler_settings;
    613   Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
    614 
    615   // Tell the client that it will fail to swap.
    616   client.SetDrawWillHappen(true);
    617   client.SetSwapWillHappenIfDrawHappens(false);
    618 
    619   // Get the compositor to do a ScheduledActionDrawAndSwapForced.
    620   scheduler->SetCanDraw(true);
    621   scheduler->SetNeedsRedraw();
    622   scheduler->SetNeedsForcedRedraw();
    623   EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapForced"));
    624 }
    625 
    626 }  // namespace
    627 }  // namespace cc
    628