| Index: cc/scheduler/scheduler.cc
|
| diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
|
| index edf5e2549d54d0554995c6352db047a1018c27e9..897ad07f0e86ff645bfb5ddfc0936724e03224f5 100644
|
| --- a/cc/scheduler/scheduler.cc
|
| +++ b/cc/scheduler/scheduler.cc
|
| @@ -4,10 +4,18 @@
|
|
|
| #include "cc/scheduler/scheduler.h"
|
|
|
| +#include <algorithm>
|
| #include "base/auto_reset.h"
|
| #include "base/debug/trace_event.h"
|
| #include "base/logging.h"
|
|
|
| +class DEVNULL {};
|
| +template <typename A>
|
| +DEVNULL& operator <<(DEVNULL &d, A a) { return d; }
|
| +//static DEVNULL gDevNull;
|
| +//#undef VLOG
|
| +//#define VLOG(x) gDevNull
|
| +
|
| namespace cc {
|
|
|
| Scheduler::Scheduler(SchedulerClient* client,
|
| @@ -21,7 +29,7 @@ Scheduler::Scheduler(SchedulerClient* client,
|
| state_machine_(scheduler_settings),
|
| inside_process_scheduled_actions_(false) {
|
| DCHECK(client_);
|
| - DCHECK(!state_machine_.BeginFrameNeededToDrawByImplThread());
|
| + DCHECK(!state_machine_.BeginFrameNeededByImplThread());
|
| }
|
|
|
| Scheduler::~Scheduler() {
|
| @@ -43,9 +51,12 @@ void Scheduler::SetCanDraw(bool can_draw) {
|
| ProcessScheduledActions();
|
| }
|
|
|
| -void Scheduler::SetHasPendingTree(bool has_pending_tree) {
|
| - state_machine_.SetHasPendingTree(has_pending_tree);
|
| +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() {
|
| @@ -53,9 +64,9 @@ void Scheduler::SetNeedsCommit() {
|
| ProcessScheduledActions();
|
| }
|
|
|
| -void Scheduler::SetNeedsForcedCommit() {
|
| +void Scheduler::SetNeedsForcedCommitForReadback() {
|
| state_machine_.SetNeedsCommit();
|
| - state_machine_.SetNeedsForcedCommit();
|
| + state_machine_.SetNeedsForcedCommitForReadback();
|
| ProcessScheduledActions();
|
| }
|
|
|
| @@ -69,11 +80,6 @@ void Scheduler::DidSwapUseIncompleteTile() {
|
| ProcessScheduledActions();
|
| }
|
|
|
| -void Scheduler::SetNeedsForcedRedraw() {
|
| - state_machine_.SetNeedsForcedRedraw();
|
| - ProcessScheduledActions();
|
| -}
|
| -
|
| void Scheduler::SetMainThreadNeedsLayerTextures() {
|
| state_machine_.SetMainThreadNeedsLayerTextures();
|
| ProcessScheduledActions();
|
| @@ -83,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() {
|
| @@ -113,12 +122,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 +136,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;
|
| + 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 immediate_disables_needed =
|
| - settings_.using_synchronous_renderer_compositor;
|
| +
|
| + 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 +175,36 @@ 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_.AdjustDeadline(-client_->DrawDurationEstimate());
|
| + state_machine_.OnBeginFrame(last_begin_frame_args_);
|
| ProcessScheduledActions();
|
| - state_machine_.DidLeaveBeginFrame();
|
| +
|
| + if (settings_.using_synchronous_renderer_compositor)
|
| + OnBeginFrameDeadline();
|
| + else if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly())
|
| + PostBeginFrameDeadline(base::TimeTicks());
|
| + else
|
| + PostBeginFrameDeadline(last_begin_frame_args_.deadline);
|
| +}
|
| +
|
| +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 =
|
| + ScheduledActionDrawSwapReadbackResult result =
|
| client_->ScheduledActionDrawAndSwapIfPossible();
|
| state_machine_.DidDrawIfPossibleCompleted(result.did_draw);
|
| if (result.did_swap)
|
| @@ -185,12 +212,16 @@ void Scheduler::DrawAndSwapIfPossible() {
|
| }
|
|
|
| void Scheduler::DrawAndSwapForced() {
|
| - ScheduledActionDrawAndSwapResult result =
|
| + ScheduledActionDrawSwapReadbackResult result =
|
| client_->ScheduledActionDrawAndSwapForced();
|
| if (result.did_swap)
|
| has_pending_begin_frame_ = false;
|
| }
|
|
|
| +void Scheduler::DrawAndReadback() {
|
| + client_->ScheduledActionDrawAndReadback();
|
| +}
|
| +
|
| void Scheduler::ProcessScheduledActions() {
|
| // We do not allow ProcessScheduledActions to be recursive.
|
| // The top-level call will iteratively execute the next action for us anyway.
|
| @@ -199,40 +230,46 @@ 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 {
|
| + //TRACE_EVENT1("cc", "SchedulerStateMachine",
|
| + // "state", state_machine_.ToString());
|
| + action = state_machine_.NextAction();
|
| state_machine_.UpdateState(action);
|
| switch (action) {
|
| - case SchedulerStateMachine::ACTION_NONE:
|
| + case SchedulerStateMachine::ACTION_NONE:VLOG(0) << __LINE__ << "ACTION_NONE\n";
|
| break;
|
| - case SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD:
|
| + case SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD:VLOG(0) << __LINE__ << "ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD\n";
|
| client_->ScheduledActionSendBeginFrameToMainThread();
|
| break;
|
| - case SchedulerStateMachine::ACTION_COMMIT:
|
| + case SchedulerStateMachine::ACTION_COMMIT:VLOG(0) << __LINE__ << "ACTION_COMMIT\n";
|
| client_->ScheduledActionCommit();
|
| break;
|
| - case SchedulerStateMachine::ACTION_CHECK_FOR_COMPLETED_TILE_UPLOADS:
|
| + case SchedulerStateMachine::ACTION_CHECK_FOR_COMPLETED_TILE_UPLOADS:VLOG(0) << __LINE__ << "ACTION_CHECK_FOR_COMPLETED_TILE_UPLOADS\n";
|
| client_->ScheduledActionCheckForCompletedTileUploads();
|
| break;
|
| - case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED:
|
| + case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED:VLOG(0) << __LINE__ << "ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED\n";
|
| client_->ScheduledActionActivatePendingTreeIfNeeded();
|
| break;
|
| - case SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE:
|
| + case SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE:VLOG(0) << __LINE__ << "ACTION_DRAW_IF_POSSIBLE\n";
|
| DrawAndSwapIfPossible();
|
| break;
|
| - case SchedulerStateMachine::ACTION_DRAW_FORCED:
|
| + case SchedulerStateMachine::ACTION_DRAW_FORCED:VLOG(0) << __LINE__ << "ACTION_DRAW_FORCED\n";
|
| DrawAndSwapForced();
|
| break;
|
| - case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
|
| + case SchedulerStateMachine::ACTION_DRAW_AND_READBACK:VLOG(0) << __LINE__ << "ACTION_DRAW_AND_READBACK";
|
| + DrawAndReadback();
|
| + break;
|
| + case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:VLOG(0) << __LINE__ << "ACTION_BEGIN_OUTPUT_SURFACE_CREATION\n";
|
| client_->ScheduledActionBeginOutputSurfaceCreation();
|
| break;
|
| - case SchedulerStateMachine::ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD:
|
| + case SchedulerStateMachine::ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD:VLOG(0) << __LINE__ << "ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD\n";
|
| client_->ScheduledActionAcquireLayerTexturesForMainThread();
|
| break;
|
| }
|
| - action = state_machine_.NextAction();
|
| - }
|
| + } while (action != SchedulerStateMachine::ACTION_NONE);
|
|
|
| + state_machine_.AdvanceBeginFrameStateWhenNoActionsRemain();
|
| SetupNextBeginFrameIfNeeded();
|
| client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime());
|
| }
|
|
|