[chromium] Slow down commit and draw rate based on visibility and draw completion
authornduca@chromium.org <nduca@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 2 Nov 2011 21:57:20 +0000 (21:57 +0000)
committernduca@chromium.org <nduca@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 2 Nov 2011 21:57:20 +0000 (21:57 +0000)
https://bugs.webkit.org/show_bug.cgi?id=71267

Reviewed by James Robinson.

Source/WebCore:

* platform/graphics/chromium/cc/CCLayerTreeHost.h:
(WebCore::CCLayerTreeHost::visible):
* platform/graphics/chromium/cc/CCLayerTreeHostImpl.h:
(WebCore::CCLayerTreeHostImpl::visible):
* platform/graphics/chromium/cc/CCScheduler.cpp:
(WebCore::CCScheduler::beginFrame):
(WebCore::CCScheduler::processScheduledActions):
* platform/graphics/chromium/cc/CCScheduler.h:
* platform/graphics/chromium/cc/CCSchedulerStateMachine.cpp:
(WebCore::CCSchedulerStateMachine::nextAction):
(WebCore::CCSchedulerStateMachine::updateState):
* platform/graphics/chromium/cc/CCSchedulerStateMachine.h:
* platform/graphics/chromium/cc/CCThreadProxy.cpp:
(WebCore::CCThreadProxy::visible):
* platform/graphics/chromium/cc/CCThreadProxy.h:

Source/WebKit/chromium:

* tests/CCSchedulerStateMachineTest.cpp:
(WebCore::TEST):
* tests/CCSchedulerTest.cpp:
(WebKitTests::FakeCCSchedulerClient::reset):
(WebKitTests::FakeCCSchedulerClient::setVisible):
(WebKitTests::FakeCCSchedulerClient::visible):
(WebKitTests::TEST):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@99100 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.h
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.h
Source/WebCore/platform/graphics/chromium/cc/CCScheduler.cpp
Source/WebCore/platform/graphics/chromium/cc/CCScheduler.h
Source/WebCore/platform/graphics/chromium/cc/CCSchedulerStateMachine.cpp
Source/WebCore/platform/graphics/chromium/cc/CCSchedulerStateMachine.h
Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.cpp
Source/WebKit/chromium/ChangeLog
Source/WebKit/chromium/tests/CCSchedulerStateMachineTest.cpp
Source/WebKit/chromium/tests/CCSchedulerTest.cpp

index 59e9e84..fc2b850 100644 (file)
@@ -1,3 +1,26 @@
+2011-10-31  Nat Duca  <nduca@chromium.org>
+
+        [chromium] Slow down commit and draw rate based on visibility and draw completion
+        https://bugs.webkit.org/show_bug.cgi?id=71267
+
+        Reviewed by James Robinson.
+
+        * platform/graphics/chromium/cc/CCLayerTreeHost.h:
+        (WebCore::CCLayerTreeHost::visible):
+        * platform/graphics/chromium/cc/CCLayerTreeHostImpl.h:
+        (WebCore::CCLayerTreeHostImpl::visible):
+        * platform/graphics/chromium/cc/CCScheduler.cpp:
+        (WebCore::CCScheduler::beginFrame):
+        (WebCore::CCScheduler::processScheduledActions):
+        * platform/graphics/chromium/cc/CCScheduler.h:
+        * platform/graphics/chromium/cc/CCSchedulerStateMachine.cpp:
+        (WebCore::CCSchedulerStateMachine::nextAction):
+        (WebCore::CCSchedulerStateMachine::updateState):
+        * platform/graphics/chromium/cc/CCSchedulerStateMachine.h:
+        * platform/graphics/chromium/cc/CCThreadProxy.cpp:
+        (WebCore::CCThreadProxy::visible):
+        * platform/graphics/chromium/cc/CCThreadProxy.h:
+
 2011-11-02  Dan Bernstein  <mitz@apple.com>
 
         <rdar://problem/10336700> Add API to get rendered text image without having to select it
index 04f76db..2e2d8fc 100644 (file)
@@ -161,6 +161,7 @@ public:
 
     bool visible() const { return m_visible; }
     void setVisible(bool);
+
     void setHaveWheelEventHandlers(bool);
 
     void updateLayers();
index 2affea2..5a68f0f 100644 (file)
@@ -86,6 +86,7 @@ public:
     CCLayerImpl* rootLayer() const { return m_rootLayerImpl.get(); }
     void setRootLayer(PassRefPtr<CCLayerImpl>);
 
+    bool visible() const { return m_visible; }
     void setVisible(bool);
     void setHaveWheelEventHandlers(bool haveWheelEventHandlers) { m_haveWheelEventHandlers = haveWheelEventHandlers; }
 
index 50ee3ab..07e2227 100644 (file)
@@ -46,6 +46,10 @@ CCScheduler::~CCScheduler()
     m_frameRateController->setActive(false);
 }
 
+void CCScheduler::setVisible(bool visible)
+{
+    m_stateMachine.setVisible(visible);
+}
 void CCScheduler::setNeedsAnimate()
 {
     // Stub through to requestCommit for now.
@@ -55,20 +59,20 @@ void CCScheduler::setNeedsAnimate()
 void CCScheduler::setNeedsCommit()
 {
     m_stateMachine.setNeedsCommit();
-    processScheduledActions(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE);
+    processScheduledActions();
 }
 
 void CCScheduler::setNeedsRedraw()
 {
     m_stateMachine.setNeedsRedraw();
-    processScheduledActions(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE);
+    processScheduledActions();
 }
 
 void CCScheduler::beginFrameComplete()
 {
     TRACE_EVENT("CCScheduler::beginFrameComplete", this, 0);
     m_stateMachine.beginFrameComplete();
-    processScheduledActions(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE);
+    processScheduledActions();
 }
 
 void CCScheduler::didSwapBuffersComplete()
@@ -89,19 +93,22 @@ void CCScheduler::beginFrame()
         m_updateMoreResourcesPending = false;
         m_stateMachine.beginUpdateMoreResourcesComplete(m_client->hasMoreResourceUpdates());
     }
-    processScheduledActions(CCSchedulerStateMachine::IMMEDIATE_STATE_INSIDE_VSYNC);
+    TRACE_EVENT("CCScheduler::beginFrame", this, 0);
+
+    m_stateMachine.setInsideVSync(true);
+    processScheduledActions();
+    m_stateMachine.setInsideVSync(false);
 }
 
-void CCScheduler::processScheduledActions(CCSchedulerStateMachine::ImmediateState immediateState)
+void CCScheduler::processScheduledActions()
 {
     // Early out so we don't spam TRACE_EVENTS with useless processScheduledActions.
-    if (m_stateMachine.nextAction(immediateState) == CCSchedulerStateMachine::ACTION_NONE)
+    if (m_stateMachine.nextAction() == CCSchedulerStateMachine::ACTION_NONE)
         return;
 
-    TRACE_EVENT("CCScheduler::processScheduledActions", this, 0);
     CCSchedulerStateMachine::Action action;
     do {
-        action = m_stateMachine.nextAction(immediateState);
+        action = m_stateMachine.nextAction();
         switch (action) {
         case CCSchedulerStateMachine::ACTION_NONE:
             return;
index 384a5e5..33e813b 100644 (file)
@@ -58,6 +58,8 @@ public:
 
     virtual ~CCScheduler();
 
+    void setVisible(bool);
+
     void setNeedsAnimate();
     void setNeedsCommit();
     void setNeedsRedraw();
@@ -76,7 +78,7 @@ public:
 private:
     CCScheduler(CCSchedulerClient*, PassOwnPtr<CCFrameRateController>);
 
-    void processScheduledActions(CCSchedulerStateMachine::ImmediateState);
+    void processScheduledActions();
 
     CCSchedulerClient* m_client;
     OwnPtr<CCFrameRateController> m_frameRateController;
index 4281bdd..4901b64 100644 (file)
@@ -32,26 +32,27 @@ CCSchedulerStateMachine::CCSchedulerStateMachine()
     : m_commitState(COMMIT_STATE_IDLE)
     , m_needsRedraw(false)
     , m_needsCommit(false)
-    , m_updateMoreResourcesPending(false) { }
+    , m_updateMoreResourcesPending(false)
+    , m_insideVSync(false)
+    , m_visible(false) { }
 
-CCSchedulerStateMachine::Action CCSchedulerStateMachine::nextAction(ImmediateState immediateState) const
+CCSchedulerStateMachine::Action CCSchedulerStateMachine::nextAction() const
 {
-    bool insideVSyncTick = immediateState & IMMEDIATE_STATE_INSIDE_VSYNC;
     switch (m_commitState) {
     case COMMIT_STATE_IDLE:
-        if (m_needsRedraw && insideVSyncTick)
+        if (m_needsRedraw && m_insideVSync && m_visible)
             return ACTION_DRAW;
-        if (m_needsCommit)
+        if (m_needsCommit && m_visible)
             return ACTION_BEGIN_FRAME;
         return ACTION_NONE;
 
     case COMMIT_STATE_FRAME_IN_PROGRESS:
-        if (m_needsRedraw && insideVSyncTick)
+        if (m_needsRedraw && m_insideVSync && m_visible)
             return ACTION_DRAW;
         return ACTION_NONE;
 
     case COMMIT_STATE_UPDATING_RESOURCES:
-        if (m_needsRedraw && insideVSyncTick)
+        if (m_needsRedraw && m_insideVSync && m_visible)
             return ACTION_DRAW;
         if (!m_updateMoreResourcesPending)
             return ACTION_BEGIN_UPDATE_MORE_RESOURCES;
@@ -59,6 +60,11 @@ CCSchedulerStateMachine::Action CCSchedulerStateMachine::nextAction(ImmediateSta
 
     case COMMIT_STATE_READY_TO_COMMIT:
         return ACTION_COMMIT;
+
+    case COMMIT_STATE_WAITING_FOR_FIRST_DRAW:
+        if (m_needsRedraw && m_insideVSync && m_visible)
+            return ACTION_DRAW;
+        return ACTION_NONE;
     }
     ASSERT_NOT_REACHED();
     return ACTION_NONE;
@@ -71,6 +77,7 @@ void CCSchedulerStateMachine::updateState(Action action)
         return;
 
     case ACTION_BEGIN_FRAME:
+        ASSERT(m_visible);
         m_commitState = COMMIT_STATE_FRAME_IN_PROGRESS;
         m_needsCommit = false;
         return;
@@ -81,16 +88,33 @@ void CCSchedulerStateMachine::updateState(Action action)
         return;
 
     case ACTION_COMMIT:
-        m_commitState = COMMIT_STATE_IDLE;
+        if (m_needsCommit || !m_visible)
+            m_commitState = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
+        else
+            m_commitState = COMMIT_STATE_IDLE;
         m_needsRedraw = true;
         return;
 
     case ACTION_DRAW:
         m_needsRedraw = false;
+        if (m_commitState == COMMIT_STATE_WAITING_FOR_FIRST_DRAW) {
+            ASSERT(m_needsCommit);
+            m_commitState = COMMIT_STATE_IDLE;
+        }
         return;
     }
 }
 
+void CCSchedulerStateMachine::setInsideVSync(bool insideVSync)
+{
+    m_insideVSync = insideVSync;
+}
+
+void CCSchedulerStateMachine::setVisible(bool visible)
+{
+    m_visible = visible;
+}
+
 void CCSchedulerStateMachine::setNeedsRedraw()
 {
     m_needsRedraw = true;
index 3f41e60..4570e59 100644 (file)
@@ -29,7 +29,7 @@
 
 namespace WebCore {
 
-// The CCSchedulerStateMachine decides how to coordinates main thread activites
+// The CCSchedulerStateMachine decides how to coordinate main thread activites
 // like painting/running javascript with rendering and input activities on the
 // impl thread.
 //
@@ -48,6 +48,7 @@ public:
         COMMIT_STATE_FRAME_IN_PROGRESS,
         COMMIT_STATE_UPDATING_RESOURCES,
         COMMIT_STATE_READY_TO_COMMIT,
+        COMMIT_STATE_WAITING_FOR_FIRST_DRAW,
     };
 
     bool commitPending() const
@@ -64,13 +65,15 @@ public:
         ACTION_COMMIT,
         ACTION_DRAW,
     };
-    enum ImmediateState {
-        IMMEDIATE_STATE_NONE = 0,
-        IMMEDIATE_STATE_INSIDE_VSYNC = 1,
-    };
-    Action nextAction(ImmediateState) const;
+    Action nextAction() const;
     void updateState(Action);
 
+    // Indicates whether the system is inside a vsync callback.
+    void setInsideVSync(bool);
+
+    // Indicates whether the LayerTreeHostImpl is visible.
+    void setVisible(bool);
+
     // Indicates that a redraw is required, either due to the impl tree changing
     // or the screen being damaged and simply needing redisplay.
     void setNeedsRedraw();
@@ -95,6 +98,8 @@ protected:
     bool m_needsRedraw;
     bool m_needsCommit;
     bool m_updateMoreResourcesPending;
+    bool m_insideVSync;
+    bool m_visible;
 };
 
 }
index 92c91b5..2a6bda1 100644 (file)
@@ -253,7 +253,6 @@ void CCThreadProxy::setVisible(bool visible)
         s_ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::didBecomeInvisibleOnImplThread, AllowCrossThreadAccess(&completion)));
         return;
     }
-
     setNeedsRedraw();
 }
 
@@ -261,6 +260,7 @@ void CCThreadProxy::didBecomeInvisibleOnImplThread(CCCompletionEvent* completion
 {
     ASSERT(isImplThread());
     m_layerTreeHost->didBecomeInvisibleOnImplThread(m_layerTreeHostImpl.get());
+    m_schedulerOnImplThread->setVisible(false);
     m_layerTreeHostImpl->setVisible(false);
     completion->signal();
 }
@@ -445,6 +445,7 @@ void CCThreadProxy::scheduledActionCommit()
     m_layerTreeHost->beginCommitOnImplThread(m_layerTreeHostImpl.get());
     CCTextureUpdater updater(m_layerTreeHostImpl->contentsTextureAllocator());
     m_layerTreeHostImpl->setVisible(m_layerTreeHost->visible());
+    m_schedulerOnImplThread->setVisible(m_layerTreeHostImpl->visible());
     m_layerTreeHost->finishCommitOnImplThread(m_layerTreeHostImpl.get());
 
     m_layerTreeHostImpl->commitComplete();
@@ -508,6 +509,7 @@ void CCThreadProxy::initializeImplOnImplThread(CCCompletionEvent* completion)
     const double displayRefreshIntervalMs = 1000.0 / 60.0;
     OwnPtr<CCFrameRateController> frameRateController = adoptPtr(new CCFrameRateController(CCDelayBasedTimeSource::create(displayRefreshIntervalMs, s_ccThread)));
     m_schedulerOnImplThread = CCScheduler::create(this, frameRateController.release());
+    m_schedulerOnImplThread->setVisible(m_layerTreeHostImpl->visible());
     completion->signal();
 }
 
index 405e191..b59ae14 100644 (file)
@@ -1,3 +1,18 @@
+2011-10-31  Nat Duca  <nduca@chromium.org>
+
+        [chromium] Slow down commit and draw rate based on visibility and draw completion
+        https://bugs.webkit.org/show_bug.cgi?id=71267
+
+        Reviewed by James Robinson.
+
+        * tests/CCSchedulerStateMachineTest.cpp:
+        (WebCore::TEST):
+        * tests/CCSchedulerTest.cpp:
+        (WebKitTests::FakeCCSchedulerClient::reset):
+        (WebKitTests::FakeCCSchedulerClient::setVisible):
+        (WebKitTests::FakeCCSchedulerClient::visible):
+        (WebKitTests::TEST):
+
 2011-11-02  Tom Sepez  <tsepez@chromium.org>
 
         XSSAuditor is silent
index 4b5eac4..7f08cc7 100644 (file)
@@ -39,7 +39,8 @@ const CCSchedulerStateMachine::CommitState allCommitStates[] = {
     CCSchedulerStateMachine::COMMIT_STATE_IDLE,
     CCSchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS,
     CCSchedulerStateMachine::COMMIT_STATE_UPDATING_RESOURCES,
-    CCSchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT
+    CCSchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
+    CCSchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW
 };
 
 // Exposes the protected state fields of the CCSchedulerStateMachine for testing
@@ -54,6 +55,9 @@ public:
     void setNeedsRedraw(bool b) { m_needsRedraw = b; }
     bool needsRedraw() const { return m_needsRedraw; }
 
+    bool insideVSync() const { return m_insideVSync; }
+    bool visible() const { return m_visible; }
+
     void setUpdateMoreResourcesPending(bool b) { m_updateMoreResourcesPending = b; }
     bool updateMoreResourcesPending() const { return m_updateMoreResourcesPending; }
 };
@@ -67,8 +71,12 @@ TEST(CCSchedulerStateMachineTest, TestNextActionBeginsFrameIfNeeded)
         state.setNeedsRedraw(false);
         state.setNeedsCommit(false);
         state.setUpdateMoreResourcesPending(false);
-        EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
-        EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_INSIDE_VSYNC));
+        state.setVisible(true);
+
+        state.setInsideVSync(false);
+        EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
+        state.setInsideVSync(true);
+        EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
     }
 
     // If commit requested, begin a frame
@@ -78,12 +86,13 @@ TEST(CCSchedulerStateMachineTest, TestNextActionBeginsFrameIfNeeded)
         state.setNeedsRedraw(false);
         state.setNeedsCommit(true);
         state.setUpdateMoreResourcesPending(false);
-        EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_FRAME, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
+        state.setVisible(true);
     }
 
     // Begin the frame, make sure needsCommit and commitState update correctly.
     {
         StateMachine state;
+        state.setVisible(true);
         state.updateState(CCSchedulerStateMachine::ACTION_BEGIN_FRAME);
         EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS, state.commitState());
         EXPECT_FALSE(state.needsCommit());
@@ -98,26 +107,28 @@ TEST(CCSchedulerStateMachineTest, TestNextActionDrawsOnVSync)
         StateMachine state;
         state.setCommitState(allCommitStates[i]);
         state.setNeedsRedraw(true);
+        state.setVisible(true);
+        state.setInsideVSync(false);
 
-        // Case 1: needsCommit=false updateMoreResourcesPending=false vsync=false.
+        // Case 1: needsCommit=false updateMoreResourcesPending=false.
         state.setNeedsCommit(false);
         state.setUpdateMoreResourcesPending(false);
-        EXPECT_NE(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
+        EXPECT_NE(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction());
 
-        // Case 2: needsCommit=false updateMoreResourcesPending=true vsync=false.
+        // Case 2: needsCommit=false updateMoreResourcesPending=true.
         state.setNeedsCommit(false);
         state.setUpdateMoreResourcesPending(true);
-        EXPECT_NE(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
+        EXPECT_NE(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction());
 
-        // Case 3: needsCommit=true updateMoreResourcesPending=false vsync=false.
+        // Case 3: needsCommit=true updateMoreResourcesPending=false.
         state.setNeedsCommit(true);
         state.setUpdateMoreResourcesPending(false);
-        EXPECT_NE(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
+        EXPECT_NE(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction());
 
-        // Case 4: needsCommit=true updateMoreResourcesPending=true vsync=false.
+        // Case 4: needsCommit=true updateMoreResourcesPending=true.
         state.setNeedsCommit(true);
         state.setUpdateMoreResourcesPending(true);
-        EXPECT_NE(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
+        EXPECT_NE(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction());
     }
 
     // When on vsync, you should always draw. Expect if you're ready to commit, in which case commit.
@@ -125,31 +136,66 @@ TEST(CCSchedulerStateMachineTest, TestNextActionDrawsOnVSync)
         StateMachine state;
         state.setCommitState(allCommitStates[i]);
         state.setNeedsRedraw(true);
+        state.setVisible(true);
+        state.setInsideVSync(true);
         CCSchedulerStateMachine::Action expectedAction;
         if (allCommitStates[i] != CCSchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT)
             expectedAction = CCSchedulerStateMachine::ACTION_DRAW;
         else
             expectedAction = CCSchedulerStateMachine::ACTION_COMMIT;
 
-        // Case 1: needsCommit=false updateMoreResourcesPending=false vsync=true.
+        // Case 1: needsCommit=false updateMoreResourcesPending=false.
         state.setNeedsCommit(false);
         state.setUpdateMoreResourcesPending(false);
-        EXPECT_EQ(expectedAction, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_INSIDE_VSYNC));
+        EXPECT_EQ(expectedAction, state.nextAction());
 
-        // Case 2: needsCommit=false updateMoreResourcesPending=true vsync=true.
+        // Case 2: needsCommit=false updateMoreResourcesPending=true.
         state.setNeedsCommit(false);
         state.setUpdateMoreResourcesPending(true);
-        EXPECT_EQ(expectedAction, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_INSIDE_VSYNC));
+        EXPECT_EQ(expectedAction, state.nextAction());
 
-        // Case 3: needsCommit=true updateMoreResourcesPending=false vsync=true.
+        // Case 3: needsCommit=true updateMoreResourcesPending=false.
         state.setNeedsCommit(true);
         state.setUpdateMoreResourcesPending(false);
-        EXPECT_EQ(expectedAction, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_INSIDE_VSYNC));
+        EXPECT_EQ(expectedAction, state.nextAction());
 
-        // Case 4: needsCommit=true updateMoreResourcesPending=true vsync=true.
+        // Case 4: needsCommit=true updateMoreResourcesPending=true.
         state.setNeedsCommit(true);
         state.setUpdateMoreResourcesPending(true);
-        EXPECT_EQ(expectedAction, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_INSIDE_VSYNC));
+        EXPECT_EQ(expectedAction, state.nextAction());
+    }
+}
+
+TEST(CCSchedulerStateMachineTest, TestNoCommitStatesRedrawWhenInvisible)
+{
+    // If not visible, never redraw.
+    size_t numCommitStates = sizeof(allCommitStates) / sizeof(CCSchedulerStateMachine::CommitState);
+    for (size_t i = 0; i < numCommitStates; ++i) {
+        StateMachine state;
+        state.setCommitState(allCommitStates[i]);
+        state.setNeedsRedraw(true);
+        state.setInsideVSync(false);
+        state.setVisible(false);
+
+        // Case 1: needsCommit=false updateMoreResourcesPending=false.
+        state.setNeedsCommit(false);
+        state.setUpdateMoreResourcesPending(false);
+        EXPECT_NE(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction());
+
+        // Case 2: needsCommit=false updateMoreResourcesPending=true.
+        state.setNeedsCommit(false);
+        state.setUpdateMoreResourcesPending(true);
+        EXPECT_NE(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction());
+
+        // Case 3: needsCommit=true updateMoreResourcesPending=false.
+        state.setNeedsCommit(true);
+        state.setUpdateMoreResourcesPending(false);
+        EXPECT_NE(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction());
+
+        // Case 4: needsCommit=true updateMoreResourcesPending=true.
+        state.setNeedsCommit(true);
+        state.setUpdateMoreResourcesPending(true);
+        EXPECT_NE(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction());
     }
 }
 
@@ -159,17 +205,27 @@ TEST(CCSchedulerStateMachineTest, TestUpdates_NoRedraw_OneRoundOfUpdates)
     state.setCommitState(CCSchedulerStateMachine::COMMIT_STATE_UPDATING_RESOURCES);
     state.setNeedsRedraw(false);
     state.setUpdateMoreResourcesPending(false);
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_INSIDE_VSYNC));
+    state.setVisible(true);
+
+    // Verify we begin update, both for vsync and not vsync.
+    state.setInsideVSync(false);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction());
+    state.setInsideVSync(true);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction());
 
     // Begin an update.
     state.updateState(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES);
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_INSIDE_VSYNC));
+
+    // Veriify we don't do anything, both for vsync and not vsync.
+    state.setInsideVSync(false);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
+    state.setInsideVSync(true);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
 
     // End update with no more updates pending.
     state.beginUpdateMoreResourcesComplete(false);
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_COMMIT, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
+    state.setInsideVSync(false);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_COMMIT, state.nextAction());
 }
 
 TEST(CCSchedulerStateMachineTest, TestUpdates_NoRedraw_TwoRoundsOfUpdates)
@@ -178,24 +234,42 @@ TEST(CCSchedulerStateMachineTest, TestUpdates_NoRedraw_TwoRoundsOfUpdates)
     state.setCommitState(CCSchedulerStateMachine::COMMIT_STATE_UPDATING_RESOURCES);
     state.setNeedsRedraw(false);
     state.setUpdateMoreResourcesPending(false);
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_INSIDE_VSYNC));
+    state.setVisible(true);
 
-    // Begin an udpate.
+    // Verify the update begins, both for vsync and not vsync.
+    state.setInsideVSync(false);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction());
+    state.setInsideVSync(true);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction());
+
+    // Begin an update.
     state.updateState(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES);
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_INSIDE_VSYNC));
+
+    // Verify we do nothing, both for vsync and not vsync.
+    state.setInsideVSync(false);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
+    state.setInsideVSync(true);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
 
     // Ack the update with more pending.
     state.beginUpdateMoreResourcesComplete(true);
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_INSIDE_VSYNC));
 
-    // Begin another update, end it with none epending.
+    // Verify we update more, both for vsync and not vsync.
+    state.setInsideVSync(false);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction());
+    state.setInsideVSync(true);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction());
+
+    // Begin another update, while inside vsync. And, it updating.
+    state.setInsideVSync(true);
     state.updateState(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES);
     state.beginUpdateMoreResourcesComplete(false);
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_COMMIT, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_COMMIT, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_INSIDE_VSYNC));
+
+    // Make sure we commit, independent of vsync.
+    state.setInsideVSync(false);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_COMMIT, state.nextAction());
+    state.setInsideVSync(true);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_COMMIT, state.nextAction());
 }
 
 TEST(CCSchedulerStateMachineTest, TestUpdates_WithRedraw_OneRoundOfUpdates)
@@ -204,36 +278,54 @@ TEST(CCSchedulerStateMachineTest, TestUpdates_WithRedraw_OneRoundOfUpdates)
     state.setCommitState(CCSchedulerStateMachine::COMMIT_STATE_UPDATING_RESOURCES);
     state.setNeedsRedraw(true);
     state.setUpdateMoreResourcesPending(false);
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
+    state.setVisible(true);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction());
 
     // Begin an update.
     state.updateState(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES);
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_INSIDE_VSYNC));
 
-    // Draw.
+    // Ensure we draw on the next vsync even though an update is in-progress.
+    state.setInsideVSync(true);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction());
     state.updateState(CCSchedulerStateMachine::ACTION_DRAW);
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_INSIDE_VSYNC));
 
-    // Finish update, levae more resources pending.
+    // Ensure that we once we have drawn, we dont do anything else.
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
+
+    // Leave the vsync before we finish the update.
+    state.setInsideVSync(false);
+
+    // Finish update but leave more resources pending.
     state.beginUpdateMoreResourcesComplete(true);
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_INSIDE_VSYNC));
 
-    // Begin another update. Finish it immediately.
+    // Verify that regardless of vsync, we update some more.
+    state.setInsideVSync(false);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction());
+    state.setInsideVSync(true);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction());
+
+    // Begin another update. Finish it immediately. Inside the vsync.
+    state.setInsideVSync(true);
     state.updateState(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES);
+    state.setInsideVSync(false);
     state.beginUpdateMoreResourcesComplete(false);
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_COMMIT, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_COMMIT, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_INSIDE_VSYNC));
+
+    // Verify we commit regardless of vsync state
+    state.setInsideVSync(false);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_COMMIT, state.nextAction());
+    state.setInsideVSync(true);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_COMMIT, state.nextAction());
 }
 
 TEST(CCSchedulerStateMachineTest, TestSetNeedsCommitIsNotLost)
 {
     StateMachine state;
     state.setNeedsCommit(true);
+    state.setVisible(true);
 
     // Begin the frame.
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_FRAME, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
-    state.updateState(state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_FRAME, state.nextAction());
+    state.updateState(state.nextAction());
     EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS, state.commitState());
 
     // Now, while the frame is in progress, set another commit.
@@ -243,44 +335,54 @@ TEST(CCSchedulerStateMachineTest, TestSetNeedsCommitIsNotLost)
     // Let the frame finish.
     state.beginFrameComplete();
     EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_UPDATING_RESOURCES, state.commitState());
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction());
     state.updateState(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES);
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
     state.beginUpdateMoreResourcesComplete(false);
     EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT, state.commitState());
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_COMMIT, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_COMMIT, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_INSIDE_VSYNC));
+
+    // Expect to commit regardless of vsync state.
+    state.setInsideVSync(false);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_COMMIT, state.nextAction());
+    state.setInsideVSync(true);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_COMMIT, state.nextAction());
+
+    // Commit and make sure we draw on next vsync
     state.updateState(CCSchedulerStateMachine::ACTION_COMMIT);
-    EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_IDLE, state.commitState());
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction());
+    EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW, state.commitState());
+    state.updateState(CCSchedulerStateMachine::ACTION_DRAW);
 
     // Verify that another commit will begin.
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_FRAME, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
+    state.setInsideVSync(false);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_FRAME, state.nextAction());
 }
 
 TEST(CCSchedulerStateMachineTest, TestFullCycle)
 {
     StateMachine state;
+    state.setVisible(true);
 
     // Start clean and set commit.
     state.setNeedsCommit(true);
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_FRAME, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_FRAME, state.nextAction());
 
     // Begin the frame.
     state.updateState(CCSchedulerStateMachine::ACTION_BEGIN_FRAME);
     EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS, state.commitState());
     EXPECT_FALSE(state.needsCommit());
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
 
     // Tell the scheduler the frame finished.
     state.beginFrameComplete();
     EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_UPDATING_RESOURCES, state.commitState());
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction());
 
     // Tell the scheduler the update began and finished
     state.updateState(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES);
     state.beginUpdateMoreResourcesComplete(false);
     EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT, state.commitState());
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_COMMIT, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_COMMIT, state.nextAction());
 
     // Commit.
     state.updateState(CCSchedulerStateMachine::ACTION_COMMIT);
@@ -288,24 +390,120 @@ TEST(CCSchedulerStateMachineTest, TestFullCycle)
     EXPECT_TRUE(state.needsRedraw());
 
     // Expect to do nothing until vsync.
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
 
     // At vsync, draw.
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_INSIDE_VSYNC));
+    state.setInsideVSync(true);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction());
     state.updateState(CCSchedulerStateMachine::ACTION_DRAW);
+    state.setInsideVSync(false);
 
     // Should be synchronized, no draw needed, no action needed.
     EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_IDLE, state.commitState());
     EXPECT_FALSE(state.needsRedraw());
-    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction(CCSchedulerStateMachine::IMMEDIATE_STATE_NONE));
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
 }
 
 TEST(CCSchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween)
 {
+    StateMachine state;
+    state.setVisible(true);
+
+    // Start clean and set commit.
+    state.setNeedsCommit(true);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_FRAME, state.nextAction());
+
+    // Begin the frame.
+    state.updateState(CCSchedulerStateMachine::ACTION_BEGIN_FRAME);
+    EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS, state.commitState());
+    EXPECT_FALSE(state.needsCommit());
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
+
+    // Request another commit while the commit is in flight.
+    state.setNeedsCommit(true);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
+
+    // Tell the scheduler the frame finished.
+    state.beginFrameComplete();
+    EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_UPDATING_RESOURCES, state.commitState());
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction());
+
+    // Tell the scheduler the update began and finished
+    state.updateState(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES);
+    state.beginUpdateMoreResourcesComplete(false);
+    EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT, state.commitState());
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_COMMIT, state.nextAction());
+
+    // Commit.
+    state.updateState(CCSchedulerStateMachine::ACTION_COMMIT);
+    EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW, state.commitState());
+    EXPECT_TRUE(state.needsRedraw());
+
+    // Expect to do nothing until vsync.
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
+
+    // At vsync, draw.
+    state.setInsideVSync(true);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction());
+    state.updateState(CCSchedulerStateMachine::ACTION_DRAW);
+    state.setInsideVSync(false);
+
+    // Should be synchronized, no draw needed, no action needed.
+    EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_IDLE, state.commitState());
+    EXPECT_FALSE(state.needsRedraw());
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_FRAME, state.nextAction());
+}
+
+TEST(CCSchedulerStateMachineTest, TestRequestCommitInvisible)
+{
+    StateMachine state;
+    state.setNeedsCommit(true);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
 }
 
-TEST(CCSchedulerStateMachineTest, TestFullCycleWithRedrawInbetween)
+TEST(CCSchedulerStateMachineTest, TestGoesInvisibleMidCommit)
 {
+    StateMachine state;
+    state.setVisible(true);
+
+    // Start clean and set commit.
+    state.setNeedsCommit(true);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_FRAME, state.nextAction());
+
+    // Begin the frame while visible.
+    state.updateState(CCSchedulerStateMachine::ACTION_BEGIN_FRAME);
+    EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS, state.commitState());
+    EXPECT_FALSE(state.needsCommit());
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
+
+    // Become invisible
+    state.setVisible(false);
+
+    // Tell the scheduler the frame finished
+    state.beginFrameComplete();
+    EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_UPDATING_RESOURCES, state.commitState());
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction());
+
+    // Tell the scheduler the update began and finished
+    state.updateState(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES);
+    state.beginUpdateMoreResourcesComplete(false);
+    EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT, state.commitState());
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_COMMIT, state.nextAction());
+
+    // Commit in invisible state should leave us:
+    // - COMMIT_STATE_WAITING_FOR_FIRST_DRAW
+    // - Waiting for redraw.
+    // - No commit needed
+    state.updateState(CCSchedulerStateMachine::ACTION_COMMIT);
+    EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW, state.commitState());
+    EXPECT_TRUE(state.needsRedraw());
+    EXPECT_FALSE(state.needsCommit());
+
+    // Expect to do nothing, both in and out of vsync.
+    state.setInsideVSync(false);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
+    state.setInsideVSync(true);
+    EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
 }
 
 }
index 6c39f74..d4ab9a5 100644 (file)
@@ -40,7 +40,11 @@ namespace {
 class FakeCCSchedulerClient : public CCSchedulerClient {
 public:
     FakeCCSchedulerClient() { reset(); }
-    void reset() { m_actions.clear(); m_hasMoreResourceUpdates = false; }
+    void reset()
+    {
+        m_actions.clear();
+        m_hasMoreResourceUpdates = false;
+    }
 
     void setHasMoreResourceUpdates(bool b) { m_hasMoreResourceUpdates = b; }
 
@@ -48,7 +52,6 @@ public:
     const char* action(int i) const { return m_actions[i]; }
 
     virtual bool hasMoreResourceUpdates() const { return m_hasMoreResourceUpdates; }
-
     virtual void scheduledActionBeginFrame() { m_actions.push_back("scheduledActionBeginFrame"); }
     virtual void scheduledActionDrawAndSwap() { m_actions.push_back("scheduledActionDrawAndSwap"); }
     virtual void scheduledActionUpdateMoreResources() { m_actions.push_back("scheduledActionUpdateMoreResources"); }
@@ -64,6 +67,7 @@ TEST(CCSchedulerTest, RequestCommit)
     FakeCCSchedulerClient client;
     RefPtr<FakeCCTimeSource> timeSource = adoptRef(new FakeCCTimeSource());
     OwnPtr<CCScheduler> scheduler = CCScheduler::create(&client, adoptPtr(new CCFrameRateController(timeSource)));
+    scheduler->setVisible(true);
 
     // SetNeedsCommit should begin the frame.
     scheduler->setNeedsCommit();
@@ -96,6 +100,7 @@ TEST(CCSchedulerTest, RequestCommitAfterBeginFrame)
     FakeCCSchedulerClient client;
     RefPtr<FakeCCTimeSource> timeSource = adoptRef(new FakeCCTimeSource());
     OwnPtr<CCScheduler> scheduler = CCScheduler::create(&client, adoptPtr(new CCFrameRateController(timeSource)));
+    scheduler->setVisible(true);
 
     // SetNedsCommit should begin the frame.
     scheduler->setNeedsCommit();
@@ -110,16 +115,16 @@ TEST(CCSchedulerTest, RequestCommitAfterBeginFrame)
     // needed, beginFrameComplete should updateMoreResources, then commit, then
     // begin another frame.
     scheduler->beginFrameComplete();
-    EXPECT_EQ(3, client.numActions());
+    EXPECT_EQ(2, client.numActions());
     EXPECT_STREQ("scheduledActionUpdateMoreResources", client.action(0));
     EXPECT_STREQ("scheduledActionCommit", client.action(1));
-    EXPECT_STREQ("scheduledActionBeginFrame", client.action(2));
     client.reset();
 
     // Tick should draw but then begin another frame.
     timeSource->tick();
-    EXPECT_EQ(1, client.numActions());
+    EXPECT_EQ(2, client.numActions());
     EXPECT_STREQ("scheduledActionDrawAndSwap", client.action(0));
+    EXPECT_STREQ("scheduledActionBeginFrame", client.action(1));
     client.reset();
 }