Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(52)

Side by Side Diff: cc/scheduler/scheduler.cc

Issue 221833009: cc: Move scheduling logic out of OutputSurface (Closed) Base URL: http://git.chromium.org/chromium/src.git@swapAck2Sched11
Patch Set: rebase; fix tests Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "cc/scheduler/delay_based_time_source.h"
13 #include "ui/gfx/frame_time.h" 14 #include "ui/gfx/frame_time.h"
14 15
15 namespace cc { 16 namespace cc {
16 17
17 Scheduler::Scheduler( 18 Scheduler::Scheduler(
18 SchedulerClient* client, 19 SchedulerClient* client,
19 const SchedulerSettings& scheduler_settings, 20 const SchedulerSettings& scheduler_settings,
20 int layer_tree_host_id, 21 int layer_tree_host_id,
21 const scoped_refptr<base::SequencedTaskRunner>& impl_task_runner) 22 const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner)
22 : settings_(scheduler_settings), 23 : settings_(scheduler_settings),
23 client_(client), 24 client_(client),
24 layer_tree_host_id_(layer_tree_host_id), 25 layer_tree_host_id_(layer_tree_host_id),
25 impl_task_runner_(impl_task_runner), 26 impl_task_runner_(impl_task_runner),
27 vsync_interval_(BeginFrameArgs::DefaultInterval()),
26 last_set_needs_begin_frame_(false), 28 last_set_needs_begin_frame_(false),
27 begin_retro_frame_posted_(false), 29 begin_retro_frame_posted_(false),
28 state_machine_(scheduler_settings), 30 state_machine_(scheduler_settings),
29 inside_process_scheduled_actions_(false), 31 inside_process_scheduled_actions_(false),
30 inside_action_(SchedulerStateMachine::ACTION_NONE), 32 inside_action_(SchedulerStateMachine::ACTION_NONE),
31 weak_factory_(this) { 33 weak_factory_(this) {
32 DCHECK(client_); 34 DCHECK(client_);
33 DCHECK(!state_machine_.BeginFrameNeeded()); 35 DCHECK(!state_machine_.BeginFrameNeeded());
34 if (settings_.main_frame_before_activation_enabled) { 36 if (settings_.main_frame_before_activation_enabled) {
35 DCHECK(settings_.main_frame_before_draw_enabled); 37 DCHECK(settings_.main_frame_before_draw_enabled);
36 } 38 }
37 39
38 begin_retro_frame_closure_ = 40 begin_retro_frame_closure_ =
39 base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr()); 41 base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr());
40 begin_impl_frame_deadline_closure_ = base::Bind( 42 begin_impl_frame_deadline_closure_ = base::Bind(
41 &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr()); 43 &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr());
42 poll_for_draw_triggers_closure_ = base::Bind( 44 poll_for_draw_triggers_closure_ = base::Bind(
43 &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr()); 45 &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr());
44 advance_commit_state_closure_ = base::Bind( 46 advance_commit_state_closure_ = base::Bind(
45 &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr()); 47 &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr());
48
49 if (!settings_.begin_frame_scheduling_enabled) {
50 SetupSyntheticBeginFrames();
51 }
46 } 52 }
47 53
48 Scheduler::~Scheduler() {} 54 Scheduler::~Scheduler() {}
Sami 2014/04/08 13:46:01 Should probably stop the time source here.
brianderson 2014/04/09 02:52:05 The timesource cleans itself up, but it wouldn't h
brianderson 2014/04/10 23:45:58 Done.
49 55
56 void Scheduler::SetupSyntheticBeginFrames() {
57 if (gfx::FrameTime::TimestampsAreHighRes()) {
58 time_source_for_synthetic_begin_frames_ =
59 DelayBasedTimeSourceHighRes::Create(vsync_interval_,
60 impl_task_runner_.get());
61 } else {
62 time_source_for_synthetic_begin_frames_ =
63 DelayBasedTimeSource::Create(vsync_interval_, impl_task_runner_.get());
64 }
65 time_source_for_synthetic_begin_frames_->SetClient(this);
66 }
67
68 void Scheduler::OnTimerTick() {
69 DCHECK(!settings_.begin_frame_scheduling_enabled);
70 BeginFrameArgs synthentic_begin_frame_args(CreateSyntheticBeginFrameArgs(
71 time_source_for_synthetic_begin_frames_->LastTickTime()));
72 BeginFrame(synthentic_begin_frame_args);
73 }
74
75 BeginFrameArgs Scheduler::CreateSyntheticBeginFrameArgs(
76 base::TimeTicks frame_time) {
77 base::TimeTicks deadline =
78 time_source_for_synthetic_begin_frames_->NextTickTime() -
79 estimated_parent_draw_time_;
80 return BeginFrameArgs::Create(frame_time, deadline, vsync_interval_);
81 }
82
83 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase,
84 base::TimeDelta interval) {
85 vsync_interval_ = interval;
86 if (!settings_.begin_frame_scheduling_enabled)
87 time_source_for_synthetic_begin_frames_->SetTimebaseAndInterval(timebase,
88 interval);
89 }
90
91 void Scheduler::SetEstimatedParentDrawTime(base::TimeDelta draw_time) {
92 estimated_parent_draw_time_ = draw_time;
93 }
94
50 void Scheduler::SetCanStart() { 95 void Scheduler::SetCanStart() {
51 state_machine_.SetCanStart(); 96 state_machine_.SetCanStart();
52 ProcessScheduledActions(); 97 ProcessScheduledActions();
53 } 98 }
54 99
55 void Scheduler::SetVisible(bool visible) { 100 void Scheduler::SetVisible(bool visible) {
56 state_machine_.SetVisible(visible); 101 state_machine_.SetVisible(visible);
57 ProcessScheduledActions(); 102 ProcessScheduledActions();
58 } 103 }
59 104
(...skipping 29 matching lines...) Expand all
89 void Scheduler::SetNeedsManageTiles() { 134 void Scheduler::SetNeedsManageTiles() {
90 DCHECK(!IsInsideAction(SchedulerStateMachine::ACTION_MANAGE_TILES)); 135 DCHECK(!IsInsideAction(SchedulerStateMachine::ACTION_MANAGE_TILES));
91 state_machine_.SetNeedsManageTiles(); 136 state_machine_.SetNeedsManageTiles();
92 ProcessScheduledActions(); 137 ProcessScheduledActions();
93 } 138 }
94 139
95 void Scheduler::SetMaxSwapsPending(int max) { 140 void Scheduler::SetMaxSwapsPending(int max) {
96 state_machine_.SetMaxSwapsPending(max); 141 state_machine_.SetMaxSwapsPending(max);
97 } 142 }
98 143
99 void Scheduler::DidSwapBuffers() { state_machine_.DidSwapBuffers(); } 144 void Scheduler::DidSwapBuffers() {
145 DCHECK(state_machine_.HasInitializedOutputSurface());
146 state_machine_.DidSwapBuffers();
147 }
100 148
101 void Scheduler::SetSwapUsedIncompleteTile(bool used_incomplete_tile) { 149 void Scheduler::SetSwapUsedIncompleteTile(bool used_incomplete_tile) {
102 state_machine_.SetSwapUsedIncompleteTile(used_incomplete_tile); 150 state_machine_.SetSwapUsedIncompleteTile(used_incomplete_tile);
103 ProcessScheduledActions(); 151 ProcessScheduledActions();
104 } 152 }
105 153
106 void Scheduler::OnSwapBuffersComplete() { 154 void Scheduler::OnSwapBuffersComplete() {
107 state_machine_.OnSwapBuffersComplete(); 155 state_machine_.OnSwapBuffersComplete();
Sami 2014/04/08 13:46:01 That DCHECK in Scheduler::DidSwapBuffers could go
brianderson 2014/04/09 02:52:05 Good idea.
brianderson 2014/04/10 23:45:58 Done.
108 ProcessScheduledActions(); 156 ProcessScheduledActions();
109 } 157 }
110 158
111 void Scheduler::SetSmoothnessTakesPriority(bool smoothness_takes_priority) { 159 void Scheduler::SetSmoothnessTakesPriority(bool smoothness_takes_priority) {
112 state_machine_.SetSmoothnessTakesPriority(smoothness_takes_priority); 160 state_machine_.SetSmoothnessTakesPriority(smoothness_takes_priority);
113 ProcessScheduledActions(); 161 ProcessScheduledActions();
114 } 162 }
115 163
116 void Scheduler::SetMainThreadNeedsLayerTextures() { 164 void Scheduler::SetMainThreadNeedsLayerTextures() {
117 state_machine_.SetMainThreadNeedsLayerTextures(); 165 state_machine_.SetMainThreadNeedsLayerTextures();
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 return timebase + (begin_impl_frame_args_.interval * intervals); 215 return timebase + (begin_impl_frame_args_.interval * intervals);
168 } 216 }
169 217
170 base::TimeTicks Scheduler::LastBeginImplFrameTime() { 218 base::TimeTicks Scheduler::LastBeginImplFrameTime() {
171 return begin_impl_frame_args_.frame_time; 219 return begin_impl_frame_args_.frame_time;
172 } 220 }
173 221
174 void Scheduler::SetupNextBeginFrameIfNeeded() { 222 void Scheduler::SetupNextBeginFrameIfNeeded() {
175 bool needs_begin_frame = state_machine_.BeginFrameNeeded(); 223 bool needs_begin_frame = state_machine_.BeginFrameNeeded();
176 224
225 if (settings_.throttle_frame_production) {
226 SetupNextBeginFrameWhenVSyncEnabled(needs_begin_frame);
Sami 2014/04/08 13:46:01 bikeshed: s/VSync/Throttling/ to keep the terms a
brianderson 2014/04/09 02:52:05 I was afraid of confusing vsync throttling with sw
brianderson 2014/04/10 23:45:58 Done.
227 } else {
228 SetupNextBeginFrameWhenVSyncDisabled(needs_begin_frame);
229 }
230 SetupPollingMechanisms(needs_begin_frame);
231 }
232
233 // When we are throttling frame production, we request BeginFrames
234 // from the OutputSurface.
235 void Scheduler::SetupNextBeginFrameWhenVSyncEnabled(bool needs_begin_frame) {
177 bool at_end_of_deadline = 236 bool at_end_of_deadline =
178 state_machine_.begin_impl_frame_state() == 237 state_machine_.begin_impl_frame_state() ==
179 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE; 238 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE;
180 239
181 bool should_call_set_needs_begin_frame = 240 bool should_call_set_needs_begin_frame =
182 // Always request the BeginFrame immediately if it wasn't needed before. 241 // Always request the BeginFrame immediately if it wasn't needed before.
183 (needs_begin_frame && !last_set_needs_begin_frame_) || 242 (needs_begin_frame && !last_set_needs_begin_frame_) ||
184 // We always need to explicitly request our next BeginFrame. 243 // Only stop requesting BeginFrames after a deadline.
185 at_end_of_deadline; 244 (!needs_begin_frame && last_set_needs_begin_frame_ && at_end_of_deadline);
186 245
187 if (should_call_set_needs_begin_frame) { 246 if (should_call_set_needs_begin_frame) {
188 client_->SetNeedsBeginFrame(needs_begin_frame); 247 if (settings_.begin_frame_scheduling_enabled) {
248 client_->SetNeedsBeginFrame(needs_begin_frame);
249 } else {
250 base::TimeTicks missed_tick_time =
251 time_source_for_synthetic_begin_frames_->SetActive(needs_begin_frame);
252 if (!missed_tick_time.is_null()) {
253 begin_retro_frame_args_.push_back(
254 CreateSyntheticBeginFrameArgs(missed_tick_time));
255 }
256 }
189 last_set_needs_begin_frame_ = needs_begin_frame; 257 last_set_needs_begin_frame_ = needs_begin_frame;
190 } 258 }
191 259
192 // Handle retroactive BeginFrames.
193 if (needs_begin_frame) 260 if (needs_begin_frame)
194 PostBeginRetroFrameIfNeeded(); 261 PostBeginRetroFrameIfNeeded();
262 }
195 263
264 // When we aren't throttling frame production, we create our own
265 // BeginImplFrames as soon as we go idle, using the BeginRetroFrame logic.
266 void Scheduler::SetupNextBeginFrameWhenVSyncDisabled(bool needs_begin_frame) {
267 last_set_needs_begin_frame_ = needs_begin_frame;
268
269 if (!needs_begin_frame || begin_retro_frame_posted_)
270 return;
271
272 if (state_machine_.begin_impl_frame_state() !=
273 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE &&
274 state_machine_.begin_impl_frame_state() !=
275 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) {
276 return;
277 }
278
279 base::TimeTicks now = gfx::FrameTime::Now();
280 base::TimeDelta interval = vsync_interval_ > base::TimeDelta()
281 ? vsync_interval_
282 : BeginFrameArgs::DefaultInterval();
283
284 DCHECK(begin_retro_frame_args_.empty());
285 begin_retro_frame_args_.push_back(
286 BeginFrameArgs::Create(now, now + interval, interval));
287 PostBeginRetroFrame();
288 }
289
290 void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) {
196 bool needs_advance_commit_state_timer = false; 291 bool needs_advance_commit_state_timer = false;
197 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but 292 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but
198 // aren't expecting any more BeginFrames. This should only be needed by 293 // aren't expecting any more BeginFrames. This should only be needed by
199 // the synchronous compositor when BeginFrameNeeded is false. 294 // the synchronous compositor when BeginFrameNeeded is false.
200 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) { 295 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) {
201 DCHECK(!state_machine_.SupportsProactiveBeginFrame()); 296 DCHECK(!state_machine_.SupportsProactiveBeginFrame());
202 DCHECK(!needs_begin_frame); 297 DCHECK(!needs_begin_frame);
203 if (poll_for_draw_triggers_task_.IsCancelled()) { 298 if (poll_for_draw_triggers_task_.IsCancelled()) {
204 poll_for_draw_triggers_task_.Reset(poll_for_draw_triggers_closure_); 299 poll_for_draw_triggers_task_.Reset(poll_for_draw_triggers_closure_);
205 base::TimeDelta delay = begin_impl_frame_args_.IsValid() 300 base::TimeDelta delay = begin_impl_frame_args_.IsValid()
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
249 344
250 if (state_machine_.begin_impl_frame_state() != 345 if (state_machine_.begin_impl_frame_state() !=
251 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE) 346 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE)
252 return; 347 return;
253 348
254 begin_retro_frame_posted_ = true; 349 begin_retro_frame_posted_ = true;
255 impl_task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_); 350 impl_task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_);
256 } 351 }
257 352
258 void Scheduler::BeginFrame(const BeginFrameArgs& args) { 353 void Scheduler::BeginFrame(const BeginFrameArgs& args) {
354 DCHECK(settings_.throttle_frame_production);
259 if (settings_.using_synchronous_renderer_compositor || 355 if (settings_.using_synchronous_renderer_compositor ||
260 (last_set_needs_begin_frame_ && begin_retro_frame_args_.empty() && 356 (last_set_needs_begin_frame_ && begin_retro_frame_args_.empty() &&
261 state_machine_.begin_impl_frame_state() == 357 state_machine_.begin_impl_frame_state() ==
262 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE)) { 358 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE)) {
263 BeginImplFrame(args); 359 BeginImplFrame(args);
264 } else { 360 } else {
265 begin_retro_frame_args_.push_back(args); 361 begin_retro_frame_args_.push_back(args);
266 TRACE_EVENT_INSTANT0( 362 TRACE_EVENT_INSTANT0(
267 "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD); 363 "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD);
268 } 364 }
269 } 365 }
270 366
367 void Scheduler::PostBeginRetroFrame() {
368 begin_retro_frame_posted_ = true;
369 impl_task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_);
370 }
371
271 void Scheduler::BeginRetroFrame() { 372 void Scheduler::BeginRetroFrame() {
272 TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame"); 373 TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame");
273 DCHECK(begin_retro_frame_posted_); 374 DCHECK(begin_retro_frame_posted_);
274 DCHECK(!begin_retro_frame_args_.empty()); 375 DCHECK(!begin_retro_frame_args_.empty());
275 376
276 // Discard expired BeginRetroFrames 377 // Discard expired BeginRetroFrames
277 base::TimeTicks now = gfx::FrameTime::Now(); 378 // Not if frame production isn't throttled though, since all frames will be
Sami 2014/04/08 13:46:01 This is getting a little confusing. Should we perh
brianderson 2014/04/09 02:52:05 This is for the unthrottled (vsync disabled) frame
brianderson 2014/04/10 23:45:58 Added a BeginUnthrottledFrame with a separate clos
278 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); 379 // BeginRetroFrames.
279 while (!begin_retro_frame_args_.empty() && 380 if (settings_.throttle_frame_production) {
280 now > AdjustedBeginImplFrameDeadline(begin_retro_frame_args_.front(), 381 base::TimeTicks now = gfx::FrameTime::Now();
281 draw_duration_estimate)) { 382 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
282 begin_retro_frame_args_.pop_front(); 383 while (!begin_retro_frame_args_.empty() &&
384 now > AdjustedBeginImplFrameDeadline(begin_retro_frame_args_.front(),
385 draw_duration_estimate)) {
386 begin_retro_frame_args_.pop_front();
387 }
283 } 388 }
284 389
285 if (begin_retro_frame_args_.empty()) { 390 if (begin_retro_frame_args_.empty()) {
391 DCHECK(settings_.throttle_frame_production);
286 TRACE_EVENT_INSTANT0( 392 TRACE_EVENT_INSTANT0(
287 "cc", "Scheduler::BeginRetroFrames expired", TRACE_EVENT_SCOPE_THREAD); 393 "cc", "Scheduler::BeginRetroFrames expired", TRACE_EVENT_SCOPE_THREAD);
288 } else { 394 } else {
289 BeginImplFrame(begin_retro_frame_args_.front()); 395 BeginImplFrame(begin_retro_frame_args_.front());
290 begin_retro_frame_args_.pop_front(); 396 begin_retro_frame_args_.pop_front();
291 } 397 }
292 398
293 begin_retro_frame_posted_ = false; 399 begin_retro_frame_posted_ = false;
294 } 400 }
295 401
296 void Scheduler::BeginImplFrame(const BeginFrameArgs& args) { 402 void Scheduler::BeginImplFrame(const BeginFrameArgs& args) {
297 TRACE_EVENT0("cc", "Scheduler::BeginImplFrame");
298 DCHECK(state_machine_.begin_impl_frame_state() == 403 DCHECK(state_machine_.begin_impl_frame_state() ==
299 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); 404 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
300 DCHECK(state_machine_.HasInitializedOutputSurface()); 405 DCHECK(state_machine_.HasInitializedOutputSurface());
301 406
302 advance_commit_state_task_.Cancel(); 407 advance_commit_state_task_.Cancel();
303 408
304 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); 409 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
305 begin_impl_frame_args_ = args; 410 begin_impl_frame_args_ = args;
306 begin_impl_frame_args_.deadline -= draw_duration_estimate; 411 begin_impl_frame_args_.deadline -= draw_duration_estimate;
307 412
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after
546 } 651 }
547 652
548 bool Scheduler::IsBeginMainFrameSentOrStarted() const { 653 bool Scheduler::IsBeginMainFrameSentOrStarted() const {
549 return (state_machine_.commit_state() == 654 return (state_machine_.commit_state() ==
550 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || 655 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT ||
551 state_machine_.commit_state() == 656 state_machine_.commit_state() ==
552 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); 657 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED);
553 } 658 }
554 659
555 } // namespace cc 660 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698