| 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/debug/trace_event_argument.h" | 10 #include "base/debug/trace_event_argument.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/single_thread_task_runner.h" | 12 #include "base/single_thread_task_runner.h" |
| 13 #include "cc/debug/devtools_instrumentation.h" | 13 #include "cc/debug/devtools_instrumentation.h" |
| 14 #include "cc/debug/traced_value.h" | 14 #include "cc/debug/traced_value.h" |
| 15 #include "cc/scheduler/delay_based_time_source.h" | 15 #include "cc/scheduler/delay_based_time_source.h" |
| 16 #include "ui/gfx/frame_time.h" | 16 #include "ui/gfx/frame_time.h" |
| 17 | 17 |
| 18 namespace cc { | 18 namespace cc { |
| 19 | 19 |
| 20 Scheduler::SyntheticBeginFrameSource::SyntheticBeginFrameSource( | 20 BeginFrameSource* SchedulerFrameSourcesConstructor::ConstructPrimaryFrameSource( |
| 21 Scheduler* scheduler, | 21 Scheduler* scheduler) { |
| 22 scoped_refptr<DelayBasedTimeSource> time_source) | 22 if (!scheduler->settings_.throttle_frame_production) { |
| 23 : scheduler_(scheduler), time_source_(time_source) { | 23 TRACE_EVENT1("cc", |
| 24 time_source_->SetClient(this); | 24 "Scheduler::Scheduler()", |
| 25 } | 25 "PrimaryFrameSource", |
| 26 "BackToBackBeginFrameSource"); |
| 27 DCHECK(!scheduler->primary_frame_source_internal_); |
| 28 scheduler->primary_frame_source_internal_ = |
| 29 BackToBackBeginFrameSource::Create(scheduler->task_runner_.get()); |
| 30 return scheduler->primary_frame_source_internal_.get(); |
| 31 } else if (scheduler->settings_.begin_frame_scheduling_enabled) { |
| 32 TRACE_EVENT1("cc", |
| 33 "Scheduler::Scheduler()", |
| 34 "PrimaryFrameSource", |
| 35 "SchedulerClient"); |
| 36 return scheduler->client_->ExternalBeginFrameSource(); |
| 37 } else { |
| 38 TRACE_EVENT1("cc", |
| 39 "Scheduler::Scheduler()", |
| 40 "PrimaryFrameSource", |
| 41 "SyntheticBeginFrameSource"); |
| 42 scoped_ptr<SyntheticBeginFrameSource> synthetic_source = |
| 43 SyntheticBeginFrameSource::Create(scheduler->task_runner_.get(), |
| 44 scheduler->Now(), |
| 45 BeginFrameArgs::DefaultInterval()); |
| 26 | 46 |
| 27 Scheduler::SyntheticBeginFrameSource::~SyntheticBeginFrameSource() { | 47 DCHECK(!scheduler->vsync_observer_); |
| 28 } | 48 scheduler->vsync_observer_ = synthetic_source.get(); |
| 29 | 49 |
| 30 void Scheduler::SyntheticBeginFrameSource::CommitVSyncParameters( | 50 DCHECK(!scheduler->primary_frame_source_internal_); |
| 31 base::TimeTicks timebase, | 51 scheduler->primary_frame_source_internal_ = synthetic_source.Pass(); |
| 32 base::TimeDelta interval) { | 52 return scheduler->primary_frame_source_internal_.get(); |
| 33 time_source_->SetTimebaseAndInterval(timebase, interval); | |
| 34 } | |
| 35 | |
| 36 void Scheduler::SyntheticBeginFrameSource::SetNeedsBeginFrame( | |
| 37 bool needs_begin_frame, | |
| 38 std::deque<BeginFrameArgs>* begin_retro_frame_args) { | |
| 39 DCHECK(begin_retro_frame_args); | |
| 40 base::TimeTicks missed_tick_time = | |
| 41 time_source_->SetActive(needs_begin_frame); | |
| 42 if (!missed_tick_time.is_null()) { | |
| 43 begin_retro_frame_args->push_back( | |
| 44 CreateSyntheticBeginFrameArgs(missed_tick_time)); | |
| 45 } | 53 } |
| 46 } | 54 } |
| 47 | 55 |
| 48 bool Scheduler::SyntheticBeginFrameSource::IsActive() const { | 56 BeginFrameSource* |
| 49 return time_source_->Active(); | 57 SchedulerFrameSourcesConstructor::ConstructBackgroundFrameSource( |
| 50 } | 58 Scheduler* scheduler) { |
| 51 | 59 TRACE_EVENT1("cc", |
| 52 void Scheduler::SyntheticBeginFrameSource::OnTimerTick() { | 60 "Scheduler::Scheduler()", |
| 53 BeginFrameArgs begin_frame_args( | 61 "BackgroundFrameSource", |
| 54 CreateSyntheticBeginFrameArgs(time_source_->LastTickTime())); | 62 "SyntheticBeginFrameSource"); |
| 55 scheduler_->BeginFrame(begin_frame_args); | 63 DCHECK(!(scheduler->background_frame_source_internal_)); |
| 56 } | 64 scheduler->background_frame_source_internal_ = |
| 57 | 65 SyntheticBeginFrameSource::Create(scheduler->task_runner_.get(), |
| 58 void Scheduler::SyntheticBeginFrameSource::AsValueInto( | 66 scheduler->Now(), |
| 59 base::debug::TracedValue* state) const { | 67 base::TimeDelta::FromSeconds(1)); |
| 60 time_source_->AsValueInto(state); | 68 return scheduler->background_frame_source_internal_.get(); |
| 61 } | |
| 62 | |
| 63 BeginFrameArgs | |
| 64 Scheduler::SyntheticBeginFrameSource::CreateSyntheticBeginFrameArgs( | |
| 65 base::TimeTicks frame_time) { | |
| 66 base::TimeTicks deadline = time_source_->NextTickTime(); | |
| 67 return BeginFrameArgs::Create( | |
| 68 frame_time, deadline, scheduler_->VSyncInterval()); | |
| 69 } | 69 } |
| 70 | 70 |
| 71 Scheduler::Scheduler( | 71 Scheduler::Scheduler( |
| 72 SchedulerClient* client, | 72 SchedulerClient* client, |
| 73 const SchedulerSettings& scheduler_settings, | 73 const SchedulerSettings& scheduler_settings, |
| 74 int layer_tree_host_id, | 74 int layer_tree_host_id, |
| 75 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) | 75 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
| 76 : settings_(scheduler_settings), | 76 SchedulerFrameSourcesConstructor* frame_sources_constructor) |
| 77 : frame_source_(), |
| 78 primary_frame_source_(NULL), |
| 79 background_frame_source_(NULL), |
| 80 primary_frame_source_internal_(), |
| 81 background_frame_source_internal_(), |
| 82 vsync_observer_(NULL), |
| 83 settings_(scheduler_settings), |
| 77 client_(client), | 84 client_(client), |
| 78 layer_tree_host_id_(layer_tree_host_id), | 85 layer_tree_host_id_(layer_tree_host_id), |
| 79 task_runner_(task_runner), | 86 task_runner_(task_runner), |
| 80 vsync_interval_(BeginFrameArgs::DefaultInterval()), | |
| 81 last_set_needs_begin_frame_(false), | |
| 82 begin_unthrottled_frame_posted_(false), | |
| 83 begin_retro_frame_posted_(false), | 87 begin_retro_frame_posted_(false), |
| 84 state_machine_(scheduler_settings), | 88 state_machine_(scheduler_settings), |
| 85 inside_process_scheduled_actions_(false), | 89 inside_process_scheduled_actions_(false), |
| 86 inside_action_(SchedulerStateMachine::ACTION_NONE), | 90 inside_action_(SchedulerStateMachine::ACTION_NONE), |
| 87 weak_factory_(this) { | 91 weak_factory_(this) { |
| 88 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), | 92 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), |
| 89 "Scheduler::Scheduler", | 93 "Scheduler::Scheduler", |
| 90 "settings", | 94 "settings", |
| 91 settings_.AsValue()); | 95 settings_.AsValue()); |
| 92 DCHECK(client_); | 96 DCHECK(client_); |
| 93 DCHECK(!state_machine_.BeginFrameNeeded()); | 97 DCHECK(!state_machine_.BeginFrameNeeded()); |
| 94 if (settings_.main_frame_before_activation_enabled) { | 98 if (settings_.main_frame_before_activation_enabled) { |
| 95 DCHECK(settings_.main_frame_before_draw_enabled); | 99 DCHECK(settings_.main_frame_before_draw_enabled); |
| 96 } | 100 } |
| 97 | 101 |
| 98 begin_retro_frame_closure_ = | 102 begin_retro_frame_closure_ = |
| 99 base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr()); | 103 base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr()); |
| 100 begin_unthrottled_frame_closure_ = | |
| 101 base::Bind(&Scheduler::BeginUnthrottledFrame, weak_factory_.GetWeakPtr()); | |
| 102 begin_impl_frame_deadline_closure_ = base::Bind( | 104 begin_impl_frame_deadline_closure_ = base::Bind( |
| 103 &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr()); | 105 &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr()); |
| 104 poll_for_draw_triggers_closure_ = base::Bind( | 106 poll_for_draw_triggers_closure_ = base::Bind( |
| 105 &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr()); | 107 &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr()); |
| 106 advance_commit_state_closure_ = base::Bind( | 108 advance_commit_state_closure_ = base::Bind( |
| 107 &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr()); | 109 &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr()); |
| 108 | 110 |
| 109 if (!settings_.begin_frame_scheduling_enabled) { | 111 frame_source_ = BeginFrameSourceMultiplexer::Create(); |
| 110 SetupSyntheticBeginFrames(); | 112 frame_source_->AddObserver(this); |
| 111 } | 113 |
| 114 // Primary frame source |
| 115 primary_frame_source_ = |
| 116 frame_sources_constructor->ConstructPrimaryFrameSource(this); |
| 117 frame_source_->AddSource(primary_frame_source_); |
| 118 |
| 119 // Background ticking frame source |
| 120 background_frame_source_ = |
| 121 frame_sources_constructor->ConstructBackgroundFrameSource(this); |
| 122 frame_source_->AddSource(background_frame_source_); |
| 112 } | 123 } |
| 113 | 124 |
| 114 Scheduler::~Scheduler() { | 125 Scheduler::~Scheduler() { |
| 115 if (synthetic_begin_frame_source_) { | |
| 116 synthetic_begin_frame_source_->SetNeedsBeginFrame(false, | |
| 117 &begin_retro_frame_args_); | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 void Scheduler::SetupSyntheticBeginFrames() { | |
| 122 scoped_refptr<DelayBasedTimeSource> time_source; | |
| 123 if (gfx::FrameTime::TimestampsAreHighRes()) { | |
| 124 time_source = DelayBasedTimeSourceHighRes::Create(VSyncInterval(), | |
| 125 task_runner_.get()); | |
| 126 } else { | |
| 127 time_source = | |
| 128 DelayBasedTimeSource::Create(VSyncInterval(), task_runner_.get()); | |
| 129 } | |
| 130 DCHECK(!synthetic_begin_frame_source_); | |
| 131 synthetic_begin_frame_source_.reset( | |
| 132 new SyntheticBeginFrameSource(this, time_source)); | |
| 133 } | 126 } |
| 134 | 127 |
| 135 base::TimeTicks Scheduler::Now() const { | 128 base::TimeTicks Scheduler::Now() const { |
| 136 return gfx::FrameTime::Now(); | 129 base::TimeTicks now = gfx::FrameTime::Now(); |
| 130 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.now"), |
| 131 "Scheduler::Now", |
| 132 "now", |
| 133 now); |
| 134 return now; |
| 137 } | 135 } |
| 138 | 136 |
| 139 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, | 137 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, |
| 140 base::TimeDelta interval) { | 138 base::TimeDelta interval) { |
| 141 // TODO(brianderson): We should not be receiving 0 intervals. | 139 // TODO(brianderson): We should not be receiving 0 intervals. |
| 142 if (interval == base::TimeDelta()) | 140 if (interval == base::TimeDelta()) |
| 143 interval = BeginFrameArgs::DefaultInterval(); | 141 interval = BeginFrameArgs::DefaultInterval(); |
| 144 vsync_interval_ = interval; | 142 |
| 145 if (!settings_.begin_frame_scheduling_enabled) | 143 if (vsync_observer_) |
| 146 synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval); | 144 vsync_observer_->OnUpdateVSyncParameters(timebase, interval); |
| 147 } | 145 } |
| 148 | 146 |
| 149 void Scheduler::SetEstimatedParentDrawTime(base::TimeDelta draw_time) { | 147 void Scheduler::SetEstimatedParentDrawTime(base::TimeDelta draw_time) { |
| 150 DCHECK_GE(draw_time.ToInternalValue(), 0); | 148 DCHECK_GE(draw_time.ToInternalValue(), 0); |
| 151 estimated_parent_draw_time_ = draw_time; | 149 estimated_parent_draw_time_ = draw_time; |
| 152 } | 150 } |
| 153 | 151 |
| 154 void Scheduler::SetCanStart() { | 152 void Scheduler::SetCanStart() { |
| 155 state_machine_.SetCanStart(); | 153 state_machine_.SetCanStart(); |
| 156 ProcessScheduledActions(); | 154 ProcessScheduledActions(); |
| 157 } | 155 } |
| 158 | 156 |
| 159 void Scheduler::SetVisible(bool visible) { | 157 void Scheduler::SetVisible(bool visible) { |
| 160 state_machine_.SetVisible(visible); | 158 state_machine_.SetVisible(visible); |
| 159 if (visible) { |
| 160 frame_source_->SetActiveSource(primary_frame_source_); |
| 161 } else { |
| 162 frame_source_->SetActiveSource(background_frame_source_); |
| 163 } |
| 161 ProcessScheduledActions(); | 164 ProcessScheduledActions(); |
| 162 } | 165 } |
| 163 | 166 |
| 164 void Scheduler::SetCanDraw(bool can_draw) { | 167 void Scheduler::SetCanDraw(bool can_draw) { |
| 165 state_machine_.SetCanDraw(can_draw); | 168 state_machine_.SetCanDraw(can_draw); |
| 166 ProcessScheduledActions(); | 169 ProcessScheduledActions(); |
| 167 } | 170 } |
| 168 | 171 |
| 169 void Scheduler::NotifyReadyToActivate() { | 172 void Scheduler::NotifyReadyToActivate() { |
| 170 state_machine_.NotifyReadyToActivate(); | 173 state_machine_.NotifyReadyToActivate(); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 233 ProcessScheduledActions(); | 236 ProcessScheduledActions(); |
| 234 } | 237 } |
| 235 | 238 |
| 236 void Scheduler::DidManageTiles() { | 239 void Scheduler::DidManageTiles() { |
| 237 state_machine_.DidManageTiles(); | 240 state_machine_.DidManageTiles(); |
| 238 } | 241 } |
| 239 | 242 |
| 240 void Scheduler::DidLoseOutputSurface() { | 243 void Scheduler::DidLoseOutputSurface() { |
| 241 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); | 244 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); |
| 242 state_machine_.DidLoseOutputSurface(); | 245 state_machine_.DidLoseOutputSurface(); |
| 243 last_set_needs_begin_frame_ = false; | 246 if (frame_source_->NeedsBeginFrames()) |
| 244 if (!settings_.begin_frame_scheduling_enabled) { | 247 frame_source_->SetNeedsBeginFrames(false); |
| 245 synthetic_begin_frame_source_->SetNeedsBeginFrame(false, | |
| 246 &begin_retro_frame_args_); | |
| 247 } | |
| 248 begin_retro_frame_args_.clear(); | 248 begin_retro_frame_args_.clear(); |
| 249 ProcessScheduledActions(); | 249 ProcessScheduledActions(); |
| 250 } | 250 } |
| 251 | 251 |
| 252 void Scheduler::DidCreateAndInitializeOutputSurface() { | 252 void Scheduler::DidCreateAndInitializeOutputSurface() { |
| 253 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); | 253 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); |
| 254 DCHECK(!last_set_needs_begin_frame_); | 254 DCHECK(!frame_source_->NeedsBeginFrames()); |
| 255 DCHECK(begin_impl_frame_deadline_task_.IsCancelled()); | 255 DCHECK(begin_impl_frame_deadline_task_.IsCancelled()); |
| 256 state_machine_.DidCreateAndInitializeOutputSurface(); | 256 state_machine_.DidCreateAndInitializeOutputSurface(); |
| 257 ProcessScheduledActions(); | 257 ProcessScheduledActions(); |
| 258 } | 258 } |
| 259 | 259 |
| 260 void Scheduler::NotifyBeginMainFrameStarted() { | 260 void Scheduler::NotifyBeginMainFrameStarted() { |
| 261 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted"); | 261 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted"); |
| 262 state_machine_.NotifyBeginMainFrameStarted(); | 262 state_machine_.NotifyBeginMainFrameStarted(); |
| 263 } | 263 } |
| 264 | 264 |
| 265 base::TimeTicks Scheduler::AnticipatedDrawTime() const { | 265 base::TimeTicks Scheduler::AnticipatedDrawTime() const { |
| 266 if (!last_set_needs_begin_frame_ || | 266 if (!frame_source_->NeedsBeginFrames() || |
| 267 begin_impl_frame_args_.interval <= base::TimeDelta()) | 267 begin_impl_frame_args_.interval <= base::TimeDelta()) |
| 268 return base::TimeTicks(); | 268 return base::TimeTicks(); |
| 269 | 269 |
| 270 base::TimeTicks now = Now(); | 270 base::TimeTicks now = Now(); |
| 271 base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time, | 271 base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time, |
| 272 begin_impl_frame_args_.deadline); | 272 begin_impl_frame_args_.deadline); |
| 273 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval); | 273 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval); |
| 274 return timebase + (begin_impl_frame_args_.interval * intervals); | 274 return timebase + (begin_impl_frame_args_.interval * intervals); |
| 275 } | 275 } |
| 276 | 276 |
| 277 base::TimeTicks Scheduler::LastBeginImplFrameTime() { | 277 base::TimeTicks Scheduler::LastBeginImplFrameTime() { |
| 278 return begin_impl_frame_args_.frame_time; | 278 return begin_impl_frame_args_.frame_time; |
| 279 } | 279 } |
| 280 | 280 |
| 281 void Scheduler::SetupNextBeginFrameIfNeeded() { | 281 void Scheduler::SetupNextBeginFrameIfNeeded() { |
| 282 if (!task_runner_.get()) | 282 if (!task_runner_.get()) |
| 283 return; | 283 return; |
| 284 | 284 |
| 285 bool needs_begin_frame = state_machine_.BeginFrameNeeded(); | 285 bool needs_begin_frame = state_machine_.BeginFrameNeeded(); |
| 286 | 286 |
| 287 if (settings_.throttle_frame_production) { | 287 bool at_end_of_deadline = |
| 288 SetupNextBeginFrameWhenVSyncThrottlingEnabled(needs_begin_frame); | 288 (state_machine_.begin_impl_frame_state() == |
| 289 } else { | 289 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE); |
| 290 SetupNextBeginFrameWhenVSyncThrottlingDisabled(needs_begin_frame); | 290 |
| 291 bool should_call_set_needs_begin_frame = |
| 292 // Always request the BeginFrame immediately if it wasn't needed before. |
| 293 (needs_begin_frame && !frame_source_->NeedsBeginFrames()) || |
| 294 // Only stop requesting BeginFrames after a deadline. |
| 295 (!needs_begin_frame && frame_source_->NeedsBeginFrames() && |
| 296 at_end_of_deadline); |
| 297 |
| 298 if (should_call_set_needs_begin_frame) { |
| 299 frame_source_->SetNeedsBeginFrames(needs_begin_frame); |
| 291 } | 300 } |
| 301 |
| 302 if (at_end_of_deadline) { |
| 303 frame_source_->DidFinishFrame(begin_retro_frame_args_.size()); |
| 304 } |
| 305 |
| 306 PostBeginRetroFrameIfNeeded(); |
| 292 SetupPollingMechanisms(needs_begin_frame); | 307 SetupPollingMechanisms(needs_begin_frame); |
| 293 } | 308 } |
| 294 | 309 |
| 295 // When we are throttling frame production, we request BeginFrames | |
| 296 // from the OutputSurface. | |
| 297 void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingEnabled( | |
| 298 bool needs_begin_frame) { | |
| 299 bool at_end_of_deadline = | |
| 300 state_machine_.begin_impl_frame_state() == | |
| 301 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE; | |
| 302 | |
| 303 bool should_call_set_needs_begin_frame = | |
| 304 // Always request the BeginFrame immediately if it wasn't needed before. | |
| 305 (needs_begin_frame && !last_set_needs_begin_frame_) || | |
| 306 // Only stop requesting BeginFrames after a deadline. | |
| 307 (!needs_begin_frame && last_set_needs_begin_frame_ && at_end_of_deadline); | |
| 308 | |
| 309 if (should_call_set_needs_begin_frame) { | |
| 310 if (settings_.begin_frame_scheduling_enabled) { | |
| 311 client_->SetNeedsBeginFrame(needs_begin_frame); | |
| 312 } else { | |
| 313 synthetic_begin_frame_source_->SetNeedsBeginFrame( | |
| 314 needs_begin_frame, &begin_retro_frame_args_); | |
| 315 } | |
| 316 last_set_needs_begin_frame_ = needs_begin_frame; | |
| 317 } | |
| 318 | |
| 319 PostBeginRetroFrameIfNeeded(); | |
| 320 } | |
| 321 | |
| 322 // When we aren't throttling frame production, we initiate a BeginFrame | |
| 323 // as soon as one is needed. | |
| 324 void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingDisabled( | |
| 325 bool needs_begin_frame) { | |
| 326 last_set_needs_begin_frame_ = needs_begin_frame; | |
| 327 | |
| 328 if (!needs_begin_frame || begin_unthrottled_frame_posted_) | |
| 329 return; | |
| 330 | |
| 331 if (state_machine_.begin_impl_frame_state() != | |
| 332 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE && | |
| 333 state_machine_.begin_impl_frame_state() != | |
| 334 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) { | |
| 335 return; | |
| 336 } | |
| 337 | |
| 338 begin_unthrottled_frame_posted_ = true; | |
| 339 task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_); | |
| 340 } | |
| 341 | |
| 342 // BeginUnthrottledFrame is used when we aren't throttling frame production. | |
| 343 // This will usually be because VSync is disabled. | |
| 344 void Scheduler::BeginUnthrottledFrame() { | |
| 345 DCHECK(!settings_.throttle_frame_production); | |
| 346 DCHECK(begin_retro_frame_args_.empty()); | |
| 347 | |
| 348 base::TimeTicks now = Now(); | |
| 349 base::TimeTicks deadline = now + vsync_interval_; | |
| 350 | |
| 351 BeginFrameArgs begin_frame_args = | |
| 352 BeginFrameArgs::Create(now, deadline, vsync_interval_); | |
| 353 BeginImplFrame(begin_frame_args); | |
| 354 | |
| 355 begin_unthrottled_frame_posted_ = false; | |
| 356 } | |
| 357 | |
| 358 // We may need to poll when we can't rely on BeginFrame to advance certain | 310 // We may need to poll when we can't rely on BeginFrame to advance certain |
| 359 // state or to avoid deadlock. | 311 // state or to avoid deadlock. |
| 360 void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) { | 312 void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) { |
| 361 bool needs_advance_commit_state_timer = false; | 313 bool needs_advance_commit_state_timer = false; |
| 362 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but | 314 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but |
| 363 // aren't expecting any more BeginFrames. This should only be needed by | 315 // aren't expecting any more BeginFrames. This should only be needed by |
| 364 // the synchronous compositor when BeginFrameNeeded is false. | 316 // the synchronous compositor when BeginFrameNeeded is false. |
| 365 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) { | 317 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) { |
| 366 DCHECK(!state_machine_.SupportsProactiveBeginFrame()); | 318 DCHECK(!state_machine_.SupportsProactiveBeginFrame()); |
| 367 DCHECK(!needs_begin_frame); | 319 DCHECK(!needs_begin_frame); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 } | 353 } |
| 402 } else { | 354 } else { |
| 403 advance_commit_state_task_.Cancel(); | 355 advance_commit_state_task_.Cancel(); |
| 404 } | 356 } |
| 405 } | 357 } |
| 406 | 358 |
| 407 // BeginFrame is the mechanism that tells us that now is a good time to start | 359 // BeginFrame is the mechanism that tells us that now is a good time to start |
| 408 // making a frame. Usually this means that user input for the frame is complete. | 360 // making a frame. Usually this means that user input for the frame is complete. |
| 409 // If the scheduler is busy, we queue the BeginFrame to be handled later as | 361 // If the scheduler is busy, we queue the BeginFrame to be handled later as |
| 410 // a BeginRetroFrame. | 362 // a BeginRetroFrame. |
| 411 void Scheduler::BeginFrame(const BeginFrameArgs& args) { | 363 BeginFrameObserver::BeginFrameArgsStatus Scheduler::ProcessBeginFrameArgs( |
| 364 const BeginFrameArgs& args) { |
| 412 TRACE_EVENT1("cc", "Scheduler::BeginFrame", "args", args.AsValue()); | 365 TRACE_EVENT1("cc", "Scheduler::BeginFrame", "args", args.AsValue()); |
| 413 DCHECK(settings_.throttle_frame_production); | |
| 414 | 366 |
| 415 BeginFrameArgs adjusted_args(args); | 367 BeginFrameArgs adjusted_args(args); |
| 416 adjusted_args.deadline -= EstimatedParentDrawTime(); | 368 adjusted_args.deadline -= EstimatedParentDrawTime(); |
| 417 | 369 |
| 418 bool should_defer_begin_frame; | 370 bool should_defer_begin_frame; |
| 419 if (settings_.using_synchronous_renderer_compositor) { | 371 if (settings_.using_synchronous_renderer_compositor) { |
| 420 should_defer_begin_frame = false; | 372 should_defer_begin_frame = false; |
| 421 } else { | 373 } else { |
| 422 should_defer_begin_frame = | 374 should_defer_begin_frame = |
| 423 !begin_retro_frame_args_.empty() || begin_retro_frame_posted_ || | 375 !begin_retro_frame_args_.empty() || begin_retro_frame_posted_ || |
| 424 !last_set_needs_begin_frame_ || | 376 !frame_source_->NeedsBeginFrames() || |
| 425 (state_machine_.begin_impl_frame_state() != | 377 (state_machine_.begin_impl_frame_state() != |
| 426 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); | 378 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); |
| 427 } | 379 } |
| 428 | 380 |
| 429 if (should_defer_begin_frame) { | 381 if (should_defer_begin_frame) { |
| 430 begin_retro_frame_args_.push_back(adjusted_args); | 382 begin_retro_frame_args_.push_back(adjusted_args); |
| 431 TRACE_EVENT_INSTANT0( | 383 TRACE_EVENT_INSTANT0( |
| 432 "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD); | 384 "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD); |
| 433 return; | 385 // Queuing the frame counts as "using it", so we need to return true. |
| 386 return BeginFrameObserver::BeginFrameArgsStatus::USED; |
| 434 } | 387 } |
| 435 | 388 |
| 436 BeginImplFrame(adjusted_args); | 389 BeginImplFrame(adjusted_args); |
| 390 return BeginFrameObserver::BeginFrameArgsStatus::USED; |
| 391 } |
| 392 |
| 393 // We have just called SetNeedsBeginFrame(true) and the BeginFrameSource has |
| 394 // sent us the last BeginFrame we have missed. As we might not be able to |
| 395 // actually make rendering for this call, handle it like a "retro frame". |
| 396 // TODO(brainderson): Add a test for this functionality ASAP! |
| 397 BeginFrameObserver::BeginFrameArgsStatus Scheduler::OnMissedBeginFrame( |
| 398 const BeginFrameArgs& args) { |
| 399 begin_retro_frame_args_.push_back(args); |
| 400 PostBeginRetroFrameIfNeeded(); |
| 401 return BeginFrameObserver::BeginFrameArgsStatus::USED; |
| 437 } | 402 } |
| 438 | 403 |
| 439 // BeginRetroFrame is called for BeginFrames that we've deferred because | 404 // BeginRetroFrame is called for BeginFrames that we've deferred because |
| 440 // the scheduler was in the middle of processing a previous BeginFrame. | 405 // the scheduler was in the middle of processing a previous BeginFrame. |
| 441 void Scheduler::BeginRetroFrame() { | 406 void Scheduler::BeginRetroFrame() { |
| 442 TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame"); | 407 TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame"); |
| 443 DCHECK(!settings_.using_synchronous_renderer_compositor); | 408 DCHECK(!settings_.using_synchronous_renderer_compositor); |
| 444 DCHECK(begin_retro_frame_posted_); | 409 DCHECK(begin_retro_frame_posted_); |
| 445 begin_retro_frame_posted_ = false; | 410 begin_retro_frame_posted_ = false; |
| 446 | 411 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 465 break; | 430 break; |
| 466 | 431 |
| 467 TRACE_EVENT_INSTANT2("cc", | 432 TRACE_EVENT_INSTANT2("cc", |
| 468 "Scheduler::BeginRetroFrame discarding", | 433 "Scheduler::BeginRetroFrame discarding", |
| 469 TRACE_EVENT_SCOPE_THREAD, | 434 TRACE_EVENT_SCOPE_THREAD, |
| 470 "deadline - now", | 435 "deadline - now", |
| 471 (adjusted_deadline - now).InMicroseconds(), | 436 (adjusted_deadline - now).InMicroseconds(), |
| 472 "BeginFrameArgs", | 437 "BeginFrameArgs", |
| 473 begin_retro_frame_args_.front().AsValue()); | 438 begin_retro_frame_args_.front().AsValue()); |
| 474 begin_retro_frame_args_.pop_front(); | 439 begin_retro_frame_args_.pop_front(); |
| 440 frame_source_->DidFinishFrame(begin_retro_frame_args_.size()); |
| 475 } | 441 } |
| 476 | 442 |
| 477 if (begin_retro_frame_args_.empty()) { | 443 if (begin_retro_frame_args_.empty()) { |
| 478 DCHECK(settings_.throttle_frame_production); | |
| 479 TRACE_EVENT_INSTANT0("cc", | 444 TRACE_EVENT_INSTANT0("cc", |
| 480 "Scheduler::BeginRetroFrames all expired", | 445 "Scheduler::BeginRetroFrames all expired", |
| 481 TRACE_EVENT_SCOPE_THREAD); | 446 TRACE_EVENT_SCOPE_THREAD); |
| 482 } else { | 447 } else { |
| 483 BeginImplFrame(begin_retro_frame_args_.front()); | 448 BeginImplFrame(begin_retro_frame_args_.front()); |
| 484 begin_retro_frame_args_.pop_front(); | 449 begin_retro_frame_args_.pop_front(); |
| 485 } | 450 } |
| 486 } | 451 } |
| 487 | 452 |
| 488 // There could be a race between the posted BeginRetroFrame and a new | 453 // There could be a race between the posted BeginRetroFrame and a new |
| 489 // BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame | 454 // BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame |
| 490 // will check if there is a pending BeginRetroFrame to ensure we handle | 455 // will check if there is a pending BeginRetroFrame to ensure we handle |
| 491 // BeginFrames in FIFO order. | 456 // BeginFrames in FIFO order. |
| 492 void Scheduler::PostBeginRetroFrameIfNeeded() { | 457 void Scheduler::PostBeginRetroFrameIfNeeded() { |
| 493 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), | 458 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), |
| 494 "Scheduler::PostBeginRetroFrameIfNeeded", | 459 "Scheduler::PostBeginRetroFrameIfNeeded", |
| 495 "state", | 460 "state", |
| 496 AsValue()); | 461 AsValue()); |
| 497 if (!last_set_needs_begin_frame_) | 462 if (!frame_source_->NeedsBeginFrames()) |
| 498 return; | 463 return; |
| 499 | 464 |
| 500 if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_) | 465 if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_) |
| 501 return; | 466 return; |
| 502 | 467 |
| 503 // begin_retro_frame_args_ should always be empty for the | 468 // begin_retro_frame_args_ should always be empty for the |
| 504 // synchronous compositor. | 469 // synchronous compositor. |
| 505 DCHECK(!settings_.using_synchronous_renderer_compositor); | 470 DCHECK(!settings_.using_synchronous_renderer_compositor); |
| 506 | 471 |
| 507 if (state_machine_.begin_impl_frame_state() != | 472 if (state_machine_.begin_impl_frame_state() != |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 705 scoped_refptr<base::debug::TracedValue> state = | 670 scoped_refptr<base::debug::TracedValue> state = |
| 706 new base::debug::TracedValue(); | 671 new base::debug::TracedValue(); |
| 707 AsValueInto(state.get()); | 672 AsValueInto(state.get()); |
| 708 return state; | 673 return state; |
| 709 } | 674 } |
| 710 | 675 |
| 711 void Scheduler::AsValueInto(base::debug::TracedValue* state) const { | 676 void Scheduler::AsValueInto(base::debug::TracedValue* state) const { |
| 712 state->BeginDictionary("state_machine"); | 677 state->BeginDictionary("state_machine"); |
| 713 state_machine_.AsValueInto(state, Now()); | 678 state_machine_.AsValueInto(state, Now()); |
| 714 state->EndDictionary(); | 679 state->EndDictionary(); |
| 715 if (synthetic_begin_frame_source_) { | 680 |
| 716 state->BeginDictionary("synthetic_begin_frame_source_"); | 681 state->BeginDictionary("frame_source_"); |
| 717 synthetic_begin_frame_source_->AsValueInto(state); | 682 frame_source_->AsValueInto(state); |
| 718 state->EndDictionary(); | 683 state->EndDictionary(); |
| 719 } | |
| 720 | 684 |
| 721 state->BeginDictionary("scheduler_state"); | 685 state->BeginDictionary("scheduler_state"); |
| 722 state->SetDouble("time_until_anticipated_draw_time_ms", | 686 state->SetDouble("time_until_anticipated_draw_time_ms", |
| 723 (AnticipatedDrawTime() - Now()).InMillisecondsF()); | 687 (AnticipatedDrawTime() - Now()).InMillisecondsF()); |
| 724 state->SetDouble("vsync_interval_ms", vsync_interval_.InMillisecondsF()); | |
| 725 state->SetDouble("estimated_parent_draw_time_ms", | 688 state->SetDouble("estimated_parent_draw_time_ms", |
| 726 estimated_parent_draw_time_.InMillisecondsF()); | 689 estimated_parent_draw_time_.InMillisecondsF()); |
| 727 state->SetBoolean("last_set_needs_begin_frame_", last_set_needs_begin_frame_); | 690 state->SetBoolean("last_set_needs_begin_frame_", |
| 728 state->SetBoolean("begin_unthrottled_frame_posted_", | 691 frame_source_->NeedsBeginFrames()); |
| 729 begin_unthrottled_frame_posted_); | |
| 730 state->SetBoolean("begin_retro_frame_posted_", begin_retro_frame_posted_); | 692 state->SetBoolean("begin_retro_frame_posted_", begin_retro_frame_posted_); |
| 731 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size()); | 693 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size()); |
| 732 state->SetBoolean("begin_impl_frame_deadline_task_", | 694 state->SetBoolean("begin_impl_frame_deadline_task_", |
| 733 !begin_impl_frame_deadline_task_.IsCancelled()); | 695 !begin_impl_frame_deadline_task_.IsCancelled()); |
| 734 state->SetBoolean("poll_for_draw_triggers_task_", | 696 state->SetBoolean("poll_for_draw_triggers_task_", |
| 735 !poll_for_draw_triggers_task_.IsCancelled()); | 697 !poll_for_draw_triggers_task_.IsCancelled()); |
| 736 state->SetBoolean("advance_commit_state_task_", | 698 state->SetBoolean("advance_commit_state_task_", |
| 737 !advance_commit_state_task_.IsCancelled()); | 699 !advance_commit_state_task_.IsCancelled()); |
| 738 state->BeginDictionary("begin_impl_frame_args"); | 700 state->BeginDictionary("begin_impl_frame_args"); |
| 739 begin_impl_frame_args_.AsValueInto(state); | 701 begin_impl_frame_args_.AsValueInto(state); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 773 } | 735 } |
| 774 | 736 |
| 775 bool Scheduler::IsBeginMainFrameSentOrStarted() const { | 737 bool Scheduler::IsBeginMainFrameSentOrStarted() const { |
| 776 return (state_machine_.commit_state() == | 738 return (state_machine_.commit_state() == |
| 777 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || | 739 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || |
| 778 state_machine_.commit_state() == | 740 state_machine_.commit_state() == |
| 779 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); | 741 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); |
| 780 } | 742 } |
| 781 | 743 |
| 782 } // namespace cc | 744 } // namespace cc |
| OLD | NEW |