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 | 8 |
9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 primary_frame_source_(NULL), | 83 primary_frame_source_(NULL), |
84 background_frame_source_(NULL), | 84 background_frame_source_(NULL), |
85 primary_frame_source_internal_(external_begin_frame_source.Pass()), | 85 primary_frame_source_internal_(external_begin_frame_source.Pass()), |
86 background_frame_source_internal_(), | 86 background_frame_source_internal_(), |
87 vsync_observer_(NULL), | 87 vsync_observer_(NULL), |
88 settings_(scheduler_settings), | 88 settings_(scheduler_settings), |
89 client_(client), | 89 client_(client), |
90 layer_tree_host_id_(layer_tree_host_id), | 90 layer_tree_host_id_(layer_tree_host_id), |
91 task_runner_(task_runner), | 91 task_runner_(task_runner), |
92 power_monitor_(power_monitor), | 92 power_monitor_(power_monitor), |
93 begin_retro_frame_posted_(false), | 93 begin_frame_process_posted_(false), |
94 state_machine_(scheduler_settings), | 94 state_machine_(scheduler_settings), |
95 inside_process_scheduled_actions_(false), | 95 inside_process_scheduled_actions_(false), |
96 inside_action_(SchedulerStateMachine::ACTION_NONE), | 96 inside_action_(SchedulerStateMachine::ACTION_NONE), |
97 weak_factory_(this) { | 97 weak_factory_(this) { |
98 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), | 98 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), |
99 "Scheduler::Scheduler", | 99 "Scheduler::Scheduler", |
100 "settings", | 100 "settings", |
101 settings_.AsValue()); | 101 settings_.AsValue()); |
102 DCHECK(client_); | 102 DCHECK(client_); |
103 DCHECK(!state_machine_.BeginFrameNeeded()); | 103 DCHECK(!state_machine_.BeginFrameNeeded()); |
104 | 104 |
105 begin_retro_frame_closure_ = | 105 begin_frame_process_closure_ = |
106 base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr()); | 106 base::Bind(&Scheduler::ProcessBeginFrames, weak_factory_.GetWeakPtr()); |
107 begin_impl_frame_deadline_closure_ = base::Bind( | 107 begin_impl_frame_deadline_closure_ = base::Bind( |
108 &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr()); | 108 &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr()); |
109 poll_for_draw_triggers_closure_ = base::Bind( | 109 poll_for_draw_triggers_closure_ = base::Bind( |
110 &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr()); | 110 &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr()); |
111 advance_commit_state_closure_ = base::Bind( | 111 advance_commit_state_closure_ = base::Bind( |
112 &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr()); | 112 &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr()); |
113 | 113 |
114 frame_source_ = BeginFrameSourceMultiplexer::Create(); | 114 frame_source_ = BeginFrameSourceMultiplexer::Create(); |
115 frame_source_->AddObserver(this); | 115 frame_source_->AddObserver(this); |
116 | 116 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
152 } | 152 } |
153 } | 153 } |
154 | 154 |
155 void Scheduler::TeardownPowerMonitoring() { | 155 void Scheduler::TeardownPowerMonitoring() { |
156 if (settings_.disable_hi_res_timer_tasks_on_battery) { | 156 if (settings_.disable_hi_res_timer_tasks_on_battery) { |
157 DCHECK(power_monitor_); | 157 DCHECK(power_monitor_); |
158 power_monitor_->RemoveObserver(this); | 158 power_monitor_->RemoveObserver(this); |
159 } | 159 } |
160 } | 160 } |
161 | 161 |
162 void Scheduler::OnPowerStateChange(bool on_battery_power) { | |
163 DCHECK(settings_.disable_hi_res_timer_tasks_on_battery); | |
164 state_machine_.SetImplLatencyTakesPriorityOnBattery(on_battery_power); | |
165 } | |
166 | |
167 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, | 162 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, |
168 base::TimeDelta interval) { | 163 base::TimeDelta interval) { |
169 // TODO(brianderson): We should not be receiving 0 intervals. | 164 // TODO(brianderson): We should not be receiving 0 intervals. |
170 if (interval == base::TimeDelta()) | 165 if (interval == base::TimeDelta()) |
171 interval = BeginFrameArgs::DefaultInterval(); | 166 interval = BeginFrameArgs::DefaultInterval(); |
172 | 167 |
173 if (vsync_observer_) | 168 if (vsync_observer_) |
174 vsync_observer_->OnUpdateVSyncParameters(timebase, interval); | 169 vsync_observer_->OnUpdateVSyncParameters(timebase, interval); |
175 } | 170 } |
176 | 171 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
242 if (!inside_process_scheduled_actions_) { | 237 if (!inside_process_scheduled_actions_) { |
243 DCHECK_EQ(state_machine_.NextAction(), SchedulerStateMachine::ACTION_NONE); | 238 DCHECK_EQ(state_machine_.NextAction(), SchedulerStateMachine::ACTION_NONE); |
244 } | 239 } |
245 } | 240 } |
246 | 241 |
247 void Scheduler::DidSwapBuffersComplete() { | 242 void Scheduler::DidSwapBuffersComplete() { |
248 state_machine_.DidSwapBuffersComplete(); | 243 state_machine_.DidSwapBuffersComplete(); |
249 ProcessScheduledActions(); | 244 ProcessScheduledActions(); |
250 } | 245 } |
251 | 246 |
252 void Scheduler::SetImplLatencyTakesPriority(bool impl_latency_takes_priority) { | |
253 state_machine_.SetImplLatencyTakesPriority(impl_latency_takes_priority); | |
254 ProcessScheduledActions(); | |
255 } | |
256 | |
257 void Scheduler::NotifyReadyToCommit() { | 247 void Scheduler::NotifyReadyToCommit() { |
258 TRACE_EVENT0("cc", "Scheduler::NotifyReadyToCommit"); | 248 TRACE_EVENT0("cc", "Scheduler::NotifyReadyToCommit"); |
259 state_machine_.NotifyReadyToCommit(); | 249 state_machine_.NotifyReadyToCommit(); |
260 ProcessScheduledActions(); | 250 ProcessScheduledActions(); |
261 } | 251 } |
262 | 252 |
263 void Scheduler::BeginMainFrameAborted(bool did_handle) { | 253 void Scheduler::BeginMainFrameAborted(bool did_handle) { |
264 TRACE_EVENT0("cc", "Scheduler::BeginMainFrameAborted"); | 254 TRACE_EVENT0("cc", "Scheduler::BeginMainFrameAborted"); |
265 state_machine_.BeginMainFrameAborted(did_handle); | 255 state_machine_.BeginMainFrameAborted(did_handle); |
266 ProcessScheduledActions(); | 256 ProcessScheduledActions(); |
267 } | 257 } |
268 | 258 |
269 void Scheduler::DidManageTiles() { | 259 void Scheduler::DidManageTiles() { |
270 state_machine_.DidManageTiles(); | 260 state_machine_.DidManageTiles(); |
271 } | 261 } |
272 | 262 |
273 void Scheduler::DidLoseOutputSurface() { | 263 void Scheduler::DidLoseOutputSurface() { |
274 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); | 264 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); |
275 state_machine_.DidLoseOutputSurface(); | 265 state_machine_.DidLoseOutputSurface(); |
276 if (frame_source_->NeedsBeginFrames()) | 266 if (frame_source_->NeedsBeginFrames()) |
277 frame_source_->SetNeedsBeginFrames(false); | 267 frame_source_->SetNeedsBeginFrames(false); |
278 begin_retro_frame_args_.clear(); | 268 pending_begin_frame_args_.clear(); |
279 ProcessScheduledActions(); | 269 ProcessScheduledActions(); |
280 } | 270 } |
281 | 271 |
282 void Scheduler::DidCreateAndInitializeOutputSurface() { | 272 void Scheduler::DidCreateAndInitializeOutputSurface() { |
283 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); | 273 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); |
284 DCHECK(!frame_source_->NeedsBeginFrames()); | 274 DCHECK(!frame_source_->NeedsBeginFrames()); |
285 DCHECK(begin_impl_frame_deadline_task_.IsCancelled()); | 275 DCHECK(begin_impl_frame_deadline_task_.IsCancelled()); |
| 276 |
286 state_machine_.DidCreateAndInitializeOutputSurface(); | 277 state_machine_.DidCreateAndInitializeOutputSurface(); |
287 ProcessScheduledActions(); | 278 ProcessScheduledActions(); |
| 279 |
| 280 // We want to start the first commit ASAP, so we post the LastBeginFrameArgs |
| 281 // onto the retro queue and process it. |
| 282 BeginFrameArgs missed = frame_source_->LastBeginFrameArgs(); |
| 283 missed.type = BeginFrameArgs::MISSED; |
| 284 // Adjust the deadline |
| 285 //missed.deadline = XXXXX |
| 286 OnBeginFrame(missed); |
288 } | 287 } |
289 | 288 |
290 void Scheduler::NotifyBeginMainFrameStarted() { | 289 void Scheduler::NotifyBeginMainFrameStarted() { |
291 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted"); | 290 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted"); |
292 state_machine_.NotifyBeginMainFrameStarted(); | 291 state_machine_.NotifyBeginMainFrameStarted(); |
293 } | 292 } |
294 | 293 |
295 base::TimeTicks Scheduler::AnticipatedDrawTime() const { | |
296 if (!frame_source_->NeedsBeginFrames() || | |
297 begin_impl_frame_args_.interval <= base::TimeDelta()) | |
298 return base::TimeTicks(); | |
299 | |
300 base::TimeTicks now = Now(); | |
301 base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time, | |
302 begin_impl_frame_args_.deadline); | |
303 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval); | |
304 return timebase + (begin_impl_frame_args_.interval * intervals); | |
305 } | |
306 | |
307 base::TimeTicks Scheduler::LastBeginImplFrameTime() { | |
308 return begin_impl_frame_args_.frame_time; | |
309 } | |
310 | |
311 void Scheduler::SetupNextBeginFrameIfNeeded() { | 294 void Scheduler::SetupNextBeginFrameIfNeeded() { |
312 if (!task_runner_.get()) | 295 if (!task_runner_.get()) |
313 return; | 296 return; |
314 | 297 |
315 bool needs_begin_frame = state_machine_.BeginFrameNeeded(); | 298 bool needs_begin_frame = state_machine_.BeginFrameNeeded(); |
316 | 299 |
317 bool at_end_of_deadline = | 300 bool at_end_of_deadline = |
318 (state_machine_.begin_impl_frame_state() == | 301 (state_machine_.begin_impl_frame_state() == |
319 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE); | 302 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE); |
320 | 303 |
321 bool should_call_set_needs_begin_frame = | 304 bool should_call_set_needs_begin_frame = |
322 // Always request the BeginFrame immediately if it wasn't needed before. | 305 // Always request the BeginFrame immediately if it wasn't needed before. |
323 (needs_begin_frame && !frame_source_->NeedsBeginFrames()) || | 306 (needs_begin_frame && !frame_source_->NeedsBeginFrames()) || |
324 // Only stop requesting BeginFrames after a deadline. | 307 // Only stop requesting BeginFrames after a deadline. |
325 (!needs_begin_frame && frame_source_->NeedsBeginFrames() && | 308 (!needs_begin_frame && frame_source_->NeedsBeginFrames() && |
326 at_end_of_deadline); | 309 at_end_of_deadline); |
327 | 310 |
328 if (should_call_set_needs_begin_frame) { | 311 if (should_call_set_needs_begin_frame) { |
329 frame_source_->SetNeedsBeginFrames(needs_begin_frame); | 312 frame_source_->SetNeedsBeginFrames(needs_begin_frame); |
330 } | 313 } |
331 | 314 |
332 if (at_end_of_deadline) { | 315 if (at_end_of_deadline) { |
333 frame_source_->DidFinishFrame(begin_retro_frame_args_.size()); | 316 frame_source_->DidFinishFrame(pending_begin_frame_args_.size()); |
334 } | 317 } |
335 | 318 |
336 PostBeginRetroFrameIfNeeded(); | |
337 SetupPollingMechanisms(needs_begin_frame); | 319 SetupPollingMechanisms(needs_begin_frame); |
338 } | 320 } |
339 | 321 |
340 // We may need to poll when we can't rely on BeginFrame to advance certain | 322 // We may need to poll when we can't rely on BeginFrame to advance certain |
341 // state or to avoid deadlock. | 323 // state or to avoid deadlock. |
342 void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) { | 324 void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) { |
343 bool needs_advance_commit_state_timer = false; | 325 bool needs_advance_commit_state_timer = false; |
344 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but | 326 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but |
345 // aren't expecting any more BeginFrames. This should only be needed by | 327 // aren't expecting any more BeginFrames. This should only be needed by |
346 // the synchronous compositor when BeginFrameNeeded is false. | 328 // the synchronous compositor when BeginFrameNeeded is false. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
379 advance_commit_state_task_.Reset(advance_commit_state_closure_); | 361 advance_commit_state_task_.Reset(advance_commit_state_closure_); |
380 task_runner_->PostDelayedTask(FROM_HERE, | 362 task_runner_->PostDelayedTask(FROM_HERE, |
381 advance_commit_state_task_.callback(), | 363 advance_commit_state_task_.callback(), |
382 begin_impl_frame_args_.interval * 2); | 364 begin_impl_frame_args_.interval * 2); |
383 } | 365 } |
384 } else { | 366 } else { |
385 advance_commit_state_task_.Cancel(); | 367 advance_commit_state_task_.Cancel(); |
386 } | 368 } |
387 } | 369 } |
388 | 370 |
| 371 base::TimeDelta Scheduler::TimeForDrawing() { |
| 372 return EstimatedParentDrawTime() + client_->DrawDurationEstimate(); |
| 373 } |
| 374 |
| 375 base::TimeTicks Scheduler::CalculateDeadline(base::TimeTicks now, const BeginFra
meArgs& args) { |
| 376 // Synchronous renderer should doesn't use deadlines. |
| 377 if (settings_.using_synchronous_renderer_compositor) { |
| 378 return base::TimeTicks(); |
| 379 } |
| 380 |
| 381 base::TimeTicks deadline = args.deadline; |
| 382 |
| 383 // Decrease the deadline enough to give drawing enough time to happen. |
| 384 deadline -= TimeForDrawing(); |
| 385 |
| 386 if (false) { //is_low_end()) { |
| 387 // On low end devices, if we start main thread rendering it can stave us |
| 388 // of CPU. Hence, if we don't think the main will make this frame we should |
| 389 // run the impl tasks right now. |
| 390 base::TimeTicks main_thread_time = |
| 391 client_->BeginMainFrameToCommitDurationEstimate() + |
| 392 client_->CommitToActivateDurationEstimate(); |
| 393 |
| 394 if (now + main_thread_time > deadline) { |
| 395 deadline = now; |
| 396 } |
| 397 } |
| 398 |
| 399 return deadline; |
| 400 } |
| 401 |
389 // BeginFrame is the mechanism that tells us that now is a good time to start | 402 // BeginFrame is the mechanism that tells us that now is a good time to start |
390 // making a frame. Usually this means that user input for the frame is complete. | 403 // making a frame. Usually this means that user input for the frame is complete. |
391 // If the scheduler is busy, we queue the BeginFrame to be handled later as | |
392 // a BeginRetroFrame. | |
393 bool Scheduler::OnBeginFrameMixInDelegate(const BeginFrameArgs& args) { | 404 bool Scheduler::OnBeginFrameMixInDelegate(const BeginFrameArgs& args) { |
394 TRACE_EVENT1("cc", "Scheduler::BeginFrame", "args", args.AsValue()); | 405 TRACE_EVENT1("cc", "Scheduler::BeginFrame", "args", args.AsValue()); |
395 | 406 |
| 407 // Push the BeginFrame onto a queue for processing. |
| 408 begin_retro_frame_args.push_back(args); |
| 409 |
| 410 // If we aren't already processing frames, start processing now. |
| 411 if (state_machine_.begin_impl_frame_state() == SchedulerStateMachine::BEGIN_IM
PL_FRAME_STATE_IDLE) { |
| 412 ProcessBeginFrames(nullptr); |
| 413 // Otherwise, post a task to process the frames after the current processing |
| 414 // is finished. |
| 415 } else if (!begin_frame_process_posted_) { |
| 416 begin_frame_process_posted_ = true; |
| 417 task_runner_->PostTask(FROM_HERE, begin_frame_process_closure_, &begin_frame
_process_posted_); |
| 418 } |
| 419 |
| 420 return true; |
| 421 } |
| 422 |
| 423 void Scheduler::ProcessBeginFrames(bool* clear_posted) { |
| 424 DCHECK(!begin_retro_frame_args.empty()); |
| 425 |
| 426 if (clear_posted) { |
| 427 *clear_posted = false; |
| 428 } |
| 429 |
| 430 // Capture now to use for all the deadline calculations |
| 431 base::TimeTicks now = Now(); |
| 432 |
| 433 // If we have multiple frames to process, discard anything which we can't |
| 434 // make it's deadline. |
| 435 while (pending_begin_frame_args_.size() > 1) { |
| 436 const BeginFrameArgs& args = pending_begin_frame_args_.front(); |
| 437 |
| 438 base::TimeTicks deadline = CalculateDeadline(now, args); |
| 439 if (now >= deadline) { |
| 440 TRACE_EVENT_INSTANT2( |
| 441 "cc", "Scheduler::BeginFrame discarding", TRACE_EVENT_SCOPE_THREAD, |
| 442 "expiration_time - now", (deadline - now).InMillisecondsF(), |
| 443 "BeginFrameArgs", args.AsValue()); |
| 444 pending_begin_frame_args_.pop_front(); |
| 445 frame_source_->DidFinishFrame(pending_begin_frame_args_.size()); |
| 446 } |
| 447 } |
| 448 |
| 449 // Process the head of the queue. |
| 450 BeginFrameArgs front_args = pending_begin_frame_args_.front(); |
| 451 pending_begin_frame_args_.pop_front(); |
| 452 front_args.deadline = CalculateDeadline(now, front_args); |
| 453 BeginImplFrame(now, front_args); |
| 454 } |
| 455 |
| 456 |
| 457 void Scheduler::BeginImplFrame(base::TimeTicks now, const BeginFrameArgs& args)
{ |
| 458 // Clear any pending impl frame deadline |
| 459 begin_impl_frame_deadline_task_.Cancel(); |
| 460 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); |
| 461 |
| 462 // TODO(mithro): ????? |
396 // Deliver BeginFrames to children. | 463 // Deliver BeginFrames to children. |
397 if (settings_.forward_begin_frames_to_children && | 464 if (settings_.forward_begin_frames_to_children && |
398 state_machine_.children_need_begin_frames()) { | 465 state_machine_.children_need_begin_frames()) { |
399 BeginFrameArgs adjusted_args_for_children(args); | 466 BeginFrameArgs adjusted_args_for_children(args); |
400 // Adjust a deadline for child schedulers. | 467 // Adjust a deadline for child schedulers. |
401 // TODO(simonhong): Once we have commitless update, we can get rid of | 468 // TODO(simonhong): Once we have commitless update, we can get rid of |
402 // BeginMainFrameToCommitDurationEstimate() + | 469 // BeginMainFrameToCommitDurationEstimate() + |
403 // CommitToActivateDurationEstimate(). | 470 // CommitToActivateDurationEstimate(). |
404 adjusted_args_for_children.deadline -= | 471 adjusted_args_for_children.deadline -= |
405 (client_->BeginMainFrameToCommitDurationEstimate() + | 472 (client_->BeginMainFrameToCommitDurationEstimate() + |
406 client_->CommitToActivateDurationEstimate() + | 473 client_->CommitToActivateDurationEstimate() + |
407 client_->DrawDurationEstimate() + EstimatedParentDrawTime()); | 474 TimeForDrawing()); |
408 client_->SendBeginFramesToChildren(adjusted_args_for_children); | 475 client_->SendBeginFramesToChildren(adjusted_args_for_children); |
409 } | 476 } |
410 | 477 |
411 // We have just called SetNeedsBeginFrame(true) and the BeginFrameSource has | 478 // Start the ImplFrame |
412 // sent us the last BeginFrame we have missed. As we might not be able to | 479 client_->BeginImplFrame(args); |
413 // actually make rendering for this call, handle it like a "retro frame". | 480 |
414 // TODO(brainderson): Add a test for this functionality ASAP! | 481 // If we are asked to schedule a deadline in the past, just run the deadline |
415 if (args.type == BeginFrameArgs::MISSED) { | 482 // right now. |
416 begin_retro_frame_args_.push_back(args); | 483 if (now >= args.deadline) { |
417 PostBeginRetroFrameIfNeeded(); | 484 OnBeginImplFrameDeadline(); |
418 return true; | 485 return; |
419 } | 486 } |
420 | 487 |
421 BeginFrameArgs adjusted_args(args); | 488 // Else post a task for the deadline |
422 adjusted_args.deadline -= EstimatedParentDrawTime(); | |
423 | |
424 bool should_defer_begin_frame; | |
425 if (settings_.using_synchronous_renderer_compositor) { | |
426 should_defer_begin_frame = false; | |
427 } else { | |
428 should_defer_begin_frame = | |
429 !begin_retro_frame_args_.empty() || begin_retro_frame_posted_ || | |
430 !frame_source_->NeedsBeginFrames() || | |
431 (state_machine_.begin_impl_frame_state() != | |
432 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); | |
433 } | |
434 | |
435 if (should_defer_begin_frame) { | |
436 begin_retro_frame_args_.push_back(adjusted_args); | |
437 TRACE_EVENT_INSTANT0( | |
438 "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD); | |
439 // Queuing the frame counts as "using it", so we need to return true. | |
440 } else { | |
441 BeginImplFrame(adjusted_args); | |
442 } | |
443 return true; | |
444 } | |
445 | |
446 void Scheduler::SetChildrenNeedBeginFrames(bool children_need_begin_frames) { | |
447 DCHECK(settings_.forward_begin_frames_to_children); | |
448 state_machine_.SetChildrenNeedBeginFrames(children_need_begin_frames); | |
449 DCHECK_EQ(state_machine_.NextAction(), SchedulerStateMachine::ACTION_NONE); | |
450 } | |
451 | |
452 // BeginRetroFrame is called for BeginFrames that we've deferred because | |
453 // the scheduler was in the middle of processing a previous BeginFrame. | |
454 void Scheduler::BeginRetroFrame() { | |
455 TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame"); | |
456 DCHECK(!settings_.using_synchronous_renderer_compositor); | |
457 DCHECK(begin_retro_frame_posted_); | |
458 begin_retro_frame_posted_ = false; | |
459 | |
460 // If there aren't any retroactive BeginFrames, then we've lost the | |
461 // OutputSurface and should abort. | |
462 if (begin_retro_frame_args_.empty()) | |
463 return; | |
464 | |
465 // Discard expired BeginRetroFrames | |
466 // Today, we should always end up with at most one un-expired BeginRetroFrame | |
467 // because deadlines will not be greater than the next frame time. We don't | |
468 // DCHECK though because some systems don't always have monotonic timestamps. | |
469 // TODO(brianderson): In the future, long deadlines could result in us not | |
470 // draining the queue if we don't catch up. If we consistently can't catch | |
471 // up, our fallback should be to lower our frame rate. | |
472 base::TimeTicks now = Now(); | |
473 | |
474 while (!begin_retro_frame_args_.empty()) { | |
475 const BeginFrameArgs& args = begin_retro_frame_args_.front(); | |
476 base::TimeTicks expiration_time = args.frame_time + args.interval; | |
477 if (now <= expiration_time) | |
478 break; | |
479 TRACE_EVENT_INSTANT2( | |
480 "cc", "Scheduler::BeginRetroFrame discarding", TRACE_EVENT_SCOPE_THREAD, | |
481 "expiration_time - now", (expiration_time - now).InMillisecondsF(), | |
482 "BeginFrameArgs", begin_retro_frame_args_.front().AsValue()); | |
483 begin_retro_frame_args_.pop_front(); | |
484 frame_source_->DidFinishFrame(begin_retro_frame_args_.size()); | |
485 } | |
486 | |
487 if (begin_retro_frame_args_.empty()) { | |
488 TRACE_EVENT_INSTANT0("cc", | |
489 "Scheduler::BeginRetroFrames all expired", | |
490 TRACE_EVENT_SCOPE_THREAD); | |
491 } else { | |
492 BeginFrameArgs front = begin_retro_frame_args_.front(); | |
493 begin_retro_frame_args_.pop_front(); | |
494 BeginImplFrame(front); | |
495 } | |
496 } | |
497 | |
498 // There could be a race between the posted BeginRetroFrame and a new | |
499 // BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame | |
500 // will check if there is a pending BeginRetroFrame to ensure we handle | |
501 // BeginFrames in FIFO order. | |
502 void Scheduler::PostBeginRetroFrameIfNeeded() { | |
503 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), | |
504 "Scheduler::PostBeginRetroFrameIfNeeded", | |
505 "state", | |
506 AsValue()); | |
507 if (!frame_source_->NeedsBeginFrames()) | |
508 return; | |
509 | |
510 if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_) | |
511 return; | |
512 | |
513 // begin_retro_frame_args_ should always be empty for the | |
514 // synchronous compositor. | |
515 DCHECK(!settings_.using_synchronous_renderer_compositor); | |
516 | |
517 if (state_machine_.begin_impl_frame_state() != | |
518 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE) | |
519 return; | |
520 | |
521 begin_retro_frame_posted_ = true; | |
522 task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_); | |
523 } | |
524 | |
525 // BeginImplFrame starts a compositor frame that will wait up until a deadline | |
526 // for a BeginMainFrame+activation to complete before it times out and draws | |
527 // any asynchronous animation and scroll/pinch updates. | |
528 void Scheduler::BeginImplFrame(const BeginFrameArgs& args) { | |
529 bool main_thread_is_in_high_latency_mode = | |
530 state_machine_.MainThreadIsInHighLatencyMode(); | |
531 TRACE_EVENT2("cc", | |
532 "Scheduler::BeginImplFrame", | |
533 "args", | |
534 args.AsValue(), | |
535 "main_thread_is_high_latency", | |
536 main_thread_is_in_high_latency_mode); | |
537 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), | |
538 "MainThreadLatency", | |
539 main_thread_is_in_high_latency_mode); | |
540 DCHECK_EQ(state_machine_.begin_impl_frame_state(), | |
541 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); | |
542 DCHECK(state_machine_.HasInitializedOutputSurface()); | |
543 | |
544 advance_commit_state_task_.Cancel(); | |
545 | |
546 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); | |
547 begin_impl_frame_args_ = args; | |
548 begin_impl_frame_args_.deadline -= draw_duration_estimate; | |
549 | |
550 if (!state_machine_.impl_latency_takes_priority() && | |
551 main_thread_is_in_high_latency_mode && | |
552 CanCommitAndActivateBeforeDeadline()) { | |
553 state_machine_.SetSkipNextBeginMainFrameToReduceLatency(); | |
554 } | |
555 | |
556 client_->WillBeginImplFrame(begin_impl_frame_args_); | |
557 state_machine_.OnBeginImplFrame(begin_impl_frame_args_); | |
558 devtools_instrumentation::DidBeginFrame(layer_tree_host_id_); | |
559 | |
560 ProcessScheduledActions(); | |
561 | |
562 state_machine_.OnBeginImplFrameDeadlinePending(); | |
563 | |
564 if (settings_.using_synchronous_renderer_compositor) { | |
565 // The synchronous renderer compositor has to make its GL calls | |
566 // within this call. | |
567 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks | |
568 // so the synchronous renderer compositor can take advantage of splitting | |
569 // up the BeginImplFrame and deadline as well. | |
570 OnBeginImplFrameDeadline(); | |
571 } else { | |
572 ScheduleBeginImplFrameDeadline( | |
573 AdjustedBeginImplFrameDeadline(args, draw_duration_estimate)); | |
574 } | |
575 } | |
576 | |
577 base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline( | |
578 const BeginFrameArgs& args, | |
579 base::TimeDelta draw_duration_estimate) const { | |
580 // The synchronous compositor does not post a deadline task. | |
581 DCHECK(!settings_.using_synchronous_renderer_compositor); | |
582 if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) { | |
583 // We are ready to draw a new active tree immediately. | |
584 // We don't use Now() here because it's somewhat expensive to call. | |
585 return base::TimeTicks(); | |
586 } else if (state_machine_.needs_redraw()) { | |
587 // We have an animation or fast input path on the impl thread that wants | |
588 // to draw, so don't wait too long for a new active tree. | |
589 return args.deadline - draw_duration_estimate; | |
590 } else { | |
591 // The impl thread doesn't have anything it wants to draw and we are just | |
592 // waiting for a new active tree, so post the deadline for the next | |
593 // expected BeginImplFrame start. This allows us to draw immediately when | |
594 // there is a new active tree, instead of waiting for the next | |
595 // BeginImplFrame. | |
596 // TODO(brianderson): Handle long deadlines (that are past the next frame's | |
597 // frame time) properly instead of using this hack. | |
598 return args.frame_time + args.interval; | |
599 } | |
600 } | |
601 | |
602 void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) { | |
603 TRACE_EVENT1( | |
604 "cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline); | |
605 | |
606 begin_impl_frame_deadline_task_.Cancel(); | |
607 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); | |
608 | |
609 base::TimeDelta delta = deadline - Now(); | |
610 if (delta <= base::TimeDelta()) | |
611 delta = base::TimeDelta(); | |
612 task_runner_->PostDelayedTask( | 489 task_runner_->PostDelayedTask( |
613 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta); | 490 FROM_HERE, begin_impl_frame_deadline_task_.callback(), now - deadline); |
614 } | 491 } |
615 | 492 |
616 void Scheduler::OnBeginImplFrameDeadline() { | 493 void Scheduler::OnBeginImplFrameDeadline() { |
617 TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline"); | 494 TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline"); |
618 begin_impl_frame_deadline_task_.Cancel(); | 495 begin_impl_frame_deadline_task_.Cancel(); |
619 | 496 |
| 497 last_begin_impl_frame_args_ = current_begin_impl_frame_args_; |
| 498 |
620 // We split the deadline actions up into two phases so the state machine | 499 // We split the deadline actions up into two phases so the state machine |
621 // has a chance to trigger actions that should occur durring and after | 500 // has a chance to trigger actions that should occur during and after the |
622 // the deadline separately. For example: | 501 // deadline separately. For example: |
623 // * Sending the BeginMainFrame will not occur after the deadline in | 502 // * Sending the BeginMainFrame will not occur after the deadline in |
624 // order to wait for more user-input before starting the next commit. | 503 // order to wait for more user-input before starting the next commit. |
625 // * Creating a new OuputSurface will not occur during the deadline in | 504 // * Creating a new OuputSurface will not occur during the deadline in |
626 // order to allow the state machine to "settle" first. | 505 // order to allow the state machine to "settle" first. |
627 state_machine_.OnBeginImplFrameDeadline(); | 506 state_machine_.OnBeginImplFrameDeadline(); |
628 ProcessScheduledActions(); | 507 ProcessScheduledActions(); |
629 state_machine_.OnBeginImplFrameIdle(); | 508 state_machine_.OnBeginImplFrameIdle(); |
630 ProcessScheduledActions(); | 509 ProcessScheduledActions(); |
631 | 510 |
632 client_->DidBeginImplFrameDeadline(); | 511 client_->DidBeginImplFrameDeadline(); |
633 } | 512 } |
634 | 513 |
| 514 void Scheduler::DidActivateSyncTree() { |
| 515 // Main frame is committed and activated |
| 516 last_main_frame_args_ = current_main_frame_args_; |
| 517 current_main_frame_args_ = BeginFrameArgs(); |
| 518 } |
| 519 |
| 520 BeginFrameArgs Scheduler::GetBeginMainFrameArgs() { |
| 521 // Did the previous main frame meet the deadline? |
| 522 bool last_main_frame_meet_deadline = (last_main_frame_args_.frame_time == last
_impl_frame_args_.frame_time); |
| 523 |
| 524 BeginFrameArgs args(current_impl_frame_args_); |
| 525 // We aren't inside an active impl frame deadline, so we use the values of |
| 526 // the last impl frame. |
| 527 // TODO(mithro): This includes deadline adjustment for draw time which could |
| 528 // instead be given to the main frame. |
| 529 if (!args.is_valid()) { |
| 530 args = last_impl_frame_args_; |
| 531 } |
| 532 |
| 533 // Do we think the main frame can make the deadline? |
| 534 base::TimeDelta main_thread_time = |
| 535 client_->BeginMainFrameToCommitDurationEstimate() + |
| 536 client_->CommitToActivateDurationEstimate(); |
| 537 if (now + main_thread_time <= args.deadline) { |
| 538 // If we think the BeginMainFrame will make the deadline, we should |
| 539 // definitely go ahead. |
| 540 return args; |
| 541 } |
| 542 |
| 543 base::TimeDelta will_missed_deadline_by = now + main_thread_time - args.deadli
ne; |
| 544 |
| 545 /* |
| 546 // If we think the BeginMainFrame will only miss by a little and we made the |
| 547 // last deadline, we are going to give it a go and see if we actually miss. |
| 548 // This exists because our estimates are rough and there is jitter in the |
| 549 // system. |
| 550 bool close_deadline_miss = (will_missed_deadline_by / base::TimeDelta::FromMil
liseconds(1)) == 0; |
| 551 if (last_main_frame_meet_deadline && close_deadline_miss) { |
| 552 return args; |
| 553 } |
| 554 */ |
| 555 |
| 556 // Otherwise, we don't think the BeginMainFrame will make the deadline and |
| 557 // have already missed the last frame. What we do depends on if we think |
| 558 // sending a BeginMainFrame now will effect the next frame's ability to meet |
| 559 // the deadline. |
| 560 |
| 561 // Work out what percentage of an normal interval the main thread rendering |
| 562 // will take. |
| 563 base::TimeDelta time_for_rendering = args.interval - (EstimatedParentDrawTime(
) + client_->DrawDurationEstimate()); |
| 564 double main_percentage_of_rendering_time = main_thread_time.InMillisecondsF()
/ time_for_rendering.InMillisecondsF(); |
| 565 |
| 566 if (main_percentage_of_rendering_time < 0.5) { |
| 567 // As the main thread can render twice a frame, starting rendering is |
| 568 // unlikely to cause us to miss the next frame. Let's try and catch the |
| 569 // main thread up to the impl thread to help with latency. |
| 570 // We keep the expired deadline so main thread knows it not to run any |
| 571 // unimportant tasks. It will have time after we catch back up. |
| 572 return args; |
| 573 } |
| 574 |
| 575 if (main_percentage_of_rendering_time > 1.0) { |
| 576 // Values greater than 1.0 mean the main thread will never make a normal |
| 577 // deadline. |
| 578 |
| 579 // If we could meet 50% of the interval, then we assume that we will do |
| 580 // that and start rendering ASAP. |
| 581 if (main_percentage_of_rendering_time < 2.0) { |
| 582 // Adjust the deadline to the next deadline we think the main thread will |
| 583 // probably make. |
| 584 while (args.deadline + time_for_rendering >= now) { |
| 585 args.deadline += args.interval; |
| 586 } |
| 587 return args; |
| 588 } |
| 589 |
| 590 // If the main thread isn't even going to make 50% frame rate, just target |
| 591 // throughput and render as fast as we can. We clear the deadline to inform |
| 592 // the main thread that we are targeting throughput and want to minimize |
| 593 // context switches. |
| 594 args.deadline = base::TimeTicks(); |
| 595 return args; |
| 596 } |
| 597 |
| 598 // If main_percentage_of_rendering_time is between 0.5 and 1.0, then if we |
| 599 // start rendering too late it will break the next frame too. However, we |
| 600 // have to be careful we don't drop *every* main frame on the floor. |
| 601 |
| 602 // If we are missing the deadline by the "slack" in the next frame, then we |
| 603 // should go ahead. |
| 604 base::TimeDelta slack_in_next_frame = time_for_rendering - main_thread_time; |
| 605 if (will_miss_deadline_by < slack_in_next_frame) { |
| 606 // We don't adjust the deadline because we want this main frame to return |
| 607 // as early as possible to give the next main frame as much chance as |
| 608 // possible. |
| 609 return args; |
| 610 } |
| 611 |
| 612 if (last_main_frame_meet_deadline == DROPPED) { |
| 613 // Drop this main frame to allow the next main frame to start as soon as |
| 614 // the BeginFrame message occurs. |
| 615 return args; |
| 616 } else { |
| 617 return BeginFrameArgs(); |
| 618 } |
| 619 } |
| 620 |
| 621 void Scheduler::SetChildrenNeedBeginFrames(bool children_need_begin_frames) { |
| 622 DCHECK(settings_.forward_begin_frames_to_children); |
| 623 state_machine_.SetChildrenNeedBeginFrames(children_need_begin_frames); |
| 624 DCHECK_EQ(state_machine_.NextAction(), SchedulerStateMachine::ACTION_NONE); |
| 625 } |
| 626 |
| 627 |
635 void Scheduler::PollForAnticipatedDrawTriggers() { | 628 void Scheduler::PollForAnticipatedDrawTriggers() { |
636 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers"); | 629 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers"); |
637 poll_for_draw_triggers_task_.Cancel(); | 630 poll_for_draw_triggers_task_.Cancel(); |
638 state_machine_.DidEnterPollForAnticipatedDrawTriggers(); | 631 state_machine_.DidEnterPollForAnticipatedDrawTriggers(); |
639 ProcessScheduledActions(); | 632 ProcessScheduledActions(); |
640 state_machine_.DidLeavePollForAnticipatedDrawTriggers(); | 633 state_machine_.DidLeavePollForAnticipatedDrawTriggers(); |
641 } | 634 } |
642 | 635 |
643 void Scheduler::PollToAdvanceCommitState() { | 636 void Scheduler::PollToAdvanceCommitState() { |
644 TRACE_EVENT0("cc", "Scheduler::PollToAdvanceCommitState"); | 637 TRACE_EVENT0("cc", "Scheduler::PollToAdvanceCommitState"); |
(...skipping 27 matching lines...) Expand all Loading... |
672 state_machine_.UpdateState(action); | 665 state_machine_.UpdateState(action); |
673 base::AutoReset<SchedulerStateMachine::Action> | 666 base::AutoReset<SchedulerStateMachine::Action> |
674 mark_inside_action(&inside_action_, action); | 667 mark_inside_action(&inside_action_, action); |
675 switch (action) { | 668 switch (action) { |
676 case SchedulerStateMachine::ACTION_NONE: | 669 case SchedulerStateMachine::ACTION_NONE: |
677 break; | 670 break; |
678 case SchedulerStateMachine::ACTION_ANIMATE: | 671 case SchedulerStateMachine::ACTION_ANIMATE: |
679 client_->ScheduledActionAnimate(); | 672 client_->ScheduledActionAnimate(); |
680 break; | 673 break; |
681 case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME: | 674 case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME: |
| 675 |
| 676 // FIXME:!!!!!!! |
| 677 BeginFrameArgs args = GetBeginMainFrameArgs(); |
| 678 if (!args.IsValid()) |
| 679 continue; |
| 680 current_main_frame_args_ = args; |
| 681 // FIXME:!!!!!!! |
| 682 |
682 client_->ScheduledActionSendBeginMainFrame(); | 683 client_->ScheduledActionSendBeginMainFrame(); |
683 break; | 684 break; |
684 case SchedulerStateMachine::ACTION_COMMIT: | 685 case SchedulerStateMachine::ACTION_COMMIT: |
685 client_->ScheduledActionCommit(); | 686 client_->ScheduledActionCommit(); |
686 break; | 687 break; |
687 case SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE: | 688 case SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE: |
688 client_->ScheduledActionActivateSyncTree(); | 689 client_->ScheduledActionActivateSyncTree(); |
689 break; | 690 break; |
690 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: | 691 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: |
691 DrawAndSwapIfPossible(); | 692 DrawAndSwapIfPossible(); |
692 break; | 693 break; |
693 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: | 694 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: |
694 client_->ScheduledActionDrawAndSwapForced(); | 695 client_->ScheduledActionDrawAndSwapForced(); |
695 break; | 696 break; |
696 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: | 697 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: |
697 // No action is actually performed, but this allows the state machine to | 698 // No action is actually performed, but this allows the state machine to |
698 // advance out of its waiting to draw state without actually drawing. | 699 // advance out of its waiting to draw state without actually drawing. |
699 break; | 700 break; |
700 case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION: | 701 case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION: |
701 client_->ScheduledActionBeginOutputSurfaceCreation(); | 702 client_->ScheduledActionBeginOutputSurfaceCreation(); |
702 break; | 703 break; |
703 case SchedulerStateMachine::ACTION_MANAGE_TILES: | 704 case SchedulerStateMachine::ACTION_MANAGE_TILES: |
704 client_->ScheduledActionManageTiles(); | 705 client_->ScheduledActionManageTiles(); |
705 break; | 706 break; |
706 } | 707 } |
707 } while (action != SchedulerStateMachine::ACTION_NONE); | 708 } while (action != SchedulerStateMachine::ACTION_NONE); |
708 | 709 |
709 SetupNextBeginFrameIfNeeded(); | 710 SetupNextBeginFrameIfNeeded(); |
710 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); | |
711 | |
712 if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) { | 711 if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) { |
713 DCHECK(!settings_.using_synchronous_renderer_compositor); | 712 DCHECK(!settings_.using_synchronous_renderer_compositor); |
714 ScheduleBeginImplFrameDeadline(base::TimeTicks()); | 713 OnBeginImplFrameDeadline(); |
715 } | 714 } |
716 } | 715 } |
717 | 716 |
718 bool Scheduler::WillDrawIfNeeded() const { | 717 bool Scheduler::WillDrawIfNeeded() const { |
719 return !state_machine_.PendingDrawsShouldBeAborted(); | 718 return !state_machine_.PendingDrawsShouldBeAborted(); |
720 } | 719 } |
721 | 720 |
722 scoped_refptr<base::debug::ConvertableToTraceFormat> Scheduler::AsValue() | 721 scoped_refptr<base::debug::ConvertableToTraceFormat> Scheduler::AsValue() |
723 const { | 722 const { |
724 scoped_refptr<base::debug::TracedValue> state = | 723 scoped_refptr<base::debug::TracedValue> state = |
(...skipping 18 matching lines...) Expand all Loading... |
743 state->EndDictionary(); | 742 state->EndDictionary(); |
744 } | 743 } |
745 | 744 |
746 state->BeginDictionary("scheduler_state"); | 745 state->BeginDictionary("scheduler_state"); |
747 state->SetDouble("time_until_anticipated_draw_time_ms", | 746 state->SetDouble("time_until_anticipated_draw_time_ms", |
748 (AnticipatedDrawTime() - Now()).InMillisecondsF()); | 747 (AnticipatedDrawTime() - Now()).InMillisecondsF()); |
749 state->SetDouble("estimated_parent_draw_time_ms", | 748 state->SetDouble("estimated_parent_draw_time_ms", |
750 estimated_parent_draw_time_.InMillisecondsF()); | 749 estimated_parent_draw_time_.InMillisecondsF()); |
751 state->SetBoolean("last_set_needs_begin_frame_", | 750 state->SetBoolean("last_set_needs_begin_frame_", |
752 frame_source_->NeedsBeginFrames()); | 751 frame_source_->NeedsBeginFrames()); |
753 state->SetBoolean("begin_retro_frame_posted_", begin_retro_frame_posted_); | 752 state->SetBoolean("begin_frame_process_posted_", begin_frame_process_posted_); |
754 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size()); | 753 state->SetInteger("pending_begin_frame_args_", pending_begin_frame_args_.size(
)); |
755 state->SetBoolean("begin_impl_frame_deadline_task_", | 754 state->SetBoolean("begin_impl_frame_deadline_task_", |
756 !begin_impl_frame_deadline_task_.IsCancelled()); | 755 !begin_impl_frame_deadline_task_.IsCancelled()); |
757 state->SetBoolean("poll_for_draw_triggers_task_", | 756 state->SetBoolean("poll_for_draw_triggers_task_", |
758 !poll_for_draw_triggers_task_.IsCancelled()); | 757 !poll_for_draw_triggers_task_.IsCancelled()); |
759 state->SetBoolean("advance_commit_state_task_", | 758 state->SetBoolean("advance_commit_state_task_", |
760 !advance_commit_state_task_.IsCancelled()); | 759 !advance_commit_state_task_.IsCancelled()); |
761 state->BeginDictionary("begin_impl_frame_args"); | 760 state->BeginDictionary("begin_impl_frame_args"); |
762 begin_impl_frame_args_.AsValueInto(state); | 761 begin_impl_frame_args_.AsValueInto(state); |
763 state->EndDictionary(); | 762 state->EndDictionary(); |
764 | 763 |
765 state->EndDictionary(); | 764 state->EndDictionary(); |
766 | 765 |
767 state->BeginDictionary("client_state"); | 766 state->BeginDictionary("client_state"); |
768 state->SetDouble("draw_duration_estimate_ms", | 767 state->SetDouble("draw_duration_estimate_ms", |
769 client_->DrawDurationEstimate().InMillisecondsF()); | 768 client_->DrawDurationEstimate().InMillisecondsF()); |
770 state->SetDouble( | 769 state->SetDouble( |
771 "begin_main_frame_to_commit_duration_estimate_ms", | 770 "begin_main_frame_to_commit_duration_estimate_ms", |
772 client_->BeginMainFrameToCommitDurationEstimate().InMillisecondsF()); | 771 client_->BeginMainFrameToCommitDurationEstimate().InMillisecondsF()); |
773 state->SetDouble( | 772 state->SetDouble( |
774 "commit_to_activate_duration_estimate_ms", | 773 "commit_to_activate_duration_estimate_ms", |
775 client_->CommitToActivateDurationEstimate().InMillisecondsF()); | 774 client_->CommitToActivateDurationEstimate().InMillisecondsF()); |
776 state->EndDictionary(); | 775 state->EndDictionary(); |
777 } | 776 } |
778 | 777 |
779 bool Scheduler::CanCommitAndActivateBeforeDeadline() const { | |
780 // Check if the main thread computation and commit can be finished before the | |
781 // impl thread's deadline. | |
782 base::TimeTicks estimated_draw_time = | |
783 begin_impl_frame_args_.frame_time + | |
784 client_->BeginMainFrameToCommitDurationEstimate() + | |
785 client_->CommitToActivateDurationEstimate(); | |
786 | |
787 TRACE_EVENT2( | |
788 TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), | |
789 "CanCommitAndActivateBeforeDeadline", | |
790 "time_left_after_drawing_ms", | |
791 (begin_impl_frame_args_.deadline - estimated_draw_time).InMillisecondsF(), | |
792 "state", | |
793 AsValue()); | |
794 | |
795 return estimated_draw_time < begin_impl_frame_args_.deadline; | |
796 } | |
797 | |
798 bool Scheduler::IsBeginMainFrameSentOrStarted() const { | 778 bool Scheduler::IsBeginMainFrameSentOrStarted() const { |
799 return (state_machine_.commit_state() == | 779 return (state_machine_.commit_state() == |
800 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || | 780 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || |
801 state_machine_.commit_state() == | 781 state_machine_.commit_state() == |
802 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); | 782 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); |
803 } | 783 } |
804 | 784 |
805 } // namespace cc | 785 } // namespace cc |
OLD | NEW |