Index: ui/cc/cc/CCSchedulerStateMachine.cpp |
diff --git a/ui/cc/cc/CCSchedulerStateMachine.cpp b/ui/cc/cc/CCSchedulerStateMachine.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c729d504b2a9257a98c81a0ce193126d13f85fc7 |
--- /dev/null |
+++ b/ui/cc/cc/CCSchedulerStateMachine.cpp |
@@ -0,0 +1,338 @@ |
+/* |
+ * Copyright (C) 2011 Google Inc. All rights reserved. |
+ * |
+ * Redistribution and use in source and binary forms, with or without |
+ * modification, are permitted provided that the following conditions |
+ * are met: |
+ * 1. Redistributions of source code must retain the above copyright |
+ * notice, this list of conditions and the following disclaimer. |
+ * 2. Redistributions in binary form must reproduce the above copyright |
+ * notice, this list of conditions and the following disclaimer in the |
+ * documentation and/or other materials provided with the distribution. |
+ * |
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY |
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ */ |
+ |
+#include "config.h" |
+ |
+#include "cc/CCSchedulerStateMachine.h" |
+ |
+#include <stdio.h> |
+ |
+namespace WebCore { |
+ |
+CCSchedulerStateMachine::CCSchedulerStateMachine() |
+ : m_commitState(COMMIT_STATE_IDLE) |
+ , m_currentFrameNumber(0) |
+ , m_lastFrameNumberWhereDrawWasCalled(-1) |
+ , m_consecutiveFailedDraws(0) |
+ , m_maximumNumberOfFailedDrawsBeforeDrawIsForced(3) |
+ , m_needsRedraw(false) |
+ , m_needsForcedRedraw(false) |
+ , m_needsForcedRedrawAfterNextCommit(false) |
+ , m_needsCommit(false) |
+ , m_needsForcedCommit(false) |
+ , m_mainThreadNeedsLayerTextures(false) |
+ , m_updateMoreResourcesPending(false) |
+ , m_insideVSync(false) |
+ , m_visible(false) |
+ , m_canBeginFrame(false) |
+ , m_canDraw(true) |
+ , m_drawIfPossibleFailed(false) |
+ , m_textureState(LAYER_TEXTURE_STATE_UNLOCKED) |
+ , m_contextState(CONTEXT_ACTIVE) |
+{ |
+} |
+ |
+bool CCSchedulerStateMachine::hasDrawnThisFrame() const |
+{ |
+ return m_currentFrameNumber == m_lastFrameNumberWhereDrawWasCalled; |
+} |
+ |
+bool CCSchedulerStateMachine::drawSuspendedUntilCommit() const |
+{ |
+ if (!m_canDraw) |
+ return true; |
+ if (!m_visible) |
+ return true; |
+ if (m_textureState == LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD) |
+ return true; |
+ return false; |
+} |
+ |
+bool CCSchedulerStateMachine::scheduledToDraw() const |
+{ |
+ if (!m_needsRedraw) |
+ return false; |
+ if (drawSuspendedUntilCommit()) |
+ return false; |
+ return true; |
+} |
+ |
+bool CCSchedulerStateMachine::shouldDraw() const |
+{ |
+ if (m_needsForcedRedraw) |
+ return true; |
+ |
+ if (!scheduledToDraw()) |
+ return false; |
+ if (!m_insideVSync) |
+ return false; |
+ if (hasDrawnThisFrame()) |
+ return false; |
+ if (m_contextState != CONTEXT_ACTIVE) |
+ return false; |
+ return true; |
+} |
+ |
+bool CCSchedulerStateMachine::shouldAcquireLayerTexturesForMainThread() const |
+{ |
+ if (!m_mainThreadNeedsLayerTextures) |
+ return false; |
+ if (m_textureState == LAYER_TEXTURE_STATE_UNLOCKED) |
+ return true; |
+ ASSERT(m_textureState == LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD); |
+ // Transfer the lock from impl thread to main thread immediately if the |
+ // impl thread is not even scheduled to draw. Guards against deadlocking. |
+ if (!scheduledToDraw()) |
+ return true; |
+ if (!vsyncCallbackNeeded()) |
+ return true; |
+ return false; |
+} |
+ |
+CCSchedulerStateMachine::Action CCSchedulerStateMachine::nextAction() const |
+{ |
+ if (shouldAcquireLayerTexturesForMainThread()) |
+ return ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD; |
+ switch (m_commitState) { |
+ case COMMIT_STATE_IDLE: |
+ if (m_contextState != CONTEXT_ACTIVE && m_needsForcedRedraw) |
+ return ACTION_DRAW_FORCED; |
+ if (m_contextState != CONTEXT_ACTIVE && m_needsForcedCommit) |
+ return ACTION_BEGIN_FRAME; |
+ if (m_contextState == CONTEXT_LOST) |
+ return ACTION_BEGIN_CONTEXT_RECREATION; |
+ if (m_contextState == CONTEXT_RECREATING) |
+ return ACTION_NONE; |
+ if (shouldDraw()) |
+ return m_needsForcedRedraw ? ACTION_DRAW_FORCED : ACTION_DRAW_IF_POSSIBLE; |
+ if (m_needsCommit && ((m_visible && m_canBeginFrame) || m_needsForcedCommit)) |
+ return ACTION_BEGIN_FRAME; |
+ return ACTION_NONE; |
+ |
+ case COMMIT_STATE_FRAME_IN_PROGRESS: |
+ if (shouldDraw()) |
+ return m_needsForcedRedraw ? ACTION_DRAW_FORCED : ACTION_DRAW_IF_POSSIBLE; |
+ return ACTION_NONE; |
+ |
+ case COMMIT_STATE_UPDATING_RESOURCES: |
+ if (shouldDraw()) |
+ return m_needsForcedRedraw ? ACTION_DRAW_FORCED : ACTION_DRAW_IF_POSSIBLE; |
+ if (!m_updateMoreResourcesPending) |
+ return ACTION_BEGIN_UPDATE_MORE_RESOURCES; |
+ return ACTION_NONE; |
+ |
+ case COMMIT_STATE_READY_TO_COMMIT: |
+ return ACTION_COMMIT; |
+ |
+ case COMMIT_STATE_WAITING_FOR_FIRST_DRAW: |
+ if (shouldDraw() || m_contextState == CONTEXT_LOST) |
+ return m_needsForcedRedraw ? ACTION_DRAW_FORCED : ACTION_DRAW_IF_POSSIBLE; |
+ // COMMIT_STATE_WAITING_FOR_FIRST_DRAW wants to enforce a draw. If m_canDraw is false |
+ // or textures are not available, proceed to the next step (similar as in COMMIT_STATE_IDLE). |
+ bool canCommit = m_visible || m_needsForcedCommit; |
+ if (m_needsCommit && canCommit && drawSuspendedUntilCommit()) |
+ return ACTION_BEGIN_FRAME; |
+ return ACTION_NONE; |
+ } |
+ ASSERT_NOT_REACHED(); |
+ return ACTION_NONE; |
+} |
+ |
+void CCSchedulerStateMachine::updateState(Action action) |
+{ |
+ switch (action) { |
+ case ACTION_NONE: |
+ return; |
+ |
+ case ACTION_BEGIN_FRAME: |
+ ASSERT(m_visible || m_needsForcedCommit); |
+ m_commitState = COMMIT_STATE_FRAME_IN_PROGRESS; |
+ m_needsCommit = false; |
+ m_needsForcedCommit = false; |
+ return; |
+ |
+ case ACTION_BEGIN_UPDATE_MORE_RESOURCES: |
+ ASSERT(m_commitState == COMMIT_STATE_UPDATING_RESOURCES); |
+ m_updateMoreResourcesPending = true; |
+ return; |
+ |
+ case ACTION_COMMIT: |
+ if ((m_needsCommit || !m_visible) && !m_needsForcedCommit) |
+ m_commitState = COMMIT_STATE_WAITING_FOR_FIRST_DRAW; |
+ else |
+ m_commitState = COMMIT_STATE_IDLE; |
+ |
+ m_needsRedraw = true; |
+ if (m_drawIfPossibleFailed) |
+ m_lastFrameNumberWhereDrawWasCalled = -1; |
+ |
+ if (m_needsForcedRedrawAfterNextCommit) { |
+ m_needsForcedRedrawAfterNextCommit = false; |
+ m_needsForcedRedraw = true; |
+ } |
+ |
+ m_textureState = LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD; |
+ return; |
+ |
+ case ACTION_DRAW_FORCED: |
+ case ACTION_DRAW_IF_POSSIBLE: |
+ m_needsRedraw = false; |
+ m_needsForcedRedraw = false; |
+ m_drawIfPossibleFailed = false; |
+ if (m_insideVSync) |
+ m_lastFrameNumberWhereDrawWasCalled = m_currentFrameNumber; |
+ if (m_commitState == COMMIT_STATE_WAITING_FOR_FIRST_DRAW) |
+ m_commitState = COMMIT_STATE_IDLE; |
+ if (m_textureState == LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD) |
+ m_textureState = LAYER_TEXTURE_STATE_UNLOCKED; |
+ return; |
+ |
+ case ACTION_BEGIN_CONTEXT_RECREATION: |
+ ASSERT(m_commitState == COMMIT_STATE_IDLE); |
+ ASSERT(m_contextState == CONTEXT_LOST); |
+ m_contextState = CONTEXT_RECREATING; |
+ return; |
+ |
+ case ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD: |
+ m_textureState = LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD; |
+ m_mainThreadNeedsLayerTextures = false; |
+ if (m_commitState != COMMIT_STATE_FRAME_IN_PROGRESS) |
+ m_needsCommit = true; |
+ return; |
+ } |
+} |
+ |
+void CCSchedulerStateMachine::setMainThreadNeedsLayerTextures() |
+{ |
+ ASSERT(!m_mainThreadNeedsLayerTextures); |
+ ASSERT(m_textureState != LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD); |
+ m_mainThreadNeedsLayerTextures = true; |
+} |
+ |
+bool CCSchedulerStateMachine::vsyncCallbackNeeded() const |
+{ |
+ if (!m_visible || m_contextState != CONTEXT_ACTIVE) { |
+ if (m_needsForcedRedraw || m_commitState == COMMIT_STATE_UPDATING_RESOURCES) |
+ return true; |
+ |
+ return false; |
+ } |
+ |
+ return m_needsRedraw || m_needsForcedRedraw || m_commitState == COMMIT_STATE_UPDATING_RESOURCES; |
+} |
+ |
+void CCSchedulerStateMachine::didEnterVSync() |
+{ |
+ m_insideVSync = true; |
+} |
+ |
+void CCSchedulerStateMachine::didLeaveVSync() |
+{ |
+ m_currentFrameNumber++; |
+ m_insideVSync = false; |
+} |
+ |
+void CCSchedulerStateMachine::setVisible(bool visible) |
+{ |
+ m_visible = visible; |
+} |
+ |
+void CCSchedulerStateMachine::setNeedsRedraw() |
+{ |
+ m_needsRedraw = true; |
+} |
+ |
+void CCSchedulerStateMachine::setNeedsForcedRedraw() |
+{ |
+ m_needsForcedRedraw = true; |
+} |
+ |
+void CCSchedulerStateMachine::didDrawIfPossibleCompleted(bool success) |
+{ |
+ m_drawIfPossibleFailed = !success; |
+ if (m_drawIfPossibleFailed) { |
+ m_needsRedraw = true; |
+ m_needsCommit = true; |
+ m_consecutiveFailedDraws++; |
+ if (m_consecutiveFailedDraws >= m_maximumNumberOfFailedDrawsBeforeDrawIsForced) { |
+ m_consecutiveFailedDraws = 0; |
+ // We need to force a draw, but it doesn't make sense to do this until |
+ // we've committed and have new textures. |
+ m_needsForcedRedrawAfterNextCommit = true; |
+ } |
+ } else |
+ m_consecutiveFailedDraws = 0; |
+} |
+ |
+void CCSchedulerStateMachine::setNeedsCommit() |
+{ |
+ m_needsCommit = true; |
+} |
+ |
+void CCSchedulerStateMachine::setNeedsForcedCommit() |
+{ |
+ m_needsForcedCommit = true; |
+} |
+ |
+void CCSchedulerStateMachine::beginFrameComplete() |
+{ |
+ ASSERT(m_commitState == COMMIT_STATE_FRAME_IN_PROGRESS); |
+ m_commitState = COMMIT_STATE_UPDATING_RESOURCES; |
+} |
+ |
+void CCSchedulerStateMachine::beginFrameAborted() |
+{ |
+ ASSERT(m_commitState == COMMIT_STATE_FRAME_IN_PROGRESS); |
+ m_commitState = COMMIT_STATE_IDLE; |
+} |
+ |
+void CCSchedulerStateMachine::beginUpdateMoreResourcesComplete(bool morePending) |
+{ |
+ ASSERT(m_commitState == COMMIT_STATE_UPDATING_RESOURCES); |
+ ASSERT(m_updateMoreResourcesPending); |
+ m_updateMoreResourcesPending = false; |
+ if (!morePending) |
+ m_commitState = COMMIT_STATE_READY_TO_COMMIT; |
+} |
+ |
+void CCSchedulerStateMachine::didLoseContext() |
+{ |
+ if (m_contextState == CONTEXT_LOST || m_contextState == CONTEXT_RECREATING) |
+ return; |
+ m_contextState = CONTEXT_LOST; |
+} |
+ |
+void CCSchedulerStateMachine::didRecreateContext() |
+{ |
+ ASSERT(m_contextState == CONTEXT_RECREATING); |
+ m_contextState = CONTEXT_ACTIVE; |
+ setNeedsCommit(); |
+} |
+ |
+void CCSchedulerStateMachine::setMaximumNumberOfFailedDrawsBeforeDrawIsForced(int numDraws) |
+{ |
+ m_maximumNumberOfFailedDrawsBeforeDrawIsForced = numDraws; |
+} |
+ |
+} |