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 | 140 |
| 131 // because every SetNeedsBeginFrame will force a redraw. | 141 bool at_end_of_deadline = |
| 132 bool proactive_begin_frame_wanted = | 142 state_machine_.begin_frame_state() == |
| 133 state_machine_.ProactiveBeginFrameWantedByImplThread() && | 143 SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_DEADLINE; |
| 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 | 144 |
| 139 bool should_call_set_needs_begin_frame = | 145 bool should_call_set_needs_begin_frame = |
| 140 // Always request the BeginFrame immediately if it wasn't needed before. | 146 // Always request the BeginFrame immediately if it wasn't needed before. |
| 141 (needs_begin_frame && !last_set_needs_begin_frame_) || | 147 (needs_begin_frame && !last_set_needs_begin_frame_) || |
| 142 // We always need to explicitly request our next BeginFrame. | 148 // We always need to explicitly request our next BeginFrame. |
| 143 state_machine_.inside_begin_frame(); | 149 at_end_of_deadline; |
| 144 | 150 |
| 145 if (should_call_set_needs_begin_frame) { | 151 if (should_call_set_needs_begin_frame) { |
| 146 client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame); | 152 client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame); |
| 147 last_set_needs_begin_frame_ = needs_begin_frame; | 153 last_set_needs_begin_frame_ = needs_begin_frame; |
| 148 } | 154 } |
| 149 | 155 |
| 150 // Setup PollForAnticipatedDrawTriggers for cases where we want a proactive | 156 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but |
| 151 // BeginFrame but aren't requesting one. | 157 // aren't expecting any more BeginFrames. This should only be needed by the |
| 152 if (!needs_begin_frame && | 158 // synchronous compositor when BeginFrameNeededByImplThread is false. |
| 153 state_machine_.ProactiveBeginFrameWantedByImplThread()) { | 159 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) { |
| 160 DCHECK(settings_.using_synchronous_renderer_compositor); | |
| 161 DCHECK(!needs_begin_frame); | |
| 154 if (poll_for_draw_triggers_closure_.IsCancelled()) { | 162 if (poll_for_draw_triggers_closure_.IsCancelled()) { |
| 155 poll_for_draw_triggers_closure_.Reset( | 163 poll_for_draw_triggers_closure_.Reset( |
| 156 base::Bind(&Scheduler::PollForAnticipatedDrawTriggers, | 164 base::Bind(&Scheduler::PollForAnticipatedDrawTriggers, |
| 157 weak_factory_.GetWeakPtr())); | 165 weak_factory_.GetWeakPtr())); |
| 158 base::MessageLoop::current()->PostDelayedTask( | 166 base::MessageLoop::current()->PostDelayedTask( |
| 159 FROM_HERE, | 167 FROM_HERE, |
| 160 poll_for_draw_triggers_closure_.callback(), | 168 poll_for_draw_triggers_closure_.callback(), |
| 161 last_begin_frame_args_.interval); | 169 last_begin_frame_args_.interval); |
| 162 } | 170 } |
| 163 } else { | 171 } else { |
| 164 poll_for_draw_triggers_closure_.Cancel(); | 172 poll_for_draw_triggers_closure_.Cancel(); |
| 165 } | 173 } |
| 166 } | 174 } |
| 167 | 175 |
| 168 void Scheduler::BeginFrame(const BeginFrameArgs& args) { | 176 void Scheduler::BeginFrame(const BeginFrameArgs& args) { |
| 169 TRACE_EVENT0("cc", "Scheduler::BeginFrame"); | 177 TRACE_EVENT0("cc", "Scheduler::BeginFrame"); |
| 170 DCHECK(!state_machine_.inside_begin_frame()); | 178 DCHECK(state_machine_.begin_frame_state() == |
| 179 SchedulerStateMachine::BEGIN_FRAME_STATE_IDLE); | |
| 171 last_begin_frame_args_ = args; | 180 last_begin_frame_args_ = args; |
| 172 state_machine_.DidEnterBeginFrame(args); | 181 last_begin_frame_args_.deadline -= client_->DrawDurationEstimate(); |
| 182 state_machine_.OnBeginFrame(last_begin_frame_args_); | |
| 173 ProcessScheduledActions(); | 183 ProcessScheduledActions(); |
| 174 state_machine_.DidLeaveBeginFrame(); | 184 state_machine_.OnBeginFrameDeadlinePending(); |
| 185 | |
| 186 if (settings_.using_synchronous_renderer_compositor) { | |
| 187 // The synchronous renderer compositor has to make its GL calls | |
| 188 // within this call to BeginFrame. | |
| 189 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks | |
| 190 // so the sychronous renderer compoistor can take advantage of splitting | |
| 191 // up the BeginFrame and deadline as well. | |
| 192 OnBeginFrameDeadline(); | |
| 193 } else if (!settings_.deadline_scheduling_enabled) { | |
| 194 // We emulate the old non-deadline scheduler here by posting the | |
| 195 // deadline task without any delay. | |
| 196 PostBeginFrameDeadline(base::TimeTicks()); | |
| 197 } else if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly()) { | |
| 198 // We are ready to draw a new active tree immediately. | |
| 199 PostBeginFrameDeadline(base::TimeTicks()); | |
| 200 } else if (state_machine_.needs_redraw()) { | |
| 201 // We have an animation or fast input path on the impl thread that wants | |
| 202 // to draw, so don't wait too long for a new active tree. | |
| 203 PostBeginFrameDeadline(last_begin_frame_args_.deadline); | |
| 204 } else { | |
| 205 // The impl thread doesn't have anything it wants to draw and we are just | |
| 206 // waiting for a new active tree, so post the deadline for the next | |
| 207 // expected BeginFrame start. This allows us to draw immediately when | |
| 208 // there is a new active tree, instead of waiting for the next BeginFrame. | |
| 209 // TODO(brianderson): Handle long deadlines (that are past the next frame's | |
| 210 // 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
| |
| 211 PostBeginFrameDeadline(last_begin_frame_args_.frame_time + | |
| 212 last_begin_frame_args_.interval); | |
| 213 } | |
| 214 } | |
| 215 | |
| 216 void Scheduler::PostBeginFrameDeadline(base::TimeTicks deadline) { | |
| 217 begin_frame_deadline_closure_.Cancel(); | |
| 218 begin_frame_deadline_closure_.Reset( | |
| 219 base::Bind(&Scheduler::OnBeginFrameDeadline, weak_factory_.GetWeakPtr())); | |
| 220 client_->PostBeginFrameDeadline(begin_frame_deadline_closure_.callback(), | |
| 221 deadline); | |
| 222 } | |
| 223 | |
| 224 void Scheduler::OnBeginFrameDeadline() { | |
| 225 TRACE_EVENT0("cc", "Scheduler::OnBeginFrameDeadline"); | |
| 226 begin_frame_deadline_closure_.Cancel(); | |
| 227 state_machine_.OnBeginFrameDeadline(); | |
| 228 ProcessScheduledActions(); | |
| 229 // We only transition out of BEGIN_FRAME_STATE_INSIDE_DEADLINE when all | |
| 230 // actions that occur back-to-back in response to entering | |
| 231 // BEGIN_FRAME_STATE_INSIDE_DEADLINE have completed. This is important | |
| 232 // because sending the BeginFrame to the main thread will not occur if | |
| 233 // we transition to BEGIN_FRAME_STATE_IDLE too early. | |
| 234 state_machine_.OnBeginFrameIdle(); | |
| 235 client_->DidBeginFrameDeadlineOnImplThread(); | |
| 175 } | 236 } |
| 176 | 237 |
| 177 void Scheduler::PollForAnticipatedDrawTriggers() { | 238 void Scheduler::PollForAnticipatedDrawTriggers() { |
| 178 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers"); | 239 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers"); |
| 179 state_machine_.DidEnterPollForAnticipatedDrawTriggers(); | 240 state_machine_.DidEnterPollForAnticipatedDrawTriggers(); |
| 180 ProcessScheduledActions(); | 241 ProcessScheduledActions(); |
| 181 state_machine_.DidLeavePollForAnticipatedDrawTriggers(); | 242 state_machine_.DidLeavePollForAnticipatedDrawTriggers(); |
| 182 | 243 |
| 183 poll_for_draw_triggers_closure_.Cancel(); | 244 poll_for_draw_triggers_closure_.Cancel(); |
| 184 } | 245 } |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 223 case SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD: | 284 case SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD: |
| 224 client_->ScheduledActionSendBeginFrameToMainThread(); | 285 client_->ScheduledActionSendBeginFrameToMainThread(); |
| 225 break; | 286 break; |
| 226 case SchedulerStateMachine::ACTION_COMMIT: | 287 case SchedulerStateMachine::ACTION_COMMIT: |
| 227 client_->ScheduledActionCommit(); | 288 client_->ScheduledActionCommit(); |
| 228 break; | 289 break; |
| 229 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES: | 290 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES: |
| 230 client_->ScheduledActionUpdateVisibleTiles(); | 291 client_->ScheduledActionUpdateVisibleTiles(); |
| 231 break; | 292 break; |
| 232 case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE: | 293 case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE: |
| 233 client_->ScheduledActionActivatePendingTree(); | 294 ActivatePendingTree(); |
| 234 break; | 295 break; |
| 235 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: | 296 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: |
| 236 DrawAndSwapIfPossible(); | 297 DrawAndSwapIfPossible(); |
| 237 break; | 298 break; |
| 238 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: | 299 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: |
| 239 DrawAndSwapForced(); | 300 DrawAndSwapForced(); |
| 240 break; | 301 break; |
| 241 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: | 302 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: |
| 242 // No action is actually performed, but this allows the state machine to | 303 // No action is actually performed, but this allows the state machine to |
| 243 // advance out of its waiting to draw state without actually drawing. | 304 // advance out of its waiting to draw state without actually drawing. |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 259 | 320 |
| 260 SetupNextBeginFrameIfNeeded(); | 321 SetupNextBeginFrameIfNeeded(); |
| 261 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); | 322 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); |
| 262 } | 323 } |
| 263 | 324 |
| 264 bool Scheduler::WillDrawIfNeeded() const { | 325 bool Scheduler::WillDrawIfNeeded() const { |
| 265 return !state_machine_.PendingDrawsShouldBeAborted(); | 326 return !state_machine_.PendingDrawsShouldBeAborted(); |
| 266 } | 327 } |
| 267 | 328 |
| 268 } // namespace cc | 329 } // namespace cc |
| OLD | NEW |