CCSchedulerStateMachine.cpp [plain text]
#include "config.h"
#include "cc/CCSchedulerStateMachine.h"
namespace WebCore {
CCSchedulerStateMachine::CCSchedulerStateMachine()
: m_commitState(COMMIT_STATE_IDLE)
, m_currentFrameNumber(0)
, m_lastFrameNumberWhereDrawWasCalled(-1)
, m_needsRedraw(false)
, m_needsForcedRedraw(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_textureState == LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD)
return true;
return false;
}
bool CCSchedulerStateMachine::scheduledToDraw() const
{
if (!m_needsRedraw)
return false;
if (!m_visible)
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);
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;
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;
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) {
ASSERT(m_needsCommit || !m_visible);
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;
}
}
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::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();
}
}