Index: cc/scheduler/scheduler.cc |
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc |
index 14f6c7fe2f1d1d9eb9a1a7bddb078101631569e4..17a72f149d77afcaa3d29a6237c9fa559ca95cf2 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,22 +135,15 @@ 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 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(); |
+ (state_machine_.begin_frame_state() == |
danakj
2013/09/17 20:26:19
bool at_end_of_deadline = "this thing" might help
brianderson
2013/09/17 21:08:24
Good suggestion. Done.
|
+ SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_DEADLINE); |
if (should_call_set_needs_begin_frame) { |
client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame); |
@@ -149,8 +152,8 @@ void Scheduler::SetupNextBeginFrameIfNeeded() { |
// Setup PollForAnticipatedDrawTriggers for cases where we want a proactive |
// BeginFrame but aren't requesting one. |
- if (!needs_begin_frame && |
- state_machine_.ProactiveBeginFrameWantedByImplThread()) { |
+ if (!last_set_needs_begin_frame_ && |
+ state_machine_.ShouldPollForAnticipatedDrawTriggers()) { |
if (poll_for_draw_triggers_closure_.IsCancelled()) { |
danakj
2013/09/17 20:26:19
As discussed, DCHECK(!needs_begin_frame) with a co
brianderson
2013/09/17 21:08:24
Done.
|
poll_for_draw_triggers_closure_.Reset( |
base::Bind(&Scheduler::PollForAnticipatedDrawTriggers, |
@@ -167,11 +170,62 @@ void Scheduler::SetupNextBeginFrameIfNeeded() { |
void Scheduler::BeginFrame(const BeginFrameArgs& args) { |
TRACE_EVENT0("cc", "Scheduler::BeginFrame"); |
- DCHECK(!state_machine_.inside_begin_frame()); |
danakj
2013/09/17 20:26:19
Can we dcheck against the begin_frame_state() inst
brianderson
2013/09/17 21:08:24
I moved DCHECKS to OnBeginFrame, OnBeginFrameDeadl
|
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. |
+ 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() { |
@@ -228,7 +282,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(); |