Chromium Code Reviews| Index: cc/scheduler/scheduler.cc |
| diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc |
| index 72bade39070fff948f572591b4917c95aaf00f89..8ffd575a7b06eddf18d18271570c4b5cc2d1a720 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" |
| @@ -21,12 +22,10 @@ Scheduler::Scheduler(SchedulerClient* client, |
| inside_process_scheduled_actions_(false), |
| inside_action_(SchedulerStateMachine::ACTION_NONE) { |
| DCHECK(client_); |
| - DCHECK(!state_machine_.BeginFrameNeededToDrawByImplThread()); |
| + DCHECK(!state_machine_.BeginFrameNeededByImplThread()); |
| } |
| -Scheduler::~Scheduler() { |
| - client_->SetNeedsBeginFrameOnImplThread(false); |
| -} |
| +Scheduler::~Scheduler() {} |
| void Scheduler::SetCanStart() { |
| state_machine_.SetCanStart(); |
| @@ -48,6 +47,12 @@ void Scheduler::NotifyReadyToActivate() { |
| ProcessScheduledActions(); |
| } |
| +void Scheduler::ActivatePendingTree() { |
| + client_->ScheduledActionActivatePendingTree(); |
| + if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly()) |
| + PostBeginFrameDeadline(base::TimeTicks()); |
| +} |
| + |
| void Scheduler::SetNeedsCommit() { |
| state_machine_.SetNeedsCommit(); |
| ProcessScheduledActions(); |
| @@ -84,6 +89,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) { |
| @@ -94,14 +102,17 @@ void Scheduler::BeginFrameAbortedByMainThread(bool did_handle) { |
| void Scheduler::DidLoseOutputSurface() { |
| TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); |
| + last_set_needs_begin_frame_ = false; |
| + begin_frame_deadline_closure_.Cancel(); |
| state_machine_.DidLoseOutputSurface(); |
| ProcessScheduledActions(); |
| } |
| void Scheduler::DidCreateAndInitializeOutputSurface() { |
| TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); |
| + DCHECK(!last_set_needs_begin_frame_); |
| + DCHECK(begin_frame_deadline_closure_.IsCancelled()); |
| state_machine_.DidCreateAndInitializeOutputSurface(); |
| - last_set_needs_begin_frame_ = false; |
| ProcessScheduledActions(); |
| } |
| @@ -112,12 +123,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() { |
| @@ -125,32 +135,30 @@ 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 needs_begin_frame = |
| + state_machine_.BeginFrameNeededByImplThread(); |
| + |
| + bool at_end_of_deadline = |
| + state_machine_.begin_frame_state() == |
| + SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_DEADLINE; |
| bool should_call_set_needs_begin_frame = |
| // Always request the BeginFrame immediately if it wasn't needed before. |
| (needs_begin_frame && !last_set_needs_begin_frame_) || |
| // We always need to explicitly request our next BeginFrame. |
| - state_machine_.inside_begin_frame(); |
| + at_end_of_deadline; |
| if (should_call_set_needs_begin_frame) { |
| client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame); |
| last_set_needs_begin_frame_ = needs_begin_frame; |
| } |
| - // Setup PollForAnticipatedDrawTriggers for cases where we want a proactive |
| - // BeginFrame but aren't requesting one. |
| - if (!needs_begin_frame && |
| - state_machine_.ProactiveBeginFrameWantedByImplThread()) { |
| + // Setup PollForAnticipatedDrawTriggers if we need to monitor state but |
| + // aren't expecting any more BeginFrames. This should only be needed by the |
| + // synchronous compositor when BeginFrameNeededByImplThread is false. |
| + if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) { |
| + DCHECK(settings_.using_synchronous_renderer_compositor); |
| + DCHECK(!needs_begin_frame); |
| if (poll_for_draw_triggers_closure_.IsCancelled()) { |
| poll_for_draw_triggers_closure_.Reset( |
| base::Bind(&Scheduler::PollForAnticipatedDrawTriggers, |
| @@ -167,11 +175,64 @@ void Scheduler::SetupNextBeginFrameIfNeeded() { |
| void Scheduler::BeginFrame(const BeginFrameArgs& args) { |
| TRACE_EVENT0("cc", "Scheduler::BeginFrame"); |
| - DCHECK(!state_machine_.inside_begin_frame()); |
| + DCHECK(state_machine_.begin_frame_state() == |
| + SchedulerStateMachine::BEGIN_FRAME_STATE_IDLE); |
| 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_.OnBeginFrameDeadlinePending(); |
| + |
| + if (settings_.using_synchronous_renderer_compositor) { |
| + // The synchronous renderer compositor has to make its 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 |
| + // 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. This allows us to draw immediately when |
| + // there is a new active tree, instead of waiting for the next BeginFrame. |
| + // TODO(brianderson): Handle long deadlines (that are past the next frame's |
| + // frame time) properly instead of using this hack. |
|
Sami
2013/09/25 13:42:52
Just curious: was the idea to handle this with a p
brianderson
2013/10/02 11:30:15
Yes, we would enter this case if a proactive Begin
|
| + 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(); |
| - state_machine_.DidLeaveBeginFrame(); |
| + // We only transition out of BEGIN_FRAME_STATE_INSIDE_DEADLINE when all |
| + // actions that occur back-to-back in response to entering |
| + // BEGIN_FRAME_STATE_INSIDE_DEADLINE have completed. This is important |
| + // because sending the BeginFrame to the main thread will not occur if |
| + // we transition to BEGIN_FRAME_STATE_IDLE too early. |
| + state_machine_.OnBeginFrameIdle(); |
| + client_->DidBeginFrameDeadlineOnImplThread(); |
| } |
| void Scheduler::PollForAnticipatedDrawTriggers() { |
| @@ -230,7 +291,7 @@ void Scheduler::ProcessScheduledActions() { |
| client_->ScheduledActionUpdateVisibleTiles(); |
| break; |
| case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE: |
| - client_->ScheduledActionActivatePendingTree(); |
| + ActivatePendingTree(); |
| break; |
| case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: |
| DrawAndSwapIfPossible(); |