Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2011 The Chromium Authors. All rights reserved. | 1 // Copyright 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "cc/scheduler/scheduler.h" | 5 #include "cc/scheduler/scheduler.h" |
| 6 | 6 |
| 7 #include <algorithm> | |
| 7 #include "base/auto_reset.h" | 8 #include "base/auto_reset.h" |
| 8 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
| 9 #include "base/logging.h" | 10 #include "base/logging.h" |
| 10 #include "cc/debug/traced_value.h" | 11 #include "cc/debug/traced_value.h" |
| 11 | 12 |
| 12 namespace cc { | 13 namespace cc { |
| 13 | 14 |
| 14 Scheduler::Scheduler(SchedulerClient* client, | 15 Scheduler::Scheduler(SchedulerClient* client, |
| 15 const SchedulerSettings& scheduler_settings) | 16 const SchedulerSettings& scheduler_settings) |
| 16 : settings_(scheduler_settings), | 17 : settings_(scheduler_settings), |
| 17 client_(client), | 18 client_(client), |
| 18 weak_factory_(this), | 19 weak_factory_(this), |
| 19 last_set_needs_begin_frame_(false), | 20 last_set_needs_begin_frame_(false), |
| 20 state_machine_(scheduler_settings), | 21 state_machine_(scheduler_settings), |
| 21 inside_process_scheduled_actions_(false), | 22 inside_process_scheduled_actions_(false), |
| 22 inside_action_(SchedulerStateMachine::ACTION_NONE) { | 23 inside_action_(SchedulerStateMachine::ACTION_NONE) { |
| 23 DCHECK(client_); | 24 DCHECK(client_); |
| 24 DCHECK(!state_machine_.BeginFrameNeededToDrawByImplThread()); | 25 DCHECK(!state_machine_.BeginFrameNeededByImplThread()); |
| 25 } | 26 } |
| 26 | 27 |
| 27 Scheduler::~Scheduler() { | 28 Scheduler::~Scheduler() {} |
| 28 client_->SetNeedsBeginFrameOnImplThread(false); | |
| 29 } | |
| 30 | 29 |
| 31 void Scheduler::SetCanStart() { | 30 void Scheduler::SetCanStart() { |
| 32 state_machine_.SetCanStart(); | 31 state_machine_.SetCanStart(); |
| 33 ProcessScheduledActions(); | 32 ProcessScheduledActions(); |
| 34 } | 33 } |
| 35 | 34 |
| 36 void Scheduler::SetVisible(bool visible) { | 35 void Scheduler::SetVisible(bool visible) { |
| 37 state_machine_.SetVisible(visible); | 36 state_machine_.SetVisible(visible); |
| 38 ProcessScheduledActions(); | 37 ProcessScheduledActions(); |
| 39 } | 38 } |
| 40 | 39 |
| 41 void Scheduler::SetCanDraw(bool can_draw) { | 40 void Scheduler::SetCanDraw(bool can_draw) { |
| 42 state_machine_.SetCanDraw(can_draw); | 41 state_machine_.SetCanDraw(can_draw); |
| 43 ProcessScheduledActions(); | 42 ProcessScheduledActions(); |
| 44 } | 43 } |
| 45 | 44 |
| 46 void Scheduler::NotifyReadyToActivate() { | 45 void Scheduler::NotifyReadyToActivate() { |
| 47 state_machine_.NotifyReadyToActivate(); | 46 state_machine_.NotifyReadyToActivate(); |
| 48 ProcessScheduledActions(); | 47 ProcessScheduledActions(); |
| 49 } | 48 } |
| 50 | 49 |
| 50 void Scheduler::ActivatePendingTree() { | |
| 51 client_->ScheduledActionActivatePendingTree(); | |
| 52 if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly()) | |
| 53 PostBeginFrameDeadline(base::TimeTicks()); | |
| 54 } | |
| 55 | |
| 51 void Scheduler::SetNeedsCommit() { | 56 void Scheduler::SetNeedsCommit() { |
| 52 state_machine_.SetNeedsCommit(); | 57 state_machine_.SetNeedsCommit(); |
| 53 ProcessScheduledActions(); | 58 ProcessScheduledActions(); |
| 54 } | 59 } |
| 55 | 60 |
| 56 void Scheduler::SetNeedsForcedCommitForReadback() { | 61 void Scheduler::SetNeedsForcedCommitForReadback() { |
| 57 state_machine_.SetNeedsCommit(); | 62 state_machine_.SetNeedsCommit(); |
| 58 state_machine_.SetNeedsForcedCommitForReadback(); | 63 state_machine_.SetNeedsForcedCommitForReadback(); |
| 59 ProcessScheduledActions(); | 64 ProcessScheduledActions(); |
| 60 } | 65 } |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 77 | 82 |
| 78 void Scheduler::SetMainThreadNeedsLayerTextures() { | 83 void Scheduler::SetMainThreadNeedsLayerTextures() { |
| 79 state_machine_.SetMainThreadNeedsLayerTextures(); | 84 state_machine_.SetMainThreadNeedsLayerTextures(); |
| 80 ProcessScheduledActions(); | 85 ProcessScheduledActions(); |
| 81 } | 86 } |
| 82 | 87 |
| 83 void Scheduler::FinishCommit() { | 88 void Scheduler::FinishCommit() { |
| 84 TRACE_EVENT0("cc", "Scheduler::FinishCommit"); | 89 TRACE_EVENT0("cc", "Scheduler::FinishCommit"); |
| 85 state_machine_.FinishCommit(); | 90 state_machine_.FinishCommit(); |
| 86 ProcessScheduledActions(); | 91 ProcessScheduledActions(); |
| 92 | |
| 93 if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly()) | |
| 94 PostBeginFrameDeadline(base::TimeTicks()); | |
| 87 } | 95 } |
| 88 | 96 |
| 89 void Scheduler::BeginFrameAbortedByMainThread(bool did_handle) { | 97 void Scheduler::BeginFrameAbortedByMainThread(bool did_handle) { |
| 90 TRACE_EVENT0("cc", "Scheduler::BeginFrameAbortedByMainThread"); | 98 TRACE_EVENT0("cc", "Scheduler::BeginFrameAbortedByMainThread"); |
| 91 state_machine_.BeginFrameAbortedByMainThread(did_handle); | 99 state_machine_.BeginFrameAbortedByMainThread(did_handle); |
| 92 ProcessScheduledActions(); | 100 ProcessScheduledActions(); |
| 93 } | 101 } |
| 94 | 102 |
| 95 void Scheduler::DidLoseOutputSurface() { | 103 void Scheduler::DidLoseOutputSurface() { |
| 96 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); | 104 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); |
| 105 last_set_needs_begin_frame_ = false; | |
| 106 begin_frame_deadline_closure_.Cancel(); | |
| 97 state_machine_.DidLoseOutputSurface(); | 107 state_machine_.DidLoseOutputSurface(); |
| 98 ProcessScheduledActions(); | 108 ProcessScheduledActions(); |
| 99 } | 109 } |
| 100 | 110 |
| 101 void Scheduler::DidCreateAndInitializeOutputSurface() { | 111 void Scheduler::DidCreateAndInitializeOutputSurface() { |
| 102 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); | 112 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); |
| 113 DCHECK(!last_set_needs_begin_frame_); | |
| 114 DCHECK(begin_frame_deadline_closure_.IsCancelled()); | |
| 103 state_machine_.DidCreateAndInitializeOutputSurface(); | 115 state_machine_.DidCreateAndInitializeOutputSurface(); |
| 104 last_set_needs_begin_frame_ = false; | |
| 105 ProcessScheduledActions(); | 116 ProcessScheduledActions(); |
| 106 } | 117 } |
| 107 | 118 |
| 108 base::TimeTicks Scheduler::AnticipatedDrawTime() { | 119 base::TimeTicks Scheduler::AnticipatedDrawTime() { |
| 109 TRACE_EVENT0("cc", "Scheduler::AnticipatedDrawTime"); | 120 TRACE_EVENT0("cc", "Scheduler::AnticipatedDrawTime"); |
| 110 | 121 |
| 111 if (!last_set_needs_begin_frame_ || | 122 if (!last_set_needs_begin_frame_ || |
| 112 last_begin_frame_args_.interval <= base::TimeDelta()) | 123 last_begin_frame_args_.interval <= base::TimeDelta()) |
| 113 return base::TimeTicks(); | 124 return base::TimeTicks(); |
| 114 | 125 |
| 115 // TODO(brianderson): Express this in terms of the deadline. | |
| 116 base::TimeTicks now = base::TimeTicks::Now(); | 126 base::TimeTicks now = base::TimeTicks::Now(); |
| 117 int64 intervals = 1 + ((now - last_begin_frame_args_.frame_time) / | 127 base::TimeTicks timebase = std::max(last_begin_frame_args_.frame_time, |
| 118 last_begin_frame_args_.interval); | 128 last_begin_frame_args_.deadline); |
| 119 return last_begin_frame_args_.frame_time + | 129 int64 intervals = 1 + ((now - timebase) / last_begin_frame_args_.interval); |
| 120 (last_begin_frame_args_.interval * intervals); | 130 return timebase + (last_begin_frame_args_.interval * intervals); |
| 121 } | 131 } |
| 122 | 132 |
| 123 base::TimeTicks Scheduler::LastBeginFrameOnImplThreadTime() { | 133 base::TimeTicks Scheduler::LastBeginFrameOnImplThreadTime() { |
| 124 return last_begin_frame_args_.frame_time; | 134 return last_begin_frame_args_.frame_time; |
| 125 } | 135 } |
| 126 | 136 |
| 127 void Scheduler::SetupNextBeginFrameIfNeeded() { | 137 void Scheduler::SetupNextBeginFrameIfNeeded() { |
| 128 bool needs_begin_frame_to_draw = | 138 bool needs_begin_frame = |
| 129 state_machine_.BeginFrameNeededToDrawByImplThread(); | 139 state_machine_.BeginFrameNeededByImplThread(); |
| 130 // We want to avoid proactive begin frames with the synchronous compositor | |
| 131 // because every SetNeedsBeginFrame will force a redraw. | |
| 132 bool proactive_begin_frame_wanted = | |
| 133 state_machine_.ProactiveBeginFrameWantedByImplThread() && | |
| 134 !settings_.using_synchronous_renderer_compositor && | |
| 135 settings_.throttle_frame_production; | |
| 136 bool needs_begin_frame = needs_begin_frame_to_draw || | |
| 137 proactive_begin_frame_wanted; | |
| 138 | 140 |
| 139 bool should_call_set_needs_begin_frame = | 141 bool should_call_set_needs_begin_frame = |
| 140 // Always request the BeginFrame immediately if it wasn't needed before. | 142 // Always request the BeginFrame immediately if it wasn't needed before. |
| 141 (needs_begin_frame && !last_set_needs_begin_frame_) || | 143 (needs_begin_frame && !last_set_needs_begin_frame_) || |
| 142 // We always need to explicitly request our next BeginFrame. | 144 // We always need to explicitly request our next BeginFrame. |
| 143 state_machine_.inside_begin_frame(); | 145 (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.
| |
| 146 SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_DEADLINE); | |
| 144 | 147 |
| 145 if (should_call_set_needs_begin_frame) { | 148 if (should_call_set_needs_begin_frame) { |
| 146 client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame); | 149 client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame); |
| 147 last_set_needs_begin_frame_ = needs_begin_frame; | 150 last_set_needs_begin_frame_ = needs_begin_frame; |
| 148 } | 151 } |
| 149 | 152 |
| 150 // Setup PollForAnticipatedDrawTriggers for cases where we want a proactive | 153 // Setup PollForAnticipatedDrawTriggers for cases where we want a proactive |
| 151 // BeginFrame but aren't requesting one. | 154 // BeginFrame but aren't requesting one. |
| 152 if (!needs_begin_frame && | 155 if (!last_set_needs_begin_frame_ && |
| 153 state_machine_.ProactiveBeginFrameWantedByImplThread()) { | 156 state_machine_.ShouldPollForAnticipatedDrawTriggers()) { |
| 154 if (poll_for_draw_triggers_closure_.IsCancelled()) { | 157 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.
| |
| 155 poll_for_draw_triggers_closure_.Reset( | 158 poll_for_draw_triggers_closure_.Reset( |
| 156 base::Bind(&Scheduler::PollForAnticipatedDrawTriggers, | 159 base::Bind(&Scheduler::PollForAnticipatedDrawTriggers, |
| 157 weak_factory_.GetWeakPtr())); | 160 weak_factory_.GetWeakPtr())); |
| 158 base::MessageLoop::current()->PostDelayedTask( | 161 base::MessageLoop::current()->PostDelayedTask( |
| 159 FROM_HERE, | 162 FROM_HERE, |
| 160 poll_for_draw_triggers_closure_.callback(), | 163 poll_for_draw_triggers_closure_.callback(), |
| 161 last_begin_frame_args_.interval); | 164 last_begin_frame_args_.interval); |
| 162 } | 165 } |
| 163 } else { | 166 } else { |
| 164 poll_for_draw_triggers_closure_.Cancel(); | 167 poll_for_draw_triggers_closure_.Cancel(); |
| 165 } | 168 } |
| 166 } | 169 } |
| 167 | 170 |
| 168 void Scheduler::BeginFrame(const BeginFrameArgs& args) { | 171 void Scheduler::BeginFrame(const BeginFrameArgs& args) { |
| 169 TRACE_EVENT0("cc", "Scheduler::BeginFrame"); | 172 TRACE_EVENT0("cc", "Scheduler::BeginFrame"); |
| 170 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
| |
| 171 last_begin_frame_args_ = args; | 173 last_begin_frame_args_ = args; |
| 172 state_machine_.DidEnterBeginFrame(args); | 174 last_begin_frame_args_.deadline -= client_->DrawDurationEstimate(); |
| 175 state_machine_.OnBeginFrame(last_begin_frame_args_); | |
| 173 ProcessScheduledActions(); | 176 ProcessScheduledActions(); |
| 174 state_machine_.DidLeaveBeginFrame(); | 177 state_machine_.OnBeginFrameDeadlinePending(); |
| 178 | |
| 179 if (settings_.using_synchronous_renderer_compositor) { | |
| 180 // The synchronous renderer compositor has to make its GL calls | |
| 181 // within this call to BeginFrame. | |
| 182 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks | |
| 183 // so the sychronous renderer compoistor can take advantage of splitting | |
| 184 // up the BeginFrame and deadline as well. | |
| 185 OnBeginFrameDeadline(); | |
| 186 } else if (!settings_.deadline_scheduling_enabled) { | |
| 187 // We emulate the old non-deadline scheduler here by posting the | |
| 188 // deadline task without any delay. | |
| 189 PostBeginFrameDeadline(base::TimeTicks()); | |
| 190 } else if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly()) { | |
| 191 // We are ready to draw a new active tree immediately. | |
| 192 PostBeginFrameDeadline(base::TimeTicks()); | |
| 193 } else if (state_machine_.needs_redraw()) { | |
| 194 // We have an animation or fast input path on the impl thread that wants | |
| 195 // to draw, so don't wait too long for a new active tree. | |
| 196 PostBeginFrameDeadline(last_begin_frame_args_.deadline); | |
| 197 } else { | |
| 198 // The impl thread doesn't have anything it wants to draw and we are just | |
| 199 // waiting for a new active tree, so post the deadline for the next | |
| 200 // expected BeginFrame start. This allows us to draw immediately when | |
| 201 // there is a new active tree, instead of waiting for the next BeginFrame. | |
| 202 // TODO(brianderson): Handle long deadlines (that are past the next frame's | |
| 203 // frame time) properly instead of using this hack. | |
| 204 PostBeginFrameDeadline(last_begin_frame_args_.frame_time + | |
| 205 last_begin_frame_args_.interval); | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 void Scheduler::PostBeginFrameDeadline(base::TimeTicks deadline) { | |
| 210 begin_frame_deadline_closure_.Cancel(); | |
| 211 begin_frame_deadline_closure_.Reset( | |
| 212 base::Bind(&Scheduler::OnBeginFrameDeadline, weak_factory_.GetWeakPtr())); | |
| 213 client_->PostBeginFrameDeadline(begin_frame_deadline_closure_.callback(), | |
| 214 deadline); | |
| 215 } | |
| 216 | |
| 217 void Scheduler::OnBeginFrameDeadline() { | |
| 218 TRACE_EVENT0("cc", "Scheduler::OnBeginFrameDeadline"); | |
| 219 begin_frame_deadline_closure_.Cancel(); | |
| 220 state_machine_.OnBeginFrameDeadline(); | |
| 221 ProcessScheduledActions(); | |
| 222 // We only transition out of BEGIN_FRAME_STATE_INSIDE_DEADLINE when all | |
| 223 // actions that occur back-to-back in response to entering | |
| 224 // BEGIN_FRAME_STATE_INSIDE_DEADLINE have completed. This is important | |
| 225 // because sending the BeginFrame to the main thread will not occur if | |
| 226 // we transition to BEGIN_FRAME_STATE_IDLE too early. | |
| 227 state_machine_.OnBeginFrameIdle(); | |
| 228 client_->DidBeginFrameDeadlineOnImplThread(); | |
| 175 } | 229 } |
| 176 | 230 |
| 177 void Scheduler::PollForAnticipatedDrawTriggers() { | 231 void Scheduler::PollForAnticipatedDrawTriggers() { |
| 178 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers"); | 232 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers"); |
| 179 state_machine_.DidEnterPollForAnticipatedDrawTriggers(); | 233 state_machine_.DidEnterPollForAnticipatedDrawTriggers(); |
| 180 ProcessScheduledActions(); | 234 ProcessScheduledActions(); |
| 181 state_machine_.DidLeavePollForAnticipatedDrawTriggers(); | 235 state_machine_.DidLeavePollForAnticipatedDrawTriggers(); |
| 182 } | 236 } |
| 183 | 237 |
| 184 void Scheduler::DrawAndSwapIfPossible() { | 238 void Scheduler::DrawAndSwapIfPossible() { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 221 case SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD: | 275 case SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD: |
| 222 client_->ScheduledActionSendBeginFrameToMainThread(); | 276 client_->ScheduledActionSendBeginFrameToMainThread(); |
| 223 break; | 277 break; |
| 224 case SchedulerStateMachine::ACTION_COMMIT: | 278 case SchedulerStateMachine::ACTION_COMMIT: |
| 225 client_->ScheduledActionCommit(); | 279 client_->ScheduledActionCommit(); |
| 226 break; | 280 break; |
| 227 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES: | 281 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES: |
| 228 client_->ScheduledActionUpdateVisibleTiles(); | 282 client_->ScheduledActionUpdateVisibleTiles(); |
| 229 break; | 283 break; |
| 230 case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE: | 284 case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE: |
| 231 client_->ScheduledActionActivatePendingTree(); | 285 ActivatePendingTree(); |
| 232 break; | 286 break; |
| 233 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: | 287 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: |
| 234 DrawAndSwapIfPossible(); | 288 DrawAndSwapIfPossible(); |
| 235 break; | 289 break; |
| 236 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: | 290 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: |
| 237 DrawAndSwapForced(); | 291 DrawAndSwapForced(); |
| 238 break; | 292 break; |
| 239 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: | 293 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: |
| 240 // No action is actually performed, but this allows the state machine to | 294 // No action is actually performed, but this allows the state machine to |
| 241 // advance out of its waiting to draw state without actually drawing. | 295 // advance out of its waiting to draw state without actually drawing. |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 257 | 311 |
| 258 SetupNextBeginFrameIfNeeded(); | 312 SetupNextBeginFrameIfNeeded(); |
| 259 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); | 313 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); |
| 260 } | 314 } |
| 261 | 315 |
| 262 bool Scheduler::WillDrawIfNeeded() const { | 316 bool Scheduler::WillDrawIfNeeded() const { |
| 263 return !state_machine_.PendingDrawsShouldBeAborted(); | 317 return !state_machine_.PendingDrawsShouldBeAborted(); |
| 264 } | 318 } |
| 265 | 319 |
| 266 } // namespace cc | 320 } // namespace cc |
| OLD | NEW |