| Index: cc/scheduler/scheduler.cc
|
| diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
|
| index 14f6c7fe2f1d1d9eb9a1a7bddb078101631569e4..57273b8bba056117e886186f7bb68b04e2288117 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.
|
| + 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 +289,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();
|
|
|