// Copyright 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "config.h" #include "CCScheduler.h" #include "TraceEvent.h" namespace cc { CCScheduler::CCScheduler(CCSchedulerClient* client, PassOwnPtr frameRateController) : m_client(client) , m_frameRateController(frameRateController) , m_updateResourcesCompletePending(false) { ASSERT(m_client); m_frameRateController->setClient(this); m_frameRateController->setActive(m_stateMachine.vsyncCallbackNeeded()); } CCScheduler::~CCScheduler() { m_frameRateController->setActive(false); } void CCScheduler::setCanBeginFrame(bool can) { m_stateMachine.setCanBeginFrame(can); processScheduledActions(); } void CCScheduler::setVisible(bool visible) { m_stateMachine.setVisible(visible); processScheduledActions(); } void CCScheduler::setCanDraw(bool canDraw) { m_stateMachine.setCanDraw(canDraw); // Defer processScheduleActions so we don't recurse and commit/draw // multiple frames. We can call processScheduledActions directly // once it is no longer re-entrant. m_frameRateController->setActive(m_stateMachine.vsyncCallbackNeeded()); } void CCScheduler::setNeedsCommit() { m_stateMachine.setNeedsCommit(); processScheduledActions(); } void CCScheduler::setNeedsForcedCommit() { m_stateMachine.setNeedsForcedCommit(); processScheduledActions(); } void CCScheduler::setNeedsRedraw() { m_stateMachine.setNeedsRedraw(); processScheduledActions(); } void CCScheduler::setNeedsForcedRedraw() { m_stateMachine.setNeedsForcedRedraw(); processScheduledActions(); } void CCScheduler::setMainThreadNeedsLayerTextures() { m_stateMachine.setMainThreadNeedsLayerTextures(); processScheduledActions(); } void CCScheduler::beginFrameComplete(bool hasResourceUpdates) { TRACE_EVENT0("cc", "CCScheduler::beginFrameComplete"); m_stateMachine.beginFrameComplete(hasResourceUpdates); processScheduledActions(); } void CCScheduler::beginFrameAborted() { TRACE_EVENT0("cc", "CCScheduler::beginFrameAborted"); m_stateMachine.beginFrameAborted(); processScheduledActions(); } void CCScheduler::setMaxFramesPending(int maxFramesPending) { m_frameRateController->setMaxFramesPending(maxFramesPending); } void CCScheduler::setSwapBuffersCompleteSupported(bool supported) { m_frameRateController->setSwapBuffersCompleteSupported(supported); } void CCScheduler::didSwapBuffersComplete() { TRACE_EVENT0("cc", "CCScheduler::didSwapBuffersComplete"); m_frameRateController->didFinishFrame(); } void CCScheduler::didLoseContext() { TRACE_EVENT0("cc", "CCScheduler::didLoseContext"); m_frameRateController->didAbortAllPendingFrames(); m_stateMachine.didLoseContext(); processScheduledActions(); } void CCScheduler::didRecreateContext() { TRACE_EVENT0("cc", "CCScheduler::didRecreateContext"); m_stateMachine.didRecreateContext(); processScheduledActions(); } void CCScheduler::setTimebaseAndInterval(double timebase, double intervalSeconds) { m_frameRateController->setTimebaseAndInterval(timebase, intervalSeconds); } void CCScheduler::vsyncTick() { TRACE_EVENT0("cc", "CCScheduler::vsyncTick"); m_stateMachine.didEnterVSync(); processScheduledActions(); m_stateMachine.didLeaveVSync(); // Allow resource updates until next vsync tick. if (m_updateResourcesCompletePending) m_client->scheduledActionUpdateMoreResources(m_frameRateController->nextTickTimeIfActivated()); } void CCScheduler::updateResourcesComplete() { TRACE_EVENT0("cc", "CCScheduler::updateResourcesComplete"); m_stateMachine.updateResourcesComplete(); m_updateResourcesCompletePending = false; processScheduledActions(); } void CCScheduler::processScheduledActions() { // Early out so we don't spam TRACE_EVENTS with useless processScheduledActions. if (m_stateMachine.nextAction() == CCSchedulerStateMachine::ACTION_NONE) { m_frameRateController->setActive(m_stateMachine.vsyncCallbackNeeded()); return; } // This function can re-enter itself. For example, draw may call // setNeedsCommit. Proceeed with caution. CCSchedulerStateMachine::Action action; do { action = m_stateMachine.nextAction(); m_stateMachine.updateState(action); TRACE_EVENT1("cc", "CCScheduler::processScheduledActions()", "action", action); switch (action) { case CCSchedulerStateMachine::ACTION_NONE: break; case CCSchedulerStateMachine::ACTION_BEGIN_FRAME: m_client->scheduledActionBeginFrame(); break; case CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_RESOURCES: ASSERT(!m_updateResourcesCompletePending); m_client->scheduledActionUpdateMoreResources(m_frameRateController->nextTickTimeIfActivated()); m_updateResourcesCompletePending = true; break; case CCSchedulerStateMachine::ACTION_COMMIT: m_client->scheduledActionCommit(); break; case CCSchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE: { CCScheduledActionDrawAndSwapResult result = m_client->scheduledActionDrawAndSwapIfPossible(); m_stateMachine.didDrawIfPossibleCompleted(result.didDraw); if (result.didSwap) m_frameRateController->didBeginFrame(); break; } case CCSchedulerStateMachine::ACTION_DRAW_FORCED: { CCScheduledActionDrawAndSwapResult result = m_client->scheduledActionDrawAndSwapForced(); if (result.didSwap) m_frameRateController->didBeginFrame(); break; } case CCSchedulerStateMachine::ACTION_BEGIN_CONTEXT_RECREATION: m_client->scheduledActionBeginContextRecreation(); break; case CCSchedulerStateMachine::ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD: m_client->scheduledActionAcquireLayerTexturesForMainThread(); break; } } while (action != CCSchedulerStateMachine::ACTION_NONE); // Activate or deactivate the frame rate controller. m_frameRateController->setActive(m_stateMachine.vsyncCallbackNeeded()); } }