Chromium Code Reviews| Index: cc/scheduler/scheduler.cc |
| diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc |
| index 010cc990b4762316273d4c4a2b27fa645d791a57..eb1f7c2b4c9551bd4f401fa26c4b4890c004ce74 100644 |
| --- a/cc/scheduler/scheduler.cc |
| +++ b/cc/scheduler/scheduler.cc |
| @@ -4,6 +4,7 @@ |
| #include "cc/scheduler/scheduler.h" |
| +#include <algorithm> |
| #include "base/auto_reset.h" |
| #include "base/debug/trace_event.h" |
| #include "base/logging.h" |
| @@ -17,11 +18,12 @@ Scheduler::Scheduler(SchedulerClient* client, |
| weak_factory_(this), |
| last_set_needs_begin_frame_(false), |
| has_pending_begin_frame_(false), |
| - safe_to_expect_begin_frame_(false), |
| + safe_to_expect_begin_frame_( |
| + !scheduler_settings.use_begin_frame_workaround_for_crbug_249806), |
| state_machine_(scheduler_settings), |
| inside_process_scheduled_actions_(false) { |
| DCHECK(client_); |
| - DCHECK(!state_machine_.BeginFrameNeededToDrawByImplThread()); |
| + DCHECK(!state_machine_.BeginFrameNeededByImplThread()); |
| } |
| Scheduler::~Scheduler() { |
| @@ -43,19 +45,27 @@ void Scheduler::SetCanDraw(bool can_draw) { |
| ProcessScheduledActions(); |
| } |
| -void Scheduler::SetHasPendingTree(bool has_pending_tree) { |
| - state_machine_.SetHasPendingTree(has_pending_tree); |
| +void Scheduler::NotifyReadyToActivate() { |
| + state_machine_.NotifyReadyToActivate(); |
| ProcessScheduledActions(); |
| } |
| +void Scheduler::SetHasTrees(bool has_pending_tree, bool active_tree_is_null) { |
| + state_machine_.SetHasTrees(has_pending_tree, active_tree_is_null); |
| + ProcessScheduledActions(); |
| + |
| + if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly()) |
| + PostBeginFrameDeadline(base::TimeTicks()); |
| +} |
| + |
| void Scheduler::SetNeedsCommit() { |
| state_machine_.SetNeedsCommit(); |
| ProcessScheduledActions(); |
| } |
| -void Scheduler::SetNeedsForcedCommit() { |
| +void Scheduler::SetNeedsForcedCommitForReadback() { |
| state_machine_.SetNeedsCommit(); |
| - state_machine_.SetNeedsForcedCommit(); |
| + state_machine_.SetNeedsForcedCommitForReadback(); |
| ProcessScheduledActions(); |
| } |
| @@ -69,11 +79,6 @@ void Scheduler::DidSwapUseIncompleteTile() { |
| ProcessScheduledActions(); |
| } |
| -void Scheduler::SetNeedsForcedRedraw() { |
| - state_machine_.SetNeedsForcedRedraw(); |
| - ProcessScheduledActions(); |
| -} |
| - |
| void Scheduler::SetMainThreadNeedsLayerTextures() { |
| state_machine_.SetMainThreadNeedsLayerTextures(); |
| ProcessScheduledActions(); |
| @@ -83,6 +88,9 @@ void Scheduler::FinishCommit() { |
| TRACE_EVENT0("cc", "Scheduler::FinishCommit"); |
| state_machine_.FinishCommit(); |
| ProcessScheduledActions(); |
| + |
| + if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly()) |
| + PostBeginFrameDeadline(base::TimeTicks()); |
| } |
| void Scheduler::BeginFrameAbortedByMainThread(bool did_handle) { |
| @@ -93,6 +101,8 @@ void Scheduler::BeginFrameAbortedByMainThread(bool did_handle) { |
| void Scheduler::DidLoseOutputSurface() { |
| TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); |
| + begin_frame_deadline_closure_.Cancel(); |
| + has_pending_begin_frame_ = false; |
| state_machine_.DidLoseOutputSurface(); |
| ProcessScheduledActions(); |
| } |
| @@ -100,9 +110,11 @@ void Scheduler::DidLoseOutputSurface() { |
| void Scheduler::DidCreateAndInitializeOutputSurface() { |
| TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); |
| state_machine_.DidCreateAndInitializeOutputSurface(); |
| + begin_frame_deadline_closure_.Cancel(); |
| has_pending_begin_frame_ = false; |
| last_set_needs_begin_frame_ = false; |
| - safe_to_expect_begin_frame_ = false; |
| + safe_to_expect_begin_frame_ = |
| + !settings_.use_begin_frame_workaround_for_crbug_249806; |
| ProcessScheduledActions(); |
| } |
| @@ -113,12 +125,11 @@ base::TimeTicks Scheduler::AnticipatedDrawTime() { |
| last_begin_frame_args_.interval <= base::TimeDelta()) |
| return base::TimeTicks(); |
| - // TODO(brianderson): Express this in terms of the deadline. |
| base::TimeTicks now = base::TimeTicks::Now(); |
| - int64 intervals = 1 + ((now - last_begin_frame_args_.frame_time) / |
| - last_begin_frame_args_.interval); |
| - return last_begin_frame_args_.frame_time + |
| - (last_begin_frame_args_.interval * intervals); |
| + base::TimeTicks timebase = std::max(last_begin_frame_args_.frame_time, |
| + last_begin_frame_args_.deadline); |
| + int64 intervals = 1 + ((now - timebase) / last_begin_frame_args_.interval); |
| + return timebase + (last_begin_frame_args_.interval * intervals); |
| } |
| base::TimeTicks Scheduler::LastBeginFrameOnImplThreadTime() { |
| @@ -128,41 +139,37 @@ base::TimeTicks Scheduler::LastBeginFrameOnImplThreadTime() { |
| void Scheduler::SetupNextBeginFrameIfNeeded() { |
| bool needs_begin_frame_to_draw = |
| state_machine_.BeginFrameNeededToDrawByImplThread(); |
| - // We want to avoid proactive begin frames with the synchronous compositor |
| - // because every SetNeedsBeginFrame will force a redraw. |
| bool proactive_begin_frame_wanted = |
| - state_machine_.ProactiveBeginFrameWantedByImplThread() && |
| - !settings_.using_synchronous_renderer_compositor && |
| - settings_.throttle_frame_production; |
| - bool needs_begin_frame = needs_begin_frame_to_draw || |
| - proactive_begin_frame_wanted; |
| - bool immediate_disables_needed = |
| - settings_.using_synchronous_renderer_compositor; |
| + state_machine_.BeginFrameProactivelyNeededByImplThread(); |
| + |
| + // We want to avoid proactive begin frames with the synchronous |
| + // compositor because every SetNeedsBeginFrame will force a redraw. |
| + bool needs_begin_frame = |
| + needs_begin_frame_to_draw || proactive_begin_frame_wanted; |
| + |
| + bool should_call_set_needs_begin_frame = |
| + // The synchronous renderer compositor needs immediate enables/disables. |
| + (settings_.using_synchronous_renderer_compositor && |
| + needs_begin_frame != last_set_needs_begin_frame_) || |
| + // Always request the BeginFrame immediately if it wasn't needed before. |
| + (needs_begin_frame && !last_set_needs_begin_frame_) || |
| + // Only disable the BeginFrame after a BeginFrame where we didn't swap. |
| + (!needs_begin_frame && last_set_needs_begin_frame_ && |
| + has_pending_begin_frame_ && !state_machine_.InsideBeginFrame()) || |
| + // We did not draw and swap this BeginFrame, |
| + // so we need to explicitly request another BeginFrame. |
| + (needs_begin_frame && has_pending_begin_frame_ && |
| + !state_machine_.InsideBeginFrame()); |
| if (needs_begin_frame_to_draw) |
| safe_to_expect_begin_frame_ = true; |
| - // Determine if we need BeginFrame notifications. |
| - // If we do, always request the BeginFrame immediately. |
| - // If not, only disable on the next BeginFrame to avoid unnecessary toggles. |
| - // The synchronous renderer compositor requires immediate disables though. |
| - if ((needs_begin_frame || |
| - state_machine_.inside_begin_frame() || |
| - immediate_disables_needed) && |
| - (needs_begin_frame != last_set_needs_begin_frame_)) { |
| + if (should_call_set_needs_begin_frame) { |
| has_pending_begin_frame_ = false; |
| client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame); |
| if (safe_to_expect_begin_frame_) |
| last_set_needs_begin_frame_ = needs_begin_frame; |
| } |
| - |
| - // Request another BeginFrame if we haven't drawn for now until we have |
| - // deadlines implemented. |
| - if (state_machine_.inside_begin_frame() && has_pending_begin_frame_) { |
| - has_pending_begin_frame_ = false; |
| - client_->SetNeedsBeginFrameOnImplThread(true); |
| - return; |
| - } |
| } |
| void Scheduler::BeginFrame(const BeginFrameArgs& args) { |
| @@ -171,13 +178,57 @@ void Scheduler::BeginFrame(const BeginFrameArgs& args) { |
| has_pending_begin_frame_ = true; |
| safe_to_expect_begin_frame_ = true; |
| last_begin_frame_args_ = args; |
| - state_machine_.DidEnterBeginFrame(args); |
| + last_begin_frame_args_.deadline -= client_->DrawDurationEstimate(); |
| + state_machine_.OnBeginFrame(last_begin_frame_args_); |
| ProcessScheduledActions(); |
| - state_machine_.DidLeaveBeginFrame(); |
| + |
| + if (settings_.using_synchronous_renderer_compositor) { |
| + // The synchronous renderer compositor has to make it's GL calls |
| + // within this call to BeginFrame. |
| + // TODO(brianderson): Have the OutputSurface initiate the deadline tasks |
| + // so the sychronous renderer compoistor can take advantage of splitting |
| + // up the BeginFrame and deadline as well. |
| + OnBeginFrameDeadline(); |
| + } else if (!settings_.deadline_scheduling_enabled) { |
| + // We emulate the old non-deadline scheduler here by posting the |
|
brianderson
2013/08/20 02:03:01
I got rid of the AdjustDeadline function that had
|
| + // deadline task without any delay. |
| + PostBeginFrameDeadline(base::TimeTicks()); |
| + } else if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly()) { |
| + // We are ready to draw a new active tree immediately. |
| + PostBeginFrameDeadline(base::TimeTicks()); |
| + } else if (state_machine_.needs_redraw()) { |
| + // We have an animation or fast input path on the impl thread that wants |
| + // to draw, so don't wait too long for a new active tree. |
| + PostBeginFrameDeadline(last_begin_frame_args_.deadline); |
| + } else { |
| + // The impl thread doesn't have anything it wants to draw and we are just |
| + // waiting for a new active tree, so post the deadline for the next |
| + // expected BeginFrame start. |
| + // TODO(brianderson): Handle long deadlines (that are past the next frame's |
| + // frame time) properly instead of using this hack. |
| + PostBeginFrameDeadline(last_begin_frame_args_.frame_time + |
| + last_begin_frame_args_.interval); |
| + } |
| +} |
| + |
| +void Scheduler::PostBeginFrameDeadline(base::TimeTicks deadline) { |
| + begin_frame_deadline_closure_.Cancel(); |
| + begin_frame_deadline_closure_.Reset( |
| + base::Bind(&Scheduler::OnBeginFrameDeadline, weak_factory_.GetWeakPtr())); |
| + client_->PostBeginFrameDeadline(begin_frame_deadline_closure_.callback(), |
| + deadline); |
| +} |
| + |
| +void Scheduler::OnBeginFrameDeadline() { |
| + TRACE_EVENT0("cc", "Scheduler::OnBeginFrameDeadline"); |
| + begin_frame_deadline_closure_.Cancel(); |
| + state_machine_.OnBeginFrameDeadline(); |
| + ProcessScheduledActions(); |
| + client_->DidBeginFrameDeadlineOnImplThread(); |
| } |
| void Scheduler::DrawAndSwapIfPossible() { |
| - ScheduledActionDrawAndSwapResult result = |
| + DrawSwapReadbackResult result = |
| client_->ScheduledActionDrawAndSwapIfPossible(); |
| state_machine_.DidDrawIfPossibleCompleted(result.did_draw); |
| if (result.did_swap) |
| @@ -185,8 +236,7 @@ void Scheduler::DrawAndSwapIfPossible() { |
| } |
| void Scheduler::DrawAndSwapForced() { |
| - ScheduledActionDrawAndSwapResult result = |
| - client_->ScheduledActionDrawAndSwapForced(); |
| + DrawSwapReadbackResult result = client_->ScheduledActionDrawAndSwapForced(); |
| if (result.did_swap) |
| has_pending_begin_frame_ = false; |
| } |
| @@ -199,8 +249,15 @@ void Scheduler::ProcessScheduledActions() { |
| base::AutoReset<bool> mark_inside(&inside_process_scheduled_actions_, true); |
| - SchedulerStateMachine::Action action = state_machine_.NextAction(); |
| - while (action != SchedulerStateMachine::ACTION_NONE) { |
| + SchedulerStateMachine::Action action; |
| + do { |
| + action = state_machine_.NextAction(); |
| + TRACE_EVENT2("cc", |
| + "SchedulerStateMachine", |
| + "action", |
| + action, |
| + "state", |
| + state_machine_.ToString()); |
| state_machine_.UpdateState(action); |
| switch (action) { |
| case SchedulerStateMachine::ACTION_NONE: |
| @@ -214,15 +271,22 @@ void Scheduler::ProcessScheduledActions() { |
| case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES: |
| client_->ScheduledActionUpdateVisibleTiles(); |
| break; |
| - case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED: |
| - client_->ScheduledActionActivatePendingTreeIfNeeded(); |
| + case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE: |
| + client_->ScheduledActionActivatePendingTree(); |
| break; |
| - case SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE: |
| + case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: |
| DrawAndSwapIfPossible(); |
| break; |
| - case SchedulerStateMachine::ACTION_DRAW_FORCED: |
| + case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: |
| DrawAndSwapForced(); |
| break; |
| + case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: |
| + // No action is actually performed, but this allows the state machine to |
| + // advance out of its waiting to draw state without actually drawing. |
| + break; |
| + case SchedulerStateMachine::ACTION_DRAW_AND_READBACK: |
| + client_->ScheduledActionDrawAndReadback(); |
| + break; |
| case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION: |
| client_->ScheduledActionBeginOutputSurfaceCreation(); |
| break; |
| @@ -230,9 +294,9 @@ void Scheduler::ProcessScheduledActions() { |
| client_->ScheduledActionAcquireLayerTexturesForMainThread(); |
| break; |
| } |
| - action = state_machine_.NextAction(); |
| - } |
| + } while (action != SchedulerStateMachine::ACTION_NONE); |
| + state_machine_.AdvanceBeginFrameStateWhenNoActionsRemain(); |
| SetupNextBeginFrameIfNeeded(); |
| client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); |
| } |