| 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 <algorithm> |
| 8 #include "base/auto_reset.h" | 8 #include "base/auto_reset.h" |
| 9 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "cc/debug/devtools_instrumentation.h" | 11 #include "cc/debug/devtools_instrumentation.h" |
| 12 #include "cc/debug/traced_value.h" | 12 #include "cc/debug/traced_value.h" |
| 13 #include "ui/gfx/frame_time.h" | 13 #include "ui/gfx/frame_time.h" |
| 14 | 14 |
| 15 namespace cc { | 15 namespace cc { |
| 16 | 16 |
| 17 Scheduler::Scheduler( | 17 Scheduler::Scheduler( |
| 18 SchedulerClient* client, | 18 SchedulerClient* client, |
| 19 const SchedulerSettings& scheduler_settings, | 19 const SchedulerSettings& scheduler_settings, |
| 20 int layer_tree_host_id, | 20 int layer_tree_host_id, |
| 21 const scoped_refptr<base::SequencedTaskRunner>& impl_task_runner) | 21 const scoped_refptr<base::SequencedTaskRunner>& impl_task_runner) |
| 22 : settings_(scheduler_settings), | 22 : settings_(scheduler_settings), |
| 23 client_(client), | 23 client_(client), |
| 24 layer_tree_host_id_(layer_tree_host_id), | 24 layer_tree_host_id_(layer_tree_host_id), |
| 25 impl_task_runner_(impl_task_runner), | 25 impl_task_runner_(impl_task_runner), |
| 26 last_set_needs_begin_impl_frame_(false), | 26 last_set_needs_begin_frame_(false), |
| 27 begin_retro_frame_posted_(false), |
| 27 state_machine_(scheduler_settings), | 28 state_machine_(scheduler_settings), |
| 28 inside_process_scheduled_actions_(false), | 29 inside_process_scheduled_actions_(false), |
| 29 inside_action_(SchedulerStateMachine::ACTION_NONE), | 30 inside_action_(SchedulerStateMachine::ACTION_NONE), |
| 30 weak_factory_(this) { | 31 weak_factory_(this) { |
| 31 DCHECK(client_); | 32 DCHECK(client_); |
| 32 DCHECK(!state_machine_.BeginImplFrameNeeded()); | 33 DCHECK(!state_machine_.BeginFrameNeeded()); |
| 33 if (settings_.main_frame_before_activation_enabled) { | 34 if (settings_.main_frame_before_activation_enabled) { |
| 34 DCHECK(settings_.main_frame_before_draw_enabled); | 35 DCHECK(settings_.main_frame_before_draw_enabled); |
| 35 } | 36 } |
| 36 | 37 |
| 38 begin_retro_frame_closure_ = |
| 39 base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr()); |
| 37 begin_impl_frame_deadline_closure_ = base::Bind( | 40 begin_impl_frame_deadline_closure_ = base::Bind( |
| 38 &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr()); | 41 &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr()); |
| 39 poll_for_draw_triggers_closure_ = base::Bind( | 42 poll_for_draw_triggers_closure_ = base::Bind( |
| 40 &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr()); | 43 &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr()); |
| 41 advance_commit_state_closure_ = base::Bind( | 44 advance_commit_state_closure_ = base::Bind( |
| 42 &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr()); | 45 &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr()); |
| 43 } | 46 } |
| 44 | 47 |
| 45 Scheduler::~Scheduler() {} | 48 Scheduler::~Scheduler() {} |
| 46 | 49 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 ProcessScheduledActions(); | 114 ProcessScheduledActions(); |
| 112 } | 115 } |
| 113 | 116 |
| 114 void Scheduler::DidManageTiles() { | 117 void Scheduler::DidManageTiles() { |
| 115 state_machine_.DidManageTiles(); | 118 state_machine_.DidManageTiles(); |
| 116 } | 119 } |
| 117 | 120 |
| 118 void Scheduler::DidLoseOutputSurface() { | 121 void Scheduler::DidLoseOutputSurface() { |
| 119 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); | 122 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); |
| 120 state_machine_.DidLoseOutputSurface(); | 123 state_machine_.DidLoseOutputSurface(); |
| 121 last_set_needs_begin_impl_frame_ = false; | 124 last_set_needs_begin_frame_ = false; |
| 125 begin_retro_frame_args_.clear(); |
| 122 ProcessScheduledActions(); | 126 ProcessScheduledActions(); |
| 123 } | 127 } |
| 124 | 128 |
| 125 void Scheduler::DidCreateAndInitializeOutputSurface() { | 129 void Scheduler::DidCreateAndInitializeOutputSurface() { |
| 126 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); | 130 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); |
| 127 DCHECK(!last_set_needs_begin_impl_frame_); | 131 DCHECK(!last_set_needs_begin_frame_); |
| 128 DCHECK(begin_impl_frame_deadline_task_.IsCancelled()); | 132 DCHECK(begin_impl_frame_deadline_task_.IsCancelled()); |
| 129 state_machine_.DidCreateAndInitializeOutputSurface(); | 133 state_machine_.DidCreateAndInitializeOutputSurface(); |
| 130 ProcessScheduledActions(); | 134 ProcessScheduledActions(); |
| 131 } | 135 } |
| 132 | 136 |
| 133 void Scheduler::NotifyBeginMainFrameStarted() { | 137 void Scheduler::NotifyBeginMainFrameStarted() { |
| 134 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted"); | 138 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted"); |
| 135 state_machine_.NotifyBeginMainFrameStarted(); | 139 state_machine_.NotifyBeginMainFrameStarted(); |
| 136 } | 140 } |
| 137 | 141 |
| 138 base::TimeTicks Scheduler::AnticipatedDrawTime() const { | 142 base::TimeTicks Scheduler::AnticipatedDrawTime() const { |
| 139 if (!last_set_needs_begin_impl_frame_ || | 143 if (!last_set_needs_begin_frame_ || |
| 140 last_begin_impl_frame_args_.interval <= base::TimeDelta()) | 144 begin_impl_frame_args_.interval <= base::TimeDelta()) |
| 141 return base::TimeTicks(); | 145 return base::TimeTicks(); |
| 142 | 146 |
| 143 base::TimeTicks now = gfx::FrameTime::Now(); | 147 base::TimeTicks now = gfx::FrameTime::Now(); |
| 144 base::TimeTicks timebase = std::max(last_begin_impl_frame_args_.frame_time, | 148 base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time, |
| 145 last_begin_impl_frame_args_.deadline); | 149 begin_impl_frame_args_.deadline); |
| 146 int64 intervals = | 150 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval); |
| 147 1 + ((now - timebase) / last_begin_impl_frame_args_.interval); | 151 return timebase + (begin_impl_frame_args_.interval * intervals); |
| 148 return timebase + (last_begin_impl_frame_args_.interval * intervals); | |
| 149 } | 152 } |
| 150 | 153 |
| 151 base::TimeTicks Scheduler::LastBeginImplFrameTime() { | 154 base::TimeTicks Scheduler::LastBeginImplFrameTime() { |
| 152 return last_begin_impl_frame_args_.frame_time; | 155 return begin_impl_frame_args_.frame_time; |
| 153 } | 156 } |
| 154 | 157 |
| 155 void Scheduler::SetupNextBeginImplFrameIfNeeded() { | 158 void Scheduler::SetupNextBeginFrameIfNeeded() { |
| 156 bool needs_begin_impl_frame = | 159 bool needs_begin_frame = state_machine_.BeginFrameNeeded(); |
| 157 state_machine_.BeginImplFrameNeeded(); | |
| 158 | 160 |
| 159 bool at_end_of_deadline = | 161 bool at_end_of_deadline = |
| 160 state_machine_.begin_impl_frame_state() == | 162 state_machine_.begin_impl_frame_state() == |
| 161 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE; | 163 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE; |
| 162 | 164 |
| 163 bool should_call_set_needs_begin_impl_frame = | 165 bool should_call_set_needs_begin_frame = |
| 164 // Always request the BeginImplFrame immediately if it wasn't needed | 166 // Always request the BeginFrame immediately if it wasn't needed before. |
| 165 // before. | 167 (needs_begin_frame && !last_set_needs_begin_frame_) || |
| 166 (needs_begin_impl_frame && !last_set_needs_begin_impl_frame_) || | 168 // We always need to explicitly request our next BeginFrame. |
| 167 // We always need to explicitly request our next BeginImplFrame. | |
| 168 at_end_of_deadline; | 169 at_end_of_deadline; |
| 169 | 170 |
| 170 if (should_call_set_needs_begin_impl_frame) { | 171 if (should_call_set_needs_begin_frame) { |
| 171 client_->SetNeedsBeginImplFrame(needs_begin_impl_frame); | 172 client_->SetNeedsBeginFrame(needs_begin_frame); |
| 172 last_set_needs_begin_impl_frame_ = needs_begin_impl_frame; | 173 last_set_needs_begin_frame_ = needs_begin_frame; |
| 173 } | 174 } |
| 174 | 175 |
| 176 // Handle retroactive BeginFrames. |
| 177 if (last_set_needs_begin_frame_) |
| 178 PostBeginRetroFrameIfNeeded(); |
| 179 |
| 175 bool needs_advance_commit_state_timer = false; | 180 bool needs_advance_commit_state_timer = false; |
| 176 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but | 181 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but |
| 177 // aren't expecting any more BeginImplFrames. This should only be needed by | 182 // aren't expecting any more BeginFrames. This should only be needed by |
| 178 // the synchronous compositor when BeginImplFrameNeeded is false. | 183 // the synchronous compositor when BeginFrameNeeded is false. |
| 179 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) { | 184 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) { |
| 180 DCHECK(!state_machine_.SupportsProactiveBeginImplFrame()); | 185 DCHECK(!state_machine_.SupportsProactiveBeginFrame()); |
| 181 DCHECK(!needs_begin_impl_frame); | 186 DCHECK(!needs_begin_frame); |
| 182 if (poll_for_draw_triggers_task_.IsCancelled()) { | 187 if (poll_for_draw_triggers_task_.IsCancelled()) { |
| 183 poll_for_draw_triggers_task_.Reset(poll_for_draw_triggers_closure_); | 188 poll_for_draw_triggers_task_.Reset(poll_for_draw_triggers_closure_); |
| 184 base::TimeDelta delay = last_begin_impl_frame_args_.IsValid() | 189 base::TimeDelta delay = begin_impl_frame_args_.IsValid() |
| 185 ? last_begin_impl_frame_args_.interval | 190 ? begin_impl_frame_args_.interval |
| 186 : BeginFrameArgs::DefaultInterval(); | 191 : BeginFrameArgs::DefaultInterval(); |
| 187 impl_task_runner_->PostDelayedTask( | 192 impl_task_runner_->PostDelayedTask( |
| 188 FROM_HERE, poll_for_draw_triggers_task_.callback(), delay); | 193 FROM_HERE, poll_for_draw_triggers_task_.callback(), delay); |
| 189 } | 194 } |
| 190 } else { | 195 } else { |
| 191 poll_for_draw_triggers_task_.Cancel(); | 196 poll_for_draw_triggers_task_.Cancel(); |
| 192 | 197 |
| 193 // At this point we'd prefer to advance through the commit flow by | 198 // At this point we'd prefer to advance through the commit flow by |
| 194 // drawing a frame, however it's possible that the frame rate controller | 199 // drawing a frame, however it's possible that the frame rate controller |
| 195 // will not give us a BeginImplFrame until the commit completes. See | 200 // will not give us a BeginFrame until the commit completes. See |
| 196 // crbug.com/317430 for an example of a swap ack being held on commit. Thus | 201 // crbug.com/317430 for an example of a swap ack being held on commit. Thus |
| 197 // we set a repeating timer to poll on ProcessScheduledActions until we | 202 // we set a repeating timer to poll on ProcessScheduledActions until we |
| 198 // successfully reach BeginImplFrame. Synchronous compositor does not use | 203 // successfully reach BeginFrame. Synchronous compositor does not use |
| 199 // frame rate controller or have the circular wait in the bug. | 204 // frame rate controller or have the circular wait in the bug. |
| 200 if (IsBeginMainFrameSentOrStarted() && | 205 if (IsBeginMainFrameSentOrStarted() && |
| 201 !settings_.using_synchronous_renderer_compositor) { | 206 !settings_.using_synchronous_renderer_compositor) { |
| 202 needs_advance_commit_state_timer = true; | 207 needs_advance_commit_state_timer = true; |
| 203 } | 208 } |
| 204 } | 209 } |
| 205 | 210 |
| 206 if (needs_advance_commit_state_timer) { | 211 if (needs_advance_commit_state_timer) { |
| 207 if (advance_commit_state_task_.IsCancelled() && | 212 if (advance_commit_state_task_.IsCancelled() && |
| 208 last_begin_impl_frame_args_.IsValid()) { | 213 begin_impl_frame_args_.IsValid()) { |
| 209 // Since we'd rather get a BeginImplFrame by the normal mechanism, we | 214 // Since we'd rather get a BeginImplFrame by the normal mechanism, we |
| 210 // set the interval to twice the interval from the previous frame. | 215 // set the interval to twice the interval from the previous frame. |
| 211 advance_commit_state_task_.Reset(advance_commit_state_closure_); | 216 advance_commit_state_task_.Reset(advance_commit_state_closure_); |
| 212 impl_task_runner_->PostDelayedTask( | 217 impl_task_runner_->PostDelayedTask(FROM_HERE, |
| 213 FROM_HERE, | 218 advance_commit_state_task_.callback(), |
| 214 advance_commit_state_task_.callback(), | 219 begin_impl_frame_args_.interval * 2); |
| 215 last_begin_impl_frame_args_.interval * 2); | |
| 216 } | 220 } |
| 217 } else { | 221 } else { |
| 218 advance_commit_state_task_.Cancel(); | 222 advance_commit_state_task_.Cancel(); |
| 219 } | 223 } |
| 220 } | 224 } |
| 221 | 225 |
| 226 // BeginFrame is the mechanism that tells us that now is a good time to start |
| 227 // making a frame. Usually this means that user input for the frame is complete. |
| 228 // If the scheduler is busy, we queue the BeginFrame to be handled later as |
| 229 // a BeginRetroFrame. |
| 230 void Scheduler::BeginFrame(const BeginFrameArgs& args) { |
| 231 bool should_defer_begin_frame; |
| 232 if (settings_.using_synchronous_renderer_compositor) { |
| 233 should_defer_begin_frame = false; |
| 234 } else { |
| 235 should_defer_begin_frame = |
| 236 !begin_retro_frame_args_.empty() || begin_retro_frame_posted_ || |
| 237 !last_set_needs_begin_frame_ || |
| 238 (state_machine_.begin_impl_frame_state() != |
| 239 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); |
| 240 } |
| 241 |
| 242 if (should_defer_begin_frame) { |
| 243 begin_retro_frame_args_.push_back(args); |
| 244 TRACE_EVENT_INSTANT0( |
| 245 "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD); |
| 246 return; |
| 247 } |
| 248 |
| 249 BeginImplFrame(args); |
| 250 } |
| 251 |
| 252 // BeginRetroFrame is called for BeginFrames that we've deferred because |
| 253 // the scheduler was in the middle of processing a previous BeginFrame. |
| 254 void Scheduler::BeginRetroFrame() { |
| 255 TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame"); |
| 256 DCHECK(begin_retro_frame_posted_); |
| 257 DCHECK(!begin_retro_frame_args_.empty()); |
| 258 DCHECK(!settings_.using_synchronous_renderer_compositor); |
| 259 |
| 260 // Discard expired BeginRetroFrames |
| 261 // Today, we should always end up with at most one un-expired BeginRetroFrame |
| 262 // because deadlines will not be greater than the next frame time. We don't |
| 263 // DCHECK though because some systems don't always have monotonic timestamps. |
| 264 // TODO(brianderson): In the future, long deadlines could result in us not |
| 265 // draining the queue if we don't catch up. If we consistently can't catch |
| 266 // up, our fallback should be to lower our frame rate. |
| 267 base::TimeTicks now = gfx::FrameTime::Now(); |
| 268 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); |
| 269 while (!begin_retro_frame_args_.empty() && |
| 270 now > AdjustedBeginImplFrameDeadline(begin_retro_frame_args_.front(), |
| 271 draw_duration_estimate)) { |
| 272 begin_retro_frame_args_.pop_front(); |
| 273 } |
| 274 |
| 275 if (begin_retro_frame_args_.empty()) { |
| 276 TRACE_EVENT_INSTANT0( |
| 277 "cc", "Scheduler::BeginRetroFrames expired", TRACE_EVENT_SCOPE_THREAD); |
| 278 } else { |
| 279 BeginImplFrame(begin_retro_frame_args_.front()); |
| 280 begin_retro_frame_args_.pop_front(); |
| 281 } |
| 282 |
| 283 begin_retro_frame_posted_ = false; |
| 284 } |
| 285 |
| 286 // There could be a race between the posted BeginRetroFrame and a new |
| 287 // BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame |
| 288 // will check if there is a pending BeginRetroFrame to ensure we handle |
| 289 // BeginFrames in FIFO order. |
| 290 void Scheduler::PostBeginRetroFrameIfNeeded() { |
| 291 if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_) |
| 292 return; |
| 293 |
| 294 // begin_retro_frame_args_ should always be empty for the |
| 295 // synchronous compositor. |
| 296 DCHECK(!settings_.using_synchronous_renderer_compositor); |
| 297 |
| 298 if (state_machine_.begin_impl_frame_state() != |
| 299 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE) |
| 300 return; |
| 301 |
| 302 begin_retro_frame_posted_ = true; |
| 303 impl_task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_); |
| 304 } |
| 305 |
| 306 // BeginImplFrame starts a compositor frame that will wait up until a deadline |
| 307 // for a BeginMainFrame+activation to complete before it times out and draws |
| 308 // any asynchronous animation and scroll/pinch updates. |
| 222 void Scheduler::BeginImplFrame(const BeginFrameArgs& args) { | 309 void Scheduler::BeginImplFrame(const BeginFrameArgs& args) { |
| 223 TRACE_EVENT0("cc", "Scheduler::BeginImplFrame"); | 310 TRACE_EVENT0("cc", "Scheduler::BeginImplFrame"); |
| 224 DCHECK(state_machine_.begin_impl_frame_state() == | 311 DCHECK(state_machine_.begin_impl_frame_state() == |
| 225 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); | 312 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); |
| 226 DCHECK(state_machine_.HasInitializedOutputSurface()); | 313 DCHECK(state_machine_.HasInitializedOutputSurface()); |
| 227 | 314 |
| 228 advance_commit_state_task_.Cancel(); | 315 advance_commit_state_task_.Cancel(); |
| 229 | 316 |
| 230 last_begin_impl_frame_args_ = args; | 317 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); |
| 231 last_begin_impl_frame_args_.deadline -= client_->DrawDurationEstimate(); | 318 begin_impl_frame_args_ = args; |
| 319 begin_impl_frame_args_.deadline -= draw_duration_estimate; |
| 232 | 320 |
| 233 if (!state_machine_.smoothness_takes_priority() && | 321 if (!state_machine_.smoothness_takes_priority() && |
| 234 state_machine_.MainThreadIsInHighLatencyMode() && | 322 state_machine_.MainThreadIsInHighLatencyMode() && |
| 235 CanCommitAndActivateBeforeDeadline()) { | 323 CanCommitAndActivateBeforeDeadline()) { |
| 236 state_machine_.SetSkipNextBeginMainFrameToReduceLatency(); | 324 state_machine_.SetSkipNextBeginMainFrameToReduceLatency(); |
| 237 } | 325 } |
| 238 | 326 |
| 239 state_machine_.OnBeginImplFrame(last_begin_impl_frame_args_); | 327 client_->WillBeginImplFrame(begin_impl_frame_args_); |
| 328 state_machine_.OnBeginImplFrame(begin_impl_frame_args_); |
| 240 devtools_instrumentation::DidBeginFrame(layer_tree_host_id_); | 329 devtools_instrumentation::DidBeginFrame(layer_tree_host_id_); |
| 241 | 330 |
| 242 ProcessScheduledActions(); | 331 ProcessScheduledActions(); |
| 243 | 332 |
| 244 if (!state_machine_.HasInitializedOutputSurface()) | 333 if (!state_machine_.HasInitializedOutputSurface()) |
| 245 return; | 334 return; |
| 246 | 335 |
| 247 state_machine_.OnBeginImplFrameDeadlinePending(); | 336 state_machine_.OnBeginImplFrameDeadlinePending(); |
| 248 base::TimeTicks adjusted_deadline = AdjustedBeginImplFrameDeadline(); | 337 ScheduleBeginImplFrameDeadline( |
| 249 ScheduleBeginImplFrameDeadline(adjusted_deadline); | 338 AdjustedBeginImplFrameDeadline(args, draw_duration_estimate)); |
| 250 } | 339 } |
| 251 | 340 |
| 252 base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline() const { | 341 base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline( |
| 342 const BeginFrameArgs& args, |
| 343 base::TimeDelta draw_duration_estimate) const { |
| 253 if (settings_.using_synchronous_renderer_compositor) { | 344 if (settings_.using_synchronous_renderer_compositor) { |
| 254 // The synchronous compositor needs to draw right away. | 345 // The synchronous compositor needs to draw right away. |
| 255 return base::TimeTicks(); | 346 return base::TimeTicks(); |
| 256 } else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) { | 347 } else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) { |
| 257 // We are ready to draw a new active tree immediately. | 348 // We are ready to draw a new active tree immediately. |
| 258 return base::TimeTicks(); | 349 return base::TimeTicks(); |
| 259 } else if (state_machine_.needs_redraw()) { | 350 } else if (state_machine_.needs_redraw()) { |
| 260 // We have an animation or fast input path on the impl thread that wants | 351 // We have an animation or fast input path on the impl thread that wants |
| 261 // to draw, so don't wait too long for a new active tree. | 352 // to draw, so don't wait too long for a new active tree. |
| 262 return last_begin_impl_frame_args_.deadline; | 353 return args.deadline - draw_duration_estimate; |
| 263 } else { | 354 } else { |
| 264 // The impl thread doesn't have anything it wants to draw and we are just | 355 // The impl thread doesn't have anything it wants to draw and we are just |
| 265 // waiting for a new active tree, so post the deadline for the next | 356 // waiting for a new active tree, so post the deadline for the next |
| 266 // expected BeginImplFrame start. This allows us to draw immediately when | 357 // expected BeginImplFrame start. This allows us to draw immediately when |
| 267 // there is a new active tree, instead of waiting for the next | 358 // there is a new active tree, instead of waiting for the next |
| 268 // BeginImplFrame. | 359 // BeginImplFrame. |
| 269 // TODO(brianderson): Handle long deadlines (that are past the next frame's | 360 // TODO(brianderson): Handle long deadlines (that are past the next frame's |
| 270 // frame time) properly instead of using this hack. | 361 // frame time) properly instead of using this hack. |
| 271 return last_begin_impl_frame_args_.frame_time + | 362 return args.frame_time + args.interval; |
| 272 last_begin_impl_frame_args_.interval; | |
| 273 } | 363 } |
| 274 } | 364 } |
| 275 | 365 |
| 276 void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) { | 366 void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) { |
| 277 if (settings_.using_synchronous_renderer_compositor) { | 367 if (settings_.using_synchronous_renderer_compositor) { |
| 278 // The synchronous renderer compositor has to make its GL calls | 368 // The synchronous renderer compositor has to make its GL calls |
| 279 // within this call. | 369 // within this call. |
| 280 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks | 370 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks |
| 281 // so the sychronous renderer compositor can take advantage of splitting | 371 // so the sychronous renderer compositor can take advantage of splitting |
| 282 // up the BeginImplFrame and deadline as well. | 372 // up the BeginImplFrame and deadline as well. |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 break; | 485 break; |
| 396 case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION: | 486 case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION: |
| 397 client_->ScheduledActionBeginOutputSurfaceCreation(); | 487 client_->ScheduledActionBeginOutputSurfaceCreation(); |
| 398 break; | 488 break; |
| 399 case SchedulerStateMachine::ACTION_MANAGE_TILES: | 489 case SchedulerStateMachine::ACTION_MANAGE_TILES: |
| 400 client_->ScheduledActionManageTiles(); | 490 client_->ScheduledActionManageTiles(); |
| 401 break; | 491 break; |
| 402 } | 492 } |
| 403 } while (action != SchedulerStateMachine::ACTION_NONE); | 493 } while (action != SchedulerStateMachine::ACTION_NONE); |
| 404 | 494 |
| 405 SetupNextBeginImplFrameIfNeeded(); | 495 SetupNextBeginFrameIfNeeded(); |
| 406 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); | 496 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); |
| 407 | 497 |
| 408 if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) { | 498 if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) { |
| 409 DCHECK(!settings_.using_synchronous_renderer_compositor); | 499 DCHECK(!settings_.using_synchronous_renderer_compositor); |
| 410 ScheduleBeginImplFrameDeadline(base::TimeTicks()); | 500 ScheduleBeginImplFrameDeadline(base::TimeTicks()); |
| 411 } | 501 } |
| 412 } | 502 } |
| 413 | 503 |
| 414 bool Scheduler::WillDrawIfNeeded() const { | 504 bool Scheduler::WillDrawIfNeeded() const { |
| 415 return !state_machine_.PendingDrawsShouldBeAborted(); | 505 return !state_machine_.PendingDrawsShouldBeAborted(); |
| 416 } | 506 } |
| 417 | 507 |
| 418 scoped_ptr<base::Value> Scheduler::StateAsValue() const { | 508 scoped_ptr<base::Value> Scheduler::StateAsValue() const { |
| 419 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue); | 509 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue); |
| 420 state->Set("state_machine", state_machine_.AsValue().release()); | 510 state->Set("state_machine", state_machine_.AsValue().release()); |
| 421 | 511 |
| 422 scoped_ptr<base::DictionaryValue> scheduler_state(new base::DictionaryValue); | 512 scoped_ptr<base::DictionaryValue> scheduler_state(new base::DictionaryValue); |
| 423 scheduler_state->SetDouble( | 513 scheduler_state->SetDouble( |
| 424 "time_until_anticipated_draw_time_ms", | 514 "time_until_anticipated_draw_time_ms", |
| 425 (AnticipatedDrawTime() - base::TimeTicks::Now()).InMillisecondsF()); | 515 (AnticipatedDrawTime() - base::TimeTicks::Now()).InMillisecondsF()); |
| 426 scheduler_state->SetBoolean("last_set_needs_begin_impl_frame_", | 516 scheduler_state->SetBoolean("last_set_needs_begin_frame_", |
| 427 last_set_needs_begin_impl_frame_); | 517 last_set_needs_begin_frame_); |
| 428 scheduler_state->SetBoolean("begin_impl_frame_deadline_task_", | 518 scheduler_state->SetBoolean("begin_impl_frame_deadline_task_", |
| 429 !begin_impl_frame_deadline_task_.IsCancelled()); | 519 !begin_impl_frame_deadline_task_.IsCancelled()); |
| 430 scheduler_state->SetBoolean("poll_for_draw_triggers_task_", | 520 scheduler_state->SetBoolean("poll_for_draw_triggers_task_", |
| 431 !poll_for_draw_triggers_task_.IsCancelled()); | 521 !poll_for_draw_triggers_task_.IsCancelled()); |
| 432 scheduler_state->SetBoolean("advance_commit_state_task_", | 522 scheduler_state->SetBoolean("advance_commit_state_task_", |
| 433 !advance_commit_state_task_.IsCancelled()); | 523 !advance_commit_state_task_.IsCancelled()); |
| 434 state->Set("scheduler_state", scheduler_state.release()); | 524 state->Set("scheduler_state", scheduler_state.release()); |
| 435 | 525 |
| 436 scoped_ptr<base::DictionaryValue> client_state(new base::DictionaryValue); | 526 scoped_ptr<base::DictionaryValue> client_state(new base::DictionaryValue); |
| 437 client_state->SetDouble("draw_duration_estimate_ms", | 527 client_state->SetDouble("draw_duration_estimate_ms", |
| 438 client_->DrawDurationEstimate().InMillisecondsF()); | 528 client_->DrawDurationEstimate().InMillisecondsF()); |
| 439 client_state->SetDouble( | 529 client_state->SetDouble( |
| 440 "begin_main_frame_to_commit_duration_estimate_ms", | 530 "begin_main_frame_to_commit_duration_estimate_ms", |
| 441 client_->BeginMainFrameToCommitDurationEstimate().InMillisecondsF()); | 531 client_->BeginMainFrameToCommitDurationEstimate().InMillisecondsF()); |
| 442 client_state->SetDouble( | 532 client_state->SetDouble( |
| 443 "commit_to_activate_duration_estimate_ms", | 533 "commit_to_activate_duration_estimate_ms", |
| 444 client_->CommitToActivateDurationEstimate().InMillisecondsF()); | 534 client_->CommitToActivateDurationEstimate().InMillisecondsF()); |
| 445 state->Set("client_state", client_state.release()); | 535 state->Set("client_state", client_state.release()); |
| 446 return state.PassAs<base::Value>(); | 536 return state.PassAs<base::Value>(); |
| 447 } | 537 } |
| 448 | 538 |
| 449 bool Scheduler::CanCommitAndActivateBeforeDeadline() const { | 539 bool Scheduler::CanCommitAndActivateBeforeDeadline() const { |
| 450 // Check if the main thread computation and commit can be finished before the | 540 // Check if the main thread computation and commit can be finished before the |
| 451 // impl thread's deadline. | 541 // impl thread's deadline. |
| 452 base::TimeTicks estimated_draw_time = | 542 base::TimeTicks estimated_draw_time = |
| 453 last_begin_impl_frame_args_.frame_time + | 543 begin_impl_frame_args_.frame_time + |
| 454 client_->BeginMainFrameToCommitDurationEstimate() + | 544 client_->BeginMainFrameToCommitDurationEstimate() + |
| 455 client_->CommitToActivateDurationEstimate(); | 545 client_->CommitToActivateDurationEstimate(); |
| 456 | 546 |
| 457 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), | 547 TRACE_EVENT2( |
| 458 "CanCommitAndActivateBeforeDeadline", | 548 TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), |
| 459 "time_left_after_drawing_ms", | 549 "CanCommitAndActivateBeforeDeadline", |
| 460 (last_begin_impl_frame_args_.deadline - estimated_draw_time) | 550 "time_left_after_drawing_ms", |
| 461 .InMillisecondsF(), | 551 (begin_impl_frame_args_.deadline - estimated_draw_time).InMillisecondsF(), |
| 462 "state", | 552 "state", |
| 463 TracedValue::FromValue(StateAsValue().release())); | 553 TracedValue::FromValue(StateAsValue().release())); |
| 464 | 554 |
| 465 return estimated_draw_time < last_begin_impl_frame_args_.deadline; | 555 return estimated_draw_time < begin_impl_frame_args_.deadline; |
| 466 } | 556 } |
| 467 | 557 |
| 468 bool Scheduler::IsBeginMainFrameSentOrStarted() const { | 558 bool Scheduler::IsBeginMainFrameSentOrStarted() const { |
| 469 return (state_machine_.commit_state() == | 559 return (state_machine_.commit_state() == |
| 470 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || | 560 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || |
| 471 state_machine_.commit_state() == | 561 state_machine_.commit_state() == |
| 472 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); | 562 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); |
| 473 } | 563 } |
| 474 | 564 |
| 475 } // namespace cc | 565 } // namespace cc |
| OLD | NEW |